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.
- vortex/__init__.py +59 -45
- vortex/algo/__init__.py +3 -2
- vortex/algo/components.py +940 -614
- vortex/algo/mpitools.py +802 -497
- vortex/algo/serversynctools.py +34 -33
- vortex/config.py +19 -22
- vortex/data/__init__.py +9 -3
- vortex/data/abstractstores.py +593 -655
- vortex/data/containers.py +217 -162
- vortex/data/contents.py +65 -39
- vortex/data/executables.py +93 -102
- vortex/data/flow.py +40 -34
- vortex/data/geometries.py +228 -132
- vortex/data/handlers.py +428 -225
- vortex/data/outflow.py +15 -15
- vortex/data/providers.py +185 -163
- vortex/data/resources.py +48 -42
- vortex/data/stores.py +544 -413
- vortex/gloves.py +114 -87
- vortex/layout/__init__.py +1 -8
- vortex/layout/contexts.py +150 -84
- vortex/layout/dataflow.py +353 -202
- vortex/layout/monitor.py +264 -128
- vortex/nwp/__init__.py +5 -2
- vortex/nwp/algo/__init__.py +14 -5
- vortex/nwp/algo/assim.py +205 -151
- vortex/nwp/algo/clim.py +683 -517
- vortex/nwp/algo/coupling.py +447 -225
- vortex/nwp/algo/eda.py +437 -229
- vortex/nwp/algo/eps.py +403 -231
- vortex/nwp/algo/forecasts.py +420 -271
- vortex/nwp/algo/fpserver.py +683 -307
- vortex/nwp/algo/ifsnaming.py +205 -145
- vortex/nwp/algo/ifsroot.py +210 -122
- vortex/nwp/algo/monitoring.py +132 -76
- vortex/nwp/algo/mpitools.py +321 -191
- vortex/nwp/algo/odbtools.py +617 -353
- vortex/nwp/algo/oopsroot.py +449 -273
- vortex/nwp/algo/oopstests.py +90 -56
- vortex/nwp/algo/request.py +287 -206
- vortex/nwp/algo/stdpost.py +878 -522
- vortex/nwp/data/__init__.py +22 -4
- vortex/nwp/data/assim.py +125 -137
- vortex/nwp/data/boundaries.py +121 -68
- vortex/nwp/data/climfiles.py +193 -211
- vortex/nwp/data/configfiles.py +73 -69
- vortex/nwp/data/consts.py +426 -401
- vortex/nwp/data/ctpini.py +59 -43
- vortex/nwp/data/diagnostics.py +94 -66
- vortex/nwp/data/eda.py +50 -51
- vortex/nwp/data/eps.py +195 -146
- vortex/nwp/data/executables.py +440 -434
- vortex/nwp/data/fields.py +63 -48
- vortex/nwp/data/gridfiles.py +183 -111
- vortex/nwp/data/logs.py +250 -217
- vortex/nwp/data/modelstates.py +180 -151
- vortex/nwp/data/monitoring.py +72 -99
- vortex/nwp/data/namelists.py +254 -202
- vortex/nwp/data/obs.py +400 -308
- vortex/nwp/data/oopsexec.py +22 -20
- vortex/nwp/data/providers.py +90 -65
- vortex/nwp/data/query.py +71 -82
- vortex/nwp/data/stores.py +49 -36
- vortex/nwp/data/surfex.py +136 -137
- vortex/nwp/syntax/__init__.py +1 -1
- vortex/nwp/syntax/stdattrs.py +173 -111
- vortex/nwp/tools/__init__.py +2 -2
- vortex/nwp/tools/addons.py +22 -17
- vortex/nwp/tools/agt.py +24 -12
- vortex/nwp/tools/bdap.py +16 -5
- vortex/nwp/tools/bdcp.py +4 -1
- vortex/nwp/tools/bdm.py +3 -0
- vortex/nwp/tools/bdmp.py +14 -9
- vortex/nwp/tools/conftools.py +728 -378
- vortex/nwp/tools/drhook.py +12 -8
- vortex/nwp/tools/grib.py +65 -39
- vortex/nwp/tools/gribdiff.py +22 -17
- vortex/nwp/tools/ifstools.py +82 -42
- vortex/nwp/tools/igastuff.py +167 -143
- vortex/nwp/tools/mars.py +14 -2
- vortex/nwp/tools/odb.py +234 -125
- vortex/nwp/tools/partitioning.py +61 -37
- vortex/nwp/tools/satrad.py +27 -12
- vortex/nwp/util/async.py +83 -55
- vortex/nwp/util/beacon.py +10 -10
- vortex/nwp/util/diffpygram.py +174 -86
- vortex/nwp/util/ens.py +144 -63
- vortex/nwp/util/hooks.py +30 -19
- vortex/nwp/util/taskdeco.py +28 -24
- vortex/nwp/util/usepygram.py +278 -172
- vortex/nwp/util/usetnt.py +31 -17
- vortex/sessions.py +72 -39
- vortex/syntax/__init__.py +1 -1
- vortex/syntax/stdattrs.py +410 -171
- vortex/syntax/stddeco.py +31 -22
- vortex/toolbox.py +327 -192
- vortex/tools/__init__.py +11 -2
- vortex/tools/actions.py +125 -59
- vortex/tools/addons.py +111 -92
- vortex/tools/arm.py +42 -22
- vortex/tools/compression.py +72 -69
- vortex/tools/date.py +11 -4
- vortex/tools/delayedactions.py +242 -132
- vortex/tools/env.py +75 -47
- vortex/tools/folder.py +342 -171
- vortex/tools/grib.py +311 -149
- vortex/tools/lfi.py +423 -216
- vortex/tools/listings.py +109 -40
- vortex/tools/names.py +218 -156
- vortex/tools/net.py +632 -298
- vortex/tools/parallelism.py +93 -61
- vortex/tools/prestaging.py +55 -31
- vortex/tools/schedulers.py +172 -105
- vortex/tools/services.py +402 -333
- vortex/tools/storage.py +293 -358
- vortex/tools/surfex.py +24 -24
- vortex/tools/systems.py +1211 -631
- vortex/tools/targets.py +156 -100
- vortex/util/__init__.py +1 -1
- vortex/util/config.py +377 -327
- vortex/util/empty.py +2 -2
- vortex/util/helpers.py +56 -24
- vortex/util/introspection.py +18 -12
- vortex/util/iosponge.py +8 -4
- vortex/util/roles.py +4 -6
- vortex/util/storefunctions.py +39 -13
- vortex/util/structs.py +3 -3
- vortex/util/worker.py +29 -17
- vortex_nwp-2.0.0b2.dist-info/METADATA +66 -0
- vortex_nwp-2.0.0b2.dist-info/RECORD +142 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/WHEEL +1 -1
- vortex/layout/appconf.py +0 -109
- vortex/layout/jobs.py +0 -1276
- vortex/layout/nodes.py +0 -1424
- vortex/layout/subjobs.py +0 -464
- vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
- vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/LICENSE +0 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/top_level.txt +0 -0
vortex/data/geometries.py
CHANGED
|
@@ -62,7 +62,6 @@ import bronx.patterns.getbytag
|
|
|
62
62
|
import footprints
|
|
63
63
|
|
|
64
64
|
from vortex.syntax.stddeco import namebuilding_insert, generic_pathname_insert
|
|
65
|
-
from vortex.util.config import GenericConfigParser
|
|
66
65
|
|
|
67
66
|
#: No automatic export
|
|
68
67
|
__all__ = []
|
|
@@ -72,6 +71,7 @@ logger = loggers.getLogger(__name__)
|
|
|
72
71
|
|
|
73
72
|
# Module Interface
|
|
74
73
|
|
|
74
|
+
|
|
75
75
|
def get(**kw):
|
|
76
76
|
"""Return actual geometry object matching description.
|
|
77
77
|
|
|
@@ -111,6 +111,7 @@ def grep(**kw):
|
|
|
111
111
|
|
|
112
112
|
# Abstract geometry classes
|
|
113
113
|
|
|
114
|
+
|
|
114
115
|
class Geometry(bronx.patterns.getbytag.GetByTag):
|
|
115
116
|
"""Abstract geometry."""
|
|
116
117
|
|
|
@@ -124,18 +125,21 @@ class Geometry(bronx.patterns.getbytag.GetByTag):
|
|
|
124
125
|
|
|
125
126
|
.. note:: This is an abstract class, do not instantiate.
|
|
126
127
|
"""
|
|
127
|
-
self.info =
|
|
128
|
+
self.info = "anonymous"
|
|
128
129
|
self.inifile = None
|
|
129
130
|
self.__dict__.update(kw)
|
|
130
|
-
self.kind =
|
|
131
|
+
self.kind = "abstract"
|
|
131
132
|
self._init_attributes = {k: v for k, v in kw.items() if v is not None}
|
|
132
|
-
logger.debug(
|
|
133
|
+
logger.debug("Abstract Geometry init kw=%s", str(kw))
|
|
133
134
|
|
|
134
135
|
@classmethod
|
|
135
136
|
def _tag_implicit_new_error(cls, tag):
|
|
136
137
|
"""Called whenever a tag does not exists and _tag_implicit_new = False."""
|
|
137
|
-
raise RuntimeError(
|
|
138
|
-
|
|
138
|
+
raise RuntimeError(
|
|
139
|
+
'The "{:s}" {:s} object does not exist yet...'.format(
|
|
140
|
+
tag, cls.__name__
|
|
141
|
+
)
|
|
142
|
+
)
|
|
139
143
|
|
|
140
144
|
@classmethod
|
|
141
145
|
def tag_clean(self, tag):
|
|
@@ -144,7 +148,7 @@ class Geometry(bronx.patterns.getbytag.GetByTag):
|
|
|
144
148
|
|
|
145
149
|
def __repr__(self):
|
|
146
150
|
"""Nicer represenation for geometries."""
|
|
147
|
-
return
|
|
151
|
+
return "<{:s}.{:s} (tag='{:s}') object at {:#x}>".format(
|
|
148
152
|
self.__module__, self.__class__.__name__, self.tag, id(self)
|
|
149
153
|
)
|
|
150
154
|
|
|
@@ -153,14 +157,14 @@ class Geometry(bronx.patterns.getbytag.GetByTag):
|
|
|
153
157
|
|
|
154
158
|
def doc_export(self):
|
|
155
159
|
"""Relevant informations to print in the documentation."""
|
|
156
|
-
return
|
|
160
|
+
return "kind={:s}".format(self.kind)
|
|
157
161
|
|
|
158
162
|
def to_inifile(self):
|
|
159
163
|
"""Format geometry to put in the inifile."""
|
|
160
164
|
self._init_attributes.update(kind=self.kind)
|
|
161
|
-
s =
|
|
165
|
+
s = "[{}]\n".format(self.tag)
|
|
162
166
|
for k in sorted(self._init_attributes.keys()):
|
|
163
|
-
s +=
|
|
167
|
+
s += "{:10s} = {}\n".format(k, self._init_attributes[k])
|
|
164
168
|
return s
|
|
165
169
|
|
|
166
170
|
|
|
@@ -178,8 +182,10 @@ class VerticalGeometry(Geometry):
|
|
|
178
182
|
.. note:: This is an abstract class, do not instantiate.
|
|
179
183
|
"""
|
|
180
184
|
super().__init__(**kw)
|
|
181
|
-
self.kind =
|
|
182
|
-
logger.debug(
|
|
185
|
+
self.kind = "vertical"
|
|
186
|
+
logger.debug(
|
|
187
|
+
"Abstract Vertical Geometry init %s %s", str(self), str(kw)
|
|
188
|
+
)
|
|
183
189
|
|
|
184
190
|
|
|
185
191
|
class HorizontalGeometry(Geometry):
|
|
@@ -197,7 +203,7 @@ class HorizontalGeometry(Geometry):
|
|
|
197
203
|
.. note:: This is an abstract class, do not instantiate.
|
|
198
204
|
"""
|
|
199
205
|
desc = dict(
|
|
200
|
-
info=
|
|
206
|
+
info="anonymous",
|
|
201
207
|
gridtype=None,
|
|
202
208
|
area=None,
|
|
203
209
|
nlon=None,
|
|
@@ -205,8 +211,8 @@ class HorizontalGeometry(Geometry):
|
|
|
205
211
|
nlat=None,
|
|
206
212
|
ni=None,
|
|
207
213
|
nj=None,
|
|
208
|
-
resolution=0
|
|
209
|
-
expected_resolution=0
|
|
214
|
+
resolution=0.0,
|
|
215
|
+
expected_resolution=0.0,
|
|
210
216
|
runit=None,
|
|
211
217
|
truncation=None,
|
|
212
218
|
truncationtype=None,
|
|
@@ -220,22 +226,30 @@ class HorizontalGeometry(Geometry):
|
|
|
220
226
|
desc.update(kw)
|
|
221
227
|
super().__init__(**desc)
|
|
222
228
|
for k, v in self.__dict__.items():
|
|
223
|
-
if isinstance(v, str) and re.match(
|
|
229
|
+
if isinstance(v, str) and re.match("none", v, re.IGNORECASE):
|
|
224
230
|
self.__dict__[k] = None
|
|
225
|
-
if isinstance(v, str) and re.match(
|
|
231
|
+
if isinstance(v, str) and re.match("true", v, re.IGNORECASE):
|
|
226
232
|
self.__dict__[k] = True
|
|
227
|
-
if isinstance(v, str) and re.match(
|
|
233
|
+
if isinstance(v, str) and re.match("false", v, re.IGNORECASE):
|
|
228
234
|
self.__dict__[k] = False
|
|
229
|
-
for item in (
|
|
235
|
+
for item in (
|
|
236
|
+
"nlon",
|
|
237
|
+
"nlat",
|
|
238
|
+
"ni",
|
|
239
|
+
"nj",
|
|
240
|
+
"nmassif",
|
|
241
|
+
"nposts",
|
|
242
|
+
"truncation",
|
|
243
|
+
):
|
|
230
244
|
cv = getattr(self, item)
|
|
231
245
|
if cv is not None:
|
|
232
246
|
setattr(self, item, int(cv))
|
|
233
|
-
for item in (
|
|
247
|
+
for item in ("stretching", "resolution", "lonmin", "latmin"):
|
|
234
248
|
cv = getattr(self, item)
|
|
235
249
|
if cv is not None:
|
|
236
250
|
setattr(self, item, float(cv))
|
|
237
251
|
self._check_attributes()
|
|
238
|
-
logger.debug(
|
|
252
|
+
logger.debug("Abstract Horizontal Geometry init %s", str(self))
|
|
239
253
|
|
|
240
254
|
def _check_attributes(self):
|
|
241
255
|
if self.lam and (self.area is None):
|
|
@@ -250,15 +264,15 @@ class HorizontalGeometry(Geometry):
|
|
|
250
264
|
def rnice(self):
|
|
251
265
|
"""Returns a string with a nice representation of the resolution (if sensible)."""
|
|
252
266
|
if self.runit is not None:
|
|
253
|
-
if self.runit ==
|
|
254
|
-
res =
|
|
255
|
-
elif self.runit in (
|
|
256
|
-
res =
|
|
267
|
+
if self.runit == "km":
|
|
268
|
+
res = "{:05.2f}".format(self.resolution)
|
|
269
|
+
elif self.runit in ("s", "min"):
|
|
270
|
+
res = "{:04.1f}".format(self.resolution)
|
|
257
271
|
else:
|
|
258
|
-
res =
|
|
259
|
-
return re.sub(r
|
|
272
|
+
res = "{:06.3f}".format(self.resolution)
|
|
273
|
+
return re.sub(r"\.", self.runit, res, 1)
|
|
260
274
|
else:
|
|
261
|
-
return
|
|
275
|
+
return "Unknown Resolution"
|
|
262
276
|
|
|
263
277
|
@property
|
|
264
278
|
def rnice_u(self):
|
|
@@ -266,16 +280,20 @@ class HorizontalGeometry(Geometry):
|
|
|
266
280
|
|
|
267
281
|
@property
|
|
268
282
|
def gco_grid_def(self):
|
|
269
|
-
return (
|
|
283
|
+
return (
|
|
284
|
+
"{0.area}" + ("_{0.rnice}" if self.runit is not None else "")
|
|
285
|
+
).format(self)
|
|
270
286
|
|
|
271
287
|
def anonymous_info(self, *args): # @UnusedVariable
|
|
272
288
|
"""Try to build a meaningful information from an anonymous geometry."""
|
|
273
|
-
return
|
|
289
|
+
return "{!s}, {:s}".format(self.area, self.rnice)
|
|
274
290
|
|
|
275
291
|
def __str__(self):
|
|
276
292
|
"""Very short presentation."""
|
|
277
|
-
if self.info ==
|
|
278
|
-
return
|
|
293
|
+
if self.info == "anonymous":
|
|
294
|
+
return "{:s}({:s})".format(
|
|
295
|
+
self.__class__.__name__, self.anonymous_info()
|
|
296
|
+
)
|
|
279
297
|
else:
|
|
280
298
|
return self.info
|
|
281
299
|
|
|
@@ -284,41 +302,61 @@ class HorizontalGeometry(Geometry):
|
|
|
284
302
|
Returns a multilines documentation string with a summary
|
|
285
303
|
of the valuable information contained by this geometry.
|
|
286
304
|
"""
|
|
287
|
-
indent =
|
|
305
|
+
indent = " " * indent
|
|
288
306
|
# Basics...
|
|
289
|
-
card = "\n".join(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
307
|
+
card = "\n".join(
|
|
308
|
+
(
|
|
309
|
+
"{0}Geometry {1!r}",
|
|
310
|
+
"{0}{0}Info : {2:s}",
|
|
311
|
+
"{0}{0}LAM : {3!s}",
|
|
312
|
+
)
|
|
313
|
+
).format(indent, self, self.info, self.lam)
|
|
294
314
|
# Optional infos
|
|
295
|
-
for attr in [
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
315
|
+
for attr in [
|
|
316
|
+
k
|
|
317
|
+
for k in (
|
|
318
|
+
"area",
|
|
319
|
+
"resolution",
|
|
320
|
+
"truncation",
|
|
321
|
+
"stretching",
|
|
322
|
+
"nlon",
|
|
323
|
+
"nlat",
|
|
324
|
+
"ni",
|
|
325
|
+
"nj",
|
|
326
|
+
"nmassif",
|
|
327
|
+
"nposts",
|
|
328
|
+
)
|
|
329
|
+
if getattr(self, k, False)
|
|
330
|
+
]:
|
|
331
|
+
card += "\n{0}{0}{1:10s} : {2!s}".format(
|
|
332
|
+
indent, attr.title(), getattr(self, attr)
|
|
333
|
+
)
|
|
301
334
|
return card
|
|
302
335
|
|
|
303
336
|
def strheader(self):
|
|
304
337
|
"""Return the beginning of the formatted print representation."""
|
|
305
|
-
header =
|
|
338
|
+
header = "{:s}.{:s} | tag='{}' id='{:s}'".format(
|
|
306
339
|
self.__module__,
|
|
307
340
|
self.__class__.__name__,
|
|
308
341
|
self.tag,
|
|
309
342
|
self.info,
|
|
310
343
|
)
|
|
311
344
|
if self.lam:
|
|
312
|
-
header +=
|
|
345
|
+
header += " area='{:s}'".format(self.area)
|
|
313
346
|
return header
|
|
314
347
|
|
|
315
348
|
@property
|
|
316
349
|
def coordinates(self):
|
|
317
|
-
if any(
|
|
350
|
+
if any(
|
|
351
|
+
[
|
|
352
|
+
getattr(self, x) is None
|
|
353
|
+
for x in ("lonmin", "latmin", "nlat", "nlon", "resolution")
|
|
354
|
+
]
|
|
355
|
+
):
|
|
318
356
|
return dict()
|
|
319
357
|
coordinates = dict(lonmin=self.lonmin, latmin=self.latmin)
|
|
320
|
-
coordinates[
|
|
321
|
-
coordinates[
|
|
358
|
+
coordinates["latmax"] = self.latmin + self.resolution * (self.nlat - 1)
|
|
359
|
+
coordinates["lonmax"] = self.lonmin + self.resolution * (self.nlon - 1)
|
|
322
360
|
return coordinates
|
|
323
361
|
|
|
324
362
|
|
|
@@ -330,10 +368,13 @@ class SpectralAwareHorizontalGeometry(HorizontalGeometry):
|
|
|
330
368
|
def _check_attributes(self):
|
|
331
369
|
super()._check_attributes()
|
|
332
370
|
if self.truncationtype is None:
|
|
333
|
-
self.truncationtype =
|
|
334
|
-
if self.truncationtype not in (
|
|
335
|
-
raise ValueError(
|
|
336
|
-
|
|
371
|
+
self.truncationtype = "linear"
|
|
372
|
+
if self.truncationtype not in ("linear", "quadratic", "cubic"):
|
|
373
|
+
raise ValueError(
|
|
374
|
+
"Improper value {:s} for *truncationtype*".format(
|
|
375
|
+
self.truncationtype
|
|
376
|
+
)
|
|
377
|
+
)
|
|
337
378
|
|
|
338
379
|
@property
|
|
339
380
|
def short_truncationtype(self):
|
|
@@ -341,11 +382,14 @@ class SpectralAwareHorizontalGeometry(HorizontalGeometry):
|
|
|
341
382
|
|
|
342
383
|
@property
|
|
343
384
|
def xtruncationtype(self):
|
|
344
|
-
return dict(quadratic=
|
|
385
|
+
return dict(quadratic="quad").get(
|
|
386
|
+
self.truncationtype, self.truncationtype
|
|
387
|
+
)
|
|
345
388
|
|
|
346
389
|
|
|
347
390
|
# Combined geometry (not used at the present time)
|
|
348
391
|
|
|
392
|
+
|
|
349
393
|
class CombinedGeometry(Geometry):
|
|
350
394
|
"""Combine horizontal and vertical geometry (not used at the present time)."""
|
|
351
395
|
|
|
@@ -362,12 +406,13 @@ class CombinedGeometry(Geometry):
|
|
|
362
406
|
self.hgeo = None
|
|
363
407
|
self.vgeo = None
|
|
364
408
|
super().__init__(**kw)
|
|
365
|
-
self.kind =
|
|
366
|
-
logger.debug(
|
|
409
|
+
self.kind = "combined"
|
|
410
|
+
logger.debug("Combined Geometry init %s %s", str(self), str(kw))
|
|
367
411
|
|
|
368
412
|
|
|
369
413
|
# Concrete geometry classes
|
|
370
414
|
|
|
415
|
+
|
|
371
416
|
class GaussGeometry(SpectralAwareHorizontalGeometry):
|
|
372
417
|
"""
|
|
373
418
|
Gaussian grid (stretched or not, rotated or not) associated with a spectral
|
|
@@ -392,8 +437,8 @@ class GaussGeometry(SpectralAwareHorizontalGeometry):
|
|
|
392
437
|
.. note:: Gaussian grids are always global grids.
|
|
393
438
|
"""
|
|
394
439
|
super().__init__(**kw)
|
|
395
|
-
self.kind =
|
|
396
|
-
logger.debug(
|
|
440
|
+
self.kind = "gauss"
|
|
441
|
+
logger.debug("Gauss Geometry init %s", str(self))
|
|
397
442
|
|
|
398
443
|
def _check_attributes(self):
|
|
399
444
|
self.lam = False # Always false for gaussian grid
|
|
@@ -401,39 +446,48 @@ class GaussGeometry(SpectralAwareHorizontalGeometry):
|
|
|
401
446
|
if self.truncation is None or self.stretching is None:
|
|
402
447
|
raise AttributeError("Some mandatory arguments are missing")
|
|
403
448
|
if self.gridtype is None:
|
|
404
|
-
self.gridtype =
|
|
405
|
-
if self.gridtype not in (
|
|
406
|
-
raise ValueError(
|
|
407
|
-
|
|
449
|
+
self.gridtype = "rgrid"
|
|
450
|
+
if self.gridtype not in ("rgrid", "octahedral"):
|
|
451
|
+
raise ValueError(
|
|
452
|
+
"Improper value {:s} for *gridtype*".format(self.gridtype)
|
|
453
|
+
)
|
|
408
454
|
|
|
409
455
|
@property
|
|
410
456
|
def short_gridtype(self):
|
|
411
|
-
return self.gridtype[0] if self.gridtype !=
|
|
457
|
+
return self.gridtype[0] if self.gridtype != "rgrid" else ""
|
|
412
458
|
|
|
413
459
|
@property
|
|
414
460
|
def gco_grid_def(self):
|
|
415
|
-
geotag_f =
|
|
416
|
-
if self.truncationtype !=
|
|
417
|
-
geotag_f +=
|
|
418
|
-
geotag_f +=
|
|
461
|
+
geotag_f = "t"
|
|
462
|
+
if self.truncationtype != "linear" or self.gridtype != "rgrid":
|
|
463
|
+
geotag_f += "{0.short_truncationtype}"
|
|
464
|
+
geotag_f += "{0.short_gridtype}{0.truncation:d}"
|
|
419
465
|
return geotag_f.format(self)
|
|
420
466
|
|
|
421
467
|
def __str__(self):
|
|
422
468
|
"""Standard formatted print representation."""
|
|
423
|
-
return
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
469
|
+
return "<{:s} t{:s}{:s}={:d} c={:g}>".format(
|
|
470
|
+
self.strheader(),
|
|
471
|
+
self.short_truncationtype,
|
|
472
|
+
self.short_gridtype,
|
|
473
|
+
self.truncation,
|
|
474
|
+
self.stretching,
|
|
475
|
+
)
|
|
428
476
|
|
|
429
477
|
def doc_export(self):
|
|
430
478
|
"""Relevant informations to print in the documentation."""
|
|
431
479
|
if self.stretching > 1:
|
|
432
|
-
fmts =
|
|
480
|
+
fmts = "kind={0:s}, t{1:s}{2:s}={3:d}, c={4:g} (pole of interest over {5!s})"
|
|
433
481
|
else:
|
|
434
|
-
fmts =
|
|
435
|
-
return fmts.format(
|
|
436
|
-
|
|
482
|
+
fmts = "kind={0:s}, t{1:s}{2:s}={3:d}, c={4:g}"
|
|
483
|
+
return fmts.format(
|
|
484
|
+
self.kind,
|
|
485
|
+
self.short_truncationtype,
|
|
486
|
+
self.short_gridtype,
|
|
487
|
+
self.truncation,
|
|
488
|
+
self.stretching,
|
|
489
|
+
self.area,
|
|
490
|
+
)
|
|
437
491
|
|
|
438
492
|
|
|
439
493
|
class ProjectedGeometry(SpectralAwareHorizontalGeometry):
|
|
@@ -451,10 +505,10 @@ class ProjectedGeometry(SpectralAwareHorizontalGeometry):
|
|
|
451
505
|
:param str runit: The unit of the resolution (km, ...) (km by default)
|
|
452
506
|
:param str area: The grid location (needed if **lam** is *True*)
|
|
453
507
|
"""
|
|
454
|
-
kw.setdefault(
|
|
508
|
+
kw.setdefault("runit", "km")
|
|
455
509
|
super().__init__(**kw)
|
|
456
|
-
self.kind =
|
|
457
|
-
logger.debug(
|
|
510
|
+
self.kind = "projected"
|
|
511
|
+
logger.debug("Projected Geometry init %s", str(self))
|
|
458
512
|
|
|
459
513
|
def _check_attributes(self):
|
|
460
514
|
super()._check_attributes()
|
|
@@ -463,23 +517,30 @@ class ProjectedGeometry(SpectralAwareHorizontalGeometry):
|
|
|
463
517
|
|
|
464
518
|
@property
|
|
465
519
|
def gco_grid_def(self):
|
|
466
|
-
geotag_f = (
|
|
467
|
-
|
|
520
|
+
geotag_f = (
|
|
521
|
+
"{0.area}_{0.rnice}"
|
|
522
|
+
if self.truncationtype == "linear"
|
|
523
|
+
else "{0.area}_{0.xtruncationtype}_{0.rnice}"
|
|
524
|
+
)
|
|
468
525
|
return geotag_f.format(self)
|
|
469
526
|
|
|
470
527
|
def __str__(self):
|
|
471
528
|
"""Standard formatted print representation."""
|
|
472
|
-
return
|
|
473
|
-
|
|
474
|
-
|
|
529
|
+
return "<{:s} r='{:s}' {:s}>".format(
|
|
530
|
+
self.strheader(), self.rnice, self.truncationtype
|
|
531
|
+
)
|
|
475
532
|
|
|
476
533
|
def doc_export(self):
|
|
477
534
|
"""Relevant informations to print in the documentation."""
|
|
478
535
|
if self.lam:
|
|
479
|
-
fmts =
|
|
536
|
+
fmts = (
|
|
537
|
+
"kind={0:s}, r={1:s}, truncationtype={2:s}, limited-area={3:s}"
|
|
538
|
+
)
|
|
480
539
|
else:
|
|
481
|
-
fmts =
|
|
482
|
-
return fmts.format(
|
|
540
|
+
fmts = "kind={0:s}, r={1:s}, truncationtype={2:s}, global"
|
|
541
|
+
return fmts.format(
|
|
542
|
+
self.kind, self.rnice, self.truncationtype, self.area
|
|
543
|
+
)
|
|
483
544
|
|
|
484
545
|
|
|
485
546
|
class LonlatGeometry(HorizontalGeometry):
|
|
@@ -499,23 +560,25 @@ class LonlatGeometry(HorizontalGeometry):
|
|
|
499
560
|
:param int nlat: The number of latitude points in the grid
|
|
500
561
|
:param str area: The grid location (needed if **lam** is *True*)
|
|
501
562
|
"""
|
|
502
|
-
kw.setdefault(
|
|
563
|
+
kw.setdefault("runit", "dg")
|
|
503
564
|
super().__init__(**kw)
|
|
504
|
-
self.kind =
|
|
565
|
+
self.kind = "lonlat"
|
|
505
566
|
# TODO: coherence entre les coordonnees et nlon/nlat/resolution
|
|
506
|
-
logger.debug(
|
|
567
|
+
logger.debug("Lon/Lat Geometry init %s", str(self))
|
|
507
568
|
|
|
508
569
|
def __str__(self):
|
|
509
570
|
"""Standard formatted print representation."""
|
|
510
|
-
return
|
|
571
|
+
return "<{:s} r='{:s}'>".format(self.strheader(), self.rnice)
|
|
511
572
|
|
|
512
573
|
def doc_export(self):
|
|
513
574
|
"""Relevant informations to print in the documentation."""
|
|
514
575
|
if self.lam:
|
|
515
|
-
fmts =
|
|
576
|
+
fmts = "kind={0:s}, r={1:s}, limited-area={2:s}, nlon={3!s}, nlat={4!s}"
|
|
516
577
|
else:
|
|
517
|
-
fmts =
|
|
518
|
-
return fmts.format(
|
|
578
|
+
fmts = "kind={0:s}, r={1:s}, global, nlon={3!s}, nlat={4!s}"
|
|
579
|
+
return fmts.format(
|
|
580
|
+
self.kind, self.rnice, self.area, self.nlon, self.nlat
|
|
581
|
+
)
|
|
519
582
|
|
|
520
583
|
|
|
521
584
|
class UnstructuredGeometry(HorizontalGeometry):
|
|
@@ -533,19 +596,19 @@ class UnstructuredGeometry(HorizontalGeometry):
|
|
|
533
596
|
.. note:: This is an abstract class, do not instantiate.
|
|
534
597
|
"""
|
|
535
598
|
super().__init__(**kw)
|
|
536
|
-
self.kind =
|
|
537
|
-
logger.debug(
|
|
599
|
+
self.kind = "unstructured"
|
|
600
|
+
logger.debug("Unstructured Geometry init %s", str(self))
|
|
538
601
|
|
|
539
602
|
def __str__(self):
|
|
540
603
|
"""Standard formatted print representation."""
|
|
541
|
-
return
|
|
604
|
+
return "<{:s}>".format(self.strheader())
|
|
542
605
|
|
|
543
606
|
def doc_export(self):
|
|
544
607
|
"""Relevant informations to print in the documentation."""
|
|
545
608
|
if self.area:
|
|
546
|
-
fmts =
|
|
609
|
+
fmts = "kind={0:s}, area={1:s}"
|
|
547
610
|
else:
|
|
548
|
-
fmts =
|
|
611
|
+
fmts = "kind={0:s}"
|
|
549
612
|
return fmts.format(self.kind, self.area)
|
|
550
613
|
|
|
551
614
|
|
|
@@ -565,7 +628,7 @@ class CurvlinearGeometry(UnstructuredGeometry):
|
|
|
565
628
|
:param str area: The grid location (needed if **lam** is *True*)
|
|
566
629
|
"""
|
|
567
630
|
super().__init__(**kw)
|
|
568
|
-
self.kind =
|
|
631
|
+
self.kind = "curvlinear"
|
|
569
632
|
|
|
570
633
|
def _check_attributes(self):
|
|
571
634
|
super()._check_attributes()
|
|
@@ -575,10 +638,14 @@ class CurvlinearGeometry(UnstructuredGeometry):
|
|
|
575
638
|
def doc_export(self):
|
|
576
639
|
"""Relevant informations to print in the documentation."""
|
|
577
640
|
if self.lam:
|
|
578
|
-
fmts =
|
|
641
|
+
fmts = (
|
|
642
|
+
"kind={0:s}, r={1:s}, limited-area={2:s}, ni={3!s}, nj={4!s}"
|
|
643
|
+
)
|
|
579
644
|
else:
|
|
580
|
-
fmts =
|
|
581
|
-
return fmts.format(
|
|
645
|
+
fmts = "kind={0:s}, r={1:s}, global, ni={3!s}, nj={4!s}"
|
|
646
|
+
return fmts.format(
|
|
647
|
+
self.kind, self.rnice, self.area, self.nlon, self.nlat
|
|
648
|
+
)
|
|
582
649
|
|
|
583
650
|
|
|
584
651
|
class RedgridGeometry(HorizontalGeometry):
|
|
@@ -598,28 +665,34 @@ class RedgridGeometry(HorizontalGeometry):
|
|
|
598
665
|
``longitudes = expected_resolution * cos(lat)``
|
|
599
666
|
:param str area: The grid location (needed if **lam** is *True*)
|
|
600
667
|
"""
|
|
601
|
-
kw.setdefault(
|
|
602
|
-
kw.setdefault(
|
|
668
|
+
kw.setdefault("runit", "dg")
|
|
669
|
+
kw.setdefault("lam", False)
|
|
603
670
|
super().__init__(**kw)
|
|
604
|
-
self.kind =
|
|
671
|
+
self.kind = "redgrid"
|
|
605
672
|
|
|
606
673
|
def _check_attributes(self):
|
|
607
|
-
if
|
|
674
|
+
if (
|
|
675
|
+
self.nlonmax is None
|
|
676
|
+
or self.nlat is None
|
|
677
|
+
or self.resolution is None
|
|
678
|
+
):
|
|
608
679
|
raise AttributeError("Some mandatory arguments are missing")
|
|
609
680
|
super()._check_attributes()
|
|
610
681
|
if self.lam is False:
|
|
611
|
-
self.area =
|
|
682
|
+
self.area = "global"
|
|
612
683
|
|
|
613
684
|
def __str__(self):
|
|
614
685
|
"""Standard formatted print representation."""
|
|
615
|
-
return
|
|
616
|
-
|
|
617
|
-
|
|
686
|
+
return "<{:s} area='{:s}' r='{:s}'>".format(
|
|
687
|
+
self.strheader(), self.area, self.rnice
|
|
688
|
+
)
|
|
618
689
|
|
|
619
690
|
def doc_export(self):
|
|
620
691
|
"""Relevant informations to print in the documentation."""
|
|
621
|
-
fmts =
|
|
622
|
-
return fmts.format(
|
|
692
|
+
fmts = "kind={0:s}, r={1:s}, area={2:s}, nlonmax={3!s}, nlat={4!s}"
|
|
693
|
+
return fmts.format(
|
|
694
|
+
self.kind, self.rnice, self.area, self.nlonmax, self.nlat
|
|
695
|
+
)
|
|
623
696
|
|
|
624
697
|
|
|
625
698
|
# Pre-defined footprint attribute for any HorizontalGeometry
|
|
@@ -637,60 +710,83 @@ def _add_geo2basename_info(cls):
|
|
|
637
710
|
def _geo2basename_info(self, add_stretching=True):
|
|
638
711
|
"""Return an array describing the geometry for the Vortex's name builder."""
|
|
639
712
|
if isinstance(self.geometry, GaussGeometry):
|
|
640
|
-
lgeo = [
|
|
641
|
-
|
|
642
|
-
|
|
713
|
+
lgeo = [
|
|
714
|
+
{
|
|
715
|
+
"truncation": (
|
|
716
|
+
self.geometry.truncation,
|
|
717
|
+
self.geometry.short_truncationtype,
|
|
718
|
+
self.geometry.short_gridtype,
|
|
719
|
+
)
|
|
720
|
+
},
|
|
721
|
+
]
|
|
643
722
|
if add_stretching:
|
|
644
|
-
lgeo.append({
|
|
723
|
+
lgeo.append({"stretching": self.geometry.stretching})
|
|
645
724
|
elif isinstance(self.geometry, (ProjectedGeometry, RedgridGeometry)):
|
|
646
725
|
lgeo = [self.geometry.area, self.geometry.rnice]
|
|
647
|
-
if (
|
|
648
|
-
|
|
726
|
+
if (
|
|
727
|
+
self.geometry.truncationtype is not None
|
|
728
|
+
and self.geometry.truncationtype != "linear"
|
|
729
|
+
):
|
|
649
730
|
lgeo.append(self.geometry.xtruncationtype)
|
|
650
731
|
else:
|
|
651
732
|
lgeo = self.geometry.area # Default: always defined
|
|
652
733
|
return lgeo
|
|
653
734
|
|
|
654
|
-
if not hasattr(cls,
|
|
735
|
+
if not hasattr(cls, "_geo2basename_info"):
|
|
655
736
|
cls._geo2basename_info = _geo2basename_info
|
|
656
737
|
return cls
|
|
657
738
|
|
|
658
739
|
|
|
659
740
|
#: Abstract footprint definition of the ``geometry`` attribute.
|
|
660
|
-
hgeometry = footprints.Footprint(
|
|
661
|
-
|
|
741
|
+
hgeometry = footprints.Footprint(
|
|
742
|
+
info="Abstract Horizontal Geometry", attr=dict(geometry=a_hgeometry)
|
|
743
|
+
)
|
|
662
744
|
|
|
663
745
|
#: Abstract footprint definition of the ``geometry`` attribute with decorators
|
|
664
746
|
#: that alter the ``namebuilding_info`` method
|
|
665
747
|
hgeometry_deco = footprints.DecorativeFootprint(
|
|
666
748
|
hgeometry,
|
|
667
|
-
decorator=[
|
|
668
|
-
|
|
669
|
-
|
|
749
|
+
decorator=[
|
|
750
|
+
_add_geo2basename_info,
|
|
751
|
+
namebuilding_insert("geo", lambda self: self._geo2basename_info()),
|
|
752
|
+
generic_pathname_insert(
|
|
753
|
+
"geometry", lambda self: self.geometry, setdefault=True
|
|
754
|
+
),
|
|
755
|
+
],
|
|
756
|
+
)
|
|
670
757
|
|
|
671
758
|
|
|
672
759
|
# Load default geometries when the module is first imported
|
|
673
760
|
|
|
674
|
-
|
|
761
|
+
|
|
762
|
+
def load(inifile="@geometries.ini", refresh=False, verbose=True):
|
|
675
763
|
"""Load a set of pre-defined geometries from a configuration file.
|
|
676
764
|
|
|
677
765
|
The class that will be instantiated depends on the "kind" keyword..
|
|
678
766
|
"""
|
|
679
767
|
iniconf = configparser.ConfigParser()
|
|
680
768
|
with importlib.resources.open_text(
|
|
681
|
-
|
|
769
|
+
"vortex.data",
|
|
770
|
+
"geometries.ini",
|
|
682
771
|
) as fh:
|
|
683
772
|
iniconf.read_file(fh)
|
|
684
773
|
for item in iniconf.sections():
|
|
685
774
|
gdesc = dict(iniconf.items(item))
|
|
686
|
-
gkind = gdesc.get(
|
|
775
|
+
gkind = gdesc.get("kind")
|
|
687
776
|
try:
|
|
688
|
-
thisclass = [
|
|
689
|
-
|
|
777
|
+
thisclass = [
|
|
778
|
+
x
|
|
779
|
+
for x in Geometry.tag_classes()
|
|
780
|
+
if x.__name__.lower().startswith(gkind.lower())
|
|
781
|
+
].pop()
|
|
690
782
|
except IndexError:
|
|
691
|
-
raise AttributeError(
|
|
783
|
+
raise AttributeError(
|
|
784
|
+
"Kind={:s} is unknown (for geometry [{:s}])".format(
|
|
785
|
+
gkind, item
|
|
786
|
+
)
|
|
787
|
+
)
|
|
692
788
|
if verbose:
|
|
693
|
-
print(
|
|
789
|
+
print("+ Load", item.ljust(16), "as", thisclass)
|
|
694
790
|
if refresh:
|
|
695
791
|
# Always recreate the Geometry...
|
|
696
792
|
thisclass(tag=item, new=True, **gdesc)
|