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