Skip to main content

power_flow/
user_data.rs

1use crate::y::build_y;
2use anyhow::Result;
3use num_complex::Complex64;
4use power_flow_data::{BusNum, FixedShunt, Generator, Load, Network};
5use sparsetools::csr::CSR;
6use sparsetools::Complex;
7use std::collections::HashMap;
8use sundials::context::Context;
9use sundials::nvector;
10use sundials::nvector::NVector;
11
12#[derive(Clone)]
13pub(super) struct UserData {
14    // pub(super) struct UserData<'a> {
15    // pub(super) network: &'a Network,
16    // pub(super) network: Network,
17    pub(super) s_base: f64,
18    pub(super) loads: Vec<Load>,
19    pub(super) generators: Vec<Generator>,
20    pub(super) fixed_shunts: Vec<FixedShunt>,
21
22    pub(super) a: HashMap<BusNum, usize>,
23    pub(super) v: HashMap<BusNum, usize>,
24    pub(super) q: HashMap<usize, usize>,
25    pub(super) p: HashMap<usize, usize>,
26    pub(super) slack: BusNum,
27
28    // pub(super) v_base: HashMap<BusNum, f64>, // kV
29    pub(super) ang0: HashMap<BusNum, f64>, // radians
30
31    pub(super) y_mat: CSR<usize, Complex64>,
32}
33
34// impl<'a> UserData<'a> {
35impl UserData {
36    // pub(super) fn new(network: &'a Network) -> Self {
37    pub(super) fn new(network: Network) -> Self {
38        let mut a = HashMap::default();
39        let mut v = HashMap::default();
40        let mut q: HashMap<usize, usize> = HashMap::default();
41        let mut p: HashMap<usize, usize> = HashMap::default();
42        // let mut v_base = HashMap::default();
43        let mut ang0 = HashMap::default();
44
45        let nb = network.buses.len();
46        let ng = network.generators.len();
47        // let index = BusbarIndex::new(&ac_system.busbars);
48        // for _, sub := range nd.net.Substations {
49        //     for _, vl := range sub.VoltageLevels {
50        //         nb += len(vl.Buses)
51        //         ng += len(vl.Generators)
52        //     }
53        // }
54        // let (node_index, n) = ac_system.nodes();
55
56        let slack: Vec<BusNum> = network
57            .buses
58            .iter()
59            .filter(|bus| bus.ide == 3)
60            .map(|bus| bus.i)
61            .collect();
62        assert_eq!(slack.len(), 1);
63        let slack = slack[0];
64
65        // let mut i = 0;
66        // let mut j = 0;
67        let mut k = 0;
68        // for _, sub := range nd.net.Substations {
69        //     for _, vl := range sub.VoltageLevels {
70        for (i, bus) in network.buses.iter().enumerate() {
71            //nd.buses[bus.Id] = i
72            a.insert(bus.i, i);
73            v.insert(bus.i, nb + i);
74
75            // v_base.insert(bus.i, bus.basekv);
76            ang0.insert(bus.i, bus.va.to_radians());
77            // i += 1;
78        }
79        for (j, gen) in network.generators.iter().enumerate() {
80            q.insert(j, 2 * nb + j);
81            // j += 1;
82
83            // if gen.ParticipationFactor == 1 {
84            if gen.i == slack {
85                p.insert(j, 2 * nb + ng + k);
86                k += 1;
87            }
88        }
89        // }
90        // }&
91
92        let y_mat = build_y(&network, &a /*, &v_base*/);
93
94        // if Debug {
95        println!("a: {:?}", a);
96        println!("v: {:?}", v);
97        println!("q: {:?}", q);
98        println!("p: {:?}", p);
99        // }
100
101        Self {
102            // network,
103            s_base: network.caseid.sbase,
104
105            loads: network.loads.clone(),
106            generators: network.generators.clone(),
107            fixed_shunts: network.fixed_shunts.clone(),
108
109            a,
110            v,
111            q,
112            p,
113            slack,
114            // v_base,
115            ang0,
116
117            y_mat,
118        }
119    }
120}
121
122pub struct Flow {
123    pub pi: f64,
124    pub qi: f64,
125    pub pj: f64,
126    pub qj: f64,
127    pub schgi: Complex64,
128    pub schgj: Complex64,
129}
130
131pub fn post_process(
132    network: &mut Network,
133    y: &NVector,
134    a: &HashMap<BusNum, usize>,
135    v: &HashMap<BusNum, usize>,
136    q: &HashMap<usize, usize>,
137    p: &HashMap<usize, usize>,
138    slack: BusNum,
139) -> Result<(Vec<Flow>, Vec<Flow>)> {
140    let s_base = network.caseid.sbase;
141    let yd = y.as_slice();
142
143    let mut brch_flows = Vec::with_capacity(network.branches.len());
144    let mut tfmr_flows = Vec::with_capacity(network.transformers.len());
145
146    // for _, sub := range nd.net.Substations {
147    //     for _, vl := range sub.VoltageLevels {
148    for bus in &mut network.buses {
149        let a = a[&bus.i];
150        let v = v[&bus.i];
151
152        bus.va = yd[a].to_degrees();
153        bus.vm = yd[v];
154    }
155    for (i, gen) in &mut network.generators.iter_mut().enumerate() {
156        // if gen.Bus != "" {
157        let q = q[&i];
158        gen.qg = yd[q] * s_base;
159
160        // if gen.ParticipationFactor == 1 {
161        if gen.i == slack {
162            let p = p[&i];
163            gen.pg = yd[p] * s_base;
164        } else {
165            // gen.pg = gen.TargetP
166        }
167        // } else {
168        //     gen.Q = 0
169        //     gen.P = 0
170        // }
171    }
172    // }
173
174    #[allow(non_snake_case)]
175    for tr in &mut network.transformers {
176        // if tr.Bus1 == "" || tr.Bus2 == "" { // TODO: semi-connected
177        //     tr.P1 = 0
178        //     tr.Q1 = 0
179        //     tr.P2 = 0
180        //     tr.Q2 = 0
181        //     continue
182        // }
183        let Sb = Complex64::new(s_base, 0.0);
184
185        let (g, b) = match tr.cm {
186            1 => (tr.mag1, tr.mag2),
187            _ => {
188                panic!("cm must be 1: {}", tr.cm);
189            }
190        };
191
192        let y0 = 0.5 * Complex64::new(g, b);
193        let y12 = 1.0 / Complex64::new(tr.r1_2, tr.x1_2);
194
195        let tap = tr.windv1;
196        let phi = tr.ang1;
197        let m = Complex64::from_polar(tap, phi.to_radians());
198        let mconj = m.conj();
199        let m2 = Complex64::new(m.norm().powi(2), 0.0);
200
201        let a1 = a[&tr.i];
202        let a2 = a[&tr.j];
203        let v1 = v[&tr.i];
204        let v2 = v[&tr.j];
205
206        let V1 = Complex64::new(yd[v1], yd[a1]);
207        let V2 = Complex64::new(yd[v2], yd[a2]);
208
209        let I1 = (V1 * ((y12 + y0/*+ y1*/) / m2)) - (V2 * (y12 / mconj));
210        let I2 = (V2 * (y12 + y0/*+ y2*/)) - (V1 * (y12 / m));
211        let S1 = V1 * I1.conj() * Sb;
212        let S2 = V2 * I2.conj() * Sb;
213
214        tfmr_flows.push(Flow {
215            pi: S1.real(),
216            qi: S1.imag(),
217            pj: S2.real(),
218            qj: S2.imag(),
219            schgi: y0 * (V1.powi(2) / m2) * Sb,
220            schgj: y0 * V2.powi(2) * Sb,
221        });
222    }
223    // }
224
225    #[allow(non_snake_case)]
226    for l in &network.branches {
227        // if l.Bus1 == "" || l.Bus2 == "" { // TODO: semi-connected
228        //     l.P1 = 0
229        //     l.Q1 = 0
230        //     l.P2 = 0
231        //     l.Q2 = 0
232        //     continue
233        // }
234        let Sb = Complex64::new(s_base, 0.0);
235
236        let y0 = 0.5 * Complex64::new(0.0, l.b);
237        // let y1 = Complex64::new(l.G1, l.B1);
238        // let y2 = Complex64::new(l.G2, l.B2);
239        let y1 = Complex64::new(l.gi, l.bi);
240        let y2 = Complex64::new(l.gj, l.bj);
241        let y12 = Complex64::new(1.0, 0.0) / Complex64::new(l.r, l.x);
242
243        let a1 = a[&l.i];
244        let a2 = a[&l.j];
245        let v1 = v[&l.i];
246        let v2 = v[&l.j];
247
248        let V1 = Complex64::new(yd[v1], yd[a1]);
249        let V2 = Complex64::new(yd[v2], yd[a2]);
250
251        let I1 = (V1 * (y12 + y0 + y1)) - (V2 * y12);
252        let I2 = (V2 * (y12 + y0 + y2)) - (V1 * y12);
253        let S1 = V1 * I1.conj() * Sb;
254        let S2 = V2 * I2.conj() * Sb;
255
256        brch_flows.push(Flow {
257            pi: S1.real(),
258            qi: S1.imag(),
259            pj: S2.real(),
260            qj: S2.imag(),
261            schgi: Complex64::new(l.gi, l.bi) * V1.powi(2) * Sb,
262            schgj: Complex64::new(l.gj, l.bj) * V2.powi(2) * Sb,
263        });
264    }
265
266    // Buses with more than one generator have the total reactive power
267    // dispatch for the bus divided equally among each online generator.
268    // The reactive power is divided in proportion to the reactive range
269    // of each generator, according to the logic in the pfsoln function
270    // by Ray Zimmerman from MATPOWER v7.
271    let mut cg = HashMap::<BusNum, Vec<usize>>::new();
272    for (j, gen) in network.generators.iter().enumerate() {
273        // if !cg.contains_key(&gen.i) {
274        //     cg.insert(gen.i, vec![]);
275        // }
276        // cg.get_mut(&gen.i).unwrap().push(j);
277        cg.entry(gen.i).or_insert_with(Vec::new).push(j);
278    }
279
280    for (_, l) in &cg {
281        if l.len() < 2 {
282            continue;
283        }
284        let mut qg_tot: f64 = 0.0; // Total Qg at the bus.
285        for &g in l {
286            qg_tot += network.generators[g].qg;
287        }
288
289        // The sum of absolute Qg, Qmax and Qmin for all generators
290        // at the bus (if Qmax/Qmin is non-infinite). Used as limit
291        // when Qmax/Qmin is infinite.
292        let mut m: f64 = 0.0;
293        for &j in l {
294            let pv = &network.generators[j];
295            let mut mj = pv.qg.abs();
296            if !pv.qt.is_infinite() {
297                mj += pv.qt.abs();
298            }
299            if !pv.qb.is_infinite() {
300                mj += pv.qb.abs();
301            }
302            m += mj
303        }
304        let mut q_min = vec![0.0; l.len()];
305        let mut q_max = vec![0.0; l.len()];
306        for (i, j) in l.iter().enumerate() {
307            let pv = &network.generators[*j];
308
309            q_min[i] = pv.qb;
310            q_max[i] = pv.qt;
311
312            if pv.qb == f64::INFINITY {
313                q_min[i] = m;
314            }
315            if pv.qb == f64::NEG_INFINITY {
316                q_min[i] = -m;
317            }
318            if pv.qt == f64::INFINITY {
319                q_max[i] = m;
320            }
321            if pv.qt == f64::NEG_INFINITY {
322                q_max[i] = -m;
323            }
324        }
325        let qg_min: f64 = q_min.iter().sum(); // Minimum total Qg at the bus.
326        let qg_max: f64 = q_max.iter().sum(); // Maximum total Qg at the bus.
327
328        if (qg_min - qg_max).abs() > 1e-13 {
329            let q = (qg_tot - qg_min) / (qg_max - qg_min);
330            for (i, &j) in l.iter().enumerate() {
331                //pv.Qg = pv.QMin + (((QgTot - QgMin) / (QgMax - QgMin)) / (pv.QMax - pv.QMin))
332                network.generators[j].qg = q_min[i] + (q * (q_max[i] - q_min[i]));
333            }
334        } else {
335            // Zero Qg range at bus. Qg set such that all generators
336            // at the bus violate their limits by the same amount.
337
338            // Total mismatch at bus divided by number of online generators.
339            let mis = (qg_tot - qg_min) / (l.len() as f64);
340            for (i, &j) in l.iter().enumerate() {
341                network.generators[j].qg = q_min[i] + mis;
342            }
343        }
344    }
345
346    Ok((brch_flows, tfmr_flows))
347}
348
349pub fn u0(
350    ctx: &Context,
351    network: &Network,
352    a: &HashMap<BusNum, usize>,
353    v: &HashMap<BusNum, usize>,
354    q: &HashMap<usize, usize>,
355    p: &HashMap<usize, usize>,
356    ang0: &HashMap<BusNum, f64>,
357    slack: BusNum,
358) -> NVector {
359    // nd.indexNetwork()
360    let s_base = network.caseid.sbase;
361
362    let n = a.len() + v.len() + q.len() + p.len();
363    let v0 = nvector::NVector::new_serial(n as i64, ctx).unwrap(); // [Va Vm Qg Pref]
364    let data = v0.as_slice_mut();
365
366    for bus in &network.buses {
367        let a = a[&bus.i];
368        let v = v[&bus.i];
369        let ang0 = ang0[&bus.i];
370
371        data[a] = ang0;
372        if bus.vm != 0.0 {
373            data[v] = bus.vm;
374        } else {
375            data[v] = 1.0;
376        }
377    }
378
379    for (i, gen) in network.generators.iter().enumerate() {
380        if gen.vs != 0.0 {
381            let v = v[&gen.i];
382            data[v] = gen.vs;
383        }
384
385        let qg = q[&i];
386        data[qg] = gen.qg / s_base;
387
388        if gen.i == slack {
389            let pg = p[&i];
390            data[pg] = gen.pg / s_base;
391        }
392    }
393
394    // println!("v0: {}", floats.String(data, prec))
395    println!("v0: {:?}", data);
396
397    v0
398}