1 /*****************************************************************************
2  * metaprint.c
3  *
4  * DESCRIPTION
5  *    This file contains the code necessary to write out the meta data
6  * structure.
7  *
8  * HISTORY
9  *    9/2002 Arthur Taylor (MDL / RSIS): Created.
10  *
11  * NOTES
12  * 1) Need to add support for GS3_ORTHOGRAPHIC = 90,
13  *    GS3_EQUATOR_EQUIDIST = 110, GS3_AZIMUTH_RANGE = 120
14  * 2) Need to add support for GS4_RADAR = 20, GS4_SATELLITE = 30
15  *****************************************************************************
16  */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <math.h>
21 #include "meta.h"
22 #include "metaname.h"
23 #include "myerror.h"
24 #include "myutil.h"
25 #include "tdlpack.h"
26 #include "myassert.h"
27 #include "clock.h"
28 
29 /*****************************************************************************
30  * Lookup() --
31  *
32  * Arthur Taylor / MDL
33  *
34  * PURPOSE
35  *   To lookup the string value in a table, given the table, the index, and
36  * some default values.
37  *
38  * ARGUMENTS
39  * table = The table to look in. (Input)
40  *     n = Size of table. (Input)
41  * index = Index to look up. (Input)
42  *
43  * FILES/DATABASES: None
44  *
45  * RETURNS: char *
46  *   The desired index value, or the appropriate default message.
47  *
48  * HISTORY
49  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
50  *
51  * NOTES
52  * Can not do a sizeof(table) here because table is now of arbitrary length.
53  * Instead do sizeof(table) in calling procedure.
54  *****************************************************************************
55  */
Lookup(const char ** table,size_t n,size_t index)56 static const char *Lookup(const char **table, size_t n, size_t index)
57 {
58    static const char *def[] =
59     { "Reserved", "Reserved for local use", "Missing" };
60    if (index < (n / sizeof (char *))) {
61       return table[index];
62    } else if (index < 192) {
63       return def[0];
64    } else if (index < 255) {
65       return def[1];
66    } else {
67       return def[2];
68    }
69 }
70 
71 /*****************************************************************************
72  * Print() --
73  *
74  * Arthur Taylor / MDL
75  *
76  * PURPOSE
77  *   To print the message to a local static array in a way similar to
78  * myerror.c::errSprintf.  This allows us to pass the results back to Tcl/Tk,
79  * as well as to save it to disk.  It also serves as a central place to
80  * change if we want a different style of output.
81  *
82  *   The caller gives a series of calls with fmt != NULL, followed by
83  * a fmt == NULL.  This last call will return the constructed message to the
84  * caller, and reset the message to NULL.  It is caller's responsibility to
85  * free the message, and to make sure that last call to Print has fmt = NULL,
86  * so that the routine doesn't accidently keep memory.
87  *
88  * ARGUMENTS
89  *   label = A label for this set of data. (Input)
90  * varName = A char string describing the variable.. (Input)
91  *     fmt = Prt_NULL, Prt_D, Prt_DS, Prt_DSS, Prt_S, Prt_F, Prt_FS, Prt_E,
92  *           Prt_ES. (Input)
93  *           determines what to expect in the rest of the arguments.
94  *           d = sInt4, s = char *, f = double,
95  *           NULL = return the constructed answer, and reset answer to NULL.
96  *
97  * FILES/DATABASES: None
98  *
99  * RETURNS: char *
100  *   NULL if (fmt != NULL) (ie we added to message)
101  *   message if (fmt == NULL) (ie return the message).
102  *       It is caller's responsibility to free the message, and to make sure
103  *       that last call to Print has fmt = NULL.
104  *
105  * HISTORY
106  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
107  *   4/2003 AAT: Changed so it could print different types of labels
108  *               "GDS" instead of "S3"
109  *  10/2004 AAT: Added Prt_SS
110  *
111  * NOTES
112  * Using enumerated type instead of "ds" "dss" etc.  For speed considerations.
113  *****************************************************************************
114  */
Print(const char * label,const char * varName,Prt_TYPE fmt,...)115 char *Print(const char *label, const char *varName, Prt_TYPE fmt, ...)
116 {
117    static char *buffer = NULL; /* Copy of message generated so far. */
118    va_list ap;          /* pointer to variable argument list. */
119    sInt4 lival;         /* Store a sInt4 val from argument list. */
120    char *sval;          /* Store a string val from argument. */
121    char *unit;          /* Second string val is usually a unit string. */
122    double dval;         /* Store a double val from argument list. */
123    char *ans;           /* Final message to return if fmt = Prt_NULL. */
124 
125    if (fmt == Prt_NULL) {
126       ans = buffer;
127       buffer = NULL;
128       return ans;
129    }
130    va_start (ap, fmt);  /* make ap point to 1st unnamed arg. */
131    switch (fmt) {
132       case Prt_D:
133          lival = va_arg (ap, sInt4);
134          reallocSprintf (&buffer, "%s | %s | %ld\n", label, varName, lival);
135          break;
136       case Prt_DS:
137          lival = va_arg (ap, sInt4);
138          sval = va_arg (ap, char *);
139          reallocSprintf (&buffer, "%s | %s | %ld (%s)\n", label, varName,
140                          lival, sval);
141          break;
142       case Prt_DSS:
143          lival = va_arg (ap, sInt4);
144          sval = va_arg (ap, char *);
145          unit = va_arg (ap, char *);
146          reallocSprintf (&buffer, "%s | %s | %ld (%s [%s])\n", label,
147                          varName, lival, sval, unit);
148          break;
149       case Prt_S:
150          sval = va_arg (ap, char *);
151          reallocSprintf (&buffer, "%s | %s | %s\n", label, varName, sval);
152          break;
153       case Prt_SS:
154          sval = va_arg (ap, char *);
155          unit = va_arg (ap, char *);
156          reallocSprintf (&buffer, "%s | %s | %s (%s)\n", label, varName,
157                          sval, unit);
158          break;
159       case Prt_F:
160          dval = va_arg (ap, double);
161          reallocSprintf (&buffer, "%s | %s | %f\n", label, varName, dval);
162          break;
163       case Prt_E:
164          dval = va_arg (ap, double);
165          reallocSprintf (&buffer, "%s | %s | %e\n", label, varName, dval);
166          break;
167       case Prt_G:
168          dval = va_arg (ap, double);
169          reallocSprintf (&buffer, "%s | %s | %g\n", label, varName, dval);
170          break;
171       case Prt_FS:
172          dval = va_arg (ap, double);
173          unit = va_arg (ap, char *);
174          reallocSprintf (&buffer, "%s | %s | %f (%s)\n", label, varName,
175                          dval, unit);
176          break;
177       case Prt_ES:
178          dval = va_arg (ap, double);
179          unit = va_arg (ap, char *);
180          reallocSprintf (&buffer, "%s | %s | %e (%s)\n", label, varName,
181                          dval, unit);
182          break;
183       case Prt_GS:
184          dval = va_arg (ap, double);
185          unit = va_arg (ap, char *);
186          reallocSprintf (&buffer, "%s | %s | %g (%s)\n", label, varName,
187                          dval, unit);
188          break;
189       default:
190          reallocSprintf (&buffer, "ERROR: Invalid Print option '%d'\n", fmt);
191    }
192    va_end (ap);         /* clean up when done. */
193    return NULL;
194 }
195 
196 /*****************************************************************************
197  * PrintSect1() --
198  *
199  * Arthur Taylor / MDL
200  *
201  * PURPOSE
202  *   To generate the message for GRIB2 section 1.
203  *
204  * ARGUMENTS
205  *      pds2 = The GRIB2 Product Definition Section to print. (Input)
206  *    center = The Center that created the data (Input)
207  * subcenter = The Sub Center that created the data (Input)
208  *
209  * FILES/DATABASES: None
210  *
211  * RETURNS: void
212  *
213  * HISTORY
214  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
215  *   4/2003 AAT: Changed to accept pointer to pdsG2Type pds2
216  *  10/2005 AAT: Adjusted to take center, subcenter as we moved that out of
217  *               the pdsG2 type.
218  *
219  * NOTES
220  *****************************************************************************
221  */
PrintSect1(pdsG2Type * pds2,unsigned short int center,unsigned short int subcenter)222 static void PrintSect1 (pdsG2Type * pds2, unsigned short int center,
223                         unsigned short int subcenter)
224 {
225    /* Based on Grib2 Code Table 1.2 */
226    static const char *table12[] = { "Analysis", "Start of Forecast",
227       "Verifying time of forecast", "Observation time"
228    };
229 
230    /* Based on Grib2 Code Table 1.3 */
231    static const char *table13[] = { "Operational products",
232       "Operational test products", "Research products",
233       "Re-analysis products"
234    };
235 
236    /* Based on Grib2 Code Table 1.4 */
237    static const char *table14[] = { "Analysis products",
238       "Forecast products", "Analysis and forecast products",
239       "Control forecast products", "Perturbed forecast products",
240       "Control and perturbed forecast products",
241       "Processed satellite observations", "Processed radar observations"
242    };
243 
244    char buffer[25];     /* Stores format of pds2->refTime. */
245    const char *ptr;
246 
247    ptr = centerLookup (center);
248    if (ptr != NULL) {
249       Print ("PDS-S1", "Originating center", Prt_DS, center, ptr);
250    } else {
251       Print ("PDS-S1", "Originating center", Prt_D, center);
252    }
253    if (subcenter != GRIB2MISSING_u2) {
254       ptr = subCenterLookup (center, subcenter);
255       if (ptr != NULL) {
256          Print ("PDS-S1", "Originating sub-center", Prt_DS, subcenter, ptr);
257       } else {
258          Print ("PDS-S1", "Originating sub-center", Prt_D, subcenter);
259       }
260    }
261    Print ("PDS-S1", "GRIB Master Tables Version", Prt_D, pds2->mstrVersion);
262    Print ("PDS-S1", "GRIB Local Tables Version", Prt_D, pds2->lclVersion);
263    Print ("PDS-S1", "Significance of reference time", Prt_DS, pds2->sigTime,
264           Lookup (table12, sizeof (table12), pds2->sigTime));
265 
266 /*   strftime (buffer, 25, "%m/%d/%Y %H:%M:%S UTC", gmtime (&(pds2->refTime)));*/
267    Clock_Print (buffer, 25, pds2->refTime, "%m/%d/%Y %H:%M:%S UTC", 0);
268 
269    Print ("PDS-S1", "Reference Time", Prt_S, buffer);
270    Print ("PDS-S1", "Operational Status", Prt_DS, pds2->operStatus,
271           Lookup (table13, sizeof (table13), pds2->operStatus));
272    Print ("PDS-S1", "Type of Data", Prt_DS, pds2->dataType,
273           Lookup (table14, sizeof (table14), pds2->dataType));
274 }
275 
276 /*****************************************************************************
277  * PrintSect2() --
278  *
279  * Arthur Taylor / MDL
280  *
281  * PURPOSE
282  *   To generate a message for the section 2 data.  This may be more
283  * appropriate in its own file (particularly the weather table.)
284  *
285  * ARGUMENTS
286  * sect2 = The sect2 structure to print (initialized by ParseSect2). (Input)
287  *
288  * FILES/DATABASES: None
289  *
290  * RETURNS: void
291  *
292  * HISTORY
293  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
294  *
295  * NOTES
296  *****************************************************************************
297  */
PrintSect2(sect2_type * sect2)298 static void PrintSect2 (sect2_type * sect2)
299 {
300    size_t i;            /* loop counter over number of sect2 data. */
301    char buffer[25];     /* Assists with labeling. */
302 
303    switch (sect2->ptrType) {
304       case GS2_WXTYPE:
305          Print ("PDS-S2", "Number of Elements in Section 2", Prt_D,
306                 sect2->wx.dataLen);
307          for (i = 0; i < sect2->wx.dataLen; i++) {
308             if (sect2->wx.ugly[i].validIndex != -1) {
309                 sprintf (buffer, "Elem %3d  Is Used", (int) i);
310             } else {
311                 sprintf (buffer, "Elem %3d NOT Used", (int) i);
312             }
313             Print ("PDS-S2", buffer, Prt_S, sect2->wx.data[i]);
314          }
315          break;
316       case GS2_UNKNOWN:
317          Print ("PDS-S2", "Number of Elements in Section 2", Prt_D,
318                 sect2->unknown.dataLen);
319          for (i = 0; i < sect2->unknown.dataLen; i++) {
320              sprintf (buffer, "Element %d", (int) i);
321             Print ("PDS-S2", buffer, Prt_F, sect2->unknown.data[i]);
322          }
323          break;
324       default:
325          return;
326    }
327 }
328 
329 /*****************************************************************************
330  * PrintSect4_Category() --
331  *
332  * Arthur Taylor / MDL
333  *
334  * PURPOSE
335  *   To generate the category message for section 4.
336  *
337  * ARGUMENTS
338  * meta = The meta file structure to generate the message for. (Input)
339  *
340  * FILES/DATABASES: None
341  *
342  * RETURNS: void
343  *
344  * HISTORY
345  *   6/2003 Arthur Taylor (MDL/RSIS): Extracted this part from PrintSect4().
346  *   1/2004 AAT: Combined PrintSect4_Meteo and PrintSect4_Ocean into this.
347  *   5/2004 AAT: Found out that I skipped "Momentum Probabilities" in tbl41_0.
348  *
349  * NOTES
350  *****************************************************************************
351  */
PrintSect4_Category(grib_MetaData * meta)352 static void PrintSect4_Category (grib_MetaData *meta)
353 {
354    sect4_type *sect4 = &(meta->pds2.sect4);
355 
356    /* Based on Grib2 Code Table 4.1 discipline 0 */
357    static const char *tbl41_0[] = {
358       "Temperature", "Moisture", "Momentum", "Mass", "Short-wave Radiation",
359       "Long-wave Radiation", "Cloud", "Thermodynamic Stability indicies",
360       "Kinematic Stability indicies", "Temperature Probabilities",
361       "Moisture Probabilities", "Momentum Probabilities",
362       "Mass Probabilities", "Aerosols", "Trace gases (e.g. ozone, C02)",
363       "Radar", "Forecast Radar Imagery", "Electro-dynamics",
364       "Nuclear/radiology", "Physical atmospheric properties"
365    };
366    /* Based on Grib2 Code Table 4.1 discipline 1 */
367    static const char *tbl41_1[] = {
368       "Hydrology basic products", "Hydrology probabilities"
369    };
370    /* Based on Grib2 Code Table 4.1 discipline 2 */
371    static const char *tbl41_2[] = {
372       "Vegetation/Biomass", "Agri-/aquacultural Special Products",
373       "Transportation-related Products", "Soil Products"
374    };
375    /* Based on Grib2 Code Table 4.1 discipline 3 */
376    static const char *tbl41_3[] = {
377       "Image format products", "Quantitative products"
378    };
379    /* Based on Grib2 Code Table 4.1 discipline 10 */
380    static const char *tbl41_10[] = {
381       "Waves", "Currents", "Ice", "Surface Properties",
382       "Sub-surface Properties"
383    };
384 
385    switch (meta->pds2.prodType) {
386       case 0:          /* Meteo category. */
387          switch (sect4->cat) {
388             case 190:
389                Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
390                       "CCITT IA5 string");
391                break;
392             case 191:
393                Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
394                       "Miscellaneous");
395                break;
396             default:
397                Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
398                       Lookup (tbl41_0, sizeof (tbl41_0), sect4->cat));
399          }
400          break;
401       case 1:          /* Hydrological */
402          Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
403                 Lookup (tbl41_1, sizeof (tbl41_1), sect4->cat));
404          break;
405       case 2:          /* Land surface */
406          Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
407                 Lookup (tbl41_2, sizeof (tbl41_2), sect4->cat));
408          break;
409       case 3:          /* Space */
410          Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
411                 Lookup (tbl41_3, sizeof (tbl41_3), sect4->cat));
412          break;
413       case 10:         /* Oceanographic */
414          Print ("PDS-S4", "Category Description", Prt_DS, sect4->cat,
415                 Lookup (tbl41_10, sizeof (tbl41_10), sect4->cat));
416          break;
417       default:
418          Print ("PDS-S4", "PrintSect4() does not handle this prodType",
419                 Prt_D, meta->pds2.prodType);
420    }
421 }
422 
423 /*****************************************************************************
424  * PrintSect4() --
425  *
426  * Arthur Taylor / MDL
427  *
428  * PURPOSE
429  *   To generate the message for section 4.
430  *
431  * ARGUMENTS
432  *   meta = The meta file structure to generate the message for. (Input)
433  * f_unit = 0 (GRIB unit), 1 (english), 2 (metric) (Input)
434  *
435  * FILES/DATABASES: None
436  *
437  * RETURNS: int (could use errSprintf())
438  *  0 if no error.
439  * -2 if asked to print data for a template that we don't support.
440  *
441  * HISTORY
442  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
443  *   2/2003 AAT: Adjusted the interpretation of the scale vactor and value.
444  *          to be consistent with what Matt found from email conversations
445  *          with WMO GRIB2 experts.
446  *   2/2003 AAT: Switched from: value / pow (10, factor)
447  *                          to: value * pow (10, -1 * factor)
448  *   6/2003 AAT: Extracted the prodType = 0 only info and put in _Meteo
449  *   6/2003 AAT: Created a PrintSect4_Ocean for ocean stuff.
450  *   1/2004 AAT: Updated table 4.7
451  *   1/2004 AAT: Modified to use "comment" from metaname.c instead of
452  *          PrintSect4_Meteo, and PrintSect4_Ocean (that way local tables are
453  *          enabled.) (Fixed meta file for PoP12).
454  *   3/2004 AAT: Added emphasis on "computation" of unit conversion.
455  *   3/2005 AAT: Added support for GS4_PROBABIL_PNT
456  *
457  * NOTES
458  * Need to add support for GS4_RADAR = 20
459  *****************************************************************************
460  */
PrintSect4(grib_MetaData * meta,sChar f_unit)461 static int PrintSect4 (grib_MetaData *meta, sChar f_unit)
462 {
463    sect4_type *sect4 = &(meta->pds2.sect4);
464    /* Based on Grib2 Code Table 4.0 */
465    static const char *tbl40[] = {
466       "Analysis at a horizontal layer at a point in time",
467       "Individual ensemble forecast at a horizontal layer at a point in time",
468       "Derived forecast based on ensemble members at a horizontal layer at a"
469             " point in time",
470       "Probability forecast at a horizontal layer or level at a point in "
471             "time",
472       "Statistically processed data at a horizontal layer or level in a time"
473             " interval",
474       "Probability forecast at a horizontal layer or level in a time "
475             "interval",
476       "Percentile forecasts at a horizontal layer or level in a time "
477             "interval",
478       "Individual ensemble forecast at a horizontal layer or level in a time"
479             " interval",
480       "Derived forecasts based in all ensemble members at a horizontal level "
481             "or layer in a time interval",
482       "Radar product", "Satellite product"
483    };
484 
485    /* Based on Grib2 Code Table 4.3 */
486    static const char *tbl43[] = {
487       "Analysis", "Initialization", "Forecast", "Bias corrected forecast",
488       "Ensemble forecast", "Probability forecast", "Forecast error",
489       "Analysis error", "Observation"
490    };
491 
492    /* Based on Grib2 Code Table 4.4 */
493    static const char *tbl44[] = {
494       "Minute", "Hour", "Day", "Month", "Year", "Decade",
495       "Normal (30 years)", "Century", "Reserved", "Reserved",
496       "3 hours", "6 hours", "12 hours", "Second"
497    };
498 
499    /* Based on Grib2 Code Table 4.5 */
500    /* See "metaname.c :: Surface[]" */
501 
502    /* Based on Grib2 Code Table 4.6 */
503    static const char *tbl46[] = {
504       "Unperturbed high-resolution control forecast",
505       "Unperturbed low-reosulution control foreacst",
506       "Negatively perturbed forecast", "Positively perturbed forecast"
507    };
508 
509    /* Based on Grib2 Code Table 4.7 */
510    static const char *tbl47[] = {
511       "Unweighted mean of all members", "Weighted mean of all members",
512       "Standard deviation with respect to cluster mean",
513       "Standard deviation with respect to cluster mean, normalized",
514       "Spread of all members",
515       "Large anomally index of all memebers",
516       "Unweighted mean of the cluster members"
517    };
518 
519    /* Based on Grib2 Code Table 4.9 */
520    static const char *tbl49[] = {
521       "Probability of event below lower limit",
522       "Probability of event above upper limit",
523       "Probability of event between limits (include lower, exclude upper)",
524       "Probability of event above lower limit",
525       "Probability of event below upper limit"
526    };
527 
528    /* Based on Grib2 Code Table 4.10 */
529    static const char *tbl410[] = {
530       "Average", "Accumulation", "Maximum", "Minimum",
531       "Difference (Value at end of time minus beginning)",
532       "Root mean square", "Standard deviation",
533       "Covariance (Temporal variance)",
534       "Difference (Value at beginning of time minus end)", "Ratio"
535    };
536 
537    /* Based on Grib2 Code Table 4.11 */
538    static const char *tbl411[] = {
539       "Reserved",
540       "Successive times; same forecast time, start time incremented",
541       "Successive times; same start time, forecast time incremented",
542       "Successive times; start time incremented, forecast time decremented, "
543             "valid time constant",
544       "Successive times; start time decremented, forecast time incremented, "
545             "valid time constant",
546       "Floating subinterval of time between forecast time, and end"
547    };
548 
549    char buffer[50];     /* Temp storage for various uses including time
550                          * format. */
551    int i;               /* counter for templat 4.8/4.9 for num time range
552                          * specs. */
553    int f_reserved;      /* Whether Table4.5 is a reserved entry or not. */
554    GRIB2SurfTable surf; /* Surface look up in Table4.5. */
555    const char *ptr;
556 
557    switch (sect4->templat) {
558       case GS4_ANALYSIS:
559       case GS4_ENSEMBLE:
560       case GS4_DERIVED:
561          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat,
562                 tbl40[sect4->templat]);
563          break;
564       case GS4_PROBABIL_PNT:
565          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[3]);
566          break;
567       case GS4_STATISTIC:
568          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[4]);
569          break;
570       case GS4_PROBABIL_TIME:
571          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[5]);
572          break;
573       case GS4_PERCENTILE:
574          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[6]);
575          break;
576       case GS4_ENSEMBLE_STAT:
577          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[7]);
578          break;
579       case GS4_DERIVED_INTERVAL:
580          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[8]);
581          break;
582 /*
583  * The following lines were removed until such time that the rest of this
584  * procedure can properly handle this template type.
585  *
586       case GS4_RADAR:
587          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[9]);
588          break;
589 */
590       case GS4_SATELLITE:
591          Print ("PDS-S4", "Product type", Prt_DS, sect4->templat, tbl40[10]);
592          break;
593       default:
594          Print ("PDS-S4", "Product type", Prt_D, sect4->templat);
595          errSprintf ("Un-supported Sect4 template %ld\n", sect4->templat);
596          return -2;
597    }
598 
599    PrintSect4_Category (meta);
600    Print ("PDS-S4", "Category Sub-Description", Prt_DS, sect4->subcat,
601           meta->comment);
602 
603    if (f_unit == 1) {
604       Print ("PDS-S4", "Output grid, (COMPUTED) english unit is", Prt_S,
605              meta->unitName);
606    } else if (f_unit == 2) {
607       Print ("PDS-S4", "Output grid, (COMPUTED) metric unit is", Prt_S,
608              meta->unitName);
609    }
610    Print ("PDS-S4", "Generation process", Prt_DS, sect4->genProcess,
611           Lookup (tbl43, sizeof (tbl43), sect4->genProcess));
612    if (sect4->templat == GS4_SATELLITE) {
613       Print ("PDS-S4", "Observation generating process", Prt_D, sect4->genID);
614       Print ("PDS-S4", "Number of contributing spectral bands", Prt_D,
615              sect4->numBands);
616       for (i = 0; i < sect4->numBands; i++) {
617          Print ("PDS-S4", "Satellite series", Prt_D, sect4->bands[i].series);
618          Print ("PDS-S4", "Satellite numbers", Prt_D,
619                 sect4->bands[i].numbers);
620          Print ("PDS-S4", "Instrument type", Prt_D, sect4->bands[i].instType);
621          Print ("PDS-S4", "Scale Factor of central wave number", Prt_D,
622                 sect4->bands[i].centWaveNum.factor);
623          Print ("PDS-S4", "Scale Value of central wave number", Prt_D,
624                 sect4->bands[i].centWaveNum.value);
625       }
626       return 0;
627    }
628    if (sect4->bgGenID != GRIB2MISSING_u1) {
629       ptr = processLookup (meta->center, sect4->bgGenID);
630       if (ptr != NULL) {
631          Print ("PDS-S4", "Background generating process ID", Prt_DS,
632                 sect4->bgGenID, ptr);
633       } else {
634          Print ("PDS-S4", "Background generating process ID", Prt_D,
635                 sect4->bgGenID);
636       }
637    }
638    if (sect4->genID != GRIB2MISSING_u1) {
639       ptr = processLookup (meta->center, sect4->genID);
640       if (ptr != NULL) {
641          Print ("PDS-S4", "Forecast generating process ID", Prt_DS,
642                 sect4->genID, ptr);
643       } else {
644          Print ("PDS-S4", "Forecast generating process ID", Prt_D,
645                 sect4->genID);
646       }
647    }
648    if (sect4->f_validCutOff) {
649       Print ("PDS-S4", "Data cut off after reference time in seconds", Prt_D,
650              sect4->cutOff);
651    }
652    Print ("PDS-S4", "Forecast time in hours", Prt_F,
653           (double) (sect4->foreSec / 3600.));
654    surf = Table45Index (sect4->fstSurfType, &f_reserved, meta->center,
655                         meta->subcenter);
656    Print ("PDS-S4", "Type of first fixed surface", Prt_DSS,
657           sect4->fstSurfType, surf.comment, surf.unit);
658    Print ("PDS-S4", "Value of first fixed surface", Prt_F,
659           sect4->fstSurfValue);
660    if (sect4->sndSurfType != GRIB2MISSING_u1) {
661       surf = Table45Index (sect4->sndSurfType, &f_reserved, meta->center,
662                            meta->subcenter);
663       Print ("PDS-S4", "Type of second fixed surface", Prt_DSS,
664              sect4->sndSurfType, surf.comment, surf.unit);
665       Print ("PDS-S4", "Value of second fixed surface", Prt_F,
666              sect4->sndSurfValue);
667    }
668    switch (sect4->templat) {
669       case GS4_ANALYSIS:
670          break;
671       case GS4_ENSEMBLE:
672          Print ("PDS-S4", "Type of Ensemble forecast", Prt_DS,
673                 sect4->typeEnsemble,
674                 Lookup (tbl46, sizeof (tbl46), sect4->typeEnsemble));
675          Print ("PDS-S4", "Perturbation number", Prt_D, sect4->perturbNum);
676          Print ("PDS-S4", "Number of forecasts in ensemble", Prt_D,
677                 sect4->numberFcsts);
678          break;
679       case GS4_ENSEMBLE_STAT:
680          Print ("PDS-S4", "Type of Ensemble forecast", Prt_DS,
681                 sect4->typeEnsemble,
682                 Lookup (tbl46, sizeof (tbl46), sect4->typeEnsemble));
683          Print ("PDS-S4", "Perturbation number", Prt_D, sect4->perturbNum);
684          Print ("PDS-S4", "Number of forecasts in ensemble", Prt_D,
685                 sect4->numberFcsts);
686          Clock_Print (buffer, 100, sect4->validTime, "%m/%d/%Y %H:%M:%S UTC",
687                       0);
688          Print ("PDS-S4", "End of overall time interval", Prt_S, buffer);
689          Print ("PDS-S4", "Total number of missing values", Prt_D,
690                 sect4->numMissing);
691          Print ("PDS-S4", "Number of time range specifications", Prt_D,
692                 sect4->numInterval);
693          for (i = 0; i < sect4->numInterval; i++) {
694             Print ("PDS-S4", "Interval number", Prt_D, i + 1);
695             Print ("PDS-S4", "Statistical process", Prt_DS,
696                    sect4->Interval[i].processID,
697                    Lookup (tbl410, sizeof (tbl410),
698                            sect4->Interval[i].processID));
699             Print ("PDS-S4", "Type of time increment", Prt_DS,
700                    sect4->Interval[i].incrType,
701                    Lookup (tbl411, sizeof (tbl411),
702                            sect4->Interval[i].incrType));
703             /* Following is so we get "# str" not "# (str)" */
704             sprintf (buffer, "%d %s", sect4->Interval[i].lenTime,
705                      Lookup (tbl44, sizeof (tbl44),
706                              sect4->Interval[i].timeRangeUnit));
707             Print ("PDS-S4", "Time range for processing", Prt_S, buffer);
708             /* Following is so we get "# str" not "# (str)" */
709             sprintf (buffer, "%d %s", sect4->Interval[i].timeIncr,
710                      Lookup (tbl44, sizeof (tbl44),
711                              sect4->Interval[i].incrUnit));
712             Print ("PDS-S4", "Time increment", Prt_S, buffer);
713          }
714          break;
715       case GS4_DERIVED:
716          Print ("PDS-S4", "Derived forecast", Prt_DS, sect4->derivedFcst,
717                 Lookup (tbl47, sizeof (tbl47), sect4->derivedFcst));
718          Print ("PDS-S4", "Number of forecasts in ensemble", Prt_D,
719                 sect4->numberFcsts);
720          break;
721       case GS4_DERIVED_INTERVAL:
722          Print ("PDS-S4", "Derived forecast", Prt_DS, sect4->derivedFcst,
723                 Lookup (tbl47, sizeof (tbl47), sect4->derivedFcst));
724          Print ("PDS-S4", "Number of forecasts in ensemble", Prt_D,
725                 sect4->numberFcsts);
726          Clock_Print (buffer, 100, sect4->validTime, "%m/%d/%Y %H:%M:%S UTC",
727                       0);
728 
729          Print ("PDS-S4", "End of overall time interval", Prt_S, buffer);
730          Print ("PDS-S4", "Total number of missing values", Prt_D,
731                 sect4->numMissing);
732          Print ("PDS-S4", "Number of time range specifications", Prt_D,
733                 sect4->numInterval);
734          for (i = 0; i < sect4->numInterval; i++) {
735             Print ("PDS-S4", "Interval number", Prt_D, i + 1);
736             Print ("PDS-S4", "Statistical process", Prt_DS,
737                    sect4->Interval[i].processID,
738                    Lookup (tbl410, sizeof (tbl410),
739                            sect4->Interval[i].processID));
740             Print ("PDS-S4", "Type of time increment", Prt_DS,
741                    sect4->Interval[i].incrType,
742                    Lookup (tbl411, sizeof (tbl411),
743                            sect4->Interval[i].incrType));
744             /* Following is so we get "# str" not "# (str)" */
745             sprintf (buffer, "%d %s", sect4->Interval[i].lenTime,
746                      Lookup (tbl44, sizeof (tbl44),
747                              sect4->Interval[i].timeRangeUnit));
748             Print ("PDS-S4", "Time range for processing", Prt_S, buffer);
749             /* Following is so we get "# str" not "# (str)" */
750             sprintf (buffer, "%d %s", sect4->Interval[i].timeIncr,
751                      Lookup (tbl44, sizeof (tbl44),
752                              sect4->Interval[i].incrUnit));
753             Print ("PDS-S4", "Time increment", Prt_S, buffer);
754          }
755          break;
756       case GS4_PROBABIL_PNT:
757          Print ("PDS-S4", "Forecast Probability Number", Prt_D,
758                 sect4->foreProbNum);
759          Print ("PDS-S4", "Total Number of Forecast Probabilities", Prt_D,
760                 sect4->numForeProbs);
761          Print ("PDS-S4", "Probability type", Prt_DS, sect4->probType,
762                 Lookup (tbl49, sizeof (tbl49), sect4->probType));
763          sprintf (buffer, "%d, %d", sect4->lowerLimit.value,
764                   sect4->lowerLimit.factor);
765          Print ("PDS-S4", "Lower limit (scale value, scale factor)", Prt_GS,
766                 sect4->lowerLimit.value *
767                 pow (10.0, -1 * sect4->lowerLimit.factor), buffer);
768          sprintf (buffer, "%d, %d", sect4->upperLimit.value,
769                   sect4->upperLimit.factor);
770          Print ("PDS-S4", "Upper limit (scale value, scale factor)", Prt_GS,
771                 sect4->upperLimit.value *
772                 pow (10.0, -1 * sect4->upperLimit.factor), buffer);
773 /*         printf ("Hello world 1\n");*/
774          break;
775       case GS4_PERCENTILE:
776          Print ("PDS-S4", "Percentile", Prt_DS, sect4->percentile, "[%]");
777 /*         strftime (buffer, 100, "%m/%d/%Y %H:%M:%S UTC",
778                    gmtime (&(sect4->validTime)));*/
779          Clock_Print (buffer, 100, sect4->validTime, "%m/%d/%Y %H:%M:%S UTC",
780                       0);
781 
782          Print ("PDS-S4", "End of overall time interval", Prt_S, buffer);
783          Print ("PDS-S4", "Total number of missing values", Prt_D,
784                 sect4->numMissing);
785          Print ("PDS-S4", "Number of time range specifications", Prt_D,
786                 sect4->numInterval);
787          for (i = 0; i < sect4->numInterval; i++) {
788             Print ("PDS-S4", "Interval number", Prt_D, i + 1);
789             Print ("PDS-S4", "Statistical process", Prt_DS,
790                    sect4->Interval[i].processID,
791                    Lookup (tbl410, sizeof (tbl410),
792                            sect4->Interval[i].processID));
793             Print ("PDS-S4", "Type of time increment", Prt_DS,
794                    sect4->Interval[i].incrType,
795                    Lookup (tbl411, sizeof (tbl411),
796                            sect4->Interval[i].incrType));
797             /* Following is so we get "# str" not "# (str)" */
798             sprintf (buffer, "%d %s", sect4->Interval[i].lenTime,
799                      Lookup (tbl44, sizeof (tbl44),
800                              sect4->Interval[i].timeRangeUnit));
801             Print ("PDS-S4", "Time range for processing", Prt_S, buffer);
802             /* Following is so we get "# str" not "# (str)" */
803             sprintf (buffer, "%d %s", sect4->Interval[i].timeIncr,
804                      Lookup (tbl44, sizeof (tbl44),
805                              sect4->Interval[i].incrUnit));
806             Print ("PDS-S4", "Time increment", Prt_S, buffer);
807          }
808          break;
809       case GS4_PROBABIL_TIME:
810          Print ("PDS-S4", "Forecast Probability Number", Prt_D,
811                 sect4->foreProbNum);
812          Print ("PDS-S4", "Total Number of Forecast Probabilities", Prt_D,
813                 sect4->numForeProbs);
814          Print ("PDS-S4", "Probability type", Prt_DS, sect4->probType,
815                 Lookup (tbl49, sizeof (tbl49), sect4->probType));
816          sprintf (buffer, "%d, %d", sect4->lowerLimit.value,
817                   sect4->lowerLimit.factor);
818          Print ("PDS-S4", "Lower limit (scale value, scale factor)", Prt_GS,
819                 sect4->lowerLimit.value *
820                 pow (10.0, -1 * sect4->lowerLimit.factor), buffer);
821          sprintf (buffer, "%d, %d", sect4->upperLimit.value,
822                   sect4->upperLimit.factor);
823          Print ("PDS-S4", "Upper limit (scale value, scale factor)", Prt_GS,
824                 sect4->upperLimit.value *
825                 pow (10.0, -1 * sect4->upperLimit.factor), buffer);
826          /* Intentionally fall through. */
827       case GS4_STATISTIC:
828 /*         strftime (buffer, 100, "%m/%d/%Y %H:%M:%S UTC",
829                    gmtime (&(sect4->validTime)));*/
830          Clock_Print (buffer, 100, sect4->validTime, "%m/%d/%Y %H:%M:%S UTC",
831                       0);
832 
833          Print ("PDS-S4", "End of overall time interval", Prt_S, buffer);
834          Print ("PDS-S4", "Total number of missing values", Prt_D,
835                 sect4->numMissing);
836          Print ("PDS-S4", "Number of time range specifications", Prt_D,
837                 sect4->numInterval);
838          for (i = 0; i < sect4->numInterval; i++) {
839             Print ("PDS-S4", "Interval number", Prt_D, i + 1);
840             Print ("PDS-S4", "Statistical process", Prt_DS,
841                    sect4->Interval[i].processID,
842                    Lookup (tbl410, sizeof (tbl410),
843                            sect4->Interval[i].processID));
844             Print ("PDS-S4", "Type of time increment", Prt_DS,
845                    sect4->Interval[i].incrType,
846                    Lookup (tbl411, sizeof (tbl411),
847                            sect4->Interval[i].incrType));
848             /* Following is so we get "# str" not "# (str)" */
849             sprintf (buffer, "%d %s", sect4->Interval[i].lenTime,
850                      Lookup (tbl44, sizeof (tbl44),
851                              sect4->Interval[i].timeRangeUnit));
852             Print ("PDS-S4", "Time range for processing", Prt_S, buffer);
853             /* Following is so we get "# str" not "# (str)" */
854             sprintf (buffer, "%d %s", sect4->Interval[i].timeIncr,
855                      Lookup (tbl44, sizeof (tbl44),
856                              sect4->Interval[i].incrUnit));
857             Print ("PDS-S4", "Time increment", Prt_S, buffer);
858          }
859          break;
860       default:
861          /* This case should have been handled in first switch statement of
862           * this procedure, but just in case... */
863          errSprintf ("Un-supported Sect4 template %d\n", sect4->templat);
864          return -2;
865    }
866    return 0;
867 }
868 
869 /*****************************************************************************
870  * PrintPDS2() --
871  *
872  * Arthur Taylor / MDL
873  *
874  * PURPOSE
875  *   To generate the message for the Product Definition Sections of the GRIB2
876  * Message.
877  *
878  * ARGUMENTS
879  *   meta = The meta file structure to generate the message for. (Input)
880  * f_unit = 0 (GRIB unit), 1 (english), 2 (metric) (Input)
881  *
882  * FILES/DATABASES: None
883  *
884  * RETURNS: void
885  *
886  * HISTORY
887  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
888  *
889  * NOTES
890  *****************************************************************************
891  */
PrintPDS2(grib_MetaData * meta,sChar f_unit)892 static int PrintPDS2 (grib_MetaData *meta, sChar f_unit)
893 {
894    pdsG2Type *pds2 = &(meta->pds2);
895    /* Based on Grib2 Code Table 0.0 */
896    static const char *table0[] = {
897       "Meteorological products", "Hydrological products",
898       "Land surface products", "Space products", "Oceanographic products"
899    };
900    int ierr;            /* The error code of a called routine */
901 
902    /* Print the data from Section 0 */
903    switch (pds2->prodType) {
904       case 10:         /* Oceanographic Product. */
905          Print ("PDS-S0", "DataType", Prt_DS, pds2->prodType, table0[4]);
906          break;
907       case 5:          /* Reserved. */
908          Print ("PDS-S0", "DataType", Prt_DS, pds2->prodType,
909                 Lookup (table0, sizeof (table0), 191));
910          break;
911       default:
912          Print ("PDS-S0", "DataType", Prt_DS, pds2->prodType,
913                 Lookup (table0, sizeof (table0), pds2->prodType));
914    }
915    PrintSect1 (pds2, meta->center, meta->subcenter);
916    PrintSect2 (&(pds2->sect2));
917    if ((ierr = PrintSect4 (meta, f_unit)) != 0) {
918       return ierr;
919    }
920    return 0;
921 }
922 
923 /*****************************************************************************
924  * PrintPDS1() --
925  *
926  * Arthur Taylor / MDL
927  *
928  * PURPOSE
929  *   To generate the message for the Product Definition Sections of the GRIB1
930  * Message.
931  *
932  * ARGUMENTS
933  *      pds1 = The GRIB1 Product Definition Section to print. (Input)
934  *   comment = A description about this element. See GRIB1_Table2LookUp (Input)
935  *    center = The Center that created the data (Input)
936  * subcenter = The Sub Center that created the data (Input)
937  *    f_unit = The unit conversion method used on the output data (Input)
938  *  unitName = The name of the output unit type. (Input)
939  *   convert = Conversion method used. (Input)
940  *
941  * FILES/DATABASES: None
942  *
943  * RETURNS: void
944  *
945  * HISTORY
946  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
947  *  10/2005 AAT: Adjusted to take center, subcenter as we moved that out of
948  *               the pdsG1 type.
949  *  11/2005 AAT: Added f_utit variable.
950  *
951  * NOTES
952  *****************************************************************************
953  */
PrintPDS1(pdsG1Type * pds1,char * comment,unsigned short int center,unsigned short int subcenter,sChar f_unit,char * unitName,int convert)954 static void PrintPDS1 (pdsG1Type *pds1, char *comment,
955                        unsigned short int center,
956                        unsigned short int subcenter, sChar f_unit,
957                        char *unitName, int convert)
958 {
959    char buffer[25];     /* Stores format of pds1->refTime. */
960    const char *ptr;
961 
962    Print ("PDS-S1", "Parameter Tables Version", Prt_D, pds1->mstrVersion);
963    ptr = centerLookup (center);
964    if (ptr != NULL) {
965       Print ("PDS-S1", "Originating center", Prt_DS, center, ptr);
966    } else {
967       Print ("PDS-S1", "Originating center", Prt_D, center);
968    }
969    ptr = subCenterLookup (center, subcenter);
970    if (ptr != NULL) {
971       Print ("PDS-S1", "Originating sub-center", Prt_DS, subcenter, ptr);
972    } else {
973       Print ("PDS-S1", "Originating sub-center", Prt_D, subcenter);
974    }
975    ptr = processLookup (center, pds1->genProcess);
976    if (ptr != NULL) {
977       Print ("PDS-S1", "Generation process", Prt_DS, pds1->genProcess, ptr);
978    } else {
979       Print ("PDS-S1", "Generation process", Prt_D, pds1->genProcess);
980    }
981    Print ("PDS-S1", "Grid Identification Number", Prt_D, pds1->gridID);
982    Print ("PDS-S1", "Indicator of parameter and units", Prt_DS, pds1->cat,
983           comment);
984    if (convert != UC_NONE) {
985       if (f_unit == 1) {
986          Print ("PDS-S1", "Output grid, (COMPUTED) english unit is", Prt_S,
987                 unitName);
988       } else if (f_unit == 2) {
989          Print ("PDS-S1", "Output grid, (COMPUTED) metric unit is", Prt_S,
990                 unitName);
991       }
992    }
993    Print ("PDS-S1", "Type of fixed surface", Prt_D, pds1->levelType);
994    Print ("PDS-S1", "Value of fixed surface", Prt_D, pds1->levelVal);
995 
996 /* strftime (buffer, 25, "%m/%d/%Y %H:%M:%S UTC", gmtime (&(pds1->refTime))); */
997    Clock_Print (buffer, 25, pds1->refTime, "%m/%d/%Y %H:%M:%S UTC", 0);
998 
999    Print ("PDS-S1", "Reference Time", Prt_S, buffer);
1000 
1001 /* strftime (buffer, 25, "%m/%d/%Y %H:%M:%S UTC",
1002              gmtime (&(pds1->validTime))); */
1003    Clock_Print (buffer, 25, pds1->validTime, "%m/%d/%Y %H:%M:%S UTC", 0);
1004 
1005    Print ("PDS-S1", "Valid Time", Prt_S, buffer);
1006 
1007 /* strftime (buffer, 25, "%m/%d/%Y %H:%M:%S UTC", gmtime (&(pds1->P1))); */
1008    Clock_Print (buffer, 25, pds1->P1, "%m/%d/%Y %H:%M:%S UTC", 0);
1009 
1010    Print ("PDS-S1", "P1 Time", Prt_S, buffer);
1011 
1012 /* strftime (buffer, 25, "%m/%d/%Y %H:%M:%S UTC", gmtime (&(pds1->P2))); */
1013    Clock_Print (buffer, 25, pds1->P2, "%m/%d/%Y %H:%M:%S UTC", 0);
1014 
1015    Print ("PDS-S1", "P2 Time", Prt_S, buffer);
1016    Print ("PDS-S1", "Time range indicator", Prt_D, pds1->timeRange);
1017    Print ("PDS-S1", "Number included in average", Prt_D, pds1->Average);
1018    Print ("PDS-S1", "Number missing from average or accumulation", Prt_D,
1019           pds1->numberMissing);
1020 
1021    if (pds1->f_hasEns) {
1022       Print ("PDS-S1", "Ensemble BitFlag (octet 29)", Prt_D,
1023              pds1->ens.BitFlag);
1024       Print ("PDS-S1", "Ensemble Application", Prt_D, pds1->ens.Application);
1025       Print ("PDS-S1", "Ensemble Type", Prt_D, pds1->ens.Type);
1026       Print ("PDS-S1", "Ensemble Number", Prt_D, pds1->ens.Number);
1027       Print ("PDS-S1", "Ensemble ProdID", Prt_D, pds1->ens.ProdID);
1028       Print ("PDS-S1", "Ensemble Smoothing", Prt_D, pds1->ens.Smooth);
1029    }
1030    if (pds1->f_hasProb) {
1031       Print ("PDS-S1", "Prob Category", Prt_D, pds1->prob.Cat);
1032       Print ("PDS-S1", "Prob Type", Prt_D, pds1->prob.Type);
1033       Print ("PDS-S1", "Prob lower", Prt_F, pds1->prob.lower);
1034       Print ("PDS-S1", "Prob upper", Prt_F, pds1->prob.upper);
1035    }
1036    if (pds1->f_hasCluster) {
1037       Print ("PDS-S1", "Cluster Ens Size", Prt_D, pds1->cluster.ensSize);
1038       Print ("PDS-S1", "Cluster Size", Prt_D, pds1->cluster.clusterSize);
1039       Print ("PDS-S1", "Cluster Number", Prt_D, pds1->cluster.Num);
1040       Print ("PDS-S1", "Cluster Method", Prt_D, pds1->cluster.Method);
1041       Print ("PDS-S1", "Cluster North Latitude", Prt_F, pds1->cluster.NorLat);
1042       Print ("PDS-S1", "Cluster South Latitude", Prt_F, pds1->cluster.SouLat);
1043       Print ("PDS-S1", "Cluster East Longitude", Prt_F, pds1->cluster.EasLon);
1044       Print ("PDS-S1", "Cluster West Longitude", Prt_F, pds1->cluster.WesLon);
1045       sprintf (buffer, "'%10s'", pds1->cluster.Member);
1046       Print ("PDS-S1", "Cluster Membership", Prt_S, buffer);
1047    }
1048 }
1049 
1050 /*****************************************************************************
1051  * PrintGDS() --
1052  *
1053  * Arthur Taylor / MDL
1054  *
1055  * PURPOSE
1056  *   To generate the message for the Grid Definition Section.
1057  *
1058  * ARGUMENTS
1059  *     gds = The gds structure to print. (Input)
1060  * version = The GRIB version number (so we know what type of projection) (In)
1061  *
1062  * FILES/DATABASES: None
1063  *
1064  * RETURNS: int (could use errSprintf())
1065  *  0 if no error.
1066  * -1 if asked to print a map projection that we don't support.
1067  *
1068  * HISTORY
1069  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1070  *   4/2003 AAT: Switched from sect3 to gds
1071  *   5/2003 AAT: Since the number for ProjectionType changed from GRIB1 to
1072  *          GRIB2, we use the GRIB2 internally, but for meta data we want to
1073  *          print the appropriate one.
1074  *   5/2003 AAT: Decided to have 1,1 be lower left corner in .shp files.
1075  *  10/2004 AAT: Added TDLP support.
1076  *
1077  * NOTES
1078  * Need to add support for GS3_ORTHOGRAPHIC = 90,
1079  * GS3_EQUATOR_EQUIDIST = 110, GS3_AZIMUTH_RANGE = 120
1080  *****************************************************************************
1081  */
PrintGDS(gdsType * gds,int version)1082 static int PrintGDS (gdsType *gds, int version)
1083 {
1084    /* Based on Grib2 Code Table 3.1 */
1085    static const char *table31[] = { "Latitude/Longitude", "Mercator",
1086       "Polar Stereographic", "Lambert Conformal",
1087       "Space view perspective orthographic",
1088       "Equatorial azimuthal equidistant projection",
1089       "Azimuth-range projection"
1090    };
1091    char buffer[50];     /* Temporary storage for info about scan flag. */
1092 
1093    Print ("GDS", "Number of Points", Prt_D, gds->numPts);
1094    switch (gds->projType) {
1095       case GS3_LATLON: /* 0 */
1096          if (version == 1) {
1097             Print ("GDS", "Projection Type", Prt_DS, GB1S2_LATLON,
1098                    table31[0]);
1099          } else {
1100             Print ("GDS", "Projection Type", Prt_DS, gds->projType,
1101                    table31[0]);
1102          }
1103          break;
1104       case GS3_MERCATOR: /* 10 */
1105          if (version == 1) {
1106             Print ("GDS", "Projection Type", Prt_DS, GB1S2_MERCATOR,
1107                    table31[1]);
1108          } else if (version == -1) {
1109             Print ("GDS", "Projection Type", Prt_DS, TDLP_MERCATOR,
1110                    table31[1]);
1111          } else {
1112             Print ("GDS", "Projection Type", Prt_DS, gds->projType,
1113                    table31[1]);
1114          }
1115          break;
1116       case GS3_POLAR:  /* 20 */
1117          if (version == 1) {
1118             Print ("GDS", "Projection Type", Prt_DS, GB1S2_POLAR, table31[2]);
1119          } else if (version == -1) {
1120             Print ("GDS", "Projection Type", Prt_DS, TDLP_POLAR, table31[2]);
1121          } else {
1122             Print ("GDS", "Projection Type", Prt_DS, gds->projType,
1123                    table31[2]);
1124          }
1125          break;
1126       case GS3_LAMBERT: /* 30 */
1127          if (version == 1) {
1128             Print ("GDS", "Projection Type", Prt_DS, GB1S2_LAMBERT,
1129                    table31[3]);
1130          } else if (version == -1) {
1131             Print ("GDS", "Projection Type", Prt_DS, TDLP_LAMBERT,
1132                    table31[3]);
1133          } else {
1134             Print ("GDS", "Projection Type", Prt_DS, gds->projType,
1135                    table31[3]);
1136          }
1137          break;
1138 /*
1139  * The following lines were removed until such time that the rest of this
1140  * procedure can properly handle these three projection types.
1141  *
1142       case GS3_ORTHOGRAPHIC:  * 90 *
1143          Print ("GDS", "Projection Type", Prt_DS, gds->projType, table31[4]);
1144          break;
1145       case GS3_EQUATOR_EQUIDIST:  * 110 *
1146          Print ("GDS", "Projection Type", Prt_DS, gds->projType, table31[5]);
1147          break;
1148       case GS3_AZIMUTH_RANGE:  * 120 *
1149          Print ("GDS", "Projection Type", Prt_DS, gds->projType, table31[6]);
1150          break;
1151 */
1152       default:
1153          Print ("GDS", "Projection Type", Prt_D, gds->projType);
1154          errSprintf ("Un-supported Map Projection %d\n", gds->projType);
1155          return -1;
1156    }
1157    if (gds->f_sphere) {
1158       Print ("GDS", "Shape of Earth", Prt_S, "sphere");
1159       Print ("GDS", "Radius", Prt_FS, gds->majEarth, "km");
1160    } else {
1161       Print ("GDS", "Shape of Earth", Prt_S, "oblate spheroid");
1162       Print ("GDS", "semi Major axis", Prt_FS, gds->majEarth, "km");
1163       Print ("GDS", "semi Minor axis", Prt_FS, gds->minEarth, "km");
1164    }
1165    Print ("GDS", "Nx (Number of points on parallel)", Prt_D, gds->Nx);
1166    Print ("GDS", "Ny (Number of points on meridian)", Prt_D, gds->Ny);
1167    Print ("GDS", "Lat1", Prt_F, gds->lat1);
1168    Print ("GDS", "Lon1", Prt_F, gds->lon1);
1169    if (gds->resFlag & GRIB2BIT_5) {
1170       Print ("GDS", "u/v vectors relative to", Prt_S, "grid");
1171    } else {
1172       Print ("GDS", "u/v vectors relative to", Prt_S, "easterly/northerly");
1173    }
1174    if (gds->projType == GS3_LATLON) {
1175       Print ("GDS", "Lat2", Prt_F, gds->lat2);
1176       Print ("GDS", "Lon2", Prt_F, gds->lon2);
1177       Print ("GDS", "Dx", Prt_FS, gds->Dx, "degrees");
1178       Print ("GDS", "Dy", Prt_FS, gds->Dy, "degrees");
1179    } else if (gds->projType == GS3_MERCATOR) {
1180       Print ("GDS", "Lat2", Prt_F, gds->lat2);
1181       Print ("GDS", "Lon2", Prt_F, gds->lon2);
1182       Print ("GDS", "Dx", Prt_FS, gds->Dx, "m");
1183       Print ("GDS", "Dy", Prt_FS, gds->Dy, "m");
1184    } else if ((gds->projType == GS3_POLAR)
1185               || (gds->projType == GS3_LAMBERT)) {
1186       Print ("GDS", "Dx", Prt_FS, gds->Dx, "m");
1187       Print ("GDS", "Dy", Prt_FS, gds->Dy, "m");
1188    }
1189    /* For scan mode... The user of this data doesn't necesarily care how it
1190     * was stored in the Grib2 grid (ie gds->scan), they just care about how
1191     * the data they are accessing is scanned (ie scan=0000) */
1192    sprintf (buffer, "%d%d%d%d", ((gds->scan & GRIB2BIT_1) / GRIB2BIT_1),
1193             ((gds->scan & GRIB2BIT_2) / GRIB2BIT_2),
1194             ((gds->scan & GRIB2BIT_3) / GRIB2BIT_3),
1195             ((gds->scan & GRIB2BIT_4) / GRIB2BIT_4));
1196    Print ("GDS", "Input GRIB2 grid, scan mode", Prt_DS, gds->scan, buffer);
1197 /*
1198    Print ("GDS", "Output grid, scan mode", Prt_DS, 0, "0000");
1199    Print ("GDS", "Output grid, scan i/x direction", Prt_S, "positive");
1200    Print ("GDS", "Output grid, scan j/y direction", Prt_S, "negative");
1201 */
1202    Print ("GDS", "Output grid, scan mode", Prt_DS, 64, "0100");
1203    Print ("GDS", "(.flt file grid), scan mode", Prt_DS, 0, "0000");
1204    Print ("GDS", "Output grid, scan i/x direction", Prt_S, "positive");
1205    Print ("GDS", "Output grid, scan j/y direction", Prt_S, "positive");
1206    Print ("GDS", "(.flt file grid), scan j/y direction", Prt_S, "negative");
1207    Print ("GDS", "Output grid, consecutive points in", Prt_S,
1208           "i/x direction");
1209    Print ("GDS", "Output grid, adjacent rows scan in", Prt_S,
1210           "same direction");
1211 
1212    /* Meshlat/orient lon/scale lat have no meaning for lat/lon grids. */
1213    if (gds->projType != GS3_LATLON) {
1214       Print ("GDS", "MeshLat", Prt_F, gds->meshLat);
1215       Print ("GDS", "OrientLon", Prt_F, gds->orientLon);
1216       if ((gds->projType == GS3_POLAR) || (gds->projType == GS3_LAMBERT)) {
1217          if (gds->center & GRIB2BIT_1) {
1218             Print ("GDS", "Which pole is on the plane", Prt_S, "South");
1219          } else {
1220             Print ("GDS", "Which pole is on the plane", Prt_S, "North");
1221          }
1222          if (gds->center & GRIB2BIT_2) {
1223             Print ("GDS", "bi-polar projection", Prt_S, "Yes");
1224          } else {
1225             Print ("GDS", "bi-polar projection", Prt_S, "No");
1226          }
1227       }
1228       Print ("GDS", "Tangent Lat1", Prt_F, gds->scaleLat1);
1229       Print ("GDS", "Tangent Lat2", Prt_F, gds->scaleLat2);
1230       Print ("GDS", "Southern Lat", Prt_F, gds->southLat);
1231       Print ("GDS", "Southern Lon", Prt_F, gds->southLon);
1232    }
1233    return 0;
1234 }
1235 
1236 /*****************************************************************************
1237  * PrintGridAttrib() --
1238  *
1239  * Arthur Taylor / MDL
1240  *
1241  * PURPOSE
1242  *   To generate the message for the various attributes of the grid.
1243  *
1244  * ARGUMENTS
1245  *  attrib = The Grid Attribute structure to print. (Input)
1246  * decimal = How many decimals to round to. (Input)
1247  *
1248  * FILES/DATABASES: None
1249  *
1250  * RETURNS: void
1251  *
1252  * HISTORY
1253  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1254  *   5/2003 AAT: Added rounding to decimal.
1255  *
1256  * NOTES
1257  *****************************************************************************
1258  */
PrintGridAttrib(gridAttribType * attrib,sChar decimal)1259 static void PrintGridAttrib (gridAttribType *attrib, sChar decimal)
1260 {
1261    /* Based on Grib2 Code Table 5.0 */
1262    static const char *table50[] = {
1263       "Grid point data - simple packing", "Matrix value - simple packing",
1264       "Grid point data - complex packing",
1265       "Grid point data - complex packing and spatial differencing"
1266    };
1267 
1268    /* Based on Grib2 Code Table 5.1 */
1269    static const char *table51[] = { "Floating point", "Integer" };
1270 
1271    /* Based on Grib2 Code Table 5.5 */
1272    static const char *table55[] = {
1273       "No explicit missing value included with data",
1274       "Primary missing value included with data",
1275       "Primary and Secondary missing values included with data"
1276    };
1277 
1278    if ((attrib->packType == GS5_JPEG2000) ||
1279        (attrib->packType == GS5_JPEG2000_ORG)) {
1280       Print ("Info", "Packing that was used", Prt_DS, attrib->packType,
1281              "JPEG 2000");
1282    } else if ((attrib->packType == GS5_PNG) ||
1283               (attrib->packType == GS5_PNG_ORG)) {
1284       Print ("Info", "Packing that was used", Prt_DS, attrib->packType,
1285              "Portable Network Graphics (PNG)");
1286    } else {
1287       Print ("Info", "Packing that was used", Prt_DS, attrib->packType,
1288              Lookup (table50, sizeof (table50), attrib->packType));
1289    }
1290    /* Added next two 1/27/2006 because of questions from Val. */
1291    Print ("Info", "Decimal Scale Factor", Prt_D, attrib->DSF);
1292    Print ("Info", "Binary Scale Factor", Prt_D, attrib->ESF);
1293    Print ("Info", "Original field type", Prt_DS, attrib->fieldType,
1294           Lookup (table51, sizeof (table51), attrib->fieldType));
1295    Print ("Info", "Missing value management", Prt_DS, attrib->f_miss,
1296           Lookup (table55, sizeof (table55), attrib->f_miss));
1297    if (attrib->f_miss == 1) {
1298       Print ("Info", "Primary missing value", Prt_F,
1299              myRound (attrib->missPri, decimal));
1300    } else if (attrib->f_miss == 2) {
1301       Print ("Info", "Primary missing value", Prt_F,
1302              myRound (attrib->missPri, decimal));
1303       Print ("Info", "Secondary missing value", Prt_F,
1304              myRound (attrib->missSec, decimal));
1305    }
1306    Print ("Info", "Detected number of Missing", Prt_D, attrib->numMiss);
1307    if (attrib->f_maxmin) {
1308       Print ("Info", "Field minimum value", Prt_F,
1309              myRound (attrib->min, decimal));
1310       Print ("Info", "Field maximum value", Prt_F,
1311              myRound (attrib->max, decimal));
1312    }
1313 }
1314 
1315 /*****************************************************************************
1316  * MetaPrintGDS() --
1317  *
1318  * Arthur Taylor / MDL
1319  *
1320  * PURPOSE
1321  *   To generate a message specific for the GDS.  Basically a wrapper for
1322  * PrintGDS and Print.
1323  *
1324  * ARGUMENTS
1325  * gds = The Grid Definition Section to generate the message for. (Input)
1326  * version = The GRIB version number (so we know what type of projection) (In)
1327  * ans = The resulting message. Up to caller to free. (Output)
1328  *
1329  * FILES/DATABASES: None
1330  *
1331  * RETURNS: int (could use errSprintf())
1332  *  0 if no error.
1333  * -1 if asked to print a map projection that we don't support.
1334  * -2 if asked to print data for a template that we don't support.
1335  *
1336  * HISTORY
1337  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
1338  *   5/2003 AAT: Commented out.  Purpose was mainly for debugging degrib1.c,
1339  *               which is now working.
1340  *
1341  * NOTES
1342  *****************************************************************************
1343  */
MetaPrintGDS(gdsType * gds,int version,char ** ans)1344 int MetaPrintGDS (gdsType *gds, int version, char **ans)
1345 {
1346    int ierr;            /* The error code of a called routine */
1347 
1348    if ((ierr = PrintGDS (gds, version)) != 0) {
1349       *ans = Print (NULL, NULL, Prt_NULL);
1350       preErrSprintf ("Print error Section 3\n");
1351       return ierr;
1352    }
1353    *ans = Print (NULL, NULL, Prt_NULL);
1354    return 0;
1355 }
1356 
1357 /*****************************************************************************
1358  * MetaPrint() --
1359  *
1360  * Arthur Taylor / MDL
1361  *
1362  * PURPOSE
1363  *   To generate the meta file message.
1364  *
1365  * ARGUMENTS
1366  *    meta = The meta file structure to generate the message for. (Input)
1367  *     ans = The resulting message. Up to caller to free. (Output)
1368  * decimal = How many decimals to round to. (Input)
1369  *  f_unit = 0 (GRIB unit), 1 (english), 2 (metric) (Input)
1370  *
1371  * FILES/DATABASES: None
1372  *
1373  * RETURNS: int (could use errSprintf())
1374  *  0 if no error.
1375  * -1 if asked to print a map projection that we don't support.
1376  * -2 if asked to print data for a template that we don't support.
1377  *
1378  * HISTORY
1379  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
1380  *   5/2003 AAT: Added rounding to decimal.
1381  *
1382  * NOTES
1383  *****************************************************************************
1384  */
MetaPrint(grib_MetaData * meta,char ** ans,sChar decimal,sChar f_unit)1385 int MetaPrint (grib_MetaData *meta, char **ans, sChar decimal, sChar f_unit)
1386 {
1387    int ierr;            /* The error code of a called routine */
1388 
1389    if (meta->GribVersion == 1) {
1390       PrintPDS1 (&(meta->pds1), meta->comment, meta->center,
1391                  meta->subcenter, f_unit, meta->unitName, meta->convert);
1392    } else if (meta->GribVersion == -1) {
1393       PrintPDS_TDLP (&(meta->pdsTdlp));
1394    } else {
1395       if ((ierr = PrintPDS2 (meta, f_unit)) != 0) {
1396          *ans = Print (NULL, NULL, Prt_NULL);
1397          preErrSprintf ("Print error in PDS for GRIB2\n");
1398          return ierr;
1399       }
1400    }
1401    if ((ierr = PrintGDS (&(meta->gds), meta->GribVersion)) != 0) {
1402       *ans = Print (NULL, NULL, Prt_NULL);
1403       preErrSprintf ("Print error Section 3\n");
1404       return ierr;
1405    }
1406    PrintGridAttrib (&(meta->gridAttrib), decimal);
1407    *ans = Print (NULL, NULL, Prt_NULL);
1408    return 0;
1409 }
1410