Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/systems/diffeqs/abstractodesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1504,5 +1504,5 @@ function InitializationProblem{iip, specialize}(sys::AbstractSystem,
else
NonlinearLeastSquaresProblem
end
TProb(isys, u0map, parammap; kwargs..., build_initializeprob = false)
TProb(isys, u0map, parammap; kwargs..., build_initializeprob = false, is_initializeprob = true)
end
40 changes: 35 additions & 5 deletions src/systems/problem_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,27 @@ function Base.showerror(io::IO, err::UnexpectedSymbolicValueInVarmap)
""")
end

struct MissingGuessError <: Exception
syms::Vector{Any}
vals::Vector{Any}
end

function Base.showerror(io::IO, err::MissingGuessError)
println(io,
"""
Unable to resolve numeric guesses for all of the variables in the system. \
This may be because your guesses are cyclic. In order for the problem to be \
initialized, all of the variables must have a numeric value to serve as a \
starting point for the nonlinear solve.

Symbolic values were found for the following variables/parameters in the map; \
please provide additional numeric guesses so they can resolve to numbers:
""")
for (sym, val) in zip(err.syms, err.vals)
println(sym, " => ", val)
Copy link
Member

Choose a reason for hiding this comment

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

If it's just missing, what's the val?

Copy link
Member Author

Choose a reason for hiding this comment

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

The symbolic value that it tries to assign to the variable

Copy link
Member

Choose a reason for hiding this comment

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

That's if it's cyclic. But this also is for if a guess is just missing, right? In which case, what does the error look like?

Copy link
Member Author

Choose a reason for hiding this comment

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

If a guess it just missing it throws a different error (IncompleteInitializationError)

Copy link
Member Author

Choose a reason for hiding this comment

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

const INCOMPLETE_INITIALIZATION_MESSAGE = """
Initialization incomplete. Not all of the state variables of the
DAE system can be determined by the initialization. Missing
variables:
"""
struct IncompleteInitializationError <: Exception
uninit::Any
end

Copy link
Member

Choose a reason for hiding this comment

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

That error doesn't make much sense to the user though? Why wouldn't the case I mentioned be a missing guess error?

Copy link
Member Author

Choose a reason for hiding this comment

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

It probably should be, this was just already in the code. I can make it throw a MissingGuessError instead of this one.

Copy link
Member Author

Choose a reason for hiding this comment

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

there is also this error but I need to dig a bit to figure out when it throws IncompleteInitializationError vs this one, maybe @AayushSabharwal knows better

const MISSING_VARIABLES_MESSAGE = """
Initial condition underdefined. Some are missing from the variable map.
Please provide a default (`u0`), initialization equation, or guess
for the following variables:
"""

end
end

"""
$(TYPEDSIGNATURES)

Expand All @@ -342,10 +363,11 @@ Keyword arguments:
[`missingvars`](@ref) to perform the check.
- `allow_symbolic` allows the returned array to contain symbolic values. If this is `true`,
`promotetoconcrete` is set to `false`.
- `is_initializeprob, guesses`: Used to determine whether the system is missing guesses.
"""
function better_varmap_to_vars(varmap::AbstractDict, vars::Vector;
tofloat = true, use_union = true, container_type = Array,
toterm = default_toterm, promotetoconcrete = nothing, check = true, allow_symbolic = false)
toterm = default_toterm, promotetoconcrete = nothing, check = true, allow_symbolic = false, is_initializeprob = false)
isempty(vars) && return nothing

if check
Expand All @@ -354,9 +376,17 @@ function better_varmap_to_vars(varmap::AbstractDict, vars::Vector;
end
vals = map(x -> varmap[x], vars)
if !allow_symbolic
missingsyms = Any[]
missingvals = Any[]
for (sym, val) in zip(vars, vals)
symbolic_type(val) == NotSymbolic() && continue
throw(UnexpectedSymbolicValueInVarmap(sym, val))
push!(missingsyms, sym)
push!(missingvals, val)
end

if !isempty(missingsyms)
is_initializeprob ? throw(MissingGuessError(missingsyms, missingvals)) :
throw(UnexpectedSymbolicValueInVarmap(missingsyms[1], missingvals[1]))
end
end

Expand Down Expand Up @@ -704,7 +734,7 @@ Keyword arguments:
- `fully_determined`: Override whether the initialization system is fully determined.
- `check_initialization_units`: Enable or disable unit checks when constructing the
initialization problem.
- `tofloat`, `use_union`: Passed to [`better_varmap_to_vars`](@ref) for building `u0` (and
- `tofloat`, `use_union`, `is_initializeprob`: Passed to [`better_varmap_to_vars`](@ref) for building `u0` (and
possibly `p`).
- `u0_constructor`: A function to apply to the `u0` value returned from `better_varmap_to_vars`
to construct the final `u0` value.
Expand Down Expand Up @@ -742,7 +772,7 @@ function process_SciMLProblem(
circular_dependency_max_cycles = 10,
substitution_limit = 100, use_scc = true,
force_initialization_time_independent = false, algebraic_only = false,
allow_incomplete = false, kwargs...)
allow_incomplete = false, is_initializeprob = false, kwargs...)
dvs = unknowns(sys)
ps = parameters(sys; initial_parameters = true)
iv = has_iv(sys) ? get_iv(sys) : nothing
Expand Down Expand Up @@ -815,7 +845,7 @@ function process_SciMLProblem(

u0 = better_varmap_to_vars(
op, dvs; tofloat = true, use_union = false,
container_type = u0Type, allow_symbolic = symbolic_u0)
container_type = u0Type, allow_symbolic = symbolic_u0, is_initializeprob)

if u0 !== nothing
u0 = u0_constructor(u0)
Expand Down
2 changes: 1 addition & 1 deletion src/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ end

function Base.showerror(io::IO, e::MissingVariablesError)
println(io, MISSING_VARIABLES_MESSAGE)
println(io, e.vars)
println(io, join(e.vars, ", "))
end

function _varmap_to_vars(varmap::Dict, varlist; defaults = Dict(), check = false,
Expand Down
20 changes: 19 additions & 1 deletion test/initial_values.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ end
[p => 2q, q => 3p]; warn_cyclic_dependency = true)
catch
end
@test_throws ModelingToolkit.UnexpectedSymbolicValueInVarmap ODEProblem(
@test_throws ModelingToolkit.MissingGuessError ODEProblem(
sys, [x => 1, y => 2], (0.0, 1.0), [p => 2q, q => 3p])
end

Expand All @@ -199,3 +199,21 @@ end
@test SciMLBase.successful_retcode(sol)
@test sol.u[1] ≈ [1.0, 1.0, 0.5, 0.5]
end

@testset "Missing/cyclic guesses throws error" begin
@parameters g
@variables x(t) y(t) [state_priority = 10] λ(t)
eqs = [D(D(x)) ~ λ * x
D(D(y)) ~ λ * y - g
x^2 + y^2 ~ 1]
@mtkbuild pend = ODESystem(eqs, t)

@test_throws ModelingToolkit.MissingGuessError ODEProblem(pend, [x => 1], (0, 1), [g => 1], guesses = [y => λ, λ => y + 1])
ODEProblem(pend, [x => 1], (0, 1), [g => 1], guesses = [y => λ, λ => 0.5])

# Throw multiple if multiple are missing
@variables a(t) b(t) c(t) d(t) e(t)
eqs = [D(a) ~ b, D(b) ~ c, D(c) ~ d, D(d) ~ e, D(e) ~ 1]
@mtkbuild sys = ODESystem(eqs, t)
@test_throws ["a(t) => ", "c(t) => "] ODEProblem(sys, [e => 2, a => b, b => a + 1, c => d, d => c + 1], (0, 1))
end
Loading