Esempio n. 1
0
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'