Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

namespace power_grid_model {

template <class MainModel, typename... ComponentType> class JobAdapter;
template <class MainModel> class JobAdapter;

template <class MainModel, class... ComponentType>
class JobAdapter<MainModel, ComponentList<ComponentType...>>
: public JobInterface<JobAdapter<MainModel, ComponentList<ComponentType...>>> {
template <class MainModel> class JobAdapter : public JobInterface<JobAdapter<MainModel>> {
public:
using ModelType = typename MainModel::ImplType;

JobAdapter(std::reference_wrapper<MainModel> model_reference,
std::reference_wrapper<MainModelOptions const> options)
: model_reference_{model_reference}, options_{options} {
Expand Down Expand Up @@ -88,12 +88,12 @@ class JobAdapter<MainModel, ComponentList<ComponentType...>>
std::reference_wrapper<MainModel> model_reference_;
std::reference_wrapper<MainModelOptions const> options_;

main_core::utils::ComponentFlags<ComponentType...> components_to_update_{};
main_core::update::independence::UpdateIndependence<ComponentType...> update_independence_{};
main_core::utils::ComponentFlags<ComponentType...> independence_flags_{};
std::shared_ptr<main_core::utils::SequenceIdx<ComponentType...>> all_scenarios_sequence_;
typename ModelType::ComponentFlags components_to_update_{};
typename ModelType::UpdateIndependence update_independence_{};
typename ModelType::ComponentFlags independence_flags_{};
std::shared_ptr<typename ModelType::SequenceIdx> all_scenarios_sequence_;
// current_scenario_sequence_cache_ is calculated per scenario, so it is excluded from the constructors.
main_core::utils::SequenceIdx<ComponentType...> current_scenario_sequence_cache_{};
typename ModelType::SequenceIdx current_scenario_sequence_cache_{};

Logger* log_{nullptr};

Expand Down Expand Up @@ -124,17 +124,17 @@ class JobAdapter<MainModel, ComponentList<ComponentType...>>
// cache component update order where possible.
// the order for a cacheable (independent) component by definition is the same across all scenarios
components_to_update_ = model_reference_.get().get_components_to_update(update_data);
update_independence_ = main_core::update::independence::check_update_independence<ComponentType...>(
update_independence_ = main_core::update::independence::check_update_independence<ModelType>(
model_reference_.get().state(), update_data);
std::ranges::transform(update_independence_, independence_flags_.begin(),
[](auto const& comp) { return comp.is_independent(); });
all_scenarios_sequence_ = std::make_shared<main_core::utils::SequenceIdx<ComponentType...>>(
main_core::update::get_all_sequence_idx_map<ComponentType...>(
all_scenarios_sequence_ =
std::make_shared<typename ModelType::SequenceIdx>(main_core::update::get_all_sequence_idx_map<ModelType>(
model_reference_.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<ComponentType...>(
current_scenario_sequence_cache_ = main_core::update::get_all_sequence_idx_map<ModelType>(
model_reference_.get().state(), update_data, scenario_idx, components_to_update_, update_independence_,
true);
auto const current_scenario_sequence = get_current_scenario_sequence_view_();
Expand All @@ -148,8 +148,8 @@ class JobAdapter<MainModel, ComponentList<ComponentType...>>
}

auto get_current_scenario_sequence_view_() const {
return main_core::utils::run_functor_with_all_types_return_array<ComponentType...>([this]<typename CT>() {
constexpr auto comp_idx = main_core::utils::index_of_component<CT, ComponentType...>;
return ModelType::run_functor_with_all_component_types_return_array([this]<typename CT>() {
constexpr auto comp_idx = ModelType::template index_of_component<CT>;
if (std::get<comp_idx>(independence_flags_)) {
return std::span<Idx2D const>{std::get<comp_idx>(*all_scenarios_sequence_)};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@

#include "../all_components.hpp"
#include "../container.hpp"
#include "state.hpp"

#include <array>
#include <vector>

namespace power_grid_model::main_core::utils {

namespace detail {

template <typename Tuple, class Functor, std::size_t... Indices>
constexpr void run_functor_with_tuple_index_return_void(Functor functor, std::index_sequence<Indices...> /*unused*/) {
(functor.template operator()<std::tuple_element_t<Indices, Tuple>>(), ...);
}

} // namespace detail

constexpr Idx invalid_index{-1};

/////////////////// To remove ///////////////////
Copy link
Member Author

@nitbharambe nitbharambe Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of these utils with ComponentTypes... is for now (and mostly in future) limited only to ComponentTypes. So nice to just move them inside.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These would be removed in final stage after all usages are cleared. which would be after #1119


template <class... ComponentTypes> constexpr size_t n_types = sizeof...(ComponentTypes);
template <class CompType, class... ComponentTypes>
constexpr size_t index_of_component = container_impl::get_cls_pos_v<CompType, ComponentTypes...>;
Expand All @@ -28,5 +39,11 @@ template <class... Types, class Functor> constexpr void run_functor_with_all_typ
template <class... Types, class Functor> constexpr auto run_functor_with_all_types_return_array(Functor functor) {
return std::array { functor.template operator()<Types>()... };
}
/////////////////// To remove ///////////////////

template <typename Tuple, class Functor> constexpr void run_functor_with_tuple_return_void(Functor functor) {
detail::run_functor_with_tuple_index_return_void<Tuple>(functor,
std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}

} // namespace power_grid_model::main_core::utils
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
//
// SPDX-License-Identifier: MPL-2.0

#pragma once

#include "../all_components.hpp"
#include "../container.hpp"
#include "state.hpp"
#include "update.hpp"

#include <array>
#include <vector>
namespace power_grid_model::main_core {

namespace detail {

template <typename Tuple> struct tuple_type_identities_to_tuple_types;

template <typename... Ts> struct tuple_type_identities_to_tuple_types<std::tuple<std::type_identity<Ts>...>> {
using type = std::tuple<Ts...>;
};

template <typename Tuple>
using tuple_type_identities_to_tuple_types_t = typename tuple_type_identities_to_tuple_types<Tuple>::type;

template <typename... Types, typename... SelectTypes>
constexpr auto filter_tuple_types(std::tuple<std::type_identity<Types>...> /*unused*/,
std::tuple<std::type_identity<SelectTypes>...> /*unused*/) {
constexpr auto sub_type_in_type = []<typename T>() { return (std::is_same_v<T, SelectTypes> || ...); };

return std::tuple_cat(std::conditional_t<sub_type_in_type.template operator()<Types>(),
std::tuple<std::type_identity<Types>>, std::tuple<>>{}...);
}

} // namespace detail

template <class T, class U> struct MainModelType;

// TODO: discussion on checking dependent types can also be done here.
template <class... ExtraRetrievableType, class... ComponentType>
struct MainModelType<ExtraRetrievableTypes<ExtraRetrievableType...>, ComponentList<ComponentType...>> {

using ComponentContainer = Container<ExtraRetrievableTypes<ExtraRetrievableType...>, ComponentType...>;
using MainModelState = main_core::MainModelState<ComponentContainer>;
using ComponentTypesTuple = std::tuple<ComponentType...>;

static constexpr size_t n_types = sizeof...(ComponentType);
// TODO Should not have to go via container_impl.
template <class CompType>
static constexpr size_t index_of_component = container_impl::get_cls_pos_v<CompType, ComponentType...>;

private:
static constexpr auto all_types_tuple_v_ =
std::tuple<std::type_identity<ComponentType>..., std::type_identity<ExtraRetrievableType>...>{};
// TODO: Would making a unique be necessary? We have Node mentioned as a ExtraRetrievableType and ComponentType so
// summing up is possible but maybe not appropriate. Would it be better to handle them both separately? using

static constexpr auto topology_types_tuple_v_ =
std::tuple<std::type_identity<Node>, std::type_identity<Branch>, std::type_identity<Branch3>,
std::type_identity<Source>, std::type_identity<Shunt>, std::type_identity<GenericLoadGen>,
std::type_identity<GenericVoltageSensor>, std::type_identity<GenericPowerSensor>,
std::type_identity<GenericCurrentSensor>, std::type_identity<Regulator>>{};

static constexpr auto topology_connection_types_tuple_v_ =
std::tuple<std::type_identity<Branch>, std::type_identity<Branch3>, std::type_identity<Source>>{};

public:
using TopologyTypesTuple = detail::tuple_type_identities_to_tuple_types_t<decltype(detail::filter_tuple_types(
topology_types_tuple_v_, all_types_tuple_v_))>;
using TopologyConnectionTypesTuple =
detail::tuple_type_identities_to_tuple_types_t<decltype(detail::filter_tuple_types(
topology_connection_types_tuple_v_, all_types_tuple_v_))>;

// Update related types
using OwnedUpdateDataset = std::tuple<std::vector<typename ComponentType::UpdateType>...>;
using SequenceIdxView = std::array<std::span<Idx2D const>, n_types>;
using UpdateIndependence = std::array<main_core::update::independence::UpdateCompProperties, n_types>;
using SequenceIdx = std::array<std::vector<Idx2D>, n_types>;
using SequenceIdxRefWrappers = std::array<std::reference_wrapper<std::vector<Idx2D> const>, n_types>;
using ComponentFlags = std::array<bool, n_types>;

// Clean these 2. They are unused
static constexpr auto branch_param_in_seq_map =
std::array{index_of_component<Line>, index_of_component<Link>, index_of_component<Transformer>};
static constexpr auto shunt_param_in_seq_map = std::array{index_of_component<Shunt>};

template <class Functor> static constexpr void run_functor_with_all_component_types_return_void(Functor functor) {
(functor.template operator()<ComponentType>(), ...);
}
template <class Functor> static constexpr auto run_functor_with_all_component_types_return_array(Functor functor) {
return std::array { functor.template operator()<ComponentType>()... };
}
};

} // namespace power_grid_model::main_core
Original file line number Diff line number Diff line change
Expand Up @@ -207,31 +207,29 @@ constexpr void register_connections_components(ComponentContainer const& compone

} // namespace detail

template <typename ComponentContainer>
requires common::component_container_c<ComponentContainer, Branch, Branch3, Source, Shunt, GenericLoadGen,
GenericVoltageSensor, GenericPowerSensor, GenericCurrentSensor, Regulator>
ComponentTopology construct_topology(ComponentContainer const& components) {
template <typename ModelType>
requires common::component_container_c<typename ModelType::ComponentContainer, Branch, Branch3, Source, Shunt,
GenericLoadGen, GenericVoltageSensor, GenericPowerSensor,
GenericCurrentSensor, Regulator>
ComponentTopology construct_topology(typename ModelType::ComponentContainer const& components) {
ComponentTopology comp_topo;
detail::register_topology_components<Node>(components, comp_topo);
detail::register_topology_components<Branch>(components, comp_topo);
detail::register_topology_components<Branch3>(components, comp_topo);
detail::register_topology_components<Source>(components, comp_topo);
detail::register_topology_components<Shunt>(components, comp_topo);
detail::register_topology_components<GenericLoadGen>(components, comp_topo);
detail::register_topology_components<GenericVoltageSensor>(components, comp_topo);
detail::register_topology_components<GenericPowerSensor>(components, comp_topo);
detail::register_topology_components<GenericCurrentSensor>(components, comp_topo);
detail::register_topology_components<Regulator>(components, comp_topo);
using TopologyTypesTuple = typename ModelType::TopologyTypesTuple;
main_core::utils::run_functor_with_tuple_return_void<TopologyTypesTuple>(
[&components, &comp_topo]<typename CompType>() {
detail::register_topology_components<CompType>(components, comp_topo);
});
return comp_topo;
}

template <typename ComponentContainer>
requires common::component_container_c<ComponentContainer, Branch, Branch3, Source>
ComponentConnections construct_components_connections(ComponentContainer const& components) {
template <typename ModelType>
requires common::component_container_c<typename ModelType::ComponentContainer, Branch, Branch3, Source>
ComponentConnections construct_components_connections(typename ModelType::ComponentContainer const& components) {
ComponentConnections comp_conn;
detail::register_connections_components<Branch>(components, comp_conn);
detail::register_connections_components<Branch3>(components, comp_conn);
detail::register_connections_components<Source>(components, comp_conn);
using TopologyConnectionTypesTuple = typename ModelType::TopologyConnectionTypesTuple;
main_core::utils::run_functor_with_tuple_return_void<TopologyConnectionTypesTuple>(
[&components, &comp_conn]<typename CompType>() {
detail::register_connections_components<CompType>(components, comp_conn);
});
return comp_conn;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ template <typename T> bool check_id_na(T const& obj) {
} // namespace detail

namespace independence {

struct UpdateCompProperties {
bool has_any_elements{false}; // whether the component has any elements in the update data
bool ids_all_na{false}; // whether all ids are all NA
Expand Down Expand Up @@ -127,9 +128,6 @@ UpdateCompProperties check_component_independence(ConstDataset const& update_dat
return properties;
}

template <class... ComponentTypes>
using UpdateIndependence = std::array<UpdateCompProperties, utils::n_types<ComponentTypes...>>;

inline void validate_update_data_independence(UpdateCompProperties const& comp, std::string const& comp_name) {
if (comp.is_empty_component()) {
return; // empty dataset is still supported
Expand All @@ -150,14 +148,13 @@ inline void validate_update_data_independence(UpdateCompProperties const& comp,
}
}

template <class... ComponentTypes, class ComponentContainer>
UpdateIndependence<ComponentTypes...> check_update_independence(MainModelState<ComponentContainer> const& state,
ConstDataset const& update_data) {
return utils::run_functor_with_all_types_return_array<ComponentTypes...>(
[&state, &update_data]<typename CompType>() {
auto const n_component = state.components.template size<CompType>();
return check_component_independence<CompType>(update_data, n_component);
});
template <typename ModelType>
typename ModelType::UpdateIndependence check_update_independence(typename ModelType::MainModelState const& state,
ConstDataset const& update_data) {
return ModelType::run_functor_with_all_component_types_return_array([&state, &update_data]<typename CompType>() {
auto const n_component = state.components.template size<CompType>();
return check_component_independence<CompType>(update_data, n_component);
});
}

} // namespace independence
Expand Down Expand Up @@ -214,22 +211,21 @@ std::vector<Idx2D> get_component_sequence(MainModelState<ComponentContainer> con
}
} // namespace detail

template <class... ComponentTypes, class ComponentContainer>
utils::SequenceIdx<ComponentTypes...>
get_all_sequence_idx_map(MainModelState<ComponentContainer> const& state, ConstDataset const& update_data,
Idx scenario_idx, utils::ComponentFlags<ComponentTypes...> const& components_to_store,
independence::UpdateIndependence<ComponentTypes...> const& independence, bool cached) {
return utils::run_functor_with_all_types_return_array<ComponentTypes...>(
template <class ModelType>
typename ModelType::SequenceIdx
get_all_sequence_idx_map(typename ModelType::MainModelState const& state, ConstDataset const& update_data,
Idx scenario_idx, typename ModelType::ComponentFlags const& components_to_store,
typename ModelType::UpdateIndependence const& independence, bool cached) {
return ModelType::run_functor_with_all_component_types_return_array(
[&state, &update_data, scenario_idx, &components_to_store, &independence, cached]<typename CompType>() {
auto const component_properties =
std::get<utils::index_of_component<CompType, ComponentTypes...>>(independence);
auto const component_properties = std::get<ModelType::template index_of_component<CompType>>(independence);
// The sequence for the independent components is cached (true). For the remaining components, the sequence
// cannot be cached (false), so the independence flags are inverted to not return an empty sequence when
// this is the case.

if (bool const component_independence = cached != component_properties.is_independent();
!component_independence ||
!std::get<utils::index_of_component<CompType, ComponentTypes...>>(components_to_store)) {
!std::get<ModelType::template index_of_component<CompType>>(components_to_store)) {
return std::vector<Idx2D>{};
}
independence::validate_update_data_independence(component_properties, CompType::name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class MainModel {
BatchParameter calculate(Options const& options, MutableDataset const& result_data,
ConstDataset const& update_data) {
info_.clear();
JobAdapter<Impl, AllComponents> adapter{std::ref(impl()), std::ref(options)};
JobAdapter<Impl> adapter{std::ref(impl()), std::ref(options)};
return JobDispatch::batch_calculation(adapter, result_data, update_data, options.threading, info_);
}

Expand Down
Loading
Loading