https://mooseframework.inl.gov
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
15 #include "SymmetricRankTwoTensor.h"
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 
31 namespace MathUtils
32 {
33 template <>
34 void mooseSetToZero<SymmetricRankFourTensorTempl<Real>>(SymmetricRankFourTensorTempl<Real> & v);
35 template <>
36 void mooseSetToZero<SymmetricRankFourTensorTempl<ADReal>>(SymmetricRankFourTensorTempl<ADReal> & v);
37 }
38 
39 template <typename T>
42 {
43  return MooseEnum("symmetric9 symmetric21 symmetric_isotropic symmetric_isotropic_E_nu "
44  "axisymmetric_rz principal orthotropic");
45 }
46 
47 template <typename T>
49 {
50  mooseAssert(Ndim == 3,
51  "SymmetricRankFourTensorTempl<T> is designed to only work in 3 dimensions.");
52  zero();
53 }
54 
55 template <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 
80 template <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 
96 template <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 
119 template <typename T>
121  FillMethod fill_method)
122 {
123  fillFromInputVector(input, fill_method);
124 }
125 
126 template <typename T>
127 void
129 {
130  std::fill(_vals.begin(), _vals.end(), 0.0);
131 }
132 
133 template <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 
151 template <typename T>
152 void
154 {
155  // build 6x6 rotation matrix
157 
158  // rotate tensor
159  (*this) = M * (*this) * M.transposeMajor();
160 }
161 
162 template <typename T>
165 {
166  for (const auto i : make_range(N2))
167  _vals[i] *= a;
168  return *this;
169 }
170 
171 template <typename T>
174 {
175  for (const auto i : make_range(N2))
176  _vals[i] /= a;
177  return *this;
178 }
179 
180 template <typename T>
183 {
184  for (const auto i : make_range(N2))
185  _vals[i] += a._vals[i];
186  return *this;
187 }
188 
189 template <typename T>
190 template <typename T2>
191 auto
194 {
196  for (const auto i : make_range(N2))
197  result._vals[i] = _vals[i] + b._vals[i];
198  return result;
199 }
200 
201 template <typename T>
204 {
205  for (const auto i : make_range(N2))
206  _vals[i] -= a._vals[i];
207  return *this;
208 }
209 
210 template <typename T>
211 template <typename T2>
212 auto
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 
222 template <typename T>
225 {
227  for (const auto i : make_range(N2))
228  result._vals[i] = -_vals[i];
229  return result;
230 }
231 
232 template <typename T>
233 template <typename T2>
234 auto
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 
249 template <typename T>
250 T
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  return std::sqrt(l2);
257 }
258 
259 template <typename T>
260 void
261 SymmetricRankFourTensorTempl<T>::print(std::ostream & stm) const
262 {
263  for (const auto i : make_range(N))
264  {
265  for (const auto j : make_range(N))
266  stm << std::setw(15) << _vals[i * N + j] << " ";
267  stm << '\n';
268  }
269  stm << std::flush;
270 }
271 
272 template <typename T>
273 void
275 {
276  for (const auto i : make_range(N))
277  {
278  for (const auto j : make_range(N))
279  stm << std::setw(15) << MetaPhysicL::raw_value(_vals[i * N + j]) << " ";
280  stm << '\n';
281  }
282  stm << std::flush;
283 }
284 
285 template <typename T>
288 {
289  std::size_t index = 0;
291  for (const auto i : make_range(N))
292  for (const auto j : make_range(N))
293  ret._vals[index++] = _vals[i + N * j];
294  return ret;
295 }
296 
297 template <typename T>
298 void
300  FillMethod fill_method)
301 {
302 
303  switch (fill_method)
304  {
305  case symmetric9:
306  fillSymmetric9FromInputVector(input);
307  break;
308  case symmetric21:
309  fillSymmetric21FromInputVector(input);
310  break;
311  case symmetric_isotropic:
312  fillSymmetricIsotropicFromInputVector(input);
313  break;
314  case symmetric_isotropic_E_nu:
315  fillSymmetricIsotropicEandNuFromInputVector(input);
316  break;
317  case axisymmetric_rz:
318  fillAxisymmetricRZFromInputVector(input);
319  break;
320  case principal:
321  fillPrincipalFromInputVector(input);
322  break;
323  case orthotropic:
324  fillGeneralOrthotropicFromInputVector(input);
325  break;
326  default:
327  mooseError("fillFromInputVector called with unknown fill_method of ", fill_method);
328  }
329 }
330 
331 template <typename T>
332 void
334 {
335  mooseAssert(input.size() == 2,
336  "To use fillSymmetricIsotropicFromInputVector, your input must have size 2.");
337  fillSymmetricIsotropic(input[0], input[1]);
338 }
339 
340 template <typename T>
341 void
343 {
344  // clang-format off
345  fillSymmetric21FromInputVector(std::array<T,21>
346  {{lambda + 2.0 * G, lambda, lambda, 0.0, 0.0, 0.0,
347  lambda + 2.0 * G, lambda, 0.0, 0.0, 0.0,
348  lambda + 2.0 * G, 0.0, 0.0, 0.0,
349  G, 0.0, 0.0,
350  G, 0.0,
351  G}});
352  // clang-format on
353 }
354 
355 template <typename T>
356 void
358  const std::vector<T> & input)
359 {
360  if (input.size() != 2)
361  mooseError(
362  "To use fillSymmetricIsotropicEandNuFromInputVector, your input must have size 2. Yours "
363  "has size ",
364  input.size());
365 
366  fillSymmetricIsotropicEandNu(input[0], input[1]);
367 }
368 
369 template <typename T>
370 void
372 {
373  // Calculate lambda and the shear modulus from the given young's modulus and poisson's ratio
374  const T & lambda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu));
375  const T & G = E / (2.0 * (1.0 + nu));
376 
377  fillSymmetricIsotropic(lambda, G);
378 }
379 
380 template <typename T>
381 void
383 {
384  mooseAssert(input.size() == 5,
385  "To use fillAxisymmetricRZFromInputVector, your input must have size 5.");
386 
387  // C1111 C1122 C1133 0 0 0
388  // C2222 C2233=C1133 0 0 0
389  // C3333 0 0 0
390  // C2323 0 0
391  // C3131=C2323 0
392  // C1212
393  // clang-format off
394  fillSymmetric21FromInputVector(std::array<T,21>
395  {{input[0],input[1],input[2], 0.0, 0.0, 0.0,
396  input[0],input[2], 0.0, 0.0, 0.0,
397  input[3], 0.0, 0.0, 0.0,
398  input[4], 0.0, 0.0,
399  input[4], 0.0,
400  (input[0] - input[1]) * 0.5}});
401  // clang-format on
402 }
403 
404 template <typename T>
405 void
407 {
408  if (input.size() != 9)
409  mooseError("To use fillPrincipalFromInputVector, your input must have size 9. Yours has size ",
410  input.size());
411 
412  zero();
413 
414  // top left block
415  _vals[0] = input[0];
416  _vals[1] = input[1];
417  _vals[2] = input[2];
418  _vals[6] = input[3];
419  _vals[7] = input[4];
420  _vals[8] = input[5];
421  _vals[12] = input[6];
422  _vals[13] = input[7];
423  _vals[14] = input[8];
424 }
425 
426 template <typename T>
427 void
429 {
430  mooseAssert(LIBMESH_DIM == 3, "This method assumes LIBMESH_DIM == 3");
431  if (input.size() != 12)
432  mooseError("To use fillGeneralOrhotropicFromInputVector, your input must have size 12. Yours "
433  "has size ",
434  input.size());
435 
436  const T & Ea = input[0];
437  const T & Eb = input[1];
438  const T & Ec = input[2];
439  const T & Gab = input[3];
440  const T & Gbc = input[4];
441  const T & Gca = input[5];
442  const T & nuba = input[6];
443  const T & nuca = input[7];
444  const T & nucb = input[8];
445  const T & nuab = input[9];
446  const T & nuac = input[10];
447  const T & nubc = input[11];
448 
449  // Input must satisfy constraints.
450  bool preserve_symmetry = MooseUtils::relativeFuzzyEqual(nuab * Eb, nuba * Ea) &&
451  MooseUtils::relativeFuzzyEqual(nuca * Ea, nuac * Ec) &&
452  MooseUtils::relativeFuzzyEqual(nubc * Ec, nucb * Eb);
453 
454  if (!preserve_symmetry)
455  mooseError("Orthotropic elasticity tensor input is not consistent with symmetry requirements. "
456  "Check input for accuracy");
457 
458  zero();
459  T k = 1 - nuab * nuba - nubc * nucb - nuca * nuac - nuab * nubc * nuca - nuba * nucb * nuac;
460 
461  bool is_positive_definite =
462  (k > 0) && (1 - nubc * nucb) > 0 && (1 - nuac * nuca) > 0 && (1 - nuab * nuba) > 0;
463  if (!is_positive_definite)
464  mooseError("Orthotropic elasticity tensor input is not positive definite. Check input for "
465  "accuracy");
466 
467  _vals[0] = Ea * (1 - nubc * nucb) / k;
468  _vals[1] = Ea * (nubc * nuca + nuba) / k;
469  _vals[2] = Ea * (nuba * nucb + nuca) / k;
470 
471  _vals[6] = Eb * (nuac * nucb + nuab) / k;
472  _vals[7] = Eb * (1 - nuac * nuca) / k;
473  _vals[8] = Eb * (nuab * nuca + nucb) / k;
474 
475  _vals[12] = Ec * (nuab * nubc + nuac) / k;
476  _vals[13] = Ec * (nuac * nuba + nubc) / k;
477  _vals[14] = Ec * (1 - nuab * nuba) / k;
478 
479  _vals[21] = 2 * Gbc;
480  _vals[28] = 2 * Gca;
481  _vals[35] = 2 * Gab;
482 }
483 
484 template <typename T>
485 T
487 {
488  mooseAssert(LIBMESH_DIM == 3, "This method assumes LIBMESH_DIM == 3");
489  // summation of Ciijj used in the volumetric locking correction
490  T sum = 0;
491  for (const auto i : make_range(3))
492  for (const auto j : make_range(3))
493  sum += (*this)(i, j);
494  return sum;
495 }
496 
497 template <typename T>
500 {
501  mooseAssert(LIBMESH_DIM == 3, "This method assumes LIBMESH_DIM == 3");
502  // used for volumetric locking correction
503  return libMesh::VectorValue<T>(_vals[0] + _vals[1] + _vals[2],
504  _vals[6] + _vals[7] + _vals[8],
505  _vals[12] + _vals[13] + _vals[14]);
506 }
507 
508 template <typename T>
509 bool
511 {
512  for (unsigned int i = 0; i < N; ++i)
513  for (unsigned int j = 0; j < N; ++j)
514  // major symmetry
515  if (_vals[i + N * j] != _vals[N * i + j])
516  return false;
517  return true;
518 }
519 
520 template <typename T>
521 bool
523 {
524  // prerequisite is symmetry
525  if (!isSymmetric())
526  return false;
527 
528  // inspect shear components
529  const T & mu = _vals[35];
530 
531  // ...diagonal
532  if (_vals[28] != mu || _vals[21] != mu)
533  return false;
534 
535  // ...off-diagonal
536  if (_vals[22] != 0.0 || _vals[23] != 0.0 || _vals[29] != 0.0)
537  return false;
538 
539  // off diagonal blocks in Voigt
540  for (const auto i : make_range(3))
541  for (const auto j : make_range(3))
542  if (_vals[3 + i + N * j] != 0.0)
543  return false;
544 
545  // top left block
546  const T & K1 = _vals[0];
547  const T & K2 = _vals[1];
548  if (!MooseUtils::relativeFuzzyEqual(K1 - 2.0 * mu / 3.0, K2 + mu / 3.0))
549  return false;
550  if (_vals[7] != K1 || _vals[14] != K1)
551  return false;
552 
553  for (const auto i : make_range(1, 3))
554  for (const auto j : make_range(i))
555  if (_vals[i + N * j] != K2)
556  return false;
557 
558  return true;
559 }
void fillAxisymmetricRZFromInputVector(const std::vector< T > &input)
fillAxisymmetricRZFromInputVector takes 5 inputs to fill the axisymmetric Rank-4 tensor with the appr...
RankFourTensorTempl is designed to handle any N-dimensional fourth order tensor, C.
std::array< T, N2 > _vals
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 fillSymmetricIsotropicEandNu(const T &E, const T &nu)
static MooseEnum fillMethodEnum()
Static method for use in validParams for getting the "fill_method".
bool isIsotropic() const
checks if the tensor is isotropic
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
auto operator+(const SymmetricRankFourTensorTempl< T2 > &a) const -> SymmetricRankFourTensorTempl< decltype(T()+T2())>
C_ijkl + a_ijkl.
FillMethod
To fill up the 36 entries in the 4th-order tensor, fillFromInputVector is called with one of the foll...
void fillSymmetricIsotropic(const T &i0, const T &i1)
Vector-less fill API functions. See docs of the corresponding ...FromInputVector methods.
SymmetricRankFourTensorTempl< T > & operator-=(const SymmetricRankFourTensorTempl< T > &a)
C_ijkl -= a_ijkl.
auto operator*(const SymmetricRankTwoTensorTempl< T2 > &b) const -> SymmetricRankTwoTensorTempl< decltype(T() *T2())>
C_ijkl*a_kl.
auto raw_value(const Eigen::Map< T > &in)
Definition: EigenADReal.h:73
const Number zero
T sum3x3() const
Calculates the sum of Ciijj for i and j varying from 0 to 2.
static SymmetricRankFourTensorTempl< T > rotationMatrix(const TypeTensor< T > &R)
Build a 6x6 rotation matrix MEHRABADI, MORTEZA M.
SymmetricRankFourTensorTempl< T > & operator+=(const SymmetricRankFourTensorTempl< T > &a)
C_ijkl += a_ijkl for all i, j, k, l.
void fillSymmetricIsotropicEandNuFromInputVector(const std::vector< T > &input)
fillSymmetricIsotropicEandNuFromInputVector is a variation of the fillSymmetricIsotropicFromInputVect...
void init(triangulateio &t)
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
void rotate(const TypeTensor< T > &R)
Rotate the tensor using C_ijkl = R_im R_jn R_ko R_lp C_mnop.
SymmetricRankFourTensorTempl< T > & operator*=(const T &a)
C_ijkl *= a.
void fillPrincipalFromInputVector(const std::vector< T > &input)
fillPrincipalFromInputVector takes 9 inputs to fill a Rank-4 tensor C1111 = input0 C1122 = input1 C11...
void printReal(std::ostream &stm=Moose::out) const
Print the values of the rank four tensor.
void fillSymmetricIsotropicFromInputVector(const std::vector< T > &input)
fillSymmetricIsotropicFromInputVector takes 2 inputs to fill the the symmetric Rank-4 tensor with the...
SymmetricRankFourTensorTempl< T > transposeMajor() const
Transpose the tensor by swapping the first pair with the second pair of indices This amounts to a reg...
void print(std::ostream &stm=Moose::out) const
Print the rank four tensor.
void fillFromInputVector(const std::vector< T > &input, FillMethod fill_method)
fillFromInputVector takes some number of inputs to fill the Rank-4 tensor.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
SymmetricRankFourTensorTempl< T > operator-() const
-C_ijkl
bool relativeFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within a relative tolerance.
Definition: MooseUtils.h:492
void fillGeneralOrthotropicFromInputVector(const std::vector< T > &input)
fillGeneralOrhotropicFromInputVector takes 10 inputs to fill the Rank-4 tensor It defines a general o...
SymmetricRankFourTensorTempl is designed to handle an N-dimensional fourth order tensor with minor sy...
IntRange< T > make_range(T beg, T end)
bool isSymmetric() const
checks if the tensor is symmetric
SymmetricRankFourTensorTempl< T > & operator/=(const T &a)
C_ijkl /= a for all i, j, k, l.
SymmetricRankFourTensorTempl()
Default constructor; fills to zero.
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
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template pow< 2 >(tan(_arg))+1.0) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(sqrt
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)