diff --git a/docs/src/changelog.md b/docs/src/changelog.md index ec2e38872..3b96a025e 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -25,8 +25,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - For the computation of Gash interception model parameter `e_r` multiply the precipitation input with the canopy fraction (this was only done for the potential evapotranspiration input). - - + - Function `BMI.update_until` could throw an `InexactError: Int64` caused by a not whole + number, representing how many times (`steps`) an update of a wflow model is required. This + is fixed by using `divrem` for the computation of the number of `steps` in this function. + An error is thrown when the absolute remainder of `divrem` is larger than `eps()`, or when + the number of `steps` is negative. + ### Changed - Stop exposing scalar variables through BMI. The `BMI.get_value_ptr` function was not working correctly for scalar model variables (a `view` was applied). Only a few scalar diff --git a/src/bmi.jl b/src/bmi.jl index 9aeab436e..def51be69 100644 --- a/src/bmi.jl +++ b/src/bmi.jl @@ -65,9 +65,19 @@ end function BMI.update_until(model::Model, time::Float64) @unpack clock, network, config = model - curtime = BMI.get_current_time(model) - n = Int(max(0, (time - curtime) / model.clock.Δt.value)) - for _ = 1:n + t = BMI.get_current_time(model) + _div, _rem = divrem(time - t, model.clock.Δt.value) + steps = Int(_div) + if steps < 0 + error("The current model timestamp $t is larger than provided `time` $time") + elseif abs(_rem) > eps() + error_message = string( + "Provided `time` $time minus the current model timestamp $t", + " is not an integer multiple of model time step $(model.clock.Δt.value)", + ) + error(error_message) + end + for _ = 1:steps model = run_timestep(model) end return model diff --git a/test/bmi.jl b/test/bmi.jl index 75470c4d5..dfd1a5577 100644 --- a/test/bmi.jl +++ b/test/bmi.jl @@ -117,8 +117,12 @@ tomlpath = joinpath(@__DIR__, "sbm_config.toml") @testset "update until and finalize" begin time = BMI.get_current_time(model) + 2 * BMI.get_time_step(model) - @test_logs (:info, "update model until 9.470304e8") model = BMI.update_until(model, time) + @test model.clock.iteration == 3 + time_off = BMI.get_current_time(model) + 1 * BMI.get_time_step(model) + 1e-06 + @test_throws ErrorException model = BMI.update_until(model, time_off) + @test_throws ErrorException model = + BMI.update_until(model, time - BMI.get_time_step(model)) BMI.finalize(model) end