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