wrfrun 0.1.8__py3-none-any.whl → 0.2.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.
- wrfrun/cli.py +131 -0
- wrfrun/core/base.py +52 -19
- wrfrun/core/config.py +257 -170
- wrfrun/core/error.py +8 -1
- wrfrun/core/replay.py +1 -1
- wrfrun/core/server.py +91 -71
- wrfrun/data.py +14 -16
- wrfrun/extension/goos_sst/__init__.py +5 -5
- wrfrun/extension/goos_sst/core.py +4 -1
- wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +1 -1
- wrfrun/extension/goos_sst/res/__init__.py +17 -0
- wrfrun/extension/goos_sst/utils.py +21 -5
- wrfrun/extension/littler/__init__.py +57 -1
- wrfrun/extension/littler/{utils.py → core.py} +329 -43
- wrfrun/extension/utils.py +24 -22
- wrfrun/model/__init__.py +24 -1
- wrfrun/model/plot.py +259 -36
- wrfrun/model/utils.py +19 -9
- wrfrun/model/wrf/__init__.py +41 -0
- wrfrun/model/wrf/core.py +229 -101
- wrfrun/model/wrf/exec_wrap.py +49 -35
- wrfrun/model/wrf/geodata.py +2 -1
- wrfrun/model/wrf/namelist.py +78 -4
- wrfrun/model/wrf/{_metgrid.py → utils.py} +38 -3
- wrfrun/model/wrf/vtable.py +9 -5
- wrfrun/res/__init__.py +22 -7
- wrfrun/res/config/config.template.toml +57 -0
- wrfrun/res/{config.toml.template → config/wrf.template.toml} +7 -46
- 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 +39 -27
- wrfrun/scheduler/__init__.py +35 -0
- wrfrun/scheduler/env.py +44 -0
- wrfrun/scheduler/lsf.py +49 -0
- wrfrun/scheduler/pbs.py +50 -0
- wrfrun/scheduler/script.py +72 -0
- wrfrun/scheduler/slurm.py +50 -0
- wrfrun/scheduler/utils.py +14 -0
- wrfrun/utils.py +8 -3
- wrfrun/workspace/__init__.py +38 -0
- wrfrun/workspace/core.py +94 -0
- wrfrun/workspace/wrf.py +165 -0
- {wrfrun-0.1.8.dist-info → wrfrun-0.2.0.dist-info}/METADATA +3 -2
- wrfrun-0.2.0.dist-info/RECORD +62 -0
- wrfrun-0.2.0.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.8.dist-info/RECORD +0 -51
- {wrfrun-0.1.8.dist-info → wrfrun-0.2.0.dist-info}/WHEEL +0 -0
wrfrun/core/config.py
CHANGED
|
@@ -11,6 +11,9 @@ All classes in this module is used to manage various configurations of ``wrfrun`
|
|
|
11
11
|
_WRFRunConstants
|
|
12
12
|
_WRFRunNamelist
|
|
13
13
|
_WRFRunResources
|
|
14
|
+
init_wrfrun_config
|
|
15
|
+
get_wrfrun_config
|
|
16
|
+
set_register_func
|
|
14
17
|
|
|
15
18
|
WRFRunConfig
|
|
16
19
|
************
|
|
@@ -20,17 +23,24 @@ It inherits from three classes: :class:`_WRFRunResources`, :class:`_WRFRunConsta
|
|
|
20
23
|
Users can use the global variable ``WRFRUNConfig``, which is the instance of this class being created when users import ``wrfrun``.
|
|
21
24
|
"""
|
|
22
25
|
|
|
26
|
+
# TODO:
|
|
27
|
+
# 1. NEW FEATURE: Allow reading work directory from config file.
|
|
28
|
+
# 2. The first one will be a break change, fix the following errors.
|
|
29
|
+
# 3. The structure of wrfrun may need to be changed again.
|
|
30
|
+
|
|
31
|
+
import threading
|
|
23
32
|
from copy import deepcopy
|
|
24
33
|
from os import environ, makedirs
|
|
25
|
-
from os.path import abspath,
|
|
34
|
+
from os.path import abspath, dirname, exists
|
|
26
35
|
from shutil import copyfile
|
|
27
|
-
from
|
|
36
|
+
from sys import platform
|
|
37
|
+
from typing import Callable, Optional, Tuple, Union
|
|
28
38
|
|
|
29
39
|
import f90nml
|
|
30
40
|
import tomli
|
|
31
41
|
import tomli_w
|
|
32
42
|
|
|
33
|
-
from .error import
|
|
43
|
+
from .error import ModelNameError, NamelistError, NamelistIDError, ResourceURIError, WRFRunContextError, ConfigError
|
|
34
44
|
from ..utils import logger
|
|
35
45
|
|
|
36
46
|
|
|
@@ -110,7 +120,7 @@ class _WRFRunResources:
|
|
|
110
120
|
|
|
111
121
|
For example, you can get the real path of ``wrfrun`` workspace with this method:
|
|
112
122
|
|
|
113
|
-
>>> workspace_path = f"{WRFRUNConfig.
|
|
123
|
+
>>> workspace_path = f"{WRFRUNConfig.WRFRUN_WORKSPACE_ROOT}/WPS" # ":WRFRUN_WORKSPACE_PATH:/WPS"
|
|
114
124
|
>>> real_path = WRFRUNConfig.parse_resource_uri(workspace_path) # should be a valid path like: "/home/syize/.config/wrfrun/workspace/WPS"
|
|
115
125
|
|
|
116
126
|
"""
|
|
@@ -139,48 +149,53 @@ class _WRFRunConstants:
|
|
|
139
149
|
Define all variables that will be used by other components.
|
|
140
150
|
"""
|
|
141
151
|
|
|
142
|
-
def __init__(self):
|
|
152
|
+
def __init__(self, work_dir: str):
|
|
143
153
|
"""
|
|
144
154
|
Define all variables that will be used by other components.
|
|
145
155
|
|
|
146
156
|
These variables are related to ``wrfrun`` installation environments, configuration files and more.
|
|
147
157
|
They are defined either directly or mapped using URIs to ensure consistent access across all components.
|
|
158
|
+
|
|
159
|
+
:param work_dir: ``wrfrun`` work directory path.
|
|
160
|
+
:type work_dir: str
|
|
148
161
|
"""
|
|
149
|
-
#
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
162
|
+
# check system
|
|
163
|
+
if platform != "linux":
|
|
164
|
+
logger.debug(f"Not Linux system!")
|
|
165
|
+
|
|
166
|
+
if work_dir != "" or platform != "linux":
|
|
167
|
+
# set temporary dir path
|
|
168
|
+
self._WRFRUN_TEMP_PATH = abspath(f"{work_dir}/tmp")
|
|
169
|
+
self._WRFRUN_HOME_PATH = abspath(work_dir)
|
|
170
|
+
|
|
171
|
+
else:
|
|
172
|
+
# the path we may need to store temp files,
|
|
173
|
+
# don't worry, it will be deleted once the system reboots
|
|
174
|
+
self._WRFRUN_TEMP_PATH = "/tmp/wrfrun"
|
|
175
|
+
user_home_path = f"{environ['HOME']}"
|
|
176
|
+
|
|
177
|
+
# WRF may need a large disk space to store output, we can't run wrf in /tmp,
|
|
178
|
+
# so we will create a folder in $HOME/.config to run wrf.
|
|
179
|
+
# we need to check if we're running as a root user
|
|
180
|
+
if user_home_path in ["/", "/root", ""]:
|
|
181
|
+
logger.warning(f"User's home path is '{user_home_path}', which means you are running this program as a root user")
|
|
182
|
+
logger.warning("It's not recommended to use wrfrun as a root user")
|
|
183
|
+
logger.warning("Set user_home_path as /root")
|
|
184
|
+
user_home_path = "/root"
|
|
185
|
+
|
|
186
|
+
self._WRFRUN_HOME_PATH = f"{user_home_path}/.config/wrfrun"
|
|
187
|
+
|
|
188
|
+
# workspace root path
|
|
189
|
+
self._WRFRUN_WORKSPACE_ROOT = f"{self._WRFRUN_HOME_PATH}/workspace"
|
|
190
|
+
self._WRFRUN_WORKSPACE_MODEL = f"{self._WRFRUN_WORKSPACE_ROOT}/model"
|
|
191
|
+
self._WRFRUN_WORKSPACE_REPLAY = f"{self._WRFRUN_WORKSPACE_ROOT}/replay"
|
|
171
192
|
|
|
172
193
|
# record WRF progress status
|
|
173
|
-
self.
|
|
194
|
+
self._WRFRUN_WORK_STATUS = ""
|
|
174
195
|
|
|
175
196
|
# record context status
|
|
176
197
|
self._WRFRUN_CONTEXT_STATUS = False
|
|
177
198
|
|
|
178
|
-
# WRFDA is not necessary
|
|
179
|
-
self.USE_WRFDA: bool = False
|
|
180
|
-
|
|
181
|
-
# output directory of ungrib
|
|
182
|
-
self._UNGRIB_OUT_DIR = "./outputs"
|
|
183
|
-
|
|
184
199
|
self._WRFRUN_OUTPUT_PATH = ":WRFRUN_OUTPUT_PATH:"
|
|
185
200
|
self._WRFRUN_RESOURCE_PATH = ":WRFRUN_RESOURCE_PATH:"
|
|
186
201
|
|
|
@@ -203,22 +218,20 @@ class _WRFRunConstants:
|
|
|
203
218
|
return {
|
|
204
219
|
self.WRFRUN_TEMP_PATH: self._WRFRUN_TEMP_PATH,
|
|
205
220
|
self.WRFRUN_HOME_PATH: self._WRFRUN_HOME_PATH,
|
|
206
|
-
self.
|
|
207
|
-
self.
|
|
208
|
-
self.
|
|
209
|
-
self.WRFDA_WORK_PATH: self._WRFDA_WORK_PATH,
|
|
210
|
-
self.WRFRUN_REPLAY_WORK_PATH: self._WRFRUN_REPLAY_WORK_PATH,
|
|
221
|
+
self.WRFRUN_WORKSPACE_ROOT: self._WRFRUN_WORKSPACE_ROOT,
|
|
222
|
+
self.WRFRUN_WORKSPACE_MODEL: self._WRFRUN_WORKSPACE_MODEL,
|
|
223
|
+
self.WRFRUN_WORKSPACE_REPLAY: self._WRFRUN_WORKSPACE_REPLAY,
|
|
211
224
|
}
|
|
212
225
|
|
|
213
226
|
@property
|
|
214
|
-
def
|
|
227
|
+
def WRFRUN_WORKSPACE_REPLAY(self) -> str:
|
|
215
228
|
"""
|
|
216
|
-
Path (URI) to store related files of ``wrfrun``
|
|
229
|
+
Path (URI) to store related files of ``wrfrun`` replay functionality.
|
|
217
230
|
|
|
218
231
|
:return: URI.
|
|
219
232
|
:rtype: str
|
|
220
233
|
"""
|
|
221
|
-
return ":
|
|
234
|
+
return ":WRFRUN_WORKSPACE_REPLAY:"
|
|
222
235
|
|
|
223
236
|
@property
|
|
224
237
|
def WRFRUN_TEMP_PATH(self) -> str:
|
|
@@ -241,44 +254,24 @@ class _WRFRunConstants:
|
|
|
241
254
|
return ":WRFRUN_HOME_PATH:"
|
|
242
255
|
|
|
243
256
|
@property
|
|
244
|
-
def
|
|
245
|
-
"""
|
|
246
|
-
Path of the workspace, in which ``wrfrun`` runs NWP models.
|
|
247
|
-
|
|
248
|
-
:return: URI
|
|
249
|
-
:rtype: str
|
|
250
|
-
"""
|
|
251
|
-
return ":WRFRUN_WORKSPACE_PATH:"
|
|
252
|
-
|
|
253
|
-
@property
|
|
254
|
-
def WPS_WORK_PATH(self) -> str:
|
|
255
|
-
"""
|
|
256
|
-
Workspace in which ``wrfrun`` runs WPS.
|
|
257
|
-
|
|
258
|
-
:return: URI
|
|
259
|
-
:rtype: str
|
|
260
|
-
"""
|
|
261
|
-
return ":WRFRUN_WPS_WORK_PATH:"
|
|
262
|
-
|
|
263
|
-
@property
|
|
264
|
-
def WRF_WORK_PATH(self) -> str:
|
|
257
|
+
def WRFRUN_WORKSPACE_ROOT(self) -> str:
|
|
265
258
|
"""
|
|
266
|
-
|
|
259
|
+
Path of the root workspace.
|
|
267
260
|
|
|
268
261
|
:return: URI
|
|
269
262
|
:rtype: str
|
|
270
263
|
"""
|
|
271
|
-
return ":
|
|
264
|
+
return ":WRFRUN_WORKSPACE_ROOT:"
|
|
272
265
|
|
|
273
266
|
@property
|
|
274
|
-
def
|
|
267
|
+
def WRFRUN_WORKSPACE_MODEL(self) -> str:
|
|
275
268
|
"""
|
|
276
|
-
|
|
269
|
+
Path of the model workspace, in which ``wrfrun`` runs numerical models.
|
|
277
270
|
|
|
278
271
|
:return: URI
|
|
279
272
|
:rtype: str
|
|
280
273
|
"""
|
|
281
|
-
return ":
|
|
274
|
+
return ":WRFRUN_WORKSPACE_MODEL:"
|
|
282
275
|
|
|
283
276
|
@property
|
|
284
277
|
def WRFRUN_WORK_STATUS(self) -> str:
|
|
@@ -291,7 +284,7 @@ class _WRFRunConstants:
|
|
|
291
284
|
:return: A string reflect the current work progress.
|
|
292
285
|
:rtype: str
|
|
293
286
|
"""
|
|
294
|
-
return self.
|
|
287
|
+
return self._WRFRUN_WORK_STATUS
|
|
295
288
|
|
|
296
289
|
@WRFRUN_WORK_STATUS.setter
|
|
297
290
|
def WRFRUN_WORK_STATUS(self, value: str):
|
|
@@ -306,29 +299,7 @@ class _WRFRunConstants:
|
|
|
306
299
|
"""
|
|
307
300
|
if not isinstance(value, str):
|
|
308
301
|
value = str(value)
|
|
309
|
-
self.
|
|
310
|
-
|
|
311
|
-
@property
|
|
312
|
-
def UNGRIB_OUT_DIR(self) -> str:
|
|
313
|
-
"""
|
|
314
|
-
Output directory path of ``ungrib.exe``.
|
|
315
|
-
|
|
316
|
-
:return: URI
|
|
317
|
-
:rtype: str
|
|
318
|
-
"""
|
|
319
|
-
return self._UNGRIB_OUT_DIR
|
|
320
|
-
|
|
321
|
-
@UNGRIB_OUT_DIR.setter
|
|
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
|
-
"""
|
|
329
|
-
if not isinstance(value, str):
|
|
330
|
-
value = str(value)
|
|
331
|
-
self._UNGRIB_OUT_DIR = value
|
|
302
|
+
self._WRFRUN_WORK_STATUS = value
|
|
332
303
|
|
|
333
304
|
@property
|
|
334
305
|
def WRFRUN_OUTPUT_PATH(self) -> str:
|
|
@@ -394,9 +365,6 @@ class _WRFRunNamelist:
|
|
|
394
365
|
If you want to use a new ``namelist_id`` other than the defaults to store namelist,
|
|
395
366
|
you can register a new ``namelist_id`` with :meth:`_WRFRunNamelist.register_custom_namelist_id`.
|
|
396
367
|
"""
|
|
397
|
-
self._wps_namelist = {}
|
|
398
|
-
self._wrf_namelist = {}
|
|
399
|
-
self._wrfda_namelist = {}
|
|
400
368
|
self._namelist_dict = {}
|
|
401
369
|
self._namelist_id_list = ("param", "geog_static_data", "wps", "wrf", "wrfda")
|
|
402
370
|
|
|
@@ -570,6 +538,24 @@ class _WRFRunNamelist:
|
|
|
570
538
|
|
|
571
539
|
self._namelist_dict.pop(namelist_id)
|
|
572
540
|
|
|
541
|
+
def check_namelist(self, namelist_id: str) -> bool:
|
|
542
|
+
"""
|
|
543
|
+
Check if a namelist has been registered and loaded.
|
|
544
|
+
|
|
545
|
+
:param namelist_id: Registered ``namelist_id``.
|
|
546
|
+
:type namelist_id: str
|
|
547
|
+
:return: ``True`` if it is registered and loaded, else ``False``.
|
|
548
|
+
:rtype: bool
|
|
549
|
+
"""
|
|
550
|
+
if namelist_id in self._namelist_id_list and namelist_id in self._namelist_dict:
|
|
551
|
+
return True
|
|
552
|
+
|
|
553
|
+
else:
|
|
554
|
+
return False
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
_URI_REGISTER_FUNC_LIST: list[Callable[["WRFRunConfig"], None]] = []
|
|
558
|
+
|
|
573
559
|
|
|
574
560
|
class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
575
561
|
"""
|
|
@@ -577,8 +563,9 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
577
563
|
"""
|
|
578
564
|
_instance = None
|
|
579
565
|
_initialized = False
|
|
566
|
+
_lock = threading.Lock()
|
|
580
567
|
|
|
581
|
-
def __init__(self):
|
|
568
|
+
def __init__(self, work_dir: str):
|
|
582
569
|
"""
|
|
583
570
|
This class provides various interfaces to access ``wrfrun``'s config, namelist values of NWP models,
|
|
584
571
|
runtime constants and resource files by inheriting from:
|
|
@@ -586,23 +573,32 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
586
573
|
|
|
587
574
|
An instance of this class called ``WRFRUNConfig`` will be created after the user import ``wrfrun``,
|
|
588
575
|
and you should use the instance to access configs or other things instead of creating another instance.
|
|
576
|
+
|
|
577
|
+
:param work_dir: ``wrfrun`` work directory path.
|
|
578
|
+
:type work_dir: str
|
|
589
579
|
"""
|
|
590
580
|
if self._initialized:
|
|
591
581
|
return
|
|
592
582
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
_WRFRunResources.__init__(self)
|
|
583
|
+
with self._lock:
|
|
584
|
+
global _URI_REGISTER_FUNC_LIST
|
|
596
585
|
|
|
597
|
-
|
|
586
|
+
self._initialized = True
|
|
598
587
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
588
|
+
_WRFRunConstants.__init__(self, work_dir)
|
|
589
|
+
_WRFRunNamelist.__init__(self)
|
|
590
|
+
_WRFRunResources.__init__(self)
|
|
591
|
+
|
|
592
|
+
self._config = {}
|
|
602
593
|
|
|
603
|
-
|
|
594
|
+
self._config_template_file_path = None
|
|
604
595
|
|
|
605
|
-
|
|
596
|
+
self._register_wrfrun_uris()
|
|
597
|
+
|
|
598
|
+
for _fun in _URI_REGISTER_FUNC_LIST:
|
|
599
|
+
_fun(self)
|
|
600
|
+
|
|
601
|
+
_URI_REGISTER_FUNC_LIST = []
|
|
606
602
|
|
|
607
603
|
def __new__(cls, *args, **kwargs):
|
|
608
604
|
if cls._instance is None:
|
|
@@ -610,6 +606,39 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
610
606
|
|
|
611
607
|
return cls._instance
|
|
612
608
|
|
|
609
|
+
def __getattribute__(self, item):
|
|
610
|
+
if item not in ("_initialized", "_instance", "_lock", "__class__"):
|
|
611
|
+
if not object.__getattribute__(self, "_initialized"):
|
|
612
|
+
logger.error(f"`WRFRUNConfig` hasn't been initialized.")
|
|
613
|
+
logger.error(f"Use `WRFRun` to load config automatically, or use function `init_wrfrun_config` to load config manually.")
|
|
614
|
+
raise ConfigError(f"`WRFRUNConfig` hasn't been initialized.")
|
|
615
|
+
|
|
616
|
+
return object.__getattribute__(self, item)
|
|
617
|
+
|
|
618
|
+
@classmethod
|
|
619
|
+
def from_config_file(cls, config_file: str) -> "WRFRunConfig":
|
|
620
|
+
"""
|
|
621
|
+
Read the config file and reinitialize.
|
|
622
|
+
|
|
623
|
+
:param config_file: Config file path.
|
|
624
|
+
:type config_file: str
|
|
625
|
+
:return: New instance
|
|
626
|
+
:rtype: WRFRunConfig
|
|
627
|
+
"""
|
|
628
|
+
cls._initialized = False
|
|
629
|
+
|
|
630
|
+
with open(config_file, "rb") as f:
|
|
631
|
+
config = tomli.load(f)
|
|
632
|
+
|
|
633
|
+
instance = cls(work_dir=config["work_dir"])
|
|
634
|
+
instance.load_wrfrun_config(config_file)
|
|
635
|
+
|
|
636
|
+
return instance
|
|
637
|
+
|
|
638
|
+
def _register_wrfrun_uris(self):
|
|
639
|
+
for key, value in self._get_uri_map().items():
|
|
640
|
+
self.register_resource_uri(key, value)
|
|
641
|
+
|
|
613
642
|
def set_config_template_path(self, file_path: str):
|
|
614
643
|
"""
|
|
615
644
|
Set file path of the config template file.
|
|
@@ -654,10 +683,39 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
654
683
|
with open(config_path, "rb") as f:
|
|
655
684
|
self._config = tomli.load(f)
|
|
656
685
|
|
|
686
|
+
config_dir_path = abspath(dirname(config_path))
|
|
687
|
+
|
|
688
|
+
# merge model config.
|
|
689
|
+
keys_list = list(self._config["model"].keys())
|
|
690
|
+
for model_key in keys_list:
|
|
691
|
+
|
|
692
|
+
# skip the key that isn't model.
|
|
693
|
+
if model_key == "debug_level":
|
|
694
|
+
continue
|
|
695
|
+
|
|
696
|
+
if "use" not in self._config["model"][model_key]:
|
|
697
|
+
continue
|
|
698
|
+
|
|
699
|
+
if self._config["model"][model_key]["use"]:
|
|
700
|
+
include_file = self._config["model"][model_key]["include"]
|
|
701
|
+
if include_file[0] != "/":
|
|
702
|
+
include_file = f"{config_dir_path}/{include_file}"
|
|
703
|
+
|
|
704
|
+
with open(include_file, "rb") as f:
|
|
705
|
+
self._config["model"][model_key] = tomli.load(f)
|
|
706
|
+
|
|
707
|
+
else:
|
|
708
|
+
self._config["model"].pop(model_key)
|
|
709
|
+
|
|
657
710
|
# register URI for output directory.
|
|
658
711
|
output_path = abspath(self["output_path"])
|
|
659
712
|
self.register_resource_uri(self.WRFRUN_OUTPUT_PATH, output_path)
|
|
660
713
|
|
|
714
|
+
# some additional check
|
|
715
|
+
if self._config["input_data_path"] == "":
|
|
716
|
+
logger.warning("It seems you forget to set 'input_data_path', set it to 'data'.")
|
|
717
|
+
self._config["input_data_path"] = "data"
|
|
718
|
+
|
|
661
719
|
def save_wrfrun_config(self, save_path: str):
|
|
662
720
|
"""
|
|
663
721
|
Save ``wrfrun``'s config to a file.
|
|
@@ -691,6 +749,18 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
691
749
|
|
|
692
750
|
return deepcopy(self._config[item])
|
|
693
751
|
|
|
752
|
+
def __setitem__(self, key: str, value):
|
|
753
|
+
if key == "model":
|
|
754
|
+
logger.error(f"Use `update_model_config` to change model configurations.")
|
|
755
|
+
raise KeyError(f"Use `update_model_config` to change model configurations.")
|
|
756
|
+
|
|
757
|
+
if key in self._config:
|
|
758
|
+
self._config[key] = value
|
|
759
|
+
|
|
760
|
+
else:
|
|
761
|
+
logger.error(f"Can't find key '{key}' in your config.")
|
|
762
|
+
raise KeyError(f"Can't find key '{key}' in your config.")
|
|
763
|
+
|
|
694
764
|
def get_input_data_path(self) -> str:
|
|
695
765
|
"""
|
|
696
766
|
Get the path of directory in which stores the input data.
|
|
@@ -717,6 +787,23 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
717
787
|
|
|
718
788
|
return deepcopy(self["model"][model_name])
|
|
719
789
|
|
|
790
|
+
def update_model_config(self, model_name: str, value: dict):
|
|
791
|
+
"""
|
|
792
|
+
Update the config of a NWP model.
|
|
793
|
+
|
|
794
|
+
An exception :class:`ModelNameError` will be raised if the config can't be found.
|
|
795
|
+
|
|
796
|
+
:param model_name: Name of the model. For example, ``wrf``.
|
|
797
|
+
:type model_name: str
|
|
798
|
+
:param value: Dictionary contains new values.
|
|
799
|
+
:type value: dict
|
|
800
|
+
"""
|
|
801
|
+
if model_name not in self["model"]:
|
|
802
|
+
logger.error(f"Config of model '{model_name}' isn't found in your config file.")
|
|
803
|
+
raise ModelNameError(f"Config of model '{model_name}' isn't found in your config file.")
|
|
804
|
+
|
|
805
|
+
self["model"][model_name] = self["model"][model_name] | value
|
|
806
|
+
|
|
720
807
|
def get_log_path(self) -> str:
|
|
721
808
|
"""
|
|
722
809
|
Get the directory path to save logs.
|
|
@@ -752,69 +839,6 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
752
839
|
"""
|
|
753
840
|
return self["core_num"]
|
|
754
841
|
|
|
755
|
-
def get_ungrib_out_dir_path(self) -> str:
|
|
756
|
-
"""
|
|
757
|
-
Get the output directory of ungrib output (WRF intermediate file).
|
|
758
|
-
|
|
759
|
-
:return: URI path.
|
|
760
|
-
:rtype: str
|
|
761
|
-
"""
|
|
762
|
-
wif_prefix = self.get_namelist("wps")["ungrib"]["prefix"]
|
|
763
|
-
wif_path = f"{self.WPS_WORK_PATH}/{dirname(wif_prefix)}"
|
|
764
|
-
|
|
765
|
-
return wif_path
|
|
766
|
-
|
|
767
|
-
def get_ungrib_out_prefix(self) -> str:
|
|
768
|
-
"""
|
|
769
|
-
Get the prefix string of ungrib output (WRF intermediate file).
|
|
770
|
-
|
|
771
|
-
:return: Prefix string of ungrib output (WRF intermediate file).
|
|
772
|
-
:rtype: str
|
|
773
|
-
"""
|
|
774
|
-
wif_prefix = self.get_namelist("wps")["ungrib"]["prefix"]
|
|
775
|
-
wif_prefix = basename(wif_prefix)
|
|
776
|
-
return wif_prefix
|
|
777
|
-
|
|
778
|
-
def set_ungrib_out_prefix(self, prefix: str):
|
|
779
|
-
"""
|
|
780
|
-
Set the prefix string of ungrib output (WRF intermediate file).
|
|
781
|
-
|
|
782
|
-
:param prefix: Prefix string of ungrib output (WRF intermediate file).
|
|
783
|
-
:type prefix: str
|
|
784
|
-
"""
|
|
785
|
-
self.update_namelist(
|
|
786
|
-
{
|
|
787
|
-
"ungrib": {"prefix": f"{self.UNGRIB_OUT_DIR}/{prefix}"}
|
|
788
|
-
}, "wps"
|
|
789
|
-
)
|
|
790
|
-
|
|
791
|
-
def get_metgrid_fg_names(self) -> list[str]:
|
|
792
|
-
"""
|
|
793
|
-
Get prefix strings from "fg_name" in namelist "metgrid" section.
|
|
794
|
-
|
|
795
|
-
:return: Prefix strings list.
|
|
796
|
-
:rtype: list
|
|
797
|
-
"""
|
|
798
|
-
fg_names = self.get_namelist("wps")["metgrid"]["fg_name"]
|
|
799
|
-
fg_names = [basename(x) for x in fg_names]
|
|
800
|
-
return fg_names
|
|
801
|
-
|
|
802
|
-
def set_metgrid_fg_names(self, prefix: Union[str, list[str]]):
|
|
803
|
-
"""
|
|
804
|
-
Set prefix strings of "fg_name" in namelist "metgrid" section.
|
|
805
|
-
|
|
806
|
-
:param prefix: Prefix strings list.
|
|
807
|
-
:type prefix: str | list
|
|
808
|
-
"""
|
|
809
|
-
if isinstance(prefix, str):
|
|
810
|
-
prefix = [prefix, ]
|
|
811
|
-
fg_names = [f"{self.UNGRIB_OUT_DIR}/{x}" for x in prefix]
|
|
812
|
-
self.update_namelist(
|
|
813
|
-
{
|
|
814
|
-
"metgrid": {"fg_name": fg_names}
|
|
815
|
-
}, "wps"
|
|
816
|
-
)
|
|
817
|
-
|
|
818
842
|
def write_namelist(self, save_path: str, namelist_id: str, overwrite=True):
|
|
819
843
|
"""
|
|
820
844
|
Write namelist values of a ``namelist_id`` to a file.
|
|
@@ -831,6 +855,69 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
|
|
|
831
855
|
super().write_namelist(save_path, namelist_id, overwrite)
|
|
832
856
|
|
|
833
857
|
|
|
834
|
-
WRFRUNConfig = WRFRunConfig()
|
|
858
|
+
WRFRUNConfig = WRFRunConfig.__new__(WRFRunConfig)
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def set_register_func(func: Callable[["WRFRunConfig"], None]):
|
|
862
|
+
"""
|
|
863
|
+
Set the function to register URIs.
|
|
864
|
+
|
|
865
|
+
These functions should accept ``WRFRUNConfig`` instance,
|
|
866
|
+
and will be called when initializing ``WRFRUNConfig``.
|
|
867
|
+
|
|
868
|
+
If ``WRFRUNConfig`` has been initialized, ``func`` will be called immediately.
|
|
869
|
+
|
|
870
|
+
Normal users should use :meth:`WRFRunConfig.register_resource_uri`,
|
|
871
|
+
because ``WRFRUNConfig`` should (and must) be initialized.
|
|
872
|
+
|
|
873
|
+
:param func: Functions to register URIs.
|
|
874
|
+
:type func: Callable
|
|
875
|
+
"""
|
|
876
|
+
global _URI_REGISTER_FUNC_LIST
|
|
877
|
+
|
|
878
|
+
if object.__getattribute__(WRFRUNConfig, "_initialized"):
|
|
879
|
+
func(WRFRUNConfig)
|
|
880
|
+
|
|
881
|
+
else:
|
|
882
|
+
if func not in _URI_REGISTER_FUNC_LIST:
|
|
883
|
+
_URI_REGISTER_FUNC_LIST.append(func)
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def init_wrfrun_config(config_file: str) -> WRFRunConfig:
|
|
887
|
+
"""
|
|
888
|
+
Initialize ``WRFRUNConfig`` with the given config file.
|
|
889
|
+
|
|
890
|
+
:param config_file: Config file path.
|
|
891
|
+
:type config_file: str
|
|
892
|
+
:return: ``WRFRUNConfig`` instance.
|
|
893
|
+
:rtype: WRFRunConfig
|
|
894
|
+
"""
|
|
895
|
+
global WRFRUNConfig
|
|
896
|
+
|
|
897
|
+
logger.info(f"Initialize `WRFRUNConfig` with config: {config_file}")
|
|
898
|
+
|
|
899
|
+
WRFRUNConfig = WRFRunConfig.from_config_file(config_file)
|
|
900
|
+
|
|
901
|
+
return WRFRUNConfig
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
def get_wrfrun_config() -> WRFRunConfig:
|
|
905
|
+
"""
|
|
906
|
+
Get ``WRFRUNConfig`` instance.
|
|
907
|
+
|
|
908
|
+
An exception :class:`ConfigError` will be raised if you haven't initialized it.
|
|
909
|
+
|
|
910
|
+
:return: ``WRFRUNConfig`` instance.
|
|
911
|
+
:rtype: WRFRunConfig
|
|
912
|
+
"""
|
|
913
|
+
global WRFRUNConfig
|
|
914
|
+
|
|
915
|
+
if WRFRUNConfig is None:
|
|
916
|
+
logger.error(f"`WRFRUNConfig` hasn't been initialized.")
|
|
917
|
+
logger.error(f"Use `WRFRun` to load config automatically, or use function `init_wrfrun_config` to load config manually.")
|
|
918
|
+
raise ConfigError(f"`WRFRUNConfig` hasn't been initialized.")
|
|
919
|
+
|
|
920
|
+
return WRFRUNConfig
|
|
921
|
+
|
|
835
922
|
|
|
836
|
-
__all__ = ["WRFRUNConfig"]
|
|
923
|
+
__all__ = ["WRFRunConfig", "WRFRUNConfig", "init_wrfrun_config", "get_wrfrun_config", "set_register_func"]
|
wrfrun/core/error.py
CHANGED
|
@@ -106,5 +106,12 @@ class ModelNameError(WRFRunBasicError):
|
|
|
106
106
|
pass
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
class RecordError(WRFRunBasicError):
|
|
110
|
+
"""
|
|
111
|
+
Exception indicates ``wrfrun`` can't record simulations.
|
|
112
|
+
"""
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
|
|
109
116
|
__all__ = ["WRFRunBasicError", "ConfigError", "WRFRunContextError", "CommandError", "OutputFileError", "ResourceURIError", "InputFileError",
|
|
110
|
-
"NamelistError", "ExecRegisterError", "GetExecClassError", "ModelNameError", "NamelistIDError"]
|
|
117
|
+
"NamelistError", "ExecRegisterError", "GetExecClassError", "ModelNameError", "NamelistIDError", "RecordError"]
|
wrfrun/core/replay.py
CHANGED
|
@@ -124,7 +124,7 @@ def replay_config_generator(replay_config_file: str) -> Generator[tuple[str, Exe
|
|
|
124
124
|
:rtype: Generator
|
|
125
125
|
"""
|
|
126
126
|
logger.info(f"Loading replay resources from: {replay_config_file}")
|
|
127
|
-
work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.
|
|
127
|
+
work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_REPLAY)
|
|
128
128
|
|
|
129
129
|
unpack_archive(replay_config_file, work_path, "zip")
|
|
130
130
|
|