23#include "libmesh/utility.h"
24#include "libmesh/tensor_value.h"
25#include "libmesh/vector_value.h"
43 return MooseEnum(
"symmetric9 symmetric21 symmetric_isotropic symmetric_isotropic_E_nu "
44 "axisymmetric_rz principal orthotropic");
50 mooseAssert(Ndim == 3,
51 "SymmetricRankFourTensorTempl<T> is designed to only work in 3 dimensions.");
65 for (
const auto i : make_range(Ndim))
69 case initIdentitySymmetricFour:
71 for (
const auto i : make_range(N))
76 mooseError(
"Unknown SymmetricRankFourTensorTempl<T> initialization pattern.");
83 for (
const auto a : make_range(N))
84 for (
const auto b : make_range(N))
86 const auto & idx = full_index[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);
101 for (
const auto a : make_range(N))
102 for (
const auto b : make_range(N))
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];
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);
123 fillFromInputVector(input, fill_method);
130 std::fill(_vals.begin(), _vals.end(), 0.0);
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)
143 M(i, j) = R(i, j) * R(i, j);
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]);
159 (*this) = M * (*this) * M.transposeMajor();
166 for (
const auto i : make_range(N2))
175 for (
const auto i : make_range(N2))
184 for (
const auto i : make_range(N2))
185 _vals[i] += a.
_vals[i];
190template <
typename T2>
196 for (
const auto i : make_range(N2))
197 result.
_vals[i] = _vals[i] + b._vals[i];
205 for (
const auto i : make_range(N2))
206 _vals[i] -= a.
_vals[i];
211template <
typename T2>
217 for (
const auto i : make_range(N2))
218 result.
_vals[i] = _vals[i] - b._vals[i];
227 for (
const auto i : make_range(N2))
228 result.
_vals[i] = -_vals[i];
233template <
typename T2>
238 typedef decltype(T() * T2()) ValueType;
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);
253 T l2 = Utility::pow<2>(_vals[0]);
254 for (
const auto i : make_range(1u, N2))
255 l2 += Utility::pow<2>(_vals[i]);
264 for (
const auto i : make_range(N))
266 for (
const auto j : make_range(N))
267 stm << std::setw(15) << _vals[i * N + j] <<
" ";
277 for (
const auto i : make_range(N))
279 for (
const auto j : make_range(N))
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];
307 fillSymmetric9FromInputVector(input);
310 fillSymmetric21FromInputVector(input);
312 case symmetric_isotropic:
313 fillSymmetricIsotropicFromInputVector(input);
315 case symmetric_isotropic_E_nu:
316 fillSymmetricIsotropicEandNuFromInputVector(input);
318 case axisymmetric_rz:
319 fillAxisymmetricRZFromInputVector(input);
322 fillPrincipalFromInputVector(input);
325 fillGeneralOrthotropicFromInputVector(input);
328 mooseError(
"fillFromInputVector called with unknown fill_method of ", fill_method);
336 mooseAssert(input.size() == 2,
337 "To use fillSymmetricIsotropicFromInputVector, your input must have size 2.");
338 fillSymmetricIsotropic(input[0], input[1]);
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,
359 const std::vector<T> & input)
361 if (input.size() != 2)
363 "To use fillSymmetricIsotropicEandNuFromInputVector, your input must have size 2. Yours "
367 fillSymmetricIsotropicEandNu(input[0], input[1]);
375 const T & lambda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu));
376 const T & G = E / (2.0 * (1.0 + nu));
378 fillSymmetricIsotropic(lambda, G);
385 mooseAssert(input.size() == 5,
386 "To use fillAxisymmetricRZFromInputVector, your input must have size 5.");
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,
401 (input[0] - input[1]) * 0.5}});
409 if (input.size() != 9)
410 mooseError(
"To use fillPrincipalFromInputVector, your input must have size 9. Yours has size ",
422 _vals[12] = input[6];
423 _vals[13] = input[7];
424 _vals[14] = input[8];
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 "
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];
451 bool preserve_symmetry = MooseUtils::relativeFuzzyEqual(nuab * Eb, nuba * Ea) &&
452 MooseUtils::relativeFuzzyEqual(nuca * Ea, nuac * Ec) &&
453 MooseUtils::relativeFuzzyEqual(nubc * Ec, nucb * Eb);
455 if (!preserve_symmetry)
456 mooseError(
"Orthotropic elasticity tensor input is not consistent with symmetry requirements. "
457 "Check input for accuracy");
460 T k = 1 - nuab * nuba - nubc * nucb - nuca * nuac - nuab * nubc * nuca - nuba * nucb * nuac;
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 "
468 _vals[0] = Ea * (1 - nubc * nucb) / k;
469 _vals[1] = Ea * (nubc * nuca + nuba) / k;
470 _vals[2] = Ea * (nuba * nucb + nuca) / k;
472 _vals[6] = Eb * (nuac * nucb + nuab) / k;
473 _vals[7] = Eb * (1 - nuac * nuca) / k;
474 _vals[8] = Eb * (nuab * nuca + nucb) / k;
476 _vals[12] = Ec * (nuab * nubc + nuac) / k;
477 _vals[13] = Ec * (nuac * nuba + nubc) / k;
478 _vals[14] = Ec * (1 - nuab * nuba) / k;
489 mooseAssert(LIBMESH_DIM == 3,
"This method assumes LIBMESH_DIM == 3");
492 for (
const auto i : make_range(3))
493 for (
const auto j : make_range(3))
494 sum += (*
this)(i, j);
502 mooseAssert(LIBMESH_DIM == 3,
"This method assumes LIBMESH_DIM == 3");
505 _vals[6] + _vals[7] + _vals[8],
506 _vals[12] + _vals[13] + _vals[14]);
513 for (
unsigned int i = 0; i < N; ++i)
514 for (
unsigned int j = 0; j < N; ++j)
516 if (_vals[i + N * j] != _vals[N * i + j])
530 const T & mu = _vals[35];
533 if (_vals[28] != mu || _vals[21] != mu)
537 if (_vals[22] != 0.0 || _vals[23] != 0.0 || _vals[29] != 0.0)
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)
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))
551 if (_vals[7] != K1 || _vals[14] != K1)
554 for (
const auto i : make_range(1, 3))
555 for (
const auto j : make_range(i))
556 if (_vals[i + N * j] != K2)
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
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...
friend class SymmetricRankFourTensorTempl
void zero()
Zeros out the tensor.
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.
InitMethod
Initialization method.
bool isSymmetric() const
checks if the tensor is symmetric
T L2norm() const
sqrt(C_ijkl*C_ijkl)
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)