/* function.c * * * Emilio 4/13/2001 * In SetModelParameters(), enlarged the size of the szLine char array * to be able to read longer lines from config file. Changed several * instances of the use of FILENAMELEN for the length of string arrays, * to LINELEN (longer). Added support for a mix of float and string * global parameters in SetModelParameters(). Changed GlobalCleanUp() * to free this memory. Did other minor fixes and cleanups. * * * Function file for all the C programs written to analyze binary and NetCDF * input and output for modelling using the Environmental Modeling Utilities, * or "EMU" package. ******************************************************************************/ #include "emu.h" #define SYSCFGFILE "./system.cfg" /* EXTERNAL VARIABLE defined in main application program file */ extern const char * cpszUsage; BOOL bSelectedConfigFileName; BOOL bNamedVariables; char * pszProgramName; char * pszConfigFile, * pszSystemConfigFile; char * pszCDLFile; /* is this functionality/variable actually used anymore ??? */ extern void ReadMask(void); /* LOCAL FUNCTIONS: Important "system" functions*/ BOOL ProcessDefaultCommandLineArgs(int * pArgc, char * argv[]); void Usage(const char * cpszUsage); void ReadSystemConfigFile(void); void SetModelParameters(void); void ReadConfigVariables(void); short ProcessNetcdfVariable(int v, VAR *tmpVars); void VariableCleanUp(void); void ReplaceAlias(VAR * pstVar, int nFlag); void ReplaceDynAlias(char * pszDest, char * pszAlias, float fData, emu_type EmuType); BOOL GetFileName(VAR * pVar, char * pszDest); int SplitString(char * pszSrc, char * pszFirst, char cSep1, char * pszMid, char cSep2, char * pszLastName); void ParseFileList(char * pszLine, DYNFILE * pstDyn); int ExtractFileElements(char * pszSeg, DYNFILE * pstDyn); /* LOCAL FUNCTIONS: "utilities" used to support the above functions */ int getVarLine(FILE *fpin, char *pszLine); int GetLine(FILE * fpin, char * pszLine, char * pszMarker, BOOL bFromStart); int ReadConfigLine(char * pszLine, char * pszMarker); int GetTimeType(char *pszTimeType); dataorg_type GetDataOrgType(char * pszDataOrgType); emu_type GetEmuType(char * pszDataType); BOOL IsValidFileType(char *pszLineElement); /* ================================================================= */ /* Call the necessary functions to read input files, settings, mask, etc. */ void Initialize(int * argc, char * argv[], short option) { if (!ProcessDefaultCommandLineArgs(argc, argv)) ExitError("Could not process default command-line arguments %s \n", "uff"); /* print out date and time */ if (!bQuiet) { printf("\n ============ BEGINNING OF PROGRAM ============= \n"); PrintTime(); printf(" ================================================= \n"); } ReadSystemConfigFile(); ProcessCommandLineArgs(argc, argv); SetModelParameters(); if (option == NOMASK) bNoMask = TRUE; else if (option == DOMASK || bNoMask == FALSE) { bNoMask = FALSE; ReadMask(); } ReadConfigVariables(); } /* ================================================================= */ short GetVarNo(char *varname) { short v=0; while (v < nVars) if (istype(pstVars[v].name, varname)) return(v); else v++; /* WHAT HAPPENS IF THERE IS NO SUCH VARNAME ??! */ return(0); } /* ================================================================= */ /* Copy all the elements of a VAR variable to another VAR variable * * for value and string arrays, allocate memory and then copy */ void CopyVar(VAR *varto, VAR *varfrom) { int i, j; strcpy(varto->name, varfrom->name); strcpy(varto->filetype, varfrom->filetype); strcpy(varto->path, varfrom->path); strcpy(varto->param, varfrom->param); varto->bIsMetaData = varfrom->bIsMetaData; varto->nCols = varfrom->nCols; varto->nRows = varfrom->nRows; strcpy(varto->YDir, varfrom->YDir); varto->tTimeType = varfrom->tTimeType; varto->t1 = varfrom->t1; strcpy(varto->szUnit, varfrom->szUnit); varto->YearOrigin = varfrom->YearOrigin; varto->tEmuType = varfrom->tEmuType; varto->scale_factor = varfrom->scale_factor; varto->add_offset = varfrom->add_offset; varto->nFillValue = varfrom->nFillValue; varto->fFillValue = varfrom->fFillValue; varto->tDataOrg = varfrom->tDataOrg; varto->nBands = varfrom->nBands; varto->bByteSwap = varfrom->bByteSwap; varto->delimeter = varfrom->delimeter; varto->ncid = varfrom->ncid; varto->var_id = varfrom->var_id; varto->nDyn = varfrom->nDyn; if (varto->nDyn) { varto->pstDyn = (DYNFILE *) malloc(sizeof(DYNFILE) * varto->nDyn); for (j = 0; j<varto->nDyn; j++) { varto->pstDyn[j].nElements = varfrom->pstDyn[j].nElements; strcpy(varto->pstDyn[j].szFormat, varfrom->pstDyn[j].szFormat); strcpy(varto->pstDyn[j].szName, varfrom->pstDyn[j].szName); varto->pstDyn[j].ppszElement = (char * *) malloc(sizeof(char *) * varto->pstDyn[j].nElements); for (i=0; i<varto->pstDyn[j].nElements; i++) AssignString(&varto->pstDyn[j].ppszElement[i], varfrom->pstDyn[j].ppszElement[i]); } } else varto->pstDyn = NULL; varto->nParams = varfrom->nParams; if (varto->nParams) { varto->P = alloc1d_f(0,varto->nParams-1); for (i=0; i<varto->nParams; i++) varto->P[i] = varfrom->P[i]; } varto->nStrParams = varfrom->nStrParams; for (i=0; i < varto->nStrParams; i++) AssignString(&varto->szP[i], varfrom->szP[i]); } /* ================================================================= */ nc_type EMUtoNCType(emu_type EmuType) { switch(EmuType) { case EMU_BYTE: return(NC_BYTE); break; case EMU_SHORT: return(NC_SHORT); break; case EMU_INT: return(NC_INT); break; case EMU_FLOAT: return(NC_FLOAT); break; case EMU_DOUBLE: return(NC_DOUBLE); break; default: return(NC_FLOAT); break; } } /* ================================================================= */ emu_type NCtoEMUType(nc_type NCType) { switch(NCType) { case NC_BYTE: return(EMU_BYTE); break; case NC_SHORT: return(EMU_SHORT); break; case NC_INT: return(EMU_INT); break; case NC_FLOAT: return(EMU_FLOAT); break; case NC_DOUBLE: return(EMU_DOUBLE); break; default: return(EMU_FLOAT); break; } } /* ================================================================= */ size_t EmuTypeSize(emu_type EmuType) { if (EmuType == EMU_BYTE) return(sizeof(BYTE)); else if (EmuType == EMU_CHAR) return(sizeof(char)); else if (EmuType == EMU_SHORT) return(sizeof(short)); else if (EmuType == EMU_USHORT) return(sizeof(unsigned short)); else if (EmuType == EMU_INT) return(sizeof(int)); else if (EmuType == EMU_FLOAT) return(sizeof(float)); else if (EmuType == EMU_DOUBLE) return(sizeof(double)); else if (EmuType == EMU_WORD) return(sizeof(WORD)); else if (EmuType == EMU_LONG) return(sizeof(long)); else if (EmuType == EMU_ULONG) return(sizeof(unsigned long)); else if (EmuType == EMU_DWORD) return(sizeof(DWORD)); return(sizeof(BYTE)); } /* ================================================================= */ void CleanUp(void) { LocalCleanUp(); GlobalCleanUp(); /* print out date and time */ if (!bQuiet) { printf("\n================ END OF PROGRAM ================ \n"); PrintTime(); printf("================================================== \n"); } } /* ================================================================= */ void GlobalCleanUp(void) { int i; VariableCleanUp(); CheckDeallocation(); if (pszConfigFile != NULL) free(pszConfigFile); if (pszSystemConfigFile != NULL) free(pszSystemConfigFile); if (pszOutputFile != NULL) free(pszOutputFile); if (pszNCtitle != NULL) free(pszNCtitle); if (pszNChist != NULL) free(pszNChist); if (nParams > 0) free1d_f(P,0,nParams-1); if (nStrParams > 0) for (i=0; i < nStrParams; i++) free(szP[i]); } /* ================================================================= */ /* ======================= LOCAL FUNCTIONS ========================= */ /* ================================================================= */ /* Check to see if there are command-line switches to be processed, * and move real arguments to front of the line, and changes argc */ BOOL ProcessDefaultCommandLineArgs(int * pArgc, char * argv[]) { int i; BOOL bProcess = TRUE; int nArgv = 1; pszProgramName = argv[0]; pszConfigFile = malloc(strlen(pszProgramName)+10); sprintf(pszConfigFile, "%s.cfg", pszProgramName); AssignString(&pszOutputFile, pszProgramName); AssignString(&pszSystemConfigFile, SYSCFGFILE); if (pszNCtitle == NULL) AssignString(&pszNCtitle, "Title"); if (pszNChist == NULL) AssignString(&pszNChist, "File History"); for (i=1; i<*pArgc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help" ) == 0) { Usage(cpszUsage); bProcess = FALSE; exit(0); } else if (strcmp(argv[i], "-v") == 0) { printf("Running using verbose mode\n"); bVerbose = TRUE; } else if (strcmp(argv[i], "-q") == 0) bQuiet = TRUE; else if (strcmp(argv[i], "-i") == 0) bInteractive = TRUE; else if (strcmp(argv[i], "-d") == 0) { printf("Running using debug mode\n"); bDebug = TRUE; } else if (strcmp(argv[i], "-nm") == 0 || strcmp(argv[i], "-nomask") == 0) bNoMask = TRUE; else if (strcmp(argv[i], "-f") == 0) { bSelectedConfigFileName = TRUE; free(pszConfigFile); AssignString(&pszConfigFile, argv[++i]); } else if (strcmp(argv[i], "-scf") == 0) { free(pszSystemConfigFile); AssignString(&pszSystemConfigFile, argv[++i]); } else if (strcmp(argv[i], "-o") == 0) { free(pszOutputFile); AssignString(&pszOutputFile, argv[++i]); } else if (strcmp(argv[i], "-ob") == 0) bOutBinary = TRUE; else if (strcmp(argv[i], "-cdl") == 0) { free(pszCDLFile); AssignString(&pszCDLFile, argv[++i]); } else if (strcmp(argv[i], "-tit") == 0) { free(pszNCtitle); AssignString(&pszNCtitle, argv[++i]); } else if (strcmp(argv[i], "-hist") == 0) { free(pszNChist); AssignString(&pszNChist, argv[++i]); } else argv[nArgv++] = argv[i]; } *pArgc = nArgv; return(bProcess); } /* ================================================================= */ /* Display the default usage message and the usage message for the * current application */ void Usage(const char * cpszUsage) { printf(cpszUsage); printf("\nStandard command line switches for emu are:\n"); printf("\t-f Filename - sets configuration file (default: %s.cfg) \n", pszProgramName); printf("\t-scf Filename - sets system configuration file (default .\\system.cfg) \n"); printf("\t-o Output Filename - sets output file name (default: %s), w/o extension \n", pszProgramName); printf("\t-ob Output Binary - sets flag usually used to output binary file types\n"); printf("\t-nm or -nomask - Don't use a mask.\n"); printf("\t-h or -help - usage screen\n"); printf("\t-d - sets debug mode\n"); printf("\t-q - sets quiet mode (no output to stdout)\n"); printf("\t-cdl CDL Filename - sets CDL filename to create netcdf output file\n"); printf("\t-hist - Enter 'history' global attribute for netcdf files\n"); printf("\t-tit - Enter 'title' global attribute for netcdf files\n"); printf("These switches are reserved but generally unsupported\n"); printf("\t-v - sets verbose mode (lots of output to stdout)\n"); printf("\t-i - sets interactive mode\n"); } /* ================================================================= */ /* read in local system configuration information */ void ReadSystemConfigFile(void) { FILE * fpc; char szLine[LINELEN]; char s[LINELEN]; if ((fpc = fopen(pszSystemConfigFile, "rt")) == NULL) Warning("Couldn't open file %s for reading in ReadSystemConfigFile\n", pszSystemConfigFile); else { if (GetLine(fpc, szLine, "# CONFIGFILE", TRUE)) { sscanf(szLine, "%s", s); if (!istype(s, "programname") && !bSelectedConfigFileName) { free(pszConfigFile); AssignString(&pszConfigFile, s); } } else if (bDebug) Warning("In %s, need entry for variable CONFIGFILE", pszSystemConfigFile); if (GetLine(fpc, szLine, "# BYTEORDER", TRUE)) { if (istype(szLine, "m")) tByteOrder = MOTOROLA; else if (istype(szLine, "d")) tByteOrder = DEC; else if (istype(szLine, "i")) tByteOrder = INTEL; else tByteOrder = INTEL; } else if (bDebug) Warning("Couldn't find \"# BYTEORDER\" in file %s in ReadSystemConfigFile\n", pszSystemConfigFile); if (GetLine(fpc, szLine, "# YEARORIGIN", TRUE)) sscanf(szLine, "%d", &YEARORIGIN); else if (bDebug) Warning("Couldn't find \"# YEARORIGIN\" in file %s in ReadSystemConfigFile\n", pszSystemConfigFile); if (GetLine(fpc, szLine, "# OUTPUTPATH", TRUE)) { sscanf(szLine, "%s", s); AssignString(&pszOutputFilePath, s); } else if (bDebug) Warning("In %s, need entry for variable OUTPUTPATH", pszSystemConfigFile); #ifndef NONETCDF if (GetLine(fpc, szLine, "# NCGEN", TRUE)) { sscanf(szLine, "%s", s); AssignString(&pszNCGenFile, s); } else if (bDebug) Warning("In %s, need entry for variable NCGEN", pszSystemConfigFile); if (GetLine(fpc, szLine, "# CDLFILE", TRUE)) { sscanf(szLine, "%s", s); AssignString(&pszCDLFile, s); } else if (bDebug) Warning("In %s, need entry for variable CDLFILE", pszSystemConfigFile); DoesFileExist(pszCDLFile); #endif fclose(fpc); } } /* ================================================================= */ /* read in the values of nRows and nCols; * read the geographic location (corners of the image, in lat/lon degrees; * read the initial and final year/month into TIME struct */ void SetModelParameters(void) { FILE * fpc; char szLine[LINELEN], *s, c1, c2, *VarArgs[50], *ss[10]; float ptmp[50]; int mo, i, nLineArgs, ParamsIndx; if (!bQuiet) printf("\n---- Reading Global Parameters in SetModelParameters() \n"); if ((fpc = fopen(pszConfigFile, "rt")) == NULL) ExitError("Couldn't open file %s for reading in SetmodelParameters\n", pszConfigFile); /* ================ read in spatial information ================ */ if (GetLine(fpc, szLine, "# SIZE", TRUE)) { nLineArgs = GetLineElements(VarArgs, szLine, ' '); nCols = atoi(VarArgs[0]); nRows = atoi(VarArgs[1]); if (nLineArgs == 3) { nYBlocks = atoi(VarArgs[2]); nBlockRows = (int) (nRows/nYBlocks); } /* clear the allocated memory for VarArgs */ for (i=0; i<nLineArgs; i++) free(VarArgs[i]); } else if (bDebug) Warning("Couldn't find \"# SIZE\" in file %s in SetModelParameters\n", pszConfigFile); if (GetLine(fpc, szLine, "# GEOGRAPHIC", TRUE)) { sscanf(szLine, "%f %f %f %f", &fLatTop, &fLatBtm, &fLonRight, &fLonLeft); fVScale = (fLatTop - fLatBtm) / (float) nRows; fHScale = (fLonRight - fLonLeft) / (float) nCols; } else if (bDebug) Warning("Couldn't find \"# GEOGRAPHIC\" in file %s in SetModelParameters\n", pszConfigFile); /* ============== read time information into global TIME struct ============= */ if (GetLine(fpc, szLine, "# TIME", TRUE)) { sscanf(szLine, "%d %d %d %d", &nFirstYear, &nFirstMonth, &nLastYear, &nLastMonth); /* read number of years for looping and I/O fpc */ nTotalYears = nLastYear - nFirstYear + 1; nTimeSteps = (12-nFirstMonth+1) + (nTotalYears-2)*12 + nLastMonth; if (!bQuiet) printf("\nFrom %d/%d to %d/%d; %d months, in %d different years\n", nFirstMonth, nFirstYear, nLastMonth, nLastYear, nTimeSteps, nTotalYears); for (mo = 0; mo < YEAR2MONTH; mo++) if (nLastMonth < nFirstMonth) { if ((mo+1) < nFirstMonth && (mo+1) > nLastMonth) nTotalMonths[mo] = nTotalYears - 2; else nTotalMonths[mo] = nTotalYears - 1; } else { if ((mo+1) <= nLastMonth && (mo+1) >= nFirstMonth) nTotalMonths[mo] = nTotalYears; else nTotalMonths[mo] = nTotalYears - 1; } } else if (bDebug) Warning("Couldn't find \"# TIME\" in file %s in SetModelParameters\n", pszConfigFile); /* ===== read-in customized, global parameters into global arrays P and szP ==== */ nParams = 0; nStrParams = 0; if (GetLine(fpc, szLine, "# PARAM", TRUE)) { nLineArgs = GetLineElements(VarArgs, szLine, ' '); for (ParamsIndx=0; ParamsIndx < nLineArgs; ParamsIndx++) { /* if 1st character is a digit, or 1st character is a '.', '+', or '-' and * * 2nd character is a digit, parameter is assumed to be a number * * (-.5 won't be recognized!) */ c1 = VarArgs[ParamsIndx][0]; c2 = VarArgs[ParamsIndx][1]; if (isdigit(c1) || ((c1 == '+' || c1 == '-' || c1 == '.') && isdigit(c2))) ptmp[nParams++] = (float) atof(VarArgs[ParamsIndx]); else AssignString(&ss[nStrParams++], VarArgs[ParamsIndx]); if(bDebug) printf("<%s>", VarArgs[ParamsIndx]); } if(bDebug) printf("\n FloatParams=%d, StrParams=%d ", nParams,nStrParams); /* process number parameters */ if (nParams > 0) { P = alloc1d_f(0,nParams-1); for (i = 0; i < nParams; i++) P[i] = ptmp[i]; } /* process string parameters and free allocated memory for ss */ for (i = 0; i < nStrParams; i++) { AssignString(&szP[i], ss[i]); free(ss[i]); } /* clear the allocated memory for VarArgs */ for (i=0; i<nLineArgs; i++) free(VarArgs[i]); } else if (bDebug) Warning("Couldn't find \"# PARAM\" in file %s in SetModelParameters\n", pszConfigFile); /* =========== read in the NAMEDVARIABLES option state ================ */ bNamedVariables = FALSE; if (GetLine(fpc, szLine, "# NAMEDVARIABLES", TRUE)) { s = (char *) malloc(strlen(szLine)+1); sscanf(szLine, "%s", s); if (istype(s, "yes")) bNamedVariables = TRUE; free(s); } else if (bDebug) Warning("Couldn't find \"# NAMEDVARIABLES\" in file %s in SetModelParameters\n", pszConfigFile); fclose(fpc); } /* ================================================================= */ void ReadConfigVariables(void) { FILE * fpc; int debug=0; int v=0, i, nLineArgs; int os; /* index offset */ int nArgs; /* number of default, fixed arguments for a particular filetype */ int nVarParams, FloatParams, StrParams; char c1, c2, *VarArgs[50], *ss[10]; char szFileType[20], szLine[LINELEN]; float ptmp[50]; short ncvars; VAR * tmpVars; tmpVars = alloc1d_VAR(0,100); if (!bQuiet) printf("\n---- Reading Paths and variable info. in ReadConfigVariables() \n"); if ((fpc = fopen(pszConfigFile, "rt")) == NULL) ExitError("Couldn't open configuration file %s for reading\n", pszConfigFile); if (GetLine(fpc, szLine, "# VAR", TRUE) == FALSE) ExitError("Couldn't find # VAR line in configuration file, %s\n", pszConfigFile); /* ===== READ AND PARSE EACH VARIABLE LINE IN THE CONFIG FILE ====== */ while (getVarLine(fpc, szLine) != 0) { /* read the var line */ nLineArgs = GetLineElements(VarArgs, szLine, ' '); /* process the elements variable name (optional) and filetype */ if (bNamedVariables || !IsValidFileType(VarArgs[0])) { os = 1; strcpy(tmpVars[v].name, VarArgs[0]); strcpy(tmpVars[v].filetype, VarArgs[1]); strcpy(szFileType, VarArgs[1]); } else { os = 0; strcpy(tmpVars[v].name, "none"); strcpy(tmpVars[v].filetype, VarArgs[0]); strcpy(szFileType, VarArgs[0]); } /* ====== process line elements according to filetype ====== */ /* ============ BINARY FILETYPE ============= */ if (istype(szFileType, "bin") || istype(szFileType, "motorola") || istype(szFileType, "intel")) { if (bDebug) printf("\n v=%d: binary file type\n", v); /* Args: filetype,datatype,filepath,filename(param),dataorg,nbands */ nArgs = 6 + os; strcpy(tmpVars[v].filetype, "bin"); if ((istype(szFileType, "motorola") && tByteOrder == INTEL) || (istype(szFileType, "intel") && tByteOrder == MOTOROLA) ) tmpVars[v].bByteSwap = TRUE; else tmpVars[v].bByteSwap = FALSE; tmpVars[v].tEmuType = GetEmuType(VarArgs[1+os]); strcpy(tmpVars[v].path, VarArgs[2+os]); strcpy(tmpVars[v].param, VarArgs[3+os]); if (VarArgs[4+os][0] == '-') tmpVars[v].tDataOrg = GetDataOrgType("fsq"); else tmpVars[v].tDataOrg = GetDataOrgType(VarArgs[4+os]); if (tmpVars[v].tDataOrg == BADTYPE) { tmpVars[v].tDataOrg = GetDataOrgType("fsq"); tmpVars[v].tTimeType = GetTimeType(VarArgs[4+os]); } else tmpVars[v].tTimeType = NOTIME; if (nLineArgs < nArgs+os) /* nBands ARGUMENT MAY NOT BE NEEDED */ tmpVars[v].nBands = 1; else if (VarArgs[5+os][0] == '-') tmpVars[v].nBands = 1; else tmpVars[v].nBands = atoi(VarArgs[5+os]); } /* ================= ASCII FILETYPE ================ */ else if (istype(szFileType, "ascii")) { if (bDebug) printf("\n v=%d: ascii file type\n", v); /* Args: filetype,datatype,filepath,filename(param),timetype,delimeter */ nArgs = 6 + os; tmpVars[v].tEmuType = GetEmuType(VarArgs[1+os]); strcpy(tmpVars[v].path, VarArgs[2+os]); strcpy(tmpVars[v].param, VarArgs[3+os]); if (VarArgs[4+os][0] != '-') tmpVars[v].tTimeType = GetTimeType(VarArgs[4+os]); else tmpVars[v].tTimeType = NOTIME; if (VarArgs[5+os][0] == 't') /* tab delimeter */ tmpVars[v].delimeter = '\t'; else /* all other single-character delimeters */ tmpVars[v].delimeter = VarArgs[5+os][0]; } /* ================ NETCDF FILETYPE ================ */ else if (istype(szFileType, "nc")) { if (bDebug) printf("\n v=%d: netcdf file type\n", v); /* Args: filetype,full filepath,NC variable name(param),timetype */ nArgs = 4 + os; strcpy(tmpVars[v].path, VarArgs[1+os]); strcpy(tmpVars[v].param, VarArgs[2+os]); tmpVars[v].tTimeType = GetTimeType(VarArgs[3+os]); } /* ====================================================== */ else ExitError("File type %s not handled", tmpVars[v].filetype); /* ====================================================== */ /* ======== REPLACE ALIASES IN FILEPATH AND FILENAME ======== */ ReplaceAlias(&tmpVars[v], PATH); ReplaceAlias(&tmpVars[v], PARAM); /* ====== INITIALIZE OTHER ELEMENTS OF THE PSTVAR STRUCTURE ====== */ tmpVars[v].t1 = 1.0F; tmpVars[v].scale_factor = 1.0F; tmpVars[v].add_offset = 0.0F; /* ========= HANDLE OPTIONAL nCols & nRows ============= */ if (nLineArgs < nArgs + 2) { tmpVars[v].nCols = nCols; tmpVars[v].nRows = nRows; } else { tmpVars[v].nCols = (VarArgs[nArgs][0] == '-') ? nCols : atoi(VarArgs[nArgs]); tmpVars[v].nRows = (VarArgs[nArgs+1][0] == '-') ? nRows : atoi(VarArgs[nArgs+1]); } if (bDebug) printf("\n nLineArgs=%d, tmpVars[%d].name=%s, .filetype=%s, .path=%s, .param=%s, .nCols=%d, .nRows=%d \n", nLineArgs,v,tmpVars[v].name,tmpVars[v].filetype,tmpVars[v].path,tmpVars[v].param,tmpVars[v].nCols,tmpVars[v].nRows); /* ======== HANDLE OPTIONAL VARIABLE PARAMETERS ========== */ FloatParams = 0; StrParams = 0; if (nLineArgs <= nArgs + 2) /* this isn't really needed now that these field are initialized in alloc1d_VAR */ { tmpVars[v].nParams = 0; tmpVars[v].nStrParams = 0; } else { for (nVarParams=nArgs+2; nVarParams < nLineArgs; nVarParams++) { /* if 1st character is a digit, or 1st character is a '.', '+', or '-' and * * 2nd character is a digit, parameter is assumed to be a number * * (-.5 won't be recognized!) */ c1 = VarArgs[nVarParams][0]; c2 = VarArgs[nVarParams][1]; if (isdigit(c1) || ((c1 == '+' || c1 == '-' || c1 == '.') && isdigit(c2))) ptmp[FloatParams++] = (float) atof(VarArgs[nVarParams]); else AssignString(&ss[StrParams++], VarArgs[nVarParams]); if(bDebug) printf("<%s>", VarArgs[nVarParams]); } if(bDebug) printf("\n FloatParams=%d, StrParams=%d ", FloatParams,StrParams); /* process number parameters */ tmpVars[v].nParams = FloatParams; if (FloatParams > 0) { tmpVars[v].P = alloc1d_f(0,FloatParams-1); for (i = 0; i < FloatParams; i++) tmpVars[v].P[i] = ptmp[i]; } /* process string parameters and free allocated memory for ss */ tmpVars[v].nStrParams = StrParams; for (i = 0; i < StrParams; i++) { AssignString(&tmpVars[v].szP[i], ss[i]); free(ss[i]); } } /* clear the allocated memory for VarArgs */ for (i=0; i<nLineArgs; i++) free(VarArgs[i]); /* ============== PROCESS METADATA OPTIONAL SPECIFIER ================ */ if (tmpVars[v].nStrParams >= 1) tmpVars[v].bIsMetaData = istype(tmpVars[v].szP[0], "metadata") ? TRUE : FALSE; else tmpVars[v].bIsMetaData = FALSE; /* ============== PROCESS NETCDF VARIABLES ================ */ if (istype(tmpVars[v].filetype, "nc")) { /* if the variable is only a metadata specifier, do not try to * * process the netcdf file */ if (tmpVars[v].bIsMetaData) /* read the data type metadata */ tmpVars[v].tEmuType = GetEmuType(tmpVars[v].szP[2]); else /* process the netcdf file and variables */ { ncvars = ProcessNetcdfVariable(v, tmpVars); v += ncvars - 1; } } if (bDebug) printf("EMU_TYPE=%d, tDataOrg=%d, tTimeType=%d, nBands=%d, bByteSwap=%d\n", tmpVars[v].tEmuType,tmpVars[v].tDataOrg,tmpVars[v].tTimeType,tmpVars[v].nBands,tmpVars[v].bByteSwap); v++; } fclose(fpc); /* ==== COPY FROM THE TEMPORARY VAR STRUCTURE, TO THE FINAL VAR STRUCTURE ==== */ /* allocate memory space to pstVars containing nVars variables */ nVars = v; pstVars = alloc1d_VAR(0,nVars-1); for (v=0; v < nVars; v++) { CopyVar(&pstVars[v], &tmpVars[v]); /* print out parameter values, for debugging */ if(bDebug) { printf("\n"); for (i = 0; i < pstVars[v].nParams; i++) printf(" P[%d]=%f ", i,pstVars[v].P[i]); for (i = 0; i < pstVars[v].nStrParams; i++) if(bDebug) printf(" szP[%d]=%s ", i,pstVars[v].szP[i]); } } free1d_VAR(tmpVars,0,100); if (!bQuiet) printf("\n %d Variables\n---- Copied final VAR structure, Done with ReadConfigVariables() \n",nVars); } /* ================================================================= */ short ProcessNetcdfVariable(int v, VAR *tmpVars) { char szName[NAMELEN], szUnit[NAMELEN]; int ncID, varID, tmpncdims, tmpncvars, ncv; int tID, recID; char szTimeOrigin[100], s[100], *pCh, szYearOrigin[5]; size_t t_index=0; nc_type ncType; if (bDebug) printf("\n ** Beginning ProcessNetcdfVariable()\n"); /* open netCDF file, get its ID, variable ID */ errnc = nc_open(tmpVars[v].path, NC_NOWRITE, &ncID); /* USE NC_WRITE OR NC_SHARE INSTEAD ? */ tmpVars[v].ncid = ncID; /* ========== Time Axis information: units, 1st time step, etc. ============ */ /* BUT THIS WILL WORK ONLY IF THE TIME DIMENSION IS DECLARED AS NC_UNLIMITED !!!! */ errnc = nc_inq_unlimdim(ncID, &recID); errnc = nc_inq_dimname(ncID, recID, szName); errnc = nc_inq_varid(ncID, szName, &tID); /* extract the YearOrigin */ ClearString(szTimeOrigin, 100); errnc = nc_get_att_text(ncID, tID, "time_origin", szTimeOrigin); if (bDebug) printf("\n szTimeOrigin = |%s|\n", szTimeOrigin); strcpy(s, szTimeOrigin); /* this scheme will work only with time origin years in the 1900's * * (ie, 19**); and assumes DEC-15 of the previous year */ while ((pCh = strchr(s, '1')) != NULL) if (*(pCh+1) == '9') break; else strcpy(s, ++pCh); if (pCh != NULL) /* found the substring beginning with '19' */ { *(pCh+4) = '\0'; strcpy(szYearOrigin, pCh); tmpVars[v].YearOrigin = (short) strtol(szYearOrigin, NULL, 0); } else Warning("Could not find YearOrigin in nc file %s\n", tmpVars[v].path); /* what happens if .tTimeType != MONTHLY (eg, ANNUAL) !? */ if (tmpVars[v].tTimeType == MONTHLY) errnc = nc_get_var1_double(ncID, tID, &t_index, &tmpVars[v].t1); if (bDebug) printf(" READ tmpVars[v].t1: .t1=%f \n", tmpVars[v].t1); /* now read time unit, and then make conversion to MONTH unit */ errnc = nc_get_att_text(ncID, tID, "units", szUnit); if (istype(szUnit, "mon") || istype(szUnit, "MON")) strcpy(tmpVars[v].szUnit, "month"); else if (istype(szUnit, "day") || istype(szUnit, "DAY")) { strcpy(tmpVars[v].szUnit, "day"); tmpVars[v].t1 = floor(tmpVars[v].t1/MONTH2DAY + 0.5); } if (istype(szUnit, "hou") || istype(szUnit, "HOU")) { strcpy(tmpVars[v].szUnit, "hour"); tmpVars[v].t1 = floor(tmpVars[v].t1/MONTH2HOUR + 0.5); } if (bDebug) printf(" NC type v=%d: ncid=%d, szUnit=%s, t1=%f, YearOrigin=%d\n", v,ncID,tmpVars[v].szUnit,tmpVars[v].t1,tmpVars[v].YearOrigin); /* ===== Variable-specific information: ID, name, scale, offset, FillValue ==== */ /* ========= Also, copy the VAR element for this new variable ================= */ /* if param code is "all", query the NC file and extract number of data variables */ if (istype(tmpVars[v].param, "all")) { errnc = nc_inq_ndims(ncID, &tmpncdims); errnc = nc_inq_nvars(ncID, &tmpncvars); tmpncvars = tmpncvars - tmpncdims; } else tmpncvars = 1; for (ncv = v; ncv < v+tmpncvars; ncv++) { if (tmpncvars > 1) { CopyVar(&tmpVars[ncv], &tmpVars[v]); tmpVars[ncv].var_id = tmpncdims + ncv; errnc = nc_inq_varname(ncID, tmpVars[ncv].var_id, tmpVars[ncv].param); } else errnc = nc_inq_varid(ncID, tmpVars[ncv].param, &tmpVars[ncv].var_id); varID = tmpVars[ncv].var_id; if (bDebug) printf(" Variable name: %s \n", tmpVars[ncv].param); errnc = nc_inq_vartype(ncID, varID, &ncType); tmpVars[ncv].tEmuType = NCtoEMUType(ncType); /* scale_factor and add_offset attributes */ /* if attribute doesn't exist the NC 3.4 lib returns the error code NC_ENOTATT */ errnc = nc_get_att_float(ncID, varID, "scale_factor", &tmpVars[ncv].scale_factor); errnc = nc_get_att_float(ncID, varID, "add_offset", &tmpVars[ncv].add_offset); /* FillValue attributes */ errnc = nc_inq_atttype(ncID, tmpVars[ncv].var_id, "_FillValue", &ncType); if (ncType == NC_SHORT) errnc = nc_get_att_short(ncID, varID, "_FillValue", &tmpVars[ncv].nFillValue); else if (ncType == NC_FLOAT) errnc = nc_get_att_float(ncID, varID, "_FillValue", &tmpVars[ncv].fFillValue); if (bDebug) printf(" NC variable ncv=%d: .param=%s, .var_id=%d, scale_factor=%f \n", ncv, tmpVars[ncv].param,tmpVars[ncv].var_id,tmpVars[ncv].scale_factor); } /* END OF ncv FOR-LOOP */ if (bDebug) printf(" tmpncvars=%d \n", tmpncvars); return(tmpncvars); } /* ================================================================= */ void VariableCleanUp(void) { int v, flagncid = -999, axis; /* close netcdf files */ for (v = 0; v < nVars; v++) if (!pstVars[v].bIsMetaData) if (istype(pstVars[v].filetype, "nc") && (pstVars[v].ncid != flagncid)) { errnc = nc_close(pstVars[v].ncid); flagncid = pstVars[v].ncid; } /* free VAR-related variables */ if (nVars != 0) free1d_VAR(pstVars,0,nVars-1); if (pstInput != NULL) free1d_VAR(pstInput,0,0); if (pstOutput != NULL) free1d_VAR(pstOutput,0,0); /* free variables related to the mask */ if (!bNoMask) { free1d_l(pMask,0,nRows*nCols-1); free1d_MASK(Masks,0,MskSitesN-1); free1d_i(FlMskSitesIDs,0,FlMskSitesN-1); free1d_i(FlMskSitesCellcount,0,FlMskSitesN-1); free1d_d(FlMskSitesArea,0,FlMskSitesN-1); free1d_i(MskSitesIDs,0,MskSitesN-1); } /* free coordinate variable arrays (used for writing files) */ for (axis=0; axis < 4; axis++) if (stAxes[axis].active) free1d_d(stAxes[axis].values, 0,stAxes[axis].length-1); } /* ================================================================= */ /* ================================================================= */ void ReplaceAlias(VAR * pstVar, int nFlag) { char szFirst[LINELEN]; char szMid[LINELEN]; char szLast[LINELEN]; char szLine[LINELEN]; char szSrc[LINELEN]; char szDest[LINELEN]; char szName[LINELEN]; char szArg[LINELEN]; char s[LINELEN]; int l_nDyn; DYNFILE * pstDyn; if (nFlag == PARAM) strcpy(szSrc, pstVar->param); else if (nFlag == PATH) strcpy(szSrc, pstVar->path); strcpy(szDest, ""); while (SplitString(szSrc, szFirst, '(', szMid, ')', szLast)) { sprintf(s, "# %s", szMid); if (ReadConfigLine(szLine, s)) { sscanf(szLine, "%s", szMid); strcat(szDest, szFirst); strcat(szDest, szMid); strcpy(szSrc, szLast); } else if (strchr(szMid, ':') != NULL) /* look for dynamic filename separator */ { strcat(szDest, szFirst); strcat(szDest, "("); strcat(szDest, szMid); strcat(szDest, ")"); strcpy(szSrc, szLast); SplitString(szMid, szName, ':', szArg, '\0', NULL); if (pstVar->pstDyn == NULL) { pstVar->nDyn = strcnt(szLast, ':') + 1; /* need to include this one */ pstVar->pstDyn = (DYNFILE *) malloc(sizeof(DYNFILE) * pstVar->nDyn); l_nDyn = 0; } else l_nDyn++; pstDyn = &(pstVar->pstDyn[l_nDyn]); strcpy(pstDyn->szName, szName); strcpy(pstDyn->szFormat, szArg); sprintf(s, "# %s", szName); if (ReadConfigLine(szLine, s)) ParseFileList(szLine, pstDyn); else pstDyn->nElements = 0; } else Warning("Alias %s not found in ReplaceAlias in config file\n", szMid); } strcat(szDest, szSrc); if (nFlag == PARAM) strcpy(pstVar->param, szDest); else if (nFlag == PATH) strcpy(pstVar->path, szDest); } /* ================================================================= */ /* EmuType can be *only* EMU_INT or EMU_FLOAT */ void ReplaceDynAlias(char * pszDest, char * pszAlias, float fData, emu_type EmuType) { char szFirst[LINELEN]; char szMid[LINELEN]; char szLast[LINELEN]; char szSrc[LINELEN]; char szName[LINELEN]; char szArg[LINELEN]; char s[LINELEN]; BOOL bFoundAlias = FALSE; strcpy(szSrc, pszDest); strcpy(pszDest, ""); while (SplitString(szSrc, szFirst, '(', szMid, ')', szLast)) { bFoundAlias = TRUE; SplitString(szMid, szName, ':', szArg, '\0', NULL); if (!strcmp(szName, pszAlias)) { strcat(pszDest, szFirst); if (EmuType == EMU_INT) sprintf(s, szArg, roundoff(fData)); else if (EmuType == EMU_FLOAT) sprintf(s, szArg, fData); strcat(pszDest, s); break; } else { strcat(pszDest, szFirst); strcat(pszDest, "("); strcat(pszDest, szMid); strcat(pszDest, ")"); } strcpy(szSrc, szLast); /* place everything after close paren into szLast */ } if (bFoundAlias) strcat(pszDest, szLast); else strcpy(pszDest, szSrc); } /* ================================================================= */ BOOL GetFileName(VAR * pVar, char * pszDest) { strcpy(pszDest, pVar->path); strcat(pszDest, pVar->param); if (strchr(pszDest, '(') == NULL) return(FALSE); else return(TRUE); } /* ================================================================= */ int SplitString(char * pszSrc, char * pszFirst, char cSep1, char * pszMid, char cSep2, char * pszLast) { char * pszSep; strcpy(pszFirst, pszSrc); if ((pszSep = strchr(pszFirst, cSep1)) != NULL) { *pszSep++ = '\0'; strcpy(pszMid, pszSep); if (cSep2 != '\0') { if ((pszSep = strchr(pszMid, cSep2)) != NULL) { *pszSep++ = '\0'; strcpy(pszLast, pszSep); } else Warning("%s not closed in SplitString\n", &cSep2); } return(TRUE); } else return(FALSE); } /* ================================================================= */ void ParseFileList(char * pszLine, DYNFILE * pstDyn) { char * pCh; char s[NAMELEN]; int n = 0; /* count elements first */ strcpy(s, pszLine); /* copy string into s from that point */ while ((pCh = strchr(s, ',')) != NULL) { *pCh = '\0'; pCh++; n += ExtractFileElements(s, NULL); strcpy(s, pCh); /* copy string into s from that point */ } n += ExtractFileElements(s, NULL); pstDyn->ppszElement = (char * *) malloc(sizeof(char *) * n); pstDyn->nElements = n; strcpy(s, pszLine); /* copy string into s from that point */ while ((pCh = strchr(s, ',')) != NULL) { *pCh = '\0'; pCh++; ExtractFileElements(s, pstDyn); strcpy(s, pCh); /* copy string into s from that point */ } ExtractFileElements(s, pstDyn); } /* ================================================================= */ int ExtractFileElements(char * pszSeg, DYNFILE * pstDyn) { char s[NAMELEN]; char s1[NAMELEN]; char * pDash; int n = 0; int nFirstIndex; int nLastIndex; strcpy(s, pszSeg); /* copy string into s from that point */ if ((pDash = strchr(s, '-')) == NULL) { /* no - */ if (pstDyn != NULL) { pstDyn->ppszElement[pstDyn->nElements] = (char *) malloc(strlen(s)+1); strcpy(pstDyn->ppszElement[pstDyn->nElements++], s); } n=1; } else { *pDash = '\0'; pDash++; sscanf(s, "%d", &nFirstIndex); strcpy(s1, pDash); sscanf(s1, "%d", &nLastIndex); if (pstDyn != NULL) { for (n = nFirstIndex; n<=nLastIndex; n++) { sprintf(s1, "%s", pstDyn->szFormat); sprintf(s, s1, n); pstDyn->ppszElement[pstDyn->nElements] = (char *) malloc(strlen(s)+1); strcpy(pstDyn->ppszElement[pstDyn->nElements++], s); } } n = nLastIndex - nFirstIndex + 1; } return(n); } /* ================================================================= */ /* ================================================================= */ int getVarLine(FILE *fpin, char *pszLine) { while (strncmp(fgets(pszLine, LINELEN, fpin), "##", 2) == 0 || strlen(pszLine) == 1) ; if (pszLine == NULL || strncmp(pszLine, "# END", 5) == 0 || strncmp(pszLine, "# VAREND", 8) == 0 ) return(0); else return(strlen(pszLine)); } /* ================================================================= */ /* find line with pszMarker, read next line, return length of line */ int GetLine(FILE * fpin, char * pszLine, char * pszMarker, BOOL bFromStart) { int nMatch; /* always start from the beginning so order is not important */ if (bFromStart) rewind(fpin); do { nMatch = strncmp(fgets(pszLine, LINELEN, fpin), pszMarker, strlen(pszMarker)); if (strncmp(pszLine, "# END", 5) == 0) return(0); } while (nMatch != 0 && pszLine != NULL); if (fgets(pszLine, LINELEN, fpin) == NULL) return(0); else return(strlen(pszLine)); } /* ================================================================= */ /* open configuration file, then use GetLine() to find line with pszMarker * * and return parameter string, return length of line */ int ReadConfigLine(char * pszLine, char * pszMarker) { FILE * fpc; if ((fpc = fopen(pszConfigFile, "rt")) == NULL) ExitError("Couldn't open file %s for reading\n", pszConfigFile); if (GetLine(fpc, pszLine, pszMarker, TRUE)) { fclose(fpc); return(strlen(pszLine)); } else if (bDebug) Warning("Couldn't find \"%s\" in config file in ReadConfigLine\n", pszMarker); fclose(fpc); return(0); } /* ================================================================= */ int GetTimeType(char *pszTimeType) { if (istype(pszTimeType, "monthly")) return(MONTHLY); else if (istype(pszTimeType, "monmean")) return(MONMEAN); else if (istype(pszTimeType, "annual")) return(ANNUAL); else if (istype(pszTimeType, "xy")) return(NOTIME); else return(NOTIME); } /* ================================================================= */ dataorg_type GetDataOrgType(char * pszDataOrgType) { if (istype(pszDataOrgType, "fsq")) return(FSQ); else if (istype(pszDataOrgType, "bsq")) return(BSQ); else if (istype(pszDataOrgType, "bil")) return(BIL); else if (istype(pszDataOrgType, "bip")) return(BIP); else return(BADTYPE); } /* ================================================================= */ emu_type GetEmuType(char * pszDataType) { if (istype(pszDataType, "b")) return(EMU_BYTE); else if (istype(pszDataType, "c")) return(EMU_CHAR); else if (istype(pszDataType, "s")) return(EMU_SHORT); else if (istype(pszDataType, "l")) return(EMU_LONG); else if (istype(pszDataType, "f")) return(EMU_FLOAT); else if (istype(pszDataType, "d")) return(EMU_DOUBLE); else if (istype(pszDataType, "us")) return(EMU_USHORT); else if (istype(pszDataType, "w")) return(EMU_USHORT); else if (istype(pszDataType, "ul")) return(EMU_ULONG); else if (istype(pszDataType, "dw")) return(EMU_ULONG); return(EMU_BYTE); } /* ================================================================= */ BOOL IsValidFileType(char *pszLineElement) { if (istype(pszLineElement, "intel") || istype(pszLineElement, "motorola") || istype(pszLineElement, "bin") || istype(pszLineElement, "ascii") || istype(pszLineElement, "nc")) return(TRUE); else return(FALSE); } /* ================================================================= */ /* ================================================================= */ /* ==== OBSOLESCENT FUNCTIONS, KEPT FOR BACKWARDS COMPATIBILITY ==== */ void SimpleInitialize(int * argc, char * argv[]) { Initialize(argc, argv, NOMASK); } /* ================================================================= */ void ReadVariable(VAR * pstVar, char * pszVarKeyword) { CopyVar(pstVar, &pstVars[GetVarNo(pszVarKeyword)]); } /* ================================================================= */ void ReadInput(void) { pstInput = alloc1d_VAR(0,0); ReadVariable(pstInput, "# INPUT "); } /* ================================================================= */ void ReadOutput(void) { pstOutput = alloc1d_VAR(0,0); ReadVariable(pstOutput, "# OUTPUT "); }