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/cli.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
from os import makedirs
|
|
4
|
+
from os.path import abspath, dirname, exists
|
|
5
|
+
from shutil import copyfile
|
|
6
|
+
|
|
7
|
+
import tomli
|
|
8
|
+
import tomli_w
|
|
9
|
+
|
|
10
|
+
from .core import WRFRunConfig
|
|
11
|
+
from .res import CONFIG_MAIN_TOML_TEMPLATE, CONFIG_WRF_TOML_TEMPLATE
|
|
12
|
+
from .utils import logger
|
|
13
|
+
|
|
14
|
+
MODEL_MAP = {
|
|
15
|
+
"wrf": CONFIG_WRF_TOML_TEMPLATE
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
wrfrun_config = WRFRunConfig("./.wrfrun")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _entry_init(args: argparse.Namespace):
|
|
23
|
+
"""
|
|
24
|
+
Initialize a wrfrun project.
|
|
25
|
+
|
|
26
|
+
:param args: Arguments namespace.
|
|
27
|
+
:type args: argparse.Namespace
|
|
28
|
+
"""
|
|
29
|
+
args = vars(args)
|
|
30
|
+
|
|
31
|
+
project_name = args["name"]
|
|
32
|
+
models = args["models"]
|
|
33
|
+
|
|
34
|
+
if exists(project_name):
|
|
35
|
+
logger.error(f"{project_name} already exists.")
|
|
36
|
+
exit(1)
|
|
37
|
+
|
|
38
|
+
makedirs(f"{project_name}/configs")
|
|
39
|
+
makedirs(f"{project_name}/data")
|
|
40
|
+
|
|
41
|
+
copyfile(wrfrun_config.parse_resource_uri(CONFIG_MAIN_TOML_TEMPLATE), f"{project_name}/config.toml")
|
|
42
|
+
|
|
43
|
+
if models is not None:
|
|
44
|
+
for _model in models:
|
|
45
|
+
src_path = wrfrun_config.parse_resource_uri(MODEL_MAP[_model])
|
|
46
|
+
copyfile(src_path, f"{project_name}/configs/{_model}.toml")
|
|
47
|
+
|
|
48
|
+
logger.info(f"Created project {project_name}.")
|
|
49
|
+
logger.info(f"Use command `wrfrun add MODEL_NAME` to add a new model to project.")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _entry_model(args: argparse.Namespace):
|
|
53
|
+
"""
|
|
54
|
+
Manage models used by wrfrun project.
|
|
55
|
+
|
|
56
|
+
:param args: Arguments namespace.
|
|
57
|
+
:type args: argparse.Namespace
|
|
58
|
+
"""
|
|
59
|
+
args = vars(args)
|
|
60
|
+
new_models = args["add"]
|
|
61
|
+
config_path = args["config"]
|
|
62
|
+
|
|
63
|
+
if not exists(config_path):
|
|
64
|
+
logger.error(f"Can't find '{config_path}', initialize this project first.")
|
|
65
|
+
exit(1)
|
|
66
|
+
|
|
67
|
+
model_config_map = {
|
|
68
|
+
"wrf": CONFIG_WRF_TOML_TEMPLATE
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for _new_model in new_models:
|
|
72
|
+
if _new_model not in model_config_map:
|
|
73
|
+
logger.error(f"Unknow model type: '{_new_model}'")
|
|
74
|
+
exit(1)
|
|
75
|
+
|
|
76
|
+
config_dir_path = f"{abspath(dirname(config_path))}/configs"
|
|
77
|
+
|
|
78
|
+
if not exists(config_dir_path):
|
|
79
|
+
makedirs(config_dir_path)
|
|
80
|
+
|
|
81
|
+
with open(config_path, "rb") as f:
|
|
82
|
+
main_config = tomli.load(f)
|
|
83
|
+
|
|
84
|
+
for _new_model in new_models:
|
|
85
|
+
if _new_model not in main_config["model"]:
|
|
86
|
+
main_config["model"][_new_model] = {
|
|
87
|
+
"note": "Config of this model is generated by wrfrun cli command. DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools.",
|
|
88
|
+
"use": True,
|
|
89
|
+
"include": f"./configs/{_new_model}.toml"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
else:
|
|
93
|
+
if not ("use" in main_config["model"] and main_config["model"]["use"]):
|
|
94
|
+
main_config["model"][_new_model] = {
|
|
95
|
+
"note": "Config of this model is generated by wrfrun cli command. DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools.",
|
|
96
|
+
"use": True,
|
|
97
|
+
"include": f"./configs/{_new_model}.toml"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for _new_model in new_models:
|
|
101
|
+
copyfile(wrfrun_config.parse_resource_uri(model_config_map[_new_model]), f"{config_dir_path}/{_new_model}.toml")
|
|
102
|
+
|
|
103
|
+
with open(config_path, "wb") as f:
|
|
104
|
+
tomli_w.dump(main_config, f)
|
|
105
|
+
|
|
106
|
+
logger.info(f"Added models: {new_models}")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def main_entry():
|
|
110
|
+
"""
|
|
111
|
+
CLI entry point.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
args_parser = argparse.ArgumentParser()
|
|
115
|
+
subparsers = args_parser.add_subparsers(title="Subcommands", description="Valid Subcommands", help="Subcommands")
|
|
116
|
+
|
|
117
|
+
init_parser = subparsers.add_parser("init", help="Initialize a wrfrun project.", add_help=True)
|
|
118
|
+
init_parser.add_argument("-n", "--name", type=str, required=True, help="Name of the wrfrun project.")
|
|
119
|
+
init_parser.add_argument("--models", nargs="*", type=str, help="List of models to use.", choices=["wrf"])
|
|
120
|
+
init_parser.set_defaults(func=_entry_init)
|
|
121
|
+
|
|
122
|
+
model_parser = subparsers.add_parser("model", help="Manage models used by wrfrun project.", add_help=True)
|
|
123
|
+
model_parser.add_argument("-c", "--config", type=str, default="config.toml", help="Path of the main config file.")
|
|
124
|
+
model_parser.add_argument("-a", "--add", nargs="+", required=True, type=str, help="Add models to the project.")
|
|
125
|
+
model_parser.set_defaults(func=_entry_model)
|
|
126
|
+
|
|
127
|
+
args = args_parser.parse_args(args=None if sys.argv[1:] else ["--help"])
|
|
128
|
+
args.func(args)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
__all__ = ["main_entry"]
|
wrfrun/core/base.py
CHANGED
|
@@ -13,14 +13,15 @@ Defines what :class:`ExecutableBase <Executable>` is, how it works and how ``wrf
|
|
|
13
13
|
FileConfigDict
|
|
14
14
|
ExecutableClassConfig
|
|
15
15
|
ExecutableConfig
|
|
16
|
-
|
|
16
|
+
ExecutableConfigRecord
|
|
17
|
+
create_recorder
|
|
17
18
|
ExecutableBase
|
|
18
19
|
|
|
19
20
|
Executable
|
|
20
21
|
**********
|
|
21
22
|
|
|
22
23
|
While ``wrfrun`` aims to provide Python interfaces to various Numerical Weather Prediction model,
|
|
23
|
-
it is important to provide a clear standard about how should
|
|
24
|
+
it is important to provide a clear standard about how should an external executable file be implemented in ``wrfrun``.
|
|
24
25
|
``wrfrun`` provides a class called :class:`ExecutableBase`, which is the parent class for all ``Executable`` classes.
|
|
25
26
|
It not only provide the method to execute external programs,
|
|
26
27
|
but also:
|
|
@@ -54,7 +55,7 @@ from typing import Optional, TypedDict, Union
|
|
|
54
55
|
import numpy as np
|
|
55
56
|
|
|
56
57
|
from .config import WRFRUNConfig
|
|
57
|
-
from .error import CommandError, ConfigError, OutputFileError
|
|
58
|
+
from .error import CommandError, ConfigError, OutputFileError, RecordError
|
|
58
59
|
from ..utils import check_path, logger
|
|
59
60
|
|
|
60
61
|
|
|
@@ -154,7 +155,9 @@ class InputFileType(Enum):
|
|
|
154
155
|
|
|
155
156
|
class FileConfigDict(TypedDict):
|
|
156
157
|
"""
|
|
157
|
-
This dict is used to store information about the file, including its path,
|
|
158
|
+
This dict is used to store information about the file, including its path,
|
|
159
|
+
the path it will be copied or moved to, its new name, etc.
|
|
160
|
+
This dict contains following keys:
|
|
158
161
|
|
|
159
162
|
.. py:attribute:: file_path
|
|
160
163
|
:type: str
|
|
@@ -174,7 +177,8 @@ class FileConfigDict(TypedDict):
|
|
|
174
177
|
.. py:attribute:: is_data
|
|
175
178
|
:type: bool
|
|
176
179
|
|
|
177
|
-
If the file is data. If not, ``wrfrun`` will treat it as a config file,
|
|
180
|
+
If the file is data. If not, ``wrfrun`` will treat it as a config file,
|
|
181
|
+
and always save it to ``.replay`` file when recording the simulation.
|
|
178
182
|
|
|
179
183
|
.. py:attribute:: is_output
|
|
180
184
|
:type: bool
|
|
@@ -273,14 +277,14 @@ class ExecutableConfig(TypedDict):
|
|
|
273
277
|
custom_config: Optional[dict]
|
|
274
278
|
|
|
275
279
|
|
|
276
|
-
class
|
|
280
|
+
class ExecutableConfigRecord:
|
|
277
281
|
"""
|
|
278
282
|
A class to helps store configs of various executables and exports them to a file.
|
|
279
283
|
"""
|
|
280
284
|
_instance = None
|
|
281
285
|
_initialized = False
|
|
282
286
|
|
|
283
|
-
def __init__(self, save_path:
|
|
287
|
+
def __init__(self, save_path: str, include_data=False):
|
|
284
288
|
"""
|
|
285
289
|
|
|
286
290
|
:param save_path: Save path of the exported config file.
|
|
@@ -300,9 +304,8 @@ class _ExecutableConfigRecord:
|
|
|
300
304
|
self.save_path = save_path
|
|
301
305
|
self.include_data = include_data
|
|
302
306
|
|
|
303
|
-
self.work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.
|
|
307
|
+
self.work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_REPLAY)
|
|
304
308
|
self.content_path = f"{self.work_path}/config_and_data"
|
|
305
|
-
check_path(self.content_path)
|
|
306
309
|
|
|
307
310
|
self._recorded_config = []
|
|
308
311
|
self._name_count = {}
|
|
@@ -315,15 +318,20 @@ class _ExecutableConfigRecord:
|
|
|
315
318
|
|
|
316
319
|
return cls._instance
|
|
317
320
|
|
|
318
|
-
|
|
321
|
+
@classmethod
|
|
322
|
+
def reinit(cls, save_path: str, include_data=False):
|
|
319
323
|
"""
|
|
320
324
|
Reinitialize this instance.
|
|
321
325
|
|
|
326
|
+
:param save_path: Save path of the exported config file.
|
|
327
|
+
:type save_path: str
|
|
328
|
+
:param include_data: If includes input data.
|
|
329
|
+
:type include_data: bool
|
|
322
330
|
:return: New instance.
|
|
323
|
-
:rtype:
|
|
331
|
+
:rtype: ExecutableConfigRecord
|
|
324
332
|
"""
|
|
325
|
-
|
|
326
|
-
return
|
|
333
|
+
cls._initialized = False
|
|
334
|
+
return cls(save_path, include_data)
|
|
327
335
|
|
|
328
336
|
def record(self, exported_config: ExecutableConfig):
|
|
329
337
|
"""
|
|
@@ -348,7 +356,7 @@ class _ExecutableConfigRecord:
|
|
|
348
356
|
self._name_count[name] = 1
|
|
349
357
|
index = 1
|
|
350
358
|
|
|
351
|
-
data_save_uri = f"{WRFRUNConfig.
|
|
359
|
+
data_save_uri = f"{WRFRUNConfig.WRFRUN_WORKSPACE_REPLAY}/{name}/{index}"
|
|
352
360
|
data_save_path = f"{self.content_path}/{name}/{index}"
|
|
353
361
|
makedirs(data_save_path)
|
|
354
362
|
|
|
@@ -414,7 +422,25 @@ class _ExecutableConfigRecord:
|
|
|
414
422
|
logger.info(f"Replay config exported to {self.save_path}")
|
|
415
423
|
|
|
416
424
|
|
|
417
|
-
ExecConfigRecorder =
|
|
425
|
+
ExecConfigRecorder: Optional[ExecutableConfigRecord] = None
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def create_recorder(save_path: str, include_data=False) -> ExecutableConfigRecord:
|
|
429
|
+
"""
|
|
430
|
+
Create a recorder to record simulations.
|
|
431
|
+
|
|
432
|
+
:param save_path: Save path of the exported config file.
|
|
433
|
+
:type save_path: str
|
|
434
|
+
:param include_data: If includes input data.
|
|
435
|
+
:type include_data: bool
|
|
436
|
+
:return: Recorder instance.
|
|
437
|
+
:rtype: ExecutableConfigRecord
|
|
438
|
+
"""
|
|
439
|
+
global ExecConfigRecorder
|
|
440
|
+
|
|
441
|
+
ExecConfigRecorder = ExecutableConfigRecord.reinit(save_path, include_data)
|
|
442
|
+
|
|
443
|
+
return ExecConfigRecorder
|
|
418
444
|
|
|
419
445
|
|
|
420
446
|
class ExecutableBase:
|
|
@@ -585,25 +611,27 @@ class ExecutableBase:
|
|
|
585
611
|
|
|
586
612
|
You can give more information with a ``FileConfigDict``.
|
|
587
613
|
|
|
614
|
+
>>> from wrfrun.workspace.wrf import get_wrf_workspace_path
|
|
588
615
|
>>> file_dict: FileConfigDict = {
|
|
589
616
|
... "file_path": "data/custom_file.nc",
|
|
590
|
-
... "save_path":
|
|
617
|
+
... "save_path": get_wrf_workspace_path("wps"),
|
|
591
618
|
... "save_name": "custom_file.nc",
|
|
592
619
|
... "is_data": True,
|
|
593
620
|
... "is_output": False
|
|
594
621
|
... }
|
|
595
622
|
>>> self.add_input_files(file_dict)
|
|
596
623
|
|
|
624
|
+
>>> from wrfrun.workspace.wrf import get_wrf_workspace_path
|
|
597
625
|
>>> file_dict_1: FileConfigDict = {
|
|
598
626
|
... "file_path": "data/custom_file",
|
|
599
|
-
... "save_path": f"{
|
|
627
|
+
... "save_path": f"{get_wrf_workspace_path('wps')}/geogrid",
|
|
600
628
|
... "save_name": "GEOGRID.TBL",
|
|
601
629
|
... "is_data": False,
|
|
602
630
|
... "is_output": False
|
|
603
631
|
... }
|
|
604
632
|
>>> file_dict_2: FileConfigDict = {
|
|
605
633
|
... "file_path": "data/custom_file",
|
|
606
|
-
... "save_path": f"{
|
|
634
|
+
... "save_path": f"{get_wrf_workspace_path('wps')}/outputs",
|
|
607
635
|
... "save_name": "test_file",
|
|
608
636
|
... "is_data": True,
|
|
609
637
|
... "is_output": True
|
|
@@ -842,7 +870,12 @@ class ExecutableBase:
|
|
|
842
870
|
self.after_exec()
|
|
843
871
|
|
|
844
872
|
if not WRFRUNConfig.IS_IN_REPLAY and WRFRUNConfig.IS_RECORDING:
|
|
873
|
+
global ExecConfigRecorder
|
|
874
|
+
if ExecConfigRecorder is None:
|
|
875
|
+
logger.error(f"Trying to record simulation before create the recorder.")
|
|
876
|
+
raise RecordError(f"Trying to record simulation before create the recorder.")
|
|
877
|
+
|
|
845
878
|
ExecConfigRecorder.record(self.export_config())
|
|
846
879
|
|
|
847
880
|
|
|
848
|
-
__all__ = ["ExecutableBase", "FileConfigDict", "InputFileType", "ExecutableConfig", "ExecutableClassConfig", "ExecConfigRecorder"]
|
|
881
|
+
__all__ = ["ExecutableBase", "FileConfigDict", "InputFileType", "ExecutableConfig", "ExecutableClassConfig", "ExecConfigRecorder", "create_recorder"]
|