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