Skip to content

[Core] Making Variable and VariableData constexpr#14260

Open
sunethwarna wants to merge 30 commits intomasterfrom
core/make_variable_constexpr
Open

[Core] Making Variable and VariableData constexpr#14260
sunethwarna wants to merge 30 commits intomasterfrom
core/make_variable_constexpr

Conversation

@sunethwarna
Copy link
Copy Markdown
Member

@sunethwarna sunethwarna commented Mar 6, 2026

📝 Description
As in the title, this PR tries to make the Variable and VariableData constexpr. One advantage is that we can now use switch jump table optimizations with variables.

This makes Variable::mZero static, which, anyway, was always default-initialized. No custom zero definitions were found anywhere in Kratos [ Check #14253 ].

Closes #14253

Eg:

const auto& func_variable = [](const Variable<double>& rVariable) -> int {
switch (rVariable.Key()) {
case PRESSURE.Key(): return 1;
case DENSITY.Key(): return 2;
default: return 3;
}
};

or
const auto& func_variable_data = [](const VariableData& rVariableData) -> int {
switch (rVariableData.Key()) {
case VELOCITY.Key(): return 1;
case ACCELERATION.Key(): return 2;
default: return 3;
}
};

Lets see whether what problems the CI gives.

🆕 Changelog

  • Made all the uses of Variable and VariableData to be const correct.
  • Made Variable::mZero static and default initialized to zero.
  • Made the Variable and VariableData constexpr
  • Added a unit test with the switch

@roigcarlo
Copy link
Copy Markdown
Member

Took a first look and unless I missed something this looks fine. I focused on checking that moving from external to static inline kept the functionality unchanged. This also improves the safety of the resulting code as it delegates the responsibility of merging the definitions of the variable to the compiler, and not to the runtime.

gj @sunethwarna !!

@sunethwarna sunethwarna marked this pull request as ready for review March 6, 2026 09:59
@sunethwarna sunethwarna requested review from a team as code owners March 6, 2026 09:59
Copy link
Copy Markdown
Member

@loumalouomega loumalouomega left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Copy Markdown
Contributor

@avdg81 avdg81 left a comment

Choose a reason for hiding this comment

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

On behalf of @KratosMultiphysics/geomechanics, we're okay with the changes proposed for the GeoMechanicsApplication 👍

Copy link
Copy Markdown
Member

@RiccardoRossi RiccardoRossi left a comment

Choose a reason for hiding this comment

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

@pooyan-dadvand is taking this over for a detailed review and approval

const int neigh_color = *(neighbor_colors_iterator++);
array_1d<double,3> dist = cell_center - rConditionCenter;
double dist_modulus = norm_2(dist);
array_1d<double,3> unit_dist;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why this change is needed?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It is because, this variable may be uninitialized because of the following if condition.

https://github.com/KratosMultiphysics/Kratos/blob/master/kratos%2Fmodeler%2Foperation%2Ffind_contacts_in_skin_model_part.cpp#L180-L183

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

unrelated then?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

related, since this PR is triggering the warning.... [For some reason it was not triggered earlier, but the warning makes sense]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

related, since this PR is triggering the warning.... [For some reason it was not triggered earlier, but the warning makes sense]

const VariableType* pTimeDerivativeVariable = nullptr
)
: VariableData(NewName, sizeof(TDataType)),
mZero(Zero),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the problem is that ublas does not allow constexpr assignement?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not for the types which are dynamic.... Like Vector and Matrix.

// Application includes
#include "includes/variables.h"
#include "includes/kratos_flags.h"
#include "includes/cfd_variables.h"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this needed?

Copy link
Copy Markdown
Member Author

@sunethwarna sunethwarna Mar 9, 2026

Choose a reason for hiding this comment

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

Yes, the FACTIONAL_STEP variable was defined both in variables.h and cfd_variables.h... since we now doing inline constexpr, there can only be one definition in one TU. So I removed the definition of the variable from variables.h. so now, this element uses it, so I had to include it.

Copy link
Copy Markdown
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 an advantage! Nevertheless, this leads me to a very important question:

What about having the same variable in two different application?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the nice thing. If the variable is in the same TU, then, it will have the same memory location, key (given the name is the same) and the name. But if they are in different TU, they will have different memory location but with the same key (as long as the name is the same) and the key same... So, now no problems in redefining the variable in multiple applications or TUs.... :)

This is the reason why i put in the pybind the py::eq and __hash__ function definitions. earlier it was using the memory locations to check for equality and hashing in python, now it uses the var key. Which i think is better and proper.

Copy link
Copy Markdown
Member

@pooyan-dadvand pooyan-dadvand left a comment

Choose a reason for hiding this comment

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

While I support the idea behind this PR, I am not sure how it affects the variables defined in different apps. Is it possible to add test for that?

KRATOS_DEFINE_APPLICATION_VARIABLE( MPM_APPLICATION, double, MP_KINETIC_ENERGY )
KRATOS_DEFINE_APPLICATION_VARIABLE( MPM_APPLICATION, double, MP_STRAIN_ENERGY )
KRATOS_DEFINE_APPLICATION_VARIABLE( MPM_APPLICATION, double, MP_TOTAL_ENERGY )
KRATOS_DEFINE_APPLICATION_VARIABLE( MPM_APPLICATION, double, MP_TEMPERATURE)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this related to this PR?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yes, this was a redeclaration of a variable defined in line 45

KRATOS_DEFINE_APPLICATION_VARIABLE(OPTIMIZATION_APPLICATION, double, D_MAX_STRESS_D_PT);
KRATOS_DEFINE_APPLICATION_VARIABLE(OPTIMIZATION_APPLICATION, double, D_MAX_STRESS_D_CT);
KRATOS_DEFINE_APPLICATION_VARIABLE(OPTIMIZATION_APPLICATION, double, D_MAX_STRESS_D_PD);
KRATOS_DEFINE_APPLICATION_VARIABLE(OPTIMIZATION_APPLICATION, double, D_MAX_STRESS_D_CD);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this related to this PR?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ok, a short summary

KRATOS_DEFINE_APPLICATION_VARIABLE used to declare a variable. Now it actually defines one.

What you're seeing here are all variables that have duplicate declarations, which have now become duplicate definitions, which is of course an error.


KRATOS_CREATE_VARIABLE_WITH_TIME_DERIVATIVE(double, TURBULENT_ENERGY_DISSIPATION_RATE_2, RANS_AUXILIARY_VARIABLE_2)
KRATOS_CREATE_VARIABLE_WITH_TIME_DERIVATIVE(double, TURBULENT_ENERGY_DISSIPATION_RATE, TURBULENT_ENERGY_DISSIPATION_RATE_2)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated changes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

explained in the above comment.

// k-omega turbulence modelling specific additional variables
KRATOS_CREATE_VARIABLE_WITH_TIME_DERIVATIVE(double, TURBULENT_SPECIFIC_ENERGY_DISSIPATION_RATE_2, RANS_AUXILIARY_VARIABLE_2)
KRATOS_CREATE_VARIABLE_WITH_TIME_DERIVATIVE(double, TURBULENT_SPECIFIC_ENERGY_DISSIPATION_RATE, TURBULENT_SPECIFIC_ENERGY_DISSIPATION_RATE_2)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated changes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

explained in the above comment

KRATOS_DEFINE_APPLICATION_VARIABLE( RANS_APPLICATION, double, TURBULENT_KINETIC_ENERGY )
KRATOS_DEFINE_APPLICATION_VARIABLE( RANS_APPLICATION, double, TURBULENT_ENERGY_DISSIPATION_RATE )
KRATOS_DEFINE_APPLICATION_VARIABLE( RANS_APPLICATION, double, TURBULENT_KINETIC_ENERGY_RATE )
KRATOS_DEFINE_APPLICATION_VARIABLE( RANS_APPLICATION, double, TURBULENT_ENERGY_DISSIPATION_RATE_2 )
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

xplained in the above comment

KRATOS_DEFINE_3D_VARIABLE_WITH_COMPONENTS( REACTION_MOMENT )
KRATOS_DEFINE_3D_VARIABLE_WITH_COMPONENTS( ANGULAR_VELOCITY )
KRATOS_DEFINE_3D_VARIABLE_WITH_COMPONENTS( ANGULAR_ACCELERATION )
KRATOS_DEFINE_3D_VARIABLE_WITH_COMPONENTS_WITH_TIME_DERIVATIVE(ANGULAR_VELOCITY, ANGULAR_ACCELERATION)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Cosmetic

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

not a cosmetic change. Ealier it was possible to define a variable with extern and pass the time derivatives with the proper definition with another macro. Now since it is inline static constexpr, the whole definition and declaration should be in once place [In my opinion it is cleaner). Therefore, when you want to define a var with time derivatives, you should do it at once, hence the above change.

const int neigh_color = *(neighbor_colors_iterator++);
array_1d<double,3> dist = cell_center - rConditionCenter;
double dist_modulus = norm_2(dist);
array_1d<double,3> unit_dist;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

unrelated then?

.def("GetComponentIndex", &VariableData::GetComponentIndex)
.def("IsComponent", &VariableData::IsComponent)
.def("__str__", PrintObject<VariableData>)
.def("__hash__", &VariableData::Key)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Intersting!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The both py::eq and __hash__ was implemented to allow comparing variables correctly even if they come from different TUs (different applications). Earlier, the memory location was used for hashing [ luckily, the unit there was one unit test, and it was comparing the memory locations for hashing ]. Now this one make sure that we always comapre and hash based on the var key.

Comment thread kratos/sources/variables.cpp
Comment thread kratos/sources/variables.cpp Outdated
@sunethwarna
Copy link
Copy Markdown
Member Author

sunethwarna commented Mar 17, 2026

While I support the idea behind this PR, I am not sure how it affects the variables defined in different apps. Is it possible to add test for that?

So the nice thing about the change is, now all the variables which have the same name will have the same key and same memory location if they are in the same TU. But if they are redefined in a different TU again such as in an application, they will have a different memory location, but the key and the name will be the same. In C++ we have the operator== defined for VariableData which is used by Variable as well. So no problem in that with different TUs defining the same variable. For python have added following to mimic the same behavior.

    .def("__hash__", &VariableData::Key)
    .def(py::self == py::self)
    .def(py::self != py::self)

A unit test is added to check the intended behavior in a scenario where the same variable is deifned from multiple TUs (or multiple apps)

We have addressed all of your comments @pooyan-dadvand . Could you please have a look again? Thanks... :D

Comment thread kratos/containers/variable_data.h Outdated
Comment thread kratos/containers/variable.h Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 👀 Next meeting TODO

Development

Successfully merging this pull request may close these issues.

7 participants