Commit 6576397e by Kutalmis Bercin Committed by Andrew Heather

ENH: improve analytic eigen for small off-diagonals

parent b476dd92
 ... ... @@ -62,9 +62,24 @@ unsigned nFail_ = 0; // Create a random symmTensor symmTensor makeRandomContainer(Random& rnd) { symmTensor A(Zero); std::generate(A.begin(), A.end(), [&]{ return rnd.GaussNormal(); }); return A; symmTensor T(Zero); std::generate(T.begin(), T.end(), [&]{ return rnd.GaussNormal(); }); return T; } // Create a symmTensor based on a given value template typename std::enable_if < std::is_same::value || std::is_same::value, symmTensor >::type makeContainer(const Type val) { symmTensor T(Zero); std::fill(T.begin(), T.end(), val); return T; } ... ... @@ -83,11 +98,11 @@ typename std::enable_if const word& msg, const Type& x, const Type& y, const scalar relTol = 1e-8, // eigen functions: ##" << nl; Info<< nl << " ## Test symmTensor eigen functions: ##" << nl; const label numberOfTests = 10000; Random rndGen(1234); ... ... @@ -640,14 +653,13 @@ int main() } { Info<< nl << " ## Test eigen functions by a zero tensor: ##"<< nl; Info<< nl << " ## A zero symmTensor: ##"<< nl; const symmTensor zeroT(Zero); test_eigen_funcs(zeroT); } { Info<< nl << " ## Test eigen functions by a tensor consisting of" << " 2 repeated eigenvalues: ##" << " ## A symmTensor with 2 repeated eigenvalues: ##" << nl; const symmTensor T ( ... ... @@ -659,8 +671,7 @@ int main() } { Info<< nl << " ## Test eigen functions by a tensor consisting of" << " 3 repeated eigenvalues: ##" << " ## A symmTensor with 3 repeated eigenvalues: ##" << nl; const symmTensor T ( ... ... @@ -670,31 +681,175 @@ int main() ); test_eigen_funcs(T); } { Info<< nl << " ## A stiff symmTensor: ##" << nl; const symmTensor stiff ( pow(10.0, 10), pow(10.0, 8), pow(10.0, -8), pow(10.0, -8), pow(10.0, 8), pow(10.0, 7) ); test_eigen_funcs(stiff); } { Info<< nl << " ## Test eigen functions by a tensor consisting of" << " SMALL off-diagonal elements: ##" << " ## Random symmTensors with tiny off-diag elements: ##" << nl; const List epsilons ({ 0, SMALL, Foam::sqrt(SMALL), sqr(SMALL), Foam::cbrt(SMALL), -SMALL, -Foam::sqrt(SMALL), -sqr(SMALL), -Foam::cbrt(SMALL) }); for (label i = 0; i < numberOfTests; ++i) { symmTensor T(makeRandomContainer(rndGen)); T.xy() = SMALL*rndGen.GaussNormal(); T.xz() = SMALL*rndGen.GaussNormal(); T.yz() = SMALL*rndGen.GaussNormal(); for (const auto& eps : epsilons) { { symmTensor T(makeRandomContainer(rndGen)); T.xy() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xz() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.yz() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xy() = eps*rndGen.GaussNormal(); T.xz() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xy() = eps*rndGen.GaussNormal(); T.yz() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xz() = eps*rndGen.GaussNormal(); T.yz() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xy() = eps*rndGen.GaussNormal(); T.xz() = eps*rndGen.GaussNormal(); T.yz() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xy() = eps; T.xz() = eps; T.yz() = eps; test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xy() = eps; T.xz() = eps; T.yz() = eps; T.zz() = eps; test_eigen_funcs(T); } { symmTensor T(makeRandomContainer(rndGen)); T.xy() = 0; T.xz() = eps*rndGen.GaussNormal(); T.yz() = 0; test_eigen_funcs(T); } } } } #if 0 // Numerical diagonalisation of 2x2 or 3x3 matrices with analytic methods // are, like the methods currently being used in OpenFOAM, inherently error // prone. Despite its speed, the analytic methods may becomes inaccurate or // may even fail completely if the matrix entries differ greatly in // magnitude, particularly with large off-diagonal elements. // The remedy is to use iterative or hybrid analytic/iterative methods // such as published here (for 3x3/2x2 matrices): // (Kopp, 2008) arXiv.org: physics/0610206 // mpi-hd.mpg.de/personalhomes/globes/3x3/index.html { Info<< nl << " ## symmTensors consisting machine epsilons: ##" << nl; Info<< " # floatScalar" << nl; const List floatEpsilons ({ floatScalarGREAT, floatScalarVGREAT, floatScalarROOTVGREAT, floatScalarSMALL, floatScalarVSMALL, floatScalarROOTVSMALL, Foam::sqrt(floatScalarSMALL), 0 }); for (const auto& eps : floatEpsilons) { const symmTensor T(makeContainer(eps)); test_eigen_funcs(T); } Info<< " # doubleScalar" << nl; const List doubleEpsilons ({ doubleScalarGREAT, doubleScalarROOTVGREAT, // doubleVGREAT fails doubleScalarSMALL, doubleScalarVSMALL, doubleScalarROOTVSMALL, Foam::sqrt(doubleScalarSMALL), 0 }); for (const auto& eps : doubleEpsilons) { const symmTensor T(makeContainer(eps)); test_eigen_funcs(T); } } { Info<< nl << " ## Test eigen functions by a stiff tensor: ##" << nl; const symmTensor stiff ( pow(10.0, 10), pow(10.0, 8), pow(10.0, -8), pow(10.0, -8), pow(10.0, 8), pow(10.0, 7) ); test_eigen_funcs(stiff); Info<< nl << " ## Random symmTensors with machine eps off-diag elmes: ##" << nl; const List floatEpsilons ({ floatScalarGREAT, floatScalarVGREAT, floatScalarROOTVGREAT, floatScalarSMALL, floatScalarVSMALL, floatScalarROOTVSMALL }); const List doubleEpsilons ({ doubleScalarGREAT, doubleScalarVGREAT, doubleScalarROOTVGREAT, doubleScalarSMALL, doubleScalarVSMALL, doubleScalarROOTVSMALL }); for (label i = 0; i < numberOfTests; ++i) { symmTensor T(makeRandomContainer(rndGen)); for (const auto& eps : floatEpsilons) { T.xy() = eps; T.xz() = eps; T.yz() = eps; test_eigen_funcs(T); } for (const auto& eps : doubleEpsilons) { T.xy() = eps; T.xz() = eps; T.yz() = eps; test_eigen_funcs(T); } } } #endif if (nFail_) ... ...
 ... ... @@ -83,11 +83,11 @@ typename std::enable_if const word& msg, const Type& x, const Type& y, const scalar relTol = 1e-8, // epsilons ({ 0, SMALL, Foam::sqrt(SMALL), sqr(SMALL), Foam::cbrt(SMALL), -SMALL, -Foam::sqrt(SMALL), -sqr(SMALL), -Foam::cbrt(SMALL) }); for (label i = 0; i < numberOfTests; ++i) { for (const auto& eps : epsilons) { { symmTensor2D T(makeRandomContainer(rndGen)); T.xy() = eps*rndGen.GaussNormal(); test_eigen_funcs(T); } { symmTensor2D T(makeRandomContainer(rndGen)); T.xy() = eps; test_eigen_funcs(T); } } } } if (nFail_) ... ...
 ... ... @@ -84,11 +84,11 @@ typename std::enable_if const word& msg, const Type& x, const Type& y, const scalar relTol = 1e-8, //