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

Refactor solvers #390

Merged
merged 55 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
322a77c
linear pf solver -> add loads and sources
petersalemink95 Sep 20, 2023
f3614c4
linear pf solver -> copy y bus
petersalemink95 Sep 20, 2023
58c9dad
remove lines
petersalemink95 Sep 20, 2023
cb0e14b
sc solver -> copy y bus
petersalemink95 Sep 20, 2023
2934f5c
remove *c
petersalemink95 Sep 20, 2023
d8e40ee
linear pf -> general functions
petersalemink95 Sep 21, 2023
7acc5b2
sc solver -> prep matrix + rhs func
petersalemink95 Sep 21, 2023
1a23260
sc solver -> add sources
petersalemink95 Sep 21, 2023
2516039
sc solver -> add faults
petersalemink95 Sep 21, 2023
1875553
sc solver -> add fault with inf imp
petersalemink95 Sep 21, 2023
0b8162d
sc solver -> add 3p fault with inf imp
petersalemink95 Sep 21, 2023
359a208
sc solver 1p to ground
petersalemink95 Sep 21, 2023
8ce4655
add two ph faults
petersalemink95 Sep 21, 2023
89de420
reformat requires
petersalemink95 Sep 22, 2023
6401561
add_fault
petersalemink95 Sep 22, 2023
adfaa80
add all faults
petersalemink95 Sep 22, 2023
a74c2dd
remove empty SC test file
petersalemink95 Sep 22, 2023
0936183
NR -> replace i with bus_number
petersalemink95 Sep 25, 2023
c49652b
linear PF -> calculate source result
petersalemink95 Sep 25, 2023
990cca1
linear PF -> calculate load_gen result
petersalemink95 Sep 25, 2023
766c9a4
rename k to diagonal position
petersalemink95 Sep 25, 2023
2dc9228
NR -> add_loads
petersalemink95 Sep 25, 2023
811de96
NR -> separate add load
petersalemink95 Sep 25, 2023
657a2ab
NR add sources
petersalemink95 Sep 25, 2023
d761910
move func
petersalemink95 Sep 25, 2023
cfecb6b
prep matrix from network perspective
petersalemink95 Sep 25, 2023
9d337f7
rename i with row
petersalemink95 Sep 25, 2023
8a7c368
it pf solver calc source
petersalemink95 Sep 27, 2023
869fa7e
it pf solver calc load gen
petersalemink95 Sep 27, 2023
dfa9efc
use abs2
petersalemink95 Sep 27, 2023
03fafcf
it curr add loads
petersalemink95 Sep 27, 2023
d0ea336
it curr add sources
petersalemink95 Sep 27, 2023
dbf24f7
when requires not sym use false
petersalemink95 Sep 27, 2023
0adf80c
when requires not sym use false 2
petersalemink95 Sep 27, 2023
5f4b367
add extra if constexpr(sym)
petersalemink95 Oct 2, 2023
5b9190d
not sym
petersalemink95 Oct 2, 2023
a367122
similar add_sources, linear PF, SC
petersalemink95 Oct 3, 2023
b85f8f9
move add_sources out of sc solver and linear pf solver
petersalemink95 Oct 3, 2023
81d79ca
add shared solver functions.hpp
petersalemink95 Oct 4, 2023
cbfe628
copy y_bus for sc solver
petersalemink95 Oct 4, 2023
5dac9ac
add copy y bus lin PF / it curr PF
petersalemink95 Oct 4, 2023
6e65ccf
remove unused variable
petersalemink95 Oct 4, 2023
b67ab7d
calculate source
petersalemink95 Oct 4, 2023
ca997c6
calc load gen result
petersalemink95 Oct 5, 2023
5d172c3
use lambda
petersalemink95 Oct 5, 2023
f39065d
/*i*/
petersalemink95 Oct 5, 2023
d2b212d
make add fault functions larger again
petersalemink95 Oct 6, 2023
b2f4e45
Merge branch 'main' into feature/split-physics-and-math
petersalemink95 Oct 6, 2023
62ee982
code smells p1
petersalemink95 Oct 6, 2023
939fc2b
Merge branch 'feature/split-physics-and-math' of https://github.com/P…
petersalemink95 Oct 6, 2023
43c2bce
Update power_grid_model_c/power_grid_model/include/power_grid_model/m…
petersalemink95 Oct 9, 2023
717b7b7
const -> static
petersalemink95 Oct 9, 2023
62ab3b9
rename to common solver functions
petersalemink95 Oct 9, 2023
d8beafa
add all
petersalemink95 Oct 9, 2023
8a8e580
Merge branch 'main' into feature/split-physics-and-math
petersalemink95 Oct 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project <dynamic.grid.calculation@alliander.com>
//
// SPDX-License-Identifier: MPL-2.0

#pragma once
#ifndef POWER_GRID_MODEL_COMMON_SOLVER_FUNCTIONS_HPP
#define POWER_GRID_MODEL_COMMON_SOLVER_FUNCTIONS_HPP

#include "y_bus.hpp"

#include "../calculation_parameters.hpp"

namespace power_grid_model::common_solver_functions {

template <bool sym>
void add_sources(IdxVector const& source_bus_indptr, Idx const& bus_number, YBus<sym> const& y_bus,
ComplexVector const& u_source_vector, ComplexTensor<sym>& diagonal_element, ComplexValue<sym>& u_bus) {
for (Idx source_number = source_bus_indptr[bus_number]; source_number != source_bus_indptr[bus_number + 1];
++source_number) {
ComplexTensor<sym> const y_source = y_bus.math_model_param().source_param[source_number];
diagonal_element += y_source; // add y_source to the diagonal of Ybus
u_bus += dot(y_source, ComplexValue<sym>{u_source_vector[source_number]}); // rhs += Y_source * U_source
}
}

template <bool sym> void copy_y_bus(YBus<sym> const& y_bus, ComplexTensorVector<sym>& mat_data) {
ComplexTensorVector<sym> const& ydata = y_bus.admittance();
std::transform(y_bus.map_lu_y_bus().cbegin(), y_bus.map_lu_y_bus().cend(), mat_data.begin(), [&](Idx k) {
if (k == -1) {
return ComplexTensor<sym>{};
}
return ydata[k];
});
}

template <bool sym>
void calculate_source_result(Idx const& bus_number, YBus<sym> const& y_bus, PowerFlowInput<sym> const& input,
MathOutput<sym>& output, IdxVector const& source_bus_indptr) {
for (Idx source = source_bus_indptr[bus_number]; source != source_bus_indptr[bus_number + 1]; ++source) {
ComplexValue<sym> const u_ref{input.source[source]};
ComplexTensor<sym> const y_ref = y_bus.math_model_param().source_param[source];
output.source[source].i = dot(y_ref, u_ref - output.u[bus_number]);
output.source[source].s = output.u[bus_number] * conj(output.source[source].i);
}
}

template <bool sym, class LoadGenFunc>
void calculate_load_gen_result(Idx const& bus_number, PowerFlowInput<sym> const& input, MathOutput<sym>& output,
IdxVector const& load_gen_bus_indptr, LoadGenFunc const& load_gen_func) {
for (Idx load_gen = load_gen_bus_indptr[bus_number]; load_gen != load_gen_bus_indptr[bus_number + 1]; ++load_gen) {
switch (LoadGenType const type = load_gen_func(load_gen); type) {
using enum LoadGenType;

case const_pq:
// always same power
output.load_gen[load_gen].s = input.s_injection[load_gen];
break;
case const_y:
// power is quadratic relation to voltage
output.load_gen[load_gen].s = input.s_injection[load_gen] * abs2(output.u[bus_number]);
break;
case const_i:
// power is linear relation to voltage
output.load_gen[load_gen].s = input.s_injection[load_gen] * cabs(output.u[bus_number]);
break;
default:
throw MissingCaseForEnumError("Power injection", type);
}
output.load_gen[load_gen].i = conj(output.load_gen[load_gen].s / output.u[bus_number]);
}
}

} // namespace power_grid_model::common_solver_functions

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Iterative Power Flow
*/

#include "block_matrix.hpp"
#include "common_solver_functions.hpp"
#include "iterative_pf_solver.hpp"
#include "sparse_lu_solver.hpp"
#include "y_bus.hpp"
Expand Down Expand Up @@ -85,19 +86,12 @@ template <bool sym> class IterativeCurrentPFSolver : public IterativePFSolver<sy
// Add source admittance to Y bus and set variable for prepared y bus to true
void initialize_derived_solver(YBus<sym> const& y_bus, MathOutput<sym> const& /* output */) {
IdxVector const& source_bus_indptr = *this->source_bus_indptr_;
ComplexTensorVector<sym> const& ydata = y_bus.admittance();
IdxVector const& bus_entry = y_bus.lu_diag();
// if Y bus is not up to date
// re-build matrix and prefactorize Build y bus data with source admittance
if (y_data_ptr_ != &y_bus.admittance()) {
ComplexTensorVector<sym> mat_data(y_bus.nnz_lu());
// copy y bus data
std::transform(y_bus.map_lu_y_bus().cbegin(), y_bus.map_lu_y_bus().cend(), mat_data.begin(), [&](Idx k) {
if (k == -1) {
return ComplexTensor<sym>{};
}
return ydata[k];
});
common_solver_functions::copy_y_bus<sym>(y_bus, mat_data);

// loop bus
for (Idx bus_number = 0; bus_number != this->n_bus_; ++bus_number) {
Expand Down Expand Up @@ -132,37 +126,8 @@ template <bool sym> class IterativeCurrentPFSolver : public IterativePFSolver<sy

// loop buses: i
for (Idx bus_number = 0; bus_number != this->n_bus_; ++bus_number) {
// loop loads/generation: j
for (Idx load_number = load_gen_bus_indptr[bus_number]; load_number != load_gen_bus_indptr[bus_number + 1];
++load_number) {
// load type
LoadGenType const type = load_gen_type[load_number];
switch (type) {
using enum LoadGenType;

case const_pq:
// I_inj_i = conj(S_inj_j/U_i) for constant PQ type
rhs_u_[bus_number] += conj(input.s_injection[load_number] / u[bus_number]);
break;
case const_y:
// I_inj_i = conj((S_inj_j * abs(U_i)^2) / U_i) = conj((S_inj_j) * U_i for const impedance type
rhs_u_[bus_number] += conj(input.s_injection[load_number]) * u[bus_number];
break;
case const_i:
// I_inj_i = conj(S_inj_j*abs(U_i)/U_i) for const current type
rhs_u_[bus_number] += conj(input.s_injection[load_number] * cabs(u[bus_number]) / u[bus_number]);
break;
default:
throw MissingCaseForEnumError("Injection current calculation", type);
}
}
// loop sources: j
for (Idx source_number = source_bus_indptr[bus_number]; source_number != source_bus_indptr[bus_number + 1];
++source_number) {
// I_inj_i += Y_source_j * U_ref_j
rhs_u_[bus_number] += dot(y_bus.math_model_param().source_param[source_number],
ComplexValue<sym>{input.source[source_number]});
}
add_loads(bus_number, input, load_gen_bus_indptr, load_gen_type, u);
add_sources(bus_number, y_bus, input, source_bus_indptr);
}
}

Expand Down Expand Up @@ -192,6 +157,43 @@ template <bool sym> class IterativeCurrentPFSolver : public IterativePFSolver<sy
// sparse solver
SparseLUSolver<ComplexTensor<sym>, ComplexValue<sym>, ComplexValue<sym>> sparse_solver_;
std::shared_ptr<BlockPermArray const> perm_;

void add_loads(Idx const& bus_number, PowerFlowInput<sym> const& input, IdxVector const& load_gen_bus_indptr,
std::vector<LoadGenType> const& load_gen_type, ComplexValueVector<sym> const& u) {
for (Idx load_number = load_gen_bus_indptr[bus_number]; load_number != load_gen_bus_indptr[bus_number + 1];
++load_number) {
// load type
LoadGenType const type = load_gen_type[load_number];
switch (type) {
using enum LoadGenType;

case const_pq:
// I_inj_i = conj(S_inj_j/U_i) for constant PQ type
rhs_u_[bus_number] += conj(input.s_injection[load_number] / u[bus_number]);
break;
case const_y:
// I_inj_i = conj((S_inj_j * abs(U_i)^2) / U_i) = conj((S_inj_j) * U_i for const impedance type
rhs_u_[bus_number] += conj(input.s_injection[load_number]) * u[bus_number];
break;
case const_i:
// I_inj_i = conj(S_inj_j*abs(U_i)/U_i) for const current type
rhs_u_[bus_number] += conj(input.s_injection[load_number] * cabs(u[bus_number]) / u[bus_number]);
break;
default:
throw MissingCaseForEnumError("Injection current calculation", type);
}
}
}

void add_sources(Idx const& bus_number, YBus<sym> const& y_bus, PowerFlowInput<sym> const& input,
IdxVector const& source_bus_indptr) {
for (Idx source_number = source_bus_indptr[bus_number]; source_number != source_bus_indptr[bus_number + 1];
++source_number) {
// I_inj_i += Y_source_j * U_ref_j
rhs_u_[bus_number] += dot(y_bus.math_model_param().source_param[source_number],
ComplexValue<sym>{input.source[source_number]});
}
}
};

template class IterativeCurrentPFSolver<true>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

// Check if all includes needed
#include "common_solver_functions.hpp"
#include "y_bus.hpp"

#include "../calculation_parameters.hpp"
Expand Down Expand Up @@ -112,41 +113,11 @@ template <bool sym, typename DerivedSolver> class IterativePFSolver {
output.load_gen.resize(load_gen_bus_indptr_->back());
output.bus_injection.resize(n_bus_);

// loop all bus
for (Idx bus = 0; bus != n_bus_; ++bus) {
// source
for (Idx source = (*source_bus_indptr_)[bus]; source != (*source_bus_indptr_)[bus + 1]; ++source) {
ComplexValue<sym> const u_ref{input.source[source]};
ComplexTensor<sym> const y_ref = y_bus.math_model_param().source_param[source];
output.source[source].i = dot(y_ref, u_ref - output.u[bus]);
output.source[source].s = output.u[bus] * conj(output.source[source].i);
}

// load_gen
for (Idx load_gen = (*load_gen_bus_indptr_)[bus]; load_gen != (*load_gen_bus_indptr_)[bus + 1];
++load_gen) {
LoadGenType const type = (*load_gen_type_)[load_gen];
switch (type) {
using enum LoadGenType;

case const_pq:
// always same power
output.load_gen[load_gen].s = input.s_injection[load_gen];
break;
case const_y:
// power is quadratic relation to voltage
output.load_gen[load_gen].s =
input.s_injection[load_gen] * cabs(output.u[bus]) * cabs(output.u[bus]);
break;
case const_i:
// power is linear relation to voltage
output.load_gen[load_gen].s = input.s_injection[load_gen] * cabs(output.u[bus]);
break;
default:
throw MissingCaseForEnumError("Power injection", type);
}
output.load_gen[load_gen].i = conj(output.load_gen[load_gen].s / output.u[bus]);
}
for (Idx bus_number = 0; bus_number != n_bus_; ++bus_number) {
common_solver_functions::calculate_source_result<sym>(bus_number, y_bus, input, output,
*source_bus_indptr_);
common_solver_functions::calculate_load_gen_result<sym>(bus_number, input, output, *load_gen_bus_indptr_,
[this](Idx i) { return (*load_gen_type_)[i]; });
}
output.bus_injection = y_bus.calculate_injection(output.u);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ if there are sources

*/

#include "common_solver_functions.hpp"
#include "sparse_lu_solver.hpp"
#include "y_bus.hpp"

Expand Down Expand Up @@ -57,9 +58,6 @@ template <bool sym> class LinearPFSolver {

MathOutput<sym> run_power_flow(YBus<sym> const& y_bus, PowerFlowInput<sym> const& input,
CalculationInfo& calculation_info) {
// getter
ComplexTensorVector<sym> const& ydata = y_bus.admittance();
IdxVector const& bus_entry = y_bus.lu_diag();
// output
MathOutput<sym> output;
output.u.resize(n_bus_);
Expand All @@ -68,36 +66,8 @@ template <bool sym> class LinearPFSolver {

// prepare matrix
Timer sub_timer(calculation_info, 2221, "Prepare matrix");

// copy y bus data
std::transform(y_bus.map_lu_y_bus().cbegin(), y_bus.map_lu_y_bus().cend(), mat_data_.begin(), [&](Idx k) {
if (k == -1) {
return ComplexTensor<sym>{};
}
return ydata[k];
});

// loop to all loads and sources, j as load number
IdxVector const& load_gen_bus_idxptr = *load_gen_bus_indptr_;
IdxVector const& source_bus_indptr = *source_bus_indptr_;
for (Idx bus_number = 0; bus_number != n_bus_; ++bus_number) {
Idx const data_sequence = bus_entry[bus_number];
// loop loads
for (Idx load_number = load_gen_bus_idxptr[bus_number]; load_number != load_gen_bus_idxptr[bus_number + 1];
++load_number) {
// YBus_diag += -conj(S_base)
add_diag(mat_data_[data_sequence], -conj(input.s_injection[load_number]));
}
// loop sources
for (Idx source_number = source_bus_indptr[bus_number]; source_number != source_bus_indptr[bus_number + 1];
++source_number) {
// YBus_diag += Y_source
mat_data_[data_sequence] += y_bus.math_model_param().source_param[source_number];
// rhs += Y_source_j * U_ref_j
output.u[bus_number] += dot(y_bus.math_model_param().source_param[source_number],
ComplexValue<sym>{input.source[source_number]});
}
}
common_solver_functions::copy_y_bus<sym>(y_bus, mat_data_);
prepare_matrix_and_rhs(y_bus, input, output);

// solve
// u vector will have I_injection for slack bus for now
Expand All @@ -123,6 +93,30 @@ template <bool sym> class LinearPFSolver {
SparseLUSolver<ComplexTensor<sym>, ComplexValue<sym>, ComplexValue<sym>> sparse_solver_;
typename SparseLUSolver<ComplexTensor<sym>, ComplexValue<sym>, ComplexValue<sym>>::BlockPermArray perm_;

void prepare_matrix_and_rhs(YBus<sym> const& y_bus, PowerFlowInput<sym> const& input, MathOutput<sym>& output) {
// getter
IdxVector const& bus_entry = y_bus.lu_diag();
IdxVector const& load_gen_bus_idxptr = *load_gen_bus_indptr_;
IdxVector const& source_bus_indptr = *source_bus_indptr_;
for (Idx bus_number = 0; bus_number != n_bus_; ++bus_number) {
Idx const diagonal_position = bus_entry[bus_number];
auto& diagonal_element = mat_data_[diagonal_position];
auto& u_bus = output.u[bus_number];
add_loads(load_gen_bus_idxptr, bus_number, input, diagonal_element);
common_solver_functions::add_sources<sym>(source_bus_indptr, bus_number, y_bus, input.source,
diagonal_element, u_bus);
}
}

static void add_loads(IdxVector const& load_gen_bus_idxptr, Idx const& bus_number, PowerFlowInput<sym> const& input,
ComplexTensor<sym>& diagonal_element) {
for (Idx load_number = load_gen_bus_idxptr[bus_number]; load_number != load_gen_bus_idxptr[bus_number + 1];
++load_number) {
// YBus_diag += -conj(S_base)
add_diag(diagonal_element, -conj(input.s_injection[load_number]));
}
}

void calculate_result(YBus<sym> const& y_bus, PowerFlowInput<sym> const& input, MathOutput<sym>& output) {
// call y bus
output.branch = y_bus.template calculate_branch_flow<BranchMathOutput<sym>>(output.u);
Expand All @@ -133,23 +127,11 @@ template <bool sym> class LinearPFSolver {
output.load_gen.resize(load_gen_bus_indptr_->back());
output.bus_injection.resize(n_bus_);

// loop all bus
for (Idx bus = 0; bus != n_bus_; ++bus) {
// source
for (Idx source = (*source_bus_indptr_)[bus]; source != (*source_bus_indptr_)[bus + 1]; ++source) {
ComplexValue<sym> const u_ref{input.source[source]};
ComplexTensor<sym> const y_ref = y_bus.math_model_param().source_param[source];
output.source[source].i = dot(y_ref, u_ref - output.u[bus]);
output.source[source].s = output.u[bus] * conj(output.source[source].i);
}

// load_gen
for (Idx load_gen = (*load_gen_bus_indptr_)[bus]; load_gen != (*load_gen_bus_indptr_)[bus + 1];
++load_gen) {
// power is always quadratic relation to voltage for linear pf
output.load_gen[load_gen].s = input.s_injection[load_gen] * abs2(output.u[bus]);
output.load_gen[load_gen].i = conj(output.load_gen[load_gen].s / output.u[bus]);
}
for (Idx bus_number = 0; bus_number != n_bus_; ++bus_number) {
common_solver_functions::calculate_source_result<sym>(bus_number, y_bus, input, output,
*source_bus_indptr_);
common_solver_functions::calculate_load_gen_result<sym>(bus_number, input, output, *load_gen_bus_indptr_,
[](Idx /*i*/) { return LoadGenType::const_y; });
}
output.bus_injection = y_bus.calculate_injection(output.u);
}
Expand Down