def test_out_of_phase_interval_fails(clock_08, almost_default_grid): ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid, modify_core_nodes=True, lowering_rate=-1) # construct and run model times = [ 0.0, 1.0, 1.01, # next time is set to 2. Divisible warning 1.02, # new time < 2. Starting skips. Skipping warning 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 2.00, # 10 skips. Loop exits. Raises Assertion Error 3.0, # Does not get this far ] model = Basic( clock_08, almost_default_grid, water_erodibility=0.0, regolith_transport_parameter=0.0, boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh}, output_writers={ "out-of-phase-ow-fails": { "class": OWStaticWrapper, "kwargs": { "add_id": False, "times": times, }, }, }, # output_interval=6.0, output_dir=_TEST_OUTPUT_DIR, output_prefix="", save_first_timestep=True, save_last_timestep=True, ) skip_warning_msg = "next time that is less than or equal to the current" divisible_warning_msg = "time that is not divisible by the model step" # Copied from ErosionModel.run() so I can control the steps model._itters = [] if model.save_first_timestep: model.iteration = 0 model._itters.append(0) model.write_output() model.iteration = 1 def run_one_iteration(): time_now = model._model_time next_run_pause = min( # time_now + model.output_interval, model.clock.stop, model.next_output_time, model.clock.stop, ) assert next_run_pause > time_now print(f"Iteration {model.iteration:05d} Model time {model.model_time}") print( f" Run for {next_run_pause - time_now}, (step = {model.clock.step})" ) model.run_for(model.clock.step, next_run_pause - time_now) time_now = model._model_time model._itters.append(model.iteration) model.write_output() model.iteration += 1 print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 0.0 and model.next_output_time == 1.0 warning_msg_sample = "time that is not divisible by the model step" with pytest.warns(UserWarning, match=warning_msg_sample): run_one_iteration() # times_iter returns 1.01, which is then delayed to 2.0 print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 1.00 and model.next_output_time == 2.0 # time_iter returns 1.02, which triggers skips and eventually fails with pytest.warns(UserWarning) as all_warnings, pytest.raises( AssertionError): run_one_iteration() ignored_warnings = [RuntimeWarning] for warn_info in all_warnings: warn_type = warn_info.category if warn_type in ignored_warnings: continue try: assert warn_type == UserWarning message = warn_info.message.args[0] is_skip_warning = skip_warning_msg in message is_divisible_warning = divisible_warning_msg in message assert is_skip_warning or is_divisible_warning except AssertionError: print(warn_info) # So I can see other warnings raise model.remove_output()
def test_out_of_phase_interval_warns(clock_08, almost_default_grid): ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid, modify_core_nodes=True, lowering_rate=-1) # construct and run model times = [ 0.0, 1.0, 1.01, # next time is set to 2. Divisible warning 1.02, # new time < 2. Starting skips. Skipping warning 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 3.00, # Finds suitable time on 10th skip. ] model = Basic( clock_08, almost_default_grid, water_erodibility=0.0, regolith_transport_parameter=0.0, boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh}, output_writers={ "out-of-phase-skipping-ow": { "class": OWStaticWrapper, "kwargs": { "add_id": False, "times": times, }, }, }, # output_interval=6.0, output_dir=_TEST_OUTPUT_DIR, output_prefix="", save_first_timestep=True, save_last_timestep=True, ) skip_warning_msg = "next time that is less than or equal to the current" divisible_warning_msg = "time that is not divisible by the model step" # Copied from ErosionModel.run() so I can control the steps model._itters = [] if model.save_first_timestep: model.iteration = 0 model._itters.append(0) model.write_output() model.iteration = 1 def run_one_iteration(): time_now = model._model_time next_run_pause = min( model.next_output_time, model.clock.stop, ) assert next_run_pause > time_now print(f"Iteration {model.iteration:05d} Model time {model.model_time}") print( f" Run for {next_run_pause - time_now}, (step = {model.clock.step})" ) model.run_for(model.clock.step, next_run_pause - time_now) time_now = model._model_time model._itters.append(model.iteration) model.write_output() model.iteration += 1 print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 0.0 and model.next_output_time == 1.0 warning_msg_sample = "time that is not divisible by the model step" with pytest.warns(UserWarning, match=warning_msg_sample): run_one_iteration() # times_iter returns 1.01, which is then delayed to 2.0 print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 1.00 and model.next_output_time == 2.0 # time_iter returns 1.02, which triggers skips but eventually finds 3.0 with pytest.warns(UserWarning) as all_warnings: run_one_iteration() print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 2.0 and model.next_output_time == 3.0 ignored_warnings = [RuntimeWarning] for warn_info in all_warnings: warn_type = warn_info.category if warn_type in ignored_warnings: continue try: assert warn_type == UserWarning message = warn_info.message.args[0] is_skip_warning = skip_warning_msg in message is_divisible_warning = divisible_warning_msg in message assert is_skip_warning or is_divisible_warning except AssertionError: print(warn_info) # So I can see other warnings raise run_one_iteration() # times_iter returns 20.0 print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 3.0 and model.next_output_time == 20.0 run_one_iteration() # Model finishes print(f"t={model.model_time}, nt={model.next_output_time}") assert model.model_time == 20.0 and model.next_output_time == np.inf # now that the model is finished running, execute finalize. model.finalize() # Check that there is a file for t=3.0 good_filename = f"out-of-phase-skipping-ow_time-{3.0:012.1f}.txt" good_filepath = get_output_filepath(good_filename) assert os.path.isfile(good_filepath), f"{good_filepath} should exist" model.remove_output()