|
| 1 | +#include "test_material_CANN_holzapfel_ogden.h" |
| 2 | +#include "test_material_holzapfel_ogden.h" |
| 3 | + |
| 4 | + |
| 5 | + |
| 6 | +// ---------------------------------------------------------------------------- |
| 7 | +// -------- Compare CANN w/ HO params against HO Model ------------------------ |
| 8 | +// ---------------------------------------------------------------------------- |
| 9 | +/** |
| 10 | + * @brief Test fixture class for comparing the CANN model with Holzapfel Ogden mdoel. |
| 11 | + * |
| 12 | + * This class sets up the necessary parameters and objects for comparing CANN model with HO parameters against the Holzapfel-Ogden model. Assuming k = 0, so chi = 0.5. |
| 13 | + */ |
| 14 | +class HolzapfelOgdenCompareTest : public MaterialTestFixture { |
| 15 | +protected: |
| 16 | + // Material parameters objects |
| 17 | + HolzapfelOgdenParams params_HO; // HO parameters |
| 18 | + CANN_HO_Params params_CANN_HO; // CANN with HO parameters |
| 19 | + |
| 20 | + // Add the test objects |
| 21 | + TestHolzapfelOgden* TestHO; |
| 22 | + TestCANN_HO* TestCANNHO; |
| 23 | + |
| 24 | + // Setup method to initialize variables before each test |
| 25 | + void SetUp() override { |
| 26 | + MaterialTestFixture::SetUp(); |
| 27 | + |
| 28 | + // Set Holzapfel-Ogden parameters from cardiac benchmark paper |
| 29 | + params_HO.a = 59.0; // Pa |
| 30 | + params_HO.a_f = 18472.0; // Pa |
| 31 | + params_HO.a_s = 2481.0; // Pa |
| 32 | + params_HO.a_fs = 216.0; // Pa |
| 33 | + params_HO.b = 8.023; // no units |
| 34 | + params_HO.b_f = 16.026; // no units |
| 35 | + params_HO.b_s = 11.12; // no units |
| 36 | + params_HO.b_fs = 11.436; // no units |
| 37 | + // setting heaviside parameter to 0 |
| 38 | + params_HO.k = 0.0; // no units |
| 39 | + |
| 40 | + // Set random values for f between 0 and 1 and normalize |
| 41 | + params_HO.f[0] = getRandomDouble(0.0, 1.0); |
| 42 | + params_HO.f[1] = getRandomDouble(0.0, 1.0); |
| 43 | + params_HO.f[2] = getRandomDouble(0.0, 1.0); |
| 44 | + double norm_f = sqrt(params_HO.f[0]*params_HO.f[0] + params_HO.f[1]*params_HO.f[1] + params_HO.f[2]*params_HO.f[2]); |
| 45 | + params_HO.f[0] /= norm_f; params_HO.f[1] /= norm_f; params_HO.f[2] /= norm_f; |
| 46 | + |
| 47 | + // Create s orthogonal to f |
| 48 | + if (fabs(params_HO.f[0]) < 0.9) { // Check if f[0] is not the dominant component |
| 49 | + params_HO.s[0] = 0; |
| 50 | + params_HO.s[1] = params_HO.f[2]; |
| 51 | + params_HO.s[2] = -params_HO.f[1]; |
| 52 | + } else { // If f[0] is the dominant component, use another approach |
| 53 | + params_HO.s[0] = -params_HO.f[2]; |
| 54 | + params_HO.s[1] = 0; |
| 55 | + params_HO.s[2] = params_HO.f[0]; |
| 56 | + } |
| 57 | + |
| 58 | + // Normalize s |
| 59 | + double norm_s = sqrt(params_HO.s[0]*params_HO.s[0] + params_HO.s[1]*params_HO.s[1] + params_HO.s[2]*params_HO.s[2]); |
| 60 | + params_HO.s[0] /= norm_s; params_HO.s[1] /= norm_s; params_HO.s[2] /= norm_s; |
| 61 | + |
| 62 | + // Check f.s = 0 |
| 63 | + double dot_fs = params_HO.f[0]*params_HO.s[0] + params_HO.f[1]*params_HO.s[1] + params_HO.f[2]*params_HO.s[2]; |
| 64 | + if (fabs(dot_fs) > 1e-6) { |
| 65 | + std::cout << "f.s = " << dot_fs << std::endl; |
| 66 | + std::cout << "f = [" << params_HO.f[0] << ", " << params_HO.f[1] << ", " << params_HO.f[2] << "]" << std::endl; |
| 67 | + std::cout << "s = [" << params_HO.s[0] << ", " << params_HO.s[1] << ", " << params_HO.s[2] << "]" << std::endl; |
| 68 | + throw std::runtime_error("f and s are not orthogonal"); |
| 69 | + } |
| 70 | + |
| 71 | + // Initializing paramter table |
| 72 | + params_CANN_HO.Table.resize(4); // Ensure it has 4 entries |
| 73 | + |
| 74 | + params_CANN_HO.Table[0].invariant_index.value_ = 1; |
| 75 | + params_CANN_HO.Table[0].activation_functions.value_ = {1,1,2}; |
| 76 | + params_CANN_HO.Table[0].weights.value_ = {1.0, params_HO.b, params_HO.a / (2 * params_HO.b)}; |
| 77 | + |
| 78 | + params_CANN_HO.Table[1].invariant_index.value_ = 4; |
| 79 | + params_CANN_HO.Table[1].activation_functions.value_ = {1,2,2}; |
| 80 | + params_CANN_HO.Table[1].weights.value_ = {1.0, params_HO.b_f, 0.5 * params_HO.a_f / (2 * params_HO.b_f)}; // 0.5 for heaviside func |
| 81 | + |
| 82 | + params_CANN_HO.Table[2].invariant_index.value_ = 8; |
| 83 | + params_CANN_HO.Table[2].activation_functions.value_ = {1,2,2}; |
| 84 | + params_CANN_HO.Table[2].weights.value_ = {1.0, params_HO.b_s, 0.5 * params_HO.a_s / (2 * params_HO.b_s)}; |
| 85 | + |
| 86 | + params_CANN_HO.Table[3].invariant_index.value_ = 6; |
| 87 | + params_CANN_HO.Table[3].activation_functions.value_ = {1,2,2}; |
| 88 | + params_CANN_HO.Table[3].weights.value_ = {1.0, params_HO.b_fs, params_HO.a_fs / (2 * params_HO.b_fs)}; |
| 89 | + |
| 90 | + // initializing fiber directions for CANN |
| 91 | + params_CANN_HO.f[0] = params_HO.f[0]; params_CANN_HO.f[1] = params_HO.f[1]; params_CANN_HO.f[2] = params_HO.f[2]; |
| 92 | + params_CANN_HO.s[0] = params_HO.s[0]; params_CANN_HO.s[1] = params_HO.s[1]; params_CANN_HO.s[2] = params_HO.s[2]; |
| 93 | + |
| 94 | + // Initialize the test objects |
| 95 | + TestHO = new TestHolzapfelOgden(params_HO); |
| 96 | + TestCANNHO = new TestCANN_HO(params_CANN_HO); |
| 97 | + |
| 98 | + if (TestCANNHO == nullptr) { |
| 99 | + throw std::runtime_error("TestCANNHO is not properly initialized"); |
| 100 | + } |
| 101 | + if (TestHO == nullptr) { |
| 102 | + throw std::runtime_error("TestHO is not properly initialized"); |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + // TearDown method to clean up after each test, if needed |
| 107 | + void TearDown() override { |
| 108 | + // Clean up the test objects |
| 109 | + delete TestHO; |
| 110 | + TestHO = nullptr; |
| 111 | + delete TestCANNHO; |
| 112 | + TestCANNHO = nullptr; |
| 113 | + } |
| 114 | +}; |
| 115 | + |
| 116 | +/** |
| 117 | + * @brief Test fixture class for STRUCT Holzapfel-Ogden Compare model. |
| 118 | + */ |
| 119 | +class STRUCT_CANNHolzapfelOgdenTest : public HolzapfelOgdenCompareTest { |
| 120 | +protected: |
| 121 | + void SetUp() override { |
| 122 | + HolzapfelOgdenCompareTest::SetUp(); |
| 123 | + |
| 124 | + // Use struct |
| 125 | + TestHO->ustruct = false; |
| 126 | + TestCANNHO->ustruct = false; |
| 127 | + } |
| 128 | +}; |
| 129 | + |
| 130 | +/** |
| 131 | + * @brief Test fixture class for USTRUCT Neo-Hookean Compare model. |
| 132 | + */ |
| 133 | +class USTRUCT_CANNHolzapfelOgdenTest : public HolzapfelOgdenCompareTest { |
| 134 | +protected: |
| 135 | + void SetUp() override { |
| 136 | + HolzapfelOgdenCompareTest::SetUp(); |
| 137 | + |
| 138 | + // Use ustruct |
| 139 | + TestHO->ustruct = true; |
| 140 | + TestCANNHO->ustruct = true; |
| 141 | + } |
| 142 | +}; |
| 143 | + |
| 144 | + |
| 145 | +// ------------------------------ STRUCT Tests -------------------------------- |
| 146 | + |
| 147 | +// Test PK2 stress zero for F = I |
| 148 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestPK2StressIdentityF) { |
| 149 | + verbose = false; // Show values of S and S_ref |
| 150 | + |
| 151 | + // Check identity F produces zero PK2 stress |
| 152 | + Array<double> F = {{1.0, 0.0, 0.0}, |
| 153 | + {0.0, 1.0, 0.0}, |
| 154 | + {0.0, 0.0, 1.0}}; |
| 155 | + Array<double> S_ref(3,3); // PK2 stress initialized to zero - want to get result from NH and set that to S_ref |
| 156 | + Array<double> Dm(6,6); |
| 157 | + TestHO->compute_pk2cc(F,S_ref,Dm); // Computing S_ref from NH |
| 158 | + TestCANNHO->testPK2StressAgainstReference(F, S_ref, rel_tol, abs_tol, verbose); // Comparing with CANN |
| 159 | +} |
| 160 | + |
| 161 | +// Test PK2 stress |
| 162 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestPK2StressTriaxialStretch) { |
| 163 | + verbose = false; // Show values of S and S_ref |
| 164 | + |
| 165 | + // Check identity F produces zero PK2 stress |
| 166 | + Array<double> F = {{1.1, 0.0, 0.0}, |
| 167 | + {0.0, 1.2, 0.0}, |
| 168 | + {0.0, 0.0, 0.757}}; |
| 169 | + Array<double> S_ref(3,3); // PK2 stress initialized to zero - want to get result from NH and set that to S_ref |
| 170 | + Array<double> Dm(6,6); |
| 171 | + TestHO->compute_pk2cc(F,S_ref,Dm); // Computing S_ref from NH |
| 172 | + TestCANNHO->testPK2StressAgainstReference(F, S_ref, rel_tol, abs_tol, verbose); // Comparing with CANN |
| 173 | +} |
| 174 | + |
| 175 | +// Test order of convergence between finite difference PK2 stress and compute_pk2cc() PK2 stress for random F (small) |
| 176 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestPK2StressConvergenceOrderAgainstReferenceRandomFSmall) { |
| 177 | + verbose = false; // Show order of convergence, errors, F, S |
| 178 | + |
| 179 | + // Loop over F in F_small_list |
| 180 | + for (auto F_std : F_small_list) { |
| 181 | + // Convert to C array |
| 182 | + convertToArray(F_std, F); |
| 183 | + |
| 184 | + // Check order of convergence between finite difference and compute_pk2cc() PK2 stress |
| 185 | + Array<double> S_ref(3,3), Dm(6,6); |
| 186 | + TestCANNHO->compute_pk2cc(F,S_ref,Dm); // Computing S_ref from CANN |
| 187 | + TestHO->testPK2StressConvergenceOrderAgainstReference(F, S_ref, delta_max, delta_min, order, convergence_order_tol, verbose); |
| 188 | + } |
| 189 | +} |
| 190 | + |
| 191 | +// Test order of convergence between finite difference PK2 stress and compute_pk2cc() PK2 stress for random F (medium) |
| 192 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestPK2StressConvergenceOrderAgainstReferenceRandomFMedium) { |
| 193 | + verbose = false; // Show order of convergence, errors, F, S |
| 194 | + |
| 195 | + // Loop over F in F_medium_list |
| 196 | + for (auto F_std : F_medium_list) { |
| 197 | + // Convert to C array |
| 198 | + convertToArray(F_std, F); |
| 199 | + |
| 200 | + // Check order of convergence between finite difference and compute_pk2cc() PK2 stress |
| 201 | + Array<double> S_ref(3,3), Dm(6,6); |
| 202 | + TestCANNHO->compute_pk2cc(F,S_ref,Dm); // Computing S_ref from CANN |
| 203 | + TestHO->testPK2StressConvergenceOrderAgainstReference(F, S_ref, delta_max, delta_min, order, convergence_order_tol, verbose); |
| 204 | + } |
| 205 | +} |
| 206 | + |
| 207 | +// Test order of convergence between finite difference PK2 stress and compute_pk2cc() PK2 stress for random F (large) |
| 208 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestPK2StressConvergenceOrderAgainstReferenceRandomFLarge) { |
| 209 | + verbose = false; // Show order of convergence, errors, F, S |
| 210 | + |
| 211 | + // Use struct |
| 212 | + //TestQVP->ustruct = false; |
| 213 | + // Loop over F in F_large_list |
| 214 | + for (auto F_std : F_large_list) { |
| 215 | + // Convert to C array |
| 216 | + convertToArray(F_std, F); |
| 217 | + |
| 218 | + // Check order of convergence between finite difference and compute_pk2cc() PK2 stress |
| 219 | + Array<double> S_ref(3,3), Dm(6,6); |
| 220 | + TestCANNHO->compute_pk2cc(F,S_ref,Dm); // Computing S_ref from CANN |
| 221 | + TestHO->testPK2StressConvergenceOrderAgainstReference(F,S_ref, delta_max, delta_min, order, convergence_order_tol, verbose); |
| 222 | + } |
| 223 | +} |
| 224 | + |
| 225 | +// Test order of convergence of consistency of material elasticity for random F (small) |
| 226 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestMaterialElasticityConsistencyConvergenceOrderAgainstHORandomFSmall) { |
| 227 | + verbose = false; // Show order of convergence, errors, F, S |
| 228 | + |
| 229 | + // Loop over F in F_small_list |
| 230 | + for (auto F_std : F_small_list) { |
| 231 | + // Convert to C array |
| 232 | + convertToArray(F_std, F); |
| 233 | + // Generating perturbation |
| 234 | + Array<double> dF(3,3); |
| 235 | + std::vector<double> deltas; |
| 236 | + TestHO->generatePerturbationdF(F,dF,delta_max, delta_min, deltas,order,verbose); |
| 237 | + // Calculating dS and CCdE |
| 238 | + Array<double> dS(3,3), CCdE(3,3); |
| 239 | + for (int i = 0; i < deltas.size(); i++) { |
| 240 | + TestCANNHO->calcCCdEFiniteDifference(F, dF, deltas[i], order, CCdE); |
| 241 | + TestHO->calcdSFiniteDifference(F, dF, deltas[i], order, dS); |
| 242 | + |
| 243 | + // Check order of convergence of consistency of material elasticity |
| 244 | + TestHO->testMaterialElasticityConsistencyConvergenceOrderBetweenMaterialModels(F, dS, CCdE, deltas, order, convergence_order_tol, verbose); |
| 245 | + } |
| 246 | + } |
| 247 | +} |
| 248 | + |
| 249 | +// Test order of convergence of consistency of material elasticity for random F (medium) |
| 250 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestMaterialElasticityConsistencyConvergenceOrderAgainstHORandomFMedium) { |
| 251 | + verbose = false; // Show order of convergence, errors, F, S |
| 252 | + |
| 253 | + // Loop over F in F_medium_list |
| 254 | + for (auto F_std : F_medium_list) { |
| 255 | + // Convert to C array |
| 256 | + convertToArray(F_std, F); |
| 257 | + // Generating perturbation |
| 258 | + Array<double> dF(3,3); |
| 259 | + std::vector<double> deltas; |
| 260 | + TestHO->generatePerturbationdF(F,dF,delta_max, delta_min, deltas,order,verbose); |
| 261 | + // Calculating dS and CCdE |
| 262 | + Array<double> dS(3,3), CCdE(3,3); |
| 263 | + for (int i = 0; i < deltas.size(); i++) { |
| 264 | + TestCANNHO->calcCCdEFiniteDifference(F, dF, deltas[i], order, CCdE); |
| 265 | + TestHO->calcdSFiniteDifference(F, dF, deltas[i], order, dS); |
| 266 | + |
| 267 | + // Check order of convergence of consistency of material elasticity |
| 268 | + TestHO->testMaterialElasticityConsistencyConvergenceOrderBetweenMaterialModels(F, dS, CCdE, deltas, order, convergence_order_tol, verbose); |
| 269 | + } |
| 270 | + } |
| 271 | +} |
| 272 | + |
| 273 | +// Test order of convergence of consistency of material elasticity for random F (large) |
| 274 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestMaterialElasticityConsistencyConvergenceOrderAgainstHORandomFLarge) { |
| 275 | + verbose = false; // Show order of convergence, errors, F, S |
| 276 | + |
| 277 | + // Loop over F in F_large_list |
| 278 | + for (auto F_std : F_large_list) { |
| 279 | + // Convert to array |
| 280 | + convertToArray(F_std, F); |
| 281 | + // Generating perturbation |
| 282 | + Array<double> dF(3,3); |
| 283 | + std::vector<double> deltas; |
| 284 | + TestHO->generatePerturbationdF(F,dF,delta_max, delta_min, deltas,order,verbose); |
| 285 | + // Calculating dS and CCdE |
| 286 | + Array<double> dS(3,3), CCdE(3,3); |
| 287 | + for (int i = 0; i < deltas.size(); i++) { |
| 288 | + TestCANNHO->calcCCdEFiniteDifference(F, dF, deltas[i], order, CCdE); |
| 289 | + TestHO->calcdSFiniteDifference(F, dF, deltas[i], order, dS); |
| 290 | + |
| 291 | + // Check order of convergence of consistency of material elasticity |
| 292 | + TestHO->testMaterialElasticityConsistencyConvergenceOrderBetweenMaterialModels(F, dS, CCdE, deltas, order, convergence_order_tol, verbose); |
| 293 | + } |
| 294 | + } |
| 295 | +} |
| 296 | + |
| 297 | +// Test PK2 stress |
| 298 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestMaterialElasticityAgainstReferenceIdentityF) { |
| 299 | + verbose = false; // Show values of CC and CC_ref |
| 300 | + |
| 301 | + // Check identity F produces zero PK2 stress |
| 302 | + Array<double> F = {{1.0, 0.0, 0.0}, |
| 303 | + {0.0, 1.0, 0.0}, |
| 304 | + {0.0, 0.0, 1.0}}; |
| 305 | + Tensor4<double> CC_ref(3,3,3,3); // CC_ref initialized to zero |
| 306 | + for (int i = 0; i < 3; i++){ |
| 307 | + for (int j = 0; j < 3; j++){ |
| 308 | + for (int k = 0; k < 3; k++){ |
| 309 | + for (int l = 0; l < 3; l++){ |
| 310 | + CC_ref(i,j,k,l) = 0; |
| 311 | + } |
| 312 | + } |
| 313 | + } |
| 314 | + } |
| 315 | + TestHO->calcMaterialElasticityReference(F,CC_ref,verbose); |
| 316 | + TestCANNHO->testMaterialElasticityAgainstReference(F, CC_ref, rel_tol, abs_tol, verbose); // Comparing with CANN |
| 317 | +} |
| 318 | + |
| 319 | +// Test PK2 stress |
| 320 | +TEST_F(STRUCT_CANNHolzapfelOgdenTest, TestMaterialElasticityAgainstReference) { |
| 321 | + verbose = false; // Show values of CC and CC_ref |
| 322 | + |
| 323 | + // Check identity F produces zero PK2 stress |
| 324 | + Array<double> F = {{1.1, 0.0, 0.0}, |
| 325 | + {0.0, 1.2, 0.0}, |
| 326 | + {0.0, 0.0, 0.757}}; |
| 327 | + Tensor4<double> CC_ref(3,3,3,3); // CC_ref initialized to zero |
| 328 | + for (int i = 0; i < 3; i++){ |
| 329 | + for (int j = 0; j < 3; j++){ |
| 330 | + for (int k = 0; k < 3; k++){ |
| 331 | + for (int l = 0; l < 3; l++){ |
| 332 | + CC_ref(i,j,k,l) = 0; |
| 333 | + } |
| 334 | + } |
| 335 | + } |
| 336 | + } |
| 337 | + TestHO->calcMaterialElasticityReference(F,CC_ref,verbose); |
| 338 | + TestCANNHO->testMaterialElasticityAgainstReference(F, CC_ref, rel_tol, abs_tol, verbose); // Comparing with CANN |
| 339 | +} |
| 340 | + |
| 341 | + |
| 342 | + |
| 343 | + |
| 344 | + |
| 345 | + |
| 346 | + |
0 commit comments