Skip to content

Commit 07e985d

Browse files
SouthEndMusicvisr
andauthored
Smoother rating curve (#2458)
Fixes #1919 --------- Co-authored-by: Martijn Visser <[email protected]>
1 parent b87c7b2 commit 07e985d

18 files changed

+1186
-412
lines changed

Manifest.toml

Lines changed: 696 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ OteraEngine = "b2d7f28f-acd6-4007-8b26-bc27716e5513"
5656
PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d"
5757
PiecewiseLinearOpt = "0f51c51e-adfa-5141-8a04-d40246b8977c"
5858
PkgToSoftwareBOM = "6254a0f9-6143-4104-aa2e-fd339a2830a6"
59+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
5960
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
6061
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
6162
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"

Ribasim-python.spdx.json

Lines changed: 278 additions & 166 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Ribasim.spdx.json

Lines changed: 118 additions & 155 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ CodecZstd = "0.7, 0.8"
6363
Configurations = "0.17"
6464
DBInterface = "2.4"
6565
DataFrames = "1.4"
66-
DataInterpolations = "8.1"
66+
DataInterpolations = "8.3"
6767
DataStructures = "0.18"
6868
Dates = "1"
6969
DelimitedFiles = "1.9.1"
@@ -97,7 +97,7 @@ Printf = "1.11.0"
9797
SQLite = "1.5.1"
9898
SciMLBase = "2.36"
9999
SparseArrays = "1"
100-
SparseConnectivityTracer = "0.6.20"
100+
SparseConnectivityTracer = "1"
101101
SparseMatrixColorings = "0.4.14"
102102
Statistics = "1"
103103
StructArrays = "0.6.13, 0.7"

core/regression_test/regression_test.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
@testset "Results values" begin
3838
@test basin.storage[1] 1.0f0
3939
@test basin.level[1] 0.044711584f0
40-
@test basin.storage[end] 16.530443267f0 atol = 0.02
41-
@test basin.level[end] 0.181817438f0 atol = 1e-4
40+
@test basin.storage[end] 62.2290641115f0 atol = 0.02
41+
@test basin.level[end] 0.352778f0 atol = 1e-4
4242
@test flow.flow_rate[1] basin.outflow_rate[1]
4343
@test all(q -> abs(q) < 1e-7, basin.balance_error)
4444
@test all(err -> abs(err) < 0.01, basin.relative_error)

core/src/Ribasim.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ using LinearAlgebra: mul!
6464
using DataInterpolations:
6565
ConstantInterpolation,
6666
LinearInterpolation,
67-
SmoothedLinearInterpolation,
67+
PCHIPInterpolation,
68+
CubicHermiteSpline,
6869
SmoothedConstantInterpolation,
6970
LinearInterpolationIntInv,
7071
invert_integral,

core/src/parameter.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,24 +166,25 @@ const ScalarLinearInterpolation = LinearInterpolation{
166166
Float64,
167167
}
168168

169-
"Smoothed linear interpolation from a Float64 to a Float64"
170-
const ScalarSmoothedLinearInterpolation = SmoothedLinearInterpolation{
169+
"SmoothedConstantInterpolation from a Float64 to a Float64"
170+
const ScalarBlockInterpolation = SmoothedConstantInterpolation{
171+
Vector{Float64},
172+
Vector{Float64},
171173
Vector{Float64},
172174
Vector{Float64},
173-
Nothing,
174175
Vector{Float64},
175176
Float64,
177+
Float64,
176178
}
177179

178-
"SmoothedConstantInterpolation from a Float64 to a Float64"
179-
const ScalarBlockInterpolation = SmoothedConstantInterpolation{
180+
"PCHIPInterpolation (a special type of CubicHermiteSpline) from a Float64 to a Float64"
181+
const ScalarPCHIPInterpolation = CubicHermiteSpline{
180182
Vector{Float64},
181183
Vector{Float64},
182184
Vector{Float64},
183185
Vector{Float64},
184186
Vector{Float64},
185187
Float64,
186-
Float64,
187188
}
188189

189190
"ConstantInterpolation from a Float64 to an Int, used to look up indices over time"
@@ -532,7 +533,7 @@ control_mapping: dictionary from (node_id, control_state) to Q(h) and/or active
532533
outflow_link::Vector{LinkMetadata} = Vector{LinkMetadata}(undef, length(node_id))
533534
active::Vector{Bool} = ones(Bool, length(node_id))
534535
max_downstream_level::Vector{Float64} = fill(Inf, length(node_id))
535-
interpolations::Vector{ScalarLinearInterpolation} = ScalarLinearInterpolation[]
536+
interpolations::Vector{ScalarPCHIPInterpolation} = ScalarLinearInterpolation[]
536537
current_interpolation_index::Vector{IndexLookup} = IndexLookup[]
537538
control_mapping::Dict{Tuple{NodeID, String}, ControlStateUpdate} =
538539
Dict{Tuple{NodeID, String}, ControlStateUpdate}()
@@ -879,7 +880,7 @@ end
879880
compound_variable::Vector{CompoundVariable}
880881
controlled_variable::Vector{String}
881882
target_ref::Vector{CacheRef} = Vector{CacheRef}(undef, length(node_id))
882-
func::Vector{ScalarSmoothedLinearInterpolation}
883+
func::Vector{ScalarPCHIPInterpolation}
883884
end
884885

885886
"""

core/src/read.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@ function continuous_control_functions(db, config, ids)
968968
errors = false
969969
# Parse the function table
970970
# Create linear interpolation objects out of the provided functions
971-
functions = ScalarSmoothedLinearInterpolation[]
971+
functions = ScalarPCHIPInterpolation[]
972972
controlled_variables = String[]
973973

974974
# Loop over the IDs of the ContinuousControl nodes
@@ -987,9 +987,20 @@ function continuous_control_functions(db, config, ids)
987987
else
988988
push!(controlled_variables, only(unique_controlled_variable))
989989
end
990-
function_itp = SmoothedLinearInterpolation(
991-
function_rows.output,
992-
function_rows.input;
990+
991+
input = collect(function_rows.input)
992+
output = collect(function_rows.output)
993+
994+
# PCHIPInterpolation cannot handle having only 2 data points:
995+
# https://github.com/SciML/DataInterpolations.jl/issues/446
996+
if length(function_rows) == 2
997+
insert!(input, 2, sum(input) / 2)
998+
insert!(output, 2, sum(output) / 2)
999+
end
1000+
1001+
function_itp = PCHIPInterpolation(
1002+
output,
1003+
input;
9931004
extrapolation = Linear,
9941005
cache_parameters = true,
9951006
)

core/src/util.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ function qh_interpolation(
9797
node_id::NodeID,
9898
level::Vector{Float64},
9999
flow_rate::Vector{Float64},
100-
)::ScalarLinearInterpolation
100+
)::CubicHermiteSpline
101101
errors = false
102102
n = length(level)
103103
if n < 2
@@ -122,7 +122,11 @@ function qh_interpolation(
122122

123123
errors && error("Errors occurred when parsing $node_id.")
124124

125-
return LinearInterpolation(
125+
# Make sure the smoothing is also correctly applied around the first level
126+
pushfirst!(level, first(level) - 1.0)
127+
pushfirst!(flow_rate, 0.0)
128+
129+
return PCHIPInterpolation(
126130
flow_rate,
127131
level;
128132
extrapolation_left = ConstantExtrapolation,

0 commit comments

Comments
 (0)