diff --git a/MaterialLib/SolidModels/MFront/MFront.h b/MaterialLib/SolidModels/MFront/MFront.h index 6be9fd61f9e405f8f51049514889ac8add168568..130126809c49314742ac0939dee3307313af2660 100644 --- a/MaterialLib/SolidModels/MFront/MFront.h +++ b/MaterialLib/SolidModels/MFront/MFront.h @@ -22,13 +22,13 @@ template <int DisplacementDim> class MFront : private MFrontGeneric<DisplacementDim, boost::mp11::mp_list<Strain>, boost::mp11::mp_list<Stress>, - boost::mp11::mp_list<>>, + boost::mp11::mp_list<Temperature>>, public MechanicsBase<DisplacementDim> { using Base = MFrontGeneric<DisplacementDim, boost::mp11::mp_list<Strain>, boost::mp11::mp_list<Stress>, - boost::mp11::mp_list<>>; + boost::mp11::mp_list<Temperature>>; using KelvinVector = typename Base::KelvinVector; using KelvinMatrix = typename Base::KelvinMatrix; @@ -118,11 +118,12 @@ public: } private: - OGSMFrontTangentOperatorBlocksView<DisplacementDim, - boost::mp11::mp_list<Strain>, - boost::mp11::mp_list<Stress>, - boost::mp11::mp_list<>> - blocks_view_{this->createTangentOperatorBlocksView()}; + OGSMFrontTangentOperatorBlocksView< + DisplacementDim, + ForcesGradsCombinations<boost::mp11::mp_list<Strain>, + boost::mp11::mp_list<Stress>, + boost::mp11::mp_list<Temperature>>::type> + blocks_view_ = this->createTangentOperatorBlocksView(); }; extern template class MFront<2>; diff --git a/MaterialLib/SolidModels/MFront/MFrontGeneric.h b/MaterialLib/SolidModels/MFront/MFrontGeneric.h index a6003719c622c838b64b49227e043b12c6dc3122..10201f6c374a8c25e396b470231d6f448daa48b3 100644 --- a/MaterialLib/SolidModels/MFront/MFrontGeneric.h +++ b/MaterialLib/SolidModels/MFront/MFrontGeneric.h @@ -20,6 +20,7 @@ #include "ParameterLib/Parameter.h" #include "TangentOperatorBlocksView.h" #include "ThermodynamicForcesView.h" +#include "Variable.h" namespace MaterialLib::Solids::MFront { @@ -302,6 +303,10 @@ public: auto const hypothesis = _behaviour.hypothesis; + static_assert( + std::is_same_v<ExtStateVars, boost::mp11::mp_list<Temperature>>, + "Temperature is the only allowed external state variable."); + if (!_behaviour.esvs.empty()) { if (_behaviour.esvs[0].name != "Temperature") @@ -596,16 +601,14 @@ public: return internal_variables; } - OGSMFrontTangentOperatorBlocksView<DisplacementDim, - Gradients, - TDynForces, - ExtStateVars> + template <typename ForcesGradsCombinations = + typename ForcesGradsCombinations<Gradients, TDynForces, + ExtStateVars>::type> + OGSMFrontTangentOperatorBlocksView<DisplacementDim, ForcesGradsCombinations> createTangentOperatorBlocksView() const { return OGSMFrontTangentOperatorBlocksView<DisplacementDim, - Gradients, - TDynForces, - ExtStateVars>{ + ForcesGradsCombinations>{ _behaviour.to_blocks}; } diff --git a/MaterialLib/SolidModels/MFront/TangentOperatorBlocksView.h b/MaterialLib/SolidModels/MFront/TangentOperatorBlocksView.h index f005ffeb4afcf1b1a77a58d68f5a1daac468f7e9..af9f3eec1bac880179270613030276c217b53b1d 100644 --- a/MaterialLib/SolidModels/MFront/TangentOperatorBlocksView.h +++ b/MaterialLib/SolidModels/MFront/TangentOperatorBlocksView.h @@ -12,6 +12,10 @@ #include <MGIS/Behaviour/Variable.hxx> #include <boost/mp11.hpp> +#include <range/v3/view/enumerate.hpp> +#include <range/v3/view/filter.hpp> +#include <range/v3/view/map.hpp> +#include <range/v3/view/zip.hpp> #include "BaseLib/cpp23.h" #include "MathLib/KelvinVector.h" @@ -34,10 +38,10 @@ struct OGSMFrontTangentOperatorData }; /** - * Provides convenient access to the individual blocks of MFront's tangent - * operator data. + * A list of MFront's tangent operator blocks. The list consists of pairs of + * types, first a thermodynamic force, and second a gradient or external state + * variable. * - * \tparam DisplacementDim the displacement dimension * \tparam Gradients a list (of types) of gradients driving the MFront behaviour * \tparam TDynForces a list (of types) of thermodynamic forces * \tparam ExtStateVars a list (of types) of external state variables @@ -54,15 +58,9 @@ struct OGSMFrontTangentOperatorData * these lists is expected to behave like Strain and the other classes in * Variable.h. * - * MFront's tangent operator blocks are stored in a single vector of double - * values. The implementer of an MFront behaviour can decide which blocks she - * wants to provide and in which order. */ -template <int DisplacementDim, - typename Gradients, - typename TDynForces, - typename ExtStateVars> -class OGSMFrontTangentOperatorBlocksView +template <typename Gradients, typename TDynForces, typename ExtStateVars> +struct ForcesGradsCombinations { static_assert(boost::mp11::mp_is_set<Gradients>::value); static_assert(boost::mp11::mp_is_set<TDynForces>::value); @@ -73,8 +71,27 @@ class OGSMFrontTangentOperatorBlocksView static_assert(boost::mp11::mp_is_set<GradientsAndExtStateVars>::value); - using ForcesGradsCombinations = boost::mp11:: + using type = boost::mp11:: mp_product<boost::mp11::mp_list, TDynForces, GradientsAndExtStateVars>; +}; + +/** + * Provides convenient access to the individual blocks of MFront's tangent + * operator data. + * + * \tparam DisplacementDim the displacement dimension + * \tparam ForcesGradsCombinations a list of pairs types corresponding to the + * tangent operator blocks' variables. See ForcesGradsCombinations template for + * details. + * + * MFront's tangent operator blocks are stored in a single vector of double + * values. The implementer of an MFront behaviour can decide which blocks she + * wants to provide and in which order. + */ +template <int DisplacementDim, typename ForcesGradsCombinations> +class OGSMFrontTangentOperatorBlocksView +{ + static_assert(boost::mp11::mp_is_set<ForcesGradsCombinations>::value); /// Indicates that the associated tangent operator block is not present in /// the data. @@ -89,25 +106,52 @@ public: { offsets_.fill(invalid_offset_); + std::vector<bool> used_blocks( + to_blocks.size(), false); // checked after creation of all offsets. + boost::mp11::mp_for_each<ForcesGradsCombinations>( - [&to_blocks, this]<typename Force, typename GradOrExtStateVar>( + [&to_blocks, + &used_blocks, + this]<typename Force, typename GradOrExtStateVar>( boost::mp11::mp_list<Force, GradOrExtStateVar>) { std::size_t data_offset = 0; - for (auto const& [force, grad] : to_blocks) + for (auto [block, is_used] : + ranges::views::zip(to_blocks, used_blocks)) { + auto const& [force, grad] = block; if (force.name == Force::name && grad.name == GradOrExtStateVar::name) { - auto const block_idx = + auto constexpr block_idx = blockIndex<Force, GradOrExtStateVar>(); offsets_[block_idx] = data_offset; + is_used = true; return; } data_offset += size(force.type) * size(grad.type); } }); + + // Indices of unused blocks. + auto indices = ranges::views::enumerate(used_blocks) | + ranges::views::filter([](auto const& pair) + { return !pair.second; }) | + ranges::views::keys; + + if (!indices.empty()) + { + ERR("There are unused tangent operator blocks provided by MFront. " + "Following blocks are unused:"); + + for (auto const i : indices) + { + auto const& [force, grad] = to_blocks[i]; + ERR("\t{}/{}", force.name, grad.name); + } + OGS_FATAL("All tangent operator blocks must be used."); + } } /// Read access to the block dForce/dGradOrExtStateVar. @@ -121,9 +165,12 @@ public: GradOrExtStateVar, OGSMFrontTangentOperatorData const& data) const { - static_assert(boost::mp11::mp_contains<TDynForces, Force>::value); - static_assert(boost::mp11::mp_contains<GradientsAndExtStateVars, - GradOrExtStateVar>::value); + static_assert( + boost::mp11::mp_contains< + ForcesGradsCombinations, + boost::mp11::mp_list<Force, GradOrExtStateVar>>::value, + "Requested tangent block was not created in the " + "OGSMFrontTangentOperatorBlocksView."); constexpr auto index = blockIndex<Force, GradOrExtStateVar>(); const auto offset = offsets_[index]; @@ -184,15 +231,9 @@ private: template <typename Force, typename GradOrExtStateVar> static constexpr std::size_t blockIndex() { - constexpr auto force_idx = - boost::mp11::mp_find<TDynForces, Force>::value; - constexpr auto grad_idx = - boost::mp11::mp_find<GradientsAndExtStateVars, - GradOrExtStateVar>::value; - constexpr auto stride = - boost::mp11::mp_size<GradientsAndExtStateVars>::value; - - return force_idx * stride + grad_idx; + return boost::mp11::mp_find< + ForcesGradsCombinations, + boost::mp11::mp_list<Force, GradOrExtStateVar>>::value; } /// Stores the data offsets of each tangent operator block. diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/ElasticTangentStiffnessModel.h b/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/ElasticTangentStiffnessModel.h index 008b4eea01d448a3b9bf09aa6a9ad3aca7c52d8d..a320213f4a42d8904288ec730aa9db95c8aa254f 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/ElasticTangentStiffnessModel.h +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/ElasticTangentStiffnessModel.h @@ -25,7 +25,7 @@ struct ElasticTangentStiffnessModel SolidConstitutiveRelation<DisplacementDim> const& solid_material) : solid_material_(solid_material), tangent_operator_blocks_view_{ - solid_material.createTangentOperatorBlocksView()} + solid_material.template createTangentOperatorBlocksView()} { } @@ -38,9 +38,10 @@ private: MSM::OGSMFrontTangentOperatorBlocksView< DisplacementDim, - boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, - boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, - boost::mp11::mp_list<MSM::Temperature>> + MSM::ForcesGradsCombinations< + boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, + boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, + boost::mp11::mp_list<MSM::Temperature>>::type> tangent_operator_blocks_view_; }; diff --git a/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/SolidMechanics.h b/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/SolidMechanics.h index d481779ad13b783a44b59b7fc45da1597c00ae27..ad994b18c63e3cbb1c10973a87d9a5509ca57cb3 100644 --- a/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/SolidMechanics.h +++ b/ProcessLib/ThermoRichardsMechanics/ConstitutiveStressSaturation_StrainPressureTemperature/SolidMechanics.h @@ -42,7 +42,7 @@ struct SolidMechanicsModel SolidConstitutiveRelation<DisplacementDim> const& solid_material) : solid_material_(solid_material), tangent_operator_blocks_view_{ - solid_material.createTangentOperatorBlocksView()} + solid_material.template createTangentOperatorBlocksView()} { } @@ -68,9 +68,11 @@ private: SolidConstitutiveRelation<DisplacementDim> const& solid_material_; MSM::OGSMFrontTangentOperatorBlocksView< - DisplacementDim, boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, - boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, - boost::mp11::mp_list<MSM::Temperature>> + DisplacementDim, + MSM::ForcesGradsCombinations< + boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, + boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, + boost::mp11::mp_list<MSM::Temperature>>::type> tangent_operator_blocks_view_; }; diff --git a/Tests/MaterialLib/CheckParamPassingMFront.cpp b/Tests/MaterialLib/CheckParamPassingMFront.cpp index 6245ed04e242d22f124db2b57b6b83739c2bc9eb..20f82ca7b7ce0feb8a2811f2b18d2eaafffc440d 100644 --- a/Tests/MaterialLib/CheckParamPassingMFront.cpp +++ b/Tests/MaterialLib/CheckParamPassingMFront.cpp @@ -112,8 +112,8 @@ auto createMFront( return MSM::createMFrontGeneric< 3, boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, - boost::mp11::mp_list<>>(parameters, local_coordinate_system, - config_tree, false); + boost::mp11::mp_list<MSM::Temperature>>( + parameters, local_coordinate_system, config_tree, false); } TEST(MaterialLib_CheckParamPassingMFront, SuccessTest) diff --git a/Tests/MaterialLib/CheckStiffnessMatrixMFront.cpp b/Tests/MaterialLib/CheckStiffnessMatrixMFront.cpp index a6a9ff9d36b12c0089c9c848edfd0641635dbf0a..3d62c2f0b09b85e8b69d6e5c2d353e180862534d 100644 --- a/Tests/MaterialLib/CheckStiffnessMatrixMFront.cpp +++ b/Tests/MaterialLib/CheckStiffnessMatrixMFront.cpp @@ -18,6 +18,8 @@ #include "MaterialLib/SolidModels/MFront/Variable.h" #include "Tests/TestTools.h" +namespace MSM = MaterialLib::Solids::MFront; + template <typename ExtStateVars> auto createMFront(std::string const& behaviour) { @@ -36,8 +38,6 @@ auto createMFront(std::string const& behaviour) &BaseLib::ConfigTree::onerror, &BaseLib::ConfigTree::onwarning); - namespace MSM = MaterialLib::Solids::MFront; - return MSM::createMFrontGeneric< 3, boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, ExtStateVars>( @@ -81,7 +81,7 @@ struct TestDataBase class MaterialLib_CheckStiffnessMatrixMFront : public ::testing::Test { protected: - template <typename ExtStateVars = boost::mp11::mp_list<>> + template <typename ExtStateVars = boost::mp11::mp_list<MSM::Temperature>> void run(std::string const& behaviour, TestDataBase const& data) const { run<ExtStateVars>(behaviour, data, @@ -92,8 +92,6 @@ protected: void run(std::string const& behaviour, TestDataBase const& data, AdditionalChecks&& checks) const { - namespace MSM = MaterialLib::Solids::MFront; - // Create MFront behaviour // ///////////////////////////////////////////////// @@ -173,8 +171,6 @@ protected: {2301, 2302, 2303, 2304, 2305, 2306})); EXPECT_DOUBLE_EQ(2307, S_L); - namespace MSM = MaterialLib::Solids::MFront; - auto const blocks_view = mfront_model->createTangentOperatorBlocksView(); @@ -238,8 +234,6 @@ TEST_F(MaterialLib_CheckStiffnessMatrixMFront, SomeBlocksMissing) TEST_F(MaterialLib_CheckStiffnessMatrixMFront, DSigmaDTBlock) { - namespace MSM = MaterialLib::Solids::MFront; - run<boost::mp11::mp_list<MSM::Temperature>>( "CheckStiffnessMatrixExcessBlocks", TestDataBase{}, [](auto const& blocks_view, auto const& tangent_operator_data) diff --git a/Tests/MaterialLib/TestTangentOperatorBlocksView.cpp b/Tests/MaterialLib/TestTangentOperatorBlocksView.cpp index e3926289f9ed6a84973c52b38ae1e822b4935e77..046064e3f59f1697d14a1856824fedabcc1c68dc 100644 --- a/Tests/MaterialLib/TestTangentOperatorBlocksView.cpp +++ b/Tests/MaterialLib/TestTangentOperatorBlocksView.cpp @@ -58,10 +58,9 @@ TYPED_TEST(MaterialLib_TangentOperatorBlocksView, Test1) using TDynForces = mp_list<Vector, MSM::Stress>; using ExtStateVars = mp_list<MSM::Temperature>; - MSM::OGSMFrontTangentOperatorBlocksView<dim, - Gradients, - TDynForces, - ExtStateVars> + MSM::OGSMFrontTangentOperatorBlocksView< + dim, + MSM::ForcesGradsCombinations<Gradients, TDynForces, ExtStateVars>::type> view(to_blocks); MSM::OGSMFrontTangentOperatorData data{}; @@ -162,10 +161,9 @@ TYPED_TEST(MaterialLib_TangentOperatorBlocksView, Test2) using TDynForces = mp_list<MSM::Saturation, MSM::Stress>; using ExtStateVars = mp_list<MSM::Temperature>; - MSM::OGSMFrontTangentOperatorBlocksView<dim, - Gradients, - TDynForces, - ExtStateVars> + MSM::OGSMFrontTangentOperatorBlocksView< + dim, + MSM::ForcesGradsCombinations<Gradients, TDynForces, ExtStateVars>::type> view(to_blocks); MSM::OGSMFrontTangentOperatorData data{}; @@ -239,4 +237,65 @@ TYPED_TEST(MaterialLib_TangentOperatorBlocksView, Test2) } } +TYPED_TEST(MaterialLib_TangentOperatorBlocksView, UnusedMFrontBlock) +{ + namespace MB = mgis::behaviour; + using Var = MB::Variable; + using namespace boost::mp11; + namespace MSM = MaterialLib::Solids::MFront; + + constexpr int dim = TypeParam::value; + + const std::vector to_blocks{ + // dsigma/dtensor + std::pair{Var{"Stress", Var::STENSOR}, Var{"tensor", Var::TENSOR}}, + // dvector/dp + std::pair{Var{"Saturation", Var::VECTOR}, + Var{"LiquidPressure", Var::SCALAR}}}; + + using Gradients = mp_list<MSM::LiquidPressure>; + using TDynForces = mp_list<MSM::Saturation, MSM::Stress>; + using ExtStateVars = mp_list<MSM::Temperature>; + + using View = MSM::OGSMFrontTangentOperatorBlocksView< + dim, + MSM::ForcesGradsCombinations<Gradients, TDynForces, ExtStateVars>:: + type>; + ASSERT_ANY_THROW({ View view(to_blocks); }); + // The constructor of View calls OGS_FATAL if MFront provides a tangent + // operator block for which there is no entry in ForcesGradsCombinations, + // i.e., that cannot be accessed in OGS through the view. + // In this test dStress/dtensor is such an inaccessible block. +} + +TYPED_TEST(MaterialLib_TangentOperatorBlocksView, OverspecifiedMFrontBlock) +{ + namespace MB = mgis::behaviour; + using Var = MB::Variable; + using namespace boost::mp11; + namespace MSM = MaterialLib::Solids::MFront; + + constexpr int dim = TypeParam::value; + + const std::vector to_blocks{ + // dsigma/dtensor + std::pair{Var{"Stress", Var::STENSOR}, Var{"tensor", Var::TENSOR}}, + std::pair{Var{"Stress", Var::STENSOR}, Var{"Temperature", Var::SCALAR}}, + // dvector/dp + std::pair{Var{"Saturation", Var::VECTOR}, + Var{"LiquidPressure", Var::SCALAR}}}; + + using Gradients = mp_list<MSM::LiquidPressure, Tensor, Vector>; + using TDynForces = mp_list<MSM::Saturation, MSM::Stress>; + using ExtStateVars = mp_list<MSM::Temperature>; + + using View = MSM::OGSMFrontTangentOperatorBlocksView< + dim, + MSM::ForcesGradsCombinations<Gradients, TDynForces, ExtStateVars>:: + type>; + ASSERT_NO_THROW(View{to_blocks}); + // to_blocks covers only a subset of all of the ForcesGradsCombinations, but + // that's OK, since not all MFront models might provide all blocks. + ASSERT_NO_THROW(View{to_blocks}); +} #endif diff --git a/Tests/MaterialLib/ThermoporoelasticityMFront.cpp b/Tests/MaterialLib/ThermoporoelasticityMFront.cpp index 8d8e353e41b987c3f59fd40cec8fda6e71edcdd0..6019f0f75565f173d03e360ee8e71337ad630360 100644 --- a/Tests/MaterialLib/ThermoporoelasticityMFront.cpp +++ b/Tests/MaterialLib/ThermoporoelasticityMFront.cpp @@ -130,8 +130,8 @@ static auto createMFront( return MSM::createMFrontGeneric< 3, boost::mp11::mp_list<MSM::Strain, MSM::LiquidPressure>, boost::mp11::mp_list<MSM::Stress, MSM::Saturation>, - boost::mp11::mp_list<>>(parameters, local_coordinate_system, - config_tree, false); + boost::mp11::mp_list<MSM::Temperature>>( + parameters, local_coordinate_system, config_tree, false); } TEST(MaterialLib_ThermoPoroElasticityMFront, IsochoricDrainedHeating)