Skip to content

Commit 4e7e1f6

Browse files
committed
Merge remote-tracking branch 'origin' into ss_discrete
merge master
2 parents f29824e + dfebe6a commit 4e7e1f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2897
-1474
lines changed

.github/workflows/Downstream.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
- {user: SciML, repo: MethodOfLines.jl, group: Interface}
3838
- {user: SciML, repo: MethodOfLines.jl, group: 2D_Diffusion}
3939
- {user: SciML, repo: MethodOfLines.jl, group: DAE}
40+
- {user: SciML, repo: ModelingToolkitNeuralNets.jl, group: All}
4041
steps:
4142
- uses: actions/checkout@v4
4243
- uses: julia-actions/setup-julia@v1

Project.toml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelingToolkit"
22
uuid = "961ee093-0014-501f-94e3-6117800e7a78"
33
authors = ["Yingbo Ma <[email protected]>", "Chris Rackauckas <[email protected]> and contributors"]
4-
version = "9.62.0"
4+
version = "9.64.1"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -83,6 +83,8 @@ AbstractTrees = "0.3, 0.4"
8383
ArrayInterface = "6, 7"
8484
BifurcationKit = "0.4"
8585
BlockArrays = "1.1"
86+
BoundaryValueDiffEqAscher = "1.1.0"
87+
BoundaryValueDiffEqMIRK = "1.4.0"
8688
ChainRulesCore = "1"
8789
Combinatorics = "1"
8890
CommonSolve = "0.2.4"
@@ -104,11 +106,11 @@ DynamicQuantities = "^0.11.2, 0.12, 0.13, 1"
104106
EnumX = "1.0.4"
105107
ExprTools = "0.1.10"
106108
Expronicon = "0.8"
109+
FMI = "0.14"
107110
FindFirstFunctions = "1"
108111
ForwardDiff = "0.10.3"
109112
FunctionWrappers = "1.1"
110113
FunctionWrappersWrappers = "0.1"
111-
FMI = "0.14"
112114
Graphs = "1.5.2"
113115
HomotopyContinuation = "2.11"
114116
InfiniteOpt = "0.5"
@@ -119,6 +121,7 @@ LabelledArrays = "1.3"
119121
Latexify = "0.11, 0.12, 0.13, 0.14, 0.15, 0.16"
120122
Libdl = "1"
121123
LinearAlgebra = "1"
124+
Logging = "1"
122125
MLStyle = "0.4.17"
123126
ModelingToolkitStandardLibrary = "2.19"
124127
NaNMath = "0.3, 1"
@@ -128,26 +131,26 @@ OrderedCollections = "1"
128131
OrdinaryDiffEq = "6.82.0"
129132
OrdinaryDiffEqCore = "1.15.0"
130133
OrdinaryDiffEqDefault = "1.2"
131-
OrdinaryDiffEqNonlinearSolve = "1.3.0"
134+
OrdinaryDiffEqNonlinearSolve = "1.5.0"
132135
PrecompileTools = "1"
133136
REPL = "1"
134137
RecursiveArrayTools = "3.26"
135138
Reexport = "0.2, 1"
136139
RuntimeGeneratedFunctions = "0.5.9"
137140
SCCNonlinearSolve = "1.0.0"
138-
SciMLBase = "2.72.1"
141+
SciMLBase = "2.73"
139142
SciMLStructures = "1.0"
140143
Serialization = "1"
141144
Setfield = "0.7, 0.8, 1"
142145
SimpleNonlinearSolve = "0.1.0, 1, 2"
143146
SparseArrays = "1"
144147
SpecialFunctions = "0.7, 0.8, 0.9, 0.10, 1.0, 2"
145148
StaticArrays = "0.10, 0.11, 0.12, 1.0"
146-
StochasticDiffEq = "6.72.1"
147149
StochasticDelayDiffEq = "1.8.1"
150+
StochasticDiffEq = "6.72.1"
148151
SymbolicIndexingInterface = "0.3.37"
149152
SymbolicUtils = "3.14"
150-
Symbolics = "6.29"
153+
Symbolics = "6.29.1"
151154
URIs = "1"
152155
UnPack = "0.1, 1.0"
153156
Unitful = "1.1"
@@ -156,6 +159,8 @@ julia = "1.9"
156159
[extras]
157160
AmplNLWriter = "7c4d4715-977e-5154-bfe0-e096adeac482"
158161
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
162+
BoundaryValueDiffEqMIRK = "1a22d4ce-7765-49ea-b6f2-13c8438986a6"
163+
BoundaryValueDiffEqAscher = "7227322d-7511-4e07-9247-ad6ff830280e"
159164
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
160165
DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0"
161166
DeepDiffs = "ab62b9b5-e342-54a8-a765-a90f495de1a6"
@@ -164,6 +169,7 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
164169
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
165170
Ipopt_jll = "9cc047cb-c261-5740-88fc-0cf96f7bdcc7"
166171
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
172+
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
167173
ModelingToolkitStandardLibrary = "16a59e39-deab-5bd0-87e4-056b12336739"
168174
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
169175
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
@@ -187,4 +193,4 @@ Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4"
187193
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
188194

189195
[targets]
190-
test = ["AmplNLWriter", "BenchmarkTools", "ControlSystemsBase", "DataInterpolations", "DelayDiffEq", "NonlinearSolve", "ForwardDiff", "Ipopt", "Ipopt_jll", "ModelingToolkitStandardLibrary", "Optimization", "OptimizationOptimJL", "OptimizationMOI", "OrdinaryDiffEq", "OrdinaryDiffEqCore", "OrdinaryDiffEqDefault", "REPL", "Random", "ReferenceTests", "SafeTestsets", "StableRNGs", "Statistics", "SteadyStateDiffEq", "Test", "StochasticDiffEq", "Sundials", "StochasticDelayDiffEq", "Pkg", "JET", "OrdinaryDiffEqNonlinearSolve"]
196+
test = ["AmplNLWriter", "BenchmarkTools", "BoundaryValueDiffEqMIRK", "BoundaryValueDiffEqAscher", "ControlSystemsBase", "DataInterpolations", "DelayDiffEq", "NonlinearSolve", "ForwardDiff", "Ipopt", "Ipopt_jll", "ModelingToolkitStandardLibrary", "Optimization", "OptimizationOptimJL", "OptimizationMOI", "OrdinaryDiffEq", "OrdinaryDiffEqCore", "OrdinaryDiffEqDefault", "REPL", "Random", "ReferenceTests", "SafeTestsets", "StableRNGs", "Statistics", "SteadyStateDiffEq", "Test", "StochasticDiffEq", "Sundials", "StochasticDelayDiffEq", "Pkg", "JET", "OrdinaryDiffEqNonlinearSolve", "Logging"]

docs/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
1515
OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e"
1616
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
1717
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
18+
PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46"
1819
SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226"
1920
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
2021
StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0"
@@ -38,6 +39,7 @@ Optimization = "3.9, 4"
3839
OptimizationOptimJL = "0.1, 0.4"
3940
OrdinaryDiffEq = "6.31"
4041
Plots = "1.36"
42+
PreallocationTools = "0.4"
4143
SciMLStructures = "1.1"
4244
Setfield = "1"
4345
StochasticDiffEq = "6"

docs/src/basics/Variable_metadata.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ state_priority(important_dof)
201201
Units for variables can be designated using symbolic metadata. For more information, please see the [model validation and units](@ref units) section of the docs. Note that `getunit` is not equivalent to `get_unit` - the former is a metadata getter for individual variables (and is provided so the same interface function for `unit` exists like other metadata), while the latter is used to handle more general symbolic expressions.
202202

203203
```@example metadata
204+
using DynamicQuantities
204205
@variables speed [unit = u"m/s"]
205206
hasunit(speed)
206207
```

docs/src/examples/remake.md

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,22 @@ parameters to optimize.
4545

4646
```@example Remake
4747
using SymbolicIndexingInterface: parameter_values, state_values
48-
using SciMLStructures: Tunable, replace, replace!
48+
using SciMLStructures: Tunable, canonicalize, replace, replace!
49+
using PreallocationTools
4950
5051
function loss(x, p)
5152
odeprob = p[1] # ODEProblem stored as parameters to avoid using global variables
5253
ps = parameter_values(odeprob) # obtain the parameter object from the problem
53-
ps = replace(Tunable(), ps, x) # create a copy with the values passed to the loss function
54+
diffcache = p[5]
55+
# get an appropriately typed preallocated buffer to store the `x` values in
56+
buffer = get_tmp(diffcache, x)
57+
# copy the current values to this buffer
58+
copyto!(buffer, canonicalize(Tunable(), ps)[1])
59+
# create a copy of the parameter object with the buffer
60+
ps = replace(Tunable(), ps, buffer)
61+
# set the updated values in the parameter object
62+
setter = p[4]
63+
setter(ps, x)
5464
# remake the problem, passing in our new parameter object
5565
newprob = remake(odeprob; p = ps)
5666
timesteps = p[2]
@@ -81,49 +91,22 @@ We can perform the optimization as below:
8191
```@example Remake
8292
using Optimization
8393
using OptimizationOptimJL
94+
using SymbolicIndexingInterface
8495
8596
# manually create an OptimizationFunction to ensure usage of `ForwardDiff`, which will
8697
# require changing the types of parameters from `Float64` to `ForwardDiff.Dual`
8798
optfn = OptimizationFunction(loss, Optimization.AutoForwardDiff())
99+
# function to set the parameters we are optimizing
100+
setter = setp(odeprob, [α, β, γ, δ])
101+
# `DiffCache` to avoid allocations
102+
diffcache = DiffCache(canonicalize(Tunable(), parameter_values(odeprob))[1])
88103
# parameter object is a tuple, to store differently typed objects together
89104
optprob = OptimizationProblem(
90-
optfn, rand(4), (odeprob, timesteps, data), lb = 0.1zeros(4), ub = 3ones(4))
105+
optfn, rand(4), (odeprob, timesteps, data, setter, diffcache),
106+
lb = 0.1zeros(4), ub = 3ones(4))
91107
sol = solve(optprob, BFGS())
92108
```
93109

94-
To identify which values correspond to which parameters, we can `replace!` them into the
95-
`ODEProblem`:
96-
97-
```@example Remake
98-
replace!(Tunable(), parameter_values(odeprob), sol.u)
99-
odeprob.ps[[α, β, γ, δ]]
100-
```
101-
102-
`replace!` operates in-place, so the values being replaced must be of the same type as those
103-
stored in the parameter object, or convertible to that type. For demonstration purposes, we
104-
can construct a loss function that uses `replace!`, and calculate gradients using
105-
`AutoFiniteDiff` rather than `AutoForwardDiff`.
106-
107-
```@example Remake
108-
function loss2(x, p)
109-
odeprob = p[1] # ODEProblem stored as parameters to avoid using global variables
110-
newprob = remake(odeprob) # copy the problem with `remake`
111-
# update the parameter values in-place
112-
replace!(Tunable(), parameter_values(newprob), x)
113-
timesteps = p[2]
114-
sol = solve(newprob, AutoTsit5(Rosenbrock23()); saveat = timesteps)
115-
truth = p[3]
116-
data = Array(sol)
117-
return sum((truth .- data) .^ 2) / length(truth)
118-
end
119-
120-
# use finite-differencing to calculate derivatives
121-
optfn2 = OptimizationFunction(loss2, Optimization.AutoFiniteDiff())
122-
optprob2 = OptimizationProblem(
123-
optfn2, rand(4), (odeprob, timesteps, data), lb = 0.1zeros(4), ub = 3ones(4))
124-
sol = solve(optprob2, BFGS())
125-
```
126-
127110
# Re-creating the problem
128111

129112
There are multiple ways to re-create a problem with new state/parameter values. We will go

docs/src/tutorials/initialization.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,73 @@ long enough you will see that `λ = 0` is required for this equation, but since
203203
problem constructor. Additionally, any warning about not being fully determined can
204204
be suppressed via passing `warn_initialize_determined = false`.
205205

206+
## Constant constraints in initialization
207+
208+
Consider the pendulum system again:
209+
210+
```@repl init
211+
equations(pend)
212+
observed(pend)
213+
```
214+
215+
Suppose we want to solve the same system with multiple different initial
216+
y-velocities from a given position.
217+
218+
```@example init
219+
prob = ODEProblem(
220+
pend, [x => 1, D(y) => 0], (0.0, 1.5), [g => 1], guesses = [λ => 0, y => 1, x => 1])
221+
sol1 = solve(prob, Rodas5P())
222+
```
223+
224+
```@example init
225+
sol1[D(y), 1]
226+
```
227+
228+
Repeatedly re-creating the `ODEProblem` with different values of `D(y)` and `x` or
229+
repeatedly calling `remake` is slow. Instead, for any `variable => constant` constraint
230+
in the `ODEProblem` initialization (whether provided to the `ODEProblem` constructor or
231+
a default value) we can update the `constant` value. ModelingToolkit refers to these
232+
values using the `Initial` operator. For example:
233+
234+
```@example init
235+
prob.ps[[Initial(x), Initial(D(y))]]
236+
```
237+
238+
To solve with a different starting y-velocity, we can simply do
239+
240+
```@example init
241+
prob.ps[Initial(D(y))] = -0.1
242+
sol2 = solve(prob, Rodas5P())
243+
```
244+
245+
```@example init
246+
sol2[D(y), 1]
247+
```
248+
249+
Note that this _only_ applies for constant constraints for the current ODEProblem.
250+
For example, `D(x)` does not have a constant constraint - it is solved for by
251+
initialization. Thus, mutating `Initial(D(x))` does not have any effect:
252+
253+
```@repl init
254+
sol2[D(x), 1]
255+
prob.ps[Initial(D(x))] = 1.0
256+
sol3 = solve(prob, Rodas5P())
257+
sol3[D(x), 1]
258+
```
259+
260+
To enforce this constraint, we would have to `remake` the problem (or construct a new one).
261+
262+
```@repl init
263+
prob2 = remake(prob; u0 = [y => 0.0, D(x) => 0.0, x => nothing, D(y) => nothing]);
264+
sol4 = solve(prob2, Rodas5P())
265+
sol4[D(x), 1]
266+
```
267+
268+
Note the need to provide `x => nothing, D(y) => nothing` to override the previously
269+
provided initial conditions. Since `remake` is a partial update, the constraints provided
270+
to it are merged with the ones already present in the problem. Existing constraints can be
271+
removed by providing a value of `nothing`.
272+
206273
## Initialization of parameters
207274

208275
Parameters may also be treated as unknowns in the initialization system. Doing so works
@@ -231,6 +298,9 @@ constraints provided to it. The new values will be combined with the original
231298
variable-value mapping provided to `ODEProblem` and used to construct the initialization
232299
problem.
233300

301+
The variable on the left hand side of all parameter dependencies also has an `Initial`
302+
variant, which is used if a constant constraint is provided for the variable.
303+
234304
### Parameter initialization by example
235305

236306
Consider the following system, where the sum of two unknowns is a constant parameter

ext/MTKBifurcationKitExt.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ function BifurcationKit.BifurcationProblem(nsys::NonlinearSystem,
9797
@set! nsys.index_cache = nothing # force usage of a parameter vector instead of `MTKParameters`
9898
# Creates F and J functions.
9999
ofun = NonlinearFunction(nsys; jac = jac)
100-
F = ofun.f
100+
F = let f = ofun.f
101+
_f(resid, u, p) = (f(resid, u, p); resid)
102+
_f(u, p) = f(u, p)
103+
end
101104
J = jac ? ofun.jac : nothing
102105

103106
# Converts the input state guess.
@@ -136,6 +139,7 @@ function BifurcationKit.BifurcationProblem(nsys::NonlinearSystem,
136139
args...;
137140
record_from_solution = record_from_solution,
138141
J = J,
142+
inplace = true,
139143
kwargs...)
140144
end
141145

ext/MTKChainRulesCoreExt.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ end
1616

1717
function subset_idxs(idxs, portion, template)
1818
ntuple(Val(length(template))) do subi
19-
[Base.tail(idx.idx) for idx in idxs if idx.portion == portion && idx.idx[1] == subi]
19+
result = [Base.tail(idx.idx)
20+
for idx in idxs if idx.portion == portion && idx.idx[1] == subi]
21+
if isempty(result)
22+
result = []
23+
end
24+
result
2025
end
2126
end
2227

src/ModelingToolkit.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ using Compat
4545
using AbstractTrees
4646
using DiffEqBase, SciMLBase, ForwardDiff
4747
using SciMLBase: StandardODEProblem, StandardNonlinearProblem, handle_varmap, TimeDomain,
48-
PeriodicClock, Clock, SolverStepClock, Continuous
48+
PeriodicClock, Clock, SolverStepClock, Continuous, OverrideInit, NoInit
4949
using Distributed
5050
import JuliaFormatter
5151
using MLStyle
@@ -56,6 +56,7 @@ using RecursiveArrayTools
5656
import Graphs: SimpleDiGraph, add_edge!, incidence_matrix
5757
import BlockArrays: BlockArray, BlockedArray, Block, blocksize, blocksizes, blockpush!,
5858
undef_blocks, blocks
59+
using OffsetArrays: Origin
5960
import CommonSolve
6061
import EnumX
6162

@@ -152,6 +153,11 @@ include("systems/imperative_affect.jl")
152153
include("systems/callbacks.jl")
153154
include("systems/codegen_utils.jl")
154155
include("systems/problem_utils.jl")
156+
include("linearization.jl")
157+
158+
include("systems/optimization/constraints_system.jl")
159+
include("systems/optimization/optimizationsystem.jl")
160+
include("systems/optimization/modelingtoolkitize.jl")
155161

156162
include("systems/nonlinear/nonlinearsystem.jl")
157163
include("systems/nonlinear/homotopy_continuation.jl")
@@ -168,10 +174,6 @@ include("systems/discrete_system/discrete_system.jl")
168174

169175
include("systems/jumps/jumpsystem.jl")
170176

171-
include("systems/optimization/constraints_system.jl")
172-
include("systems/optimization/optimizationsystem.jl")
173-
include("systems/optimization/modelingtoolkitize.jl")
174-
175177
include("systems/pde/pdesystem.jl")
176178

177179
include("systems/sparsematrixclil.jl")
@@ -258,7 +260,8 @@ export Term, Sym
258260
export SymScope, LocalScope, ParentScope, DelayParentScope, GlobalScope
259261
export independent_variable, equations, controls, observed, full_equations
260262
export initialization_equations, guesses, defaults, parameter_dependencies, hierarchy
261-
export structural_simplify, expand_connections, linearize, linearization_function
263+
export structural_simplify, expand_connections, linearize, linearization_function,
264+
LinearizationProblem
262265

263266
export calculate_jacobian, generate_jacobian, generate_function, generate_custom_function
264267
export calculate_control_jacobian, generate_control_jacobian
@@ -278,7 +281,7 @@ export toexpr, get_variables
278281
export simplify, substitute
279282
export build_function
280283
export modelingtoolkitize
281-
export generate_initializesystem
284+
export generate_initializesystem, Initial
282285

283286
export alg_equations, diff_equations, has_alg_equations, has_diff_equations
284287
export get_alg_eqs, get_diff_eqs, has_alg_eqs, has_diff_eqs

0 commit comments

Comments
 (0)