29 import nwpservice.wrf.real
33 DEFAULT_LOG_LEVEL = logging.DEBUG
35 LOGGER = logging.getLogger(__name__)
36 handler = logging.StreamHandler()
37 formatter = logging.Formatter(
38 '%(levelname)s - %(filename)s:%(funcName)s:%(lineno)d --> %(message)s'
40 handler.setFormatter(formatter)
41 LOGGER.addHandler(handler)
43 LOGGER.setLevel(DEFAULT_LOG_LEVEL)
49 '''Class for managing preparation and execution of real components
55 wpswrf_distro_path=None,
62 metgrid_data_dict=None,
64 log_level=DEFAULT_LOG_LEVEL,
65 bypass_namelist_input=None,
68 '''Check and initialise the class
73 wpswrf_distro_path : str
74 (Optional) Full path to the WPS/WRF distribution to be used.
75 This is assumed to have been installed in a way that is compatible
76 with the nwpservice module. If arg is not present, uses a default
79 (Optional) Full path to a directory (assumed to have already
80 been created), to be used as scratch space for setting up and
81 running this real instance. If arg is not present, uses a
83 start_time_dt : datetime
84 Time of first ungribbed file(s)
85 stop_time_dt : datetime
86 Time of last ungribbed file(s)
88 Interval (in hours) between ungribbed files
90 Number of domain nests represented in metgrid data, and in
91 the real data that will be produced
92 nests_defn_dict : dict
93 Dict of nest definitions (of use if generating namelist.input)
95 (Optional) Number of MPI tasks to use for running this instance
96 of real. If arg is not present, non-MPI execution is assumed.
97 metgrid_data_dict : dict
98 Necessary information on the metgrid files. We expect dict with
99 entries {'path' : <path>, 'filelist' : [list of metgrid files]}.
100 This implies that the metgrid files are all in the same src
103 Python logging level (e.g. logging.INFO)
104 bypass_namelist_input : str
105 This is an assumed-correct namelist.input to be used for
106 execution of real. Its presence bypasses the normal process
107 of creating a namelist.input, and puts complete trust in the
108 correctness of the provided namelist.input. If this argument
109 is present, then any values for start_time_dt, stop_time_dt,
110 hours_intvl and num_nests are ignored. This is meant primarily
111 for devtest operations, and probably shouldn't be used for
117 These are examples of the metgrid_data_dict
121 metgrid_data_dict = {
122 'path' : '/path/to/dir/with/metgrid/files'
123 'filelist' : ['met_em.d01.2022-05-14_12:00:00.nc',
124 'met_em.d01.2022-05-14_15:00:00.nc',
125 'met_em.d02.2022-05-14_12:00:00.nc',
126 'met_em.d02.2022-05-14_15:00:00.nc'
137 LOGGER.debug(
'started')
148 if bypass_namelist_input:
149 if not os.path.isfile(bypass_namelist_input):
150 raise FileNotFoundError(
'bypass_namelist_input not found: %s' %
151 bypass_namelist_input)
153 LOGGER.debug(
'bypass_namelist_input: %s' %
156 if not wpswrf_distro_path:
157 wpswrf_distro_path = DEFAULTS.wpswrf_distro_path()
161 raise FileNotFoundError(
'wpswrf_distro_path not found: %s' %
164 if not working_rootdir:
165 working_rootdir = DEFAULTS.working_scratch_rootdir()
168 raise FileNotFoundError(
'working_rootdir not found: %s' %
176 metgrid_dir = metgrid_data_dict[
'path_to_files']
177 metgrid_files = metgrid_data_dict[
'files_list']
178 for fname
in metgrid_files:
179 fpath = os.path.join(metgrid_dir, fname)
180 if not os.path.isfile(fpath):
181 raise FileNotFoundError(
'fpath: %s' % fpath)
189 raise ValueError(
"Missing num_nests arg")
191 raise ValueError(
"num_nests: %d" % num_nests)
196 expected_nest =
'd%02d' % (i+1)
198 for fname
in metgrid_files:
199 nest_str = fname[7:10]
202 if expected_nest == nest_str:
205 raise ValueError(
'Did not find nest: %s' % expected_nest)
211 raise ValueError(
'Did not find nests_defn_dict...')
219 if 1 <= num_mpi_tasks <= DEFAULTS.max_mpi_tasks():
221 mpirunpath = DEFAULTS.mpirun_path()
222 if os.path.isfile(mpirunpath)
and \
223 os.access(mpirunpath, os.X_OK):
227 raise FileNotFoundError(
'mpirun not executable: %s' %
230 raise ValueError(
'Bad num_mpi_tasks value: %d' % num_mpi_tasks)
263 '''Set up and run, via nwpservice module, instance of real
267 real_output_stagedir : str
268 (Optional) Full path to dir where real files will be staged.
269 If not specified, no staging will be done. If specified, we
270 assume the dir already exists.
275 Dictionary with manifest of the real files and the location
276 (if applicable) of staged files
280 LOGGER.debug(
'Starting run_real()...')
299 nml[
'time_control'][
'interval_seconds'] / 3600)
305 namelist_input_path =
None
306 raise NotImplementedError(
307 'namelist.input creation not yet supported')
312 LOGGER.debug(
'domainpath: %s' % domainpath)
315 nwpreal_obj = nwpservice.wrf.real.Real(
317 wpswrf_rundir=domainpath,
319 namelist_input=namelist_input_path,
320 output_dir=real_output_stagedir,
327 output_manifest = nwpreal_obj.run()
328 LOGGER.debug(
'output_manifest: %s' % output_manifest)
332 stage_success = nwpreal_obj.stage_output(auxfiles=
True)
334 staging_dir = real_output_stagedir
342 'real_output_manifest' : output_manifest,
343 'staging_dir' : staging_dir,
346 LOGGER.debug(
'return_dict: %s' % return_dict)