wrfrun 0.1.7__py3-none-any.whl → 0.1.8__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.
- wrfrun/core/__init__.py +33 -0
- wrfrun/core/base.py +241 -73
- wrfrun/core/config.py +241 -122
- wrfrun/core/error.py +47 -17
- wrfrun/core/replay.py +64 -31
- wrfrun/core/server.py +75 -18
- wrfrun/data.py +10 -5
- wrfrun/extension/__init__.py +28 -0
- wrfrun/extension/goos_sst/__init__.py +67 -0
- wrfrun/extension/goos_sst/core.py +108 -0
- wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +7 -0
- wrfrun/extension/goos_sst/res/__init__.py +9 -0
- wrfrun/extension/goos_sst/utils.py +81 -0
- wrfrun/model/plot.py +1 -1
- wrfrun/model/wrf/core.py +3 -3
- wrfrun/model/wrf/namelist.py +3 -7
- wrfrun/model/wrf/scheme.py +85 -1
- wrfrun/plot/wps.py +66 -58
- wrfrun/res/config.toml.template +3 -1
- {wrfrun-0.1.7.dist-info → wrfrun-0.1.8.dist-info}/METADATA +2 -2
- {wrfrun-0.1.7.dist-info → wrfrun-0.1.8.dist-info}/RECORD +22 -17
- {wrfrun-0.1.7.dist-info → wrfrun-0.1.8.dist-info}/WHEEL +0 -0
wrfrun/core/config.py
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
wrfrun.core.config
|
|
3
|
+
##################
|
|
4
|
+
|
|
5
|
+
All classes in this module is used to manage various configurations of ``wrfrun`` and NWP model.
|
|
6
|
+
|
|
7
|
+
.. autosummary::
|
|
8
|
+
:toctree: generated/
|
|
9
|
+
|
|
10
|
+
WRFRunConfig
|
|
11
|
+
_WRFRunConstants
|
|
12
|
+
_WRFRunNamelist
|
|
13
|
+
_WRFRunResources
|
|
14
|
+
|
|
15
|
+
WRFRunConfig
|
|
16
|
+
************
|
|
17
|
+
|
|
18
|
+
A comprehensive class which provides interfaces to access various configurations and resources.
|
|
19
|
+
It inherits from three classes: :class:`_WRFRunResources`, :class:`_WRFRunConstants` and :class:`_WRFRunNamelist`.
|
|
20
|
+
Users can use the global variable ``WRFRUNConfig``, which is the instance of this class being created when users import ``wrfrun``.
|
|
3
21
|
"""
|
|
4
22
|
|
|
5
23
|
from copy import deepcopy
|
|
@@ -12,22 +30,39 @@ import f90nml
|
|
|
12
30
|
import tomli
|
|
13
31
|
import tomli_w
|
|
14
32
|
|
|
15
|
-
from .error import ResourceURIError, WRFRunContextError, ModelNameError
|
|
33
|
+
from .error import ResourceURIError, WRFRunContextError, ModelNameError, NamelistIDError, NamelistError
|
|
16
34
|
from ..utils import logger
|
|
17
35
|
|
|
18
36
|
|
|
19
37
|
class _WRFRunResources:
|
|
20
38
|
"""
|
|
21
|
-
Manage resource files used by wrfrun components
|
|
22
|
-
These resources include various configuration files from NWP as well as those provided by wrfrun itself.
|
|
23
|
-
Since their actual file paths may vary depending on the wrfrun installation environment, wrfrun maps them using URIs to ensure consistent access regardless of the environment.
|
|
39
|
+
Manage resource files used by wrfrun components
|
|
24
40
|
"""
|
|
41
|
+
|
|
25
42
|
def __init__(self):
|
|
43
|
+
"""
|
|
44
|
+
This class manage resource files used by wrfrun components.
|
|
45
|
+
|
|
46
|
+
These resources include various configuration files from NWP as well as those provided by ``wrfrun`` itself.
|
|
47
|
+
Since their actual file paths may vary depending on the installation environment,
|
|
48
|
+
``wrfrun`` maps them using URIs to ensure consistent access regardless of the environment.
|
|
49
|
+
The URI always starts with the prefix string ``:WRFRUN_`` and ends with ``:``.
|
|
50
|
+
|
|
51
|
+
To register custom URIs, user can use :meth:`_WRFRunResources.register_resource_uri`,
|
|
52
|
+
which will check if the provided URI is valid.
|
|
53
|
+
|
|
54
|
+
To convert any possible URIs in a string, user can use :meth:`_WRFRunResources.parse_resource_uri`
|
|
55
|
+
|
|
56
|
+
For more information about how to use resource files, please see :class:`WRFRunConfig`,
|
|
57
|
+
which inherits this class.
|
|
58
|
+
"""
|
|
26
59
|
self._resource_namespace_db = {}
|
|
27
60
|
|
|
28
61
|
def check_resource_uri(self, unique_uri: str) -> bool:
|
|
29
62
|
"""
|
|
30
|
-
Check if the
|
|
63
|
+
Check if the URI has been registered.
|
|
64
|
+
|
|
65
|
+
``wrfrun`` uses unique URIs to represent resource files. If you want to register a custom URI, you need to check if it's available.
|
|
31
66
|
|
|
32
67
|
:param unique_uri: Unique URI represents the resource.
|
|
33
68
|
:type unique_uri: str
|
|
@@ -42,16 +77,13 @@ class _WRFRunResources:
|
|
|
42
77
|
|
|
43
78
|
def register_resource_uri(self, unique_uri: str, res_space_path: str):
|
|
44
79
|
"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Register a unique resource file namespace.
|
|
80
|
+
Register a resource path with a URI. The URI should start with ``:WRFRUN_`` ,end with ``:`` and hasn't been registered yet,
|
|
81
|
+
otherwise an exception :class:`ResourceURIError` will be raised.
|
|
48
82
|
|
|
49
83
|
:param unique_uri: Unique URI represents the resource. It must start with ``:WRFRUN_`` and end with ``:``. For example, ``":WRFRUN_WORK_PATH:"``.
|
|
50
84
|
:type unique_uri: str
|
|
51
85
|
:param res_space_path: REAL absolute path of your resource path. For example, "$HOME/.config/wrfrun/res".
|
|
52
86
|
:type res_space_path: str
|
|
53
|
-
:return:
|
|
54
|
-
:rtype:
|
|
55
87
|
"""
|
|
56
88
|
if not (unique_uri.startswith(":WRFRUN_") and unique_uri.endswith(":")):
|
|
57
89
|
logger.error(f"Can't register resource URI: '{unique_uri}'. It should start with ':WRFRUN_' and end with ':'.")
|
|
@@ -61,36 +93,41 @@ class _WRFRunResources:
|
|
|
61
93
|
logger.error(f"Resource URI '{unique_uri}' exists.")
|
|
62
94
|
raise ResourceURIError(f"Resource URI '{unique_uri}' exists.")
|
|
63
95
|
|
|
64
|
-
|
|
65
|
-
|
|
66
96
|
logger.debug(f"Register URI '{unique_uri}' to '{res_space_path}'")
|
|
67
97
|
self._resource_namespace_db[unique_uri] = res_space_path
|
|
68
98
|
|
|
69
|
-
def parse_resource_uri(self,
|
|
99
|
+
def parse_resource_uri(self, resource_path: str) -> str:
|
|
70
100
|
"""
|
|
71
|
-
Return
|
|
72
|
-
|
|
101
|
+
Return the converted string by parsing the URI string in it.
|
|
73
102
|
Normal path will be returned with no change.
|
|
74
103
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
:
|
|
104
|
+
If the URI hasn't been registered, an exception :class:`ResourceURIError` will be raised.
|
|
105
|
+
|
|
106
|
+
:param resource_path: Resource path string which may contain URI string.
|
|
107
|
+
:type resource_path: str
|
|
108
|
+
:return: Real resource path.
|
|
78
109
|
:rtype: str
|
|
110
|
+
|
|
111
|
+
For example, you can get the real path of ``wrfrun`` workspace with this method:
|
|
112
|
+
|
|
113
|
+
>>> workspace_path = f"{WRFRUNConfig.WRFRUN_WORKSPACE_PATH}/WPS" # ":WRFRUN_WORKSPACE_PATH:/WPS"
|
|
114
|
+
>>> real_path = WRFRUNConfig.parse_resource_uri(workspace_path) # should be a valid path like: "/home/syize/.config/wrfrun/workspace/WPS"
|
|
115
|
+
|
|
79
116
|
"""
|
|
80
|
-
if not
|
|
81
|
-
return
|
|
117
|
+
if not resource_path.startswith(":WRFRUN_"):
|
|
118
|
+
return resource_path
|
|
82
119
|
|
|
83
|
-
res_namespace_string =
|
|
120
|
+
res_namespace_string = resource_path.split(":")[1]
|
|
84
121
|
res_namespace_string = f":{res_namespace_string}:"
|
|
85
122
|
|
|
86
123
|
if res_namespace_string in self._resource_namespace_db:
|
|
87
|
-
|
|
124
|
+
resource_path = resource_path.replace(res_namespace_string, self._resource_namespace_db[res_namespace_string])
|
|
88
125
|
|
|
89
|
-
if not
|
|
90
|
-
return
|
|
126
|
+
if not resource_path.startswith(":WRFRUN_"):
|
|
127
|
+
return resource_path
|
|
91
128
|
|
|
92
129
|
else:
|
|
93
|
-
return self.parse_resource_uri(
|
|
130
|
+
return self.parse_resource_uri(resource_path)
|
|
94
131
|
|
|
95
132
|
else:
|
|
96
133
|
logger.error(f"Unknown resource URI: '{res_namespace_string}'")
|
|
@@ -99,11 +136,16 @@ class _WRFRunResources:
|
|
|
99
136
|
|
|
100
137
|
class _WRFRunConstants:
|
|
101
138
|
"""
|
|
102
|
-
Define all variables that will be used by other
|
|
103
|
-
These variables are related to the wrfrun installation environment and configuration files.
|
|
104
|
-
They are defined either directly or mapped using URIs to ensure consistent access across all components.
|
|
139
|
+
Define all variables that will be used by other components.
|
|
105
140
|
"""
|
|
141
|
+
|
|
106
142
|
def __init__(self):
|
|
143
|
+
"""
|
|
144
|
+
Define all variables that will be used by other components.
|
|
145
|
+
|
|
146
|
+
These variables are related to ``wrfrun`` installation environments, configuration files and more.
|
|
147
|
+
They are defined either directly or mapped using URIs to ensure consistent access across all components.
|
|
148
|
+
"""
|
|
107
149
|
# the path we may need to store temp files,
|
|
108
150
|
# don't worry, it will be deleted once the system reboots
|
|
109
151
|
self._WRFRUN_TEMP_PATH = "/tmp/wrfrun"
|
|
@@ -152,11 +194,11 @@ class _WRFRunConstants:
|
|
|
152
194
|
|
|
153
195
|
def _get_uri_map(self) -> dict[str, str]:
|
|
154
196
|
"""
|
|
155
|
-
Return
|
|
156
|
-
|
|
197
|
+
Return URIs and their values.
|
|
198
|
+
``wrfrun`` will use this to register uri when initialize config.
|
|
157
199
|
|
|
158
|
-
:return:
|
|
159
|
-
:rtype:
|
|
200
|
+
:return: A dict in which URIs are keys and their values are dictionary values.
|
|
201
|
+
:rtype: dict
|
|
160
202
|
"""
|
|
161
203
|
return {
|
|
162
204
|
self.WRFRUN_TEMP_PATH: self._WRFRUN_TEMP_PATH,
|
|
@@ -170,14 +212,20 @@ class _WRFRunConstants:
|
|
|
170
212
|
|
|
171
213
|
@property
|
|
172
214
|
def WRFRUN_REPLAY_WORK_PATH(self) -> str:
|
|
215
|
+
"""
|
|
216
|
+
Path (URI) to store related files of ``wrfrun``'s replay functionality.
|
|
217
|
+
|
|
218
|
+
:return: URI.
|
|
219
|
+
:rtype: str
|
|
220
|
+
"""
|
|
173
221
|
return ":WRFRUN_REPLAY_WORK_PATH:"
|
|
174
222
|
|
|
175
223
|
@property
|
|
176
224
|
def WRFRUN_TEMP_PATH(self) -> str:
|
|
177
225
|
"""
|
|
178
|
-
Path
|
|
226
|
+
Path to store ``wrfrun`` temporary files.
|
|
179
227
|
|
|
180
|
-
:return:
|
|
228
|
+
:return: URI
|
|
181
229
|
:rtype: str
|
|
182
230
|
"""
|
|
183
231
|
return ":WRFRUN_TEMP_PATH:"
|
|
@@ -185,9 +233,9 @@ class _WRFRunConstants:
|
|
|
185
233
|
@property
|
|
186
234
|
def WRFRUN_HOME_PATH(self) -> str:
|
|
187
235
|
"""
|
|
188
|
-
|
|
236
|
+
Root path of all others directories. .
|
|
189
237
|
|
|
190
|
-
:return:
|
|
238
|
+
:return: URI
|
|
191
239
|
:rtype: str
|
|
192
240
|
"""
|
|
193
241
|
return ":WRFRUN_HOME_PATH:"
|
|
@@ -195,19 +243,19 @@ class _WRFRunConstants:
|
|
|
195
243
|
@property
|
|
196
244
|
def WRFRUN_WORKSPACE_PATH(self) -> str:
|
|
197
245
|
"""
|
|
198
|
-
Path of the wrfrun
|
|
246
|
+
Path of the workspace, in which ``wrfrun`` runs NWP models.
|
|
199
247
|
|
|
200
|
-
:return:
|
|
248
|
+
:return: URI
|
|
201
249
|
:rtype: str
|
|
202
250
|
"""
|
|
203
|
-
return ":
|
|
251
|
+
return ":WRFRUN_WORKSPACE_PATH:"
|
|
204
252
|
|
|
205
253
|
@property
|
|
206
254
|
def WPS_WORK_PATH(self) -> str:
|
|
207
255
|
"""
|
|
208
|
-
|
|
256
|
+
Workspace in which ``wrfrun`` runs WPS.
|
|
209
257
|
|
|
210
|
-
:return:
|
|
258
|
+
:return: URI
|
|
211
259
|
:rtype: str
|
|
212
260
|
"""
|
|
213
261
|
return ":WRFRUN_WPS_WORK_PATH:"
|
|
@@ -215,9 +263,9 @@ class _WRFRunConstants:
|
|
|
215
263
|
@property
|
|
216
264
|
def WRF_WORK_PATH(self) -> str:
|
|
217
265
|
"""
|
|
218
|
-
|
|
266
|
+
Workspace in which ``wrfrun`` runs WRF.
|
|
219
267
|
|
|
220
|
-
:return:
|
|
268
|
+
:return: URI
|
|
221
269
|
:rtype: str
|
|
222
270
|
"""
|
|
223
271
|
return ":WRFRUN_WRF_WORK_PATH:"
|
|
@@ -225,9 +273,9 @@ class _WRFRunConstants:
|
|
|
225
273
|
@property
|
|
226
274
|
def WRFDA_WORK_PATH(self) -> str:
|
|
227
275
|
"""
|
|
228
|
-
|
|
276
|
+
Workspace in which ``wrfrun`` runs WRFDA.
|
|
229
277
|
|
|
230
|
-
:return:
|
|
278
|
+
:return: URI
|
|
231
279
|
:rtype: str
|
|
232
280
|
"""
|
|
233
281
|
return ":WRFRUN_WRFDA_WORK_PATH:"
|
|
@@ -235,28 +283,49 @@ class _WRFRunConstants:
|
|
|
235
283
|
@property
|
|
236
284
|
def WRFRUN_WORK_STATUS(self) -> str:
|
|
237
285
|
"""
|
|
238
|
-
wrfrun work status.
|
|
286
|
+
``wrfrun`` work status.
|
|
287
|
+
|
|
288
|
+
This attribute can be changed by ``Executable`` to reflect the current work progress of ``wrfrun``.
|
|
289
|
+
The returned string is the name of ``Executable``.
|
|
239
290
|
|
|
240
|
-
:return:
|
|
291
|
+
:return: A string reflect the current work progress.
|
|
241
292
|
:rtype: str
|
|
242
293
|
"""
|
|
243
294
|
return self._WORK_STATUS
|
|
244
295
|
|
|
245
296
|
@WRFRUN_WORK_STATUS.setter
|
|
246
297
|
def WRFRUN_WORK_STATUS(self, value: str):
|
|
298
|
+
"""
|
|
299
|
+
Set ``wrfrun`` work status.
|
|
300
|
+
|
|
301
|
+
``wrfrun`` recommends ``Executable`` set the status string with their name,
|
|
302
|
+
so to avoid the possible conflicts with other ``Executable`` and the user can easily understand the current work progress.
|
|
303
|
+
|
|
304
|
+
:param value: A string represents the work status.
|
|
305
|
+
:type value: str
|
|
306
|
+
"""
|
|
247
307
|
if not isinstance(value, str):
|
|
248
308
|
value = str(value)
|
|
249
309
|
self._WORK_STATUS = value
|
|
250
310
|
|
|
251
311
|
@property
|
|
252
|
-
def UNGRIB_OUT_DIR(self):
|
|
312
|
+
def UNGRIB_OUT_DIR(self) -> str:
|
|
253
313
|
"""
|
|
254
|
-
Output directory path of ungrib.
|
|
314
|
+
Output directory path of ``ungrib.exe``.
|
|
315
|
+
|
|
316
|
+
:return: URI
|
|
317
|
+
:rtype: str
|
|
255
318
|
"""
|
|
256
319
|
return self._UNGRIB_OUT_DIR
|
|
257
320
|
|
|
258
321
|
@UNGRIB_OUT_DIR.setter
|
|
259
322
|
def UNGRIB_OUT_DIR(self, value: str):
|
|
323
|
+
"""
|
|
324
|
+
Set the output directory path of ``ungrib.exe``.
|
|
325
|
+
|
|
326
|
+
:param value: A real path or a URI represents the directory path of ``ungrib.exe``'s output.
|
|
327
|
+
:type value: str
|
|
328
|
+
"""
|
|
260
329
|
if not isinstance(value, str):
|
|
261
330
|
value = str(value)
|
|
262
331
|
self._UNGRIB_OUT_DIR = value
|
|
@@ -264,22 +333,28 @@ class _WRFRunConstants:
|
|
|
264
333
|
@property
|
|
265
334
|
def WRFRUN_OUTPUT_PATH(self) -> str:
|
|
266
335
|
"""
|
|
267
|
-
|
|
336
|
+
The root path to store all outputs of the ``wrfrun`` and NWP model.
|
|
337
|
+
|
|
338
|
+
:return: URI
|
|
339
|
+
:rtype: str
|
|
268
340
|
"""
|
|
269
341
|
return self._WRFRUN_OUTPUT_PATH
|
|
270
342
|
|
|
271
343
|
@property
|
|
272
344
|
def WRFRUN_RESOURCE_PATH(self) -> str:
|
|
273
345
|
"""
|
|
274
|
-
|
|
346
|
+
The root path of all ``wrfrun`` resource files.
|
|
347
|
+
|
|
348
|
+
:return: URI
|
|
349
|
+
:rtype: str
|
|
275
350
|
"""
|
|
276
351
|
return self._WRFRUN_RESOURCE_PATH
|
|
277
352
|
|
|
278
353
|
def check_wrfrun_context(self, error=False) -> bool:
|
|
279
354
|
"""
|
|
280
|
-
Check if
|
|
355
|
+
Check if in WRFRun context or not.
|
|
281
356
|
|
|
282
|
-
:param error:
|
|
357
|
+
:param error: An exception :class:`WRFRunContextError` will be raised if ``error==True`` when we are not in WRFRun context.
|
|
283
358
|
:type error: bool
|
|
284
359
|
:return: True or False.
|
|
285
360
|
:rtype: bool
|
|
@@ -298,7 +373,7 @@ class _WRFRunConstants:
|
|
|
298
373
|
"""
|
|
299
374
|
Change ``WRFRun`` context status to True or False.
|
|
300
375
|
|
|
301
|
-
:param status: ``
|
|
376
|
+
:param status: ``True`` or ``False``.
|
|
302
377
|
:type status: bool
|
|
303
378
|
"""
|
|
304
379
|
self._WRFRUN_CONTEXT_STATUS = status
|
|
@@ -306,9 +381,19 @@ class _WRFRunConstants:
|
|
|
306
381
|
|
|
307
382
|
class _WRFRunNamelist:
|
|
308
383
|
"""
|
|
309
|
-
|
|
384
|
+
Manage all namelist configurations of NWP models.
|
|
310
385
|
"""
|
|
386
|
+
|
|
311
387
|
def __init__(self):
|
|
388
|
+
"""
|
|
389
|
+
Manage all namelist configurations of NWP models.
|
|
390
|
+
|
|
391
|
+
This class provides interfaces to read and write various namelist values of NWP model.
|
|
392
|
+
Namelist values are stored in a dictionary with a unique ``namelist_id`` to avoid being messed up with other namelist.
|
|
393
|
+
|
|
394
|
+
If you want to use a new ``namelist_id`` other than the defaults to store namelist,
|
|
395
|
+
you can register a new ``namelist_id`` with :meth:`_WRFRunNamelist.register_custom_namelist_id`.
|
|
396
|
+
"""
|
|
312
397
|
self._wps_namelist = {}
|
|
313
398
|
self._wrf_namelist = {}
|
|
314
399
|
self._wrfda_namelist = {}
|
|
@@ -317,7 +402,7 @@ class _WRFRunNamelist:
|
|
|
317
402
|
|
|
318
403
|
def register_custom_namelist_id(self, namelist_id: str) -> bool:
|
|
319
404
|
"""
|
|
320
|
-
Register a
|
|
405
|
+
Register a unique ``namelist_id`` so you can read, update and write namelist with it later.
|
|
321
406
|
|
|
322
407
|
:param namelist_id: A unique namelist id.
|
|
323
408
|
:type namelist_id: str
|
|
@@ -333,13 +418,11 @@ class _WRFRunNamelist:
|
|
|
333
418
|
|
|
334
419
|
def unregister_custom_namelist_id(self, namelist_id: str):
|
|
335
420
|
"""
|
|
336
|
-
Unregister a
|
|
337
|
-
If unregister successfully, all
|
|
421
|
+
Unregister a ``namelist_id``.
|
|
422
|
+
If unregister successfully, all values of this namelist will be deleted.
|
|
338
423
|
|
|
339
424
|
:param namelist_id: A unique namelist id.
|
|
340
425
|
:type namelist_id: str
|
|
341
|
-
:return:
|
|
342
|
-
:rtype:
|
|
343
426
|
"""
|
|
344
427
|
if namelist_id not in self._namelist_id_list:
|
|
345
428
|
return
|
|
@@ -349,11 +432,11 @@ class _WRFRunNamelist:
|
|
|
349
432
|
|
|
350
433
|
def check_namelist_id(self, namelist_id: str) -> bool:
|
|
351
434
|
"""
|
|
352
|
-
Check if a
|
|
435
|
+
Check if a ``namelist_id`` is registered.
|
|
353
436
|
|
|
354
|
-
:param namelist_id:
|
|
355
|
-
:type namelist_id:
|
|
356
|
-
:return: True if the
|
|
437
|
+
:param namelist_id: A ``namelist_id``.
|
|
438
|
+
:type namelist_id: str
|
|
439
|
+
:return: True if the ``namelist_id`` is registered, else False.
|
|
357
440
|
:rtype: bool
|
|
358
441
|
"""
|
|
359
442
|
if namelist_id in self._namelist_id_list:
|
|
@@ -363,11 +446,14 @@ class _WRFRunNamelist:
|
|
|
363
446
|
|
|
364
447
|
def read_namelist(self, file_path: str, namelist_id: str):
|
|
365
448
|
"""
|
|
366
|
-
Read namelist
|
|
449
|
+
Read namelist values from a file and store them with the ``namelist_id``.
|
|
450
|
+
|
|
451
|
+
If ``wrfrun`` can't read the file, ``FileNotFoundError`` will be raised.
|
|
452
|
+
If ``namelist_id`` isn't registered, :class:`NamelistIDError` will be raised.
|
|
367
453
|
|
|
368
454
|
:param file_path: Namelist file path.
|
|
369
455
|
:type file_path: str
|
|
370
|
-
:param namelist_id:
|
|
456
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
371
457
|
:type namelist_id: str
|
|
372
458
|
"""
|
|
373
459
|
# check the file path
|
|
@@ -377,36 +463,36 @@ class _WRFRunNamelist:
|
|
|
377
463
|
|
|
378
464
|
if namelist_id not in self._namelist_id_list:
|
|
379
465
|
logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
380
|
-
raise
|
|
466
|
+
raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
381
467
|
|
|
382
468
|
self._namelist_dict[namelist_id] = f90nml.read(file_path).todict()
|
|
383
469
|
|
|
384
470
|
def write_namelist(self, save_path: str, namelist_id: str, overwrite=True):
|
|
385
471
|
"""
|
|
386
|
-
Write namelist to file.
|
|
472
|
+
Write namelist values of a ``namelist_id`` to a file.
|
|
387
473
|
|
|
388
|
-
:param save_path:
|
|
474
|
+
:param save_path: Target file path.
|
|
389
475
|
:type save_path: str
|
|
390
|
-
:param namelist_id:
|
|
476
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
391
477
|
:type namelist_id: str
|
|
392
|
-
:param overwrite: If overwrite the existed file
|
|
478
|
+
:param overwrite: If overwrite the existed file.
|
|
393
479
|
:type overwrite: bool
|
|
394
480
|
"""
|
|
395
481
|
if namelist_id not in self._namelist_id_list:
|
|
396
482
|
logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
397
|
-
raise
|
|
483
|
+
raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
398
484
|
|
|
399
485
|
if namelist_id not in self._namelist_dict:
|
|
400
486
|
logger.error(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
|
|
401
|
-
raise
|
|
487
|
+
raise NamelistError(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
|
|
402
488
|
|
|
403
489
|
f90nml.Namelist(self._namelist_dict[namelist_id]).write(save_path, force=overwrite)
|
|
404
490
|
|
|
405
491
|
def update_namelist(self, new_values: Union[str, dict], namelist_id: str):
|
|
406
492
|
"""
|
|
407
|
-
Update
|
|
493
|
+
Update namelist values of a ``namelist_id``.
|
|
408
494
|
|
|
409
|
-
You can give
|
|
495
|
+
You can give the path of a whole namelist file or a file only contains values you want to change.
|
|
410
496
|
|
|
411
497
|
>>> namelist_file = "./namelist.wps"
|
|
412
498
|
>>> WRFRUNConfig.update_namelist(namelist_file, namelist_id="wps")
|
|
@@ -414,7 +500,7 @@ class _WRFRunNamelist:
|
|
|
414
500
|
>>> namelist_file = "./namelist.wrf"
|
|
415
501
|
>>> WRFRUNConfig.update_namelist(namelist_file, namelist_id="wrf")
|
|
416
502
|
|
|
417
|
-
|
|
503
|
+
You can also give a dict contains values you want to change.
|
|
418
504
|
|
|
419
505
|
>>> namelist_values = {"ungrib": {"prefix": "./output/FILE"}}
|
|
420
506
|
>>> WRFRUNConfig.update_namelist(namelist_values, namelist_id="wps")
|
|
@@ -422,14 +508,14 @@ class _WRFRunNamelist:
|
|
|
422
508
|
>>> namelist_values = {"time_control": {"debug_level": 100}}
|
|
423
509
|
>>> WRFRUNConfig.update_namelist(namelist_values, namelist_id="wrf")
|
|
424
510
|
|
|
425
|
-
:param new_values:
|
|
511
|
+
:param new_values: The path of a namelist file, or a dict contains namelist values.
|
|
426
512
|
:type new_values: str | dict
|
|
427
|
-
:param namelist_id:
|
|
513
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
428
514
|
:type namelist_id: str
|
|
429
515
|
"""
|
|
430
516
|
if namelist_id not in self._namelist_id_list:
|
|
431
517
|
logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
432
|
-
raise
|
|
518
|
+
raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
433
519
|
|
|
434
520
|
elif namelist_id not in self._namelist_dict:
|
|
435
521
|
self._namelist_dict[namelist_id] = new_values
|
|
@@ -452,29 +538,28 @@ class _WRFRunNamelist:
|
|
|
452
538
|
|
|
453
539
|
def get_namelist(self, namelist_id: str) -> dict:
|
|
454
540
|
"""
|
|
455
|
-
Get
|
|
541
|
+
Get namelist values of a ``namelist_id``.
|
|
456
542
|
|
|
457
|
-
:param namelist_id:
|
|
543
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
458
544
|
:type namelist_id: str
|
|
459
|
-
:return:
|
|
545
|
+
:return: A dictionary which contains namelist values.
|
|
460
546
|
:rtype: dict
|
|
461
547
|
"""
|
|
462
548
|
if namelist_id not in self._namelist_id_list:
|
|
463
549
|
logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
464
|
-
raise
|
|
550
|
+
raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
465
551
|
elif namelist_id not in self._namelist_dict:
|
|
466
|
-
|
|
552
|
+
logger.error(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
|
|
553
|
+
raise NamelistError(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
|
|
467
554
|
else:
|
|
468
555
|
return deepcopy(self._namelist_dict[namelist_id])
|
|
469
556
|
|
|
470
557
|
def delete_namelist(self, namelist_id: str):
|
|
471
558
|
"""
|
|
472
|
-
Delete
|
|
559
|
+
Delete namelist values of a ``namelist_id``.
|
|
473
560
|
|
|
474
|
-
:param namelist_id:
|
|
561
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
475
562
|
:type namelist_id: str
|
|
476
|
-
:return:
|
|
477
|
-
:rtype:
|
|
478
563
|
"""
|
|
479
564
|
if namelist_id not in self._namelist_id_list:
|
|
480
565
|
logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
|
|
@@ -488,12 +573,20 @@ class _WRFRunNamelist:
|
|
|
488
573
|
|
|
489
574
|
class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
490
575
|
"""
|
|
491
|
-
Class to manage wrfrun config.
|
|
576
|
+
Class to manage wrfrun config, runtime constants, namelists and resource files.
|
|
492
577
|
"""
|
|
493
578
|
_instance = None
|
|
494
579
|
_initialized = False
|
|
495
580
|
|
|
496
581
|
def __init__(self):
|
|
582
|
+
"""
|
|
583
|
+
This class provides various interfaces to access ``wrfrun``'s config, namelist values of NWP models,
|
|
584
|
+
runtime constants and resource files by inheriting from:
|
|
585
|
+
:class:`_WRFRunConstants`, :class:`_WRFRunNamelist` and :class:`_WRFRunResources`.
|
|
586
|
+
|
|
587
|
+
An instance of this class called ``WRFRUNConfig`` will be created after the user import ``wrfrun``,
|
|
588
|
+
and you should use the instance to access configs or other things instead of creating another instance.
|
|
589
|
+
"""
|
|
497
590
|
if self._initialized:
|
|
498
591
|
return
|
|
499
592
|
|
|
@@ -519,20 +612,24 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
519
612
|
|
|
520
613
|
def set_config_template_path(self, file_path: str):
|
|
521
614
|
"""
|
|
522
|
-
Set
|
|
615
|
+
Set file path of the config template file.
|
|
523
616
|
|
|
524
617
|
:param file_path: Template file path.
|
|
525
618
|
:type file_path: str
|
|
526
|
-
:return:
|
|
527
|
-
:rtype:
|
|
528
619
|
"""
|
|
529
620
|
self._config_template_file_path = file_path
|
|
530
621
|
|
|
531
622
|
def load_wrfrun_config(self, config_path: Optional[str] = None):
|
|
532
623
|
"""
|
|
533
|
-
Load wrfrun config.
|
|
624
|
+
Load ``wrfrun`` config from a config file.
|
|
625
|
+
|
|
626
|
+
If the config path is invalid, ``wrfrun`` will create a new config file at the same place,
|
|
627
|
+
and raise ``FileNotFoundError``.
|
|
628
|
+
|
|
629
|
+
If you don't give the config path, ``wrfrun`` will create a new config file under the current directory,
|
|
630
|
+
and read it.
|
|
534
631
|
|
|
535
|
-
:param config_path:
|
|
632
|
+
:param config_path: TOML config file. Defaults to None.
|
|
536
633
|
:type config_path: str
|
|
537
634
|
"""
|
|
538
635
|
config_template_path = self.parse_resource_uri(self._config_template_file_path)
|
|
@@ -563,7 +660,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
563
660
|
|
|
564
661
|
def save_wrfrun_config(self, save_path: str):
|
|
565
662
|
"""
|
|
566
|
-
Save config to a file.
|
|
663
|
+
Save ``wrfrun``'s config to a file.
|
|
567
664
|
|
|
568
665
|
:param save_path: Save path of the config.
|
|
569
666
|
:type save_path: str
|
|
@@ -577,29 +674,41 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
577
674
|
with open(save_path, "wb") as f:
|
|
578
675
|
tomli_w.dump(self._config, f)
|
|
579
676
|
|
|
580
|
-
def __getitem__(self, item):
|
|
677
|
+
def __getitem__(self, item: str):
|
|
678
|
+
"""
|
|
679
|
+
You can access ``wrfrun`` config like the way to access values in a dictionary.
|
|
680
|
+
|
|
681
|
+
For example
|
|
682
|
+
|
|
683
|
+
>>> model_config = WRFRUNConfig["model"] # get all model configs.
|
|
684
|
+
|
|
685
|
+
:param item: Keys.
|
|
686
|
+
:type item: str
|
|
687
|
+
"""
|
|
581
688
|
if len(self._config) == 0:
|
|
582
689
|
logger.error("Attempt to read value before load config")
|
|
583
690
|
raise RuntimeError("Attempt to read value before load config")
|
|
584
691
|
|
|
585
692
|
return deepcopy(self._config[item])
|
|
586
693
|
|
|
587
|
-
def get_input_data_path(self) ->
|
|
694
|
+
def get_input_data_path(self) -> str:
|
|
588
695
|
"""
|
|
589
|
-
|
|
696
|
+
Get the path of directory in which stores the input data.
|
|
590
697
|
|
|
591
|
-
:return:
|
|
592
|
-
:rtype:
|
|
698
|
+
:return: Directory path.
|
|
699
|
+
:rtype: str
|
|
593
700
|
"""
|
|
594
701
|
return deepcopy(self["input_data_path"])
|
|
595
702
|
|
|
596
703
|
def get_model_config(self, model_name: str) -> dict:
|
|
597
704
|
"""
|
|
598
|
-
|
|
705
|
+
Get the config of a NWP model.
|
|
599
706
|
|
|
600
|
-
|
|
707
|
+
An exception :class:`ModelNameError` will be raised if the config can't be found.
|
|
708
|
+
|
|
709
|
+
:param model_name: Name of the model. For example, ``wrf``.
|
|
601
710
|
:type model_name: str
|
|
602
|
-
:return: A
|
|
711
|
+
:return: A dictionary.
|
|
603
712
|
:rtype: dict
|
|
604
713
|
"""
|
|
605
714
|
if model_name not in self["model"]:
|
|
@@ -610,7 +719,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
610
719
|
|
|
611
720
|
def get_log_path(self) -> str:
|
|
612
721
|
"""
|
|
613
|
-
|
|
722
|
+
Get the directory path to save logs.
|
|
614
723
|
|
|
615
724
|
:return: A directory path.
|
|
616
725
|
:rtype: str
|
|
@@ -619,7 +728,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
619
728
|
|
|
620
729
|
def get_socket_server_config(self) -> Tuple[str, int]:
|
|
621
730
|
"""
|
|
622
|
-
|
|
731
|
+
Get settings of the socket server.
|
|
623
732
|
|
|
624
733
|
:return: ("host", port)
|
|
625
734
|
:rtype: tuple
|
|
@@ -628,7 +737,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
628
737
|
|
|
629
738
|
def get_job_scheduler_config(self) -> dict:
|
|
630
739
|
"""
|
|
631
|
-
|
|
740
|
+
Get configs of job scheduler.
|
|
632
741
|
|
|
633
742
|
:return: A dict object.
|
|
634
743
|
:rtype: dict
|
|
@@ -637,9 +746,9 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
637
746
|
|
|
638
747
|
def get_core_num(self) -> int:
|
|
639
748
|
"""
|
|
640
|
-
|
|
641
|
-
:return:
|
|
642
|
-
:rtype:
|
|
749
|
+
Get the number of CPU cores to be used.
|
|
750
|
+
:return: Core numbers
|
|
751
|
+
:rtype: int
|
|
643
752
|
"""
|
|
644
753
|
return self["core_num"]
|
|
645
754
|
|
|
@@ -672,12 +781,12 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
672
781
|
|
|
673
782
|
:param prefix: Prefix string of ungrib output (WRF intermediate file).
|
|
674
783
|
:type prefix: str
|
|
675
|
-
:return:
|
|
676
|
-
:rtype:
|
|
677
784
|
"""
|
|
678
|
-
self.update_namelist(
|
|
679
|
-
|
|
680
|
-
|
|
785
|
+
self.update_namelist(
|
|
786
|
+
{
|
|
787
|
+
"ungrib": {"prefix": f"{self.UNGRIB_OUT_DIR}/{prefix}"}
|
|
788
|
+
}, "wps"
|
|
789
|
+
)
|
|
681
790
|
|
|
682
791
|
def get_metgrid_fg_names(self) -> list[str]:
|
|
683
792
|
"""
|
|
@@ -692,26 +801,36 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
692
801
|
|
|
693
802
|
def set_metgrid_fg_names(self, prefix: Union[str, list[str]]):
|
|
694
803
|
"""
|
|
695
|
-
Set prefix strings
|
|
804
|
+
Set prefix strings of "fg_name" in namelist "metgrid" section.
|
|
696
805
|
|
|
697
806
|
:param prefix: Prefix strings list.
|
|
698
807
|
:type prefix: str | list
|
|
699
|
-
:return:
|
|
700
|
-
:rtype:
|
|
701
808
|
"""
|
|
702
809
|
if isinstance(prefix, str):
|
|
703
810
|
prefix = [prefix, ]
|
|
704
811
|
fg_names = [f"{self.UNGRIB_OUT_DIR}/{x}" for x in prefix]
|
|
705
|
-
self.update_namelist(
|
|
706
|
-
|
|
707
|
-
|
|
812
|
+
self.update_namelist(
|
|
813
|
+
{
|
|
814
|
+
"metgrid": {"fg_name": fg_names}
|
|
815
|
+
}, "wps"
|
|
816
|
+
)
|
|
708
817
|
|
|
709
818
|
def write_namelist(self, save_path: str, namelist_id: str, overwrite=True):
|
|
819
|
+
"""
|
|
820
|
+
Write namelist values of a ``namelist_id`` to a file.
|
|
821
|
+
This method is overwritten to convert URIs in ``save_path`` first.
|
|
822
|
+
|
|
823
|
+
:param save_path: Target file path.
|
|
824
|
+
:type save_path: str
|
|
825
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
826
|
+
:type namelist_id: str
|
|
827
|
+
:param overwrite: If overwrite the existed file.
|
|
828
|
+
:type overwrite: bool
|
|
829
|
+
"""
|
|
710
830
|
save_path = self.parse_resource_uri(save_path)
|
|
711
831
|
super().write_namelist(save_path, namelist_id, overwrite)
|
|
712
832
|
|
|
713
833
|
|
|
714
834
|
WRFRUNConfig = WRFRunConfig()
|
|
715
835
|
|
|
716
|
-
|
|
717
836
|
__all__ = ["WRFRUNConfig"]
|