diff --git a/docs/user_manual/calculations.md b/docs/user_manual/calculations.md index dadba724c3..007f03e3df 100644 --- a/docs/user_manual/calculations.md +++ b/docs/user_manual/calculations.md @@ -628,7 +628,7 @@ Power flow calculations that take the behavior of these regulators into account The following control logic is used: -- Regulated transformers are ranked according to how close they are to {hoverxreftooltip}`sources ` in terms of the amount of transformers inbetween. +- Regulated transformers are ranked according to how close they are to {hoverxreftooltip}`sources ` in terms of the amount of regulated transformers inbetween. - Transformers are regulated in order according to their ranks. - Initialize all transformers to their starting tap position (see {hoverxreftooltip}`user_manual/calculations:Initialization and exploitation of regulated transformers`) - Find the optimal state using the following procedure diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp index 14218306bd..5b39906213 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp @@ -196,6 +196,13 @@ class AutomaticTapCalculationError : public PowerGridError { } }; +class AutomaticTapInputError : public PowerGridError { + public: + AutomaticTapInputError(std::string const& msg) { + append_msg("Automatic tap changer has invalid configuration. " + msg); // NOSONAR + } +}; + class IDWrongType : public PowerGridError { public: explicit IDWrongType(ID id) { append_msg("Wrong type for object with id " + detail::to_string(id) + '\n'); } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp index 67a2124fb5..fd39b6ac47 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp @@ -137,28 +137,8 @@ inline void add_component(MainModelState& state, ForwardIter } }(); - if (regulated_object_idx.group == get_component_type_index(state)) { - auto const& regulated_object = get_component(state, regulated_object_idx); - - auto const non_tap_side = - regulated_object.tap_side() == BranchSide::from ? BranchSide::to : BranchSide::from; - if (get_component(state, regulated_object.node(regulated_object.tap_side())).u_rated() < - get_component(state, regulated_object.node(non_tap_side)).u_rated()) { - throw AutomaticTapCalculationError(id); - } - } else if (regulated_object_idx.group == get_component_type_index(state)) { - auto const& regulated_object = get_component(state, regulated_object_idx); - auto const tap_side_u_rated = - get_component(state, regulated_object.node(regulated_object.tap_side())).u_rated(); - for (auto const side : branch3_sides) { - if (side == regulated_object.tap_side()) { - continue; - } - if (tap_side_u_rated < get_component(state, regulated_object.node(side)).u_rated()) { - throw AutomaticTapCalculationError(id); - } - } - } else { + if (regulated_object_idx.group != get_component_type_index(state) && + regulated_object_idx.group != get_component_type_index(state)) { throw InvalidRegulatedObject(input.regulated_object, Component::name); } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp index 4f80700694..f17f3c2eaf 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp @@ -42,7 +42,6 @@ using RankedTransformerGroups = std::vector>; constexpr auto infty = std::numeric_limits::max(); constexpr Idx2D unregulated_idx = {-1, -1}; - struct TrafoGraphVertex { bool is_source{}; }; @@ -51,6 +50,10 @@ struct TrafoGraphEdge { Idx2D regulated_idx{}; EdgeWeight weight{}; + constexpr TrafoGraphEdge() = default; + constexpr TrafoGraphEdge(Idx2D regulated_idx_, EdgeWeight weight_) + : regulated_idx{regulated_idx_}, weight{weight_} {} + bool operator==(const TrafoGraphEdge& other) const { return regulated_idx == other.regulated_idx && weight == other.weight; } // thanks boost @@ -66,12 +69,36 @@ struct TrafoGraphEdge { } }; +constexpr auto unregulated_edge_prop = TrafoGraphEdge{unregulated_idx, 0}; using TrafoGraphEdges = std::vector>; using TrafoGraphEdgeProperties = std::vector; +struct RegulatedTrafoProperties { + Idx id{}; + ControlSide control_side{}; + + auto operator<=>(RegulatedTrafoProperties const& other) const = default; // NOLINT(modernize-use-nullptr) +}; + +using RegulatedTrafos = std::set; + +inline std::pair regulated_trafos_contain(RegulatedTrafos const& trafos_set, Idx const& id) { + if (auto it = + std::ranges::find_if(trafos_set, [&](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 transformers; - std::set transformers3w; + RegulatedTrafos trafos; + RegulatedTrafos trafos3w; + + std::pair contains_trafo(Idx const& id) const { return regulated_trafos_contain(trafos, id); } + std::pair contains_trafo3w(Idx const& id) const { + return regulated_trafos_contain(trafos3w, id); + } }; using TransformerGraph = boost::compressed_sparse_row_graph 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, 3> const branch3_combinations{ - {{side_1, side_2}, {side_2, side_3}, {side_3, side_1}}}; + {{side_1, side_2}, {side_1, side_3}, {side_2, side_3}}}; for (auto const& [first_side, second_side] : branch3_combinations) { if (!transformer3w.status(first_side) || !transformer3w.status(second_side)) { @@ -105,19 +132,24 @@ inline void process_trafo3w_edge(main_core::main_model_state_c auto const& state auto const& to_node = transformer3w.node(second_side); 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 - if (single_direction_condition) { + auto const connected_to_primary_side_regulated = + trafo3w_is_regulated && (tap_at_first_side || (transformer3w.tap_side() == second_side)); + + auto const tap_at_control = static_cast(control_side) == static_cast(transformer3w.tap_side()); + + // only add weighted edge if the trafo3w meets the condition + if (connected_to_primary_side_regulated) { 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. - Idx2D const regulated_idx = from_node == tap_side_node ? unregulated_idx : trafo3w_idx; - add_to_edge(state, edges, edge_props, tap_side_node, non_tap_side_node, {regulated_idx, 1}); + auto const edge_value = TrafoGraphEdge{trafo3w_idx, 1}; + 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_idx, 1}); - add_to_edge(state, edges, edge_props, to_node, from_node, {unregulated_idx, 1}); + 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); } } } @@ -129,9 +161,10 @@ constexpr void add_edge(main_core::MainModelState const& sta TrafoGraphEdgeProperties& edge_props) { for (auto const& transformer3w : state.components.template citer()) { - 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); } } @@ -146,15 +179,17 @@ constexpr void add_edge(main_core::MainModelState 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}); + auto const trafo_regulated = regulated_objects.contains_trafo(transformer.id()); + if (trafo_regulated.first) { + 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()); + + 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_idx, 1}); - add_to_edge(state, edges, edge_props, to_node, from_node, {unregulated_idx, 1}); + 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); } } } @@ -172,8 +207,8 @@ constexpr void add_edge(main_core::MainModelState const& sta if (!branch.from_status() || !branch.to_status()) { continue; } - add_to_edge(state, edges, edge_props, branch.from_node(), branch.to_node(), {unregulated_idx, 0}); - add_to_edge(state, edges, edge_props, branch.to_node(), branch.from_node(), {unregulated_idx, 0}); + add_to_edge(state, edges, edge_props, branch.from_node(), branch.to_node(), unregulated_edge_prop); + add_to_edge(state, edges, edge_props, branch.to_node(), branch.from_node(), unregulated_edge_prop); } } @@ -190,10 +225,11 @@ 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.trafos.emplace(RegulatedTrafoProperties{regulator.regulated_object(), control_side}); } else { - regulated_objects.transformers3w.emplace(regulator.regulated_object()); + regulated_objects.trafos3w.emplace(RegulatedTrafoProperties{regulator.regulated_object(), control_side}); } } return regulated_objects; @@ -243,7 +279,8 @@ inline void process_edges_dijkstra(Idx v, std::vector& vertex_distan auto t = boost::target(e, graph); const EdgeWeight weight = graph[e].weight; - // We can not use BGL_FORALL_OUTEDGES here because our grid is undirected + // We can not use BGL_FORALL_OUTEDGES here because we need information + // regardless of edge direction if (u == s && vertex_distances[s] + weight < vertex_distances[t]) { vertex_distances[t] = vertex_distances[s] + weight; pq.emplace(vertex_distances[t], t); @@ -270,9 +307,33 @@ inline auto get_edge_weights(TransformerGraph const& graph) -> TrafoGraphEdgePro if (graph[e].regulated_idx == unregulated_idx) { continue; } - auto edge_res = std::min(vertex_distances[boost::source(e, graph)], vertex_distances[boost::target(e, graph)]); + auto const edge_src_rank = vertex_distances[boost::source(e, graph)]; + auto const edge_tgt_rank = vertex_distances[boost::target(e, graph)]; + auto const edge_res = std::min(edge_src_rank, edge_tgt_rank); + + // New edge logic for ranking + // | Tap | Control | All edges | + // --------------------------------------------- + // | A | A | [B->A], [C->A], [B<->C] | + // | A | B | [A->B], [A->C], [B<->C] | + // | A | C | [A->B], [A->C], [B<->C] | + // | B | A | [B->A], [C<->A], [B->C] | + // | B | B | [A->B], [C<->A], [C->B] | + // | B | C | [B->A], [C<->A], [B->C] | + // | C | A | [A<->B], [C->A], [C->B] | + // | C | B | [A<->B], [C->A], [C->B] | + // | C | C | [A<->B], [A->C], [A->B] | + // In two winding trafo, the edge is always pointing to the control side; in three winding trafo edges, the + // unidirectional edges are always pointing towards the control side and the node connected to the control + // side via the bidirectional edge (if it exists). For delta configuration ABC, the above + // situations can happen. + // The logic still holds in meshed grids, albeit operating a more complex graph. + if (edge_src_rank != edge_tgt_rank - 1) { + throw AutomaticTapInputError("The control side of a transformer regulator should be relatively further " + "away from the source than the tap side.\n"); + } if (!is_unreachable(edge_res)) { - result.push_back({graph[e].regulated_idx, edge_res}); + result.emplace_back(graph[e].regulated_idx, edge_tgt_rank); } } @@ -292,7 +353,10 @@ inline auto rank_transformers(TrafoGraphEdgeProperties const& w_trafo_list) -> R groups.emplace_back(); previous_weight = trafo.weight; } - groups.back().push_back(trafo.regulated_idx); + auto& current_group = groups.back(); // avoid duplicates + if (std::ranges::find(current_group, trafo.regulated_idx) == current_group.end()) { + current_group.emplace_back(trafo.regulated_idx); + } } return groups; } @@ -336,11 +400,19 @@ constexpr IntS one_step_tap_down(transformer_c auto const& transformer) { return tap_min < tap_max ? tap_pos - IntS{1} : tap_pos + IntS{1}; } // higher voltage at control side => lower voltage at tap side => lower tap pos -constexpr IntS one_step_control_voltage_up(transformer_c auto const& transformer) { +constexpr IntS one_step_control_voltage_up(transformer_c auto const& transformer, bool control_at_tap_side) { + if (control_at_tap_side) { + // control side is tap side, voltage up requires tap up + return one_step_tap_up(transformer); + } return one_step_tap_down(transformer); } // lower voltage at control side => higher voltage at tap side => higher tap pos -constexpr IntS one_step_control_voltage_down(transformer_c auto const& transformer) { +constexpr IntS one_step_control_voltage_down(transformer_c auto const& transformer, bool control_at_tap_side) { + if (control_at_tap_side) { + // control side is tap side, voltage down requires tap down + return one_step_tap_down(transformer); + } return one_step_tap_up(transformer); } @@ -366,6 +438,9 @@ template class TransformerWrapper { IntS tap_max() const { return apply([](auto const& t) { return t.tap_max(); }); } + IntS tap_side() const { + return apply([](auto const& t) { return static_cast(t.tap_side()); }); + } int64_t tap_range() const { return apply([](auto const& t) { return std::abs(static_cast(t.tap_max()) - static_cast(t.tap_min())); @@ -387,6 +462,10 @@ template class TransformerWrapper { template struct TapRegulatorRef { std::reference_wrapper regulator; TransformerWrapper transformer; + + bool control_at_tap_side() const { + return static_cast(regulator.get().control_side()) == transformer.tap_side(); + } }; template @@ -650,7 +729,9 @@ class TapPositionOptimizerImpl, StateCalculator, class BinarySearch { public: BinarySearch() = default; - BinarySearch(IntS tap_pos, IntS tap_min, IntS tap_max) { reset(tap_pos, tap_min, tap_max); } + BinarySearch(IntS tap_pos, IntS tap_min, IntS tap_max, bool control_at_tap_side) { + reset(tap_pos, tap_min, tap_max, control_at_tap_side); + } constexpr IntS get_current_tap() const { return current_; } constexpr bool get_last_down() const { return last_down_; } @@ -668,8 +749,8 @@ class TapPositionOptimizerImpl, StateCalculator, // Lower bound should be updated to the current tap position if following is the case: // - tap_max > tap_min && strategy_max == true // - tap_max < tap_min && strategy_max == false - // Upper bound should be updated to the current tap position if the rest is the case. - if (tap_reverse_ == strategy_max) { + bool const invert_strategy = control_at_tap_side_ != strategy_max; + if (tap_reverse_ == invert_strategy) { lower_bound_ = current_; last_down_ = false; } else { @@ -679,7 +760,7 @@ class TapPositionOptimizerImpl, StateCalculator, } void propose_new_pos(bool strategy_max, bool above_range) { - bool const is_down = above_range == tap_reverse_; + bool const is_down = (above_range == tap_reverse_) != control_at_tap_side_; if (last_check_) { current_ = is_down ? lower_bound_ : upper_bound_; inevitable_run_ = true; @@ -693,7 +774,7 @@ class TapPositionOptimizerImpl, StateCalculator, // __prefer_higher__ indicates a preference towards higher voltage // that is a result of both the strategy as well as whether the current // transformer has a reversed tap_max and tap_min - bool const prefer_higher = strategy_max != tap_reverse_; + bool const prefer_higher = (strategy_max != tap_reverse_) != control_at_tap_side_; auto const tap_pos = search(prefer_higher); auto const tap_diff = tap_pos - get_current_tap(); if (tap_diff == 0) { @@ -714,7 +795,7 @@ class TapPositionOptimizerImpl, StateCalculator, } private: - void reset(IntS tap_pos, IntS tap_min, IntS tap_max) { + void reset(IntS tap_pos, IntS tap_min, IntS tap_max, bool control_at_tap_side) { last_down_ = false; last_check_ = false; current_ = tap_pos; @@ -722,6 +803,7 @@ class TapPositionOptimizerImpl, StateCalculator, lower_bound_ = std::min(tap_min, tap_max); upper_bound_ = std::max(tap_min, tap_max); tap_reverse_ = tap_max < tap_min; + control_at_tap_side_ = control_at_tap_side; } void adjust(bool strategy_max = true) { @@ -737,25 +819,27 @@ class TapPositionOptimizerImpl, StateCalculator, } } - IntS search(bool prefer_higher = true) const { - // This logic is used to determin which of the middle points could be of interest + IntS search(bool prefer_higher_) const { + // This logic is used to determine which of the middle points could be of interest // given strategy used in optimization: // Since in BinarySearch we insist on absolute upper and lower bounds, we only need to // find the corresponding mid point. std::midpoint returns always the lower mid point // if the range is of even length. This is why we need to adjust bounds accordingly. // Not because upper bound and lower bound might be reversed, which is not possible. + bool const prefer_higher = control_at_tap_side_ != prefer_higher_; auto const primary_bound = prefer_higher ? upper_bound_ : lower_bound_; auto const secondary_bound = prefer_higher ? lower_bound_ : upper_bound_; return std::midpoint(primary_bound, secondary_bound); } - IntS lower_bound_{}; // tap position lower bound - IntS upper_bound_{}; // tap position upper bound - IntS current_{0}; // current tap position - bool last_down_{false}; // last direction - bool last_check_{false}; // last run checked - bool tap_reverse_{false}; // tap range normal or reversed - bool inevitable_run_{false}; // inevitable run + IntS lower_bound_{}; // tap position lower bound + IntS upper_bound_{}; // tap position upper bound + IntS current_{0}; // current tap position + bool last_down_{false}; // last direction + bool last_check_{false}; // last run checked + bool tap_reverse_{false}; // tap range normal or reversed + bool inevitable_run_{false}; // inevitable run + bool control_at_tap_side_{false}; // regulator control side is at tap side }; std::vector> binary_search_; struct BinarySearchOptions { @@ -856,7 +940,7 @@ class TapPositionOptimizerImpl, StateCalculator, std::vector binary_search_group(same_rank_regulators.size()); std::ranges::transform(same_rank_regulators, binary_search_group.begin(), [](auto const& regulator) { return BinarySearch{regulator.transformer.tap_pos(), regulator.transformer.tap_min(), - regulator.transformer.tap_max()}; + regulator.transformer.tap_max(), regulator.control_at_tap_side()}; }); binary_search_.push_back(std::move(binary_search_group)); } @@ -985,13 +1069,15 @@ class TapPositionOptimizerImpl, StateCalculator, auto [node_state, param] = compute_node_state_and_param(regulator, state, solver_output); + bool control_at_tap_side = regulator.control_at_tap_side(); + auto const cmp = node_state <=> param; - auto new_tap_pos = [&transformer, &cmp] { + auto new_tap_pos = [&transformer, &cmp, &control_at_tap_side] { if (cmp > 0) { // NOLINT(modernize-use-nullptr) - return one_step_control_voltage_down(transformer); + return one_step_control_voltage_down(transformer, control_at_tap_side); } if (cmp < 0) { // NOLINT(modernize-use-nullptr) - return one_step_control_voltage_up(transformer); + return one_step_control_voltage_up(transformer, control_at_tap_side); } return transformer.tap_pos(); }(); @@ -1090,11 +1176,19 @@ class TapPositionOptimizerImpl, StateCalculator, auto pilot_run(std::vector> const& regulator_order) { using namespace std::string_literals; - constexpr auto max_voltage_pos = [](transformer_c auto const& transformer) -> IntS { + constexpr auto max_voltage_pos = [](transformer_c auto const& transformer, bool control_at_tap_side) -> IntS { + if (control_at_tap_side) { + // max voltage at tap side <=> max tap pos + return transformer.tap_max(); + } // max voltage at control side => min voltage at tap side => min tap pos return transformer.tap_min(); }; - constexpr auto min_voltage_pos = [](transformer_c auto const& transformer) -> IntS { + constexpr auto min_voltage_pos = [](transformer_c auto const& transformer, bool control_at_tap_side) -> IntS { + if (control_at_tap_side) { + // min voltage at tap side <=> min tap pos + return transformer.tap_min(); + } // min voltage at control side => max voltage at tap side => max tap pos return transformer.tap_max(); }; @@ -1125,11 +1219,11 @@ class TapPositionOptimizerImpl, StateCalculator, void exploit_neighborhood(std::vector> const& regulator_order) { using namespace std::string_literals; - constexpr auto one_step_up = [](transformer_c auto const& transformer) -> IntS { - return one_step_control_voltage_up(transformer); + constexpr auto increment_voltage = [](transformer_c auto const& transformer, bool control_at_tap_side) -> IntS { + return one_step_control_voltage_up(transformer, control_at_tap_side); }; - constexpr auto one_step_down = [](transformer_c auto const& transformer) -> IntS { - return one_step_control_voltage_down(transformer); + constexpr auto decrement_voltage = [](transformer_c auto const& transformer, bool control_at_tap_side) -> IntS { + return one_step_control_voltage_down(transformer, control_at_tap_side); }; switch (strategy_) { @@ -1140,12 +1234,12 @@ class TapPositionOptimizerImpl, StateCalculator, case OptimizerStrategy::global_maximum: [[fallthrough]]; case OptimizerStrategy::local_maximum: - regulate_transformers(one_step_up, regulator_order); + regulate_transformers(increment_voltage, regulator_order); break; case OptimizerStrategy::global_minimum: [[fallthrough]]; case OptimizerStrategy::local_minimum: - regulate_transformers(one_step_down, regulator_order); + regulate_transformers(decrement_voltage, regulator_order); break; default: throw MissingCaseForEnumError{"TapPositionOptimizer::exploit_neighborhood"s, strategy_}; @@ -1160,21 +1254,24 @@ class TapPositionOptimizerImpl, StateCalculator, } template - requires((std::invocable && - std::same_as, IntS>) && + requires((std::invocable && + std::same_as, IntS>) && ...) auto regulate_transformers(Func to_new_tap_pos, std::vector> const& regulator_order) const { UpdateBuffer update_data; auto const get_update = [to_new_tap_pos_func = std::move(to_new_tap_pos), - &update_data](transformer_c auto const& transformer) { - add_tap_pos_update(to_new_tap_pos_func(transformer), transformer, update_data); + &update_data](transformer_c auto const& transformer, bool control_at_tap_side) { + add_tap_pos_update(to_new_tap_pos_func(transformer, control_at_tap_side), transformer, update_data); }; for (auto const& sub_order : regulator_order) { for (auto const& regulator : sub_order) { - regulator.transformer.apply(get_update); + bool const control_at_tap_side = regulator.control_at_tap_side(); + regulator.transformer.apply([&get_update, &control_at_tap_side](auto const& transformer) { + get_update(transformer, control_at_tap_side); + }); } } diff --git a/src/power_grid_model/_core/error_handling.py b/src/power_grid_model/_core/error_handling.py index 758156c978..17d544fd01 100644 --- a/src/power_grid_model/_core/error_handling.py +++ b/src/power_grid_model/_core/error_handling.py @@ -14,6 +14,7 @@ from power_grid_model._core.power_grid_core import power_grid_core as pgc from power_grid_model.errors import ( AutomaticTapCalculationError, + AutomaticTapInputError, ConflictID, ConflictVoltage, IDNotFound, @@ -71,6 +72,8 @@ _AUTOMATIC_TAP_CALCULATION_ERROR_RE = re.compile( r"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id (-?\d+)\n" ) +_AUTOMATIC_TAP_INPUT_ERROR_RE = re.compile(r"Automatic tap changer has invalid configuration") + _ID_WRONG_TYPE_RE = re.compile(r"Wrong type for object with id (-?\d+)\n") _INVALID_CALCULATION_METHOD_RE = re.compile(r"The calculation method is invalid for this calculation!") _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE = re.compile(r"short circuit type") # multiple different flavors @@ -95,6 +98,7 @@ _INVALID_MEASURED_OBJECT_RE: InvalidMeasuredObject, _INVALID_REGULATED_OBJECT_RE: InvalidRegulatedObject, _AUTOMATIC_TAP_CALCULATION_ERROR_RE: AutomaticTapCalculationError, + _AUTOMATIC_TAP_INPUT_ERROR_RE: AutomaticTapInputError, _ID_WRONG_TYPE_RE: IDWrongType, _INVALID_CALCULATION_METHOD_RE: InvalidCalculationMethod, _INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE: InvalidShortCircuitPhaseOrType, diff --git a/src/power_grid_model/errors.py b/src/power_grid_model/errors.py index 312387ab2e..4576253906 100644 --- a/src/power_grid_model/errors.py +++ b/src/power_grid_model/errors.py @@ -97,6 +97,10 @@ class AutomaticTapCalculationError(PowerGridError): """Automatic tap changer with tap at LV side is unsupported for automatic tap changing calculation.""" +class AutomaticTapInputError(PowerGridError): + """Automatic tap changer has invalid configuration.""" + + class InvalidShortCircuitPhaseOrType(PowerGridError): """Invalid (combination of) short circuit types and phase(s) provided.""" diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py index 6b8a23b895..8413a841fe 100644 --- a/src/power_grid_model/validation/validation.py +++ b/src/power_grid_model/validation/validation.py @@ -950,6 +950,7 @@ def validate_regulator(data: SingleDataset, component: ComponentType) -> list[Va def validate_transformer_tap_regulator(data: SingleDataset) -> list[ValidationError]: errors = validate_regulator(data, ComponentType.transformer_tap_regulator) errors += _all_boolean(data, ComponentType.transformer_tap_regulator, "status") + errors += _all_unique(data, ComponentType.transformer_tap_regulator, "regulated_object") errors += _all_valid_enum_values( data, ComponentType.transformer_tap_regulator, "control_side", [BranchSide, Branch3Side] ) diff --git a/tests/cpp_unit_tests/test_optimizer.hpp b/tests/cpp_unit_tests/test_optimizer.hpp index 7f24b915d6..4ef45bf6fa 100644 --- a/tests/cpp_unit_tests/test_optimizer.hpp +++ b/tests/cpp_unit_tests/test_optimizer.hpp @@ -146,7 +146,7 @@ static_assert(std::convertible_to::min(), .tap_max = std::numeric_limits::max(), @@ -183,7 +184,17 @@ TEST_CASE("Test Transformer ranking") { CHECK_NOTHROW(pgm_tap::build_transformer_graph(get_state(6, 2, 1, 4, 5))); } - SUBCASE("Full grid") { + SUBCASE("Full grid 1 - For graph construction steps") { + // =====Test Grid===== + // ________[0]________ + // || | | + // [1] [4]--[5] + // | | | + // [2] | [7] + // | [6] | + // [3]----------| [8] + // | | + // L---------------[9] TestState state; std::vector nodes{{0, 150e3}, {1, 10e3}, {2, 10e3}, {3, 10e3}, {4, 10e3}, {5, 50e3}, {6, 10e3}, {7, 10e3}, {8, 10e3}, {9, 10e3}}; @@ -195,7 +206,8 @@ TEST_CASE("Test Transformer ranking") { get_transformer(15, 8, 9, BranchSide::from)}; main_core::add_component(state, transformers.begin(), transformers.end(), 50.0); - std::vector transformers3w{get_transformer3w(16, 0, 4, 5)}; + std::vector transformers3w{ + get_transformer3w(16, 0, 4, 5, Branch3Side::side_1, 0)}; main_core::add_component(state, transformers3w.begin(), transformers3w.end(), 50.0); std::vector lines{get_line_input(17, 3, 6), get_line_input(18, 3, 9)}; @@ -208,9 +220,9 @@ TEST_CASE("Test Transformer ranking") { main_core::add_component(state, sources.begin(), sources.end(), 50.0); std::vector regulators{ - get_regulator(23, 11, ControlSide::from), get_regulator(24, 12, ControlSide::from), - get_regulator(25, 13, ControlSide::from), get_regulator(26, 14, ControlSide::from), - get_regulator(27, 15, ControlSide::from), get_regulator(28, 16, ControlSide::side_1)}; + get_regulator(23, 11, ControlSide::to), get_regulator(24, 12, ControlSide::to), + get_regulator(25, 13, ControlSide::to), get_regulator(26, 14, ControlSide::to), + get_regulator(27, 15, ControlSide::to), get_regulator(28, 16, ControlSide::side_2)}; main_core::add_component(state, regulators.begin(), regulators.end(), 50.0); state.components.set_construction_complete(); @@ -221,18 +233,11 @@ TEST_CASE("Test Transformer ranking") { using vertex_iterator = boost::graph_traits::vertex_iterator; // reference graph creation - // Inserted in order of transformer, transformer3w, line and link - std::vector> expected_edges; - expected_edges.insert(expected_edges.end(), {{0, 1}, {0, 1}, {5, 7}, {2, 3}, {8, 9}}); - expected_edges.insert(expected_edges.end(), {{0, 4}, {4, 5}, {5, 4}, {0, 5}}); - expected_edges.insert(expected_edges.end(), {{3, 6}, {6, 3}, {3, 9}, {9, 3}}); - expected_edges.insert(expected_edges.end(), {{2, 1}, {1, 2}, {6, 4}, {4, 6}, {8, 7}, {7, 8}}); - pgm_tap::TrafoGraphEdgeProperties expected_edges_prop; expected_edges_prop.insert(expected_edges_prop.end(), {{{3, 0}, 1}, {{3, 1}, 1}, {{3, 2}, 1}, {{3, 3}, 1}, {{3, 4}, 1}}); expected_edges_prop.insert(expected_edges_prop.end(), - {{{4, 0}, 1}, {unregulated_idx, 1}, {unregulated_idx, 1}, {unregulated_idx, 1}}); + {{{4, 0}, 1}, {{4, 0}, 1}, {unregulated_idx, 0}, {unregulated_idx, 0}}); expected_edges_prop.insert(expected_edges_prop.end(), 10, {unregulated_idx, 0}); std::vector const expected_vertex_props{ @@ -256,27 +261,12 @@ TEST_CASE("Test Transformer ranking") { CHECK(actual_edges_prop == expected_edges_prop); } - SUBCASE("Automatic tap unsupported tap side at LV") { - TestState bad_state; - std::vector bad_nodes{{0, 50e3}, {1, 10e3}}; - main_core::add_component(bad_state, bad_nodes.begin(), bad_nodes.end(), 50.0); - - std::vector bad_trafo{get_transformer(2, 0, 1, BranchSide::to)}; - main_core::add_component(bad_state, bad_trafo.begin(), bad_trafo.end(), 50.0); - - std::vector bad_regulators{get_regulator(3, 2, ControlSide::from)}; - - CHECK_THROWS_AS(main_core::add_component(bad_state, bad_regulators.begin(), - bad_regulators.end(), 50.0), - AutomaticTapCalculationError); - } - SUBCASE("Process edge weights") { using vertex_iterator = boost::graph_traits::vertex_iterator; // Dummy graph pgm_tap::TrafoGraphEdges const edge_array = {{0, 1}, {0, 2}, {2, 3}}; - pgm_tap::TrafoGraphEdgeProperties const edge_prop{{{0, 1}, 1}, {{-1, -1}, 2}, {{2, 3}, 3}}; + pgm_tap::TrafoGraphEdgeProperties const edge_prop{{{0, 1}, 1}, {{-1, -1}, 0}, {{2, 3}, 1}}; std::vector vertex_props{{true}, {false}, {false}, {false}}; pgm_tap::TransformerGraph g{boost::edges_are_unsorted_multi_pass, edge_array.cbegin(), edge_array.cend(), @@ -290,7 +280,7 @@ TEST_CASE("Test Transformer ranking") { } pgm_tap::TrafoGraphEdgeProperties const regulated_edge_weights = get_edge_weights(g); - pgm_tap::TrafoGraphEdgeProperties const ref_regulated_edge_weights{{{0, 1}, 0}, {{2, 3}, 2}}; + pgm_tap::TrafoGraphEdgeProperties const ref_regulated_edge_weights{{{0, 1}, 1}, {{2, 3}, 1}}; CHECK(regulated_edge_weights == ref_regulated_edge_weights); } @@ -313,13 +303,12 @@ TEST_CASE("Test Transformer ranking") { using vertex_iterator = boost::graph_traits::vertex_iterator; // Grid with multiple sources and symetric graph - pgm_tap::TrafoGraphEdges const edge_array = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}}; - pgm_tap::TrafoGraphEdgeProperties const edge_prop{ - {{0, 1}, 1}, {{1, 2}, 1}, {{2, 3}, 1}, {{3, 4}, 1}, {{4, 5}, 1}}; - std::vector vertex_props{{true}, {false}, {false}, {false}, {false}, {true}}; + pgm_tap::TrafoGraphEdges const edge_array = {{0, 1}, {1, 2}, {3, 2}, {4, 3}}; + pgm_tap::TrafoGraphEdgeProperties const edge_prop{{{0, 1}, 1}, {{1, 2}, 1}, {{2, 3}, 1}, {{3, 4}, 1}}; + std::vector vertex_props{{true}, {false}, {false}, {false}, {true}}; pgm_tap::TransformerGraph g{boost::edges_are_unsorted_multi_pass, edge_array.cbegin(), edge_array.cend(), - edge_prop.cbegin(), 6}; + edge_prop.cbegin(), 5}; // Vertex properties can not be set during graph creation vertex_iterator vi; @@ -330,14 +319,66 @@ TEST_CASE("Test Transformer ranking") { pgm_tap::TrafoGraphEdgeProperties const regulated_edge_weights = get_edge_weights(g); pgm_tap::TrafoGraphEdgeProperties const ref_regulated_edge_weights{ - {{0, 1}, 0}, {{1, 2}, 1}, {{2, 3}, 2}, {{3, 4}, 1}, {{4, 5}, 0}}; + {{0, 1}, 1}, {{1, 2}, 2}, {{2, 3}, 2}, {{3, 4}, 1}}; CHECK(regulated_edge_weights == ref_regulated_edge_weights); } + SUBCASE("Ranking complete the graph") { + // The test grid 1 is not compatible with the updated logic for step up transformers + CHECK_THROWS_AS(pgm_tap::rank_transformers(state), AutomaticTapInputError); + } + } + + // The test grid 2 is compatible with the updated logic for step up transformers + SUBCASE("Full grid 2 - For transformer ranking only") { + // =====Test Grid===== + // ________[0]________ + // || | | + // [1] [4]--[5] + // | | | + // [2] | [8] + // | [6] | + // [3]----[7]---| [9] + // | | + // L--------------[10] + TestState state; + std::vector nodes{{0, 150e3}, {1, 10e3}, {2, 10e3}, {3, 10e3}, {4, 10e3}, {5, 50e3}, + {6, 10e3}, {7, 10e3}, {8, 10e3}, {9, 10e3}, {10, 10e3}}; + main_core::add_component(state, nodes.begin(), nodes.end(), 50.0); + + std::vector transformers{ + get_transformer(11, 0, 1, BranchSide::to), get_transformer(12, 0, 1, BranchSide::from), + get_transformer(13, 2, 3, BranchSide::from), get_transformer(14, 6, 7, BranchSide::from), + get_transformer(15, 5, 8, BranchSide::from), get_transformer(16, 9, 10, BranchSide::from)}; + main_core::add_component(state, transformers.begin(), transformers.end(), 50.0); + + std::vector transformers3w{ + get_transformer3w(17, 0, 4, 5, Branch3Side::side_2, 0)}; + main_core::add_component(state, transformers3w.begin(), transformers3w.end(), 50.0); + + std::vector lines{get_line_input(18, 4, 6), get_line_input(19, 3, 10)}; + main_core::add_component(state, lines.begin(), lines.end(), 50.0); + + std::vector links{{20, 1, 2, 1, 1}, {21, 3, 7, 1, 1}, {22, 8, 9, 1, 1}}; + main_core::add_component(state, links.begin(), links.end(), 50.0); + + std::vector sources{{23, 0, 1, 1.0, 0, nan, nan, nan}}; + main_core::add_component(state, sources.begin(), sources.end(), 50.0); + + std::vector regulators{ + get_regulator(24, 11, ControlSide::to), get_regulator(25, 12, ControlSide::to), + get_regulator(26, 13, ControlSide::to), get_regulator(27, 14, ControlSide::to), + get_regulator(28, 15, ControlSide::to), get_regulator(29, 16, ControlSide::to), + get_regulator(30, 17, ControlSide::side_2)}; + main_core::add_component(state, regulators.begin(), regulators.end(), 50.0); + + state.components.set_construction_complete(); + + // Subcases 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}}}; + pgm_tap::RankedTransformerGroups const ref_order{ + {{Idx2D{3, 0}, Idx2D{3, 1}, Idx2D{4, 0}, Idx2D{3, 4}}, {Idx2D{3, 2}, Idx2D{3, 3}, Idx2D{3, 5}}}}; CHECK(order == ref_order); } } @@ -584,26 +625,151 @@ template class MockTransformerRanker { } }; -using TapPositionCheckFunc = std::function; +using TapPositionCheckFunc = std::function; +using TapPositionCheckFuncGeneric = std::function; auto check_exact(IntS tap_pos) -> TapPositionCheckFunc { - return [tap_pos](IntS value, OptimizerStrategy /*strategy*/) { CHECK(value == tap_pos); }; + return [tap_pos](IntS value, OptimizerStrategy /*strategy*/, bool /*control_at_tap_side*/) { + CHECK(value == tap_pos); + }; +}; +auto check_exact_generic(IntS tap_pos) -> TapPositionCheckFuncGeneric { + return + [tap_pos](IntS value, OptimizerStrategy /*strategy*/, ControlSide /*at_tap_side*/) { CHECK(value == tap_pos); }; +}; + +auto check_exact_per_strategy(IntS tap_pos_any, IntS tap_range_min, IntS tap_range_max) -> TapPositionCheckFunc { + return + [tap_pos_any, tap_range_min, tap_range_max](IntS value, OptimizerStrategy strategy, bool control_at_tap_side) { + using enum OptimizerStrategy; + + switch (strategy) { + case any: + case fast_any: + CHECK(value == tap_pos_any); + break; + case local_maximum: + case global_maximum: + CHECK(value == (control_at_tap_side ? tap_range_min : tap_range_max)); + break; + case local_minimum: + case global_minimum: + CHECK(value == (control_at_tap_side ? tap_range_max : tap_range_min)); + break; + default: + FAIL("Unreachable"); + } + }; +} +struct CompensatedResultPerStrategy { + IntS tap_pos_any; + IntS tap_pos_any_comp; + IntS tap_range_min; + IntS tap_range_max; + IntS tap_range_min_comp; + IntS tap_range_max_comp; + IntS get_any(bool control_at_tap_side) const { return control_at_tap_side ? tap_pos_any_comp : tap_pos_any; } + IntS get_min(bool control_at_tap_side) const { + return control_at_tap_side ? tap_range_max_comp : tap_range_min_comp; + } + IntS get_max(bool control_at_tap_side) const { return control_at_tap_side ? tap_range_min : tap_range_max; } +}; +auto check_compensated_exact_per_strategy(CompensatedResultPerStrategy const& comp_result) -> TapPositionCheckFunc { + return [comp_result](IntS value, OptimizerStrategy strategy, bool control_at_tap_side) { + using enum OptimizerStrategy; + + switch (strategy) { + case any: + case fast_any: + CHECK(value == comp_result.get_any(control_at_tap_side)); + break; + case local_maximum: + case global_maximum: + CHECK(value == comp_result.get_max(control_at_tap_side)); + break; + case local_minimum: + case global_minimum: + CHECK(value == comp_result.get_min(control_at_tap_side)); + break; + default: + FAIL("Unreachable"); + } + }; +} +struct GenericResultPerStrategy { + IntS tap_pos_any_1; + IntS tap_pos_any_2; + IntS tap_pos_any_3; + IntS tap_range_min_1; + IntS tap_range_min_2; + IntS tap_range_min_3; + IntS tap_range_max_1; + IntS tap_range_max_2; + IntS tap_range_max_3; + + IntS get_any(ControlSide const& tap_side) const { + using enum ControlSide; + + switch (tap_side) { + case side_1: + return tap_pos_any_1; + case side_2: + return tap_pos_any_2; + case side_3: + return tap_pos_any_3; + default: + FAIL("Unreachable in get_any"); + return 0; + } + } + + IntS get_min(ControlSide const& tap_side) const { + using enum ControlSide; + + switch (tap_side) { + case side_1: + return tap_range_min_1; + case side_2: + return tap_range_min_2; + case side_3: + return tap_range_min_3; + default: + FAIL("Unreachable in get_min"); + return 0; + } + } + IntS get_max(ControlSide const& tap_side) const { + using enum ControlSide; + + switch (tap_side) { + case side_1: + return tap_range_max_1; + case side_2: + return tap_range_max_2; + case side_3: + return tap_range_max_3; + default: + FAIL("Unreachable in get_max"); + return 0; + } + } }; -auto check_exact_per_strategy(IntS tap_pos_any, IntS tap_pos_min, IntS tap_pos_max) -> TapPositionCheckFunc { - return [tap_pos_any, tap_pos_min, tap_pos_max](IntS value, OptimizerStrategy strategy) { +auto check_generic_exact_per_strategy(GenericResultPerStrategy const& generic_result) -> TapPositionCheckFuncGeneric { + return [generic_result](IntS value, OptimizerStrategy strategy, ControlSide tap_side) { using enum OptimizerStrategy; switch (strategy) { case any: - CHECK(value == tap_pos_any); + case fast_any: + CHECK(value == generic_result.get_any(tap_side)); break; case local_maximum: case global_maximum: - CHECK(value == tap_pos_max); + CHECK(value == generic_result.get_max(tap_side)); break; case local_minimum: case global_minimum: - CHECK(value == tap_pos_min); + CHECK(value == generic_result.get_min(tap_side)); break; default: FAIL("Unreachable"); @@ -755,9 +921,9 @@ TEST_CASE("Test Tap position optimizer") { SUBCASE("optimization") { main_core::emplace_component( - state, 1, MockTransformerState{.id = 1, .math_id = {.group = 0, .pos = 0}}); + state, 1, MockTransformerState{.id = 1, .tap_side = ControlSide::from, .math_id = {.group = 0, .pos = 0}}); main_core::emplace_component( - state, 2, MockTransformerState{.id = 2, .math_id = {.group = 0, .pos = 1}}); + state, 2, MockTransformerState{.id = 2, .tap_side = ControlSide::from, .math_id = {.group = 0, .pos = 1}}); auto& transformer_a = main_core::get_component(state, 1); auto& transformer_b = main_core::get_component(state, 2); @@ -802,7 +968,9 @@ TEST_CASE("Test Tap position optimizer") { state_b.tap_min = 1; state_b.tap_max = 1; state_b.rank = MockTransformerState::unregulated; - check_b = [&state_b](IntS value, OptimizerStrategy /*strategy*/) { CHECK(value == state_b.tap_pos); }; + check_b = [&state_b](IntS value, OptimizerStrategy /*strategy*/, bool /*control_at_tap_side*/) { + CHECK(value == state_b.tap_pos); + }; auto const control_side = main_core::get_component(state, 4).control_side(); SUBCASE("not regulated") {} @@ -834,26 +1002,26 @@ TEST_CASE("Test Tap position optimizer") { SUBCASE("multipe valid values") { state_b.rank = 0; - check_b = [&state_b](IntS value, OptimizerStrategy strategy) { + check_b = [&state_b](IntS value, OptimizerStrategy strategy, bool control_at_tap_side) { switch (strategy) { using enum OptimizerStrategy; case any: + case fast_any: CHECK(value == state_b.tap_pos); break; case local_maximum: case global_maximum: - // max voltage => min tap pos - CHECK(value == state_b.tap_min); + CHECK(value == (control_at_tap_side ? state_b.tap_max : state_b.tap_min)); break; case local_minimum: case global_minimum: - // min voltage => max tap pos - CHECK(value == state_b.tap_max); + CHECK(value == (control_at_tap_side ? state_b.tap_min : state_b.tap_max)); break; default: FAIL("unreachable"); } }; + SUBCASE("normal tap range") { state_b.tap_min = 1; state_b.tap_max = 3; @@ -886,12 +1054,12 @@ TEST_CASE("Test Tap position optimizer") { SUBCASE("voltage band") { state_b.rank = 0; - state_b.u_pu = [&state_b, ®ulator_b](ControlSide side) { - CHECK(side == regulator_b.control_side()); - - // tap pos closer to tap_max at tap side <=> lower voltage at control side - return static_cast( - test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min)); + state_b.u_pu = [&state_b, ®ulator_b](ControlSide /*side*/) { + return state_b.tap_side == regulator_b.control_side() + ? static_cast( + test::normalized_lerp(state_b.tap_pos, state_b.tap_min, state_b.tap_max)) + : static_cast( + test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min)); }; auto update_data = TransformerTapRegulatorUpdate{.id = 4, .u_set = 0.5, .u_band = 0.0}; @@ -904,16 +1072,19 @@ TEST_CASE("Test Tap position optimizer") { SUBCASE("line drop compensation") { state_b.rank = 0; - state_b.u_pu = [&state_b, ®ulator_b](ControlSide side) { - CHECK(side == regulator_b.control_side()); - - // tap pos closer to tap_max at tap side <=> lower voltage at control side - return static_cast( - test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min)); + state_b.u_pu = [&state_b, ®ulator_b](ControlSide /*side*/) { + return state_b.tap_side == regulator_b.control_side() + ? static_cast( + test::normalized_lerp(state_b.tap_pos, state_b.tap_min, state_b.tap_max)) + : static_cast( + test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min)); }; state_b.i_pu = [&state_b, ®ulator_b](ControlSide side) { - CHECK(side == regulator_b.control_side()); - auto const value = test::normalized_lerp(state_b.tap_pos, state_b.tap_min, state_b.tap_max); + bool const control_at_tap = side == regulator_b.control_side(); + + auto const value = control_at_tap + ? test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min) + : test::normalized_lerp(state_b.tap_pos, state_b.tap_min, state_b.tap_max); return DoubleComplex{value, value}; }; @@ -926,15 +1097,30 @@ TEST_CASE("Test Tap position optimizer") { SUBCASE("no line drop compensation") { check_b = test::check_exact_per_strategy(3, 4, 2); } SUBCASE("resistance") { update_data.line_drop_compensation_r = 0.5 / base_power_3p; - check_b = test::check_exact_per_strategy(3, 5, 3); + check_b = test::check_compensated_exact_per_strategy({.tap_pos_any = 3, + .tap_pos_any_comp = 3, + .tap_range_min = 3, + .tap_range_max = 3, + .tap_range_min_comp = 4, + .tap_range_max_comp = 1}); } SUBCASE("positive reactance") { update_data.line_drop_compensation_x = 0.125 / base_power_3p; - check_b = test::check_exact_per_strategy(3, 5, 2); + check_b = test::check_compensated_exact_per_strategy({.tap_pos_any = 3, + .tap_pos_any_comp = 3, + .tap_range_min = 4, + .tap_range_max = 2, + .tap_range_min_comp = 4, + .tap_range_max_comp = 1}); } SUBCASE("negative reactance") { update_data.line_drop_compensation_x = -0.5 / base_power_3p; - check_b = test::check_exact_per_strategy(3, 5, 3); + check_b = test::check_compensated_exact_per_strategy({.tap_pos_any = 3, + .tap_pos_any_comp = 3, + .tap_range_min = 3, + .tap_range_max = 3, + .tap_range_min_comp = 4, + .tap_range_max_comp = 1}); } regulator_b.update(update_data); @@ -953,10 +1139,13 @@ TEST_CASE("Test Tap position optimizer") { // u_2a = f(tap_pos_a) when rank is 0 // u_2a = (u_1a * n_1) / (1.0 + relative_tap_pos_a) + // u_2a = 1.0 + relative_tap_pos_a, when control side is at tap side // consider u_1a = n_1 = 1.0 // For a tap_size of 0.1 and tap_nom of 0, tap_pos_relative_a = 0.1 * (tap_pos_a - 0) auto const relative_tap_a = static_cast(state_a.tap_pos) * 0.1; - return static_cast(1.0 / (1.0 + relative_tap_a)); + return state_a.tap_side == regulator_a.control_side() + ? static_cast(1.0 + relative_tap_a) + : static_cast(1.0 / (1.0 + relative_tap_a)); }; state_b.u_pu = [&state_a, ®ulator_a, &state_b, ®ulator_b](ControlSide side) { @@ -964,82 +1153,42 @@ TEST_CASE("Test Tap position optimizer") { // u_2b = f(tap_pos_a, tap_pos_b) when rank is 1 // u_2b = (u_1b * n_2) / (1.0 + relative_tap_pos_b) + // u_2b = (1.0 + relative_tap_pos_b) / (u_1b * n_2), when control side is at tap side // consider n_2 = 1. Also u_1a = u_2b // For a tap_size of 0.1 and tap_nom of 0, tap_pos_relative_b = 0.1 * (tap_pos_b - 0) auto const relative_tap_b = static_cast(state_b.tap_pos) * 0.1; - return state_a.u_pu(regulator_a.control_side()) / (1.0 + relative_tap_b); + return state_b.tap_side == regulator_b.control_side() + ? (1.0 + relative_tap_b) * state_a.u_pu(regulator_a.control_side()) + : state_a.u_pu(regulator_a.control_side()) / (1.0 + relative_tap_b); }; SUBCASE("Situation 1") { regulator_a.update({.id = 3, .u_set = 1.25, .u_band = 0.01}); - regulator_b.update({.id = 4, .u_set = 1.13636, .u_band = 0.01}); + regulator_b.update({.id = 4, .u_set = 0.9, .u_band = 0.5}); check_a = test::check_exact(-2); - check_b = test::check_exact(1); + check_b = test::check_compensated_exact_per_strategy({.tap_pos_any = 1, + .tap_pos_any_comp = -1, + .tap_range_min = -1, + .tap_range_max = 1, + .tap_range_min_comp = 5, + .tap_range_max_comp = -4}); } SUBCASE("Situation 2") { regulator_a.update({.id = 3, .u_set = 1.1111, .u_band = 0.01}); - regulator_b.update({.id = 4, .u_set = 1.5873, .u_band = 0.01}); + regulator_b.update({.id = 4, .u_set = 1.0873, .u_band = 0.1}); check_a = test::check_exact(-1); - check_b = test::check_exact(-3); + check_b = test::check_exact(0); } SUBCASE("Situation 3") { regulator_a.update({.id = 3, .u_set = 1.0, .u_band = 0.01}); - regulator_b.update({.id = 4, .u_set = 0.7142, .u_band = 0.01}); + regulator_b.update({.id = 4, .u_set = 1.0, .u_band = 0.01}); check_a = test::check_exact(0); - check_b = test::check_exact(4); - } - } - - SUBCASE("multiple transformers with generic control function") { - state_a.tap_min = 0; - state_a.tap_max = 2; - state_b.tap_min = 0; - state_b.tap_max = 2; - regulator_a.update({.id = 3, .u_set = 1.0, .u_band = 0.2}); - regulator_b.update({.id = 4, .u_set = 1.0, .u_band = 0.2}); - - // Both control side voltages have a function which follows this table - // t_a \ t_b | 0 | 1 | 2 | 3 - // --------- | ---- | ---- | ---- | ---- - // 0 | 1.5 | 1.25 | 1.0 | 0.75 - // 1 | 1.25 | 1.0 | 0.75 | 0.5 - // 2 | 1.0 | 0.75 | 0.5 | 0.25 - // 3 | 0.75 | 0.5 | 0.25 | 0.0 - - state_a.u_pu = [&state_a, &state_b, ®ulator_a](ControlSide side) { - CHECK(side == regulator_a.control_side()); - auto const tap_sum = static_cast(state_a.tap_pos + state_b.tap_pos); - return static_cast(1.5 - tap_sum / 4.0); - }; - - state_b.u_pu = [&state_a, &state_b, ®ulator_b](ControlSide side) { - CHECK(side == regulator_b.control_side()); - auto const tap_sum = static_cast(state_a.tap_pos + state_b.tap_pos); - return static_cast(1.5 - tap_sum / 4.0); - }; - - SUBCASE("Rank a < Rank b") { - state_a.rank = 0; - state_b.rank = 1; - check_a = test::check_exact_per_strategy(2, 0, 2); - check_b = test::check_exact_per_strategy(0, 2, 0); - } - SUBCASE("Rank a > Rank b") { - state_a.rank = 1; - state_b.rank = 0; - check_a = test::check_exact_per_strategy(0, 2, 0); - check_b = test::check_exact_per_strategy(2, 0, 2); - } - SUBCASE("Rank a == Rank b") { - state_a.rank = 0; - state_b.rank = 0; - check_a = test::check_exact(1); - check_b = test::check_exact(1); + check_b = test::check_exact(0); } } - auto const initial_a{transformer_a.tap_pos()}; - auto const initial_b{transformer_b.tap_pos()}; + auto const initial_tap_pos_a{transformer_a.tap_pos()}; + auto const initial_tap_pos_b{transformer_b.tap_pos()}; for (auto strategy_search_side : test::strategy_search_and_sides) { auto strategy = strategy_search_side.strategy; @@ -1050,7 +1199,7 @@ TEST_CASE("Test Tap position optimizer") { CAPTURE(tap_side); state_b.tap_side = tap_side; - state_a.tap_side = tap_side; + state_a.tap_side = ControlSide::to; // no need to make tap side of a a variable auto optimizer = get_optimizer(strategy, search); auto const result = optimizer.optimize(state, CalculationMethod::default_method); @@ -1070,31 +1219,185 @@ TEST_CASE("Test Tap position optimizer") { // check optimal state CHECK(result.solver_output.size() == 1); - check_a(get_state_tap_pos(state_a.id), strategy); - check_b(get_state_tap_pos(state_b.id), strategy); + auto const control_at_tap_side_a = regulator_a.control_side() == state_a.tap_side; + auto const control_at_tap_side_b = regulator_b.control_side() == state_b.tap_side; + check_a(get_state_tap_pos(state_a.id), strategy, control_at_tap_side_a); + check_b(get_state_tap_pos(state_b.id), strategy, control_at_tap_side_b); // check optimal output if (state_a.rank != MockTransformerState::unregulated) { - check_a(get_output_tap_pos(state_a.id), strategy); + check_a(get_output_tap_pos(state_a.id), strategy, control_at_tap_side_a); } if (state_b.rank != MockTransformerState::unregulated) { - check_b(get_output_tap_pos(state_b.id), strategy); + check_b(get_output_tap_pos(state_b.id), strategy, control_at_tap_side_b); } // reset - CHECK(transformer_a.tap_pos() == initial_a); - CHECK(transformer_b.tap_pos() == initial_b); + CHECK(transformer_a.tap_pos() == initial_tap_pos_a); + CHECK(transformer_b.tap_pos() == initial_tap_pos_b); } } - SUBCASE("Check throw as MaxIterationReached") { // This only applies to non-binary search - state_b.rank = 0; - state_b.u_pu = [&state_b, ®ulator_b](ControlSide side) { + SUBCASE("multiple transformers with generic control function") { + auto check_a = test::check_exact_generic(0); + auto check_b = test::check_exact_generic(0); + + state_a.tap_min = 0; + state_a.tap_max = 3; + state_b.tap_min = 0; + state_b.tap_max = 3; + regulator_a.update({.id = 3, .u_set = 1.0, .u_band = 0.2}); + regulator_b.update({.id = 4, .u_set = 1.0, .u_band = 0.2}); + + // Both control side voltages have a function which follows this table + // t_a \ t_b | 0 | 1 | 2 | 3 + // --------- | ---- | ---- | ---- | ---- + // 0 | 1.5 | 1.25 | 1.0 | 0.75 + // 1 | 1.25 | 1.0 | 0.75 | 0.5 + // 2 | 1.0 | 0.75 | 0.5 | 0.25 + // 3 | 0.75 | 0.5 | 0.25 | 0.0 + + state_a.u_pu = [&state_a, &state_b, ®ulator_a, ®ulator_b](ControlSide side) { + CHECK(side == regulator_a.control_side()); + auto const tap_a_sign = state_a.tap_side == regulator_a.control_side() ? -1.0 : 1.0; + auto const tap_b_sign = state_b.tap_side == regulator_b.control_side() ? -1.0 : 1.0; + auto const tap_sum = tap_a_sign * state_a.tap_pos + tap_b_sign * state_b.tap_pos; + return static_cast(1.5 - tap_sum / 4.0); + }; + + state_b.u_pu = [&state_a, &state_b, ®ulator_a, ®ulator_b](ControlSide side) { CHECK(side == regulator_b.control_side()); + auto const tap_a_sign = state_a.tap_side == regulator_a.control_side() ? -1.0 : 1.0; + auto const tap_b_sign = state_b.tap_side == regulator_b.control_side() ? -1.0 : 1.0; + auto const tap_sum = tap_a_sign * state_a.tap_pos + tap_b_sign * state_b.tap_pos; + return static_cast(1.5 - tap_sum / 4.0); + }; + + SUBCASE("Rank a < Rank b") { + state_a.rank = 0; + state_b.rank = 1; + check_a = test::check_generic_exact_per_strategy({ + .tap_pos_any_1 = 0, + .tap_pos_any_2 = 2, + .tap_pos_any_3 = 2, + .tap_range_min_1 = 1, + .tap_range_min_2 = 2, + .tap_range_min_3 = 0, + .tap_range_max_1 = 0, + .tap_range_max_2 = 3, + .tap_range_max_3 = 2, + }); + check_b = test::check_generic_exact_per_strategy({ + .tap_pos_any_1 = 2, + .tap_pos_any_2 = 0, + .tap_pos_any_3 = 0, + .tap_range_min_1 = 3, + .tap_range_min_2 = 0, + .tap_range_min_3 = 2, + .tap_range_max_1 = 2, + .tap_range_max_2 = 1, + .tap_range_max_3 = 0, + }); + } + + SUBCASE("Rank a > Rank b") { + state_a.rank = 1; + state_b.rank = 0; + check_a = test::check_generic_exact_per_strategy({ + .tap_pos_any_1 = 0, + .tap_pos_any_2 = 2, + .tap_pos_any_3 = 0, + .tap_range_min_1 = 0, + .tap_range_min_2 = 3, + .tap_range_min_3 = 2, + .tap_range_max_1 = 1, + .tap_range_max_2 = 2, + .tap_range_max_3 = 0, + }); + check_b = test::check_generic_exact_per_strategy({ + .tap_pos_any_1 = 2, + .tap_pos_any_2 = 0, + .tap_pos_any_3 = 2, + .tap_range_min_1 = 2, + .tap_range_min_2 = 1, + .tap_range_min_3 = 0, + .tap_range_max_1 = 3, + .tap_range_max_2 = 0, + .tap_range_max_3 = 2, + }); + } + + SUBCASE("Rank a == Rank b") { + state_a.rank = 0; + state_b.rank = 0; + regulator_a.update({.id = 3, .u_set = 1.0, .u_band = 0.5}); // u_band enlarged + regulator_b.update({.id = 4, .u_set = 1.0, .u_band = 0.5}); // u_band enlarged + check_a = test::check_generic_exact_per_strategy({ + .tap_pos_any_1 = 0, + .tap_pos_any_2 = 1, + .tap_pos_any_3 = 1, + .tap_range_min_1 = 0, + .tap_range_min_2 = 3, + .tap_range_min_3 = 1, + .tap_range_max_1 = 1, + .tap_range_max_2 = 2, + .tap_range_max_3 = 1, + }); + check_b = test::check_generic_exact_per_strategy({ + .tap_pos_any_1 = 1, + .tap_pos_any_2 = 0, + .tap_pos_any_3 = 1, + .tap_range_min_1 = 3, + .tap_range_min_2 = 0, + .tap_range_min_3 = 1, + .tap_range_max_1 = 2, + .tap_range_max_2 = 1, + .tap_range_max_3 = 1, + }); + } + + auto const initial_tap_pos_a{transformer_a.tap_pos()}; + auto const initial_tap_pos_b{transformer_b.tap_pos()}; + + for (auto strategy_search_side : test::strategy_search_and_sides) { + auto strategy = strategy_search_side.strategy; + auto search = strategy_search_side.search; + auto tap_side = strategy_search_side.side; + CAPTURE(strategy); + CAPTURE(search); + CAPTURE(tap_side); + + state_b.tap_side = tap_side; + state_a.tap_side = tap_side; + auto optimizer = get_optimizer(strategy, search); + auto const result = optimizer.optimize(state, CalculationMethod::default_method); - // tap pos closer to tap_max at tap side <=> lower voltage at control side - return static_cast( - test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min)); + auto const get_state_tap_pos = [&](ID const id) { + REQUIRE(!result.solver_output.empty()); + return result.solver_output.front().state_tap_positions.at(id); + }; + + // check optimal state + CHECK(result.solver_output.size() == 1); + check_a(get_state_tap_pos(state_a.id), strategy, tap_side); + check_b(get_state_tap_pos(state_b.id), strategy, tap_side); + + // reset + CHECK(transformer_a.tap_pos() == initial_tap_pos_a); + CHECK(transformer_b.tap_pos() == initial_tap_pos_b); + } + } + + SUBCASE("Check throw as MaxIterationReached") { // This only applies to non-binary search + state_b.rank = 0; + state_b.u_pu = [&state_b, ®ulator_b](ControlSide /*side*/) { + return state_b.tap_side == regulator_b.control_side() + ? static_cast( + test::normalized_lerp(state_b.tap_pos, state_b.tap_min, state_b.tap_max)) + : + // tap pos closer to tap_max at tap side <=> lower voltage at control side + static_cast( + test::normalized_lerp(state_b.tap_pos, state_b.tap_max, state_b.tap_min)); }; auto update_data = TransformerTapRegulatorUpdate{.id = 4, .u_set = 0.4, .u_band = 0.0}; diff --git a/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/input.json b/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/input.json index 58178eab23..9bc8598321 100644 --- a/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/input.json +++ b/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/input.json @@ -11,22 +11,18 @@ {"id": 3, "u_rated": 10500}, {"id": 4, "u_rated": 10500}, {"id": 5, "u_rated": 21000}, - {"id": 6, "u_rated": 10500}, - {"id": 25, "u_rated": 21000}, - {"id": 26, "u_rated": 10500} + {"id": 6, "u_rated": 10500} ], "line": [ {"id": 7, "from_node": 2, "to_node": 3, "from_status": 1, "to_status": 1, "r1": 0.506, "x1": 1.07, "c1": 5.099999999999999e-06, "tan1": 0, "r0": 11.47, "x0": 2.94, "c0": 5.099999999999999e-06, "tan0": 0, "i_n": 604}, - {"id": 8, "from_node": 1, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 1.01, "x1": 1.92, "c1": 3.2e-06, "tan1": 0, "r0": 22.36, "x0": 6.11, "c0": 3.2e-06, "tan0": 0, "i_n": 431}, - {"id": 27, "from_node": 1, "to_node": 25, "from_status": 0, "to_status": 1, "r1": 1.01, "x1": 1.92, "c1": 3.2e-06, "tan1": 0, "r0": 22.36, "x0": 6.11, "c0": 3.2e-06, "tan0": 0, "i_n": 431} + {"id": 8, "from_node": 1, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 1.01, "x1": 1.92, "c1": 3.2e-06, "tan1": 0, "r0": 22.36, "x0": 6.11, "c0": 3.2e-06, "tan0": 0, "i_n": 431} ], "transformer": [ {"id": 9, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 12000000, "uk": 0.204, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -11, "tap_max": 9, "tap_nom": 0, "tap_size": 2500, "uk_min": 0.204, "uk_max": 0.204, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0}, {"id": 10, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 12000000, "uk": 0.204, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -11, "tap_max": 9, "tap_nom": 0, "tap_size": 2500, "uk_min": 0.204, "uk_max": 0.204, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0}, {"id": 11, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 21000, "sn": 25000000, "uk": 0.208, "pk": 80000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 2, "clock": 1, "tap_side": 0, "tap_pos": 0, "tap_min": -16, "tap_max": 16, "tap_nom": 0, "tap_size": 1730, "uk_min": 0.208, "uk_max": 0.208, "pk_min": 80000, "pk_max": 80000, "r_grounding_from": 0, "x_grounding_from": 0}, {"id": 12, "from_node": 5, "to_node": 6, "from_status": 1, "to_status": 1, "u1": 21000, "u2": 10000, "sn": 12000000, "uk": 0.08, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 0, "tap_min": -15, "tap_max": 15, "tap_nom": 0, "tap_size": 270, "uk_min": 0.08, "uk_max": 0.08, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0}, - {"id": 13, "from_node": 3, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10500, "u2": 10500, "sn": 12000000, "uk": 0.005, "pk": 0, "i0": 0, "p0": 0, "winding_from": 0, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 7, "tap_min": 1, "tap_max": 13, "tap_nom": 7, "tap_size": 150, "uk_min": 0.004500000000000001, "uk_max": 0.006, "pk_min": 0, "pk_max": 0, "r_grounding_from": 0, "x_grounding_from": 0, "r_grounding_to": 0, "x_grounding_to": 0}, - {"id": 24, "from_node": 25, "to_node": 26, "from_status": 1, "to_status": 1, "u1": 21000, "u2": 10500, "sn": 12000000, "uk": 0.08, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 0, "tap_min": -15, "tap_max": 15, "tap_nom": 0, "tap_size": 270, "uk_min": 0.08, "uk_max": 0.08, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0} + {"id": 13, "from_node": 3, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10500, "u2": 10500, "sn": 12000000, "uk": 0.005, "pk": 0, "i0": 0, "p0": 0, "winding_from": 0, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 7, "tap_min": 1, "tap_max": 13, "tap_nom": 7, "tap_size": 150, "uk_min": 0.004500000000000001, "uk_max": 0.006, "pk_min": 0, "pk_max": 0, "r_grounding_from": 0, "x_grounding_from": 0, "r_grounding_to": 0, "x_grounding_to": 0} ], "source": [ {"id": 14, "node": 0, "status": 1, "u_ref": 1, "sk": 1e+20, "rx_ratio": 0.1, "z01_ratio": 3} @@ -42,8 +38,7 @@ {"id": 20, "regulated_object": 10, "status": 1, "control_side": 1, "u_set": 10600, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0}, {"id": 21, "regulated_object": 11, "status": 1, "control_side": 1, "u_set": 21000, "u_band": 2000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0}, {"id": 22, "regulated_object": 12, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0}, - {"id": 23, "regulated_object": 13, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0}, - {"id": 28, "regulated_object": 24, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0} + {"id": 23, "regulated_object": 13, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0} ] } } \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/sym_output_batch.json b/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/sym_output_batch.json index 1476d458ca..2cb1a3897c 100644 --- a/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/sym_output_batch.json +++ b/tests/data/power_flow/automatic-tap-regulator/pgm-automatic-tap-any/sym_output_batch.json @@ -33,14 +33,6 @@ { "id": 6, "u": 10048.07315915877 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -63,10 +55,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -99,14 +87,6 @@ { "id": 6, "u": 10024.9003318057 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -129,10 +109,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -165,14 +141,6 @@ { "id": 6, "u": 10136.77258061671 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -195,10 +163,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -231,14 +195,6 @@ { "id": 6, "u": 10144.34439013452 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -261,10 +217,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -297,14 +249,6 @@ { "id": 6, "u": 10046.73073697228 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -327,10 +271,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -363,14 +303,6 @@ { "id": 6, "u": 10079.02200578903 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -393,10 +325,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -429,14 +357,6 @@ { "id": 6, "u": 10165.32348156409 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -459,10 +379,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -495,14 +411,6 @@ { "id": 6, "u": 10129.14037222201 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -525,10 +433,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -561,14 +465,6 @@ { "id": 6, "u": 10075.37911738707 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -591,10 +487,6 @@ { "id": 23, "tap_pos": 9 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -627,14 +519,6 @@ { "id": 6, "u": 10048.07315915904 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -657,10 +541,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -693,14 +573,6 @@ { "id": 6, "u": 10024.90033180593 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -723,10 +595,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -759,14 +627,6 @@ { "id": 6, "u": 10136.77258061701 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -789,10 +649,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -825,14 +681,6 @@ { "id": 6, "u": 10144.34439013479 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -855,10 +703,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -891,14 +735,6 @@ { "id": 6, "u": 10046.73073697251 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -921,10 +757,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -957,14 +789,6 @@ { "id": 6, "u": 10079.02200578931 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -987,10 +811,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1023,14 +843,6 @@ { "id": 6, "u": 10165.32348156435 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1053,10 +865,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1089,14 +897,6 @@ { "id": 6, "u": 10129.14037222224 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1119,10 +919,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1155,14 +951,6 @@ { "id": 6, "u": 10075.37911738739 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1185,10 +973,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1221,14 +1005,6 @@ { "id": 6, "u": 10048.0731591589 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1251,10 +1027,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1287,14 +1059,6 @@ { "id": 6, "u": 10024.90033180582 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1317,10 +1081,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1353,14 +1113,6 @@ { "id": 6, "u": 10136.77258061686 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1383,10 +1135,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1419,14 +1167,6 @@ { "id": 6, "u": 10144.34439013465 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1449,10 +1189,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1485,14 +1221,6 @@ { "id": 6, "u": 10046.7307369724 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1515,10 +1243,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1551,14 +1275,6 @@ { "id": 6, "u": 10079.02200578916 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1581,10 +1297,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1617,14 +1329,6 @@ { "id": 6, "u": 10165.32348156422 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1647,10 +1351,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1683,14 +1383,6 @@ { "id": 6, "u": 10129.14037222212 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1713,10 +1405,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1749,14 +1437,6 @@ { "id": 6, "u": 10075.37911738721 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1779,10 +1459,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1815,14 +1491,6 @@ { "id": 6, "u": 10048.07315915894 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1845,10 +1513,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1881,14 +1545,6 @@ { "id": 6, "u": 10024.90033180585 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1911,10 +1567,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -1947,14 +1599,6 @@ { "id": 6, "u": 10136.77258061689 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -1977,10 +1621,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2013,14 +1653,6 @@ { "id": 6, "u": 10144.34439013468 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2043,10 +1675,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2079,14 +1707,6 @@ { "id": 6, "u": 10046.73073697243 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2109,10 +1729,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2145,14 +1761,6 @@ { "id": 6, "u": 10079.02200578922 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2175,10 +1783,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2211,14 +1815,6 @@ { "id": 6, "u": 10165.32348156424 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2241,10 +1837,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2277,14 +1869,6 @@ { "id": 6, "u": 10129.14037222216 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2307,10 +1891,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2343,14 +1923,6 @@ { "id": 6, "u": 10075.37911738727 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2373,10 +1945,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2409,14 +1977,6 @@ { "id": 6, "u": 10048.07315915901 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2439,10 +1999,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2475,14 +2031,6 @@ { "id": 6, "u": 10024.90033180592 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2505,10 +2053,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2541,14 +2085,6 @@ { "id": 6, "u": 10136.77258061698 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2571,10 +2107,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2607,14 +2139,6 @@ { "id": 6, "u": 10144.34439013476 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2637,10 +2161,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2673,14 +2193,6 @@ { "id": 6, "u": 10046.7307369725 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2703,10 +2215,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2739,14 +2247,6 @@ { "id": 6, "u": 10079.02200578929 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2769,10 +2269,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2805,14 +2301,6 @@ { "id": 6, "u": 10165.32348156432 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2835,10 +2323,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2871,14 +2355,6 @@ { "id": 6, "u": 10129.14037222223 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2901,10 +2377,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -2937,14 +2409,6 @@ { "id": 6, "u": 10075.37911738735 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -2967,10 +2431,6 @@ { "id": 23, "tap_pos": 8 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3003,14 +2463,6 @@ { "id": 6, "u": 10048.07315915869 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3033,10 +2485,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3069,14 +2517,6 @@ { "id": 6, "u": 10024.90033180562 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3099,10 +2539,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3135,14 +2571,6 @@ { "id": 6, "u": 10136.77258061664 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3165,10 +2593,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3201,14 +2625,6 @@ { "id": 6, "u": 10144.34439013444 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3231,10 +2647,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3267,14 +2679,6 @@ { "id": 6, "u": 10046.73073697219 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3297,10 +2701,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3333,14 +2733,6 @@ { "id": 6, "u": 10079.02200578893 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3363,10 +2755,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3399,14 +2787,6 @@ { "id": 6, "u": 10165.32348156402 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3429,10 +2809,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3465,14 +2841,6 @@ { "id": 6, "u": 10129.14037222192 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3495,10 +2863,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3531,14 +2895,6 @@ { "id": 6, "u": 10075.37911738698 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3561,10 +2917,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3597,14 +2949,6 @@ { "id": 6, "u": 10048.07315915892 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3627,10 +2971,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3663,14 +3003,6 @@ { "id": 6, "u": 10024.90033180583 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3693,10 +3025,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3729,14 +3057,6 @@ { "id": 6, "u": 10136.77258061688 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3759,10 +3079,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3795,14 +3111,6 @@ { "id": 6, "u": 10144.34439013466 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3825,10 +3133,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3861,14 +3165,6 @@ { "id": 6, "u": 10046.7307369724 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3891,10 +3187,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3927,14 +3219,6 @@ { "id": 6, "u": 10079.02200578919 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -3957,10 +3241,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -3993,14 +3273,6 @@ { "id": 6, "u": 10165.32348156424 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4023,10 +3295,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4059,14 +3327,6 @@ { "id": 6, "u": 10129.14037222214 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4089,10 +3349,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4125,14 +3381,6 @@ { "id": 6, "u": 10075.37911738724 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4155,10 +3403,6 @@ { "id": 23, "tap_pos": 10 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4191,14 +3435,6 @@ { "id": 6, "u": 10048.07315915882 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4221,10 +3457,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4257,14 +3489,6 @@ { "id": 6, "u": 10024.90033180573 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4287,10 +3511,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4323,14 +3543,6 @@ { "id": 6, "u": 10136.77258061677 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4353,10 +3565,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4389,14 +3597,6 @@ { "id": 6, "u": 10144.34439013456 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4419,10 +3619,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4455,14 +3651,6 @@ { "id": 6, "u": 10046.73073697231 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4485,10 +3673,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4521,14 +3705,6 @@ { "id": 6, "u": 10079.02200578907 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4551,10 +3727,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4587,14 +3759,6 @@ { "id": 6, "u": 10165.32348156412 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4617,10 +3781,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4653,14 +3813,6 @@ { "id": 6, "u": 10129.14037222205 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4683,10 +3835,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4719,14 +3867,6 @@ { "id": 6, "u": 10075.37911738712 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4749,10 +3889,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4785,14 +3921,6 @@ { "id": 6, "u": 10048.07315915828 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4815,10 +3943,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4851,14 +3975,6 @@ { "id": 6, "u": 10024.90033180522 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4881,10 +3997,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4917,14 +4029,6 @@ { "id": 6, "u": 10136.7725806162 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -4947,10 +4051,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -4983,14 +4083,6 @@ { "id": 6, "u": 10144.34439013405 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -5013,10 +4105,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -5049,14 +4137,6 @@ { "id": 6, "u": 10046.73073697181 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -5079,10 +4159,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -5115,14 +4191,6 @@ { "id": 6, "u": 10079.02200578851 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -5145,10 +4213,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -5181,14 +4245,6 @@ { "id": 6, "u": 10165.32348156362 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -5211,10 +4267,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -5247,14 +4299,6 @@ { "id": 6, "u": 10129.14037222152 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -5277,10 +4321,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] }, @@ -5313,14 +4353,6 @@ { "id": 6, "u": 10075.37911738651 - }, - { - "id": 25, - "u": 0 - }, - { - "id": 26, - "u": 0 } ], "transformer_tap_regulator": [ @@ -5343,10 +4375,6 @@ { "id": 23, "tap_pos": 7 - }, - { - "id": 28, - "tap_pos": -128 } ] } diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/input.json new file mode 100644 index 0000000000..e64ff3421a --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/input.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 150000}, + {"id": 4, "u_rated": 10500}, + {"id": 6, "u_rated": 21000} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 66000000, "uk": 0.199, "pk": 217000, "i0": 1e-3, "p0": 19500, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": -1, "tap_min": -8, "tap_max": 9, "tap_size": 2500}, + {"id": 5, "from_node": 4, "to_node": 6, "from_status": 1, "to_status": 1, "u1": 10600, "u2": 21000, "sn": 20000000, "uk": 0.119, "pk": 127000, "i0": 1e-03, "p0": 5700, "winding_from": 1, "winding_to": 1, "clock": 2, "tap_side": 1, "tap_pos": 4, "tap_min": -13, "tap_max": 4, "tap_size": 270} + ], + "sym_load": [ + {"id": 7, "node": 6, "status": 1, "type": 0, "p_specified": 10000000, "q_specified": 5000000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1.0} + ], + "transformer_tap_regulator": [ + {"id": 8, "regulated_object": 5, "status": 1, "control_side": 1, "u_set": 21000, "u_band": 522} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/params.json new file mode 100644 index 0000000000..9b92db92dd --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "any_valid_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/sym_output.json new file mode 100644 index 0000000000..af65417c03 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/sym_output.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.999278516660926, "u": 149891.7774991389, "u_angle": -9.40859459e-04, "p": 10072090.38950087, "q": 6233932.488836197}, + {"id": 4, "energized": 1, "u_pu": 1.04527504169727, "u": 10975.38793782133, "u_angle": -2.648551665902222, "p": 1.347554049236793e-07, "q": -6.249688283352644e-08}, + {"id": 6, "energized": 1, "u_pu": 1.000888626113226, "u": 21018.66114837775, "u_angle": 2.531593366079055, "p": -10000000.00000001, "q": -4999999.999999996} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.1794728270763556, "p_from": 10072090.38950087, "q_from": 6233932.488836197, "i_from": 45.62513918866066, "s_from": 11845206.58703947, "p_to": -10045576.12305796, "q_to": -5762159.458271895, "i_to": 609.2000361925834, "s_to": 11580849.76444753}, + {"id": 5, "energized": 1, "loading": 0.579042488222381, "p_from": 10045576.12305808, "q_from": 5762159.458271859, "i_from": 609.2000361925881, "s_from": 11580849.76444762, "p_to": -10000000.00000001, "q_to": -4999999.999999996, "i_to": 307.1067275936952, "s_to": 11180339.88749895} + ], + "sym_load": [ + {"id": 7, "energized": 1, "p": 10000000, "q": 5000000, "i": 307.1067275936951, "s": 11180339.88749895, "pf": 0.8944271909999159} + ], + "source": [ + {"id": 1, "energized": 1, "p": 10072090.38950087, "q": 6233932.488836197, "i": 45.62513918866066, "s": 11845206.58703947, "pf": 0.8503093901731802} + ], + "transformer_tap_regulator": [ + {"id": 8, "energized": 1, "tap_pos": 0} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-any-valid-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/input.json new file mode 100644 index 0000000000..e64ff3421a --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/input.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 150000}, + {"id": 4, "u_rated": 10500}, + {"id": 6, "u_rated": 21000} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 66000000, "uk": 0.199, "pk": 217000, "i0": 1e-3, "p0": 19500, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": -1, "tap_min": -8, "tap_max": 9, "tap_size": 2500}, + {"id": 5, "from_node": 4, "to_node": 6, "from_status": 1, "to_status": 1, "u1": 10600, "u2": 21000, "sn": 20000000, "uk": 0.119, "pk": 127000, "i0": 1e-03, "p0": 5700, "winding_from": 1, "winding_to": 1, "clock": 2, "tap_side": 1, "tap_pos": 4, "tap_min": -13, "tap_max": 4, "tap_size": 270} + ], + "sym_load": [ + {"id": 7, "node": 6, "status": 1, "type": 0, "p_specified": 10000000, "q_specified": 5000000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1.0} + ], + "transformer_tap_regulator": [ + {"id": 8, "regulated_object": 5, "status": 1, "control_side": 1, "u_set": 21000, "u_band": 522} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/params.json new file mode 100644 index 0000000000..614875394c --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "fast_any_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/sym_output.json new file mode 100644 index 0000000000..af65417c03 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/sym_output.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.999278516660926, "u": 149891.7774991389, "u_angle": -9.40859459e-04, "p": 10072090.38950087, "q": 6233932.488836197}, + {"id": 4, "energized": 1, "u_pu": 1.04527504169727, "u": 10975.38793782133, "u_angle": -2.648551665902222, "p": 1.347554049236793e-07, "q": -6.249688283352644e-08}, + {"id": 6, "energized": 1, "u_pu": 1.000888626113226, "u": 21018.66114837775, "u_angle": 2.531593366079055, "p": -10000000.00000001, "q": -4999999.999999996} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.1794728270763556, "p_from": 10072090.38950087, "q_from": 6233932.488836197, "i_from": 45.62513918866066, "s_from": 11845206.58703947, "p_to": -10045576.12305796, "q_to": -5762159.458271895, "i_to": 609.2000361925834, "s_to": 11580849.76444753}, + {"id": 5, "energized": 1, "loading": 0.579042488222381, "p_from": 10045576.12305808, "q_from": 5762159.458271859, "i_from": 609.2000361925881, "s_from": 11580849.76444762, "p_to": -10000000.00000001, "q_to": -4999999.999999996, "i_to": 307.1067275936952, "s_to": 11180339.88749895} + ], + "sym_load": [ + {"id": 7, "energized": 1, "p": 10000000, "q": 5000000, "i": 307.1067275936951, "s": 11180339.88749895, "pf": 0.8944271909999159} + ], + "source": [ + {"id": 1, "energized": 1, "p": 10072090.38950087, "q": 6233932.488836197, "i": 45.62513918866066, "s": 11845206.58703947, "pf": 0.8503093901731802} + ], + "transformer_tap_regulator": [ + {"id": 8, "energized": 1, "tap_pos": 0} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-fast-any-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/input.json new file mode 100644 index 0000000000..e64ff3421a --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/input.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 150000}, + {"id": 4, "u_rated": 10500}, + {"id": 6, "u_rated": 21000} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 66000000, "uk": 0.199, "pk": 217000, "i0": 1e-3, "p0": 19500, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": -1, "tap_min": -8, "tap_max": 9, "tap_size": 2500}, + {"id": 5, "from_node": 4, "to_node": 6, "from_status": 1, "to_status": 1, "u1": 10600, "u2": 21000, "sn": 20000000, "uk": 0.119, "pk": 127000, "i0": 1e-03, "p0": 5700, "winding_from": 1, "winding_to": 1, "clock": 2, "tap_side": 1, "tap_pos": 4, "tap_min": -13, "tap_max": 4, "tap_size": 270} + ], + "sym_load": [ + {"id": 7, "node": 6, "status": 1, "type": 0, "p_specified": 10000000, "q_specified": 5000000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1.0} + ], + "transformer_tap_regulator": [ + {"id": 8, "regulated_object": 5, "status": 1, "control_side": 1, "u_set": 21000, "u_band": 522} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/params.json new file mode 100644 index 0000000000..d22393c9e0 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "max_voltage_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/sym_output.json new file mode 100644 index 0000000000..af65417c03 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/sym_output.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.999278516660926, "u": 149891.7774991389, "u_angle": -9.40859459e-04, "p": 10072090.38950087, "q": 6233932.488836197}, + {"id": 4, "energized": 1, "u_pu": 1.04527504169727, "u": 10975.38793782133, "u_angle": -2.648551665902222, "p": 1.347554049236793e-07, "q": -6.249688283352644e-08}, + {"id": 6, "energized": 1, "u_pu": 1.000888626113226, "u": 21018.66114837775, "u_angle": 2.531593366079055, "p": -10000000.00000001, "q": -4999999.999999996} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.1794728270763556, "p_from": 10072090.38950087, "q_from": 6233932.488836197, "i_from": 45.62513918866066, "s_from": 11845206.58703947, "p_to": -10045576.12305796, "q_to": -5762159.458271895, "i_to": 609.2000361925834, "s_to": 11580849.76444753}, + {"id": 5, "energized": 1, "loading": 0.579042488222381, "p_from": 10045576.12305808, "q_from": 5762159.458271859, "i_from": 609.2000361925881, "s_from": 11580849.76444762, "p_to": -10000000.00000001, "q_to": -4999999.999999996, "i_to": 307.1067275936952, "s_to": 11180339.88749895} + ], + "sym_load": [ + {"id": 7, "energized": 1, "p": 10000000, "q": 5000000, "i": 307.1067275936951, "s": 11180339.88749895, "pf": 0.8944271909999159} + ], + "source": [ + {"id": 1, "energized": 1, "p": 10072090.38950087, "q": 6233932.488836197, "i": 45.62513918866066, "s": 11845206.58703947, "pf": 0.8503093901731802} + ], + "transformer_tap_regulator": [ + {"id": 8, "energized": 1, "tap_pos": 0} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-max-voltage-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/input.json new file mode 100644 index 0000000000..e64ff3421a --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/input.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 150000}, + {"id": 4, "u_rated": 10500}, + {"id": 6, "u_rated": 21000} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 66000000, "uk": 0.199, "pk": 217000, "i0": 1e-3, "p0": 19500, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": -1, "tap_min": -8, "tap_max": 9, "tap_size": 2500}, + {"id": 5, "from_node": 4, "to_node": 6, "from_status": 1, "to_status": 1, "u1": 10600, "u2": 21000, "sn": 20000000, "uk": 0.119, "pk": 127000, "i0": 1e-03, "p0": 5700, "winding_from": 1, "winding_to": 1, "clock": 2, "tap_side": 1, "tap_pos": 4, "tap_min": -13, "tap_max": 4, "tap_size": 270} + ], + "sym_load": [ + {"id": 7, "node": 6, "status": 1, "type": 0, "p_specified": 10000000, "q_specified": 5000000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1.0} + ], + "transformer_tap_regulator": [ + {"id": 8, "regulated_object": 5, "status": 1, "control_side": 1, "u_set": 21000, "u_band": 522} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/params.json new file mode 100644 index 0000000000..a8c656c79c --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "min_voltage_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/sym_output.json new file mode 100644 index 0000000000..800fe32e5a --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/sym_output.json @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.999278516660926, "u": 149891.7774991389, "u_angle": -9.40859459e-04, "p": 10072090.38950087, "q": 6233932.488836197}, + {"id": 4, "energized": 1, "u_pu": 1.04527504169727, "u": 10975.38793782133, "u_angle": -2.648551665902222, "p": 1.347554049236793e-07, "q": -6.249688283352644e-08}, + {"id": 6, "energized": 1, "u_pu": 0.9880200580631995, "u": 20748.42121932719, "u_angle": 2.5315933660790546, "p": -10000000.00000001, "q": -4999999.999999996} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.1794728270763556, "p_from": 10072090.38950087, "q_from": 6233932.488836197, "i_from": 45.62513918866066, "s_from": 11845206.58703947, "p_to": -10045576.12305796, "q_to": -5762159.458271895, "i_to": 609.2000361925834, "s_to": 11580849.76444753}, + {"id": 5, "energized": 1, "loading": 0.579042488222381, "p_from": 10045576.12305808, "q_from": 5762159.458271859, "i_from": 609.2000361925881, "s_from": 11580849.76444762, "p_to": -10000000.00000001, "q_to": -4999999.999999996, "i_to": 311.1066705001248, "s_to": 11180339.88749895} + ], + "sym_load": [ + {"id": 7, "energized": 1, "p": 10000000, "q": 5000000, "i": 311.1066705001252, "s": 11180339.88749895, "pf": 0.8944271909999159} + ], + "source": [ + {"id": 1, "energized": 1, "p": 10072090.38950087, "q": 6233932.488836197, "i": 45.62513918866066, "s": 11845206.58703947, "pf": 0.8503093901731802} + ], + "transformer_tap_regulator": [ + {"id": 8, "energized": 1, "tap_pos": -1} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/step-up-transformer-min-voltage-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/input.json new file mode 100644 index 0000000000..f1e4a62a8e --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/input.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 10000}, + {"id": 4, "u_rated": 400} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 100000, "uk": 0.1, "pk": 1000, "i0": 1e-06, "p0": 100, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 1, "tap_pos": -6, "tap_min": -11, "tap_max": 9, "tap_size": 4} + ], + "sym_load": [ + {"id": 5, "node": 4, "status": 1, "type": 0, "p_specified": 1000, "q_specified": 5000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1} + ], + "transformer_tap_regulator": [ + {"id": 6, "regulated_object": 3, "status": 1, "control_side": 1, "u_set": 400, "u_band": 40} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/params.json new file mode 100644 index 0000000000..9b92db92dd --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "any_valid_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/sym_output.json new file mode 100644 index 0000000000..e856140d16 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/sym_output.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.9999994897958192, "u": 9999.994897958191, "u_angle": -5.965288902752594e-08, "p": 1102.127597334631, "q": 5026.237885203922}, + {"id": 4, "energized": 1, "u_pu": 0.9550976436776861, "u": 382.0390574710744, "u_angle": -2.6185409613966666, "p": -999.999999999987, "q": -4999.999999999801} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.05145653750444719, "p_from": 1102.127597334631, "q_from": 5026.237885203922, "i_from": 0.2970846096364031, "s_from": 5145.653750444719, "p_to": -999.999999999987, "q_to": -4999.999999999801, "i_to": 7.705809736479206, "s_to": 5099.019513592587} + ], + "sym_load": [ + {"id": 5, "energized": 1, "p": 1000, "q": 5000, "i": 7.705809736479218, "s": 5099.019513592785, "pf": 0.196116135138184} + ], + "source": [ + {"id": 1, "energized": 1, "p": 1102.127597334631, "q": 5026.237885203921, "i": 0.2970846096364031, "s": 5145.653750444718, "pf": 0.2141861172138484} + ], + "transformer_tap_regulator": [ + {"id": 6, "energized": 1, "tap_pos": -4} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-any-valid-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/input.json new file mode 100644 index 0000000000..f1e4a62a8e --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/input.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 10000}, + {"id": 4, "u_rated": 400} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 100000, "uk": 0.1, "pk": 1000, "i0": 1e-06, "p0": 100, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 1, "tap_pos": -6, "tap_min": -11, "tap_max": 9, "tap_size": 4} + ], + "sym_load": [ + {"id": 5, "node": 4, "status": 1, "type": 0, "p_specified": 1000, "q_specified": 5000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1} + ], + "transformer_tap_regulator": [ + {"id": 6, "regulated_object": 3, "status": 1, "control_side": 1, "u_set": 400, "u_band": 40} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/params.json new file mode 100644 index 0000000000..614875394c --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "fast_any_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/sym_output.json new file mode 100644 index 0000000000..df7345261f --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/sym_output.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.9999994897958192, "u": 9999.994897958191, "u_angle": -5.965288903415767e-08, "p": 1102.127597334631, "q": 5026.237885203922}, + {"id": 4, "energized": 1, "u_pu": 1.014791246407541, "u": 405.9164985630166, "u_angle": -2.6185409613966666, "p": -999.999999999987, "q": -4999.999999999801} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.05145653750444719, "p_from": 1102.127597334631, "q_from": 5026.237885203922, "i_from": 0.2970846096364031, "s_from": 5145.653750444719, "p_to": -999.999999999987, "q_to": -4999.999999999801, "i_to": 7.252526810803689, "s_to": 5099.019513592587} + ], + "sym_load": [ + {"id": 5, "energized": 1, "p": 1000, "q": 5000, "i": 7.25252681080397, "s": 5099.019513592785, "pf": 0.196116135138184} + ], + "source": [ + {"id": 1, "energized": 1, "p": 1102.127597334631, "q": 5026.237885203921, "i": 0.2970846096364031, "s": 5145.653750444718, "pf": 0.2141861172138484} + ], + "transformer_tap_regulator": [ + {"id": 6, "energized": 1, "tap_pos": 2} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-fast-any-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/input.json new file mode 100644 index 0000000000..f1e4a62a8e --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/input.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 10000}, + {"id": 4, "u_rated": 400} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 100000, "uk": 0.1, "pk": 1000, "i0": 1e-06, "p0": 100, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 1, "tap_pos": -6, "tap_min": -11, "tap_max": 9, "tap_size": 4} + ], + "sym_load": [ + {"id": 5, "node": 4, "status": 1, "type": 0, "p_specified": 1000, "q_specified": 5000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1} + ], + "transformer_tap_regulator": [ + {"id": 6, "regulated_object": 3, "status": 1, "control_side": 1, "u_set": 400, "u_band": 40} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/params.json new file mode 100644 index 0000000000..d22393c9e0 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "max_voltage_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/sym_output.json new file mode 100644 index 0000000000..e4e667266c --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/sym_output.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.9999994897958192, "u": 9999.994897958191, "u_angle": -5.965288902823402e-08, "p": 1102.127597334631, "q": 5026.237885203922}, + {"id": 4, "energized": 1, "u_pu": 1.044638047772469, "u": 417.8552191089875, "u_angle": -2.6185409613966666, "p": -999.999999999987, "q": -4999.999999999801} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.05145653750444719, "p_from": 1102.127597334631, "q_from": 5026.237885203922, "i_from": 0.2970846096364031, "s_from": 5145.653750444719, "p_to": -999.999999999987, "q_to": -4999.999999999801, "i_to": 7.045311759066855, "s_to": 5099.019513592587} + ], + "sym_load": [ + {"id": 5, "energized": 1, "p": 1000, "q": 5000, "i": 7.045311759066715, "s": 5099.019513592785, "pf": 0.196116135138184} + ], + "source": [ + {"id": 1, "energized": 1, "p": 1102.127597334631, "q": 5026.237885203921, "i": 0.2970846096364031, "s": 5145.653750444718, "pf": 0.2141861172138484} + ], + "transformer_tap_regulator": [ + {"id": 6, "energized": 1, "tap_pos": 5} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-max-voltage-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/input.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/input.json new file mode 100644 index 0000000000..f1e4a62a8e --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/input.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "u_rated": 10000}, + {"id": 4, "u_rated": 400} + ], + "transformer": [ + {"id": 3, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 100000, "uk": 0.1, "pk": 1000, "i0": 1e-06, "p0": 100, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 1, "tap_pos": -6, "tap_min": -11, "tap_max": 9, "tap_size": 4} + ], + "sym_load": [ + {"id": 5, "node": 4, "status": 1, "type": 0, "p_specified": 1000, "q_specified": 5000} + ], + "source": [ + {"id": 1, "node": 2, "status": 1, "u_ref": 1} + ], + "transformer_tap_regulator": [ + {"id": 6, "regulated_object": 3, "status": 1, "control_side": 1, "u_set": 400, "u_band": 40} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/input.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/input.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/params.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/params.json new file mode 100644 index 0000000000..a8c656c79c --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/params.json @@ -0,0 +1,6 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "min_voltage_tap", + "rtol": 1e-05, + "atol": 1e-05 +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/params.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/params.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/sym_output.json new file mode 100644 index 0000000000..e856140d16 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/sym_output.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 2, "energized": 1, "u_pu": 0.9999994897958192, "u": 9999.994897958191, "u_angle": -5.965288902752594e-08, "p": 1102.127597334631, "q": 5026.237885203922}, + {"id": 4, "energized": 1, "u_pu": 0.9550976436776861, "u": 382.0390574710744, "u_angle": -2.6185409613966666, "p": -999.999999999987, "q": -4999.999999999801} + ], + "transformer": [ + {"id": 3, "energized": 1, "loading": 0.05145653750444719, "p_from": 1102.127597334631, "q_from": 5026.237885203922, "i_from": 0.2970846096364031, "s_from": 5145.653750444719, "p_to": -999.999999999987, "q_to": -4999.999999999801, "i_to": 7.705809736479206, "s_to": 5099.019513592587} + ], + "sym_load": [ + {"id": 5, "energized": 1, "p": 1000, "q": 5000, "i": 7.705809736479218, "s": 5099.019513592785, "pf": 0.196116135138184} + ], + "source": [ + {"id": 1, "energized": 1, "p": 1102.127597334631, "q": 5026.237885203921, "i": 0.2970846096364031, "s": 5145.653750444718, "pf": 0.2141861172138484} + ], + "transformer_tap_regulator": [ + {"id": 6, "energized": 1, "tap_pos": -4} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/sym_output.json.license new file mode 100644 index 0000000000..7601059167 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/trafo-control-tap-same-side-min-voltage-tap/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/unit/test_error_handling.py b/tests/unit/test_error_handling.py index 15902c6fc8..ec07512033 100644 --- a/tests/unit/test_error_handling.py +++ b/tests/unit/test_error_handling.py @@ -10,7 +10,7 @@ from power_grid_model._core.power_grid_meta import initialize_array from power_grid_model.enum import CalculationMethod, LoadGenType, MeasuredTerminalType, TapChangingStrategy from power_grid_model.errors import ( - AutomaticTapCalculationError, + AutomaticTapInputError, ConflictID, ConflictVoltage, IDNotFound, @@ -25,6 +25,7 @@ IterationDiverge, MissingCaseForEnumError, NotObservableError, + PowerGridError, ) from .utils import PowerGridModelWithExt @@ -303,43 +304,80 @@ def test_handle_invalid_calculation_method_error(): model.calculate_power_flow(calculation_method=CalculationMethod.iec60909) -def test_transformer_tap_regulator_at_lv_tap_side(): - node_input = initialize_array("input", "node", 2) - node_input["id"] = [0, 1] - node_input["u_rated"] = [1e4, 4e2] +def test_transformer_tap_regulator_control_side_not_closer_to_source(): + # =====Test Grid===== + # ________[0]________ + # || | | + # [1] [4]--[5] + # | | | + # [2] | [7] + # | [6] | + # [3]----------| [8] + # | | + # L---------------[9] + node_input = initialize_array("input", "node", 10) + node_input["id"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + node_input["u_rated"] = [150e3, 10e3, 10e3, 10e3, 10e3, 50e3, 10e3, 10e3, 10e3, 10e3] + + transformer_input = initialize_array("input", "transformer", 5) + transformer_input["id"] = [11, 12, 13, 14, 15] + transformer_input["from_node"] = [0, 0, 5, 2, 8] + transformer_input["to_node"] = [1, 1, 7, 3, 9] + transformer_input["from_status"] = [1, 1, 1, 1, 1] + transformer_input["to_status"] = [1, 1, 1, 1, 1] + transformer_input["winding_from"] = [1, 1, 1, 1, 1] + transformer_input["winding_to"] = [1, 1, 1, 1, 1] + transformer_input["clock"] = [0, 0, 0, 0, 0] + transformer_input["tap_side"] = [0, 0, 0, 0, 0] + + three_winding_transformer_input = initialize_array("input", "three_winding_transformer", 1) + three_winding_transformer_input["id"] = [16] + three_winding_transformer_input["node_1"] = [0] + three_winding_transformer_input["node_2"] = [4] + three_winding_transformer_input["node_3"] = [5] + three_winding_transformer_input["clock_12"] = [0] + three_winding_transformer_input["clock_13"] = [0] + three_winding_transformer_input["winding_1"] = [1] + three_winding_transformer_input["winding_2"] = [1] + three_winding_transformer_input["winding_3"] = [1] + + line_input = initialize_array("input", "line", 2) + line_input["id"] = [17, 18] + line_input["from_node"] = [3, 3] + line_input["to_node"] = [6, 9] + + link_input = initialize_array("input", "link", 3) + link_input["id"] = [19, 20, 21] + link_input["from_node"] = [2, 6, 8] + link_input["to_node"] = [1, 4, 7] + link_input["from_status"] = [1, 1, 1] + link_input["to_status"] = [1, 1, 1] source_input = initialize_array("input", "source", 1) - source_input["id"] = [2] + source_input["id"] = [22] source_input["node"] = [0] source_input["status"] = [1] - source_input["u_ref"] = [10.0e3] - - transformer_input = initialize_array("input", "transformer", 1) - transformer_input["id"] = [3] - transformer_input["from_node"] = [0] - transformer_input["to_node"] = [1] - transformer_input["from_status"] = [1] - transformer_input["to_status"] = [1] - transformer_input["winding_from"] = [2] - transformer_input["winding_to"] = [1] - transformer_input["clock"] = [5] - transformer_input["tap_side"] = [1] - - transformer_tap_regulator_input = initialize_array("input", "transformer_tap_regulator", 1) - transformer_tap_regulator_input["id"] = [4] - transformer_tap_regulator_input["regulated_object"] = [3] - transformer_tap_regulator_input["status"] = [1] - transformer_tap_regulator_input["control_side"] = [0] + source_input["u_ref"] = [1.0] - with pytest.raises(AutomaticTapCalculationError): - PowerGridModel( - input_data={ - "node": node_input, - "transformer": transformer_input, - "source": source_input, - "transformer_tap_regulator": transformer_tap_regulator_input, - } - ) + transformer_tap_regulator_input = initialize_array("input", "transformer_tap_regulator", 6) + transformer_tap_regulator_input["id"] = [23, 24, 25, 26, 27, 28] + transformer_tap_regulator_input["regulated_object"] = [11, 12, 13, 14, 15, 16] + transformer_tap_regulator_input["status"] = [1, 1, 1, 1, 1, 1] + transformer_tap_regulator_input["control_side"] = [1, 1, 1, 1, 1, 1] + + model = PowerGridModel( + input_data={ + "node": node_input, + "transformer": transformer_input, + "three_winding_transformer": three_winding_transformer_input, + "line": line_input, + "link": link_input, + "source": source_input, + "transformer_tap_regulator": transformer_tap_regulator_input, + } + ) + with pytest.raises(AutomaticTapInputError): + model.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.min_voltage_tap, decode_error=True) def test_automatic_tap_changing(): diff --git a/tests/unit/utils.py b/tests/unit/utils.py index 3c9ef8a927..afab0e4f02 100644 --- a/tests/unit/utils.py +++ b/tests/unit/utils.py @@ -16,6 +16,7 @@ from power_grid_model.data_types import Dataset, PythonDataset, SingleDataset from power_grid_model.errors import ( AutomaticTapCalculationError, + AutomaticTapInputError, ConflictID, ConflictVoltage, IDWrongType, @@ -55,6 +56,7 @@ InvalidMeasuredObject, InvalidRegulatedObject, AutomaticTapCalculationError, + AutomaticTapInputError, InvalidTransformerClock, NotObservableError, SparseMatrixError, diff --git a/tests/unit/validation/test_input_validation.py b/tests/unit/validation/test_input_validation.py index aef0061b50..2e79c22547 100644 --- a/tests/unit/validation/test_input_validation.py +++ b/tests/unit/validation/test_input_validation.py @@ -645,6 +645,7 @@ def test_validate_input_data_transformer_tap_regulator(input_data): UnsupportedTransformerRegulationError("transformer_tap_regulator", ["control_side", "regulated_object"], [54]) in validation_errors ) + assert NotUniqueError("transformer_tap_regulator", "regulated_object", [51, 54]) in validation_errors def test_fault(input_data):