Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connector for nonlinear system #3288

Open
weigao-123 opened this issue Jan 4, 2025 · 3 comments
Open

connector for nonlinear system #3288

weigao-123 opened this issue Jan 4, 2025 · 3 comments
Labels
question Further information is requested

Comments

@weigao-123
Copy link

Question❓
Is there any tutorial or maybe feature to support connector for pure nonlinear systems?

Explaination
According to the documentation, which says MTK could also for modeling NonlinearSystem besides ODESystem, but currently not supported with the macros, and this is fine if we can programmatically generate the system.
My scenario is that I still would like to use the acausal modeling benefiting from connector, but only nonlinear system instead of ode system. From my understanding based on this, it seems that connector only supports ODESystem, so is there any way that we can achieve this?

Example
Here is basically what I would like to do:

using ModelingToolkit

@connector Pin begin
    @variables begin
        v
        i, [connect = Flow]
    end
end

@named node1 = Pin()
println(node1)

and with the following errors:

ArgumentError: Variable v is not a function of independent variable t.

Stacktrace:
 [1] check_variables(dvs::Vector{SymbolicUtils.BasicSymbolic{Real}}, iv::SymbolicUtils.BasicSymbolic{Real})
   @ ModelingToolkit C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\utils.jl:151
 [2] ODESystem(tag::UInt64, deqs::Vector{Equation}, iv::SymbolicUtils.BasicSymbolic{Real}, dvs::Vector{SymbolicUtils.BasicSymbolic{Real}}, ps::Vector{Any}, tspan::Nothing, var_to_name::Dict{Any, Any}, ctrls::Vector{Any}, observed::Vector{Equation}, tgrad::Base.RefValue{Vector{Num}}, jac::Base.RefValue{Any}, ctrl_jac::Base.RefValue{Any}, Wfact::Base.RefValue{Matrix{Num}}, Wfact_t::Base.RefValue{Matrix{Num}}, name::Symbol, description::String, systems::Vector{ODESystem}, defaults::Dict{Any, Any}, guesses::Dict{Any, Any}, torn_matching::Nothing, initializesystem::Nothing, initialization_eqs::Vector{Equation}, schedule::Nothing, connector_type::Nothing, preface::Nothing, cevents::Vector{ModelingToolkit.SymbolicContinuousCallback}, devents::Vector{ModelingToolkit.SymbolicDiscreteCallback}, parameter_dependencies::Vector{Equation}, metadata::Nothing, gui_metadata::ModelingToolkit.GUIMetadata, is_dde::Bool, tstops::Vector{Any}, tearing_state::Nothing, substitutions::Nothing, complete::Bool, index_cache::Nothing, discrete_subsystems::Nothing, solved_unknowns::Nothing, split_idxs::Nothing, parent::Nothing; checks::Bool)
   @ ModelingToolkit C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\diffeqs\odesystem.jl:201
 [3] ODESystem
   @ C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\diffeqs\odesystem.jl:189 [inlined]
 [4] ODESystem(deqs::Vector{Equation}, iv::Num, dvs::Vector{Any}, ps::Vector{Any}; controls::Vector{Num}, observed::Vector{Equation}, systems::Vector{ODESystem}, tspan::Nothing, name::Symbol, description::String, default_u0::Dict{Any, Any}, default_p::Dict{Any, Any}, defaults::Dict{Num, Union{Function, Number, Symbol}}, guesses::Dict{Any, Any}, initializesystem::Nothing, initialization_eqs::Vector{Equation}, schedule::Nothing, connector_type::Nothing, preface::Nothing, continuous_events::Nothing, discrete_events::Nothing, parameter_dependencies::Vector{Equation}, checks::Bool, metadata::Nothing, gui_metadata::ModelingToolkit.GUIMetadata, is_dde::Nothing, tstops::Vector{Any})
   @ ModelingToolkit C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\diffeqs\odesystem.jl:302
 [5] __Pin__(; name::Symbol, v::ModelingToolkit.NoValue, i::ModelingToolkit.NoValue)
   @ Main C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\model_parsing.jl:914
 [6] __Pin__
   @ C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\model_parsing.jl:138 [inlined]
 [7] #_#440
   @ C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\model_parsing.jl:25 [inlined]
 [8] top-level scope
   @ C:\Users\xxx\.julia\packages\ModelingToolkit\klLLV\src\systems\abstractsystem.jl:2060
@weigao-123 weigao-123 added the question Further information is requested label Jan 4, 2025
@ChrisRackauckas
Copy link
Member

Time-dependent systems have a nonlinear system associated with their steady state, so the simplest thing would be just to use that interpretation directly, i.e. define everything as time-dependent but then with no differential equations, only algebraic equations, and call NonlinearProblem on it.

@weigao-123
Copy link
Author

Time-dependent systems have a nonlinear system associated with their steady state, so the simplest thing would be just to use that interpretation directly, i.e. define everything as time-dependent but then with no differential equations, only algebraic equations, and call NonlinearProblem on it.

Hi Chris,
Thank you for the suggestion! I tried it as follows:

prob = NonlinearProblem(simplified_sys, [])

but, I got:

No methods were found for the model function passed to the equation solver.
The function `f` needs to have dispatches, for example, for an ODEProblem
`f` must define either `f(u,p,t)` or `f(du,u,p,t)`. For more information
on how the model function `f` should be defined, consult the docstring for
the appropriate `AbstractSciMLFunction`.

Offending function: f

Stacktrace:
 [1] isinplace(f::ODESystem, inplace_param_number::Int64, fname::String, iip_preferred::Bool; has_two_dispatches::Bool, isoptimization::Bool, outofplace_param_number::Int64)
   @ SciMLBase C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\utils.jl:254
 [2] isinplace (repeats 2 times)
   @ C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\utils.jl:246 [inlined]
 [3] NonlinearFunction(f::ODESystem; kwargs::@Kwargs{})
   @ SciMLBase C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\scimlfunctions.jl:4008
 [4] NonlinearFunction
   @ C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\scimlfunctions.jl:4007 [inlined]
 [5] NonlinearProblem(f::ODESystem, u0::Vector{Any}, p::SciMLBase.NullParameters; kwargs::@Kwargs{})
   @ SciMLBase C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\problems\nonlinear_problems.jl:201
 [6] NonlinearProblem
   @ C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\problems\nonlinear_problems.jl:200 [inlined]
 [7] NonlinearProblem(f::ODESystem, u0::Vector{Any})
   @ SciMLBase C:\Users\xxx\.julia\packages\SciMLBase\XzPx0\src\problems\nonlinear_problems.jl:200
 [8] top-level scope
   @ f:\SymPowerSystems\jl_notebook_cell_df34fa98e69747e1a8f8a730347b8e2f_Y123sZmlsZQ==.jl:1

And I tried building the system with NonlinearSystem instead of ODESystem, but also has other errors.
One way I can do it still treat it as an ODESystem, and set a very short timespan, I can also solve this algebraic equations, but it seems not that elegant and I have concern with the performance with a very large scale problem.
Any other suggestions or comments?

@weigao-123
Copy link
Author

One way I can do it still treat it as an ODESystem, and set a very short timespan, I can also solve this algebraic equations, but it seems not that elegant and I have concern with the performance with a very large scale problem. Any other suggestions or comments?

Ok, I think I might found a workaround for this, a simple example as follows:

  • Build Resistor Circuit Model (by default, ODESystem)

    code
    using ModelingToolkit, Plots, DifferentialEquations
    using ModelingToolkit: t_nounits as t, D_nounits as D
    
    @connector Pin begin
        v(t)
        i(t), [connect = Flow]
    end
    
    @mtkmodel Ground begin
        @components begin
            g = Pin()
        end
        @equations begin
            g.v ~ 0
        end
    end
    
    @mtkmodel OnePort begin
        @components begin
            p = Pin()
            n = Pin()
        end
        @variables begin
            v(t)
            i(t)
        end
        @equations begin
            v ~ p.v - n.v
            0 ~ p.i + n.i
            i ~ p.i
        end
    end
    
    @mtkmodel Resistor begin
        @extend OnePort()
        @parameters begin
            R = 1.0 # Sets the default resistance
        end
        @equations begin
            v ~ i * R
        end
    end
    
    @mtkmodel ConstantVoltage begin
        @extend OnePort()
        @parameters begin
            V = 1.0
        end
        @equations begin
            V ~ v
        end
    end
    
    @mtkmodel RModel begin
        @components begin
            resistor = Resistor(R = 1.0)
            source = ConstantVoltage(V = 1.0)
            ground = Ground()
        end
        @equations begin
            connect(source.p, resistor.p)
            connect(resistor.n, source.n)
            connect(resistor.n, ground.g)
        end
    end
    
    @mtkbuild r_model = RModel(resistor.R = 2.0)
  • Simulate as ODESystem

prob = ODEProblem(r_model, [], (0, 10.0))
sol = solve(prob)
sol[[t, r_model.resistor.v]]
  • Simulate as NonlinearSystem
@named ns = NonlinearSystem([equations(r_model); observed(r_model)])
@named simplified_ns = structural_simplify(ns)
prob = NonlinearProblem(simplified_ns, [])
sol = solve(prob, NewtonRaphson())
sol[r_model.resistor.v]

Even though the resistor circuit is a linear system, but it is fine.
Still, I really appreciate it if there is any better way of doing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants