From ba48084d8d99365a93a12c0f10f4761c46281b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20W=C3=BCrfel?= Date: Tue, 3 Jun 2025 09:36:30 +0200 Subject: [PATCH 1/3] unify localmake --- docs/localmake.jl | 82 ++++++++++++++++++++++++++--------------------- docs/make.jl | 2 +- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/docs/localmake.jl b/docs/localmake.jl index 3c06321a6..f082fc3cb 100755 --- a/docs/localmake.jl +++ b/docs/localmake.jl @@ -11,53 +11,61 @@ use the updated `*.md` and source files. This way the Julia session keeps alive individual builds are much faster. =# -#= +PORT = isempty(ARGS) ? 8000 : parse(Int, ARGS[1]) +@assert 8000 ≤ PORT ≤ 9000 "PORT has to be in range 8000..9000!" + +print("Do you want to update docs environment? [y/n] (default: n) ") +answer = readline() +UPDATE_ENV = if !isempty(answer) && answer[1] == 'y' + true +else + false +end + +print("Do you want to build docs continously on file change? This will enable the `draft=true` flag, and the examples will not run. [y/n] (default: n)") +answer = readline() +SERVEDOCS_DRAFT = if !isempty(answer) && answer[1] == 'y' + true +else + false +end + + using Pkg Pkg.activate(@__DIR__) Pkg.instantiate() -print("Do you want to update docs environment? [y/n] ") -answer = readline() -if !isempty(answer) && answer[1] == 'y' + +if UPDATE_ENV Pkg.update() end using Revise using LiveServer -using REPL.TerminalMenus - -port = isempty(ARGS) ? 8000 : parse(Int, ARGS[1]) -@assert 8000 ≤ port ≤ 9000 "port has to be in range 8000..9000!" - -@info "Start server..." -@async serve(;dir=joinpath(@__DIR__, "build"), port) - -menu = RadioMenu(["Run again!", "Quit!"]) -while true - revise() - @info "Start building docs..." - try - include("make.jl") - catch e - @info "make.jl error" e - end - - println("\nDocs are served at http://localhost:$port") +using NetworkDynamics +cd(pkgdir(NetworkDynamics)) - if request("What now?", menu) != 1 - break - end -end -=# +if SERVEDOCS_DRAFT + servedocs( + literate_dir = joinpath("docs", "examples"), + skip_dir = joinpath("docs", "src", "generated") + ) +else + @info "Start server..." + @async serve(;dir=joinpath(@__DIR__, "build"), PORT) -using Pkg -Pkg.activate(@__DIR__) -using NetworkDynamics -using LiveServer + while true + revise() + @info "Start building docs..." + try + include("make.jl") + catch e + @info "make.jl error" e + end -cd(pkgdir(NetworkDynamics)) + println("\nDocs are served at http://localhost:$port") -servedocs( - literate_dir = joinpath("docs", "examples"), - skip_dir = joinpath("docs", "src", "generated") -) + println("Press [Enter] to rerun the make process or [Ctrl+C] to exit.") + readline() + end +end diff --git a/docs/make.jl b/docs/make.jl index f0bd89ca9..b91c25b71 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -68,7 +68,7 @@ kwargs = (; "Directed and Weighted Graphs" => "generated/directed_and_weighted_graphs.md", ] ], - draft=false, + draft = isdefined(Main, :SERVEDOCS_DRAFT) ? Main.SERVEDOCS_PREVIEW : false, format = Documenter.HTML(ansicolor = true), warnonly=[:missing_docs], ) From fb362445435fcb61069485a633c8e3a01fbdcfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20W=C3=BCrfel?= Date: Tue, 3 Jun 2025 09:59:48 +0200 Subject: [PATCH 2/3] basic renamings --- Project.toml | 2 +- docs/examples/gas_network.jl | 2 +- docs/src/API.md | 6 +++--- docs/src/metadata.md | 2 +- docs/src/mtk_integration.md | 8 ++++---- ext/NetworkDynamicsMTKExt.jl | 30 +++++++++++++++--------------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Project.toml b/Project.toml index 508333c53..201933549 100644 --- a/Project.toml +++ b/Project.toml @@ -64,7 +64,7 @@ KernelAbstractions = "0.9.18" LinearAlgebra = "1" MacroTools = "0.5.15" Mixers = "0.1.2" -ModelingToolkit = "9.67" +ModelingToolkit = "10" NNlib = "0.9.13" NonlinearSolve = "4" OrderedCollections = "1.8.0" diff --git a/docs/examples/gas_network.jl b/docs/examples/gas_network.jl index f2af2c40b..cc789f839 100644 --- a/docs/examples/gas_network.jl +++ b/docs/examples/gas_network.jl @@ -233,7 +233,7 @@ As a workaround we had to explicitly define `LinearInterpolations` as unitless, To build the network, we first need to define the components. This is a two-step process: -- first create the symbolic `ODESystem` using ModelingToolkit +- first create the symbolic `System` using ModelingToolkit - secondly build a NetworkDynamics component model ([`VertexModel`](@ref)/[`EdgeModel`](@ref)) based on the symbolic system. In the first step we can use the keyword arguments to pass "default" values for our parameters and states. diff --git a/docs/src/API.md b/docs/src/API.md index b7a0a87aa..cfbf620b1 100644 --- a/docs/src/API.md +++ b/docs/src/API.md @@ -17,9 +17,9 @@ EdgeModel() ## Component Models with MTK ```@docs -VertexModel(::ModelingToolkit.ODESystem, ::Any, ::Any) -EdgeModel(::ModelingToolkit.ODESystem, ::Any, ::Any, ::Any, ::Any) -EdgeModel(::ModelingToolkit.ODESystem, ::Any, ::Any, ::Any) +VertexModel(::ModelingToolkit.System, ::Any, ::Any) +EdgeModel(::ModelingToolkit.System, ::Any, ::Any, ::Any, ::Any) +EdgeModel(::ModelingToolkit.System, ::Any, ::Any, ::Any) ``` ### Output Function Helpers/Wrappers diff --git a/docs/src/metadata.md b/docs/src/metadata.md index 4ab19f412..7d45c8f1a 100644 --- a/docs/src/metadata.md +++ b/docs/src/metadata.md @@ -32,7 +32,7 @@ Special cases for symbol metadata are: For those, there are special functions `has_*`, `get_*`, `set_*!` and `delete_*!`. See [Per Symbol Metadata API](@ref). -These are closely aligned with the [metadata use in ModelingToolkit](https://docs.sciml.ai/ModelingToolkit/stable/basics/Variable_metadata/). They are automatically copied from the `ODESystem` if you use MTK models to create NetworkDynamics models. +These are closely aligned with the [metadata use in ModelingToolkit](https://docs.sciml.ai/ModelingToolkit/stable/basics/Variable_metadata/). They are automatically copied from the `System` if you use MTK models to create NetworkDynamics models. ## Metadata Utils Accessing metadata (especially defaults) of states and parameters is a very diff --git a/docs/src/mtk_integration.md b/docs/src/mtk_integration.md index 77fc09f80..8d9a735d8 100644 --- a/docs/src/mtk_integration.md +++ b/docs/src/mtk_integration.md @@ -6,13 +6,13 @@ which are then connected on network scale using NetworkDynamics. The main entry point for this interop are the constructors ```julia -VertexModel(::ODESystem, inputs, outputs) -EdgeModel(::ODESystem, srcin, dstin, [srscout], dstout) +VertexModel(::System, inputs, outputs) +EdgeModel(::System, srcin, dstin, [srscout], dstout) ``` whose docstrings can be found in the [Component Models with MTK](@ref) section in the API. These constructors will: -- transform the states marked as input to parameters and `structural_simplify`ing the system, +- transform the states marked as input to parameters and `mtkcompile`ing the system, - generate the `f` and `g` functions, - generate code for observables, - port all supported [Metadata](@ref) from MTK symbols to component symbols and @@ -76,7 +76,7 @@ An ideal voltage source is just a model which pins its output voltage to a fixed The source ejects whatever current is necessary. We introduce another variable `i(t)` to "capture" this current. This variable will be removed during structural simplify, but will be available for plotting through the [Observables](@ref) mechanism. -The `VertexModel` can be generated from an `ODESystem` by providing names of the input and output states: +The `VertexModel` can be generated from an `System` by providing names of the input and output states: ```@example mtk @mtkmodel VoltageSource begin diff --git a/ext/NetworkDynamicsMTKExt.jl b/ext/NetworkDynamicsMTKExt.jl index be7c699dd..3f79b2374 100644 --- a/ext/NetworkDynamicsMTKExt.jl +++ b/ext/NetworkDynamicsMTKExt.jl @@ -1,8 +1,8 @@ module NetworkDynamicsMTKExt using ModelingToolkit: Symbolic, iscall, operation, arguments, build_function -using ModelingToolkit: ModelingToolkit, Equation, ODESystem, Differential -using ModelingToolkit: equations, full_equations, get_variables, structural_simplify, getname, unwrap +using ModelingToolkit: ModelingToolkit, Equation, System, Differential +using ModelingToolkit: equations, full_equations, get_variables, mtkcompile, getname, unwrap using ModelingToolkit: parameters, unknowns, independent_variables, observed, defaults using Symbolics: Symbolics, fixpoint_sub, substitute using RecursiveArrayTools: RecursiveArrayTools @@ -18,22 +18,22 @@ import NetworkDynamics: VertexModel, EdgeModel, AnnotatedSym include("MTKExt_utils.jl") """ - VertexModel(sys::ODESystem, inputs, outputs; + VertexModel(sys::System, inputs, outputs; verbose=false, name=getname(sys), extin=nothing, ff_to_constraint=true, kwargs...) -Create a `VertexModel` object from a given `ODESystem` created with ModelingToolkit. +Create a `VertexModel` object from a given `System` created with ModelingToolkit. You need to provide 2 lists of symbolic names (`Symbol` or `Vector{Symbols}`): - `inputs`: names of variables in you equation representing the aggregated edge states - `outputs`: names of variables in you equation representing the node output Additional kw arguments: -- `name`: Set name of the component model. Will be lifted from the ODESystem name. +- `name`: Set name of the component model. Will be lifted from the System name. - `extin=nothing`: Provide external inputs as pairs, i.e. `extin=[:extvar => VIndex(1, :a)]` will bound the variable `extvar(t)` in the equations to the state `a` of the first vertex. - `ff_to_constraint=true`: Controlls, whether output transformations `g` which depend on inputs should be transformed into constraints. Defaults to true since ND.jl does not handle vertices with FF yet. """ -function VertexModel(sys::ODESystem, inputs, outputs; verbose=false, name=getname(sys), +function VertexModel(sys::System, inputs, outputs; verbose=false, name=getname(sys), ff_to_constraint=true, extin=nothing, kwargs...) warn_events(sys) inputs = inputs isa AbstractVector ? inputs : [inputs] @@ -87,9 +87,9 @@ function VertexModel(sys::ODESystem, inputs, outputs; verbose=false, name=getnam end """ - EdgeModel(sys::ODESystem, srcin, dstin, AntiSymmetric(dstout); kwargs...) + EdgeModel(sys::System, srcin, dstin, AntiSymmetric(dstout); kwargs...) -Create a `EdgeModel` object from a given `ODESystem` created with ModelingToolkit for **single sided models**. +Create a `EdgeModel` object from a given `System` created with ModelingToolkit for **single sided models**. Here you only need to provide one list of output symbols: `dstout`. To make it clear how to handle the single-sided output definiton, you musst wrap @@ -100,13 +100,13 @@ the symbol vector in Additional `kwargs` are the same as for the double-sided EdgeModel MTK constructor. """ -EdgeModel(sys::ODESystem, srcin, dstin, dstout; kwargs...) = EdgeModel(sys, srcin, dstin, nothing, dstout; kwargs...) +EdgeModel(sys::System, srcin, dstin, dstout; kwargs...) = EdgeModel(sys, srcin, dstin, nothing, dstout; kwargs...) """ - EdgeModel(sys::ODESystem, srcin, dstin, srcout, dstout; + EdgeModel(sys::System, srcin, dstin, srcout, dstout; verbose=false, name=getname(sys), extin=nothing, ff_to_constraint=false, kwargs...) -Create a `EdgeModel` object from a given `ODESystem` created with ModelingToolkit. +Create a `EdgeModel` object from a given `System` created with ModelingToolkit. You need to provide 4 lists of symbolic names (`Symbol` or `Vector{Symbols}`): - `srcin`: names of variables in you equation representing the node state at the source - `dstin`: names of variables in you equation representing the node state at the destination @@ -114,13 +114,13 @@ You need to provide 4 lists of symbolic names (`Symbol` or `Vector{Symbols}`): - `dstout`: names of variables in you equation representing the output at the destination Additional kw arguments: -- `name`: Set name of the component model. Will be lifted from the ODESystem name. +- `name`: Set name of the component model. Will be lifted from the System name. - `extin=nothing`: Provide external inputs as pairs, i.e. `extin=[:extvar => VIndex(1, :a)]` will bound the variable `extvar(t)` in the equations to the state `a` of the first vertex. - `ff_to_constraint=false`: Controlls, whether output transformations `g` which depend on inputs should be transformed into constraints. """ -function EdgeModel(sys::ODESystem, srcin, dstin, srcout, dstout; verbose=false, name=getname(sys), +function EdgeModel(sys::System, srcin, dstin, srcout, dstout; verbose=false, name=getname(sys), ff_to_constraint=false, extin=nothing, kwargs...) warn_events(sys) srcin = srcin isa AbstractVector ? srcin : [srcin] @@ -300,7 +300,7 @@ function generate_io_function(_sys, inputss::Tuple, outputss::Tuple; verbose && @warn "The specified outputs $implicit_outputs do not appear in the equations of the system!" end verbose && @info "Simplifying system with inputs $_openinputs and outputs $_definedoutputs" - structural_simplify(_sys, (_openinputs, _definedoutputs); simplify=false)[1] + mtkcompile(_sys; inputs=_openinputs, outputs=_definedoutputs, simplify=false) end allparams = parameters(sys) # contains inputs! @@ -398,7 +398,7 @@ function generate_io_function(_sys, inputss::Tuple, outputss::Tuple; end verbose && @info "Transformed algebraic eqs" eqs - # create massmatrix, we don't use the method provided by ODESystem because of reordering + # create massmatrix, we don't use the method provided by System because of reordering mm = generate_massmatrix(eqs) verbose && @info "Generated mass matrix" mm mm From 22342c3e9564b6489836cfc1df4ab45f7bef16e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20W=C3=BCrfel?= Date: Tue, 3 Jun 2025 10:12:51 +0200 Subject: [PATCH 3/3] remove constants --- ext/NetworkDynamicsMTKExt.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/NetworkDynamicsMTKExt.jl b/ext/NetworkDynamicsMTKExt.jl index 3f79b2374..741304a27 100644 --- a/ext/NetworkDynamicsMTKExt.jl +++ b/ext/NetworkDynamicsMTKExt.jl @@ -308,8 +308,8 @@ function generate_io_function(_sys, inputss::Tuple, outputss::Tuple; params = setdiff(allparams, Set(allinputs)) # extract the main equations and observed equations - eqs::Vector{Equation} = ModelingToolkit.subs_constants(equations(sys)) - obseqs_sorted::Vector{Equation} = ModelingToolkit.subs_constants(observed(sys)) + eqs::Vector{Equation} = equations(sys) + obseqs_sorted::Vector{Equation} = observed(sys) fix_metadata!(eqs, sys); fix_metadata!(obseqs_sorted, sys);