Ejemplo n.º 1
0
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_*')
Ejemplo n.º 2
0
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.')
Ejemplo n.º 3
0
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.')
Ejemplo n.º 4
0
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!'
            )
Ejemplo n.º 5
0
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.')
Ejemplo n.º 6
0
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.')
Ejemplo n.º 7
0
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.')