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