Skip to content

Commit 7c78a71

Browse files
Refactoring CANN NH and HO tests. Fix typo in holzapfel_ogden header guard
1 parent 405bf5e commit 7c78a71

File tree

6 files changed

+925
-3
lines changed

6 files changed

+925
-3
lines changed

Code/Source/solver/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ if(ENABLE_UNIT_TEST)
321321
"../../../tests/unitTests/test_material_mooney_rivlin.cpp"
322322
"../../../tests/unitTests/test_material_holzapfel_ogden.cpp"
323323
"../../../tests/unitTests/test_material_holzapfel_ogden_MA.cpp"
324+
"../../../tests/unitTests/test_material_CANN_neohookean.cpp"
325+
"../../../tests/unitTests/test_material_CANN_holzapfel_ogden.cpp"
324326
)
325327

326328
list(REMOVE_ITEM CSRCS "main.cpp")
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
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

Comments
 (0)