def download_gdas(time): dir_name = f'gdas.{time.format("YYYYMMDD")}/{time.format("HH")}' res = requests.head(f'{root_url}/{dir_name}/') if res.status_code != 200 and res.status_code != 302: cli.error(f'Remote GDAS data at {time} do not exist!') file_name = 'gdas.t{:02d}z.prepbufr.nr'.format(time.hour) url = f'{root_url}/{dir_name}/{file_name}' if not os.path.isdir(f'{output_root}/{dir_name}'): os.makedirs(f'{output_root}/{dir_name}') cli.notice(f'Create directory {output_root}/{dir_name}.') cli.notice(f'Downloading {url}.') local_file_path = f'{output_root}/{dir_name}/{file_name}' if is_downloading(local_file_path): cli.warning(f'Skip downloading {local_file_path}.') return if os.path.isfile(local_file_path): if check_file_size(url, local_file_path): cli.notice(f'File {local_file_path} exists.') return else: # File is not downloaded completely. os.remove(local_file_path) try: subprocess.call(['curl', '-C', '-', '-o', local_file_path, url]) except Exception as e: cli.error(f'Encounter exception {e}!') if not check_file_size(url, local_file_path): os.remove(local_file_path) cli.error(f'Failed to download {file_name}!')
def download_gfs(start_time, forecast_hour): dir_name = f'{prefix}.{start_time.format("YYYYMMDD")}/{start_time.format("HH")}' file_name = '{}.t{:02d}z.pgrb2.{}.f{:03d}'.format(prefix, start_time.hour, resolution, forecast_hour) url = f'{root_url}/{dir_name}/{file_name}' if not os.path.isdir(f'{output_root}/{dir_name}'): os.makedirs(f'{output_root}/{dir_name}') cli.notice(f'Create directory {output_root}/{dir_name}.') cli.notice(f'Downloading {url}.') local_file_path = f'{output_root}/{dir_name}/{file_name}' if is_downloading(local_file_path): cli.warning(f'Skip downloading {local_file_path}.') return if os.path.isfile(local_file_path): if check_file_size(url, local_file_path): cli.notice(f'File {local_file_path} exists.') return else: # File is not downloaded completely. os.remove(local_file_path) try: subprocess.call(['curl', '-C', '-', '-o', local_file_path, url]) except Exception as e: cli.error('Encounter exception {e}!') if not check_file_size(url, local_file_path): os.remove(local_file_path) cli.error(f'Failed to download {file_name}!')
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 run_wrfda_3dvar(work_root, wrfda_root, config, args, wrf_work_dir=None, force=False, tag=None, fg=None): start_time = config['custom']['start_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: if tag != None: wrf_work_dir = f'{work_root}/wrf_{tag}' else: wrf_work_dir = f'{work_root}/wrf' if tag != None: obsproc_work_dir = f'{work_root}/wrfda_{tag}/obsproc' else: obsproc_work_dir = f'{work_root}/wrfda/obsproc' if max_dom > 1: dom_str = 'd' + str(config['custom']['wrfda']['dom'] + 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_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.mkdir(wrfda_work_dir) os.chdir(wrfda_work_dir) cli.stage(f'Run da_wrfvar.exe at {wrfda_work_dir} ...') if os.path.isfile(f'wrfvar_output_{start_time_str}' ) and not args.force and not force: run(f'ls -l wrfvar_output_{start_time_str}') cli.notice(f'wrfvar_output_{start_time_str} already exist.') return run(f'ln -sf {wrfda_root}/run/LANDUSE.TBL {wrfda_work_dir}') if not os.path.isfile('namelist.input'): cli.error( 'namelist.input has not been generated! Run config_wrfda.py.') # BE matrix if 'cv_options' in config['wrfvar7']: be_work_dir = os.path.dirname( os.path.abspath(work_root)) + '/be/' + dom_str if not os.path.isdir(be_work_dir): be_work_dir = os.path.dirname( os.path.abspath(work_root)) + '/../be/' + dom_str if config['wrfvar7']['cv_options'] == 5: if not os.path.isfile(f'{be_work_dir}/be.dat.cv5'): cli.error( f'BE matrix {be_work_dir}/be.dat.cv5 does not exist!') run(f'ln -sf {be_work_dir}/be.dat.cv5 be.dat') elif config['wrfvar7']['cv_options'] == 6: if not os.path.isfile(f'{be_work_dir}/be.dat.cv6'): cli.error( f'BE matrix {be_work_dir}/be.dat.cv6 does not exist!') run(f'ln -sf {be_work_dir}/be.dat.cv6 be.dat') elif config['wrfvar7']['cv_options'] == 7: if not os.path.isfile(f'{be_work_dir}/be.dat.cv7'): cli.error( f'BE matrix {be_work_dir}/be.dat.cv7 does not exist!') run(f'ln -sf {be_work_dir}/be.dat.cv7 be.dat') if not os.path.exists('./be.dat'): run(f'ln -sf {wrfda_root}/var/run/be.dat.cv3 be.dat') # First guess # TODO: Assume there is only one domain to be assimilated. if fg != None: run(f'ln -sf {fg} {wrfda_work_dir}/fg') else: expected_files = [ '{}/wrfout_d{:02d}_{}'.format(wrf_work_dir, i + 1, start_time_str) for i in range(max_dom) ] if check_files(expected_files): run(f'ln -sf {wrf_work_dir}/wrfout_{dom_str}_{start_time_str} {wrfda_work_dir}/fg' ) else: expected_files = [ '{}/wrfinput_d{:02d}_{}'.format(wrf_work_dir, i + 1, start_time_str) for i in range(max_dom) ] if not check_files(expected_files): cli.error( 'real.exe or da_update_bc.exe wasn\'t executed successfully!' ) run(f'ln -sf {wrf_work_dir}/wrfinput_{dom_str}_{start_time_str} {wrfda_work_dir}/fg' ) # Observation data if config['custom']['wrfda']['type'] == '3dvar': if 'use_radarobs' in config['wrfvar4'] and config['wrfvar4'][ 'use_radarobs']: # Radar data run(f'rm -f ob.*') for obs_radar_file in glob( f'{args.littler_root}/{start_time.format("YYYYMMDD")}/obs.radar.*' ): radar_time = pendulum.from_format( os.path.basename(obs_radar_file).split('.')[2], 'YYYYMMDDHHmm') if radar_time == start_time: run(f'ln -sf {obs_radar_file} ob.radar') if os.path.isfile(f'wrfvar_output_{start_time_str}'): cli.notice('Use previous analysis data as the background.') run(f'mv wrfvar_output_{start_time_str} wrfvar_output_conv_{start_time_str}' ) run(f'ln -sf wrfvar_output_conv_{start_time_str} fg') elif 'conv_obs' in config['custom']: if 'dir_pattern' in config['custom']['conv_obs']: obs_dir = Template( config['custom']['conv_obs']['dir_pattern']).render( obs_time=start_time) if 'file_pattern' in config['custom']['conv_obs']: obs_file = Template( config['custom']['conv_obs']['file_pattern']).render( obs_time=start_time) if config['wrfvar3']['ob_format'] == 1: run(f'ln -sf {args.prepbufr_root}/{obs_dir}/{obs_file} ob.bufr' ) elif config['wrfvar3']['ob_format'] == 2: run(f'ln -sf {args.prepbufr_root}/{obs_dir}/{obs_file} ob.ascii' ) elif config['wrfvar3']['ob_format'] == 2 and os.path.isfile( f'{obsproc_work_dir}/obs_gts_{start_time.format(datetime_fmt)}.3DVAR' ): # LITTLE_R conventional data run(f'ln -sf {obsproc_work_dir}/obs_gts_{start_time.format(datetime_fmt)}.3DVAR ob.ascii' ) elif config['wrfvar3']['ob_format'] == 1 and config['custom']['wrfda'][ 'prepbufr_source'] == 'gdas': # PREPBUFR conventional data gdas_file_path = f'{args.prepbufr_root}/gdas.{start_time.format("YYYYMMDD")}/gdas.t{start_time.hour:02}z.prepbufr.nr' if not os.path.isfile(gdas_file_path): cli.error(f'{gdas_file_path} does not exist!') run(f'ln -sf {gdas_file_path} ob.bufr') if os.path.isfile(f'{wrfda_work_dir}/wrfvar_output_{start_time_str}' ) and not args.force: cli.notice( f'{wrfda_work_dir}/wrfvar_output_{start_time_str} already exists.') return submit_job(f'{wrfda_root}/var/build/da_wrfvar.exe', min(20, args.np), config, args, wait=True) expected_files = [f'wrfvar_output', 'statistics'] if not check_files(expected_files): # Check if the failure is caused by parallel computing? Such as cv_options is zero in some process. if search_files('rsl.error.*', 'Invalid CV option chosen: cv_options = 0'): cli.warning( 'Failed to run da_wrfvar.exe in parallel. Try to run in serial.' ) submit_job(f'{wrfda_root}/var/build/da_wrfvar.exe', 1, config, args, wait=True) if not check_files(expected_files): cli.error( f'Still failed! See {wrfda_work_dir}/rsl.error.0000.') else: cli.error(f'Failed! See {wrfda_work_dir}/rsl.error.0000.') else: print(open('statistics').read()) run(f'ncl -Q {scripts_root}/../plots/plot_cost_grad_fn.ncl') run(f'cp wrfvar_output wrfvar_output_{start_time_str}') cli.notice('Succeeded.')
def build_nceplibs(nceplibs_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', 'ncdump'], stdout=subprocess.PIPE) if res.returncode == 0: os.environ['NETCDF'] = os.path.dirname( os.path.dirname(res.stdout.decode('utf-8'))) cli.notice(f'Set NETCDF to {os.environ["NETCDF"]}') if not 'NETCDF' in os.environ: cli.warning('NETCDF environment variable is not set!') if not 'JASPER_INC' in os.environ or not 'JASPER_LIB' in os.environ: if 'JASPER_ROOT' in os.environ: os.environ['JASPER_INC'] = os.environ['JASPER_ROOT'] + '/include' os.environ['JASPER_LIB'] = os.environ['JASPER_ROOT'] + '/lib' cli.notice(f'Set JASPER_INC to {os.environ["JASPER_INC"]}.') cli.notice(f'Set JASPER_LIB to {os.environ["JASPER_LIB"]}.') else: cli.error( 'JASPERINC and JASPERLIB environment variables are not set!') if not 'PNG_INC' in os.environ or not 'PNG_LIB' in os.environ: if 'LIBPNG_ROOT' in os.environ: os.environ['PNG_INC'] = os.environ['LIBPNG_ROOT'] + '/include' os.environ['PNG_LIB'] = os.environ['LIBPNG_ROOT'] + '/lib' else: os.environ['PNG_INC'] = '/usr/include' os.environ['PNG_LIB'] = '/usr/lib64' cli.notice(f'Set PNG_INC to {os.environ["PNG_INC"]}.') cli.notice(f'Set PNG_LIB to {os.environ["PNG_LIB"]}.') os.chdir(nceplibs_root) if args.compiler_suite == 'gnu': # Fix for gfortran 9.1.0. edit_file('src/g2/v3.1.0/src/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_8)/=0']], return_on_first_match=True) edit_file('src/g2/v3.1.0/src/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_4)/=0']], return_on_first_match=True) edit_file('src/g2/v3.1.0/src/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_2)/=0']], return_on_first_match=True) edit_file('src/g2/v3.1.0/src/intmath.f', [['iand\(i,i-1\)/=0', 'iand(i,i-1_1)/=0']], return_on_first_match=True) edit_file('make_ncep_libs.sh', [['read -p "Proceed\? \(y/n\) " yn', 'yn=y']]) run(f'./make_ncep_libs.sh -s linux -c {args.compiler_suite} -d {args.nceplibs_root} -o 0 -a upp' )
def build_gsi(wrf_root, gsi_root, args): # Check environment. 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', 'ncdump'], stdout=subprocess.PIPE) if res.returncode == 0: os.environ['NETCDF'] = os.path.dirname( os.path.dirname(res.stdout.decode('utf-8'))) cli.notice(f'Set NETCDF to {os.environ["NETCDF"]}') if not 'NETCDF' in os.environ: cli.warning('NETCDF environment variable is not set!') if not os.getenv('LAPACK_PATH') and args.compiler_suite != 'intel': cli.error('Shell variable LAPACK_PATH is not set!') version = gsi_version(args.gsi_root) if version <= Version('3.6'): # 3.7 changes: Added wrf interface as a library (wrflib). No need to compile WRF with GSI and EnKF. if not os.path.isdir(args.wrf_root): cli.error(f'WRF directory {args.wrf_root} does not exist!') os.chdir(args.wrf_root) expected_exe_files = ('main/wrf.exe') if not check_files(expected_exe_files): cli.error('WRF has not been built! Build it first.') os.chdir(args.gsi_root) if args.force: run('rm -rf build') if not os.path.isdir('build'): os.mkdir('build') os.chdir('build') if version == Version('3.6'): expected_exe_files = ('bin/gsi.x', 'lib/libbacio_v2.0.1.a', 'lib/libbufr_v10.2.5.a', 'lib/libcrtm_v2.2.3.a', 'lib/libenkfdeplib.a', 'lib/libenkflib.a', 'lib/libgsilib_shrd.a', 'lib/libgsilib_wrf.a', 'lib/libnemsio_v2.2.1.a', 'lib/libsfcio_v1.1.0.a', 'lib/libsigio_v2.0.1.a', 'lib/libsp_v2.0.2.a', 'lib/libw3emc_v2.2.0.a', 'lib/libw3nco_v2.0.6.a') elif version == Version('3.7'): expected_exe_files = ('bin/enkf_wrf.x', 'bin/gsi.x', 'lib/libbacio_v2.0.1.a', 'lib/libbufr_v10.2.5.a', 'lib/libcrtm_v2.2.3.a', 'lib/libenkfdeplib.a', 'lib/libenkflib.a', 'lib/libgsilib_shrd.a', 'lib/libgsilib_wrf.a', 'lib/libnemsio_v2.2.1.a', 'lib/libsfcio_v1.1.0.a', 'lib/libsigio_v2.0.1.a', 'lib/libsp_v2.0.2.a', 'lib/libw3emc_v2.2.0.a', 'lib/libw3nco_v2.0.6.a') if not check_files(expected_exe_files): cmake_args = f'-DBUILD_ENKF=ON -DBUILD_CORELIBS=ON -DUSE_WRF=ON -DBUILD_WRF=ON -DBUILD_GFS=OFF ' if version == Version('3.6'): cli.notice('Fix GSI 3.6!') edit_file('../cmake/Modules/FindCORELIBS.cmake', [[ '\${CMAKE_SOURCE_DIR}/libsrc', '${CMAKE_SOURCE_DIR}/lib/libsrc' ]]) if args.compiler_suite == 'gnu': edit_file('../cmake/Modules/setCompilerFlags.cmake', [[ 'set\(BACIO_Fortran_FLAGS " -O3 -fconvert=big-endian -ffree-form', 'set(BACIO_Fortran_FLAGS " -O3 -fconvert=big-endian' ]]) elif args.compiler_suite == 'intel': edit_file('../cmake/Modules/setCompilerFlags.cmake', [[ 'set \(BACIO_Fortran_FLAGS "-O3 -free -assume nocc_omp', 'set(BACIO_Fortran_FLAGS " -O3 -assume nocc_omp' ]]) edit_file('../core-libs/sigio/CMakeLists.txt', [['\*\.f\)', '*.f90)']]) edit_file('../src/hybrid_ensemble_isotropic.F90', [['stop\(123\)', 'stop 123']]) edit_file('../src/setupoz.f90', [[ 'my_head%ij\(1\),my_head%wij\(1\)\)', 'my_head%ij,my_head%wij)' ]]) cmake_args += f'-DWRFPATH={args.wrf_root}' if version == Version('3.7'): cli.notice('Fix GSI 3.7!') edit_file('../src/setuplight.f90', [['my_head%wij\(1\)\)', 'my_head%wij)']]) cli.warning( 'GSI 3.7 has bug when rerun cmake, so clean all build files.') run('rm -rf ../build/*') cmake_args += '-DBUILD_UTIL_COM=ON' # Fix not-found -lnetcdf -lnetcdff. edit_file('../cmake/Modules/setCompilerFlags.cmake', [['-lnetcdf -lnetcdff', '']]) cli.notice('Configure GSI ...') if args.compiler_suite == 'gnu': cc = 'gcc' cxx = 'g++' fc = 'gfortran' elif args.compiler_suite == 'intel': cc = 'mpiicc' cxx = 'mpiicpc' fc = 'mpiifort' if args.verbose: run(f'CC={cc} CXX={cxx} FC={fc} cmake .. {cmake_args}') else: run(f'CC={cc} CXX={cxx} FC={fc} cmake .. {cmake_args} &> cmake.out' ) cli.notice('Compile GSI ...') if args.verbose: run('make') else: run('make &> make.out') if check_files(expected_exe_files): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed') else: cli.error(f'Failed! Check {args.gsi_root}/build/make.out') else: cli.notice('GSI has already been built.') if version == Version('3.6'): os.chdir(f'{args.gsi_root}/util/bufr_tools') if args.force: run('make clean') expected_exe_files = ( 'bufr_append_sample.exe', 'bufr_decode_radiance.exe', 'bufr_decode_sample.exe', 'bufr_encode_sample.exe', 'prepbufr_append_retrieve.exe', 'prepbufr_append_surface.exe', 'prepbufr_append_upperair.exe', 'prepbufr_decode_all.exe', 'prepbufr_encode_surface.exe', 'prepbufr_encode_upperair.exe', 'prepbufr_inventory.exe') if not check_files(expected_exe_files): edit_file('makefile', [['^\s*FC\s*=.*$', f'FC = {fc}'], ['-I\.\./\.\./dtc', '-I../../build'], ['-L\.\./\.\./dtc', '-L../../build'], ['-lbufr_i4r8', '-lbufr_v10.2.5']]) cli.notice('Compile bufr_tools ...') if args.verbose: run('make') else: run('make &> make.out') if check_files(expected_exe_files): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed!') else: cli.error( f'Failed! Check {args.gsi_root}/util/bufr_tools/make.out' ) else: cli.notice('GSI bufr_tools has been built.') os.chdir(f'{args.gsi_root}/util/Analysis_Utilities/read_diag/') expected_exe_files = ('read_diag_conv.exe', 'read_diag_conv_ens.exe', 'read_diag_rad.exe') if not check_files(expected_exe_files): edit_file('makefile', [[ 'include \.\./\.\./\.\./dtc/configure.gsi', '' ], ['\$\(SFC\)', fc], ['-I\.\./\.\./\.\./dtc', '-I../../../build'], [ '-L\.\./\.\./\.\./src -lgsi', '-L../../../build/lib -lgsilib_shrd' ], [ 'FLAGS= \$\(FFLAGS_DEFAULT\)', 'FLAGS = -fconvert=big-endian' ]]) cli.notice('Compile read_diag ...') if args.verbose: run('make') else: run('make &> make.out') if check_files(expected_exe_files): cli.notice('Succeeded.') else: if args.verbose: cli.error('Failed') else: cli.error( f'Failed! Check {args.gsi_root}/util/Analysis_Utilities/read_diag/make.out' ) else: cli.notice('GSI read_diag has been built.')
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.')
def build_upp(wrf_root, upp_root, args): if wrf_root != None: os.environ['WRF_DIR'] = wrf_root 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', 'ncdump'], stdout=subprocess.PIPE) if res.returncode == 0: os.environ['NETCDF'] = os.path.dirname( os.path.dirname(res.stdout.decode('utf-8'))) cli.notice(f'Set NETCDF to {os.environ["NETCDF"]}') 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!') version = upp_version(args.upp_root) if version < Version('4.1'): expected_exe_files = ('bin/copygb.exe', 'bin/ndate.exe', 'bin/unipost.exe') else: expected_exe_files = ('exec/unipost.exe') if not check_files(expected_exe_files): if not args.nceplibs_root: args.nceplibs_root = f'{os.path.dirname(args.upp_root)}/NCEPLIBS' if not os.path.isdir(args.nceplibs_root): cli.error('NCEPLIBS is not ready!') os.environ['NCEPLIBS_DIR'] = args.nceplibs_root if not check_files(expected_exe_files): os.chdir(upp_root) if args.force: run('./clean -a &> /dev/null') cli.notice('Configure UPP ...') child = pexpect.spawn('./configure') child.expect('Enter selection.*') if args.compiler_suite == 'intel': child.sendline('4') # Linux x86_64, Intel compiler (dmpar) elif args.compiler_suite == 'gnu': child.sendline('8') # Linux x86_64, gfortran compiler (dmpar) elif args.compiler_suite == 'pgi': child.sendline( '14') # Linux x86_64, PGI compiler: -f90=pgf90 (dmpar) child.wait() if args.compiler_suite == 'intel': edit_file('./configure.upp', [['mpif90', 'mpiifort'], ['mpicc', 'mpiicc']]) if 'LIBPNG_ROOT' in os.environ: edit_file('./configure.upp', [ ['-lpng', f'-L{os.environ["LIBPNG_ROOT"]}/lib -lpng'], [ 'GRIB2SUPT_INC\s*=\s*(.*)', f'GRIB2SUPT_INC = \\1 -I{os.environ["LIBPNG_ROOT"]}/include' ] ]) cli.notice('Compile UPP ...') run('./compile &> compile.out') if check_files(expected_exe_files): cli.notice('Succeeded.') else: cli.error(f'Failed! Check {upp_root}/compile.out') else: cli.notice('UPP is already built.')
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.')
args.wrfda_root, config, args, fg=fg) wrf.run_wrfda_update_bc(args.work_root + '/fa', args.wrfda_root, False, config, args) wrf.config_wrf(args.work_root + '/fa', args.wrf_root, args.wrfda_root, config, args) wrf.run_wrf(args.work_root + '/fa', args.wrf_root, config, args) # Interpolate reference at valid time. cli.banner(' Interpolate reference at valid time') ref_config = copy.deepcopy(config) ref_config['custom']['start_time'] = config['custom']['end_time'] if not args.ref_root: cli.warning('Use background as reference.') args.ref_root = args.bkg_root else: ref_config['custom']['background'] = { 'type': 'gfs', 'file_pattern': 'gdas.t{{ bkg_start_time.format("HH") }}z.pgrb2.*.f{{ "%03d" % bkg_forecast_hour }}', 'dir_pattern': 'gdas.{{ bkg_start_time.format("YYYYMMDD") }}/{{ bkg_start_time.format("HH") }}' } wrf.config_wps(args.work_root + '/ref', args.wps_root, args.geog_root, ref_config, args) run(f'ln -sf {args.work_root}/wps/geo_em.d01.nc {args.work_root}/ref/wps') wrf.run_wps_ungrib_metgrid(args.work_root + '/ref', args.wps_root, args.ref_root, ref_config, args)
def run_real(work_root, wps_work_dir, wrf_root, config, args, tag=None): start_time = config['custom']['start_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 os.path.isdir(wps_work_dir): cli.error(f'WPS work directory {wps_work_dir} does not exist!') 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) cli.stage(f'Run real.exe at {wrf_work_dir} ...') expected_files = [ 'wrfinput_d{:02d}_{}'.format(i + 1, start_time_str) for i in range(max_dom) ] expected_files.append('wrfbdy_d01') if not check_files(expected_files) or args.force: run('rm -f wrfinput_* met_em.*.nc') run(f'ln -sf {wps_work_dir}/met_em.*.nc .') try: dataset = Dataset(glob('met_em.*.nc')[0]) except: cli.error('Failed to open one of met_em.*.nc file!') # Check met_em file. if not 'num_st_layers' in dataset.dimensions or dataset.dimensions[ 'num_st_layers'].size == 0: cli.error( 'Failed to run ungrib and metgrid due to num_metgrid_soil_levels is zero!' ) namelist_input = f90nml.read('./namelist.input') namelist_input['domains']['num_metgrid_levels'] = dataset.dimensions[ 'num_metgrid_levels'].size namelist_input['physics']['num_land_cat'] = dataset.getncattr( 'NUM_LAND_CAT') if 'num_st_layers' in dataset.dimensions: namelist_input['domains'][ 'num_metgrid_soil_levels'] = dataset.dimensions[ 'num_st_layers'].size else: cli.warning( f'Dimension num_st_layers is not in {dataset.filepath()}! Set num_metgrid_soil_levels to 0.' ) namelist_input['domains']['num_metgrid_soil_levels'] = 0 dataset.close() namelist_input.write('./namelist.input', force=True) submit_job(f'{wrf_root}/run/real.exe', args.np, config, args, wait=True) for i in range(max_dom): if not os.path.isfile('wrfinput_d{0:02d}'.format(i + 1)): # Check if the failure is caused by parallel computing? cli.warning( 'Failed to run real.exe in parallel. Try to run in serial.' ) submit_job(f'{wrf_root}/run/real.exe', 1, config, args, wait=True) if not os.path.isfile('wrfinput_d{0:02d}'.format(i + 1)): cli.error( f'Still failed to generate wrfinput_d{0:02d}! See {wrf_work_dir}/rsl.error.0000.' .format(i + 1)) run('ln -sf wrfinput_d{0:02d} wrfinput_d{0:02d}_{1}'.format( i + 1, start_time_str)) if os.path.isfile('wrfbdy_d01'): run(f'ln -sf wrfbdy_d01 wrfbdy_d01_{start_time_str}') cli.notice('Succeeded.') else: run('ls -l wrfinput_* wrfbdy_*') cli.notice('File wrfinput_* already exist.')
def run_wrf(work_root, wrf_root, config, args, wrfda_work_dir=None, tag=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) end_time_str = end_time.format(datetime_fmt) max_dom = config['domains']['max_dom'] if not wrfda_work_dir: if tag != None: wrfda_work_dir = f'{work_root}/wrfda_{tag}' else: wrfda_work_dir = f'{work_root}/wrfda' elif not os.path.isdir(wrfda_work_dir): cli.error(f'run_wrf: {wrfda_work_dir} does not exist!') 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): cli.error(f'run_wrf: {wrf_work_dir} does not exist!') os.chdir(wrf_work_dir) all_wrfda_ok = True for dom_idx in range(max_dom): dom_str = 'd' + str(dom_idx + 1).zfill(2) if not copy_wrfda_output(dom_str, start_time_str, wrfda_work_dir): all_wrfda_ok = False break if not all_wrfda_ok: cli.warning('Do not use data assimilation.') expected_files = ['wrfinput_d{:02d}_{}'.format(i + 1, start_time_str) for i in range(max_dom)] expected_files.append(f'wrfbdy_d01_{start_time_str}') if not check_files(expected_files): cli.error('real.exe wasn\'t executed successfully!') for i in range(max_dom): run('ln -sf wrfinput_d{0:02d}_{1} wrfinput_d{0:02d}'.format(i + 1, start_time_str)) run(f'ln -sf wrfbdy_d01_{start_time_str} wrfbdy_d01') cli.stage(f'Run wrf.exe at {wrf_work_dir} ...') expected_files = ['wrfout_d{:02d}_{}'.format(i + 1, end_time_str) for i in range(max_dom)] if not check_files(expected_files) or args.force: run('rm -f wrfout_*') run(f'ln -sf {wrf_root}/run/LANDUSE.TBL .') run(f'ln -sf {wrf_root}/run/ozone_plev.formatted .') run(f'ln -sf {wrf_root}/run/ozone_lat.formatted .') run(f'ln -sf {wrf_root}/run/ozone.formatted .') run(f'ln -sf {wrf_root}/run/RRTM_DATA_DBL RRTM_DATA') run(f'ln -sf {wrf_root}/run/RRTMG_LW_DATA .') run(f'ln -sf {wrf_root}/run/RRTMG_SW_DATA .') run(f'ln -sf {wrf_root}/run/VEGPARM.TBL .') run(f'ln -sf {wrf_root}/run/SOILPARM.TBL .') run(f'ln -sf {wrf_root}/run/GENPARM.TBL .') retries = 0 while True: submit_job(f'{wrf_root}/run/wrf.exe', args.np, config, args, wait=True) if not check_files(expected_files): if retries == 0: cli.error(f'Failed! Check output {os.path.abspath(wrf_work_dir)}/rsl.error.0000.') retries = retries + 1 cli.warning(f'Failed to run wrf, retry it! {retries}') else: break cli.notice('Succeeded.') else: cli.notice('File wrfout_* already exist.') run(f'ls -l {wrf_work_dir}/wrfout_*')