wrfrun 0.1.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wrfrun/__init__.py +3 -0
- wrfrun/core/__init__.py +5 -0
- wrfrun/core/base.py +680 -0
- wrfrun/core/config.py +717 -0
- wrfrun/core/error.py +80 -0
- wrfrun/core/replay.py +113 -0
- wrfrun/core/server.py +212 -0
- wrfrun/data.py +418 -0
- wrfrun/extension/__init__.py +1 -0
- wrfrun/extension/littler/__init__.py +1 -0
- wrfrun/extension/littler/utils.py +599 -0
- wrfrun/extension/utils.py +66 -0
- wrfrun/model/__init__.py +7 -0
- wrfrun/model/base.py +14 -0
- wrfrun/model/plot.py +54 -0
- wrfrun/model/utils.py +34 -0
- wrfrun/model/wrf/__init__.py +6 -0
- wrfrun/model/wrf/_metgrid.py +71 -0
- wrfrun/model/wrf/_ndown.py +39 -0
- wrfrun/model/wrf/core.py +805 -0
- wrfrun/model/wrf/exec_wrap.py +101 -0
- wrfrun/model/wrf/geodata.py +301 -0
- wrfrun/model/wrf/namelist.py +377 -0
- wrfrun/model/wrf/scheme.py +311 -0
- wrfrun/model/wrf/vtable.py +65 -0
- wrfrun/pbs.py +86 -0
- wrfrun/plot/__init__.py +1 -0
- wrfrun/plot/wps.py +188 -0
- wrfrun/res/__init__.py +22 -0
- wrfrun/res/config.toml.template +136 -0
- wrfrun/res/extension/plotgrids.ncl +216 -0
- wrfrun/res/job_scheduler/pbs.template +6 -0
- wrfrun/res/job_scheduler/slurm.template +6 -0
- wrfrun/res/namelist/namelist.input.da_wrfvar.template +261 -0
- wrfrun/res/namelist/namelist.input.dfi.template +260 -0
- wrfrun/res/namelist/namelist.input.real.template +256 -0
- wrfrun/res/namelist/namelist.input.wrf.template +256 -0
- wrfrun/res/namelist/namelist.wps.template +44 -0
- wrfrun/res/namelist/parame.in.template +11 -0
- wrfrun/res/run.sh.template +16 -0
- wrfrun/run.py +264 -0
- wrfrun/utils.py +257 -0
- wrfrun/workspace.py +88 -0
- wrfrun-0.1.7.dist-info/METADATA +67 -0
- wrfrun-0.1.7.dist-info/RECORD +46 -0
- wrfrun-0.1.7.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
&time_control
|
|
2
|
+
run_days = 0
|
|
3
|
+
run_hours = 72
|
|
4
|
+
run_minutes = 0
|
|
5
|
+
run_seconds = 0
|
|
6
|
+
start_year = 2022, 2022, 2022
|
|
7
|
+
start_month = 5, 5, 5
|
|
8
|
+
start_day = 19, 19, 19
|
|
9
|
+
start_hour = 18, 18, 18
|
|
10
|
+
start_minute = 0, 0, 0
|
|
11
|
+
start_second = 0, 0, 0
|
|
12
|
+
end_year = 2022, 2022, 2022
|
|
13
|
+
end_month = 5, 5, 5
|
|
14
|
+
end_day = 22, 22, 22
|
|
15
|
+
end_hour = 18, 18, 18
|
|
16
|
+
end_minute = 0, 0, 0
|
|
17
|
+
end_second = 0, 0, 0
|
|
18
|
+
interval_seconds = 10800
|
|
19
|
+
input_from_file = .true., .true., .true.
|
|
20
|
+
fine_input_stream = 0, 0, 2
|
|
21
|
+
history_interval = 180, 180, 60
|
|
22
|
+
frames_per_outfile = 1000, 1000, 1000
|
|
23
|
+
history_outname = 'wrfout_d<domain>_<date>'
|
|
24
|
+
restart = .false.
|
|
25
|
+
restart_interval = 5000
|
|
26
|
+
override_restart_timers = .false.
|
|
27
|
+
io_form_history = 2
|
|
28
|
+
io_form_restart = 2
|
|
29
|
+
io_form_input = 2
|
|
30
|
+
io_form_boundary = 2
|
|
31
|
+
io_form_auxinput4 = 2
|
|
32
|
+
io_form_auxinput2 = 2
|
|
33
|
+
debug_level = 0
|
|
34
|
+
auxinput1_inname = './met_em.d<domain>.<date>'
|
|
35
|
+
auxinput4_inname = 'wrflowinp_d<domain>'
|
|
36
|
+
auxinput4_interval = 180, 180, 180
|
|
37
|
+
inputout_interval = 180
|
|
38
|
+
input_outname = 'wrfvar_d<domain>_<date>'
|
|
39
|
+
adjust_output_times = .true.
|
|
40
|
+
/
|
|
41
|
+
|
|
42
|
+
&domains
|
|
43
|
+
time_step = 120
|
|
44
|
+
time_step_fract_num = 0
|
|
45
|
+
time_step_fract_den = 1
|
|
46
|
+
max_dom = 2
|
|
47
|
+
time_step_dfi = 0
|
|
48
|
+
s_we = 1, 1, 1
|
|
49
|
+
e_we = 110, 151, 133
|
|
50
|
+
s_sn = 1, 1, 1
|
|
51
|
+
e_sn = 120, 181, 133
|
|
52
|
+
s_vert = 1, 1, 1
|
|
53
|
+
e_vert = 44, 44, 57
|
|
54
|
+
num_metgrid_levels = 38
|
|
55
|
+
num_metgrid_soil_levels = 3
|
|
56
|
+
p_top_requested = 5000
|
|
57
|
+
vert_refine_fact = 1
|
|
58
|
+
interp_theta = .false.
|
|
59
|
+
hypsometric_opt = 2
|
|
60
|
+
interp_type = 2
|
|
61
|
+
extrap_type = 2
|
|
62
|
+
t_extrap_type = 2
|
|
63
|
+
lowest_lev_from_sfc = .false.
|
|
64
|
+
force_sfc_in_vinterp = 1
|
|
65
|
+
use_surface = .true.
|
|
66
|
+
dx = 30000, 10000, 3333.333
|
|
67
|
+
dy = 30000, 10000, 3333.333
|
|
68
|
+
grid_id = 1, 2, 3
|
|
69
|
+
parent_id = 1, 1, 2
|
|
70
|
+
i_parent_start = 1, 35, 40
|
|
71
|
+
j_parent_start = 1, 34, 40
|
|
72
|
+
parent_grid_ratio = 1, 3, 3
|
|
73
|
+
parent_time_step_ratio = 1, 3, 4
|
|
74
|
+
feedback = 1
|
|
75
|
+
smooth_option = 2
|
|
76
|
+
nproc_x = -1
|
|
77
|
+
nproc_y = -1
|
|
78
|
+
numtiles = 6
|
|
79
|
+
use_adaptive_time_step = .false.
|
|
80
|
+
step_to_output_time = .true.
|
|
81
|
+
target_cfl = 1.1, 1.1, 1.1
|
|
82
|
+
max_step_increase_pct = 5, 51, 51
|
|
83
|
+
starting_time_step = 120, 40, 10
|
|
84
|
+
max_time_step = 240, 80, 20
|
|
85
|
+
min_time_step = 60, 20, 10
|
|
86
|
+
adaptation_domain = 1
|
|
87
|
+
/
|
|
88
|
+
|
|
89
|
+
&dfi_control
|
|
90
|
+
dfi_opt = 0
|
|
91
|
+
dfi_nfilter = 7
|
|
92
|
+
dfi_write_filtered_input = .true.
|
|
93
|
+
dfi_write_dfi_history = .false.
|
|
94
|
+
dfi_cutoff_seconds = 3600
|
|
95
|
+
dfi_time_dim = 9000
|
|
96
|
+
dfi_bckstop_year = 9991
|
|
97
|
+
dfi_bckstop_month = 9992
|
|
98
|
+
dfi_bckstop_day = 9993
|
|
99
|
+
dfi_bckstop_hour = 9994
|
|
100
|
+
dfi_bckstop_minute = 0
|
|
101
|
+
dfi_bckstop_second = 0
|
|
102
|
+
dfi_fwdstop_year = 8881
|
|
103
|
+
dfi_fwdstop_month = 8882
|
|
104
|
+
dfi_fwdstop_day = 8883
|
|
105
|
+
dfi_fwdstop_hour = 8884
|
|
106
|
+
dfi_fwdstop_minute = 30
|
|
107
|
+
dfi_fwdstop_second = 0
|
|
108
|
+
/
|
|
109
|
+
|
|
110
|
+
&physics
|
|
111
|
+
chem_opt = 0
|
|
112
|
+
mp_physics = 2, 2, 2
|
|
113
|
+
progn = 0, 0, 0
|
|
114
|
+
mp_zero_out = 2
|
|
115
|
+
mp_zero_out_thresh = 1e-08
|
|
116
|
+
do_radar_ref = 1
|
|
117
|
+
gsfcgce_hail = 0
|
|
118
|
+
gsfcgce_2ice = 0
|
|
119
|
+
no_mp_heating = 0
|
|
120
|
+
ra_lw_physics = 4, 4, 4
|
|
121
|
+
ra_sw_physics = 4, 4, 4
|
|
122
|
+
radt = 15, 15, 10
|
|
123
|
+
sf_sfclay_physics = 1, 1, 1
|
|
124
|
+
iz0tlnd = 1
|
|
125
|
+
sf_surface_physics = 2, 2, 2
|
|
126
|
+
sf_urban_physics = 1, 1, 1
|
|
127
|
+
bl_pbl_physics = 1, 1, 1
|
|
128
|
+
bl_mynn_tkeadvect = .true., .true., .true.
|
|
129
|
+
ysu_topdown_pblmix = 1
|
|
130
|
+
topo_wind = 1
|
|
131
|
+
bldt = 0, 0, 0
|
|
132
|
+
opt_thcnd = 2
|
|
133
|
+
grav_settling = 2, 2, 2
|
|
134
|
+
cu_physics = 1, 1, 0
|
|
135
|
+
ishallow = 0
|
|
136
|
+
cudt = 0, 0, 0
|
|
137
|
+
kfeta_trigger = 1
|
|
138
|
+
cu_rad_feedback = .true., .true., .true.
|
|
139
|
+
cugd_avedx = 1
|
|
140
|
+
isfflx = 1
|
|
141
|
+
ifsnow = 0
|
|
142
|
+
icloud = 3
|
|
143
|
+
surface_input_source = 1
|
|
144
|
+
num_land_cat = 21
|
|
145
|
+
num_soil_cat = 16
|
|
146
|
+
usemonalb = .true.
|
|
147
|
+
rdlai2d = .true.
|
|
148
|
+
sst_update = 1
|
|
149
|
+
num_soil_layers = 4
|
|
150
|
+
maxiens = 1
|
|
151
|
+
maxens = 3
|
|
152
|
+
maxens2 = 3
|
|
153
|
+
maxens3 = 16
|
|
154
|
+
ensdim = 144
|
|
155
|
+
slope_rad = 1
|
|
156
|
+
topo_shading = 1
|
|
157
|
+
shadlen = 25000.0
|
|
158
|
+
sf_ocean_physics = 0
|
|
159
|
+
oml_hml0 = 50
|
|
160
|
+
oml_gamma = 0.14
|
|
161
|
+
isftcflx = 0
|
|
162
|
+
fractional_seaice = 0
|
|
163
|
+
/
|
|
164
|
+
|
|
165
|
+
&fdda
|
|
166
|
+
obs_nudge_opt = 0, 0, 0
|
|
167
|
+
max_obs = 36000
|
|
168
|
+
fdda_start = 360.0, 360.0, 360.0
|
|
169
|
+
fdda_end = 99999.0, 99999.0, 99999.0
|
|
170
|
+
obs_nudge_wind = 1, 1, 1
|
|
171
|
+
obs_coef_wind = 0.0004, 0.0004, 0.0004
|
|
172
|
+
obs_nudge_temp = 1, 1, 1
|
|
173
|
+
obs_coef_temp = 0.0004, 0.0004, 0.0004
|
|
174
|
+
obs_nudge_mois = 1, 1, 1
|
|
175
|
+
obs_coef_mois = 2e-05, 2e-05, 2e-05
|
|
176
|
+
obs_rinxy = 240.0, 60.0, 180.0
|
|
177
|
+
obs_rinsig = 0.1
|
|
178
|
+
obs_twindo = 0.666667
|
|
179
|
+
obs_npfi = 10
|
|
180
|
+
obs_ionf = 2
|
|
181
|
+
obs_idynin = 0
|
|
182
|
+
obs_dtramp = 40.0
|
|
183
|
+
obs_ipf_errob = .true.
|
|
184
|
+
obs_ipf_nudob = .true.
|
|
185
|
+
obs_ipf_in4dob = .true.
|
|
186
|
+
grid_fdda = 0, 0
|
|
187
|
+
gfdda_inname = 'wrffdda_d<domain>'
|
|
188
|
+
gfdda_end_h = 72, 72
|
|
189
|
+
io_form_gfdda = 2
|
|
190
|
+
fgdt = 0, 0
|
|
191
|
+
if_no_pbl_nudging_uv = 0, 0
|
|
192
|
+
if_no_pbl_nudging_t = 1, 1
|
|
193
|
+
if_no_pbl_nudging_q = 1, 1
|
|
194
|
+
guv = 0.0004, 0.0004
|
|
195
|
+
gt = 0.0004, 0.0004
|
|
196
|
+
gq = 0.0004, 0.0004
|
|
197
|
+
if_ramping = 0
|
|
198
|
+
dtramp_min = 60
|
|
199
|
+
/
|
|
200
|
+
|
|
201
|
+
&dynamics
|
|
202
|
+
rk_ord = 3
|
|
203
|
+
w_damping = 1
|
|
204
|
+
diff_opt = 2
|
|
205
|
+
km_opt = 4
|
|
206
|
+
diff_6th_opt = 2, 2, 2
|
|
207
|
+
diff_6th_factor = 0.12, 0.12, 0.12
|
|
208
|
+
use_theta_m = 1
|
|
209
|
+
use_q_diabatic = 1
|
|
210
|
+
base_temp = 290.0
|
|
211
|
+
use_baseparam_fr_nml = .true.
|
|
212
|
+
damp_opt = 3
|
|
213
|
+
zdamp = 5000.0, 5000.0, 5000.0
|
|
214
|
+
dampcoef = 0.2, 0.2, 0.2
|
|
215
|
+
khdif = 0, 0, 0
|
|
216
|
+
kvdif = 0, 0, 0
|
|
217
|
+
non_hydrostatic = .true., .true., .true.
|
|
218
|
+
use_input_w = .true.
|
|
219
|
+
moist_adv_opt = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
220
|
+
moist_adv_dfi_opt = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
221
|
+
scalar_adv_opt = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
222
|
+
chem_adv_opt = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
223
|
+
tracer_adv_opt = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
224
|
+
tke_adv_opt = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
225
|
+
gwd_opt = 0
|
|
226
|
+
/
|
|
227
|
+
|
|
228
|
+
&bdy_control
|
|
229
|
+
spec_bdy_width = 5
|
|
230
|
+
spec_zone = 1
|
|
231
|
+
relax_zone = 4
|
|
232
|
+
specified = .true., .false., .false.
|
|
233
|
+
nested = .false., .true., .true.
|
|
234
|
+
constant_bc = .false.
|
|
235
|
+
have_bcs_moist = .false.
|
|
236
|
+
have_bcs_scalar = .false.
|
|
237
|
+
/
|
|
238
|
+
|
|
239
|
+
&tc
|
|
240
|
+
insert_bogus_storm = .false.
|
|
241
|
+
remove_storm = .false.
|
|
242
|
+
num_storm = 1
|
|
243
|
+
latc_loc = 25.0
|
|
244
|
+
lonc_loc = 127.0
|
|
245
|
+
vmax_meters_per_second = 60.0
|
|
246
|
+
rmax = 60000.0
|
|
247
|
+
vmax_ratio = 0.85
|
|
248
|
+
/
|
|
249
|
+
|
|
250
|
+
&grib2
|
|
251
|
+
/
|
|
252
|
+
|
|
253
|
+
&namelist_quilt
|
|
254
|
+
nio_tasks_per_group = 0
|
|
255
|
+
nio_groups = 1
|
|
256
|
+
/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
&share
|
|
2
|
+
wrf_core = 'ARW'
|
|
3
|
+
max_dom = 2
|
|
4
|
+
start_date = '2022-05-19_15:00:00', '2022-05-19_15:00:00', '2022-05-19_15:00:00'
|
|
5
|
+
end_date = '2022-05-22_18:00:00', '2022-05-22_18:00:00', '2022-05-22_18:00:00'
|
|
6
|
+
interval_seconds = 10800
|
|
7
|
+
io_form_geogrid = 2
|
|
8
|
+
/
|
|
9
|
+
|
|
10
|
+
&geogrid
|
|
11
|
+
parent_id = 1, 1, 2
|
|
12
|
+
parent_grid_ratio = 1, 3, 3
|
|
13
|
+
i_parent_start = 1, 35, 40
|
|
14
|
+
j_parent_start = 1, 34, 40
|
|
15
|
+
e_we = 110, 151, 133
|
|
16
|
+
e_sn = 120, 181, 133
|
|
17
|
+
geog_data_res = '10m', '2m', '30s'
|
|
18
|
+
dx = 30000
|
|
19
|
+
dy = 30000
|
|
20
|
+
map_proj = 'lambert'
|
|
21
|
+
ref_lat = 36.0
|
|
22
|
+
ref_lon = 123.0
|
|
23
|
+
truelat1 = 20.0
|
|
24
|
+
truelat2 = 50.0
|
|
25
|
+
stand_lon = 123.0
|
|
26
|
+
geog_data_path = ''
|
|
27
|
+
/
|
|
28
|
+
|
|
29
|
+
&ungrib
|
|
30
|
+
out_format = 'WPS'
|
|
31
|
+
prefix = './outputs/FILE'
|
|
32
|
+
/
|
|
33
|
+
|
|
34
|
+
&metgrid
|
|
35
|
+
fg_name = './outputs/FILE'
|
|
36
|
+
process_only_bdy = 0
|
|
37
|
+
io_form_metgrid = 2
|
|
38
|
+
opt_output_from_metgrid_path = './'
|
|
39
|
+
/
|
|
40
|
+
|
|
41
|
+
&mod_levs
|
|
42
|
+
press_pa = 201300, 200100, 100000, 92500, 85000, 70000, 60000, 50000,
|
|
43
|
+
40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000
|
|
44
|
+
/
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#PBS -q batch
|
|
3
|
+
##PBS -q odasc
|
|
4
|
+
#PBS -N py-wrfrun
|
|
5
|
+
#PBS -o {STDOUT_LOG_PATH}
|
|
6
|
+
#PBS -e {STDERR_LOG_PATH}
|
|
7
|
+
#PBS -l nodes={NODE_NUM}:ppn={CORE_NUM}
|
|
8
|
+
#PBS -l walltime=9999:00:00
|
|
9
|
+
|
|
10
|
+
ulimit -s unlimited
|
|
11
|
+
|
|
12
|
+
{ENV_SETTINGS}
|
|
13
|
+
|
|
14
|
+
cd {WORK_PATH}
|
|
15
|
+
|
|
16
|
+
{WORK_COMMAND}
|
wrfrun/run.py
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""
|
|
2
|
+
``wrfrun.run`` module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import threading
|
|
7
|
+
from os.path import abspath, dirname, exists
|
|
8
|
+
from typing import Optional, Tuple, Union
|
|
9
|
+
|
|
10
|
+
from .core import ExecConfigRecorder, WRFRUNConfig, WRFRunBasicError, WRFRunServer, WRFRunServerHandler, replay_config_generator, stop_server
|
|
11
|
+
from .data import prepare_wps_input_data
|
|
12
|
+
from .model import clear_model_logs, plot_domain_area
|
|
13
|
+
from .pbs import in_pbs, prepare_pbs_script
|
|
14
|
+
from .utils import call_subprocess, logger, logger_add_file_handler
|
|
15
|
+
from .workspace import prepare_workspace
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def confirm_model_area():
|
|
19
|
+
"""
|
|
20
|
+
Ask user to check domain area.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
plot_domain_area()
|
|
24
|
+
|
|
25
|
+
if not in_pbs():
|
|
26
|
+
# ask user
|
|
27
|
+
logger.warning(f"Check the domain image, is it right?")
|
|
28
|
+
answer = input("Is it right? [y/N]: ")
|
|
29
|
+
|
|
30
|
+
answer = answer.lower()
|
|
31
|
+
|
|
32
|
+
if answer not in ["y", "yes"]:
|
|
33
|
+
logger.error(f"Change your domain setting and run again")
|
|
34
|
+
exit(1)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class WRFRun:
|
|
38
|
+
"""
|
|
39
|
+
``WRFRun`` is a context class to use all functions in ``wrfrun`` package.
|
|
40
|
+
"""
|
|
41
|
+
_instance = None
|
|
42
|
+
_initialized = False
|
|
43
|
+
|
|
44
|
+
def __init__(self, config_file: str, init_workspace=True, start_server=False, pbs_mode=False, prepare_wps_data=False, wps_data_area: Optional[Tuple[int, int, int, int]] = None):
|
|
45
|
+
"""
|
|
46
|
+
WRFRun, a context class to achieve some goals before and after running WRF, like save a copy of config file, start and close WRFRunServer.
|
|
47
|
+
|
|
48
|
+
:param config_file: ``wrfrun`` config file's path.
|
|
49
|
+
:param init_workspace: If True, clean old files in workspace and re-create it.
|
|
50
|
+
:param start_server: Whether to start WRFRunServer, defaults to True.
|
|
51
|
+
:param pbs_mode: If commit this task to the PBS system, defaults to True.
|
|
52
|
+
:param prepare_wps_data: If True, download input datas for WPS first.
|
|
53
|
+
:param wps_data_area: If ``prepare_wps_data==True``, you need to give the area range of input data so download function can download data from ERA5.
|
|
54
|
+
:return:
|
|
55
|
+
"""
|
|
56
|
+
if self._initialized:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# variables for running WRFRunServer
|
|
60
|
+
self._start_server = start_server
|
|
61
|
+
self._wrfrun_server: Union[WRFRunServer, None] = None
|
|
62
|
+
self._wrfrun_server_thread: Union[threading.Thread, None] = None
|
|
63
|
+
self._ip = ""
|
|
64
|
+
self._port = -1
|
|
65
|
+
|
|
66
|
+
self._pbs_mode = pbs_mode
|
|
67
|
+
self._init_workspace = init_workspace
|
|
68
|
+
self._prepare_wps_data = prepare_wps_data
|
|
69
|
+
self._wps_data_area = wps_data_area
|
|
70
|
+
self._entry_file_path = abspath(sys.argv[0])
|
|
71
|
+
self._entry_file_dir_path = dirname(self._entry_file_path)
|
|
72
|
+
self._replay_configs = None
|
|
73
|
+
|
|
74
|
+
# make sure we can read the config file, because sometimes the user may run the Python script in a different path.
|
|
75
|
+
abs_config_path = f"{self._entry_file_dir_path}/{config_file}"
|
|
76
|
+
WRFRUNConfig.load_wrfrun_config(abs_config_path)
|
|
77
|
+
|
|
78
|
+
self._record_output_path = None
|
|
79
|
+
self._record_include_data = False
|
|
80
|
+
self._WRFRUNReplay = ExecConfigRecorder
|
|
81
|
+
|
|
82
|
+
self._initialized = True
|
|
83
|
+
|
|
84
|
+
def __new__(cls, *args, **kwargs):
|
|
85
|
+
if cls._instance is None:
|
|
86
|
+
cls._instance = super().__new__(cls)
|
|
87
|
+
|
|
88
|
+
return cls._instance
|
|
89
|
+
|
|
90
|
+
def __enter__(self):
|
|
91
|
+
# check workspace
|
|
92
|
+
check_list = [WRFRUNConfig.WPS_WORK_PATH, WRFRUNConfig.WRF_WORK_PATH, WRFRUNConfig.WRFDA_WORK_PATH]
|
|
93
|
+
check_list = [WRFRUNConfig.parse_resource_uri(x) for x in check_list]
|
|
94
|
+
for _path in check_list:
|
|
95
|
+
if not exists(_path) and not self._init_workspace:
|
|
96
|
+
logger.info(f"Force re-create workspace because it is broken.")
|
|
97
|
+
self._init_workspace = True
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
# here is the condition we need to initialize workspace:
|
|
101
|
+
# 1. pbs_mode = True and init_workspace = True, do prepare_workspace before committing the task to the PBS system.
|
|
102
|
+
# 2. pbs_mode = False and init_workspace = True, do prepare_workspace.
|
|
103
|
+
if self._pbs_mode and not in_pbs():
|
|
104
|
+
if self._init_workspace:
|
|
105
|
+
prepare_workspace()
|
|
106
|
+
|
|
107
|
+
# ask user before commit the task
|
|
108
|
+
confirm_model_area()
|
|
109
|
+
|
|
110
|
+
prepare_pbs_script(self._entry_file_path)
|
|
111
|
+
|
|
112
|
+
call_subprocess(["qsub", f"{self._entry_file_dir_path}/run.sh"])
|
|
113
|
+
logger.info(f"Work has been submit to PBS system")
|
|
114
|
+
exit(0)
|
|
115
|
+
|
|
116
|
+
elif not self._pbs_mode:
|
|
117
|
+
if self._init_workspace:
|
|
118
|
+
prepare_workspace()
|
|
119
|
+
|
|
120
|
+
confirm_model_area()
|
|
121
|
+
|
|
122
|
+
# save a copy of config to the output path
|
|
123
|
+
WRFRUNConfig.save_wrfrun_config(f"{WRFRUNConfig.WRFRUN_OUTPUT_PATH}/config.toml")
|
|
124
|
+
|
|
125
|
+
# check if we need to start a server
|
|
126
|
+
if self._start_server:
|
|
127
|
+
# start server
|
|
128
|
+
self._start_wrfrun_server()
|
|
129
|
+
|
|
130
|
+
# change status
|
|
131
|
+
WRFRUNConfig.set_wrfrun_context(True)
|
|
132
|
+
|
|
133
|
+
logger_add_file_handler(WRFRUNConfig.get_log_path())
|
|
134
|
+
|
|
135
|
+
if self._prepare_wps_data:
|
|
136
|
+
if self._wps_data_area is None:
|
|
137
|
+
logger.error(f"If you want wrfrun preparing data, you need to give `wps_data_area`")
|
|
138
|
+
raise ValueError(f"If you want wrfrun preparing data, you need to give `wps_data_area`")
|
|
139
|
+
else:
|
|
140
|
+
prepare_wps_input_data(self._wps_data_area)
|
|
141
|
+
|
|
142
|
+
logger.info(r"Enter wrfrun context")
|
|
143
|
+
|
|
144
|
+
return self
|
|
145
|
+
|
|
146
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
147
|
+
# stop thread if needed
|
|
148
|
+
if self._start_server:
|
|
149
|
+
stop_server(self._ip, self._port) # type: ignore
|
|
150
|
+
|
|
151
|
+
if exc_type is None and WRFRUNConfig.IS_RECORDING:
|
|
152
|
+
self._WRFRUNReplay.export_replay_file()
|
|
153
|
+
self._WRFRUNReplay.clear_records()
|
|
154
|
+
|
|
155
|
+
# change status
|
|
156
|
+
WRFRUNConfig.set_wrfrun_context(False)
|
|
157
|
+
|
|
158
|
+
clear_model_logs()
|
|
159
|
+
|
|
160
|
+
logger.info(r"Exit wrfrun context")
|
|
161
|
+
|
|
162
|
+
def _start_wrfrun_server(self):
|
|
163
|
+
"""
|
|
164
|
+
Start a WRFRunServer.
|
|
165
|
+
"""
|
|
166
|
+
# read ip and port settings from config
|
|
167
|
+
socket_ip, socket_port = WRFRUNConfig.get_socket_server_config()
|
|
168
|
+
|
|
169
|
+
# get simulate settings
|
|
170
|
+
start_date = WRFRUNConfig.get_model_config("wrf")["time"]["start_date"]
|
|
171
|
+
end_date = WRFRUNConfig.get_model_config("wrf")["time"]["end_date"]
|
|
172
|
+
|
|
173
|
+
start_date = start_date[0] if isinstance(start_date, list) else start_date
|
|
174
|
+
end_date = end_date[0] if isinstance(end_date, list) else end_date
|
|
175
|
+
|
|
176
|
+
# calculate simulate seconds
|
|
177
|
+
time_delta = end_date - start_date
|
|
178
|
+
simulate_seconds = time_delta.days * 24 * 60 * 60 + time_delta.seconds
|
|
179
|
+
|
|
180
|
+
# init server
|
|
181
|
+
self._wrfrun_server = WRFRunServer(
|
|
182
|
+
start_date, simulate_seconds, (socket_ip, socket_port),
|
|
183
|
+
WRFRunServerHandler
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# get ip and port from instance, because the port may change
|
|
187
|
+
self._ip, self._port = self._wrfrun_server.server_address
|
|
188
|
+
|
|
189
|
+
logger.info(f"Start socket server on {self._ip}:{self._port}")
|
|
190
|
+
|
|
191
|
+
# start server thread
|
|
192
|
+
self._wrfrun_server_thread = threading.Thread(
|
|
193
|
+
target=self._wrfrun_server.serve_forever
|
|
194
|
+
)
|
|
195
|
+
self._wrfrun_server_thread.daemon = True
|
|
196
|
+
self._wrfrun_server_thread.start()
|
|
197
|
+
|
|
198
|
+
def record_simulation(self, output_path: str, include_data=False):
|
|
199
|
+
"""
|
|
200
|
+
Change settings, so wrfrun can record simulation and generate a replay file.
|
|
201
|
+
|
|
202
|
+
:param output_path: Output file path.
|
|
203
|
+
:type output_path: str
|
|
204
|
+
:param include_data: If includes data.
|
|
205
|
+
:type include_data: bool
|
|
206
|
+
:return:
|
|
207
|
+
:rtype:
|
|
208
|
+
"""
|
|
209
|
+
self._record_output_path = output_path
|
|
210
|
+
self._record_include_data = include_data
|
|
211
|
+
self._WRFRUNReplay = self._WRFRUNReplay.reinit(save_path=output_path, include_data=include_data)
|
|
212
|
+
|
|
213
|
+
def replay_simulation(self, replay_file: str):
|
|
214
|
+
"""
|
|
215
|
+
Replay the simulation without any changes.
|
|
216
|
+
|
|
217
|
+
:param replay_file:
|
|
218
|
+
:type replay_file:
|
|
219
|
+
:return:
|
|
220
|
+
:rtype:
|
|
221
|
+
"""
|
|
222
|
+
WRFRUNConfig.check_wrfrun_context(True)
|
|
223
|
+
|
|
224
|
+
if self._replay_configs is not None:
|
|
225
|
+
del self._replay_configs
|
|
226
|
+
|
|
227
|
+
self._replay_configs = replay_config_generator(replay_file)
|
|
228
|
+
|
|
229
|
+
WRFRUNConfig.IS_IN_REPLAY = True
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
for _, executable in self._replay_configs:
|
|
233
|
+
executable.replay()
|
|
234
|
+
|
|
235
|
+
except WRFRunBasicError:
|
|
236
|
+
logger.error("Failed to replay the simulation")
|
|
237
|
+
|
|
238
|
+
WRFRUNConfig.IS_IN_REPLAY = False
|
|
239
|
+
|
|
240
|
+
def replay_executables(self, replay_file: str):
|
|
241
|
+
"""
|
|
242
|
+
Replay the simulation without any changes.
|
|
243
|
+
|
|
244
|
+
:param replay_file:
|
|
245
|
+
:type replay_file:
|
|
246
|
+
:return:
|
|
247
|
+
:rtype:
|
|
248
|
+
"""
|
|
249
|
+
WRFRUNConfig.check_wrfrun_context(True)
|
|
250
|
+
|
|
251
|
+
if self._replay_configs is not None:
|
|
252
|
+
del self._replay_configs
|
|
253
|
+
|
|
254
|
+
self._replay_configs = replay_config_generator(replay_file)
|
|
255
|
+
|
|
256
|
+
WRFRUNConfig.IS_IN_REPLAY = True
|
|
257
|
+
|
|
258
|
+
for name, executable in self._replay_configs:
|
|
259
|
+
yield name, executable
|
|
260
|
+
|
|
261
|
+
WRFRUNConfig.IS_IN_REPLAY = False
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
__all__ = ["WRFRun"]
|