wrfrun 0.1.9__tar.gz → 0.3.0__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.9 → wrfrun-0.3.0}/.gitignore +3 -0
- wrfrun-0.3.0/.python-version +1 -0
- wrfrun-0.3.0/PKG-INFO +240 -0
- wrfrun-0.3.0/README.md +211 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/meson.build +2 -2
- {wrfrun-0.1.9 → wrfrun-0.3.0}/pyproject.toml +19 -4
- wrfrun-0.3.0/wrfrun/__init__.py +8 -0
- wrfrun-0.3.0/wrfrun/cli.py +171 -0
- wrfrun-0.3.0/wrfrun/core/__init__.py +55 -0
- wrfrun-0.3.0/wrfrun/core/_config.py +308 -0
- wrfrun-0.3.0/wrfrun/core/_constant.py +236 -0
- wrfrun-0.3.0/wrfrun/core/_exec_db.py +105 -0
- wrfrun-0.3.0/wrfrun/core/_namelist.py +287 -0
- wrfrun-0.3.0/wrfrun/core/_record.py +178 -0
- wrfrun-0.3.0/wrfrun/core/_resource.py +172 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/core/base.py +136 -380
- wrfrun-0.3.0/wrfrun/core/core.py +196 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/core/error.py +35 -2
- wrfrun-0.3.0/wrfrun/core/meson.build +18 -0
- wrfrun-0.3.0/wrfrun/core/replay.py +60 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/core/server.py +74 -32
- wrfrun-0.3.0/wrfrun/core/type.py +171 -0
- wrfrun-0.3.0/wrfrun/data.py +586 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/__init__.py +2 -2
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/core.py +9 -14
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/res/__init__.py +0 -1
- wrfrun-0.3.0/wrfrun/extension/goos_sst/utils.py +103 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/littler/core.py +105 -88
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/utils.py +5 -3
- wrfrun-0.3.0/wrfrun/log.py +117 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/meson.build +1 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/__init__.py +11 -7
- wrfrun-0.3.0/wrfrun/model/constants.py +52 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/meson.build +3 -1
- wrfrun-0.3.0/wrfrun/model/palm/__init__.py +30 -0
- wrfrun-0.3.0/wrfrun/model/palm/core.py +145 -0
- wrfrun-0.3.0/wrfrun/model/palm/meson.build +8 -0
- wrfrun-0.3.0/wrfrun/model/palm/namelist.py +33 -0
- wrfrun-0.3.0/wrfrun/model/plot.py +257 -0
- wrfrun-0.3.0/wrfrun/model/type.py +116 -0
- wrfrun-0.3.0/wrfrun/model/utils.py +33 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/__init__.py +4 -9
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/core.py +262 -165
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/exec_wrap.py +13 -12
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/geodata.py +116 -99
- wrfrun-0.3.0/wrfrun/model/wrf/log.py +103 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/meson.build +2 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/namelist.py +92 -76
- wrfrun-0.3.0/wrfrun/model/wrf/plot.py +102 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/scheme.py +108 -52
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/utils.py +39 -24
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/model/wrf/vtable.py +42 -7
- wrfrun-0.3.0/wrfrun/plot/__init__.py +21 -0
- wrfrun-0.3.0/wrfrun/plot/wps.py +213 -0
- wrfrun-0.3.0/wrfrun/res/__init__.py +135 -0
- wrfrun-0.3.0/wrfrun/res/_doc.rst +79 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/config/config.template.toml +15 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/config/meson.build +1 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/config/name_map.json +4 -0
- wrfrun-0.3.0/wrfrun/res/config/palm.template.toml +23 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/generate_init.py +42 -13
- wrfrun-0.3.0/wrfrun/run.py +304 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/__init__.py +1 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/lsf.py +4 -1
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/pbs.py +4 -1
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/script.py +19 -5
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/slurm.py +4 -1
- wrfrun-0.3.0/wrfrun/scheduler/utils.py +26 -0
- wrfrun-0.3.0/wrfrun/utils.py +151 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/workspace/__init__.py +8 -5
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/workspace/core.py +21 -11
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/workspace/meson.build +1 -0
- wrfrun-0.3.0/wrfrun/workspace/palm.py +137 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/workspace/wrf.py +59 -14
- wrfrun-0.1.9/.python-version +0 -1
- wrfrun-0.1.9/PKG-INFO +0 -68
- wrfrun-0.1.9/README.md +0 -39
- wrfrun-0.1.9/uv.lock +0 -2443
- wrfrun-0.1.9/wrfrun/__init__.py +0 -3
- wrfrun-0.1.9/wrfrun/cli.py +0 -128
- wrfrun-0.1.9/wrfrun/core/__init__.py +0 -38
- wrfrun-0.1.9/wrfrun/core/config.py +0 -767
- wrfrun-0.1.9/wrfrun/core/meson.build +0 -11
- wrfrun-0.1.9/wrfrun/core/replay.py +0 -146
- wrfrun-0.1.9/wrfrun/data.py +0 -423
- wrfrun-0.1.9/wrfrun/extension/goos_sst/utils.py +0 -97
- wrfrun-0.1.9/wrfrun/model/base.py +0 -14
- wrfrun-0.1.9/wrfrun/model/plot.py +0 -272
- wrfrun-0.1.9/wrfrun/model/utils.py +0 -43
- wrfrun-0.1.9/wrfrun/model/wrf/log.py +0 -43
- wrfrun-0.1.9/wrfrun/model/wrf/plot.py +0 -5
- wrfrun-0.1.9/wrfrun/plot/__init__.py +0 -1
- wrfrun-0.1.9/wrfrun/plot/wps.py +0 -196
- wrfrun-0.1.9/wrfrun/res/__init__.py +0 -25
- wrfrun-0.1.9/wrfrun/run.py +0 -260
- wrfrun-0.1.9/wrfrun/scheduler/utils.py +0 -14
- wrfrun-0.1.9/wrfrun/utils.py +0 -262
- {wrfrun-0.1.9 → wrfrun-0.3.0}/.gitattributes +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/LICENSE +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/build.sh +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/__init__.py +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/README.md +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/res/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/littler/README.md +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/littler/__init__.py +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/littler/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/extension/micaps/README.md +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/plot/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/README.md +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/config/wrf.template.toml +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/extension/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/extension/name_map.json +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/extension/plotgrids.ncl +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/name_map.json +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/name_map.json +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.da_wrfvar.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.dfi.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.real.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.wrf.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.wps.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/namelist/parame.in.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/run.template.sh +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/scheduler/lsf.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/scheduler/meson.build +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/scheduler/name_map.json +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/scheduler/pbs.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/res/scheduler/slurm.template +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/env.py +0 -0
- {wrfrun-0.1.9 → wrfrun-0.3.0}/wrfrun/scheduler/meson.build +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.10
|
wrfrun-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: wrfrun
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: wrfrun is a comprehensive toolkit for managing and using WRF
|
|
5
|
+
Keywords: WRF
|
|
6
|
+
Author-Email: Syize <syizeliu@gmail.com>
|
|
7
|
+
Maintainer-Email: Syize <syizeliu@gmail.com>
|
|
8
|
+
License: GPL-3.0-or-later
|
|
9
|
+
Project-URL: homepage, https://github.com/Syize/wrfrun
|
|
10
|
+
Project-URL: repository, https://github.com/Syize/wrfrun
|
|
11
|
+
Project-URL: documentation, https://wrfrun.syize.cn
|
|
12
|
+
Project-URL: Bug Tracker, https://github.com/Syize/wrfrun/issues
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: xarray
|
|
16
|
+
Requires-Dist: netCDF4
|
|
17
|
+
Requires-Dist: rich
|
|
18
|
+
Requires-Dist: pandas
|
|
19
|
+
Requires-Dist: f90nml
|
|
20
|
+
Requires-Dist: cdsapi
|
|
21
|
+
Requires-Dist: matplotlib
|
|
22
|
+
Requires-Dist: Cartopy
|
|
23
|
+
Requires-Dist: tomli
|
|
24
|
+
Requires-Dist: tomli-w
|
|
25
|
+
Requires-Dist: haversine
|
|
26
|
+
Requires-Dist: wrf-python>=1.3.1
|
|
27
|
+
Requires-Dist: cfgrib>=0.9.15.1
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# 🌀 wrfrun
|
|
31
|
+
|
|
32
|
+
> A modern, unified framework for running and managing numerical models.
|
|
33
|
+
>
|
|
34
|
+
> Designed for researchers who want to focus on science — not on the details of model execution.
|
|
35
|
+
|
|
36
|
+
## 📖 Introduction
|
|
37
|
+
|
|
38
|
+
`wrfrun` is a Python package that provides a general-purpose, reproducible, and extensible framework for running numerical models.
|
|
39
|
+
|
|
40
|
+
It automates the tedious parts of model execution — preparing input data, handling `namelist` configurations, organizing logs, and submitting jobs — so that you can spend your time on research, not on managing model runs.
|
|
41
|
+
|
|
42
|
+
## ⚡ Quick Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install wrfrun
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 📖 Documentation
|
|
49
|
+
|
|
50
|
+
Check [https://wrfrun.syize.cn](https://wrfrun.syize.cn/).
|
|
51
|
+
|
|
52
|
+
## 🌟 Core Features
|
|
53
|
+
|
|
54
|
+
### 🧩 Unified Interface Architecture
|
|
55
|
+
|
|
56
|
+
`wrfrun` enforces a unified interface specification for all numerical models. Specifically, each model interface must inherit from a provided base class, ensuring a consistent structure and behavior across different models.
|
|
57
|
+
|
|
58
|
+
This design makes model execution intuitive — any supported model can be launched simply by calling a Python function or class method, while `wrfrun` automatically handles all background tasks such as data preparation and configuration file management.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from wrfrun import WRFRun
|
|
62
|
+
from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
|
|
63
|
+
|
|
64
|
+
# wrfrun will prepare input data, generate namelist file,
|
|
65
|
+
# save outputs and logs automatically.
|
|
66
|
+
with WRFRun("./config.toml", init_workspace=True) as wrf_run:
|
|
67
|
+
geogrid()
|
|
68
|
+
ungrib()
|
|
69
|
+
metgrid()
|
|
70
|
+
real()
|
|
71
|
+
wrf()
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 🪶 Record & Replay
|
|
75
|
+
|
|
76
|
+
Every simulation can be fully recorded and later reproduced from a single `.replay` file — ensuring total reproducibility.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from wrfrun import WRFRun
|
|
80
|
+
from wrfrun.model.wrf import geogrid, ungrib, metgrid, real, wrf
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# 1. Record simulation with method `record_simulation`.
|
|
84
|
+
with WRFRun("./config.toml", init_workspace=True) as wrf_run:
|
|
85
|
+
wrf_run.record_simulation(output_path="./outputs/example.replay")
|
|
86
|
+
|
|
87
|
+
geogrid()
|
|
88
|
+
ungrib()
|
|
89
|
+
metgrid()
|
|
90
|
+
real()
|
|
91
|
+
wrf()
|
|
92
|
+
|
|
93
|
+
# 2. Replay the simulation in a different directory or on a different machine.
|
|
94
|
+
with WRFRun("./config.toml", init_workspace=True) as wrf_run:
|
|
95
|
+
wrf_run.replay_simulation("./example.replay")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### ⚙️ Simplified Configuration
|
|
99
|
+
|
|
100
|
+
Manage all simulation settings in TOML files: A main config file, and model config files.
|
|
101
|
+
|
|
102
|
+
For more information about the configuration file, check [config](wrfrun/res/config).
|
|
103
|
+
|
|
104
|
+
```toml
|
|
105
|
+
# main config file: config.toml
|
|
106
|
+
work_dir = "./.wrfrun"
|
|
107
|
+
|
|
108
|
+
input_data_path = ""
|
|
109
|
+
output_path = "./outputs"
|
|
110
|
+
log_path = "./logs"
|
|
111
|
+
|
|
112
|
+
server_host = "localhost"
|
|
113
|
+
server_port = 54321
|
|
114
|
+
|
|
115
|
+
core_num = 36
|
|
116
|
+
|
|
117
|
+
[job_scheduler]
|
|
118
|
+
job_scheduler = "pbs"
|
|
119
|
+
|
|
120
|
+
queue_name = ""
|
|
121
|
+
node_num = 1
|
|
122
|
+
env_settings = {}
|
|
123
|
+
python_interpreter = "/usr/bin/python3" # or just "python3"
|
|
124
|
+
|
|
125
|
+
[model]
|
|
126
|
+
[model.wrf]
|
|
127
|
+
use = false
|
|
128
|
+
include = "./configs/wrf.toml"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`wrfrun` remains compatible with original `namelist` inputs, just set namelist file path in the model config.
|
|
132
|
+
|
|
133
|
+
```toml
|
|
134
|
+
# WRF model config file: wrf.toml
|
|
135
|
+
wps_path = '/path/to/your/WPS/folder'
|
|
136
|
+
wrf_path = '/path/to/your/WRF/folder'
|
|
137
|
+
wrfda_path = '' # WRFDA is optional.
|
|
138
|
+
geog_data_path = '/path/to/your/geog/data'
|
|
139
|
+
user_wps_namelist = '' # set your own namelist file here
|
|
140
|
+
user_real_namelist = '' # set your own namelist file here
|
|
141
|
+
user_wrf_namelist = '' # set your own namelist file here
|
|
142
|
+
user_wrfda_namelist = '' # set your own namelist file here
|
|
143
|
+
restart_mode = false
|
|
144
|
+
debug_level = 100
|
|
145
|
+
|
|
146
|
+
[time]
|
|
147
|
+
start_date = 2021-03-24T12:00:00Z # or [2021-03-24T12:00:00Z, 2021-03-24T12:00:00Z]
|
|
148
|
+
end_date = 2021-03-26T00:00:00Z # or [2021-03-26T00:00:00Z, 2021-03-24T12:00:00Z]
|
|
149
|
+
input_data_interval = 10800
|
|
150
|
+
output_data_interval = 180
|
|
151
|
+
time_step = 120
|
|
152
|
+
parent_time_step_ratio = [1, 3, 4]
|
|
153
|
+
restart_interval = -1
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
[domain]
|
|
157
|
+
domain_num = 3
|
|
158
|
+
parent_grid_ratio = [1, 3, 9]
|
|
159
|
+
i_parent_start = [1, 17, 72]
|
|
160
|
+
j_parent_start = [1, 17, 36]
|
|
161
|
+
e_we = [120, 250, 1198]
|
|
162
|
+
e_sn = [120, 220, 1297]
|
|
163
|
+
dx = 9000
|
|
164
|
+
dy = 9000
|
|
165
|
+
map_proj = 'lambert'
|
|
166
|
+
truelat1 = 34.0
|
|
167
|
+
truelat2 = 40.0
|
|
168
|
+
ref_lat = 37.0
|
|
169
|
+
ref_lon = 120.5
|
|
170
|
+
stand_lon = 120.5
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
[scheme]
|
|
174
|
+
long_wave_scheme = { name = "rrtm", option = {} }
|
|
175
|
+
short_wave_scheme = { name = "rrtmg", option = {} }
|
|
176
|
+
cumulus_scheme = { name = "kf", option = {} }
|
|
177
|
+
pbl_scheme = { name = "ysu", option = { ysu_topdown_pblmix = 1} }
|
|
178
|
+
land_surface_scheme = { name = "noah", option = {} }
|
|
179
|
+
surface_layer_scheme = { name = "mm5", option = {} }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 💻 Job Scheduling Integration
|
|
183
|
+
|
|
184
|
+
Automatically submit jobs to supported schedulers:
|
|
185
|
+
|
|
186
|
+
- PBS
|
|
187
|
+
- Slurm
|
|
188
|
+
- LSF
|
|
189
|
+
|
|
190
|
+
`wrfrun` takes care of resource requests and queue management automatically.
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from wrfrun import WRFRun
|
|
194
|
+
from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
|
|
195
|
+
|
|
196
|
+
# just set submit_job=True
|
|
197
|
+
with WRFRun("./config.toml", init_workspace=True, submit_job=True) as wrf_run:
|
|
198
|
+
geogrid()
|
|
199
|
+
ungrib()
|
|
200
|
+
metgrid()
|
|
201
|
+
real()
|
|
202
|
+
wrf()
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 📡 Real-time Monitoring
|
|
206
|
+
|
|
207
|
+
`wrfrun` can parse model log files and start a lightweight socket server to report simulation progress.
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from wrfrun import WRFRun
|
|
211
|
+
from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
|
|
212
|
+
|
|
213
|
+
# just set start_server=True
|
|
214
|
+
with WRFRun("./config.toml", init_workspace=True, start_server=True) as wrf_run:
|
|
215
|
+
geogrid()
|
|
216
|
+
ungrib()
|
|
217
|
+
metgrid()
|
|
218
|
+
real()
|
|
219
|
+
wrf()
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 🌍 Current Capabilities
|
|
223
|
+
|
|
224
|
+
- Automated ERA5 data download (requires `cdsapi` authentication)
|
|
225
|
+
- Real-time progress reporting via socket interface
|
|
226
|
+
- Partial WRF support:
|
|
227
|
+
- Full support for WPS
|
|
228
|
+
- Wrapped execution for `real` and `wrf`
|
|
229
|
+
- Job submission on PBS, Slurm, and LSF
|
|
230
|
+
- `record` / `replay` reproducibility for all compliant interfaces
|
|
231
|
+
|
|
232
|
+
## 🧭 TODO
|
|
233
|
+
|
|
234
|
+
- [ ] Full WRF model integration.
|
|
235
|
+
- [ ] Broaden model support.
|
|
236
|
+
- [ ] Enhanced progress visualization dashboard.
|
|
237
|
+
|
|
238
|
+
## 🤝 Contributing
|
|
239
|
+
|
|
240
|
+
This project is currently for personal and research use. If you have ideas or feature requests, feel free to open an issue.
|
wrfrun-0.3.0/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# 🌀 wrfrun
|
|
2
|
+
|
|
3
|
+
> A modern, unified framework for running and managing numerical models.
|
|
4
|
+
>
|
|
5
|
+
> Designed for researchers who want to focus on science — not on the details of model execution.
|
|
6
|
+
|
|
7
|
+
## 📖 Introduction
|
|
8
|
+
|
|
9
|
+
`wrfrun` is a Python package that provides a general-purpose, reproducible, and extensible framework for running numerical models.
|
|
10
|
+
|
|
11
|
+
It automates the tedious parts of model execution — preparing input data, handling `namelist` configurations, organizing logs, and submitting jobs — so that you can spend your time on research, not on managing model runs.
|
|
12
|
+
|
|
13
|
+
## ⚡ Quick Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install wrfrun
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 📖 Documentation
|
|
20
|
+
|
|
21
|
+
Check [https://wrfrun.syize.cn](https://wrfrun.syize.cn/).
|
|
22
|
+
|
|
23
|
+
## 🌟 Core Features
|
|
24
|
+
|
|
25
|
+
### 🧩 Unified Interface Architecture
|
|
26
|
+
|
|
27
|
+
`wrfrun` enforces a unified interface specification for all numerical models. Specifically, each model interface must inherit from a provided base class, ensuring a consistent structure and behavior across different models.
|
|
28
|
+
|
|
29
|
+
This design makes model execution intuitive — any supported model can be launched simply by calling a Python function or class method, while `wrfrun` automatically handles all background tasks such as data preparation and configuration file management.
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from wrfrun import WRFRun
|
|
33
|
+
from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
|
|
34
|
+
|
|
35
|
+
# wrfrun will prepare input data, generate namelist file,
|
|
36
|
+
# save outputs and logs automatically.
|
|
37
|
+
with WRFRun("./config.toml", init_workspace=True) as wrf_run:
|
|
38
|
+
geogrid()
|
|
39
|
+
ungrib()
|
|
40
|
+
metgrid()
|
|
41
|
+
real()
|
|
42
|
+
wrf()
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 🪶 Record & Replay
|
|
46
|
+
|
|
47
|
+
Every simulation can be fully recorded and later reproduced from a single `.replay` file — ensuring total reproducibility.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from wrfrun import WRFRun
|
|
51
|
+
from wrfrun.model.wrf import geogrid, ungrib, metgrid, real, wrf
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# 1. Record simulation with method `record_simulation`.
|
|
55
|
+
with WRFRun("./config.toml", init_workspace=True) as wrf_run:
|
|
56
|
+
wrf_run.record_simulation(output_path="./outputs/example.replay")
|
|
57
|
+
|
|
58
|
+
geogrid()
|
|
59
|
+
ungrib()
|
|
60
|
+
metgrid()
|
|
61
|
+
real()
|
|
62
|
+
wrf()
|
|
63
|
+
|
|
64
|
+
# 2. Replay the simulation in a different directory or on a different machine.
|
|
65
|
+
with WRFRun("./config.toml", init_workspace=True) as wrf_run:
|
|
66
|
+
wrf_run.replay_simulation("./example.replay")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### ⚙️ Simplified Configuration
|
|
70
|
+
|
|
71
|
+
Manage all simulation settings in TOML files: A main config file, and model config files.
|
|
72
|
+
|
|
73
|
+
For more information about the configuration file, check [config](wrfrun/res/config).
|
|
74
|
+
|
|
75
|
+
```toml
|
|
76
|
+
# main config file: config.toml
|
|
77
|
+
work_dir = "./.wrfrun"
|
|
78
|
+
|
|
79
|
+
input_data_path = ""
|
|
80
|
+
output_path = "./outputs"
|
|
81
|
+
log_path = "./logs"
|
|
82
|
+
|
|
83
|
+
server_host = "localhost"
|
|
84
|
+
server_port = 54321
|
|
85
|
+
|
|
86
|
+
core_num = 36
|
|
87
|
+
|
|
88
|
+
[job_scheduler]
|
|
89
|
+
job_scheduler = "pbs"
|
|
90
|
+
|
|
91
|
+
queue_name = ""
|
|
92
|
+
node_num = 1
|
|
93
|
+
env_settings = {}
|
|
94
|
+
python_interpreter = "/usr/bin/python3" # or just "python3"
|
|
95
|
+
|
|
96
|
+
[model]
|
|
97
|
+
[model.wrf]
|
|
98
|
+
use = false
|
|
99
|
+
include = "./configs/wrf.toml"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`wrfrun` remains compatible with original `namelist` inputs, just set namelist file path in the model config.
|
|
103
|
+
|
|
104
|
+
```toml
|
|
105
|
+
# WRF model config file: wrf.toml
|
|
106
|
+
wps_path = '/path/to/your/WPS/folder'
|
|
107
|
+
wrf_path = '/path/to/your/WRF/folder'
|
|
108
|
+
wrfda_path = '' # WRFDA is optional.
|
|
109
|
+
geog_data_path = '/path/to/your/geog/data'
|
|
110
|
+
user_wps_namelist = '' # set your own namelist file here
|
|
111
|
+
user_real_namelist = '' # set your own namelist file here
|
|
112
|
+
user_wrf_namelist = '' # set your own namelist file here
|
|
113
|
+
user_wrfda_namelist = '' # set your own namelist file here
|
|
114
|
+
restart_mode = false
|
|
115
|
+
debug_level = 100
|
|
116
|
+
|
|
117
|
+
[time]
|
|
118
|
+
start_date = 2021-03-24T12:00:00Z # or [2021-03-24T12:00:00Z, 2021-03-24T12:00:00Z]
|
|
119
|
+
end_date = 2021-03-26T00:00:00Z # or [2021-03-26T00:00:00Z, 2021-03-24T12:00:00Z]
|
|
120
|
+
input_data_interval = 10800
|
|
121
|
+
output_data_interval = 180
|
|
122
|
+
time_step = 120
|
|
123
|
+
parent_time_step_ratio = [1, 3, 4]
|
|
124
|
+
restart_interval = -1
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
[domain]
|
|
128
|
+
domain_num = 3
|
|
129
|
+
parent_grid_ratio = [1, 3, 9]
|
|
130
|
+
i_parent_start = [1, 17, 72]
|
|
131
|
+
j_parent_start = [1, 17, 36]
|
|
132
|
+
e_we = [120, 250, 1198]
|
|
133
|
+
e_sn = [120, 220, 1297]
|
|
134
|
+
dx = 9000
|
|
135
|
+
dy = 9000
|
|
136
|
+
map_proj = 'lambert'
|
|
137
|
+
truelat1 = 34.0
|
|
138
|
+
truelat2 = 40.0
|
|
139
|
+
ref_lat = 37.0
|
|
140
|
+
ref_lon = 120.5
|
|
141
|
+
stand_lon = 120.5
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
[scheme]
|
|
145
|
+
long_wave_scheme = { name = "rrtm", option = {} }
|
|
146
|
+
short_wave_scheme = { name = "rrtmg", option = {} }
|
|
147
|
+
cumulus_scheme = { name = "kf", option = {} }
|
|
148
|
+
pbl_scheme = { name = "ysu", option = { ysu_topdown_pblmix = 1} }
|
|
149
|
+
land_surface_scheme = { name = "noah", option = {} }
|
|
150
|
+
surface_layer_scheme = { name = "mm5", option = {} }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 💻 Job Scheduling Integration
|
|
154
|
+
|
|
155
|
+
Automatically submit jobs to supported schedulers:
|
|
156
|
+
|
|
157
|
+
- PBS
|
|
158
|
+
- Slurm
|
|
159
|
+
- LSF
|
|
160
|
+
|
|
161
|
+
`wrfrun` takes care of resource requests and queue management automatically.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from wrfrun import WRFRun
|
|
165
|
+
from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
|
|
166
|
+
|
|
167
|
+
# just set submit_job=True
|
|
168
|
+
with WRFRun("./config.toml", init_workspace=True, submit_job=True) as wrf_run:
|
|
169
|
+
geogrid()
|
|
170
|
+
ungrib()
|
|
171
|
+
metgrid()
|
|
172
|
+
real()
|
|
173
|
+
wrf()
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 📡 Real-time Monitoring
|
|
177
|
+
|
|
178
|
+
`wrfrun` can parse model log files and start a lightweight socket server to report simulation progress.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from wrfrun import WRFRun
|
|
182
|
+
from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
|
|
183
|
+
|
|
184
|
+
# just set start_server=True
|
|
185
|
+
with WRFRun("./config.toml", init_workspace=True, start_server=True) as wrf_run:
|
|
186
|
+
geogrid()
|
|
187
|
+
ungrib()
|
|
188
|
+
metgrid()
|
|
189
|
+
real()
|
|
190
|
+
wrf()
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 🌍 Current Capabilities
|
|
194
|
+
|
|
195
|
+
- Automated ERA5 data download (requires `cdsapi` authentication)
|
|
196
|
+
- Real-time progress reporting via socket interface
|
|
197
|
+
- Partial WRF support:
|
|
198
|
+
- Full support for WPS
|
|
199
|
+
- Wrapped execution for `real` and `wrf`
|
|
200
|
+
- Job submission on PBS, Slurm, and LSF
|
|
201
|
+
- `record` / `replay` reproducibility for all compliant interfaces
|
|
202
|
+
|
|
203
|
+
## 🧭 TODO
|
|
204
|
+
|
|
205
|
+
- [ ] Full WRF model integration.
|
|
206
|
+
- [ ] Broaden model support.
|
|
207
|
+
- [ ] Enhanced progress visualization dashboard.
|
|
208
|
+
|
|
209
|
+
## 🤝 Contributing
|
|
210
|
+
|
|
211
|
+
This project is currently for personal and research use. If you have ideas or feature requests, feel free to open an issue.
|
|
@@ -4,7 +4,7 @@ requires = ["meson-python"]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wrfrun"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = { text = "GPL-3.0-or-later" }
|
|
10
10
|
requires-python = '>=3.10'
|
|
@@ -24,11 +24,11 @@ dependencies = [
|
|
|
24
24
|
"cdsapi",
|
|
25
25
|
"matplotlib",
|
|
26
26
|
"Cartopy",
|
|
27
|
-
"wrf-python",
|
|
28
|
-
"cfgrib",
|
|
29
27
|
"tomli",
|
|
30
28
|
"tomli-w",
|
|
31
|
-
"haversine"
|
|
29
|
+
"haversine",
|
|
30
|
+
"wrf-python>=1.3.1",
|
|
31
|
+
"cfgrib>=0.9.15.1",
|
|
32
32
|
]
|
|
33
33
|
|
|
34
34
|
[project.urls]
|
|
@@ -53,4 +53,19 @@ dev = [
|
|
|
53
53
|
"sphinx-design",
|
|
54
54
|
"meson-python",
|
|
55
55
|
"sphinx-autobuild",
|
|
56
|
+
"ruff>=0.14.3",
|
|
57
|
+
"pyright>=1.1.407",
|
|
56
58
|
]
|
|
59
|
+
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 130
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint]
|
|
64
|
+
select = ["D", "E", "F", "I"]
|
|
65
|
+
ignore = ["F403", "D211", "D212", "D200", "D203", "D401", "D404", "D205", "D400", "D415"]
|
|
66
|
+
|
|
67
|
+
[tool.pyright]
|
|
68
|
+
include = ["wrfrun"]
|
|
69
|
+
pythonVersion = "3.10"
|
|
70
|
+
pythonPlatform = "Linux"
|
|
71
|
+
reportArgumentType = false
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
wrfrun.cli
|
|
3
|
+
##########
|
|
4
|
+
|
|
5
|
+
.. autosummary::
|
|
6
|
+
:toctree: generated/
|
|
7
|
+
|
|
8
|
+
main_entry
|
|
9
|
+
|
|
10
|
+
``wrfrun`` command line interface (CLI).
|
|
11
|
+
|
|
12
|
+
**This is an experimental tool, NOT BEING STABLE YET.**
|
|
13
|
+
|
|
14
|
+
After installing ``wrfrun``, you can use command ``wrfrun`` to create a simulation project.
|
|
15
|
+
Get more information by running ``wrfrun --help``.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import sys
|
|
20
|
+
from os import listdir, makedirs
|
|
21
|
+
from os.path import abspath, dirname, exists
|
|
22
|
+
from shutil import copyfile
|
|
23
|
+
|
|
24
|
+
import tomli
|
|
25
|
+
import tomli_w
|
|
26
|
+
|
|
27
|
+
from .core import WRFRunConfig
|
|
28
|
+
from .log import logger
|
|
29
|
+
from .res import CONFIG_MAIN_TOML_TEMPLATE, CONFIG_PALM_TOML_TEMPLATE, CONFIG_WRF_TOML_TEMPLATE, _register_res_uri
|
|
30
|
+
|
|
31
|
+
MODEL_MAP = {
|
|
32
|
+
"wrf": CONFIG_WRF_TOML_TEMPLATE,
|
|
33
|
+
"palm": CONFIG_PALM_TOML_TEMPLATE,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# need some mannual calls to make cli work without a config file.
|
|
37
|
+
wrfrun_config = WRFRunConfig("./.wrfrun")
|
|
38
|
+
_register_res_uri(wrfrun_config)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _entry_init(args: argparse.Namespace):
|
|
42
|
+
"""
|
|
43
|
+
Initialize a wrfrun project.
|
|
44
|
+
|
|
45
|
+
:param args: Arguments namespace.
|
|
46
|
+
:type args: argparse.Namespace
|
|
47
|
+
"""
|
|
48
|
+
configs = vars(args)
|
|
49
|
+
|
|
50
|
+
project_name = configs["name"]
|
|
51
|
+
models = configs["models"]
|
|
52
|
+
|
|
53
|
+
if project_name is None:
|
|
54
|
+
project_name = "."
|
|
55
|
+
|
|
56
|
+
if exists(project_name):
|
|
57
|
+
# we need to check if this directory isn't empty.
|
|
58
|
+
files = listdir()
|
|
59
|
+
# exclude:
|
|
60
|
+
exclude_target = [".venv", ".git", ".gitignore", ".gitattribute", "pyproject.toml", "uv.lock"]
|
|
61
|
+
files = [x for x in files if x not in exclude_target]
|
|
62
|
+
|
|
63
|
+
if len(files) != 0:
|
|
64
|
+
logger.error(f"{project_name} isn't empty, choose an empty directory, or backup and delete your files first.")
|
|
65
|
+
exit(1)
|
|
66
|
+
|
|
67
|
+
makedirs(f"{project_name}/configs")
|
|
68
|
+
makedirs(f"{project_name}/data")
|
|
69
|
+
namelist_path = f"{project_name}/namelists"
|
|
70
|
+
makedirs(namelist_path)
|
|
71
|
+
|
|
72
|
+
copyfile(wrfrun_config.parse_resource_uri(CONFIG_MAIN_TOML_TEMPLATE), f"{project_name}/config.toml")
|
|
73
|
+
|
|
74
|
+
if models is not None:
|
|
75
|
+
for _model in models:
|
|
76
|
+
src_path = wrfrun_config.parse_resource_uri(MODEL_MAP[_model])
|
|
77
|
+
copyfile(src_path, f"{project_name}/configs/{_model}.toml")
|
|
78
|
+
makedirs(f"{namelist_path}/{_model}")
|
|
79
|
+
|
|
80
|
+
logger.info(f"Created project {project_name}")
|
|
81
|
+
logger.info(f"All your configs should be placed in {project_name}/configs.")
|
|
82
|
+
logger.info(f"All your data should be placed in {project_name}/data.")
|
|
83
|
+
logger.info(f"All your namelist files should be placed in {namelist_path}")
|
|
84
|
+
logger.info(f"Make sure to set `use = True` to enable models in {project_name}/config.toml .")
|
|
85
|
+
logger.info("It is recommanded to use git to track your wrfrun and model configs.")
|
|
86
|
+
logger.info("Use command `wrfrun add MODEL_NAME` to add a new model to project.")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _entry_model(args: argparse.Namespace):
|
|
90
|
+
"""
|
|
91
|
+
Manage models used by wrfrun project.
|
|
92
|
+
|
|
93
|
+
:param args: Arguments namespace.
|
|
94
|
+
:type args: argparse.Namespace
|
|
95
|
+
"""
|
|
96
|
+
configs = vars(args)
|
|
97
|
+
new_models = configs["add"]
|
|
98
|
+
config_path = configs["config"]
|
|
99
|
+
|
|
100
|
+
if not exists(config_path):
|
|
101
|
+
logger.error(f"Can't find '{config_path}', initialize this project first.")
|
|
102
|
+
exit(1)
|
|
103
|
+
|
|
104
|
+
for _new_model in new_models:
|
|
105
|
+
if _new_model not in MODEL_MAP:
|
|
106
|
+
logger.error(f"Unknow model type: '{_new_model}'")
|
|
107
|
+
exit(1)
|
|
108
|
+
|
|
109
|
+
config_dir_path = f"{abspath(dirname(config_path))}/configs"
|
|
110
|
+
|
|
111
|
+
if not exists(config_dir_path):
|
|
112
|
+
makedirs(config_dir_path)
|
|
113
|
+
|
|
114
|
+
with open(config_path, "rb") as f:
|
|
115
|
+
main_config = tomli.load(f)
|
|
116
|
+
|
|
117
|
+
for _new_model in new_models:
|
|
118
|
+
if _new_model not in main_config["model"]:
|
|
119
|
+
main_config["model"][_new_model] = {
|
|
120
|
+
"note": (
|
|
121
|
+
"Config of this model is generated by wrfrun cli command. "
|
|
122
|
+
"DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools."
|
|
123
|
+
),
|
|
124
|
+
"use": True,
|
|
125
|
+
"include": f"./configs/{_new_model}.toml",
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
else:
|
|
129
|
+
if not ("use" in main_config["model"] and main_config["model"]["use"]):
|
|
130
|
+
main_config["model"][_new_model] = {
|
|
131
|
+
"note": (
|
|
132
|
+
"Config of this model is generated by wrfrun cli command. "
|
|
133
|
+
"DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools."
|
|
134
|
+
),
|
|
135
|
+
"use": True,
|
|
136
|
+
"include": f"./configs/{_new_model}.toml",
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for _new_model in new_models:
|
|
140
|
+
copyfile(wrfrun_config.parse_resource_uri(MODEL_MAP[_new_model]), f"{config_dir_path}/{_new_model}.toml")
|
|
141
|
+
|
|
142
|
+
with open(config_path, "wb") as f:
|
|
143
|
+
tomli_w.dump(main_config, f)
|
|
144
|
+
|
|
145
|
+
logger.info(f"Added models: {new_models}")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def main_entry():
|
|
149
|
+
"""
|
|
150
|
+
CLI entry point.
|
|
151
|
+
"""
|
|
152
|
+
args_parser = argparse.ArgumentParser()
|
|
153
|
+
subparsers = args_parser.add_subparsers(title="Subcommands", description="Valid Subcommands", help="Subcommands")
|
|
154
|
+
|
|
155
|
+
init_parser = subparsers.add_parser("init", help="Initialize a wrfrun project.", add_help=True)
|
|
156
|
+
init_parser.add_argument("-n", "--name", type=str, help="Name of the wrfrun project.")
|
|
157
|
+
init_parser.add_argument("--models", nargs="*", type=str, help="List of models to use.", choices=["wrf", "palm"])
|
|
158
|
+
init_parser.set_defaults(func=_entry_init)
|
|
159
|
+
|
|
160
|
+
model_parser = subparsers.add_parser("model", help="Manage models used by wrfrun project.", add_help=True)
|
|
161
|
+
model_parser.add_argument("-c", "--config", type=str, default="config.toml", help="Path of the main config file.")
|
|
162
|
+
model_parser.add_argument(
|
|
163
|
+
"-a", "--add", nargs="+", required=True, type=str, help="Add models to the project.", choices=["wrf", "palm"]
|
|
164
|
+
)
|
|
165
|
+
model_parser.set_defaults(func=_entry_model)
|
|
166
|
+
|
|
167
|
+
args = args_parser.parse_args(args=None if sys.argv[1:] else ["--help"])
|
|
168
|
+
args.func(args)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
__all__ = ["main_entry"]
|