Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature/tap regulator output #607

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ struct TransformerTapRegulatorCalcParam {
};

struct TransformerTapPosition {
Idx2D index{};
ID transformer_id{};
IntS tap_position{};
};
using TransformerTapPositionResult = std::vector<TransformerTapPosition>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,17 @@ class TransformerTapRegulator : public Regulator {
return update_data;
}

constexpr TransformerTapRegulatorOutput get_null_output() const {
return {.id = id(), .energized = 0, .tap_pos = na_IntS};
}
TransformerTapRegulatorOutput get_output(IntS const& tap_pos) const {
TransformerTapRegulatorOutput output{};
output.id = id();
output.energized = static_cast<IntS>(energized(true));
output.tap_pos = tap_pos;
return output;
}
constexpr RegulatorShortCircuitOutput get_null_sc_output() const { return {.id = id(), .energized = 0}; }

template <symmetry_tag sym> TransformerTapRegulatorCalcParam calc_param() const {
TransformerTapRegulatorCalcParam param{};
Expand All @@ -77,7 +81,6 @@ class TransformerTapRegulator : public Regulator {

// getter
ControlSide control_side() const { return control_side_; }
RegulatorShortCircuitOutput get_null_sc_output() const { return {.id = id(), .energized = 0}; }

private:
// transformer tap regulator parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,19 +335,25 @@ inline auto output_result(Component const& fault, MainModelState<ComponentContai
template <std::derived_from<TransformerTapRegulator> Component, class ComponentContainer,
steady_state_solver_output_type SolverOutputType>
requires model_component_state_c<MainModelState, ComponentContainer, Component>
constexpr auto output_result(Component const& /* transformer_tap_regulator */,
constexpr auto output_result(Component const& transformer_tap_regulator,
MainModelState<ComponentContainer> const& /* state */,
std::vector<SolverOutputType> const& /* solver_output */, Idx const /* obj_seq */) {
// TODO: this function is not implemented
using sym = typename SolverOutputType::sym;
return typename TransformerTapRegulator::OutputType<sym>{};
MathOutput<std::vector<SolverOutputType>> const& math_output, Idx const /* obj_seq */) {
if (auto const it = std::ranges::find_if(
math_output.optimizer_output.transformer_tap_positions,
[regulated_object = transformer_tap_regulator.regulated_object()](auto const& transformer_tap_pos) {
return transformer_tap_pos.transformer_id == regulated_object;
});
it != std::end(math_output.optimizer_output.transformer_tap_positions)) {
return transformer_tap_regulator.get_output(it->tap_position);
}
return transformer_tap_regulator.get_null_output();
}
template <std::derived_from<TransformerTapRegulator> Component, class ComponentContainer,
short_circuit_solver_output_type SolverOutputType>
requires model_component_state_c<MainModelState, ComponentContainer, Component>
inline auto output_result(Component const& transformer_tap_regulator,
MainModelState<ComponentContainer> const& /* state */,
std::vector<SolverOutputType> const& /* solver_output */, Idx const /* obj_seq */) {
constexpr auto
output_result(Component const& transformer_tap_regulator, MainModelState<ComponentContainer> const& /* state */,
MathOutput<std::vector<SolverOutputType>> const& /* math_output */, Idx const /* obj_seq */) {
return transformer_tap_regulator.get_null_sc_output();
}

Expand Down Expand Up @@ -415,6 +421,22 @@ constexpr ResIt output_result(MainModelState<ComponentContainer> const& state,
return output_result<Component>(component, math_output.solver_output, math_id);
});
}
template <std::derived_from<Base> Component, class ComponentContainer, typename SolverOutputType,
std::forward_iterator ResIt>
requires model_component_state_c<MainModelState, ComponentContainer, Component> &&
requires(Component const& component, MainModelState<ComponentContainer> const& state,
MathOutput<SolverOutputType> const& math_output, Idx const obj_seq) {
{
output_result<Component>(component, state, math_output, obj_seq)
} -> std::convertible_to<std::iter_value_t<ResIt>>;
}
constexpr ResIt output_result(MainModelState<ComponentContainer> const& state,
MathOutput<SolverOutputType> const& math_output, ResIt res_it) {
return detail::produce_output<Component, Idx>(
state, res_it, [&state, &math_output](Component const& component, Idx const obj_seq) {
return output_result<Component, ComponentContainer>(component, state, math_output, obj_seq);
});
}

// output source, load_gen, shunt individually
template <std::same_as<Appliance> Component, class ComponentContainer, solver_output_type SolverOutputType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,25 +552,6 @@ template <symmetry_tag sym> struct NodeState {
}
};

template <main_core::main_model_state_c State, steady_state_solver_output_type SolverOutputType>
inline void create_tap_regulator_output(State const& state, std::vector<SolverOutputType>& solver_output) {
for (Idx const group : boost::counting_range(Idx{0}, static_cast<Idx>(solver_output.size()))) {
solver_output[group].transformer_tap_regulator.resize(state.math_topology[group]->n_transformer_tap_regulator(),
{.tap_pos = na_IntS});
}
}

template <transformer_c Component, class ComponentContainer>
requires main_core::model_component_state_c<main_core::MainModelState, ComponentContainer, Component>
constexpr void get_transformer_tap_positions(main_core::MainModelState<ComponentContainer> const& state,
TransformerTapPositionResult& transformer_tap_positions) {
constexpr auto group_index = ComponentContainer::template get_type_idx<Component>();
for (auto const& transformer : state.components.template citer<Component>()) {
transformer_tap_positions.emplace_back(Idx2D{group_index, transformer.id()},
narrow_cast<IntS>(transformer.tap_pos()));
}
}

template <typename... T> class TapPositionOptimizerImpl;
template <transformer_c... TransformerTypes, typename StateCalculator, typename StateUpdater_, typename State_,
typename TransformerRanker_>
Expand Down Expand Up @@ -604,7 +585,6 @@ class TapPositionOptimizerImpl<std::tuple<TransformerTypes...>, StateCalculator,
: calculate_{std::move(calculator)}, update_{std::move(updater)}, strategy_{strategy} {}

auto optimize(State const& state, CalculationMethod method) -> MathOutput<ResultType> final {

auto const order = regulator_mapping<TransformerTypes...>(state, TransformerRanker{}(state));

auto const cache = this->cache_states(order);
Expand All @@ -622,21 +602,25 @@ class TapPositionOptimizerImpl<std::tuple<TransformerTypes...>, StateCalculator,
initialize(regulator_order);

if (auto result = iterate_with_fallback(state, regulator_order, method); strategy_ == OptimizerStrategy::any) {
return produce_output(state, std::move(result));
return produce_output(regulator_order, std::move(result));
}

// refine solution
exploit_neighborhood(regulator_order);
return produce_output(state, iterate_with_fallback(state, regulator_order, method));
return produce_output(regulator_order, iterate_with_fallback(state, regulator_order, method));
}

auto produce_output(State const& state, ResultType solver_output) const -> MathOutput<ResultType> {
auto produce_output(std::vector<std::vector<RegulatedTransformer>> const& regulator_order,
ResultType solver_output) const -> MathOutput<ResultType> {
TransformerTapPositionResult transformer_tap_positions;

// TODO(mgovers): only output the transformers that are regulated
(get_transformer_tap_positions<TransformerTypes, typename State::ComponentContainer>(state,
transformer_tap_positions),
...);
for (auto const& sub_order : regulator_order) {
for (auto const& regulator : sub_order) {
mgovers marked this conversation as resolved.
Show resolved Hide resolved
auto const& transformer = regulator.transformer;
transformer_tap_positions.push_back(
{.transformer_id = transformer.id(), .tap_position = transformer.tap_pos()});
}
}

return {.solver_output = {std::move(solver_output)},
.optimizer_output = {std::move(transformer_tap_positions)}};
Expand Down
63 changes: 19 additions & 44 deletions tests/cpp_unit_tests/test_tap_position_optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,16 +930,32 @@ TEST_CASE("Test Tap position optimizer") {
auto optimizer = get_optimizer(strategy);
auto const result = optimizer.optimize(state, CalculationMethod::default_method);

auto get_state_tap_pos = [&](const ID id) {
REQUIRE(result.solver_output.size() > 0);
auto const get_state_tap_pos = [&](const ID id) {
REQUIRE(!result.solver_output.empty());
return result.solver_output.front().state_tap_positions.at(id);
};
auto const get_output_tap_pos = [&](const ID id) {
REQUIRE(!result.optimizer_output.transformer_tap_positions.empty());
auto const it = std::ranges::find_if(result.optimizer_output.transformer_tap_positions,
[id](auto const& x) { return x.transformer_id == id; });
REQUIRE(it != std::end(result.optimizer_output.transformer_tap_positions));
CHECK(it->transformer_id == id);
return it->tap_position;
};

// correctness
// 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);

// check optimal output
if (state_a.rank != MockTransformerState::unregulated) {
check_a(get_output_tap_pos(state_a.id), strategy);
}
if (state_b.rank != MockTransformerState::unregulated) {
check_b(get_output_tap_pos(state_b.id), strategy);
}

// reset
CHECK(transformer_a.tap_pos() == initial_a);
CHECK(transformer_b.tap_pos() == initial_b);
Expand Down Expand Up @@ -990,47 +1006,6 @@ TEST_CASE("Test tap position optmizer I/O") {
bad_regulators.end(), 50.0),
DuplicativelyRegulatedObject);
}

SUBCASE("transformer tap position retrieval") {
Jerry-Jinfeng-Guo marked this conversation as resolved.
Show resolved Hide resolved
// Minimum grid for only transformer tap position optimizer I/O
test::TestState state_;
std::vector<NodeInput> nodes{{0, 150e3}, {1, 10e3}, {2, 10e3}, {3, 10e3}, {4, 10e3},
{5, 50e3}, {6, 10e3}, {7, 10e3}, {8, 10e3}, {9, 10e3}};
main_core::add_component<Node>(state_, nodes.begin(), nodes.end(), 50.0);

std::vector<TransformerInput> transformers{
test::get_transformer(11, 0, 1, BranchSide::from, 0), test::get_transformer(12, 0, 1, BranchSide::from, -1),
test::get_transformer(13, 5, 7, BranchSide::from, 1), test::get_transformer(14, 2, 3, BranchSide::from, -2),
test::get_transformer(15, 8, 9, BranchSide::from, 2)};
main_core::add_component<Transformer>(state_, transformers.begin(), transformers.end(), 50.0);

std::vector<ThreeWindingTransformerInput> transformers3w{test::get_transformer3w(16, 0, 4, 5, 3)};
main_core::add_component<ThreeWindingTransformer>(state_, transformers3w.begin(), transformers3w.end(), 50.0);

state_.components.set_construction_complete();

TransformerTapPositionResult transformer_tap_positions;
power_grid_model::optimizer::tap_position_optimizer::get_transformer_tap_positions<
Transformer, test::TestState::ComponentContainer>(state_, transformer_tap_positions);
power_grid_model::optimizer::tap_position_optimizer::get_transformer_tap_positions<
ThreeWindingTransformer, test::TestState::ComponentContainer>(state_, transformer_tap_positions);
std::vector<TransformerTapPosition> expected_tap_positions{
{{3, 11}, 0}, {{3, 12}, -1}, {{3, 13}, 1}, {{3, 14}, -2}, {{3, 15}, 2}, {{4, 16}, 3},
};
auto check_tap_positions_match = [](const std::vector<TransformerTapPosition>& vec1,
const std::vector<TransformerTapPosition>& vec2) {
if (vec1.size() != vec2.size()) {
return false;
}
for (size_t i = 0; i < vec1.size(); ++i) {
if (vec1[i].index != vec2[i].index || vec1[i].tap_position != vec2[i].tap_position) {
return false;
}
}
return true;
};
CHECK(check_tap_positions_match(transformer_tap_positions, expected_tap_positions));
}
}

} // namespace power_grid_model
Expand Down
Loading