/* 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 ");
}