diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc index 257110d7e..671c71883 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc @@ -1,1010 +1,880 @@ /** * @file test_elastic_materials.cc * * @author Guillaume Anciaux * @author Lucas Frerot * @author Enrico Milanese * * @date creation: Fri Nov 17 2017 * @date last modification: Tue Feb 20 2018 * * @brief Tests the Elastic materials * * @section LICENSE * * Copyright (©) 2016-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" #include "material_elastic_orthotropic.hh" #include "solid_mechanics_model.hh" #include "test_material_fixtures.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; using types = ::testing::Types, Traits, Traits, Traits, Traits, Traits, Traits>; /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial>::testComputeStress() { +template <> void FriendMaterial>::setParams() { Real E = 3.; + Real rho = 2; setParam("E", E); + setParam("rho", rho); +} +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial>::testComputeStress() { Matrix eps = {{2}}; Matrix sigma(1, 1); Real sigma_th = 2; this->computeStressOnQuad(eps, sigma, sigma_th); auto solution = E * eps(0, 0) + sigma_th; - ASSERT_NEAR(sigma(0, 0), solution, 1e-14); + EXPECT_NEAR(sigma(0, 0), solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Real eps = 2, sigma = 2; Real epot = 0; this->computePotentialEnergyOnQuad({{eps}}, {{sigma}}, epot); Real solution = 2; - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testComputeTangentModuli() { - Real E = 2; - setParam("E", E); Matrix tangent(1, 1); this->computeTangentModuliOnQuad(tangent); - ASSERT_NEAR(tangent(0, 0), E, 1e-14); + EXPECT_NEAR(tangent(0, 0), E, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - Real E = 3., rho = 2.; - setParam("E", E); - setParam("rho", rho); - auto wave_speed = this->getCelerity(Element()); auto solution = std::sqrt(E / rho); - ASSERT_NEAR(wave_speed, solution, 1e-14); + EXPECT_NEAR(wave_speed, solution, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial>::testComputeStress() { +template <> void FriendMaterial>::setParams() { Real E = 1.; Real nu = .3; - Real sigma_th = 0.3; // thermal stress + Real rho = 2; setParam("E", E); setParam("nu", nu); + setParam("rho", rho); +} - Real bulk_modulus_K = E / 3. / (1 - 2. * nu); - Real shear_modulus_mu = 0.5 * E / (1 + nu); +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial>::testComputeStress() { + Real bulk_modulus_K = E / (3 * (1 - 2 * nu)); + Real shear_modulus_mu = E / (2 * (1 + nu)); - Matrix rotation_matrix = getRandomRotation2d(); + auto rotation_matrix = getRandomRotation(); auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2); auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); Matrix sigma_rot(2, 2); this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th); auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); - Matrix identity(2, 2); - identity.eye(); + auto identity = Matrix::eye(2, 1.); - Matrix strain = 0.5 * (grad_u + grad_u.transpose()); - Matrix deviatoric_strain = strain - 1. / 3. * strain.trace() * identity; + auto strain = 0.5 * (grad_u + grad_u.transpose()); + auto deviatoric_strain = strain - 1. / 3. * strain.trace() * identity; - Matrix sigma_expected = 2 * shear_modulus_mu * deviatoric_strain + - (sigma_th + 2. * bulk_modulus_K) * identity; + auto sigma_expected = 2 * shear_modulus_mu * deviatoric_strain + + (sigma_th + 2. * bulk_modulus_K) * identity; auto diff = sigma - sigma_expected; - Real stress_error = diff.norm(); - ASSERT_NEAR(stress_error, 0., 1e-14); + Real stress_error = diff.norm() / sigma_expected.norm(); + EXPECT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Matrix sigma = {{1, 2}, {2, 4}}; Matrix eps = {{1, 0}, {0, 1}}; Real epot = 0; Real solution = 2.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testComputeTangentModuli() { - Real E = 1.; - Real nu = .3; - setParam("E", E); - setParam("nu", nu); Matrix tangent(3, 3); /* Plane Strain */ // clang-format off Matrix solution = { {1 - nu, nu, 0}, {nu, 1 - nu, 0}, {0, 0, (1 - 2 * nu) / 2}, }; // clang-format on solution *= E / ((1 + nu) * (1 - 2 * nu)); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - solution).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); /* Plane Stress */ this->plane_stress = true; this->updateInternalParameters(); // clang-format off solution = { {1, nu, 0}, {nu, 1, 0}, {0, 0, (1 - nu) / 2}, }; // clang-format on solution *= E / (1 - nu * nu); this->computeTangentModuliOnQuad(tangent); tangent_error = (tangent - solution).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - Real E = 1.; - Real nu = .3; - Real rho = 2; - setParam("E", E); - setParam("nu", nu); - setParam("rho", rho); auto push_wave_speed = this->getPushWaveSpeed(Element()); auto celerity = this->getCelerity(Element()); Real K = E / (3 * (1 - 2 * nu)); Real mu = E / (2 * (1 + nu)); Real sol = std::sqrt((K + 4. / 3 * mu) / rho); - ASSERT_NEAR(push_wave_speed, sol, 1e-14); - ASSERT_NEAR(celerity, sol, 1e-14); + EXPECT_NEAR(push_wave_speed, sol, 1e-14); + EXPECT_NEAR(celerity, sol, 1e-14); auto shear_wave_speed = this->getShearWaveSpeed(Element()); sol = std::sqrt(mu / rho); - ASSERT_NEAR(shear_wave_speed, sol, 1e-14); + EXPECT_NEAR(shear_wave_speed, sol, 1e-14); } /* -------------------------------------------------------------------------- */ - -template <> void FriendMaterial>::testComputeStress() { +template <> void FriendMaterial>::setParams() { Real E = 1.; Real nu = .3; - Real sigma_th = 0.3; // thermal stress + Real rho = 2; setParam("E", E); setParam("nu", nu); + setParam("rho", rho); +} +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial>::testComputeStress() { Real bulk_modulus_K = E / 3. / (1 - 2. * nu); Real shear_modulus_mu = 0.5 * E / (1 + nu); - Matrix rotation_matrix = getRandomRotation3d(); + Matrix rotation_matrix = getRandomRotation(); auto grad_u = this->getComposedStrain(1.); auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); Matrix sigma_rot(3, 3); this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th); auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); Matrix identity(3, 3); identity.eye(); Matrix strain = 0.5 * (grad_u + grad_u.transpose()); Matrix deviatoric_strain = strain - 1. / 3. * strain.trace() * identity; Matrix sigma_expected = 2 * shear_modulus_mu * deviatoric_strain + (sigma_th + 3. * bulk_modulus_K) * identity; auto diff = sigma - sigma_expected; Real stress_error = diff.norm(); - ASSERT_NEAR(stress_error, 0., 1e-14); + EXPECT_NEAR(stress_error, 0., 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Matrix sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; Matrix eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; Real epot = 0; Real solution = 5.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testComputeTangentModuli() { - Real E = 1.; - Real nu = .3; - setParam("E", E); - setParam("nu", nu); Matrix tangent(6, 6); // clang-format off Matrix solution = { {1 - nu, nu, nu, 0, 0, 0}, {nu, 1 - nu, nu, 0, 0, 0}, {nu, nu, 1 - nu, 0, 0, 0}, {0, 0, 0, (1 - 2 * nu) / 2, 0, 0}, {0, 0, 0, 0, (1 - 2 * nu) / 2, 0}, {0, 0, 0, 0, 0, (1 - 2 * nu) / 2}, }; // clang-format on solution *= E / ((1 + nu) * (1 - 2 * nu)); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - solution).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - Real E = 1.; - Real nu = .3; - Real rho = 2; - setParam("E", E); - setParam("nu", nu); - setParam("rho", rho); - auto push_wave_speed = this->getPushWaveSpeed(Element()); auto celerity = this->getCelerity(Element()); Real K = E / (3 * (1 - 2 * nu)); Real mu = E / (2 * (1 + nu)); Real sol = std::sqrt((K + 4. / 3 * mu) / rho); - ASSERT_NEAR(push_wave_speed, sol, 1e-14); - ASSERT_NEAR(celerity, sol, 1e-14); + EXPECT_NEAR(push_wave_speed, sol, 1e-14); + EXPECT_NEAR(celerity, sol, 1e-14); auto shear_wave_speed = this->getShearWaveSpeed(Element()); sol = std::sqrt(mu / rho); - ASSERT_NEAR(shear_wave_speed, sol, 1e-14); + EXPECT_NEAR(shear_wave_speed, sol, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial>::setParams() { + // Note: for this test material and canonical basis coincide + Vector n1 = {1, 0}; + Vector n2 = {0, 1}; + Real E1 = 1.; + Real E2 = 2.; + Real nu12 = 0.1; + Real G12 = 2.; + Real rho = 2.5; + + *this->dir_vecs[0] = n1; + *this->dir_vecs[1] = n2; + this->E1 = E1; + this->E2 = E2; + this->nu12 = nu12; + this->G12 = G12; + this->rho = rho; } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testComputeStress() { UInt Dim = 2; - - this->E1 = 1.; - this->E2 = 2.; - this->nu12 = 0.1; - this->G12 = 2.; - // material frame of reference is rotate by rotation_matrix starting from // canonical basis - Matrix rotation_matrix = getRandomRotation2d(); + Matrix rotation_matrix = getRandomRotation(); // canonical basis as expressed in the material frame of reference, as // required by MaterialElasticOrthotropic class (it is simply given by the // columns of the rotation_matrix; the lines give the material basis expressed // in the canonical frame of reference) *this->dir_vecs[0] = rotation_matrix(0); *this->dir_vecs[1] = rotation_matrix(1); // set internal Cijkl matrix expressed in the canonical frame of reference this->updateInternalParameters(); // gradient in material frame of reference auto grad_u = this->getComposedStrain(2.).block(0, 0, 2, 2); // gradient in canonical basis (we need to rotate *back* to the canonical // basis) auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); // stress in the canonical basis Matrix sigma_rot(2, 2); this->computeStressOnQuad(grad_u_rot, sigma_rot); // stress in the material reference (we need to apply the rotation) auto sigma = this->applyRotation(sigma_rot, rotation_matrix); // construction of Cijkl engineering tensor in the *material* frame of // reference // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real gamma = 1 / (1 - nu12 * nu21); Matrix C_expected(2 * Dim, 2 * Dim, 0); C_expected(0, 0) = gamma * E1; C_expected(1, 1) = gamma * E2; C_expected(2, 2) = G12; C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21; // epsilon is computed directly in the *material* frame of reference Matrix epsilon = 0.5 * (grad_u + grad_u.transpose()); // sigma_expected is computed directly in the *material* frame of reference Matrix sigma_expected(Dim, Dim); for (UInt i = 0; i < Dim; ++i) { for (UInt j = 0; j < Dim; ++j) { sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j); } } sigma_expected(0, 1) = sigma_expected(1, 0) = C_expected(2, 2) * 2 * epsilon(0, 1); // sigmas are checked in the *material* frame of reference auto diff = sigma - sigma_expected; Real stress_error = diff.norm(); - ASSERT_NEAR(stress_error, 0., 1e-13); + EXPECT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Matrix sigma = {{1, 2}, {2, 4}}; Matrix eps = {{1, 0}, {0, 1}}; Real epot = 0; Real solution = 2.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testComputeTangentModuli() { - - // Note: for this test material and canonical basis coincide - Vector n1 = {1, 0}; - Vector n2 = {0, 1}; - Real E1 = 1.; - Real E2 = 2.; - Real nu12 = 0.1; - Real G12 = 2.; - - *this->dir_vecs[0] = n1; - *this->dir_vecs[1] = n2; - - this->E1 = E1; - this->E2 = E2; - this->nu12 = nu12; - this->G12 = G12; - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - // construction of Cijkl engineering tensor in the *material* frame of // reference // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real gamma = 1 / (1 - nu12 * nu21); Matrix C_expected(3, 3); C_expected(0, 0) = gamma * E1; C_expected(1, 1) = gamma * E2; C_expected(2, 2) = G12; C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21; Matrix tangent(3, 3); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - C_expected).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - - // Note: for this test material and canonical basis coincide - Vector n1 = {1, 0}; - Vector n2 = {0, 1}; - Real E1 = 1.; - Real E2 = 2.; - Real nu12 = 0.1; - Real G12 = 2.; - Real rho = 2.5; - - *this->dir_vecs[0] = n1; - *this->dir_vecs[1] = n2; - this->E1 = E1; - this->E2 = E2; - this->nu12 = nu12; - this->G12 = G12; - this->rho = rho; - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - // construction of Cijkl engineering tensor in the *material* frame of // reference // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real gamma = 1 / (1 - nu12 * nu21); Matrix C_expected(3, 3); C_expected(0, 0) = gamma * E1; C_expected(1, 1) = gamma * E2; C_expected(2, 2) = G12; C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21; Vector eig_expected(3); C_expected.eig(eig_expected); auto celerity_expected = std::sqrt(eig_expected(0) / rho); auto celerity = this->getCelerity(Element()); - ASSERT_NEAR(celerity_expected, celerity, 1e-14); + EXPECT_NEAR(celerity_expected, celerity, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> -void FriendMaterial>::testComputeStress() { - UInt Dim = 3; +template <> void FriendMaterial>::setParams() { + Vector n1 = {1, 0, 0}; + Vector n2 = {0, 1, 0}; + Vector n3 = {0, 0, 1}; Real E1 = 1.; Real E2 = 2.; Real E3 = 3.; Real nu12 = 0.1; Real nu13 = 0.2; Real nu23 = 0.3; Real G12 = 2.; Real G13 = 3.; Real G23 = 1.; + Real rho = 2.3; + *this->dir_vecs[0] = n1; + *this->dir_vecs[1] = n2; + *this->dir_vecs[2] = n3; this->E1 = E1; this->E2 = E2; this->E3 = E3; this->nu12 = nu12; this->nu13 = nu13; this->nu23 = nu23; this->G12 = G12; this->G13 = G13; this->G23 = G23; + this->rho = rho; +} + +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial>::testComputeStress() { + UInt Dim = 3; // material frame of reference is rotate by rotation_matrix starting from // canonical basis - Matrix rotation_matrix = getRandomRotation3d(); + Matrix rotation_matrix = getRandomRotation(); // canonical basis as expressed in the material frame of reference, as // required by MaterialElasticOrthotropic class (it is simply given by the // columns of the rotation_matrix; the lines give the material basis expressed // in the canonical frame of reference) *this->dir_vecs[0] = rotation_matrix(0); *this->dir_vecs[1] = rotation_matrix(1); *this->dir_vecs[2] = rotation_matrix(2); // set internal Cijkl matrix expressed in the canonical frame of reference this->updateInternalParameters(); // gradient in material frame of reference auto grad_u = this->getComposedStrain(2.); // gradient in canonical basis (we need to rotate *back* to the canonical // basis) auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); // stress in the canonical basis Matrix sigma_rot(3, 3); this->computeStressOnQuad(grad_u_rot, sigma_rot); // stress in the material reference (we need to apply the rotation) auto sigma = this->applyRotation(sigma_rot, rotation_matrix); // construction of Cijkl engineering tensor in the *material* frame of // reference // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real nu31 = nu13 * E3 / E1; Real nu32 = nu23 * E3 / E2; Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - 2 * nu21 * nu32 * nu13); Matrix C_expected(6, 6); C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32); C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31); C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21); C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23); C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32); C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31); C_expected(3, 3) = G23; C_expected(4, 4) = G13; C_expected(5, 5) = G12; // epsilon is computed directly in the *material* frame of reference Matrix epsilon = 0.5 * (grad_u + grad_u.transpose()); // sigma_expected is computed directly in the *material* frame of reference Matrix sigma_expected(Dim, Dim); for (UInt i = 0; i < Dim; ++i) { for (UInt j = 0; j < Dim; ++j) { sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j); } } sigma_expected(0, 1) = C_expected(5, 5) * 2 * epsilon(0, 1); sigma_expected(0, 2) = C_expected(4, 4) * 2 * epsilon(0, 2); sigma_expected(1, 2) = C_expected(3, 3) * 2 * epsilon(1, 2); sigma_expected(1, 0) = sigma_expected(0, 1); sigma_expected(2, 0) = sigma_expected(0, 2); sigma_expected(2, 1) = sigma_expected(1, 2); // sigmas are checked in the *material* frame of reference auto diff = sigma - sigma_expected; Real stress_error = diff.norm(); - ASSERT_NEAR(stress_error, 0., 1e-13); + EXPECT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Matrix sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; Matrix eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; Real epot = 0; Real solution = 5.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testComputeTangentModuli() { - // Note: for this test material and canonical basis coincide UInt Dim = 3; - Vector n1 = {1, 0, 0}; - Vector n2 = {0, 1, 0}; - Vector n3 = {0, 0, 1}; - Real E1 = 1.; - Real E2 = 2.; - Real E3 = 3.; - Real nu12 = 0.1; - Real nu13 = 0.2; - Real nu23 = 0.3; - Real G12 = 2.; - Real G13 = 3.; - Real G23 = 1.; - - *this->dir_vecs[0] = n1; - *this->dir_vecs[1] = n2; - *this->dir_vecs[2] = n3; - this->E1 = E1; - this->E2 = E2; - this->E3 = E3; - this->nu12 = nu12; - this->nu13 = nu13; - this->nu23 = nu23; - this->G12 = G12; - this->G13 = G13; - this->G23 = G23; - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); // construction of Cijkl engineering tensor in the *material* frame of // reference // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real nu31 = nu13 * E3 / E1; Real nu32 = nu23 * E3 / E2; Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - 2 * nu21 * nu32 * nu13); Matrix C_expected(2 * Dim, 2 * Dim, 0); C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32); C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31); C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21); C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23); C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32); C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31); C_expected(3, 3) = G23; C_expected(4, 4) = G13; C_expected(5, 5) = G12; Matrix tangent(6, 6); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - C_expected).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - // Note: for this test material and canonical basis coincide UInt Dim = 3; - Vector n1 = {1, 0, 0}; - Vector n2 = {0, 1, 0}; - Vector n3 = {0, 0, 1}; - Real E1 = 1.; - Real E2 = 2.; - Real E3 = 3.; - Real nu12 = 0.1; - Real nu13 = 0.2; - Real nu23 = 0.3; - Real G12 = 2.; - Real G13 = 3.; - Real G23 = 1.; - Real rho = 2.3; - - *this->dir_vecs[0] = n1; - *this->dir_vecs[1] = n2; - *this->dir_vecs[2] = n3; - this->E1 = E1; - this->E2 = E2; - this->E3 = E3; - this->nu12 = nu12; - this->nu13 = nu13; - this->nu23 = nu23; - this->G12 = G12; - this->G13 = G13; - this->G23 = G23; - this->rho = rho; - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - // construction of Cijkl engineering tensor in the *material* frame of // reference // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real nu31 = nu13 * E3 / E1; Real nu32 = nu23 * E3 / E2; Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - 2 * nu21 * nu32 * nu13); Matrix C_expected(2 * Dim, 2 * Dim, 0); C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32); C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31); C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21); C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23); C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32); C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31); C_expected(3, 3) = G23; C_expected(4, 4) = G13; C_expected(5, 5) = G12; Vector eig_expected(6); C_expected.eig(eig_expected); auto celerity_expected = std::sqrt(eig_expected(0) / rho); auto celerity = this->getCelerity(Element()); - ASSERT_NEAR(celerity_expected, celerity, 1e-14); + EXPECT_NEAR(celerity_expected, celerity, 1e-14); } /* -------------------------------------------------------------------------- */ template <> -void FriendMaterial>::testComputeStress() { - UInt Dim = 2; +void FriendMaterial>::setParams() { Matrix C = { {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, }; for (auto i = 0u; i < C.rows(); ++i) for (auto j = 0u; j < C.cols(); ++j) this->Cprime(i, j) = C(i, j); + this->rho = 2.7; + // material frame of reference is rotate by rotation_matrix starting from // canonical basis - Matrix rotation_matrix = getRandomRotation2d(); + Matrix rotation_matrix = getRandomRotation(); // canonical basis as expressed in the material frame of reference, as // required by MaterialElasticLinearAnisotropic class (it is simply given by // the columns of the rotation_matrix; the lines give the material basis // expressed in the canonical frame of reference) *this->dir_vecs[0] = rotation_matrix(0); *this->dir_vecs[1] = rotation_matrix(1); +} - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial>::testComputeStress() { + Matrix C = { + {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, + }; + + Matrix rotation_matrix(2, 2); + + rotation_matrix(0) = *this->dir_vecs[0]; + rotation_matrix(1) = *this->dir_vecs[1]; // gradient in material frame of reference auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2); // gradient in canonical basis (we need to rotate *back* to the canonical // basis) auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); // stress in the canonical basis Matrix sigma_rot(2, 2); this->computeStressOnQuad(grad_u_rot, sigma_rot); // stress in the material reference (we need to apply the rotation) auto sigma = this->applyRotation(sigma_rot, rotation_matrix); // epsilon is computed directly in the *material* frame of reference Matrix epsilon = 0.5 * (grad_u + grad_u.transpose()); Vector epsilon_voigt(3); epsilon_voigt(0) = epsilon(0, 0); epsilon_voigt(1) = epsilon(1, 1); epsilon_voigt(2) = 2 * epsilon(0, 1); // sigma_expected is computed directly in the *material* frame of reference Vector sigma_voigt = C * epsilon_voigt; - Matrix sigma_expected(Dim, Dim); + Matrix sigma_expected(2, 2); sigma_expected(0, 0) = sigma_voigt(0); sigma_expected(1, 1) = sigma_voigt(1); sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(2); // sigmas are checked in the *material* frame of reference auto diff = sigma - sigma_expected; Real stress_error = diff.norm(); - ASSERT_NEAR(stress_error, 0., 1e-13); + EXPECT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Matrix sigma = {{1, 2}, {2, 4}}; Matrix eps = {{1, 0}, {0, 1}}; Real epot = 0; Real solution = 2.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial< MaterialElasticLinearAnisotropic<2>>::testComputeTangentModuli() { - - // Note: for this test material and canonical basis coincide - Matrix C = { - {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, - }; - - for (auto i = 0u; i < C.rows(); ++i) - for (auto j = 0u; j < C.cols(); ++j) - this->Cprime(i, j) = C(i, j); - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - Matrix tangent(3, 3); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - C).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - - // Note: for this test material and canonical basis coincide - Matrix C = { - {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, - }; - - Real rho = 2.7; - - for (auto i = 0u; i < C.rows(); ++i) - for (auto j = 0u; j < C.cols(); ++j) - this->Cprime(i, j) = C(i, j); - - this->rho = rho; - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - Vector eig_expected(3); C.eig(eig_expected); - auto celerity_expected = std::sqrt(eig_expected(0) / rho); - + auto celerity_expected = std::sqrt(eig_expected(0) / this->rho); auto celerity = this->getCelerity(Element()); - ASSERT_NEAR(celerity_expected, celerity, 1e-14); + EXPECT_NEAR(celerity_expected, celerity, 1e-14); } /* -------------------------------------------------------------------------- */ template <> -void FriendMaterial>::testComputeStress() { - UInt Dim = 3; +void FriendMaterial>::setParams() { + // Note: for this test material and canonical basis coincide Matrix C = { {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, }; for (auto i = 0u; i < C.rows(); ++i) for (auto j = 0u; j < C.cols(); ++j) this->Cprime(i, j) = C(i, j); + this->rho = 2.9; + // material frame of reference is rotate by rotation_matrix starting from // canonical basis - Matrix rotation_matrix = getRandomRotation3d(); + Matrix rotation_matrix = getRandomRotation(); // canonical basis as expressed in the material frame of reference, as // required by MaterialElasticLinearAnisotropic class (it is simply given by // the columns of the rotation_matrix; the lines give the material basis // expressed in the canonical frame of reference) *this->dir_vecs[0] = rotation_matrix(0); *this->dir_vecs[1] = rotation_matrix(1); *this->dir_vecs[2] = rotation_matrix(2); +} - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial>::testComputeStress() { + Matrix C = { + {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, + {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, + {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, + }; + + Matrix rotation_matrix(3, 3); + + rotation_matrix(0) = *this->dir_vecs[0]; + rotation_matrix(1) = *this->dir_vecs[1]; + rotation_matrix(2) = *this->dir_vecs[2]; // gradient in material frame of reference auto grad_u = this->getComposedStrain(2.); // gradient in canonical basis (we need to rotate *back* to the canonical // basis) auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); // stress in the canonical basis Matrix sigma_rot(3, 3); this->computeStressOnQuad(grad_u_rot, sigma_rot); // stress in the material reference (we need to apply the rotation) auto sigma = this->applyRotation(sigma_rot, rotation_matrix); // epsilon is computed directly in the *material* frame of reference Matrix epsilon = 0.5 * (grad_u + grad_u.transpose()); Vector epsilon_voigt(6); epsilon_voigt(0) = epsilon(0, 0); epsilon_voigt(1) = epsilon(1, 1); epsilon_voigt(2) = epsilon(2, 2); epsilon_voigt(3) = 2 * epsilon(1, 2); epsilon_voigt(4) = 2 * epsilon(0, 2); epsilon_voigt(5) = 2 * epsilon(0, 1); // sigma_expected is computed directly in the *material* frame of reference Vector sigma_voigt = C * epsilon_voigt; - Matrix sigma_expected(Dim, Dim); + Matrix sigma_expected(3, 3); sigma_expected(0, 0) = sigma_voigt(0); sigma_expected(1, 1) = sigma_voigt(1); sigma_expected(2, 2) = sigma_voigt(2); sigma_expected(1, 2) = sigma_expected(2, 1) = sigma_voigt(3); sigma_expected(0, 2) = sigma_expected(2, 0) = sigma_voigt(4); sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(5); // sigmas are checked in the *material* frame of reference auto diff = sigma - sigma_expected; Real stress_error = diff.norm(); - ASSERT_NEAR(stress_error, 0., 1e-13); + EXPECT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testEnergyDensity() { Matrix sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; Matrix eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; Real epot = 0; Real solution = 5.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); + EXPECT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial< MaterialElasticLinearAnisotropic<3>>::testComputeTangentModuli() { - - // Note: for this test material and canonical basis coincide - Matrix C = { - {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, - {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, - {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, - }; - - for (auto i = 0u; i < C.rows(); ++i) - for (auto j = 0u; j < C.cols(); ++j) - this->Cprime(i, j) = C(i, j); - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - Matrix tangent(6, 6); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - C).norm(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + EXPECT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ template <> void FriendMaterial>::testCelerity() { - - // Note: for this test material and canonical basis coincide - Matrix C = { - {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, - {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, - {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, - }; - Real rho = 2.9; - - for (auto i = 0u; i < C.rows(); ++i) - for (auto j = 0u; j < C.cols(); ++j) - this->Cprime(i, j) = C(i, j); - - this->rho = rho; - - // set internal Cijkl matrix expressed in the canonical frame of reference - this->updateInternalParameters(); - Vector eig_expected(6); C.eig(eig_expected); - auto celerity_expected = std::sqrt(eig_expected(0) / rho); + auto celerity_expected = std::sqrt(eig_expected(0) / this->rho); auto celerity = this->getCelerity(Element()); - ASSERT_NEAR(celerity_expected, celerity, 1e-14); + EXPECT_NEAR(celerity_expected, celerity, 1e-14); } /* -------------------------------------------------------------------------- */ namespace { template class TestElasticMaterialFixture : public ::TestMaterialFixture {}; TYPED_TEST_CASE(TestElasticMaterialFixture, types); TYPED_TEST(TestElasticMaterialFixture, ComputeStress) { this->material->testComputeStress(); } TYPED_TEST(TestElasticMaterialFixture, EnergyDensity) { this->material->testEnergyDensity(); } TYPED_TEST(TestElasticMaterialFixture, ComputeTangentModuli) { this->material->testComputeTangentModuli(); } TYPED_TEST(TestElasticMaterialFixture, ComputeCelerity) { this->material->testCelerity(); } } // namespace diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh index eeef37f6f..b61960820 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh @@ -1,209 +1,211 @@ /** * @file test_material_fixtures.hh * * @author Guillaume Anciaux * * @date creation: Fri Nov 17 2017 * @date last modification: Tue Feb 20 2018 * * @brief Fixture for material tests * * @section LICENSE * * Copyright (©) 2016-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ template class FriendMaterial : public T { public: ~FriendMaterial() = default; + FriendMaterial(SolidMechanicsModel & model, const ID & id = "material") + : T(model, id) { + gen.seed(::testing::GTEST_FLAG(random_seed)); + } + virtual void testComputeStress() { AKANTU_TO_IMPLEMENT(); }; virtual void testComputeTangentModuli() { AKANTU_TO_IMPLEMENT(); }; virtual void testEnergyDensity() { AKANTU_TO_IMPLEMENT(); }; virtual void testCelerity() { AKANTU_TO_IMPLEMENT(); } - static inline Matrix getDeviatoricStrain(Real intensity); - static inline Matrix getHydrostaticStrain(Real intensity); - static inline Matrix getComposedStrain(Real intensity); + virtual void setParams() {} + virtual void SetUp() { + this->setParams(); + this->initMaterial(); + } + + virtual void TearDown() { } + + inline Matrix getDeviatoricStrain(Real intensity); + inline Matrix getHydrostaticStrain(Real intensity); + inline Matrix getComposedStrain(Real intensity); - static inline const Matrix - reverseRotation(Matrix mat, Matrix rotation_matrix) { + inline const Matrix reverseRotation(Matrix mat, + Matrix rotation_matrix) { Matrix R = rotation_matrix; Matrix m2 = mat * R; Matrix m1 = R.transpose(); return m1 * m2; }; - static inline const Matrix - applyRotation(Matrix mat, const Matrix rotation_matrix) { + inline const Matrix applyRotation(Matrix mat, + const Matrix rotation_matrix) { Matrix R = rotation_matrix; Matrix m2 = mat * R.transpose(); Matrix m1 = R; return m1 * m2; }; - static inline Matrix getRandomRotation3d(); - static inline Matrix getRandomRotation2d(); + inline Vector getRandomVector(); + inline Matrix getRandomRotation(); - using T::T; +protected: + std::mt19937 gen; }; /* -------------------------------------------------------------------------- */ template Matrix FriendMaterial::getDeviatoricStrain(Real intensity) { Matrix dev = {{0., 1., 2.}, {1., 0., 3.}, {2., 3., 0.}}; dev *= intensity; return dev; } /* -------------------------------------------------------------------------- */ template Matrix FriendMaterial::getHydrostaticStrain(Real intensity) { Matrix dev = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; dev *= intensity; return dev; } /* -------------------------------------------------------------------------- */ template Matrix FriendMaterial::getComposedStrain(Real intensity) { Matrix s = FriendMaterial::getHydrostaticStrain(intensity) + FriendMaterial::getDeviatoricStrain(intensity); s *= intensity; return s; } /* -------------------------------------------------------------------------- */ -template Matrix FriendMaterial::getRandomRotation3d() { - constexpr UInt Dim = 3; - // Seed with a real random value, if available - std::random_device rd; - std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() +template Vector FriendMaterial::getRandomVector() { + auto dim = this->spatial_dimension; std::uniform_real_distribution dis; - - Vector v1(Dim); - Vector v2(Dim); - Vector v3(Dim); - - for (UInt i = 0; i < Dim; ++i) { - v1(i) = dis(gen); - v2(i) = dis(gen); + Vector vector(dim, 0.); + while(vector.norm() < 1e-9) { + for (auto s : arange(dim)) + vector(s) = dis(gen); } - - v1.normalize(); - - auto d = v1.dot(v2); - v2 -= v1 * d; - v2.normalize(); - - v3.crossProduct(v1, v2); - - Matrix mat(Dim, Dim); - for (UInt i = 0; i < Dim; ++i) { - mat(0, i) = v1[i]; - mat(1, i) = v2[i]; - mat(2, i) = v3[i]; - } - - return mat; + return vector; } /* -------------------------------------------------------------------------- */ -template Matrix FriendMaterial::getRandomRotation2d() { - constexpr UInt Dim = 2; - // Seed with a real random value, if available - std::random_device rd; - std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() - std::uniform_real_distribution<> dis; - - // v1 and v2 are such that they form a right-hand basis with prescribed v3, - // it's need (at least) for 2d linear elastic anisotropic and (orthotropic) - // materials to rotate the tangent stiffness - - Vector v1(3); - Vector v2(3); - Vector v3 = {0, 0, 1}; - - for (UInt i = 0; i < Dim; ++i) { - v1(i) = dis(gen); - // v2(i) = dis(gen); +template Matrix FriendMaterial::getRandomRotation() { + auto dim = this->spatial_dimension; + + Matrix rotation(dim, dim); + Vector v1 = rotation(0); + v1 = getRandomVector().normalize(); + if (dim == 2) { + Vector v1_ = {v1(0), v1(1), 0}; + Vector v2_(3); + Vector v3_ = {0, 0, 1}; + v2_.crossProduct(v3_, v1_); + + Vector v2 = rotation(1); + v2(0) = v2_(0); + v2(1) = v2_(1); } - v1.normalize(); - v2.crossProduct(v3, v1); + if (dim == 3) { + auto v2 = getRandomVector(); + v2 = (v2 - v2.dot(v1) * v1).normalize(); + + Vector v3(3); + v3.crossProduct(v1, v2); - Matrix mat(Dim, Dim); - for (UInt i = 0; i < Dim; ++i) { - mat(0, i) = v1[i]; - mat(1, i) = v2[i]; + rotation(1) = v2; + rotation(2) = v3; } - return mat; +//#define debug_ +#if defined(debug_) + if (dim == 2) + rotation = Matrix{{1., 0.}, {0., 1.}}; + if (dim == 3) + rotation = Matrix{{1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}}; +#endif + + rotation = rotation.transpose(); + + return rotation; } /* -------------------------------------------------------------------------- */ template class TestMaterialBaseFixture : public ::testing::Test { public: using mat_class = typename T::mat_class; void SetUp() override { constexpr auto spatial_dimension = T::Dim; mesh = std::make_unique(spatial_dimension); model = std::make_unique(*mesh); material = std::make_unique(*model); + material->SetUp(); } void TearDown() override { + material->TearDown(); material.reset(nullptr); model.reset(nullptr); mesh.reset(nullptr); } using friend_class = FriendMaterial; protected: std::unique_ptr mesh; std::unique_ptr model; std::unique_ptr material; }; /* -------------------------------------------------------------------------- */ template