Skip to content

Commit

Permalink
Merge branch 'main' into feature/source-calculation-using-ybus
Browse files Browse the repository at this point in the history
  • Loading branch information
mgovers authored Jun 20, 2024
2 parents 8339285 + e2652ff commit 2287bc5
Show file tree
Hide file tree
Showing 19 changed files with 672 additions and 189 deletions.
12 changes: 12 additions & 0 deletions code_generation/data/dataset_class_maps/dataset_definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
"names": ["transformer"],
"class_name": "TransformerInput"
},
{
"names": ["transformer_tap_regulator"],
"class_name": "TransformerTapRegulatorInput"
},
{
"names": ["three_winding_transformer"],
"class_name": "ThreeWindingTransformerInput"
Expand Down Expand Up @@ -62,6 +66,10 @@
"names": ["line", "link", "transformer"],
"class_name": "BranchOutput"
},
{
"names": ["transformer_tap_regulator"],
"class_name": "TransformerTapRegulatorOutput"
},
{
"names": ["three_winding_transformer"],
"class_name": "Branch3Output"
Expand Down Expand Up @@ -104,6 +112,10 @@
"names": ["transformer"],
"class_name": "TransformerUpdate"
},
{
"names": ["transformer_tap_regulator"],
"class_name": "TransformerTapRegulatorUpdate"
},
{
"names": ["three_winding_transformer"],
"class_name": "ThreeWindingTransformerUpdate"
Expand Down
4 changes: 2 additions & 2 deletions docs/user_manual/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ levels. An example of usage of transformer is given in [Transformer Examples](..
| `winding_to` | {py:class}`WindingType <power_grid_model.enum.WindingType>` | - | to-side winding type | &#10004; | &#10060; | |
| `clock` | `int8_t` | - | clock number of phase shift. <br> Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. <br> Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | &#10004; | &#10060; | `>= 0` and `<= 12` |
| `tap_side` | {py:class}`BranchSide <power_grid_model.enum.BranchSide>` | - | side of tap changer | &#10004; | &#10060; | |
| `tap_pos` | `int8_t` | - | current position of tap changer | &#10004; | &#10004; | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` |
| `tap_pos` | `int8_t` | - | current position of tap changer | &#10060; default `tap_nom`, if no `tap_nom` default `0` | &#10004; | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` |
| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | &#10004; | &#10060; | |
| `tap_max` | `int8_t` | - | position of tap changer at maximum voltage | &#10004; | &#10060; | |
| `tap_nom` | `int8_t` | - | nominal position of tap changer | &#10060; default `0` | &#10060; | `(tap_min <= tap_nom <= tap_max)` or `(tap_min >= tap_nom >= tap_max)` |
Expand Down Expand Up @@ -301,7 +301,7 @@ voltage levels. An example of usage of three-winding transformer is given in [Tr
| `clock_12` | `int8_t` | - | clock number of phase shift across side 1-2, odd number is only allowed for Dy(n) or Y(N)d configuration. | &#10004; | &#10060; | `>= 0` and `<= 12` |
| `clock_13` | `int8_t` | - | clock number of phase shift across side 1-3, odd number is only allowed for Dy(n) or Y(N)d configuration. | &#10004; | &#10060; | `>= 0` and `<= 12` |
| `tap_side` | {py:class}`Branch3Side <power_grid_model.enum.Branch3Side>` | - | side of tap changer | &#10004; | &#10060; | `side_1` or `side_2` or `side_3` |
| `tap_pos` | `int8_t` | - | current position of tap changer | &#10004; | &#10004; | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` |
| `tap_pos` | `int8_t` | - | current position of tap changer | &#10060; default `tap_nom`, if no `tap_nom` default `0` | &#10004; | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` |
| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | &#10004; | &#10060; | |
| `tap_max` | `int8_t` | - | position of tap changer at maximum voltage | &#10004; | &#10060; | |
| `tap_nom` | `int8_t` | - | nominal position of tap changer | &#10060; default `0` | &#10060; | `(tap_min <= tap_nom <= tap_max)` or `(tap_min >= tap_nom >= tap_max)` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,11 @@ class ThreeWindingTransformer : public Branch3 {
clock_12_{three_winding_transformer_input.clock_12},
clock_13_{three_winding_transformer_input.clock_13},
tap_side_{three_winding_transformer_input.tap_side},
tap_pos_{three_winding_transformer_input.tap_pos},
tap_min_{three_winding_transformer_input.tap_min},
tap_max_{three_winding_transformer_input.tap_max},
tap_nom_{three_winding_transformer_input.tap_nom == na_IntS ? (IntS)0
tap_nom_{three_winding_transformer_input.tap_nom == na_IntS ? IntS{0}
: three_winding_transformer_input.tap_nom},
tap_direction_{tap_max_ > tap_min_ ? (IntS)1 : (IntS)-1},
tap_direction_{tap_max_ > tap_min_ ? IntS{1} : IntS{-1}},
tap_size_{three_winding_transformer_input.tap_size},
uk_12_min_{is_nan(three_winding_transformer_input.uk_12_min) ? uk_12_
: three_winding_transformer_input.uk_12_min},
Expand Down Expand Up @@ -79,6 +78,14 @@ class ThreeWindingTransformer : public Branch3 {
z_grounding_1_{three_winding_transformer_input.r_grounding_1, three_winding_transformer_input.x_grounding_1},
z_grounding_2_{three_winding_transformer_input.r_grounding_2, three_winding_transformer_input.x_grounding_2},
z_grounding_3_{three_winding_transformer_input.r_grounding_3, three_winding_transformer_input.x_grounding_3} {
// init tap_pos_ linter smell
if (three_winding_transformer_input.tap_pos == na_IntS) {
tap_pos_ =
three_winding_transformer_input.tap_nom == na_IntS ? IntS{0} : three_winding_transformer_input.tap_nom;
} else {
tap_pos_ = three_winding_transformer_input.tap_pos;
}

if (!is_valid_clock(clock_12_, winding_1_, winding_2_)) {
throw InvalidTransformerClock{id(), clock_12_};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ class Transformer : public Branch {
winding_to_{transformer_input.winding_to},
clock_{transformer_input.clock},
tap_side_{transformer_input.tap_side},
tap_pos_{transformer_input.tap_pos},
tap_min_{transformer_input.tap_min},
tap_max_{transformer_input.tap_max},
tap_nom_{transformer_input.tap_nom == na_IntS ? (IntS)0 : transformer_input.tap_nom},
tap_direction_{tap_max_ > tap_min_ ? (IntS)1 : (IntS)-1},
tap_nom_{transformer_input.tap_nom == na_IntS ? IntS{0} : transformer_input.tap_nom},
tap_direction_{tap_max_ > tap_min_ ? IntS{1} : IntS{-1}},
uk_min_{is_nan(transformer_input.uk_min) ? uk_ : transformer_input.uk_min},
uk_max_{is_nan(transformer_input.uk_max) ? uk_ : transformer_input.uk_max},
pk_min_{is_nan(transformer_input.pk_min) ? pk_ : transformer_input.pk_min},
Expand All @@ -53,6 +52,13 @@ class Transformer : public Branch {
calculate_z_pu(transformer_input.r_grounding_from, transformer_input.x_grounding_from, u1_rated)},
z_grounding_to_{
calculate_z_pu(transformer_input.r_grounding_to, transformer_input.x_grounding_to, u2_rated)} {
// init tap_pos_ linter smell
if (transformer_input.tap_pos == na_IntS) {
tap_pos_ = transformer_input.tap_nom == na_IntS ? IntS{0} : transformer_input.tap_nom;
} else {
tap_pos_ = transformer_input.tap_pos;
}

if (!is_valid_clock(clock_, winding_from_, winding_to_)) {
throw InvalidTransformerClock{id(), clock_};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org>
//
// SPDX-License-Identifier: MPL-2.0

#pragma once

#include "common/common.hpp"

#include <algorithm>
#include <cassert>
#include <compare>
#include <map>
#include <set>
#include <utility>
#include <vector>

namespace power_grid_model {

namespace detail {
class DegreeLookup {
public:
void set(Idx u, Idx degree) {
if (auto degree_it = vertex_to_degree.find(u); degree_it != vertex_to_degree.end()) {
remove_degree(u, degree_it->second);
degree_it->second = degree;
} else {
vertex_to_degree.try_emplace(u, degree);
}
degrees_to_vertex[degree].insert(u);
}

void erase(Idx u) {
auto vertex_it = vertex_to_degree.find(u);
if (vertex_it == vertex_to_degree.end()) {
return;
}
Idx const degree = vertex_it->second;
vertex_to_degree.erase(vertex_it);
remove_degree(u, degree);
}

friend auto min_element(DegreeLookup const& dgd);

private:
void remove_degree(Idx u, Idx degree) {
if (auto degree_it = degrees_to_vertex.find(degree); degree_it != degrees_to_vertex.end()) {
degree_it->second.erase(u);
if (degree_it->second.empty()) {
degrees_to_vertex.erase(degree_it);
}
}
}

std::map<Idx, Idx> vertex_to_degree;
std::map<Idx, std::set<Idx>> degrees_to_vertex;
};

inline auto min_element(DegreeLookup const& dgd) {
Idx const vertex = *dgd.degrees_to_vertex.begin()->second.begin();
return dgd.vertex_to_degree.find(vertex);
}

inline void remove_element_degree(Idx u, DegreeLookup& dgd) { dgd.erase(u); }

inline void set_element_degree(Idx u, Idx degree, DegreeLookup& dgd) { dgd.set(u, degree); }

inline Idx num_adjacent(Idx const u, std::map<Idx, IdxVector> const& d) {
if (auto it = d.find(u); it != d.end()) {
return static_cast<Idx>(it->second.size());
}
return 0;
}

inline IdxVector const& adj(Idx const u, std::map<Idx, IdxVector> const& d) { return d.at(u); }

inline std::vector<std::pair<Idx, DegreeLookup>> comp_size_degrees_graph(std::map<Idx, IdxVector> const& d) {
DegreeLookup dd;
IdxVector v;

for (auto const& [k, adjacent] : d) {
v.push_back(k);
set_element_degree(k, static_cast<Idx>(adjacent.size()), dd);
}

return {{d.size(), dd}};
}

inline std::map<Idx, IdxVector> make_clique(IdxVector& l) {
std::map<Idx, IdxVector> d;

for (Idx i = 0; i < static_cast<Idx>(l.size()); i++) {
IdxVector sl(l.size() - 1);
std::copy(l.begin(), l.begin() + i, sl.begin());
std::copy(l.begin() + i + 1, l.end(), sl.begin() + i);
d[l[i]] = std::move(sl);
}

return d;
}

inline std::vector<std::pair<IdxVector, IdxVector>> check_indistguishable(Idx const u,
std::map<Idx, IdxVector> const& d) {
IdxVector rl;

auto l = adj(u, d);
auto lu = l;
lu.push_back(u);
std::ranges::sort(lu);

for (auto const& v : l) {
auto lv = adj(v, d);
lv.push_back(v);
std::ranges::sort(lv);
if (lu == lv) {
rl.push_back(v);
}
}

return {{l, rl}};
}

inline bool in_graph(std::pair<Idx, Idx> const& e, std::map<Idx, IdxVector> const& d) {
if (auto edges_it = d.find(e.first);
edges_it != d.cend() && std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) {
return true;
}
return false;
}

inline IdxVector remove_vertices_update_degrees(Idx const u, std::map<Idx, IdxVector>& d, DegreeLookup& dgd,
std::vector<std::pair<Idx, Idx>>& fills) {
std::vector<std::pair<IdxVector, IdxVector>> nbsrl = check_indistguishable(u, d);
auto& [nbs, rl] = nbsrl[0];
IdxVector alpha = rl;
std::map<Idx, IdxVector> dd;

rl.push_back(u);

for (auto uu : rl) {
if (uu != u) {
std::erase(nbs, uu);
}

remove_element_degree(uu, dgd);
IdxVector el;
for (auto e : d[uu]) {
auto& adjacents = d[e];
std::erase(adjacents, uu);
if (adjacents.empty()) {
el.push_back(e);
}
}

el.push_back(uu);

for (auto const& it : el) {
d.erase(it);
}
}

dd = make_clique(nbs);

for (auto const& [k, adjacent] : dd) {
auto it = d.find(k);
for (Idx const e : adjacent) {
if (!in_graph(std::make_pair(k, e), d)) {
if (it == d.end()) {
std::tie(it, std::ignore) = d.try_emplace(k);
}
it->second.push_back(e);
d[e].push_back(k);
fills.emplace_back(k, e);
}
}
}

for (auto const& e : nbs) {
set_element_degree(e, num_adjacent(e, d), dgd);
}

return alpha;
}
} // namespace detail

inline std::pair<IdxVector, std::vector<std::pair<Idx, Idx>>> minimum_degree_ordering(std::map<Idx, IdxVector> d) {
// make symmetric
for (auto const& [k, adjacent] : d) {
for (auto e : adjacent) {
d[e].push_back(k);
}
}
for (auto& [k, adjacent] : d) {
std::set<Idx> const unique_sorted_adjacent{adjacent.begin(), adjacent.end()};
adjacent = IdxVector{unique_sorted_adjacent.begin(), unique_sorted_adjacent.end()};
}

auto data = detail::comp_size_degrees_graph(d);
auto& [n, dgd] = data[0];

IdxVector alpha;
std::vector<std::pair<Idx, Idx>> fills;

for (Idx k = 0; k < n; ++k) {
Idx const u = get<0>(*detail::min_element(dgd));
alpha.push_back(u);
if (d.size() == 2) {
assert(d.begin()->second.size() == 1);

Idx const from = d.begin()->first;
Idx const to = d.begin()->second[0];
alpha.push_back(alpha.back() == from ? to : from);
return {alpha, fills};
}
std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha));
if (d.empty()) {
return {alpha, fills};
}
}
return {alpha, fills};
}
} // namespace power_grid_model
Loading

0 comments on commit 2287bc5

Please sign in to comment.