wrfrun 0.2.0__tar.gz → 0.3.1__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.1}/.gitignore +3 -0
  2. wrfrun-0.3.1/.python-version +1 -0
  3. wrfrun-0.3.1/PKG-INFO +239 -0
  4. wrfrun-0.3.1/README.md +211 -0
  5. {wrfrun-0.2.0 → wrfrun-0.3.1}/meson.build +2 -2
  6. {wrfrun-0.2.0 → wrfrun-0.3.1}/pyproject.toml +18 -4
  7. wrfrun-0.3.1/wrfrun/__init__.py +8 -0
  8. wrfrun-0.3.1/wrfrun/cli.py +171 -0
  9. wrfrun-0.3.1/wrfrun/core/__init__.py +55 -0
  10. wrfrun-0.3.1/wrfrun/core/_config.py +308 -0
  11. wrfrun-0.3.1/wrfrun/core/_constant.py +236 -0
  12. wrfrun-0.3.1/wrfrun/core/_exec_db.py +105 -0
  13. wrfrun-0.3.1/wrfrun/core/_namelist.py +287 -0
  14. wrfrun-0.3.1/wrfrun/core/_record.py +178 -0
  15. wrfrun-0.3.1/wrfrun/core/_resource.py +172 -0
  16. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/core/base.py +132 -406
  17. wrfrun-0.3.1/wrfrun/core/core.py +196 -0
  18. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/core/error.py +28 -2
  19. wrfrun-0.3.1/wrfrun/core/meson.build +18 -0
  20. wrfrun-0.3.1/wrfrun/core/replay.py +60 -0
  21. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/core/server.py +52 -27
  22. wrfrun-0.3.1/wrfrun/core/type.py +171 -0
  23. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/data.py +304 -139
  24. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/__init__.py +2 -2
  25. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/core.py +9 -14
  26. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/res/__init__.py +0 -1
  27. wrfrun-0.3.1/wrfrun/extension/goos_sst/utils.py +103 -0
  28. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/littler/core.py +105 -88
  29. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/utils.py +4 -3
  30. wrfrun-0.3.1/wrfrun/log.py +117 -0
  31. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/meson.build +1 -0
  32. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/__init__.py +11 -7
  33. wrfrun-0.3.1/wrfrun/model/constants.py +52 -0
  34. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/meson.build +3 -1
  35. wrfrun-0.3.1/wrfrun/model/palm/__init__.py +30 -0
  36. wrfrun-0.3.1/wrfrun/model/palm/core.py +145 -0
  37. wrfrun-0.3.1/wrfrun/model/palm/meson.build +8 -0
  38. wrfrun-0.3.1/wrfrun/model/palm/namelist.py +33 -0
  39. wrfrun-0.3.1/wrfrun/model/plot.py +257 -0
  40. wrfrun-0.3.1/wrfrun/model/type.py +116 -0
  41. wrfrun-0.3.1/wrfrun/model/utils.py +33 -0
  42. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/__init__.py +4 -9
  43. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/core.py +246 -161
  44. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/exec_wrap.py +13 -12
  45. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/geodata.py +116 -100
  46. wrfrun-0.3.1/wrfrun/model/wrf/log.py +103 -0
  47. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/meson.build +2 -0
  48. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/namelist.py +90 -73
  49. wrfrun-0.3.1/wrfrun/model/wrf/plot.py +102 -0
  50. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/scheme.py +108 -52
  51. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/utils.py +39 -25
  52. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/model/wrf/vtable.py +35 -3
  53. wrfrun-0.3.1/wrfrun/plot/__init__.py +21 -0
  54. wrfrun-0.3.1/wrfrun/plot/wps.py +219 -0
  55. wrfrun-0.3.1/wrfrun/res/__init__.py +135 -0
  56. wrfrun-0.3.1/wrfrun/res/_doc.rst +79 -0
  57. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/config/config.template.toml +8 -0
  58. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/config/meson.build +1 -0
  59. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/config/name_map.json +4 -0
  60. wrfrun-0.3.1/wrfrun/res/config/palm.template.toml +23 -0
  61. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/generate_init.py +27 -13
  62. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/run.py +105 -77
  63. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/scheduler/__init__.py +1 -0
  64. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/scheduler/lsf.py +3 -2
  65. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/scheduler/pbs.py +3 -2
  66. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/scheduler/script.py +17 -5
  67. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/scheduler/slurm.py +3 -2
  68. wrfrun-0.3.1/wrfrun/scheduler/utils.py +26 -0
  69. wrfrun-0.3.1/wrfrun/utils.py +151 -0
  70. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/workspace/__init__.py +8 -5
  71. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/workspace/core.py +20 -12
  72. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/workspace/meson.build +1 -0
  73. wrfrun-0.3.1/wrfrun/workspace/palm.py +137 -0
  74. {wrfrun-0.2.0 → wrfrun-0.3.1}/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.1}/.gitattributes +0 -0
  97. {wrfrun-0.2.0 → wrfrun-0.3.1}/LICENSE +0 -0
  98. {wrfrun-0.2.0 → wrfrun-0.3.1}/build.sh +0 -0
  99. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/__init__.py +0 -0
  100. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/README.md +0 -0
  101. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/meson.build +0 -0
  102. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +0 -0
  103. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/goos_sst/res/meson.build +0 -0
  104. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/littler/README.md +0 -0
  105. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/littler/__init__.py +0 -0
  106. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/littler/meson.build +0 -0
  107. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/meson.build +0 -0
  108. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/extension/micaps/README.md +0 -0
  109. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/plot/meson.build +0 -0
  110. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/README.md +0 -0
  111. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/config/wrf.template.toml +0 -0
  112. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/extension/meson.build +0 -0
  113. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/extension/name_map.json +0 -0
  114. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/extension/plotgrids.ncl +0 -0
  115. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/meson.build +0 -0
  116. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/name_map.json +0 -0
  117. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/meson.build +0 -0
  118. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/name_map.json +0 -0
  119. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/namelist.input.da_wrfvar.template +0 -0
  120. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/namelist.input.dfi.template +0 -0
  121. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/namelist.input.real.template +0 -0
  122. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/namelist.input.wrf.template +0 -0
  123. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/namelist.wps.template +0 -0
  124. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/namelist/parame.in.template +0 -0
  125. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/run.template.sh +0 -0
  126. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/scheduler/lsf.template +0 -0
  127. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/scheduler/meson.build +0 -0
  128. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/scheduler/name_map.json +0 -0
  129. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/scheduler/pbs.template +0 -0
  130. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/res/scheduler/slurm.template +0 -0
  131. {wrfrun-0.2.0 → wrfrun-0.3.1}/wrfrun/scheduler/env.py +0 -0
  132. {wrfrun-0.2.0 → wrfrun-0.3.1}/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.1/PKG-INFO ADDED
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.1
2
+ Name: wrfrun
3
+ Version: 0.3.1
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: cfgrib>=0.9.15.1
27
+ Description-Content-Type: text/markdown
28
+
29
+ # 🌀 wrfrun
30
+
31
+ > A modern, unified framework for running and managing numerical models.
32
+ >
33
+ > Designed for researchers who want to focus on science — not on the details of model execution.
34
+
35
+ ## 📖 Introduction
36
+
37
+ `wrfrun` is a Python package that provides a general-purpose, reproducible, and extensible framework for running numerical models.
38
+
39
+ 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.
40
+
41
+ ## ⚡ Quick Installation
42
+
43
+ ```bash
44
+ pip install wrfrun
45
+ ```
46
+
47
+ ## 📖 Documentation
48
+
49
+ Check [https://wrfrun.syize.cn](https://wrfrun.syize.cn/).
50
+
51
+ ## 🌟 Core Features
52
+
53
+ ### 🧩 Unified Interface Architecture
54
+
55
+ `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.
56
+
57
+ 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.
58
+
59
+ ```python
60
+ from wrfrun import WRFRun
61
+ from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
62
+
63
+ # wrfrun will prepare input data, generate namelist file,
64
+ # save outputs and logs automatically.
65
+ with WRFRun("./config.toml", init_workspace=True) as wrf_run:
66
+ geogrid()
67
+ ungrib()
68
+ metgrid()
69
+ real()
70
+ wrf()
71
+ ```
72
+
73
+ ### 🪶 Record & Replay
74
+
75
+ Every simulation can be fully recorded and later reproduced from a single `.replay` file — ensuring total reproducibility.
76
+
77
+ ```python
78
+ from wrfrun import WRFRun
79
+ from wrfrun.model.wrf import geogrid, ungrib, metgrid, real, wrf
80
+
81
+
82
+ # 1. Record simulation with method `record_simulation`.
83
+ with WRFRun("./config.toml", init_workspace=True) as wrf_run:
84
+ wrf_run.record_simulation(output_path="./outputs/example.replay")
85
+
86
+ geogrid()
87
+ ungrib()
88
+ metgrid()
89
+ real()
90
+ wrf()
91
+
92
+ # 2. Replay the simulation in a different directory or on a different machine.
93
+ with WRFRun("./config.toml", init_workspace=True) as wrf_run:
94
+ wrf_run.replay_simulation("./example.replay")
95
+ ```
96
+
97
+ ### ⚙️ Simplified Configuration
98
+
99
+ Manage all simulation settings in TOML files: A main config file, and model config files.
100
+
101
+ For more information about the configuration file, check [config](wrfrun/res/config).
102
+
103
+ ```toml
104
+ # main config file: config.toml
105
+ work_dir = "./.wrfrun"
106
+
107
+ input_data_path = ""
108
+ output_path = "./outputs"
109
+ log_path = "./logs"
110
+
111
+ server_host = "localhost"
112
+ server_port = 54321
113
+
114
+ core_num = 36
115
+
116
+ [job_scheduler]
117
+ job_scheduler = "pbs"
118
+
119
+ queue_name = ""
120
+ node_num = 1
121
+ env_settings = {}
122
+ python_interpreter = "/usr/bin/python3" # or just "python3"
123
+
124
+ [model]
125
+ [model.wrf]
126
+ use = false
127
+ include = "./configs/wrf.toml"
128
+ ```
129
+
130
+ `wrfrun` remains compatible with original `namelist` inputs, just set namelist file path in the model config.
131
+
132
+ ```toml
133
+ # WRF model config file: wrf.toml
134
+ wps_path = '/path/to/your/WPS/folder'
135
+ wrf_path = '/path/to/your/WRF/folder'
136
+ wrfda_path = '' # WRFDA is optional.
137
+ geog_data_path = '/path/to/your/geog/data'
138
+ user_wps_namelist = '' # set your own namelist file here
139
+ user_real_namelist = '' # set your own namelist file here
140
+ user_wrf_namelist = '' # set your own namelist file here
141
+ user_wrfda_namelist = '' # set your own namelist file here
142
+ restart_mode = false
143
+ debug_level = 100
144
+
145
+ [time]
146
+ start_date = 2021-03-24T12:00:00Z # or [2021-03-24T12:00:00Z, 2021-03-24T12:00:00Z]
147
+ end_date = 2021-03-26T00:00:00Z # or [2021-03-26T00:00:00Z, 2021-03-24T12:00:00Z]
148
+ input_data_interval = 10800
149
+ output_data_interval = 180
150
+ time_step = 120
151
+ parent_time_step_ratio = [1, 3, 4]
152
+ restart_interval = -1
153
+
154
+
155
+ [domain]
156
+ domain_num = 3
157
+ parent_grid_ratio = [1, 3, 9]
158
+ i_parent_start = [1, 17, 72]
159
+ j_parent_start = [1, 17, 36]
160
+ e_we = [120, 250, 1198]
161
+ e_sn = [120, 220, 1297]
162
+ dx = 9000
163
+ dy = 9000
164
+ map_proj = 'lambert'
165
+ truelat1 = 34.0
166
+ truelat2 = 40.0
167
+ ref_lat = 37.0
168
+ ref_lon = 120.5
169
+ stand_lon = 120.5
170
+
171
+
172
+ [scheme]
173
+ long_wave_scheme = { name = "rrtm", option = {} }
174
+ short_wave_scheme = { name = "rrtmg", option = {} }
175
+ cumulus_scheme = { name = "kf", option = {} }
176
+ pbl_scheme = { name = "ysu", option = { ysu_topdown_pblmix = 1} }
177
+ land_surface_scheme = { name = "noah", option = {} }
178
+ surface_layer_scheme = { name = "mm5", option = {} }
179
+ ```
180
+
181
+ ### 💻 Job Scheduling Integration
182
+
183
+ Automatically submit jobs to supported schedulers:
184
+
185
+ - PBS
186
+ - Slurm
187
+ - LSF
188
+
189
+ `wrfrun` takes care of resource requests and queue management automatically.
190
+
191
+ ```python
192
+ from wrfrun import WRFRun
193
+ from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
194
+
195
+ # just set submit_job=True
196
+ with WRFRun("./config.toml", init_workspace=True, submit_job=True) as wrf_run:
197
+ geogrid()
198
+ ungrib()
199
+ metgrid()
200
+ real()
201
+ wrf()
202
+ ```
203
+
204
+ ### 📡 Real-time Monitoring
205
+
206
+ `wrfrun` can parse model log files and start a lightweight socket server to report simulation progress.
207
+
208
+ ```python
209
+ from wrfrun import WRFRun
210
+ from wrfrun.model.wrf import geogrid, metgrid, real, ungrib, wrf
211
+
212
+ # just set start_server=True
213
+ with WRFRun("./config.toml", init_workspace=True, start_server=True) as wrf_run:
214
+ geogrid()
215
+ ungrib()
216
+ metgrid()
217
+ real()
218
+ wrf()
219
+ ```
220
+
221
+ ## 🌍 Current Capabilities
222
+
223
+ - Automated ERA5 data download (requires `cdsapi` authentication)
224
+ - Real-time progress reporting via socket interface
225
+ - Partial WRF support:
226
+ - Full support for WPS
227
+ - Wrapped execution for `real` and `wrf`
228
+ - Job submission on PBS, Slurm, and LSF
229
+ - `record` / `replay` reproducibility for all compliant interfaces
230
+
231
+ ## 🧭 TODO
232
+
233
+ - [ ] Full WRF model integration.
234
+ - [ ] Broaden model support.
235
+ - [ ] Enhanced progress visualization dashboard.
236
+
237
+ ## 🤝 Contributing
238
+
239
+ 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.1/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.1',
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.1"
8
8
  readme = "README.md"
9
9
  license = { text = "GPL-3.0-or-later" }
10
10
  requires-python = '>=3.10'
@@ -24,11 +24,10 @@ 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
+ "cfgrib>=0.9.15.1",
32
31
  ]
33
32
 
34
33
  [project.urls]
@@ -53,4 +52,19 @@ dev = [
53
52
  "sphinx-design",
54
53
  "meson-python",
55
54
  "sphinx-autobuild",
55
+ "ruff>=0.14.3",
56
+ "pyright>=1.1.407",
56
57
  ]
58
+
59
+ [tool.ruff]
60
+ line-length = 130
61
+
62
+ [tool.ruff.lint]
63
+ select = ["D", "E", "F", "I"]
64
+ ignore = ["F403", "D211", "D212", "D200", "D203", "D401", "D404", "D205", "D400", "D415"]
65
+
66
+ [tool.pyright]
67
+ include = ["wrfrun"]
68
+ pythonVersion = "3.10"
69
+ pythonPlatform = "Linux"
70
+ 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"]