anemoi-datasets 0.5.21__py3-none-any.whl → 0.5.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anemoi/datasets/_version.py +2 -2
- anemoi/datasets/check.py +93 -0
- anemoi/datasets/commands/check.py +101 -0
- anemoi/datasets/commands/copy.py +43 -3
- anemoi/datasets/commands/create.py +2 -3
- anemoi/datasets/commands/scan.py +17 -5
- anemoi/datasets/create/__init__.py +18 -7
- anemoi/datasets/create/check.py +19 -1
- anemoi/datasets/create/input/action.py +2 -0
- anemoi/datasets/create/input/result.py +6 -2
- anemoi/datasets/create/sources/accumulations.py +394 -34
- anemoi/datasets/create/sources/accumulations2.py +2 -3
- anemoi/datasets/create/sources/grib.py +18 -10
- anemoi/datasets/create/sources/xarray_support/metadata.py +6 -0
- anemoi/datasets/create/sources/xarray_zarr.py +1 -1
- anemoi/datasets/data/complement.py +28 -11
- anemoi/datasets/data/forwards.py +4 -0
- anemoi/datasets/data/grids.py +3 -3
- anemoi/datasets/data/stores.py +36 -4
- {anemoi_datasets-0.5.21.dist-info → anemoi_datasets-0.5.23.dist-info}/METADATA +4 -3
- {anemoi_datasets-0.5.21.dist-info → anemoi_datasets-0.5.23.dist-info}/RECORD +25 -23
- {anemoi_datasets-0.5.21.dist-info → anemoi_datasets-0.5.23.dist-info}/WHEEL +1 -1
- {anemoi_datasets-0.5.21.dist-info → anemoi_datasets-0.5.23.dist-info}/entry_points.txt +0 -0
- {anemoi_datasets-0.5.21.dist-info → anemoi_datasets-0.5.23.dist-info}/licenses/LICENSE +0 -0
- {anemoi_datasets-0.5.21.dist-info → anemoi_datasets-0.5.23.dist-info}/top_level.txt +0 -0
|
@@ -68,9 +68,11 @@ class Accumulation:
|
|
|
68
68
|
number: int,
|
|
69
69
|
step: List[int],
|
|
70
70
|
frequency: int,
|
|
71
|
+
accumulations_reset_frequency: Optional[int] = None,
|
|
72
|
+
user_date: Optional[str] = None,
|
|
71
73
|
**kwargs: Any,
|
|
72
74
|
) -> None:
|
|
73
|
-
"""
|
|
75
|
+
"""Initialises an Accumulation instance.
|
|
74
76
|
|
|
75
77
|
Parameters
|
|
76
78
|
----------
|
|
@@ -88,6 +90,10 @@ class Accumulation:
|
|
|
88
90
|
List of steps.
|
|
89
91
|
frequency : int
|
|
90
92
|
Frequency of accumulation.
|
|
93
|
+
accumulations_reset_frequency : Optional[int], optional
|
|
94
|
+
Frequency at which accumulations reset. Defaults to None.
|
|
95
|
+
user_date : Optional[str], optional
|
|
96
|
+
User-defined date. Defaults to None.
|
|
91
97
|
**kwargs : Any
|
|
92
98
|
Additional keyword arguments.
|
|
93
99
|
"""
|
|
@@ -103,7 +109,9 @@ class Accumulation:
|
|
|
103
109
|
self.endStep: Optional[int] = None
|
|
104
110
|
self.done = False
|
|
105
111
|
self.frequency = frequency
|
|
112
|
+
self.accumulations_reset_frequency = accumulations_reset_frequency
|
|
106
113
|
self._check = None
|
|
114
|
+
self.user_date = user_date
|
|
107
115
|
|
|
108
116
|
@property
|
|
109
117
|
def key(self) -> Tuple[str, int, int, List[int], int]:
|
|
@@ -161,14 +169,28 @@ class Accumulation:
|
|
|
161
169
|
f"Negative values when computing accumutation for {self.param} ({self.date} {self.time}): min={np.amin(self.values)} max={np.amax(self.values)}"
|
|
162
170
|
)
|
|
163
171
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
# In GRIB1, is the step is greater that 254 (one byte), we cannot use a range, because both P1 and P2 values
|
|
173
|
+
# are used to store the end step
|
|
174
|
+
|
|
175
|
+
edition = template.metadata("edition")
|
|
176
|
+
|
|
177
|
+
if edition == 1 and self.endStep > 254:
|
|
178
|
+
self.out.write(
|
|
179
|
+
self.values,
|
|
180
|
+
template=template,
|
|
181
|
+
stepType="instant",
|
|
182
|
+
step=self.endStep,
|
|
183
|
+
check_nans=True,
|
|
184
|
+
)
|
|
185
|
+
else:
|
|
186
|
+
self.out.write(
|
|
187
|
+
self.values,
|
|
188
|
+
template=template,
|
|
189
|
+
stepType="accum",
|
|
190
|
+
startStep=self.startStep,
|
|
191
|
+
endStep=self.endStep,
|
|
192
|
+
check_nans=True,
|
|
193
|
+
)
|
|
172
194
|
self.values = None
|
|
173
195
|
self.done = True
|
|
174
196
|
|
|
@@ -179,7 +201,7 @@ class Accumulation:
|
|
|
179
201
|
----------
|
|
180
202
|
field : Any
|
|
181
203
|
The field containing the values.
|
|
182
|
-
values :
|
|
204
|
+
values : NDArray[Any]
|
|
183
205
|
The values to add.
|
|
184
206
|
"""
|
|
185
207
|
self.check(field)
|
|
@@ -189,7 +211,7 @@ class Accumulation:
|
|
|
189
211
|
return
|
|
190
212
|
|
|
191
213
|
if not np.all(values >= 0):
|
|
192
|
-
warnings.warn(f"Negative values for {field}: {np.
|
|
214
|
+
warnings.warn(f"Negative values for {field}: {np.nanmin(values)} {np.nanmax(values)}")
|
|
193
215
|
|
|
194
216
|
assert not self.done, (self.key, step)
|
|
195
217
|
assert step not in self.seen, (self.key, step)
|
|
@@ -197,8 +219,8 @@ class Accumulation:
|
|
|
197
219
|
startStep = field.metadata("startStep")
|
|
198
220
|
endStep = field.metadata("endStep")
|
|
199
221
|
|
|
200
|
-
if
|
|
201
|
-
startStep =
|
|
222
|
+
if startStep == endStep:
|
|
223
|
+
startStep, endStep = self.adjust_steps(startStep, endStep)
|
|
202
224
|
|
|
203
225
|
assert step == endStep, (startStep, endStep, step)
|
|
204
226
|
|
|
@@ -212,12 +234,15 @@ class Accumulation:
|
|
|
212
234
|
@classmethod
|
|
213
235
|
def mars_date_time_steps(
|
|
214
236
|
cls,
|
|
237
|
+
*,
|
|
215
238
|
dates: List[datetime.datetime],
|
|
216
239
|
step1: int,
|
|
217
240
|
step2: int,
|
|
218
241
|
frequency: Optional[int],
|
|
219
242
|
base_times: List[int],
|
|
220
243
|
adjust_step: bool,
|
|
244
|
+
accumulations_reset_frequency: Optional[int],
|
|
245
|
+
user_date: Optional[str],
|
|
221
246
|
) -> Generator[Tuple[int, int, Tuple[int, ...]], None, None]:
|
|
222
247
|
"""Generates MARS date-time steps.
|
|
223
248
|
|
|
@@ -235,6 +260,10 @@ class Accumulation:
|
|
|
235
260
|
List of base times.
|
|
236
261
|
adjust_step : bool
|
|
237
262
|
Whether to adjust the step.
|
|
263
|
+
accumulations_reset_frequency : Optional[int], optional
|
|
264
|
+
Frequency at which accumulations reset. Defaults to None.
|
|
265
|
+
user_date : Optional[str], optional
|
|
266
|
+
User-defined date. Defaults to None.
|
|
238
267
|
|
|
239
268
|
Returns
|
|
240
269
|
-------
|
|
@@ -244,8 +273,16 @@ class Accumulation:
|
|
|
244
273
|
# assert step1 > 0, (step1, step2, frequency)
|
|
245
274
|
|
|
246
275
|
for valid_date in dates:
|
|
247
|
-
base_date = valid_date - datetime.timedelta(hours=step2)
|
|
248
276
|
add_step = 0
|
|
277
|
+
base_date = valid_date - datetime.timedelta(hours=step2)
|
|
278
|
+
if user_date is not None:
|
|
279
|
+
assert user_date == "????-??-01", user_date
|
|
280
|
+
new_base_date = base_date.replace(day=1)
|
|
281
|
+
assert new_base_date <= base_date, (new_base_date, base_date)
|
|
282
|
+
add_step = int((base_date - new_base_date).total_seconds() // 3600)
|
|
283
|
+
|
|
284
|
+
base_date = new_base_date
|
|
285
|
+
|
|
249
286
|
if base_date.hour not in base_times:
|
|
250
287
|
if not adjust_step:
|
|
251
288
|
raise ValueError(
|
|
@@ -257,23 +294,93 @@ class Accumulation:
|
|
|
257
294
|
base_date -= datetime.timedelta(hours=1)
|
|
258
295
|
add_step += 1
|
|
259
296
|
|
|
260
|
-
yield cls._mars_date_time_step(
|
|
297
|
+
yield cls._mars_date_time_step(
|
|
298
|
+
base_date=base_date,
|
|
299
|
+
step1=step1,
|
|
300
|
+
step2=step2,
|
|
301
|
+
add_step=add_step,
|
|
302
|
+
frequency=frequency,
|
|
303
|
+
accumulations_reset_frequency=accumulations_reset_frequency,
|
|
304
|
+
user_date=user_date,
|
|
305
|
+
requested_date=valid_date,
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
def compute(self, values: NDArray[Any], startStep: int, endStep: int) -> None:
|
|
309
|
+
"""Computes the accumulation.
|
|
261
310
|
|
|
262
|
-
|
|
263
|
-
|
|
311
|
+
Parameters
|
|
312
|
+
----------
|
|
313
|
+
values : NDArray[Any]
|
|
314
|
+
The values to accumulate.
|
|
315
|
+
startStep : int
|
|
316
|
+
The start step.
|
|
317
|
+
endStep : int
|
|
318
|
+
The end step.
|
|
319
|
+
"""
|
|
320
|
+
pass
|
|
321
|
+
|
|
322
|
+
@classmethod
|
|
323
|
+
def _mars_date_time_step(
|
|
324
|
+
cls,
|
|
325
|
+
*,
|
|
326
|
+
base_date: datetime.datetime,
|
|
327
|
+
step1: int,
|
|
328
|
+
step2: int,
|
|
329
|
+
add_step: int,
|
|
330
|
+
frequency: Optional[int],
|
|
331
|
+
accumulations_reset_frequency: Optional[int],
|
|
332
|
+
user_date: Optional[str],
|
|
333
|
+
requested_date: Optional[datetime.datetime] = None,
|
|
334
|
+
) -> Tuple[int, int, Tuple[int, ...]]:
|
|
335
|
+
"""Generates a MARS date-time step.
|
|
336
|
+
|
|
337
|
+
Parameters
|
|
338
|
+
----------
|
|
339
|
+
base_date : datetime.datetime
|
|
340
|
+
The base date.
|
|
341
|
+
step1 : int
|
|
342
|
+
First step.
|
|
343
|
+
step2 : int
|
|
344
|
+
Second step.
|
|
345
|
+
add_step : int
|
|
346
|
+
Additional step.
|
|
347
|
+
frequency : Optional[int]
|
|
348
|
+
Frequency of accumulation.
|
|
349
|
+
accumulations_reset_frequency : Optional[int], optional
|
|
350
|
+
Frequency at which accumulations reset. Defaults to None.
|
|
351
|
+
user_date : Optional[str], optional
|
|
352
|
+
User-defined date. Defaults to None.
|
|
353
|
+
requested_date : Optional[datetime.datetime], optional
|
|
354
|
+
Requested date. Defaults to None.
|
|
264
355
|
|
|
265
356
|
Returns
|
|
266
357
|
-------
|
|
267
|
-
|
|
268
|
-
|
|
358
|
+
Tuple[int, int, Tuple[int, ...]]
|
|
359
|
+
A tuple representing the MARS date-time step.
|
|
269
360
|
"""
|
|
270
|
-
|
|
361
|
+
pass
|
|
271
362
|
|
|
272
363
|
|
|
273
364
|
class AccumulationFromStart(Accumulation):
|
|
274
365
|
"""Class to handle data accumulation from the start of the forecast."""
|
|
275
366
|
|
|
276
|
-
|
|
367
|
+
def adjust_steps(self, startStep: int, endStep: int) -> Tuple[int, int]:
|
|
368
|
+
"""Adjusts the start and end steps.
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
startStep : int
|
|
373
|
+
The start step.
|
|
374
|
+
endStep : int
|
|
375
|
+
The end step.
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
Tuple[int, int]
|
|
380
|
+
The adjusted start and end steps.
|
|
381
|
+
"""
|
|
382
|
+
assert endStep == startStep
|
|
383
|
+
return (0, endStep)
|
|
277
384
|
|
|
278
385
|
def compute(self, values: NDArray[Any], startStep: int, endStep: int) -> None:
|
|
279
386
|
"""Computes the accumulation from the start.
|
|
@@ -314,7 +421,16 @@ class AccumulationFromStart(Accumulation):
|
|
|
314
421
|
|
|
315
422
|
@classmethod
|
|
316
423
|
def _mars_date_time_step(
|
|
317
|
-
cls,
|
|
424
|
+
cls,
|
|
425
|
+
*,
|
|
426
|
+
base_date: datetime.datetime,
|
|
427
|
+
step1: int,
|
|
428
|
+
step2: int,
|
|
429
|
+
add_step: int,
|
|
430
|
+
frequency: Optional[int],
|
|
431
|
+
accumulations_reset_frequency: Optional[int],
|
|
432
|
+
user_date: Optional[str],
|
|
433
|
+
requested_date: Optional[datetime.datetime] = None,
|
|
318
434
|
) -> Tuple[int, int, Tuple[int, ...]]:
|
|
319
435
|
"""Generates a MARS date-time step.
|
|
320
436
|
|
|
@@ -330,12 +446,19 @@ class AccumulationFromStart(Accumulation):
|
|
|
330
446
|
Additional step.
|
|
331
447
|
frequency : Optional[int]
|
|
332
448
|
Frequency of accumulation.
|
|
449
|
+
accumulations_reset_frequency : Optional[int], optional
|
|
450
|
+
Frequency at which accumulations reset. Defaults to None.
|
|
451
|
+
user_date : Optional[str], optional
|
|
452
|
+
User-defined date. Defaults to None.
|
|
453
|
+
requested_date : Optional[datetime.datetime], optional
|
|
454
|
+
Requested date. Defaults to None.
|
|
333
455
|
|
|
334
456
|
Returns
|
|
335
457
|
-------
|
|
336
458
|
Tuple[int, int, Tuple[int, ...]]
|
|
337
459
|
A tuple representing the MARS date-time step.
|
|
338
460
|
"""
|
|
461
|
+
assert user_date is None, user_date
|
|
339
462
|
assert not frequency, frequency
|
|
340
463
|
|
|
341
464
|
steps = (step1 + add_step, step2 + add_step)
|
|
@@ -352,8 +475,6 @@ class AccumulationFromStart(Accumulation):
|
|
|
352
475
|
class AccumulationFromLastStep(Accumulation):
|
|
353
476
|
"""Class to handle data accumulation from the last step of the forecast."""
|
|
354
477
|
|
|
355
|
-
buggy_steps = False
|
|
356
|
-
|
|
357
478
|
def compute(self, values: NDArray[Any], startStep: int, endStep: int) -> None:
|
|
358
479
|
"""Computes the accumulation from the last step.
|
|
359
480
|
|
|
@@ -389,7 +510,16 @@ class AccumulationFromLastStep(Accumulation):
|
|
|
389
510
|
|
|
390
511
|
@classmethod
|
|
391
512
|
def _mars_date_time_step(
|
|
392
|
-
cls,
|
|
513
|
+
cls,
|
|
514
|
+
*,
|
|
515
|
+
base_date: datetime.datetime,
|
|
516
|
+
step1: int,
|
|
517
|
+
step2: int,
|
|
518
|
+
add_step: int,
|
|
519
|
+
frequency: int,
|
|
520
|
+
accumulations_reset_frequency: Optional[int],
|
|
521
|
+
user_date: Optional[str] = None,
|
|
522
|
+
requested_date: Optional[datetime.datetime] = None,
|
|
393
523
|
) -> Tuple[int, int, Tuple[int, ...]]:
|
|
394
524
|
"""Generates a MARS date-time step.
|
|
395
525
|
|
|
@@ -405,18 +535,221 @@ class AccumulationFromLastStep(Accumulation):
|
|
|
405
535
|
Additional step.
|
|
406
536
|
frequency : int
|
|
407
537
|
Frequency of accumulation.
|
|
538
|
+
accumulations_reset_frequency : Optional[int], optional
|
|
539
|
+
Frequency at which accumulations reset. Defaults to None.
|
|
540
|
+
user_date : Optional[str], optional
|
|
541
|
+
User-defined date. Defaults to None.
|
|
542
|
+
requested_date : Optional[datetime.datetime], optional
|
|
543
|
+
Requested date. Defaults to None.
|
|
408
544
|
|
|
409
545
|
Returns
|
|
410
546
|
-------
|
|
411
547
|
Tuple[int, int, Tuple[int, ...]]
|
|
412
548
|
A tuple representing the MARS date-time step.
|
|
413
549
|
"""
|
|
550
|
+
|
|
551
|
+
assert user_date is None, user_date
|
|
552
|
+
|
|
414
553
|
assert frequency > 0, frequency
|
|
415
554
|
# assert step1 > 0, (step1, step2, frequency, add_step, base_date)
|
|
416
555
|
|
|
417
556
|
steps = []
|
|
418
557
|
for step in range(step1 + frequency, step2 + frequency, frequency):
|
|
419
558
|
steps.append(step + add_step)
|
|
559
|
+
|
|
560
|
+
return (
|
|
561
|
+
base_date.year * 10000 + base_date.month * 100 + base_date.day,
|
|
562
|
+
base_date.hour * 100 + base_date.minute,
|
|
563
|
+
tuple(steps),
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
class AccumulationFromLastReset(Accumulation):
|
|
568
|
+
"""Class to handle data accumulation from the last step of the forecast."""
|
|
569
|
+
|
|
570
|
+
def adjust_steps(self, startStep: int, endStep: int) -> Tuple[int, int]:
|
|
571
|
+
"""Adjusts the start and end steps.
|
|
572
|
+
|
|
573
|
+
Parameters
|
|
574
|
+
----------
|
|
575
|
+
startStep : int
|
|
576
|
+
The start step.
|
|
577
|
+
endStep : int
|
|
578
|
+
The end step.
|
|
579
|
+
|
|
580
|
+
Returns
|
|
581
|
+
-------
|
|
582
|
+
Tuple[int, int]
|
|
583
|
+
The adjusted start and end steps.
|
|
584
|
+
"""
|
|
585
|
+
return self.__class__._adjust_steps(startStep, endStep, self.frequency, self.accumulations_reset_frequency)
|
|
586
|
+
|
|
587
|
+
@classmethod
|
|
588
|
+
def _adjust_steps(
|
|
589
|
+
self, startStep: int, endStep: int, frequency: int, accumulations_reset_frequency: int
|
|
590
|
+
) -> Tuple[int, int]:
|
|
591
|
+
"""Adjusts the start and end steps.
|
|
592
|
+
|
|
593
|
+
Parameters
|
|
594
|
+
----------
|
|
595
|
+
startStep : int
|
|
596
|
+
The start step.
|
|
597
|
+
endStep : int
|
|
598
|
+
The end step.
|
|
599
|
+
frequency : int
|
|
600
|
+
Frequency of accumulation.
|
|
601
|
+
accumulations_reset_frequency : int
|
|
602
|
+
Frequency at which accumulations reset.
|
|
603
|
+
|
|
604
|
+
Returns
|
|
605
|
+
-------
|
|
606
|
+
Tuple[int, int]
|
|
607
|
+
The adjusted start and end steps.
|
|
608
|
+
"""
|
|
609
|
+
|
|
610
|
+
assert frequency == 1, (frequency, startStep, endStep)
|
|
611
|
+
assert endStep - startStep <= accumulations_reset_frequency, (startStep, endStep)
|
|
612
|
+
|
|
613
|
+
return ((startStep // accumulations_reset_frequency) * accumulations_reset_frequency, endStep)
|
|
614
|
+
|
|
615
|
+
@classmethod
|
|
616
|
+
def _steps(
|
|
617
|
+
cls,
|
|
618
|
+
valid_date: datetime.datetime,
|
|
619
|
+
base_date: datetime.datetime,
|
|
620
|
+
frequency: int,
|
|
621
|
+
accumulations_reset_frequency: int,
|
|
622
|
+
) -> Tuple[int, int]:
|
|
623
|
+
"""Calculates the steps for accumulation.
|
|
624
|
+
|
|
625
|
+
Parameters
|
|
626
|
+
----------
|
|
627
|
+
valid_date : datetime.datetime
|
|
628
|
+
The valid date.
|
|
629
|
+
base_date : datetime.datetime
|
|
630
|
+
The base date.
|
|
631
|
+
frequency : int
|
|
632
|
+
Frequency of accumulation.
|
|
633
|
+
accumulations_reset_frequency : int
|
|
634
|
+
Frequency at which accumulations reset.
|
|
635
|
+
|
|
636
|
+
Returns
|
|
637
|
+
-------
|
|
638
|
+
Tuple[int, int]
|
|
639
|
+
A tuple representing the steps for accumulation.
|
|
640
|
+
"""
|
|
641
|
+
|
|
642
|
+
assert base_date.day == 1, (base_date, valid_date)
|
|
643
|
+
|
|
644
|
+
step = (valid_date - base_date).total_seconds()
|
|
645
|
+
assert int(step) == step, (valid_date, base_date, step)
|
|
646
|
+
assert int(step) % 3600 == 0, (valid_date, base_date, step)
|
|
647
|
+
step = int(step // 3600)
|
|
648
|
+
start, end = cls._adjust_steps(step, step, frequency, accumulations_reset_frequency)
|
|
649
|
+
|
|
650
|
+
return start + frequency, end
|
|
651
|
+
|
|
652
|
+
def compute(self, values: NDArray[Any], startStep: int, endStep: int) -> None:
|
|
653
|
+
"""Computes the accumulation from the last step.
|
|
654
|
+
|
|
655
|
+
Parameters
|
|
656
|
+
----------
|
|
657
|
+
values : NDArray[Any]
|
|
658
|
+
The values to accumulate.
|
|
659
|
+
startStep : int
|
|
660
|
+
The start step.
|
|
661
|
+
endStep : int
|
|
662
|
+
The end step.
|
|
663
|
+
"""
|
|
664
|
+
|
|
665
|
+
assert self.frequency == 1
|
|
666
|
+
|
|
667
|
+
assert startStep % self.accumulations_reset_frequency == 0, (
|
|
668
|
+
startStep,
|
|
669
|
+
endStep,
|
|
670
|
+
self.accumulations_reset_frequency,
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
if self.values is None:
|
|
674
|
+
|
|
675
|
+
self.values = np.copy(values)
|
|
676
|
+
self.startStep = startStep
|
|
677
|
+
self.endStep = endStep
|
|
678
|
+
|
|
679
|
+
if len(self.steps) == 1:
|
|
680
|
+
assert self.startStep == self.endStep - self.frequency, (self.startStep, self.endStep)
|
|
681
|
+
|
|
682
|
+
else:
|
|
683
|
+
assert endStep != self.endStep, (self.endStep, endStep)
|
|
684
|
+
|
|
685
|
+
if endStep > self.endStep:
|
|
686
|
+
# assert endStep - self.endStep == self.stepping, (self.endStep, endStep, self.stepping)
|
|
687
|
+
self.values = values - self.values
|
|
688
|
+
self.startStep = self.endStep
|
|
689
|
+
self.endStep = endStep
|
|
690
|
+
else:
|
|
691
|
+
# assert self.endStep - endStep == self.stepping, (self.endStep, endStep, self.stepping)
|
|
692
|
+
self.values = self.values - values
|
|
693
|
+
self.startStep = endStep
|
|
694
|
+
|
|
695
|
+
assert self.endStep - self.startStep <= self.accumulations_reset_frequency, (self.startStep, startStep)
|
|
696
|
+
|
|
697
|
+
@classmethod
|
|
698
|
+
def _mars_date_time_step(
|
|
699
|
+
cls,
|
|
700
|
+
*,
|
|
701
|
+
base_date: datetime.datetime,
|
|
702
|
+
step1: int,
|
|
703
|
+
step2: int,
|
|
704
|
+
add_step: int,
|
|
705
|
+
frequency: int,
|
|
706
|
+
accumulations_reset_frequency: Optional[int],
|
|
707
|
+
user_date: Optional[str],
|
|
708
|
+
requested_date: Optional[datetime.datetime] = None,
|
|
709
|
+
) -> Tuple[int, int, Tuple[int, ...]]:
|
|
710
|
+
"""Generates a MARS date-time step.
|
|
711
|
+
|
|
712
|
+
Parameters
|
|
713
|
+
----------
|
|
714
|
+
base_date : datetime.datetime
|
|
715
|
+
The base date.
|
|
716
|
+
step1 : int
|
|
717
|
+
First step.
|
|
718
|
+
step2 : int
|
|
719
|
+
Second step.
|
|
720
|
+
add_step : int
|
|
721
|
+
Additional step.
|
|
722
|
+
frequency : int
|
|
723
|
+
Frequency of accumulation.
|
|
724
|
+
accumulations_reset_frequency : Optional[int]
|
|
725
|
+
Frequency at which accumulations reset.
|
|
726
|
+
user_date : Optional[str]
|
|
727
|
+
User-defined date.
|
|
728
|
+
requested_date : Optional[datetime.datetime], optional
|
|
729
|
+
Requested date. Defaults to None.
|
|
730
|
+
|
|
731
|
+
Returns
|
|
732
|
+
-------
|
|
733
|
+
Tuple[int, int, Tuple[int, ...]]
|
|
734
|
+
A tuple representing the MARS date-time step.
|
|
735
|
+
"""
|
|
736
|
+
# assert frequency > 0, frequency
|
|
737
|
+
# assert step1 > 0, (step1, step2, frequency, add_step, base_date)
|
|
738
|
+
|
|
739
|
+
step1 += add_step
|
|
740
|
+
step2 += add_step
|
|
741
|
+
|
|
742
|
+
assert step2 - step1 == frequency, (step1, step2, frequency)
|
|
743
|
+
|
|
744
|
+
adjust_step1 = cls._adjust_steps(step1, step1, frequency, accumulations_reset_frequency)
|
|
745
|
+
adjust_step2 = cls._adjust_steps(step2, step2, frequency, accumulations_reset_frequency)
|
|
746
|
+
|
|
747
|
+
if adjust_step1[1] % accumulations_reset_frequency == 0:
|
|
748
|
+
# First step of a new accumulation
|
|
749
|
+
steps = (adjust_step2[1],)
|
|
750
|
+
else:
|
|
751
|
+
steps = (adjust_step1[1], adjust_step2[1])
|
|
752
|
+
|
|
420
753
|
return (
|
|
421
754
|
base_date.year * 10000 + base_date.month * 100 + base_date.day,
|
|
422
755
|
base_date.hour * 100 + base_date.minute,
|
|
@@ -446,6 +779,8 @@ def _compute_accumulations(
|
|
|
446
779
|
request: Dict[str, Any],
|
|
447
780
|
user_accumulation_period: Union[int, Tuple[int, int]] = 6,
|
|
448
781
|
data_accumulation_period: Optional[int] = None,
|
|
782
|
+
accumulations_reset_frequency: Optional[int] = None,
|
|
783
|
+
user_date: Optional[str] = None,
|
|
449
784
|
patch: Any = _identity,
|
|
450
785
|
base_times: Optional[List[int]] = None,
|
|
451
786
|
use_cdsapi_dataset: Optional[str] = None,
|
|
@@ -464,6 +799,10 @@ def _compute_accumulations(
|
|
|
464
799
|
User-defined accumulation period. Defaults to 6.
|
|
465
800
|
data_accumulation_period : Optional[int], optional
|
|
466
801
|
Data accumulation period. Defaults to None.
|
|
802
|
+
accumulations_reset_frequency : Optional[int], optional
|
|
803
|
+
Frequency at which accumulations reset. Defaults to None.
|
|
804
|
+
user_date : Optional[str], optional
|
|
805
|
+
User-defined date. Defaults to None.
|
|
467
806
|
patch : Any, optional
|
|
468
807
|
Patch function. Defaults to _identity.
|
|
469
808
|
base_times : Optional[List[int]], optional
|
|
@@ -485,20 +824,34 @@ def _compute_accumulations(
|
|
|
485
824
|
step1, step2 = user_accumulation_period
|
|
486
825
|
assert step1 < step2, user_accumulation_period
|
|
487
826
|
|
|
827
|
+
if data_accumulation_period is None:
|
|
828
|
+
data_accumulation_period = user_accumulation_period[1] - user_accumulation_period[0]
|
|
829
|
+
|
|
488
830
|
if base_times is None:
|
|
489
|
-
|
|
831
|
+
if "time" in request:
|
|
832
|
+
time = request.pop("time")
|
|
833
|
+
if time > 100:
|
|
834
|
+
time = time // 100
|
|
835
|
+
base_times = [time]
|
|
836
|
+
else:
|
|
837
|
+
base_times = [0, 6, 12, 18]
|
|
490
838
|
|
|
491
839
|
base_times = [t // 100 if t > 100 else t for t in base_times]
|
|
492
840
|
|
|
493
|
-
|
|
841
|
+
if accumulations_reset_frequency is not None:
|
|
842
|
+
AccumulationClass = AccumulationFromLastReset
|
|
843
|
+
else:
|
|
844
|
+
AccumulationClass = AccumulationFromStart if data_accumulation_period in (0, None) else AccumulationFromLastStep
|
|
494
845
|
|
|
495
846
|
mars_date_time_steps = AccumulationClass.mars_date_time_steps(
|
|
496
|
-
dates,
|
|
497
|
-
step1,
|
|
498
|
-
step2,
|
|
499
|
-
data_accumulation_period,
|
|
500
|
-
base_times,
|
|
501
|
-
adjust_step,
|
|
847
|
+
dates=dates,
|
|
848
|
+
step1=step1,
|
|
849
|
+
step2=step2,
|
|
850
|
+
frequency=data_accumulation_period,
|
|
851
|
+
base_times=base_times,
|
|
852
|
+
adjust_step=adjust_step,
|
|
853
|
+
accumulations_reset_frequency=accumulations_reset_frequency,
|
|
854
|
+
user_date=user_date,
|
|
502
855
|
)
|
|
503
856
|
|
|
504
857
|
request = deepcopy(request)
|
|
@@ -538,7 +891,10 @@ def _compute_accumulations(
|
|
|
538
891
|
)
|
|
539
892
|
|
|
540
893
|
accumulations = {}
|
|
541
|
-
for a in [
|
|
894
|
+
for a in [
|
|
895
|
+
AccumulationClass(out, frequency=frequency, accumulations_reset_frequency=accumulations_reset_frequency, **r)
|
|
896
|
+
for r in requests
|
|
897
|
+
]:
|
|
542
898
|
for s in a.steps:
|
|
543
899
|
key = (a.param, a.date, a.time, s, a.number)
|
|
544
900
|
accumulations.setdefault(key, []).append(a)
|
|
@@ -654,6 +1010,8 @@ def accumulations(
|
|
|
654
1010
|
stream = request.get("stream", "oper")
|
|
655
1011
|
|
|
656
1012
|
user_accumulation_period = request.pop("accumulation_period", 6)
|
|
1013
|
+
accumulations_reset_frequency = request.pop("accumulations_reset_frequency", None)
|
|
1014
|
+
user_date = request.pop("date", None)
|
|
657
1015
|
|
|
658
1016
|
# If `data_accumulation_period` is not set, this means that the accumulations are from the start
|
|
659
1017
|
# of the forecast.
|
|
@@ -677,7 +1035,9 @@ def accumulations(
|
|
|
677
1035
|
dates,
|
|
678
1036
|
request,
|
|
679
1037
|
user_accumulation_period=user_accumulation_period,
|
|
1038
|
+
accumulations_reset_frequency=accumulations_reset_frequency,
|
|
680
1039
|
use_cdsapi_dataset=use_cdsapi_dataset,
|
|
1040
|
+
user_date=user_date,
|
|
681
1041
|
**kwargs,
|
|
682
1042
|
)
|
|
683
1043
|
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
import datetime
|
|
11
11
|
import logging
|
|
12
|
-
import warnings
|
|
13
12
|
from abc import abstractmethod
|
|
14
13
|
from copy import deepcopy
|
|
15
14
|
from typing import Any
|
|
@@ -118,8 +117,8 @@ class Period:
|
|
|
118
117
|
|
|
119
118
|
assert accumulated.shape == values.shape, (accumulated.shape, values.shape)
|
|
120
119
|
|
|
121
|
-
if not np.all(values >= 0):
|
|
122
|
-
|
|
120
|
+
# if not np.all(values >= 0):
|
|
121
|
+
# warnings.warn(f"Negative values for {values}: {np.amin(values)} {np.amax(values)}")
|
|
123
122
|
|
|
124
123
|
return accumulated + self.sign * values
|
|
125
124
|
|
|
@@ -87,16 +87,24 @@ def execute(
|
|
|
87
87
|
*args: Any,
|
|
88
88
|
**kwargs: Any,
|
|
89
89
|
) -> ekd.FieldList:
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
"""Executes the function to load data from GRIB files.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
context : Any
|
|
95
|
+
The context in which the function is executed.
|
|
96
|
+
dates : list of Any
|
|
97
|
+
List of dates.
|
|
98
|
+
path : str or list of str
|
|
99
|
+
Path or list of paths to the GRIB files.
|
|
100
|
+
flavour : str or dict of str to Any, optional
|
|
101
|
+
Flavour information, by default None.
|
|
102
|
+
grid_definition : dict of str to Any, optional
|
|
103
|
+
Grid definition configuration to create a Grid object, by default None.
|
|
104
|
+
*args : Any
|
|
105
|
+
Additional positional arguments.
|
|
106
|
+
**kwargs : Any
|
|
107
|
+
Additional keyword arguments.
|
|
100
108
|
|
|
101
109
|
Returns
|
|
102
110
|
-------
|
|
@@ -209,6 +209,12 @@ class XArrayMetadata(RawMetadata):
|
|
|
209
209
|
Any
|
|
210
210
|
The value for the specified key, optionally cast to the specified type.
|
|
211
211
|
"""
|
|
212
|
+
|
|
213
|
+
if key == "levelist":
|
|
214
|
+
# Special case for levelist, for compatibility with GRIB
|
|
215
|
+
if key not in self._d and "level" in self._d:
|
|
216
|
+
key = "level"
|
|
217
|
+
|
|
212
218
|
if key in self._d:
|
|
213
219
|
if astype is not None:
|
|
214
220
|
return astype(self._d[key])
|