Skip to content

Commit

Permalink
Merge pull request #681 from PowerGridModel/feature/calculation-type-…
Browse files Browse the repository at this point in the history
…options

Feature/calculation type in options
  • Loading branch information
mgovers authored Aug 5, 2024
2 parents 7e01723 + 02680d8 commit 6b6cdf8
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ template <class T> constexpr CType ctype_v = ctype_t<T>::value;
// function selector based on ctype
// the operator() of the functor should have a single template parameter
// the selector will instantiate the operator() with relevant type
template <class Functor, class... Args> decltype(auto) ctype_func_selector(CType ctype, Functor f, Args&&... args) {
template <class Functor, class... Args> decltype(auto) ctype_func_selector(CType ctype, Functor&& f, Args&&... args) {
using enum CType;

switch (ctype) {
case c_double:
return f.template operator()<double>(std::forward<Args>(args)...);
return std::forward<Functor>(f).template operator()<double>(std::forward<Args>(args)...);
case c_double3:
return f.template operator()<RealValue<asymmetric_t>>(std::forward<Args>(args)...);
return std::forward<Functor>(f).template operator()<RealValue<asymmetric_t>>(std::forward<Args>(args)...);
case c_int8:
return f.template operator()<int8_t>(std::forward<Args>(args)...);
return std::forward<Functor>(f).template operator()<int8_t>(std::forward<Args>(args)...);
case c_int32:
return f.template operator()<int32_t>(std::forward<Args>(args)...);
return std::forward<Functor>(f).template operator()<int32_t>(std::forward<Args>(args)...);
default:
throw MissingCaseForEnumError{"CType selector", ctype};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ enum class Branch3Side : IntS { side_1 = 0, side_2 = 1, side_3 = 2 };

enum class ControlSide : IntS { from = 0, to = 1, side_1 = 0, side_2 = 1, side_3 = 2 };

enum class CalculationType : IntS { power_flow = 0, state_estimation = 1, short_circuit = 2 };

enum class CalculationSymmetry : IntS { symmetric = 0, asymmetric = 1 };

enum class CalculationMethod : IntS {
default_method = -128,
linear = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,39 +83,60 @@ class MainModel {
impl().output_result<CompType>(math_output, target.begin());
}

template <symmetry_tag sym>
MathOutput<std::vector<SolverOutput<sym>>> calculate_power_flow(Options const& options) {
return impl().calculate_power_flow<sym>(options);
template <symmetry_tag sym> MathOutput<std::vector<SolverOutput<sym>>> calculate_power_flow(Options options) {
options.calculation_type = CalculationType::power_flow;
return impl().calculate<power_flow_t, sym>(options);
}
template <symmetry_tag sym> void calculate_power_flow(Options const& options, MutableDataset const& result_data) {
return impl().calculate_power_flow<sym>(options, result_data);
template <symmetry_tag sym> void calculate_power_flow(Options options, MutableDataset const& result_data) {
options.calculation_type = CalculationType::power_flow;
options.calculation_symmetry =
is_symmetric_v<sym> ? CalculationSymmetry::symmetric : CalculationSymmetry::asymmetric;
return impl().calculate(options, result_data);
}
template <symmetry_tag sym>
BatchParameter calculate_power_flow(Options const& options, MutableDataset const& result_data,
BatchParameter calculate_power_flow(Options options, MutableDataset const& result_data,
ConstDataset const& update_data) {
return impl().calculate_power_flow<sym>(options, result_data, update_data);
options.calculation_type = CalculationType::power_flow;
options.calculation_symmetry =
is_symmetric_v<sym> ? CalculationSymmetry::symmetric : CalculationSymmetry::asymmetric;
return impl().calculate(options, result_data, update_data);
}
template <symmetry_tag sym>
MathOutput<std::vector<SolverOutput<sym>>> calculate_state_estimation(Options const& options) {
return impl().calculate_state_estimation<sym>(options);
template <symmetry_tag sym> MathOutput<std::vector<SolverOutput<sym>>> calculate_state_estimation(Options options) {
options.calculation_type = CalculationType::state_estimation;
options.calculation_symmetry =
is_symmetric_v<sym> ? CalculationSymmetry::symmetric : CalculationSymmetry::asymmetric;
return impl().calculate<state_estimation_t, sym>(options);
}
template <symmetry_tag sym>
BatchParameter calculate_state_estimation(Options const& options, MutableDataset const& result_data,
BatchParameter calculate_state_estimation(Options options, MutableDataset const& result_data,
ConstDataset const& update_data) {

return impl().calculate_state_estimation<sym>(options, result_data, update_data);
options.calculation_type = CalculationType::state_estimation;
options.calculation_symmetry =
is_symmetric_v<sym> ? CalculationSymmetry::symmetric : CalculationSymmetry::asymmetric;
return impl().calculate(options, result_data, update_data);
}
template <symmetry_tag sym>
MathOutput<std::vector<ShortCircuitSolverOutput<sym>>> calculate_short_circuit(Options const& options) {

return impl().calculate_short_circuit<sym>(options);
MathOutput<std::vector<ShortCircuitSolverOutput<sym>>> calculate_short_circuit(Options options) {
options.calculation_type = CalculationType::short_circuit;
options.calculation_symmetry =
is_symmetric_v<sym> ? CalculationSymmetry::symmetric : CalculationSymmetry::asymmetric;
return impl().calculate<short_circuit_t, sym>(options);
}
void calculate_short_circuit(Options const& options, MutableDataset const& result_data) {
return impl().calculate_short_circuit(options, result_data);
void calculate_short_circuit(Options options, MutableDataset const& result_data) {
options.calculation_type = CalculationType::short_circuit;
return impl().calculate(options, result_data);
}
BatchParameter calculate_short_circuit(Options const& options, MutableDataset const& result_data,
BatchParameter calculate_short_circuit(Options options, MutableDataset const& result_data,
ConstDataset const& update_data) {
return impl().calculate_short_circuit(options, result_data, update_data);
options.calculation_type = CalculationType::short_circuit;
return impl().calculate(options, result_data, update_data);
}
void calculate(Options const& options, MutableDataset const& result_data) {
return impl().calculate(options, result_data);
}
BatchParameter calculate(Options const& options, MutableDataset const& result_data,
ConstDataset const& update_data) {
return impl().calculate(options, result_data, update_data);
}

CalculationInfo calculation_info() const { return impl().calculation_info(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ concept cache_type_c = std::same_as<T, cached_update_t> || std::same_as<T, perma
struct MainModelOptions {
static constexpr Idx sequential = -1;

CalculationType calculation_type{CalculationType::power_flow};
CalculationSymmetry calculation_symmetry{CalculationSymmetry::symmetric};
CalculationMethod calculation_method{CalculationMethod::default_method};
OptimizerType optimizer_type{OptimizerType::no_optimization};
OptimizerStrategy optimizer_strategy{OptimizerStrategy::any};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,65 @@ template <> struct output_type_getter<SolverOutput<asymmetric_t>> {
template <class T> using type = meta_data::asym_output_getter_s<T>;
};

struct power_flow_t {};
struct state_estimation_t {};
struct short_circuit_t {};

template <typename T>
concept calculation_type_tag = std::derived_from<T, power_flow_t> || std::derived_from<T, state_estimation_t> ||
std::derived_from<T, short_circuit_t>;

template <class Functor, class... Args>
decltype(auto) calculation_symmetry_func_selector(CalculationSymmetry calculation_symmetry, Functor&& f,
Args&&... args) {
using enum CalculationSymmetry;

switch (calculation_symmetry) {
case symmetric:
return std::forward<Functor>(f).template operator()<symmetric_t>(std::forward<Args>(args)...);
case asymmetric:
return std::forward<Functor>(f).template operator()<asymmetric_t>(std::forward<Args>(args)...);
default:
throw MissingCaseForEnumError{"Calculation symmetry selector", calculation_symmetry};
}
}

template <class Functor, class... Args>
decltype(auto) calculation_type_func_selector(CalculationType calculation_type, Functor&& f, Args&&... args) {
using enum CalculationType;

switch (calculation_type) {
case CalculationType::power_flow:
return std::forward<Functor>(f).template operator()<power_flow_t>(std::forward<Args>(args)...);
case CalculationType::state_estimation:
return std::forward<Functor>(f).template operator()<state_estimation_t>(std::forward<Args>(args)...);
case CalculationType::short_circuit:
return std::forward<Functor>(f).template operator()<short_circuit_t>(std::forward<Args>(args)...);
default:
throw MissingCaseForEnumError{"CalculationType", calculation_type};
}
}

template <class Functor, class... Args>
decltype(auto) calculation_type_symmetry_func_selector(CalculationType calculation_type,
CalculationSymmetry calculation_symmetry, Functor&& f,
Args&&... args) {
calculation_type_func_selector(
calculation_type,
[]<calculation_type_tag calculation_type, typename Functor_, typename... Args_>(
CalculationSymmetry calculation_symmetry_, Functor_ && f_, Args_ && ... args_) {
calculation_symmetry_func_selector(
calculation_symmetry_,
[]<symmetry_tag sym, typename SubFunctor, typename... SubArgs>(SubFunctor && sub_f,
SubArgs && ... sub_args) {
std::forward<SubFunctor>(sub_f).template operator()<calculation_type, sym>(
std::forward<SubArgs>(sub_args)...);
},
std::forward<Functor_>(f_), std::forward<Args_>(args_)...);
},
calculation_symmetry, std::forward<Functor>(f), std::forward<Args>(args)...);
}

// main model implementation template
template <class T, class U> class MainModelImpl;

Expand Down Expand Up @@ -651,106 +710,64 @@ class MainModelImpl<ExtraRetrievableTypes<ExtraRetrievableType...>, ComponentLis
return std::ranges::all_of(update_independent, [](bool const is_independent) { return is_independent; });
}

template <symmetry_tag sym> auto calculate_power_flow(Options const& options) {
// Single calculation
template <calculation_type_tag calculation_type, symmetry_tag sym> auto calculate(Options const& options) {
auto const calculator = [this, &options] {
if constexpr (std::derived_from<calculation_type, power_flow_t>) {
return calculate_power_flow_<sym>(options.err_tol, options.max_iter);
}
assert(options.optimizer_type == OptimizerType::no_optimization);
if constexpr (std::derived_from<calculation_type, state_estimation_t>) {
return calculate_state_estimation_<sym>(options.err_tol, options.max_iter);
}
if constexpr (std::derived_from<calculation_type, short_circuit_t>) {
return calculate_short_circuit_<sym>(options.short_circuit_voltage_scaling);
}
throw UnreachableHit{"MainModelImpl::calculate", "Unknown calculation type"};
}();

return optimizer::get_optimizer<MainModelState, ConstDataset>(
options.optimizer_type, options.optimizer_strategy,
calculate_power_flow_<sym>(options.err_tol, options.max_iter),
options.optimizer_type, options.optimizer_strategy, calculator,
[this](ConstDataset update_data) { this->update_component<permanent_update_t>(update_data); },
*meta_data_)
->optimize(state_, options.calculation_method);
}

// Single load flow calculation, propagating the results to result_data
template <symmetry_tag sym>
void calculate_power_flow(Options const& options, MutableDataset const& result_data, Idx pos = 0) {
// Single calculation, propagating the results to result_data
void calculate(Options options, MutableDataset const& result_data, Idx pos = 0) {
assert(construction_complete_);
auto const math_output = calculate_power_flow<sym>(options);

if (pos != ignore_output) {
output_result(math_output, result_data, pos);
}
}
if (options.calculation_type == CalculationType::short_circuit) {
auto const faults = state_.components.template citer<Fault>();
auto const is_three_phase = std::ranges::all_of(
faults, [](Fault const& fault) { return fault.get_fault_type() == FaultType::three_phase; });
options.calculation_symmetry =
is_three_phase ? CalculationSymmetry::symmetric : CalculationSymmetry::asymmetric;
};

// Batch load flow calculation, propagating the results to result_data
template <symmetry_tag sym>
BatchParameter calculate_power_flow(Options const& options, MutableDataset const& result_data,
ConstDataset const& update_data) {
return batch_calculation_(
[&options](MainModelImpl& model, MutableDataset const& target_data, Idx pos) {
auto sub_opt = options; // copy
sub_opt.err_tol = pos != ignore_output ? options.err_tol : std::numeric_limits<double>::max();
sub_opt.max_iter = pos != ignore_output ? options.max_iter : 1;
calculation_type_symmetry_func_selector(
options.calculation_type, options.calculation_symmetry,
[]<calculation_type_tag calculation_type, symmetry_tag sym>(
MainModelImpl& main_model_, Options const& options_, MutableDataset const& result_data_, Idx pos_) {
auto const math_output = main_model_.calculate<calculation_type, sym>(options_);

model.calculate_power_flow<sym>(sub_opt, target_data, pos);
if (pos_ != ignore_output) {
main_model_.output_result(math_output, result_data_, pos_);
}
},
result_data, update_data, options.threading);
}

// Single state estimation calculation, returning math output results
template <symmetry_tag sym> auto calculate_state_estimation(Options const& options) {
return MathOutput<std::vector<SolverOutput<sym>>>{
.solver_output =
calculate_state_estimation_<sym>(options.err_tol, options.max_iter)(state_, options.calculation_method),
.optimizer_output = {}};
*this, options, result_data, pos);
}

// Single state estimation calculation, propagating the results to result_data
template <symmetry_tag sym>
void calculate_state_estimation(Options const& options, MutableDataset const& result_data, Idx pos = 0) {
assert(construction_complete_);
auto const solver_output = calculate_state_estimation<sym>(options);

if (pos != ignore_output) {
output_result(solver_output, result_data, pos);
}
}

// Batch state estimation calculation, propagating the results to result_data
template <symmetry_tag sym>
BatchParameter calculate_state_estimation(Options const& options, MutableDataset const& result_data,
ConstDataset const& update_data) {
// Batch calculation, propagating the results to result_data
BatchParameter calculate(Options const& options, MutableDataset const& result_data,
ConstDataset const& update_data) {
return batch_calculation_(
[&options](MainModelImpl& model, MutableDataset const& target_data, Idx pos) {
auto sub_opt = options; // copy

sub_opt.err_tol = pos != ignore_output ? options.err_tol : std::numeric_limits<double>::max();
sub_opt.max_iter = pos != ignore_output ? options.max_iter : 1;

model.calculate_state_estimation<sym>(sub_opt, target_data, pos);
},
result_data, update_data, options.threading);
}

// Single short circuit calculation, returning short circuit math output results
template <symmetry_tag sym> auto calculate_short_circuit(Options const& options) {
return MathOutput<std::vector<ShortCircuitSolverOutput<sym>>>{
.solver_output = calculate_short_circuit_<sym>(options.short_circuit_voltage_scaling)(
state_, options.calculation_method),
.optimizer_output = {}};
}

// Single short circuit calculation, propagating the results to result_data
void calculate_short_circuit(Options const& options, MutableDataset const& result_data, Idx pos = 0) {
assert(construction_complete_);
if (std::all_of(state_.components.template citer<Fault>().begin(),
state_.components.template citer<Fault>().end(),
[](Fault const& fault) { return fault.get_fault_type() == FaultType::three_phase; })) {
auto const solver_output = calculate_short_circuit<symmetric_t>(options);
output_result(solver_output, result_data, pos);
} else {
auto const solver_output = calculate_short_circuit<asymmetric_t>(options);
output_result(solver_output, result_data, pos);
}
}

// Batch load flow calculation, propagating the results to result_data
BatchParameter calculate_short_circuit(Options const& options, MutableDataset const& result_data,
ConstDataset const& update_data) {
return batch_calculation_(
[&options](MainModelImpl& model, MutableDataset const& target_data, Idx pos) {
if (pos != ignore_output) {
model.calculate_short_circuit(options, target_data, pos);
}
model.calculate(sub_opt, target_data, pos);
},
result_data, update_data, options.threading);
}
Expand Down
Loading

0 comments on commit 6b6cdf8

Please sign in to comment.