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/calculation type in options #681

Merged
merged 15 commits into from
Aug 5, 2024
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)...);
figueroa1395 marked this conversation as resolved.
Show resolved Hide resolved
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 {};
Jerry-Jinfeng-Guo marked this conversation as resolved.
Show resolved Hide resolved

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;
};

figueroa1395 marked this conversation as resolved.
Show resolved Hide resolved
// 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(
figueroa1395 marked this conversation as resolved.
Show resolved Hide resolved
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