https://mooseframework.inl.gov
RankTwoTensorImplementation.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 
12 #include "RankTwoTensor.h"
13 
14 // MOOSE includes
15 #include "MooseEnum.h"
16 #include "ColumnMajorMatrix.h"
17 #include "MooseRandom.h"
18 #include "RankFourTensor.h"
19 #include "SymmetricRankTwoTensor.h"
20 #include "Conversion.h"
21 #include "MooseArray.h"
22 
23 #include "libmesh/libmesh.h"
24 #include "libmesh/tensor_value.h"
25 #include "libmesh/vector_value.h"
26 #include "libmesh/utility.h"
27 
28 // PETSc includes
29 #include <petscblaslapack.h>
30 
31 // C++ includes
32 #include <iomanip>
33 #include <ostream>
34 #include <vector>
35 #include <array>
36 
37 // Eigen includes
38 #include <Eigen/Core>
39 #include <Eigen/Eigenvalues>
40 
41 namespace Eigen
42 {
43 namespace internal
44 {
45 template <>
46 struct cast_impl<ADReal, int>
47 {
48  static inline int run(const ADReal & x) { return static_cast<int>(MetaPhysicL::raw_value(x)); }
49 };
50 } // namespace internal
51 } // namespace Eigen
52 
53 template <typename T>
55 
56 namespace MathUtils
57 {
58 template <>
60 template <>
62 }
63 
64 template <typename T>
67 {
68  return MooseEnum("autodetect=0 isotropic1=1 diagonal3=3 symmetric6=6 general=9", "autodetect");
69 }
70 
71 template <typename T>
73 {
74  mooseAssert(N == 3, "RankTwoTensorTempl is currently only tested for 3 dimensions.");
75 
76  for (unsigned int i = 0; i < N2; i++)
77  _coords[i] = 0.0;
78 }
79 
80 template <typename T>
82 {
83  switch (init)
84  {
85  case initNone:
86  break;
87 
88  case initIdentity:
89  this->zero();
90  for (const auto i : make_range(N))
91  (*this)(i, i) = 1.0;
92  break;
93 
94  default:
95  mooseError("Unknown RankTwoTensorTempl initialization pattern.");
96  }
97 }
98 
99 template <typename T>
101  const libMesh::TypeVector<T> & row2,
102  const libMesh::TypeVector<T> & row3)
103 {
105  "This constructor is deprecated in favor of RankTwoTensorTempl<T>::initializeFromRows");
106 
107  // Initialize the Tensor matrix from the passed in vectors
108  for (const auto i : make_range(N))
109  _coords[i] = row1(i);
110 
111  for (const auto i : make_range(N))
112  _coords[N + i] = row2(i);
113 
114  for (const auto i : make_range(N))
115  _coords[2 * N + i] = row3(i);
116 }
117 
118 template <typename T>
121  const libMesh::TypeVector<T> & v1,
122  const libMesh::TypeVector<T> & v2)
123 {
124  return RankTwoTensorTempl<T>(v0(0),
125  (v1(0) + v0(1)) / 2.0,
126  (v2(0) + v0(2)) / 2.0,
127  (v1(0) + v0(1)) / 2.0,
128  v1(1),
129  (v2(1) + v1(2)) / 2.0,
130  (v2(0) + v0(2)) / 2.0,
131  (v2(1) + v1(2)) / 2.0,
132  v2(2));
133 }
134 
135 template <typename T>
138  const libMesh::TypeVector<T> & row1,
139  const libMesh::TypeVector<T> & row2)
140 {
141  return RankTwoTensorTempl<T>(
142  row0(0), row1(0), row2(0), row0(1), row1(1), row2(1), row0(2), row1(2), row2(2));
143 }
144 
145 template <typename T>
148  const libMesh::TypeVector<T> & col1,
149  const libMesh::TypeVector<T> & col2)
150 {
151  return RankTwoTensorTempl<T>(
152  col0(0), col0(1), col0(2), col1(0), col1(1), col1(2), col2(0), col2(1), col2(2));
153 }
154 
155 template <typename T>
157  const T & S11, const T & S22, const T & S33, const T & S23, const T & S13, const T & S12)
158 {
159  (*this)(0, 0) = S11;
160  (*this)(1, 1) = S22;
161  (*this)(2, 2) = S33;
162  (*this)(1, 2) = (*this)(2, 1) = S23;
163  (*this)(0, 2) = (*this)(2, 0) = S13;
164  (*this)(0, 1) = (*this)(1, 0) = S12;
165 }
166 
167 template <typename T>
169  const T & S21,
170  const T & S31,
171  const T & S12,
172  const T & S22,
173  const T & S32,
174  const T & S13,
175  const T & S23,
176  const T & S33)
177 {
178  (*this)(0, 0) = S11;
179  (*this)(1, 0) = S21;
180  (*this)(2, 0) = S31;
181  (*this)(0, 1) = S12;
182  (*this)(1, 1) = S22;
183  (*this)(2, 1) = S32;
184  (*this)(0, 2) = S13;
185  (*this)(1, 2) = S23;
186  (*this)(2, 2) = S33;
187 }
188 
189 template <typename T>
190 void
191 RankTwoTensorTempl<T>::fillFromInputVector(const std::vector<T> & input, FillMethod fill_method)
192 {
193  if (fill_method != autodetect && fill_method != input.size())
194  mooseError("Expected an input vector size of ", fill_method, " to fill the RankTwoTensorTempl");
195 
196  switch (input.size())
197  {
198  case 1:
199  this->zero();
200  (*this)(0, 0) = input[0]; // S11
201  (*this)(1, 1) = input[0]; // S22
202  (*this)(2, 2) = input[0]; // S33
203  break;
204 
205  case 3:
206  this->zero();
207  (*this)(0, 0) = input[0]; // S11
208  (*this)(1, 1) = input[1]; // S22
209  (*this)(2, 2) = input[2]; // S33
210  break;
211 
212  case 6:
213  (*this)(0, 0) = input[0]; // S11
214  (*this)(1, 1) = input[1]; // S22
215  (*this)(2, 2) = input[2]; // S33
216  (*this)(1, 2) = (*this)(2, 1) = input[3]; // S23
217  (*this)(0, 2) = (*this)(2, 0) = input[4]; // S13
218  (*this)(0, 1) = (*this)(1, 0) = input[5]; // S12
219  break;
220 
221  case 9:
222  (*this)(0, 0) = input[0]; // S11
223  (*this)(1, 0) = input[1]; // S21
224  (*this)(2, 0) = input[2]; // S31
225  (*this)(0, 1) = input[3]; // S12
226  (*this)(1, 1) = input[4]; // S22
227  (*this)(2, 1) = input[5]; // S32
228  (*this)(0, 2) = input[6]; // S13
229  (*this)(1, 2) = input[7]; // S23
230  (*this)(2, 2) = input[8]; // S33
231  break;
232 
233  default:
234  mooseError("Please check the number of entries in the input vector for building "
235  "a RankTwoTensorTempl. It must be 1, 3, 6, or 9");
236  }
237 }
238 
239 template <typename T>
240 void
242 {
243  switch (scalar_variable.size())
244  {
245  case 1:
246  this->zero();
247  (*this)(0, 0) = scalar_variable[0]; // S11
248  break;
249 
250  case 3:
251  this->zero();
252  (*this)(0, 0) = scalar_variable[0]; // S11
253  (*this)(1, 1) = scalar_variable[1]; // S22
254  (*this)(0, 1) = (*this)(1, 0) = scalar_variable[2]; // S12
255  break;
256 
257  case 6:
258  (*this)(0, 0) = scalar_variable[0]; // S11
259  (*this)(1, 1) = scalar_variable[1]; // S22
260  (*this)(2, 2) = scalar_variable[2]; // S33
261  (*this)(1, 2) = (*this)(2, 1) = scalar_variable[3]; // S23
262  (*this)(0, 2) = (*this)(2, 0) = scalar_variable[4]; // S13
263  (*this)(0, 1) = (*this)(1, 0) = scalar_variable[5]; // S12
264  break;
265 
266  default:
267  mooseError("Only FIRST, THIRD, or SIXTH order scalar variable can be used to build "
268  "a RankTwoTensorTempl.");
269  }
270 }
271 
272 template <typename T>
274 RankTwoTensorTempl<T>::column(const unsigned int c) const
275 {
276  return libMesh::VectorValue<T>((*this)(0, c), (*this)(1, c), (*this)(2, c));
277 }
278 
279 template <typename T>
282 {
283  return a * a.transpose();
284 }
285 
286 template <typename T>
289 {
290  return a.transpose() * a;
291 }
292 
293 template <typename T>
296 {
297  return a + a.transpose();
298 }
299 
300 template <typename T>
303 {
304  return *this * *this;
305 }
306 
307 template <typename T>
310 {
311  RankTwoTensorTempl<T> result(*this);
312  result.rotate(R);
313  return result;
314 }
315 
316 template <typename T>
317 void
319 {
321  for (const auto i : make_range(N))
322  {
323  const auto i1 = i * N;
324  for (const auto j : make_range(N))
325  {
326  // tmp += R(i,k)*R(j,l)*(*this)(k,l);
327  // clang-format off
328  const auto j1 = j * N;
329  T tmp = R._coords[i1 + 0] * R._coords[j1 + 0] * (*this)(0, 0) +
330  R._coords[i1 + 0] * R._coords[j1 + 1] * (*this)(0, 1) +
331  R._coords[i1 + 0] * R._coords[j1 + 2] * (*this)(0, 2) +
332  R._coords[i1 + 1] * R._coords[j1 + 0] * (*this)(1, 0) +
333  R._coords[i1 + 1] * R._coords[j1 + 1] * (*this)(1, 1) +
334  R._coords[i1 + 1] * R._coords[j1 + 2] * (*this)(1, 2) +
335  R._coords[i1 + 2] * R._coords[j1 + 0] * (*this)(2, 0) +
336  R._coords[i1 + 2] * R._coords[j1 + 1] * (*this)(2, 1) +
337  R._coords[i1 + 2] * R._coords[j1 + 2] * (*this)(2, 2);
338  // clang-format on
339  temp._coords[i1 + j] = tmp;
340  }
341  }
342  for (unsigned int i = 0; i < N2; i++)
343  _coords[i] = temp._coords[i];
344 }
345 
346 template <typename T>
349 {
350  using std::cos, std::sin;
351  T c = cos(a);
352  T s = sin(a);
353  T x = (*this)(0, 0) * c * c + (*this)(1, 1) * s * s + 2.0 * (*this)(0, 1) * c * s;
354  T y = (*this)(0, 0) * s * s + (*this)(1, 1) * c * c - 2.0 * (*this)(0, 1) * c * s;
355  T xy = ((*this)(1, 1) - (*this)(0, 0)) * c * s + (*this)(0, 1) * (c * c - s * s);
356 
357  RankTwoTensorTempl<T> b(*this);
358 
359  b(0, 0) = x;
360  b(1, 1) = y;
361  b(1, 0) = b(0, 1) = xy;
362 
363  return b;
364 }
365 
366 template <typename T>
369 {
371 }
372 
373 template <typename T>
376 {
378  return *this;
379 }
380 
381 template <typename T>
384 {
386  return *this;
387 }
388 
389 template <typename T>
392 {
394 }
395 
396 template <typename T>
399 {
401  return *this;
402 }
403 
404 template <typename T>
407 {
409  return *this;
410 }
411 
412 template <typename T>
415 {
416  *this = *this * a;
417  return *this;
418 }
419 
420 template <typename T>
421 bool
423 {
424  for (const auto i : make_range(N))
425  for (const auto j : make_range(N))
426  if (!MooseUtils::absoluteFuzzyEqual((*this)(i, j), a(i, j)))
427  return false;
428 
429  return true;
430 }
431 
432 template <typename T>
433 bool
435 {
436  auto test = MetaPhysicL::raw_value(*this - transpose());
437  return MooseUtils::absoluteFuzzyEqual(test.norm_sq(), 0);
438 }
439 
440 template <typename T>
443 {
444  if (a.n() != N || a.m() != N)
445  mooseError("Dimensions of ColumnMajorMatrixTempl<T> are incompatible with RankTwoTensorTempl");
446 
447  const T * cmm_rawdata = a.rawData();
448  for (const auto i : make_range(N))
449  for (const auto j : make_range(N))
450  _coords[i * N + j] = cmm_rawdata[i + j * N];
451 
452  return *this;
453 }
454 
455 template <typename T>
456 T
458 {
459  // deprecate this!
461 }
462 
463 template <typename T>
466 {
468 
469  for (const auto i : make_range(N))
470  for (const auto j : make_range(N))
471  for (const auto k : make_range(N))
472  for (const auto l : make_range(N))
473  result(i, k, l) += (*this)(i, j) * b(j, k, l);
474 
475  return result;
476 }
477 
478 template <typename T>
481 {
483 
484  for (const auto i : make_range(N))
485  for (const auto j : make_range(N))
486  for (const auto k : make_range(N))
487  result(i, j, k) += (*this)(j, k) * b(i);
488 
489  return result;
490 }
491 
492 template <typename T>
495 {
496  RankTwoTensorTempl<T> deviatoric(*this);
497  // actually construct deviatoric part
498  deviatoric.addIa(-1.0 / 3.0 * this->tr());
499  return deviatoric;
500 }
501 
502 template <typename T>
503 T
505 {
506  return (*this)(0, 0) * (*this)(1, 1) + (*this)(0, 0) * (*this)(2, 2) +
507  (*this)(1, 1) * (*this)(2, 2) - (*this)(0, 1) * (*this)(1, 0) -
508  (*this)(0, 2) * (*this)(2, 0) - (*this)(1, 2) * (*this)(2, 1);
509 }
510 
511 template <typename T>
512 T
514 {
515  T result;
516 
517  // RankTwoTensorTempl<T> deviatoric(*this);
518  // deviatoric.addIa(-1.0/3.0 * this->tr()); // actually construct deviatoric part
519  // result = 0.5*(deviatoric + deviatoric.transpose()).doubleContraction(deviatoric +
520  // deviatoric.transpose());
521  result = Utility::pow<2>((*this)(0, 0) - (*this)(1, 1)) / 6.0;
522  result += Utility::pow<2>((*this)(0, 0) - (*this)(2, 2)) / 6.0;
523  result += Utility::pow<2>((*this)(1, 1) - (*this)(2, 2)) / 6.0;
524  result += Utility::pow<2>((*this)(0, 1) + (*this)(1, 0)) / 4.0;
525  result += Utility::pow<2>((*this)(0, 2) + (*this)(2, 0)) / 4.0;
526  result += Utility::pow<2>((*this)(1, 2) + (*this)(2, 1)) / 4.0;
527  return result;
528 }
529 
530 template <typename T>
533 {
534  return RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
535 }
536 
537 template <typename T>
540 {
541  RankFourTensorTempl<T> result;
542  for (const auto i : make_range(N))
543  for (const auto j : make_range(N))
544  for (const auto k : make_range(N))
545  for (const auto l : make_range(N))
546  result(i, j, k, l) = 0.5 * (i == k) * (j == l) + 0.5 * (i == l) * (j == k) -
547  (1.0 / 3.0) * (i == j) * (k == l);
548  return result;
549 }
550 
551 template <typename T>
552 T
554 {
555  // deprecate this!
556  return this->tr();
557 }
558 
559 template <typename T>
562 {
563  return RankTwoTensorTempl<T>(1, 0, 0, 0, 1, 0, 0, 0, 1);
564 }
565 
566 template <typename T>
569 {
571 }
572 
573 template <typename T>
574 T
576 {
577  const auto s = RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
578  return s(0, 0) * (s(1, 1) * s(2, 2) - s(2, 1) * s(1, 2)) -
579  s(1, 0) * (s(0, 1) * s(2, 2) - s(2, 1) * s(0, 2)) +
580  s(2, 0) * (s(0, 1) * s(1, 2) - s(1, 1) * s(0, 2));
581 }
582 
583 template <typename T>
586 {
587  const auto s = RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
588  const T s3 = secondInvariant() / 3.0;
589 
591  d(0, 0) = s(1, 1) * s(2, 2) - s(2, 1) * s(1, 2) + s3;
592  d(0, 1) = s(2, 0) * s(1, 2) - s(1, 0) * s(2, 2);
593  d(0, 2) = s(1, 0) * s(2, 1) - s(2, 0) * s(1, 1);
594  d(1, 0) = s(2, 1) * s(0, 2) - s(0, 1) * s(2, 2);
595  d(1, 1) = s(0, 0) * s(2, 2) - s(2, 0) * s(0, 2) + s3;
596  d(1, 2) = s(2, 0) * s(0, 1) - s(0, 0) * s(2, 1);
597  d(2, 0) = s(0, 1) * s(1, 2) - s(1, 1) * s(0, 2);
598  d(2, 1) = s(1, 0) * s(0, 2) - s(0, 0) * s(1, 2);
599  d(2, 2) = s(0, 0) * s(1, 1) - s(1, 0) * s(0, 1) + s3;
600  return d;
601 }
602 
603 template <typename T>
606 {
607  const auto s = RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
608 
610  for (const auto i : make_range(N))
611  for (const auto j : make_range(N))
612  for (const auto k : make_range(N))
613  for (const auto l : make_range(N))
614  {
615  d2(i, j, k, l) = Real(i == j) * s(k, l) / 3.0 + Real(k == l) * s(i, j) / 3.0;
616  // for (const auto a: make_range(N))
617  // for (const auto b: make_range(N))
618  // d2(i, j, k, l) += 0.5*(PermutationTensor::eps(i, k, a)*PermutationTensor::eps(j, l,
619  // b) + PermutationTensor::eps(i, l, a)*PermutationTensor::eps(j, k, b))*s(a, b);
620  }
621 
622  // I'm not sure which is more readable: the above
623  // PermutationTensor stuff, or the stuff below.
624  // Anyway, they yield the same result, and so i leave
625  // both of them here to enlighten you!
626 
627  d2(0, 0, 1, 1) += s(2, 2);
628  d2(0, 0, 1, 2) -= s(2, 1);
629  d2(0, 0, 2, 1) -= s(1, 2);
630  d2(0, 0, 2, 2) += s(1, 1);
631 
632  d2(0, 1, 0, 1) -= s(2, 2) / 2.0;
633  d2(0, 1, 1, 0) -= s(2, 2) / 2.0;
634  d2(0, 1, 0, 2) += s(1, 2) / 2.0;
635  d2(0, 1, 2, 0) += s(1, 2) / 2.0;
636  d2(0, 1, 1, 2) += s(2, 0) / 2.0;
637  d2(0, 1, 2, 1) += s(2, 0) / 2.0;
638  d2(0, 1, 2, 2) -= s(1, 0);
639 
640  d2(0, 2, 0, 1) += s(2, 1) / 2.0;
641  d2(0, 2, 1, 0) += s(2, 1) / 2.0;
642  d2(0, 2, 0, 2) -= s(1, 1) / 2.0;
643  d2(0, 2, 2, 0) -= s(1, 1) / 2.0;
644  d2(0, 2, 1, 1) -= s(2, 0);
645  d2(0, 2, 1, 2) += s(1, 0) / 2.0;
646  d2(0, 2, 2, 1) += s(1, 0) / 2.0;
647 
648  d2(1, 0, 0, 1) -= s(2, 2) / 2.0;
649  d2(1, 0, 1, 0) -= s(2, 2) / 2.0;
650  d2(1, 0, 0, 2) += s(1, 2) / 2.0;
651  d2(1, 0, 2, 0) += s(1, 2) / 2.0;
652  d2(1, 0, 1, 2) += s(2, 0) / 2.0;
653  d2(1, 0, 2, 1) += s(2, 0) / 2.0;
654  d2(1, 0, 2, 2) -= s(1, 0);
655 
656  d2(1, 1, 0, 0) += s(2, 2);
657  d2(1, 1, 0, 2) -= s(2, 0);
658  d2(1, 1, 2, 0) -= s(2, 0);
659  d2(1, 1, 2, 2) += s(0, 0);
660 
661  d2(1, 2, 0, 0) -= s(2, 1);
662  d2(1, 2, 0, 1) += s(2, 0) / 2.0;
663  d2(1, 2, 1, 0) += s(2, 0) / 2.0;
664  d2(1, 2, 0, 2) += s(0, 1) / 2.0;
665  d2(1, 2, 2, 0) += s(0, 1) / 2.0;
666  d2(1, 2, 1, 2) -= s(0, 0) / 2.0;
667  d2(1, 2, 2, 1) -= s(0, 0) / 2.0;
668 
669  d2(2, 0, 0, 1) += s(2, 1) / 2.0;
670  d2(2, 0, 1, 0) += s(2, 1) / 2.0;
671  d2(2, 0, 0, 2) -= s(1, 1) / 2.0;
672  d2(2, 0, 2, 0) -= s(1, 1) / 2.0;
673  d2(2, 0, 1, 1) -= s(2, 0);
674  d2(2, 0, 1, 2) += s(1, 0) / 2.0;
675  d2(2, 0, 2, 1) += s(1, 0) / 2.0;
676 
677  d2(2, 1, 0, 0) -= s(2, 1);
678  d2(2, 1, 0, 1) += s(2, 0) / 2.0;
679  d2(2, 1, 1, 0) += s(2, 0) / 2.0;
680  d2(2, 1, 0, 2) += s(0, 1) / 2.0;
681  d2(2, 1, 2, 0) += s(0, 1) / 2.0;
682  d2(2, 1, 1, 2) -= s(0, 0) / 2.0;
683  d2(2, 1, 2, 1) -= s(0, 0) / 2.0;
684 
685  d2(2, 2, 0, 0) += s(1, 1);
686  d2(2, 2, 0, 1) -= s(1, 0);
687  d2(2, 2, 1, 0) -= s(1, 0);
688  d2(2, 2, 1, 1) += s(0, 0);
689 
690  return d2;
691 }
692 
693 template <typename T>
696 {
698 
699  d(0, 0) = (*this)(1, 1) * (*this)(2, 2) - (*this)(2, 1) * (*this)(1, 2);
700  d(0, 1) = (*this)(2, 0) * (*this)(1, 2) - (*this)(1, 0) * (*this)(2, 2);
701  d(0, 2) = (*this)(1, 0) * (*this)(2, 1) - (*this)(2, 0) * (*this)(1, 1);
702  d(1, 0) = (*this)(2, 1) * (*this)(0, 2) - (*this)(0, 1) * (*this)(2, 2);
703  d(1, 1) = (*this)(0, 0) * (*this)(2, 2) - (*this)(2, 0) * (*this)(0, 2);
704  d(1, 2) = (*this)(2, 0) * (*this)(0, 1) - (*this)(0, 0) * (*this)(2, 1);
705  d(2, 0) = (*this)(0, 1) * (*this)(1, 2) - (*this)(1, 1) * (*this)(0, 2);
706  d(2, 1) = (*this)(1, 0) * (*this)(0, 2) - (*this)(0, 0) * (*this)(1, 2);
707  d(2, 2) = (*this)(0, 0) * (*this)(1, 1) - (*this)(1, 0) * (*this)(0, 1);
708 
709  return d;
710 }
711 
712 template <typename T>
713 void
714 RankTwoTensorTempl<T>::print(std::ostream & stm) const
715 {
716  const RankTwoTensorTempl<T> & a = *this;
717  for (const auto i : make_range(N))
718  {
719  for (const auto j : make_range(N))
720  stm << std::setw(15) << a(i, j) << ' ';
721  stm << std::endl;
722  }
723 }
724 
725 template <>
726 void RankTwoTensor::printReal(std::ostream & stm) const;
727 
728 template <>
729 void ADRankTwoTensor::printReal(std::ostream & stm) const;
730 
731 template <>
732 void ADRankTwoTensor::printADReal(unsigned int nDual, std::ostream & stm) const;
733 
734 template <typename T>
735 void
737 {
738  for (const auto i : make_range(N))
739  (*this)(i, i) += a;
740 }
741 
742 template <typename T>
743 T
745 {
746  T norm = 0.0;
747  for (const auto i : make_range(N2))
748  {
749  T v = _coords[i];
750  norm += v * v;
751  }
752  using std::sqrt;
753  return norm == 0.0 ? 0.0 : sqrt(norm);
754 }
755 
756 template <typename T>
757 void
759 {
760  if (input.size() == 4)
761  {
762  // initialize with zeros
763  this->zero();
764  (*this)(0, 0) = input[0];
765  (*this)(0, 1) = input[1];
766  (*this)(1, 0) = input[2];
767  (*this)(1, 1) = input[3];
768  }
769  else
770  mooseError("please provide correct number of values for surface RankTwoTensorTempl<T> "
771  "initialization.");
772 }
773 
774 template <typename T>
775 void
776 RankTwoTensorTempl<T>::syev(const char *, std::vector<T> &, std::vector<T> &) const
777 {
778  mooseError("The syev method is only supported for Real valued tensors");
779 }
780 
781 template <>
782 void RankTwoTensor::syev(const char * calculation_type,
783  std::vector<Real> & eigvals,
784  std::vector<Real> & a) const;
785 
786 template <typename T>
787 void
788 RankTwoTensorTempl<T>::symmetricEigenvalues(std::vector<T> & eigvals) const
789 {
791  symmetricEigenvaluesEigenvectors(eigvals, a);
792 }
793 
794 template <>
795 void RankTwoTensor::symmetricEigenvalues(std::vector<Real> & eigvals) const;
796 
797 template <typename T>
798 void
800  RankTwoTensorTempl<T> &) const
801 {
802  mooseError(
803  "symmetricEigenvaluesEigenvectors is only available for ordered tensor component types");
804 }
805 
806 template <>
807 void RankTwoTensor::symmetricEigenvaluesEigenvectors(std::vector<Real> & eigvals,
808  RankTwoTensor & eigvecs) const;
809 
810 template <>
811 void ADRankTwoTensor::symmetricEigenvaluesEigenvectors(std::vector<ADReal> & eigvals,
812  ADRankTwoTensor & eigvecs) const;
813 
814 template <typename T>
815 void
817  std::vector<RankTwoTensorTempl<T>> & deigvals) const
818 {
819  deigvals.resize(N);
820 
821  std::vector<T> a;
822  syev("V", eigvals, a);
823 
824  // now a contains the eigenvetors
825  // extract these and place appropriately in deigvals
826  std::vector<T> eig_vec;
827  eig_vec.resize(N);
828 
829  for (const auto i : make_range(N))
830  {
831  for (const auto j : make_range(N))
832  eig_vec[j] = a[i * N + j];
833  for (const auto j : make_range(N))
834  for (const auto k : make_range(N))
835  deigvals[i](j, k) = eig_vec[j] * eig_vec[k];
836  }
837 
838  // There are discontinuities in the derivative
839  // for equal eigenvalues. The following is
840  // an attempt to make a sensible choice for
841  // the derivative. This agrees with a central-difference
842  // approximation to the derivative.
843  if (eigvals[0] == eigvals[1] && eigvals[0] == eigvals[2])
844  deigvals[0] = deigvals[1] = deigvals[2] = (deigvals[0] + deigvals[1] + deigvals[2]) / 3.0;
845  else if (eigvals[0] == eigvals[1])
846  deigvals[0] = deigvals[1] = (deigvals[0] + deigvals[1]) / 2.0;
847  else if (eigvals[0] == eigvals[2])
848  deigvals[0] = deigvals[2] = (deigvals[0] + deigvals[2]) / 2.0;
849  else if (eigvals[1] == eigvals[2])
850  deigvals[1] = deigvals[2] = (deigvals[1] + deigvals[2]) / 2.0;
851 }
852 
853 template <typename T>
854 void
856 {
857  std::vector<T> eigvec;
858  std::vector<T> eigvals;
859  T ev[N][N];
860 
861  // reset rank four tensor
862  deriv.assign(N, RankFourTensorTempl<T>());
863 
864  // get eigen values and eigen vectors
865  syev("V", eigvals, eigvec);
866 
867  for (const auto i : make_range(N))
868  for (const auto j : make_range(N))
869  ev[i][j] = eigvec[i * N + j];
870 
871  for (unsigned int alpha = 0; alpha < N; ++alpha)
872  for (unsigned int beta = 0; beta < N; ++beta)
873  {
874  if (eigvals[alpha] == eigvals[beta])
875  continue;
876 
877  for (const auto i : make_range(N))
878  for (const auto j : make_range(N))
879  for (const auto k : make_range(N))
880  for (const auto l : make_range(N))
881  {
882  deriv[alpha](i, j, k, l) +=
883  0.5 * (ev[beta][i] * ev[alpha][j] + ev[alpha][i] * ev[beta][j]) *
884  (ev[beta][k] * ev[alpha][l] + ev[beta][l] * ev[alpha][k]) /
885  (eigvals[alpha] - eigvals[beta]);
886  }
887  }
888 }
889 
890 template <typename T>
891 void
893 {
894  mooseError("getRUDecompositionRotation is only supported for Real valued tensors");
895 }
896 
897 template <>
899 
900 template <typename T>
901 void
902 RankTwoTensorTempl<T>::initRandom(unsigned int rand_seed)
903 {
904  MooseRandom::seed(rand_seed);
905 }
906 
907 template <typename T>
910 {
911  RankTwoTensorTempl<T> result;
912  for (const auto i : make_range(N))
913  for (const auto j : make_range(N))
914  result(i, j) = (MooseRandom::rand() + mean) * stddev;
915  return result;
916 }
917 
918 template <typename T>
921 {
922  auto r = [&]() { return (MooseRandom::rand() + mean) * stddev; };
923  return RankTwoTensorTempl<T>(r(), r(), r(), r(), r(), r());
924 }
925 
926 template <typename T>
927 void
929  const libMesh::TypeVector<T> & v2)
930 {
931  RankTwoTensorTempl<T> & a = *this;
932  for (const auto i : make_range(N))
933  for (const auto j : make_range(N))
934  a(i, j) = v1(i) * v2(j);
935 }
936 
937 template <typename T>
940  const libMesh::TypeVector<T> & v2)
941 {
942  RankTwoTensorTempl<T> result;
943  for (const auto i : make_range(N))
944  for (const auto j : make_range(N))
945  result(i, j) = v1(i) * v2(j);
946  return result;
947 }
948 
949 template <typename T>
952 {
954  for (unsigned int i = 0; i < N; ++i)
955  for (unsigned int j = 0; j < N; ++j)
956  result(i, j) = v(i) * v(j);
957  return result;
958 }
959 
960 template <typename T>
961 void
963 {
964  for (const auto i : make_range(N))
965  for (const auto j : make_range(N))
966  tensor(i, j) = (*this)(i, j);
967 }
968 
969 template <typename T>
970 void
972 {
973  for (const auto i : make_range(N))
974  (*this)(r, i) = v(i);
975 }
976 
977 template <typename T>
978 void
980 {
981  for (const auto i : make_range(N))
982  (*this)(i, c) = v(i);
983 }
984 
985 template <typename T>
988 {
989  RankTwoTensorTempl<T> result;
990  for (const auto i : make_range(N))
991  for (const auto j : make_range(N))
992  for (const auto k : make_range(N))
993  for (const auto l : make_range(N))
994  result(k, l) += (*this)(i, j) * b(i, j, k, l);
995  return result;
996 }
997 
998 template <typename T>
999 void
1001 {
1002  mooseAssert(N2 == 9, "RankTwoTensorTempl is currently only tested for 3 dimensions.");
1003  for (const auto i : make_range(N2))
1004  _coords[i] = identityCoords[i];
1005 }
RankFourTensorTempl is designed to handle any N-dimensional fourth order tensor, C.
void fillRow(unsigned int r, const libMesh::TypeVector< T > &v)
Assign values to a specific row of the second order tensor.
RankTwoTensorTempl< T > dsecondInvariant() const
Return the derivative of the main second invariant w.r.t.
RankTwoTensorTempl< T > inverse() const
Return the inverse of this second order tensor.
RankFourTensorTempl< T > d2secondInvariant() const
Return the second derivative of the main second invariant w.r.t.
RankTwoTensorTempl()
Empty constructor; fills to zero.
bool operator==(const RankTwoTensorTempl< T > &a) const
Defines logical equality with another RankTwoTensorTempl<T>
void printADReal(unsigned int nDual, std::ostream &stm=Moose::out) const
Print the Real part of the RankTwoTensorTempl<ADReal> along with its first nDual dual numbers...
T generalSecondInvariant() const
Return the principal second invariant of this second order tensor.
const TypeTensor< T > & operator/=(const T &)
static RankTwoTensorTempl initializeSymmetric(const libMesh::TypeVector< T > &v0, const libMesh::TypeVector< T > &v1, const libMesh::TypeVector< T > &v2)
Named constructor for initializing symmetrically.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
static void initRandom(unsigned int)
Initialize the random seed based on an unsigned integer.
void symmetricEigenvalues(std::vector< T > &eigvals) const
computes eigenvalues, assuming tens is symmetric, and places them in ascending order in eigvals ...
This class defines a Tensor that can change its shape.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
void dsymmetricEigenvalues(std::vector< T > &eigvals, std::vector< RankTwoTensorTempl< T >> &deigvals) const
computes eigenvalues, and their symmetric derivatives wrt vals, assuming tens is symmetric ...
static RankTwoTensorTempl< T > genRandomTensor(T stddev, T mean)
Generate a random second order tensor with all 9 components treated as independent random variables f...
void print(std::ostream &stm=Moose::out) const
Print the rank two tensor.
RankTwoTensorTempl< T > & operator-=(const RankTwoTensorTempl< T > &a)
Subtract another second order tensor from this one.
static RankTwoTensorTempl< T > plusTranspose(const RankTwoTensorTempl< T > &)
Initialize a second order tensor with expression .
RankThreeTensorTempl< T > contraction(const RankThreeTensorTempl< T > &b) const
Return the single contraction of this second order tensor with a third order tensor ...
TypeTensor< T > transpose() const
Definition: JsonIO.h:48
auto raw_value(const Eigen::Map< T > &in)
Definition: EigenADReal.h:100
void surfaceFillFromInputVector(const std::vector< T > &input)
sets _coords[0][0], _coords[0][1], _coords[1][0], _coords[1][1] to input, and the remainder to zero ...
void mooseSetToZero< ADRankTwoTensor >(ADRankTwoTensor &v)
Helper function template specialization to set an object to zero.
Definition: RankTwoTensor.C:26
RankTwoTensorTempl< T > & operator+=(const RankTwoTensorTempl< T > &a)
Add another second order tensor to this one.
T secondInvariant() const
Return the main second invariant of this second order tensor.
RankTwoTensorTempl< T > dtrace() const
Return the derivative of the trace w.r.t.
const Number zero
T _coords[LIBMESH_DIM *LIBMESH_DIM]
DualNumber< Real, DNDerivativeType, true > ADReal
Definition: ADRealForward.h:42
RankTwoTensorTempl< T > dthirdInvariant() const
Denote the _coords[i][j] by A_ij, then this returns d(thirdInvariant()/dA_ij.
void rotate(const RankTwoTensorTempl< T > &R)
Rotate the tensor in-place given a rotation tensor .
RankThreeTensor is designed to handle any N-dimensional third order tensor, r.
void fillColumn(unsigned int c, const libMesh::TypeVector< T > &v)
Assign values to a specific column of the second order tensor.
T trace() const
A wrapper for tr()
static RankTwoTensorTempl< T > selfOuterProduct(const libMesh::TypeVector< T > &)
Initialize a second order tensor as the outer product of a vector with itself, i.e.
static RankTwoTensorTempl initializeFromRows(const libMesh::TypeVector< T > &row0, const libMesh::TypeVector< T > &row1, const libMesh::TypeVector< T > &row2)
Named constructor for initializing from row vectors.
RankTwoTensorTempl< T > deviatoric() const
Return the deviatoric part of this tensor .
static MooseEnum fillMethodEnum()
Get the available FillMethod options.
T L2norm() const
Sqrt(_coords[i][j]*_coords[i][j])
T * rawData()
Returns a reference to the raw data pointer.
void fillFromInputVector(const std::vector< T > &input, FillMethod fill_method=autodetect)
The smart mutator that determines how to fill the second order tensor based on the size of the input ...
void setToIdentity()
Set the tensor to identity.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
TypeTensor< T > operator-() const
RankTwoTensorTempl< T > & operator/=(const T &a)
Divide this tensor by a scalar (component-wise)
Real deriv(unsigned n, unsigned alpha, unsigned beta, Real x)
RankFourTensorTempl< T > d2thirdInvariant() const
Denote the _coords[i][j] by A_ij, then this returns d^2(thirdInvariant)/dA_ij/dA_kl.
void addIa(const T &a)
Add identity times a to _coords.
unsigned int m() const
Returns the number of columns.
RankTwoTensorTempl< T > rotateXyPlane(T a)
Rotate the tensor about the z-axis.
libMesh::VectorValue< T > column(const unsigned int i) const
Get the i-th column of the second order tensor.
void d2symmetricEigenvalues(std::vector< RankFourTensorTempl< T >> &deriv) const
Computes second derivatives of Eigenvalues of a rank two tensor.
static RankTwoTensorTempl< T > genRandomSymmTensor(T stddev, T mean)
Generate a random symmetric second order tensor with the 6 upper-triangular components treated as ind...
void init(triangulateio &t)
RankTwoTensorTempl< T > rotated(const RankTwoTensorTempl< T > &R) const
Return the rotated tensor given a rotation tensor .
T doubleContraction(const RankTwoTensorTempl< T > &a) const
Return the double contraction with another second order tensor .
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
RankTwoTensorTempl< T > square() const
Return .
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:374
auto norm(const T &a) -> decltype(std::abs(a))
RankTwoTensorTempl< T > & operator*=(const T &a)
Multiply this tensor by a scalar (component-wise)
T thirdInvariant() const
Denote the _coords[i][j] by A_ij, then S_ij = A_ij - de_ij*tr(A)/3 Then this returns det(S + S...
CompareTypes< T, T2 >::supertype contract(const TypeTensor< T2 > &) const
void printReal(std::ostream &stm=Moose::out) const
Print the Real part of the RankTwoTensorTempl<ADReal>
static RankTwoTensorTempl< T > timesTranspose(const RankTwoTensorTempl< T > &)
Initialize a second order tensor with expression .
OutputTools< Real >::VariableValue VariableValue
Definition: MooseTypes.h:343
static RankTwoTensorTempl< T > transposeTimes(const RankTwoTensorTempl< T > &)
Initialize a second order tensor with expression .
RankTwoTensorTempl< T > transpose() const
Return the tensor transposed.
void vectorOuterProduct(const libMesh::TypeVector< T > &, const libMesh::TypeVector< T > &)
Set the values of the second order tensor to be the outer product of two vectors, i...
void fillRealTensor(libMesh::TensorValue< T > &)
Fill a libMesh::TensorValue<T> from this second order tensor.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool isSymmetric() const
Test for symmetry.
void symmetricEigenvaluesEigenvectors(std::vector< T > &eigvals, RankTwoTensorTempl< T > &eigvecs) const
computes eigenvalues and eigenvectors, assuming tens is symmetric, and places them in ascending order...
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
RankTwoTensorTempl< T > operator-() const
Return the negation of this tensor.
RankTwoTensorTempl is designed to handle the Stress or Strain Tensor for a fully anisotropic material...
Definition: RankTwoTensor.h:87
static void seed(unsigned int seed)
The method seeds the random number generator.
Definition: MooseRandom.h:44
RankThreeTensorTempl< T > mixedProductJkI(const libMesh::VectorValue< T > &b) const
Return the tensor product of this second order tensor with a vector .
TypeTensor< T > inverse() const
void syev(const char *calculation_type, std::vector< T > &eigvals, std::vector< T > &a) const
Uses the petscblaslapack.h LAPACKsyev_ routine to find, for symmetric _coords: (1) the eigenvalues (i...
static RankTwoTensorTempl< T > outerProduct(const libMesh::TypeVector< T > &, const libMesh::TypeVector< T > &)
Initialize a second order tensor as the outer product of two vectors, i.e.
IntRange< T > make_range(T beg, T end)
void getRUDecompositionRotation(RankTwoTensorTempl< T > &rot) const
Uses the petscblaslapack.h LAPACKsyev_ routine to perform RU decomposition and obtain the rotation te...
static Real rand()
This method returns the next random number (Real format) from the generator.
Definition: MooseRandom.h:50
RankTwoTensorTempl< T > ddet() const
Denote the _coords[i][j] by A_ij, then this returns d(det)/dA_ij.
FillMethod
To fill up the 9 entries in the 2nd-order tensor, fillFromInputVector is called with one of the follo...
const TypeTensor< T > & operator-=(const TypeTensor< T2 > &)
const TypeTensor< T > & operator+=(const TypeTensor< T2 > &)
unsigned int n() const
Returns the number of rows.
static RankTwoTensorTempl initializeFromColumns(const libMesh::TypeVector< T > &col0, const libMesh::TypeVector< T > &col1, const libMesh::TypeVector< T > &col2)
Named constructor for initializing from row vectors.
RankTwoTensorTempl< T > initialContraction(const RankFourTensorTempl< T > &b) const
returns this_ij * b_ijkl
void mooseSetToZero< RankTwoTensor >(RankTwoTensor &v)
Helper function template specialization to set an object to zero.
Definition: RankTwoTensor.C:19
InitMethod
The initialization method.
const TypeTensor< T > & operator*=(const Scalar &factor)
RankTwoTensorTempl< T > & operator=(const RankTwoTensorTempl< T > &a)=default
Assignment operator.
void fillFromScalarVariable(const VariableValue &scalar_variable)
The smart mutator that determines how to fill the second order tensor based on the order of the scal...
void ErrorVector unsigned int
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