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