tap_control_probe/
tap_control_probe.rs1use 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}