vortex-nwp 2.0.0b1__py3-none-any.whl → 2.0.0b2__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.
- vortex/__init__.py +59 -45
- vortex/algo/__init__.py +3 -2
- vortex/algo/components.py +940 -614
- vortex/algo/mpitools.py +802 -497
- vortex/algo/serversynctools.py +34 -33
- vortex/config.py +19 -22
- vortex/data/__init__.py +9 -3
- vortex/data/abstractstores.py +593 -655
- vortex/data/containers.py +217 -162
- vortex/data/contents.py +65 -39
- vortex/data/executables.py +93 -102
- vortex/data/flow.py +40 -34
- vortex/data/geometries.py +228 -132
- vortex/data/handlers.py +428 -225
- vortex/data/outflow.py +15 -15
- vortex/data/providers.py +185 -163
- vortex/data/resources.py +48 -42
- vortex/data/stores.py +544 -413
- vortex/gloves.py +114 -87
- vortex/layout/__init__.py +1 -8
- vortex/layout/contexts.py +150 -84
- vortex/layout/dataflow.py +353 -202
- vortex/layout/monitor.py +264 -128
- vortex/nwp/__init__.py +5 -2
- vortex/nwp/algo/__init__.py +14 -5
- vortex/nwp/algo/assim.py +205 -151
- vortex/nwp/algo/clim.py +683 -517
- vortex/nwp/algo/coupling.py +447 -225
- vortex/nwp/algo/eda.py +437 -229
- vortex/nwp/algo/eps.py +403 -231
- vortex/nwp/algo/forecasts.py +420 -271
- vortex/nwp/algo/fpserver.py +683 -307
- vortex/nwp/algo/ifsnaming.py +205 -145
- vortex/nwp/algo/ifsroot.py +210 -122
- vortex/nwp/algo/monitoring.py +132 -76
- vortex/nwp/algo/mpitools.py +321 -191
- vortex/nwp/algo/odbtools.py +617 -353
- vortex/nwp/algo/oopsroot.py +449 -273
- vortex/nwp/algo/oopstests.py +90 -56
- vortex/nwp/algo/request.py +287 -206
- vortex/nwp/algo/stdpost.py +878 -522
- vortex/nwp/data/__init__.py +22 -4
- vortex/nwp/data/assim.py +125 -137
- vortex/nwp/data/boundaries.py +121 -68
- vortex/nwp/data/climfiles.py +193 -211
- vortex/nwp/data/configfiles.py +73 -69
- vortex/nwp/data/consts.py +426 -401
- vortex/nwp/data/ctpini.py +59 -43
- vortex/nwp/data/diagnostics.py +94 -66
- vortex/nwp/data/eda.py +50 -51
- vortex/nwp/data/eps.py +195 -146
- vortex/nwp/data/executables.py +440 -434
- vortex/nwp/data/fields.py +63 -48
- vortex/nwp/data/gridfiles.py +183 -111
- vortex/nwp/data/logs.py +250 -217
- vortex/nwp/data/modelstates.py +180 -151
- vortex/nwp/data/monitoring.py +72 -99
- vortex/nwp/data/namelists.py +254 -202
- vortex/nwp/data/obs.py +400 -308
- vortex/nwp/data/oopsexec.py +22 -20
- vortex/nwp/data/providers.py +90 -65
- vortex/nwp/data/query.py +71 -82
- vortex/nwp/data/stores.py +49 -36
- vortex/nwp/data/surfex.py +136 -137
- vortex/nwp/syntax/__init__.py +1 -1
- vortex/nwp/syntax/stdattrs.py +173 -111
- vortex/nwp/tools/__init__.py +2 -2
- vortex/nwp/tools/addons.py +22 -17
- vortex/nwp/tools/agt.py +24 -12
- vortex/nwp/tools/bdap.py +16 -5
- vortex/nwp/tools/bdcp.py +4 -1
- vortex/nwp/tools/bdm.py +3 -0
- vortex/nwp/tools/bdmp.py +14 -9
- vortex/nwp/tools/conftools.py +728 -378
- vortex/nwp/tools/drhook.py +12 -8
- vortex/nwp/tools/grib.py +65 -39
- vortex/nwp/tools/gribdiff.py +22 -17
- vortex/nwp/tools/ifstools.py +82 -42
- vortex/nwp/tools/igastuff.py +167 -143
- vortex/nwp/tools/mars.py +14 -2
- vortex/nwp/tools/odb.py +234 -125
- vortex/nwp/tools/partitioning.py +61 -37
- vortex/nwp/tools/satrad.py +27 -12
- vortex/nwp/util/async.py +83 -55
- vortex/nwp/util/beacon.py +10 -10
- vortex/nwp/util/diffpygram.py +174 -86
- vortex/nwp/util/ens.py +144 -63
- vortex/nwp/util/hooks.py +30 -19
- vortex/nwp/util/taskdeco.py +28 -24
- vortex/nwp/util/usepygram.py +278 -172
- vortex/nwp/util/usetnt.py +31 -17
- vortex/sessions.py +72 -39
- vortex/syntax/__init__.py +1 -1
- vortex/syntax/stdattrs.py +410 -171
- vortex/syntax/stddeco.py +31 -22
- vortex/toolbox.py +327 -192
- vortex/tools/__init__.py +11 -2
- vortex/tools/actions.py +125 -59
- vortex/tools/addons.py +111 -92
- vortex/tools/arm.py +42 -22
- vortex/tools/compression.py +72 -69
- vortex/tools/date.py +11 -4
- vortex/tools/delayedactions.py +242 -132
- vortex/tools/env.py +75 -47
- vortex/tools/folder.py +342 -171
- vortex/tools/grib.py +311 -149
- vortex/tools/lfi.py +423 -216
- vortex/tools/listings.py +109 -40
- vortex/tools/names.py +218 -156
- vortex/tools/net.py +632 -298
- vortex/tools/parallelism.py +93 -61
- vortex/tools/prestaging.py +55 -31
- vortex/tools/schedulers.py +172 -105
- vortex/tools/services.py +402 -333
- vortex/tools/storage.py +293 -358
- vortex/tools/surfex.py +24 -24
- vortex/tools/systems.py +1211 -631
- vortex/tools/targets.py +156 -100
- vortex/util/__init__.py +1 -1
- vortex/util/config.py +377 -327
- vortex/util/empty.py +2 -2
- vortex/util/helpers.py +56 -24
- vortex/util/introspection.py +18 -12
- vortex/util/iosponge.py +8 -4
- vortex/util/roles.py +4 -6
- vortex/util/storefunctions.py +39 -13
- vortex/util/structs.py +3 -3
- vortex/util/worker.py +29 -17
- vortex_nwp-2.0.0b2.dist-info/METADATA +66 -0
- vortex_nwp-2.0.0b2.dist-info/RECORD +142 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/WHEEL +1 -1
- vortex/layout/appconf.py +0 -109
- vortex/layout/jobs.py +0 -1276
- vortex/layout/nodes.py +0 -1424
- vortex/layout/subjobs.py +0 -464
- vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
- vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/LICENSE +0 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/top_level.txt +0 -0
vortex/nwp/util/ens.py
CHANGED
|
@@ -43,35 +43,44 @@ def drawingfunction(options):
|
|
|
43
43
|
|
|
44
44
|
:rtype: A file like object
|
|
45
45
|
"""
|
|
46
|
-
rhdict = options.get(
|
|
46
|
+
rhdict = options.get("rhandler", None)
|
|
47
47
|
if rhdict:
|
|
48
|
-
date = rhdict[
|
|
48
|
+
date = rhdict["resource"]["date"]
|
|
49
49
|
rgen = random.Random()
|
|
50
50
|
rgen.seed(int(date[:-2]))
|
|
51
|
-
nbsample = rhdict[
|
|
51
|
+
nbsample = rhdict["resource"].get("nbsample", 0)
|
|
52
52
|
if not nbsample:
|
|
53
|
-
raise FunctionStoreCallbackError(
|
|
54
|
-
|
|
53
|
+
raise FunctionStoreCallbackError(
|
|
54
|
+
"The resource must hold a non-null nbsample attribute"
|
|
55
|
+
)
|
|
56
|
+
population = rhdict["resource"].get("population", [])
|
|
55
57
|
if not population:
|
|
56
|
-
raise FunctionStoreCallbackError(
|
|
58
|
+
raise FunctionStoreCallbackError(
|
|
59
|
+
"The resource must hold a non-empty population attribute"
|
|
60
|
+
)
|
|
57
61
|
nbset = len(population)
|
|
58
62
|
|
|
59
|
-
tirage =
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
tirage = rgen.sample(
|
|
64
|
+
population * (nbsample // nbset), (nbsample // nbset) * nbset
|
|
65
|
+
) + rgen.sample(population, nbsample % nbset)
|
|
66
|
+
logger.info(
|
|
67
|
+
"List of random elements: %s", ", ".join([str(x) for x in tirage])
|
|
68
|
+
)
|
|
62
69
|
else:
|
|
63
70
|
raise FunctionStoreCallbackError("no resource handler here :-(")
|
|
64
71
|
# NB: The result have to be a file like object !
|
|
65
|
-
outdict = dict(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
outdict = dict(
|
|
73
|
+
vapp=rhdict["provider"].get("vapp", None),
|
|
74
|
+
vconf=rhdict["provider"].get("vconf", None),
|
|
75
|
+
cutoff=rhdict["resource"].get("cutoff", None),
|
|
76
|
+
date=rhdict["resource"].get("date", None),
|
|
77
|
+
resource_kind=rhdict["resource"].get("kind", None),
|
|
78
|
+
drawing=tirage,
|
|
79
|
+
population=population,
|
|
80
|
+
)
|
|
81
|
+
if rhdict["provider"].get("experiment", None) is not None:
|
|
82
|
+
outdict["experiment"] = rhdict["provider"]["experiment"]
|
|
83
|
+
return io.BytesIO(json.dumps(outdict, indent=4).encode(encoding="utf_8"))
|
|
75
84
|
|
|
76
85
|
|
|
77
86
|
def _checkingfunction_dict(options):
|
|
@@ -79,38 +88,95 @@ def _checkingfunction_dict(options):
|
|
|
79
88
|
Internal function that returns a dictionnary that describes the available
|
|
80
89
|
inputs.
|
|
81
90
|
"""
|
|
82
|
-
rhdict = options.get(
|
|
91
|
+
rhdict = options.get("rhandler", None)
|
|
83
92
|
if rhdict:
|
|
84
93
|
# If no nbsample is provided, easy to achieve...
|
|
85
|
-
nbsample = rhdict[
|
|
94
|
+
nbsample = rhdict["resource"].get("nbsample", None)
|
|
86
95
|
# ...and if no explicit minimum of resources, nbsample is the minimum
|
|
87
|
-
nbmin = int(
|
|
96
|
+
nbmin = int(
|
|
97
|
+
options.get(
|
|
98
|
+
"min",
|
|
99
|
+
[
|
|
100
|
+
(0 if nbsample is None else nbsample),
|
|
101
|
+
],
|
|
102
|
+
).pop()
|
|
103
|
+
)
|
|
88
104
|
if nbsample is not None and nbsample < nbmin:
|
|
89
|
-
logger.warning(
|
|
105
|
+
logger.warning(
|
|
106
|
+
"%d resources needed, %d required: sin of gluttony ?",
|
|
107
|
+
nbsample,
|
|
108
|
+
nbmin,
|
|
109
|
+
)
|
|
90
110
|
# What to look for ?
|
|
91
|
-
checkrole = rhdict[
|
|
111
|
+
checkrole = rhdict["resource"].get("checkrole", None)
|
|
92
112
|
if not checkrole:
|
|
93
|
-
raise FunctionStoreCallbackError(
|
|
94
|
-
|
|
113
|
+
raise FunctionStoreCallbackError(
|
|
114
|
+
"The resource must hold a non-empty checkrole attribute"
|
|
115
|
+
)
|
|
116
|
+
rolematch = re.match(r"(\w+)(?:\+(\w+))?$", checkrole)
|
|
95
117
|
cur_t = sessions.current()
|
|
96
118
|
if rolematch:
|
|
97
119
|
ctx = cur_t.context
|
|
98
|
-
checklist = [
|
|
99
|
-
|
|
100
|
-
|
|
120
|
+
checklist = [
|
|
121
|
+
sec.rh
|
|
122
|
+
for sec in ctx.sequence.filtered_inputs(
|
|
123
|
+
role=rolematch.group(1)
|
|
124
|
+
)
|
|
125
|
+
]
|
|
126
|
+
mandatorylist = (
|
|
127
|
+
[
|
|
128
|
+
sec.rh
|
|
129
|
+
for sec in ctx.sequence.filtered_inputs(
|
|
130
|
+
role=rolematch.group(2)
|
|
131
|
+
)
|
|
132
|
+
]
|
|
133
|
+
if rolematch.group(2)
|
|
134
|
+
else []
|
|
135
|
+
)
|
|
101
136
|
else:
|
|
102
|
-
raise FunctionStoreCallbackError(
|
|
137
|
+
raise FunctionStoreCallbackError(
|
|
138
|
+
"checkrole is not properly formatted"
|
|
139
|
+
)
|
|
103
140
|
# Other options
|
|
104
|
-
nretries = int(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
nretries = int(
|
|
142
|
+
options.get(
|
|
143
|
+
"nretries",
|
|
144
|
+
[
|
|
145
|
+
0,
|
|
146
|
+
],
|
|
147
|
+
).pop()
|
|
148
|
+
)
|
|
149
|
+
retry_wait = Period(
|
|
150
|
+
options.get(
|
|
151
|
+
"retry_wait",
|
|
152
|
+
[
|
|
153
|
+
"PT5M",
|
|
154
|
+
],
|
|
155
|
+
).pop()
|
|
156
|
+
)
|
|
157
|
+
comp_delay = Period(
|
|
158
|
+
options.get(
|
|
159
|
+
"comp_delay",
|
|
160
|
+
[
|
|
161
|
+
0,
|
|
162
|
+
],
|
|
163
|
+
).pop()
|
|
164
|
+
)
|
|
165
|
+
fakecheck = options.get(
|
|
166
|
+
"fakecheck",
|
|
167
|
+
[
|
|
168
|
+
False,
|
|
169
|
+
],
|
|
170
|
+
).pop()
|
|
108
171
|
|
|
109
172
|
def _retry_cond(the_ntries, the_acceptable_time):
|
|
110
|
-
return (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
173
|
+
return (
|
|
174
|
+
the_acceptable_time is None and the_ntries <= nretries
|
|
175
|
+
) or (
|
|
176
|
+
the_acceptable_time
|
|
177
|
+
and (time.time() - the_acceptable_time)
|
|
178
|
+
< comp_delay.total_seconds()
|
|
179
|
+
)
|
|
114
180
|
|
|
115
181
|
# Ok let's work...
|
|
116
182
|
ntries = 0
|
|
@@ -118,30 +184,41 @@ def _checkingfunction_dict(options):
|
|
|
118
184
|
found = []
|
|
119
185
|
while _retry_cond(ntries, acceptable_time):
|
|
120
186
|
if ntries:
|
|
121
|
-
logger.info(
|
|
122
|
-
|
|
187
|
+
logger.info(
|
|
188
|
+
"Let's sleep %d sec. before the next check round...",
|
|
189
|
+
retry_wait.total_seconds(),
|
|
190
|
+
)
|
|
123
191
|
cur_t.sh.sleep(retry_wait.total_seconds())
|
|
124
192
|
ntries += 1
|
|
125
193
|
try:
|
|
126
194
|
logger.info("Starting an input check...")
|
|
127
|
-
found, candidates = helpers.colorfull_input_checker(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
195
|
+
found, candidates = helpers.colorfull_input_checker(
|
|
196
|
+
nbmin,
|
|
197
|
+
checklist,
|
|
198
|
+
mandatory=mandatorylist,
|
|
199
|
+
fakecheck=fakecheck,
|
|
200
|
+
)
|
|
131
201
|
if acceptable_time is None and (found or nbmin == 0):
|
|
132
202
|
acceptable_time = time.time()
|
|
133
|
-
if comp_delay.total_seconds() and len(found) != len(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
203
|
+
if comp_delay.total_seconds() and len(found) != len(
|
|
204
|
+
candidates
|
|
205
|
+
):
|
|
206
|
+
logger.info(
|
|
207
|
+
"The minimum required size was reached (nbmin=%d). "
|
|
208
|
+
+ "That's great but we are waiting a little longer "
|
|
209
|
+
+ "(for at most %d sec.)",
|
|
210
|
+
nbmin,
|
|
211
|
+
comp_delay.total_seconds(),
|
|
212
|
+
)
|
|
138
213
|
|
|
139
214
|
if len(found) == len(candidates):
|
|
140
215
|
# No need to wait any longer...
|
|
141
216
|
break
|
|
142
217
|
except helpers.InputCheckerError as e:
|
|
143
218
|
if not _retry_cond(ntries, acceptable_time):
|
|
144
|
-
raise FunctionStoreCallbackError(
|
|
219
|
+
raise FunctionStoreCallbackError(
|
|
220
|
+
"The input checher failed ({!s})".format(e)
|
|
221
|
+
)
|
|
145
222
|
return found
|
|
146
223
|
else:
|
|
147
224
|
raise FunctionStoreCallbackError("no resource handler here :-(\n")
|
|
@@ -163,17 +240,19 @@ def checkingfunction(options):
|
|
|
163
240
|
|
|
164
241
|
:rtype: A file like object
|
|
165
242
|
"""
|
|
166
|
-
rhdict = options.get(
|
|
243
|
+
rhdict = options.get("rhandler", None)
|
|
167
244
|
avail_list = _checkingfunction_dict(options)
|
|
168
|
-
outdict = dict(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
245
|
+
outdict = dict(
|
|
246
|
+
vapp=rhdict["provider"].get("vapp", None),
|
|
247
|
+
vconf=rhdict["provider"].get("vconf", None),
|
|
248
|
+
cutoff=rhdict["resource"].get("cutoff", None),
|
|
249
|
+
date=rhdict["resource"].get("date", None),
|
|
250
|
+
resource_kind=rhdict["resource"].get("kind", None),
|
|
251
|
+
population=avail_list,
|
|
252
|
+
)
|
|
253
|
+
if rhdict["provider"].get("experiment", None) is not None:
|
|
254
|
+
outdict["experiment"] = rhdict["provider"]["experiment"]
|
|
255
|
+
return io.BytesIO(json.dumps(outdict, indent=4).encode(encoding="utf_8"))
|
|
177
256
|
|
|
178
257
|
|
|
179
258
|
def safedrawingfunction(options):
|
|
@@ -182,7 +261,7 @@ def safedrawingfunction(options):
|
|
|
182
261
|
See the documentation of these two functions for more details.
|
|
183
262
|
"""
|
|
184
263
|
checkedlist = _checkingfunction_dict(options)
|
|
185
|
-
options[
|
|
264
|
+
options["rhandler"]["resource"]["population"] = checkedlist
|
|
186
265
|
return drawingfunction(options)
|
|
187
266
|
|
|
188
267
|
|
|
@@ -192,7 +271,9 @@ def unsafedrawingfunction(options):
|
|
|
192
271
|
|
|
193
272
|
See the documentation of these two functions for more details.
|
|
194
273
|
"""
|
|
195
|
-
options[
|
|
274
|
+
options["fakecheck"] = [
|
|
275
|
+
True,
|
|
276
|
+
]
|
|
196
277
|
checkedlist = _checkingfunction_dict(options)
|
|
197
|
-
options[
|
|
278
|
+
options["rhandler"]["resource"]["population"] = checkedlist
|
|
198
279
|
return drawingfunction(options)
|
vortex/nwp/util/hooks.py
CHANGED
|
@@ -21,10 +21,15 @@ def update_namelist(t, rh, *completive_rh):
|
|
|
21
21
|
touched = False
|
|
22
22
|
for crh in completive_rh:
|
|
23
23
|
if not isinstance(crh, (list, tuple)):
|
|
24
|
-
crh = [
|
|
24
|
+
crh = [
|
|
25
|
+
crh,
|
|
26
|
+
]
|
|
25
27
|
for arh in crh:
|
|
26
|
-
logger.info(
|
|
27
|
-
|
|
28
|
+
logger.info(
|
|
29
|
+
"Merging: {!r} :\n{:s}".format(
|
|
30
|
+
arh.container, arh.contents.dumps()
|
|
31
|
+
)
|
|
32
|
+
)
|
|
28
33
|
rh.contents.merge(arh.contents)
|
|
29
34
|
touched = True
|
|
30
35
|
if touched:
|
|
@@ -36,14 +41,16 @@ def concatenate(t, rh, *rhlist):
|
|
|
36
41
|
blocksize = 32 * 1024 * 1024 # 32Mb
|
|
37
42
|
rh.container.close()
|
|
38
43
|
with rh.container.iod_context():
|
|
39
|
-
myfh = rh.container.iodesc(mode=
|
|
44
|
+
myfh = rh.container.iodesc(mode="ab")
|
|
40
45
|
for crh in rhlist:
|
|
41
46
|
if not isinstance(crh, (list, tuple)):
|
|
42
|
-
crh = [
|
|
47
|
+
crh = [
|
|
48
|
+
crh,
|
|
49
|
+
]
|
|
43
50
|
for arh in crh:
|
|
44
|
-
logger.info(
|
|
51
|
+
logger.info("Appending %s to self.", str(arh.container))
|
|
45
52
|
with arh.container.iod_context():
|
|
46
|
-
afh = arh.container.iodesc(mode=
|
|
53
|
+
afh = arh.container.iodesc(mode="rb")
|
|
47
54
|
stuff = afh.read(blocksize)
|
|
48
55
|
while stuff:
|
|
49
56
|
myfh.write(stuff)
|
|
@@ -64,14 +71,17 @@ def insert_cutoffs(t, rh, rh_cutoff_source, fuse_per_obstype=False):
|
|
|
64
71
|
ValueError("The resource handler's list is empty.")
|
|
65
72
|
# Get the CutoffDispenser
|
|
66
73
|
import vortex.tools.listings
|
|
74
|
+
|
|
67
75
|
assert vortex.tools.listings
|
|
68
|
-
if rh_cutoff_source.container.actualfmt ==
|
|
76
|
+
if rh_cutoff_source.container.actualfmt == "bdmbufr_listing":
|
|
69
77
|
c_disp_callback = functools.partial(
|
|
70
78
|
rh_cutoff_source.contents.data.cutoffs_dispenser,
|
|
71
|
-
fuse_per_obstype=fuse_per_obstype
|
|
79
|
+
fuse_per_obstype=fuse_per_obstype,
|
|
72
80
|
)
|
|
73
81
|
else:
|
|
74
|
-
raise RuntimeError(
|
|
82
|
+
raise RuntimeError(
|
|
83
|
+
"Incompatible < {!s} > ressource handler".format(rh_cutoff_source)
|
|
84
|
+
)
|
|
75
85
|
# Fill the gaps in the original request
|
|
76
86
|
rh.contents.add_cutoff_info(c_disp_callback())
|
|
77
87
|
# Actually save the result to file
|
|
@@ -79,7 +89,6 @@ def insert_cutoffs(t, rh, rh_cutoff_source, fuse_per_obstype=False):
|
|
|
79
89
|
|
|
80
90
|
|
|
81
91
|
def _new_static_cutoff_dispencer(base_date, cutoffs_def):
|
|
82
|
-
|
|
83
92
|
def x_period(p):
|
|
84
93
|
try:
|
|
85
94
|
return Period(p)
|
|
@@ -89,8 +98,10 @@ def _new_static_cutoff_dispencer(base_date, cutoffs_def):
|
|
|
89
98
|
if not isinstance(base_date, Date):
|
|
90
99
|
base_date = Date(base_date)
|
|
91
100
|
if isinstance(cutoffs_def, collections.abc.Mapping):
|
|
92
|
-
cutoffs_def = {
|
|
93
|
-
|
|
101
|
+
cutoffs_def = {
|
|
102
|
+
(k if isinstance(k, Period) else x_period(k)): v
|
|
103
|
+
for k, v in cutoffs_def.items()
|
|
104
|
+
}
|
|
94
105
|
cutoffs = {base_date + k: v for k, v in cutoffs_def.items()}
|
|
95
106
|
c_disp = StaticCutoffDispenser(max(cutoffs.keys()), cutoffs)
|
|
96
107
|
else:
|
|
@@ -110,19 +121,19 @@ def insert_static_cutoffs(t, rh, base_date, cutoffs_def):
|
|
|
110
121
|
associates a cutoff with a list of `obstypes`.
|
|
111
122
|
"""
|
|
112
123
|
# Fill the gaps in the original request
|
|
113
|
-
rh.contents.add_cutoff_info(
|
|
124
|
+
rh.contents.add_cutoff_info(
|
|
125
|
+
_new_static_cutoff_dispencer(base_date, cutoffs_def)
|
|
126
|
+
)
|
|
114
127
|
# Actually save the result to files
|
|
115
128
|
rh.save()
|
|
116
129
|
|
|
117
130
|
|
|
118
131
|
def arpifs_obs_error_correl_legacy2oops(t, rh):
|
|
119
132
|
"""Convert a constant file that contains observation errors correlations."""
|
|
120
|
-
if rh.resource.realkind !=
|
|
121
|
-
raise ValueError(
|
|
133
|
+
if rh.resource.realkind != "correlations":
|
|
134
|
+
raise ValueError("Incompatible resource: {!s}".format(rh))
|
|
122
135
|
if rh.contents[0].startswith("SIGMAO"):
|
|
123
136
|
logger.warning("Non conversion is needed...")
|
|
124
137
|
else:
|
|
125
|
-
rh.contents[:0] = ["SIGMAO unused\n",
|
|
126
|
-
"1 1.2\n",
|
|
127
|
-
"CORRELATIONS\n"]
|
|
138
|
+
rh.contents[:0] = ["SIGMAO unused\n", "1 1.2\n", "CORRELATIONS\n"]
|
|
128
139
|
rh.save()
|
vortex/nwp/util/taskdeco.py
CHANGED
|
@@ -34,15 +34,17 @@ def process_needs_lfi_stuff(*kargs, **kwargs):
|
|
|
34
34
|
pass
|
|
35
35
|
|
|
36
36
|
"""
|
|
37
|
-
cyclekey = kwargs.pop(
|
|
37
|
+
cyclekey = kwargs.pop("cyclekey", "cycle")
|
|
38
38
|
|
|
39
39
|
def decorate_process(cls):
|
|
40
40
|
"""Decorator for Task: get LFI stuff before calling process."""
|
|
41
|
-
original_process = getattr(cls,
|
|
41
|
+
original_process = getattr(cls, "process", None)
|
|
42
42
|
if original_process is not None:
|
|
43
|
+
|
|
43
44
|
def process(self, *args, **kwargs):
|
|
44
45
|
_get_lfi_stuff(self, cyclekey)
|
|
45
46
|
original_process(self, *args, **kwargs)
|
|
47
|
+
|
|
46
48
|
process.__doc__ = original_process.__doc__
|
|
47
49
|
cls.process = process
|
|
48
50
|
return cls
|
|
@@ -55,27 +57,29 @@ def process_needs_lfi_stuff(*kargs, **kwargs):
|
|
|
55
57
|
|
|
56
58
|
def _get_lfi_stuff(self, cyclekey):
|
|
57
59
|
"""Get LFI stuff method (called from process)."""
|
|
58
|
-
if
|
|
59
|
-
|
|
60
|
+
if "early-fetch" in self.steps or "fetch" in self.steps:
|
|
60
61
|
actualcycle = getattr(self.conf, cyclekey)
|
|
61
62
|
|
|
62
|
-
self.sh.title(
|
|
63
|
-
toolbox.input(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
63
|
+
self.sh.title("Toolbox input tblfiscripts")
|
|
64
|
+
toolbox.input(
|
|
65
|
+
role="LFIScripts",
|
|
66
|
+
genv=actualcycle,
|
|
67
|
+
kind="lfiscripts",
|
|
68
|
+
local="usualtools/tools.lfi.tgz",
|
|
69
|
+
)
|
|
70
|
+
self.sh.title("Toolbox input tbiopoll")
|
|
71
|
+
toolbox.input(
|
|
72
|
+
role="IOPoll",
|
|
73
|
+
format="unknown",
|
|
74
|
+
genv=actualcycle,
|
|
75
|
+
kind="iopoll",
|
|
76
|
+
language="perl",
|
|
77
|
+
local="usualtools/io_poll",
|
|
78
|
+
)
|
|
79
|
+
self.sh.title("Toolbox input tblfitools")
|
|
80
|
+
toolbox.input(
|
|
81
|
+
role="LFITOOLS",
|
|
82
|
+
genv=actualcycle,
|
|
83
|
+
kind="lfitools",
|
|
84
|
+
local="usualtools/lfitools",
|
|
85
|
+
)
|