NCEPLIBS-g2c  1.8.0
g2cdegrib2.c
Go to the documentation of this file.
1 
8 #include "grib2_int.h"
9 #include <stdarg.h>
10 #include <math.h>
11 
14 
17 
19 #define G2C_MAX_TYPE_OF_FIXED_SURFACE_LEN 40
20 
21 #define G2C_DATE_TIME_LEN 25
48 int
49 g2c_get_datetime(int ipdtn, long long int *ipdtmpl, short year, unsigned char month, unsigned char day,
50  unsigned char hour, unsigned char minute, unsigned char second, char *tabbrev)
51 {
52  int iutpos, iutpos2, iunit, iunit2;
53  char tunit[G2C_DATE_TIME_LEN], tunit2[G2C_DATE_TIME_LEN];
54  char reftime[G2C_DATE_TIME_LEN], endtime[G2C_DATE_TIME_LEN], tmpval2[G2C_DATE_TIME_LEN];
55  int itemp, itemp2, is;
56  /* character(len = 16) :: reftime, endtime */
57  /* character(len = 10) :: tmpval, tmpval2 */
58  /* character(len = 10) :: tunit, tunit2 */
59  /* integer, dimension(200) :: ipos, ipos2 */
60  /* integer :: is, itemp, itemp2, iunit, iuni2t2, iunit2, iutpos, iutpos2, j */
61 
62  /* data ipos /7*0, 16, 23, 17, 19, 18, 32, 31, 27*0, 17, 20, 0, 0, 22, & */
63  /* 25, 43*0, 23, 109*0/ */
64 
65  int ipos[200] = {
66  0, 0, 0, 0, 0, 0, 0, 16, 23, 17, 19, 18, 32, 31, 0, 0, 0, 0, 0, 0,
67  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68  0, 17, 20, 0, 0, 22, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
76  };
77  /* data ipos2 /7*0, 26, 33, 27, 29, 28, 42, 41, 27*0, 22, 30, 0, 0, 32, & */
78  /* 35, 43*0, 33, 109*0/ */
79 
80  int ipos2[200] = {
81  0, 0, 0, 0, 0, 0, 0, 26, 33, 27,
82  29, 28, 42, 41, 0, 0, 0, 0, 0, 0,
83  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85  0, 22, 30, 0, 0, 32, 35, 0, 0, 0,
86  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90  33, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
101  };
102  /* tabbrev(1:100) = " " */
103 
104  /* Check inputs. */
105  assert(ipdtn >= 0 && ipdtmpl && tabbrev);
106 
107  /* The unit of time range is stored in the product template, but
108  * stored at different places for different template numbers. Find
109  * where it is stored for this product template number. */
110  if (ipdtn <= 15 || ipdtn == 32 || ipdtn == 50 || ipdtn == 51 || ipdtn == 91)
111  iutpos = 7;
112  else if (ipdtn >= 40 && ipdtn <= 43)
113  iutpos = 8;
114  else if (ipdtn >= 44 && ipdtn <= 47)
115  iutpos = 13;
116  else if (ipdtn == 48)
117  iutpos = 18;
118  else if (ipdtn == 52)
119  iutpos = 10;
120  else
121  iutpos = 7;
122 
123  /* Determine first unit of time range. */
124  switch (ipdtmpl[iutpos])
125  {
126  case 0:
127  strcpy(tunit, "minute");
128  iunit = 1;
129  break;
130  case 1:
131  strcpy(tunit, "hour");
132  iunit = 1;
133  break;
134  case 2:
135  strcpy(tunit, "day");
136  iunit = 1;
137  break;
138  case 3:
139  strcpy(tunit, "month");
140  iunit = 1;
141  break;
142  case 4:
143  strcpy(tunit, "year");
144  iunit = 1;
145  break;
146  case 10:
147  strcpy(tunit, "hour");
148  iunit = 3;
149  break;
150  case 11:
151  strcpy(tunit, "hour");
152  iunit = 6;
153  break;
154  default:
155  strcpy(tunit, "hour");
156  iunit = 1;
157  }
158 
159  /* Determine second unit of time range. */
160  if (ipdtn > 0)
161  iutpos2 = ipos2[ipdtn - 1];
162  else
163  iutpos2 = 0;
164  switch (ipdtmpl[iutpos2])
165  {
166  case 0:
167  strcpy(tunit2, "minute");
168  iunit2 = 1;
169  break;
170  case 1:
171  strcpy(tunit2, "hour");
172  iunit2 = 1;
173  break;
174  case 2:
175  strcpy(tunit2, "day");
176  iunit2 = 1;
177  break;
178  case 3:
179  strcpy(tunit2, "month");
180  iunit2 = 1;
181  break;
182  case 4:
183  strcpy(tunit2, "year");
184  iunit2 = 1;
185  break;
186  case 10:
187  strcpy(tunit2, "hour");
188  iunit2 = 3;
189  break;
190  case 11:
191  strcpy(tunit2, "hour");
192  iunit2 = 6;
193  break;
194  default:
195  strcpy(tunit2, "hour");
196  iunit2 = 1;
197  }
198 
199  /* Write a string with the date and time from section 1 of the message. */
200  sprintf(reftime, "%4.4d%2.2d%2.2d%2.2d:%2.2d:%2.2d", year, month, day, hour, minute, second);
201 
202  itemp = abs(ipdtmpl[iutpos + 1]) * iunit;
203 
204  /* write(tmpval, '(I0)') itemp */
205 
206  sprintf(tabbrev, "valid at %lld", ipdtmpl[iutpos + 1]);
207  /* write(tabbrev, fmt = '("valid at ", i4)') ipdtmpl(iutpos + 1) */
208 
209  /* Determine Reference Time: Year, Month, Day, Hour, Minute, Second. */
210 
211  if ((ipdtn >= 0 && ipdtn <= 7) || ipdtn == 15 || ipdtn == 20 || (ipdtn >= 30 && ipdtn <= 32) || ipdtn == 40 ||
212  ipdtn == 41 || ipdtn == 44 || ipdtn == 45 || ipdtn == 48 || (ipdtn >= 50 && ipdtn <= 52)) /* Point in time. */
213  {
214  sprintf(tabbrev, "valid %d %s after %s", itemp, tunit, reftime);
215  }
216  else
217  {
218  is = ipos[ipdtn - 1] - 1; /* Continuous time interval. */
219  sprintf(endtime, "%4.4d%2.2d%2.2d%2.2d:%2.2d:%2.2d", (int)ipdtmpl[is], (int)ipdtmpl[is + 1],
220  (int)ipdtmpl[is + 2], (int)ipdtmpl[is + 3], (int)ipdtmpl[is + 4], (int)ipdtmpl[is + 5]);
221  /* write(endtime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (ipdtmpl(j), j = is, is + 5) */
222  itemp2 = abs(ipdtmpl[iutpos2]) * iunit2;
223  itemp2 = itemp + itemp2;
224  sprintf(tmpval2, "%d", itemp2);
225  if (ipdtn == 8 && ipdtmpl[8] < 0)
226  {
227  /* tabbrev = "(" // trim(tmpval) // " -" // trim(tmpval2) // ") valid " // trim(tmpval) // " " // trim(tunit) // " before " // reftime // " to " //endtime */
228  sprintf(tabbrev, "(%d -%d) valid %d %s before %s to %s", itemp, itemp2, itemp, tunit, reftime, endtime);
229  }
230  else if ((ipdtn >= 8 && ipdtn <= 14) || (ipdtn >= 42 && ipdtn <= 47) ||
231  ipdtn == 91) /* Continuous time interval */
232  {
233  /* write(tmpval2, '(I0)') itemp2 */
234  /* tabbrev = "(" // trim(tmpval) // " -" // trim(tmpval2) // " hr) valid " // trim(tmpval) // " " // trim(tunit) // " after " // reftime // " to " // endtime */
235  sprintf(tabbrev, "(%d -%d hr) valid %d %s after %s to %s", itemp, itemp2, itemp, tunit, reftime, endtime);
236  }
237  }
238 
239  return G2C_NOERROR;
240 }
241 
255 static int
256 format_level(char *cbuf, int ival, int scale)
257 {
258  char tmpcbuf[37];
259 
260  assert(cbuf);
261 
262  if (!scale)
263  sprintf(cbuf, "%d", ival);
264  else
265  {
266  float rval;
267 
268  rval = (float)ival * pow(10, -1 * scale);
269  if (rval == (int)rval)
270  {
271  /* This adds a space in front of the number, to match
272  * behavor of the Fortran degrib2 utility. */
273  sprintf(cbuf, " %d", (int)rval);
274  }
275  else
276  {
277  char fmt[37];
278  sprintf(fmt, "%s%d%s", "%.", (int)abs(scale), "f");
279  sprintf(tmpcbuf, fmt, rval);
280  strcpy(cbuf, &tmpcbuf[1]);
281  }
282 
283  }
284  return G2C_NOERROR;
285 }
286 
311 int
312 g2c_get_level_desc(int ipdtn, long long int *ipdtmpl, char *level_desc)
313 {
314  int ipos;
315  char tmpval1[37];
316  char tmpval2[37];
317  int ret;
318 
319  /* Check inputs. */
320  assert(ipdtn >= 0 && ipdtmpl && level_desc);
321 
322  /* Use the template number to determine which element of the
323  * product template array holds the "Type of first fixed surface"
324  * value (which will be stored in ipos). */
325  if (ipdtn <= 15)
326  ipos = 9;
327  else if (ipdtn >= 40 && ipdtn <= 43)
328  ipos = 10;
329  else if (ipdtn >= 44 && ipdtn <= 47)
330  ipos = 15;
331  else if (ipdtn == 48)
332  ipos = 20;
333  else if (ipdtn >= 50 && ipdtn <= 51)
334  ipos = 9;
335  else if (ipdtn == 52)
336  ipos = 12;
337  else if (ipdtn == 91)
338  ipos = 9;
339  else
340  ipos = 9;
341 
342  /* Pressure Level. */
343  if (ipdtmpl[ipos] == 100 && ipdtmpl[ipos + 3] == 255)
344  {
345  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1] + 2)))
346  return ret;
347  sprintf(level_desc, "%s %s", tmpval1, "mb");
348  }
349  /* Pressure Layer. */
350  else if (ipdtmpl[ipos] == 100 && ipdtmpl[ipos + 3] == 100)
351  {
352  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1] + 2)))
353  return ret;
354  if ((ret = format_level(tmpval2, ipdtmpl[ipos + 5], ipdtmpl[ipos + 4] + 2)))
355  return ret;
356  sprintf(level_desc, "%s - %s mb", tmpval1, tmpval2);
357  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1) + 2) */
358  /* call frmt(tmpval2, ipdtmpl(ipos + 5), ipdtmpl(ipos + 4) + 2) */
359  /* level_desc = trim(tmpval1)//" - "//trim(tmpval2)//" mb" */
360  }
361  else if (ipdtmpl[ipos] == 101)
362  {
363  strcpy(level_desc, " Mean Sea Level");
364  }
365  /* Altitude above MSL. */
366  else if (ipdtmpl[ipos] == 102 && ipdtmpl[ipos + 3] == 255)
367  {
368  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
369  return ret;
370  sprintf(level_desc, "%s %s", tmpval1, "m above MSL");
371  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
372  /* level_desc = trim(tmpval1)//" m above MSL" */
373  }
374  /* Height above Ground. */
375  else if (ipdtmpl[ipos] == 103 && ipdtmpl[ipos + 3] == 255)
376  {
377  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
378  /* level_desc = trim(tmpval1)//" m above ground" */
379  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
380  return ret;
381  sprintf(level_desc, "%s %s", tmpval1, "m above ground");
382  }
383  /* Height above Ground. */
384  else if (ipdtmpl[ipos] == 103 && ipdtmpl[ipos + 3] == 103)
385  {
386  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
387  return ret;
388  if ((ret = format_level(tmpval2, ipdtmpl[ipos + 5], ipdtmpl[ipos + 4])))
389  return ret;
390  sprintf(level_desc, "%s - %s m AGL", tmpval1, tmpval2);
391  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
392  /* call frmt(tmpval2, ipdtmpl(ipos + 5), ipdtmpl(ipos + 4)) */
393  /* level_desc = trim(tmpval1)//" - "//trim(tmpval2)//" m AGL" */
394  }
395  /* Sigma Level. */
396  else if (ipdtmpl[ipos] == 104 && ipdtmpl[ipos + 3] == 255)
397  {
398  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
399  return ret;
400  sprintf(level_desc, "%s %s", tmpval1, "sigma");
401  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
402  /* level_desc = trim(tmpval1)//" sigma" */
403  }
404  /* Sigma Layer. */
405  else if (ipdtmpl[ipos] == 104 && ipdtmpl[ipos + 3] == 104)
406  {
407  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
408  return ret;
409  if ((ret = format_level(tmpval2, ipdtmpl[ipos + 5], ipdtmpl[ipos + 4])))
410  return ret;
411  sprintf(level_desc, "%s - %s sigma", tmpval1, tmpval2);
412  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
413  /* call frmt(tmpval2, ipdtmpl(ipos + 5), ipdtmpl(ipos + 4)) */
414  /* level_desc = trim(tmpval1)//" - "//trim(tmpval2)//" sigma" */
415  }
416  /* Hybrid Level. */
417  else if (ipdtmpl[ipos] == 105 && ipdtmpl[ipos + 3] == 255)
418  {
419  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
420  return ret;
421  sprintf(level_desc, "%s %s", tmpval1, "hybrid lvl");
422  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
423  /* level_desc = trim(tmpval1)//" hybrid lvl" */
424  }
425  /* Hybrid Level. */
426  else if (ipdtmpl[ipos] == 105 && ipdtmpl[ipos + 3] == 105)
427  {
428  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
429  return ret;
430  if ((ret = format_level(tmpval2, ipdtmpl[ipos + 5], ipdtmpl[ipos + 4])))
431  return ret;
432  sprintf(level_desc, "%s - %s hybrid lvl", tmpval1, tmpval2);
433  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
434  /* call frmt(tmpval2, ipdtmpl(ipos + 5), ipdtmpl(ipos + 4)) */
435  /* level_desc = trim(tmpval1)//" - "//trim(tmpval2)//" hybrid lvl" */
436  }
437  /* Depth Below Land Sfc. */
438  else if (ipdtmpl[ipos] == 106 && ipdtmpl[ipos + 3] == 255)
439  {
440  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
441  return ret;
442  sprintf(level_desc, "%s %s", tmpval1, "m below land");
443  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
444  /* level_desc = trim(tmpval1)//" m below land" */
445  }
446  /* Depth Below Land Sfc Layer. */
447  else if (ipdtmpl[ipos] == 106 && ipdtmpl[ipos + 3] == 106)
448  {
449  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
450  return ret;
451  if ((ret = format_level(tmpval2, ipdtmpl[ipos + 5], ipdtmpl[ipos + 4])))
452  return ret;
453  sprintf(level_desc, "%s - %s m DBLY", tmpval1, tmpval2);
454  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)) */
455  /* call frmt(tmpval2, ipdtmpl(ipos + 5), ipdtmpl(ipos + 4)) */
456  /* level_desc = trim(tmpval1)//" - "//trim(tmpval2)//" m DBLY" */
457  }
458  else if (ipdtmpl[ipos] == 107)
459  {
460  strcpy(level_desc, " Isentropic level");
461  }
462  /* Press Diff from Ground Layer. */
463  else if (ipdtmpl[ipos] == 108 && ipdtmpl[ipos + 3] == 108)
464  {
465  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1] + 2)))
466  return ret;
467  if ((ret = format_level(tmpval2, ipdtmpl[ipos + 5], ipdtmpl[ipos + 4] + 2)))
468  return ret;
469  sprintf(level_desc, "%s - %s mb SPDY", tmpval1, tmpval2);
470  /* write(tmpval1, *) ipdtmpl(ipos + 2)/100. */
471  /* write(tmpval2, *) ipdtmpl(ipos + 5)/100. */
472  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1) + 2) */
473  /* call frmt(tmpval2, ipdtmpl(ipos + 5), ipdtmpl(ipos + 4) + 2) */
474  /* level_desc = trim(tmpval1)//" - "//trim(tmpval2)//" mb SPDY" */
475  }
476  else if (ipdtmpl[ipos] == 110)
477  {
478  strcpy(level_desc, " Layer bet 2-hyb lvl");
479  }
480  /* Potential Vorticity Sfc. */
481  else if (ipdtmpl[ipos] == 109 && ipdtmpl[ipos + 3] == 255)
482  {
483  if ((ret = format_level(tmpval1, ipdtmpl[ipos + 2], ipdtmpl[ipos + 1])))
484  return ret;
485  sprintf(level_desc, "%s %s", tmpval1, "pv surface");
486  /* write(tmpval1, *) ipdtmpl(ipos + 2). */
487  /* call frmt(tmpval1, ipdtmpl(ipos + 2), ipdtmpl(ipos + 1)-6) */
488  /* level_desc = trim(tmpval1)//" pv surface" */
489  }
490  else if (ipdtmpl[ipos] == 111)
491  strcpy(level_desc, " Eta level");
492  else if (ipdtmpl[ipos] == 114)
493  strcpy(level_desc, " Layer bet. 2-isent.");
494  else if (ipdtmpl[ipos] == 117)
495  strcpy(level_desc, " Mixed layer depth");
496  else if (ipdtmpl[ipos] == 120)
497  strcpy(level_desc, " Layer bet. 2-Eta lvl");
498  else if (ipdtmpl[ipos] == 121)
499  strcpy(level_desc, " Layer bet. 2-isob.");
500  else if (ipdtmpl[ipos] == 125)
501  strcpy(level_desc, " Specified height lvl");
502  else if (ipdtmpl[ipos] == 126)
503  strcpy(level_desc, " Isobaric level");
504  else if (ipdtmpl[ipos] == 160)
505  strcpy(level_desc, " Depth below sea lvl");
506  else if (ipdtmpl[ipos] == 170)
507  strcpy(level_desc, " Ionospheric D-region lvl");
508  else if (ipdtmpl[ipos] == 1)
509  strcpy(level_desc, " Surface");
510  else if (ipdtmpl[ipos] == 2)
511  strcpy(level_desc, " Cloud base lvl");
512  else if (ipdtmpl[ipos] == 3)
513  strcpy(level_desc, " Cloud top lvl");
514  else if (ipdtmpl[ipos] == 4)
515  strcpy(level_desc, " 0 Deg Isotherm");
516  else if (ipdtmpl[ipos] == 5) /* from the surface. */
517  strcpy(level_desc, " Level of adiabatic" );
518  else if (ipdtmpl[ipos] == 6)
519  strcpy(level_desc, " Max wind lvl");
520  else if (ipdtmpl[ipos] == 7)
521  strcpy(level_desc, " Tropopause");
522  else if (ipdtmpl[ipos] == 8)
523  strcpy(level_desc, " Nom. top");
524  else if (ipdtmpl[ipos] == 9)
525  strcpy(level_desc, " Sea Bottom");
526  else if (ipdtmpl[ipos] == 10)
527  strcpy(level_desc, " Entire Atmosphere");
528  else if (ipdtmpl[ipos] == 11)
529  strcpy(level_desc, " Cumulonimbus Base");
530  else if (ipdtmpl[ipos] == 12)
531  strcpy(level_desc, " Cumulonimbus Top");
532  else if (ipdtmpl[ipos] == 20)
533  strcpy(level_desc, " Isothermal level");
534  else if (ipdtmpl[ipos] == 200)
535  strcpy(level_desc, " Entire Atmosphere");
536  else if (ipdtmpl[ipos] == 201)
537  strcpy(level_desc, " Entire ocean");
538  else if (ipdtmpl[ipos] == 204)
539  strcpy(level_desc, " Highest Frz. lvl");
540  else if (ipdtmpl[ipos] == 206)
541  strcpy(level_desc, " Grid scale cloud bl");
542  else if (ipdtmpl[ipos] == 207)
543  strcpy(level_desc, " Grid scale cloud tl");
544  else if (ipdtmpl[ipos] == 209)
545  strcpy(level_desc, " Boundary layer cbl");
546  else if (ipdtmpl[ipos] == 210)
547  strcpy(level_desc, " Boundary layer ctl");
548  else if (ipdtmpl[ipos] == 211)
549  strcpy(level_desc, " Boundary layer cl");
550  else if (ipdtmpl[ipos] == 212)
551  strcpy(level_desc, " Low cloud bot. lvl");
552  else if (ipdtmpl[ipos] == 213)
553  strcpy(level_desc, " Low cloud top lvl");
554  else if (ipdtmpl[ipos] == 214)
555  strcpy(level_desc, " Low cloud layer");
556  else if (ipdtmpl[ipos] == 215)
557  strcpy(level_desc, " Cloud ceiling");
558  else if (ipdtmpl[ipos] == 220)
559  strcpy(level_desc, " Planetary boundary");
560  else if (ipdtmpl[ipos] == 221)
561  strcpy(level_desc, " Layer 2 Hybrid lvl");
562  else if (ipdtmpl[ipos] == 222)
563  strcpy(level_desc, " Mid. cloud bot. lvl");
564  else if (ipdtmpl[ipos] == 223)
565  strcpy(level_desc, " Mid. cloud top lvl");
566  else if (ipdtmpl[ipos] == 224)
567  strcpy(level_desc, " Middle cloud layer");
568  else if (ipdtmpl[ipos] == 232)
569  strcpy(level_desc, " High cloud bot. lvl");
570  else if (ipdtmpl[ipos] == 233)
571  strcpy(level_desc, " High cloud top lvl");
572  else if (ipdtmpl[ipos] == 234)
573  strcpy(level_desc, " High cloud layer");
574  else if (ipdtmpl[ipos] == 235)
575  strcpy(level_desc, " Ocean Isotherm lvl");
576  else if (ipdtmpl[ipos] == 236)
577  strcpy(level_desc, " Layer 2-depth below");
578  else if (ipdtmpl[ipos] == 237)
579  strcpy(level_desc, " Bot. Ocean mix. lyr");
580  else if (ipdtmpl[ipos] == 238)
581  strcpy(level_desc, " Bot. Ocean iso. lyr");
582  else if (ipdtmpl[ipos] == 239) /* isothermal level (S26CY). */
583  strcpy(level_desc, " layer ocean sfc 26C" );
584  else if (ipdtmpl[ipos] == 240)
585  strcpy(level_desc, " Ocean Mixed Layer");
586  else if (ipdtmpl[ipos] == 241)
587  strcpy(level_desc, " Order Seq. Of Data");
588  else if (ipdtmpl[ipos] == 242)
589  strcpy(level_desc, " Con. cloud bot. lvl");
590  else if (ipdtmpl[ipos] == 243)
591  strcpy(level_desc, " Con. cloud top lvl");
592  else if (ipdtmpl[ipos] == 244)
593  strcpy(level_desc, " Conv. cloud layer");
594  else if (ipdtmpl[ipos] == 245)
595  strcpy(level_desc, " Lowest lvl wet bulb");
596  else if (ipdtmpl[ipos] == 246)
597  strcpy(level_desc, " Max. equi. potential");
598  else if (ipdtmpl[ipos] == 247)
599  strcpy(level_desc, " Equilibrium level");
600  else if (ipdtmpl[ipos] == 248)
601  strcpy(level_desc, " Shallow con. cld bl");
602  else if (ipdtmpl[ipos] == 249)
603  strcpy(level_desc, " Shallow con. cld tl");
604  else if (ipdtmpl[ipos] == 251)
605  strcpy(level_desc, " Deep conv. cld bl");
606  else if (ipdtmpl[ipos] == 252)
607  strcpy(level_desc, " Deep conv. cld tl");
608  else if (ipdtmpl[ipos] == 253) /* liquid water layer (LBLSW). */
609  strcpy(level_desc, " Lowest bot. lvl sup" );
610  else if (ipdtmpl[ipos] == 254) /* liquid water layer (HBLSW). */
611  strcpy(level_desc, " highest top lvl sup" );
612  else
613  {
614  sprintf(level_desc, " %4d (Unknown Lvl)", (int)ipdtmpl[ipos]);
615  /* write(level_desc, fmt = '(1x,I4," (Unknown Lvl)")') ipdtmpl[ipos] */
616  }
617 
618  return G2C_NOERROR;
619 }
620 
636 int
637 g2c_degrib2(int g2cid, const char *fileout)
638 {
639  FILE *f;
640  G2C_MESSAGE_INFO_T *msg;
641  int total_fields = 0;
642  int i;
643  int ret;
644 
645  /* Check inputs. */
646  if (g2cid < 0 || g2cid > G2C_MAX_FILES || g2c_file[g2cid].g2cid != g2cid)
647  return G2C_EBADID;
648  if (!fileout)
649  return G2C_EINVAL;
650 
651  LOG((2, "g2c_degrib2 fileout %s", fileout));
652 
653  /* Open output file. */
654  if (!(f = fopen(fileout, "w")))
655  return G2C_EFILE;
656 
657  /* Print a summary for each message in the file. */
658  for (msg = g2c_file[g2cid].msg; msg; msg = msg->next)
659  {
660  int fld;
661 
662  fprintf(f, "\n");
663  fprintf(f, " GRIB MESSAGE %ld starts at %ld\n", msg->msg_num + 1, msg->bytes_to_msg + 1);
664  fprintf(f, "\n");
665  fprintf(f, " SECTION 0: %d 2 %ld\n", msg->discipline, msg->bytes_in_msg);
666  fprintf(f, " SECTION 1: %d %d %d %d %d %d %d %d %d %d %d %d %d\n", msg->center, msg->subcenter,
667  msg->master_version, msg->local_version, msg->sig_ref_time, msg->year, msg->month, msg->day,
668  msg->hour, msg->minute, msg->second, msg->status, msg->type);
669  fprintf(f, " Contains %d Local Sections and %d data fields.\n", msg->num_local, msg->num_fields);
670  LOG((5, " SECTION 1: %d %d %d %d %d %d %d %d %d %d %d %d %d\n", msg->center, msg->subcenter,
671  msg->master_version, msg->local_version, msg->sig_ref_time, msg->year, msg->month, msg->day,
672  msg->hour, msg->minute, msg->second, msg->status, msg->type));
673 
674  /* For each field, print info. */
675  for (fld = 0; fld < msg->num_fields; fld++)
676  {
677  G2C_SECTION_INFO_T *sec, *sec2, *sec3, *sec5, *sec6;
678  G2C_SECTION3_INFO_T *sec3_info;
679  G2C_SECTION4_INFO_T *sec4_info;
680  G2C_SECTION5_INFO_T *sec5_info;
681  G2C_SECTION6_INFO_T *sec6_info;
682  char abbrev[G2C_MAX_NOAA_ABBREV_LEN + 1];
683  char level_desc[G2C_MAX_TYPE_OF_FIXED_SURFACE_LEN + 1];
684  char date_time[100 + 1];
685  float *data = NULL;
686  float total = 0.0, max = 0.0, min = 0.0;
687  int t;
688 
689  fprintf(f, "\n");
690  fprintf(f, " FIELD %d\n", fld + 1);
691  /* Only print section 0 and 1 data for the first field. */
692  if (fld == 0)
693  {
694  fprintf(f, " SECTION 0: %d 2\n", msg->discipline);
695  fprintf(f, " SECTION 1: %d %d %d %d %d %d %d %d %d %d %d %d %d\n", msg->center, msg->subcenter,
696  msg->master_version, msg->local_version, msg->sig_ref_time, msg->year, msg->month, msg->day,
697  msg->hour, msg->minute, msg->second, msg->status, msg->type);
698  }
699 
700  /* Find this field (a.k.a. product, a.k.a. section 4). */
701  for (sec = msg->sec; sec; sec = sec->next)
702  if (sec->sec_num == 4 && ((G2C_SECTION4_INFO_T *)(sec->sec_info))->field_num == fld)
703  break;
704  if (!sec)
705  return G2C_ENOSECTION;
706 
707  /* Is there a local section? */
708  for (sec2 = sec; sec2; sec2 = sec2->prev)
709  if (sec2->sec_num == 2)
710  break;
711  if (sec2)
712  fprintf(f, " SECTION 2: %d bytes\n", sec2->sec_len - 5); /* Subtract 4 byte seclen and 1 byte secnum. */
713 
714  /* Find the sec3 that applies to this field. */
715  for (sec3 = sec; sec3; sec3 = sec3->prev)
716  if (sec3->sec_num == 3)
717  break;
718  if (!sec3)
719  return G2C_ENOSECTION;
720 
721  /* Print the section 3 (grid) info. */
722  sec3_info = (G2C_SECTION3_INFO_T *)sec3->sec_info;
723  fprintf(f, " SECTION 3: %d %d %d %d %d\n", sec3_info->source_grid_def, sec3_info->num_data_points, sec3_info->num_opt,
724  sec3_info->interp_list, sec3_info->grid_def);
725  fprintf(f, " GRID TEMPLATE 3. %d : ", sec3_info->grid_def);
726  /* Cast to int to match behavior of degrib2.F90. */
727  for (t = 0; t < sec3->template_len; t++)
728  fprintf(f, " %d", (int)sec3->template[t]);
729  fprintf(f, "\n");
730  if (!sec3_info->optional)
731  fprintf(f, " NO Optional List Defining Number of Data Points.\n");
732 
733  /* Print the section 4 (product) info. */
734  sec4_info = (G2C_SECTION4_INFO_T *)sec->sec_info;
735  fprintf(f, " PRODUCT TEMPLATE 4. %d: ", sec4_info->prod_def);
736 
737  /* We can look up the parameter abbreviation with the
738  * discipline and the first two elements of the product
739  * template, which will be the category and product
740  * number. */
741  if ((ret = g2c_param_abbrev(msg->discipline, sec->template[0], sec->template[1], abbrev)))
742  return ret;
743  fprintf(f, "( PARAMETER = %-8s %d %lld %lld ) ", abbrev, sec->msg->discipline, sec->template[0],
744  sec->template[1]);
745  /* Cast to int to match behavior of degrib2.F90. */
746  for (t = 0; t < sec->template_len; t++)
747  fprintf(f, " %d", (int)sec->template[t]);
748  fprintf(f, "\n");
749 
750  /* Using the product template number, and the template
751  * values, we can figure out a description for the
752  * horizontal level description. */
753  if ((ret = g2c_get_level_desc(sec4_info->prod_def, sec->template, level_desc)))
754  return ret;
755 
756  /* The Fortran code for level descriptions puts a space in
757  * front of level descriptions that don't start with a
758  * number. It's annoying, but do it here to match the
759  * behavior of Fortran degrib2. */
760  /* if (!isdigit(level_desc[0])) */
761  /* { */
762  /* char tmp_level_desc[G2C_MAX_TYPE_OF_FIXED_SURFACE_LEN + 2]; */
763  /* sprintf(tmp_level_desc, " %s", level_desc); */
764  /* strcpy(level_desc, tmp_level_desc); */
765  /* } */
766 
767  /* Put the date/time in a formatted string. */
768  if ((ret = g2c_get_datetime(sec4_info->prod_def, sec->template, msg->year, msg->month, msg->day,
769  msg->hour, msg->minute, msg->second, date_time)))
770  return ret;
771  fprintf(f, " FIELD: %-8s%s %s\n", abbrev, level_desc, date_time);
772  if (!sec4_info->num_coord)
773  fprintf(f, " NO Optional Vertical Coordinate List.\n");
774 
775  /* Find the sec5 that applies to this field. */
776  for (sec5 = sec; sec5; sec5 = sec5->next)
777  if (sec5->sec_num == 5)
778  break;
779  if (!sec5)
780  return G2C_ENOSECTION;
781 
782  /* Find the sec6 that applies to this field, if any. */
783  for (sec6 = sec; sec6; sec6 = sec6->next)
784  if (sec6->sec_num == 6)
785  break;
786 
787  /* Section 5 and 6 info. */
788  sec5_info = (G2C_SECTION5_INFO_T *)sec5->sec_info;
789  sec6_info = (G2C_SECTION6_INFO_T *)sec6->sec_info;
790  if (sec6_info->indicator != 255)
791  fprintf(f, " Num. of Data Points = %d with BIT-MAP 0\n", sec5_info->num_data_points);
792  else
793  fprintf(f, " Num. of Data Points = %d NO BIT-MAP \n", sec5_info->num_data_points);
794  fprintf(f, " DRS TEMPLATE 5. %d : ", sec5_info->data_def);
795  /* Cast to int to match behavior of degrib2.F90. */
796  for (t = 0; t < sec5->template_len; t++)
797  fprintf(f, " %d", (int)sec5->template[t]);
798  fprintf(f, "\n");
799  fprintf(f, " Data Values:\n");
800  fprintf(f, " Num. of Data Points = %d Num. of Data Undefined = 0\n", sec5_info->num_data_points);
801 
802  /* Now read the data and find the min, max, and average values. */
803 
804  LOG((5, "sec5_info->num_data_points %ld", sec5_info->num_data_points));
805  if (sec5_info->num_data_points)
806  {
807  /* Allocate storage for the data. */
808  if (!(data = malloc(sec5_info->num_data_points * sizeof(float))))
809  return G2C_ERROR;
810  }
811 
812  /* Get the data from message 0, product 0. */
813  if ((ret = g2c_get_prod(g2cid, msg->msg_num, fld, NULL, data)))
814  return ret;
815 
816  /* Find min/max/avg. */
817  if (sec5_info->num_data_points)
818  {
819  max = data[0];
820  min = data[0];
821  total = data[0];
822  for (i = 1; i < sec5_info->num_data_points; i++)
823  {
824  total += data[i];
825  if (data[i] > max)
826  max = data[i];
827  if (data[i] < min)
828  min = data[i];
829  }
830  }
831  fprintf(f, "( PARM= %s ) : MIN=%25.8f AVE=%25.8f MAX=%25.8f\n",
832  abbrev, min, total/sec5_info->num_data_points, max);
833 
834  /* Free the data. */
835  if (sec5_info->num_data_points)
836  free(data);
837 
838  total_fields++;
839  }
840  }
841 
842  fprintf(f, " \n Total Number of Fields Found = %d\n", total_fields);
843 
844  /* Close output file. */
845  if (fclose(f))
846  return G2C_EFILE;
847 
848  return G2C_NOERROR;
849 }
#define G2C_DATE_TIME_LEN
Size of the date/time string.
Definition: g2cdegrib2.c:21
static int format_level(char *cbuf, int ival, int scale)
Format the level string for degrib2 output.
Definition: g2cdegrib2.c:256
#define G2C_MAX_TYPE_OF_FIXED_SURFACE_LEN
Maximum length of "Type of first fixed surface" string.
Definition: g2cdegrib2.c:19
int g2c_degrib2(int g2cid, const char *fileout)
Write a summary file like the degrib2 utility.
Definition: g2cdegrib2.c:637
G2C_FILE_INFO_T g2c_file[G2C_MAX_FILES+1]
Global file information.
Definition: g2cfile.c:10
int g2c_get_level_desc(int ipdtn, long long int *ipdtmpl, char *level_desc)
Determine the string that describes the level information, given the GRIB2 Product Definition Templat...
Definition: g2cdegrib2.c:312
int g2c_get_datetime(int ipdtn, long long int *ipdtmpl, short year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second, char *tabbrev)
Convert date and time from GRIB2 info to string output.
Definition: g2cdegrib2.c:49
G2C_CODE_TABLE_T * g2c_table
Pointer to the list of code tables.
Definition: g2cxml.c:15
int g2c_param_abbrev(int g2disc, int g2cat, int g2num, char *abbrev)
Get NOAA abbreviation for a GRIB2 parameter.
Definition: g2cparams.c:1091
int g2c_get_prod(int g2cid, int msg_num, int prod_num, int *num_data_points, float *data)
Read the data for a product.
Definition: g2cprod.c:28
#define G2C_MAX_FILES
Maximum number of open files.
Definition: grib2.h:289
#define G2C_ENOSECTION
Cannot find section.
Definition: grib2.h:506
#define G2C_EFILE
File I/O error.
Definition: grib2.h:497
#define G2C_ERROR
General error code, returned for some test errors.
Definition: grib2.h:492
#define G2C_EINVAL
Invalid input.
Definition: grib2.h:496
#define G2C_EBADID
Bad ID.
Definition: grib2.h:498
#define G2C_MAX_NOAA_ABBREV_LEN
Maximum length of a NOAA abbreviation of a parameter.
Definition: grib2.h:432
#define G2C_NOERROR
No error.
Definition: grib2.h:491
Header file with internal function prototypes NCEPLIBS-g2c library.
struct g2c_section_info * next
Pointer to next in list.
Definition: grib2_int.h:176
struct g2c_section_info * sec
List of section metadata.
Definition: grib2_int.h:162
short subcenter
Originating subcenter.
Definition: grib2_int.h:150
unsigned char master_version
GRIB master tables version number.
Definition: grib2_int.h:151
unsigned char type
Type of processed data in this GRIB message.
Definition: grib2_int.h:161
unsigned short grid_def
Grid definition template number (= N) (See Table 3.1).
Definition: grib2_int.h:199
unsigned char hour
Hour.
Definition: grib2_int.h:157
unsigned char minute
Minute.
Definition: grib2_int.h:158
unsigned int num_data_points
Number of data points.
Definition: grib2_int.h:196
unsigned short num_coord
Number of coordinate values after template.
Definition: grib2_int.h:209
int num_local
Number of local sections in the message.
Definition: grib2_int.h:141
unsigned char sig_ref_time
Significance of reference time.
Definition: grib2_int.h:153
unsigned char num_opt
Number of octets for optional list of numbers defining number of points.
Definition: grib2_int.h:197
unsigned char discipline
Discipline from section 0.
Definition: grib2_int.h:138
unsigned char interp_list
Interpetation of list of numbers defining number of points (See Table 3.11).
Definition: grib2_int.h:198
size_t bytes_in_msg
Number of bytes in this message.
Definition: grib2_int.h:137
struct g2c_section_info * prev
Pointer to previous in list.
Definition: grib2_int.h:177
int num_fields
Number of fields in the message.
Definition: grib2_int.h:140
unsigned char sec_num
Section number.
Definition: grib2_int.h:173
unsigned int num_data_points
Number of data points where one or more values are specified in Section 7 when a bit map is present,...
Definition: grib2_int.h:221
void * sec_info
Pointer to struct specific for section 3, 4, 5, 6, or 7.
Definition: grib2_int.h:175
unsigned char indicator
Bit map indicator.
Definition: grib2_int.h:231
unsigned int sec_len
Length of the section (in bytes).
Definition: grib2_int.h:171
short year
Year.
Definition: grib2_int.h:154
unsigned char status
Production Status of Processed data in the GRIB message.
Definition: grib2_int.h:160
#define LOG(e)
Ignore logging to stdout.
Definition: grib2_int.h:426
unsigned char second
Second.
Definition: grib2_int.h:159
unsigned char day
Day.
Definition: grib2_int.h:156
unsigned char source_grid_def
Source of grid definition (See Table 3.0).
Definition: grib2_int.h:195
int template_len
Number of entries in template.
Definition: grib2_int.h:179
unsigned char local_version
Version number of GRIB local tables used to augment Master Tables.
Definition: grib2_int.h:152
unsigned char month
Month.
Definition: grib2_int.h:155
size_t msg_num
Number of message in file (0-based).
Definition: grib2_int.h:135
unsigned short data_def
Data representation template number (See Table 5.0).
Definition: grib2_int.h:222
size_t bytes_to_msg
Number of bytes to skip in the file, to get to this message.
Definition: grib2_int.h:136
long long int * template
Grid, product, or data template.
Definition: grib2_int.h:178
struct g2c_message_info * next
Pointer to next in list.
Definition: grib2_int.h:164
G2C_MESSAGE_INFO_T * msg
Pointer to contianing message.
Definition: grib2_int.h:174
short center
Originating center.
Definition: grib2_int.h:149
int * optional
Optional list of numbers defining number of points.
Definition: grib2_int.h:200
unsigned short prod_def
Product definition template number (See Table 4.0).
Definition: grib2_int.h:210
A GRIB2 code table.
Definition: grib2_int.h:255
This is the information about each open file.
Definition: grib2_int.h:236
This is the information about each message.
Definition: grib2_int.h:134
Information about Section 3 GRID DEFINITION SECTION.
Definition: grib2_int.h:194
Information about Section 4 PRODUCT DEFINITION SECTION.
Definition: grib2_int.h:207
Information about Section 5 DATA REPRESENTATION SECTION.
Definition: grib2_int.h:217
Information about Section 6 BIT-MAP SECTION.
Definition: grib2_int.h:228
Information about a section 3 through 7 in a GRIB2 message.
Definition: grib2_int.h:169