1616
1717_convert_array (data:: N , backend) where {names,N<: NamedTuple{names} } =
1818 NamedTuple {names} (ExaModels. convert_array (d, backend) for d in data)
19- function _parse_ac_data_raw (filename)
19+ function _parse_ac_data_raw (filename; T = Float64 )
2020 ref = _build_power_ref (filename) # FIXME : only parse once
2121 arcdict = Dict (a => k for (k, a) in enumerate (ref[:arcs ]))
2222 busdict = Dict (k => i for (i, (k, _)) in enumerate (ref[:bus ]))
@@ -27,24 +27,24 @@ function _parse_ac_data_raw(filename)
2727 begin
2828 loads = [ref[:load ][l] for l in ref[:bus_loads ][k]]
2929 shunts = [ref[:shunt ][s] for s in ref[:bus_shunts ][k]]
30- pd = sum (load[" pd" ] for load in loads; init = 0.0 )
31- qd = sum (load[" qd" ] for load in loads; init = 0.0 )
32- gs = sum (shunt[" gs" ] for shunt in shunts; init = 0.0 )
33- bs = sum (shunt[" bs" ] for shunt in shunts; init = 0.0 )
30+ pd = T ( sum (load[" pd" ] for load in loads; init = 0.0 ) )
31+ qd = T ( sum (load[" qd" ] for load in loads; init = 0.0 ) )
32+ gs = T ( sum (shunt[" gs" ] for shunt in shunts; init = 0.0 ) )
33+ bs = T ( sum (shunt[" bs" ] for shunt in shunts; init = 0.0 ) )
3434 (i = busdict[k], pd = pd, gs = gs, qd = qd, bs = bs)
3535 end for (k, _) in ref[:bus ]
3636 ],
3737 gen = [
3838 (
3939 i = gendict[k],
40- cost1 = v[" cost" ][1 ],
41- cost2 = v[" cost" ][2 ],
42- cost3 = v[" cost" ][3 ],
40+ cost1 = T ( v[" cost" ][1 ]) ,
41+ cost2 = T ( v[" cost" ][2 ]) ,
42+ cost3 = T ( v[" cost" ][3 ]) ,
4343 bus = busdict[v[" gen_bus" ]],
4444 ) for (k, v) in ref[:gen ]
4545 ],
4646 arc = [
47- (i = k, rate_a = ref[:branch ][l][" rate_a" ], bus = busdict[i]) for
47+ (i = k, rate_a = T ( ref[:branch ][l][" rate_a" ]) , bus = busdict[i]) for
4848 (k, (l, i, _)) in enumerate (ref[:arcs ])
4949 ],
5050 branch = [
@@ -67,34 +67,34 @@ function _parse_ac_data_raw(filename)
6767 t_idx = t_idx,
6868 f_bus = busdict[branch[" f_bus" ]],
6969 t_bus = busdict[branch[" t_bus" ]],
70- c1 = ( - g * tr - b * ti) / ttm,
71- c2 = ( - b * tr + g * ti) / ttm,
72- c3 = ( - g * tr + b * ti) / ttm,
73- c4 = ( - b * tr - g * ti) / ttm,
74- c5 = ( g + g_fr) / ttm,
75- c6 = ( b + b_fr) / ttm,
76- c7 = ( g + g_to),
77- c8 = ( b + b_to),
78- rate_a_sq = branch[" rate_a" ]^ 2 ,
70+ c1 = T (( - g * tr - b * ti) / ttm) ,
71+ c2 = T (( - b * tr + g * ti) / ttm) ,
72+ c3 = T (( - g * tr + b * ti) / ttm) ,
73+ c4 = T (( - b * tr - g * ti) / ttm) ,
74+ c5 = T (( g + g_fr) / ttm) ,
75+ c6 = T (( b + b_fr) / ttm) ,
76+ c7 = T (( g + g_to) ),
77+ c8 = T (( b + b_to) ),
78+ rate_a_sq = T ( branch[" rate_a" ]^ 2 ) ,
7979 )
8080 end for (i, branch_raw) in ref[:branch ]
8181 ],
8282 ref_buses = [busdict[i] for (i, _) in ref[:ref_buses ]],
83- vmax = [v[" vmax" ] for (_, v) in ref[:bus ]],
84- vmin = [v[" vmin" ] for (_, v) in ref[:bus ]],
85- pmax = [v[" pmax" ] for (_, v) in ref[:gen ]],
86- pmin = [v[" pmin" ] for (_, v) in ref[:gen ]],
87- qmax = [v[" qmax" ] for (_, v) in ref[:gen ]],
88- qmin = [v[" qmin" ] for (_, v) in ref[:gen ]],
89- rate_a = [ref[:branch ][l][" rate_a" ] for (l, _, _) in ref[:arcs ]],
90- angmax = [b[" angmax" ] for (_, b) in ref[:branch ]],
91- angmin = [b[" angmin" ] for (_, b) in ref[:branch ]],
83+ vmax = [T ( v[" vmax" ]) for (_, v) in ref[:bus ]],
84+ vmin = [T ( v[" vmin" ]) for (_, v) in ref[:bus ]],
85+ pmax = [T ( v[" pmax" ]) for (_, v) in ref[:gen ]],
86+ pmin = [T ( v[" pmin" ]) for (_, v) in ref[:gen ]],
87+ qmax = [T ( v[" qmax" ]) for (_, v) in ref[:gen ]],
88+ qmin = [T ( v[" qmin" ]) for (_, v) in ref[:gen ]],
89+ rate_a = [T ( ref[:branch ][l][" rate_a" ]) for (l, _, _) in ref[:arcs ]],
90+ angmax = [T ( b[" angmax" ]) for (_, b) in ref[:branch ]],
91+ angmin = [T ( b[" angmin" ]) for (_, b) in ref[:branch ]],
9292 )
9393end
9494
9595_parse_ac_data (filename) = _parse_ac_data_raw (filename)
96- function _parse_ac_data (filename, backend)
97- _convert_array (_parse_ac_data_raw (filename), backend)
96+ function _parse_ac_data (filename, backend; T = Float64 )
97+ _convert_array (_parse_ac_data_raw (filename, T = T ), backend)
9898end
9999
100100function create_ac_power_model (
@@ -188,9 +188,101 @@ function create_ac_power_model(
188188 return ExaModel (c; prod = prod)
189189end
190190
191- # TODO : parametric version
191+ # Parametric version
192192
193- function create_power_models (backend = OpenCLBackend ())
193+ function create_parametric_ac_power_model (filename:: String = " pglib_opf_case14_ieee.m" ;
194+ prod:: Bool = true , backend = OpenCLBackend (), T= Float64, kwargs... )
195+ data = _parse_ac_data (filename, backend, T= T)
196+ c = ExaCore (T; backend = backend)
197+
198+ va = variable (c, length (data. bus);)
199+ vm = variable (
200+ c,
201+ length (data. bus);
202+ start = fill! (similar (data. bus, T), 1.0 ),
203+ lvar = data. vmin,
204+ uvar = data. vmax,
205+ )
206+
207+ pg = variable (c, length (data. gen); lvar = data. pmin, uvar = data. pmax)
208+ qg = variable (c, length (data. gen); lvar = data. qmin, uvar = data. qmax)
209+
210+ @allowscalar pd = parameter (c, [b. pd for b in data. bus])
211+ @allowscalar qd = parameter (c, [b. qd for b in data. bus])
212+
213+ p = variable (c, length (data. arc); lvar = - data. rate_a, uvar = data. rate_a)
214+ q = variable (c, length (data. arc); lvar = - data. rate_a, uvar = data. rate_a)
215+
216+ o = objective (c, g. cost1 * pg[g. i]^ 2 + g. cost2 * pg[g. i] + g. cost3 for g in data. gen)
217+
218+ # Reference bus angle ------------------------------------------------------
219+ c1 = constraint (c, va[i] for i in data. ref_buses)
220+
221+ # Branch power-flow equations ---------------------------------------------
222+ constraint (
223+ c,
224+ (p[b. f_idx] - b. c5 * vm[b. f_bus]^ 2 -
225+ b. c3 * (vm[b. f_bus] * vm[b. t_bus] * cos (va[b. f_bus] - va[b. t_bus])) -
226+ b. c4 * (vm[b. f_bus] * vm[b. t_bus] * sin (va[b. f_bus] - va[b. t_bus])) for
227+ b in data. branch),
228+ )
229+
230+ constraint (
231+ c,
232+ (q[b. f_idx] + b. c6 * vm[b. f_bus]^ 2 +
233+ b. c4 * (vm[b. f_bus] * vm[b. t_bus] * cos (va[b. f_bus] - va[b. t_bus])) -
234+ b. c3 * (vm[b. f_bus] * vm[b. t_bus] * sin (va[b. f_bus] - va[b. t_bus])) for
235+ b in data. branch),
236+ )
237+
238+ constraint (
239+ c,
240+ (p[b. t_idx] - b. c7 * vm[b. t_bus]^ 2 -
241+ b. c1 * (vm[b. t_bus] * vm[b. f_bus] * cos (va[b. t_bus] - va[b. f_bus])) -
242+ b. c2 * (vm[b. t_bus] * vm[b. f_bus] * sin (va[b. t_bus] - va[b. f_bus])) for
243+ b in data. branch),
244+ )
245+
246+ constraint (
247+ c,
248+ (q[b. t_idx] + b. c8 * vm[b. t_bus]^ 2 +
249+ b. c2 * (vm[b. t_bus] * vm[b. f_bus] * cos (va[b. t_bus] - va[b. f_bus])) -
250+ b. c1 * (vm[b. t_bus] * vm[b. f_bus] * sin (va[b. t_bus] - va[b. f_bus])) for
251+ b in data. branch),
252+ )
253+
254+ # Angle difference limits --------------------------------------------------
255+ constraint (
256+ c,
257+ va[b. f_bus] - va[b. t_bus] for b in data. branch; lcon = data. angmin, ucon = data. angmax,
258+ )
259+
260+ # Apparent power thermal limits -------------------------------------------
261+ constraint (
262+ c,
263+ p[b. f_idx]^ 2 + q[b. f_idx]^ 2 - b. rate_a_sq for b in data. branch;
264+ lcon = fill! (similar (data. branch, Float64, length (data. branch)), - Inf ),
265+ )
266+ constraint (
267+ c,
268+ p[b. t_idx]^ 2 + q[b. t_idx]^ 2 - b. rate_a_sq for b in data. branch;
269+ lcon = fill! (similar (data. branch, Float64, length (data. branch)), - Inf ),
270+ )
271+
272+ # Power balance at each bus -----------------------------------------------
273+ load_balance_p = constraint (c, pd[b. i] + b. gs * vm[b. i]^ 2 for b in data. bus)
274+ load_balance_q = constraint (c, qd[b. i] - b. bs * vm[b. i]^ 2 for b in data. bus)
275+
276+ # Map arc & generator variables into the bus balance equations
277+ constraint! (c, load_balance_p, a. bus => p[a. i] for a in data. arc)
278+ constraint! (c, load_balance_q, a. bus => q[a. i] for a in data. arc)
279+ constraint! (c, load_balance_p, g. bus => - pg[g. i] for g in data. gen)
280+ constraint! (c, load_balance_q, g. bus => - qg[g. i] for g in data. gen)
281+
282+ return ExaModel (c; prod = prod)
283+ end
284+
285+ function create_power_models (backend = OpenCLBackend (), T= Float64)
194286 models = ExaModel[]
195287 push! (models, create_ac_power_model (" pglib_opf_case14_ieee.m" ; backend = backend))
196288 names = [" AC-OPF – IEEE-14" ]
0 commit comments