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