OpenCPN Partial API docs
Loading...
Searching...
No Matches
grib_v2_record.cpp
Go to the documentation of this file.
1/**********************************************************************
2zyGrib: meteorological GRIB file viewer
3Copyright (C) 2008 - Jacques Zaninetti - http://www.zygrib.org
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17***********************************************************************/
18
25/*
26** File: unpackgrib2.c
27**
28** Author: Bob Dattore
29** NCAR/DSS
30** dattore@ucar.edu
31** (303) 497-1825
32** latest
33** 14 Aug 2015:
34** DRS Template 5.3 (complex packing and spatial differencing)
35
36 copyright ?
37*/
38
39#define __STDC_LIMIT_MACROS
40
41#include "wx/wxprec.h"
42
43#ifndef WX_PRECOMP
44#include "wx/wx.h"
45#endif
46
47#include <stdlib.h>
48
49#include "grib_v2_record.h"
50
51#ifdef JASPER
52#include <jasper/jasper.h>
53#endif
54
55const double GRIB_MISSING_VALUE = GRIB_NOTDEF;
56
58public:
59 int proc_code;
60 int incr_type;
61 int time_unit;
62 int time_length;
63 int incr_unit;
64 int incr_length;
65};
66
68public:
69 GRIBMetadata() : bitmap(nullptr), bms(nullptr) {
70 stat_proc.t = nullptr;
71 lvl1_type = 0;
72 lvl2_type = 0;
73 lvl1 = 0.;
74 lvl2 = 0.;
75 };
76
78 delete[] stat_proc.t;
79 delete[] bitmap;
80 delete[] bms;
81 };
82
83 int gds_templ_num;
84
85 int earth_shape;
86 unsigned char
87 earth_sphere_scale_factor; // Scale factor of radius of spherical Earth
88 int earth_sphere_scale_value; // Scale value of radius of spherical Earth
89
90 unsigned char earth_major_scale_factor; // Scale factor of major axis of
91 // oblate spheroid Earth
92 int earth_major_scale_value; // Scaled value of major axis of oblate spheroid
93 // Earth
94
95 unsigned char earth_minor_scale_factor; // Scale factor of minor axis of
96 // oblate spheroid Earth
97 int earth_minor_scale_value; // Scaled value of minor axis of oblate spheroid
98 // Earth
99
100 int nx, ny;
101 double slat, slon, latin1, latin2, splat, splon;
102 double latD;
103 union {
104 double elat;
105 double lad;
106 } lats;
107 union {
108 double elon;
109 double lov;
110 } lons;
111 union {
112 double loinc;
113 double dxinc;
114 } xinc;
115 union {
116 double lainc;
117 double dyinc;
118 } yinc;
119 int rescomp, scan_mode, proj_flag;
120 int pds_templ_num;
121 int param_cat, param_num, gen_proc, time_unit, fcst_time;
122 int ens_type, perturb_num, derived_fcst_code, nfcst_in_ensemble;
123 int lvl1_type, lvl2_type;
124 double lvl1, lvl2;
125 struct {
126 int eyr, emo, edy, etime;
127 int num_ranges, nmiss;
128 GRIBStatproc *t;
129 } stat_proc;
130 struct {
131 int stat_proc, type, num_points;
132 } spatial_proc;
133 struct {
134 int split_method, miss_val_mgmt;
135 unsigned int num_groups;
136 float primary_miss_sub, secondary_miss_sub;
137 struct {
138 int ref, pack_width;
139 } width;
140 struct {
141 unsigned int ref, incr, last, pack_width;
142 } length;
143 struct {
144 unsigned int order, order_vals_width;
145 } spatial_diff;
146 } complex_pack;
147 int drs_templ_num;
148 int precision;
149 float R;
150 int E, D, num_packed, pack_width, orig_val_type;
151 int bms_ind;
152 unsigned char *bitmap;
154 zuchar *bms;
155 int bmssize;
156};
157
159public:
160 GRIB2Grid() : gridpoints(nullptr) {};
161 ~GRIB2Grid() { delete[] gridpoints; };
162
163 double *gridpoints;
164};
165
167public:
168 GRIBMessage() : buffer(nullptr) {};
169 ~GRIBMessage() { delete[] buffer; };
170 unsigned char *buffer;
171 int offset; /* offset in bytes to next GRIB2 section */
172 int total_len, disc, ed_num;
173 int center_id, sub_center_id, table_ver, local_table_ver, ref_time_type;
174 int yr, mo, dy, time;
175 int prod_status, data_type;
176 GRIBMetadata md;
177 size_t num_grids;
178 GRIB2Grid grids;
179};
180
181#ifdef JASPER
182static int dec_jpeg2000(char *injpc, int bufsize, int *outfld)
183/*$$$ SUBPROGRAM DOCUMENTATION BLOCK
184 * . . . .
185 * SUBPROGRAM: dec_jpeg2000 Decodes JPEG2000 code stream
186 * PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-02
187 *
188 * ABSTRACT: This Function decodes a JPEG2000 code stream specified in the
189 * JPEG2000 Part-1 standard (i.e., ISO/IEC 15444-1) using JasPer
190 * Software version 1.500.4 (or 1.700.2) written by the University of British
191 * Columbia and Image Power Inc, and others.
192 * JasPer is available at http://www.ece.uvic.ca/~mdadams/jasper/.
193 *
194 * PROGRAM HISTORY LOG:
195 * 2002-12-02 Gilbert
196 *
197 * USAGE: int dec_jpeg2000(char *injpc,int bufsize,int *outfld)
198 *
199 * INPUT ARGUMENTS:
200 * injpc - Input JPEG2000 code stream.
201 * bufsize - Length (in bytes) of the input JPEG2000 code stream.
202 *
203 * OUTPUT ARGUMENTS:
204 * outfld - Output matrix of grayscale image values.
205 *
206 * RETURN VALUES :
207 * 0 = Successful decode
208 * -2 = no memory Error.
209 * -3 = Error decode jpeg2000 code stream.
210 * -5 = decoded image had multiple color components.
211 * Only grayscale is expected.
212 *
213 * REMARKS:
214 *
215 * Requires JasPer Software version 1.500.4 or 1.700.2
216 *
217 * ATTRIBUTES:
218 * LANGUAGE: C
219 * MACHINE: IBM SP
220 *
221 *$$$*/
222
223{
224 int ier;
225 int i, j, k;
226 jas_image_t *image = nullptr;
227 jas_stream_t *jpcstream;
228 jas_image_cmpt_t *pcmpt;
229 char *opts = nullptr;
230 jas_matrix_t *data;
231
232 // jas_init();
233
234 ier = 0;
235 //
236 // Create jas_stream_t containing input JPEG200 codestream in memory.
237 //
238
239 jpcstream = jas_stream_memopen(injpc, bufsize);
240 if (jpcstream == nullptr) {
241 printf(" dec_jpeg2000: no memory\n");
242 return -2;
243 }
244 //
245 // Decode JPEG200 codestream into jas_image_t structure.
246 //
247 image = jpc_decode(jpcstream, opts);
248 if (image == nullptr) {
249 printf(" jpc_decode return = %d \n", ier);
250 return -3;
251 }
252
253 pcmpt = image->cmpts_[0];
254
255 // Expecting jpeg2000 image to be grayscale only.
256 // No color components.
257 //
258 if (image->numcmpts_ != 1) {
259 printf("dec_jpeg2000: Found color image. Grayscale expected.\n");
260 return (-5);
261 }
262
263 //
264 // Create a data matrix of grayscale image values decoded from
265 // the jpeg2000 codestream.
266 //
267 data = jas_matrix_create(jas_image_height(image), jas_image_width(image));
268 jas_image_readcmpt(image, 0, 0, 0, jas_image_width(image),
269 jas_image_height(image), data);
270 //
271 // Copy data matrix to output integer array.
272 //
273 k = 0;
274 for (i = 0; i < pcmpt->height_; i++)
275 for (j = 0; j < pcmpt->width_; j++) outfld[k++] = data->rows_[i][j];
276 //
277 // Clean up JasPer work structures.
278 //
279 jas_matrix_destroy(data);
280 ier = jas_stream_close(jpcstream);
281 jas_image_destroy(image);
282
283 return 0;
284}
285#endif
286
287static unsigned int uint2(unsigned char const *p) { return (p[0] << 8) + p[1]; }
288
289static unsigned int uint4(unsigned const char *p) {
290 return ((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
291}
292
293static int int2(unsigned const char *p) {
294 int i;
295 if ((p[0] & 0x80)) {
296 i = -(((p[0] & 0x7f) << 8) + p[1]);
297 } else {
298 i = (p[0] << 8) + p[1];
299 }
300 return i;
301}
302
303static int int4(unsigned const char *p) {
304 int i;
305 if ((p[0] & 0x80)) {
306 i = -(((p[0] & 0x7f) << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
307 } else {
308 i = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
309 }
310 return i;
311}
312
313static float ieee2flt(unsigned const char *ieee) {
314 double fmant;
315 int exp;
316
317 if ((ieee[0] & 127) == 0 && ieee[1] == 0 && ieee[2] == 0 && ieee[3] == 0)
318 return (float)0.0;
319
320 exp = ((ieee[0] & 127) << 1) + (ieee[1] >> 7);
321 fmant = (double)((int)ieee[3] + (int)(ieee[2] << 8) +
322 (int)((ieee[1] | 128) << 16));
323 if (ieee[0] & 128) fmant = -fmant;
324
325 return (float)(ldexp(fmant, (int)(exp - 128 - 22)));
326}
327
328static inline void getBits(unsigned const char *buf, int *loc, size_t first,
329 size_t nbBits) {
330 if (nbBits == 0) {
331 // x >> 32 is undefined behavior, on x86 it returns x
332 *loc = 0;
333 return;
334 }
335
336 zuint oct = first / 8;
337 zuint bit = first % 8;
338
339 zuint val = (buf[oct] << 24) + (buf[oct + 1] << 16) + (buf[oct + 2] << 8) +
340 (buf[oct + 3]);
341 val = val << bit;
342 val = val >> (32 - nbBits);
343 *loc = val;
344}
345
346//-------------------------------------------------------------------------------
347// Lecture depuis un fichier
348//-------------------------------------------------------------------------------
349static void unpackIDS(GRIBMessage *grib_msg) {
350 int length;
351 int hh, mm, ss;
352 size_t ofs = grib_msg->offset / 8;
353 unsigned char *b = grib_msg->buffer + ofs;
354
355 length = uint4(b); /* length of the IDS */
356
357 grib_msg->center_id = uint2(b + 5); /* center ID */
358 grib_msg->sub_center_id = uint2(b + 7); /* sub-center ID */
359 grib_msg->table_ver = b[9]; /* table version */
360 grib_msg->local_table_ver = b[10]; /* local table version */
361 grib_msg->ref_time_type = b[11]; /* significance of reference time */
362 grib_msg->yr = uint2(b + 12); /* year */
363 grib_msg->mo = b[14]; /* month */
364 grib_msg->dy = b[15]; /* day */
365 hh = b[16]; /* hours */
366 mm = b[17]; /* minutes */
367 ss = b[18]; /* seconds */
368 grib_msg->time = hh * 10000 + mm * 100 + ss;
369 grib_msg->prod_status = b[19]; /* production status */
370 grib_msg->data_type = b[20]; /* type of data */
371 grib_msg->offset += length * 8;
372}
373
374static bool unpackLUS(GRIBMessage *grib_msg) { return true; }
375
376static void parse_earth(GRIBMessage *grib_msg) {
377 size_t ofs = grib_msg->offset / 8;
378 unsigned char *b = grib_msg->buffer + ofs;
379
380 grib_msg->md.earth_shape = b[14]; // shape of the earth
381
382 grib_msg->md.earth_sphere_scale_factor =
383 b[15]; // Scale factor of radius of spherical Earth
384 grib_msg->md.earth_sphere_scale_value =
385 uint4(b + 16); // Scale value of radius of spherical Earth
386
387 grib_msg->md.earth_major_scale_factor =
388 b[20]; // Scale factor of major axis of oblate spheroid Earth
389 grib_msg->md.earth_major_scale_value =
390 uint4(b + 21); // Scaled value of major axis of oblate spheroid Earth
391
392 grib_msg->md.earth_minor_scale_factor =
393 b[25]; // Scale factor of minor axis of oblate spheroid Earth
394 grib_msg->md.earth_minor_scale_value =
395 uint4(b + 26); // Scaled value of minor axis of oblate spheroid Earth
396}
397
398static bool unpackGDS(GRIBMessage *grib_msg) {
399 int src, num_in_list;
400 size_t ofs = grib_msg->offset / 8;
401 unsigned char *b = grib_msg->buffer + ofs;
402
403 src = b[5]; /* source of grid definition */
404 if (src != 0) {
405 fprintf(stderr, "Don't recognize predetermined grid definitions");
406 return false;
407 }
408
409 num_in_list = b[10]; /* quasi-regular grid indication */
410 if (num_in_list > 0) {
411 fprintf(stderr, "Unable to unpack quasi-regular grids");
412 return false;
413 }
414
415 /* grid definition template number Table 3.1 */
416 grib_msg->md.gds_templ_num = uint2(b + 12);
417 switch (grib_msg->md.gds_templ_num) {
418 case 0: /* Latitude/Longitude Also called Equidistant Cylindrical or Plate
419 Caree */
420 case 40: /* Gaussian Latitude/Longitude */
421 parse_earth(grib_msg);
422
423 grib_msg->md.nx = uint4(b + 30); /* number of latitudes */
424 grib_msg->md.ny = uint4(b + 34); /* number of longitudes */
425
426 grib_msg->md.slat =
427 int4(b + 46) / 1000000.; /* latitude of first gridpoint */
428 grib_msg->md.slon =
429 int4(b + 50) / 1000000.; /* longitude of first gridpoint */
430
431 grib_msg->md.rescomp = b[54]; /* resolution and component flags */
432
433 grib_msg->md.lats.elat =
434 int4(b + 55) / 1000000.; /* latitude of last gridpoint */
435 grib_msg->md.lons.elon =
436 int4(b + 59) / 1000000.; /* longitude of last gridpoint */
437
438 grib_msg->md.xinc.loinc =
439 uint4(b + 63) / 1000000.; /* longitude increment */
440
441 if (grib_msg->md.gds_templ_num == 0)
442 grib_msg->md.yinc.lainc =
443 uint4(b + 67) / 1000000.; /* latitude increment */
444
445 grib_msg->md.scan_mode = b[71]; /* scanning mode flag */
446 break;
447 case 10: /* Mercator */
448 parse_earth(grib_msg);
449
450 grib_msg->md.nx = uint4(b + 30); /* number of points along a parallel */
451 grib_msg->md.ny = uint4(b + 34); /* number of points along a meridian */
452
453 grib_msg->md.slat =
454 int4(b + 38) / 1000000.; /* latitude of first gridpoint */
455 grib_msg->md.slon =
456 int4(b + 42) / 1000000.; /* longitude of first gridpoint */
457
458 grib_msg->md.rescomp = b[46]; /* resolution and component flags */
459 grib_msg->md.latD =
460 int4(b + 47) /
461 1000000.; /* latitude at which the Mercator projection intersects the
462 Earth (Latitude where Di and Dj are specified) */
463
464 grib_msg->md.lats.elat =
465 int4(b + 51) / 1000000.; /* latitude of last gridpoint */
466 grib_msg->md.lons.elon =
467 int4(b + 55) / 1000000.; /* longitude of last gridpoint */
468
469 grib_msg->md.scan_mode = b[59]; /* scanning mode flag */
470
471 grib_msg->md.xinc.loinc = uint4(b + 64) / 1000.; /* longitude increment */
472 grib_msg->md.yinc.lainc = uint4(b + 68) / 1000.; /* latitude increment */
473 break;
474 case 30: /* Lambert conformal grid */
475 parse_earth(grib_msg);
476
477 grib_msg->md.nx = uint4(b + 30); /* number of points along a parallel */
478 grib_msg->md.ny = uint4(b + 34); /* number of points along a meridian */
479
480 grib_msg->md.slat =
481 int4(b + 38) / 1000000.; /* latitude of first gridpoint */
482 grib_msg->md.slon =
483 int4(b + 42) / 1000000.; /* longitude of first gridpoint */
484
485 grib_msg->md.rescomp = b[46]; /* resolution and component flags */
486
487 grib_msg->md.lats.lad = int4(b + 47) / 1000000.; /* LaD */
488 grib_msg->md.lons.lov = int4(b + 51) / 1000000.; /* LoV */
489
490 grib_msg->md.xinc.dxinc =
491 int4(b + 55) / 1000.; /* x-direction increment */
492 grib_msg->md.yinc.dyinc =
493 int4(b + 59) / 1000.; /* y-direction increment */
494
495 grib_msg->md.proj_flag = b[63]; /* projection center flag */
496 grib_msg->md.scan_mode = b[64]; /* scanning mode flag */
497
498 grib_msg->md.latin1 = int4(b + 65) / 1000000.; /* latin1 */
499 grib_msg->md.latin2 = int4(b + 69) / 1000000.; /* latin2 */
500
501 grib_msg->md.splat =
502 int4(b + 73) / 1000000.; /* latitude of southern pole of projection */
503 grib_msg->md.splon =
504 int4(b + 77) /
505 1000000.; /* longitude of southern pole of projection */
506 break;
507 default:
508 fprintf(stderr, "Grid template %d is not understood\n",
509 grib_msg->md.gds_templ_num);
510 return false;
511 }
512 return true;
513}
514
515static void unpack_stat_proc(GRIBMessage *grib_msg, unsigned const char *b) {
516 int hh, mm, ss;
517 size_t n, off;
518
519 grib_msg->md.stat_proc.eyr = uint2(b);
520 grib_msg->md.stat_proc.emo = b[2];
521 grib_msg->md.stat_proc.edy = b[3];
522 hh = b[4];
523 mm = b[5];
524 ss = b[6];
525 grib_msg->md.stat_proc.etime = hh * 10000 + mm * 100 + ss;
526
527 grib_msg->md.stat_proc.num_ranges =
528 b[7]; /* number of time range specifications */
529 grib_msg->md.stat_proc.nmiss =
530 uint4(b + 8); /* number of values missing from process */
531
532 if (grib_msg->md.stat_proc.t != 0) {
533 delete[] grib_msg->md.stat_proc.t;
534 }
535 grib_msg->md.stat_proc.t =
536 new GRIBStatproc[grib_msg->md.stat_proc.num_ranges];
537 off = 12;
538 for (n = 0; n < (size_t)grib_msg->md.stat_proc.num_ranges; n++) {
539 grib_msg->md.stat_proc.t[n].proc_code = b[off];
540 grib_msg->md.stat_proc.t[n].incr_type = b[off + 1];
541 grib_msg->md.stat_proc.t[n].time_unit = b[off + 2];
542 grib_msg->md.stat_proc.t[n].time_length = uint4(b + off + 3);
543 grib_msg->md.stat_proc.t[n].incr_unit = b[off + 7];
544 grib_msg->md.stat_proc.t[n].incr_length = uint4(b + off + 8);
545 off += 12;
546 }
547}
548
549// Section 4: Product Definition Section
550static bool unpackPDS(GRIBMessage *grib_msg) {
551 int num_coords, factor;
552 size_t ofs = grib_msg->offset / 8;
553 unsigned char *b = grib_msg->buffer + ofs;
554
555 num_coords = uint2(b + 5); /* indication of hybrid coordinate system */
556 if (num_coords > 0) {
557 fprintf(stderr, "Unable to decode hybrid coordinates");
558 return false;
559 }
560
561 grib_msg->md.pds_templ_num =
562 uint2(b + 7); /* product definition template number */
563 grib_msg->md.stat_proc.num_ranges = 0;
564 switch (grib_msg->md.pds_templ_num) {
565 case 0:
566 case 1:
567 case 2:
568 case 8: // Average, accumulation, extreme values
569 case 11:
570 case 12:
571 case 15:
572 grib_msg->md.ens_type = -1;
573 grib_msg->md.derived_fcst_code = -1;
574 grib_msg->md.spatial_proc.type = -1;
575 grib_msg->md.param_cat = b[9]; /* parameter category */
576 grib_msg->md.param_num = b[10]; /* parameter number */
577 grib_msg->md.gen_proc = b[11]; /* generating process */
578
579 grib_msg->md.time_unit = b[17]; /* time range indicator*/
580 grib_msg->md.fcst_time = uint4(b + 18); /* forecast time */
581
582 grib_msg->md.lvl1_type = b[22]; /* type of first level */
583 factor = b[23]; /* value of first level */
584 grib_msg->md.lvl1 = int4(b + 24) / pow(10., (double)factor);
585
586 grib_msg->md.lvl2_type = b[28]; /* type of second level */
587 factor = b[29]; /* value of second level */
588 grib_msg->md.lvl2 = int4(b + 30) / pow(10., (double)factor);
589
590 switch (grib_msg->md.pds_templ_num) {
591 case 1:
592 case 11:
593 grib_msg->md.ens_type = b[34];
594 grib_msg->md.perturb_num = b[35];
595 grib_msg->md.nfcst_in_ensemble = b[36];
596
597 switch (grib_msg->md.pds_templ_num) {
598 case 11:
599 unpack_stat_proc(grib_msg, b + 37);
600 break;
601 }
602 break;
603 case 2:
604 case 12:
605 grib_msg->md.derived_fcst_code = b[34];
606 grib_msg->md.nfcst_in_ensemble = b[35];
607
608 switch (grib_msg->md.pds_templ_num) {
609 case 12:
610 unpack_stat_proc(grib_msg, b + 36);
611 break;
612 }
613 break;
614 case 8:
615 unpack_stat_proc(grib_msg, b + 34);
616 break;
617 case 15:
618 grib_msg->md.spatial_proc.stat_proc = b[34];
619 grib_msg->md.spatial_proc.type = b[35];
620 grib_msg->md.spatial_proc.num_points = b[36];
621 break;
622 }
623 break;
624 default:
625 fprintf(stderr, "Product Definition Template %d is not understood\n",
626 grib_msg->md.pds_templ_num);
627 return false;
628 }
629 return true;
630}
631
632// Section 5: Data Representation Section
633static bool unpackDRS(GRIBMessage *grib_msg) {
634 size_t ofs = grib_msg->offset / 8;
635 unsigned char *b = grib_msg->buffer + ofs;
636
637 grib_msg->md.num_packed = uint4(b + 5); /* number of packed values */
638 grib_msg->md.drs_templ_num =
639 uint2(b + 9); /* data representation template number */
640
641 switch (grib_msg->md.drs_templ_num) { // Table 5.0
642 case 4: // Grid Point Data - Simple Packing
643 grib_msg->md.precision = b[11];
644 break;
645 case 0: // Grid Point Data - Simple Packing
646 case 2: // Grid Point Data - Complex Packing
647 case 3: // Grid Point Data - Complex Packing and Spatial Differencing
648#ifdef JASPER
649 case 40: // Grid Point Data - JPEG2000 Compression
650 case 40000:
651#endif
652 /* cf
653 * http://www.wmo.int/pages/prog/www/WMOCodes/Guides/GRIB/GRIB2_062006.pdf
654 * p. 36*/
655 grib_msg->md.R = ieee2flt(b + 11);
656 grib_msg->md.E = int2(b + 15);
657 grib_msg->md.D = int2(b + 17);
658 grib_msg->md.R /= pow(10., grib_msg->md.D);
659
660 grib_msg->md.pack_width = b[19];
661 grib_msg->md.orig_val_type = b[20];
662
663 if (grib_msg->md.drs_templ_num == 3 || grib_msg->md.drs_templ_num == 2) {
664 grib_msg->md.complex_pack.split_method = b[21];
665 grib_msg->md.complex_pack.miss_val_mgmt = b[22];
666 if (grib_msg->md.orig_val_type == 0) { // Table 5.1
667 grib_msg->md.complex_pack.primary_miss_sub = ieee2flt(b + 23);
668 grib_msg->md.complex_pack.secondary_miss_sub = ieee2flt(b + 27);
669 } else if (grib_msg->md.orig_val_type == 1) {
670 grib_msg->md.complex_pack.primary_miss_sub = uint4(b + 23);
671 grib_msg->md.complex_pack.secondary_miss_sub = uint4(b + 27);
672 } else {
673 fprintf(stderr,
674 "Unable to decode missing value substitutes for original "
675 "value type %d\n",
676 grib_msg->md.orig_val_type);
677 return false;
678 }
679 grib_msg->md.complex_pack.num_groups = uint4(b + 31);
680
681 grib_msg->md.complex_pack.width.ref = b[35];
682 grib_msg->md.complex_pack.width.pack_width = b[36];
683
684 grib_msg->md.complex_pack.length.ref = uint4(b + 37);
685 grib_msg->md.complex_pack.length.incr = b[41];
686 grib_msg->md.complex_pack.length.last = uint4(b + 42);
687 grib_msg->md.complex_pack.length.pack_width = b[46];
688 }
689 if (grib_msg->md.drs_templ_num == 3) {
690 grib_msg->md.complex_pack.spatial_diff.order = b[47];
691 grib_msg->md.complex_pack.spatial_diff.order_vals_width = b[48];
692 } else {
693 grib_msg->md.complex_pack.spatial_diff.order = 0;
694 grib_msg->md.complex_pack.spatial_diff.order_vals_width = 0;
695 }
696 break;
697 default:
698 fprintf(stderr, "Data template %d is not understood\n",
699 grib_msg->md.drs_templ_num);
700 return false;
701 }
702 return true;
703}
704
705// Section 6: Bit-Map Section
706static bool unpackBMS(GRIBMessage *grib_msg) {
707 int ind, len, n, bit;
708 size_t ofs = grib_msg->offset / 8;
709 unsigned char *b = grib_msg->buffer + ofs;
710
711 ind = b[5]; /* bit map indicator */
712 switch (ind) {
713 case 0: // A bit map applies to this product and is specified in this
714 // section.
715 len = uint4(b);
716 if (len < 7) return false;
717 len -= 6;
718 grib_msg->md.bmssize = len;
719 len *= 8;
720 delete[] grib_msg->md.bitmap;
721 delete[] grib_msg->md.bms;
722 grib_msg->md.bitmap = new unsigned char[len];
723 grib_msg->md.bms = new zuchar[grib_msg->md.bmssize];
724 memcpy(grib_msg->md.bms, b + 6, grib_msg->md.bmssize);
725 for (n = 0; n < len; n++) {
726 getBits(grib_msg->buffer, &bit, grib_msg->offset + 48 + n, 1);
727 grib_msg->md.bitmap[n] = bit;
728 }
729 break;
730 case 254: // A bit map previously defined in the same GRIB2 message applies
731 // to this product.
732 break;
733 case 255: // A bit map does not apply to this product.
734 delete[] grib_msg->md.bitmap;
735 grib_msg->md.bitmap = nullptr;
736 delete[] grib_msg->md.bms;
737 grib_msg->md.bms = nullptr;
738 grib_msg->md.bmssize = 0;
739 break;
740 default:
741 fprintf(stderr,
742 "This code is not currently set up to deal with predefined "
743 "bit-maps\n");
744 return false;
745 }
746 return true;
747}
748
749// Section 7: Data Section
750static bool unpackDS(GRIBMessage *grib_msg) {
751 int off, pval, l;
752 unsigned int n, m;
753
754 struct {
755 int *ref_vals, *widths;
756 int *lengths;
757 int *first_vals = 0, sign, omin;
758 long long miss_val, group_miss_val;
759 int max_length;
760 } groups;
761 float lastgp, D = pow(10., grib_msg->md.D), E = pow(2., grib_msg->md.E);
762
763 groups.omin = 0;
764 groups.first_vals = nullptr;
765
766 off = grib_msg->offset + 40;
767 int npoints = grib_msg->md.ny * grib_msg->md.nx;
768 switch (grib_msg->md.drs_templ_num) {
769 case 0:
770 grib_msg->grids.gridpoints = new double[npoints];
771 for (l = 0; l < npoints; l++) {
772 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) {
773 getBits(grib_msg->buffer, &pval, off, grib_msg->md.pack_width);
774 grib_msg->grids.gridpoints[l] = grib_msg->md.R + pval * E / D;
775 off += grib_msg->md.pack_width;
776 } else
777 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
778 }
779 break;
780 case 3:
781 if (grib_msg->md.complex_pack.num_groups > 0) {
782 if (grib_msg->md.complex_pack.spatial_diff.order) {
783 groups.first_vals =
784 new int[grib_msg->md.complex_pack.spatial_diff.order];
785 for (n = 0; n < grib_msg->md.complex_pack.spatial_diff.order; ++n) {
786 getBits(
787 grib_msg->buffer, &groups.first_vals[n], off,
788 grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8);
789 off += grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8;
790 }
791 }
792 getBits(grib_msg->buffer, &groups.sign, off, 1);
793 getBits(
794 grib_msg->buffer, &groups.omin, off + 1,
795 grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8 - 1);
796 if (groups.sign == 1) {
797 groups.omin = -groups.omin;
798 }
799 off += grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8;
800 }
801 // fall through
802 case 2:
803 grib_msg->grids.gridpoints = new double[npoints];
804 if (grib_msg->md.complex_pack.num_groups == 0) {
805 for (l = 0; l < npoints; ++l) {
806 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
807 }
808 break;
809 }
810 if (grib_msg->md.complex_pack.miss_val_mgmt > 0) {
811 groups.miss_val = pow(2., grib_msg->md.pack_width) - 1;
812 } else {
813 groups.miss_val = GRIB_MISSING_VALUE;
814 }
815
816 groups.ref_vals = new int[grib_msg->md.complex_pack.num_groups];
817 groups.widths = new int[grib_msg->md.complex_pack.num_groups];
818 groups.lengths = new int[grib_msg->md.complex_pack.num_groups];
819
820 for (n = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
821 getBits(grib_msg->buffer, &groups.ref_vals[n], off,
822 grib_msg->md.pack_width);
823 off += grib_msg->md.pack_width;
824 }
825 off = (off + 7) & ~7; // byte boundary padding
826
827 for (n = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
828 getBits(grib_msg->buffer, &groups.widths[n], off,
829 grib_msg->md.complex_pack.width.pack_width);
830 groups.widths[n] += grib_msg->md.complex_pack.width.ref;
831 off += grib_msg->md.complex_pack.width.pack_width;
832 }
833 off = (off + 7) & ~7;
834
835 for (n = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
836 getBits(grib_msg->buffer, &groups.lengths[n], off,
837 grib_msg->md.complex_pack.length.pack_width);
838 off += grib_msg->md.complex_pack.length.pack_width;
839 }
840 off = (off + 7) & ~7;
841
842 groups.max_length = 0;
843 for (n = 0; n < grib_msg->md.complex_pack.num_groups - 1; ++n) {
844 groups.lengths[n] =
845 grib_msg->md.complex_pack.length.ref +
846 groups.lengths[n] * grib_msg->md.complex_pack.length.incr;
847 if (groups.lengths[n] > groups.max_length) {
848 groups.max_length = groups.lengths[n];
849 }
850 }
851 groups.lengths[n] = grib_msg->md.complex_pack.length.last;
852 if (groups.lengths[n] > groups.max_length) {
853 groups.max_length = groups.lengths[n];
854 }
855 // unpack the field of differences
856 for (n = 0, l = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
857 if (groups.widths[n] > 0) {
858 if (grib_msg->md.complex_pack.miss_val_mgmt > 0) {
859 groups.group_miss_val = pow(2., groups.widths[n]) - 1;
860 } else {
861 groups.group_miss_val = GRIB_MISSING_VALUE;
862 }
863 for (int i = 0; i < groups.lengths[n];) {
864 if (grib_msg->md.bitmap != nullptr && grib_msg->md.bitmap[l] == 0) {
865 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
866 } else {
867 getBits(grib_msg->buffer, &pval, off, groups.widths[n]);
868 off += groups.widths[n];
869 if (pval == groups.group_miss_val) {
870 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
871 } else {
872 grib_msg->grids.gridpoints[l] =
873 pval + groups.ref_vals[n] + groups.omin;
874 }
875 ++i;
876 }
877 ++l;
878 }
879 } else { // constant group XXX bitmap?
880 for (int i = 0; i < groups.lengths[n];) {
881 if (grib_msg->md.bitmap != nullptr && grib_msg->md.bitmap[l] == 0) {
882 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
883 } else {
884 if (groups.ref_vals[n] == groups.miss_val) {
885 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
886 } else {
887 grib_msg->grids.gridpoints[l] =
888 groups.ref_vals[n] + groups.omin;
889 }
890 ++i;
891 }
892 ++l;
893 }
894 }
895 }
896
897 for (; l < npoints; ++l) {
898 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
899 }
900
901 if (grib_msg->md.drs_templ_num == 3) {
902 if (groups.first_vals != nullptr) {
903 for (n = grib_msg->md.complex_pack.spatial_diff.order - 1; n > 0;
904 --n) {
905 lastgp = groups.first_vals[n] - groups.first_vals[n - 1];
906 for (l = 0, m = 0; l < grib_msg->md.nx * grib_msg->md.ny; ++l) {
907 if (grib_msg->grids.gridpoints[l] != GRIB_MISSING_VALUE) {
908 if (m >= grib_msg->md.complex_pack.spatial_diff.order) {
909 grib_msg->grids.gridpoints[l] += lastgp;
910 lastgp = grib_msg->grids.gridpoints[l];
911 }
912 ++m;
913 }
914 }
915 }
916 }
917 for (l = 0, m = 0, lastgp = 0; l < npoints; ++l) {
918 if (grib_msg->grids.gridpoints[l] != GRIB_MISSING_VALUE) {
919 if (m < grib_msg->md.complex_pack.spatial_diff.order) {
920 grib_msg->grids.gridpoints[l] =
921 grib_msg->md.R + groups.first_vals[m] * E / D;
922 lastgp = grib_msg->md.R * D / E + groups.first_vals[m];
923 } else {
924 lastgp += grib_msg->grids.gridpoints[l];
925 grib_msg->grids.gridpoints[l] = lastgp * E / D;
926 }
927 ++m;
928 }
929 }
930 delete[] groups.first_vals;
931 } else
932 for (l = 0; l < npoints; ++l) {
933 if (grib_msg->grids.gridpoints[l] != GRIB_MISSING_VALUE) {
934 grib_msg->grids.gridpoints[l] =
935 grib_msg->md.R + grib_msg->grids.gridpoints[l] * E / D;
936 }
937 }
938 delete[] groups.ref_vals;
939 delete[] groups.widths;
940 delete[] groups.lengths;
941 break;
942 case 4: {
943 // Grid point data - IEEE Floating Point Data
944 if (grib_msg->md.precision == 1) { // IEEE754 single precision
945 grib_msg->grids.gridpoints = new double[npoints];
946 for (int ll = 0; ll < npoints; ll++) {
947 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[ll] == 1) {
948 grib_msg->grids.gridpoints[ll] =
949 ieee2flt(grib_msg->buffer + off / 8);
950 off += 32;
951 } else
952 grib_msg->grids.gridpoints[ll] = GRIB_MISSING_VALUE;
953 }
954 } else if (grib_msg->md.precision == 2) { // IEEE754 single precision
955 static const int one = 1;
956 bool const is_lsb = *((char *)&one) == 1;
957 grib_msg->grids.gridpoints = new double[npoints];
958 for (l = 0; l < npoints; l++) {
959 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) {
960 double d;
961 if (is_lsb) {
962 unsigned char temp[8];
963 for (int j = 0; j < 8; j++) {
964 temp[j] = grib_msg->buffer[off / 8 + 7 - j];
965 }
966 memcpy(&d, temp, 8);
967 } else {
968 memcpy(&d, grib_msg->buffer + off / 8, 8);
969 }
970 grib_msg->grids.gridpoints[l] = d;
971 off += 64;
972 } else
973 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
974 }
975 } else {
976 fprintf(stderr,
977 "g2_unpack7: Invalid precision=%d for Data Section 5.4.\n",
978 grib_msg->md.precision);
979 return false;
980 }
981 } break;
982#ifdef JASPER
983 case 40:
984 case 40000:
985 int len, *jvals, cnt;
986 getBits(grib_msg->buffer, &len, grib_msg->offset, 32);
987 if (len < 5) return false;
988 len = len - 5;
989 jvals = new int[npoints];
990 grib_msg->grids.gridpoints = new double[npoints];
991 if (len > 0)
992 dec_jpeg2000((char *)&grib_msg->buffer[grib_msg->offset / 8 + 5], len,
993 jvals);
994 cnt = 0;
995 for (l = 0; l < npoints; l++) {
996 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) {
997 if (len == 0) jvals[cnt] = 0;
998 grib_msg->grids.gridpoints[l] = grib_msg->md.R + jvals[cnt++] * E / D;
999 } else
1000 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
1001 }
1002 delete[] jvals;
1003 break;
1004#endif
1005 default:
1006 erreur("Unknown packing %d", grib_msg->md.drs_templ_num);
1007 break;
1008 }
1009 return true;
1010}
1011
1012static zuchar GRBV2_TO_DATA(int productDiscipline, int dataCat, int dataNum) {
1013 zuchar ret = 255;
1014 // printf("search %d %d %d\n", productDiscipline, dataCat, dataNum);
1015 switch (productDiscipline) { // TABLE 4.2
1016 case 0: // Meteorological products
1017 switch (dataCat) {
1018 case 0: // Temperature
1019 switch (dataNum) {
1020 case 0:
1021 ret = GRB_TEMP;
1022 break; // DATA_TO_GRBV2[DATA_TEMP] = grb2DataType(0,0,0);
1023 case 2:
1024 ret = GRB_TPOT;
1025 break; // DATA_TO_GRBV2[DATA_TEMP_POT] = grb2DataType(0,0,2);
1026 case 4:
1027 ret = GRB_TMAX;
1028 break; // DATA_TO_GRBV2[DATA_TMAX] = grb2DataType(0,0,4);
1029 case 5:
1030 ret = GRB_TMIN;
1031 break; // DATA_TO_GRBV2[DATA_TMIN] = grb2DataType(0,0,5);
1032 case 6:
1033 ret = GRB_DEWPOINT;
1034 break; // DATA_TO_GRBV2[DATA_DEWPOINT] = grb2DataType(0,0,6);
1035 case 17:
1036 ret = GRB_WTMP; // Skin temperature [C] SFC="Ground or water
1037 // surface"
1038 break; // DATA_TO_GRBV2[DATA_DEWPOINT] = grb2DataType(0,0,17);
1039 }
1040 break;
1041 case 1: // dataCat Moisture
1042 switch (dataNum) {
1043 case 0:
1044 ret = GRB_HUMID_SPEC;
1045 break; // DATA_TO_GRBV2[DATA_HUMID_SPEC] = grb2DataType(0,1,0);
1046 case 1:
1047 ret = GRB_HUMID_REL;
1048 break; // DATA_TO_GRBV2[DATA_HUMID_REL] = grb2DataType(0,1,1);
1049 case 7:
1050 ret = GRB_PRECIP_RATE;
1051 break; // DATA_TO_GRBV2[DATA_PRECIP_RATE] = grb2DataType(0,1,7);
1052 case 49: // Total Water Precipitation (Meteo France Arome 0.01
1053 case 52: // Total precipitation rate kg m–2 s–1
1054 case 8:
1055 ret = GRB_PRECIP_TOT;
1056 break; // DATA_TO_GRBV2[DATA_PRECIP_TOT] = grb2DataType(0,1,8);
1057 case 11:
1058 ret = GRB_SNOW_DEPTH;
1059 break; // DATA_TO_GRBV2[DATA_SNOW_DEPTH] = grb2DataType(0,1,11);
1060 case 193:
1061 ret = GRB_FRZRAIN_CATEG;
1062 break; // DATA_TO_GRBV2[DATA_FRZRAIN_CATEG] =
1063 // grb2DataType(0,1,193);
1064 case 195:
1065 ret = GRB_SNOW_CATEG;
1066 break; // DATA_TO_GRBV2[DATA_SNOW_CATEG] = grb2DataType(0,1,195);
1067 }
1068 break;
1069 case 2: // dataCat Momentum
1070 switch (dataNum) {
1071 case 0:
1072 ret = GRB_WIND_DIR;
1073 break;
1074 case 1:
1075 ret = GRB_WIND_SPEED;
1076 break;
1077 case 2:
1078 ret = GRB_WIND_VX;
1079 break; // DATA_TO_GRBV2[DATA_WIND_VX] = grb2DataType(0,2,2);
1080 case 3:
1081 ret = GRB_WIND_VY;
1082 break; // DATA_TO_GRBV2[DATA_WIND_VY] = grb2DataType(0,2,3);
1083 case 22:
1084 ret = GRB_WIND_GUST;
1085 break; //
1086 }
1087 break;
1088 case 3: // dataCat mass
1089 switch (dataNum) {
1090 case 0:
1091 ret = GRB_PRESSURE;
1092 break; // DATA_TO_GRBV2[DATA_PRESSURE] = grb2DataType(0,3,0);
1093 case 1:
1094 ret = GRB_PRESSURE;
1095 break; // PRSMSL //DATA_TO_GRBV2[DATA_PRESSURE] =
1096 // grb2DataType(0,3,0);
1097 case 5:
1098 ret = GRB_GEOPOT_HGT;
1099 break; // DATA_TO_GRBV2[DATA_GEOPOT_HGT]= grb2DataType(0,3,5);
1100
1101 case 192:
1102 ret = GRB_PRESSURE;
1103 break; // DATA_TO_GRBV2[DATA_MSLET] = grb2DataType(0,3,192);
1104 }
1105 break;
1106 case 6: // dataCat
1107 switch (dataNum) {
1108 case 1:
1109 ret = GRB_CLOUD_TOT;
1110 break; // DATA_TO_GRBV2[DATA_CLOUD_TOT] = grb2DataType(0,6,1);
1111 }
1112 break;
1113 case 7: // dataCat
1114 switch (dataNum) {
1115 // case 7: ret = GRB_?; break // DATA_TO_GRBV2[DATA_CIN] =
1116 // grb2DataType(0,7,7);
1117 case 6:
1118 ret = GRB_CAPE;
1119 break; // DATA_TO_GRBV2[DATA_CAPE] = grb2DataType(0,7,6);
1120 }
1121 break;
1122 case 16: // Meteorological products, Forecast Radar Imagery category
1123 switch (dataNum) {
1124 case 196:
1125 ret = GRB_COMP_REFL;
1126 break; // = grb2DataType(0,16, 196);
1127 }
1128 break;
1129 }
1130 break;
1131 case 10: // productDiscipline Oceanographic products
1132 switch (dataCat) {
1133 case 0: // waves
1134#if 0
1135 switch (dataNum) {
1136 case 3: ret= GRB_WVHGT; break; //DATA_TO_GRBV2[DATA_WAVES_SIG_HGT_COMB] = grb2DataType(10,0,3);
1137 DATA_TO_GRBV2[DATA_WAVES_WND_DIR] = grb2DataType(10,0,4);
1138 DATA_TO_GRBV2[DATA_WAVES_WND_HGT] = grb2DataType(10,0,5);
1139 DATA_TO_GRBV2[DATA_WAVES_WND_PERIOD] = grb2DataType(10,0,6);
1140 DATA_TO_GRBV2[DATA_WAVES_SWL_DIR] = grb2DataType(10,0,7);
1141 DATA_TO_GRBV2[DATA_WAVES_SWL_HGT] = grb2DataType(10,0,8);
1142 DATA_TO_GRBV2[DATA_WAVES_SWL_PERIOD] = grb2DataType(10,0,9);
1143 DATA_TO_GRBV2[DATA_WAVES_PRIM_DIR] = grb2DataType(10,0,10);
1144 DATA_TO_GRBV2[DATA_WAVES_PRIM_PERIOD] = grb2DataType(10,0,11);
1145 DATA_TO_GRBV2[DATA_WAVES_SEC_DIR] = grb2DataType(10,0,12);
1146 DATA_TO_GRBV2[DATA_WAVES_SEC_PERIOD] = grb2DataType(10,0,13);
1147 }
1148#endif
1149
1150 switch (dataNum) {
1151 case 3:
1152 ret = GRB_HTSGW;
1153 break; // Significant Height of Combined Wind Waves and Swell
1154 case 4:
1155 ret = GRB_WVDIR;
1156 break; // Direction of Wind Waves
1157 case 5:
1158 ret = GRB_WVHGT;
1159 break; // Significant Height of Wind Waves
1160 case 6:
1161 ret = GRB_WVPER;
1162 break; // Mean Period of Wind Waves
1163 case 14:
1164 ret = GRB_DIR;
1165 break; // Direction of Combined Wind Waves and Swell
1166 case 15:
1167 ret = GRB_PER;
1168 break; // Mean Period of Combined Wind Waves and Swell
1169 }
1170 break;
1171
1172 case 1: // Currents
1173 switch (dataNum) {
1174 case 0:
1175 ret = GRB_CUR_DIR;
1176 break;
1177 case 1:
1178 ret = GRB_CUR_SPEED;
1179 break;
1180 case 2:
1181 ret = GRB_UOGRD;
1182 break; // DATA_TO_GRBV2[DATA_CURRENT_VX] = grb2DataType(10,1,2);
1183 case 3:
1184 ret = GRB_VOGRD;
1185 break; // DATA_TO_GRBV2[DATA_CURRENT_VY] = grb2DataType(10,1,3);
1186 }
1187 break;
1188 case 3: // Surface Properties
1189 switch (dataNum) {
1190 case 0:
1191 ret = GRB_WTMP;
1192 break; // DATA_TO_GRBV2[DATA_CURRENT_VX] = grb2DataType(10,1,2);
1193 }
1194 break;
1195 }
1196 break;
1197 }
1198#if 1
1199 if (ret == 255) {
1200 erreur("unknown Discipline %d dataCat %d dataNum %d", productDiscipline,
1201 dataCat, dataNum);
1202 }
1203#endif
1204 return ret;
1205}
1206
1208static int mapStatisticalEndTime(GRIBMessage *grid) {
1209 // lovely md.fcst_time is in grid->md.time_unit but
1210 // md.stat_proc.t[0].time_length is in grid->md.stat_proc.t[0].time_unit not
1211 // always the same.
1212 if (grid->md.time_unit == grid->md.stat_proc.t[0].time_unit)
1213 switch (grid->md.time_unit) { // table 4.4
1214 case 0: // minute
1215 // return (grid->md.stat_proc.etime/100 % 100)-(grid->time/100 % 100);
1216 case 1: // hour
1217 return grid->md.fcst_time + grid->md.stat_proc.t[0].time_length;
1218 // return (grid->md.stat_proc.etime/10000- grid->time/10000);
1219 case 2: // Day
1220 return (grid->md.stat_proc.edy - grid->dy);
1221 case 3:
1222 return (grid->md.stat_proc.emo - grid->mo);
1223 case 4:
1224 return (grid->md.stat_proc.eyr - grid->yr);
1225 default:
1226 fprintf(stderr, "Unable to map end time with units %d to GRIB1\n",
1227 grid->md.time_unit);
1228 return UINT_MAX;
1229 }
1230
1231 if (grid->md.time_unit == 0 && grid->md.stat_proc.t[0].time_unit == 1) {
1232 // in minute + hourly increment
1233 return grid->md.fcst_time + grid->md.stat_proc.t[0].time_length * 60;
1234 }
1235
1236 if (grid->md.time_unit == 1 && grid->md.stat_proc.t[0].time_unit == 0 &&
1237 (grid->md.stat_proc.t[0].time_unit % 60) != 0) {
1238 // convert in hour
1239 return grid->md.fcst_time + grid->md.stat_proc.t[0].time_length / 60;
1240 }
1241
1242 fprintf(stderr, "Unable to map end time %d %d %d %d \n", grid->md.time_unit,
1243 grid->md.stat_proc.t[0].time_unit, grid->md.fcst_time,
1244 grid->md.stat_proc.t[0].time_length);
1245 return UINT_MAX;
1246}
1247
1248// map GRIB2 msg time to GRIB1 P1 and P2 in sec
1249static bool mapTimeRange(GRIBMessage *grid, zuint *p1, zuint *p2,
1250 zuchar *t_range, int *n_avg, int *n_missing,
1251 int center) {
1252 switch (grid->md.pds_templ_num) {
1253 case 0:
1254 case 1:
1255 case 2:
1256 case 15:
1257 *t_range = 0;
1258 *p1 = grid->md.fcst_time;
1259 *p2 = 0;
1260 *n_avg = *n_missing = 0;
1261 break;
1262 case 8:
1263 case 11:
1264 case 12:
1265 if (grid->md.stat_proc.num_ranges > 1) {
1266 if (center == 7 && grid->md.stat_proc.num_ranges == 2) {
1267 /* NCEP CFSR monthly grids */
1268 *p2 = grid->md.stat_proc.t[0].incr_length;
1269 *p1 = *p2 - grid->md.stat_proc.t[1].time_length;
1270 *n_avg = grid->md.stat_proc.t[0].time_length;
1271 switch (grid->md.stat_proc.t[0].proc_code) {
1272 case 193:
1273 *t_range = 113;
1274 break;
1275 case 194:
1276 *t_range = 123;
1277 break;
1278 case 195:
1279 *t_range = 128;
1280 break;
1281 case 196:
1282 *t_range = 129;
1283 break;
1284 case 197:
1285 *t_range = 130;
1286 break;
1287 case 198:
1288 *t_range = 131;
1289 break;
1290 case 199:
1291 *t_range = 132;
1292 break;
1293 case 200:
1294 *t_range = 133;
1295 break;
1296 case 201:
1297 *t_range = 134;
1298 break;
1299 case 202:
1300 *t_range = 135;
1301 break;
1302 case 203:
1303 *t_range = 136;
1304 break;
1305 case 204:
1306 *t_range = 137;
1307 break;
1308 case 205:
1309 *t_range = 138;
1310 break;
1311 case 206:
1312 *t_range = 139;
1313 break;
1314 case 207:
1315 *t_range = 140;
1316 break;
1317 default:
1318 fprintf(
1319 stderr,
1320 "Unable to map NCEP statistical process code %d to GRIB1\n",
1321 grid->md.stat_proc.t[0].proc_code);
1322 return false;
1323 }
1324 } else {
1325 fprintf(stderr,
1326 "Unable to map multiple statistical processes to GRIB1\n");
1327 return false;
1328 }
1329 } else {
1330 switch (grid->md.stat_proc.t[0].proc_code) {
1331 case 0:
1332 case 1:
1333 case 4:
1334 switch (grid->md.stat_proc.t[0].proc_code) {
1335 case 0: /* average */
1336 *t_range = 3;
1337 break;
1338 case 1: /* accumulation */
1339 *t_range = 4;
1340 break;
1341 case 4: /* difference */
1342 *t_range = 5;
1343 break;
1344 }
1345 *p1 = grid->md.fcst_time;
1346 *p2 = mapStatisticalEndTime(grid);
1347 if (*p2 == UINT_MAX) {
1348 return false;
1349 }
1350 if (grid->md.stat_proc.t[0].incr_length == 0)
1351 *n_avg = 0;
1352 else {
1353 fprintf(stderr, "Unable to map discrete processing to GRIB1\n");
1354 return false;
1355 }
1356 break;
1357
1358 case 2: // maximum
1359 case 3: // minimum
1360 *t_range = 2;
1361 *p1 = grid->md.fcst_time;
1362 *p2 = mapStatisticalEndTime(grid);
1363 if (*p2 == UINT_MAX) {
1364 return false;
1365 }
1366 if (grid->md.stat_proc.t[0].incr_length == 0)
1367 *n_avg = 0;
1368 else {
1369 fprintf(stderr, "Unable to map discrete processing to GRIB1\n");
1370 return false;
1371 }
1372 break;
1373 default:
1374 // patch for NCEP grids
1375 if (grid->md.stat_proc.t[0].proc_code == 255 && center == 7) {
1376 if (grid->disc == 0) {
1377 if (grid->md.param_cat == 0) {
1378 switch (grid->md.param_num) {
1379 case 4:
1380 case 5:
1381 *t_range = 2;
1382 *p1 = grid->md.fcst_time;
1383 *p2 = mapStatisticalEndTime(grid);
1384 if (*p2 == UINT_MAX) {
1385 return false;
1386 }
1387 if (grid->md.stat_proc.t[0].incr_length == 0)
1388 *n_avg = 0;
1389 else {
1390 fprintf(stderr,
1391 "Unable to map discrete processing to GRIB1\n");
1392 return false;
1393 }
1394 break;
1395 }
1396 }
1397 }
1398 } else {
1399 fprintf(stderr, "Unable to map statistical process %d to GRIB1\n",
1400 grid->md.stat_proc.t[0].proc_code);
1401 return false;
1402 }
1403 }
1404 }
1405 *n_missing = grid->md.stat_proc.nmiss;
1406 break;
1407 default:
1408 fprintf(stderr,
1409 "Unable to map time range for Product Definition Template %d "
1410 "into GRIB1\n",
1411 grid->md.pds_templ_num);
1412 return false;
1413 }
1414 return true;
1415}
1416
1417//-------------------------------------------------------------------------------
1418// Adjust data type from different mete center
1419//-------------------------------------------------------------------------------
1420void GribV2Record::translateDataType() {
1421 this->known_data = true;
1422 data_center_model = OTHER_DATA_CENTER;
1423 //------------------------
1424 // NOAA GFS
1425 //------------------------
1426 if (data_type == GRB_PRECIP_RATE) { // mm/s -> mm/h
1427 multiplyAllData(3600.0);
1428 }
1429 if (id_center == 7 && id_model == 2) // NOAA
1430 {
1431 data_center_model = NOAA_GFS;
1432 // altitude level (entire atmosphere vs entire atmosphere considered as 1
1433 // level)
1434 if (level_type == LV_ATMOS_ENT) {
1435 level_type = LV_ATMOS_ALL;
1436 }
1437 if (data_type == GRB_TEMP // gfs Water surface Temperature
1438 && level_type == LV_GND_SURF && level_value == 0)
1439 data_type = GRB_WTMP;
1440 }
1441 //------------------------
1442 // DNMI-NEurope.grb
1443 //------------------------
1444 else if (id_center == 7 && id_model == 88 && id_grid == 255) { // saildocs
1445 data_center_model = NOAA_NCEP_WW3;
1446 }
1447 //----------------------------
1448 // NOAA RTOFS
1449 //--------------------------------
1450 else if (id_center == 7 && id_model == 45 && id_grid == 255) {
1451 data_center_model = NOAA_RTOFS;
1452 }
1453 //----------------------------------------------
1454 // NCEP sea surface temperature
1455 //----------------------------------------------
1456 else if ((id_center == 7 && id_model == 44 && id_grid == 173) ||
1457 (id_center == 7 && id_model == 44 && id_grid == 235)) {
1458 data_center_model = NOAA_NCEP_SST;
1459 }
1460 //----------------------------------------------
1461 // FNMOC WW3 mediterranean sea
1462 //----------------------------------------------
1463 else if (id_center == 58 && id_model == 111 && id_grid == 179) {
1464 data_center_model = FNMOC_WW3_MED;
1465 }
1466 //----------------------------------------------
1467 // FNMOC WW3
1468 //----------------------------------------------
1469 else if (id_center == 58 && id_model == 110 && id_grid == 240) {
1470 data_center_model = FNMOC_WW3_GLB;
1471 }
1472 //------------------------
1473 // Meteorem (Scannav)
1474 //------------------------
1475 else if (id_center == 59 && id_model == 78 && id_grid == 255) {
1476 // data_center_model = ??
1477 if ((GetDataType() == GRB_WIND_VX || GetDataType() == GRB_WIND_VY) &&
1478 GetLevelType() == LV_MSL && GetLevelValue() == 0) {
1479 level_type = LV_ABOV_GND;
1480 level_value = 10;
1481 }
1482 if (GetDataType() == GRB_PRECIP_TOT && GetLevelType() == LV_MSL &&
1483 GetLevelValue() == 0) {
1484 level_type = LV_GND_SURF;
1485 level_value = 0;
1486 }
1487 } else if (id_center == 84 && id_model <= 5 && id_grid == 0) {
1488 }
1489 // MeteoFrance
1490 else if (id_center == 85) {
1491 if (data_type == GRB_CLOUD_TOT && level_type == LV_GND_SURF &&
1492 level_value == 0) {
1493 level_type = LV_ATMOS_ALL;
1494 }
1495 }
1496
1497 //------------------------
1498 // Unknown center
1499 //------------------------
1500 else {
1501 data_center_model = OTHER_DATA_CENTER;
1502 // printf("Uncorrected GribRecord: ");
1503 // this->print();
1504 // this->known_data = false;
1505 }
1506 // translate significant wave height and dir
1507 if (this->known_data) {
1508 switch (level_type) {
1509 case 100: // LV_ISOBARIC
1510 /* GRIB1 is in hectoPascal
1511 GRIB2 in Pascal, convert to GRIB1
1512 */
1513 level_value = level_value / 100;
1514 break;
1515 case 103:
1516 level_type = LV_ABOV_GND;
1517 break;
1518 case 101:
1519 level_type = LV_MSL;
1520 break;
1521 }
1522 switch (GetDataType()) {
1523 case GRB_WIND_GUST:
1524 level_type = LV_GND_SURF;
1525 level_value = 0;
1526 break;
1527 case GRB_UOGRD:
1528 case GRB_VOGRD:
1529 break;
1530 case GRB_WVHGT:
1531 case GRB_HTSGW:
1532 case GRB_WVDIR:
1533 case GRB_WVPER:
1534 case GRB_DIR:
1535 case GRB_PER:
1536 level_type = LV_GND_SURF;
1537 level_value = 0;
1538 break;
1539 }
1540 }
1541 // this->print();
1542}
1543
1544// -------------------------------------
1545void GribV2Record::readDataSet(ZUFILE *file) {
1546 bool skip = false;
1547 bool DS = false;
1548 int len, sec_num;
1549
1550 data = nullptr;
1551 bms_bits = nullptr;
1552 hasBMS = false;
1553 known_data = false;
1554 is_duplicated = false;
1555
1556 while (strncmp(&((char *)grib_msg->buffer)[grib_msg->offset / 8], "7777",
1557 4) != 0) {
1558 DS = false;
1559 getBits(grib_msg->buffer, &len, grib_msg->offset, 32);
1560 getBits(grib_msg->buffer, &sec_num, grib_msg->offset + 4 * 8, 8);
1561 switch (sec_num) {
1562 case 2: // Section 2: Local Use Section
1563 if (skip == true) break;
1564 ok = unpackLUS(grib_msg);
1565 break;
1566 case 3: // Section 3: Grid Definition Section
1567 if (skip == true) break;
1568 ok = unpackGDS(grib_msg);
1569 if (ok) {
1570 Ni = grib_msg->md.nx;
1571 Nj = grib_msg->md.ny;
1572 La1 = grib_msg->md.slat;
1573 Lo1 = grib_msg->md.slon;
1574 La2 = grib_msg->md.lats.elat;
1575 Lo2 = grib_msg->md.lons.elon;
1576 Di = grib_msg->md.xinc.loinc;
1577 Dj = grib_msg->md.yinc.lainc;
1578 scan_flags = grib_msg->md.scan_mode;
1579 is_scan_i_positive = (scan_flags & 0x80) == 0;
1580 is_scan_j_positive = (scan_flags & 0x40) != 0;
1581 is_adjacent_i = (scan_flags & 0x20) == 0;
1582 if (Lo1 >= 0 && Lo1 <= 180 && Lo2 < 0)
1583 Lo2 +=
1584 360.0; // cross the 180 deg meridien,beetwen alaska and russia
1585
1586 if (is_scan_i_positive)
1587 while (Lo1 > Lo2) { // horizontal size > 360 °
1588 Lo1 -= 360.0;
1589 }
1590 if (Lo2 > Lo1) {
1591 lon_min = Lo1;
1592 lon_max = Lo2;
1593 } else {
1594 lon_min = Lo2;
1595 lon_max = Lo1;
1596 }
1597 if (La2 > La1) {
1598 lat_min = La1;
1599 lat_max = La2;
1600 } else {
1601 lat_min = La2;
1602 lat_max = La1;
1603 }
1604 if (Ni <= 1 || Nj <= 1) {
1605 erreur("Record %d: Ni=%d Nj=%d", id, Ni, Nj);
1606 ok = false;
1607 } else {
1608 Di = (Lo2 - Lo1) / (Ni - 1);
1609 Dj = (La2 - La1) / (Nj - 1);
1610 }
1611 }
1612 break;
1613 case 4: // Section 4: Product Definition Section
1614 if (skip == true) break;
1615 ok = unpackPDS(grib_msg);
1616 if (ok) {
1617 // printf("template %d 0 meteo data cat %d data num %d\n",
1618 // grib_msg->md.pds_templ_num, grib_msg->md.param_cat,
1619 // grib_msg->md.param_num);
1620 productTemplate = grib_msg->md.pds_templ_num;
1621 dataCat = grib_msg->md.param_cat;
1622 dataNum = grib_msg->md.param_num;
1623 data_type = GRBV2_TO_DATA(productDiscipline, dataCat, dataNum);
1624 if (data_type == 255) {
1625 // printf("unused data type, skip\n");
1626 skip = true;
1627 break;
1628 }
1629
1630 level_type = grib_msg->md.lvl1_type;
1631 level_value = grib_msg->md.lvl1;
1632 if (grib_msg->md.lvl2_type == 8 && grib_msg->md.lvl1_type == 1) {
1633 // cf table 4.5: 8 Nominal top of the atmosphere
1634 level_type = LV_ATMOS_ALL;
1635 level_value = 0.;
1636 }
1637 int n_avg, n_missing;
1638
1639 if (!mapTimeRange(grib_msg, &period_p1, &period_p2, &time_range,
1640 &n_avg, &n_missing, id_center)) {
1641 skip = true;
1642 break;
1643 }
1644 periodsec = periodSeconds(grib_msg->md.time_unit, period_p1,
1645 period_p2, time_range);
1646 SetRecordCurrentDate(MakeDate(refyear, refmonth, refday, refhour,
1647 refminute, periodsec));
1648 // printf("%d %d %d %d %d %d \n",
1649 // refyear,refmonth,refday,refhour,refminute,periodsec); printf("%d
1650 // Periode %d P1=%d p2=%d %s\n", grib_msg->md.time_unit, periodsec,
1651 // period_p1,period_p2, str_cur_date);
1652 }
1653 break;
1654 case 5: // Section 5: Data Representation Section
1655 if (skip == true) break;
1656 ok = unpackDRS(grib_msg);
1657 break;
1658 case 6: // Section 6: Bit-Map Section
1659 if (skip == true) break;
1660 ok = unpackBMS(grib_msg);
1661 if (ok) {
1662 if (grib_msg->md.bmssize != 0) {
1663 hasBMS = true;
1664 bms_size = grib_msg->md.bmssize;
1665 bms_bits = new zuchar[grib_msg->md.bmssize];
1666 memcpy(bms_bits, grib_msg->md.bms, grib_msg->md.bmssize);
1667 }
1668 }
1669 break;
1670 case 7: // Section 7: Data Section
1671 if (skip == false) {
1672 ok = unpackDS(grib_msg);
1673 if (ok) {
1674 data = grib_msg->grids.gridpoints;
1675 grib_msg->grids.gridpoints = 0;
1676 }
1677 }
1678 if (grib_msg->num_grids != 1) DS = true;
1679 break;
1680 }
1681 grib_msg->offset += len * 8;
1682 if (ok == false || DS == true) break;
1683 }
1684
1685 // ok = false;
1686 if (false) {
1687 // if (true) {
1688 printf("==== GV2 %d\n", ok);
1689 printf("Lo1=%f Lo2=%f La1=%f La2=%f\n", Lo1, Lo2, La1, La2);
1690 printf("Lo1=%f Lo2=%f La1=%f La2=%f\n", grib_msg->md.slon,
1691 grib_msg->md.lons.elon, grib_msg->md.slat, grib_msg->md.lats.elat);
1692 printf("Ni=%d Nj=%d\n", Ni, Nj);
1693 printf("has_di_dj=%d Di,Dj=(%f %f)\n", has_di_dj, Di, Dj);
1694 printf("is_scan_i_positive=%d is_scan_j_positive=%d is_adjacent_i=%d\n",
1695 is_scan_i_positive, is_scan_j_positive, is_adjacent_i);
1696 printf("hasBMS=%d\n", hasBMS);
1697 }
1698 if (ok) {
1699 if (!skip) {
1700 translateDataType();
1701 SetDataType(data_type);
1702 }
1703 }
1704 if (!ok || !DS ||
1705 strncmp(&((char *)grib_msg->buffer)[grib_msg->offset / 8], "7777", 4) ==
1706 0) {
1707 delete grib_msg;
1708 grib_msg = 0;
1709 }
1710}
1711
1712// -----------------
1713GribV2Record::GribV2Record(ZUFILE *file, int id_) {
1714 id = id_;
1715 seekStart = zu_tell(file); // moved to section 0 read
1716 data = nullptr;
1717 bms_size = 0;
1718 bms_bits = nullptr;
1719 hasBMS = false;
1720 eof = false;
1721 known_data = false;
1722 is_duplicated = false;
1723 long start = seekStart;
1724
1725 grib_msg = new GRIBMessage();
1726
1727 // Pre read 4 bytes to check for length adder needed for some GRIBS (like
1728 // WRAMS and NAM)
1729 char strgrib[5];
1730 if (zu_read(file, strgrib, 4) != 4) {
1731 ok = false;
1732 eof = true;
1733 return;
1734 }
1735
1736 bool b_haveReadGRIB = false; // already read the "GRIB" of section 0 ??
1737
1738 if (strncmp(strgrib, "GRIB", 4) != 0)
1739 b_len_add_8 = true;
1740 else {
1741 b_len_add_8 = false;
1742 b_haveReadGRIB = true;
1743 }
1744
1745 // Another special case, where zero padding is used between records.
1746 if ((strgrib[0] == 0) && (strgrib[1] == 0) && (strgrib[2] == 0) &&
1747 (strgrib[3] == 0)) {
1748 b_len_add_8 = false;
1749 b_haveReadGRIB = false;
1750 }
1751 ok = readGribSection0_IS(file,
1752 b_haveReadGRIB); // Section 0: Indicator Section
1753
1754 int len, sec_num;
1755 if (ok) {
1756 unpackIDS(grib_msg); // Section 1: Identification Section
1757 int off;
1758 /* find out how many grids are in this message */
1759 off = grib_msg->offset / 8;
1760 while (strncmp(&((char *)grib_msg->buffer)[off], "7777", 4) != 0) {
1761 len = uint4(grib_msg->buffer + off);
1762 sec_num = grib_msg->buffer[off + 4];
1763 if (sec_num == 7) grib_msg->num_grids++;
1764 off += len;
1765 }
1766 } else {
1767 // seek back if V1
1768 (void)zu_seek(file, start, SEEK_SET);
1769 return;
1770 }
1771 refyear = grib_msg->yr;
1772 refmonth = grib_msg->mo;
1773 refday = grib_msg->dy;
1774 refhour = grib_msg->time / 10000;
1775 refminute = (grib_msg->time / 100) % 100;
1776 ref_date = MakeDate(refyear, refmonth, refday, refhour, refminute, 0);
1777 sprintf(str_ref_date, "%04d-%02d-%02d %02d:%02d", refyear, refmonth, refday,
1778 refhour, refminute);
1779 id_center = grib_msg->center_id;
1780 id_model = grib_msg->table_ver;
1781 id_grid = 0; // FIXME data1[6];
1782 productDiscipline = grib_msg->disc;
1783 readDataSet(file);
1784}
1785
1786// ---------------------------------------
1787bool GribV2Record::hasMoreDataSet() const {
1788 return grib_msg && grib_msg->num_grids != 1 ? true : false;
1789}
1790
1791// ---------------------------------------
1792GribV2Record *GribV2Record::GribV2NextDataSet(ZUFILE *file, int id_) {
1793 GribV2Record *rec1 = new GribV2Record(*this);
1794 // XXX should have a shallow copy constructor
1795 delete[] rec1->data;
1796 delete[] rec1->bms_bits;
1797 // new records take ownership
1798 this->grib_msg = 0;
1799 rec1->id = id_;
1800 rec1->readDataSet(file);
1801 return rec1;
1802}
1803
1804//-------------------------------------------------------------------------------
1805// Constructeur de recopie
1806//-------------------------------------------------------------------------------
1807#pragma warning(disable : 4717)
1808GribV2Record::GribV2Record(const GribRecord &rec) : GribRecord(rec) {
1809 *this = rec;
1810#pragma warning(default : 4717)
1811}
1812
1813GribV2Record::~GribV2Record() { delete grib_msg; }
1814
1815//==============================================================
1816// Lecture des données
1817//==============================================================
1818//----------------------------------------------
1819// SECTION 0: THE INDICATOR SECTION (IS)
1820//----------------------------------------------
1821static bool unpackIS(ZUFILE *fp, GRIBMessage *grib_msg) {
1822 unsigned char temp[16];
1823 int status;
1824 size_t num;
1825
1826 if (grib_msg->buffer != nullptr) {
1827 delete[] grib_msg->buffer;
1828 grib_msg->buffer = nullptr;
1829 }
1830 grib_msg->num_grids = 0;
1831
1832 if ((status = zu_read(fp, &temp[4], 12)) != 12) {
1833 return false;
1834 }
1835 grib_msg->disc = temp[6];
1836 grib_msg->ed_num = temp[7];
1837
1838 // Bail out early if this is not GRIB2
1839 if (grib_msg->ed_num != 2) return false;
1840
1841 getBits(temp, &grib_msg->total_len, 96, 32);
1842 // too small or overflow
1843 if (grib_msg->total_len < 16 || grib_msg->total_len > (INT_MAX - 4))
1844 return false;
1845
1846 grib_msg->md.nx = grib_msg->md.ny = 0;
1847 grib_msg->buffer = new unsigned char[grib_msg->total_len + 4];
1848 memcpy(grib_msg->buffer, temp, 16);
1849 num = grib_msg->total_len - 16;
1850
1851 status = zu_read(fp, &grib_msg->buffer[16], num);
1852 if (status != (int)num) return false;
1853
1854 if (strncmp(&((char *)grib_msg->buffer)[grib_msg->total_len - 4], "7777",
1855 4) != 0)
1856 fprintf(stderr, "Warning: no end section found\n");
1857
1858 grib_msg->offset = 128;
1859 return true;
1860}
1861
1862bool GribV2Record::readGribSection0_IS(ZUFILE *file, bool b_skip_initial_GRIB) {
1863 char strgrib[4];
1864 fileOffset0 = zu_tell(file);
1865
1866 if (!b_skip_initial_GRIB) {
1867 // Cherche le 1er 'G'
1868 while ((zu_read(file, strgrib, 1) == 1) && (strgrib[0] != 'G')) {
1869 }
1870
1871 if (strgrib[0] != 'G') {
1872 ok = false;
1873 eof = true;
1874 return false;
1875 }
1876 if (zu_read(file, strgrib + 1, 3) != 3) {
1877 ok = false;
1878 eof = true;
1879 return false;
1880 }
1881 if (strncmp(strgrib, "GRIB", 4) != 0) {
1882 printf("readGribSection0_IS(): Unknown file header : %c%c%c%c\n",
1883 strgrib[0], strgrib[1], strgrib[2], strgrib[3]);
1884 ok = false;
1885 eof = true;
1886 return false;
1887 }
1888 }
1889
1890 seekStart = zu_tell(file) - 4;
1891 // totalSize = readInt3(file);
1892 if (unpackIS(file, grib_msg) == false) {
1893 ok = false;
1894 eof = true;
1895 return false;
1896 }
1897
1898 edition_number = grib_msg->ed_num;
1899 if (edition_number != 2) {
1900 ok = false;
1901 eof = true;
1902 return false;
1903 }
1904
1905 return true;
1906}
1907
1908//==============================================================
1909// Fonctions utiles
1910//==============================================================
1911zuint GribV2Record::periodSeconds(zuchar unit, zuint P1, zuint P2,
1912 zuchar range) {
1913 zuint res, dur;
1914
1915 switch (unit) {
1916 case 0: // Minute
1917 res = 60;
1918 break;
1919 case 1: // Hour
1920 res = 3600;
1921 break;
1922 case 2: // Day
1923 res = 86400;
1924 break;
1925 case 10: // 3 hours
1926 res = 10800;
1927 break;
1928 case 11: // 6 hours
1929 res = 21600;
1930 break;
1931 case 12: // 12 hours
1932 res = 43200;
1933 break;
1934 case 13: // Second
1935 res = 1;
1936 break;
1937 case 3: // Month
1938 case 4: // Year
1939 case 5: // Decade (10 years)
1940 case 6: // Normal (30 years)
1941 case 7: // Century (100 years)
1942 default:
1943 erreur("id=%d: unknown time unit in PDS b18=%d", id, unit);
1944 res = 0;
1945 ok = false;
1946 }
1947 grib_debug("id=%d: PDS unit %d (time range) b21=%d %d P1=%d P2=%d\n", id,
1948 unit, range, res, P1, P2);
1949 dur = 0;
1950
1951 switch (range) {
1952 case 0:
1953 dur = (zuint)P1;
1954 break;
1955 case 1:
1956 dur = 0;
1957 break;
1958
1959 case 2:
1960 case 3: // Average (reference time + P1 to reference time + P2)
1961 // dur = ((zuint)P1+(zuint)P2)/2; break; // TODO
1962 dur = (zuint)P2;
1963 break;
1964
1965 case 4: // Accumulation (reference time + P1 to reference time + P2)
1966 dur = (zuint)P2;
1967 break;
1968
1969 case 10:
1970 dur = ((zuint)P1 << 8) + (zuint)P2;
1971 break;
1972 default:
1973 erreur("id=%d: unknown time range in PDS b21=%d", id, range);
1974 dur = 0;
1975 ok = false;
1976 }
1977 return res * dur;
1978}
1979
1980//===============================================================================================
A meteorological data grid from a GRIB (Gridded Binary) file.
bool eof
Signals when the end of the GRIB file has been reached during parsing.
zuint periodsec
Forecast period in seconds.
bool is_duplicated
Indicates if this record was created through copying rather than direct reading.
double Lo2
Grid end coordinates.
zuint period_p1
Time range indicators for this forecast step.
double Lo1
Grid origin coordinates.
zuchar id_model
Model identifier within the originating center.
zuchar GetDataType() const
Returns the type of meteorological parameter stored in this grid.
zuchar id_grid
Grid identifier used by the originating center.
bool ok
Indicates record validity.
int id
Unique identifier for this record.
bool hasBMS
Indicates presence of a bitmap section.
zuint level_value
Numeric value associated with level_type.
zuint GetLevelValue() const
Returns the numeric value associated with the level type.
zuint refyear
Components of the reference time for this forecast.
zuchar data_type
Parameter identifier as defined by GRIB tables.
time_t ref_date
Unix timestamp of model initialization time.
zuchar level_type
Vertical level type indicator.
bool known_data
Indicates whether the data type in this record is recognized by the parser.
int data_center_model
Identifies the numerical weather model that produced this data.
zuchar id_center
Originating center ID as defined by WMO common table C-1.
zuchar edition_number
GRIB edition number, indicating the version of the GRIB specification used.
zuchar time_range
Statistical processing indicator.
zuchar GetLevelType() const
Returns the type of vertical level for this grid's data.
GRIB Version 2 Record Implementation.