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  T c = std::cos(a);
351  T s = std::sin(a);
352  T x = (*this)(0, 0) * c * c + (*this)(1, 1) * s * s + 2.0 * (*this)(0, 1) * c * s;
353  T y = (*this)(0, 0) * s * s + (*this)(1, 1) * c * c - 2.0 * (*this)(0, 1) * c * s;
354  T xy = ((*this)(1, 1) - (*this)(0, 0)) * c * s + (*this)(0, 1) * (c * c - s * s);
355 
356  RankTwoTensorTempl<T> b(*this);
357 
358  b(0, 0) = x;
359  b(1, 1) = y;
360  b(1, 0) = b(0, 1) = xy;
361 
362  return b;
363 }
364 
365 template <typename T>
368 {
370 }
371 
372 template <typename T>
375 {
377  return *this;
378 }
379 
380 template <typename T>
383 {
385  return *this;
386 }
387 
388 template <typename T>
391 {
393 }
394 
395 template <typename T>
398 {
400  return *this;
401 }
402 
403 template <typename T>
406 {
408  return *this;
409 }
410 
411 template <typename T>
414 {
415  *this = *this * a;
416  return *this;
417 }
418 
419 template <typename T>
420 bool
422 {
423  for (const auto i : make_range(N))
424  for (const auto j : make_range(N))
425  if (!MooseUtils::absoluteFuzzyEqual((*this)(i, j), a(i, j)))
426  return false;
427 
428  return true;
429 }
430 
431 template <typename T>
432 bool
434 {
435  auto test = MetaPhysicL::raw_value(*this - transpose());
436  return MooseUtils::absoluteFuzzyEqual(test.norm_sq(), 0);
437 }
438 
439 template <typename T>
442 {
443  if (a.n() != N || a.m() != N)
444  mooseError("Dimensions of ColumnMajorMatrixTempl<T> are incompatible with RankTwoTensorTempl");
445 
446  const T * cmm_rawdata = a.rawData();
447  for (const auto i : make_range(N))
448  for (const auto j : make_range(N))
449  _coords[i * N + j] = cmm_rawdata[i + j * N];
450 
451  return *this;
452 }
453 
454 template <typename T>
455 T
457 {
458  // deprecate this!
460 }
461 
462 template <typename T>
465 {
467 
468  for (const auto i : make_range(N))
469  for (const auto j : make_range(N))
470  for (const auto k : make_range(N))
471  for (const auto l : make_range(N))
472  result(i, k, l) += (*this)(i, j) * b(j, k, l);
473 
474  return result;
475 }
476 
477 template <typename T>
480 {
482 
483  for (const auto i : make_range(N))
484  for (const auto j : make_range(N))
485  for (const auto k : make_range(N))
486  result(i, j, k) += (*this)(j, k) * b(i);
487 
488  return result;
489 }
490 
491 template <typename T>
494 {
495  RankTwoTensorTempl<T> deviatoric(*this);
496  // actually construct deviatoric part
497  deviatoric.addIa(-1.0 / 3.0 * this->tr());
498  return deviatoric;
499 }
500 
501 template <typename T>
502 T
504 {
505  return (*this)(0, 0) * (*this)(1, 1) + (*this)(0, 0) * (*this)(2, 2) +
506  (*this)(1, 1) * (*this)(2, 2) - (*this)(0, 1) * (*this)(1, 0) -
507  (*this)(0, 2) * (*this)(2, 0) - (*this)(1, 2) * (*this)(2, 1);
508 }
509 
510 template <typename T>
511 T
513 {
514  T result;
515 
516  // RankTwoTensorTempl<T> deviatoric(*this);
517  // deviatoric.addIa(-1.0/3.0 * this->tr()); // actually construct deviatoric part
518  // result = 0.5*(deviatoric + deviatoric.transpose()).doubleContraction(deviatoric +
519  // deviatoric.transpose());
520  result = Utility::pow<2>((*this)(0, 0) - (*this)(1, 1)) / 6.0;
521  result += Utility::pow<2>((*this)(0, 0) - (*this)(2, 2)) / 6.0;
522  result += Utility::pow<2>((*this)(1, 1) - (*this)(2, 2)) / 6.0;
523  result += Utility::pow<2>((*this)(0, 1) + (*this)(1, 0)) / 4.0;
524  result += Utility::pow<2>((*this)(0, 2) + (*this)(2, 0)) / 4.0;
525  result += Utility::pow<2>((*this)(1, 2) + (*this)(2, 1)) / 4.0;
526  return result;
527 }
528 
529 template <typename T>
532 {
533  return RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
534 }
535 
536 template <typename T>
539 {
540  RankFourTensorTempl<T> result;
541  for (const auto i : make_range(N))
542  for (const auto j : make_range(N))
543  for (const auto k : make_range(N))
544  for (const auto l : make_range(N))
545  result(i, j, k, l) = 0.5 * (i == k) * (j == l) + 0.5 * (i == l) * (j == k) -
546  (1.0 / 3.0) * (i == j) * (k == l);
547  return result;
548 }
549 
550 template <typename T>
551 T
553 {
554  // deprecate this!
555  return this->tr();
556 }
557 
558 template <typename T>
561 {
562  return RankTwoTensorTempl<T>(1, 0, 0, 0, 1, 0, 0, 0, 1);
563 }
564 
565 template <typename T>
568 {
570 }
571 
572 template <typename T>
573 T
575 {
576  const auto s = RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
577  return s(0, 0) * (s(1, 1) * s(2, 2) - s(2, 1) * s(1, 2)) -
578  s(1, 0) * (s(0, 1) * s(2, 2) - s(2, 1) * s(0, 2)) +
579  s(2, 0) * (s(0, 1) * s(1, 2) - s(1, 1) * s(0, 2));
580 }
581 
582 template <typename T>
585 {
586  const auto s = RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
587  const T s3 = secondInvariant() / 3.0;
588 
590  d(0, 0) = s(1, 1) * s(2, 2) - s(2, 1) * s(1, 2) + s3;
591  d(0, 1) = s(2, 0) * s(1, 2) - s(1, 0) * s(2, 2);
592  d(0, 2) = s(1, 0) * s(2, 1) - s(2, 0) * s(1, 1);
593  d(1, 0) = s(2, 1) * s(0, 2) - s(0, 1) * s(2, 2);
594  d(1, 1) = s(0, 0) * s(2, 2) - s(2, 0) * s(0, 2) + s3;
595  d(1, 2) = s(2, 0) * s(0, 1) - s(0, 0) * s(2, 1);
596  d(2, 0) = s(0, 1) * s(1, 2) - s(1, 1) * s(0, 2);
597  d(2, 1) = s(1, 0) * s(0, 2) - s(0, 0) * s(1, 2);
598  d(2, 2) = s(0, 0) * s(1, 1) - s(1, 0) * s(0, 1) + s3;
599  return d;
600 }
601 
602 template <typename T>
605 {
606  const auto s = RankTwoTensorTempl<T>::plusTranspose(deviatoric()) * 0.5;
607 
609  for (const auto i : make_range(N))
610  for (const auto j : make_range(N))
611  for (const auto k : make_range(N))
612  for (const auto l : make_range(N))
613  {
614  d2(i, j, k, l) = Real(i == j) * s(k, l) / 3.0 + Real(k == l) * s(i, j) / 3.0;
615  // for (const auto a: make_range(N))
616  // for (const auto b: make_range(N))
617  // d2(i, j, k, l) += 0.5*(PermutationTensor::eps(i, k, a)*PermutationTensor::eps(j, l,
618  // b) + PermutationTensor::eps(i, l, a)*PermutationTensor::eps(j, k, b))*s(a, b);
619  }
620 
621  // I'm not sure which is more readable: the above
622  // PermutationTensor stuff, or the stuff below.
623  // Anyway, they yield the same result, and so i leave
624  // both of them here to enlighten you!
625 
626  d2(0, 0, 1, 1) += s(2, 2);
627  d2(0, 0, 1, 2) -= s(2, 1);
628  d2(0, 0, 2, 1) -= s(1, 2);
629  d2(0, 0, 2, 2) += s(1, 1);
630 
631  d2(0, 1, 0, 1) -= s(2, 2) / 2.0;
632  d2(0, 1, 1, 0) -= s(2, 2) / 2.0;
633  d2(0, 1, 0, 2) += s(1, 2) / 2.0;
634  d2(0, 1, 2, 0) += s(1, 2) / 2.0;
635  d2(0, 1, 1, 2) += s(2, 0) / 2.0;
636  d2(0, 1, 2, 1) += s(2, 0) / 2.0;
637  d2(0, 1, 2, 2) -= s(1, 0);
638 
639  d2(0, 2, 0, 1) += s(2, 1) / 2.0;
640  d2(0, 2, 1, 0) += s(2, 1) / 2.0;
641  d2(0, 2, 0, 2) -= s(1, 1) / 2.0;
642  d2(0, 2, 2, 0) -= s(1, 1) / 2.0;
643  d2(0, 2, 1, 1) -= s(2, 0);
644  d2(0, 2, 1, 2) += s(1, 0) / 2.0;
645  d2(0, 2, 2, 1) += s(1, 0) / 2.0;
646 
647  d2(1, 0, 0, 1) -= s(2, 2) / 2.0;
648  d2(1, 0, 1, 0) -= s(2, 2) / 2.0;
649  d2(1, 0, 0, 2) += s(1, 2) / 2.0;
650  d2(1, 0, 2, 0) += s(1, 2) / 2.0;
651  d2(1, 0, 1, 2) += s(2, 0) / 2.0;
652  d2(1, 0, 2, 1) += s(2, 0) / 2.0;
653  d2(1, 0, 2, 2) -= s(1, 0);
654 
655  d2(1, 1, 0, 0) += s(2, 2);
656  d2(1, 1, 0, 2) -= s(2, 0);
657  d2(1, 1, 2, 0) -= s(2, 0);
658  d2(1, 1, 2, 2) += s(0, 0);
659 
660  d2(1, 2, 0, 0) -= s(2, 1);
661  d2(1, 2, 0, 1) += s(2, 0) / 2.0;
662  d2(1, 2, 1, 0) += s(2, 0) / 2.0;
663  d2(1, 2, 0, 2) += s(0, 1) / 2.0;
664  d2(1, 2, 2, 0) += s(0, 1) / 2.0;
665  d2(1, 2, 1, 2) -= s(0, 0) / 2.0;
666  d2(1, 2, 2, 1) -= s(0, 0) / 2.0;
667 
668  d2(2, 0, 0, 1) += s(2, 1) / 2.0;
669  d2(2, 0, 1, 0) += s(2, 1) / 2.0;
670  d2(2, 0, 0, 2) -= s(1, 1) / 2.0;
671  d2(2, 0, 2, 0) -= s(1, 1) / 2.0;
672  d2(2, 0, 1, 1) -= s(2, 0);
673  d2(2, 0, 1, 2) += s(1, 0) / 2.0;
674  d2(2, 0, 2, 1) += s(1, 0) / 2.0;
675 
676  d2(2, 1, 0, 0) -= s(2, 1);
677  d2(2, 1, 0, 1) += s(2, 0) / 2.0;
678  d2(2, 1, 1, 0) += s(2, 0) / 2.0;
679  d2(2, 1, 0, 2) += s(0, 1) / 2.0;
680  d2(2, 1, 2, 0) += s(0, 1) / 2.0;
681  d2(2, 1, 1, 2) -= s(0, 0) / 2.0;
682  d2(2, 1, 2, 1) -= s(0, 0) / 2.0;
683 
684  d2(2, 2, 0, 0) += s(1, 1);
685  d2(2, 2, 0, 1) -= s(1, 0);
686  d2(2, 2, 1, 0) -= s(1, 0);
687  d2(2, 2, 1, 1) += s(0, 0);
688 
689  return d2;
690 }
691 
692 template <typename T>
695 {
697 
698  d(0, 0) = (*this)(1, 1) * (*this)(2, 2) - (*this)(2, 1) * (*this)(1, 2);
699  d(0, 1) = (*this)(2, 0) * (*this)(1, 2) - (*this)(1, 0) * (*this)(2, 2);
700  d(0, 2) = (*this)(1, 0) * (*this)(2, 1) - (*this)(2, 0) * (*this)(1, 1);
701  d(1, 0) = (*this)(2, 1) * (*this)(0, 2) - (*this)(0, 1) * (*this)(2, 2);
702  d(1, 1) = (*this)(0, 0) * (*this)(2, 2) - (*this)(2, 0) * (*this)(0, 2);
703  d(1, 2) = (*this)(2, 0) * (*this)(0, 1) - (*this)(0, 0) * (*this)(2, 1);
704  d(2, 0) = (*this)(0, 1) * (*this)(1, 2) - (*this)(1, 1) * (*this)(0, 2);
705  d(2, 1) = (*this)(1, 0) * (*this)(0, 2) - (*this)(0, 0) * (*this)(1, 2);
706  d(2, 2) = (*this)(0, 0) * (*this)(1, 1) - (*this)(1, 0) * (*this)(0, 1);
707 
708  return d;
709 }
710 
711 template <typename T>
712 void
713 RankTwoTensorTempl<T>::print(std::ostream & stm) const
714 {
715  const RankTwoTensorTempl<T> & a = *this;
716  for (const auto i : make_range(N))
717  {
718  for (const auto j : make_range(N))
719  stm << std::setw(15) << a(i, j) << ' ';
720  stm << std::endl;
721  }
722 }
723 
724 template <>
725 void RankTwoTensor::printReal(std::ostream & stm) const;
726 
727 template <>
728 void ADRankTwoTensor::printReal(std::ostream & stm) const;
729 
730 template <>
731 void ADRankTwoTensor::printADReal(unsigned int nDual, std::ostream & stm) const;
732 
733 template <typename T>
734 void
736 {
737  for (const auto i : make_range(N))
738  (*this)(i, i) += a;
739 }
740 
741 template <typename T>
742 T
744 {
745  T norm = 0.0;
746  for (const auto i : make_range(N2))
747  {
748  T v = _coords[i];
749  norm += v * v;
750  }
751  return norm == 0.0 ? 0.0 : std::sqrt(norm);
752 }
753 
754 template <typename T>
755 void
757 {
758  if (input.size() == 4)
759  {
760  // initialize with zeros
761  this->zero();
762  (*this)(0, 0) = input[0];
763  (*this)(0, 1) = input[1];
764  (*this)(1, 0) = input[2];
765  (*this)(1, 1) = input[3];
766  }
767  else
768  mooseError("please provide correct number of values for surface RankTwoTensorTempl<T> "
769  "initialization.");
770 }
771 
772 template <typename T>
773 void
774 RankTwoTensorTempl<T>::syev(const char *, std::vector<T> &, std::vector<T> &) const
775 {
776  mooseError("The syev method is only supported for Real valued tensors");
777 }
778 
779 template <>
780 void RankTwoTensor::syev(const char * calculation_type,
781  std::vector<Real> & eigvals,
782  std::vector<Real> & a) const;
783 
784 template <typename T>
785 void
786 RankTwoTensorTempl<T>::symmetricEigenvalues(std::vector<T> & eigvals) const
787 {
789  symmetricEigenvaluesEigenvectors(eigvals, a);
790 }
791 
792 template <>
793 void RankTwoTensor::symmetricEigenvalues(std::vector<Real> & eigvals) const;
794 
795 template <typename T>
796 void
798  RankTwoTensorTempl<T> &) const
799 {
800  mooseError(
801  "symmetricEigenvaluesEigenvectors is only available for ordered tensor component types");
802 }
803 
804 template <>
805 void RankTwoTensor::symmetricEigenvaluesEigenvectors(std::vector<Real> & eigvals,
806  RankTwoTensor & eigvecs) const;
807 
808 template <>
809 void ADRankTwoTensor::symmetricEigenvaluesEigenvectors(std::vector<ADReal> & eigvals,
810  ADRankTwoTensor & eigvecs) const;
811 
812 template <typename T>
813 void
815  std::vector<RankTwoTensorTempl<T>> & deigvals) const
816 {
817  deigvals.resize(N);
818 
819  std::vector<T> a;
820  syev("V", eigvals, a);
821 
822  // now a contains the eigenvetors
823  // extract these and place appropriately in deigvals
824  std::vector<T> eig_vec;
825  eig_vec.resize(N);
826 
827  for (const auto i : make_range(N))
828  {
829  for (const auto j : make_range(N))
830  eig_vec[j] = a[i * N + j];
831  for (const auto j : make_range(N))
832  for (const auto k : make_range(N))
833  deigvals[i](j, k) = eig_vec[j] * eig_vec[k];
834  }
835 
836  // There are discontinuities in the derivative
837  // for equal eigenvalues. The following is
838  // an attempt to make a sensible choice for
839  // the derivative. This agrees with a central-difference
840  // approximation to the derivative.
841  if (eigvals[0] == eigvals[1] && eigvals[0] == eigvals[2])
842  deigvals[0] = deigvals[1] = deigvals[2] = (deigvals[0] + deigvals[1] + deigvals[2]) / 3.0;
843  else if (eigvals[0] == eigvals[1])
844  deigvals[0] = deigvals[1] = (deigvals[0] + deigvals[1]) / 2.0;
845  else if (eigvals[0] == eigvals[2])
846  deigvals[0] = deigvals[2] = (deigvals[0] + deigvals[2]) / 2.0;
847  else if (eigvals[1] == eigvals[2])
848  deigvals[1] = deigvals[2] = (deigvals[1] + deigvals[2]) / 2.0;
849 }
850 
851 template <typename T>
852 void
854 {
855  std::vector<T> eigvec;
856  std::vector<T> eigvals;
857  T ev[N][N];
858 
859  // reset rank four tensor
860  deriv.assign(N, RankFourTensorTempl<T>());
861 
862  // get eigen values and eigen vectors
863  syev("V", eigvals, eigvec);
864 
865  for (const auto i : make_range(N))
866  for (const auto j : make_range(N))
867  ev[i][j] = eigvec[i * N + j];
868 
869  for (unsigned int alpha = 0; alpha < N; ++alpha)
870  for (unsigned int beta = 0; beta < N; ++beta)
871  {
872  if (eigvals[alpha] == eigvals[beta])
873  continue;
874 
875  for (const auto i : make_range(N))
876  for (const auto j : make_range(N))
877  for (const auto k : make_range(N))
878  for (const auto l : make_range(N))
879  {
880  deriv[alpha](i, j, k, l) +=
881  0.5 * (ev[beta][i] * ev[alpha][j] + ev[alpha][i] * ev[beta][j]) *
882  (ev[beta][k] * ev[alpha][l] + ev[beta][l] * ev[alpha][k]) /
883  (eigvals[alpha] - eigvals[beta]);
884  }
885  }
886 }
887 
888 template <typename T>
889 void
891 {
892  mooseError("getRUDecompositionRotation is only supported for Real valued tensors");
893 }
894 
895 template <>
897 
898 template <typename T>
899 void
900 RankTwoTensorTempl<T>::initRandom(unsigned int rand_seed)
901 {
902  MooseRandom::seed(rand_seed);
903 }
904 
905 template <typename T>
908 {
909  RankTwoTensorTempl<T> result;
910  for (const auto i : make_range(N))
911  for (const auto j : make_range(N))
912  result(i, j) = (MooseRandom::rand() + mean) * stddev;
913  return result;
914 }
915 
916 template <typename T>
919 {
920  auto r = [&]() { return (MooseRandom::rand() + mean) * stddev; };
921  return RankTwoTensorTempl<T>(r(), r(), r(), r(), r(), r());
922 }
923 
924 template <typename T>
925 void
927  const libMesh::TypeVector<T> & v2)
928 {
929  RankTwoTensorTempl<T> & a = *this;
930  for (const auto i : make_range(N))
931  for (const auto j : make_range(N))
932  a(i, j) = v1(i) * v2(j);
933 }
934 
935 template <typename T>
938  const libMesh::TypeVector<T> & v2)
939 {
940  RankTwoTensorTempl<T> result;
941  for (const auto i : make_range(N))
942  for (const auto j : make_range(N))
943  result(i, j) = v1(i) * v2(j);
944  return result;
945 }
946 
947 template <typename T>
950 {
952  for (unsigned int i = 0; i < N; ++i)
953  for (unsigned int j = 0; j < N; ++j)
954  result(i, j) = v(i) * v(j);
955  return result;
956 }
957 
958 template <typename T>
959 void
961 {
962  for (const auto i : make_range(N))
963  for (const auto j : make_range(N))
964  tensor(i, j) = (*this)(i, j);
965 }
966 
967 template <typename T>
968 void
970 {
971  for (const auto i : make_range(N))
972  (*this)(r, i) = v(i);
973 }
974 
975 template <typename T>
976 void
978 {
979  for (const auto i : make_range(N))
980  (*this)(i, c) = v(i);
981 }
982 
983 template <typename T>
986 {
987  RankTwoTensorTempl<T> result;
988  for (const auto i : make_range(N))
989  for (const auto j : make_range(N))
990  for (const auto k : make_range(N))
991  for (const auto l : make_range(N))
992  result(k, l) += (*this)(i, j) * b(i, j, k, l);
993  return result;
994 }
995 
996 template <typename T>
997 void
999 {
1000  mooseAssert(N2 == 9, "RankTwoTensorTempl is currently only tested for 3 dimensions.");
1001  for (const auto i : make_range(N2))
1002  _coords[i] = identityCoords[i];
1003 }
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 ...
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
Definition: MooseUtils.h:380
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:302
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
auto raw_value(const Eigen::Map< T > &in)
Definition: EigenADReal.h:73
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:47
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:353
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:314
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