OpenCPN Partial API docs
Loading...
Searching...
No Matches
grib_v1_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#include "wx/wxprec.h"
26
27#ifndef WX_PRECOMP
28#include "wx/wx.h"
29#endif // precompiled headers
30
31#include <stdlib.h>
32
33#include "grib_v1_record.h"
34
35//-------------------------------------------------------------------------------
36// Adjust data type from different mete center
37//-------------------------------------------------------------------------------
38void GribV1Record::translateDataType() {
39 this->known_data = true;
40 //------------------------
41 // NOAA GFS
42 //------------------------
43 if (id_center == 7 && (id_model == 96 || id_model == 81) // NOAA
44 && (id_grid == 4 || id_grid == 255)) // Saildocs
45 {
46 data_center_model = NOAA_GFS;
47 if (data_type == GRB_PRECIP_RATE) { // mm/s -> mm/h
48 multiplyAllData(3600.0);
49 }
50 if (data_type == GRB_TEMP // gfs Water surface Temperature
51 && level_type == LV_GND_SURF && level_value == 0)
52 data_type = GRB_WTMP;
53
54 // altitude level (entire atmosphere vs entire atmosphere considered as 1
55 // level)
56 if (level_type == LV_ATMOS_ENT) {
57 level_type = LV_ATMOS_ALL;
58 }
59 }
60 //------------------------
61 // ICON DWD Saildoc
62 //------------------------
63 else if (id_center == 78 && id_model == 1 && id_grid == 255) {
64 if (data_type == GRB_TEMP // ICON Water surface Temperature
65 && level_type == LV_GND_SURF && level_value == 0)
66 data_type = GRB_WTMP;
67 }
68 //------------------------
69 // EMCF masquaraded as NOAA ?
70 //------------------------
71 else if (id_center == 7 && id_model == 64 && id_grid == 4) {
72 data_center_model = NOAA_GFS;
73 if (data_type == GRB_PRECIP_RATE) { // mm/s -> mm/h
74 multiplyAllData(3600.0);
75 }
76 }
77 //------------------------
78 // DNMI-NEurope.grb
79 //------------------------
80 else if ((id_center == 88 && id_model == 255 && id_grid == 255) ||
81 (id_center == 88 && id_model == 230 && id_grid == 255) ||
82 (id_center == 88 && id_model == 200 && id_grid == 255) ||
83 (id_center == 88 && id_model == 67 && id_grid == 255)) {
84 if (data_type == GRB_TEMP && level_type == LV_GND_SURF &&
85 level_value == 0) { // air temperature at groud level
86 level_type = LV_ABOV_GND;
87 level_value = 2;
88 }
89 data_center_model = NORWAY_METNO;
90 }
91 //------------------------
92 // WRF NMM grib.meteorologic.net
93 //------------------------
94 else if (id_center == 7 && id_model == 89 && id_grid == 255) {
95 // data_center_model ??
96 if (data_type == GRB_PRECIP_RATE) { // mm/s -> mm/h
97 multiplyAllData(3600.0);
98 }
99 } else if (id_center == 7 && id_model == 88 && id_grid == 255) { // saildocs
100 data_center_model = NOAA_NCEP_WW3;
101 }
102 //----------------------------
103 // NOAA RTOFS
104 //--------------------------------
105 else if (id_center == 7 && id_model == 45 && id_grid == 255) {
106 data_center_model = NOAA_RTOFS;
107 }
108 //----------------------------------------------
109 // NCEP sea surface temperature
110 //----------------------------------------------
111 else if ((id_center == 7 && id_model == 44 && id_grid == 173) ||
112 (id_center == 7 && id_model == 44 && id_grid == 235)) {
113 data_center_model = NOAA_NCEP_SST;
114 }
115 //----------------------------------------------
116 // FNMOC WW3 mediterranean sea
117 //----------------------------------------------
118 else if (id_center == 58 && id_model == 111 && id_grid == 179) {
119 data_center_model = FNMOC_WW3_MED;
120 }
121 //----------------------------------------------
122 // FNMOC WW3
123 //----------------------------------------------
124 else if (id_center == 58 && id_model == 110 && id_grid == 240) {
125 data_center_model = FNMOC_WW3_GLB;
126 }
127 //------------------------
128 // Meteorem (Scannav)
129 //------------------------
130 else if (id_center == 59 && id_model == 78 && id_grid == 255) {
131 // data_center_model = ??
132 if ((GetDataType() == GRB_WIND_VX || GetDataType() == GRB_WIND_VY) &&
133 GetLevelType() == LV_MSL && GetLevelValue() == 0) {
134 level_type = LV_ABOV_GND;
135 level_value = 10;
136 }
137 if (GetDataType() == GRB_PRECIP_TOT && GetLevelType() == LV_MSL &&
138 GetLevelValue() == 0) {
139 level_type = LV_GND_SURF;
140 level_value = 0;
141 }
142 }
143 //----------------------------------------------
144 // ECMWF ERA5
145 //----------------------------------------------
146 else if (id_center == 98 && (id_model == 145 || id_model == 255) &&
147 id_grid == 255 && tableVersion == 128) {
148 data_center_model = ECMWF_ERA5;
149 if (GetLevelType() == LV_ISOBARIC) { // for pressure level data
150 if (GetDataType() == 130) {
151 data_type = GRB_TEMP;
152 } else if (GetDataType() == 131) // u wind
153 {
154 data_type = GRB_WIND_VX;
155 } else if (GetDataType() == 132) // v wind
156 {
157 data_type = GRB_WIND_VY;
158 } else if (GetDataType() == 157) // rh
159 {
160 data_type = GRB_HUMID_REL;
161 } else if (GetDataType() == 129) // geopotential
162 {
163 data_type = GRB_GEOPOT_HGT;
164 multiplyAllData(0.102); // convert to geopot height
165 }
166 }
167 if (GetLevelType() == LV_GND_SURF &&
168 GetLevelValue() == 0) { // single level data
169 if (GetDataType() == 141) // Snow depth (m of water equivalent)
170 {
171 data_type = GRB_SNOW_DEPTH;
172 } else if (GetDataType() == 151) {
173 data_type = GRB_PRESSURE;
174 level_type = LV_MSL;
175 } else if (GetDataType() == 165 || GetDataType() == 166) {
176 if (GetDataType() == 165) data_type = GRB_WIND_VX;
177 if (GetDataType() == 166) data_type = GRB_WIND_VY;
178 level_type = LV_ABOV_GND;
179 level_value = 10;
180 } else if (GetDataType() == 167) {
181 data_type = GRB_TEMP;
182 level_type = LV_ABOV_GND;
183 level_value = 2;
184 } else if (GetDataType() == 168) {
185 data_type = GRB_DEWPOINT;
186 level_type = LV_ABOV_GND;
187 level_value = 2;
188 } else if (GetDataType() == 34) {
189 data_type = -1; // Sea surface temperature (K)
190 } else if (GetDataType() == 164) {
191 data_type = GRB_CLOUD_TOT;
192 level_type = LV_ATMOS_ALL;
193 multiplyAllData(
194 100.0); // ECMWF ERA5 cloud range is 0-1, but we expect 0-100
195 } else if (GetDataType() == 228) {
196 data_type = GRB_PRECIP_TOT;
197 // m/h -> mm/h
198 multiplyAllData(1000.0);
199 }
200 }
201 } else if (id_center == 98 && id_model == 145 && id_grid == 255 &&
202 tableVersion == 228) {
203 data_center_model = ECMWF_ERA5;
204 if (GetLevelType() == LV_GND_SURF && GetLevelValue() == 0) {
205 if (GetDataType() == 29) {
206 data_type = GRB_WIND_GUST;
207 // level_value = 10; // XXX really 10 but we only display 0
208 }
209 }
210 }
211 //----------------------------------------------
212 // ECMWF ERA5 WAVE
213 //----------------------------------------------
214 else if (id_center == 98 && id_model == 111 && id_grid == 255 &&
215 tableVersion == 140) {
216 data_center_model = ECMWF_ERA5;
217 switch (GetDataType()) {
218 case 229: // SWH Significant height of combined wind waves and swell (m)
219 data_type = GRB_HTSGW;
220 break;
221 case 230: // MWD Mean wave direction (Degree true)
222 data_type = GRB_WVDIR;
223 break;
224 case 232: // MWP Mean wave period (s)
225 data_type = GRB_WVPER;
226 break;
227 }
228 }
229 //------------------------
230 // EMCWF grib1...
231 //------------------------
232 else if (id_center == 98 /*&& id_model==148*/ && id_grid == 255) {
233 data_center_model = OTHER_DATA_CENTER;
234 if (data_type == GRB_PRECIP_RATE) { // mm/s -> mm/h
235 // data_type=71 level_type=1 level_value=0
236 multiplyAllData(3600.0);
237 } else if (GetDataType() == GRB_CLOUD_TOT &&
238 GetLevelType() == LV_GND_SURF && GetLevelValue() == 0) {
239 // data_type=59 level_type=1 level_value=0
240 level_type = LV_ATMOS_ALL;
241 } else if (GetDataType() == GRB_PRESSURE && GetLevelType() == LV_GND_SURF &&
242 GetLevelValue() == 0) {
243 // data_type=2 level_type=1 level_value=0
244 level_type = LV_MSL;
245 }
246 }
247 //------------------------------------------
248 // KNMI
249 // ------------------------
250 else if (id_center == 99 && id_grid == 255) {
251 if (id_model == 8) {
252 data_center_model = KNMI_HIRLAM;
253 } else if (id_model == 2) {
254 data_center_model = KNMI_HARMONIE_AROME;
255 }
256 switch (GetDataType()) {
257 case 1:
258 if (GetLevelType() == LV_ABOV_MSL) {
259 data_type = GRB_PRESSURE;
260 level_type = LV_MSL;
261 }
262 break;
263 case GRB_HUMID_REL:
264 // 0-1 -> 0-100%
265 multiplyAllData(100.0);
266 break;
267 case 162:
268 data_type = GRB_WIND_GUST_VX;
269 level_type = LV_GND_SURF;
270 level_value = 0;
271 break;
272 case 163:
273 data_type = GRB_WIND_GUST_VY;
274 level_type = LV_GND_SURF;
275 level_value = 0;
276 break;
277 case GRB_CLOUD_TOT:
278 level_type = LV_ATMOS_ALL;
279 level_value = 0;
280 multiplyAllData(100.0);
281 break;
282 case 181:
283 level_type = LV_GND_SURF;
284 level_value = 0;
285 if (GetTimeRange() == 4) {
286 data_type = GRB_PRECIP_TOT;
287 } else if (GetTimeRange() == 0) {
288 data_type = GRB_PRECIP_RATE;
289 }
290 break;
291 }
292 }
293 //------------------------
294 // Unknown center
295 //------------------------
296 else {
297 data_center_model = OTHER_DATA_CENTER;
298 // printf("Uncorrected GribRecord: ");
299 // this->print();
300 // this->known_data = false;
301 }
302 // translate significant wave height and dir
303 if (this->known_data) {
304 switch (GetDataType()) {
305 case GRB_UOGRD:
306 case GRB_VOGRD:
307 level_type = LV_GND_SURF;
308 level_value = 0;
309 break;
310 case GRB_HTSGW:
311 case GRB_WVDIR:
312 case GRB_WVPER:
313 level_type = LV_GND_SURF;
314 level_value = 0;
315 break;
316 }
317 }
318 // this->print();
319}
320
321//-------------------------------------------------------------------------------
322// Lecture depuis un fichier
323//-------------------------------------------------------------------------------
324GribV1Record::GribV1Record(ZUFILE* file, int id_) {
325 id = id_;
326 // seekStart = zu_tell(file); // moved to section 0 read
327 data = nullptr;
328 bms_bits = nullptr;
329 eof = false;
330 known_data = true;
331 is_duplicated = false;
332 long start = zu_tell(file);
333
334 // Pre read 4 bytes to check for length adder needed for some GRIBS (like
335 // WRAMS and NAM)
336 // but some Gribs has the "GRIB" header starting in second, third or fourth
337 // bytes. So for these cases let's read its one by one. If 'G' is found in 1st
338 // byte or not found at all then process as before, but if 'G' is not found in
339 // 1st byte but found in one of the next three bytes, stop reading then the
340 // read can be continued from that position in the file in the section 0 read
341 char strgrib[5];
342
343 unsigned int b_haveReadGRIB = 0; // already read the "GRIB" of section 0 ?
344
345 for (unsigned i = 0; i < 4; i++) { // read the four first bytes one by one
346 if (zu_read(file, strgrib + i, 1) != 1) { // detect end of file?
347 ok = false;
348 eof = true;
349 return;
350 } else { // search "GRIB" or at least "G"
351 if (strgrib[0] != 'G') { // if no 'G' found in the 1st byte
352 if (strgrib[i] == 'G') { // but found in the next 3 bytes
353 b_haveReadGRIB =
354 1; // stop reading.The 3 following bytes will be read in section
355 // 0 read starting at that position
356 b_len_add_8 = false;
357 break;
358 } // end 'G' found in the next bytes
359 } // end no 'G' found in 1st byte.
360 }
361 } // end reading four bytes
362
363 if (b_haveReadGRIB == 0) { // the four bytes have been read
364 if (strncmp(strgrib, "GRIB", 4) != 0)
365 b_len_add_8 = true; //"GRIB" header no valid so apply length adder.
366 // Further reading will happen
367 else {
368 b_haveReadGRIB = 2; //"GRIB" header is valid so no further reading
369 b_len_add_8 = false;
370 }
371
372 // Another special case, where zero padding is used between records.
373 if ((strgrib[0] == 0) && (strgrib[1] == 0) && (strgrib[2] == 0) &&
374 (strgrib[3] == 0)) {
375 b_len_add_8 = false;
376 b_haveReadGRIB = 0;
377 }
378 }
379
380 ok = readGribSection0_IS(file, b_haveReadGRIB);
381 if (ok) {
382 ok = readGribSection1_PDS(file);
383 zu_seek(file, fileOffset1 + sectionSize1, SEEK_SET);
384 }
385 if (ok) {
386 ok = readGribSection2_GDS(file);
387 zu_seek(file, fileOffset2 + sectionSize2, SEEK_SET);
388 }
389 if (ok) {
390 ok = readGribSection3_BMS(file);
391 zu_seek(file, fileOffset3 + sectionSize3, SEEK_SET);
392 }
393 if (ok) {
394 ok = readGribSection4_BDS(file);
395 zu_seek(file, fileOffset4 + sectionSize4, SEEK_SET);
396 }
397 if (ok) {
398 ok = readGribSection5_ES(file);
399 }
400 if (ok) {
401 zu_seek(file, seekStart + totalSize + (b_len_add_8 ? 8 : 0), SEEK_SET);
402 }
403
404 if (ok) {
405 translateDataType();
406 SetDataType(data_type);
407 } else {
408 // XXX very slow with bzip2 file
409 zu_seek(file, start, SEEK_SET);
410 }
411}
412
413//-------------------------------------------------------------------------------
414// Constructeur de recopie
415//-------------------------------------------------------------------------------
416#pragma warning(disable : 4717)
417GribV1Record::GribV1Record(const GribRecord& rec) : GribRecord(rec) {
418 *this = rec;
419#pragma warning(default : 4717)
420}
421
422GribV1Record::~GribV1Record() {}
423
424//----------------------------------------------
425static zuint readPackedBits(zuchar* buf, zuint first, zuint nbBits) {
426#if 0
427 // should test when loading nbBitsInPack?
428 if (nbBits == 0 || nbBits > 31) {
429 // x >> 32 is undefined behavior, on x86 it returns x
430 return 0;
431 }
432#endif
433 zuint oct = first / 8;
434 zuint bit = first % 8;
435
436 zuint val = (buf[oct] << 24) + (buf[oct + 1] << 16) + (buf[oct + 2] << 8) +
437 (buf[oct + 3]);
438 val = val << bit;
439 val = val >> (32 - nbBits);
440 return val;
441}
442
443//==============================================================
444// Lecture des données
445//==============================================================
446//----------------------------------------------
447// SECTION 0: THE INDICATOR SECTION (IS)
448//----------------------------------------------
449bool GribV1Record::readGribSection0_IS(ZUFILE* file,
450 unsigned int b_skip_initial_GRIB) {
451 char strgrib[4];
452 fileOffset0 = zu_tell(file);
453
454 if (b_skip_initial_GRIB == 0) {
455 // Cherche le 1er 'G'
456 while ((zu_read(file, strgrib, 1) == 1) && (strgrib[0] != 'G')) {
457 }
458
459 if (strgrib[0] != 'G') {
460 ok = false;
461 eof = true;
462 return false;
463 }
464 } else if (b_skip_initial_GRIB ==
465 1) // the first 'G' has been found previously
466 strgrib[0] = 'G';
467
468 if (b_skip_initial_GRIB == 0 ||
469 b_skip_initial_GRIB ==
470 1) { // contine to search the end of "GRIB" in the next three bytes
471 if (zu_read(file, strgrib + 1, 3) != 3) {
472 ok = false;
473 eof = true;
474 return false;
475 }
476 /* if (zu_read(file, strgrib, 4) != 4) {
477 ok = false;
478 eof = true;
479 return false;
480 }*/
481 if (strncmp(strgrib, "GRIB", 4) != 0) {
482 // erreur("readGribSection0_IS(): Unknown file header :
483 // %c%c%c%c",
484 // strgrib[0],strgrib[1],strgrib[2],strgrib[3]);
485 ok = false;
486 eof = true;
487 return false;
488 }
489 }
490
491 seekStart = zu_tell(file) - 4;
492 totalSize = readInt3(file);
493
494 edition_number = readChar(file);
495 if (edition_number != 1) {
496 ok = false;
497 eof = true;
498 return false;
499 }
500
501 return true;
502}
503//----------------------------------------------
504// SECTION 1: THE PRODUCT DEFINITION SECTION (PDS)
505//----------------------------------------------
506bool GribV1Record::readGribSection1_PDS(ZUFILE* file) {
507 fileOffset1 = zu_tell(file);
508 if (zu_read(file, data1, 28) != 28) {
509 ok = false;
510 eof = true;
511 return false;
512 }
513 sectionSize1 = makeInt3(data1[0], data1[1], data1[2]);
514 tableVersion = data1[3];
515 id_center = data1[4];
516 id_model = data1[5];
517 id_grid = data1[6];
518 hasGDS = (data1[7] & 128) != 0;
519 hasBMS = (data1[7] & 64) != 0;
520
521 data_type = data1[8]; // octet 9 = parameters and units
522 level_type = data1[9];
523 level_value = makeInt2(data1[10], data1[11]);
524
525 refyear = (data1[24] - 1) * 100 + data1[12];
526 refmonth = data1[13];
527 refday = data1[14];
528 refhour = data1[15];
529 refminute = data1[16];
530
531 ref_date = MakeDate(refyear, refmonth, refday, refhour, refminute, 0);
532 sprintf(str_ref_date, "%04d-%02d-%02d %02d:%02d", refyear, refmonth, refday,
533 refhour, refminute);
534
535 period_p1 = data1[18];
536 period_p2 = data1[19];
537 time_range = data1[20];
538 periodsec = periodSeconds(data1[17], data1[18], data1[19], time_range);
539 cur_date = MakeDate(refyear, refmonth, refday, refhour, refminute, periodsec);
540 // if (data_type == GRB_PRECIP_TOT) printf("P1=%d p2=%d\n",
541 // period_p1,period_p2);
542
543 int decim;
544 decim = (int)(((((zuint)data1[26] & 0x7F) << 8) + (zuint)data1[27]) & 0x7FFF);
545 if (data1[26] & 0x80) decim *= -1;
546 decimalFactorD = pow(10.0, decim);
547
548 // Controls
549 if (!hasGDS) {
550 erreur("Record %d: GDS not found", id);
551 ok = false;
552 }
553 if (decimalFactorD == 0) {
554 erreur("Record %d: decimalFactorD null", id);
555 ok = false;
556 }
557 return ok;
558}
559//----------------------------------------------
560// SECTION 2: THE GRID DESCRIPTION SECTION (GDS)
561//----------------------------------------------
562bool GribV1Record::readGribSection2_GDS(ZUFILE* file) {
563 if (!hasGDS) return 0;
564 fileOffset2 = zu_tell(file);
565 sectionSize2 = readInt3(file); // byte 1-2-3
566 NV = readChar(file); // byte 4
567 PV = readChar(file); // byte 5
568 grid_type = readChar(file); // byte 6
569
570 if (grid_type != 0
571 // && grid_type != 4
572 ) {
573 erreur("Record %d: unknown grid type GDS(6) : %d", id, grid_type);
574 ok = false;
575 }
576
577 Ni = readInt2(file); // byte 7-8
578 Nj = readInt2(file); // byte 9-10
579 La1 = readSignedInt3(file) / 1000.0; // byte 11-12-13
580 Lo1 = readSignedInt3(file) / 1000.0; // byte 14-15-16
581 resol_flags = readChar(file); // byte 17
582 La2 = readSignedInt3(file) / 1000.0; // byte 18-19-20
583 Lo2 = readSignedInt3(file) / 1000.0; // byte 21-22-23
584
585 if (Lo1 >= 0 && Lo1 <= 180 && Lo2 < 0) {
586 Lo2 += 360.0; // cross the 180 deg meridien,beetwen alaska and russia
587 }
588
589 Di = readSignedInt2(file) / 1000.0; // byte 24-25
590 Dj = readSignedInt2(file) / 1000.0; // byte 26-27
591
592 while (Lo1 > Lo2 && Di > 0) { // horizontal size > 360 °
593 Lo1 -= 360.0;
594 }
595 has_di_dj = (resol_flags & 0x80) != 0;
596 is_earth_spheric = (resol_flags & 0x40) == 0;
597 is_ueast_vnorth = (resol_flags & 0x08) == 0;
598
599 scan_flags = readChar(file); // byte 28
600 is_scan_i_positive = (scan_flags & 0x80) == 0;
601 is_scan_j_positive = (scan_flags & 0x40) != 0;
602 is_adjacent_i = (scan_flags & 0x20) == 0;
603
604 if (Lo2 > Lo1) {
605 lon_min = Lo1;
606 lon_max = Lo2;
607 } else {
608 lon_min = Lo2;
609 lon_max = Lo1;
610 }
611 if (La2 > La1) {
612 lat_min = La1;
613 lat_max = La2;
614 } else {
615 lat_min = La2;
616 lat_max = La1;
617 }
618 if (Ni <= 1 || Nj <= 1) {
619 erreur("Record %d: Ni=%d Nj=%d", id, Ni, Nj);
620 ok = false;
621 } else {
622 Di = (Lo2 - Lo1) / (Ni - 1);
623 Dj = (La2 - La1) / (Nj - 1);
624 }
625
626 if (false) {
627 printf("==== GV1 \n");
628 printf("Lo1=%f Lo2=%f La1=%f La2=%f\n", Lo1, Lo2, La1, La2);
629 printf("Ni=%d Nj=%d\n", Ni, Nj);
630 printf("has_di_dj=%d Di,Dj=(%f %f)\n", has_di_dj, Di, Dj);
631 printf("hasBMS=%d\n", hasBMS);
632 printf("is_scan_i_positive=%d is_scan_j_positive=%d is_adjacent_i=%d\n",
633 is_scan_i_positive, is_scan_j_positive, is_adjacent_i);
634 }
635 return ok;
636}
637
638//----------------------------------------------
639// SECTION 3: BIT MAP SECTION (BMS)
640//----------------------------------------------
641bool GribV1Record::readGribSection3_BMS(ZUFILE* file) {
642 fileOffset3 = zu_tell(file);
643 if (!hasBMS) {
644 sectionSize3 = 0;
645 return ok;
646 }
647 sectionSize3 = readInt3(file);
648 (void)readChar(file);
649 int bitMapFollows = readInt2(file);
650
651 if (bitMapFollows != 0) {
652 return ok;
653 }
654 if (sectionSize3 <= 6) {
655 ok = false;
656 return ok;
657 }
658 bms_size = sectionSize3 - 6;
659 bms_bits = new zuchar[bms_size];
660
661 for (zuint i = 0; i < bms_size; i++) {
662 bms_bits[i] = readChar(file);
663 }
664 return ok;
665}
666
667//----------------------------------------------
668// SECTION 4: BINARY DATA SECTION (BDS)
669//----------------------------------------------
670bool GribV1Record::readGribSection4_BDS(ZUFILE* file) {
671 fileOffset4 = zu_tell(file);
672 sectionSize4 = readInt3(file); // byte 1-2-3
673
674 zuchar flags = readChar(file); // byte 4
675 scaleFactorE = readSignedInt2(file); // byte 5-6
676 refValue = readFloat4(file); // byte 7-8-9-10
677 nbBitsInPack = readChar(file); // byte 11
678 scaleFactorEpow2 = pow(2., scaleFactorE);
679 unusedBitsEndBDS = flags & 0x0F;
680 isGridData = (flags & 0x80) == 0;
681 isSimplePacking = (flags & 0x80) == 0;
682 isFloatValues = (flags & 0x80) == 0;
683
684 // printf("BDS type=%3d - bits=%02d - level %3d - %d\n", data_type,
685 // nbBitsInPack, level_type,level_value);
686
687 if (!isGridData) {
688 erreur("Record %d: need grid data", id);
689 ok = false;
690 }
691 if (!isSimplePacking) {
692 erreur("Record %d: need simple packing", id);
693 ok = false;
694 }
695 if (!isFloatValues) {
696 erreur("Record %d: need double values", id);
697 ok = false;
698 }
699
700 if (!ok) {
701 return ok;
702 }
703
704 if (sectionSize4 <= 11 || sectionSize4 > INT_MAX - 4) {
705 ok = false;
706 return ok;
707 }
708 zuint startbit = 0;
709 int datasize = sectionSize4 - 11;
710 zuchar* buf =
711 new zuchar[datasize +
712 4](); // +4 pour simplifier les décalages ds readPackedBits
713
714 if (zu_read(file, buf, datasize) != datasize) {
715 erreur("Record %d: data read error", id);
716 ok = false;
717 eof = true;
718 }
719 if (!ok) {
720 delete[] buf;
721 return ok;
722 }
723
724 // Allocate memory for the data
725 data = new double[Ni * Nj];
726
727 // Read data in the order given by is_adjacent_i
728 zuint i, j, x;
729 int ind;
730 if (is_adjacent_i) {
731 for (j = 0; j < Nj; j++) {
732 for (i = 0; i < Ni; i++) {
733#if 0
734 // XXX
735 // not need because we do it in XY after recomputing Di and Dj?
736 if (!has_di_dj && !is_scan_j_positive) {
737 ind = (Nj-1 -j)*Ni+i;
738 }
739 else {
740 ind = j*Ni+i;
741 }
742#else
743 ind = j * Ni + i;
744#endif
745
746 if (HasValue(i, j)) {
747 x = readPackedBits(buf, startbit, nbBitsInPack);
748 data[ind] = (refValue + x * scaleFactorEpow2) / decimalFactorD;
749 startbit += nbBitsInPack;
750 // printf(" %d %d %f ", i,j, data[ind]);
751 } else {
752 data[ind] = GRIB_NOTDEF;
753 }
754 }
755 }
756 } else {
757 for (i = 0; i < Ni; i++) {
758 for (j = 0; j < Nj; j++) {
759#if 0
760 if (!has_di_dj && !is_scan_j_positive) {
761 ind = (Nj-1 -j)*Ni+i;
762 }
763 else {
764 ind = j*Ni+i;
765 }
766#else
767 ind = j * Ni + i;
768#endif
769
770 if (HasValue(i, j)) {
771 x = readPackedBits(buf, startbit, nbBitsInPack);
772 startbit += nbBitsInPack;
773 data[ind] = (refValue + x * scaleFactorEpow2) / decimalFactorD;
774 // printf(" %d %d %f ", i,j, data[ind]);
775 } else {
776 data[ind] = GRIB_NOTDEF;
777 }
778 }
779 }
780 }
781
782 delete[] buf;
783 return ok;
784}
785
786//----------------------------------------------
787// SECTION 5: END SECTION (ES)
788//----------------------------------------------
789bool GribV1Record::readGribSection5_ES(ZUFILE* file) {
790 char str[4];
791 if (zu_read(file, str, 4) != 4) {
792 ok = false;
793 eof = true;
794 return false;
795 }
796 if (strncmp(str, "7777", 4) != 0) {
797 erreur("Final 7777 not read: %c%c%c%c", str[0], str[1], str[2], str[3]);
798 ok = false;
799 return false;
800 }
801 return ok;
802}
803
804//==============================================================
805// Fonctions utiles
806//==============================================================
807double GribV1Record::readFloat4(ZUFILE* file) {
808 unsigned char t[4];
809 if (zu_read(file, t, 4) != 4) {
810 ok = false;
811 eof = true;
812 return 0;
813 }
814
815 double val;
816 int A = (zuint)t[0] & 0x7F;
817 int B = ((zuint)t[1] << 16) + ((zuint)t[2] << 8) + (zuint)t[3];
818
819 val = pow(2., -24) * B * pow(16., A - 64);
820 if (t[0] & 0x80)
821 return -val;
822 else
823 return val;
824}
825//----------------------------------------------
826zuchar GribV1Record::readChar(ZUFILE* file) {
827 zuchar t;
828 if (zu_read(file, &t, 1) != 1) {
829 ok = false;
830 eof = true;
831 return 0;
832 }
833 return t;
834}
835//----------------------------------------------
836int GribV1Record::readSignedInt3(ZUFILE* file) {
837 unsigned char t[3];
838 if (zu_read(file, t, 3) != 3) {
839 ok = false;
840 eof = true;
841 return 0;
842 }
843 int val = (((zuint)t[0] & 0x7F) << 16) + ((zuint)t[1] << 8) + (zuint)t[2];
844 if (t[0] & 0x80)
845 return -val;
846 else
847 return val;
848}
849//----------------------------------------------
850int GribV1Record::readSignedInt2(ZUFILE* file) {
851 unsigned char t[2];
852 if (zu_read(file, t, 2) != 2) {
853 ok = false;
854 eof = true;
855 return 0;
856 }
857 int val = (((zuint)t[0] & 0x7F) << 8) + (zuint)t[1];
858 if (t[0] & 0x80)
859 return -val;
860 else
861 return val;
862}
863//----------------------------------------------
864zuint GribV1Record::readInt3(ZUFILE* file) {
865 unsigned char t[3];
866 if (zu_read(file, t, 3) != 3) {
867 ok = false;
868 eof = true;
869 return 0;
870 }
871 return ((zuint)t[0] << 16) + ((zuint)t[1] << 8) + (zuint)t[2];
872}
873//----------------------------------------------
874zuint GribV1Record::readInt2(ZUFILE* file) {
875 unsigned char t[2];
876 if (zu_read(file, t, 2) != 2) {
877 ok = false;
878 eof = true;
879 return 0;
880 }
881 return ((zuint)t[0] << 8) + (zuint)t[1];
882}
883//----------------------------------------------
884zuint GribV1Record::makeInt3(zuchar a, zuchar b, zuchar c) {
885 return ((zuint)a << 16) + ((zuint)b << 8) + (zuint)c;
886}
887//----------------------------------------------
888zuint GribV1Record::makeInt2(zuchar b, zuchar c) {
889 return ((zuint)b << 8) + (zuint)c;
890}
891//----------------------------------------------
892zuint GribV1Record::periodSeconds(zuchar unit, zuchar P1, zuchar P2,
893 zuchar range) {
894 zuint res, dur;
895 switch (unit) {
896 case 0: // Minute
897 res = 60;
898 break;
899 case 1: // Hour
900 res = 3600;
901 break;
902 case 2: // Day
903 res = 86400;
904 break;
905 case 10: // 3 hours
906 res = 10800;
907 break;
908 case 11: // 6 hours
909 res = 21600;
910 break;
911 case 12: // 12 hours
912 res = 43200;
913 break;
914 case 254: // Second
915 res = 1;
916 break;
917 case 3: // Month
918 case 4: // Year
919 case 5: // Decade (10 years)
920 case 6: // Normal (30 years)
921 case 7: // Century (100 years)
922 default:
923 erreur("id=%d: unknown time unit in PDS b18=%d", id, unit);
924 res = 0;
925 ok = false;
926 }
927 grib_debug("id=%d: PDS unit %d (time range) b21=%d %d P1=%d P2=%d\n", id,
928 unit, range, res, P1, P2);
929 dur = 0;
930 // (grib1/5.table)
931 switch (range) {
932 case 0:
933 dur = (zuint)P1;
934 break;
935 case 1:
936 dur = 0;
937 break;
938
939 case 2:
940 case 3: // Average (reference time + P1 to reference time + P2)
941 // dur = ((zuint)P1+(zuint)P2)/2; break; // TODO
942 dur = (zuint)P2;
943 break;
944
945 case 4: // Accumulation (reference time + P1 to reference time + P2)
946 dur = (zuint)P2;
947 break;
948
949 case 10: // P1 occupies octets 19 and 20; product valid at reference time +
950 // P1
951 dur = ((zuint)P1 << 8) + (zuint)P2;
952 break;
953 default:
954 erreur("id=%d: unknown time range in PDS b21=%d", id, range);
955 dur = 0;
956 ok = false;
957 }
958 return res * dur;
959}
960
961//===============================================================================================
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.
time_t cur_date
Unix timestamp of when this forecast is valid.
bool is_duplicated
Indicates if this record was created through copying rather than direct reading.
zuchar GetTimeRange() const
Returns the time range indicator that defines how P1 and P2 should be interpreted.
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.
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 1 Record Implementation.