1
1
module MTKPyomoDynamicOptExt
2
2
using ModelingToolkit
3
- using PythonCall
3
+ using Pyomo
4
4
using DiffEqBase
5
5
using UnPack
6
6
using NaNMath
7
7
const MTK = ModelingToolkit
8
8
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
28
10
model:: ConcreteModel
29
- U:: PyomoDAEVar
30
- V:: PyomoDAEVar
31
- tₛ:: Union{Int, Py }
11
+ U:: PyomoVar
12
+ V:: PyomoVar
13
+ tₛ:: Union{Int, PyomoVar }
32
14
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)
40
24
end
41
25
end
42
26
@@ -46,7 +30,7 @@ struct PyomoDynamicOptProblem{uType, tType, isinplace, P, F, K} <:
46
30
u0:: uType
47
31
tspan:: tType
48
32
p:: P
49
- wrapped_model:: ConcreteModel
33
+ wrapped_model:: PyomoDynamicOptModel
50
34
kwargs:: K
51
35
52
36
function PyomoDynamicOptProblem (f, u0, tspan, p, model, kwargs... )
58
42
function MTK. PyomoDynamicOptProblem (sys:: ODESystem , u0map, tspan, pmap;
59
43
dt = nothing , steps = nothing ,
60
44
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
63
47
MTK. add_equational_constraints! (prob. wrapped_model, sys, pmap, tspan)
64
48
prob
65
49
end
66
50
67
- MTK. generate_internal_model (m:: Type{PyomoModel } ) = pyomo. ConcreteModel ()
51
+ MTK. generate_internal_model (m:: Type{PyomoDynamicOptModel } ) = ConcreteModel ( pyomo. ConcreteModel () )
68
52
69
53
function MTK. generate_time_variable! (m:: ConcreteModel , tspan, tsteps)
70
54
m. steps = length (tsteps)
71
- m. t = pyomo . ContinuousSet (initialize = collect ( tsteps) , bounds = tspan)
55
+ m. t = dae . ContinuousSet (initialize = tsteps, bounds = tspan)
72
56
end
73
57
74
58
function MTK. generate_state_variable! (m:: ConcreteModel , u0, ns, ts)
75
59
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)
77
62
end
78
63
79
- function MTK. generate_input_variable! (m:: ConcreteModel , u0 , nc, ts)
64
+ function MTK. generate_input_variable! (m:: ConcreteModel , c0 , nc, ts)
80
65
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)
82
68
end
83
69
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
86
72
end
87
73
88
- function MTK. add_constraint! (pmodel:: PyomoModel , cons)
74
+ function MTK. add_constraint! (pmodel:: PyomoDynamicOptModel , cons)
89
75
@unpack model, model_sym, idx_sym, t_sym = pmodel
76
+ @show model. dU
90
77
expr = if cons isa Equation
91
78
cons. lhs - cons. rhs == 0
92
79
elseif cons. relational_op === Symbolics. geq
93
80
cons. lhs - cons. rhs ≥ 0
94
81
else
95
82
cons. lhs - cons. rhs ≤ 0
96
83
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)))
99
89
end
100
90
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
102
94
103
- function add_initial_constraints! (model:: PyomoModel , u0, u0_idxs)
95
+ function MTK . add_initial_constraints! (model:: PyomoDynamicOptModel , u0, u0_idxs, ts )
104
96
for i in u0_idxs
105
97
model. U[i, 0 ]. fix (u0[i])
106
98
end
107
99
end
108
100
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)
144
102
@unpack model, model_sym, t_sym = m
145
103
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)
147
105
end
148
106
149
107
MTK. process_integral_bounds (model, integral_span, tspan) = integral_span
150
108
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)
154
118
end
155
119
156
120
struct PyomoCollocation <: AbstractCollocation
@@ -164,25 +128,18 @@ function MTK.prepare_and_optimize!(prob::PyomoDynamicOptProblem, collocation; ve
164
128
m = prob. wrapped_model. model
165
129
dm = collocation. derivative_method
166
130
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))
169
133
solver = SolverFactory (string (collocation. solver))
170
- solver. solve (m)
134
+ solver. solve (m, tee = true )
135
+ Main. xx[] = solver
171
136
end
172
137
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 )
184
141
185
- function MTK. successful_solve (m:: PyomoModel )
142
+ function MTK. successful_solve (m:: PyomoDynamicOptModel )
186
143
ss = m. solver. status
187
144
tc = m. solver. termination_condition
188
145
if ss == opt. SolverStatus. ok && (tc == opt. TerminationStatus. optimal || tc == opt. TerminationStatus. locallyOptimal)
0 commit comments