diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 03c46a70..66bf33bb 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -1,6 +1,11 @@
name: CI
-on: [push]
+on:
+ push:
+ branches:
+ - 'main'
+ - 'release-v**'
+ pull_request:
jobs:
build:
diff --git a/.gitignore b/.gitignore
index 342ed83d..5015bfa0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,18 @@ org.eclipse.core.resources.prefs
org.eclipse.jdt.core.prefs
org.eclipse.m2e.core.prefs
org.eclipse.jdt.groovy.core.prefs
+/ampl_files/ampl_network_batteries.txt
+/ampl_files/ampl_network_branches.txt
+/ampl_files/ampl_network_buses.txt
+/ampl_files/ampl_network_generators.txt
+/ampl_files/ampl_network_hvdc.txt
+/ampl_files/ampl_network_lcc_converter_stations.txt
+/ampl_files/ampl_network_limits.txt
+/ampl_files/ampl_network_loads.txt
+/ampl_files/ampl_network_ptc.txt
+/ampl_files/ampl_network_rtc.txt
+/ampl_files/ampl_network_shunts.txt
+/ampl_files/ampl_network_static_var_compensators.txt
+/ampl_files/ampl_network_substations.txt
+/ampl_files/ampl_network_tct.txt
+/ampl_files/ampl_network_vsc_converter_stations.txt
diff --git a/README.md b/README.md
index 0ad5590b..bf392735 100644
--- a/README.md
+++ b/README.md
@@ -5,3 +5,4 @@
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=com.powsybl%3Apowsybl-incubator&metric=alert_status)](https://sonarcloud.io/dashboard?id=com.powsybl%3Apowsybl-incubator)
[![MPL-2.0 License](https://img.shields.io/badge/license-MPL_2.0-blue.svg)](https://www.mozilla.org/en-US/MPL/2.0/)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/powsybl)
+[![Slack](https://img.shields.io/badge/slack-powsybl-blueviolet.svg?logo=slack)](https://join.slack.com/t/powsybl/shared_invite/zt-rzvbuzjk-nxi0boim1RKPS5PjieI0rA)
diff --git a/ampl_files/ampl_computed_data.mod b/ampl_files/ampl_computed_data.mod
new file mode 100644
index 00000000..15f66f14
--- /dev/null
+++ b/ampl_files/ampl_computed_data.mod
@@ -0,0 +1,57 @@
+#--- COMPUTED DATA ---
+# We are assuming that the "variant" input data always equals 1
+# VARIANTS check
+set VARIANTS = union{(i,j) in VARIANTS_BUSES} {i};
+if card(VARIANTS) > 1 then {
+ printf "Two different variants in data files !\n";
+ quit;
+} else
+ printf "Correct using of variant input\n";
+
+# PV/PQ BUSES definitions and checks
+param set_target_V default 0;
+param generator_controling default 0;
+set BUSES = union{(i,j) in VARIANTS_BUSES} {j};
+set GENS = union{(i,j) in VARIANTS_GENS} {j};
+set PV_BUSES = {i in BUSES: card({j in GENS: gen_bus[1, j] == i and gen_vregul[1, j] == "true"}) >= 1};
+set PQ_BUSES = {i in BUSES: card({j in GENS: gen_bus[1, j] == i and gen_vregul[1, j] == "true"}) == 0};
+param targetV{PV_BUSES};
+for{i in PV_BUSES} {
+ let set_target_V := 0;
+ for{j in GENS: gen_bus[1,j]==i} {
+ if gen_conbus[1,j] != i then {
+ # FIX ME
+ printf "Control of generator %d is not local.\nHowever it will be turned to local in this simulation.\n", j;
+ }
+ if set_target_V == 1 then {
+ if targetV[i] != gen_targetv[1,j] then printf"Inconsistent target V between generators %d and %d at bus %d.\nGenerator %d is chosen as reference.\n", j, generator_controling, i, generator_controling;
+ } else {
+ let targetV[i] := gen_targetv[1,j];
+ let set_target_V := 1;
+ let generator_controling := j;
+ }
+ }
+}
+
+#BRANCHES and LOADS definitions
+set BRANCHES = union{(i,j) in VARIANTS_BRANCHES} {j};
+set LOADS = union{(i,j) in VARIANTS_LOADS} {j};
+
+
+# Compute slack node
+param slack_bus default 0;
+param voltage_level_slack default 0;
+param neighbours_slack default 0;
+for{i in PV_BUSES} {
+ if ss_nomv[1,bus_substations[1,i]] >= voltage_level_slack then {
+ if card({j in BUSES: exists {k in BRANCHES} ((br_bus1[1,k]==i and br_bus2[1,k]==j) or (br_bus1[1,k]==j and br_bus2[1,k]==i))}) > neighbours_slack then {
+ let slack_bus := i;
+ let voltage_level_slack := ss_nomv[1,bus_substations[1,i]];
+ let neighbours_slack := card({j in BUSES: exists {k in BRANCHES} ((br_bus1[1,k]==i and br_bus2[1,k]==j) or (br_bus1[1,k]==j and br_bus2[1,k]==i))});
+ }
+ }
+}
+
+# Branches data computations
+param br_y{i in BRANCHES} := 1/sqrt(br_r[1,i]*br_r[1,i] + br_x[1,i]*br_x[1,i]);
+param br_ksi{i in BRANCHES} := atan2(br_r[1,i], br_x[1,i]);
\ No newline at end of file
diff --git a/ampl_files/ampl_data.dat b/ampl_files/ampl_data.dat
new file mode 100644
index 00000000..f5c099c9
--- /dev/null
+++ b/ampl_files/ampl_data.dat
@@ -0,0 +1,11 @@
+data;
+
+param: VARIANTS_BUSES: bus_substations bus_cc bus_v bus_theta bus_p bus_q bus_fault bus_curative bus_id := include ampl_network_buses.txt;
+
+param: VARIANTS_GENS: gen_bus gen_conbus gen_substation gen_minp gen_maxp gen_minqmaxp gen_minq0 gen_minqminp gen_maxqmaxp gen_maxq0 gen_maxqminp gen_vregul gen_targetv gen_targetp gen_targetq gen_fault gen_curative gen_id gen_desc gen_p gen_q := include ampl_network_generators.txt;
+
+param: VARIANTS_BRANCHES: br_bus1 br_bus2 br_3wtnum br_sub1 br_sub2 br_r br_x br_g1 br_g2 br_b1 br_b2 br_cstr br_ratiotc br_phasetc br_p1 br_p2 br_q1 br_q2 br_patl1 br_patl2 br_merged br_fault br_curative br_id br_desc := include ampl_network_branches.txt;
+
+param: VARIANTS_SS: ss_unused1 ss_unused2 ss_nomv ss_minv ss_maxv ss_fault ss_curative ss_country ss_id ss_desc := include ampl_network_substations.txt;
+
+param: VARIANTS_LOADS: ld_bus ld_ss ld_p0 ld_q0 ld_fault ld_curative ld_id ld_desc ld_p ld_q := include ampl_network_loads.txt;
\ No newline at end of file
diff --git a/ampl_files/ampl_dataread_model.mod b/ampl_files/ampl_dataread_model.mod
new file mode 100644
index 00000000..b720a3f2
--- /dev/null
+++ b/ampl_files/ampl_dataread_model.mod
@@ -0,0 +1,91 @@
+#--- READ DATA ---
+set VARIANTS_BUSES dimen 2;
+
+param bus_substations{VARIANTS_BUSES};
+param bus_cc{VARIANTS_BUSES};
+param bus_v{VARIANTS_BUSES};
+param bus_theta{VARIANTS_BUSES};
+param bus_p{VARIANTS_BUSES};
+param bus_q{VARIANTS_BUSES};
+param bus_fault{VARIANTS_BUSES} binary;
+param bus_curative{VARIANTS_BUSES} binary;
+param bus_id{VARIANTS_BUSES} symbolic;
+
+set VARIANTS_GENS dimen 2;
+param gen_bus{VARIANTS_GENS};
+param gen_conbus{VARIANTS_GENS};
+param gen_substation{VARIANTS_GENS};
+param gen_minp{VARIANTS_GENS};
+param gen_maxp{VARIANTS_GENS};
+param gen_minqmaxp{VARIANTS_GENS};
+param gen_minq0{VARIANTS_GENS};
+param gen_minqminp{VARIANTS_GENS};
+param gen_maxqmaxp{VARIANTS_GENS};
+param gen_maxq0{VARIANTS_GENS};
+param gen_maxqminp{VARIANTS_GENS};
+param gen_vregul{VARIANTS_GENS} symbolic;
+param gen_targetv{VARIANTS_GENS};
+param gen_targetp{VARIANTS_GENS};
+param gen_targetq{VARIANTS_GENS};
+param gen_fault{VARIANTS_GENS} binary;
+param gen_curative{VARIANTS_GENS} binary;
+param gen_id{VARIANTS_GENS} symbolic;
+param gen_desc{VARIANTS_GENS} symbolic;
+param gen_p{VARIANTS_GENS};
+param gen_q{VARIANTS_GENS};
+
+set VARIANTS_BRANCHES dimen 2;
+param br_bus1{VARIANTS_BRANCHES};
+param br_bus2{VARIANTS_BRANCHES};
+param br_3wtnum{VARIANTS_BRANCHES};
+param br_sub1{VARIANTS_BRANCHES};
+param br_sub2{VARIANTS_BRANCHES};
+param br_r{VARIANTS_BRANCHES};
+param br_x{VARIANTS_BRANCHES};
+param br_g1{VARIANTS_BRANCHES};
+param br_g2{VARIANTS_BRANCHES};
+param br_b1{VARIANTS_BRANCHES};
+param br_b2{VARIANTS_BRANCHES};
+param br_cstr{VARIANTS_BRANCHES};
+param br_ratiotc{VARIANTS_BRANCHES};
+param br_phasetc{VARIANTS_BRANCHES};
+param br_p1{VARIANTS_BRANCHES};
+param br_p2{VARIANTS_BRANCHES};
+param br_q1{VARIANTS_BRANCHES};
+param br_q2{VARIANTS_BRANCHES};
+param br_patl1{VARIANTS_BRANCHES};
+param br_patl2{VARIANTS_BRANCHES};
+param br_merged{VARIANTS_BRANCHES} symbolic;
+param br_fault{VARIANTS_BRANCHES} binary;
+param br_curative{VARIANTS_BRANCHES} binary;
+param br_id{VARIANTS_BRANCHES} symbolic;
+param br_desc{VARIANTS_BRANCHES} symbolic;
+
+set VARIANTS_SS dimen 2;
+param ss_unused1{VARIANTS_SS} symbolic;
+param ss_unused2{VARIANTS_SS};
+param ss_nomv{VARIANTS_SS};
+param ss_minv{VARIANTS_SS};
+param ss_maxv{VARIANTS_SS};
+param ss_fault{VARIANTS_SS} binary;
+param ss_curative{VARIANTS_SS} binary;
+param ss_country{VARIANTS_SS} symbolic;
+param ss_id{VARIANTS_SS} symbolic;
+param ss_desc{VARIANTS_SS} symbolic;
+
+set VARIANTS_LOADS dimen 2;
+param ld_bus{VARIANTS_LOADS};
+param ld_ss{VARIANTS_LOADS};
+param ld_p0{VARIANTS_LOADS};
+param ld_q0{VARIANTS_LOADS};
+param ld_fault{VARIANTS_LOADS} binary;
+param ld_curative{VARIANTS_LOADS} binary;
+param ld_id{VARIANTS_LOADS} symbolic;
+param ld_desc{VARIANTS_LOADS} symbolic;
+param ld_p{VARIANTS_LOADS};
+param ld_q{VARIANTS_LOADS};
+
+param v_min{VARIANTS_BUSES} default 0.8;
+param v_max{VARIANTS_BUSES} default 1.2;
+
+param p_pu default 100;
\ No newline at end of file
diff --git a/ampl_files/ampl_model.mod b/ampl_files/ampl_model.mod
new file mode 100644
index 00000000..a582d17d
--- /dev/null
+++ b/ampl_files/ampl_model.mod
@@ -0,0 +1,39 @@
+# Variables
+var V{i in BUSES} default if bus_v[1,i] > 0 then bus_v[1,i] else 1;
+var Phi{BUSES} default 0;
+var Q{PV_BUSES} default 0;
+
+# Objectif function
+minimize Quadratic_Error:
+ sum {i in PQ_BUSES: bus_v[1,i] > 0} ( (V[i] - bus_v[1,i]) * (V[i] - bus_v[1,i]) );
+
+# Constraints
+subject to Active_power_balance{i in BUSES: i != slack_bus}:
+ sum {j in BRANCHES: br_bus1[1,j] == i and br_bus2[1,j] != -1} ( br_cstr[1,j] * V[i] * ( br_g1[1,j] * br_cstr[1,j] * V[i] + br_y[j] * br_cstr[1,j] * V[i] * sin(br_ksi[j]) - br_y[j] * 1 * V[br_bus2[1,j]] * sin(br_ksi[j] - 0 + 0 - Phi[i] + Phi[br_bus2[1,j]]) ) )
+ + sum {j in BRANCHES: br_bus2[1,j] == i and br_bus1[1,j] != -1} ( 1 * V[i] * ( br_g2[1,j] * 1 * V[i] - br_y[j] * br_cstr[1,j] * V[br_bus1[1,j]] * sin(br_ksi[j] + 0 - 0 + Phi[br_bus1[1,j]] - Phi[i]) + br_y[j] * 1 * V[i] * sin(br_ksi[j]) ) )
+ == (sum {j in GENS: gen_bus[1,j] == i} gen_targetp[1,j] - sum {j in LOADS: ld_bus[1,j] == i} ld_p0[1,j])/p_pu;
+
+subject to Null_phase_slack{i in BUSES: i == slack_bus}:
+ Phi[i] == 0;
+
+subject to Rective_power_balance_PQ{i in PQ_BUSES}:
+ sum {j in BRANCHES: br_bus1[1,j] == i and br_bus2[1,j] != -1} ( br_cstr[1,j] * V[i] * (- br_b1[1,j] * br_cstr[1,j] * V[i] + br_y[j] * br_cstr[1,j] * V[i] * cos(br_ksi[j]) - br_y[j] * 1 * V[br_bus2[1,j]] * cos(br_ksi[j] - 0 + 0 - Phi[i] + Phi[br_bus2[1,j]]) ) )
+ + sum {j in BRANCHES: br_bus2[1,j] == i and br_bus1[1,j] != -1} ( 1 * V[i] * ( - br_b2[1,j] * 1 * V[i] - br_y[j] * br_cstr[1,j] * V[br_bus1[1,j]] * cos(br_ksi[j] + 0 - 0 + Phi[br_bus1[1,j]] - Phi[i]) + br_y[j] * 1 * V[i] * cos(br_ksi[j]) ) )
+ == (sum {j in GENS: gen_bus[1,j] == i} gen_targetq[1,j] - sum {j in LOADS: ld_bus[1,j] == i} ld_q0[1,j])/p_pu;
+
+subject to Rective_power_balance_PV{i in PV_BUSES}:
+ sum {j in BRANCHES: br_bus1[1,j] == i and br_bus2[1,j] != -1} ( br_cstr[1,j] * V[i] * (- br_b1[1,j] * br_cstr[1,j] * V[i] + br_y[j] * br_cstr[1,j] * V[i] * cos(br_ksi[j]) - br_y[j] * 1 * V[br_bus2[1,j]] * cos(br_ksi[j] - 0 + 0 - Phi[i] + Phi[br_bus2[1,j]]) ) )
+ + sum {j in BRANCHES: br_bus2[1,j] == i and br_bus1[1,j] != -1} ( 1 * V[i] * ( - br_b2[1,j] * 1 * V[i] - br_y[j] * br_cstr[1,j] * V[br_bus1[1,j]] * cos(br_ksi[j] + 0 - 0 + Phi[br_bus1[1,j]] - Phi[i]) + br_y[j] * 1 * V[i] * cos(br_ksi[j]) ) )
+ == Q[i]/p_pu;
+
+subject to Reactive_power_inf{i in PV_BUSES}:
+ sum {j in GENS: gen_bus[1,j] == i} gen_minq0[1,j] - sum {j in LOADS: ld_bus[1,j] == i} ld_q0[1,j] <= Q[i];
+
+subject to Reactive_power_sup{i in PV_BUSES}:
+ Q[i] <= sum {j in GENS: gen_bus[1,j] == i} gen_maxq0[1,j] - sum {j in LOADS: ld_bus[1,j] == i} ld_q0[1,j];
+
+subject to Voltage_limit_inf{i in BUSES}:
+ sum{(j,k) in VARIANTS_SS: k == bus_substations[1,i] and j == 1} ss_minv[j,k] <= V[i];
+
+subject to Voltage_limit_sup{i in BUSES}:
+ V[i] <= sum{(j,k) in VARIANTS_SS: k == bus_substations[1,i] and j == 1} ss_maxv[j,k];
\ No newline at end of file
diff --git a/ampl_files/ampl_model.run b/ampl_files/ampl_model.run
new file mode 100644
index 00000000..26a0dd30
--- /dev/null
+++ b/ampl_files/ampl_model.run
@@ -0,0 +1,45 @@
+model ampl_dataread_model.mod;
+data ampl_data.dat;
+model ampl_computed_data.mod;
+model ampl_model.mod;
+option solver knitroampl;
+option knitro_options "feastol=1e-3";
+/*
+display BUSES;
+display PV_BUSES;
+display PQ_BUSES;
+display br_x;
+display ss_country;
+display BRANCHES;
+display slack_bus;
+display ld_p0;
+display br_y;
+display br_ksi;
+*/
+problem Initialize_voltage_plan: V, Phi, Q, Quadratic_Error, Active_power_balance, Null_phase_slack, Rective_power_balance_PQ, Rective_power_balance_PV, Reactive_power_inf, Reactive_power_sup, Voltage_limit_inf, Voltage_limit_sup;
+
+solve Initialize_voltage_plan;
+/*
+display V;
+display Phi;
+display Active_power_balance;
+
+for{i in BUSES: i != slack_bus} {
+ display i;
+ display sum {j in BRANCHES: br_bus1[1,j] == i} ( br_cstr[1,j] * V[i] * ( br_g1[1,j] * br_cstr[1,j] * V[i] + br_y[j] * br_cstr[1,j] * V[i] * sin(br_ksi[j]) - br_y[j] * 1 * V[br_bus2[1,j]] * sin(br_ksi[j] - 0 + 0 - Phi[i] + Phi[br_bus2[1,j]]) ) )
+ + sum {j in BRANCHES: br_bus2[1,j] == i} ( 1 * V[i] * ( br_g2[1,j] * 1 * V[i] - br_y[j] * br_cstr[1,j] * V[br_bus1[1,j]] * sin(br_ksi[j] + 0 - 0 + Phi[br_bus1[1,j]] - Phi[i]) + br_y[j] * 1 * V[i] * sin(br_ksi[j]) ) );
+ display sum {j in GENS: gen_bus[1,j] == i} gen_targetp[1,j] - sum {j in LOADS: ld_bus[1,j] == i} ld_p0[1,j];
+ display sum {j in BRANCHES: br_bus1[1,j] == i} ( br_cstr[1,j] * V[i] * (- br_b1[1,j] * br_cstr[1,j] * V[i] + br_y[j] * br_cstr[1,j] * V[i] * cos(br_ksi[j]) - br_y[j] * 1 * V[br_bus2[1,j]] * cos(br_ksi[j] - 0 + 0 - Phi[i] + Phi[br_bus2[1,j]]) ) )
+ + sum {j in BRANCHES: br_bus2[1,j] == i} ( 1 * V[i] * ( - br_b2[1,j] * 1 * V[i] - br_y[j] * br_cstr[1,j] * V[br_bus1[1,j]] * cos(br_ksi[j] + 0 - 0 + Phi[br_bus1[1,j]] - Phi[i]) + br_y[j] * 1 * V[i] * cos(br_ksi[j]) ) );
+ display sum {j in GENS: gen_bus[1,j] == i} gen_targetq[1,j] - sum {j in LOADS: ld_bus[1,j] == i} ld_q0[1,j];
+}
+
+for{i in BUSES} {
+ if sum{(j,k) in VARIANTS_SS: k == bus_substations[1,i] and j == 1} ss_minv[j,k] > V[i] or sum{(j,k) in VARIANTS_SS: k == bus_substations[1,i] and j == 1} ss_maxv[j,k] < V[i] then printf "Bus %d : %f < %f < %f\n", i, sum{(j,k) in VARIANTS_SS: k == bus_substations[1,i] and j == 1} ss_minv[j,k], V[i], sum{(j,k) in VARIANTS_SS: k == bus_substations[1,i] and j == 1} ss_maxv[j,k];
+}
+
+printf "slack node (i=1) \n";
+display sum {j in BRANCHES: br_bus1[1,j] == 1} ( br_cstr[1,j] * V[1] * ( br_g1[1,j] * br_cstr[1,j] * V[1] + br_y[j] * br_cstr[1,j] * V[1] * sin(br_ksi[j]) - br_y[j] * 1 * V[br_bus2[1,j]] * sin(br_ksi[j] - 0 + 0 - Phi[1] + Phi[br_bus2[1,j]]) ) )
+ + sum {j in BRANCHES: br_bus2[1,j] == 1} ( 1 * V[1] * ( br_g2[1,j] * 1 * V[1] - br_y[j] * br_cstr[1,j] * V[br_bus1[1,j]] * sin(br_ksi[j] + 0 - 0 + Phi[br_bus1[1,j]] - Phi[1]) + br_y[j] * 1 * V[1] * sin(br_ksi[j]) ) );
+display Q[1];
+*/
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8e30ae86..6ebd1d02 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,19 +56,20 @@
+ simulator
11
- 4.9.2
+ 1.2.2
com.powsybl
- powsybl-core
- ${powsybl-core.version}
+ powsybl-dependencies
+ ${powsybl-dependencies.version}
pom
import
diff --git a/pyomo/init_voltage_plan/script.py b/pyomo/init_voltage_plan/script.py
new file mode 100644
index 00000000..08cf8f6d
--- /dev/null
+++ b/pyomo/init_voltage_plan/script.py
@@ -0,0 +1,143 @@
+import time
+import pypowsybl as pp
+import pyomo.environ as pyo
+from pyomo.opt import SolverFactory
+from utils import *
+
+debug = True
+if debug:
+ tic = time.perf_counter()
+ print("Beginning...")
+
+# Import network
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Import network...")
+p_pu = 100 # pu is 100MW by default
+n = pp.network.load(network_path)
+#n = pp.per_unit.per_unit_view(n, p_pu) T be used when per unit will be released
+
+# Create pyomo model
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Create pyomo model...")
+model = pyo.ConcreteModel()
+
+# Define bus types
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Define bus types...")
+buses = n.get_buses().index.tolist()
+PV_buses = []
+PQ_buses = []
+for id_gen, row in n.get_generators().iterrows():
+ if row["voltage_regulator_on"]:
+ if row["bus_id"] not in PV_buses: # TO DO: Work only when regulations are local
+ PV_buses.append(row["bus_id"])
+
+for bus in buses:
+ if bus not in PV_buses:
+ PQ_buses.append(bus)
+
+# Define slack node
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Define slack node...")
+slack_bus = ""
+voltage_level_slack = 0
+neighbours_slack = 0
+PV_neighbours = nb_neighboursPV(n, PV_buses)
+for id_b, row in n.get_buses().iterrows():
+ if id_b not in PV_buses:
+ continue
+ if n.get_voltage_levels().at[row["voltage_level_id"], "nominal_v"] >= voltage_level_slack:
+ if PV_neighbours[id_b] > neighbours_slack:
+ slack_bus = id_b
+ voltage_level_slack = n.get_voltage_levels().at[row["voltage_level_id"], "nominal_v"]
+ neighbours_slack = PV_neighbours[id_b]
+
+# Create variables
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Create variables...")
+model.Buses = pyo.Set(initialize=buses)
+model.PVbuses = pyo.Set(initialize=PV_buses)
+model.V = pyo.Var(model.Buses, domain=pyo.NonNegativeReals, bounds=voltage_bounds(n), initialize=voltage_init(n))
+model.Phi = pyo.Var(model.Buses, domain=pyo.Reals, initialize=0)
+model.Q = pyo.Var(model.PVbuses, domain=pyo.Reals, bounds=reactive_power_bounds(n), initialize=reactive_init(n))
+
+# Objective function
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Objective function...")
+model.OBJ = pyo.Objective(rule=obj_expression(n, PQ_buses))
+
+# Constraints
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("Constraints...")
+## Active power balance
+if debug:
+ toc = time.perf_counter()
+ print(f"\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("\tActive power balance...")
+buses_wo_slack = []
+for bus in buses:
+ if bus == slack_bus:
+ continue
+ buses_wo_slack.append(bus)
+
+model.Buses_wo_slack = pyo.Set(initialize=buses_wo_slack)
+model.ActivePowerBalance = pyo.Constraint(model.Buses_wo_slack, rule=active_power_balance_expr(n, buses, p_pu))
+
+## Null phase for slack
+if debug:
+ toc = time.perf_counter()
+ print(f"\t\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("\tNull phase...")
+model.NullPhaseSlack = pyo.Constraint(expr = model.Phi[slack_bus] == 0)
+
+## Reactive power balance for PQ buses
+if debug:
+ toc = time.perf_counter()
+ print(f"\t\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("\tReactive power balance PQ...")
+model.PQbuses = pyo.Set(initialize=PQ_buses)
+model.ReactivePowerBalancePQ = pyo.Constraint(model.PQbuses,rule=reactive_power_balancePQ_expr(n, buses, p_pu))
+
+## Reactive power balance for PV buses
+if debug:
+ toc = time.perf_counter()
+ print(f"\t\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("\tReactive power balance PV...")
+model.ReactivePowerBalancePV = pyo.Constraint(model.PVbuses,rule=reactive_power_balancePV_expr(n, buses, p_pu))
+
+# End
+if debug:
+ toc = time.perf_counter()
+ print(f"\t\tin {toc-tic:0.4f} seconds")
+ tic = time.perf_counter()
+ print("End")
+
+# Solve
+executable = 'knitroampl.exe'
+opt = SolverFactory("knitro", executable=executable, solver_io='nl')
+results = opt.solve(model)
\ No newline at end of file
diff --git a/pyomo/init_voltage_plan/utils.py b/pyomo/init_voltage_plan/utils.py
new file mode 100644
index 00000000..8d163d20
--- /dev/null
+++ b/pyomo/init_voltage_plan/utils.py
@@ -0,0 +1,317 @@
+import numpy as np
+import pyomo.environ as pyo
+
+# Count neighbours function
+def nb_neighboursPV(net, PV_buses):
+ neighbours_count = dict()
+ buses = net.get_buses().index.tolist()
+ for id_line, row in net.get_lines().iterrows():
+ b1 = row["bus1_id"]
+ b2 = row["bus2_id"]
+ if b1 in PV_buses and b2 in buses:
+ if b1 not in neighbours_count:
+ neighbours_count[b1] = 1
+ else:
+ neighbours_count[b1] += 1
+ if b2 in PV_buses and b1 in buses:
+ if b2 not in neighbours_count:
+ neighbours_count[b2] = 1
+ else:
+ neighbours_count[b2] += 1
+ for id_tr, row in net.get_2_windings_transformers().iterrows():
+ b1 = row["bus1_id"]
+ b2 = row["bus2_id"]
+ if b1 in PV_buses and b2 in buses:
+ if b1 not in neighbours_count:
+ neighbours_count[b1] = 1
+ else:
+ neighbours_count[b1] += 1
+ if b2 in PV_buses and b1 in buses:
+ if b2 not in neighbours_count:
+ neighbours_count[b2] = 1
+ else:
+ neighbours_count[b2] += 1
+ return neighbours_count
+
+# Objectif function
+def obj_expression(n, PQ_buses):
+ def obj_expression_m(m):
+ res = 0
+ for id_b, row in n.get_buses().iterrows():
+ if id_b not in PQ_buses:
+ continue
+ if not np.isnan(row["v_mag"]):
+ v_pu_coeff = n.get_voltage_levels().at[row["voltage_level_id"], "nominal_v"]
+ bus_v_pu = row["v_mag"] / v_pu_coeff # TO DO: to be replaced with pu getters
+ res += (m.V[id_b] - bus_v_pu) * (m.V[id_b] - bus_v_pu)
+ return res
+ return obj_expression_m
+
+# Active power balance
+def active_power_balance_expr(n, buses, p_pu):
+ def active_power_balance_expr_m(m,i):
+ v_pu_coeff_i = n.get_voltage_levels().at[n.get_buses().at[i, "voltage_level_id"], "nominal_v"]
+ lhs = 0
+ rhs = 0
+ is_empty = True
+ for id_line, row in n.get_lines().iterrows():
+ if row["bus1_id"] == i and row["bus2_id"] in buses:
+ is_empy = False
+ j = row["bus2_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu = 1
+ line_g1_pu = row[ "g1"] / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += ratio_tr_pu * m.V[i] * ( line_g1_pu * ratio_tr_pu * m.V[i] + line_y_pu * ratio_tr_pu * m.V[i] * pyo.sin(line_ksi) - line_y_pu * 1 * m.V[j] * pyo.sin(line_ksi - 0 + 0 - m.Phi[i] + m.Phi[j]) )
+ elif row["bus2_id"] == i and row["bus1_id"] in buses:
+ is_empy = False
+ j = row["bus1_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu = 1
+ line_g2_pu = row["g2"] / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += 1 * m.V[i] * ( line_g2_pu * 1 * m.V[i] - line_y_pu * ratio_tr_pu * m.V[j] * pyo.sin(line_ksi + 0 - 0 + m.Phi[j] - m.Phi[i]) + line_y_pu * 1 * m.V[i] * pyo.sin(line_ksi) )
+ for id_tr, row in n.get_2_windings_transformers().iterrows():
+ if row["bus1_id"] == i and row["bus2_id"] in buses:
+ is_empy = False
+ j = row["bus2_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu_coeff = v_pu_coeff_j / v_pu_coeff_i
+ ratio_tr_pu = row["rated_u2"] / row["rated_u1"] / ratio_tr_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += ratio_tr_pu * m.V[i] * (line_y_pu * ratio_tr_pu * m.V[i] * pyo.sin(line_ksi) - line_y_pu * 1 * m.V[j] * pyo.sin(line_ksi - 0 + 0 - m.Phi[i] + m.Phi[j]) )
+ elif row["bus2_id"] == i and row["bus1_id"] in buses:
+ is_empy = False
+ j = row["bus1_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu_coeff = v_pu_coeff_i / v_pu_coeff_j
+ ratio_tr_pu = row["rated_u2"] / row["rated_u1"] / ratio_tr_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += 1 * m.V[i] * (- line_y_pu * ratio_tr_pu * m.V[j] * pyo.sin(line_ksi + 0 - 0 + m.Phi[j] - m.Phi[i]) + line_y_pu * 1 * m.V[i] * pyo.sin(line_ksi) )
+ for id_gen, row in n.get_generators().iterrows():
+ if row["bus_id"] == i:
+ rhs += row["target_p"] / p_pu # TO DO: to be replaced with pu getters
+ for id_ld, row in n.get_loads().iterrows():
+ if row["bus_id"] == i:
+ rhs -= row["p0"] / p_pu # TO DO: to be replaced with pu getters
+ if is_empty:
+ return pyo.Constraint.Skip
+ else:
+ return lhs == rhs
+ return active_power_balance_expr_m
+
+# Reactive power balance for PQ buses
+def reactive_power_balancePQ_expr(n, buses, p_pu):
+ def reactive_power_balancePQ_expr_m(m,i):
+ v_pu_coeff_i = n.get_voltage_levels().at[n.get_buses().at[i, "voltage_level_id"], "nominal_v"]
+ lhs = 0
+ rhs = 0
+ is_empty = True
+ for id_line, row in n.get_lines().iterrows():
+ if row["bus1_id"] == i and row["bus2_id"] in buses:
+ is_empy = False
+ j = row["bus2_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu = 1
+ line_b1_pu = row[ "b1"] / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += ratio_tr_pu * m.V[i] * (-line_b1_pu * ratio_tr_pu * m.V[i] + line_y_pu * ratio_tr_pu * m.V[i] * pyo.cos(line_ksi) - line_y_pu * 1 * m.V[j] * pyo.cos(line_ksi - 0 + 0 - m.Phi[i] + m.Phi[j]) )
+ elif row["bus2_id"] == i and row["bus1_id"] in buses:
+ is_empy = False
+ j = row["bus1_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu = 1
+ line_b2_pu = row["b2"] / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += 1 * m.V[i] * ( - line_b2_pu * 1 * m.V[i] - line_y_pu * ratio_tr_pu * m.V[j] * pyo.cos(line_ksi + 0 - 0 + m.Phi[j] - m.Phi[i]) + line_y_pu * 1 * m.V[i] * pyo.cos(line_ksi) )
+ for id_tr, row in n.get_2_windings_transformers().iterrows():
+ if row["bus1_id"] == i and row["bus2_id"] in buses:
+ is_empy = False
+ j = row["bus2_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu_coeff = v_pu_coeff_j / v_pu_coeff_i
+ ratio_tr_pu = row["rated_u2"] / row["rated_u1"] / ratio_tr_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += ratio_tr_pu * m.V[i] * (line_y_pu * ratio_tr_pu * m.V[i] * pyo.cos(line_ksi) - line_y_pu * 1 * m.V[j] * pyo.cos(line_ksi - 0 + 0 - m.Phi[i] + m.Phi[j]) )
+ elif row["bus2_id"] == i and row["bus1_id"] in buses:
+ is_empy = False
+ j = row["bus1_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu_coeff = v_pu_coeff_i / v_pu_coeff_j
+ ratio_tr_pu = row["rated_u2"] / row["rated_u1"] / ratio_tr_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += 1 * m.V[i] * ( - line_y_pu * ratio_tr_pu * m.V[j] * pyo.cos(line_ksi + 0 - 0 + m.Phi[j] - m.Phi[i]) + line_y_pu * 1 * m.V[i] * pyo.cos(line_ksi) )
+ for id_gen, row in n.get_generators().iterrows():
+ if row["bus_id"] == i:
+ rhs += row["target_q"] / p_pu # TO DO: to be replaced with pu getters
+ for id_ld, row in n.get_loads().iterrows():
+ if row["bus_id"] == i:
+ rhs -= row["q0"] / p_pu # TO DO: to be replaced with pu getters
+ if is_empty:
+ return pyo.Constraint.Skip
+ else:
+ return lhs == rhs
+ return reactive_power_balancePQ_expr_m
+
+# Reactive power balance for PV buses
+def reactive_power_balancePV_expr(n, buses, p_pu):
+ def reactive_power_balancePV_expr_m(m,i):
+ v_pu_coeff_i = n.get_voltage_levels().at[n.get_buses().at[i, "voltage_level_id"], "nominal_v"]
+ lhs = 0
+ rhs = 0
+ is_empty = True
+ for id_line, row in n.get_lines().iterrows():
+ if row["bus1_id"] == i and row["bus2_id"] in buses:
+ is_empy = False
+ j = row["bus2_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu = 1
+ line_b1_pu = row[ "b1"] / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += ratio_tr_pu * m.V[i] * (-line_b1_pu * ratio_tr_pu * m.V[i] + line_y_pu * ratio_tr_pu * m.V[i] * pyo.cos(line_ksi) - line_y_pu * 1 * m.V[j] * pyo.cos(line_ksi - 0 + 0 - m.Phi[i] + m.Phi[j]) )
+ elif row["bus2_id"] == i and row["bus1_id"] in buses:
+ is_empy = False
+ j = row["bus1_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu = 1
+ line_b2_pu = row["b2"] / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += 1 * m.V[i] * ( - line_b2_pu * 1 * m.V[i] - line_y_pu * ratio_tr_pu * m.V[j] * pyo.cos(line_ksi + 0 - 0 + m.Phi[j] - m.Phi[i]) + line_y_pu * 1 * m.V[i] * pyo.cos(line_ksi) )
+ for id_tr, row in n.get_2_windings_transformers().iterrows():
+ if row["bus1_id"] == i and row["bus2_id"] in buses:
+ is_empy = False
+ j = row["bus2_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu_coeff = v_pu_coeff_j / v_pu_coeff_i
+ ratio_tr_pu = row["rated_u2"] / row["rated_u1"] / ratio_tr_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += ratio_tr_pu * m.V[i] * (line_y_pu * ratio_tr_pu * m.V[i] * pyo.cos(line_ksi) - line_y_pu * 1 * m.V[j] * pyo.cos(line_ksi - 0 + 0 - m.Phi[i] + m.Phi[j]) )
+ elif row["bus2_id"] == i and row["bus1_id"] in buses:
+ is_empy = False
+ j = row["bus1_id"]
+ v_pu_coeff_j = n.get_voltage_levels().at[n.get_buses().at[j, "voltage_level_id"], "nominal_v"]
+ sus_pu_coeff = p_pu / v_pu_coeff_i / v_pu_coeff_j #POWER/U/U
+ ratio_tr_pu_coeff = v_pu_coeff_i / v_pu_coeff_j
+ ratio_tr_pu = row["rated_u2"] / row["rated_u1"] / ratio_tr_pu_coeff # TO DO: to be replaced with pu getters
+ line_r = row["r"]
+ line_x = row["x"]
+ line_y_pu = 1 / np.sqrt(line_r * line_r + line_x * line_x) / sus_pu_coeff # TO DO: to be replaced with pu getters
+ line_ksi = np.arctan2(line_r,line_x)
+ lhs += 1 * m.V[i] * ( - line_y_pu * ratio_tr_pu * m.V[j] * pyo.cos(line_ksi + 0 - 0 + m.Phi[j] - m.Phi[i]) + line_y_pu * 1 * m.V[i] * pyo.cos(line_ksi) )
+ rhs += m.Q[i] / p_pu
+ if is_empty:
+ return pyo.Constraint.Skip
+ else:
+ return lhs == rhs
+ return reactive_power_balancePV_expr_m
+
+# Reactive power bounds
+def reactive_power_bounds(n):
+ def reactive_power_bounds_m(m, i):
+ lb = 0
+ ub = 0
+ for id_gen, row in n.get_generators().iterrows():
+ if row["bus_id"] == i:
+ target_p = row["target_p"]
+ dist = np.nan
+ for id_curve, row in n.get_reactive_capability_curve_points().iterrows():
+ if id_curve[0] == id_gen:
+ if np.isnan(dist):
+ dist = abs(target_p-row["p"])
+ minq = row["min_q"]
+ maxq = row["max_q"]
+ else:
+ if abs(target_p-row["p"]) < dist:
+ dist = abs(target_p-row["p"])
+ minq = row["min_q"]
+ maxq = row["max_q"]
+ lb += minq
+ ub += maxq
+ for id_ld, row in n.get_loads().iterrows():
+ if row["bus_id"] == i:
+ lb -= row["q0"]
+ ub -= row["q0"]
+ return (lb, ub)
+ return reactive_power_bounds_m
+
+# Reactive power initialization
+def reactive_init(n):
+ def reactive_init_m(m,i):
+ q_init = 0
+ if q_init < m.Q[i].lb:
+ q_init = m.Q[i].lb
+ if q_init > m.Q[i].ub:
+ q_init = m.Q[i].ub
+ return q_init
+ return reactive_init_m
+
+# Voltage bounds
+def voltage_bounds(n):
+ def voltage_bounds_m(m, i):
+ voltage_level_id = n.get_buses().at[i, "voltage_level_id"]
+ v_pu_coeff = n.get_voltage_levels().at[voltage_level_id, "nominal_v"]
+ v_min_pu = n.get_voltage_levels().at[voltage_level_id, "low_voltage_limit"] / v_pu_coeff # TO DO: to be replaced with pu getters
+ v_max_pu = n.get_voltage_levels().at[voltage_level_id, "high_voltage_limit"] / v_pu_coeff # TO DO: to be replaced with pu getters
+ return (v_min_pu, v_max_pu)
+ return voltage_bounds_m
+
+# Voltage initialization
+def voltage_init(n):
+ def voltage_init_m(m,i):
+ voltage_level_id = n.get_buses().at[i, "voltage_level_id"]
+ v_init = n.get_buses().at[i,"v_mag"]
+ if np.isnan(v_init):
+ v_init_pu = 1
+ else:
+ v_pu_coeff = n.get_voltage_levels().at[voltage_level_id, "nominal_v"]
+ v_init_pu = n.get_buses().at[i,"v_mag"] / v_pu_coeff # TO DO: to be replaced with pu getters
+ if v_init_pu < m.V[i].lb:
+ v_init_pu = m.V[i].lb
+ if v_init_pu > m.V[i].ub:
+ v_init_pu = m.V[i].ub
+ return v_init_pu
+ return voltage_init_m
\ No newline at end of file
diff --git a/simulator/network-reduction/pom.xml b/simulator/network-reduction/pom.xml
new file mode 100644
index 00000000..c80d498f
--- /dev/null
+++ b/simulator/network-reduction/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+ 4.0.0
+
+
+ com.powsybl
+ powsybl-incubator-simulator
+ 1.0.0-SNAPSHOT
+
+
+ powsybl-incubator-simulator-network-reduction
+ Network reduction base on Ward injection equivalent
+
+
+
+ com.powsybl
+ powsybl-incubator-simulator-util
+ ${project.version}
+
+
+
+ com.powsybl
+ powsybl-incubator-simulator-util
+ ${project.version}
+ test-jar
+ test
+
+
+ com.powsybl
+ powsybl-config-test
+ test
+
+
+ com.powsybl
+ powsybl-ieee-cdf-converter
+ test
+
+
+ com.powsybl
+ powsybl-iidm-impl
+ test
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
diff --git a/simulator/network-reduction/src/main/java/com/powsybl/incubator/simulator/networkreduction/ReductionEngine.java b/simulator/network-reduction/src/main/java/com/powsybl/incubator/simulator/networkreduction/ReductionEngine.java
new file mode 100644
index 00000000..a9efa003
--- /dev/null
+++ b/simulator/network-reduction/src/main/java/com/powsybl/incubator/simulator/networkreduction/ReductionEngine.java
@@ -0,0 +1,681 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.networkreduction;
+
+import com.powsybl.incubator.simulator.util.AdmittanceEquationSystem;
+import com.powsybl.incubator.simulator.util.AdmittanceMatrix;
+import com.powsybl.incubator.simulator.util.EquationType;
+import com.powsybl.commons.reporter.Reporter;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.VariableType;
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.openloadflow.OpenLoadFlowParameters;
+import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowParameters;
+import com.powsybl.openloadflow.equations.*;
+import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
+import com.powsybl.openloadflow.network.*;
+import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
+import com.powsybl.openloadflow.network.util.VoltageInitializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ReductionEngine {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ReductionEngine.class);
+
+ private final Network network;
+
+ private final List lfNetworks;
+
+ private final ReductionParameters parameters;
+
+ public List getLfNetworks() {
+ return lfNetworks;
+ }
+
+ private ReductionHypotheses reductionHypo;
+
+ public ReductionHypotheses getReductionHypo() {
+ return reductionHypo;
+ }
+
+ private ReductionResults results;
+
+ public ReductionResults getReductionResults() {
+ return results;
+ }
+
+ public enum ReductionType {
+ WARD_INJ, // all external nodal injections that does not come from branches are considered as current injectors (including shunts elements)
+ WARD_SHUNT, // all external nodal injections that does not come from branches are considered as current injectors (but not shunt elements)
+ WARD_ADMIT; // all external nodal injections are transformed into passive shunt elements included in the Y matrix (then [Ie] should be [0])
+ }
+
+ public class ReductionResults {
+
+ private Matrix minusYeq;
+
+ private Map busNumToRealIeq;
+
+ private Map busNumToImagIeq;
+
+ private Map yeqRowNumToBusNum; //gives the bus number from the row number of the Y submatrix in input
+
+ private Map yeqRowNumToBusType; //gives the type of equation from the row number of the Y submatrix in input
+
+ private Map yeqColNumToBusNum; //gives the bus number from the row number of the Y submatrix in input
+
+ private Map yeqColNumToBusType; //gives the type of variable from the row number of the Y submatrix in input
+
+ ReductionResults(Matrix minusYeq) {
+ this.minusYeq = minusYeq;
+ busNumToRealIeq = new HashMap<>();
+ busNumToImagIeq = new HashMap<>();
+ yeqRowNumToBusNum = new HashMap<>();
+ yeqRowNumToBusType = new HashMap<>();
+ yeqColNumToBusNum = new HashMap<>();
+ yeqColNumToBusType = new HashMap<>();
+ }
+
+ public Matrix getMinusYeq() {
+ return minusYeq;
+ }
+
+ public Map getBusNumToRealIeq() {
+ return busNumToRealIeq;
+ }
+
+ public Map getBusNumToImagIeq() {
+ return busNumToImagIeq;
+ }
+
+ public Map getYeqRowNumToBusNum() {
+ return yeqRowNumToBusNum;
+ }
+
+ public Map getYeqRowNumToBusType() {
+ return yeqRowNumToBusType;
+ }
+
+ public Map getYeqColNumToBusNum() {
+ return yeqColNumToBusNum;
+ }
+
+ public Map getYeqColNumToBusType() {
+ return yeqColNumToBusType;
+ }
+
+ void printReductionResults() {
+ for (Map.Entry i : getBusNumToRealIeq().entrySet()) {
+ int nb = i.getKey();
+ System.out.println("Bus = " + nb + " has Ieq real = " + i.getValue());
+ }
+ for (Map.Entry i : getBusNumToImagIeq().entrySet()) {
+ int nb = i.getKey();
+ System.out.println("Bus = " + nb + " has Ieq imag = " + i.getValue());
+ }
+
+ for (int i = 0; i < minusYeq.getRowCount(); i++) {
+ System.out.println("RowYeq[" + i + "] = bus Num " + getYeqRowNumToBusNum().get(i) + " bus Eq type " + getYeqRowNumToBusType().get(i));
+ }
+ for (int i = 0; i < minusYeq.getRowCount(); i++) {
+ System.out.println("ColYeq[" + i + "] = bus Num " + getYeqColNumToBusNum().get(i) + " bus Var type " + getYeqColNumToBusType().get(i));
+ }
+
+ System.out.println("===> -Yeq =");
+ minusYeq.print(System.out);
+ }
+
+ }
+
+ public class ReductionHypotheses {
+
+ private List yijBlocks;
+
+ public List eqBranches;
+
+ public List eqShunts;
+
+ public List eqLoads;
+
+ private class YijBlock {
+
+ private int bus1;
+ private int bus2;
+ private double y1r2r;
+ private double y1r2i;
+ private double y1i2r;
+ private double y1i2i;
+ private double y2r1r;
+ private double y2r1i;
+ private double y2i1i;
+ private double y2i1r;
+
+ YijBlock(int busi, int busj) {
+
+ this.bus1 = busi;
+ this.bus2 = busj;
+ y1r2r = 0;
+ y1r2i = 0;
+ y1i2r = 0;
+ y1i2i = 0;
+ y2r1r = 0;
+ y2r1i = 0;
+ y2i1i = 0;
+ y2i1r = 0;
+
+ }
+ }
+
+ private YijBlock createYijBlock(int busi, int busj) {
+ YijBlock yb = new YijBlock(busi, busj);
+ return yb;
+ }
+
+ ReductionHypotheses() {
+ yijBlocks = new ArrayList();
+ eqBranches = new ArrayList();
+ eqShunts = new ArrayList();
+ eqLoads = new ArrayList();
+ }
+
+ private YijBlock getYijBlock(int i, int j) {
+
+ if (yijBlocks.isEmpty()) {
+ return null;
+ }
+/*
+ ListIterator itYb = yijBlocks.listIterator();
+ {
+ yb0 = itYb.next();
+ }
+ while (itYb.hasNext() && ((itYb.next().busi == i && itYb.next().busj == j) || (itYb.next().busi == j && itYb.next().busj == i) ))
+*/
+ YijBlock yb0 = null;
+ for (YijBlock yb : yijBlocks) {
+ if ((yb.bus1 == i && yb.bus2 == j) || (yb.bus1 == j && yb.bus2 == i)) {
+ yb0 = yb;
+ break;
+ }
+ }
+
+ return yb0;
+ }
+
+ public class EquivalentBranch {
+
+ public double rEq;
+ public double xEq;
+ public double alphaEq;
+ public int bus1Eq;
+ public int bus2Eq;
+
+ EquivalentBranch(int busi, int busj, double r, double x, double alpha) {
+ this.bus1Eq = busi;
+ this.bus2Eq = busj;
+ this.rEq = r;
+ this.xEq = x;
+ this.alphaEq = alpha;
+ }
+ }
+
+ private EquivalentBranch createEquivalentBranch(int busi, int busj, double r, double x, double alpha) {
+ EquivalentBranch eqBr = new EquivalentBranch(busi, busj, r, x, alpha);
+ return eqBr;
+ }
+
+ public class EquivalentShunt {
+ public double gEq;
+ public double bEq;
+ public int busEq;
+
+ EquivalentShunt(int bus, double g, double b) {
+ this.busEq = bus;
+ this.gEq = g;
+ this.bEq = b;
+ }
+ }
+
+ private EquivalentShunt createEquivalentShunt(int bus, double g, double b) {
+ EquivalentShunt eqSh = new EquivalentShunt(bus, g, b);
+ return eqSh;
+ }
+
+ public class EquivalentLoad {
+ public double pEq;
+ public double qEq;
+ public int busEq;
+
+ EquivalentLoad(int bus, double p, double q) {
+ this.busEq = bus;
+ this.pEq = p;
+ this.qEq = q;
+ }
+ }
+
+ private EquivalentLoad createEquivalentLoad(int bus, double p, double q) {
+ EquivalentLoad eqLoad = new EquivalentLoad(bus, p, q);
+ return eqLoad;
+ }
+ }
+
+ private Set extBusses;
+
+ private Set borderBusses;
+
+ public ReductionEngine(Network network, ReductionParameters parameters) {
+ this.network = Objects.requireNonNull(network);
+ this.lfNetworks = LfNetwork.load(network, new LfNetworkLoaderImpl(), new LfNetworkParameters(new FirstSlackBusSelector()));
+ this.parameters = Objects.requireNonNull(parameters);
+ extBusses = new HashSet<>();
+ borderBusses = new HashSet<>();
+ }
+
+ public void run() {
+ //TODO: put type reduction in parameter
+ runWard(parameters.getReductionType());
+ }
+
+ public void runWard(ReductionType reductionType) {
+ LfNetwork lfNetwork = lfNetworks.get(0);
+
+ // List and tag external + boarder + internal nodes from external voltagelevels list given in input
+ defineZones(lfNetwork);
+
+ VoltageInitializer voltageInitializer = parameters.getVoltageInitializer();
+ AdmittanceEquationSystem.AdmittanceVoltageProfileType admittanceVoltageProfileType = AdmittanceEquationSystem.AdmittanceVoltageProfileType.CALCULATED;
+
+ AdmittanceEquationSystem.AdmittanceType admittanceType = AdmittanceEquationSystem.AdmittanceType.ADM_INJ;
+ if (reductionType == ReductionType.WARD_SHUNT) {
+ admittanceType = AdmittanceEquationSystem.AdmittanceType.ADM_SHUNT;
+ } else if (reductionType == ReductionType.WARD_ADMIT) {
+ admittanceType = AdmittanceEquationSystem.AdmittanceType.ADM_ADMIT;
+ }
+
+ OpenLoadFlowParameters loadflowParametersExt = OpenLoadFlowParameters.get(parameters.getLoadFlowParameters());
+ AcLoadFlowParameters acLoadFlowParameters = OpenLoadFlowParameters.createAcParameters(network, parameters.getLoadFlowParameters(), loadflowParametersExt, parameters.getMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), Reporter.NO_OP);
+
+ EquationSystem equationSystem = AdmittanceEquationSystem.create(lfNetwork, new VariableSet<>(), admittanceType, admittanceVoltageProfileType, acLoadFlowParameters);
+
+ // Reduction problem:
+ // The Grid is decomposed in 3 zones: internal (i), border (b), external (e) which is to be reduced
+ // Matrix decomposition gives:
+ // [[Yii] [Yib] [ 0 ]] [Vi] [Ii]
+ // [Y]*[V] = [I] <=> [[Ybi] [Ybb] [Ybe]] * [Vb] = [Ib]
+ // [[ 0 ] [Yeb] [Yee]] [Ve] [Ie]
+ //
+ // Use Gaussian elimination to remove external part (e):
+ // [[Yii] [Yib ]] [Ii ]
+ // [[Ybi] [Ybb']] = [Ib']
+ // with
+ // Ybb' = Ybb + Yeq where Yeq = -Ybe * inv(Yee) * Yeb
+ // Ib' = Ib + Ieq where Ieq = -Ybe * inv(Yee) * Ie
+ // Resolving the reduction problem is equivalent to find Ieq and Yeq
+
+ AdmittanceMatrix yeb = new AdmittanceMatrix(equationSystem, parameters.getMatrixFactory(), extBusses, borderBusses, lfNetwork);
+ AdmittanceMatrix yee = new AdmittanceMatrix(equationSystem, parameters.getMatrixFactory(), extBusses, extBusses, lfNetwork);
+ AdmittanceMatrix ybe = new AdmittanceMatrix(equationSystem, parameters.getMatrixFactory(), borderBusses, extBusses, lfNetwork);
+ AdmittanceMatrix ybb = new AdmittanceMatrix(equationSystem, parameters.getMatrixFactory(), borderBusses, borderBusses, lfNetwork);
+
+ // Step 1: Get [Ie]:
+ // [Ie] = [Yeb]*[Vb] + [Yee]*[Ve] or t[Ie] = t[Vb]*t[Yeb] + t[Ve]*t[Yee]
+ Matrix tmYeb = yeb.getMatrix(); //tmYeb is the transposed of [Yeb]
+ Matrix tmVb = yeb.getVoltageVector(lfNetwork, voltageInitializer); //tmVb is the transposed of the column vector [Vb]
+
+ Matrix tmYee = yee.getMatrix(); //tmYee is the transposed of [Yee]
+ Matrix tmVe = yee.getVoltageVector(lfNetwork, voltageInitializer); //tmVe is the transposed of the column vector [Ve]
+
+ Matrix tmYebVb = tmVb.times(tmYeb);
+ Matrix tmYeeVe = tmVe.times(tmYee);
+
+ Matrix tmIe = addRowVector(tmYebVb, tmYeeVe);
+
+ //Step 2: Solve for [W] the following equation: [Yee]*[W] = [Yeb] or t[W]*t[Yee] = t[Yeb]
+ DenseMatrix dTmYeb = tmYeb.toDense();
+
+ DenseMatrix dYeb = yeb.transpose();
+
+ yee.solveTransposed(dYeb);
+
+ DenseMatrix tmW = dYeb.transpose();
+
+ //Step 3: Compute -[Yeq] = [Ybe]*[W] or -t[Yeq] = t[W]*t[Ybe]
+ Matrix tmYbe = ybe.getMatrix(); //tmYbe is the transposed of [Ybe]
+ Matrix tmMinusYeq = tmW.times(tmYbe);
+
+ //Step 4: Solve for [X] the following equation [Yee]*[X] = [Ie] or t[X]*t[Yee] = t[Ie]
+ double[] x = rowVectorToDouble(tmIe);
+ yee.solveTransposed(x);
+
+ //Step 5: Compute -[Ieq] = [Ybe]*[X] or -t[Ieq] = t[X]*t[Ybe]
+ Matrix mX = Matrix.createFromRow(x, parameters.getMatrixFactory());
+ Matrix tmMinusIeq = mX.times(tmYbe);
+
+ // Reintegration of the Matrix results into the admittance system:
+ // [Ieq] and [Yeq] are of the dimension of [Ib] and [Ybb] respectively, we use Ybb admittance system as the structure for the reintegration of the results
+ results = new ReductionResults(tmMinusYeq);
+ processResults(ybb, rowVectorToDouble(tmMinusIeq), results);
+
+ results.printReductionResults();
+
+ generateReductionHypotheses();
+ }
+
+ public void processResults(AdmittanceMatrix y, double[] minusIeq, ReductionEngine.ReductionResults rRes) {
+
+ if (!y.getAdmSys().isSubAdmittance) {
+ throw new IllegalArgumentException("Result reintegration of a reduction problem are only relevant for a subsystem defined by the border area");
+ }
+
+ int yRowCount = y.getAdmSys().eqToRowNum.size(); //number of rows of Y (and number of columns of the "matrix" which is the transposed of Y)
+ int yColumnCount = y.getAdmSys().varToColNum.size(); //number of columns of Y (and number of rows of the "matrix" which is the transposed of Y)
+
+ if (yRowCount != minusIeq.length) {
+ throw new IllegalArgumentException("Ieq must be of the same dimension than the number of rows of the Y admittance matrix");
+ }
+ for (var eq : y.getEquationSystem().getIndex().getSortedEquationsToSolve()) {
+ int numBus = eq.getElementNum();
+ if (y.getAdmSys().eqToRowNum.containsKey(eq)) {
+ int row = y.getAdmSys().eqToRowNum.get(eq);
+ rRes.getYeqRowNumToBusNum().put(row, numBus);
+ if (eq.getType() == EquationType.BUS_YR) {
+ rRes.getBusNumToRealIeq().put(numBus, -minusIeq[row]);
+ rRes.getYeqRowNumToBusType().put(row, EquationType.BUS_YR);
+ } else if (eq.getType() == EquationType.BUS_YI) {
+ rRes.getBusNumToImagIeq().put(numBus, -minusIeq[row]);
+ rRes.getYeqRowNumToBusType().put(row, EquationType.BUS_YI);
+ }
+ }
+ }
+
+ if (yRowCount != yColumnCount) {
+ throw new IllegalArgumentException("Reduction algorithm must provide a square Yeq Matrix");
+ }
+ for (Variable v : y.getEquationSystem().getIndex().getSortedVariablesToFind()) {
+ if (y.getAdmSys().varToColNum.containsKey(v)) {
+ int col = y.getAdmSys().varToColNum.get(v);
+ rRes.getYeqColNumToBusNum().put(col, v.getElementNum());
+ if (v.getType() == VariableType.BUS_VR) {
+ rRes.getYeqColNumToBusType().put(col, VariableType.BUS_VR);
+ } else if (v.getType() == VariableType.BUS_VI) {
+ rRes.getYeqColNumToBusType().put(col, VariableType.BUS_VI);
+ }
+ }
+ }
+ }
+
+ private Matrix addRowVector(Matrix m1, Matrix m2) {
+ DenseMatrix m1d = m1.toDense();
+ DenseMatrix m2d = m2.toDense();
+ for (int j = 0; j < m1d.getColumnCount(); j++) {
+ m1d.set(0, j, m1d.get(0, j) + m2d.get(0, j));
+ }
+ return m1d;
+ }
+
+ public double[] rowVectorToDouble(Matrix m1) {
+ DenseMatrix m1d = m1.toDense();
+ double[] v = new double[m1d.getColumnCount()];
+ for (int j = 0; j < m1d.getColumnCount(); j++) {
+ v[j] = m1d.get(0, j);
+ }
+ return v;
+ }
+
+ private void defineZones(LfNetwork network) {
+ for (LfBranch br : network.getBranches()) {
+ if (br.getBus1() != null && br.getBus2() == null) {
+ if (parameters.getExternalVoltageLevels().contains(br.getBus1().getVoltageLevelId())) {
+ extBusses.add(br.getBus1());
+ }
+ } else if (br.getBus2() != null && br.getBus1() == null) {
+ if (parameters.getExternalVoltageLevels().contains(br.getBus2().getVoltageLevelId())) {
+ extBusses.add(br.getBus2());
+ }
+ } else if (br.getBus2() != null && br.getBus1() != null) {
+ LfBus b1 = br.getBus1();
+ LfBus b2 = br.getBus2();
+ boolean isB1Ext = parameters.getExternalVoltageLevels().contains(b1.getVoltageLevelId());
+ boolean isB2Ext = parameters.getExternalVoltageLevels().contains(b2.getVoltageLevelId());
+ if (isB1Ext && isB2Ext) {
+ extBusses.add(b1);
+ extBusses.add(b2);
+ } else if (isB1Ext) {
+ extBusses.add(b1);
+ borderBusses.add(b2);
+ } else if (isB2Ext) {
+ extBusses.add(b2);
+ borderBusses.add(b1);
+ }
+ }
+ }
+
+ //check built zones
+ for (LfBus b : extBusses) {
+ System.out.println("Bus = " + b.getId() + " is ext ");
+ }
+
+ for (LfBus b : borderBusses) {
+ System.out.println("Bus = " + b.getId() + " is border ");
+ }
+
+ }
+
+ // Example to compute full sytem nodal current injectors I = Y*V
+ /*public void computeCurrentInjections(AdmittanceEquationSystem.AdmittanceType admittanceType) {
+ //test with full sytem compute I = Y*V
+
+ LfNetwork lfNetwork = lfNetworks.get(0);
+
+ OpenLoadFlowParameters loadflowParametersExt = OpenLoadFlowParameters.get(parameters.getLoadFlowParameters());
+ AcLoadFlowParameters acLoadFlowParameters = OpenLoadFlowParameters.createAcParameters(network, parameters.getLoadFlowParameters(), loadflowParametersExt, parameters.getMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), Reporter.NO_OP);
+ AdmittanceEquationSystem.AdmittanceVoltageProfileType admittanceVoltageProfileType = AdmittanceEquationSystem.AdmittanceVoltageProfileType.CALCULATED;
+
+ EquationSystem equationSystem = AdmittanceEquationSystem.create(lfNetwork, parameters.getMatrixFactory(), new VariableSet<>(), admittanceType, admittanceVoltageProfileType, acLoadFlowParameters);
+
+ VoltageInitializer voltageInitializer = parameters.getVoltageInitializer();
+
+ AdmittanceMatrix a = new AdmittanceMatrix(equationSystem, parameters.getMatrixFactory(), lfNetwork);
+ Matrix a1 = a.getMatrix();
+ Matrix mV = a.getVoltageVector(lfNetwork, voltageInitializer);
+ System.out.println("v = ");
+ mV.print(System.out);
+
+ Matrix mI = mV.times(a1);
+ System.out.println("i = ");
+ mI.print(System.out);
+ }*/
+
+ public void generateReductionHypotheses() {
+
+ LfNetwork network = lfNetworks.get(0);
+
+ reductionHypo = new ReductionHypotheses();
+ DenseMatrix m = results.minusYeq.toDense();
+
+ //step 1: extract values of [Yeq] binding upper and under extra-diagonal terms together if they have the same nodes
+ //
+ // [I1r] [ y1r1r y1r1i y1r2r y1r2i ] [ g1+g12 -b1-b12 -g12 b12 ] [V1r]
+ // [I1i] [ y1i1r y1i1i y1i2r y1i2i ] [ b1+b12 g1+g12 -b12 -g12 ] [V1i]
+ // [I2r] = [ y2r1r y2r1i y2r2r y2r2i ] * [V] = [ -g21 b21 g2+g21 -b2-b21 ] * [V2r]
+ // [I2i] [ y2i1r y2i1i y2i2r y2i2i ] [ -b21 -g21 b2+b21 g2+g21 ] [V2i]
+ //
+ //
+ HashMap busNumtToDiagonalBlock = new HashMap<>(); //use for a direct access to diagonal blocks from bus num
+ for (int mi = 0; mi < results.minusYeq.getRowCount(); mi++) {
+
+ int busi = results.yeqRowNumToBusNum.get(mi);
+ EquationType typei = results.yeqRowNumToBusType.get(mi);
+
+ for (int mj = 0; mj < results.minusYeq.getRowCount(); mj++) {
+ int busj = results.yeqColNumToBusNum.get(mj);
+
+ if (Math.abs(m.get(mj, mi)) > 0.00001) { //no block created or modified if matrix term is zero
+ // mi and mj inverted because "m" is the transposed of Y standard admittance matrix
+
+ VariableType typej = results.yeqColNumToBusType.get(mj);
+
+ //Create or update Yij block
+ ReductionHypotheses.YijBlock yb = reductionHypo.getYijBlock(busi, busj);
+ if (yb == null) {
+ yb = reductionHypo.createYijBlock(busi, busj);
+ reductionHypo.yijBlocks.add(yb);
+ if (busi == busj) {
+ busNumtToDiagonalBlock.put(busi, yb);
+ }
+ }
+ if (busi == yb.bus1) { //in the case where busi = busj only y1r2r,y1r2i,y1i2i,y1i2r are useful
+ if (typei == EquationType.BUS_YR && typej == VariableType.BUS_VR) {
+ yb.y1r2r = -m.get(mj, mi); //mi and mj inverted as "m" is the transposed of Y
+ } else if (typei == EquationType.BUS_YR && typej == VariableType.BUS_VI) {
+ yb.y1r2i = -m.get(mj, mi);
+ } else if (typei == EquationType.BUS_YI && typej == VariableType.BUS_VI) {
+ yb.y1i2i = -m.get(mj, mi);
+ } else if (typei == EquationType.BUS_YI && typej == VariableType.BUS_VR) {
+ yb.y1i2r = -m.get(mj, mi);
+ }
+ } else if (busi == yb.bus2) {
+ if (typei == EquationType.BUS_YR && typej == VariableType.BUS_VR) {
+ yb.y2r1r = -m.get(mj, mi);
+ } else if (typei == EquationType.BUS_YR && typej == VariableType.BUS_VI) {
+ yb.y2r1i = -m.get(mj, mi);
+ } else if (typei == EquationType.BUS_YI && typej == VariableType.BUS_VI) {
+ yb.y2i1i = -m.get(mj, mi);
+ } else if (typei == EquationType.BUS_YI && typej == VariableType.BUS_VR) {
+ yb.y2i1r = -m.get(mj, mi);
+ }
+
+ }
+ }
+ }
+ }
+
+ //step 2: check the consistency of the blocks since some terms must be equal to deduce an equivalent branch
+ //step 3: deduce g12, b12, g21, b21 and then g1, b1, g2, b2
+ for (ReductionHypotheses.YijBlock yb : reductionHypo.yijBlocks) {
+ //step 2
+ double epsilon = 0.00001;
+ if (Math.abs(yb.y1r2r - yb.y1i2i) > epsilon) {
+ throw new IllegalArgumentException("Admittance block values y1r2r and y1i2i of nodes num {" + yb.bus1 + ";" + yb.bus2 + "} have inconsitant values y1r2r= " + yb.y1r2r + " y1i2i=" + yb.y1i2i);
+ }
+ if (Math.abs(yb.y1i2r + yb.y1r2i) > epsilon) {
+ throw new IllegalArgumentException("Admittance block values y1i2r and y1r2i of nodes num {" + yb.bus1 + ";" + yb.bus2 + "} have inconsitant values");
+ }
+ if (Math.abs(yb.y2r1r - yb.y2i1i) > epsilon) {
+ throw new IllegalArgumentException("Admittance block values y2r1r and y2i1i of nodes num {" + yb.bus1 + ";" + yb.bus2 + "} have inconsitant values");
+ }
+ if (Math.abs(yb.y2i1r + yb.y2r1i) > epsilon) {
+ throw new IllegalArgumentException("Admittance block values y2i1r and y2r1i of nodes num {" + yb.bus1 + ";" + yb.bus2 + "} have inconsitant values");
+ }
+ }
+
+ for (ReductionHypotheses.YijBlock yb : reductionHypo.yijBlocks) {
+ //step 3
+ double g12 = 0;
+ double b12 = 0;
+ double g21 = 0;
+ double b21 = 0;
+
+ if (yb.bus1 != yb.bus2) {
+ g12 = -yb.y1r2r;
+ b12 = yb.y1r2i;
+ g21 = -yb.y2r1r;
+ b21 = yb.y2r1i;
+
+ //remove g12 from diagonal term y1r2r = g1 + sum(g1i) (for a diagonal block y1r2r is equivalent to y1r1r since bus1 = bus2)
+ busNumtToDiagonalBlock.get(yb.bus1).y1r2r = busNumtToDiagonalBlock.get(yb.bus1).y1r2r - g12;
+ //remove b12 from diagonal term y1i2r = b1 + sum(b1i)
+ busNumtToDiagonalBlock.get(yb.bus1).y1i2r = busNumtToDiagonalBlock.get(yb.bus1).y1i2r - b12;
+ //remove g21 from diagonal term y1r2r = g2 + sum(g2i)
+ busNumtToDiagonalBlock.get(yb.bus2).y1r2r = busNumtToDiagonalBlock.get(yb.bus2).y1r2r - g21;
+ //remove b21 from diagonal term y1i2r = b2 + sum(b2i)
+ busNumtToDiagonalBlock.get(yb.bus2).y1i2r = busNumtToDiagonalBlock.get(yb.bus2).y1i2r - b21;
+
+ //deduce branch characteristics from g12, b12, g21, b21
+ // we use the hypothesis that rho = 1 but in case nominal voltage values of voltage levels are not the same, we will have to create a transformer with rho = 1
+ double denom = g21 * g12 + b21 * b12;
+ double alpha = 0.;
+ if (denom > 0.0001) {
+ alpha = 0.5 * Math.atan((b21 * g12 - b12 * g21) / denom);
+ }
+
+ double r = (g12 * Math.cos(alpha) - b12 * Math.sin(alpha)) / (g12 * g12 + b12 * b12);
+ double x = -(b12 * Math.cos(alpha) + g12 * Math.sin(alpha)) / (g12 * g12 + b12 * b12);
+
+ ReductionHypotheses.EquivalentBranch eqBr = reductionHypo.createEquivalentBranch(yb.bus1, yb.bus2, r, x, alpha);
+ reductionHypo.eqBranches.add(eqBr);
+ System.out.println("Equivalent branch r=" + r + " x=" + x + " at busses = " + yb.bus1 + ";" + yb.bus2);
+ }
+ }
+
+ //remove g1 + g12 of branches linking E and B zones
+ for (LfBranch branch : network.getBranches()) {
+ LfBus bus1 = branch.getBus1();
+ LfBus bus2 = branch.getBus2();
+ PiModel piModel = branch.getPiModel();
+ if (extBusses.contains(bus1) && borderBusses.contains(bus2)) {
+ double b2 = 0.; // g2g21sum = r * zInvSquare + gPi2;
+ double g2 = 0.; // b2b21sum = -x * zInvSquare + bPi2;
+ g2 = piModel.getR() / (piModel.getZ() * piModel.getZ()) + piModel.getG2();
+ b2 = -piModel.getX() / (piModel.getZ() * piModel.getZ()) + piModel.getB2();
+
+ busNumtToDiagonalBlock.get(bus2.getNum()).y1r2r = busNumtToDiagonalBlock.get(bus2.getNum()).y1r2r + g2;
+ busNumtToDiagonalBlock.get(bus2.getNum()).y1i2r = busNumtToDiagonalBlock.get(bus2.getNum()).y1i2r + b2;
+
+ } else if (extBusses.contains(bus2) && borderBusses.contains(bus1)) {
+ double b1 = 0.; //g1g12sum = rho * rho * (gPi1 + r * zInvSquare);
+ double g1 = 0.; //b1b12sum = rho * rho * (bPi1 - x * zInvSquare);
+ g1 = piModel.getR1() * piModel.getR1() * (piModel.getG1() + piModel.getR() / (piModel.getZ() * piModel.getZ()));
+ b1 = piModel.getR1() * piModel.getR1() * (piModel.getB1() - piModel.getX() / (piModel.getZ() * piModel.getZ()));
+
+ busNumtToDiagonalBlock.get(bus1.getNum()).y1r2r = busNumtToDiagonalBlock.get(bus1.getNum()).y1r2r + g1;
+ busNumtToDiagonalBlock.get(bus1.getNum()).y1i2r = busNumtToDiagonalBlock.get(bus1.getNum()).y1i2r + b1;
+ }
+ }
+
+ //step4: generate hypotheses of creation of equivalent shunts for remaining g1, b1 and g2, b2
+ //check if we need to remove EB lines from g1 and b1???
+ for (Map.Entry diagBlock : busNumtToDiagonalBlock.entrySet()) {
+ int busNum = diagBlock.getKey();
+ ReductionHypotheses.YijBlock yb = diagBlock.getValue();
+ double g1 = 0;
+ double b1 = 0;
+ g1 = yb.y1r2r;
+ b1 = yb.y1i2r;
+ if (Math.abs(g1) > 0.000001 || Math.abs(b1) > 0.000001) {
+ ReductionHypotheses.EquivalentShunt eqSh = reductionHypo.createEquivalentShunt(busNum, g1, b1);
+ reductionHypo.eqShunts.add(eqSh);
+ System.out.println("Equivalent shunt g=" + g1 + " b=" + b1 + " at bus num=" + busNum);
+ }
+ }
+
+ //step5: generation of equivalent load injections from equivalent currents
+ for (Map.Entry ieq : results.busNumToRealIeq.entrySet()) {
+ int busNum = ieq.getKey();
+ double ir = ieq.getValue();
+ double ii = results.busNumToImagIeq.get(busNum);
+
+ double vr = parameters.getVoltageInitializer().getMagnitude(network.getBus(busNum)) * Math.cos(Math.toRadians(parameters.getVoltageInitializer().getAngle(network.getBus(busNum))));
+ double vi = parameters.getVoltageInitializer().getMagnitude(network.getBus(busNum)) * Math.sin(Math.toRadians(parameters.getVoltageInitializer().getAngle(network.getBus(busNum))));
+
+ double pEq = -(vr * ir + vi * ii);
+ double qEq = ii * vr - vi * ir;
+
+ if (Math.abs(pEq) > 0.00001 || Math.abs(qEq) > 0.00001) {
+ ReductionHypotheses.EquivalentLoad eqLoad = reductionHypo.createEquivalentLoad(busNum, pEq, qEq);
+ reductionHypo.eqLoads.add(eqLoad);
+ System.out.println("Equivalent load P=" + pEq + " Q=" + qEq + " at bus num=" + busNum);
+ }
+ }
+ }
+}
diff --git a/simulator/network-reduction/src/main/java/com/powsybl/incubator/simulator/networkreduction/ReductionParameters.java b/simulator/network-reduction/src/main/java/com/powsybl/incubator/simulator/networkreduction/ReductionParameters.java
new file mode 100644
index 00000000..c9bab1b9
--- /dev/null
+++ b/simulator/network-reduction/src/main/java/com/powsybl/incubator/simulator/networkreduction/ReductionParameters.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.networkreduction;
+
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer;
+import com.powsybl.openloadflow.network.util.VoltageInitializer;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ReductionParameters {
+
+ private final LoadFlowParameters loadFlowParameters;
+
+ private final MatrixFactory matrixFactory;
+
+ private VoltageInitializer voltageInitializer = new PreviousValueVoltageInitializer(); //TODO: check why previous does not work
+
+ private final List externalVoltageLevels;
+
+ private final ReductionEngine.ReductionType reductionType;
+
+ public ReductionParameters(LoadFlowParameters loadFlowParameters, MatrixFactory matrixFactory, List externalVoltageLevels, ReductionEngine.ReductionType reductionType) {
+ this.loadFlowParameters = Objects.requireNonNull(loadFlowParameters);
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ this.externalVoltageLevels = Objects.requireNonNull(externalVoltageLevels);
+ this.reductionType = Objects.requireNonNull(reductionType);
+ }
+
+ public LoadFlowParameters getLoadFlowParameters() {
+ return loadFlowParameters;
+ }
+
+ public MatrixFactory getMatrixFactory() {
+ return matrixFactory;
+ }
+
+ public VoltageInitializer getVoltageInitializer() {
+ return voltageInitializer;
+ }
+
+ public List getExternalVoltageLevels() {
+ return externalVoltageLevels;
+ }
+
+ public ReductionEngine.ReductionType getReductionType() {
+ return reductionType;
+ }
+}
diff --git a/simulator/network-reduction/src/test/java/com/powsybl/incubator/simulator/networkreduction/ReductionTest.java b/simulator/network-reduction/src/test/java/com/powsybl/incubator/simulator/networkreduction/ReductionTest.java
new file mode 100644
index 00000000..436be6fd
--- /dev/null
+++ b/simulator/network-reduction/src/test/java/com/powsybl/incubator/simulator/networkreduction/ReductionTest.java
@@ -0,0 +1,257 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.networkreduction;
+
+import com.powsybl.commons.reporter.Reporter;
+import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.loadflow.LoadFlowResult;
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.DenseMatrixFactory;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowParameters;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowParameters;
+import com.powsybl.openloadflow.equations.EquationSystem;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
+import com.powsybl.openloadflow.network.LfNetwork;
+import com.powsybl.openloadflow.network.util.VoltageInitializer;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+class ReductionTest {
+
+ private LoadFlowParameters loadFlowParameters;
+
+ private OpenLoadFlowParameters loadFlowParametersExt;
+
+ private MatrixFactory matrixFactory;
+
+ private LoadFlow.Runner loadFlowRunner;
+
+ @BeforeEach
+ void setUp() {
+ loadFlowParameters = new LoadFlowParameters();
+ loadFlowParametersExt = OpenLoadFlowParameters.get(loadFlowParameters)
+ .setAddRatioToLinesWithDifferentNominalVoltageAtBothEnds(false);
+ loadFlowParameters.addExtension(OpenLoadFlowParameters.class, loadFlowParametersExt);
+
+ matrixFactory = new DenseMatrixFactory();
+ loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+ }
+
+ /**
+ * Check behaviour of the load flow for simple manipulations on eurostag example 1 network.
+ * - line opening
+ * - load change
+ */
+ @Test
+ void computeCurrentInjectorTest() {
+ Network network = IeeeCdfNetworkFactory.create14();
+
+ List voltageLevels = new ArrayList<>();
+
+ ReductionParameters reductionParameters = new ReductionParameters(loadFlowParameters, matrixFactory, voltageLevels, ReductionEngine.ReductionType.WARD_INJ);
+
+ ReductionEngine re = new ReductionEngine(network, reductionParameters);
+ LfNetwork lfNetwork = re.getLfNetworks().get(0);
+
+ OpenLoadFlowParameters loadflowParametersExt = OpenLoadFlowParameters.get(loadFlowParameters);
+ AcLoadFlowParameters acLoadFlowParameters = OpenLoadFlowParameters.createAcParameters(network, loadFlowParameters, loadflowParametersExt, matrixFactory, new EvenShiloachGraphDecrementalConnectivityFactory<>(), Reporter.NO_OP);
+ AdmittanceEquationSystem.AdmittanceVoltageProfileType admittanceVoltageProfileType = AdmittanceEquationSystem.AdmittanceVoltageProfileType.CALCULATED;
+ //AdditionalDataInfo additionalDataInfo = new AdditionalDataInfo();
+ AdmittanceEquationSystem.AdmittancePeriodType admittancePeriodType = AdmittanceEquationSystem.AdmittancePeriodType.ADM_TRANSIENT;
+ EquationSystemFeeders feeders = new EquationSystemFeeders();
+ EquationSystem equationSystem = AdmittanceEquationSystem.create(lfNetwork, new VariableSet<>(), AdmittanceEquationSystem.AdmittanceType.ADM_INJ, admittanceVoltageProfileType, admittancePeriodType, false, feeders, acLoadFlowParameters);
+
+ VoltageInitializer voltageInitializer = reductionParameters.getVoltageInitializer();
+
+ AdmittanceMatrix a = new AdmittanceMatrix(equationSystem, reductionParameters.getMatrixFactory(), lfNetwork);
+ Matrix a1 = a.getMatrix();
+ Matrix mV = a.getVoltageVector(lfNetwork, voltageInitializer);
+ //System.out.println("===> v =");
+ //mV.print(System.out);
+
+ Matrix mI = mV.times(a1);
+ //System.out.println("===> i =");
+ //mI.print(System.out);
+
+ double[] x = re.rowVectorToDouble(mI);
+
+ assertEquals(2.1919, x[0], 0.01);
+ assertEquals(0.1581, x[1], 0.01);
+ assertEquals(0.1506, x[2], 0.01);
+ assertEquals(-0.2990, x[3], 0.01);
+ }
+
+ @Test
+ void computeCurrentInjectorWithLfResultsTest() {
+ Network network = IeeeCdfNetworkFactory.create14();
+
+ List voltageLevels = new ArrayList<>();
+
+ LoadFlowResult resultLf = loadFlowRunner.run(network, loadFlowParameters);
+
+ ReductionParameters reductionParameters = new ReductionParameters(loadFlowParameters, matrixFactory, voltageLevels, ReductionEngine.ReductionType.WARD_INJ);
+
+ ReductionEngine re = new ReductionEngine(network, reductionParameters);
+ LfNetwork lfNetwork = re.getLfNetworks().get(0);
+
+ OpenLoadFlowParameters loadflowParametersExt = OpenLoadFlowParameters.get(loadFlowParameters);
+ AcLoadFlowParameters acLoadFlowParameters = OpenLoadFlowParameters.createAcParameters(network, loadFlowParameters, loadflowParametersExt, matrixFactory, new EvenShiloachGraphDecrementalConnectivityFactory<>(), Reporter.NO_OP);
+ AdmittanceEquationSystem.AdmittanceVoltageProfileType admittanceVoltageProfileType = AdmittanceEquationSystem.AdmittanceVoltageProfileType.CALCULATED;
+ AdmittanceEquationSystem.AdmittancePeriodType admittancePeriodType = AdmittanceEquationSystem.AdmittancePeriodType.ADM_TRANSIENT;
+ //AdditionalDataInfo additionalDataInfo = new AdditionalDataInfo();
+ EquationSystemFeeders feeders = new EquationSystemFeeders();
+ EquationSystem equationSystem = AdmittanceEquationSystem.create(lfNetwork, new VariableSet<>(), AdmittanceEquationSystem.AdmittanceType.ADM_INJ, admittanceVoltageProfileType, admittancePeriodType, false, feeders, acLoadFlowParameters);
+
+ VoltageInitializer voltageInitializer = reductionParameters.getVoltageInitializer();
+
+ AdmittanceMatrix a = new AdmittanceMatrix(equationSystem, reductionParameters.getMatrixFactory(), lfNetwork);
+ Matrix a1 = a.getMatrix();
+ Matrix mV = a.getVoltageVector(lfNetwork, voltageInitializer);
+ //System.out.println("===> v =");
+ //mV.print(System.out);
+
+ Matrix mI = mV.times(a1);
+ //System.out.println("===> i =");
+ //mI.print(System.out);
+
+ double[] x = re.rowVectorToDouble(mI);
+
+ assertEquals(2.192, x[0], 0.001);
+ assertEquals(0.156, x[1], 0.001);
+ assertEquals(0.148, x[2], 0.001);
+ assertEquals(-0.309, x[3], 0.001);
+ }
+
+ @Test
+ void ieee14ReductionTest() {
+
+ Network network = IeeeCdfNetworkFactory.create14();
+
+ List voltageLevels = new ArrayList<>();
+ voltageLevels.add("VL12");
+ voltageLevels.add("VL13");
+
+ LoadFlowResult resultLf = loadFlowRunner.run(network, loadFlowParameters);
+
+ ReductionParameters reductionParameters = new ReductionParameters(loadFlowParameters, matrixFactory, voltageLevels, ReductionEngine.ReductionType.WARD_INJ);
+
+ ReductionEngine re = new ReductionEngine(network, reductionParameters);
+
+ re.run();
+
+ ReductionEngine.ReductionResults results = re.getReductionResults();
+
+ DenseMatrix m = results.getMinusYeq().toDense();
+
+ assertEquals(2, results.getBusNumToRealIeq().size(), 0);
+ assertEquals(3.730432312, m.get(0, 0), 0.000001);
+ /*assertEquals(-0.9770922266610, m.get(1, 0), 0.000001);
+ assertEquals(-4.0518208119503, m.get(2, 0), 0.000001);
+ assertEquals(-1.1284861339383, m.get(3, 0), 0.000001);
+ assertEquals(0.9770922266610, m.get(0, 1), 0.000001);
+ assertEquals(-10.640432247821, m.get(1, 1), 0.000001);
+ assertEquals(1.1284861339383, m.get(2, 1), 0.000001);
+ assertEquals(-4.051820811950, m.get(3, 1), 0.000001);
+ assertEquals(-3.2261022158310, m.get(0, 2), 0.000001);
+ assertEquals(-0.3281562136182, m.get(1, 2), 0.000001);
+ assertEquals(-1.3282719530734, m.get(2, 2), 0.000001);
+ assertEquals(-0.36576402166078, m.get(3, 2), 0.000001);
+ assertEquals(0.3281562136182, m.get(0, 3), 0.000001);
+ assertEquals(-3.2261022158310, m.get(1, 3), 0.000001);
+ assertEquals(0.3657640216607, m.get(2, 3), 0.000001);
+ assertEquals(-1.328271953073, m.get(3, 3), 0.000001);*/
+
+ ReductionEngine.ReductionHypotheses hypo = re.getReductionHypo();
+ assertEquals(0.159817620898, hypo.eqLoads.get(0).pEq, 0.00001);
+ /*assertEquals(0.062286236316, hypo.eqLoads.get(0).qEq, 0.00001);
+ assertEquals(13.86653446365, hypo.eqShunts.get(0).gEq, 0.0001);
+ assertEquals(1.305248440279, hypo.eqShunts.get(0).bEq, 0.0001);
+ assertEquals(-0.3030327598342, hypo.eqBranches.get(0).rEq, 0.0001);
+ assertEquals(0.05718010758327, hypo.eqBranches.get(0).xEq, 0.0001);*/
+
+ }
+
+ @Test
+ void example4nReductionTest() {
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ //Create a list of voltage of the external network
+ List voltageLevels = new ArrayList<>();
+ voltageLevels.add("VL_4");
+
+ Network nt4 = Networks.create4n();
+ LoadFlowResult resultnt4 = loadFlowRunner.run(nt4, loadFlowParameters);
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+ ReductionParameters reductionParameters = new ReductionParameters(loadFlowParameters, matrixFactory, voltageLevels, ReductionEngine.ReductionType.WARD_INJ);
+ ReductionEngine re = new ReductionEngine(nt4, reductionParameters);
+
+ re.run();
+
+ ReductionEngine.ReductionResults results = re.getReductionResults();
+ ReductionEngine.ReductionHypotheses hypo = re.getReductionHypo();
+
+ assertEquals(0.045, hypo.eqBranches.get(0).xEq, 0.00001);
+ }
+
+ @Test
+ void example4nShuntReductionTest() {
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ //Create a list of voltage of the external network
+ List voltageLevels = new ArrayList<>();
+ voltageLevels.add("VL_4");
+
+ Network nt4Shunt = Networks.create4nShunt();
+ LoadFlowResult resultnt4Shunt = loadFlowRunner.run(nt4Shunt, loadFlowParameters);
+
+ ReductionParameters reductionParameters = new ReductionParameters(loadFlowParameters, matrixFactory, voltageLevels, ReductionEngine.ReductionType.WARD_SHUNT);
+ ReductionEngine re = new ReductionEngine(nt4Shunt, reductionParameters);
+
+ re.run();
+
+ ReductionEngine.ReductionResults results = re.getReductionResults();
+ ReductionEngine.ReductionHypotheses hypo = re.getReductionHypo();
+
+ assertEquals(0.0450525, hypo.eqBranches.get(0).xEq, 0.0000001); // line between B1 and B3
+ assertEquals(-0.046612, hypo.eqShunts.get(0).bEq, 0.000001); // shunt at bus 1
+ assertEquals(-0.058265, hypo.eqShunts.get(1).bEq, 0.000001); // shunt at bus 3
+
+ //we compare the previous network with the next one removing all equiments of BUS 4 and adding the previous hypotheses
+ Network nt4ShuntEq = Networks.create4nShuntEq();
+ LoadFlowResult resultnt4Eq = loadFlowRunner.run(nt4ShuntEq, loadFlowParameters);
+
+ double v1 = nt4Shunt.getBusBreakerView().getBus("B1").getV();
+ double v2 = nt4Shunt.getBusBreakerView().getBus("B2").getV();
+ double v3 = nt4Shunt.getBusBreakerView().getBus("B3").getV();
+
+ double v1Eq = nt4ShuntEq.getBusBreakerView().getBus("B1").getV();
+ double v2Eq = nt4ShuntEq.getBusBreakerView().getBus("B2").getV();
+ double v3Eq = nt4ShuntEq.getBusBreakerView().getBus("B3").getV();
+
+ assertEquals(v1, v1Eq, 0.000001);
+ assertEquals(v2, v2Eq, 0.000001);
+ assertEquals(v3, v3Eq, 0.000001);
+
+ }
+}
diff --git a/simulator/pom.xml b/simulator/pom.xml
new file mode 100644
index 00000000..46245fe4
--- /dev/null
+++ b/simulator/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+
+
+ com.powsybl
+ powsybl-incubator
+ 1.0.0-SNAPSHOT
+
+
+ powsybl-incubator-simulator
+ 1.0.0-SNAPSHOT
+ pom
+
+ Incubator for simulators
+
+
+ network-reduction
+ util
+ short-circuit
+
+
+
+ 11
+ 5.8.2
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+ test
+
+
+
+
diff --git a/simulator/short-circuit/pom.xml b/simulator/short-circuit/pom.xml
new file mode 100644
index 00000000..9670e14c
--- /dev/null
+++ b/simulator/short-circuit/pom.xml
@@ -0,0 +1,63 @@
+
+
+
+ 4.0.0
+
+
+ powsybl-incubator-simulator
+ com.powsybl
+ 1.0.0-SNAPSHOT
+
+
+ powsybl-incubator-simulator-short-circuit
+ Short circuit calculation
+
+
+
+ com.powsybl
+ powsybl-shortcircuit-api
+
+
+ com.powsybl
+ powsybl-incubator-simulator-util
+ ${project.version}
+
+
+
+ com.powsybl
+ powsybl-config-test
+ test
+
+
+ com.powsybl
+ powsybl-iidm-impl
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+ com.powsybl
+ powsybl-incubator-simulator-util
+ ${project.version}
+ test-jar
+ test
+
+
+
\ No newline at end of file
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/AbstractShortCircuitCalculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/AbstractShortCircuitCalculator.java
new file mode 100644
index 00000000..e65cfd3c
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/AbstractShortCircuitCalculator.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public abstract class AbstractShortCircuitCalculator {
+
+ Matrix mIo;
+ Matrix mId;
+ Matrix mIi;
+
+ Matrix mIk; //contains the shortcircuit values
+
+ double rdf;
+ double xdf;
+
+ double xof;
+ double rof;
+
+ double rg;
+ double xg;
+
+ double initVx;
+ double initVy;
+
+ MatrixFactory mf;
+
+ public AbstractShortCircuitCalculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf) {
+ this.rdf = rdf;
+ this.xdf = xdf;
+ this.rof = rof;
+ this.xof = xof;
+ this.rg = rg;
+ this.xg = xg;
+ this.initVx = initVx;
+ this.initVy = initVy;
+ this.mf = mf;
+
+ }
+
+ Matrix getmIo() {
+ return mIo;
+ }
+
+ Matrix getmId() {
+ return mId;
+ }
+
+ Matrix getmIi() {
+ return mIi;
+ }
+
+ public abstract void computeCurrents();
+
+ public enum BlocType {
+ A,
+ A2,
+ Id,
+ J
+ }
+
+ public static Matrix getMatrixByType(BlocType bt, double scalar, MatrixFactory mf) {
+ Matrix m = mf.create(2, 2, 2);
+ addMatrixBlocByType(m, bt, scalar);
+ return m;
+ }
+
+ public static void addMatrixBlocByType(Matrix m, BlocType bt, double scalar) {
+ if (bt == BlocType.A) {
+ addMatrixBloc(m, 1, -1. / 2. * scalar, -Math.sqrt(3.) / 2. * scalar, Math.sqrt(3.) / 2. * scalar, -1. / 2. * scalar);
+ } else if (bt == BlocType.A2) {
+ addMatrixBloc(m, 1, 1. / 2. * scalar, -Math.sqrt(3.) / 2. * scalar, Math.sqrt(3.) / 2. * scalar, 1. / 2. * scalar);
+ } else if (bt == BlocType.Id) {
+ addMatrixBloc(m, 1, scalar, 0., 0., scalar);
+ } else if (bt == BlocType.J) {
+ addMatrixBloc(m, 1, 0., -scalar, scalar, 0.);
+ } else {
+ throw new IllegalArgumentException("Bloc type unknown ");
+ }
+ }
+
+ public static void addMatrixBloc(Matrix m, int numBloc, double m11, double m12, double m21, double m22) {
+
+ if (numBloc != 1 && numBloc != 2) {
+ throw new IllegalArgumentException("Bloc number must be either 1 or 2 ");
+ }
+
+ int iIndex = 0;
+ if (numBloc == 2) {
+ iIndex = 2;
+ }
+
+ m.add(iIndex, 0, m11);
+ m.add(iIndex, 1, m12);
+ m.add(iIndex + 1, 0, m21);
+ m.add(iIndex + 1, 1, m22);
+ }
+
+ public static DenseMatrix addMatrices22(DenseMatrix m1, DenseMatrix m2, MatrixFactory mf) {
+ Matrix m = mf.create(2, 2, 2);
+
+ m.add(0, 0, m1.get(0, 0) + m2.get(0, 0));
+ m.add(0, 1, m1.get(0, 1) + m2.get(0, 1));
+ m.add(1, 0, m1.get(0, 1) + m2.get(1, 0));
+ m.add(1, 1, m1.get(0, 1) + m2.get(1, 1));
+
+ return m.toDense();
+ }
+
+ public static Matrix getInvZt(double r, double x, MatrixFactory mf) {
+ double detZ = r * r + x * x;
+ Matrix invZ = mf.create(2, 2, 2);
+ invZ.add(0, 0, r / detZ);
+ invZ.add(0, 1, x / detZ);
+ invZ.add(1, 0, -x / detZ);
+ invZ.add(1, 1, r / detZ);
+
+ return invZ;
+ }
+
+ public static Matrix getInvZt(Matrix m, MatrixFactory mf) {
+ double r = m.toDense().get(0, 0);
+ double x = m.toDense().get(1, 0);
+
+ return getInvZt(r, x, mf);
+ }
+
+ public static Matrix getZ(double r, double x, MatrixFactory mf) {
+ Matrix z = mf.create(2, 2, 2);
+ z.add(0, 0, r);
+ z.add(0, 1, -x);
+ z.add(1, 0, x);
+ z.add(1, 1, r);
+
+ return z;
+ }
+
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/AbstractShortCircuitEngine.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/AbstractShortCircuitEngine.java
new file mode 100644
index 00000000..cc544942
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/AbstractShortCircuitEngine.java
@@ -0,0 +1,209 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.commons.reporter.Reporter;
+import com.powsybl.iidm.network.Branch;
+import com.powsybl.iidm.network.Bus;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.iidm.network.ThreeWindingsTransformer;
+import com.powsybl.incubator.simulator.util.AdmittanceEquationSystem;
+import com.powsybl.incubator.simulator.util.CalculationLocation;
+import com.powsybl.incubator.simulator.util.extensions.ShortCircuitExtensions;
+import com.powsybl.openloadflow.OpenLoadFlowParameters;
+import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowParameters;
+import com.powsybl.openloadflow.graph.EvenShiloachGraphDecrementalConnectivityFactory;
+import com.powsybl.openloadflow.network.FirstSlackBusSelector;
+import com.powsybl.openloadflow.network.LfNetwork;
+import com.powsybl.openloadflow.network.LfNetworkParameters;
+import com.powsybl.openloadflow.network.impl.LfNetworkLoaderImpl;
+import org.apache.commons.math3.util.Pair;
+
+import java.util.*;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public abstract class AbstractShortCircuitEngine {
+ protected final Network network;
+
+ protected final ShortCircuitEngineParameters parameters;
+
+ protected final List lfNetworks;
+
+ public Map resultsPerFault = new HashMap<>();
+
+ protected List solverFaultList; // list of faults provided to the solver (not including biphased common support faults)
+
+ protected List solverBiphasedFaultList; // list of biphased common support faults provided to the solver
+
+ protected final AcLoadFlowParameters acLoadFlowParameters;
+
+ public AbstractShortCircuitEngine(Network network, ShortCircuitEngineParameters parameters) {
+ this.network = Objects.requireNonNull(network);
+ this.parameters = Objects.requireNonNull(parameters);
+ this.lfNetworks = LfNetwork.load(network, new LfNetworkLoaderImpl(), new LfNetworkParameters(new FirstSlackBusSelector()));
+ this.acLoadFlowParameters = getAcLoadFlowParametersFromParam();
+ ShortCircuitExtensions.add(network, lfNetworks, parameters.getAdditionalDataInfo());
+ }
+
+ protected AcLoadFlowParameters getAcLoadFlowParametersFromParam() {
+ OpenLoadFlowParameters loadflowParametersExt = OpenLoadFlowParameters.get(parameters.getLoadFlowParameters());
+ AcLoadFlowParameters acLoadFlowParameters = OpenLoadFlowParameters.createAcParameters(parameters.getLoadFlowParameters(), loadflowParametersExt, parameters.getMatrixFactory(), new EvenShiloachGraphDecrementalConnectivityFactory<>(), Reporter.NO_OP, false, false);
+ return acLoadFlowParameters;
+ }
+
+ protected AdmittanceEquationSystem.AdmittancePeriodType getAdmittancePeriodTypeFromParam() {
+ AdmittanceEquationSystem.AdmittancePeriodType admittancePeriodType = AdmittanceEquationSystem.AdmittancePeriodType.ADM_TRANSIENT;
+ if (parameters.getPeriodType() == ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT) {
+ admittancePeriodType = AdmittanceEquationSystem.AdmittancePeriodType.ADM_SUB_TRANSIENT;
+ } else if (parameters.getPeriodType() == ShortCircuitEngineParameters.PeriodType.STEADY_STATE) {
+ admittancePeriodType = AdmittanceEquationSystem.AdmittancePeriodType.ADM_STEADY_STATE;
+ }
+ return admittancePeriodType;
+ }
+
+ protected AdmittanceEquationSystem.AdmittanceVoltageProfileType getAdmittanceVoltageProfileTypeFromParam() {
+ AdmittanceEquationSystem.AdmittanceVoltageProfileType admittanceVoltageProfileType = AdmittanceEquationSystem.AdmittanceVoltageProfileType.NOMINAL;
+ if (parameters.getVoltageProfileType() == ShortCircuitEngineParameters.VoltageProfileType.CALCULATED) {
+ admittanceVoltageProfileType = AdmittanceEquationSystem.AdmittanceVoltageProfileType.CALCULATED;
+ }
+ return admittanceVoltageProfileType;
+ }
+
+ protected void buildSystematicList(ShortCircuitFault.ShortCircuitType type) {
+ List scfSystematic = new ArrayList<>();
+ parameters.setVoltageUpdate(false);
+ for (Bus bus : network.getBusBreakerView().getBuses()) {
+ ShortCircuitFault sc = new ShortCircuitFault(bus.getId(), false, bus.getId(), 0., 0., type); //TODO : check validity of voltage levels if no connexity
+ scfSystematic.add(sc);
+ }
+ parameters.setShortCircuitFaults(scfSystematic);
+ }
+
+ protected Pair, List> buildFaultListsFromInputs() {
+ // We handle a pre-treatement of faults given in input:
+ // - filtering faults because of some inconsistencies on the bus identification
+ // - addition of info in each fault to ease the identification in LfNetwork of iidm info
+
+ List faultList = new ArrayList<>();
+ List biphasedFaultList = new ArrayList<>();
+ Map> tmpListBus1 = new HashMap<>();
+ for (ShortCircuitFault scfe : parameters.getShortCircuitFaults()) {
+ String busName = scfe.getBusLocation();
+ String bus2Name = scfe.getBusLocationBiPhased();
+
+ if (bus2Name.isEmpty()) { // TODO : adapt
+ // TODO : put a condition that it is an unbalanced shortCircuit
+ if (scfe.getType() == ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT) {
+ throw new IllegalArgumentException(" short circuit fault : " + busName + " must have a second voltage level defined because it is a common support fault");
+ }
+ Pair branchFaultInfo = buildFaultBranchFromBusId(busName, network); // creates additional info for fault, identifying location through iidm branches instead of iidm busses to easily get lf busses
+ scfe.setIidmBusInfo(branchFaultInfo); // the short circuit fault info is now enriched with the couple iidmBranchId + iidmBranchSide and not only the iidm bus name in order to be able to identify the busses in the LfNetwork
+ faultList.add(scfe);
+
+ } else {
+ if (scfe.getType() != ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT) {
+ throw new IllegalArgumentException(" short circuit fault : " + busName + " has a second bus defined : " + bus2Name + " but is not a common support fault");
+ }
+
+ // Step 1 : get info at bus 1 initialization of bus 2 list
+ if (!tmpListBus1.containsKey(busName)) {
+ Pair branchBus1FaultInfo = buildFaultBranchFromBusId(busName, network);
+ tmpListBus1.put(busName, branchBus1FaultInfo);
+ }
+
+ // step 2 : get info at bus 2
+ Pair branchBus2FaultInfo = buildFaultBranchFromBusId(bus2Name, network);
+ Pair branchBus1FaultInfo = tmpListBus1.get(busName);
+
+ scfe.setIidmBusInfo(branchBus1FaultInfo);
+ scfe.setIidmBus2Info(branchBus2FaultInfo);
+ biphasedFaultList.add(scfe);
+ }
+ }
+
+ return new Pair<>(faultList, biphasedFaultList);
+ }
+
+ protected static Pair buildFaultBranchFromBusId(String busId, Network tmpNetwork) {
+ Pair branchFaultInfo = buildFaultDipoleFromBusId(busId, tmpNetwork);
+ if (branchFaultInfo.getKey().equals("")) {
+ // Bus not found in branches, try three windings transformers
+ branchFaultInfo = buildFaultT3WbranchFromBusId(busId, tmpNetwork);
+ }
+ return branchFaultInfo;
+ }
+
+ protected static Pair buildFaultDipoleFromBusId(String busId, Network tmpNetwork) {
+ // TODO : improve with direct correspondence between iidm busses and lfBusses when available, because this loop is not very efficient
+ Bus bus = tmpNetwork.getBusBreakerView().getBus(busId);
+ String branchId = "";
+ int branchSide = 0;
+ boolean isFound = false;
+ for (Branch branch : tmpNetwork.getBranches()) {
+ Bus bus1 = branch.getTerminal1().getBusBreakerView().getBus();
+ Bus bus2 = branch.getTerminal2().getBusBreakerView().getBus();
+ if (bus == bus1) {
+ branchId = branch.getId();
+ branchSide = 1;
+ isFound = true;
+ break;
+ } else if (bus == bus2) {
+ branchId = branch.getId();
+ branchSide = 2;
+ isFound = true;
+ break;
+ }
+ }
+
+ if (!isFound) {
+ System.out.println(" input CC Bus " + busId + " could not be associated with a bipole");
+ }
+
+ return new Pair<>(branchId, branchSide);
+ }
+
+ protected static Pair buildFaultT3WbranchFromBusId(String busId, Network tmpNetwork) {
+ // TODO : improve with direct correspondence between iidm busses and lfBusses when available, because this loop is not very efficient
+ Bus bus = tmpNetwork.getBusBreakerView().getBus(busId);
+ String branchId = "";
+ int legNum = 0;
+ boolean isFound = false;
+ for (ThreeWindingsTransformer t3w : tmpNetwork.getThreeWindingsTransformers()) {
+ Bus bus1 = t3w.getLeg1().getTerminal().getBusBreakerView().getBus();
+ Bus bus2 = t3w.getLeg2().getTerminal().getBusBreakerView().getBus();
+ Bus bus3 = t3w.getLeg3().getTerminal().getBusBreakerView().getBus();
+
+ if (bus == bus1) {
+ branchId = t3w.getId();
+ legNum = 1;
+ isFound = true;
+ break;
+ } else if (bus == bus2) {
+ branchId = t3w.getId();
+ legNum = 2;
+ isFound = true;
+ break;
+ } else if (bus == bus3) {
+ branchId = t3w.getId();
+ legNum = 3;
+ isFound = true;
+ break;
+ }
+ }
+
+ if (!isFound) {
+ System.out.println(" Bus " + busId + " could not be associated with a tripole");
+ }
+
+ return new Pair<>(branchId, legNum);
+ }
+
+ public abstract void run();
+
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1A2Calculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1A2Calculator.java
new file mode 100644
index 00000000..2c940f1b
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1A2Calculator.java
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class BiphasedC1A2Calculator extends BiphasedCommonSupportShortCircuitCalculator {
+
+ public BiphasedC1A2Calculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf,
+ double v2dxInit, double v2dyInit,
+ double ro12, double xo12, double ro22, double xo22, double ro21, double xo21,
+ double rd12, double xd12, double rd22, double xd22, double rd21, double xd21) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf, v2dxInit, v2dyInit, ro12, xo12, ro22, xo22, ro21, xo21, rd12, xd12, rd22, xd22, rd21, xd21);
+
+ //Description of the fault (short circuit between c1 and a2) :
+ // a1 ---------------x------------------ by definition : Ia1 = Ib1 = Ib2 = Ic2 = 0
+ // b1 ---------------x------------------ Ic1 = -Ia2
+ // c1 ---------------+------------------ Vc1 = Zf * Ic1 + Va2
+ // |
+ // Zf
+ // |
+ // a2 ---------------+------------------
+ // b2 ---------------x------------------
+ // c2 ---------------x------------------
+
+ //Problem to solve:
+ // Given the equalities above, we need to solve for V and I the following problem:
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = -tM * inv(Yd) * M * [ Idf ] + tM * [ V(init) ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+ // Where:
+ // - Yo and Yd are the full network admittance matrices (zero and direct fortescue components)
+ // - M is the extraction matrix to get the subvectors V1, V2, I1 and I2 of the full network vectors [V] and [I]
+ //
+ // Step 1: express the currents in fortescue basis :
+ //
+ // [ I1o ] [ 1 1 1 ] [ 0 ] [ 1 ]
+ // [ I1d ] = 1/3 * [ 1 a a²] * [ 0 ] = 1/3 * Ic1 * [ a²]
+ // [ I1i ] [ 1 a² a ] [ Ic1] [ a ]
+ //
+ // [ I2o ] [ 1 ]
+ // [ I2d ] = -1/3 *Ic1 * [ 1 ]
+ // [ I2i ] [ 1 ]
+ //
+ // Step 2: get Ic1 :
+ // Given: Vc1 = V1o + a * V1d + a² * V1i and Va2 = V2o + V2d + V2i
+ // and replacing them in: Vc1 = Zf * Ic1 + Va2
+ // we get
+ // a * V1d(init) - V2d(init)
+ // Ic1 = -----------------------------------------------------------------------------------------------------------------
+ // Zf + 1/3*(Zd_11 - a*Zd_12 + Zd_22-a²*Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - a²*Zi_12 + Zi_11 - a*Zi_21)
+ //
+ //
+ // Where Zo_ij and Zd_ij are complex impedance matrix elements at nodes 1 and 2:
+ // Zo = tM * inv(Yo) * M and Zd = tM * inv(Yd) * M
+ //
+ // Then, for example, we have with complex variables :
+ // [ V1of ] [ I1of ] [ Zo_11 Zo_12 ] [ I1of ]
+ // [ V2of ] = -Zof * [ I2of ] = - [ Zo_21 Zo_22 ] * [ I2of ]
+ //
+ // Step 3: compute the short circuit voltages:
+ // From computed Ic1 we get complex values : I1o, I1d, I1i, I2o, I2d, I2i using step 1 formulas expressed with Ic1
+ // Then compute the voltages from current values
+
+ computeZt(); // computes rt and xt
+ computeIc(); // computes Ic of common support from rt and xt
+ computeCurrents(); // computes Io, Id, Ii for both supports from computed Ic
+ computeVoltages(); // computes Vo, Vd, Vi from computed currents and computed terms of the impedance matrix
+
+ }
+
+ @Override
+ public void computeIc() {
+
+ // Compute Ic1 :
+ // Complex expression :
+ // a * V1d(init) - V2d(init)
+ // Ic1 = ------------------------------------------------------------------------------------------------------------------
+ // Zf + 1/3*(Zd_11 - a*Zd_12 + Zd_22-a²*Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - a²*Zi_12 + Zi_11 - a*Zi_21)
+ //
+ //
+ // The equivalent cartesian matrix expression of Ic :
+ // 1
+ // [ic1x] = ------------------------ * [ rt xt ] * ( [ -1/2 -sqrt(3)/2 ] * [vd1x] - [vd2x] )
+ // [ic1y] (rt² + xt²) [-xt rt ] ( [ sqrt(3)/2 -1/2 ] [vd1y] [vd2y] )
+ //
+
+ //compute the numerator matrix = a * V1d(init) - V2d(init)
+ Matrix ma = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1.0, mf);
+
+ Matrix mVd1Init = mf.create(2, 1, 2);
+ mVd1Init.add(0, 0, initVx);
+ mVd1Init.add(1, 0, initVy);
+
+ Matrix maVd = ma.times(mVd1Init);
+
+ maVd.add(0, 0, -v2dxInit);
+ maVd.add(1, 0, -v2dyInit);
+
+ // get Ic by multiplying the numerator to inv(Zt)
+ Matrix invZt = getInvZt(rt, xt, mf);
+ mIc = invZt.times(maVd);
+ }
+
+ @Override
+ public void computeZt() {
+ // Zf + 1/3*(Zd_11 - a*Zd_12 + Zd_22 -a²*Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - a²*Zi_12 + Zi_11 - a*Zi_21)
+ Matrix a2 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A2, 1.0, mf);
+ Matrix a = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1.0, mf);
+ Matrix minusId = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, -1.0, mf);
+ Matrix idDiv3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, 1. / 3., mf);
+
+ // td12 = - a*Zd_12
+ Matrix tmpd12 = a.times(zdf12);
+ Matrix td12 = minusId.times(tmpd12);
+
+ // td21 = -a²*Zd_21
+ Matrix tmpd21 = a2.times(zdf21);
+ Matrix td21 = minusId.times(tmpd21);
+
+ // to21 = -zof21 and to12 = -zof12
+ Matrix to21 = minusId.times(zof21);
+ Matrix to12 = minusId.times(zof12);
+
+ // ti12 = -a²*Zi_12
+ Matrix tmpi12 = a2.times(zif12);
+ Matrix ti12 = minusId.times(tmpi12);
+
+ // ti21 = - a*Zi_21
+ Matrix tmpi21 = a.times(zif21);
+ Matrix ti21 = minusId.times(tmpi21);
+
+ DenseMatrix zt = addMatrices22(zdf11.toDense(), td12.toDense(), mf);
+ zt = addMatrices22(zt, zdf22.toDense(), mf);
+ zt = addMatrices22(zt, td21.toDense(), mf);
+ zt = addMatrices22(zt, zof11.toDense(), mf);
+ zt = addMatrices22(zt, to21.toDense(), mf);
+ zt = addMatrices22(zt, zof22.toDense(), mf);
+ zt = addMatrices22(zt, to12.toDense(), mf);
+ zt = addMatrices22(zt, zif22.toDense(), mf);
+ zt = addMatrices22(zt, ti12.toDense(), mf);
+ zt = addMatrices22(zt, zif11.toDense(), mf);
+ zt = addMatrices22(zt, ti21.toDense(), mf);
+
+ Matrix tmpzt = idDiv3.times(zt);
+
+ Matrix zf = getZ(rg, xg, mf);
+
+ zt = addMatrices22(tmpzt.toDense(), zf.toDense(), mf);
+
+ rt = zt.get(0, 0);
+ xt = zt.get(1, 0);
+ }
+
+ @Override
+ public void computeCurrents() {
+ // step 3:
+ // get the currents vectors
+ // [ I1o ] [ 1 ]
+ // [ I1d ] = 1/3 * Ic1 * [ a²]
+ // [ I1i ] [ a ]
+ //
+ // [ I2o ] [ 1 ]
+ // [ I2d ] = -1/3 *Ic1 * [ 1 ]
+ // [ I2i ] [ 1 ]
+
+ Matrix mI3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, 1. / 3, mf);
+ Matrix ma2Div3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A2, 1. / 3, mf);
+ Matrix maDiv3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1. / 3, mf);
+ Matrix mMinusI = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, -1., mf);
+
+ mIo = mI3.times(mIc);
+ mId = ma2Div3.times(mIc);
+ mIi = maDiv3.times(mIc);
+
+ mI2o = mMinusI.times(mIo);
+ mI2d = mI2o;
+ mI2i = mI2o;
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1B2Calculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1B2Calculator.java
new file mode 100644
index 00000000..66a1349d
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1B2Calculator.java
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class BiphasedC1B2Calculator extends BiphasedCommonSupportShortCircuitCalculator {
+
+ public BiphasedC1B2Calculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf,
+ double v2dxInit, double v2dyInit,
+ double ro12, double xo12, double ro22, double xo22, double ro21, double xo21,
+ double rd12, double xd12, double rd22, double xd22, double rd21, double xd21) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf, v2dxInit, v2dyInit, ro12, xo12, ro22, xo22, ro21, xo21, rd12, xd12, rd22, xd22, rd21, xd21);
+
+ //Description of the fault (short circuit between c1 and a2) :
+ // a1 ---------------x------------------ by definition : Ia1 = Ib1 = Ia2 = Ic2 = 0
+ // b1 ---------------x------------------ Ic1 = -Ib2
+ // c1 ---------------+------------------ Vc1 = Zf * Ic1 + Vb2
+ // |
+ // Zf
+ // |
+ // b2 ---------------+------------------
+ // c2 ---------------x------------------
+ // a2 ---------------x------------------
+
+ //Problem to solve:
+ // Given the equalities above, we need to solve for V and I the following problem:
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = tM * [ V(init) ] - tM * inv(Yd) * M * [ Idf ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+ // Where:
+ // - Yo and Yd are the full network admittance matrices (zero and direct fortescue components)
+ // - M is the extraction matrix to get the subvectors V1, V2, I1 and I2 of the full network vectors [V] and [I]
+ //
+ // Step 1: express the currents in fortescue basis :
+ //
+ // [ I1o ] [ 1 1 1 ] [ 0 ] [ 1 ]
+ // [ I1d ] = 1/3 * [ 1 a a²] * [ 0 ] = 1/3 * Ic1 * [ a²]
+ // [ I1i ] [ 1 a² a ] [ Ic1] [ a ]
+ //
+ // [ I2o ] [ 1 ]
+ // [ I2d ] = -1/3 *Ic1 * [ a ]
+ // [ I2i ] [ a²]
+ //
+ // Step 2: get Ic1 :
+ // Given: Vc1 = V1o + a * V1d + a² * V1i and Vb2 = V2o + a² * V2d + a * V2i
+ // and replacing them in: Vc1 = Zf * Ic1 + Vb2
+ // we get
+ // a * V1d(init) - a² * V2d(init)
+ // Ic1 = --------------------------------------------------------------------------------------------------------------------
+ // Zf + 1/3*(Zd_11 - a²*Zd_12 + Zd_22 - a*Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - a*Zi_12 + Zi_11 - a²*Zi_21)
+ //
+ // Where Zof_ij and Zdf_ij are complex impedance matrix elements at nodes 1 and 2:
+ // Zof = tM * inv(Yo) * M and Zdf = tM * inv(Yd) * M
+ //
+ // Then, for example, we have with complex variables :
+ // [ V1of ] [ I1of ] [ Zof_11 Zof_12 ] [ I1of ]
+ // [ V2of ] = -Zof * [ I2of ] = - [ Zof_21 Zof_22 ] * [ I2of ]
+ //
+ // Step 3: compute the short circuit voltages:
+ // From computed Ic1 we get complex values : I1o, I1d, I1i, I2o, I2d, I2i using step 1 formulas expressed with Ic1
+ // Then compute the voltages from current values
+
+ computeZt(); // computes rt and xt
+ computeIc(); // computes Ic of common support from rt and xt
+ computeCurrents(); // computes Io, Id, Ii for both supports from computed Ic
+ computeVoltages(); // computes Vo, Vd, Vi from computed currents and computed terms of the impedance matrix
+
+ }
+
+ @Override
+ public void computeIc() {
+
+ // Compute Ic1 :
+ // Complex expression :
+ // a * V1d(init) - a² * V2d(init)
+ // Ic1 = -------------------------------------------------------------------------------------------------------------------
+ // Zf + 1/3*(Zd_11 - a²*Zd_12 + Zd_22 - a*Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - a*Zi_12 + Zi_11 - a²*Zi_21)
+ //
+ //
+ // The equivalent cartesian matrix expression of Ic :
+ // 1
+ // [ic1x] = ------------------------ * [ rt xt ] * ( [ -1/2 -sqrt(3)/2 ] * [vd1x] - [ 1/2 -sqrt(3)/2 ] * [vd2x] )
+ // [ic1y] (rt² + xt²) [-xt rt ] ( [ sqrt(3)/2 -1/2 ] [vd1y] [ sqrt(3)/2 1/2 ] [vd2y] )
+ //
+
+ //compute the numerator matrix = a * V1d(init) - a² * V2d(init)
+ Matrix ma = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1.0, mf);
+
+ Matrix mVd2Init = mf.create(2, 1, 2);
+ mVd2Init.add(0, 0, -v2dxInit);
+ mVd2Init.add(1, 0, -v2dyInit);
+ Matrix maVd2 = ma.times(mVd2Init);
+
+ maVd2.add(0, 0, initVx);
+ maVd2.add(1, 0, initVy);
+
+ DenseMatrix numerator = ma.times(maVd2).toDense();
+
+ // get Ic by multiplying the numerator to inv(Zt)
+ Matrix invZt = getInvZt(rt, xt, mf);
+ mIc = invZt.times(numerator);
+ }
+
+ @Override
+ public void computeZt() {
+
+ // Zf + 1/3*(Zd_11 - a²*Zd_12 + Zd_22 - a*Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - a*Zi_12 + Zi_11 - a²*Zi_21)
+ Matrix a2 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A2, 1.0, mf);
+ Matrix a = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1.0, mf);
+ Matrix minusId = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, -1.0, mf);
+ Matrix idDiv3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, 1. / 3., mf);
+
+ // td12 = - a²*Zd_12
+ Matrix tmpd12 = a2.times(zdf12);
+ Matrix td12 = minusId.times(tmpd12);
+
+ // td21 = - a*Zd_21
+ Matrix tmpd21 = a.times(zdf21);
+ Matrix td21 = minusId.times(tmpd21);
+
+ // to21 = -zof21 and to12 = -zof12
+ Matrix to21 = minusId.times(zof21);
+ Matrix to12 = minusId.times(zof12);
+
+ // ti12 = - a*Zi_12
+ Matrix tmpi12 = a.times(zif12);
+ Matrix ti12 = minusId.times(tmpi12);
+
+ // ti21 = - a²*Zi_21
+ Matrix tmpi21 = a2.times(zif21);
+ Matrix ti21 = minusId.times(tmpi21);
+
+ DenseMatrix zt = addMatrices22(zdf11.toDense(), td12.toDense(), mf);
+ zt = addMatrices22(zt, zdf22.toDense(), mf);
+ zt = addMatrices22(zt, td21.toDense(), mf);
+ zt = addMatrices22(zt, zof11.toDense(), mf);
+ zt = addMatrices22(zt, to21.toDense(), mf);
+ zt = addMatrices22(zt, zof22.toDense(), mf);
+ zt = addMatrices22(zt, to12.toDense(), mf);
+ zt = addMatrices22(zt, zif22.toDense(), mf);
+ zt = addMatrices22(zt, ti12.toDense(), mf);
+ zt = addMatrices22(zt, zif11.toDense(), mf);
+ zt = addMatrices22(zt, ti21.toDense(), mf);
+
+ Matrix tmpzt = idDiv3.times(zt);
+
+ Matrix zf = getZ(rg, xg, mf);
+
+ zt = addMatrices22(tmpzt.toDense(), zf.toDense(), mf);
+
+ rt = zt.get(0, 0);
+ xt = zt.get(1, 0);
+
+ }
+
+ @Override
+ public void computeCurrents() {
+ // step 3:
+ // get the currents vectors
+ // [ I1o ] [ 1 ]
+ // [ I1d ] = 1/3 * Ic1 * [ a²]
+ // [ I1i ] [ a ]
+ //
+ // [ I2o ] [ 1 ]
+ // [ I2d ] = -1/3 *Ic1 * [ a ]
+ // [ I2i ] [ a²]
+
+ Matrix mI3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, 1. / 3, mf);
+ Matrix ma2Div3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A2, 1. / 3, mf);
+ Matrix maDiv3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1. / 3, mf);
+ Matrix mMinusI = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, -1., mf);
+
+ mIo = mI3.times(mIc);
+ mId = ma2Div3.times(mIc);
+ mIi = maDiv3.times(mIc);
+
+ mI2o = mMinusI.times(mIo);
+ mI2d = maDiv3.times(mIo);
+ mI2i = ma2Div3.times(mIo);
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1C2Calculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1C2Calculator.java
new file mode 100644
index 00000000..19bf728c
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedC1C2Calculator.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class BiphasedC1C2Calculator extends BiphasedCommonSupportShortCircuitCalculator {
+
+ public BiphasedC1C2Calculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf,
+ double v2dxInit, double v2dyInit,
+ double ro12, double xo12, double ro22, double xo22, double ro21, double xo21,
+ double rd12, double xd12, double rd22, double xd22, double rd21, double xd21) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf, v2dxInit, v2dyInit, ro12, xo12, ro22, xo22, ro21, xo21, rd12, xd12, rd22, xd22, rd21, xd21);
+
+//Description of the fault (short circuit between c1 and a2) :
+ // a1 ---------------x------------------ by definition : Ia1 = Ib1 = Ia2 = Ib2 = 0
+ // b1 ---------------x------------------ Ic1 = -Ic2
+ // c1 ---------------+------------------ Vc1 = Zf * Ic1 + Vc2
+ // |
+ // Zf
+ // |
+ // c2 ---------------+------------------
+ // a2 ---------------x------------------
+ // b2 ---------------x------------------
+
+ //Problem to solve:
+ // Given the equalities above, we need to solve for V and I the following problem:
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = tM * [ V(init) ] - tM * inv(Yd) * M * [ Idf ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+ // Where:
+ // - Yo and Yd are the full network admittance matrices (zero and direct fortescue components)
+ // - M is the extraction matrix to get the subvectors V1, V2, I1 and I2 of the full network vectors [V] and [I]
+ //
+ // Step 1: express the currents in fortescue basis :
+ //
+ // [ I1o ] [ 1 1 1 ] [ 0 ] [ 1 ]
+ // [ I1d ] = 1/3 * [ 1 a a²] * [ 0 ] = 1/3 * Ic1 * [ a²]
+ // [ I1i ] [ 1 a² a ] [ Ic1] [ a ]
+ //
+ // [ I2o ] [ 1 ]
+ // [ I2d ] = -1/3 *Ic1 * [ a²]
+ // [ I2i ] [ a ]
+ //
+ // Step 2: get Ic1 :
+ // Given: Vc1 = V1o + a * V1d + a² * V1i and Vc2 = V2o + a * V2d + a² * V2i
+ // and replacing them in: Vc1 = Zf * Ic1 + Vb2
+ // we get
+ // a * (V1d(init) - V2d(init))
+ // Ic1 = ---------------------------------------------------------------------------------------------------------
+ // Zf + 1/3*(Zd_11 - Zd_12 + Zd_22 - Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - Zi_12 + Zi_11 - Zi_21)
+ //
+ // Where Zof_ij and Zdf_ij are complex impedance matrix elements at nodes 1 and 2:
+ // Zof = tM * inv(Yo) * M and Zdf = tM * inv(Yd) * M
+ //
+ // Then, for example, we have with complex variables :
+ // [ V1of ] [ I1of ] [ Zof_11 Zof_12 ] [ I1of ]
+ // [ V2of ] = -Zof * [ I2of ] = - [ Zof_21 Zof_22 ] * [ I2of ]
+ //
+ // Step 3: compute the short circuit voltages:
+ // From computed Ic1 we get complex values : I1o, I1d, I1i, I2o, I2d, I2i using step 1 formulas expressed with Ic1
+ // Then compute the voltages from current values
+
+ computeZt(); // computes rt and xt
+ computeIc(); // computes Ic of common support from rt and xt
+ computeCurrents(); // computes Io, Id, Ii for both supports from computed Ic
+ computeVoltages(); // computes Vo, Vd, Vi from computed currents and computed terms of the impedance matrix
+
+ }
+
+ @Override
+ public void computeIc() {
+
+ // Compute Ic1 :
+ // Complex expression :
+ // a * (V1d(init) - V2d(init))
+ // Ic1 = ---------------------------------------------------------------------------------------------------------
+ // Zf + 1/3*(Zd_11 - Zd_12 + Zd_22 - Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - Zi_12 + Zi_11 - Zi_21)
+ //
+ //
+ // The equivalent cartesian matrix expression of Ic :
+ // 1
+ // [ic1x] = ------------------------ * [ rt xt ] * [ -1/2 -sqrt(3)/2 ] * ( [vd1x] - [vd2x] )
+ // [ic1y] (rt² + xt²) [-xt rt ] [ sqrt(3)/2 -1/2 ] ( [vd1y] [vd2y] )
+ //
+
+ //compute the numerator matrix = a * (V1d(init) - V2d(init))
+ Matrix ma = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1.0, mf);
+
+ Matrix mVdInit = mf.create(2, 1, 2);
+ mVdInit.add(0, 0, initVx - v2dxInit);
+ mVdInit.add(1, 0, initVy - v2dyInit);
+
+ Matrix numerator = ma.times(mVdInit);
+
+ // get Ic by multiplying the numerator to inv(Zt)
+ Matrix invZt = getInvZt(rt, xt, mf);
+ mIc = invZt.times(numerator);
+ }
+
+ @Override
+ public void computeZt() {
+ // Zf + 1/3*(Zd_11 - Zd_12 + Zd_22 - Zd_21 + Zo_11 - Zo_21 + Zo_22 - Zo_12 + Zi_22 - Zi_12 + Zi_11 - Zi_21)
+ Matrix mId = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, -1.0, mf);
+ Matrix idDiv3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, 1. / 3., mf);
+
+ Matrix td12 = mId.times(zdf12);
+ Matrix td21 = mId.times(zdf21);
+
+ Matrix to21 = mId.times(zof21);
+ Matrix to12 = mId.times(zof12);
+
+ Matrix ti12 = mId.times(zif12);
+ Matrix ti21 = mId.times(zif21);
+
+ DenseMatrix zt = addMatrices22(zdf11.toDense(), td12.toDense(), mf);
+ zt = addMatrices22(zt, zdf22.toDense(), mf);
+ zt = addMatrices22(zt, td21.toDense(), mf);
+ zt = addMatrices22(zt, zof11.toDense(), mf);
+ zt = addMatrices22(zt, to21.toDense(), mf);
+ zt = addMatrices22(zt, zof22.toDense(), mf);
+ zt = addMatrices22(zt, to12.toDense(), mf);
+ zt = addMatrices22(zt, zif22.toDense(), mf);
+ zt = addMatrices22(zt, ti12.toDense(), mf);
+ zt = addMatrices22(zt, zif11.toDense(), mf);
+ zt = addMatrices22(zt, ti21.toDense(), mf);
+
+ Matrix tmpzt = idDiv3.times(zt);
+
+ Matrix zf = getZ(rg, xg, mf);
+
+ zt = addMatrices22(tmpzt.toDense(), zf.toDense(), mf);
+
+ rt = zt.get(0, 0);
+ xt = zt.get(1, 0);
+ }
+
+ @Override
+ public void computeCurrents() {
+ // step 3:
+ // get the currents vectors
+ // [ I1o ] [ 1 ]
+ // [ I1d ] = 1/3 * Ic1 * [ a²]
+ // [ I1i ] [ a ]
+ //
+ // [ I2o ] [ 1 ]
+ // [ I2d ] = -1/3 *Ic1 * [ a²]
+ // [ I2i ] [ a ]
+
+ Matrix mI3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, 1. / 3, mf);
+ Matrix ma2Div3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A2, 1. / 3, mf);
+ Matrix maDiv3 = getMatrixByType(AbstractShortCircuitCalculator.BlocType.A, 1. / 3, mf);
+ Matrix mMinusI = getMatrixByType(AbstractShortCircuitCalculator.BlocType.Id, -1., mf);
+
+ mIo = mI3.times(mIc);
+ mId = ma2Div3.times(mIc);
+ mIi = maDiv3.times(mIc);
+
+ mI2o = mMinusI.times(mIo);
+ mI2d = mMinusI.times(mId);
+ mI2i = mMinusI.times(mIi);
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedCommonSupportShortCircuitCalculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedCommonSupportShortCircuitCalculator.java
new file mode 100644
index 00000000..27cbf368
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedCommonSupportShortCircuitCalculator.java
@@ -0,0 +1,295 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class BiphasedCommonSupportShortCircuitCalculator extends AbstractShortCircuitCalculator {
+
+ protected double ro12;
+ protected double xo12;
+ protected double ro22;
+ protected double xo22;
+ protected double ro21;
+ protected double xo21;
+
+ protected double rd12;
+ protected double xd12;
+ protected double rd22;
+ protected double xd22;
+ protected double rd21;
+ protected double xd21;
+
+ protected double v2dxInit;
+ protected double v2dyInit;
+
+ protected Matrix zdf11;
+ protected Matrix zdf12;
+ protected Matrix zdf21;
+ protected Matrix zdf22;
+ protected Matrix zof11;
+ protected Matrix zof12;
+ protected Matrix zof21;
+ protected Matrix zof22;
+ protected Matrix zif11;
+ protected Matrix zif12;
+ protected Matrix zif21;
+ protected Matrix zif22;
+
+ protected Matrix zdf;
+ protected Matrix zof;
+
+ protected Matrix mI2o; // current from bus 2
+ protected Matrix mI2d;
+ protected Matrix mI2i;
+
+ protected Matrix mVo;
+ protected Matrix mVd;
+ protected Matrix mVi;
+
+ protected double rt; // values of total impedance used to get Ic
+ protected double xt;
+
+ protected Matrix mIc; // short circuit phase C1 current circulating from common support 1 to 2
+
+ public BiphasedCommonSupportShortCircuitCalculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf,
+ double v2dxInit, double v2dyInit,
+ double ro12, double xo12, double ro22, double xo22, double ro21, double xo21,
+ double rd12, double xd12, double rd22, double xd22, double rd21, double xd21) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf);
+ this.ro12 = ro12;
+ this.ro21 = ro21;
+ this.ro22 = ro22;
+ this.xo12 = xo12;
+ this.xo21 = xo21;
+ this.xo22 = xo22;
+ this.rd12 = rd12;
+ this.rd21 = rd21;
+ this.rd22 = rd22;
+ this.xd12 = xd12;
+ this.xd21 = xd21;
+ this.xd22 = xd22;
+ this.v2dxInit = v2dxInit;
+ this.v2dyInit = v2dyInit;
+
+ buildZxf(); // build all remaining matrix elements from inputs
+
+ }
+
+ public void computeZt() { }
+
+ public void computeIc() { }
+
+ public void computeCurrents() { }
+
+ public void computeVoltages() {
+ // Function using no input args
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = -tM * inv(Yd) * M * [ Idf ] + tM * [ V(init) ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+
+ //get the voltage vectors
+ // Vo :
+ // [v1ox] [ rof_11 -xof_11 rof_12 -xof_12 ] [ i1ox ]
+ // [v1oy] = -1 * [ xof_11 rof_11 xof_12 rof_12 ] * [ i1oy ]
+ // [v2ox] [ rof_21 -xof_21 rof_22 -xof_22 ] [ i2ox ]
+ // [v2oy] [ xof_21 rof_21 xof_22 rof_22 ] [ i2oy ]
+ Matrix minusIo = mf.create(4, 1, 4);
+ minusIo.add(0, 0, -getmIo().toDense().get(0, 0));
+ minusIo.add(1, 0, -getmIo().toDense().get(1, 0));
+ minusIo.add(2, 0, -getmI2o().toDense().get(0, 0));
+ minusIo.add(3, 0, -getmI2o().toDense().get(1, 0));
+
+ mVo = zof.times(minusIo);
+
+ // Vd :
+ // [v1dx] [ rdf_11 -xdf_11 rdf_12 -xdf_12 ] [ i1ox ] [v1dx(init)]
+ // [v1dy] = -1 * [ xdf_11 rdf_11 xdf_12 rdf_12 ] * [ i1oy ] + [v1dy(init)]
+ // [v2dx] [ rdf_21 -xdf_21 rdf_22 -xdf_22 ] [ i2ox ] [v2dx(init)]
+ // [v2dy] [ xdf_21 rdf_21 xdf_22 rdf_22 ] [ i2oy ] [v2dy(init)]
+ Matrix minusId = mf.create(4, 1, 4);
+ minusId.add(0, 0, -getmId().toDense().get(0, 0));
+ minusId.add(1, 0, -getmId().toDense().get(1, 0));
+ minusId.add(2, 0, -getmI2d().toDense().get(0, 0));
+ minusId.add(3, 0, -getmI2d().toDense().get(1, 0));
+
+ mVd = zdf.times(minusId);
+ // TODO: mVd contains the delta values, not Vinit, this is why lines below are commented and will be removed
+ //mVd.add(0, 0, initVx);
+ //mVd.add(1, 0, initVy);
+ //mVd.add(2, 0, v2dxInit);
+ //mVd.add(3, 0, v2dyInit);
+
+ // Vi :
+ // [v1ix] [ rdf_11 -xdf_11 rdf_12 -xdf_12 ] [ i1dx ]
+ // [v1iy] = -1 * [ xdf_11 rdf_11 xdf_12 rdf_12 ] * [ i1dy ]
+ // [v2ix] [ rdf_21 -xdf_21 rdf_22 -xdf_22 ] [ i2dx ]
+ // [v2iy] [ xdf_21 rdf_21 xdf_22 rdf_22 ] [ i2dy ]
+
+ Matrix minusIi = mf.create(4, 1, 4);
+ minusIi.add(0, 0, -getmIi().toDense().get(0, 0));
+ minusIi.add(1, 0, -getmIi().toDense().get(1, 0));
+ minusIi.add(2, 0, -getmI2i().toDense().get(0, 0));
+ minusIi.add(3, 0, -getmI2i().toDense().get(1, 0));
+
+ mVi = zdf.times(minusIi);
+
+ }
+
+ public void buildZxf() {
+
+ zdf11 = mf.create(2, 2, 2);
+ zdf11.add(0, 0, rdf);
+ zdf11.add(0, 1, -xdf);
+ zdf11.add(1, 0, xdf);
+ zdf11.add(1, 1, rdf);
+
+ zdf12 = mf.create(2, 2, 2);
+ zdf12.add(0, 0, rd12);
+ zdf12.add(0, 1, -xd12);
+ zdf12.add(1, 0, xd12);
+ zdf12.add(1, 1, rd12);
+
+ zdf21 = mf.create(2, 2, 2);
+ zdf21.add(0, 0, rd21);
+ zdf21.add(0, 1, -xd21);
+ zdf21.add(1, 0, xd21);
+ zdf21.add(1, 1, rd21);
+
+ zdf22 = mf.create(2, 2, 2);
+ zdf22.add(0, 0, rd22);
+ zdf22.add(0, 1, -xd22);
+ zdf22.add(1, 0, xd22);
+ zdf22.add(1, 1, rd22);
+
+ zof11 = mf.create(2, 2, 2);
+ zof11.add(0, 0, rof);
+ zof11.add(0, 1, -xof);
+ zof11.add(1, 0, xof);
+ zof11.add(1, 1, rof);
+
+ zof12 = mf.create(2, 2, 2);
+ zof12.add(0, 0, ro12);
+ zof12.add(0, 1, -xo12);
+ zof12.add(1, 0, xo12);
+ zof12.add(1, 1, ro12);
+
+ zof21 = mf.create(2, 2, 2);
+ zof21.add(0, 0, ro21);
+ zof21.add(0, 1, -xo21);
+ zof21.add(1, 0, xo21);
+ zof21.add(1, 1, ro21);
+
+ zof22 = mf.create(2, 2, 2);
+ zof22.add(0, 0, ro22);
+ zof22.add(0, 1, -xo22);
+ zof22.add(1, 0, xo22);
+ zof22.add(1, 1, ro22);
+
+ zif11 = mf.create(2, 2, 2);
+ zif11.add(0, 0, rdf);
+ zif11.add(0, 1, -xdf);
+ zif11.add(1, 0, xdf);
+ zif11.add(1, 1, rdf);
+
+ zif12 = mf.create(2, 2, 2);
+ zif12.add(0, 0, rd12);
+ zif12.add(0, 1, -xd12);
+ zif12.add(1, 0, xd12);
+ zif12.add(1, 1, rd12);
+
+ zif21 = mf.create(2, 2, 2);
+ zif21.add(0, 0, rd21);
+ zif21.add(0, 1, -xd21);
+ zif21.add(1, 0, xd21);
+ zif21.add(1, 1, rd21);
+
+ zif22 = mf.create(2, 2, 2);
+ zif22.add(0, 0, rd22);
+ zif22.add(0, 1, -xd22);
+ zif22.add(1, 0, xd22);
+ zif22.add(1, 1, rd22);
+
+ //Matrix zof
+ // [ rof_11 -xof_11 rof_12 -xof_12 ]
+ // [ xof_11 rof_11 xof_12 rof_12 ]
+ // [ rof_21 -xof_21 rof_22 -xof_22 ]
+ // [ xof_21 rof_21 xof_22 rof_22 ]
+ zof = mf.create(4, 4, 16);
+ zof.add(0, 0, rof);
+ zof.add(0, 1, -xof);
+ zof.add(1, 0, xof);
+ zof.add(1, 1, rof);
+
+ zof.add(0, 2, ro12);
+ zof.add(0, 3, -xo12);
+ zof.add(1, 2, xo12);
+ zof.add(1, 3, ro12);
+
+ zof.add(2, 0, ro21);
+ zof.add(2, 1, -xo21);
+ zof.add(3, 0, xo21);
+ zof.add(3, 1, ro21);
+
+ zof.add(2, 2, ro22);
+ zof.add(2, 3, -xo22);
+ zof.add(3, 2, xo22);
+ zof.add(3, 3, ro22);
+
+ //Matrix zdf
+ zdf = mf.create(4, 4, 16);
+ zdf.add(0, 0, rdf);
+ zdf.add(0, 1, -xdf);
+ zdf.add(1, 0, xdf);
+ zdf.add(1, 1, rdf);
+
+ zdf.add(0, 2, rd12);
+ zdf.add(0, 3, -xd12);
+ zdf.add(1, 2, xd12);
+ zdf.add(1, 3, rd12);
+
+ zdf.add(2, 0, rd21);
+ zdf.add(2, 1, -xd21);
+ zdf.add(3, 0, xd21);
+ zdf.add(3, 1, rd21);
+
+ zdf.add(2, 2, rd22);
+ zdf.add(2, 3, -xd22);
+ zdf.add(3, 2, xd22);
+ zdf.add(3, 3, rd22);
+
+ }
+
+ public Matrix getmI2d() {
+ return mI2d;
+ }
+
+ public Matrix getmI2i() {
+ return mI2i;
+ }
+
+ public Matrix getmI2o() {
+ return mI2o;
+ }
+
+ public Matrix getmVd() {
+ return mVd;
+ }
+
+ public Matrix getmVi() {
+ return mVi;
+ }
+
+ public Matrix getmVo() {
+ return mVo;
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedGroundShortCircuitCalculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedGroundShortCircuitCalculator.java
new file mode 100644
index 00000000..e7efb48c
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedGroundShortCircuitCalculator.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class BiphasedGroundShortCircuitCalculator extends AbstractShortCircuitCalculator {
+
+ public BiphasedGroundShortCircuitCalculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf);
+
+ }
+
+ public void computeCurrents() {
+ //Description of the fault:
+ // a ---------------x------------------ by definition : Ia = 0
+ // b ---------------+------------------ Vc = Vb = 0
+ // |
+ // |
+ // c ---------------+------------------
+ // |
+ // |
+ // /////
+ //
+ //Problem to solve:
+ // Given the equalities above, we need to solve for V and I the following problem:
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = -tM * inv(Yd) * M * [ Idf ] + tM * [ V(init) ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+ // Where:
+ // - Yo and Yd are the full network admittance matrices (zero and direct fortescue components)
+ // - M is the extraction matrix to get the subvectors V1, I1 of the full network vectors [V] and [I]
+ //
+ // Step 1: express the currents in fortescue basis :
+ //
+ // [ Io ] [ 1 1 1 ] [ 0 ]
+ // [ Id ] = 1/3 * [ 1 a a²] * [ Ib ] => Io + Id + Ii = 0
+ // [ Ii ] [ 1 a² a ] [ Ic ]
+ //
+ // Vo = Vd = Vi = 1/3 * Va
+ //
+ // Step 2:
+ // Using the previous expressions we get : Id, Ii, Io and Va
+
+ // Zof and Zdf are complex impedance matrix elements :
+ // Zof = tM * inv(Yo) * M and Zdf = tM * inv(Yd) * M
+ //
+ // Step 3: compute the short circuit voltages:
+ // From computed Ic1 we get complex values : I1o, I1d, I1i, I2o, I2d, I2i using step 1 formulas expressed with Ic1
+ // Then compute the voltages from current values
+
+ Matrix zof = getZ(rof, xof, mf);
+ Matrix zdf = getZ(rdf, xdf, mf);
+
+ // (zof + zdf) * [Vinit]
+ // Id = ---------------------------
+ // Zdf * (Zdf + 2 * Zof)
+ //
+ // - zof * [Vinit]
+ // Ii = ---------------------------
+ // Zdf * (Zdf + 2 * Zof)
+ //
+ // - zdf * [Vinit]
+ // Io = ---------------------------
+ // Zdf * (Zdf + 2 * Zof)
+ //
+ // - 3 * zof * [Vinit]
+ // Va = ---------------------
+ // Zdf + 2 * Zof
+
+ Matrix vdInit = mf.create(2, 1, 2);
+ vdInit.add(0, 0, initVx);
+ vdInit.add(1, 0, initVy);
+
+ Matrix twoId = getMatrixByType(BlocType.Id, 2., mf);
+ Matrix minusId = getMatrixByType(BlocType.Id, -1., mf);
+ Matrix threeId = getMatrixByType(BlocType.Id, 3., mf);
+
+ Matrix twoZof = twoId.times(zof);
+ Matrix zdf2Zof = addMatrices22(zdf.toDense(), twoZof.toDense(), mf);
+ Matrix zdfZof = addMatrices22(zdf.toDense(), zof.toDense(), mf);
+ Matrix minusZof = zof.times(minusId);
+ Matrix minusZdf = zdf.times(minusId);
+
+ Matrix numId = zdfZof.times(vdInit);
+ Matrix numIo = minusZdf.times(vdInit);
+ Matrix numIi = minusZof.times(vdInit);
+
+ Matrix demonI = zdf.times(zdf2Zof);
+ Matrix invDemonI = getInvZt(demonI, mf);
+
+ mId = invDemonI.times(numId);
+ mIo = invDemonI.times(numIo);
+ mIi = invDemonI.times(numIi);
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedShortCircuitCalculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedShortCircuitCalculator.java
new file mode 100644
index 00000000..7e24f43f
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/BiphasedShortCircuitCalculator.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class BiphasedShortCircuitCalculator extends AbstractShortCircuitCalculator {
+
+ public BiphasedShortCircuitCalculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf);
+
+ }
+
+ public void computeCurrents() {
+ //Description of the fault:
+ // a ---------------x------------------ by definition : Ia = 0
+ // b ---------------+------------------ Ib = -Ic
+ // |
+ // Zf
+ // |
+ // c ---------------+------------------ Vb = Zf * Ib + Vc
+ //
+ //Problem to solve:
+ // Given the equalities above, we need to solve for V and I the following problem:
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = -tM * inv(Yd) * M * [ Idf ] + tM * [ V(init) ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+ // Where:
+ // - Yo and Yd are the full network admittance matrices (zero and direct fortescue components)
+ // - M is the extraction matrix to get the subvectors V1, I1 of the full network vectors [V] and [I]
+ //
+ // Step 1: express the currents in fortescue basis :
+ //
+ // [ Io ] [ 1 1 1 ] [ 0 ] [ 0 ]
+ // [ Id ] = 1/3 * [ 1 a a²] * [ Ib ] = 1/3 * Ib * [a - a²]
+ // [ Ii ] [ 1 a² a ] [-Ib ] [a²- a ]
+ //
+ // Step 2: get Ib :
+ // Given: Vb = Vo + a² * Vd + a * Vi and Vc = Vo + a * Vd + a² * Vi
+ // replacing them in Vb = Zf * Ib + Vc we get :
+ //
+ // tM * [Vinit] j * sqrt(3) * tM * [Vinit]
+ // Ib = ----------------------------------- = -----------------------------
+ // (a-a²)/3 * (Zif + Zdf) + Zf/(a²-a) Zdf + Zif +Zf
+ //
+ // Where Zof and Zdf are complex impedance matrix elements :
+ // Zof = tM * inv(Yo) * M and Zdf = tM * inv(Yd) * M
+ //
+ // Step 3: compute the short circuit voltages:
+ // From computed Ic1 we get complex values : I1o, I1d, I1i, I2o, I2d, I2i using step 1 formulas expressed with Ic1
+ // Then compute the voltages from current values
+ double rt = 2 * rdf + rg;
+ double xt = 2 * xdf + xg;
+
+ // [Zt] = [ rt -xt ]
+ // [ xt rt ]
+ //
+ // Cartesian expression of Ic using matrices :
+ // -sqrt(3)
+ // [ibx] = - inv([Zt]) * [j] *sqrt(3) * [vdx] = ------------ * [ rt xt ] * [ 0 -1 ] * [vdx]
+ // [iby] [vdy] (rt² + xt²) [-xt rt ] [ 1 0 ] [vdy]
+
+ Matrix vdInit = mf.create(2, 1, 2);
+ vdInit.add(0, 0, initVx);
+ vdInit.add(1, 0, initVy);
+
+ Matrix jmSqrt3 = getMatrixByType(BlocType.J, -Math.sqrt(3), mf);
+ Matrix invZt = getInvZt(rt, xt, mf);
+
+ Matrix tmpjVd = jmSqrt3.times(vdInit);
+ Matrix mIb = invZt.times(tmpjVd);
+
+ // Compute the currents :
+ // [ Io ] [ 1 1 1 ] [ 0 ] [ 0 ]
+ // [ Id ] = 1/3 * [ 1 a a²] * [ Ib ] = 1/3 * Ib * [a - a²]
+ // [ Ii ] [ 1 a² a ] [-Ib ] [a²- a ]
+
+ // [Io] = 0
+ Matrix adiv3 = getMatrixByType(BlocType.A, 1. / 3., mf);
+ Matrix ma2div3 = getMatrixByType(BlocType.A2, -1. / 3, mf);
+ Matrix minusId = getMatrixByType(BlocType.Id, -1., mf);
+ Matrix aa2div3 = addMatrices22(adiv3.toDense(), ma2div3.toDense(), mf);
+
+ mId = aa2div3.times(mIb);
+ mIi = minusId.times(mId);
+ mIo = mf.create(2, 1, 2);
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/MonophasedShortCircuitCalculator.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/MonophasedShortCircuitCalculator.java
new file mode 100644
index 00000000..72d99963
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/MonophasedShortCircuitCalculator.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class MonophasedShortCircuitCalculator extends AbstractShortCircuitCalculator {
+
+ public MonophasedShortCircuitCalculator(double rdf, double xdf, double rof, double xof, double rg, double xg,
+ double initVx, double initVy, MatrixFactory mf) {
+ super(rdf, xdf, rof, xof, rg, xg, initVx, initVy, mf);
+
+ }
+
+ public void computeCurrents() {
+
+ //Description of the fault:
+ // a ---------------x------------------ by definition : Ia = Ib = 0
+ // b ---------------x------------------
+ // c ---------------+------------------ Vc = Zf * Ic
+ // |
+ // Zf
+ // |
+ // /////
+
+ //Problem to solve:
+ // Given the equalities above, we need to solve for V and I the following problem:
+ // [ Vof ] = -tM * inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = tM * [ V(init) ] - tM * inv(Yd) * M * [ Idf ]
+ // [ Vif ] = -tM * inv(Yd) * M * [ Iif ]
+ // Where:
+ // - Yo and Yd are the full network admittance matrices (zero and direct fortescue components)
+ // - M is the extraction matrix to get the subvectors V1, I1 of the full network vectors [V] and [I]
+ //
+ // Step 1: express the currents in fortescue basis :
+ //
+ // [ Io ] [ 1 1 1 ] [ 0 ] [ 1 ]
+ // [ Id ] = 1/3 * [ 1 a a²] * [ 0 ] = 1/3 * Ic * [ a²]
+ // [ Ii ] [ 1 a² a ] [ Ic ] [ a ]
+ //
+ // Step 2: get Ic1 :
+ // Given: Vc = a² * Vo + Vd + a * Vi and replacing it in Vc = Zf * Ic we get :
+ //
+ // a * tM * [Vinit]
+ // Ic = -----------------------------
+ // 1/3 * (Zof + 2 * Zdf) + Zf
+ //
+ // Where Zof and Zdf are complex impedance matrix elements :
+ // Zof = tM * inv(Yo) * M and Zdf = tM * inv(Yd) * M
+ //
+ // Step 3: compute the short circuit voltages:
+ // From computed Ic1 we get complex values : I1o, I1d, I1i, I2o, I2d, I2i using step 1 formulas expressed with Ic1
+ // Then compute the voltages from current values
+
+ // Complex expression of Ic :
+ // a * Vd(init) a * Vd(init)
+ // Ic = ----------------------------- = -----------------
+ // 1/3 * (Zof + 2 * Zdf) + Zf Zt
+
+ double rt = (2 * rdf + rof) / 3 + rg;
+ double xt = (2 * xdf + xof) / 3 + xg;
+
+ // [Zt] = [ rt -xt ]
+ // [ xt rt ]
+ //
+ // Cartesian expression of Ic using matrices :
+ // 1
+ // [icx] = inv([Zt]) * [a] * [vdx] = ------------ * [ rt xt ] * [ -1/2 -sqrt(3)/2 ] * [vdx]
+ // [icy] [vdy] (rt² + xt²) [-xt rt ] [ sqrt(3)/2 -1/2 ] [vdy]
+
+ Matrix vdInit = mf.create(2, 1, 2);
+ vdInit.add(0, 0, initVx);
+ vdInit.add(1, 0, initVy);
+
+ Matrix ma = getMatrixByType(BlocType.A, 1.0, mf);
+ Matrix ma2 = getMatrixByType(BlocType.A2, 1.0, mf);
+
+ Matrix invZt = getInvZt(rt, xt, mf);
+
+ Matrix tmpaVd = ma.times(vdInit);
+ Matrix mIc = invZt.times(tmpaVd);
+
+ System.out.println(" Vinit = " + initVx + " + j(" + initVy + ")");
+ System.out.println(" Ic = " + mIc.toDense().get(0, 0) + " + j(" + mIc.toDense().get(1, 0) + ")");
+ System.out.println(" Zo = " + rof + " + j(" + xof + ")");
+ System.out.println(" Zd = " + rdf + " + j(" + xdf + ")");
+
+ // TODO : check this is equivalent to :
+ //
+ // -rt*(vdxi + vdyi*sqrt(3)) + xt*(vdxi*sqrt(3)-vdyi)
+ //Icx = ----------------------------------------------------
+ // 2 * (rt² + xt²)
+
+ //double icx = (-rt * (v1dxInit + v1dyInit * Math.sqrt(3)) + xt*(v1dxInit * Math.sqrt(3) - v1dyInit)) / (2 * detZt);
+
+ //
+ // rt*(vdxi*sqrt(3) - vdyi) + xt*(vdxi+sqrt(3)*vdyi)
+ //Icy = ----------------------------------------------------
+ // 2 * (rt² + xt²)
+
+ //double icy = (-rt * (v1dxInit * Math.sqrt(3) - v1dyInit) + xt * (v1dxInit + v1dyInit * Math.sqrt(3))) / (2 * detZt);
+
+ Matrix mIdiv3 = getMatrixByType(BlocType.Id, 1. / 3., mf);
+
+ mIo = mIdiv3.times(mIc);
+ mId = ma2.times(mIo);
+ mIi = ma.times(mIo);
+
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/OpenShortCircuitProvider.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/OpenShortCircuitProvider.java
new file mode 100644
index 00000000..f673a698
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/OpenShortCircuitProvider.java
@@ -0,0 +1,170 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.google.auto.service.AutoService;
+import com.google.common.base.Stopwatch;
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.computation.ComputationManager;
+import com.powsybl.iidm.network.Bus;
+import com.powsybl.iidm.network.Network;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.loadflow.LoadFlowResult;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.math.matrix.SparseMatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import com.powsybl.security.LimitViolation;
+import com.powsybl.shortcircuit.*;
+import com.powsybl.shortcircuit.interceptors.ShortCircuitAnalysisInterceptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+@AutoService(ShortCircuitAnalysisProvider.class)
+public class OpenShortCircuitProvider implements ShortCircuitAnalysisProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(OpenShortCircuitProvider.class);
+
+ private final List interceptors = new ArrayList<>();
+
+ private final MatrixFactory matrixFactory;
+
+ public OpenShortCircuitProvider() {
+ this(new SparseMatrixFactory());
+ }
+
+ public OpenShortCircuitProvider(MatrixFactory matrixFactory) {
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ }
+
+ @Override
+ public void addInterceptor(ShortCircuitAnalysisInterceptor interceptor) {
+ interceptors.add(interceptor);
+ }
+
+ @Override
+ public boolean removeInterceptor(ShortCircuitAnalysisInterceptor interceptor) {
+ return interceptors.remove(interceptor);
+ }
+
+ @Override
+ public String getName() {
+ return "OpenShortCircuit";
+ }
+
+ @Override
+ public String getVersion() {
+ return "0.1";
+ }
+
+ @Override
+ public CompletableFuture run(Network network, List faults, ShortCircuitParameters parameters, ComputationManager computationManager, List faultParameters) {
+ //public CompletableFuture run(Network network, List faults, ShortCircuitParameters parameters, ComputationManager computationManager, List faultParameters, Reporter reporter) {
+
+ Objects.requireNonNull(network);
+ Objects.requireNonNull(parameters);
+ Stopwatch stopwatch = Stopwatch.createStarted();
+
+ LoadFlowParameters lfParameters = new LoadFlowParameters();
+ LoadFlow.Runner loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+
+ LoadFlowResult lfResult = loadFlowRunner.run(network, lfParameters);
+
+ List scList = new ArrayList<>();
+
+ // TODO : improve the handling of faults, for now we use this map to get the correspondence between short circuit provider and internal modelling of fault
+ Map scFaultToFault = new HashMap<>();
+
+ for (Fault fault : faults) {
+
+ if (fault.getType() == Fault.Type.BRANCH) {
+ LOGGER.warn("Short circuit of type BRANCH not yet supported, fault : " + fault.getId() + " is ignored");
+ continue;
+ }
+
+ if (fault.getFaultType() == Fault.FaultType.SINGLE_PHASE) {
+ LOGGER.warn(" Short circuit of type SINGLE_PHASE not yet supported, fault : " + fault.getId() + " is ignored");
+ continue;
+ }
+
+ // TODO : transform parallel input into a series input
+ if (fault.getConnectionType() == Fault.ConnectionType.PARALLEL) {
+ LOGGER.warn(" Short circuit connection of type PARALLEL not yet supported, fault : " + fault.getId() + " is ignored");
+ continue;
+ }
+
+ // TODO : see how to get lfBus from iidm Bus
+ String elementId = fault.getElementId();
+
+ double rFault = fault.getRToGround();
+ double xFault = fault.getXToGround();
+ Bus bus = network.getBusBreakerView().getBus(elementId);
+ String busId = bus.getId();
+ ShortCircuitFault sc = new ShortCircuitFault(busId, true, busId, rFault, xFault, ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ scList.add(sc);
+
+ // TODO improve:
+ scFaultToFault.put(sc, fault);
+
+ }
+
+ //Parameters that could be added in the short circuit provider API later:
+ // Voltage Profile
+ //ShortCircuitBalancedParameters.VoltageProfileType vp = ShortCircuitBalancedParameters.VoltageProfileType.CALCULATED;
+ ShortCircuitEngineParameters.VoltageProfileType vp = ShortCircuitEngineParameters.VoltageProfileType.NOMINAL;
+
+ // Selective or Systematic short circuit analysis
+ //ShortCircuitBalancedParameters.AnalysisType at = ShortCircuitBalancedParameters.AnalysisType.SYSTEMATIC;
+ ShortCircuitEngineParameters.AnalysisType at = ShortCircuitEngineParameters.AnalysisType.SELECTIVE;
+
+ // selection of the period of analysis
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.TRANSIENT;
+
+ AdditionalDataInfo additionalDataInfo = new AdditionalDataInfo(); //no extra data handled in the provider, we need to enrich the input API if necessary
+
+ LoadFlowParameters loadFlowParameters = new LoadFlowParameters();
+ ShortCircuitNormCourcirc shortCircuitNormCourcirc = new ShortCircuitNormCourcirc();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, at, scList, true, vp, false, periodType, additionalDataInfo, shortCircuitNormCourcirc);
+ ShortCircuitBalancedEngine scbEngine = new ShortCircuitBalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+
+ List frs = new ArrayList<>();
+ List lvs = new ArrayList<>();
+
+ // the results per faults might be inconsistent if many busses per voltage level
+ // TODO : see how this could be improved by allowing results per electrical bus on the short circuit provider
+ for (Map.Entry scResult : scbEngine.resultsPerFault.entrySet()) {
+ ShortCircuitFault scFault = scResult.getKey();
+ double ir = scResult.getValue().getIdx();
+ double ii = scResult.getValue().getIdy();
+ double icc = Math.sqrt(ir * ir + ii * ii);
+
+ Fault fault = scFaultToFault.get(scFault);
+
+ // TODO : put here additional results
+ List feederResults = new ArrayList<>();
+ List limitViolations = new ArrayList<>();
+ FortescueValue current = new FortescueValue(icc, 0.);
+
+ FaultResult fr = new FaultResult(fault, 0., feederResults, limitViolations, current);
+ frs.add(fr);
+ }
+
+ LOGGER.info("Short circuit calculation done in {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
+
+ return CompletableFuture.completedFuture(new ShortCircuitAnalysisResult(frs));
+ }
+
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBalancedEngine.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBalancedEngine.java
new file mode 100644
index 00000000..344b9193
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBalancedEngine.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.openloadflow.network.LfBus;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitBalancedEngine extends AbstractShortCircuitEngine {
+
+ public ShortCircuitBalancedEngine(Network network, ShortCircuitEngineParameters parameters) {
+ super(network, parameters);
+ }
+
+ @Override
+ public void run() { //can handle both selective and systematic analysis with one single matrix inversion
+
+ // building a contingency list with all voltage levels
+ // TODO : generate a list with busses
+ if (parameters.getAnalysisType() == ShortCircuitEngineParameters.AnalysisType.SYSTEMATIC) {
+ buildSystematicList(ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ }
+
+ solverFaultList = buildFaultListsFromInputs().getKey();
+
+ ImpedanceLinearResolutionParameters linearResolutionParameters = new ImpedanceLinearResolutionParameters(acLoadFlowParameters,
+ parameters.getMatrixFactory(), solverFaultList, parameters.isVoltageUpdate(), getAdmittanceVoltageProfileTypeFromParam(), getAdmittancePeriodTypeFromParam(), AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN,
+ parameters.isIgnoreShunts(), parameters.getAdditionalDataInfo());
+
+ ImpedanceLinearResolution directResolution = new ImpedanceLinearResolution(network, linearResolutionParameters);
+
+ directResolution.run();
+
+ //Build the ShortCircuit results using the Thevenin computation results
+ resultsPerFault = new LinkedHashMap<>();
+ processAdmittanceLinearResolutionResults(directResolution);
+
+ }
+
+ protected void processAdmittanceLinearResolutionResults(ImpedanceLinearResolution directResolution) {
+
+ for (ImpedanceLinearResolution.ImpedanceLinearResolutionResult linearResolutionResult : directResolution.results) {
+ LfBus bus = linearResolutionResult.getBus();
+
+ // For each contingency that matches the given bus of the linear resolution we compute:
+ // If = Eth / (Zth + Zf) gives:
+ //
+ // ethi*(xf+xth) + ethr*(rf+rth) + j*[ethi*(rf+rth) - ethr*(xf+xth)]
+ // If = --------------------------------------------------------------------
+ // (rf+rth)² + (xf+xth)²
+ //
+
+ // values that does not change for a given bus in input
+ double vxInit = linearResolutionResult.getEthr();
+ double vyInit = linearResolutionResult.getEthi();
+
+ double rth = linearResolutionResult.getRthz11();
+ double xth = linearResolutionResult.getXthz12();
+
+ for (CalculationLocation calculationLocation : solverFaultList) {
+ ShortCircuitFault scfe = (ShortCircuitFault) calculationLocation; // TODO : better check but calculationLocation must be a ShortCircuitFault
+ ShortCircuitFault scf = null;
+ if (bus.getId().equals(scfe.getLfBusInfo())) {
+ scf = scfe;
+ }
+
+ if (scf == null) {
+ continue;
+ }
+
+ double rf = scf.getZfr();
+ double xf = scf.getZfi();
+
+ double denom = (rf + rth) * (rf + rth) + (xf + xth) * (xf + xth);
+ double ifr = (vyInit * (xf + xth) + vxInit * (rf + rth)) / denom;
+ double ifi = (vyInit * (rf + rth) - vxInit * (xf + xth)) / denom;
+ // The post-fault voltage values at faulted bus are computed as follow :
+ // [Vr] = [Vr_init] - ifr * [e_dVr] + ifi * [e_dVi]
+ // [Vi] = [Vi_init] - ifr * [e_dVi] - ifi * [e_dVr]
+ double dvr = -ifr * linearResolutionResult.getEnBus().get(0, 0) + ifi * linearResolutionResult.getEnBus().get(1, 0);
+ double dvi = -ifr * linearResolutionResult.getEnBus().get(1, 0) - ifi * linearResolutionResult.getEnBus().get(0, 0);
+
+ ShortCircuitResult res = new ShortCircuitResult(scf, bus, ifr, ifi, rth, xth, vxInit, vyInit, dvr, dvi, parameters.getMatrixFactory(), linearResolutionResult.getEqSysFeeders(), parameters.getNorm());
+ if (parameters.voltageUpdate) {
+ //we get the lfNetwork to process the results
+ res.setLfNetwork(directResolution.lfNetworkResult);
+
+ res.setTrueVoltageProfileUpdate();
+ // The post-fault voltage values are computed as follow :
+ // [Vr] = [Vr_init] - ifr * [e_dVr] + ifi * [e_dVi]
+ // [Vi] = [Vi_init] - ifr * [e_dVi] - ifi * [e_dVr]
+ // we compute the delta values to be added to Vinit if we want the post-fault voltage :
+ int nbBusses = directResolution.lfNetworkResult.getBuses().size();
+ res.createEmptyFortescueVoltageVector(nbBusses);
+
+ for (Map.Entry vd : linearResolutionResult.getDv().entrySet()) {
+ int busNum = vd.getKey();
+ double edVr = vd.getValue().get(0, 0);
+ double edVi = vd.getValue().get(1, 0);
+ //System.out.println(" dVth(" + vdr.getKey() + ") = " + edVr + " + j(" + edVi + ")");
+ double deltaVr = -ifr * edVr + ifi * edVi;
+ double deltaVi = -ifr * edVi - ifi * edVr;
+
+ res.fillVoltageInFortescueVector(busNum, deltaVr, deltaVi);
+ }
+ }
+
+ res.updateFeedersResult(); // feeders are updated only if voltageUpdate is made
+ resultsPerFault.put(scf, res);
+ }
+ }
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitEngineParameters.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitEngineParameters.java
new file mode 100644
index 00000000..7b08d214
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitEngineParameters.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.math.matrix.MatrixFactory;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitEngineParameters {
+ public enum VoltageProfileType {
+ CALCULATED, // use the computed values at nodes to compute Zth and Eth
+ NOMINAL; // use the nominal voltage values at nodes to get Zth and Eth
+ }
+
+ public enum PeriodType {
+ SUB_TRANSIENT, //uses subTransient parameters x"d
+ TRANSIENT, //uses transient parameters x'd
+ STEADY_STATE;
+ }
+
+ public enum AnalysisType {
+ SELECTIVE, // short circuit analysis for List faults in input
+ SYSTEMATIC; // short circuit analysis for all busses of input grid
+ }
+
+ private final LoadFlowParameters loadFlowParameters;
+
+ private List shortCircuitFaults;
+
+ private final MatrixFactory matrixFactory;
+
+ private final VoltageProfileType vProfile;
+
+ private final boolean ignoreShunts;
+
+ private final AnalysisType analysisType;
+
+ public boolean voltageUpdate;
+
+ private AdditionalDataInfo additionalDataInfo;
+
+ private PeriodType periodType;
+
+ private ShortCircuitNorm norm;
+
+ public ShortCircuitEngineParameters(LoadFlowParameters loadFlowParameters, MatrixFactory matrixFactory, AnalysisType analysisType, List faults, boolean isVoltageExport, VoltageProfileType vProfile, boolean ignoreShunts, PeriodType periodType, AdditionalDataInfo additionalDataInfo, ShortCircuitNorm norm) {
+ this.loadFlowParameters = Objects.requireNonNull(loadFlowParameters);
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ this.shortCircuitFaults = Objects.requireNonNull(faults);
+ this.voltageUpdate = isVoltageExport;
+ this.ignoreShunts = ignoreShunts;
+ this.vProfile = vProfile;
+ this.analysisType = analysisType;
+ this.periodType = periodType;
+ this.additionalDataInfo = Objects.requireNonNull(additionalDataInfo);
+ this.norm = norm;
+ }
+
+ public LoadFlowParameters getLoadFlowParameters() {
+ return loadFlowParameters;
+ }
+
+ public List getShortCircuitFaults() {
+ return shortCircuitFaults;
+ }
+
+ public MatrixFactory getMatrixFactory() {
+ return matrixFactory;
+ }
+
+ public VoltageProfileType getVoltageProfileType() {
+ return vProfile;
+ }
+
+ public boolean isIgnoreShunts() {
+ return ignoreShunts;
+ }
+
+ public AnalysisType getAnalysisType() {
+ return analysisType;
+ }
+
+ public void setShortCircuitFaults(List faults) {
+ shortCircuitFaults = faults;
+ }
+
+ public AdditionalDataInfo getAdditionalDataInfo() {
+ return additionalDataInfo;
+ }
+
+ public PeriodType getPeriodType() {
+ return periodType;
+ }
+
+ public ShortCircuitNorm getNorm() {
+ return norm;
+ }
+
+ public boolean isVoltageUpdate() {
+ return voltageUpdate;
+ }
+
+ public void setVoltageUpdate(boolean bool) {
+ voltageUpdate = bool;
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitFault.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitFault.java
new file mode 100644
index 00000000..b7217f65
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitFault.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.incubator.simulator.util.CalculationLocation;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitFault extends CalculationLocation {
+
+ public ShortCircuitFault(String busLocation, boolean voltageUpdate, String faultId, double zfr, double zfi, ShortCircuitType type) {
+ super(busLocation, voltageUpdate);
+ this.zfr = zfr;
+ this.zfi = zfi;
+ this.type = type;
+ this.inputByBus = false;
+ this.faultId = faultId;
+ }
+
+ public ShortCircuitFault(String busLocation, String busLocationBiPhased, boolean voltageUpdate, String faultId, double zfr, double zfi, ShortCircuitType type, ShortCircuitBiphasedType biphasedType) {
+ super(busLocation, busLocationBiPhased, voltageUpdate);
+ this.zfr = zfr;
+ this.zfi = zfi;
+ this.type = type;
+ this.inputByBus = false;
+ this.faultId = faultId;
+ this.biphasedType = biphasedType;
+ }
+
+
+ public enum ShortCircuitType {
+ TRIPHASED_GROUND,
+ BIPHASED,
+ BIPHASED_GROUND,
+ BIPHASED_COMMON_SUPPORT,
+ MONOPHASED;
+ }
+
+ public enum ShortCircuitBiphasedType {
+ C1_C2,
+ C1_B2,
+ C1_A2;
+ }
+
+ // TODO : remove once input by bus is OK
+
+ private String faultId;
+
+ private boolean inputByBus; // true if input given by bus
+
+ private double zfr; //real part of the short circuit impedance Zf
+ private double zfi; //imaginary part of the short circuit impedance Zf
+
+ private ShortCircuitType type;
+
+ private ShortCircuitBiphasedType biphasedType;
+
+ public boolean isInputByBus() {
+ return inputByBus;
+ }
+
+ public ShortCircuitType getType() {
+ return type;
+ }
+
+ public double getZfr() {
+ return zfr;
+ }
+
+ public double getZfi() {
+ return zfi;
+ }
+
+ public ShortCircuitBiphasedType getBiphasedType() {
+ return biphasedType;
+ }
+
+ public String getFaultId() {
+ return faultId;
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNorm.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNorm.java
new file mode 100644
index 00000000..f202e76d
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNorm.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.ThreeWindingsTransformer;
+import com.powsybl.iidm.network.TwoWindingsTransformer;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitNorm {
+
+ public enum NormType {
+ NONE,
+ IEC,
+ RTE_COURCIRC;
+ }
+
+ ShortCircuitNorm() {
+
+ }
+
+ public double getCmaxVoltageFactor(double nominalVoltage) {
+ return 1.0;
+ }
+
+ public double getCminVoltageFactor(double nominalVoltage) {
+ return 1.0;
+ }
+
+ public double getKtT2W(TwoWindingsTransformer t2w) {
+ return 1.0;
+ }
+
+ public double getKtT3W(ThreeWindingsTransformer t3w, int numLeg) {
+ return 1.0;
+ }
+
+ public NormType getNormType() {
+ return NormType.NONE;
+ }
+
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNormCourcirc.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNormCourcirc.java
new file mode 100644
index 00000000..a280cdf4
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNormCourcirc.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitNormCourcirc extends ShortCircuitNorm {
+
+ public ShortCircuitNormCourcirc() {
+ super();
+ }
+
+ @Override
+ public double getCmaxVoltageFactor(double nominalVoltage) {
+ double cmax = 1.0;
+ return cmax;
+ }
+
+ @Override
+ public double getCminVoltageFactor(double nominalVoltage) {
+ double cmin = 1.0;
+ return cmin;
+ }
+
+ @Override
+ public NormType getNormType() {
+ return NormType.RTE_COURCIRC;
+ }
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNormIec.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNormIec.java
new file mode 100644
index 00000000..db164a21
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitNormIec.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.ThreeWindingsTransformer;
+import com.powsybl.iidm.network.TwoWindingsTransformer;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitNormIec extends ShortCircuitNorm {
+
+ public static final double LOW_VOLTAGE_KV_THRESHOLD = 1.;
+ public static final double MEDIUM_VOLTAGE_KV_THRESHOLD = 35.;
+
+ public static final double LOW_VOLTAGE_6PERCENT_CMAX = 1.05;
+ public static final double LOW_VOLTAGE_10PERCENT_CMAX = 1.10;
+ public static final double MEDIUM_VOLTAGE_CMAX = 1.10;
+ public static final double HIGH_VOLTAGE_MAX_CMAX = 1.10;
+
+ public static final double LOW_VOLTAGE_CMIN = 0.95;
+ public static final double MEDIUM_VOLTAGE_CMIN = 1.0;
+ public static final double HIGH_VOLTAGE_MAX_CMIN = 1.0;
+
+ public ShortCircuitNormIec() {
+ super();
+ }
+
+ @Override
+ public double getCmaxVoltageFactor(double nominalVoltage) {
+ double cmax = 1.0;
+ if (nominalVoltage <= LOW_VOLTAGE_KV_THRESHOLD) {
+ cmax = LOW_VOLTAGE_6PERCENT_CMAX; //TODO : make the distinction with 10% tolerance parameter
+ } else if (nominalVoltage <= MEDIUM_VOLTAGE_KV_THRESHOLD) {
+ cmax = MEDIUM_VOLTAGE_CMAX;
+ } else {
+ cmax = HIGH_VOLTAGE_MAX_CMAX;
+ }
+ return cmax;
+ }
+
+ @Override
+ public double getCminVoltageFactor(double nominalVoltage) {
+ double cmin = 1.0;
+ if (nominalVoltage <= LOW_VOLTAGE_KV_THRESHOLD) {
+ cmin = LOW_VOLTAGE_CMIN;
+ } else if (nominalVoltage <= MEDIUM_VOLTAGE_KV_THRESHOLD) {
+ cmin = MEDIUM_VOLTAGE_CMIN;
+ } else {
+ cmin = HIGH_VOLTAGE_MAX_CMIN;
+ }
+ return cmin;
+ }
+
+ @Override
+ public double getKtT2W(TwoWindingsTransformer t2w) {
+ double cmax = getCmaxVoltageFactor(t2w.getTerminal1().getVoltageLevel().getNominalV());
+ double ratedSt2w = t2w.getRatedS();
+ double ratedU2 = t2w.getRatedU2(); //TODO : check that the assumption to use ratedU2 is always correct
+ double xt2w = t2w.getX();
+
+ double kt = 0.95 * cmax / (1 + 0.6 * xt2w * ratedSt2w / (ratedU2 * ratedU2));
+
+ return kt;
+ }
+
+ @Override
+ public double getKtT3W(ThreeWindingsTransformer t3w, int numLeg) {
+
+ ThreeWindingsTransformer.Leg t3wLeg;
+ if (numLeg == 1) {
+ t3wLeg = t3w.getLeg1();
+ } else if (numLeg == 2) {
+ t3wLeg = t3w.getLeg2();
+ } else if (numLeg == 3) {
+ t3wLeg = t3w.getLeg3();
+ } else {
+ throw new IllegalArgumentException("Three Winding Transformer " + t3w.getId() + " input leg must be 1, 2 or 3 but was : " + numLeg);
+ }
+
+ double cmax = getCmaxVoltageFactor(t3wLeg.getTerminal().getVoltageLevel().getNominalV());
+ double ratedSt3w = t3wLeg.getRatedS();
+ double ratedU0 = t3w.getRatedU0(); // we suppose that all impedances are based on an impedance base (Sb_leg, U0)
+ double xt3w = t3wLeg.getX();
+
+ double kt = 0.95 * cmax / (1 + 0.6 * xt3w * ratedSt3w / (ratedU0 * ratedU0));
+
+ return kt;
+ }
+
+ @Override
+ public NormType getNormType() {
+ return NormType.IEC;
+ }
+
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitResult.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitResult.java
new file mode 100644
index 00000000..20d95c72
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitResult.java
@@ -0,0 +1,476 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfBus;
+import com.powsybl.openloadflow.network.LfNetwork;
+import com.powsybl.openloadflow.network.PiModel;
+
+import java.util.*;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitResult {
+
+ public class CommonSupportResult {
+
+ private LfBus lfBus2; // FIXME : might be wrongly overwritten in the "resultsPerFault" presentation
+
+ private double eth2x;
+
+ private double eth2y;
+
+ private DenseMatrix i2Fortescue; //fortescue vector of currents
+
+ private DenseMatrix v2Fortescue; //fortescue vector of voltages
+
+ CommonSupportResult(LfBus lfBus2, double eth2x, double eth2y,
+ double i2dx, double i2dy, double i2ox, double i2oy, double i2ix, double i2iy,
+ double dv2dx, double dv2dy, double dv2ox, double dv2oy, double dv2ix, double dv2iy) {
+ this.lfBus2 = lfBus2;
+ this.eth2x = eth2x;
+ this.eth2y = eth2y;
+
+ Matrix mI2 = matrixFactory.create(6, 1, 6);
+ mI2.add(0, 0, i2ox);
+ mI2.add(1, 0, i2oy);
+ mI2.add(2, 0, i2dx);
+ mI2.add(3, 0, i2dy);
+ mI2.add(4, 0, i2ix);
+ mI2.add(5, 0, i2iy);
+ this.i2Fortescue = mI2.toDense();
+
+ //construction of the fortescue vector vFortescue = t[Vh, Vd, Vi]
+ double vdx = eth2x + dv2dx;
+ double vdy = eth2y + dv2dy;
+ double vhx = dv2ox;
+ double vhy = dv2oy;
+ double vix = dv2ix;
+ double viy = dv2iy;
+
+ Matrix mV2 = matrixFactory.create(6, 1, 6);
+ mV2.add(0, 0, vhx);
+ mV2.add(1, 0, vhy);
+ mV2.add(2, 0, vdx);
+ mV2.add(3, 0, vdy);
+ mV2.add(4, 0, vix);
+ mV2.add(5, 0, viy);
+ this.v2Fortescue = mV2.toDense();
+ }
+ }
+
+ private final MatrixFactory matrixFactory;
+
+ private LfBus lfBus; // FIXME : might be wrongly overwritten in the "resultsPerFault" presentation
+
+ private LfNetwork lfNetwork;
+
+ private ShortCircuitNorm norm;
+
+ private double rd; // equivalent direct impedance
+
+ private double xd;
+
+ private double ri; // equivalent inverse impedance
+
+ private double xi;
+
+ private double rh; // equivalent homopolar impedance
+
+ private double xh;
+
+ private double ethx;
+
+ private double ethy;
+
+ private DenseMatrix iFortescue; //fortescue vector of currents
+
+ private DenseMatrix vFortescue; //fortescue vector of voltages
+
+ private boolean isVoltageProfileUpdated;
+ private List busNum2Dv;
+
+ private EquationSystemFeeders eqSysFeedersDirect;
+
+ private EquationSystemFeeders eqSysFeedersHomopolar;
+
+ private Map feedersAtBusResultsDirect;
+
+ private Map feedersAtBusResultsHomopolar;
+
+ private ShortCircuitFault shortCircuitFault;
+
+ private CommonSupportResult commonSupportResult; // used only for biphased with common support faults
+
+ public ShortCircuitResult(ShortCircuitFault shortCircuitFault, LfBus lfBus,
+ double ifr, double ifi,
+ double rth, double xth, double ethr, double ethi, double dvr, double dvi,
+ MatrixFactory matrixFactory, EquationSystemFeeders eqSysFeeders, ShortCircuitNorm norm) {
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ this.lfBus = lfBus;
+ this.eqSysFeedersDirect = eqSysFeeders;
+ this.shortCircuitFault = shortCircuitFault;
+ this.norm = norm;
+
+ this.rd = rth;
+ this.xd = xth;
+ this.ri = 0.;
+ this.xi = 0.;
+ this.rh = 0.;
+ this.xh = 0.;
+
+ this.ethx = ethr;
+ this.ethy = ethi;
+
+ //construction of the fortescue vector iFortescue = t[Ih, Id, Ii]
+ double idx = ifr;
+ double idy = ifi;
+ double iix = 0.;
+ double iiy = 0.;
+ double ihx = 0.;
+ double ihy = 0.;
+
+ Matrix mI = matrixFactory.create(6, 1, 6);
+ mI.add(0, 0, ihx);
+ mI.add(1, 0, ihy);
+ mI.add(2, 0, idx);
+ mI.add(3, 0, idy);
+ mI.add(4, 0, iix);
+ mI.add(5, 0, iiy);
+ this.iFortescue = mI.toDense();
+
+ //construction of the fortescue vector vFortescue = t[Vh, Vd, Vi]
+ double vdx = ethr + dvr;
+ double vdy = ethi + dvi;
+ double vhx = 0.;
+ double vhy = 0.;
+ double vix = 0.;
+ double viy = 0.;
+
+ Matrix mV = matrixFactory.create(6, 1, 6);
+ mV.add(0, 0, vhx);
+ mV.add(1, 0, vhy);
+ mV.add(2, 0, vdx);
+ mV.add(3, 0, vdy);
+ mV.add(4, 0, vix);
+ mV.add(5, 0, viy);
+ this.vFortescue = mV.toDense();
+
+ isVoltageProfileUpdated = false;
+
+ }
+
+ public ShortCircuitResult(ShortCircuitFault shortCircuitFault, LfBus lfBus,
+ double idx, double idy, double iox, double ioy, double iix, double iiy,
+ double rd, double xd, double ro, double xo, double ri, double xi,
+ double vdxinit, double vdyinit, double dvdx, double dvdy, double dvox, double dvoy, double dvix, double dviy,
+ MatrixFactory matrixFactory, EquationSystemFeeders eqSysFeedersDirect, EquationSystemFeeders eqSysFeedersHomopolar, ShortCircuitNorm norm) {
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ this.lfBus = lfBus;
+ this.eqSysFeedersDirect = eqSysFeedersDirect;
+ this.eqSysFeedersHomopolar = eqSysFeedersHomopolar;
+ this.shortCircuitFault = shortCircuitFault;
+ this.norm = norm;
+
+ this.rd = rd;
+ this.xd = xd;
+ this.ri = ri;
+ this.xi = xi;
+ this.rh = ro;
+ this.xh = xo;
+
+ this.ethx = vdxinit;
+ this.ethy = vdyinit;
+
+ //construction of the fortescue vector iFortescue = t[Ih, Id, Ii]
+ Matrix mI = matrixFactory.create(6, 1, 6);
+ mI.add(0, 0, iox);
+ mI.add(1, 0, ioy);
+ mI.add(2, 0, idx);
+ mI.add(3, 0, idy);
+ mI.add(4, 0, iix);
+ mI.add(5, 0, iiy);
+ this.iFortescue = mI.toDense();
+
+ //construction of the fortescue vector vFortescue = t[Vh, Vd, Vi]
+ double vdx = ethx + dvdx;
+ double vdy = ethy + dvdy;
+ double vhx = dvox;
+ double vhy = dvoy;
+ double vix = dvix;
+ double viy = dviy;
+
+ Matrix mV = matrixFactory.create(6, 1, 6);
+ mV.add(0, 0, vhx);
+ mV.add(1, 0, vhy);
+ mV.add(2, 0, vdx);
+ mV.add(3, 0, vdy);
+ mV.add(4, 0, vix);
+ mV.add(5, 0, viy);
+ this.vFortescue = mV.toDense();
+
+ isVoltageProfileUpdated = false;
+
+ }
+
+ public ShortCircuitResult(ShortCircuitFault shortCircuitFault, LfBus lfBus,
+ double idx, double idy, double iox, double ioy, double iix, double iiy,
+ double rd, double xd, double ro, double xo, double ri, double xi,
+ double vdxinit, double vdyinit, double dvdx, double dvdy, double dvox, double dvoy, double dvix, double dviy,
+ MatrixFactory matrixFactory, EquationSystemFeeders eqSysFeedersDirect, EquationSystemFeeders eqSysFeedersHomopolar, ShortCircuitNorm norm,
+ double i2dx, double i2dy, double i2ox, double i2oy, double i2ix, double i2iy,
+ double v2dxinit, double v2dyinit, double dv2dx, double dv2dy, double dv2ox, double dv2oy, double dv2ix, double dv2iy,
+ LfBus lfBus2) {
+ this(shortCircuitFault, lfBus,
+ idx, idy, iox, ioy, iix, iiy,
+ rd, xd, ro, xo, ri, xi,
+ vdxinit, vdyinit, dvdx, dvdy, dvox, dvoy, dvix, dviy,
+ matrixFactory, eqSysFeedersDirect, eqSysFeedersHomopolar, norm);
+
+ this.commonSupportResult = new CommonSupportResult(lfBus2, v2dxinit, v2dyinit,
+ i2dx, i2dy, i2ox, i2oy, i2ix, i2iy,
+ dv2dx, dv2dy, dv2ox, dv2oy, dv2ix, dv2iy);
+
+ }
+
+ public void updateFeedersResult() {
+ //System.out.println(" VL name = " + shortCircuitVoltageLevelLocation);
+ //System.out.println(" bus name = " + shortCircuitLfbusLocation);
+ //System.out.println(" Icc = " + getIcc());
+ //System.out.println(" Ih = " + iFortescue.get(0, 0) + " + j(" + iFortescue.get(1, 0) + ")");
+ //System.out.println(" Id = " + iFortescue.get(2, 0) + " + j(" + iFortescue.get(3, 0) + ")");
+ //System.out.println(" Ii = " + iFortescue.get(4, 0) + " + j(" + iFortescue.get(5, 0) + ")");
+ //System.out.println(" Vh = " + vFortescue.get(0, 0) + " + j(" + vFortescue.get(1, 0) + ")");
+ //System.out.println(" Vd = " + vFortescue.get(2, 0) + " + j(" + vFortescue.get(3, 0) + ")");
+ //System.out.println(" Vi = " + vFortescue.get(4, 0) + " + j(" + vFortescue.get(5, 0) + ")");
+ //System.out.println(" Eth = " + ethx + " + j(" + ethy + ")");
+
+ if (isVoltageProfileUpdated) {
+
+ /*for (Map.Entry vd : bus2dv.entrySet()) {
+ System.out.println(" dVd(" + vd.getKey() + ") = " + vd.getValue().get(2, 0) + " + j(" + vd.getValue().get(3, 0) + ")");
+ System.out.println(" dVo(" + vd.getKey() + ") = " + vd.getValue().get(0, 0) + " + j(" + vd.getValue().get(1, 0) + ")");
+ System.out.println(" dVi(" + vd.getKey() + ") = " + vd.getValue().get(4, 0) + " + j(" + vd.getValue().get(5, 0) + ")");
+ }*/
+
+ feedersAtBusResultsDirect = new HashMap<>(); // TODO : homopolar
+
+ for (LfBus bus : lfNetwork.getBuses()) {
+ //int busNum = bus.getNum();
+ //double dvx = busNum2Dv.get(busNum).get(2, 0);
+ //double dvy = busNum2Dv.get(busNum).get(3, 0);
+ //double vx = dvx + ethx;
+ //double vy = dvy + ethy;
+
+ //System.out.println(" dVd(" + bus.getId() + ") = " + dvx + " + j(" + dvy + ") Module = " + bus.getNominalV() * Math.sqrt(vx * vx + vy * vy));
+ //System.out.println(" dVo(" + bus.getId() + ") = " + bus2dv.get(busNum).get(0, 0) + " + j(" + bus2dv.get(busNum).get(1, 0) + ")");
+ //System.out.println(" dVi(" + bus.getId() + ") = " + bus2dv.get(busNum).get(4, 0) + " + j(" + bus2dv.get(busNum).get(5, 0) + ")");
+
+ // Init of feeder results
+ EquationSystemBusFeeders busFeeders = eqSysFeedersDirect.busToFeeders.get(bus);
+ EquationSystemBusFeedersResult resultBusFeeders = new EquationSystemBusFeedersResult(busFeeders.getFeeders(), bus);
+ feedersAtBusResultsDirect.put(bus, resultBusFeeders); // TODO : homopolar
+
+ }
+
+ for (LfBranch branch : lfNetwork.getBranches()) {
+ LfBus bus1 = branch.getBus1();
+ LfBus bus2 = branch.getBus2();
+ if (bus1 != null && bus2 != null) {
+ DenseMatrix yd12 = getAdmittanceMatrixBranch(branch, bus1, bus2, matrixFactory, AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN);
+ int busNum1 = bus1.getNum();
+ double dvx1 = busNum2Dv.get(busNum1).get(2, 0);
+ double dvy1 = busNum2Dv.get(busNum1).get(3, 0);
+ int busNum2 = bus2.getNum();
+ double dvx2 = busNum2Dv.get(busNum2).get(2, 0);
+ double dvy2 = busNum2Dv.get(busNum2).get(3, 0);
+ DenseMatrix v12 = matrixFactory.create(4, 1, 4).toDense();
+ v12.add(0, 0, dvx1 + 0.); //TODO : replace 1. by initial value
+ v12.add(1, 0, dvy1 + 0.); //TODO : replace 0. by initial value
+ v12.add(2, 0, dvx2 + 0.); //TODO : replace 1. by initial value
+ v12.add(3, 0, dvy2 + 0.); //TODO : replace 0. by initial value
+ DenseMatrix i12 = yd12.times(v12).toDense();
+ //System.out.println(" dI1d(" + branch.getId() + ") = " + i12.get(0, 0) + " + j(" + i12.get(1, 0) + ") Module I1d = " + 1000. * 100. / bus1.getNominalV() * Math.sqrt((i12.get(0, 0) * i12.get(0, 0) + i12.get(1, 0) * i12.get(1, 0)) / 3));
+ //System.out.println(" dI2d(" + branch.getId() + ") = " + i12.get(2, 0) + " + j(" + i12.get(3, 0) + ") Module I2d = " + 1000. * 100. / bus2.getNominalV() * Math.sqrt((i12.get(2, 0) * i12.get(2, 0) + i12.get(3, 0) * i12.get(3, 0)) / 3));
+
+ // Feeders :
+ // compute the sum of currents from branches at each bus
+ EquationSystemBusFeedersResult resultBus1Feeders = feedersAtBusResultsDirect.get(bus1); // TODO : homopolar
+ EquationSystemBusFeedersResult resultBus2Feeders = feedersAtBusResultsDirect.get(bus2); // TODO : homopolar
+
+ resultBus1Feeders.addIfeeders(i12.get(0, 0), i12.get(1, 0));
+ resultBus2Feeders.addIfeeders(i12.get(2, 0), i12.get(3, 0));
+
+ }
+ }
+
+ // computing feeders contribution
+ for (LfBus bus : lfNetwork.getBuses()) {
+ EquationSystemBusFeedersResult busFeeders = feedersAtBusResultsDirect.get(bus); // TODO : homopolar
+ busFeeders.updateContributions();
+ }
+ }
+ }
+
+ public double getIdx() {
+ return iFortescue.get(2, 0);
+ }
+
+ public double getIdy() {
+ return iFortescue.get(3, 0);
+ }
+
+ public double getIox() {
+ return iFortescue.get(0, 0);
+ }
+
+ public double getIoy() {
+ return iFortescue.get(1, 0);
+ }
+
+ public double getIcc() {
+ // Icc = 1/sqrt(3) * Eth(pu) / Zth(pu) * SB(MVA) * 10e6 / (VB(kV) * 10e3)
+ //return Math.sqrt((getIdx() * getIdx() + getIdy() * getIdy()) / 3) * 1000. * 100. / lfBus.getNominalV();
+ return Math.sqrt((getIdx() * getIdx() + getIdy() * getIdy()) / 3) * 1000. * 100.;
+ }
+
+ public double getIk() {
+ // Ik = c * Un / (sqrt(3) * Zk) = c / sqrt(3) * Eth(pu) / Zth(pu) * Sb / Vb
+ return Math.sqrt((getIdx() * getIdx() + getIdy() * getIdy()) / 3) * 100. / lfBus.getNominalV() * norm.getCmaxVoltageFactor(lfBus.getNominalV());
+ }
+
+ public LfBus getLfBus() {
+ return lfBus;
+ }
+
+ public double getPcc() {
+ //Pcc = |Eth|*Icc*sqrt(3)
+ return Math.sqrt(3) * getIcc() * lfBus.getV() * lfBus.getNominalV(); //TODO: check formula
+ }
+
+ public void setTrueVoltageProfileUpdate() {
+ isVoltageProfileUpdated = true;
+ }
+
+ public void createEmptyFortescueVoltageVector(int nbBusses) {
+ List busNum2Dv = new ArrayList<>();
+ for (int i = 0; i < nbBusses; i++) {
+ DenseMatrix mdV = matrixFactory.create(6, 1, 6).toDense();
+ busNum2Dv.add(mdV);
+ }
+ this.busNum2Dv = busNum2Dv;
+ }
+
+ public void fillVoltageInFortescueVector(int busNum, double dVdx, double dVdy) {
+ this.busNum2Dv.get(busNum).add(2, 0, dVdx);
+ this.busNum2Dv.get(busNum).add(3, 0, dVdy);
+ }
+
+ public void fillVoltageInFortescueVector(int busNum, double dVdx, double dVdy, double dVox, double dVoy, double dVix, double dViy) {
+ this.busNum2Dv.get(busNum).add(0, 0, dVox);
+ this.busNum2Dv.get(busNum).add(1, 0, dVoy);
+ this.busNum2Dv.get(busNum).add(2, 0, dVdx);
+ this.busNum2Dv.get(busNum).add(3, 0, dVdy);
+ this.busNum2Dv.get(busNum).add(4, 0, dVix);
+ this.busNum2Dv.get(busNum).add(5, 0, dViy);
+ }
+
+ public void setLfNetwork(LfNetwork lfNetwork) {
+ this.lfNetwork = lfNetwork;
+ }
+
+ static DenseMatrix getAdmittanceMatrixBranch(LfBranch branch, LfBus bus1, LfBus bus2, MatrixFactory matrixFactory,
+ AdmittanceEquationSystem.AdmittanceType admittanceType) {
+
+ // TODO : code duplicated with the admittance equation system, should be un-duplicated
+ PiModel piModel = branch.getPiModel();
+ if (piModel.getX() == 0) {
+ throw new IllegalArgumentException("Branch '" + branch.getId() + "' has reactance equal to zero");
+ }
+ double rho = piModel.getR1();
+ if (piModel.getZ() == 0) {
+ throw new IllegalArgumentException("Branch '" + branch.getId() + "' has Z equal to zero");
+ }
+ double zInvSquare = 1 / (piModel.getZ() * piModel.getZ());
+ double r = piModel.getR();
+ double x = piModel.getX();
+ double alpha = piModel.getA1();
+ double cosA = Math.cos(Math.toRadians(alpha));
+ double sinA = Math.sin(Math.toRadians(alpha));
+ double gPi1 = piModel.getG1();
+ double bPi1 = piModel.getB1();
+ double gPi2 = piModel.getG2();
+ double bPi2 = piModel.getB2();
+
+ double g12 = rho * zInvSquare * (r * cosA + x * sinA);
+ double b12 = -rho * zInvSquare * (x * cosA + r * sinA);
+ double g1g12sum = rho * rho * (gPi1 + r * zInvSquare);
+ double b1b12sum = rho * rho * (bPi1 - x * zInvSquare);
+ if (admittanceType == AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ g12 = g12 * AdmittanceConstants.COEF_XO_XD; // Xo = 3 * Xd as a first approximation : TODO : improve when more data available
+ b12 = b12 * AdmittanceConstants.COEF_XO_XD;
+ g1g12sum = g1g12sum * AdmittanceConstants.COEF_XO_XD;
+ b1b12sum = b1b12sum * AdmittanceConstants.COEF_XO_XD;
+ }
+
+ double g21 = rho * zInvSquare * (r * cosA + x * sinA);
+ double b21 = rho * zInvSquare * (r * sinA - x * cosA);
+ double g2g21sum = r * zInvSquare + gPi2;
+ double b2b21sum = -x * zInvSquare + bPi2;
+ if (admittanceType == AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ g21 = g21 * AdmittanceConstants.COEF_XO_XD; // Xo = 3 * Xd as a first approximation : TODO : improve when more data available
+ b21 = b21 * AdmittanceConstants.COEF_XO_XD;
+ g2g21sum = g2g21sum * AdmittanceConstants.COEF_XO_XD;
+ b2b21sum = b2b21sum * AdmittanceConstants.COEF_XO_XD;
+ }
+
+ DenseMatrix mAdmittance = matrixFactory.create(4, 4, 16).toDense();
+ mAdmittance.add(0, 0, g1g12sum);
+ mAdmittance.add(0, 1, -b1b12sum);
+ mAdmittance.add(0, 2, -g12);
+ mAdmittance.add(0, 3, b12);
+ mAdmittance.add(1, 0, b1b12sum);
+ mAdmittance.add(1, 1, g1g12sum);
+ mAdmittance.add(1, 2, -b12);
+ mAdmittance.add(1, 3, -g12);
+ mAdmittance.add(2, 0, -g21);
+ mAdmittance.add(2, 1, b21);
+ mAdmittance.add(2, 2, g2g21sum);
+ mAdmittance.add(2, 3, -b2b21sum);
+ mAdmittance.add(3, 0, -b21);
+ mAdmittance.add(3, 1, -g21);
+ mAdmittance.add(3, 2, b2b21sum);
+ mAdmittance.add(3, 3, g2g21sum);
+
+ return mAdmittance.toDense();
+
+ }
+
+ // used for tests
+ public double getIxFeeder(String busId, String feederId) {
+ double ix = 0.;
+ for (LfBus bus : lfNetwork.getBuses()) {
+ if (bus.getId().equals(busId)) {
+ EquationSystemBusFeedersResult resultFeeder = feedersAtBusResultsDirect.get(bus); // TODO : homopolar
+ List busFeedersResults = resultFeeder.getBusFeedersResults();
+ for (EquationSystemResultFeeder feeder : busFeedersResults) {
+ if (feeder.getId().equals(feederId)) {
+ ix = feeder.getIxContribution();
+ }
+ }
+ }
+ }
+ return ix;
+ }
+
+}
diff --git a/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitUnbalancedEngine.java b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitUnbalancedEngine.java
new file mode 100644
index 00000000..5149af4f
--- /dev/null
+++ b/simulator/short-circuit/src/main/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitUnbalancedEngine.java
@@ -0,0 +1,419 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+//import com.powsybl.math.matrix.DenseMatrix;
+
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.network.LfBus;
+import org.apache.commons.math3.util.Pair;
+
+import java.util.*;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitUnbalancedEngine extends AbstractShortCircuitEngine {
+
+ public ShortCircuitUnbalancedEngine(Network network, ShortCircuitEngineParameters parameters) {
+ super(network, parameters);
+ }
+
+ @Override
+ public void run() {
+
+ if (parameters.getAnalysisType() == ShortCircuitEngineParameters.AnalysisType.SYSTEMATIC) {
+ buildSystematicList(ShortCircuitFault.ShortCircuitType.MONOPHASED); // TODO : by default it is monophased, could be changed to choose type of systematic default
+ // Biphased common support faults will not be supported yet in systematic
+ }
+
+ // We handle a pre-treatement of faults given in input:
+ // - filtering of some inconsistencies on the bus identification
+ // - addition of info in each fault to ease the identification in LfNetwork of iidm info
+ Pair, List> faultLists = buildFaultListsFromInputs();
+
+ solverFaultList = faultLists.getKey();
+ solverBiphasedFaultList = faultLists.getValue();
+
+ ImpedanceLinearResolutionParameters admittanceLinearResolutionParametersHomopolar = new ImpedanceLinearResolutionParameters(acLoadFlowParameters,
+ parameters.getMatrixFactory(), solverFaultList, parameters.isVoltageUpdate(),
+ getAdmittanceVoltageProfileTypeFromParam(), getAdmittancePeriodTypeFromParam(), AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR,
+ parameters.isIgnoreShunts(), parameters.getAdditionalDataInfo(), solverBiphasedFaultList);
+
+ ImpedanceLinearResolutionParameters admittanceLinearResolutionParametersDirect = new ImpedanceLinearResolutionParameters(acLoadFlowParameters,
+ parameters.getMatrixFactory(), solverFaultList, parameters.isVoltageUpdate(),
+ getAdmittanceVoltageProfileTypeFromParam(), getAdmittancePeriodTypeFromParam(), AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN,
+ parameters.isIgnoreShunts(), parameters.getAdditionalDataInfo(), solverBiphasedFaultList);
+
+ ImpedanceLinearResolution directResolution = new ImpedanceLinearResolution(network, admittanceLinearResolutionParametersDirect);
+ ImpedanceLinearResolution homopolarResolution = new ImpedanceLinearResolution(network, admittanceLinearResolutionParametersHomopolar);
+
+ directResolution.run();
+ homopolarResolution.run();
+
+ //Build the ShortCircuit results using the linear resolution computation results
+ resultsPerFault = new LinkedHashMap<>();
+ processAdmittanceLinearResolutionResults(directResolution, homopolarResolution, ShortCircuitFault.ShortCircuitType.MONOPHASED);
+ processAdmittanceLinearResolutionResults(directResolution, homopolarResolution, ShortCircuitFault.ShortCircuitType.BIPHASED);
+ processAdmittanceLinearResolutionResults(directResolution, homopolarResolution, ShortCircuitFault.ShortCircuitType.BIPHASED_GROUND);
+ processAdmittanceLinearResolutionResults(directResolution, homopolarResolution, ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT);
+ }
+
+ public void processAdmittanceLinearResolutionResults(ImpedanceLinearResolution directResolution, ImpedanceLinearResolution homopolarResolution, ShortCircuitFault.ShortCircuitType shortCircuitType) {
+
+ int numResult = 0;
+ for (ImpedanceLinearResolution.ImpedanceLinearResolutionResult directResult : directResolution.results) {
+
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult homopolarResult = homopolarResolution.results.get(numResult);
+ numResult++;
+
+ LfBus lfBus1 = directResult.getBus();
+
+ List matchingFaults = new ArrayList<>();
+
+ if (shortCircuitType == ShortCircuitFault.ShortCircuitType.MONOPHASED
+ || shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED
+ || shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED_GROUND) {
+ for (CalculationLocation calculationLocation : solverFaultList) {
+ ShortCircuitFault scfe = (ShortCircuitFault) calculationLocation; // TODO : better check but calculationLocation must be a ShortCircuitFault
+ if (lfBus1.getId().equals(scfe.getLfBusInfo()) && scfe.getType() == shortCircuitType) {
+ matchingFaults.add(scfe);
+ }
+ }
+ }
+
+ if (shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT) {
+ for (CalculationLocation calculationLocation : solverBiphasedFaultList) {
+ ShortCircuitFault scfe = (ShortCircuitFault) calculationLocation; // TODO : better check but calculationLocation must be a ShortCircuitFault
+ if (lfBus1.getId().equals(scfe.getLfBusInfo()) && scfe.getType() == shortCircuitType) {
+ matchingFaults.add(scfe);
+ }
+ }
+ }
+
+ double v1dxInit = directResult.getEthr();
+ double v1dyInit = directResult.getEthi();
+
+ double rdf = directResult.getRthz11();
+ double xdf = directResult.getXthz12();
+
+ double rof = homopolarResult.getRthz11();
+ double xof = homopolarResult.getXthz12();
+
+ for (ShortCircuitFault scf : matchingFaults) {
+
+ double rf = scf.getZfr();
+ double xf = scf.getZfi();
+
+ MatrixFactory mf = parameters.getMatrixFactory();
+
+ Matrix mIo = mf.create(2, 1, 2);
+ Matrix mId = mf.create(2, 1, 2);
+ Matrix mIi = mf.create(2, 1, 2);
+
+ ShortCircuitResult res;
+
+ if (shortCircuitType == ShortCircuitFault.ShortCircuitType.MONOPHASED
+ || shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED
+ || shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED_GROUND) {
+ if (shortCircuitType == ShortCircuitFault.ShortCircuitType.MONOPHASED) {
+ MonophasedShortCircuitCalculator monophasedCalculator = new MonophasedShortCircuitCalculator(rdf, xdf, rof, xof, rf, xf, v1dxInit, v1dyInit, mf);
+ monophasedCalculator.computeCurrents();
+
+ mIo = monophasedCalculator.getmIo();
+ mId = monophasedCalculator.getmId();
+ mIi = monophasedCalculator.getmIi();
+
+ } else if (shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED) {
+ BiphasedShortCircuitCalculator biphasedCalculator = new BiphasedShortCircuitCalculator(rdf, xdf, rof, xof, rf, xf, v1dxInit, v1dyInit, mf);
+ biphasedCalculator.computeCurrents();
+
+ mIo = biphasedCalculator.getmIo();
+ mId = biphasedCalculator.getmId();
+ mIi = biphasedCalculator.getmIi();
+ } else if (shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED_GROUND) {
+ BiphasedGroundShortCircuitCalculator biphasedGrCalculator = new BiphasedGroundShortCircuitCalculator(rdf, xdf, rof, xof, rf, xf, v1dxInit, v1dyInit, mf);
+ biphasedGrCalculator.computeCurrents();
+
+ mIo = biphasedGrCalculator.getmIo();
+ mId = biphasedGrCalculator.getmId();
+ mIi = biphasedGrCalculator.getmIi();
+ }
+
+ res = buildUnbalancedResult(mId, mIo, mIi, rdf, xdf, rof, xof, mf,
+ directResult, homopolarResult,
+ scf, lfBus1, v1dxInit, v1dyInit, directResolution);
+
+ } else if (shortCircuitType == ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT) {
+ // TODO : We only handle the first biphased of the list for now, check how to handle this in the final version
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult.ImpedanceLinearResolutionResultBiphased biphasedDirectResult = directResult.getBiphasedResultsAtBus().get(0);
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult.ImpedanceLinearResolutionResultBiphased biphasedHomopolarResult = homopolarResult.getBiphasedResultsAtBus().get(0);
+
+ double ro12 = biphasedHomopolarResult.getZ12txx(); // TODO : add some tests to check consistency with Z12tyy and Z12tyx
+ double xo12 = -biphasedHomopolarResult.getZ12txy();
+ double ro22 = biphasedHomopolarResult.getZ22txx();
+ double xo22 = -biphasedHomopolarResult.getZ22txy();
+ double ro21 = biphasedHomopolarResult.getZ21txx();
+ double xo21 = -biphasedHomopolarResult.getZ21txy();
+
+ double rd12 = biphasedDirectResult.getZ12txx();
+ double xd12 = -biphasedDirectResult.getZ12txy();
+ double rd22 = biphasedDirectResult.getZ22txx();
+ double xd22 = -biphasedDirectResult.getZ22txy();
+ double rd21 = biphasedDirectResult.getZ21txx();
+ double xd21 = -biphasedDirectResult.getZ21txy();
+
+ BiphasedCommonSupportShortCircuitCalculator biphasedCommonCalculator;
+ if (scf.getBiphasedType() == ShortCircuitFault.ShortCircuitBiphasedType.C1_A2) {
+ biphasedCommonCalculator = new BiphasedC1A2Calculator(rdf, xdf, rof, xof, rf, xf, v1dxInit, v1dyInit, mf,
+ biphasedDirectResult.getV2x(), biphasedDirectResult.getV2y(),
+ ro12, xo12, ro22, xo22, ro21, xo21,
+ rd12, xd12, rd22, xd22, rd21, xd21);
+ } else if (scf.getBiphasedType() == ShortCircuitFault.ShortCircuitBiphasedType.C1_B2) {
+ biphasedCommonCalculator = new BiphasedC1B2Calculator(rdf, xdf, rof, xof, rf, xf, v1dxInit, v1dyInit, mf,
+ biphasedDirectResult.getV2x(), biphasedDirectResult.getV2y(),
+ ro12, xo12, ro22, xo22, ro21, xo21,
+ rd12, xd12, rd22, xd22, rd21, xd21);
+ } else if (scf.getBiphasedType() == ShortCircuitFault.ShortCircuitBiphasedType.C1_C2) {
+ biphasedCommonCalculator = new BiphasedC1C2Calculator(rdf, xdf, rof, xof, rf, xf, v1dxInit, v1dyInit, mf,
+ biphasedDirectResult.getV2x(), biphasedDirectResult.getV2y(),
+ ro12, xo12, ro22, xo22, ro21, xo21,
+ rd12, xd12, rd22, xd22, rd21, xd21);
+ } else {
+ throw new IllegalArgumentException(" short circuit fault of type : " + scf.getBiphasedType() + " not yet handled");
+ }
+
+ //biphasedCommonCalculator.computeCurrents();
+ mIo = biphasedCommonCalculator.getmIo();
+ mId = biphasedCommonCalculator.getmId();
+ mIi = biphasedCommonCalculator.getmIi();
+
+ // TODO : check if we need to make a separate function to handle biphased common support
+ Matrix mI2o = biphasedCommonCalculator.getmI2o();
+ Matrix mI2d = biphasedCommonCalculator.getmI2d();
+ Matrix mI2i = biphasedCommonCalculator.getmI2i();
+
+ //biphasedCommonCalculator.computeVoltages();
+ Matrix mdVo = biphasedCommonCalculator.getmVo(); // Contains variations of voltages, without Vinit
+ Matrix mdVd = biphasedCommonCalculator.getmVd(); // each voltage vector contains [V1x; V1y; V2x; V2y]
+ Matrix mdVi = biphasedCommonCalculator.getmVi();
+
+ LfBus lfBus2 = biphasedDirectResult.getBus2();
+
+ double v2dxInit = biphasedDirectResult.getV2x();
+ double v2dyInit = biphasedDirectResult.getV2y();
+
+ res = buildUnbalancedCommunSuppportResult(mId, mIo, mIi, mI2d, mI2o, mI2i, mdVd, mdVo, mdVi, rdf, xdf, rof, xof, mf,
+ directResult, homopolarResult, scf,
+ lfBus1, v1dxInit, v1dyInit, directResolution,
+ lfBus2, v2dxInit, v2dyInit, biphasedDirectResult, biphasedHomopolarResult);
+
+ } else {
+ throw new IllegalArgumentException(" Post-processing of short circuit type = " + shortCircuitType + "not yet implemented");
+ }
+
+ res.updateFeedersResult(); // feeders are updated only if voltageUpdate is made. TODO : see if update of homopolar feeders are to be updated
+ resultsPerFault.put(scf, res);
+ }
+
+ }
+ }
+
+ public ShortCircuitResult buildUnbalancedResult(Matrix mId, Matrix mIo, Matrix mIi, double rdf, double xdf, double rof, double xof, MatrixFactory mf,
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult directResult,
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult homopolarResult,
+ ShortCircuitFault scf, LfBus lfBus1, double v1dxInit, double v1dyInit, ImpedanceLinearResolution directResolution) {
+ //get the voltage vectors
+ // Vo :
+ // [vox] [ rof -xof ] [ iox ]
+ // [voy] = - [ xof rof ] * [ ioy ]
+
+ Matrix zof = getZ(rof, xof, mf);
+ Matrix zdf = getZ(rdf, xdf, mf);
+
+ Matrix minusVo = zof.times(mIo);
+ Matrix minusVd = zdf.times(mId);
+ Matrix minusVi = zdf.times(mIi);
+
+ //record the results
+ EquationSystemFeeders equationSystemFeedersDirect = directResult.getEqSysFeeders();
+ EquationSystemFeeders equationSystemFeedersHomopolar = homopolarResult.getEqSysFeeders();
+
+ ShortCircuitResult res = new ShortCircuitResult(scf, lfBus1,
+ mId.toDense().get(0, 0), mId.toDense().get(1, 0),
+ mIo.toDense().get(0, 0), mIo.toDense().get(1, 0),
+ mIi.toDense().get(0, 0), mIi.toDense().get(1, 0),
+ rdf, xdf, rof, xof, rdf, xdf,
+ v1dxInit, v1dyInit,
+ -minusVd.toDense().get(0, 0), -minusVd.toDense().get(1, 0),
+ -minusVo.toDense().get(0, 0), -minusVo.toDense().get(1, 0),
+ -minusVi.toDense().get(0, 0), -minusVi.toDense().get(1, 0),
+ mf, equationSystemFeedersDirect, equationSystemFeedersHomopolar, parameters.getNorm());
+
+ if (parameters.voltageUpdate) {
+ res.setLfNetwork(directResolution.lfNetworkResult);
+ res.setTrueVoltageProfileUpdate();
+ // The post-fault voltage values for the network busses are computed as follow :
+ // [ Vof ] = -inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = -inv(Yd) * M * [ Idf ] + [ V(init) ]
+ // [ Vif ] = -inv(Yd) * M * [ Iif ]
+ // dMo = inv(Yo) * M
+ // dMd = inv(Yd) * M
+
+ int nbBusses = directResolution.lfNetworkResult.getBuses().size();
+ res.createEmptyFortescueVoltageVector(nbBusses);
+
+ for (Map.Entry vd : directResult.getDv().entrySet()) {
+ int busNum = vd.getKey();
+
+ //direct
+ double edVr = vd.getValue().get(0, 0);
+ double edVi = vd.getValue().get(1, 0);
+
+ double idr = -mId.toDense().get(0, 0);
+ double idi = -mId.toDense().get(1, 0);
+
+ double deltaVdr = -idr * edVr + idi * edVi;
+ double deltaVdi = -idr * edVi - idi * edVr;
+
+ //inverse
+ double iir = -mIi.toDense().get(0, 0);
+ double iii = -mIi.toDense().get(1, 0);
+
+ double deltaVir = -iir * edVr + iii * edVi;
+ double deltaVii = -iir * edVi - iii * edVr;
+
+ //homopolar
+ double eoVr = homopolarResult.getDv().get(busNum).get(0, 0);
+ double eoVi = homopolarResult.getDv().get(busNum).get(1, 0);
+
+ double ior = -mIo.toDense().get(0, 0);
+ double ioi = -mIo.toDense().get(1, 0);
+
+ double deltaVor = -ior * eoVr + ioi * eoVi;
+ double deltaVoi = -ior * eoVi - ioi * eoVr;
+
+ //System.out.println(" dVth(" + vdr.getKey() + ") = " + edVr + " + j(" + edVi + ")");
+
+ res.fillVoltageInFortescueVector(busNum, deltaVdr, deltaVdi, deltaVor, deltaVoi, deltaVir, deltaVii);
+ }
+ }
+
+ return res;
+ }
+
+ public ShortCircuitResult buildUnbalancedCommunSuppportResult(Matrix mId, Matrix mIo, Matrix mIi, Matrix mI2d, Matrix mI2o, Matrix mI2i, Matrix mVd, Matrix mVo, Matrix mVi, double rdf, double xdf, double rof, double xof, MatrixFactory mf,
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult directResult,
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult homopolarResult, ShortCircuitFault scf,
+ LfBus lfBus1, double v1dxInit, double v1dyInit, ImpedanceLinearResolution directResolution,
+ LfBus lfBus2, double v2dxInit, double v2dyInit,
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult.ImpedanceLinearResolutionResultBiphased biphasedDirectResult,
+ ImpedanceLinearResolution.ImpedanceLinearResolutionResult.ImpedanceLinearResolutionResultBiphased biphasedHomopolarResult) {
+
+ //record the results
+ EquationSystemFeeders equationSystemFeedersDirect = directResult.getEqSysFeeders();
+ EquationSystemFeeders equationSystemFeedersHomopolar = homopolarResult.getEqSysFeeders();
+ // TODO : adapt in case of a biphased common support
+
+ ShortCircuitResult res = new ShortCircuitResult(scf, lfBus1,
+ mId.toDense().get(0, 0), mId.toDense().get(1, 0),
+ mIo.toDense().get(0, 0), mIo.toDense().get(1, 0),
+ mIi.toDense().get(0, 0), mIi.toDense().get(1, 0),
+ rdf, xdf, rof, xof, rdf, xdf,
+ v1dxInit, v1dyInit,
+ mVd.toDense().get(0, 0), mVd.toDense().get(1, 0),
+ mVo.toDense().get(0, 0), mVo.toDense().get(1, 0),
+ mVi.toDense().get(0, 0), mVi.toDense().get(1, 0),
+ mf, equationSystemFeedersDirect, equationSystemFeedersHomopolar, parameters.getNorm(),
+ mI2d.toDense().get(0, 0), mI2d.toDense().get(1, 0),
+ mI2o.toDense().get(0, 0), mI2o.toDense().get(1, 0),
+ mI2i.toDense().get(0, 0), mI2i.toDense().get(1, 0),
+ v2dxInit, v2dyInit,
+ mVd.toDense().get(2, 0), mVd.toDense().get(3, 0),
+ mVo.toDense().get(2, 0), mVo.toDense().get(3, 0),
+ mVi.toDense().get(2, 0), mVi.toDense().get(3, 0),
+ lfBus2);
+
+ if (parameters.voltageUpdate) {
+ res.setLfNetwork(directResolution.lfNetworkResult);
+ res.setTrueVoltageProfileUpdate();
+ // The post-fault voltage values for the network busses are computed as follow :
+ // [ Vof ] = -inv(Yo) * M * [ Iof ]
+ // [ Vdf ] = -inv(Yd) * M * [ Idf ] + [ V(init) ]
+ // [ Vif ] = -inv(Yd) * M * [ Iif ]
+ // dMo = inv(Yo) * M
+ // dMd = inv(Yd) * M
+
+ int nbBusses = directResolution.lfNetworkResult.getBuses().size();
+ res.createEmptyFortescueVoltageVector(nbBusses);
+
+ for (Map.Entry vd : directResult.getDv().entrySet()) {
+ int busNum = vd.getKey();
+
+ //int numBus2 = biphasedDirectResult.getNumBus2Fault();
+
+ //direct
+ double edVr = vd.getValue().get(0, 0);
+ double edVi = vd.getValue().get(1, 0);
+ double edV2r = biphasedDirectResult.getDv2().get(busNum).get(0, 0); // TODO : check : probably wrong, should be busNum
+ double edV2i = biphasedDirectResult.getDv2().get(busNum).get(1, 0); // TODO : check order to access DV2 is OK
+
+ double idr = -mId.toDense().get(0, 0);
+ double idi = -mId.toDense().get(1, 0);
+ double i2dr = -mI2d.toDense().get(0, 0);
+ double i2di = -mI2d.toDense().get(1, 0);
+
+ double deltaVdr = -idr * edVr + idi * edVi - i2dr * edV2r + i2di * edV2i;
+ double deltaVdi = -idr * edVi - idi * edVr - i2dr * edV2i - i2di * edV2r;
+
+ //inverse
+ double iir = -mIi.toDense().get(0, 0);
+ double iii = -mIi.toDense().get(1, 0);
+ double i2ir = -mI2i.toDense().get(0, 0);
+ double i2ii = -mI2i.toDense().get(1, 0);
+
+ double deltaVir = -iir * edVr + iii * edVi - i2ir * edV2r - i2ii * edV2i;
+ double deltaVii = -iir * edVi - iii * edVr - i2ir * edV2i - i2ii * edV2r;
+
+ //homopolar
+ double eoVr = homopolarResult.getDv().get(busNum).get(0, 0);
+ double eoVi = homopolarResult.getDv().get(busNum).get(1, 0);
+ double eoV2r = biphasedHomopolarResult.getDv2().get(busNum).get(0, 0);
+ double eoV2i = biphasedHomopolarResult.getDv2().get(busNum).get(1, 0);
+
+ double ior = -mIo.toDense().get(0, 0);
+ double ioi = -mIo.toDense().get(1, 0);
+ double i2or = -mI2o.toDense().get(0, 0);
+ double i2oi = -mI2o.toDense().get(1, 0);
+
+ double deltaVor = -ior * eoVr + ioi * eoVi - i2or * eoV2r + i2oi * eoV2i;
+ double deltaVoi = -ior * eoVi - ioi * eoVr - i2or * eoV2i - i2oi * eoV2r;
+
+ //System.out.println(" dVth(" + vdr.getKey() + ") = " + edVr + " + j(" + edVi + ")");
+
+ res.fillVoltageInFortescueVector(busNum, deltaVdr, deltaVdi, deltaVor, deltaVoi, deltaVir, deltaVii);
+ }
+ }
+
+ return res;
+ }
+
+ public static Matrix getZ(double r, double x, MatrixFactory mf) {
+ Matrix z = mf.create(2, 2, 2);
+ z.add(0, 0, r);
+ z.add(0, 1, -x);
+ z.add(1, 0, x);
+ z.add(1, 1, r);
+
+ return z;
+ }
+
+}
diff --git a/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBalancedTest.java b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBalancedTest.java
new file mode 100644
index 00000000..96c3fd6d
--- /dev/null
+++ b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBalancedTest.java
@@ -0,0 +1,708 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.computation.ComputationManager;
+import com.powsybl.computation.local.LocalComputationManager;
+import com.powsybl.iidm.network.*;
+import com.powsybl.iidm.network.extensions.GeneratorShortCircuitAdder;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.loadflow.LoadFlowResult;
+import com.powsybl.math.matrix.DenseMatrixFactory;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import com.powsybl.shortcircuit.*;
+import org.apache.commons.math3.util.Pair;
+import org.joda.time.DateTime;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitBalancedTest {
+
+ private LoadFlowParameters parameters;
+
+ private MatrixFactory matrixFactory;
+
+ private LoadFlow.Runner loadFlowRunner;
+
+ @BeforeEach
+ void setUp() {
+ parameters = new LoadFlowParameters();
+ matrixFactory = new DenseMatrixFactory();
+ loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+ }
+
+ @Test
+ void computeIccTest() {
+ Network nt2 = create2n(NetworkFactory.findDefault());
+ LoadFlowResult resultnt2 = loadFlowRunner.run(nt2, parameters);
+
+ List tmpV = new ArrayList<>();
+ ShortCircuitFault sc2 = new ShortCircuitFault("B2", true, "sc2", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ tmpV.add(sc2);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.TRANSIENT;
+
+ AdditionalDataInfo additionalDataInfo = new AdditionalDataInfo(); //No specific additional info needed in this test
+
+ ShortCircuitEngineParameters.VoltageProfileType vp = ShortCircuitEngineParameters.VoltageProfileType.CALCULATED;
+ ShortCircuitEngineParameters.AnalysisType at = ShortCircuitEngineParameters.AnalysisType.SELECTIVE;
+
+ LoadFlowParameters loadFlowParameters = new LoadFlowParameters();
+ ShortCircuitNormCourcirc shortCircuitNormCourcirc = new ShortCircuitNormCourcirc();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, at, tmpV, true, vp, false, periodType, additionalDataInfo, shortCircuitNormCourcirc);
+ ShortCircuitBalancedEngine scbEngine = new ShortCircuitBalancedEngine(nt2, scbParameters);
+
+ scbEngine.run();
+
+ scbEngine.resultsPerFault.get(sc2).updateFeedersResult();
+
+ assertEquals(-0.4316661015058293, scbEngine.resultsPerFault.get(sc2).getIdx(), 0.000001);
+ assertEquals(-4.617486568622836, scbEngine.resultsPerFault.get(sc2).getIdy(), 0.000001);
+ assertEquals(-0.5197272846952616, scbEngine.resultsPerFault.get(sc2).getIxFeeder("VL_1_0", "G1"), 0.000001);
+
+ }
+
+ @Test
+ void openShortCircuitProvider2n() {
+
+ //set up LF info
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+ Network nt2 = create2n(NetworkFactory.findDefault());
+ LoadFlowResult resultnt2 = LoadFlow.run(nt2, loadFlowParameters);
+
+ //set up ShortCircuitProvider info
+ ShortCircuitAnalysisProvider provider = new OpenShortCircuitProvider(new DenseMatrixFactory());
+ ComputationManager cm = LocalComputationManager.getDefault();
+ ShortCircuitParameters scp = new ShortCircuitParameters();
+
+ //CompletableFuture scar = provider.run(nt2, scp, cm);
+ List faults = new ArrayList<>();
+ BusFault bf1 = new BusFault("F1", "B1");
+ BusFault bf2 = new BusFault("F2", "B2");
+ faults.add(bf1);
+ faults.add(bf2);
+
+ ShortCircuitAnalysisResult scar = provider.run(nt2, faults, scp, cm, Collections.emptyList()).join();
+
+ List frs = scar.getFaultResults();
+
+ String providerName = provider.getName();
+ String providerVersion = provider.getVersion();
+
+ assertEquals(4.646530628204346, frs.get(1).getCurrent().getDirectMagnitude(), 0.00001);
+ assertEquals(5.100971698760986, frs.get(0).getCurrent().getDirectMagnitude(), 0.00001);
+ assertEquals("OpenShortCircuit", providerName);
+ assertEquals("0.1", providerVersion);
+
+ }
+
+ @Test
+ void openShortCircuitProvider4n() {
+
+ //set up LF info
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+ Network nt4 = create4n(NetworkFactory.findDefault());
+ LoadFlowResult resultnt4 = LoadFlow.run(nt4, loadFlowParameters);
+
+ //set up ShortCircuitProvider info
+ ShortCircuitAnalysisProvider provider = new OpenShortCircuitProvider(new DenseMatrixFactory());
+ ComputationManager cm = LocalComputationManager.getDefault();
+ ShortCircuitParameters scp = new ShortCircuitParameters();
+
+ //CompletableFuture scar = provider.run(nt2, scp, cm);
+ List faults = new ArrayList<>(); // TODO
+
+ BusFault bf1 = new BusFault("F1", "B1");
+ BusFault bf2 = new BusFault("F2", "B2");
+ BusFault bf3 = new BusFault("F3", "B3");
+ BusFault bf4 = new BusFault("F4", "B4");
+
+ faults.add(bf1);
+ faults.add(bf2);
+ faults.add(bf3);
+ faults.add(bf4);
+
+ ShortCircuitAnalysisResult scar = provider.run(nt4, faults, scp, cm, Collections.emptyList()).join();
+
+ List frs = scar.getFaultResults();
+
+ assertEquals(6.143869876861572, frs.get(0).getCurrent().getDirectMagnitude(), 0.00001);
+ assertEquals(6.491052150726318, frs.get(1).getCurrent().getDirectMagnitude(), 0.00001);
+ assertEquals(6.222183704376221, frs.get(2).getCurrent().getDirectMagnitude(), 0.00001);
+ assertEquals(5.909138679504394, frs.get(3).getCurrent().getDirectMagnitude(), 0.00001);
+
+ }
+
+ @Test
+ void openShortCircuitProvider2nTfo() {
+
+ //set up LF info
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+ Network nt2 = create2nTfo(NetworkFactory.findDefault());
+ LoadFlowResult resultnt2 = LoadFlow.run(nt2, loadFlowParameters);
+
+ //set up ShortCircuitProvider info
+ ShortCircuitAnalysisProvider provider = new OpenShortCircuitProvider(new DenseMatrixFactory());
+ ComputationManager cm = LocalComputationManager.getDefault();
+ ShortCircuitParameters scp = new ShortCircuitParameters();
+
+ //CompletableFuture scar = provider.run(nt2, scp, cm);
+ List faults = new ArrayList<>(); // TODO
+
+ BusFault bf1 = new BusFault("F1", "B1");
+ BusFault bf2 = new BusFault("F2", "B2");
+ faults.add(bf1);
+ faults.add(bf2);
+
+ ShortCircuitAnalysisResult scar = provider.run(nt2, faults, scp, cm, Collections.emptyList()).join();
+
+ List frs = scar.getFaultResults();
+
+ assertEquals(4.888257026672363, frs.get(1).getCurrent().getDirectMagnitude(), 0.00001);
+ assertEquals(5.100976467132568, frs.get(0).getCurrent().getDirectMagnitude(), 0.00001);
+
+ }
+
+ @Test
+ void shortCircuitSystematic() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Network nt2 = create2n(NetworkFactory.findDefault());
+ LoadFlowResult resultnt2 = LoadFlow.run(nt2, loadFlowParameters);
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List tmpV = new ArrayList<>();
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.TRANSIENT;
+
+ AdditionalDataInfo additionalDataInfo = new AdditionalDataInfo(); //No specific additional info needed in this test
+
+ ShortCircuitNormCourcirc shortCircuitNormCourcirc = new ShortCircuitNormCourcirc();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SYSTEMATIC, tmpV, false, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormCourcirc);
+ ShortCircuitBalancedEngine scbEngine = new ShortCircuitBalancedEngine(nt2, scbParameters);
+
+ scbEngine.run();
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIdx());
+ }
+
+ assertEquals(0.0996007987855852, val.get(0), 0.00001);
+ assertEquals(0.0999999987871081, val.get(1), 0.00001);
+
+ }
+
+ @Test
+ void shortCircuitSubTransientReference() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitReference();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B7", true, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc1);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+
+ ShortCircuitNormCourcirc shortCircuitNormCourcirc = new ShortCircuitNormCourcirc();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, true, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormCourcirc);
+ ShortCircuitBalancedEngine scbEngine = new ShortCircuitBalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIcc());
+ }
+
+ // here Icc = 1/sqrt(3)*Eth(pu)/Zth(pu100)*Sb100/Vb*1000
+ // here new Icc = 1/sqrt(3)*Eth(pu)/Zth(pu100)*Sb100*1000
+ // and Idocumentation = Ib*Eth(pu)/Zth(pu15) then Idocumentation = Icc * Ib * sqrt(3) * Vb / (1000 * Sb15) with Ib = 18.064
+ // in the documentation, expected Idocumentation ~ 35.656 kA
+ assertEquals(35.69309945355154, val.get(0) * 18.064 * 0.277 * Math.sqrt(3) / (1000. * 15.) / 0.277, 0.00001);
+
+ }
+
+ @Test
+ void shortCircuitIec31() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B3", true, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc1);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, true, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitBalancedEngine scbEngine = new ShortCircuitBalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIk());
+ }
+
+ // here Icc = 1/sqrt(3)*Eth(pu)/Zth(pu100)*Sb100/Vb*1000
+ // and I"k = 1/sqrt(3) * cmax * Un /(Zeq) and expected I"k = 34.62 kA
+ assertEquals(34.62398968800272, val.get(0), 0.00001);
+
+ }
+
+ @Test
+ void shortCircuitIec31TestNetwork() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31testNetwork();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B1", true, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc1);
+ ShortCircuitFault sc2 = new ShortCircuitFault("B2", true, "sc2", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc2);
+ ShortCircuitFault sc3 = new ShortCircuitFault("B3", true, "sc3", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc3);
+ ShortCircuitFault sc4 = new ShortCircuitFault("B4", true, "sc4", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc4);
+ ShortCircuitFault sc5 = new ShortCircuitFault("B5", true, "sc5", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc5);
+ ShortCircuitFault sc6 = new ShortCircuitFault("B6", true, "sc6", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc6);
+ ShortCircuitFault sc7 = new ShortCircuitFault("B7", true, "sc7", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc7);
+ ShortCircuitFault sc8 = new ShortCircuitFault("B8", true, "sc8", 0., 0., ShortCircuitFault.ShortCircuitType.TRIPHASED_GROUND);
+ faultList.add(sc8);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, true, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitBalancedEngine scbEngine = new ShortCircuitBalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ List values = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ values.add(res.getValue().getIk());
+ }
+
+ // I"k = 1/sqrt(3) * cmax * Un /(Zeq)
+ assertEquals(40.64478476116188, values.get(0), 0.001); // bus 1 : expected in doc = 40.6447 kA
+ assertEquals(31.783052222534174, values.get(1), 0.001); // bus 2 : expected in doc = 31.7831 kA
+ assertEquals(19.672955775750143, values.get(2), 0.001); // bus 3 : expected in doc = 19.673 kA
+ assertEquals(16.227655866910894, values.get(3), 0.001); // bus 4 : expected in doc = 16.2277 kA
+ assertEquals(33.18941481677016, values.get(4), 0.001); // bus 5 : expected in doc = 33.1894 kA
+ assertEquals(37.56287899040728, values.get(5), 0.001); // bus 6 : expected in doc = 37.5629 kA
+ assertEquals(25.589463480212533, values.get(6), 0.001); // bus 7 : expected in doc = 25.5895 kA
+ assertEquals(13.577771545200052, values.get(7), 0.001); // bus 8 : expected in doc = 13.5778 kA
+
+ //assertEquals(4039.8610235151364, values.get(8), 0.1); // T3 U0 node : for check only
+ //assertEquals(4039.8610235151364, values.get(8), 0.1); // T4 U0 node : for check only
+
+ }
+
+ public static Network create2n(NetworkFactory networkFactory) {
+ Objects.requireNonNull(networkFactory);
+
+ double p0l2 = 10;
+ double q0l2 = 10;
+ double pgen = 10;
+ double xl = 2.;
+
+ Network network = networkFactory.createNetwork("2n", "test");
+ network.setCaseDate(DateTime.parse("2018-03-05T13:30:30.486+01:00"));
+ Substation substation1 = network.newSubstation()
+ .setId("S1")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl1 = substation1.newVoltageLevel()
+ .setId("VL_1")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus1 = vl1.getBusBreakerView().newBus()
+ .setId("B1")
+ .add();
+ bus1.setV(100.0).setAngle(0.);
+ Generator gen1 = vl1.newGenerator()
+ .setId("G1")
+ .setBus(bus1.getId())
+ .setMinP(0.0)
+ .setMaxP(150)
+ .setTargetP(pgen)
+ .setTargetV(100.0)
+ .setVoltageRegulatorOn(true)
+ .add();
+
+ gen1.newExtension(GeneratorShortCircuitAdder.class)
+ .withDirectSubtransX(20)
+ .withDirectTransX(20)
+ .withStepUpTransformerX(0.)
+ .add();
+
+ Substation substation2 = network.newSubstation()
+ .setId("S2")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl2 = substation2.newVoltageLevel()
+ .setId("VL_2")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus2 = vl2.getBusBreakerView().newBus()
+ .setId("B2")
+ .add();
+ bus2.setV(100.0).setAngle(0);
+ vl2.newLoad()
+ .setId("LOAD_2")
+ .setBus(bus2.getId())
+ .setP0(p0l2)
+ .setQ0(q0l2)
+ .add();
+
+ network.newLine()
+ .setId("B1_B2")
+ .setVoltageLevel1(vl1.getId())
+ .setBus1(bus1.getId())
+ .setConnectableBus1(bus1.getId())
+ .setVoltageLevel2(vl2.getId())
+ .setBus2(bus2.getId())
+ .setConnectableBus2(bus2.getId())
+ .setR(0.0)
+ .setX(xl)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+
+ return network;
+ }
+
+ public static Network create4n(NetworkFactory networkFactory) {
+ Objects.requireNonNull(networkFactory);
+ // 2 3
+ // (~)-|--------------X23--------------|-[X] Po= 10. Qo = 100.
+ // |--+ +--|
+ // | / |--+
+ // | / |
+ // | / |
+ // X12 / |
+ // | +-----X13-----+ X34
+ // | / |
+ // 1 | / |
+ // |--+ / |
+ // |-----+ |--+
+ // +--|--------------X14--------------|-----[X] Po= 20. Qo = 10.
+ // | |--B4
+ // B1
+
+ Network network = networkFactory.createNetwork("4n", "test");
+ network.setCaseDate(DateTime.parse("2018-03-05T13:30:30.486+01:00"));
+ Substation substation1 = network.newSubstation()
+ .setId("S1")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl1 = substation1.newVoltageLevel()
+ .setId("VL_1")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus1 = vl1.getBusBreakerView().newBus()
+ .setId("B1")
+ .add();
+ bus1.setV(100.0).setAngle(0.);
+ // test with shunt (could be removed)
+ vl1.newShuntCompensator()
+ .setId("SHUNT_1")
+ .setBus(bus1.getId())
+ .setSectionCount(1)
+ .setVoltageRegulatorOn(false)
+ .newLinearModel().setMaximumSectionCount(1).setBPerSection(-0.003).add()
+ .add();
+
+ Substation substation2 = network.newSubstation()
+ .setId("S2")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl2 = substation2.newVoltageLevel()
+ .setId("VL_2")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus2 = vl2.getBusBreakerView().newBus()
+ .setId("B2")
+ .add();
+ bus2.setV(100.0).setAngle(0);
+ Generator gen2 = vl2.newGenerator()
+ .setId("G2")
+ .setBus(bus2.getId())
+ .setMinP(0.0)
+ .setMaxP(150)
+ .setTargetP(30)
+ .setTargetV(100.0)
+ .setVoltageRegulatorOn(true)
+ .add();
+ gen2.newExtension(GeneratorShortCircuitAdder.class)
+ .withDirectTransX(20.)
+ .withDirectSubtransX(20.)
+ .withStepUpTransformerX(0.)
+ .add();
+
+ Substation substation3 = network.newSubstation()
+ .setId("S3")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl3 = substation3.newVoltageLevel()
+ .setId("VL_3")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus3 = vl3.getBusBreakerView().newBus()
+ .setId("B3")
+ .add();
+ bus3.setV(100.0).setAngle(0.);
+ vl3.newLoad()
+ .setId("LOAD_3")
+ .setBus(bus3.getId())
+ .setP0(10.0)
+ .setQ0(100.)
+ .add();
+
+ Substation substation4 = network.newSubstation()
+ .setId("S4")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl4 = substation4.newVoltageLevel()
+ .setId("VL_4")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus4 = vl4.getBusBreakerView().newBus()
+ .setId("B4")
+ .add();
+ bus4.setV(100.0).setAngle(0.);
+ vl4.newShuntCompensator()
+ .setId("SHUNT_4")
+ .setBus(bus4.getId())
+ .setSectionCount(1)
+ .setVoltageRegulatorOn(false)
+ .newLinearModel().setMaximumSectionCount(1).setBPerSection(-0.00105).add()
+ .add();
+ vl4.newLoad()
+ .setId("LOAD_4")
+ .setBus(bus4.getId())
+ .setP0(20.)
+ .setQ0(10.)
+ .add();
+
+ network.newLine()
+ .setId("B1_B2")
+ .setVoltageLevel1(vl1.getId())
+ .setBus1(bus1.getId())
+ .setConnectableBus1(bus1.getId())
+ .setVoltageLevel2(vl2.getId())
+ .setBus2(bus2.getId())
+ .setConnectableBus2(bus2.getId())
+ .setR(0.0)
+ .setX(1 / 0.5)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+ network.newLine()
+ .setId("B1_B3")
+ .setVoltageLevel1(vl1.getId())
+ .setBus1(bus1.getId())
+ .setConnectableBus1(bus1.getId())
+ .setVoltageLevel2(vl3.getId())
+ .setBus2(bus3.getId())
+ .setConnectableBus2(bus3.getId())
+ .setR(0.0)
+ .setX(1 / 0.4)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+ network.newLine()
+ .setId("B1_B4")
+ .setVoltageLevel1(vl1.getId())
+ .setBus1(bus1.getId())
+ .setConnectableBus1(bus1.getId())
+ .setVoltageLevel2(vl4.getId())
+ .setBus2(bus4.getId())
+ .setConnectableBus2(bus4.getId())
+ .setR(0.0)
+ .setX(1 / 0.4)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+ network.newLine()
+ .setId("B2_B3")
+ .setVoltageLevel1(vl2.getId())
+ .setBus1(bus2.getId())
+ .setConnectableBus1(bus2.getId())
+ .setVoltageLevel2(vl3.getId())
+ .setBus2(bus3.getId())
+ .setConnectableBus2(bus3.getId())
+ .setR(0.0)
+ .setX(1 / 0.6)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+ network.newLine()
+ .setId("B3_B4")
+ .setVoltageLevel1(vl3.getId())
+ .setBus1(bus3.getId())
+ .setConnectableBus1(bus3.getId())
+ .setVoltageLevel2(vl4.getId())
+ .setBus2(bus4.getId())
+ .setConnectableBus2(bus4.getId())
+ .setR(0.0)
+ .setX(1 / 0.5)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+
+ return network;
+ }
+
+ public static Network create2nTfo(NetworkFactory networkFactory) {
+ Objects.requireNonNull(networkFactory);
+
+ double p0l2 = 10;
+ double q0l2 = 10;
+ double pGen = 10;
+ double xl = 2.;
+
+ Network network = networkFactory.createNetwork("2nTfo", "test");
+ network.setCaseDate(DateTime.parse("2018-03-05T13:30:30.486+01:00"));
+ Substation substation1 = network.newSubstation()
+ .setId("S1")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vl1 = substation1.newVoltageLevel()
+ .setId("VL_1")
+ .setNominalV(100.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus1 = vl1.getBusBreakerView().newBus()
+ .setId("B1")
+ .add();
+ bus1.setV(100.0).setAngle(0.);
+
+ Generator gen1 = vl1.newGenerator()
+ .setId("G1")
+ .setBus(bus1.getId())
+ .setMinP(0.0)
+ .setMaxP(150)
+ .setTargetP(pGen)
+ .setTargetV(100.0)
+ .setVoltageRegulatorOn(true)
+ .add();
+
+ gen1.newExtension(GeneratorShortCircuitAdder.class)
+ .withDirectSubtransX(20)
+ .withDirectTransX(20)
+ .withStepUpTransformerX(0.)
+ .add();
+
+ VoltageLevel vl2 = substation1.newVoltageLevel()
+ .setId("VL_2")
+ .setNominalV(150.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(200)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus bus2 = vl2.getBusBreakerView().newBus()
+ .setId("B2")
+ .add();
+ bus2.setV(150.0).setAngle(0);
+ vl2.newLoad()
+ .setId("LOAD_2")
+ .setBus(bus2.getId())
+ .setP0(p0l2)
+ .setQ0(q0l2)
+ .add();
+
+ TwoWindingsTransformer t2w = substation1.newTwoWindingsTransformer()
+ .setId("B1_B2")
+ .setVoltageLevel1(vl1.getId())
+ .setBus1(bus1.getId())
+ .setConnectableBus1(bus1.getId())
+ .setVoltageLevel2(vl2.getId())
+ .setBus2(bus2.getId())
+ .setConnectableBus2(bus2.getId())
+ .setR(0.0)
+ .setX(xl)
+ .setRatedU1(100.0)
+ .setRatedU2(150.0)
+ .setG(0.0)
+ .setB(0.0)
+ .add();
+
+ return network;
+ }
+}
diff --git a/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBiphasedGroundTest.java b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBiphasedGroundTest.java
new file mode 100644
index 00000000..5c99f337
--- /dev/null
+++ b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBiphasedGroundTest.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.math.matrix.DenseMatrixFactory;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import org.apache.commons.math3.util.Pair;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitBiphasedGroundTest {
+
+ private LoadFlowParameters parameters;
+
+ private MatrixFactory matrixFactory;
+
+ private LoadFlow.Runner loadFlowRunner;
+
+ @BeforeEach
+ void setUp() {
+ parameters = new LoadFlowParameters();
+ matrixFactory = new DenseMatrixFactory();
+ loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+ }
+
+ @Test
+ void shortCircuitIec31Mono() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B3", false, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED_GROUND);
+ faultList.add(sc1);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, false, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitUnbalancedEngine scbEngine = new ShortCircuitUnbalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIk());
+ }
+
+ assertEquals(52.3687065865033, 3 * val.get(0), 0.00001);
+
+ }
+}
diff --git a/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBiphasedTest.java b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBiphasedTest.java
new file mode 100644
index 00000000..984ebd67
--- /dev/null
+++ b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitBiphasedTest.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.math.matrix.DenseMatrixFactory;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import org.apache.commons.math3.util.Pair;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitBiphasedTest {
+
+ private LoadFlowParameters parameters;
+
+ private MatrixFactory matrixFactory;
+
+ private LoadFlow.Runner loadFlowRunner;
+
+ @BeforeEach
+ void setUp() {
+ parameters = new LoadFlowParameters();
+ matrixFactory = new DenseMatrixFactory();
+ loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+ }
+
+ @Test
+ void shortCircuitIec31Mono() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B3", false, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED);
+ faultList.add(sc1);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, false, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitUnbalancedEngine scbEngine = new ShortCircuitUnbalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIk());
+ }
+
+ assertEquals(67.51864695211795, 3 * val.get(0), 0.00001);
+
+ }
+
+}
diff --git a/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitMonophasedTest.java b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitMonophasedTest.java
new file mode 100644
index 00000000..a0b4fb0c
--- /dev/null
+++ b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShortCircuitMonophasedTest.java
@@ -0,0 +1,343 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.*;
+import com.powsybl.iidm.network.extensions.GeneratorShortCircuitAdder;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.loadflow.LoadFlowResult;
+import com.powsybl.math.matrix.DenseMatrixFactory;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import org.apache.commons.math3.util.Pair;
+import org.joda.time.DateTime;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShortCircuitMonophasedTest {
+
+ private LoadFlowParameters parameters;
+
+ private MatrixFactory matrixFactory;
+
+ private LoadFlow.Runner loadFlowRunner;
+
+ @BeforeEach
+ void setUp() {
+ parameters = new LoadFlowParameters();
+ matrixFactory = new DenseMatrixFactory();
+ loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+ }
+
+ @Test
+ void shortCircuitIec31Mono() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B3", false, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.MONOPHASED);
+ faultList.add(sc1);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, false, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitUnbalancedEngine scbEngine = new ShortCircuitUnbalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIk());
+ }
+
+ // here Icc = 1/sqrt(3)*Eth(pu)/Zth(pu100)*Sb100/Vb*1000
+ // here new Icc = 1/sqrt(3)*Eth(pu)/Zth(pu100)*Sb100*1000
+ // and I"k = sqrt(3) * cmax * Un /(Zeq) and expected I"k = 35.64 kA with some approximations on the impedance values
+
+ //assertEquals(35.70435548244156, 3 * val.get(0) * 1.05 / 1000. / 0.4, 0.00001);
+ assertEquals(35.70435548244156, 3 * val.get(0), 0.00001);
+
+ }
+
+ @Test
+ void shortCircuitIecTestNetworkMono() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31testNetwork();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B2", false, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.MONOPHASED);
+ faultList.add(sc1);
+ ShortCircuitFault sc2 = new ShortCircuitFault("B3", false, "sc2", 0., 0., ShortCircuitFault.ShortCircuitType.MONOPHASED);
+ faultList.add(sc2);
+ ShortCircuitFault sc3 = new ShortCircuitFault("B4", false, "sc3", 0., 0., ShortCircuitFault.ShortCircuitType.MONOPHASED);
+ faultList.add(sc3);
+ ShortCircuitFault sc4 = new ShortCircuitFault("B5", false, "sc4", 0., 0., ShortCircuitFault.ShortCircuitType.MONOPHASED);
+ faultList.add(sc4);
+
+ // additional faults
+ ShortCircuitFault sc5 = new ShortCircuitFault("B2", false, "sc5", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED);
+ faultList.add(sc5);
+ ShortCircuitFault sc6 = new ShortCircuitFault("B3", false, "sc6", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED_GROUND);
+ faultList.add(sc6);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, false, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitUnbalancedEngine scbEngine = new ShortCircuitUnbalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+ Map values = new HashMap<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ values.put(res.getKey().getFaultId(), res.getValue().getIk());
+ }
+
+ //I"k = sqrt(3) * cmax * Un /(Zeq)
+ assertEquals(15.9722, 3 * values.get("sc1"), 0.00001); // bus 2 : expected doc value : 15.9722 kA
+ assertEquals(10.410558286260768, 3 * values.get("sc2"), 0.00001); // bus 3 : expected doc value : 10.4106 kA
+ assertEquals(9.049787523396647, 3 * values.get("sc3"), 0.00001); // bus 4 : expected doc value : 9.0498 kA
+ assertEquals(17.0452, 3 * values.get("sc4"), 0.00001); // bus 5 : expected doc value : 17.0452 kA
+
+ // test to check that non monophased faults does not have an impact on monophased results
+ assertEquals(57.48674948061683, 3 * values.get("sc5"), 0.00001); // biphased not in ref doc
+ assertEquals(25.21494837446988, 3 * values.get("sc6"), 0.00001); // biphased not in ref doc
+
+ }
+
+ @Test
+ void computeIoTestNew() {
+ Pair result = createGiard(NetworkFactory.findDefault());
+
+ Network network = result.getKey();
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ LoadFlowResult resultntg = loadFlowRunner.run(network, parameters);
+
+ Map machineToGround = new HashMap<>(); //true if the generating unit has its neutral linked to the ground
+ machineToGround.put("GA", false);
+ machineToGround.put("GB", true);
+
+ additionalDataInfo.setMachineToGround(machineToGround);
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("BP", true, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.MONOPHASED);
+
+ faultList.add(sc1);
+
+ LoadFlowParameters loadFlowParameters = new LoadFlowParameters();
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.TRANSIENT;
+ ShortCircuitNormCourcirc shortCircuitNormCourcirc = new ShortCircuitNormCourcirc();
+ ShortCircuitEngineParameters scunbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, true, ShortCircuitEngineParameters.VoltageProfileType.CALCULATED, false, periodType, additionalDataInfo, shortCircuitNormCourcirc);
+ ShortCircuitUnbalancedEngine scunbEngine = new ShortCircuitUnbalancedEngine(network, scunbParameters);
+
+ scunbEngine.run();
+
+ //assertEquals(2.8286512112174034, scunbEngine.results.get(sc1).getIox() / Math.sqrt(3), 0.000001); // results changed with modification of input data
+ //assertEquals(1.6331225382399293, scunbEngine.results.get(sc1).getIoy() / Math.sqrt(3), 0.000001);
+ assertEquals(2.7099928109273916, scunbEngine.resultsPerFault.get(sc1).getIox() / Math.sqrt(3), 0.000001);
+ assertEquals(1.5646150788908801, scunbEngine.resultsPerFault.get(sc1).getIoy() / Math.sqrt(3), 0.000001);
+
+ }
+
+ public static Pair createGiard(NetworkFactory networkFactory) {
+
+ // M1 P M2 machine M1: isolated neutral with X'd1, Xmi1, Xmo1
+ // (~)-|---Xd1---|---Xd2---|--(~) machine M2: grounded neutral through Xn, with X'd2, Xmi2, Xmo2
+ // Xi1 Xi2 | In P, there is a direct monophased fault to the ground (phase 1)
+ // Xo1 Xo2 Xn
+ // |
+ // /////
+ //
+ // Direct schema:
+ // P
+ // --X'd1--|---Xd1---|---Xd2---|--X'd2-- Xd'1 = 65 ohms Xd'2 = 130 ohms
+ // ^ ^ Xd1 = 30 ohms Xd2 = 15 ohms
+ // | Ed1 | Ed2
+ // | |
+ // /// ///
+ //
+ // Inverse P
+ // --Xmi1--|---Xi1---|---Xi2---|--Xmi2-- Xi = Xd
+ // | |
+ // | |
+ // /// ///
+ //
+ // Homopolar P
+ // --XmO1--|---Xo1---|---Xo2---|--Xmo2-- Xmo1 = Xd'1 / 3
+ // | Xmo2 = Xd'2 / 3
+ // 3.Xn Xo1 = 3 * Xd1
+ // | Xo2 = 3 * Xd2
+ // /// Xn = 25 ohms
+
+ Objects.requireNonNull(networkFactory);
+
+ double pgen = 0.;
+ double xd1 = 30.;
+ double xd2 = 15.;
+ double coeffXo1 = 3.;
+ double coeffXo2 = 3.;
+ double uac = 420.;
+ double ubc = 410.;
+
+ Network network = networkFactory.createNetwork("Giard exemple", "test");
+ network.setCaseDate(DateTime.parse("2018-03-05T13:30:30.486+01:00"));
+ Substation substationA = network.newSubstation()
+ .setId("SA")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vlA = substationA.newVoltageLevel()
+ .setId("VL_A")
+ .setNominalV(380.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(500)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus busA = vlA.getBusBreakerView().newBus()
+ .setId("BA")
+ .add();
+ busA.setV(uac).setAngle(0.);
+ Generator genA = vlA.newGenerator()
+ .setId("GA")
+ .setBus(busA.getId())
+ .setMinP(-10.0)
+ .setMaxP(150)
+ .setTargetP(pgen)
+ .setTargetV(uac)
+ .setVoltageRegulatorOn(true)
+ .add();
+
+ genA.newExtension(GeneratorShortCircuitAdder.class)
+ .withDirectSubtransX(65)
+ .withDirectTransX(65)
+ .withStepUpTransformerX(0.)
+ .add();
+
+ Substation substationP = network.newSubstation()
+ .setId("SP")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vlP = substationP.newVoltageLevel()
+ .setId("VL_P")
+ .setNominalV(380.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(500)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus busP = vlP.getBusBreakerView().newBus()
+ .setId("BP")
+ .add();
+ busP.setV(413.0).setAngle(0);
+
+ Substation substationB = network.newSubstation()
+ .setId("SB")
+ .setCountry(Country.FR)
+ .add();
+ VoltageLevel vlB = substationB.newVoltageLevel()
+ .setId("VL_B")
+ .setNominalV(380.0)
+ .setLowVoltageLimit(0)
+ .setHighVoltageLimit(500)
+ .setTopologyKind(TopologyKind.BUS_BREAKER)
+ .add();
+ Bus busB = vlB.getBusBreakerView().newBus()
+ .setId("BB")
+ .add();
+ busB.setV(ubc).setAngle(0.);
+ Generator genB = vlB.newGenerator()
+ .setId("GB")
+ .setBus(busB.getId())
+ .setMinP(-10.0)
+ .setMaxP(150)
+ .setTargetP(pgen)
+ .setTargetV(ubc)
+ .setVoltageRegulatorOn(true)
+ .add();
+
+ genB.newExtension(GeneratorShortCircuitAdder.class)
+ .withDirectSubtransX(130)
+ .withDirectTransX(130)
+ .withStepUpTransformerX(0.)
+ .add();
+
+ network.newLine()
+ .setId("BA_BP")
+ .setVoltageLevel1(vlA.getId())
+ .setBus1(busA.getId())
+ .setConnectableBus1(busA.getId())
+ .setVoltageLevel2(vlP.getId())
+ .setBus2(busP.getId())
+ .setConnectableBus2(busP.getId())
+ .setR(0.0)
+ .setX(xd1)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+
+ network.newLine()
+ .setId("BP_BB")
+ .setVoltageLevel1(vlP.getId())
+ .setBus1(busP.getId())
+ .setConnectableBus1(busP.getId())
+ .setVoltageLevel2(vlB.getId())
+ .setBus2(busB.getId())
+ .setConnectableBus2(busB.getId())
+ .setR(0.0)
+ .setX(xd2)
+ .setG1(0.0)
+ .setB1(0.0)
+ .setG2(0.0)
+ .setB2(0.0)
+ .add();
+
+ Map machineToTransRd = new HashMap<>(); //map to store the real part of the transient impedance
+ Map machineToSubTransRd = new HashMap<>();
+ Map machineToGround = new HashMap<>();
+
+ Map leg1type = new HashMap<>();
+ Map leg2type = new HashMap<>();
+
+ Map lineIdToCoeffRo = new HashMap<>();
+ Map lineIdToCoeffXo = new HashMap<>();
+ Map tfo2wIdToCoeffRo = new HashMap<>();
+ Map tfo2wIdToCoeffXo = new HashMap<>();
+
+ lineIdToCoeffXo.put("BA_BP", coeffXo1);
+ lineIdToCoeffXo.put("BP_BB", coeffXo2);
+
+ AdditionalDataInfo additionalDataInfo = new AdditionalDataInfo(machineToTransRd, machineToSubTransRd, machineToGround,
+ leg1type, leg2type, lineIdToCoeffRo, lineIdToCoeffXo, tfo2wIdToCoeffRo, tfo2wIdToCoeffXo);
+
+ Pair result = new Pair<>(network, additionalDataInfo);
+ return result;
+ }
+}
diff --git a/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShotCircuitBiphasedCommonSupportTest.java b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShotCircuitBiphasedCommonSupportTest.java
new file mode 100644
index 00000000..df050f60
--- /dev/null
+++ b/simulator/short-circuit/src/test/java/com/powsybl/incubator/simulator/shortcircuit/ShotCircuitBiphasedCommonSupportTest.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.shortcircuit;
+
+import com.powsybl.iidm.network.Network;
+import com.powsybl.incubator.simulator.util.*;
+import com.powsybl.incubator.simulator.util.extensions.AdditionalDataInfo;
+import com.powsybl.loadflow.LoadFlow;
+import com.powsybl.loadflow.LoadFlowParameters;
+import com.powsybl.math.matrix.DenseMatrixFactory;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.OpenLoadFlowProvider;
+import org.apache.commons.math3.util.Pair;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class ShotCircuitBiphasedCommonSupportTest {
+
+ private LoadFlowParameters parameters;
+
+ private MatrixFactory matrixFactory;
+
+ private LoadFlow.Runner loadFlowRunner;
+
+ @BeforeEach
+ void setUp() {
+ parameters = new LoadFlowParameters();
+ matrixFactory = new DenseMatrixFactory();
+ loadFlowRunner = new LoadFlow.Runner(new OpenLoadFlowProvider(matrixFactory));
+ }
+
+ @Test
+ void shortCircuitIec31BiphasedCommonSupport() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B2", "B3", true, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT, ShortCircuitFault.ShortCircuitBiphasedType.C1_A2);
+ faultList.add(sc1);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, true, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitUnbalancedEngine scbEngine = new ShortCircuitUnbalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIk());
+ }
+
+ assertEquals(31.16265030753145, 3 * val.get(0), 0.00001); // TODO : check manually result
+
+ }
+
+ @Test
+ void shortCircuitIec31MultiBiphasedCommonSupport() {
+
+ LoadFlowParameters loadFlowParameters = LoadFlowParameters.load();
+ loadFlowParameters.setTwtSplitShuntAdmittance(true);
+
+ Pair result = ReferenceNetwork.createShortCircuitIec31();
+ Network network = result.getKey();
+
+ AdditionalDataInfo additionalDataInfo = result.getValue();
+
+ MatrixFactory matrixFactory = new DenseMatrixFactory();
+
+ List faultList = new ArrayList<>();
+ ShortCircuitFault sc1 = new ShortCircuitFault("B2", "B3", true, "sc1", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT, ShortCircuitFault.ShortCircuitBiphasedType.C1_B2);
+ ShortCircuitFault sc2 = new ShortCircuitFault("B4", "B5", true, "sc2", 0., 0., ShortCircuitFault.ShortCircuitType.BIPHASED_COMMON_SUPPORT, ShortCircuitFault.ShortCircuitBiphasedType.C1_C2);
+ // TODO : a list that contains BIPHASED_COMMON_SUPPORT with the same nodes is not supported yet : FIX_ME
+ faultList.add(sc1);
+ faultList.add(sc2);
+
+ ShortCircuitEngineParameters.PeriodType periodType = ShortCircuitEngineParameters.PeriodType.SUB_TRANSIENT;
+ ShortCircuitNormIec shortCircuitNormIec = new ShortCircuitNormIec();
+ ShortCircuitEngineParameters scbParameters = new ShortCircuitEngineParameters(loadFlowParameters, matrixFactory, ShortCircuitEngineParameters.AnalysisType.SELECTIVE, faultList, true, ShortCircuitEngineParameters.VoltageProfileType.NOMINAL, false, periodType, additionalDataInfo, shortCircuitNormIec);
+ ShortCircuitUnbalancedEngine scbEngine = new ShortCircuitUnbalancedEngine(network, scbParameters);
+
+ scbEngine.run();
+
+ List val = new ArrayList<>();
+ for (Map.Entry res : scbEngine.resultsPerFault.entrySet()) {
+ val.add(res.getValue().getIk());
+ }
+
+ assertEquals(31.16265030753145, 3 * val.get(0), 0.00001); // TODO : check manually result
+ assertEquals(0., 3 * val.get(1), 0.00001); // TODO : check manually result
+
+ }
+
+}
diff --git a/simulator/util/pom.xml b/simulator/util/pom.xml
new file mode 100644
index 00000000..6bd03897
--- /dev/null
+++ b/simulator/util/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ 4.0.0
+
+
+ powsybl-incubator-simulator
+ com.powsybl
+ 1.0.0-SNAPSHOT
+
+
+ powsybl-incubator-simulator-util
+ Simulator utilities
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ test-jar
+
+
+
+
+
+
+
+
+
+ com.powsybl
+ powsybl-open-loadflow
+
+
+
+ com.powsybl
+ powsybl-iidm-impl
+ test
+
+
+ com.powsybl
+ powsybl-config-test
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+
+
\ No newline at end of file
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AbstractAdmittanceEquationTerm.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AbstractAdmittanceEquationTerm.java
new file mode 100644
index 00000000..5067c56c
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AbstractAdmittanceEquationTerm.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.openloadflow.equations.AbstractNamedEquationTerm;
+import com.powsybl.openloadflow.equations.Variable;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.ElementType;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfBus;
+import com.powsybl.openloadflow.network.PiModel;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public abstract class AbstractAdmittanceEquationTerm extends AbstractNamedEquationTerm implements LinearEquationTerm {
+
+ private final LfBranch branch;
+
+ protected final Variable v1rVar;
+
+ protected final Variable v1iVar;
+
+ protected final Variable v2rVar;
+
+ protected final Variable v2iVar;
+
+ protected final List> variables;
+
+ protected double rho;
+
+ protected double zInvSquare;
+
+ protected double r;
+
+ protected double x;
+
+ protected double cosA;
+
+ protected double sinA;
+
+ protected double cos2A;
+
+ protected double sin2A;
+
+ protected double gPi1;
+
+ protected double bPi1;
+
+ protected double gPi2;
+
+ protected double bPi2;
+
+ // zero sequence additional attributes
+ //
+ // Proposed Transformer model :
+ // Ia Yg A' rho B' Yg Ib Zga : grounding impedance on A side (in ohms expressed on A side)
+ // A-->--3*Zga--+ +--(())--+--Zoa--+--Zob--+ +--3*ZGb--<--B Zoa : leakage impedance of A-winding (in ohms expressed on B side)
+ // Y + | + Y Zob : leakage impdedance of B-winding (in ohms expressed on B side)
+ // + D Zom + D Zom : magnetizing impedance of the two windings (in ohms expressed on B side)
+ // | | | Zgb : grounding impedance on B side (in ohms expressed on B side)
+ // | | | rho might be a complex value
+ // | free fluxes \ |
+ // | | |
+ // ///// ///// ///// A' and B' are connected to Yg, Y or D depending on the winding connection type (Y to ground, Y or Delta)
+ //
+ protected AbstractAdmittanceEquationTerm(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet) {
+ this.branch = Objects.requireNonNull(branch);
+ Objects.requireNonNull(bus1);
+ Objects.requireNonNull(bus2);
+ Objects.requireNonNull(variableSet);
+
+ v1rVar = variableSet.getVariable(bus1.getNum(), VariableType.BUS_VR);
+ v2rVar = variableSet.getVariable(bus2.getNum(), VariableType.BUS_VR);
+ v1iVar = variableSet.getVariable(bus1.getNum(), VariableType.BUS_VI);
+ v2iVar = variableSet.getVariable(bus2.getNum(), VariableType.BUS_VI);
+
+ variables = List.of(v1rVar, v2rVar, v1iVar, v2iVar);
+
+ PiModel piModel = branch.getPiModel();
+ if (piModel.getX() == 0) {
+ throw new IllegalArgumentException("Branch '" + branch.getId() + "' has reactance equal to zero");
+ }
+ rho = piModel.getR1();
+ if (piModel.getZ() == 0) {
+ throw new IllegalArgumentException("Branch '" + branch.getId() + "' has Z equal to zero");
+ }
+ zInvSquare = 1 / (piModel.getZ() * piModel.getZ());
+ r = piModel.getR();
+ x = piModel.getX();
+ double alpha = piModel.getA1();
+ cosA = Math.cos(Math.toRadians(alpha));
+ sinA = Math.sin(Math.toRadians(alpha));
+ cos2A = Math.cos(Math.toRadians(2 * alpha));
+ sin2A = Math.sin(Math.toRadians(2 * alpha));
+
+ gPi1 = piModel.getG1();
+ bPi1 = piModel.getB1();
+ gPi2 = piModel.getG2();
+ bPi2 = piModel.getB2();
+ }
+
+ @Override
+ public List> getVariables() {
+ return variables;
+ }
+
+ @Override
+ public ElementType getElementType() {
+ return ElementType.BRANCH;
+ }
+
+ @Override
+ public int getElementNum() {
+ return branch.getNum();
+ }
+
+ @Override
+ public double eval() {
+ throw new UnsupportedOperationException("Not needed");
+ }
+
+ @Override
+ public double der(Variable variable) {
+ throw new UnsupportedOperationException("Not needed");
+ }
+
+ @Override
+ public boolean hasRhs() {
+ return false;
+ }
+
+ @Override
+ public double rhs() {
+ return 0;
+ }
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceConstants.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceConstants.java
new file mode 100644
index 00000000..fd1891f2
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceConstants.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+/**
+ * @author Geoffroy Jamgotchian {@literal }
+ */
+public final class AdmittanceConstants {
+
+ private AdmittanceConstants() {
+ }
+
+ public static final double XN_PU = 0.0173; //default value if data not available
+
+ public static final double COEF_XO_XD = 0.33; // xd/xo = 1/3 and xmo/x"d = 1/3
+
+ public static final double INFINITE_IMPEDANCE_ADMITTANCE_VALUE = 0.00000001;
+ // This value represents the case where have a hompoloar transformer conecting two different connex areas through an infinite impedance.
+ // This may create a singular matrix. As a consequence we replace the zero admittance value by a very small one.
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationSystem.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationSystem.java
new file mode 100644
index 00000000..70577cf3
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationSystem.java
@@ -0,0 +1,292 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.incubator.simulator.util.extensions.ShortCircuitExtensions;
+import com.powsybl.incubator.simulator.util.extensions.ShortCircuitGenerator;
+import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowContext;
+import com.powsybl.openloadflow.ac.outerloop.AcLoadFlowParameters;
+import com.powsybl.openloadflow.ac.outerloop.AcloadFlowEngine;
+import com.powsybl.openloadflow.equations.EquationSystem;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.*;
+import net.jafama.FastMath;
+import org.apache.commons.math3.util.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public final class AdmittanceEquationSystem {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AdmittanceEquationSystem.class);
+
+ private static final double SB = 100.;
+
+ private static final double EPSILON = 0.00000001;
+
+ private AdmittanceEquationSystem() {
+ }
+
+ //Equations are created based on the branches connections
+ private static void createImpedantBranch(VariableSet variableSet, EquationSystem equationSystem,
+ LfBranch branch, LfBus bus1, LfBus bus2, AdmittanceType admittanceType) {
+ if (bus1 != null && bus2 != null) { //TODO: check case when one bus is OK
+ // Equation system Y*V = I (expressed in cartesian coordinates x,y)
+ equationSystem.createEquation(bus1.getNum(), EquationType.BUS_YR)
+ .addTerm(new AdmittanceEquationTermX1(branch, bus1, bus2, variableSet, admittanceType));
+
+ equationSystem.createEquation(bus1.getNum(), EquationType.BUS_YI)
+ .addTerm(new AdmittanceEquationTermY1(branch, bus1, bus2, variableSet, admittanceType));
+
+ equationSystem.createEquation(bus2.getNum(), EquationType.BUS_YR)
+ .addTerm(new AdmittanceEquationTermX2(branch, bus1, bus2, variableSet, admittanceType));
+
+ equationSystem.createEquation(bus2.getNum(), EquationType.BUS_YI)
+ .addTerm(new AdmittanceEquationTermY2(branch, bus1, bus2, variableSet, admittanceType));
+ }
+ }
+
+ public enum AdmittanceVoltageProfileType {
+ CALCULATED, // use the computed values at nodes to compute Y elements
+ NOMINAL; // use the nominal voltage values at nodes to get Y elements
+ }
+
+ public enum AdmittanceType {
+ //TODO : adapt for the different kinds of admittance matrices
+ ADM_INJ, // all external nodal injections that does not come from branches are considered as current injectors (including shunts elements)
+ ADM_SHUNT, // all external nodal injections that does not come from branches are considered as current injectors (but not shunt elements)
+ ADM_ADMIT, // all external nodal injections are transformed into passive shunt elements included in the Y matrix (then [Ie] should be [0])
+ ADM_THEVENIN, // used to compute the Zth Thevenin Equivalent: shunts remain shunts, synchronous machines are transformed into X" equivalent shunts, remaining injections are transformed into passive shunt elements included in the Y matrix
+ ADM_THEVENIN_HOMOPOLAR; // used to compute the homopolar admittance matrix for unbalanced short circuits
+ }
+
+ public enum AdmittancePeriodType {
+ ADM_SUB_TRANSIENT, // all external nodal injections that does not come from branches are considered as current injectors (including shunts elements)
+ ADM_TRANSIENT, // all external nodal injections that does not come from branches are considered as current injectors (but not shunt elements)
+ ADM_STEADY_STATE, // all external nodal injections are transformed into passive shunt elements included in the Y matrix (then [Ie] should be [0])
+ }
+
+ private static void createBranches(LfNetwork network, VariableSet variableSet, EquationSystem equationSystem, AdmittanceType admittanceType) {
+ for (LfBranch branch : network.getBranches()) {
+ LfBus bus1 = branch.getBus1();
+ LfBus bus2 = branch.getBus2();
+ PiModel piModel = branch.getPiModel();
+ if (FastMath.abs(piModel.getX()) < LfBranch.LOW_IMPEDANCE_THRESHOLD) {
+ if (bus1 != null && bus2 != null) {
+ LOGGER.warn("Warning: Branch = {} : Non impedant lines not supported in the current version of the reduction method",
+ branch.getId());
+ }
+ } else {
+ //System.out.println("X(" + branch.getId() + ")= " + piModel.getX());
+ createImpedantBranch(variableSet, equationSystem, branch, bus1, bus2, admittanceType);
+ }
+ }
+ }
+
+ private static double getBfromShunt(LfBus bus) {
+ List feederList = new ArrayList<>();
+ return getBfromShunt(bus, feederList);
+ }
+
+ private static double getBfromShunt(LfBus bus, List feederList) {
+ LfShunt shunt = bus.getShunt().orElse(null);
+ double tmpB = 0.;
+ if (shunt != null) {
+ tmpB += shunt.getB();
+ EquationSystemFeeder shuntFeeder = new EquationSystemFeeder(shunt.getB(), 0., shunt.getId(), EquationSystemFeeder.FeederType.SHUNT);
+ feederList.add(shuntFeeder);
+ //check if g will be implemented
+ }
+ LfShunt controllerShunt = bus.getControllerShunt().orElse(null);
+ if (controllerShunt != null) {
+ tmpB += controllerShunt.getB();
+ EquationSystemFeeder shuntFeeder = new EquationSystemFeeder(shunt.getB(), 0., shunt.getId(), EquationSystemFeeder.FeederType.CONTROLLED_SHUNT);
+ feederList.add(shuntFeeder);
+ //check if g will be implemented
+ }
+
+ return tmpB;
+ }
+
+ private static Pair getYtransfromRdXd(LfBus bus, AdmittancePeriodType admittancePeriodType, List feederList, AdmittanceType admittanceType) {
+ double vnomVl = bus.getNominalV();
+
+ double tmpG = 0.;
+ double tmpB = 0.;
+ for (LfGenerator lfgen : bus.getGenerators()) { //compute R'd or R"d from generators at bus
+ ShortCircuitGenerator scGen = (ShortCircuitGenerator) lfgen.getProperty(ShortCircuitExtensions.PROPERTY_NAME);
+ double rd = scGen.getTransRd() + scGen.getStepUpTfoR();
+ double xd = scGen.getTransXd() + scGen.getStepUpTfoX();
+ if (admittancePeriodType == AdmittancePeriodType.ADM_SUB_TRANSIENT) {
+ xd = scGen.getSubTransXd() + scGen.getStepUpTfoX();
+ rd = scGen.getSubTransRd() + scGen.getStepUpTfoR();
+ }
+
+ double coeffR = 1.0; // coeff used to deduce Ro from Rd. It is equal to 1.0 if we are looking for direct values. If the machine is not grounded, homopolar values are zero, then we set coeffs to 0.
+ double coeffX = 1.0;
+ if (admittanceType == AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ coeffR = 0.;
+ coeffX = 0.;
+ if (scGen.isGrounded()) {
+ coeffR = scGen.getCoeffRo();
+ coeffX = scGen.getCoeffXo();
+ }
+ }
+
+ double epsilon = 0.0000001;
+
+ rd = rd * coeffR;
+ xd = xd * coeffX;
+
+ if (Math.abs(rd) > epsilon || Math.abs(xd) > epsilon) {
+ double gGen = (vnomVl * vnomVl / SB) * rd / (rd * rd + xd * xd);
+ double bGen = -(vnomVl * vnomVl / SB) * xd / (rd * rd + xd * xd);
+ tmpG = tmpG + gGen;
+ tmpB = tmpB + bGen; // TODO: check: for now X'd = 0 not allowed
+ EquationSystemFeeder shuntFeeder = new EquationSystemFeeder(bGen, gGen, lfgen.getId(), EquationSystemFeeder.FeederType.GENERATOR);
+ feederList.add(shuntFeeder);
+ }
+ }
+
+ Pair result = new Pair<>(tmpG, tmpB);
+ return result;
+ }
+
+ private static void createShunts(LfNetwork network, VariableSet variableSet, EquationSystem equationSystem, AdmittanceType admittanceType,
+ AdmittanceVoltageProfileType admittanceVoltageProfileType, AdmittancePeriodType admittancePeriodType,
+ boolean isShuntsIgnore, EquationSystemFeeders feeders) {
+ for (LfBus bus : network.getBuses()) {
+
+ //total shunt at bus to be integrated in the admittance matrix
+ double g = 0.;
+ double b = 0.;
+
+ //shunts created to represent the equivalence of loads and to be integrated in the total admittance matrix shunt at bus
+ double gLoadEq = 0.;
+ double bLoadEq = 0.;
+
+ //shunts created to represent the equivalence of generating units sand to be integrated in the total admittance matrix shunt at bus
+ double gGenEq = 0.;
+ double bGenEq = 0.;
+
+ //choice of vbase to be used to transform power injections into equivalent shunts
+ double vr = bus.getV() * Math.cos(bus.getAngle());
+ double vi = bus.getV() * Math.sin(bus.getAngle());
+ if (admittanceVoltageProfileType == AdmittanceVoltageProfileType.NOMINAL) {
+ vr = 1.0; //TODO: check if Vnom or Vnom/Vbase
+ vi = 0.;
+ }
+ boolean isBusPv = bus.isVoltageControlled();
+
+ if (admittanceType == AdmittanceType.ADM_SHUNT) {
+ if (!isShuntsIgnore) {
+ b = getBfromShunt(bus); // Handling shunts that physically exist
+ }
+ } else if (admittanceType == AdmittanceType.ADM_ADMIT) {
+ if (!isShuntsIgnore) {
+ b = getBfromShunt(bus); // Handling shunts that physically exist
+ }
+ gLoadEq = bus.getLoadTargetP() / (vr * vr + vi * vi); // Handling transformation of bus loads into equivalent shunts
+ bLoadEq = -bus.getLoadTargetQ() / (vr * vr + vi * vi);
+ // Handling transformation of generators into equivalent shunts
+ // Warning !!! : evaluation of power injections mandatory
+ gGenEq = -(bus.getP().eval() + bus.getLoadTargetP()) / (vr * vr + vi * vi); // full nodal P injection without the load
+
+ if (isBusPv) {
+ bGenEq = (bus.getQ().eval() + bus.getLoadTargetQ()) / (vr * vr + vi * vi); // full nodal Q injection without the load
+ } else {
+ bGenEq = bus.getGenerationTargetQ() / (vr * vr + vi * vi);
+ }
+ } else if (admittanceType == AdmittanceType.ADM_THEVENIN) {
+
+ List feederList = new ArrayList<>();
+
+ if (!isShuntsIgnore) {
+ // Handling shunts that physically exist
+ b = getBfromShunt(bus, feederList); // ! updates feederList
+ }
+ gLoadEq = bus.getLoadTargetP() / (vr * vr + vi * vi); // Handling transformation of bus loads into equivalent shunts
+ bLoadEq = -bus.getLoadTargetQ() / (vr * vr + vi * vi);
+
+ EquationSystemFeeder shuntFeeder = new EquationSystemFeeder(bLoadEq, gLoadEq, bus.getId(), EquationSystemFeeder.FeederType.LOAD);
+ feederList.add(shuntFeeder);
+
+ Pair bAndG = getYtransfromRdXd(bus, admittancePeriodType, feederList, admittanceType); // ! updates feederList
+ bGenEq = bAndG.getValue(); //TODO : check how the verify that the generators are operating
+ gGenEq = bAndG.getKey();
+
+ //shortCircuitNetwork.busToFeeder.put(bus, feederList);
+ EquationSystemBusFeeders shortCircuitEquationSystemBusFeeders = new EquationSystemBusFeeders(feederList, bus);
+ feeders.busToFeeders.put(bus, shortCircuitEquationSystemBusFeeders);
+
+ } else if (admittanceType == AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+
+ List feederList = new ArrayList<>(); // not used yet in homopolar
+
+ Pair bAndG = getYtransfromRdXd(bus, admittancePeriodType, feederList, admittanceType); // ! updates feederList
+ bGenEq = bAndG.getValue(); //TODO : check how the verify that the generators are operating
+ gGenEq = bAndG.getKey();
+
+ }
+
+ g = g + gLoadEq + gGenEq;
+ b = b + bLoadEq + bGenEq;
+
+ //System.out.println("result = g(" + bus.getId() + ")= " + g);
+ //System.out.println("result = b(" + bus.getId() + ")= " + b);
+
+ if (Math.abs(g) > EPSILON || Math.abs(b) > EPSILON) {
+ equationSystem.createEquation(bus.getNum(), EquationType.BUS_YR)
+ .addTerm(new AdmittanceEquationTermShunt(g, b, bus, variableSet, true));
+ equationSystem.createEquation(bus.getNum(), EquationType.BUS_YI)
+ .addTerm(new AdmittanceEquationTermShunt(g, b, bus, variableSet, false));
+ }
+ }
+ }
+
+ public static EquationSystem create(LfNetwork network, VariableSet variableSet,
+ AdmittanceType admittanceType, AdmittanceVoltageProfileType admittanceVoltageProfileType,
+ AcLoadFlowParameters acLoadFlowParameters) {
+
+ // Following data Not needed for reduction methods
+ AdmittanceEquationSystem.AdmittancePeriodType admittancePeriodType = AdmittanceEquationSystem.AdmittancePeriodType.ADM_TRANSIENT; //TODO: not relevant for reduction: see how to improve that
+ EquationSystemFeeders equationsSystemFeeders = new EquationSystemFeeders();
+ boolean isShuntsIgnore = false;
+
+ return create(network, variableSet,
+ admittanceType, admittanceVoltageProfileType, admittancePeriodType, isShuntsIgnore,
+ equationsSystemFeeders, acLoadFlowParameters);
+ }
+
+ public static EquationSystem create(LfNetwork network, VariableSet variableSet,
+ AdmittanceType admittanceType, AdmittanceVoltageProfileType admittanceVoltageProfileType,
+ AdmittancePeriodType admittancePeriodType, boolean isShuntsIgnore, EquationSystemFeeders feeders,
+ AcLoadFlowParameters acLoadFlowParameters) {
+
+ EquationSystem equationSystem = new EquationSystem<>();
+
+ if (admittanceType == AdmittanceType.ADM_ADMIT) {
+ try (AcLoadFlowContext context = new AcLoadFlowContext(network, acLoadFlowParameters)) {
+ new AcloadFlowEngine(context)
+ .run();
+ }
+ }
+
+ createBranches(network, variableSet, equationSystem, admittanceType);
+ if (admittanceType != AdmittanceType.ADM_INJ) { //shunts created in the admittance matrix are only those that really exist in the network
+ createShunts(network, variableSet, equationSystem, admittanceType, admittanceVoltageProfileType, admittancePeriodType, isShuntsIgnore, feeders); // TODO : shuntIgnore was set at false
+ }
+
+ return equationSystem;
+ }
+
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermShunt.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermShunt.java
new file mode 100644
index 00000000..202212e4
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermShunt.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.openloadflow.equations.AbstractNamedEquationTerm;
+import com.powsybl.openloadflow.equations.Variable;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.ElementType;
+import com.powsybl.openloadflow.network.LfBus;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class AdmittanceEquationTermShunt extends AbstractNamedEquationTerm implements LinearEquationTerm {
+
+ private final LfBus bus;
+
+ protected final Variable v1rVar;
+
+ protected final Variable v1iVar;
+
+ protected final List> variables;
+
+ protected double g;
+
+ protected double b;
+
+ protected boolean isReal;
+ // v1r v1i
+ // | |
+ //Eq1r - [ y1r1r y1r1i ] [ g -b ]
+ //Eq1i - [ y1i1r y1i1i ] = [ b g ] =
+
+ public AdmittanceEquationTermShunt(double g, double b, LfBus bus, VariableSet variableSet, boolean isReal) {
+ this.bus = Objects.requireNonNull(bus);
+ Objects.requireNonNull(variableSet);
+
+ v1rVar = variableSet.getVariable(bus.getNum(), VariableType.BUS_VR);
+ v1iVar = variableSet.getVariable(bus.getNum(), VariableType.BUS_VI);
+
+ variables = List.of(v1rVar, v1iVar);
+
+ this.g = g;
+ this.b = b;
+ this.isReal = isReal;
+
+ }
+
+ @Override
+ public ElementType getElementType() {
+ return ElementType.BUS;
+ }
+
+ @Override
+ public int getElementNum() {
+ return bus.getNum();
+ }
+
+ public List> getVariables() {
+ return variables;
+ }
+
+ @Override
+ public double eval() {
+ throw new UnsupportedOperationException("Not needed");
+ }
+
+ @Override
+ public double der(Variable variable) {
+ throw new UnsupportedOperationException("Not needed");
+ }
+
+ @Override
+ public boolean hasRhs() {
+ return false;
+ }
+
+ @Override
+ public double rhs() {
+ return 0;
+ }
+
+ @Override
+ public double getCoefficient(Variable variable) {
+ if (variable.equals(v1rVar)) {
+ if (isReal) {
+ return g;
+ } else {
+ return b;
+ }
+ } else if (variable.equals(v1iVar)) {
+ if (isReal) {
+ return -b;
+ } else {
+ return g;
+ }
+ } else {
+ throw new IllegalArgumentException("Unknown variable " + variable);
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return "yshunt";
+ }
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermX1.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermX1.java
new file mode 100644
index 00000000..72366109
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermX1.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.openloadflow.equations.Variable;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfBus;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class AdmittanceEquationTermX1 extends AbstractAdmittanceEquationTerm {
+
+ private final double g12;
+
+ private final double b12;
+
+ private final double g1g12sum;
+
+ private final double b1b12sum;
+
+ public AdmittanceEquationTermX1(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, AdmittanceEquationSystem.AdmittanceType admittanceType) {
+ super(branch, bus1, bus2, variableSet);
+ // Direct component:
+ // I1x = (g1 + g12)V1x - (b1 + b12)V1y - g12 * V2x + b12 * V2y
+ if (admittanceType == AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ HomopolarModel homopolarModel = HomopolarModel.build(branch);
+ if (branch.getBranchType() == LfBranch.BranchType.LINE) {
+ // default if branch type is a line
+ g12 = rho * homopolarModel.getZoInvSquare() * (homopolarModel.getRo() * cosA + homopolarModel.getXo() * sinA);
+ b12 = -rho * homopolarModel.getZoInvSquare() * (homopolarModel.getXo() * cosA + homopolarModel.getRo() * sinA);
+ g1g12sum = rho * rho * (homopolarModel.getGom() + homopolarModel.getRo() * homopolarModel.getZoInvSquare());
+ b1b12sum = rho * rho * (homopolarModel.getBom() - homopolarModel.getXo() * homopolarModel.getZoInvSquare());
+ } else if (branch.getBranchType() == LfBranch.BranchType.TRANSFO_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_1
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_3) {
+ // case where branch is part of a transformer
+ DenseMatrix mo = homopolarModel.computeHomopolarAdmittanceMatrix();
+ b1b12sum = -mo.get(0, 1);
+ g1g12sum = mo.get(0, 0);
+ b12 = mo.get(0, 3);
+ g12 = -mo.get(0, 2);
+ } else {
+ throw new IllegalArgumentException("branch type not yet handled");
+ }
+ } else {
+ g12 = rho * zInvSquare * (r * cosA + x * sinA);
+ b12 = -rho * zInvSquare * (x * cosA + r * sinA);
+ g1g12sum = rho * rho * (gPi1 + r * zInvSquare);
+ b1b12sum = rho * rho * (bPi1 - x * zInvSquare);
+ }
+ }
+
+ @Override
+ public double getCoefficient(Variable variable) {
+ if (variable.equals(v1rVar)) {
+ return g1g12sum;
+ } else if (variable.equals(v2rVar)) {
+ return -g12;
+ } else if (variable.equals(v1iVar)) {
+ return -b1b12sum;
+ } else if (variable.equals(v2iVar)) {
+ return b12;
+ } else {
+ throw new IllegalArgumentException("Unknown variable " + variable);
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return "yr1";
+ }
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermX2.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermX2.java
new file mode 100644
index 00000000..ed906415
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermX2.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.openloadflow.equations.Variable;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfBus;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class AdmittanceEquationTermX2 extends AbstractAdmittanceEquationTerm {
+
+ private final double g21;
+
+ private final double b21;
+
+ private final double g2g21sum;
+
+ private final double b2b21sum;
+
+ public AdmittanceEquationTermX2(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, AdmittanceEquationSystem.AdmittanceType admittanceType) {
+ super(branch, bus1, bus2, variableSet);
+ // Direct component:
+ // I2x = -g21 * V1x + b21 * V1y + (g2 + g21)V2x - (b2 + b21)V2y
+ if (admittanceType == AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ HomopolarModel homopolarModel = HomopolarModel.build(branch);
+ if (branch.getBranchType() == LfBranch.BranchType.LINE) {
+ g21 = rho * homopolarModel.getZoInvSquare() * (homopolarModel.getRo() * cosA + homopolarModel.getXo() * sinA);
+ b21 = rho * homopolarModel.getZoInvSquare() * (homopolarModel.getRo() * sinA - homopolarModel.getXo() * cosA);
+ g2g21sum = homopolarModel.getRo() * homopolarModel.getZoInvSquare() + gPi2 * AdmittanceConstants.COEF_XO_XD;
+ b2b21sum = -homopolarModel.getXo() * homopolarModel.getZoInvSquare() + bPi2 * AdmittanceConstants.COEF_XO_XD;
+ } else if (branch.getBranchType() == LfBranch.BranchType.TRANSFO_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_1
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_3) {
+ // case where branch is part of a transformer
+ DenseMatrix mo = homopolarModel.computeHomopolarAdmittanceMatrix();
+ b2b21sum = -mo.get(2, 3);
+ g2g21sum = mo.get(2, 2);
+ b21 = mo.get(2, 1);
+ g21 = -mo.get(2, 0);
+ } else {
+ throw new IllegalArgumentException("branch type not yet handled");
+ }
+ } else {
+ double g12 = rho * zInvSquare * (r * cosA + x * sinA);
+ g21 = g12;
+ b21 = rho * zInvSquare * (r * sinA - x * cosA);
+ g2g21sum = r * zInvSquare + gPi2;
+ b2b21sum = -x * zInvSquare + bPi2;
+ }
+ }
+
+ @Override
+ public double getCoefficient(Variable variable) {
+ if (variable.equals(v1rVar)) {
+ return -g21;
+ } else if (variable.equals(v2rVar)) {
+ return g2g21sum;
+ } else if (variable.equals(v1iVar)) {
+ return b21;
+ } else if (variable.equals(v2iVar)) {
+ return -b2b21sum;
+ } else {
+ throw new IllegalArgumentException("Unknown variable " + variable);
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return "yr2";
+ }
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermY1.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermY1.java
new file mode 100644
index 00000000..e25d11d9
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermY1.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.openloadflow.equations.Variable;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfBus;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class AdmittanceEquationTermY1 extends AbstractAdmittanceEquationTerm {
+
+ private final double g12;
+
+ private final double b12;
+
+ private final double g1g12sum;
+
+ private final double b1b12sum;
+
+ public AdmittanceEquationTermY1(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, AdmittanceEquationSystem.AdmittanceType admittanceType) {
+ super(branch, bus1, bus2, variableSet);
+ // Direct component:
+ // I1y = (b1 + b12)V1x + (g1 + g12)V1y - b12 * V2x - g12 * V2y
+ if (admittanceType == AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ HomopolarModel homopolarModel = HomopolarModel.build(branch);
+ if (branch.getBranchType() == LfBranch.BranchType.LINE) {
+ // case where branch is a line with available homopolar parameters
+ g12 = rho * homopolarModel.getZoInvSquare() * (homopolarModel.getRo() * cosA + homopolarModel.getXo() * sinA);
+ b12 = -rho * homopolarModel.getZoInvSquare() * (homopolarModel.getXo() * cosA + homopolarModel.getRo() * sinA);
+ g1g12sum = rho * rho * (homopolarModel.getGom() + homopolarModel.getRo() * homopolarModel.getZoInvSquare());
+ b1b12sum = rho * rho * (homopolarModel.getBom() - homopolarModel.getXo() * homopolarModel.getZoInvSquare());
+ } else if (branch.getBranchType() == LfBranch.BranchType.TRANSFO_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_1
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_3) {
+ // case where branch is part of a transformer
+ DenseMatrix mo = homopolarModel.computeHomopolarAdmittanceMatrix();
+ b1b12sum = mo.get(1, 0);
+ g1g12sum = mo.get(1, 1);
+ b12 = -mo.get(1, 2);
+ g12 = -mo.get(1, 3);
+ } else {
+ throw new IllegalArgumentException("branch type not yet handled");
+ }
+ } else {
+ g12 = rho * zInvSquare * (r * cosA + x * sinA);
+ b12 = -rho * zInvSquare * (x * cosA + r * sinA);
+ g1g12sum = rho * rho * (gPi1 + r * zInvSquare);
+ b1b12sum = rho * rho * (bPi1 - x * zInvSquare);
+ }
+ }
+
+ @Override
+ public double getCoefficient(Variable variable) {
+ if (variable.equals(v1rVar)) {
+ return b1b12sum;
+ } else if (variable.equals(v2rVar)) {
+ return -b12;
+ } else if (variable.equals(v1iVar)) {
+ return g1g12sum;
+ } else if (variable.equals(v2iVar)) {
+ return -g12;
+ } else {
+ throw new IllegalArgumentException("Unknown variable " + variable);
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return "yi1";
+ }
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermY2.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermY2.java
new file mode 100644
index 00000000..3d86f92c
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceEquationTermY2.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.openloadflow.equations.Variable;
+import com.powsybl.openloadflow.equations.VariableSet;
+import com.powsybl.openloadflow.network.LfBranch;
+import com.powsybl.openloadflow.network.LfBus;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class AdmittanceEquationTermY2 extends AbstractAdmittanceEquationTerm {
+
+ private final double g21;
+
+ private final double b21;
+
+ private final double g2g21sum;
+
+ private final double b2b21sum;
+
+ public AdmittanceEquationTermY2(LfBranch branch, LfBus bus1, LfBus bus2, VariableSet variableSet, AdmittanceEquationSystem.AdmittanceType admittanceType) {
+ super(branch, bus1, bus2, variableSet);
+ // Direct component:
+ // I2y = -b21 * V1x - g21 * V1y + (b2 + b21)V2x + (g2 + g21)V2y
+ if (admittanceType == AdmittanceEquationSystem.AdmittanceType.ADM_THEVENIN_HOMOPOLAR) {
+ HomopolarModel homopolarModel = HomopolarModel.build(branch);
+ if (branch.getBranchType() == LfBranch.BranchType.LINE) {
+ // case where branch is a line with available homopolar parameters
+ g21 = rho * homopolarModel.getZoInvSquare() * (homopolarModel.getRo() * cosA + homopolarModel.getXo() * sinA);
+ b21 = rho * homopolarModel.getZoInvSquare() * (homopolarModel.getRo() * sinA - homopolarModel.getXo() * cosA);
+ g2g21sum = homopolarModel.getRo() * homopolarModel.getZoInvSquare() + gPi2 * AdmittanceConstants.COEF_XO_XD;
+ b2b21sum = -homopolarModel.getXo() * homopolarModel.getZoInvSquare() + bPi2 * AdmittanceConstants.COEF_XO_XD;
+ } else if (branch.getBranchType() == LfBranch.BranchType.TRANSFO_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_1
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_2
+ || branch.getBranchType() == LfBranch.BranchType.TRANSFO_3_LEG_3) {
+ // case where branch is part of a transformer
+ DenseMatrix mo = homopolarModel.computeHomopolarAdmittanceMatrix();
+ b2b21sum = mo.get(3, 2);
+ g2g21sum = mo.get(3, 3);
+ b21 = -mo.get(3, 0);
+ g21 = -mo.get(3, 1);
+ } else {
+ throw new IllegalArgumentException("branch type not yet handled");
+ }
+ } else {
+ double g12 = rho * zInvSquare * (r * cosA + x * sinA);
+ g21 = g12;
+ b21 = rho * zInvSquare * (r * sinA - x * cosA);
+ g2g21sum = r * zInvSquare + gPi2;
+ b2b21sum = -x * zInvSquare + bPi2;
+ }
+ }
+
+ @Override
+ public double getCoefficient(Variable variable) {
+ if (variable.equals(v1rVar)) {
+ return -b21;
+ } else if (variable.equals(v2rVar)) {
+ return b2b21sum;
+ } else if (variable.equals(v1iVar)) {
+ return -g21;
+ } else if (variable.equals(v2iVar)) {
+ return g2g21sum;
+ } else {
+ throw new IllegalArgumentException("Unknown variable " + variable);
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return "yi2";
+ }
+}
diff --git a/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceMatrix.java b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceMatrix.java
new file mode 100644
index 00000000..ef69777b
--- /dev/null
+++ b/simulator/util/src/main/java/com/powsybl/incubator/simulator/util/AdmittanceMatrix.java
@@ -0,0 +1,390 @@
+/**
+ * Copyright (c) 2022, Jean-Baptiste Heyberger & Geoffroy Jamgotchian
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package com.powsybl.incubator.simulator.util;
+
+import com.powsybl.math.matrix.DenseMatrix;
+import com.powsybl.math.matrix.LUDecomposition;
+import com.powsybl.math.matrix.Matrix;
+import com.powsybl.math.matrix.MatrixFactory;
+import com.powsybl.openloadflow.equations.*;
+import com.powsybl.openloadflow.network.LfBus;
+import com.powsybl.openloadflow.network.LfNetwork;
+import com.powsybl.openloadflow.network.util.VoltageInitializer;
+
+import java.util.*;
+
+/**
+ * @author Jean-Baptiste Heyberger
+ */
+public class AdmittanceMatrix implements AutoCloseable {
+
+ public class AdmittanceSystem {
+
+ //created to extract a subset of the equationSystem to easily create admittance subMatrices for the reduction problem while keeping consistency on the global equation system
+ private Set numRowBusses;
+
+ private Set numColBusses;
+
+ public Map, Integer> eqToRowNum;
+
+ public Map, Integer> varToColNum;
+
+ public boolean isSubAdmittance;
+
+ AdmittanceSystem() {
+
+ numRowBusses = new HashSet<>();
+ numColBusses = new HashSet<>();
+
+ eqToRowNum = new HashMap<>();
+ varToColNum = new HashMap<>();
+
+ //Convert rowBusses and columnBusses Sets into eq number Sets
+ if (rowBusses != null) {
+ for (LfBus b : rowBusses) {
+ numRowBusses.add(b.getNum());
+ }
+ }
+
+ if (columnBusses != null) {
+ for (LfBus b : columnBusses) {
+ numColBusses.add(b.getNum());
+ }
+ }
+
+ isSubAdmittance = numRowBusses.size() > 0 || numColBusses.size() > 0; //if false then build the full admittance system based on the equationSystem infos
+
+ if (isSubAdmittance) {
+ int nbRow = 0;
+ int nbCol = 0;
+ for (var eq : equationSystem.getIndex().getSortedEquationsToSolve()) {
+ int numBusEq = eq.getElementNum();
+ if (numRowBusses.contains(numBusEq)) {
+ eqToRowNum.put(eq, nbRow++);
+ }
+ }
+
+ for (Variable v : equationSystem.getIndex().getSortedVariablesToFind()) {
+ int numBusVar = v.getElementNum();
+ if (numColBusses.contains(numBusVar)) {
+ varToColNum.put(v, nbCol++);
+ }
+ }
+ }
+ }
+ }
+
+ private final EquationSystem equationSystem;
+
+ private final LfNetwork lfNetwork;
+
+ private final MatrixFactory matrixFactory;
+
+ private Matrix matrix;
+
+ private LUDecomposition lu;
+
+ private Set rowBusses;
+
+ private Set columnBusses;
+
+ private AdmittanceSystem admSys;
+
+ private List busNumToRowR; //given a number of bus, provides the Row and Column to the matrix
+ private List busNumToColR;
+ private List busNumToRowI; //given a number of bus, provides the Row and Column to the matrix
+ private List busNumToColI;
+
+ public AdmittanceMatrix(EquationSystem equationSystem, MatrixFactory matrixFactory, LfNetwork network) {
+ this.equationSystem = Objects.requireNonNull(equationSystem);
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ this.admSys = new AdmittanceSystem();
+ this.lfNetwork = Objects.requireNonNull(network);
+ initAdmittanceSystem();
+ }
+
+ public AdmittanceMatrix(EquationSystem equationSystem, MatrixFactory matrixFactory, Set rowBusses, Set columnBusses, LfNetwork network) {
+ this.equationSystem = Objects.requireNonNull(equationSystem);
+ this.matrixFactory = Objects.requireNonNull(matrixFactory);
+ this.rowBusses = Objects.requireNonNull(rowBusses);
+ this.columnBusses = Objects.requireNonNull(columnBusses);
+ this.admSys = new AdmittanceSystem();
+ this.lfNetwork = Objects.requireNonNull(network);
+ initAdmittanceSystem();
+ }
+
+ public AdmittanceSystem getAdmSys() {
+ return admSys;
+ }
+
+ public EquationSystem getEquationSystem() {
+ return equationSystem;
+ }
+
+ private void clear() {
+ matrix = null;
+ if (lu != null) {
+ lu.close();
+ }
+ lu = null;
+ }
+
+ public int getRowCount() {
+ int rowCount = equationSystem.getIndex().getSortedEquationsToSolve().size();
+ if (admSys.isSubAdmittance) {
+ rowCount = admSys.eqToRowNum.size();
+ }
+ return rowCount;
+ }
+
+ public int getColCount() {
+ int columnCount = equationSystem.getIndex().getSortedVariablesToFind().size();
+ if (admSys.isSubAdmittance) {
+ columnCount = admSys.varToColNum.size();
+ }
+ return columnCount;
+ }
+
+ private Map