MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
mast_solid_1d_section_element_property_card.cpp
Go to the documentation of this file.
1 // Catch2 includes
2 #include "catch.hpp"
3 
4 // libMesh includes
5 #include "libmesh/point.h"
6 
7 // MAST includes
8 #include "base/parameter.h"
12 
13 // Custom includes
14 #include "test_helpers.h"
15 
16 extern libMesh::LibMeshInit* p_global_init;
17 
18 
23 TEST_CASE("solid_element_property_card_constant_base_1d",
24  "[1D],[isotropic],[constant],[property]")
25 {
26  const uint dim = 1;
27 
28  // Define Material Properties as MAST Parameters
29  MAST::Parameter rho("rho_param", 1420.5); // Density
30  MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity
31  MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio
32  MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient
33  MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity
34  MAST::Parameter k("k_param", 237.0); // Thermal Conductivity
35 
36  // Define Section Properties as MAST Parameters
37  MAST::Parameter thickness_y("hz", 3.0); // Section thickness in z-direction
38  MAST::Parameter thickness_z("hy", 0.75); // Section thickness in y-direction
39  MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction
40  MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction
41  MAST::Parameter Kzz("Kzz", 8.3330248143102326e-01);
42  MAST::Parameter Kyy("Kyy", 5.5763491072129889e-01);
43 
44  // Create field functions to dsitribute these constant parameters throughout the model
45  // Section Property Field Functions
46  MAST::ConstantFieldFunction thickness_y_f("hz", thickness_y);
47  MAST::ConstantFieldFunction thickness_z_f("hy", thickness_z);
48  MAST::ConstantFieldFunction offsety_f("hy_off", offset_y);
49  MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z);
50  MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz);
51  MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy);
52 
53  // Material Property Field Functions
54  MAST::ConstantFieldFunction rho_f("rho", rho);
55  MAST::ConstantFieldFunction E_f("E", E);
56  MAST::ConstantFieldFunction nu_f("nu", nu);
57  MAST::ConstantFieldFunction cp_f("cp", cp);
58  MAST::ConstantFieldFunction k_f("k_th", k);
59 
60  // Initialize the material
62 
63  // Add the material property constant field functions to the material card
64  material.add(rho_f);
65  material.add(k_f);
66  material.add(cp_f);
67  material.add(E_f);
68  material.add(nu_f);
69 
70  // Initialize the section
72 
73  // Add the section property constant field functions to the section card
74  section.add(thickness_y_f);
75  section.add(thickness_z_f);
76  section.add(offsety_f);
77  section.add(offsetz_f);
78  section.add(Kzz_f);
79  section.add(Kyy_f);
80 
81  // Add the material card to the section card
82  section.set_material(material);
83 
84  // Specify a section orientation point and add it to the section.
85  RealVectorX orientation = RealVectorX::Zero(3);
86  orientation(1) = 1.0;
87  section.y_vector() = orientation;
88 
89  // Now initialize the section
90  section.init();
91 
92  REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional
93  REQUIRE( section.depends_on(thickness_y) );
94  REQUIRE( section.depends_on(offset_y) );
95  REQUIRE( section.depends_on(thickness_z) );
96  REQUIRE( section.depends_on(offset_z) );
97  REQUIRE( section.depends_on(k) );
98  REQUIRE( section.depends_on(cp) );
99  REQUIRE( section.depends_on(rho) );
100  REQUIRE( section.if_isotropic() );
101 
102  // True values calculated using the sectionproperties module in python BAR.py
103  const Real area_true = 2.2500000000000004e+00;
104  const Real torsion_constant_true = 3.5540414988249380e-01;
105  const Real first_area_moment_z_true = 6.4574999999999994e-01;
106  const Real first_area_moment_y_true = 3.7214999999999945e+00;
107  const Real second_area_moment_zz_true = 2.9079899999999986e-01;
108  const Real second_area_moment_yy_true = 7.8428609999999814e+00;
109  const Real second_area_moment_zy_true = 1.0680705000000006e+00;
110  const Real second_area_moment_polar_true = 8.1336599999999812e+00;
111  const Real Izzc_true = 1.0546874999999994e-01;
112  const Real Iyyc_true = 1.6875000000000009e+00;
113  const Real Izyc_true = 2.4424906541753444e-15;
114  const Real warping_constant_true = 6.1030611538894504e-02;
115  const Real kappa_z_true = 8.3330248143102326e-01;
116  const Real kappa_y_true = 5.5763491072129889e-01;
117  const Real xs_true = 1.6540000458463804e+00;
118  const Real ys_true = 2.8700000023051281e-01;
119  const Real xst_true = 1.6540000458463804e+00;
120  const Real yst_true = 2.8700000023051281e-01;
121  const libMesh::Point shear_center_true(xs_true, ys_true, 0.);
122  const libMesh::Point centroid_true(1.654, 0.287, 0.);
123 
124  // NOTE: The default 1D section is rectangular
125  const libMesh::Point point(4.3, -3.5, -6.7);
126  const Real time = 8.22;
127 
128  Real area;
129  const MAST::FieldFunction<Real>& Area = section.A();
130  Area(point, time, area);
131  REQUIRE( area == Approx(area_true) );
132 
133  Real first_area_moment_y;
134  const MAST::FieldFunction<Real>& Ay = section.Ay();
135  Ay(point, time, first_area_moment_y);
136  CHECK( first_area_moment_y == Approx(first_area_moment_y_true) );
137 
138  Real first_area_moment_z;
139  const MAST::FieldFunction<Real>& Az = section.Az();
140  Az(point, time, first_area_moment_z);
141  CHECK( first_area_moment_z == Approx(first_area_moment_z_true) );
142 
143  RealMatrixX I;
144  const MAST::FieldFunction<RealMatrixX>& Inertias = section.I();
145  Inertias(point, time, I);
146  REQUIRE( I(0,1) == I(1,0) );
147  Real Iyy = I(1,1);
148  Real Izz = I(0,0);
149  Real Izy = I(0,1);
150  REQUIRE( Izz == Approx(second_area_moment_zz_true) );
151  REQUIRE( Iyy == Approx(second_area_moment_yy_true) );
152  REQUIRE( Izy == Approx(second_area_moment_zy_true) );
153 
154  Real Ip;
155  const MAST::FieldFunction<Real>& PolarInertia = section.Ip();
156  PolarInertia(point, time, Ip);
157  REQUIRE( Ip == Approx(second_area_moment_polar_true) );
158 
159  Real torsion_constant;
160  const MAST::FieldFunction<Real>& TorsionConstant = section.J();
161  TorsionConstant(point, time, torsion_constant);
162  REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.005) );
163 
164 // Real warping_constant;
165 // const MAST::FieldFunction<Real>& WarpingConstant = section.Gam();
166 // WarpingConstant(point, time, warping_constant);
167 // REQUIRE( warping_constant == Approx(warping_constant_true) );
168 
169  RealMatrixX shear_coefficients;
170  const MAST::FieldFunction<RealMatrixX>& ShearCoefficientMatrix = section.Kap();
171  ShearCoefficientMatrix(point, time, shear_coefficients);
172  REQUIRE( shear_coefficients(0,0) == Approx(kappa_z_true) );
173  REQUIRE( shear_coefficients(1,1) == Approx(kappa_y_true) );
174 
175 // libMesh::Point centroid = section.cross_section->get_centroid(p, t);
176 // REQUIRE( centroid(0) == Approx(centroid_true(0)) );
177 // REQUIRE( centroid(1) == Approx(centroid_true(1)) );
178 
179 // libMesh::Point shear_center = section.cross_section->get_shear_center(p, t);
180 // REQUIRE(shear_center(0) == Approx(xs_true));
181 // REQUIRE(shear_center(1) == Approx(ys_true));
182 
183  REQUIRE_FALSE( section.if_diagonal_mass_matrix() );
184 
185  section.set_diagonal_mass_matrix(true);
186  REQUIRE( section.if_diagonal_mass_matrix() );
187 }
188 
189 
194 TEST_CASE("solid_element_property_card_constant_base_sensitivity_1d",
195  "[1D],[isotropic],[constant],[property],[sensitivity]")
196 {
197  const uint dim = 1;
198 
199  // Define Material Properties as MAST Parameters
200  MAST::Parameter rho("rho_param", 1420.5); // Density
201  MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity
202  MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio
203  MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient
204  MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity
205  MAST::Parameter k("k_param", 237.0); // Thermal Conductivity
206 
207  // Define Section Properties as MAST Parameters
208  MAST::Parameter thickness_y("hz", 3.0); // Section thickness in z-direction
209  MAST::Parameter thickness_z("hy", 0.75); // Section thickness in y-direction
210  MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction
211  MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction
212  MAST::Parameter Kzz("Kzz", 8.3330248143102326e-01);
213  MAST::Parameter Kyy("Kyy", 5.5763491072129889e-01);
214 
215  // Define Sensitivity Parameters
216  std::vector<MAST::Parameter*> sens_params = {&thickness_y, &thickness_z};
217  uint n_s = sens_params.size();
218 
219  // Create field functions to dsitribute these constant parameters throughout the model
220  // Section Property Field Functions
221  MAST::ConstantFieldFunction thickness_y_f("hz", thickness_y);
222  MAST::ConstantFieldFunction thickness_z_f("hy", thickness_z);
223  MAST::ConstantFieldFunction offsety_f("hy_off", offset_y);
224  MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z);
225  MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz);
226  MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy);
227 
228  // Material Property Field Functions
229  MAST::ConstantFieldFunction rho_f("rho", rho);
230  MAST::ConstantFieldFunction E_f("E", E);
231  MAST::ConstantFieldFunction nu_f("nu", nu);
232  MAST::ConstantFieldFunction cp_f("cp", cp);
233  MAST::ConstantFieldFunction k_f("k_th", k);
234 
235  // Initialize the material
237 
238  // Add the material property constant field functions to the material card
239  material.add(rho_f);
240  material.add(k_f);
241  material.add(cp_f);
242  material.add(E_f);
243  material.add(nu_f);
244 
245  // Initialize the section
247 
248  // Add the section property constant field functions to the section card
249  section.add(thickness_y_f);
250  section.add(thickness_z_f);
251  section.add(offsety_f);
252  section.add(offsetz_f);
253  section.add(Kzz_f);
254  section.add(Kyy_f);
255 
256  // Add the material card to the section card
257  section.set_material(material);
258 
259  // Specify a section orientation point and add it to the section.
260  RealVectorX orientation = RealVectorX::Zero(3);
261  orientation(1) = 1.0;
262  section.y_vector() = orientation;
263 
264  // Now initialize the section
265  section.init();
266 
267  REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional
268  REQUIRE( section.depends_on(thickness_y) );
269  REQUIRE( section.depends_on(offset_y) );
270  REQUIRE( section.depends_on(thickness_z) );
271  REQUIRE( section.depends_on(offset_z) );
272  REQUIRE( section.depends_on(k) );
273  REQUIRE( section.depends_on(cp) );
274  REQUIRE( section.depends_on(rho) );
275  REQUIRE( section.if_isotropic() );
276 
277  // True values calculated using the sectionproperties module in python BAR.py
278  const Real area_true = 2.2500000000000004e+00;
279  const Real torsion_constant_true = 3.5540414988249380e-01;
280  const Real first_area_moment_z_true = 6.4574999999999994e-01;
281  const Real first_area_moment_y_true = 3.7214999999999945e+00;
282  const Real second_area_moment_zz_true = 2.9079899999999986e-01;
283  const Real second_area_moment_yy_true = 7.8428609999999814e+00;
284  const Real second_area_moment_zy_true = 1.0680705000000006e+00;
285  const Real second_area_moment_polar_true = 8.1336599999999812e+00;
286  const Real Izzc_true = 1.0546874999999994e-01;
287  const Real Iyyc_true = 1.6875000000000009e+00;
288  const Real Izyc_true = 2.4424906541753444e-15;
289  const Real warping_constant_true = 6.1030611538894504e-02;
290  const Real kappa_z_true = 8.3330248143102326e-01;
291  const Real kappa_y_true = 5.5763491072129889e-01;
292  const Real xs_true = 1.6540000458463804e+00;
293  const Real ys_true = 2.8700000023051281e-01;
294  const Real xst_true = 1.6540000458463804e+00;
295  const Real yst_true = 2.8700000023051281e-01;
296  const libMesh::Point shear_center_true(xs_true, ys_true, 0.);
297 
298  const libMesh::Point centroid_true(1.654, 0.287);
299  Real stress_C_x, stress_C_y, stress_D_x, stress_D_y;
300  Real stress_E_x, stress_E_y, stress_F_x, stress_F_y;
301 
302  const libMesh::Point point(4.3, -3.5, -6.7);
303  const Real time = 8.22;
304 
305  Real dA_dthickness_y, dA_dthickness_z;
306  Real dCz_dthickness_y, dCz_dthickness_z;
307  Real dCy_dthickness_y, dCy_dthickness_z;
308  Real dQz_dthickness_y, dQz_dthickness_z;
309  Real dQy_dthickness_y, dQy_dthickness_z;
310  Real dIzz_dthickness_y, dIzz_dthickness_z;
311  Real dIyy_dthickness_y, dIyy_dthickness_z;
312  Real dIzy_dthickness_y, dIzy_dthickness_z;
313  Real dIp_dthickness_y, dIp_dthickness_z;
314  Real dIzzc_dthickness_y, dIzzc_dthickness_z;
315  Real dIyyc_dthickness_y, dIyyc_dthickness_z;
316  Real dIzyc_dthickness_y, dIzyc_dthickness_z;
317  Real dIpc_dthickness_y, dIpc_dthickness_z;
318  Real dJ_dthickness_y, dJ_dthickness_z;
319  Real dxs_dthickness_y, dxs_dthickness_z;
320  Real dys_dthickness_y, dys_dthickness_z;
321  Real dW_dthickness_y, dW_dthickness_z;
322 
323  Real f_h, f_2h, f_n, f_2n;
324  RealVectorX fv_h, fv_2h, fv_n, fv_2n;
325  RealMatrixX fm_h, fm_2h, fm_n, fm_2n;
326 
327  const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25)
328 
329  // Area Sensitivity Check
330  const MAST::FieldFunction<Real>& Area = section.A();
331  std::vector<Real> dA(n_s);
332  for (uint i=0; i<n_s; i++)
333  {
334  Area.derivative(*sens_params[i], point, time, dA[i]);
335  }
336 
337  std::vector<Real> dA_cd(n_s);
338  for (uint i=0; i<n_s; i++)
339  {
340  (*sens_params[i])() += delta;
341  Area(point, time, f_h);
342 
343  (*sens_params[i])() += delta;
344  Area(point, time, f_2h);
345 
346  (*sens_params[i])() -= 3.0*delta;
347  Area(point, time, f_n);
348 
349  (*sens_params[i])() -= delta;
350  Area(point, time, f_2n);
351 
352  (*sens_params[i])() += 2.0*delta;
353 
354  dA_cd[i] = (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta);
355 
356  libMesh::out << "dA_d" << sens_params[i]->name() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl;
357  REQUIRE(dA[i] == Approx(dA_cd[i]));
358  }
359 
360 
361 // // Centroid Sensitivity Check
362 // std::vector<libMesh::Point> dC(n_s);
363 // for (uint i=0; i<n_s; i++)
364 // {
365 // dC[i] = section.cross_section->get_centroid_derivative(*sens_params[i], point, time);
366 // }
367 //
368 // libMesh::Point fp_h, fp_2h, fp_n, fp_2n;
369 // std::vector<libMesh::Point> dC_cd(n_s);
370 // for (uint i=0; i<n_s; i++)
371 // {
372 // (*sens_params[i])() += delta;
373 // fp_h = section.cross_section->get_centroid(point, time);
374 //
375 // (*sens_params[i])() += delta;
376 // fp_2h = section.cross_section->get_centroid(point, time);
377 //
378 // (*sens_params[i])() -= 3.0*delta;
379 // fp_n = section.cross_section->get_centroid(point, time);
380 //
381 // (*sens_params[i])() -= delta;
382 // fp_2n = section.cross_section->get_centroid(point, time);
383 //
384 // (*sens_params[i])() += 2.0*delta;
385 //
386 // dC_cd[i] = (fp_2n - 8.*fp_n + 8*fp_h - fp_2h)/(12.*delta);
387 //
388 // libMesh::out << "dC_d" << sens_params[i]->name() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl;
389 // REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) );
390 // REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) );
391 // }
392 
393  // First Area Moments Sensitivity Check
394  const MAST::FieldFunction<Real>& Area_y = section.Ay();
395  std::vector<Real> dAy(n_s);
396  for (uint i=0; i<n_s; i++)
397  {
398  Area_y.derivative(*sens_params[i], point, time, dAy[i]);
399  }
400 
401  std::vector<Real> dAy_cd(n_s);
402  for (uint i=0; i<n_s; i++)
403  {
404  (*sens_params[i])() += delta;
405  Area_y(point, time, f_h);
406 
407  (*sens_params[i])() += delta;
408  Area_y(point, time, f_2h);
409 
410  (*sens_params[i])() -= 3.0*delta;
411  Area_y(point, time, f_n);
412 
413  (*sens_params[i])() -= delta;
414  Area_y(point, time, f_2n);
415 
416  (*sens_params[i])() += 2.0*delta;
417 
418  dAy_cd[i] = (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta);
419 
420  libMesh::out << "dAy_d" << sens_params[i]->name() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl;
421  REQUIRE(dAy[i] == Approx(dAy_cd[i]));
422  }
423 
424 
425  const MAST::FieldFunction<Real>& Area_z = section.Az();
426  std::vector<Real> dAz(n_s);
427  for (uint i=0; i<n_s; i++)
428  {
429  Area_z.derivative(*sens_params[i], point, time, dAz[i]);
430  }
431 
432  std::vector<Real> dAz_cd(n_s);
433  for (uint i=0; i<n_s; i++)
434  {
435  (*sens_params[i])() += delta;
436  Area_z(point, time, f_h);
437 
438  (*sens_params[i])() += delta;
439  Area_z(point, time, f_2h);
440 
441  (*sens_params[i])() -= 3.0*delta;
442  Area_z(point, time, f_n);
443 
444  (*sens_params[i])() -= delta;
445  Area_z(point, time, f_2n);
446 
447  (*sens_params[i])() += 2.0*delta;
448 
449  dAz_cd[i] = (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta);
450 
451  libMesh::out << "dAz_d" << sens_params[i]->name() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl;
452  REQUIRE(dAz[i] == Approx(dAz_cd[i]));
453  }
454 
455 
456  // Second Area Moments Sensitivity Check
457  const MAST::FieldFunction<RealMatrixX>& Inertia = section.I();
458  std::vector<RealMatrixX> dI(n_s);
459  for (uint i=0; i<n_s; i++)
460  {
461  Inertia.derivative(*sens_params[i], point, time, dI[i]);
462  }
463 
464  std::vector<RealMatrixX> dI_cd(n_s);
465  for (uint i=0; i<n_s; i++)
466  {
467  (*sens_params[i])() += delta;
468  Inertia(point, time, fm_h);
469 
470  (*sens_params[i])() += delta;
471  Inertia(point, time, fm_2h);
472 
473  (*sens_params[i])() -= 3.0*delta;
474  Inertia(point, time, fm_n);
475 
476  (*sens_params[i])() -= delta;
477  Inertia(point, time, fm_2n);
478 
479  (*sens_params[i])() += 2.0*delta;
480 
481  dI_cd[i] = (fm_2n - 8.*fm_n + 8*fm_h - fm_2h)/(12.*delta);
482 
483  libMesh::out << "dI_d" << sens_params[i]->name() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl;
484 
485  Real dIzz = dI[i](0,0);
486  Real dIyy = dI[i](1,1);
487  Real dIyz = dI[i](1,0);
488  Real dIzy = dI[i](0,1);
489 
490  Real dIzz_cd = dI_cd[i](0,0);
491  Real dIyy_cd = dI_cd[i](1,1);
492  Real dIyz_cd = dI_cd[i](1,0);
493  Real dIzy_cd = dI_cd[i](0,1);
494 
495  REQUIRE(dIzz == Approx(dIzz_cd));
496  REQUIRE(dIyy == Approx(dIyy_cd));
497  REQUIRE(dIyz == Approx(dIyz_cd));
498  REQUIRE(dIzy == Approx(dIzy_cd));
499  REQUIRE(dIyz == dIzy); // symmetry check
500  }
501 
502 
503  // Second Area Polar Moment Sensitivity Check
504  const MAST::FieldFunction<Real>& PolarInertia = section.Ip();
505  std::vector<Real> dIp(n_s);
506  for (uint i=0; i<n_s; i++)
507  {
508  PolarInertia.derivative(*sens_params[i], point, time, dIp[i]);
509  }
510 
511  std::vector<Real> dIp_cd(n_s);
512  for (uint i=0; i<n_s; i++)
513  {
514  (*sens_params[i])() += delta;
515  PolarInertia(point, time, f_h);
516 
517  (*sens_params[i])() += delta;
518  PolarInertia(point, time, f_2h);
519 
520  (*sens_params[i])() -= 3.0*delta;
521  PolarInertia(point, time, f_n);
522 
523  (*sens_params[i])() -= delta;
524  PolarInertia(point, time, f_2n);
525 
526  (*sens_params[i])() += 2.0*delta;
527 
528  dIp_cd[i] = (f_2n - 8.*f_n + 8.*f_h - f_2h)/(12.*delta);
529 
530  libMesh::out << "dIp_d" << sens_params[i]->name() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl;
531  REQUIRE(dIp[i] == Approx(dIp_cd[i]));
532  }
533 
534 
535 // // Shear Center Sensitivity Check
536 // std::vector<libMesh::Point> dCs(n_s);
537 // for (uint i=0; i<n_s; i++)
538 // {
539 // dCs[i] = section.cross_section->get_shear_center_derivative(*sens_params[i], point, time);
540 // }
541 //
542 // std::vector<libMesh::Point> dCs_cd(n_s);
543 // for (uint i=0; i<n_s; i++)
544 // {
545 // (*sens_params[i])() += delta;
546 // fp_h = section.cross_section->get_shear_center(point, time);
547 //
548 // (*sens_params[i])() += delta;
549 // fp_2h = section.cross_section->get_shear_center(point, time);
550 //
551 // (*sens_params[i])() -= 3.0*delta;
552 // fp_n = section.cross_section->get_shear_center(point, time);
553 //
554 // (*sens_params[i])() -= delta;
555 // fp_2n = section.cross_section->get_shear_center(point, time);
556 //
557 // (*sens_params[i])() += 2.0*delta;
558 //
559 // dCs_cd[i] = (fp_2n - 8.*fp_n + 8.*fp_h - fp_2h)/(12.*delta);
560 //
561 // libMesh::out << "dCs_d" << sens_params[i]->name() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl;
562 // REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) );
563 // REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) );
564 // }
565 
566 
567  // Torsion Constant Sensitivity Check
568  // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity.
569  MAST::FieldFunction<Real>& TorsionConstant = section.J();
570  std::vector<Real> dJ(n_s);
571  for (uint i=0; i<n_s; i++)
572  {
573  TorsionConstant.derivative(*sens_params[i], point, time, dJ[i]);
574  }
575 
576  std::vector<Real> dJ_cd(n_s);
577  for (uint i=0; i<n_s; i++)
578  {
579  (*sens_params[i])() += delta;
580  TorsionConstant(point, time, f_h);
581 
582  (*sens_params[i])() += delta;
583  TorsionConstant(point, time, f_2h);
584 
585  (*sens_params[i])() -= 3.0*delta;
586  TorsionConstant(point, time, f_n);
587 
588  (*sens_params[i])() -= delta;
589  TorsionConstant(point, time, f_2n);
590 
591  (*sens_params[i])() += 2.0*delta;
592 
593  dJ_cd[i] = (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta);
594 
595  libMesh::out << "dJ_d" << sens_params[i]->name() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl;
596  REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) );
597  // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference
598  }
599 
600 
601 // // Shear Coefficient Sensitivity Check
602 // // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity.
603 // MAST::FieldFunction<RealMatrixX>& Kappa = section.Kap();
604 // std::vector<RealMatrixX> dK(n_s);
605 // for (uint i=0; i<n_s; i++)
606 // {
607 // Kappa.derivative(*sens_params[i], point, time, dK[i]);
608 // }
609 //
610 // std::vector<RealMatrixX> dK_cd(n_s);
611 // for (uint i=0; i<n_s; i++)
612 // {
613 // (*sens_params[i])() += delta;
614 // Kappa(point, time, fm_h);
615 //
616 // (*sens_params[i])() += delta;
617 // Kappa(point, time, fm_2h);
618 //
619 // (*sens_params[i])() -= 3.0*delta;
620 // Kappa(point, time, fm_n);
621 //
622 // (*sens_params[i])() -= delta;
623 // Kappa(point, time, fm_2n);
624 //
625 // (*sens_params[i])() += 2.0*delta;
626 //
627 // dK_cd[i] = (fm_2n - 8.*fm_n + 8*fm_h - fm_2h)/(12.*delta);
628 //
629 // libMesh::out << "dK_d" << sens_params[i]->name() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl;
630 //
631 // Real dKzz = dK[i](0,0);
632 // Real dKyy = dK[i](1,1);
633 // Real dKyz = dK[i](1,0);
634 // Real dKzy = dK[i](0,1);
635 //
636 // Real dKzz_cd = dK_cd[i](0,0);
637 // Real dKyy_cd = dK_cd[i](1,1);
638 // Real dKyz_cd = dK_cd[i](1,0);
639 // Real dKzy_cd = dK_cd[i](0,1);
640 //
641 // REQUIRE(dKzz == Approx(dKzz_cd).epsilon(0.1));
642 // REQUIRE(dKyy == Approx(dKyy_cd).epsilon(0.1));
643 // //REQUIRE(dKyz == Approx(dKyz_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13)
644 // //REQUIRE(dKzy == Approx(dKzy_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13)
645 // // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference
646 // REQUIRE(dKyz == dKzy); // symmetry check
647 // }
648 
649 
650  // Warping Constant Sensitivity Check
651  // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity.
652  MAST::FieldFunction<Real>& WarpingConstant = section.Gam();
653  std::vector<Real> dW(n_s);
654  for (uint i=0; i<n_s; i++)
655  {
656  WarpingConstant.derivative(*sens_params[i], point, time, dW[i]);
657  }
658 
659  std::vector<Real> dW_cd(n_s);
660  for (uint i=0; i<n_s; i++)
661  {
662  (*sens_params[i])() += delta;
663  WarpingConstant(point, time, f_h);
664 
665  (*sens_params[i])() += delta;
666  WarpingConstant(point, time, f_2h);
667 
668  (*sens_params[i])() -= 3.0*delta;
669  WarpingConstant(point, time, f_n);
670 
671  (*sens_params[i])() -= delta;
672  WarpingConstant(point, time, f_2n);
673 
674  (*sens_params[i])() += 2.0*delta;
675 
676  dW_cd[i] = (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta);
677 
678  libMesh::out << "dW_d" << sens_params[i]->name() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl;
679  REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) );
680  // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference
681  }
682 }
683 
684 
685 TEST_CASE("solid_element_property_card_constant_heat_transfer_1d",
686  "[heat_transfer],[1D],[isotropic],[constant],[property]")
687 {
688  const uint dim = 1;
689 
690  // Define Material Properties as MAST Parameters
691  MAST::Parameter rho("rho_param", 1420.5); // Density
692  MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity
693  MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio
694  MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient
695  MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity
696  MAST::Parameter k("k_param", 237.0); // Thermal Conductivity
697 
698  // Define Section Properties as MAST Parameters
699  MAST::Parameter thickness_y("hz", 3.0); // Section thickness in z-direction
700  MAST::Parameter thickness_z("hy", 0.75); // Section thickness in y-direction
701  MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction
702  MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction
703  MAST::Parameter Kzz("Kzz", 8.3330248143102326e-01);
704  MAST::Parameter Kyy("Kyy", 5.5763491072129889e-01);
705 
706  // Create field functions to dsitribute these constant parameters throughout the model
707  // Section Property Field Functions
708  MAST::ConstantFieldFunction thickness_y_f("hz", thickness_y);
709  MAST::ConstantFieldFunction thickness_z_f("hy", thickness_z);
710  MAST::ConstantFieldFunction offsety_f("hy_off", offset_y);
711  MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z);
712  MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz);
713  MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy);
714 
715  // Material Property Field Functions
716  MAST::ConstantFieldFunction rho_f("rho", rho);
717  MAST::ConstantFieldFunction E_f("E", E);
718  MAST::ConstantFieldFunction nu_f("nu", nu);
719  MAST::ConstantFieldFunction cp_f("cp", cp);
720  MAST::ConstantFieldFunction k_f("k_th", k);
721 
722  // Initialize the material
724 
725  // Add the material property constant field functions to the material card
726  material.add(rho_f);
727  material.add(k_f);
728  material.add(cp_f);
729  material.add(E_f);
730  material.add(nu_f);
731 
732  // Initialize the section
734 
735  // Add the section property constant field functions to the section card
736  section.add(thickness_y_f);
737  section.add(thickness_z_f);
738  section.add(offsety_f);
739  section.add(offsetz_f);
740  section.add(Kzz_f);
741  section.add(Kyy_f);
742 
743  // Add the material card to the section card
744  section.set_material(material);
745 
746 // // Specify a section orientation point and add it to the section.
747 // RealVectorX orientation = RealVectorX::Zero(3);
748 // orientation(1) = 1.0;
749 // section.y_vector() = orientation;
750 
751  // Now initialize the section
752  section.init();
753 
754  REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional
755  REQUIRE( section.depends_on(thickness_y) );
756  REQUIRE( section.depends_on(offset_y) );
757  REQUIRE( section.depends_on(thickness_z) );
758  REQUIRE( section.depends_on(offset_z) );
759  REQUIRE( section.depends_on(k) );
760  REQUIRE( section.depends_on(cp) );
761  REQUIRE( section.depends_on(rho) );
762  REQUIRE( section.if_isotropic() );
763 
764  // True values calculated using the sectionproperties module in python BAR.py
765  const Real area_true = 2.2500000000000004e+00;
766 
767  // NOTE: The default 1D section is rectangular
768  const libMesh::Point point(4.3, -3.5, -6.7);
769  const Real time = 8.22;
770 
771  Real area;
772  const MAST::FieldFunction<Real>& Area = section.A();
773  Area(point, time, area);
774  REQUIRE( area == Approx(area_true) );
775 
776 
777  SECTION("1D section thermal conductance matrix")
778  {
789  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> conduct_mat = section.thermal_conductance_matrix();
790 
791  const libMesh::Point point(2.3, 3.1, 5.2);
792  const Real time = 2.34;
793  RealMatrixX D_sec_conduc;
794  conduct_mat->operator()(point, time, D_sec_conduc);
795 
796  // Hard-coded value of the section's extension stiffness
797  RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1);
798  D_sec_conduc_true(0,0) = k() * area_true;
799 
800  // Convert the test and truth Eigen::Matrix objects to std::vector
801  // since Catch2 has built in methods to compare vectors
802  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_conduc);
803  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true);
804 
805  // Floating point approximations are diffcult to compare since the
806  // values typically aren't exactly equal due to numerical error.
807  // Therefore, we use the Approx comparison instead of Equals
808  CHECK_THAT( test, Catch::Approx<double>(truth) );
809  }
810 
811  SECTION("1D section thermal capacitance matrix")
812  {
823  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> capaci_mat = section.thermal_capacitance_matrix();
824 
825  const libMesh::Point point(2.3, 3.1, 5.2);
826  const Real time = 2.34;
827  RealMatrixX D_sec_capac;
828  capaci_mat->operator()(point, time, D_sec_capac);
829 
830  // Hard-coded value of the section's extension stiffness
831  RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1);
832  D_sec_capac_true(0,0) = cp() * rho() * area_true;
833 
834  // Convert the test and truth Eigen::Matrix objects to std::vector
835  // since Catch2 has built in methods to compare vectors
836  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_capac);
837  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true);
838 
839  // Floating point approximations are diffcult to compare since the
840  // values typically aren't exactly equal due to numerical error.
841  // Therefore, we use the Approx comparison instead of Equals
842  CHECK_THAT( test, Catch::Approx<double>(truth) );
843  }
844 }
845 
846 
847 TEST_CASE("solid_element_property_card_constant_thermoelastic_1d",
848  "[thermoelastic],[1D],[isotropic],[constant],[property]")
849 {
850  const uint dim = 1;
851 
852  // Define Material Properties as MAST Parameters
853  MAST::Parameter rho("rho_param", 1420.5); // Density
854  MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity
855  MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio
856  MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient
857  MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity
858  MAST::Parameter k("k_param", 237.0); // Thermal Conductivity
859  MAST::Parameter alpha("alpha_param", 5.43e-05); // Coefficient of thermal expansion
860 
861  // Define Section Properties as MAST Parameters
862  MAST::Parameter thickness_y("hz", 3.0); // Section thickness in z-direction
863  MAST::Parameter thickness_z("hy", 0.75); // Section thickness in y-direction
864  MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction
865  MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction
866  MAST::Parameter Kzz("Kzz", 8.3330248143102326e-01);
867  MAST::Parameter Kyy("Kyy", 5.5763491072129889e-01);
868 
869 
870  // Create field functions to dsitribute these constant parameters throughout the model
871  // Section Property Field Functions
872  MAST::ConstantFieldFunction thickness_y_f("hz", thickness_y);
873  MAST::ConstantFieldFunction thickness_z_f("hy", thickness_z);
874  MAST::ConstantFieldFunction offsety_f("hy_off", offset_y);
875  MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z);
876  MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz);
877  MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy);
878 
879 
880  // Material Property Field Functions
881  MAST::ConstantFieldFunction rho_f("rho", rho);
882  MAST::ConstantFieldFunction E_f("E", E);
883  MAST::ConstantFieldFunction nu_f("nu", nu);
884  MAST::ConstantFieldFunction cp_f("cp", cp);
885  MAST::ConstantFieldFunction k_f("k_th", k);
886  MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha);
887 
888  // Initialize the material
890 
891  // Add the material property constant field functions to the material card
892  material.add(rho_f);
893  material.add(k_f);
894  material.add(cp_f);
895  material.add(E_f);
896  material.add(nu_f);
897  material.add(alpha_f);
898 
899  // Initialize the section
901 
902  // Add the section property constant field functions to the section card
903  section.add(thickness_y_f);
904  section.add(thickness_z_f);
905  section.add(offsety_f);
906  section.add(offsetz_f);
907  section.add(Kzz_f);
908  section.add(Kyy_f);
909 
910  // Add the material card to the section card
911  section.set_material(material);
912 
913  // Specify a section orientation point and add it to the section.
914  RealVectorX orientation = RealVectorX::Zero(3);
915  orientation(1) = 1.0;
916  section.y_vector() = orientation;
917 
918  // Now initialize the section
919  section.init();
920 
921  REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional
922  REQUIRE( section.depends_on(thickness_y) );
923  REQUIRE( section.depends_on(offset_y) );
924  REQUIRE( section.depends_on(thickness_z) );
925  REQUIRE( section.depends_on(offset_z) );
926  REQUIRE( section.depends_on(E) );
927  REQUIRE( section.depends_on(nu) );
928  REQUIRE( section.depends_on(alpha) );
929  REQUIRE( section.if_isotropic() );
930 
931  // True values calculated using the sectionproperties module in python BAR.py
932  // NOTE: The default 1D section is rectangular
933  const libMesh::Point point(4.3, -3.5, -6.7);
934  const Real time = 8.22;
935 
936 // True values calculated using the sectionproperties module in python BAR.py
937  const Real area_true = 2.2500000000000004e+00;
938  const Real first_area_moment_z_true = 6.4574999999999994e-01;
939  const Real first_area_moment_y_true = 3.7214999999999945e+00;
940 
941  SECTION("1D thermal expansion A matrix")
942  {
954  Real area;
955  const MAST::FieldFunction<Real>& Area = section.A();
956  Area(point, time, area);
957  CHECK( area == Approx(area_true) );
958 
959  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> texp_A_mat = section.thermal_expansion_A_matrix();
960 
961  const libMesh::Point point(2.3, 3.1, 5.2);
962  const Real time = 2.34;
963  RealMatrixX D_sec_texpA;
964  texp_A_mat->operator()(point, time, D_sec_texpA);
965 
966  // Hard-coded value of the section's extension stiffness
967  RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1);
968  D_sec_texpA_true(0,0) = E() * alpha() * area_true;
969 
970  // Convert the test and truth Eigen::Matrix objects to std::vector
971  // since Catch2 has built in methods to compare vectors
972  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_texpA);
973  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true);
974 
975 
976  // Floating point approximations are diffcult to compare since the
977  // values typically aren't exactly equal due to numerical error.
978  // Therefore, we use the Approx comparison instead of Equals
979  CHECK_THAT( test, Catch::Approx<double>(truth) );
980  }
981 
982  SECTION("1D thermal expansion B matrix")
983  {
995  Real first_area_moment_y;
996  const MAST::FieldFunction<Real>& Ay = section.Ay();
997  Ay(point, time, first_area_moment_y);
998  CHECK( first_area_moment_y == Approx(first_area_moment_y_true) );
999 
1000  Real first_area_moment_z;
1001  const MAST::FieldFunction<Real>& Az = section.Az();
1002  Az(point, time, first_area_moment_z);
1003  CHECK( first_area_moment_z == Approx(first_area_moment_z_true) );
1004 
1005  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> texp_B_mat = section.thermal_expansion_B_matrix();
1006 
1007  const libMesh::Point point(2.3, 3.1, 5.2);
1008  const Real time = 2.34;
1009  RealMatrixX D_sec_texpB;
1010  texp_B_mat->operator()(point, time, D_sec_texpB);
1011 
1012  libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl;
1013 
1014  // Hard-coded value of the section's extension stiffness
1015  RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1);
1016  D_sec_texpB_true(0,0) = E() * alpha() * area_true * offset_y();
1017  D_sec_texpB_true(1,0) = E() * alpha() * area_true * offset_z();
1018 
1019 
1020  // Convert the test and truth Eigen::Matrix objects to std::vector
1021  // since Catch2 has built in methods to compare vectors
1022  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_texpB);
1023  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true);
1024 
1025  // Floating point approximations are diffcult to compare since the
1026  // values typically aren't exactly equal due to numerical error.
1027  // Therefore, we use the Approx comparison instead of Equals
1028  CHECK_THAT( test, Catch::Approx<double>(truth) );
1029  }
1030 }
1031 
1032 
1033 TEST_CASE("solid_element_property_card_constant_dynamic_1d",
1034  "[dynamic],[1D],[isotropic],[constant],[property]")
1035 {
1036  const uint dim = 1;
1037 
1038  // Define Material Properties as MAST Parameters
1039  MAST::Parameter rho("rho_param", 1420.5); // Density
1040  MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity
1041  MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio
1042  MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient
1043  MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity
1044  MAST::Parameter k("k_param", 237.0); // Thermal Conductivity
1045  MAST::Parameter alpha("alpha_param", 5.43e-05); // Coefficient of thermal expansion
1046 
1047  // Define Section Properties as MAST Parameters
1048  MAST::Parameter thickness_y("hz", 3.0); // Section thickness in z-direction
1049  MAST::Parameter thickness_z("hy", 0.75); // Section thickness in y-direction
1050  MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction
1051  MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction
1052  MAST::Parameter Kzz("Kzz", 8.3330248143102326e-01);
1053  MAST::Parameter Kyy("Kyy", 5.5763491072129889e-01);
1054 
1055 
1056  // Create field functions to dsitribute these constant parameters throughout the model
1057  // Section Property Field Functions
1058  MAST::ConstantFieldFunction thickness_y_f("hz", thickness_y);
1059  MAST::ConstantFieldFunction thickness_z_f("hy", thickness_z);
1060  MAST::ConstantFieldFunction offsety_f("hy_off", offset_y);
1061  MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z);
1062  MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz);
1063  MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy);
1064 
1065 
1066  // Material Property Field Functions
1067  MAST::ConstantFieldFunction rho_f("rho", rho);
1068  MAST::ConstantFieldFunction E_f("E", E);
1069  MAST::ConstantFieldFunction nu_f("nu", nu);
1070  MAST::ConstantFieldFunction cp_f("cp", cp);
1071  MAST::ConstantFieldFunction k_f("k_th", k);
1072  MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha);
1073 
1074  // Initialize the material
1076 
1077  // Add the material property constant field functions to the material card
1078  material.add(rho_f);
1079  material.add(k_f);
1080  material.add(cp_f);
1081  material.add(E_f);
1082  material.add(nu_f);
1083  material.add(alpha_f);
1084 
1085  // Initialize the section
1087 
1088  // Add the section property constant field functions to the section card
1089  section.add(thickness_y_f);
1090  section.add(thickness_z_f);
1091  section.add(offsety_f);
1092  section.add(offsetz_f);
1093  section.add(Kzz_f);
1094  section.add(Kyy_f);
1095 
1096  // Add the material card to the section card
1097  section.set_material(material);
1098 
1099  // Specify a section orientation point and add it to the section.
1100  RealVectorX orientation = RealVectorX::Zero(3);
1101  orientation(1) = 1.0;
1102  section.y_vector() = orientation;
1103 
1104  // Now initialize the section
1105  section.init();
1106 
1107  REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional
1108  REQUIRE( section.depends_on(thickness_y) );
1109  REQUIRE( section.depends_on(offset_y) );
1110  REQUIRE( section.depends_on(thickness_z) );
1111  REQUIRE( section.depends_on(offset_z) );
1112  REQUIRE( section.depends_on(k) );
1113  REQUIRE( section.depends_on(cp) );
1114  REQUIRE( section.depends_on(rho) );
1115  REQUIRE( section.if_isotropic() );
1116 
1117  // True values calculated using the sectionproperties module in python BAR.py
1118  const Real area_true = 2.2500000000000004e+00;
1119  const Real torsion_constant_true = 3.5540414988249380e-01;
1120  const Real first_area_moment_z_true = 6.4574999999999994e-01;
1121  const Real first_area_moment_y_true = 3.7214999999999945e+00;
1122  const Real second_area_moment_zz_true = 2.9079899999999986e-01;
1123  const Real second_area_moment_yy_true = 7.8428609999999814e+00;
1124  const Real second_area_moment_zy_true = 1.0680705000000006e+00;
1125  const Real second_area_moment_polar_true = 8.1336599999999812e+00;
1126  const Real Izzc_true = 1.0546874999999994e-01;
1127  const Real Iyyc_true = 1.6875000000000009e+00;
1128  const Real Izyc_true = 2.4424906541753444e-15;
1129  const Real warping_constant_true = 6.1030611538894504e-02;
1130  const Real kappa_z_true = 8.3330248143102326e-01;
1131  const Real kappa_y_true = 5.5763491072129889e-01;
1132  const Real xs_true = 1.6540000458463804e+00;
1133  const Real ys_true = 2.8700000023051281e-01;
1134  const Real xst_true = 1.6540000458463804e+00;
1135  const Real yst_true = 2.8700000023051281e-01;
1136  const libMesh::Point shear_center_true(xs_true, ys_true, 0.);
1137  const libMesh::Point centroid_true(1.654, 0.287, 0.);
1138 
1139  // NOTE: The default 1D section is rectangular
1140  const libMesh::Point point(4.3, -3.5, -6.7);
1141  const Real time = 8.22;
1142 
1143  SECTION("1D section inertia matrix")
1144  {
1155  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> inertia_mat = section.inertia_matrix();
1156 
1157  const libMesh::Point point(2.3, 3.1, 5.2);
1158  const Real time = 2.34;
1159  RealMatrixX D_sec_iner;
1160  inertia_mat->operator()(point, time, D_sec_iner);
1161 
1162  // Hard-coded value of the section's extension stiffness
1163  RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6);
1164 
1165 
1166  Real area;
1167  const MAST::FieldFunction<Real>& Area = section.A();
1168  Area(point, time, area);
1169  REQUIRE( area == Approx(area_true) );
1170  D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true;
1171 
1172  Real Ip;
1173  const MAST::FieldFunction<Real>& PolarInertia = section.Ip();
1174  PolarInertia(point, time, Ip);
1175  CHECK( Ip == Approx(second_area_moment_polar_true) );
1176  D_sec_iner_true(3,3) = second_area_moment_polar_true;
1177 
1178 
1179  Real first_area_moment_y;
1180  const MAST::FieldFunction<Real>& Ay = section.Ay();
1181  Ay(point, time, first_area_moment_y);
1182  CHECK( first_area_moment_y == Approx(first_area_moment_y_true) );
1183  D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true;
1184 
1185  Real first_area_moment_z;
1186  const MAST::FieldFunction<Real>& Az = section.Az();
1187  Az(point, time, first_area_moment_z);
1188  CHECK( first_area_moment_z == Approx(first_area_moment_z_true) );
1189  D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true;
1190 
1191 
1192  RealMatrixX I;
1193  const MAST::FieldFunction<RealMatrixX>& Inertias = section.I();
1194  Inertias(point, time, I);
1195  REQUIRE( I(0,1) == I(1,0) );
1196  Real Iyy = I(1,1);
1197  Real Izz = I(0,0);
1198  Real Izy = I(0,1);
1199  REQUIRE( Izz == Approx(second_area_moment_zz_true) );
1200  REQUIRE( Iyy == Approx(second_area_moment_yy_true) );
1201  REQUIRE( Izy == Approx(second_area_moment_zy_true) );
1202  D_sec_iner_true(4,4) = Iyy; // TODO: Should this be Izz?
1203  D_sec_iner_true(4,5) = Izy;
1204  D_sec_iner_true(5,4) = Izy;
1205  D_sec_iner_true(5,5) = Izz; // TODO: Should this be Iyy??
1206 
1207  D_sec_iner_true *= rho();
1208 
1209  // Convert the test and truth Eigen::Matrix objects to std::vector
1210  // since Catch2 has built in methods to compare vectors
1211  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_iner);
1212  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true);
1213 
1214  // Floating point approximations are diffcult to compare since the
1215  // values typically aren't exactly equal due to numerical error.
1216  // Therefore, we use the Approx comparison instead of Equals
1217  CHECK_THAT( test, Catch::Approx<double>(truth) );
1218  }
1219 }
1220 
1221 
1222 TEST_CASE("solid_element_property_card_constant_structural_1d",
1223  "[structural],[1D],[isotropic],[constant],[property]")
1224 {
1225  const uint dim = 1;
1226 
1227  // Define Material Properties as MAST Parameters
1228  MAST::Parameter rho("rho_param", 1420.5); // Density
1229  MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity
1230  MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio
1231  MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient
1232  MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity
1233  MAST::Parameter k("k_param", 237.0); // Thermal Conductivity
1234  MAST::Parameter alpha("alpha_param", 5.43e-05); // Coefficient of thermal expansion
1235 
1236  // Define Section Properties as MAST Parameters
1237  MAST::Parameter thickness_y("hz", 3.0); // Section thickness in z-direction
1238  MAST::Parameter thickness_z("hy", 0.75); // Section thickness in y-direction
1239  MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction
1240  MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction
1241  MAST::Parameter Kzz("Kzz", 8.3330248143102326e-01);
1242  MAST::Parameter Kyy("Kyy", 5.5763491072129889e-01);
1243 
1244 
1245  // Create field functions to dsitribute these constant parameters throughout the model
1246  // Section Property Field Functions
1247  MAST::ConstantFieldFunction thickness_y_f("hz", thickness_y);
1248  MAST::ConstantFieldFunction thickness_z_f("hy", thickness_z);
1249  MAST::ConstantFieldFunction offsety_f("hy_off", offset_y);
1250  MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z);
1251  MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz);
1252  MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy);
1253 
1254 
1255  // Material Property Field Functions
1256  MAST::ConstantFieldFunction rho_f("rho", rho);
1257  MAST::ConstantFieldFunction E_f("E", E);
1258  MAST::ConstantFieldFunction nu_f("nu", nu);
1259  MAST::ConstantFieldFunction cp_f("cp", cp);
1260  MAST::ConstantFieldFunction k_f("k_th", k);
1261  MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha);
1262 
1263  // Initialize the material
1265 
1266  // Add the material property constant field functions to the material card
1267  material.add(rho_f);
1268  material.add(k_f);
1269  material.add(cp_f);
1270  material.add(E_f);
1271  material.add(nu_f);
1272  material.add(alpha_f);
1273 
1274  // Initialize the section
1276 
1277  // Add the section property constant field functions to the section card
1278  section.add(thickness_y_f);
1279  section.add(thickness_z_f);
1280  section.add(offsety_f);
1281  section.add(offsetz_f);
1282  section.add(Kzz_f);
1283  section.add(Kyy_f);
1284 
1285  // Add the material card to the section card
1286  section.set_material(material);
1287 
1288  // Specify a section orientation point and add it to the section.
1289  RealVectorX orientation = RealVectorX::Zero(3);
1290  orientation(1) = 1.0;
1291  section.y_vector() = orientation;
1292 
1293  // Now initialize the section
1294  section.init();
1295 
1296  REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional
1297  REQUIRE( section.depends_on(thickness_y) );
1298  REQUIRE( section.depends_on(offset_y) );
1299  REQUIRE( section.depends_on(thickness_z) );
1300  REQUIRE( section.depends_on(offset_z) );
1301  REQUIRE( section.depends_on(E) );
1302  REQUIRE( section.depends_on(nu) );
1303  REQUIRE( section.depends_on(Kzz) );
1304  REQUIRE( section.depends_on(Kyy) );
1305  REQUIRE( section.depends_on(rho) );
1306  REQUIRE( section.if_isotropic() );
1307 
1308  // True values calculated using the sectionproperties module in python BAR.py
1309  const Real area_true = 2.2500000000000004e+00;
1310  const Real torsion_constant_true = 3.5540414988249380e-01;
1311  const Real first_area_moment_z_true = 6.4574999999999994e-01;
1312  const Real first_area_moment_y_true = 3.7214999999999945e+00;
1313  const Real second_area_moment_zz_true = 2.9079899999999986e-01;
1314  const Real second_area_moment_yy_true = 7.8428609999999814e+00;
1315  const Real second_area_moment_zy_true = 1.0680705000000006e+00;
1316  const Real second_area_moment_polar_true = 8.1336599999999812e+00;
1317  const Real Izzc_true = 1.0546874999999994e-01;
1318  const Real Iyyc_true = 1.6875000000000009e+00;
1319  const Real Izyc_true = 2.4424906541753444e-15;
1320  const Real warping_constant_true = 6.1030611538894504e-02;
1321  const Real kappa_z_true = 8.3330248143102326e-01;
1322  const Real kappa_y_true = 5.5763491072129889e-01;
1323  const Real xs_true = 1.6540000458463804e+00;
1324  const Real ys_true = 2.8700000023051281e-01;
1325  const Real xst_true = 1.6540000458463804e+00;
1326  const Real yst_true = 2.8700000023051281e-01;
1327  const libMesh::Point shear_center_true(xs_true, ys_true, 0.);
1328  const libMesh::Point centroid_true(1.654, 0.287, 0.);
1329 
1330  // NOTE: The default 1D section is rectangular
1331  const libMesh::Point point(4.3, -3.5, -6.7);
1332  const Real time = 8.22;
1333 
1334  SECTION("set_get_bending_model")
1335  {
1336  // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted.
1341 
1342  // TODO: Implement element creation for testing of getting bending_model and checking default
1343  //REQUIRE( section.bending_model()
1344  }
1345 
1346 // SECTION("quadrature_order")
1347 // {
1348 // section.set_bending_model(MAST::MINDLIN);
1349 // REQUIRE( section.extra_quadrature_order(elem) == 0 );
1350 //
1351 // section.set_bending_model(MAST::DKT);
1352 // REQUIRE( section.extra_quadrature_order(elem) == 2 );
1353 // }
1354 
1355  SECTION("1D extension stiffness matrix")
1356  {
1367  Real area;
1368  const MAST::FieldFunction<Real>& Area = section.A();
1369  Area(point, time, area);
1370  REQUIRE( area == Approx(area_true) );
1371 
1372  Real torsion_constant;
1373  const MAST::FieldFunction<Real>& TorsionConstant = section.J();
1374  TorsionConstant(point, time, torsion_constant);
1375  REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) );
1376 
1377  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> extension_stiffness_mat = section.stiffness_A_matrix();
1378 
1379  const libMesh::Point point(2.3, 3.1, 5.2);
1380  const Real time = 2.34;
1381  RealMatrixX D_sec_ext;
1382  extension_stiffness_mat->operator()(point, time, D_sec_ext);
1383 
1384  libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl;
1385 
1386  // Hard-coded value of the section's extension stiffness
1387  Real G = E() / (2. * (1.+nu()));
1388  RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2);
1389  D_sec_ext_true(0,0) = E() * area_true;
1390  D_sec_ext_true(1,1) = G * torsion_constant_true;
1391 
1392 
1393  // Convert the test and truth Eigen::Matrix objects to std::vector
1394  // since Catch2 has built in methods to compare vectors
1395  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_ext);
1396  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true);
1397 
1398  // Floating point approximations are diffcult to compare since the
1399  // values typically aren't exactly equal due to numerical error.
1400  // Therefore, we use the Approx comparison instead of Equals
1401  CHECK_THAT( test, Catch::Approx<double>(truth).epsilon(0.05) );
1402  }
1403 
1404 
1405  SECTION("1D bending section stiffness matrix")
1406  {
1417  RealMatrixX I;
1418  const MAST::FieldFunction<RealMatrixX>& Inertias = section.I();
1419  Inertias(point, time, I);
1420  REQUIRE( I(0,1) == I(1,0) );
1421  Real Izz = I(0,0);
1422  Real Iyy = I(1,1);
1423  Real Izy = I(0,1);
1424  REQUIRE( Izz == Approx(second_area_moment_zz_true) );
1425  REQUIRE( Iyy == Approx(second_area_moment_yy_true) );
1426  REQUIRE( Izy == Approx(second_area_moment_zy_true) );
1427 
1428  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> bending_stiffness_mat = section.stiffness_D_matrix();
1429 
1430  const libMesh::Point point(2.3, 3.1, 5.2);
1431  const Real time = 2.34;
1432  RealMatrixX D_sec_bnd;
1433  bending_stiffness_mat->operator()(point, time, D_sec_bnd);
1434 
1435  // Hard-coded value of the section's extension stiffness
1436  RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2);
1437  D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true;
1438  D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true;
1439  D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true;
1440  D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true;
1441 
1442  // Convert the test and truth Eigen::Matrix objects to std::vector
1443  // since Catch2 has built in methods to compare vectors
1444  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_bnd);
1445  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true);
1446 
1447  // Floating point approximations are diffcult to compare since the
1448  // values typically aren't exactly equal due to numerical error.
1449  // Therefore, we use the Approx comparison instead of Equals
1450  CHECK_THAT( test, Catch::Approx<double>(truth) );
1451  }
1452 
1453  SECTION("1D extension-bending section stiffness matrix")
1454  {
1465  Real first_area_moment_y;
1466  const MAST::FieldFunction<Real>& Ay = section.Ay();
1467  Ay(point, time, first_area_moment_y);
1468  CHECK( first_area_moment_y == Approx(first_area_moment_y_true) );
1469 
1470  Real first_area_moment_z;
1471  const MAST::FieldFunction<Real>& Az = section.Az();
1472  Az(point, time, first_area_moment_z);
1473  CHECK( first_area_moment_z == Approx(first_area_moment_z_true) );
1474 
1475  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> bndext_stiffness_mat = section.stiffness_B_matrix();
1476 
1477  const libMesh::Point point(2.3, 3.1, 5.2);
1478  const Real time = 2.34;
1479  RealMatrixX D_sec_bndext;
1480  bndext_stiffness_mat->operator()(point, time, D_sec_bndext);
1481 
1482  // Hard-coded value of the section's extension stiffness
1483  RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2);
1484  D_sec_bndext_true(0,0) = E() * first_area_moment_z_true;
1485  D_sec_bndext_true(0,1) = E() * first_area_moment_y_true;
1486  // TODO: Add checks for torsion bending coupling when added to MAST.
1487 
1488  // Convert the test and truth Eigen::Matrix objects to std::vector
1489  // since Catch2 has built in methods to compare vectors
1490  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_bndext);
1491  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true);
1492 
1493  // Floating point approximations are diffcult to compare since the
1494  // values typically aren't exactly equal due to numerical error.
1495  // Therefore, we use the Approx comparison instead of Equals
1496  CHECK_THAT( test, Catch::Approx<double>(truth) );
1497  }
1498 
1499  SECTION("1D transverse shear section stiffness matrix")
1500  {
1511  Real area;
1512  const MAST::FieldFunction<Real>& Area = section.A();
1513  Area(point, time, area);
1514  REQUIRE( area == Approx(area_true) );
1515 
1516  std::unique_ptr<MAST::FieldFunction<RealMatrixX>> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix();
1517 
1518  const libMesh::Point point(2.3, 3.1, 5.2);
1519  const Real time = 2.34;
1520  RealMatrixX D_sec_shr;
1521  trans_shear_stiffness_mat->operator()(point, time, D_sec_shr);
1522 
1523  // Hard-coded value of the section's extension stiffness
1524  Real G = E() / (2. * (1.+nu()));
1525  RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2);
1526  D_sec_shr_true(0,0) = G*area_true*kappa_z_true;
1527  D_sec_shr_true(1,1) = G*area_true*kappa_y_true;
1528 
1529  // Convert the test and truth Eigen::Matrix objects to std::vector
1530  // since Catch2 has built in methods to compare vectors
1531  std::vector<double> test = TEST::eigen_matrix_to_std_vector(D_sec_shr);
1532  std::vector<double> truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true);
1533 
1534  // Floating point approximations are diffcult to compare since the
1535  // values typically aren't exactly equal due to numerical error.
1536  // Therefore, we use the Approx comparison instead of Equals
1537  CHECK_THAT( test, Catch::Approx<double>(truth) );
1538  }
1539 
1540 
1541 // SECTION("1D spring section stiffness matrix")
1542 // {
1543 // /**
1544 // * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an
1545 // * MAST::ElementBase object, but does not actually use it. To get
1546 // * around requiring the creation of such an object (and therefore
1547 // * the creation of a MAST::SystemInitialization, MAST::AssemblyBase,
1548 // * and MAST::GeomElem objects as well).
1549 // *
1550 // * To remedy this, an additional method was added to MAST which allows
1551 // * transverse_shear_stiffness_matrix to be obtained without any input arguments.
1552 // */
1553 // std::unique_ptr<MAST::FieldFunction<RealMatrixX>> spring_stiffness_mat = section.stiffness_S_matrix();
1554 //
1555 // const libMesh::Point point(2.3, 3.1, 5.2);
1556 // const Real time = 2.34;
1557 // RealMatrixX D_sec_spring;
1558 // spring_stiffness_mat->operator()(point, time, D_sec_spring);
1559 //
1560 // // Hard-coded value of the section's extension stiffness
1561 // // NOTE: Should be all zero's for non-bushing sections
1562 // RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6);
1563 //
1564 // // Convert the test and truth Eigen::Matrix objects to std::vector
1565 // // since Catch2 has built in methods to compare vectors
1566 // std::vector<double> test = eigen_matrix_to_std_vector(D_sec_spring);
1567 // std::vector<double> truth = eigen_matrix_to_std_vector(D_sec_spring_true);
1568 //
1569 // // Floating point approximations are diffcult to compare since the
1570 // // values typically aren't exactly equal due to numerical error.
1571 // // Therefore, we use the Approx comparison instead of Equals
1572 // CHECK_THAT( test, Catch::Approx<double>(truth) );
1573 // }
1574 }
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > stiffness_B_matrix(const MAST::ElementBase &e) const
virtual const MAST::FieldFunction< Real > & Ip() const
virtual void set_material(MAST::MaterialPropertyCardBase &mat)
sets the material card
void set_diagonal_mass_matrix(bool m)
sets the mass matrix to be diagonal or consistent
RealVectorX & y_vector()
returns value of the property val.
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > thermal_conductance_matrix(const MAST::ElementBase &e) const
This is a scalar function whose value can be changed and one that can be used as a design variable in...
Definition: parameter.h:35
libMesh::LibMeshInit * p_global_init
Definition: init_catch2.cpp:26
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > transverse_shear_stiffness_matrix(const MAST::ElementBase &e) const
virtual void derivative(const MAST::FunctionBase &f, ValType &v) const
calculates the value of the function derivative and returns it in v.
libMesh::Real Real
virtual const MAST::FieldFunction< RealMatrixX > & I() const
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > thermal_capacitance_matrix(const MAST::ElementBase &e) const
void add(MAST::FunctionBase &f)
adds the function to this card and returns a reference to it.
std::vector< double > eigen_matrix_to_std_vector(RealMatrixX M)
Converts an Eigen Matrix object to a std::vector.
virtual bool depends_on(const MAST::FunctionBase &f) const
returns true if the property card depends on the function f
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > stiffness_D_matrix(const MAST::ElementBase &e) const
Matrix< Real, Dynamic, Dynamic > RealMatrixX
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > thermal_expansion_B_matrix(const MAST::ElementBase &e) const
virtual const MAST::FieldFunction< Real > & Az() const
virtual const MAST::FieldFunction< Real > & Gam() const
TEST_CASE("solid_element_property_card_constant_base_1d", "[1D],[isotropic],[constant],[property]")
The default 1D solid section is defined as a solid rectangular cross section defined by two parameter...
virtual bool if_isotropic() const
return true if the property is isotropic
virtual unsigned int dim() const
dimension of the element for which this property is defined
virtual const MAST::FieldFunction< Real > & A() const
Matrix< Real, Dynamic, 1 > RealVectorX
virtual const MAST::FieldFunction< Real > & Ay() const
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > stiffness_A_matrix(const MAST::ElementBase &e) const
bool if_diagonal_mass_matrix() const
returns the type of strain to be used for this element
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > thermal_expansion_A_matrix(const MAST::ElementBase &e) const
void set_bending_model(MAST::BendingOperatorType b)
returns the bending model to be used for the 2D element
virtual const MAST::FieldFunction< RealMatrixX > & Kap() const
virtual const MAST::FieldFunction< Real > & J() const
virtual std::unique_ptr< MAST::FieldFunction< RealMatrixX > > inertia_matrix(const MAST::ElementBase &e) const