diff --git a/.gitignore b/.gitignore index d3888e74c..337834570 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.so *.o *~ +#* .DS_Store bin @@ -14,6 +15,7 @@ bin /lib /log +codebase/superdarn/src.lib/tk/idl.tar.gz codebase/general/src.lib/stdkey.1.5/src/make_palette *errstr.h diff --git a/codebase/analysis/src.lib/linearfit.1.0/doc/linearfit.doc.xml b/codebase/analysis/src.lib/linearfit.1.0/doc/linearfit.doc.xml new file mode 100644 index 000000000..d40ac8b5b --- /dev/null +++ b/codebase/analysis/src.lib/linearfit.1.0/doc/linearfit.doc.xml @@ -0,0 +1,20 @@ + + +analysis +linearfit +src.lib/linearfit + + + +linear_regression +src.lib/linearfit +
analysis/linearfit.h
+int linear_regression(float x[], float y[], float sig[], int num, int mwt, float *intercept, float *sig_intercept, float *slope, float *sig_slope, float *chi2, float *q); +

The linear_regression function calculates linear regression for an array of independent and dependent variables, with optional errors.

+
+

Returns the fitted slope and intercept (slope, intercept), their errors (sig_slope, sig_intercept), as well as the chi-squared and gamma results for the fit (chi2, q).

+
+If there are problems assigning data to the subarrays when performing the sorting, the routine will exit with 0. +
+ +
diff --git a/codebase/analysis/src.lib/linearfit.1.0/include/linearfit.h b/codebase/analysis/src.lib/linearfit.1.0/include/linearfit.h new file mode 100644 index 000000000..60fdca617 --- /dev/null +++ b/codebase/analysis/src.lib/linearfit.1.0/include/linearfit.h @@ -0,0 +1,39 @@ +/* linearfit.h + =========== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#ifndef _LINEARFIT_H +#define _LINEARFIT_H + +#ifndef _RTYPES_H +#include "rtypes.h" +#endif + +#ifndef _STATS_H +#include "stats.h" +#endif + +static float sqrarg; +#ifndef SQR +#define SQR(a) ((sqrarg = (a)) == 0.0 ? 0.0 : sqrarg * sqrarg); +#endif + +#ifndef MINSIG +#define MINSIG 1.0e-5 +#endif + +int linear_regression(float x[], float y[], float sig[], int num, int mwt, + float *intercept, float *sig_intercept, float *slope, + float *sig_slope, float *chi2, float *q); + +#endif diff --git a/codebase/analysis/src.lib/linearfit.1.0/src/linearfit.c b/codebase/analysis/src.lib/linearfit.1.0/src/linearfit.c new file mode 100644 index 000000000..44cee5011 --- /dev/null +++ b/codebase/analysis/src.lib/linearfit.1.0/src/linearfit.c @@ -0,0 +1,110 @@ +/* linearfit.c + =========== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include + +#include "linearfit.h" + +/** + * @brief perform a linear regression + * + * @params[in] x - independent variable array + * y - dependent variable array + * sig - error of the dependent variable array + * num - number of variables in x, y, and sig + * mwt - boolean, if true sig is used to calculate weights + * + * @params[out] intercept - pointer to the fitted intercept + * sig_intercept - pointer to the error of the intercept + * slope - pointer to the fitted slope + * sig_slope - pointer to the error of the slope + * chi2 - pointer to the Chi-squared value + * q - pointer to the gamma function output + * + * @references Numerical Recipes in C, 2nd Edition + **/ + +int linear_regression(float x[], float y[], float sig[], int num, int mwt, + float *intercept, float *sig_intercept, float *slope, + float *sig_slope, float *chi2, float *q) +{ + int n, status = 1; + + float wt, t, sxoss, sx, sy, st2, ss, sigdat; + + sx = sy = st2 = 0.0; + *slope = 0.0; + + if(mwt) + { + for(ss = 0.0, n = 0; n < num; n++) + { + if(sig[n] == 0.0) sig[n] = MINSIG; + + wt = 1.0 / (sig[n] * sig[n]); + ss += wt; + sx += x[n] * wt; + sy += y[n] * wt; + } + } + else + { + for(ss = num, n = 0; n < num; n++) + { + sx += x[n]; + sy += y[n]; + } + } + + sxoss = sx / ss; + + for(n = 0; n < num; n++) + { + t = (mwt) ? (x[n] - sxoss) / sig[n] : x[n] - sxoss; + st2 += t * t; + *slope += t * y[n]; + } + + *slope /= st2; + *intercept = (sy - sx * (*slope)) / ss; + *sig_intercept = sqrt((1.0 + sx * sx / (ss * st2)) / ss); + *sig_slope = sqrt(1.0 / st2); + + /* Calculate Chi2 */ + + *chi2 = 0.0; + *q = 1.0; + + if(mwt == 0) + { + for(n = 0; n < num; n++) + *chi2 += SQR(y[n] - (*intercept) - (*slope) * x[n]); + + sigdat = sqrt((*chi2) / (float)(num - 2)); + *sig_slope *= sigdat; + *sig_intercept *= sigdat; + status = 0; + } + else + { + for(n = 0; n < num; n++) + *chi2 += SQR((y[n] - (*intercept) - (*slope) * x[n]) / sig[n]); + + if(num > 2) *q = (float)gammaq(0.5 * (double)(num - 2), + 0.5 * (double)(*chi2)); + } + + return(status); +} diff --git a/codebase/analysis/src.lib/linearfit.1.0/src/makefile b/codebase/analysis/src.lib/linearfit.1.0/src/makefile new file mode 100644 index 000000000..c53a72979 --- /dev/null +++ b/codebase/analysis/src.lib/linearfit.1.0/src/makefile @@ -0,0 +1,24 @@ +# Makefile for the linearfit library +# ================================== +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/analysis -I../include +INC = $(IPATH)/analysis +OUTPUT = linearfit +DSTPATH = $(LIBPATH) + +SRC = linearfit.c +OBJS = $(SRC:.c=.o) + +LINK = "1" + +include $(MAKELIB).$(SYSTEM) + diff --git a/codebase/analysis/src.lib/stats.1.0/doc/stats.doc.xml b/codebase/analysis/src.lib/stats.1.0/doc/stats.doc.xml new file mode 100644 index 000000000..b0fdb219a --- /dev/null +++ b/codebase/analysis/src.lib/stats.1.0/doc/stats.doc.xml @@ -0,0 +1,238 @@ + + +analysis +stats +src.lib/stats + + + +num_unique_int_vals +src.lib/stats +
analysis/stats.h
+int num_unique_int_vals(int num, int array[]); +

The num_unique_int_vals function calculates the number of unique elements in array. The input array of integers is not modified in any way.

+
+

Returns the number of unique values in array.

+If there are problems assigning data to the subarrays when performing the sorting, the routine will exit with -1. +
+ + +get_unique_str +src.lib/stats +
analysis/stats.h
+int get_unique_str(int in_num, char **in_str, char **out_str) +

Identify and obtain the unique strings from an array of strings, in_str

+
+

Returns a pointer containing all of the unique strings and the number of unique strings as the output.

+
+ + +stdev_float +src.lib/stats +
analysis/stats.h
+float stdev_float(int num, float array[]); +

The stdev_float function calculates the standard deviation of the values in the floating point decimal array, array.

+
+

Returns the standard deviation.

+If there are not enough values to calculate the standard deviation, a value of 0.0 is returned. +
+ + +mean_stdev_float +src.lib/stats +
analysis/stats.h
+void mean_stdev_float(int num, float array[], float *mean, float *stdev); +

The mean_stdev_float function calculates the arithmatic mean and standard deviation of the values in the floating point decimal array, array.

+
+

Returns the mean and standard deviation as pointers.

+If there are not enough values to calculate the mean or standard deviation, a value of 0.0 is returned. +
+ + +zscore +src.lib/stats +
analysis/stats.h
+void zscore(int num, float array[], float *zscore); +

Calculate the z-score for each value in array

+
+

Returns the z-score as a pointer equal in size to the input array

+If the standard deviation could not be calculated (is zero), a z-score of infinity is assigned for every value. +
+ + +gaussian +src.lib/stats +
analysis/stats.h
+double gaussian(double x, double *params); +

A function that calculates the value for a Gaussian at x using the amplitude, mean, and standard deviation of the distribution provided in that order through params. This function is formatted for use in MINPACK optimization.

+
+

Returns the result of amplitude * e^(-(x-mean)^2 / (2 * standard_deviation^2)).

+
+ + +mult_gaussian +src.lib/stats +
analysis/stats.h
+double mult_gaussian(double x, double *params); +

A function that calculates the value for a multi-peaked Gaussian at x using the number of distributions, and amplitudes, means, and standard deviations for each of these of the distributions provided in that order through params. If the number of distributions is one, the results are the same as gaussian. This function is formatted for use in MINPACK optimization.

+
+

Returns the result of SUM(amplitude_i * e^(-(x-mean_i)^2 / (2 * standard_deviation_i^2))).

+
+ + +gaussian_dev +src.lib/stats +
analysis/stats.h
+double gaussian_dev(int m, int n, double *p, double *deviates, double **derivs, void *private); +

A function that calculates the deviation between the values of a data set and a fitted Gaussian function. This function is formatted for use in MINPACK optimization.

+
+

Returns a value of zero and updates the deviates pointer. The derivs pointer is not used.

+
+ + +mult_gaussian_dev +src.lib/stats +
analysis/stats.h
+double mult_gaussian_dev(int m, int n, double *p, double *deviates, double **derivs, void *private); +

A function that calculates the deviation between the values of a data set and a fitted multi-peaked Gaussian function. This function is formatted for use in MINPACK optimization.

+
+

Returns a value of zero and updates the deviates pointer. The derivs pointer is not used.

+
+ + + +histogram +src.lib/stats +
analysis/stats.h
+void histogram(int nvals, float vals[], int nbin, float val_min, float val_max, int *hist_bins, float *leading_bin_val); +

The histogram function determines the number of values, provided by vals in a set of nbin bins. The maximum and minimum values to consider are constrained by val_min and val_max.

+
+

Returns the number of values in each bin through the hist_bins pointer and the value for the leading edge of each bin through the leading_bin_val pointer.

+
+ + +int_argrelmax +src.lib/stats +
analysis/stats.h
+int int_argrelmax(int num, int vals[], int order, int clip, int *ismax); +

The int_argrelmax function finds the relative maxima in a data set, vals. order specifies how many points on each side of a value should be considered for a comparison to be true and clip specifies how the edges of the data set should be treated. This routine expects evenly spaced data as input, such as the results of a function like histogram.

+
+

Returns the number of relative maxima as output and an array of booleans (True is 1 and False is 0) through the ismax pointer.

+

Based off of, but not identical to, the Python scipy hidden function _boolrelextrema.

+
+
+ + +int_argabsmax +src.lib/stats +
analysis/stats.h
+int int_argabsmax(int num, int vals[]); +

The int_argabsmax function finds the index of the absolute maximum for the integers in vals.

+
+

Returns the zero-ordered index of the maximum in vals.

+
+
+ + +float_absmax +src.lib/stats +
analysis/stats.h
+float float_absmax(int num, float vals[]) +

The float_absmax function finds the absolute maximum for the floating point decimals in vals.

+
+

Returns the the maximum from vals.

+
+
+ + +float_absmin +src.lib/stats +
analysis/stats.h
+float float_absmin(int num, float vals[]) +

The float_absmin function finds the absolute minimum for the floating point decimals in vals.

+
+

Returns the minimum from vals.

+
+
+ + +gammaq +src.lib/stats +
analysis/stats.h
+double gammaq(double a, double x); +

The gammaq function computes the incomplete upper gamma function using the most efficient method.

+
+

Returns the incomplete upper gamma function.

+
+

NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING.

+
+
+ + +gamma_series_rep +src.lib/stats +
analysis/stats.h
+void gamma_series_rep(double *gamser, double a, double x, double *gln); +

The gamma_series_rep function computes the incomplete upper gamma function using a series representation.

+
+

Returns the incomplete upper gamma function through the gamser pointer.

+
+

NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING.

+
+
+ + +gamma_continued_frac +src.lib/stats +
analysis/stats.h
+void gamma_continued_frac(double *gammcf, double a, double x, double *gln); +

The gamma_continued_frac function computes the incomplete upper gamma function as continued fractions.

+
+

Returns the incomplete upper gamma function through the gammcf pointer.

+
+

NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING.

+
+
+ + +gammln +src.lib/stats +
analysis/stats.h
+double gammln(double xx; +

The gammln function computes the log of the gamma function, preventing overflows in the gamma calcuation.

+
+

Returns the log of the gamma function.

+
+

NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING.

+
+
+ + + gauss_data + src.lib/stats +
analysis/stats.h
+ + + + double *x; + Pointer of independent data values. + + + + double *y; + Pointer of dependent data values. + + + + double *y_error; + Pointer of dependent data errors. + + + + + +

The struct gauss_data structure stores the data and errors used to fit a specified function using MINPACK.

+
+
+ +
diff --git a/codebase/analysis/src.lib/stats.1.0/include/stats.h b/codebase/analysis/src.lib/stats.1.0/include/stats.h new file mode 100644 index 000000000..76d9ce5fe --- /dev/null +++ b/codebase/analysis/src.lib/stats.1.0/include/stats.h @@ -0,0 +1,72 @@ +/* stats.h + ======= + Authors: Keith Kotyk - ISAS - 2015 and Angeline G. Burrell - NRL - 2021 + Copyright (C) 2016 SuperDARN Canada (gamma functions) + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#ifndef _STATS_H +#define _STATS_H + +#ifndef _MPFIT_H +#include "mpfit.h" +#endif + +#ifndef _SORT_H +#include "sort.h" +#endif + +#ifndef INFINITY +#define INFINITY 9.99E7 +#endif + +#ifndef ITMAX +#define ITMAX 100 +#endif + +#ifndef EPS +#define EPS 3.0e-7 +#endif + +#ifndef FPMIN +#define FPMIN 1.0e-30 +#endif + +struct gauss_data +{ + double *x; + double *y; + double *y_error; +}; + +int num_unique_int_vals(int num, int array[]); +int get_unique_str(int in_num, char **in_str, char **out_str); +float stdev_float(int num, float array[]); +void mean_stdev_float(int num, float array[], float *mean, float *stdev); +void zscore(int num, float array[], float *zscore); +double gaussian(double x, double *params); +double mult_gaussian(double x, double *params); +int gaussian_dev(int m, int n, double *p, double *deviates, double **derivs, + void *private); +int mult_gaussian_dev(int m, int n, double *p, double *deviates, + double **derivs, void *private); +void histogram(int nvals, float vals[], int nbin, float val_min, float val_max, + int *hist_bins, float *leading_bin_val); +int int_argrelmax(int num, int vals[], int order, int clip, int *ismax); +int int_argabsmax(int num, int vals[]); +float float_absmax(int num, float vals[]); +float float_absmin(int num, float vals[]); +double gammaq(double a, double x); +void gamma_series_rep(double *gamser, double a, double x, double *gln); +void gamma_continued_frac(double *gammcf, double a, double x, double *gln); +double gammln(double xx); + +#endif diff --git a/codebase/analysis/src.lib/stats.1.0/src/makefile b/codebase/analysis/src.lib/stats.1.0/src/makefile new file mode 100644 index 000000000..b80b4b2e8 --- /dev/null +++ b/codebase/analysis/src.lib/stats.1.0/src/makefile @@ -0,0 +1,24 @@ +# Makefile for the stats library +# ============================== +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/analysis -I../include +INC = $(IPATH)/analysis +OUTPUT = stats +DSTPATH = $(LIBPATH) + +SRC = stats.c +OBJS = $(SRC:.c=.o) + +LINK = "1" + +include $(MAKELIB).$(SYSTEM) + diff --git a/codebase/analysis/src.lib/stats.1.0/src/stats.c b/codebase/analysis/src.lib/stats.1.0/src/stats.c new file mode 100644 index 000000000..c11c90a82 --- /dev/null +++ b/codebase/analysis/src.lib/stats.1.0/src/stats.c @@ -0,0 +1,625 @@ +/* stats.c + ======= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include + +#include "mpfit.h" +#include "sort.h" +#include "stats.h" + +/** + * @brief Calculate the number of unique values for an integer array + * + * @params[in] num - Number of elements in `array` + * array - Data array with `num` elements + * + * @params[out] num_unique - Number of unique elements in `array` + **/ + +int num_unique_int_vals(int num, int array[]) +{ + int i, num_unique, *sorted_array; + + /* Initialize the sorted array and load it with the input data to */ + /* prevent the input array from being re-arranged. */ + sorted_array = (int *)calloc(num, sizeof(int)); + for(i = 0; i < num; i++) sorted_array[i] = array[i]; + + /* Sort the array */ + smart_sort_int(num, sorted_array); + + /* Count the number of unique elements */ + for(num_unique = 1, i = 1; i < num; i++) + { + if(sorted_array[i - 1] < sorted_array[i]) + num_unique++; + } + + free(sorted_array); + return(num_unique); +} + +/** + * @brief Take an array of strings and return an array of the unique strings + * + * @param[in] int_num Number of strings contained within in_str + * in_str Array of strings to evaluate + * + * @param[out] out_num Number of unique strings found within in_str + * out_str Array of unique strings + **/ + +int get_unique_str(int in_num, char **in_str, char **out_str) +{ + int i, j, out_num, match; + + out_num = 1; + strcpy(out_str[0], in_str[0]); + + for(i = 1; i < in_num; i++) + { + /* Look for a matching string */ + for(match = 0, j = 0; j < out_num && match == 0; j++) + { + if(strcmp(out_str[j], in_str[i]) == 0) match = 1; + } + + /* If there is no matching string, add this to the output */ + if(match == 0) + { + strcpy(out_str[out_num], in_str[i]); + out_num++; + } + } + + return(out_num); +} + +/** + * @brief Calculate the standard deviation + * + * @params[in] num - Number of elements in `array` + * array - Data array with `num` elements + * + * @params[out] stdev - Standard deviation of the input data, or zero if + * there isn't enough data for a calculation + **/ + +float stdev_float(int num, float array[]) +{ + int i; + + float sum, mean, stdev; + + if(num <= 1) + stdev = 0.0; + else + { + for(sum = 0.0, i = 0; i < num; i++) + sum += array[i]; + + mean = sum / (float)num; + + for(sum = 0.0, i = 0; i < num; i++) + sum += pow(array[i] - mean, 2); + + stdev = sqrt(sum / (float)num); + } + + return(stdev); +} + +/** + * @brief Calculate the mean and standard deviation + * + * @params[in] num - Number of elements in `array` + * array - Data array with `num` elements + * + * @params[out] mean - Arithmatic mean of the input data, or zero if no data + * stdev - Standard deviation of the input data, or zero if + * there isn't enough data for a calculation + **/ + +void mean_stdev_float(int num, float array[], float *mean, float *stdev) +{ + int i; + + float sum; + + /* Ensure there is enough data to calculate a value */ + if(num <= 1) + { + /* A single value has no deviation, for no values both are zero */ + *mean = (num == 1) ? array[0] : 0.0; + *stdev = 0.0; + } + else + { + /* Calculate the mean */ + for(sum = 0.0, i = 0; i < num; i++) + sum += array[i]; + + *mean = sum / (float)num; + + for(sum = 0.0, i = 0; i < num; i++) + sum += pow(array[i] - *mean, 2); + + *stdev = sqrt(sum / (float)num); + } + + return; +} + +/** + * @brief Calculate the z-score + * + * @params[in] num - Number of elements in `array` + * array - Data array with `num` elements + * + * @params[out] zscore - z-score, a single float value + **/ + +void zscore(int num, float array[], float *zscore) +{ + int i; + + float mean, stdev; + + /* Get the mean and standard deviation */ + mean_stdev_float(num, array, &mean, &stdev); + + /* Calculate the z-score */ + for(i = 0; i < num; i++) + { + if(stdev == 0.0) zscore[i] = INFINITY; + else zscore[i] = (array[i] - mean) / stdev; + } + + return; +} + +/** + * @brief A Gaussian function for MINPACK optimization + * + * @params[in] x - Independent variable value + * params - Pointer holding amplitude, mean, and standard deviation + * + * @params[out] y - Result of Gaussian calculation + **/ + +double gaussian(double x, double *params) +{ + double y; + + y = params[0] * exp(-pow((x - params[1]), 2.0) + / (2.0 * params[2] * params[2])); + return(y); +} + +/** + * @brief A Multi-Gaussian function for MINPACK optimization + * + * @params[in] x - Independent variable value + * params - Pointer holding the number of gaussian peaks, followed + * by the amplitude, mean, and standard deviation for + * each peak. + * + * @params[out] y - Result of Gaussian calculation + **/ + +double mult_gaussian(double x, double *params) +{ + int i, imax; + + double y, nparams[3]; + + imax = (int)params[0]; + + for(y = 0.0, i = 0; i < imax; i++) + { + nparams[0] = params[1 + i * 3]; + nparams[1] = params[2 + i * 3]; + nparams[2] = params[3 + i * 3]; + y += gaussian(x, nparams); + } + + return y; +} + +/** + * @brief Calculates the deviation of a multi-gaussian function for minimization + * + * @params[in] m - Number of samples in `private` data structure + * n - Number of samples in `p` parameter pointer + * p - Parameter pointer (see mult_gaussian) + * private - Structure holding the input data + * + * @params[out] deviates - deviation between the model and data + * derivs - optional derivative values, not used + **/ + +int mult_gaussian_dev(int m, int n, double *p, double *deviates, + double **derivs, void *private) +{ + int i; + double *x, *y, *y_err; + + struct gauss_data *gdat = (struct gauss_data *)private; + + x = gdat->x; + y = gdat->y; + y_err = gdat->y_error; + + for(i = 0; i < m; i++) + deviates[i] = (y[i] - mult_gaussian(x[i], p)) / y_err[i]; + + return(0); +} + +/** + * @brief Calculates the deviation of a gaussian function for minimization + * + * @params[in] m - Number of samples in `private` data structure + * n - Number of samples in `p` parameter pointer + * p - Parameter pointer (amplitude, mean, standard deviation) + * private - Structure holding the input data + * + * @params[out] deviates - deviation between the model and data + * derivs - optional derivative values, not used + **/ + +int gaussian_dev(int m, int n, double *p, double *deviates, double **derivs, + void *private) +{ + int i; + double *x, *y, *y_err; + + struct gauss_data *gdat = (struct gauss_data *)private; + + x = gdat->x; + y = gdat->y; + y_err = gdat->y_error; + + for(i = 0; i < m; i++) + deviates[i] = (y[i] - gaussian(x[i], p)) / y_err[i]; + + return(0); +} + +/** + * @brief A histogram function + * + * @params[in] nvals - Number of values in `vals` array + * vals - Array of values + * nbin - Number of bins to use in histogram + * val_min - Minimum value to consider + * val_max - Maximum value to consider + * + * @params[out] hist_bins - Array of counts for values in this bin + * leading_bin_val - Array of values corresponding to the leading + * edge of the histogram bins + **/ + +void histogram(int nvals, float vals[], int nbin, float val_min, float val_max, + int *hist_bins, float *leading_bin_val) +{ + int i, ival; + + float val_inc, trailing_bin_val; + + /* Calculate the bin increment */ + val_inc = (val_max - val_min) / (float)nbin; + + /* Initalize the output */ + for(i = 0; i < nbin; i++) + { + leading_bin_val[i] = val_min + (float)i * val_inc; + hist_bins[i] = 0; + } + + /* Cycle through each bin, identifying the number of points in each */ + for(ival = 0; ival < nvals; ival++) + { + for(i = 0; i < nbin; i++) + { + trailing_bin_val = leading_bin_val[i] + val_inc; + if(leading_bin_val[i] <= vals[ival] && vals[ival] < trailing_bin_val) + { + hist_bins[i]++; + break; + } + } + } + + return; +} + +/** + * @brief Routine to find the relative maxima based on numpy _boolrelextrema + * + * @params[in] num - Number of samples in `vals` + * vals - Integer array of input values to be searched + * order - How many points to each side of a value to consider for + * a comparison to be true + * clip - 1 to treat the edge of the `vals` array as a hard edge, + * any other value to wrap the `vals` array + * + * @params[out] ismax - Array of booleans specifying which vals indices are + * a relative maxima + * nmax - Number of relative maxima identified + **/ + +int int_argrelmax(int num, int vals[], int order, int clip, int *ismax) +{ + int i, shift, iplus, iminus, nmax, val_plus, val_minus; + + /* Test the order input */ + if(order < 1) order = 1; + + /* Initialize the output and working variables*/ + for(i = 0; i < num; i++) ismax[i] = 0; + nmax = 0; + + /* Cycle through each order of consideration */ + for(shift = order; shift >= 1; shift--) + { + for(i = 0; i < num; i++) + { + iminus = i - shift; + iplus = i + shift; + + /* If the plus/minus indices extend beyond the array limits, */ + /* either clip them (keep them at the edge) or wrap them. */ + if(iminus < 0) + { + if(clip == 1) val_minus = vals[i] - 1; + else val_minus = vals[iminus + num]; + } + else val_minus = vals[iminus]; + + if(iplus >= num) + { + if(clip == 1) val_plus = vals[i] - 1; + else val_plus = vals[iplus - num]; + } + else val_plus = vals[iplus]; + + /* Evaluate the values, looking for a relative maximum */ + if(vals[i] > val_plus && vals[i] > val_minus) + { + if(ismax[i] == 0) + { + nmax++; + ismax[i] = 1; + } + } + else if(ismax[i] == 1) + { + ismax[i] = 0; + nmax--; + } + } + + /* If all potential relative maxima have been eliminated, exit */ + if(nmax == 0) return(nmax); + } + + return(nmax); +} + +/** + * @brief Routine to find the absolute maximum for int intput + * + * @params[in] num - Number of samples in `vals` + * vals - Integer array of input values to be searched + * + * @params[out] imax - Index of absolute maximum + **/ + +int int_argabsmax(int num, int vals[]) +{ + int i, imax; + + for(imax = 0, i = 1; i < num; i++) + { + if(vals[imax] < vals[i]) imax = i; + } + + return(imax); +} + + +/** + * @brief Routine to find the absolute maximum for float input + * + * @params[in] num - Number of samples in `vals` + * vals - Integer array of input values to be searched + * + * @params[out] max_val - Index of absolute maximum + **/ + +float float_absmax(int num, float vals[]) +{ + int i; + + float max_val; + + for(max_val = vals[0], i = 1; i < num; i++) + { + if(max_val < vals[i]) max_val = vals[i]; + } + + return(max_val); +} + + +/** + * @brief Routine to find the absolute minimum for float input + * + * @params[in] num - Number of samples in `vals` + * vals - Integer array of input values to be searched + * + * @params[out] min_val - Value absolute maximum + **/ + +float float_absmin(int num, float vals[]) +{ + int i; + + float min_val; + + min_val = vals[0]; + for(i = 1; i < num; i++) + { + if(min_val > vals[i]) min_val = vals[i]; + } + + return(min_val); +} + +/** + * @brief Computes the incomplete upper gamma function. + * + * Computes the incomplete upper gamma function using either series + * representation or continued fractions, depending on which will be faster. + * Directly taken from Numerical Recipies in C. Refer to text for more + * description. + * + * @references NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. + **/ + +double gammaq(double a, double x) +{ + double gamser = 0.0, gammcf = 0.0, gln = 0.0; + + if (x < 0.0 || a <= 0.0) return -1.0; + + if (x < (a + 1.0)) + { + gamma_series_rep(&gamser, a, x, &gln); + return 1.0 - gamser; + } + else + { + gamma_continued_frac(&gammcf, a, x, &gln); + return gammcf; + } +} + +/** + * @brief Computes the gamma function as a series representation + * + * Computes the gamma function as a series representation. Directly taken from + * Numerical Recipies in C. Refer to text for more description. + * + * @references NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. + **/ + +void gamma_series_rep(double *gamser, double a, double x, double *gln) +{ + int n; + double sum, del, ap; + + *gln = gammln(a); + + if (x <= 0.0) + { + if (x < 0.0) *gamser = 0.0; + return; + } + else + { + ap = a; + del = sum = 1.0 / a; + for (n = 1;n <= ITMAX; n++) + { + ++ap; + del *= x / ap; + sum += del; + if (fabs(del) < fabs(sum) * EPS) + { + *gamser = sum * exp(-x + a * log(x) - (*gln)); + return; + } + } + return; + } +} + +/** + * @brief Computes the gamma function as continued fractions + * + * Computes the gamma function as continued fractions. Directly taken from + * Numerical Recipies in C. Refer to text for more description. + * + * @references NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. + **/ + +void gamma_continued_frac(double *gammcf, double a, double x, double *gln) +{ + int i; + double an,b,c,d,del,h; + + *gln = gammln(a); + b = x + 1.0 - a; + c = 1.0 / FPMIN; + d = 1.0 / b; + h = d; + + for (i = 1; i <= ITMAX; i++) + { + an = -i * (i - a); + b += 2.0; + d = an * d + b; + if (fabs(d) < FPMIN) d = FPMIN; + c = b + an / c; + if (fabs(c) < FPMIN) c = FPMIN; + d = 1.0 / d; + del = d * c; + h *= del; + if (fabs(del-1.0) < EPS) break; + } + if (i > ITMAX) + *gammcf = exp(-x + a * log(x) - (*gln)) * h; +} + +/** + * @brief Computes log of gamma function. + * + * Computes the log of a gamma function to prevent overflows. Directely taken + * from Numerical Recipies in C. Refer to text for more description. + * + * @references NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. + **/ + +double gammln(double xx) +{ + double x, y, tmp, ser; + + static double cof[6] = {76.18009172947146, -86.50532032941677, + 24.01409824083091, -1.231739572450155, + 0.1208650973866179e-2, -0.5395239384953e-5}; + int j; + + y = x = xx; + tmp = x + 5.5; + tmp -= (x + 0.5) * log(tmp); + ser = 1.000000000190015; + + for (j = 0;j <= 5; j++) ser += cof[j] / ++y; + return -tmp + log(2.5066282746310005 * ser / x); +} diff --git a/codebase/general/src.lib/dmap.1.25/src/dmap.c b/codebase/general/src.lib/dmap.1.25/src/dmap.c index 7c9a040e1..bfbaff388 100644 --- a/codebase/general/src.lib/dmap.1.25/src/dmap.c +++ b/codebase/general/src.lib/dmap.1.25/src/dmap.c @@ -79,7 +79,6 @@ void DataMapFreeScalar(struct DataMapScalar *ptr) { (ptr->type==DATAMAP) && (*ptr->data.mptr !=NULL)) DataMapFree(*ptr->data.mptr); - if ((ptr->mode !=0) && (ptr->data.vptr !=NULL)) free(ptr->data.vptr); free(ptr); return; @@ -294,7 +293,7 @@ void DataMapFreeArray(struct DataMapArray *ptr) { char **v=NULL; for (n=0;ndim;n++) s=s*ptr->rng[n]; v=((char **) ptr->data.vptr); - for (n=0;nmode & 0x04) && (ptr->data.mptr !=NULL) && @@ -302,7 +301,7 @@ void DataMapFreeArray(struct DataMapArray *ptr) { int s=1,n; for (n=0;ndim;n++) s=s*ptr->rng[n]; for (n=0;ndata.mptr[n] !=NULL) - DataMapFree(ptr->data.mptr[n]); + DataMapFree(ptr->data.mptr[n]); } @@ -883,13 +882,13 @@ void DataMapFree(struct DataMap *ptr) { if (ptr==NULL) return; if (ptr->scl !=NULL) { for (s=0;ssnum;s++) { - DataMapFreeScalar(ptr->scl[s]); + DataMapFreeScalar(ptr->scl[s]); } free(ptr->scl); } if (ptr->arr !=NULL) { - for (a=0;aanum;a++) { - DataMapFreeArray(ptr->arr[a]); + for (a=0;aanum;a++) { + DataMapFreeArray(ptr->arr[a]); } free(ptr->arr); } diff --git a/codebase/general/src.lib/sort.1.0/docs/sort.doc.xml b/codebase/general/src.lib/sort.1.0/docs/sort.doc.xml new file mode 100644 index 000000000..05510220e --- /dev/null +++ b/codebase/general/src.lib/sort.1.0/docs/sort.doc.xml @@ -0,0 +1,123 @@ + + +general +sort +src.lib/sort + + + +smart_sort +src.lib/sort +
general/sort.h
+void smart_sort(int num, double array[]); +

The smart_sort function re-arranges the doubles provided in `array` (with length `num`) to be ordered from least to greatest using the fastest of two sorting algorithms.

+
+Numerical Recipes in C, 2nd Ed. +If there are problems assigning data to the subarrays, the routine will exit with -1. +
+ + +smart_argsort_float +src.lib/sort +
general/sort.h
+void smart_argsort_float(int num, float array[], int sortargs[]); +

The smart_argsort_float function maintains the order of the input data in `array` (with length `num`) and returns the zero-index integers needed to ordered input data from least to greatest in `sortargs`.

+
+Numerical Recipes in C, 2nd Ed. +If there are problems assigning data to the subarrays, the routine will exit with -1. +
+ + +smart_argsort_int +src.lib/sort +
general/sort.h
+void smart_argsort_int(int num, int array[], int sortargs[]); +

The smart_argsort_int function maintains the order of the input data in `array` (with length `num`) and returns the zero-index integers needed to ordered input data from least to greatest in `sortargs`.

+
+Numerical Recipes in C, 2nd Ed. +If there are problems assigning data to the subarrays, the routine will exit with -1. +
+ + +smart_sort_int +src.lib/sort +
general/sort.h
+void smart_sort_int(int num, int array[]); +

The smart_sort_int function +re-arranges the integers provided in `array` (with length `num`) to be ordered from least to greatest using the fastest of two sorting algorithms.

+
+Numerical Recipes in C, 2nd Ed. +If there are problems assigning data to the subarrays, the routine will exit with -1. +
+ + +straight_sort +src.lib/sort +
general/sort.h
+void straight_sort(int num, double array[]); +

The straight_sort function +re-arranges the doubles provided in `array` (with length `num`) to be ordered from least to greatest.

+

This function uses the straight insertion method for sorting. This is an N2 method, best for N (`num`) less than 20.

+
+Numerical Recipes in C, 2nd Ed. +
+ + +straight_sort_int +src.lib/sort +
general/sort.h
+void straight_sort_int(int num, int array[]); +

The straight_sort_int function re-arranges the integers provided in `array` (with length `num`) to be ordered from least to greatest.

+

This function uses the straight insertion method for sorting. This is an N2 method, best for N (`num`) less than 20.

+
+Numerical Recipes in C, 2nd Ed. +
+ + +straight_argsort +src.lib/sort +
general/sort.h
+void straight_argsort(short int num, int array[], int argout[]); +

The straight_argsort function maintains the integers provided in `array` (with length `num`) and provides the zero-indexed integers needed to order the input from least to greatest in `argout`.

+

This function uses the straight insertion method for sorting. This is an N2 method, best for N (`num`) less than 20.

+
+Numerical Recipes in C, 2nd Ed. +
+ + +quicksort +src.lib/sort +
general/sort.h
+void quicksort(int num, double array[]); +

The quicksort function re-arranges the doubles provided in `array` (with length `num`) to be ordered from least to greatest.

+

This function is typically the fastest sorting algorithm for large N (`num`).

+
+If there are problems assigning data to the subarrays, the routine will exit with -1. +Numerical Recipes in C, 2nd Ed. +
+ + +quicksort_int +src.lib/sort +
general/sort.h
+void quicksort_int(int num, int array[]); +

The quicksort_int function re-arranges the integers provided in `array` (with length `num`) to be ordered from least to greatest.

+

This function is typically the fastest sorting algorithm for large N (`num`).

+
+If there are problems assigning data to the subarrays, the routine will exit with -1. +Numerical Recipes in C, 2nd Ed. +
+ + +quickargsort +src.lib/sort +
general/sort.h
+void quickargsort(int num, double array[], int argout[]); +

The quickargsort function maintains the doubles provided in `array` (with length `num`) and provides an array of zero-indexed integers that will order the input data from least to greatest in `argout`.

+

This function is typically the fastest sorting algorithm for large N (`num`).

+
+If there are problems assigning data to the subarrays, the routine will exit with -1. +Numerical Recipes in C, 2nd Ed. +
+ +
diff --git a/codebase/general/src.lib/sort.1.0/include/sort.h b/codebase/general/src.lib/sort.1.0/include/sort.h new file mode 100644 index 000000000..c0800589c --- /dev/null +++ b/codebase/general/src.lib/sort.1.0/include/sort.h @@ -0,0 +1,49 @@ +/* sort.h + ====== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#ifndef _SORT_H +#define _SORT_H + +#ifndef SWAP +#define SWAP(a,b) temp=(a);(a)=(b);(b)=temp; +#endif + +#ifndef SIGN +#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) +#endif + +#ifndef SHIFT +#define SHIFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d); +#endif + +#ifndef NSTACK +#define NSTACK 50 +#endif + +#ifndef MSTACK +#define MSTACK 7 +#endif + +void smart_sort(int num, double array[]); +void smart_argsort_float(int num, float array[], int sortargs[]); +void smart_sort_int(int num, int array[]); +void straight_sort(short int num, double array[]); +void straight_sort_int(short int num, int array[]); +void straight_argsort(short int num, double array[], int argout[]); +void smart_argsort_int(int num, int array[], int sortargs[]); +void quicksort(int num, double array[]); +void quicksort_int(int num, int array[]); +void quickargsort(int num, double array[], int argout[]); + +#endif diff --git a/codebase/general/src.lib/sort.1.0/src/makefile b/codebase/general/src.lib/sort.1.0/src/makefile new file mode 100644 index 000000000..f2ce19f44 --- /dev/null +++ b/codebase/general/src.lib/sort.1.0/src/makefile @@ -0,0 +1,23 @@ +# Makefile for sort library +# ========================= +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I../include +INC = $(IPATH)/general +DSTPATH = $(LIBPATH) +OUTPUT = sort + +SRC = sort.c +OBJS = $(SRC:.c=.o) + +LINK = "1" + +include $(MAKELIB).$(SYSTEM) diff --git a/codebase/general/src.lib/sort.1.0/src/sort.c b/codebase/general/src.lib/sort.1.0/src/sort.c new file mode 100644 index 000000000..b379e4018 --- /dev/null +++ b/codebase/general/src.lib/sort.1.0/src/sort.c @@ -0,0 +1,574 @@ +/* sort.c + ====== + Author: Angeline G. Burrell - UTDallas, NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include + +#include "sort.h" + +/** + * @brief Sorts input using the most effecient of the available sort routines + * + * @params[in] num - Number of values in input array + * array - Array of double values to sort, has length `num` + * + * @notes Rearranges input in `array` to be ordered from least to greatest + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void smart_sort(int num, double array[]) +{ + if(num < MSTACK) straight_sort((short int)num, array); + else quicksort(num, array); + + return; +} + +/** + * @brief Returns the indices that would sort the input array + * + * @params[in] num - number of values in input `array` + * array - input data array of float values with length `num` + * + * @params[out] sortargs - array of length `num` containing the zero-index + * integers needed to sort `array` + * + * @notes Does not sort the input array + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void smart_argsort_float(int num, float array[], int sortargs[]) +{ + int i; + double *sorted_array; + + sorted_array = (double *)calloc(num, sizeof(double)); + for(i = 0; i < num; i++) sorted_array[i] = (double)array[i]; + + if(num < MSTACK) straight_argsort((short int)num, sorted_array, sortargs); + else quickargsort(num, sorted_array, sortargs); + + return; +} + +/** + * @brief Returns the indices that would sort the input array + * + * @params[in] num - number of values in input `array` + * array - input data array of integer values with length `num` + * + * @params[out] sortargs - array of length `num` containing the zero-index + * integers needed to sort `array` + * + * @notes Does not sort the input array + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void smart_argsort_int(int num, int array[], int sortargs[]) +{ + int i; + double *sorted_array; + + sorted_array = (double *)calloc(num, sizeof(double)); + for(i = 0; i < num; i++) sorted_array[i] = (double)array[i]; + + if(num < MSTACK) straight_argsort((short int)num, sorted_array, sortargs); + else quickargsort(num, sorted_array, sortargs); + + return; +} + +/** + * @brief Sorts input using the most effecient of the available sort routines + * + * @params[in] num - Number of values in input array + * array - Array of integer values to sort, has length `num` + * + * @notes Rearranges input in `array` to be ordered from least to greatest + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void smart_sort_int(int num, int array[]) +{ + if(num < MSTACK) straight_sort_int((short int)num, array); + else quicksort_int(num, array); + + return; +} + +/** + * @brief Straight insertion method for sorting, N^2 method, best for N < 20. + * + * @params[in] num - Number of values in input array + * array - Array of double values to sort, has length `num` + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void straight_sort(short int num, double array[]) +{ + int i, j; + + double array_val; + + for(j = 1; j < num; j++) + { + array_val = array[j]; + i = j - 1; + + /* Search for the proper place to insert a */ + + while(i >= 0 && array[i] > array_val) + { + array[i + 1] = array[i]; + i--; + } + + /* Insert a */ + + array[i + 1] = array_val; + } + + return; +} + +/** + * @brief Straight insertion method for sorting; N^2 method, best for N < 20. + * + * @params[in] num - Number of values in input array + * array - Array of integer values to sort, has length `num` + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void straight_sort_int(short int num, int array[]) +{ + int i, j, array_val; + + for(j = 1; j < num; j++) + { + array_val = array[j]; + i = j - 1; + + /* Search for the proper place to insert a */ + while(i >= 0 && array[i] > array_val) + { + array[i + 1] = array[i]; + i--; + } + + /* Insert the held array value into its new location */ + array[i + 1] = array_val; + } + + return; +} + +/** + * @brief Straight insertion method for sorted; N^2 method, best for N < 20. + * + * @params[in] num - length of the input array + * array - input data that will be sorted + * + * @params[out] argout - sorted indices that would sort the unsorted input + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void straight_argsort(short int num, double array[], int argout[]) +{ + int i, j, ival; + + double array_val; + + /* Initialize the arguement output array */ + for(i = 0; i < num; i++) + argout[i] = i; + + /* Cycle through the array, starting at the second point */ + for(j = 1; j < num; j++) + { + array_val = array[j]; + ival = argout[j]; + i = j - 1; + + /* Search for the proper place to insert a */ + while(i >= 0 && array[i] > array_val) + { + array[i + 1] = array[i]; + argout[i + 1] = argout[i]; + i--; + } + + /* Insert the held array value and value index */ + array[i + 1] = array_val; + argout[i + 1] = ival; + } + + return; +} + +/** + * @brief Sorts data, typically the fasted sorting algorithm for large N. + * + * @params[in] num - length of the input array + * array - input data that will be sorted + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void quicksort(int num, double array[]) +{ + int jstack = -1, i, ir = num - 1, j, k, l = 0, *istack; + + double temp, array_val; + + istack = (int *)calloc(NSTACK, sizeof(int)); + + for(;;) + { + if(ir - l < MSTACK) + { + /* Use insertion sort once subarray is small enough */ + for(j = l + 1; j <= ir; j++) + { + array_val = array[j]; + + for(i = j - 1; i >= l; i--) + { + if(array[i] <= array_val) break; + array[i + 1] = array[i]; + } + + array[i + 1] = array_val; + } + + if(jstack == 0) break; + + /* Pop stack and begin a new round of partitioning */ + ir = istack[jstack--]; + l = istack[jstack--]; + } + else + { + /* Choose median of left, center and right elements as */ + /* partitioning element `array_val`. Also rearrange */ + /* so that array[l-1] <= array[l] <= array[ir-1] */ + k = (l + ir) >> 1; + SWAP(array[k], array[l + 1]); + + /* NOTE: compilation error if parenthesis excluded in if statements */ + if(array[l] > array[ir]) + { + SWAP(array[l], array[ir]); + } + if(array[l + 1] > array[ir]) + { + SWAP(array[l + 1], array[ir]); + } + if(array[l] > array[l + 1]) + { + SWAP(array[l], array[l + 1]); + } + + /* Inistialize pointers for partitioning */ + i = l + 1; + j = ir; + array_val = array[l + 1]; + + /* Beginning of innermost loop, scanning up and down to find */ + /* elements > array_val and < array_val */ + for(;;) + { + do i++; while(array[i] < array_val); + do j--; while(array[j] > array_val); + + if(j < i) break; + + SWAP(array[i], array[j]); + } + + array[l + 1] = array[j]; + array[j] = array_val; + jstack += 2; + + /* Push pointers to larger subarray on stack, process smaller */ + /* subarray immediately */ + if(jstack > NSTACK) + { + printf("%s ERROR: stack size of subarray too small [%d < %d]\n", + "quicksort", NSTACK, jstack); + exit(-1); + } + + if(ir - i + 1 >= j - 1) + { + istack[jstack] = ir; + istack[jstack - 1] = i; + ir = j - 1; + } + else + { + istack[jstack] = j - 1; + istack[jstack - 1] = l; + l = i; + } + } + } + + free(istack); + return; +} + +/** + * @brief Sorts int data, typically the fasted sorting algorithm for large N. + * + * @params[in] num - length of the input array + * array - input data that will be sorted + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void quicksort_int(int num, int array[]) +{ + int temp, array_val, jstack = -1, i, ir = num - 1, j, k, l = 0, *istack; + + istack = (int *)calloc(NSTACK, sizeof(int)); + + for(;;) + { + if(ir - l < MSTACK) + { + /* Use insertion sort once subarray is small enough */ + for(j = l + 1; j <= ir; j++) + { + array_val = array[j]; + + for(i = j - 1; i >= l; i--) + { + if(array[i] <= array_val) break; + array[i + 1] = array[i]; + } + + array[i + 1] = array_val; + } + + if(jstack == -1) break; + + /* Pop stack and begin a new round of partitioning */ + ir = istack[jstack--]; + l = istack[jstack--]; + } + else + { + /* Choose median of left, center and right elements as */ + /* partitioning element `array_val`. Also rearrange */ + /* so that array[l-1] <= array[l] <= array[ir-1] */ + k = (l + ir) >> 1; + SWAP(array[k], array[l + 1]); + + /* NOTE: compilation error if parenthesis excluded in if statements */ + if(array[l] > array[ir]) + { + SWAP(array[l], array[ir]); + } + if(array[l + 1] > array[ir]) + { + SWAP(array[l + 1], array[ir]); + } + if(array[l] > array[l + 1]) + { + SWAP(array[l], array[l + 1]); + } + + /* Initialize pointers for partitioning */ + i = l + 1; + j = ir; + array_val = array[l + 1]; + + /* Beginning of innermost loop, scanning up and down to find */ + /* elements > array_val and < array_val */ + for(;;) + { + do i++; while(array[i] < array_val); + do j--; while(array[j] > array_val); + + if(j < i) break; + + SWAP(array[i], array[j]); + } + + array[l + 1] = array[j]; + array[j] = array_val; + jstack += 2; + + /* Push pointers to larger subarray on stack, process smaller */ + /* subarray immediately */ + if(jstack > NSTACK) + { + printf("%s ERROR: stack size of subarray too small [%d < %d]\n", + "quicksort_int", NSTACK, jstack); + exit(-1); + } + + if(ir - i + 1 >= j - 1) + { + istack[jstack] = ir; + istack[jstack - 1] = i; + ir = j - 1; + } + else + { + istack[jstack] = j - 1; + istack[jstack - 1] = l; + l = i; + } + } + } + + free(istack); + return; +} + +/** + * @brief Sorts data, typically the fasted sorting algorithm for large N. + * + * @params[in] num - length of the input array + * array - input data that will be sorted + * + * @params[out] argout - sorted indices that would sort the unsorted input + * + * @reference Numerical Recipes in C, 2nd Ed. + **/ + +void quickargsort(int num, double array[], int argout[]) +{ + int ival, jstack = -1, i, ir = num - 1, j, k, l = 0, *istack; + + double temp, array_val; + + /* Initialize the stack and the sorted index output */ + istack = (int *)calloc(NSTACK, sizeof(int)); + for(i = 0; i < num; i++) + argout[i] = i; + + for(;;) + { + if(ir - l < MSTACK) + { + /* Use insertion sort once subarray is small enough */ + for(j = l + 1; j <= ir; j++) + { + array_val = array[j]; + ival = argout[j]; + + for(i = j - 1; i >= l; i--) + { + if(array[i] <= array_val) break; + array[i + 1] = array[i]; + argout[i + 1] = argout[i]; + } + + array[i + 1] = array_val; + argout[i + 1] = ival; + } + + if(jstack == 0) break; + + /* Pop stack and begin a new round of partitioning */ + ir = istack[jstack--]; + l = istack[jstack--]; + } + else + { + /* Choose median of left, center and right elements as */ + /* partitioning element `array_val`. Also rearrange */ + /* so that array[l-1] <= array[l] <= array[ir-1] */ + k = (l + ir) >> 1; + SWAP(array[k], array[l + 1]); + SWAP(argout[k], argout[l + 1]); + + /* NOTE: compilation error if parenthesis excluded in if statements */ + if(array[l] > array[ir]) + { + SWAP(array[l], array[ir]); + SWAP(argout[l], argout[ir]); + } + if(array[l + 1] > array[ir]) + { + SWAP(array[l + 1], array[ir]); + SWAP(argout[l + 1], argout[ir]); + } + if(array[l] > array[l + 1]) + { + SWAP(array[l], array[l + 1]); + SWAP(argout[l], argout[l + 1]); + } + + /* Inistialize pointers for partitioning */ + i = l + 1; + j = ir; + array_val = array[l + 1]; + ival = argout[l + 1]; + + /* Beginning of innermost loop, scanning up and down to find */ + /* elements > array_val and < array_val */ + for(;;) + { + do i++; while(array[i] < array_val); + do j--; while(array[j] > array_val); + + if(j < i) break; + + SWAP(array[i], array[j]); + SWAP(argout[i], argout[j]); + } + + array[l + 1] = array[j]; + array[j] = array_val; + argout[l + 1] = argout[j]; + argout[j] = ival; + jstack += 2; + + /* Push pointers to larger subarray on stack, process smaller */ + /* subarray immediately */ + if(jstack > NSTACK) + { + printf("%s ERROR: stack size of subarray too small [%d < %d]\n", + "quicksort", NSTACK, jstack); + exit(-1); + } + + if(ir - i + 1 >= j - 1) + { + istack[jstack] = ir; + istack[jstack - 1] = i; + ir = j - 1; + } + else + { + istack[jstack] = j - 1; + istack[jstack - 1] = l; + l = i; + } + } + } + + free(istack); + return; +} diff --git a/codebase/general/src.lib/time.1.7/src/time.c b/codebase/general/src.lib/time.1.7/src/time.c index 998d7cf63..c745e95f3 100644 --- a/codebase/general/src.lib/time.1.7/src/time.c +++ b/codebase/general/src.lib/time.1.7/src/time.c @@ -108,13 +108,13 @@ void TimeYrsecToYMDHMS(int yrsec,int yr,int *mo,int *dy,int *hr,int *mn, } -double TimeYMDHMSToEpoch(int yr,int mo,int dy,int hr,int mn,double sec) { - +double TimeYMDHMSToEpoch(int yr, int mo, int dy, int hr, int mn, double sec) +{ time_t clock; struct tm tm; char *tz; - memset(&tm,0,sizeof(struct tm)); + memset(&tm, 0, sizeof(struct tm)); tm.tm_year=yr-1900; tm.tm_mon=mo-1; tm.tm_mday=dy; diff --git a/codebase/superdarn/src.bin/tk/reformat/fitmultbsidtoascii.1.0/fitmultbsidtoascii.c b/codebase/superdarn/src.bin/tk/reformat/fitmultbsidtoascii.1.0/fitmultbsidtoascii.c new file mode 100644 index 000000000..a13a1cc0a --- /dev/null +++ b/codebase/superdarn/src.bin/tk/reformat/fitmultbsidtoascii.1.0/fitmultbsidtoascii.c @@ -0,0 +1,156 @@ +/* fitmultbsidtoascii.c + ==================== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include + +#include "fitmultbsid.h" +#include "option.h" +#include "hlpstr.h" +#include "errstr.h" + +struct OptionData opt; + +/** + * Outputs an error statement for an unrecognized input option + **/ + +int rst_opterr(char *txt) +{ + fprintf(stderr, "Option not recognized: %s\n", txt); + fprintf(stderr, "Please try: fitmultbsidtoascii --help\n"); + return(-1); +} + +/** + * Load the command line options + **/ + +int command_options(int argc, char *argv[]) +{ + /* Initialize input options */ + int farg=0; + unsigned char help=0, option=0, version=0; + + int rst_opterr(char *txt); + + /* If only information is desired, print it out and exit */ + OptionAdd(&opt, "-help", 'x', &help); + OptionAdd(&opt, "-option", 'x', &option); + OptionAdd(&opt, "-version", 'x', &version); + + /* Process command line options */ + farg = OptionProcess(1, argc, argv, &opt, rst_opterr); + + /* If 'help' set then print help message */ + if(help==1) + { + OptionPrintInfo(stdout, hlpstr); + exit(0); + } + + /* If 'version' set, then print the version number */ + if(version==1) + { + OptionVersion(stdout); + exit(0); + } + + /* If 'option' set then print all command line options */ + if(option==1) + { + OptionDump(stdout, &opt); + exit(0); + } + + /* If command line option not recognized then print error and exit */ + if(farg == -1) exit(-1); + + if(farg == argc) + { + OptionPrintInfo(stderr, errstr); + exit(-1); + } + + return farg; +} + +/** + * Reads in a binary FitMultBSID file and outputs an ASCII file + **/ + +int main(int argc, char *argv[]) +{ + int inum, len, fnum, farg, status; + + FILE *fp=NULL; + + struct FitMultBSID *mult_bsid; + + /* Initialize file information */ + char **dnames=NULL; + + /* Declare local subroutines */ + int command_options(int argc, char *argv[]); + + /* Process the command line options */ + farg = command_options(argc, argv); + + /* Make a list of input files */ + fnum = argc - farg; + if(fnum == 0) + { + fprintf(stderr, "must provide input file(s) to read\n"); + exit(1); + } + else + { + dnames = (char **)malloc(sizeof(char *) * fnum); + + for(inum = 0; inum < fnum; inum++) + { + len = strlen(argv[inum + argc - fnum]); + dnames[inum] = (char *)malloc(sizeof(char) * (len + 1)); + strcpy(dnames[inum], argv[argc - fnum + inum]); + } + } + + /* Initialize and load the binary data */ + mult_bsid = FitMultBSIDMake(); + + /* Read in each file */ + for(status = 0, inum = 0; inum < fnum && status >= 0; inum++) + { + if((fp = fopen(dnames[inum], "r")) == NULL) + { + fprintf(stderr, "unable to open input file [%s]\n", dnames[inum]); + exit(1); + } + status = ReadFitMultBSIDBin(fp, mult_bsid); + } + + /* Write the output in ASCII format */ + if(mult_bsid->num_scans > 0) + WriteFitMultBSIDASCII(stdout, mult_bsid); + + /* Free the data structure pointer */ + FitMultBSIDFree(mult_bsid); + + /* Free the remaining pointers */ + for(inum = 0; inum < fnum; inum++) free(dnames[inum]); + free(dnames); + + return(status); +} diff --git a/codebase/superdarn/src.bin/tk/reformat/fitmultbsidtoascii.1.0/makefile b/codebase/superdarn/src.bin/tk/reformat/fitmultbsidtoascii.1.0/makefile new file mode 100644 index 000000000..6075eda0a --- /dev/null +++ b/codebase/superdarn/src.bin/tk/reformat/fitmultbsidtoascii.1.0/makefile @@ -0,0 +1,33 @@ +# Makefile for make_fov +# ===================== +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I$(IPATH)/analysis -I$(IPATH)/base -I$(IPATH)/general \ + -I$(IPATH)/superdarn -I../include/ + +SRC = fitmultbsidtoascii.c + +OBJS = $(SRC:.c=.o) + +INC=$(IPATH)/superdarn + +DSTPATH = $(BINPATH) + +OUTPUT = fitmultbsidtoascii + +LIBS = -lchannel.1 -lfitmultbsid.1.0 -lrpos.1 -lfit.1 -lrscan.1 -lradar.1 \ + -ldmap.1 -lopt.1 -lrtime.1 -lrcnv.1 -ligrf.1 -laacgm_v2.1 -ligrf_v2.1 \ + -lastalg.1 + +SLIB = -lm -lz + +include $(MAKEBIN).$(SYSTEM) diff --git a/codebase/superdarn/src.bin/tk/tool/cat_fit.1.12/makefile b/codebase/superdarn/src.bin/tk/tool/cat_fit.1.12/makefile index 0fc59405f..652ba15a2 100644 --- a/codebase/superdarn/src.bin/tk/tool/cat_fit.1.12/makefile +++ b/codebase/superdarn/src.bin/tk/tool/cat_fit.1.12/makefile @@ -13,6 +13,6 @@ DSTPATH = $(BINPATH) OUTPUT = cat_fit LIBS=-lfit.1 -lcfit.1 -lradar.1 -loldfit.1 -lrscan.1 -lopt.1 -ldmap.1 -lrtime.1 -lrcnv.1 SLIB=-lm -lz - + include $(MAKEBIN).$(SYSTEM) diff --git a/codebase/superdarn/src.bin/tk/tool/grid_filter.1.7/makefile b/codebase/superdarn/src.bin/tk/tool/grid_filter.1.7/makefile index 72f2e5189..e6cf82680 100644 --- a/codebase/superdarn/src.bin/tk/tool/grid_filter.1.7/makefile +++ b/codebase/superdarn/src.bin/tk/tool/grid_filter.1.7/makefile @@ -13,6 +13,6 @@ OUTPUT = grid_filter LIBS= -lgrd.1 -loldgrd.1 -lrfile.1 -ldmap.1 -lopt.1 -lrtime.1 -lrcnv.1 SLIB= -lm -lz - + include $(MAKEBIN).$(SYSTEM) diff --git a/codebase/superdarn/src.bin/tk/tool/make_fit/makefile b/codebase/superdarn/src.bin/tk/tool/make_fit/makefile index 197a272cf..141c19592 100644 --- a/codebase/superdarn/src.bin/tk/tool/make_fit/makefile +++ b/codebase/superdarn/src.bin/tk/tool/make_fit/makefile @@ -24,15 +24,15 @@ include $(MAKECFG).$(SYSTEM) -INCLUDE=-I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/superdarn +INCLUDE=-I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/analysis -I$(IPATH)/superdarn OBJS = make_fit.o SRC=hlpstr.h errstr.h make_fit.c DSTPATH = $(BINPATH) OUTPUT = make_fit -LIBS=-loldraw.1 -loldfit.1 -lcfit.1 -lrscan.1 -lradar.1 -lfitacf.1 -lfitacf.3.0 -lfitacfex2.1 -lfitacfex.1 -llmfit.1 -lelevation.1 -lraw.1 -lfit.1 -ldmap.1 -lopt.1 -lrtime.1 -lrcnv.1 -lrmath.1 -lmpfit.1 +LIBS=-loldraw.1 -loldfit.1 -lcfit.1 -lrscan.1 -lradar.1 -lfitacf.1 -lfitacf.3.0 -lfitacfex2.1 -lfitacfex.1 -llmfit.1 -lelevation.1 -lraw.1 -lfit.1 -ldmap.1 -lopt.1 -lrtime.1 -lrcnv.1 -lrmath.1 -lmpfit.1 -lstats.1 -lsort.1 SLIB=-lm -lz -lpthread - + include $(MAKEBIN).$(SYSTEM) diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/docs/make_fov.doc.xml b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/docs/make_fov.doc.xml new file mode 100644 index 000000000..7bf93ac92 --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/docs/make_fov.doc.xml @@ -0,0 +1,132 @@ + + +superdarn +make_fov +src.bin/tk/tool/make_fov + + +make_fov --help +make_fov [options] fitacfname [inxname] +make_fov -old [options] fitname [inxname] +make_fov [options] fitacfnames... +make_fov -old [options] fitnames... +make_fov -vb -ascii -ns -sd yyyymmdd -st hr:mn -ed yyyymmdd -et hr:mn -ex hr:mn -tl tlen -cn a/b -tfmin frequency -tfmax frequency -tdiff-update -tdiff calibration -dhmin D region height min -dhmax D region height max -ehmax E region height max -fhmax F region height max filenames + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Creates an enhanced fitacf format file for a single radar site with the correct backscatter return direction from either a fit or fitacf format file.

+

Creates an fitacf format file with additional flags that denote the correct backscatter return direction and updated elevation angles for a single radar site from either a fit or fitacf format file.

+

The return direction is determined by examining the variations in elevation angle across the field-of-view (FoV), with ground and ionospheric backscatter examined seperately. Backscatter are also grouped into different propagation paths (by hop and ionospheric region) using virtual height limits. These limits vary from radar to radar, and care should be taken when choosing the limits for each radar. The default limits were tested for CLY and INV. The limits at HAN are the same, but with fhmax set to 900km.

+

The algorithm (Burrell et al. 2015) optionally allows the user to specify the frequency bands, update the interferometer calibration (TDIFF), and specify whether badly identified groundscatter should be treated as ionospheric scatter for the purposes of calculating the origin FoV. Most radars use either a 300 kHz or 500 kHz bandwidth, so if no frequency band is specified they will be determined using a 300 kHz band width.

+

After determining the return direction, text lines are written to standard output.

+

The program accepts multiple fit files as input. If more than one input file is provided, the program will concatenate them together for processing. Note that only fit files from a single radar site may be concatenated.

+
+ + +make_fov -vb -tfmin 10000 -tfmax 12000 -update-tdiff -tdiff -0.010500 20170708.2001.00.cly.fitacf3 > 20170708.2001.00.cly.10_12.fov +Generate a binary field-of-view file from a FitACF v3.0 file "20170708.2001.00.cly.fitacf3" and store it in the file "20170708.2001.00.cly.10_12.fov". This file only processes transmission frequencies between 10 and 12 MHz and uses a TDIFF value for this radar and frequency band calculated using the Chisham Meteor Method. Reports the status on standard error. + + + +make_fov -old -bandwidth 600 20000510.*.kod.fit > 20000510.kod.600bw.fov +Concatenate all the old fit files that meet the date and radar criteria in the current directory to create a field-of-view file with 600 kHz frequency bands. Store the output in the file "20000510.kod.600bw.fov". + + + +make_fov -ascii -bandwidth 300 -cn a -fhmax 900 19960916.0400.00.han.fit > 19960916.0400.00.a.han.300bw.fov_txt +Generate a text field-of-view file from the fit file "19960916.0400.00.han.fit". Uses a 300 kHz bandwidth, only data from STEREO channel a, and changes the F-region virtual height maximum from 750 km to 900 km, as is appropriate for this radar. Store an extended format grid file in "19960916.0400.00.a.han.300bw.fov_txt" + + + +
diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/eval_groundscatter.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/eval_groundscatter.c new file mode 100644 index 000000000..0b711d1eb --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/eval_groundscatter.c @@ -0,0 +1,175 @@ +/* eval_groundscatter.c + ==================== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include + +#include "fitmultbsid.h" + +/** + * @brief Set the new groundscatter flag 'gflg' + * + * @param[in] beam - radar beam structure + * + * @notes Criteria: + * - power above 0 + * - gflg of 1 + * - range gate above 10 for any positive power + * - range gate below 10 and between 0.0-5.0 dB power + * - at least half of backscatter in a 10 range gate box is groundscatter + * - at least 3 groundscatter points are found in a 10 range gate box + **/ + +void EvalGroundScatter(struct FitBSIDBeam *beam) +{ + int irg, gflg, min_rg, max_rg, box_width, npnts, nmin; + + float max_power, gflg_frac, gs_tol; + + int CheckGroundScatter(int rg, int gflg, float slant_dist, float power, + int min_rg, int max_rg, float max_power); + float CalcFracGroundScatter(int box_width, int icenter, + struct FitBSIDBeam *beam, int *npnts); + + /* Set the evaluation defaults */ + min_rg = 10; + max_rg = beam->nrang; + max_power = 5.0; + box_width = 5; + gs_tol = 0.5; + nmin = 3; + + /* Check each groundscatter flag, looking for bad values */ + for(irg = 0; irg < beam->nrang; irg++) + { + if(beam->sct[irg] == 1 && beam->rng_flgs[irg].gflg == 1) + { + gflg = CheckGroundScatter(irg, beam->rng_flgs[irg].gflg, + beam->front_loc[irg].dist, + beam->rng[irg].p_l, min_rg, max_rg, + max_power); + + /* Compare new flag with current flag, set groundscatter flag */ + /* to -1 if the groundscatter check failed */ + if(gflg != beam->rng_flgs[irg].gflg) beam->rng_flgs[irg].gflg = -1; + } + } + + /* After the single point check, remove any isolated groundscatter points */ + for(irg = 0; irg < beam->nrang; irg++) + { + if(beam->sct[irg] == 1 && beam->rng_flgs[irg].gflg == 1) + { + npnts = 0; + gflg_frac = CalcFracGroundScatter(box_width, irg, beam, &npnts); + + if(gflg_frac < gs_tol || npnts < nmin) beam->rng_flgs[irg].gflg = -1; + } + } + + return; +} + +/** + * @brief Single-point groundscatter quality evaluation + * + * @param[in] rg - range gate index + * gflg - GS flag (1=ground scatter, 0=ionospheric scatter) + * slant_dist - 1-hop slant distance in km + * power - signal power in dB + * min_rg - minimum range gate for D-region power considerations + * max_rg - maximum range gate + * max_power - maximum power for near-range gate groundscatter + * + * @param[out] out_flag - Returns 0 if GS check fails, 1 if it passes + * + * @notes Routine uses the following criteria to evaluate groundscatter status: + * - power above 0 + * - gflg of 1 + * - 1/2 hop distances closer than 160 km <- re-evaluate for h' 100 km? + * - range gate above min_rg for any positive power + * - range gate below min_rg and between 0.0 and max_power + **/ + +int CheckGroundScatter(int rg, int gflg, float slant_dist, float power, + int min_rg, int max_rg, float max_power) +{ + int out_gflg = 0; + + float min_slant_dist = 78; /* minimum slant distance to be ionospheric */ + + /* Ensure the scatter fits the standard groundscatter definition (slow */ + /* moving), has a positive power (successful fit), and has a slant */ + /* distance long enough to have refracted in the ionosphere. */ + if(gflg == 1 && power >= 0.0 && slant_dist > min_slant_dist) + { + if(rg < min_rg) + { + /* Ensure the power in the near-range gates */ + /* is low enough to not be meteor ablation. */ + if(power < max_power) out_gflg = 1; + } + else if(rg <= max_rg) out_gflg = 1; /* Maximum range gate to consider */ + } + + return(out_gflg); +} + + +/** + * @brief Proximity test for groundscatter along a beam + * + * @param[in] box_width - 1/2 size of box in range gates + * rg_center - range gate of central point + * beam - FitRange structured radar beam + * + * @param[out] npnts - number of points with groundscatter in box + * frac - fraction of points in range gate box that are GS + **/ + +float CalcFracGroundScatter(int box_width, int rg_center, + struct FitBSIDBeam *beam, int *npnts) +{ + int irg, num, min_box, max_box; + + float frac; + + /* Set the upper and lower range gate limits for the current box */ + min_box = rg_center - box_width; + max_box = rg_center + box_width; + + if(min_box < 0) min_box = 0; + if(max_box > beam->nrang) max_box = beam->nrang; + + /* Initialize the output */ + num = 0; + frac = 0.0; + + /* Cycle through the range gates in the box, updating the total number of */ + /* points and total number of groundscatter points */ + for(irg = min_box; irg < max_box; irg++) + { + if(beam->sct[irg] == 1) + { + num++; + if(beam->rng_flgs[irg].gflg == 1) frac += 1.0; + } + } + + /* Set the output */ + if(num > 0 && frac > 0.0) frac /= (float)num; + *npnts = num; + + return(frac); +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/load_fit_update_fov.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/load_fit_update_fov.c new file mode 100644 index 000000000..93e55f7f8 --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/load_fit_update_fov.c @@ -0,0 +1,324 @@ +/* load_fit_update_fov.c + ===================== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include +#include + +#include "rtypes.h" +#include "rtime.h" +#include "dmap.h" /* DMap library needs to go before rprm.h */ +#include "radar.h" +#include "rprm.h" +#include "llist.h" +#include "pthread.h" +#include "scandata.h" /* scandata.h needs to go before the various fitdata.h */ +#include "fitindex.h" +#include "fitdata.h" +#include "fitread.h" +#include "fitscan.h" +#include "fitseek.h" +#include "oldfitread.h" +#include "oldfitscan.h" +#include "fitmultbsid.h" + +/** + * @brief Load the fit data and determine the return direction + * + * @params[in] fnum - Number of files + * channel - Stereo channel number + * channel_fix - User-specified channel number + * old - Flag for old/new FitACF input + * tlen - Lenth of custon scan in seconds + * stime - Starting time + * sdate - Starting date + * etime - Ending time + * edate - Ending date + * extime - Time extent (zero to use start/end date-times) + * nsflg - If 1, exclude data where scan flag is -1 + * vb - Verbosity flag + * vbuf - Verbosity buffer + * iname - Index filename or NULL + * dnames - Array of filenames to open + * strict_gs - (1/0) Remove indeterminate backscatter (1) + * freq_min - Minimum allowed transmission frequency in kHz + * freq_max - Maximum transmission frequency limit in kHz + * min_pnts - Minimum number of points necessary to perfrom + * certain range gate or beam specific evaluations (3) + * D_nrg - Number of range gates for D-region box (2) + * E_nrg - Number of range gates for E-region box (5) + * F_nrg - Number of range gates for near F-region box (10) + * far_nrg - Number of range gates for far F-region box (20) + * D_rgmax - Maximum range gate for D-region box width (5) + * E_rgmax - Maximum range gate for E-region box width (25) + * F_rgmax - Maximum range gate for near F-region box width (40) + * D_hmin - Minimum h' for D-region in km (75) + * D_hmax - Maximum h' for D-region in km (115) + * E_hmax - Maximum h' for E-region in km (150) + * F_hmax - Minimum h' for F-region in km (450) + * D_vh_box - h' range for D-region box in km (40) + * E_vh_box - h' range for E-region box in km (35) + * F_vh_box - h' range for near F-region box in km (50) + * far_vh_box - h' range for far F-region box in km (150) + * max_hop - maximum number of hops to consider (3.0) + * + * @params[out] mult_bsid - Ouptut data structure + * ret_flg - Return status flag (-1 for an error) + **/ + +int load_fit_update_fov(int fnum, int channel, int channel_fix, int old, + int tlen, double stime, double sdate, double etime, + double edate, double extime, unsigned char nsflg, + unsigned char vb, char *vbuf, char *iname, + char **dnames, short int tdiff_flag, double tdiff, + short int strict_gs, int freq_min, int freq_max, + int min_pnts, int D_nrg, int E_nrg, int F_nrg, + int far_nrg, int D_rgmax, int E_rgmax, int F_rgmax, + float D_hmin, float D_hmax, float E_hmax, float F_hmax, + float D_vh_box, float E_vh_box, float F_vh_box, + float far_vh_box, float max_hop, + struct FitMultBSID *mult_bsid) +{ + int inum, yr = -1, mo = -1, dy = -1, hr = -1, mt = -1, ret_flg = 0, state = 0; + int syncflg = 1, site_flg = 0; + + double sc = 0.0; + + FILE *fp, *fitfp; + + struct RadarSite *site = NULL; + struct RadarParm *prm; + struct FitData *fit; + struct FitIndex *inx = NULL; + struct OldFitFp *oldfitfp = NULL; + struct RadarScan *scan; + + void UpdateScanBSFoV(short int strict_gs, int freq_min, int freq_max, + int min_pnts, int D_nrg, int E_nrg, int F_nrg, + int far_nrg, int D_rgmax, int E_rgmax, int F_rgmax, + float D_hmin, float D_hmax, float E_hmax, float F_hmax, + float D_vh_box, float E_vh_box, float F_vh_box, + float far_vh_box, float max_hop, struct RadarScan *scan, + struct RadarSite *hard, struct FitMultBSID *mult_bsid); + + /* Initialize radar parameter and fit structures. If you initialize `site` */ + /* it won't set properly. */ + scan = RadarScanMake(); + prm = RadarParmMake(); + fit = FitMake(); + + /* Cycle through all of the fit files */ + for(inum=0; inum < fnum; inum++) + { + /* Assign the input and index file names */ + fprintf(stderr, "Opening file:%s\n", dnames[inum]); + + /* Open the fit or fitacf file, reading the first scan */ + if(old) + { + /* Input file is in fit format. Open the fit file for reading */ + if((oldfitfp = OldFitOpen(dnames[inum], iname)) == NULL) + { + fprintf(stderr, "File not found.\n"); + exit(-1); + } + + /* Read first available radar scan in fit file (will use scan + flag if tlen not provided) */ + ret_flg = OldFitReadRadarScan(oldfitfp, &state, scan, prm, fit, + tlen, syncflg, channel); + + /* Verify that scan was properly read */ + if(ret_flg == -1) + { + fprintf(stderr,"Error reading file.\n"); + exit(-1); + } + } + else + { + /* Input file is in fitacf format. Check if index file provided */ + if(iname != NULL) + { + /* Open the index file for reading */ + if((fp = fopen(iname, "r")) == NULL) + fprintf(stderr, "Could not open index.\n"); + + else + { + if((inx = FitIndexFload(fp)) == NULL) + fprintf(stderr, "Error loading index.\n"); + fclose(fp); + } + } + + /* Open the fitacf file for reading */ + if((fitfp = fopen(dnames[inum], "r")) == NULL) + { + fprintf(stderr, "File not found.\n"); + exit(-1); + } + + /* Read first available radar scan in fitacf file (will use scan + flag if tlen not provided) */ + ret_flg = FitFreadRadarScan(fitfp, &state, scan, prm, fit, + tlen, syncflg, channel); + + /* Verify that scan was properly read */ + if(ret_flg == -1) + { + fprintf(stderr, "Error reading file.\n"); + exit(-1); + } + } + + /* If either start time or date not provided as input then determine it */ + if((stime != -1) || (sdate != -1)) + { + /* We must skip the start of the files. If start time not provided */ + /* then use time of first record in the fit file */ + if(stime==-1) stime = ((int)scan->st_time % (24 * 3600)); + + /* If start date not provided then use date of first record */ + /* in fit file, otherwise use provided sdate */ + if (sdate == -1) stime += scan->st_time - ((int)scan->st_time + % (24 * 3600)); + else stime += sdate; + + /* Calculate year, month, day, hour, minute, and second of the */ + /* scan start time. */ + TimeEpochToYMDHMS(stime, &yr, &mo, &dy, &hr, &mt, &sc); + + /* Search for index of corresponding record in input file given */ + /* start time */ + if(old) + ret_flg = OldFitSeek(oldfitfp, yr, mo, dy, hr, mt, sc, NULL); + else ret_flg = FitFseek(fitfp, yr, mo, dy, hr, mt, sc, NULL, inx); + + /* If a matching record could not be found then exit */ + if(ret_flg == -1) + { + fprintf(stderr, "File doesn't contain the requested interval.\n"); + exit(-1); + } + + /* If using scan flag instead of tlen then continue to read + fit records until reaching the beginning of a new scan */ + if(tlen==0) + { + if(old) + { + while((ret_flg = OldFitRead(oldfitfp, prm, fit)) != -1) + { + if(abs(prm->scan) == 1) break; + } + } + else + { + while((ret_flg = FitFread(fitfp, prm, fit)) != -1) + { + if(abs(prm->scan) == 1) break; + } + } + } + else state=0; + + /* Read the first full scan of data from open fit or fitacf file + corresponding to the requested start date and time */ + if(old) + ret_flg = OldFitReadRadarScan(oldfitfp, &state, scan, prm, fit, + tlen, syncflg, channel); + else + ret_flg = FitFreadRadarScan(fitfp, &state, scan, prm, fit, tlen, + syncflg, channel); + } + else + { + /* If the start date and time are not provided, use the time of */ + /* the input file's first record */ + stime = scan->st_time; + + /* Calculate year, month, day, hour, minute, and second of the */ + /* scan start time. */ + TimeEpochToYMDHMS(stime, &yr, &mo, &dy, &hr, &mt, &sc); + } + + /* If end time provided then determine end date */ + if(etime != -1) + { + /* If end date not provided then use date of first record + in input file */ + if(edate == -1) etime += scan->st_time - ((int) scan->st_time + % (24 * 3600)); + else etime += edate; + } + + /* If time extent provided then use that to calculate end time */ + if(extime != 0) etime = stime + extime; + + /* Continue updating the frequency limits until the input scan data is */ + /* beyond the end time or end of input file is reached */ + do + { + /* If 'ns' option set then exclude data where scan flag = -1 */ + if(nsflg) exclude_outofscan(scan); + + /* Load the appropriate radar hardware information for the day + and time of the radar scan (only done once) */ + if(site_flg == 0) + { + /* Get the radar site */ + site = load_radar_site(yr, mo, dy, hr, mt, sc, scan->stid); + site_flg = 1; + + if(tdiff_flag) site->tdiff[channel] = tdiff; + } + + /* Update the backscatter FoV data using only data from this scan */ + UpdateScanBSFoV(strict_gs, freq_min, freq_max, min_pnts, D_nrg, E_nrg, + F_nrg, far_nrg, D_rgmax, E_rgmax, F_rgmax, D_hmin, + D_hmax, E_hmax, F_hmax, D_vh_box, E_vh_box, F_vh_box, + far_vh_box, max_hop, scan, site, mult_bsid); + + /* Read next radar scan from input file */ + if(old) + ret_flg = OldFitReadRadarScan(oldfitfp, &state, scan, prm, fit, + tlen, syncflg, channel); + else + ret_flg = FitFreadRadarScan(fitfp, &state, scan, prm, fit, + tlen, syncflg, channel); + + /* If scan data is beyond end time then break out of loop */ + if((etime != -1) && (scan->st_time > etime)) break; + + } while (ret_flg != -1); + + /* Close the input file */ + if(old) OldFitClose(oldfitfp); + else fclose(fitfp); + } + + /* Free the local pointers. Freeing site here causes abort(6) */ + if(scan != NULL) RadarScanFree(scan); + if(prm != NULL) RadarParmFree(prm); + + /* Close the scan structure */ + if(mult_bsid->num_scans > 0) + mult_bsid->last_ptr->next_scan = (struct FitBSIDScan *)(NULL); + + /* Return with the status flag */ + return(ret_flg); +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/make_fov.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/make_fov.c new file mode 100644 index 000000000..34b909406 --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/make_fov.c @@ -0,0 +1,381 @@ +/* make_fov.c + ========== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include + +#include "rtime.h" +#include "option.h" +#include "fitmultbsid.h" +#include "channel.h" +#include "freqband.h" +#include "hlpstr.h" +#include "errstr.h" + +#ifndef MAX_FREQ_KHZ +#define MAX_FREQ_KHZ 30000 +#endif + +struct OptionData opt; + +/** + * Outputs an error statement for an unrecognized input option + **/ + +int rst_opterr(char *txt) +{ + fprintf(stderr, "Option not recognized: %s\n", txt); + fprintf(stderr, "Please try: make_fov --help\n"); + return(-1); +} + +/** + * Load the command line options + **/ + +int command_options(int argc, char *argv[], int *old, int *tlen, + unsigned char *vb, unsigned char *catflg, + unsigned char *nsflg, unsigned char *txtflg, char **stmestr, + char **etmestr, char **sdtestr, char **edtestr, + char **exstr, char **chnstr, char **chnstr_fix, + int *freq_min, int *freq_max, int *band_width, + short int *strict_gs, short int *tdiff_flag, double *tdiff, + float *D_hmin, float *D_hmax, float *E_hmax, float *F_hmax, + int *nbms, int *min_pnts, int *D_nrg, int *E_nrg, + int *F_nrg, int *far_nrg, int *D_rgmax, int *E_rgmax, + int *F_rgmax, float *D_vh_box, float *E_vh_box, + float *F_vh_box, float *far_vh_box, float *max_hop, + float *min_frac, double *ut_box_sec) +{ + /* Initialize input options */ + int farg=0; + unsigned char help=0, option=0, version=0; + + int rst_opterr(char *txt); + + /* If only information is desired, print it out and exit */ + OptionAdd(&opt, "-help", 'x', &help); + OptionAdd(&opt, "-option", 'x', &option); + OptionAdd(&opt, "-version", 'x', &version); + + /* Determine input file format */ + OptionAdd(&opt, "old", 'x', old); /* Old fit format */ + + /* Concatenate multiple input files */ + OptionAdd(&opt, "c", 'x', catflg); + + /* Verbose: log information to console */ + OptionAdd(&opt, "vb", 'x', vb); + + /* Set time information */ + OptionAdd(&opt, "st", 't', stmestr); /* Start time in HH:MM format */ + OptionAdd(&opt, "et", 't', etmestr); /* End time in HH:MM format */ + OptionAdd(&opt, "sd", 't', sdtestr); /* Start date in YYYYMMDD format */ + OptionAdd(&opt, "ed", 't', edtestr); /* End date in YYYYMMDD format */ + OptionAdd(&opt, "ex", 't', exstr); /* Use interval with extent HH:MM */ + + /* Ignore scan flag, use scan length of tl seconds */ + OptionAdd(&opt, "tl", 'i', tlen); + + /* Process channel options */ + OptionAdd(&opt, "cn", 't', chnstr); /* For stereo channel a or b */ + OptionAdd(&opt, "cn_fix", 't', chnstr_fix); /* User-defined channel number */ + + /* Apply scan flag limit (ie exclude data with scan flag = -1) */ + OptionAdd(&opt, "ns", 'x', nsflg); + + /* Provide ASCII output instead of binary output */ + OptionAdd(&opt, "ascii", 'x', txtflg); + + /* Apply transmission frequency limits or options */ + OptionAdd(&opt, "tfmin", 'i', freq_min); /* Minimum transmission frequency */ + OptionAdd(&opt, "tfmax", 'i', freq_max); /* Maximum transmission frequency */ + OptionAdd(&opt, "bandwidth", 'i', band_width); /* frequency bandwidth */ + + /* Apply groundscatter strictness conditions (1=remove indeterminate GS) */ + OptionAdd(&opt, "gs-strict", 'x', strict_gs); + + /* Process the tdiff options */ + OptionAdd(&opt, "update-tdiff", 'x', tdiff_flag); + OptionAdd(&opt, "tdiff", 'd', tdiff); + + /* Process the region height limit options */ + OptionAdd(&opt, "dhmin", 'f', D_hmin); + OptionAdd(&opt, "dhmax", 'f', D_hmax); + OptionAdd(&opt, "ehmax", 'f', E_hmax); + OptionAdd(&opt, "fhmax", 'f', F_hmax); + + /* Number of beams to use in UT evaluation */ + OptionAdd(&opt, "nbms", 'i', nbms); + + /* Minimum number of points to consider for multi-point evaluations */ + OptionAdd(&opt, "minpnts", 'i', min_pnts); + + /* Number of range gates to consider for groups in each ionospheric region */ + OptionAdd(&opt, "dnrg", 'i', D_nrg); + OptionAdd(&opt, "enrg", 'i', E_nrg); + OptionAdd(&opt, "fnrg", 'i', F_nrg); + OptionAdd(&opt, "farnrg", 'i', far_nrg); + + /* Maximum range gate that 1/2 hop backscatter from an ionospheric region */ + /* can be found in. */ + OptionAdd(&opt, "drgmax", 'i', D_rgmax); + OptionAdd(&opt, "ergmax", 'i', E_rgmax); + OptionAdd(&opt, "frgmax", 'i', F_rgmax); + + /* Size of the virtual height box to use in each ionospheric region */ + OptionAdd(&opt, "dhbox", 'f', D_vh_box); + OptionAdd(&opt, "ehbox", 'f', E_vh_box); + OptionAdd(&opt, "fhbox", 'f', F_vh_box); + OptionAdd(&opt, "farhbox", 'f', far_vh_box); + + /* Maximum number of hops possible */ + OptionAdd(&opt, "maxhop", 'f', max_hop); + + /* Minimum fraction of points needed to perform a UT evaluation */ + OptionAdd(&opt, "minfrac", 'f', min_frac); + + /* Number of seconds for the UT evaluation box */ + OptionAdd(&opt, "utbox", 'd', ut_box_sec); + + /* Process command line options */ + farg = OptionProcess(1, argc, argv, &opt, rst_opterr); + + /* If 'help' set then print help message */ + if(help==1) + { + OptionPrintInfo(stdout, hlpstr); + exit(0); + } + + /* If 'version' set, then print the version number */ + if(version==1) + { + OptionVersion(stdout); + exit(0); + } + + /* If 'option' set then print all command line options */ + if(option==1) + { + OptionDump(stdout, &opt); + exit(0); + } + + /* If command line option not recognized then print error and exit */ + if(farg == -1) exit(-1); + + if(farg == argc) + { + OptionPrintInfo(stderr, errstr); + exit(-1); + } + + return farg; +} + +/** + * Determines the backscatter origin field-of-view + **/ + +int main(int argc, char *argv[]) +{ + int inum, len, fnum, ret_stat, nfbands; + int fbands[90][2], all_freq[MAX_FREQ_KHZ]; + + char vstr[256]; + + struct FitMultBSID *mult_bsid; + + /* Initialize input options */ + short int strict_gs=0, tdiff_flag=0; + + /* Default frequency limits set to the limits of the HF range */ + int old=0, farg=0, tlen=0, channel=0, channel_fix=0; + int freq_min=3000, freq_max=30000, band_width=300, nbms=3, min_pnts=3; + int D_nrg=2, E_nrg=5, F_nrg=10, far_nrg=20; + int D_rgmax=5, E_rgmax=25, F_rgmax=40; + + /* Default ionospheric region height limits, especially the F-region may */ + /* be radar dependent. INV uses 750 km, HAN uses 900 km. */ + float D_hmin=75.0, D_hmax=100.0, E_hmax=120.0, F_hmax=750.0; + float D_vh_box=40.0, E_vh_box=35.0, F_vh_box=50.0, far_vh_box=150.0; + float max_hop=3.0, min_frac=0.1; + + double stime=-1.0, etime=-1.0, extime=0.0, sdate=-1.0, edate=-1.0, tdiff=0.0; + double ut_box_sec=1200.0; /* 20 minutes */ + + unsigned char vb=0, catflg=0, nsflg=0, txtflg=0; + + char *vbuf=NULL, *chnstr=NULL, *chnstr_fix=NULL, *exstr=NULL, *etmestr=NULL; + char *edtestr=NULL, *sdtestr=NULL, *stmestr=NULL; + + /* Initialize file information */ + char **dnames=NULL, *iname=NULL; + + /* Declare local subroutines */ + int command_options(int argc, char *argv[], int *old, int *tlen, + unsigned char *vb, unsigned char *catflg, + unsigned char *nsflg, unsigned char *txtflg, + char **stmestr, char **etmestr, char **sdtestr, + char **edtestr, char **exstr, char **chnstr, + char **chnstr_fix, int *freq_min, int *freq_max, + int *band_width, short int *strict_gs, + short int *tdiff_flag, double *tdiff, float *D_hmin, + float *D_hmax, float *E_hmax, float *F_hmax, int *nbms, + int *min_pnts, int *D_nrg, int *E_nrg, int *F_nrg, + int *far_nrg, int *D_rgmax, int *E_rgmax, int *F_rgmax, + float *D_vh_box, float *E_vh_box, float *F_vh_box, + float *far_vh_box, float *max_hop, float *min_frac, + double *ut_box_sec); + int load_fit_update_fov(int fnum, int channel, int channel_fix, int old, + int tlen, double stime, double sdate, double etime, + double edate, double extime, unsigned char nsflg, + unsigned char vb, char *vbuf, char *iname, + char **dnames, short int tdiff_flag, double tdiff, + short int strict_gs, int freq_min, int freq_max, + int min_pnts, int D_nrg, int E_nrg, int F_nrg, + int far_nrg, int D_rgmax, int E_rgmax, int F_rgmax, + float D_hmin, float D_hmax, float E_hmax, + float F_hmax, float D_vh_box, float E_vh_box, + float F_vh_box, float far_vh_box, float max_hop, + struct FitMultBSID *mult_bsid); + void test_ut_fov_struct(unsigned char vb, char *vbuf, int nbms, + float min_frac, double ut_box_sec, int D_nrg, + int E_nrg, int F_nrg, int far_nrg, int D_rgmax, + int E_rgmax, int F_rgmax, float D_hmin, float D_hmax, + float E_hmax, float F_hmax, + struct FitMultBSID *mult_bsid); + + /* Process the command line options */ + farg = command_options(argc, argv, &old, &tlen, &vb, &catflg, &nsflg, &txtflg, + &stmestr, &etmestr, &sdtestr, &edtestr, &exstr, + &chnstr, &chnstr_fix, &freq_min, &freq_max, + &band_width, &strict_gs, &tdiff_flag, &tdiff, &D_hmin, + &D_hmax, &E_hmax, &F_hmax, &nbms, &min_pnts, &D_nrg, + &E_nrg, &F_nrg, &far_nrg, &D_rgmax, &E_rgmax, &F_rgmax, + &D_vh_box, &E_vh_box, &F_vh_box, &far_vh_box, &max_hop, + &min_frac, &ut_box_sec); + + /* If 'cn' set then determine Stereo channel, either A or B */ + if(chnstr != NULL) channel = set_stereo_channel(chnstr); + + /* If 'cn_fix' set then determine appropriate channel for output file */ + if(chnstr_fix != NULL) channel_fix = set_fix_channel(chnstr_fix); + + /* Format the time data */ + if(exstr != NULL) extime = TimeStrToSOD(exstr); + if(stmestr != NULL) stime = TimeStrToSOD(stmestr); + if(etmestr != NULL) etime = TimeStrToSOD(etmestr); + if(sdtestr != NULL) sdate = TimeStrToEpoch(sdtestr); + if(edtestr != NULL) edate = TimeStrToEpoch(edtestr); + + /* If verbose, set output */ + if(vb) vbuf = vstr; + + /* Make a list of input files */ + if(catflg == 0) + { + /* For a single input file, an index file may also be provided */ + dnames = (char **)malloc(sizeof(char *)); + + if(argc-farg > 1) + { + iname = argv[argc-1]; + fnum = argc - 2; + } + else fnum = argc - 1; + + len = strlen(argv[fnum]); + dnames[0] = (char *)malloc(sizeof(char) * (len + 1)); + strcpy(dnames[0], argv[fnum]); + fnum = 1; + } + else + { + /* For multiple input files, no index files are allowed */ + fnum = argc - farg; + dnames = (char **)malloc(sizeof(char*) * fnum); + + for(inum = 0; inum < fnum; inum++) + { + len = strlen(argv[inum+argc]); + dnames[inum] = (char *)malloc(sizeof(char) * (len + 1)); + strcpy(dnames[inum], argv[inum + argc]); + } + } + + /* Dynamically establish transmission frequency bands for these scans */ + /* unless a frequency range was specified */ + if(freq_max - freq_min == 27000) + { + nfbands = get_fit_tfreq_bands(fnum, channel, channel_fix, old, tlen, + stime, sdate, etime, edate, extime, 1, + nsflg, vb, vbuf, iname, dnames, band_width, + fbands, all_freq); + if(nfbands < 0) + { + fprintf(stderr, "make_fov ERROR: frequency band width too small"); + return(1); + } + } + else + { + nfbands = 1; + fbands[0][0] = freq_min; + fbands[0][1] = freq_max; + } + + /* Initialize and load the fitted data */ + mult_bsid = FitMultBSIDMake(); + + /* Treat each frequency band seperately */ + for(inum = 0; inum < nfbands; inum++) + { + /* Cycle through the scans, updating the backscatter data in each one */ + /* Based off of DaViTpy routine: */ + /* pydarn.proc.fov.update_backscatter.update_bs_w_scan */ + ret_stat = load_fit_update_fov(fnum, channel, channel_fix, old, tlen, + stime, sdate, etime, edate, extime, nsflg, + vb, vbuf, iname, dnames, tdiff_flag, tdiff, + strict_gs, freq_min, freq_max, min_pnts, + D_nrg, E_nrg, F_nrg, far_nrg, D_rgmax, + E_rgmax, F_rgmax, D_hmin, D_hmax, E_hmax, + F_hmax, D_vh_box, E_vh_box, F_vh_box, + far_vh_box, max_hop, mult_bsid); + + if(ret_stat < 0 && mult_bsid->num_scans > 0) + /* Examine the UT evolution and consistency of the elevation angles */ + test_ut_fov_struct(vb, vbuf, nbms, min_frac, ut_box_sec, D_nrg, E_nrg, + F_nrg, far_nrg, D_rgmax, E_rgmax, F_rgmax, D_hmin, + D_hmax, E_hmax, F_hmax, mult_bsid); + } + + /* Write the output, which will be binary unless ASCII is requested */ + if(mult_bsid->num_scans > 0) + { + if(txtflg == 1) WriteFitMultBSIDASCII(stdout, mult_bsid); + else ret_stat = WriteFitMultBSIDBin(stdout, 0, 0, mult_bsid); + } + + /* Free the data structure pointer */ + FitMultBSIDFree(mult_bsid); + + /* Free the remaining pointers */ + for(inum = 0; inum < fnum; inum++) free(dnames[inum]); + free(dnames); + + return(ret_stat); +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/makefile b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/makefile new file mode 100644 index 000000000..ed758092c --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/makefile @@ -0,0 +1,45 @@ +# Makefile for make_fov +# ===================== +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I$(IPATH)/analysis -I$(IPATH)/base -I$(IPATH)/general \ + -I$(IPATH)/superdarn -I../include/ + +# Notes: +# grid_utils, get_fit_tfreq_band, should likely be called through libraries +SRC = make_fov.c \ + eval_groundscatter.c \ + load_fit_update_fov.c \ + scan_utils.c \ + select_alt_groups.c \ + test_ut_fov_struct.c \ + update_beam.c \ + update_scan.c + +OBJS = $(SRC:.c=.o) + +INC=$(IPATH)/superdarn + +DSTPATH = $(BINPATH) + +OUTPUT = make_fov + +LIBS = -lchannel.1 -lfreqband.1 -loldfit.1 -lgtabw.1 -loldgtabw.1 -lgtable.1 \ + -lrpos.1 -lfilter.1 -lcfit.1 -lfit.1 -lrscan.1 -lradar.1 -ldmap.1 \ + -lopt.1 -lrtime.1 -lrcnv.1 -laacgm.1 -ligrf.1 -laacgm_v2.1 -ligrf_v2.1 \ + -lastalg.1 -lfitacf.1 -lfitacf.3.0 -lmpfit.1.5 -lelevation.1.0 \ + -lpropagation.1.0 -lsort.1.0 -lfitmultbsid.1.0 -lstats.1.0 \ + -llinearfit.1.0 + +SLIB = -lm -lz + +include $(MAKEBIN).$(SYSTEM) diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/scan_utils.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/scan_utils.c new file mode 100644 index 000000000..1a18ae17d --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/scan_utils.c @@ -0,0 +1,420 @@ +/* update_scan.c + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include + +#include "linearfit.h" +#include "scan_utils.h" + +/** + * @brief Evaluate the azimuthal variations in a group of elevation angles + * + * @param[in] num - Number of points in the `scan_*` arrays + * fov - Integer denoting field of view (0=back, 1=front) + * scan_bm - Array holding the group's beam numbers + * scan_rg - Array holding the group's range gates + * fovflg - Beam x RG array holding assigned FoVs (-1=back, 1=front) + * fovpast - Beam x RG array holding previously assigned FoV flags + * scan_vh - Array holding the group's virtual heights in km + * scan_elv - Array holding the group's elevation angles in deg + **/ + +void eval_az_var_in_elv(int num, int fov, int scan_bm[], int scan_rg[], + int fovflg[MAX_BMS][MAX_RGS], + int fovpast[MAX_BMS][MAX_RGS], float scan_vh[], + float scan_elv[], float fovstd[MAX_BMS][MAX_RGS], + float fovscore[MAX_BMS][MAX_RGS], + int fovextreme[MAX_BMS][MAX_RGS]) +{ + int i, irg, ibm, reg_stat, *is_extreme; + int get_fov[2] = {-1, 1}; + + float max_std, max_score, intercept, sig_intercept, slope, chi2, q, lstd; + float sig_slope, line_std, high_elv, low_elv, frac_extreme, max_extreme; + float *scan_x, *lval, *ldev, *abs_ldev, *lscore, *line_dev, *sig; + + /* Initalize the maximum statistics and reference variables */ + max_std = 5.0; /* Used to be 3.0, changed after INV tests */ + max_score = 3.0; + max_extreme = 1.0; /* Fraction of points in this group that may possibly */ + high_elv = 50.0; /* be aliased in this FoV. */ + low_elv = 0.0; + + /* Initialize the evalutaion statistics to default values */ + line_std = max_std + 100.0; + is_extreme = (int *)calloc(num, sizeof(int)); + line_dev = (float *)calloc(num, sizeof(float)); + sig = (float *)calloc(num, sizeof(float)); + lval = (float *)calloc(num, sizeof(float)); + ldev = (float *)calloc(num, sizeof(float)); + abs_ldev = (float *)calloc(num, sizeof(float)); + lscore = (float *)calloc(num, sizeof(float)); + scan_x = (float *)calloc(num, sizeof(float)); + for(frac_extreme = 0.0, i = 0; i < num; i++) + { + scan_x[i] = (float)scan_rg[i]; + line_dev[i] = line_std; + sig[i] = 0.0; + + /* Determine whether or not all elevation angles are extreme */ + if(scan_elv[i] >= high_elv || scan_elv[i] <= low_elv) + { + is_extreme[i] = 1; + frac_extreme += 1.0; + } + else is_extreme[i] = 0; + } + frac_extreme = frac_extreme / (float)num; + + /* Get the linear regression of the elevation angles as a function of */ + /* range gate. The slope of this line must be flat or negative. Aliasing */ + /* will cause positive jumps, but these should not be present in all */ + /* boxes, allowing data to be assigned at times when the aliasing jump */ + /* isn't present. A more robust method (such as RANSAC or Theil-Sen) was */ + /* not used, since the number of points available are small. */ + reg_stat = linear_regression(scan_x, scan_elv, sig, num, 0, &intercept, + &sig_intercept, &slope, &sig_slope, &chi2, &q); + + /* Don't check for slope being negative or flat, because flat can be */ + /* slightly positive and it's been too finicky finding a good threshold. */ + if(reg_stat == 0) + { + /* If there were no calculation problems, and the slope is flat or */ + /* decreasing, calculate the linear values */ + for(i = 0; i < num; i++) + { + lval[i] = slope * scan_x[i] + intercept; + ldev[i] = lval[i] - scan_elv[i]; + abs_ldev[i] = fabs(ldev[i]); + } + + lstd = stdev_float(num, ldev); + zscore(num, abs_ldev, lscore); + + /* Use current and past z-scores to determine whether or not each */ + /* point is well-characterized by the linear regression. */ + if(lstd <= max_std) + { + for(i = 0; i < num; i++) + { + /* If this backscatter point's score is below the maximum and */ + /* lower than previous estimate's scores. */ + if(lscore[i] <= max_score) + { + irg = scan_rg[i]; + ibm = scan_bm[i]; + + /* Also update if this is the first evaluation. Adapted the */ + /* requirement for this line's standard to be less than the */ + /* previous line's standard deviation as well as a lower */ + /* z-score. */ + if(fovflg[ibm][irg] == 0 + || (fabs(lscore[i]) < fovscore[ibm][irg] + && lstd <= fovstd[ibm][irg] + && frac_extreme <= max_extreme) || + (is_extreme[i] == 0 && fovextreme[ibm][irg] == 1)) + { + /* Update with the new good FoV stats and flag */ + fovflg[ibm][irg] = get_fov[fov]; + fovstd[ibm][irg] = lstd; + fovscore[ibm][irg] = fabs(lscore[i]); + } + else if(fovpast[ibm][irg] == 0) + { + /* Other FoV is valid */ + fovpast[ibm][irg] = get_fov[fov]; + fovextreme[ibm][irg] = is_extreme[i]; + } + else if(fovpast[ibm][irg] == 0) + { + /* The other FoV is better, but this FoV is also valid */ + fovpast[ibm][irg] = get_fov[fov]; + } + } + } + } + } + + /* Free the pointers */ + free(is_extreme); + free(line_dev); + free(sig); + free(lval); + free(ldev); + free(abs_ldev); + free(lscore); + free(scan_x); + + return; +} + + +/** + * @brief: Evaluate the FoV flags, removing and identifying outliers + * + * @params[in] max_rg - Maximum number of range gates + * max_bm - Maximum number of beams/maximum beam index + 1 + * bmwidth - Beam half-width in beam numbers (75% of min_pnts) + * D_rgmax - Maximum range gate for the D-region box width (5) + * D_nrg - Number of range gates for D-region box (2) + * E_rgmax - Maximum range gate for the E-region box width (25) + * E_nrg - Number of range gates for E-region box (5) + * F_rgmax - Max range gate for the near F-region box width (40) + * F_nrg - Number of range gates for near F-region box (10) + * far_nrg - Number of range gates for far F-region box (20) + * fovflg - Beam x RG array holding assigned FoVs + * fovpast - Beam x RG array holding previously assigned FoV flags + * fovbelong - Beam x RG x 3 array holding True/False assignments + * indicating the point is an inlier (0), outlier (1), + * or mixed-ID (2). Must be initialized outside of this + * routine. + * opp_in - Beam x RG array holding True/False assignments + * indicating the point is a better inlier if the FoV + * for the central point is swapped. Must be + * initialized outside of this routine. + * scan - Scan structure holding data by beam and range gate + * + * @note `*_rgmax` parameters are equivalent to `rg_max` in davitpy + **/ + +void eval_fov_flag_consistency(int max_rg, int max_bm, int bmwidth, int D_rgmax, + int D_nrg, int E_rgmax, int E_nrg, int F_rgmax, + int F_nrg, int far_nrg, + int fovflg[MAX_BMS][MAX_RGS], + int fovpast[MAX_BMS][MAX_RGS], + int fovbelong[MAX_BMS][MAX_RGS][3], + int opp_in[MAX_BMS][MAX_RGS], + struct FitBSIDScan *scan) +{ + int irg, ibm, ifov, irsel, ibsel, bind, rmin, rmax, bmin, bmax, bad_fov; + int fnum[2], bnum[2]; + + float ffrac, fov_frac, ffrac_opp, near_rg; + + struct FitBSIDBeam bm, bm_ref; + struct CellBSIDLoc loc, ref_loc[2]; + + /* Initialize the variables */ + fov_frac = 2.0 / 3.0; + near_rg = -1.0; + + /* Cycle through all of the range gates, looking for consistency in the */ + /* neighboring backscatter fields of view. */ + for(irg = 0; irg < max_rg; irg++) + { + /* Get the range gate box limits */ + get_rg_box_limits(irg, max_rg, D_rgmax, E_rgmax, F_rgmax, D_nrg, + E_nrg, F_nrg, far_nrg, &rmin, &rmax); + + /* For each beam in the maximum possible range gate window, gather */ + /* the range gate, FoV flag, beam index, and range gate index by */ + /* propagation path. */ + for(ibm = 0; ibm < scan->num_bms; ibm++) + { + /* Cycle the reference beam and evaluation beam to the */ + /* correct range gate */ + bm = scan->bm[ibm]; + + /* Ensure only good beams with data are used */ + if(bm.frang > 0 && bm.rsep > 0) + { + if(near_rg < 0.0) + { + /* Calculate once in the routine */ + near_rg = ((500.0 / (5.0e-10 * C) + - ((float)bm.frang * 20.0 / 3.0)) + / ((float)bm.rsep * 20.0 / 3.0)); + } + + if(bm.sct[irg] == 1 && fovflg[bm.bm][irg] != 0) + { + if(fovflg[bm.bm][irg] == -1) + { + ref_loc[0] = bm.back_loc[irg]; + ref_loc[1] = bm.front_loc[irg]; + } + else + { + ref_loc[0] = bm.front_loc[irg]; + ref_loc[1] = bm.back_loc[irg]; + } + + /* Get the beam limits for the azimuthal box */ + bmin = bm.bm - bmwidth; + bmax = bm.bm + bmwidth; + if(bmin < 0) bmin = 0; + if(bmax > max_bm) bmax = max_bm; + + /* Cycle through each range gate and beam in the box, */ + /* getting the number of points for the same hop in */ + /* each field-of-view */ + for(ifov = 0; ifov < 2; ifov++) + { + fnum[ifov] = 0; + bnum[ifov] = 0; + } + + for(ibsel = bmin; ibsel < bmax; ibsel++) + { + for(irsel = rmin; irsel < rmax; irsel++) + { + if(fovflg[ibsel][irsel] != 0) + { + bind = get_bm_by_bmnum(ibsel, scan); + bm_ref = scan->bm[bind]; + if(fovflg[ibsel][irsel] == -1) + loc = bm_ref.back_loc[irsel]; + else loc = bm_ref.front_loc[irsel]; + + if(loc.hop == ref_loc[0].hop) + { + if(fovflg[ibsel][irsel] == 1) fnum[0]++; + else bnum[0]++; + } + + if(fovpast[bind][irg] != 0) + { + if(irg == irsel && bm.bm == ibsel) + { + if(fovpast[ibsel][irsel] == 1) fnum[1]++; + else bnum[1]++; + } + else if(loc.hop == ref_loc[1].hop) + { + if(fovflg[ibsel][irsel] == 1) fnum[1]++; + else bnum[1]++; + } + } + } + } + } + + /* Sum up the number of points in this range gate/beam box */ + /* and see if there is an overwhelming number of points in */ + /* either field-of-view. */ + if(fnum[0] + bnum[0] > 0) + { + /* Get the bad field of view and test the opposite FoV */ + ffrac = (float)fnum[0] / (float)(fnum[0] + bnum[0]); + ffrac_opp = (float)fnum[1] / (float)(fnum[1] + bnum[1]); + if(ffrac >= fov_frac) + { + bad_fov = -1; + + if(ffrac_opp > ffrac) opp_in[bm.bm][irg] = 1; + } + else if((1.0 - ffrac) >= fov_frac) + { + bad_fov = 1; + + if(ffrac_opp < ffrac) opp_in[bm.bm][irg] = 1; + } + else + { + bad_fov = 0; + + if((ffrac_opp >= fov_frac) + || ((1.0 - ffrac_opp) >= fov_frac)) + opp_in[bm.bm][irg] = 1; + else opp_in[bm.bm][irg] = 0; + } + + if(opp_in[bm.bm][irg] == 1 + && fovpast[bm.bm][irg] == bad_fov) + opp_in[bm.bm][irg] = 0; + + /* Tag all points whose FoV are or are not */ + /* consistent with the observed structure */ + /* at this propagation path */ + for(ibsel = bmin; ibsel < bmax; ibsel++) + { + for(irsel = rmin; irsel < rmax; irsel++) + { + if(fovflg[ibsel][irsel] != 0) + { + bind = get_bm_by_bmnum(ibsel, scan); + bm_ref = scan->bm[bind]; + if(fovflg[ibsel][irsel] == -1) + loc = bm_ref.back_loc[irsel]; + else loc = bm_ref.front_loc[irsel]; + + if(ifov == 0 && loc.hop == ref_loc[0].hop) + { + if(bad_fov == 0) + fovbelong[ibsel][irsel][2]++; + else if(fovflg[ibsel][irsel] == bad_fov) + { + /* If this point is not */ + /* associated with a structure */ + /* dominated by points with the */ + /* same FoV, and this is not */ + /* the only FoV able to produce */ + /* a realistic elevation angle, */ + /* flag this point as an outlier */ + if(irsel < near_rg) + fovbelong[ibsel][irsel][1]++; + } + else fovbelong[ibsel][irsel][0]++; + } + } + } + } + } + } + } + } + } + + return; +} + +/** + * @brief Get range gate limits for an input point and set regional guidelines + * + * @params[in] rg - Zero-starting range gate index + * max_rg - Maximum transmission frequency limit in kH + * D_rgmax - Maximum range gate for D-region box width (5) + * E_rgmax - Maximum range gate for E-region box width (25) + * F_rgmax - Maximum range gate for near F-region box width (40)z + * D_nrg - Number of range gates for D-region box (2) + * E_nrg - Number of range gates for E-region box (5) + * F_nrg - Number of range gates for near F-region box (10) + * far_nrg - Number of range gates for far F-region box (20) + * + * @params[out] rg_min - minimum range gate in box + * rg_max - maximum range gate in box + **/ + +void get_rg_box_limits(int rg, int max_rg, int D_rgmax, int E_rgmax, + int F_rgmax, int D_nrg, int E_nrg, int F_nrg, + int far_nrg, int *rg_min, int *rg_max) +{ + int width; + + /* Get the half-width of the range gate box */ + if(rg < D_rgmax) width = D_nrg / 2; /* (D_nrg + inc) / 2; */ + else if(rg < E_rgmax) width = E_nrg / 2; /* (E_nrg + inc) / 2; */ + else if(rg < F_rgmax) width = F_nrg / 2; /* (F_nrg + inc) / 2; */ + else width = far_nrg / 2; /* (far_nrg + inc) / 2; */ + + /* Set the upper and lower box limits, limiting them */ + /* to the possible upper and lower range gate limits. */ + *rg_min = (rg - width < 0) ? 0 : rg - width; + *rg_max = (rg + width > max_rg) ? max_rg : rg + width; + + return; +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/scan_utils.h b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/scan_utils.h new file mode 100644 index 000000000..e956dce9c --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/scan_utils.h @@ -0,0 +1,55 @@ +/* scan_utils.h + ============ + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#ifndef _SCAN_UTILS_H +#define _SCAN_UTILS_H + +#ifndef _RMATH_H +#include "rmath.h" +#endif + +#ifndef _STAT_UTILS_H +#include "stats.h" +#endif + +#ifndef _FITMULTBSID_H +#include "fitmultbsid.h" +#endif + +#ifndef MAX_BMS +#define MAX_BMS 25 /* Current maximum in hdw files */ +#endif + +#ifndef MAX_RGS +#define MAX_RGS 225 /* Current maximum in hdw files */ +#endif + +void eval_az_var_in_elv(int num, int fov, int scan_bm[], int scan_rg[], + int fovflg[MAX_BMS][MAX_RGS], + int fovpast[MAX_BMS][MAX_RGS], float scan_vh[], + float scan_elv[], float fovstd[MAX_BMS][MAX_RGS], + float fovscore[MAX_BMS][MAX_RGS], + int fovextreme[MAX_BMS][MAX_RGS]); +void eval_fov_flag_consistency(int max_rg, int max_bm, int bmwidth, int D_rgmax, + int D_nrg, int E_rgmax, int E_nrg, int F_rgmax, + int F_nrg, int far_nrg, + int fovflg[MAX_BMS][MAX_RGS], + int fovpast[MAX_BMS][MAX_RGS], + int fovbelong[MAX_BMS][MAX_RGS][3], + int opp_in[MAX_BMS][MAX_RGS], + struct FitBSIDScan *scan); +void get_rg_box_limits(int rg, int max_rg, int D_rgmax, int E_rgmax, + int F_rgmax, int D_nrg, int E_nrg, int F_nrg, + int far_nrg, int *rg_min, int *rg_max); +#endif diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/select_alt_groups.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/select_alt_groups.c new file mode 100644 index 000000000..00d33d4a9 --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/select_alt_groups.c @@ -0,0 +1,517 @@ +/* select_alt_groups.c + =================== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include + +#include "mpfit.h" +#include "fitmultbsid.h" +#include "stats.h" +#include "sort.h" + +/** + * @brief Get the alt limits for a select group of data. Look at the + * distribution of the data and fit a Gaussian curve to the occurance + * peaks to establish appropriate limits. + * + * @params[in] num - Number of points in `rg` and `vh` arrays + * vh - Array of virtual heights for each range gate + * vh_min - Minimum allowable virtual height in km + * vh_max - Maximum allowable virtual height in km + * vh_box - Width of virtual height box in km + * min_pnts - Minimum number of points allowed in a box + * max_vbin - Maximum number of virtuaal height bins + * + * @params[out] vh_mins - Lower virtual height limit of each bin + * vh_maxs - Upper virtual height limit of each bin + * npeaks - Number of virtual height bins + **/ + +int select_alt_groups(int num, float vh[], float vh_min, float vh_max, + float vh_box, int min_pnts, int max_vbin, float *vh_mins, + float *vh_maxs) +{ + int i, j, nbin, nmax, status, npeaks, *hist_bins, *ismax, *valmax; + int *argmax; + + float local_min, local_max, vmin, vmax, vlow, vhigh, hist_width; + float *hist_edges, *vh_peaks; + + double *params; + + struct gauss_data *private; + struct mp_config_struct *config; + struct mp_result_struct *result; + + int sort_expand_boundaries(int num, int max_vbin, float local_min, + float local_max, float vh_min, float vh_max, + float vh_box, float vh_mins[], float vh_maxs[], + float *vh_peaks); + + /* Initialize the structures and variables */ + private = (struct gauss_data *)(malloc(sizeof(struct gauss_data))); + memset(private, 0, sizeof(struct gauss_data)); + result = (struct mp_result_struct *)malloc(sizeof(struct mp_result_struct)); + memset(result, 0, sizeof(struct mp_result_struct)); + config = (struct mp_config_struct *)malloc(sizeof(struct mp_config_struct)); + memset(config, 0, sizeof(struct mp_config_struct)); + vh_peaks = (float *)calloc(max_vbin, sizeof(float)); + + npeaks = 0; + + /* Create a histogram of the number of observations at each virtual height */ + nbin = (int)((vh_max - vh_min) / (vh_box * 0.25)); + if(nbin > 10) nbin = 10; + if(nbin <= 0) + { + fprintf(stderr, "vheight range too small for a histogram analysis: "); + fprintf(stderr, "%d = (%f - %f) / %f", nbin, vh_max, vh_min, + vh_box * 0.25); + free(private); + free(result); + free(vh_peaks); + exit(1); + } + + hist_bins = (int *)calloc(nbin, sizeof(int)); + hist_edges = (float *)calloc(nbin, sizeof(float)); + histogram(num, vh, nbin, vh_min, vh_max, hist_bins, hist_edges); + + /* Find the maxima in the histogram */ + ismax = (int *)calloc(nbin, sizeof(int)); + nmax = int_argrelmax(nbin, hist_bins, 2, 1, ismax); + + /* A relative maximum can't be identified if two identical values */ + /* are side-by-side, and it should almost always be included. */ + i = int_argabsmax(nbin, hist_bins); + + /* Only add the absolute maximum if it is significant and absent. */ + if(ismax[i] == 0 && hist_bins[nmax] >= min_pnts) + { + ismax[nmax] = 1; + nmax++; + } + + /* Get the maximum and minimum of the virtual heights */ + local_min = float_absmin(num, vh); + local_max = float_absmax(num, vh); + + /* Without a significant maximum, set the limits using the suggested width */ + if(nmax == 0) + { + npeaks = (int)ceil((double)(local_max - local_min) / (double)vh_box); + vmin = (local_max - local_min) / (float)npeaks + local_min - vh_box; + + if(npeaks > max_vbin) + { + fprintf(stderr, "suggested width created too many vheight bins\n"); + exit(1); + } + + for(i = 0; i < npeaks; i++) + { + vh_mins[i] = vmin + i * vh_box; + vh_maxs[i] = vh_mins[i] + vh_box; + vh_peaks[i] = vmin + 0.5 * vh_box; + } + } + else + { + /* Configure the least-squares fitting structure, setting */ + /* variables not assigned to the defaults */ + config->maxfev = 1600; + + /* Now set the defaults */ + config->ftol = 1.0e-10; + config->xtol = 1.0e-10; + config->gtol = 1.0e-10; + config->epsfcn = MP_MACHEP0; + config->stepfactor = 100.0; + config->covtol = 1.0e-14; + config->maxiter = 200; + config->nprint = 1; + config->douserscale = 0; + config->nofinitecheck = 0; + config->iterproc = 0; + + /* Sort the maxima */ + valmax = (int *)malloc(nmax * sizeof(int)); + argmax = (int *)calloc(nmax, sizeof(int)); + for(i = 0, j = 0; i < nbin && j < nmax; i++) + { + if(ismax[i] == 1) + { + argmax[j] = i; + valmax[j++] = hist_bins[i]; + } + } + + /* Cast the histogram bins as doubles for use by MINPACK */ + private->x = (double *)calloc(nbin, sizeof(double)); + private->y = (double *)calloc(nbin, sizeof(double)); + private->y_error = (double *)calloc(nbin, sizeof(double)); + + hist_width = (nbin >= 1) ? (hist_edges[1] - hist_edges[0]) / 2.0 : vh_box; + + /* Set the structure for values that will not be updated */ + for(i = 0; i < nbin; i++) + { + private->x[i] = (double)(hist_edges[i] + hist_width); + private->y[i] = (double)hist_bins[i]; + private->y_error[i] = 1.0; /* Unity is the same as no error */ + } + + /* Set the parameters */ + params = (double *)malloc(sizeof(double) * (nmax * 3 + 1)); + params[0] = (double)nmax; + + for(j = 0; j < nmax; j++) + { + params[1 + j * 3] = (double)valmax[j]; + params[2 + j * 3] = private->x[argmax[j]]; + params[3 + j * 3] = 0.5 * (double)vh_box; + } + + /* Use non-linear least-squares to fit a Gaussian to the */ + /* histogram. */ + status = mpfit(mult_gaussian_dev, nbin, 3, params, 0, config, private, result); + + /* Accept all success conditions */ + if(status > 1) + { + for(j = 0; j < nmax; j++) + { + /* Get the 3-sigma limits */ + vmin = params[2 + j * 3] - 3.0 * params[3 + j * 3]; + if(vmin < vh_min) vmin = vh_min; + + vmax = params[2 + j * 3] + 3.0 * params[3 + j * 3]; + if(vmax > vh_max) vmax = vh_max; + + /* Get the 2-sigma limits */ + vlow = params[2 + j * 3] - 2.0 * params[3 + j * 3]; + if(vlow < vh_min) vlow = vh_min; + + vhigh = params[2 + j * 3] + 2.0 * params[3 + j * 3]; + if(vhigh > vh_max) vhigh = vh_max; + + /* Save the 3-sigma limits as the upper and lower virtual */ + /* height box limits if the detected peak is within the */ + /* 2-sigma limits. Also remove this peak from the xdata */ + /* array to allow lower level peaks to be identified. */ + if((private->x[argmax[j]] >= vlow) && (private->x[argmax[j]] <= vhigh)) + { + /* Make sure there is enough memory for this peak */ + if(npeaks >= max_vbin) + { + fprintf(stderr, + "histogram fits created too many vheight bins\n"); + exit(1); + } + + /* Save this altitude bin */ + vh_mins[npeaks] = vmin; + vh_maxs[npeaks] = vmax; + vh_peaks[npeaks] = params[1]; + npeaks++; + } + } + + free(valmax); + free(argmax); + free(params); + } + + /* Evaluate the current limits to see if the overlap each or have gaps. */ + /* Use the suggested width to set limits if done were found. */ + if(npeaks == 0) + { + /* Get the expected number of peaks and set the first set of */ + /* boundary limits. */ + j = (int)ceil((double)((local_max - local_min) / vh_box)); + vh_mins[0] = (local_max + - local_min) / (float)j + local_min - vh_box; + if(vh_mins[0] < vh_min) vh_mins[0] = vh_min; + vh_maxs[0] = vh_mins[0] + vh_box; + if(vh_maxs[0] > vh_max) vh_maxs[0] = vh_max; + vh_peaks[i] = 0.5 * (vh_maxs[i] - vh_mins[i]) + vh_mins[i]; + + /* Set each limit, stopping if the maximum height is reached */ + for(i = 1; i < j && vh_maxs[i-1] < vh_max; i++) + { + vh_mins[i] = vh_maxs[i - 1]; + vh_maxs[i] = vh_mins[i] + vh_box; + if(vh_maxs[i] > vh_max) vh_maxs[i] = vh_max; + vh_peaks[i] = 0.5 * (vh_maxs[i] - vh_mins[i]) + vh_mins[i]; + } + npeaks = i; + } + else + { + /* Sorts the virtual height limits, eliminating overlaps and gaps */ + npeaks = sort_expand_boundaries(npeaks, max_vbin, local_min, + local_max, vh_min, vh_max, vh_box, + vh_mins, vh_maxs, vh_peaks); + } + + /* Free the allocated sub-pointers */ + free(private->x); + free(private->y); + free(private->y_error); + free(result->resid); + free(result->xerror); + free(result->covar); + } + + /* Free the allocated memory */ + free(hist_bins); + free(hist_edges); + free(vh_peaks); + free(private); + free(result); + free(config); + + /* Return the number of virtual height bins as the routine status */ + return(npeaks); +} + +/** + * @brief Sorts the virtual height limits, eliminating overlaps and gaps + * + * @params[in] num - Number of values in vh_(mins/maxs/peaks) at input + * local_min - Minimum of provided virtual height values in km + * local_max - Maximum of provided virtual height values in km + * vh_box - Width of desired virtual height bin in km + * + * @params[in/out] vh_mins - Lower limit of virtual height bins in km + * vh_maxs - Upper limit of virtual height bins in km + * vh_peaks - Peak height for virtual height bins in km + * + * @reference Part of davitpy.proc.fov.update_backscatter.select_alt_groups + **/ + +int sort_expand_boundaries(int num, int max_vbin, float local_min, + float local_max, float vh_min, float vh_max, + float vh_box, float vh_mins[], float vh_maxs[], + float *vh_peaks) +{ + int i, inew, vnum, *sortargs, *priority; + + float hmin, vspan, *new_mins, *new_maxs, *new_peaks; + + void smart_argsort_float(int num, float array[], int sortargs[]); + + if(num == 0) return(0); + + /* Initialize the local pointers */ + new_mins = (float *)calloc(max_vbin, sizeof(float)); + new_maxs = (float *)calloc(max_vbin, sizeof(float)); + new_peaks = (float *)calloc(max_vbin, sizeof(float)); + priority = (int *)calloc(max_vbin, sizeof(int)); + inew = 0; + + /* Get the indices for sorted Gaussian limits */ + sortargs = (int *)calloc(num, sizeof(int)); + smart_argsort_float(num, vh_mins, sortargs); + + /* If there are points that fall below the lower limit, add more regions */ + /* using the suggested width limits. */ + if(vh_mins[sortargs[0]] > local_min) + { + vnum = (int)((vh_mins[sortargs[0]] - local_min) / vh_box); + if(vnum == 0) + { + /* The outlying points are close enough that the lower limit */ + /* should be extended. */ + vh_mins[sortargs[0]] = floor(local_min); + if(vh_mins[sortargs[0]] < vh_min) + vh_mins[sortargs[0]] = vh_min; + } + else + { + /* Create new virtual height bins and prioritize them. Low */ + /* priority values indicate a higher priority to keep this bin. */ + vspan = (vh_mins[sortargs[0]] - local_min) / (float)vnum; + + for(i = 0; i < vnum; i++) + { + /* Calculate the lower limit of the virtual height bin */ + hmin = local_min + (float)i * vspan; + if(hmin < local_min) hmin = local_min; + + /* Add the new virtual height bin to the start of the local */ + /* pointers, which need to be sorted from least to greatest */ + new_mins[inew] = floor(hmin); + new_maxs[inew] = ceil(hmin + vspan); + new_peaks[inew] = hmin + 0.5 * vspan; + priority[inew] = inew + num; + inew++; + + if(inew >= max_vbin) + { + fprintf(stderr, + "exceeded new virtual height boundary limits\n"); + exit(1); + } + } + } + } + + /* Add the Gaussian limits to the local pointers */ + for(i = 0; i < num; i++) + { + /* Get the next lowest minimum virtual height bin value */ + hmin = vh_mins[sortargs[i]]; + + /* Test for overlapping bins and gaps */ + if(inew > 0) + { + /* Test for overlaps or gaps with the previous height window */ + if((new_maxs[inew - 1] >= vh_peaks[sortargs[i]]) + || (hmin <= new_peaks[inew - 1])) + { + /* There is a significant overlap between the two regions. */ + /* Use the priority to decide which boundary to adjust. */ + if(priority[inew - 1] < sortargs[i]) + { + new_mins[inew] = new_maxs[inew - 1]; + new_maxs[inew] = ceil(vh_maxs[sortargs[i]]); + new_peaks[inew] = new_mins[inew] + 0.5 * (new_maxs[inew] - new_mins[inew]); + priority[inew] = inew + num; + inew++; + } + else + { + /* If this adjustment places the previous maximum at or */ + /* below the previous minimum, remove that height bin. */ + while(hmin <= new_mins[inew - 1] && inew > 0) + inew--; + + /* Set the maximum of the new last window to the minimum */ + /* of the next window, removing any gap. */ + if(inew > 0) new_maxs[inew - 1] = hmin; + } + } + else if(new_maxs[inew - 1] < hmin) + { + /* There is a gap between the two height bins. Construct */ + /* bridging window(s) before adding the current height */ + /* bin to the local pointers. */ + vnum = (int)((hmin - new_maxs[inew - 1]) / vh_box); + + if(vnum == 0) + { + /* The outlying points are close enough that the last */ + /* upper limit should be expanded. */ + new_maxs[inew - 1] = hmin; + } + else + { + vspan = (hmin - new_maxs[inew - 1]) / (float)vnum; + + for(i = 0; i < vnum; i++) + { + /* Add the new virtual height bin to the local pointers */ + new_mins[inew] = new_maxs[inew - 1]; + new_maxs[inew] = ceil(new_mins[inew] + vspan); + new_peaks[inew] = new_mins[inew] + 0.5 * vspan; + priority[inew] = inew + num; + inew++; + } + } + } + else + { + /* Add the current height bin, if it is a sensible width */ + if(hmin < vh_maxs[sortargs[i]]) + { + new_mins[inew] = hmin; + new_maxs[inew] = ceil(vh_maxs[sortargs[i]]); + new_peaks[inew] = vh_peaks[sortargs[i]]; + priority[inew] = sortargs[i]; + inew++; + } + } + } + else + { + /* Add the current height bin, if it is a sensible width */ + if(hmin < vh_maxs[sortargs[i]]) + { + new_mins[inew] = floor(hmin); + new_maxs[inew] = ceil(vh_maxs[sortargs[i]]); + new_peaks[inew] = vh_peaks[sortargs[i]]; + priority[inew] = sortargs[i]; + inew++; + } + } + + if(inew >= max_vbin) + { + fprintf(stderr, "exceeded new virtual height boundary limits\n"); + exit(1); + } + } + + /* If there are points that fall above the upper limit, add more regions */ + if((num == 0) || (new_maxs[inew - 1] < local_max)) + { + vnum = (int)((local_max - new_maxs[inew - 1]) / vh_box); + + if(vnum == 0) + { + /* The outlying points are close enough that the upper limit */ + /* should be expanded. */ + new_maxs[inew - 1] = ceil(local_max); + if(new_maxs[inew - 1] > vh_max) new_maxs[inew - 1] = vh_max; + } + else + { + vspan = (local_max - new_maxs[inew - 1]) / (float)vnum; + + for(i = 0; i < vnum && new_maxs[inew - 1] < vh_max; i++) + { + /* Get the maximum, ensuring it doesn't extend too high */ + hmin = new_maxs[inew - 1] + vspan; + if(hmin > vh_max) hmin = vh_max; + + /* Add the new virtual height bin to the local pointers */ + new_mins[inew] = new_maxs[inew - 1]; + new_maxs[inew] = ceil(hmin); + new_peaks[inew] = 0.5 * (hmin - new_mins[inew]) + new_mins[inew]; + priority[inew] = inew + num; + inew++; + } + } + } + + /* Update the output with the sorted local values */ + for(i = 0; i < inew; i++) + { + vh_mins[i] = new_mins[i]; + vh_maxs[i] = new_maxs[i]; + vh_peaks[i] = new_peaks[i]; + } + + /* Free the local pointers */ + free(sortargs); + free(new_mins); + free(new_maxs); + free(new_peaks); + free(priority); + + return(inew); +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/test_ut_fov_struct.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/test_ut_fov_struct.c new file mode 100644 index 000000000..fd1ab54c8 --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/test_ut_fov_struct.c @@ -0,0 +1,608 @@ +/* test_ut_fov_struct.c + ==================== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include + +#include "rtypes.h" +#include "rtime.h" +#include "fitmultbsid.h" +#include "scan_utils.h" + +/** + * @brief Examine the FoV values assigned for scans as a function of time + * + * @params[in] vb - Verbosity flag + * vbuf - Verbosity buffer + * nbms - Number of beams used in each time eval (1) + * min_frac - Minimum fraction of possible backscatter points + * needed in the RG/UT box to test the FoV (0.1) + * ut_box_sec - UT box size in decimal seconds (1200.0) + * D_nrg - Number of range gates for D-region box (2) + * E_nrg - Number of range gates for E-region box (5) + * F_nrg - Number of range gates for near F-region box (10) + * far_nrg - Number of range gates for far F-region box (20) + * D_rgmax - Maximum range gate for D-region box width (5) + * E_rgmax - Maximum range gate for E-region box width (25) + * F_rgmax - Maximum range gate for near F-region box width (40) + * D_hmin - Minimum h' for D-region in km (75) + * D_hmax - Maximum h' for D-region in km (115) + * E_hmax - Maximum h' for E-region in km (150) + * F_hmax - Minimum h' for F-region in km (450) + * + * @params[in/out] mult_bsid - Ouptut data structure + **/ + +void test_ut_fov_struct(unsigned char vb, char *vbuf, int nbms, float min_frac, + double ut_box_sec, int D_nrg, int E_nrg, int F_nrg, + int far_nrg, int D_rgmax, int E_rgmax, int F_rgmax, + float D_hmin, float D_hmax, float E_hmax, float F_hmax, + struct FitMultBSID *mult_bsid) +{ + int i, iscan, ibm, irg, ireg, ihop, ibox, iwin, istime, ietime, ifov, sbm; + int bind, bmid, max_pnts, num_bms, max_rg, cpid, bmnum, num_rg, min_bmnum; + int max_bmnum, good_fov, bad_fov, has_fov, rmin, rmax; + int fnum[2], bnum[2]; + int ****fovflg, ****region, ****hop, **fov_in, **fov_out, **fov_mix, **opp_in; + + float fov_frac, frac_num, past_frac; + + double *stime; + + struct CellBSIDLoc loc, opp; + struct FitBSIDBeam *bm; + struct FitBSIDScan *scan; + + /* Test the input structure length */ + if(mult_bsid->ed_time - mult_bsid->st_time < ut_box_sec) + { + if(vb) sprintf(vbuf, + "too few scans to perform a temporal FoV evaluation\n"); + return; + } + + if(nbms < 1) + { + if(vb) sprintf(vbuf, "Requested no time evalutation for FoV\n"); + return; + } + + /* Initialize the local variables */ + fov_frac = 2.0 / 3.0; + + opp_in = (int **)NULL; + fov_in = (int **)NULL; + fov_out = (int **)NULL; + fov_mix = (int **)NULL; + fovflg = (int ****)NULL; + region = (int ****)NULL; + hop = (int ****)NULL; + stime = (double *)NULL; + + /* Load the first scan */ + scan = mult_bsid->scan_ptr; + num_bms = scan->num_bms; + max_rg = -1; + + /* Cycle through all of the scans for each beam */ + for(ibm = 0; ibm < num_bms; ibm++) + { + /* Set the central beam number and CPID for this beam eval */ + cpid = scan->bm[ibm].cpid; + bmnum = scan->bm[ibm].bm; + num_rg = scan->bm[ibm].nrang; + + /* Determine the minimum and maximum beam numbers */ + min_bmnum = bmnum; + max_bmnum = bmnum; + bmid = 0; + if(nbms == 2) + { + if(bmnum == 0) max_bmnum += 1; + else + { + min_bmnum -= 1; + bmid = 1; + } + } + else if(nbms > 2) + { + bmid = nbms / 2; + min_bmnum -= bmid; + max_bmnum += bmid; + + if(min_bmnum < 0) + { + min_bmnum = 0; + max_bmnum = min_bmnum + nbms - 1; + } + else if(max_bmnum >= num_bms) + { + max_bmnum = num_bms - 1; + min_bmnum = max_bmnum - nbms + 1; + } + } + + /* Initialize the FoV flag tracking pointers */ + if(fovflg == NULL) + { + fovflg = (int ****)malloc(sizeof(int ***) * 2); + region = (int ****)malloc(sizeof(int ***) * 2); + hop = (int ****)malloc(sizeof(int ***) * 2); + fov_in = (int **)malloc(sizeof(int *) * mult_bsid->num_scans); + fov_out = (int **)malloc(sizeof(int *) * mult_bsid->num_scans); + fov_mix = (int **)malloc(sizeof(int *) * mult_bsid->num_scans); + opp_in = (int **)malloc(sizeof(int *) * mult_bsid->num_scans); + stime = (double *)calloc(mult_bsid->num_scans, sizeof(double)); + + for(ifov = 0; ifov < 2; ifov++) + { + fovflg[ifov] = (int ***)malloc(sizeof(int **) + * mult_bsid->num_scans); + region[ifov] = (int ***)malloc(sizeof(int **) + * mult_bsid->num_scans); + hop[ifov] = (int ***)malloc(sizeof(int **) + * mult_bsid->num_scans); + + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + fovflg[ifov][iscan] = (int **)malloc(sizeof(int *) * nbms); + region[ifov][iscan] = (int **)malloc(sizeof(int *) * nbms); + hop[ifov][iscan] = (int **)malloc(sizeof(int *) * nbms); + } + } + } + + if(max_rg < num_rg) + { + if(max_rg == -1) + { + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + for(ifov = 0; ifov < 2; ifov++) + { + for(sbm = 0; sbm < nbms; sbm++) + { + fovflg[ifov][iscan][sbm] = (int *)malloc(sizeof(int) + * num_rg); + region[ifov][iscan][sbm] = (int *)malloc(sizeof(int) + * num_rg); + hop[ifov][iscan][sbm] = (int *)malloc(sizeof(int) + * num_rg); + } + } + + fov_in[iscan] = (int *)malloc(sizeof(int) * num_rg); + fov_out[iscan] = (int *)malloc(sizeof(int) * num_rg); + fov_mix[iscan] = (int *)malloc(sizeof(int) * num_rg); + opp_in[iscan] = (int *)malloc(sizeof(int) * num_rg); + } + } + else + { + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + for(ifov = 0; ifov < 2; ifov++) + { + for(sbm = 0; sbm < nbms; sbm++) + { + fovflg[ifov][iscan][sbm] = (int *) + realloc(fovflg[iscan], num_rg * sizeof(int)); + region[ifov][iscan][sbm] = (int *) + realloc(region[iscan], num_rg * sizeof(int)); + hop[ifov][iscan][sbm] = (int *) + realloc(hop[iscan], num_rg * sizeof(int)); + } + } + + fov_in[iscan] = (int *) + realloc(fov_in[iscan], num_rg * sizeof(int)); + fov_out[iscan] = (int *) + realloc(fov_out[iscan], num_rg * sizeof(int)); + fov_mix[iscan] = (int *) + realloc(fov_mix[iscan], num_rg * sizeof(int)); + opp_in[iscan] = (int *) + realloc(fov_in[iscan], num_rg * sizeof(int)); + } + } + + max_rg = num_rg; + } + + /* Cycle through each scan, loading the desired beam data */ + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + /* Load the desired beams for this scan */ + for(i = 0, sbm = min_bmnum; sbm <= max_bmnum; sbm++, i++) + { + if(iscan == 0 && sbm == bmnum) bind = ibm; + else bind = get_bm_by_bmnum(sbm, scan); + + bm = &scan->bm[bind]; + + if(ibm == 0) stime[iscan] = scan->st_time; + + /* Ensure a consistent CPID and number of range gates */ + if(bm->cpid == cpid && bm->nrang == num_rg) + { + /* Initialize each scan/RG pointer to zero */ + for(irg = 0; irg < num_rg; irg++) + { + for(ifov = 0; ifov < 2; ifov++) + { + fovflg[ifov][iscan][i][irg] = 0; + region[ifov][iscan][i][irg] = 0; + hop[ifov][iscan][i][irg] = 0; + } + + fov_in[iscan][irg] = 0; + fov_out[iscan][irg] = 0; + fov_mix[iscan][irg] = 0; + opp_in[iscan][irg] = 0; + } + + /* Load the FoV data for this beam, */ + /* sorting by path and RG bin */ + for(irg = 0; irg < num_rg; irg++) + { + /* Only consider data with a FoV flag */ + if(bm->sct[irg] == 1 && bm->rng_flgs[irg].fov != 0) + { + if(bm->rng_flgs[irg].fov == 1) + { + loc = bm->front_loc[irg]; + opp = bm->back_loc[irg]; + } + else + { + loc = bm->back_loc[irg]; + opp = bm->front_loc[irg]; + } + + /* Determine the path by region and hop */ + if(strstr(loc.region, "D") != NULL) ireg = 0; + else if(strstr(loc.region, "E") != NULL) ireg = 1; + else if(strstr(loc.region, "F") != NULL) ireg = 2; + else ireg = -1; + ihop = (int)(2.0 * loc.hop); + + if(ireg >= 0 && ihop > 0) + { + fovflg[0][iscan][i][irg] = bm->rng_flgs[irg].fov; + region[0][iscan][i][irg] = ireg; + hop[0][iscan][i][irg] = ihop; + } + + if(bm->rng_flgs[irg].fov_past != 0) + { + /* Determine the path by region and hop */ + if(strstr(opp.region, "D") != NULL) ireg = 0; + else if(strstr(opp.region, "E") != NULL) ireg = 1; + else if(strstr(opp.region, "F") != NULL) ireg = 2; + else ireg = -1; + ihop = (int)(2.0 * opp.hop); + + if(ireg >= 0 && ihop > 0) + { + fovflg[1][iscan][i][irg] = bm->rng_flgs[irg].fov_past; + region[1][iscan][i][irg] = ireg; + hop[1][iscan][i][irg] = ihop; + } + } + } + } + } + else + { + /* Set each scan/RG pointer to zero, ensuring no bad access */ + for(irg = 0; irg < max_rg; irg++) + { + for(ifov = 0; ifov < 2; ifov++) + { + fovflg[ifov][iscan][i][irg] = 0; + region[ifov][iscan][i][irg] = 0; + hop[ifov][iscan][i][irg] = 0; + } + + fov_in[iscan][irg] = 0; + fov_out[iscan][irg] = 0; + fov_mix[iscan][irg] = 0; + opp_in[iscan][irg] = 0; + } + } + } + + /* Cycle to the next scan */ + scan = scan->next_scan; + } + + /* For this beam, sum the number of front/back FoV detections in */ + /* each UT/RG/Region/Hop bin. */ + istime = 0; + ietime = 0; + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + /* Cycle the start time index */ + while(stime[iscan] - stime[istime] > 0.5 * ut_box_sec + && istime < iscan) + istime++; + + /* Cycle the end time index */ + while(stime[ietime] - stime[iscan] < 0.5 * ut_box_sec + && ietime < mult_bsid->num_scans - 1) + ietime++; + + for(irg = 0; irg < num_rg; irg++) + { + for(has_fov = 0, i = 0, sbm = min_bmnum; + sbm <= max_bmnum && has_fov == 0; sbm++, i++) + { + if(fovflg[0][iscan][i][irg] != 0) has_fov = 1; + } + + if(has_fov == 1) + { + /* Determine the range gate bin size */ + get_rg_box_limits(irg, num_rg, D_rgmax, E_rgmax, F_rgmax, + D_nrg, E_nrg, F_nrg, far_nrg, &rmin, &rmax); + + /* Determine the maximum number of points in this bin */ + max_pnts = (ietime - istime) * (rmax - rmin) * nbms; + + /* Cycle through all points in the UT/RG bin. Also test */ + /* to see if flipping this point agrees with all the other */ + /* (unflipped) points around it better than the current FoV */ + for(ifov = 0; ifov < 2; ifov++) + { + fnum[ifov] = 0; + bnum[ifov] = 0; + for(iwin = istime; iwin < ietime; iwin++) + { + for(ibox = rmin; ibox < rmax; ibox++) + { + for(i = 0, sbm = min_bmnum; sbm <= max_bmnum; + sbm++, i++) + { + if(iwin == iscan && ibox == irg) + { + if(fovflg[ifov][iwin][i][ibox] == 1) + fnum[ifov]++; + else if(fovflg[ifov][iwin][i][ibox] + == -1) + bnum[ifov]++; + } + else if((hop[0][iwin][i][ibox] + == hop[ifov][iscan][bmid][irg]) + && (region[0][iwin][i][ibox] == + region[ifov][iscan][bmid][irg])) + { + /* Sum, since this point has the same */ + /* propagation paths the central point */ + if(fovflg[0][iwin][i][ibox] == 1) + fnum[ifov]++; + else if(fovflg[0][iwin][i][ibox] == -1) + bnum[ifov]++; + } + } + } + } + + /* See if there are enough points for an evaluation */ + frac_num = (float)(fnum[ifov] + bnum[ifov]); + if(frac_num < (float)max_pnts * min_frac) + { + if(vb) + { + sprintf(vbuf, "insufficent data at beams "); + sprintf(vbuf, "%d - %d and RG %d for UT test\n", + min_bmnum, max_bmnum, irg); + } + } + else if(fnum[ifov] + bnum[ifov] > max_pnts) + { + fprintf(stderr, "too many points at beams %d-%d", + min_bmnum, max_bmnum); + fprintf(stderr, "range gate %d (%d > %d)\n", irg, + fnum[ifov] + bnum[ifov], max_pnts); + exit(1); + } + else + { + /* Evaluate the fraction of points in each FoV */ + frac_num = (float)fnum[ifov] / frac_num; + + if(ifov == 0) + { + if(frac_num >= fov_frac) + { + good_fov = 1; + bad_fov = -1; + } + else if(1.0 - frac_num >= fov_frac) + { + good_fov = 1; + bad_fov = 1; + } + else + { + good_fov = 0; + bad_fov = 0; + } + + /* Update the inlier/outlier/mixed sum for each */ + /* point that went into this evaluation. */ + for(iwin = istime; iwin < ietime; iwin++) + { + for(ibox = rmin; ibox < rmax; ibox++) + { + for(i = 0, sbm = min_bmnum; + sbm <= max_bmnum; sbm++, i++) + { + if((hop[ifov][iwin][i][ibox] + == hop[ifov][iscan][bmid][irg]) && + (region[ifov][iwin][i][ibox] == + region[ifov][iscan][bmid][irg])) + { + if(good_fov == 1) + { + if(fovflg[ifov][iwin][i][ibox] == bad_fov) + fov_out[iwin][ibox]++; + else fov_in[iwin][ibox]++; + } + else if(fovflg[ifov][iwin][i][ibox] != 0) + fov_mix[iwin][ibox]++; + } + } + } + } + } + else + { + /* Determine if swapping the FoV makes this */ + /* point an inlier. */ + past_frac = (float)fnum[0] / (float)(fnum[0] + + bnum[0]); + if(frac_num >= fov_frac + && fovflg[ifov][iscan][bmid][irg] == 1) + { + opp_in[iscan][irg] = 1; + + if(frac_num > past_frac) + opp_in[iscan][irg]++; + } + else if(1.0 - frac_num >= fov_frac + && fovflg[ifov][iscan][bmid][irg] == -1) + { + opp_in[iscan][irg] = 1; + + if(frac_num < past_frac) + opp_in[iscan][irg]++; + } + else opp_in[iscan][irg] = 0; + } + } + } + } + } + } + + /* Set the scan pointer back to the first scan */ + scan = mult_bsid->scan_ptr; + + /* Update the FoV flags for the central beam */ + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + /* Load the desired beam for this scan */ + if(iscan == 0) bind = ibm; + else bind = get_bm_by_bmnum(bmnum, scan); + + bm = &scan->bm[bind]; + + /* Ensure a consistent CPID and number of range gates */ + if(bm->cpid == cpid && bm->nrang == num_rg) + { + /* Load the FoV data for this beam, sorting by path and RG bin */ + for(irg = 0; irg < num_rg; irg++) + { + /* Only consider data with a FoV flag */ + if(bm->sct[irg] == 1 && fovflg[0][iscan][bmid][irg] != 0) + { + /* This point was included in the UT/RG */ + /* evaluation and can be updated if it is found */ + /* to be an outlier, not clearly in either FoV, */ + /* or a better inlier in the opposite FoV. */ + if(fov_in[iscan][irg] < (fov_out[iscan][irg] + + fov_mix[iscan][irg]) + && fov_out[iscan][irg] > 0) + { + /* This point is not an inlier */ + if(fov_out[iscan][irg] > fov_mix[iscan][irg] + && fov_out[iscan][irg] > fov_in[iscan][irg]) + /* This point is an outlier */ + bm->rng_flgs[irg].fov = bm->rng_flgs[irg].fov_past; + + else + { + if(opp_in[iscan][irg] > 0) + /* This point is an inlier when swapped */ + bm->rng_flgs[irg].fov = bm->rng_flgs[irg].fov_past; + else + /* This point is complicated */ + bm->rng_flgs[irg].fov = 0; + } + + bm->rng_flgs[irg].fov_past = fovflg[0][iscan][bmid][irg]; + } + else if(opp_in[iscan][irg] == 2) + { + /* This point is a better inlier when swapped */ + bm->rng_flgs[irg].fov = bm->rng_flgs[irg].fov_past; + bm->rng_flgs[irg].fov_past = fovflg[0][iscan][bmid][irg]; + } + } + } + } + + /* Cycle to the next scan */ + scan = scan->next_scan; + } + + /* Set the scan pointer back to the first scan */ + scan = mult_bsid->scan_ptr; + } + + /* Free the local pointers */ + if(fovflg != NULL) + { + for(iscan = 0; iscan < mult_bsid->num_scans; iscan++) + { + for(ifov = 0; ifov < 2; ifov++) + { + for(sbm = 0; sbm < nbms; sbm++) + { + free(fovflg[ifov][iscan][sbm]); + free(region[ifov][iscan][sbm]); + free(hop[ifov][iscan][sbm]); + } + + free(fovflg[ifov][iscan]); + free(region[ifov][iscan]); + free(hop[ifov][iscan]); + } + + free(fov_in[iscan]); + free(fov_out[iscan]); + free(fov_mix[iscan]); + free(opp_in[iscan]); + } + + for(ifov = 0; ifov < 2; ifov++) + { + free(fovflg[ifov]); + free(region[ifov]); + free(hop[ifov]); + } + + free(fovflg); + free(region); + free(hop); + free(fov_in); + free(fov_out); + free(fov_mix); + free(opp_in); + } + + return; +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/update_beam.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/update_beam.c new file mode 100644 index 000000000..0e9a0d665 --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/update_beam.c @@ -0,0 +1,215 @@ +/* update_beam.c + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include + +#include "radar.h" +#include "fitmultbsid.h" +#include "rpos.h" +#include "shfconst.h" +#include "elevation.h" +#include "propagation.h" + +#ifndef RE_KM +#define RE_KM Re / 1000.0 +#endif + +/** + * @brief Update the RadarBSIDBeam. + * + * @param[in] strict_gs - (1/0) Remove indeterminate backscatter (1) + * max_hop - maximum number of hops to consider (3.0) + * D_hmin - Minimum h' for D-region in km (75) + * D_hmax - Maximum h' for D-region in km (115) + * E_hmax - Maximum h' for E-region in km (150) + * F_hmax - Minimum h' for F-region in km (450) + * site - Radar hardware site structure + * + * @param[in/out] beam - Radar backscatter ID beam structure with data to update + **/ + +void UpdateBeamFit(short int strict_gs, float max_hop, float D_hmin, + float D_hmax, float E_hmax, float F_hmax, + struct RadarSite *site, struct FitBSIDBeam *beam) +{ + int irg; + + float vh_low, vh_high; + + void EvalGroundScatter(struct FitBSIDBeam *beam); + + /* Calculate the 1/2 hop distance and initialize the hop values */ + for(irg=0; irgnrang; irg++) + { + if(beam->sct[irg] == 1) + { + beam->front_loc[irg].dist = slant_range_no_edge(beam->frang, + beam->rsep, + (double)beam->rxrise, + irg); + beam->back_loc[irg].dist = beam->front_loc[irg].dist; + } + } + + /* Update the groundscatter flag */ + EvalGroundScatter(beam); + + /* Use the front and back lobe values */ + for(irg = 0; irg < beam->nrang; irg++) + { + if(beam->sct[irg] == 1) + { + if(beam->rng_flgs[irg].gflg == 1) + { + /* Update groundscatter hop and distance */ + beam->front_loc[irg].hop = 1.0; + beam->front_loc[irg].dist *= 0.5; + beam->back_loc[irg].hop = 1.0; + beam->back_loc[irg].dist *= 0.5; + } + else + { + if((strict_gs == 1) && (beam->rng_flgs[irg].gflg == -1)) + { + /* Remove bad groundscattter hop and distance by assigning */ + /* negative values (since NaN is more complicated) */ + beam->front_loc[irg].hop = 0.0; + beam->front_loc[irg].dist = 0.0; + beam->back_loc[irg].hop = 0.0; + beam->back_loc[irg].dist = 0.0; + beam->sct[irg] = 0; + } + else + { + beam->front_loc[irg].hop = 0.5; + beam->back_loc[irg].hop = 0.5; + + if(beam->rng[irg].p_l < 0.0) + { + /* Remove bad ionospheric hop and distance by assigning */ + /* unrealistic values (since NaN is more complicated) */ + beam->front_loc[irg].hop = 0.0; + beam->front_loc[irg].dist = 0.0; + beam->back_loc[irg].hop = 0.0; + beam->back_loc[irg].dist = 0.0; + beam->sct[irg] = 0; + } + } + } + + if(beam->sct[irg] == 1 && beam->rng[irg].phi0 == 0.0) + beam->sct[irg] = 0.0; + + else if(beam->sct[irg] == 1) + { + /* Calculate the elevation. Front must be assigned here */ + /* as well, since TDIFF may have been updated. */ + beam->front_elv[irg].normal = elevation_v2_lobe(1, beam->bm, + beam->freq, + beam->channel, + site, + beam->rng[irg].phi0); + beam->back_elv[irg].normal = elevation_v2_lobe(-1, beam->bm, + beam->freq, + beam->channel, + site, + beam->rng[irg].phi0); + + /* Calculate the virtual heights */ + beam->front_loc[irg].vh = calc_elv_vheight(beam->front_loc[irg].dist, beam->front_loc[irg].hop, RE_KM, beam->front_elv[irg].normal); + beam->back_loc[irg].vh = calc_elv_vheight(beam->back_loc[irg].dist, beam->back_loc[irg].hop, RE_KM, beam->back_elv[irg].normal); + sprintf(beam->front_loc[irg].vh_m, "E"); + sprintf(beam->back_loc[irg].vh_m, "E"); + + /* Test and adjust the virtual height and propagation path */ + AdjustPropagation(1, RE_KM, D_hmin, D_hmax, E_hmax, F_hmax, + max_hop, beam->bm, beam->freq, site, + beam->rng[irg].phi0, &beam->front_loc[irg].hop, + &beam->front_loc[irg].vh, + &beam->front_elv[irg].normal, + &beam->front_loc[irg].dist); + AdjustPropagation(-1, RE_KM, D_hmin, D_hmax, E_hmax, F_hmax, + max_hop, beam->bm, beam->freq, site, + beam->rng[irg].phi0, &beam->back_loc[irg].hop, + &beam->back_loc[irg].vh, + &beam->back_elv[irg].normal, + &beam->back_loc[irg].dist); + + /* If a realistic propagtion path could not be found in */ + /* either field of view, remove this positive scatter ID */ + if(beam->front_loc[irg].hop == 0.0 + && beam->back_loc[irg].hop == 0.0) + beam->sct[irg] = 0; + else + { + /* Add the elevation angle errors */ + beam->front_elv[irg].low = elevation_v2_lobe(1, beam->bm, + beam->freq, + beam->channel, + site, + beam->rng[irg].phi0 - beam->rng[irg].phi0_e); + beam->front_elv[irg].high = elevation_v2_lobe(1, beam->bm, + beam->freq, + beam->channel, + site, + beam->rng[irg].phi0 + beam->rng[irg].phi0_e); + beam->back_elv[irg].low = elevation_v2_lobe(-1, beam->bm, + beam->freq, + beam->channel, + site, + beam->rng[irg].phi0 - beam->rng[irg].phi0_e); + beam->back_elv[irg].high = elevation_v2_lobe(-1, beam->bm, + beam->freq, + beam->channel, + site, + beam->rng[irg].phi0 + beam->rng[irg].phi0_e); + + /* Add the virtual height errors */ + vh_low = beam->front_loc[irg].vh - calc_elv_vheight(beam->front_loc[irg].dist, beam->front_loc[irg].hop, RE_KM, beam->front_elv[irg].low); + vh_high = calc_elv_vheight(beam->back_loc[irg].dist, beam->back_loc[irg].hop, RE_KM, beam->front_elv[irg].high) - beam->front_loc[irg].vh; + beam->front_loc[irg].vh_e = (vh_low > vh_high) ? vh_low : vh_high; + + vh_low = beam->back_loc[irg].vh - calc_elv_vheight(beam->back_loc[irg].dist, beam->back_loc[irg].hop, RE_KM, beam->back_elv[irg].low); + vh_high = calc_elv_vheight(beam->back_loc[irg].dist, beam->back_loc[irg].hop, RE_KM, beam->back_elv[irg].high) - beam->back_loc[irg].vh; + beam->back_loc[irg].vh_e = (vh_low > vh_high) ? vh_low : vh_high; + + /* Add the region ID */ + SetRegion(beam->front_loc[irg].hop, D_hmin, D_hmax, E_hmax, + F_hmax, beam->front_loc[irg].vh, + beam->front_loc[irg].region); + SetRegion(beam->back_loc[irg].hop, D_hmin, D_hmax, E_hmax, + F_hmax, beam->back_loc[irg].vh, + beam->back_loc[irg].region); + } + } + } + else + { + /* Set defaults for the empty points */ + beam->front_loc[irg].hop = 0.0; + beam->front_loc[irg].dist = 0.0; + beam->front_elv[irg].normal = 0.0; + beam->front_elv[irg].low = 0.0; + beam->front_elv[irg].high = 0.0; + beam->back_loc[irg].hop = 0.0; + beam->back_loc[irg].dist = 0.0; + beam->back_elv[irg].normal = 0.0; + beam->back_elv[irg].low = 0.0; + beam->back_elv[irg].high = 0.0; + } + } + + return; +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/update_scan.c b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/update_scan.c new file mode 100644 index 000000000..c3b508d7f --- /dev/null +++ b/codebase/superdarn/src.bin/tk/tool/make_fov.1.0/update_scan.c @@ -0,0 +1,580 @@ +/* update_scan.c + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include + +#include "rmath.h" +#include "radar.h" +#include "fitmultbsid.h" +#include "scan_utils.h" + +#ifndef MAX_BMS +#define MAX_BMS 25 /* Current maximum in hdw files */ +#endif + +#ifndef MAX_RGS +#define MAX_RGS 225 /* Current maximum in hdw files */ +#endif + +#ifndef MIN_BMS +#define MIN_BMS 3 /* Minimum number of beams to find azimuthal variations */ +#endif + +#ifndef MAX_PATH +#define MAX_PATH 8 /* Minimum number of paths allowed */ +#endif + +/** + * @brief Update scan backscatter propagation path, elevation angle, + * backscatter type, structure flag, and origin field of view for all + * backscatter observatoins in each bean for a scan of data. A full + * scan is not necessary, but if the number of beams is less than the + * specified minimum, a less rigerous evaluation method will be used. + * + * @params[in] strict_gs - (1/0) Remove indeterminate backscatter (1) + * freq_min - Minimum allowed transmission frequency in kHz + * freq_max - Maximum transmission frequency limit in kHz + * min_pnts - Minimum number of points necessary to perfrom + * certain range gate or beam specific evaluations (3) + * D_nrg - Number of range gates for D-region box (2) + * E_nrg - Number of range gates for E-region box (5) + * F_nrg - Number of range gates for near F-region box (10) + * far_nrg - Number of range gates for far F-region box (20) + * D_rgmax - Maximum range gate for D-region box width (5) + * E_rgmax - Maximum range gate for E-region box width (25) + * F_rgmax - Maximum range gate for near F-region box width (40) + * D_hmin - Minimum h' for D-region in km (75) + * D_hmax - Maximum h' for D-region in km (100) + * E_hmax - Maximum h' for E-region in km (120) + * F_hmax - Minimum h' for F-region in km (450) + * D_vh_box - h' range for D-region box in km (40) + * E_vh_box - h' range for E-region box in km (35) + * F_vh_box - h' range for near F-region box in km (50) + * far_vh_box - h' range for far F-region box in km (150) + * max_hop - maximum number of hops to consider (3.0) + * scan - Input radar scan + * hard - Radar site information from hardware file + * + * @params[out] mult_bsid - Output scans with location and scan-assingned FoVs + **/ + +void UpdateScanBSFoV(short int strict_gs, int freq_min, int freq_max, + int min_pnts, int D_nrg, int E_nrg, int F_nrg, int far_nrg, + int D_rgmax, int E_rgmax, int F_rgmax, float D_hmin, + float D_hmax, float E_hmax, float F_hmax, float D_vh_box, + float E_vh_box, float F_vh_box, float far_vh_box, + float max_hop, struct RadarScan *scan, + struct RadarSite *hard, struct FitMultBSID *mult_bsid) +{ + int iscan, ibm, irg, ifov, ipath, ireg, ivh, igbm, cpid, scan_chan, max_vbin; + int bind, max_rg, out_num, group_num, bm_num, bmwidth, igood_num; + int igood[MAX_BMS], bgood[MAX_BMS]; + int group_bm[MAX_BMS * MAX_RGS], group_rg[MAX_BMS * MAX_RGS]; + int fovflg[MAX_BMS][MAX_RGS], fovpast[MAX_BMS][MAX_RGS]; + int fovextreme[MAX_BMS][MAX_RGS], fovbelong[MAX_BMS][MAX_RGS][3]; + int opp_in[MAX_BMS][MAX_RGS], scan_num[3][2][MAX_PATH]; + int scan_bm[3][2][MAX_PATH][MAX_BMS * MAX_RGS]; + int scan_rg[3][2][MAX_PATH][MAX_BMS * MAX_RGS]; + + float hmin, hmax, hbox, *vmins, *vmaxs; + float group_elv[MAX_BMS * MAX_RGS], group_vh[MAX_BMS * MAX_RGS]; + float fovstd[MAX_BMS][MAX_RGS], fovscore[MAX_BMS][MAX_RGS]; + float scan_vh[3][2][MAX_PATH][MAX_BMS * MAX_RGS]; + float scan_elv[3][2][MAX_PATH][MAX_BMS * MAX_RGS]; + + struct CellBSIDLoc loc; + struct FitElv elv; + struct RadarBeam bm_old; + struct FitBSIDBeam *bm_new; + struct FitBSIDScan *scan_new, *prev_new; + + void UpdateBeamFit(short int strict_gs, float max_hop, float D_hmin, + float D_hmax, float E_hmax, float F_hmax, + struct RadarSite *site, struct FitBSIDBeam *beam); + int select_alt_groups(int num, float vh[], float vh_min, float vh_max, + float vh_box, int min_pnts, int max_vbin, + float *vh_mins, float *vh_maxs); + + /* Test to ensure the local definitions agree with the hardware file */ + if(MAX_BMS < hard->maxbeam || MAX_RGS < hard->maxrange) + { + fprintf(stderr, "local definitions of max range gates or beams is "); + fprintf(stderr, "too small [%d > %d or %d > %d]\n", MAX_BMS, + hard->maxbeam, MAX_RGS, hard->maxrange); + exit(1); + } + + /* Initialize the local pointers and variables */ + bmwidth = (int)((float)min_pnts * 0.75); + + for(ibm = 0; ibm < MAX_BMS; ibm++) + { + igood[ibm] = -1; + bgood[ibm] = -1; + + for(irg = 0; irg < MAX_RGS; irg++) + { + fovflg[ibm][irg] = 0; + fovpast[ibm][irg] = 0; + fovextreme[ibm][irg] = 0; + fovstd[ibm][irg] = 0.0; + fovscore[ibm][irg] = 0.0; + opp_in[ibm][irg] = 0; + + for(iscan = 0; iscan < 3; iscan++) + fovbelong[ibm][irg][iscan] = 0; + } + } + + if(max_hop * 2.0 > MAX_PATH) + { + fprintf(stderr, "maximum hop greater than allowed limit (%f > %f)\n", + max_hop, MAX_PATH / 2.0); + exit(1); + } + + for(ireg = 0; ireg < 3; ireg++) + { + if(ireg == 0) out_num = D_rgmax * scan->num; + else if(ireg == 1) out_num = E_rgmax * scan->num; + else out_num = F_rgmax * scan->num; + + if(out_num > MAX_BMS * MAX_RGS) + { + fprintf(stderr, + "Maximum range gates for region %s too big for %d beams\n", + (ireg == 0) ? "D" : ((ireg == 1) ? "E" : "F"), scan->num); + exit(1); + } + + for(ifov = 1; ifov >= 0; ifov--) + { + for(ipath = 0; ipath < MAX_PATH; ipath++) + { + scan_num[ireg][ifov][ipath] = 0; + + for(ivh = 0; ivh < MAX_BMS * MAX_RGS; ivh++) + { + scan_rg[ireg][ifov][ipath][ivh] = -1; + scan_bm[ireg][ifov][ipath][ivh] = -1; + scan_elv[ireg][ifov][ipath][ivh] = -1.0; + scan_vh[ireg][ifov][ipath][ivh] = -1.0; + } + } + } + } + + max_vbin = (F_rgmax > E_rgmax) ? F_rgmax : E_rgmax; + if(D_rgmax > max_vbin) max_vbin = D_rgmax; + vmins = (float *)calloc(max_vbin, sizeof(float)); + vmaxs = (float *)calloc(max_vbin, sizeof(float)); + + /* Before initializing this new scan data, make sure the frequency for the */ + /* beams are correct. Also test to ensure constant CPID and channel. */ + for(igood_num = 0, ibm = 0; ibm < scan->num && igood_num >= 0; ibm++) + { + bm_old = scan->bm[ibm]; + + if(ibm == 0) + { + cpid = bm_old.cpid; + scan_chan = bm_old.channel; + } + + if(bm_old.freq >= freq_min && bm_old.freq < freq_max) + { + /* Only verify CPID and channel for requested frequency range */ + if(cpid != bm_old.cpid) + { + fprintf(stderr, + "CP changes in scan, try limiting channels [%d != %d]\n", + cpid, bm_old.cpid); + exit(1); + } + if(scan_chan != bm_old.channel) + { + fprintf(stderr, + "channel changes in scan, try -cn option [%d != %d]\n", + scan_chan, bm_old.channel); + exit(1); + } + + /* If there are too many good beams in this scan, exit */ + if(igood_num >= hard->maxbeam) + { + fprintf(stderr, "too many beams in scan [%d-%d kHZ, %d CPID]\n", + freq_min, freq_max, cpid); + igood_num = -1; + break; + } + else + { + igood[igood_num] = ibm; + bgood[igood_num] = bm_old.bm; + igood_num++; + } + } + } + + /* If there are good beams in this scan, add it to the output structure. */ + /* If there are too many good beams, this is a beam-switching mode and */ + /* we can't currently process it. */ + if(igood_num >= MIN_BMS && igood_num <= hard->maxbeam) + { + /* Test to see that there are no duplicate beams. This is something */ + /* that may be possible to process, but isn't at the moment. */ + if(num_unique_int_vals(igood_num, bgood) != igood_num) + { + fprintf(stderr, + "duplicate beams in scan, requires different FoV method\n"); + } + else + { + /* Inititalize the output scan */ + scan_new = (struct FitBSIDScan *)malloc(sizeof(struct FitBSIDScan)); + + if(mult_bsid->num_scans == 0) + { + mult_bsid->scan_ptr = scan_new; + mult_bsid->stid = scan->stid; + mult_bsid->st_time = scan->st_time; + mult_bsid->ed_time = scan->ed_time; + mult_bsid->version.major = scan->version.major; + mult_bsid->version.minor = scan->version.minor; + prev_new = (struct FitBSIDScan *)(NULL); + } + else + { + prev_new = mult_bsid->last_ptr; + prev_new->next_scan = scan_new; + scan_new->prev_scan = prev_new; + scan_new->next_scan = (struct FitBSIDScan *)(NULL); + mult_bsid->ed_time = scan->ed_time; + } + mult_bsid->last_ptr = scan_new; + + scan_new->st_time = scan->st_time; + scan_new->ed_time = scan->ed_time; + scan_new->num_bms = scan->num; + scan_new->bm = (struct FitBSIDBeam *) + malloc(sizeof(struct FitBSIDBeam) * scan_new->num_bms); + memset(scan_new->bm, 0, sizeof(struct FitBSIDBeam) + * scan_new->num_bms); + + max_rg = 0; + + /* Cycle through each beam in the scan, but only update the beams */ + /* with appropriate frequencies. */ + for(igbm = 0, ibm = 0; ibm < scan_new->num_bms; ibm++) + { + if(igood[igbm] == ibm) + { + igbm++; + bm_old = scan->bm[ibm]; + bm_new = &scan_new->bm[ibm]; + + /* This corresponds to + * davitpy.pydarn.proc.fov.update_backscatter.update_beam_fit + * + * Start by initializing new beams in the new scan */ + bm_new->cpid = bm_old.cpid; + bm_new->bm = bm_old.bm; + bm_new->bmazm = bm_old.bmazm; + bm_new->time = bm_old.time; + bm_new->intt.sc = bm_old.intt.sc; + bm_new->intt.us = bm_old.intt.us; + + /* Set the beam parameter values */ + bm_new->nave = bm_old.nave; + bm_new->frang = bm_old.frang; + bm_new->rsep = bm_old.rsep; + bm_new->rxrise = bm_old.rxrise; + bm_new->freq = bm_old.freq; + bm_new->noise = bm_old.noise; + bm_new->atten = bm_old.atten; + bm_new->channel = bm_old.channel; + + /* Initialize the range-dependent variables */ + bm_new->nrang = bm_old.nrang; + bm_new->rng = (struct RadarCell *) + calloc(bm_new->nrang, sizeof(struct RadarCell)); + bm_new->med_rng = (struct RadarCell *) + calloc(bm_new->nrang, sizeof(struct RadarCell)); + bm_new->rng_flgs = (struct CellBSIDFlgs *) + malloc(bm_new->nrang * sizeof(struct CellBSIDFlgs)); + bm_new->front_loc = (struct CellBSIDLoc *) + malloc(bm_new->nrang * sizeof(struct CellBSIDLoc)); + bm_new->back_loc = (struct CellBSIDLoc *) + malloc(bm_new->nrang * sizeof(struct CellBSIDLoc)); + bm_new->front_elv = (struct FitElv *) + calloc(bm_new->nrang, sizeof(struct FitElv)); + bm_new->back_elv = (struct FitElv *) + calloc(bm_new->nrang, sizeof(struct FitElv)); + if(bm_old.sct == NULL) bm_new->sct = (unsigned char *)(NULL); + else bm_new->sct = (unsigned char *) + calloc(bm_new->nrang, sizeof(char)); + + if(bm_new->nrang > max_rg) max_rg = bm_new->nrang; + + for(irg = 0; irg < bm_new->nrang; irg++) + { + bm_new->sct[irg] = bm_old.sct[irg]; + + /* Load only for range gates with data */ + if(bm_old.sct[irg] == 1) + { + bm_new->rng[irg].gsct = bm_old.rng[irg].gsct; + bm_new->rng[irg].p_0 = bm_old.rng[irg].p_0; + bm_new->rng[irg].p_0_e = bm_old.rng[irg].p_0_e; + bm_new->rng[irg].v = bm_old.rng[irg].v; + bm_new->rng[irg].v_e = bm_old.rng[irg].v_e; + bm_new->rng[irg].w_l = bm_old.rng[irg].w_l; + bm_new->rng[irg].w_l_e = bm_old.rng[irg].w_l_e; + bm_new->rng[irg].p_l = bm_old.rng[irg].p_l; + bm_new->rng[irg].p_l_e = bm_old.rng[irg].p_l_e; + bm_new->rng[irg].phi0 = bm_old.rng[irg].phi0; + bm_new->rng[irg].phi0_e = bm_old.rng[irg].phi0_e; + bm_new->rng[irg].elv = bm_old.rng[irg].elv; + + /* Initialize the range gate flags */ + bm_new->rng_flgs[irg].gflg = bm_new->rng[irg].gsct; + bm_new->rng_flgs[irg].fov = 0; + bm_new->rng_flgs[irg].fov_past = 0; + bm_new->rng_flgs[irg].grpflg = 0; + bm_new->rng_flgs[irg].grpnum = 0; + sprintf(bm_new->rng_flgs[irg].grpid, "U"); + } + } + + /* Update the front and back FoVs */ + UpdateBeamFit(strict_gs, max_hop, D_hmin, D_hmax, + E_hmax, F_hmax, hard, bm_new); + + /* Find the scan's altitude bins by FoV, region, and path */ + for(irg = 0; irg < bm_new->nrang; irg++) + { + if(bm_new->sct[irg] == 1) + { + /* Assign this data to the correct region list for */ + /* each FoV (ifov is 0 for back and 1 for front). */ + /* Try the front FoV first, because it is more */ + /* likely to be correct and only assign the rear */ + /* FoV if it is clearly superior. */ + for(ifov = 1; ifov >= 0; ifov--) + { + if(ifov == 0) + { + loc = bm_new->back_loc[irg]; + elv = bm_new->back_elv[irg]; + } + else + { + loc = bm_new->front_loc[irg]; + elv = bm_new->front_elv[irg]; + } + + ipath = (int)(loc.hop * 2.0); + if(strstr(loc.region, "D") != NULL) ireg = 0; + else if(strstr(loc.region, "E") != NULL) ireg = 1; + else if(strstr(loc.region, "F") != NULL) ireg = 2; + else ireg = -1; + + if(ireg >= 0) + { + if(ipath == 0) + { + fprintf(stderr, "bad hop encountered at"); + fprintf(stderr, " beam [%d], range", ibm); + fprintf(stderr, " gate [%d], FoV [", irg); + fprintf(stderr, "%s], time %f\n", + (ifov == 0) ? "back" : "front", + scan_new->st_time); + exit(1); + } + + scan_bm[ireg][ifov][ipath][scan_num[ireg][ifov][ipath]] = bm_new->bm; + scan_rg[ireg][ifov][ipath][scan_num[ireg][ifov][ipath]] = irg; + scan_vh[ireg][ifov][ipath][scan_num[ireg][ifov][ipath]] = (float)loc.vh; + scan_elv[ireg][ifov][ipath][scan_num[ireg][ifov][ipath]] = (float)elv.normal; + scan_num[ireg][ifov][ipath]++; + } + } + } + } + } + } + + /* To determine the FoV, evaluate the elevation variations across */ + /* all beams for a range gate and virtual height band, considering */ + /* each propagation path (region and hop) seperately. */ + for(ireg = 0; ireg < 3; ireg++) + { + if(ireg == 0) + { + hmin = D_hmin; + hmax = D_hmax; + hbox = D_vh_box; + } + else if(ireg == 1) + { + hmin = D_hmax; + hmax = E_hmax; + hbox = E_vh_box; + } + else if(ireg == 2) + { + hmin = E_hmax; + hmax = F_hmax; + hbox = F_vh_box; + } + + for(ifov = 1; ifov >= 0; ifov--) + { + for(ipath = 1; ipath < MAX_PATH; ipath++) + { + if(ireg == 2 && ipath >= 3) hbox = far_vh_box; + + if(scan_num[ireg][ifov][ipath] >= min_pnts) + { + /* Use select_alt_groups */ + out_num = select_alt_groups(scan_num[ireg][ifov][ipath], scan_vh[ireg][ifov][ipath], hmin, hmax, hbox, min_pnts, max_vbin, vmins, vmaxs); + + if(out_num > max_vbin) + { + fprintf(stderr, "too many virtual height bins\n"); + exit(1); + } + + /* For each virtual height bin, determine if this */ + /* FoV has a realistic azimuth variation. */ + for(ivh = 0; ivh < out_num; ivh++) + { + for(group_num = 0, irg = 0; + irg < scan_num[ireg][ifov][ipath]; irg++) + { + if(scan_vh[ireg][ifov][ipath][irg] + >= vmins[ivh] + && scan_vh[ireg][ifov][ipath][irg] + < vmaxs[ivh]) + { + group_bm[group_num] = scan_bm[ireg][ifov][ipath][irg]; + group_rg[group_num] = scan_rg[ireg][ifov][ipath][irg]; + group_vh[group_num] = scan_vh[ireg][ifov][ipath][irg]; + group_elv[group_num] = scan_elv[ireg][ifov][ipath][irg]; + group_num++; + + if(group_num >= MAX_BMS * MAX_RGS) + { + fprintf(stderr, + "too many points in group\n"); + exit(1); + } + } + } + + if(group_num >= min_pnts) + { + /* Test to see if there are enough beams */ + bm_num = num_unique_int_vals(group_num, + group_bm); + + if(bm_num >= MIN_BMS) + eval_az_var_in_elv(group_num, ifov, + group_bm, group_rg, + fovflg, fovpast, + group_vh, group_elv, + fovstd, fovscore, + fovextreme); + } + } + } + } + } + } + + /* Evaluate the FoV flags, removing points that are surrounded by */ + /* data assigned to the opposite FoV. */ + eval_fov_flag_consistency(max_rg, hard->maxbeam, bmwidth, D_rgmax, + D_nrg, E_rgmax, E_nrg, F_rgmax, F_nrg, + far_nrg, fovflg, fovpast, fovbelong, + opp_in, scan_new); + + /* Assign the appropriate virtual heights, regions, and elevation */ + /* angles to each point based on their FoV. */ + for(ibm = 0; ibm < scan_new->num_bms; ibm++) + { + bm_new = &scan_new->bm[ibm]; + bind = bm_new->bm; + + for(irg = 0; irg < bm_new->nrang; irg++) + { + /* Remove or change the FoV of any points flagged as */ + /* outliers. Recall that in the last dimension of fovbelong */ + /* the 0 index records the times flagged as an inlier, the */ + /* 1 index records the times flagged as an outlier, and */ + /* the index 2 records the times with mixed FoVs. */ + if((fovbelong[bind][irg][0] < fovbelong[bind][irg][1] + + fovbelong[bind][irg][2]) && fovbelong[bind][irg][1] > 0) + { + /* This point is an outlier in a structure with the */ + /* opposite FoV. If this point fit the criteria for */ + /* a different FoV in the past, assign that FoV. */ + /* Otherwise remove any FoV assignment. */ + if((fovbelong[bind][irg][1] > fovbelong[bind][irg][2]) + && (fovbelong[bind][irg][1] > fovbelong[bind][irg][0])) + fovflg[bind][irg] = fovpast[bind][irg]; + else + fovflg[bind][irg] = 0; + + /* Clear the past (former present), since it proved to */ + /* be unrealistic */ + fovpast[bind][irg] = 0; + } + else if(opp_in[bind][irg] == 1 && + (fovbelong[bind][irg][0] >= fovbelong[bind][irg][1] + + fovbelong[bind][irg][2])) + { + /* This point is a better inlier when swapped */ + /* and not an inlier when it isn't swapped. */ + fovflg[bind][irg] = fovpast[bind][irg]; + fovpast[bind][irg] *= -1; + } + + /* Update the location values for this beam and range gate */ + bm_new->rng_flgs[irg].fov = fovflg[bind][irg]; + bm_new->rng_flgs[irg].fov_past = fovpast[bind][irg]; + } + } + + /* Cycle to the next scan, if a new scan was loaded */ + scan_new->next_scan = (struct FitBSIDScan *) + malloc(sizeof(struct FitBSIDScan)); + prev_new = scan_new; + scan_new = scan_new->next_scan; + scan_new->prev_scan = prev_new; + mult_bsid->last_ptr = prev_new; + scan_new->next_scan = (struct FitBSIDScan *)(NULL); + mult_bsid->num_scans++; + } + } + + /* Free the assigned memory */ + free(vmins); + free(vmaxs); + + return; +} diff --git a/codebase/superdarn/src.bin/tk/tool/make_grid.2.0/make_grid.c b/codebase/superdarn/src.bin/tk/tool/make_grid.2.0/make_grid.c index 5cc29b17a..5d8df0c86 100644 --- a/codebase/superdarn/src.bin/tk/tool/make_grid.2.0/make_grid.c +++ b/codebase/superdarn/src.bin/tk/tool/make_grid.2.0/make_grid.c @@ -26,6 +26,7 @@ along with this program. If not, see . Modifications: 2021-01-11 Marina Schmidt fixing concatenation bug with start/end time, and deprecated -c flag 2021-08-27 Angeline G Burrell removed duplicate code now present in libraries + 2021-10-04 Angeline G Burrell removed duplicate code now present in radar library */ @@ -85,8 +86,6 @@ struct RadarScan *out; struct FitIndex *inx; -struct RadarNetwork *network; -struct Radar *radar; struct RadarSite *site; int nbox; @@ -102,10 +101,11 @@ struct GridTable *grid; /** - * Exclude scatter in range gates below minrng or beyond maxrng, - * or from slant ranges below minsrng or beyond maxsrng. If range - * gate and slant range thresholds are both provided, only the - * slant range thresholds are considered. + * Exclude scatter in range gates below minrng or beyond maxrng (the minimum + * and maximum range gates, respectively), or from slant ranges below + * minsrng or beyond maxsrng (the minimum and maximum slant ranges, + * respectively). If range gate and slant range thresholds are both provided, + * only the slant range thresholds are considered. **/ void exclude_range(struct RadarScan *ptr,int minrng,int maxrng, double minsrng,double maxsrng) { @@ -156,7 +156,7 @@ void exclude_range(struct RadarScan *ptr,int minrng,int maxrng, /** - * + * Parse the comma separated list of beams to exclude **/ void parse_ebeam(char *str) { @@ -181,6 +181,55 @@ void parse_ebeam(char *str) { } + +/** + * Converts an input date from YYYYMMDD format to an epoch time in number of + * seconds since 00:00 UT on January 1, 1970. + **/ +double strdate(char *text) { + + double tme; + int val; + int yr,mo,dy; + + /* Calculate day, month, and year from YYYYMMDD format date */ + val=atoi(text); + dy=val % 100; + mo=(val / 100) % 100; + yr=(val / 10000); + + /* If only 2-digit year provided then assume it was pre-2000 */ + if (yr<1970) yr+=1900; + + /* Calculate epoch time of input year, month, and day */ + tme=TimeYMDHMSToEpoch(yr,mo,dy,0,0,0); + + /* Return epoch time in number of seconds since 00:00UT on January 1, 1970 */ + return tme; + +} + + +/** + * Converts an input time from HHMM format to number of seconds. + **/ +double strtime(char *text) { + + int hr,mn; + int i; + + for (i=0;(text[i] !=':') && (text[i] !=0);i++); + if (text[i]==0) return atoi(text)*3600L; + text[i]=0; + hr=atoi(text); + mn=atoi(text+i+1); + return hr*3600L+mn*60L; + +} + +/** + * Outputs an error statement for an unrecognized input option + **/ int rst_opterr(char *txt) { fprintf(stderr,"Option not recognized: %s\n",txt); fprintf(stderr,"Please try: make_grid --help\n"); @@ -235,9 +284,6 @@ int main(int argc,char *argv[]) { double sdate=-1; double edate=-1; - char *envstr; - FILE *fp; - int bxcar=0; int limit=0; int bflg=0; @@ -296,38 +342,6 @@ int main(int argc,char *argv[]) { /* Initialize GridTable structure */ grid=GridTableMake(); - /* Make sure the SD_RADAR environment variable is set */ - envstr=getenv("SD_RADAR"); - if (envstr==NULL) { - fprintf(stderr,"Environment variable 'SD_RADAR' must be defined.\n"); - exit(-1); - } - - /* Open the radar information file */ - fp=fopen(envstr,"r"); - if (fp==NULL) { - fprintf(stderr,"Could not locate radar information file.\n"); - exit(-1); - } - - /* Load the radar network information */ - network=RadarLoad(fp); - fclose(fp); - if (network==NULL) { - fprintf(stderr,"Failed to read radar information.\n"); - exit(-1); - } - - /* Make sure the SD_HDWPATH environment variable is set */ - envstr=getenv("SD_HDWPATH"); - if (envstr==NULL) { - fprintf(stderr,"Environment variable 'SD_HDWPATH' must be defined.\n"); - exit(-1); - } - - /* Load the hardware information for the radar network */ - RadarLoadHardware(envstr,network); - /* Set up command line options */ OptionAdd(&opt,"-help",'x',&help); /* Print the help message and exit */ OptionAdd(&opt,"-option",'x',&option); /* Print all command line options */ @@ -735,14 +749,9 @@ int main(int argc,char *argv[]) { /* Load the appropriate radar hardware information for the day * and time of the radar scan (only done once) */ - if (site==NULL) { - radar=RadarGetRadar(network,out->stid); - if (radar==NULL) { - fprintf(stderr,"Failed to get radar information.\n"); - exit(-1); - } - site=RadarYMDHMSGetSite(radar,yr,mo,dy,hr,mt,(int) sc); - } + if (site==NULL) + site = load_radar_site(yr, mo, dy, hr, mt, (int)sc, + out->stid); /* Test whether gridded data should be written to a file; if so * returns weighted average velocity, power, and width values diff --git a/codebase/superdarn/src.lib/tk/elevation.1.0/include/elevation.h b/codebase/superdarn/src.lib/tk/elevation.1.0/include/elevation.h index 02a1b801f..3e990931c 100644 --- a/codebase/superdarn/src.lib/tk/elevation.1.0/include/elevation.h +++ b/codebase/superdarn/src.lib/tk/elevation.1.0/include/elevation.h @@ -23,11 +23,27 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . Modifications: +2021-09-27 Angeline G. Burrell: Added a version of the elevation angle routine + that accounts for lobe direction. */ +#ifndef _RMATH_H +#include "rmath.h" +#endif + +#ifndef _RADAR_H +#include "radar.h" +#endif + +#ifndef _FITBLK_H +#include "fitblk.h" +#endif + #ifndef _ELEVATION_H #define _ELEVATION_H +double elevation_v2_lobe(int lobe, int bmnum, int tfreq, int channel, + struct RadarSite *site, double psi_obs); double elevation(struct FitPrm *prm, double phi0); double elevation_v2(struct FitPrm *prm, double psi_obs); double elev_goose(struct FitPrm *prm, double phi0); diff --git a/codebase/superdarn/src.lib/tk/elevation.1.0/src/elevation_v2.c b/codebase/superdarn/src.lib/tk/elevation.1.0/src/elevation_v2.c index f12b60651..17753f558 100644 --- a/codebase/superdarn/src.lib/tk/elevation.1.0/src/elevation_v2.c +++ b/codebase/superdarn/src.lib/tk/elevation.1.0/src/elevation_v2.c @@ -23,10 +23,16 @@ along with this program. If not, see . Modifications: E.G.Thomas 2021-08: added support for bmoff parameter + 2021-09-27 Angeline G. Burrell: Added a version of the elevation angle routine + that accounts for lobe direction. + */ #include #include + +#include "fitblk.h" +#include "radar.h" #include "rmath.h" #include "fitblk.h" @@ -124,3 +130,131 @@ double elevation_v2(struct FitPrm *prm, double psi_obs) return (180.*alpha/PI); } + +/** + * @brief Calculate elevation for the specified field of view + * + * @param[in] lobe - Field-of-view specifier: 1=front, -1=back + * bmnum - Beam number (zero offset) + * tfreq - Transmission frequency in kHz + * channel - Channel index for tdiff + * site - Radar hardware site structure + * psi_obs - Phase lag value + * + * @param[out] alpha - Elevation angle [deg] + * + * @notes SGS somehow need to pass in options for allowing negative elevation + * angles and residual phase + **/ + +double elevation_v2_lobe(int lobe, int bmnum, int tfreq, int channel, + struct RadarSite *site, double psi_obs) +{ + static double X, Y, Z; /* interferometer offsets [m] */ + double k; /* wavenumber [rad/m] */ + double boff; /* offset in beam widths to edge of FOV */ + double phi0_max; /* beam direction off boresight [rad] */ + double cp0, sp0; /* cosine and sine of phi0 */ + double ca0, sa0; /* cosine and sine of a0 */ + double psi_ele; /* phase delay due to electrical path diff [rad] */ + double psi_max; /* max and min phase difference [rad] */ + double a0; /* angle where phase is maximum [rad] */ + int sgn; /* sign of Y offset */ + double dpsi; /* delta phase [rad] */ + double n2pi; /* number of 2PI factors */ + double d2pi; /* correct multiple value of 2PIs */ + double E; /* factor for simplifying expression */ + double alpha; /* elevation angle [degrees] */ + + static double d = -9999.0; /* separation of antenna arrays [m] */ + + /* At first call, calculate the values that don't change. */ + if (d < -999.0) + { + X = site->interfer[0]; + Y = site->interfer[1]; + Z = site->interfer[2]; + + d = sqrt(X*X + Y*Y + Z*Z); + } + + /* SGS: 20180926 + * + * There is still some question as to exactly what the phidiff parameter in + * the hdw.dat files means. The note in the hdw.dat files, presumably written + * by Ray is: + * 12) Phase sign (Cabling errors can lead to a 180 degree shift of the + * interferometry phase measurement. +1 indicates that the sign is + * correct, -1 indicates that it must be flipped.) + * The _only_ hdw.dat file that has this value set to -1 is GBR during the + * time period: 19870508 - 19921203 + * + * To my knowlege there is no data available prior to 1993, so dealing with + * this parameter is no longer necessary. For this reason I am simply + * removing it from this algorithm. + */ + + sgn = (Y < 0) ? -1 : 1; + + boff = (double)site->maxbeam / 2.0 - 0.5; + phi0_max = site->bmsep * ((double)bmnum - boff) * PI / 180.0; + + cp0 = cos(phi0_max); + sp0 = sin(phi0_max); + + /* Determine the elevation angle (a0) where the phase difference (psi) is * + * at its maximum. This occurs when k and d are anti-parallel. Using * + * calculus of variations to compute the value: d(psi)/d(a) = 0 */ + a0 = asin(sgn * Z * cp0 / sqrt(Y*Y + Z*Z)); + + /* Note: We are assuming that negative elevation angles are unphysical. * + * The act of setting a0 = 0 _only_ has the effect to change psi_max * + * (which is used to compute the correct number of 2pi factors and map * + * the observed phase to the actual phase. The _only_ elevation angles * + * that are affected are the small range from [-a0, 0]. Instead of * + * these being mapped to negative elevation they are mapped to very * + * small ranges just below the maximum. */ + + /* Note that it is possible in some cases with sloping ground that * + * extends far in front of the radar, that negative elevation angles * + * might exist. However, since elevation angles near the maximum "share" * + * this phase [-pi, pi] it is perhaps more likely that the higher * + * elevation angles are actually what is being observed. */ + + /* In either case, one must decide which angle to chose (just as with all * + * the aliased angles). Here we decide that negative elevation angles are */ + /* unphysical and map them to the upper end. */ + + if (a0 < 0.0) a0 = 0.0; + + ca0 = cos(a0); + sa0 = sin(a0); + k = 2.0 * PI * tfreq * 1000.0 / C; + + /* Phase delay [radians] due to electrical path difference. * + * If the path length (cable and electronics) to the interferometer is * + * shorter than that to the main antenna array, then the time for the * + * to transit the interferometer electrical path is shorter: tdiff < 0 */ + psi_ele = -2.0 * PI * tfreq * site->tdiff[channel] * 1.0e-3; + + /* maximum phase = psi_ele + psi_geo(a0) */ + psi_max = psi_ele + k * (X * sp0 + Y * sqrt(ca0 * ca0 - sp0 * sp0) + Z * sa0); + + /* Compute the number of 2pi factors necessary to map to correct region. * + * The lobe direction changes the sign of the observed phase difference, * + * phi_obs. (AGB) */ + psi_obs *= (double)lobe; + dpsi = psi_max - psi_obs; + n2pi = (Y > 0) ? floor(dpsi / (2.0 * PI)) : ceil(dpsi / (2.0 * PI)); + d2pi = n2pi * 2.0 * PI; + psi_obs += d2pi; + + /* Evaluate the phase shift and solve for the elevation angle, alpha */ + E = (psi_obs / (k * C) + site->tdiff[channel] * 1.0e-6) * C - X * sp0; + alpha = asin((E * Z + sqrt(E * E * Z * Z - (Y * Y + Z * Z) + * (E * E - Y * Y * cp0 * cp0))) + / (Y * Y + Z * Z)); + alpha *= 180.0 / PI; /* Convert from radians to degrees */ + + return(alpha); +} diff --git a/codebase/superdarn/src.lib/tk/fit.1.35/src/fitscan.c b/codebase/superdarn/src.lib/tk/fit.1.35/src/fitscan.c index dd25f944d..907e45d1c 100644 --- a/codebase/superdarn/src.lib/tk/fit.1.35/src/fitscan.c +++ b/codebase/superdarn/src.lib/tk/fit.1.35/src/fitscan.c @@ -166,11 +166,12 @@ int FitReadRadarScan(int fid, int *state, bm->rng[r].p_l=fit->rng[r].p_l; bm->rng[r].w_l=fit->rng[r].w_l; bm->rng[r].v_e=fit->rng[r].v_err; - if (fit->xrng !=NULL) bm->rng[r].phi0=fit->xrng[r].phi0; + if (fit->xrng != NULL) bm->rng[r].phi0=fit->xrng[r].phi0; else bm->rng[r].phi0=0; - if (fit->elv !=NULL) bm->rng[r].elv=fit->elv[r].normal; + if (fit->elv != NULL) bm->rng[r].elv=fit->elv[r].normal; else bm->rng[r].elv=0; - + if (fit->xrng != NULL) bm->rng[r].phi0_e=fit->rng[r].phi0_err; + else bm->rng[r].phi0_e=0; } /* Calculate end time of radar scan */ @@ -235,8 +236,8 @@ int FitReadRadarScan(int fid, int *state, * variable */ if (flg==1) *state=2; - /* Return zero on success, 1 if the end of file was reached, or -1 if an error - * occurred */ + /* Return zero on success, 1 if the end of file was reached, or -1 if an + * error occurred */ return flg; } diff --git a/codebase/superdarn/src.lib/tk/fitacf_v3.0/include/leastsquares.h b/codebase/superdarn/src.lib/tk/fitacf_v3.0/include/leastsquares.h index 1a58aef71..58e67a49d 100644 --- a/codebase/superdarn/src.lib/tk/fitacf_v3.0/include/leastsquares.h +++ b/codebase/superdarn/src.lib/tk/fitacf_v3.0/include/leastsquares.h @@ -80,5 +80,6 @@ void find_chi_2(llist_node data,FITDATA *fit_data,FIT_TYPE* fit_type); void calculate_sums(llist_node data,FITDATA *fit_data,FIT_TYPE* fit_type); void print_fit_data(FITDATA *fit_data,FILE* fp); +double gammaq(double a, double x); #endif diff --git a/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/leastsquares.c b/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/leastsquares.c index df231675e..cf5124d71 100644 --- a/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/leastsquares.c +++ b/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/leastsquares.c @@ -27,19 +27,19 @@ Modifications: -*/ +Modifications: + Angeline G. Burrell - 1 Oct 2021 - Moved gamma functions to the stats library +*/ +#include "sort.h" +#include "stats.h" #include "leastsquares.h" #include "rtypes.h" #include #include #include -#define ITMAX 100 -#define EPS 3.0e-7 -#define FPMIN 1.0e-30 - typedef struct data{ double y; double x; @@ -194,111 +194,6 @@ void find_chi_2(llist_node data,FITDATA *fit_data, FIT_TYPE* fit_type){ } } -/** - * @brief Computes log of gamma function. - * - * Computes the log of a gamma function to prevent overflows. Directely taken from - * NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. Refer to text for descriptions. - */ -double gammln(double xx) -{ - double x,y,tmp,ser; - static double cof[6]={76.18009172947146,-86.50532032941677, - 24.01409824083091,-1.231739572450155, - 0.1208650973866179e-2,-0.5395239384953e-5}; - int j; - y=x=xx; - tmp=x+5.5; - tmp -= (x+0.5)*log(tmp); - ser=1.000000000190015; - for (j=0;j<=5;j++) ser += cof[j]/++y; - return -tmp+log(2.5066282746310005*ser/x); -} - -/** - * @brief Computes the gamma function as a series representation - * - * Computes the gamma function as a series representation. Directly taken from - * NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. Refer to text for more description. - */ -void gamma_series_rep(double *gamser, double a, double x, double *gln) -{ - int n; - double sum,del,ap; - *gln=gammln(a); - if (x <= 0.0) { - if (x < 0.0) /*fprintf(stderr,"error x = %f\n",x);*/ - *gamser=0.0; - return; - } else { - ap=a; - del=sum=1.0/a; - for (n=1;n<=ITMAX;n++) { - ++ap; - del *= x/ap; - sum += del; - if (fabs(del) < fabs(sum)*EPS) { - *gamser=sum*exp(-x+a*log(x)-(*gln)); - return; - } - } - return; - } -} - - -/** - * @brief Computes the gamma function as continued fractions - * - * Computes the gamma function as continued fractions. Directly taken from - * NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. Refer to text for more description. - */ -void gamma_continued_frac(double *gammcf, double a, double x, double *gln) -{ - int i; - double an,b,c,d,del,h; - *gln=gammln(a); - b=x+1.0-a; - c=1.0/FPMIN; - d=1.0/b; - h=d; - for (i=1;i<=ITMAX;i++) { - an = -i*(i-a); - b += 2.0; - d=an*d+b; - if (fabs(d) < FPMIN) d=FPMIN; - c=b+an/c; - if (fabs(c) < FPMIN) c=FPMIN; - d=1.0/d; - del=d*c; - h *= del; - if (fabs(del-1.0) < EPS) break; - } - if (i > ITMAX) - *gammcf=exp(-x+a*log(x)-(*gln))*h; -} - -/** - * @brief Computes the incomplete upper gamma function. - * - * Computes the incomplete upper gamma function using eitherseries representation or continued - * fractions, depending on which will be faster. Directly taken from - * NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING. Refer to text for more description. - * - */ -double gammaq(double a, double x){ - - double gamser = 0.0,gammcf = 0.0,gln = 0.0; - if (x < 0.0 || a <= 0.0) return -1.0; - if (x < (a+1.0)) { - gamma_series_rep(&gamser,a,x,&gln); - return 1.0-gamser; - } else { - gamma_continued_frac(&gammcf,a,x,&gln); - return gammcf; - } -} - /** * @brief Performs a two parameter straight line fit. * diff --git a/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/makefile b/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/makefile index b0427edd9..98c007089 100644 --- a/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/makefile +++ b/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/makefile @@ -1,21 +1,26 @@ # makefile for fitacf 3.0 +# ===================== # +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license # -include $(MAKECFG).$(SYSTEM) - +# Modifications: +# 2021-10-04 Angeline G. Burrell - Modified to use new stats library +include $(MAKECFG).$(SYSTEM) -INCLUDE= -I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/superdarn/fit -I$(IPATH)/superdarn -SRC = determinations.c fitacftoplevel.c fitting.c leastsquares.c llist.c \ - preprocessing.c determinations.h fit_structures.h leastsquares.h \ - preprocessing.h fitacftoplevel.h fitting.h llist.h -OBJS = determinations.o fitacftoplevel.o fitting.o leastsquares.o llist.o \ - preprocessing.o -INC=$(IPATH)/superdarn -DSTPATH=$(LIBPATH) -OUTPUT=fitacf -LINK="3.0" - +INCLUDE = -I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/analysis \ + -I$(IPATH)/superdarn/fit -I$(IPATH)/superdarn +INC = $(IPATH)/superdarn +DSTPATH = $(LIBPATH) +OUTPUT = fitacf +LINK = "3.0" +SRC = determinations.c fitacftoplevel.c fitting.c leastsquares.c \ + llist.c preprocessing.c determinations.h fit_structures.h \ + leastsquares.h preprocessing.h fitacftoplevel.h fitting.h \ + llist.h +OBJS = determinations.o fitacftoplevel.o fitting.o leastsquares.o \ + llist.o preprocessing.o include $(MAKELIB).$(SYSTEM) diff --git a/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/preprocessing.c b/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/preprocessing.c index 777d82636..d2135ae69 100644 --- a/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/preprocessing.c +++ b/codebase/superdarn/src.lib/tk/fitacf_v3.0/src/preprocessing.c @@ -727,7 +727,7 @@ void phase_correction(PHASENODE* phase, double* slope_est, int* total_2pi_correc phase_node->phi += phi_corr * 2 * PI; - *total_2pi_corrections += abs(phi_corr); + *total_2pi_corrections += fabs(phi_corr); } diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/doc/fitmultbsid.doc.xml b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/doc/fitmultbsid.doc.xml new file mode 100644 index 000000000..20d012ff3 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/doc/fitmultbsid.doc.xml @@ -0,0 +1,406 @@ + + +superdarn +fitmultbsid +src.lib/tk/fitmultbsid + + +FitMultBSIDMake +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+struct FitMultBSID *FitMultBSIDMake(); + +

The FitMultBSIDMake function initializes the FitMultBSID data structure.

+
+fitmultbsid.c +
+ + +FitMultBSIDFree +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+void FitMultBSIDFree(struct FitMultBSID *ptr); + +

The FitMultBSIDFree function frees the memory assigned to the FitMultBSID pointer, ptr.

+
+fitmultbsid.c +
+ + +FitMultBSIDReset +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+void FitMultBSIDReset(struct FitMultBSID *ptr); + +

The FitMultBSIDReset function frees the memory assigned to the FitMultBSID pointer, ptr, before initializing the structure for use with new data.

+
+fitmultbsid.c +
+ + + +FitBSIDScanFreeNext +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+void FitBSIDScanFreeNext(struct FitBSIDScan *ptr); + +

The FitBSIDScanFreeNext function frees the memory assigned to the current FitBSIDScan pointer, ptr, and cycles to the next pointer in the scan data structure.

+
+fitmultbsid.c +
+ + +FitBSIDBeamFree +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+void FitBSIDBeamFree(struct FitBSIDBeam *ptr); + +

The FitBSIDBeamFree function frees the memory assigned to the FitBSIDBeam pointer, ptr.

+
+fitmultbsid.c +
+ + +get_bm_by_bmnum +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+int get_bm_by_bmnum(int ibm, struct FitBSIDScan *scan); + +

The get_bm_by_bmnum cycles through the scan, looking for the index that corresponds to the radar beam number, ibm.

+
+fitmultbsid.c +
+ + +WriteFitMultBSIDASCII +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+void WriteFitMultBSIDASCII(FILE *fp, struct FitMultBSID *mult_scan); + +

The WriteFitMultBSIDASCII cycle through the mult_scan data and write the data to the file pointer in an ASCII format.

+
+fitmultbsid.c +
+ + +WriteFitBSIDScanASCII +src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+void WriteFitBSIDScanASCII(FILE *fp, int stid, struct FitBSIDScan *scan); + +

The WriteFitBSIDScanASCII cycle through the beams and range gates in the scan data, writing the data to the file pointer in an ASCII format. If no scan data is provided (NULL), writes the header information.

+
+fitmultbsid.c +
+ + + + CellBSIDFlgs + src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+ + + + int fov; + Radar field of view flag, 1 if front, -1 if rear, 0 if unknown or unset. + + + + int fov_past; + Previous value for fov. + + + + int grpflg; + Flag that indicates a group of nearest-neighbors has been identified (0 if not a part of a group, 1 if part of a group). + + + + int grpnum; + Number of nearest-neighbors in a group. + + + + char grpid[100]; + String ID for this group, facilitating group identification across multiple files. + + + + + +

The struct CellBSIDFlgs structure stores the flags needed for field-of-view identification and re-classification of backscatter type.

+
+
+ + + + CellBSIDLoc + src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+ + + + float vh; + Virtual height in km. + + + + float vh_e; + Virtual height error in km. + + + + char vh_m[5]; + Short character flag indicating of method used to calculate virtual height. Uses 'E' for elevation, 'C' for the Chisham virtual height model, and 'S' for the standard virtual height model. + + + + char region[20]; + Character indicating the ionospheric region. + + + + float hop; + Number of hops for the propagation path. + + + + float dist; + Slant distance in km. + + + + + +

The struct CellBSIDLoc structure stores the location information needed for field-of-view identification and re-classification of backscatter type.

+
+
+ + + + FitBSIDBeam + src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+ + + + int cpid; + Radar programme mode. + + + + int bm; + Radar beam number. + + + + float bmazm; + Beam azimuth in degrees. + + + + double time; + Epoch time of backscatter observation. + + + + int intt.sc; + Integer seconds of backscatter observation. + + + + int intt.us; + Integer micro-seconds of backscatter observation. + + + + int nave; + Number of pulse sequences transmitted. + + + + int frang; + Distance to the first range gate in km. + + + + int rsep; + Range separation in km. + + + + int rxrise; + Receiver rise time in microseconds. + + + + int freq; + Transmission frequency in kHz. + + + + int noise; + Noise from Fit files + + + + int atten; + Attenuation level (unitless) + + + + int channel; + Channel number, used to denote different Tx/Rx channels on Stereo radars, and to denote changes in radar operating parameters between scans, e.g. alternating between 2 frequencies scan-to-scan + + + + int nrang; + Number of range gates in this beam. For each structure below, the range gate index corresponds to the actual range gate. + + + + unsigned char *sct; + Flag that indicates whether there is backscatter data for each range gate (i.e., if sct[4] == 1, the zero-offset range gate 4 has backscatter and if sct[74] == 0, the zero-offset range gate 74 does not have backscatter). + + + + struct RadarCell *rng; + Pointer with RadarCell data for each range gate. + + + + struct RadarCell *med_rng; + Pointer with median values of the RadarCell data for each range gate. + + + + struct FitElv *front_elv; + Pointer with elevation values corresponding to the front field-of-view for each range gate. + + + + struct FitElv *back_elv; + Pointer with elevation values corresponding to the rear field-of-view for each range gate. + + + + struct CellBSIDFlgs *rng_flgs; + Flags that identify the field-of-view and nearest-neighbor groups for each range gate. + + + + struct CellBSIDLoc *front_loc; + Location information for backscatter from the front field-of-view at each range gate. + + + + struct CellBSIDLoc *back_loc; + Location information for backscatter from the rear field-of-view at each range gate. + + + + + +

The struct FitBSIDBeam structure stores the FitACF, field-of-view, and updated backscatter ID information, and the information needed for the field-of-view identification and re-classification of backscatter type for a radar beam.

+
+
+ + + + FitBSIDScan + src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+ + + + double st_time; + Epoch time corresponding to the start of the scan. + + + + double ed_time; + Epoch time corresponding to the end of the scan. + + + + int num_bms; + Number of beams in the scan. + + + + struct FitBSIDBeam *bm; + Pointer with beam information for each beam in this scan. Beam index does not necessarily correspond to the beam number. + + + + struct FitBSIDScan *next_scan; + Pointer to the next scan in this structure. + + + + struct FitBSIDScan *prev_scan; + Pointer to the previous scan in this structure. + + + + + +

The struct FitBSIDScan structure stores the FitACF and additional data needed for Field-of-View identification and updating the backscatter type. Uses a linked list to cycle through the scans loaded for the specified file(s).

+
+
+ + + FitMultBSID + src.lib/tk/fitmultbsid +
superdarn/fitmultbsid.h
+ + + + int stid; + Numerical radar station ID. + + + + int version.major; + Major version number. + + + + int version.minor; + Minor version number. + + + + double st_time; + Epoch time corresponding to the start of the file(s). + + + + double ed_time; + Epoch time corresponding to the end of the file(s). + + + + int num_scans; + Number of loaded scans. + + + + struct FitBSIDScan *scan_ptr; + Pointer to the first scan in this structure. + + + + struct FitBSIDScan *last_scan; + Pointer to the last scan in this structure. + + + + + +

The struct FitMultBSID structure stores the FitACF and additional data needed for Field-of-View identification and updating the backscatter type. Uses a linked list to cycle through the scans loaded for the specified file(s).

+
+
+ + +
diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/include/fitmultbsid.h b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/include/fitmultbsid.h new file mode 100644 index 000000000..242b346b0 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/include/fitmultbsid.h @@ -0,0 +1,154 @@ +/* fitmultbsid.h + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#ifndef _FITMULTBSID_H +#define _FITMULTBSID_H + +/* Ensure the neccessary library headers are included */ +#ifndef _ZLIB_H +#include +#endif + +#ifndef _RTIME_H +#include "rtime.h" +#endif + +#ifndef _RTYPES_H +#include "rtypes.h" +#endif + +#ifndef _RCONVERT_H +#include "rconvert.h" +#endif + +#ifndef _DMAP_H +#include "dmap.h" +#endif + +#ifndef _RPRM_H +#include "rprm.h" +#endif + +#ifndef _FITBLK_H +#include "scandata.h" +#endif + +#ifndef _FITBLK_H +#include "fitblk.h" +#endif + + +struct CellBSIDFlgs +{ + int gflg; + int fov; + int fov_past; + int grpflg; + int grpnum; + char grpid[2]; +}; + +struct CellBSIDLoc +{ + float vh; + float vh_e; + char vh_m[2]; + char region[2]; + float hop; + float dist; +}; + +struct FitBSIDBeam +{ + /* Set the beam constants */ + int cpid; + int bm; + float bmazm; + double time; + struct { + int sc; + int us; + } intt; + + /* Set the beam parameter values */ + int nave; + int frang; + int rsep; + int rxrise; + int freq; + int noise; + int atten; + int channel; + + /* Set the beam range-gate information */ + int nrang; + unsigned char *sct; + struct RadarCell *rng; + struct RadarCell *med_rng; + struct FitElv *front_elv; + struct FitElv *back_elv; + struct CellBSIDFlgs *rng_flgs; + struct CellBSIDLoc *front_loc; + struct CellBSIDLoc *back_loc; +}; + +struct FitBSIDScan +{ + double st_time; + double ed_time; + int num_bms; + struct FitBSIDBeam *bm; + struct FitBSIDScan *next_scan; + struct FitBSIDScan *prev_scan; +}; + +struct FitMultBSID +{ + int stid; + struct + { + int major; + int minor; + } version; + + double st_time; + double ed_time; + int num_scans; + + struct FitBSIDScan *scan_ptr; + struct FitBSIDScan *last_ptr; +}; + +struct FitMultBSID *FitMultBSIDMake(); +void FitMultBSIDFree(struct FitMultBSID *ptr); +int FitMultBSIDReset(struct FitMultBSID *ptr); +void FitBSIDScanFreeNext(struct FitBSIDScan *ptr); +void FitBSIDBeamFree(struct FitBSIDBeam *ptr); +int get_bm_by_bmnum(int ibm, struct FitBSIDScan *scan); + +int FitMultBSIDHeaderDecode(struct DataMap *ptr, struct FitMultBSID *mult_scan); +int FitBSIDScanDecode(FILE *fp, struct FitBSIDScan *scan); +int FitBSIDBeamDecode(FILE *fp, struct FitBSIDBeam *bm); +int ReadFitMultBSIDBin(FILE *fp, struct FitMultBSID *mult_scan); + +void WriteFitMultBSIDASCII(FILE *fp, struct FitMultBSID *mult_scan); +void WriteFitBSIDScanASCII(FILE *fp, int stid, struct FitBSIDScan *scan); +int WriteFitMultBSIDBin(FILE *fp, int grp_flg, int med_flg, + struct FitMultBSID *mult_scan); +int WriteFitBSIDBeamBin(int fid, int grp_flg, int med_flg, + struct FitBSIDBeam bm); +int FitBSIDBeamEncode(int grp_flg, int med_flg, struct DataMap *ptr, + struct FitBSIDBeam bm); + +#endif diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/fitmultbsid.c b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/fitmultbsid.c new file mode 100644 index 000000000..1a2777f74 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/fitmultbsid.c @@ -0,0 +1,139 @@ +/* fitmultbsid.c + =========== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include + +#include "fitmultbsid.h" + + +struct FitMultBSID *FitMultBSIDMake() +{ + struct FitMultBSID *ptr; + + ptr = (struct FitMultBSID *)malloc(sizeof(struct FitMultBSID)); + memset(ptr, 0, sizeof(struct FitMultBSID)); + ptr->num_scans = 0; + ptr->scan_ptr = (struct FitBSIDScan *)(NULL); + ptr->last_ptr = ptr->scan_ptr; + + return ptr; +} + +void FitMultBSIDFree(struct FitMultBSID *ptr) +{ + if(FitMultBSIDReset(ptr) == 0) return; + free(ptr); + return; +} + +int FitMultBSIDReset(struct FitMultBSID *ptr) +{ + int n; + struct FitBSIDScan *scan; + + if(ptr == NULL) return(0); + + scan = ptr->scan_ptr; + for(n = 0; n < ptr->num_scans; n++) + FitBSIDScanFreeNext(scan); + + ptr->num_scans = 0; + ptr->scan_ptr = (struct FitBSIDScan *)(NULL); + ptr->last_ptr = (struct FitBSIDScan *)(NULL); + return(1); +} + +void FitBSIDScanFreeNext(struct FitBSIDScan *ptr) +{ + int ibm; + struct FitBSIDBeam *bm; + + /* Free the current pointer and cycle to the next one */ + bm = ptr->bm; + for(ibm = 0; ibm < ptr->num_bms; ibm++) + FitBSIDBeamFree(&bm[ibm]); + + if(ptr->num_bms > 0) + { + free(ptr->bm); + ptr->num_bms = 0; + } + + ptr = ptr->next_scan; + + return; +} + +void FitBSIDBeamFree(struct FitBSIDBeam *ptr) +{ + free(ptr->rng); + free(ptr->med_rng); + free(ptr->front_elv); + free(ptr->back_elv); + free(ptr->rng_flgs); + free(ptr->front_loc); + free(ptr->back_loc); + return; +} + +/** + * @brief Cycle through scan, returning beam by beam number + * + * @param[in] ibm - Zero-index beam number + * scan - Scan data structure + * + * @param[out] bm - Pointer to the desired beam structure + **/ + +int get_bm_by_bmnum(int ibm, struct FitBSIDScan *scan) +{ + int i; + + struct FitBSIDBeam bm; + + if(ibm < scan->num_bms) + { + /* This scan may be ordered by beam number */ + i = ibm; + bm = scan->bm[i]; + + /* This scan may be ordered by reverse beam order */ + if(bm.bm != ibm) + { + i = scan->num_bms - (ibm + 1); + bm = scan->bm[i]; + } + + if(bm.bm == ibm) return(i); + } + + /* Not a clear relationship between beam index and beam number */ + i = 0; + bm = scan->bm[i]; + + while(bm.bm != ibm && i < scan->num_bms) + bm = scan->bm[++i]; + + if(i >= scan->num_bms) + { + fprintf(stderr, "can't find beam number [%d] in scan with time [%f]\n", + ibm, scan->st_time); + exit(1); + } + + return(i); +} diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/makefile b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/makefile new file mode 100644 index 000000000..8a25cb474 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/makefile @@ -0,0 +1,27 @@ +# Makefile for the FitACF MultBSID library +# ======================================== +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/superdarn -I../include/ +INC = $(IPATH)/superdarn +DSTPATH = $(LIBPATH) +OUTPUT = fitmultbsid + +SRC = fitmultbsid.c \ + read_binary.c \ + write_ascii.c \ + write_binary.c + +OBJS = $(SRC:.c=.o) + +LINK = "1" + +include $(MAKELIB).$(SYSTEM) diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/read_binary.c b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/read_binary.c new file mode 100644 index 000000000..3bf4b2f15 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/read_binary.c @@ -0,0 +1,582 @@ +/* read_binary.c + ============= + Author Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include +#include +#include + +#include "rtypes.h" +#include "rtime.h" +#include "fitmultbsid.h" + +int FitMultBSIDHeaderDecode(struct DataMap *ptr, struct FitMultBSID *mult_scan) +{ + short int stid, isnew; + int i, status; + struct DataMapScalar *sptr; + + /* Determine whether or not this is a new structure */ + isnew = 0 ? (mult_scan->num_scans == 0) : 1; + stid = -1; + + /* Load the data header */ + for(status = 0, i = 0; i < ptr->snum; i++) + { + sptr = ptr->scl[i]; + + if((strcmp(sptr->name, "fitmultbsid.version.major") == 0) + && (sptr->type == DATAINT)) + mult_scan->version.major = *(sptr->data.iptr); + else if((strcmp(sptr->name, "fitmultbsid.version.minor") == 0) + && (sptr->type == DATAINT)) + mult_scan->version.minor = *(sptr->data.iptr); + else if((strcmp(sptr->name, "stid") == 0) && (sptr->type == DATASHORT)) + stid = *(sptr->data.iptr); + else if((strcmp(sptr->name, "num_scans") == 0) && (sptr->type == DATAINT)) + mult_scan->num_scans += *(sptr->data.iptr); + else + { + fprintf(stderr, "unexpected line reached, not header data\n"); + status = -1; + } + } + + /* Ensure there is is a radar station ID and that it doesn't change */ + if(isnew == 1) + { + if(stid == -1) + { + fprintf(stderr, "radar STID missing from file\n"); + exit(1); + } + + mult_scan->stid = stid; + } + else if(mult_scan->stid != stid) + { + fprintf(stderr, "radar change detected (%d != %d), can't load files\n", + mult_scan->stid, stid); + exit(1); + } + + return(status); +} + +int FitBSIDScanDecode(FILE *fp, struct FitBSIDScan *scan) +{ + int i, status, ibm; + + struct DataMap *ptr; + struct DataMapScalar *sptr; + + /* Decode the number of beams in this scan */ + ptr = DataMapFread(fp); + for(status = 0, i = 0; i < ptr->snum; i++) + { + sptr = ptr->scl[i]; + + if((strcmp(sptr->name, "num_bms") == 0) && (sptr->type == DATAINT)) + scan->num_bms = *(sptr->data.iptr); + else + { + fprintf(stderr, "unexpected line reached, not scan header data\n"); + status = -1; + } + } + DataMapFree(ptr); + + /* Initialize the beam data */ + scan->bm = (struct FitBSIDBeam *)malloc(sizeof(struct FitBSIDBeam) + * scan->num_bms); + memset(scan->bm, 0, sizeof(struct FitBSIDBeam)); + + /* Decode the beam data for this scan */ + for(ibm = 0; ibm < scan->num_bms && status >= 0; ibm++) + status = FitBSIDBeamDecode(fp, &scan->bm[ibm]); + + scan->st_time = scan->bm[0].time; + scan->ed_time = scan->bm[scan->num_bms-1].time; + + return(status); +} + +int FitBSIDBeamDecode(FILE *fp, struct FitBSIDBeam *bm) +{ + int i, j, yr=-1, mo=-1, dy=-1, hr=-1, mt=-1, *slist=NULL, *fov=NULL; + + char **vstr=NULL; + + struct DataMap *ptr; + struct DataMapScalar *sptr; + struct DataMapArray *aptr; + + /* Decode the number of beams in this scan */ + ptr = DataMapFread(fp); + for(i = 0; i < ptr->snum; i++) + { + sptr = ptr->scl[i]; + + if((strcmp(sptr->name, "cpid") == 0) && (sptr->type == DATAINT)) + bm->cpid = *(sptr->data.iptr); + else if((strcmp(sptr->name, "bmnum") == 0) && (sptr->type == DATASHORT)) + bm->bm = *(sptr->data.sptr); + else if((strcmp(sptr->name, "bmazm") == 0) && (sptr->type == DATAFLOAT)) + bm->bmazm = *(sptr->data.fptr); + else if((strcmp(sptr->name, "yr") == 0) && (sptr->type == DATAINT)) + yr = *(sptr->data.iptr); + else if((strcmp(sptr->name, "mo") == 0) && (sptr->type == DATAINT)) + mo = *(sptr->data.iptr); + else if((strcmp(sptr->name, "dy") == 0) && (sptr->type == DATAINT)) + dy = *(sptr->data.iptr); + else if((strcmp(sptr->name, "hr") == 0) && (sptr->type == DATAINT)) + hr = *(sptr->data.iptr); + else if((strcmp(sptr->name, "mt") == 0) && (sptr->type == DATAINT)) + mt = *(sptr->data.iptr); + else if((strcmp(sptr->name, "sc") == 0) && (sptr->type == DATAINT)) + bm->intt.sc = *(sptr->data.iptr); + else if((strcmp(sptr->name, "us") == 0) && (sptr->type == DATAINT)) + bm->intt.us = *(sptr->data.iptr); + else if((strcmp(sptr->name, "nave") == 0) && (sptr->type == DATAINT)) + bm->nave = *(sptr->data.iptr); + else if((strcmp(sptr->name, "frang") == 0) && (sptr->type == DATAINT)) + bm->frang = *(sptr->data.iptr); + else if((strcmp(sptr->name, "rsep") == 0) && (sptr->type == DATAINT)) + bm->rsep = *(sptr->data.iptr); + else if((strcmp(sptr->name, "rxrise") == 0) && (sptr->type == DATAINT)) + bm->rxrise = *(sptr->data.iptr); + else if((strcmp(sptr->name, "freq") == 0) && (sptr->type == DATAINT)) + bm->freq = *(sptr->data.iptr); + else if((strcmp(sptr->name, "noise") == 0) && (sptr->type == DATAINT)) + bm->noise = *(sptr->data.iptr); + else if((strcmp(sptr->name, "atten") == 0) && (sptr->type == DATAINT)) + bm->atten = *(sptr->data.iptr); + else if((strcmp(sptr->name, "channel") == 0) && (sptr->type == DATAINT)) + bm->channel = *(sptr->data.iptr); + else if((strcmp(sptr->name, "nrang") == 0) && (sptr->type == DATAINT)) + bm->nrang = *(sptr->data.iptr); + else + { + fprintf(stderr, "unexpected line reached, not beam data\n"); + return(-1); + } + } + + /* Set the time */ + if(yr > -1 && mo > -1 && dy > -1 && hr > -1 && mt > -1) + bm->time = TimeYMDHMSToEpoch(yr, mo, dy, hr, mt, 0.0); + else + { + fprintf(stderr, "unable to read all time variables\n"); + return(-1); + } + + /* Initialize the range gate data */ + bm->sct = (unsigned char *)calloc(bm->nrang, sizeof(unsigned char)); + bm->rng = (struct RadarCell *)calloc(bm->nrang, + sizeof(struct RadarCell)); + bm->med_rng = (struct RadarCell *)calloc(bm->nrang, + sizeof(struct RadarCell)); + bm->rng_flgs = (struct CellBSIDFlgs *)calloc(bm->nrang, + sizeof(struct CellBSIDFlgs)); + bm->front_loc = (struct CellBSIDLoc *)calloc(bm->nrang, + sizeof(struct CellBSIDLoc)); + bm->back_loc = (struct CellBSIDLoc *)calloc(bm->nrang, + sizeof(struct CellBSIDLoc)); + bm->front_elv = (struct FitElv *)calloc(bm->nrang, sizeof(struct FitElv)); + bm->back_elv = (struct FitElv *)calloc(bm->nrang, sizeof(struct FitElv)); + + /* Decode the range gate data for this scan */ + for(i = 0; i < ptr->anum && (slist == NULL || fov == NULL); i++) + { + aptr = ptr->arr[i]; + + if((strcmp(aptr->name, "slist") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + slist = malloc(sizeof(int) * aptr->rng[0]); + if(slist == NULL) break; + for(j = 0; j < aptr->rng[0]; j++) + { + slist[j] = aptr->data.sptr[j]; + bm->sct[slist[j]] = 1; + } + } + else if((strcmp(aptr->name, "fov") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + fov = malloc(sizeof(int) * aptr->rng[0]); + if(fov == NULL) break; + for(j = 0; j < aptr->rng[0]; j++) fov[j] = aptr->data.sptr[j]; + } + } + + if(slist == NULL || fov == NULL) return(-1); + + /* Initialize the group ID name */ + for(j = 0; j < bm->nrang; j++) + { + sprintf(bm->rng_flgs[j].grpid, "U"); + sprintf(bm->front_loc[j].vh_m, "U"); + sprintf(bm->back_loc[j].vh_m, "U"); + sprintf(bm->front_loc[j].region, "U"); + sprintf(bm->back_loc[j].region, "U"); + } + + /* Decode the range gate dependant data for this scan */ + for(i = 0; i < ptr->anum; i++) + { + aptr = ptr->arr[i]; + + if((strcmp(aptr->name, "gsct") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].gsct = aptr->data.sptr[j]; + } + else if((strcmp(aptr->name, "gflg") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng_flgs[slist[j]].gflg = aptr->data.sptr[j]; + } + else if((strcmp(aptr->name, "fov") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng_flgs[slist[j]].fov = aptr->data.sptr[j]; + } + else if((strcmp(aptr->name, "fov_past") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng_flgs[slist[j]].fov_past = aptr->data.sptr[j]; + } + else if((strcmp(aptr->name, "pwr0") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].p_0 = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "pwr0_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].p_0_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "p_l") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].p_l = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "p_l_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].p_l_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "w_l") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].w_l = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "w_l_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].w_l_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "v") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].v = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "v_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].v_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "phi0") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].phi0 = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "phi0_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng[slist[j]].phi0_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "elv") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + bm->rng[slist[j]].elv = aptr->data.fptr[j]; + + if(fov[j] == 1) bm->front_elv[j].normal = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_elv[j].normal = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "elv_low") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) bm->front_elv[j].low = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_elv[j].low = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "elv_high") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) bm->front_elv[j].high = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_elv[j].high = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "vh") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) bm->front_loc[j].vh = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_loc[j].vh = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "vh_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) bm->front_loc[j].vh_e = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_loc[j].vh_e = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "hop") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) bm->front_loc[j].hop = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_loc[j].hop = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "dist") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) bm->front_loc[j].dist = aptr->data.fptr[j]; + else if(fov[j] == -1) bm->back_loc[j].dist = aptr->data.fptr[j]; + } + } + else if((strcmp(aptr->name, "vh_m") == 0) && (aptr->type == DATASTRING) + && (aptr->dim == 1)) + { + vstr = ((char **) aptr->data.vptr); + + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) + memcpy(bm->front_loc[j].vh_m, vstr[j], 2); + else if(fov[j] == -1) + memcpy(bm->back_loc[j].vh_m, vstr[j], 2); + } + } + else if((strcmp(aptr->name, "region") == 0) && (aptr->type == DATASTRING) + && (aptr->dim == 1)) + { + vstr = ((char **) aptr->data.vptr); + + for(j = 0; j < aptr->rng[0]; j++) + { + if(fov[j] == 1) + memcpy(bm->front_loc[j].region, vstr[j], 2); + else if(fov[j] == -1) + memcpy(bm->back_loc[j].region, vstr[j], 2); + } + } + else if((strcmp(aptr->name, "med_gsct") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].gsct = aptr->data.sptr[j]; + } + else if((strcmp(aptr->name, "med_pwr0") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].p_0 = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_pwr0_e") == 0) + && (aptr->type == DATAFLOAT) && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].p_0_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_p_l") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].p_l = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_p_l_e") == 0) + && (aptr->type == DATAFLOAT) && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].p_l_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_w_l") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].w_l = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_w_l_e") == 0) + && (aptr->type == DATAFLOAT) && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].w_l_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_v") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].v = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_v_e") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].v_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_phi0") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].phi0 = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_phi0_e") == 0) + && (aptr->type == DATAFLOAT) && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].phi0_e = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "med_elv") == 0) && (aptr->type == DATAFLOAT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->med_rng[slist[j]].elv = aptr->data.fptr[j]; + } + else if((strcmp(aptr->name, "grpflg") == 0) && (aptr->type == DATASHORT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng_flgs[slist[j]].grpflg = aptr->data.sptr[j]; + } + else if((strcmp(aptr->name, "grpnum") == 0) && (aptr->type == DATAINT) + && (aptr->dim == 1)) + { + for(j = 0; j < aptr->rng[0]; j++) + bm->rng_flgs[slist[j]].grpnum = aptr->data.iptr[j]; + } + else if((strcmp(aptr->name, "grpid") == 0) && (aptr->type == DATASTRING) + && (aptr->dim == 1)) + { + vstr = ((char **) aptr->data.vptr); + for(j = 0; j < aptr->rng[0]; j++) + memcpy(bm->rng_flgs[slist[j]].grpid, vstr[j], 2); + } + } + + /* Free the pointers */ + free(slist); + free(fov); + DataMapFree(ptr); + + return(0); +} + +int ReadFitMultBSIDBin(FILE *fp, struct FitMultBSID *mult_scan) +{ + int status, iscan; + + struct FitBSIDScan *scan, *prev; + struct DataMap *ptr; + + /* Initialize the output structure */ + status = 0; + if(mult_scan == NULL) mult_scan = FitMultBSIDMake(); + + /* Decode the header */ + ptr = DataMapFread(fp); + + /* Cycle through all the scans, decoding the binary data */ + scan = (struct FitBSIDScan *)malloc(sizeof(struct FitBSIDScan)); + scan->next_scan = (struct FitBSIDScan *)(NULL); + iscan = mult_scan->num_scans; + + if(mult_scan->num_scans == 0) + { + mult_scan->scan_ptr = scan; + prev = (struct FitBSIDScan *)(NULL); + } + else + { + prev = mult_scan->last_ptr; + prev->next_scan = scan; + } + scan->prev_scan = prev; + status = FitMultBSIDHeaderDecode(ptr, mult_scan); + DataMapFree(ptr); + + if(status != 0) return(status); + + for(; iscan < mult_scan->num_scans && status >= 0; iscan++) + { + status = FitBSIDScanDecode(fp, scan); + + if(status >= 0) + { + mult_scan->ed_time = scan->ed_time; + if(iscan == 0 && status >= 0) + mult_scan->st_time = scan->st_time; + } + + scan->next_scan = (struct FitBSIDScan *) + malloc(sizeof(struct FitBSIDScan)); + prev = scan; + scan = scan->next_scan; + scan->prev_scan = prev; + prev->next_scan = scan; + } + + /* Close out the linked structure */ + prev->next_scan = (struct FitBSIDScan *)(NULL); + mult_scan->last_ptr = prev; + + /* Check the number of scans and set the start and end time */ + if(iscan != mult_scan->num_scans) status = -1; + + return(status); +} diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/write_ascii.c b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/write_ascii.c new file mode 100644 index 000000000..d4348f955 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/write_ascii.c @@ -0,0 +1,151 @@ +/* write_ascii.c + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include +#include + + +#include "rtypes.h" +#include "rtime.h" +#include "fitmultbsid.h" + +/** + * @brief Cycle through and write multiple scans of radar data + * + * @param[in] fp - open file pointer + * mult_scan - Cyclable scan structure + **/ + +void WriteFitMultBSIDASCII(FILE *fp, struct FitMultBSID *mult_scan) +{ + int iscan; + + struct FitBSIDScan *scan; + + /* Write the header */ + WriteFitBSIDScanASCII(fp, mult_scan->stid, NULL); + + /* Cycle through all the scans */ + scan = mult_scan->scan_ptr; + + for(iscan = 0; iscan < mult_scan->num_scans; iscan++) + { + /* Write all the beams from this scan */ + WriteFitBSIDScanASCII(fp, mult_scan->stid, scan); + + /* Cycle to the next scan */ + scan = scan->next_scan; + } + + return; +} + +/** + * @brief Write a scan of radar data + * + * @param[in] fp - Open file pointer + * stid - Radar Station ID + * scan - BSID scan structure + **/ + +void WriteFitBSIDScanASCII(FILE *fp, int stid, struct FitBSIDScan *scan) +{ + int ibm, irg, yr, mo, dy, hr, mt; + double sc; + + char scan_info[10], bm_info[1000], rng_info[3000]; + + struct FitBSIDBeam bm; + struct RadarCell rng, med_rng; + struct FitElv elv, opp_elv; + struct CellBSIDLoc loc, opp_loc; + struct CellBSIDFlgs rng_flgs; + + /* If there is no scan data, print the header information */ + if(scan == NULL) + { + sprintf(scan_info, "#STID"); + sprintf(bm_info, "DATE TIME INTT_US BMNUM BMAZM CPID NAVE FRANG RSEP RXRISE FREQ NOISE ATTEN CHANNEL NRANG"); + sprintf(rng_info, "RG GFLG NEW_GFLG FOVFLG FOV_PAST GRPFLG GRPNUM GRPID P_0 P_0_ERR V V_ERR W_L W_L_ERR P_L P_L_ERR PHI0 PHI0_ERR ELV ELV_LOW ELV_HIGH VH VH_ERR VH_METHOD REGION HOP DIST MED_P_0 MED_P_0_ERR MED_V MED_V_ERR MED_W_L MED_W_L_ERR MED_P_L MED_P_L_ERR MED_PHI0 MED_PHI0_ERR OPP_ELV OPP_ELV_LOW OPP_ELV_HIGH OPP_VH OPP_VH_ERR OPP_VH_METHOD OPP_REGION OPP_HOP OPP_DIST"); + + fprintf(fp, "%s %s %s\n", scan_info, bm_info, rng_info); + } + else + { + /* Cycle through all the beams in this scan */ + for(ibm = 0; ibm < scan->num_bms; ibm++) + { + /* Write out the desired info that is the same for this scan */ + sprintf(scan_info, "%d", stid); + + /* Write out the desired info that is the same for this beam */ + bm = scan->bm[ibm]; + TimeEpochToYMDHMS(bm.time, &yr, &mo, &dy, &hr, &mt, &sc); + + sprintf(bm_info, + "%04d-%02d-%02d %02d:%02d:%02d %d %d %0.3f %d %d %d %d %d %d %d %d %d %d", + yr, mo, dy, hr, mt, bm.intt.sc, bm.intt.us, bm.bm, + bm.bmazm, bm.cpid, bm.nave, bm.frang, bm.rsep, bm.rxrise, + bm.freq, bm.noise, bm.atten, bm.channel, bm.nrang); + + /* Cycle through all the range gates */ + for(irg = 0; irg < bm.nrang; irg++) + { + /* Write out the range info */ + if(bm.sct[irg] == 1) + { + rng = bm.rng[irg]; + med_rng = bm.med_rng[irg]; + rng_flgs = bm.rng_flgs[irg]; + if(rng_flgs.fov == -1) + { + elv = bm.back_elv[irg]; + loc = bm.back_loc[irg]; + opp_elv = bm.front_elv[irg]; + opp_loc = bm.front_loc[irg]; + } + else + { + elv = bm.front_elv[irg]; + loc = bm.front_loc[irg]; + opp_elv = bm.back_elv[irg]; + opp_loc = bm.back_loc[irg]; + } + + sprintf(rng_info, + "%d %d %d %d %d %d %d %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %s %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %s %s %f %f", + irg, rng.gsct, rng_flgs.gflg, rng_flgs.fov, + rng_flgs.fov_past, rng_flgs.grpflg, rng_flgs.grpnum, + rng_flgs.grpid, rng.p_0, rng.p_0_e, rng.v, rng.v_e, + rng.w_l, rng.w_l_e, rng.p_l, rng.p_l_e, rng.phi0, + rng.phi0_e, elv.normal, elv.low, elv.high, loc.vh, + loc.vh_e, loc.vh_m, loc.region, loc.hop, loc.dist, + med_rng.p_0, med_rng.p_0_e, med_rng.v, med_rng.v_e, + med_rng.w_l, med_rng.w_l_e, med_rng.p_l, + med_rng.p_l_e, med_rng.phi0, med_rng.phi0_e, + opp_elv.normal, opp_elv.low, opp_elv.high, opp_loc.vh, + opp_loc.vh_e, opp_loc.vh_m, opp_loc.region, + opp_loc.hop, opp_loc.dist); + + fprintf(fp, "%s %s %s\n", scan_info, bm_info, rng_info); + } + } + } + } + + return; +} diff --git a/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/write_binary.c b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/write_binary.c new file mode 100644 index 000000000..b5025c00d --- /dev/null +++ b/codebase/superdarn/src.lib/tk/fitmultbsid.1.0/src/write_binary.c @@ -0,0 +1,380 @@ +/* write_binary.c + ============== + Author Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include +#include +#include +#include +#include + +#include "rtypes.h" +#include "rtime.h" +#include "fitmultbsid.h" + +/** + * @brief Encode the beam data into a general data mapping structure + * + * @param[in] grp_flg - boolean flag, 0 to exclude or 1 to include group IDs + * med_flg - boolean flag, 0 to exclude or 1 to include median data + * ptr - pointer to the DataMap binary writing structure + * bm - data-filled FitBSIDBeam structure + * + * @param[out] status - returns zero upon success and -1 upon failure + **/ + +int FitBSIDBeamEncode(int grp_flg, int med_flg, struct DataMap *ptr, + struct FitBSIDBeam bm) +{ + short int has_fov; + int igood, irg, ngood; + + int cpid, bmnum, yr, mo, dy, hr, mt, sc, us; + int nave, frang, rsep, rxrise, freq, noise, atten, channel, nrang; + float bmazm; + double seconds; + + int16 *slist=NULL, *gsct=NULL, *gflg=NULL, *med_gflg=NULL; + int16 *fov=NULL, *fov_past=NULL, *grpflg=NULL, *grpnum=NULL; + float *pwr0=NULL, *pwr0_e=NULL, *v=NULL, *v_e=NULL; + float *p_l=NULL, *p_l_e=NULL, *w_l=NULL, *w_l_e=NULL; + float *phi0=NULL, *phi0_e=NULL, *elv=NULL, *elv_low=NULL, *elv_high=NULL; + float *med_pwr0=NULL, *med_pwr0_e=NULL, *med_v=NULL, *med_v_e=NULL; + float *med_p_l=NULL, *med_p_l_e=NULL, *med_w_l=NULL, *med_w_l_e=NULL; + float *med_phi0=NULL, *med_phi0_e=NULL, *med_elv=NULL; + float *vh=NULL, *vh_e=NULL, *hop=NULL, *dist=NULL; + char *sct=NULL, **grpid=NULL, **vh_m=NULL, **region=NULL; + + struct FitElv bm_elv; + struct CellBSIDLoc bm_loc; + + /* Add the general beam data */ + cpid = bm.cpid; + bmnum = bm.bm; + bmazm = bm.bmazm; + + TimeEpochToYMDHMS(bm.time, &yr, &mo, &dy, &hr, &mt, &seconds); + sc = bm.intt.sc; + us = bm.intt.us; + + TimeEpochToYMDHMS(bm.time, &yr, &mo, &dy, &hr, &mt, &seconds); + DataMapStoreScalar(ptr, "cpid", DATAINT, &cpid); + DataMapStoreScalar(ptr, "bmnum", DATASHORT, &bmnum); + DataMapStoreScalar(ptr, "bmazm", DATAFLOAT, &bmazm); + DataMapStoreScalar(ptr, "yr", DATAINT, &yr); + DataMapStoreScalar(ptr, "mo", DATAINT, &mo); + DataMapStoreScalar(ptr, "dy", DATAINT, &dy); + DataMapStoreScalar(ptr, "hr", DATAINT, &hr); + DataMapStoreScalar(ptr, "mt", DATAINT, &mt); + DataMapStoreScalar(ptr, "sc", DATAINT, &sc); + DataMapStoreScalar(ptr, "us", DATAINT, &us); + + /* Add the beam parameter values */ + nave = bm.nave; + frang = bm.frang; + rsep = bm.rsep; + rxrise = bm.rxrise; + freq = bm.freq; + noise = bm.noise; + atten = bm.atten; + channel = bm.channel; + nrang = bm.nrang; + + DataMapStoreScalar(ptr, "nave", DATAINT, &nave); + DataMapStoreScalar(ptr, "frang", DATAINT, &frang); + DataMapStoreScalar(ptr, "rsep", DATAINT, &rsep); + DataMapStoreScalar(ptr, "rxrise", DATAINT, &rxrise); + DataMapStoreScalar(ptr, "freq", DATAINT, &freq); + DataMapStoreScalar(ptr, "noise", DATAINT, &noise); + DataMapStoreScalar(ptr, "atten", DATAINT, &atten); + DataMapStoreScalar(ptr, "channel", DATAINT, &channel); + DataMapStoreScalar(ptr, "nrang", DATAINT, &nrang); + + /* Get the size of the data arrays (only as long as the actual data) */ + sct = DataMapStoreArray(ptr, "sct", DATACHAR, 1, &nrang, NULL); + + for(ngood = 0, irg = 0; irg < nrang; irg++) + { + sct[irg] = bm.sct[irg]; + if(bm.sct[irg] == 1) ngood++; + } + + /* Initiallize the range gate information */ + slist = DataMapStoreArray(ptr, "slist", DATASHORT, 1, &ngood, NULL); + gsct = DataMapStoreArray(ptr, "gsct", DATASHORT, 1, &ngood, NULL); + gflg = DataMapStoreArray(ptr, "gflg", DATASHORT, 1, &ngood, NULL); + fov = DataMapStoreArray(ptr, "fov", DATASHORT, 1, &ngood, NULL); + fov_past = DataMapStoreArray(ptr, "fov_past", DATASHORT, 1, &ngood, NULL); + pwr0 = DataMapStoreArray(ptr, "pwr0", DATAFLOAT, 1, &ngood, NULL); + pwr0_e = DataMapStoreArray(ptr, "pwr0_e", DATAFLOAT, 1, &ngood, NULL); + p_l = DataMapStoreArray(ptr, "p_l", DATAFLOAT, 1, &ngood, NULL); + p_l_e = DataMapStoreArray(ptr, "p_l_e", DATAFLOAT, 1, &ngood, NULL); + w_l = DataMapStoreArray(ptr, "w_l", DATAFLOAT, 1, &ngood, NULL); + w_l_e = DataMapStoreArray(ptr, "w_l_e", DATAFLOAT, 1, &ngood, NULL); + v = DataMapStoreArray(ptr, "v", DATAFLOAT, 1, &ngood, NULL); + v_e = DataMapStoreArray(ptr, "v_e", DATAFLOAT, 1, &ngood, NULL); + phi0 = DataMapStoreArray(ptr, "phi0", DATAFLOAT, 1, &ngood, NULL); + phi0_e = DataMapStoreArray(ptr, "phi0_e", DATAFLOAT, 1, &ngood, NULL); + elv = DataMapStoreArray(ptr, "elv", DATAFLOAT, 1, &ngood, NULL); + elv_low = DataMapStoreArray(ptr, "elv_low", DATAFLOAT, 1, &ngood, NULL); + elv_high = DataMapStoreArray(ptr, "elv_high", DATAFLOAT, 1, &ngood, NULL); + vh = DataMapStoreArray(ptr, "vh", DATAFLOAT, 1, &ngood, NULL); + vh_e = DataMapStoreArray(ptr, "vh_e", DATAFLOAT, 1, &ngood, NULL); + vh_m = DataMapStoreArray(ptr, "vh_m", DATASTRING, 1, &ngood, NULL); + region = DataMapStoreArray(ptr, "region", DATASTRING, 1, &ngood, NULL); + hop = DataMapStoreArray(ptr, "hop", DATAFLOAT, 1, &ngood, NULL); + dist = DataMapStoreArray(ptr, "dist", DATAFLOAT, 1, &ngood, NULL); + + /* Initialize the optional structures */ + if(med_flg == 1) + { + med_gflg = DataMapStoreArray(ptr, "med_gsct", DATASHORT, 1, &ngood, NULL); + med_pwr0 = DataMapStoreArray(ptr, "med_pwr0", DATAFLOAT, 1, &ngood, NULL); + med_pwr0_e = DataMapStoreArray(ptr, "med_pwr0_e", DATAFLOAT, 1, &ngood, + NULL); + med_p_l = DataMapStoreArray(ptr, "med_p_l", DATAFLOAT, 1, &ngood, NULL); + med_p_l_e = DataMapStoreArray(ptr, "med_p_l_e", DATAFLOAT, 1, &ngood, + NULL); + med_w_l = DataMapStoreArray(ptr, "med_p_l", DATAFLOAT, 1, &ngood, NULL); + med_w_l_e = DataMapStoreArray(ptr, "med_p_l_e", DATAFLOAT, 1, &ngood, + NULL); + med_v = DataMapStoreArray(ptr, "med_v", DATAFLOAT, 1, &ngood, NULL); + med_v_e = DataMapStoreArray(ptr, "med_v_e", DATAFLOAT, 1, &ngood, NULL); + med_phi0 = DataMapStoreArray(ptr, "med_phi0", DATAFLOAT, 1, &ngood, + NULL); + med_phi0_e = DataMapStoreArray(ptr, "med_phi0_e", DATAFLOAT, 1, &ngood, + NULL); + med_elv = DataMapStoreArray(ptr, "med_elv", DATAFLOAT, 1, &ngood, NULL); + } + + if(grp_flg == 1) + { + grpflg = DataMapStoreArray(ptr, "grpflg", DATASHORT, 1, &ngood, NULL); + grpnum = DataMapStoreArray(ptr, "grpnum", DATAINT, 1, &ngood, NULL); + grpid = DataMapStoreArray(ptr, "grpid", DATASTRING, 1, &ngood, NULL); + } + + /* Set the data for all of the initialized arrays */ + for(igood = 0, irg = 0; irg < nrang; irg++) + { + if(bm.sct[irg] == 1) + { + /* Check that the number of good points has not exceeded the */ + /* expected maximum. */ + if(igood >= ngood) return(-1); + + /* Assign the basic data at this range gate */ + slist[igood] = irg; + gsct[igood] = bm.rng[irg].gsct; + gflg[igood] = bm.rng_flgs[irg].gflg; + fov[igood] = bm.rng_flgs[irg].fov; + fov_past[igood] = bm.rng_flgs[irg].fov_past; + pwr0[igood] = bm.rng[irg].p_0; + pwr0_e[igood] = bm.rng[irg].p_0_e; + p_l[igood] = bm.rng[irg].p_l; + p_l_e[igood] = bm.rng[irg].p_l_e; + w_l[igood] = bm.rng[irg].w_l; + w_l_e[igood] = bm.rng[irg].w_l_e; + v[igood] = bm.rng[irg].v; + v_e[igood] = bm.rng[irg].v_e; + phi0[igood] = bm.rng[irg].phi0; + phi0_e[igood] = bm.rng[irg].phi0_e; + + /* Assign the FoV dependent information at this range gate */ + if(fov[igood] == 1) + { + bm_elv = bm.front_elv[irg]; + bm_loc = bm.front_loc[irg]; + has_fov = 1; + } + else if(fov[igood] == -1) + { + bm_elv = bm.back_elv[irg]; + bm_loc = bm.back_loc[irg]; + has_fov = 1; + } + else has_fov = 0; + + vh_m[igood] = malloc(sizeof(char) * 2); + region[igood] = malloc(sizeof(char) * 2); + + if(has_fov == 1) + { + elv[igood] = bm_elv.normal; + elv_low[igood] = bm_elv.low; + elv_high[igood] = bm_elv.high; + vh[igood] = bm_loc.vh; + vh_e[igood] = bm_loc.vh_e; + hop[igood] = bm_loc.hop; + dist[igood] = bm_loc.dist; + + memcpy(vh_m[igood], bm_loc.vh_m, 2); + memcpy(region[igood], bm_loc.region, 2); + } + else + { + elv[igood] = 0.0; + elv_low[igood] = 0.0; + elv_high[igood] = 0.0; + vh[igood] = 0.0; + vh_e[igood] = 0.0; + hop[igood] = 0.0; + dist[igood] = 0.0; + + memcpy(vh_m[igood], "U", 2); + memcpy(region[igood], "U", 2); + } + + /* Assign the median data, if desired */ + if(med_flg == 1) + { + med_gflg[igood] = bm.med_rng[irg].gsct; + med_pwr0[igood] = bm.med_rng[irg].p_0; + med_pwr0_e[igood] = bm.med_rng[irg].p_0_e; + med_p_l[igood] = bm.med_rng[irg].p_l; + med_p_l_e[igood] = bm.med_rng[irg].p_l_e; + med_w_l[igood] = bm.med_rng[irg].w_l; + med_w_l_e[igood] = bm.med_rng[irg].w_l_e; + med_v[igood] = bm.med_rng[irg].v; + med_v_e[igood] = bm.med_rng[irg].v_e; + med_phi0[igood] = bm.med_rng[irg].phi0; + med_phi0_e[igood] = bm.med_rng[irg].phi0_e; + med_elv[igood] = bm.med_rng[irg].elv; + } + + /* Assign the group data, if desired */ + if(grp_flg == 1) + { + grpflg[igood] = bm.rng_flgs[irg].grpflg; + grpnum[igood] = bm.rng_flgs[irg].grpnum; + grpid[igood] = malloc(sizeof(char) * 2); + memcpy(grpid[igood], bm.rng_flgs[irg].grpid, 2); + } + + /* Cycle to the next good index */ + igood++; + } + } + + return(0); +} + +/** + * @brief Encode and write the beam data from the fit fov/bsid structure + * + * @param[in] fid - integer file ID + * grp_flg - boolean flag, 0 to exclude or 1 to include group IDs + * med_flg - boolean flag, 0 to exclude or 1 to include median data + * bm - FitBSIDBeam structure object + * + * @param[out] status - returns -1 upon failure and the size of data written + * upon success + **/ + +int WriteFitBSIDBeamBin(int fid, int grp_flg, int med_flg, + struct FitBSIDBeam bm) +{ + int status; + struct DataMap *ptr = NULL; + + /* Initialize the binary data mapping structure */ + if((ptr = DataMapMake()) == NULL) return(-1); + + /* Encode the data mapping structure with the beam data */ + status = FitBSIDBeamEncode(grp_flg, med_flg, ptr, bm); + + /* Write the encoded beam data */ + if(status >= 0) + { + if(fid != -1) status = DataMapWrite(fid, ptr); + else status = DataMapSize(ptr); + } + + /* Free the header data pointer */ + DataMapFree(ptr); + + return status; +} + +/** + * @brief Write a binary file containing the Fit, FoV, and BSID data + * + * @param[in] fp - open file pointer + * grp_flg - boolean flag, 0 to exclude or 1 to include group IDs + * med_flg - boolean flag, 0 to exclude or 1 to include median data + * mult_scan - FitMultBSID structure with data to write + * + * @param[out] status - A positive value on success and -1 if there is an error + **/ + +int WriteFitMultBSIDBin(FILE *fp, int grp_flg, int med_flg, + struct FitMultBSID *mult_scan) +{ + int fid, status, iscan, ibm; + + struct FitBSIDScan *scan; + struct DataMap *ptr = NULL; + + /* Get the file ID and set (or return) the status */ + if((fid = fileno(fp)) == -1) return(-1); + + status = 0; + + /* Initialize the binary data mapping structure */ + if((ptr = DataMapMake()) == NULL) return(-1); + + /* Add the header info */ + DataMapAddScalar(ptr, "fitmultbsid.version.major", DATAINT, + &mult_scan->version.major); + DataMapAddScalar(ptr, "fitmultbsid.version.minor", DATAINT, + &mult_scan->version.minor); + DataMapAddScalar(ptr, "stid", DATASHORT, &mult_scan->stid); + DataMapAddScalar(ptr, "num_scans", DATAINT, &mult_scan->num_scans); + + /* Write the header data */ + if(status >= 0) + { + if(fid != -1) status = DataMapWrite(fid, ptr); + else status = DataMapSize(ptr); + } + DataMapFree(ptr); + + /* Cycle through all the scans, encoding the binary data */ + scan = mult_scan->scan_ptr; + + for(iscan = 0; iscan < mult_scan->num_scans && status >= 0; iscan++) + { + /* Record the number of beams in this scan */ + if((ptr = DataMapMake()) == NULL) return(-1); + DataMapAddScalar(ptr, "num_bms", DATAINT, &scan->num_bms); + + /* Write the scan-header data */ + if(status >= 0) + { + if(fid != -1) status = DataMapWrite(fid, ptr); + else status = DataMapSize(ptr); + } + DataMapFree(ptr); + + /* Cycle through all the beams in this scan */ + for(ibm = 0; ibm < scan->num_bms && status >= 0; ibm++) + status = WriteFitBSIDBeamBin(fid, grp_flg, med_flg, scan->bm[ibm]); + + scan = scan->next_scan; + } + + return(status); +} + + diff --git a/codebase/superdarn/src.lib/tk/freqband.1.0/include/freqband.h b/codebase/superdarn/src.lib/tk/freqband.1.0/include/freqband.h index ee8e06de8..b402899c6 100644 --- a/codebase/superdarn/src.lib/tk/freqband.1.0/include/freqband.h +++ b/codebase/superdarn/src.lib/tk/freqband.1.0/include/freqband.h @@ -5,8 +5,8 @@ This file is part of the Radar Software Toolkit (RST). - Disclaimer: This code is licensed under GPL v3.0 please LICENSE to see the - full license + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license Modifications: diff --git a/codebase/superdarn/src.lib/tk/freqband.1.0/src/get_fit_tfreq_band.c b/codebase/superdarn/src.lib/tk/freqband.1.0/src/get_fit_tfreq_band.c index dbb1ecae4..5f579e2c3 100644 --- a/codebase/superdarn/src.lib/tk/freqband.1.0/src/get_fit_tfreq_band.c +++ b/codebase/superdarn/src.lib/tk/freqband.1.0/src/get_fit_tfreq_band.c @@ -5,8 +5,8 @@ This file is part of the Radar Software Toolkit (RST). - Disclaimer: This code is licensed under GPL v3.0 please LICENSE to see the - full license + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license Modifications: diff --git a/codebase/superdarn/src.lib/tk/grid.1.24/src/makefile b/codebase/superdarn/src.lib/tk/grid.1.24/src/makefile index fcc3df507..4a59da006 100644 --- a/codebase/superdarn/src.lib/tk/grid.1.24/src/makefile +++ b/codebase/superdarn/src.lib/tk/grid.1.24/src/makefile @@ -14,9 +14,7 @@ INC=$(IPATH)/superdarn LINK="1" DSTPATH=$(LIBPATH) OUTPUT = grd - - diff --git a/codebase/superdarn/src.lib/tk/oldfit.1.25/src/fitscan.c b/codebase/superdarn/src.lib/tk/oldfit.1.25/src/fitscan.c index 886be617f..2cfac59f9 100644 --- a/codebase/superdarn/src.lib/tk/oldfit.1.25/src/fitscan.c +++ b/codebase/superdarn/src.lib/tk/oldfit.1.25/src/fitscan.c @@ -126,10 +126,19 @@ int OldFitReadRadarScan(struct OldFitFp *fp,int *state, bm->rng[r].p_l=fit->rng[r].p_l; bm->rng[r].w_l=fit->rng[r].w_l; bm->rng[r].v_e=fit->rng[r].v_err; - if (fit->xrng !=NULL) bm->rng[r].phi0=fit->xrng[r].phi0; - else bm->rng[r].phi0=0; if (fit->elv !=NULL) bm->rng[r].elv=fit->elv[r].normal; else bm->rng[r].elv=0; + + if(fit->xrng != NULL) + { + bm->rng[r].phi0=fit->xrng[r].phi0; + bm->rng[r].phi0_e=fit->xrng[r].phi0_err; + } + else + { + bm->rng[r].phi0=0; + bm->rng[r].phi0_e=0; + } } ptr->ed_time=TimeYMDHMSToEpoch(prm->time.yr,prm->time.mo, diff --git a/codebase/superdarn/src.lib/tk/propagation.1.0/doc/propagation.doc.xml b/codebase/superdarn/src.lib/tk/propagation.1.0/doc/propagation.doc.xml new file mode 100644 index 000000000..47dd3a1da --- /dev/null +++ b/codebase/superdarn/src.lib/tk/propagation.1.0/doc/propagation.doc.xml @@ -0,0 +1,39 @@ + + +superdarn +propagation +src.lib/tk/propagation + + + +TestPropagation +src.lib/tk/propagation +
superdarn/propagation.h
+int TestPropagation(float hop, float vheight, float slant_dist, float D_hmin, float D_hmax, float E_hmax); +

The TestPropagation function takes the hop, virtual height, slant distance, and regional limits and tests the propagation path for realism.

+
+Returns 1 for a good path and 0 for a bad path. +
+ + + +AdjustPropagation +src.lib/tk/propagation +
superdarn/propagation.h
+void AdjustPropagation(int lobe, float radius, float D_hmin, float D_hmax, float E_hmax, float F_hmax, float max_hop, int bmnum, int tfreq, struct RadarSite *site, double psi_obs, float *hop, float *vheight, double *elv, float *slant_dist); +

The AdjustPropagation function tests the propagation path for backscatter with the specified characteristics against the provided ionospheric regional limits for realism and adjusts the hop if needed.

+
+
+ + + +SetRegion +src.lib/tk/propagation +
superdarn/propagation.h
+void SetRegion(float hop, float D_hmin, float D_hmax, float E_hmax, float F_hmax, float vheight, char *region); +

The SetRegion function determines the ionospheric region using a set of provided virtual height limits, the hop, and the virtual height for a backscatter observation.

+
+
+ + +
diff --git a/codebase/superdarn/src.lib/tk/propagation.1.0/include/propagation.h b/codebase/superdarn/src.lib/tk/propagation.1.0/include/propagation.h new file mode 100644 index 000000000..31cecc214 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/propagation.1.0/include/propagation.h @@ -0,0 +1,33 @@ +/* propagation.h + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + + +#ifndef _PROPAGATION_H +#define _PROPAGATION_H + +int TestPropagation(float hop, float vheight, float slant_dist, float D_hmin, + float D_hmax, float E_hmax); + + +void AdjustPropagation(int lobe, float radius, float D_hmin, float D_hmax, + float E_hmax, float F_hmax, float max_hop, + int bmnum, int tfreq, struct RadarSite *site, + double psi_obs, float *hop, float *vheight, + double *elv, float *slant_dist); + + +void SetRegion(float hop, float D_hmin, float D_hmax, float E_hmax, + float F_hmax, float vheight, char *region); + +#endif diff --git a/codebase/superdarn/src.lib/tk/propagation.1.0/src/makefile b/codebase/superdarn/src.lib/tk/propagation.1.0/src/makefile new file mode 100644 index 000000000..721bac763 --- /dev/null +++ b/codebase/superdarn/src.lib/tk/propagation.1.0/src/makefile @@ -0,0 +1,25 @@ +# Makefile for propagation library +# ================================ +# Author: Angeline G. Burrell, NRL (2021) +# This is a U.S. government work and not under copyright protection in the U.S. +# +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: + +include $(MAKECFG).$(SYSTEM) + +INCLUDE = -I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/superdarn -I../include/ +INC = $(IPATH)/superdarn +DSTPATH = $(LIBPATH) +OUTPUT = propagation + +SRC = propagation.c \ + region.c + +OBJS = $(SRC:.c=.o) + +LINK = "1" + +include $(MAKELIB).$(SYSTEM) diff --git a/codebase/superdarn/src.lib/tk/propagation.1.0/src/propagation.c b/codebase/superdarn/src.lib/tk/propagation.1.0/src/propagation.c new file mode 100644 index 000000000..fa8af403a --- /dev/null +++ b/codebase/superdarn/src.lib/tk/propagation.1.0/src/propagation.c @@ -0,0 +1,123 @@ +/* propagation.c + ============= + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include + +#include "radar.h" +#include "rmath.h" +#include "rpos.h" +#include "elevation.h" +#include "propagation.h" + +/** + * @brief Test the propagation path for realism using the basic properties of HF + * radars. + * + * @param[in] hop - number of hops (0.5, 1.0, 1.5, etc) + * vheight - virtual height in km + * slant_dist - slant distance in km + * D_hmin - minimum height for D region in km + * D_hmax - maximum height for D region in km + * E_hmax - maximum height for E region in km + * + * @param[out] good_path - 1 if good, 0 if bad + **/ + +int TestPropagation(float hop, float vheight, float slant_dist, float D_hmin, + float D_hmax, float E_hmax) +{ + int good_path=1; + + if(vheight < D_hmin) good_path = 0; + else if(vheight <= D_hmax) + { + if(hop > 0.5 || slant_dist > 500.0) good_path = 0; + } + else if(vheight <= E_hmax) + { + if(hop < 1.5 && slant_dist > 900.0) good_path = 0; + } + + return(good_path); +} + + +/** + * @brief Test the propagation path for realism using the basic properties of HF + * radars. + * + * @param[in] lobe - Field-of-view specifier: 1=front, -1=back + * radius - Earth radius in km + * D_hmin - Minimum height for D region in km + * D_hmax - Maximum height for D region in km + * E_hmax - Maximum height for E region in km + * F_hmax - Maximum height for F region in km + * max_hop - Maximum number of realistic hops allowed + * bmnum - Beam number (zero offset) + * tfreq - Transmission frequency in kHz + * site - Radar hardware site structure + * psi_obs - Phase lag value + * hop - Number of hops (0.5, 1.0, 1.5, etc) + * vheight - Virtual height in km + * elv - Elevation angle in degrees + * slant_dist - Slant distance of entire path in km + **/ + +void AdjustPropagation(int lobe, float radius, float D_hmin, float D_hmax, + float E_hmax, float F_hmax, float max_hop, + int bmnum, int tfreq, struct RadarSite *site, + double psi_obs, float *hop, float *vheight, + double *elv, float *slant_dist) +{ + int good_hop; + + float new_hop; + + /* If the virtual height is realistic, assign the current propagation path. */ + new_hop = *hop; + good_hop = TestPropagation(*hop, *vheight, *slant_dist, D_hmin, D_hmax, + E_hmax); + + /* While the virtual height is above the maximum height of the refractable */ + /* F-region, adjust the propagation path */ + while(*vheight > F_hmax && new_hop <= max_hop && good_hop == 1) + { + /* Add a hop and recalculate the slant distance and virtual height */ + new_hop += 1.0; + *vheight = calc_elv_vheight(*slant_dist, new_hop, radius, *elv); + good_hop = TestPropagation(new_hop, *vheight, *slant_dist, D_hmin, D_hmax, + E_hmax); + } + + /* Evaluate the status of the current propagation path */ + if(new_hop <= max_hop && good_hop == 1) + { + /* This is a realistic propagation path. The original Python */ + /* algorithm from Burrell et al. (2015) would assign the */ + /* ionospheric region here as well. */ + *hop = new_hop; + *slant_dist = *slant_dist / (2.0 * new_hop); + } + else + { + /* This is an unrealistic propagation path, return unrealistic values */ + *hop = 0.0; + *slant_dist = 0.0; + *elv = -1.0; + *vheight = 0.0; + } + + return; +} diff --git a/codebase/superdarn/src.lib/tk/propagation.1.0/src/region.c b/codebase/superdarn/src.lib/tk/propagation.1.0/src/region.c new file mode 100644 index 000000000..749efe5fd --- /dev/null +++ b/codebase/superdarn/src.lib/tk/propagation.1.0/src/region.c @@ -0,0 +1,53 @@ +/* region.c + ======== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include + +/** + * @brief determine the ionospheric region + * + * @param[in] hop - number of hops (e.g., 0.5, 1.0, 1.5, etc.) + * D_hmin - minimum height for D region in km + * D_hmax - maximum height for D region in km + * E_hmax - maximum height for E region in km + * F_hmax - maximum height for E region in km + * vheight - virtual height in km + * + * @param[out] region - "D", "E", "F", or "U" (unknown) + * + * @notes Each region has a maximum number of hops: + * D - 0.5 + * E - 1.5 + * F - Specified outside of this routine + * Mixed propagation paths are not identified here (yet) + **/ + +void SetRegion(float hop, float D_hmin, float D_hmax, float E_hmax, + float F_hmax, float vheight, char *region) +{ + + if(vheight < D_hmin || vheight > F_hmax) sprintf(region, "U"); + else if(vheight <= D_hmax) + { + if(hop > 0.5) sprintf(region, "U"); + else sprintf(region, "D"); + } + else if(vheight <= E_hmax) + { + if(hop > 1.5) sprintf(region, "U"); + else sprintf(region, "E"); + } + else sprintf(region, "F"); + return; +} diff --git a/codebase/superdarn/src.lib/tk/radar.1.22/doc/radar.doc.xml b/codebase/superdarn/src.lib/tk/radar.1.22/doc/radar.doc.xml index 19a1d757e..1f7d55b69 100644 --- a/codebase/superdarn/src.lib/tk/radar.1.22/doc/radar.doc.xml +++ b/codebase/superdarn/src.lib/tk/radar.1.22/doc/radar.doc.xml @@ -200,6 +200,15 @@ On error, a NULL pointer is returned. +load_radar_site +src.lib/tk/radar +
superdarn/radar.h
+struct RadarSite *load_radar_site(int yr, int mo, int dy, int hr, int mt, int sc, int stid); +

The load_radar_site function initalizes the radar hardware network, and returns the hardware data for the specified time and radar station.

+
+Returns a pointer to the radar hardware information for the desired time. On error loading the site data for a specific time, a NULL pointer is returned. +On error loading the network or the radar site hardware data, the function with exit with -1. + Radar diff --git a/codebase/superdarn/src.lib/tk/radar.1.22/include/radar.h b/codebase/superdarn/src.lib/tk/radar.1.22/include/radar.h index 345bd96b3..da80a2dfa 100644 --- a/codebase/superdarn/src.lib/tk/radar.1.22/include/radar.h +++ b/codebase/superdarn/src.lib/tk/radar.1.22/include/radar.h @@ -23,6 +23,7 @@ along with this program. If not, see . Modifications: E.G.Thomas 2021-08: added support for new hdw file fields E.G.Thomas 2022-03: added support for tdiff calibration files + 2021-10-05 - Angeline G. Burrell (NRL) - Added load_radar_site routine. */ @@ -103,5 +104,7 @@ int RadarLoadTdiff(char *tdiffpath,struct RadarNetwork *ptr); struct RadarSite *RadarGetSite(struct RadarNetwork *ptr, int yr,int mo,int dy,int hr,int mt,int sc, int stid); +struct RadarSite *load_radar_site(int yr, int mo, int dy, int hr, int mt, + int sc, int stid); #endif diff --git a/codebase/superdarn/src.lib/tk/radar.1.22/include/rprm.h b/codebase/superdarn/src.lib/tk/radar.1.22/include/rprm.h index 72252fcf9..b18097728 100644 --- a/codebase/superdarn/src.lib/tk/radar.1.22/include/rprm.h +++ b/codebase/superdarn/src.lib/tk/radar.1.22/include/rprm.h @@ -106,6 +106,7 @@ struct RadarParm { struct RadarParm *RadarParmMake(); void RadarParmFree(struct RadarParm *ptr); +void RadarParmReset(struct RadarParm *ptr); int RadarParmSetOriginTime(struct RadarParm *ptr,char *str); diff --git a/codebase/superdarn/src.lib/tk/radar.1.22/src/radar.c b/codebase/superdarn/src.lib/tk/radar.1.22/src/radar.c index 1761e92f1..d9202de04 100644 --- a/codebase/superdarn/src.lib/tk/radar.1.22/src/radar.c +++ b/codebase/superdarn/src.lib/tk/radar.1.22/src/radar.c @@ -22,6 +22,8 @@ along with this program. If not, see . Modifications: E.G.Thomas 2021-08: added support for new hdw file fields E.G.Thomas 2022-03: added support for tdiff calibration files + 2021-10-05 - Angeline G. Burrell (NRL) - Added load_radar_site routine. + */ @@ -191,8 +193,10 @@ int RadarLoadHardware(char *hdwpath,struct RadarNetwork *ptr) { double recrise; int maxatten,maxrange,maxbeam; int status; + if (ptr==NULL) return -1; if (hdwpath==NULL) return -1; + for (n=0;nrnum;n++) { sprintf(fname,"%s/%s",hdwpath,ptr->radar[n].hdwfname); fp=fopen(fname,"r"); @@ -459,3 +463,78 @@ struct RadarNetwork *RadarLoad(FILE *fp) { ptr->rnum=num; return ptr; } + +/** + * @brief Load in radar parameter data for a specified time and radar ID + * + * @param[in] yr - integer year + * mo - integer month + * dy - integer day of month + * hr - integer hour of day + * mt - integer minute of hour + * sc - integer second of minute + * stid - integer station identification + * + * @param[out] Returns a RadarSite structure pointer. + **/ + +struct RadarSite *load_radar_site(int yr, int mo, int dy, int hr, int mt, + int sc, int stid) +{ + char *envstr; + + FILE *fp; + + struct RadarNetwork *network; + struct Radar *radar; + + /* Make sure the SD_RADAR environment variable is set */ + envstr = getenv("SD_RADAR"); + if(envstr==NULL) + { + fprintf(stderr, "Environment variable 'SD_RADAR' must be defined.\n"); + exit(-1); + } + + /* Open the radar information file */ + fp = fopen(envstr, "r"); + if(fp == NULL) + { + fprintf(stderr, "Could not locate radar information file.\n"); + exit(-1); + } + + /* Load the radar network information */ + network = RadarLoad(fp); + fclose(fp); + if(network == NULL) + { + fprintf(stderr,"Failed to read radar information.\n"); + exit(-1); + } + + /* Make sure the SD_HDWPATH environment variable is set */ + envstr = getenv("SD_HDWPATH"); + if(envstr == NULL) + { + fprintf(stderr, "Environment variable 'SD_HDWPATH' must be defined.\n"); + exit(-1); + } + + /* Load the hardware information for the radar network */ + RadarLoadHardware(envstr, network); + + /* Load the appropriate radar hardware information for the day + and time of the radar scan (only done once) */ + radar = RadarGetRadar(network, stid); + + if(radar == NULL) + { + fprintf(stderr,"Failed to get radar information for stid %d.\n", stid); + exit(-1); + } + + /* Get the radar site */ + return RadarYMDHMSGetSite(radar, yr, mo, dy, hr, mt, sc); + +} diff --git a/codebase/superdarn/src.lib/tk/radar.1.22/src/rprm.c b/codebase/superdarn/src.lib/tk/radar.1.22/src/rprm.c index d30e0cb17..bb85f26e1 100644 --- a/codebase/superdarn/src.lib/tk/radar.1.22/src/rprm.c +++ b/codebase/superdarn/src.lib/tk/radar.1.22/src/rprm.c @@ -50,6 +50,29 @@ struct RadarParm *RadarParmMake() { return ptr; } +void RadarParmReset(struct RadarParm *ptr) +{ + if (ptr==NULL) ptr = RadarParmMake(); + else + { + if (ptr->origin.time != NULL) free(ptr->origin.time); + if (ptr->origin.command != NULL) free(ptr->origin.command); + if (ptr->pulse != NULL) free(ptr->pulse); + if (ptr->lag[0] != NULL) free(ptr->lag[0]); + if (ptr->lag[1] != NULL) free(ptr->lag[1]); + if (ptr->combf != NULL) free(ptr->combf); + + memset(ptr, 0, sizeof(struct RadarParm)); + ptr->origin.time = NULL; + ptr->origin.command = NULL; + ptr->pulse = NULL; + ptr->lag[0] = NULL; + ptr->lag[1] = NULL; + ptr->combf = NULL; + } + return; +} + void RadarParmFree(struct RadarParm *ptr) { if (ptr==NULL) return; if (ptr->origin.time !=NULL) free(ptr->origin.time); @@ -59,6 +82,7 @@ void RadarParmFree(struct RadarParm *ptr) { if (ptr->lag[1] !=NULL) free(ptr->lag[1]); if (ptr->combf !=NULL) free(ptr->combf); free(ptr); + return; } int RadarParmSetOriginTime(struct RadarParm *ptr,char *str) { @@ -172,28 +196,16 @@ int RadarParmSetLag(struct RadarParm *ptr,int mplgs,int16 *lag) { -int RadarParmDecode(struct DataMap *ptr,struct RadarParm *prm) { +int RadarParmDecode(struct DataMap *ptr, struct RadarParm *prm) { - int n,c; + int c; struct DataMapScalar *s; struct DataMapArray *a; if (ptr==NULL) return -1; if (prm==NULL) return -2; - if (prm->origin.time !=NULL) free(prm->origin.time); - if (prm->origin.command !=NULL) free(prm->origin.command); - if (prm->pulse !=NULL) free(prm->pulse); - for (n=0;n<2;n++) if (prm->lag[n] !=NULL) free(prm->lag[n]); - if (prm->combf !=NULL) free(prm->combf); - - memset(prm,0,sizeof(struct RadarParm)); - prm->origin.time=NULL; - prm->origin.command=NULL; - prm->pulse=NULL; - prm->lag[0]=NULL; - prm->lag[1]=NULL; - prm->combf=NULL; + RadarParmReset(prm); for (c=0;csnum;c++) { s=ptr->scl[c]; diff --git a/codebase/superdarn/src.lib/tk/rpos.1.7/include/rpos.h b/codebase/superdarn/src.lib/tk/rpos.1.7/include/rpos.h index 140a1549a..11e583f6f 100644 --- a/codebase/superdarn/src.lib/tk/rpos.1.7/include/rpos.h +++ b/codebase/superdarn/src.lib/tk/rpos.1.7/include/rpos.h @@ -20,6 +20,8 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . Modifications: +2021-09-27 Angeline G. Burrell: Added new routines that support make_fov. + */ #ifndef _RPOS_H @@ -37,6 +39,11 @@ double slant_range(int frang,int rsep, double rxris,double range_edge, int rang_gate); +double slant_range_no_edge(int frang, int rsep, double rxris, int irg); + +double calc_elv_vheight(double slant_dist, double hop, double radius, + double elv); + void RPosGeo(int center,int bcrd,int rcrd, struct RadarSite *pos, int lagfr,int smsep,int rxrise,double height, diff --git a/codebase/superdarn/src.lib/tk/rpos.1.7/src/cnvtcoord.c b/codebase/superdarn/src.lib/tk/rpos.1.7/src/cnvtcoord.c index b4c856ce9..f09b64140 100644 --- a/codebase/superdarn/src.lib/tk/rpos.1.7/src/cnvtcoord.c +++ b/codebase/superdarn/src.lib/tk/rpos.1.7/src/cnvtcoord.c @@ -23,6 +23,9 @@ along with this program. If not, see . Comments: E.G.Thomas (2016) 2020-03-11 Marina Schmidt removed earth's radius defined constant E.G.Thomas 2021-08: added support for new hdw file fields + 2021-09-27 Angeline G. Burrell: Added a slant range routine that doesn't + require specifying a range_edge value. + */ #include @@ -58,6 +61,33 @@ double slant_range(int frang, int rsep, } +/** + * @brief Calculates the slant range to a range gate without using range_edge. + * + * @param[in] frang - distance to first range gate in km + * rsep - range gate size in km + * rxris - receiver rise time in microseconds + * irg - zero offset range gate index + * + * @param[out] sdist - slant distance in km + **/ +double slant_range_no_edge(int frang, int rsep, double rxris, int irg) +{ + + int lagfr, smsep; + double sdist; + + /* Calculate the lag to first range gate in microseconds */ + lagfr = frang * 20 / 3; + + /* Calculate the sample separation in microseconds */ + smsep = rsep * 20 / 3; + + /* Return the calculated slant range distance [km] */ + sdist = C * 5.0e-10 * (lagfr - rxris + irg * smsep); + + return sdist; +} /** * Converts from geodetic coordinates (gdlat,gdlon) to geocentric spherical diff --git a/codebase/superdarn/src.lib/tk/rpos.1.7/src/elvheight.c b/codebase/superdarn/src.lib/tk/rpos.1.7/src/elvheight.c new file mode 100644 index 000000000..47417e67a --- /dev/null +++ b/codebase/superdarn/src.lib/tk/rpos.1.7/src/elvheight.c @@ -0,0 +1,45 @@ +/* elvheight.c + =========== + Author: Angeline G. Burrell - NRL - 2021 + This is a U.S. government work and not under copyright protection in the U.S. + + This file is part of the Radar Software Toolkit (RST). + + Disclaimer: RST is licensed under GPL v3.0. Please visit + to see the full license + + Modifications: + +*/ + +#include +#include + +#include "rmath.h" + +/** + * @brief Calculate the virtual height using hop number and elevation angle + * + * @param[in] slant_dist - slant distance in km + * hop - number of hops (0.5, 1.0, 1.5, etc) + * radius - radius of the Earth in km + * elv - elevation angle in degrees + * + * @param[out] vheight - virtual height above the surface of the Earth in km + */ + +double calc_elv_vheight(double slant_dist, double hop, double radius, + double elv) +{ + double vheight; + + /* Adjust the slant distance to find the length up to the ionosphere * + * This assumes the propagation path can be evenly segmented, which * + * is mildly not correct, but very much not correct in some cases. */ + slant_dist /= (2.0 * hop); + + vheight = sqrt(slant_dist * slant_dist + radius * radius + + 2.0 * slant_dist * radius * sin(elv * PI / 180.0)) - radius; + + return(vheight); +} diff --git a/codebase/superdarn/src.lib/tk/rpos.1.7/src/makefile b/codebase/superdarn/src.lib/tk/rpos.1.7/src/makefile index 66069edaa..4a6449678 100644 --- a/codebase/superdarn/src.lib/tk/rpos.1.7/src/makefile +++ b/codebase/superdarn/src.lib/tk/rpos.1.7/src/makefile @@ -2,14 +2,35 @@ # ========================== # by R.J.Barnes # +# Disclaimer: RST is licensed under GPL v3.0. Please visit +# to see the full license +# +# Modifications: +# 2021-09-27 Angeline G. Burrell: Added a routine to calculate virtual height +# using elevation angles. + include $(MAKECFG).$(SYSTEM) +INCLUDE=-I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/analysis \ + -I$(IPATH)/superdarn + +SRC = cnvtcoord.c \ + calcvector.c \ + invmag.c \ + geodtgc.h \ + rpos_v2.c \ + elvheight.c + +OBJS = cnvtcoord.o \ + calcvector.o \ + invmag.o \ + rpos_v2.o \ + elvheight.o -INCLUDE=-I$(IPATH)/base -I$(IPATH)/general -I$(IPATH)/analysis -I$(IPATH)/superdarn -SRC = cnvtcoord.c calcvector.c invmag.c geodtgc.h rpos_v2.c -OBJS = cnvtcoord.o calcvector.o invmag.o rpos_v2.o INC=$(IPATH)/superdarn + DSTPATH=$(LIBPATH) + OUTPUT = rpos LINK="1" diff --git a/codebase/superdarn/src.lib/tk/scan.1.7/include/scandata.h b/codebase/superdarn/src.lib/tk/scan.1.7/include/scandata.h index ffb5ae785..99ec027fe 100644 --- a/codebase/superdarn/src.lib/tk/scan.1.7/include/scandata.h +++ b/codebase/superdarn/src.lib/tk/scan.1.7/include/scandata.h @@ -4,26 +4,24 @@ */ /* - Copyright (c) 2012 The Johns Hopkins University/Applied Physics Laboratory - -This file is part of the Radar Software Toolkit (RST). - -RST is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. + LICENSE AND DISCLAIMER -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Modifications: -2021-09-21 Angeline G. Burrell: added `exclude_outofscan` routine to header. + Copyright (c) 2012 The Johns Hopkins University/Applied Physics Laboratory + This file is part of the Radar Software Toolkit (RST). + RST is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + RST is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with RST. If not, see . + Modifications: + 2021-09-21 Angeline G. Burrell: added `exclude_outofscan` routine to header. + AGB Jul 2021 - Added phase lag error to the RadarCell structure */ #ifndef _SCANDATA_H #define _SCANDATA_H @@ -39,6 +37,7 @@ struct RadarCell { double p_l; double p_l_e; double phi0; + double phi0_e; double elv; }; diff --git a/codebase/superdarn/src.lib/tk/scan.1.7/src/makefile b/codebase/superdarn/src.lib/tk/scan.1.7/src/makefile index 09a452158..81073d917 100644 --- a/codebase/superdarn/src.lib/tk/scan.1.7/src/makefile +++ b/codebase/superdarn/src.lib/tk/scan.1.7/src/makefile @@ -13,23 +13,4 @@ LINK="1" DSTPATH=$(LIBPATH) OUTPUT = rscan - - - - - - - - - - - - - - - - - - - include $(MAKELIB).$(SYSTEM) diff --git a/codebase/superdarn/src.lib/tk/scan.1.7/src/radarscan.c b/codebase/superdarn/src.lib/tk/scan.1.7/src/radarscan.c index f6a60dd8f..00b8b7331 100644 --- a/codebase/superdarn/src.lib/tk/scan.1.7/src/radarscan.c +++ b/codebase/superdarn/src.lib/tk/scan.1.7/src/radarscan.c @@ -42,7 +42,7 @@ struct RadarScan *RadarScanMake() { ptr=malloc(sizeof(struct RadarScan)); if (ptr==NULL) return NULL; memset(ptr,0,sizeof(struct RadarScan)); - ptr->bm=NULL; + ptr->bm = (struct RadarBeam *)(NULL); return ptr; } @@ -50,6 +50,7 @@ void RadarScanFree(struct RadarScan *ptr) { if (ptr==NULL) return; RadarScanReset(ptr); free(ptr); + return; } int RadarScanReset(struct RadarScan *ptr) { @@ -100,7 +101,7 @@ int RadarScanResetBeam(struct RadarScan *ptr,int bmnum,int *bmptr) { } } else { free(tmp); - ptr->bm=NULL; + ptr->bm = (struct RadarBeam *)(NULL); } ptr->num=num; return 0; diff --git a/docs/dev/fitmultbsid_struct_c.md b/docs/dev/fitmultbsid_struct_c.md new file mode 100644 index 000000000..055819eb4 --- /dev/null +++ b/docs/dev/fitmultbsid_struct_c.md @@ -0,0 +1,169 @@ + + +# Structure in C for the Fitted ACF data with additional flags + +## Summary + +A description of the data structure in the C language used to store the Fitted +ACF Data with additional flags that denote the origin Field of View (FoV), +backscatter region, and nearest-neighbour groups. + +## Description + +The FitACF algorithm is used to derive doppler velocities, spectral widths and +powers from the raw ACF data. Improved information about the origin and scatter +type may be obtained by running additional algorithms. This data structure is +intended to work with any additional level of processing that improves the +fitted backscatter processing. Listed below is the C data structures used to +store the fitted ACF and additional necessary data +struct FitMultBSID, struct FitBSIDScan, +struct FitBSIDBeam, struct CellBSIDLoc, and +struct CellBSIDFlgs. All these structures are defined in the +header superdarn/fitmultbsid.h. Additional structures contained +within struct FitBSIDBeam are found in +superdarn/fitblk.h and superdarn/scandata.h. + +### `struct FitMultBSID` + +This structure organizes the data in a linked list heirarchically by scan, beam, +and range gate. + +``` +struct FitMultBSID +{ + int stid; /* Radar station ID */ + struct + { + int major; /* major version */ + int minor; /* minor version */ + } version; + + double st_time; /* Starting time of data */ + double ed_time; /* Ending time of data */ + int num_scans; /* Total number of scans */ + + struct FitBSIDScan *scan_ptr; /* Pointer to the first scan */ + struct FitBSIDScan *last_ptr; /* Pointer to the last scan */ +}; +``` + +### `struct FitBSIDScan` + +This structure organizes the data for a single scan that contains data for each +beam indexed in chronological order and then numerically by range gate. It may +also be linked to the previous and subsequent scans. + +``` +struct FitBSIDScan +{ + double st_time; /* Starting time of scan data */ + double ed_time; /* Ending time of scan data */ + int num_bms; /* Total number of beams in this scan */ + struct FitBSIDBeam *bm; /* Pointer of `num_bms` beam data */ + struct FitBSIDScan *next_scan; /* Pointer to the next scan */ + struct FitBSIDScan *prev_scan; /* Pointer to the previous scan */ +}; +``` + +### `struct FitBSIDBeam` + +This structure organizes the data for a single beam, with range gate data +stored in the zero-indexed pointer that corresponds to each data's range gate. + +``` +struct FitBSIDBeam +{ + /* Set the beam constants */ + int cpid; /* Radar program ID */ + int bm; /* Beam number */ + float bmazm; /* Beam azimuth in degrees */ + double time; /* Epoch time (does not include seconds or microseconds */ + struct { + int sc; /* Seconds */ + int us; /* Microseconds */ + } intt; + + /* Set the beam parameter values */ + int nave; /* Number of pulse sequences transmitted */ + int frang; /* Lag to the first range gate in km */ + int rsep; /* Range gate seperation in km */ + int rxrise; /* Receiver rise time in microseconds */ + int freq; /* Transmission frequency in kHz */ + int noise; /* Noise level */ + int atten; /* Beam attenuation level */ + int channel; /* Channel number */ + + /* Set the beam range-gate information */ + int nrang; /* Number of range gates at this beam */ + unsigned char *sct; /* Flag denoting presence or absence of scatter */ + struct RadarCell *rng; /* Fitted ACF data for each range gate */ + struct RadarCell *med_rng; /* Median smoothed data for each range gate */ + struct FitElv *front_elv; /* Elevation angles, assuming front FoV */ + struct FitElv *back_elv; /* Elevation angles, assuming rear FoV */ + struct CellBSIDFlgs *rng_flgs; /* Additional flag data for each range gate */ + struct CellBSIDLoc *front_loc; /* Location data, assuming front FoV */ + struct CellBSIDLoc *back_loc; /* Location data, assuming rear FoV */ +}; +``` + +### `struct CellBSIDLoc` + +This structure contains location data, assuming an origin FoV. + +``` +struct CellBSIDLoc +{ + float vh; /* Virtual height in km */ + float vh_e; /* Virtual height error in km */ + char vh_m[2]; /* Virtual height calculation method: E (elv), S (standard), or C (Chisham) */ + char region[2]; /* Ionospheric region: U (unset), D, E, or F */ + float hop; /* Number of hops in the propagation path */ + float dist; /* Slant distance to the 1/2 hop location in km */ +}; +``` + +### `struct CellBSIDFlgs` + +This structure contains flag data, assuming an origin FoV. + +``` +struct CellBSIDFlgs +{ + int fov; /* FoV flag values: 1 front Fov, 0 unknown FoV, -1 rear FoV */ + int fov_past; /* Past FoV flag values */ + int grpflg; /* Group flag: 0 if not a member, 1 if a member */ + int grpnum; /* Group number */ + char grpid[2]; /* Group ID string (U if unset) */ +}; +``` + +## References + +- The algorithms for which these structures were designed were published in: + +1. Burrell, A. G., Milan, S. E., Perry, G. W., Yeoman, T. K., and Lester, M. + (2015), Automatically determining the origin direction and propagation mode + of high-frequency radar backscatter, Radio Sci., 50, 1225– 1245, + [doi:10.1002/2015RS005808](https://agupubs.onlinelibrary.wiley.com/doi/full/10.1002/2015RS005808). +2. Burrell, A. G., Perry, G. W., Yeoman, T. K., Milan, S. E., & Stoneback, R. + (2018). Solar influences on the return direction of high-frequency radar + backscatter. Radio Science, 53, 577– 597. + [doi:10.1002/2017RS006512](https://agupubs.onlinelibrary.wiley.com/doi/10.1002/2017RS006512) +3. Ribeiro, A. J., Ruohoniemi, J. M., Baker, J., Clausen, L. B. N., de Larquier, + S., & Greenwald, R. A. (2011). A new approach for identifying ionospheric + backscatter in midlatitude SuperDARN HF radar observations. Radio Science, + 46, RS4011. [doi:10.1029/2011RS004676](https://doi.org/10.1029/2011RS004676) +4. J Ribeiro, Kevin Sterne, Sebastien de Larquier, Ashton Reimer, Matt Wessel, + Muhammad Rafiq (Maimaitirebike Maimaiti), Jef Spaleta, Angeline Burrell, + Bharat Kunduri, Xueling Shi, Christer van der Meeren, Pål Ellingsen, + Ray Greenwald, Nathaniel Frissell, Anurag Sharma, & Phil Erickson. (2020). + vtsuperdarn/davitpy: Final release of davitpy (v0.9). Zenodo. + [doi:10.5281/zenodo.3824466](https://doi.org/10.5281/zenodo.3824466) + +## History + +- 2021/11/23 Initial Revision. + diff --git a/docs/dev/gotchas.md b/docs/dev/gotchas.md new file mode 100644 index 000000000..ac0e19d00 --- /dev/null +++ b/docs/dev/gotchas.md @@ -0,0 +1,18 @@ + + +# Development Gotchas + +The RST codebase has a long legacy, and it can be difficult to begin expanding +or maintaining. Commonly enountered issues are recored here to help new +developers. + +1. The library order in RST tool makefiles is important. Incorrect order may + cause compilation failure on some operating systems and memory leaks or + segmentation faults on other systems. This can be difficult to debug if your + system does not cause a compilation failure. +2. The validity of SuperDARN binary files may be tested simply using the + `dmapdump` function. It prints the contents of any SuperDARN binary file to + standard out in plain text. diff --git a/docs/index.md b/docs/index.md index 37dd0a078..e21699b8c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,13 +4,17 @@ author: Marina Schmidt, SuperDARN Canada --> # Radar Software Toolkit (RST) -RST is an open source software package (licensed under GPL v3.0) that allows researchers to analyze, model, and quickly visualize the SuperDARN project data. +RST is an open source software package (licensed under GPL v3.0) that allows +researchers to analyze, model, and quickly visualize the SuperDARN project data. ## RST source code The RST is released as a zip archive on [Zenodo](https://doi.org/10.5281/zenodo.801458) with a citable doi. -The software is maintained by the SuperDARN Data Analysis Working Group (DAWG) on [GitHub](https://github.com/SuperDARN/rst). Bug reports, comments and suggestions can be provided by submitting an [issue](https://github.com/SuperDARN/rst/issues) on Github. +The software is maintained by the SuperDARN Data Analysis Working Group (DAWG) +on [GitHub](https://github.com/SuperDARN/rst). Bug reports, comments and +suggestions can be provided by submitting an +[issue](https://github.com/SuperDARN/rst/issues) on Github. ## Table of Contents - Installation @@ -28,12 +32,12 @@ The software is maintained by the SuperDARN Data Analysis Working Group (DAWG) o * [FITACF to GRID](user_guide/make_grid.md) * [GRID to MAP](user_guide/map_grid.md) - Plotting Data - * [Range-time Plots](user_guide/time_plot.md) - * [Field of View Plots](user_guide/fov_plot.md) - * [Field Plots](user_guide/field_plot.md) - * [Grid Plots](user_guide/grid_plot.md) - * [Convection Plots](user_guide/map_plot.md) - * [Customizing Colors](user_guide/colors.md) + * [Range-time Plots](user_guide/time_plot.md) + * [Field of View Plots](user_guide/fov_plot.md) + * [Field Plots](user_guide/field_plot.md) + * [Grid Plots](user_guide/grid_plot.md) + * [Convection Plots](user_guide/map_plot.md) + * [Customizing Colors](user_guide/colors.md) - SuperDARN Data Formats * [cFit Format](references/general/cfit.md) * [Dmap Data](references/general/dmap_data.md) @@ -59,19 +63,21 @@ The software is maintained by the SuperDARN Data Analysis Working Group (DAWG) o * [Testing Code](dev/testing.md) * [Code Reviews](dev/code_reviews.md) * [Releasing Code](dev/releases.md) + * [Gotchas](dev/gotchas.md) - Data Structures in C - * [cFit](dev/cfit_struct_c.md) - * [FitACF](dev/fitacf_struct_c.md) - * [Grid](dev/grid_struct_c.md) - * [IQDat](dev/iqdat_struct_c.md) - * [Map (cnvmap)](dev/cnvmap_struct_c.md) - * [Radar Parameter Block](dev/radar_parameter_c.md) - * [RawACF](dev/rawacf_struct_c.md) + * [FitMultBSID](dev/fitmultbsid_struct_c.md) + * [cFit](dev/cfit_struct_c.md) + * [FitACF](dev/fitacf_struct_c.md) + * [Grid](dev/grid_struct_c.md) + * [IQDat](dev/iqdat_struct_c.md) + * [Map (cnvmap)](dev/cnvmap_struct_c.md) + * [Radar Parameter Block](dev/radar_parameter_c.md) + * [RawACF](dev/rawacf_struct_c.md) - Data Structures in IDL - * [FitACF](dev/fitacf_struct_idl.md) - * [Grid](dev/grid_struct_idl.md) - * [IQDat](dev/iqdat_struct_idl.md) - * [Map (cnvmap)](dev/cnvmap_struct_idl.md) - * [Radar Parameter Block](dev/radar_parameter_idl.md) - * [RawACF](dev/rawacf_struct_idl.md) + * [FitACF](dev/fitacf_struct_idl.md) + * [Grid](dev/grid_struct_idl.md) + * [IQDat](dev/iqdat_struct_idl.md) + * [Map (cnvmap)](dev/cnvmap_struct_idl.md) + * [Radar Parameter Block](dev/radar_parameter_idl.md) + * [RawACF](dev/rawacf_struct_idl.md)