vortex-nwp 2.0.0b1__py3-none-any.whl → 2.1.0__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 +75 -47
- vortex/algo/__init__.py +3 -2
- vortex/algo/components.py +944 -618
- vortex/algo/mpitools.py +802 -497
- vortex/algo/mpitools_templates/__init__.py +1 -0
- 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 +436 -227
- vortex/data/outflow.py +15 -15
- vortex/data/providers.py +185 -163
- vortex/data/resources.py +48 -42
- vortex/data/stores.py +540 -417
- vortex/data/sync_templates/__init__.py +0 -0
- 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 +416 -275
- vortex/nwp/algo/fpserver.py +683 -307
- vortex/nwp/algo/ifsnaming.py +205 -145
- vortex/nwp/algo/ifsroot.py +215 -122
- vortex/nwp/algo/monitoring.py +137 -76
- vortex/nwp/algo/mpitools.py +330 -190
- vortex/nwp/algo/odbtools.py +637 -353
- vortex/nwp/algo/oopsroot.py +454 -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 +110 -121
- 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 +341 -162
- vortex/tools/lfi.py +423 -216
- vortex/tools/listings.py +109 -40
- vortex/tools/names.py +218 -156
- vortex/tools/net.py +655 -299
- vortex/tools/parallelism.py +93 -61
- vortex/tools/prestaging.py +55 -31
- vortex/tools/schedulers.py +172 -105
- vortex/tools/services.py +403 -334
- vortex/tools/storage.py +293 -358
- vortex/tools/surfex.py +24 -24
- vortex/tools/systems.py +1234 -643
- vortex/tools/targets.py +156 -100
- vortex/util/__init__.py +1 -1
- vortex/util/config.py +378 -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.1.0.dist-info/METADATA +67 -0
- vortex_nwp-2.1.0.dist-info/RECORD +144 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.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.1.0.dist-info/licenses}/LICENSE +0 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/top_level.txt +0 -0
vortex/nwp/algo/ifsroot.py
CHANGED
|
@@ -5,11 +5,17 @@ Abstract base class for any AlgoComponent leveraging the Arpege/IFS code.
|
|
|
5
5
|
from bronx.fancies import loggers
|
|
6
6
|
import footprints
|
|
7
7
|
|
|
8
|
-
from vortex.algo.components import
|
|
8
|
+
from vortex.algo.components import (
|
|
9
|
+
Parallel,
|
|
10
|
+
ParallelIoServerMixin,
|
|
11
|
+
AlgoComponentError,
|
|
12
|
+
)
|
|
9
13
|
from vortex.syntax.stdattrs import model
|
|
10
14
|
from vortex.tools import grib
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
# footprints import
|
|
17
|
+
from . import ifsnaming as ifsnaming
|
|
18
|
+
|
|
13
19
|
from ..syntax.stdattrs import algo_member
|
|
14
20
|
from ..tools import satrad, drhook
|
|
15
21
|
|
|
@@ -19,105 +25,127 @@ __all__ = []
|
|
|
19
25
|
logger = loggers.getLogger(__name__)
|
|
20
26
|
|
|
21
27
|
|
|
22
|
-
class IFSParallel(
|
|
23
|
-
|
|
28
|
+
class IFSParallel(
|
|
29
|
+
Parallel,
|
|
30
|
+
ParallelIoServerMixin,
|
|
31
|
+
satrad.SatRadDecoMixin,
|
|
32
|
+
drhook.DrHookDecoMixin,
|
|
33
|
+
grib.EcGribDecoMixin,
|
|
34
|
+
):
|
|
24
35
|
"""Abstract IFSModel parallel algo components."""
|
|
25
36
|
|
|
26
37
|
_abstract = True
|
|
27
38
|
_footprint = [
|
|
28
|
-
model,
|
|
39
|
+
model,
|
|
40
|
+
algo_member,
|
|
29
41
|
dict(
|
|
30
|
-
info
|
|
31
|
-
attr
|
|
32
|
-
kind
|
|
33
|
-
info
|
|
34
|
-
default
|
|
35
|
-
doc_zorder
|
|
42
|
+
info="Abstract AlgoComponent for anything based on Arpege/IFS.",
|
|
43
|
+
attr=dict(
|
|
44
|
+
kind=dict(
|
|
45
|
+
info="The kind of processing we want the Arpege/IFS binary to perform.",
|
|
46
|
+
default="ifsrun",
|
|
47
|
+
doc_zorder=90,
|
|
36
48
|
),
|
|
37
|
-
model
|
|
38
|
-
values
|
|
39
|
-
|
|
49
|
+
model=dict(
|
|
50
|
+
values=[
|
|
51
|
+
"arpege",
|
|
52
|
+
"arp",
|
|
53
|
+
"arp_court",
|
|
54
|
+
"aladin",
|
|
55
|
+
"ald",
|
|
56
|
+
"arome",
|
|
57
|
+
"aro",
|
|
58
|
+
"aearp",
|
|
59
|
+
"pearp",
|
|
60
|
+
"ifs",
|
|
61
|
+
"alaro",
|
|
62
|
+
"harmoniearome",
|
|
63
|
+
]
|
|
40
64
|
),
|
|
41
|
-
ioname
|
|
42
|
-
default
|
|
65
|
+
ioname=dict(
|
|
66
|
+
default="nwpioserv",
|
|
43
67
|
),
|
|
44
|
-
binarysingle
|
|
45
|
-
default
|
|
68
|
+
binarysingle=dict(
|
|
69
|
+
default="basicnwp",
|
|
46
70
|
),
|
|
47
|
-
conf
|
|
48
|
-
info
|
|
49
|
-
type
|
|
50
|
-
optional
|
|
51
|
-
default
|
|
52
|
-
doc_visibility
|
|
71
|
+
conf=dict(
|
|
72
|
+
info="The configuration number given to Arpege/IFS.",
|
|
73
|
+
type=int,
|
|
74
|
+
optional=True,
|
|
75
|
+
default=1,
|
|
76
|
+
doc_visibility=footprints.doc.visibility.ADVANCED,
|
|
53
77
|
),
|
|
54
|
-
timescheme
|
|
55
|
-
info
|
|
56
|
-
optional
|
|
57
|
-
default
|
|
58
|
-
values
|
|
59
|
-
remap
|
|
60
|
-
|
|
61
|
-
semilag = 'sli'
|
|
62
|
-
),
|
|
63
|
-
doc_visibility = footprints.doc.visibility.ADVANCED,
|
|
78
|
+
timescheme=dict(
|
|
79
|
+
info="The timescheme that will be used by Arpege/IFS model.",
|
|
80
|
+
optional=True,
|
|
81
|
+
default="sli",
|
|
82
|
+
values=["eul", "eulerian", "sli", "semilag"],
|
|
83
|
+
remap=dict(eulerian="eul", semilag="sli"),
|
|
84
|
+
doc_visibility=footprints.doc.visibility.ADVANCED,
|
|
64
85
|
),
|
|
65
|
-
timestep
|
|
66
|
-
info
|
|
67
|
-
type
|
|
68
|
-
optional
|
|
69
|
-
default
|
|
86
|
+
timestep=dict(
|
|
87
|
+
info="The timestep of the Arpege/IFS model.",
|
|
88
|
+
type=float,
|
|
89
|
+
optional=True,
|
|
90
|
+
default=600.0,
|
|
70
91
|
),
|
|
71
|
-
fcterm
|
|
72
|
-
info
|
|
73
|
-
type
|
|
74
|
-
optional
|
|
75
|
-
default
|
|
92
|
+
fcterm=dict(
|
|
93
|
+
info="The forecast term of the Arpege/IFS model.",
|
|
94
|
+
type=int,
|
|
95
|
+
optional=True,
|
|
96
|
+
default=0,
|
|
76
97
|
),
|
|
77
|
-
fcunit
|
|
78
|
-
info
|
|
79
|
-
optional
|
|
80
|
-
default
|
|
81
|
-
values
|
|
82
|
-
remap
|
|
83
|
-
hour
|
|
84
|
-
step
|
|
85
|
-
timestep
|
|
86
|
-
)
|
|
98
|
+
fcunit=dict(
|
|
99
|
+
info="The unit used in the *fcterm* attribute.",
|
|
100
|
+
optional=True,
|
|
101
|
+
default="h",
|
|
102
|
+
values=["h", "hour", "t", "step", "timestep"],
|
|
103
|
+
remap=dict(
|
|
104
|
+
hour="h",
|
|
105
|
+
step="t",
|
|
106
|
+
timestep="t",
|
|
107
|
+
),
|
|
87
108
|
),
|
|
88
|
-
xpname
|
|
89
|
-
info
|
|
90
|
-
optional
|
|
91
|
-
default
|
|
92
|
-
doc_visibility
|
|
109
|
+
xpname=dict(
|
|
110
|
+
info="The default labelling of files used in Arpege/IFS model.",
|
|
111
|
+
optional=True,
|
|
112
|
+
default="XPVT",
|
|
113
|
+
doc_visibility=footprints.doc.visibility.ADVANCED,
|
|
93
114
|
),
|
|
94
|
-
)
|
|
95
|
-
)
|
|
115
|
+
),
|
|
116
|
+
),
|
|
96
117
|
]
|
|
97
118
|
|
|
98
119
|
def fstag(self):
|
|
99
120
|
"""Extend default tag with ``kind`` value."""
|
|
100
|
-
return super().fstag() +
|
|
121
|
+
return super().fstag() + "." + self.kind
|
|
122
|
+
|
|
123
|
+
def _mpitool_attributes(self, opts):
|
|
124
|
+
conf_dict = super()._mpitool_attributes(opts)
|
|
125
|
+
conf_dict.update({"mplbased": True})
|
|
126
|
+
return conf_dict
|
|
101
127
|
|
|
102
128
|
def valid_executable(self, rh):
|
|
103
129
|
"""Be sure that the specifed executable is ifsmodel compatible."""
|
|
104
130
|
valid = super().valid_executable(rh)
|
|
105
131
|
try:
|
|
106
|
-
return valid and bool(rh.resource.realkind ==
|
|
132
|
+
return valid and bool(rh.resource.realkind == "ifsmodel")
|
|
107
133
|
except (ValueError, TypeError):
|
|
108
134
|
return False
|
|
109
135
|
|
|
110
136
|
def spawn_hook(self):
|
|
111
137
|
"""Usually a good habit to dump the fort.4 namelist."""
|
|
112
138
|
super().spawn_hook()
|
|
113
|
-
if self.system.path.exists(
|
|
114
|
-
self.system.subtitle(
|
|
115
|
-
|
|
139
|
+
if self.system.path.exists("fort.4"):
|
|
140
|
+
self.system.subtitle(
|
|
141
|
+
"{:s} : dump namelist <fort.4>".format(self.realkind)
|
|
142
|
+
)
|
|
143
|
+
self.system.cat("fort.4", output=False)
|
|
116
144
|
|
|
117
145
|
def spawn_command_options(self):
|
|
118
146
|
"""Dictionary provided for command line factory."""
|
|
119
147
|
return dict(
|
|
120
|
-
name=(self.xpname +
|
|
148
|
+
name=(self.xpname + "xxxx")[:4].upper(),
|
|
121
149
|
conf=self.conf,
|
|
122
150
|
timescheme=self.timescheme,
|
|
123
151
|
timestep=self.timestep,
|
|
@@ -133,19 +161,18 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
133
161
|
:param actualfmt: The format of the target file.
|
|
134
162
|
:param dict kwargs: Any argument you may see fit.
|
|
135
163
|
"""
|
|
136
|
-
nc_args = dict(model=self.model,
|
|
137
|
-
conf=self.conf,
|
|
138
|
-
xpname=self.xpname)
|
|
164
|
+
nc_args = dict(model=self.model, conf=self.conf, xpname=self.xpname)
|
|
139
165
|
nc_args.update(kwargs)
|
|
140
|
-
nc = footprints.proxy.ifsnamingconv(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
**nc_args)
|
|
166
|
+
nc = footprints.proxy.ifsnamingconv(
|
|
167
|
+
kind=kind, actualfmt=actualfmt, cycle=rh.resource.cycle, **nc_args
|
|
168
|
+
)
|
|
144
169
|
if nc is None:
|
|
145
170
|
raise AlgoComponentError("No IFSNamingConvention was found.")
|
|
146
171
|
return nc
|
|
147
172
|
|
|
148
|
-
def do_climfile_fixer(
|
|
173
|
+
def do_climfile_fixer(
|
|
174
|
+
self, rh, convkind, actualfmt=None, geo=None, **kwargs
|
|
175
|
+
):
|
|
149
176
|
"""Is it necessary to fix the climatology file ? (i.e link in the appropriate file).
|
|
150
177
|
|
|
151
178
|
:param rh: The binary's ResourceHandler.
|
|
@@ -155,16 +182,27 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
155
182
|
:param dict kwargs: Any argument you may see fit (used to create and call
|
|
156
183
|
the IFSNamingConvention object.
|
|
157
184
|
"""
|
|
158
|
-
nc = self.naming_convention(
|
|
185
|
+
nc = self.naming_convention(
|
|
186
|
+
kind=convkind, rh=rh, actualfmt=actualfmt, **kwargs
|
|
187
|
+
)
|
|
159
188
|
nc_args = dict()
|
|
160
189
|
if geo:
|
|
161
|
-
nc_args[
|
|
190
|
+
nc_args["area"] = geo.area
|
|
162
191
|
nc_args.update(kwargs)
|
|
163
|
-
return not self.system.path.exists(nc(**
|
|
164
|
-
|
|
165
|
-
def climfile_fixer(
|
|
166
|
-
|
|
167
|
-
|
|
192
|
+
return not self.system.path.exists(nc(**nc_args))
|
|
193
|
+
|
|
194
|
+
def climfile_fixer(
|
|
195
|
+
self,
|
|
196
|
+
rh,
|
|
197
|
+
convkind,
|
|
198
|
+
month,
|
|
199
|
+
geo=None,
|
|
200
|
+
notgeo=None,
|
|
201
|
+
actualfmt=None,
|
|
202
|
+
inputrole=None,
|
|
203
|
+
inputkind=None,
|
|
204
|
+
**kwargs,
|
|
205
|
+
):
|
|
168
206
|
"""Fix the climatology files (by choosing the appropriate month, geometry, ...)
|
|
169
207
|
|
|
170
208
|
:param rh: The binary's ResourceHandler.
|
|
@@ -179,19 +217,25 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
179
217
|
the IFSNamingConvention object).
|
|
180
218
|
"""
|
|
181
219
|
if geo is not None and notgeo is not None:
|
|
182
|
-
raise ValueError(
|
|
220
|
+
raise ValueError("*geo* and *notgeo* cannot be provided together.")
|
|
183
221
|
|
|
184
222
|
def check_month(actualrh):
|
|
185
|
-
return bool(
|
|
186
|
-
|
|
223
|
+
return bool(
|
|
224
|
+
hasattr(actualrh.resource, "month")
|
|
225
|
+
and actualrh.resource.month == month
|
|
226
|
+
)
|
|
187
227
|
|
|
188
228
|
def check_month_and_geo(actualrh):
|
|
189
|
-
return (
|
|
190
|
-
|
|
229
|
+
return (
|
|
230
|
+
check_month(actualrh)
|
|
231
|
+
and actualrh.resource.geometry.tag == geo.tag
|
|
232
|
+
)
|
|
191
233
|
|
|
192
234
|
def check_month_and_notgeo(actualrh):
|
|
193
|
-
return (
|
|
194
|
-
|
|
235
|
+
return (
|
|
236
|
+
check_month(actualrh)
|
|
237
|
+
and actualrh.resource.geometry.tag != notgeo.tag
|
|
238
|
+
)
|
|
195
239
|
|
|
196
240
|
if geo:
|
|
197
241
|
checker = check_month_and_geo
|
|
@@ -200,23 +244,41 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
200
244
|
else:
|
|
201
245
|
checker = check_month
|
|
202
246
|
|
|
203
|
-
nc = self.naming_convention(
|
|
247
|
+
nc = self.naming_convention(
|
|
248
|
+
kind=convkind, rh=rh, actualfmt=actualfmt, **kwargs
|
|
249
|
+
)
|
|
204
250
|
nc_args = dict()
|
|
205
251
|
if geo:
|
|
206
|
-
nc_args[
|
|
252
|
+
nc_args["area"] = geo.area
|
|
207
253
|
nc_args.update(kwargs)
|
|
208
|
-
target_name = nc(**
|
|
254
|
+
target_name = nc(**nc_args)
|
|
209
255
|
|
|
210
256
|
self.system.remove(target_name)
|
|
211
257
|
|
|
212
|
-
logger.info(
|
|
213
|
-
|
|
214
|
-
|
|
258
|
+
logger.info(
|
|
259
|
+
"Linking in the %s file (%s) for month %s.",
|
|
260
|
+
convkind,
|
|
261
|
+
target_name,
|
|
262
|
+
month,
|
|
263
|
+
)
|
|
264
|
+
rc = self.setlink(
|
|
265
|
+
initrole=inputrole,
|
|
266
|
+
initkind=inputkind,
|
|
267
|
+
inittest=checker,
|
|
268
|
+
initname=target_name,
|
|
269
|
+
)
|
|
215
270
|
return target_name if rc else None
|
|
216
271
|
|
|
217
|
-
def all_localclim_fixer(
|
|
218
|
-
|
|
219
|
-
|
|
272
|
+
def all_localclim_fixer(
|
|
273
|
+
self,
|
|
274
|
+
rh,
|
|
275
|
+
month,
|
|
276
|
+
convkind="targetclim",
|
|
277
|
+
actualfmt=None,
|
|
278
|
+
inputrole=("LocalClim", "TargetClim", "BDAPClim"),
|
|
279
|
+
inputkind="clim_bdap",
|
|
280
|
+
**kwargs,
|
|
281
|
+
):
|
|
220
282
|
"""Fix all the local/BDAP climatology files (by choosing the appropriate month)
|
|
221
283
|
|
|
222
284
|
:param rh: The binary's ResourceHandler.
|
|
@@ -231,19 +293,33 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
231
293
|
"""
|
|
232
294
|
|
|
233
295
|
def check_month(actualrh):
|
|
234
|
-
return bool(
|
|
235
|
-
|
|
296
|
+
return bool(
|
|
297
|
+
hasattr(actualrh.resource, "month")
|
|
298
|
+
and actualrh.resource.month == month
|
|
299
|
+
)
|
|
236
300
|
|
|
237
|
-
nc = self.naming_convention(
|
|
301
|
+
nc = self.naming_convention(
|
|
302
|
+
kind=convkind, rh=rh, actualfmt=actualfmt, **kwargs
|
|
303
|
+
)
|
|
238
304
|
dealtwith = list()
|
|
239
305
|
|
|
240
|
-
for tclimrh in [
|
|
241
|
-
|
|
242
|
-
|
|
306
|
+
for tclimrh in [
|
|
307
|
+
x.rh
|
|
308
|
+
for x in self.context.sequence.effective_inputs(
|
|
309
|
+
role=inputrole,
|
|
310
|
+
kind=inputkind,
|
|
311
|
+
)
|
|
312
|
+
if x.rh.resource.month == month
|
|
313
|
+
]:
|
|
243
314
|
thisclim = tclimrh.container.localpath()
|
|
244
315
|
thisname = nc(area=tclimrh.resource.geometry.area)
|
|
245
316
|
if thisclim != thisname:
|
|
246
|
-
logger.info(
|
|
317
|
+
logger.info(
|
|
318
|
+
"Linking in the %s to %s for month %s.",
|
|
319
|
+
thisclim,
|
|
320
|
+
thisname,
|
|
321
|
+
month,
|
|
322
|
+
)
|
|
247
323
|
self.system.symlink(thisclim, thisname)
|
|
248
324
|
dealtwith.append(thisname)
|
|
249
325
|
|
|
@@ -251,13 +327,17 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
251
327
|
|
|
252
328
|
def find_namelists(self, opts=None):
|
|
253
329
|
"""Find any namelists candidates in actual context inputs."""
|
|
254
|
-
return [
|
|
255
|
-
|
|
330
|
+
return [
|
|
331
|
+
x.rh
|
|
332
|
+
for x in self.context.sequence.effective_inputs(
|
|
333
|
+
kind=("namelist", "namelistfp")
|
|
334
|
+
)
|
|
335
|
+
]
|
|
256
336
|
|
|
257
337
|
def _set_nam_macro(self, namcontents, namlocal, macro, value):
|
|
258
338
|
"""Set a namelist macro and log it!"""
|
|
259
339
|
namcontents.setmacro(macro, value)
|
|
260
|
-
logger.info(
|
|
340
|
+
logger.info("Setup macro %s=%s in %s", macro, str(value), namlocal)
|
|
261
341
|
|
|
262
342
|
def prepare_namelist_delta(self, rh, namcontents, namlocal):
|
|
263
343
|
"""Apply a namelist delta depending on the cycle of the binary."""
|
|
@@ -268,34 +348,47 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
268
348
|
nam_updated = False
|
|
269
349
|
# For cy41 onward, replace some namelist macros with the command line
|
|
270
350
|
# arguments
|
|
271
|
-
if rh.resource.cycle >=
|
|
272
|
-
if
|
|
351
|
+
if rh.resource.cycle >= "cy41":
|
|
352
|
+
if "NAMARG" in namcontents:
|
|
273
353
|
opts_arg = self.spawn_command_options()
|
|
274
|
-
self._set_nam_macro(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
self._set_nam_macro(
|
|
354
|
+
self._set_nam_macro(
|
|
355
|
+
namcontents, namlocal, "CEXP", opts_arg["name"]
|
|
356
|
+
)
|
|
357
|
+
self._set_nam_macro(
|
|
358
|
+
namcontents, namlocal, "TIMESTEP", opts_arg["timestep"]
|
|
359
|
+
)
|
|
360
|
+
fcstop = "{:s}{:d}".format(
|
|
361
|
+
opts_arg["fcunit"], opts_arg["fcterm"]
|
|
362
|
+
)
|
|
363
|
+
self._set_nam_macro(namcontents, namlocal, "FCSTOP", fcstop)
|
|
278
364
|
nam_updated = True
|
|
279
365
|
else:
|
|
280
|
-
logger.info(
|
|
366
|
+
logger.info("No NAMARG block in %s", namlocal)
|
|
281
367
|
|
|
282
368
|
if self.member is not None:
|
|
283
|
-
for macro_name in (
|
|
284
|
-
self._set_nam_macro(
|
|
369
|
+
for macro_name in ("MEMBER", "PERTURB"):
|
|
370
|
+
self._set_nam_macro(
|
|
371
|
+
namcontents, namlocal, macro_name, self.member
|
|
372
|
+
)
|
|
285
373
|
nam_updated = True
|
|
286
374
|
return nam_updated
|
|
287
375
|
|
|
288
376
|
def prepare_namelists(self, rh, opts=None):
|
|
289
377
|
"""Update each of the namelists."""
|
|
290
378
|
namcandidates = self.find_namelists(opts)
|
|
291
|
-
self.system.subtitle(
|
|
379
|
+
self.system.subtitle("Namelist candidates")
|
|
292
380
|
for nam in namcandidates:
|
|
293
381
|
nam.quickview()
|
|
294
382
|
for namrh in namcandidates:
|
|
295
383
|
namc = namrh.contents
|
|
296
|
-
if self.prepare_namelist_delta(
|
|
384
|
+
if self.prepare_namelist_delta(
|
|
385
|
+
rh, namc, namrh.container.actualpath()
|
|
386
|
+
):
|
|
297
387
|
if namc.dumps_needs_update:
|
|
298
|
-
logger.info(
|
|
388
|
+
logger.info(
|
|
389
|
+
"Rewritting the %s namelists file.",
|
|
390
|
+
namrh.container.actualpath(),
|
|
391
|
+
)
|
|
299
392
|
namc.rewrite(namrh.container)
|
|
300
393
|
|
|
301
394
|
def prepare(self, rh, opts):
|
|
@@ -306,6 +399,6 @@ class IFSParallel(Parallel, ParallelIoServerMixin,
|
|
|
306
399
|
|
|
307
400
|
def execute_single(self, rh, opts):
|
|
308
401
|
"""Standard IFS-Like execution parallel execution."""
|
|
309
|
-
if rh.resource.cycle <
|
|
310
|
-
self.system.ls(output=
|
|
402
|
+
if rh.resource.cycle < "cy46":
|
|
403
|
+
self.system.ls(output="dirlst")
|
|
311
404
|
super().execute_single(rh, opts)
|