def test_run_candidate_channel_only(candidate_sim, candidate_channel_only_sim, output_dir, ncores, capsys): if candidate_sim.model.model_config.lower().find('nwm') < 0: pytest.skip('Channel-only test only applicable to nwm_ana config') with capsys.disabled(): print("\nQuestion: The candidate channel-only mode runs successfully?", end='') # Dont recompile the model, just use the candidate's model. candidate_channel_only_sim.model = candidate_sim.model # Set the forcing directory # Set run directory and go for execution. run_dir = output_dir / 'run_candidate_channel_only' run_dir.mkdir(parents=True) os.chdir(str(run_dir)) # Job exe_command = ('mpirun -np {0} ./wrf_hydro.exe').format(str(ncores)) job = wrfhydropy.Job(job_id='run_candidate_channel_only', exe_cmd=exe_command) candidate_channel_only_sim.add(job) candidate_channel_only_sim.jobs[0]._hrldas_namelist['noahlsm_offline']['indir'] = \ str(output_dir / 'run_candidate') # Run with warnings.catch_warnings(): warnings.simplefilter("ignore") candidate_channel_only_sim.compose() with capsys.disabled(): print('\nwaiting for job to complete...', end='') candidate_channel_only_sim.run() # Wait to collect until job has finished. All test runs are performed on a single job with # job_id='test_job' wait_job(candidate_channel_only_sim) candidate_channel_only_sim.collect() candidate_channel_only_sim.pickle( run_dir.joinpath('WrfHydroSim_collected.pkl')) # Check job run statuses for job in candidate_channel_only_sim.jobs: assert job.exit_status == 0, \ "Candidate channel-only code run exited with non-zero status"
def test_perfrestart_candidate_channel_only(output_dir): candidate_channel_only_sim_file = \ output_dir / 'run_candidate_channel_only' / 'WrfHydroSim.pkl' candidate_channel_only_collected_file = \ output_dir / 'run_candidate_channel_only' / 'WrfHydroSim_collected.pkl' if candidate_channel_only_collected_file.is_file() is False: pytest.skip( 'candidate_channel_only run object not found, skipping test') print( "\nQuestion: The candidate_channel_only outputs from a restart run match the outputs " "from standard run?\n", end='') print('\n') # Load initial run model object and copy candidate_channel_only_sim = \ pickle.load(candidate_channel_only_sim_file.open(mode="rb")) candidate_channel_only_sim_expected = \ pickle.load(candidate_channel_only_collected_file.open(mode="rb")) candidate_channel_only_sim_restart = copy.deepcopy( candidate_channel_only_sim) # Set run directory run_dir = output_dir / 'restart_candidate_channel_only' run_dir.mkdir(parents=True) os.chdir(str(run_dir)) # Get a new start time 1 hour later restart_job = candidate_channel_only_sim_restart.jobs[0] restart_job.model_start_time = restart_job.model_start_time + dt.timedelta( hours=2) # Get restart files from previous run and symlink into restart sim dir # Hydro: Use actual time listed in meta data not filename or positional list index for restart_file in candidate_channel_only_sim_expected.output.restart_hydro: restart_time = restart_file.open().Restart_Time restart_time = pd.to_datetime(restart_time, format='%Y-%m-%d_%H:%M:%S') if restart_time == restart_job.model_start_time: candidate_hydro_restart_file = pathlib.Path(restart_file.name) candidate_hydro_restart_file.symlink_to(restart_file) # Nudging: Use actual time listed in meta data not filename or positional list index for restart_file in candidate_channel_only_sim_expected.output.restart_nudging: restart_time = restart_file.open().modelTimeAtOutput restart_time = pd.to_datetime(restart_time, format='%Y-%m-%d_%H:%M:%S') if restart_time == restart_job.model_start_time: candidate_nudging_restart_file = pathlib.Path(restart_file.name) candidate_nudging_restart_file.symlink_to(restart_file) # Compose and run # Catch warnings related to missing start and end job times with warnings.catch_warnings(): warnings.simplefilter("ignore") candidate_channel_only_sim_restart.compose(force=True) print('\nwaiting for job to complete...', end='') candidate_channel_only_sim_restart.run() # Wait to collect until job has finished. All test runs are performed on a single job with wait_job(candidate_channel_only_sim_restart) candidate_channel_only_sim_restart.collect() candidate_channel_only_sim_restart.pickle( run_dir.joinpath('WrfHydroSim_collected.pkl')) # Check outputs with warnings.catch_warnings(): warnings.simplefilter("ignore") diffs = wrfhydropy.outputdiffs.OutputDataDiffs( candidate_channel_only_sim_restart.output, candidate_channel_only_sim_expected.output) # Assert all diff values are 0 and print diff stats if not has_diffs = any(value != 0 for value in diffs.diff_counts.values()) if has_diffs: eprint(diffs.diff_counts) for key, value in diffs.diff_counts.items(): if value != 0: diffs = getattr(diffs, key) eprint('\n' + key + '\n') for diff in diffs: eprint(diff) assert has_diffs is False, \ 'Outputs for candidate run do not match outputs from candidate restart run'
def test_ncores_candidate_channel_only(output_dir): candidate_channel_only_sim_file = \ output_dir / 'run_candidate_channel_only' / 'WrfHydroSim.pkl' candidate_channel_only_collected_file = \ output_dir / 'run_candidate_channel_only' / 'WrfHydroSim_collected.pkl' if candidate_channel_only_collected_file.is_file() is False: pytest.skip( 'candidate_channel_only collected run object not found, skipping test.' ) print( "\nQuestion: The candidate_channel-only output files from an ncores runmatch those " "from an ncores-1 run?\n", end='') print('\n') candidate_channel_only_sim = \ pickle.load(candidate_channel_only_sim_file.open("rb")) candidate_channel_only_sim_expected = \ pickle.load(candidate_channel_only_collected_file.open("rb")) candidate_channel_only_sim_ncores = copy.deepcopy( candidate_channel_only_sim) run_dir = output_dir / 'ncores_candidate_channel_only' run_dir.mkdir(parents=True) os.chdir(str(run_dir)) old_job = candidate_channel_only_sim.jobs[0] new_job = wrfhydropy.Job(job_id='ncores_candidate', exe_cmd=old_job._exe_cmd) # Remove old job and add new job candidate_channel_only_sim_ncores.jobs.pop(0) candidate_channel_only_sim_ncores.add(new_job) # Edit the sim object number of cores if candidate_channel_only_sim_ncores.scheduler is not None: candidate_channel_only_sim_ncores.scheduler.nproc = \ candidate_channel_only_sim_ncores.scheduler.nproc - 1 else: orig_exe_cmd = candidate_channel_only_sim_ncores.jobs[0]._exe_cmd orig_exe_cmd = orig_exe_cmd.replace('-np 2', '-np 1') # Recompose into new directory and run # catch warnings related to missing start and end job times with warnings.catch_warnings(): warnings.simplefilter("ignore") candidate_channel_only_sim_ncores.compose(force=True) print('\nwaiting for job to complete...', end='') candidate_channel_only_sim_ncores.run() # Wait to collect until job has finished. All test runs are performed on a single job with # job_id='test_job' wait_job(candidate_channel_only_sim_ncores) candidate_channel_only_sim_ncores.collect() candidate_channel_only_sim_ncores.pickle( run_dir.joinpath('WrfHydroSim_collected.pkl')) # Check outputs with warnings.catch_warnings(): warnings.simplefilter("ignore") diffs = wrfhydropy.outputdiffs.OutputDataDiffs( candidate_channel_only_sim_ncores.output, candidate_channel_only_sim_expected.output) # Assert all diff values are 0 and print diff stats if not has_diffs = any(value != 0 for value in diffs.diff_counts.values()) if has_diffs: eprint(diffs.diff_counts) for key, value in diffs.diff_counts.items(): if value != 0: diffs = getattr(diffs, key) eprint('\n' + key + '\n') for diff in diffs: eprint(diff) assert has_diffs is False, \ 'Outputs for candidate_channel_only run with ncores do not match outputs with ncores-1'