From cdab8df6f98478051eb7fe0130881c92890bb01c Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Sun, 28 Mar 2010 20:14:53 +0000 Subject: [PATCH] bugfix: dFdq may not be invertible [[Imported from SVN: r5804]] --- src/localgeodesicfefunction.hh | 40 ++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/localgeodesicfefunction.hh b/src/localgeodesicfefunction.hh index ea167299..b89f645a 100644 --- a/src/localgeodesicfefunction.hh +++ b/src/localgeodesicfefunction.hh @@ -9,6 +9,8 @@ #include <dune/src/averagedistanceassembler.hh> #include <dune/src/targetspacertrsolver.hh> +#include <dune/src/svd.hh> + /** \brief A geodesic function from the reference element to a manifold \tparam dim Dimension of the reference element @@ -20,6 +22,7 @@ class LocalGeodesicFEFunction { typedef typename TargetSpace::EmbeddedTangentVector EmbeddedTangentVector; + static const int targetDim = EmbeddedTangentVector::size; public: @@ -48,7 +51,34 @@ private: } return result; } + + static Dune::FieldMatrix<double,targetDim,targetDim> pseudoInverse(const Dune::FieldMatrix<double,targetDim,targetDim>& A) + { + Dune::FieldMatrix<double,targetDim,targetDim> U = A; + Dune::FieldVector<double,targetDim> W; + Dune::FieldMatrix<double,targetDim,targetDim> V; + + svdcmp(U,W,V); + + // pseudoInv = V W^{-1} U^T + Dune::FieldMatrix<double,targetDim,targetDim> UT; + + for (int i=0; i<targetDim; i++) + for (int j=0; j<targetDim; j++) + UT[i][j] = U[j][i]; + + for (int i=0; i<targetDim; i++) { + if (std::abs(W[i]) > 1e-12) // Diagonal may be zero, that's why we're using the pseudo inverse + UT[i] /= W[i]; + else + UT[i] = 0; + } + + Dune::FieldMatrix<double,targetDim,targetDim> pseudoInv; + Dune::FMatrixHelp::multMatrix(V,UT,pseudoInv); + return pseudoInv; + } /** \brief The coefficient vector */ std::vector<TargetSpace> coefficients_; @@ -104,7 +134,7 @@ evaluateDerivative(const Dune::FieldVector<ctype, dim>& local) // Hence we need to solve a small system of linear equations. // //////////////////////////////////////////////////////////////////////// - // the function value at the point where we are evaluation the derivative + // the function value at the point where we are evaluating the derivative TargetSpace q = evaluate(local); // the matrix that turns coordinates on the reference simplex into coordinates on the standard simplex @@ -139,13 +169,19 @@ evaluateDerivative(const Dune::FieldVector<ctype, dim>& local) // solve the system // //////////////////////////////////// + // dFDq is not invertible, if the target space is embedded into a higher-dimensional + // Euclidean space. Therefore we use its pseudo inverse. I don't think that is the + // best way, though. + Dune::FieldMatrix<ctype,targetDim,targetDim> dFdqPseudoInv = pseudoInverse(dFdq); + for (int i=0; i<dim; i++) { Dune::FieldVector<ctype,targetDim> rhs, x; for (int j=0; j<targetDim; j++) rhs[j] = RHS[j][i]; - dFdq.solve(x, rhs); + //dFdq.solve(x, rhs); + dFdqPseudoInv.mv(rhs,x); for (int j=0; j<targetDim; j++) result[j][i] = x[j]; -- GitLab