cangyeone's picture
Publish audited synthetic reproducibility data and independent revision evidence
2b6ccf8 verified
Raw History Blame Contribute Delete
229 kB
/*
* Copyright (C) 1999-2021 Anthony Lomax <anthony@alomax.net, http://www.alomax.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 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 Lesser Public License for more details.
* You should have received a copy of the GNU Lesser Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* GridLib.c
grid library functions
*/
/*-----------------------------------------------------------------------
Anthony Lomax
Anthony Lomax Scientific Software
Mouans-Sartoux, France
e-mail: anthony@alomax.net web: http://www.alomax.net
-------------------------------------------------------------------------*/
/*
history:
ver 01 22SEP1997 AJL Original version
.........1.........2.........3.........4.........5.........6.........7.........8
*/
#include "GridLib.h"
// define globals
int nll_mode;
PhaseIdent PhaseID[MAX_NUM_PHASE_ID];
int NumPhaseID;
char fn_control[MAXLINE]; /* control file name */
FILE *fp_control; /* control file pointer */
char fn_output[MAXLINE]; /* output file name */
/* miscellaneous */
int RandomNumSeed;
int NumFilesOpen;
int NumGridBufFilesOpen, NumGridHdrFilesOpen;
int NumAllocations;
/* algorithm constants */
int prog_mode_3d;
int prog_mode_2dto3d;
int GeometryMode;
/* 3D grid description */
int grid_type; /* grid type (VELOCITY, SLOWNESS, SLOW2, etc) */
GridDesc grid_in;
/* source */
int NumSources;
SourceDesc Source[MAX_NUM_SOURCES];
/* stations */
//int NumStations;
StationDesc Station[MAX_NUM_SOURCES];
/* arrivals */
int PhaseFormat;
int MAX_NUM_STATIONS;
int MAX_NUM_ARRIVALS;
int NumArrivals;
ArrivalDesc* Arrival;
/* hypocenter */
HypoDesc Hypocenter;
char map_trans_type[NUM_PROJ_MAX][MAXLINE]; /* name of projection */
int map_itype[NUM_PROJ_MAX]; /* int id of projection */
char MapProjStr[NUM_PROJ_MAX][2 * MAXLINE]; /* string description of proj params */
char map_ref_ellipsoid[NUM_PROJ_MAX][MAXLINE]; /* name of reference ellipsoid */
/* general map parameters */
double map_orig_lat[NUM_PROJ_MAX], map_orig_long[NUM_PROJ_MAX], map_rot[NUM_PROJ_MAX], map_scale_factor[NUM_PROJ_MAX];
long map_false_easting[NUM_PROJ_MAX];
double map_cosang[NUM_PROJ_MAX], map_sinang[NUM_PROJ_MAX]; /* rotation */
/* LAMBERT projection parameters */
double map_lambert_1st_std_paral[NUM_PROJ_MAX], map_lambert_2nd_std_paral[NUM_PROJ_MAX];
/* SDC Short Distance Coversion projection parameters */
double map_sdc_xltkm[NUM_PROJ_MAX], map_sdc_xlnkm[NUM_PROJ_MAX];
/* constants */
double cPI;
double cRPD;
double c111;
/* include file */
char fn_include[FILENAME_MAX];
FILE* fp_include;
FILE* fp_input_save;
/* take-off angle */
TakeOffAngles AnglesNULL;
/* quality to error mapping (hypo71, etc) */
double Quality2Error[MAX_NUM_QUALITY_LEVELS];
int NumQuality2ErrorLevels;
// int ModelCoordsMode; // 20200608 AJL - bug fix (e-mail 07/06/2020 03:11 陈俊磊)
int ModelCoordsMode;
char ExpandWildCards_pattern[FILENAME_MAX];
// private functions
int _WriteLocation(FILE *fpio, HypoDesc* phypo, ArrivalDesc* parrivals,
int narrivals, char* filename,
int iWriteArrivals, int iWriteEndLoc, int iWriteMinimal,
GridDesc* pgrid, int n_proj, int io_arrival_mode);
/** function to set constants */
void SetConstants(void) {
MAX_NUM_STATIONS = X_MAX_NUM_STATIONS;
MAX_NUM_ARRIVALS = X_MAX_NUM_ARRIVALS;
// AEH/AJL 20080709
// if ((Arrival = (ArrivalDesc *) malloc(MAX_NUM_ARRIVALS * sizeof(ArrivalDesc))) == NULL) {
if ((Arrival = (ArrivalDesc *) calloc(MAX_NUM_ARRIVALS, sizeof (ArrivalDesc))) == NULL) {
nll_puterr("ERROR: re-allocating Arrival array.");
exit(EXIT_ERROR_MEMORY);
}
strcpy(package_name, PACKAGE);
strcpy(prog_ver, PVER);
strcpy(prog_date, PDATE);
strcpy(prog_copyright, PCOPYRIGHT);
message_flag = 0;
// 20171122 AJL cPI = 4. * atan(1.); /* PI */
cPI = M_PI; /* PI */
cRPD = cPI / 180.; /* radians per degree */
// 20171122 AJL - changed km/deg scaling to be based on sphere with radius 6371, average Earth radius.
//c111 = 10000.0 / 90.0; /* kilometers per degree */
c111 = DEG2KM;
fp_include = NULL; /* set include file ptr */
/* bookkeeping */
NumFilesOpen = 0;
NumGridBufFilesOpen = 0;
NumGridHdrFilesOpen = 0;
NumAllocations = 0;
/* program variables */
NumQuality2ErrorLevels = 0;
PhaseFormat = FORMAT_PHASE_1;
/* set null angles indicator */
AnglesNULL = SetTakeOffAngles(400.0, 200.0, 0);
/* set null elliposid */
/*Ellipsoid3D Ell3NULL = {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0};
EllipsoidNULL = Ell3NULL;
Ellipse2D Ell2NULL = {-1.0, -1.0, -1.0};
EllipseNULL = Ell2NULL;
*/
}
/** function to read control params ***/
int get_control(char* line1) {
int istat;
istat = sscanf(line1, "%d %d", &message_flag, &RandomNumSeed);
if (istat == 1)
RandomNumSeed = 837465;
/* display program information */
DispProgInfo();
sprintf(MsgStr, "CONTROL: MessageFlag: %d RandomNumSeed: %d", message_flag, RandomNumSeed);
nll_putmsg(3, MsgStr);
if (checkRangeInt("CONTROL", "MessageFlag", message_flag, 1, -1, 0, 0) != 0)
return (-1);
if (istat != 1 && istat != 2)
return (-1);
return (0);
}
/** function to read output file name ***/
int get_outfile(char* line1) {
int istat;
istat = sscanf(line1, "%s", fn_output);
sprintf(MsgStr, "OUTPUT FILES: %s.*", fn_output);
nll_putmsg(3, MsgStr);
if (istat != 1)
return (-1);
return (0);
}
/** function to read include file name and reset input to include file ***/
int GetIncludeFile(char* line1, FILE **fp_io) {
/* read include file name */
sscanf(line1, "%s", fn_include);
sprintf(MsgStr, "Reading from INCLUDE FILE: %s", fn_include);
nll_putmsg(3, MsgStr);
/* open include file */
if ((fp_include = fopen(fn_include, "r")) == NULL) {
nll_puterr2("ERROR: opening INCLUDE file", fn_include);
return (-1);
}
NumFilesOpen++;
/* swap file pointers */
fp_input_save = *fp_io;
*fp_io = fp_include;
return (0);
}
/** function to reset input from include file to inlput file ***/
void SwapBackIncludeFP(FILE **fp_io) {
/* swap file pointers */
*fp_io = fp_input_save;
// AJL - 20080709 (valgrind)
//fp_include = NULL;
if (fp_include != NULL) {
fclose(fp_include);
NumFilesOpen--;
fp_include = NULL;
}
sprintf(MsgStr, "Returning from INCLUDE FILE: %s.*", fn_include);
nll_putmsg(3, MsgStr);
}
/** function to read source params from input line */
int GetNextSource(char* in_line) {
int istat;
SourceDesc *srce_in = NULL;
/* check number of sources */
if (NumSources >= MAX_NUM_SOURCES) {
nll_puterr2("ERROR: to many sources, ignoring source", srce_in->label);
return (0);
}
srce_in = Source + NumSources;
istat = GetSource(in_line, srce_in, NumSources);
if (istat < 0)
return (istat);
// check if duplicate
if (FindSource(srce_in->label) != NULL) {
if (message_flag >= 2) {
sprintf(MsgStr, "WARNING: duplicated source, ignoring source: %s", srce_in->label);
nll_putmsg(2, MsgStr);
return (istat);
}
}
NumSources++;
return (istat);
}
/** function to read source params fom input line */
int GetSource(char* in_line, SourceDesc *srce_in, int num_sources) {
int istat, ierr;
char chr1, chr2, coord_type[MAXLINE];
double val1, val1a, val1b, val2, val2a, val2b, val3, val4;
double sign;
char label[ARRIVAL_LABEL_LEN];
/* initialize some source fields */
srce_in->is_coord_xyz = 0;
srce_in->is_coord_latlon = 0;
srce_in->otime = 0.0;
/* read coordinate type */
istat = sscanf(in_line, "%*s %s", coord_type);
/* read coordinate type and coordinates */
if (strncmp(coord_type, "XYZ", 3) == 0) {
istat = sscanf(in_line, "%s %s %lf %lf %lf %lf",
label,
coord_type, &val1, &val2, &val3, &val4);
strncpy(srce_in->label, label, ARRIVAL_LABEL_LEN);
srce_in->x = val1;
srce_in->y = val2;
srce_in->z = val3 - val4;
srce_in->is_coord_xyz = 1;
if (message_flag >= 5) {
sprintf(MsgStr,
"SOURCE: %3d Name: %s Loc: type: %s X(east) %lg Y(north) %lg Z(pos DOWN) %lg",
num_sources, srce_in->label,
coord_type, srce_in->x, srce_in->y, srce_in->z);
nll_putmsg(5, MsgStr);
}
if (istat != 6)
return (-1);
} else if (strcmp(coord_type, "LATLON") == 0) {
istat = sscanf(in_line, "%s %s %lf %lf %lf %lf", label,
coord_type, &val1, &val2, &val3, &val4);
strncpy(srce_in->label, label, ARRIVAL_LABEL_LEN);
srce_in->dlat = val1;
srce_in->dlong = val2;
srce_in->depth = val3 - val4;
srce_in->is_coord_latlon = 1;
ierr = 0;
if (checkRangeDouble("SRCE",
"Lat", srce_in->dlat, 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("SRCE",
"Long", srce_in->dlong, 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (message_flag >= 5) {
sprintf(MsgStr,
"SOURCE: %d Name: %s Loc: type: %s Lat %lg Long %lg Depth %lg",
num_sources, srce_in->label,
coord_type, srce_in->dlat, srce_in->dlong,
srce_in->depth);
nll_putmsg(5, MsgStr);
}
if (ierr < 0 || istat != 6)
return (-1);
} else if (strcmp(coord_type, "LATLONDM") == 0) {
istat = sscanf(in_line,
"%s %s %lf %lf %c %lf %lf %c %lf %lf",
label, coord_type, &val1, &val1a, &chr1,
&val2, &val2a, &chr2, &val3, &val4);
strncpy(srce_in->label, label, ARRIVAL_LABEL_LEN);
if ((toupper(chr1) != 'N' && toupper(chr1) != 'S')
|| (toupper(chr2) != 'E' && toupper(chr2) != 'W'))
return (-1);
sign = toupper(chr1) == 'N' ? 1.0 : -1.0;
srce_in->dlat = sign * (val1 + val1a / 60.0);
sign = toupper(chr2) == 'E' ? 1.0 : -1.0;
srce_in->dlong = sign * (val2 + val2a / 60.0);
srce_in->depth = val3 - val4;
srce_in->is_coord_latlon = 1;
ierr = 0;
if (checkRangeDouble("SRCE",
"Lat", srce_in->dlat, 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("SRCE",
"Long", srce_in->dlong, 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (message_flag >= 5) {
sprintf(MsgStr,
"SOURCE: %d Name: %s Loc: type: %s Lat %lg Long %lg Depth %lg",
num_sources, srce_in->label,
coord_type, srce_in->dlat, srce_in->dlong,
srce_in->depth);
nll_putmsg(5, MsgStr);
}
if (ierr < 0 || istat != 10)
return (-1);
} else if (strcmp(coord_type, "LATLONDS") == 0) {
istat = sscanf(in_line,
"%s %s %lf %lf %lf %c %lf %lf %lf %c %lf %lf",
label, coord_type,
&val1, &val1a, &val1b, &chr1,
&val2, &val2a, &val2b, &chr2, &val3, &val4);
strncpy(srce_in->label, label, ARRIVAL_LABEL_LEN);
if ((toupper(chr1) != 'N' && toupper(chr1) != 'S')
|| (toupper(chr2) != 'E' && toupper(chr2) != 'W'))
return (-1);
sign = toupper(chr1) == 'N' ? 1.0 : -1.0;
srce_in->dlat = sign * (val1 + (val1a + val1b / 60.0) / 60.0);
sign = toupper(chr2) == 'E' ? 1.0 : -1.0;
srce_in->dlong = sign * (val2 + (val2a + val2b / 60.0) / 60.0);
srce_in->depth = val3 - val4;
srce_in->is_coord_latlon = 1;
ierr = 0;
if (checkRangeDouble("SRCE",
"Lat", srce_in->dlat, 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("SRCE",
"Long", srce_in->dlong, 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (message_flag >= 5) {
sprintf(MsgStr,
"SOURCE: %d Name: %s Loc: type: %s Lat %lg Long %lg Depth %lg",
num_sources, srce_in->label,
coord_type, srce_in->dlat, srce_in->dlong,
srce_in->depth);
nll_putmsg(5, MsgStr);
}
if (ierr < 0 || istat != 12)
return (-1);
} else {
nll_puterr2("ERROR: unrecognized coordinate type", in_line);
return (-1);
}
return (0);
}
/** function to find source from label */
SourceDesc* FindSource(char* label) {
int len = strlen(label);
int nsrce;
int len2;
for (nsrce = 0; nsrce < NumSources; nsrce++) {
len2 = strlen((Source + nsrce)->label);
// 20100512 AJL
if (len2 != len)
continue;
// 20100409 AJL if(strncmp((Source + nsrce)->label, label, ARRIVAL_LABEL_LEN) == 0)
if (strncmp((Source + nsrce)->label, label, len) == 0)
return (Source + nsrce);
}
return (NULL);
}
/** function to convert map projection string to map transformation parameter string by removing parameter tags
*
* Example: converts
* TRANSFORM LAMBERT RefEllipsoid Clarke-1880 LatOrig 40.780400 LongOrig 15.415500 FirstStdParal 43.199300 SecondStdParal 44.996100 RotCW 0.000000
* to
* LAMBERT Clarke-1880 40.780400 15.415500 43.199300 44.996100 0.000000
*
***/
char* projection_str2transform_str(char* trans_str, char* proj_str) {
char *proj_ptr;
char *trans_ptr;
proj_ptr = proj_str;
trans_ptr = trans_str;
while (*proj_ptr != '\0') {
// skip tag
while (*proj_ptr != ' ' && *proj_ptr != '\0') {
proj_ptr++;
}
// skip space
while (*proj_ptr == ' ' && *proj_ptr != '\0') {
proj_ptr++;
}
// copy parameter value
while (*proj_ptr != ' ' && *proj_ptr != '\0') {
*trans_ptr = *proj_ptr;
trans_ptr++;
proj_ptr++;
}
// copy space
while (*proj_ptr == ' ' && *proj_ptr != '\0') {
*trans_ptr = *proj_ptr;
trans_ptr++;
proj_ptr++;
}
}
*trans_ptr = '\0';
return (trans_str);
}
/** function to read map transformation parameters from input line ***/
int get_transform(int n_proj, char* in_line) {
int istat, ierr;
double angle;
// SDC
double dlt1, dlt2, del, r, bc;
map_itype[n_proj] = MAP_TRANS_UNDEF;
GeometryMode = MODE_RECT;
/* read transform input line */
sscanf(in_line, "%s", map_trans_type[n_proj]);
if (strcmp(map_trans_type[n_proj], "GLOBAL") == 0) {
// mode
GeometryMode = MODE_GLOBAL;
map_itype[n_proj] = MAP_TRANS_GLOBAL;
istat = sscanf(in_line, "%s", map_trans_type[n_proj]);
angle = 0.0;
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s",
map_trans_type[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
ierr = 0;
if (ierr < 0 || istat != 1) {
nll_puterr("ERROR: reading GLOBAL transformation parameters");
return (-1);
}
} else if (strcmp(map_trans_type[n_proj], "NONE") == 0) {
map_itype[n_proj] = MAP_TRANS_NONE;
istat = sscanf(in_line, "%s", map_trans_type[n_proj]);
angle = 0.0;
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s",
map_trans_type[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
ierr = 0;
if (ierr < 0 || istat != 1) {
nll_puterr("ERROR: reading NONE transformation parameters");
return (-1);
}
} else if (strcmp(map_trans_type[n_proj], "SIMPLE") == 0) {
map_itype[n_proj] = MAP_TRANS_SIMPLE;
istat = sscanf(in_line, "%s %lf %lf %lf",
map_trans_type[n_proj], &map_orig_lat[n_proj], &map_orig_long[n_proj],
&map_rot[n_proj]);
angle = -cRPD * map_rot[n_proj];
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s LatOrig %lf LongOrig %lf RotCW %lf",
map_trans_type[n_proj], map_orig_lat[n_proj], map_orig_long[n_proj], map_rot[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
ierr = 0;
if (checkRangeDouble("TRANS",
"LatOrig", map_orig_lat[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"LongOrig", map_orig_long[n_proj], 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"RotCW", map_rot[n_proj], 1, -360.0, 1, 360.0) != 0)
ierr = -1;
if (ierr < 0 || istat != 4) {
nll_puterr("ERROR: reading SIMPLE transformation parameters");
return (-1);
}
} else if (strcmp(map_trans_type[n_proj], "SDC") == 0) {
map_itype[n_proj] = MAP_TRANS_SDC;
istat = sscanf(in_line, "%s %lf %lf %lf",
map_trans_type[n_proj], &map_orig_lat[n_proj], &map_orig_long[n_proj],
&map_rot[n_proj]);
angle = -cRPD * map_rot[n_proj];
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s LatOrig %lf LongOrig %lf RotCW %lf",
map_trans_type[n_proj], map_orig_lat[n_proj], map_orig_long[n_proj], map_rot[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
ierr = 0;
if (checkRangeDouble("TRANS",
"LatOrig", map_orig_lat[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"LongOrig", map_orig_long[n_proj], 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"RotCW", map_rot[n_proj], 1, -360.0, 1, 360.0) != 0)
ierr = -1;
if (ierr < 0 || istat != 4) {
nll_puterr("ERROR: reading SDC transformation parameters");
return (-1);
}
// SDC initialization
// conversion factor for latitude
dlt1 = atan(MAP_TRANS_SDC_DRLT * tan(map_orig_lat[n_proj] * DE2RA));
dlt2 = atan(MAP_TRANS_SDC_DRLT * tan((map_orig_lat[n_proj] + 1.0) * DE2RA));
del = dlt2 - dlt1;
r = ERAD * (1.0 - pow(sin(dlt1), 2) * FLATTENING);
map_sdc_xltkm[n_proj] = r * del;
// conversion factor for longitude
del = acos(1.0 - (1.0 - cos(DE2RA)) * pow(cos(dlt1), 2));
bc = r * del;
map_sdc_xlnkm[n_proj] = bc / cos(dlt1);
} else if (strcmp(map_trans_type[n_proj], "LAMBERT") == 0) {
map_itype[n_proj] = MAP_TRANS_LAMBERT;
istat = sscanf(in_line, "%s %s %lf %lf %lf %lf %lf",
map_trans_type[n_proj], map_ref_ellipsoid[n_proj],
&map_orig_lat[n_proj], &map_orig_long[n_proj],
&map_lambert_1st_std_paral[n_proj], &map_lambert_2nd_std_paral[n_proj],
&map_rot[n_proj]);
ierr = 0;
if (checkRangeDouble("TRANS",
"LatOrig", map_orig_lat[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"LongOrig", map_orig_long[n_proj], 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"FirstStdParal", map_lambert_1st_std_paral[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"SecondStdParal", map_lambert_2nd_std_paral[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"RotCW", map_rot[n_proj], 1, -360.0, 1, 360.0) != 0)
ierr = -1;
angle = -cRPD * map_rot[n_proj];
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
/* initialize GMT projection values */
if (map_setup_proxy(n_proj, map_ref_ellipsoid[n_proj]) < 0) {
nll_puterr(
"ERROR: initializing general transformation parameters, RefEllipsoid may be invalid");
return (-1);
}
/* initialize lambert projection */
vlamb(n_proj, map_orig_long[n_proj], map_orig_lat[n_proj],
map_lambert_1st_std_paral[n_proj], map_lambert_2nd_std_paral[n_proj]);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s RefEllipsoid %s LatOrig %lf LongOrig %lf FirstStdParal %lf SecondStdParal %lf RotCW %lf",
map_trans_type[n_proj], map_ref_ellipsoid[n_proj],
map_orig_lat[n_proj], map_orig_long[n_proj],
map_lambert_1st_std_paral[n_proj], map_lambert_2nd_std_paral[n_proj],
map_rot[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
if (ierr < 0 || istat != 7) {
nll_puterr("ERROR: reading LAMBERT transformation parameters");
return (-1);
}
} else if (strcmp(map_trans_type[n_proj], "TRANS_MERC") == 0) {
// 20160725 AJL - added TRANSVERSE MERCATOR PROJECTION (TM)
map_itype[n_proj] = MAP_TRANS_TM;
int use_false_easting = 0;
// set default values for false easting and scale factor for backwards
// compatibility, if not given on TRANS line
map_false_easting[n_proj] = 500000;
map_scale_factor[n_proj] = 1.0;
istat = sscanf(in_line, "%s %s %lf %lf %lf %d %ld %lf",
map_trans_type[n_proj], map_ref_ellipsoid[n_proj],
&map_orig_lat[n_proj], &map_orig_long[n_proj],
&map_rot[n_proj], &use_false_easting,
&map_false_easting[n_proj], &map_scale_factor[n_proj]);
ierr = 0;
if (checkRangeDouble("TRANS",
"LatOrig", map_orig_lat[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"LongOrig", map_orig_long[n_proj], 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"RotCW", map_rot[n_proj], 1, -360.0, 1, 360.0) != 0)
ierr = -1;
angle = -cRPD * map_rot[n_proj];
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
// initialize GMT projection values
if (map_setup_proxy(n_proj, map_ref_ellipsoid[n_proj]) < 0) {
nll_puterr(
"ERROR: initializing general transformation parameters, RefEllipsoid may be invalid");
return (-1);
}
// initialize projection
vtm(n_proj, map_orig_long[n_proj], map_orig_lat[n_proj], use_false_easting,
map_false_easting[n_proj], map_scale_factor[n_proj]);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s RefEllipsoid %s LatOrig %lf LongOrig %lf RotCW %lf UseFalseEasting %d FalseEasting %ld ScaleFactor %lf",
map_trans_type[n_proj], map_ref_ellipsoid[n_proj],
map_orig_lat[n_proj], map_orig_long[n_proj],
map_rot[n_proj], use_false_easting, map_false_easting[n_proj],
map_scale_factor[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
// 5: old, when omitting UseFalseEasting
// 6: old, when specifying UseFalseEasting
// 7: new, when specifying UseFalseEasting, FalseEasting but not ScaleFactor
// 8: new, when specifying UseFalseEasting, FalseEasting and ScaleFactor
if (ierr < 0 || (istat != 5 && istat != 6 && istat != 7 && istat != 8)) {
nll_puterr("ERROR: reading TRANS_MERC transformation parameters");
return (-1);
}
} else if (strcmp(map_trans_type[n_proj], "AZIMUTHAL_EQUIDIST") == 0) {
// 20171120 AJL - added AZIMUTHAL EQUIDISTANT PROJECTION
map_itype[n_proj] = MAP_TRANS_AZ_EQUID;
istat = sscanf(in_line, "%s %s %lf %lf %lf",
map_trans_type[n_proj], map_ref_ellipsoid[n_proj],
&map_orig_lat[n_proj], &map_orig_long[n_proj],
&map_rot[n_proj]);
ierr = 0;
if (checkRangeDouble("TRANS",
"LatOrig", map_orig_lat[n_proj], 1, -90.0, 1, 90.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"LongOrig", map_orig_long[n_proj], 1, -180.0, 1, 180.0) != 0)
ierr = -1;
if (checkRangeDouble("TRANS",
"RotCW", map_rot[n_proj], 1, -360.0, 1, 360.0) != 0)
ierr = -1;
angle = -cRPD * map_rot[n_proj];
map_cosang[n_proj] = cos(angle);
map_sinang[n_proj] = sin(angle);
// initialize GMT projection values
if (map_setup_proxy(n_proj, map_ref_ellipsoid[n_proj]) < 0) {
nll_puterr(
"ERROR: initializing general transformation parameters, RefEllipsoid may be invalid");
return (-1);
}
// initialize projection
vazeqdist(n_proj, map_orig_long[n_proj], map_orig_lat[n_proj]);
sprintf(MapProjStr[n_proj],
"TRANSFORM %s RefEllipsoid %s LatOrig %lf LongOrig %lf RotCW %lf",
map_trans_type[n_proj], map_ref_ellipsoid[n_proj],
map_orig_lat[n_proj], map_orig_long[n_proj],
map_rot[n_proj]);
nll_putmsg(3, MapProjStr[n_proj]);
if (ierr < 0 || istat != 5) {
nll_puterr("ERROR: reading AZIMUTHAL_EQUIDIST transformation parameters");
return (-1);
}
} else {
nll_puterr("ERROR: unrecognized map transformation type");
return (-1);
}
return (0);
}
/** function to read grid params */
int get_grid(char* input_line) {
int istat, ierr = 0;
istat = sscanf(input_line, "%d %d %d %lf %lf %lf %lf %lf %lf %s",
&(grid_in.numx), &(grid_in.numy), &(grid_in.numz),
&(grid_in.origx), &(grid_in.origy), &(grid_in.origz),
&(grid_in.dx), &(grid_in.dy), &(grid_in.dz), grid_in.chr_type);
grid_in.iSwapBytes = 0;
convert_grid_type(&grid_in, 1);
if (message_flag >= 2)
display_grid_param(&grid_in);
if (checkRangeInt("GRID", "xNum", grid_in.numx, 1, 2, 0, 0) != 0)
ierr = -1;
if (checkRangeInt("GRID", "yNum", grid_in.numy, 1, 2, 0, 0) != 0)
ierr = -1;
if (checkRangeInt("GRID", "zNum", grid_in.numz, 1, 2, 0, 0) != 0)
ierr = -1;
if (ierr < 0)
return (-1);
if (istat != 10)
return (-1);
return (0);
}
/** function to convert grid type from char to numeric or v.v. */
int convert_grid_type(GridDesc* pgrid, int char2numeric) {
int i;
int ntypes = 20;
//
static char char_types[][32] = {
"VELOCITY", "VELOCITY_METERS",
"SLOWNESS", "SLOW_LEN", "VEL2", "SLOW2", "SLOW2_METERS",
"TIME", "TIME2D",
"ANGLE", "ANGLE2D",
"INCLINATION", "INCLINATION2D",
"PROB_DENSITY", "MISFIT", "LIKELIHOOD",
"DEPTH", "LENGTH", "COULOMB", "SSST_TIMECORR"
};
//
static int types[] = {
GRID_VELOCITY, GRID_VELOCITY_METERS,
GRID_SLOWNESS, GRID_SLOW_LEN, GRID_VEL2, GRID_SLOW2, GRID_SLOW2_METERS,
GRID_TIME, GRID_TIME_2D,
GRID_ANGLE, GRID_ANGLE_2D,
GRID_INCLINATION, GRID_INCLINATION_2D,
GRID_PROB_DENSITY, GRID_MISFIT, GRID_LIKELIHOOD,
GRID_DEPTH, GRID_LENGTH, GRID_COULOMB, GRID_SSST_TIMECORR
};
/* check grid type */
if (char2numeric) {
for (i = 0; i < ntypes; i++) {
if (strcmp(pgrid->chr_type, char_types[i]) == 0) {
pgrid->type = types[i];
return (pgrid->type);
}
}
pgrid->type = GRID_UNDEF;
nll_puterr2("WARNING: unrecognized grid type", pgrid->chr_type);
return (pgrid->type);
} else {
for (i = 0; i < ntypes; i++) {
if (pgrid->type == types[i]) {
strcpy(pgrid->chr_type, char_types[i]);
return (pgrid->type);
}
}
nll_puterr("WARNING: unrecognized grid type code");
return (pgrid->type);
}
}
/** function to display grid params */
int display_grid_param(GridDesc* pgrid) {
fprintf(stdout,
"GRID: {x, y, z}\n Num: {%d, %d, %d}\n Orig: {%lg, %lg, %lg}\n LenSide: {%lg, %lg, %lg}\n",
pgrid->numx, pgrid->numy, pgrid->numz,
pgrid->origx, pgrid->origy, pgrid->origz,
pgrid->dx, pgrid->dy, pgrid->dz);
fprintf(stdout, " Type: %s\n", pgrid->chr_type);
return (0);
}
/** function to determine if a grid is type Cascading 3D grid
*
* 20161019 AJL - added
*/
int isCascadingGrid(GridDesc* pgrid) {
return (pgrid->flagGridCascading == IS_CASCADING);
}
/** function set a grid as type Cascading 3D grid
*
* 20161020 AJL - added
*/
void setCascadingGrid(GridDesc* pgrid) {
pgrid->flagGridCascading = IS_CASCADING;
// flag dynamic arrays as uninitialized
pgrid->gridDesc_Cascading.xyz_scale = NULL;
pgrid->gridDesc_Cascading.zindex = NULL;
}
/** function to write grid buffer and header to disk ***/
int WriteGrid3dBuf(GridDesc* pgrid, SourceDesc* psrce, char* filename, char* file_type) {
int istat;
FILE *fpio;
char fname[FILENAME_MAX];
/* write buffer file */
if (file_type != NULL) {
sprintf(fname, "%s.%s.buf", filename, file_type);
} else {
sprintf(fname, "%s.buf", filename);
}
if ((fpio = fopen(fname, "w")) == NULL) {
nll_puterr("ERROR: opening buffer output file.");
return (-1);
}
NumFilesOpen++;
if (fwrite((char *) pgrid->buffer, pgrid->buffer_size, 1, fpio) != 1) {
nll_puterr("ERROR: writing grid buffer output file.");
return (-1);
}
fclose(fpio);
NumFilesOpen--;
/* write header file */
istat = WriteGrid3dHdr(pgrid, psrce, filename, file_type);
return (istat);
}
/** function to write grid header to disk ***/
int WriteGrid3dHdr(GridDesc* pgrid, SourceDesc* psrce,
char* filename, char* file_type) {
FILE *fpio;
char fname[FILENAME_MAX];
/* write header file */
if (file_type != NULL) {
sprintf(fname, "%s.%s.hdr", filename, file_type);
} else {
sprintf(fname, "%s.hdr", filename);
}
if ((fpio = fopen(fname, "w")) == NULL) {
nll_puterr("ERROR: opening grid output header file.");
return (-1);
}
NumFilesOpen++;
fprintf(fpio, "%d %d %d %lf %lf %lf %lf %lf %lf %s",
pgrid->numx, pgrid->numy, pgrid->numz,
pgrid->origx, pgrid->origy, pgrid->origz,
pgrid->dx, pgrid->dy, pgrid->dz, pgrid->chr_type);
#ifdef GRID_FLOAT_TYPE_DOUBLE
fprintf(fpio, " DOUBLE\n");
#else
fprintf(fpio, " FLOAT\n");
#endif
if (pgrid->type == GRID_TIME || pgrid->type == GRID_TIME_2D
|| pgrid->type == GRID_ANGLE || pgrid->type == GRID_ANGLE_2D
|| pgrid->type == GRID_INCLINATION || pgrid->type == GRID_INCLINATION_2D
)
fprintf(fpio, "%s %lf %lf %lf\n",
psrce->label, psrce->x, psrce->y, psrce->z);
fprintf(fpio, "%s\n", MapProjStr[0]);
// write extra cascading grid header lines
if (isCascadingGrid(pgrid)) {
fprintf(fpio, "CASCADING_GRID %d ", pgrid->gridDesc_Cascading.num_z_merge_depths);
for (int n = 0; n < pgrid->gridDesc_Cascading.num_z_merge_depths; n++) {
fprintf(fpio, "%f,", pgrid->gridDesc_Cascading.z_merge_depths[n]);
}
}
fprintf(fpio, "\n");
fclose(fpio);
NumFilesOpen--;
return (0);
}
//#define DEBUG_CASC
/** function to allocate buffer for Cascading 3D grid
*
* 20161019 AJL - added
*/
void* AllocateGrid_Cascading(GridDesc* pgrid, int allocate_buffer) {
// free any existing allocations
if (allocate_buffer) {
FreeGrid(pgrid);
} else {
FreeGrid_Cascading(pgrid);
}
// allocate cascading grid description index arrays
pgrid->gridDesc_Cascading.zindex = (void *) malloc((size_t) (pgrid->numz * sizeof (double)));
NumAllocations++;
pgrid->gridDesc_Cascading.xyz_scale = (void *) malloc((size_t) (pgrid->numz * sizeof (int)));
NumAllocations++;
// set indices and determine grid memory size
double reg_grid_depth = pgrid->origz;
int reg_grid_z_index = 0;
int reg_grid_z_index_below_last_merge_depth = 0;
double casc_grid_z_index = 0.0;
int merge_factor = 1;
long size_casc_grid = 0;
long size_reg_grid = 0;
// loop over specified merge depths
int below_deepest_merge_depth = 0;
for (int n = 0; n <= pgrid->gridDesc_Cascading.num_z_merge_depths; n++) {
#ifdef DEBUG_CASC
printf("DEBUG: ndep %d depth=%f ===========================================\n", n,
(n < pgrid->gridDesc_Cascading.num_z_merge_depths) ? pgrid->gridDesc_Cascading.z_merge_depths[n] : 999);
#endif
if (n == pgrid->gridDesc_Cascading.num_z_merge_depths) {
below_deepest_merge_depth = 1;
}
// set zindex and xyz_scale while regular grid depth < merge depth
while (reg_grid_z_index < pgrid->numz // above bottom of regular grid
&& (below_deepest_merge_depth // below deepest specified merge depth
|| (!below_deepest_merge_depth && reg_grid_depth < pgrid->gridDesc_Cascading.z_merge_depths[n]) // above current merge depth
|| reg_grid_z_index_below_last_merge_depth % merge_factor != 0 // not at bottom of new cascading grid cell
)) {
if (reg_grid_z_index_below_last_merge_depth % merge_factor == 0) { // at top of new cascading grid depth level, increment grid memory size
//size_casc_grid += (pgrid->numx / merge_factor) * (pgrid->numy / merge_factor); // truncate in x, y
//size_casc_grid += (int) ((double) pgrid->numx / (double) merge_factor) * (int) ((double) pgrid->numy / (double) merge_factor); // allow fraction of full cascading cell x, y
int nx_use = 1 + (pgrid->numx - 1) / merge_factor;
nx_use += (pgrid->numx - 1) % merge_factor > 0 ? 1 : 0;
//nx_use += pgrid->numx % merge_factor != 1 ? 1 : 0;
int ny_use = 1 + (pgrid->numy - 1) / merge_factor;
ny_use += (pgrid->numy - 1) % merge_factor > 0 ? 1 : 0;
//ny_use += pgrid->numy % merge_factor != 1 ? 1 : 0;
size_casc_grid += nx_use * ny_use; // allow fraction of full cascading cell x, y
}
size_reg_grid += pgrid->numx * pgrid->numy;
#ifdef DEBUG_CASC
printf("DEBUG: ireg %d, dep_reg %.1f, ds_casc %.1f, icasc %.2f, size_casc %ld/%ld [%.2f]\n",
reg_grid_z_index, reg_grid_depth, pgrid->dz * (double) merge_factor, casc_grid_z_index,
size_casc_grid, size_reg_grid, (double) size_casc_grid / (double) size_reg_grid);
#endif
pgrid->gridDesc_Cascading.zindex[reg_grid_z_index] = casc_grid_z_index;
casc_grid_z_index += (1.0 / (double) merge_factor);
pgrid->gridDesc_Cascading.xyz_scale[reg_grid_z_index] = merge_factor;
reg_grid_z_index++;
reg_grid_z_index_below_last_merge_depth++;
reg_grid_depth += pgrid->dz;
}
if (!below_deepest_merge_depth && reg_grid_z_index >= pgrid->numz) {
sprintf(MsgStr, "WARNING: AllocateGrid_Cascading: z merge depth: %f below grid bottom: %f",
pgrid->gridDesc_Cascading.z_merge_depths[n], pgrid->origz + (double) (pgrid->numz - 1) * pgrid->dz);
nll_puterr(MsgStr);
//return (NULL);
}
reg_grid_z_index_below_last_merge_depth = 0;
merge_factor *= 2; // creates a new cascade level
}
//pgrid->gridDesc_Cascading.num_z_cascading = pgrid->gridDesc_Cascading.zindex[pgrid->numz - 1];
pgrid->buffer_size = (size_t) (size_casc_grid * sizeof (GRID_FLOAT_TYPE));
// DEBUG pgrid->buffer_size -= 128 * sizeof (GRID_FLOAT_TYPE);
if (allocate_buffer) {
pgrid->buffer = (void *) malloc(pgrid->buffer_size);
if (pgrid->buffer != NULL)
NumAllocations++;
}
#ifdef DEBUG_CASC
printf("DEBUG: byte size_casc %ld/%ld [%.2f], val size_casc %ld/%ld\n",
size_casc_grid * sizeof (GRID_FLOAT_TYPE), size_reg_grid * sizeof (GRID_FLOAT_TYPE), (double) size_casc_grid / (double) size_reg_grid,
size_casc_grid, size_reg_grid);
#endif
return (pgrid->buffer);
}
/** function to create array for accessing Cascading 3D grid
*
* 20161019 AJL - added
*/
void*** CreateGridArray_Cascading(GridDesc* pgrid) {
#ifdef DEBUG_CASC
for (int i = 0; i < pgrid->numz; i++) { // DEBUG
printf("iz_reg %d, zindex[i] %d, xyz_scale[i] %d\n",
i, pgrid->gridDesc_Cascading.zindex[i], pgrid->gridDesc_Cascading.xyz_scale[i]);
}
#endif
GRID_FLOAT_TYPE ***garray;
if ((garray = (GRID_FLOAT_TYPE ***) malloc((size_t) pgrid->numx * sizeof (GRID_FLOAT_TYPE **))) == NULL)
return ((void***) garray);
NumAllocations++;
int ix_casc, iy_casc, iz_reg, numz;
int current_numz;
int xyz_scale;
GRID_FLOAT_TYPE *buf_ptr = (GRID_FLOAT_TYPE *) pgrid->buffer;
long bfactor = 1;
if (buf_ptr == NULL) { // buffer not created, arrays used to fseek in direct read of buffer on disk in ReadGrid3dValue()
bfactor = 2; // conversion from pointer addressing to absolute byte addressing
buf_ptr = 0;
}
#ifdef DEBUG_CASC
printf("garray begin: buf_ptr %ld buf_ptr_end %ld\n", (long) buf_ptr, (buf_ptr - (GRID_FLOAT_TYPE *) pgrid->buffer));
#endif
for (ix_casc = 0; ix_casc < pgrid->numx; ix_casc++) {
if ((garray[ix_casc] = (GRID_FLOAT_TYPE **) malloc((size_t) pgrid->numy * sizeof (GRID_FLOAT_TYPE *))) == NULL)
return (NULL);
NumAllocations++;
for (iy_casc = 0; iy_casc < pgrid->numy; iy_casc++) {
current_numz = -1;
// calculate num z cascading at this x,y
numz = 0;
for (iz_reg = 0; iz_reg < pgrid->numz; iz_reg++) { // loop over nominal regular grid z levels
if (pgrid->gridDesc_Cascading.zindex[iz_reg] == current_numz) { // still in current cascading grid z level
continue;
}
// into new cascading grid z level
current_numz = pgrid->gridDesc_Cascading.zindex[iz_reg];
// check if xyz cascading cell exists at this ix_casc,iy_casc,numz
xyz_scale = pgrid->gridDesc_Cascading.xyz_scale[iz_reg];
if (ix_casc * xyz_scale < pgrid->numx + xyz_scale - 1 && iy_casc * xyz_scale < pgrid->numy + xyz_scale - 1) {
//if (ix_casc <= pgrid->numx / xyz_scale && iy_casc <= pgrid->numy / xyz_scale) {
numz++; // increment count of z levels for this x,y, cascading
} else {
break; // reached bottom of z levels for this x,y cascading
}
}
garray[ix_casc][iy_casc] = buf_ptr;
//buf_ptr += numz * sizeof (GRID_FLOAT_TYPE);
buf_ptr += numz * bfactor;
if (buf_ptr - (GRID_FLOAT_TYPE *) pgrid->buffer > 2 * pgrid->buffer_size / sizeof (GRID_FLOAT_TYPE)) {
sprintf(MsgStr, "ERROR: CreateGridArray_Cascading: buf_ptr > buffer_size: x%d y%d numz%d (offset %ld buf_size %ld diff %ld) in: %s",
ix_casc, iy_casc, numz, (buf_ptr - (GRID_FLOAT_TYPE *) pgrid->buffer), 2 * pgrid->buffer_size / sizeof (GRID_FLOAT_TYPE), (buf_ptr - (GRID_FLOAT_TYPE *) pgrid->buffer) - 2 * pgrid->buffer_size / sizeof (GRID_FLOAT_TYPE), pgrid->title);
nll_puterr(MsgStr);
}
#ifdef DEBUG_CASC
//if ((ix_casc == 0 || ix_casc == pgrid->numx - 1) && (iy_casc == 0 || iy_casc == pgrid->numy - 1))
if (ix_casc < 4 && iy_casc < 4 && iz_reg < 4)
printf("garray [ix_casc %d, iy_casc %d] buf_ptr %ld buf_ptr_end %ld numz %d\n",
ix_casc, iy_casc, (long) buf_ptr, (buf_ptr - (GRID_FLOAT_TYPE *) pgrid->buffer), numz);
#endif
}
}
#ifdef DEBUG_CASC
printf("garray end: buf_ptr %ld buf_ptr_end %ld buf_size %ld\n", (long) buf_ptr, (buf_ptr - (GRID_FLOAT_TYPE *) pgrid->buffer), pgrid->buffer_size / sizeof (GRID_FLOAT_TYPE));
#endif
pgrid->array = (void***) garray;
return ((void***) garray);
}
/** function to allocate buffer for 3D grid ***/
void* AllocateGrid(GridDesc * pgrid) {
if (isCascadingGrid(pgrid)) {
AllocateGrid_Cascading(pgrid, 1);
return (pgrid->buffer);
}
pgrid->buffer_size = (size_t) (pgrid->numx * pgrid->numy * pgrid->numz * sizeof (GRID_FLOAT_TYPE));
pgrid->buffer = (void *) malloc(pgrid->buffer_size);
if (pgrid->buffer != NULL)
NumAllocations++;
return (pgrid->buffer);
}
/** function to free buffer for 3D grid ***/
void FreeGrid_Cascading(GridDesc * pgrid) {
// 20170207 AJL - z_merge_depths moved to fixed array to ease memory management
/*if (pgrid->gridDesc_Cascading.z_merge_depths != NULL) {
free(pgrid->gridDesc_Cascading.z_merge_depths);
pgrid->gridDesc_Cascading.z_merge_depths = NULL;
NumAllocations--;
}
pgrid->gridDesc_Cascading.z_merge_depths = NULL;*/
//printf("DEBUG: FreeGrid_Cascading: pgrid->gridDesc_Cascading.zindex %ld\n", (long) pgrid->gridDesc_Cascading.zindex);
if (pgrid->gridDesc_Cascading.zindex != NULL) {
free(pgrid->gridDesc_Cascading.zindex);
pgrid->gridDesc_Cascading.zindex = NULL;
NumAllocations--;
}
pgrid->gridDesc_Cascading.zindex = NULL;
if (pgrid->gridDesc_Cascading.xyz_scale != NULL) {
free(pgrid->gridDesc_Cascading.xyz_scale);
pgrid->gridDesc_Cascading.xyz_scale = NULL;
NumAllocations--;
}
pgrid->gridDesc_Cascading.xyz_scale = NULL;
}
/** function to free buffer for 3D grid ***/
void FreeGrid(GridDesc * pgrid) {
if (isCascadingGrid(pgrid)) {
FreeGrid_Cascading(pgrid);
}
if (pgrid->buffer != NULL) {
free(pgrid->buffer);
pgrid->buffer = NULL;
NumAllocations--;
}
}
/** function to initialize buffer for 3D grid ***/
int InitializeGrid(GridDesc* pgrid, GRID_FLOAT_TYPE init_value) {
GRID_FLOAT_TYPE *gbuf;
gbuf = (GRID_FLOAT_TYPE *) pgrid->buffer + pgrid->numx * pgrid->numy * pgrid->numz;
while (gbuf-- > (GRID_FLOAT_TYPE *) pgrid->buffer)
*gbuf = init_value;
return (0);
}
/** function to create array for accessing 3D grid ***/
void*** CreateGridArray(GridDesc * pgrid) {
if (isCascadingGrid(pgrid)) {
return (CreateGridArray_Cascading(pgrid));
}
int ix, iy, numyz;
GRID_FLOAT_TYPE ***garray;
if ((garray = (GRID_FLOAT_TYPE ***) malloc((size_t) pgrid->numx * sizeof (GRID_FLOAT_TYPE **))) == NULL)
return ((void***) garray);
NumAllocations++;
numyz = pgrid->numy * pgrid->numz;
for (ix = 0; ix < pgrid->numx; ix++) {
if ((garray[ix] = (GRID_FLOAT_TYPE **) malloc((size_t) pgrid->numy * sizeof (GRID_FLOAT_TYPE *))) == NULL)
return (NULL);
NumAllocations++;
for (iy = 0; iy < pgrid->numy; iy++) {
garray[ix][iy] = (GRID_FLOAT_TYPE *) pgrid->buffer + ix * numyz + iy * pgrid->numz;
}
}
pgrid->array = (void***) garray;
return ((void***) garray);
}
/** function to free array for accessing 3D grid ***/
void DestroyGridArray(GridDesc * pgrid) {
int ix;
//printf("DEBUG: DestroyGridArray(): pgrid %X pgrid->array %X\n", pgrid, pgrid->array);
if (pgrid->array != NULL) {
for (ix = 0; ix < pgrid->numx; ix++) {
//printf("DEBUG: DestroyGridArray(): ix %d/%d pgrid->array[ix] %X\n", ix, pgrid->numx, pgrid->array[ix]);
free(pgrid->array[ix]);
pgrid->array[ix] = NULL;
NumAllocations--;
}
free(pgrid->array);
pgrid->array = NULL;
NumAllocations--;
}
}
/** function to duplicate a 3D grid description and allocate grid memory */
void DuplicateGrid(GridDesc* pnew_grid, GridDesc* pold_grid, char *new_chr_type) {
/* copy grid description */
*pnew_grid = *pold_grid;
/* set grid type */
strcpy(pnew_grid->chr_type, new_chr_type);
convert_grid_type(pnew_grid, 1);
/* allocate grid */
pnew_grid->buffer = AllocateGrid(pnew_grid);
if (pnew_grid->buffer == NULL) {
nll_puterr(
"ERROR: allocating memory for duplicate 3D grid buffer.");
exit(EXIT_ERROR_MEMORY);
}
/* create grid array access pointers */
pnew_grid->array = CreateGridArray(pnew_grid);
if (pnew_grid->array == NULL) {
nll_puterr(
"ERROR: creating array for accessing duplicate 3D grid buffer.");
exit(EXIT_ERROR_MEMORY);
}
}
/** function to perform several checks on grid data ***/
int CheckGridArray(GridDesc* pgrid, double gridMax, double gridMaxReplace,
double gridMin, double gridMinReplace) {
int ix, iy, iz;
int ierror = 0, inegative = 0, imax = 0, imin = 0;
GRID_FLOAT_TYPE val;
for (ix = 0; ix < pgrid->numx; ix++) {
for (iy = 0; iy < pgrid->numy; iy++) {
for (iz = 0; iz < pgrid->numz; iz++) {
/* check for negative values */
if ((val = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz]) < 0.0)
inegative++;
/* check for out of range values */
if (val > gridMax) {
val = gridMaxReplace;
imax++;
} else if (val < gridMin) {
val = gridMinReplace;
imin++;
}
}
}
}
if (inegative) {
sprintf(MsgStr,
"WARNING: %d negative values in grid.", inegative);
nll_putmsg(1, MsgStr);
ierror = -1;
}
if (imax) {
sprintf(MsgStr,
"WARNING: %d values > %e in grid replaced with %e",
imax, gridMax, gridMaxReplace);
nll_putmsg(1, MsgStr);
ierror = -1;
}
if (imin) {
sprintf(MsgStr,
"WARNING: %d values < %e in grid replaced with %e",
imin, gridMin, gridMinReplace);
nll_putmsg(1, MsgStr);
ierror = -1;
}
return (ierror);
}
/** function to sum 2 grids ***/
/* reads from array if fp_grid_new == NULL */
//#define DEBUG_SUMGRIDS
int SumGrids(GridDesc* pgrid_sum, GridDesc* pgrid_new, FILE* fp_grid_new, double factor) {
int ix, iy, iz;
GRID_FLOAT_TYPE xval, yval, zval, newval;
int identical = pgrid_new->array != NULL && testIdentical(pgrid_sum, pgrid_new);
xval = pgrid_sum->origx;
for (ix = 0; ix < pgrid_sum->numx; ix++) {
yval = pgrid_sum->origy;
for (iy = 0; iy < pgrid_sum->numy; iy++) {
zval = pgrid_sum->origz;
for (iz = 0; iz < pgrid_sum->numz; iz++) {
if (identical) {
newval = ((GRID_FLOAT_TYPE ***) pgrid_new->array)[ix][iy][iz];
} else {
newval = ReadAbsInterpGrid3d(fp_grid_new, pgrid_new, xval, yval, zval, 0);
}
if (newval > -LARGE_FLOAT) {
#ifdef DEBUG_SUMGRIDS
float result = ((GRID_FLOAT_TYPE ***) pgrid_sum->array)[ix][iy][iz] + factor * newval;
if (factor < 0.0 && fabs(result) > 1.0)
printf("DEBUG: SumGrids: %d %d %d %f + %f * %f = %f\n",
ix, iy, iz, ((GRID_FLOAT_TYPE ***) pgrid_sum->array)[ix][iy][iz], factor, newval, result);
#endif
((GRID_FLOAT_TYPE ***) pgrid_sum->array)[ix][iy][iz] += factor * newval;
}
zval += pgrid_sum->dz;
}
yval += pgrid_sum->dy;
}
xval += pgrid_sum->dx;
}
return (0);
}
/** function to multiply grid by a constant factor ***/
/* reads from array if fp_grid_in == NULL */
//#define DEBUG_MULCONSTGRID
int MulConstGrid(GridDesc* pgrid_out, GridDesc* pgrid_in, FILE* fp_grid_in, double factor) {
int ix, iy, iz;
GRID_FLOAT_TYPE xval, yval, zval, newval;
int identical = pgrid_in->array != NULL && testIdentical(pgrid_out, pgrid_in);
xval = pgrid_out->origx;
for (ix = 0; ix < pgrid_out->numx; ix++) {
yval = pgrid_out->origy;
for (iy = 0; iy < pgrid_out->numy; iy++) {
zval = pgrid_out->origz;
for (iz = 0; iz < pgrid_out->numz; iz++) {
if (identical) {
newval = ((GRID_FLOAT_TYPE ***) pgrid_in->array)[ix][iy][iz];
} else {
newval = ReadAbsInterpGrid3d(fp_grid_in, pgrid_in, xval, yval, zval, 0);
}
if (newval > -LARGE_FLOAT) {
#ifdef DEBUG_MULCONSTGRID
float result = ((GRID_FLOAT_TYPE ***) pgrid_out->array)[ix][iy][iz] + factor * newval;
if (factor < 0.0 && fabs(result) > 1.0)
printf("DEBUG: SumGrids: %d %d %d %f + %f * %f = %f\n",
ix, iy, iz, ((GRID_FLOAT_TYPE ***) pgrid_out->array)[ix][iy][iz], factor, newval, result);
#endif
((GRID_FLOAT_TYPE ***) pgrid_out->array)[ix][iy][iz] = factor * newval;
}
zval += pgrid_out->dz;
}
yval += pgrid_out->dy;
}
xval += pgrid_out->dx;
}
return (0);
}
/** check if two grids origin and dimensions are identical
*
* requires that grid are identical in size,
* returns 1 if identical, returns 0 if not
*
*/
int testIdentical(GridDesc* pGrid1, GridDesc* pGrid2) {
//printf("DEBUG: testIdentical: test %s / %s\n", pGrid2->title, pGrid1->title);
// check all relevant grid parameters are identical
if (pGrid1->origx != pGrid2->origx
|| pGrid1->origy != pGrid2->origy
|| pGrid1->origz != pGrid2->origz
) {
//printf("return 0 %f %f %f : %f %f %f\n", pGrid1->origx, pGrid1->origy, pGrid1->origz, pGrid2->origx, pGrid2->origy, pGrid2->origz);
return (0);
}
if (pGrid1->dx != pGrid2->dx
|| pGrid1->dy != pGrid2->dy
|| pGrid1->dz != pGrid2->dz
) {
//printf("return 0 %f %f %f : %f %f %f\n", pGrid1->dx, pGrid1->dy, pGrid1->dz, pGrid2->dx, pGrid2->dy, pGrid2->dz);
return (0);
}
if (pGrid1->numx != pGrid2->numx
|| pGrid1->numy != pGrid2->numy
|| pGrid1->numz != pGrid2->numz
) {
//printf("return 1 %d %d %d : %d %d %d\n", pGrid1->numx, pGrid1->numy, pGrid1->numz, pGrid2->numx, pGrid2->numy, pGrid2->numz);
return (0);
}
return (1);
}
/** function to check if a point is on grid boundary */
/* return 10,11,20,21,30,31 if within tolerance of x,y,z orig/end boundary, return 0 otherwise */
int isOnGridBoundary(double xloc, double yloc, double zloc, GridDesc* pgrid,
double tolerance_xy, double tolerance_z, int i_check_top) {
// 20151118 AJL - bug fix, should not perform these tests for GLOBAL mode, if whole earth TODO: add check if global search volume is whole earth?
// if (GeometryMode == MODE_GLOBAL) {
if (GeometryMode != MODE_GLOBAL) {
if (fabs(xloc - pgrid->origx) <= tolerance_xy)
return (10);
if (fabs(xloc - (pgrid->origx + (double) (pgrid->numx - 1) * pgrid->dx))
<= tolerance_xy)
return (11);
if (fabs(yloc - pgrid->origy) <= tolerance_xy)
return (20);
if (fabs(yloc - (pgrid->origy + (double) (pgrid->numy - 1) * pgrid->dy))
<= tolerance_xy)
return (21);
}
if (i_check_top && fabs(zloc - pgrid->origz) <= tolerance_z)
return (30);
if (fabs(zloc - (pgrid->origz + (double) (pgrid->numz - 1) * pgrid->dz))
<= tolerance_z)
return (31);
return (0);
}
/** function to check if a point is contained within a grid */
int IsPointInsideGrid(GridDesc* pgrid, double xloc, double yloc, double zloc) {
if (xloc < pgrid->origx ||
xloc > pgrid->origx + (double) (pgrid->numx - 1) * pgrid->dx)
return (0);
if (yloc < pgrid->origy ||
yloc > pgrid->origy + (double) (pgrid->numy - 1) * pgrid->dy)
return (0);
if (zloc < pgrid->origz ||
zloc > pgrid->origz + (double) (pgrid->numz - 1) * pgrid->dz)
return (0);
return (1);
}
/** function to check if a grid is entirely contained within another grid */
/* return 1 if pgrid_inside is inside pgrid, return 0 otherwise */
/* if iShiftFlag==1 shifts grid to attempt to get it inside */
int IsGridInside(GridDesc* pgrid_inside, GridDesc* pgrid, int iShiftFlag) {
double xmin_in, xmax_in, ymin_in, ymax_in, zmin_in, zmax_in;
double xmin, xmax, ymin, ymax, zmin, zmax;
if (pgrid_inside == pgrid)
return (1);
xmin_in = pgrid_inside->origx;
xmax_in = pgrid_inside->origx +
(double) (pgrid_inside->numx - 1) * pgrid_inside->dx;
ymin_in = pgrid_inside->origy;
ymax_in = pgrid_inside->origy +
(double) (pgrid_inside->numy - 1) * pgrid_inside->dy;
zmin_in = pgrid_inside->origz;
zmax_in = pgrid_inside->origz +
(double) (pgrid_inside->numz - 1) * pgrid_inside->dz;
xmin = pgrid->origx;
xmax = pgrid->origx + (double) (pgrid->numx - 1) * pgrid->dx;
ymin = pgrid->origy;
ymax = pgrid->origy + (double) (pgrid->numy - 1) * pgrid->dy;
zmin = pgrid->origz;
zmax = pgrid->origz + (double) (pgrid->numz - 1) * pgrid->dz;
if (!iShiftFlag) {
if (xmin_in < xmin || xmax_in > xmax ||
ymin_in < ymin || ymax_in > ymax ||
zmin_in < zmin || zmax_in > zmax)
return (0);
else
return (1);
} else {
if (xmin_in < xmin)
pgrid_inside->origx += xmin - xmin_in;
else if (xmax_in > xmax)
pgrid_inside->origx -= xmax_in - xmax;
if (ymin_in < ymin)
pgrid_inside->origy += ymin - ymin_in;
else if (ymax_in > ymax)
pgrid_inside->origy -= ymax_in - ymax;
if (zmin_in < zmin)
pgrid_inside->origz += zmin - zmin_in;
else if (zmax_in > zmax)
pgrid_inside->origz -= zmax_in - zmax;
return (IsGridInside(pgrid_inside, pgrid, 0));
}
}
/** function to check if greatest distance from a station to a 3D grid
is less than the horizontal extent of a 2D grid and
if depth range of the 3D grid is less than that of the 2D grid
and if station is within dist_horiz_min -> dist_horiz_max of grid location
xcent, ycent */
/* return 1 if yes, return 0 otherwise */
int IsDistStaGridOK(GridDesc* pgrid_3D, SourceDesc* station,
double dist_horiz_min, double dist_horiz_max, double xcent, double ycent) {
double distance;
/* check distances from grid location xcent, ycent */
if (dist_horiz_min < dist_horiz_max) {
// check if dist_horiz_min < DIST < dist_horiz_max
if (dist_horiz_min > SMALL_DOUBLE) {
if ((distance = GetEpiDist(station, xcent, ycent)) < dist_horiz_min)
return (-2);
}
if (dist_horiz_max > SMALL_DOUBLE) {
if ((distance = GetEpiDist(station, xcent, ycent)) > dist_horiz_max)
return (-2);
}
} else {
// check if DIST < dist_horiz_max && DIST > dist_horiz_min
if (dist_horiz_min > SMALL_DOUBLE && dist_horiz_max > SMALL_DOUBLE) {
distance = GetEpiDist(station, xcent, ycent);
if (distance < dist_horiz_min && distance > dist_horiz_max)
return (-2);
}
}
return (1);
}
/** function to check if greatest distance from a station to a 3D grid
is less than the horizontal extent of a 2D grid and
if depth range of the 3D grid is less than that of the 2D grid
and if station is within dist_horiz_min -> dist_horiz_max of grid location
xcent, ycent */
/* return 1 if yes, return 0 otherwise */
int IsGrid2DBigEnough(GridDesc* pgrid_3D, GridDesc* pgrid_2D,
SourceDesc* station,
double dist_horiz_min, double dist_horiz_max, double xcent, double ycent) {
double extent_horiz, distance;
double xmin_in, xmax_in, ymin_in, ymax_in, zmin_in, zmax_in;
double ymin, ymax, zmin, zmax;
/* check distances from grid location xcent, ycent */
if (dist_horiz_min < dist_horiz_max) {
// check if dist_horiz_min < DIST < dist_horiz_max
if (dist_horiz_min > SMALL_DOUBLE) {
if ((distance = GetEpiDist(station, xcent, ycent)) < dist_horiz_min)
return (-2);
}
if (dist_horiz_max > SMALL_DOUBLE) {
if ((distance = GetEpiDist(station, xcent, ycent)) > dist_horiz_max)
return (-2);
}
} else {
// check if DIST < dist_horiz_max && DIST > dist_horiz_min
if (dist_horiz_min > SMALL_DOUBLE && dist_horiz_max > SMALL_DOUBLE) {
distance = GetEpiDist(station, xcent, ycent);
if (distance < dist_horiz_min && distance > dist_horiz_max)
return (-2);
}
}
// 20160926 AJL - moved this block here from before previous block
// GLOBAL
if (GeometryMode == MODE_GLOBAL) {
return (1); //INGV do not worry about grid size
}
/* get extent of 2D grid */
ymin = pgrid_2D->origy;
ymax = pgrid_2D->origy + (double) (pgrid_2D->numy - 1) * pgrid_2D->dy;
extent_horiz = ymax - ymin;
zmin = pgrid_2D->origz;
zmax = pgrid_2D->origz + (double) (pgrid_2D->numz - 1) * pgrid_2D->dz;
/* get bounds of 3D grid */
xmin_in = pgrid_3D->origx;
xmax_in = pgrid_3D->origx +
(double) (pgrid_3D->numx - 1) * pgrid_3D->dx;
ymin_in = pgrid_3D->origy;
ymax_in = pgrid_3D->origy +
(double) (pgrid_3D->numy - 1) * pgrid_3D->dy;
zmin_in = pgrid_3D->origz;
zmax_in = pgrid_3D->origz +
(double) (pgrid_3D->numz - 1) * pgrid_3D->dz;
// adjust for GLOBAL (grid units = deg, GetEpiDist units = km)
if (GeometryMode == MODE_GLOBAL)
extent_horiz /= KM2DEG;
/* check each horizontal corner */
if ((distance = GetEpiDist(station, xmin_in, ymin_in)) > extent_horiz)
return (-1);
if ((distance = GetEpiDist(station, xmin_in, ymax_in)) > extent_horiz)
return (-1);
if ((distance = GetEpiDist(station, xmax_in, ymax_in)) > extent_horiz)
return (-1);
if ((distance = GetEpiDist(station, xmax_in, ymin_in)) > extent_horiz)
return (-1);
/* check depth range */
if (zmin_in < zmin || zmax_in > zmax)
return (-3);
return (1);
}
/** function to calculate epicentral (horizontal) distance from a source to an x-y position */
double GetEpiDist(SourceDesc* psrce, double xval, double yval) {
double xtmp, ytmp;
if (GeometryMode == MODE_GLOBAL) {
return (GCDistance(yval, xval, psrce->y, psrce->x));
//return(EllipsoidDistance(yval, xval, psrce->y, psrce->x));
} else {
xtmp = xval - psrce->x;
ytmp = yval - psrce->y;
return (sqrt(xtmp * xtmp + ytmp * ytmp));
}
}
/** function to calculate epicentral (horizontal) distance from a station to an x-y position */
double GetEpiDistSta(StationDesc* psta, double xval, double yval) {
double xtmp, ytmp;
if (GeometryMode == MODE_GLOBAL) {
return (GCDistance(yval, xval, psta->y, psta->x));
//return(EllipsoidDistance(yval, xval, psta->y, psta->x));
} else {
xtmp = xval - psta->x;
ytmp = yval - psta->y;
return (sqrt(xtmp * xtmp + ytmp * ytmp));
}
}
/** function to calculate epicentral (horizontal) azimuth from a x-y position to a source */
double GetEpiAzim(SourceDesc* psrce, double xval, double yval) {
double xtmp, ytmp, azim;
if (GeometryMode == MODE_GLOBAL) {
return (GCAzimuth(yval, xval, psrce->y, psrce->x));
} else {
xtmp = psrce->x - xval;
ytmp = psrce->y - yval;
azim = atan2(xtmp, ytmp) / cRPD;
if (azim < 0.0)
azim += 360.0;
return (azim);
}
}
/** function to calculate epicentral (horizontal) azimuth from a
x-y position to a station */
double GetEpiAzimSta(StationDesc* psta, double xval, double yval) {
double xtmp, ytmp, azim;
if (GeometryMode == MODE_GLOBAL) {
return (GCAzimuth(yval, xval, psta->y, psta->x));
} else {
xtmp = psta->x - xval;
ytmp = psta->y - yval;
azim = atan2(xtmp, ytmp) / cRPD;
if (azim < 0.0)
azim += 360.0;
return (azim);
}
}
/** function to calculate distance between 2 XYZ points */
double Dist2D(double x1, double x2, double y1, double y2) {
if (GeometryMode == MODE_GLOBAL) {
return (GCDistance(y1, x1, y2, x2));
//return(EllipsoidDistance(yval, xval, psta->y, psta->x));
} else {
double dx, dy;
dx = x1 - x2;
dy = y1 - y2;
return (sqrt(dx * dx + dy * dy));
}
}
/** function to calculate distance between 2 XYZ points */
double Dist3D(double x1, double x2, double y1, double y2,
double z1, double z2) {
double epi_dist = Dist2D(x1, x2, y1, y2);
double dz = z1 - z2;
return (sqrt(epi_dist * epi_dist + dz * dz));
}
/** function to calculate average inter-station distance */
double calcAveInterStationDistance(SourceDesc *stations, int numStations) {
int ndist, n, m = 0;
double x, y;
double x2, y2;
double dist_sum, dist_ave;
// calculate average distance
dist_sum = 0.0;
ndist = 0;
for (n = 0; n < numStations; n++) {
// 20101021 AJL = Bug fix
// check if station has ignored reading for this event
if ((stations + n)->ignored)
continue;
x = (stations + n)->x;
y = (stations + n)->y;
if (!stationLocationIsKnown(x, y)) // station location not known
continue;
for (m = 0; m < n; m++) {
if ((stations + m)->ignored)
continue;
x2 = (stations + m)->x;
y2 = (stations + m)->y;
if (!stationLocationIsKnown(x2, y2)) // station location not known
continue;
dist_sum += GetEpiDist((stations + m), x, y);
ndist++;
}
//printf("Sta: %s x %f y %f dist_sum %f\n", (stations + n)->label, x, y, dist_sum);
}
if (ndist <= 0)
return (-1.0);
dist_ave = dist_sum / (double) ndist;
return (dist_ave);
}
/** function to check if station location is known */
int stationLocationIsKnown(double x, double y) {
// station location not known
if (x == 0.0 && y == 0.0)
return (0);
// station location not known
if (x < -LARGE_DOUBLE / 2.0 || y < -LARGE_DOUBLE / 2.0)
return (0);
// station location known
return (1);
}
/** function to generate a grid from an OctTree structure */
int ConvertOctTree2Grid(Tree3D* tree, double dx, double dy, double dz, char *grid_type, GridDesc * pgrid_out) {
int ix, iy, iz;
Vect3D coords;
OctNode* node;
GRID_FLOAT_TYPE value;
pgrid_out->numx = 1 + (int) ((double) tree->numx * tree->ds.x / dx);
pgrid_out->numy = 1 + (int) ((double) tree->numy * tree->ds.y / dy);
pgrid_out->numz = 1 + (int) ((double) tree->numz * tree->ds.z / dz);
pgrid_out->origx = tree->orig.x;
pgrid_out->origy = tree->orig.y;
pgrid_out->origz = tree->orig.z;
pgrid_out->dx = dx;
pgrid_out->dy = dy;
pgrid_out->dz = dz;
if (grid_type != NULL) {
strcpy(pgrid_out->chr_type, grid_type);
convert_grid_type(pgrid_out, 1);
} else {
pgrid_out->type = tree->data_code;
convert_grid_type(pgrid_out, 0);
}
/* allocate grid buffer */
if (message_flag >= 4)
display_grid_param(pgrid_out);
pgrid_out->buffer = AllocateGrid(pgrid_out);
if (pgrid_out->buffer == NULL) {
nll_puterr("ERROR: allocating memory for 3D PDF grid buffer.");
exit(EXIT_ERROR_MEMORY);
}
/* create grid array access pointers */
pgrid_out->array = CreateGridArray(pgrid_out);
if (pgrid_out->array == NULL) {
nll_puterr("ERROR: creating array for accessing 3D PDF grid buffer.");
exit(EXIT_ERROR_MEMORY);
}
/*
// use values for center of target cell
coords.x = pgrid_out->origx + dx / 2.0; // center of cell
for (ix = 0; ix < pgrid_out->numx; ix++) {
if (ix == pgrid_out->numx - 1)
coords.x -= dx / 2.0 + dx / 1000.0;
coords.y = pgrid_out->origy + dy / 2.0;
for (iy = 0; iy < pgrid_out->numy; iy++) {
if (iy == pgrid_out->numy - 1)
coords.y -= dy / 2.0 + dy / 1000.0;
coords.z = pgrid_out->origz + dz / 2.0;
for (iz = 0; iz < pgrid_out->numz; iz++) {
if (iz == pgrid_out->numz - 1)
coords.z -= dz / 2.0 + dz / 1000.0;
node = getLeafNodeContaining(tree, coords);
value = (GRID_FLOAT_TYPE) node->value;
pgrid_out->array[ix][iy][iz] = value;
coords.z += dz;
}
coords.y += dy;
}
coords.x += dx;
}
*/
// use values for corner of target cell
coords.x = pgrid_out->origx; // corner of cell
for (ix = 0; ix < pgrid_out->numx; ix++) {
if (ix == pgrid_out->numx - 1)
coords.x -= dx / 1000.0;
coords.y = pgrid_out->origy;
for (iy = 0; iy < pgrid_out->numy; iy++) {
if (iy == pgrid_out->numy - 1)
coords.y -= dy / 1000.0;
coords.z = pgrid_out->origz;
for (iz = 0; iz < pgrid_out->numz; iz++) {
if (iz == pgrid_out->numz - 1)
coords.z -= dz / 1000.0;
node = getLeafNodeContaining(tree, coords);
value = (GRID_FLOAT_TYPE) node->value;
((GRID_FLOAT_TYPE ***) pgrid_out->array)[ix][iy][iz] = value;
coords.z += dz;
}
coords.y += dy;
}
coords.x += dx;
}
return (0);
}
/** function to swap bytes in grid buffer ***/
int swapBytes(GRID_FLOAT_TYPE *buffer, long bufsize) {
GRID_FLOAT_TYPE *bufpos;
char ctmp;
unsigned short itmp;
union {
char cval[4];
unsigned short ival[2];
float fval;
}
bufval;
bufpos = buffer;
while (bufpos < buffer + bufsize) {
bufval.fval = *bufpos;
ctmp = bufval.cval[0];
bufval.cval[0] = bufval.cval[1];
bufval.cval[1] = ctmp;
ctmp = bufval.cval[2];
bufval.cval[2] = bufval.cval[3];
bufval.cval[3] = ctmp;
itmp = bufval.ival[0];
bufval.ival[0] = bufval.ival[1];
bufval.ival[1] = itmp;
*bufpos = bufval.fval;
bufpos++;
}
return (0);
}
/** function to read entire grid buffer from disk ***/
int ReadGrid3dBuf(GridDesc* pgrid, FILE * fpio) {
long readsize;
// 20161021 AJL readsize = pgrid->numx * pgrid->numy * pgrid->numz * sizeof (GRID_FLOAT_TYPE);
readsize = pgrid->buffer_size;
/* read from grid file to buffer */
int ireturn;
if ((ireturn = fread((char *) pgrid->buffer, readsize, 1, fpio)) != 1) {
printf("DEBUG: pgrid->buffer %ld, readsize %ld, fpio %ld, ireturn %d\n", (long) pgrid->buffer, readsize, (long) fpio, ireturn);
nll_puterr2("ERROR: reading grid file", pgrid->title);
return (-1);
}
if (pgrid->iSwapBytes)
swapBytes(pgrid->buffer, readsize / sizeof (float));
return (0);
}
/** function to read y-z sheet of grid buffer from disk ***/
int ReadGrid3dBufSheet(GRID_FLOAT_TYPE* sheetbuf, GridDesc* pgrid_disk,
FILE* fpio, int ix) {
long offset;
long readsize;
/* check indexes in range */
if (ix < 0 || ix >= pgrid_disk->numx) {
sprintf(MsgStr,
"WARNING: grid file x-sheet index %d out of range (%d,%d)",
ix, 0, pgrid_disk->numx - 1);
return (-1);
}
/* calculate offset in bytes */
offset = sizeof (GRID_FLOAT_TYPE) * (ix * (pgrid_disk->numy * pgrid_disk->numz));
fseek(fpio, offset, SEEK_SET);
/* calculate number of bytes to read */
readsize = pgrid_disk->numy * pgrid_disk->numz * sizeof (GRID_FLOAT_TYPE);
/* read sheet from grid file to buffer */
if (fread((char *) sheetbuf, readsize, 1, fpio) != 1) {
nll_puterr("ERROR: reading x-sheet grid file.");
return (-1);
}
if (pgrid_disk->iSwapBytes)
swapBytes(sheetbuf, readsize / sizeof (GRID_FLOAT_TYPE));
return (0);
}
/** function to read grid header file ***/
int ReadGrid3dHdr(GridDesc* pgrid, SourceDesc* psrce, char* filename, char* file_type) {
FILE *fpio;
char fname[FILENAME_MAX];
/* read header file */
sprintf(fname, "%s.%s.hdr", filename, file_type);
if ((fpio = fopen(fname, "r")) == NULL) {
if (message_flag >= 1)
nll_puterr2("ERROR: opening grid header file: %s", fname);
return (-1);
}
NumFilesOpen++;
if (ReadGrid3dHdr_grid_description(fpio, pgrid, fname) < 0) {
fclose(fpio);
NumFilesOpen--;
return (-1);
}
if (strncmp(file_type, "time", 4) == 0
|| strncmp(file_type, "angle", 4) == 0)
fscanf(fpio, "%s %lf %lf %lf\n",
psrce->label, &(psrce->x), &(psrce->y), &(psrce->z));
// check for optional header lines
char line[MAXLINE_LONG];
char tag[MAXLINE_LONG];
// check for map projection
strcpy(pgrid->mapProjStr, "");
rewind(fpio);
while (fgets(line, MAXLINE_LONG, fpio) != NULL) {
int istat = sscanf(line, "%s", tag);
if (istat == 1 && strcmp(tag, "TRANSFORM") == 0) {
strcpy(pgrid->mapProjStr, line);
}
}
// check if cascading grid
pgrid->flagGridCascading = IS_NOT_CASCADING;
int num_z_merge_depths;
rewind(fpio);
while (fgets(line, MAXLINE_LONG, fpio) != NULL) {
int istat = sscanf(line, "%s %d", tag, &num_z_merge_depths);
if (istat == 2 && strcmp(tag, "CASCADING_GRID") == 0) {
setCascadingGrid(pgrid);
pgrid->gridDesc_Cascading.num_z_merge_depths = num_z_merge_depths;
if (pgrid->gridDesc_Cascading.num_z_merge_depths > MAX_NUM_Z_MERGE_DEPTHS) {
pgrid->gridDesc_Cascading.num_z_merge_depths = MAX_NUM_Z_MERGE_DEPTHS;
sprintf(MsgStr, "ERROR: too many cascading grid Z merge depths, only using first %d depths.",
pgrid->gridDesc_Cascading.num_z_merge_depths);
nll_puterr(MsgStr);
}
// 20170207 AJL - z_merge_depths moved to fixed array to ease memory management
//pgrid->gridDesc_Cascading.z_merge_depths = (double*) malloc((size_t) num_z_merge_depths * sizeof (double));
char doubling_depths[1024];
sscanf(line, "%*s %*d %s", doubling_depths);
char *str_pos = strtok(doubling_depths, ",");
int n = 0;
while (str_pos != NULL) {
pgrid->gridDesc_Cascading.z_merge_depths[n] = atof(str_pos);
//printf("DEBUG: CASCADING_GRID doubling depth added: %s %f\n", str_pos, pgrid->gridDesc_Cascading.z_merge_depths[n]);
n++;
str_pos = strtok(NULL, ",");
}
}
}
fclose(fpio);
NumFilesOpen--;
return (0);
}
/** function to read grid header file grid description line ***/
int ReadGrid3dHdr_grid_description(FILE *fpio, GridDesc *pgrid, char *fname) {
char line[MAXLINE_LONG];
if (fgets(line, MAXLINE_LONG, fpio) == NULL) {
nll_puterr2("ERROR: reading grid header file: ", fname);
return (-1);
}
strcpy(pgrid->float_type, "FLOAT");
sscanf(line, "%d %d %d %lf %lf %lf %lf %lf %lf %s %s",
&(pgrid->numx), &(pgrid->numy), &(pgrid->numz),
&(pgrid->origx), &(pgrid->origy), &(pgrid->origz),
&(pgrid->dx), &(pgrid->dy), &(pgrid->dz), pgrid->chr_type, pgrid->float_type);
#ifdef GRID_FLOAT_TYPE_DOUBLE
if (strcmp(pgrid->float_type, "DOUBLE") != 0) {
nll_puterr("ERROR: Global grid float type is set to DOUBLE, but grid file type is not DOUBLE. (see compiler flag GRID_FLOAT_TYPE_DOUBLE)");
return (-1);
}
#else
if (strcmp(pgrid->float_type, "FLOAT") != 0) {
nll_puterr("ERROR: Global grid float type is set to FLOAT, but grid file type is not FLOAT. (see compiler flag GRID_FLOAT_TYPE_DOUBLE)");
return (-1);
}
#endif
return (0);
}
/** function to open grid file and read header ***/
int OpenGrid3dFile(char *fname, FILE **fp_grid, FILE **fp_hdr,
GridDesc* pgrid, char* file_type, SourceDesc* psrce, int iSwapBytes) {
char fn_grid[FILENAME_MAX], fn_hdr[FILENAME_MAX];
/* open grid file and header file */
sprintf(fn_grid, "%s.buf", fname);
if (message_flag >= 3) {
sprintf(MsgStr, "Opening Grid File: %s", fn_grid);
nll_putmsg(3, MsgStr);
}
if ((*fp_grid = fopen(fn_grid, "r")) == NULL) {
if (message_flag >= 3) {
sprintf(MsgStr, "WARNING: cannot open grid buffer file: %s", fn_grid);
nll_putmsg(3, MsgStr);
}
//return(-1); // sometimes only header is wanted
} else {
NumGridBufFilesOpen++;
NumFilesOpen++;
}
sprintf(fn_hdr, "%s.hdr", fname);
if ((*fp_hdr = fopen(fn_hdr, "r")) == NULL) {
if (message_flag >= 3) {
sprintf(MsgStr,
"WARNING: cannot open grid header file: %s", fn_hdr);
nll_putmsg(3, MsgStr);
}
if (*fp_grid != NULL) {
fclose(*fp_grid);
NumGridBufFilesOpen--;
NumFilesOpen--;
}
return (-1);
}
NumGridHdrFilesOpen++;
NumFilesOpen++;
// initialize key fields
pgrid->array = NULL;
pgrid->buffer = NULL;
/* read header file */
pgrid->iSwapBytes = iSwapBytes;
if (ReadGrid3dHdr_grid_description(*fp_hdr, pgrid, fn_hdr) < 0) {
fclose(*fp_hdr);
NumGridBufFilesOpen--;
NumFilesOpen--;
if (*fp_grid != NULL) {
fclose(*fp_grid);
NumGridBufFilesOpen--;
NumFilesOpen--;
}
return (-1);
}
// make sure that dx for 2D grids is non-zero
if (pgrid->numx == 1)
pgrid->dx = 1.0;
convert_grid_type(pgrid, 1);
if (message_flag >= 4)
display_grid_param(pgrid);
if (psrce != NULL && (strncmp(file_type, "time", 4) == 0
|| strncmp(file_type, "angle", 4) == 0)) {
fscanf(*fp_hdr, "%s %lf %lf %lf\n",
psrce->label, &(psrce->x), &(psrce->y), &(psrce->z));
psrce->is_coord_xyz = 1;
}
// save filename as grid identifier
strcpy(pgrid->title, fname);
// check for optional header lines
char line[MAXLINE_LONG];
char tag[MAXLINE_LONG];
// check for map projection
strcpy(pgrid->mapProjStr, "");
rewind(*fp_hdr);
while (fgets(line, MAXLINE_LONG, *fp_hdr) != NULL) {
int istat = sscanf(line, "%s", tag);
if (istat == 1 && strcmp(tag, "TRANSFORM") == 0) {
strcpy(pgrid->mapProjStr, line);
}
}
// check if cascading grid
pgrid->flagGridCascading = IS_NOT_CASCADING;
int num_z_merge_depths;
rewind(*fp_hdr);
while (fgets(line, MAXLINE_LONG, *fp_hdr) != NULL) {
int istat = sscanf(line, "%s %d", tag, &num_z_merge_depths);
if (istat == 2 && strcmp(tag, "CASCADING_GRID") == 0) {
setCascadingGrid(pgrid);
pgrid->gridDesc_Cascading.num_z_merge_depths = num_z_merge_depths;
if (pgrid->gridDesc_Cascading.num_z_merge_depths > MAX_NUM_Z_MERGE_DEPTHS) {
pgrid->gridDesc_Cascading.num_z_merge_depths = MAX_NUM_Z_MERGE_DEPTHS;
sprintf(MsgStr, "ERROR: too many cascading grid Z merge depths, only using first %d depths.",
pgrid->gridDesc_Cascading.num_z_merge_depths);
nll_puterr(MsgStr);
}
// 20170207 AJL - z_merge_depths moved to fixed array to ease memory management
//pgrid->gridDesc_Cascading.z_merge_depths = (double*) malloc((size_t) num_z_merge_depths * sizeof (double));
char doubling_depths[1024];
sscanf(line, "%*s %*d %s", doubling_depths);
char *str_pos = strtok(doubling_depths, ",");
int n = 0;
while (str_pos != NULL) {
pgrid->gridDesc_Cascading.z_merge_depths[n] = atof(str_pos);
//printf("DEBUG: CASCADING_GRID doubling depth added: %s %f\n", str_pos, pgrid->gridDesc_Cascading.z_merge_depths[n]);
n++;
str_pos = strtok(NULL, ",");
}
}
}
return (0);
}
/** function to close grid file and header ***/
void CloseGrid3dFile(GridDesc* pgrid, FILE **fp_grid, FILE **fp_hdr) {
// 20170207 AJL - z_merge_depths moved to fixed array to ease memory management
/*if (pgrid != NULL) {
if (isCascadingGrid(pgrid)) {
if (pgrid->gridDesc_Cascading.z_merge_depths != NULL) {
free(pgrid->gridDesc_Cascading.z_merge_depths);
pgrid->gridDesc_Cascading.z_merge_depths = NULL;
NumAllocations--;
}
pgrid->gridDesc_Cascading.z_merge_depths = NULL;
}
}*/
if (*fp_grid != NULL) {
fclose(*fp_grid);
*fp_grid = NULL;
NumGridBufFilesOpen--;
NumFilesOpen--;
}
if (*fp_hdr != NULL) {
fclose(*fp_hdr);
*fp_hdr = NULL;
NumGridHdrFilesOpen--;
NumFilesOpen--;
}
}
/** function to read values from 2D or 3D grid file
*
* The required grids must be present as *.buf and *.hyp disk files.
*/
GRID_FLOAT_TYPE * ReadGridFile
(
// calling parameters
GRID_FLOAT_TYPE* values, // GRID_FLOAT_TYPE array to return grid values, must be of size nvalues or larger
char *fname, // grid file path and root name
char* file_type, // grid file type (e.g. "mod", "time" or "angle")
double* xloc, double* yloc, double* zloc, // arrays of x, y, z coordinates in grid units of target point, arrays must be of size nvalues or larger
int nvalues, // number of values to read
int iSwapBytes, // flag to indicate if hi and low bytes of input velocity grid file should be swapped (1=swap, 0=no swap)
SourceDesc* psrceIn // station source to use instead of srce in grid file (use only for station=DEFAULT 2D grids, use NULL otherwise)
) {
int istat, i;
FILE *fp_grid, *fp_hdr;
GridDesc gdesc;
SourceDesc srce;
SourceDesc* psrce_use;
double yval_grid;
// initialize values to invalid
for (i = 0; i < nvalues; i++)
values[i] = -VERY_LARGE_FLOAT;
// open grid file
if ((istat = OpenGrid3dFile(fname, &fp_grid, &fp_hdr, &gdesc, file_type, &srce, iSwapBytes)) < 0) {
if (message_flag >= 3) {
sprintf(MsgStr, "WARNING: cannot open grid file: %s", fname);
nll_putmsg(3, MsgStr);
}
return (values);
}
if (gdesc.type == GRID_TIME_2D || gdesc.type == GRID_ANGLE_2D) {
// 2D grid (1D model)
psrce_use = &srce;
if (psrceIn != NULL) {
psrce_use = psrceIn;
}
// printf("DEBUG: SOURCE: Name: %s Loc: latlon: %d X(east) %lg Y(north) %lg Z(pos DOWN) %lg lat %lg lon %lg\n",
// psrce_use->label, psrce_use->is_coord_latlon,
// psrce_use->x, psrce_use->y, psrce_use->z,
// psrce_use->dlat, psrce_use->dlong
// );
for (i = 0; i < nvalues; i++) {
yval_grid = GetEpiDist(psrce_use, xloc[i], yloc[i]);
if (GeometryMode == MODE_GLOBAL)
yval_grid *= KM2DEG;
values[i] = ReadAbsInterpGrid2d(fp_grid, &gdesc, yval_grid, zloc[i]);
// printf("DEBUG: yval_grid=%f xloc[i]=%f yloc[i]=%f zloc[i]=%f values[i]=%f\n", yval_grid, xloc[i], yloc[i], zloc[i], values[i]);
}
} else {
// 3D grid
for (i = 0; i < nvalues; i++) {
// get GRID_FLOAT_TYPE value on grid
values[i] = ReadAbsInterpGrid3d(fp_grid, &gdesc, xloc[i], yloc[i], zloc[i], 0);
}
}
// close grid file
CloseGrid3dFile(&gdesc, &fp_grid, &fp_hdr);
return (values);
}
/** function to read cascading grid data from disk or array at index location
*
* 20161019 AJL - added
*
* ix_casc, iy_casc, iz_casc are indices in cascading grid index units
*/
GRID_FLOAT_TYPE ReadCascadingGrid3dValue(FILE *fpgrid, int ix_casc, int iy_casc, int iz_casc, GridDesc * pgrid) {
long offset;
GRID_FLOAT_TYPE fvalue;
// get fvalue
if (fpgrid != NULL) {
// calculate offset in bytes from array offset
offset = ((GRID_FLOAT_TYPE **) pgrid->array[ix_casc][iy_casc] + (long) iz_casc) - (GRID_FLOAT_TYPE **) pgrid->array[0][0];
offset *= sizeof (GRID_FLOAT_TYPE);
//offset *= 2;
//if (ix_casc < 4 && iy_casc < 4 && iz_casc < 4)
// printf("ixyz %d,%d,%d ixyz_casc %d,%d,%d offset %ld/%ld = (GRID_FLOAT_TYPE **) pgrid->array[ix_casc][iy_casc] %ld + iz_casc %d - (GRID_FLOAT_TYPE **) pgrid->array[0][0] %ld\n",
// ix, iy, iz, ix_casc, iy_casc, iz_casc, offset, offset * sizeof (GRID_FLOAT_TYPE), (GRID_FLOAT_TYPE **) pgrid->array[ix_casc][iy_casc], iz_casc, (GRID_FLOAT_TYPE **) pgrid->array[0][0]);
fseek(fpgrid, offset, SEEK_SET);
// read fvalue
if (fread(&fvalue, sizeof (GRID_FLOAT_TYPE), 1, fpgrid) != 1) {
sprintf(MsgStr, "ERROR: reading cascading grid value at: x%d y%d z%d (offset %ld buf_size %ld diff %ld) in: %s",
ix_casc, iy_casc, iz_casc, offset, pgrid->buffer_size, offset - pgrid->buffer_size, pgrid->title);
nll_puterr(MsgStr);
return (-VERY_LARGE_FLOAT);
}
if (pgrid->iSwapBytes)
swapBytes(&fvalue, 1);
} else {
fvalue = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix_casc][iy_casc][iz_casc];
}
return (fvalue);
}
/** function to read cascading grid data from disk or array at interpolated point corresponding to regular grid index location
*
* 20161021 AJL - added
*
* ix_dbl, iy_dbl, iz_dbl are indices in virtual, regular grid equivalent to this cascading grid
*/
GRID_FLOAT_TYPE ReadGrid3dValue_Cascading_Interp(FILE *fpgrid, double ix_dbl, double iy_dbl, double iz_dbl, GridDesc * pgrid, int clean_casc_allocs) {
int ix = (int) ix_dbl;
int iy = (int) iy_dbl;
int iz = (int) iz_dbl;
// check indexes in range
// ix, iy, iz are indices in virtual, regular grid equivalent to this cascading grid
if (ix < 0 || ix >= pgrid->numx || iy < 0 || iy >= pgrid->numy || iz < 0 || iz >= pgrid->numz) {
//nll_puterr("WARNING: grid file index out of range.");
return (-VERY_LARGE_FLOAT);
}
// need grid array to find offset
int created_grid_array_cascading = 0;
int allocated_grid_cascading = 0;
if (pgrid->array == NULL) {
if (pgrid->buffer == NULL) {
// prepare grid memory without allocating buffer, required to initialize cascading grid array
AllocateGrid_Cascading(pgrid, 0);
allocated_grid_cascading = 1;
}
pgrid->array = CreateGridArray_Cascading(pgrid);
created_grid_array_cascading = 1;
}
int xyz_scale = pgrid->gridDesc_Cascading.xyz_scale[iz];
// set upper x,y,z indices in cascading grid
int iz0_casc = pgrid->gridDesc_Cascading.zindex[iz];
int ix0_casc = ix / xyz_scale;
int iy0_casc = iy / xyz_scale;
// interpolate within cascading grid cell
// check if at change in grid cell size, gets complicated...
int xy_scale_use = xyz_scale;
int ix0_casc_up, iy0_casc_up, ix0_casc_dn, iy0_casc_dn;
int ix1_casc_up, iy1_casc_up, ix1_casc_dn, iy1_casc_dn;
int iz1_casc;
int irescale = 0;
if (iz < pgrid->numz - 2) {
// find first regular z index in next cascading grid level
int iz_test = iz + 1;
// 20170207 AJL while (iz_test < pgrid->numz && pgrid->gridDesc_Cascading.zindex[iz_test] == iz0_casc) {
while (iz_test < pgrid->numz - 1 && pgrid->gridDesc_Cascading.zindex[iz_test] == iz0_casc) {
iz_test++;
}
// check if scale changes in next cascading grid level
irescale = pgrid->gridDesc_Cascading.xyz_scale[iz_test] > xyz_scale;
}
if (irescale) { // change of grid size
//printf("DEBUG: rescale! iz %d scale %d, iz+1 %d, scale %d\n",iz, xyz_scale, iz + 1, pgrid->gridDesc_Cascading.xyz_scale[iz + 1]);
xy_scale_use = 2 * xyz_scale;
// set upper and lower x,y indices in cascading grid
// x
// make sure upper values are at even index, align with cell below
ix0_casc_up = 2 * (ix0_casc / 2);
// upper index increases by 2
ix1_casc_up = ix0_casc_up + 2;
int ixmax = (pgrid->numx - 1) / xyz_scale + ((pgrid->numx - 1) % xyz_scale == 0 ? 0 : 1); // includes fractional final casc grid node if xyz_scale != 1
if (ix1_casc_up > ixmax) {
ix1_casc_up = ixmax;
}
// lower index in larger cell size increases by 1
ix0_casc_dn = ix0_casc_up / 2;
ix1_casc_dn = ix0_casc_dn + 1;
ixmax = (pgrid->numx - 1) / xy_scale_use + ((pgrid->numx - 1) % xy_scale_use == 0 ? 0 : 1); // includes fractional final casc grid node if xyz_scale != 1
if (ix1_casc_dn > ixmax) {
ix1_casc_dn = ixmax;
}
// y
// make sure upper values are at even index, align with cell below
iy0_casc_up = 2 * (iy0_casc / 2);
// upper index increases by 2
iy1_casc_up = iy0_casc_up + 2;
int iymax = (pgrid->numy - 1) / xyz_scale + ((pgrid->numy - 1) % xyz_scale == 0 ? 0 : 1); // includes fractional final casc grid node if xyz_scale != 1
if (iy1_casc_up > iymax) {
iy1_casc_up = iymax;
}
// lower index in larger cell size increases by 1
iy0_casc_dn = iy0_casc_up / 2;
iy1_casc_dn = iy0_casc_dn + 1;
iymax = (pgrid->numy - 1) / xy_scale_use + ((pgrid->numy - 1) % xy_scale_use == 0 ? 0 : 1); // includes fractional final casc grid node if xyz_scale != 1
if (iy1_casc_dn > iymax) {
iy1_casc_dn = iymax;
}
} else {
// set upper and lower x,y indices in cascading grid
// x
ix0_casc_up = ix0_casc_dn = ix0_casc;
ix1_casc_up = ix0_casc + 1;
if (ix1_casc_up >= pgrid->numx) {
ix1_casc_up = pgrid->numx - 1;
}
ix1_casc_dn = ix1_casc_up;
// y
iy0_casc_up = iy0_casc_dn = iy0_casc;
iy1_casc_up = iy0_casc + 1;
if (iy1_casc_up >= pgrid->numy) {
iy1_casc_up = pgrid->numy - 1;
}
iy1_casc_dn = iy1_casc_up;
}
iz1_casc = iz0_casc + 1;
if (iz1_casc > pgrid->gridDesc_Cascading.zindex[pgrid->numz - 1]) {
iz1_casc = pgrid->gridDesc_Cascading.zindex[pgrid->numz - 1];
}
DOUBLE xdiff, ydiff, zdiff;
// x
int lastx = ((pgrid->numx - 1) / xy_scale_use) * xy_scale_use; // reg index of end of last full casc grid cell
if (ix > lastx) { // casc grid cell is truncated in x relative to cell of size xy_scale_use reg grid cells
xdiff = (ix_dbl - (DOUBLE) lastx) / (DOUBLE) (pgrid->numx - 1 - lastx);
if (ix0_casc_up != ix0_casc_dn && iy == 133) {
printf("xy_scale_use %d, xdiff %f = (DOUBLE) (ix %d - lastx %d) / (DOUBLE) (pgrid->numx %d - 1 - lastx %d)\n", xy_scale_use, xdiff, ix, lastx, pgrid->numx, lastx);
printf("ix0_casc_up/dn %d/%d, ix1_casc_up/dn %d/%d, iz0_casc %d, iz1_casc %d\n", ix0_casc_up, ix0_casc_dn, ix1_casc_up, ix1_casc_dn, iz0_casc, iz1_casc);
printf("iy0_casc_up %d, iy0_casc_dn %d, iy1_casc_up %d, iy1_casc_dn %d, iz0_casc %d, iz1_casc %d\n", iy0_casc_up, iy0_casc_dn, iy1_casc_up, iy1_casc_dn, iz0_casc, iz1_casc);
}
} else {
//xdiff = (DOUBLE) (ix % xy_scale_use) / (DOUBLE) xy_scale_use;
xdiff = fmod(ix_dbl, (DOUBLE) xy_scale_use) / (DOUBLE) xy_scale_use;
}
// y
int lasty = ((pgrid->numy - 1) / xy_scale_use) * xy_scale_use; // reg index of end of last full casc grid cell
if (iy > lasty) { // casc grid cell is truncated in y relative to cell of size xy_scale_use reg grid cells
ydiff = (iy_dbl - (DOUBLE) lasty) / (DOUBLE) (pgrid->numy - 1 - lasty);
//printf("xy_scale_use %d, ydiff %f = (DOUBLE) (iy %d - lasty %d) / (DOUBLE) (pgrid->numy %d - 1 - lasty %d)\n", xy_scale_use, ydiff, iy, lasty, pgrid->numy, lasty);
} else {
//ydiff = (DOUBLE) (iy % xy_scale_use) / (DOUBLE) xy_scale_use;
ydiff = fmod(iy_dbl, (DOUBLE) xy_scale_use) / (DOUBLE) xy_scale_use;
}
//xdiff = (DOUBLE) (ix % xy_scale_use) / (DOUBLE) xy_scale_use;
//ydiff = (DOUBLE) (iy % xy_scale_use) / (DOUBLE) xy_scale_use;
// find regular grid z steps to reach upper limit
int iz_test = iz;
while (iz_test > 0 && pgrid->gridDesc_Cascading.zindex[iz_test - 1] == iz0_casc) {
iz_test--;
}
// 20161026 zdiff = (DOUBLE) (iz - iz_test) / (DOUBLE) xy_scale_use;
zdiff = (iz_dbl - (DOUBLE) iz_test) / (DOUBLE) xyz_scale;
GRID_FLOAT_TYPE value;
if (xdiff < 0.0 || xdiff > 1.0) {
value = -VERY_LARGE_FLOAT;
goto cleanup;
}
if (ydiff < 0.0 || ydiff > 1.0) {
value = -VERY_LARGE_FLOAT;
goto cleanup;
}
if (zdiff < 0.0 || zdiff > 1.0) {
value = -VERY_LARGE_FLOAT;
goto cleanup;
}
// location at grid node
/*if (xdiff + ydiff + zdiff < SMALL_FLOAT) {
value = ReadCascadingGrid3dValue(fpgrid, ix0_casc, iy0_casc, iz0_casc, pgrid);
return (value);
}*/
DOUBLE vval000, vval001, vval010, vval011, vval100, vval101, vval110, vval111;
vval000 = ReadCascadingGrid3dValue(fpgrid, ix0_casc_up, iy0_casc_up, iz0_casc, pgrid);
vval001 = ReadCascadingGrid3dValue(fpgrid, ix0_casc_dn, iy0_casc_dn, iz1_casc, pgrid);
vval010 = ReadCascadingGrid3dValue(fpgrid, ix0_casc_up, iy1_casc_up, iz0_casc, pgrid);
vval011 = ReadCascadingGrid3dValue(fpgrid, ix0_casc_dn, iy1_casc_dn, iz1_casc, pgrid);
vval100 = ReadCascadingGrid3dValue(fpgrid, ix1_casc_up, iy0_casc_up, iz0_casc, pgrid);
vval101 = ReadCascadingGrid3dValue(fpgrid, ix1_casc_dn, iy0_casc_dn, iz1_casc, pgrid);
vval110 = ReadCascadingGrid3dValue(fpgrid, ix1_casc_up, iy1_casc_up, iz0_casc, pgrid);
vval111 = ReadCascadingGrid3dValue(fpgrid, ix1_casc_dn, iy1_casc_dn, iz1_casc, pgrid);
// check for invalid / mask nodes
// 20210803 AJL - Bug fix: only perform this test for grids that never have valid negative values!
if (pgrid->type != GRID_SSST_TIMECORR) {
if (vval000 < 0.0 || vval010 < 0.0 || vval100 < 0.0 || vval110 < 0.0
|| vval001 < 0.0 || vval011 < 0.0 || vval101 < 0.0 || vval111 < 0.0) {
value = -VERY_LARGE_FLOAT;
goto cleanup;
}
}
value = InterpCubeLagrange(xdiff, ydiff, zdiff,
vval000, vval001, vval010, vval011,
vval100, vval101, vval110, vval111);
cleanup:
// clean up
if (clean_casc_allocs) {
if (allocated_grid_cascading) {
FreeGrid_Cascading(pgrid);
}
if (created_grid_array_cascading) {
DestroyGridArray(pgrid);
}
}
return (value);
}
/** function to read cascading grid data from disk or array at upper xyz indices corresponding to regular grid index location
*
* 20161019 AJL - added
*
* ix, iy, iz are indices in virtual, regular grid equivalent to this cascading grid
*/
GRID_FLOAT_TYPE ReadGrid3dValue_Cascading(FILE *fpgrid, int ix, int iy, int iz, GridDesc * pgrid) {
// check indexes in range
// ix, iy, iz are indices in virtual, regular grid equivalent to this cascading grid
if (ix < 0 || ix >= pgrid->numx || iy < 0 || iy >= pgrid->numy || iz < 0 || iz >= pgrid->numz) {
//nll_puterr("WARNING: grid file index out of range.");
return (-VERY_LARGE_FLOAT);
}
// need grid array to find offset
if (pgrid->array == NULL) {
if (pgrid->buffer == NULL) {
// prepare grid memory without allocating buffer, required to initialize cascading grid array
AllocateGrid_Cascading(pgrid, 0);
}
pgrid->array = CreateGridArray_Cascading(pgrid);
}
// set x,y,z indices in cascading grid
int iz_casc = pgrid->gridDesc_Cascading.zindex[iz];
int ix_casc = ix / pgrid->gridDesc_Cascading.xyz_scale[iz];
int iy_casc = iy / pgrid->gridDesc_Cascading.xyz_scale[iz];
// get fvalue
GRID_FLOAT_TYPE fvalue = ReadCascadingGrid3dValue(fpgrid, ix_casc, iy_casc, iz_casc, pgrid);
return (fvalue);
}
/** function to read grid data from disk or array at index location ***/
GRID_FLOAT_TYPE ReadGrid3dValue(FILE *fpgrid, int ix, int iy, int iz, GridDesc * pgrid, int clean_casc_allocs) {
if (isCascadingGrid(pgrid)) {
//return (ReadGrid3dValue_Cascading(fpgrid, ix, iy, iz, pgrid));
return (ReadGrid3dValue_Cascading_Interp(fpgrid, (double) ix, (double) iy, (double) iz, pgrid, clean_casc_allocs));
}
int numyz;
long offset;
GRID_FLOAT_TYPE fvalue;
/* check indexes in range */
if (ix < 0 || ix >= pgrid->numx || iy < 0 || iy >= pgrid->numy
|| iz < 0 || iz >= pgrid->numz) {
//nll_puterr("WARNING: grid file index out of range.");
return (-VERY_LARGE_FLOAT);
}
/* get fvalue */
if (fpgrid != NULL) {
/* calculate offset in bytes */
numyz = pgrid->numy * pgrid->numz;
offset = sizeof (GRID_FLOAT_TYPE) * (ix * numyz + iy * pgrid->numz + iz);
fseek(fpgrid, offset, SEEK_SET);
/* read fvalue */
if (fread(&fvalue, sizeof (GRID_FLOAT_TYPE), 1, fpgrid) != 1) {
sprintf(MsgStr,
"ERROR: reading grid value: %s: ix%d iy=%d iz=%d", pgrid->title, ix, iy, iz);
nll_puterr(MsgStr);
return (-VERY_LARGE_FLOAT);
}
if (pgrid->iSwapBytes)
swapBytes(&fvalue, 1);
} else {
fvalue = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz];
}
return (fvalue);
}
/** function to read grid data from disk or array at absolute location ***/
GRID_FLOAT_TYPE ReadAbsGrid3dValue(FILE *fpgrid, GridDesc* pgrid,
double xloc, double yloc, double zloc, int ifloor) {
int ix, iy, iz;
GRID_FLOAT_TYPE fvalue;
double shift;
if (ifloor)
shift = 0.0;
else
shift = 0.5;
/* calculate nearest grid location */
ix = (int) (shift + (xloc - pgrid->origx) / pgrid->dx);
iy = (int) (shift + (yloc - pgrid->origy) / pgrid->dy);
iz = (int) (shift + (zloc - pgrid->origz) / pgrid->dz);
/* read grid data */
fvalue = ReadGrid3dValue(fpgrid, ix, iy, iz, pgrid, 0);
return (fvalue);
}
/** function to find value inside a cube using Lagrange interpolation***/
/* 0.0 <= vvalKLM <= 1.0 */
/* returns interp value at (xdiff, ydiff, zdiff) */
DOUBLE InterpCubeLagrange(DOUBLE xdiff, DOUBLE ydiff, DOUBLE zdiff,
DOUBLE vval000, DOUBLE vval001, DOUBLE vval010, DOUBLE vval011,
DOUBLE vval100, DOUBLE vval101, DOUBLE vval110, DOUBLE vval111) {
DOUBLE value;
DOUBLE oneMinusXdiff;
DOUBLE oneMinusYdiff;
DOUBLE oneMinusZdiff;
oneMinusXdiff = 1.0 - xdiff;
oneMinusYdiff = 1.0 - ydiff;
oneMinusZdiff = 1.0 - zdiff;
/*value = vval000 * (oneMinusXdiff) * oneMinusYdiff * (oneMinusZdiff)
+ vval001 * (oneMinusXdiff) * (oneMinusYdiff) * zdiff
+ vval010 * (oneMinusXdiff) * ydiff * (oneMinusZdiff)
+ vval011 * (oneMinusXdiff) * ydiff * zdiff
+ vval100 * xdiff * (oneMinusYdiff) * (oneMinusZdiff)
+ vval101 * xdiff * (oneMinusYdiff) * zdiff
+ vval110 * xdiff * ydiff * (oneMinusZdiff)
+ vval111 * xdiff * ydiff * zdiff;*/
value = oneMinusXdiff * (
oneMinusYdiff * (vval000 * oneMinusZdiff + vval001 * zdiff)
+ ydiff * (vval010 * oneMinusZdiff + vval011 * zdiff)
)
+ xdiff * (
oneMinusYdiff * (vval100 * oneMinusZdiff + vval101 * zdiff)
+ ydiff * (vval110 * oneMinusZdiff + vval111 * zdiff)
);
return (value);
}
/** function to find angles inside a cube */
float InterpCubeAngles(DOUBLE xdiff, DOUBLE ydiff, DOUBLE zdiff,
DOUBLE vval000, DOUBLE vval001, DOUBLE vval010, DOUBLE vval011,
DOUBLE vval100, DOUBLE vval101, DOUBLE vval110, DOUBLE vval111) {
int nx, ny, nz;
double azim[2][2][2], dip[2][2][2], azim_interp, dip_interp;
int iqual[2][2][2], iqual_low;
float value;
TakeOffAngles angles;
double azim_ref, azim_test;
/* decode angles on vertices of cube */
SetAnglesFloat(&angles, vval000);
iqual[0][0][0] = GetTakeOffAngles(&angles,
&(azim[0][0][0]), &(dip[0][0][0]), &(iqual[0][0][0]));
SetAnglesFloat(&angles, vval001);
iqual[0][0][1] = GetTakeOffAngles(&angles,
&(azim[0][0][1]), &(dip[0][0][1]), &(iqual[0][0][1]));
SetAnglesFloat(&angles, vval010);
iqual[0][1][0] = GetTakeOffAngles(&angles,
&(azim[0][1][0]), &(dip[0][1][0]), &(iqual[0][1][0]));
SetAnglesFloat(&angles, vval011);
iqual[0][1][1] = GetTakeOffAngles(&angles,
&(azim[0][1][1]), &(dip[0][1][1]), &(iqual[0][1][1]));
SetAnglesFloat(&angles, vval100);
iqual[1][0][0] = GetTakeOffAngles(&angles,
&(azim[1][0][0]), &(dip[1][0][0]), &(iqual[1][0][0]));
SetAnglesFloat(&angles, vval101);
iqual[1][0][1] = GetTakeOffAngles(&angles,
&(azim[1][0][1]), &(dip[1][0][1]), &(iqual[1][0][1]));
SetAnglesFloat(&angles, vval110);
iqual[1][1][0] = GetTakeOffAngles(&angles,
&(azim[1][1][0]), &(dip[1][1][0]), &(iqual[1][1][0]));
SetAnglesFloat(&angles, vval111);
iqual[1][1][1] = GetTakeOffAngles(&angles,
&(azim[1][1][1]), &(dip[1][1][1]), &(iqual[1][1][1]));
// check for lowest quality angles
// 20130823 AJL - bug fix:
// correct azimuths to avoid discontinuity at 0/360 deg
iqual_low = 999;
azim_ref = azim[0][0][0];
for (nx = 0; nx < 2; nx++) {
for (ny = 0; ny < 2; ny++) {
for (nz = 0; nz < 2; nz++) {
//printf("%d %d %d az %f dip %f q %d\n", nx, ny, nz, azim[nx][ny][nz], dip[nx][ny][nz], iqual[nx][ny][nz]);
if (iqual[nx][ny][nz] < iqual_low)
iqual_low = iqual[nx][ny][nz];
azim_test = azim[nx][ny][nz] - azim_ref;
if (azim_test < -90.0) {
azim[nx][ny][nz] += 360.0;
} else if (azim_test > 90.0) {
azim[nx][ny][nz] -= 360.0;
}
}
}
}
/* determine angles to return */
if (iqual_low < ANGLE_QUALITY_CUTOFF) {
/* if lowest quality is too low, use nearest node */
value = vval000;
} else {
/* otherwise interpolate */
azim_interp = InterpCubeLagrange(xdiff, ydiff, zdiff,
azim[0][0][0], azim[0][0][1], azim[0][1][0],
azim[0][1][1], azim[1][0][0], azim[1][0][1],
azim[1][1][0], azim[1][1][1]);
// 20130823 AJL - bug fix:
if (azim_interp < 0.0) {
azim_interp += 360.0;
} else if (azim_interp > 360.0) {
azim_interp -= 360.0;
}
dip_interp = InterpCubeLagrange(xdiff, ydiff, zdiff,
dip[0][0][0], dip[0][0][1], dip[0][1][0],
dip[0][1][1], dip[1][0][0], dip[1][0][1],
dip[1][1][0], dip[1][1][1]);
angles = SetTakeOffAngles(azim_interp, dip_interp, iqual_low);
value = angles.fval;
}
return (value);
}
/** function to read grid data from disk or buffer at absolute location
with interpolation ***/
/* read from file if fpgrid != NULL, otherwise read from grid buffer */
GRID_FLOAT_TYPE ReadAbsInterpGrid3d(FILE *fpgrid, GridDesc* pgrid, double xloc, double yloc, double zloc, int clean_casc_allocs) {
DOUBLE xoff, yoff, zoff;
xoff = (xloc - pgrid->origx) / pgrid->dx;
yoff = (yloc - pgrid->origy) / pgrid->dy;
zoff = (zloc - pgrid->origz) / pgrid->dz;
// check if cascading grid
if (isCascadingGrid(pgrid)) {
return (ReadGrid3dValue_Cascading_Interp(fpgrid, xoff, yoff, zoff, pgrid, clean_casc_allocs));
}
int ix0, ix1, iy0, iy1, iz0, iz1;
GRID_FLOAT_TYPE value;
DOUBLE vval000, vval001, vval010, vval011, vval100, vval101, vval110, vval111;
DOUBLE xdiff, ydiff, zdiff;
int numx, numy, numz, numyz;
GRID_FLOAT_TYPE *buffer;
buffer = (GRID_FLOAT_TYPE *) pgrid->buffer;
numx = pgrid->numx;
numy = pgrid->numy;
numz = pgrid->numz;
numyz = numy * numz;
/* calculate grid locations on edge of solid containing point */
ix0 = (int) (xoff - VERY_SMALL_DOUBLE);
iy0 = (int) (yoff - VERY_SMALL_DOUBLE);
iz0 = (int) (zoff - VERY_SMALL_DOUBLE);
ix1 = (ix0 < numx - 1) ? ix0 + 1 : ix0;
iy1 = (iy0 < numy - 1) ? iy0 + 1 : iy0;
iz1 = (iz0 < numz - 1) ? iz0 + 1 : iz0;
/* if (ix1 < 0 || ix1 >= numx) fprintf(stderr, "GRID INDEX ERROR: ix1 %d (%d-%d) xloc %lf ix0 %d ix1 %d\n", ix1, 0, numx, xloc, ix0, ix1);
if (iy1 < 0 || iy1 >= numy) fprintf(stderr, "GRID INDEX ERROR: iy1 %d (%d-%d) yloc %lf iy0 %d iy1 %d\n", iy1, 0, numy, yloc, iy0, iy1);
if (iz1 < 0 || iz1 >= numz) fprintf(stderr, "GRID INDEX ERROR: iz1 %d (%d-%d) zloc %lf iz0 %d iz1 %d\n", iz1, 0, numz, zloc, iz0, iz1);
if (ix0 < 0 || ix0 >= numx) fprintf(stderr, "GRID INDEX ERROR: ix0 %d (%d-%d) xloc %lf ix0 %d ix1 %d\n", ix0, 0, numx, xloc, ix0, ix1);
if (iy0 < 0 || iy0 >= numy) fprintf(stderr, "GRID INDEX ERROR: iy0 %d (%d-%d) yloc %lf iy0 %d iy1 %d\n", iy0, 0, numy, yloc, iy0, iy1);
if (iz0 < 0 || iz0 >= numz) fprintf(stderr, "GRID INDEX ERROR: iz0 %d (%d-%d) zloc %lf iz0 %d iz1 %d\n", iz0, 0, numz, zloc, iz0, iz1);
*/
/* if (ix1 < 0 || ix1 >= numx) ix1 = ix0;
if (iy1 < 0 || iy1 >= numy) iy1 = iy0;
if (iz1 < 0 || iz1 >= numz) iz1 = iz0;
if (ix0 < 0 || ix0 >= numx) ix0 = ix1;
if (iy0 < 0 || iy0 >= numy) iy0 = iy1;
if (iz0 < 0 || iz0 >= numz) iz0 = iz1;
*/
xdiff = xoff - (DOUBLE) ix0;
ydiff = yoff - (DOUBLE) iy0;
zdiff = zoff - (DOUBLE) iz0;
if (xdiff < 0.0 || xdiff > 1.0) {
//printf("DEBUG: xdiff < 0.0 || xdiff > 1.0: xloc %f yloc %f zloc %f\n", xloc, yloc, zloc);
return (-VERY_LARGE_FLOAT);
}
if (ydiff < 0.0 || ydiff > 1.0) {
//printf("DEBUG: ydiff < 0.0 || ydiff > 1.0: xloc %f yloc %f zloc %f\n", xloc, yloc, zloc);
return (-VERY_LARGE_FLOAT);
}
if (zdiff < 0.0 || zdiff > 1.0) {
//printf("DEBUG: zdiff < 0.0 || zdiff > 1.0: xloc %f yloc %f zloc %f\n", xloc, yloc, zloc);
return (-VERY_LARGE_FLOAT);
}
/* location at grid node */
if (xdiff + ydiff + zdiff < SMALL_FLOAT) {
if (fpgrid != NULL)
value = ReadGrid3dValue(fpgrid, ix0, iy0, iz0, pgrid, 0);
else
value = *(buffer + ix0 * numyz + iy0 * numz + iz0);
return (value);
}
/* read vertex values from grid file or array */
if (fpgrid != NULL) {
vval000 = ReadGrid3dValue(fpgrid, ix0, iy0, iz0, pgrid, 0);
vval001 = ReadGrid3dValue(fpgrid, ix0, iy0, iz1, pgrid, 0);
vval010 = ReadGrid3dValue(fpgrid, ix0, iy1, iz0, pgrid, 0);
vval011 = ReadGrid3dValue(fpgrid, ix0, iy1, iz1, pgrid, 0);
vval100 = ReadGrid3dValue(fpgrid, ix1, iy0, iz0, pgrid, 0);
vval101 = ReadGrid3dValue(fpgrid, ix1, iy0, iz1, pgrid, 0);
vval110 = ReadGrid3dValue(fpgrid, ix1, iy1, iz0, pgrid, 0);
vval111 = ReadGrid3dValue(fpgrid, ix1, iy1, iz1, pgrid, 0);
} else {
/*
vval000 = pgrid->array[ix0][iy0][iz0];
vval001 = pgrid->array[ix0][iy0][iz1];
vval010 = pgrid->array[ix0][iy1][iz0];
vval011 = pgrid->array[ix0][iy1][iz1];
vval100 = pgrid->array[ix1][iy0][iz0];
vval101 = pgrid->array[ix1][iy0][iz1];
vval110 = pgrid->array[ix1][iy1][iz0];
vval111 = pgrid->array[ix1][iy1][iz1];
*/
vval000 = *(buffer + ix0 * numyz + iy0 * numz + iz0);
vval001 = *(buffer + ix0 * numyz + iy0 * numz + iz1);
vval010 = *(buffer + ix0 * numyz + iy1 * numz + iz0);
vval011 = *(buffer + ix0 * numyz + iy1 * numz + iz1);
vval100 = *(buffer + ix1 * numyz + iy0 * numz + iz0);
vval101 = *(buffer + ix1 * numyz + iy0 * numz + iz1);
vval110 = *(buffer + ix1 * numyz + iy1 * numz + iz0);
vval111 = *(buffer + ix1 * numyz + iy1 * numz + iz1);
}
/* interpolate values */
if (pgrid->type == GRID_ANGLE || pgrid->type == GRID_ANGLE_2D) {
value = InterpCubeAngles(xdiff, ydiff, zdiff,
vval000, vval001, vval010, vval011,
vval100, vval101, vval110, vval111);
} else {
// INGV
// check for invalid / mask nodes
// 20210803 AJL - Bug fix: only perform this test for grids that never have valid negative values!
if (pgrid->type != GRID_SSST_TIMECORR) {
if (vval000 < 0.0 || vval010 < 0.0 || vval100 < 0.0 || vval110 < 0.0
|| vval001 < 0.0 || vval011 < 0.0 || vval101 < 0.0 || vval111 < 0.0) {
//printf("DEBUG: vvalNNN < 0.0 vval000 %f vval001 %f vval010 %f vval011 %f vval100 %f vval101 %f vval110 %f vval111 %f\n", vval000, vval001, vval010, vval011, vval100, vval101, vval110, vval111);
return (-VERY_LARGE_FLOAT);
}
}
value = InterpCubeLagrange(xdiff, ydiff, zdiff,
vval000, vval001, vval010, vval011,
vval100, vval101, vval110, vval111);
}
return (value);
}
/** function to read grid data from disk or buffer at absolute location with interpolation ***/
/* 2D version - ix assumed = 0 */
/* read from file if fpgrid != NULL, otherwise read from grid buffer */
DOUBLE ReadAbsInterpGrid2d(FILE *fpgrid, GridDesc* pgrid, double yloc, double zloc) {
int ix0, iy0, iy1, iz0, iz1;
DOUBLE value;
DOUBLE vval00, vval01, vval10, vval11;
DOUBLE yoff, zoff;
DOUBLE ydiff, zdiff;
/* calculate grid locations on edge of solid containing point */
ix0 = 0;
yoff = (yloc - pgrid->origy) / pgrid->dy;
iy0 = (int) (yoff - VERY_SMALL_DOUBLE);
zoff = (zloc - pgrid->origz) / pgrid->dz;
iz0 = (int) (zoff - VERY_SMALL_DOUBLE);
iy1 = (iy0 < pgrid->numy - 1) ? iy0 + 1 : iy0;
iz1 = (iz0 < pgrid->numz - 1) ? iz0 + 1 : iz0;
ydiff = yoff - (DOUBLE) iy0;
zdiff = zoff - (DOUBLE) iz0;
// DEBUG
/*
printf("%d %d %d %lf %lf %lf %lf %lf %lf %s\n",
pgrid->numx, pgrid->numy, pgrid->numz,
pgrid->origx, pgrid->origy, pgrid->origz,
pgrid->dx, pgrid->dy, pgrid->dz, pgrid->chr_type);
if (iy0 < 0 || iy1 >= pgrid->numy )
printf("ERROR: ReadAbsInterpGrid2d: (iy0 < 0 || iy1 >= pgrid->numy )\n");
if (iz0 < 0 || iz1 >= pgrid->numz )
printf("ERROR: ReadAbsInterpGrid2d: (iz0 < 0 || iz1 >= pgrid->numz )\n");
if (ydiff < 0.0 || ydiff > 1.0)
printf("ERROR: ReadAbsInterpGrid2d: (ydiff < 0.0 || ydiff > 1.0 )\n");
if (zdiff < 0.0 || zdiff > 1.0)
printf("ERROR: ReadAbsInterpGrid2d: (zdiff < 0.0 || zdiff > 1.0 )\n");
*/
// End - DEBUG
//INGV
if (iy0 < 0 || iy1 >= pgrid->numy)
return (-VERY_LARGE_DOUBLE);
if (iz0 < 0 || iz1 >= pgrid->numz)
return (-VERY_LARGE_DOUBLE);
if (ydiff < 0.0 || ydiff > 1.0)
return (-VERY_LARGE_DOUBLE);
if (zdiff < 0.0 || zdiff > 1.0)
return (-VERY_LARGE_DOUBLE);
/* location at grid node */
if (ydiff + zdiff < SMALL_FLOAT) {
if (fpgrid != NULL)
value = ReadGrid3dValue(fpgrid, ix0, iy0, iz0, pgrid, 0);
else
value = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix0][iy0][iz0];
return (value);
}
/* read vertex values from grid file or array */
if (fpgrid != NULL) {
vval00 = ReadGrid3dValue(fpgrid, ix0, iy0, iz0, pgrid, 0);
vval01 = ReadGrid3dValue(fpgrid, ix0, iy0, iz1, pgrid, 0);
vval10 = ReadGrid3dValue(fpgrid, ix0, iy1, iz0, pgrid, 0);
vval11 = ReadGrid3dValue(fpgrid, ix0, iy1, iz1, pgrid, 0);
} else {
vval00 = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix0][iy0][iz0];
vval01 = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix0][iy0][iz1];
vval10 = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix0][iy1][iz0];
vval11 = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix0][iy1][iz1];
}
// DEBUG
/*
if (vval00 < 0.0 || vval01 < 0.0 || vval10 < 0.0 || vval11 < 0.0)
printf("ERROR: ReadAbsInterpGrid2d: (vval00 < 0.0 || vval01 < 0.0 || vval10 < 0.0 || vval11 < 0.0)\n");
*/
// End - DEBUG
// INGV
// check for invalid / mask nodes
// 20210803 AJL - Bug fix: only perform this test for grids that never have valid negative values!
if (pgrid->type != GRID_SSST_TIMECORR) {
if (vval00 < 0.0 || vval01 < 0.0 || vval10 < 0.0 || vval11 < 0.0)
return (-VERY_LARGE_DOUBLE);
}
/* interpolate values */
value = InterpSquareLagrange(ydiff, zdiff,
vval00, vval01, vval10, vval11);
return (value);
}
/** function to find value inside a square using Lagrange interpolation */
/* 0.0 <= vvalKLM <= 1.0 */
/* returns interp value at (xdiff, zdiff) */
DOUBLE InterpSquareLagrange(DOUBLE xdiff, DOUBLE zdiff,
DOUBLE vval00, DOUBLE vval01, DOUBLE vval10, DOUBLE vval11) {
DOUBLE value;
value = vval00 * (1.0 - xdiff) * (1.0 - zdiff)
+ vval01 * (1.0 - xdiff) * zdiff
+ vval10 * xdiff * (1.0 - zdiff)
+ vval11 * xdiff * zdiff;
return (value);
}
/** function to write hypocenter to output in CSV format */
// 20240826 AJL - added
void WriteLocationCSVheader(FILE *fpio) {
fprintf(fpio, "date-time, latitude, longitude, depth, RMS, Nphs, Gap, Dist, errH, errZ, Mamp, Mdur, expect_lat, expect_lon, expect_z, EllipsoidAz1, EllipsoidDip1, EllipsoidLen1, EllipsoidAz2, EllipsoidDip2, EllipsoidLen2, EllipsoidLen3, minHorUnc, maxHorUnc, azMaxHorUnc, pdfVolume, publicId\n");
}
/** function to write hypocenter to output in CSV format */
// 20240826 AJL - added
int WriteLocationCSV(FILE *fpio, HypoDesc* phypo, char* filename) {
int ifile = 0;
// write hypocenter to CSV file
// date-time, latitude, longitude, depth, RMS, Nphs, Gap, Dist, errH, errZ, Mamp, Mdur, expect_lat, expect_lon, expect_z, EllipsoidAz1, EllipsoidDip1, EllipsoidLen1, EllipsoidAz2, EllipsoidDip2, EllipsoidLen2, EllipsoidLen3, EllipseAz1, EllipseDip1, EllipseLen1, EllipseAz2, EllipseDip2, EllipseLen2, pdfVolume, publicId
if (fpio == NULL) {
if ((fpio = fopen(filename, "w")) == NULL) {
nll_puterr2("ERROR: opening hypocenter CSV output file", filename);
return (-1);
}
NumFilesOpen++;
ifile = 1;
WriteLocationCSVheader(fpio);
}
// origin time, lat, lon, depth
fprintf(fpio,
"%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%09.6f, %.4f, %.4f, %.4f",
phypo->year, phypo->month, phypo->day,
phypo->hour, phypo->min, (float) phypo->sec,
(float) phypo->dlat, (float) phypo->dlong, (float) phypo->depth);
// statistics
fprintf(fpio, ", %.6f", (float) phypo->rms);
fprintf(fpio, ", %d", phypo->nreadings);
fprintf(fpio, ", %.4f", (float) phypo->gap);
fprintf(fpio, ", %.4f", (float) phypo->dist);
fprintf(fpio, ", %.4f", (float) phypo->ellipse.len2);
double quality_errZ = sqrt(DELTA_CHI_SQR_68_2 * phypo->cov.zz);
fprintf(fpio, ", %.4f", (float) quality_errZ);
fprintf(fpio, ", %.4f", (float) phypo->amp_mag);
fprintf(fpio, ", %.4f", (float) phypo->dur_mag);
fprintf(fpio, ", %.4f, %.4f, %.4f", (float) phypo->expect_dlat, (float) phypo->expect_dlong, (float) phypo->expect.z);
// ellipsoid
fprintf(fpio, ", %.4f, %.4f, %.4f",
phypo->ellipsoid.az1, phypo->ellipsoid.dip1,
phypo->ellipsoid.len1);
fprintf(fpio, ", %.4f, %.4f, %.4f",
phypo->ellipsoid.az2, phypo->ellipsoid.dip2,
phypo->ellipsoid.len2);
fprintf(fpio, ", %.4f", phypo->ellipsoid.len3);
// ellipse
double azMaxHorUnc = phypo->ellipse.az1 + 90.0;
if (azMaxHorUnc >= 360.0)
azMaxHorUnc -= 360.0;
if (azMaxHorUnc >= 180.0)
azMaxHorUnc -= 180.0;
fprintf(fpio, ", %.4f, %.4f, %.4f", phypo->ellipse.len1, phypo->ellipse.len2, azMaxHorUnc);
fprintf(fpio, ", %.4f", (float) phypo->oct_tree_scatter_volume);
fprintf(fpio, ", %s", phypo->public_id);
fprintf(fpio, "\n");
if (ifile) {
fclose(fpio);
NumFilesOpen--;
}
return (0);
}
/** function to write hypocenter/arrivals to output */
int WriteLocation(FILE *fpio, HypoDesc* phypo, ArrivalDesc* parrivals,
int narrivals, char* filename,
int iWriteArrivals, int iWriteEndLoc, int iWriteMinimal,
GridDesc* pgrid, int n_proj) {
return (_WriteLocation(fpio, phypo, parrivals,
narrivals, filename,
iWriteArrivals, iWriteEndLoc, iWriteMinimal,
pgrid, n_proj, IO_ARRIVAL_ALL));
}
/** function to write arrivals to output */
int WritePhases(FILE *fpio, HypoDesc* phypo, ArrivalDesc* parrivals,
int narrivals, char* filename,
int iWriteArrivals, int iWriteEndLoc, int iWriteMinimal,
GridDesc* pgrid, int n_proj, int io_arrival_mode) {
return (_WriteLocation(fpio, phypo, parrivals,
narrivals, filename,
iWriteArrivals, iWriteEndLoc, iWriteMinimal,
pgrid, n_proj, io_arrival_mode));
}
/** function to write hypocenter/arrivals to output */
int _WriteLocation(FILE *fpio, HypoDesc* phypo, ArrivalDesc* parrivals,
int narrivals, char * filename,
int iWriteArrivals, int iWriteEndLoc, int iWriteMinimal,
GridDesc* pgrid, int n_proj, int io_arrival_mode) {
int ifile = 0, narr;
ArrivalDesc* parr;
/* write hypocenter to file */
if (fpio == NULL) {
if ((fpio = fopen(filename, "w")) == NULL) {
nll_puterr2("ERROR: opening hypocenter output file", filename);
return (-1);
}
NumFilesOpen++;
ifile = 1;
}
/* write hypocenter parameters */
if (iWriteMinimal) {
fprintf(fpio, "NLLOC \"%s\" \"%s\" \" \"\n",
phypo->fileroot, phypo->locStat);
fprintf(fpio, "PUBLIC_ID %s\n", phypo->public_id); // 20230428 AJL - added
} else {
fprintf(fpio, "NLLOC \"%s\" \"%s\" \"%s\"\n",
phypo->fileroot, phypo->locStat, phypo->locStatComm);
fprintf(fpio, "PUBLIC_ID %s\n", phypo->public_id); // 20190823 AJL - added
fprintf(fpio, "SIGNATURE \"%s\"\n", phypo->signature);
fprintf(fpio, "COMMENT \"%s\"\n", phypo->comment);
if (pgrid != NULL)
fprintf(fpio, "GRID %d %d %d %lg %lg %lg %lg %lg %lg %s\n",
pgrid->numx, pgrid->numy, pgrid->numz,
pgrid->origx, pgrid->origy, pgrid->origz,
pgrid->dx, pgrid->dy, pgrid->dz, pgrid->chr_type);
else
fprintf(fpio, "GRID %d %d %d %lg %lg %lg %lg %lg %lg %s\n",
-1, -1, -1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, "NULLGRID");
fprintf(fpio, "SEARCH %s\n", phypo->searchInfo);
fprintf(fpio,
"HYPOCENTER x %lg y %lg z %lg OT %lg ix %d iy %d iz %d %s\n",
phypo->x, phypo->y, phypo->z, (double) phypo->sec,
phypo->ix, phypo->iy, phypo->iz,
phypo->type // 20170811 AJL - added to allow saving of expectation hypocenter results instead of maximum likelihood
);
}
fprintf(fpio,
"GEOGRAPHIC OT %4.4d %2.2d %2.2d %2.2d %2.2d %lf Lat %lf Long %lf Depth %lf\n",
// 20151224 "GEOGRAPHIC OT %4.4d %2.2d %2.2d %2.2d %2.2d %f Lat %f Long %f Depth %lg\n",
//"GEOGRAPHIC OT %4.4d %2.2d %2.2d %2.2d %2.2d %lg Lat %lg Long %lg Depth %lg\n",
phypo->year, phypo->month, phypo->day,
phypo->hour, phypo->min, (double) phypo->sec,
phypo->dlat, phypo->dlong, phypo->depth);
fprintf(fpio,
"QUALITY Pmax %Lg MFmin %lg MFmax %lg RMS %lg Nphs %d Gap %lg Dist %lg Mamp %5.2lf %d Mdur %5.2lf %d\n",
phypo->probmax, phypo->misfit, phypo->grid_misfit_max,
phypo->rms, phypo->nreadings, phypo->gap,
GeometryMode == MODE_GLOBAL ? phypo->dist * KM2DEG : phypo->dist,
phypo->amp_mag, phypo->num_amp_mag,
phypo->dur_mag, phypo->num_dur_mag
);
fprintf(fpio,
"VPVSRATIO VpVsRatio %lg Npair %d Diff %lg\n",
phypo->VpVs, phypo->nVpVs, phypo->tsp_min_max_diff
);
if (!iWriteMinimal) {
fprintf(fpio,
// 20190903 AJL "STATISTICS ExpectX %lg Y %lg Z %lg",
"STATISTICS ExpectX %f Y %f Z %f", // increase precision, important for spherical (lat, lon) output
phypo->expect.x, phypo->expect.y, phypo->expect.z);
fprintf(fpio, " CovXX %lg XY %lg XZ %lg",
phypo->cov.xx, phypo->cov.xy, phypo->cov.xz);
fprintf(fpio, " YY %lg YZ %lg",
phypo->cov.yy, phypo->cov.yz);
fprintf(fpio, " ZZ %lg",
phypo->cov.zz);
fprintf(fpio, " EllAz1 %lg Dip1 %lg Len1 %lg",
phypo->ellipsoid.az1, phypo->ellipsoid.dip1,
phypo->ellipsoid.len1);
fprintf(fpio, " Az2 %lg Dip2 %lg Len2 %lg",
phypo->ellipsoid.az2, phypo->ellipsoid.dip2,
phypo->ellipsoid.len2);
fprintf(fpio, " Len3 %le\n", phypo->ellipsoid.len3);
fprintf(fpio,
"STAT_GEOG ExpectLat %lf Long %lf Depth %lf\n",
// 20151224 "STAT_GEOG ExpectLat %f Long %f Depth %f\n",
phypo->expect_dlat, phypo->expect_dlong, phypo->expect.z);
// 20170811 AJL - added to allow saving of expectation hypocenter results instead of maximum likelihood
if (strcmp(phypo->type, HYPO_TYPE_EXPECTATION) == 0) {
fprintf(fpio,
"MAXIMUM_LIKELIHOOD MaxLikeLat %lf Long %lf Depth %lf OT %lf\n",
phypo->max_like_dlat, phypo->max_like_dlong, phypo->max_like.z, (double) phypo->max_like_sec);
}
fprintf(fpio, "%s\n", MapProjStr[n_proj]);
// 20100519 AJL Added new hypo line
/*
int associatedPhaseCount; // - Number of associated phases, regardless of their use for origin computation.
// [->nreadings] int usedPhaseCount; // QML - Number of defining phases, i. e., phase observations that were actually used for computing
// the origin. Note that there may be more than one defining phase per station.
int associatedStationCount; // QML - Number of stations at which the event was observed.
int usedStationCount; // QML - Number of stations from which data was used for origin computation.
int depthPhaseCount; // QML - Number of depth phases (typically pP, sometimes sP) used in depth computation.
// [->rms] double standardError; // QML - RMS of the travel time residuals of the arrivals used for the origin computation. Unit: s
// [->gap] double azimuthalGap; // QML - Largest azimuthal gap in station distribution as seen from epicenter. Unit: deg
// [->gap_secondary] double secondaryAzimuthalGap; // QML - Secondary azimuthal gap in station distribution, i. e., the largest azimuthal gap a station closes. Unit: deg
char groundTruthLevel[8]; // QML - String describing ground-truth level, e. g. GT0, GT5, etc.
double minimumDistance; // QML - Epicentral distance of station closest to the epicenter. Unit: km
double maximumDistance; // QML - Epicentral distance of station farthest from the epicenter. Unit: km
double medianDistance; // QML - Median epicentral distance of used stations. Unit: km
*/
fprintf(fpio,
"QML_OriginQuality assocPhCt %d usedPhCt %d assocStaCt %d usedStaCt %d depthPhCt %d stdErr %lg azGap %lg secAzGap %lg",
phypo->associatedPhaseCount, phypo->nreadings, phypo->associatedStationCount, phypo->usedStationCount, phypo->depthPhaseCount,
phypo->rms, phypo->gap, phypo->gap_secondary
);
fprintf(fpio,
" gtLevel %s minDist %lg maxDist %lg medDist %lg\n",
phypo->groundTruthLevel, phypo->minimumDistance, phypo->maximumDistance, phypo->medianDistance
);
// 20100519 AJL Added new hypo line
/*
// QML fields added for compatibility with QuakeML OriginUncertainty attributes (AJL 201005)
// preferredDescription enum 0..1 – Element (OriginUncertaintyDescription)
double horizontalUncertainty; // QML - Circular confidence region, given by single value of horizontal uncertainty. Unit: km
double minHorizontalUncertainty; // QML - Semi-minor axis of confidence ellipse. Unit: km
double maxHorizontalUncertainty; // QML - Semi-major axis of confidence ellipse. Unit: km
double azimuthMaxHorizontalUncertainty; // QML - Azimuth of major axis of confidence ellipse. Unit: km
*/
double azMaxHorUnc = phypo->ellipse.az1 + 90.0;
if (azMaxHorUnc >= 360.0)
azMaxHorUnc -= 360.0;
if (azMaxHorUnc >= 180.0)
azMaxHorUnc -= 180.0;
fprintf(fpio,
"QML_OriginUncertainty horUnc %lg minHorUnc %lg maxHorUnc %lg azMaxHorUnc %lg\n",
-1.0, // 20100617 AJL - horizontalUncertainty: not clear what this is, set undefined
phypo->ellipse.len1, phypo->ellipse.len2, azMaxHorUnc
);
// 20150602 AJL Added new hypo line
/*
// QML fields added for compatibility with QuakeML ConfidenceEllipsoid attributes (AJL 201005)
semiMajorAxisLength Largest uncertainty, corresponding to the semi-major axis of the confidence ellipsoid. Unit: m
semiMinorAxisLength Smallest uncertainty, corresponding to the semi-minor axis of the confidence ellipsoid. Unit: m
semiIntermediateAxisLength Uncertainty in direction orthogonal to major and minor axes of the confidence ellipsoid. Unit: m
majorAxisPlunge Plunge angle of major axis of confidence ellipsoid. Corresponds to Tait-Bryan angle phi. Unit: deg
majorAxisAzimuth Azimuth angle of major axis of confidence ellipsoid. Corresponds to Tait-Bryan angle psi. Unit: deg
majorAxisRotation This angle describes a rotation about the confidence ellipsoid’s major axis which is required
to define the direction of the ellipsoid’s minor axis. Corresponds to Tait-Bryan angle θ. Unit: deg
*/
double semiMajorAxisLength;
double semiMinorAxisLength;
double semiIntermediateAxisLength;
double majorAxisAzimuth;
double majorAxisPlunge;
double majorAxisRotation;
if (nllEllipsiod2QMLConfidenceEllipsoid(
&(phypo->ellipsoid),
&semiMajorAxisLength, &semiMinorAxisLength, &semiIntermediateAxisLength,
&majorAxisAzimuth, &majorAxisPlunge, &majorAxisRotation) < 0) {
semiMajorAxisLength = -1.0;
semiMinorAxisLength = -1.0;
semiIntermediateAxisLength = -1.0;
majorAxisAzimuth = -1.0;
majorAxisPlunge = -1.0;
majorAxisRotation = -1.0;
}
fprintf(fpio,
"QML_ConfidenceEllipsoid semiMajorAxisLength %lg semiMinorAxisLength %lg semiIntermediateAxisLength %lg majorAxisPlunge %lg majorAxisAzimuth %lg majorAxisRotation %lg\n",
semiMajorAxisLength, semiMinorAxisLength, semiIntermediateAxisLength, majorAxisPlunge, majorAxisAzimuth, majorAxisRotation
);
// 20100617 AJL Added new hypo line
// SED-ETH fields added for compatibility with legacy SED location quality indicators (AJL 201006)
// SED_Origin errx 33.0775 erry 7.5298 errz 27.5298 diffMaxLikeExpect 4.9584 quality B
if (phypo->qualitySED != '\0') {
fprintf(fpio,
"SED_Origin errx %lg erry %lg errz %lg diffMaxLikeExpect %lg quality %c\n",
sqrt(phypo->cov.xx), sqrt(phypo->cov.yy), sqrt(phypo->cov.zz), phypo->diffMaxLikeExpect, phypo->qualitySED
);
}
/* write mechanism */
fprintf(fpio,
"FOCALMECH Hyp %f %f %f",
phypo->dlat, phypo->dlong, phypo->depth);
fprintf(fpio,
" Mech %lg %lg %lg",
phypo->focMech.dipDir, phypo->focMech.dipAng,
phypo->focMech.rake);
fprintf(fpio, " mf %lg nObs %d",
phypo->focMech.misfit, phypo->focMech.nObs);
fprintf(fpio, "\n");
/* write differential loc parameters */
if (nll_mode == MODE_DIFFERENTIAL
|| phypo->event_id >= 0) { // 20110620 AJL - preserve event id if available
fprintf(fpio,
"DIFFERENTIAL Nhyp %ld", phypo->event_id);
fprintf(fpio, "\n");
}
}
/* write arrival parameters */
/* !!! Remember to modify the sscanf in function GetHypLoc() when modifying this fprintf */
if (iWriteArrivals) {
fprintf(fpio,
"PHASE ID Ins Cmp On Pha FM Date HrMn Sec Err ErrMag Coda Amp Per");
if (PhaseFormat == FORMAT_PHASE_2)
fprintf(fpio,
" PriorWt");
if (io_arrival_mode == IO_ARRIVAL_ALL) {
fprintf(fpio,
" > TTpred Res Weight StaLoc(X Y Z) SDist SAzim RAz RDip RQual Tcorr ");
if (PhaseFormat == FORMAT_PHASE_2)
fprintf(fpio,
" TTerr");
}
fprintf(fpio, "\n");
for (narr = 0; narr < narrivals; narr++) {
parr = parrivals + narr;
if (nll_mode == MODE_DIFFERENTIAL) {
//printf("phypo->event_id %ld parr->dd_event_id_1 %ld parr->dd_event_id_2 %ld\n", phypo->event_id, parr->dd_event_id_1, parr->dd_event_id_2);
if (parr->flag_ignore || !(phypo->event_id == parr->dd_event_id_1
|| phypo->event_id == parr->dd_event_id_2))
continue;
}
WriteArrival(fpio, parr, io_arrival_mode);
}
fprintf(fpio, "END_PHASE\n");
}
/* write end line and blank line */
if (iWriteEndLoc)
fprintf(fpio, "END_NLLOC\n\n");
if (ifile) {
fclose(fpio);
NumFilesOpen--;
}
return (0);
}
/** function to read hypocenter/arrival parameters */
int GetHypLoc(FILE *fpio, const char* filein, HypoDesc* phypo,
ArrivalDesc* parrivals, int *pnarrivals, int iReadArrivals,
GridDesc* pgrid, int n_proj) {
int ifile = 0;
int lineLength;
char fn_in[FILENAME_MAX];
char line[MAXLINE_LONG], *pstr, *pstr2 = NULL;
double hypo_sec, templat, templong;
ArrivalDesc* parr;
/* open hypocenter file */
if (fpio == NULL) {
if ((pstr = strstr(filein, ".hyp")) == NULL
|| ((pstr - filein) < strlen(filein) - 4))
sprintf(fn_in, "%s.hyp", filein);
else
sprintf(fn_in, "%s", filein);
if ((fpio = fopen(fn_in, "r")) == NULL) {
nll_puterr2("ERROR: opening hypocenter file", fn_in);
return (-2);
}
NumFilesOpen++;
ifile = 1;
}
/* read hypocenter parameters */
/* search for first line of hypocenter description */
do {
if (fgets(line, MAXLINE_LONG, fpio) == NULL)
goto eof_exit;
} while (strncmp("NLLOC", line, 5));
phypo->fileroot[0] = '\0';
if ((pstr = strchr(line, '"')) != NULL) {
if ((pstr2 = strchr(pstr + 1, '"')) != NULL) {
strncpy(phypo->fileroot, pstr + 1, pstr2 - pstr - 1);
phypo->fileroot[pstr2 - pstr - 1] = '\0';
}
}
phypo->locStat[0] = '\0';
if ((pstr = strchr(pstr2 + 1, '"')) != NULL) {
if ((pstr2 = strchr(pstr + 1, '"')) != NULL) {
strncpy(phypo->locStat, pstr + 1, pstr2 - pstr - 1);
phypo->locStat[pstr2 - pstr - 1] = '\0';
}
}
phypo->locStatComm[0] = '\0';
if ((pstr = strchr(pstr2 + 1, '"')) != NULL) {
if ((pstr2 = strchr(pstr + 1, '"')) != NULL) {
strncpy(phypo->locStatComm, pstr + 1,
pstr2 - pstr - 1);
phypo->locStatComm[pstr2 - pstr - 1] = '\0';
}
}
/* read hypocenter description lines until END_NLLOC reached */
while (1) {
/* read next line */
if (fgets(line, MAXLINE_LONG, fpio) == NULL)
goto eof_exit;
/* end of NLLoc hypocenter descrition */
if (strncmp(line, "END_NLLOC", 9) == 0)
break;
lineLength = TrimString(line);
/* blank line */
if (lineLength == 0)
continue;
/* identify and read line */
if (strncmp(line, "PUBLIC_ID", 9) == 0) {
// 20190823 AJL - added
if (sscanf(line, "%*s %s", phypo->public_id) == EOF)
goto eof_exit;
} else if (strncmp(line, "SIGNATURE", 9) == 0) {
/* SIGNATURE */
strcpy(phypo->signature, strchr(line, '"') + 1);
*(strchr(phypo->signature, '"')) = '\0';
} else if (strncmp(line, "COMMENT", 7) == 0) {
/* COMMENT */
strcpy(phypo->comment, strchr(line, '"') + 1);
*(strchr(phypo->comment, '"')) = '\0';
} else if (strncmp(line, "GRID", 4) == 0) {
/* GRID */
if (pgrid != NULL) {
if (sscanf(line,
"%*s %d %d %d %lf %lf %lf %lf %lf %lf %s",
&pgrid->numx, &pgrid->numy, &pgrid->numz,
&pgrid->origx, &pgrid->origy, &pgrid->origz,
&pgrid->dx, &pgrid->dy, &pgrid->dz,
pgrid->chr_type)
== EOF)
goto eof_exit;
}
} else if (strncmp(line, "SEARCH", 6) == 0) {
/* SEARCH */
line[MAXLINE_LONG - 1] = '\0';
strcpy(phypo->searchInfo, strchr(line, ' ') + 1);
} else if (strncmp(line, "HYPOCENTER", 10) == 0) {
/* HYPOCENTER */
if (sscanf(line,
"%*s %*s %lf %*s %lf %*s %lf %*s %lf %*s %d %*s %d %*s %d %s",
&(phypo->x), &(phypo->y), &(phypo->z),
&hypo_sec,
&(phypo->ix), &(phypo->iy), &(phypo->iz),
phypo->type // 20170811 AJL - added to allow saving of expectation hypocenter results instead of maximum likelihood
)
== EOF)
goto eof_exit;
phypo->sec = (long double) hypo_sec;
} else if (strncmp(line, "GEOGRAPHIC", 10) == 0) {
/* GEOGRAPHIC */
if (sscanf(line,
"%*s %*s %d %d %d %d %d %lf %*s %lf %*s %lf %*s %lf",
&(phypo->year), &(phypo->month), &(phypo->day),
&(phypo->hour), &(phypo->min), &hypo_sec,
&(phypo->dlat), &(phypo->dlong),
&(phypo->depth)) == EOF)
goto eof_exit;
phypo->sec = (long double) hypo_sec;
} else if (strncmp(line, "QUALITY", 7) == 0) {
/* QUALITY */
if (sscanf(line,
"%*s %*s %Lf %*s %lf %*s %lf %*s %lf %*s %d %*s %lf %*s %lf %*s %lf %d %*s %lf %d",
&phypo->probmax, &phypo->misfit,
&phypo->grid_misfit_max,
&phypo->rms, &phypo->nreadings, &phypo->gap,
&phypo->dist,
&phypo->amp_mag, &phypo->num_amp_mag,
&phypo->dur_mag, &phypo->num_dur_mag
) == EOF)
goto eof_exit;
if (GeometryMode == MODE_GLOBAL)
phypo->dist /= KM2DEG; // always store in memory in km
} else if (strncmp(line, "QUALITY2", 8) == 0) { // 20100519 AJL Added new hypo line
/* QUALITY2 */
if (sscanf(line,
"%*s %*s %lf",
&phypo->gap_secondary
) == EOF)
goto eof_exit;
} else if (strncmp(line, "VPVSRATIO", 9) == 0) {
/* VPVSRATIO */
if (sscanf(line,
"%*s %*s %lf %*s %d %*s %lf",
&phypo->VpVs, &phypo->nVpVs, &phypo->tsp_min_max_diff
) == EOF)
goto eof_exit;
} else if (strncmp(line, "STATISTICS", 10) == 0) {
/* STATISTICS */
if (sscanf(line,
"%*s %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf %*s %lf",
&phypo->expect.x, &phypo->expect.y,
&phypo->expect.z,
&phypo->cov.xx, &phypo->cov.xy, &phypo->cov.xz,
&phypo->cov.yy, &phypo->cov.yz, &phypo->cov.zz,
&phypo->ellipsoid.az1, &phypo->ellipsoid.dip1,
&phypo->ellipsoid.len1,
&phypo->ellipsoid.az2, &phypo->ellipsoid.dip2,
&phypo->ellipsoid.len2,
&phypo->ellipsoid.len3) == EOF)
goto eof_exit;
phypo->cov.yx = phypo->cov.xy;
phypo->cov.zx = phypo->cov.xz;
phypo->cov.zy = phypo->cov.yz;
} else if (strncmp(line, "STAT_GEOG", 9) == 0) {
/* STATISTICS */
if (sscanf(line,
"%*s %*s %lf %*s %lf %*s %lf",
&phypo->expect_dlat, &phypo->expect_dlong, &phypo->expect.z) == EOF)
goto eof_exit;
} else if (strncmp(line, "MAXIMUM_LIKELIHOOD", 18) == 0) {
/* MAXIMUM_LIKELIHOOD */
// 20170811 AJL - added to allow saving of expectation hypocenter results instead of maximum likelihood
if (sscanf(line,
"%*s %*s %lf %*s %lf %*s %lf %*s %lf",
&phypo->max_like_dlat, &phypo->max_like_dlong, &phypo->max_like.z, &phypo->max_like_sec) == EOF)
goto eof_exit;
} else if (strncmp(line, "ELLIPSOID", 9) == 0) {
/* ELLIPSOID */
if (sscanf(line,
"%*s %*s %lf %lf %lf %*s %lf %lf %lf %*s %lf %lf %lf %*s %lf",
&templat, &templong,
&phypo->expect.z,
&phypo->ellipsoid.az1, &phypo->ellipsoid.dip1,
&phypo->ellipsoid.len1,
&phypo->ellipsoid.az2, &phypo->ellipsoid.dip2,
&phypo->ellipsoid.len2,
&phypo->ellipsoid.len3
) == EOF)
goto eof_exit;
latlon2rect(0, templat, templong,
&phypo->expect.x, &phypo->expect.y);
} else if (strncmp(line, "FOCALMECH", 9) == 0) {
/* FOCALMECH */
/* Hyp dlat dlong depth Mech dipDir dipAng rake mf misfit nObs nObs */
if (sscanf(line,
"%*s %*s %lf %lf %lf %*s %lf %lf %lf %*s %lf %*s %d",
&phypo->focMech.dlat, &phypo->focMech.dlong,
&phypo->focMech.depth,
&phypo->focMech.dipDir, &phypo->focMech.dipAng,
&phypo->focMech.rake,
&phypo->focMech.misfit, &phypo->focMech.nObs
) == EOF)
goto eof_exit;
} else if (strncmp(line, "TRANSFORM", 9) == 0) {
/* TRANSFORM */
if (n_proj >= 0)
line[MAXLINE_LONG - 1] = '\0';
strcpy(MapProjStr[n_proj], line);
} else if (strncmp(line, "DIFFERENTIAL", 12) == 0) {
/* DIFFERENTIAL */
/* Nhyp n */
if (sscanf(line, "%*s %*s %ld", &phypo->event_id) == EOF)
goto eof_exit;
} else if (strncmp(line, "QML_OriginQuality", 12) == 0) { // 20181017 AJL - added
if (sscanf(line,
"QML_OriginQuality assocPhCt %d usedPhCt %*d assocStaCt %d usedStaCt %d depthPhCt %d"
" stdErr %*g azGap %*g secAzGap %lg gtLevel %s minDist %lg maxDist %lg medDist %lg",
&phypo->associatedPhaseCount, &phypo->associatedStationCount, &phypo->usedStationCount, &phypo->depthPhaseCount,
&phypo->gap_secondary, phypo->groundTruthLevel, &phypo->minimumDistance, &phypo->maximumDistance, &phypo->medianDistance) == EOF)
goto eof_exit;
} else if (strncmp(line, "QML_OriginUncertainty", 12) == 0) { // 20181017 AJL - added
double azMaxHorUnc;
if (sscanf(line,
"QML_OriginUncertainty horUnc %*g minHorUnc %lg maxHorUnc %lg azMaxHorUnc %lg",
// 20100617 AJL - horizontalUncertainty: not clear what this is, ignore
&phypo->ellipse.len1, &phypo->ellipse.len2, &azMaxHorUnc) == EOF)
goto eof_exit;
phypo->ellipse.az1 = azMaxHorUnc - 90.0;
if (phypo->ellipse.az1 <= 0.0)
phypo->ellipse.az1 += 360.0;
} else if (strncmp(line, "PHASE", 5) == 0) {
/* read arrival/phase parameters */
/* !!! Remember to modify this sscanf when modifying
fprintf format in function WriteLocation() */
if (pnarrivals != NULL)
*pnarrivals = 0;
/* if requested to read arrivals */
if (iReadArrivals) {
/* read arrivals */
while ((pstr = fgets(line, MAXLINE_LONG, fpio))
!= NULL
&& strncmp("END_PHASE", line, 9)) {
if (*pnarrivals >= MAX_NUM_ARRIVALS) {
sprintf(MsgStr, "WARNING: maximum number of arrivals (%d) exceeded.", MAX_NUM_ARRIVALS);
nll_puterr(MsgStr);
(*pnarrivals)--;
break;
}
parr = parrivals + *pnarrivals;
ReadArrival(line, parr, IO_ARRIVAL_ALL);
(*pnarrivals)++;
};
}/* not requested to read arrivals */
else {
while ((pstr = fgets(line, MAXLINE_LONG, fpio))
!= NULL
&& strncmp("END_PHASE", line, 9))
;
}
if (pstr == NULL)
goto eof_exit;
} else if (strncmp(line, "SCATTER", 7) == 0) {
/* skip scatter points */
while ((pstr = fgets(line, MAXLINE_LONG, fpio))
!= NULL
&& strncmp("END_SCATTER", line, 11))
;
if (pstr == NULL)
goto eof_exit;
} else if (strncmp(line, "QML_", 4) == 0) {
/* QML_ */
;
} else {
nll_putmsg(1,
"WARNING: unrecognized line in NLLOC hypocenter description:");
sprintf(MsgStr, " <%s>", line);
nll_putmsg(1, MsgStr);
}
} /* while(1) */
/* normal return */
if (ifile) {
fclose(fpio);
NumFilesOpen--;
}
return (0);
/* return at end of file */
eof_exit:
if (ifile) {
fclose(fpio);
NumFilesOpen--;
}
return (EOF);
}
/** function to read arrival */
/* returns: 1 if only observation part of phase read
2 if observation and calculated parts of phase read
EOF if EOF or error occurs before any values read
-1 otherwise
*
* NOTE: if this function is changed, then Early-est->trace_processing/timedomain_processing/timedomain_processing_data.c->get_next_pick_nll() should be modified.
*/
int ReadArrival(char* line, ArrivalDesc* parr, int iReadType) {
int istat, istat2;
long int idate, ihrmin;
char *line_calc;
static char label[ARRIVAL_LABEL_LEN];
// new values NLL PHASE_2 format
// 20060629 AJL - Added
double apriori_weight;
// 20070326 AJL - Added
double tt_error;
/* dummy values for unsupported fields */
strcpy(parr->network, ARRIVAL_NULL_STR);
/* read observation part of phase line */
istat = sscanf(line, "%s %s %s %s %s %s %ld %ld %lf %s %lf %lf %lf %lf",
label,
parr->inst,
parr->comp,
parr->onset,
parr->phase,
parr->first_mot,
/*&parr->quality, */
&idate, &ihrmin,
&(parr->sec),
parr->error_type,
// AJL 2000628 bug fix - replaced following line
//&parr->error,
&(parr->error),
&(parr->coda_dur),
&(parr->amplitude),
&(parr->period)
);
// check for QUAL error type and convert to GAU error using LOCQUAL2ERR
// 20160727 AJL - added
if (strcmp(parr->error_type, "QUAL") == 0) {
parr->quality = (int) lround(parr->error);
Qual2Err(parr);
}
// check for negative error and convert to P or S GAU error using LOCQUAL2ERR
// assumes LOCQUAL2ERR is set with 2 values: qual 0 -> P error, qual 1 -> other phase types
// 20230812 AJL - added
if (strcmp(parr->error_type, "GAU") == 0 && parr->error < 0.0) {
if (IsPhaseID(parr->phase, "P")) {
parr->quality = 0;
} else {
parr->quality = 1;
}
Qual2Err(parr);
}
// DEBUG
/*printf("%s %s %s %s %s %s %ld %ld %lf %s %lf %lf %lf %lf %lf\n",
parr->label,
parr->inst,
parr->comp,
parr->onset,
parr->phase,
parr->first_mot,
//&parr->quality,
idate, ihrmin,
(parr->sec),
parr->error_type, parr->error,
(parr->coda_dur),
(parr->amplitude),
(parr->period),
parr->apriori_weight
);
*/
// new values NLL PHASE_2 format
// 20060629 AJL - Added
// test input of new values
istat2 = sscanf(line, "%*s %*s %*s %*s %*s %*s %*d %*d %*f %*s %*f %*f %*f %*f %lf",
&apriori_weight
);
if (istat2 == 1) {
parr->apriori_weight = apriori_weight;
} else {
parr->apriori_weight = 1.0;
}
// DEBUG
/*printf(" %lf\n",
parr->apriori_weight
);
*/
// AJL 20050324 $$$ XXX
// work around for bug in SeisGram2K Cumul_XX uncertainty
// parr->error /= 2.0;
strncpy(parr->label, label, ARRIVAL_LABEL_LEN);
if (istat == EOF)
return (istat);
if (istat != 14)
return (-1);
/* decode data and time integers */
parr->year = idate / 10000;
idate = idate % 10000;
parr->month = idate / 100;
parr->day = idate % 100;
parr->hour = ihrmin / 100;
parr->min = ihrmin % 100;
/* set null quality value */
parr->quality = -1;
if (iReadType != IO_ARRIVAL_ALL)
return (1);
/* read calculated part of phase line */
if ((line_calc = strchr(line, '>')) == NULL)
return (1);
istat = sscanf(line_calc + 1,
"%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %d %lf",
&parr->pred_travel_time, &parr->residual,
&parr->weight,
&parr->station.x, &parr->station.y,
&parr->station.z,
&parr->dist, &parr->azim,
&parr->ray_azim, &parr->ray_dip, &parr->ray_qual,
&parr->delay
);
parr->station.is_coord_xyz = 1; // 20200206 AJL - Bug fix.
parr->station.is_coord_latlon = 0; // 20200206 AJL - Bug fix.
if (istat == EOF)
return (istat);
//if (istat != 11) // delay added
if (istat < 11)
return (-1);
// new values NLL PHASE_2 format
// 20070326 AJL - Added
// test input of new values
istat2 = sscanf(line, "%*f %*f %*f %*f %*f %*f %*f %*f %*f %*f %*d %*f %lf",
&tt_error
);
if (istat2 == 1) {
parr->tt_error = tt_error;
} else {
parr->tt_error = -1.0;
}
if (GeometryMode == MODE_GLOBAL)
parr->dist /= KM2DEG; // always store in memory in km
/* convert azimuths to grid coords direction */
parr->azim = latlon2rectAngle(0, parr->azim);
parr->ray_azim = latlon2rectAngle(0, parr->ray_azim);
return (2);
}
/** function to write arrival */
int WriteArrival(FILE* fpio, ArrivalDesc* parr, int iWriteType) {
int istat;
long int idate, ihrmin;
double sta_azim, ray_azim;
/* code data and time integers */
idate = parr->year * 10000 + parr->month * 100
+ parr->day;
ihrmin = parr->hour * 100 + parr->min;
if (PhaseFormat == FORMAT_PHASE_1) {
// write observation part of phase line
istat = fprintf(fpio,
"%-6.6s %-4.4s %-4.4s %-1.1s %-6.6s %-1.1s %8.8ld %4.4ld %9.4lf %-3.3s %9.2le %9.2le %9.2le %9.2le",
parr->label,
parr->inst,
parr->comp,
parr->onset,
parr->phase,
parr->first_mot,
/*parr->quality, */
idate, ihrmin,
parr->sec,
parr->error_type, parr->error,
parr->coda_dur,
parr->amplitude,
parr->period
);
if (istat < 0)
return (-1);
} else if (PhaseFormat == FORMAT_PHASE_2) {
// write observation part of FORMAT_PHASE_2 phase line
istat = fprintf(fpio,
// 20110107 AJL "%-6s %-4s %-4s %-1s %-6s %-1s %8.8ld %4.4ld %9.4lf %-3s %9.2le %9.2le %9.2le %9.2le %9.4lf",
"%-12s %-4s %-4s %-1s %-6s %-1s %8.8ld %4.4ld %9.4lf %-3s %9.2le %9.2le %9.2le %9.2le %9.4lf",
parr->label,
parr->inst,
parr->comp,
parr->onset,
parr->phase,
parr->first_mot,
/*parr->quality, */
idate, ihrmin,
parr->sec,
parr->error_type, parr->error,
parr->coda_dur,
parr->amplitude,
parr->period,
parr->apriori_weight
);
if (istat < 0)
return (-1);
}
/* write calculated part of phase line */
if (iWriteType == IO_ARRIVAL_ALL) {
/* convert ray azimuth to geographic direction */
sta_azim = rect2latlonAngle(0, parr->azim);
ray_azim = rect2latlonAngle(0, parr->ray_azim);
if (PhaseFormat == FORMAT_PHASE_1) {
// write calculated part of phase line
istat = fprintf(fpio,
" > %9.4lf %9.4lf %9.4lf %9.4lf %9.4lf %9.4lf %9.4lf %6.2lf %5.1lf %5.1lf %2d %9.4lf",
parr->pred_travel_time, parr->residual,
parr->weight,
parr->station.x, parr->station.y,
parr->station.z,
GeometryMode == MODE_GLOBAL ? parr->dist * KM2DEG : parr->dist,
sta_azim,
ray_azim, parr->ray_dip, parr->ray_qual,
parr->delay
);
if (istat < 0)
return (-1);
} else if (PhaseFormat == FORMAT_PHASE_2) {
// write calculated part of FORMAT_PHASE_2 phase line
istat = fprintf(fpio,
" > %9.4lf %9.4lf %9.4lf %9.4lf %9.4lf %9.4lf %9.4lf %6.2lf %5.1lf %5.1lf %2d %9.4lf %9.4lf",
parr->pred_travel_time, parr->residual,
parr->weight,
parr->station.x, parr->station.y,
parr->station.z,
GeometryMode == MODE_GLOBAL ? parr->dist * KM2DEG : parr->dist,
sta_azim,
ray_azim, parr->ray_dip, parr->ray_qual,
parr->delay,
parr->tt_error
);
if (istat < 0)
return (-1);
}
}
istat = fprintf(fpio, "\n");
if (istat < 0)
return (-1);
return (0);
}
/** function to clone (deep copy) a HypoDesc */
HypoDesc * cloneHypoDesc(HypoDesc * phypo_orig) {
HypoDesc *phypo = NULL;
// clone HypoDesc
phypo = (HypoDesc*) malloc(sizeof (HypoDesc));
if (phypo == NULL) { // memory allocation problem
nll_puterr("ERROR: cloneHypoDesc(): allocating memory for hypocenter.\n");
} else {
*phypo = *phypo_orig;
}
/*
// clone member structures
//Vect3D expect;
phypo->expect = (Vect3D*) malloc(sizeof(Vect3D));
*(phypo->expect) = *(phypo_orig->expect);
//Mtrx3D cov
phypo->cov = (Vect3D*) malloc(sizeof(Mtrx3D));
*(phypo->cov) = *(phypo_orig->cov);
//Ellipsoid3D ellipsoid;
phypo->ellipsoid = (Ellipsoid3D*) malloc(sizeof(Ellipsoid3D));
*(phypo->ellipsoid) = *(phypo_orig->ellipsoid);
//FocalMech focMech;
phypo->focMech = (Vect3D*) malloc(sizeof(FocalMech));
*(phypo->focMech) = *(phypo_orig->focMech);
*/
return (phypo);
}
/** function to clone (deep copy) an array of ArrivalDesc's */
ArrivalDesc * cloneArrivalDescArray(ArrivalDesc* parrivals_orig, int narrivals) {
int i;
ArrivalDesc* parrivals;
parrivals = (ArrivalDesc*) calloc(narrivals, sizeof (ArrivalDesc));
if (parrivals == NULL) { // memory allocation problem
nll_puterr("ERROR: cloneArrivalDescArray(): allocating memory for arrivals.\n");
} else {
for (i = 0; i < narrivals; i++)
parrivals[i] = parrivals_orig[i];
}
return (parrivals);
}
/** function to clone (deep copy) a GridDesc */
GridDesc * cloneGridDesc(GridDesc * pgrid_orig) {
GridDesc* pgrid;
pgrid = (GridDesc*) malloc(sizeof (GridDesc));
if (pgrid == NULL) { // memory allocation problem
nll_puterr("ERROR: cloneGridDesc(): allocating memory for grid.\n");
} else {
*pgrid = *pgrid_orig;
}
return (pgrid);
}
/** function to write arrival in hypo71/hypoellipse format */
int WriteArrivalHypo(FILE* fpio, ArrivalDesc* arrival, int iwriteEOL) {
int istat = 0;
int pha_qual;
/* write phase */
pha_qual = (arrival->quality >= 0 && arrival->quality <= 4) ?
arrival->quality : Err2Qual(arrival);
if (pha_qual < 0)
pha_qual = 0; /* !! not necessarily a good choice */
if (iwriteEOL)
istat = fprintf(fpio, "\n");
/* P phase */
if (strcmp(arrival->phase, "P") == 0) {
/* write P arrival output */
istat = fprintf(fpio, "%4.4s", arrival->label);
istat = fprintf(fpio, "%1s", arrival->onset);
istat = fprintf(fpio, "%1s", arrival->phase);
istat = fprintf(fpio, "%1s", arrival->first_mot);
istat = fprintf(fpio, "%1.1d", pha_qual);
istat = fprintf(fpio, " %2.2d", arrival->year % 100);
istat = fprintf(fpio, "%2.2d", arrival->month);
istat = fprintf(fpio, "%2.2d", arrival->day);
istat = fprintf(fpio, "%2.2d", arrival->hour);
istat = fprintf(fpio, "%2.2d", arrival->min);
istat = fprintf(fpio, "%5.2f", arrival->sec);
/* S phase */
} else if (strcmp(arrival->phase, "S") == 0) {
/* write S phase output (NOTE: assumes written directly after corresponding P) */
istat = fprintf(fpio, " %5.2f", arrival->sec);
istat = fprintf(fpio, " %1s ", arrival->phase);
istat = fprintf(fpio, "%1.1d", pha_qual);
}
if (istat < 0)
return (-1);
return (0);
}
/** function to generate GMT JVAL from map transformation parameters */
double getGMTJVAL(int n_proj, char* jval_string, double xlen, double vxmax, double vxmin,
double ylen, double vymax, double vymin) {
double gmt_scale;
jval_string[0] = '\0';
if (map_itype[n_proj] == MAP_TRANS_GLOBAL) {
/* -Jmscale or -JMwidth (Mercator [C])
Give scale along equator (1:xxxx or inch/degree).
*/
gmt_scale = xlen / (vxmax - vxmin);
sprintf(jval_string, "-Jm%lf", gmt_scale);
return (gmt_scale);
} else if (map_itype[n_proj] == MAP_TRANS_SIMPLE || map_itype[n_proj] == MAP_TRANS_SDC || map_itype[n_proj] == MAP_TRANS_NONE) {
/* -Jmscale or -JMwidth (Mercator [C])
Give scale along equator (1:xxxx or inch/degree).
*/
gmt_scale = xlen / (vxmax - vxmin);
sprintf(jval_string, "-Jm%lf", gmt_scale);
return (gmt_scale);
} else if (map_itype[n_proj] == MAP_TRANS_LAMBERT) {
/* -JLlon0/lat0/lat1/lat2/width (Lambert [C])
Give origin, 2 standard parallels, and scale along
these (1:xxxx or inch/degree)
*/
gmt_scale = (ylen / (vymax - vymin)); // * (xmaxrect0 - xminrect0) / (xmaxrect - xminrect);
sprintf(jval_string, "-JL%lf/%lf/%lf/%lf/%lf",
map_orig_long[n_proj], map_orig_lat[n_proj],
map_lambert_1st_std_paral[n_proj], map_lambert_2nd_std_paral[n_proj],
xlen);
return (gmt_scale);
} else if (map_itype[n_proj] == MAP_TRANS_TM) {
/* -Jtlon0/[lat0/]scale or -JTlon0/[lat0/]width (Transverse Mercator [C])
Give the central meridian lon0, central parallel lat0 (optional), and scale (1:xxxx or UNIT/degree).
*/
gmt_scale = (ylen / (vymax - vymin)); // * (xmaxrect0 - xminrect0) / (xmaxrect - xminrect);
sprintf(jval_string, "-JT%lf/%lf/%lf",
map_orig_long[n_proj], map_orig_lat[n_proj], xlen);
return (gmt_scale);
} else if (map_itype[n_proj] == MAP_TRANS_AZ_EQUID) {
/* -Je|E<lon0>/<lat0>[/<horizon>]/<scale>|<width> (Azimuthal Equidistant)
<lon0>/<lat0> is the center of the projection.
<horizon> is max distance from center of the projection (<= 180, default 180).
<scale> can also be given as <radius>/<lat>, where <radius> is the distance
in cm to the oblique parallel <lat>.
*/
gmt_scale = (ylen / (vymax - vymin)); // * (xmaxrect0 - xminrect0) / (xmaxrect - xminrect);
sprintf(jval_string, "-JE%lf/%lf/180/%lf",
map_orig_long[n_proj], map_orig_lat[n_proj], xlen);
return (gmt_scale);
}
return (-1.0);
}
/** function to convert between coord systems */
int convertCoordsRect(int proj_index_from, int proj_index_to, double x, double y, double *pxnew, double *pynew) {
double dlat = 0.0, dlong = 0.0;
if (proj_index_from < 0 || proj_index_to < 0)
return (-1);
if (proj_index_from == proj_index_to) {
*pxnew = x;
*pynew = y;
return (0);
}
rect2latlon(proj_index_from, x, y, &dlat, &dlong);
latlon2rect(proj_index_to, dlat, dlong, pxnew, pynew);
return (0);
}
/** function to convert lat/long to rectangular km coord */
/* rotation about rect coord origin */
int latlon2rect(int n_proj, double dlat, double dlong, double* pxrect, double* pyrect) {
double xtemp, ytemp;
double xlt1;
if (map_itype[n_proj] == MAP_TRANS_GLOBAL) {
*pxrect = dlong;
*pyrect = dlat;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_NONE) {
*pxrect = dlong;
*pyrect = dlat;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_SIMPLE) {
xtemp = dlong - map_orig_long[n_proj];
if (xtemp > 180.0)
xtemp -= 360.0;
if (xtemp < -180.0)
xtemp += 360.0;
xtemp = xtemp * c111 * cos(cRPD * dlat);
ytemp = (dlat - map_orig_lat[n_proj]) * c111;
*pxrect = xtemp * map_cosang[n_proj] - ytemp * map_sinang[n_proj];
*pyrect = ytemp * map_cosang[n_proj] + xtemp * map_sinang[n_proj];
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_SDC) {
/*
c now convert lat and lon differences to km
x=xln-pln
c x=pln-xln
y=plt-xlt
xlt1=atan(drlt*tan(drad*(plt+xlt)/120.))
x=x*xlnkm*cos(xlt1)
y=y*xltkm
*/
xtemp = dlong - map_orig_long[n_proj];
if (xtemp > 180.0)
xtemp -= 360.0;
if (xtemp < -180.0)
xtemp += 360.0;
ytemp = dlat - map_orig_lat[n_proj];
xlt1 = atan(MAP_TRANS_SDC_DRLT * tan(DE2RA * (dlat + map_orig_lat[n_proj]) / 2.0));
xtemp = xtemp * map_sdc_xlnkm[n_proj] * cos(xlt1);
ytemp = ytemp * map_sdc_xltkm[n_proj];
*pxrect = xtemp * map_cosang[n_proj] - ytemp * map_sinang[n_proj];
*pyrect = ytemp * map_cosang[n_proj] + xtemp * map_sinang[n_proj];
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_LAMBERT) {
lamb(n_proj, dlong, dlat, &xtemp, &ytemp);
xtemp /= 1000.0; /* m -> km */
ytemp /= 1000.0; /* m -> km */
*pxrect = xtemp * map_cosang[n_proj] - ytemp * map_sinang[n_proj];
*pyrect = ytemp * map_cosang[n_proj] + xtemp * map_sinang[n_proj];
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_TM) {
tm(n_proj, dlong, dlat, &xtemp, &ytemp);
xtemp /= 1000.0; /* m -> km */
ytemp /= 1000.0; /* m -> km */
*pxrect = xtemp * map_cosang[n_proj] - ytemp * map_sinang[n_proj];
*pyrect = ytemp * map_cosang[n_proj] + xtemp * map_sinang[n_proj];
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_AZ_EQUID) {
azeqdist(n_proj, dlong, dlat, &xtemp, &ytemp);
xtemp /= 1000.0; /* m -> km */
ytemp /= 1000.0; /* m -> km */
*pxrect = xtemp * map_cosang[n_proj] - ytemp * map_sinang[n_proj];
*pyrect = ytemp * map_cosang[n_proj] + xtemp * map_sinang[n_proj];
return (0);
}
return (-1);
}
/** function to convert rectangular km coord to lat/long */
int rect2latlon(int n_proj, double xrect, double yrect, double* pdlat, double* pdlong) {
double xtemp, ytemp;
double xlt1;
if (map_itype[n_proj] == MAP_TRANS_GLOBAL) {
*pdlat = yrect;
*pdlong = xrect;
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_NONE) {
*pdlat = yrect;
*pdlong = xrect;
/* 20170321 AJL - bug fix
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;*/
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_SIMPLE) {
xtemp = xrect * map_cosang[n_proj] + yrect * map_sinang[n_proj];
ytemp = yrect * map_cosang[n_proj] - xrect * map_sinang[n_proj];
*pdlat = map_orig_lat[n_proj] + ytemp / c111;
*pdlong = map_orig_long[n_proj] + xtemp / (c111 * cos(cRPD * *pdlat));
// 20121005 AJL - prevent longitude outside of -180 -> 180 deg range
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_SDC) {
xtemp = xrect * map_cosang[n_proj] + yrect * map_sinang[n_proj];
ytemp = yrect * map_cosang[n_proj] - xrect * map_sinang[n_proj];
/*
c
fy=fy/xltkm
plt=xlt+fy
c
xlt1=atan(rlt*tan(rad*(plt+xlt)/120.))
fx=fx/(xlnkm*cos(xlt1))
pln=xln+fx
*/
ytemp = ytemp / map_sdc_xltkm[n_proj];
*pdlat = map_orig_lat[n_proj] + ytemp;
xlt1 = atan(MAP_TRANS_SDC_DRLT * tan(DE2RA * (*pdlat + map_orig_lat[n_proj]) / 2.0));
xtemp = xtemp / (map_sdc_xlnkm[n_proj] * cos(xlt1));
*pdlong = map_orig_long[n_proj] + xtemp;
// 20121005 AJL - prevent longitude outside of -180 -> 180 deg range
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_LAMBERT) {
xtemp = xrect * map_cosang[n_proj] + yrect * map_sinang[n_proj];
ytemp = yrect * map_cosang[n_proj] - xrect * map_sinang[n_proj];
ilamb(n_proj, pdlong, pdlat, xtemp * 1000.0, ytemp * 1000.0);
// 20121005 AJL - prevent longitude outside of -180 -> 180 deg range
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_TM) {
xtemp = xrect * map_cosang[n_proj] + yrect * map_sinang[n_proj];
ytemp = yrect * map_cosang[n_proj] - xrect * map_sinang[n_proj];
itm(n_proj, pdlong, pdlat, xtemp * 1000.0, ytemp * 1000.0);
// 20121005 AJL - prevent longitude outside of -180 -> 180 deg range
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;
return (0);
} else if (map_itype[n_proj] == MAP_TRANS_AZ_EQUID) {
xtemp = xrect * map_cosang[n_proj] + yrect * map_sinang[n_proj];
ytemp = yrect * map_cosang[n_proj] - xrect * map_sinang[n_proj];
iazeqdist(n_proj, pdlong, pdlat, xtemp * 1000.0, ytemp * 1000.0);
if (*pdlong < -180.0)
*pdlong += 360.0;
else if (*pdlong > 180.0)
*pdlong -= 360.0;
return (0);
}
return (-1);
}
/** function to convert rectangular km angle to lat/long angle */
double rect2latlonAngle(int n_proj, double rectAngle) {
double angle;
if (map_itype[n_proj] == MAP_TRANS_SIMPLE ||
map_itype[n_proj] == MAP_TRANS_SDC ||
map_itype[n_proj] == MAP_TRANS_LAMBERT ||
map_itype[n_proj] == MAP_TRANS_TM ||
map_itype[n_proj] == MAP_TRANS_AZ_EQUID) {
angle = rectAngle - map_rot[n_proj];
if (angle < 0.0)
angle += 360.0;
else if (angle > 360.0)
angle -= 360.0;
return (angle);
} else
return (rectAngle);
}
/** function to convert lat/long km angle to rectangular angle */
double latlon2rectAngle(int n_proj, double latlonAngle) {
double angle;
if (map_itype[n_proj] == MAP_TRANS_SIMPLE ||
map_itype[n_proj] == MAP_TRANS_SDC ||
map_itype[n_proj] == MAP_TRANS_LAMBERT ||
map_itype[n_proj] == MAP_TRANS_TM ||
map_itype[n_proj] == MAP_TRANS_AZ_EQUID) {
angle = latlonAngle + map_rot[n_proj];
if (angle < 0.0)
angle += 360.0;
else if (angle > 360.0)
angle -= 360.0;
return (angle);
} else
return (latlonAngle);
}
/** function to convert source location parameters between coord systems */
int ConvertSourceLoc(int n_proj, SourceDesc *source, int numSources, int toXY, int toLatLon) {
int istat = 0, nsource;
SourceDesc *srce_in;
for (nsource = 0; nsource < numSources; nsource++) {
srce_in = source + nsource;
istat = ConvertASourceLocation(n_proj, srce_in, toXY, toLatLon);
}
return (istat);
}
/** function to convert source location parameters between coord systems */
int ConvertASourceLocation(int n_proj, SourceDesc *srce_in, int toXY, int toLatLon) {
int istat = 0;
if (toXY && srce_in->is_coord_latlon && !srce_in->is_coord_xyz) {
istat = latlon2rect(n_proj, srce_in->dlat, srce_in->dlong,
&(srce_in->x), &(srce_in->y));
srce_in->is_coord_xyz = 1; // 20200206 AJL - Bug fix.
srce_in->z = srce_in->depth;
}
if (toLatLon && srce_in->is_coord_xyz && !srce_in->is_coord_latlon) {
istat = rect2latlon(n_proj, srce_in->x, srce_in->y,
&(srce_in->dlat), &(srce_in->dlong));
srce_in->is_coord_latlon = 1; // 20200206 AJL - Bug fix.
srce_in->depth = srce_in->z;
}
return (istat);
}
/** function to set model coordinates mode to rect or latlon */
int SetModelCoordsMode(int num_surfaces) {
double xloc, yloc;
/* if surfaces read, assume lat/long */
if (num_surfaces > 0) {
ModelCoordsMode = COORDS_LATLON;
/* check geographic transformation */
if (rect2latlon(0, 0.0, 0.0, &yloc, &xloc) < 0) {
nll_puterr(
"FATAL ERROR: geographic transformation required with SURFACE options,\n\tbut transformation (TRANS) not initialized.");
exit(-1);
}
} else
ModelCoordsMode = COORDS_RECT;
return (0);
}
/*** date functions */
/** function to convert character month to integer month */
int Month2Int(char* cmonth) {
int i;
for (i = 0; i < strlen(cmonth); i++)
cmonth[i] = toupper(cmonth[i]);
if (strcmp(cmonth, "JAN") == 0)
return (1);
if (strcmp(cmonth, "FEB") == 0)
return (2);
if (strcmp(cmonth, "MAR") == 0)
return (3);
if (strcmp(cmonth, "APR") == 0)
return (4);
if (strcmp(cmonth, "MAY") == 0)
return (5);
if (strcmp(cmonth, "JUN") == 0)
return (6);
if (strcmp(cmonth, "JUL") == 0)
return (7);
if (strcmp(cmonth, "AUG") == 0)
return (8);
if (strcmp(cmonth, "SEP") == 0)
return (9);
if (strcmp(cmonth, "OCT") == 0)
return (10);
if (strcmp(cmonth, "NOV") == 0)
return (11);
if (strcmp(cmonth, "DEC") == 0)
return (12);
nll_puterr2("ERROR: unrecognized charcter month", cmonth);
return (0);
}
/*** date functions */
static char daytab[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
/** function to set day of year */
int DayOfYear(int year, int month, int day) {
int i, leap;
leap = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
for (i = 1; i < month; i++)
day += daytab[leap][i];
return day;
}
/** function to set month / day from day of year */
void MonthDay(int year, int yearday, int* pmonth, int* pday) {
int i, leap;
leap = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
for (i = 1; yearday > daytab[leap][i]; i++)
yearday -= daytab[leap][i];
*pmonth = i;
*pday = yearday;
}
/** function to construct current date/time string */
char* CurrTimeStr(void) {
static char timestr[MAXLINE];
time_t curr_time;
curr_time = time(NULL);
strftime(timestr, (size_t) MAXLINE, "%d%b%Y %Hh%Mm%S", localtime(&curr_time));
return (timestr);
}
/** function to check for and expand wild card characters in filenames
and to return a list of equivalent files */
int ExpandWildCards(char* fileFilter, char fileList[][FILENAME_MAX], int maxNumFiles) {
int nfiles = 0;
char *pchr;
/* check for no '*' or '?' character */
if ((pchr = strchr(fileFilter, '*')) == NULL && (pchr = strchr(fileFilter, '?')) == NULL) {
strcpy(fileList[0], fileFilter);
nfiles = 1;
return (nfiles);
}
// get directory and filename
char directory[FILENAME_MAX];
if ((pchr = strrchr(fileFilter, '/')) != NULL) {
strncpy(directory, fileFilter, pchr - fileFilter);
directory[pchr - fileFilter] = '\0';
strcpy(ExpandWildCards_pattern, pchr + 1);
} else {
strcpy(directory, ".");
strcpy(ExpandWildCards_pattern, fileFilter);
}
/*DEBUG*///printf("directory: <%s>\n", directory);
/*DEBUG*///printf("filename: <%s>\n", ExpandWildCards_pattern);
/* expand wildcard file names into list of files */
nfiles = 0;
struct dirent **namelist;
int n;
n = scandir(directory, &namelist, fnmatch_wrapper, alphasort);
//n = scandir(directory, &namelist, NULL, alphasort);
/*DEBUG*///printf("directory: <%s> n %d\n", directory, n);
if (n <= 0) {
nll_puterr2("ERROR: expanding wildcard filenames in: ", fileFilter);
return (-1);
} else if (n == 0) {
nll_puterr2("ERROR: empty directory: expanding wildcard filenames in: ", fileFilter);
return (-1);
} else if (n > maxNumFiles) { // 20111011 AJL - added this block to catch excess number of wildcard files
sprintf(MsgStr,
"ERROR: too many files: expanding wildcard filenames in: %s, max number of files = %d",
fileFilter, maxNumFiles);
nll_puterr(MsgStr);
return (-1);
} else {
while (--n >= 0) {
sprintf(fileList[n], "%s/%s", directory, namelist[n]->d_name);
/*DEBUG*///printf("%s -> %s\n", namelist[n]->d_name,fileList[n]);
nfiles++;
free(namelist[n]);
namelist[n] = NULL;
}
free(namelist);
namelist = NULL;
}
return (nfiles);
}
/** function to wrap fnmatch */
int fnmatch_wrapper(const struct dirent * entry) {
int match = 0;
int flags = 0;
match = fnmatch(ExpandWildCards_pattern, entry->d_name, flags);
/*DEBUG*///printf("ExpandWildCards_pattern: <%s> entry->d_name: <%s> match %d\n", ExpandWildCards_pattern, entry->d_name, match);
return (!match);
}
/** function to check for and expand wild card characters in filenames
and to return a list of equivalent files */
int ExpandWildCards_OLD(char* fileName, char fileList[][FILENAME_MAX], int maxNumFiles) {
int istat;
int nfiles = 0;
char system_str[MAXLINE];
char list_file[FILENAME_MAX] = "filelist.tmp";
char *pchr;
FILE* fpio;
/* check for no '*' or '?' character */
if ((pchr = strchr(fileName, '*')) == NULL
&& (pchr = strchr(fileName, '?')) == NULL) {
strcpy(fileList[0], fileName);
nfiles = 1;
return (nfiles);
}
/* expand wildcard file names into list of files */
sprintf(system_str, "ls %s > %s", fileName, list_file);
system(system_str);
if ((fpio = fopen(list_file, "r")) == NULL) {
nll_puterr2("ERROR: opening fileList temporary file: ", list_file);
return (-1);
}
NumFilesOpen++;
nfiles = 0;
while (nfiles < maxNumFiles &&
(istat = fscanf(fpio, "%s", fileList[nfiles])) != EOF
&& istat == 1) {
nfiles++;
}
fclose(fpio);
NumFilesOpen--;
return (nfiles);
}
/** function to sort arrivals by obs_time field */
int SortArrivalsTime(ArrivalDesc* arrival, int num_arrivals) {
qsort((void *) arrival, (size_t) num_arrivals, sizeof (ArrivalDesc),
(int (*)(const void *, const void *)) CmpArrivalsTime);
return (0);
}
/** function to compare arrivals by obs_time field */
int CmpArrivalsTime(const ArrivalDesc *keyval, const ArrivalDesc * datum) {
if (keyval->obs_time < datum->obs_time)
return (-1);
if (keyval->obs_time > datum->obs_time)
return (1);
return (0);
}
/** function to sort arrivals by flag_ignore field */
int SortArrivalsIgnore(ArrivalDesc* arrival, int num_arrivals) {
qsort((void *) arrival, (size_t) num_arrivals, sizeof (ArrivalDesc),
(int (*)(const void *, const void *)) CmpArrivalsIgnore);
return (0);
}
/** function to compare arrivals by flag_ignore field */
int CmpArrivalsIgnore(const ArrivalDesc *keyval, const ArrivalDesc * datum) {
if (keyval->flag_ignore < datum->flag_ignore)
return (-1);
if (keyval->flag_ignore > datum->flag_ignore)
return (1);
return (0);
}
/** function to sort arrivals by dist field */
int SortArrivalsDist(ArrivalDesc* arrival, int num_arrivals) {
qsort((void *) arrival, (size_t) num_arrivals, sizeof (ArrivalDesc),
(int (*)(const void *, const void *)) CmpArrivalsDist);
return (0);
}
/** function to compare arrivals by dist field */
int CmpArrivalsDist(const ArrivalDesc *keyval, const ArrivalDesc * datum) {
if (keyval->dist < datum->dist)
return (-1);
if (keyval->dist > datum->dist)
return (1);
// if same distance, assume same sta sort by time // 20161004 AJL - added
if (keyval->obs_time < datum->obs_time)
return (-1);
if (keyval->obs_time > datum->obs_time)
return (1);
return (0);
}
/** function to sort array of doubles */
int SortDoubles(double* array, int num_elements) {
qsort((void *) array, (size_t) num_elements, sizeof (double),
(int (*)(const void *, const void *)) CmpDoubles);
return (0);
}
/** function to compare doubles */
int CmpDoubles(const double *keyval, const double *datum) {
if (*keyval < *datum)
return (-1);
if (*keyval > *datum)
return (1);
return (0);
}
/** function to set angle values in take-off angles union */
TakeOffAngles SetTakeOffAngles(double azim, double dip, int iqual) {
TakeOffAngles angles;
// 20201221 AJL - Bug fix: cannot represent a negative number as unsigned short - duh!
if (azim < 0.0) {
angles.ival[1] = ANGLES_DIP_REVERSE;
} else {
angles.ival[1] = (unsigned short) (0.5 + 10.0 * azim);
}
angles.ival[0] = (unsigned short) iqual
+ (unsigned short) ANGLES_OFFSET
* (unsigned short) (0.5 + 10.0 * dip);
return (angles);
}
/** function to set float values in take-off angles union */
void SetAnglesFloat(TakeOffAngles* pangles, float fvalue) {
pangles->fval = fvalue;
}
/** function to get values in take-off angles union */
int GetTakeOffAngles(TakeOffAngles *pangles, double *pazim, double *pdip, int *piqual) {
*pazim = ((double) pangles->ival[1]) / 10.0;
*pdip = ((double) (pangles->ival[0] / (int) ANGLES_OFFSET)) / 10.0;
*piqual = (int) pangles->ival[0] % (int) ANGLES_OFFSET;
//printf("i0 %d i1 %d\n", pangles->ival[0], pangles->ival[1]);
return (*piqual);
}
/** function to read take-off angles from file */
int ReadTakeOffAnglesFile(char *fname, double xloc, double yloc, double zloc,
double *pazim, double *pdip, int *piqual, double sta_azim, int iSwapBytes) {
int istat;
FILE *fp_grid, *fp_hdr;
float fvalue;
GridDesc gdesc;
TakeOffAngles angles;
//printf("DEBUG: ReadTakeOffAnglesFile: fname %s\n", fname);
/* open angle grid file */
if ((istat = OpenGrid3dFile(fname, &fp_grid, &fp_hdr, &gdesc, "angle", NULL, iSwapBytes)) < 0) {
if (message_flag >= 3) {
sprintf(MsgStr, "WARNING: cannot open angle grid file, ignoring angles: %s", fname);
nll_putmsg(3, MsgStr);
//printf("DEBUG: ReadTakeOffAnglesFile: WARNING: cannot open angle grid file, ignoring angles: %s", fname);
}
angles = SetTakeOffAngles(0.0, 0.0, 0);
GetTakeOffAngles(&angles, pazim, pdip, piqual);
return (-1);
}
/* get angles float value on grid */
fvalue = ReadAbsInterpGrid3d(fp_grid, &gdesc, xloc, yloc, zloc, 0);
/* get angles */
SetAnglesFloat(&angles, fvalue);
GetTakeOffAngles(&angles, pazim, pdip, piqual);
//printf("DEBUG: ReadTakeOffAnglesFile: x y z %f %f %f raz %f rdip %f rq %d\n", xloc, yloc, zloc, *pazim, *pdip, *piqual);
/* determine azimuth (2D grids) */
if (gdesc.type == GRID_ANGLE_2D) {
//printf("DEBUG: *pazim %f <= ANGLES_DIP_MAX %f\n", *pazim, ANGLES_DIP_MAX);
// 20201221 AJL - Bug fix: cannot represent a negative number as unsigned short - duh!
//if (*pazim > 0.0)
if (*pazim <= ANGLES_DIP_MAX)
*pazim = sta_azim;
else { // reverse azimuth
*pazim = sta_azim - 180.0;
if (*pazim < 0.0)
*pazim += 360.0;
}
}
/* close angle grid file */
CloseGrid3dFile(&gdesc, &fp_grid, &fp_hdr);
return (0);
}
/** function to generate normally distributed deviate with zero mean and unit variance */
double normal_dist_deviate() {
static int iset = 0;
static float gset;
double fac, r, v1, v2;
if (iset == 0) {
do {
v1 = get_rand_double(-1.0, 1.0);
v2 = get_rand_double(-1.0, 1.0);
r = v1 * v1 + v2*v2;
} while (r >= 1.0);
fac = sqrt(-2.0 * log(r) / r);
gset = v1 * fac;
iset = 1;
return v2 * fac;
} else {
iset = 0;
return gset;
}
}
/** function to test normal_dist_deviate function */
#define NUM_BIN 21
#define WIDTH 3.0
void test_normal_dist_deviate() {
long nmax = 210000;
long n, m;
long ibin[NUM_BIN];
double test;
double dbin, binmax[NUM_BIN];
int sum_one_std;
dbin = 2.0 / (float) NUM_BIN;
for (n = 0; n < NUM_BIN; n++) {
ibin[n] = 0;
binmax[n] = WIDTH * ((double) (n + 1) * dbin - 1.0);
}
for (n = 0; n < nmax; n++) {
test = normal_dist_deviate();
m = 0;
while (test > binmax[m] && m < NUM_BIN - 1)
m++;
ibin[m]++;
}
sum_one_std = 0;
fprintf(stdout,
"\nnormal_dist_deviate function test (samples= %ld)\n", nmax);
fprintf(stdout, " Bin -Inf,%lf N=%ld\n", binmax[0], ibin[0]);
for (n = 1; n < NUM_BIN - 1; n++) {
fprintf(stdout,
" Bin %lf,%lf N=%ld\n", binmax[n - 1], binmax[n], ibin[n]);
if (binmax[n - 1] >= -1.0 && binmax[n] <= 1.0)
sum_one_std += ibin[n];
}
fprintf(stdout,
" Bin %lf,Inf N=%ld\n", binmax[NUM_BIN - 2],
ibin[NUM_BIN - 1]);
fprintf(stdout,
"Percent in range (-1,1) %lf\n", (double) sum_one_std / (double) nmax);
}
/** function to generate and display "traditional" statistics from grid file */
int GenTraditionStats(GridDesc *pgrid, Vect3D *pexpect, Mtrx3D *pcov,
FILE * fpgrid) {
int istat;
/* allocate grid buffer */
pgrid->buffer = AllocateGrid(pgrid);
if (pgrid->buffer == NULL) {
nll_puterr(
"ERROR: allocating memory for 3D PDF grid buffer.");
exit(EXIT_ERROR_MEMORY);
}
/* create grid array access pointers */
pgrid->array = CreateGridArray(pgrid);
if (pgrid->array == NULL) {
nll_puterr(
"ERROR: creating array for accessing 3D PDF grid buffer.");
exit(EXIT_ERROR_MEMORY);
}
/* read PDF grid */
if ((istat = ReadGrid3dBuf(pgrid, fpgrid)) < 0) {
nll_puterr("ERROR: reading PDF grid from disk.");
exit(EXIT_ERROR_IO);
}
/* calculate expectation */
*pexpect = CalcExpectation(pgrid, NULL);
if (message_flag >= 3) {
sprintf(MsgStr, "EXPECTATION { x %lf y %lf z %lf }",
pexpect->x, pexpect->y, pexpect->z);
nll_putmsg(3, MsgStr);
}
/* calculate covariance matrix */
*pcov = CalcCovariance(pgrid, pexpect, NULL);
if (message_flag >= 3) {
sprintf(MsgStr, "COVARIANCE: {");
nll_putmsg(3, MsgStr);
sprintf(MsgStr, " xx: %lf xy: %lf xz: %lf",
pcov->xx, pcov->xy, pcov->xz);
nll_putmsg(3, MsgStr);
sprintf(MsgStr, " yx: %lf yy: %lf yz: %lf",
pcov->yx, pcov->yy, pcov->yz);
nll_putmsg(3, MsgStr);
sprintf(MsgStr, " zx: %lf zy: %lf zz: %lf",
pcov->zx, pcov->zy, pcov->zz);
nll_putmsg(3, MsgStr);
sprintf(MsgStr, "}");
nll_putmsg(3, MsgStr);
}
/* clean up */
FreeGrid(pgrid);
DestroyGridArray(pgrid);
return (0);
}
/** function to calculate the expectation (mean) of a PDF grid */
Vect3D CalcExpectation(GridDesc* pgrid, FILE * fpgrid) {
int ix, iy, iz;
GRID_FLOAT_TYPE val;
double volume;
Vect3D expect = {0.0, 0.0, 0.0};
/* cannot calculate for misfit grid */
if (pgrid->type == GRID_MISFIT) {
expect.x = expect.y = expect.z = -LARGE_DOUBLE;
return (expect);
}
for (ix = 0; ix < pgrid->numx; ix++) {
for (iy = 0; iy < pgrid->numy; iy++) {
for (iz = 0; iz < pgrid->numz; iz++) {
if (fpgrid != NULL)
val = ReadGrid3dValue(fpgrid,
ix, iy, iz, pgrid, 0);
else
val = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz];
expect.x += (double) val * (double) ix;
expect.y += (double) val * (double) iy;
expect.z += (double) val * (double) iz;
}
}
}
volume = pgrid->dx * pgrid->dy * pgrid->dz;
expect.x = pgrid->origx + expect.x * pgrid->dx * volume;
expect.y = pgrid->origy + expect.y * pgrid->dy * volume;
expect.z = pgrid->origz + expect.z * pgrid->dz * volume;
return (expect);
}
/** function to calculate the covariance a PDF grid */
Mtrx3D CalcCovariance_OLD(GridDesc* pgrid, Vect3D* pexpect, FILE * fpgrid) {
int ix, iy, iz;
double val;
double x, y, z, xx, xy, xz, yy, yz, zz;
double volume;
Mtrx3D cov = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
/* cannot calculate for misfit grid */
if (pgrid->type == GRID_MISFIT) {
cov.xx = cov.xy = cov.xz =
cov.yx = cov.yy = cov.yz =
cov.zx = cov.zy = cov.zz
= -LARGE_DOUBLE;
return (cov);
}
/* calculate covariance following eq. (6-12), T & V, 1982 */
for (ix = 0; ix < pgrid->numx; ix++) {
x = pgrid->origx + (double) ix * pgrid->dx;
xx = x * x;
for (iy = 0; iy < pgrid->numy; iy++) {
y = pgrid->origy + (double) iy * pgrid->dy;
yy = y * y;
xy = x * y;
for (iz = 0; iz < pgrid->numz; iz++) {
z = pgrid->origz + (double) iz * pgrid->dz;
xz = x * z;
yz = y * z;
zz = z * z;
if (fpgrid != NULL)
val = ReadGrid3dValue(fpgrid, ix, iy, iz, pgrid, 0);
else
val = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz];
if (val < 0.0) {
printf("ERROR: CalcCovariance: Grid value < 0: ixyz= %d %d %d value= %g\n", ix, iy, iz, val);
continue;
}
cov.xx += (double) val * xx;
cov.xy += (double) val * xy;
cov.xz += (double) val * xz;
cov.yy += (double) val * yy;
cov.yz += (double) val * yz;
cov.zz += (double) val * zz;
}
}
}
volume = pgrid->dx * pgrid->dy * pgrid->dz;
//printf("DEBUG: cov.yy = cov.yy(%g) * volume(%g) (= %g) - pexpect->y(%g) * pexpect->y (= %g)\n", cov.yy, volume, cov.yy * volume, pexpect->y, pexpect->y * pexpect->y);
cov.xx = cov.xx * volume - pexpect->x * pexpect->x;
cov.xy = cov.xy * volume - pexpect->x * pexpect->y;
cov.xz = cov.xz * volume - pexpect->x * pexpect->z;
cov.yx = cov.xy;
cov.yy = cov.yy * volume - pexpect->y * pexpect->y;
cov.yz = cov.yz * volume - pexpect->y * pexpect->z;
cov.zx = cov.xz;
cov.zy = cov.yz;
cov.zz = cov.zz * volume - pexpect->z * pexpect->z;
//printf("DEBUG: CalcCovariance: volume= %g cov.yy= %g\n", volume, cov.yy);
return (cov);
}
/** function to calculate the covariance a PDF grid */
Mtrx3D CalcCovariance(GridDesc* pgrid, Vect3D* pexpect, FILE * fpgrid) {
int ix, iy, iz;
double val;
double x, y, z, xx, xy, xz, yy, yz, zz;
double volume;
Mtrx3D cov = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
/* cannot calculate for misfit grid */
if (pgrid->type == GRID_MISFIT) {
cov.xx = cov.xy = cov.xz =
cov.yx = cov.yy = cov.yz =
cov.zx = cov.zy = cov.zz
= -LARGE_DOUBLE;
return (cov);
}
/* calculate covariance following eq. (6-12), T & V, 1982 */
for (ix = 0; ix < pgrid->numx; ix++) {
x = pgrid->origx + (double) ix * pgrid->dx - pexpect->x;
xx = x * x;
for (iy = 0; iy < pgrid->numy; iy++) {
y = pgrid->origy + (double) iy * pgrid->dy - pexpect->y;
yy = y * y;
xy = x * y;
for (iz = 0; iz < pgrid->numz; iz++) {
z = pgrid->origz + (double) iz * pgrid->dz - pexpect->z;
xz = x * z;
yz = y * z;
zz = z * z;
if (fpgrid != NULL)
val = ReadGrid3dValue(fpgrid, ix, iy, iz, pgrid, 0);
else
val = ((GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz];
if (val < 0.0) {
printf("ERROR: CalcCovariance: Grid value < 0: ixyz= %d %d %d value= %g\n", ix, iy, iz, val);
continue;
}
cov.xx += (double) val * xx;
cov.xy += (double) val * xy;
cov.xz += (double) val * xz;
cov.yy += (double) val * yy;
cov.yz += (double) val * yz;
cov.zz += (double) val * zz;
}
}
}
volume = pgrid->dx * pgrid->dy * pgrid->dz;
//printf("DEBUG: cov.yy = cov.yy(%g) * volume(%g) (= %g) - pexpect->y(%g) * pexpect->y (= %g)\n", cov.yy, volume, cov.yy * volume, pexpect->y, pexpect->y * pexpect->y);
cov.xx = cov.xx * volume;
cov.xy = cov.xy * volume;
cov.xz = cov.xz * volume;
cov.yx = cov.xy;
cov.yy = cov.yy * volume;
cov.yz = cov.yz * volume;
cov.zx = cov.xz;
cov.zy = cov.yz;
cov.zz = cov.zz * volume;
//printf("DEBUG: CalcCovariance: volume= %g cov.yy= %g\n", volume, cov.yy);
return (cov);
}
/** function to calculate the covariance of a set of samples */
Mtrx3D CalcCovarianceSamples(float* fdata, int nSamples, Vect3D * pexpect) {
//printf("GeometryMode %s\n", GeometryMode == MODE_GLOBAL ? "MODE_GLOBAL" : "MODE_RECT");
if (GeometryMode == MODE_GLOBAL)
return (CalcCovarianceSamplesGlobal(fdata, nSamples, pexpect));
else
return (CalcCovarianceSamplesRect(fdata, nSamples, pexpect));
}
/** function to read expectation and covariance from a hyp file */
int ReadHypStatistics(FILE **pfpio, char* fnroot_in,
Vect3D* pmax_like, Vect3D* pexpect,
Mtrx3D* pcov, Ellipsoid3D *pellipsoid,
ArrivalDesc* parrivals, int *pnarrivals) {
char fn_in[FILENAME_MAX];
static HypoDesc hypo;
/* open hypocenter file if necessary */
if (*pfpio == NULL) {
sprintf(fn_in, "%s.hyp", fnroot_in);
if ((*pfpio = fopen(fn_in, "r")) == NULL) {
nll_puterr("ERROR: opening hypocenter file.");
return (EOF);
}
NumFilesOpen++;
}
/* read next hypocenter */
if (GetHypLoc(*pfpio, fnroot_in, &hypo, parrivals, pnarrivals, 1, NULL, 0) != EOF) {
pmax_like->x = hypo.x;
pmax_like->y = hypo.y;
pmax_like->z = hypo.z;
*pexpect = hypo.expect;
*pcov = hypo.cov;
*pellipsoid = hypo.ellipsoid;
return (0);
}
/* end of file */
fclose(*pfpio);
NumFilesOpen--;
return (EOF);
}
/** function to read hypocenter description from a single event hyp file */
int ReadHypoDesc(char* fnroot_in, HypoDesc *phypo) {
char fn_in[FILENAME_MAX];
FILE *fp_io;
/* open hypocenter file if necessary */
sprintf(fn_in, "%s.hyp", fnroot_in);
if ((fp_io = fopen(fn_in, "r")) == NULL) {
nll_puterr2("ERROR: opening hypocenter file:", fnroot_in);
return (-1);
}
NumFilesOpen++;
// read next hypocenter
ArrivalDesc* parrivals = NULL;
int *pnarrivals = NULL;
int istat = GetHypLoc(fp_io, fnroot_in, phypo, parrivals, pnarrivals, 0, NULL, 0);
fclose(fp_io);
NumFilesOpen--;
return (istat); // -1 if error opening hypo file, EOF if EOF error reading hypo file, 0 otherwise
}
/** function to read mechanism from a hyp file */
int ReadFocalMech(FILE **pfpio, char* fnroot_in,
FocalMech* pfocalMech,
ArrivalDesc* parrivals, int *pnarrivals) {
char fn_in[FILENAME_MAX];
static HypoDesc hypo;
/* open hypocenter file if necessary */
if (*pfpio == NULL) {
sprintf(fn_in, "%s.hyp", fnroot_in);
if ((*pfpio = fopen(fn_in, "r")) == NULL) {
nll_puterr("ERROR: opening hypocenter file.");
return (EOF);
}
NumFilesOpen++;
}
/* read next hypocenter */
if (GetHypLoc(*pfpio, fnroot_in, &hypo, parrivals, pnarrivals, 1, NULL, 0) != EOF) {
*pfocalMech = hypo.focMech;
return (0);
}
/* end of file */
fclose(*pfpio);
NumFilesOpen--;
return (EOF);
}
/** function to read arrivals with first-motions readings from a hyp file
*
* returns ArrivalDesc array containing only arrivals with first motion readings
* readings are converted to "+" or "-"
*
*/
int ReadFirstMotionArrivals(FILE **pfpio, char* fnroot_in, ArrivalDesc* parrivals, int *pnarrivals) {
char fn_in[FILENAME_MAX];
static HypoDesc hypo;
// open hypocenter file if necessary
if (*pfpio == NULL) {
sprintf(fn_in, "%s.hyp", fnroot_in);
if ((*pfpio = fopen(fn_in, "r")) == NULL) {
nll_puterr("ERROR: opening hypocenter file.");
return (EOF);
}
NumFilesOpen++;
}
// read next hypocenter
if (GetHypLoc(*pfpio, fnroot_in, &hypo, parrivals, pnarrivals, 1, NULL, 0) != EOF) {
// compact arrival array to contain only those with first-motion readings
int naccept = 0;
ArrivalDesc* parr = parrivals;
for (int narr = 0; narr < *pnarrivals; narr++) {
if (strstr("CcUu+", parr->first_mot)) { // follows fmamp conventions in fmamp/read_input.c
strcpy(parr->first_mot, "+");
parrivals[naccept] = *parr;
naccept++;
} else if (strstr("DdRr-", parr->first_mot)) { // follows fmamp conventions in fmamp/read_input.c
strcpy(parr->first_mot, "-");
parrivals[naccept] = *parr;
naccept++;
}
parr++;
}
*pnarrivals = naccept;
return (0);
}
// end of file
fclose(*pfpio);
NumFilesOpen--;
return (EOF);
}
/** function to trim leading and trailing blanks from character strings */
int TrimString(char* line) {
char *line0, *line1, *pendchr;
/* find end of string */
pendchr = strchr(line, '\0');
if (pendchr == NULL)
return (-1);
/* remove leading spaces */
while (isspace(line[0])) {
line0 = line + 1;
line1 = line;
do
*(line1++) = *line0; while (*(line0++) != '\0');
}
/* re-find end of string */
pendchr = strchr(line, '\0');
if (pendchr == NULL)
return (-1);
/* remove trailing spaces */
// AJL 20071018 while (--pendchr > line && isspace(*pendchr))
while (--pendchr > line && (isspace(*pendchr) || *pendchr == '\t' || *pendchr == '\n' || *pendchr == '\r'))
*pendchr = '\0';
return (pendchr - line);
}
/** function to check for blank line */
int LineIsBlank(char *line) {
char* pstr;
pstr = line;
while (*pstr) {
if (!isspace(*pstr++))
return (0);
}
return (1);
}
/** function to read FORTRAN character format fields */
int ReadFortranString(char* line, int istart, int ilen, char* string_in) {
char chrtmp[MAXLINE], *chrpos;
/* check for null char before end of read */
chrpos = strchr(line, '\0');
if (chrpos - line < istart + ilen - 1)
return (-1);
/* copy field to temp string */
strncpy(chrtmp, line + (istart - 1), ilen);
chrtmp[ilen] = '\0';
/* check for blank field */
/* for (n = 0; n < ilen; n++) {
if (chrtmp[n] != ' ')
break;
}
if (n == ilen) {
for (n = 0; n < ilen; n++)
string_in[n] = ' ';
return(1);
}
*/
strncpy(string_in, chrtmp, ilen);
string_in[ilen] = '\0';
return (1);
}
/** function to read FORTRAN integer format fields */
int ReadFortranInt(char* line, int istart, int ilen, int* pintval) {
char chrtmp[MAXLINE], *chrpos;
int istat, n;
/* check for null char before end of read */
chrpos = strchr(line, '\0');
if (chrpos - line < istart + ilen - 1)
return (-1);
/* copy field to temp string */
strncpy(chrtmp, line + (istart - 1), ilen);
chrtmp[ilen] = '\0';
/* check for blank field */
for (n = 0; n < ilen; n++) {
if (chrtmp[n] != ' ')
break;
}
if (n == ilen) {
*pintval = 0;
return (1);
}
istat = sscanf(chrtmp, "%d", pintval);
return (istat);
}
/** function to read FORTRAN real format fields */
int ReadFortranReal(char* line, int istart, int ilen, double* pdblval) {
char chrtmp[MAXLINE], *chrpos;
int istat, n;
/* check for null char before end of read */
chrpos = strchr(line, '\0');
if (chrpos - line < istart + ilen - 1)
return (-1);
/* copy field to temp string */
strncpy(chrtmp, line + (istart - 1), ilen);
chrtmp[ilen] = '\0';
/* check for blank field */
for (n = 0; n < ilen; n++) {
if (chrtmp[n] != ' ')
break;
}
if (n == ilen) {
*pdblval = 0.0;
return (1);
}
istat = sscanf(chrtmp, "%lf", pdblval);
return (istat);
}
/** function to convert phase error to hypo71 style quality */
int Err2Qual(ArrivalDesc * arrival) {
int errLevel;
/* find error level with error >= arrival error */
for (errLevel = 0; errLevel < NumQuality2ErrorLevels; errLevel++) {
if (arrival->error <= Quality2Error[errLevel]) {
arrival->quality = errLevel;
return (errLevel);
}
}
/* not found or no quality/error values available */
return (-1);
}
/** function to convert quality to error */
void Qual2Err(ArrivalDesc * arrival) {
/* set error fields */
strcpy(arrival->error_type, "GAU");
if (arrival->quality >= 0 &&
arrival->quality < NumQuality2ErrorLevels) {
arrival->error = Quality2Error[arrival->quality];
} else {
arrival->error = Quality2Error[NumQuality2ErrorLevels - 1];
nll_puterr("WARNING: invalid arrival quality.");
}
}
/** function to read Quality2Error values ***/
int GetQuality2Err(char* line1) {
int istat, ierr, nlev;
double qual2err;
char frmt[MAXLINE] = "%lf";
char frmttmp[MAXLINE];
while ((istat = sscanf(line1, frmt, &qual2err)) == 1) {
Quality2Error[NumQuality2ErrorLevels++] = qual2err;
sprintf(frmttmp, "%%*f %s", frmt);
strcpy(frmt, frmttmp);
}
if (message_flag >= 2) {
sprintf(MsgStr, "NLLoc LOCQUAL2ERR:");
nll_putmsg(2, MsgStr);
}
ierr = 0;
for (nlev = 0; nlev < NumQuality2ErrorLevels; nlev++) {
if (message_flag >= 2) {
sprintf(MsgStr, " %d -> %lf", nlev, Quality2Error[nlev]);
nll_putmsg(2, MsgStr);
}
if ((istat = checkRangeDouble("QUAL2ERR", "Quality2Error",
Quality2Error[nlev], 1, 0.0, 0, 0.0)) != 0)
ierr = -1;
}
if (ierr < 0)
return (-1);
return (0);
}
/** function to check if phase_in matches phase_check
true if phase_in == phase_check
true if phase_in is in phase ID list for phase_check */
int IsPhaseID(char *phase_in, char *phase_check) {
int npha_id;
char test_str[PHASE_LABEL_LEN + 4];
//printf("phase_in %s, phase_check %s, ", phase_in, phase_check);
/* check for blank phase_in */
if (strstr(" ", phase_in) != NULL) {
//printf(" NO - BLANK\n");
return (0);
}
// check if phase_in == phase_check (AJL 20041201 added)
if (strcmp(phase_in, phase_check) == 0) {
//printf(" YES (%s %s)\n", phase_in, phase_check);
return (1);
}
// check if phase_in is in phase ID list for phase_check
removeSpace(phase_in);
sprintf(test_str, " %s ", phase_in);
for (npha_id = 0; npha_id < NumPhaseID; npha_id++) {
//printf(" compare (<%s> <%s>)\n", PhaseID[npha_id].id_string, test_str);
if (strcmp(PhaseID[npha_id].phase, phase_check) == 0) {
if (strstr(PhaseID[npha_id].id_string, test_str) != NULL) {
//printf(" YES (%s %s)\n", PhaseID[npha_id].id_string, phase_in);
return (1);
}
}
}
//printf(" NO\n");
return (0);
}
/** function to evaluate phase ID from phase ID lists */
// 20161004 AJL - moved here from NLLocLib.c
int EvalPhaseID(char *phase_out, char *phase_in) {
int npha_id;
for (npha_id = 0; npha_id < NumPhaseID; npha_id++) {
if (IsPhaseID(phase_in, PhaseID[npha_id].phase)) {
if (phase_out != NULL)
strcpy(phase_out, PhaseID[npha_id].phase);
return (1);
}
}
if (phase_out != NULL)
strcpy(phase_out, phase_in);
return (0); // returned unchanged
}
/** function remove whitespace from string */
void removeSpace(char *str) {
int n, m;
n = 0;
while (str[n] != '\0' && n < 1000000)
if (isspace(str[n])) {
m = n;
while (str[m] != '\0' && m < 1000000) {
str[m] = str[m + 1];
m++;
}
} else {
n++;
}
}
/** function to read fpfit summary record to HypoDesc structure */
int ReadFpfitSum(FILE *fp_in, HypoDesc * phypo) {
int istat;
char *cstat;
double mag, dtemp;
double deg, dmin;
char strNS[2], strMagType[2];
static char line[MAXLINE_LONG];
/* read next line */
cstat = fgets(line, MAXLINE_LONG, fp_in);
if (cstat == NULL)
return (EOF);
/* read hypocenter parameters */
istat = 0;
istat += ReadFortranInt(line, 1, 2, &phypo->year);
if (phypo->year < 20)
phypo->year += 2000;
if (phypo->year < 100)
phypo->year += 1900;
istat += ReadFortranInt(line, 3, 2, &phypo->month);
istat += ReadFortranInt(line, 5, 2, &phypo->day);
istat += ReadFortranInt(line, 8, 2, &phypo->hour);
istat += ReadFortranInt(line, 10, 2, &phypo->min);
istat += ReadFortranReal(line, 12, 6, &phypo->sec);
istat += ReadFortranReal(line, 18, 3, &deg);
istat += ReadFortranString(line, 21, 1, strNS);
istat += ReadFortranReal(line, 22, 5, &dmin);
phypo->dlat = deg + dmin / 60.0;
if (strncmp(strNS, "S", 1) == 0)
phypo->dlat = -phypo->dlat;
istat += ReadFortranReal(line, 27, 4, &deg);
istat += ReadFortranString(line, 31, 1, strNS);
istat += ReadFortranReal(line, 32, 5, &dmin);
phypo->dlong = deg + dmin / 60.0;
if (strncmp(strNS, "W", 1) == 0)
phypo->dlong = -phypo->dlong;
istat += ReadFortranReal(line, 37, 7, &phypo->depth);
istat += ReadFortranReal(line, 46, 5, &mag);
istat += ReadFortranInt(line, 51, 3, &phypo->nreadings);
istat += ReadFortranReal(line, 54, 4, &dtemp);
phypo->gap = (int) 0.5 + dtemp;
istat += ReadFortranReal(line, 58, 5, &phypo->dist);
istat += ReadFortranReal(line, 63, 5, &phypo->rms);
/* hypoinverse horiz and vertical error are converted to ellipsoid,
this is not correct statistically */
istat += ReadFortranReal(line, 68, 5, &(phypo->ellipsoid.len1));
phypo->ellipsoid.az1 = 0.0;
phypo->ellipsoid.dip1 = 0.0;
phypo->ellipsoid.len2 = phypo->ellipsoid.len1;
phypo->ellipsoid.az2 = 90.0;
phypo->ellipsoid.dip2 = 0.0;
istat += ReadFortranReal(line, 73, 5, &(phypo->ellipsoid.len3));
istat += ReadFortranString(line, 80, 1, strMagType);
/* focal mechanism parameters */
istat += ReadFortranReal(line, 82, 3, &phypo->focMech.dipDir);
istat += ReadFortranReal(line, 86, 2, &phypo->focMech.dipAng);
istat += ReadFortranReal(line, 88, 4, &phypo->focMech.rake);
istat += ReadFortranReal(line, 94, 4, &phypo->focMech.misfit);
istat += ReadFortranInt(line, 99, 3, &phypo->focMech.nObs);
istat += ReadFortranReal(line, 103, 5, &phypo->focMech.misfit90);
istat += ReadFortranReal(line, 109, 4, &phypo->focMech.staDist);
istat += ReadFortranReal(line, 114, 4, &phypo->focMech.ratioMH);
istat += ReadFortranReal(line, 120, 2, &phypo->focMech.conf90strike);
istat += ReadFortranReal(line, 123, 2, &phypo->focMech.conf90dip);
istat += ReadFortranReal(line, 126, 2, &phypo->focMech.conf90rake);
istat += ReadFortranString(line, 128, 1, phypo->focMech.convFlag);
istat += ReadFortranString(line, 129, 1, phypo->focMech.multSolFlag);
return (istat);
}
//========================================================
// DD
// see hypoDD doc (Open File Report 01-113)
/** function to read hypoDD Initial hypocenter input format to HypoDesc structure */
/* example
19850124 2195871 37.8832 -122.2415 9.800 1.4 0.15 0.51 0.02 38542
19911126 14274555 37.8738 -122.2432 9.950 1.4 0.22 0.53 0.09 238298
*/
/*
One event per line: DATE, TIME, LAT, LON, DEP, MAG, EH, EV, RMS, ID
Parameter Description:
DATE Concatenated origin date (YYYYMMDD; year, month and day).
TIME Concatenated origin time (HHMMSSSS; hour, minute and seconds).
LAT, LON, DEP Latitude, longitude, depth (km).
MAG Magnitude (set to 0.0 if not available).
EH, EV Horizontal and vertical error (km) of original location (set to 0.0 if not available).
RMS Residual rms (s) (set to 0.0 is not available).
ID Event identification [I9].
*/
int ReadHypoDDInitHypo(FILE *fp_in, HypoDesc *phypo, int n_proj) {
int istat;
char *cstat;
double err_horiz, err_vert;
static char line[MAXLINE_LONG];
/* read next line */
cstat = fgets(line, MAXLINE_LONG, fp_in);
if (cstat == NULL)
return (EOF);
// DEBUG
printf("%s\n", line);
/* read hypocenter parameters */
istat = 0;
istat += ReadFortranInt(line, 1, 4, &phypo->year);
istat += ReadFortranInt(line, 5, 2, &phypo->month);
istat += ReadFortranInt(line, 7, 2, &phypo->day);
istat += ReadFortranInt(line, 11, 2, &phypo->hour);
istat += ReadFortranInt(line, 13, 2, &phypo->min);
if (line[16] == '.') {
// non-standard HypoDD: decimal point in seconds
// YMD HMS str1 str2 lat lon depth mag errH errZ rms event_id
// 20200414 101739.37 XXX XXX 31.705758 -104.035262 6.996 2.7 -1 -1 -1 1001
istat += ReadFortranReal(line, 15, 5, &phypo->sec);
} else {
istat += ReadFortranReal(line, 15, 4, &phypo->sec);
phypo->sec /= 100.0;
}
istat += sscanf(line, "%*s %*s %lf %lf %lf %lf %lf %lf %lf %ld",
&phypo->dlat, &phypo->dlong, &phypo->depth, &phypo->amp_mag,
&err_horiz, &err_vert, &phypo->rms, &phypo->event_id);
// DEBUG
printf("%d %d %d %d %d %f %s %s %f %f %f %f %f %f %f %ld\n", phypo->year, phypo->month, phypo->day, phypo->hour, phypo->min, phypo->sec, "X", "X", phypo->dlat, phypo->dlong, phypo->depth, phypo->amp_mag, err_horiz, err_vert, phypo->rms, phypo->event_id);
//phypo->depth -= 8.0;
/* hypoDD horiz and vertical error are converted to ellipsoid,
this is not correct statistically */
phypo->ellipsoid.az1 = 0.0;
phypo->ellipsoid.dip1 = 0.0;
phypo->ellipsoid.len1 = phypo->ellipsoid.len2 = err_horiz;
phypo->ellipsoid.az2 = 90.0;
phypo->ellipsoid.dip2 = 0.0;
phypo->ellipsoid.len3 = err_vert;
/* set additional hypocenter fields */
latlon2rect(n_proj, phypo->dlat, phypo->dlong, &(phypo->x), &(phypo->y));
phypo->z = phypo->depth;
phypo->dotime = 0.0;
return (istat == 14 ? 1 : -1);
}
/** function to write hypoDD Initial hypocenter input format to out */
/* example
19850124 2195871 37.8832 -122.2415 9.800 1.4 0.15 0.51 0.02 38542 x y z
19911126 14274555 37.8738 -122.2432 9.950 1.4 0.22 0.53 0.09 238298
*/
int WriteHypoDDInitHypo(FILE *fp_out, HypoDesc * phypo) {
fprintf(fp_out,
"%4.4d%2.2d%2.2d %2.2d%2.2d%4.4d %9.4f %10.4f %10.3f %4.1f %7.2f %7.2f %6.2f %10ld %10.4f %10.4f %10.4f\n",
phypo->year, phypo->month, phypo->day,
phypo->hour, phypo->min, (int) (phypo->sec * 100.0 + 0.5),
phypo->dlat, phypo->dlong, phypo->depth, phypo->amp_mag,
phypo->ellipsoid.len1, phypo->ellipsoid.len3, phypo->rms, phypo->event_id,
phypo->x, phypo->y, phypo->z);
return (0);
}
/** function to write hypoDD Cross correlation differential time input (e.g. file dt.cc) format to out */
/* example:
# 28136 46442 -0.174000
# 402093 402094 -0.009000
NCCMO 0.000000 -1.994625 ??
NCCMO -0.038245201 0.63 P
NCCRP -0.062200069 0.78 P
NCJBG -0.020649910 0.60 P
NCJPS -0.011000156 0.50 P
*/
int WriteHypoDDXCorrDiff(FILE *fp_out, int num_arrivals, ArrivalDesc *arrival, HypoDesc * hypos) {
int narr;
long dd_event_id_1, dd_event_id_2;
double dd_otime_corr;
ArrivalDesc *parr;
dd_event_id_1 = dd_event_id_2 = -1;
for (narr = 0; narr < num_arrivals; narr++) {
parr = arrival + narr;
if (parr->flag_ignore)
continue;
if (parr->dd_event_id_1 != dd_event_id_1 || parr->dd_event_id_2 != dd_event_id_2) {
dd_event_id_1 = parr->dd_event_id_1;
dd_event_id_2 = parr->dd_event_id_2;
// set new otime corr OTC based on current perturbatios to otimes
// original OTC was incorporated into dd_dtime when reading dt file.
dd_otime_corr = hypos[parr->dd_event_index_1].dotime
- hypos[parr->dd_event_index_2].dotime;
fprintf(fp_out, "# %8ld %8ld %13.6lf\n",
dd_event_id_1, dd_event_id_2, dd_otime_corr);
}
fprintf(fp_out, "%-8s %12lf %7lf %4s\n",
parr->label, parr->dd_dtime, parr->weight, parr->phase);
}
return (0);
}
/** function to write arrival */
int WriteDiffArrival(FILE* fpio, HypoDesc* hypos, ArrivalDesc* parr, int iWriteType) {
int istat;
double sta_azim, ray_azim;
double dd_otime_corr;
/* write observation part of phase line */
// set new otime corr OTC based on current perturbatios to otimes
// original OTC was incorporated into dd_dtime when reading dt file.
dd_otime_corr = hypos[parr->dd_event_index_1].dotime
- hypos[parr->dd_event_index_2].dotime;
istat = fprintf(fpio,
"%-6.6s %-4.4s %-4.4s %-6.6s %8ld %8ld %9.5lf %9.5lf",
parr->label,
parr->inst,
parr->comp,
parr->phase,
parr->dd_event_id_1, parr->dd_event_id_2,
parr->dd_dtime - dd_otime_corr,
parr->weight
);
if (istat < 0)
return (-1);
if (iWriteType == IO_ARRIVAL_ALL) {
/* convert ray aziumuth to geographic direction */
sta_azim = rect2latlonAngle(0, parr->azim);
ray_azim = rect2latlonAngle(0, parr->ray_azim);
/* write calculated part of phase line */
istat = fprintf(fpio,
" > %9.5lf %9.5lf %9.4lf %9.4lf %9.4lf %9.4lf %6.2lf %5.1lf %5.1lf %2d",
parr->pred_travel_time, parr->residual,
parr->station.x, parr->station.y,
parr->station.z,
GeometryMode == MODE_GLOBAL ? parr->dist * KM2DEG : parr->dist,
sta_azim,
ray_azim, parr->ray_dip, parr->ray_qual
);
if (istat < 0)
return (-1);
}
istat = fprintf(fpio, "\n");
if (istat < 0)
return (-1);
return (0);
}
/** function to generate take-off angles from travel time grid
using a numerical gradient algorithm */
int CalcAnglesGradient(GridDesc* ptgrid, GridDesc* pagrid, int angle_mode, int grid_mode) {
int ix, iy, iz, edge_flagx = 0, edge_flagy = 0, iflag2D = 0;
double dx, dy, dz;
double xlow = 0.0, xhigh = 0.0;
double azim, dip;
int iqual;
TakeOffAngles angles = AnglesNULL;
/* write message */
sprintf(MsgStr, "Generating take-off angle grid...");
nll_putmsg(1, MsgStr);
if (grid_mode == GRID_TIME_2D) {
iflag2D = 1;
xlow = xhigh = 0.0;
}
/* estimate take-off angles from numerical gradients */
dx = pagrid->dx;
dy = pagrid->dy;
dz = pagrid->dz;
for (ix = 0; ix < pagrid->numx; ix++) {
/* 2D grids, store angles in ix = 0 sheet */
if (ix == 1 && iflag2D)
edge_flagx = 1;
if ((ix == 0 || ix == pagrid->numx - 1)
&& grid_mode == GRID_TIME)
edge_flagx = 1;
for (iy = 0; iy < pagrid->numy; iy++) {
if (iy == 0 || iy == pagrid->numy - 1)
edge_flagy = 1;
for (iz = 0; iz < pagrid->numz; iz++) {
/* no calculation for edges of grid */
if (edge_flagx || edge_flagy
|| iz == 0 || iz == pagrid->numz - 1) {
((GRID_FLOAT_TYPE ***) pagrid->array)[ix][iy][iz] = AnglesNULL.fval;
continue;
}
if (!iflag2D) {
xlow = ((GRID_FLOAT_TYPE ***) ptgrid->array)[ix - 1][iy][iz];
xhigh = ((GRID_FLOAT_TYPE ***) ptgrid->array)[ix + 1][iy][iz];
}
angles = GetGradientAngles(
((GRID_FLOAT_TYPE ***) ptgrid->array)[ix][iy][iz],
xlow,
xhigh,
((GRID_FLOAT_TYPE ***) ptgrid->array)[ix][iy - 1][iz],
((GRID_FLOAT_TYPE ***) ptgrid->array)[ix][iy + 1][iz],
/* intentional reversal of z
signs to get pos = up */
((GRID_FLOAT_TYPE ***) ptgrid->array)[ix][iy][iz + 1],
((GRID_FLOAT_TYPE ***) ptgrid->array)[ix][iy][iz - 1],
dx, dy, dz, iflag2D,
&azim, &dip, &iqual);
if (angle_mode == ANGLE_MODE_YES) {
((GRID_FLOAT_TYPE ***) pagrid->array)[ix][iy][iz] = angles.fval;
} else if (angle_mode == ANGLE_MODE_INCLINATION) {
((
GRID_FLOAT_TYPE ***) pagrid->array)[ix][iy][iz] = dip;
}
}
edge_flagy = 0;
}
edge_flagx = 0;
}
return (0);
}
/** function to generate take-off angles from time grid node values */
TakeOffAngles GetGradientAngles(double vcent, double xlow, double xhigh,
double ylow, double yhigh, double zlow, double zhigh,
double dx, double dy, double dz, int iflag2D,
double *pazim, double *pdip, int *piqual) {
double grad_low, grad_high, gradx, grady, gradz, azim, dip;
int iqualx, iqualy, iqualz, iqual, iflip;
TakeOffAngles angles = AnglesNULL;
/* calculate gradient of travel time and quality in Z direction */
grad_low = (vcent - zlow) / dz;
grad_high = (zhigh - vcent) / dz;
iqualz = CalcAnglesQuality(grad_low, grad_high);
gradz = (grad_low + grad_high) / 2.0;
gradz = -gradz; /* reverse sign to get take-off angle */
/* calculate gradient of travel time and quality in Y direction */
grad_low = (vcent - ylow) / dy;
grad_high = (yhigh - vcent) / dy;
iqualy = CalcAnglesQuality(grad_low, grad_high);
grady = (grad_low + grad_high) / 2.0;
grady = -grady; /* reverse sign to get take-off angle */
/* thats all for 2D grids */
if (iflag2D) {
/* calculate dip angle (range of 0 (down) to 180 (up)) */
//dip = atan2(grady, -gradz) / cRPD;
dip = atan2(fabs(grady), -gradz) / cRPD;
//dip = -dip; // TEST!
iflip = 0;
// 20201221 AJL - Bug fix: ray depart direction depend only on grady
if (grady > 0.0) { // ray departs source away from station
iflip = 1;
}
// 20201221 AJL - Bug fix: with atan2(<positive>, real) dip is restricted to 0-180 (atan2 restricted to 0-PI)
/*if (dip > 180.0) {
dip = dip - 180.0;
iflip = 1;
} else if (dip < 0.0) {
dip = -dip;
iflip = 1;
}*/
/* calculate azimuth polarity (1 or -1) relative to pos Y dir */
azim = iflip ? -1.0 : 1.0;
/* find combined quality - weighted average of component qual */
iqual = (fabs(grady) * (double) iqualy
+ fabs(gradz) * (double) iqualz)
/ (fabs(grady) + fabs(gradz));
/* set angles */
angles = SetTakeOffAngles(azim, dip, iqual);
*pazim = azim;
*pdip = dip;
*piqual = iqual;
return (angles);
}
/* calculate gradient of travel time and quality in X direction */
grad_low = (vcent - xlow) / dx;
grad_high = (xhigh - vcent) / dx;
iqualx = CalcAnglesQuality(grad_low, grad_high);
gradx = (grad_low + grad_high) / 2.0;
gradx = -gradx; /* reverse sign to get take-off angle */
/* find combined quality - weighted average of component qual */
iqual = (fabs(gradx) * (double) iqualx
+ fabs(grady) * (double) iqualy
+ fabs(gradz) * (double) iqualz)
/ (fabs(gradx) + fabs(grady) + fabs(gradz));
/* calculate dip angle (range of 0 (down) to 180 (up)) */
dip = atan2(sqrt(gradx * gradx + grady * grady), -gradz) / cRPD;
/* calculate azimuth angle (0 to 360) */
azim = atan2(gradx, grady) / cRPD;
if (azim < 0.0)
azim += 360.0;
angles = SetTakeOffAngles(azim, dip, iqual);
// return double angles values
*pazim = azim;
*pdip = dip;
*piqual = iqual;
return (angles);
}
/** function to estimate quality of take-off angle determination */
/* quality is: 0 if sign of A = grad_low and B = grad_high differ
0->10 as (2AB / (AA + BB)) -> 1;
*/
int CalcAnglesQuality(double grad_low, double grad_high) {
double ratio;
/* if both gradients are zero, return highest quality */
if (fabs(grad_low) + fabs(grad_high) < SMALL_DOUBLE)
return (10);
/* calculate quality */
ratio = 2.0 * grad_low * grad_high /
(grad_low * grad_low + grad_high * grad_high);
return (ratio > 0.0 ? (int) (10.01 * ratio) : 0);
}
// END - DD
//========================================================
// 20190509 AJL - following function moved here from NLLocLib.c
/** function to generate sample (scatter) of location PDF
*
* IMPORTANT: assumes integral of dvol * prob_den over grid = 1.0
*/
int GenEventScatterGrid(GridDesc* ptgrid, HypoDesc* phypo, ScatterParams* pscat, char* filename) {
FILE *fpio;
char fname[4 * FILENAME_MAX];
int ix, iy, iz;
double origx, origy, origz;
double dx, dy, dz, dvol;
double xval, yval, zval;
float fdata[4];
int tot_npoints = 0;
double xnpoints;
double probmax, prob_den;
/* return if no scatter samples requested */
if (pscat->npts < 1)
return (0);
sprintf(fname, "%s.scat", filename);
/* write message */
if (message_flag >= 3) {
nll_putmsg(3, "");
nll_putmsg2(3, "Generating event scatter file:", fname);
}
/* open scatter file */
// 20190509 AJL sprintf(fname, "%s.loc.scat", filename);
if ((fpio = fopen(fname, "w")) == NULL) {
nll_puterr("ERROR: opening scatter output file.");
return (-1);
} else {
NumFilesOpen++;
}
/* skip header record (used later to store number of samples taken) */
fseek(fpio, 4 * sizeof (float), SEEK_SET);
/* generate N=Scatter->npts events with prob P=prob_den/probmax at */
/* uniformly-randomly chosen grid locations */
origx = ptgrid->origx;
origy = ptgrid->origy;
origz = ptgrid->origz;
dx = ptgrid->dx;
dy = ptgrid->dy;
dz = ptgrid->dz;
dvol = dx * dy * dz;
probmax = phypo->probmax;
for (ix = 0; ix < ptgrid->numx; ix++) {
for (iy = 0; iy < ptgrid->numy; iy++) {
for (iz = 0; iz < ptgrid->numz; iz++) {
//printf("DEBUG: message_flag %d, ix, iy, iz %d %d %d %d\n", message_flag, ix, iy, iz, tot_npoints);
prob_den = ((GRID_FLOAT_TYPE ***) ptgrid->array)[ix][iy][iz];
xnpoints = (double) pscat->npts * dvol * prob_den;
xval = origx + (double) ix * dx;
yval = origy + (double) iy * dy;
zval = origz + (double) iz * dz;
while (xnpoints > 0.0) {
if (xnpoints > 1.0 || xnpoints - (double) ((int) xnpoints) > get_rand_double(0.0, 1.0)) {
fdata[0] = (float) (xval + get_rand_double(-dx / 2.0, dx / 2.0));
fdata[1] = (float) (yval + get_rand_double(-dy / 2.0, dy / 2.0));
fdata[2] = (float) (zval + get_rand_double(-dz / 2.0, dz / 2.0));
fdata[3] = (float) prob_den;
fwrite(fdata, sizeof (float), 4, fpio);
tot_npoints++;
}
xnpoints -= 1.0;
}
}
}
}
/* write header information */
fseek(fpio, 0, SEEK_SET);
fwrite(&tot_npoints, sizeof (int), 1, fpio);
fdata[0] = (float) probmax;
fwrite(fdata, sizeof (float), 1, fpio);
fclose(fpio);
NumFilesOpen--;
/* write message */
if (message_flag >= 3) {
sprintf(MsgStr, " %d points generated.", tot_npoints);
nll_putmsg(3, MsgStr);
sprintf(MsgStr, " (%d points requested, dvol= %lf, probmax=%lf)",
pscat->npts, dvol, probmax);
nll_putmsg(3, MsgStr);
}
return (0);
}
/** function to calculate the integral over volume of a PDF grid */
double IntegrateGrid(GridDesc* pgrid, int flag_normalize) {
double integral = 0.0;
int ix, iy, iz;
double dvolume = pgrid->dx * pgrid->dy * pgrid->dz;
// integrate
for (ix = 0; ix < pgrid->numx; ix++) {
for (iy = 0; iy < pgrid->numy; iy++) {
for (iz = 0; iz < pgrid->numz; iz++) {
integral += dvolume * ((GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz];
}
}
}
//printf("DEBUG: IntegrateGrid: integral=%f\n", integral);
// normalize
if (flag_normalize && fabs(integral) > FLT_MIN) {
for (ix = 0; ix < pgrid->numx; ix++) {
for (iy = 0; iy < pgrid->numy; iy++) {
for (iz = 0; iz < pgrid->numz; iz++) {
((
GRID_FLOAT_TYPE ***) pgrid->array)[ix][iy][iz] /= integral;
}
}
}
}
return (integral);
}
// 20200122 AJL - following function moved here from NLLocLib.c
/** function to add arrival station to station list */
int addToStationList(SourceDesc *stations, int numStations, ArrivalDesc *arrival, int nArrivals, int iuse_phaseid_in_label, int i_check_station_has_XYZ_coords) {
int i, n, nAdded = 0;
// set default ignored flag, weight and nullname
for (n = 0; n < MAX_NUM_ARRIVALS; n++) {
(stations + n)->ignored = 1;
(stations + n)->station_weight = 1.0;
//strcpy((stations + n)->label, "");
}
char arrival_label[ARRIVAL_LABEL_LEN];
for (i = 0; i < nArrivals; i++) {
// 20200122 AJL - added
if (iuse_phaseid_in_label) {
sprintf(arrival_label, "%s#%s", (arrival + i)->label, (arrival + i)->phase);
} else {
strcpy(arrival_label, (arrival + i)->label);
}
// find station in list
n = 0;
for (; n < numStations; n++) {
if (strcmp((stations + n)->label, arrival_label) == 0) {
break; // already in list
}
}
// check arrival station has xyz coordinates
if (i_check_station_has_XYZ_coords) {
if (((arrival + i)->station).x < -LARGE_DOUBLE / 2.0 || ((arrival + i)->station).y < -LARGE_DOUBLE / 2.0 || ((arrival + i)->station).z < -LARGE_DOUBLE / 2.0) {
//sprintf(MsgStr, "ERROR: addToStationList: No xyz station coordinates available: cannot add station %s ", arrival_label);
//nll_puterr(MsgStr);
// 20230718 AJL - change to WARNING to avoid excessive console output
sprintf(MsgStr, "WARNING: addToStationList: No xyz station coordinates available: cannot add station %s ", arrival_label);
nll_putmsg(2, MsgStr);
continue;
}
}
// not found, add station to list
if (n == numStations) {
if (numStations >= MAX_NUM_ARRIVALS) {
sprintf(MsgStr, "ERROR: addToStationList: numStations (%d) >= MAX_NUM_ARRIVALS (%d): cannot add station %s ",
numStations, MAX_NUM_ARRIVALS, arrival_label);
nll_puterr(MsgStr);
//return (0); // 20101209 AJL - bug fix
continue;
}
*(stations + n) = (arrival + i)->station;
strcpy((stations + n)->label, arrival_label);
nAdded++;
numStations++;
if (message_flag >= 4) {
sprintf(MsgStr, "Added to station list: %s (%lf,%lf,%lf)",
(stations + n)->label, (stations + n)->x, (stations + n)->y, (stations + n)->z);
nll_putmsg(4, MsgStr);
}
}
if (!((arrival + i)->flag_ignore))
(stations + n)->ignored = 0;
}
return (numStations);
}
/** function to write station list to file */
int WriteStationList(FILE* fpio, SourceDesc *stations, int numStations) {
fprintf(fpio, "Label x y z lat lon depth\n");
ConvertSourceLoc(0, stations, numStations, 1, 1);
for (int n = 0; n < numStations; n++) {
fprintf(fpio, "%s %lf %lf %lf %lf %lf %lf\n",
(stations + n)->label, (stations + n)->x, (stations + n)->y, (stations + n)->z, (stations + n)->dlat, (stations + n)->dlong, (stations + n)->depth);
}
return (0);
}
/** function to read phase identification values ***/
int GetPhaseID(char* line1) {
int istat, ilen;
char *substr, *cpos;
if (NumPhaseID >= MAX_NUM_PHASE_ID) {
nll_puterr(
"LOCPHASEID: WARNING: maximum number of PhaseIDs reached, ignoring phase ID.");
return (-1);
}
if ((istat = sscanf(line1, "%s", PhaseID[NumPhaseID].phase)) != 1)
return (-1);
substr = strstr(line1, PhaseID[NumPhaseID].phase);
/* save phase id values with spaces at each end */
if ((cpos = strchr(substr, '\n')) != NULL)
*cpos = '\0';
sprintf(PhaseID[NumPhaseID].id_string, " %s ", substr + 1);
if ((ilen = strlen(PhaseID[NumPhaseID].id_string)) == 0)
return (-1);
sprintf(MsgStr, "LOCPHASEID:");
nll_putmsg(3, MsgStr);
sprintf(MsgStr, " Phase: %s PhaseID: <%s>",
PhaseID[NumPhaseID].phase,
PhaseID[NumPhaseID].id_string);
nll_putmsg(3, MsgStr);
NumPhaseID++;
return (0);
}
// 20200122 AJL - following function moved here from NLLocLib.h
/** function to set output file root name using arrival time or public_id */
int SetOutName(ArrivalDesc *arrival, char* out_file_root, char* out_file,
char* lastfile, int isec, int ipublic_id, char* public_id, int *pncount) {
char filename_ctr[10];
/* if (isec)
sprintf(out_file, "%s.%4.4d%2.2d%2.2d.%2.2d%2.2d%2.2d",
out_file_root, arrival->year, arrival->month, arrival->day,
arrival->hour, arrival->min, (int) arrival->sec);
else
sprintf(out_file, "%s.%4.4d%2.2d%2.2d.%2.2d%2.2d",
out_file_root, arrival->year, arrival->month, arrival->day,
arrival->hour, arrival->min); */
/* SH 03/28/02 change to include digits of sec to construct filename */
if (isec) {
sprintf(out_file, "%s.%4.4d%2.2d%2.2d.%2.2d%2.2d%05.2f",
out_file_root, arrival->year, arrival->month, arrival->day,
arrival->hour, arrival->min, arrival->sec);
} else if (ipublic_id) {
sprintf(out_file, "%s.%4.4d%2.2d%2.2d.%2.2d%2.2d%2.2d_%s",
out_file_root, arrival->year, arrival->month, arrival->day,
arrival->hour, arrival->min, (int) arrival->sec, public_id);
} else {
sprintf(out_file, "%s.%4.4d%2.2d%2.2d.%2.2d%2.2d%2.2d",
out_file_root, arrival->year, arrival->month, arrival->day,
arrival->hour, arrival->min, (int) arrival->sec);
}
/* SH 04/08/02 check if same filename as previous event;
if so append 'b' to filename;
identical filenames can happen with swarm data */
//printf(">>>>>>%s<>%s<\n", out_file, lastfile);
//if (ncount++ > 0 || strcmp(out_file, lastfile) == 0) {
// AJL 20060615 bug fix! Following line added
if (strcmp(out_file, lastfile) == 0) {
strcpy(lastfile, out_file); /* save filename */
sprintf(filename_ctr, "_%3.3d", *pncount);
strcat(out_file, filename_ctr);
(*pncount)++;
} else {
strcpy(lastfile, out_file); /* save filename */
*pncount = 1;
}
return (0);
}