wrfrun 0.1.7__tar.gz → 0.1.8__tar.gz
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-0.1.7 → wrfrun-0.1.8}/.gitignore +3 -1
- {wrfrun-0.1.7 → wrfrun-0.1.8}/PKG-INFO +2 -2
- {wrfrun-0.1.7 → wrfrun-0.1.8}/meson.build +1 -1
- {wrfrun-0.1.7 → wrfrun-0.1.8}/pyproject.toml +2 -2
- wrfrun-0.1.8/wrfrun/core/__init__.py +38 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/core/base.py +241 -73
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/core/config.py +241 -122
- wrfrun-0.1.8/wrfrun/core/error.py +110 -0
- wrfrun-0.1.8/wrfrun/core/replay.py +146 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/core/server.py +75 -18
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/data.py +10 -5
- wrfrun-0.1.8/wrfrun/extension/__init__.py +29 -0
- wrfrun-0.1.8/wrfrun/extension/goos_sst/__init__.py +67 -0
- wrfrun-0.1.7/wrfrun/extension/goos_sst/goos_sst.py → wrfrun-0.1.8/wrfrun/extension/goos_sst/core.py +38 -16
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/goos_sst/meson.build +1 -1
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/meson.build +1 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/core.py +3 -3
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/namelist.py +3 -7
- wrfrun-0.1.8/wrfrun/model/wrf/plot.py +158 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/scheme.py +85 -1
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/plot/wps.py +66 -58
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/config.toml.template +3 -1
- wrfrun-0.1.7/wrfrun/core/__init__.py +0 -5
- wrfrun-0.1.7/wrfrun/core/error.py +0 -80
- wrfrun-0.1.7/wrfrun/core/replay.py +0 -113
- wrfrun-0.1.7/wrfrun/extension/__init__.py +0 -1
- wrfrun-0.1.7/wrfrun/extension/goos_sst/__init__.py +0 -3
- {wrfrun-0.1.7 → wrfrun-0.1.8}/.gitattributes +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/LICENSE +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/README.md +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/build.sh +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/core/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/goos_sst/README.md +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/goos_sst/res/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/goos_sst/res/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/goos_sst/utils.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/littler/README.md +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/littler/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/littler/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/littler/utils.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/micaps/README.md +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/extension/utils.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/base.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/plot.py +1 -1
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/utils.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/_metgrid.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/_ndown.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/exec_wrap.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/geodata.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/model/wrf/vtable.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/pbs.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/plot/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/plot/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/README.md +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/__init__.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/config.yaml.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/extension/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/extension/name_map.json +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/extension/plotgrids.ncl +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/generate_init.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/job_scheduler/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/job_scheduler/name_map.json +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/job_scheduler/pbs.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/job_scheduler/slurm.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/name_map.json +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/meson.build +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/name_map.json +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/namelist.input.da_wrfvar.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/namelist.input.dfi.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/namelist.input.real.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/namelist.input.wrf.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/namelist.wps.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/namelist/parame.in.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/res/run.sh.template +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/run.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/utils.py +0 -0
- {wrfrun-0.1.7 → wrfrun-0.1.8}/wrfrun/workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wrfrun
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: wrfrun is a comprehensive toolkit for managing and using WRF
|
|
5
5
|
Keywords: WRF
|
|
6
6
|
Author-Email: Syize <syizeliu@gmail.com>
|
|
@@ -10,7 +10,7 @@ Project-URL: homepage, https://github.com/Syize/wrfrun
|
|
|
10
10
|
Project-URL: repository, https://github.com/Syize/wrfrun
|
|
11
11
|
Project-URL: documentation, https://wrfrun.syize.cn
|
|
12
12
|
Project-URL: Bug Tracker, https://github.com/Syize/wrfrun/issues
|
|
13
|
-
Requires-Python:
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
14
|
Requires-Dist: numpy<2.0.0
|
|
15
15
|
Requires-Dist: xarray
|
|
16
16
|
Requires-Dist: netCDF4
|
|
@@ -4,10 +4,10 @@ requires = ["meson-python"]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wrfrun"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.8"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = { text = "GPL-3.0-or-later" }
|
|
10
|
-
requires-python = '
|
|
10
|
+
requires-python = '>=3.10'
|
|
11
11
|
authors = [{name = "Syize", email = "syizeliu@gmail.com"}]
|
|
12
12
|
maintainers = [
|
|
13
13
|
{ name = "Syize", email = "syizeliu@gmail.com" },
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
wrfrun.core
|
|
3
|
+
###########
|
|
4
|
+
|
|
5
|
+
The core functionalities of ``wrfrun`` are all implemented in the submodule ``wrfrun.core``,
|
|
6
|
+
such as processing namelist files, managing resource files required during model's running (e.g., VTable files),
|
|
7
|
+
calling the numerical model and process its output and log files, monitoring simulation process via model's log,
|
|
8
|
+
recording and replaying the simulation.
|
|
9
|
+
|
|
10
|
+
The functionalities are split into several submodules, which are listed in the table below.
|
|
11
|
+
|
|
12
|
+
Submodules
|
|
13
|
+
**********
|
|
14
|
+
|
|
15
|
+
================================ ========================================================
|
|
16
|
+
:doc:`base </api/core.base>` Executable base class and related classes.
|
|
17
|
+
:doc:`config </api/core.config>` ``wrfrun`` config classes.
|
|
18
|
+
:doc:`error </api/core.error>` ``wrfrun`` error classes.
|
|
19
|
+
:doc:`replay </api/core.replay>` Functions and classes to record and replay simulations.
|
|
20
|
+
:doc:`server </api/core.server>` Functions and classes to start socket server.
|
|
21
|
+
================================ ========================================================
|
|
22
|
+
|
|
23
|
+
.. toctree::
|
|
24
|
+
:maxdepth: 1
|
|
25
|
+
:hidden:
|
|
26
|
+
|
|
27
|
+
base <core.base>
|
|
28
|
+
config <core.config>
|
|
29
|
+
error <core.error>
|
|
30
|
+
replay <core.replay>
|
|
31
|
+
server <core.server>
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from .base import *
|
|
35
|
+
from .config import *
|
|
36
|
+
from .error import *
|
|
37
|
+
from .replay import *
|
|
38
|
+
from .server import *
|
|
@@ -1,4 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
wrfrun.core.base
|
|
3
|
+
################
|
|
4
|
+
|
|
5
|
+
Defines what :class:`ExecutableBase <Executable>` is, how it works and how ``wrfrun`` records simulations.
|
|
6
|
+
|
|
7
|
+
.. autosummary::
|
|
8
|
+
:toctree: generated/
|
|
9
|
+
|
|
10
|
+
check_subprocess_status
|
|
11
|
+
call_subprocess
|
|
12
|
+
InputFileType
|
|
13
|
+
FileConfigDict
|
|
14
|
+
ExecutableClassConfig
|
|
15
|
+
ExecutableConfig
|
|
16
|
+
_ExecutableConfigRecord
|
|
17
|
+
ExecutableBase
|
|
18
|
+
|
|
19
|
+
Executable
|
|
20
|
+
**********
|
|
21
|
+
|
|
22
|
+
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 a external executable file be implemented in ``wrfrun``.
|
|
24
|
+
``wrfrun`` provides a class called :class:`ExecutableBase`, which is the parent class for all ``Executable`` classes.
|
|
25
|
+
It not only provide the method to execute external programs,
|
|
26
|
+
but also:
|
|
27
|
+
|
|
28
|
+
* Store all the information about the program (e.g., its inputs and outputs, its configuration).
|
|
29
|
+
* Provide the interface to import and export ``Executable``'s config.
|
|
30
|
+
* Support the ``replay`` functionality of ``wrfrun``.
|
|
31
|
+
|
|
32
|
+
If you want to use all the ``wrfrun``'s features, you **HAVE TO** implement your code with :class:`ExecutableBase`.
|
|
33
|
+
|
|
34
|
+
ExecConfigRecorder
|
|
35
|
+
******************
|
|
36
|
+
|
|
37
|
+
To be able to record the whole simulation, ``wrfrun`` introduces the global variable ``ExecConfigRecorder``,
|
|
38
|
+
which is an instance of class :class:`_ExecutableConfigRecord`.
|
|
39
|
+
``ExecConfigRecorder`` can store the config of any ``Executable`` in the correct order and export them to a JSON file,
|
|
40
|
+
enabling the precise replay of the simulation. Depending on the internal implementation of the ``Executable``,
|
|
41
|
+
the recorded config may even include the complete namelist values, Vtable config, and more.
|
|
42
|
+
Please check :meth:`ExecutableBase.generate_custom_config` for more details.
|
|
43
|
+
"""
|
|
44
|
+
|
|
1
45
|
import subprocess
|
|
46
|
+
from copy import deepcopy
|
|
2
47
|
from enum import Enum
|
|
3
48
|
from json import dumps
|
|
4
49
|
from os import chdir, getcwd, listdir, makedirs, remove, symlink
|
|
@@ -15,7 +60,8 @@ from ..utils import check_path, logger
|
|
|
15
60
|
|
|
16
61
|
def check_subprocess_status(status: subprocess.CompletedProcess):
|
|
17
62
|
"""
|
|
18
|
-
Check subprocess return code
|
|
63
|
+
Check subprocess return code.
|
|
64
|
+
An ``RuntimeError`` exception will be raised if ``return_code != 0``, and the ``stdout`` and ``stderr`` of the subprocess will be logged.
|
|
19
65
|
|
|
20
66
|
:param status: Status from subprocess.
|
|
21
67
|
:type status: CompletedProcess
|
|
@@ -39,7 +85,7 @@ def check_subprocess_status(status: subprocess.CompletedProcess):
|
|
|
39
85
|
|
|
40
86
|
def call_subprocess(command: list[str], work_path: Optional[str] = None, print_output=False):
|
|
41
87
|
"""
|
|
42
|
-
Execute the given command in system shell.
|
|
88
|
+
Execute the given command in the system shell.
|
|
43
89
|
|
|
44
90
|
:param command: A list contains the command and parameters to be executed.
|
|
45
91
|
:type command: list
|
|
@@ -48,8 +94,6 @@ def call_subprocess(command: list[str], work_path: Optional[str] = None, print_o
|
|
|
48
94
|
:type work_path: str | None
|
|
49
95
|
:param print_output: If print standard output and error in the logger.
|
|
50
96
|
:type print_output: bool
|
|
51
|
-
:return:
|
|
52
|
-
:rtype:
|
|
53
97
|
"""
|
|
54
98
|
if work_path is not None:
|
|
55
99
|
origin_path = getcwd()
|
|
@@ -88,9 +132,21 @@ def _json_default(obj):
|
|
|
88
132
|
|
|
89
133
|
class InputFileType(Enum):
|
|
90
134
|
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
135
|
+
This class is an ``Enum`` class, providing the following values:
|
|
136
|
+
|
|
137
|
+
.. py:attribute:: WRFRUN_RES
|
|
138
|
+
:type: int
|
|
139
|
+
:value: 1
|
|
140
|
+
|
|
141
|
+
Indicating resource files are from the model or ``wrfrun``.
|
|
142
|
+
``wrfrun`` won't save these files when recording the simulation.
|
|
143
|
+
|
|
144
|
+
.. py:attribute:: CUSTOM_RES
|
|
145
|
+
:type: int
|
|
146
|
+
:value: 2
|
|
147
|
+
|
|
148
|
+
Indicating resource files are provided by the user.
|
|
149
|
+
``wrfrun`` will also save these files to ``.replay`` file when recording the simulation to ensure the simulation is replayable.
|
|
94
150
|
"""
|
|
95
151
|
WRFRUN_RES = 1
|
|
96
152
|
CUSTOM_RES = 2
|
|
@@ -98,7 +154,32 @@ class InputFileType(Enum):
|
|
|
98
154
|
|
|
99
155
|
class FileConfigDict(TypedDict):
|
|
100
156
|
"""
|
|
101
|
-
|
|
157
|
+
This dict is used to store information about the file, including its path, the path it will be copied or moved to, its new name, etc. This dict contains following keys:
|
|
158
|
+
|
|
159
|
+
.. py:attribute:: file_path
|
|
160
|
+
:type: str
|
|
161
|
+
|
|
162
|
+
A real file path or a valid URI which can be converted to a file path.
|
|
163
|
+
|
|
164
|
+
.. py:attribute:: save_path
|
|
165
|
+
:type: str
|
|
166
|
+
|
|
167
|
+
Save path of the file.
|
|
168
|
+
|
|
169
|
+
.. py:attribute:: save_name
|
|
170
|
+
:type: str
|
|
171
|
+
|
|
172
|
+
Save name of the file.
|
|
173
|
+
|
|
174
|
+
.. py:attribute:: is_data
|
|
175
|
+
:type: bool
|
|
176
|
+
|
|
177
|
+
If the file is data. If not, ``wrfrun`` will treat it as a config file, and always save it to ``.replay`` file when recording the simulation.
|
|
178
|
+
|
|
179
|
+
.. py:attribute:: is_output
|
|
180
|
+
:type: bool
|
|
181
|
+
|
|
182
|
+
If the file is model's output. Output file will never be saved to ``.replay`` file.
|
|
102
183
|
"""
|
|
103
184
|
file_path: str
|
|
104
185
|
save_path: str
|
|
@@ -109,7 +190,17 @@ class FileConfigDict(TypedDict):
|
|
|
109
190
|
|
|
110
191
|
class ExecutableClassConfig(TypedDict):
|
|
111
192
|
"""
|
|
112
|
-
|
|
193
|
+
This dict is used to store arguments of ``Executable``'s ``__init__`` function.
|
|
194
|
+
|
|
195
|
+
.. py:attribute:: class_args
|
|
196
|
+
:type: tuple
|
|
197
|
+
|
|
198
|
+
Positional arguments of the class.
|
|
199
|
+
|
|
200
|
+
.. py:attribute:: class_kwargs
|
|
201
|
+
:type: dict
|
|
202
|
+
|
|
203
|
+
Keyword arguments of the class.
|
|
113
204
|
"""
|
|
114
205
|
# only list essential config
|
|
115
206
|
class_args: tuple
|
|
@@ -118,7 +209,57 @@ class ExecutableClassConfig(TypedDict):
|
|
|
118
209
|
|
|
119
210
|
class ExecutableConfig(TypedDict):
|
|
120
211
|
"""
|
|
121
|
-
|
|
212
|
+
This dict is used to store all configs of a :class:`ExecutableBase`.
|
|
213
|
+
|
|
214
|
+
.. py:attribute:: name
|
|
215
|
+
:type: str
|
|
216
|
+
|
|
217
|
+
Name of the executable. Each type of executable has a unique name.
|
|
218
|
+
|
|
219
|
+
.. py:attribute:: cmd
|
|
220
|
+
:type: str | list[str]
|
|
221
|
+
|
|
222
|
+
Command of the executable.
|
|
223
|
+
|
|
224
|
+
.. py:attribute:: work_path
|
|
225
|
+
:type: str | None
|
|
226
|
+
|
|
227
|
+
Work path of the executable.
|
|
228
|
+
|
|
229
|
+
.. py:attribute:: mpi_use
|
|
230
|
+
:type: bool
|
|
231
|
+
|
|
232
|
+
If the executable will use MPI.
|
|
233
|
+
|
|
234
|
+
.. py:attribute:: mpi_cmd
|
|
235
|
+
:type: str | None
|
|
236
|
+
|
|
237
|
+
Command name of the MPI.
|
|
238
|
+
|
|
239
|
+
.. py:attribute:: mpi_core_num
|
|
240
|
+
:type: int | None
|
|
241
|
+
|
|
242
|
+
Number of the CPU core to use with MPI.
|
|
243
|
+
|
|
244
|
+
.. py:attribute:: class_config
|
|
245
|
+
:type: ExecutableClassConfig | None
|
|
246
|
+
|
|
247
|
+
A dict stores arguments of ``Executable``'s ``__init__`` function.
|
|
248
|
+
|
|
249
|
+
.. py:attribute:: input_file_config
|
|
250
|
+
:type: list[FileConfigDict] | None
|
|
251
|
+
|
|
252
|
+
A list stores information about input files of the executable.
|
|
253
|
+
|
|
254
|
+
.. py:attribute:: output_file_config
|
|
255
|
+
:type: list[FileConfigDict] | None
|
|
256
|
+
|
|
257
|
+
A list stores information about output files of the executable.
|
|
258
|
+
|
|
259
|
+
.. py:attribute:: custom_config
|
|
260
|
+
:type: dict | None
|
|
261
|
+
|
|
262
|
+
A dict that can be used by subclass to store other configs.
|
|
122
263
|
"""
|
|
123
264
|
name: str
|
|
124
265
|
cmd: Union[str, list[str]]
|
|
@@ -134,17 +275,16 @@ class ExecutableConfig(TypedDict):
|
|
|
134
275
|
|
|
135
276
|
class _ExecutableConfigRecord:
|
|
136
277
|
"""
|
|
137
|
-
|
|
278
|
+
A class to helps store configs of various executables and exports them to a file.
|
|
138
279
|
"""
|
|
139
280
|
_instance = None
|
|
140
281
|
_initialized = False
|
|
141
282
|
|
|
142
283
|
def __init__(self, save_path: Optional[str] = None, include_data=False):
|
|
143
284
|
"""
|
|
144
|
-
Record executable configs and export them.
|
|
145
285
|
|
|
146
286
|
:param save_path: Save path of the exported config file.
|
|
147
|
-
:type save_path: str
|
|
287
|
+
:type save_path: str | None
|
|
148
288
|
:param include_data: If includes input data.
|
|
149
289
|
:type include_data: bool
|
|
150
290
|
"""
|
|
@@ -179,8 +319,8 @@ class _ExecutableConfigRecord:
|
|
|
179
319
|
"""
|
|
180
320
|
Reinitialize this instance.
|
|
181
321
|
|
|
182
|
-
:return:
|
|
183
|
-
:rtype:
|
|
322
|
+
:return: New instance.
|
|
323
|
+
:rtype: _ExecutableConfigRecord
|
|
184
324
|
"""
|
|
185
325
|
self._initialized = False
|
|
186
326
|
return _ExecutableConfigRecord(save_path, include_data)
|
|
@@ -191,8 +331,6 @@ class _ExecutableConfigRecord:
|
|
|
191
331
|
|
|
192
332
|
:param exported_config: Executable config.
|
|
193
333
|
:type exported_config: ExecutableConfig
|
|
194
|
-
:return:
|
|
195
|
-
:rtype:
|
|
196
334
|
"""
|
|
197
335
|
if not self.include_data:
|
|
198
336
|
self._recorded_config.append(exported_config)
|
|
@@ -236,19 +374,13 @@ class _ExecutableConfigRecord:
|
|
|
236
374
|
|
|
237
375
|
def clear_records(self):
|
|
238
376
|
"""
|
|
239
|
-
Clean
|
|
240
|
-
|
|
241
|
-
:return:
|
|
242
|
-
:rtype:
|
|
377
|
+
Clean recorded configs.
|
|
243
378
|
"""
|
|
244
379
|
self._recorded_config = []
|
|
245
380
|
|
|
246
381
|
def export_replay_file(self):
|
|
247
382
|
"""
|
|
248
|
-
Save replay file to the
|
|
249
|
-
|
|
250
|
-
:return:
|
|
251
|
-
:rtype:
|
|
383
|
+
Save replay file to the save path.
|
|
252
384
|
"""
|
|
253
385
|
if len(self._recorded_config) == 0:
|
|
254
386
|
logger.warning("No replay config has been recorded.")
|
|
@@ -288,12 +420,37 @@ ExecConfigRecorder = _ExecutableConfigRecord()
|
|
|
288
420
|
class ExecutableBase:
|
|
289
421
|
"""
|
|
290
422
|
Base class for all executables.
|
|
423
|
+
|
|
424
|
+
.. py:attribute:: class_config
|
|
425
|
+
:type: ExecutableClassConfig
|
|
426
|
+
:value: {"class_args": (), "class_kwargs": {}}
|
|
427
|
+
|
|
428
|
+
A dict stores arguments of ``Executable``'s ``__init__`` function.
|
|
429
|
+
|
|
430
|
+
.. py:attribute:: custom_config
|
|
431
|
+
:type: dict
|
|
432
|
+
:value: {}
|
|
433
|
+
|
|
434
|
+
A dict that can be used by subclass to store custom configs.
|
|
435
|
+
|
|
436
|
+
.. py:attribute:: input_file_config
|
|
437
|
+
:type: list[FileConfigDict]
|
|
438
|
+
:value: []
|
|
439
|
+
|
|
440
|
+
A list stores information about input files of the executable.
|
|
441
|
+
|
|
442
|
+
.. py:attribute:: output_file_config
|
|
443
|
+
:type: list[FileConfigDict]
|
|
444
|
+
:value: []
|
|
445
|
+
|
|
446
|
+
A list stores information about output files of the executable.
|
|
447
|
+
|
|
291
448
|
"""
|
|
292
449
|
_instance = None
|
|
293
450
|
|
|
294
|
-
def __init__(self, name: str, cmd: Union[str, list[str]], work_path: str,
|
|
451
|
+
def __init__(self, name: str, cmd: Union[str, list[str]], work_path: str,
|
|
452
|
+
mpi_use=False, mpi_cmd: Optional[str] = None, mpi_core_num: Optional[int] = None):
|
|
295
453
|
"""
|
|
296
|
-
Base class for all executables.
|
|
297
454
|
|
|
298
455
|
:param name: Unique name to identify different executables.
|
|
299
456
|
:type name: str
|
|
@@ -338,19 +495,23 @@ class ExecutableBase:
|
|
|
338
495
|
|
|
339
496
|
def generate_custom_config(self):
|
|
340
497
|
"""
|
|
341
|
-
Generate custom configs.
|
|
498
|
+
Generate custom configs. This method should be overwritten in the child class,
|
|
499
|
+
and **MUST STORE THE CUSTOM CONFIG IN THE ATTRIBUTE** :attr:`ExecutableBase.custom_config`,
|
|
500
|
+
or it will do nothing except print a debug log.
|
|
342
501
|
|
|
343
|
-
|
|
344
|
-
|
|
502
|
+
You can export various configs in this method, like the complete namelist values of a NWP model binary,
|
|
503
|
+
or the path of Vtable file this executable will use.
|
|
504
|
+
|
|
505
|
+
If you overwrite this method to generate custom configs,
|
|
506
|
+
you also have to overwrite :meth:`ExecutableBase.load_custom_config` to load your custom configs.
|
|
345
507
|
"""
|
|
346
508
|
logger.debug(f"Method 'generate_custom_config' not implemented in '{self.name}'")
|
|
347
509
|
|
|
348
510
|
def load_custom_config(self):
|
|
349
511
|
"""
|
|
350
512
|
Load custom configs.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
:rtype:
|
|
513
|
+
This method should be overwritten in the child class to process the custom config stored in :attr:`ExecutableBase.custom_config`,
|
|
514
|
+
or it will do nothing except print a debug log.
|
|
354
515
|
"""
|
|
355
516
|
logger.debug(f"Method 'load_custom_config' not implemented in '{self.name}'")
|
|
356
517
|
|
|
@@ -370,20 +531,18 @@ class ExecutableBase:
|
|
|
370
531
|
"mpi_use": self.mpi_use,
|
|
371
532
|
"mpi_cmd": self.mpi_cmd,
|
|
372
533
|
"mpi_core_num": self.mpi_core_num,
|
|
373
|
-
"class_config": self.class_config,
|
|
374
|
-
"custom_config": self.custom_config,
|
|
375
|
-
"input_file_config": self.input_file_config,
|
|
376
|
-
"output_file_config": self.output_file_config
|
|
534
|
+
"class_config": deepcopy(self.class_config),
|
|
535
|
+
"custom_config": deepcopy(self.custom_config),
|
|
536
|
+
"input_file_config": deepcopy(self.input_file_config),
|
|
537
|
+
"output_file_config": deepcopy(self.output_file_config)
|
|
377
538
|
}
|
|
378
539
|
|
|
379
540
|
def load_config(self, config: ExecutableConfig):
|
|
380
541
|
"""
|
|
381
|
-
Load config from a dict.
|
|
542
|
+
Load executable config from a dict.
|
|
382
543
|
|
|
383
544
|
:param config: Config dict. It must contain some essential keys. Check ``ExecutableConfig`` for details.
|
|
384
545
|
:type config: ExecutableConfig
|
|
385
|
-
:return:
|
|
386
|
-
:rtype:
|
|
387
546
|
"""
|
|
388
547
|
if "name" not in config:
|
|
389
548
|
logger.error("A valid config is required. Please check ``ExecutableConfig``.")
|
|
@@ -398,10 +557,10 @@ class ExecutableBase:
|
|
|
398
557
|
self.mpi_use = config["mpi_use"]
|
|
399
558
|
self.mpi_cmd = config["mpi_cmd"]
|
|
400
559
|
self.mpi_core_num = config["mpi_core_num"]
|
|
401
|
-
self.class_config = config["class_config"]
|
|
402
|
-
self.custom_config = config["custom_config"]
|
|
403
|
-
self.input_file_config = config["input_file_config"]
|
|
404
|
-
self.output_file_config = config["output_file_config"]
|
|
560
|
+
self.class_config = deepcopy(config["class_config"])
|
|
561
|
+
self.custom_config = deepcopy(config["custom_config"])
|
|
562
|
+
self.input_file_config = deepcopy(config["input_file_config"])
|
|
563
|
+
self.output_file_config = deepcopy(config["output_file_config"])
|
|
405
564
|
|
|
406
565
|
self.load_custom_config()
|
|
407
566
|
|
|
@@ -409,23 +568,22 @@ class ExecutableBase:
|
|
|
409
568
|
"""
|
|
410
569
|
This method will be called when replay the simulation.
|
|
411
570
|
This method should take care every job that will be done when replaying the simulation.
|
|
412
|
-
|
|
413
|
-
:return:
|
|
414
|
-
:rtype:
|
|
571
|
+
By default, this method will call ``__call__`` method of the instance.
|
|
415
572
|
"""
|
|
416
573
|
logger.debug(f"Method 'replay' not implemented in '{self.name}', fall back to default action.")
|
|
417
574
|
self()
|
|
418
575
|
|
|
419
|
-
def add_input_files(self, input_files: Union[str, list[str], FileConfigDict, list[FileConfigDict]],
|
|
576
|
+
def add_input_files(self, input_files: Union[str, list[str], FileConfigDict, list[FileConfigDict]],
|
|
577
|
+
is_data=True, is_output=True):
|
|
420
578
|
"""
|
|
421
|
-
Add input files the
|
|
579
|
+
Add input files the executable will use.
|
|
422
580
|
|
|
423
581
|
You can give a single file path or a list contains files' path.
|
|
424
582
|
|
|
425
583
|
>>> self.add_input_files("data/custom_file")
|
|
426
584
|
>>> self.add_input_files(["data/custom_file_1", "data/custom_file_2"])
|
|
427
585
|
|
|
428
|
-
You can give more information with a ``FileConfigDict
|
|
586
|
+
You can give more information with a ``FileConfigDict``.
|
|
429
587
|
|
|
430
588
|
>>> file_dict: FileConfigDict = {
|
|
431
589
|
... "file_path": "data/custom_file.nc",
|
|
@@ -452,12 +610,14 @@ class ExecutableBase:
|
|
|
452
610
|
... }
|
|
453
611
|
>>> self.add_input_files([file_dict_1, file_dict_2])
|
|
454
612
|
|
|
455
|
-
|
|
613
|
+
Please check :class:`FileConfigDict` for more details.
|
|
614
|
+
|
|
615
|
+
:param input_files: Custom files.
|
|
456
616
|
:type input_files: str | list | dict
|
|
457
|
-
:param is_data: If
|
|
617
|
+
:param is_data: If it is a data file. This parameter will be overwritten by the value in ``input_files``.
|
|
458
618
|
:type is_data: bool
|
|
459
|
-
:
|
|
460
|
-
:
|
|
619
|
+
:param is_output: If it is an output from another executable. This parameter will be overwritten by the value in ``input_files``.
|
|
620
|
+
:type is_output: bool
|
|
461
621
|
"""
|
|
462
622
|
if isinstance(input_files, str):
|
|
463
623
|
self.input_file_config.append(
|
|
@@ -496,22 +656,39 @@ class ExecutableBase:
|
|
|
496
656
|
endswith: Union[None, str, tuple[str, ...]] = None, outputs: Union[None, str, list[str]] = None, no_file_error=True
|
|
497
657
|
):
|
|
498
658
|
"""
|
|
499
|
-
|
|
659
|
+
Find and save model's outputs to the output save path.
|
|
660
|
+
An ``OutputFileError`` exception will be raised if no file can be found and ``no_file_error==True``.
|
|
661
|
+
|
|
662
|
+
You can give the specific path of a file or multiple files.
|
|
663
|
+
|
|
664
|
+
>>> self.add_output_files(outputs="wrfout.d01")
|
|
665
|
+
>>> self.add_output_files(outputs=["wrfout.d01", "wrfout.d02"])
|
|
666
|
+
|
|
667
|
+
If you have too many outputs, but they have the same prefix or postfix, you can use ``startswith`` or ``endswith``.
|
|
668
|
+
|
|
669
|
+
>>> self.add_output_files(startswith="rsl.out.")
|
|
670
|
+
>>> self.add_output_files(endswith="log")
|
|
671
|
+
>>> self.add_output_files(startswith=("rsl", "wrfout"), endswith="log")
|
|
672
|
+
|
|
673
|
+
``startswith``, ``endswith`` and ``outputs`` can be used together.
|
|
500
674
|
|
|
501
|
-
|
|
675
|
+
``output_dir`` specify the search path of outputs, by default it is the work path of the executable.
|
|
676
|
+
You can change its value if the output path of the executable isn't its work path.
|
|
677
|
+
|
|
678
|
+
>>> self.add_output_files(output_dir=f"/absolute/dir/path", outputs=...)
|
|
679
|
+
|
|
680
|
+
:param output_dir: Search path of outputs.
|
|
502
681
|
:type output_dir: str
|
|
503
|
-
:param save_path:
|
|
682
|
+
:param save_path: New save path of outputs. By default, it is ``f"{WRFRUNConfig.WRFRUN_OUTPUT_PATH}/{self.name}"``.
|
|
504
683
|
:type save_path: str
|
|
505
684
|
:param startswith: Prefix string or prefix list of output files.
|
|
506
685
|
:type startswith: str | list
|
|
507
|
-
:param endswith: Postfix string or
|
|
686
|
+
:param endswith: Postfix string or postfix list of output files.
|
|
508
687
|
:type endswith: str | list
|
|
509
688
|
:param outputs: Files name list. All files in the list will be saved.
|
|
510
689
|
:type outputs: str | list
|
|
511
|
-
:param no_file_error: If True, an
|
|
690
|
+
:param no_file_error: If True, an OutputFileError will be raised if no output file can be found. Defaults to True.
|
|
512
691
|
:type no_file_error: bool
|
|
513
|
-
:return:
|
|
514
|
-
:rtype:
|
|
515
692
|
"""
|
|
516
693
|
if WRFRUNConfig.FAKE_SIMULATION_MODE:
|
|
517
694
|
return
|
|
@@ -567,10 +744,7 @@ class ExecutableBase:
|
|
|
567
744
|
|
|
568
745
|
def before_exec(self):
|
|
569
746
|
"""
|
|
570
|
-
Prepare input files.
|
|
571
|
-
|
|
572
|
-
:return:
|
|
573
|
-
:rtype:
|
|
747
|
+
Prepare input files before executing the external program.
|
|
574
748
|
"""
|
|
575
749
|
if WRFRUNConfig.FAKE_SIMULATION_MODE:
|
|
576
750
|
logger.info(f"We are in fake simulation mode, skip preparing input files for '{self.name}'")
|
|
@@ -603,10 +777,7 @@ class ExecutableBase:
|
|
|
603
777
|
|
|
604
778
|
def after_exec(self):
|
|
605
779
|
"""
|
|
606
|
-
Save outputs and logs.
|
|
607
|
-
|
|
608
|
-
:return:
|
|
609
|
-
:rtype:
|
|
780
|
+
Save outputs and logs after executing the external program.
|
|
610
781
|
"""
|
|
611
782
|
if WRFRUNConfig.FAKE_SIMULATION_MODE:
|
|
612
783
|
logger.info(f"We are in fake simulation mode, skip saving outputs for '{self.name}'")
|
|
@@ -639,9 +810,6 @@ class ExecutableBase:
|
|
|
639
810
|
def exec(self):
|
|
640
811
|
"""
|
|
641
812
|
Execute the given command.
|
|
642
|
-
|
|
643
|
-
:return:
|
|
644
|
-
:rtype:
|
|
645
813
|
"""
|
|
646
814
|
work_path = WRFRUNConfig.parse_resource_uri(self.work_path)
|
|
647
815
|
|
|
@@ -664,7 +832,7 @@ class ExecutableBase:
|
|
|
664
832
|
|
|
665
833
|
def __call__(self):
|
|
666
834
|
"""
|
|
667
|
-
Execute the given command
|
|
835
|
+
Execute the given command by calling ``before_exec``, ``exec`` and ``after_exec``.
|
|
668
836
|
|
|
669
837
|
:return:
|
|
670
838
|
:rtype:
|