1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
28 #include "mathematicalConstants.H"
30 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 const char* const tensor::typeName = "tensor";
41 const char* tensor::componentNames[] =
49 const tensor tensor::zero
57 const tensor tensor::one
65 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
67 // Return eigenvalues in ascending order of absolute values
68 vector eigenValues(const tensor& t)
77 mag(t.xy()) + mag(t.xz()) + mag(t.yx())
78 + mag(t.yz()) + mag(t.zx()) + mag(t.zy())
90 scalar a = -t.xx() - t.yy() - t.zz();
92 scalar b = t.xx()*t.yy() + t.xx()*t.zz() + t.yy()*t.zz()
93 - t.xy()*t.yx() - t.xz()*t.zx() - t.yz()*t.zy();
95 scalar c = - t.xx()*t.yy()*t.zz() - t.xy()*t.yz()*t.zx()
96 - t.xz()*t.yx()*t.zy() + t.xz()*t.yy()*t.zx()
97 + t.xy()*t.yx()*t.zz() + t.xx()*t.yz()*t.zy();
99 // If there is a zero root
100 if (mag(c) < 1.0e-100)
102 scalar disc = sqr(a) - 4*b;
106 scalar q = -0.5*sqrt(max(0.0, disc));
114 FatalErrorIn("eigenValues(const tensor&)")
115 << "zero and complex eigenvalues in tensor: " << t
116 << abort(FatalError);
121 scalar Q = (a*a - 3*b)/9;
122 scalar R = (2*a*a*a - 9*a*b + 27*c)/54;
127 // Three different real roots
130 scalar sqrtQ = sqrt(Q);
131 scalar theta = acos(R/(Q*sqrtQ));
133 scalar m2SqrtQ = -2*sqrtQ;
136 i = m2SqrtQ*cos(theta/3) - aBy3;
137 ii = m2SqrtQ*cos((theta + mathematicalConstant::twoPi)/3)
139 iii = m2SqrtQ*cos((theta - mathematicalConstant::twoPi)/3)
144 scalar A = cbrt(R + sqrt(R2 - Q3));
146 // Three equal real roots
150 return vector(root, root, root);
155 WarningIn("eigenValues(const tensor&)")
156 << "complex eigenvalues detected for tensor: " << t
166 // Sort the eigenvalues into ascending order
167 if (mag(i) > mag(ii))
172 if (mag(ii) > mag(iii))
177 if (mag(i) > mag(ii))
182 return vector(i, ii, iii);
186 vector eigenVector(const tensor& t, const scalar lambda)
188 if (mag(lambda) < SMALL)
193 // Construct the matrix for the eigenvector problem
194 tensor A(t - lambda*I);
196 // Calculate the sub-determinants of the 3 components
197 scalar sd0 = A.yy()*A.zz() - A.yz()*A.zy();
198 scalar sd1 = A.xx()*A.zz() - A.xz()*A.zx();
199 scalar sd2 = A.xx()*A.yy() - A.xy()*A.yx();
201 scalar magSd0 = mag(sd0);
202 scalar magSd1 = mag(sd1);
203 scalar magSd2 = mag(sd2);
205 // Evaluate the eigenvector using the largest sub-determinant
206 if (magSd0 > magSd1 && magSd0 > magSd2 && magSd0 > SMALL)
211 (A.yz()*A.zx() - A.zz()*A.yx())/sd0,
212 (A.zy()*A.yx() - A.yy()*A.zx())/sd0
218 else if (magSd1 > magSd2 && magSd1 > SMALL)
222 (A.xz()*A.zy() - A.zz()*A.xy())/sd1,
224 (A.zx()*A.xy() - A.xx()*A.zy())/sd1
230 else if (magSd2 > SMALL)
234 (A.xy()*A.yz() - A.yy()*A.xz())/sd2,
235 (A.yx()*A.xz() - A.xx()*A.yz())/sd2,
249 tensor eigenVectors(const tensor& t)
251 vector evals(eigenValues(t));
254 evs.x() = eigenVector(t, evals.x());
255 evs.y() = eigenVector(t, evals.y());
256 evs.z() = eigenVector(t, evals.z());
262 // Return eigenvalues in ascending order of absolute values
263 vector eigenValues(const symmTensor& t)
272 mag(t.xy()) + mag(t.xz()) + mag(t.xy())
273 + mag(t.yz()) + mag(t.xz()) + mag(t.yz())
285 scalar a = -t.xx() - t.yy() - t.zz();
287 scalar b = t.xx()*t.yy() + t.xx()*t.zz() + t.yy()*t.zz()
288 - t.xy()*t.xy() - t.xz()*t.xz() - t.yz()*t.yz();
290 scalar c = - t.xx()*t.yy()*t.zz() - t.xy()*t.yz()*t.xz()
291 - t.xz()*t.xy()*t.yz() + t.xz()*t.yy()*t.xz()
292 + t.xy()*t.xy()*t.zz() + t.xx()*t.yz()*t.yz();
294 // If there is a zero root
295 if (mag(c) < 1.0e-100)
297 scalar disc = sqr(a) - 4*b;
301 scalar q = -0.5*sqrt(max(0.0, disc));
309 FatalErrorIn("eigenValues(const tensor&)")
310 << "zero and complex eigenvalues in tensor: " << t
311 << abort(FatalError);
316 scalar Q = (a*a - 3*b)/9;
317 scalar R = (2*a*a*a - 9*a*b + 27*c)/54;
322 // Three different real roots
325 scalar sqrtQ = sqrt(Q);
326 scalar theta = acos(R/(Q*sqrtQ));
328 scalar m2SqrtQ = -2*sqrtQ;
331 i = m2SqrtQ*cos(theta/3) - aBy3;
332 ii = m2SqrtQ*cos((theta + mathematicalConstant::twoPi)/3)
334 iii = m2SqrtQ*cos((theta - mathematicalConstant::twoPi)/3)
339 scalar A = cbrt(R + sqrt(R2 - Q3));
341 // Three equal real roots
345 return vector(root, root, root);
350 WarningIn("eigenValues(const symmTensor&)")
351 << "complex eigenvalues detected for symmTensor: " << t
361 // Sort the eigenvalues into ascending order
362 if (mag(i) > mag(ii))
367 if (mag(ii) > mag(iii))
372 if (mag(i) > mag(ii))
377 return vector(i, ii, iii);
381 vector eigenVector(const symmTensor& t, const scalar lambda)
383 if (mag(lambda) < SMALL)
388 // Construct the matrix for the eigenvector problem
389 symmTensor A(t - lambda*I);
391 // Calculate the sub-determinants of the 3 components
392 scalar sd0 = A.yy()*A.zz() - A.yz()*A.yz();
393 scalar sd1 = A.xx()*A.zz() - A.xz()*A.xz();
394 scalar sd2 = A.xx()*A.yy() - A.xy()*A.xy();
396 scalar magSd0 = mag(sd0);
397 scalar magSd1 = mag(sd1);
398 scalar magSd2 = mag(sd2);
400 // Evaluate the eigenvector using the largest sub-determinant
401 if (magSd0 > magSd1 && magSd0 > magSd2 && magSd0 > SMALL)
406 (A.yz()*A.xz() - A.zz()*A.xy())/sd0,
407 (A.yz()*A.xy() - A.yy()*A.xz())/sd0
413 else if (magSd1 > magSd2 && magSd1 > SMALL)
417 (A.xz()*A.yz() - A.zz()*A.xy())/sd1,
419 (A.xz()*A.xy() - A.xx()*A.yz())/sd1
425 else if (magSd2 > SMALL)
429 (A.xy()*A.yz() - A.yy()*A.xz())/sd2,
430 (A.xy()*A.xz() - A.xx()*A.yz())/sd2,
444 tensor eigenVectors(const symmTensor& t)
446 vector evals(eigenValues(t));
449 evs.x() = eigenVector(t, evals.x());
450 evs.y() = eigenVector(t, evals.y());
451 evs.z() = eigenVector(t, evals.z());
457 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
459 } // End namespace Foam
461 // ************************************************************************* //