tensor.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "tensor.H"
30 #include "cubicEqn.H"
31 #include "mathematicalConstants.H"
32 
33 using namespace Foam::constant::mathematical;
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 template<>
38 const char* const Foam::tensor::vsType::typeName = "tensor";
39 
40 template<>
41 const char* const Foam::tensor::vsType::componentNames[] =
42 {
43  "xx", "xy", "xz",
44  "yx", "yy", "yz",
45  "zx", "zy", "zz"
46 };
47 
48 template<>
49 const Foam::tensor Foam::tensor::vsType::zero(tensor::uniform(0));
50 
51 template<>
52 const Foam::tensor Foam::tensor::vsType::one(tensor::uniform(1));
53 
54 template<>
55 const Foam::tensor Foam::tensor::vsType::max(tensor::uniform(VGREAT));
56 
57 template<>
58 const Foam::tensor Foam::tensor::vsType::min(tensor::uniform(-VGREAT));
59 
60 template<>
61 const Foam::tensor Foam::tensor::vsType::rootMax(tensor::uniform(ROOTVGREAT));
62 
63 template<>
64 const Foam::tensor Foam::tensor::vsType::rootMin(tensor::uniform(-ROOTVGREAT));
65 
66 template<>
68 (
69  1, 0, 0,
70  0, 1, 0,
71  0, 0, 1
72 );
73 
74 
75 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
76 
78 {
79  // Return diagonal if T is effectively diagonal tensor
80  if
81  (
82  (
83  sqr(T.xy()) + sqr(T.xz()) + sqr(T.yz())
84  + sqr(T.yx()) + sqr(T.zx()) + sqr(T.zy())
85  ) < ROOTSMALL
86  )
87  {
88  return Vector<complex>
89  (
90  complex(T.xx()), complex(T.yy()), complex(T.zz())
91  );
92  }
93 
94  // Coefficients of the characteristic cubic polynomial (a = 1)
95  const scalar b = - T.xx() - T.yy() - T.zz();
96  const scalar c =
97  T.xx()*T.yy() + T.xx()*T.zz() + T.yy()*T.zz()
98  - T.xy()*T.yx() - T.yz()*T.zy() - T.zx()*T.xz();
99  const scalar d =
100  - T.xx()*T.yy()*T.zz()
101  - T.xy()*T.yz()*T.zx() - T.xz()*T.zy()*T.yx()
102  + T.xx()*T.yz()*T.zy() + T.yy()*T.zx()*T.xz() + T.zz()*T.xy()*T.yx();
103 
104  // Determine the roots of the characteristic cubic polynomial
105  const Roots<3> roots(cubicEqn(1, b, c, d).roots());
106  // Check the root types
107  bool isComplex = false;
108  forAll(roots, i)
109  {
110  switch (roots.type(i))
111  {
112  case roots::complex:
113  isComplex = true;
114  break;
115  case roots::posInf:
116  case roots::negInf:
117  case roots::nan:
119  << "Eigenvalue computation fails for tensor: " << T
120  << "due to the not-a-number root = " << roots[i]
121  << endl;
122  case roots::real:
123  break;
124  }
125  }
126 
127  if (isComplex)
128  {
129  return
131  (
132  complex(roots[0], 0),
133  complex(roots[1], roots[2]),
134  complex(roots[1], -roots[2])
135  );
136  }
137 
138  return
140  (
141  complex(roots[0], 0),
142  complex(roots[1], 0),
143  complex(roots[2], 0)
144  );
145 }
146 
147 
149 (
150  const tensor& T,
151  const complex& eVal,
152  const Vector<complex>& standardBasis1,
153  const Vector<complex>& standardBasis2
154 )
155 {
156  // Construct the characteristic equation system for this eigenvalue
158  forAll(A, i)
159  {
160  A[i] = complex(T[i], 0);
161  }
162  A.xx() -= eVal;
163  A.yy() -= eVal;
164  A.zz() -= eVal;
165 
166  // Determinants of the 2x2 sub-matrices used to find the eigenvectors
167  // Sub-determinants for a unique eigenvenvalue
168  complex sd0 = A.yy()*A.zz() - A.yz()*A.zy();
169  complex sd1 = A.zz()*A.xx() - A.zx()*A.xz();
170  complex sd2 = A.xx()*A.yy() - A.xy()*A.yx();
171  scalar magSd0 = mag(sd0);
172  scalar magSd1 = mag(sd1);
173  scalar magSd2 = mag(sd2);
174 
175  // Evaluate the eigenvector using the largest sub-determinant
176  if (magSd0 >= magSd1 && magSd0 >= magSd2 && magSd0 > SMALL)
177  {
178  const Vector<complex> eVec
179  (
180  complex(1, 0),
181  (A.yz()*A.zx() - A.zz()*A.yx())/sd0,
182  (A.zy()*A.yx() - A.yy()*A.zx())/sd0
183  );
184 
185  #ifdef FULLDEBUG
186  if (mag(eVec) < SMALL)
187  {
189  << "Eigenvector magnitude should be non-zero:"
190  << "mag(eigenvector) = " << mag(eVec)
191  << abort(FatalError);
192  }
193  #endif
194 
195  return eVec/mag(eVec);
196  }
197  else if (magSd1 >= magSd2 && magSd1 > SMALL)
198  {
199  const Vector<complex> eVec
200  (
201  (A.xz()*A.zy() - A.zz()*A.xy())/sd1,
202  complex(1, 0),
203  (A.zx()*A.xy() - A.xx()*A.zy())/sd1
204  );
205 
206  #ifdef FULLDEBUG
207  if (mag(eVec) < SMALL)
208  {
210  << "Eigenvector magnitude should be non-zero:"
211  << "mag(eigenvector) = " << mag(eVec)
212  << abort(FatalError);
213  }
214  #endif
215 
216  return eVec/mag(eVec);
217  }
218  else if (magSd2 > SMALL)
219  {
220  const Vector<complex> eVec
221  (
222  (A.xy()*A.yz() - A.yy()*A.xz())/sd2,
223  (A.yx()*A.xz() - A.xx()*A.yz())/sd2,
224  complex(1, 0)
225  );
226 
227  #ifdef FULLDEBUG
228  if (mag(eVec) < SMALL)
229  {
231  << "Eigenvector magnitude should be non-zero:"
232  << "mag(eigenvector) = " << mag(eVec)
233  << abort(FatalError);
234  }
235  #endif
236 
237  return eVec/mag(eVec);
238  }
239 
240  // Sub-determinants for a repeated eigenvalue
241  sd0 = A.yy()*standardBasis1.z() - A.yz()*standardBasis1.y();
242  sd1 = A.zz()*standardBasis1.x() - A.zx()*standardBasis1.z();
243  sd2 = A.xx()*standardBasis1.y() - A.xy()*standardBasis1.x();
244  magSd0 = mag(sd0);
245  magSd1 = mag(sd1);
246  magSd2 = mag(sd2);
247 
248  // Evaluate the eigenvector using the largest sub-determinant
249  if (magSd0 >= magSd1 && magSd0 >= magSd2 && magSd0 > SMALL)
250  {
251  const Vector<complex> eVec
252  (
253  complex(1, 0),
254  (A.yz()*standardBasis1.x() - standardBasis1.z()*A.yx())/sd0,
255  (standardBasis1.y()*A.yx() - A.yy()*standardBasis1.x())/sd0
256  );
257 
258  #ifdef FULLDEBUG
259  if (mag(eVec) < SMALL)
260  {
262  << "Eigenvector magnitude should be non-zero:"
263  << "mag(eigenvector) = " << mag(eVec)
264  << abort(FatalError);
265  }
266  #endif
267 
268  return eVec/mag(eVec);
269  }
270  else if (magSd1 >= magSd2 && magSd1 > SMALL)
271  {
272  const Vector<complex> eVec
273  (
274  (standardBasis1.z()*A.zy() - A.zz()*standardBasis1.y())/sd1,
275  complex(1, 0),
276  (A.zx()*standardBasis1.y() - standardBasis1.x()*A.zy())/sd1
277  );
278 
279  #ifdef FULLDEBUG
280  if (mag(eVec) < SMALL)
281  {
283  << "Eigenvector magnitude should be non-zero:"
284  << "mag(eigenvector) = " << mag(eVec)
285  << abort(FatalError);
286  }
287  #endif
288 
289  return eVec/mag(eVec);
290  }
291  else if (magSd2 > SMALL)
292  {
293  const Vector<complex> eVec
294  (
295  (A.xy()*standardBasis1.z() - standardBasis1.y()*A.xz())/sd2,
296  (standardBasis1.x()*A.xz() - A.xx()*standardBasis1.z())/sd2,
297  complex(1, 0)
298  );
299 
300  #ifdef FULLDEBUG
301  if (mag(eVec) < SMALL)
302  {
304  << "Eigenvector magnitude should be non-zero:"
305  << "mag(eigenvector) = " << mag(eVec)
306  << abort(FatalError);
307  }
308  #endif
309 
310  return eVec/mag(eVec);
311  }
312 
313  // Triple eigenvalue
314  return standardBasis1^standardBasis2;
315 }
316 
317 
319 (
320  const tensor& T,
321  const Vector<complex>& eVals
322 )
323 {
324  Vector<complex> Ux(complex(1, 0), Zero, Zero);
325  Vector<complex> Uy(Zero, complex(1, 0), Zero);
326  Vector<complex> Uz(Zero, Zero, complex(1, 0));
327 
328  Ux = eigenVector(T, eVals.x(), Uy, Uz);
329  Uy = eigenVector(T, eVals.y(), Uz, Ux);
330  Uz = eigenVector(T, eVals.z(), Ux, Uy);
331 
332  return Tensor<complex>(Ux, Uy, Uz);
333 }
334 
335 
337 {
338  const Vector<complex> eVals(eigenValues(T));
339 
340  return eigenVectors(T, eVals);
341 }
342 
343 
344 // ************************************************************************* //
Foam::Roots::type
void type(const direction i, const roots::type t)
Set the type of the i-th root.
Definition: RootsI.H:122
Foam::Tensor
A templated (3 x 3) tensor of objects of <T> derived from MatrixSpace.
Definition: complexI.H:275
Foam::Vector::x
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:73
mathematicalConstants.H
Foam::roots::complex
Definition: Roots.H:57
cubicEqn.H
Foam::roots::posInf
Definition: Roots.H:58
Foam::roots::nan
Definition: Roots.H:60
Foam::Tensor::I
static const Tensor I
Definition: Tensor.H:85
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::eigenVector
vector eigenVector(const symmTensor &T, const scalar eVal, const vector &standardBasis1, const vector &standardBasis2)
Definition: symmTensor.C:152
Foam::eigenValues
dimensionedVector eigenValues(const dimensionedSymmTensor &dt)
Definition: dimensionedTensor.C:149
Foam::eigenVectors
dimensionedTensor eigenVectors(const dimensionedSymmTensor &dt)
Definition: dimensionedTensor.C:160
A
static const Foam::dimensionedScalar A("", Foam::dimPressure, 611.21)
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::Vector::z
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:85
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
tensor.H
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::roots::negInf
Definition: Roots.H:59
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:58
Foam::roots::real
Definition: Roots.H:56
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::FatalError
error FatalError
Foam::complex
A complex number, similar to the C++ complex type.
Definition: complex.H:82
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::Vector::y
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:79
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::constant::mathematical
Mathematical constants.
Foam::Vector
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:62
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::cubicEqn
Container to encapsulate various operations for cubic equation of the forms with real coefficients:
Definition: cubicEqn.H:112
Foam::Roots
Templated storage for the roots of polynomial equations, plus flags to indicate the nature of the roo...
Definition: Roots.H:70
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328