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.
- vortex/__init__.py +135 -0
- vortex/algo/__init__.py +12 -0
- vortex/algo/components.py +2136 -0
- vortex/algo/mpitools.py +1648 -0
- vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
- vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
- vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
- vortex/algo/serversynctools.py +170 -0
- vortex/config.py +115 -0
- vortex/data/__init__.py +13 -0
- vortex/data/abstractstores.py +1572 -0
- vortex/data/containers.py +780 -0
- vortex/data/contents.py +596 -0
- vortex/data/executables.py +284 -0
- vortex/data/flow.py +113 -0
- vortex/data/geometries.ini +2689 -0
- vortex/data/geometries.py +703 -0
- vortex/data/handlers.py +1021 -0
- vortex/data/outflow.py +67 -0
- vortex/data/providers.py +465 -0
- vortex/data/resources.py +201 -0
- vortex/data/stores.py +1271 -0
- vortex/gloves.py +282 -0
- vortex/layout/__init__.py +27 -0
- vortex/layout/appconf.py +109 -0
- vortex/layout/contexts.py +511 -0
- vortex/layout/dataflow.py +1069 -0
- vortex/layout/jobs.py +1276 -0
- vortex/layout/monitor.py +833 -0
- vortex/layout/nodes.py +1424 -0
- vortex/layout/subjobs.py +464 -0
- vortex/nwp/__init__.py +11 -0
- vortex/nwp/algo/__init__.py +12 -0
- vortex/nwp/algo/assim.py +483 -0
- vortex/nwp/algo/clim.py +920 -0
- vortex/nwp/algo/coupling.py +609 -0
- vortex/nwp/algo/eda.py +632 -0
- vortex/nwp/algo/eps.py +613 -0
- vortex/nwp/algo/forecasts.py +745 -0
- vortex/nwp/algo/fpserver.py +927 -0
- vortex/nwp/algo/ifsnaming.py +403 -0
- vortex/nwp/algo/ifsroot.py +311 -0
- vortex/nwp/algo/monitoring.py +202 -0
- vortex/nwp/algo/mpitools.py +554 -0
- vortex/nwp/algo/odbtools.py +974 -0
- vortex/nwp/algo/oopsroot.py +735 -0
- vortex/nwp/algo/oopstests.py +186 -0
- vortex/nwp/algo/request.py +579 -0
- vortex/nwp/algo/stdpost.py +1285 -0
- vortex/nwp/data/__init__.py +12 -0
- vortex/nwp/data/assim.py +392 -0
- vortex/nwp/data/boundaries.py +261 -0
- vortex/nwp/data/climfiles.py +539 -0
- vortex/nwp/data/configfiles.py +149 -0
- vortex/nwp/data/consts.py +929 -0
- vortex/nwp/data/ctpini.py +133 -0
- vortex/nwp/data/diagnostics.py +181 -0
- vortex/nwp/data/eda.py +148 -0
- vortex/nwp/data/eps.py +383 -0
- vortex/nwp/data/executables.py +1039 -0
- vortex/nwp/data/fields.py +96 -0
- vortex/nwp/data/gridfiles.py +308 -0
- vortex/nwp/data/logs.py +551 -0
- vortex/nwp/data/modelstates.py +334 -0
- vortex/nwp/data/monitoring.py +220 -0
- vortex/nwp/data/namelists.py +644 -0
- vortex/nwp/data/obs.py +748 -0
- vortex/nwp/data/oopsexec.py +72 -0
- vortex/nwp/data/providers.py +182 -0
- vortex/nwp/data/query.py +217 -0
- vortex/nwp/data/stores.py +147 -0
- vortex/nwp/data/surfex.py +338 -0
- vortex/nwp/syntax/__init__.py +9 -0
- vortex/nwp/syntax/stdattrs.py +375 -0
- vortex/nwp/tools/__init__.py +10 -0
- vortex/nwp/tools/addons.py +35 -0
- vortex/nwp/tools/agt.py +55 -0
- vortex/nwp/tools/bdap.py +48 -0
- vortex/nwp/tools/bdcp.py +38 -0
- vortex/nwp/tools/bdm.py +21 -0
- vortex/nwp/tools/bdmp.py +49 -0
- vortex/nwp/tools/conftools.py +1311 -0
- vortex/nwp/tools/drhook.py +62 -0
- vortex/nwp/tools/grib.py +268 -0
- vortex/nwp/tools/gribdiff.py +99 -0
- vortex/nwp/tools/ifstools.py +163 -0
- vortex/nwp/tools/igastuff.py +249 -0
- vortex/nwp/tools/mars.py +56 -0
- vortex/nwp/tools/odb.py +548 -0
- vortex/nwp/tools/partitioning.py +234 -0
- vortex/nwp/tools/satrad.py +56 -0
- vortex/nwp/util/__init__.py +6 -0
- vortex/nwp/util/async.py +184 -0
- vortex/nwp/util/beacon.py +40 -0
- vortex/nwp/util/diffpygram.py +359 -0
- vortex/nwp/util/ens.py +198 -0
- vortex/nwp/util/hooks.py +128 -0
- vortex/nwp/util/taskdeco.py +81 -0
- vortex/nwp/util/usepygram.py +591 -0
- vortex/nwp/util/usetnt.py +87 -0
- vortex/proxy.py +6 -0
- vortex/sessions.py +341 -0
- vortex/syntax/__init__.py +9 -0
- vortex/syntax/stdattrs.py +628 -0
- vortex/syntax/stddeco.py +176 -0
- vortex/toolbox.py +982 -0
- vortex/tools/__init__.py +11 -0
- vortex/tools/actions.py +457 -0
- vortex/tools/addons.py +297 -0
- vortex/tools/arm.py +76 -0
- vortex/tools/compression.py +322 -0
- vortex/tools/date.py +20 -0
- vortex/tools/ddhpack.py +10 -0
- vortex/tools/delayedactions.py +672 -0
- vortex/tools/env.py +513 -0
- vortex/tools/folder.py +663 -0
- vortex/tools/grib.py +559 -0
- vortex/tools/lfi.py +746 -0
- vortex/tools/listings.py +354 -0
- vortex/tools/names.py +575 -0
- vortex/tools/net.py +1790 -0
- vortex/tools/odb.py +10 -0
- vortex/tools/parallelism.py +336 -0
- vortex/tools/prestaging.py +186 -0
- vortex/tools/rawfiles.py +10 -0
- vortex/tools/schedulers.py +413 -0
- vortex/tools/services.py +871 -0
- vortex/tools/storage.py +1061 -0
- vortex/tools/surfex.py +61 -0
- vortex/tools/systems.py +3396 -0
- vortex/tools/targets.py +384 -0
- vortex/util/__init__.py +9 -0
- vortex/util/config.py +1071 -0
- vortex/util/empty.py +24 -0
- vortex/util/helpers.py +184 -0
- vortex/util/introspection.py +63 -0
- vortex/util/iosponge.py +76 -0
- vortex/util/roles.py +51 -0
- vortex/util/storefunctions.py +103 -0
- vortex/util/structs.py +26 -0
- vortex/util/worker.py +150 -0
- vortex_nwp-2.0.0b1.dist-info/LICENSE +517 -0
- vortex_nwp-2.0.0b1.dist-info/METADATA +50 -0
- vortex_nwp-2.0.0b1.dist-info/RECORD +146 -0
- vortex_nwp-2.0.0b1.dist-info/WHEEL +5 -0
- vortex_nwp-2.0.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic Resources and Contents to work with namelists.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from bronx.fancies import loggers
|
|
8
|
+
from bronx.stdtypes.date import Time, Date
|
|
9
|
+
from bronx.datagrip.namelist import NO_SORTING, NamelistSet, NamelistParser
|
|
10
|
+
from footprints.stdtypes import FPList
|
|
11
|
+
from vortex import sessions
|
|
12
|
+
from vortex.data.outflow import ModelResource, StaticResource
|
|
13
|
+
from vortex.data.outflow import ModelGeoResource
|
|
14
|
+
from vortex.data.contents import AlmostDictContent, IndexedTable
|
|
15
|
+
from vortex.syntax.stdattrs import binaries, term, cutoff
|
|
16
|
+
from vortex.syntax.stddeco import namebuilding_insert
|
|
17
|
+
from vortex.tools import env
|
|
18
|
+
from ..syntax.stdattrs import gvar
|
|
19
|
+
|
|
20
|
+
#: No automatic export
|
|
21
|
+
__all__ = []
|
|
22
|
+
|
|
23
|
+
logger = loggers.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
KNOWN_NAMELIST_MACROS = {'NPROC', 'NBPROC', 'NBPROC_IO', 'NCPROC', 'NDPROC',
|
|
26
|
+
'NBPROCIN', 'NBPROCOUT', 'IDAT', 'CEXP',
|
|
27
|
+
'TIMESTEP', 'FCSTOP', 'NMODVAL', 'NBE', 'SEED',
|
|
28
|
+
'MEMBER', 'NUMOD', 'OUTPUTID', 'NRESX', 'PERTURB',
|
|
29
|
+
'JOUR', 'RES', 'LLADAJ', 'LLADMON', 'LLFLAG',
|
|
30
|
+
'LLARO', 'LLVRP', 'LLCAN'}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class NamelistPack(ModelResource):
|
|
34
|
+
"""
|
|
35
|
+
Class for all kinds of namelists
|
|
36
|
+
"""
|
|
37
|
+
_footprint = [
|
|
38
|
+
gvar,
|
|
39
|
+
dict(
|
|
40
|
+
info = 'A whole Namelist pack',
|
|
41
|
+
attr = dict(
|
|
42
|
+
kind = dict(
|
|
43
|
+
values = ['namelistpack']
|
|
44
|
+
),
|
|
45
|
+
gvar = dict(
|
|
46
|
+
values = ['NAMELIST_' + x.upper() for x in binaries],
|
|
47
|
+
default = 'namelist_[binary]'
|
|
48
|
+
),
|
|
49
|
+
model = dict(
|
|
50
|
+
optional = True,
|
|
51
|
+
),
|
|
52
|
+
binary = dict(
|
|
53
|
+
optional = True,
|
|
54
|
+
values = binaries,
|
|
55
|
+
default = '[model]',
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def realkind(self):
|
|
63
|
+
return 'namelistpack'
|
|
64
|
+
|
|
65
|
+
def gget_urlquery(self):
|
|
66
|
+
"""GGET specific query : ``dir_extract``."""
|
|
67
|
+
return 'dir_extract=1'
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class NamelistContentError(ValueError):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class NamelistContent(AlmostDictContent):
|
|
75
|
+
"""Fortran namelist including namelist blocks."""
|
|
76
|
+
|
|
77
|
+
def __init__(self, **kw):
|
|
78
|
+
"""
|
|
79
|
+
Initialize default namelist content with optional parameters:
|
|
80
|
+
* macros : pre-defined macros for all namelist blocks
|
|
81
|
+
* remove : elements to remove from the contents
|
|
82
|
+
* parser : a namelist parser object (a default one will be built otherwise)
|
|
83
|
+
"""
|
|
84
|
+
kw.setdefault('macros', {k: None for k in KNOWN_NAMELIST_MACROS})
|
|
85
|
+
kw.setdefault('remove', set())
|
|
86
|
+
kw.setdefault('parser', None)
|
|
87
|
+
kw.setdefault('data', NamelistSet())
|
|
88
|
+
super().__init__(**kw)
|
|
89
|
+
self._declaredmacros = set(self._macros.keys())
|
|
90
|
+
|
|
91
|
+
def toremove(self, bname):
|
|
92
|
+
"""Add an entry to the list of blocks to be removed."""
|
|
93
|
+
self._remove.add(bname)
|
|
94
|
+
|
|
95
|
+
def rmblocks(self):
|
|
96
|
+
"""Returns the list of blocks to get rid off."""
|
|
97
|
+
return self._remove
|
|
98
|
+
|
|
99
|
+
def macros(self):
|
|
100
|
+
"""Returns the dictionary of macros already registered."""
|
|
101
|
+
return self._macros.copy()
|
|
102
|
+
|
|
103
|
+
def setmacro(self, item, value):
|
|
104
|
+
"""Set macro value for further substitution."""
|
|
105
|
+
self._data.setmacro(item, value)
|
|
106
|
+
self._macros[item] = value
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def dumps_needs_update(self):
|
|
110
|
+
"""Tells wether something as changed in the namelist's dump."""
|
|
111
|
+
return self._data.dumps_needs_update
|
|
112
|
+
|
|
113
|
+
def dumps(self, sorting=NO_SORTING):
|
|
114
|
+
"""
|
|
115
|
+
Returns the namelist contents as a string.
|
|
116
|
+
Sorting option **sorting** (from bronx.datagrip.namelist):
|
|
117
|
+
|
|
118
|
+
* NO_SORTING;
|
|
119
|
+
* FIRST_ORDER_SORTING => sort all keys within blocks;
|
|
120
|
+
* SECOND_ORDER_SORTING => sort only within indexes or attributes of the same key.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
return self._data.dumps(sorting=sorting)
|
|
124
|
+
|
|
125
|
+
def merge(self, delta, rmkeys=None, rmblocks=None, clblocks=None):
|
|
126
|
+
"""Merge of the current namelist content with the set of namelist blocks provided."""
|
|
127
|
+
if isinstance(delta, NamelistContent):
|
|
128
|
+
if rmblocks is None and hasattr(delta, 'rmblocks'):
|
|
129
|
+
rmblocks = delta.rmblocks()
|
|
130
|
+
actualdelta = delta.data
|
|
131
|
+
else:
|
|
132
|
+
actualdelta = delta
|
|
133
|
+
self._data.merge(actualdelta,
|
|
134
|
+
rmkeys=rmkeys, rmblocks=rmblocks, clblocks=clblocks)
|
|
135
|
+
|
|
136
|
+
def slurp(self, container):
|
|
137
|
+
"""Get data from the ``container`` namelist."""
|
|
138
|
+
if not self._parser:
|
|
139
|
+
self._parser = NamelistParser(macros=self._declaredmacros)
|
|
140
|
+
with container.preferred_decoding(byte=False):
|
|
141
|
+
container.rewind()
|
|
142
|
+
try:
|
|
143
|
+
namset = self._parser.parse(container.read())
|
|
144
|
+
except (ValueError, OSError) as e:
|
|
145
|
+
raise NamelistContentError('Could not parse container contents: {!s}'.format(e))
|
|
146
|
+
self._data = namset
|
|
147
|
+
for macro, value in self._macros.items():
|
|
148
|
+
self._data.setmacro(macro, value)
|
|
149
|
+
|
|
150
|
+
def rewrite(self, container, sorting=NO_SORTING):
|
|
151
|
+
"""
|
|
152
|
+
Write the namelist contents in the specified container.
|
|
153
|
+
Sorting option **sorting** (from bronx.datagrip.namelist):
|
|
154
|
+
|
|
155
|
+
* NO_SORTING;
|
|
156
|
+
* FIRST_ORDER_SORTING => sort all keys within blocks;
|
|
157
|
+
* SECOND_ORDER_SORTING => sort only within indexes or attributes of the same key.
|
|
158
|
+
|
|
159
|
+
"""
|
|
160
|
+
container.close()
|
|
161
|
+
with container.iod_context():
|
|
162
|
+
with container.preferred_decoding(byte=False):
|
|
163
|
+
container.write(self.dumps(sorting=sorting))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class Namelist(ModelResource):
|
|
167
|
+
"""
|
|
168
|
+
Class for all kinds of namelists
|
|
169
|
+
"""
|
|
170
|
+
_footprint = [
|
|
171
|
+
gvar,
|
|
172
|
+
dict(
|
|
173
|
+
info = 'Namelist from binary pack',
|
|
174
|
+
attr = dict(
|
|
175
|
+
kind = dict(
|
|
176
|
+
values = ['namelist']
|
|
177
|
+
),
|
|
178
|
+
clscontents = dict(
|
|
179
|
+
default = NamelistContent
|
|
180
|
+
),
|
|
181
|
+
gvar = dict(
|
|
182
|
+
values = ['NAMELIST_' + x.upper() for x in binaries],
|
|
183
|
+
default = 'namelist_[binary]'
|
|
184
|
+
),
|
|
185
|
+
source = dict(
|
|
186
|
+
info = 'The namelist name within the namelist pack.',
|
|
187
|
+
optional = True,
|
|
188
|
+
default = 'namel_[binary]',
|
|
189
|
+
doc_zorder = 50
|
|
190
|
+
),
|
|
191
|
+
model = dict(
|
|
192
|
+
optional = True,
|
|
193
|
+
),
|
|
194
|
+
binary = dict(
|
|
195
|
+
optional = True,
|
|
196
|
+
values = binaries,
|
|
197
|
+
default = '[model]',
|
|
198
|
+
),
|
|
199
|
+
date = dict(
|
|
200
|
+
type = Date,
|
|
201
|
+
optional = True,
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def realkind(self):
|
|
209
|
+
return 'namelist'
|
|
210
|
+
|
|
211
|
+
def _find_source(self):
|
|
212
|
+
sources = self.source.split('|')
|
|
213
|
+
if len(sources) == 1:
|
|
214
|
+
source = sources[0].split(':')[0]
|
|
215
|
+
else:
|
|
216
|
+
# Check that the date argument was provided.:
|
|
217
|
+
if self.date is None:
|
|
218
|
+
raise AttributeError('The date argument should be provided when dealing ' +
|
|
219
|
+
'with time based namelist sources.')
|
|
220
|
+
datedSource = {}
|
|
221
|
+
for s in sources:
|
|
222
|
+
dateNsource = s.split(':')
|
|
223
|
+
if dateNsource[0]:
|
|
224
|
+
if len(dateNsource) == 2:
|
|
225
|
+
date = Date(dateNsource[1], year=self.date.year)
|
|
226
|
+
else:
|
|
227
|
+
date = Date(self.date.year, 1, 1)
|
|
228
|
+
if date not in datedSource.keys():
|
|
229
|
+
datedSource[date] = dateNsource[0]
|
|
230
|
+
else:
|
|
231
|
+
logger.warning('%s already begins the %s, %s is ignored.',
|
|
232
|
+
datedSource[date],
|
|
233
|
+
date.strftime('%d of %b.'), dateNsource[0])
|
|
234
|
+
datedSource = sorted(datedSource.items(), reverse=True)
|
|
235
|
+
source = datedSource[0][1]
|
|
236
|
+
for dateNsource in datedSource:
|
|
237
|
+
if self.date >= dateNsource[0]:
|
|
238
|
+
source = dateNsource[1]
|
|
239
|
+
break
|
|
240
|
+
logger.info('The consistent source is %s', source)
|
|
241
|
+
|
|
242
|
+
return source
|
|
243
|
+
|
|
244
|
+
def gget_urlquery(self):
|
|
245
|
+
"""GGET specific query : ``extract``."""
|
|
246
|
+
return 'extract=' + self._find_source()
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class NamelistDelta(Namelist):
|
|
250
|
+
"""
|
|
251
|
+
Class for namelist deltas (i.e. small bits of namelists).
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
_footprint = dict(
|
|
255
|
+
attr = dict(
|
|
256
|
+
kind = dict(
|
|
257
|
+
values = ['namdelta', 'deltanam', ]
|
|
258
|
+
),
|
|
259
|
+
source = dict(
|
|
260
|
+
default = 'deltanam.[binary]',
|
|
261
|
+
),
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
@property
|
|
266
|
+
def realkind(self):
|
|
267
|
+
return 'namdelta'
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class NamelistUtil(Namelist):
|
|
271
|
+
"""
|
|
272
|
+
Class for namelists utilities
|
|
273
|
+
"""
|
|
274
|
+
_footprint = dict(
|
|
275
|
+
info = 'Namelist from utilities pack',
|
|
276
|
+
attr = dict(
|
|
277
|
+
kind = dict(
|
|
278
|
+
values = ['namelist_util', 'namutil'],
|
|
279
|
+
remap = dict(autoremap = 'first'),
|
|
280
|
+
),
|
|
281
|
+
gvar = dict(
|
|
282
|
+
values = ['NAMELIST_UTILITIES'],
|
|
283
|
+
default = 'namelist_utilities'
|
|
284
|
+
),
|
|
285
|
+
binary = dict(
|
|
286
|
+
values = ['batodb', 'utilities', 'odbtools'],
|
|
287
|
+
default = 'utilities',
|
|
288
|
+
optional = True,
|
|
289
|
+
),
|
|
290
|
+
)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class NamelistTerm(Namelist):
|
|
295
|
+
"""
|
|
296
|
+
Class for all the terms dependent namelists
|
|
297
|
+
"""
|
|
298
|
+
_footprint = [
|
|
299
|
+
term,
|
|
300
|
+
dict(
|
|
301
|
+
info = 'Terms dependent namelist',
|
|
302
|
+
attr = dict(
|
|
303
|
+
kind = dict(
|
|
304
|
+
values = ['namterm']
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
)
|
|
308
|
+
]
|
|
309
|
+
|
|
310
|
+
def incoming_xxt_fixup(self, attr, key=None, prefix=None):
|
|
311
|
+
"""Fix as best as possible the ``xxt.def`` file."""
|
|
312
|
+
|
|
313
|
+
regex = re.compile(r',(.*)$')
|
|
314
|
+
myenv = env.current()
|
|
315
|
+
suffix = regex.search(myenv.VORTEX_XXT_DEF)
|
|
316
|
+
if suffix:
|
|
317
|
+
fp = suffix.group(1)
|
|
318
|
+
else:
|
|
319
|
+
fp = None
|
|
320
|
+
|
|
321
|
+
try:
|
|
322
|
+
with open('xxt.def') as f:
|
|
323
|
+
lines = f.readlines()
|
|
324
|
+
except OSError:
|
|
325
|
+
logger.error('Could not open file xxt.def')
|
|
326
|
+
raise
|
|
327
|
+
|
|
328
|
+
select = lines[self.term.hour].split()[2]
|
|
329
|
+
|
|
330
|
+
if not re.match(r'undef', select):
|
|
331
|
+
if fp:
|
|
332
|
+
rgx = re.compile(key + r'(.*)$')
|
|
333
|
+
sfx = rgx.search(select)
|
|
334
|
+
if sfx:
|
|
335
|
+
s = sfx.group(1)
|
|
336
|
+
else:
|
|
337
|
+
s = ''
|
|
338
|
+
return ''.join((key, '_', fp, s))
|
|
339
|
+
else:
|
|
340
|
+
return select
|
|
341
|
+
else:
|
|
342
|
+
logger.error('Fullpos namelist id not defined for term %s', self.term)
|
|
343
|
+
|
|
344
|
+
def incoming_namelist_fixup(self, attr, key=None):
|
|
345
|
+
"""Fix as best as possible the namelist term extensions."""
|
|
346
|
+
|
|
347
|
+
val = getattr(self, attr)
|
|
348
|
+
r1 = re.compile(r'^(.*\/)?(' + key + r'.*_fp|cpl)$')
|
|
349
|
+
r2 = re.compile(r'^(.*\/)?(' + key + r'.*_fp)(\..*)$')
|
|
350
|
+
r3 = re.compile(r'^(.*\/)?(' + key + r'.*_p)$')
|
|
351
|
+
|
|
352
|
+
fixed = 0
|
|
353
|
+
|
|
354
|
+
for r in (r1, r2, r3):
|
|
355
|
+
s = r.search(val)
|
|
356
|
+
if s:
|
|
357
|
+
fixed = 1
|
|
358
|
+
(dirpath, base) = (s.group(1), s.group(2))
|
|
359
|
+
if dirpath is None:
|
|
360
|
+
dirpath = ''
|
|
361
|
+
ext = ''
|
|
362
|
+
if r == r3:
|
|
363
|
+
if self.term.hour == 0:
|
|
364
|
+
p = '0'
|
|
365
|
+
elif self.term.hour % 6 == 0:
|
|
366
|
+
p = '6'
|
|
367
|
+
elif self.term.hour % 3 == 0:
|
|
368
|
+
p = '3'
|
|
369
|
+
else:
|
|
370
|
+
p = '1'
|
|
371
|
+
else:
|
|
372
|
+
if self.term.hour == 0:
|
|
373
|
+
p = '0'
|
|
374
|
+
else:
|
|
375
|
+
p = ''
|
|
376
|
+
if r == r2:
|
|
377
|
+
ext = s.group(3)
|
|
378
|
+
if ext is None:
|
|
379
|
+
ext = ''
|
|
380
|
+
|
|
381
|
+
if fixed:
|
|
382
|
+
return dirpath + base + p + ext
|
|
383
|
+
else:
|
|
384
|
+
return val
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class NamelistSelect(NamelistTerm):
|
|
388
|
+
"""
|
|
389
|
+
Class for the select namelists
|
|
390
|
+
"""
|
|
391
|
+
_footprint = [
|
|
392
|
+
dict(
|
|
393
|
+
info = 'Select namelist for fullpos ',
|
|
394
|
+
attr = dict(
|
|
395
|
+
kind = dict(
|
|
396
|
+
values = ['namselect', ]
|
|
397
|
+
)
|
|
398
|
+
)
|
|
399
|
+
)
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
@property
|
|
403
|
+
def realkind(self):
|
|
404
|
+
return 'namselect'
|
|
405
|
+
|
|
406
|
+
def gget_urlquery(self):
|
|
407
|
+
"""GGET specific query : ``extract``."""
|
|
408
|
+
myenv = env.current()
|
|
409
|
+
if myenv.true('VORTEX_XXT_DEF'):
|
|
410
|
+
return 'extract=' + self.incoming_xxt_fixup('source', 'select')
|
|
411
|
+
else:
|
|
412
|
+
return 'extract={:s}'.format(self.source)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class NamelistFullPos(NamelistTerm):
|
|
416
|
+
"""
|
|
417
|
+
Class for the fullpos term dependent namelists
|
|
418
|
+
"""
|
|
419
|
+
_footprint = [
|
|
420
|
+
dict(
|
|
421
|
+
info = 'Namelist for offline fullpos ',
|
|
422
|
+
attr = dict(
|
|
423
|
+
kind = dict(
|
|
424
|
+
values = ['namelistfp', ]
|
|
425
|
+
)
|
|
426
|
+
)
|
|
427
|
+
)
|
|
428
|
+
]
|
|
429
|
+
|
|
430
|
+
@property
|
|
431
|
+
def realkind(self):
|
|
432
|
+
return 'namelistfp'
|
|
433
|
+
|
|
434
|
+
def gget_urlquery(self):
|
|
435
|
+
"""GGET specific query : ``extract``."""
|
|
436
|
+
return 'extract=' + self.incoming_namelist_fixup('source', 'namel')
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
class NamelistFpServerObject(Namelist):
|
|
440
|
+
"""Class for a fullpos server object's namelists."""
|
|
441
|
+
|
|
442
|
+
_footprint = dict(
|
|
443
|
+
info = 'Namelist for a fullpos server object',
|
|
444
|
+
attr = dict(
|
|
445
|
+
kind = dict(
|
|
446
|
+
values = ['namelist_fpobject', ]
|
|
447
|
+
),
|
|
448
|
+
fp_conf = dict(
|
|
449
|
+
info = 'The FPCONF setting associated with this object.',
|
|
450
|
+
type = int,
|
|
451
|
+
optional = True,
|
|
452
|
+
),
|
|
453
|
+
fp_cmodel = dict(
|
|
454
|
+
info = 'The CMODEL setting associated with this object.',
|
|
455
|
+
optional = True,
|
|
456
|
+
),
|
|
457
|
+
fp_lextern = dict(
|
|
458
|
+
info = 'The LEXTERN setting associated with this object.',
|
|
459
|
+
type = bool,
|
|
460
|
+
optional = True,
|
|
461
|
+
),
|
|
462
|
+
fp_terms = dict(
|
|
463
|
+
info = ('Apply this object only on a subset of the input '
|
|
464
|
+
'data (based on term)'),
|
|
465
|
+
type = FPList,
|
|
466
|
+
optional = True,
|
|
467
|
+
)
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
@property
|
|
472
|
+
def realkind(self):
|
|
473
|
+
return 'namelist_fpobject'
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
class XXTContent(IndexedTable):
|
|
477
|
+
"""Indexed table of selection namelist used by inlined fullpos forecasts."""
|
|
478
|
+
|
|
479
|
+
def __init__(self, *kargs, **kwargs):
|
|
480
|
+
super().__init__(*kargs, **kwargs)
|
|
481
|
+
self._cachedomains = None
|
|
482
|
+
self._cachedomains_term = None
|
|
483
|
+
|
|
484
|
+
def fmtkey(self, key):
|
|
485
|
+
"""Reshape entry keys of the internal dictionary as a :class:`~bronx.stdtypes.date.Time` value."""
|
|
486
|
+
key = Time(key)
|
|
487
|
+
return key.fmthm
|
|
488
|
+
|
|
489
|
+
def xxtpos(self, n, g, x):
|
|
490
|
+
"""
|
|
491
|
+
Return value in position ``n`` for the ``term`` occurence defined in ``g`` or ``x``.
|
|
492
|
+
* ``g`` stands for a guess dictionary.
|
|
493
|
+
* ``x`` stands for an extra dictionary.
|
|
494
|
+
|
|
495
|
+
These naming convention refer to the footprints resolve mechanism.
|
|
496
|
+
"""
|
|
497
|
+
t = g.get('term', x.get('term', None))
|
|
498
|
+
if t is None:
|
|
499
|
+
return None
|
|
500
|
+
else:
|
|
501
|
+
value = None
|
|
502
|
+
try:
|
|
503
|
+
t = Time(t)
|
|
504
|
+
except (ValueError, TypeError):
|
|
505
|
+
return None
|
|
506
|
+
tkey = self.get(t.fmthm, self.get(str(t.hour), None))
|
|
507
|
+
if tkey is None:
|
|
508
|
+
logger.warning('No entry found in the XXT file for term = %s.', t.fmthm)
|
|
509
|
+
else:
|
|
510
|
+
try:
|
|
511
|
+
value = tkey[n]
|
|
512
|
+
except IndexError:
|
|
513
|
+
return None
|
|
514
|
+
return value
|
|
515
|
+
|
|
516
|
+
def xxtnam(self, g, x):
|
|
517
|
+
"""Return local namelist filename according to first column."""
|
|
518
|
+
return self.xxtpos(0, g, x)
|
|
519
|
+
|
|
520
|
+
def xxtsrc(self, g, x):
|
|
521
|
+
"""Return local namelist source in gco set according to second column."""
|
|
522
|
+
return self.xxtpos(1, g, x)
|
|
523
|
+
|
|
524
|
+
def mapdomains(self, maxterm=None, where=None):
|
|
525
|
+
"""Return a map of domains associated for each term in selection namelists."""
|
|
526
|
+
mapdom = dict()
|
|
527
|
+
allterms = sorted([Time(x) for x in self.keys()])
|
|
528
|
+
if maxterm is None:
|
|
529
|
+
if allterms:
|
|
530
|
+
maxterm = allterms[-1]
|
|
531
|
+
else:
|
|
532
|
+
maxterm = -1
|
|
533
|
+
maxterm = Time(maxterm)
|
|
534
|
+
|
|
535
|
+
if (self._cachedomains is None) or (self._cachedomains_term != maxterm):
|
|
536
|
+
|
|
537
|
+
select_seen = dict()
|
|
538
|
+
for a_term in [x for x in allterms if x <= maxterm]:
|
|
539
|
+
tvalue = self.get(a_term.fmthm, self.get(str(a_term.hour), None))
|
|
540
|
+
sh = sessions.system()
|
|
541
|
+
if tvalue[0] is not None:
|
|
542
|
+
local_guesses = [tvalue[0], 'fpselect_' + a_term.fmthm]
|
|
543
|
+
if where:
|
|
544
|
+
local_guesses = [sh.path.join(where, g) for g in local_guesses]
|
|
545
|
+
local_guesses = [g for g in local_guesses if sh.path.exists(g)]
|
|
546
|
+
if local_guesses:
|
|
547
|
+
# Do not waste time on duplicated selects...
|
|
548
|
+
if tvalue[1] not in select_seen:
|
|
549
|
+
fortp = NamelistParser()
|
|
550
|
+
with open(local_guesses[0]) as fd:
|
|
551
|
+
xx = fortp.parse(fd.read())
|
|
552
|
+
domains = set()
|
|
553
|
+
for nb in xx.values():
|
|
554
|
+
for domlist in [y for x, y in nb.items() if x.startswith('CLD')]:
|
|
555
|
+
domains = domains | set(domlist.pop().split(':'))
|
|
556
|
+
select_seen[tvalue[1]] = domains
|
|
557
|
+
else:
|
|
558
|
+
domains = select_seen[tvalue[1]]
|
|
559
|
+
mapdom[a_term.fmthm] = list(domains)
|
|
560
|
+
if a_term.minute == 0:
|
|
561
|
+
mapdom[str(a_term.hour)] = list(domains)
|
|
562
|
+
|
|
563
|
+
self._cachedomains_term = maxterm
|
|
564
|
+
self._cachedomains = mapdom
|
|
565
|
+
|
|
566
|
+
else:
|
|
567
|
+
mapdom = self._cachedomains
|
|
568
|
+
|
|
569
|
+
return dict(term=mapdom)
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
class NamelistSelectDef(StaticResource):
|
|
573
|
+
"""Utility, so-called xxt file."""
|
|
574
|
+
_footprint = [
|
|
575
|
+
cutoff,
|
|
576
|
+
gvar,
|
|
577
|
+
dict(
|
|
578
|
+
info = 'xxt.def file from namelist pack',
|
|
579
|
+
attr = dict(
|
|
580
|
+
gvar = dict(
|
|
581
|
+
values = ['NAMELIST_' + x.upper() for x in binaries],
|
|
582
|
+
default = 'namelist_[binary]'
|
|
583
|
+
),
|
|
584
|
+
source = dict(
|
|
585
|
+
optional = True,
|
|
586
|
+
),
|
|
587
|
+
binary = dict(
|
|
588
|
+
optional = True,
|
|
589
|
+
values = binaries,
|
|
590
|
+
default = '[model]',
|
|
591
|
+
),
|
|
592
|
+
kind = dict(
|
|
593
|
+
values = ['xxtdef', 'namselectdef']
|
|
594
|
+
),
|
|
595
|
+
clscontents = dict(
|
|
596
|
+
default = XXTContent
|
|
597
|
+
)
|
|
598
|
+
),
|
|
599
|
+
bind = ['gvar', 'source']
|
|
600
|
+
)
|
|
601
|
+
]
|
|
602
|
+
|
|
603
|
+
_source_map = dict(assim='xxt.def.assim', )
|
|
604
|
+
|
|
605
|
+
@property
|
|
606
|
+
def realkind(self):
|
|
607
|
+
return 'namselectdef'
|
|
608
|
+
|
|
609
|
+
def gget_urlquery(self):
|
|
610
|
+
"""GGET specific query : ``extract``."""
|
|
611
|
+
if self.source is None:
|
|
612
|
+
thesource = self._source_map.get(self.cutoff, 'xxt.def')
|
|
613
|
+
else:
|
|
614
|
+
thesource = self.source
|
|
615
|
+
return 'extract=' + thesource
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
@namebuilding_insert('src', lambda s: s.target)
|
|
619
|
+
class GeoBlocks(ModelGeoResource):
|
|
620
|
+
"""Extract of a namelist containing Geometry blocks."""
|
|
621
|
+
|
|
622
|
+
_footprint = dict(
|
|
623
|
+
attr = dict(
|
|
624
|
+
kind = dict(
|
|
625
|
+
info = "Geometry blocks of namelist.",
|
|
626
|
+
values = ['geoblocks']
|
|
627
|
+
),
|
|
628
|
+
clscontents = dict(
|
|
629
|
+
default = NamelistContent,
|
|
630
|
+
),
|
|
631
|
+
target = dict(
|
|
632
|
+
info = "Scope that should use these blocks.",
|
|
633
|
+
),
|
|
634
|
+
nativefmt = dict(
|
|
635
|
+
optional = True,
|
|
636
|
+
values = ['nam'],
|
|
637
|
+
default = 'nam',
|
|
638
|
+
),
|
|
639
|
+
)
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
@property
|
|
643
|
+
def realkind(self):
|
|
644
|
+
return 'geoblocks'
|