https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
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
41namespace Eigen
42{
43namespace internal
44{
45template <>
46struct 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
53template <typename T>
55
56namespace MathUtils
57{
58template <>
60template <>
62}
63
64template <typename T>
67{
68 return MooseEnum("autodetect=0 isotropic1=1 diagonal3=3 symmetric6=6 general=9", "autodetect");
69}
70
71template <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
80template <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
99template <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
118template <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
135template <typename T>
139 const libMesh::TypeVector<T> & row2)
140{
142 row0(0), row1(0), row2(0), row0(1), row1(1), row2(1), row0(2), row1(2), row2(2));
144
145template <typename T>
148 const libMesh::TypeVector<T> & col1,
149 const libMesh::TypeVector<T> & col2)
150{
152 col0(0), col0(1), col0(2), col1(0), col1(1), col1(2), col2(0), col2(1), col2(2));
153}
154
155template <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
167template <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
189template <typename T>
190void
191RankTwoTensorTempl<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;
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
239template <typename T>
240void
242{
243 switch (scalar_variable.size())
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
272template <typename T>
274RankTwoTensorTempl<T>::column(const unsigned int c) const
275{
276 return libMesh::VectorValue<T>((*this)(0, c), (*this)(1, c), (*this)(2, c));
277}
278
279template <typename T>
285
286template <typename T>
292
293template <typename T>
299
300template <typename T>
303{
304 return *this * *this;
305}
306
307template <typename T>
310{
311 RankTwoTensorTempl<T> result(*this);
312 result.rotate(R);
313 return result;
314}
315
316template <typename T>
317void
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
346template <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
366template <typename T>
372
373template <typename T>
380
381template <typename T>
386 return *this;
387}
388
389template <typename T>
395
396template <typename T>
399{
401 return *this;
402}
403
404template <typename T>
407{
409 return *this;
410}
411
412template <typename T>
415{
416 *this = *this * a;
417 return *this;
418}
419
420template <typename T>
421bool
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}
432template <typename T>
433bool
435{
436 auto test = MetaPhysicL::raw_value(*this - transpose());
437 return MooseUtils::absoluteFuzzyEqual(test.norm_sq(), 0);
438}
439
440template <typename T>
443{
444 if (a.n() != N || a.m() != N)
445 mooseError("Dimensions of ColumnMajorMatrixTempl<T> are incompatible with RankTwoTensorTempl");
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
455template <typename T>
456T
458{
459 // deprecate this!
461}
462
463template <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
478template <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
492template <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
502template <typename T>
503T
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
511template <typename T>
512T
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
530template <typename T>
536
537template <typename T>
540{
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
551template <typename T>
552T
554{
555 // deprecate this!
556 return this->tr();
557}
558
559template <typename T>
562{
563 return RankTwoTensorTempl<T>(1, 0, 0, 0, 1, 0, 0, 0, 1);
564}
565
566template <typename T>
572
573template <typename T>
574T
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
583template <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
603template <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))
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
693template <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
712template <typename T>
713void
714RankTwoTensorTempl<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
725template <>
726void RankTwoTensor::printReal(std::ostream & stm) const;
727
728template <>
729void ADRankTwoTensor::printReal(std::ostream & stm) const;
730
731template <>
732void ADRankTwoTensor::printADReal(unsigned int nDual, std::ostream & stm) const;
733
734template <typename T>
735void
737{
738 for (const auto i : make_range(N))
739 (*this)(i, i) += a;
740}
741
742template <typename T>
743T
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
756template <typename T>
757void
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
774template <typename T>
775void
776RankTwoTensorTempl<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
781template <>
782void RankTwoTensor::syev(const char * calculation_type,
783 std::vector<Real> & eigvals,
784 std::vector<Real> & a) const;
785
786template <typename T>
787void
788RankTwoTensorTempl<T>::symmetricEigenvalues(std::vector<T> & eigvals) const
789{
791 symmetricEigenvaluesEigenvectors(eigvals, a);
792}
793
794template <>
795void RankTwoTensor::symmetricEigenvalues(std::vector<Real> & eigvals) const;
796
797template <typename T>
798void
800 RankTwoTensorTempl<T> &) const
801{
803 "symmetricEigenvaluesEigenvectors is only available for ordered tensor component types");
804}
805
806template <>
807void RankTwoTensor::symmetricEigenvaluesEigenvectors(std::vector<Real> & eigvals,
808 RankTwoTensor & eigvecs) const;
809
810template <>
811void ADRankTwoTensor::symmetricEigenvaluesEigenvectors(std::vector<ADReal> & eigvals,
812 ADRankTwoTensor & eigvecs) const;
813
814template <typename T>
815void
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
853template <typename T>
854void
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);
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]);
887 }
888}
889
890template <typename T>
891void
893{
894 mooseError("getRUDecompositionRotation is only supported for Real valued tensors");
895}
896
897template <>
899
900template <typename T>
901void
903{
904 MooseRandom::seed(rand_seed);
905}
906
907template <typename T>
910{
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
918template <typename T>
921{
922 auto r = [&]() { return (MooseRandom::rand() + mean) * stddev; };
923 return RankTwoTensorTempl<T>(r(), r(), r(), r(), r(), r());
924}
925
926template <typename T>
927void
929 const libMesh::TypeVector<T> & v2)
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
937template <typename T>
940 const libMesh::TypeVector<T> & v2)
941{
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
949template <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
960template <typename T>
961void
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
969template <typename T>
970void
972{
973 for (const auto i : make_range(N))
974 (*this)(r, i) = v(i);
975}
976
977template <typename T>
978void
980{
981 for (const auto i : make_range(N))
982 (*this)(i, c) = v(i);
983}
984
985template <typename T>
988{
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
998template <typename T>
999void
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}
DualNumber< Real, DNDerivativeType, true > ADReal
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition MooseError.h:363
for(PetscInt i=0;i< nvars;++i)
void ErrorVector unsigned int
This class defines a Tensor that can change its shape.
unsigned int n() const
Returns the number of rows.
T * rawData()
Returns a reference to the raw data pointer.
unsigned int m() const
Returns the number of columns.
unsigned int size() const
The number of elements that can currently be stored in the array.
Definition MooseArray.h:259
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
static Real rand()
This method returns the next random number (Real format) from the generator.
Definition MooseRandom.h:50
static void seed(unsigned int seed)
The method seeds the random number generator.
Definition MooseRandom.h:44
RankFourTensorTempl is designed to handle any N-dimensional fourth order tensor, C.
RankThreeTensor is designed to handle any N-dimensional third order tensor, r.
RankTwoTensorTempl is designed to handle the Stress or Strain Tensor for a fully anisotropic material...
void setToIdentity()
Set the tensor to identity.
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.
static void initRandom(unsigned int)
Initialize the random seed based on an unsigned integer.
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.
void fillFromScalarVariable(const VariableValue &scalar_variable)
The smart mutator that determines how to fill the second order tensor based on the order of the scala...
T trace() const
A wrapper for tr()
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 > selfOuterProduct(const libMesh::TypeVector< T > &)
Initialize a second order tensor as the outer product of a vector with itself, i.e.
RankTwoTensorTempl< T > operator-() const
Return the negation of this tensor.
RankThreeTensorTempl< T > mixedProductJkI(const libMesh::VectorValue< T > &b) const
Return the tensor product of this second order tensor with a vector .
void addIa(const T &a)
Add identity times a to _coords.
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 .
static MooseEnum fillMethodEnum()
Get the available FillMethod options.
RankTwoTensorTempl< T > ddet() const
Denote the _coords[i][j] by A_ij, then this returns d(det)/dA_ij.
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.
T doubleContraction(const RankTwoTensorTempl< T > &a) const
Return the double contraction with another second order tensor .
void fillRow(unsigned int r, const libMesh::TypeVector< T > &v)
Assign values to a specific row of the second order tensor.
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...
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....
RankTwoTensorTempl< T > & operator=(const RankTwoTensorTempl< T > &a)=default
Assignment operator.
RankTwoTensorTempl< T > inverse() const
Return the inverse of this second order tensor.
bool isSymmetric() const
Test for symmetry.
void getRUDecompositionRotation(RankTwoTensorTempl< T > &rot) const
Uses the petscblaslapack.h LAPACKsyev_ routine to perform RU decomposition and obtain the rotation te...
void printReal(std::ostream &stm=Moose::out) const
Print the Real part of the RankTwoTensorTempl<ADReal>
void rotate(const RankTwoTensorTempl< T > &R)
Rotate the tensor in-place given a rotation tensor .
RankTwoTensorTempl< T > transpose() const
Return the tensor transposed.
void print(std::ostream &stm=Moose::out) const
Print the rank two tensor.
T generalSecondInvariant() const
Return the principal second invariant of this second order tensor.
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 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....
T secondInvariant() const
Return the main second invariant of this second order tensor.
InitMethod
The initialization method.
RankTwoTensorTempl< T > dthirdInvariant() const
Denote the _coords[i][j] by A_ij, then this returns d(thirdInvariant()/dA_ij.
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...
static RankTwoTensorTempl< T > transposeTimes(const RankTwoTensorTempl< T > &)
Initialize a second order tensor with expression .
RankTwoTensorTempl< T > & operator*=(const T &a)
Multiply this tensor by a scalar (component-wise)
libMesh::VectorValue< T > column(const unsigned int i) const
Get the i-th column of the second order tensor.
RankTwoTensorTempl< T > & operator/=(const T &a)
Divide this tensor by a scalar (component-wise)
FillMethod
To fill up the 9 entries in the 2nd-order tensor, fillFromInputVector is called with one of the follo...
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
bool operator==(const RankTwoTensorTempl< T > &a) const
Defines logical equality with another RankTwoTensorTempl<T>
static RankTwoTensorTempl< T > genRandomTensor(T stddev, T mean)
Generate a random second order tensor with all 9 components treated as independent random variables f...
RankTwoTensorTempl< T > & operator-=(const RankTwoTensorTempl< T > &a)
Subtract another second order tensor from this one.
void fillRealTensor(libMesh::TensorValue< T > &)
Fill a libMesh::TensorValue<T> from this second order tensor.
RankFourTensorTempl< T > d2thirdInvariant() const
Denote the _coords[i][j] by A_ij, then this returns d^2(thirdInvariant)/dA_ij/dA_kl.
void symmetricEigenvalues(std::vector< T > &eigvals) const
computes eigenvalues, assuming tens is symmetric, and places them in ascending order in eigvals
RankTwoTensorTempl< T > dsecondInvariant() const
Return the derivative of the main second invariant w.r.t.
void fillColumn(unsigned int c, const libMesh::TypeVector< T > &v)
Assign values to a specific column of the second order tensor.
RankTwoTensorTempl< T > rotateXyPlane(T a)
Rotate the tensor about the z-axis.
T L2norm() const
Sqrt(_coords[i][j]*_coords[i][j])
RankTwoTensorTempl< T > dtrace() const
Return the derivative of the trace w.r.t.
RankTwoTensorTempl< T > deviatoric() const
Return the deviatoric part of this tensor .
RankTwoTensorTempl< T > & operator+=(const RankTwoTensorTempl< T > &a)
Add another second order tensor to this one.
RankFourTensorTempl< T > d2secondInvariant() const
Return the second derivative of the main second invariant w.r.t.
void symmetricEigenvaluesEigenvectors(std::vector< T > &eigvals, RankTwoTensorTempl< T > &eigvecs) const
computes eigenvalues and eigenvectors, assuming tens is symmetric, and places them in ascending order...
RankTwoTensorTempl< T > initialContraction(const RankFourTensorTempl< T > &b) const
returns this_ij * b_ijkl
static RankTwoTensorTempl initializeSymmetric(const libMesh::TypeVector< T > &v0, const libMesh::TypeVector< T > &v1, const libMesh::TypeVector< T > &v2)
Named constructor for initializing symmetrically.
RankTwoTensorTempl< T > rotated(const RankTwoTensorTempl< T > &R) const
Return the rotated tensor given a rotation tensor .
static RankTwoTensorTempl< T > timesTranspose(const RankTwoTensorTempl< T > &)
Initialize a second order tensor with expression .
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.
RankTwoTensorTempl()
Empty constructor; fills to zero.
RankTwoTensorTempl< T > square() const
Return .
T _coords[LIBMESH_DIM *LIBMESH_DIM]
Definition JsonIO.h:69
void mooseSetToZero< ADRankTwoTensor >(ADRankTwoTensor &v)
Helper function template specialization to set an object to zero.
void mooseSetToZero< RankTwoTensor >(RankTwoTensor &v)
Helper function template specialization to set an object to zero.
auto raw_value(const Eigen::Map< T > &in)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real