11module MTKPyomoDynamicOptExt
22using ModelingToolkit
3- using PythonCall
3+ using Pyomo
44using DiffEqBase
55using UnPack
66using NaNMath
77const MTK = ModelingToolkit
88
9- # import pyomo
10- const pyomo = PythonCall. pynew ()
11- PythonCall. pycopy! (pyomo, pyimport (" pyomo.environ" ))
12-
13- struct PyomoDAEVar
14- v:: Py
15- end
16- (v:: PyomoDAEVar )(t) = v. v[:, t]
17- getindex (v:: PyomoDAEVar , i:: Union{Num, Symbolic} , t:: Union{Num, Symbolic} ) = wrap (Term {symeltype(v)} (getindex, [v, unwrap (i), unwrap (t)]))
18- getindex (v:: PyomoDAEVar , i:: Int ) = wrap (Term {symeltype(v)} (getindex, [v, unwrap (i), Colon ()]))
19-
20- for ff in [acos, log1p, acosh, log2, asin, tan, atanh, cos, log, sin, log10, sqrt]
21- f = nameof (ff)
22- @eval NaNMath.$ f (x:: PyomoDAEVar ) = Base.$ f (x)
23- end
24-
25- const SymbolicConcreteModel = Symbolics. symstruct (ConcreteModel)
26-
27- struct PyomoModel
9+ struct PyomoDynamicOptModel
2810 model:: ConcreteModel
29- U:: PyomoDAEVar
30- V:: PyomoDAEVar
31- tₛ:: Union{Int, Py }
11+ U:: PyomoVar
12+ V:: PyomoVar
13+ tₛ:: Union{Int, PyomoVar }
3214 is_free_final:: Bool
33- model_sym:: SymbolicConcreteModel
34- t_sym:: Union{Num, BasicSymbolic}
35- idx_sym:: Union{Num, BasicSymbolic}
36-
37- function PyomoModel (model, U, V, tₛ, is_free_final)
38- @variables MODEL_SYM:: SymbolicConcreteModel IDX_SYM:: Int T_SYM
39- PyomoModel (model, U, V, tₛ, is_free_final, MODEL_SYM, T_SYM, INDEX_SYM)
15+ dU:: PyomoVar
16+ model_sym:: Union{Num, Symbolics.BasicSymbolic}
17+ t_sym:: Union{Num, Symbolics.BasicSymbolic}
18+ idx_sym:: Union{Num, Symbolics.BasicSymbolic}
19+
20+ function PyomoDynamicOptModel (model, U, V, tₛ, is_free_final)
21+ @variables MODEL_SYM:: Symbolics.symstruct (PyomoDynamicOptModel) IDX_SYM:: Int T_SYM
22+ model. dU = dae. DerivativeVar (U, wrt = model. t, initialize = 0 )
23+ new (model, U, V, tₛ, is_free_final, PyomoVar (model. dU), MODEL_SYM, T_SYM, IDX_SYM)
4024 end
4125end
4226
@@ -46,7 +30,7 @@ struct PyomoDynamicOptProblem{uType, tType, isinplace, P, F, K} <:
4630 u0:: uType
4731 tspan:: tType
4832 p:: P
49- wrapped_model:: ConcreteModel
33+ wrapped_model:: PyomoDynamicOptModel
5034 kwargs:: K
5135
5236 function PyomoDynamicOptProblem (f, u0, tspan, p, model, kwargs... )
5842function MTK. PyomoDynamicOptProblem (sys:: ODESystem , u0map, tspan, pmap;
5943 dt = nothing , steps = nothing ,
6044 guesses = Dict (), kwargs... )
61- prob = MTK. process_DynamicOptProblem (PyomoDynamicOptProblem, PyomoModel , sys, u0map, tspan, pmap; dt, steps, guesses, kwargs... )
62- prob . wrapped_model . model . dU = pyomo . DerivativeVar ( prob. wrapped_model. model. U, wrt = model . t)
45+ prob = MTK. process_DynamicOptProblem (PyomoDynamicOptProblem, PyomoDynamicOptModel , sys, u0map, tspan, pmap; dt, steps, guesses, kwargs... )
46+ conc_model = prob. wrapped_model. model
6347 MTK. add_equational_constraints! (prob. wrapped_model, sys, pmap, tspan)
6448 prob
6549end
6650
67- MTK. generate_internal_model (m:: Type{PyomoModel } ) = pyomo. ConcreteModel ()
51+ MTK. generate_internal_model (m:: Type{PyomoDynamicOptModel } ) = ConcreteModel ( pyomo. ConcreteModel () )
6852
6953function MTK. generate_time_variable! (m:: ConcreteModel , tspan, tsteps)
7054 m. steps = length (tsteps)
71- m. t = pyomo . ContinuousSet (initialize = collect ( tsteps) , bounds = tspan)
55+ m. t = dae . ContinuousSet (initialize = tsteps, bounds = tspan)
7256end
7357
7458function MTK. generate_state_variable! (m:: ConcreteModel , u0, ns, ts)
7559 m. u_idxs = pyomo. RangeSet (1 , ns)
76- PyomoDAEVar (pyomo. Var (m. u_idxs, m. t))
60+ m. U = pyomo. Var (m. u_idxs, m. t, initialize = 0 )
61+ PyomoVar (m. U)
7762end
7863
79- function MTK. generate_input_variable! (m:: ConcreteModel , u0 , nc, ts)
64+ function MTK. generate_input_variable! (m:: ConcreteModel , c0 , nc, ts)
8065 m. v_idxs = pyomo. RangeSet (1 , nc)
81- PyomoDAEVar (pyomo. Var (m. v_idxs, m. t))
66+ m. V = pyomo. Var (m. v_idxs, m. t, initialize = 0 )
67+ PyomoVar (m. V)
8268end
8369
84- function MTK. generate_timescale (m:: ConcreteModel , guess, is_free_t)
85- m. tₛ = is_free_t ? pyomo. Var (initialize = guess, bounds = (0 , Inf )) : 1
70+ function MTK. generate_timescale! (m:: ConcreteModel , guess, is_free_t)
71+ m. tₛ = is_free_t ? PyomoVar ( pyomo. Var (initialize = guess, bounds = (0 , Inf ) )) : 1
8672end
8773
88- function MTK. add_constraint! (pmodel:: PyomoModel , cons)
74+ function MTK. add_constraint! (pmodel:: PyomoDynamicOptModel , cons)
8975 @unpack model, model_sym, idx_sym, t_sym = pmodel
76+ @show model. dU
9077 expr = if cons isa Equation
9178 cons. lhs - cons. rhs == 0
9279 elseif cons. relational_op === Symbolics. geq
9380 cons. lhs - cons. rhs ≥ 0
9481 else
9582 cons. lhs - cons. rhs ≤ 0
9683 end
97- constraint_f = Symbolics. build_function (expr, model_sym, idx_sym, t_sym)
98- pyomo. Constraint (rule = constraint_f)
84+ constraint_f = Symbolics. build_function (expr, model_sym, idx_sym, t_sym, expression = Val{false })
85+ @show typeof (constraint_f)
86+ @show typeof (Pyomo. pyfunc (constraint_f))
87+ cons_sym = gensym ()
88+ setproperty! (model, cons_sym, pyomo. Constraint (model. u_idxs, model. t, rule = Pyomo. pyfunc (constraint_f)))
9989end
10090
101- function MTK. set_objective! (m:: PyomoModel , expr) = pyomo. Objective (expr = expr)
91+ function MTK. set_objective! (m:: PyomoDynamicOptModel , expr)
92+ m. model. obj = pyomo. Objective (expr = expr)
93+ end
10294
103- function add_initial_constraints! (model:: PyomoModel , u0, u0_idxs)
95+ function MTK . add_initial_constraints! (model:: PyomoDynamicOptModel , u0, u0_idxs, ts )
10496 for i in u0_idxs
10597 model. U[i, 0 ]. fix (u0[i])
10698 end
10799end
108100
109- function fixed_t_map (m:: PyomoModel , sys, exprs)
110- stidxmap = Dict ([v => i for (i, v) in x_ops])
111- ctidxmap = Dict ([v => i for (i, v) in c_ops])
112- mU = Symbolics. symbolic_getproperty (model_sym, :U )
113- mV = Symbolics. symbolic_getproperty (model_sym, :V )
114- fixed_t_map = Dict ()
115- for expr in exprs
116- vars = MTK. vars (exprs)
117- for st in vars
118- MTK. iscall (st) || continue
119- x = MTK. operation (st)
120- t = only (MTK. arguments (st))
121- MTK. symbolic_type (t) === MTK. NotSymbolic () || continue
122- m. model. t. add (t)
123- fixed_t_map[x (t)] = haskey (stidxmap, x) ? mU[stidxmap[x], t] : mV[ctidxmap[x], t]
124- end
125- end
126- fixed_t_map
127- end
128-
129- function MTK. free_t_map (model, x_ops, c_ops)
130- mU = Symbolics. symbolic_getproperty (model_sym, :U )
131- mV = Symbolics. symbolic_getproperty (model_sym, :V )
132- Dict ([[x (tₛ) => mU[i, end ] for (i, x) in enumerate (x_ops)];
133- [c (tₛ) => mV[i, end ] for (i, c) in enumerate (c_ops)]])
134- end
135-
136- function MTK. whole_t_map (model)
137- mU = Symbolics. symbolic_getproperty (model_sym, :U )
138- mV = Symbolics. symbolic_getproperty (model_sym, :V )
139- Dict ([[v => mU[i, t_sym] for (i, v) in enumerate (sts)];
140- [v => mV[i, t_sym] for (i, v) in enumerate (cts)]])
141- end
142-
143- function MTK. lowered_integral (m:: PyomoModel , arg)
101+ function MTK. lowered_integral (m:: PyomoDynamicOptModel , arg, lo, hi)
144102 @unpack model, model_sym, t_sym = m
145103 arg_f = Symbolics. build_function (arg, model_sym, t_sym)
146- Integral (model. t, wrt = model. t, rule= arg_f)
104+ dae . Integral (model. t, wrt = model. t, rule= arg_f)
147105end
148106
149107MTK. process_integral_bounds (model, integral_span, tspan) = integral_span
150108
151- function MTK. lowered_derivative (m:: PyomoModel , i)
152- mdU = Symbolics. symbolic_getproperty (model_sym, :dU )
153- mdU[i, t_sym]
109+ function MTK. lowered_derivative (m:: PyomoDynamicOptModel , i)
110+ mdU = Symbolics. symbolic_getproperty (m. model_sym, :dU ). val
111+ Symbolics. unwrap (mdU[i, m. t_sym])
112+ end
113+
114+ function MTK. lowered_var (m:: PyomoDynamicOptModel , uv, i, t)
115+ X = Symbolics. symbolic_getproperty (m. model_sym, uv). val
116+ var = t isa Union{Num, Symbolics. Symbolic} ? X[i, m. t_sym] : X[i, t]
117+ Symbolics. unwrap (var)
154118end
155119
156120struct PyomoCollocation <: AbstractCollocation
@@ -164,25 +128,18 @@ function MTK.prepare_and_optimize!(prob::PyomoDynamicOptProblem, collocation; ve
164128 m = prob. wrapped_model. model
165129 dm = collocation. derivative_method
166130 discretizer = TransformationFactory (dm)
167- ncp = is_finite_difference (dm) ? 1 : dm. np
168- discretizer. apply_to (model , wrt = m. t, nfe = m. steps, ncp = ncp, scheme = scheme_string (dm))
131+ ncp = Pyomo . is_finite_difference (dm) ? 1 : dm. np
132+ discretizer. apply_to (m , wrt = m. t, nfe = m. steps, scheme = Pyomo . scheme_string (dm))
169133 solver = SolverFactory (string (collocation. solver))
170- solver. solve (m)
134+ solver. solve (m, tee = true )
135+ Main. xx[] = solver
171136end
172137
173- function MTK. get_U_values (m:: PyomoModel )
174- [pyomo. value (model. U[i]) for i in model. U]
175- end
176-
177- function MTK. get_V_values (m:: PyomoModel )
178- [pyomo. value (model. V[i]) for i in model. V]
179- end
180-
181- function MTK. get_t_values (m:: PyomoModel )
182- [pyomo. value (model. t[i]) for i in model. t]
183- end
138+ MTK. get_U_values (m:: PyomoDynamicOptModel ) = [pyomo. value (m. model. U[i]) for i in m. model. U. index_set ()]
139+ MTK. get_V_values (m:: PyomoDynamicOptModel ) = [pyomo. value (m. model. V[i]) for i in m. model. V. index_set ()]
140+ MTK. get_t_values (m:: PyomoDynamicOptModel ) = Pyomo. get_results (m. model, :t )
184141
185- function MTK. successful_solve (m:: PyomoModel )
142+ function MTK. successful_solve (m:: PyomoDynamicOptModel )
186143 ss = m. solver. status
187144 tc = m. solver. termination_condition
188145 if ss == opt. SolverStatus. ok && (tc == opt. TerminationStatus. optimal || tc == opt. TerminationStatus. locallyOptimal)
0 commit comments