vortex-nwp 2.0.0b1__py3-none-any.whl → 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. vortex/__init__.py +75 -47
  2. vortex/algo/__init__.py +3 -2
  3. vortex/algo/components.py +944 -618
  4. vortex/algo/mpitools.py +802 -497
  5. vortex/algo/mpitools_templates/__init__.py +1 -0
  6. vortex/algo/serversynctools.py +34 -33
  7. vortex/config.py +19 -22
  8. vortex/data/__init__.py +9 -3
  9. vortex/data/abstractstores.py +593 -655
  10. vortex/data/containers.py +217 -162
  11. vortex/data/contents.py +65 -39
  12. vortex/data/executables.py +93 -102
  13. vortex/data/flow.py +40 -34
  14. vortex/data/geometries.py +228 -132
  15. vortex/data/handlers.py +436 -227
  16. vortex/data/outflow.py +15 -15
  17. vortex/data/providers.py +185 -163
  18. vortex/data/resources.py +48 -42
  19. vortex/data/stores.py +540 -417
  20. vortex/data/sync_templates/__init__.py +0 -0
  21. vortex/gloves.py +114 -87
  22. vortex/layout/__init__.py +1 -8
  23. vortex/layout/contexts.py +150 -84
  24. vortex/layout/dataflow.py +353 -202
  25. vortex/layout/monitor.py +264 -128
  26. vortex/nwp/__init__.py +5 -2
  27. vortex/nwp/algo/__init__.py +14 -5
  28. vortex/nwp/algo/assim.py +205 -151
  29. vortex/nwp/algo/clim.py +683 -517
  30. vortex/nwp/algo/coupling.py +447 -225
  31. vortex/nwp/algo/eda.py +437 -229
  32. vortex/nwp/algo/eps.py +403 -231
  33. vortex/nwp/algo/forecasts.py +416 -275
  34. vortex/nwp/algo/fpserver.py +683 -307
  35. vortex/nwp/algo/ifsnaming.py +205 -145
  36. vortex/nwp/algo/ifsroot.py +215 -122
  37. vortex/nwp/algo/monitoring.py +137 -76
  38. vortex/nwp/algo/mpitools.py +330 -190
  39. vortex/nwp/algo/odbtools.py +637 -353
  40. vortex/nwp/algo/oopsroot.py +454 -273
  41. vortex/nwp/algo/oopstests.py +90 -56
  42. vortex/nwp/algo/request.py +287 -206
  43. vortex/nwp/algo/stdpost.py +878 -522
  44. vortex/nwp/data/__init__.py +22 -4
  45. vortex/nwp/data/assim.py +125 -137
  46. vortex/nwp/data/boundaries.py +121 -68
  47. vortex/nwp/data/climfiles.py +193 -211
  48. vortex/nwp/data/configfiles.py +73 -69
  49. vortex/nwp/data/consts.py +426 -401
  50. vortex/nwp/data/ctpini.py +59 -43
  51. vortex/nwp/data/diagnostics.py +94 -66
  52. vortex/nwp/data/eda.py +50 -51
  53. vortex/nwp/data/eps.py +195 -146
  54. vortex/nwp/data/executables.py +440 -434
  55. vortex/nwp/data/fields.py +63 -48
  56. vortex/nwp/data/gridfiles.py +183 -111
  57. vortex/nwp/data/logs.py +250 -217
  58. vortex/nwp/data/modelstates.py +180 -151
  59. vortex/nwp/data/monitoring.py +72 -99
  60. vortex/nwp/data/namelists.py +254 -202
  61. vortex/nwp/data/obs.py +400 -308
  62. vortex/nwp/data/oopsexec.py +22 -20
  63. vortex/nwp/data/providers.py +90 -65
  64. vortex/nwp/data/query.py +71 -82
  65. vortex/nwp/data/stores.py +49 -36
  66. vortex/nwp/data/surfex.py +136 -137
  67. vortex/nwp/syntax/__init__.py +1 -1
  68. vortex/nwp/syntax/stdattrs.py +173 -111
  69. vortex/nwp/tools/__init__.py +2 -2
  70. vortex/nwp/tools/addons.py +22 -17
  71. vortex/nwp/tools/agt.py +24 -12
  72. vortex/nwp/tools/bdap.py +16 -5
  73. vortex/nwp/tools/bdcp.py +4 -1
  74. vortex/nwp/tools/bdm.py +3 -0
  75. vortex/nwp/tools/bdmp.py +14 -9
  76. vortex/nwp/tools/conftools.py +728 -378
  77. vortex/nwp/tools/drhook.py +12 -8
  78. vortex/nwp/tools/grib.py +65 -39
  79. vortex/nwp/tools/gribdiff.py +22 -17
  80. vortex/nwp/tools/ifstools.py +82 -42
  81. vortex/nwp/tools/igastuff.py +167 -143
  82. vortex/nwp/tools/mars.py +14 -2
  83. vortex/nwp/tools/odb.py +234 -125
  84. vortex/nwp/tools/partitioning.py +61 -37
  85. vortex/nwp/tools/satrad.py +27 -12
  86. vortex/nwp/util/async.py +83 -55
  87. vortex/nwp/util/beacon.py +10 -10
  88. vortex/nwp/util/diffpygram.py +174 -86
  89. vortex/nwp/util/ens.py +144 -63
  90. vortex/nwp/util/hooks.py +30 -19
  91. vortex/nwp/util/taskdeco.py +28 -24
  92. vortex/nwp/util/usepygram.py +278 -172
  93. vortex/nwp/util/usetnt.py +31 -17
  94. vortex/sessions.py +72 -39
  95. vortex/syntax/__init__.py +1 -1
  96. vortex/syntax/stdattrs.py +410 -171
  97. vortex/syntax/stddeco.py +31 -22
  98. vortex/toolbox.py +327 -192
  99. vortex/tools/__init__.py +11 -2
  100. vortex/tools/actions.py +110 -121
  101. vortex/tools/addons.py +111 -92
  102. vortex/tools/arm.py +42 -22
  103. vortex/tools/compression.py +72 -69
  104. vortex/tools/date.py +11 -4
  105. vortex/tools/delayedactions.py +242 -132
  106. vortex/tools/env.py +75 -47
  107. vortex/tools/folder.py +342 -171
  108. vortex/tools/grib.py +341 -162
  109. vortex/tools/lfi.py +423 -216
  110. vortex/tools/listings.py +109 -40
  111. vortex/tools/names.py +218 -156
  112. vortex/tools/net.py +655 -299
  113. vortex/tools/parallelism.py +93 -61
  114. vortex/tools/prestaging.py +55 -31
  115. vortex/tools/schedulers.py +172 -105
  116. vortex/tools/services.py +403 -334
  117. vortex/tools/storage.py +293 -358
  118. vortex/tools/surfex.py +24 -24
  119. vortex/tools/systems.py +1234 -643
  120. vortex/tools/targets.py +156 -100
  121. vortex/util/__init__.py +1 -1
  122. vortex/util/config.py +378 -327
  123. vortex/util/empty.py +2 -2
  124. vortex/util/helpers.py +56 -24
  125. vortex/util/introspection.py +18 -12
  126. vortex/util/iosponge.py +8 -4
  127. vortex/util/roles.py +4 -6
  128. vortex/util/storefunctions.py +39 -13
  129. vortex/util/structs.py +3 -3
  130. vortex/util/worker.py +29 -17
  131. vortex_nwp-2.1.0.dist-info/METADATA +67 -0
  132. vortex_nwp-2.1.0.dist-info/RECORD +144 -0
  133. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/WHEEL +1 -1
  134. vortex/layout/appconf.py +0 -109
  135. vortex/layout/jobs.py +0 -1276
  136. vortex/layout/nodes.py +0 -1424
  137. vortex/layout/subjobs.py +0 -464
  138. vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
  139. vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
  140. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info/licenses}/LICENSE +0 -0
  141. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/top_level.txt +0 -0
@@ -14,51 +14,63 @@ __all__ = []
14
14
  logger = loggers.getLogger(__name__)
15
15
 
16
16
 
17
- class OdbMonitoring(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin):
17
+ class OdbMonitoring(
18
+ Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin
19
+ ):
18
20
  """Compute monitoring statistics."""
19
21
 
20
22
  _footprint = dict(
21
- attr = dict(
22
- kind = dict(
23
- values = ['monitoring'],
23
+ attr=dict(
24
+ kind=dict(
25
+ values=["monitoring"],
24
26
  ),
25
- npool = dict(
26
- default = 1,
27
- optional = True,
27
+ npool=dict(
28
+ default=1,
29
+ optional=True,
28
30
  ),
29
- obs = dict(
30
- values = ['all', 'used'],
31
+ obs=dict(
32
+ values=["all", "used"],
31
33
  ),
32
- date = a_date,
33
- model= a_model,
34
- cutoff = a_cutoff,
35
- start = dict(
36
- type = bool,
37
- default = False,
38
- optional = True,
34
+ date=a_date,
35
+ model=a_model,
36
+ cutoff=a_cutoff,
37
+ start=dict(
38
+ type=bool,
39
+ default=False,
40
+ optional=True,
39
41
  ),
40
- cumul = dict(
41
- type = bool,
42
- default = True,
43
- optional = True,
42
+ cumul=dict(
43
+ type=bool,
44
+ default=True,
45
+ optional=True,
44
46
  ),
45
- extend = dict(
46
- type = bool,
47
- default = False,
48
- optional = True,
47
+ extend=dict(
48
+ type=bool,
49
+ default=False,
50
+ optional=True,
49
51
  ),
50
- stage = dict(
51
- values = ['can', 'surf', 'surface', 'atm', 'atmospheric'],
52
- remap = dict(can='surf', surface='surf', atmospheric='atm'),
53
- info = 'The processing stage of the ODB base.',
52
+ stage=dict(
53
+ values=["can", "surf", "surface", "atm", "atmospheric"],
54
+ remap=dict(can="surf", surface="surf", atmospheric="atm"),
55
+ info="The processing stage of the ODB base.",
54
56
  ),
55
57
  )
56
58
  )
57
59
 
60
+ def _mpitool_attributes(self, opts):
61
+ conf_dict = super()._mpitool_attributes(opts)
62
+ conf_dict.update({"mplbased": True})
63
+ return conf_dict
64
+
58
65
  def _fix_nam_macro(self, rh, macro, value):
59
66
  """Set a given namelist macro and issue a log message."""
60
67
  rh.contents.setmacro(macro, value)
61
- logger.info('Setup %s macro to %s in %s', macro, value, rh.container.actualpath())
68
+ logger.info(
69
+ "Setup %s macro to %s in %s",
70
+ macro,
71
+ value,
72
+ rh.container.actualpath(),
73
+ )
62
74
 
63
75
  def prepare(self, rh, opts):
64
76
  """Update some variables in the namelist and check the presence of the accumulated statistics file."""
@@ -69,31 +81,42 @@ class OdbMonitoring(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin)
69
81
 
70
82
  # Virtual upper-air observations database
71
83
  obsatm_virt = [
72
- x for x in self.lookupodb(fatal=False)
73
- if (x.rh.resource.stage.startswith('matchup') or
74
- x.rh.resource.stage.startswith('screening')) and x.rh.resource.part == 'virtual'
84
+ x
85
+ for x in self.lookupodb(fatal=False)
86
+ if (
87
+ x.rh.resource.stage.startswith("matchup")
88
+ or x.rh.resource.stage.startswith("screening")
89
+ )
90
+ and x.rh.resource.part == "virtual"
75
91
  ]
76
92
 
77
93
  # Single upper-air observations database
78
94
  obsatm_single = [
79
- x for x in self.lookupodb(fatal=False)
80
- if x.rh.resource.stage.startswith('matchup') or x.rh.resource.stage.startswith('screening')
95
+ x
96
+ for x in self.lookupodb(fatal=False)
97
+ if x.rh.resource.stage.startswith("matchup")
98
+ or x.rh.resource.stage.startswith("screening")
81
99
  ]
82
100
  if len(obsatm_single) > 1:
83
101
  obsatm_single = []
84
102
 
85
103
  # Surface observations database
86
104
  obssurf = [
87
- x for x in self.lookupodb(fatal=False)
88
- if x.rh.resource.stage.startswith('canari') and (x.rh.resource.part == 'surf' or
89
- x.rh.resource.part == 'ground')
105
+ x
106
+ for x in self.lookupodb(fatal=False)
107
+ if x.rh.resource.stage.startswith("canari")
108
+ and (
109
+ x.rh.resource.part == "surf" or x.rh.resource.part == "ground"
110
+ )
90
111
  ]
91
112
 
92
113
  # One database at a time
93
- if not (obsatm_virt or obsatm_single) and self.stage == 'atm':
94
- raise ValueError('Could not find any ODB matchup or screening ECMA database')
95
- if not obssurf and self.stage == 'surf':
96
- raise ValueError('Could not find any ODB surface ECMA database')
114
+ if not (obsatm_virt or obsatm_single) and self.stage == "atm":
115
+ raise ValueError(
116
+ "Could not find any ODB matchup or screening ECMA database"
117
+ )
118
+ if not obssurf and self.stage == "surf":
119
+ raise ValueError("Could not find any ODB surface ECMA database")
97
120
 
98
121
  # Set actual ODB paths
99
122
  if obsatm_virt:
@@ -104,8 +127,12 @@ class OdbMonitoring(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin)
104
127
  ecma = obssurf.pop(0)
105
128
  ecma_path = sh.path.abspath(ecma.rh.container.localpath())
106
129
  self.odb.fix_db_path(ecma.rh.resource.layout, ecma_path)
107
- self.env.IOASSIGN = sh.path.join(ecma_path, 'IOASSIGN')
108
- logger.info('Setting ODB env %s = %s.', 'IOASSIGN', sh.path.join(ecma_path, 'IOASSIGN'))
130
+ self.env.IOASSIGN = sh.path.join(ecma_path, "IOASSIGN")
131
+ logger.info(
132
+ "Setting ODB env %s = %s.",
133
+ "IOASSIGN",
134
+ sh.path.join(ecma_path, "IOASSIGN"),
135
+ )
109
136
 
110
137
  # Let ancestors handling most of the env setting
111
138
  super().prepare(rh, opts)
@@ -113,69 +140,103 @@ class OdbMonitoring(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin)
113
140
  # Force to start a new accumulated statistics file if first day and first hour of the month
114
141
  mnt_start = self.start
115
142
 
116
- if not mnt_start and int(self.date.day) == 1 and int(self.date.hh) == 0 and not self.extend:
117
- logger.info('First day and first hour of the month : force start attribute to True.')
143
+ if (
144
+ not mnt_start
145
+ and int(self.date.day) == 1
146
+ and int(self.date.hh) == 0
147
+ and not self.extend
148
+ ):
149
+ logger.info(
150
+ "First day and first hour of the month : force start attribute to True."
151
+ )
118
152
  mnt_start = True
119
153
 
120
154
  mnt_cumul = self.cumul
121
- if self.cutoff == 'production':
155
+ if self.cutoff == "production":
122
156
  mnt_cumul = False
123
- logger.info('No output accumulated statistics file will be produced because '
124
- 'cutoff = production : force cumul to False')
157
+ logger.info(
158
+ "No output accumulated statistics file will be produced because "
159
+ "cutoff = production : force cumul to False"
160
+ )
125
161
 
126
162
  # Monitoring namelist
127
163
  namrh = self.context.sequence.effective_inputs(
128
- role='Namelist',
129
- kind='namelist',)
164
+ role="Namelist",
165
+ kind="namelist",
166
+ )
130
167
  if len(namrh) != 1:
131
- logger.critical('There must be exactly one namelist for monitoring. Stop.')
132
- raise ValueError('There must be exactly one namelist for monitoring. Stop.')
168
+ logger.critical(
169
+ "There must be exactly one namelist for monitoring. Stop."
170
+ )
171
+ raise ValueError(
172
+ "There must be exactly one namelist for monitoring. Stop."
173
+ )
133
174
  namrh = namrh[0].rh
134
175
 
135
176
  # Cumulated statistics file
136
177
  cumulrh = self.context.sequence.effective_inputs(
137
- role='Cumulated monitoring statistics',
138
- kind='accumulated_stats',
178
+ role="Cumulated monitoring statistics",
179
+ kind="accumulated_stats",
139
180
  )
140
181
 
141
182
  if len(cumulrh) > 1:
142
- logger.critical('There must be at most one accumulated statistics file.Stop.')
143
- raise ValueError('There must be one accumulated statistics file or none.Stop.')
183
+ logger.critical(
184
+ "There must be at most one accumulated statistics file.Stop."
185
+ )
186
+ raise ValueError(
187
+ "There must be one accumulated statistics file or none.Stop."
188
+ )
144
189
  else:
145
190
  if len(cumulrh) == 0:
146
191
  if not mnt_start:
147
192
  if mnt_cumul:
148
- logger.critical('There must be one input accumulated statistics file. Stop.')
149
- raise ValueError('There must be one input accumulated statistics file. Stop.')
193
+ logger.critical(
194
+ "There must be one input accumulated statistics file. Stop."
195
+ )
196
+ raise ValueError(
197
+ "There must be one input accumulated statistics file. Stop."
198
+ )
150
199
  else:
151
- logger.info('No input accumulated statistics file is necessary.')
152
- logger.info('No output accumulated statistics file will be produced.')
200
+ logger.info(
201
+ "No input accumulated statistics file is necessary."
202
+ )
203
+ logger.info(
204
+ "No output accumulated statistics file will be produced."
205
+ )
153
206
  else:
154
207
  if mnt_cumul:
155
- logger.info('No input accumulated statistics file. It will be created by the binary.')
208
+ logger.info(
209
+ "No input accumulated statistics file. It will be created by the binary."
210
+ )
156
211
  else:
157
- logger.info('No output accumulated statistics file will be produced.')
212
+ logger.info(
213
+ "No output accumulated statistics file will be produced."
214
+ )
158
215
  else:
159
216
  cumulrh = cumulrh[0].rh
160
217
  if not mnt_cumul:
161
- logger.info('No input accumulated statistics file is necessary(start=False).')
218
+ logger.info(
219
+ "No input accumulated statistics file is necessary(start=False)."
220
+ )
162
221
  cumulrh.container.clear()
163
222
  else:
164
223
  if mnt_start:
165
- logger.info('No input accumulated statistics file is necessary (start=True)')
224
+ logger.info(
225
+ "No input accumulated statistics file is necessary (start=True)"
226
+ )
166
227
  cumulrh.container.clear()
167
228
 
168
- self._fix_nam_macro(namrh, 'JOUR', int(self.date.ymd))
169
- self._fix_nam_macro(namrh, 'RES', int(self.date.hh))
229
+ self._fix_nam_macro(namrh, "JOUR", int(self.date.ymd))
230
+ self._fix_nam_macro(namrh, "RES", int(self.date.hh))
170
231
 
171
- self._fix_nam_macro(namrh, 'LLADMON', mnt_cumul)
172
- self._fix_nam_macro(namrh, 'LLADAJ', mnt_cumul and not mnt_start)
232
+ self._fix_nam_macro(namrh, "LLADMON", mnt_cumul)
233
+ self._fix_nam_macro(namrh, "LLADAJ", mnt_cumul and not mnt_start)
173
234
 
174
- self._fix_nam_macro(namrh, 'LLFLAG', self.obs != 'all')
235
+ self._fix_nam_macro(namrh, "LLFLAG", self.obs != "all")
175
236
 
176
- self._fix_nam_macro(namrh, 'LLARO', self.model == 'arome')
177
- self._fix_nam_macro(namrh, 'LLVRP', self.model == 'varpack')
178
- self._fix_nam_macro(namrh, 'LLCAN', self.stage == 'surf')
237
+ self._fix_nam_macro(namrh, "LLARO", self.model == "arome")
238
+ self._fix_nam_macro(namrh, "LLVRP", self.model == "varpack")
239
+ self._fix_nam_macro(namrh, "LLCAN", self.stage == "surf")
179
240
 
180
241
  if namrh.contents.dumps_needs_update:
181
242
  namrh.contents.rewrite(namrh.container)
@@ -189,13 +250,13 @@ class OdbMonitoring(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin)
189
250
  allfiles = sh.ls()
190
251
  for f in allfiles:
191
252
  if self.system.path.getsize(f) == 0:
192
- logger.info('Remove %s because size of %s is zero.', f, f)
253
+ logger.info("Remove %s because size of %s is zero.", f, f)
193
254
  sh.remove(f)
194
255
 
195
- obspoint_out = sh.ls('point.*')
256
+ obspoint_out = sh.ls("point.*")
196
257
  if obspoint_out:
197
- dest = 'obslocationpack'
198
- logger.info('Creating an OBSLOCATION pack: %s', dest)
258
+ dest = "obslocationpack"
259
+ logger.info("Creating an OBSLOCATION pack: %s", dest)
199
260
  sh.mkdir(dest)
200
261
  for fname in obspoint_out:
201
262
  sh.mv(fname, dest)