vortex-nwp 2.0.0b1__py3-none-any.whl → 2.0.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. vortex/__init__.py +59 -45
  2. vortex/algo/__init__.py +3 -2
  3. vortex/algo/components.py +940 -614
  4. vortex/algo/mpitools.py +802 -497
  5. vortex/algo/serversynctools.py +34 -33
  6. vortex/config.py +19 -22
  7. vortex/data/__init__.py +9 -3
  8. vortex/data/abstractstores.py +593 -655
  9. vortex/data/containers.py +217 -162
  10. vortex/data/contents.py +65 -39
  11. vortex/data/executables.py +93 -102
  12. vortex/data/flow.py +40 -34
  13. vortex/data/geometries.py +228 -132
  14. vortex/data/handlers.py +428 -225
  15. vortex/data/outflow.py +15 -15
  16. vortex/data/providers.py +185 -163
  17. vortex/data/resources.py +48 -42
  18. vortex/data/stores.py +544 -413
  19. vortex/gloves.py +114 -87
  20. vortex/layout/__init__.py +1 -8
  21. vortex/layout/contexts.py +150 -84
  22. vortex/layout/dataflow.py +353 -202
  23. vortex/layout/monitor.py +264 -128
  24. vortex/nwp/__init__.py +5 -2
  25. vortex/nwp/algo/__init__.py +14 -5
  26. vortex/nwp/algo/assim.py +205 -151
  27. vortex/nwp/algo/clim.py +683 -517
  28. vortex/nwp/algo/coupling.py +447 -225
  29. vortex/nwp/algo/eda.py +437 -229
  30. vortex/nwp/algo/eps.py +403 -231
  31. vortex/nwp/algo/forecasts.py +420 -271
  32. vortex/nwp/algo/fpserver.py +683 -307
  33. vortex/nwp/algo/ifsnaming.py +205 -145
  34. vortex/nwp/algo/ifsroot.py +210 -122
  35. vortex/nwp/algo/monitoring.py +132 -76
  36. vortex/nwp/algo/mpitools.py +321 -191
  37. vortex/nwp/algo/odbtools.py +617 -353
  38. vortex/nwp/algo/oopsroot.py +449 -273
  39. vortex/nwp/algo/oopstests.py +90 -56
  40. vortex/nwp/algo/request.py +287 -206
  41. vortex/nwp/algo/stdpost.py +878 -522
  42. vortex/nwp/data/__init__.py +22 -4
  43. vortex/nwp/data/assim.py +125 -137
  44. vortex/nwp/data/boundaries.py +121 -68
  45. vortex/nwp/data/climfiles.py +193 -211
  46. vortex/nwp/data/configfiles.py +73 -69
  47. vortex/nwp/data/consts.py +426 -401
  48. vortex/nwp/data/ctpini.py +59 -43
  49. vortex/nwp/data/diagnostics.py +94 -66
  50. vortex/nwp/data/eda.py +50 -51
  51. vortex/nwp/data/eps.py +195 -146
  52. vortex/nwp/data/executables.py +440 -434
  53. vortex/nwp/data/fields.py +63 -48
  54. vortex/nwp/data/gridfiles.py +183 -111
  55. vortex/nwp/data/logs.py +250 -217
  56. vortex/nwp/data/modelstates.py +180 -151
  57. vortex/nwp/data/monitoring.py +72 -99
  58. vortex/nwp/data/namelists.py +254 -202
  59. vortex/nwp/data/obs.py +400 -308
  60. vortex/nwp/data/oopsexec.py +22 -20
  61. vortex/nwp/data/providers.py +90 -65
  62. vortex/nwp/data/query.py +71 -82
  63. vortex/nwp/data/stores.py +49 -36
  64. vortex/nwp/data/surfex.py +136 -137
  65. vortex/nwp/syntax/__init__.py +1 -1
  66. vortex/nwp/syntax/stdattrs.py +173 -111
  67. vortex/nwp/tools/__init__.py +2 -2
  68. vortex/nwp/tools/addons.py +22 -17
  69. vortex/nwp/tools/agt.py +24 -12
  70. vortex/nwp/tools/bdap.py +16 -5
  71. vortex/nwp/tools/bdcp.py +4 -1
  72. vortex/nwp/tools/bdm.py +3 -0
  73. vortex/nwp/tools/bdmp.py +14 -9
  74. vortex/nwp/tools/conftools.py +728 -378
  75. vortex/nwp/tools/drhook.py +12 -8
  76. vortex/nwp/tools/grib.py +65 -39
  77. vortex/nwp/tools/gribdiff.py +22 -17
  78. vortex/nwp/tools/ifstools.py +82 -42
  79. vortex/nwp/tools/igastuff.py +167 -143
  80. vortex/nwp/tools/mars.py +14 -2
  81. vortex/nwp/tools/odb.py +234 -125
  82. vortex/nwp/tools/partitioning.py +61 -37
  83. vortex/nwp/tools/satrad.py +27 -12
  84. vortex/nwp/util/async.py +83 -55
  85. vortex/nwp/util/beacon.py +10 -10
  86. vortex/nwp/util/diffpygram.py +174 -86
  87. vortex/nwp/util/ens.py +144 -63
  88. vortex/nwp/util/hooks.py +30 -19
  89. vortex/nwp/util/taskdeco.py +28 -24
  90. vortex/nwp/util/usepygram.py +278 -172
  91. vortex/nwp/util/usetnt.py +31 -17
  92. vortex/sessions.py +72 -39
  93. vortex/syntax/__init__.py +1 -1
  94. vortex/syntax/stdattrs.py +410 -171
  95. vortex/syntax/stddeco.py +31 -22
  96. vortex/toolbox.py +327 -192
  97. vortex/tools/__init__.py +11 -2
  98. vortex/tools/actions.py +125 -59
  99. vortex/tools/addons.py +111 -92
  100. vortex/tools/arm.py +42 -22
  101. vortex/tools/compression.py +72 -69
  102. vortex/tools/date.py +11 -4
  103. vortex/tools/delayedactions.py +242 -132
  104. vortex/tools/env.py +75 -47
  105. vortex/tools/folder.py +342 -171
  106. vortex/tools/grib.py +311 -149
  107. vortex/tools/lfi.py +423 -216
  108. vortex/tools/listings.py +109 -40
  109. vortex/tools/names.py +218 -156
  110. vortex/tools/net.py +632 -298
  111. vortex/tools/parallelism.py +93 -61
  112. vortex/tools/prestaging.py +55 -31
  113. vortex/tools/schedulers.py +172 -105
  114. vortex/tools/services.py +402 -333
  115. vortex/tools/storage.py +293 -358
  116. vortex/tools/surfex.py +24 -24
  117. vortex/tools/systems.py +1211 -631
  118. vortex/tools/targets.py +156 -100
  119. vortex/util/__init__.py +1 -1
  120. vortex/util/config.py +377 -327
  121. vortex/util/empty.py +2 -2
  122. vortex/util/helpers.py +56 -24
  123. vortex/util/introspection.py +18 -12
  124. vortex/util/iosponge.py +8 -4
  125. vortex/util/roles.py +4 -6
  126. vortex/util/storefunctions.py +39 -13
  127. vortex/util/structs.py +3 -3
  128. vortex/util/worker.py +29 -17
  129. vortex_nwp-2.0.0b2.dist-info/METADATA +66 -0
  130. vortex_nwp-2.0.0b2.dist-info/RECORD +142 -0
  131. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/WHEEL +1 -1
  132. vortex/layout/appconf.py +0 -109
  133. vortex/layout/jobs.py +0 -1276
  134. vortex/layout/nodes.py +0 -1424
  135. vortex/layout/subjobs.py +0 -464
  136. vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
  137. vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
  138. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/LICENSE +0 -0
  139. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/top_level.txt +0 -0
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 = 'anonymous'
128
+ self.info = "anonymous"
128
129
  self.inifile = None
129
130
  self.__dict__.update(kw)
130
- self.kind = 'abstract'
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('Abstract Geometry init kw=%s', str(kw))
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('The "{:s}" {:s} object does not exist yet...'.
138
- format(tag, cls.__name__))
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 '<{:s}.{:s} (tag=\'{:s}\') object at {:#x}>'.format(
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 'kind={:s}'.format(self.kind)
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 = '[{}]\n'.format(self.tag)
165
+ s = "[{}]\n".format(self.tag)
162
166
  for k in sorted(self._init_attributes.keys()):
163
- s += '{:10s} = {}\n'.format(k, self._init_attributes[k])
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 = 'vertical'
182
- logger.debug('Abstract Vertical Geometry init %s %s', str(self), str(kw))
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='anonymous',
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('none', v, re.IGNORECASE):
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('true', v, re.IGNORECASE):
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('false', v, re.IGNORECASE):
233
+ if isinstance(v, str) and re.match("false", v, re.IGNORECASE):
228
234
  self.__dict__[k] = False
229
- for item in ('nlon', 'nlat', 'ni', 'nj', 'nmassif', 'nposts', 'truncation'):
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 ('stretching', 'resolution', 'lonmin', 'latmin'):
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('Abstract Horizontal Geometry init %s', str(self))
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 == 'km':
254
- res = '{:05.2f}'.format(self.resolution)
255
- elif self.runit in ('s', 'min'):
256
- res = '{:04.1f}'.format(self.resolution)
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 = '{:06.3f}'.format(self.resolution)
259
- return re.sub(r'\.', self.runit, res, 1)
272
+ res = "{:06.3f}".format(self.resolution)
273
+ return re.sub(r"\.", self.runit, res, 1)
260
274
  else:
261
- return 'Unknown Resolution'
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 ('{0.area}' + ('_{0.rnice}' if self.runit is not None else '')).format(self)
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 '{!s}, {:s}'.format(self.area, self.rnice)
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 == 'anonymous':
278
- return '{:s}({:s})'.format(self.__class__.__name__, self.anonymous_info())
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 = ' ' * indent
305
+ indent = " " * indent
288
306
  # Basics...
289
- card = "\n".join((
290
- '{0}Geometry {1!r}',
291
- '{0}{0}Info : {2:s}',
292
- '{0}{0}LAM : {3!s}',
293
- )).format(indent, self, self.info, self.lam)
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 [k for k in ('area', 'resolution', 'truncation',
296
- 'stretching', 'nlon', 'nlat', 'ni', 'nj',
297
- 'nmassif', 'nposts')
298
- if getattr(self, k, False)]:
299
- card += "\n{0}{0}{1:10s} : {2!s}".format(indent, attr.title(),
300
- getattr(self, attr))
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 = '{:s}.{:s} | tag=\'{}\' id=\'{:s}\''.format(
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 += ' area=\'{:s}\''.format(self.area)
345
+ header += " area='{:s}'".format(self.area)
313
346
  return header
314
347
 
315
348
  @property
316
349
  def coordinates(self):
317
- if any([getattr(self, x) is None for x in ('lonmin', 'latmin', 'nlat', 'nlon', 'resolution')]):
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['latmax'] = self.latmin + self.resolution * (self.nlat - 1)
321
- coordinates['lonmax'] = self.lonmin + self.resolution * (self.nlon - 1)
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 = 'linear'
334
- if self.truncationtype not in ('linear', 'quadratic', 'cubic'):
335
- raise ValueError("Improper value {:s} for *truncationtype*"
336
- .format(self.truncationtype))
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='quad').get(self.truncationtype, self.truncationtype)
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 = 'combined'
366
- logger.debug('Combined Geometry init %s %s', str(self), str(kw))
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 = 'gauss'
396
- logger.debug('Gauss Geometry init %s', str(self))
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 = 'rgrid'
405
- if self.gridtype not in ('rgrid', 'octahedral'):
406
- raise ValueError("Improper value {:s} for *gridtype*"
407
- .format(self.gridtype))
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 != 'rgrid' else ''
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 = 't'
416
- if self.truncationtype != 'linear' or self.gridtype != 'rgrid':
417
- geotag_f += '{0.short_truncationtype}'
418
- geotag_f += '{0.short_gridtype}{0.truncation:d}'
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 '<{:s} t{:s}{:s}={:d} c={:g}>'.format(self.strheader(),
424
- self.short_truncationtype,
425
- self.short_gridtype,
426
- self.truncation,
427
- self.stretching)
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 = 'kind={0:s}, t{1:s}{2:s}={3:d}, c={4:g} (pole of interest over {5!s})'
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 = 'kind={0:s}, t{1:s}{2:s}={3:d}, c={4:g}'
435
- return fmts.format(self.kind, self.short_truncationtype, self.short_gridtype,
436
- self.truncation, self.stretching, self.area)
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('runit', 'km')
508
+ kw.setdefault("runit", "km")
455
509
  super().__init__(**kw)
456
- self.kind = 'projected'
457
- logger.debug('Projected Geometry init %s', str(self))
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 = ('{0.area}_{0.rnice}' if self.truncationtype == 'linear' else
467
- '{0.area}_{0.xtruncationtype}_{0.rnice}')
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 '<{:s} r=\'{:s}\' {:s}>'.format(self.strheader(),
473
- self.rnice,
474
- self.truncationtype)
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 = 'kind={0:s}, r={1:s}, truncationtype={2:s}, limited-area={3:s}'
536
+ fmts = (
537
+ "kind={0:s}, r={1:s}, truncationtype={2:s}, limited-area={3:s}"
538
+ )
480
539
  else:
481
- fmts = 'kind={0:s}, r={1:s}, truncationtype={2:s}, global'
482
- return fmts.format(self.kind, self.rnice, self.truncationtype, self.area)
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('runit', 'dg')
563
+ kw.setdefault("runit", "dg")
503
564
  super().__init__(**kw)
504
- self.kind = 'lonlat'
565
+ self.kind = "lonlat"
505
566
  # TODO: coherence entre les coordonnees et nlon/nlat/resolution
506
- logger.debug('Lon/Lat Geometry init %s', str(self))
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 '<{:s} r=\'{:s}\'>'.format(self.strheader(), self.rnice)
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 = 'kind={0:s}, r={1:s}, limited-area={2:s}, nlon={3!s}, nlat={4!s}'
576
+ fmts = "kind={0:s}, r={1:s}, limited-area={2:s}, nlon={3!s}, nlat={4!s}"
516
577
  else:
517
- fmts = 'kind={0:s}, r={1:s}, global, nlon={3!s}, nlat={4!s}'
518
- return fmts.format(self.kind, self.rnice, self.area, self.nlon, self.nlat)
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 = 'unstructured'
537
- logger.debug('Unstructured Geometry init %s', str(self))
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 '<{:s}>'.format(self.strheader())
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 = 'kind={0:s}, area={1:s}'
609
+ fmts = "kind={0:s}, area={1:s}"
547
610
  else:
548
- fmts = 'kind={0:s}'
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 = 'curvlinear'
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 = 'kind={0:s}, r={1:s}, limited-area={2:s}, ni={3!s}, nj={4!s}'
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 = 'kind={0:s}, r={1:s}, global, ni={3!s}, nj={4!s}'
581
- return fmts.format(self.kind, self.rnice, self.area, self.nlon, self.nlat)
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('runit', 'dg')
602
- kw.setdefault('lam', False)
668
+ kw.setdefault("runit", "dg")
669
+ kw.setdefault("lam", False)
603
670
  super().__init__(**kw)
604
- self.kind = 'redgrid'
671
+ self.kind = "redgrid"
605
672
 
606
673
  def _check_attributes(self):
607
- if self.nlonmax is None or self.nlat is None or self.resolution is None:
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 = 'global'
682
+ self.area = "global"
612
683
 
613
684
  def __str__(self):
614
685
  """Standard formatted print representation."""
615
- return '<{:s} area=\'{:s}\' r=\'{:s}\'>'.format(self.strheader(),
616
- self.area,
617
- self.rnice)
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 = 'kind={0:s}, r={1:s}, area={2:s}, nlonmax={3!s}, nlat={4!s}'
622
- return fmts.format(self.kind, self.rnice, self.area, self.nlonmax, self.nlat)
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 = [{'truncation': (self.geometry.truncation,
641
- self.geometry.short_truncationtype,
642
- self.geometry.short_gridtype)}, ]
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({'stretching': self.geometry.stretching})
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 (self.geometry.truncationtype is not None and
648
- self.geometry.truncationtype != 'linear'):
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, '_geo2basename_info'):
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(info='Abstract Horizontal Geometry',
661
- attr=dict(geometry=a_hgeometry))
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=[_add_geo2basename_info,
668
- namebuilding_insert('geo', lambda self: self._geo2basename_info()),
669
- generic_pathname_insert('geometry', lambda self: self.geometry, setdefault=True)])
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
- def load(inifile='@geometries.ini', refresh=False, verbose=True):
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
- "vortex.data", "geometries.ini",
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('kind')
775
+ gkind = gdesc.get("kind")
687
776
  try:
688
- thisclass = [x for x in Geometry.tag_classes()
689
- if x.__name__.lower().startswith(gkind.lower())].pop()
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('Kind={:s} is unknown (for geometry [{:s}])'.format(gkind, item))
783
+ raise AttributeError(
784
+ "Kind={:s} is unknown (for geometry [{:s}])".format(
785
+ gkind, item
786
+ )
787
+ )
692
788
  if verbose:
693
- print('+ Load', item.ljust(16), 'as', thisclass)
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)