def run_wrfplus_ad(work_root, wrfplus_root, config, args): start_time = config['custom']['start_time'] end_time = config['custom']['end_time'] datetime_fmt = 'YYYY-MM-DD_HH:mm:ss' start_time_str = start_time.format(datetime_fmt) max_dom = config['domains']['max_dom'] wrf_work_dir = os.path.abspath(work_root) + '/wrf' if not os.path.isdir(wrf_work_dir): cli.error(f'WRF work directory {wrf_work_dir} does not exist!') wrfplus_work_dir = os.path.abspath(work_root) + '/wrfplus' if not os.path.isdir(wrfplus_work_dir): cli.error(f'WRFPLUS has not been configured! Run config_wrfplus.py first.') os.chdir(wrfplus_work_dir) if os.path.isfile(f'{wrf_work_dir}/wrfinput_d01_{start_time_str}'): run(f'ln -sf {wrf_work_dir}/wrfinput_d01 .') elif os.path.isfile(f'{wrf_work_dir}/wrfout_d01_{start_time_str}'): run(f'ln -sf {wrf_work_dir}/wrfout_d01_{start_time_str} wrfinput_d01') run(f'ln -sf {wrf_work_dir}/wrfbdy_d01 .') if not os.path.isfile('final_sens_d01'): cli.error('There is no final_sens_d01 file!') version = wrf_version(wrfplus_root) cli.stage(f'Run WRFPLUS at {wrfplus_work_dir} ...') expected_files = ['wrfout_d{:02d}_{}'.format(i + 1, start_time_str) for i in range(max_dom)] expected_files.append(f'init_sens_d01_{start_time_str}') if not check_files(expected_files) or args.force: run('rm -f wrfout_*') run(f'ln -sf {wrfplus_root}/run/LANDUSE.TBL .') run(f'ln -sf {wrfplus_root}/run/VEGPARM.TBL .') run(f'ln -sf {wrfplus_root}/run/SOILPARM.TBL .') run(f'ln -sf {wrfplus_root}/run/GENPARM.TBL .') run(f'ln -sf {wrfplus_root}/run/RRTM_DATA_DBL RRTM_DATA') run(f'ln -sf {wrfplus_root}/run/ETAMPNEW_DATA_DBL ETAMPNEW_DATA') if version >= Version('4.0'): cmd = f'{wrfplus_root}/run/wrfplus.exe' else: cmd = f'{wrfplus_root}/run/wrf.exe' retries = 0 while True: submit_job(cmd, args.np, config, args, wait=True) if os.path.isfile(f'gradient_wrfplus_d01_{start_time_str}'): run(f'mv gradient_wrfplus_d01_{start_time_str} init_sens_d01_{start_time_str}') if not check_files(expected_files): if retries == 10: cli.error(f'Failed! Check output {os.path.abspath(wrfplus_work_dir)}/rsl.error.0000.') retries = retries + 1 cli.warning('Failed to run wrfplus, retry it!') else: break cli.notice('Succeeded.') else: cli.notice('File wrfout_* already exist.') run(f'ls -l {wrfplus_work_dir}/wrfout_*')
def config_wps(work_root, wps_root, geog_root, config, args): if has_key(config, ('custom', 'start_time')): start_time = config['custom']['start_time'] start_time_str = start_time.format('YYYY-MM-DD_HH:mm:ss') if not has_key(config, ('custom', 'end_time')): cli.error('custom->end_time does not exist in config file!') end_time = config['custom']['end_time'] end_time_str = end_time.format('YYYY-MM-DD_HH:mm:ss') if not has_key(config, ('domains', 'max_dom')): cli.error('domains->max_dom does not exist in config file!') max_dom = config['domains']['max_dom'] wps_work_dir = work_root + '/wps' if not os.path.isdir(wps_work_dir): os.makedirs(wps_work_dir) os.chdir(wps_work_dir) version = wrf_version(wps_root) if version < Version('3.9.1'): cli.error( f'WPS {version} may not handle GFS data correctly! Please use WPS >= 3.9.1.' ) cli.notice('Edit namelist.wps for WPS.') copy(f'{wps_root}/namelist.wps', 'namelist.wps') namelist_wps = f90nml.read('namelist.wps') namelist_wps['share']['max_dom'] = max_dom if has_key(config, ('custom', 'start_time')): namelist_wps['share']['start_date'] = [ start_time_str for i in range(max_dom) ] if has_key(config, ('custom', 'end_time')): namelist_wps['share']['end_date'] = [ end_time_str if i == 0 else start_time_str for i in range(max_dom) ] if has_key(config, ('custom', 'background')) and has_key( config, ('custom', 'background', 'interval_seconds')): namelist_wps['share']['interval_seconds'] = config['custom'][ 'background']['interval_seconds'] namelist_wps['geogrid']['geog_data_path'] = geog_root for key, value in config['geogrid'].items(): namelist_wps['geogrid'][key] = value namelist_wps['geogrid']['opt_geogrid_tbl_path'] = wps_work_dir namelist_wps['metgrid']['opt_metgrid_tbl_path'] = wps_work_dir if 'metgrid' in config: for key, value in config['metgrid'].items(): namelist_wps['metgrid'][key] = value namelist_wps.write('./namelist.wps', force=True) run(f'ncl -Q {script_root}/../plots/plot_domains.ncl') cli.notice(f'Check {wps_work_dir}/wps_show_dom.pdf for domains.') cli.notice('Succeeded.')
def config_wrf(work_root, wrf_root, wrfda_root, config, args, tag=None): phys_config = config['physics'] if 'physics' in config else {} start_time = config['custom']['start_time'] end_time = config['custom']['end_time'] max_dom = config['domains']['max_dom'] start_time_str = start_time.format('YYYY-MM-DD_HH:mm:ss') end_time_str = end_time.format('YYYY-MM-DD_HH:mm:ss') if tag != None: wrf_work_dir = f'{work_root}/wrf_{tag}' else: wrf_work_dir = f'{work_root}/wrf' if not os.path.isdir(wrf_work_dir): os.mkdir(wrf_work_dir) os.chdir(wrf_work_dir) version = wrf_version(wrf_root) if os.path.isfile(f'{wrf_work_dir}/wrfinput_d01_{start_time_str}'): num_land_cat = get_num_land_cat( f'{wrf_work_dir}/wrfinput_d01_{start_time_str}') elif os.path.isfile(f'{wrf_work_dir}/wrfinput_d01'): num_land_cat = get_num_land_cat(f'{wrf_work_dir}/wrfinput_d01') elif os.path.isfile(f'{wrf_work_dir}/wrfout_d01_{start_time_str}'): num_land_cat = get_num_land_cat( f'{wrf_work_dir}/wrfout_d01_{start_time_str}') else: cli.warning( f'Cannot get num_land_cat parameter from an existing wrfinput_d01 file in {wrf_work_dir}!' ) num_land_cat = None cli.notice('Edit namelist.input for WRF.') copy(f'{wrf_root}/run/namelist.input', 'namelist.input') namelist_input = f90nml.read('namelist.input') namelist_input['time_control']['run_hours'] = config['custom'][ 'forecast_hours'] namelist_input['time_control']['start_year'] = [ int(start_time.format("Y")) for i in range(max_dom) ] namelist_input['time_control']['start_month'] = [ int(start_time.format("M")) for i in range(max_dom) ] namelist_input['time_control']['start_day'] = [ int(start_time.format("D")) for i in range(max_dom) ] namelist_input['time_control']['start_hour'] = [ int(start_time.format("H")) for i in range(max_dom) ] namelist_input['time_control']['end_year'] = [ int(end_time.format("Y")) for i in range(max_dom) ] namelist_input['time_control']['end_month'] = [ int(end_time.format("M")) for i in range(max_dom) ] namelist_input['time_control']['end_day'] = [ int(end_time.format("D")) for i in range(max_dom) ] namelist_input['time_control']['end_hour'] = [ int(end_time.format("H")) for i in range(max_dom) ] namelist_input['time_control']['frames_per_outfile'] = [ 1 for i in range(max_dom) ] if 'background' in config['custom'] and 'interval_seconds' in config[ 'custom']['background']: namelist_input['time_control']['interval_seconds'] = config['custom'][ 'background']['interval_seconds'] if 'time_control' in config: for key, value in config['time_control'].items(): namelist_input['time_control'][key] = value for key, value in config['domains'].items(): namelist_input['domains'][key] = value if 'physics_suite' in namelist_input['physics']: del namelist_input['physics']['physics_suite'] for key, value in phys_config.items(): namelist_input['physics'][key] = value if num_land_cat != None: namelist_input['physics']['num_land_cat'] = num_land_cat if 'dynamics' in config: for key, value in config['dynamics'].items(): namelist_input['dynamics'][key] = value if version == Version('3.9.1'): namelist_input['dynamics']['gwd_opt'] = 0 namelist_input.write('./namelist.input', force=True) cli.notice('Succeeded.')
args.geog_root = os.path.abspath(args.geog_root) if not os.path.isdir(args.geog_root): cli.error(f'Directory {args.geog_root} does not exist!') if not args.bkg_root: if os.getenv('BKG_ROOT'): args.bkg_root = os.getenv('BKG_ROOT') else: cli.error( 'Option --bkg-root or environment variable BKG_ROOT need to be set!' ) args.bkg_root = os.path.abspath(args.bkg_root) if not os.path.isdir(args.bkg_root): cli.error(f'Directory {args.bkg_root} does not exist!') version = wrf_version(args.wrf_root) config = parse_config(args.config_json) if args.start_time: config['custom']['start_time'] = args.start_time config['custom']['end_time'] = args.start_time.add( hours=config['custom']['forecast_hours']) if config['wrfvar3']['ob_format'] == 1: if not args.prepbufr_root: if os.getenv('PREPBUFR_ROOT'): args.prepbufr_root = os.getenv('PREPBUFR_ROOT') else: cli.error( 'Option --prepbufr-root or environment variable PREPBUFR_ROOT need to be set!' )
def config_wrfda(work_root, wrfda_root, config, args, wrf_work_dir=None, tag=None, fg=None): start_time = config['custom']['start_time'] end_time = config['custom']['end_time'] datetime_fmt = 'YYYY-MM-DD_HH:mm:ss' start_time_str = start_time.format(datetime_fmt) max_dom = config['domains']['max_dom'] # Need to take some parameters from wrfinput file. if not wrf_work_dir: if tag != None: wrf_work_dir = f'{work_root}/wrf_{tag}' else: wrf_work_dir = f'{work_root}/wrf' if max_dom > 1: if not has_key(config, ('custom', 'wrfda', 'dom')): cli.error( 'You need to set custom->wrfda->dom to set which domain to work on!' ) dom_idx = config['custom']['wrfda']['dom'] dom_str = 'd' + str(dom_idx + 1).zfill(2) if tag != None: wrfda_work_dir = f'{work_root}/wrfda_{tag}/{dom_str}' else: wrfda_work_dir = f'{work_root}/wrfda/{dom_str}' else: dom_idx = 0 dom_str = 'd01' if tag != None: wrfda_work_dir = f'{work_root}/wrfda_{tag}' else: wrfda_work_dir = f'{work_root}/wrfda' if not os.path.isdir(wrfda_work_dir): os.makedirs(wrfda_work_dir) os.chdir(wrfda_work_dir) version = wrf_version(wrfda_root) if os.path.isfile(f'{wrf_work_dir}/wrfinput_{dom_str}'): f = Dataset(f'{wrf_work_dir}/wrfinput_{dom_str}') elif os.path.isfile(f'{wrf_work_dir}/wrfout_{dom_str}_{start_time_str}'): f = Dataset(f'{wrf_work_dir}/wrfout_{dom_str}_{start_time_str}') elif fg: f = Dataset(fg) else: cli.error( f'config_wrfda: Cannot find wrfinput or wrfout in {wrf_work_dir} or wrfvar!' ) num_land_cat = f.getncattr('NUM_LAND_CAT') hypsometric_opt = f.getncattr('HYPSOMETRIC_OPT') f.close() time_window = get_value(config, ('custom', 'wrfda', 'time_window'), 360) # Read in namelist template (not exact Fortran namelist format, we need to change it). template = open(f'{wrfda_root}/var/README.namelist').read() template = re.sub(r'^[^&]*', '', template, flags=re.DOTALL) template = re.sub(r';.*', '', template) template = re.sub(r'\([^\)]*\)', '', template) namelist_input = f90nml.read(StringIO(template)) namelist_input['wrfvar1']['var4d_lbc'] = False namelist_input['wrfvar18']['analysis_date'] = start_time_str namelist_input['wrfvar21']['time_window_min'] = start_time.subtract( minutes=time_window / 2).format(datetime_fmt) namelist_input['wrfvar22']['time_window_max'] = start_time.add( minutes=time_window / 2).format(datetime_fmt) # Fix bugs namelist_input['wrfvar2']['qc_rej_both'] = False namelist_input['wrfvar14']['rtminit_satid'] = -1 namelist_input['wrfvar14']['rtminit_sensor'] = -1 if version == Version('3.6.1'): namelist_input['wrfvar4']['use_iasiobs'] = False del namelist_input['wrfvar4']['use_iasisobs'] namelist_input['wrfvar4']['use_seviriobs'] = False del namelist_input['wrfvar4']['use_sevirisobs'] namelist_input['wrfvar5']['max_omb_spd'] = namelist_input['wrfvar5'][ 'max_omb_sp'] del namelist_input['wrfvar5']['max_omb_sp'] namelist_input['wrfvar5']['max_error_spd'] = namelist_input['wrfvar5'][ 'max_error_sp'] del namelist_input['wrfvar5']['max_error_sp'] elif version > Version('3.8.1'): namelist_input['wrfvar11']['write_detail_grad_fn'] = True namelist_input['wrfvar11']['calculate_cg_cost_fn'] = True # Merge namelist.input in tutorial. tmp = f90nml.read(f'{wrfda_root}/var/test/tutorial/namelist.input') for key, value in tmp.items(): if not key in namelist_input: namelist_input[key] = value namelist_input['time_control']['run_hours'] = config['custom'][ 'forecast_hours'] namelist_input['time_control']['start_year'] = [ int(start_time.format("Y")) for i in range(max_dom) ] namelist_input['time_control']['start_month'] = [ int(start_time.format("M")) for i in range(max_dom) ] namelist_input['time_control']['start_day'] = [ int(start_time.format("D")) for i in range(max_dom) ] namelist_input['time_control']['start_hour'] = [ int(start_time.format("H")) for i in range(max_dom) ] namelist_input['time_control']['end_year'] = [ int(end_time.format("Y")) for i in range(max_dom) ] namelist_input['time_control']['end_month'] = [ int(end_time.format("M")) for i in range(max_dom) ] namelist_input['time_control']['end_day'] = [ int(end_time.format("D")) for i in range(max_dom) ] namelist_input['time_control']['end_hour'] = [ int(end_time.format("H")) for i in range(max_dom) ] namelist_input['time_control']['frames_per_outfile'] = [ 1 for i in range(max_dom) ] for key, value in config['time_control'].items(): namelist_input['time_control'][key] = value for key, value in config['domains'].items(): namelist_input['domains'][key] = value # WRFDA only take grids parameters one domain at a time. namelist_input['domains']['max_dom'] = 1 for key in ('e_we', 'e_sn', 'e_vert', 'dx', 'dy', 'grid_id', 'parent_id', 'i_parent_start', 'j_parent_start', 'parent_grid_ratio', 'parent_time_step_ratio'): if key in config['domains']: namelist_input['domains'][key] = config['domains'][key][dom_idx] namelist_input['domains']['hypsometric_opt'] = hypsometric_opt # Sync physics parameters. if 'physics' in config: for key, value in config['physics'].items(): namelist_input['physics'][key] = value namelist_input['physics']['num_land_cat'] = num_land_cat if version == Version('3.9.1'): namelist_input['dynamics']['gwd_opt'] = 0 # Write customized parameters. for tag in range(1, 23): section = f'wrfvar{tag}' for key, value in config[section].items(): namelist_input[section][key] = value # Validate some parameters. for key in ('as1', 'as2', 'as3', 'as4', 'as5'): if namelist_input['wrfvar7'][key] == -1: cli.error(f'wrfvar7->{key} is -1!') namelist_input.write(f'{wrfda_work_dir}/namelist.input', force=True) cli.notice('Succeeded.')
def build_wrf(wrf_root, wps_root, wrfplus_root, wrfda_root, args): if not 'HDF5' in os.environ: res = subprocess.run(['which', 'h5dump'], stdout=subprocess.PIPE) if res.returncode == 0: os.environ['HDF5'] = os.path.dirname(os.path.dirname(res.stdout.decode('utf-8'))) cli.notice(f'Set HDF5 to {os.environ["HDF5"]}') if not 'HDF5' in os.environ: cli.warning('HDF5 environment variable is not set') if not 'NETCDF' in os.environ: res = subprocess.run(['which', 'nf-config'], stdout=subprocess.PIPE) if res.returncode == 0: os.environ['NETCDF'] = os.path.dirname(os.path.dirname(res.stdout.decode('utf-8'))) res = subprocess.run(['nf-config', '--includedir'], stdout=subprocess.PIPE) os.environ['NETCDF_INC'] = res.stdout.decode('utf-8').strip() res = subprocess.run(['nf-config', '--flibs'], stdout=subprocess.PIPE) os.environ['NETCDF_LIB'] = re.search(r'-L([^ ]*)', res.stdout.decode('utf-8'))[1] cli.notice(f'Set NETCDF_INC to {os.environ["NETCDF_INC"]}') cli.notice(f'Set NETCDF_LIB to {os.environ["NETCDF_LIB"]}') if not 'NETCDF' in os.environ: cli.warning('NETCDF environment variable is not set!') if not 'JASPERINC' in os.environ or not 'JASPERLIB' in os.environ: if 'JASPER_ROOT' in os.environ: os.environ['JASPERINC'] = os.environ['JASPER_ROOT'] + '/include' os.environ['JASPERLIB'] = os.environ['JASPER_ROOT'] + '/lib' cli.notice(f'Set JASPERINC to {os.environ["JASPERINC"]}.') cli.notice(f'Set JASPERLIB to {os.environ["JASPERLIB"]}.') else: cli.error('JASPERINC and JASPERLIB environment variables are not set!') if not 'LIBPNG_ROOT' in os.environ: cli.warning('LIBPNG_ROOT environment variable is not set. Library PNG may not be found!') if not 'WRFIO_NCD_LARGE_FILE_SUPPORT' in os.environ: os.environ['WRFIO_NCD_LARGE_FILE_SUPPORT'] = '1' cli.notice('Set WRFIO_NCD_LARGE_FILE_SUPPORT to 1.') if args.rttov: os.environ['RTTOV'] = args.rttov cli.notice(f'Use RTTOV in {args.rttov}.') # --------------------------------------------------------------------------------- # WRF os.chdir(wrf_root) version = wrf_version(wrf_root) if version <= Version('3.6.1'): os.environ['BUFR'] = '1' # Fix possible code bugs. if Version('3.6.1') <= version <= Version('3.8.1'): edit_file('phys/module_cu_g3.F', [['integer, dimension \(12\) :: seed', 'integer, dimension (33) :: seed']]) if args.force: run('./clean -a 1> /dev/null 2>&1') expected_exe_files = ('main/wrf.exe', 'main/real.exe', 'main/ndown.exe', 'main/tc.exe') if not check_files(expected_exe_files): cli.notice('Configure WRF ...') if args.use_grib: cli.notice('Set GRIB2 flag.') edit_file('./arch/Config.pl', [ ['\$I_really_want_to_output_grib2_from_WRF = "FALSE"', '$I_really_want_to_output_grib2_from_WRF = "TRUE"'] ]) if args.use_hyb: child = pexpect.spawn('./configure -hyb', encoding='utf-8') else: child = pexpect.spawn('./configure', encoding='utf-8') child.expect('Enter selection.*') if platform.system() == 'Darwin': if args.compiler_suite == 'gnu': child.sendline('15') else: if args.compiler_suite == 'intel': if args.openmp: child.sendline('16') # INTEL (ifort/icc) dm+sm else: child.sendline('15') # INTEL (ifort/icc) dmpar elif args.compiler_suite == 'gnu': if args.openmp: child.sendline('35') # GNU (gfortran/gcc) dm+sm else: child.sendline('34') # GNU (gfortran/gcc) dmpar elif args.compiler_suite == 'pgi': if args.openmp: child.sendline('55') # PGI (pgf90/pgcc) dm+sm else: child.sendline('54') # PGI (pgf90/pgcc) dmpar child.expect('Compile for nesting.*:') child.sendline('1') if platform.system() == 'Darwin': child.expect('This build of WRF will use NETCDF4 with HDF5 compression') child.wait() if args.compiler_suite == 'intel': edit_file('./configure.wrf', [ ['mpif90', 'mpiifort'], ['mpicc', 'mpiicc'] ]) elif args.compiler_suite == 'pgi': edit_file('./configure.wrf', [ ['pgf90', 'pgfortran'], ['mpif90', 'mpifort'] ]) # Fix for OpenMPI. edit_file('./configure.wrf', [ ['DM_CC\s*=\s*mpicc\s*$', 'DM_CC = mpicc -DMPI2_SUPPORT\n'] ]) cli.notice('Compile WRF ...') if args.debug: if args.compiler_suite == 'intel': debug_options = '-O0 -g -traceback' elif args.compiler_suite == 'gnu': debug_options = '-O0 -g -fbacktrace' edit_file('configure.wrf', [ ['FCFLAGS\s*=\s*\$\(FCOPTIM\)\s*\$\(FCBASEOPTS\)', f'FCFLAGS = {debug_options} $(FCBASEOPTS)'] ]) if args.verbose: run(f'./compile em_real') else: run(f'./compile em_real 1> compile.out 2>&1') if check_files(expected_exe_files): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed!') else: cli.error(f'Failed! Check {wrf_root}/compile.out') else: cli.notice('WRF is already built.') # --------------------------------------------------------------------------------- # WPS os.chdir(wps_root) if args.force: run('./clean -a 1> /dev/null 2>&1') expected_exe_files = ('geogrid/src/geogrid.exe', 'metgrid/src/metgrid.exe', 'ungrib/src/ungrib.exe') if not check_files(expected_exe_files): cli.notice('Configure WPS ...') child = pexpect.spawn('./configure') child.expect('Enter selection.*') if args.compiler_suite == 'intel': child.sendline('19') # Linux x86_64, Intel compiler (dmpar) elif args.compiler_suite == 'gnu': child.sendline('3') # Linux x86_64, gfortran (dmpar) elif args.compiler_suite == 'pgi': child.sendline('7') child.wait() if args.compiler_suite == 'intel': edit_file('./configure.wps', [ ['mpif90', 'mpiifort'], ['mpicc', 'mpiicc'] ]) elif args.compiler_suite == 'pgi': edit_file('./configure.wps', [ ['pgf90', 'pgfortran'], ['mpif90', 'mpifort'] ]) else: run('sed -i "s/mpicc -cc=.*/mpicc/" configure.wps') run('sed -i "s/mpif90 -f90=.*/mpif90/" configure.wps') run('sed -i "s/WRF_DIR\s*=.*/WRF_DIR = ..\/WRF/" configure.wps') if 'LIBPNG_ROOT' in os.environ: run(f'sed -i "s@COMPRESSION_LIBS\s*=\(.*\)@COMPRESSION_LIBS = \\1 -L{os.environ["LIBPNG_ROOT"]}/lib@" configure.wps') run(f'sed -i "s@COMPRESSION_INC\s*=\(.*\)@COMPRESSION_INC = \\1 -I{os.environ["LIBPNG_ROOT"]}/include@" configure.wps') if args.compiler_suite == 'gnu': # Fix for gfortran 9.1.0. edit_file('ungrib/src/ngl/g2/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_8)/=0']], return_on_first_match=True) edit_file('ungrib/src/ngl/g2/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_4)/=0']], return_on_first_match=True) edit_file('ungrib/src/ngl/g2/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_2)/=0']], return_on_first_match=True) edit_file('ungrib/src/ngl/g2/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_1)/=0']], return_on_first_match=True) # Fix for OpenMPI. edit_file('./configure.wps', [ ['DM_CC\s*=\s*mpicc\s*$', 'DM_CC = mpicc -DMPI2_SUPPORT\n'] ]) cli.notice('Compile WPS ...') if args.verbose: run('./compile') else: run('./compile 1> compile.out 2>&1') if check_files(expected_exe_files): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed!') else: cli.error(f'Failed! Check {wps_root}/compile.out') else: cli.notice('WPS is already built.') # --------------------------------------------------------------------------------- # WRFPLUS os.chdir(wrfplus_root) if args.force: run('./clean -a 1> /dev/null 2>&1') if Version('3.6.1') <= version <= Version('3.9.1'): edit_file('phys/module_cu_g3.F', [['integer, dimension \(12\) :: seed', 'integer, dimension (33) :: seed']]) if version == Version('3.6.1'): line_number = 841 elif version == Version('3.8.1'): line_number = 855 elif version == Version('3.9.1'): line_number = 856 else: error('Find out the wrong OpenMP directive in WRFPLUS/main/module_wrf_top.F!') edit_file('main/module_wrf_top.F', [[line_number, ' !$OMP DEFAULT (SHARED) PRIVATE ( ij )\n']]) if version >= Version('4.0'): expected_exe_files = ('main/wrfplus.exe') else: expected_exe_files = ('main/wrf.exe') if not check_files(expected_exe_files): cli.notice('Configure WRFPLUS ...') if args.use_grib: cli.notice('Set GRIB2 flag.') edit_file('./arch/Config.pl', [ ['\$I_really_want_to_output_grib2_from_WRF = "FALSE"', '$I_really_want_to_output_grib2_from_WRF = "TRUE"'] ]) child = pexpect.spawn('./configure wrfplus') child.expect('Enter selection.*') if args.compiler_suite == 'intel': if version <= Version('3.6.1'): child.sendline('8') else: child.sendline('34') elif args.compiler_suite == 'gnu': child.sendline('18') elif args.compiler_suite == 'pgi': child.sendline('28') child.wait() if args.compiler_suite == 'intel': edit_file('./configure.wrf', [ ['mpif90', 'mpiifort'], ['mpicc', 'mpiicc'], ['override-limits', 'qoverride-limits'] ]) # Fix for OpenMPI. edit_file('./configure.wrf', [ ['DM_CC\s*=\s*mpicc\s*$', 'DM_CC = mpicc -DMPI2_SUPPORT\n'] ]) cli.notice('Compile WRFPLUS ...') if args.debug: if args.compiler_suite == 'intel': debug_options = '-O0 -g -traceback' elif args.compiler_suite == 'gnu': debug_options = '-O0 -g -fbacktrace' edit_file('configure.wrf', [ ['FCFLAGS\s*=\s*\$\(FCOPTIM\)\s*\$\(FCBASEOPTS\)', f'FCFLAGS = {debug_options} $(FCBASEOPTS)'] ]) if version >= Version('4.0'): build_target = 'wrfplus' else: build_target = 'wrf' if args.verbose: run(f'./compile {build_target}') else: run(f'./compile {build_target} 1> compile.out 2>&1') if check_files(expected_exe_files): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed!') else: cli.error(f'Failed! Check {wrfplus_root}/compile.out') else: cli.notice('WRFPLUS is already built.') # --------------------------------------------------------------------------------- # WRFDA os.chdir(wrfda_root) os.environ['WRFPLUS_DIR'] = wrfplus_root if args.force: run('./clean -a 1> /dev/null 2>&1') if Version('3.6.1') <= version <= Version('3.9.1'): cli.warning(f'Fix {wrfda_root}/var/da/da_define_structures/da_zero_y.inc') edit_file('var/da/da_define_structures/da_zero_y.inc', [ [', value \)', ', value_ )'], [':: value$', ':: value_\nreal value'], ['if \(.not.\(present\(value\)\)\) value = 0.0', ''' if (.not.(present(value_))) then value = 0.0 else value = value_ end if '''] ]) if version == Version('4.1.1'): cli.warning(f'Fix {wrfda_root}/share/input_wrf.F') edit_file('share/input_wrf.F', [ ['FUNCTION check_which_switch', 'FUNCTION check_which_switch1'] ]) expected_exe_files = [ 'var/build/da_advance_time.exe', 'var/build/da_bias_airmass.exe', 'var/build/da_bias_scan.exe', 'var/build/da_bias_sele.exe', 'var/build/da_bias_verif.exe', 'var/build/da_rad_diags.exe', 'var/build/da_tune_obs_desroziers.exe', 'var/build/da_tune_obs_hollingsworth1.exe', 'var/build/da_tune_obs_hollingsworth2.exe', 'var/build/da_update_bc_ad.exe', 'var/build/da_update_bc.exe', 'var/build/da_verif_grid.exe', 'var/build/da_verif_obs.exe', 'var/build/da_wrfvar.exe', 'var/build/gen_be_addmean.exe', 'var/build/gen_be_cov2d3d_contrib.exe', 'var/build/gen_be_cov2d.exe', 'var/build/gen_be_cov3d2d_contrib.exe', 'var/build/gen_be_cov3d3d_bin3d_contrib.exe', 'var/build/gen_be_cov3d3d_contrib.exe', 'var/build/gen_be_cov3d.exe', 'var/build/gen_be_diags.exe', 'var/build/gen_be_diags_read.exe', 'var/build/gen_be_ensmean.exe', 'var/build/gen_be_ensrf.exe', 'var/build/gen_be_ep1.exe', 'var/build/gen_be_ep2.exe', 'var/build/gen_be_etkf.exe', 'var/build/gen_be_hist.exe', 'var/build/gen_be_stage0_gsi.exe', 'var/build/gen_be_stage0_wrf.exe', 'var/build/gen_be_stage1_1dvar.exe', 'var/build/gen_be_stage1.exe', 'var/build/gen_be_stage1_gsi.exe', 'var/build/gen_be_stage2_1dvar.exe', 'var/build/gen_be_stage2a.exe', 'var/build/gen_be_stage2.exe', 'var/build/gen_be_stage2_gsi.exe', 'var/build/gen_be_stage3.exe', 'var/build/gen_be_stage4_global.exe', 'var/build/gen_be_stage4_regional.exe', 'var/build/gen_be_vertloc.exe', 'var/build/gen_mbe_stage2.exe', 'var/obsproc/src/obsproc.exe'] if not check_files(expected_exe_files): cli.notice('Configure WRFDA ...') if args.use_grib: cli.notice('Set GRIB2 flag.') edit_file('./arch/Config.pl', [ ['\$I_really_want_to_output_grib2_from_WRF = "FALSE"', '$I_really_want_to_output_grib2_from_WRF = "TRUE"'] ]) child = pexpect.spawn('./configure 4dvar') child.expect('Enter selection.*') if args.compiler_suite == 'intel': child.sendline('8') elif args.compiler_suite == 'gnu': child.sendline('18') elif args.compiler_suite == 'pgi': child.sendline('28') child.wait() if args.compiler_suite == 'intel': edit_file('./configure.wrf', [ ['mpif90', 'mpiifort'], ['mpicc', 'mpiicc'] ]) # Fix for OpenMPI. edit_file('./configure.wrf', [ ['DM_CC\s*=\s*mpicc\s*$', 'DM_CC = mpicc -DMPI2_SUPPORT\n'] ]) cli.notice('Compile WRFDA ...') if args.debug: if args.compiler_suite == 'intel': debug_options = '-O0 -g -traceback' elif args.compiler_suite == 'gnu': debug_options = '-O0 -g -fbacktrace' edit_file('configure.wrf', [ ['FCFLAGS\s*=\s*\$\(FCOPTIM\)\s*\$\(FCBASEOPTS\)', f'FCFLAGS = {debug_options} $(FCBASEOPTS)'] ]) if args.verbose: run(f'./compile all_wrfvar') else: run(f'./compile all_wrfvar 1> compile.out 2>&1') if check_files(expected_exe_files, fatal=True): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed!') else: cli.error(f'Failed! Check {wrfda_root}/compile.out') else: cli.notice('WRFDA is already built.')
def config_wrfda_sens(work_root, wrfda_root, config, args, wrf_work_dir=None): if not 'wrfda' in config: cli.error('There is no "wrfda" in configuration file!') wrfda_config = config['wrfda'] phys_config = config['physics'] if 'physics' in config else {} start_time = config['custom']['start_time'] end_time = config['custom']['end_time'] datetime_fmt = 'YYYY-MM-DD_HH:mm:ss' start_time_str = start_time.format(datetime_fmt) max_dom = config['domains']['max_dom'] if not wrf_work_dir: wrf_work_dir = work_root + '/wrf' if not os.path.isdir(wrf_work_dir): cli.error(f'{wrf_work_dir} does not exist!') wrfda_work_dir = os.path.abspath(work_root) + '/wrfda' if not os.path.isdir(wrfda_work_dir): os.mkdir(wrfda_work_dir) os.chdir(wrfda_work_dir) version = wrf_version(wrfda_root) wrfinput = Dataset(f'{wrf_work_dir}/wrfinput_d01_{start_time_str}') num_land_cat = wrfinput.getncattr('NUM_LAND_CAT') wrfinput.close() time_window = config['wrfda']['time_window'] if 'time_window' in config['wrfda'] else 360 # Read in namelist template (not exact Fortran namelist format, we need to change it). template = open(f'{wrfda_root}/var/README.namelist').read() template = re.sub(r'^[^&]*', '', template, flags=re.DOTALL) template = re.sub(r';.*', '', template) template = re.sub(r'\([^\)]*\)', '', template) namelist_input = f90nml.read(StringIO(template)) # Merge namelist.input in tutorial. tmp = f90nml.read(f'{wrfda_root}/var/test/tutorial/namelist.input') for key, value in tmp.items(): if not key in namelist_input: namelist_input[key] = value namelist_input['wrfvar1'] ['var4d_lbc'] = False namelist_input['wrfvar3'] ['ob_format'] = wrfda_config['ob_format'] namelist_input['wrfvar6'] ['orthonorm_gradient'] = True namelist_input['wrfvar6'] ['use_lanczos'] = True namelist_input['wrfvar6'] ['read_lanczos'] = True namelist_input['wrfvar17'] ['adj_sens'] = True namelist_input['wrfvar17'] ['sensitivity_option'] = 0 namelist_input['wrfvar17'] ['analysis_type'] = 'QC-OBS' namelist_input['wrfvar18'] ['analysis_date'] = start_time_str namelist_input['wrfvar21'] ['time_window_min'] = start_time.subtract(minutes=time_window/2).format(datetime_fmt) namelist_input['wrfvar22'] ['time_window_max'] = start_time.add(minutes=time_window/2).format(datetime_fmt) # Fix bugs namelist_input['wrfvar2'] ['qc_rej_both'] = False namelist_input['wrfvar7'] ['cv_options'] = wrfda_config['cv_options'] namelist_input['wrfvar14'] ['rtminit_satid'] = -1 namelist_input['wrfvar14'] ['rtminit_sensor'] = -1 namelist_input['time_control']['run_hours'] = config['custom']['forecast_hours'] namelist_input['time_control']['start_year'] = [int(start_time.format("Y")) for i in range(max_dom)] namelist_input['time_control']['start_month'] = [int(start_time.format("M")) for i in range(max_dom)] namelist_input['time_control']['start_day'] = [int(start_time.format("D")) for i in range(max_dom)] namelist_input['time_control']['start_hour'] = [int(start_time.format("H")) for i in range(max_dom)] namelist_input['time_control']['end_year'] = [int(end_time.format("Y")) for i in range(max_dom)] namelist_input['time_control']['end_month'] = [int(end_time.format("M")) for i in range(max_dom)] namelist_input['time_control']['end_day'] = [int(end_time.format("D")) for i in range(max_dom)] namelist_input['time_control']['end_hour'] = [int(end_time.format("H")) for i in range(max_dom)] namelist_input['time_control']['io_form_auxinput17'] = 2 namelist_input['time_control']['auxinput17_inname'] = './gr01' namelist_input['time_control']['iofields_filename'] = f'{wrfda_root}/var/run/fso.io_config' for key, value in config['domains'].items(): namelist_input['domains'][key] = value # Sync physics parameters. for key, value in phys_config.items(): namelist_input['physics'][key] = value namelist_input['physics']['num_land_cat'] = num_land_cat if version == Version('3.9.1'): namelist_input['dynamics']['gwd_opt'] = 0 namelist_input.write(f'{wrfda_work_dir}/namelist.input', force=True) cli.notice('Succeeded.')