Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix up initializesystem for hierarchical models
The first version only worked on non-hierarchical models. Now it handles all models. Here's some example usage. Here's an example model: ```julia using ModelingToolkit, DifferentialEquations @parameters t D = Differential(t) @connector Port begin p(t) dm(t)=0, [connect = Flow] end @connector Flange begin dx(t)=0 f(t), [connect = Flow] end # Components ---- @mtkmodel Orifice begin @parameters begin Cₒ=2.7 Aₒ=0.00094 ρ₀=1000 p′=0 end @variables begin dm(t)=0 p₁(t)=p′ p₂(t)=p′ end @components begin port₁ = Port(p=p′) port₂ = Port(p=p′) end begin u = dm/(ρ₀*Aₒ) end @equations begin dm ~ +port₁.dm dm ~ -port₂.dm p₁ ~ port₁.p p₂ ~ port₂.p p₁ - p₂ ~ (1/2)*ρ₀*u^2*Cₒ end end @mtkmodel Volume begin @parameters begin A=0.1 ρ₀=1000 β=2e9 direction=+1 p′ x′ end @variables begin p(t)=p′ x(t)=x′ dm(t)=0 f(t)=p′ * A dx(t)=0 r(t), [guess = 1000] dr(t), [guess = 1000] end @components begin port = Port(p=p′) flange = Flange(f=-p′ * A * direction) end @equations begin D(x) ~ dx D(r) ~ dr p ~ +port.p dm ~ +port.dm # mass is entering f ~ -flange.f * direction # force is leaving dx ~ flange.dx * direction r ~ ρ₀*(1 + p/β) dm ~ (r*dx*A) + (dr*x*A) f ~ p * A end end @mtkmodel Mass begin @parameters begin m = 100 f′ end @variables begin f(t)=f′ x(t)=0 dx(t)=0 ẍ(t)=f′/m end @components begin flange = Flange(f=f′) end @equations begin D(x) ~ dx D(dx) ~ ẍ f ~ flange.f dx ~ flange.dx m*ẍ ~ f end end @mtkmodel Actuator begin @parameters begin p₁′ p₂′ end begin #constants x′=0.5 A=0.1 end @components begin port₁ = Port(p=p₁′) port₂ = Port(p=p₂′) vol₁ = Volume(p′=p₁′, x′=x′, direction=-1) vol₂ = Volume(p′=p₂′, x′=x′, direction=+1) mass = Mass(f′=(p₂′ - p₁′)*A) flange = Flange(f=0) end @equations begin connect(port₁, vol₁.port) connect(port₂, vol₂.port) connect(vol₁.flange, vol₂.flange, mass.flange, flange) end end @mtkmodel Source begin @parameters begin p′ end @components begin port = Port(p=p′) end @equations begin port.p ~ p′ end end @mtkmodel Damper begin @parameters begin c = 1000 end @components begin flange = Flange(f=0) end @equations begin flange.f ~ c*flange.dx end end @mtkmodel System begin @components begin res₁ = Orifice(p′=300e5) res₂ = Orifice(p′=0) act = Actuator(p₁′=300e5, p₂′=0) src = Source(p′=300e5) snk = Source(p′=0) dmp = Damper() end @equations begin connect(src.port, res₁.port₁) connect(res₁.port₂, act.port₁) connect(act.port₂, res₂.port₁) connect(res₂.port₂, snk.port) connect(dmp.flange, act.flange) end end @mtkbuild sys = System() ``` It's having troubles initializing, so what is the system it's trying to initialize? ```julia initsys = initializesystem(sys) ``` That gives it symbolically. We have 98 equations for 54 variables, shesh that's overloaded. ```julia julia> initprob = NonlinearProblem(initsys,[]) ERROR: ArgumentError: Equations (98), states (54), and initial conditions (54) are of different lengths. To allow a different number of equations than states use kwarg check_length=false. Stacktrace: [1] check_eqs_u0(eqs::Vector{…}, dvs::Vector{…}, u0::Vector{…}; check_length::Bool, kwargs::@kwargs{}) @ ModelingToolkit C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\abstractsystem.jl:1871 [2] process_NonlinearProblem(constructor::Type, sys::NonlinearSystem, u0map::Vector{…}, parammap::SciMLBase.NullParameters; version::Nothing, jac::Bool, checkbounds::Bool, sparse::Bool, simplify::Bool, linenumbers::Bool, parallel::Symbolics.SerialForm, eval_expression::Bool, use_union::Bool, tofloat::Bool, kwargs::@kwargs{…}) @ ModelingToolkit C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\nonlinear\nonlinearsystem.jl:339 [3] process_NonlinearProblem @ C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\nonlinear\nonlinearsystem.jl:323 [inlined] [4] (NonlinearProblem{…})(sys::NonlinearSystem, u0map::Vector{…}, parammap::SciMLBase.NullParameters; check_length::Bool, kwargs::@kwargs{}) @ ModelingToolkit C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\nonlinear\nonlinearsystem.jl:368 [5] NonlinearProblem (repeats 2 times) @ ModelingToolkit C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\nonlinear\nonlinearsystem.jl:365 [inlined] [6] #NonlinearProblem#698 @ ModelingToolkit C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\nonlinear\nonlinearsystem.jl:362 [inlined] [7] NonlinearProblem(sys::NonlinearSystem, args::Vector{Any}) @ ModelingToolkit C:\Users\accou\.julia\packages\ModelingToolkit\Gpzyo\src\systems\nonlinear\nonlinearsystem.jl:361 [8] top-level scope @ REPL[1]:1 Some type information was truncated. Use `show(err)` to see complete types. ``` So we can't build a NonlinearProblem. But we can do this: ```julia initprob = NonlinearProblem(initsys,[], check_length=false, checkbounds = true) lsqprob = NonlinearLeastSquaresProblem(NonlinearFunction(initprob.f.f, resid_prototype = zeros(98)), initprob.u0, initprob.p) initsol = solve(lsqprob, GaussNewton(), reltol = 1e-12, abstol = 1e-12) retcode: Success u: 54-element Vector{Float64}: 0.5 1015.0 0.5 1000.0 0.0 -1.208682818218319e-28 ⋮ 5.048709793414476e-28 -3.52499105861307e-29 -1.5146129380243427e-28 -3.0e6 -30000.0 -3.0e6 ``` And now we can make our initial conditions match that: ```julia allinit = states(initsys) .=> initsol prob = ODEProblem(sys, allinit, (0,0.1)) ``` and solve: ```julia sol = solve(prob) tmp = [0.0, 0.0, -0.0, -0.0, -0.0, -0.0, 8.123585990009498e-54, 1.1599794698483246e-51, 1.5375323209568473e-26, -2.914685306392616e-26] ┌ Warning: Instability detected. Aborting └ @ SciMLBase C:\Users\accou\.julia\packages\SciMLBase\3Mujd\src\integrator_interface.jl:602 ``` Here is modified the solver so tmp is the `resid` vector inside of the initializer. You can see it worked because the initialization errors are all zero. This is as opposed to with the default initial conditions: ```julia sysguesses = [ModelingToolkit.getguess(st) for st in states(sys)] hasaguess = findall(!isnothing, sysguesses) sysguesses = Dict(states(sys)[hasaguess] .=> sysguesses[hasaguess]) prob = ODEProblem(sys, sysguesses, (0,0.1)) sol = solve(prob) ``` ```julia julia> sol = solve(prob) tmp = [-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -3.0e7, 0.0, 50.0, 50.0] nlsol.resid = [-3.0e7, 0.0, 50.0, 50.0] nlsol.retcode = SciMLBase.ReturnCode.MaxIters retcode: InitialFailure Interpolation: specialized 4rd order "free" stiffness-aware interpolation t: 1-element Vector{Float64}: 0.0 u: 1-element Vector{Vector{Float64}}: [0.5, 1000.0, 0.5, 1000.0, 0.0, 0.0, 0.0, 0.0, 1000.0, 1000.0] ```
- Loading branch information