wrfrun 0.2.0__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.
Files changed (132) hide show
  1. {wrfrun-0.2.0 → wrfrun-0.3.0}/.gitignore +3 -0
  2. wrfrun-0.3.0/.python-version +1 -0
  3. wrfrun-0.3.0/PKG-INFO +240 -0
  4. wrfrun-0.3.0/README.md +211 -0
  5. {wrfrun-0.2.0 → wrfrun-0.3.0}/meson.build +2 -2
  6. {wrfrun-0.2.0 → wrfrun-0.3.0}/pyproject.toml +19 -4
  7. wrfrun-0.3.0/wrfrun/__init__.py +8 -0
  8. wrfrun-0.3.0/wrfrun/cli.py +171 -0
  9. wrfrun-0.3.0/wrfrun/core/__init__.py +55 -0
  10. wrfrun-0.3.0/wrfrun/core/_config.py +308 -0
  11. wrfrun-0.3.0/wrfrun/core/_constant.py +236 -0
  12. wrfrun-0.3.0/wrfrun/core/_exec_db.py +105 -0
  13. wrfrun-0.3.0/wrfrun/core/_namelist.py +287 -0
  14. wrfrun-0.3.0/wrfrun/core/_record.py +178 -0
  15. wrfrun-0.3.0/wrfrun/core/_resource.py +172 -0
  16. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/core/base.py +132 -406
  17. wrfrun-0.3.0/wrfrun/core/core.py +196 -0
  18. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/core/error.py +28 -2
  19. wrfrun-0.3.0/wrfrun/core/meson.build +18 -0
  20. wrfrun-0.3.0/wrfrun/core/replay.py +60 -0
  21. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/core/server.py +52 -27
  22. wrfrun-0.3.0/wrfrun/core/type.py +171 -0
  23. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/data.py +304 -139
  24. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/__init__.py +2 -2
  25. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/core.py +9 -14
  26. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/res/__init__.py +0 -1
  27. wrfrun-0.3.0/wrfrun/extension/goos_sst/utils.py +103 -0
  28. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/littler/core.py +105 -88
  29. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/utils.py +4 -3
  30. wrfrun-0.3.0/wrfrun/log.py +117 -0
  31. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/meson.build +1 -0
  32. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/__init__.py +11 -7
  33. wrfrun-0.3.0/wrfrun/model/constants.py +52 -0
  34. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/meson.build +3 -1
  35. wrfrun-0.3.0/wrfrun/model/palm/__init__.py +30 -0
  36. wrfrun-0.3.0/wrfrun/model/palm/core.py +145 -0
  37. wrfrun-0.3.0/wrfrun/model/palm/meson.build +8 -0
  38. wrfrun-0.3.0/wrfrun/model/palm/namelist.py +33 -0
  39. wrfrun-0.3.0/wrfrun/model/plot.py +257 -0
  40. wrfrun-0.3.0/wrfrun/model/type.py +116 -0
  41. wrfrun-0.3.0/wrfrun/model/utils.py +33 -0
  42. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/__init__.py +4 -9
  43. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/core.py +246 -161
  44. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/exec_wrap.py +13 -12
  45. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/geodata.py +116 -100
  46. wrfrun-0.3.0/wrfrun/model/wrf/log.py +103 -0
  47. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/meson.build +2 -0
  48. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/namelist.py +90 -73
  49. wrfrun-0.3.0/wrfrun/model/wrf/plot.py +102 -0
  50. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/scheme.py +108 -52
  51. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/utils.py +39 -25
  52. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/model/wrf/vtable.py +35 -3
  53. wrfrun-0.3.0/wrfrun/plot/__init__.py +21 -0
  54. wrfrun-0.3.0/wrfrun/plot/wps.py +213 -0
  55. wrfrun-0.3.0/wrfrun/res/__init__.py +135 -0
  56. wrfrun-0.3.0/wrfrun/res/_doc.rst +79 -0
  57. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/config/config.template.toml +8 -0
  58. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/config/meson.build +1 -0
  59. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/config/name_map.json +4 -0
  60. wrfrun-0.3.0/wrfrun/res/config/palm.template.toml +23 -0
  61. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/generate_init.py +27 -13
  62. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/run.py +105 -77
  63. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/__init__.py +1 -0
  64. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/lsf.py +3 -2
  65. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/pbs.py +3 -2
  66. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/script.py +17 -5
  67. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/slurm.py +3 -2
  68. wrfrun-0.3.0/wrfrun/scheduler/utils.py +26 -0
  69. wrfrun-0.3.0/wrfrun/utils.py +151 -0
  70. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/workspace/__init__.py +8 -5
  71. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/workspace/core.py +20 -12
  72. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/workspace/meson.build +1 -0
  73. wrfrun-0.3.0/wrfrun/workspace/palm.py +137 -0
  74. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/workspace/wrf.py +16 -15
  75. wrfrun-0.2.0/.python-version +0 -1
  76. wrfrun-0.2.0/PKG-INFO +0 -68
  77. wrfrun-0.2.0/README.md +0 -39
  78. wrfrun-0.2.0/uv.lock +0 -2443
  79. wrfrun-0.2.0/wrfrun/__init__.py +0 -3
  80. wrfrun-0.2.0/wrfrun/cli.py +0 -131
  81. wrfrun-0.2.0/wrfrun/core/__init__.py +0 -38
  82. wrfrun-0.2.0/wrfrun/core/config.py +0 -923
  83. wrfrun-0.2.0/wrfrun/core/meson.build +0 -11
  84. wrfrun-0.2.0/wrfrun/core/replay.py +0 -146
  85. wrfrun-0.2.0/wrfrun/extension/goos_sst/utils.py +0 -97
  86. wrfrun-0.2.0/wrfrun/model/base.py +0 -14
  87. wrfrun-0.2.0/wrfrun/model/plot.py +0 -277
  88. wrfrun-0.2.0/wrfrun/model/utils.py +0 -44
  89. wrfrun-0.2.0/wrfrun/model/wrf/log.py +0 -43
  90. wrfrun-0.2.0/wrfrun/model/wrf/plot.py +0 -5
  91. wrfrun-0.2.0/wrfrun/plot/__init__.py +0 -1
  92. wrfrun-0.2.0/wrfrun/plot/wps.py +0 -196
  93. wrfrun-0.2.0/wrfrun/res/__init__.py +0 -37
  94. wrfrun-0.2.0/wrfrun/scheduler/utils.py +0 -14
  95. wrfrun-0.2.0/wrfrun/utils.py +0 -262
  96. {wrfrun-0.2.0 → wrfrun-0.3.0}/.gitattributes +0 -0
  97. {wrfrun-0.2.0 → wrfrun-0.3.0}/LICENSE +0 -0
  98. {wrfrun-0.2.0 → wrfrun-0.3.0}/build.sh +0 -0
  99. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/__init__.py +0 -0
  100. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/README.md +0 -0
  101. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/meson.build +0 -0
  102. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +0 -0
  103. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/goos_sst/res/meson.build +0 -0
  104. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/littler/README.md +0 -0
  105. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/littler/__init__.py +0 -0
  106. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/littler/meson.build +0 -0
  107. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/meson.build +0 -0
  108. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/extension/micaps/README.md +0 -0
  109. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/plot/meson.build +0 -0
  110. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/README.md +0 -0
  111. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/config/wrf.template.toml +0 -0
  112. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/extension/meson.build +0 -0
  113. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/extension/name_map.json +0 -0
  114. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/extension/plotgrids.ncl +0 -0
  115. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/meson.build +0 -0
  116. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/name_map.json +0 -0
  117. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/meson.build +0 -0
  118. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/name_map.json +0 -0
  119. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.da_wrfvar.template +0 -0
  120. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.dfi.template +0 -0
  121. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.real.template +0 -0
  122. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.input.wrf.template +0 -0
  123. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/namelist.wps.template +0 -0
  124. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/namelist/parame.in.template +0 -0
  125. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/run.template.sh +0 -0
  126. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/scheduler/lsf.template +0 -0
  127. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/scheduler/meson.build +0 -0
  128. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/scheduler/name_map.json +0 -0
  129. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/scheduler/pbs.template +0 -0
  130. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/res/scheduler/slurm.template +0 -0
  131. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/env.py +0 -0
  132. {wrfrun-0.2.0 → wrfrun-0.3.0}/wrfrun/scheduler/meson.build +0 -0
@@ -22,3 +22,6 @@ test.*
22
22
  config.yaml
23
23
  main.py
24
24
  namelist.*
25
+ uv.lock
26
+
27
+ !**/namelist.py
@@ -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.
@@ -1,8 +1,8 @@
1
1
  project(
2
2
  'wrfrun',
3
3
  'c',
4
- version: '0.2.0',
5
- license: 'BSD-3',
4
+ version: '0.3.0',
5
+ license: 'GPL-3',
6
6
  meson_version: '>=0.64.0',
7
7
  default_options: ['warning_level=2'],
8
8
  )
@@ -4,7 +4,7 @@ requires = ["meson-python"]
4
4
 
5
5
  [project]
6
6
  name = "wrfrun"
7
- version = "0.2.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,8 @@
1
+ """
2
+ wrfrun
3
+ ######
4
+ """
5
+
6
+ from . import core, data, extension, model, plot, res, run, scheduler, utils, workspace
7
+
8
+ __all__ = ["core", "data", "extension", "model", "plot", "res", "run", "scheduler", "utils", "workspace"]
@@ -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"]