Skip to content

Implement success - #2200

Merged
visr merged 6 commits into
mainfrom
success
Apr 2, 2025
Merged

Implement success#2200
visr merged 6 commits into
mainfrom
success

Conversation

@visr

@visr visr commented Apr 1, 2025

Copy link
Copy Markdown
Member

This is a follow-up of #2191. An issue with that is that it logged a warning about crashing simulations also when it succeeded. Also it didn't log the bottlenecks when you interrupt a (hanging) simulation.

Now it does both, this is what is shown when interrupting a simulation, stacktrace is clipped off:

┌ Info: Starting a Ribasim simulation.
│   toml_path = c:\Users\visser_mn\Downloads\lhm-sel\lhm-sel.toml
│   cli.ribasim_version = 2025.2.0
│   starttime = 2020-01-01T00:00:00
│   endtime = 2021-01-01T00:00:00
└ @ Ribasim C:\ProgramData\DevDrives\repo\ribasim\Ribasim\core\src\main.jl:40
┌ Warning: Simulation crashed or interrupted.
└ @ Ribasim C:\ProgramData\DevDrives\repo\ribasim\Ribasim\core\src\main.jl:51
┌ Warning: Convergence bottlenecks in descending order of severity:
│   Outlet #591225 = 48782.889544290454
│   Outlet #591226 = 48782.889544290454
│   ManningResistance #340784 = 0.04819449424793999
│   Pump #340303 = 0.045638255628477994
│   Pump #340194 = 0.04563825461806383
└ @ Ribasim C:\ProgramData\DevDrives\repo\ribasim\Ribasim\core\src\logging.jl:55
ERROR: InterruptException:
Stacktrace:
  [1] bracketstrictlymontonic(v::Vector{Float64}, x::Float64, guess::Int64, o::Base.Order.ForwardOrdering)

This implements Base.success(::Model)::Bool. Before we checked the SciML retcode. I noticed that the retcode of an ongoing simulation that gets interrupted is also successfull. So now we check both the retcode and if it is_finished.

@visr
visr requested a review from SouthEndMusic April 1, 2025 11:46
@visr

visr commented Apr 1, 2025

Copy link
Copy Markdown
Member Author

It was good that this adds is_finished, which now checks if the t at the end is equal to endtime, because it highlighted an issue that I wasn't aware of. Two models had allocation.timestep = 100_000, which doesn't fit exactly in days. So we had a remainder timestep that we didn't take. This is now fixed:

Ribasim/core/src/model.jl

Lines 350 to 359 in e007c98

for _ in 1:n_allocation_times
update_allocation!(integrator)
SciMLBase.step!(integrator, timestep, true)
end
# Any possible remaining step (< allocation.timestep) after the last allocation
dt = tspan[end] - integrator.t
if dt > 0
update_allocation!(integrator)
SciMLBase.step!(integrator, dt, true)
end

At first I thought SciMLBase.solve! perhaps didn't mean it would end at the endtime, but it does, it was our own custom allocation timestep code that was wrong.

@SouthEndMusic SouthEndMusic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, added some nits

Comment thread core/src/bmi.jl

function BMI.update(model::Model)::Nothing
step!(model.integrator)
SciMLBase.step!(model.integrator)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? Was there a name conflict?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this PR we overloaded SciMLBase.solve! and SciMLBase.step!, and now they are just Ribasim.solve! and Ribasim.solve!, so internally solve! is Ribasim.solve and we qualify the SciMLBase methods.

The overloading was not really useful and potentially confusing. And with some bad luck they can lead to more invalidations.

Comment thread core/src/main.jl
function display_error(io::Union{IOStream, Nothing} = nothing)::Nothing
stack = current_exceptions()
Base.invokelatest(Base.display_error, stack)
if io !== nothing

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if io !== nothing
if !isnothing(io)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit hesitant because I believe the io !== nothing can be easier on the compiler. We use === and !== in many places, more than isnothing. See for instance JuliaLang/julia#35585. It might be better in more recent julia versions though.

Comment thread core/src/model.jl Outdated
if config.allocation.use_allocation
(; tspan) = integrator.sol.prob
(; timestep) = config.allocation
allocation_times = 0:timestep:(tspan[end] - timestep)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like allocation_times is only used to determine n_allocation_times, so maybe this can be simply

n_allocation_times = int(floor(tspan[end]/timestep))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, good call.

Comment thread core/test/bmi_test.jl
Comment on lines +12 to +13
endtime = BMI.get_end_time(model)
@test endtime ≈ 3.16224e7

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? The value is the same. I just need the variable for an extra test of the time at the end through BMI.

@visr
visr merged commit c47d30b into main Apr 2, 2025
@visr
visr deleted the success branch April 2, 2025 11:45
@visr visr mentioned this pull request Apr 14, 2025
visr added a commit that referenced this pull request Apr 15, 2025
## [v2025.3.0] - 2025-04-14

The only breaking change in this release is to disallow connecting a
single FlowBoundary to multiple Basins.
There are large improvements in the ability to visualize results on the
map in QGIS.
We also welcome the Junction node to the family, which will help laying
out networks in a recognizable manner.

### Added
- Add spatio-temporal results layers to QGIS.
[#2208](#2208)
- Add topological (straight line) link view toggle to QGIS.
[#2208](#2208)
- Added [Junction](https://ribasim.org/reference/node/junction.html)
node type. [#2175](#2175)
- Write results and log bottlenecks also on an interrupt or crash.
[#2191](#2191)
[#2200](#2200)
- Log computation time and save it to `solver_stats.arrow`.
[#2209](https://github.com/Deltares/Ribasim/pull/)
- Experimental support for writing the model network and results into
files used by Delft-FEWS,
[`model.to_fews`](`https://ribasim.org/reference/python/Model.html#ribasim.Model.to_fews`).
[#2161](#2161)
- Document
[`results/concentration.arrow`](https://ribasim.org/reference/usage.html#concentration---concentration.arrow).
[#2165](#2165)

### Changed
- Allow max 1 outflow neighbour for FlowBoundary.
[#2192](#2192)
- Automatic differentiation is enabled by default again, `autodiff =
true`, leading to better performance.
[#2137](#2137)
[#2183](#2183)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants