/* * Copyright(c) 2017, Space Science and Engineering Center, UW-Madison * Refer to "McIDAS Software Acquisition and Distribution Policies" * in the file mcidas/data/license.txt */ /**** $Id: glmnks.c,v 1.13 2021/02/08 15:11:43 daves Exp $ ****/ /* ** Name: ** glmnks : ADDE point data server for GLM NetCDF source data. ** ** Interface: ** int ** main(int argc, char *argv[]) ** ** Input: ** argc : argument count ** argv : argument vector ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** 0 : success ** < 0 : failure, enumerated by text message returned to client ** ** Remarks: ** This is a subserver executed to deliver point data objects ** from NetCDF source files (rather than McIDAS MD files). It is ** general enough that it will work on any NetCDF point data files, ** as long as the following two preliminary conditions are met. ** ** 1. There must be a configuration file, named by schema/descriptor ** with a .cfg suffix (PT.cfg for an example dataset) that provides ** a mapping from McIDAS parameter name, units, and scale factor, to ** the corresponding NetCDF variable name. This file must be located ** in a MCPATH directory on the server. So, an example line from this ** file mapping the McIDAS latitude key to a NetCDF variable might look ** like: ** ** LAT DEG 4 Latitude ** ** 2. File naming and locating can be done one of two ways. The first ** way also utilizes the configuration file described above. You specify ** a directory mask and a file mask in the config file by two lines as ** shown in the example below: ** ** DIRMASK=/home/mcadde/mcidas/data/ ** FILEMASK=PT*.nc ** ** The directory and file masks are regular expressions describing ** a set of possible directories and a set of possible files. While this ** isn't the best example, it illustrates the point. ** ** If a DIRMASK and FILEMASK are not specified in the configuration ** file, the NetCDF files must be given unique names beforehand formed ** via the McIDAS schema/descriptor name concatenated with a four character ** text representation of the position number, with a suffix of .nc. ** For example, if I had NetCDF data that represents the GRET schema, ** and a particular file was to be used as dataset position 1, the ** filename would be GRET0001.nc. These files must also reside in a valid ** directory in MCPATH on the server. ** ** Categories: ** ADDE server */ #include #include #include #include #include #if defined(__APPLE__) #include #endif #include #include #include "mcidas.h" #include "mcidasp.h" #include "mcptreq.h" #include "mcncdf.h" #include "m0arg.h" #include "netcdf.h" #include "SDIUtil.h" #define MAXDIMS (100) /* * this structure is used to construct a position ordered list of * available NetCDF point data files. */ typedef struct ncdfnode_ { int posNum; int sDate; int sTime; int eDate; int eTime; char fileName[MAXPATHLENGTH]; struct ncdfnode_ * nextNode; } ncdfnode; /* * this structure is used to construct a list of all parameters needed * for this request, and any selection or ancillary info for the params. */ typedef struct parmnode_ { int keyParm; /* is this a requested param? */ int selParm; /* is this a select param? */ int selList; /* is the select a list? */ int selRange; /* is the select a range? */ float selRangeLo; /* low bound for select range */ float selRangeHi; /* high bound for select range */ char **tokenList; /* list of select tokens */ char parmName[5]; /* parameter text name */ char parmUnit[5]; /* parameter text units */ char selUnit[5]; /* select param text units */ int parmScale; /* parameter scale factor */ int numDims; /* number of dims in NetCDF variable */ int varId; /* NetCDF variable id for parameter */ int *dimIds; /* array of dimension ids */ int *lastDimSent; /* index of dimension -> to client */ size_t *dimIdx; /* array of dimension indices */ char *ncdfName; /* NetCDF name for parameter */ int nodePosn; /* position of this node in the stack */ float fillValue; /* fill value for parameter */ nc_type vType; /* variable type of parameter */ int uninitialized; /* flag: uninitialized dimension vrbl?*/ struct parmnode_ * nextNode; } parmnode; /* prototypes for functions local to this source module */ static int M0GetDimensionList( parmnode * , int *, int *[MAXDIMS], int , size_t ** , int ** ); static int M0GetVariableDims(parmnode * , size_t * , int * , int , size_t ** ); static int M0GetDayTime(parmnode * , size_t *, int * , int * , int * , int , int * ) ; int Mcmstohms(double, int *); void AddParmNode(parmnode **, parmnode **); parmnode * MakeParmNode(char *, int , PTREQUEST); int M0GetNCDFTimes(int, int, int, int **, int **); int M0GetValidDimensionIndex(int, int, int, parmnode *, int **, int *); int M0GetValidTimeDimensionIndex(int *, int *, int, parmnode *, int **, int *); int glm_parallax(float , float, float, float*, float*); int main ( int argc, char *argv[]) { /* variables used to deal with linked list of NetCDF file nodes */ ncdfnode *aftNode = NULL; /* after position Node pointer */ ncdfnode *befNode = NULL; /* before position Node pointer */ ncdfnode *fstNode = NULL; /* pointer to 1st position node */ ncdfnode *lstNode = NULL; /* pointer to last position node */ ncdfnode *newNode = NULL; /* new node position pointer */ ncdfnode *oldNode = NULL; /* old node position pointer */ ncdfnode *tmpNode = NULL; /* temporary position node pointer */ /* variables used to deal with linked list of request parameter nodes */ parmnode *headNode = NULL; /* 1st parameter node pointer */ parmnode *parmNode = NULL; /* parameter node pointer */ parmnode *tempNode = NULL; /* temporary parameter node pointer */ char cfgFile[MAXPATHLENGTH] = {0}; /* config file name */ char cfgString[MAXPATHLENGTH]; /* string extract from config file */ char chArr[MAXPATHLENGTH]; /*array to look at NetCDF filenames char by char */ char cData[4] = {0}; /* data point from netcdf file */ char *dirMask=NULL; /* directory mask */ char emptyString; /* empty string for config file reads */ char basetimename[MAXPATHLENGTH]; /* netcdf name of basetime variable*/ char timeoffsetname[MAXPATHLENGTH]; /* netcdf name of time offset */ char *fileMask=NULL; /* file mask name */ char fileName[MAXPATHLENGTH]; /* absolute file path name */ char keyVal[MAXPATHLENGTH]; /* parameter, McIDAS representation*/ char selString[12]; /* error string for invalid select */ char tFill[MAXPATHLENGTH]; /* text Fill value for netcdf var */ char * comment; /* ADDE comment field from sxdatasetinfo */ char * cfgField = NULL; /* text field from configfile */ char * cDsc; /* descriptor name (GRET, ARET, etc.) */ char * cPos; /* position number */ char * dataset; /* ADDE dataset name */ char * dirStr; /* directory taken from MCPATH */ char * toPtr = NULL; /* time offset pointer */ char * btPtr = NULL; /* basetime character string */ char * format; /* ADDE dataset format field */ char * keyList; /* array of keys for this request */ char * group; /* ADDE dataset group name */ char * info; /* ADDE dataset info field */ char * mask; /* mask name from m0sxdatasetinfo */ char * mcPath; /* MCPATH environment variable */ char * request = NULL; /* pointer to client request text */ char * type; /* ADDE dataset type field */ char * unitList; /* array of unit strings for request */ char ** cfgFiles; /* list of config file names */ char ** flist = NULL; /* list of file names */ char ** keyVec; /* vector of Valid Keys */ char ** vecPtr = NULL; /* used to traverse vector of parameters */ char ** dimNames; /* array of dimension names */ const char server[] = {"glmnks"}; /* the names of this server */ const char *dum; /* dummy variable for the arg fetchers */ double dFill; /* fill (missing) value, dbl precision */ float fData; /* float format single data value */ float fDatatmp; /* float format single data value */ float fFill; /* fill (missing) value, sngl precision */ float fOrigVal; /* float un-altered netcdf value */ int bPos = 0; /* begin position for datasets */ int *dimarray[MAXDIMS]; /* valid values of the dimensions to send */ /* back to the client */ int dimarraysize[MAXDIMS]; /* # valid dimensions to send to client */ int *dimsize=NULL; /* array of dimension sizes */ int *dimidps=NULL; /* array of dimension ids */ int ePos = 0; /* ending position for datasets */ int foundBaseTime = 0; /* found a base time in netcdf file */ int foundTimeOffset = 0; /* found time offset in netcdf file */ int foundDirMask = 0; /* flad indicating a directory mask */ int foundFileMask = 0; /* flag indicating file mask found */ int hiBound; /* posn bound for argument validation */ int i,ii; /* looping variable */ int idMatch = 0; /* matched ids for flagged dimensions */ int iData; /* integer format single data value */ int iFill; /* fill (missing) value, integers */ int *index = NULL; /* index values of valid dimensions */ int j,jj; /* looping variable */ int keyCount = 0; /* number of parameters requested */ int keyFound = 0; /* non-zero if valid schema/dataset key */ int keyIdx = 0; /* parameter # being worked on (zero based)*/ int latIdx = -1; /* index of latitude */ int lonIdx = -1; /* index of longitude */ int loBound; /* posn bound for argument validation */ int maxDimPosn; /* where in stack list is max dim array? */ int maxDims = 0; /* max dimensionality of all vars in NCDF file*/ int maxPosNum = 0; /* maximum position # for a NetCDF file */ int maxRecs = 1; /* max records in particular NetCDF file */ int maxSet = 0; /* is max possible records set? */ int missingVal; /* missing value code in native byte order */ int ncdfId; /* id for the current NetCDF file */ int nindex; /* number of dimension indices */ int numBytes; /* number bytes sent back */ int numDims; /* # netcdf dimensions for variable*/ int numRecsFound = 0; /* number of total records found */ int numRecsFile = 0; /* number of records found in this file */ int ndimsp,nvarsp,ngattp,unlimimp; /* returned from nc_inq_att */ int maxRecsWanted = 0; /* max number of records wanted */ int numRecsWanted = 1; /* number records to send back */ int allRecsWanted; /* FLAG to signal we want ALL records */ int num_flist; /* number of file list names */ int paramDay = 0; /* is DAY a parameter to send back*/ int paramTime = 0; /* is TIME a parameter to send back*/ int prmFound = 0; /* non-zero if valid key in parameter clause */ int rc, rc_att; /* return code from function call */ int rec = 0; /* loop control vrbl, record number*/ int rt_flag; /* ADDE dataset rt_flag field */ int scaleFacs[8] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000}; int nselect; /* counter for filtered select variables */ int selectDay; /* is DAY in the select clause? */ int selectPlax; /* is PLAX in the select clause? */ int selectTime; /* is TIME in the select clause? */ int FilterByTime; /* use time to filter the files */ int timeID=-1; /* which is the time dimension? */ int timedim=-1; /* which is the time dimension? */ int timelength=0; /* Number of different times... */ int trace = 0; /* trace toggle (on/off) */ int validRec = 0; /* Found a Valid record */ int validSel = 1; /* record passes all select criteria*/ int validTimeDimensions=0; /* is time a dimension? */ int varId = 0; /* variable's netcdf id */ int * data; /* array of data for 1 point object returned */ int * dimIds = NULL; /* dimension id array (max dimensionality */ int * dimnumbers = NULL; int * scaleList; /* array of scale factors for this request */ int * refcyd = NULL; /* array of days in file */ int * refhms = NULL; /* array of times in file */ /* the next three variables are used to */ /* store the dimension array indices for */ /* the last variable read from the netcdf*/ /* file */ int * LastDimensionReadFromFile = NULL; /* dimension index (or indices) */ int * DimensionIDInteger = NULL; /* the integer used by netcdf file to */ /* refer to a particular dimension */ int number_of_dimensions; /* I hope this is self-explanatory */ servacct requestBlock = {0}; /* request block servacct struct */ short sFill; /* short fill value for a NetCDF variable */ size_t * dim_index = NULL; /* dimension index to get from netCDF file */ struct dirent * entry; /* current dirent item being examined */ unsigned char uFill; /* unsigned char fill value for NetCDF var */ size_t dimLen; /* NetCDF dimension length variable */ DIR * dir; /* current directory we are working in */ FILE * cfp; /* config file pointer */ PTREQUEST ptReq = {0}; /* a point data request structure */ float scale_factor, add_offset; /* ********************************************************************* */ /* added for GLM datasets */ char *file_name; char *c_date; /* date string */ char *c_day; /* day string */ char *units; double d_parm; /* double precision value */ double d_hms; /* double precision time */ int attsize=NULL; /* unit sizes */ int attlength; int file_handle; /* handle to parsed file name */ int length; /* character length of a parsed file name token */ int len_cdate; /* length of date string */ int i_parm; /* index into the parsed file name */ int n_parm; /* number of parsed file name tokens */ int cyd; /* file CCYYDDD */ int hms; /* file HHMMSSS*/ int sec; /* file absolute seconds */ int current_day; /* today */ int current_time; /* gmt time */ int loBound_day; /* earliest day = 2017001 */ int loBound_time; /* earliest time = 00:00:00.0 */ int hiBound_day; /* latest day = today */ int hiBound_time; /* latest time = 23:59:59.9 */ int begDay; /* request beginning day */ int endDay; /* request ending day */ int begTime; /* request beginning time */ int endTime; /* request ending time */ int begSeconds; /* request beginning absolute seconds */ int endSeconds; /* request ending absolute seconds */ int begFSeconds; /* file beginning absolute seconds */ int endFSeconds; /* file ending absolute seconds */ int Num_check; /* passed position and time checks */ int Pos_check; /* pass flag for POS */ int Day_check; /* pass flag for DAY */ int Tim_check; /* pass flag for TIME */ int this_date; int this_time; int isDate,isTime; int ieDate,ieTime; int iPos; int MakeNode; int NumNode; int lapNumber; /* flag set after 1st file SCALES/KEYS/UNITS sent */ unsigned short sData; float sublon, flat, flon, plat, plon; /* struct tm dob; */ /* string contains parsing mask */ McArgSyntax filesyntax = {"/_.", "=", ".", "{\"", "}", "'", "'", NULL, "X", " "}; /* ********************************************************************* */ /* sublon = -89.5; Remove this after getting sublon from netCDF file */ /* initialize the subserver */ rc = M0InitLocalServer(server, argc, argv, &requestBlock, &request); if (rc < 0) { (void) strcpy(requestBlock.errormsg, "Unable to initialize server"); /* requestBlock.returncode = rc; */ requestBlock.returncode = -501; goto done; } /* extract point data request */ rc = McExtractPtRequest(server, &requestBlock, &ptReq); if (rc < 0) { (void) strcpy(requestBlock.errormsg, "Unable to extract client request"); /* requestBlock.returncode = rc; */ requestBlock.returncode = -502; goto done; } /* see if logging should be done, determined by hidden TRACE= flag in request string */ trace = M0IsTraceSet(request); if (trace > 0) { rc = putenv("MCLOG=/tmp"); sLogInit(argv[0], 0); sLogSetFill(); } /* ok to log some info now... */ sLog(1, "-- GLMNKS begin\n"); sLog(1, " trace flag: %d\n", trace); sLog(1, " request: %s\n", request); /* log the select clauses */ selectPlax = 0; nselect = 0; ii = 0; if (ptReq.n_select > 0) { for (i = 0; i < ptReq.n_select; i++) { if ( strstr(ptReq.select_string[i],"PLAX") != NULL ) { selectPlax = 1; } else { nselect++; ptReq.select_string[ii] = ptReq.select_string[i]; sLog(1, " select %d: %s\n", ii, ptReq.select_string[ii]); ii++; } } ptReq.n_select = nselect; } sLog(1," >>>>>> PLAX is in the select clause FLAG=%d\n",selectPlax); /* log the parameters requested */ if (ptReq.n_parameter > 0) { for (i = 0; i < ptReq.n_parameter; i++) { sLog(1, " parameter %d: %s\n", i, ptReq.parameter[i]); } } /* get dataset info, will need text for header text id field */ rc = M0sxdatasetinfo (request, &group, &dataset, &type, &format, &mask, &info, &comment, &loBound, &hiBound, &rt_flag); if (rc < 0) { sLog(1, " M0sxdatasetinfo failed, returns: %d\n", rc); (void) strcpy(requestBlock.errormsg, "Unable to load dataset info"); requestBlock.returncode = rc; goto done; } sLog(1, " datasetinfo gives Config file %s\n", info); sLog(1, " datasetinfo gives mask %s\n", mask); /* get the data paths -- this takes the mask in the mask variable ** and splits it into a directory mask and a file mask ****/ rc = XtractDataPath(mask,&dirMask,&fileMask,&foundDirMask,&foundFileMask); sLog(1," Xtract data path returns %d\n",rc); /* move the request back into the comm block */ (void) strncpy(requestBlock.text, request, sizeof(requestBlock.text)); /* will need an empty string for config file reads below */ (void) strcpy(&emptyString, ""); /* will need missing value in native byte order */ missingVal = MCMISSING4; M0swbyt4(&missingVal, 1); /* * grab the descriptor name desired */ rc = Mcargstr(0, "", 1, "", (const char **) &cDsc); sLog(1, " descriptor requested: %s\n", cDsc); /* everything looks good, try to satisfy request */ /* first, make sure the configuration file (in the 'info' variable) exists */ /* config file name is descriptor, with suffix .cfg */ if (info != NULL && strcmp(info,"") != 0) { (void)strcpy(cfgFile,info); sLog(1, " CFG FILE from INFO: %s\n", cfgFile); } else { /* the default config file name is PT.cfg -- ** where the first part is the ** name of the data ***/ (void) strcpy(cfgFile, cDsc); (void) strcat(cfgFile, ".cfg"); sLog(1, " CFG FILE from DESCRIPTOR: %s\n", cfgFile); } cfgFiles = VecNew(); cfgFiles = VecAdd(cfgFiles, cfgFile); rc = M0SetDefaultFiles((const char *) NULL, (const char **) cfgFiles, 1); if (rc < 0) { (void) strcpy(requestBlock.errormsg, "Unable to initialize configuration file"); requestBlock.returncode = rc; goto done; } else { sLog(1, " config file %s initialized ok\n", cfgFile); } (void) VecOld(cfgFiles); /* try and get list of valid keys from config file */ cfp = fopen(cfgFile, "r"); if (cfp == NULL) { sLog(1, " config Unable to open file %s\n", cfgFile); (void) sprintf(requestBlock.errormsg, "Unable to open configuration file: >%s<",cfgFile); requestBlock.returncode = rc; goto done; } else { sLog(1, " config file %s opened ok\n", cfgFile); } /* GLM configuration files do not include keys for DAY and TIME. The files contain millisecond OFFSETs from a BASETIME. NCDF provides a utility to convert the OFFSET/BASETIME fields to a standard CCYYDDDHHMMSS.SSS format. This server will return these values for DAY, TIME and MSEC keys of a standard McIDAS client request. */ /* initialize the time-offset variable name */ if( strstr(info, "EVENT") != NULL) { (void)strcpy(timeoffsetname,"event_time_offset"); } else if( strstr(info, "GROUP") != NULL ) { (void)strcpy(timeoffsetname,"group_time_offset"); } else if( strstr(info, "FLASH") != NULL ) { (void)strcpy(timeoffsetname,"flash_time_offset"); } else { (void) strcpy(requestBlock.errormsg, "Unknown GLM type from INFO"); sLog(1," Unknown GLM descriptor is: %s",info); requestBlock.returncode = -30; goto done; } /* toPtr += strlen("TIMEOFFSET="); */ /* strcpy(timeoffsetname, toPtr); */ foundTimeOffset = 1; foundBaseTime = 1; sLog(1," *** TIMEOFFSET variable name: %s\n",timeoffsetname); /* go through configuration file ** need to keep a vector of all parameters in schema to validate request ** and the time_offset variable name */ keyVec = VecNew(); while (fgets(cfgString, sizeof(cfgString), cfp) != NULL) { /* skip comment lines which start with a # (pound) character */ if (cfgString[0] == '\043') continue; /* skip empty lines */ if( strlen(cfgString) <= 1 ) continue; (void) memset(keyVal, 0, sizeof(keyVal)); rc = sscanf(cfgString, "%s", keyVal); if (rc != 1) { sLog(1, " unable to parse key val : %s\n",cfgString); continue; } keyVec = VecAdd(keyVec, keyVal); } /* close config file */ rc = fclose(cfp); /* go through requested params and make sure each is valid */ if (ptReq.n_parameter > 0) { for (i = 0; i < ptReq.n_parameter; i++) { keyFound = 0; vecPtr = keyVec; while (*vecPtr != NULL) { if (strcmp(ptReq.parameter[i], *vecPtr) == 0) { keyFound = 1; break; } vecPtr++; } /* If the key is not found, but it's DAY/TIME and there is a timeoffset, then we don't really have an error */ if (!keyFound) { if ( (strcmp(ptReq.parameter[i],"TIME") == 0 || strcmp(ptReq.parameter[i],"DAY") == 0 ) && foundTimeOffset ==1) { if (strcmp(ptReq.parameter[i],"TIME") == 0) { paramTime = 1; } if (strcmp(ptReq.parameter[i],"DAY") == 0) { paramDay = 1; } } else { (void) strcpy(requestBlock.errormsg, "Invalid return parameter requested"); sLog(1," Invalid parameter request is: %s",ptReq.parameter[i]); requestBlock.returncode = -30; goto done; } } } } sLog(1," Checked Requested Parameters to return -- they all exist\n"); /* go through requested select params and make sure each is valid */ selectTime = 0; selectDay = 0; if (ptReq.n_select > 0) { for (i = 0; i < ptReq.n_select; i++) { sLog(1,"*** THIS SELECT CLAUSE = %s\n",ptReq.select_string[i]); keyFound = 0; vecPtr = keyVec; while (*vecPtr != NULL) { if ( strstr(ptReq.select_string[i],"TIME") != NULL && foundBaseTime ==1 && foundTimeOffset == 1) { sLog(1," TIME is in the select clause\n"); selectTime = 1; keyFound = 1; break; } if ( strstr(ptReq.select_string[i],"DAY") != NULL && foundBaseTime ==1 && foundTimeOffset == 1) { sLog(1," DAY is in the select clause\n"); selectDay = 1; keyFound = 1; break; } if (strstr(ptReq.select_string[i], *vecPtr) == ptReq.select_string[i]) { keyFound = 1; break; } /* If the key is not found, but it's DAY/TIME and there is a basetime and a timeoffset, then we don't really have an error if ( strstr(ptReq.select_string[i],"TIME") != NULL && foundBaseTime ==1 && foundTimeOffset == 1) { sLog(1," TIME is in the select clause\n"); selectTime = 1; keyFound = 1; break; } if ( strstr(ptReq.select_string[i],"DAY") != NULL && foundBaseTime ==1 && foundTimeOffset == 1) { sLog(1," DAY is in the select clause\n"); selectDay = 1; keyFound = 1; break; } */ vecPtr++; } if (!keyFound) { (void) strcpy(requestBlock.errormsg, "Error in SELECT clause for "); rc = sscanf(ptReq.select_string[i], "%s", selString); (void) strcat(requestBlock.errormsg, selString); (void) strcat(requestBlock.errormsg, " -- parameter specified is not in dataset"); requestBlock.returncode = -30; goto done; } } } sLog(1," Checked Select Parameters to filter -- they all exist\n"); /* make a parameter node for each requested key */ if (ptReq.n_parameter > 0) { for (i = 0; i < ptReq.n_parameter; i++) { parmNode = MakeParmNode(ptReq.parameter[i], 1, ptReq); (void) AddParmNode(&headNode, &parmNode); } } else { /* no specific parameters requested, so return all possible */ vecPtr = keyVec; while (*vecPtr != NULL) { parmNode = MakeParmNode(*vecPtr, 1, ptReq); (void) AddParmNode(&headNode, &parmNode); vecPtr++; } } /* now make a node for any that are only in a select clause */ if (ptReq.n_select > 0) { for (i = 0; i < ptReq.n_select; i++) { /* for each select, look through entire parm node list for match */ prmFound = 0; tempNode = headNode; while (tempNode != NULL) { if (strstr(ptReq.select_string[i], tempNode->parmName) == ptReq.select_string[i]) { prmFound = 1; break; } tempNode = tempNode->nextNode; } if (!prmFound) { rc = sscanf(ptReq.select_string[i], "%s", keyVal); sLog(1,"Make select Parm Node for >%s< >%s<\n", ptReq.select_string[i],keyVal); parmNode = MakeParmNode(keyVal, 0, ptReq); (void) AddParmNode(&headNode, &parmNode); } } } /* log the vector of key names */ parmNode = headNode; while (parmNode != NULL) { sLog(1, " node: %x key: %s \n", parmNode, parmNode->parmName); if (parmNode->keyParm) { keyCount++; } parmNode = parmNode->nextNode; } /* current position num max is limited to four digits, so 9999 */ maxPosNum = MAX_NCDF_FNUM; sLog(1, " max position num: %d\n", maxPosNum); /* * beginning and ending position - need to grab from keywords */ /* pick up beginning position num as a string first */ rc = Mcargstr(0, "POS", 1, "", (const char **) &cPos); /* if the user did specify ALL */ if (strcmp(cPos, "ALL") == 0) { bPos = 1; ePos = maxPosNum; } else { /* gotta pick up position as an integer */ sLog(1," get position between %d and %d\n",loBound,hiBound); rc = Mcargint(0, "POS", 1, loBound, loBound, hiBound, &bPos, &dum); if (rc < 0) { (void) sprintf(requestBlock.errormsg, "Position number specified is not valid"); requestBlock.returncode = rc; goto done; } /* just one position keyword, so set ePos to bPos and be done with it */ ePos = bPos; } /* * beginning and ending day/time - need to grab from SELECT */ /* scan parmNodes for DAY and TIME Ranges */ parmNode = headNode; sLog(1, "*** SELECTDAY=%d\n",selectDay); sLog(1, "*** SELECTTIME=%d\n",selectTime); while (parmNode != NULL) { if( selectDay == 1 && strstr(parmNode->parmName,"DAY") != NULL ) { loBound_day = (int) (parmNode->selRangeLo); hiBound_day = (int) (parmNode->selRangeHi); rc = Mcargiyd(0, "DAY", 1, loBound_day, loBound_day, hiBound_day, &begDay, &dum); if (rc < 0) { (void) sprintf(requestBlock.errormsg, "Beginning Day specified is not valid"); requestBlock.returncode = rc; goto done; } rc = Mcargiyd(0, "DAY", 2, hiBound_day, begDay, hiBound_day, &endDay, &dum); if (rc < 0) { (void) sprintf(requestBlock.errormsg, "Ending Day specified is not valid"); requestBlock.returncode = rc; goto done; } } if( selectTime == 1 &&strstr(parmNode->parmName,"TIME") != NULL ) { loBound_time = (int) (parmNode->selRangeLo); hiBound_time = (int) (parmNode->selRangeHi); rc = Mcargihr(0, "TIM.E", 1, loBound_time, loBound_time, hiBound_time, &begTime, &dum); if (rc < 0) { (void) sprintf(requestBlock.errormsg, "Beginning Time specified is not valid"); requestBlock.returncode = rc; goto done; } rc = Mcargihr(0, "TIM.E", 2, hiBound_time, begTime, hiBound_time, &endTime, &dum); if (rc < 0) { (void) sprintf(requestBlock.errormsg, "Ending Time specified is not valid"); requestBlock.returncode = rc; goto done; } } parmNode = parmNode->nextNode; } /* compute the absolute seconds of the beginning day/time and ending day/time */ FilterByTime = 0; if( selectDay == 1 && selectTime == 0 ) { begTime = 0; endTime = 235959; rc = Mcdaytimetosec( begDay, begTime, &begSeconds ); rc = Mcdaytimetosec( endDay, endTime, &endSeconds ); FilterByTime = 1; sLog(1, " SELECT DAY range: %d to %d\n", begDay,endDay); sLog(1, " SELECT TIME range: %d to %d\n", begTime,endTime); } if( selectDay == 1 && selectTime == 1 ) { rc = Mcdaytimetosec( begDay, begTime, &begSeconds ); rc = Mcdaytimetosec( endDay, endTime, &endSeconds ); FilterByTime = 1; sLog(1, " SELECT DAY range: %d to %d\n", begDay,endDay); sLog(1, " SELECT TIME range: %d to %d\n", begTime,endTime); } /* max records to send back, pick up integer keyword */ rc = Mcargint(0, "MAX", 1, 1, 1, 99999999, &numRecsWanted, &dum); if (rc < 0) { (void) strcpy(requestBlock.errormsg, "Invalid max records to return"); requestBlock.returncode = rc; goto done; } /* ALL records wanted */ allRecsWanted = 0; if( numRecsWanted == 999999 ) allRecsWanted = 1; maxRecsWanted = numRecsWanted; /* status log the keyword params gathered */ sLog(1, " bPos: %d, ePos: %d, numRecsWanted: %d\n",bPos,ePos,numRecsWanted); /* now we make a position num ordered list of available entries */ /* if config file had directory and file mask, use that method */ if ((foundDirMask==1) ) { /* get the list of files matching the mask condition */ flist = M0GetMaskFileList(mask); if (flist == (char **) NULL) { (void)strcpy(requestBlock.errormsg,"Failed to generate file mask list"); requestBlock.returncode = -30; goto done; } else { num_flist = VecLen(flist); sLog(1, " Number of source files= %d\n", num_flist); } if (num_flist <= 0 ) { (void)strcpy(requestBlock.errormsg,"No files found matching mask"); requestBlock.returncode = -30; goto done; } /* loop through the list and remove file names that are valid for time range */ NumNode = 0; for (i=0; i= 0 ) { /* start time */ rc = Mcargstr( file_handle, " ", i_parm+2, " ", &c_date); len_cdate = strlen( c_date ); for( jj=1; jj= begSeconds && begFSeconds <= endSeconds ) { Day_check = 1; Tim_check = 1; } /* if ((isDate >= begDay) && (ieDate <= endDay)) Day_check = 1; if ((isTime >= begTime) && (ieTime <= endTime)) Tim_check = 1; */ } } /* free the file handle */ rc = Mcargfree( file_handle ); /* Should we make a new node 0=NO, 1=YES */ if( FilterByTime == 1 ) { MakeNode = 0; if( Day_check == 1 && Tim_check == 1 ) MakeNode = 1; } else { MakeNode = 1; } /* exclude based on position */ if( Pos_check == 0 ) MakeNode = 0; /* allocate a new node */ if( MakeNode == 1 ) { /* allocate memory for a new node */ newNode = (ncdfnode *) calloc((size_t) 1, sizeof(ncdfnode)); if (newNode == NULL) { (void)strcpy(requestBlock.errormsg, "Unable to allocate memory\n"); requestBlock.returncode = -109; goto done; } else { /* increment the node counter */ NumNode++; /* set the position number */ newNode->posNum = NumNode; /* set the file name */ (void) strcpy(newNode->fileName, fileName); /* set the start time */ newNode->sDate = isDate; newNode->sTime = isTime; /* set the end time */ newNode->eDate = ieDate; newNode->eTime = ieTime; newNode->nextNode = NULL; /* set the node pointers */ if (fstNode == NULL) { fstNode = newNode; aftNode = newNode; } else { aftNode->nextNode = newNode; aftNode = newNode; } } } } } else { /* otherwise, we use the MCPATH method */ mcPath = (char *) getenv("MCPATH"); /* break this into individual directories */ dirStr = strtok(mcPath, ":"); sLog(1, "\n now working in MCPATH directory: %s\n", dirStr); while (dirStr != (char *) NULL) { if ((dir = opendir(dirStr)) == NULL) { dirStr = strtok((char *) NULL, ":"); if (dirStr != NULL) { sLog(1, "\n now working in MCPATH directory: %s\n", dirStr); } continue; } /* got an open directory, now process the entries */ while ((entry = readdir(dir)) != NULL) { /* target files gotta have nc suffix, and the descriptor entered */ if ((strstr(entry->d_name, ".nc") != NULL) && (strstr(entry->d_name, cDsc) != NULL)) { sLog(1, "\n starting to examine a NetCDF file...\n"); /* try to open as NetCDF file */ (void) strcpy(fileName, dirStr); (void) strcat(fileName, "/"); (void) strcat(fileName, entry->d_name); /* just make sure NetCDF file opens ok */ rc = nc_open(fileName, NC_NOWRITE, &ncdfId); if (rc != NC_NOERR) { sLog(1, " failed to open NetCDF file %s\n", fileName); continue; } else { sLog(1, " NetCDF file successfully opened!\n"); } /* can close NetCDF file now, don't need it anymore */ rc = nc_close(ncdfId); if (rc != NC_NOERR) { sLog(1, " failed to close NetCDF file ...\n"); continue; } else { sLog(1, " NetCDF file closed ok...\n"); } sLog(1, " making node from this file: %s\n", entry->d_name); /* allocate a new node and bump (potential) send count */ newNode = (ncdfnode *) calloc((size_t) 1, sizeof(ncdfnode)); if (newNode == NULL) { (void)strcpy(requestBlock.errormsg, "Unable to allocate memory\n"); requestBlock.returncode = -109; goto done; } /* fill in node fields */ /* first, extract and convert position number portion of file name */ (void) strcpy(chArr, entry->d_name); /* set pointer to first digit in file name */ i = 0; while (!isdigit(chArr[i])) { i++; } /* convert this part of file name to a position number */ rc = sscanf(&chArr[i], "%d.nc", &(newNode->posNum)); (void) strcpy(newNode->fileName, fileName); newNode->nextNode = NULL; /* use the position num to insert node in list */ /* easy case, empty list - just set head to the new node */ if (fstNode == NULL) { fstNode = newNode; continue; } /* handle special case, insert at head of list */ if (fstNode->posNum > newNode->posNum) { newNode->nextNode = fstNode; fstNode = newNode; continue; } /* general case */ befNode = fstNode; for ( ; ; ) { aftNode = befNode->nextNode; /* end of list? */ if (aftNode == NULL) { break; } if (aftNode->posNum > newNode->posNum) { break; } befNode = aftNode; } befNode->nextNode = newNode; newNode->nextNode = aftNode; } } dirStr = strtok((char *) NULL, ":"); } } sLog(1, " \n Finished initial pass... number of nodes = %d\n", NumNode ); /* User may have specified a POSITION number ... In this case the previous loop will identify the position and validate the time bounds of the file. There will be only 1 file in the list. We need to reset the bPos and ePos to the be that file */ if( bPos == ePos ) { bPos = 1; ePos = 1; } /* walk through list, eliminating any nodes not within position range */ tmpNode = fstNode; while (tmpNode != NULL) { Num_check = 0; if ((tmpNode->posNum >= bPos) && (tmpNode->posNum <= ePos)) { lstNode = tmpNode; tmpNode = tmpNode->nextNode; Num_check ++; } else { /* move first node pointer if needed */ if (tmpNode == fstNode) { fstNode = fstNode->nextNode; } oldNode = tmpNode; tmpNode = tmpNode->nextNode; free(oldNode); } } if (lstNode != NULL) lstNode->nextNode = NULL; sLog(1, " \n Finished secondary pass ... number of nodes = %d\n", NumNode); tmpNode = fstNode; while (tmpNode != NULL) { /* sLog the positions/filenames */ sLog(1, " posnum= %d filename=%s \n", tmpNode->posNum,tmpNode->fileName); tmpNode = tmpNode->nextNode; } sLog(1, " \n file list walkthrough done\n\n"); /* we can exit early if position num requested doesn't exist in dataset */ if (fstNode == NULL) { (void) strcpy(requestBlock.errormsg, "No records match specified search conditions"); requestBlock.returncode = -1; goto done; } /* allocate space for key list, unit list */ keyList = calloc((size_t) keyCount, 4); unitList = calloc((size_t) keyCount, 4); scaleList = calloc((size_t) keyCount, 4); data = calloc((size_t) keyCount, 4); (void) memset(unitList, 0x20, (unsigned int) keyCount * 4); /* * walk through the list, sending point data objects as requested */ tmpNode = fstNode; lapNumber = 0; sLog(1, " \n Enter the send loop... \n\n"); while (tmpNode != NULL) { int kk,dimidp; size_t dimlength; char dimname[NC_MAX_NAME]; sLog(1, " Number of records sent so far = %d\n",numRecsFound); numRecsFile = 0; if( allRecsWanted == 1 ) numRecsWanted = 999999; /* open the NetCDF file this node refers to */ sLog(1, " OPEN FILE = %s\n", tmpNode->fileName ); rc = nc_open(tmpNode->fileName, NC_NOWRITE, &ncdfId); /* get the satellite subpoint longitude */ rc = nc_inq_varid(ncdfId,"nominal_satellite_subpoint_lon",&varId); rc = nc_get_var1_float( ncdfId, varId, 0, &sublon); sLog(1, " >>>>>> SATELLITE SUBLON = %f\n", sublon ); /* find the dimension names ... they can be used as SELECT ** criteria **** */ rc = nc_inq(ncdfId, &ndimsp, &nvarsp, &ngattp, &unlimimp); if (rc != NC_NOERR) { sLog(1, nc_strerror(rc)); goto done; } else { sLog(1, " NC_INQ returns: ndimsp = %d, unlimimp = %d\n", ndimsp,unlimimp ); } if (ndimsp > MAXDIMS) { sLog(1,"Too many dimensions in file: %d\n",ndimsp); /* note that MAXDIMS is completely artificial and ** is there to simplify things -- one could also ** malloc the required space on the fly ***/ goto endsend; } sLog(1,"#dims %d #vars %d #gattp %d unlim %d\n", ndimsp,nvarsp,ngattp,unlimimp); if (DimensionIDInteger == NULL) { /* initialize the arrays that hold the indices of the ** dimensions of the last variable read from the netcdf file ******/ int blksize; sLog(1,"Initialized the arrays for dimension indices\n"); number_of_dimensions = ndimsp; blksize = sizeof(int)*number_of_dimensions; DimensionIDInteger = (int *)malloc(blksize); LastDimensionReadFromFile = (int *)malloc(blksize); if (DimensionIDInteger == NULL || LastDimensionReadFromFile == NULL) { sLog(1,"Ran out of memory, malloc failed\n"); (void) strcpy(requestBlock.errormsg, "Memory allocation failed, no space left"); requestBlock.returncode = -10; goto done; } } dimNames = VecNew(); sLog(1,"*** START DIMENSION VERIFICATION: ndimsp=%d\n",ndimsp); for (kk=0 ; kk call M0GetValidDimensionIndex\n"); rc = M0GetValidDimensionIndex(ncdfId,dimidp,dimlength, headNode,&index,&nindex); sLog(1,"M0GetValidDimensionIndex returns %d %d \n",rc,nindex); if (rc < 0) { sLog(1,"Failure in M0GetValidDimensionIndex, rc = %d\n",rc); (void) sprintf(requestBlock.errormsg, "Select clauses parameter nonexistent"); requestBlock.returncode = -1; goto endsend; } dimarraysize[kk] = nindex; dimarray[kk] = index; if (nindex == -1) { sLog(1,"found no select clauses with %s dimension\n",dimname); sLog(1,"Discard no data based on %s \n",dimname); } for (i = 0; i < dimarraysize[kk] ; i++) { sLog(1,"DEBUG Save %d %d %d\n",i,index[i],dimarray[kk][i]); } } } sLog(1,"\n\nWe have checked through the dimensions for select clauses\n"); sLog(1,"Now go through and look to see if the keyNames exist! \n"); /* If you're here, and the SEL clause has time in it, you ** can't (yet) bail out if there are no times in the ** dimension list -- TIME could be a plain variable, ** not a dimension ******/ /* loop over the vector of key names */ keyIdx = 0; maxDimPosn = 0; parmNode = headNode; while (parmNode != NULL) { /* read the NetCDF parameter name from the config file */ rc = M0GetDefaultArgStr ( parmNode->parmName, &emptyString, 3, &(parmNode->ncdfName) ); /* if we can't find this key, continue loop at top */ /* Not necessarily an error -- can request a non-valid key among ** a binch of valids -- it'll just print out as missing */ if (rc < 0) { sLog(1, " unable to find NetCDF param name %s in config file\n", parmNode->parmName); parmNode = parmNode->nextNode; continue; } /* read the parameter (variable) id for the NetCDF file */ rc = nc_inq_varid(ncdfId, parmNode->ncdfName, &varId); sLog(1,"Read %s name and get varId %d\n",parmNode->ncdfName,varId); if (rc != NC_NOERR) { sLog(1,"try to find %s\n",parmNode->ncdfName); sLog(1,nc_strerror(rc)); if ( ( (strcmp(parmNode->ncdfName,"time") == 0 ) || (strcmp(parmNode->ncdfName,"TIME") == 0 ) || (strcmp(parmNode->ncdfName,"day") == 0 ) || (strcmp(parmNode->ncdfName,"DAY") == 0 ) ) && timeID > -1) { varId = timeID; sLog(1,"Push %d into the time var id...continue\n",timeID); } else { int ijk; /* if the parameter for which values are requested is ** a dimension, set the uninitialized flag which means ** that the indices of the array should be sent back. */ for (ijk=0;ijkncdfName); if (strcmp(dimNames[ijk],parmNode->ncdfName)==0) { sLog(1,"Found Match!, dimension id number is %d\n", dimidps[ijk]); varId = dimidps[ijk]; parmNode->uninitialized = 1; break; } } if (ijk < 0 || ijk >= ndimsp) { sLog(1,"Could not find parameter...aborting\n"); (void) strncpy(requestBlock.errormsg, "Error reading NetCDF file", sizeof(requestBlock.errormsg)); requestBlock.returncode = -6; rc = nc_close(ncdfId); rc = -6; goto endsend; } } } parmNode->varId = varId; sLog(1,"STORE POSITION NUMBER: %d\n",maxDimPosn); parmNode->nodePosn = maxDimPosn; maxDimPosn++; /* read the variable type */ rc = nc_inq_vartype(ncdfId, parmNode->varId, &(parmNode->vType)); sLog(1," netCDF param %s id # %d type %d\n",parmNode->ncdfName, parmNode->varId, parmNode->vType); if (rc != NC_NOERR) { sLog(1,nc_strerror(rc)); } /* read the variable fill value -- the value that is in *** the variable to denote its missing-ness ***/ if (parmNode->uninitialized == 0) { /* i.e., this parmNode does not ** refer to an uninitialized ** dimension attribute...we don't ** need fill values for uninitialized ** data values, nor do we need to ** know the dimensions of the dimension ** attributes. */ switch (parmNode->vType) { case NC_FLOAT: rc = nc_get_att_float ( ncdfId, parmNode->varId, "_FillValue", &fFill); if (rc == NC_NOERR) { sLog(1, " read NetCDF variable fill value: %f\n", fFill); parmNode->fillValue = fFill; } break; case NC_DOUBLE: rc = nc_get_att_double ( ncdfId, parmNode->varId, "_FillValue", &dFill); if (rc == NC_NOERR) { sLog(1, " read NetCDF variable fill value: %f\n", dFill); parmNode->fillValue = (float) dFill; } break; case NC_BYTE: rc = nc_get_att_uchar ( ncdfId, parmNode->varId, "_FillValue", &uFill); if (rc == NC_NOERR) { sLog(1, " read NetCDF variable fill value: %d\n", uFill); parmNode->fillValue = (float) uFill; } break; case NC_SHORT: rc = nc_get_att_short ( ncdfId, parmNode->varId, "_FillValue", &sFill); if (rc == NC_NOERR) { parmNode->fillValue = (float) sFill; } break; case NC_INT: rc = nc_get_att_int ( ncdfId, parmNode->varId, "_FillValue", &iFill); if (rc == NC_NOERR) { sLog(1, " read NetCDF variable fill value: %d\n", iFill); parmNode->fillValue = (float) iFill; } break; case NC_CHAR: sLog(1,"CHAR\n"); rc = nc_get_att_text ( ncdfId, parmNode->varId, "_FillValue", tFill); if (rc == NC_NOERR) { sLog(1, " read NetCDF variable fill value: %s\n", tFill); (void) memcpy(&(parmNode->fillValue), tFill, 4); } break; default: sLog(1,"FLOAT\n"); break; } /* read the number of dimensions for this parameter (variable) */ rc = nc_inq_varndims(ncdfId, parmNode->varId, &numDims); if (numDims == 0 && parmNode->varId == timeID) { numDims = 1; } parmNode->numDims = numDims; /* update max dims if needed */ if (maxDims < numDims) { maxDims = numDims; } /* allocate the parameter node space for dimension ids and indices */ parmNode->dimIds = calloc((size_t) numDims, sizeof(int)); parmNode->lastDimSent = calloc((size_t) numDims, sizeof(int)); parmNode->dimIdx = calloc((size_t) numDims, sizeof(size_t)); for (ii = 0; ii < numDims ; ii++) { parmNode->lastDimSent[ii] = -1; } /* fill dimension ids array */ rc = nc_inq_vardimid(ncdfId, parmNode->varId, parmNode->dimIds); if (rc != NC_NOERR) { (void) strncpy(requestBlock.errormsg, "Error reading NetCDF file", sizeof(requestBlock.errormsg)); requestBlock.returncode = -30; rc = nc_close(ncdfId); goto endsend; } for (kk=0 ; kkdimIds[kk], &parmNode->dimIdx[kk]); if (rc != NC_NOERR) { (void)strcpy(requestBlock.errormsg,"NetCDF dimension error"); requestBlock.returncode = -30; rc = nc_close(ncdfId); goto endsend; } } } else { /* for uninitialized variables, make ** dimIds and dimIdx placeholders ** Put the actual dimension value into ** dimIds **/ sLog(1,"Create node values for unintialized vars\n"); sLog(1,"\n\n\n MAKE SPACE FOR ->dimIds \n"); numDims = 1; parmNode->numDims = numDims; parmNode->dimIds = calloc((size_t) numDims, sizeof(int)); parmNode->lastDimSent = calloc((size_t) numDims, sizeof(int)); parmNode->dimIdx = calloc((size_t) numDims, sizeof(size_t)); parmNode->dimIds[0] = parmNode->varId; parmNode->dimIdx[0] = -1; parmNode->lastDimSent[0] = -1; } if (parmNode->keyParm) { /* build the parameter list */ (void) strncpy(&keyList[keyIdx * 4], parmNode->parmName,4); /* build the unit string list */ if (strcmp(parmNode->parmUnit,"MS") != 0) { (void) memcpy(&unitList[keyIdx * 4], parmNode->parmUnit, strlen(parmNode->parmUnit)); } else { (void) memcpy(&unitList[keyIdx * 4], "HMS ",strlen("HMS ")); } sLog(1, " storing units: %s\n", parmNode->parmUnit); /* store the scale factor */ rc = M0GetDefaultArgStr(parmNode->parmName, &emptyString, 2, &cfgField); rc = sscanf(cfgField, "%d", &scaleList[keyIdx]); sLog(1, " storing scale factor: %d\n", scaleList[keyIdx]); keyIdx++; } parmNode = parmNode->nextNode; } /* * validate the request based on NetCDF variable and dimension * implementations. */ /* * first, make sure all parameters of max dimensionality have * the same dimensions. */ /* allocate space for the dimension values used globally */ dimIds = calloc((size_t) maxDims, sizeof(int)); /* this loop checks the dim id numbers of the variables to ** be sent back/used as select criteria to make sure ** they are all matching ... It would make no sense ** */ parmNode = headNode; maxSet = 0; while (parmNode != NULL) { /* store first set of max dimension ids found for global use */ if ((parmNode->numDims == maxDims) && (maxSet == 0)) { for (i = 0; i < maxDims; i++) { dimIds[i] = parmNode->dimIds[i]; /* this is where we determine max possible records from dim lengths */ rc = nc_inq_dimlen(ncdfId, dimIds[i], &dimLen); /* force maxRecs */ if( maxRecs <= 0 ) maxRecs = 1; maxRecs = dimLen; } maxSet = 1; maxDimPosn = parmNode->nodePosn; } /* now we make sure each param of max dimension has same dimensions */ if (parmNode->numDims == maxDims) { for (i = 0; i < maxDims; i++) { if (parmNode->dimIds[i] != dimIds[i]) { (void) strncpy(requestBlock.errormsg, "Dimension MisMatch in request to NetCDF data", sizeof(requestBlock.errormsg)); requestBlock.returncode = -30; rc = nc_close(ncdfId); goto endsend; } } } parmNode = parmNode->nextNode; } /* * next, make sure all parameters of less than max dimensionality * have a dimension set that is a subset of those parameters of * maximum dimensionality. also, provide a mapping for these * dimensions to the max dimensionality order. */ parmNode = headNode; while (parmNode != NULL) { idMatch = 0; if (parmNode->numDims < maxDims) { for (i = 0; i < parmNode->numDims; i++) { for (j = 0; j < maxDims; j++) { if (parmNode->dimIds[i] == dimIds[j]) { idMatch = 1; /* found the match, break out of the loop */ break; } } } /* if any dimension ids don't match, can't fulfill request */ if (!idMatch) { (void) strncpy(requestBlock.errormsg, "Mismatch in parameter dimensions in NetCDF data", sizeof(requestBlock.errormsg)); sLog(1,"Didn't match any dimIds\n"); requestBlock.returncode = -30; rc = nc_close(ncdfId); goto done; } } parmNode = parmNode->nextNode; } if (maxDims == 0) { (void)strncpy(requestBlock.errormsg, "Dimensions requested have no values", sizeof(requestBlock.errormsg)); requestBlock.returncode = -150; rc = nc_close(ncdfId); goto done; } if (dim_index != NULL) { free(dim_index); } dim_index = (size_t *)malloc(sizeof(size_t)*maxDims); if (dim_index == NULL) { (void)strncpy(requestBlock.errormsg,"Server ran out of memory space", sizeof(requestBlock.errormsg)); requestBlock.returncode = -1*maxDims; rc = nc_close(ncdfId); goto done; } /* these are only sent the first time throught the loop */ if( lapNumber == 0 ) { numBytes = keyCount * 4; M0swbyt4(&numBytes, 1); M0sxsend(4, &numBytes); numBytes = keyCount * 4; M0sxsend(numBytes, keyList); numBytes = keyCount * 4; M0swbyt4(&numBytes, 1); M0sxsend(4, &numBytes); numBytes = keyCount * 4; M0sxsend(numBytes, unitList); numBytes = keyCount * 4; M0swbyt4(&numBytes, 1); M0sxsend(4, &numBytes); numBytes = keyCount * 4; M0swbyt4(scaleList, keyCount); M0sxsend(numBytes, scaleList); /* switch back, will need to use it */ M0swbyt4(scaleList, keyCount); /* increment the lapNumber */ lapNumber++; } /* adjust max records to file limit if exceeded */ /*if( maxRecs < 0 ) maxRecs = 0; */ sLog(1, " max records we could look at: %d\n", maxRecs); if (numRecsWanted > maxRecs) { numRecsWanted = maxRecs; sLog(1, " num records truncated to: %d\n", numRecsWanted); } for (rec = 0; rec < maxRecs; rec++) { /* reset valid record flag, gets set when we find good data */ validRec = 0; /* select ok until found otherwise */ validSel = 1; keyIdx = 0; parmNode = headNode; /* Get the dimension values that are valid for this send-back of data */ if(dim_index != NULL) free(dim_index); if(dimnumbers != NULL) free(dimnumbers); rc = M0GetDimensionList(parmNode,dimarraysize,dimarray,maxDimPosn, &dim_index, &dimnumbers); if (rc != 0) { /* We are done! */ if( rc == -10 ) goto endsend; requestBlock.returncode = 0; rc = nc_close(ncdfId); goto done; } while (parmNode != NULL) { size_t *DimIndex = NULL; if ( (strcmp(parmNode->parmName,"DAY") == 0 || strcmp(parmNode->parmName,"TIME") == 0) && validTimeDimensions == 1) { int timevalue; /* if day or time is requested, get them out of ** the refcyd and refhms arrays -- no need to ** query the netcdf file -- it's been done already! */ rc = M0GetDayTime(parmNode, (size_t *)dim_index, dimnumbers,refcyd, refhms,timedim,&timevalue); fData = (float) timevalue; if (strcmp(parmNode->parmUnit,"MS") == 0) { /* convert ms to hms */ double dval; int hms; dval = (double) fData; rc = Mcmstohms(dval,&hms); if (rc == 0) { fData = (float) hms; } else { fData = -1; } } } else { int iij; rc = M0GetVariableDims(parmNode, (size_t *)dim_index, dimnumbers, maxDims, &DimIndex); if (rc != 0) { /* found all the dimensions that exist ** so it's time to gracefully exit *******/ rec = maxRecs; break; } /* save the dimensions for the variable just obtained */ for (iij=0;iijncdfName, &varId); /* get the data ** if the data are really uninitialized dimension values ** no need to query the netcdf file */ if (parmNode->uninitialized==0) { switch (parmNode->vType) { /*only needed if dimensions all there*/ case NC_FLOAT: case NC_DOUBLE: case NC_BYTE: case NC_SHORT: case NC_INT: /* nc_get_var1_* requires an array to tell the routine ** which one variable to get in the possibly multi- ** dimensional array...for example if you want the ** 8th col and the 16th row, and column is the first ** array dimension, then dimIdx will be an array with ** values {8,16} in it **/ switch (parmNode->vType) { case NC_INT: rc = nc_get_var1_int( ncdfId, parmNode->varId, DimIndex, &iData); fData = (float) iData; break; case NC_SHORT: rc = nc_get_var1_short( ncdfId, parmNode->varId, DimIndex, &sData); fData = (float) sData; break; default: rc = nc_get_var1_float( ncdfId, parmNode->varId, DimIndex, &fData); break; } scale_factor = 0.0; rc_att = nc_get_att_float( ncdfId, parmNode->varId, "scale_factor", &scale_factor); if (rc_att < 0 || fabsf(scale_factor) < 0.000000001) scale_factor=1.0; add_offset = 0.0; rc_att = nc_get_att_float( ncdfId, parmNode->varId, "add_offset", &add_offset); if (rc_att < 0) add_offset=0.0; fData = fData*scale_factor+ add_offset; /* COMMENT THIS OUT FOR NOW rc = nc_inq_attlen( ncdfId, parmNode->varId, "units", &attlength ); if( attlength > 0 ) { if (attsize == NULL) { units = (char **) malloc((attlength+1)*sizeof(char)); } else { units = (int *) realloc(units, (attlength+1)*sizeof(char)); } if( units == NULL ) return(-100); attsize = attlength+1; sLog(1,"LENGTH OF THE UNITS VAR = %d\n",attlength); (void) memset(units, NULL, (attlength+1)*sizeof(char)); rc_att = nc_get_att_string (ncdfId, parmNode->varId, "units", units); sLog(1,"UNITS VAR = %s %s %s %s %s %s \n",units[0],units[1],units[2],units[3],units[4],units[5] ); } */ if (strstr(parmNode->parmName,"TIME") != NULL) { if (strcmp(parmNode->parmUnit,"MS") == 0) { double dval; int hms; dval = fData; rc = Mcmstohms(dval,&hms); fData = hms; } } break; case NC_CHAR: rc = nc_get_var1_text ( ncdfId, parmNode->varId, DimIndex, &cData[0]); DimIndex[1]++; rc = nc_get_var1_text ( ncdfId, parmNode->varId, DimIndex, &cData[1]); DimIndex[1]++; rc = nc_get_var1_text ( ncdfId, parmNode->varId, DimIndex, &cData[2]); DimIndex[1]++; rc = nc_get_var1_text ( ncdfId, parmNode->varId, DimIndex, &cData[3]); parmNode->dimIdx[1] = 0; (void) memcpy(&fData, cData, 4); break; default: break; } if (rc != NC_NOERR) { (void) strncpy(requestBlock.errormsg, "Error reading NetCDF file", sizeof(requestBlock.errormsg)); requestBlock.returncode = rc; rc = nc_close(ncdfId); goto done; } } else { /* if the dimension is uninitialized, get ** the data from the array holding the last ** dimension index values retrieved from the ** netCDF file (This part of the code will ** be reached only if a dimension is being ** sent back or used as a select clause) */ int iik; for (iik = 0; iik < number_of_dimensions; iik++) { if (DimensionIDInteger[iik] == parmNode->varId) { fData = LastDimensionReadFromFile[iik] + 1; } } } } /* update the last sent data for this variable */ for ( i = 0 ; i < parmNode->numDims ; i++) { int tval; tval = parmNode->lastDimSent[i]; if( DimIndex != NULL) { parmNode->lastDimSent[i] = (int) DimIndex[i]; } } /* store original value, needed to check against fill value */ fOrigVal = fData; if (strcmp(parmNode->parmName, "LAT") == 0) { latIdx = keyIdx; } /* negate longitudes - McIDAS convention */ if (strcmp(parmNode->parmName, "LON") == 0) { fData = -fData; if (fData < -180.0) { fData = fData + 360.0; } lonIdx = keyIdx; } /* Compute the DAY */ if (strcmp(parmNode->parmName, "DAY") == 0) { fData = tmpNode->sDate; /* sLog(1,"*** DAY UNITS = %s\n",units); */ /* sLog(1,"*** DAY UNITS = %s\n",parmNode->parmUnit); */ /* dob = num2date( &fData, units, 'standard'); fData = ((1900+dob->tm_year)*1000) + (dob->tm_yday); */ } /* Compute the TIME */ if (strcmp(parmNode->parmName, "TIME") == 0) { fData = tmpNode->sTime; /* sLog(1,"*** TIME UNITS = %s\n",units); */ /* dob = num2date( &fData, units, 'standard'); fData = (dob->tm_hour*10000) + (dob->tm_min*100) + (dob->tm_sec); */ } /* only convert to scaled int if we intend to send this data */ if (parmNode->keyParm) { switch (parmNode->vType) { case NC_FLOAT: case NC_DOUBLE: case NC_BYTE: case NC_SHORT: case NC_INT: iData = (int) (fData * scaleFacs[scaleList[keyIdx]]); break; case NC_CHAR: (void) memcpy(&iData, cData, 4); M0swbyt4(&iData, 1); break; default: break; } if ((parmNode->vType == NC_FLOAT) && (fOrigVal == parmNode->fillValue)) { data[keyIdx] = missingVal; } else { data[keyIdx] = iData; validRec = 1; } keyIdx++; } if (parmNode->selParm) { /* range check */ if (parmNode->selRange) { if( (fData < parmNode->selRangeLo) || (fData > parmNode->selRangeHi) ) { /* check to see if time is requested .. if so, convert ** from dhr to ihr -- the select times are stored ** as ihr. **/ if (strcmp(parmNode->parmName,"TIME") == 0) { double dtime1,dtime2; int itime1,itime2; dtime1 = (double) parmNode->selRangeLo; dtime2 = (double) parmNode->selRangeHi; rc = Mcdhrtoihr(dtime1,&itime1); rc = Mcdhrtoihr(dtime2,&itime2); fData = itime1; if ( (fData < itime1) || (fData > itime2) ) { sLog(1, " discarding TIME record, val out of range... \n"); validSel = 0; } } else if (strcmp(parmNode->parmName,"DAY") == 0) { double dtime1,dtime2; int itime1,itime2; dtime1 = (double) parmNode->selRangeLo; dtime2 = (double) parmNode->selRangeHi; rc = Mcdhrtoihr(dtime1,&itime1); rc = Mcdhrtoihr(dtime2,&itime2); fData = itime1; if ( (fData < itime1) || (fData > itime2) ) { sLog(1, " discarding DAY record, val out of range... \n"); validSel = 0; } } else { if (strcmp(parmNode->parmName,"LON") == 0) { /* check for wrap - around longitudes ! */ sLog(1, " LON RANGE Lo=%f Hi=%f FDATA=%f \n",parmNode->selRangeLo, parmNode->selRangeHi,fData); /* this is the dateline check */ if (parmNode->selRangeLo > parmNode->selRangeHi) { fDatatmp = fData; if( fDatatmp < 0 ) fDatatmp = fData + 360; if( (fDatatmp <=parmNode->selRangeHi+360 ) && (fDatatmp >=parmNode->selRangeLo ) ){ sLog(1, " DATELINE: GOOD DATA \n" ); } else { sLog(1, " DATELINE: BAD DATA \n" ); validSel = 0; } } else { sLog(1, " NOT CROSSING THE DATELINE \n" ); if( (fData < parmNode->selRangeLo) || (fData > parmNode->selRangeHi) ) { sLog(1, " NOT DATELINE: BAD DATA \n" ); validSel = 0; } else { sLog(1, " NOT DATELINE: GOOD DATA \n" ); } } } else { sLog(1, " discarding record, val out of range...\n"); validSel = 0; } if( validSel == 0 ) break; } } } /* list check */ if (parmNode->selList) { vecPtr = parmNode->tokenList; validSel = 0; while (*vecPtr != NULL) { switch (parmNode->vType) { case NC_FLOAT: case NC_DOUBLE: case NC_BYTE: case NC_SHORT: case NC_INT: if (fData == ((float) atof(*vecPtr))) { validSel = 1; break; } break; case NC_CHAR: if (strncmp(cData, *vecPtr, 4) == 0) { validSel = 1; break; } break; default: break; } vecPtr++; } } } parmNode = parmNode->nextNode; free(DimIndex); } /* send if at least one param in record was valid data */ if ((validRec) && (validSel)) { /* If requested, return lat/lon without parallax correction */ if(selectPlax == 1 && latIdx != -1 && lonIdx != -1) { flat = (float) data[latIdx]/( (float)scaleFacs[scaleList[latIdx]]); flon = (float) data[lonIdx]/( (float)scaleFacs[scaleList[lonIdx]]); rc = glm_parallax(sublon, flat, flon, &plat, &plon); data[latIdx] = (int) (plat * scaleFacs[scaleList[latIdx]]); data[lonIdx] = (int) (plon * scaleFacs[scaleList[lonIdx]]); } numBytes = keyCount * 4; M0swbyt4(&numBytes, 1); M0sxsend(4, &numBytes); numBytes = keyCount * 4; for (j = 0; j < keyCount; j++) { M0swbyt4(&data[j], 1); } M0sxsend(numBytes, data); /* keep count of number of records found, exit loop if done */ numRecsFound++; numRecsFile++; if( allRecsWanted == 0 ) { if( numRecsFound == maxRecsWanted ) goto done; } if (numRecsFound == numRecsWanted) { break; } } } endsend: sLog(1, " \n end send loop... FileRecs=%d TotalRecs=%d\n",numRecsFile, numRecsFound); /* done with this NetCDF file, close it */ rc = nc_close(ncdfId); /* free up space this node is using */ oldNode = tmpNode; tmpNode = tmpNode->nextNode; free(oldNode); } /* if no point data objects were delivered, send an "error" message */ if (numRecsFound == 0) { (void) strncpy(requestBlock.errormsg, "No NetCDF file data satisfies the request", sizeof(requestBlock.errormsg)); requestBlock.returncode = -30; goto done; } done: /* test parallax sublon = -89.5; flat = 43.; flon = 89.; rc = glm_parallax(sublon, flat, flon, &plat, &plon); sLog(1, "parallax: %f %f %f %f\n", flat, flon, plat, plon); end parallax test */ /* termination */ M0sxdone(&requestBlock); sLog(1, "\n-- glmnks exit\n"); return (0); } /* *| Name: *| AddParmNode(headNode, parmNode) *| *| Interface: *| *| void *| AddParmNode(parmnode ** headNode, parmnode **parmNode) *| *| Input: *| headNode - first node in a list of parameter nodes *| parmNode - node to be added to linked list *| *| Input and Output: *| none *| *| Output: *| none *| *| Return values: *| NULL - failure *| !NULL - pointer to a parameter node *| *| Remarks: *| Add a parameter node to a linked list of nodes *| *| Categories: *| point */ void AddParmNode(parmnode ** headNode, parmnode ** parmNode) { /* * variables used: * * tempNode a parameter node pointer */ parmnode *tempNode; /* put new node on list, in order parameters are read from file */ tempNode = *headNode; if (tempNode == NULL) { *headNode = *parmNode; } else { while (tempNode->nextNode != NULL) { tempNode = tempNode->nextNode; } tempNode->nextNode = *parmNode; } return; } /* *| Name: *| MakeParmNode(keyName, keyFlag ptReq) *| *| Interface: *| *| parmnode * *| MakeParmNode(char * keyName, int keyFlat, PTREQUEST ptReq) *| *| Input: *| keyName - name of parameter for which node is being made *| keyFlag - 1 if sent back, 0 if only in select clause *| ptReq - info in point request string to server *| *| Input and Output: *| none *| *| Output: *| none *| *| Return values: *| NULL - failure *| !NULL - pointer to a parameter node *| *| Remarks: *| Make a parameter node and fill it with the appopriate information *| *| Categories: *| point */ parmnode * MakeParmNode(char *keyName, int keyFlag, PTREQUEST ptReq) { /* * variables used: * * parmNode a parameter node pointer * emptyString holds an empty string, for config file reads * selUnits units passed in for a selection parameter * cfgField text field from a configuration file * cPtr character pointer * token char token used to parse select clause * fLoVal select clause low value * fHiVal select clause high value * index index into arrays of select and param keys * rc return code * i loop control variable */ parmnode * parmNode; char emptyString; char selUnits[12]={""}; char *cfgField = NULL; char *cPtr = NULL; char *tPtr = NULL; char *dPtr = NULL; char *token; float fLoVal, fHiVal; int indx = 0; int rc; int i; /* will need an empty string for config file reads below */ (void) strcpy(&emptyString, ""); /* allocate memory for the new node */ parmNode = calloc((size_t) 1, sizeof(parmnode)); if (parmNode == NULL) return (parmNode); (void) strncpy(parmNode->parmName, keyName, sizeof(parmNode->parmName)); parmNode->selParm = 0; parmNode->keyParm = keyFlag; parmNode->nextNode = NULL; /* extract the unit string */ rc = M0GetDefaultArgStr(parmNode->parmName, &emptyString, 1, &cfgField); if (strcmp(cfgField, "X") == 0) { cfgField = NULL; } (void) strncpy(parmNode->parmUnit, cfgField, sizeof(parmNode->parmUnit)); /* see if it's a select key */ if (ptReq.n_select > 0) { for (i = 0; i < ptReq.n_select; i++) { if (strstr(ptReq.select_string[i], keyName) == ptReq.select_string[i]) { sLog(1, " param is a select clause: %s\n", keyName); parmNode->selParm = 1; indx = i; break; } } } /* if it was a select key, need to parse select clause */ if (parmNode->selParm == 1) { /* is it a select list or select range? look for a comma */ /* If it has a comma, then it's a list and you have to ** go through and pluck off all the values ****/ if (strstr(ptReq.select_string[indx], ",") != NULL) { sLog(1, " select clause is a list\n"); parmNode->tokenList = VecNew(); parmNode->selList = 1; /* align pointer with first list element */ cPtr = strchr(ptReq.select_string[indx], 0x20); sLog(1," first Cptr is %s\n",cPtr); cPtr++; sLog(1," add 1 to Cptr to get>%s<\n",cPtr); token = strtok(cPtr, ","); sLog(1," Token is %s\n",token); while (token != NULL) { char * ttoken; ttoken = (char *)malloc(sizeof(char)*500); (void)strcpy(ttoken,token); /* do something special if token is a time or a day -- ** convert the string to HHMMSS or to CCYYDDD **/ if (strcmp(keyName,"TIME") == 0) { int ok, ihr; ok = Mcstrtoihr(token,&ihr); sLog(1,"Time starts as %s becomes %d\n",token,ihr); (void)sprintf(ttoken,"%d",ihr); sLog(1,"Time starts as %d becomes %s\n",ihr,ttoken); } if (strcmp(keyName,"DAY") == 0) { int ok, iyd; ok = Mcstrtoiyd(token,&iyd); sLog(1,"Day starts as %s becomes %d\n",token,iyd); (void)sprintf(ttoken,"%d",iyd); sLog(1,"Day starts as %d becomes %s\n",iyd,ttoken); } /* if there is a blank in the token, consider the first ** value the token and the second value the units **/ if (strstr(token," ") != NULL) { char * ptr; sLog(1,"Separate units from token\n"); ptr = strrchr(token,' '); strcpy(&selUnits[0],ptr); ptr = strstr(token," "); *ptr = 0; sLog(1," Value is %s separated-out units are %s\n",token, selUnits); } parmNode->tokenList = VecAdd(parmNode->tokenList, ttoken); sLog(1, " new token: %s\n", ttoken); token = strtok((char *) NULL, ","); sLog(1, " new token: %s\n", token); free(ttoken); } goto END_OF_FUNCTION; } /* IF it's not a comma-separated list, it may be a range with a ** ' TO ' in it ... check that now **/ if (strstr(ptReq.select_string[indx]," TO ") != NULL) { sLog(1, "select clause is a range: %s\n",ptReq.select_string[indx]); parmNode->selRange = 1; cPtr = strstr(ptReq.select_string[indx],keyName); cPtr += strlen(keyName); /* if two values, will be separated by " TO " */ if (strstr(cPtr, " TO ") != NULL) { if (strcmp(keyName,"TIME") == 0) { /* TIME in range */ char * timestring1; char * timestring2; double doubletime1,doubletime2; int rc1,rc2; timestring1 = (char *)malloc(sizeof(char)*500); timestring2 = (char *)malloc(sizeof(char)*500); rc = sscanf(cPtr,"%s TO %s %s",timestring1,timestring2,selUnits); rc1 = Mcstrtodhr(timestring1,&doubletime1); rc2 = Mcstrtodhr(timestring2,&doubletime2); if (rc1 < 0 || rc2 < 0) { sLog(1,"Time conversion failed! %s\n",cPtr); return(NULL); } fLoVal = (float)doubletime1; fHiVal = (float)doubletime2; free(timestring1); free(timestring2); } else { if (strcmp(keyName,"DAY") == 0) { /* DAY in range */ char * daystring1; char * daystring2; int intday1,intday2; int rc1,rc2; daystring1 = (char *)malloc(sizeof(char)*500); daystring2 = (char *)malloc(sizeof(char)*500); rc = sscanf(cPtr,"%s TO %s %s",daystring1,daystring2,selUnits); rc1 = Mcstrtoiyd(daystring1,&intday1); rc2 = Mcstrtoiyd(daystring2,&intday2); if (rc1 < 0 || rc2 < 0) { sLog(1,"Time conversion failed! %s\n",cPtr); return(NULL); } fLoVal = (float)intday1; fHiVal = (float)intday2; free(daystring1); free(daystring2); } else { rc = sscanf(cPtr, "%f TO %f %s", &fLoVal, &fHiVal, selUnits); if (rc == 0) { sLog(1,"Tried to do a range over characters! %s\n", cPtr); return(NULL); } sLog(1, " sel range lo val: %f\n", fLoVal); sLog(1, " sel range hi val: %f\n", fHiVal); /* if sscanf converted 3 vals, there were units specified */ if (rc == 3) { sLog(1, " sel range units: %s\n", selUnits); } } } parmNode->selRangeLo = fLoVal; parmNode->selRangeHi = fHiVal; } goto END_OF_FUNCTION; } /* otherwise, must be a single value ( and there could be units ) */ parmNode->selList = 1; /* a list of 1, but a list */ sLog(1," Just one variable! %s\n",ptReq.select_string[indx]); cPtr = strstr(ptReq.select_string[indx],keyName); cPtr += strlen(keyName); sLog(1," cPtr is %s\n",cPtr); sLog(1," keyName is %s\n",keyName); /* see if we're working with DAY/TIME and convert to ** hhmmss or ccyyddd if necessary **/ if (strcmp(keyName,"TIME") == 0) { int ihr; /* the 100 was arbitrarily chosen */ tPtr = (char *)malloc(sizeof(char)*100); dPtr = (char *)malloc(sizeof(char)*100); rc = sscanf(cPtr,"%s %s",tPtr,selUnits); rc = Mcstrtoihr(tPtr,&ihr); (void)sprintf(dPtr,"%d",ihr); sLog(1, " sel list : %s\n", dPtr); free(tPtr); } else { if (strcmp(keyName,"DAY") == 0) { int iyd; dPtr = (char *)malloc(sizeof(char)*100); rc = sscanf(cPtr,"%s %s",dPtr,selUnits); sLog(1," DAY sscanf returns %d %s %s\n",rc,dPtr,selUnits); rc = Mcstrtoiyd(dPtr,&iyd); sLog(1," mcstrtoiud returns %s %d\n",dPtr,iyd); (void)sprintf(dPtr,"%d",iyd); sLog(1, " sel list : %s\n", dPtr); } else { dPtr = (char *)malloc(sizeof(char)*100); rc = sscanf(cPtr, "%s %s", dPtr, selUnits); sLog(1, " sel range lo val: %s\n", dPtr); /* if sscanf converted 2 vals, there were units specified */ if (rc == 2) { sLog(1, " sel range units: %s\n", selUnits); } } } /* save the list of 1 in the parmNode... */ parmNode->tokenList = VecNew(); parmNode->selList = 1; parmNode->tokenList = VecAdd(parmNode->tokenList, dPtr); } (void)strcpy(parmNode->selUnit,selUnits); END_OF_FUNCTION: ; return (parmNode); } /* *| Name: *| M0GetNCDFTimes( ncdfId, dimidp, dimlength, cyd, hms) *| *| Interface: *| *| int *| M0GetNCDFTimes(int ncdfId, int dimidp, int dimlength, *| int ** days, int ** times) *| *| Input: *| ncdfId - netcdf file ID pointer *| dimidp - netcdf dimension identifier of time variable *| dimlength - number of dimensions *| *| Input and Output: *| none *| *| Output: *| days - array of days associated with data, one for each point *| times - array of times associated with data, one for each point *| *| Return values: *| 0 - success *| *| Remarks: *| Query the netcdf file to determine the date for each data point *| *| Categories: *| point */ int M0GetNCDFTimes(int ncdfId,int dimidp,int dimlength,int **days,int **times) { /**** parameters passed in ********* ncdfId; id for current netcdf file dimidp; dimension id of parameter dimlength; number of entries in this dimension **days; array of dimlength days **times; array of dimlength times *****/ size_t start,count,leng; double *reftime; char *unit_str; nc_type nctypenull; int rc; int mpy; int baseday; int basetime; int ijk; int *refcyd; int *refhms; reftime = (double *)malloc(dimlength*sizeof(double)); sLog(1,"Get times dimlength is %d %d\n",dimlength,dimidp); start = 0; count = dimlength; rc = nc_get_vara_double(ncdfId,dimidp,&start,&count,reftime); sLog(1,"reftime time is %f\n",reftime[0]); /* get string length for ** malloc */ rc = nc_inq_att(ncdfId,dimidp,"units",&nctypenull,&leng); unit_str = (char *)malloc(sizeof(char)*(leng+1)); rc = nc_get_att_text(ncdfId,dimidp,"units",unit_str); sLog(1,"Unit string is %s\n",unit_str); if (strstr(unit_str,"since") != NULL) { int arg_hdl,ok,numminsec,numsec,nummin,nhours,srefhms; int newday,nday,numhourminsec; const char * str1 = NULL; const char * str2 = NULL; /* string is seconds since some time --- find out what that time is **** first set up the parsing... */ arg_hdl = Mcargparse( unit_str, NULL, NULL); if (arg_hdl < 0) { /* FUBAR */ return(-100); } ok = Mcargstr( arg_hdl, "", 0, "", &str1 ) ; if ( ok < 0 ) { return (-100); } ok = Mcargstr( arg_hdl, "", 1, "", &str2 ) ; if ( ok < 0 ) { return (-100); } mpy = 86400; if ( strcmp( str1, "hours") == 0) mpy = 3600; if ( strcmp( str1, "minutes") == 0) mpy = 60; if ( strcmp( str1, "seconds") == 0) mpy = 1; if ( mpy!= 0 && strcmp( str2, "since") == 0 ) { ok = Mcargiyd( arg_hdl, "", 2, 0, 1, 0, &baseday, NULL ); if ( ok < 0 ) { return (-101); } ok = Mcargihr(arg_hdl, "", 3, 0, 1, 0, &basetime, NULL ); if ( ok < 0 ) { return (-101); } sLog(1,"baseday %d basetime %d\n",baseday,basetime); } Mcargfree(arg_hdl); reftime[0] = reftime[0]*mpy; /* convert reftime to hhmmss format instead of seconds */ numminsec = ( (int) reftime[0])%3600; numsec = numminsec%60; nummin = (numminsec - numsec)/60; nhours = (reftime[0] - numminsec)/3600; numhourminsec = ( (int) reftime[0])%86400; nday = (reftime[0] - numhourminsec)/86400; nhours = nhours - nday*24; srefhms = numsec + 100*nummin + 10000*nhours; ok = Mcincday(baseday,nday,&newday); if (srefhms != 0) { int nuday,nutime; ok = Mcinctime(newday,basetime,srefhms,&nuday,&nutime); if (ok < 0) return(-200); newday = nuday; basetime = nutime; } } dimidp++; rc = nc_get_vara_double(ncdfId,dimidp,&start,&count,reftime); /* convert the times to cyd and hms formats -- first allocate ** space for it... */ refcyd = (int *)malloc(sizeof(int)*dimlength); refhms = (int *)malloc(sizeof(int)*dimlength); if (refcyd == NULL || refhms == NULL) return(-140); rc = nc_inq_att(ncdfId,dimidp,"units",&nctypenull,&leng); unit_str = (char *)malloc(sizeof(char)*(leng+1)); rc = nc_get_att_text(ncdfId,dimidp,"units",unit_str); sLog(1,"Unit string is %s\n",unit_str); if (strstr(unit_str,"since") != NULL) { int arg_hdl,ok,numminsec,numsec,nummin,nhours,srefhms; int newday,nday,numhourminsec; const char * str1 = NULL; const char * str2 = NULL; /* string is seconds since some time --- find out what that time is **** first set up the parsing... */ arg_hdl = Mcargparse( unit_str, NULL, NULL); if (arg_hdl < 0) { /* FUBAR */ return(-100); } ok = Mcargstr( arg_hdl, "", 0, "", &str1 ) ; if ( ok < 0 ) { return (-100); } ok = Mcargstr( arg_hdl, "", 1, "", &str2 ) ; if ( ok < 0 ) { return (-100); } mpy = 0; if ( strcmp( str1, "hours") == 0) mpy = 3600; if ( strcmp( str1, "minutes") == 0) mpy = 60; if ( strcmp( str1, "seconds") == 0) mpy = 1; if ( mpy!= 0 && strcmp( str2, "since") == 0 ) { ok = Mcargiyd( arg_hdl, "", 2, 0, 1, 0, &baseday, NULL ); if ( ok < 0 ) { return (-101); } ok = Mcargihr(arg_hdl, "", 3, 0, 1, 0, &basetime, NULL ); if ( ok < 0 ) { return (-101); } sLog(1,"baseday %d basetime %d\n",baseday,basetime); } Mcargfree(arg_hdl); reftime[0] = reftime[0]*mpy; /* convert reftime to hhmmss format instead of seconds */ numminsec = ( (int) reftime[0])%3600; numsec = numminsec%60; nummin = (numminsec - numsec)/60; nhours = (reftime[0] - numminsec)/3600; numhourminsec = ( (int) reftime[0])%86400; nday = (reftime[0] - numhourminsec)/86400; nhours = nhours - nday*24; srefhms = numsec + 100*nummin + 10000*nhours; ok = Mcincday(baseday,nday,&newday); sLog(1,"new day is %d\n",newday); sLog(1,"reftime %f sec %d min %d hours %d days %d leftoer hms %d\n", reftime[0],numsec,nummin,nhours,nday,srefhms); if (srefhms != 0) { int nuday,nutime; ok = Mcinctime(newday,basetime,srefhms,&nuday,&nutime); if (ok < 0) return(-200); newday = nuday; basetime = nutime; } sLog(1," day %d time %d\n",newday,basetime); for(ijk=0;ijkncdfName,tempNode->parmName, emptyString); rc = M0GetDefaultArgStr ( tempNode->parmName, &emptyString, 3, &(tempNode->ncdfName) ); sLog(1,"NCDF name=%s McIDAS name=%s\n",tempNode->ncdfName,tempNode->parmName); /* ..->selParm must be 1 for select clause */ if (tempNode->selParm == 1 && tempNode->parmName != NULL) { sLog(1,"checking for select string %s --> %s(%s)\n", tempNode->parmName,tempNode->ncdfName,dimname); rc = strcmp(tempNode->ncdfName,dimname); if (rc == 0) { npoints = 0; /* see how many points exist */ /**** we have a SEL clause that matches the netcdf ***** dimension ---- read in the the values for ***** the netcdf dimension values making sure you ***** read into the correct kind of array based ***** on the vType variable in the parmnode structure ***** ****/ /* double check -- do the dimension ids match too? */ /* can dimIds be initialized before now? */ if (tempNode->dimIds == NULL) { /* if the code reaches here, we may have the case wherein ** a non-initialized dimension is requested by array index ** value....If so, save the index (or indices) requested, ** subtracting one from the values to make them zero-based ** as in the netCDF file */ int value=-1; int ntokens; npoints = -1; if (tempNode->dimIds == NULL) { /* ** check to see if a select clause was entered for this ** dimension. If so, store 'em as index values */ ntokens = VecLen(tempNode->tokenList); if (ntokens == 0) { /* not a list -- better be a range!! */ if (tempNode->selRangeHi == tempNode->selRangeLo) { if (tempNode->selRangeHi == 0) { return(-500);} value = (int) tempNode->selRangeHi - 1; /* value must be zero-based */ if (value != tempNode->selRangeHi) { /* not an int, can't be array index */ return(-501); } } /* save the range of requested dimensions */ npoints = tempNode->selRangeHi-tempNode->selRangeLo+1; points = (int *)malloc(sizeof(int)*npoints); if (points==NULL) return(-505); for (i=tempNode->selRangeLo;iselRangeHi;i++){ int ii; ii = i - (int) tempNode->selRangeLo - 1;/* 0-base */ points[ii] = i; } } else { int jj; npoints = ntokens; points = (int *)malloc(sizeof(int)*npoints); if (points==NULL) return(-505); for (jj=0;jjtokenList[jj],&value); if (ok < 0) return(-502); points[jj] = value - 1; } } } if (npoints < 0) {return(-5);} } else { if (tempNode->dimIds[0] != dimidp) { int value=-1; int ntokens; npoints = -1; if (tempNode->dimIds[0] == 0) { /* ** check to see if a select clause was entered for this ** dimension. If so, store 'em as index values */ ntokens = VecLen(tempNode->tokenList); if (ntokens == 0) { /* not a list -- better be a range!! */ if (tempNode->selRangeHi == tempNode->selRangeLo) { if (tempNode->selRangeHi == 0) { return(-500);} value = (int) tempNode->selRangeHi - 1; /* value must be zero-based */ if (value != tempNode->selRangeHi) { /* not an int, can't be array index */ return(-501); } } /* save the range of requested dimensions */ npoints = tempNode->selRangeHi-tempNode->selRangeLo+1; points = (int *)malloc(sizeof(int)*npoints); if (points==NULL) return(-505); for (i=tempNode->selRangeLo;iselRangeHi;i++){ int ii; ii = i - (int) tempNode->selRangeLo - 1;/* 0-base */ points[ii] = i; } } else { int jj; npoints = ntokens; points = (int *)malloc(sizeof(int)*npoints); if (points==NULL) return(-505); for (jj=0;jjtokenList[jj],&value); if (ok < 0) return(-502); points[jj] = value - 1; } } } if (npoints < 0) {return(-5);} } if (tempNode->dimIds[0] == dimidp) { switch (tempNode->vType) { case NC_FLOAT: farray = (float *)malloc(sizeof(float)*dimlength); if (farray == NULL) return(-20); rc = nc_get_vara_float(ncdfId,dimidp,&start,&count,farray); if (rc != NC_NOERR) { sLog(1,"Error reading float variables\n"); return(-30); } if (tempNode->selRange == 1) { double loval = (double) tempNode->selRangeLo ; double hival = (double) tempNode->selRangeHi ; for (i=0;i= loval && farray[i] <= hival) { if (points == NULL) { points = (int *)malloc(sizeof(int)); } else { points = (int *)realloc(points,sizeof(int)* (npoints+1)); } points[npoints] = i; npoints++; } } } if (tempNode->selList == 1) { int ntokens; ntokens = VecLen(tempNode->tokenList); for (i=0;itokenList[j],&dblval); if ( (double)farray[i] == dblval) { if (points == NULL) { points = (int *)malloc(sizeof(int)); } else { points = (int *) realloc(points, sizeof(int)*(npoints+1)); } points[npoints] = i; npoints++; } } } } break; case NC_DOUBLE: darray = (double *)malloc(sizeof(float)*dimlength); if (darray == NULL) return(-20); rc = nc_get_vara_double(ncdfId,dimidp,&start,&count,darray); if (rc != NC_NOERR) { sLog(1,"Error reading float variables\n"); return(-30); } if (tempNode->selRange == 1) { double loval = (double) tempNode->selRangeLo ; double hival = (double) tempNode->selRangeHi ; for (i=0;i= loval && darray[i] <= hival) { if (points == NULL) { points = (int *)malloc(sizeof(int)); } else { points = (int *)realloc(points,sizeof(int)* (npoints+1)); } points[npoints] = i; npoints++; } } } if (tempNode->selList == 1) { int ntokens; ntokens = VecLen(tempNode->tokenList); for (i=0;itokenList[j],&dblval); if ( darray[i] == dblval) { if (points == NULL) { points = (int *)malloc(sizeof(int)); } else { points = (int *) realloc(points, sizeof(int)*(npoints+1)); } points[npoints] = i; npoints++; } } } } break; case NC_BYTE: case NC_SHORT: case NC_INT: iarray = (int *)malloc(sizeof(float)*dimlength); if (iarray == NULL) return(-20); rc = nc_get_vara_int(ncdfId,dimidp,&start,&count,iarray); if (rc != NC_NOERR) { sLog(1,"Error reading float variables\n"); return(-30); } if (tempNode->selRange == 1) { double loval = (double) tempNode->selRangeLo ; double hival = (double) tempNode->selRangeHi ; for (i=0;i= loval && iarray[i] <= hival) { if (points == NULL) { points = (int *)malloc(sizeof(int)); } else { points = (int *)realloc(points,sizeof(int)* (npoints+1)); } points[npoints] = i; npoints++; } } } if (tempNode->selList == 1) { int ntokens; ntokens = VecLen(tempNode->tokenList); for (i=0;itokenList[j],&intval); if ( iarray[i] == intval) { if (points == NULL) { points = (int *)malloc(sizeof(int)); } else { points = (int *) realloc(points, sizeof(int)*(npoints+1)); } points[npoints] = i; npoints++; } } } } break; case NC_CHAR: continue; break; default: sLog(1,"wrong netcdf variable type %d\n", tempNode->vType); } } } } } tempNode = tempNode->nextNode; } *nindex = npoints; *index = points; return(0); } /* *| Name: *| M0GetValidTimeDimensionIndex(int dimidp, int dimlength, *| parmNodew headNode, int ncdfId, int ** index) *| *| Interface: *| *| int *| M0GetValidTimeDimensionIndex(int *refcyd, int *refhms, int dimlength, *| parmNode * headNode, int **index, int * nindex) *| *| *| Input: *| refcyd - array of Julian Days for time dimension in netcdf file *| refhms - array of times for time dimension in netcdf file *| dimlength - number of elements in refcyd and refhms file *| headNode - Top of linked nodes *| *| Input and Output: *| none *| *| Output: *| index - list of array indices that contain values that *| match select clauses for this dimension *| nindex - number of elements in index array *| *| Return values: *| 0 - success *| -5 - id values don't match like they should *| -10 - incompatible lengths *| -20 - memory problems *| *| Remarks: *| Query the netcdf file to determine the date for each data point. *| refcyd or refhms may be filled with -1s if any old cyd/hms will *| do *| *| Categories: *| point */ int M0GetValidTimeDimensionIndex(int *refcyd, int *refhms, int dimlength, parmnode * headNode, int **index, int *nindex) { int ok; /* function return value */ int rc; /* function return value */ int i; /* loop bound */ int j; /* loop bound */ int isdayselect=0; /* a DAY select exists */ int istimeselect=0; /* a TIME select exists */ parmnode * tempNode; /* temporary node for searching nodes */ int * points_time = NULL;/* time points that are good */ int * points_day = NULL; /* day points that are good */ int * points_timeday = NULL;/* combination points that are good */ int npoints_time = 0; /* number of good time points */ int npoints_day = 0; /* number of good day points */ int npoints_timeday = 0;/* number of good combination points */ int selFound = 0; /* select clause with TIME found */ /* got through the nodes first to see if TIME= is matched */ tempNode = headNode; while (tempNode != NULL) { if (tempNode->selParm == 1) { /* must be 1 for select clause */ if (strcmp(tempNode->parmName,"TIME") == 0) { double loval = (double) tempNode->selRangeLo ; double hival = (double) tempNode->selRangeHi ; int ihrloval,ihrhival; selFound = 1; rc = Mcdhrtoihr(loval,&ihrloval); rc = Mcdhrtoihr(hival,&ihrhival); istimeselect = 1; /* we know the select parameter associated with this node is TIME ** Check to see if the TIMES stored in the hms array (of size ** dimlength) match the variables in the select list **/ if (tempNode->selRange == 1) { for (i = 0 ; i < dimlength ; i++) { if ( (refhms[i] >= ihrloval && refhms[i] <= ihrhival) || refhms[i] == -1) { /* point is in between values or is -1 -- good! */ if (points_time == NULL) { points_time = (int *)malloc(sizeof(int)); } else { points_time = (int *)realloc(points_time,sizeof(int)* (npoints_time+1)); } points_time[npoints_time] = i; npoints_time++; } } } if (tempNode->selList == 1) { int ntokens; ntokens = VecLen(tempNode->tokenList); for (i = 0 ; i < dimlength ; i++) { /* see if the values in the refhms array match those ** in the SELECT clause! ****/ for (j=0;jtokenList[j],&dblval); if ( (double)refhms[i] == dblval || refhms[i] < 0 ) { if (points_time == NULL) { points_time = (int *)malloc(sizeof(int)); } else { points_time = (int *) realloc(points_time, sizeof(int)*(npoints_time+1)); } points_time[npoints_time] = i; npoints_time++; } } } } } /* we now have an array containing good matches ** on the time -- go through and find good ** matches on DAY ****/ if (strcmp(tempNode->parmName,"DAY") == 0) { float loval = tempNode->selRangeLo ; float hival = tempNode->selRangeHi ; isdayselect = 1; selFound = 1; /* we know the select parameter associated with this node is DAY ** Check to see if the DAYS stored in the refcyd array (of size ** dimlength) match the variables in the select list **/ if (tempNode->selRange == 1) { for (i = 0 ; i < dimlength ; i++) { if ( (refcyd[i] >= loval && refcyd[i] <= hival) || refcyd[i] == -1) { /* point is in between values or is -1 -- good! */ if (points_day == NULL) { points_day = (int *)malloc(sizeof(int)); } else { points_day = (int *)realloc(points_day,sizeof(int)* (npoints_day+1)); } points_day[npoints_day] = i; npoints_day++; } } } if (tempNode->selList == 1) { int ntokens; ntokens = VecLen(tempNode->tokenList); for (i = 0 ; i < dimlength ; i++) { /* see if the values in the refcyd array match the list ** in the SELECT clause! ****/ for (j = 0 ; j < ntokens ; j++) { double dblval; ok = Mcstrtodbl(tempNode->tokenList[j],&dblval); if ( (double)refcyd[i] == dblval || refcyd[i] < 0 ) { if (points_day == NULL) { points_day = (int *)malloc(sizeof(int)); } else { points_day = (int *) realloc(points_day, sizeof(int)*(npoints_day+1)); } points_day[npoints_day] = i; npoints_day++; } } } } } } tempNode = tempNode->nextNode; } /* done with walk-through through nodes */ sLog(1,"Found %d matches on TIME \n",npoints_time); sLog(1,"Found %d matches on DAY \n",npoints_day); if (selFound == 0) { sLog(1,"Found no select clauses with TIME or DAY\n"); } else { sLog(1,"select clauses with TIME or DAY exist\n"); } /* Now find the times that match both DAY and TIME in the time ** dimension **/ npoints_timeday = 0; if (npoints_time > 0 && npoints_day > 0) { for (i = 0; i < npoints_time ; i++ ) { for ( j = 0 ; j < npoints_day ; j++) { if (points_day[j] == points_time[i]) { /* found good data pt */ if (points_timeday == NULL) { points_timeday = (int *)malloc(sizeof(int)); } else { points_timeday = (int *) realloc(points_timeday, sizeof(int)*(npoints_timeday+1)); } /* save the dimension value that is valid */ points_timeday[npoints_timeday] = points_time[i]; npoints_timeday++; } } } } else { if (npoints_time == 0) { if (npoints_day != 0) { sLog(1,"No time points %d day points\n",npoints_day); points_timeday = (int *)malloc(sizeof(int)*npoints_day); for (i = 0; i < npoints_day; i++) { points_timeday[i] = points_day[i]; } npoints_timeday = npoints_day; } else { /* no day points and no time points --- if there ** are no DAY/TIME select clauses, this is not an ** error...but it is if there are such select clauses */ if (selFound == 1) { /* error! */ return(-10); } npoints_timeday = -1; } } if (npoints_day == 0 && npoints_time != 0) { sLog(1,"No day points %d time points\n",npoints_time); points_timeday = (int *)malloc(sizeof(int)*npoints_time); for (i = 0; i < npoints_time; i++) { points_timeday[i] = points_time[i]; } npoints_timeday = npoints_time; } } /* now assign the array to be returned */ sLog(1," Matched %d points total \n",npoints_timeday); /* pass the array and the number back to calling program */ *nindex = npoints_timeday; *index = points_timeday; free(points_day); free(points_time); return(0); } /* *| Name: *| M0GetVariableDims - given a node, return the dimension *| array needed for the call to nc_get_var1_[int,short..] *| *| Interface: *| *| static int *| M0GetVariableDims( parmnode * thisNode, *| size_t *dimindex, int *dimIDs, int MaxDimNum, *| size_t ** Found) *| *| Input: *| thisNode - parameter node of data *| dimindex - array of valid dimension indices to fetch this time *| dimIDs - ID #s corresponding to dimensions in dimindex *| MaxDimNum - maximum number of dimensions *| *| Input and Output: *| none *| *| Output: *| Found - valid dimension to be sent to client *| *| Return values: *| 0 - success *| -1 - memory error *| *| Remarks: *| *| *| Categories: *| point */ static int M0GetVariableDims(parmnode * thisNode, size_t * dimindex, int * dimIDs, int NumDimensions, size_t ** Found) { size_t * tFound = NULL; /* which dimension to send back */ int i,j; /* loop bounds */ int ndims; /* 0-based number of dimensions */ int * LastDimSent=NULL; /* last dimensions sent to client */ ndims = thisNode->numDims; if(tFound != NULL) free(tFound); tFound = (size_t *)malloc(sizeof(size_t)*(MAXDIMS)); if (tFound == NULL) { return(-1); } /* initialize tFound to the last dimensions sent */ for (i = 0 ; i < ndims ; i++ ) { int iidim; iidim = thisNode->dimIds[i]; /* find match between this dimension and all the dimensions ** in the dimindex/dimIDs arrays **/ for (j = 0; j < NumDimensions ; j++) { if (dimIDs[j] == iidim) { tFound[i] = dimindex[j]; } } } *Found = tFound; return(0); } /* *| Name: *| M0GetDayTime - get the day or time that is valid *| for the dimension to be sent back *| *| Interface: *| *| static int *| M0GetDayTime( parmnode * thisNode, size_t * dimindex, int * dimIDs, *| int * days, int * times, int timedim, int * timevalue) *| *| Input: *| thisNode - parameter node *| dimindex - dimension index (or indices) to send back *| dimIDs - dimension IDs to send back *| timedim - dimension id for time dimension *| days - array of DAYS associated with time dimension *| times - array of TIMES associated with time dimension *| *| Input and Output: *| none *| *| Output: *| timevalue - single DAY or TIME value to be sent back to client *| *| Return values: *| 0 - success *| -1 - memory error *| -4 - dimension error in time *| *| Remarks: *| This function takes an array of days/times (of length as in dimsize) *| and the valid dimensions to be sent back, and it returns the day or *| time of the specific dimension number. *| *| Categories: *| point */ static int M0GetDayTime(parmnode * thisNode, size_t *dimindex, int * dimIDs, int * refcyd, int * refhms, int timedim, int * timevalue) { int i; /* loop bounds */ int dim; /* dimension we're dealing with now */ int ndimensions; /* number of dimensions in parameter */ int found = -1; int index_to_return; /* because this is extracting a time that is a dimension, there ** should be only one dimension, and it better be the timedimension! **/ ndimensions = thisNode->numDims; if (ndimensions > 1 || thisNode->dimIds[0] != timedim) { sLog(1,"Error in gettin time dimension: %d dimensions\n", ndimensions); sLog(1," dimensions id is %d time id is %d\n", thisNode->dimIds[0],timedim); return(-4); } /* See which dimension is the dimension to be saved */ dim = thisNode->dimIds[0]; found = -1; for (i = 0; i < ndimensions ; i++) { if (dimIDs[i] == dim) { sLog(1,"%d Looking for dim %d %d\n",i,refhms[i],refcyd[i]); found = i; } } if (found == -1) { sLog(1,"didn't find the right dimension %d\n",dim); return(-5); } index_to_return = dimindex[found]; sLog(1,"index to return is %d %s\n",index_to_return,thisNode->parmName); *timevalue = -1; if (strcmp(thisNode->parmName,"TIME") == 0) { *timevalue = refhms[index_to_return]; } else { if (strcmp(thisNode->parmName,"DAY") == 0) { *timevalue = refcyd[index_to_return]; } else { sLog(1,"Parameter incorrect! not DAY or TIME, but it is %s\n", thisNode->parmName); return(-6); } } sLog(1,"Time value found is %d \n",*timevalue); return(0); } /* *| Name: *| M0GetDimensionList - check through the list of *| parameter nodes, find the biggest in terms of *| dimensionality, and find which dimensions are to *| sent back *| *| Interface: *| *| static int *| M0GetDimensionList( parmnode * Head, int *dimarraysize, *| int maxDimPosn, int *dimarrayvalid[MAXDIMS], *| size_t ** Found, int ** dimensionlist) *| *| Input: *| Head - first node in list of parameter nodes *| dimarraysize - number of valid dimensions to be sent back *| dimarrayvalid - array indices of valid dimensions to be sent back *| maxDimPosn - parameter position with data of max dimensionality *| *| Input and Output: *| none *| *| Output: *| Found - valid dimension to be sent to client *| dimensionlist - list of dimensions to be sent to client *| *| Return values: *| 0 - success *| -1 - memory error *| -5 - No max dimension node found in node stack *| *| Remarks: *| *| *| Categories: *| point */ static int M0GetDimensionList( parmnode * Head, int *dimarraysize, int *dimarrayvalid[MAXDIMS], int maxDimPosn, size_t ** Found, int ** dimensionlist) { size_t * tFound = NULL; /* which dimension to send back */ int i,j; /* loop bounds */ int idim; /* dimension we're dealing with now */ int Inc = 0; /* successful incrementation? */ int ndims; /* 0-based number of dimensions */ int * LastDimSent=NULL; /* last dimensions sent to client */ parmnode * thisNode; /* the parm node we're talkin' aboutnow */ int * dimlist = NULL; /* list of dimensions to send back */ thisNode = Head; /* find the node that contains the maxDimPosn */ while (thisNode != NULL) { if (thisNode->nodePosn == maxDimPosn) break; thisNode = thisNode->nextNode; } if (thisNode == NULL) { /* didn't find max dimension node */ sLog(1,"Found no max position node in nodestack\n"); return(-5); } ndims = thisNode->numDims; if(tFound != NULL) free(tFound); if(LastDimSent != NULL) free(LastDimSent); if(dimlist != NULL) free(dimlist); tFound = (size_t *)malloc(sizeof(size_t)*(MAXDIMS)); if (tFound == NULL) { return(-1); } LastDimSent = (int *)malloc(sizeof(int)*(MAXDIMS)); if (LastDimSent == NULL) { free(tFound); return(-1); } dimlist = (int *)malloc(sizeof(int)*(MAXDIMS)); if (dimlist == NULL) { free(tFound); free(LastDimSent); return(-1); } /* initialize tFound to the last dimensions sent */ for (i = 0 ; i < ndims ; i++ ) { int iidim; iidim = thisNode->dimIds[i]; dimlist[i] = thisNode->dimIds[i]; tFound[i] = (size_t) thisNode->lastDimSent[i]; } /* we want to increment the last dimension values sent....to ** do this, we have to start at the end and work towards the ** front because the fastest-changing dimension is last in the ** list... ***/ Inc = 0; /* successful incrementing */ for ( i = ndims-1 ; i >= 0 ; i--) { /* subtract 1 from ndims (0-base it) */ idim = thisNode->dimIds[i]; if ( ( (int) tFound[i]) > -1 && Inc != 0) { /* Not checking dimension %d -- incremented already */ break; } /* Are its values */ if (dimarraysize[idim] < 1) { /*somehow restricted? NO*/ (tFound[i])++; if ((int)tFound[i] >= (int)thisNode->dimIdx[i]) { /* is the next value to send greater than the ** maximum index in the array? If so, reset ** the index to 0 and increment the next most ** quickly incrementing array dimension index **/ /* Sent all for this dimension, must increment lower dimensions */ /* start over for this dimension, set tFound to 0 */ tFound[i] = 0; } else { Inc = 1; LastDimSent[idim] = (int) tFound[i]; continue; } } else { /* values are restricted -- search through array ** to get next acceptable value */ int jj,kk; /* if it's a restricted value, 1st go through the ** dimarrayvalid array for the dimension to see ** which value was sent back last...then increment ** that index **/ kk = -1; for ( jj = 0; jj < dimarraysize[idim]; jj++) { if (dimarrayvalid[idim][jj] == (int) tFound[i]) { /* increment jj and save */ sLog(1,"index %d has a match -- increment it\n",i); kk = jj + 1; break; } if ((int)tFound[i] == -1) { kk = 0; break; } } if (kk != -1) { tFound[i] = kk; } else { sLog(1,"Found no match in dimension values sent\n"); if (i == 0) { free(tFound); free(LastDimSent); free(dimlist); return(-5); /* could not increment any more */ } } sLog(1,"Get restricted value # %d (out of %d)\n",tFound[i], dimarraysize[idim]); if ((int) tFound[i] >= dimarraysize[idim]) { tFound[i] = 0; } else { LastDimSent[i] = tFound[i]; tFound[i] = dimarrayvalid[idim][(int)tFound[i]]; sLog(1,"Found a value of %d\n",tFound[i]); Inc = 1; continue; } } } if (Inc == 0) { /* gone all way through dimensions */ free(tFound); free(LastDimSent); free(dimlist); return(-10); } *Found = tFound; *dimensionlist = dimlist; free(LastDimSent); return(0); } /* *| Name: *| glm_parallax - uncorrect GLM parallax *| *| Interface: *| int *| glm_parallax(float sublon, float lat, float lon, float *plat, float *plon) *| *| Input: *| sublon - subpoint longitude of satellite (east positive) *| lat - parallax corrected GLM latitude *| lon - parallax corrected GLM longitude (west positive) *| *| Input and Output: *| none *| *| Output: *| plat - parallax uncorrected GLM latitude *| plon - parallax uncorrected GLM longitude *| *| Return values: *| 0 - success *| <>0 - failure *| *| Categories: *| image */ float get_plax(float); int glm_parallax(float sublon, float lat, float lon, float *plat, float *plon) { Fint nav[128]; Fint one, two; int rc; Freal img_line, img_elem, dummy; Freal plaxh; const char *LL = "LL "; const char *ABIN = "ABIN"; const char *HGT = "HGT "; one = 1; two = 2; memcpy(&nav[0], ABIN, 4); nav[1] = 15186500; nav[2] = -15186500; nav[3] = -1400; nav[4] = 1400; nav[5] = (int) (sublon*10.); nav[6] = 1; rc = nvprep_(&one, nav); rc = nv1ini_(&two, (Fint*)LL ); plaxh = get_plax(lat); rc = nv1opt_(HGT, &plaxh, &dummy ); rc = nv1eas_(&lat, &lon, &dummy, &img_line, &img_elem, &dummy ); plaxh = 0.0; rc = nv1opt_((Fint*) HGT, &plaxh, &dummy ); rc = nv1sae_(&img_line, &img_elem, &dummy, plat, plon, &dummy ); return rc; } float get_plax(float lat) { float plaxh; plaxh = 16.*sin(0.0174533*(90.-fabs(lat))); return plaxh; }