39static double interp_angle(
double a0,
double a1,
double d,
double p) {
44 double a = (1 - d) * a0 + d * a1;
45 if (a < (p == 180. ? 0. : -p)) a += 2 * p;
50void GribRecord::Print()
const {
52 "%d: id_center=%d id_model=%d id_grid=%d data_type=%d level_type=%d "
53 "level_value=%d hr=%f\n",
65 if (rec.data !=
nullptr) {
66 int size =
static_cast<int>(rec.Ni * rec.Nj);
67 this->data =
new double[size];
68 for (
int i = 0; i < size; i++) this->data[i] = rec.data[i];
70 if (rec.bms_bits !=
nullptr) {
71 int size = rec.bms_size;
72 this->bms_bits =
new zuchar[size];
73 for (
int i = 0; i < size; i++) this->bms_bits[i] = rec.bms_bits[i];
77bool GribRecord::GetInterpolatedParameters(
79 double &La2,
double &Lo2,
double &Di,
double &Dj,
int &im1,
int &jm1,
80 int &im2,
int &jm2,
int &Ni,
int &Nj,
int &rec1offi,
int &rec1offj,
81 int &rec2offi,
int &rec2offj) {
82 if (!rec1.IsOk() || !rec2.IsOk())
return false;
85 if (rec1.
GetDj() * rec2.
GetDj() <= 0)
return false;
93 La1 = wxMax(rec1.La1, rec2.La1), La2 = wxMin(rec1.La2, rec2.La2);
95 La1 = wxMin(rec1.La1, rec2.La1), La2 = wxMax(rec1.La2, rec2.La2);
104 double rec1offdi = 0, rec2offdi = 0;
105 double rec1offdj = 0., rec2offdj = 0.;
107 double iiters = rec2.Di / rec1.Di;
110 im1 = 1, im2 =
static_cast<int>(iiters);
112 im1 =
static_cast<int>(iiters), im2 = 1;
114 for (i = 0; i < iiters; i++) {
115 rec1offdi = (
Lo1 - rec1.
Lo1) / rec1.Di;
116 rec2offdi = (
Lo1 - rec2.
Lo1) / rec2.Di;
117 if (rec1offdi == floor(rec1offdi) && rec2offdi == floor(rec2offdi))
break;
119 Lo1 += wxMin(rec1.Di, rec2.Di);
124 double jiters = rec2.Dj / rec1.Dj;
127 jm1 = 1, jm2 =
static_cast<int>(jiters);
129 jm1 =
static_cast<int>(jiters), jm2 = 1;
131 for (j = 0; j < jiters; j++) {
132 rec1offdj = (La1 - rec1.La1) / rec1.Dj;
133 rec2offdj = (La1 - rec2.La1) / rec2.Dj;
134 if (rec1offdj == floor(rec1offdj) && rec2offdj == floor(rec2offdj))
break;
136 La1 += Dj < 0 ? wxMax(rec1.
GetDj(), rec2.
GetDj())
143 if (La1 * Dj > La2 * Dj ||
Lo1 >
Lo2)
return false;
146 Ni = (
Lo2 -
Lo1) / Di + 1, Nj = (La2 - La1) / Dj + 1;
149 Lo2 =
Lo1 + (Ni - 1) * Di, La2 = La1 + (Nj - 1) * Dj;
151 rec1offi = rec1offdi, rec2offi =
static_cast<int>(rec2offdi);
152 rec1offj =
static_cast<int>(rec1offdj),
153 rec2offj =
static_cast<int>(rec2offdj);
155 if (!rec1.data || !rec2.data)
return false;
166 double La1,
Lo1, La2,
Lo2, Di, Dj;
167 int im1, jm1, im2, jm2;
168 int Ni, Nj, rec1offi, rec1offj, rec2offi, rec2offj;
169 if (!GetInterpolatedParameters(rec1, rec2, La1,
Lo1, La2,
Lo2, Di, Dj, im1,
170 jm1, im2, jm2, Ni, Nj, rec1offi, rec1offj,
176 auto *data =
new double[size];
178 zuchar *BMSbits =
nullptr;
179 if (rec1.bms_bits !=
nullptr && rec2.bms_bits !=
nullptr)
180 BMSbits =
new zuchar[(Ni * Nj - 1) / 8 + 1]();
182 for (
int i = 0; i < Ni; i++)
183 for (
int j = 0; j < Nj; j++) {
185 int i1 = (j * jm1 + rec1offj) * rec1.Ni + i * im1 + rec1offi;
186 int i2 = (j * jm2 + rec2offj) * rec2.Ni + i * im2 + rec2offi;
187 double data1 = rec1.data[i1], data2 = rec2.data[i2];
188 if (data1 == GRIB_NOTDEF || data2 == GRIB_NOTDEF)
189 data[in] = GRIB_NOTDEF;
192 data[in] = (1 - d) * data1 + d * data2;
194 data[in] = interp_angle(data1, data2, d, 180.);
198 int b1 = rec1.bms_bits[i1 >> 3] & 1 << (i1 & 7);
199 int b2 = rec2.bms_bits[i2 >> 3] & 1 << (i2 & 7);
201 BMSbits[in >> 3] |= 1 << (in & 7);
203 BMSbits[in >> 3] &= ~(1 << (in & 7));
212 ret->Di = Di, ret->Dj = Dj;
213 ret->Ni = Ni, ret->Nj = Nj;
215 ret->La1 = La1, ret->La2 = La2;
219 ret->bms_bits = BMSbits;
221 ret->lat_min = wxMin(La1, La2), ret->lat_max = wxMax(La1, La2);
222 ret->lon_min =
Lo1, ret->lon_max =
Lo2;
235 double La1,
Lo1, La2,
Lo2, Di, Dj;
236 int im1, jm1, im2, jm2;
237 int Ni, Nj, rec1offi, rec1offj, rec2offi, rec2offj;
240 if (!GetInterpolatedParameters(rec1x, rec2x, La1,
Lo1, La2,
Lo2, Di, Dj, im1,
241 jm1, im2, jm2, Ni, Nj, rec1offi, rec1offj,
245 if (!rec1y.data || !rec2y.data || !rec1y.IsOk() || !rec2y.IsOk() ||
246 rec1x.Di != rec1y.Di || rec1x.Dj != rec1y.Dj || rec2x.Di != rec2y.Di ||
247 rec2x.Dj != rec2y.Dj || rec1x.Ni != rec1y.Ni || rec1x.Nj != rec1y.Nj ||
248 rec2x.Ni != rec2y.Ni || rec2x.Nj != rec2y.Nj) {
257 double *datax =
new double[size], *datay =
new double[size];
258 for (
int i = 0; i < Ni; i++) {
259 for (
int j = 0; j < Nj; j++) {
261 int i1 = (j * jm1 + rec1offj) * rec1x.Ni + i * im1 + rec1offi;
262 int i2 = (j * jm2 + rec2offj) * rec2x.Ni + i * im2 + rec2offi;
263 double data1x = rec1x.data[i1], data1y = rec1y.data[i1];
264 double data2x = rec2x.data[i2], data2y = rec2y.data[i2];
265 if (data1x == GRIB_NOTDEF || data1y == GRIB_NOTDEF ||
266 data2x == GRIB_NOTDEF || data2y == GRIB_NOTDEF) {
267 datax[in] = GRIB_NOTDEF;
268 datay[in] = GRIB_NOTDEF;
270 double data1m = sqrt(pow(data1x, 2) + pow(data1y, 2));
271 double data2m = sqrt(pow(data2x, 2) + pow(data2y, 2));
272 double datam = (1 - d) * data1m + d * data2m;
274 double data1a = atan2(data1y, data1x);
275 double data2a = atan2(data2y, data2x);
276 if (data1a - data2a > M_PI)
278 else if (data2a - data1a > M_PI)
280 double dataa = (1 - d) * data1a + d * data2a;
282 datax[in] = datam * cos(dataa);
283 datay[in] = datam * sin(dataa);
294 ret->Di = Di, ret->Dj = Dj;
295 ret->Ni = Ni, ret->Nj = Nj;
297 ret->La1 = La1, ret->La2 = La2;
301 ret->bms_bits =
nullptr;
304 ret->lat_min = wxMin(La1, La2), ret->lat_max = wxMax(La1, La2);
305 ret->lon_min =
Lo1, ret->lon_max =
Lo2;
311 rety->bms_bits =
nullptr;
322 if (rec1.data && rec2.data && rec1.Ni == rec2.Ni && rec1.Nj == rec2.Nj) {
323 int size = rec1.Ni * rec1.Nj;
324 for (
int i = 0; i < size; i++)
325 if (rec1.data[i] == GRIB_NOTDEF || rec2.data[i] == GRIB_NOTDEF)
326 rec->data[i] = GRIB_NOTDEF;
328 rec->data[i] = sqrt(pow(rec1.data[i], 2) + pow(rec2.data[i], 2));
332 if (rec1.bms_bits !=
nullptr && rec2.bms_bits !=
nullptr) {
333 if (rec1.bms_size == rec2.bms_size) {
334 int size = rec1.bms_size;
335 for (
int i = 0; i < size; i++)
336 rec->bms_bits[i] = rec1.bms_bits[i] & rec2.bms_bits[i];
345 if (pDIR->data && pSPEED->data && pDIR->Ni == pSPEED->Ni &&
346 pDIR->Nj == pSPEED->Nj) {
347 int size = pDIR->Ni * pDIR->Nj;
348 for (
int i = 0; i < size; i++) {
349 if (pDIR->data[i] != GRIB_NOTDEF && pSPEED->data[i] != GRIB_NOTDEF) {
350 double dir = pDIR->data[i];
351 double speed = pSPEED->data[i];
352 pDIR->data[i] = -speed * sin(dir * M_PI / 180.);
353 pSPEED->data[i] = -speed * cos(dir * M_PI / 180.);
366void GribRecord::Substract(
const GribRecord &rec,
bool pos) {
368 if (rec.data ==
nullptr || !rec.IsOk())
return;
370 if (data ==
nullptr || !IsOk())
return;
372 if (Ni != rec.Ni || Nj != rec.Nj)
return;
374 zuint size = Ni * Nj;
375 for (zuint i = 0; i < size; i++) {
376 if (rec.data[i] == GRIB_NOTDEF)
continue;
377 if (data[i] == GRIB_NOTDEF) {
378 data[i] = -rec.data[i];
379 if (bms_bits !=
nullptr) {
381 bms_bits[i >> 3] |= 1 << (i & 7);
385 data[i] -= rec.data[i];
386 if (data[i] < 0. && pos) {
394void GribRecord::Average(
const GribRecord &rec) {
404 if (rec.data ==
nullptr || !rec.IsOk())
return;
406 if (data ==
nullptr || !IsOk())
return;
408 if (Ni != rec.Ni || Nj != rec.Nj)
return;
415 if (d2 <= d1)
return;
417 zuint size = Ni * Nj;
418 double diff = d2 - d1;
419 for (zuint i = 0; i < size; i++) {
420 if (rec.data[i] == GRIB_NOTDEF)
continue;
421 if (data[i] == GRIB_NOTDEF)
continue;
423 data[i] = (data[i] * d2 - rec.data[i] * d1) / diff;
428void GribRecord::SetDataType(
const zuchar t) {
433std::string GribRecord::MakeKey(
434 int dataType,
int levelType,
441 k.Printf(
"%d-%d-%d", dataType, levelType, levelValue);
442 return std::string(k.mb_str());
445GribRecord::~GribRecord() {
460void GribRecord::multiplyAllData(
double k) {
461 if (!data || !IsOk())
return;
463 for (zuint j = 0; j < Nj; j++) {
464 for (zuint i = 0; i < Ni; i++) {
465 if (IsDefined(i, j)) {
466 data[j * Ni + i] *= k;
473void GribRecord::SetRecordCurrentDate(time_t t) {
476 struct tm *date = gmtime(&t);
478 zuint year = date->tm_year + 1900;
479 zuint month = date->tm_mon + 1;
480 zuint day = date->tm_mday;
481 zuint hour = date->tm_hour;
482 zuint minute = date->tm_min;
483 sprintf(str_cur_date,
"%04d-%02d-%02d %02d:%02d", year, month, day, hour,
488static bool isleapyear(zuint y) {
489 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
492time_t GribRecord::MakeDate(zuint year, zuint month, zuint day, zuint hour,
493 zuint min, zuint sec) {
494 if (year < 1970 || year > 2200 || month < 1 || month > 12 || day < 1)
499 for (zuint y = 1970; y < year; y++) {
500 r += 365 * 24 * 3600;
501 if (isleapyear(y)) r += 24 * 3600;
503 for (zuint m = 1; m < month; m++) {
506 if (isleapyear(year)) r += 24 * 3600;
507 }
else if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 ||
514 r += (day - 1) * 24 * 3600;
524 bool numericalInterpolation,
526 if (!
ok || Di == 0 || Dj == 0)
return GRIB_NOTDEF;
528 if (!IsPointInMap(px, py)) {
530 if (!IsPointInMap(px, py)) {
532 if (!IsPointInMap(px, py)) {
538 pi = (px -
Lo1) / Di;
539 pj = (py - La1) / Dj;
546 unsigned int i1 = pi + 1, j1 = pj + 1;
548 if (i1 >= Ni) i1 = i0;
550 if (j1 >= Nj) j1 = j0;
556 if (!numericalInterpolation) {
557 if (dx >= 0.5) i0 = i1;
558 if (dy >= 0.5) j0 = j1;
575 if (
GetValue(i0, j0) != GRIB_NOTDEF) nbval++;
576 if (
GetValue(i1, j0) != GRIB_NOTDEF) nbval++;
577 if (
GetValue(i0, j1) != GRIB_NOTDEF) nbval++;
578 if (
GetValue(i1, j1) != GRIB_NOTDEF) nbval++;
580 if (nbval < 3)
return GRIB_NOTDEF;
582 dx = (3.0 - 2.0 * dx) * dx * dx;
583 dy = (3.0 - 2.0 * dy) * dy * dy;
585 double xa, xb, xc, kx, ky;
597 double x1 = (1.0 - dx) * x00 + dx * x10;
598 double x2 = (1.0 - dx) * x01 + dx * x11;
599 return (1.0 - dy) * x1 + dy * x2;
601 double x1 = interp_angle(x00, x01, dx, 180.);
602 double x2 = interp_angle(x10, x11, dx, 180.);
603 return interp_angle(x1, x2, dy, 180.);
608 if (dir)
return GRIB_NOTDEF;
611 if (
GetValue(i0, j0) == GRIB_NOTDEF) {
618 }
else if (
GetValue(i0, j1) == GRIB_NOTDEF) {
625 }
else if (
GetValue(i1, j0) == GRIB_NOTDEF) {
642 if (k < 0 || k > 1)
return GRIB_NOTDEF;
644 if (k == 0)
return xa;
647 double vx = k * xb + (1 - k) * xa;
648 double vy = k * xc + (1 - k) * xa;
651 return k2 * vx + (1 - k2) * vy;
657 double py,
bool numericalInterpolation) {
658 if (!GRX || !GRY)
return false;
660 if (!GRX->
ok || !GRY->
ok || GRX->Di == 0 || GRX->Dj == 0)
return false;
662 if (!GRX->IsPointInMap(px, py) || !GRY->IsPointInMap(px, py)) {
664 if (!GRX->IsPointInMap(px, py) || !GRY->IsPointInMap(px, py)) {
666 if (!GRX->IsPointInMap(px, py) || !GRY->IsPointInMap(px, py)) {
672 pi = (px - GRX->
Lo1) / GRX->Di;
673 pj = (py - GRX->La1) / GRX->Dj;
680 unsigned int i1 = pi + 1, j1 = pj + 1;
681 if (i1 >= GRX->Ni) i1 = i0;
683 if (j1 >= GRX->Nj) j1 = j0;
689 if (!numericalInterpolation) {
691 if (dx >= 0.5) i0 = i1;
692 if (dy >= 0.5) j0 = j1;
696 if (vx == GRIB_NOTDEF || vy == GRIB_NOTDEF)
return false;
698 M = sqrt(vx * vx + vy * vy);
699 A = atan2(-vx, -vy) * 180 / M_PI;
715 if (GRY->
GetValue(i0, j0) != GRIB_NOTDEF) nbval++;
716 if (GRY->
GetValue(i1, j0) != GRIB_NOTDEF) nbval++;
717 if (GRY->
GetValue(i0, j1) != GRIB_NOTDEF) nbval++;
718 if (GRY->
GetValue(i1, j1) != GRIB_NOTDEF) nbval++;
720 if (nbval <= 3)
return false;
723 if (GRX->
GetValue(i0, j0) != GRIB_NOTDEF) nbval++;
724 if (GRX->
GetValue(i1, j0) != GRIB_NOTDEF) nbval++;
725 if (GRX->
GetValue(i0, j1) != GRIB_NOTDEF) nbval++;
726 if (GRX->
GetValue(i1, j1) != GRIB_NOTDEF) nbval++;
728 if (nbval <= 3)
return false;
730 dx = (3.0 - 2.0 * dx) * dx * dx;
731 dy = (3.0 - 2.0 * dy) * dy * dy;
740 double x00m = sqrt(x00x * x00x + x00y * x00y), x00a = atan2(x00x, x00y);
743 double x01m = sqrt(x01x * x01x + x01y * x01y), x01a = atan2(x01x, x01y);
746 double x10m = sqrt(x10x * x10x + x10y * x10y), x10a = atan2(x10x, x10y);
749 double x11m = sqrt(x11x * x11x + x11y * x11y), x11a = atan2(x11x, x11y);
751 double x0m = (1 - dx) * x00m + dx * x10m,
752 x0a = interp_angle(x00a, x10a, dx, M_PI);
754 double x1m = (1 - dx) * x01m + dx * x11m,
755 x1a = interp_angle(x01a, x11a, dx, M_PI);
757 M = (1 - dy) * x0m + dy * x1m;
758 A = interp_angle(x0a, x1a, dy, M_PI);
767 double xa, xb, xc, kx, ky;
811 double vx = k*xb + (1-k)*xa;
812 double vy = k*xc + (1-k)*xa;
815 val = k2*vx + (1-k2)*vy;
A meteorological data grid from a GRIB (Gridded Binary) file.
static bool GetInterpolatedValues(double &M, double &A, const GribRecord *GRX, const GribRecord *GRY, double px, double py, bool numericalInterpolation=true)
Gets spatially interpolated wind or current vector values at a specific latitude/longitude point.
static void Polar2UV(GribRecord *pDIR, GribRecord *pSPEED)
Converts wind or current values from polar (direction/speed) to cartesian (U/V) components.
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.
double Lo2
Grid end coordinates.
GribRecord(const GribRecord &rec)
Copy constructor performs a deep copy of the GribRecord.
double Lo1
Grid origin coordinates.
bool is_filled
Indicates whether the data array has been populated.
static GribRecord * Interpolated2DRecord(GribRecord *&rety, const GribRecord &rec1x, const GribRecord &rec1y, const GribRecord &rec2x, const GribRecord &rec2y, double d)
Creates temporally interpolated records for vector fields (wind, currents).
int GetPeriodP2() const
Returns the end of the period (P2) used for this record.
zuchar id_model
Model identifier within the originating center.
double GetValue(int i, int j) const
Returns the data value at a specific grid point.
std::string data_key
Unique string identifier constructed from data type, level type, and level value.
static GribRecord * InterpolatedRecord(const GribRecord &rec1, const GribRecord &rec2, double d, bool dir=false)
Creates a new GribRecord by temporally interpolating between two time points.
zuchar id_grid
Grid identifier used by the originating center.
bool ok
Indicates record validity.
double GetInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
bool hasBMS
Indicates presence of a bitmap section.
zuint level_value
Numeric value associated with level_type.
int GetPeriodP1() const
Returns the start of the period (P1) used for this record.
zuchar data_type
Parameter identifier as defined by GRIB tables.
double GetDj() const
Returns the grid spacing in latitude (j) direction in degrees.
time_t ref_date
Unix timestamp of model initialization time.
zuchar level_type
Vertical level type indicator.
zuchar id_center
Originating center ID as defined by WMO common table C-1.
double GetDi() const
Returns the grid spacing in longitude (i) direction in degrees.
GRIB Record Base Class Implementation.