OpenCPN Partial API docs
Loading...
Searching...
No Matches
GribReader.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 "GribReader.h"
29#include "GribV1Record.h"
30#include "GribV2Record.h"
31#include <cassert>
32
33//-------------------------------------------------------------------------------
34GribReader::GribReader() {
35 ok = false;
36 dewpointDataStatus = NO_DATA_IN_FILE;
37}
38//-------------------------------------------------------------------------------
39GribReader::GribReader(const wxString fname) {
40 ok = false;
41 dewpointDataStatus = NO_DATA_IN_FILE;
42 if (fname != _T("")) {
43 openFile(fname);
44 } else {
45 clean_all_vectors();
46 }
47}
48//-------------------------------------------------------------------------------
49GribReader::~GribReader() {
50 clean_all_vectors();
51 if (file != nullptr) {
52 zu_close(file);
53 file = nullptr;
54 }
55}
56
57//-------------------------------------------------------------------------------
58void GribReader::clean_all_vectors() {
59 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
60 for (it = mapGribRecords.begin(); it != mapGribRecords.end(); it++) {
61 std::vector<GribRecord *> *ls = (*it).second;
62 clean_vector(*ls);
63 delete ls;
64 }
65 mapGribRecords.clear();
66}
67//-------------------------------------------------------------------------------
68void GribReader::clean_vector(std::vector<GribRecord *> &ls) {
69 std::vector<GribRecord *>::iterator it;
70 for (it = ls.begin(); it != ls.end(); it++) {
71 delete *it;
72 *it = nullptr;
73 }
74 ls.clear();
75}
76
77//---------------------------------------------------------------------------------
78void GribReader::storeRecordInMap(GribRecord *rec) {
79#if 0
80 fprintf(stderr,
81 "GribReader: STORE record type: dataType=%d levelType=%d levelValue=%d idCenter==%d && idModel==%d && idGrid==%d\n",
82 rec->getDataType(), rec->getLevelType(), rec->getLevelValue(),
83 rec->getIdCenter(), rec->getIdModel(), rec->getIdGrid()
84 );
85#endif
86 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
87 it = mapGribRecords.find(rec->getKey());
88 if (it == mapGribRecords.end()) {
89 mapGribRecords[rec->getKey()] = new std::vector<GribRecord *>;
90 assert(mapGribRecords[rec->getKey()]);
91 }
92 mapGribRecords[rec->getKey()]->push_back(rec);
93}
94
95//---------------------------------------------------------------------------------
96static bool RecordIsWind(GribRecord *rec) {
97 return rec->getDataType() == GRB_WIND_VX ||
98 rec->getDataType() == GRB_WIND_VY ||
99 rec->getDataType() == GRB_WIND_DIR ||
100 rec->getDataType() == GRB_WIND_SPEED;
101}
102
103//---------------------------------------------------------------------------------
104static bool RecordIsGust(GribRecord *rec) {
105 return rec->getDataType() == GRB_WIND_GUST_VX ||
106 rec->getDataType() == GRB_WIND_GUST_VY ||
107 rec->getDataType() == GRB_WIND_GUST;
108}
109
110static bool RecordIsCurrent(GribRecord *rec) {
111 return rec->getDataType() == GRB_UOGRD || rec->getDataType() == GRB_VOGRD ||
112 rec->getDataType() == GRB_CUR_DIR ||
113 rec->getDataType() == GRB_CUR_SPEED;
114}
115
116void GribReader::readAllGribRecords() {
117 //--------------------------------------------------------
118 // Lecture de l'ensemble des GribRecord du fichier
119 // et stockage dans les listes appropriées.
120 //--------------------------------------------------------
121 GribRecord *rec = nullptr;
122 GribRecord *prevDataSet = nullptr;
123 int id = 0;
124 time_t firstdate = -1;
125 bool b_EOF;
126 bool is_v2 = false;
127
128 do {
129 id++;
130 // use the previously seen record type first
131 // a miss with compressed file is really slow as
132 // seek may mean re reading and decompressing the
133 // file from the start
134
135 if (is_v2 == false) {
136 rec = new GribV1Record(file, id);
137 if (rec->isOk() == false) {
138 delete rec;
139 rec = new GribV2Record(file, id);
140 is_v2 = rec->isOk();
141 }
142 } else {
143 GribV2Record *rec2 = dynamic_cast<GribV2Record *>(rec);
144 if (rec2 && rec2->hasMoreDataSet()) {
145 rec = rec2->GribV2NextDataSet(file, id);
146 delete prevDataSet;
147 } else {
148 rec = new GribV2Record(file, id);
149 }
150
151 is_v2 = rec->isOk();
152 if (rec->isOk() == false) {
153 delete rec;
154 rec = new GribV1Record(file, id);
155 }
156 }
157 prevDataSet = nullptr;
158 if (rec->isOk() == false) {
159 delete rec;
160 break;
161 }
162 b_EOF = rec->isEof();
163
164 if (!rec->isDataKnown()) {
165 GribV2Record *rec2 = dynamic_cast<GribV2Record *>(rec);
166 if (rec2 == nullptr || !rec2->hasMoreDataSet()) {
167 delete rec;
168 rec = nullptr;
169 } else { // must delete it in the next iteration
170 prevDataSet = rec;
171 }
172 continue;
173 }
174 ok = true; // au moins 1 record ok
175
176 if (firstdate == -1) firstdate = rec->getRecordCurrentDate();
177
178 if ((rec->getDataType() == GRB_PRESSURE && rec->getLevelValue() == 0 &&
179 (rec->getLevelType() == LV_MSL ||
180 rec->getLevelType() == LV_GND_SURF)) ||
181 (RecordIsWind(rec) && rec->getLevelType() == LV_ABOV_GND &&
182 rec->getLevelValue() == 10) ||
183 (RecordIsWind(rec) &&
184 rec->getLevelType() == LV_ISOBARIC // wind at x hpa
185 && (rec->getLevelValue() == 850 || rec->getLevelValue() == 700 ||
186 rec->getLevelValue() == 500 || rec->getLevelValue() == 300)))
187 storeRecordInMap(rec);
188
189 else if ((RecordIsGust(rec) && rec->getLevelType() == LV_GND_SURF &&
190 rec->getLevelValue() == 0))
191 storeRecordInMap(rec);
192
193 else if (RecordIsWind(rec) && rec->getLevelType() == LV_GND_SURF)
194 storeRecordInMap(rec);
195
196 else if (rec->getDataType() == GRB_TEMP // Air temperature at 2m
197 && rec->getLevelType() == LV_ABOV_GND && rec->getLevelValue() == 2)
198 storeRecordInMap(rec);
199
200 else if (rec->getDataType() == GRB_TEMP // Air temperature at x hpa
201 && rec->getLevelType() == LV_ISOBARIC &&
202 (rec->getLevelValue() == 850 || rec->getLevelValue() == 700 ||
203 rec->getLevelValue() == 500 || rec->getLevelValue() == 300))
204 storeRecordInMap(rec);
205
206 else if (rec->getDataType() == GRB_PRECIP_TOT // total rainfall
207 && rec->getLevelType() == LV_GND_SURF && rec->getLevelValue() == 0)
208 storeRecordInMap(rec);
209
210 else if (rec->getDataType() == GRB_PRECIP_RATE &&
211 rec->getLevelType() == LV_GND_SURF && rec->getLevelValue() == 0)
212 storeRecordInMap(rec);
213
214 else if ((rec->getDataType() == GRB_CLOUD_TOT // cloud cover
215 || rec->getDataType() == GRB_COMP_REFL) &&
216 rec->getLevelType() == LV_ATMOS_ALL && rec->getLevelValue() == 0)
217 storeRecordInMap(rec);
218 else if (rec->getDataType() == GRB_HTSGW) // Significant Wave Height
219 storeRecordInMap(rec);
220
221 else if (rec->getDataType() ==
222 GRB_PER) // Combined Wind Waves and Swell period
223 storeRecordInMap(rec);
224
225 else if (rec->getDataType() ==
226 GRB_DIR) // Combined Wind Waves and Swell Direction
227 storeRecordInMap(rec);
228
229 else if (rec->getDataType() == GRB_WVHGT) // Wind Wave Height
230 storeRecordInMap(rec);
231
232 else if (rec->getDataType() == GRB_WVPER) // Wind Waves period
233 storeRecordInMap(rec);
234
235 else if (rec->getDataType() == GRB_WVDIR) // Wind Waves Direction
236 storeRecordInMap(rec);
237
238 else if (rec->getDataType() == GRB_CRAIN) // Catagorical Rain 1/0
239 storeRecordInMap(rec);
240
241 else if ((rec->getDataType() == GRB_WTMP) &&
242 (rec->getLevelType() == LV_GND_SURF) &&
243 (rec->getLevelValue() == 0))
244 storeRecordInMap(rec); // rtofs Water Temp + translated gfs Water Temp
245
246 else if (RecordIsCurrent(rec)) // rtofs model sea current current
247 storeRecordInMap(rec);
248
249 else if (rec->getDataType() == GRB_CAPE &&
250 rec->getLevelType() == LV_GND_SURF &&
251 rec->getLevelValue() == 0) // Potential energy
252 storeRecordInMap(rec);
253
254 else if ((rec->getDataType() == GRB_GEOPOT_HGT &&
255 rec->getLevelType() ==
256 LV_ISOBARIC) // geopotentiel geight at x hpa
257 && (rec->getLevelValue() == 850 || rec->getLevelValue() == 700 ||
258 rec->getLevelValue() == 500 || rec->getLevelValue() == 300))
259 storeRecordInMap(rec);
260
261 else if ((rec->getDataType() == GRB_HUMID_REL &&
262 rec->getLevelType() == LV_ISOBARIC) // relative humidity at x hpa
263 && (rec->getLevelValue() == 850 || rec->getLevelValue() == 700 ||
264 rec->getLevelValue() == 500 || rec->getLevelValue() == 300))
265 storeRecordInMap(rec);
266
267 else {
268 GribV2Record *rec2 = dynamic_cast<GribV2Record *>(rec);
269#if 0
270 fprintf(stderr,
271 "GribReader: unknown record type: dataType=%d levelType=%d levelValue=%d idCenter==%d && idModel==%d && idGrid==%d\n",
272 rec->getDataType(), rec->getLevelType(), rec->getLevelValue(),
273 rec->getIdCenter(), rec->getIdModel(), rec->getIdGrid()
274 );
275#endif
276 if (rec2 == nullptr || !rec2->hasMoreDataSet()) {
277 delete rec;
278 rec = nullptr;
279 } else {
280 prevDataSet = rec;
281 }
282 }
283 } while (!b_EOF);
284 delete prevDataSet;
285}
286
287//---------------------------------------------------------------------------------
288void GribReader::copyFirstCumulativeRecord(int dataType, int levelType,
289 int levelValue) {
290 time_t dateref = getRefDate();
291 GribRecord *rec = getGribRecord(dataType, levelType, levelValue, dateref);
292 if (rec == nullptr) {
293 rec = getFirstGribRecord(dataType, levelType, levelValue);
294 if (rec != nullptr) {
295 GribRecord *r2 = new GribRecord(*rec);
296 r2->setRecordCurrentDate(dateref); // 1er enregistrement factice
297 storeRecordInMap(r2);
298 }
299 }
300}
301/*
302//---------------------------------------------------------------------------------
303void GribReader::removeFirstCumulativeRecord (int dataType,int levelType,int
304levelValue)
305{
306 time_t dateref = getRefDate();
307 GribRecord *rec = getFirstGribRecord(dataType, levelType, levelValue);
308
309 if (rec!=nullptr && rec->getRecordCurrentDate() == dateref)
310 {
311 std::vector<GribRecord *> *liste = getListOfGribRecords(dataType,
312levelType, levelValue); if (liste != nullptr) { std::vector<GribRecord
313*>::iterator it; for (it=liste->begin(); it!=liste->end() && (*it)!=rec; it++)
314 {
315 }
316 if ((*it) == rec) {
317 liste->erase(it);
318 }
319 }
320 }
321}
322*/
323void GribReader::copyMissingWaveRecords(int dataType, int levelType,
324 int levelValue) {
325 std::set<time_t> setdates = getListDates();
326 std::set<time_t>::iterator itd, itd2;
327 for (itd = setdates.begin(); itd != setdates.end(); itd++) {
328 time_t date = *itd;
329 GribRecord *rec = getGribRecord(dataType, levelType, levelValue, date);
330 if (rec == nullptr) {
331 itd2 = itd;
332 itd2++; // next date
333 if (itd2 != setdates.end()) {
334 time_t date2 = *itd2;
335 GribRecord *rec2 =
336 getGribRecord(dataType, levelType, levelValue, date2);
337 if (rec2 && rec2->isOk()) {
338 // create a copied record from date2
339 GribRecord *r2 = new GribRecord(*rec2);
340 r2->setRecordCurrentDate(date);
341 storeRecordInMap(r2);
342 }
343 }
344 }
345 }
346}
347
348void GribReader::computeAccumulationRecords(int dataType, int levelType,
349 int levelValue) {
350 std::set<time_t> setdates = getListDates();
351 std::set<time_t>::reverse_iterator rit;
352 GribRecord *prev = 0;
353 int p1 = 0, p2 = 0;
354
355 if (setdates.empty()) return;
356
357 // XXX only work if P2 -P1 === time
358 for (rit = setdates.rbegin(); rit != setdates.rend(); ++rit) {
359 time_t date = *rit;
360 GribRecord *rec = getGribRecord(dataType, levelType, levelValue, date);
361 if (rec && rec->isOk()) {
362 // XXX double check reference date and timerange
363 if (prev != 0) {
364 if (prev->getPeriodP1() == rec->getPeriodP1()) {
365 // printf("substract %d %d %d\n", prev->getPeriodP1(),
366 // prev->getPeriodP2(), prev->getPeriodSec());
367 if (rec->getTimeRange() == 4) {
368 // accumulation
369 // prev = prev -rec
370 prev->Substract(*rec);
371 p1 = rec->getPeriodP2();
372 } else if (rec->getTimeRange() == 3) {
373 // average
374 // prev = (prev*d2 - rec*d1) / (double) (d2 - d1);
375 prev->Average(*rec);
376 p1 = rec->getPeriodP2();
377 }
378 }
379 // convert to mm/h
380 if (p2 > p1 && rec->getTimeRange() == 4) {
381 prev->multiplyAllData(1.0 / (p2 - p1));
382 }
383 p2 = p1 = 0;
384 }
385 prev = rec;
386 p1 = prev->getPeriodP1();
387 p2 = prev->getPeriodP2();
388 }
389 }
390 if (prev != 0 && p2 > p1 && prev->getTimeRange() == 4) {
391 // the last one
392 prev->multiplyAllData(1.0 / (p2 - p1));
393 }
394}
395
396//---------------------------------------------------------------------------------
398 copyFirstCumulativeRecord(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
399 copyFirstCumulativeRecord(GRB_PRECIP_TOT, LV_GND_SURF, 0);
400}
401/*
402//---------------------------------------------------------------------------------
403void GribReader::removeFirstCumulativeRecord()
404{
405 removeFirstCumulativeRecord(GRB_TMIN, LV_ABOV_GND, 2);
406 removeFirstCumulativeRecord(GRB_TMAX, LV_ABOV_GND, 2);
407 removeFirstCumulativeRecord(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
408 removeFirstCumulativeRecord(GRB_PRECIP_TOT, LV_GND_SURF, 0);
409 removeFirstCumulativeRecord(GRB_PRECIP_RATE, LV_GND_SURF, 0);
410 removeFirstCumulativeRecord(GRB_SNOW_CATEG, LV_GND_SURF, 0);
411 removeFirstCumulativeRecord(GRB_FRZRAIN_CATEG, LV_GND_SURF, 0);
412}
413*/
415 copyMissingWaveRecords(GRB_HTSGW, LV_GND_SURF, 0);
416 copyMissingWaveRecords(GRB_WVDIR, LV_GND_SURF, 0);
417 copyMissingWaveRecords(GRB_WVPER, LV_GND_SURF, 0);
418 copyMissingWaveRecords(GRB_DIR, LV_GND_SURF, 0);
419 copyMissingWaveRecords(GRB_PER, LV_GND_SURF, 0);
420}
421
422//---------------------------------------------------------------------------------
423void GribReader::readGribFileContent() {
424 fileSize = zu_filesize(file);
425 readAllGribRecords();
426 createListDates();
427 // hoursBetweenRecords = computeHoursBeetweenGribRecords();
428 // XXX should it be done after reading all files, rather than per file?
429 if (getNumberOfGribRecords(GRB_WIND_GUST, LV_GND_SURF, 0) == 0) {
430 for (auto date : setAllDates) {
431 GribRecord *recX = getGribRecord(GRB_WIND_GUST_VX, LV_GND_SURF, 0, date);
432 if (recX == nullptr) continue;
433
434 GribRecord *recY = getGribRecord(GRB_WIND_GUST_VY, LV_GND_SURF, 0, date);
435 if (recY == nullptr) continue;
436 GribRecord *rec = GribRecord::MagnitudeRecord(*recX, *recY);
437 rec->setDataType(GRB_WIND_GUST);
438 storeRecordInMap(rec);
439 }
440 }
441 //-----------------------------------------------------
442 // Are dewpoint data in file ?
443 // If no, compute it with Magnus-Tetens formula, if possible.
444 //-----------------------------------------------------
445 dewpointDataStatus = DATA_IN_FILE;
446 if (getNumberOfGribRecords(GRB_DEWPOINT, LV_ABOV_GND, 2) != 0) return;
447
448 dewpointDataStatus = NO_DATA_IN_FILE;
449 if (getNumberOfGribRecords(GRB_HUMID_REL, LV_ABOV_GND, 2) == 0 ||
450 getNumberOfGribRecords(GRB_TEMP, LV_ABOV_GND, 2) == 0)
451 return;
452
453 dewpointDataStatus = COMPUTED_DATA;
454 for (auto iter : setAllDates) {
455 time_t date = iter;
456 GribRecord *recModel = getGribRecord(GRB_TEMP, LV_ABOV_GND, 2, date);
457 if (recModel == nullptr) continue;
458
459 // Crée un GribRecord avec les dewpoints calculés
460 GribRecord *recDewpoint = new GribRecord(*recModel);
461 recDewpoint->setDataType(GRB_DEWPOINT);
462 for (zuint i = 0; i < (zuint)recModel->getNi(); i++) {
463 for (zuint j = 0; j < (zuint)recModel->getNj(); j++) {
464 double x, y;
465 recModel->getXY(i, j, &x, &y);
466 double dp = computeDewPoint(x, y, date);
467 recDewpoint->setValue(i, j, dp);
468 }
469 }
470 storeRecordInMap(recDewpoint);
471 }
472}
473
474//---------------------------------------------------
475int GribReader::getDewpointDataStatus(int /*levelType*/, int /*levelValue*/) {
476 return dewpointDataStatus;
477}
478
479//---------------------------------------------------
480int GribReader::getTotalNumberOfGribRecords() {
481 int nb = 0;
482 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
483 for (it = mapGribRecords.begin(); it != mapGribRecords.end(); it++) {
484 nb += (*it).second->size();
485 }
486 return nb;
487}
488
489//---------------------------------------------------
490std::vector<GribRecord *> *GribReader::getFirstNonEmptyList() {
491 std::vector<GribRecord *> *ls = nullptr;
492 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
493 for (it = mapGribRecords.begin(); ls == nullptr && it != mapGribRecords.end();
494 it++) {
495 if ((*it).second->size() > 0) ls = (*it).second;
496 }
497 return ls;
498}
499
500//---------------------------------------------------
501int GribReader::getNumberOfGribRecords(int dataType, int levelType,
502 int levelValue) {
503 std::vector<GribRecord *> *liste =
504 getListOfGribRecords(dataType, levelType, levelValue);
505 if (liste != nullptr)
506 return liste->size();
507 else
508 return 0;
509}
510
511//---------------------------------------------------------------------
512std::vector<GribRecord *> *GribReader::getListOfGribRecords(int dataType,
513 int levelType,
514 int levelValue) {
515 std::string key = GribRecord::makeKey(dataType, levelType, levelValue);
516 if (mapGribRecords.find(key) != mapGribRecords.end())
517 return mapGribRecords[key];
518 else
519 return nullptr;
520}
521//---------------------------------------------------------------------------
522double GribReader::getTimeInterpolatedValue(int dataType, int levelType,
523 int levelValue, double px,
524 double py, time_t date) {
525 GribRecord *before, *after;
526 findGribsAroundDate(dataType, levelType, levelValue, date, &before, &after);
527 return get2GribsInterpolatedValueByDate(px, py, date, before, after);
528}
529
530//------------------------------------------------------------------
531void GribReader::findGribsAroundDate(int dataType, int levelType,
532 int levelValue, time_t date,
533 GribRecord **before, GribRecord **after) {
534 // Cherche les GribRecord qui encadrent la date
535 std::vector<GribRecord *> *ls =
536 getListOfGribRecords(dataType, levelType, levelValue);
537 *before = nullptr;
538 *after = nullptr;
539 zuint nb = ls->size();
540 for (zuint i = 0; i < nb && *before == nullptr && *after == nullptr; i++) {
541 GribRecord *rec = (*ls)[i];
542 if (rec->getRecordCurrentDate() == date) {
543 *before = rec;
544 *after = rec;
545 } else if (rec->getRecordCurrentDate() < date) {
546 *before = rec;
547 } else if (rec->getRecordCurrentDate() > date && *before != nullptr) {
548 *after = rec;
549 }
550 }
551}
552
553//------------------------------------------------------------------
554double GribReader::get2GribsInterpolatedValueByDate(double px, double py,
555 time_t date,
556 GribRecord *before,
557 GribRecord *after) {
558 double val = GRIB_NOTDEF;
559 if (before != nullptr && after != nullptr) {
560 if (before == after) {
561 val = before->getInterpolatedValue(px, py);
562 } else {
563 time_t t1 = before->getRecordCurrentDate();
564 time_t t2 = after->getRecordCurrentDate();
565 if (t1 == t2) {
566 val = before->getInterpolatedValue(px, py);
567 } else {
568 double v1 = before->getInterpolatedValue(px, py);
569 double v2 = after->getInterpolatedValue(px, py);
570 if (v1 != GRIB_NOTDEF && v2 != GRIB_NOTDEF) {
571 double k = fabs((double)(date - t1) / (t2 - t1));
572 val = (1.0 - k) * v1 + k * v2;
573 }
574 }
575 }
576 }
577 return val;
578}
579
580//---------------------------------------------------
581// Premier GribRecord trouvé (pour récupérer la grille)
582GribRecord *GribReader::getFirstGribRecord() {
583 std::vector<GribRecord *> *ls = getFirstNonEmptyList();
584 if (ls != nullptr) {
585 return ls->at(0);
586 } else {
587 return nullptr;
588 }
589}
590//---------------------------------------------------
591// Premier GribRecord (par date) pour un type donné
592GribRecord *GribReader::getFirstGribRecord(int dataType, int levelType,
593 int levelValue) {
594 std::set<time_t>::iterator it;
595 GribRecord *rec = nullptr;
596 for (it = setAllDates.begin(); rec == nullptr && it != setAllDates.end();
597 it++) {
598 time_t date = *it;
599 rec = getGribRecord(dataType, levelType, levelValue, date);
600 }
601 return rec;
602}
603//---------------------------------------------------
604// Délai en heures entre 2 records
605// On suppose qu'il est fixe pour tout le fichier !!!
606// NOT USED
607double GribReader::computeHoursBeetweenGribRecords() {
608 double res = 1;
609 std::vector<GribRecord *> *ls = getFirstNonEmptyList();
610 if (ls != nullptr) {
611 time_t t0 = (*ls)[0]->getRecordCurrentDate();
612 time_t t1 = (*ls)[1]->getRecordCurrentDate();
613 res = fabs((double)(t1 - t0)) / 3600.0;
614 if (res < 1) res = 1;
615 }
616 return res;
617}
618//---------------------------------------------------
619GribRecord *GribReader::getGribRecord(int dataType, int levelType,
620 int levelValue, time_t date) {
621 std::vector<GribRecord *> *ls =
622 getListOfGribRecords(dataType, levelType, levelValue);
623 if (ls != nullptr) {
624 // Cherche le premier enregistrement à la bonne date
625 GribRecord *res = nullptr;
626 zuint nb = ls->size();
627 for (zuint i = 0; i < nb && res == nullptr; i++) {
628 if ((*ls)[i]->getRecordCurrentDate() == date) res = (*ls)[i];
629 }
630 return res;
631 } else {
632 return nullptr;
633 }
634}
635
636//-------------------------------------------------------
637// Génère la liste des dates pour lesquelles des prévisions existent
638void GribReader::createListDates() { // Le set assure l'ordre et l'unicité des
639 // dates
640 setAllDates.clear();
641 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
642 for (it = mapGribRecords.begin(); it != mapGribRecords.end(); it++) {
643 std::vector<GribRecord *> *ls = (*it).second;
644 for (zuint i = 0; i < ls->size(); i++) {
645 setAllDates.insert(ls->at(i)->getRecordCurrentDate());
646 }
647 }
648}
649
650//-------------------------------------------------------
651double GribReader::computeDewPoint(double lon, double lat, time_t now) {
652 double diewpoint = GRIB_NOTDEF;
653
654 GribRecord *recTempDiew = getGribRecord(GRB_DEWPOINT, LV_ABOV_GND, 2, now);
655 if (recTempDiew != nullptr) {
656 // GRIB file contains diew point data
657 diewpoint = recTempDiew->getInterpolatedValue(lon, lat);
658 } else {
659 // Compute diew point with Magnus-Tetens formula
660 GribRecord *recTemp = getGribRecord(GRB_TEMP, LV_ABOV_GND, 2, now);
661 GribRecord *recHumid = getGribRecord(GRB_HUMID_REL, LV_ABOV_GND, 2, now);
662 if (recTemp && recHumid) {
663 double temp = recTemp->getInterpolatedValue(lon, lat);
664 double humid = recHumid->getInterpolatedValue(lon, lat);
665 if (temp != GRIB_NOTDEF && humid != GRIB_NOTDEF) {
666 double a = 17.27;
667 double b = 237.7;
668 double t = temp - 273.15;
669 double rh = humid;
670 // if ( t>0 && t<60 && rh>0.01)
671 {
672 double alpha = a * t / (b + t) + log(rh / 100.0);
673 diewpoint = b * alpha / (a - alpha);
674 diewpoint += 273.15;
675 }
676 }
677 }
678 }
679 return diewpoint;
680}
681
682//-------------------------------------------------------------------------------
683// Lecture complète d'un fichier GRIB
684//-------------------------------------------------------------------------------
685void GribReader::openFile(const wxString fname) {
686 grib_debug("Open file: %s", (const char *)fname.mb_str());
687 fileName = fname;
688 ok = false;
689 // clean_all_vectors();
690 //--------------------------------------------------------
691 // Open the file
692 //--------------------------------------------------------
693 file = zu_open((const char *)fname.mb_str(), "rb", ZU_COMPRESS_AUTO);
694 if (file == nullptr) {
695 erreur("Can't open file: %s", (const char *)fname.mb_str());
696 return;
697 }
698 readGribFileContent();
699
700 // Look for compressed files with alternate extensions
701 if (!ok) {
702 if (file != nullptr) zu_close(file);
703 file = zu_open((const char *)fname.mb_str(), "rb", ZU_COMPRESS_BZIP);
704 if (file != nullptr) readGribFileContent();
705 }
706 if (!ok) {
707 if (file != nullptr) zu_close(file);
708 file = zu_open((const char *)fname.mb_str(), "rb", ZU_COMPRESS_GZIP);
709 if (file != nullptr) readGribFileContent();
710 }
711 if (!ok) {
712 if (file != nullptr) zu_close(file);
713 file = zu_open((const char *)fname.mb_str(), "rb", ZU_COMPRESS_NONE);
714 if (file != nullptr) readGribFileContent();
715 }
716 if (file != nullptr) {
717 zu_close(file);
718 file = nullptr;
719 }
720}
GRIB (GRIdded Binary) file reader and parser.
GRIB Version 1 Record Implementation.
GRIB Version 2 Record Implementation.
void copyMissingWaveRecords()
Fills gaps in wave-related data fields by propagating known values across missing time periods.
void copyFirstCumulativeRecord()
Initializes cumulative meteorological parameters by copying their first record values.
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
int getPeriodP1() const
Returns the start of the period (P1) used for this record.
Definition GribRecord.h:405
void getXY(int i, int j, double *x, double *y) const
Converts grid indices to longitude/latitude coordinates.
Definition GribRecord.h:562
zuchar getIdModel() const
Returns the model/process ID within the originating center.
Definition GribRecord.h:376
int getPeriodP2() const
Returns the end of the period (P2) used for this record.
Definition GribRecord.h:417
double getInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
int getNi() const
Returns the number of points in the longitude (i) direction of the grid.
Definition GribRecord.h:448
int getNj() const
Returns the number of points in the latitude (j) direction of the grid.
Definition GribRecord.h:454
zuchar getIdGrid() const
Returns the grid definition template number.
Definition GribRecord.h:387
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 getDataType() const
Returns the type of meteorological parameter stored in this grid.
Definition GribRecord.h:298
zuchar getIdCenter() const
Returns the originating center ID as defined by WMO (World Meteorological Organization).
Definition GribRecord.h:364