vortex-nwp 2.0.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.
Files changed (144) hide show
  1. vortex/__init__.py +159 -0
  2. vortex/algo/__init__.py +13 -0
  3. vortex/algo/components.py +2462 -0
  4. vortex/algo/mpitools.py +1953 -0
  5. vortex/algo/mpitools_templates/__init__.py +1 -0
  6. vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
  7. vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
  8. vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
  9. vortex/algo/serversynctools.py +171 -0
  10. vortex/config.py +112 -0
  11. vortex/data/__init__.py +19 -0
  12. vortex/data/abstractstores.py +1510 -0
  13. vortex/data/containers.py +835 -0
  14. vortex/data/contents.py +622 -0
  15. vortex/data/executables.py +275 -0
  16. vortex/data/flow.py +119 -0
  17. vortex/data/geometries.ini +2689 -0
  18. vortex/data/geometries.py +799 -0
  19. vortex/data/handlers.py +1230 -0
  20. vortex/data/outflow.py +67 -0
  21. vortex/data/providers.py +487 -0
  22. vortex/data/resources.py +207 -0
  23. vortex/data/stores.py +1390 -0
  24. vortex/data/sync_templates/__init__.py +0 -0
  25. vortex/gloves.py +309 -0
  26. vortex/layout/__init__.py +20 -0
  27. vortex/layout/contexts.py +577 -0
  28. vortex/layout/dataflow.py +1220 -0
  29. vortex/layout/monitor.py +969 -0
  30. vortex/nwp/__init__.py +14 -0
  31. vortex/nwp/algo/__init__.py +21 -0
  32. vortex/nwp/algo/assim.py +537 -0
  33. vortex/nwp/algo/clim.py +1086 -0
  34. vortex/nwp/algo/coupling.py +831 -0
  35. vortex/nwp/algo/eda.py +840 -0
  36. vortex/nwp/algo/eps.py +785 -0
  37. vortex/nwp/algo/forecasts.py +886 -0
  38. vortex/nwp/algo/fpserver.py +1303 -0
  39. vortex/nwp/algo/ifsnaming.py +463 -0
  40. vortex/nwp/algo/ifsroot.py +404 -0
  41. vortex/nwp/algo/monitoring.py +263 -0
  42. vortex/nwp/algo/mpitools.py +694 -0
  43. vortex/nwp/algo/odbtools.py +1258 -0
  44. vortex/nwp/algo/oopsroot.py +916 -0
  45. vortex/nwp/algo/oopstests.py +220 -0
  46. vortex/nwp/algo/request.py +660 -0
  47. vortex/nwp/algo/stdpost.py +1641 -0
  48. vortex/nwp/data/__init__.py +30 -0
  49. vortex/nwp/data/assim.py +380 -0
  50. vortex/nwp/data/boundaries.py +314 -0
  51. vortex/nwp/data/climfiles.py +521 -0
  52. vortex/nwp/data/configfiles.py +153 -0
  53. vortex/nwp/data/consts.py +954 -0
  54. vortex/nwp/data/ctpini.py +149 -0
  55. vortex/nwp/data/diagnostics.py +209 -0
  56. vortex/nwp/data/eda.py +147 -0
  57. vortex/nwp/data/eps.py +432 -0
  58. vortex/nwp/data/executables.py +1045 -0
  59. vortex/nwp/data/fields.py +111 -0
  60. vortex/nwp/data/gridfiles.py +380 -0
  61. vortex/nwp/data/logs.py +584 -0
  62. vortex/nwp/data/modelstates.py +363 -0
  63. vortex/nwp/data/monitoring.py +193 -0
  64. vortex/nwp/data/namelists.py +696 -0
  65. vortex/nwp/data/obs.py +840 -0
  66. vortex/nwp/data/oopsexec.py +74 -0
  67. vortex/nwp/data/providers.py +207 -0
  68. vortex/nwp/data/query.py +206 -0
  69. vortex/nwp/data/stores.py +160 -0
  70. vortex/nwp/data/surfex.py +337 -0
  71. vortex/nwp/syntax/__init__.py +9 -0
  72. vortex/nwp/syntax/stdattrs.py +437 -0
  73. vortex/nwp/tools/__init__.py +10 -0
  74. vortex/nwp/tools/addons.py +40 -0
  75. vortex/nwp/tools/agt.py +67 -0
  76. vortex/nwp/tools/bdap.py +59 -0
  77. vortex/nwp/tools/bdcp.py +41 -0
  78. vortex/nwp/tools/bdm.py +24 -0
  79. vortex/nwp/tools/bdmp.py +54 -0
  80. vortex/nwp/tools/conftools.py +1661 -0
  81. vortex/nwp/tools/drhook.py +66 -0
  82. vortex/nwp/tools/grib.py +294 -0
  83. vortex/nwp/tools/gribdiff.py +104 -0
  84. vortex/nwp/tools/ifstools.py +203 -0
  85. vortex/nwp/tools/igastuff.py +273 -0
  86. vortex/nwp/tools/mars.py +68 -0
  87. vortex/nwp/tools/odb.py +657 -0
  88. vortex/nwp/tools/partitioning.py +258 -0
  89. vortex/nwp/tools/satrad.py +71 -0
  90. vortex/nwp/util/__init__.py +6 -0
  91. vortex/nwp/util/async.py +212 -0
  92. vortex/nwp/util/beacon.py +40 -0
  93. vortex/nwp/util/diffpygram.py +447 -0
  94. vortex/nwp/util/ens.py +279 -0
  95. vortex/nwp/util/hooks.py +139 -0
  96. vortex/nwp/util/taskdeco.py +85 -0
  97. vortex/nwp/util/usepygram.py +697 -0
  98. vortex/nwp/util/usetnt.py +101 -0
  99. vortex/proxy.py +6 -0
  100. vortex/sessions.py +374 -0
  101. vortex/syntax/__init__.py +9 -0
  102. vortex/syntax/stdattrs.py +867 -0
  103. vortex/syntax/stddeco.py +185 -0
  104. vortex/toolbox.py +1117 -0
  105. vortex/tools/__init__.py +20 -0
  106. vortex/tools/actions.py +523 -0
  107. vortex/tools/addons.py +316 -0
  108. vortex/tools/arm.py +96 -0
  109. vortex/tools/compression.py +325 -0
  110. vortex/tools/date.py +27 -0
  111. vortex/tools/ddhpack.py +10 -0
  112. vortex/tools/delayedactions.py +782 -0
  113. vortex/tools/env.py +541 -0
  114. vortex/tools/folder.py +834 -0
  115. vortex/tools/grib.py +738 -0
  116. vortex/tools/lfi.py +953 -0
  117. vortex/tools/listings.py +423 -0
  118. vortex/tools/names.py +637 -0
  119. vortex/tools/net.py +2124 -0
  120. vortex/tools/odb.py +10 -0
  121. vortex/tools/parallelism.py +368 -0
  122. vortex/tools/prestaging.py +210 -0
  123. vortex/tools/rawfiles.py +10 -0
  124. vortex/tools/schedulers.py +480 -0
  125. vortex/tools/services.py +940 -0
  126. vortex/tools/storage.py +996 -0
  127. vortex/tools/surfex.py +61 -0
  128. vortex/tools/systems.py +3976 -0
  129. vortex/tools/targets.py +440 -0
  130. vortex/util/__init__.py +9 -0
  131. vortex/util/config.py +1122 -0
  132. vortex/util/empty.py +24 -0
  133. vortex/util/helpers.py +216 -0
  134. vortex/util/introspection.py +69 -0
  135. vortex/util/iosponge.py +80 -0
  136. vortex/util/roles.py +49 -0
  137. vortex/util/storefunctions.py +129 -0
  138. vortex/util/structs.py +26 -0
  139. vortex/util/worker.py +162 -0
  140. vortex_nwp-2.0.0.dist-info/METADATA +67 -0
  141. vortex_nwp-2.0.0.dist-info/RECORD +144 -0
  142. vortex_nwp-2.0.0.dist-info/WHEEL +5 -0
  143. vortex_nwp-2.0.0.dist-info/licenses/LICENSE +517 -0
  144. vortex_nwp-2.0.0.dist-info/top_level.txt +1 -0
vortex/tools/names.py ADDED
@@ -0,0 +1,637 @@
1
+ """
2
+ Functions and tools to handle resources names or other kind of names.
3
+
4
+ Any "name building" object, must conform to the :class:`AbstractVortexNameBuilder`
5
+ abstract class interface.
6
+ """
7
+
8
+ from bronx.fancies import loggers
9
+ import footprints
10
+ from footprints import proxy as fpx
11
+
12
+ #: No automatic export
13
+ __all__ = []
14
+
15
+ logger = loggers.getLogger(__name__)
16
+
17
+
18
+ class VortexNameBuilderError(ValueError):
19
+ """Raised whenever the name building process fails."""
20
+
21
+ pass
22
+
23
+
24
+ class AbstractVortexNameBuilder(footprints.FootprintBase):
25
+ """Abstract class for any name building class."""
26
+
27
+ _abstract = True
28
+ _collector = ("vortexnamebuilder",)
29
+ _footprint = dict(
30
+ info="Abstract Vortex NameBuilder",
31
+ attr=dict(
32
+ name=dict(
33
+ info="The NameBuilder's name.",
34
+ ),
35
+ ),
36
+ fastkeys={"name"},
37
+ )
38
+
39
+ def __init__(self, *args, **kw):
40
+ logger.debug("Init VortexNameBuilder %s", self.__class__)
41
+ super().__init__(*args, **kw)
42
+ self._default = dict(
43
+ radical="vortexdata",
44
+ )
45
+ # List of known defaults
46
+ for k in [
47
+ "flow",
48
+ "src",
49
+ "term",
50
+ "period",
51
+ "cen_period",
52
+ "geo",
53
+ "suffix",
54
+ "stage",
55
+ "fmt",
56
+ "part",
57
+ "compute",
58
+ "number",
59
+ "filtername",
60
+ ]:
61
+ self._default[k] = None
62
+ self.setdefault(**kw)
63
+
64
+ def setdefault(self, **kw):
65
+ """Update or set new default values as the background description used in packing."""
66
+ self._default.update(kw)
67
+
68
+ @property
69
+ def defaults(self):
70
+ """List of currently declared defaults (defined or not)."""
71
+ return self._default.keys()
72
+
73
+ def as_dump(self):
74
+ """Nicely formated view of the current class in dump context."""
75
+ return str(self._default)
76
+
77
+ def pack(self, d):
78
+ """A shortcut to :meth:`pack_basename` (legacy)."""
79
+ return self.pack_basename(d)
80
+
81
+ def pack_basename(self, d):
82
+ """Returns a basename given the **d** info dictionary."""
83
+ raise NotImplementedError("This is an abstract method !")
84
+
85
+ def pack_pathname(self, d):
86
+ """Returns a pathname given the **d** info dictionary."""
87
+ raise NotImplementedError("This is an abstract method !")
88
+
89
+
90
+ # Activate the footprint's fasttrack on the resources collector
91
+ vbcollect = footprints.collectors.get(tag="vortexnamebuilder")
92
+ vbcollect.fasttrack = ("name",)
93
+ del vbcollect
94
+
95
+
96
+ class AbstractVortexNameBuilderProxy(AbstractVortexNameBuilder):
97
+ """Abstract class for any "proxy" builder object.
98
+
99
+ Given the input dictionary, find the appropriate builder object and delegate
100
+ the work.
101
+ """
102
+
103
+ _abstract = True
104
+
105
+ def __init__(self, *kargs, **kwargs):
106
+ # Cache for actual builder objects
107
+ self._instanciated_builders = dict()
108
+ super().__init__(*kargs, **kwargs)
109
+
110
+ def setdefault(self, **kw):
111
+ """Update or set new default values as the background description used in packing."""
112
+ self._default.update(kw)
113
+ for builder in self._instanciated_builders.values():
114
+ builder.setdefault(**kw)
115
+
116
+ def _get_builder(self, name):
117
+ """Return a builder object given a name.
118
+
119
+ A cache is used in order for faster computations.
120
+ """
121
+ if name not in self._instanciated_builders:
122
+ builder = fpx.vortexnamebuilder(name=name)
123
+ if self._default:
124
+ builder.setdefault(**self._default)
125
+ self._instanciated_builders[name] = builder
126
+ return self._instanciated_builders[name]
127
+
128
+ def _pick_actual_builder(self, d):
129
+ """Given the input dictionary, returns the appropriate builder object."""
130
+ raise NotImplementedError("This is an abstract method !")
131
+
132
+ def pack_basename(self, d):
133
+ """Returns a basename given the **d** info dictionary."""
134
+ components = dict()
135
+ components.update(self._default)
136
+ components.update(d)
137
+ return self._pick_actual_builder(components).pack_basename(d)
138
+
139
+ def pack_pathname(self, d):
140
+ """Returns a pathname given the **d** info dictionary."""
141
+ components = dict()
142
+ components.update(self._default)
143
+ components.update(d)
144
+ return self._pick_actual_builder(components).pack_pathname(d)
145
+
146
+
147
+ class AbstractActualVortexNameBuilder(AbstractVortexNameBuilder):
148
+ """Abstract class for any "concrete" builder object (as opposed to proxies)."""
149
+
150
+ _abstract = True
151
+
152
+ def _pack_generic(self, d, what, default="std"):
153
+ """
154
+ Build the resource vortex basename/pathname or whatever according to
155
+ ``style`` value.
156
+ """
157
+ components = dict()
158
+ components.update(self._default)
159
+ components.update(d)
160
+
161
+ packstyle = getattr(
162
+ self,
163
+ "_pack_{!s}_{!s}".format(what, components.get("style", default)),
164
+ )
165
+ return packstyle(components)
166
+
167
+ def pack_basename(self, d):
168
+ """Build the resource vortex basename according to ``style`` value."""
169
+ return self._pack_generic(d, "basename")
170
+
171
+ def pack_pathname(self, d):
172
+ """Build the resource vortex pathname according to ``style`` value."""
173
+ return "/".join(self._pack_generic(d, "pathname"))
174
+
175
+ # A Vortex pathname may include the following bits
176
+
177
+ def _pack_pathname_init(self, d):
178
+ """Mandatory things to be packed into the pathname."""
179
+ pathbits = []
180
+ for k in ["vapp", "vconf", "experiment"]:
181
+ if k not in d:
182
+ raise VortexNameBuilderError(
183
+ "The {!r} info key is mandatory".format(k)
184
+ )
185
+ pathbits.append(str(d[k]))
186
+ return pathbits
187
+
188
+ def _pack_pathname_append_flowdate(self, pathbits, d):
189
+ """Pack the date/cutoff that characterise the resource's flow."""
190
+ if "flow" in d and d["flow"] is not None:
191
+ pathbits.append(
192
+ self._pack_std_items_datestuff(d["flow"], fatal=True)
193
+ )
194
+ else:
195
+ raise VortexNameBuilderError("The flow info key is mandatory")
196
+
197
+ def _pack_pathname_append_flowperiod(self, pathbits, d):
198
+ """Pack the period/cutoff that characterise the resource's flow."""
199
+ if "flow" in d and d["flow"] is not None:
200
+ pathbits.append(
201
+ self._pack_std_items_periodstuff(d["flow"], fatal=True)
202
+ )
203
+ else:
204
+ raise VortexNameBuilderError("The flow info key is mandatory")
205
+
206
+ def _pack_pathname_append_member(self, pathbits, d):
207
+ """Pack the provider's member number (optional)."""
208
+ if "member" in d and d["member"] is not None:
209
+ pathbits.append(self._pack_std_item_member(d["member"]))
210
+
211
+ def _pack_pathname_append_scenario(self, pathbits, d):
212
+ """Pack the provider's scenario identifier (optional)."""
213
+ if "scenario" in d and d["scenario"] is not None:
214
+ pathbits.append(self._pack_std_item_scenario(d["scenario"]))
215
+
216
+ def _pack_pathname_append_block(self, pathbits, d):
217
+ """Pack the provider's block name."""
218
+ if "block" in d:
219
+ if d["block"]:
220
+ pathbits.append("_".join(self._pack_std_items(d["block"])))
221
+ else:
222
+ raise VortexNameBuilderError("The block info key is mandatory")
223
+
224
+ # A bunch of utility methods that prepares values
225
+
226
+ def _pack_void_item(self, value):
227
+ """The most trivial conversion mechanism: the ``value`` as string."""
228
+ return str(value)
229
+
230
+ def _pack_std_item_seta(self, value):
231
+ """Packing of a MPI-task number in first direction."""
232
+ return "a{:04d}".format(int(value))
233
+
234
+ def _pack_std_item_setb(self, value):
235
+ """Packing of a MPI-task number in second direction."""
236
+ return "b{:04d}".format(int(value))
237
+
238
+ def _pack_std_item_mpi(self, value):
239
+ """Packing of a MPI-task number."""
240
+ return "n{:04d}".format(int(value))
241
+
242
+ def _pack_std_item_openmp(self, value):
243
+ """Packing of an OpenMP id number."""
244
+ return "omp{:02d}".format(int(value))
245
+
246
+ def _pack_std_item_month(self, value):
247
+ """Packing of a month-number value."""
248
+ return "m{!s}".format(value)
249
+
250
+ def _pack_std_item_stretching(self, value):
251
+ """Packing of the stretching factor in spectral geometry."""
252
+ return "c{!s}".format(int(value * 10))
253
+
254
+ def _pack_std_item_truncation(self, value):
255
+ """Packing of the geometry's truncation value."""
256
+ if isinstance(value, tuple):
257
+ return "t{1:s}{2:s}{0!s}".format(*value)
258
+ else:
259
+ return "tl{!s}".format(value)
260
+
261
+ def _pack_std_item_filtering(self, value):
262
+ """Packing of the geometry's filtering value."""
263
+ return "f{!s}".format(value)
264
+
265
+ def _pack_std_item_time(self, value):
266
+ """Packing of a Time object."""
267
+ return value.fmthm if hasattr(value, "fmthm") else str(value)
268
+
269
+ _pack_std_item_begintime = _pack_std_item_time
270
+ _pack_std_item_endtime = _pack_std_item_time
271
+
272
+ def _pack_std_item_date(self, value):
273
+ """Packing of a Time object."""
274
+ return value.stdvortex if hasattr(value, "stdvortex") else str(value)
275
+
276
+ _pack_std_item_begindate = _pack_std_item_date
277
+ _pack_std_item_enddate = _pack_std_item_date
278
+
279
+ def _pack_std_item_cutoff(self, value):
280
+ """Abbreviate the cutoff name."""
281
+ cutoff_map = dict(production="prod")
282
+ return cutoff_map.get(value, value)
283
+
284
+ def _pack_std_item_shortcutoff(self, value, default="X"):
285
+ """Abbreviate the cutoff name."""
286
+ return value[0].upper() if value is not None else default
287
+
288
+ def _pack_std_item_member(self, value):
289
+ return "mb{:03d}".format(value)
290
+
291
+ def _pack_std_item_scenario(self, value):
292
+ return "s{:s}".format(value)
293
+
294
+ def _pack_std_items(self, items):
295
+ """
296
+ Go through all items and pack them according to the so-called standard way.
297
+ Result is always a list of string values.
298
+ """
299
+ if not isinstance(items, list):
300
+ items = [items]
301
+ packed = list()
302
+ for i in items:
303
+ if isinstance(i, dict):
304
+ for k, v in i.items():
305
+ packmtd = getattr(
306
+ self, "_pack_std_item_" + k, self._pack_void_item
307
+ )
308
+ packed.append(packmtd(v))
309
+ else:
310
+ packed.append(self._pack_void_item(i))
311
+ return packed
312
+
313
+ def _pack_std_items_negativetimes(self, items):
314
+ return [
315
+ (t[1:] + "ago" if t[0] == "-" else t)
316
+ for t in self._pack_std_items(items)
317
+ ]
318
+
319
+ def _pack_std_items_datestuff(self, d, fatal=False):
320
+ """Specialised version of _pack_std_items that deals with date/cutoff pairs."""
321
+ flowdate = None
322
+ flowcut = None
323
+ if isinstance(d, (tuple, list)):
324
+ for flowitem in [x for x in d if isinstance(x, dict)]:
325
+ if "date" in flowitem:
326
+ flowdate = flowitem["date"]
327
+ if "shortcutoff" in flowitem:
328
+ flowcut = flowitem["shortcutoff"]
329
+ if flowdate is None:
330
+ if fatal:
331
+ raise VortexNameBuilderError("A date is mandatory here...")
332
+ else:
333
+ return ""
334
+ return self._pack_std_item_date(
335
+ flowdate
336
+ ) + self._pack_std_item_shortcutoff(flowcut)
337
+
338
+ def _pack_std_items_periodstuff(self, d, fatal=False):
339
+ """Specialised version of _pack_std_items that deals with begindate/enddate/cutoff pairs."""
340
+ flowbegin = None
341
+ flowend = None
342
+ flowcut = None
343
+ if isinstance(d, (tuple, list)):
344
+ for flowitem in [x for x in d if isinstance(x, dict)]:
345
+ if "begindate" in flowitem:
346
+ flowbegin = flowitem["begindate"]
347
+ if "enddate" in flowitem:
348
+ flowend = flowitem["enddate"]
349
+ if "shortcutoff" in flowitem:
350
+ flowcut = flowitem["shortcutoff"]
351
+ if flowbegin is None or flowend is None:
352
+ if fatal:
353
+ raise VortexNameBuilderError(
354
+ "A begindate/enddate pair is mandatory here..."
355
+ )
356
+ else:
357
+ return ""
358
+ return "-".join(
359
+ [
360
+ self._pack_std_item_date(flowbegin)
361
+ + self._pack_std_item_shortcutoff(flowcut, default=""),
362
+ self._pack_std_item_date(flowend),
363
+ ]
364
+ )
365
+
366
+ # A Vortex basename may include the following bits
367
+
368
+ def _pack_std_basename_prefixstuff(self, d): # @UnusedVariable
369
+ """Adds any info about date, cutoff ..."""
370
+ name0 = d["radical"]
371
+ name0 += self._join_basename_bit(d, "src", prefix=".", sep="-")
372
+ name0 += self._join_basename_bit(d, "filtername", prefix=".", sep="-")
373
+ name0 += self._join_basename_bit(d, "geo", prefix=".", sep="-")
374
+ name0 += self._join_basename_bit(d, "compute", prefix=".", sep="-")
375
+ return name0
376
+
377
+ def _pack_std_basename_flowstuff(self, d): # @UnusedVariable
378
+ """Adds any info about date, cutoff ..."""
379
+ return ""
380
+
381
+ def _pack_std_basename_timestuff(self, d): # @UnusedVariable
382
+ """Adds any info about term, period, ..."""
383
+ name = ""
384
+ if d["term"] is not None:
385
+ name += self._join_basename_bit(
386
+ d,
387
+ "term",
388
+ prefix="+",
389
+ sep=".",
390
+ packcb=self._pack_std_items_negativetimes,
391
+ )
392
+ else:
393
+ if d["period"] is not None:
394
+ name += self._join_basename_bit(
395
+ d,
396
+ "period",
397
+ prefix="+",
398
+ sep="-",
399
+ packcb=self._pack_std_items_negativetimes,
400
+ )
401
+ elif d["cen_period"] is not None:
402
+ name += self._join_basename_bit(
403
+ d,
404
+ "cen_period",
405
+ prefix="_",
406
+ sep="_",
407
+ packcb=self._pack_std_items_negativetimes,
408
+ )
409
+ return name
410
+
411
+ def _pack_std_basename_suffixstuff(self, d): # @UnusedVariable
412
+ """Adds any info about date, cutoff ..."""
413
+ name1 = ""
414
+ name1 += self._join_basename_bit(d, "number", prefix=".", sep="-")
415
+ name1 += self._join_basename_bit(d, "fmt", prefix=".", sep=".")
416
+ name1 += self._join_basename_bit(d, "suffix", prefix=".", sep=".")
417
+ return name1
418
+
419
+ def _join_basename_bit(self, d, entry, prefix=".", sep="-", packcb=None):
420
+ if d[entry] is not None:
421
+ if packcb is None:
422
+ return prefix + sep.join(self._pack_std_items(d[entry]))
423
+ else:
424
+ return prefix + sep.join(packcb(d[entry]))
425
+ else:
426
+ return ""
427
+
428
+ # Methods that generates basenames
429
+
430
+ def _pack_basename_std(self, d):
431
+ """
432
+ Main entry point to convert a description into a file name
433
+ according to the so-called standard style.
434
+ """
435
+ return (
436
+ self._pack_std_basename_prefixstuff(d).lower()
437
+ + self._pack_std_basename_flowstuff(d)
438
+ + self._pack_std_basename_timestuff(d)
439
+ + self._pack_std_basename_suffixstuff(d).lower()
440
+ )
441
+
442
+ # Methods that generates pathnames
443
+
444
+ def _pack_pathname_std(self, d):
445
+ """
446
+ Main entry point to convert a description into a path name
447
+ according to the so-called standard style.
448
+ """
449
+ raise NotImplementedError("This is an abstract method !")
450
+
451
+
452
+ class VortexDateNameBuilder(AbstractActualVortexNameBuilder):
453
+ """A Standard Vortex NameBuilder (with date and cutoff)."""
454
+
455
+ _footprint = dict(
456
+ info="A Standard Vortex NameBuilder (with date and cutoff)",
457
+ attr=dict(
458
+ name=dict(
459
+ values=[
460
+ "date@std",
461
+ ],
462
+ ),
463
+ ),
464
+ )
465
+
466
+ # A Vortex basename may include the following bits
467
+
468
+ def _pack_std_basename_flowstuff(self, d):
469
+ """Adds any info about term and period, ..."""
470
+ name = ""
471
+ if d["flow"] is not None:
472
+ pstuff = self._pack_std_items_periodstuff(d["flow"])
473
+ if pstuff:
474
+ name += "." + pstuff
475
+ return name
476
+
477
+ # Methods that generates basenames
478
+
479
+ def _pack_basename_obs(self, d):
480
+ """
481
+ Main entry point to convert a description into a file name
482
+ according to the so-called observation style.
483
+ """
484
+ obsfmt = d.get("nativefmt", d.get("fmt", None))
485
+ if obsfmt is None:
486
+ raise VortexNameBuilderError()
487
+ name = ".".join(
488
+ [
489
+ obsfmt + "-" + d.get("layout", "std"),
490
+ "void" if d["stage"] is None else d["stage"],
491
+ "all" if d["part"] is None else d["part"],
492
+ ]
493
+ )
494
+ if d["suffix"] is not None:
495
+ name = name + "." + d["suffix"]
496
+
497
+ return name.lower()
498
+
499
+ def _pack_basename_obsmap(self, d):
500
+ """
501
+ Main entry point to convert a description into a file name
502
+ according to the so-called observation-map style.
503
+ """
504
+ name = ".".join(
505
+ (
506
+ d["radical"],
507
+ "-".join(self._pack_std_items(d["stage"])),
508
+ "txt" if d["fmt"] is None else d["fmt"],
509
+ )
510
+ )
511
+ return name.lower()
512
+
513
+ # Methods that generates pathnames
514
+
515
+ def _pack_pathname_std(self, d):
516
+ """
517
+ Main entry point to convert a description into a path name
518
+ according to the so-called standard style.
519
+ """
520
+ pathbits = self._pack_pathname_init(d)
521
+ self._pack_pathname_append_flowdate(pathbits, d)
522
+ self._pack_pathname_append_scenario(pathbits, d)
523
+ self._pack_pathname_append_member(pathbits, d)
524
+ self._pack_pathname_append_block(pathbits, d)
525
+ return pathbits
526
+
527
+ _pack_pathname_obs = _pack_pathname_std
528
+ _pack_pathname_obsmap = _pack_pathname_std
529
+
530
+
531
+ class VortexPeriodNameBuilder(AbstractActualVortexNameBuilder):
532
+ """A Standard Vortex NameBuilder (with period and cutoff)."""
533
+
534
+ _footprint = dict(
535
+ info="A Standard Vortex NameBuilder (with period and cutoff)",
536
+ attr=dict(
537
+ name=dict(
538
+ values=[
539
+ "period@std",
540
+ ],
541
+ ),
542
+ ),
543
+ )
544
+
545
+ # A Vortex basename may include the following bits
546
+
547
+ def _pack_std_basename_flowstuff(self, d):
548
+ name = ""
549
+ if d["flow"] is not None:
550
+ dstuff = self._pack_std_items_datestuff(d["flow"])
551
+ if dstuff:
552
+ name += "." + dstuff
553
+ return name
554
+
555
+ # Methods that generates pathnames
556
+
557
+ def _pack_pathname_std(self, d):
558
+ """
559
+ Main entry point to convert a description into a file name
560
+ according to the so-called standard style.
561
+ """
562
+ pathbits = self._pack_pathname_init(d)
563
+ self._pack_pathname_append_flowperiod(pathbits, d)
564
+ self._pack_pathname_append_scenario(pathbits, d)
565
+ self._pack_pathname_append_member(pathbits, d)
566
+ self._pack_pathname_append_block(pathbits, d)
567
+ return pathbits
568
+
569
+
570
+ class VortexFlatNameBuilder(AbstractActualVortexNameBuilder):
571
+ """'A Standard Vortex NameBuilder (without date or period)."""
572
+
573
+ _footprint = dict(
574
+ info="A Standard Vortex NameBuilder (without date or period)",
575
+ attr=dict(
576
+ name=dict(
577
+ values=[
578
+ "flat@std",
579
+ ],
580
+ ),
581
+ ),
582
+ )
583
+
584
+ # A Vortex basename may include the following bits
585
+
586
+ def _pack_std_basename_flowstuff(self, d):
587
+ name = ""
588
+ if d["flow"] is not None:
589
+ dstuff = self._pack_std_items_datestuff(d["flow"])
590
+ if dstuff:
591
+ name += "." + dstuff
592
+ pstuff = self._pack_std_items_periodstuff(d["flow"])
593
+ if pstuff:
594
+ name += "." + pstuff
595
+ return name
596
+
597
+ # Methods that generates pathnames
598
+
599
+ def _pack_pathname_std(self, d):
600
+ """
601
+ Main entry point to convert a description into a file name
602
+ according to the so-called standard style.
603
+ """
604
+ pathbits = self._pack_pathname_init(d)
605
+ self._pack_pathname_append_scenario(pathbits, d)
606
+ self._pack_pathname_append_member(pathbits, d)
607
+ self._pack_pathname_append_block(pathbits, d)
608
+ return pathbits
609
+
610
+
611
+ class VortexNameBuilder(AbstractVortexNameBuilderProxy):
612
+ _explicit = False
613
+ _footprint = dict(
614
+ info="Standard Vortex NameBuilder Proxy",
615
+ attr=dict(
616
+ name=dict(
617
+ values=[
618
+ "std",
619
+ ],
620
+ optional=True,
621
+ default="std",
622
+ ),
623
+ ),
624
+ )
625
+
626
+ def _pick_actual_builder(self, d):
627
+ """Given the input dictionary, returns the appropriate builder object."""
628
+ actual_builder_name = "flat@std"
629
+ if "flow" in d and isinstance(d["flow"], (tuple, list)):
630
+ flowkeys = set()
631
+ for item in [item for item in d["flow"] if isinstance(item, dict)]:
632
+ flowkeys.update(item.keys())
633
+ if "date" in flowkeys:
634
+ actual_builder_name = "date@std"
635
+ elif "begindate" in flowkeys and "enddate" in flowkeys:
636
+ actual_builder_name = "period@std"
637
+ return self._get_builder(actual_builder_name)