1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2010 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
27 #include "mathematicalConstants.H"
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 const char* const tensor::typeName = "tensor";
40 const char* tensor::componentNames[] =
48 const tensor tensor::zero
56 const tensor tensor::one
64 const tensor tensor::max
66 VGREAT, VGREAT, VGREAT,
67 VGREAT, VGREAT, VGREAT,
68 VGREAT, VGREAT, VGREAT
72 const tensor tensor::min
74 -VGREAT, -VGREAT, -VGREAT,
75 -VGREAT, -VGREAT, -VGREAT,
76 -VGREAT, -VGREAT, -VGREAT
80 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
82 // Return eigenvalues in ascending order of absolute values
83 vector eigenValues(const tensor& t)
92 mag(t.xy()) + mag(t.xz()) + mag(t.yx())
93 + mag(t.yz()) + mag(t.zx()) + mag(t.zy())
105 scalar a = -t.xx() - t.yy() - t.zz();
107 scalar b = t.xx()*t.yy() + t.xx()*t.zz() + t.yy()*t.zz()
108 - t.xy()*t.yx() - t.xz()*t.zx() - t.yz()*t.zy();
110 scalar c = - t.xx()*t.yy()*t.zz() - t.xy()*t.yz()*t.zx()
111 - t.xz()*t.yx()*t.zy() + t.xz()*t.yy()*t.zx()
112 + t.xy()*t.yx()*t.zz() + t.xx()*t.yz()*t.zy();
114 // If there is a zero root
115 if (mag(c) < 1.0e-100)
117 scalar disc = sqr(a) - 4*b;
121 scalar q = -0.5*sqrt(max(0.0, disc));
129 FatalErrorIn("eigenValues(const tensor&)")
130 << "zero and complex eigenvalues in tensor: " << t
131 << abort(FatalError);
136 scalar Q = (a*a - 3*b)/9;
137 scalar R = (2*a*a*a - 9*a*b + 27*c)/54;
142 // Three different real roots
145 scalar sqrtQ = sqrt(Q);
146 scalar theta = acos(R/(Q*sqrtQ));
148 scalar m2SqrtQ = -2*sqrtQ;
151 i = m2SqrtQ*cos(theta/3) - aBy3;
154 *cos((theta + constant::mathematical::twoPi)/3)
158 *cos((theta - constant::mathematical::twoPi)/3)
163 scalar A = cbrt(R + sqrt(R2 - Q3));
165 // Three equal real roots
169 return vector(root, root, root);
174 WarningIn("eigenValues(const tensor&)")
175 << "complex eigenvalues detected for tensor: " << t
185 // Sort the eigenvalues into ascending order
186 if (mag(i) > mag(ii))
191 if (mag(ii) > mag(iii))
196 if (mag(i) > mag(ii))
201 return vector(i, ii, iii);
205 vector eigenVector(const tensor& t, const scalar lambda)
207 if (mag(lambda) < SMALL)
212 // Construct the matrix for the eigenvector problem
213 tensor A(t - lambda*I);
215 // Calculate the sub-determinants of the 3 components
216 scalar sd0 = A.yy()*A.zz() - A.yz()*A.zy();
217 scalar sd1 = A.xx()*A.zz() - A.xz()*A.zx();
218 scalar sd2 = A.xx()*A.yy() - A.xy()*A.yx();
220 scalar magSd0 = mag(sd0);
221 scalar magSd1 = mag(sd1);
222 scalar magSd2 = mag(sd2);
224 // Evaluate the eigenvector using the largest sub-determinant
225 if (magSd0 > magSd1 && magSd0 > magSd2 && magSd0 > SMALL)
230 (A.yz()*A.zx() - A.zz()*A.yx())/sd0,
231 (A.zy()*A.yx() - A.yy()*A.zx())/sd0
237 else if (magSd1 > magSd2 && magSd1 > SMALL)
241 (A.xz()*A.zy() - A.zz()*A.xy())/sd1,
243 (A.zx()*A.xy() - A.xx()*A.zy())/sd1
249 else if (magSd2 > SMALL)
253 (A.xy()*A.yz() - A.yy()*A.xz())/sd2,
254 (A.yx()*A.xz() - A.xx()*A.yz())/sd2,
268 tensor eigenVectors(const tensor& t)
270 vector evals(eigenValues(t));
274 eigenVector(t, evals.x()),
275 eigenVector(t, evals.y()),
276 eigenVector(t, evals.z())
283 // Return eigenvalues in ascending order of absolute values
284 vector eigenValues(const symmTensor& t)
293 mag(t.xy()) + mag(t.xz()) + mag(t.xy())
294 + mag(t.yz()) + mag(t.xz()) + mag(t.yz())
306 scalar a = -t.xx() - t.yy() - t.zz();
308 scalar b = t.xx()*t.yy() + t.xx()*t.zz() + t.yy()*t.zz()
309 - t.xy()*t.xy() - t.xz()*t.xz() - t.yz()*t.yz();
311 scalar c = - t.xx()*t.yy()*t.zz() - t.xy()*t.yz()*t.xz()
312 - t.xz()*t.xy()*t.yz() + t.xz()*t.yy()*t.xz()
313 + t.xy()*t.xy()*t.zz() + t.xx()*t.yz()*t.yz();
315 // If there is a zero root
316 if (mag(c) < 1.0e-100)
318 scalar disc = sqr(a) - 4*b;
322 scalar q = -0.5*sqrt(max(0.0, disc));
330 FatalErrorIn("eigenValues(const tensor&)")
331 << "zero and complex eigenvalues in tensor: " << t
332 << abort(FatalError);
337 scalar Q = (a*a - 3*b)/9;
338 scalar R = (2*a*a*a - 9*a*b + 27*c)/54;
343 // Three different real roots
346 scalar sqrtQ = sqrt(Q);
347 scalar theta = acos(R/(Q*sqrtQ));
349 scalar m2SqrtQ = -2*sqrtQ;
352 i = m2SqrtQ*cos(theta/3) - aBy3;
355 *cos((theta + constant::mathematical::twoPi)/3)
359 *cos((theta - constant::mathematical::twoPi)/3)
364 scalar A = cbrt(R + sqrt(R2 - Q3));
366 // Three equal real roots
370 return vector(root, root, root);
375 WarningIn("eigenValues(const symmTensor&)")
376 << "complex eigenvalues detected for symmTensor: " << t
386 // Sort the eigenvalues into ascending order
387 if (mag(i) > mag(ii))
392 if (mag(ii) > mag(iii))
397 if (mag(i) > mag(ii))
402 return vector(i, ii, iii);
406 vector eigenVector(const symmTensor& t, const scalar lambda)
408 if (mag(lambda) < SMALL)
413 // Construct the matrix for the eigenvector problem
414 symmTensor A(t - lambda*I);
416 // Calculate the sub-determinants of the 3 components
417 scalar sd0 = A.yy()*A.zz() - A.yz()*A.yz();
418 scalar sd1 = A.xx()*A.zz() - A.xz()*A.xz();
419 scalar sd2 = A.xx()*A.yy() - A.xy()*A.xy();
421 scalar magSd0 = mag(sd0);
422 scalar magSd1 = mag(sd1);
423 scalar magSd2 = mag(sd2);
425 // Evaluate the eigenvector using the largest sub-determinant
426 if (magSd0 > magSd1 && magSd0 > magSd2 && magSd0 > SMALL)
431 (A.yz()*A.xz() - A.zz()*A.xy())/sd0,
432 (A.yz()*A.xy() - A.yy()*A.xz())/sd0
438 else if (magSd1 > magSd2 && magSd1 > SMALL)
442 (A.xz()*A.yz() - A.zz()*A.xy())/sd1,
444 (A.xz()*A.xy() - A.xx()*A.yz())/sd1
450 else if (magSd2 > SMALL)
454 (A.xy()*A.yz() - A.yy()*A.xz())/sd2,
455 (A.xy()*A.xz() - A.xx()*A.yz())/sd2,
469 tensor eigenVectors(const symmTensor& t)
471 vector evals(eigenValues(t));
475 eigenVector(t, evals.x()),
476 eigenVector(t, evals.y()),
477 eigenVector(t, evals.z())
484 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
486 } // End namespace Foam
488 // ************************************************************************* //