Skip to content

Commit

Permalink
Merge branch 'main' into balance_error_at_runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
SouthEndMusic committed Aug 29, 2024
2 parents 0780763 + 23bbbbc commit f131b9d
Show file tree
Hide file tree
Showing 33 changed files with 370 additions and 100 deletions.
12 changes: 12 additions & 0 deletions .docker/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: '2'

services:
qgis:
image: qgis/qgis:release-3_34
container_name: qgis
volumes:
- ../ribasim_qgis/:/tests_directory/ribasim_qgis
environment:
- CI=true
- DISPLAY=:99
tty: true
7 changes: 7 additions & 0 deletions .docker/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -eux

docker compose -f compose.yml up -d --force-recreate --remove-orphans
echo "Installation of the plugin Ribasim"
docker exec -t qgis sh -c "qgis_setup.sh ribasim_qgis"
echo "Containers are running"
6 changes: 6 additions & 0 deletions .docker/stop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -eux

echo 'Stopping/killing containers'
docker compose -f compose.yml kill
docker compose -f compose.yml rm -f
4 changes: 4 additions & 0 deletions .docker/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -eux

docker exec -t qgis sh -c "cd /tests_directory && xvfb-run -a qgis_testrunner.sh ribasim_qgis.tests"
40 changes: 17 additions & 23 deletions .github/workflows/qgis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,21 @@ on:
pull_request:
paths-ignore: [".teamcity/**"]
merge_group:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: QGIS plugin ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
- macOS-latest
- windows-latest
steps:
- uses: actions/checkout@v4
- uses: prefix-dev/[email protected]
with:
pixi-version: "latest"
- name: Run tests
run: pixi run test-ribasim-qgis-cov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
test-qgis:
name: "Test"
runs-on: ubuntu-latest
defaults:
run:
working-directory: .docker
steps:
- uses: actions/checkout@v4
- uses: prefix-dev/[email protected]
with:
pixi-version: "latest"
- name: Run tests
run: pixi run test-ribasim-qgis-docker
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
10 changes: 2 additions & 8 deletions Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
version = "1.2.0"

[[deps.NonlinearSolve]]
deps = ["ADTypes", "ArrayInterface", "ConcreteStructs", "DiffEqBase", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LazyArrays", "LineSearches", "LinearAlgebra", "LinearSolve", "MaybeInplace", "PrecompileTools", "Preferences", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SimpleNonlinearSolve", "SparseArrays", "SparseDiffTools", "StaticArraysCore", "SymbolicIndexingInterface", "TimerOutputs"]
deps = ["ADTypes", "ArrayInterface", "ConcreteStructs", "DiffEqBase", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LazyArrays", "LineSearches", "LinearAlgebra", "LinearSolve", "MaybeInplace", "PrecompileTools", "Preferences", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SimpleNonlinearSolve", "SparseArrays", "SparseDiffTools", "StaticArraysCore", "SymbolicIndexingInterface"]
git-tree-sha1 = "3adb1e5945b5a6b1eaee754077f25ccc402edd7f"
uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
version = "3.13.1"
Expand Down Expand Up @@ -1418,7 +1418,7 @@ uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "3.5.18"

[[deps.Ribasim]]
deps = ["Accessors", "Arrow", "BasicModelInterface", "CodecZstd", "ComponentArrays", "Configurations", "DBInterface", "DataInterpolations", "DataStructures", "Dates", "DiffEqCallbacks", "EnumX", "FiniteDiff", "ForwardDiff", "Graphs", "HiGHS", "Integrals", "IterTools", "JuMP", "Legolas", "LinearSolve", "Logging", "LoggingExtras", "MetaGraphsNext", "OrdinaryDiffEq", "PreallocationTools", "SQLite", "SciMLBase", "SparseArrays", "SparseConnectivityTracer", "StructArrays", "Tables", "TerminalLoggers", "TranscodingStreams"]
deps = ["Accessors", "Arrow", "BasicModelInterface", "CodecZstd", "ComponentArrays", "Configurations", "DBInterface", "DataInterpolations", "DataStructures", "Dates", "DiffEqCallbacks", "EnumX", "FiniteDiff", "ForwardDiff", "Graphs", "HiGHS", "Integrals", "IterTools", "JuMP", "Legolas", "LinearSolve", "LineSearches", "Logging", "LoggingExtras", "MetaGraphsNext", "OrdinaryDiffEq", "PreallocationTools", "SQLite", "SciMLBase", "SparseArrays", "SparseConnectivityTracer", "StructArrays", "Tables", "TerminalLoggers", "TranscodingStreams"]
path = "core"
uuid = "aac5e3d9-0b8f-4d4f-8241-b1a7a9632635"
version = "2024.10.0"
Expand Down Expand Up @@ -1826,12 +1826,6 @@ weakdeps = ["RecipesBase"]
[deps.TimeZones.extensions]
TimeZonesRecipesBaseExt = "RecipesBase"

[[deps.TimerOutputs]]
deps = ["ExprTools", "Printf"]
git-tree-sha1 = "5a13ae8a41237cff5ecf34f73eb1b8f42fff6531"
uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
version = "0.5.24"

[[deps.TranscodingStreams]]
git-tree-sha1 = "d73336d81cafdc277ff45558bb7eaa2b04a8e472"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
Expand Down
2 changes: 2 additions & 0 deletions core/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Integrals = "de52edbc-65ea-441a-8357-d3a637375a31"
IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
Legolas = "741b9549-f6ed-4911-9fbf-4a1c0c97f0cd"
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
LoggingExtras = "e6f89c97-d47a-5376-807f-9c37f3926c36"
Expand Down Expand Up @@ -71,6 +72,7 @@ IOCapture = "0.2"
IterTools = "1.4"
JuMP = "1.15"
Legolas = "0.5"
LineSearches = "7"
LinearSolve = "2.24"
Logging = "<0.0.1, 1"
LoggingExtras = "1"
Expand Down
34 changes: 13 additions & 21 deletions core/ext/RibasimMakieExt.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module RibasimMakieExt
using DataFrames: DataFrame
using Makie: Figure, Axis, lines!, axislegend
using Makie: Figure, Axis, scatterlines!, axislegend
using Ribasim: Ribasim, Model

function Ribasim.plot_basin_data!(model::Model, ax::Axis, column::Symbol)
basin_data = DataFrame(Ribasim.basin_table(model))
for node_id in unique(basin_data.node_id)
group = filter(:node_id => ==(node_id), basin_data)
lines!(ax, group.time, getproperty(group, column); label = "Basin #$node_id")
scatterlines!(ax, group.time, getproperty(group, column); label = "Basin #$node_id")
end

axislegend(ax)
Expand All @@ -23,31 +23,23 @@ function Ribasim.plot_basin_data(model::Model)
f
end

function Ribasim.plot_flow!(
model::Model,
ax::Axis,
edge_id::Int32;
skip_conservative_out = false,
)
function Ribasim.plot_flow!(model::Model, ax::Axis, edge_metadata::Ribasim.EdgeMetadata)
flow_data = DataFrame(Ribasim.flow_table(model))
flow_data = filter(:edge_id => ==(edge_id), flow_data)
first_row = first(flow_data)
# Skip outflows of conservative nodes because these are the same as the inflows
if skip_conservative_out &&
Ribasim.NodeType.T(first_row.from_node_type) in Ribasim.conservative_nodetypes
return nothing
end
label = "$(first_row.from_node_type) #$(first_row.from_node_id)$(first_row.to_node_type) #$(first_row.to_node_id)"
lines!(ax, flow_data.time, flow_data.flow_rate; label)
flow_data = filter(:edge_id => ==(edge_metadata.id), flow_data)
label = "$(edge_metadata.edge[1])$(edge_metadata.edge[2])"
scatterlines!(ax, flow_data.time, flow_data.flow_rate; label)
return nothing
end

function Ribasim.plot_flow(model::Model)
function Ribasim.plot_flow(model::Model; skip_conservative_out = true)
f = Figure()
ax = Axis(f[1, 1]; xlabel = "time", ylabel = "flow rate [m³s⁻¹]")
edge_ids = unique(Ribasim.flow_table(model).edge_id)
for edge_id in edge_ids
Ribasim.plot_flow!(model, ax, edge_id; skip_conservative_out = true)
for edge_metadata in values(model.integrator.p.graph.edge_data)
if skip_conservative_out &&
edge_metadata.edge[1].type in Ribasim.conservative_nodetypes
continue
end
Ribasim.plot_flow!(model, ax, edge_metadata)
end
axislegend(ax)
f
Expand Down
13 changes: 11 additions & 2 deletions core/src/Ribasim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ For more granular access, see:
module Ribasim

# Algorithms for solving ODEs.
using OrdinaryDiffEq: OrdinaryDiffEq, OrdinaryDiffEqRosenbrockAdaptiveAlgorithm, get_du
using OrdinaryDiffEq:
OrdinaryDiffEq,
OrdinaryDiffEqRosenbrockAdaptiveAlgorithm,
get_du,
AbstractNLSolver,
relax!,
_compute_rhs!,
calculate_residuals!
using LineSearches: BackTracking

# Algorithms for solving explicit integral problems
using Integrals: IntegralProblem, solve, QuadGKJL
Expand All @@ -34,7 +42,8 @@ using SciMLBase:
ODEProblem,
ODESolution,
VectorContinuousCallback,
get_proposed_dt
get_proposed_dt,
DEIntegrator

# Automatically detecting the sparsity pattern of the Jacobian of water_balance!
# through operator overloading
Expand Down
6 changes: 4 additions & 2 deletions core/src/config.jl
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ const algorithms = Dict{String, Type}(
)

"Create an OrdinaryDiffEqAlgorithm from solver config"
function algorithm(solver::Solver)::OrdinaryDiffEqAlgorithm
function algorithm(solver::Solver; u0 = [])::OrdinaryDiffEqAlgorithm
algotype = get(algorithms, solver.algorithm, nothing)
if algotype === nothing
options = join(keys(algorithms), ", ")
Expand All @@ -240,7 +240,9 @@ function algorithm(solver::Solver)::OrdinaryDiffEqAlgorithm
end
kwargs = Dict{Symbol, Any}()
if algotype <: OrdinaryDiffEqNewtonAdaptiveAlgorithm
kwargs[:nlsolve] = NLNewton(; relax = 0.1)
kwargs[:nlsolve] = NLNewton(;
relax = Ribasim.MonitoredBackTracking(; z_tmp = copy(u0), dz_tmp = copy(u0)),
)
end
# not all algorithms support this keyword
kwargs[:autodiff] = solver.autodiff
Expand Down
4 changes: 3 additions & 1 deletion core/src/logging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ function log_bottlenecks(model; converged::Bool)
end
push!(errors, node_id => error)
end
@logmsg level "Convergence bottlenecks in descending order of severity:" errors...
if !isempty(errors)
@logmsg level "Convergence bottlenecks in descending order of severity:" errors...
end
else
algorithm = model.config.solver.algorithm
@logmsg level "Convergence bottlenecks are not shown for the chosen solver algorithm." algorithm
Expand Down
4 changes: 3 additions & 1 deletion core/src/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ function Model(config_path::AbstractString)::Model
end

function Model(config::Config)::Model
alg = algorithm(config.solver)
db_path = input_path(config, config.database)
if !isfile(db_path)
@error "Database file not found" db_path
Expand Down Expand Up @@ -109,6 +108,9 @@ function Model(config::Config)::Model
u0 = ComponentVector{Float64}(; storage, integral)
du0 = zero(u0)

# The Solver algorithm
alg = algorithm(config.solver; u0)

# Synchronize level with storage
set_current_basin_properties!(parameters.basin, u0, du0)

Expand Down
10 changes: 7 additions & 3 deletions core/src/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,8 @@ function Basin(db::DB, config::Config, graph::MetaGraph)::Basin
error("Invalid Basin / profile table.")
end

level_to_area = LinearInterpolation.(area, level; extrapolate = true)
level_to_area =
LinearInterpolation.(area, level; extrapolate = true, cache_parameters = true)
storage_to_level = invert_integral.(level_to_area)

t_end = seconds_since(config.endtime, config.starttime)
Expand Down Expand Up @@ -923,6 +924,7 @@ function user_demand_static!(
fill(first_row.return_factor, 2),
return_factor_old.t;
extrapolate = true,
cache_parameters = true,
)
min_level[user_demand_idx] = first_row.min_level

Expand Down Expand Up @@ -1028,8 +1030,10 @@ function UserDemand(db::DB, config::Config, graph::MetaGraph)::UserDemand
]
demand_from_timeseries = fill(false, n_user)
allocated = fill(Inf, n_user, n_priority)
return_factor =
[LinearInterpolation(zeros(2), trivial_timespan) for i in eachindex(node_ids)]
return_factor = [
LinearInterpolation(zeros(2), trivial_timespan; cache_parameters = true) for
i in eachindex(node_ids)
]
min_level = zeros(n_user)

# Process static table
Expand Down
11 changes: 11 additions & 0 deletions core/src/solve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,20 @@ function water_balance!(
# Formulate du (controlled by PidControl)
formulate_du_pid_controlled!(du, graph, pid_control)

# https://github.com/Deltares/Ribasim/issues/1705#issuecomment-2283293974
stop_declining_negative_storage!(du, u)

return nothing
end

function stop_declining_negative_storage!(du, u)
for (i, s) in enumerate(u.storage)
if s < 0
du.storage[i] = max(du.storage[i], 0.0)
end
end
end

function formulate_continuous_control!(du, p, t)::Nothing
(; compound_variable, target_ref, func) = p.continuous_control

Expand Down
Loading

0 comments on commit f131b9d

Please sign in to comment.