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