Skip to main content

tap_control_probe/
tap_control_probe.rs

1//! Runs the tap-control outer loops over a CGMES conformity fixture and prints
2//! what each controller decided, against the position the fixture's own SV
3//! profile published.
4use std::path::{Path, PathBuf};
5
6fn main() {
7    let root =
8        Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/data/CGMES-Test-Configurations/v3.0");
9    for name in std::env::args().skip(1) {
10        let dir = root.join(&name);
11        let mut paths: Vec<PathBuf> = std::fs::read_dir(&dir)
12            .unwrap_or_else(|e| panic!("{}: {e}", dir.display()))
13            .filter_map(|e| e.ok().map(|e| e.path()))
14            .filter(|p| p.extension().is_some_and(|e| e == "xml"))
15            .collect();
16        paths.sort();
17        let refs: Vec<&Path> = paths.iter().map(|p| p.as_path()).collect();
18        let ds = gridoxide::cgmes::load_profiles(&refs).expect("load");
19        let net = gridoxide::cgmes::cgmes_to_network(&ds, 100e6).expect("convert");
20
21        let before: Vec<Option<i32>> = net
22            .tap_changers
23            .iter()
24            .map(|c| c.as_ref().map(|c| c.position))
25            .collect();
26
27        let report = gridoxide::run_power_flow(
28            net.buses.clone(),
29            &net.lines,
30            &net.transformers,
31            &net.shunts,
32            gridoxide::TapData {
33                changers: &net.tap_changers,
34                regulation: &net.regulation,
35            },
36            gridoxide::PowerFlowOptions {
37                control_taps: true,
38                enforce_q_limits: true,
39                max_outer_iter: 40,
40                tol: 1e-8,
41                max_iter: 30,
42                ..Default::default()
43            },
44        );
45        let outer = report.outer.as_ref().expect("loops ran");
46        println!("=== {name}: {:?}", report.stats.status);
47        println!("    {:?}", outer.report.as_ref().unwrap());
48        for c in &outer.taps {
49            println!(
50                "    tf {:>3}  {} -> {}  steps {}  reversals {}  {:?}",
51                c.transformer,
52                c.initial_position,
53                c.final_position,
54                c.steps_moved,
55                c.direction_changes,
56                c.outcome
57            );
58        }
59        let moved: Vec<usize> = outer
60            .changers
61            .iter()
62            .enumerate()
63            .filter(|(i, c)| c.as_ref().map(|c| c.position) != before[*i])
64            .map(|(i, _)| i)
65            .collect();
66        println!("    transformers whose tap moved: {moved:?}");
67    }
68}