/* $Id: cedar.c 5790 2016-09-13 16:25:05Z brideout $ */ /* modification history -------------------- 00a,26Apr96 original */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* global mutex to allow only one thread to load the */ /* following global data */ pthread_mutex_t cedar_mutex = PTHREAD_MUTEX_INITIALIZER; /* Parameter code parameters */ static int nparcodes = 0; static int code[MAXPARCODES]; static char description[MAXPARCODES][40]; static char Int16Description[MAXPARCODES][12]; static double scaleFactor[MAXPARCODES]; static char units[MAXPARCODES][9]; static char mnemonic[MAXPARCODES][MNEM_LEN]; static char format[MAXPARCODES][9]; static int width[MAXPARCODES]; static int catId[MAXPARCODES]; static int hasDesc[MAXPARCODES]; static int hasErrDesc[MAXPARCODES]; static int cdi[MAXPARCODES]; /* lists parms with additional increments */ static int ipar = 0; /* number of parms with additional increments */ static double faci[MAXPARCODES]; /* scale factors relating main parm to additional increment parameter */ /* Instrument location parameters */ static int nkinst = 0; static int kinstList[MAXINSTRUMENTS]; static char kinstName[MAXINSTRUMENTS][INST_LEN]; static double kinstLat[MAXINSTRUMENTS]; static double kinstLon[MAXINSTRUMENTS]; static double kinstAlt[MAXINSTRUMENTS]; /* Category parameters */ static int nCategories = 0; static char catList[MAXCATEGORIES][CAT_LEN]; static int catMin[MAXCATEGORIES]; static int catMax[MAXCATEGORIES]; /* Exp table */ static int nExperiments = 0; static int * expIdList; static char ** expPathList; static char ** expNameList; static double * expStarttime; static double * expEndtime; static int * expKinstList; /* File table */ static int nFiles = 0; static char ** fileFileNameList; static int * fileExpIDList; static int * fileKindatList; static int * fileCategoryList; static int * filePermissionList; static char *lastError = (char *)NULL; static int pflag = 0; /*********************************************************************** * * cedarGetMadroot copies Madroot path into user-supplied character * buffer. * * Simply calls getenv, if not found, uses #define __MAD_ROOT__ * * Returns void */ void cedarGetMadroot(char * buf) { if (getenv("MADROOT") == NULL) strcpy(buf, __MAD_ROOT__); else strcpy(buf, getenv("MADROOT")); } /*********************************************************************** * * cedarGetLtot gets length of record * */ int cedarGetLtot (Int16 *cedarp) { return(cedarp[0]); } /*********************************************************************** * * cedarGetKrec gets Kind of record * */ int cedarGetKrec (Int16 *cedarp) { return(cedarp[1]); } /*********************************************************************** * * isDataRecord returns 1 if data record, 0 if catalog or header * */ int isDataRecord(Int16 *cedarp) { if (cedarp[1] == CATALOGBIN || cedarp[1] == HEADERBIN || cedarp[1] == CATALOGASCII || cedarp[1] == HEADERASCII) return 0; else return 1; } /*********************************************************************** * * cedarGetKinst gets instrument code for these data * */ int cedarGetKinst (Int16 *cedarp) { return(cedarp[2]); } /*********************************************************************** * * cedarGetKindat gets kind-of-data code * */ int cedarGetKindat (Int16 *cedarp) { return(cedarp[3]); } /*********************************************************************** * * cedarGetIbyr gets beginning year * */ int cedarGetIbyr (Int16 *cedarp) { return(cedarp[4]); } /*********************************************************************** * * cedarGetIbdt gets beginning date (100*month+day) * */ int cedarGetIbdt (Int16 *cedarp) { return(cedarp[5]); } /*********************************************************************** * * cedarGetIbhm gets beginning hour and minute (100*hour + minute) * */ int cedarGetIbhm (Int16 *cedarp) { return(cedarp[6]); } /*********************************************************************** * * cedarGetIbcs gets beginning centisecond * */ int cedarGetIbcs (Int16 *cedarp) { return(cedarp[7]); } /*********************************************************************** * * cedarGetIeyr gets ending year * */ int cedarGetIeyr (Int16 *cedarp) { return(cedarp[8]); } /*********************************************************************** * * cedarGetIedt gets ending date (100*month+day) * */ int cedarGetIedt (Int16 *cedarp) { return(cedarp[9]); } /*********************************************************************** * * cedarGetIehm gets ending hour and minute (100*hour + minute) * */ int cedarGetIehm (Int16 *cedarp) { return(cedarp[10]); } /*********************************************************************** * * cedarGetIecs gets ending centisecond * */ int cedarGetIecs (Int16 *cedarp) { return(cedarp[11]); } /*********************************************************************** * * cedarGetLprol gets prolog length * */ int cedarGetLprol (Int16 *cedarp) { return(cedarp[12]); } /*********************************************************************** * * cedarGetJpar gets number of single-valued parameters * */ int cedarGetJpar (Int16 *cedarp) { return(cedarp[13]); } /*********************************************************************** * * cedarGetMpar gets number of multiple-valued parameters * */ int cedarGetMpar (Int16 *cedarp) { return(cedarp[14]); } /*********************************************************************** * * cedarGetNrow gets number of entries for each multiple-valued parameter * */ int cedarGetNrow (Int16 *cedarp) { return(cedarp[15]); } /*********************************************************************** * * cedarGetKpar gets number of derived parameters * * Deprecated - use Maddata module for all derived data * */ int cedarGetKpar (Int16 *cedarp) { return(8); } /*********************************************************************** * * cedarGetWord gets specified word from cedar record * */ int cedarGetWord (Int16 *cedarp, int word) { if (word < cedarGetLtot(cedarp)) return(cedarp[word-1]); else return(-1); } /*********************************************************************** * * cedarGetStartTime gets start time of record * */ int cedarGetStartTime (Int16 *cedarp, int *year, int *month, int *day, int *hour, int *minute, int *second, int *centisecond) { *year = cedarp[4]; *month = cedarp[5]/100; *day = cedarp[5] - 100*(*month); *hour = cedarp[6]/100; *minute = cedarp[6] - 100*(* hour); *second = cedarp[7]/100; *centisecond = cedarp[7] - 100*(*second); return(0); } /*********************************************************************** * * cedarGetEndTime gets end time of record * */ int cedarGetEndTime (Int16 *cedarp, int *year, int *month, int *day, int *hour, int *minute, int *second, int *centisecond) { *year = cedarp[8]; *month = cedarp[9]/100; *day = cedarp[9] - 100*(*month); *hour = cedarp[10]/100; *minute = cedarp[10] - 100*(* hour); *second = cedarp[11]/100; *centisecond = cedarp[11] - 100*(*second); return(0); } /*********************************************************************** * * cedarGetStartJday gets start Julian Day plus fractioanl day * */ double cedarGetStartJday (Int16 *cedarp) { int year=0, month=0, day=0, hour=0, minute=0, second=0; double rjday=0.0; year = cedarp[4]; month = cedarp[5]/100; day = cedarp[5] - 100*month; hour = cedarp[6]/100; minute = cedarp[6] - 100*hour; second = cedarp[7]/100; /* centisecond = cedarp[7] - 100*second; */ rjday = jday(day, month, year) + hour/24.0 + minute/1440.0 + second/86400.0; return(rjday); } /*********************************************************************** * * cedarGetEndJday gets end Julian Day plus fractioanl day * */ double cedarGetEndJday (Int16 *cedarp) { int year=0, month=0, day=0, hour=0, minute=0, second=0; double rjday=0.0; year = cedarp[8]; month = cedarp[9]/100; day = cedarp[9] - 100*month; hour = cedarp[10]/100; minute = cedarp[10] - 100*hour; second = cedarp[11]/100; /* centisecond = cedarp[11] - 100*second; */ rjday = jday(day, month, year) + hour/24.0 + minute/1440.0 + second/86400.0; return(rjday); } /*********************************************************************** * * cedarGetStartIndex gets start index time of record * */ double cedarGetStartIndex (Int16 *cedarp) { return(dmadptr((int)cedarp[4], (int)cedarp[5], (int)cedarp[6], (int)cedarp[7])); } /*********************************************************************** * * cedarGetEndIndex gets end index time of record * */ double cedarGetEndIndex (Int16 *cedarp) { return(dmadptr((int)cedarp[8], (int)cedarp[9], (int)cedarp[10], (int)cedarp[11])); } /*********************************************************************** * * cedarGet1dParcodes gets 1D parameter codes from a madrigal record * * This methods allocates dynamic memory for the array of ints * returned. The caller of this method is responsible for * calling free to release this memory when finished with it. * * If no 1D parameter codes, returns NULL pointer. * */ int * cedarGet1dParcodes(Int16 *cedarp) { int i=0, l=0,lprol=0, jpar=0; int *parcodesp = (int *)NULL; lprol = cedarp[12]; jpar = cedarp[13]; /* check whether any 1D parameter codes exist */ if (jpar > 0) { parcodesp = (int *)malloc(jpar*sizeof(int)); for (i=0; i 0) { parcodesp = (int *)malloc(mpar*sizeof(int)); for (i=0; i 0) incrValue = cedarGet1dInt(cedarp, parcode+1); else incrValue = cedarGet1dInt(cedarp, parcode-1); if (incrValue != missingData) value += (double)incrValue*faci[j]; } } return (value); } } return(missing); } /*********************************************************************** * * cedarGet2dParm gets a scaled 2D parameter from a madrigal record * * If 2D parm does not exist, returns array of double "missing" * If 2D parm = -32767 (missing), returns double "missing" * If 2D parm is an error code, and = -32766 (assumed), returns double "assumed" * If 2D parm is an error code, and = +32767 (known bad), returns double "knownbad" * * Otherwise, scales value and includes additional increment values * if they exist * * This methods allocates dynamic memory for the array of doubles * returned. The caller of this method is responsible for * calling free to release this memory when finished with it. * * If nrow = 0, returns NULL pointer. * * If parcode not found, returns array of missing * * If cedarp is a header or catalog record; warning is printed to std err * and returns NULL */ double * cedarGet2dParm(Int16 *cedarp, int parcode) { int i=0, j=0, k=0, l=0, lprol=0, jpar=0, krec=0, mpar=0, nrow=0, l2j=0; int incrValue = 0; Int16 * intArr; int isSpecial = 0; /* used to flag a special value, no scaling */ double scale=0.0; double *parp = (double *)NULL; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); krec = cedarp[1]; if (krec == CATALOGBIN || krec == HEADERBIN) { fprintf(stderr, "Warning: cedarGet2dParm called for non-data record!\n"); return ((double *) NULL); } lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; l2j = lprol + 2*jpar; if (nrow == 0) return ((double *) NULL); parp = (double *)malloc(nrow*sizeof(double)); for (i=0; i 0) { intArr = cedarGet2dInt(cedarp, parcode+1); incrValue = intArr[k]; if (incrValue != missingData) parp[k] += (double)incrValue*faci[j]; free(intArr); } else { /* handle error codes */ intArr = cedarGet2dInt(cedarp, parcode-1); incrValue = intArr[k]; if (incrValue != missingData && incrValue != assumedData && incrValue != knownBadData) parp[k] += (double)incrValue*faci[j]; free(intArr); } } } /* Check for special values */ isSpecial = 0; if (parcode > 0) { if (cedarp[l] == missingData) { isSpecial = 1; parp[k] = missing; } } else if (parcode < 0) { /* handle special cases of error parameters */ /* missing */ if (cedarp[l] == missingData) { isSpecial = 1; parp[k] = missing; } /* assumed */ else if (cedarp[l] == assumedData) { isSpecial = 1; parp[k] = assumed; } /* known bad */ else if (cedarp[l] == knownBadData) { isSpecial = 1; parp[k] = knownbad; } } } return(parp); } } /* parcode not found in record */ for (k=0; k 0) { incrValue = cedarGet2dIntValue(cedarp, parcode+1, row); if (incrValue != missingData) parp += (double)incrValue*faci[j]; } else { /* handle error codes */ incrValue = cedarGet2dIntValue(cedarp, parcode-1, row); if (incrValue != missingData && incrValue != assumedData && incrValue != knownBadData) parp += (double)incrValue*faci[j]; } } } /* Check for special values */ isSpecial = 0; if (parcode > 0) { if (cedarp[l] == missingData) { isSpecial = 1; parp = missing; } } else if (parcode < 0) { /* handle special cases of error parameters */ /* missing */ if (cedarp[l] == missingData) { isSpecial = 1; parp = missing; } /* assumed */ else if (cedarp[l] == assumedData) { isSpecial = 1; parp = assumed; } /* known bad */ else if (cedarp[l] == knownBadData) { isSpecial = 1; parp = knownbad; } } return(parp); } /* next 2D parm code */ } /* parcode not found in record */ return(missing); } /*********************************************************************** * * cedarGetFlatParm creates a flattened 2D parameter * * If 1D parmeter exists, copies array of double of length nrow with * every value set to the 1D value. If not, uses cedarGet2dParm. Note * cedarGet2dParm returns all "missing" is parm not found. * * This methods allocates dynamic memory for the array of doubles * returned. The caller of this method is responsible for * calling free to release this memory when finished with it. * * If nrow = 0, returns NULL pointer. * * If parcode not found, returns array of missing */ double * cedarGetFlatParm(Int16 *cedarp, int parcode) { int nrow, i; double * result2d; double val1d = 0.0; double * parmArr; nrow = cedarGetNrow(cedarp); if (nrow == 0) return ((double *) NULL); parmArr = (double *)malloc(nrow*sizeof(double)); val1d = cedarGet1dParm(cedarp, parcode); if (!isnan(val1d)){ /* copy array of 1d value */ for (i=0; ipparms which are actually available * from the current record. * * User is responsible for calling free to release the returned * array of ints when finished with them. * * Deprecated - use Maddata module instead */ int * cedarGetParmCodeArray(Int16 *cedarp, Ffspec *specp, int *nlines) { int i=0, j=0, k=0, l=0; int lprol=0, jpar=0, mpar=0, l2j=0; static const int kpar=8, cd1[8] = {10,11,12,13,14,15,16,34}; static const int lpar=3, cd2[3] = {110,160,170}; int *codep = (int *)NULL; lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; codep = (int *)malloc((jpar+mpar+kpar)*sizeof(int)); k = 0; /* 1D parameters */ for (i=0; inparms; j++) { if (cedarp[l] == specp->pparms[j]) { codep[k++] = cedarp[l]; break; } } } /* 2D parameters */ l2j = lprol + 2*jpar; for (i=0; inparms; j++) { if (cedarp[l] == specp->pparms[j]) { codep[k++] = cedarp[l]; break; } } } /* Derived 1D Parameters */ for (i=0; inparms; j++) { if (cd1[i] == specp->pparms[j]) { codep[k++] = cd1[i]; break; } } } /* Derived 2D Parameters */ for (i=0; inparms; j++) { if (cd2[i] == specp->pparms[j]) { codep[k++] = cd2[i]; break; } } } *nlines = k; return(codep); } /*********************************************************************** * * cedarGetParmArray flattens a subset of a CEDAR file * * If record is rejected, nlinesp will be set to 0; returned * double array will be set to random values. * * User is responsible for calling free to release the returned * array of doubles when finished with them. * * Deprecated - use Maddata module */ double * cedarGetParmArray(Int16 *cedarp, Ffspec *specp, int *nlinesp) { int i=0, j=0, k=0, l=0, li=0, real_li=0, m=0, j1=0, j2=0, parcode=0, foundit=0, lprol=0, jpar=0, mpar=0, nrow=0, l2j=0,year=0, month=0, day=0, hour=0, minute=0, second=0, centisecond=0; double dval[8]; double scale=0.0, scalei=0.0, parm=0.0; double startJday=0.0, ut1=0.0, ut2=0.0, uth=0.0; int startJday0=0; /* 1d derived parameters */ static const int kpar=8, cd1[8] = {10,11,12,13,14,15,16,34}; /* 2d derived parameters */ static int lpar=3, cd2[3] = {110,160,170}; double *gdlatp, *glonp, *gdaltp; /* an array of 2D row reject flags */ int *qrowp = (int *)NULL; /* the array of doubles to be returned */ static double *parp = (double *)NULL; lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; /* Allocate enough memory for flattened array */ parp = (double *)malloc(nrow*specp->nparms*sizeof(double)); /* Allocate memory for row reject flag */ qrowp = (int *)malloc(nrow*sizeof(int)); for (i=0; infilters; m++) { /* for each filter parameter */ if (cd1[i] == specp->fparms[m]) { /* Check if in 1d array */ parm = dval[i]; /* Reject this record if parameter does not pass filter */ if (parm < specp->fmin[m] || parm > specp->fmax[m]) { *nlinesp = 0; free(qrowp); return (parp); } } } } /* Apply 1D parameter filters */ for (i=0; infilters; m++) { /* for each filter parameter */ if (cedarp[l] == specp->fparms[m]) { /* check if in 1d array */ parcode = cedarp[l]; scale = cedarGetParScaleFactor(parcode); parm = scale*cedarp[l+jpar]; /* Apply the scale factor */ /* Reject this record if parameter does not pass filter */ if (parm < specp->fmin[m] || parm > specp->fmax[m]) { *nlinesp = 0; free(qrowp); return (parp); } } } } /* Apply 2D parameter filters */ l2j = lprol + 2*jpar; for (i=0; infilters; m++) { /* for each filter parameter */ if (cedarp[l] == specp->fparms[m]) { /* check if in 2d array */ parcode = cedarp[l]; scale = cedarGetParScaleFactor(parcode); for (j=0; j= 32767) { parm = missing; } else { parm = scale*cedarp[l]; } /* Reject this row if parameter does not pass filter */ if (parm < specp->fmin[m] || parm > specp->fmax[m]) { qrowp[j] = 0; } } break; } } } /* Apply 2D derived parameters filters */ for (i=0; infilters; m++) { /* for each filter parameter */ if (cd2[i] == specp->fparms[m]) { (void) cedarGetGeodetic(cedarp, &gdlatp, &glonp, &gdaltp); for (j=0; jfparms[m] == 160) parm = gdlatp[j]; else if (specp->fparms[m] == 170) parm = glonp[j]; else if (specp->fparms[m] == 110) parm = gdaltp[j]; /* Reject this row if parameter does not pass filter */ if (parm < specp->fmin[m] || parm > specp->fmax[m]) { qrowp[j] = 0; } } free (gdlatp); free (glonp); free (gdaltp); break; } } } *nlinesp = 0; for (j=0; jnparms; m++) { /* for each output parameter */ /* Add 1d derived parameters to output array */ foundit = 0; for (i=0; ipparms[m]) { for (j=0; jpparms[m]) { /* check if in 1d array */ scale = cedarGetParScaleFactor(specp->pparms[m]); scalei = 0.0; /* Check for increment */ for (j1=0; j1pparms[m]) { for (j2=0; j2pparms[m]+1) { scalei = faci[j1]; real_li = li; } } break; } } for (j=0; j 0.0) { parp[k] = parp[k] + scalei*cedarp[real_li+jpar]; } k++; } } foundit = 1; break; } } if (foundit == 1) continue; /* Add 2D parameters to the output array */ l2j = lprol + 2*jpar; foundit = 0; for (i=0; ipparms[m]) { /* check if in 2d array */ scale = cedarGetParScaleFactor(specp->pparms[m]); scalei = 0.0; /* Check for increment */ for (j1=0; j1pparms[m]) { for (j2=0; j2pparms[m]+1) { scalei = faci[j1]; real_li = li; } } break; } } for (j=0; j= 32767) { parp[k] = missing; } else { parp[k] = scale*cedarp[l]; if (scalei > 0.0) { if (cedarp[real_li+(j+1)*mpar] > -32766 && cedarp[real_li+(j+1)*mpar] < 32767) { parp[k] = parp[k] + scalei*cedarp[real_li+(j+1)*mpar]; } } } k++; } } foundit = 1; break; } } if (foundit == 1) continue; /* Add 2D derived parameters to the output array */ foundit = 0; for (i=0; ipparms[m]) { (void) cedarGetGeodetic(cedarp, &gdlatp, &glonp, &gdaltp); for (j=0; jpparms[m] == 160) parp[k++] = gdlatp[j]; else if (specp->pparms[m] == 170) parp[k++] = glonp[j]; else if (specp->pparms[m] == 110) parp[k++] = gdaltp[j]; } } free (gdlatp); free (glonp); free (gdaltp); foundit = 1; break; } } if (foundit == 1) continue; } free(qrowp); return(parp); } /*********************************************************************** * * cedarGetGeodetic gets geodetic coordinates from radar coordinates * * cedarGetGeodetic modifies the three arrays of doubles to return * lat, long, and alt. Length of each array is nrows. Geodetic * coordinates will be calculated in any of the following ways: * * 1) az, el, and range - az from azm, az1, or az2, and * el from elm, el, or el2 * 2) (altb, alte, or gdalt), gdlat and glon * 3) (altb, altav or altb, alte, or gdalt) alone - lat and long assumed * to be that of instrument * * If all three methods fail, all three arrays populated with missing * * All parameters can be either 1d or 2d. * * This methods allocates dynamic memory for the array of doubles * modified. The caller of this method is responsible for * calling free to release the memory from these 3 arrays when * finished with them. * * If nrow = 0, returns -1. */ int cedarGetGeodetic(Int16 *cedarp, double **gdlatpp, double **glonpp, double **gdaltpp) { int i=0, kinst=0, nrow=0; /* station location */ double slat = 0.0, slon = 0.0, salt = 0.0; int noData = 0; /* flag to indicate no data found */ /* temp arrays of data - freed internally when done */ double *azm =(double *)NULL, *az1 =(double *)NULL, *az2 =(double *)NULL, *azd =(double *)NULL, *elm =(double *)NULL, *el1 =(double *)NULL, *el2 =(double *)NULL, *range =(double *)NULL, *altb =(double *)NULL, *altav =(double *)NULL, *alte =(double *)NULL, *gdalt =(double *)NULL, *gdlat =(double *)NULL, *glon =(double *)NULL; /* arrays to be freed by user */ double *latp = (double *)NULL; double *lonp = (double *)NULL; double *altp = (double *)NULL; nrow = cedarGetNrow(cedarp); kinst = cedarGetKinst(cedarp); if (nrow == 0) return (-1); /* from kinst, get station coordinates */ (void) los2geodetic(kinst, 0.0, 0.0, 0.0, &slat, &slon, &salt); /* allocate arrays */ latp = (double *)malloc(nrow*sizeof(double)); lonp = (double *)malloc(nrow*sizeof(double)); altp = (double *)malloc(nrow*sizeof(double)); azd = (double *)malloc(nrow*sizeof(double)); /* Populate each temp array */ azm = cedarGetFlatParm(cedarp, 130); az1 = cedarGetFlatParm(cedarp, 132); az2 = cedarGetFlatParm(cedarp, 133); elm = cedarGetFlatParm(cedarp, 140); el1 = cedarGetFlatParm(cedarp, 142); el2 = cedarGetFlatParm(cedarp, 143); range = cedarGetFlatParm(cedarp, 120); altb = cedarGetFlatParm(cedarp, 106); altav = cedarGetFlatParm(cedarp, 115); alte = cedarGetFlatParm(cedarp, 108); gdalt = cedarGetFlatParm(cedarp, 110); gdlat = cedarGetFlatParm(cedarp, 160); glon = cedarGetFlatParm(cedarp, 170); /* Compute mean azimuth - always check for missing data even if some data exists */ if (!hasData(nrow, azm)) { if (hasData(nrow, az1) && hasData(nrow, az2)) { for (i=0; i +180.0) az1[i]=az1[i]-360.0; } if (!isnan(az2[i])) { while (az2[i] < -180.0) az2[i]=az2[i]+360.0; while (az2[i] > +180.0) az2[i]=az2[i]-360.0; } if (!isnan(az1[i]) && !isnan(az2[i])) { azd[i] = az2[i] - az1[i]; while (azd[i] < -180.0) azd[i]=azd[i]+360.0; while (azd[i] > +180.0) azd[i]=azd[i]-360.0; azm[i] = (az1[i] + azd[i]/2.0); } else if (isnan(az1[i]) && !isnan(az2[i])) azm[i] = az2[i]; else if (!isnan(az1[i]) && isnan(az2[i])) azm[i] = az1[i]; else azm[i] = missing; } } else if (hasData(nrow, az1)) { for (i=0; i number of 2d rows, returns missingData. * * If parcode not found, returns missingData */ Int16 cedarGet2dIntValue(Int16 *cedarp, int parcode, int row) { int i=0, l=0, lprol=0, jpar=0, mpar=0, nrow=0; Int16 parp = missingData; lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; if (nrow == 0) return (missingData); for (i=0; i 32678) { fprintf(stderr, "Error - Cedar format unable to handle length greater than 32678, this record would be %i\n", ltot); cedarp = NULL; return(cedarp); } cedarp = (Int16 *) malloc(ltot*sizeof(Int16)); cedarp[0] = (Int16)ltot; cedarp[1] = krec; cedarp[2] = kinst; cedarp[3] = kindat; cedarp[4] = year1; cedarp[5] = 100*month1 + day1; cedarp[6] = 100*hour1 + minute1; cedarp[7] = 100*second1 + centisecond1; cedarp[8] = year2; cedarp[9] = 100*month2 + day2; cedarp[10] = 100*hour2 + minute2; cedarp[11] = 100*second2 + centisecond2; cedarp[12] = (Int16)lprol; cedarp[13] = (Int16)jpar; cedarp[14] = (Int16)mpar; cedarp[15] = (Int16)nrow; for (i=lprol; i jpar-1) { return(1); } l = lprol + index; cedarp[l] = parcode; for (j=0; j= 0.0) { /* check if out of range */ if ((parm/scaleFactor[j] - 1) > knownBadData) { cedarp[l+jpar] = (Int16)missingData; return(1); } else cedarp[l+jpar] = (Int16)(parm/scaleFactor[j] + 0.5); } else { /* check if out of range */ if ((parm/scaleFactor[j] + 1) < missingData) { cedarp[l+jpar] = (Int16)missingData; return(1); } else cedarp[l+jpar] = (Int16)(parm/scaleFactor[j] - 0.5); } break; } } return(0); } /*********************************************************************** * * cedarSetNorm1dParm sets a 1D parameter in a Cedar record with the units * of the standard parameter even if additional increment parameter * * Inputs: * Int16 *cedarp - pointer to existing Cedar record * int parcode - Cedar parmater code * double parm - doubles containing value to set.Special values * may be set by setting values to #defines * missing, assumed, or knownbad * int index - index of which 2d parameter to set * * Returns 1 if failure, 0 if success. If value out of Int16 range, will set * value to missing and return failure. */ int cedarSetNorm1dParm(Int16 *cedarp, int parcode, double parm, int index) { int lprol=0, jpar=0, j=0, l=0; double scale = 0.0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); scale = cedarGetNormScaleFactor (parcode); lprol = cedarp[12]; jpar = cedarp[13]; if (index > jpar-1) { return(1); } l = lprol + index; cedarp[l] = parcode; for (j=0; j= 0.0) { /* check if out of range */ if ((parm/scale - 1) > knownBadData) { cedarp[l+jpar] = (Int16)missingData; return(1); } else cedarp[l+jpar] = (Int16)(parm/scale + 0.5); } else { /* check if out of range */ if ((parm/scale + 1) < missingData) { cedarp[l+jpar] = (Int16)missingData; return(1); } else cedarp[l+jpar] = (Int16)(parm/scale - 0.5); } break; } } return(0); } /*********************************************************************** * * cedarSet2dParm sets all values for a 2D parameter in a cedar record * * Inputs: * Int16 *cedarp - pointer to existing Cedar record * int parcode - Cedar parmater code * double *parmp - array of doubles containing values to set. Length * must be nrow. Special values may be set by setting * values to #defines missing, assumed, or knownbad * int index - index of which 2d parameter to set * * Returns 1 if failure, 0 if success. If any value out of Int16 range, will set * value to missing, but all valid values will still be set. Returns 1 if any * out of range data found. * */ int cedarSet2dParm(Int16 *cedarp, int parcode, double *parmp, int index) { int k=0, j=0, l=0,lprol=0, jpar=0, mpar=0, nrow=0; int retCode = 0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; if (index > mpar-1) { return(1); } l = lprol + 2*jpar + index; cedarp[l] = parcode; for (j=0; j= 0.0) { /* check if out of range */ if ((parmp[k]/scaleFactor[j] + 1) > knownBadData) { cedarp[l+(k+1)*mpar] = (Int16)missingData; retCode = 1; } else cedarp[l+(k+1)*mpar] = (Int16)(parmp[k]/scaleFactor[j] + 0.5); } else { /* check if out of range */ if ((parmp[k]/scaleFactor[j] - 1) < missingData) { cedarp[l+(k+1)*mpar] = (Int16)missingData; retCode = 1; } else cedarp[l+(k+1)*mpar] = (Int16)(parmp[k]/scaleFactor[j] - 0.5); } } break; } } return(retCode); } /*********************************************************************** * * cedarSetNorm2dParm sets all values for a 2D parameter in a cedar record * with the units as standard parameter even if * additional increment parameter * * Inputs: * Int16 *cedarp - pointer to existing Cedar record * int parcode - Cedar parmater code * double *parmp - array of doubles containing values to set. Length * must be nrow. Special values may be set by setting * values to #defines missing, assumed, or knownbad * int index - index of which 2d parameter to set * * Returns 1 if failure, 0 if success. If any value out of Int16 range, will set * value to missing, but all valid values will still be set. Returns 1 if any * out of range data found. * */ int cedarSetNorm2dParm(Int16 *cedarp, int parcode, double *parmp, int index) { int k=0, j=0, l=0,lprol=0, jpar=0, mpar=0, nrow=0; int retCode = 0; double scale = 0.0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); scale = cedarGetNormScaleFactor (parcode); lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; if (index > mpar-1) { return(1); } l = lprol + 2*jpar + index; cedarp[l] = parcode; for (j=0; j= 0.0) { /* check if out of range */ if ((parmp[k]/scale - 1) > knownBadData) { cedarp[l+(k+1)*mpar] = (Int16)missingData; retCode = 1; } else cedarp[l+(k+1)*mpar] = (Int16)(parmp[k]/scale + 0.5); } else { /* check if out of range */ if ((parmp[k]/scale + 1) < missingData) { cedarp[l+(k+1)*mpar] = (Int16)missingData; retCode = 1; } else cedarp[l+(k+1)*mpar] = (Int16)(parmp[k]/scale - 0.5); } } break; } } return(retCode); } /*********************************************************************** * * cedarSet1dInt puts a 1D parameter (unscaled) into a madrigal record * */ int cedarSet1dInt(Int16 *cedarp, int parcode, Int16 int1d, int index) { int lprol=0, jpar=0, l=0; lprol = cedarp[12]; jpar = cedarp[13]; l = lprol + index; if (index > jpar-1) { return(1); } cedarp[l] = parcode; cedarp[l+jpar] = int1d; return(0); } /*********************************************************************** * * cedarSet2dInt puts a 2D parameter (unscaled) into a madrigal record * */ int cedarSet2dInt(Int16 *cedarp, int parcode, Int16 *int2dp, int index) { int k=0, l=0,lprol=0, jpar=0, mpar=0, nrow=0; lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; if (index > mpar-1) { return(1); } l = lprol + 2*jpar + index; cedarp[l] = parcode; for (k=0; k 0) if (cedarp[i+jpar] != -32767) (void) printf("%6d %12.5e %40s\n", cedarp[i], scaleFactor[j]*cedarp[i+jpar], description[j]); else (void) printf("%6d %12.5e %40s\n", cedarp[i], (double)cedarp[i+jpar], description[j]); else if (cedarp[i+jpar] != -32767 && cedarp[i+jpar] != -32766 && cedarp[i+jpar] != 32767) (void) printf("%6d %12.5e Uncertainty in %40s\n", cedarp[i], scaleFactor[j]*cedarp[i+jpar], description[j]); else (void) printf("%6d %12.5e Uncertainty in %40s\n", cedarp[i], (double)cedarp[i+jpar], description[j]); } else /* unknown code */ { if (cedarp[i] > 0) (void) printf("%6d %12.5e %40s\n", cedarp[i], 1.0*cedarp[i+jpar], "Unknown parameter"); else (void) printf("%6d %12.5e Uncertainty in %40s\n", cedarp[i], 1.0*cedarp[i+jpar], "Unknown parameter"); } } /* Print 2D Parameter Codes and Descriptions */ (void) printf("\n2D parameter codes and descriptions\n"); for (i=0; i 0) (void) printf("%6d %s\n", cedarp[l], description[j]); else (void) printf("%6d Uncertainty in %s\n", cedarp[l], description[j]); } else /* unknown code */ { if (cedarp[l] > 0) (void) printf("%6d %s\n", cedarp[l], "Unknown parameter"); else (void) printf("%6d Uncertainty in %s\n", cedarp[l], "Unknown parameter"); } } /* Print 2D parameters */ (void) printf("\n2D parameters\n"); nblk = mpar/12; if (nblk*12 != mpar) nblk++; for (iblk=0; iblk=12*iblk && j<12*(iblk+1)) { if (i == 0) { if (cedarp[l] < 0) isError[j] = 1; codeFound = 0; for (k=0; k=0; k--) { if (isgraph((int)s[k])) break; } for (j=0; j<=k; j++) { (void) fputc(s[j], stdout); } (void) fputc('\n', stdout); } } (void) fflush(stdout); return(0); } /*********************************************************************** * * cedarGetInformation gets Ascii Information from Catalog or Header record * * inputs: Int16 * cedarp (pointer to cedar record) * * outputs: char * (pointer to dynamically allocated string holding * ASCII text in catalog or header record, or empty string * if no text available. Will return empty string if called * with a data record instead of a header or catalog record). * The string will have 81 characters for each line of * information - the first 80 characters will be the 80 * characters in the file with unprintable characters converted * to spaces, and the 81st character a newline. After the last * line a null character is added to make a valid c string. * * The user is resposible for freeing the returned string when finished * with it. * */ char * cedarGetInformation(Int16 *cedarp) { int i=0, j=0,ltot=0, krec=0, nlines=0; char *s; char * information; ltot = cedarp[0]; krec = cedarp[1]; if (krec != CATALOGBIN && krec != HEADERBIN) { /* not a catalog or header record */ information = (char *)malloc(1); information[0] = '\0'; } else { nlines = ltot/40; if (nlines < 1) nlines = 1; /* allocate 81 bytes for each line plus final terminator */ information = (char *)malloc(((81 * (nlines - 1)) + 1) * sizeof(char)); /* Handle each line */ for (i=1; i 32) { (void) cedarSetError(err1); for (i=0; i<16; i++) { (void) printf("%6d", cedarp[i]); } return(1); } for (i=0; i= 0) return i; else return -i; } } return(missingData); } /*********************************************************************** * * madGetParMnemIndex Gets index of Madrigal parameter code in table, given its mnemonic * * Returns the index of the specified mnemonic. Matching is case-insensitive, and * ignores whitespace. If not found and begins with "D", will next search with "D" * removed, and return the negitive of the index found. If still not found, * returns missingData. * */ int madGetParMnemIndex (char * mnem) { int i = 0; char stdMnem[MNEM_LEN] = ""; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); getStdMnem(mnem, stdMnem); /* try to find non-error index */ for (i = 0; i < nparcodes; i++) { if (strcmp(stdMnem, mnemonic[i]) == 0) return i; } /* now try to find error index */ if (stdMnem[0] != 'D') return (missingData); for (i = 0; i < nparcodes; i++) { if (strcmp(stdMnem + 1, mnemonic[i]) == 0) return (-i); } return(missingData); } /*********************************************************************** * * isMadparmError returns 1 if this is an error parm, 0 if standard, * -1 if neither * * */ int isMadparmError(const char * mnem) { int i = 0; char stdMnem[MNEM_LEN] = ""; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); getStdMnem(mnem, stdMnem); /* try to find non-error index */ for (i = 0; i < nparcodes; i++) { if (strcmp(stdMnem, mnemonic[i]) == 0) return (0); } /* now try to find error index */ if (stdMnem[0] == 'D') { for (i = 0; i < nparcodes; i++) { if (strcmp(stdMnem + 1, mnemonic[i]) == 0) return (1); } } /* check if stdMnem is an integer */ for (i = 0; i < strlen(mnem); i++) { if (!isdigit(stdMnem[i]) && stdMnem[i] != '-') return (-1); /* not an integer */ } /* stdMnem is an integer */ i = atoi(stdMnem); if (i < 0) return (1); else return (0); } /*********************************************************************** * * getStdMnem converts a str to standard mnemonic form * * Inputs: const char * mnem - the string containing the mnemonic to be converted * char * stdMnem - a string to copy the standard form of the * mnemonic to. Allocated by the user. At most * MNEM_LEN - 1 characters will be copied. Std form * strips all whitespace and is upper case. * */ void getStdMnem (const char * mnem, char * stdMnem) { int i = 0, j = 0; for (i=0; i < strlen(mnem); i++) { if (i == MNEM_LEN - 1) { stdMnem[i] = '\0'; return; } if (mnem[i] == ' ' || mnem[i] == '\t' || mnem[i] == '\n') continue; /* valid character found */ stdMnem[j++] = toupper(mnem[i]); } stdMnem[j] = '\0'; } /*********************************************************************** * * cedarGetParCodeType Gets type of Cedar parameter code from table, given its code. * * For a pure Madrigal parameter with code 0, will return first found. Use * madGetParMnemType instead. If not in parcods.tab but in a standard range, * as defined by madCatTab.txt will return Cedar values. If not in parcodes * and not in any standard range, will return "Unknown Parameter Type" * * User is responsible for freeing dynamically allocated string * when finished with it. */ char * cedarGetParCodeType (int parcode) { int index=0; char * retStr = NULL; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); /* allocate string to return */ retStr = (char *)malloc(sizeof(char)*CAT_LEN); /* first find index, if any */ index = cedarGetParCodeIndex(parcode); if (index != missingData) { strcpy(retStr, catList[catId[abs(index)]]); return (retStr); } /* else parcode was not in parcods.tab, */ /* try to return type based on min and max in madCatTab.txt */ for (index = 0; index < nCategories; index++) { if (abs(parcode) >= catMin[index] && abs(parcode) <= catMax[index]) { strcpy(retStr, catList[index]); return (retStr); } } /* outside of standard ranges */ strcpy(retStr, "Unknown Parameter Type"); return(retStr); } /*********************************************************************** * * madGetParMnemType Gets type of Madrigal parameter from table, given its mnemonic. * * If mnemonic not in parcods.tab, will return "Unknown Parameter Type" * * User is responsible for freeing dynamically allocated string * when finished with it. */ char * madGetParMnemType (char * mnem) { int index=0, i=0; char * retStr = NULL; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); /* allocate string to return */ retStr = (char *)malloc(sizeof(char)*CAT_LEN); /* first find index, if any */ index = madGetParMnemIndex(mnem); if (index != missingData) strcpy(retStr, catList[catId[abs(index)]]); else { /* check if mnem is an integer */ for (i = 0; i < strlen(mnem); i++) { if (!isdigit(mnem[i]) && mnem[i] != '-') { strcpy(retStr, "Unknown Parameter Type"); return(retStr); } } /* mnemonic is an integer, let cedarGetParCodeType deal with it */ free(retStr); retStr = cedarGetParCodeType(atoi(mnem)); } return(retStr); } /*********************************************************************** * * madGetCategoryIndex Gets the index of a given Category name. * * If category string not found, returns missingData * Matching is case and whitespace sensitive * */ int madGetCategoryIndex (char * category) { int index=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); for(index = 0; index < nCategories; index++) { if(strcmp(category, catList[index]) == 0) return(index); } return(missingData); } /*********************************************************************** * * cedarGetParDescription Gets Cedar parameter code description from * table * * User is responsible for freeing dynamically allocated string * when finished with it. * * */ char * cedarGetParDescription (int parcode) { int i=0; /* Note that allocated string is longer than DESC_LEN to allow */ /* "Error in " to be prepended */ char * desc = malloc(sizeof(char) * (DESC_LEN + 10)); /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = cedarGetParCodeIndex(parcode); if (i == missingData) { strcpy(desc, "Unknown Parameter Code"); return(desc); } if (parcode > 0 ) { strcpy(desc, description[i]); return(desc); } else { (void) strcpy(desc, "Error in "); (void) strcat(desc, description[abs(i)]); return(desc); } } /*********************************************************************** * * madGetParDescription Gets Madrigal parameter code description from * table, given mnemonic * * User is responsible for freeing dynamically allocated string * when finished with it. * */ char * madGetParDescription (char * mnem) { int i=0; /* Note that allocated string is longer than DESC_LEN to allow */ /* "Error in " to be prepended */ char * desc = malloc(sizeof(char) * (DESC_LEN + 10)); /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = madGetParMnemIndex(mnem); if (i == missingData) { strcpy(desc, "Unknown Parameter Code"); return(desc); } if (i > 0 ) { strcpy(desc, description[i]); return(desc); } else { (void) strcpy(desc, "Error in "); (void) strcat(desc, description[abs(i)]); return(desc); } } /*********************************************************************** * * cedarGetParInt16Description Gets Cedar parameter code Int16 * description from table * * User is responsible for freeing dynamically allocated string * when finished with it. */ char * cedarGetParInt16Description (int parcode) { int i=0; char * retStr = NULL; /* allocate string to return */ retStr = (char *)malloc(sizeof(char)*DESC16_LEN); /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = cedarGetParCodeIndex(parcode); if (i == missingData) { strcpy(retStr, "Unknown"); } else strcpy(retStr, Int16Description[abs(i)]); return(retStr); } /*********************************************************************** * * madGetParInt16Description Gets Madrigal parameter code Int16 * description from table, given mnemonic * */ char * madGetParInt16Description (char * mnem) { int i=0; char * retStr = NULL; /* allocate string to return */ retStr = (char *)malloc(sizeof(char)*DESC16_LEN); /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = madGetParMnemIndex(mnem); if (i == missingData) { strcpy(retStr, "Unknown"); } else strcpy(retStr, Int16Description[abs(i)]); return(retStr); } /*********************************************************************** * * cedarGetParScaleFactor Gets Cedar parameter scale factor from table * */ double cedarGetParScaleFactor (int parcode) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = cedarGetParCodeIndex(parcode); if (i == missingData) { return(1.0); } return(scaleFactor[abs(i)]); } /*********************************************************************** * * madGetParScaleFactor Gets Madrigal parameter scale factor from table, * given mnemonic * */ double madGetParScaleFactor (char * mnem) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = madGetParMnemIndex(mnem); if (i == missingData) { return(1.0); } return(scaleFactor[abs(i)]); } /*********************************************************************** * * cedarGetNormScaleFactor Gets Cedar parameter scale factor, where additional * increment parameters use the same units as main * parameter. Differs from cedarGetParScaleFactor, which * returns scale factors for additional increment parameters * that may have different units than the main parameter. * */ double cedarGetNormScaleFactor (int parcode) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); /* see if this is an additional increment parameter */ for (i=0; i 0 ) { strcpy(mnem, mnemonic[i]); return(mnem); } else { (void) strcpy(mnem, "D"); (void) strcat(mnem, mnemonic[abs(i)]); return(mnem); } } /*********************************************************************** * * cedarGetParCodeFromMnemonic Gets Cedar parameter code given mnemonic * * If mnemonic is integer in form of string, returns that integer * If not found, returns missingData * */ int cedarGetParCodeFromMnemonic (char * mnem) { int index = 0; int i = 0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); index = madGetParMnemIndex(mnem); if (index == missingData) { /* check if the mnemonic is already an integer */ for (i=0; i= 0) return(code[index]); else return(-1 * code[abs(index)]); } /*********************************************************************** * * cedarGetParFormat Gets Cedar parameter code format from table. * * If not found, returns NULL */ char * cedarGetParFormat (int parcode) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = cedarGetParCodeIndex(parcode); if (i == missingData) { return (NULL); } else return(format[abs(i)]); } /*********************************************************************** * * madGetParFormat Gets Madrigal parameter format from table (given mnemonic) * * If not found, returns NULL */ char * madGetParFormat (char * mnem) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = madGetParMnemIndex(mnem); if (i == missingData) { return (NULL); } else return(format[abs(i)]); } /*********************************************************************** * * cedarGetParWidth Gets Cedar parameter field width from table * * If unknown, returns default value of 11 * */ int cedarGetParWidth (int parcode) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = cedarGetParCodeIndex(parcode); if (i == missingData) { return(11); } return(width[abs(i)]); } /*********************************************************************** * * madGetParWidth Gets Madrigal parameter field width from table, * given mnemonic * * If unknown, returns default value of 11 */ int madGetParWidth (char * mnem) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = madGetParMnemIndex(mnem); if (i == missingData) { return(11); } return(width[abs(i)]); } /*********************************************************************** * * cedarHasHtmlDesc Returns 1 if parameter has entry in Html description * page, 0 if not. Works also for error codes (< 0) * * If unknown, returns default value of 0 * */ int cedarHasHtmlDesc(int parcode) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = cedarGetParCodeIndex(parcode); if (i == missingData) { return(0); } if (parcode > 0) return(hasDesc[abs(i)]); else return(hasErrDesc[abs(i)]); } /*********************************************************************** * * madHasHtmlDesc Returns 1 if mnemonic has entry in Html description * page, 0 if not. Works also for error mnemonics. * * If unknown, returns default value of 0 */ int madHasHtmlDesc (char * mnem) { int i=0; /* be sure cedarReadParCodes has been called */ if (nkinst == 0) cedarReadParCodes(); i = madGetParMnemIndex(mnem); if (i == missingData) { return(0); } if (isMadparmError(mnem)) return(hasErrDesc[abs(i)]); else return(hasDesc[abs(i)]); } /*********************************************************************** * * cedarCheckRecord checks cedar record for consistency * */ int cedarCheckRecord (Int16 *cedarp) { int ltot=0, lprol=0, jpar=0, mpar=0, nrow=0; ltot = cedarp[0]; lprol = cedarp[12]; jpar = cedarp[13]; mpar = cedarp[14]; nrow = cedarp[15]; if (ltot != lprol + 2*jpar + mpar*(nrow+1)) { return(1); } return(0); } /*********************************************************************** * * cedarHexPrintRecord prints hex version of record * */ int cedarHexPrintRecord (Int16 *cedarp) { int ltot, i, j; char cbuf1[9], cbuf2[5]; ltot = cedarp[0]; cbuf2[4] = '\0'; for (i=0; i xt[nt-1]) { y = badval; return (y); } /* find the tabular points on either side of x */ for (n=1; n *latestEndTime) *latestEndTime = endTime; (*parmMaxpp)[0] = year; (*parmMaxpp)[1] = month; (*parmMaxpp)[2] = day; (*parmMaxpp)[3] = hour; (*parmMaxpp)[4] = minute; (*parmMaxpp)[5] = second; (*parmMaxpp)[6] = centisecond; ut1 = 24.0*(cedarGetStartJday(cedarp) - *startJday0); ut2 = 24.0*(cedarGetEndJday(cedarp) - *startJday0); uth = 0.5*(ut1 + ut2); (*parmMaxpp)[7] = uth; } /* Get geodetic coordinates */ if (*numParmsp == 8) { *numParmsp = 11; *parmsListpp = (int *)realloc(*parmsListpp, (*numParmsp)*sizeof(int)); *parmLocpp = (int *)realloc(*parmLocpp, (*numParmsp)*sizeof(int)); *parmMinpp = (double *)realloc(*parmMinpp, (*numParmsp)*sizeof(double)); *parmMaxpp = (double *)realloc(*parmMaxpp, (*numParmsp)*sizeof(double)); *parmMissing = (int *)realloc(*parmMissing, (*numParmsp)*sizeof(int)); (*parmsListpp)[8] = 160; /* latitude */ (*parmMinpp)[8] = 1.e38; (*parmMaxpp)[8] = -1.e38; (*parmsListpp)[9] = 170; /* longitude */ (*parmMinpp)[9] = 1.e38; (*parmMaxpp)[9] = -1.e38; (*parmsListpp)[10] = 110; /* altitude */ (*parmMinpp)[10] = 1.e38; (*parmMaxpp)[10] = -1.e38; /* assume not missing */ (*parmMissing)[8] = 0; (*parmMissing)[9] = 0; (*parmMissing)[10] = 0; } retVal = cedarGetGeodetic(cedarp, &gdlatp, &glonp, &gdaltp); if (retVal != -1) { for (k=0; k (*parmMaxpp)[8]) && (!isnan(gdlatp[k]))) (*parmMaxpp)[8] = gdlatp[k]; if ((glonp[k] > (*parmMaxpp)[9]) && (!isnan(glonp[k]))) (*parmMaxpp)[9] = glonp[k]; if ((glonp[k] < (*parmMinpp)[9]) && (!isnan(glonp[k]))) (*parmMinpp)[9] = glonp[k]; if ((gdaltp[k] > (*parmMaxpp)[10]) && (!isnan(gdaltp[k]))) (*parmMaxpp)[10] = gdaltp[k]; if ((gdaltp[k] < (*parmMinpp)[10]) && (!isnan(gdaltp[k]))) (*parmMinpp)[10] = gdaltp[k]; } free (gdlatp); free (glonp); free (gdaltp); } /* check if any existing parameters are missing from this record */ /* start with 11 to ignore derived parameters */ for (j=11; j<*numParmsp; j++) { if (!cedarHas1DParcode(cedarp, (*parmsListpp)[j]) && !cedarHas2DParcode(cedarp, (*parmsListpp)[j])) { /* this parameter is missing */ (*parmMissing)[j] = 1; } } /* Check for new 1D Parameter Codes */ for (i=lprol; i (*parmMaxpp)[j] && !isnan(cedarGet1dParm(cedarp, cedarp[i]))) (*parmMaxpp)[j] = cedarGet1dParm(cedarp, cedarp[i]); } /* now check if any "derived" parameters need to be derived by 1D data */ /* since cedarGetGeodetic only handles 2D data */ if (nrow == 0) { if (cedarp[i] == 160)/* latitude */ { if ((!isnan(cedarGet1dParm(cedarp, 160))) && (cedarGet1dParm(cedarp, 160) < (*parmMinpp)[8])) (*parmMinpp)[8] = cedarGet1dParm(cedarp, 160); if ((!isnan(cedarGet1dParm(cedarp, 160))) && (cedarGet1dParm(cedarp, 160) > (*parmMaxpp)[8])) (*parmMaxpp)[8] = cedarGet1dParm(cedarp, 160); } if (cedarp[i] == 170)/* longitude */ { if ((!isnan(cedarGet1dParm(cedarp, 170))) && (cedarGet1dParm(cedarp, 170) < (*parmMinpp)[9])) (*parmMinpp)[9] = cedarGet1dParm(cedarp, 170); if ((!isnan(cedarGet1dParm(cedarp, 170))) && (cedarGet1dParm(cedarp, 170) > (*parmMaxpp)[9])) (*parmMaxpp)[9] = cedarGet1dParm(cedarp, 170); } if (cedarp[i] == 110)/* altitude */ { if ((!isnan(cedarGet1dParm(cedarp, 110))) && (cedarGet1dParm(cedarp, 110) < (*parmMinpp)[10])) (*parmMinpp)[10] = cedarGet1dParm(cedarp, 110); if ((!isnan(cedarGet1dParm(cedarp, 110))) && (cedarGet1dParm(cedarp, 110) > (*parmMaxpp)[10])) (*parmMaxpp)[10] = cedarGet1dParm(cedarp, 110); } } } /* Check for new 2D Parameter Codes*/ for (i=0; i (*parmMaxpp)[j]) & (!isnan(val[k]))) (*parmMaxpp)[j] = val[k]; } } else { for (k=0; k (*parmMaxpp)[j]) & (!isnan(val[k]))) (*parmMaxpp)[j] = val[k]; } } /* free val for next call to cedarGet2dParm */ free(val); } /* check for new values of kinst */ kinstFound = 0; for (i=0; i<*numKinst; i++) { if (kinst == kinstArr[i]) { kinstFound = 1; break; } } if (kinstFound == 0) { kinstArr[*numKinst] = kinst; *numKinst = *numKinst + 1; } /* check for new values of kindat */ kindatFound = 0; for (i=0; i<*numKindat; i++) { if (kindat == kindatArr[i]) { kindatFound = 1; break; } } if (kindatFound == 0) { kindatArr[*numKindat] = kindat; *numKindat = *numKindat + 1; } free(hasGoodData); return(result); } /*********************************************************************** * * cedarGetStationPos Gets instrument coordinates for a given kinst * * Uses data from metadata/instTab.txt * */ void cedarGetStationPos(int kinst, double * lat, double * lon, double * alt) { int i = 0; /* make sure instTab.txt has been loaded */ if (nkinst == 0) cedarReadParCodes(); for (i=0; i 0 * * returns: 0 if success, non-zero and error set if not successful * */ int searchFilesByDate(double starttime, double endtime, int * numFilesFound, char ** fileList, double ** fileStarttime, double ** fileEndtime) { int i=0, j=0; int expID = 0; int fileListStrlen = 0; /* keeps track of present len of fileList string */ /* be sure loadExpFileTable called first */ if(loadExpFileTable()) return(-1); /* init */ *numFilesFound = 0; *fileList = NULL; *fileStarttime = NULL; *fileEndtime = NULL; /* loop through each experiment to see if data matches */ for (i=0; i endtime) continue; /* exp okay, find all its default files */ expID = expIdList[i]; for (j=0; j 1) strcat(*fileList, ","); else strcpy(*fileList, ""); strcat(*fileList, expPathList[i]); strcat(*fileList, "/"); strcat(*fileList, fileFileNameList[j]); (*fileStarttime)[(*numFilesFound)-1] = expStarttime[i]; (*fileEndtime)[(*numFilesFound)-1] = expEndtime[i]; } } /* success */ return (0); } /*********************************************************************** * * loadExpFileTable Loads data from expTab.txt and fileTab.txt into * global data. Private method - do not call directly. * * arguments: None * * returns: 0 if success, non-zero and error set if not successful * * Affects: loads global data that deals with expTab and fileTab * */ int loadExpFileTable() { /* Data file declarations */ FILE *fp; /* Miscellaneous declarations */ char infile[128], s[1200], tmpStr[1200]; int i=0; int year=0, month=0, day=0, hour=0, min=0, sec=0; int date=0, time=0; char * pToken; char * subStr; static const char *err1="loadExpFileTable error - expTab.txt does not exist"; static const char *err2="loadExpFileTable error - fileTab.txt does not exist"; static const char *err3="loadExpFileTable error - format error in expTab.tab"; static const char *err4="loadExpFileTable error - format error in fileTab.tab"; /* the global mutex cedar_mutex must be acquired before this method is called */ pthread_mutex_lock(&cedar_mutex); /* if already loaded, just release mutex and return */ if (nExperiments != 0) { pthread_mutex_unlock(&cedar_mutex); return(0); } /* This is the first thread to get the lock */ /* Load data and release mutex at the end */ /* now parse the expTab.txt file */ cedarGetMadroot(infile); (void) strcat(infile, "/metadata/expTab.txt"); if ((fp = fopen (infile, "r")) == NULL) { (void) cedarSetError(err1); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* Read expTab.txt File */ while (fgets(s, 1200, fp) != NULL) { /* tokenize the line using comma as tokenizer */ pToken = strtok(s, ","); if (pToken == NULL) continue; /* add new experiment */ nExperiments++; /* allocate expIdList */ if (nExperiments == 1) expIdList = (int *)malloc(sizeof(int)*1); else expIdList = (int *)realloc(expIdList, sizeof(int)*nExperiments); expIdList[nExperiments - 1] = atoi(pToken); /* get path from next token */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* alloc expPathList */ if (nExperiments == 1) expPathList = (char **)malloc(sizeof(char*)*1); else expPathList = (char **)realloc(expPathList, sizeof(char*)*nExperiments); /* find string madtoc/ (7 chars long) */ strcpy(tmpStr, pToken); subStr = strstr(tmpStr, "madtoc/"); if (subStr == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* malloc expPathList, less 7 unneeded chars */ expPathList[nExperiments-1] = malloc(sizeof(char)*(strlen(subStr)-5)); strcpy(expPathList[nExperiments-1], subStr + 7); /* get name from next token */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* alloc expNameList */ if (nExperiments == 1) expNameList = (char **)malloc(sizeof(char*)*1); else expNameList = (char **)realloc(expNameList, sizeof(char*)*nExperiments); /* malloc expNameList */ expNameList[nExperiments-1] = malloc(sizeof(char)*(1+strlen(pToken))); strcpy(expNameList[nExperiments-1], pToken); /* skip next field - site id */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* get start date */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } date = atoi(pToken); /* get start time */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } time = atoi(pToken); /* convert to year, month, day */ year = date/10000; date = date - year*10000; month = date/100; day = date - month*100; /* convert to hour, min, sec */ hour = time/10000; time = time - hour*10000; min = time/100; sec = time - min*100; /* allocate expStarttime */ if (nExperiments == 1) expStarttime = (double *)malloc(sizeof(double)*1); else expStarttime = (double *)realloc(expStarttime, sizeof(double)*nExperiments); /* set expStarttime */ expStarttime[nExperiments - 1] = getKey(year, month, day, hour, min, sec); /* get end date */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } date = atoi(pToken); /* get end time */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } time = atoi(pToken); /* convert to year, month, day */ year = date/10000; date = date - year*10000; month = date/100; day = date - month*100; /* convert to hour, min, sec */ hour = time/10000; time = time - hour*10000; min = time/100; sec = time - min*100; /* allocate expEndtime */ if (nExperiments == 1) expEndtime = (double *)malloc(sizeof(double)*1); else expEndtime = (double *)realloc(expEndtime, sizeof(double)*nExperiments); /* set expEndtime */ expEndtime[nExperiments - 1] = getKey(year, month, day, hour, min, sec); /* get kinst */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* allocate expKinstList */ if (nExperiments == 1) expKinstList = (int *)malloc(sizeof(int)*1); else expKinstList = (int *)realloc(expKinstList, sizeof(int)*nExperiments); expKinstList[nExperiments - 1] = atoi(pToken); } (void) fclose(fp); /* raise error if nExperiments == 0 */ if (nExperiments == 0) { (void) cedarSetError(err3); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* now parse the fileTab.txt file */ cedarGetMadroot(infile); (void) strcat(infile, "/metadata/fileTab.txt"); if ((fp = fopen (infile, "r")) == NULL) { (void) cedarSetError(err2); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* Read fileTab.txt File */ while (fgets(s, 1200, fp) != NULL) { /* tokenize the line using comma as tokenizer */ pToken = strtok(s, ","); if (pToken == NULL) continue; /* add new file */ nFiles++; /* alloc fileFileNameList */ if (nFiles == 1) fileFileNameList = (char **)malloc(sizeof(char*)*1); else fileFileNameList = (char **)realloc(fileFileNameList, sizeof(char*)*nFiles); /* malloc fileFileNameList */ fileFileNameList[nFiles-1] = malloc(sizeof(char)*(1+strlen(pToken))); strcpy(fileFileNameList[nFiles-1], pToken); /* get expId */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err4); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* allocate fileExpIDList */ if (nFiles == 1) fileExpIDList = (int *)malloc(sizeof(int)*1); else fileExpIDList = (int *)realloc(fileExpIDList, sizeof(int)*nFiles); fileExpIDList[nFiles - 1] = atoi(pToken); /* get kindat */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err4); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* allocate fileKindatList */ if (nFiles == 1) fileKindatList = (int *)malloc(sizeof(int)*1); else fileKindatList = (int *)realloc(fileKindatList, sizeof(int)*nFiles); fileKindatList[nFiles - 1] = atoi(pToken); /* get category */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err4); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* allocate fileCategoryList */ if (nFiles == 1) fileCategoryList = (int *)malloc(sizeof(int)*1); else fileCategoryList = (int *)realloc(fileCategoryList, sizeof(int)*nFiles); fileCategoryList[nFiles - 1] = atoi(pToken); /* skip next six tokens */ for (i=0; i<6; i++) { pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err4); pthread_mutex_unlock(&cedar_mutex); return(-1); } } /* get permission */ pToken = strtok(NULL, ","); if (pToken == NULL) { (void) cedarSetError(err4); pthread_mutex_unlock(&cedar_mutex); return(-1); } /* allocate filePermissionList */ if (nFiles == 1) filePermissionList = (int *)malloc(sizeof(int)*1); else filePermissionList = (int *)realloc(filePermissionList, sizeof(int)*nFiles); filePermissionList[nFiles - 1] = atoi(pToken); } (void) fclose(fp); /* raise error if nFiles == 0 */ if (nFiles == 0) { (void) cedarSetError(err4); pthread_mutex_unlock(&cedar_mutex); return(-1); } pthread_mutex_unlock(&cedar_mutex); return(0); } /*********************************************************************** * * goodDataExists Returns 1 if record contains valid data at 2d parameter * index index2D. Valid data is when the absolute value * of any error parameter is not missing or knownbad. * If no error parameters, always returns 1. * 0 otherwise. * * arguments: * record pointer to Madrigal record * index into 2D parameter values * * returns: * 1 if 2d index contains valid data, * 0 if not * */ int goodDataExists(Int16 * recordp, int index2D) { int i; int num2DParms; int * list2DParams; double errorValue; int errParmFound = 0; /* get number of 2D parameters */ num2DParms = cedarGetMpar(recordp); /* get list of 2D parameters */ list2DParams = cedarGet2dParcodes(recordp); /* loop through each 2D parameter to find a real error measurement */ for (i = 0; i < num2DParms; i++) { /* check if a negitive (error) parameter, otherwise continue */ if (list2DParams[i] >= 0) continue; errParmFound = 1; /* check if a valid error value */ /* valid if not missing or knownbad */ errorValue = cedarGet2dParmValue(recordp, list2DParams[i], index2D); if (isnan(errorValue) || errorValue == knownbad) continue; else { /* good row */ free(list2DParams); return 1; } } free(list2DParams); /* if no error parameters, return 1 */ if (errParmFound == 0) return 1; /* no valid error code found */ return 0; }