https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SymmetricRankFourTensorImplementation.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
13
14// MOOSE includes
16#include "RankFourTensor.h"
17#include "MooseEnum.h"
18#include "MooseException.h"
19#include "MooseUtils.h"
20#include "MatrixTools.h"
21#include "PermutationTensor.h"
22
23#include "libmesh/utility.h"
24#include "libmesh/tensor_value.h"
25#include "libmesh/vector_value.h"
26
27// C++ includes
28#include <iomanip>
29#include <ostream>
30
31namespace MathUtils
32{
33template <>
34void mooseSetToZero<SymmetricRankFourTensorTempl<Real>>(SymmetricRankFourTensorTempl<Real> & v);
35template <>
36void mooseSetToZero<SymmetricRankFourTensorTempl<ADReal>>(SymmetricRankFourTensorTempl<ADReal> & v);
37}
38
39template <typename T>
42{
43 return MooseEnum("symmetric9 symmetric21 symmetric_isotropic symmetric_isotropic_E_nu "
44 "axisymmetric_rz principal orthotropic");
45}
46
47template <typename T>
49{
50 mooseAssert(Ndim == 3,
51 "SymmetricRankFourTensorTempl<T> is designed to only work in 3 dimensions.");
52 zero();
53}
54
55template <typename T>
57{
58 switch (init)
59 {
60 case initNone:
61 break;
62
63 case initIdentity:
64 zero();
65 for (const auto i : make_range(Ndim))
66 (*this)(i, i) = 1.0;
67 break;
68
69 case initIdentitySymmetricFour:
70 zero();
71 for (const auto i : make_range(N))
72 (*this)(i, i) = 1.0;
73 break;
74
75 default:
76 mooseError("Unknown SymmetricRankFourTensorTempl<T> initialization pattern.");
77 }
78}
79
80template <typename T>
82{
83 for (const auto a : make_range(N))
84 for (const auto b : make_range(N))
85 {
86 const auto & idx = full_index[a][b];
87 auto i = idx[0];
88 auto j = idx[1];
89 auto k = idx[2];
90 auto l = idx[3];
91 (*this)(a, b) =
92 (t(i, j, k, l) + t(j, i, l, k) + t(j, i, k, l) + t(i, j, l, k)) / 4 * mandelFactor(a, b);
93 }
94}
95
96template <typename T>
98{
99 auto & q = *this;
101 for (const auto a : make_range(N))
102 for (const auto b : make_range(N))
103 {
104 const auto i = full_index[a][b][0];
105 const auto j = full_index[a][b][1];
106 const auto k = full_index[a][b][2];
107 const auto l = full_index[a][b][3];
108
109 // Rijkl = Rjikl = Rijlk = Rjilk
110 r(i, j, k, l) = q(a, b) / mandelFactor(a, b);
111 r(j, i, k, l) = q(a, b) / mandelFactor(a, b);
112 r(i, j, l, k) = q(a, b) / mandelFactor(a, b);
113 r(j, i, l, k) = q(a, b) / mandelFactor(a, b);
114 }
115
116 return r;
117}
118
119template <typename T>
121 FillMethod fill_method)
122{
123 fillFromInputVector(input, fill_method);
124}
125
126template <typename T>
127void
129{
130 std::fill(_vals.begin(), _vals.end(), 0.0);
131}
132
133template <typename T>
136{
138 const static std::array<std::size_t, 3> a = {{1, 0, 0}};
139 const static std::array<std::size_t, 3> b = {{2, 2, 1}};
140 for (std::size_t i = 0; i < 3; ++i)
141 for (std::size_t j = 0; j < 3; ++j)
142 {
143 M(i, j) = R(i, j) * R(i, j);
144 M(i + 3, j) = MathUtils::sqrt2 * R((i + 1) % 3, j) * R((i + 2) % 3, j);
145 M(j, i + 3) = MathUtils::sqrt2 * R(j, (i + 1) % 3) * R(j, (i + 2) % 3);
146 M(i + 3, j + 3) = R(a[i], a[j]) * R(b[i], b[j]) + R(a[i], b[j]) * R(b[i], a[j]);
147 }
148 return M;
149}
150
151template <typename T>
152void
154{
155 // build 6x6 rotation matrix
157
158 // rotate tensor
159 (*this) = M * (*this) * M.transposeMajor();
160}
161
162template <typename T>
165{
166 for (const auto i : make_range(N2))
167 _vals[i] *= a;
168 return *this;
169}
170
171template <typename T>
174{
175 for (const auto i : make_range(N2))
176 _vals[i] /= a;
177 return *this;
178}
179
180template <typename T>
183{
184 for (const auto i : make_range(N2))
185 _vals[i] += a._vals[i];
186 return *this;
187}
188
189template <typename T>
190template <typename T2>
191auto
193 -> SymmetricRankFourTensorTempl<decltype(T() + T2())>
194{
195 SymmetricRankFourTensorTempl<decltype(T() + T2())> result;
196 for (const auto i : make_range(N2))
197 result._vals[i] = _vals[i] + b._vals[i];
198 return result;
199}
200
201template <typename T>
204{
205 for (const auto i : make_range(N2))
206 _vals[i] -= a._vals[i];
207 return *this;
208}
209
210template <typename T>
211template <typename T2>
212auto
214 -> SymmetricRankFourTensorTempl<decltype(T() - T2())>
215{
216 SymmetricRankFourTensorTempl<decltype(T() - T2())> result;
217 for (const auto i : make_range(N2))
218 result._vals[i] = _vals[i] - b._vals[i];
219 return result;
220}
221
222template <typename T>
225{
227 for (const auto i : make_range(N2))
228 result._vals[i] = -_vals[i];
229 return result;
230}
231
232template <typename T>
233template <typename T2>
234auto
236 -> SymmetricRankFourTensorTempl<decltype(T() * T2())>
237{
238 typedef decltype(T() * T2()) ValueType;
240
241 for (const auto i : make_range(N))
242 for (const auto j : make_range(N))
243 for (const auto p : make_range(N))
244 result(i, j) += (*this)(i, p) * b(p, j);
245
246 return result;
247}
248
249template <typename T>
250T
252{
253 T l2 = Utility::pow<2>(_vals[0]);
254 for (const auto i : make_range(1u, N2))
255 l2 += Utility::pow<2>(_vals[i]);
256 using std::sqrt;
257 return sqrt(l2);
258}
259
260template <typename T>
261void
263{
264 for (const auto i : make_range(N))
265 {
266 for (const auto j : make_range(N))
267 stm << std::setw(15) << _vals[i * N + j] << " ";
268 stm << '\n';
269 }
270 stm << std::flush;
271}
272
273template <typename T>
274void
276{
277 for (const auto i : make_range(N))
278 {
279 for (const auto j : make_range(N))
280 stm << std::setw(15) << MetaPhysicL::raw_value(_vals[i * N + j]) << " ";
281 stm << '\n';
282 }
283 stm << std::flush;
284}
285
286template <typename T>
289{
290 std::size_t index = 0;
292 for (const auto i : make_range(N))
293 for (const auto j : make_range(N))
294 ret._vals[index++] = _vals[i + N * j];
295 return ret;
296}
297
298template <typename T>
299void
301 FillMethod fill_method)
302{
303
304 switch (fill_method)
305 {
306 case symmetric9:
307 fillSymmetric9FromInputVector(input);
308 break;
309 case symmetric21:
310 fillSymmetric21FromInputVector(input);
311 break;
312 case symmetric_isotropic:
313 fillSymmetricIsotropicFromInputVector(input);
314 break;
315 case symmetric_isotropic_E_nu:
316 fillSymmetricIsotropicEandNuFromInputVector(input);
317 break;
318 case axisymmetric_rz:
319 fillAxisymmetricRZFromInputVector(input);
320 break;
321 case principal:
322 fillPrincipalFromInputVector(input);
323 break;
324 case orthotropic:
325 fillGeneralOrthotropicFromInputVector(input);
326 break;
327 default:
328 mooseError("fillFromInputVector called with unknown fill_method of ", fill_method);
329 }
330}
331
332template <typename T>
333void
335{
336 mooseAssert(input.size() == 2,
337 "To use fillSymmetricIsotropicFromInputVector, your input must have size 2.");
338 fillSymmetricIsotropic(input[0], input[1]);
339}
340
341template <typename T>
342void
344{
345 // clang-format off
346 fillSymmetric21FromInputVector(std::array<T,21>
347 {{lambda + 2.0 * G, lambda, lambda, 0.0, 0.0, 0.0,
348 lambda + 2.0 * G, lambda, 0.0, 0.0, 0.0,
349 lambda + 2.0 * G, 0.0, 0.0, 0.0,
350 G, 0.0, 0.0,
351 G, 0.0,
352 G}});
353 // clang-format on
354}
355
356template <typename T>
357void
359 const std::vector<T> & input)
360{
361 if (input.size() != 2)
363 "To use fillSymmetricIsotropicEandNuFromInputVector, your input must have size 2. Yours "
364 "has size ",
365 input.size());
366
367 fillSymmetricIsotropicEandNu(input[0], input[1]);
368}
369
370template <typename T>
371void
373{
374 // Calculate lambda and the shear modulus from the given young's modulus and poisson's ratio
375 const T & lambda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu));
376 const T & G = E / (2.0 * (1.0 + nu));
377
378 fillSymmetricIsotropic(lambda, G);
379}
380
381template <typename T>
382void
384{
385 mooseAssert(input.size() == 5,
386 "To use fillAxisymmetricRZFromInputVector, your input must have size 5.");
387
388 // C1111 C1122 C1133 0 0 0
389 // C2222 C2233=C1133 0 0 0
390 // C3333 0 0 0
391 // C2323 0 0
392 // C3131=C2323 0
393 // C1212
394 // clang-format off
395 fillSymmetric21FromInputVector(std::array<T,21>
396 {{input[0],input[1],input[2], 0.0, 0.0, 0.0,
397 input[0],input[2], 0.0, 0.0, 0.0,
398 input[3], 0.0, 0.0, 0.0,
399 input[4], 0.0, 0.0,
400 input[4], 0.0,
401 (input[0] - input[1]) * 0.5}});
402 // clang-format on
403}
404
405template <typename T>
406void
408{
409 if (input.size() != 9)
410 mooseError("To use fillPrincipalFromInputVector, your input must have size 9. Yours has size ",
411 input.size());
412
413 zero();
414
415 // top left block
416 _vals[0] = input[0];
417 _vals[1] = input[1];
418 _vals[2] = input[2];
419 _vals[6] = input[3];
420 _vals[7] = input[4];
421 _vals[8] = input[5];
422 _vals[12] = input[6];
423 _vals[13] = input[7];
424 _vals[14] = input[8];
425}
426
427template <typename T>
428void
430{
431 mooseAssert(LIBMESH_DIM == 3, "This method assumes LIBMESH_DIM == 3");
432 if (input.size() != 12)
433 mooseError("To use fillGeneralOrhotropicFromInputVector, your input must have size 12. Yours "
434 "has size ",
435 input.size());
436
437 const T & Ea = input[0];
438 const T & Eb = input[1];
439 const T & Ec = input[2];
440 const T & Gab = input[3];
441 const T & Gbc = input[4];
442 const T & Gca = input[5];
443 const T & nuba = input[6];
444 const T & nuca = input[7];
445 const T & nucb = input[8];
446 const T & nuab = input[9];
447 const T & nuac = input[10];
448 const T & nubc = input[11];
449
450 // Input must satisfy constraints.
451 bool preserve_symmetry = MooseUtils::relativeFuzzyEqual(nuab * Eb, nuba * Ea) &&
452 MooseUtils::relativeFuzzyEqual(nuca * Ea, nuac * Ec) &&
453 MooseUtils::relativeFuzzyEqual(nubc * Ec, nucb * Eb);
454
455 if (!preserve_symmetry)
456 mooseError("Orthotropic elasticity tensor input is not consistent with symmetry requirements. "
457 "Check input for accuracy");
458
459 zero();
460 T k = 1 - nuab * nuba - nubc * nucb - nuca * nuac - nuab * nubc * nuca - nuba * nucb * nuac;
461
462 bool is_positive_definite =
463 (k > 0) && (1 - nubc * nucb) > 0 && (1 - nuac * nuca) > 0 && (1 - nuab * nuba) > 0;
464 if (!is_positive_definite)
465 mooseError("Orthotropic elasticity tensor input is not positive definite. Check input for "
466 "accuracy");
467
468 _vals[0] = Ea * (1 - nubc * nucb) / k;
469 _vals[1] = Ea * (nubc * nuca + nuba) / k;
470 _vals[2] = Ea * (nuba * nucb + nuca) / k;
471
472 _vals[6] = Eb * (nuac * nucb + nuab) / k;
473 _vals[7] = Eb * (1 - nuac * nuca) / k;
474 _vals[8] = Eb * (nuab * nuca + nucb) / k;
475
476 _vals[12] = Ec * (nuab * nubc + nuac) / k;
477 _vals[13] = Ec * (nuac * nuba + nubc) / k;
478 _vals[14] = Ec * (1 - nuab * nuba) / k;
479
480 _vals[21] = 2 * Gbc;
481 _vals[28] = 2 * Gca;
482 _vals[35] = 2 * Gab;
483}
484
485template <typename T>
486T
488{
489 mooseAssert(LIBMESH_DIM == 3, "This method assumes LIBMESH_DIM == 3");
490 // summation of Ciijj used in the volumetric locking correction
491 T sum = 0;
492 for (const auto i : make_range(3))
493 for (const auto j : make_range(3))
494 sum += (*this)(i, j);
495 return sum;
496}
497
498template <typename T>
501{
502 mooseAssert(LIBMESH_DIM == 3, "This method assumes LIBMESH_DIM == 3");
503 // used for volumetric locking correction
504 return libMesh::VectorValue<T>(_vals[0] + _vals[1] + _vals[2],
505 _vals[6] + _vals[7] + _vals[8],
506 _vals[12] + _vals[13] + _vals[14]);
507}
508
509template <typename T>
510bool
512{
513 for (unsigned int i = 0; i < N; ++i)
514 for (unsigned int j = 0; j < N; ++j)
515 // major symmetry
516 if (_vals[i + N * j] != _vals[N * i + j])
517 return false;
518 return true;
519}
520
521template <typename T>
522bool
524{
525 // prerequisite is symmetry
526 if (!isSymmetric())
527 return false;
528
529 // inspect shear components
530 const T & mu = _vals[35];
531
532 // ...diagonal
533 if (_vals[28] != mu || _vals[21] != mu)
534 return false;
535
536 // ...off-diagonal
537 if (_vals[22] != 0.0 || _vals[23] != 0.0 || _vals[29] != 0.0)
538 return false;
539
540 // off diagonal blocks in Voigt
541 for (const auto i : make_range(3))
542 for (const auto j : make_range(3))
543 if (_vals[3 + i + N * j] != 0.0)
544 return false;
545
546 // top left block
547 const T & K1 = _vals[0];
548 const T & K2 = _vals[1];
549 if (!MooseUtils::relativeFuzzyEqual(K1 - 2.0 * mu / 3.0, K2 + mu / 3.0))
550 return false;
551 if (_vals[7] != K1 || _vals[14] != K1)
552 return false;
553
554 for (const auto i : make_range(1, 3))
555 for (const auto j : make_range(i))
556 if (_vals[i + N * j] != K2)
557 return false;
558
559 return true;
560}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
RankFourTensorTempl is designed to handle any N-dimensional fourth order tensor, C.
SymmetricRankFourTensorTempl is designed to handle an N-dimensional fourth order tensor with minor sy...
void fillSymmetricIsotropicFromInputVector(const std::vector< T > &input)
fillSymmetricIsotropicFromInputVector takes 2 inputs to fill the the symmetric Rank-4 tensor with the...
void fillFromInputVector(const std::vector< T > &input, FillMethod fill_method)
fillFromInputVector takes some number of inputs to fill the Rank-4 tensor.
SymmetricRankFourTensorTempl< T > transposeMajor() const
Transpose the tensor by swapping the first pair with the second pair of indices This amounts to a reg...
void fillSymmetricIsotropic(const T &i0, const T &i1)
Vector-less fill API functions. See docs of the corresponding ...FromInputVector methods.
void fillAxisymmetricRZFromInputVector(const std::vector< T > &input)
fillAxisymmetricRZFromInputVector takes 5 inputs to fill the axisymmetric Rank-4 tensor with the appr...
SymmetricRankFourTensorTempl< T > operator-() const
-C_ijkl
void printReal(std::ostream &stm=Moose::out) const
Print the values of the rank four tensor.
libMesh::VectorValue< T > sum3x1() const
Calculates the vector a[i] = sum over j Ciijj for i and j varying from 0 to 2.
void fillGeneralOrthotropicFromInputVector(const std::vector< T > &input)
fillGeneralOrhotropicFromInputVector takes 10 inputs to fill the Rank-4 tensor It defines a general o...
SymmetricRankFourTensorTempl< T > & operator+=(const SymmetricRankFourTensorTempl< T > &a)
C_ijkl += a_ijkl for all i, j, k, l.
static MooseEnum fillMethodEnum()
Static method for use in validParams for getting the "fill_method".
auto operator+(const SymmetricRankFourTensorTempl< T2 > &a) const -> SymmetricRankFourTensorTempl< decltype(T()+T2())>
C_ijkl + a_ijkl.
bool isIsotropic() const
checks if the tensor is isotropic
auto operator*(const SymmetricRankTwoTensorTempl< T2 > &b) const -> SymmetricRankTwoTensorTempl< decltype(T() *T2())>
C_ijkl*a_kl.
void fillPrincipalFromInputVector(const std::vector< T > &input)
fillPrincipalFromInputVector takes 9 inputs to fill a Rank-4 tensor C1111 = input0 C1122 = input1 C11...
void fillSymmetricIsotropicEandNu(const T &E, const T &nu)
void print(std::ostream &stm=Moose::out) const
Print the rank four tensor.
static SymmetricRankFourTensorTempl< T > rotationMatrix(const TypeTensor< T > &R)
Build a 6x6 rotation matrix MEHRABADI, MORTEZA M.; COWIN, STEPHEN C.
void rotate(const TypeTensor< T > &R)
Rotate the tensor using C_ijkl = R_im R_jn R_ko R_lp C_mnop.
std::array< T, N2 > _vals
The values of the rank-four tensor.
T sum3x3() const
Calculates the sum of Ciijj for i and j varying from 0 to 2.
bool isSymmetric() const
checks if the tensor is symmetric
SymmetricRankFourTensorTempl< T > & operator/=(const T &a)
C_ijkl /= a for all i, j, k, l.
FillMethod
To fill up the 36 entries in the 4th-order tensor, fillFromInputVector is called with one of the foll...
SymmetricRankFourTensorTempl< T > & operator*=(const T &a)
C_ijkl *= a.
void fillSymmetricIsotropicEandNuFromInputVector(const std::vector< T > &input)
fillSymmetricIsotropicEandNuFromInputVector is a variation of the fillSymmetricIsotropicFromInputVect...
SymmetricRankFourTensorTempl< T > & operator-=(const SymmetricRankFourTensorTempl< T > &a)
C_ijkl -= a_ijkl.
static constexpr Real sqrt2
std::sqrt is not constexpr, so we add sqrt(2) as a constant (used in Mandel notation)
Definition MathUtils.h:25
auto raw_value(const Eigen::Map< T > &in)