#define PROGRAM_VERSION "1.0" #define PROGRAM_DATE "09/24/2013" /***************************************************************************** * psurge2nwps.c * * DESCRIPTION * This program converts from a P-Surge file that has been stored as a * set of .flt files (by degrib) to the output format that the National Wave * Prediction System can use. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES * * Flow of the program is as follows: * a) Get the WFO grid definitions * b) Read the "degrib .txt" file to get the P-Surge map projection * c) Get various meta data from the "degrib .flt" filename * d) Open the .flt file and loop over the WFO grids * For each WFO grid, loop over the lat/lons * For each lat/lon, * map to grid coordinate * fseek data from .flt file * use either bi-linear or nearest neighbor to get value * output result * * Assumes that ("degrib -V" = "2.02") was used as follows: * ${DEGRIB} -C -Flt -msg all -Unit none * -nameStyle "%e_%lv_%p_e${EXCEED}.txt" * * 1) Assumes the .flt file was created in "big endian". * 2) Assumes the .flt file was created in meters. * 3) Assumes the binary .dat file should be in "little endian". * 4) Assumes the .flt file missing value is '9999'. Could determine by * reading the .txt file. * 5) Assumes the wfo grids missing value is '-9999'. Could be a command * line option. * * Output file name is defined as follows: * psurge_AsOf_WFO_X_Y_S_T_E.dat * AsOf (YYYYMMDDHH) = {2012102906} * WFO = {phi} * X = (NX)-(lon1 * -100) {779-7625} * Y = (NY)-(lat1 * 100) {779-3760} * NX = (-72.7500 - -76.2500) / .0045 + 1 = {778.777 = 779} * NY = (41.1000 - 37.6000) / .0045 + 1 = {778.777 = 779} * S (spacing * 10,000) = {45} * T = {f006} * E (exceedance) = {e10} * e.g: psurge_2012102906_phi_779-7625_779-3760_45_f006_e10.dat ****************************************************************************/ #include #include #include #include #include "libaat.h" #include "mymapf.h" #ifdef MEMWATCH #include "memwatch.h" #endif /***************************************************************************** * Get_WFOGrids() -- Arthur Taylor / MDL * * PURPOSE * Define the WFO grid by reading in the RTOFLON and RTOFLAT data from the * WFO [wfo]_ncep_config.sh files located in the 'wfoDir'. Uses that * information combined with the spacing variable to compute the number of X * cells (NX) and number of Y cells (NY). * * ARGUMENTS * wfoList = Comma separeated list of WFO's to define (Input) * wfoDir = Location of the WFO .sh files (Input) * spacing = # degrees to separate WFO points by (both X and Y) (Input) * numGrids = Number of WFO grids (Output) * WfoMap = Set of Wfo grids. * * RETURNS: 1 on error, 0 on ok. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES ****************************************************************************/ /* Structure used to hold a WFO grid. */ typedef struct { char WFO[4]; /* WFO. */ double lat1, lon1; /* Lower left corner of WFO grid. */ double lat2, lon2; /* Upper right corner of WFO grid. */ sInt4 NX, NY; /* Number of points in X and Y direction. */ } wfoGridType; static int Get_WFOGrids (const char *wfoList, const char *wfoDir, double spacing, size_t *numGrids, wfoGridType ** WfoGrid) { int f_error = 0; /* Return value */ char *spBuff = NULL; /* Copy of wfoList with ',' => \0 and trimmed */ size_t spBuffLen = 0; /* Allocated length of spBuff */ size_t numCol = 0; /* Number of columns in wfoList */ char **col = NULL; /* Pointers to beginning of columns in spBuff */ size_t i; /* Loop counter over number of columns */ wfoGridType *wfoGrid; /* Local copy of wfoGrid for constructing */ char *configName = NULL; /* Name of WFO config file */ FILE *fp; /* Open'ed WFO config file */ char *line = NULL; /* Current line in WFO config file */ size_t lineLen = 0; /* Allocated length of line */ char *ptr; /* Pointer to begininng of RTOF.. in line */ char *ptr2; /* Pointer to '=' in line */ /* Split the wfoList by the ',' */ if (mySplit (wfoList, ',', &spBuffLen, &spBuff, &numCol, &col, 1) != 0) { fprintf (stderr, "Problems working with wfoList: %s\n", wfoList); f_error = 1; goto error; } /* Allocate the wfoGrids. */ *numGrids = numCol; wfoGrid = (wfoGridType *) malloc (numCol * sizeof (wfoGridType)); /* Loop over the wfoGrids. */ for (i = 0; i < numCol; i++) { /* Determine the WFO config file name */ strToLower (col[i]); strncpy (wfoGrid[i].WFO, col[i], 3); wfoGrid[i].WFO[3] = '\0'; mallocSprintf (&configName, "%s/%s_ncep_config.sh", wfoDir, col[i]); /* Open the WFO config file and look for the 'right' lines. */ if ((fp = fopen (configName, "rt")) == NULL) { fprintf (stderr, "Problems opening Config file %s\n", configName); f_error = 1; goto error; } while (reallocFGets (&line, &lineLen, fp) > 0) { strTrim (line); if ((line[0] != '#') && (strlen (line) > 0)) { /* Look for RTOFSLON= or RTOFSLAT= */ if ((ptr = strchr (line, 'R')) != NULL) { if ((ptr[1] == 'T') && ((ptr2 = strchr (ptr, '=')) != NULL)) { *ptr2 = '\0'; if (strcmp (ptr, "RTOFSLON") == 0) { /* The + 2 below avoids the = and the first " char */ sscanf (ptr2 + 2, "%lf %lf", &wfoGrid[i].lon1, &wfoGrid[i].lon2); wfoGrid[i].NX = ceil ((wfoGrid[i].lon2 - wfoGrid[i].lon1) / spacing + 1); /* Get longitudes in range of -180 to 180 */ wfoGrid[i].lon1 = wfoGrid[i].lon1 - 360; wfoGrid[i].lon2 = wfoGrid[i].lon2 - 360; } else if (strcmp (ptr, "RTOFSLAT") == 0) { /* The + 2 below avoids the = and the first " char */ sscanf (ptr2 + 2, "%lf %lf", &wfoGrid[i].lat1, &wfoGrid[i].lat2); wfoGrid[i].NY = ceil ((wfoGrid[i].lat2 - wfoGrid[i].lat1) / spacing + 1); } else { fprintf (stderr, "Unexpected line '%s' in '%s'\n", line, configName); f_error = 1; free (wfoGrid); goto error; } } } } } free (configName); configName = NULL; fclose (fp); } /* Set the answer pointer to the local pointer. */ *WfoGrid = wfoGrid; error: free (line); if (configName != NULL) { free (configName); } if (spBuff != NULL) { free (spBuff); } if (col != NULL) { free (col); } return f_error; } /***************************************************************************** * Read_DegribTxtGDS() -- Arthur Taylor / MDL * * PURPOSE * Read the Grid Definition Section (GDS) from a degrib formated .txt file. * This creates a gdsType which can then be used to define a map projection * via a call to mapMapf.c::SetMapParamGDS(). * * ARGUMENTS * filename = Filename to read the degrib formated .txt file from (Input) * gds = Resulting Grid Definition Section (GDS) (Output) * * RETURNS: 1 on error, 0 on ok. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES ****************************************************************************/ static int Read_DegribTxtGDS (const char *filename, gdsType *gds) { int f_error = 0; /* Return value */ FILE *fp; /* Open'ed 'degrib .txt' file */ char *line = NULL; /* Current line in degrib .txt file */ size_t lineLen = 0; /* Allocated length of line */ char *spBuff = NULL; /* Copy of line with '|' => \0 and trimmed */ size_t spBuffLen = 0; /* Allocated length of spBuff */ size_t numCol = 0; /* Number of columns in line */ char **col = NULL; /* Pointers to beginning of columns in spBuff */ /* Open the 'degrib .txt' file. */ if ((fp = fopen (filename, "rt")) == NULL) { fprintf (stderr, "Problems opening Map file %s\n", filename); return 1; } /* Set gds elements we don't care about. */ gds->resFlag = 0; gds->center = 0; gds->lat2 = 0; gds->lon2 = 0; /* Really obscure gds entries. */ gds->poleLat = 0; gds->poleLon = 0; gds->stretchFactor = 0; gds->f_typeLatLon = 0; gds->angleRotate = 0; gds->hdatum = 0; /* Loop over the lines in the 'degrib .txt' file. */ while (reallocFGets (&line, &lineLen, fp) > 0) { if (strncmp (line, "GDS", 3) == 0) { /* Split on the '|' and make sure the line is well formed. */ if (mySplit (line, '|', &spBuffLen, &spBuff, &numCol, &col, 1) != 0) { fprintf (stderr, "%s is not well formed\n", line); f_error = 1; goto error; } if (numCol != 3) { fprintf (stderr, "%s is not well formed\n", line); f_error = 1; goto error; } /* Parse the GDS entries that we care about. */ if (strcmp (col[1], "Number of Points") == 0) { gds->numPts = atoi (col[2]); } else if (strcmp (col[1], "Projection Type") == 0) { gds->projType = atoi (col[2]); if (gds->projType != 30) { fprintf (stderr, "Have only tested this procedure with lambert " "conformal projections\nIf '%s' is Mercator, we need " "to parse lat2, lon2\n", line); f_error = 1; goto error; } } else if (strcmp (col[1], "Shape of Earth") == 0) { gds->f_sphere = 1; if (strcmp (col[2], "sphere") != 0) { fprintf (stderr, "Currently can only handle spheres\n"); f_error = 1; goto error; } } else if (strcmp (col[1], "Radius") == 0) { gds->majEarth = atof (col[2]); gds->minEarth = gds->majEarth; } else if (strcmp (col[1], "Nx (Number of points on parallel)") == 0) { gds->Nx = atoi (col[2]); } else if (strcmp (col[1], "Ny (Number of points on meridian)") == 0) { gds->Ny = atoi (col[2]); } else if (strcmp (col[1], "Lat1") == 0) { gds->lat1 = atof (col[2]); } else if (strcmp (col[1], "Lon1") == 0) { gds->lon1 = atof (col[2]); } else if (strcmp (col[1], "OrientLon") == 0) { gds->orientLon = atof (col[2]); } else if (strcmp (col[1], "Dx") == 0) { gds->Dx = atof (col[2]); } else if (strcmp (col[1], "Dy") == 0) { gds->Dy = atof (col[2]); } else if (strcmp (col[1], "MeshLat") == 0) { gds->meshLat = atof (col[2]); } else if (strcmp (col[1], "(.flt file grid), scan mode") == 0) { gds->scan = atof (col[2]); } else if (strcmp (col[1], "Tangent Lat1") == 0) { gds->scaleLat1 = atof (col[2]); } else if (strcmp (col[1], "Tangent Lat2") == 0) { gds->scaleLat2 = atof (col[2]); } else if (strcmp (col[1], "Southern Lat") == 0) { gds->southLat = atof (col[2]); } else if (strcmp (col[1], "Southern Lon") == 0) { gds->southLon = atof (col[2]); } } } /* Check that 'mapMapf.c' considers the gds to be valid. */ if (GDSValid (gds) != 0) { fprintf (stderr, "Something wrong with the gds\n"); f_error = 1; goto error; } error: fclose (fp); free (line); if (spBuff != NULL) { free (spBuff); } if (col != NULL) { free (col); } return f_error; } /***************************************************************************** * Get_MetaInfo() -- Arthur Taylor / MDL * * PURPOSE * Parse the fltFile name for (a) the asof time (when the forecast was made) * (b) the valid time (remember that this is the end of the forecast time) * (c) the P-Surge exceedance level. * This assumes that the file name was constructed using "degrib's" nameStyle * "%e_%lv_%p_e${EXCEED}.txt" where ${EXCEED} is the P-Surge Exceedance level. * * ARGUMENTS * fltFile = The .flt filename to parse (Input) * Asof = When the forecast was made (aka reference time) (Output) * Time = The number of hours between the Asof time and the end of the valid * period. For P-Surge that is currently 6-hours later. (Output) * Exceed = What P-Surge exceedance level (e10, e20, e30, e40, e50) (Output) * * RETURNS: 1 on error, 0 on ok. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES ****************************************************************************/ static int Get_MetaInfo (const char *fltFile, char **Asof, char **Time, char **Exceed) { int f_error = 0; /* Return value */ char *spBuff = NULL; /* Copy of fltFile with '_' => \0 and trimmed */ size_t spBuffLen = 0; /* Allocated length of spBuff */ size_t numCol = 0; /* Number of columns in fltFile */ char **col = NULL; /* Pointers to beginning of columns in spBuff */ char *ptr; /* Points to first '.' in 4th column of fltFile */ /* Split on the '_' and make sure the fltFile is well formed. */ if (mySplit (fltFile, '_', &spBuffLen, &spBuff, &numCol, &col, 1) != 0) { fprintf (stderr, "Problems working with fltFileName: %s\n", fltFile); f_error = 1; goto error; } if (numCol != 4) { fprintf (stderr, "fltFile: %s is not of the form " "*_[asof]_[projection time]_[exceed].*\n", fltFile); f_error = 1; goto error; } /* Get the columns that we care about. */ *Asof = malloc (strlen (col[1]) + 1); strcpy (*Asof, col[1]); *Time = malloc (strlen (col[2]) + 1); strcpy (*Time, col[2]); ptr = strchr (col[3], '.'); *ptr = '\0'; *Exceed = malloc (strlen (col[3]) + 1); strcpy (*Exceed, col[3]); error: if (spBuff != NULL) { free (spBuff); } if (col != NULL) { free (col); } return f_error; } /***************************************************************************** * OutputWFO() -- Arthur Taylor / MDL * * PURPOSE * For a given WFO grid, loop over the lat/lons mapping the lat/lon to the * the P-Surge grid. Use fseek() and FREAD_BIG() to get the data from the .flt * file. Depending on the user's choice of f_interp, either use nearest neighbor * or bi-linear interpolation to determine the resulting value. Write the value * to outFile based on the user's choice of output style. * * ARGUMENTS * flt = Opened .flt file (Input) * map = Map projection associated with the .flt file (Input) * fltNx = NX of the .flt file (Input) * fltNy = NY of the .flt file (Input) * fltMiss = Missing value for the .flt file (Input) * wfoGrid = WFO Grid to output (Input) * spacing = Delta X and Delta Y spacing (in degrees) for WFO grids (Input) * wfoMiss = Missing value for the wfoGrid (Input) * f_interp = 1 => use bi-linear, 0 => use nearest-neighbor (Input) * f_feet = 1 => output in feet, 0 => output in meters (Input) * f_outStyle = Which output style to use. (Input) Choices are: * 1 => Binary 4 byte float file (.dat) with z values * 2 => ASCII file (.dat) with z values * 3 => ASCII file (.csv) with lon, lat, z values * 4 => ASCII file (.csv) with lon, lat, x, y, z values * outFile = Name of file to write output to (Output) * * RETURNS: 1 on error, 0 on ok. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES * 1) Assumes the .flt file was created in "big endian". * 2) Assumes the .flt file was created in meters. * 3) Assumes the binary .dat file should be in "little endian". ****************************************************************************/ #define M2FT 3.28084 static int OutputWFO (FILE *flt, myMaparam *map, sInt4 fltNx, sInt4 fltNy, double fltMiss, wfoGridType * wfoGrid, double spacing, sInt4 wfoMiss, char f_interp, char f_feet, char f_outStyle, char *outFile) { sInt4 i, j; /* Loop Counters over the WFO lat/lon's */ double lat, lon; /* Current lat/lon in the grid */ double x, y; /* Current x/y in the grid */ sInt4 iX, iY; /* integer value of lower left corner of x/y or the * nearest neighbor to x/y depending on f_interp */ sInt4 offset; /* Current offset into the flt file */ float d11, d12, d21, d22; /* Corner values during bi-linear interpolation */ float d1, d2; /* Edge values during bi-linear interpolation */ float d; /* Resulting P-Surge value */ FILE *fp; /* The opened output file */ /* Open the output file. */ if (f_outStyle == 1) { if ((fp = fopen (outFile, "wb")) == NULL) { fprintf (stderr, "Problems opening output file %s\n", outFile); return 1; } } else { if ((fp = fopen (outFile, "wt")) == NULL) { fprintf (stderr, "Problems opening output file %s\n", outFile); return 1; } if (f_outStyle == 3) { fprintf (fp, "Lon, Lat, Z\n"); } else if (f_outStyle == 4) { fprintf (fp, "Lon, Lat, X, Y, Z\n"); } } if (f_interp) { /* Bi-linear interpolation */ for (i = 0; i < wfoGrid->NX; i++) { for (j = 0; j < wfoGrid->NY; j++) { lon = wfoGrid->lon1 + i * spacing; lat = wfoGrid->lat1 + j * spacing; myCll2xy (map, lat, lon, &x, &y); iX = floor (x); iY = floor (y); /* Get the data value 'd' */ offset = ((iX - 1) + ((fltNy - 1) - (iY - 1)) * fltNx) * sizeof (float); fseek (flt, offset, SEEK_SET); FREAD_BIG (&(d11), sizeof (float), 1, flt); offset = ((iX - 1) + ((fltNy - 1) - (iY)) * fltNx) * sizeof (float); fseek (flt, offset, SEEK_SET); FREAD_BIG (&(d12), sizeof (float), 1, flt); offset = ((iX) + ((fltNy - 1) - (iY - 1)) * fltNx) * sizeof (float); fseek (flt, offset, SEEK_SET); FREAD_BIG (&(d21), sizeof (float), 1, flt); offset = ((iX) + ((fltNy - 1) - (iY)) * fltNx) * sizeof (float); fseek (flt, offset, SEEK_SET); FREAD_BIG (&(d22), sizeof (float), 1, flt); if ((d11 == fltMiss) || (d12 == fltMiss) || (d21 == fltMiss) || (d22 == fltMiss)) { d = wfoMiss; } else { /* *INDENT-OFF* */ /* d1 = d11 + (y - y1) / (y2 - y1) * (d12 - d11); * d2 = d21 + (y - y1) / (y2 - y1) * (d22 - d21); * y2 - y1 = 1 ; y - y1 = y - iY */ /* *INDENT-ON* */ d1 = d11 + (y - iY) * (d12 - d11); d2 = d21 + (y - iY) * (d22 - d21); /* *INDENT-OFF* */ /* d = d1 + (x - x1) / (x2 - x1) * (d2 - d1); * x2 - x1 = 1 ; x - x1 = x - iX */ /* *INDENT-ON* */ d = d1 + (x - iX) * (d2 - d1); if (f_feet) { d = d * M2FT; } } /* Output the result: .flt file is in meters to 3 decimals (i.e we * have either +/- 0.001 meter or 0.00328 feet). In text output, * round to 3 decimals. */ if (f_outStyle == 1) { FWRITE_LIT (&(d), sizeof (float), 1, fp); } else if (f_outStyle == 2) { fprintf (fp, "%.3f\n", d); } else if (f_outStyle == 3) { fprintf (fp, "%f, %f, %.3f\n", lon, lat, d); } else if (f_outStyle == 4) { fprintf (fp, "%f, %f, %f, %f, %.3f\n", lon, lat, x, y, d); } } } } else { /* Nearest neighbor interpolation */ for (i = 0; i < wfoGrid->NX; i++) { for (j = 0; j < wfoGrid->NY; j++) { lon = wfoGrid->lon1 + i * spacing; lat = wfoGrid->lat1 + j * spacing; myCll2xy (map, lat, lon, &x, &y); iX = floor (x + 0.5); iY = floor (y + 0.5); /* Get the data value 'd' */ offset = ((iX - 1) + ((fltNy - 1) - (iY - 1)) * fltNx) * sizeof (float); fseek (flt, offset, SEEK_SET); FREAD_BIG (&(d), sizeof (float), 1, flt); if (d == fltMiss) { d = wfoMiss; } else { if (f_feet) { d = d * M2FT; } } /* Output the result: .flt file is in meters to 3 decimals (i.e we * have either +/- 0.001 meter or 0.00328 feet). In text output, * round to 3 decimals. */ if (f_outStyle == 1) { FWRITE_LIT (&(d), sizeof (float), 1, fp); } else if (f_outStyle == 2) { fprintf (fp, "%.3f\n", d); } else if (f_outStyle == 3) { fprintf (fp, "%f, %f, %.3f\n", lon, lat, d); } else if (f_outStyle == 4) { fprintf (fp, "%f, %f, %f, %f, %.3f\n", lon, lat, x, y, d); } } } } fclose (fp); return 0; } /***************************************************************************** * ParseCmdLine() -- Arthur Taylor / MDL * * PURPOSE * Parse the user's options from the command line. Also provides the * Usage() and About() functions via the flag=1, and flag=2 options. * * ARGUMENTS * flag = 0 => Parse the command line, 1 = Print usage, 2 = Print version (In) * argc = The number of arguments on the command line. (Input) * argv = The arguments on the command line. (Input) * usr = The parsed user parameters (Output) * * RETURNS: -1 on error, 0 on ok and continue, 1 on ok, but quit. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES ****************************************************************************/ typedef struct { char *fltFile; /* Name of the .flt file */ char *wfoList; /* Comma separated list of WFO's */ char *wfoDir; /* Where to find the '[wfo]_ncep_config.sh' files */ double spacing; /* Spacing (in degrees) for the WFO grid */ char f_interp; /* 1=bi-linear, 0=nearest neighbor interpolation */ char f_feet; /* Output in 1=feet, 0=meter */ char f_outStyle; /* Output style (see usage) */ } usrType; static int ParseCmdLine (int flag, int argc, char **argv, usrType * usr) { int c; /* Returned command line option */ struct getOptRet getOp; /* Command line option structure */ if (flag == 2) { /* Print version info and return */ printf ("%s\nVersion: %s\nDate: %s\nAuthors: Arthur Taylor\n", argv[0], PROGRAM_VERSION, PROGRAM_DATE); printf ("Compiled by %s\n", CC_VER); printf ("Compiled date %s\n", __DATE__); printf ("sizeof(long int)=%d, sizeof(sInt4)=%d\n", (int) sizeof (long int), (int) sizeof (sInt4)); return 0; } else if (flag == 1) { /* Print usage info and return */ printf ("usage: %s [options]\n\n", argv[0]); printf (" -H = Prints this help\n"); printf (" -V = Version of the program\n\n"); printf (" -d [arg] = Directory containing [wfo]_ncep_config.sh files\n"); printf (" -i = [Optional] Use bi-linear interpolation (vs nearest " "neighbor)\n"); printf (" -m = [Optional] Output meters (vs feet)\n"); printf (" -o [arg] = [Optional] Output format (default 1)\n"); printf (" [1] = Binary 4 byte float file (.dat) with z values" ".\n"); printf (" 2 = ASCII file (.dat) with z values.\n"); printf (" 3 = ASCII file (.csv) with lon, lat, z values.\n"); printf (" 4 = ASCII file (.csv) with lon, lat, x, y, z values" ".\n"); printf (" -s [arg] = [Optional] spacing for the wfo grid (default = 0.00" "45 degree)\n"); printf (" -w [arg] = WFO(s) to convert.sh file(s) containing the NWPS ex" "tents\n\n"); printf ("Assumptions:\n"); printf (" 1) mapfile is same as .flt except with a .txt extension.\n"); printf (" 2) Name of .flt file is of form *_[asof]_[proj. time]_[exceed" "].*\n"); printf (" e.g. SURGE10_asof_006_e10.flt\n\n"); printf ("Example: %s foo.flt -w mfl,mlb -d ./wfoFiles\n", argv[0]); return 0; } /* Init the usr options. */ usr->fltFile = NULL; usr->wfoList = NULL; usr->wfoDir = NULL; usr->spacing = 0.0045; usr->f_interp = 0; usr->f_feet = 1; usr->f_outStyle = 1; /* Parse the command line. */ getOp.opterr = 0; while ((c = myGetOpt (argc, argv, "HVd:imo:s:w:", NULL, &getOp)) != -1) { switch (c) { case 'H': ParseCmdLine (1, argc, argv, usr); return 1; case 'V': ParseCmdLine (2, argc, argv, usr); return 1; case 'd': usr->wfoDir = getOp.optarg; break; case 'i': usr->f_interp = 1; break; case 'm': usr->f_feet = 0; break; case 'o': usr->f_outStyle = atoi (getOp.optarg); break; case 's': usr->spacing = atof (getOp.optarg); break; case 'w': usr->wfoList = getOp.optarg; break; case '?': if ((getOp.optopt == 'd') || (getOp.optopt == 'o') || (getOp.optopt == 's') || (getOp.optopt == 'w')) { fprintf (stderr, "Option -%c requires an argument.\n", getOp.optopt); } else { fprintf (stderr, "Unknown option character `\\x%x'.\n", getOp.optopt); } return -1; default: ParseCmdLine (1, argc, argv, usr); return -1; } } if ((usr->wfoDir == NULL) || (usr->wfoList == NULL)) { fprintf (stderr, "Please provide a list of wfo's and/or the wfo" " directory\n"); ParseCmdLine (1, argc, argv, usr); return -1; } if (getOp.optind + 1 != argc) { fprintf (stderr, "Please provide a .flt file\n"); ParseCmdLine (1, argc, argv, usr); return -1; } usr->fltFile = argv[getOp.optind]; return 0; } /***************************************************************************** * main() -- Arthur Taylor / MDL * * PURPOSE * The main entry point for the psurge2nwps program. * * ARGUMENTS * argc = The number of arguments on the command line. (Input) * argv = The arguments on the command line. (Input) * * RETURNS: 1 on error, 0 on ok. * * HISTORY * 9/2013 Arthur Taylor (MDL): Created. * * NOTES * 4) Assumes the .flt file missing value is '9999'. Could determine by * reading the .txt file. * 5) Assumes the wfo grids missing value is '-9999'. Could be a command * line option. ****************************************************************************/ int main (int argc, char **argv) { int f_error = 0; /* Return value */ usrType usr; /* User's command line options */ size_t numWFO = 0; /* Number of WFO's */ wfoGridType *wfoGrid = NULL; /* WFO Grid definitions */ char *ptr; /* Points to '.' in flt file to create .txt name */ gdsType gds; /* Grid Definition Section associated with .flt file */ myMaparam map; /* map projection associated with .flt file */ char *asof = NULL; /* Reference time */ char *time = NULL; /* Valid Time - Reference Time */ char *exceed = NULL; /* Exceedance level */ FILE *fp; /* Open pointer to the flt file */ size_t i; /* Loop counter over number of WFO grids */ char *outFile = NULL; /* Name of the output file */ double fltMiss = 9999; /* Missing value in the .flt file */ sInt4 wfoMiss = -9999; /* Missing value in the wfo output file */ /* Parse the command line for the user's choices. */ if ((f_error = ParseCmdLine (0, argc, argv, &usr)) != 0) { if (f_error == -1) { /* Error occured. */ return 1; } else { /* Exited safely. */ return 0; } } /* Open the WFO List. */ if (Get_WFOGrids (usr.wfoList, usr.wfoDir, usr.spacing, &numWFO, &wfoGrid) != 0) { return 1; } /* Open the .txt file to read the GDS. */ if ((ptr = strchr (usr.fltFile, '.')) == NULL) { fprintf (stderr, "Can't find the . in %s\n", usr.fltFile); ParseCmdLine (1, argc, argv, &usr); free (wfoGrid); return 1; } strcpy (ptr + 1, "txt"); if (Read_DegribTxtGDS (usr.fltFile, &gds) != 0) { free (wfoGrid); return 1; } strcpy (ptr + 1, "flt"); /* Set up the map projection. */ SetMapParamGDS (&map, &gds); /* Get the meta data from the .flt filename */ if (Get_MetaInfo (usr.fltFile, &asof, &time, &exceed) != 0) { fprintf (stderr, "%s is not of for *_[asof]_[time]_[exceed].*\n", usr.fltFile); ParseCmdLine (1, argc, argv, &usr); free (wfoGrid); return 1; } /* Open the flt file. */ if ((fp = fopen (usr.fltFile, "rb")) == NULL) { fprintf (stderr, "Problems opening fltFile %s\n", usr.fltFile); free (wfoGrid); free (asof); free (time); free (exceed); return 1; } /* Loop over the WFO grids output'ing the results. */ for (i = 0; i < numWFO; i++) { /* Create the output file name. */ mallocSprintf (&outFile, "psurge_%s_%s_%d-%d_%d-%d_%d_f%s_%s.", asof, wfoGrid[i].WFO, wfoGrid[i].NX, (int) (-1 * wfoGrid[i].lon1 * 100), wfoGrid[i].NY, (int) (wfoGrid[i].lat1 * 100), (int) (ceil (usr.spacing * 10000)), time, exceed); if ((usr.f_outStyle == 1) || (usr.f_outStyle == 2)) { reallocSprintf (&outFile, "dat"); } else { reallocSprintf (&outFile, "csv"); } /* Output to the WFO file by probing the .flt file */ if (OutputWFO (fp, &map, gds.Nx, gds.Ny, fltMiss, &(wfoGrid[i]), usr.spacing, wfoMiss, usr.f_interp, usr.f_feet, usr.f_outStyle, outFile) != 0) { fprintf (stderr, "Problems with looping over the wfo grid\n"); free (wfoGrid); free (asof); free (time); free (exceed); return 1; } free (outFile); outFile = NULL; } fclose (fp); free (asof); free (time); free (exceed); free (wfoGrid); return 0; }