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