diff --git a/Tests/MaterialLib/TestThermodynamicForcesView.cpp b/Tests/MaterialLib/TestThermodynamicForcesView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d70dc8751b5eff58aea254c061ec3f5cc03215f --- /dev/null +++ b/Tests/MaterialLib/TestThermodynamicForcesView.cpp @@ -0,0 +1,370 @@ +/** + * \file + * \copyright + * Copyright (c) 2012-2022, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "MaterialLib/SolidModels/MFront/ThermodynamicForcesView.h" +#include "MathLib/KelvinVector.h" +#include "Tests/TestTools.h" + +#ifdef OGS_USE_MFRONT +#include "MaterialLib/SolidModels/MFront/Variable.h" +#endif + +namespace MSM = MaterialLib::Solids::MFront; + +// ///////////////////////////////////////////////////////////////////////////// +// Currently (08/2022) there are no vectorial and tensorial variables defined. +// So we have to provide them here. + +#ifdef OGS_USE_MFRONT +struct Vector : MaterialLib::Solids::MFront::Variable<Vector> +{ + constexpr static mgis::behaviour::Variable::Type type = + mgis::behaviour::Variable::Type::VECTOR; +}; + +struct Tensor : MaterialLib::Solids::MFront::Variable<Tensor> +{ + constexpr static mgis::behaviour::Variable::Type type = + mgis::behaviour::Variable::Type::TENSOR; +}; +#endif + +// ///////////////////////////////////////////////////////////////////////////// +// The unit tests in this file all have a version that needs MFront and a +// version that doesn't. For the latter we have to provide the right mock +// variables, here. +// The mocking does not only allow tests in environments that do not use MFront, +// but also shows that OGSMFrontThermodynamicForcesView works entirely without +// MFront, i.e., can in principle be used in other contexts, too. The necessary +// adapters have to be like the mock variables in this file. + +struct MockStress +{ + template <int DisplacementDim> + static constexpr std::size_t size() + { + return rows<DisplacementDim>() * cols<DisplacementDim>(); + } + + template <int DisplacementDim> + static constexpr std::size_t rows() + { + return MathLib::KelvinVector::kelvin_vector_dimensions(DisplacementDim); + } + + template <int DisplacementDim> + static constexpr std::size_t cols() + { + return 1; + } +}; + +struct MockSaturation +{ + template <int DisplacementDim> + static constexpr std::size_t size() + { + return rows<DisplacementDim>() * cols<DisplacementDim>(); + } + + template <int DisplacementDim> + static constexpr std::size_t rows() + { + return 1; + } + + template <int DisplacementDim> + static constexpr std::size_t cols() + { + return 1; + } +}; + +struct MockVector +{ + template <int DisplacementDim> + static constexpr std::size_t size() + { + return rows<DisplacementDim>() * cols<DisplacementDim>(); + } + + template <int DisplacementDim> + static constexpr std::size_t rows() + { + return DisplacementDim; + } + + template <int DisplacementDim> + static constexpr std::size_t cols() + { + return 1; + } +}; + +struct MockTensor +{ + template <int DisplacementDim> + static constexpr std::size_t size() + { + return rows<DisplacementDim>() * cols<DisplacementDim>(); + } + + template <int DisplacementDim> + static constexpr std::size_t rows() + { + return DisplacementDim; + } + + template <int DisplacementDim> + static constexpr std::size_t cols() + { + return DisplacementDim; + } +}; + +template <typename Stress, typename Saturation> +static void +test_MaterialLib_ThermodynamicForcesView_ReadAccess_STensorScalar_3D_impl() +{ + using TDynForces = boost::mp11::mp_list<Stress, Saturation>; + + MSM::OGSMFrontThermodynamicForcesData const data{{ + 1, 2, 3, 4, 5, 6, // stress + 7 // saturation + }}; + + MSM::OGSMFrontThermodynamicForcesView<3, TDynForces> view; + + auto const stress = view.block(Stress{}, data); + + EXPECT_THAT(stress, + testing::Pointwise(testing::DoubleEq(), {1, 2, 3, 4, 5, 6})); + + auto const saturation = view.block(Saturation{}, data); + + EXPECT_DOUBLE_EQ(7, saturation); +} + +#ifdef OGS_USE_MFRONT +TEST(MaterialLib_ThermodynamicForcesView, ReadAccess_STensorScalar_3D) +{ + test_MaterialLib_ThermodynamicForcesView_ReadAccess_STensorScalar_3D_impl< + MSM::Stress, + MSM::Saturation>(); +} +#endif + +TEST(MaterialLib_ThermodynamicForcesView, ReadAccess_STensorScalar_3D_Mock) +{ + test_MaterialLib_ThermodynamicForcesView_ReadAccess_STensorScalar_3D_impl< + MockStress, + MockSaturation>(); +} + +template <typename Vector, typename Tensor> +static void +test_MaterialLib_ThermodynamicForcesView_ReadAccess_VectorTensor_2D_impl() +{ + using TDynForces = boost::mp11::mp_list<Vector, Tensor>; + + MSM::OGSMFrontThermodynamicForcesData const data{{ + 1, 2, // vector data + 3, 4, 5, 6 // tensor data + }}; + + MSM::OGSMFrontThermodynamicForcesView<2, TDynForces> view; + + auto const vector = view.block(Vector{}, data); + + EXPECT_THAT(vector, testing::Pointwise(testing::DoubleEq(), {1, 2})); + + auto const tensor = view.block(Tensor{}, data); + auto const tensor_expected = (Eigen::Matrix2d{} << 3, 4, 5, 6).finished(); + + ASSERT_PRED_FORMAT2(Tests::EigenIsNear{}, tensor, tensor_expected); +} + +#ifdef OGS_USE_MFRONT +TEST(MaterialLib_ThermodynamicForcesView, ReadAccess_VectorTensor_2D) +{ + test_MaterialLib_ThermodynamicForcesView_ReadAccess_VectorTensor_2D_impl< + Vector, + Tensor>(); +} +#endif + +TEST(MaterialLib_ThermodynamicForcesView, ReadAccess_VectorTensor_2D_Mock) +{ + test_MaterialLib_ThermodynamicForcesView_ReadAccess_VectorTensor_2D_impl< + MockVector, + MockTensor>(); +} + +template <typename Saturation, typename Vector> +static void +test_MaterialLib_ThermodynamicForcesView_WriteAccess_ScalarVector_2D_impl() +{ + using TDynForces = boost::mp11::mp_list<Saturation, Vector>; + + MSM::OGSMFrontThermodynamicForcesData data{{ + 1, // saturation + 2, 3 // vector data + }}; + + MSM::OGSMFrontThermodynamicForcesView<2, TDynForces> view; + + view.block(Saturation{}, data) = 5; + view.block(Vector{}, data)[1] = 7; + + EXPECT_THAT(data.data, testing::Pointwise(testing::DoubleEq(), {5, 2, 7})); +} + +#ifdef OGS_USE_MFRONT +TEST(MaterialLib_ThermodynamicForcesView, WriteAccess_ScalarVector_2D) +{ + test_MaterialLib_ThermodynamicForcesView_WriteAccess_ScalarVector_2D_impl< + MSM::Saturation, + Vector>(); +} +#endif + +TEST(MaterialLib_ThermodynamicForcesView, WriteAccess_ScalarVector_2D_Mock) +{ + test_MaterialLib_ThermodynamicForcesView_WriteAccess_ScalarVector_2D_impl< + MockSaturation, + MockVector>(); +} + +template <typename Tensor, typename STensor> +static void +test_MaterialLib_ThermodynamicForcesView_WriteAccess_TensorSTensor_3D_impl() +{ + using TDynForces = boost::mp11::mp_list<Tensor, STensor>; + + MSM::OGSMFrontThermodynamicForcesData data{{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, // tensor data + 10, 11, 12, 13, 14, 15 // strain + }}; + + MSM::OGSMFrontThermodynamicForcesView<3, TDynForces> view; + + view.block(STensor{}, data).template segment<3>(1) = + Eigen::Vector3d(21, 22, 23); + view.block(Tensor{}, data).template block<1, 2>(1, 1) = + Eigen::RowVector2d(31, 32); + + EXPECT_THAT(data.data, + testing::Pointwise( + testing::DoubleEq(), + {1, 2, 3, 4, 31, 32, 7, 8, 9, 10, 21, 22, 23, 14, 15})); +} + +#ifdef OGS_USE_MFRONT +TEST(MaterialLib_ThermodynamicForcesView, WriteAccess_TensorSTensor_3D) +{ + test_MaterialLib_ThermodynamicForcesView_WriteAccess_TensorSTensor_3D_impl< + Tensor, + MSM::Strain>(); +} +#endif + +TEST(MaterialLib_ThermodynamicForcesView, WriteAccess_TensorSTensor_3D_Mock) +{ + test_MaterialLib_ThermodynamicForcesView_WriteAccess_TensorSTensor_3D_impl< + MockTensor, + MockStress>(); +} + +template <typename Scalar, typename Vector, typename STensor, typename Tensor> +static void test_MaterialLib_ThermodynamicForcesView_DataSizes_impl() +{ + { + using TDynForces = boost::mp11::mp_list<Tensor, STensor>; + + static_assert(MSM::OGSMFrontThermodynamicForcesView<3, TDynForces>:: + data_size_all_forces == 3 * 3 + 6); + + static_assert(MSM::OGSMFrontThermodynamicForcesView<2, TDynForces>:: + data_size_all_forces == 2 * 2 + 4); + } + + // same as above, order changed + { + using TDynForces = boost::mp11::mp_list<STensor, Tensor>; + + static_assert(MSM::OGSMFrontThermodynamicForcesView<3, TDynForces>:: + data_size_all_forces == 3 * 3 + 6); + + static_assert(MSM::OGSMFrontThermodynamicForcesView<2, TDynForces>:: + data_size_all_forces == 2 * 2 + 4); + } + + { + using TDynForces = boost::mp11::mp_list<Scalar, Vector>; + + static_assert(MSM::OGSMFrontThermodynamicForcesView<3, TDynForces>:: + data_size_all_forces == 1 + 3); + + static_assert(MSM::OGSMFrontThermodynamicForcesView<2, TDynForces>:: + data_size_all_forces == 1 + 2); + } + + // same as above, order changed + { + using TDynForces = boost::mp11::mp_list<Vector, Scalar>; + + static_assert(MSM::OGSMFrontThermodynamicForcesView<3, TDynForces>:: + data_size_all_forces == 1 + 3); + + static_assert(MSM::OGSMFrontThermodynamicForcesView<2, TDynForces>:: + data_size_all_forces == 1 + 2); + } + + { + using TDynForces = boost::mp11::mp_list<STensor, Scalar>; + + static_assert(MSM::OGSMFrontThermodynamicForcesView<3, TDynForces>:: + data_size_all_forces == 6 + 1); + + static_assert(MSM::OGSMFrontThermodynamicForcesView<2, TDynForces>:: + data_size_all_forces == 4 + 1); + } + + // same as above, order changed + { + using TDynForces = boost::mp11::mp_list<Scalar, STensor>; + + static_assert(MSM::OGSMFrontThermodynamicForcesView<3, TDynForces>:: + data_size_all_forces == 6 + 1); + + static_assert(MSM::OGSMFrontThermodynamicForcesView<2, TDynForces>:: + data_size_all_forces == 4 + 1); + } +} + +#ifdef OGS_USE_MFRONT +TEST(MaterialLib_ThermodynamicForcesView, DataSizes) +{ + test_MaterialLib_ThermodynamicForcesView_DataSizes_impl<MSM::Saturation, + Vector, + MSM::Strain, + Tensor>(); +} +#endif + +TEST(MaterialLib_ThermodynamicForcesView, DataSizes_Mock) +{ + test_MaterialLib_ThermodynamicForcesView_DataSizes_impl<MockSaturation, + MockVector, + MockStress, + MockTensor>(); +}