Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature / Step-up transformer tap changer support updated ranking #832

Draft
wants to merge 6 commits into
base: feature/step-up-transformer-tap-changer-support
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <optional>
#include <queue>
#include <ranges>
#include <utility>
#include <variant>
#include <vector>

Expand Down Expand Up @@ -69,9 +70,35 @@ constexpr TrafoGraphEdge unregulated_edge_prop = {unregulated_idx, 0};
using TrafoGraphEdges = std::vector<std::pair<TrafoGraphIdx, TrafoGraphIdx>>;
using TrafoGraphEdgeProperties = std::vector<TrafoGraphEdge>;

struct RegulatedTrafoProperties {
Idx id{};
ControlSide control_side{};

auto operator<=>(RegulatedTrafoProperties const& other) const = default;
};

using RegulatedTrafos = std::set<RegulatedTrafoProperties>;

inline std::pair<bool, ControlSide> regulated_trafos_contain(RegulatedTrafos const& trafos_set, Idx const& id) {
if (auto it = std::find_if(trafos_set.begin(), trafos_set.end(),
[&](RegulatedTrafoProperties const& trafo) { return trafo.id == id; });
it != trafos_set.end()) {
return {true, it->control_side};
}
return {false, ControlSide{}}; // no default invalid control side, won't be used by logic
}

struct RegulatedObjects {
std::set<Idx> transformers{};
std::set<Idx> transformers3w{};
// (TODO: jguo) old way, to be removed
// std::set<Idx> transformers{};
// std::set<Idx> transformers3w{};
RegulatedTrafos trafos{};
RegulatedTrafos trafos3w{};
Comment on lines +98 to +99
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of trafo is standard across the code base. So please skip comments regarding transformer vs trafo.


std::pair<bool, ControlSide> contains_trafo(Idx const& id) const { return regulated_trafos_contain(trafos, id); }
std::pair<bool, ControlSide> contains_trafo3w(Idx const& id) const {
return regulated_trafos_contain(trafos3w, id);
}
};

using TransformerGraph = boost::compressed_sparse_row_graph<boost::directedS, TrafoGraphVertex, TrafoGraphEdge,
Expand All @@ -90,13 +117,16 @@ inline void add_to_edge(main_core::MainModelState<ComponentContainer> const& sta

inline void process_trafo3w_edge(main_core::main_model_state_c auto const& state,
ThreeWindingTransformer const& transformer3w, bool const& trafo3w_is_regulated,
Idx2D const& trafo3w_idx, TrafoGraphEdges& edges,
ControlSide const& control_side, Idx2D const& trafo3w_idx, TrafoGraphEdges& edges,
TrafoGraphEdgeProperties& edge_props) {
using enum Branch3Side;

constexpr std::array<std::tuple<Branch3Side, Branch3Side>, 3> const branch3_combinations{
{{side_1, side_2}, {side_2, side_3}, {side_3, side_1}}};

auto const tap_at_control_side = [&control_side](Branch3Side const& tap_side) {
return static_cast<IntS>(control_side) == static_cast<IntS>(tap_side);
};
for (auto const& [first_side, second_side] : branch3_combinations) {
if (!transformer3w.status(first_side) || !transformer3w.status(second_side)) {
continue;
Expand All @@ -106,16 +136,23 @@ inline void process_trafo3w_edge(main_core::main_model_state_c auto const& state

auto const tap_at_first_side = transformer3w.tap_side() == first_side;
auto const single_direction_condition =
trafo3w_is_regulated && (tap_at_first_side || transformer3w.tap_side() == second_side);
// ranking
trafo3w_is_regulated && (tap_at_first_side || (transformer3w.tap_side() == second_side));

auto const tap_at_control = tap_at_control_side(transformer3w.tap_side());

// only add weighted edge if the trafo3w meets the condition
if (single_direction_condition) {
auto const& tap_side_node = tap_at_first_side ? from_node : to_node;
auto const& non_tap_side_node = tap_at_first_side ? to_node : from_node;
auto const edge_from_node = tap_at_control ? non_tap_side_node : tap_side_node;
auto const edge_to_node = tap_at_control ? tap_side_node : non_tap_side_node;
// add regulated idx only when the first side node is tap side node.
// This is done to add only one directional edge with regulated idx.
auto const edge_value =
(from_node == tap_side_node) ? unregulated_edge_prop : TrafoGraphEdge{trafo3w_idx, 1};
add_to_edge(state, edges, edge_props, tap_side_node, non_tap_side_node, edge_value);
// (TODO: jguo) old way, to be removed
// add_to_edge(state, edges, edge_props, tap_side_node, non_tap_side_node, edge_value);
add_to_edge(state, edges, edge_props, edge_from_node, edge_to_node, edge_value);
} else {
add_to_edge(state, edges, edge_props, from_node, to_node, unregulated_edge_prop);
add_to_edge(state, edges, edge_props, to_node, from_node, unregulated_edge_prop);
Expand All @@ -130,9 +167,11 @@ constexpr void add_edge(main_core::MainModelState<ComponentContainer> const& sta
TrafoGraphEdgeProperties& edge_props) {

for (auto const& transformer3w : state.components.template citer<ThreeWindingTransformer>()) {
bool const trafo3w_is_regulated = regulated_objects.transformers3w.contains(transformer3w.id());
// bool const trafo3w_is_regulated = regulated_objects.transformers3w.contains(transformer3w.id());
auto const trafo3w_is_regulated = regulated_objects.contains_trafo3w(transformer3w.id());
Idx2D const trafo3w_idx = main_core::get_component_idx_by_id(state, transformer3w.id());
process_trafo3w_edge(state, transformer3w, trafo3w_is_regulated, trafo3w_idx, edges, edge_props);
process_trafo3w_edge(state, transformer3w, trafo3w_is_regulated.first, trafo3w_is_regulated.second, trafo3w_idx,
edges, edge_props);
}
}

Expand All @@ -147,12 +186,22 @@ constexpr void add_edge(main_core::MainModelState<ComponentContainer> const& sta
}
auto const& from_node = transformer.from_node();
auto const& to_node = transformer.to_node();
if (regulated_objects.transformers.contains(transformer.id())) {
auto const tap_at_from_side = transformer.tap_side() == BranchSide::from;
auto const& tap_side_node = tap_at_from_side ? from_node : to_node;
auto const& non_tap_side_node = tap_at_from_side ? to_node : from_node;
add_to_edge(state, edges, edge_props, tap_side_node, non_tap_side_node,
{main_core::get_component_idx_by_id(state, transformer.id()), 1});
// if (regulated_objects.transformers.contains(transformer.id())) {
auto const trafo_regulated = regulated_objects.contains_trafo(transformer.id());
if (trafo_regulated.first) {
// (TODO: jguo) old way, to be removed
// auto const tap_at_from_side = transformer.tap_side() == BranchSide::from;
// auto const& tap_side_node = tap_at_from_side ? from_node : to_node;
// auto const& non_tap_side_node = tap_at_from_side ? to_node : from_node;
auto const control_side = trafo_regulated.second;
auto const control_side_node = control_side == ControlSide::from ? from_node : to_node;
auto const non_control_side_node = control_side == ControlSide::from ? to_node : from_node;
auto const trafo_idx = main_core::get_component_idx_by_id(state, transformer.id());

// (TODO: jguo) old way, to be removed
// add_to_edge(state, edges, edge_props, tap_side_node, non_tap_side_node,
// {main_core::get_component_idx_by_id(state, transformer.id()), 1});
add_to_edge(state, edges, edge_props, non_control_side_node, control_side_node, {trafo_idx, 1});
} else {
add_to_edge(state, edges, edge_props, from_node, to_node, unregulated_edge_prop);
add_to_edge(state, edges, edge_props, to_node, from_node, unregulated_edge_prop);
Expand Down Expand Up @@ -191,10 +240,13 @@ inline auto retrieve_regulator_info(State const& state) -> RegulatedObjects {
if (!regulator.status()) {
continue;
}
auto const control_side = regulator.control_side();
if (regulator.regulated_object_type() == ComponentType::branch) {
regulated_objects.transformers.emplace(regulator.regulated_object());
// regulated_objects.transformers.emplace(regulator.regulated_object());
regulated_objects.trafos.emplace(RegulatedTrafoProperties{regulator.regulated_object(), control_side});
} else {
regulated_objects.transformers3w.emplace(regulator.regulated_object());
// regulated_objects.transformers3w.emplace(regulator.regulated_object());
regulated_objects.trafos3w.emplace(RegulatedTrafoProperties{regulator.regulated_object(), control_side});
}
}
return regulated_objects;
Expand Down
3 changes: 2 additions & 1 deletion tests/cpp_unit_tests/test_tap_position_optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ TEST_CASE("Test Transformer ranking") {
CHECK(actual_edges_prop == expected_edges_prop);
}

// (TODO: jguo) old way, to be removed
SUBCASE("Automatic tap unsupported tap side at LV") {
TestState bad_state;
std::vector<NodeInput> bad_nodes{{0, 50e3}, {1, 10e3}};
Expand Down Expand Up @@ -337,7 +338,7 @@ TEST_CASE("Test Transformer ranking") {
SUBCASE("Ranking complete the graph") {
pgm_tap::RankedTransformerGroups order = pgm_tap::rank_transformers(state);
pgm_tap::RankedTransformerGroups const ref_order{
{Idx2D{3, 0}, Idx2D{3, 1}, Idx2D{4, 0}, Idx2D{3, 3}, Idx2D{3, 2}, Idx2D{3, 4}}};
{Idx2D{3, 0}, Idx2D{3, 1}, Idx2D{3, 3}, Idx2D{4, 0}, Idx2D{3, 2}, Idx2D{3, 4}}};
CHECK(order == ref_order);
}
}
Expand Down
Loading