|
5 | 5 | # granted to it by virtue of its status as an intergovernmental organisation
|
6 | 6 | # nor does it submit to any jurisdiction.
|
7 | 7 |
|
| 8 | +import datetime |
8 | 9 | import logging
|
9 | 10 | import os
|
10 | 11 | import sys
|
|
19 | 20 | LOG = logging.getLogger(__name__)
|
20 | 21 |
|
21 | 22 |
|
22 |
| -class MarsInput: |
| 23 | +class RequestBasedInput: |
23 | 24 | def __init__(self, owner, **kwargs):
|
24 | 25 | self.owner = owner
|
25 | 26 |
|
26 | 27 | @cached_property
|
27 | 28 | def fields_sfc(self):
|
28 |
| - LOG.info("Loading surface fields from MARS") |
29 |
| - request = dict( |
30 |
| - date=self.owner.date, |
31 |
| - time=self.owner.time, |
32 |
| - param=self.owner.param_sfc, |
33 |
| - grid=self.owner.grid, |
34 |
| - area=self.owner.area, |
35 |
| - levtype="sfc", |
| 29 | + LOG.info(f"Loading surface fields from {self.WHERE}") |
| 30 | + return cml.load_source( |
| 31 | + "multi", |
| 32 | + [ |
| 33 | + self.sfc_load_source( |
| 34 | + date=date, |
| 35 | + time=time, |
| 36 | + param=self.owner.param_sfc, |
| 37 | + grid=self.owner.grid, |
| 38 | + area=self.owner.area, |
| 39 | + ) |
| 40 | + for date, time in self.owner.datetimes() |
| 41 | + ], |
36 | 42 | )
|
37 |
| - return cml.load_source("mars", request) |
38 | 43 |
|
39 | 44 | @cached_property
|
40 | 45 | def fields_pl(self):
|
41 |
| - LOG.info("Loading pressure fields from MARS") |
| 46 | + LOG.info(f"Loading pressure fields from {self.WHERE}") |
42 | 47 | param, level = self.owner.param_level_pl
|
43 |
| - request = dict( |
44 |
| - date=self.owner.date, |
45 |
| - time=self.owner.time, |
46 |
| - param=param, |
47 |
| - level=level, |
48 |
| - grid=self.owner.grid, |
49 |
| - area=self.owner.area, |
50 |
| - levtype="pl", |
| 48 | + return cml.load_source( |
| 49 | + "multi", |
| 50 | + [ |
| 51 | + self.pl_load_source( |
| 52 | + date=date, |
| 53 | + time=time, |
| 54 | + param=param, |
| 55 | + level=level, |
| 56 | + grid=self.owner.grid, |
| 57 | + area=self.owner.area, |
| 58 | + ) |
| 59 | + for date, time in self.owner.datetimes() |
| 60 | + ], |
51 | 61 | )
|
52 |
| - return cml.load_source("mars", request) |
53 | 62 |
|
54 | 63 | @cached_property
|
55 | 64 | def all_fields(self):
|
56 | 65 | return self.fields_sfc + self.fields_pl
|
57 | 66 |
|
58 | 67 |
|
59 |
| -class CdsInput: |
| 68 | +class MarsInput(RequestBasedInput): |
| 69 | + WHERE = "MARS" |
| 70 | + |
60 | 71 | def __init__(self, owner, **kwargs):
|
61 | 72 | self.owner = owner
|
62 | 73 |
|
63 |
| - @cached_property |
64 |
| - def fields_sfc(self): |
65 |
| - LOG.info("Loading surface fields from the CDS") |
66 |
| - request = dict( |
67 |
| - product_type="reanalysis", |
68 |
| - date=self.owner.date, |
69 |
| - time=self.owner.time, |
70 |
| - param=self.owner.param_sfc, |
71 |
| - grid=self.owner.grid, |
72 |
| - area=self.owner.area, |
73 |
| - levtype="sfc", |
74 |
| - ) |
75 |
| - return cml.load_source("cds", "reanalysis-era5-single-levels", request) |
| 74 | + def pl_load_source(self, **kwargs): |
| 75 | + kwargs["levtype"] = "pl" |
| 76 | + logging.debug("load source mars %s", kwargs) |
| 77 | + return cml.load_source("mars", kwargs) |
76 | 78 |
|
77 |
| - @cached_property |
78 |
| - def fields_pl(self): |
79 |
| - LOG.info("Loading pressure fields from the CDS") |
80 |
| - param, level = self.owner.param_level_pl |
81 |
| - request = dict( |
82 |
| - product_type="reanalysis", |
83 |
| - date=self.owner.date, |
84 |
| - time=self.owner.time, |
85 |
| - param=param, |
86 |
| - level=level, |
87 |
| - grid=self.owner.grid, |
88 |
| - area=self.owner.area, |
89 |
| - levtype="pl", |
90 |
| - ) |
91 |
| - return cml.load_source("cds", "reanalysis-era5-pressure-levels", request) |
| 79 | + def sfc_load_source(self, **kwargs): |
| 80 | + kwargs["levtype"] = "sfc" |
| 81 | + logging.debug("load source mars %s", kwargs) |
| 82 | + return cml.load_source("mars", kwargs) |
92 | 83 |
|
93 |
| - @cached_property |
94 |
| - def all_fields(self): |
95 |
| - return self.fields_sfc + self.fields_pl |
| 84 | + |
| 85 | +class CdsInput(RequestBasedInput): |
| 86 | + WHERE = "CDS" |
| 87 | + |
| 88 | + def pl_load_source(self, **kwargs): |
| 89 | + return cml.load_source("cds", "reanalysis-era5-pressure-levels", kwargs) |
| 90 | + |
| 91 | + def sfc_load_source(self, **kwargs): |
| 92 | + return cml.load_source("cds", "reanalysis-era5-single-levels", kwargs) |
96 | 93 |
|
97 | 94 |
|
98 | 95 | class FileInput:
|
@@ -200,6 +197,7 @@ def __exit__(self, *args):
|
200 | 197 |
|
201 | 198 |
|
202 | 199 | class Model:
|
| 200 | + lagged = False |
203 | 201 | assets_extra_dir = None
|
204 | 202 |
|
205 | 203 | def __init__(self, input, output, download_assets, **kwargs):
|
@@ -305,6 +303,43 @@ def timer(self, title):
|
305 | 303 | def stepper(self, step):
|
306 | 304 | return Stepper(step, self.lead_time)
|
307 | 305 |
|
| 306 | + def datetimes(self): |
| 307 | + date = self.date |
| 308 | + assert isinstance(date, int) |
| 309 | + if date <= 0: |
| 310 | + date = datetime.datetime.utcnow() + datetime.timedelta(days=date) |
| 311 | + date = date.year * 10000 + date.month * 100 + date.day |
| 312 | + |
| 313 | + time = self.time |
| 314 | + assert isinstance(time, int) |
| 315 | + if time < 100: |
| 316 | + time *= 100 |
| 317 | + assert time in (0, 600, 1200, 1800), time |
| 318 | + |
| 319 | + lagged = self.lagged |
| 320 | + if not lagged: |
| 321 | + lagged = [0] |
| 322 | + |
| 323 | + full = datetime.datetime( |
| 324 | + date // 10000, |
| 325 | + date % 10000 // 100, |
| 326 | + date % 100, |
| 327 | + time // 100, |
| 328 | + time % 100, |
| 329 | + ) |
| 330 | + |
| 331 | + result = [] |
| 332 | + for lag in lagged: |
| 333 | + date = full + datetime.timedelta(hours=lag) |
| 334 | + result.append( |
| 335 | + ( |
| 336 | + date.year * 10000 + date.month * 100 + date.day, |
| 337 | + date.hour, |
| 338 | + ), |
| 339 | + ) |
| 340 | + |
| 341 | + return result |
| 342 | + |
308 | 343 | def print_fields(self):
|
309 | 344 | param, level = self.param_level_pl
|
310 | 345 | print("Grid:", self.grid)
|
|
0 commit comments