From ce4902bdc126d2df0d26d98818768eebdfa58a14 Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Mon, 18 Apr 2011 10:36:06 +0000 Subject: [PATCH] Implement the derivative of a gfe function value wrt the coefficients. Also: fix more bugs in the implementation of the derivative of gfe function gradients wrt the coefficients. This appears to work now, but inexact evaluations remain an issue. [[Imported from SVN: r7180]] --- dune/gfe/localgeodesicfefunction.hh | 117 ++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 8 deletions(-) diff --git a/dune/gfe/localgeodesicfefunction.hh b/dune/gfe/localgeodesicfefunction.hh index a33dd594..e624d897 100644 --- a/dune/gfe/localgeodesicfefunction.hh +++ b/dune/gfe/localgeodesicfefunction.hh @@ -87,6 +87,16 @@ public: /** \brief For debugging: Evaluate the derivative of the function using a finite-difference approximation*/ Dune::FieldMatrix<ctype, EmbeddedTangentVector::size, dim> evaluateDerivativeFD(const Dune::FieldVector<ctype, dim>& local) const; + /** \brief Evaluate the derivative of the function value with respect to a coefficient */ + void evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, + int coefficient, + Dune::FieldMatrix<double,embeddedDim,embeddedDim>& derivative) const; + + /** \brief Evaluate the derivative of the function value with respect to a coefficient */ + void evaluateFDDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, + int coefficient, + Dune::FieldMatrix<double,embeddedDim,embeddedDim>& derivative) const; + /** \brief Evaluate the derivative of the gradient of the function with respect to a coefficient */ void evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, int coefficient, @@ -158,6 +168,15 @@ private: return dFdw; } + Tensor3<ctype,embeddedDim,embeddedDim,embeddedDim> computeDqDqF(const std::vector<ctype>& w, const TargetSpace& q) const + { + Tensor3<ctype,embeddedDim,embeddedDim,embeddedDim> result; + result = 0; + for (int i=0; i<dim+1; i++) + result.axpy(w[i], TargetSpace::thirdDerivativeOfDistanceSquaredWRTSecondArgument(coefficients_[i],q)); + return result; + } + /** \brief The coefficient vector */ std::vector<TargetSpace> coefficients_; @@ -283,6 +302,66 @@ evaluateDerivativeFD(const Dune::FieldVector<ctype, dim>& local) const return result; } +template <int dim, class ctype, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, + int coefficient, + Dune::FieldMatrix<double,embeddedDim,embeddedDim>& result) const +{ + // the function value at the point where we are evaluating the derivative + TargetSpace q = evaluate(local); + + // dFdq + std::vector<ctype> w = barycentricCoordinates(local); + AverageDistanceAssembler<TargetSpace> assembler(coefficients_, w); + + Dune::FieldMatrix<ctype,embeddedDim,embeddedDim> dFdq(0); + assembler.assembleEmbeddedHessian(q,dFdq); + + // 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,embeddedDim,embeddedDim> dFdqPseudoInv = pseudoInverse(dFdq); + + // + result = TargetSpace::secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(coefficients_[coefficient], q); + result *= -w[coefficient]; + + result = result * dFdqPseudoInv; +} + +template <int dim, class ctype, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +evaluateFDDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, + int coefficient, + Dune::FieldMatrix<double,embeddedDim,embeddedDim>& result) const +{ + double eps = 1e-6; + for (int j=0; j<TargetSpace::EmbeddedTangentVector::size; j++) { + + std::vector<TargetSpace> cornersPlus = coefficients_; + std::vector<TargetSpace> cornersMinus = coefficients_; + typename TargetSpace::CoordinateType aPlus = coefficients_[coefficient].globalCoordinates(); + typename TargetSpace::CoordinateType aMinus = coefficients_[coefficient].globalCoordinates(); + aPlus[j] += eps; + aMinus[j] -= eps; + cornersPlus[coefficient] = TargetSpace(aPlus); + cornersMinus[coefficient] = TargetSpace(aMinus); + LocalGeodesicFEFunction<dim,double,TargetSpace> fPlus(cornersPlus); + LocalGeodesicFEFunction<dim,double,TargetSpace> fMinus(cornersMinus); + + TargetSpace hPlus = fPlus.evaluate(local); + TargetSpace hMinus = fMinus.evaluate(local); + + result[j] = hPlus.globalCoordinates(); + result[j] -= hMinus.globalCoordinates(); + result[j] /= 2*eps; + + } + +} + + template <int dim, class ctype, class TargetSpace> void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, @@ -325,20 +404,42 @@ evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& dvDqF = w[coefficient] * dvDqF; // Put it all together -#if 0 - for (size_t i=0; i<result.size(); i++) - result[i] = dFdqPseudoInv * ( dvDqF[i] * dFdqPseudoInv * dFdw - dvDwF[i]) * B; -#else - Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::size, dim> derivative = evaluateDerivative(local); - Tensor3<double, TargetSpace::EmbeddedTangentVector::size,TargetSpace::EmbeddedTangentVector::size,dim> foo; - foo = -1 * dvDwF * B - dvDqF*derivative; + Dune::FieldMatrix<double,embeddedDim,embeddedDim> dvq; + evaluateDerivativeOfValueWRTCoefficient(local,coefficient,dvq); + + Dune::FieldMatrix<ctype, embeddedDim, dim> derivative = evaluateDerivative(local); + + Tensor3<double, embeddedDim,embeddedDim,embeddedDim> dqdqF; + dqdqF = computeDqDqF(w,q); + + Tensor3<double, embeddedDim,embeddedDim,dim+1> dqdwF; + + for (int k=0; k<dim+1; k++) { + Dune::FieldMatrix<ctype,embeddedDim,embeddedDim> hesse = TargetSpace::secondDerivativeOfDistanceSquaredWRTSecondArgument(coefficients_[k], q); + for (int i=0; i<embeddedDim; i++) + for (int j=0; j<embeddedDim; j++) + dqdwF[i][j][k] = hesse[i][j]; + } + + Tensor3<double, embeddedDim,embeddedDim,dim+1> dqdwF_times_dvq; + for (int i=0; i<embeddedDim; i++) + for (int j=0; j<embeddedDim; j++) + for (int k=0; k<dim+1; k++) { + dqdwF_times_dvq[i][j][k] = 0; + for (int l=0; l<embeddedDim; l++) + dqdwF_times_dvq[i][j][k] += dqdwF[l][j][k] * dvq[l][i]; + } + + Tensor3<double, embeddedDim,embeddedDim,dim> foo; + foo = -1 * dvDqF*derivative - (dvq*dqdqF)*derivative - dvDwF * B - dqdwF_times_dvq*B; + result = 0; for (int i=0; i<embeddedDim; i++) for (int j=0; j<embeddedDim; j++) for (int k=0; k<dim; k++) for (int l=0; l<embeddedDim; l++) result[i][j][k] += dFdqPseudoInv[j][l] * foo[i][l][k]; -#endif + } -- GitLab