From 8459a9e6f407c26c75ebbd2e42bc7a87c6e7d59f Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Wed, 25 Jun 2025 10:59:28 +0200 Subject: [PATCH 01/33] [skip ci] broken - just tinkering Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/batch_dispatch.hpp | 69 ++++++++++++++----- .../batch_dispatch_interface.hpp | 45 ++++++++++++ .../power_grid_model/main_model_impl.hpp | 14 ++++ 3 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp index 40459c1cb4..328117ccb8 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp @@ -21,6 +21,13 @@ template class BatchDispatch { static constexpr Idx ignore_output{-1}; static constexpr Idx sequential{-1}; + // here model is just used for model.calculate, in the interface, i should just create one overload of calculate_fn + // thing and then in the adaptor, make it such that we implement each, that should remove here at least the + // dependency on main model and keep only calculation_fn as entry point. with this, result data can probably be + // removed as well, mabe even update data too, and perhaps calculation_info but this one needs to be explored. + // ideally, only threading and some calculation_fn_proxy should stay alive and perhaps the calculation_info + // depending on how it is used. probably just focus on getting read of main model and putting all together in the + // calculation_fn_proxy template requires std::invocable, MainModel&, MutableDataset const&, Idx> static BatchParameter batch_calculation_(MainModel& model, CalculationInfo& calculation_info, @@ -29,12 +36,13 @@ template class BatchDispatch { // if the update dataset is empty without any component // execute one power flow in the current instance, no batch calculation is needed if (update_data.empty()) { - std::forward(calculation_fn)(model, result_data, 0); + std::forward(calculation_fn)(model, result_data, + 0); // calculation_fn_1: model, target data, pos return BatchParameter{}; - } + } // calculate function that takes the model as parameter // get batch size - Idx const n_scenarios = update_data.batch_size(); + Idx const n_scenarios = update_data.batch_size(); // this may need to be also proxied // if the batch_size is zero, it is a special case without doing any calculations at all // we consider in this case the batch set is independent but not topology cacheable @@ -43,15 +51,15 @@ template class BatchDispatch { } // calculate once to cache topology, ignore results, all math solvers are initialized - try { - calculation_fn(model, + try { // same as above, but this time topology is cached + calculation_fn(model, // calculation_fn_2 { false, 1, "sym_output", model.meta_data(), }, - ignore_output); + ignore_output); // think about this ignore output thingies } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR // missing entries are provided in the update data } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR @@ -67,14 +75,32 @@ template class BatchDispatch { auto sub_batch = sub_batch_calculation_(model, std::forward(calculation_fn), result_data, update_data, all_scenarios_sequence, exceptions, infos); - batch_dispatch(sub_batch, n_scenarios, threading); + batch_dispatch(sub_batch, n_scenarios, threading); // this is alreadyy decoupled - handle_batch_exceptions(exceptions); - calculation_info = main_core::merge_calculation_info(infos); + handle_batch_exceptions(exceptions); // this is already decoupled + calculation_info = + main_core::merge_calculation_info(infos); // this means that calc_info needs to be passed as well + // so it is not decoupled, but maybe on the proxy is fine. this should be okay, no need of main model here return BatchParameter{}; } + // this is the actual problem, sub batch calculation knows about main model a lot. + // main_model used for: + // get_components_to_update(update_data) + // state() + // base model constructor + // then the copyy from above constructor is used for calculation function and many others + // calculation function is used as usual + // result datais used for: + // to write to, this may be more difficult to decouple, but maybe it is fine to keep passing everywhere + // update data is used for: + // maybe it is good to keep passing as well here, + // all_scenarios_sequence: why do we even need this as argument? + // the problem here would be main model only, let's focus first on thisonly. + // an idea could be to pass a sub_batch structure thingy with functions that point to state, the constructor and + // get_componen ts_to_update, and then the calculation function can be passed as well (possibly), not sure about + // this but we need to deal with the calc function separately. template requires std::invocable, MainModel&, MutableDataset const&, Idx> static auto sub_batch_calculation_(MainModel const& base_model, Calculate&& calculation_fn, @@ -113,7 +139,8 @@ template class BatchDispatch { calculation_fn_(model, result_data, scenario_idx); infos[scenario_idx].merge(model.calculation_info()); }, - std::move(setup), std::move(winddown), scenario_exception_handler(model, exceptions, infos), + std::move(setup), std::move(winddown), + scenario_exception_handler(model.calculation_info(), exceptions, infos), // model.calculation_info(), [&model, ©_model_functor](Idx scenario_idx) { model = copy_model_functor(scenario_idx); }); for (Idx scenario_idx = start; scenario_idx < n_scenarios; scenario_idx += stride) { @@ -151,6 +178,8 @@ template class BatchDispatch { } } + // maybe this one is okayy as well, as it does use model stuff, but indirectly. well implemented. + // also affected by the mutable introduction... probably needs to be addressed. template requires std::invocable, Args const&...> && @@ -162,7 +191,7 @@ template class BatchDispatch { RecoverFromBadFn recover_from_bad) { return [setup_ = std::move(setup), run_ = std::move(run), winddown_ = std::move(winddown), handle_exception_ = std::move(handle_exception), - recover_from_bad_ = std::move(recover_from_bad)](Args const&... args) { + recover_from_bad_ = std::move(recover_from_bad)](Args const&... args) mutable { try { setup_(args...); run_(args...); @@ -178,6 +207,8 @@ template class BatchDispatch { }; } + // this will be hard. + // model: state(), update_components(), restore_components() static auto scenario_update_restore( MainModel& model, ConstDataset const& update_data, main_core::utils::ComponentFlags const& components_to_store, @@ -205,23 +236,27 @@ template class BatchDispatch { do_update_cache_ = std::move(do_update_cache), &infos](Idx scenario_idx) { Timer const t_update_model(infos[scenario_idx], 1200, "Update model"); current_scenario_sequence_cache = main_core::update::get_all_sequence_idx_map( - model.state(), update_data, scenario_idx, components_to_store, do_update_cache_, true); + model.state(), update_data, scenario_idx, components_to_store, do_update_cache_, + true); // model.state - model.template update_components(update_data, scenario_idx, scenario_sequence()); + model.template update_components(update_data, scenario_idx, + scenario_sequence()); // model.update_components }, [&model, scenario_sequence, ¤t_scenario_sequence_cache, &infos](Idx scenario_idx) { Timer const t_update_model(infos[scenario_idx], 1201, "Restore model"); - model.restore_components(scenario_sequence()); + model.restore_components(scenario_sequence()); // model.restore_components std::ranges::for_each(current_scenario_sequence_cache, [](auto& comp_seq_idx) { comp_seq_idx.clear(); }); }); } + // passing now info_single_scenario introduced the many mutables because of std::map::merge, so probably + // there is a better way to do this. But keeping it as first attempt for the proof of concept. // Lippincott pattern - static auto scenario_exception_handler(MainModel& model, std::vector& messages, + static auto scenario_exception_handler(CalculationInfo info_single_scenario, std::vector& messages, std::vector& infos) { - return [&model, &messages, &infos](Idx scenario_idx) { + return [info_single_scenario, &messages, &infos](Idx scenario_idx) mutable { std::exception_ptr const ex_ptr = std::current_exception(); try { std::rethrow_exception(ex_ptr); @@ -230,7 +265,7 @@ template class BatchDispatch { } catch (...) { messages[scenario_idx] = "unknown exception"; } - infos[scenario_idx].merge(model.calculation_info()); + infos[scenario_idx].merge(std::move(info_single_scenario)); }; } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp new file mode 100644 index 0000000000..27eea1432a --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include +#include +#include + +namespace power_grid_model { +template class BatchDispatchInterface { + public: + template // a concept for ResultDataset can be added if needed + requires std::invocable && + requires(Derived& adapter, Calculate&& calculation_fn, ResultDataset const& result_data) { + { + adapter.calculate_impl(std::forward(calculation_fn), result_data) + } -> std::same_as; // maybe it returns something different, just check the type on + // main_model_impl + } + BatchParameter calculate(Calculate&& calculation_fn, ResultDataset const& result_data) { + return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data); + } +}; + +class BatchDispatchAdapter : BatchDispatchInterface { + public: + BatchDispatchAdapter(MainModelImpl& model) : model_(model) {} + + private: + friend class BatchDispatchInterface; + MainModelImpl& model_; + template + requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> + BatchParameter + calculate_impl(Calculate&& calculation_fn, // change this Calculate to a differnt one cause is confusing from above + MutableDataset const& result_data) { + return std::forward(calculation_fn)(model_, result_data, 0); + } +}; + +// Then the BatchDispatch class takes an interface as a a function argument for when calling thebatch dispatch, but +// pass the adapter as the interface, then make each call directly inside BatchDispatch +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index da35883119..25672782c4 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -8,6 +8,7 @@ // main include #include "batch_dispatch.hpp" +#include "batch_dispatch_interface.hpp" #include "batch_parameter.hpp" #include "calculation_parameters.hpp" #include "container.hpp" @@ -1156,6 +1157,19 @@ class MainModelImpl, ComponentLis std::ranges::for_each(parameter_changed_components_, [](auto& comps) { comps.clear(); }); last_updated_calculation_symmetry_mode_ = is_symmetric_v; } + + private: + class BatchDispatchAdapter : BatchDispatchInterface { + public: + BatchDispatchAdapter(MainModelImpl& model) : model(model) {} + + private: + friend class BatchDispatchInterface; + + auto calculate_impl( + + MainModelImpl& model; + } }; } // namespace power_grid_model From 3f411018b83bf71c3fff89c49e03930b61c22b56 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 11 Jul 2025 15:38:25 +0200 Subject: [PATCH 02/33] working poc Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/batch_dispatch.hpp | 13 +++++--- .../batch_dispatch_interface.hpp | 32 +++---------------- .../power_grid_model/main_model_impl.hpp | 22 +++++++------ 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp index 328117ccb8..df1924e27e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp @@ -9,6 +9,8 @@ #include "main_core/calculation_info.hpp" #include "main_core/update.hpp" +#include "batch_dispatch_interface.hpp" + #include namespace power_grid_model { @@ -28,16 +30,17 @@ template class BatchDispatch { // ideally, only threading and some calculation_fn_proxy should stay alive and perhaps the calculation_info // depending on how it is used. probably just focus on getting read of main model and putting all together in the // calculation_fn_proxy - template - requires std::invocable, MainModel&, MutableDataset const&, Idx> + template static BatchParameter batch_calculation_(MainModel& model, CalculationInfo& calculation_info, Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, Idx threading = sequential) { + ConstDataset const& update_data, BatchDispatchInterfaceT& adapter, + Idx threading = sequential) { // if the update dataset is empty without any component // execute one power flow in the current instance, no batch calculation is needed if (update_data.empty()) { - std::forward(calculation_fn)(model, result_data, - 0); // calculation_fn_1: model, target data, pos + adapter.calculate_1(std::forward(calculation_fn), result_data); + // std::forward(calculation_fn)(model, result_data, + // 0); // calculation_fn_1: model, target data, pos return BatchParameter{}; } // calculate function that takes the model as parameter diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp index 27eea1432a..132023230e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp @@ -12,34 +12,12 @@ namespace power_grid_model { template class BatchDispatchInterface { public: template // a concept for ResultDataset can be added if needed - requires std::invocable && - requires(Derived& adapter, Calculate&& calculation_fn, ResultDataset const& result_data) { - { - adapter.calculate_impl(std::forward(calculation_fn), result_data) - } -> std::same_as; // maybe it returns something different, just check the type on - // main_model_impl - } - BatchParameter calculate(Calculate&& calculation_fn, ResultDataset const& result_data) { - return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data); + requires requires(Derived& adapter, Calculate&& calculation_fn, ResultDataset const& result_data) { + { adapter.calculate_1_impl(std::forward(calculation_fn), result_data) } -> std::same_as; + } + void calculate_1(Calculate&& calculation_fn, ResultDataset const& result_data) { + return static_cast(this)->calculate_1_impl(std::forward(calculation_fn), result_data); } }; -class BatchDispatchAdapter : BatchDispatchInterface { - public: - BatchDispatchAdapter(MainModelImpl& model) : model_(model) {} - - private: - friend class BatchDispatchInterface; - MainModelImpl& model_; - template - requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> - BatchParameter - calculate_impl(Calculate&& calculation_fn, // change this Calculate to a differnt one cause is confusing from above - MutableDataset const& result_data) { - return std::forward(calculation_fn)(model_, result_data, 0); - } -}; - -// Then the BatchDispatch class takes an interface as a a function argument for when calling thebatch dispatch, but -// pass the adapter as the interface, then make each call directly inside BatchDispatch } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index 25672782c4..a83365708b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -512,7 +512,7 @@ class MainModelImpl, ComponentLis BatchParameter batch_calculation_(Calculate&& calculation_fn, MutableDataset const& result_data, ConstDataset const& update_data, Idx threading = sequential) { return BatchDispatcher::batch_calculation_(*this, calculation_info_, std::forward(calculation_fn), - result_data, update_data, threading); + result_data, update_data, batch_dispatch_adapter, threading); } // Calculate with optimization, e.g., automatic tap changer @@ -1158,18 +1158,22 @@ class MainModelImpl, ComponentLis last_updated_calculation_symmetry_mode_ = is_symmetric_v; } - private: - class BatchDispatchAdapter : BatchDispatchInterface { + public: // this would be moved to its own file, so public for now + class BatchDispatchAdapter : public BatchDispatchInterface { public: - BatchDispatchAdapter(MainModelImpl& model) : model(model) {} + BatchDispatchAdapter(std::reference_wrapper model) : model_(std::move(model)) {} private: - friend class BatchDispatchInterface; - - auto calculate_impl( + friend class BatchDispatchInterface; + std::reference_wrapper model_; + template + requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> + void calculate_1_impl(Calculate&& calculation_fn, MutableDataset const& result_data) { + return std::forward(calculation_fn)(model_.get(), result_data, 0); + } + }; - MainModelImpl& model; - } + BatchDispatchAdapter batch_dispatch_adapter{*this}; }; } // namespace power_grid_model From 884e12233d38d9d284628182697aef66fdb24fd2 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 11 Jul 2025 16:53:50 +0200 Subject: [PATCH 03/33] cache works Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/batch_dispatch.hpp | 36 ++++++------------- .../batch_dispatch_interface.hpp | 19 +++++++--- .../power_grid_model/main_model_impl.hpp | 24 ++++++++++--- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp index df1924e27e..61ad456b5f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp @@ -23,29 +23,22 @@ template class BatchDispatch { static constexpr Idx ignore_output{-1}; static constexpr Idx sequential{-1}; - // here model is just used for model.calculate, in the interface, i should just create one overload of calculate_fn - // thing and then in the adaptor, make it such that we implement each, that should remove here at least the - // dependency on main model and keep only calculation_fn as entry point. with this, result data can probably be - // removed as well, mabe even update data too, and perhaps calculation_info but this one needs to be explored. - // ideally, only threading and some calculation_fn_proxy should stay alive and perhaps the calculation_info - // depending on how it is used. probably just focus on getting read of main model and putting all together in the - // calculation_fn_proxy - template + // goal: remove model, from signature and deal with them in the adapter + // posibly add a fake (using) tag to Adapter interface to add concept here + // at last, explore if calculation_fn can also be removed from here, if not, see if it is possible to + // add concepts to it some way without elluding to model. + template static BatchParameter batch_calculation_(MainModel& model, CalculationInfo& calculation_info, Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, BatchDispatchInterfaceT& adapter, + ConstDataset const& update_data, Adapter& adapter, Idx threading = sequential) { - // if the update dataset is empty without any component - // execute one power flow in the current instance, no batch calculation is needed if (update_data.empty()) { - adapter.calculate_1(std::forward(calculation_fn), result_data); - // std::forward(calculation_fn)(model, result_data, - // 0); // calculation_fn_1: model, target data, pos + adapter.calculate(std::forward(calculation_fn), result_data); return BatchParameter{}; - } // calculate function that takes the model as parameter + } // get batch size - Idx const n_scenarios = update_data.batch_size(); // this may need to be also proxied + Idx const n_scenarios = update_data.batch_size(); // if the batch_size is zero, it is a special case without doing any calculations at all // we consider in this case the batch set is independent but not topology cacheable @@ -54,15 +47,8 @@ template class BatchDispatch { } // calculate once to cache topology, ignore results, all math solvers are initialized - try { // same as above, but this time topology is cached - calculation_fn(model, // calculation_fn_2 - { - false, - 1, - "sym_output", - model.meta_data(), - }, - ignore_output); // think about this ignore output thingies + try { // same as above, but this time topology is cached + adapter.cache_calculate(std::forward(calculation_fn)); } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR // missing entries are provided in the update data } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp index 132023230e..407546b2c8 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp @@ -11,12 +11,21 @@ namespace power_grid_model { template class BatchDispatchInterface { public: - template // a concept for ResultDataset can be added if needed - requires requires(Derived& adapter, Calculate&& calculation_fn, ResultDataset const& result_data) { - { adapter.calculate_1_impl(std::forward(calculation_fn), result_data) } -> std::same_as; + // a concept for ResultDataset can be added if needed or MutableDataset can be used directly + template + requires requires(Derived& adapter, Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos) { + { adapter.calculate_impl(std::forward(calculation_fn), result_data, pos) } -> std::same_as; } - void calculate_1(Calculate&& calculation_fn, ResultDataset const& result_data) { - return static_cast(this)->calculate_1_impl(std::forward(calculation_fn), result_data); + void calculate(Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos = 0) { + return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data, pos); + } + + template + requires requires(Derived& adapter, Calculate&& calculation_fn) { + { adapter.cache_calculate_impl(std::forward(calculation_fn)) } -> std::same_as; + } + void cache_calculate(Calculate&& calculation_fn) { + return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); } }; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index a83365708b..5ad798f6b6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -882,7 +882,7 @@ class MainModelImpl, ComponentLis * The default lambda `include_all` always returns `true`. */ template (CalcStructOut::*comp_vect), class ComponentIn, + std::vector(CalcStructOut::* comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -901,7 +901,7 @@ class MainModelImpl, ComponentLis } template (CalcStructOut::*comp_vect), class ComponentIn, + std::vector(CalcStructOut::* comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -921,7 +921,7 @@ class MainModelImpl, ComponentLis } } - template ::*component), class Component> + template ::* component), class Component> static void prepare_input_status(MainModelState const& state, std::vector const& objects, std::vector>& input) { for (Idx i = 0, n = narrow_cast(objects.size()); i != n; ++i) { @@ -1166,10 +1166,24 @@ class MainModelImpl, ComponentLis private: friend class BatchDispatchInterface; std::reference_wrapper model_; + + template + requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> + void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx pos) { + return std::forward(calculation_fn)(model_.get(), result_data, pos); + } + template requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> - void calculate_1_impl(Calculate&& calculation_fn, MutableDataset const& result_data) { - return std::forward(calculation_fn)(model_.get(), result_data, 0); + void cache_calculate_impl(Calculate&& calculation_fn) { + return std::forward(calculation_fn)(model_.get(), + { + false, + 1, + "sym_output", + model_.get().meta_data(), + }, + ignore_output); } }; From 04fe5d2df62b80b6252b35dabf9ec5a4944845ab Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 14 Jul 2025 13:49:57 +0200 Subject: [PATCH 04/33] moved adapter to separate file Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/batch_dispatch.hpp | 50 +++++++-------- .../batch_dispatch_adapter.hpp | 63 +++++++++++++++++++ .../batch_dispatch_interface.hpp | 18 ++++-- .../power_grid_model/main_model_impl.hpp | 45 +++---------- 4 files changed, 106 insertions(+), 70 deletions(-) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp index 61ad456b5f..93e1090213 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp @@ -25,13 +25,13 @@ template class BatchDispatch { // goal: remove model, from signature and deal with them in the adapter // posibly add a fake (using) tag to Adapter interface to add concept here + // it might be a good idea just to keep concepts at the interface and adaptor level, for easier decoupling // at last, explore if calculation_fn can also be removed from here, if not, see if it is possible to - // add concepts to it some way without elluding to model. + // add concepts to it some way without elluding to main model. template - static BatchParameter batch_calculation_(MainModel& model, CalculationInfo& calculation_info, - Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, Adapter& adapter, - Idx threading = sequential) { + static BatchParameter batch_calculation_(MainModel& model, Calculate&& calculation_fn, + MutableDataset const& result_data, ConstDataset const& update_data, + Adapter& adapter, Idx threading = sequential) { if (update_data.empty()) { adapter.calculate(std::forward(calculation_fn), result_data); return BatchParameter{}; @@ -64,12 +64,10 @@ template class BatchDispatch { auto sub_batch = sub_batch_calculation_(model, std::forward(calculation_fn), result_data, update_data, all_scenarios_sequence, exceptions, infos); - batch_dispatch(sub_batch, n_scenarios, threading); // this is alreadyy decoupled + batch_dispatch(sub_batch, n_scenarios, threading); - handle_batch_exceptions(exceptions); // this is already decoupled - calculation_info = - main_core::merge_calculation_info(infos); // this means that calc_info needs to be passed as well - // so it is not decoupled, but maybe on the proxy is fine. this should be okay, no need of main model here + handle_batch_exceptions(exceptions); + adapter.set_calculation_info(main_core::merge_calculation_info(infos)); return BatchParameter{}; } @@ -80,16 +78,6 @@ template class BatchDispatch { // state() // base model constructor // then the copyy from above constructor is used for calculation function and many others - // calculation function is used as usual - // result datais used for: - // to write to, this may be more difficult to decouple, but maybe it is fine to keep passing everywhere - // update data is used for: - // maybe it is good to keep passing as well here, - // all_scenarios_sequence: why do we even need this as argument? - // the problem here would be main model only, let's focus first on thisonly. - // an idea could be to pass a sub_batch structure thingy with functions that point to state, the constructor and - // get_componen ts_to_update, and then the calculation function can be passed as well (possibly), not sure about - // this but we need to deal with the calc function separately. template requires std::invocable, MainModel&, MutableDataset const&, Idx> static auto sub_batch_calculation_(MainModel const& base_model, Calculate&& calculation_fn, @@ -98,11 +86,13 @@ template class BatchDispatch { std::vector& exceptions, std::vector& infos) { // cache component update order where possible. // the order for a cacheable (independent) component by definition is the same across all scenarios - auto const components_to_update = base_model.get_components_to_update(update_data); + auto const components_to_update = + base_model.get_components_to_update(update_data); // helper function inside scenario_update_restore auto const update_independence = main_core::update::independence::check_update_independence( - base_model.state(), update_data); + base_model.state(), update_data); // helper function inside scenario_update_restore all_scenarios_sequence = main_core::update::get_all_sequence_idx_map( - base_model.state(), update_data, 0, components_to_update, update_independence, false); + base_model.state(), update_data, 0, components_to_update, update_independence, + false); // helper function inside scenario_update_restore return [&base_model, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), &result_data, &update_data, &all_scenarios_sequence_ = std::as_const(all_scenarios_sequence), @@ -112,6 +102,7 @@ template class BatchDispatch { Timer const t_total(infos[start], 0000, "Total in thread"); + // possibly another another helper call from adapter auto const copy_model_functor = [&base_model, &infos](Idx scenario_idx) { Timer const t_copy_model_functor(infos[scenario_idx], 1100, "Copy model"); return MainModel{base_model}; @@ -119,14 +110,15 @@ template class BatchDispatch { auto model = copy_model_functor(start); auto current_scenario_sequence_cache = main_core::utils::SequenceIdx{}; - auto [setup, winddown] = - scenario_update_restore(model, update_data, components_to_update, update_independence, - all_scenarios_sequence_, current_scenario_sequence_cache, infos); + auto [setup, winddown] = scenario_update_restore( // this is the main problem + model, update_data, components_to_update, update_independence, all_scenarios_sequence_, // model + current_scenario_sequence_cache, infos); auto calculate_scenario = BatchDispatch::call_with( - [&model, &calculation_fn_, &result_data, &infos](Idx scenario_idx) { - calculation_fn_(model, result_data, scenario_idx); - infos[scenario_idx].merge(model.calculation_info()); + [&model, &calculation_fn_, &result_data, &infos](Idx scenario_idx) { // model + calculation_fn_(model, result_data, scenario_idx); // just use calculate function in adapter + infos[scenario_idx].merge(model.calculation_info()); // this can just be replaced with a function + // and forget about main model }, std::move(setup), std::move(winddown), scenario_exception_handler(model.calculation_info(), exceptions, infos), // model.calculation_info(), diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp new file mode 100644 index 0000000000..c440c7a7fe --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +// batch dispatch adapter class + +#include "batch_dispatch_interface.hpp" +#include "main_core/calculation_info.hpp" +#include "main_core/update.hpp" + +namespace power_grid_model { + +template class BatchDispatchAdapter : public BatchDispatchInterface> { + public: + BatchDispatchAdapter(std::reference_wrapper model) + : model_{std::move(model)} {} // , owns_model_copy_{false} {} + + // BatchDispatchAdapter(BatchDispatchAdapter const& other) + // : model_copy_{other.model_.get()}, model_{model_copy_}, owns_model_copy_{true} {} + + // BatchDispatchAdapter& operator=(BatchDispatchAdapter const& other) { + // if (this != &other) { + // model_copy_ = MainModel{other.model_.get()}; + // model_ = model_copy_; + // owns_model_copy_ = true; + // } + // return *this; + // } + + private: + static constexpr Idx ignore_output{-1}; + + friend class BatchDispatchInterface; + std::reference_wrapper model_; + // MainModel model_copy_; + // bool owns_model_copy_{false}; + + template + requires std::invocable, MainModel&, MutableDataset const&, Idx> + void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx pos) { + return std::forward(calculation_fn)(model_.get(), result_data, pos); + } + + template + requires std::invocable, MainModel&, MutableDataset const&, Idx> + void cache_calculate_impl(Calculate&& calculation_fn) { + return std::forward(calculation_fn)(model_.get(), + { + false, + 1, + "sym_output", + model_.get().meta_data(), + }, + ignore_output); + } + + CalculationInfo calculation_info_impl() const { return model_.get().calculation_info(); } + + void set_calculation_info_impl(CalculationInfo const& info) { model_.get().set_calculation_info(info); } +}; +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp index 407546b2c8..1e092ed820 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp @@ -4,28 +4,36 @@ #pragma once +// batch dispatch interface class + #include #include #include namespace power_grid_model { -template class BatchDispatchInterface { +template class BatchDispatchInterface { public: // a concept for ResultDataset can be added if needed or MutableDataset can be used directly template - requires requires(Derived& adapter, Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos) { + requires requires(Adapter& adapter, Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos) { { adapter.calculate_impl(std::forward(calculation_fn), result_data, pos) } -> std::same_as; } void calculate(Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos = 0) { - return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data, pos); + return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data, pos); } template - requires requires(Derived& adapter, Calculate&& calculation_fn) { + requires requires(Adapter& adapter, Calculate&& calculation_fn) { { adapter.cache_calculate_impl(std::forward(calculation_fn)) } -> std::same_as; } void cache_calculate(Calculate&& calculation_fn) { - return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); + return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); + } + + CalculationInfo get_calculation_info() const { return static_cast(this)->get_calculation_info_impl(); } + + void set_calculation_info(CalculationInfo const& info) { + static_cast(this)->set_calculation_info_impl(info); } }; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index 5ad798f6b6..0c6132d80f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -8,7 +8,7 @@ // main include #include "batch_dispatch.hpp" -#include "batch_dispatch_interface.hpp" +#include "batch_dispatch_adapter.hpp" #include "batch_parameter.hpp" #include "calculation_parameters.hpp" #include "container.hpp" @@ -511,8 +511,8 @@ class MainModelImpl, ComponentLis requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> BatchParameter batch_calculation_(Calculate&& calculation_fn, MutableDataset const& result_data, ConstDataset const& update_data, Idx threading = sequential) { - return BatchDispatcher::batch_calculation_(*this, calculation_info_, std::forward(calculation_fn), - result_data, update_data, batch_dispatch_adapter, threading); + return BatchDispatcher::batch_calculation_(*this, std::forward(calculation_fn), result_data, + update_data, batch_dispatch_adapter, threading); } // Calculate with optimization, e.g., automatic tap changer @@ -585,6 +585,7 @@ class MainModelImpl, ComponentLis } CalculationInfo calculation_info() const { return calculation_info_; } + void set_calculation_info(CalculationInfo const& info) { calculation_info_ = info; } auto const& state() const { assert(construction_complete_); return state_; @@ -882,7 +883,7 @@ class MainModelImpl, ComponentLis * The default lambda `include_all` always returns `true`. */ template (CalcStructOut::* comp_vect), class ComponentIn, + std::vector(CalcStructOut::*comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -901,7 +902,7 @@ class MainModelImpl, ComponentLis } template (CalcStructOut::* comp_vect), class ComponentIn, + std::vector(CalcStructOut::*comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -921,7 +922,7 @@ class MainModelImpl, ComponentLis } } - template ::* component), class Component> + template ::*component), class Component> static void prepare_input_status(MainModelState const& state, std::vector const& objects, std::vector>& input) { for (Idx i = 0, n = narrow_cast(objects.size()); i != n; ++i) { @@ -1158,36 +1159,8 @@ class MainModelImpl, ComponentLis last_updated_calculation_symmetry_mode_ = is_symmetric_v; } - public: // this would be moved to its own file, so public for now - class BatchDispatchAdapter : public BatchDispatchInterface { - public: - BatchDispatchAdapter(std::reference_wrapper model) : model_(std::move(model)) {} - - private: - friend class BatchDispatchInterface; - std::reference_wrapper model_; - - template - requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> - void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx pos) { - return std::forward(calculation_fn)(model_.get(), result_data, pos); - } - - template - requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> - void cache_calculate_impl(Calculate&& calculation_fn) { - return std::forward(calculation_fn)(model_.get(), - { - false, - 1, - "sym_output", - model_.get().meta_data(), - }, - ignore_output); - } - }; - - BatchDispatchAdapter batch_dispatch_adapter{*this}; + public: + BatchDispatchAdapter batch_dispatch_adapter{static_cast(*this)}; }; } // namespace power_grid_model From 7dbd3def2391ea8655271a1e2948756e58b20e66 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 14 Jul 2025 15:01:36 +0200 Subject: [PATCH 05/33] [skip ci] copy constructor introduces memory issue Signed-off-by: Santiago Figueroa Manrique --- .../batch_dispatch_adapter.hpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp index c440c7a7fe..c03edc0c48 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp @@ -14,28 +14,27 @@ namespace power_grid_model { template class BatchDispatchAdapter : public BatchDispatchInterface> { public: - BatchDispatchAdapter(std::reference_wrapper model) - : model_{std::move(model)} {} // , owns_model_copy_{false} {} - - // BatchDispatchAdapter(BatchDispatchAdapter const& other) - // : model_copy_{other.model_.get()}, model_{model_copy_}, owns_model_copy_{true} {} - - // BatchDispatchAdapter& operator=(BatchDispatchAdapter const& other) { - // if (this != &other) { - // model_copy_ = MainModel{other.model_.get()}; - // model_ = model_copy_; - // owns_model_copy_ = true; - // } - // return *this; - // } + BatchDispatchAdapter(std::reference_wrapper model) : model_{std::move(model)} {} //, owns_model_copy_{false} {} + + BatchDispatchAdapter(BatchDispatchAdapter const& other) + : model_copy_{new MainModel{other.model_.get()}}, model_{std::ref(*model_copy_)}, owns_model_copy_{true} {} + + BatchDispatchAdapter& operator=(BatchDispatchAdapter const& other) { + if (this != &other) { + model_copy_ = std::make_unique(other.model_.get()); + model_ = std::ref(*model_copy_); + owns_model_copy_ = true; + } + return *this; + } private: static constexpr Idx ignore_output{-1}; friend class BatchDispatchInterface; + std::unique_ptr model_copy_; std::reference_wrapper model_; - // MainModel model_copy_; - // bool owns_model_copy_{false}; + bool owns_model_copy_{false}; template requires std::invocable, MainModel&, MutableDataset const&, Idx> From a5f097c2c5d6459eb3c6aed0eaa3888469183bb2 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 14 Jul 2025 15:46:20 +0200 Subject: [PATCH 06/33] fix infinite recursion during copying Signed-off-by: Martijn Govers --- .../power_grid_model/main_model_impl.hpp | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index 0c6132d80f..d5eeed65ff 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -494,27 +494,6 @@ class MainModelImpl, ComponentLis }); }; } - - /* - run the calculation function in batch on the provided update data. - - The calculation function should be able to run standalone. - It should output to the provided result_data if the trailing argument is not ignore_output. - - threading - < 0 sequential - = 0 parallel, use number of hardware threads - > 0 specify number of parallel threads - raise a BatchCalculationError if any of the calculations in the batch raised an exception - */ - template - requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> - BatchParameter batch_calculation_(Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, Idx threading = sequential) { - return BatchDispatcher::batch_calculation_(*this, std::forward(calculation_fn), result_data, - update_data, batch_dispatch_adapter, threading); - } - // Calculate with optimization, e.g., automatic tap changer template auto calculate(Options const& options) { auto const calculator = [this, &options] { @@ -570,10 +549,25 @@ class MainModelImpl, ComponentLis } public: - // Batch calculation, propagating the results to result_data + /* + Batch calculation, propagating the results to result_data + + run the calculation function in batch on the provided update data. + + The calculation function should be able to run standalone. + It should output to the provided result_data if the trailing argument is not ignore_output. + + threading + < 0 sequential + = 0 parallel, use number of hardware threads + > 0 specify number of parallel threads + raise a BatchCalculationError if any of the calculations in the batch raised an exception + */ BatchParameter calculate(Options const& options, MutableDataset const& result_data, ConstDataset const& update_data) { - return batch_calculation_( + BatchDispatchAdapter adapter{std::ref(*this)}; + return BatchDispatcher::batch_calculation_( + *this, // TODO(mgovers): relace this with the adapter [&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::max(); @@ -581,7 +575,7 @@ class MainModelImpl, ComponentLis model.calculate(sub_opt, target_data, pos); }, - result_data, update_data, options.threading); + result_data, update_data, adapter, options.threading); } CalculationInfo calculation_info() const { return calculation_info_; } @@ -883,7 +877,7 @@ class MainModelImpl, ComponentLis * The default lambda `include_all` always returns `true`. */ template (CalcStructOut::*comp_vect), class ComponentIn, + std::vector(CalcStructOut::* comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -902,7 +896,7 @@ class MainModelImpl, ComponentLis } template (CalcStructOut::*comp_vect), class ComponentIn, + std::vector(CalcStructOut::* comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -922,7 +916,7 @@ class MainModelImpl, ComponentLis } } - template ::*component), class Component> + template ::* component), class Component> static void prepare_input_status(MainModelState const& state, std::vector const& objects, std::vector>& input) { for (Idx i = 0, n = narrow_cast(objects.size()); i != n; ++i) { @@ -1158,9 +1152,6 @@ class MainModelImpl, ComponentLis std::ranges::for_each(parameter_changed_components_, [](auto& comps) { comps.clear(); }); last_updated_calculation_symmetry_mode_ = is_symmetric_v; } - - public: - BatchDispatchAdapter batch_dispatch_adapter{static_cast(*this)}; }; } // namespace power_grid_model From c8cc1060795eda1cff8c468713c7e09ae5b22009 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 21 Jul 2025 17:34:58 +0200 Subject: [PATCH 07/33] wip - still broken, but getting there Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 139 ++++++------------ .../power_grid_model/job_dispatch_adapter.hpp | 119 +++++++++++++++ .../job_dispatch_interface.hpp | 51 +++++++ .../power_grid_model/main_model_impl.hpp | 55 ++++--- 4 files changed, 239 insertions(+), 125 deletions(-) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 70f7bf14bc..4f4043df94 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -4,7 +4,7 @@ #pragma once -#include "main_model_fwd.hpp" +#include "job_dispatch_interface.hpp" #include "main_core/calculation_info.hpp" #include "main_core/update.hpp" @@ -13,23 +13,20 @@ namespace power_grid_model { -template class JobDispatch { - private: - using SequenceIdxView = std::array, main_core::utils::n_types>; - +class JobDispatch { public: static constexpr Idx ignore_output{-1}; static constexpr Idx sequential{-1}; - template - requires std::invocable, MainModel&, MutableDataset const&, Idx> - static BatchParameter batch_calculation_(MainModel& model, CalculationInfo& calculation_info, - Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, Idx threading = sequential) { - // if the update dataset is empty without any component - // execute one power flow in the current instance, no batch calculation is needed + // TODO(figueroa1395): remove calculation_fn dependency + // TODO(figueroa1395): add concept to Adapter template parameter + // TODO(figueroa1395): add generic template parameters for update_data and result_data + template + static BatchParameter batch_calculation(Adapter& adapter, Calculate&& calculation_fn, + MutableDataset const& result_data, ConstDataset const& update_data, + Idx threading = sequential) { if (update_data.empty()) { - std::forward(calculation_fn)(model, result_data, 0); + adapter.calculate(std::forward(calculation_fn), result_data); return BatchParameter{}; } @@ -44,14 +41,7 @@ template class JobDispatch { // calculate once to cache topology, ignore results, all math solvers are initialized try { - calculation_fn(model, - { - false, - 1, - "sym_output", - model.meta_data(), - }, - ignore_output); + adapter.cache_calculate(std::forward(calculation_fn)); } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR // missing entries are provided in the update data } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR @@ -62,59 +52,53 @@ template class JobDispatch { std::vector exceptions(n_scenarios, ""); std::vector infos(n_scenarios); - // lambda for sub batch calculation - main_core::utils::SequenceIdx all_scenarios_sequence; - auto sub_batch = sub_batch_calculation_(model, std::forward(calculation_fn), result_data, - update_data, all_scenarios_sequence, exceptions, infos); + auto sub_batch = sub_batch_calculation_(adapter, std::forward(calculation_fn), result_data, + update_data, exceptions, infos); job_dispatch(sub_batch, n_scenarios, threading); handle_batch_exceptions(exceptions); - calculation_info = main_core::merge_calculation_info(infos); + adapter.merge_calculation_infos(infos); return BatchParameter{}; } - template - requires std::invocable, MainModel&, MutableDataset const&, Idx> - static auto sub_batch_calculation_(MainModel const& base_model, Calculate&& calculation_fn, + private: + template + static auto sub_batch_calculation_(Adapter& base_adapter, Calculate&& calculation_fn, MutableDataset const& result_data, ConstDataset const& update_data, - main_core::utils::SequenceIdx& all_scenarios_sequence, std::vector& exceptions, std::vector& infos) { - // cache component update order where possible. - // the order for a cacheable (independent) component by definition is the same across all scenarios - auto const components_to_update = base_model.get_components_to_update(update_data); - auto const update_independence = main_core::update::independence::check_update_independence( - base_model.state(), update_data); - all_scenarios_sequence = main_core::update::get_all_sequence_idx_map( - base_model.state(), update_data, 0, components_to_update, update_independence, false); - - return [&base_model, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), - &result_data, &update_data, &all_scenarios_sequence_ = std::as_const(all_scenarios_sequence), - components_to_update, update_independence](Idx start, Idx stride, Idx n_scenarios) { + base_adapter.prepare_sub_batch_calculation(update_data); + return [&base_adapter, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), + &result_data, &update_data](Idx start, Idx stride, Idx n_scenarios) { assert(n_scenarios <= narrow_cast(exceptions.size())); assert(n_scenarios <= narrow_cast(infos.size())); Timer const t_total(infos[start], 0000, "Total in thread"); - auto const copy_model_functor = [&base_model, &infos](Idx scenario_idx) { - Timer const t_copy_model_functor(infos[scenario_idx], 1100, "Copy model"); - return MainModel{base_model}; + auto const copy_adapter_functor = [&base_adapter, &infos](Idx scenario_idx) { + Timer const t_copy_adapter_functor(infos[scenario_idx], 1100, "Copy model"); + return Adapter{base_adapter}; }; - auto model = copy_model_functor(start); + auto adapter = copy_adapter_functor(start); - auto current_scenario_sequence_cache = main_core::utils::SequenceIdx{}; - auto [setup, winddown] = - scenario_update_restore(model, update_data, components_to_update, update_independence, - all_scenarios_sequence_, current_scenario_sequence_cache, infos); + auto setup = [&adapter, &update_data, &infos](Idx scenario_idx) { + Timer const t_update_model(infos[scenario_idx], 1200, "Update model"); + adapter.setup(update_data, scenario_idx); + }; + + auto winddown = [&adapter, &infos](Idx scenario_idx) { + Timer const t_update_model(infos[scenario_idx], 1201, "Restore model"); + adapter.winddown(); + }; auto calculate_scenario = JobDispatch::call_with( - [&model, &calculation_fn_, &result_data, &infos](Idx scenario_idx) { - calculation_fn_(model, result_data, scenario_idx); - infos[scenario_idx].merge(model.calculation_info()); + [&adapter, &calculation_fn_, &result_data, &infos](Idx scenario_idx) { + adapter.calculate(calculation_fn_, result_data, scenario_idx); + infos[scenario_idx].merge(adapter.get_calculation_info()); }, - std::move(setup), std::move(winddown), scenario_exception_handler(model, exceptions, infos), - [&model, ©_model_functor](Idx scenario_idx) { model = copy_model_functor(scenario_idx); }); + std::move(setup), std::move(winddown), scenario_exception_handler(adapter, exceptions, infos), + [&adapter, ©_adapter_functor](Idx scenario_idx) { adapter = copy_adapter_functor(scenario_idx); }); for (Idx scenario_idx = start; scenario_idx < n_scenarios; scenario_idx += stride) { Timer const t_total_single(infos[scenario_idx], 0100, "Total single calculation in thread"); @@ -178,50 +162,11 @@ template class JobDispatch { }; } - static auto scenario_update_restore( - MainModel& model, ConstDataset const& update_data, - main_core::utils::ComponentFlags const& components_to_store, - main_core::update::independence::UpdateIndependence const& do_update_cache, - main_core::utils::SequenceIdx const& all_scenario_sequence, - main_core::utils::SequenceIdx& current_scenario_sequence_cache, - std::vector& infos) noexcept { - main_core::utils::ComponentFlags independence_flags{}; - std::ranges::transform(do_update_cache, independence_flags.begin(), - [](auto const& comp) { return comp.is_independent(); }); - auto const scenario_sequence = [&all_scenario_sequence, ¤t_scenario_sequence_cache, - independence_flags_ = std::move(independence_flags)]() -> SequenceIdxView { - return main_core::utils::run_functor_with_all_types_return_array( - [&all_scenario_sequence, ¤t_scenario_sequence_cache, &independence_flags_]() { - constexpr auto comp_idx = main_core::utils::index_of_component; - if (std::get(independence_flags_)) { - return std::span{std::get(all_scenario_sequence)}; - } - return std::span{std::get(current_scenario_sequence_cache)}; - }); - }; - - return std::make_pair( - [&model, &update_data, scenario_sequence, ¤t_scenario_sequence_cache, &components_to_store, - do_update_cache_ = std::move(do_update_cache), &infos](Idx scenario_idx) { - Timer const t_update_model(infos[scenario_idx], 1200, "Update model"); - current_scenario_sequence_cache = main_core::update::get_all_sequence_idx_map( - model.state(), update_data, scenario_idx, components_to_store, do_update_cache_, true); - - model.template update_components(update_data, scenario_idx, scenario_sequence()); - }, - [&model, scenario_sequence, ¤t_scenario_sequence_cache, &infos](Idx scenario_idx) { - Timer const t_update_model(infos[scenario_idx], 1201, "Restore model"); - - model.restore_components(scenario_sequence()); - std::ranges::for_each(current_scenario_sequence_cache, - [](auto& comp_seq_idx) { comp_seq_idx.clear(); }); - }); - } - // Lippincott pattern - static auto scenario_exception_handler(MainModel& model, std::vector& messages, + template + static auto scenario_exception_handler(Adapter& adapter, std::vector& messages, std::vector& infos) { - return [&model, &messages, &infos](Idx scenario_idx) { + return [&adapter, &messages, &infos](Idx scenario_idx) { std::exception_ptr const ex_ptr = std::current_exception(); try { std::rethrow_exception(ex_ptr); @@ -230,7 +175,7 @@ template class JobDispatch { } catch (...) { messages[scenario_idx] = "unknown exception"; } - infos[scenario_idx].merge(model.calculation_info()); + infos[scenario_idx].merge(adapter.get_calculation_info()); }; } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp new file mode 100644 index 0000000000..688573024e --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +// batch dispatch adapter class + +#include "auxiliary/dataset.hpp" +#include "job_dispatch_interface.hpp" +#include "main_model_fwd.hpp" + +#include "main_core/calculation_info.hpp" +#include "main_core/update.hpp" + +namespace power_grid_model { + +template +class JobDispatchAdapter : public JobDispatchInterface> { + public: + JobDispatchAdapter(std::reference_wrapper model) : model_{std::move(model)} {} + + JobDispatchAdapter(JobDispatchAdapter const& other) + : model_copy_{std::make_unique(other.model_.get())}, model_{std::ref(*model_copy_)} {} + + JobDispatchAdapter& operator=(JobDispatchAdapter const& other) { + if (this != &other) { + model_copy_ = std::make_unique(other.model_.get()); + model_ = std::ref(*model_copy_); + } + return *this; + } + + private: + static constexpr Idx ignore_output{-1}; + + friend class JobDispatchInterface; + std::unique_ptr model_copy_; + std::reference_wrapper model_; + + main_core::utils::SequenceIdx current_scenario_sequence_cache_{}; + std::shared_ptr> components_to_update_; + std::shared_ptr> + update_independence_; + std::shared_ptr> all_scenarios_sequence_; + main_core::utils::ComponentFlags independence_flags_{}; + + // TODO(figueroa1395): Keep calculation_fn at the adapter level only + + template + requires std::invocable, MainModel&, MutableDataset const&, Idx> + void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx scenario_idx) const { + return std::forward(calculation_fn)(model_.get(), result_data, scenario_idx); + } + + template + requires std::invocable, MainModel&, MutableDataset const&, Idx> + void cache_calculate_impl(Calculate&& calculation_fn) const { + return std::forward(calculation_fn)(model_.get(), + { + false, + 1, + "sym_output", + model_.get().meta_data(), + }, + ignore_output); + } + + void prepare_sub_batch_calculation_impl(ConstDataset const& update_data) { + // cache component update order where possible. + // the order for a cacheable (independent) component by definition is the same across all scenarios + components_to_update_ = + std::make_shared>( + model_.get().get_components_to_update(update_data)); + update_independence_ = std::make_shared< + const power_grid_model::main_core::update::independence::UpdateIndependence>( + main_core::update::independence::check_update_independence(model_.get().state(), + update_data)); + assert(components_to_update_ != nullptr); + assert(update_independence_ != nullptr); + all_scenarios_sequence_ = std::make_shared>( + main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, 0, *components_to_update_, *update_independence_, false)); + + std::ranges::transform(*update_independence_, independence_flags_.begin(), + [](auto const& comp) { return comp.is_independent(); }); + } + + void setup_impl(ConstDataset const& update_data, Idx scenario_idx) { + assert(components_to_update_ != nullptr); + assert(update_independence_ != nullptr); + current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); + model_.get().template update_components(update_data, scenario_idx, + get_current_scenario_sequence_view_()); + } + + void winddown_impl() { + model_.get().restore_components(get_current_scenario_sequence_view_()); + std::ranges::for_each(current_scenario_sequence_cache_, [](auto& comp_seq_idx) { comp_seq_idx.clear(); }); + } + + CalculationInfo get_calculation_info_impl() const { return model_.get().calculation_info(); } + + void merge_calculation_infos_impl(std::vector const& infos) { + model_.get().set_calculation_info(main_core::merge_calculation_info(infos)); + } + + auto get_current_scenario_sequence_view_() const { + return main_core::utils::run_functor_with_all_types_return_array([this]() { + constexpr auto comp_idx = main_core::utils::index_of_component; + if (std::get(independence_flags_)) { + return std::span{std::get(*all_scenarios_sequence_)}; + } + return std::span{std::get(current_scenario_sequence_cache_)}; + }); + } +}; +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp new file mode 100644 index 0000000000..0c57426087 --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +// batch dispatch interface class + +#include +#include +#include + +namespace power_grid_model { +template class JobDispatchInterface { + public: + template + requires requires(Adapter& adapter, Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos) { + { adapter.calculate_impl(std::forward(calculation_fn), result_data, pos) } -> std::same_as; + } + void calculate(Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos = 0) { + return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data, pos); + } + + template + requires requires(Adapter& adapter, Calculate&& calculation_fn) { + { adapter.cache_calculate_impl(std::forward(calculation_fn)) } -> std::same_as; + } + void cache_calculate(Calculate&& calculation_fn) { + return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); + } + + template void prepare_sub_batch_calculation(UpdateDataset const& update_data) { + return static_cast(this)->prepare_sub_batch_calculation_impl(update_data); + } + + template void setup(UpdateDataset const& update_data, Idx scenario_idx) { + return static_cast(this)->setup_impl(update_data, scenario_idx); + } + + void winddown() { return static_cast(this)->winddown_impl(); } + + CalculationInfo get_calculation_info() const { + return static_cast(this)->get_calculation_info_impl(); + } + + void merge_calculation_infos(std::vector const& info) { + static_cast(this)->merge_calculation_infos_impl(info); + } +}; + +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index a3e481adca..9340916aa7 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -11,6 +11,7 @@ #include "calculation_parameters.hpp" #include "container.hpp" #include "job_dispatch.hpp" +#include "job_dispatch_adapter.hpp" #include "main_model_fwd.hpp" #include "topology.hpp" @@ -151,14 +152,10 @@ class MainModelImpl, ComponentLis using SequenceIdxView = std::array, main_core::utils::n_types>; using OwnedUpdateDataset = std::tuple...>; - using JobDispatcher = - JobDispatch, ComponentList>, - ComponentType...>; - - static constexpr Idx ignore_output{JobDispatcher::ignore_output}; + static constexpr Idx ignore_output{JobDispatch::ignore_output}; static constexpr Idx isolated_component{-1}; static constexpr Idx not_connected{-1}; - static constexpr Idx sequential{JobDispatcher::sequential}; + static constexpr Idx sequential{JobDispatch::sequential}; public: using Options = MainModelOptions; @@ -459,26 +456,6 @@ class MainModelImpl, ComponentLis }; } - /* - run the calculation function in batch on the provided update data. - - The calculation function should be able to run standalone. - It should output to the provided result_data if the trailing argument is not ignore_output. - - threading - < 0 sequential - = 0 parallel, use number of hardware threads - > 0 specify number of parallel threads - raise a BatchCalculationError if any of the calculations in the batch raised an exception - */ - template - requires std::invocable, MainModelImpl&, MutableDataset const&, Idx> - BatchParameter batch_calculation_(Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, Idx threading = sequential) { - return JobDispatcher::batch_calculation_(*this, calculation_info_, std::forward(calculation_fn), - result_data, update_data, threading); - } - // Calculate with optimization, e.g., automatic tap changer template auto calculate(Options const& options) { auto const calculator = [this, &options] { @@ -534,10 +511,28 @@ class MainModelImpl, ComponentLis } public: - // Batch calculation, propagating the results to result_data + /* + Batch calculation, propagating the results to result_data + + Run the calculation function in batch on the provided update data. + + The calculation function should be able to run standalone. + It should output to the provided result_data if the trailing argument is not ignore_output. + + threading + < 0 sequential + = 0 parallel, use number of hardware threads + > 0 specify number of parallel threads + raise a BatchCalculationError if any of the calculations in the batch raised an exception + */ BatchParameter calculate(Options const& options, MutableDataset const& result_data, ConstDataset const& update_data) { - return batch_calculation_( + JobDispatchAdapter< + MainModelImpl, ComponentList>, + ComponentType...> + adapter{std::ref(*this)}; + return JobDispatch::batch_calculation( + adapter, [&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::max(); @@ -549,6 +544,10 @@ class MainModelImpl, ComponentLis } CalculationInfo calculation_info() const { return calculation_info_; } + void set_calculation_info(CalculationInfo const& info) { + assert(construction_complete_); + calculation_info_ = info; + } auto const& state() const { assert(construction_complete_); return state_; From ce332ac6f839350ff2fe72196689c2b6bd61f43f Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 21 Jul 2025 17:39:12 +0200 Subject: [PATCH 08/33] [skip ci] line with apparent issue Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch_adapter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 688573024e..761d30c61d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -89,7 +89,7 @@ class JobDispatchAdapter : public JobDispatchInterface( + current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( // something wrong here model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); model_.get().template update_components(update_data, scenario_idx, get_current_scenario_sequence_view_()); From 30277c3966da333e2770b4fbe9dcc49d634072f4 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 21 Jul 2025 17:34:58 +0200 Subject: [PATCH 09/33] wip - still broken, but getting there Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/batch_dispatch.hpp | 272 ------------------ .../include/power_grid_model/job_dispatch.hpp | 207 +++++++++++++ .../power_grid_model/job_dispatch_adapter.hpp | 119 ++++++++ .../job_dispatch_interface.hpp | 51 ++++ .../power_grid_model/main_model_impl.hpp | 35 +-- 5 files changed, 396 insertions(+), 288 deletions(-) delete mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp deleted file mode 100644 index 93e1090213..0000000000 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch.hpp +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-FileCopyrightText: Contributors to the Power Grid Model project -// -// SPDX-License-Identifier: MPL-2.0 - -#pragma once - -#include "main_model_fwd.hpp" - -#include "main_core/calculation_info.hpp" -#include "main_core/update.hpp" - -#include "batch_dispatch_interface.hpp" - -#include - -namespace power_grid_model { - -template class BatchDispatch { - private: - using SequenceIdxView = std::array, main_core::utils::n_types>; - - public: - static constexpr Idx ignore_output{-1}; - static constexpr Idx sequential{-1}; - - // goal: remove model, from signature and deal with them in the adapter - // posibly add a fake (using) tag to Adapter interface to add concept here - // it might be a good idea just to keep concepts at the interface and adaptor level, for easier decoupling - // at last, explore if calculation_fn can also be removed from here, if not, see if it is possible to - // add concepts to it some way without elluding to main model. - template - static BatchParameter batch_calculation_(MainModel& model, Calculate&& calculation_fn, - MutableDataset const& result_data, ConstDataset const& update_data, - Adapter& adapter, Idx threading = sequential) { - if (update_data.empty()) { - adapter.calculate(std::forward(calculation_fn), result_data); - return BatchParameter{}; - } - - // get batch size - Idx const n_scenarios = update_data.batch_size(); - - // if the batch_size is zero, it is a special case without doing any calculations at all - // we consider in this case the batch set is independent but not topology cacheable - if (n_scenarios == 0) { - return BatchParameter{}; - } - - // calculate once to cache topology, ignore results, all math solvers are initialized - try { // same as above, but this time topology is cached - adapter.cache_calculate(std::forward(calculation_fn)); - } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR - // missing entries are provided in the update data - } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR - // missing entries are provided in the update data - } - - // error messages - std::vector exceptions(n_scenarios, ""); - std::vector infos(n_scenarios); - - // lambda for sub batch calculation - main_core::utils::SequenceIdx all_scenarios_sequence; - auto sub_batch = sub_batch_calculation_(model, std::forward(calculation_fn), result_data, - update_data, all_scenarios_sequence, exceptions, infos); - - batch_dispatch(sub_batch, n_scenarios, threading); - - handle_batch_exceptions(exceptions); - adapter.set_calculation_info(main_core::merge_calculation_info(infos)); - - return BatchParameter{}; - } - - // this is the actual problem, sub batch calculation knows about main model a lot. - // main_model used for: - // get_components_to_update(update_data) - // state() - // base model constructor - // then the copyy from above constructor is used for calculation function and many others - template - requires std::invocable, MainModel&, MutableDataset const&, Idx> - static auto sub_batch_calculation_(MainModel const& base_model, Calculate&& calculation_fn, - MutableDataset const& result_data, ConstDataset const& update_data, - main_core::utils::SequenceIdx& all_scenarios_sequence, - std::vector& exceptions, std::vector& infos) { - // cache component update order where possible. - // the order for a cacheable (independent) component by definition is the same across all scenarios - auto const components_to_update = - base_model.get_components_to_update(update_data); // helper function inside scenario_update_restore - auto const update_independence = main_core::update::independence::check_update_independence( - base_model.state(), update_data); // helper function inside scenario_update_restore - all_scenarios_sequence = main_core::update::get_all_sequence_idx_map( - base_model.state(), update_data, 0, components_to_update, update_independence, - false); // helper function inside scenario_update_restore - - return [&base_model, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), - &result_data, &update_data, &all_scenarios_sequence_ = std::as_const(all_scenarios_sequence), - components_to_update, update_independence](Idx start, Idx stride, Idx n_scenarios) { - assert(n_scenarios <= narrow_cast(exceptions.size())); - assert(n_scenarios <= narrow_cast(infos.size())); - - Timer const t_total(infos[start], 0000, "Total in thread"); - - // possibly another another helper call from adapter - auto const copy_model_functor = [&base_model, &infos](Idx scenario_idx) { - Timer const t_copy_model_functor(infos[scenario_idx], 1100, "Copy model"); - return MainModel{base_model}; - }; - auto model = copy_model_functor(start); - - auto current_scenario_sequence_cache = main_core::utils::SequenceIdx{}; - auto [setup, winddown] = scenario_update_restore( // this is the main problem - model, update_data, components_to_update, update_independence, all_scenarios_sequence_, // model - current_scenario_sequence_cache, infos); - - auto calculate_scenario = BatchDispatch::call_with( - [&model, &calculation_fn_, &result_data, &infos](Idx scenario_idx) { // model - calculation_fn_(model, result_data, scenario_idx); // just use calculate function in adapter - infos[scenario_idx].merge(model.calculation_info()); // this can just be replaced with a function - // and forget about main model - }, - std::move(setup), std::move(winddown), - scenario_exception_handler(model.calculation_info(), exceptions, infos), // model.calculation_info(), - [&model, ©_model_functor](Idx scenario_idx) { model = copy_model_functor(scenario_idx); }); - - for (Idx scenario_idx = start; scenario_idx < n_scenarios; scenario_idx += stride) { - Timer const t_total_single(infos[scenario_idx], 0100, "Total single calculation in thread"); - - calculate_scenario(scenario_idx); - } - }; - } - - // run sequential if - // specified threading < 0 - // use hardware threads, but it is either unknown (0) or only has one thread (1) - // specified threading = 1 - template - requires std::invocable, Idx /*start*/, Idx /*stride*/, Idx /*n_scenarios*/> - static void batch_dispatch(RunSubBatchFn sub_batch, Idx n_scenarios, Idx threading) { - // run batches sequential or parallel - auto const hardware_thread = static_cast(std::thread::hardware_concurrency()); - if (threading < 0 || threading == 1 || (threading == 0 && hardware_thread < 2)) { - // run all in sequential - sub_batch(0, 1, n_scenarios); - } else { - // create parallel threads - Idx const n_thread = std::min(threading == 0 ? hardware_thread : threading, n_scenarios); - std::vector threads; - threads.reserve(n_thread); - for (Idx thread_number = 0; thread_number < n_thread; ++thread_number) { - // compute each sub batch with stride - threads.emplace_back(sub_batch, thread_number, n_thread, n_scenarios); - } - for (auto& thread : threads) { - thread.join(); - } - } - } - - // maybe this one is okayy as well, as it does use model stuff, but indirectly. well implemented. - // also affected by the mutable introduction... probably needs to be addressed. - template - requires std::invocable, Args const&...> && - std::invocable, Args const&...> && - std::invocable, Args const&...> && - std::invocable, Args const&...> && - std::invocable, Args const&...> - static auto call_with(RunFn run, SetupFn setup, WinddownFn winddown, HandleExceptionFn handle_exception, - RecoverFromBadFn recover_from_bad) { - return [setup_ = std::move(setup), run_ = std::move(run), winddown_ = std::move(winddown), - handle_exception_ = std::move(handle_exception), - recover_from_bad_ = std::move(recover_from_bad)](Args const&... args) mutable { - try { - setup_(args...); - run_(args...); - winddown_(args...); - } catch (...) { - handle_exception_(args...); - try { - winddown_(args...); - } catch (...) { - recover_from_bad_(args...); - } - } - }; - } - - // this will be hard. - // model: state(), update_components(), restore_components() - static auto scenario_update_restore( - MainModel& model, ConstDataset const& update_data, - main_core::utils::ComponentFlags const& components_to_store, - main_core::update::independence::UpdateIndependence const& do_update_cache, - main_core::utils::SequenceIdx const& all_scenario_sequence, - main_core::utils::SequenceIdx& current_scenario_sequence_cache, - std::vector& infos) noexcept { - main_core::utils::ComponentFlags independence_flags{}; - std::ranges::transform(do_update_cache, independence_flags.begin(), - [](auto const& comp) { return comp.is_independent(); }); - auto const scenario_sequence = [&all_scenario_sequence, ¤t_scenario_sequence_cache, - independence_flags_ = std::move(independence_flags)]() -> SequenceIdxView { - return main_core::utils::run_functor_with_all_types_return_array( - [&all_scenario_sequence, ¤t_scenario_sequence_cache, &independence_flags_]() { - constexpr auto comp_idx = main_core::utils::index_of_component; - if (std::get(independence_flags_)) { - return std::span{std::get(all_scenario_sequence)}; - } - return std::span{std::get(current_scenario_sequence_cache)}; - }); - }; - - return std::make_pair( - [&model, &update_data, scenario_sequence, ¤t_scenario_sequence_cache, &components_to_store, - do_update_cache_ = std::move(do_update_cache), &infos](Idx scenario_idx) { - Timer const t_update_model(infos[scenario_idx], 1200, "Update model"); - current_scenario_sequence_cache = main_core::update::get_all_sequence_idx_map( - model.state(), update_data, scenario_idx, components_to_store, do_update_cache_, - true); // model.state - - model.template update_components(update_data, scenario_idx, - scenario_sequence()); // model.update_components - }, - [&model, scenario_sequence, ¤t_scenario_sequence_cache, &infos](Idx scenario_idx) { - Timer const t_update_model(infos[scenario_idx], 1201, "Restore model"); - - model.restore_components(scenario_sequence()); // model.restore_components - std::ranges::for_each(current_scenario_sequence_cache, - [](auto& comp_seq_idx) { comp_seq_idx.clear(); }); - }); - } - - // passing now info_single_scenario introduced the many mutables because of std::map::merge, so probably - // there is a better way to do this. But keeping it as first attempt for the proof of concept. - // Lippincott pattern - static auto scenario_exception_handler(CalculationInfo info_single_scenario, std::vector& messages, - std::vector& infos) { - return [info_single_scenario, &messages, &infos](Idx scenario_idx) mutable { - std::exception_ptr const ex_ptr = std::current_exception(); - try { - std::rethrow_exception(ex_ptr); - } catch (std::exception const& ex) { - messages[scenario_idx] = ex.what(); - } catch (...) { - messages[scenario_idx] = "unknown exception"; - } - infos[scenario_idx].merge(std::move(info_single_scenario)); - }; - } - - static void handle_batch_exceptions(std::vector const& exceptions) { - std::string combined_error_message; - IdxVector failed_scenarios; - std::vector err_msgs; - for (Idx batch = 0; batch < static_cast(exceptions.size()); ++batch) { - // append exception if it is not empty - if (!exceptions[batch].empty()) { - combined_error_message = - std::format("{}Error in batch #{}: {}\n", combined_error_message, batch, exceptions[batch]); - failed_scenarios.push_back(batch); - err_msgs.push_back(exceptions[batch]); - } - } - if (!combined_error_message.empty()) { - throw BatchCalculationError(combined_error_message, failed_scenarios, err_msgs); - } - } -}; - -} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp new file mode 100644 index 0000000000..d030413a99 --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -0,0 +1,207 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "job_dispatch_interface.hpp" + +#include "main_core/calculation_info.hpp" +#include "main_core/update.hpp" + +#include "batch_dispatch_interface.hpp" + +#include + +namespace power_grid_model { + +class JobDispatch { + public: + static constexpr Idx ignore_output{-1}; + static constexpr Idx sequential{-1}; + + // TODO(figueroa1395): remove calculation_fn dependency + // TODO(figueroa1395): add concept to Adapter template parameter + // TODO(figueroa1395): add generic template parameters for update_data and result_data + template + static BatchParameter batch_calculation(Adapter& adapter, Calculate&& calculation_fn, + MutableDataset const& result_data, ConstDataset const& update_data, + Idx threading = sequential) { + if (update_data.empty()) { + adapter.calculate(std::forward(calculation_fn), result_data); + return BatchParameter{}; + } + + // get batch size + Idx const n_scenarios = update_data.batch_size(); + + // if the batch_size is zero, it is a special case without doing any calculations at all + // we consider in this case the batch set is independent but not topology cacheable + if (n_scenarios == 0) { + return BatchParameter{}; + } + + // calculate once to cache topology, ignore results, all math solvers are initialized + try { + adapter.cache_calculate(std::forward(calculation_fn)); + } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR + // missing entries are provided in the update data + } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR + // missing entries are provided in the update data + } + + // error messages + std::vector exceptions(n_scenarios, ""); + std::vector infos(n_scenarios); + + auto sub_batch = sub_batch_calculation_(adapter, std::forward(calculation_fn), result_data, + update_data, exceptions, infos); + + batch_dispatch(sub_batch, n_scenarios, threading); + + handle_batch_exceptions(exceptions); + adapter.merge_calculation_infos(infos); + + return BatchParameter{}; + } + + private: + template + static auto sub_batch_calculation_(Adapter& base_adapter, Calculate&& calculation_fn, + MutableDataset const& result_data, ConstDataset const& update_data, + std::vector& exceptions, std::vector& infos) { + base_adapter.prepare_sub_batch_calculation(update_data); + return [&base_adapter, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), + &result_data, &update_data](Idx start, Idx stride, Idx n_scenarios) { + assert(n_scenarios <= narrow_cast(exceptions.size())); + assert(n_scenarios <= narrow_cast(infos.size())); + + Timer const t_total(infos[start], 0000, "Total in thread"); + + auto const copy_adapter_functor = [&base_adapter, &infos](Idx scenario_idx) { + Timer const t_copy_adapter_functor(infos[scenario_idx], 1100, "Copy model"); + return Adapter{base_adapter}; + }; + auto adapter = copy_adapter_functor(start); + + auto setup = [&adapter, &update_data, &infos](Idx scenario_idx) { + Timer const t_update_model(infos[scenario_idx], 1200, "Update model"); + adapter.setup(update_data, scenario_idx); + }; + + auto winddown = [&adapter, &infos](Idx scenario_idx) { + Timer const t_update_model(infos[scenario_idx], 1201, "Restore model"); + adapter.winddown(); + }; + + auto calculate_scenario = JobDispatch::call_with( + [&adapter, &calculation_fn_, &result_data, &infos](Idx scenario_idx) { + adapter.calculate(calculation_fn_, result_data, scenario_idx); + infos[scenario_idx].merge(adapter.get_calculation_info()); + }, + std::move(setup), std::move(winddown), scenario_exception_handler(adapter, exceptions, infos), + [&adapter, ©_adapter_functor](Idx scenario_idx) { adapter = copy_adapter_functor(scenario_idx); }); + + for (Idx scenario_idx = start; scenario_idx < n_scenarios; scenario_idx += stride) { + Timer const t_total_single(infos[scenario_idx], 0100, "Total single calculation in thread"); + + calculate_scenario(scenario_idx); + } + }; + } + + // run sequential if + // specified threading < 0 + // use hardware threads, but it is either unknown (0) or only has one thread (1) + // specified threading = 1 + template + requires std::invocable, Idx /*start*/, Idx /*stride*/, Idx /*n_scenarios*/> + static void batch_dispatch(RunSubBatchFn sub_batch, Idx n_scenarios, Idx threading) { + // run batches sequential or parallel + auto const hardware_thread = static_cast(std::thread::hardware_concurrency()); + if (threading < 0 || threading == 1 || (threading == 0 && hardware_thread < 2)) { + // run all in sequential + sub_batch(0, 1, n_scenarios); + } else { + // create parallel threads + Idx const n_thread = std::min(threading == 0 ? hardware_thread : threading, n_scenarios); + std::vector threads; + threads.reserve(n_thread); + for (Idx thread_number = 0; thread_number < n_thread; ++thread_number) { + // compute each sub batch with stride + threads.emplace_back(sub_batch, thread_number, n_thread, n_scenarios); + } + for (auto& thread : threads) { + thread.join(); + } + } + } + + // maybe this one is okayy as well, as it does use model stuff, but indirectly. well implemented. + // also affected by the mutable introduction... probably needs to be addressed. + template + requires std::invocable, Args const&...> && + std::invocable, Args const&...> && + std::invocable, Args const&...> && + std::invocable, Args const&...> && + std::invocable, Args const&...> + static auto call_with(RunFn run, SetupFn setup, WinddownFn winddown, HandleExceptionFn handle_exception, + RecoverFromBadFn recover_from_bad) { + return [setup_ = std::move(setup), run_ = std::move(run), winddown_ = std::move(winddown), + handle_exception_ = std::move(handle_exception), + recover_from_bad_ = std::move(recover_from_bad)](Args const&... args) mutable { + try { + setup_(args...); + run_(args...); + winddown_(args...); + } catch (...) { + handle_exception_(args...); + try { + winddown_(args...); + } catch (...) { + recover_from_bad_(args...); + } + } + }; + } + + // passing now info_single_scenario introduced the many mutables because of std::map::merge, so probably + // there is a better way to do this. But keeping it as first attempt for the proof of concept. + // Lippincott pattern + template + static auto scenario_exception_handler(Adapter& adapter, std::vector& messages, + std::vector& infos) { + return [&adapter, &messages, &infos](Idx scenario_idx) { + std::exception_ptr const ex_ptr = std::current_exception(); + try { + std::rethrow_exception(ex_ptr); + } catch (std::exception const& ex) { + messages[scenario_idx] = ex.what(); + } catch (...) { + messages[scenario_idx] = "unknown exception"; + } + infos[scenario_idx].merge(adapter.get_calculation_info()); + }; + } + + static void handle_batch_exceptions(std::vector const& exceptions) { + std::string combined_error_message; + IdxVector failed_scenarios; + std::vector err_msgs; + for (Idx batch = 0; batch < static_cast(exceptions.size()); ++batch) { + // append exception if it is not empty + if (!exceptions[batch].empty()) { + combined_error_message = + std::format("{}Error in batch #{}: {}\n", combined_error_message, batch, exceptions[batch]); + failed_scenarios.push_back(batch); + err_msgs.push_back(exceptions[batch]); + } + } + if (!combined_error_message.empty()) { + throw BatchCalculationError(combined_error_message, failed_scenarios, err_msgs); + } + } +}; + +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp new file mode 100644 index 0000000000..688573024e --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +// batch dispatch adapter class + +#include "auxiliary/dataset.hpp" +#include "job_dispatch_interface.hpp" +#include "main_model_fwd.hpp" + +#include "main_core/calculation_info.hpp" +#include "main_core/update.hpp" + +namespace power_grid_model { + +template +class JobDispatchAdapter : public JobDispatchInterface> { + public: + JobDispatchAdapter(std::reference_wrapper model) : model_{std::move(model)} {} + + JobDispatchAdapter(JobDispatchAdapter const& other) + : model_copy_{std::make_unique(other.model_.get())}, model_{std::ref(*model_copy_)} {} + + JobDispatchAdapter& operator=(JobDispatchAdapter const& other) { + if (this != &other) { + model_copy_ = std::make_unique(other.model_.get()); + model_ = std::ref(*model_copy_); + } + return *this; + } + + private: + static constexpr Idx ignore_output{-1}; + + friend class JobDispatchInterface; + std::unique_ptr model_copy_; + std::reference_wrapper model_; + + main_core::utils::SequenceIdx current_scenario_sequence_cache_{}; + std::shared_ptr> components_to_update_; + std::shared_ptr> + update_independence_; + std::shared_ptr> all_scenarios_sequence_; + main_core::utils::ComponentFlags independence_flags_{}; + + // TODO(figueroa1395): Keep calculation_fn at the adapter level only + + template + requires std::invocable, MainModel&, MutableDataset const&, Idx> + void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx scenario_idx) const { + return std::forward(calculation_fn)(model_.get(), result_data, scenario_idx); + } + + template + requires std::invocable, MainModel&, MutableDataset const&, Idx> + void cache_calculate_impl(Calculate&& calculation_fn) const { + return std::forward(calculation_fn)(model_.get(), + { + false, + 1, + "sym_output", + model_.get().meta_data(), + }, + ignore_output); + } + + void prepare_sub_batch_calculation_impl(ConstDataset const& update_data) { + // cache component update order where possible. + // the order for a cacheable (independent) component by definition is the same across all scenarios + components_to_update_ = + std::make_shared>( + model_.get().get_components_to_update(update_data)); + update_independence_ = std::make_shared< + const power_grid_model::main_core::update::independence::UpdateIndependence>( + main_core::update::independence::check_update_independence(model_.get().state(), + update_data)); + assert(components_to_update_ != nullptr); + assert(update_independence_ != nullptr); + all_scenarios_sequence_ = std::make_shared>( + main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, 0, *components_to_update_, *update_independence_, false)); + + std::ranges::transform(*update_independence_, independence_flags_.begin(), + [](auto const& comp) { return comp.is_independent(); }); + } + + void setup_impl(ConstDataset const& update_data, Idx scenario_idx) { + assert(components_to_update_ != nullptr); + assert(update_independence_ != nullptr); + current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); + model_.get().template update_components(update_data, scenario_idx, + get_current_scenario_sequence_view_()); + } + + void winddown_impl() { + model_.get().restore_components(get_current_scenario_sequence_view_()); + std::ranges::for_each(current_scenario_sequence_cache_, [](auto& comp_seq_idx) { comp_seq_idx.clear(); }); + } + + CalculationInfo get_calculation_info_impl() const { return model_.get().calculation_info(); } + + void merge_calculation_infos_impl(std::vector const& infos) { + model_.get().set_calculation_info(main_core::merge_calculation_info(infos)); + } + + auto get_current_scenario_sequence_view_() const { + return main_core::utils::run_functor_with_all_types_return_array([this]() { + constexpr auto comp_idx = main_core::utils::index_of_component; + if (std::get(independence_flags_)) { + return std::span{std::get(*all_scenarios_sequence_)}; + } + return std::span{std::get(current_scenario_sequence_cache_)}; + }); + } +}; +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp new file mode 100644 index 0000000000..0c57426087 --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +// batch dispatch interface class + +#include +#include +#include + +namespace power_grid_model { +template class JobDispatchInterface { + public: + template + requires requires(Adapter& adapter, Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos) { + { adapter.calculate_impl(std::forward(calculation_fn), result_data, pos) } -> std::same_as; + } + void calculate(Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos = 0) { + return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data, pos); + } + + template + requires requires(Adapter& adapter, Calculate&& calculation_fn) { + { adapter.cache_calculate_impl(std::forward(calculation_fn)) } -> std::same_as; + } + void cache_calculate(Calculate&& calculation_fn) { + return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); + } + + template void prepare_sub_batch_calculation(UpdateDataset const& update_data) { + return static_cast(this)->prepare_sub_batch_calculation_impl(update_data); + } + + template void setup(UpdateDataset const& update_data, Idx scenario_idx) { + return static_cast(this)->setup_impl(update_data, scenario_idx); + } + + void winddown() { return static_cast(this)->winddown_impl(); } + + CalculationInfo get_calculation_info() const { + return static_cast(this)->get_calculation_info_impl(); + } + + void merge_calculation_infos(std::vector const& info) { + static_cast(this)->merge_calculation_infos_impl(info); + } +}; + +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index ed01b8dfdc..c63b56a4b5 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -7,11 +7,11 @@ // main model class // main include -#include "batch_dispatch.hpp" -#include "batch_dispatch_adapter.hpp" #include "batch_parameter.hpp" #include "calculation_parameters.hpp" #include "container.hpp" +#include "job_dispatch.hpp" +#include "job_dispatch_adapter.hpp" #include "main_model_fwd.hpp" #include "topology.hpp" @@ -152,14 +152,10 @@ class MainModelImpl, ComponentLis using SequenceIdxView = std::array, main_core::utils::n_types>; using OwnedUpdateDataset = std::tuple...>; - using BatchDispatcher = - BatchDispatch, ComponentList>, - ComponentType...>; - - static constexpr Idx ignore_output{BatchDispatcher::ignore_output}; + static constexpr Idx ignore_output{JobDispatch::ignore_output}; static constexpr Idx isolated_component{-1}; static constexpr Idx not_connected{-1}; - static constexpr Idx sequential{BatchDispatcher::sequential}; + static constexpr Idx sequential{JobDispatch::sequential}; public: using Options = MainModelOptions; @@ -459,6 +455,7 @@ class MainModelImpl, ComponentLis }); }; } + // Calculate with optimization, e.g., automatic tap changer template auto calculate(Options const& options) { auto const calculator = [this, &options] { @@ -517,7 +514,7 @@ class MainModelImpl, ComponentLis /* Batch calculation, propagating the results to result_data - run the calculation function in batch on the provided update data. + Run the calculation function in batch on the provided update data. The calculation function should be able to run standalone. It should output to the provided result_data if the trailing argument is not ignore_output. @@ -530,9 +527,12 @@ class MainModelImpl, ComponentLis */ BatchParameter calculate(Options const& options, MutableDataset const& result_data, ConstDataset const& update_data) { - BatchDispatchAdapter adapter{std::ref(*this)}; - return BatchDispatcher::batch_calculation_( - *this, // TODO(mgovers): relace this with the adapter + JobDispatchAdapter< + MainModelImpl, ComponentList>, + ComponentType...> + adapter{std::ref(*this)}; + return JobDispatch::batch_calculation( + adapter, [&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::max(); @@ -544,7 +544,10 @@ class MainModelImpl, ComponentLis } CalculationInfo calculation_info() const { return calculation_info_; } - void set_calculation_info(CalculationInfo const& info) { calculation_info_ = info; } + void set_calculation_info(CalculationInfo const& info) { + assert(construction_complete_); + calculation_info_ = info; + } auto const& state() const { assert(construction_complete_); return state_; @@ -842,7 +845,7 @@ class MainModelImpl, ComponentLis * The default lambda `include_all` always returns `true`. */ template (CalcStructOut::* comp_vect), class ComponentIn, + std::vector(CalcStructOut::*comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -861,7 +864,7 @@ class MainModelImpl, ComponentLis } template (CalcStructOut::* comp_vect), class ComponentIn, + std::vector(CalcStructOut::*comp_vect), class ComponentIn, std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, @@ -881,7 +884,7 @@ class MainModelImpl, ComponentLis } } - template ::* component), class Component> + template ::*component), class Component> static void prepare_input_status(MainModelState const& state, std::vector const& objects, std::vector>& input) { for (Idx i = 0, n = narrow_cast(objects.size()); i != n; ++i) { From 47396fb627b00f341b65a7cf47cec035b520c2c8 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 21 Jul 2025 17:39:12 +0200 Subject: [PATCH 10/33] [skip ci] line with apparent issue Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch_adapter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 688573024e..761d30c61d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -89,7 +89,7 @@ class JobDispatchAdapter : public JobDispatchInterface( + current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( // something wrong here model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); model_.get().template update_components(update_data, scenario_idx, get_current_scenario_sequence_view_()); From e19aec67c74abde9570fc496115ecaac1e31a736 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Tue, 22 Jul 2025 09:40:03 +0200 Subject: [PATCH 11/33] [skip ci] finished solving branch issues, wip, almost there Signed-off-by: Santiago Figueroa Manrique --- .../batch_dispatch_adapter.hpp | 62 ------------------- .../batch_dispatch_interface.hpp | 40 ------------ .../include/power_grid_model/job_dispatch.hpp | 2 - .../power_grid_model/main_model_impl.hpp | 2 +- 4 files changed, 1 insertion(+), 105 deletions(-) delete mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp delete mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp deleted file mode 100644 index c03edc0c48..0000000000 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_adapter.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: Contributors to the Power Grid Model project -// -// SPDX-License-Identifier: MPL-2.0 - -#pragma once - -// batch dispatch adapter class - -#include "batch_dispatch_interface.hpp" -#include "main_core/calculation_info.hpp" -#include "main_core/update.hpp" - -namespace power_grid_model { - -template class BatchDispatchAdapter : public BatchDispatchInterface> { - public: - BatchDispatchAdapter(std::reference_wrapper model) : model_{std::move(model)} {} //, owns_model_copy_{false} {} - - BatchDispatchAdapter(BatchDispatchAdapter const& other) - : model_copy_{new MainModel{other.model_.get()}}, model_{std::ref(*model_copy_)}, owns_model_copy_{true} {} - - BatchDispatchAdapter& operator=(BatchDispatchAdapter const& other) { - if (this != &other) { - model_copy_ = std::make_unique(other.model_.get()); - model_ = std::ref(*model_copy_); - owns_model_copy_ = true; - } - return *this; - } - - private: - static constexpr Idx ignore_output{-1}; - - friend class BatchDispatchInterface; - std::unique_ptr model_copy_; - std::reference_wrapper model_; - bool owns_model_copy_{false}; - - template - requires std::invocable, MainModel&, MutableDataset const&, Idx> - void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx pos) { - return std::forward(calculation_fn)(model_.get(), result_data, pos); - } - - template - requires std::invocable, MainModel&, MutableDataset const&, Idx> - void cache_calculate_impl(Calculate&& calculation_fn) { - return std::forward(calculation_fn)(model_.get(), - { - false, - 1, - "sym_output", - model_.get().meta_data(), - }, - ignore_output); - } - - CalculationInfo calculation_info_impl() const { return model_.get().calculation_info(); } - - void set_calculation_info_impl(CalculationInfo const& info) { model_.get().set_calculation_info(info); } -}; -} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp deleted file mode 100644 index 1e092ed820..0000000000 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/batch_dispatch_interface.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: Contributors to the Power Grid Model project -// -// SPDX-License-Identifier: MPL-2.0 - -#pragma once - -// batch dispatch interface class - -#include -#include -#include - -namespace power_grid_model { -template class BatchDispatchInterface { - public: - // a concept for ResultDataset can be added if needed or MutableDataset can be used directly - template - requires requires(Adapter& adapter, Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos) { - { adapter.calculate_impl(std::forward(calculation_fn), result_data, pos) } -> std::same_as; - } - void calculate(Calculate&& calculation_fn, ResultDataset const& result_data, Idx pos = 0) { - return static_cast(this)->calculate_impl(std::forward(calculation_fn), result_data, pos); - } - - template - requires requires(Adapter& adapter, Calculate&& calculation_fn) { - { adapter.cache_calculate_impl(std::forward(calculation_fn)) } -> std::same_as; - } - void cache_calculate(Calculate&& calculation_fn) { - return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); - } - - CalculationInfo get_calculation_info() const { return static_cast(this)->get_calculation_info_impl(); } - - void set_calculation_info(CalculationInfo const& info) { - static_cast(this)->set_calculation_info_impl(info); - } -}; - -} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index d030413a99..c7d6a5278d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -9,8 +9,6 @@ #include "main_core/calculation_info.hpp" #include "main_core/update.hpp" -#include "batch_dispatch_interface.hpp" - #include namespace power_grid_model { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index c63b56a4b5..4c63ba2ea4 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -540,7 +540,7 @@ class MainModelImpl, ComponentLis model.calculate(sub_opt, target_data, pos); }, - result_data, update_data, adapter, options.threading); + result_data, update_data, options.threading); } CalculationInfo calculation_info() const { return calculation_info_; } From 77358983876e3b8ebd880613d627bede7058374e Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Tue, 22 Jul 2025 09:48:24 +0200 Subject: [PATCH 12/33] [skip ci] minor Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 1 - .../include/power_grid_model/job_dispatch_adapter.hpp | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 9bcf973b50..4f4043df94 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -55,7 +55,6 @@ class JobDispatch { auto sub_batch = sub_batch_calculation_(adapter, std::forward(calculation_fn), result_data, update_data, exceptions, infos); - job_dispatch(sub_batch, n_scenarios, threading); handle_batch_exceptions(exceptions); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 761d30c61d..94417c33bc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -89,8 +89,9 @@ class JobDispatchAdapter : public JobDispatchInterface( // something wrong here - model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); + current_scenario_sequence_cache_ = + main_core::update::get_all_sequence_idx_map( // something wrong here + model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); model_.get().template update_components(update_data, scenario_idx, get_current_scenario_sequence_view_()); } From a21cb9aad5aea447d0149e02c86e8753123e50f0 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 22 Jul 2025 14:47:05 +0200 Subject: [PATCH 13/33] fix stupid variadic stuff Signed-off-by: Martijn Govers --- .../include/power_grid_model/job_dispatch_adapter.hpp | 2 +- .../include/power_grid_model/main_core/calculation_info.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 94417c33bc..5c7f8d1c1e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -16,7 +16,7 @@ namespace power_grid_model { template -class JobDispatchAdapter : public JobDispatchInterface> { +class JobDispatchAdapter : public JobDispatchInterface> { public: JobDispatchAdapter(std::reference_wrapper model) : model_{std::move(model)} {} diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/calculation_info.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/calculation_info.hpp index cc5f1879aa..029078f986 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/calculation_info.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/calculation_info.hpp @@ -4,6 +4,7 @@ #pragma once +#include "../common/calculation_info.hpp" #include "../common/common.hpp" namespace power_grid_model::main_core { From 426af73412dcd47d8ef7e5efed4300bc06f5335e Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Wed, 23 Jul 2025 17:03:29 +0200 Subject: [PATCH 14/33] [skip ci] resolved some comments - tests still broken Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 22 ++++------- .../power_grid_model/job_dispatch_adapter.hpp | 39 +++++++++++-------- .../job_dispatch_interface.hpp | 4 +- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 4f4043df94..29f28c6e5d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -39,21 +39,15 @@ class JobDispatch { return BatchParameter{}; } - // calculate once to cache topology, ignore results, all math solvers are initialized - try { - adapter.cache_calculate(std::forward(calculation_fn)); - } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR - // missing entries are provided in the update data - } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR - // missing entries are provided in the update data - } + // calculate once to cache, ignore results + adapter.cache_calculate(std::forward(calculation_fn)); // error messages std::vector exceptions(n_scenarios, ""); std::vector infos(n_scenarios); - auto sub_batch = sub_batch_calculation_(adapter, std::forward(calculation_fn), result_data, - update_data, exceptions, infos); + auto sub_batch = single_threaded_job(adapter, std::forward(calculation_fn), result_data, update_data, + exceptions, infos); job_dispatch(sub_batch, n_scenarios, threading); @@ -65,10 +59,10 @@ class JobDispatch { private: template - static auto sub_batch_calculation_(Adapter& base_adapter, Calculate&& calculation_fn, - MutableDataset const& result_data, ConstDataset const& update_data, - std::vector& exceptions, std::vector& infos) { - base_adapter.prepare_sub_batch_calculation(update_data); + static auto single_threaded_job(Adapter& base_adapter, Calculate&& calculation_fn, + MutableDataset const& result_data, ConstDataset const& update_data, + std::vector& exceptions, std::vector& infos) { + base_adapter.prepare_job(update_data); return [&base_adapter, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), &result_data, &update_data](Idx start, Idx stride, Idx n_scenarios) { assert(n_scenarios <= narrow_cast(exceptions.size())); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 5c7f8d1c1e..020e4543b7 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -19,10 +19,8 @@ template class JobDispatchAdapter : public JobDispatchInterface> { public: JobDispatchAdapter(std::reference_wrapper model) : model_{std::move(model)} {} - JobDispatchAdapter(JobDispatchAdapter const& other) : model_copy_{std::make_unique(other.model_.get())}, model_{std::ref(*model_copy_)} {} - JobDispatchAdapter& operator=(JobDispatchAdapter const& other) { if (this != &other) { model_copy_ = std::make_unique(other.model_.get()); @@ -30,11 +28,14 @@ class JobDispatchAdapter : public JobDispatchInterface; // CRTP + static constexpr Idx ignore_output{-1}; - friend class JobDispatchInterface; std::unique_ptr model_copy_; std::reference_wrapper model_; @@ -50,23 +51,30 @@ class JobDispatchAdapter : public JobDispatchInterface requires std::invocable, MainModel&, MutableDataset const&, Idx> void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx scenario_idx) const { - return std::forward(calculation_fn)(model_.get(), result_data, scenario_idx); + std::forward(calculation_fn)(model_.get(), result_data, scenario_idx); } template requires std::invocable, MainModel&, MutableDataset const&, Idx> void cache_calculate_impl(Calculate&& calculation_fn) const { - return std::forward(calculation_fn)(model_.get(), - { - false, - 1, - "sym_output", - model_.get().meta_data(), - }, - ignore_output); + // calculate once to cache topology, ignore results, all math solvers are initialized + try { + std::forward(calculation_fn)(model_.get(), + { + false, + 1, + "sym_output", + model_.get().meta_data(), + }, + ignore_output); + } catch (SparseMatrixError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR + // missing entries are provided in the update data + } catch (NotObservableError const&) { // NOLINT(bugprone-empty-catch) // NOSONAR + // missing entries are provided in the update data + } } - void prepare_sub_batch_calculation_impl(ConstDataset const& update_data) { + void prepare_job_impl(ConstDataset const& update_data) { // cache component update order where possible. // the order for a cacheable (independent) component by definition is the same across all scenarios components_to_update_ = @@ -89,9 +97,8 @@ class JobDispatchAdapter : public JobDispatchInterface( // something wrong here - model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); + current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); model_.get().template update_components(update_data, scenario_idx, get_current_scenario_sequence_view_()); } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp index 0c57426087..8a108223a6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -29,8 +29,8 @@ template class JobDispatchInterface { return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); } - template void prepare_sub_batch_calculation(UpdateDataset const& update_data) { - return static_cast(this)->prepare_sub_batch_calculation_impl(update_data); + template void prepare_job(UpdateDataset const& update_data) { + return static_cast(this)->prepare_job_impl(update_data); } template void setup(UpdateDataset const& update_data, Idx scenario_idx) { From cfc1e9377b50e76c9ef21c9c0a13e05c56c07bca Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Wed, 23 Jul 2025 17:31:27 +0200 Subject: [PATCH 15/33] [skip ci] resolved some more comments Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/job_dispatch_adapter.hpp | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 020e4543b7..729040c99e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -40,14 +40,12 @@ class JobDispatchAdapter : public JobDispatchInterface model_; main_core::utils::SequenceIdx current_scenario_sequence_cache_{}; - std::shared_ptr> components_to_update_; - std::shared_ptr> - update_independence_; - std::shared_ptr> all_scenarios_sequence_; + power_grid_model::main_core::utils::ComponentFlags components_to_update_{}; + power_grid_model::main_core::update::independence::UpdateIndependence update_independence_{}; + main_core::utils::SequenceIdx all_scenarios_sequence_{}; main_core::utils::ComponentFlags independence_flags_{}; // TODO(figueroa1395): Keep calculation_fn at the adapter level only - template requires std::invocable, MainModel&, MutableDataset const&, Idx> void calculate_impl(Calculate&& calculation_fn, MutableDataset const& result_data, Idx scenario_idx) const { @@ -77,28 +75,19 @@ class JobDispatchAdapter : public JobDispatchInterface>( - model_.get().get_components_to_update(update_data)); - update_independence_ = std::make_shared< - const power_grid_model::main_core::update::independence::UpdateIndependence>( - main_core::update::independence::check_update_independence(model_.get().state(), - update_data)); - assert(components_to_update_ != nullptr); - assert(update_independence_ != nullptr); - all_scenarios_sequence_ = std::make_shared>( - main_core::update::get_all_sequence_idx_map( - model_.get().state(), update_data, 0, *components_to_update_, *update_independence_, false)); - - std::ranges::transform(*update_independence_, independence_flags_.begin(), + components_to_update_ = model_.get().get_components_to_update(update_data); + update_independence_ = main_core::update::independence::check_update_independence( + model_.get().state(), update_data); + all_scenarios_sequence_ = main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, 0, components_to_update_, update_independence_, false); + + std::ranges::transform(update_independence_, independence_flags_.begin(), [](auto const& comp) { return comp.is_independent(); }); } void setup_impl(ConstDataset const& update_data, Idx scenario_idx) { - assert(components_to_update_ != nullptr); - assert(update_independence_ != nullptr); current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( - model_.get().state(), update_data, scenario_idx, *components_to_update_, *update_independence_, true); + model_.get().state(), update_data, scenario_idx, components_to_update_, update_independence_, true); model_.get().template update_components(update_data, scenario_idx, get_current_scenario_sequence_view_()); } @@ -118,7 +107,7 @@ class JobDispatchAdapter : public JobDispatchInterface([this]() { constexpr auto comp_idx = main_core::utils::index_of_component; if (std::get(independence_flags_)) { - return std::span{std::get(*all_scenarios_sequence_)}; + return std::span{std::get(all_scenarios_sequence_)}; } return std::span{std::get(current_scenario_sequence_cache_)}; }); From 8ff37f41e2c451a5d293d401d05b3fac775b3114 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Thu, 24 Jul 2025 08:04:00 +0200 Subject: [PATCH 16/33] [skip ci] minor Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 29f28c6e5d..59e5d04a7d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -46,10 +46,10 @@ class JobDispatch { std::vector exceptions(n_scenarios, ""); std::vector infos(n_scenarios); - auto sub_batch = single_threaded_job(adapter, std::forward(calculation_fn), result_data, update_data, - exceptions, infos); + auto single_job = single_thread_job(adapter, std::forward(calculation_fn), result_data, update_data, + exceptions, infos); - job_dispatch(sub_batch, n_scenarios, threading); + job_dispatch(single_job, n_scenarios, threading); handle_batch_exceptions(exceptions); adapter.merge_calculation_infos(infos); @@ -59,9 +59,9 @@ class JobDispatch { private: template - static auto single_threaded_job(Adapter& base_adapter, Calculate&& calculation_fn, - MutableDataset const& result_data, ConstDataset const& update_data, - std::vector& exceptions, std::vector& infos) { + static auto single_thread_job(Adapter& base_adapter, Calculate&& calculation_fn, MutableDataset const& result_data, + ConstDataset const& update_data, std::vector& exceptions, + std::vector& infos) { base_adapter.prepare_job(update_data); return [&base_adapter, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), &result_data, &update_data](Idx start, Idx stride, Idx n_scenarios) { @@ -106,22 +106,22 @@ class JobDispatch { // specified threading < 0 // use hardware threads, but it is either unknown (0) or only has one thread (1) // specified threading = 1 - template - requires std::invocable, Idx /*start*/, Idx /*stride*/, Idx /*n_scenarios*/> - static void job_dispatch(RunSubBatchFn sub_batch, Idx n_scenarios, Idx threading) { + template + requires std::invocable, Idx /*start*/, Idx /*stride*/, Idx /*n_scenarios*/> + static void job_dispatch(RunSingleJobFn single_thread_job, Idx n_scenarios, Idx threading) { // run batches sequential or parallel auto const hardware_thread = static_cast(std::thread::hardware_concurrency()); if (threading < 0 || threading == 1 || (threading == 0 && hardware_thread < 2)) { // run all in sequential - sub_batch(0, 1, n_scenarios); + single_thread_job(0, 1, n_scenarios); } else { // create parallel threads Idx const n_thread = std::min(threading == 0 ? hardware_thread : threading, n_scenarios); std::vector threads; threads.reserve(n_thread); for (Idx thread_number = 0; thread_number < n_thread; ++thread_number) { - // compute each sub batch with stride - threads.emplace_back(sub_batch, thread_number, n_thread, n_scenarios); + // compute each single thread job with stride + threads.emplace_back(single_thread_job, thread_number, n_thread, n_scenarios); } for (auto& thread : threads) { thread.join(); From febcdb95410626eb2c21c50c1b240900cb3e1f5e Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Thu, 24 Jul 2025 15:35:33 +0200 Subject: [PATCH 17/33] tests pass locally - still an issue Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 2 +- .../include/power_grid_model/job_dispatch_adapter.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 59e5d04a7d..9c3f530ba0 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -62,7 +62,6 @@ class JobDispatch { static auto single_thread_job(Adapter& base_adapter, Calculate&& calculation_fn, MutableDataset const& result_data, ConstDataset const& update_data, std::vector& exceptions, std::vector& infos) { - base_adapter.prepare_job(update_data); return [&base_adapter, &exceptions, &infos, calculation_fn_ = std::forward(calculation_fn), &result_data, &update_data](Idx start, Idx stride, Idx n_scenarios) { assert(n_scenarios <= narrow_cast(exceptions.size())); @@ -76,6 +75,7 @@ class JobDispatch { }; auto adapter = copy_adapter_functor(start); + adapter.prepare_job(update_data); auto setup = [&adapter, &update_data, &infos](Idx scenario_idx) { Timer const t_update_model(infos[scenario_idx], 1200, "Update model"); adapter.setup(update_data, scenario_idx); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 729040c99e..de1b14631a 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -88,8 +88,8 @@ class JobDispatchAdapter : public JobDispatchInterface( model_.get().state(), update_data, scenario_idx, components_to_update_, update_independence_, true); - model_.get().template update_components(update_data, scenario_idx, - get_current_scenario_sequence_view_()); + auto const current_scenario_sequence = get_current_scenario_sequence_view_(); + model_.get().template update_components(update_data, scenario_idx, current_scenario_sequence); } void winddown_impl() { From 0031bb25e4d2726f106bdbac49756137eed4acf9 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 25 Jul 2025 10:15:46 +0200 Subject: [PATCH 18/33] move assignment operator Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch_adapter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index de1b14631a..a97f7ef04e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -29,6 +29,7 @@ class JobDispatchAdapter : public JobDispatchInterface Date: Fri, 1 Aug 2025 09:57:12 +0200 Subject: [PATCH 19/33] fix missing merge conflicts Signed-off-by: Martijn Govers --- .../include/power_grid_model/job_dispatch.hpp | 30 +++++++------------ .../power_grid_model/job_dispatch_adapter.hpp | 9 ++++-- .../job_dispatch_interface.hpp | 7 +++-- .../power_grid_model/main_model_impl.hpp | 4 +-- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index de7de82976..ce6bafed05 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -46,16 +46,8 @@ class JobDispatch { // error messages std::vector exceptions(n_scenarios, ""); - // thread-safe handling of calculation info - std::mutex calculation_info_mutex; - auto const thread_safe_add_calculation_info = [&calculation_info, - &calculation_info_mutex](CalculationInfo const& info) { - std::lock_guard const lock{calculation_info_mutex}; - main_core::merge_into(calculation_info, info); - }; - - auto single_job = single_thread_job(adapter, std::forward(calculation_fn), result_data, update_data, - exceptions, thread_safe_add_calculation_info); + auto single_job = + single_thread_job(adapter, std::forward(calculation_fn), result_data, update_data, exceptions); job_dispatch(single_job, n_scenarios, threading); @@ -65,17 +57,17 @@ class JobDispatch { } private: - template + template static auto single_thread_job(Adapter& base_adapter, Calculate&& calculation_fn, MutableDataset const& result_data, - ConstDataset const& update_data, std::vector& exceptions, - AddCalculationInfo&& thread_safe_add_calculation_info) { - return [&base_adapter, &exceptions, &thread_safe_add_calculation_info, - calculation_fn_ = std::forward(calculation_fn), &result_data, + ConstDataset const& update_data, std::vector& exceptions) { + return [&base_adapter, &exceptions, calculation_fn_ = std::forward(calculation_fn), &result_data, &update_data](Idx start, Idx stride, Idx n_scenarios) { assert(n_scenarios <= narrow_cast(exceptions.size())); CalculationInfo thread_info; + Timer t_total(thread_info, 1000, "Total batch calculation in thread"); + auto const copy_adapter_functor = [&base_adapter, &thread_info](Idx scenario_idx) { Timer const t_copy_adapter_functor(thread_info, 1100, "Copy model"); return Adapter{base_adapter}; @@ -107,13 +99,13 @@ class JobDispatch { } t_total.stop(); - thread_safe_add_calculation_info(thread_info); + base_adapter.thread_safe_add_calculation_info(thread_info); }; } - template - requires std::invocable, Idx /*start*/, Idx /*stride*/, Idx /*n_scenarios*/> - static void job_dispatch(RunSubBatchFn sub_batch, Idx n_scenarios, Idx threading) { + template + requires std::invocable, Idx /*start*/, Idx /*stride*/, Idx /*n_scenarios*/> + static void job_dispatch(RunSingleJobFn single_thread_job, Idx n_scenarios, Idx threading) { // run batches sequential or parallel auto const n_thread = n_threads(n_scenarios, threading); if (n_thread == 1) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index a97f7ef04e..1a1d4fe8cc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -46,6 +46,8 @@ class JobDispatchAdapter : public JobDispatchInterface all_scenarios_sequence_{}; main_core::utils::ComponentFlags independence_flags_{}; + std::mutex calculation_info_mutex_; + // TODO(figueroa1395): Keep calculation_fn at the adapter level only template requires std::invocable, MainModel&, MutableDataset const&, Idx> @@ -100,8 +102,11 @@ class JobDispatchAdapter : public JobDispatchInterface const& infos) { - model_.get().set_calculation_info(main_core::merge_calculation_info(infos)); + void add_calculation_info_impl(CalculationInfo const& info) { model_.get().merge_calculation_info(info); } + + void thread_safe_add_calculation_info_impl(CalculationInfo const& info) { + std::lock_guard const lock{calculation_info_mutex_}; + add_calculation_info_impl(info); } auto get_current_scenario_sequence_view_() const { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp index 8a108223a6..a6abd3d576 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -6,6 +6,9 @@ // batch dispatch interface class +#include "common/calculation_info.hpp" +#include "common/common.hpp" + #include #include #include @@ -43,8 +46,8 @@ template class JobDispatchInterface { return static_cast(this)->get_calculation_info_impl(); } - void merge_calculation_infos(std::vector const& info) { - static_cast(this)->merge_calculation_infos_impl(info); + void thread_safe_add_calculation_info(CalculationInfo const& info) { + static_cast(this)->thread_safe_add_calculation_info_impl(info); } }; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index 9340916aa7..de4ca02493 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -544,9 +544,9 @@ class MainModelImpl, ComponentLis } CalculationInfo calculation_info() const { return calculation_info_; } - void set_calculation_info(CalculationInfo const& info) { + void merge_calculation_info(CalculationInfo const& info) { assert(construction_complete_); - calculation_info_ = info; + main_core::merge_into(calculation_info_, info); } auto const& state() const { assert(construction_complete_); From 021fc82fc25b378c8cef79a30fc8044e0b25f840 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 1 Aug 2025 10:04:15 +0200 Subject: [PATCH 20/33] fix clang Signed-off-by: Martijn Govers --- .../power_grid_model/include/power_grid_model/job_dispatch.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index ce6bafed05..a18184dca1 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -68,7 +68,7 @@ class JobDispatch { Timer t_total(thread_info, 1000, "Total batch calculation in thread"); - auto const copy_adapter_functor = [&base_adapter, &thread_info](Idx scenario_idx) { + auto const copy_adapter_functor = [&base_adapter, &thread_info](Idx /*scenario_idx*/) { Timer const t_copy_adapter_functor(thread_info, 1100, "Copy model"); return Adapter{base_adapter}; }; From 41566333df1761defb02fc075b774472db1a3f3b Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 1 Aug 2025 11:21:09 +0200 Subject: [PATCH 21/33] fix Signed-off-by: Santiago Figueroa Manrique --- .../power_grid_model/include/power_grid_model/job_dispatch.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index a18184dca1..9c3efbb3fb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -80,7 +80,7 @@ class JobDispatch { adapter.setup(update_data, scenario_idx); }; - auto winddown = [&adapter, &thread_info](Idx scenario_idx) { + auto winddown = [&adapter, &thread_info](Idx /*scenario_idx*/) { Timer const t_update_model(thread_info, 1201, "Restore model"); adapter.winddown(); }; From b8b95ab2d60cdb2ce72c17b1dcafe97cb11ac149 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 1 Aug 2025 13:37:25 +0200 Subject: [PATCH 22/33] constructors and improvement Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 4 +- .../power_grid_model/job_dispatch_adapter.hpp | 57 ++++++++++++++++--- .../job_dispatch_interface.hpp | 8 ++- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 9c3efbb3fb..558974defb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -46,6 +46,7 @@ class JobDispatch { // error messages std::vector exceptions(n_scenarios, ""); + adapter.prepare_job_dispatch(update_data); auto single_job = single_thread_job(adapter, std::forward(calculation_fn), result_data, update_data, exceptions); @@ -72,9 +73,10 @@ class JobDispatch { Timer const t_copy_adapter_functor(thread_info, 1100, "Copy model"); return Adapter{base_adapter}; }; + auto adapter = copy_adapter_functor(start); + adapter.prepare_scenarios(update_data); - adapter.prepare_job(update_data); auto setup = [&adapter, &update_data, &thread_info](Idx scenario_idx) { Timer const t_update_model(thread_info, 1200, "Update model"); adapter.setup(update_data, scenario_idx); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 1a1d4fe8cc..7cd33e621f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -20,18 +20,48 @@ class JobDispatchAdapter : public JobDispatchInterface model) : model_{std::move(model)} {} JobDispatchAdapter(JobDispatchAdapter const& other) - : model_copy_{std::make_unique(other.model_.get())}, model_{std::ref(*model_copy_)} {} + : model_copy_{std::make_unique(other.model_.get())}, + model_{std::ref(*model_copy_)}, + components_to_update_{other.components_to_update_}, + update_independence_{other.update_independence_}, + independence_flags_{other.independence_flags_} {} JobDispatchAdapter& operator=(JobDispatchAdapter const& other) { if (this != &other) { model_copy_ = std::make_unique(other.model_.get()); model_ = std::ref(*model_copy_); + components_to_update_ = other.components_to_update_; + update_independence_ = other.update_independence_; + independence_flags_ = other.independence_flags_; + } + return *this; + } + JobDispatchAdapter(JobDispatchAdapter&& other) noexcept + : model_copy_{std::move(other.model_copy_)}, + model_{model_copy_ ? std::ref(*model_copy_) : std::move(other.model_)}, + components_to_update_{std::move(other.components_to_update_)}, + update_independence_{std::move(other.update_independence_)}, + independence_flags_{std::move(other.independence_flags_)} {} + JobDispatchAdapter& operator=(JobDispatchAdapter&& other) noexcept { + if (this != &other) { + model_copy_ = std::move(other.model_copy_); + model_ = model_copy_ ? std::ref(*model_copy_) : std::move(other.model_); + components_to_update_ = std::move(other.components_to_update_); + update_independence_ = std::move(other.update_independence_); + independence_flags_ = std::move(other.independence_flags_); } return *this; } - JobDispatchAdapter(JobDispatchAdapter&& other) = default; - JobDispatchAdapter& operator=(JobDispatchAdapter&& other) = default; ~JobDispatchAdapter() = default; + // MainModel(MainModel&& other) noexcept : impl_{std::move(other.impl_)} {} + // MainModel& operator=(MainModel&& other) noexcept { + // if (this != &other) { + // impl_ = std::move(other.impl_); + // } + // return *this; + // }; + // ~MainModel() { impl_.reset(); } + private: friend class JobDispatchInterface; // CRTP @@ -40,12 +70,17 @@ class JobDispatchAdapter : public JobDispatchInterface model_copy_; std::reference_wrapper model_; - main_core::utils::SequenceIdx current_scenario_sequence_cache_{}; power_grid_model::main_core::utils::ComponentFlags components_to_update_{}; power_grid_model::main_core::update::independence::UpdateIndependence update_independence_{}; - main_core::utils::SequenceIdx all_scenarios_sequence_{}; main_core::utils::ComponentFlags independence_flags_{}; + // These are expensive to copy and easier to calculate from scratch + // They are explicitly left out of the constructors for these reason + // TODO(figueroa1395): Can all_scenarios_sequence_ be a shared pointer or similar and its + // calculation be included in prepare_job_dispatch_impl? + main_core::utils::SequenceIdx all_scenarios_sequence_{}; + main_core::utils::SequenceIdx current_scenario_sequence_cache_{}; + std::mutex calculation_info_mutex_; // TODO(figueroa1395): Keep calculation_fn at the adapter level only @@ -75,19 +110,23 @@ class JobDispatchAdapter : public JobDispatchInterface( model_.get().state(), update_data); - all_scenarios_sequence_ = main_core::update::get_all_sequence_idx_map( - model_.get().state(), update_data, 0, components_to_update_, update_independence_, false); - + // all_scenarios_sequence_ = main_core::update::get_all_sequence_idx_map( + // model_.get().state(), update_data, 0, components_to_update_, update_independence_, false); std::ranges::transform(update_independence_, independence_flags_.begin(), [](auto const& comp) { return comp.is_independent(); }); } + void prepare_scenarios_impl(ConstDataset const& update_data) { + all_scenarios_sequence_ = main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, 0, components_to_update_, update_independence_, false); + } + void setup_impl(ConstDataset const& update_data, Idx scenario_idx) { current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map( model_.get().state(), update_data, scenario_idx, components_to_update_, update_independence_, true); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp index a6abd3d576..9aaf407df8 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -32,8 +32,12 @@ template class JobDispatchInterface { return static_cast(this)->cache_calculate_impl(std::forward(calculation_fn)); } - template void prepare_job(UpdateDataset const& update_data) { - return static_cast(this)->prepare_job_impl(update_data); + template void prepare_job_dispatch(UpdateDataset const& update_data) { + return static_cast(this)->prepare_job_dispatch_impl(update_data); + } + + template void prepare_scenarios(UpdateDataset const& update_data) { + return static_cast(this)->prepare_scenarios_impl(update_data); } template void setup(UpdateDataset const& update_data, Idx scenario_idx) { From f01dc282200781599d9faf3805d2e0c8c28d83ab Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 1 Aug 2025 13:57:09 +0200 Subject: [PATCH 23/33] cleanup Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 1 - .../power_grid_model/job_dispatch_adapter.hpp | 37 ++++++------------- .../job_dispatch_interface.hpp | 4 -- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 558974defb..7bd10f7468 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -75,7 +75,6 @@ class JobDispatch { }; auto adapter = copy_adapter_functor(start); - adapter.prepare_scenarios(update_data); auto setup = [&adapter, &update_data, &thread_info](Idx scenario_idx) { Timer const t_update_model(thread_info, 1200, "Update model"); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 7cd33e621f..366450de5b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -24,7 +24,8 @@ class JobDispatchAdapter : public JobDispatchInterface(other.model_.get()); @@ -32,6 +33,7 @@ class JobDispatchAdapter : public JobDispatchInterface; // CRTP @@ -73,12 +68,8 @@ class JobDispatchAdapter : public JobDispatchInterface components_to_update_{}; power_grid_model::main_core::update::independence::UpdateIndependence update_independence_{}; main_core::utils::ComponentFlags independence_flags_{}; - - // These are expensive to copy and easier to calculate from scratch - // They are explicitly left out of the constructors for these reason - // TODO(figueroa1395): Can all_scenarios_sequence_ be a shared pointer or similar and its - // calculation be included in prepare_job_dispatch_impl? - main_core::utils::SequenceIdx all_scenarios_sequence_{}; + std::shared_ptr> all_scenarios_sequence_; + // current_scenario_sequence_cache_ is calculated per scenario, so it is excluded from the constructors. main_core::utils::SequenceIdx current_scenario_sequence_cache_{}; std::mutex calculation_info_mutex_; @@ -116,15 +107,11 @@ class JobDispatchAdapter : public JobDispatchInterface( model_.get().state(), update_data); - // all_scenarios_sequence_ = main_core::update::get_all_sequence_idx_map( - // model_.get().state(), update_data, 0, components_to_update_, update_independence_, false); std::ranges::transform(update_independence_, independence_flags_.begin(), [](auto const& comp) { return comp.is_independent(); }); - } - - void prepare_scenarios_impl(ConstDataset const& update_data) { - all_scenarios_sequence_ = main_core::update::get_all_sequence_idx_map( - model_.get().state(), update_data, 0, components_to_update_, update_independence_, false); + all_scenarios_sequence_ = std::make_shared>( + main_core::update::get_all_sequence_idx_map( + model_.get().state(), update_data, 0, components_to_update_, update_independence_, false)); } void setup_impl(ConstDataset const& update_data, Idx scenario_idx) { @@ -152,7 +139,7 @@ class JobDispatchAdapter : public JobDispatchInterface([this]() { constexpr auto comp_idx = main_core::utils::index_of_component; if (std::get(independence_flags_)) { - return std::span{std::get(all_scenarios_sequence_)}; + return std::span{std::get(*all_scenarios_sequence_)}; } return std::span{std::get(current_scenario_sequence_cache_)}; }); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp index 9aaf407df8..a9f2fb232d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -36,10 +36,6 @@ template class JobDispatchInterface { return static_cast(this)->prepare_job_dispatch_impl(update_data); } - template void prepare_scenarios(UpdateDataset const& update_data) { - return static_cast(this)->prepare_scenarios_impl(update_data); - } - template void setup(UpdateDataset const& update_data, Idx scenario_idx) { return static_cast(this)->setup_impl(update_data, scenario_idx); } From 1a7a5724bb6638d15ef109142d7751ab070c1bfa Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 4 Aug 2025 09:25:01 +0200 Subject: [PATCH 24/33] revert accidental checkin of experimental file Signed-off-by: Martijn Govers --- .../power_grid_model/common/two_d_array.hpp | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/common/two_d_array.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/two_d_array.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/two_d_array.hpp deleted file mode 100644 index 6e6e591ff3..0000000000 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/two_d_array.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-FileCopyrightText: Contributors to the Power Grid Model project -// -// SPDX-License-Identifier: MPL-2.0 - -#pragma once - -#include "common.hpp" - -// eigen properties -#include - -#include - -namespace power_grid_model::two_d_array { -template using Eigen3Vector = Eigen::Array; -template using Eigen3Tensor = Eigen::Array; -template using Eigen4Tensor = Eigen::Array; -template using Eigen3DiagonalTensor = Eigen::DiagonalMatrix; -} // namespace power_grid_model::two_d_array From 6c7182ee543005e6f32e6e7a43a19d67bd91b202 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 4 Aug 2025 11:46:42 +0200 Subject: [PATCH 25/33] Update power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp Signed-off-by: Martijn Govers Signed-off-by: Martijn Govers --- .../power_grid_model/include/power_grid_model/job_dispatch.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 7bd10f7468..578aa1b265 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -89,7 +89,7 @@ class JobDispatch { auto calculate_scenario = JobDispatch::call_with( [&adapter, &calculation_fn_, &result_data, &thread_info](Idx scenario_idx) { adapter.calculate(calculation_fn_, result_data, scenario_idx); - thread_info.merge(adapter.get_calculation_info()); + main_core::merge_into(thread_info, adapter.get_calculation_info()); }, std::move(setup), std::move(winddown), scenario_exception_handler(adapter, exceptions, thread_info), [&adapter, ©_adapter_functor](Idx scenario_idx) { adapter = copy_adapter_functor(scenario_idx); }); From 1769f1ca1254d2969048b3e5dc78cacc0e3e1de2 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 4 Aug 2025 15:21:05 +0200 Subject: [PATCH 26/33] -sm destructor Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch_adapter.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 366450de5b..b9e0fd9a17 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -55,7 +55,7 @@ class JobDispatchAdapter : public JobDispatchInterface; // CRTP @@ -128,11 +128,9 @@ class JobDispatchAdapter : public JobDispatchInterface Date: Thu, 7 Aug 2025 07:52:55 +0200 Subject: [PATCH 27/33] Update power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp Signed-off-by: Martijn Govers Co-authored-by: Nitish Bharambe <78108900+nitbharambe@users.noreply.github.com> Signed-off-by: Martijn Govers --- .../include/power_grid_model/job_dispatch_adapter.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index b9e0fd9a17..7aec5a5545 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -65,8 +65,8 @@ class JobDispatchAdapter : public JobDispatchInterface model_copy_; std::reference_wrapper model_; - power_grid_model::main_core::utils::ComponentFlags components_to_update_{}; - power_grid_model::main_core::update::independence::UpdateIndependence update_independence_{}; + main_core::utils::ComponentFlags components_to_update_{}; + main_core::update::independence::UpdateIndependence update_independence_{}; main_core::utils::ComponentFlags independence_flags_{}; std::shared_ptr> all_scenarios_sequence_; // current_scenario_sequence_cache_ is calculated per scenario, so it is excluded from the constructors. From 1eb11646a00043fbdc5c8402e1950556ef23c334 Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Fri, 8 Aug 2025 10:17:19 +0200 Subject: [PATCH 28/33] address comments Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 4 ++-- .../include/power_grid_model/job_dispatch_interface.hpp | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 578aa1b265..95f9ac794b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -67,7 +67,7 @@ class JobDispatch { CalculationInfo thread_info; - Timer t_total(thread_info, 1000, "Total batch calculation in thread"); + Timer t_total(thread_info, 0200, "Total batch calculation in thread"); auto const copy_adapter_functor = [&base_adapter, &thread_info](Idx /*scenario_idx*/) { Timer const t_copy_adapter_functor(thread_info, 1100, "Copy model"); @@ -82,7 +82,7 @@ class JobDispatch { }; auto winddown = [&adapter, &thread_info](Idx /*scenario_idx*/) { - Timer const t_update_model(thread_info, 1201, "Restore model"); + Timer const t_restore_model(thread_info, 1201, "Restore model"); adapter.winddown(); }; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp index a9f2fb232d..9b649dbe33 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -49,6 +49,14 @@ template class JobDispatchInterface { void thread_safe_add_calculation_info(CalculationInfo const& info) { static_cast(this)->thread_safe_add_calculation_info_impl(info); } + + protected: + JobDispatchInterface() = default; + JobDispatchInterface(const JobDispatchInterface& /*other*/) = default; + JobDispatchInterface(JobDispatchInterface&& /*other*/) = default; + JobDispatchInterface& operator=(const JobDispatchInterface& /*other*/) = default; + JobDispatchInterface& operator=(JobDispatchInterface&& /*other*/) = default; + ~JobDispatchInterface() = default; }; } // namespace power_grid_model From f1f4a256cb52c792b2e7df3f7c66d31ff9b146b3 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Fri, 8 Aug 2025 13:43:14 +0200 Subject: [PATCH 29/33] remove extra Idx Signed-off-by: Nitish Bharambe --- .../include/power_grid_model/job_dispatch.hpp | 32 +++++++++++-------- .../power_grid_model/job_dispatch_adapter.hpp | 2 +- .../job_dispatch_interface.hpp | 4 +-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 95f9ac794b..0dadc62c0f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -69,30 +69,34 @@ class JobDispatch { Timer t_total(thread_info, 0200, "Total batch calculation in thread"); - auto const copy_adapter_functor = [&base_adapter, &thread_info](Idx /*scenario_idx*/) { + // Can we remove this Idx? + auto const copy_adapter_functor = [&base_adapter, &thread_info]() { Timer const t_copy_adapter_functor(thread_info, 1100, "Copy model"); return Adapter{base_adapter}; }; - auto adapter = copy_adapter_functor(start); + auto adapter = copy_adapter_functor(); auto setup = [&adapter, &update_data, &thread_info](Idx scenario_idx) { Timer const t_update_model(thread_info, 1200, "Update model"); adapter.setup(update_data, scenario_idx); }; - auto winddown = [&adapter, &thread_info](Idx /*scenario_idx*/) { + auto winddown = [&adapter, &thread_info]() { Timer const t_restore_model(thread_info, 1201, "Restore model"); adapter.winddown(); }; + auto recover_from_bad = [&adapter, ©_adapter_functor]() { adapter = copy_adapter_functor(); }; + + auto run = [&adapter, &calculation_fn_, &result_data, &thread_info](Idx scenario_idx) { + adapter.calculate(calculation_fn_, result_data, scenario_idx); + main_core::merge_into(thread_info, adapter.get_calculation_info()); + }; + auto calculate_scenario = JobDispatch::call_with( - [&adapter, &calculation_fn_, &result_data, &thread_info](Idx scenario_idx) { - adapter.calculate(calculation_fn_, result_data, scenario_idx); - main_core::merge_into(thread_info, adapter.get_calculation_info()); - }, - std::move(setup), std::move(winddown), scenario_exception_handler(adapter, exceptions, thread_info), - [&adapter, ©_adapter_functor](Idx scenario_idx) { adapter = copy_adapter_functor(scenario_idx); }); + std::move(run), std::move(setup), std::move(winddown), + scenario_exception_handler(adapter, exceptions, thread_info), std::move(recover_from_bad)); for (Idx scenario_idx = start; scenario_idx < n_scenarios; scenario_idx += stride) { Timer const t_total_single(thread_info, 0100, "Total single calculation in thread"); @@ -142,9 +146,9 @@ class JobDispatch { typename RecoverFromBadFn> requires std::invocable, Args const&...> && std::invocable, Args const&...> && - std::invocable, Args const&...> && + std::invocable> && std::invocable, Args const&...> && - std::invocable, Args const&...> + std::invocable> static auto call_with(RunFn run, SetupFn setup, WinddownFn winddown, HandleExceptionFn handle_exception, RecoverFromBadFn recover_from_bad) { return [setup_ = std::move(setup), run_ = std::move(run), winddown_ = std::move(winddown), @@ -153,13 +157,13 @@ class JobDispatch { try { setup_(args...); run_(args...); - winddown_(args...); + winddown_(); } catch (...) { handle_exception_(args...); try { - winddown_(args...); + winddown_(); } catch (...) { - recover_from_bad_(args...); + recover_from_bad_(); } } }; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 7aec5a5545..c12a5ba7d5 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -4,7 +4,7 @@ #pragma once -// batch dispatch adapter class +// Adapter that connects the JobDispatch to the MainModelImpl #include "auxiliary/dataset.hpp" #include "job_dispatch_interface.hpp" diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp index 9b649dbe33..5ba163cec5 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp @@ -54,8 +54,8 @@ template class JobDispatchInterface { JobDispatchInterface() = default; JobDispatchInterface(const JobDispatchInterface& /*other*/) = default; JobDispatchInterface(JobDispatchInterface&& /*other*/) = default; - JobDispatchInterface& operator=(const JobDispatchInterface& /*other*/) = default; - JobDispatchInterface& operator=(JobDispatchInterface&& /*other*/) = default; + JobDispatchInterface& operator=(const JobDispatchInterface& /*other*/) noexcept = default; + JobDispatchInterface& operator=(JobDispatchInterface&& /*other*/) noexcept = default; ~JobDispatchInterface() = default; }; From 6a95434758116e7da06357f7eef54b249c9685c6 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Fri, 8 Aug 2025 14:19:08 +0200 Subject: [PATCH 30/33] remove repeatition Signed-off-by: Nitish Bharambe --- .../power_grid_model/job_dispatch_adapter.hpp | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index c12a5ba7d5..6c12bed7eb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -20,38 +20,30 @@ class JobDispatchAdapter : public JobDispatchInterface model) : model_{std::move(model)} {} JobDispatchAdapter(JobDispatchAdapter const& other) - : model_copy_{std::make_unique(other.model_.get())}, - model_{std::ref(*model_copy_)}, - components_to_update_{other.components_to_update_}, - update_independence_{other.update_independence_}, - independence_flags_{other.independence_flags_}, - all_scenarios_sequence_{other.all_scenarios_sequence_} {} + : model_copy_{std::make_unique(other.model_.get())}, model_{std::ref(*model_copy_)} { + copy_construction_remaining_members(other); + } + JobDispatchAdapter& operator=(JobDispatchAdapter const& other) { if (this != &other) { model_copy_ = std::make_unique(other.model_.get()); model_ = std::ref(*model_copy_); - components_to_update_ = other.components_to_update_; - update_independence_ = other.update_independence_; - independence_flags_ = other.independence_flags_; - all_scenarios_sequence_ = other.all_scenarios_sequence_; + copy_construction_remaining_members(other); } return *this; } JobDispatchAdapter(JobDispatchAdapter&& other) noexcept : model_copy_{std::move(other.model_copy_)}, - model_{model_copy_ ? std::ref(*model_copy_) : std::move(other.model_)}, - components_to_update_{std::move(other.components_to_update_)}, - update_independence_{std::move(other.update_independence_)}, - independence_flags_{std::move(other.independence_flags_)}, - all_scenarios_sequence_{std::move(other.all_scenarios_sequence_)} {} + model_{model_copy_ ? std::ref(*model_copy_) : std::move(other.model_)} { + move_construction_remaining_members(std::move(other)); + other.model_copy_.reset(); + } JobDispatchAdapter& operator=(JobDispatchAdapter&& other) noexcept { if (this != &other) { model_copy_ = std::move(other.model_copy_); model_ = model_copy_ ? std::ref(*model_copy_) : std::move(other.model_); - components_to_update_ = std::move(other.components_to_update_); - update_independence_ = std::move(other.update_independence_); - independence_flags_ = std::move(other.independence_flags_); - all_scenarios_sequence_ = std::move(other.all_scenarios_sequence_); + move_construction_remaining_members(std::move(other)); + other.model_copy_.reset(); } return *this; } @@ -74,6 +66,19 @@ class JobDispatchAdapter : public JobDispatchInterface requires std::invocable, MainModel&, MutableDataset const&, Idx> From b998a2ab7bdfdf833a1feb769cd5fe9b295f5110 Mon Sep 17 00:00:00 2001 From: Nitish Bharambe Date: Fri, 8 Aug 2025 15:54:00 +0200 Subject: [PATCH 31/33] Revert "remove repeatition" This reverts commit 6a95434758116e7da06357f7eef54b249c9685c6. Signed-off-by: Nitish Bharambe --- .../power_grid_model/job_dispatch_adapter.hpp | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp index 6c12bed7eb..c12a5ba7d5 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp @@ -20,30 +20,38 @@ class JobDispatchAdapter : public JobDispatchInterface model) : model_{std::move(model)} {} JobDispatchAdapter(JobDispatchAdapter const& other) - : model_copy_{std::make_unique(other.model_.get())}, model_{std::ref(*model_copy_)} { - copy_construction_remaining_members(other); - } - + : model_copy_{std::make_unique(other.model_.get())}, + model_{std::ref(*model_copy_)}, + components_to_update_{other.components_to_update_}, + update_independence_{other.update_independence_}, + independence_flags_{other.independence_flags_}, + all_scenarios_sequence_{other.all_scenarios_sequence_} {} JobDispatchAdapter& operator=(JobDispatchAdapter const& other) { if (this != &other) { model_copy_ = std::make_unique(other.model_.get()); model_ = std::ref(*model_copy_); - copy_construction_remaining_members(other); + components_to_update_ = other.components_to_update_; + update_independence_ = other.update_independence_; + independence_flags_ = other.independence_flags_; + all_scenarios_sequence_ = other.all_scenarios_sequence_; } return *this; } JobDispatchAdapter(JobDispatchAdapter&& other) noexcept : model_copy_{std::move(other.model_copy_)}, - model_{model_copy_ ? std::ref(*model_copy_) : std::move(other.model_)} { - move_construction_remaining_members(std::move(other)); - other.model_copy_.reset(); - } + model_{model_copy_ ? std::ref(*model_copy_) : std::move(other.model_)}, + components_to_update_{std::move(other.components_to_update_)}, + update_independence_{std::move(other.update_independence_)}, + independence_flags_{std::move(other.independence_flags_)}, + all_scenarios_sequence_{std::move(other.all_scenarios_sequence_)} {} JobDispatchAdapter& operator=(JobDispatchAdapter&& other) noexcept { if (this != &other) { model_copy_ = std::move(other.model_copy_); model_ = model_copy_ ? std::ref(*model_copy_) : std::move(other.model_); - move_construction_remaining_members(std::move(other)); - other.model_copy_.reset(); + components_to_update_ = std::move(other.components_to_update_); + update_independence_ = std::move(other.update_independence_); + independence_flags_ = std::move(other.independence_flags_); + all_scenarios_sequence_ = std::move(other.all_scenarios_sequence_); } return *this; } @@ -66,19 +74,6 @@ class JobDispatchAdapter : public JobDispatchInterface requires std::invocable, MainModel&, MutableDataset const&, Idx> From 7f1409b3a87bebe64c10fa94a8c96fef8e39b20d Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 11 Aug 2025 09:38:47 +0200 Subject: [PATCH 32/33] resolve comments Signed-off-by: Santiago Figueroa Manrique --- .../{job_dispatch_adapter.hpp => job_adapter.hpp} | 7 +++++-- .../include/power_grid_model/job_dispatch.hpp | 3 +-- .../{job_dispatch_interface.hpp => job_interface.hpp} | 1 + .../include/power_grid_model/main_model_impl.hpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) rename power_grid_model_c/power_grid_model/include/power_grid_model/{job_dispatch_adapter.hpp => job_adapter.hpp} (95%) rename power_grid_model_c/power_grid_model/include/power_grid_model/{job_dispatch_interface.hpp => job_interface.hpp} (96%) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_adapter.hpp similarity index 95% rename from power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp rename to power_grid_model_c/power_grid_model/include/power_grid_model/job_adapter.hpp index c12a5ba7d5..b1d1bb1b6f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_adapter.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_adapter.hpp @@ -7,7 +7,7 @@ // Adapter that connects the JobDispatch to the MainModelImpl #include "auxiliary/dataset.hpp" -#include "job_dispatch_interface.hpp" +#include "job_interface.hpp" #include "main_model_fwd.hpp" #include "main_core/calculation_info.hpp" @@ -58,7 +58,10 @@ class JobDispatchAdapter : public JobDispatchInterface; // CRTP + // Grant the CRTP base (JobDispatchInterface) access to + // JobDispatchAdapter's private members. This allows the base class template + // to call derived-class implementation details as part of the CRTP pattern. + friend class JobDispatchInterface; static constexpr Idx ignore_output{-1}; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 0dadc62c0f..772f344cab 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -4,7 +4,7 @@ #pragma once -#include "job_dispatch_interface.hpp" +#include "job_interface.hpp" #include "main_core/calculation_info.hpp" #include "main_core/update.hpp" @@ -69,7 +69,6 @@ class JobDispatch { Timer t_total(thread_info, 0200, "Total batch calculation in thread"); - // Can we remove this Idx? auto const copy_adapter_functor = [&base_adapter, &thread_info]() { Timer const t_copy_adapter_functor(thread_info, 1100, "Copy model"); return Adapter{base_adapter}; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp similarity index 96% rename from power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp rename to power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp index 5ba163cec5..9f8c73c3ce 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp @@ -51,6 +51,7 @@ template class JobDispatchInterface { } protected: + // Protected & defaulted special members — CRTP: only the derived can create/copy/move this base JobDispatchInterface() = default; JobDispatchInterface(const JobDispatchInterface& /*other*/) = default; JobDispatchInterface(JobDispatchInterface&& /*other*/) = default; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index 75c844d7c3..17755fb5b0 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -10,8 +10,8 @@ #include "batch_parameter.hpp" #include "calculation_parameters.hpp" #include "container.hpp" +#include "job_adapter.hpp" #include "job_dispatch.hpp" -#include "job_dispatch_adapter.hpp" #include "main_model_fwd.hpp" #include "topology.hpp" From 158c9d19df2189b90ce0f31b33fad6f1ad3bfa5f Mon Sep 17 00:00:00 2001 From: Santiago Figueroa Manrique Date: Mon, 11 Aug 2025 10:12:55 +0200 Subject: [PATCH 33/33] minor Signed-off-by: Santiago Figueroa Manrique --- .../include/power_grid_model/job_dispatch.hpp | 1 - .../include/power_grid_model/job_interface.hpp | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp index 772f344cab..6cd8750789 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_dispatch.hpp @@ -9,7 +9,6 @@ #include "main_core/calculation_info.hpp" #include "main_core/update.hpp" -#include #include namespace power_grid_model { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp index 9f8c73c3ce..a8bf5aab69 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/job_interface.hpp @@ -10,6 +10,7 @@ #include "common/common.hpp" #include +#include #include #include @@ -54,8 +55,8 @@ template class JobDispatchInterface { // Protected & defaulted special members — CRTP: only the derived can create/copy/move this base JobDispatchInterface() = default; JobDispatchInterface(const JobDispatchInterface& /*other*/) = default; - JobDispatchInterface(JobDispatchInterface&& /*other*/) = default; - JobDispatchInterface& operator=(const JobDispatchInterface& /*other*/) noexcept = default; + JobDispatchInterface& operator=(const JobDispatchInterface& /*other*/) = default; + JobDispatchInterface(JobDispatchInterface&& /*other*/) noexcept = default; JobDispatchInterface& operator=(JobDispatchInterface&& /*other*/) noexcept = default; ~JobDispatchInterface() = default; };