@@ -109,56 +109,70 @@ include("elements.jl")
109
109
110
110
include (" circuit.jl" )
111
111
112
- struct ModelNonlinearEquation{F,Tpexp<: SMatrix ,Tq0<: SVector ,Tfq<: SMatrix }
112
+ struct ModelNonlinearEquation{F,Solver, Tpexp<: SMatrix ,Tq0<: SVector ,Tfq<: SMatrix }
113
113
func:: F
114
114
pexp:: Tpexp
115
115
q0:: Tq0
116
+ dq:: Matrix{Float64}
117
+ eq:: Matrix{Float64}
118
+ fqprev:: Matrix{Float64}
116
119
fq:: Tfq
120
+ solver:: Solver
117
121
end
118
- function ModelNonlinearEquation (func, pexp, q0, fq)
122
+ function ModelNonlinearEquation (func, pexp′, q0′, dq, eq, fqprev, fq′, :: Type{Solver} , init_z) where {Solver}
123
+ nn = size (fq′, 2 )
124
+ nq = size (pexp′, 1 )
125
+ np = size (pexp′, 2 )
126
+ pexp = SMatrix {nq, np, Float64} (pexp′)
127
+ q0 = SVector {nq, Float64} (q0′)
128
+ fq = SMatrix {nq, nn, Float64} (fq′)
129
+ solver = Solver (
130
+ ParametricNonLinEq {nn, np, nq} (
131
+ (pfull, z) -> func (pfull, fq, z),
132
+ (p) -> q0 + pexp * p,
133
+ (Jq) -> Jq * pexp,
134
+ ),
135
+ zeros (np),
136
+ init_z,
137
+ )
119
138
return ModelNonlinearEquation (
120
139
func,
121
- SMatrix {size(pexp,1),size(pexp,2),Float64} (pexp),
122
- SVector {length(q0),Float64} (q0),
123
- SMatrix {size(fq,1),size(fq,2),Float64} (fq)
140
+ pexp,
141
+ q0,
142
+ Matrix {Float64} (dq),
143
+ Matrix {Float64} (eq),
144
+ Matrix {Float64} (fqprev),
145
+ fq,
146
+ solver,
124
147
)
125
148
end
126
149
127
150
nn (nleq:: ModelNonlinearEquation ) = size (nleq. fq, 2 )
128
151
np (nleq:: ModelNonlinearEquation ) = size (nleq. pexp, 2 )
129
152
nq (nleq:: ModelNonlinearEquation ) = size (nleq. pexp, 1 )
130
153
131
- mutable struct DiscreteModel{Solvers }
154
+ mutable struct DiscreteModel{NLEQs }
132
155
a:: Matrix{Float64}
133
156
b:: Matrix{Float64}
134
157
c:: Matrix{Float64}
135
158
x0:: Vector{Float64}
136
- dqs:: Vector{Matrix{Float64}}
137
- eqs:: Vector{Matrix{Float64}}
138
- fqprevs:: Vector{Matrix{Float64}}
139
159
dy:: Matrix{Float64}
140
160
ey:: Matrix{Float64}
141
161
fy:: Matrix{Float64}
142
162
y0:: Vector{Float64}
143
163
144
- nonlinear_eqs:: Vector{<:ModelNonlinearEquation}
164
+ nonlinear_eqs:: NLEQs
145
165
146
- solvers:: Solvers
147
166
x:: Vector{Float64}
148
167
149
- function DiscreteModel (
150
- mats:: Dict{Symbol} ,
151
- nonlinear_eqs:: Vector{<:ModelNonlinearEquation} ,
152
- solvers:: Solvers ,
153
- ) where {Solvers}
154
- model = new {Solvers} ()
168
+ function DiscreteModel (mats:: Dict{Symbol} , nonlinear_eqs:: NLEQs ) where {NLEQs}
169
+ model = new {NLEQs} ()
155
170
156
- for mat in (:a , :b , :c , :dqs , :eqs , :fqprevs , : dy , :ey , :fy , :x0 , :y0 )
171
+ for mat in (:a , :b , :c , :dy , :ey , :fy , :x0 , :y0 )
157
172
setfield! (model, mat, convert (fieldtype (typeof (model), mat), mats[mat]))
158
173
end
159
174
160
175
model. nonlinear_eqs = nonlinear_eqs
161
- model. solvers = solvers
162
176
model. x = zeros (nx (model))
163
177
return model
164
178
end
@@ -235,26 +249,16 @@ function DiscreteModel(circ::Circuit, t::Real, ::Type{Solver}=HomotopySolver{Cac
235
249
model_nps = size .(mats[:dqs ], 1 )
236
250
end
237
251
238
- nonlinear_eqs = ModelNonlinearEquation[
239
- ModelNonlinearEquation (func, pexp, q0, fq)
240
- for (func, pexp, q0, fq) in zip (
241
- nonlinear_eq_funcs, mats[:pexps ], mats[:q0s ], mats[:fqs ]
242
- )
243
- ]
244
-
245
- solvers = Tuple (
246
- Solver (
247
- ParametricNonLinEq {nn(nleq), np(nleq), nq(nleq)} (
248
- (pfull, z) -> nleq. func (pfull, nleq. fq, z),
249
- (p) -> nleq. q0 + nleq. pexp * p,
250
- (Jq) -> Jq * nleq. pexp,
251
- ),
252
- zeros (np (nleq)),
253
- init_z,
252
+ nonlinear_eqs = Tuple (
253
+ ModelNonlinearEquation (func, pexp, q0, dq, eq, fqprev, fq, Solver, init_z)
254
+ for (func, pexp, q0, dq, eq, fqprev, fq, init_z) in zip (
255
+ nonlinear_eq_funcs,
256
+ getindex .((mats,), (:pexps , :q0s , :dqs , :eqs , :fqprevs , :fqs ))... ,
257
+ init_zs,
254
258
)
255
- for (nleq, init_z) in zip (nonlinear_eqs, init_zs)
256
259
)
257
- return DiscreteModel (mats, nonlinear_eqs, solvers)
260
+
261
+ return DiscreteModel (mats, nonlinear_eqs)
258
262
end
259
263
260
264
function model_matrices (circ:: Circuit , t:: Rational{BigInt} )
439
443
440
444
nx (model:: DiscreteModel ) = length (model. x0)
441
445
nq (model:: DiscreteModel , subidx) = length (model. nonlinear_eqs[subidx]. q0)
442
- np (model:: DiscreteModel , subidx) = size (model. dqs [subidx], 1 )
446
+ np (model:: DiscreteModel , subidx) = np (model. nonlinear_eqs [subidx])
443
447
nu (model:: DiscreteModel ) = size (model. b, 2 )
444
448
ny (model:: DiscreteModel ) = length (model. y0)
445
449
nn (model:: DiscreteModel , subidx) = size (model. nonlinear_eqs[subidx]. fq, 2 )
@@ -449,22 +453,22 @@ function steadystate(model::DiscreteModel, u=zeros(nu(model)))
449
453
IA_LU = lu (I- model. a)
450
454
steady_z = zeros (nn (model))
451
455
zoff = 1
452
- for idx in 1 : length ( model. solvers)
453
- zoff_last = zoff+ nn (model,idx )- 1
454
- steady_q0 = model . nonlinear_eqs[idx] . q0 + model . nonlinear_eqs[idx] . pexp * ((model . dqs[idx] / IA_LU * model . b + model . eqs[idx]) * u + (model . dqs[idx] / IA_LU * model . c + model . fqprevs[idx]) * steady_z) +
455
- model . nonlinear_eqs[idx] . pexp* model. dqs[idx] / IA_LU* model. x0
456
- fq = model . nonlinear_eqs[idx] . pexp* model . dqs[idx] / IA_LU* model. c[:,zoff : zoff_last] + model . nonlinear_eqs[idx] . fq
457
- nleq = model. nonlinear_eqs[idx] . func
458
- steady_nl_eq_func = (pfull, z) -> nleq (pfull, fq, z)
459
- steady_nleq = ParametricNonLinEq {nn(model, idx ), nq(model, idx )} (steady_nl_eq_func)
460
- steady_solver = Base . invokelatest (HomotopySolver{SimpleSolver}, steady_nleq, zeros ( nq (model, idx)),
461
- zeros (nn (model, idx )))
456
+ for nleq in model. nonlinear_eqs
457
+ zoff_last = zoff+ nn (nleq )- 1
458
+ steady_q0 = nleq . q0 +
459
+ nleq . pexp* ((nleq . dq / IA_LU * model. b + nleq . eq) * u + (nleq . dq / IA_LU* model. c + nleq . fqprev) * steady_z) +
460
+ nleq . pexp* nleq . dq / IA_LU* model. x0
461
+ fq = nleq . pexp * nleq . dq / IA_LU * model. c[:,zoff : zoff_last] + nleq . fq
462
+ steady_nl_eq_func = (pfull, z) -> nleq. func (pfull, fq, z)
463
+ steady_nleq = ParametricNonLinEq {nn(nleq ), nq(nleq )} (steady_nl_eq_func)
464
+ steady_solver =
465
+ HomotopySolver {SimpleSolver} (steady_nleq, zeros (nq (nleq)), zeros ( nn (nleq )))
462
466
set_resabstol! (steady_solver, 1e-15 )
463
467
steady_z[zoff: zoff_last] = Base. invokelatest (solve, steady_solver, steady_q0)
464
468
if ! hasconverged (steady_solver)
465
469
error (" Failed to find steady state solution" )
466
470
end
467
- zoff += nn (model,idx )
471
+ zoff += nn (nleq )
468
472
end
469
473
return IA_LU\ (model. b* u + model. c* steady_z + model. x0)
470
474
end
@@ -477,10 +481,10 @@ end
477
481
478
482
function linearize (model:: DiscreteModel , usteady:: AbstractVector{Float64} = zeros (nu (model)))
479
483
xsteady = steadystate (model, usteady)
480
- zranges = Vector {UnitRange{Int64}} (undef, length (model. solvers ))
481
- dzdps = Vector {Matrix{Float64}} (undef, length (model. solvers ))
482
- dqlins = Vector {Matrix{Float64}} (undef, length (model. solvers ))
483
- eqlins = Vector {Matrix{Float64}} (undef, length (model. solvers ))
484
+ zranges = Vector {UnitRange{Int64}} (undef, length (model. nonlinear_eqs ))
485
+ dzdps = Vector {Matrix{Float64}} (undef, length (model. nonlinear_eqs ))
486
+ dqlins = Vector {Matrix{Float64}} (undef, length (model. nonlinear_eqs ))
487
+ eqlins = Vector {Matrix{Float64}} (undef, length (model. nonlinear_eqs ))
484
488
zsteady = zeros (nn (model))
485
489
zoff = 1
486
490
x0 = copy (model. x0)
@@ -492,17 +496,16 @@ function linearize(model::DiscreteModel, usteady::AbstractVector{Float64}=zeros(
492
496
ey = copy (model. ey)
493
497
fy = copy (model. fy)
494
498
495
- for idx in 1 : length (model. solvers)
496
- psteady = model. dqs[idx] * xsteady + model. eqs[idx] * usteady +
497
- model. fqprevs[idx] * zsteady
498
- zsub, dzdps[idx] =
499
- Base. invokelatest (linearize, model. solvers[idx], psteady)
499
+ for idx in 1 : length (model. nonlinear_eqs)
500
+ psteady = model. nonlinear_eqs[idx]. dq * xsteady + model. nonlinear_eqs[idx]. eq * usteady +
501
+ model. nonlinear_eqs[idx]. fqprev * zsteady
502
+ zsub, dzdps[idx] = linearize (model. nonlinear_eqs[idx]. solver, psteady)
500
503
copyto! (zsteady, zoff, zsub, 1 , length (zsub))
501
504
502
505
zranges[idx] = zoff: zoff+ length (zsub)- 1
503
- fqdzdps = [model. fqprevs [idx][:,zranges[n]] * dzdps[n] for n in 1 : idx- 1 ]
504
- dqlins[idx] = reduce (+ , init= model. dqs [idx], fqdzdps .* dqlins[1 : idx- 1 ])
505
- eqlins[idx] = reduce (+ , init= model. eqs [idx], fqdzdps .* eqlins[1 : idx- 1 ])
506
+ fqdzdps = [model. nonlinear_eqs [idx]. fqprev [:,zranges[n]] * dzdps[n] for n in 1 : idx- 1 ]
507
+ dqlins[idx] = reduce (+ , init= model. nonlinear_eqs [idx]. dq , fqdzdps .* dqlins[1 : idx- 1 ])
508
+ eqlins[idx] = reduce (+ , init= model. nonlinear_eqs [idx]. eq , fqdzdps .* eqlins[1 : idx- 1 ])
506
509
507
510
x0 += model. c[:,zranges[idx]] * (zsub - dzdps[idx]* psteady)
508
511
a += model. c[:,zranges[idx]] * dzdps[idx] * dqlins[idx]
@@ -520,7 +523,7 @@ function linearize(model::DiscreteModel, usteady::AbstractVector{Float64}=zeros(
520
523
:eqs => Matrix{Float64}[], :fqprevs => Matrix{Float64}[],
521
524
:fqs => Matrix{Float64}[], :q0s => Vector{Float64}[],
522
525
:dy => dy, :ey => ey, :fy => zeros (ny (model), 0 ), :x0 => x0, :y0 => y0)
523
- return DiscreteModel (mats, ModelNonlinearEquation[], ())
526
+ return DiscreteModel (mats, ())
524
527
end
525
528
526
529
"""
@@ -550,7 +553,7 @@ struct ModelRunner{Model<:DiscreteModel,ShowProgress}
550
553
z:: Vector{Float64}
551
554
function ModelRunner {Model,ShowProgress} (model:: Model ) where {Model<: DiscreteModel ,ShowProgress}
552
555
ucur = Vector {Float64} (undef, nu (model))
553
- ps = Vector{Float64}[Vector {Float64} (undef, np (model, idx)) for idx in 1 : length (model. solvers )]
556
+ ps = Vector{Float64}[Vector {Float64} (undef, np (model, idx)) for idx in 1 : length (model. nonlinear_eqs )]
554
557
ycur = Vector {Float64} (undef, ny (model))
555
558
xnew = Vector {Float64} (undef, nx (model))
556
559
z = Vector {Float64} (undef, nn (model))
@@ -646,20 +649,20 @@ function step!(runner::ModelRunner, y::AbstractMatrix{Float64}, u::AbstractMatri
646
649
copyto! (ucur, 1 , u, (n- 1 )* nu (model)+ 1 , nu (model))
647
650
zoff = 1
648
651
fill! (z, 0.0 )
649
- for idx in 1 : length (model. solvers )
652
+ for idx in 1 : length (model. nonlinear_eqs )
650
653
p = runner. ps[idx]
651
654
# copyto!(p, model.dqs[idx] * model.x + model.eqs[idx] * u[:,n]) + model.fqprevs[idx] * z
652
- if size (model. dqs [idx], 2 ) == 0
655
+ if size (model. nonlinear_eqs [idx]. dq , 2 ) == 0
653
656
fill! (p, 0.0 )
654
657
else
655
- BLAS. gemv! (' N' , 1. , model. dqs [idx], model. x, 0. , p)
658
+ BLAS. gemv! (' N' , 1. , model. nonlinear_eqs [idx]. dq , model. x, 0. , p)
656
659
end
657
- BLAS. gemv! (' N' , 1. , model. eqs [idx], ucur, 1. , p)
660
+ BLAS. gemv! (' N' , 1. , model. nonlinear_eqs [idx]. eq , ucur, 1. , p)
658
661
if idx > 1
659
- BLAS. gemv! (' N' , 1. , model. fqprevs [idx], z, 1. , p)
662
+ BLAS. gemv! (' N' , 1. , model. nonlinear_eqs [idx]. fqprev , z, 1. , p)
660
663
end
661
- zsub = solve (model. solvers [idx], p)
662
- if ! hasconverged (model. solvers [idx])
664
+ zsub = solve (model. nonlinear_eqs [idx]. solver , p)
665
+ if ! hasconverged (model. nonlinear_eqs [idx]. solver )
663
666
if all (isfinite, zsub)
664
667
@warn " Failed to converge while solving non-linear equation."
665
668
else
0 commit comments