Skip to content

Conversation

@figueroa1395
Copy link
Member

@figueroa1395 figueroa1395 commented Oct 24, 2025

This PR is aimed to remove all the stuff related to preparing the calculation/solvers out of the main model. This PR should be an enabler to unit test the touched logic more easily, keep trimming the main model, and get it ready to remove everything related to the calculation logic in a followup.

Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
@figueroa1395 figueroa1395 self-assigned this Oct 24, 2025
@figueroa1395 figueroa1395 added improvement Improvement on internal implementation do-not-merge This should not be merged labels Oct 24, 2025
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Copy link
Member

@mgovers mgovers left a comment

Choose a reason for hiding this comment

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

This is a global review, not an in-depth one. Awesome cleanup!

namespace power_grid_model {
struct SolverPreparationContext {
main_core::MathState math_state;
Idx n_math_solvers{0};
Copy link
Member

Choose a reason for hiding this comment

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

Is it required to keep n_math_solvers?
Is it ever not equivalent to math_state.topology.size()?

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed it (in 4f0d589) in favor of a helper function that does the calling from state.math_topology.size() indeed. It should be fine and

assert(n_math_solvers == static_cast<Idx>(main_core::get_y_bus<sym>(solver_context.math_state).size()));|

still remains as a sanity check.

Let me know what you think.

Copy link
Member

Choose a reason for hiding this comment

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

i think this is indeed legacy from the era when we would re-use a math solver when our amount of connected components in the grid remained the same, even when our topology changed (i.e. we would reuse preallocated math solver memory, but it doesn't make sense because the elephant in the room is not the math solver but the y bus structure/topology. therefore, we changed that)

as long as our cache invalidation works correctly, with the current state of the code base, that should work as intended

Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
@figueroa1395 figueroa1395 removed the do-not-merge This should not be merged label Oct 29, 2025
@figueroa1395 figueroa1395 marked this pull request as ready for review October 29, 2025 08:54
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
@sonarqubecloud
Copy link

Comment on lines +26 to +35
struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
typename ModelType::SequenceIdx parameter_changed_components{};
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
};
IsParameterUpToDateHelper is_parameter_up_to_date{};
};
Copy link
Member

Choose a reason for hiding this comment

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

although not strictly necessary, for the sake of readability:

Suggested change
struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
typename ModelType::SequenceIdx parameter_changed_components{};
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
};
IsParameterUpToDateHelper is_parameter_up_to_date{};
};
struct StatusCheckingContext {
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
};
using SequenceIdx = typename ModelType::SequenceIdx;
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
SequenceIdx parameter_changed_components{};
IsParameterUpToDateHelper is_parameter_up_to_date{};
};

alternatively, if you really want to do it inline, you can also do

Suggested change
struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
typename ModelType::SequenceIdx parameter_changed_components{};
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
};
IsParameterUpToDateHelper is_parameter_up_to_date{};
};
struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
typename ModelType::SequenceIdx parameter_changed_components{};
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
} is_parameter_up_to_date{};
};

but i'm not a fan of that personally

Copy link
Member

@mgovers mgovers Nov 17, 2025

Choose a reason for hiding this comment

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

definitively out of scope but i have also been thinking about doing a class that can only invalidate, never validate (which plain bool flags can), that is, something along the lines of

Suggested change
struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
typename ModelType::SequenceIdx parameter_changed_components{};
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
};
IsParameterUpToDateHelper is_parameter_up_to_date{};
};
class StatusCheckingContext {
public:
struct invalid_t {};
struct valid_t {};
static constexpr invalid_t invalid_tag{};
static constexpr valid_t valid_tag{};
StatusCheckingContext() = default;
StatusCheckingContext(invalid_t /*tag*/): StatusCheckingContext() {}
StatusCheckingContext(valid_t /*tag*/):
is_topology_up_to_date_{true},
is_parameter_up_to_date_{{.sym=true, .asym=true}},
last_updated_calculation_symmetry_mode_{true} {}
void set_topo_invalid() {
is_topology_up_to_date_= false;
set_parameter_invalid_<symmetric_t>();
set_parameter_invalid_<asymmetric_t>();
}
template <symmetry_c sym> void set_parameter_invalid() {
if constexpr (is_symmetric<sym>) {
is_parameter_up_to_date.sym = false;
} else {
is_parameter_up_to_date.asym = false;
}
}
bool is_topo_up_to_date() { return is_topology_up_to_date_; }
template <symmetry_c sym>
private:
struct IsParameterUpToDateHelper {
bool sym{false};
bool asym{false};
};
bool is_topology_up_to_date_{false};
IsParameterUpToDateHelper is_parameter_up_to_date_{};
bool last_updated_calculation_symmetry_mode_{false};
typename ModelType::SequenceIdx parameter_changed_components_{}; // we need to figure out what to do with this.
};

while it looks like overkill, it ensures the invariant in which any invalidated topology will always also invalidate the parameters. It cannot be accidentally forgotten.

the only way to reset is to create a new object, e.g.

StatusCheckingContext validity; // all invalid / default
foo(validity);

update(validity);
validity = StatusCheckingContext{StatusCheckingContext::valid}; // all valid

bar_invalidates_params(validity); // now, topo is still up to date

update(validity); // now, we make the bunch valid again
validity = StatusCheckingContext{StatusCheckingContext::valid}; // tada

alternatively, we can also create either an enum or extend the set of tags to reflect this stuff

struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
typename ModelType::SequenceIdx parameter_changed_components{};
Copy link
Member

@mgovers mgovers Nov 17, 2025

Choose a reason for hiding this comment

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

it feels a little bit confusing to me that the status and the cache are part of the same struct called StatusCheckingContext.

Maybe the name is just not clear enough. Maybe something along the lines of CacheStatus or CacheValidity?

That said, maybe the confusing part is not the name of the type but the fact that one thing tells something about the cache validity while the other about the context in which it is valid? maybe that means that they shouldn't be part of the same class in the first place?

requires(main_core::is_main_model_type_v<ModelType>)
struct StatusCheckingContext {
bool is_topology_up_to_date{false};
bool last_updated_calculation_symmetry_mode{false};
Copy link
Member

Choose a reason for hiding this comment

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

i don't like this name with the fact that it's a bool. Maybe you can make it an enum? or otherwise rename to something along the lines of last_updated_was_symmetric?

this is basically an invariant, namely a mapping of the previous calculation type to the next. maybe you can solve it using a setter (instead of doing the checking at the user side), e.g.

class StatusCheckingContext {
    template <symmetry_tag sym> set_most_recent_calculation_symmetry() {
        last_updated_calculation_was_symmetric_ = is_symmetric_v<sym>;
    }
    template <symmetry_tag sym> is_same_calculation_symmetry() {
        return last_updated_calculation_was_symmetric_ == is_symmetric_v<sym>;
    }
};

You can also use IsParameterUpToDateHelper for caching (although slightly less memory efficient, but if we really want to go down that direction, we also don't need a separate bool for topology; we could just use bitflags or enums

note that using std::variant would be overkill.

} // namespace detail

template <symmetry_tag sym, class ModelType>
bool& is_parameter_up_to_date(
Copy link
Member

Choose a reason for hiding this comment

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

i prefer to make this a member function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improvement on internal implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants