RCube
Rcube Rest Server calculates sail routes based on Grib files and sailing boat polar files
Loading...
Searching...
No Matches
r3grib.c
Go to the documentation of this file.
1
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <stdbool.h>
6#include <time.h>
7#include <math.h>
8#include <sys/stat.h>
9#include <locale.h>
10#include "glibwrapper.h"
11#include "r3types.h"
12#include "r3util.h"
13#include "inline.h"
14#include "readgriball.h"
15
16#define EPSILON 0.001 // for approximat value
17
19double zoneTimeDiff (const Zone *zone1, const Zone *zone0) {
20 if (zone1->wellDefined && zone0->wellDefined) {
21 time_t time1 = gribDateTimeToEpoch (zone1->dataDate [0], zone1->dataTime [0]);
22 time_t time0 = gribDateTimeToEpoch (zone0->dataDate [0], zone0->dataTime [0]);
23 return (time1 - time0) / 3600.0;
24 }
25 else return 0;
26}
27
33float *buildUVGWarray(const Zone *zone, const char *initialOfNames, const FlowP *gribData, size_t *outNValues) {
34 size_t nPoints = zone->nTimeStamp * zone->nbLat * zone->nbLon;
35 *outNValues = 0;
36 if (! strchr(initialOfNames, 'u') || ! strchr(initialOfNames, 'v')) { // u, v should be present
37 return NULL;
38 }
39 bool hasG = (strchr(initialOfNames, 'g') != NULL);
40 bool hasW = (strchr(initialOfNames, 'w') != NULL);
41 size_t nComp = 2; // u, v
42 if (hasG) nComp += 1;
43 if (hasW) nComp += 1;
44
45 size_t nValues = nPoints * nComp;
46
47 float *arr = malloc(nValues * sizeof(float));
48 if (!arr) return NULL;
49
50 size_t idx = 0;
51 long iGrib;
52
53 for (size_t k = 0; k < zone->nTimeStamp; k++) {
54 for (long i = 0; i < zone->nbLat; i++) {
55 for (long j = 0; j < zone->nbLon; j++) {
56 iGrib = (k * zone->nbLat * zone->nbLon) + (i * zone->nbLon) + j;
57 arr[idx++] = gribData[iGrib].u; // u allways sent
58 arr[idx++] = gribData[iGrib].v; // v allways sent
59 if (hasG) arr[idx++] = gribData[iGrib].g; // g is an option
60 if (hasW) arr[idx++] = gribData[iGrib].w; // w is an option
61 }
62 }
63 }
64 *outNValues = idx;
65 return arr;
66}
67
69void printGrib (const Zone *zone, const FlowP *gribData) {
70 long iGrib;
71 printf ("printGribAll\n");
72 for (size_t k = 0; k < zone->nTimeStamp; k++) {
73 double t = zone->timeStamp [k];
74 printf ("Time: %.0lf\n", t);
75 printf ("lon lat u v g w\n");
76 for (int i = 0; i < zone->nbLat; i++) {
77 for (int j = 0; j < zone->nbLon; j++) {
78 iGrib = (k * zone->nbLat * zone->nbLon) + (i * zone->nbLon) + j;
79 printf (" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", \
80 gribData [iGrib].lon, \
81 gribData [iGrib].lat, \
82 gribData [iGrib].u, \
83 gribData [iGrib].v, \
84 gribData [iGrib].g, \
85 gribData [iGrib].w);
86 }
87 }
88 printf ("\n");
89 }
90}
91
92/* true if all value seem OK */
93static bool checkGrib (const Zone *zone, int iFlow, CheckGrib *check) {
94 const int maxUV = 100;
95 const int maxW = 20;
96 memset (check, 0, sizeof (CheckGrib));
97 for (size_t iGrib = 0; iGrib < zone->nTimeStamp * zone->nbLat * zone->nbLon; iGrib += 1) {
98 if (tGribData [iFlow] [iGrib].u == MISSING) check->uMissing += 1;
99 else if (fabs (tGribData [iFlow] [iGrib].u) > maxUV) check->uStrange += 1;
100
101 if (tGribData [iFlow] [iGrib].v == MISSING) check->vMissing += 1;
102 else if (fabs (tGribData [iFlow] [iGrib].v) > maxUV) check->vStrange += 1;
103
104 if (tGribData [iFlow] [iGrib].w == MISSING) check->wMissing += 1;
105 else if ((tGribData [iFlow] [iGrib].w > maxW) || (tGribData [iFlow] [iGrib].w < 0)) check->wStrange += 1;
106
107 if (tGribData [iFlow] [iGrib].g == MISSING) check->gMissing += 1;
108 else if ((tGribData [iFlow] [iGrib].g > maxUV) || (tGribData [iFlow] [iGrib].g < 0)) check->gStrange += 1;
109
110 if ((tGribData [iFlow] [iGrib].lat > zone->latMax) || (tGribData [iFlow] [iGrib].lat < zone->latMin) ||
111 (tGribData [iFlow] [iGrib].lon > zone->lonRight) || (tGribData [iFlow] [iGrib].lon < zone->lonLeft))
112 check->outZone += 1;
113 }
114 return (check->uMissing == 0) && (check->vMissing == 0) && (check->gMissing == 0) /* && (check->wMissing == 0)*/ &&
115 (check->uStrange == 0) && (check->vStrange == 0) && (check->gStrange == 0) && (check->wStrange == 0) &&
116 (check->outZone == 0);
117}
118
120static bool geoIntersectGrib (const Zone *zone1, const Zone *zone2) {
121 return
122 ((zone2->latMin < zone1 -> latMax) &&
123 (zone2->latMax > zone1 -> latMin) &&
124 (zone2->lonLeft < zone1 -> lonRight) &&
125 (zone2->lonRight > zone1 -> lonLeft));
126}
127
129static bool timeIntersectGrib (const Zone *zone1, const Zone *zone2) {
130 const time_t timeMin1 = gribDateTimeToEpoch (zone1->dataDate [0], zone1->dataTime [0]);
131 const time_t timeMin2 = gribDateTimeToEpoch (zone2->dataDate [0], zone2->dataTime [0]);
132 const time_t timeMax1 = timeMin1 + 3600 * (zone1-> timeStamp [zone1 -> nTimeStamp -1]);
133 const time_t timeMax2 = timeMin2 + 3600 * (zone2-> timeStamp [zone2 -> nTimeStamp -1]);
134
135 return (timeMin2 < timeMax1) && (timeMax2 > timeMin1);
136}
137
139static bool timeStepRegularGrib (const Zone *zone) {
140 if (zone->nTimeStamp < 2) return true;
141 for (size_t i = 1; i < zone->intervalLimit; i++) {
142 if ((zone->timeStamp [i] - zone->timeStamp [i-1]) != zone->intervalBegin) {
143 return false;
144 }
145 }
146 for (size_t i = zone->intervalLimit; i < zone->nTimeStamp - 1; i++) {
147 if ((zone->timeStamp [i] - zone->timeStamp [i-1]) != zone->intervalEnd) {
148 return false;
149 }
150 }
151 return true;
152}
153
155bool uvPresentGrib (const Zone *zone) {
156 bool uPresent = false, vPresent = false;
157 for (size_t i = 0; i < zone->nShortName; i++) {
158 if ((strcmp (zone->shortName [i], "10u") == 0) || (strcmp (zone->shortName [i], "u") == 0) ||
159 (strcmp (zone->shortName [i], "ucurr") == 0))
160 uPresent = true;
161 if ((strcmp (zone->shortName [i], "10v") == 0) || (strcmp (zone->shortName [i], "v") == 0) ||
162 (strcmp (zone->shortName [i], "vcurr") == 0))
163 vPresent = true;
164 }
165 return uPresent && vPresent;
166}
167
169bool isPresentGrib (const Zone *zone, const char *name) {
170 for (size_t i = 0; i < zone->nShortName; i++) {
171 if (strcmp (zone->shortName [i], name) == 0) return true;
172 }
173 return false;
174}
175
178static int consistentGrib (const Zone *zone, int iFlow, double epsilon, int *nLatSuspects, int *nLonSuspects) {
179 int n = 0;
180 long iGrib;
181 double lat, lon;
182 *nLatSuspects = 0;
183 *nLonSuspects = 0;
184 for (size_t k = 0; k < zone->nTimeStamp; k++) {
185 for (int i = 0; i < zone->nbLat; i++) {
186 for (int j = 0; j < zone->nbLon; j++) {
187 n += 1,
188 iGrib = (k * zone->nbLat * zone->nbLon) + (i * zone->nbLon) + j;
189 lat = zone->latMin + i * zone->latStep;
190 lon = zone->lonLeft + j * zone->lonStep;
191 if (! zone->anteMeridian)
192 lon = lonCanonize (lon);
193 if (fabs (lat - tGribData [iFlow][iGrib].lat) > epsilon) {
194 *nLatSuspects += 1;
195 }
196 if (fabs (lon - tGribData [iFlow][iGrib].lon) > epsilon) {
197 *nLonSuspects += 1;
198 }
199 }
200 }
201 }
202 return n;
203}
204
207bool checkGribInfoToStr (int type, Zone *zone, char *buffer, size_t maxLen) {
208 const double windEpsilon = 0.01;
209 const double currentEpsilon = 0.1;
210 CheckGrib sCheck;
211 int nVal = 0, nLatSuspects, nLonSuspects;
212 bool OK = true;
213 char str [MAX_SIZE_LINE] = "";
214 const char *separator = "----------------------------------------------------------------------------------";
215 snprintf (str, MAX_SIZE_LINE, "\n%s\nCheck Grib Info: %s\n%s\n", separator, (type == WIND) ? "Wind" : "Current", separator);
216 g_strlcat (buffer, str, maxLen);
217
218 if (zone->nbLat <= 0) {
219 snprintf (str, MAX_SIZE_LINE, "No %s grib available\n", (type == WIND) ? "Wind" : "Current");
220 g_strlcat (buffer, str, maxLen);
221 return true;
222 }
223 if ((zone->nDataDate != 1) || (zone->nDataTime != 1)) {
224 OK = false;
225 snprintf (str, MAX_SIZE_LINE, "Expected nDataDate = 1 and nDataTime = 1. nDataDate: %zu, nDataTime: %zu\n", zone->nDataDate, zone->nDataTime);
226 g_strlcat (buffer, str, maxLen);
227 }
228 if (zone->stepUnits != 1) {
229 OK = false;
230 snprintf (str, MAX_SIZE_LINE, "Expected stepUnits = 1, stepUnits = %ld\n", zone->stepUnits);
231 g_strlcat (buffer, str, maxLen);
232 }
233 if (zone->numberOfValues != zone->nbLon * zone->nbLat) {
234 OK = false;
235 snprintf (str, MAX_SIZE_LINE, "Expected numberofValues = nbLon x nbLat = %ld, but numberOfValues = %ld\n",\
237 g_strlcat (buffer, str, maxLen);
238 }
239 if (! (fabs ((zone->lonRight - zone->lonLeft) - zone->lonStep * (zone->nbLon - 1)) < EPSILON)) {
240 OK = false;
241 snprintf (str, MAX_SIZE_LINE, "Expected difference between lonLeft and lonRight is %.2lf, found: %.2lf\n",\
242 (zone->lonStep * (zone->nbLon - 1)), zone->lonRight - zone->lonLeft);
243 g_strlcat (buffer, str, maxLen);
244 }
245 if (! (fabs((zone->latMax - zone->latMin) - (zone->latStep * (zone->nbLat - 1)) ) < EPSILON )) {
246 OK = false;
247 snprintf (str, MAX_SIZE_LINE, "Expected difference between latMax and latMin is %.2lf, found: %.2lf\n",\
248 (zone->latStep * (zone->nbLat - 1)), zone->latMax - zone->latMin);
249 g_strlcat (buffer, str, maxLen);
250 }
251 if ((zone->nTimeStamp) < 1 ) {
252 OK = false;
253 snprintf (str, MAX_SIZE_LINE, "Expected nTimeStamp >= 1, nTimeStamp = %zu\n", zone->nTimeStamp);
254 g_strlcat (buffer, str, maxLen);
255 }
256
257 nVal = consistentGrib (zone, type, (type == WIND) ? windEpsilon : currentEpsilon, &nLatSuspects, &nLonSuspects);
258 if ((nLatSuspects > 0) || (nLonSuspects > 0)) {
259 OK = false;
260 snprintf (str, MAX_SIZE_LINE, "n Val suspect Lat: %d, ratio: %.2lf %% \n", nLatSuspects, 100 * (double)nLatSuspects/(double) (nVal));
261 g_strlcat (buffer, str, maxLen);
262 snprintf (str, MAX_SIZE_LINE, "n Val suspect Lon: %d, ratio: %.2lf %% \n", nLonSuspects, 100 * (double)nLonSuspects/(double) (nVal));
263 g_strlcat (buffer, str, maxLen);
264 }
265 snprintf (str, MAX_SIZE_LINE, "n Val Values: %d\n", nVal); // at least this line
266 g_strlcat (buffer, str, maxLen);
267 snprintf (str, MAX_SIZE_LINE, "%s\n", (zone->wellDefined) ? (zone->allTimeStepOK) ? "Wind Zone Well defined" : "All Zone TimeSteps are not defined" : "Zone Undefined");
268 g_strlcat (buffer, str, maxLen);
269
270 if (!uvPresentGrib (zone)) {
271 OK = false;
272 snprintf (str, MAX_SIZE_LINE, "lack u or v\n");
273 g_strlcat (buffer, str, maxLen);
274 }
275
276 if (! timeStepRegularGrib (zone)) {
277 OK = false;
278 snprintf (str, MAX_SIZE_LINE, "timeStep is NOT REGULAR !!!\n");
279 g_strlcat (buffer, str, maxLen);
280 }
281
282 // check grib missing or strange values and out of zone for wind
283 if (! checkGrib (zone, type, &sCheck)) {
284 OK = false;
285 snprintf (str, MAX_SIZE_LINE, "out zone Values: %d, ratio: %.2lf %% \n", sCheck.outZone, 100 * (double)sCheck.outZone/(double) (nVal));
286 g_strlcat (buffer, str, maxLen);
287
288 snprintf (str, MAX_SIZE_LINE, "u missing Values: %d, ratio: %.2lf %% \n", sCheck.uMissing, 100 * (double)sCheck.uMissing/(double) (nVal));
289 g_strlcat (buffer, str, maxLen);
290 snprintf (str, MAX_SIZE_LINE, "u strange Values: %d, ratio: %.2lf %% \n", sCheck.uStrange, 100 * (double)sCheck.uStrange/(double) (nVal));
291 g_strlcat (buffer, str, maxLen);
292
293 snprintf (str, MAX_SIZE_LINE, "v missing Values: %d, ratio: %.2lf %% \n", sCheck.vMissing, 100 * (double)sCheck.vMissing/(double) (nVal));
294 g_strlcat (buffer, str, maxLen);
295 snprintf (str, MAX_SIZE_LINE, "v strange Values: %d, ratio: %.2lf %% \n", sCheck.vStrange, 100 * (double)sCheck.vStrange/(double) (nVal));
296 g_strlcat (buffer, str, maxLen);
297
298 if (type == WIND) {
299 snprintf (str, MAX_SIZE_LINE, "w missing Values: %d, ratio: %.2lf %% \n", sCheck.wMissing, 100 * (double)sCheck.wMissing/(double) (nVal));
300 g_strlcat (buffer, str, maxLen);
301
302 snprintf (str, MAX_SIZE_LINE, "w strange Values: %d, ratio: %.2lf %% \n", sCheck.wStrange, 100 * (double)sCheck.wStrange/(double) (nVal));
303 g_strlcat (buffer, str, maxLen);
304
305 snprintf (str, MAX_SIZE_LINE, "g missing Values: %d, ratio: %.2lf %% \n", sCheck.gMissing, 100 * (double)sCheck.gMissing/(double) (nVal));
306 g_strlcat (buffer, str, maxLen);
307 snprintf (str, MAX_SIZE_LINE, "g strange Values: %d, ratio: %.2lf %% \n", sCheck.gStrange, 100 * (double)sCheck.gStrange/(double) (nVal));
308 g_strlcat (buffer, str, maxLen);
309 }
310 }
311 return OK;
312}
313
316bool checkGribToStr (bool hasCurrentGrib, char *buffer, size_t maxLen) {
317 char str [MAX_SIZE_LINE] = "";
318 buffer [0] = '\0';
319
320 bool OK = (checkGribInfoToStr (WIND, &zone, buffer, maxLen));
321 if (OK) buffer [0] = '\0';
322 if (!hasCurrentGrib) return OK;
323 if (! checkGribInfoToStr (CURRENT, &currentZone, buffer, maxLen)) OK = false;
324 if (OK) buffer [0] = '\0';
325
326 if (currentZone.nbLat > 0) { // current exist
327 // check geo intersection between current and wind
328 if (! geoIntersectGrib (&zone, &currentZone)) {
329 OK = false;
330 snprintf (str, MAX_SIZE_LINE, "\nCurrent and wind grib have no common geo\n");
331 g_strlcat (buffer, str, maxLen);
332 }
333 // check time intersection between current and wind
335 OK = false;
336 snprintf (str, MAX_SIZE_LINE, "\nCurrent and wind grib have no common time\n");
337 g_strlcat (buffer, str, maxLen);
338 }
339 }
340 return OK;
341}
342
344static inline void findTimeAround (double t, int *iTInf, int *iTSup, const Zone *zone) {
345 size_t k;
346 if (t <= zone->timeStamp [0]) {
347 *iTInf = 0;
348 *iTSup = 0;
349 return;
350 }
351 for (k = 0; k < zone->nTimeStamp; k++) {
352 if (t == zone->timeStamp [k]) {
353 *iTInf = k;
354 *iTSup = k;
355 return;
356 }
357 if (t < zone->timeStamp [k]) {
358 *iTInf = k - 1;
359 *iTSup = k;
360 return;
361 }
362 }
363 *iTInf = zone->nTimeStamp -1;
364 *iTSup = zone->nTimeStamp -1;
365}
366
368static inline double arrondiMin (double v, double step) {
369 return ((double) floor (v/step)) * step;
370}
371
373static inline double arrondiMax (double v, double step) {
374 return ((double) ceil (v/step)) * step;
375}
376
378static inline void find4PointsAround (double lat, double lon, double *latMin,
379 double *latMax, double *lonMin, double *lonMax, Zone *zone) {
380
381 *latMin = arrondiMin (lat, zone->latStep);
382 *latMax = arrondiMax (lat, zone->latStep);
383 *lonMin = arrondiMin (lon, zone->lonStep);
384 *lonMax = arrondiMax (lon, zone->lonStep);
385
386 // check limits
387 if (zone->latMin > *latMin) *latMin = zone->latMin;
388 if (zone->latMax < *latMax) *latMax = zone->latMax;
389 if (zone->lonLeft > *lonMin) *lonMin = zone->lonLeft;
390 if (zone->lonRight < *lonMax) *lonMax = zone->lonRight;
391
392 if (zone->latMax < *latMin) *latMin = zone->latMax;
393 if (zone->latMin > *latMax) *latMax = zone->latMin;
394 if (zone->lonRight < *lonMin) *lonMin = zone->lonRight;
395 if (zone->lonLeft > *lonMax) *lonMax = zone->lonLeft;
396}
397
399static inline long indLat (double lat, const Zone *zone) {
400 return (long) round ((lat - zone->latMin)/zone->latStep);
401}
402
404static inline long indLon (double lon, const Zone *zone) {
405 if (lon < zone->lonLeft) lon += 360.0;
406 return (long) round ((lon - zone->lonLeft)/zone->lonStep);
407}
408
410static bool findFlow (double lat, double lon, double t, double *rU, double *rV, \
411 double *rG, double *rW, Zone *zone, const FlowP *gribData) {
412
413 double t0,t1;
414 double latMin, latMax, lonMin, lonMax;
415 double a, b, u0, u1, v0, v1, g0, g1, w0, w1;
416 int iT0, iT1;
417 FlowP windP00, windP01, windP10, windP11;
418 if ((!zone->wellDefined) || (zone->nbLat == 0) || (! isInZone (lat, lon, zone) && par.constWindTws == 0) || (t < 0)){
419 *rU = 0, *rV = 0, *rG = 0; *rW = 0;
420 return false;
421 }
422
423 findTimeAround (t, &iT0, &iT1, zone);
424 find4PointsAround (lat, lon, &latMin, &latMax, &lonMin, &lonMax, zone);
425 //printf ("lat %lf iT0 %d, iT1 %d, latMin %lf latMax %lf lonMin %lf lonMax %lf\n", p.lat, iT0, iT1, latMin, latMax, lonMin, lonMax);
426 // 4 points at time t0
427 windP00 = gribData [iT0 * zone->nbLat * zone->nbLon + indLat(latMax, zone) * zone->nbLon + indLon(lonMin, zone)];
428 windP01 = gribData [iT0 * zone->nbLat * zone->nbLon + indLat(latMax, zone) * zone->nbLon + indLon(lonMax, zone)];
429 windP10 = gribData [iT0 * zone->nbLat * zone->nbLon + indLat(latMin, zone) * zone->nbLon + indLon(lonMax, zone)];
430 windP11 = gribData [iT0 * zone->nbLat * zone->nbLon + indLat(latMin, zone) * zone->nbLon + indLon(lonMin, zone)];
431
432 // printf ("00lat %lf 01lat %lf 10lat %lf 11lat %lf\n", windP00.lat, windP01.lat,windP10.lat,windP11.lat);
433 // printf ("00tws %lf 01tws %lf 10tws %lf 11tws %lf\n", windP00.tws, windP01.tws,windP10.tws,windP11.tws);
434 // speed longitude interpolation at northern latitudes
435
436 // interpolation for u, v, w, g
437 a = interpolate (lon, windP00.lon, windP01.lon, windP00.u, windP01.u);
438 b = interpolate (lon, windP10.lon, windP11.lon, windP10.u, windP11.u);
439 u0 = interpolate (lat, windP00.lat, windP10.lat, a, b);
440
441 a = interpolate (lon, windP00.lon, windP01.lon, windP00.v, windP01.v);
442 b = interpolate (lon, windP10.lon, windP11.lon, windP10.v, windP11.v);
443 v0 = interpolate (lat, windP00.lat, windP10.lat, a, b);
444
445 a = interpolate (lon, windP00.lon, windP01.lon, windP00.g, windP01.g);
446 b = interpolate (lon, windP10.lon, windP11.lon, windP10.g, windP11.g);
447 g0 = interpolate (lat, windP00.lat, windP10.lat, a, b);
448
449 a = interpolate (lon, windP00.lon, windP01.lon, windP00.w, windP01.w);
450 b = interpolate (lon, windP10.lon, windP11.lon, windP10.w, windP11.w);
451 w0 = interpolate (lat, windP00.lat, windP10.lat, a, b);
452
453 // 4 points at time t1
454 windP00 = gribData [iT1 * zone->nbLat * zone->nbLon + indLat(latMax, zone) * zone->nbLon + indLon(lonMin, zone)];
455 windP01 = gribData [iT1 * zone->nbLat * zone->nbLon + indLat(latMax, zone) * zone->nbLon + indLon(lonMax, zone)];
456 windP10 = gribData [iT1 * zone->nbLat * zone->nbLon + indLat(latMin, zone) * zone->nbLon + indLon(lonMax, zone)];
457 windP11 = gribData [iT1 * zone->nbLat * zone->nbLon + indLat(latMin, zone) * zone->nbLon + indLon(lonMin, zone)];
458
459 // interpolatuon for for u, v
460 a = interpolate (lon, windP00.lon, windP01.lon, windP00.u, windP01.u);
461 b = interpolate (lon, windP10.lon, windP11.lon, windP10.u, windP11.u);
462 u1 = interpolate (lat, windP00.lat, windP10.lat, a, b);
463
464 a = interpolate (lon, windP00.lon, windP01.lon, windP00.v, windP01.v);
465 b = interpolate (lon, windP10.lon, windP11.lon, windP10.v, windP11.v);
466 v1 = interpolate (lat, windP00.lat, windP10.lat, a, b);
467
468 a = interpolate (lon, windP00.lon, windP01.lon, windP00.g, windP01.g);
469 b = interpolate (lon, windP10.lon, windP11.lon, windP10.g, windP11.g);
470 g1 = interpolate (lat, windP00.lat, windP10.lat, a, b);
471
472 a = interpolate (lon, windP00.lon, windP01.lon, windP00.w, windP01.w);
473 b = interpolate (lon, windP10.lon, windP11.lon, windP10.w, windP11.w);
474 w1 = interpolate (lat, windP00.lat, windP10.lat, a, b);
475
476 // finally, interpolation twd tws between t0 and t1
477 t0 = zone->timeStamp [iT0];
478 t1 = zone->timeStamp [iT1];
479 *rU = interpolate (t, t0, t1, u0, u1);
480 *rV = interpolate (t, t0, t1, v0, v1);
481 *rG = interpolate (t, t0, t1, g0, g1);
482 *rW = interpolate (t, t0, t1, w0, w1);
483
484 return true;
485}
486
488void findWindGrib (double lat, double lon, double t, double *u, double *v, \
489 double *gust, double *w, double *twd, double *tws ) {
490 if (par.constWindTws != 0) {
491 *twd = par.constWindTwd;
492 *tws = par.constWindTws;
495 *w = 0;
496 *gust = hypot (*u, *v); // m/s
497 return;
498 }
499 findFlow (lat, lon, t, u, v, gust, w, &zone, tGribData [WIND]);
500 *twd = fTwd (*u, *v);
501 *tws = fTws (*u, *v);
502 if (par.constWave < 0) *w = 0;
503 else if (par.constWave != 0) *w = par.constWave;
504}
505
507void findCurrentGrib (double lat, double lon, double t, double *uCurr,\
508 double *vCurr, double *tcd, double *tcs) {
509
510 double gust, bidon;
511 *uCurr = 0;
512 *vCurr = 0;
513 *tcd = 0;
514 *tcs = 0;
515 if (par.constCurrentS != 0) {
518 *tcd = par.constCurrentD; // direction
519 *tcs = par.constCurrentS; // speed
520 return;
521 }
522 if (t > currentZone.timeStamp [currentZone.nTimeStamp - 1]) return;
523
524 findFlow (lat, lon, t, uCurr, vCurr, &gust, &bidon, &currentZone, tGribData [CURRENT]);
525 *tcd = fTwd (*uCurr, *vCurr);
526 *tcs = fTws (*uCurr, *vCurr);
527}
528
530char *gribToStr (const Zone *zone, char *str, size_t maxLen) {
531 char line [MAX_SIZE_LINE] = "";
532 char strTmp [MAX_SIZE_LINE] = "";
533 char strLat0 [MAX_SIZE_NAME] = "", strLon0 [MAX_SIZE_NAME] = "";
534 char strLat1 [MAX_SIZE_NAME] = "", strLon1 [MAX_SIZE_NAME] = "";
535 char centreName [MAX_SIZE_NAME] = "";
536
537 for (size_t i = 0; i < sizeof(meteoTab) / sizeof(meteoTab[0]); i++) // search name of center
538 if (meteoTab [i].id == zone->centreId)
539 g_strlcpy (centreName, meteoTab [i].name, sizeof (centreName));
540
541 newDate (zone->dataDate [0], zone->dataTime [0]/100, strTmp, sizeof (strTmp));
542 snprintf (str, maxLen, "Centre ID: %ld %s %s Ed number: %ld\nnMessages: %d\nstepUnits: %ld\n# values : %ld\n",\
544 snprintf (line, MAX_SIZE_LINE, "Zone From: %s, %s To: %s, %s\n",\
545 latToStr (zone->latMin, par.dispDms, strLat0, sizeof (strLat0)),\
546 lonToStr (zone->lonLeft, par.dispDms, strLon0, sizeof (strLon0)),\
547 latToStr (zone->latMax, par.dispDms, strLat1, sizeof (strLat1)),\
548 lonToStr (zone->lonRight, par.dispDms, strLon1, sizeof (strLon1)));
549 g_strlcat (str, line, maxLen);
550 snprintf (line, MAX_SIZE_LINE, "LatStep : %04.4f° LonStep: %04.4f°\n", zone->latStep, zone->lonStep);
551 g_strlcat (str, line, maxLen);
552 snprintf (line, MAX_SIZE_LINE, "Nb Lat : %ld Nb Lon : %ld\n", zone->nbLat, zone->nbLon);
553 g_strlcat (str, line, maxLen);
554 if (zone->nTimeStamp < 8) {
555 snprintf (line, MAX_SIZE_LINE, "TimeStamp List of %zu : [ ", zone->nTimeStamp);
556 g_strlcat (str, line, maxLen);
557 for (size_t k = 0; k < zone->nTimeStamp; k++) {
558 snprintf (line, MAX_SIZE_LINE, "%ld ", zone->timeStamp [k]);
559 g_strlcat (str, line, maxLen);
560 }
561 g_strlcat (str, "]\n", maxLen);
562 }
563 else {
564 snprintf (line, MAX_SIZE_LINE, "TimeStamp List of %zu : [%ld, %ld, ..%ld]\n", zone->nTimeStamp,\
566 g_strlcat (str, line, maxLen);
567 }
568
569 snprintf (line, MAX_SIZE_LINE, "Shortname List: [ ");
570 g_strlcat (str, line, maxLen);
571 for (size_t k = 0; k < zone->nShortName; k++) {
572 snprintf (line, MAX_SIZE_LINE, "%s ", zone->shortName [k]);
573 g_strlcat (str, line, maxLen);
574 }
575 g_strlcat (str, "]\n", maxLen);
576 if ((zone->nDataDate > 1) || (zone->nDataTime > 1)) {
577 snprintf (line, MAX_SIZE_LINE, "Warning number of Date: %zu, number of Time: %zu\n", zone->nDataDate, zone->nDataTime);
578 g_strlcat (str, line, maxLen);
579 }
580 snprintf (line, MAX_SIZE_LINE, "Zone is : %s\n", (zone->wellDefined) ? "Well defined" : "Undefined");
581 g_strlcat (str, line, maxLen);
582 return str;
583}
584
586char *gribToStrJson (const char *fileName, char *out, size_t maxLen) {
587 char gribName [MAX_SIZE_FILE_NAME];
588 char str [MAX_SIZE_TEXT] = "";
589 char infoStr [MAX_SIZE_LINE] = "";
590 struct stat st;
591 char str0 [MAX_SIZE_NAME] = "";
592 char str1 [MAX_SIZE_NAME] = "";
593 char centreName [MAX_SIZE_NAME] = "";
594 struct tm tm_buf, *tm_info;
595 char strTime [20] = "1970-01-01 00:00:00";
596 Zone gZone;
597
598 buildRootName (fileName, gribName, sizeof (gribName));
599
600 if (stat (gribName, &st) != 0) {
601 fprintf (stderr, "In gribToStrJson Error stat: %s\n", gribName);
602 snprintf (out, maxLen, "{}\n");
603 return out;
604 }
605 if (! readGribLists (gribName, &gZone)) {
606 fprintf (stderr, "In gribToStrJson Error reading: %s\n", gribName);
607 snprintf (out, maxLen, "{}\n");
608 return out;
609 }
610 if (! readGribParameters (gribName, &gZone)) {
611 fprintf (stderr, "In gribToStrJson Error reading: %s\n", gribName);
612 snprintf (out, maxLen, "{}\n");
613 return out;
614 }
615 if (gZone.nbLat == 0) {
616 fprintf (stderr, "In gribToStrJson Error no value available in: %s\n", gribName);
617 snprintf (out, maxLen, "{}\n");
618 return out;
619 }
620 for (size_t i = 0; i < N_METEO_ADMIN; i++) {// search name of center
621 if (meteoTab [i].id == gZone.centreId) {
622 g_strlcpy (centreName, meteoTab [i].name, sizeof (centreName));
623 break;
624 }
625 }
626 newDate (gZone.dataDate [0], gZone.dataTime [0]/100, str0, sizeof (str0));
627 newDate (gZone.dataDate [0], gZone.dataTime [0]/100 + gZone.timeStamp [gZone.nTimeStamp -1], str1, sizeof (str1));
628
629 snprintf (out, maxLen,
630 "{\n \"centreID\": %ld, \"centreName\": \"%s\", \"edNumber\": %ld, \n"
631 " \"runStart\": \"%s\", \"runEnd\": \"%s\", \n"
632 " \"epochStart\": %ld,\n"
633 " \"topLat\": %.6f, \"leftLon\": %.6f, \"bottomLat\": %.6f, \"rightLon\": %.6f, \n"
634 " \"latStep\": %.4f, \"lonStep\": %.4f, \n"
635 " \"nLat\": %ld, \"nLon\": %ld, \"nValues\": %ld, \"nTimeStamp\": %zu,\n"
636 " \"timeStamps\": \n [",
637 gZone.centreId, centreName, gZone.editionNumber,
638 str0, str1,
639 gribDateTimeToEpoch(gZone.dataDate[0], gZone.dataTime[0]),
640 gZone.latMax, gZone.lonLeft, gZone.latMin, gZone.lonRight,
641 gZone.latStep, gZone.lonStep,
642 gZone.nbLat, gZone.nbLon, gZone.numberOfValues, gZone.nTimeStamp
643 );
644
645 for (size_t i = 0; i < gZone.nTimeStamp; i += 1) {
646 snprintf (str, sizeof (str), "%ld%s", gZone.timeStamp [i], (i < gZone.nTimeStamp -1) ? ", " : ""); // no comma for last
647 g_strlcat (out, str, maxLen);
648 }
649 g_strlcat (out, "],\n", maxLen);
650
651 snprintf (str, sizeof (str), " \"nShortName\": %zu, \"shortNames\": [", gZone.nShortName);
652 g_strlcat (out, str, maxLen);
653
654 for (size_t i = 0; i < gZone.nShortName; i += 1) {
655 snprintf (str, sizeof (str), "\"%s\"%s", gZone.shortName [i], (i < gZone.nShortName -1) ? ", " : ""); // no comma for last
656 g_strlcat (out, str, maxLen);
657 }
658 g_strlcat (out, "],\n", maxLen);
659
660 tm_info = localtime_r (&st.st_mtime, &tm_buf);
661 if (tm_info) strftime(strTime, sizeof strTime, "%Y-%m-%d %H:%M:%S", tm_info);
662
663 char *gribBaseName = g_path_get_basename (fileName);
664 snprintf (str, sizeof (str), " \"name\": \"%s\", \"fileSize\": %ld, \"fileTime\": \"%s\",\n",
665 gribBaseName, st.st_size, strTime);
666 g_strlcat (out, str, maxLen);
667 free (gribBaseName);
668
669 if ((gZone.nDataDate != 1) || (gZone.nDataTime != 1)) {
670 snprintf (infoStr, sizeof (infoStr), "Warning number of Date: %zu, number of Time: %zu", gZone.nDataDate, gZone.nDataTime);
671 }
672 snprintf (str, sizeof (str), " \"info\": \"%s\"\n}\n", infoStr);
673 g_strlcat (out, str, maxLen);
674 return out;
675}
676
#define g_strlcat(dest, src, size)
Definition glibwrapper.h:10
#define g_strlcpy(dest, src, size)
Definition glibwrapper.h:9
static char * g_path_get_basename(const char *path)
close to Glib g_path_get_basename
static bool isInZone(double lat, double lon, Zone *zone)
true if P (lat, lon) is within the zone
Definition inline.h:47
static double interpolate(double x, double x0, double x1, double fx0, double fx1)
return fx : linear interpolation
Definition inline.h:78
static double fTwd(double u, double v)
true wind direction
Definition inline.h:52
static double lonCanonize(double lon)
return lon on ]-180, 180 ] interval
Definition inline.h:29
static double fTws(double u, double v)
true wind speed.
Definition inline.h:58
#define EPSILON
compilation: gcc -c grib.c pkg-config --cflags glib-2.0
Definition r3grib.c:16
static int consistentGrib(const Zone *zone, int iFlow, double epsilon, int *nLatSuspects, int *nLonSuspects)
check lat, lon are consistent with indice return number of values
Definition r3grib.c:178
static bool findFlow(double lat, double lon, double t, double *rU, double *rV, double *rG, double *rW, Zone *zone, const FlowP *gribData)
interpolation to get u, v, g (gust), w (waves) at point (lat, lon) and time t
Definition r3grib.c:410
bool uvPresentGrib(const Zone *zone)
true if u and v (or uCurr, vCurr) are in zone
Definition r3grib.c:155
void findCurrentGrib(double lat, double lon, double t, double *uCurr, double *vCurr, double *tcd, double *tcs)
use findflow to get current
Definition r3grib.c:507
char * gribToStr(const Zone *zone, char *str, size_t maxLen)
write Grib information in string
Definition r3grib.c:530
static long indLat(double lat, const Zone *zone)
return indice of lat in gribData wind or current
Definition r3grib.c:399
static bool timeIntersectGrib(const Zone *zone1, const Zone *zone2)
true if (wind) zone and zone 2 intersect in time
Definition r3grib.c:129
static bool checkGrib(const Zone *zone, int iFlow, CheckGrib *check)
Definition r3grib.c:93
static double arrondiMax(double v, double step)
ex arrondiMax (46.4, 0.25) = 46.50
Definition r3grib.c:373
void printGrib(const Zone *zone, const FlowP *gribData)
print Grib u v ... for all lat lon time information
Definition r3grib.c:69
static void findTimeAround(double t, int *iTInf, int *iTSup, const Zone *zone)
find iTinf and iTsup in order t : zone.timeStamp [iTInf] <= t <= zone.timeStamp [iTSup]
Definition r3grib.c:344
bool isPresentGrib(const Zone *zone, const char *name)
true if shortname in zone
Definition r3grib.c:169
bool checkGribToStr(bool hasCurrentGrib, char *buffer, size_t maxLen)
check Grib information and write report in the buffer return false if something wrong
Definition r3grib.c:316
static void find4PointsAround(double lat, double lon, double *latMin, double *latMax, double *lonMin, double *lonMax, Zone *zone)
provide 4 wind points around point lat, lon
Definition r3grib.c:378
char * gribToStrJson(const char *fileName, char *out, size_t maxLen)
write grib meta information in string
Definition r3grib.c:586
double zoneTimeDiff(const Zone *zone1, const Zone *zone0)
return difference in hours between two zones (current zone and Wind zone)
Definition r3grib.c:19
static bool geoIntersectGrib(const Zone *zone1, const Zone *zone2)
true if (wind) zone and currentZone intersect in geography
Definition r3grib.c:120
static long indLon(double lon, const Zone *zone)
return indice of lon in gribData wind or current
Definition r3grib.c:404
static bool timeStepRegularGrib(const Zone *zone)
check if time steps are regular
Definition r3grib.c:139
bool checkGribInfoToStr(int type, Zone *zone, char *buffer, size_t maxLen)
check Grib information and write (add) report in the buffer return false if something wrong
Definition r3grib.c:207
float * buildUVGWarray(const Zone *zone, const char *initialOfNames, const FlowP *gribData, size_t *outNValues)
return array of outNvalues floats n = nTimeStamp * nbLat * nbLon * nShortNames values = [u1,...
Definition r3grib.c:33
void findWindGrib(double lat, double lon, double t, double *u, double *v, double *gust, double *w, double *twd, double *tws)
use findflow to get wind and waves
Definition r3grib.c:488
static double arrondiMin(double v, double step)
ex arrondiMin (46.4, 0.25) = 46.25
Definition r3grib.c:368
#define MISSING
Definition r3types.h:21
#define DEG_TO_RAD
Definition r3types.h:28
#define N_METEO_ADMIN
Definition r3types.h:69
#define MAX_SIZE_NAME
Definition r3types.h:61
#define MAX_SIZE_FILE_NAME
Definition r3types.h:63
#define MAX_SIZE_LINE
Definition r3types.h:45
#define KN_TO_MS
Definition r3types.h:24
@ WIND
Definition r3types.h:77
@ CURRENT
Definition r3types.h:77
#define MAX_SIZE_TEXT
Definition r3types.h:48
char * lonToStr(double lon, int type, char *str, size_t maxLen)
convert lon to str according to type
Definition r3util.c:462
Zone currentZone
Definition r3util.c:65
char * buildRootName(const char *fileName, char *rootName, size_t maxLen)
Build root name if not already a root name.
Definition r3util.c:230
char * newDate(long intDate, double nHours, char *res, size_t maxLen)
return date and time using ISO notation after adding myTime (hours) to the Date
Definition r3util.c:386
Par par
parameter
Definition r3util.c:58
Zone zone
geographic zone covered by grib file
Definition r3util.c:64
const struct MeteoElmt meteoTab[N_METEO_ADMIN]
dictionnary of meteo services
Definition r3util.c:35
char * latToStr(double lat, int type, char *str, size_t maxLen)
convert lat to str according to type
Definition r3util.c:440
char name[MAX_SIZE_NAME]
Definition r3util.c:22
time_t gribDateTimeToEpoch(long date, long hhmm)
convert long date/time from GRIB to time_t (UTC, via timegm)
Definition r3util.c:408
FlowP * tGribData[]
grib data description
bool readGribLists(const char *fileName, Zone *zone)
Read lists zone.timeStamp, shortName, zone.dataDate, dataTime before full grib reading.
bool readGribParameters(const char *fileName, Zone *zone)
Read grib parameters in zone before full grib reading.
Check grib structure.
Definition r3types.h:115
int wStrange
Definition r3types.h:123
int uMissing
Definition r3types.h:116
int wMissing
Definition r3types.h:119
int vMissing
Definition r3types.h:117
int uStrange
Definition r3types.h:120
int gMissing
Definition r3types.h:118
int gStrange
Definition r3types.h:122
int vStrange
Definition r3types.h:121
int outZone
Definition r3types.h:124
Wind point.
Definition r3types.h:128
float u
Definition r3types.h:131
float g
Definition r3types.h:134
float lat
Definition r3types.h:129
float w
Definition r3types.h:133
float v
Definition r3types.h:132
float lon
Definition r3types.h:130
double constWindTws
Definition r3types.h:328
double constCurrentD
Definition r3types.h:332
double constWindTwd
Definition r3types.h:329
double constWave
Definition r3types.h:330
double constCurrentS
Definition r3types.h:331
int dispDms
Definition r3types.h:376
zone description
Definition r3types.h:140
double latMin
Definition r3types.h:149
double lonRight
Definition r3types.h:152
bool anteMeridian
Definition r3types.h:141
long dataTime[MAX_N_DATA_TIME]
Definition r3types.h:165
long intervalEnd
Definition r3types.h:167
bool wellDefined
Definition r3types.h:143
long centreId
Definition r3types.h:144
long intervalBegin
Definition r3types.h:166
long numberOfValues
Definition r3types.h:147
size_t nTimeStamp
Definition r3types.h:157
char shortName[MAX_N_SHORT_NAME][MAX_SIZE_SHORT_NAME]
Definition r3types.h:162
long nbLon
Definition r3types.h:156
long stepUnits
Definition r3types.h:148
long editionNumber
Definition r3types.h:146
size_t nDataDate
Definition r3types.h:158
double lonStep
Definition r3types.h:154
long nbLat
Definition r3types.h:155
double latMax
Definition r3types.h:150
double lonLeft
Definition r3types.h:151
int nMessage
Definition r3types.h:145
size_t intervalLimit
Definition r3types.h:168
double latStep
Definition r3types.h:153
size_t nShortName
Definition r3types.h:161
bool allTimeStepOK
Definition r3types.h:142
long timeStamp[MAX_N_TIME_STAMPS]
Definition r3types.h:163
long dataDate[MAX_N_DATA_DATE]
Definition r3types.h:164
size_t nDataTime
Definition r3types.h:159