diff --git a/BaseLib/BoostMP11Utils.h b/BaseLib/BoostMP11Utils.h new file mode 100644 index 00000000000..0b383bfcbeb --- /dev/null +++ b/BaseLib/BoostMP11Utils.h @@ -0,0 +1,30 @@ +/** + * \file + * \copyright + * Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#pragma once + +#include + +namespace boost::mp11 +{ +// Alias to be used together with static_assert to improve possible compile +// error messages. +template +constexpr bool mp_contains_v = mp_contains::value; + +// Alias to be used together with static_assert to improve possible compile +// error messages +template +constexpr bool mp_is_list_v = mp_is_list::value; + +// Alias to be used together with static_assert to improve possible compile +// error messages +template +constexpr bool mp_is_set_v = mp_is_set::value; +} // namespace boost::mp11 diff --git a/ProcessLib/Graph/Apply.h b/ProcessLib/Graph/Apply.h index 8f9562993af..30c264a858a 100644 --- a/ProcessLib/Graph/Apply.h +++ b/ProcessLib/Graph/Apply.h @@ -229,14 +229,14 @@ auto applyImpl(Function&& f, Args&&... args) -> mp_transform; static_assert( - boost::mp11::mp_is_set::value, + mp_is_set_v, "The types of all elements of all passed tuples must be unique."); using FunctionArgumentTypesPlain = typename detail::GetFunctionArgumentTypesPlain::type; static_assert( - boost::mp11::mp_is_set::value, + mp_is_set_v, "The argument types of the function to be called must be unique."); return unpackAndInvoke(FunctionArgumentTypesPlain{}, diff --git a/ProcessLib/Graph/Get.h b/ProcessLib/Graph/Get.h index c8c8d718caa..796fb48ba2d 100644 --- a/ProcessLib/Graph/Get.h +++ b/ProcessLib/Graph/Get.h @@ -11,6 +11,8 @@ #include +#include "BaseLib/BoostMP11Utils.h" + namespace ProcessLib::Graph { namespace detail @@ -43,16 +45,6 @@ struct GetFlattenedTupleTypes using type = boost::mp11::mp_flatten>; }; - -// Alias to be used together with static_assert to improve possible compile -// error messages. -template -constexpr bool mp_contains_v = boost::mp11::mp_contains::value; - -// Alias to be used together with static_assert to improve possible compile -// error messages -template -constexpr bool mp_is_set_v = boost::mp11::mp_is_set::value; } // namespace detail /// Type-based access of an element of any of the passed tuples. @@ -77,10 +69,10 @@ auto& get(Tuples&... ts) mp_transform; static_assert( - detail::mp_is_set_v, + mp_is_set_v, "The types of all elements of all passed tuples must be unique."); - static_assert(detail::mp_contains_v, + static_assert(mp_contains_v, "Type T must be inside any of the passed tuples."); return detail::getImpl(ts...); diff --git a/ProcessLib/Reflection/ReflectionIPData.h b/ProcessLib/Reflection/ReflectionIPData.h index 3b73767d2a7..4db5714a383 100644 --- a/ProcessLib/Reflection/ReflectionIPData.h +++ b/ProcessLib/Reflection/ReflectionIPData.h @@ -12,6 +12,8 @@ #include +#include "BaseLib/BoostMP11Utils.h" +#include "BaseLib/StrongType.h" #include "MathLib/KelvinVector.h" #include "ReflectionData.h" @@ -19,34 +21,6 @@ namespace ProcessLib::Reflection { namespace detail { -template -concept has_reflect = requires { T::reflect(); }; - -template -auto reflect(std::type_identity>) -{ - using namespace boost::mp11; - - // The types Ts... must be unique. Duplicate types are incompatible with the - // concept of "reflected" I/O: they would lead to duplicate names for the - // I/O data. - static_assert(mp_is_set>::value); - - return reflectWithoutName>( - [](auto& tuple_) -> auto& { return std::get(tuple_); }...); -} - -template -auto reflect(std::type_identity) -{ - return T::reflect(); -} - -template -concept is_reflectable = requires { - ProcessLib::Reflection::detail::reflect(std::type_identity{}); -}; - /** * Raw data is data that will be read or written, e.g., double values or Eigen * vectors. @@ -126,6 +100,79 @@ struct NumberOfComponents { }; +template +concept has_reflect = requires +{ + T::reflect(); +}; + +template +auto reflect(std::type_identity>) +{ + using namespace boost::mp11; + + // The types Ts... must be unique. Duplicate types are incompatible with the + // concept of "reflected" I/O: they would lead to duplicate names for the + // I/O data. + static_assert(mp_is_set_v>); + + return reflectWithoutName>( + [](auto& tuple_) -> auto& { return std::get(tuple_); }...); +} + +template +auto reflect(std::type_identity) +{ + return T::reflect(); +} + +template +concept has_ioName = requires(T* t) +{ + ioName(t); +}; + +template +auto reflect(std::type_identity>) +{ + using ST = BaseLib::StrongType; + + auto accessor = [](auto& o) -> auto& + { + return *o; + }; + + // Maybe in the future we might want to lift the following two constraints. + // But beware: that generalization has to be tested thoroughly such that we + // don't accidentally produce I/O data without name and the like. + static_assert( + has_ioName, + /* We use ioName(Tag* tag), because it works with an incomplete type + * Tag, as opposed to ioName(Tag tag), i.e. declaring + * std::string_view ioName(struct SomeTag*); + * is possible, whereas + * std::string_view ioName(struct SomeTag); + * is not. + * This choice makes the code for every ioName() definition rather + * compact. + */ + "For I/O of StrongType you have to define an ioName(Tag* tag) " + "function returning the name used for I/O."); + static_assert( + is_raw_data_v, + "I/O of StrongTypes is supported only for StrongTypes wrapping 'raw " + "data' such as double values, vectors and matrices."); + + return std::tuple{makeReflectionData( + std::string{ioName(static_cast(nullptr))}, std::move(accessor))}; +} + +template +concept is_reflectable = requires +{ + ProcessLib::Reflection::detail::reflect(std::type_identity{}); +}; + /** A function object taking a local assembler as its argument and returning a * std::vector\ of some specific "flattened" integration point * (IP) data. @@ -328,6 +375,13 @@ void forEachReflectedFlattenedIPDataAccessor( Accessor_CurrentLevelFromIPDataVecElement const& accessor_current_level_from_ip_data_vec_element) { + static_assert(boost::mp11::mp_is_list_v, + "The passed reflection data is not a std::tuple."); + static_assert( + std::is_same_v>, + "The passed reflection data is not a std::tuple."); + boost::mp11::tuple_for_each( reflection_data, [&accessor_ip_data_vec_in_loc_asm, @@ -357,12 +411,13 @@ void forEachReflectedFlattenedIPDataAccessor( } else { - static_assert(is_raw_data::value, + static_assert(is_raw_data_v, "The current member is not reflectable, so we " "expect it to be raw data."); constexpr unsigned num_comp = NumberOfComponents::value; + assert(!refl_data.name.empty()); callback(refl_data.name, num_comp, getFlattenedIPDataFromLocAsm( accessor_ip_data_vec_in_loc_asm, @@ -401,7 +456,14 @@ template void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data, Callback const& callback) { - boost::mp11::tuple_for_each( + using namespace boost::mp11; + + static_assert(mp_is_list_v, + "The passed reflection data is not a std::tuple."); + static_assert(std::is_same_v>, + "The passed reflection data is not a std::tuple."); + + tuple_for_each( reflection_data, [&callback]( ReflectionData const& refl_data) @@ -416,13 +478,13 @@ void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data, // AccessorResult must be a std::vector. We // check that, now. - static_assert(boost::mp11::mp_is_list:: - value); // std::vector - // is a list in the Boost MP11 sense static_assert( - std::is_same_v< - AccessorResult, - boost::mp11::mp_rename>, + mp_is_list_v); // std::vector is a list in + // the Boost MP11 sense + static_assert( + std::is_same_v>, "We expect a std::vector, here."); // Now, we know that AccessorResult is std::vector. To be // more specific, AccessorResult is a std::vector and Member @@ -432,7 +494,9 @@ void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data, auto accessor_ip_data_vec_in_loc_asm = [ip_data_vector_accessor = refl_data.accessor](LocAsmIF const& loc_asm) -> auto const& - { return ip_data_vector_accessor(loc_asm); }; + { + return ip_data_vector_accessor(loc_asm); + }; if constexpr (detail::is_reflectable) { @@ -443,13 +507,14 @@ void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data, } else { - static_assert(detail::is_raw_data::value, + static_assert(detail::is_raw_data_v, "The current member is not reflectable, so we " "expect it to be raw data."); constexpr unsigned num_comp = detail::NumberOfComponents::value; + assert(!refl_data.name.empty()); callback(refl_data.name, num_comp, detail::getFlattenedIPDataFromLocAsm( accessor_ip_data_vec_in_loc_asm)); diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h index 54a0d49d9be..75cac833160 100644 --- a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h +++ b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h @@ -809,8 +809,8 @@ void RichardsMechanicsLocalAssembler(variables, x_position, t, dt); - std::get(CD) - .viscosity = mu; + *std::get(CD) = + mu; // Swelling and possibly volumetric strain rate update. updateSwellingStressAndVolumetricStrain( @@ -1141,9 +1141,8 @@ void RichardsMechanicsLocalAssembler>(CD) .Ki; double const mu = - std::get( - CD) - .viscosity; + *std::get( + CD); GlobalDimMatrixType const rho_Ki_over_mu = K_intrinsic * rho_LR / mu; diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.cpp b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.cpp index a56725c47a4..8bceb6e7951 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.cpp +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.cpp @@ -10,8 +10,6 @@ #include "DarcyLaw.h" -#include "MaterialLib/MPL/Utils/FormEigenTensor.h" - namespace ProcessLib::ThermoRichardsMechanics { template @@ -23,10 +21,10 @@ void DarcyLawModel::eval( ThermoOsmosisData const& th_osmosis_data, DarcyLawData& out) const { - out.v_darcy = perm_data.Ki / mu_L_data.viscosity * - (perm_data.k_rel * - (p_cap_data.grad_p_cap + rho_L_data.rho_LR * b_)) + - th_osmosis_data.seepage_velocity_contribution; + *out = perm_data.Ki / mu_L_data() * + (perm_data.k_rel * + (p_cap_data.grad_p_cap + rho_L_data.rho_LR * b_)) + + th_osmosis_data.seepage_velocity_contribution; } template struct DarcyLawModel<2>; diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.h b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.h index b5c09bede41..faab1905057 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.h +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/DarcyLaw.h @@ -10,6 +10,7 @@ #pragma once +#include "BaseLib/StrongType.h" #include "LiquidDensity.h" #include "LiquidViscosity.h" #include "PermeabilityData.h" @@ -19,18 +20,13 @@ namespace ProcessLib::ThermoRichardsMechanics { template -struct DarcyLawData -{ - Eigen::Vector v_darcy; - - static auto reflect() - { - using Self = DarcyLawData; +using DarcyLawData = BaseLib::StrongType, + struct DarcyLawDataTag>; - return ProcessLib::Reflection::reflectWithName("velocity", - &Self::v_darcy); - } -}; +constexpr std::string_view ioName(struct DarcyLawDataTag*) +{ + return "velocity"; +} template struct DarcyLawModel diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/EqP.cpp b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/EqP.cpp index b8d7a09315f..0b79275aebe 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/EqP.cpp +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/EqP.cpp @@ -29,14 +29,14 @@ void EqPModel::eval( { out.M_pu_X_BTI2N = S_L_data.S_L * rho_L_data.rho_LR * biot_data(); - out.K_pp_Laplace = perm_data.k_rel * rho_L_data.rho_LR * perm_data.Ki / - mu_L_data.viscosity; + out.K_pp_Laplace = + perm_data.k_rel * rho_L_data.rho_LR * perm_data.Ki / mu_L_data(); out.J_pp_X_BTI2NT_u_dot_N = -rho_L_data.rho_LR * dS_L_data.dS_L_dp_cap * biot_data(); out.J_pp_dNT_V_N = - perm_data.Ki / mu_L_data.viscosity * + perm_data.Ki / mu_L_data() * (rho_L_data.rho_LR * perm_data.dk_rel_dS_L * dS_L_data.dS_L_dp_cap * (p_cap_data.grad_p_cap + rho_L_data.rho_LR * b_)); diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.cpp b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.cpp index bc4d2a88d92..337df896229 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.cpp +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.cpp @@ -24,9 +24,8 @@ void LiquidViscosityModel::eval( variables.temperature = T_data.T; variables.density = rho_L_data.rho_LR; - out.viscosity = - media_data.liquid.property(MPL::PropertyType::viscosity) - .template value(variables, x_t.x, x_t.t, x_t.dt); + *out = media_data.liquid.property(MPL::PropertyType::viscosity) + .template value(variables, x_t.x, x_t.t, x_t.dt); } template struct LiquidViscosityModel<2>; diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.h b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.h index 6b65e4da3e7..53ab7f941ab 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.h +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/LiquidViscosity.h @@ -11,20 +11,18 @@ #pragma once #include "Base.h" +#include "BaseLib/StrongType.h" #include "LiquidDensity.h" namespace ProcessLib::ThermoRichardsMechanics { -struct LiquidViscosityData -{ - double viscosity; +using LiquidViscosityData = + BaseLib::StrongType; - static auto reflect() - { - return ProcessLib::Reflection::reflectWithName( - "viscosity", &LiquidViscosityData::viscosity); - } -}; +constexpr std::string_view ioName(struct LiquidViscosityDataTag*) +{ + return "viscosity"; +} template struct LiquidViscosityModel diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/TRMHeatStorageAndFlux.cpp b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/TRMHeatStorageAndFlux.cpp index 0f81bea6959..a2e4a8bf984 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/TRMHeatStorageAndFlux.cpp +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveCommon/TRMHeatStorageAndFlux.cpp @@ -63,16 +63,15 @@ void TRMHeatStorageAndFluxModel::eval( // Unit is J / m^2 / s / K. It's not a heat flux, but related. out.advective_heat_flux_contribution_to_K_liquid = - volumetric_heat_capacity_liquid * darcy_data.v_darcy; + volumetric_heat_capacity_liquid * darcy_data(); // // temperature equation, pressure part // out.K_Tp_NT_V_dN = -volumetric_heat_capacity_liquid * perm.k_rel / - mu_L_data.viscosity * - (perm.Ki.transpose() * T_data.grad_T); + mu_L_data() * (perm.Ki.transpose() * T_data.grad_T); out.K_Tp_X_NTN = -volumetric_heat_capacity_liquid * - darcy_data.v_darcy.dot(T_data.grad_T) / perm.k_rel * + darcy_data().dot(T_data.grad_T) / perm.k_rel * perm.dk_rel_dS_L * dS_L_data.dS_L_dp_cap; } diff --git a/Tests/ProcessLib/TestReflectIPData.cpp b/Tests/ProcessLib/TestReflectIPData.cpp index ad6fbe060b6..be5c3e1e611 100644 --- a/Tests/ProcessLib/TestReflectIPData.cpp +++ b/Tests/ProcessLib/TestReflectIPData.cpp @@ -71,10 +71,20 @@ struct Level2b } }; +template +using Kelvin1Data = + BaseLib::StrongType, + struct Kelvin1DataTag>; + +constexpr std::string_view ioName(struct Kelvin1DataTag*) +{ + return "kelvin1"; +} + template struct Level1 { - MathLib::KelvinVector::KelvinVectorType kelvin1; + Kelvin1Data kelvin1; Eigen::Vector vector1; double scalar1; Level2 level2; @@ -83,7 +93,7 @@ struct Level1 static auto reflect() { using namespace ProcessLib::Reflection; - return std::tuple{makeReflectionData("kelvin1", &Level1::kelvin1), + return std::tuple{makeReflectionData(&Level1::kelvin1), makeReflectionData("vector1", &Level1::vector1), makeReflectionData("scalar1", &Level1::scalar1), makeReflectionData(&Level1::level2), @@ -103,6 +113,13 @@ struct Level1b } }; +using ScalarData = BaseLib::StrongType; + +constexpr std::string_view ioName(struct ScalarDataTag*) +{ + return "scalar"; +} + template struct LocAsmIF { @@ -117,7 +134,7 @@ struct LocAsmIF std::size_t numIPs() const { return ip_data_scalar.size(); } - std::vector ip_data_scalar; + std::vector ip_data_scalar; std::vector> ip_data_vector; std::vector> ip_data_kelvin; std::vector> ip_data_level1; @@ -127,7 +144,7 @@ struct LocAsmIF { using namespace ProcessLib::Reflection; return std::tuple{ - makeReflectionData("scalar", &LocAsmIF::ip_data_scalar), + makeReflectionData(&LocAsmIF::ip_data_scalar), makeReflectionData("vector", &LocAsmIF::ip_data_vector), makeReflectionData("kelvin", &LocAsmIF::ip_data_kelvin), makeReflectionData(&LocAsmIF::ip_data_level1), @@ -376,7 +393,7 @@ struct ReferenceData ref.scalar = initScalar( loc_asm, start_value(), [](auto& loc_asm, unsigned const ip) -> auto& { - return loc_asm.ip_data_scalar[ip]; + return *loc_asm.ip_data_scalar[ip]; }, for_read_test); @@ -413,7 +430,7 @@ struct ReferenceData ref.kelvin1 = initKelvin( loc_asm, start_value(), [](auto& loc_asm, unsigned const ip) -> auto& { - return loc_asm.ip_data_level1[ip].kelvin1; + return *loc_asm.ip_data_level1[ip].kelvin1; }, for_read_test);