Skip to content

Commit

Permalink
Merge pull request #2879 from SciML/fully_determined
Browse files Browse the repository at this point in the history
Allow for setting fully_determined=true in initialization
  • Loading branch information
ChrisRackauckas authored Jul 19, 2024
2 parents d03379d + 704f085 commit f5587e1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 6 deletions.
9 changes: 8 additions & 1 deletion docs/src/tutorials/initialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ may not be analytically satisfiable!**. In our case here, if you sit down with a
long enough you will see that `λ = 0` is required for this equation, but since we chose
`λ = 1` we end up with a set of equations that are impossible to satisfy.

!!! note

If you would prefer to have an error instead of a warning in the context of non-fully
determined systems, pass the keyword argument `fully_determined = true` into the
problem constructor. Additionally, any warning about not being fully determined can
be suppressed via passing `warn_initialize_determined = false`.

## Diving Deeper: Constructing the Initialization System

To get a better sense of the initialization system and to help debug it, you can construct
Expand Down Expand Up @@ -271,7 +278,7 @@ sol = solve(iprob)
```

!!! note

For more information on solving NonlinearProblems and NonlinearLeastSquaresProblems,
check out the [NonlinearSolve.jl tutorials!](https://docs.sciml.ai/NonlinearSolve/stable/tutorials/getting_started/).

Expand Down
13 changes: 8 additions & 5 deletions src/systems/diffeqs/abstractodesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,7 @@ function process_DEProblem(constructor, sys::AbstractODESystem, u0map, parammap;
warn_initialize_determined = true,
build_initializeprob = true,
initialization_eqs = [],
fully_determined = false,
kwargs...)
eqs = equations(sys)
dvs = unknowns(sys)
Expand Down Expand Up @@ -835,7 +836,7 @@ function process_DEProblem(constructor, sys::AbstractODESystem, u0map, parammap;
end
initializeprob = ModelingToolkit.InitializationProblem(
sys, t, u0map, parammap; guesses, warn_initialize_determined,
initialization_eqs, eval_expression, eval_module)
initialization_eqs, eval_expression, eval_module, fully_determined)
initializeprobmap = getu(initializeprob, unknowns(sys))

zerovars = Dict(setdiff(unknowns(sys), keys(defaults(sys))) .=> 0.0)
Expand Down Expand Up @@ -1478,6 +1479,7 @@ InitializationProblem{iip}(sys::AbstractODESystem, u0map, tspan,
simplify = false,
linenumbers = true, parallel = SerialForm(),
initialization_eqs = [],
fully_determined = false,
kwargs...) where {iip}
```
Expand Down Expand Up @@ -1527,6 +1529,7 @@ function InitializationProblem{iip, specialize}(sys::AbstractODESystem,
check_length = true,
warn_initialize_determined = true,
initialization_eqs = [],
fully_determined = false,
kwargs...) where {iip, specialize}
if !iscomplete(sys)
error("A completed system is required. Call `complete` or `structural_simplify` on the system before creating an `ODEProblem`")
Expand All @@ -1535,10 +1538,10 @@ function InitializationProblem{iip, specialize}(sys::AbstractODESystem,
isys = get_initializesystem(sys; initialization_eqs)
elseif isempty(u0map) && get_initializesystem(sys) === nothing
isys = structural_simplify(
generate_initializesystem(sys; initialization_eqs); fully_determined = false)
generate_initializesystem(sys; initialization_eqs); fully_determined)
else
isys = structural_simplify(
generate_initializesystem(sys; u0map, initialization_eqs); fully_determined = false)
generate_initializesystem(sys; u0map, initialization_eqs); fully_determined)
end

uninit = setdiff(unknowns(sys), [unknowns(isys); getfield.(observed(isys), :lhs)])
Expand All @@ -1553,10 +1556,10 @@ function InitializationProblem{iip, specialize}(sys::AbstractODESystem,
nunknown = length(unknowns(isys))

if warn_initialize_determined && neqs > nunknown
@warn "Initialization system is overdetermined. $neqs equations for $nunknown unknowns. Initialization will default to using least squares. To suppress this warning pass warn_initialize_determined = false."
@warn "Initialization system is overdetermined. $neqs equations for $nunknown unknowns. Initialization will default to using least squares. To suppress this warning pass warn_initialize_determined = false. To make this warning into an error, pass fully_determined = true"
end
if warn_initialize_determined && neqs < nunknown
@warn "Initialization system is underdetermined. $neqs equations for $nunknown unknowns. Initialization will default to using least squares. To suppress this warning pass warn_initialize_determined = false."
@warn "Initialization system is underdetermined. $neqs equations for $nunknown unknowns. Initialization will default to using least squares. To suppress this warning pass warn_initialize_determined = false. To make this warning into an error, pass fully_determined = true"
end

parammap = parammap isa DiffEqBase.NullParameters || isempty(parammap) ?
Expand Down
22 changes: 22 additions & 0 deletions test/initializationsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ sol = solve(initprob)
@test SciMLBase.successful_retcode(sol)
@test maximum(abs.(sol[conditions])) < 1e-14

@test_throws ModelingToolkit.ExtraVariablesSystemException ModelingToolkit.InitializationProblem(
pend, 0.0, [], [g => 1];
guesses = [ModelingToolkit.missing_variable_defaults(pend); x => 1; y => 0.2],
fully_determined = true)

initprob = ModelingToolkit.InitializationProblem(pend, 0.0, [x => 1, y => 0], [g => 1];
guesses = ModelingToolkit.missing_variable_defaults(pend))
@test initprob isa NonlinearProblem
Expand All @@ -31,6 +36,10 @@ initprob = ModelingToolkit.InitializationProblem(
sol = solve(initprob)
@test !SciMLBase.successful_retcode(sol)

@test_throws ModelingToolkit.ExtraVariablesSystemException ModelingToolkit.InitializationProblem(
pend, 0.0, [], [g => 1]; guesses = ModelingToolkit.missing_variable_defaults(pend),
fully_determined = true)

prob = ODEProblem(pend, [x => 1, y => 0], (0.0, 1.5), [g => 1],
guesses = ModelingToolkit.missing_variable_defaults(pend))
prob.f.initializeprob isa NonlinearProblem
Expand All @@ -47,6 +56,11 @@ sol = solve(prob.f.initializeprob)
sol = solve(prob, Rodas5P())
@test maximum(abs.(sol[conditions][1])) < 1e-14

@test_throws ModelingToolkit.ExtraVariablesSystemException ODEProblem(
pend, [x => 1], (0.0, 1.5), [g => 1],
guesses = ModelingToolkit.missing_variable_defaults(pend),
fully_determined = true)

@connector Port begin
p(t)
dm(t) = 0, [connect = Flow]
Expand Down Expand Up @@ -225,14 +239,22 @@ initsol = solve(initprob, reltol = 1e-12, abstol = 1e-12)
@test SciMLBase.successful_retcode(initsol)
@test maximum(abs.(initsol[conditions])) < 1e-14

@test_throws ModelingToolkit.ExtraEquationsSystemException ModelingToolkit.InitializationProblem(
sys, 0.0, fully_determined = true)

allinit = unknowns(sys) .=> initsol[unknowns(sys)]
prob = ODEProblem(sys, allinit, (0, 0.1))
sol = solve(prob, Rodas5P(), initializealg = BrownFullBasicInit())
# If initialized incorrectly, then it would be InitialFailure
@test sol.retcode == SciMLBase.ReturnCode.Unstable
@test maximum(abs.(initsol[conditions][1])) < 1e-14

prob = ODEProblem(sys, allinit, (0, 0.1))
prob = ODEProblem(sys, [], (0, 0.1), check = false)

@test_throws ModelingToolkit.ExtraEquationsSystemException ODEProblem(
sys, [], (0, 0.1), fully_determined = true)

sol = solve(prob, Rodas5P())
# If initialized incorrectly, then it would be InitialFailure
@test sol.retcode == SciMLBase.ReturnCode.Unstable
Expand Down

0 comments on commit f5587e1

Please sign in to comment.