From 924813d55f37f00589b903bf79109ddd3f4458f6 Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Thu, 3 Jul 2014 19:15:52 +0000 Subject: [PATCH] Implement vector-mode AD for the Hesse matrix This almost halves the assembly time for the Hesse matrix. Nice! Nevertheless I still keep the scalar-mode code around, hidden behind and #ifdef. Higher-order vector-mode in ADOL-C appears to be not quite as reliable as the rest, so I want to be able to easily compare results with the scalar code. Also, unlike the scalar code, the vector-mode one again computes the full Hessian in the surrounding Euclidean space. Only afterwards, that full Hessian is multiplied by the tangent space basis vectors to obtain a Hesse matrix on the tangent space. To obtain better efficiency one could have ADOL-C compute the Hessian in the tangent directions directly. However, ADOL-C sometimes segfaults... when doing that. [[Imported from SVN: r9815]] --- dune/gfe/localgeodesicfeadolcstiffness.hh | 73 +++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/dune/gfe/localgeodesicfeadolcstiffness.hh b/dune/gfe/localgeodesicfeadolcstiffness.hh index a1b7a878..3bbbcdd8 100644 --- a/dune/gfe/localgeodesicfeadolcstiffness.hh +++ b/dune/gfe/localgeodesicfeadolcstiffness.hh @@ -4,6 +4,7 @@ #include <adolc/adouble.h> // use of active doubles #include <adolc/drivers/drivers.h> // use of "Easy to Use" drivers // gradient(.) and hessian(.) +#include <adolc/interfaces.h> // use of "Easy to Use" drivers #include <adolc/taping.h> // use of taping #include <dune/gfe/adolcnamespaceinjections.hh> @@ -13,6 +14,8 @@ #include <dune/gfe/localgeodesicfestiffness.hh> +#define ADOLC_VECTOR_MODE + /** \brief Assembles energy gradient and Hessian with ADOL-C (automatic differentiation) */ template<class GridView, class LocalFiniteElement, class TargetSpace> @@ -241,6 +244,7 @@ assembleGradientAndHessian(const Entity& element, for (size_t i=0; i<nDofs; i++) orthonormalFrame[i] = localSolution[i].orthonormalFrame(); +#ifndef ADOLC_VECTOR_MODE Dune::Matrix<Dune::FieldMatrix<double,blocksize, embeddedBlocksize> > embeddedHessian(nDofs,nDofs); std::vector<double> v(nDoubles); @@ -296,6 +300,75 @@ assembleGradientAndHessian(const Entity& element, } +#else + Dune::Matrix<Dune::FieldMatrix<double,embeddedBlocksize, embeddedBlocksize> > embeddedHessian(nDofs,nDofs); + + int n = nDoubles; + //std::cout << "n: " << n << std::endl; + int nDirections = nDoubles; + double* tangent[nDoubles]; + for(size_t i=0; i<nDoubles; i++) + tangent[i] = (double*)malloc(nDirections*sizeof(double)); + + double* rawHessian[nDoubles]; + for(size_t i=0; i<nDoubles; i++) + rawHessian[i] = (double*)malloc(nDirections*sizeof(double)); + + //std::cout << "nDirections: " << nDirections << std::endl; + for (int i=0; i<n; i++) + for (int j=0; j<nDirections; j++) + tangent[i][j] = (i==j); + + hess_mat(1,nDoubles,nDirections,xp.data(),tangent,rawHessian); + + //std::cout << "Hallo Welt!" << std::endl; + + // Copy Hessian into Dune data type + for(size_t i=0; i<nDoubles; i++) + for (size_t j=0; j<nDoubles; j++) + embeddedHessian[i/embeddedBlocksize][j/embeddedBlocksize][i%embeddedBlocksize][j%embeddedBlocksize] = rawHessian[i][j]; + + + for(size_t i=0; i<nDoubles; i++) { + free(rawHessian[i]); + free(tangent[i]); + } + //printmatrix(std::cout, embeddedHessian, "hessian", "--"); + + // From this, compute the Hessian with respect to the manifold (which we assume here is embedded + // isometrically in a Euclidean space. + // For the detailed explanation of the following see: Absil, Mahoney, Trumpf, "An extrinsic look + // at the Riemannian Hessian". + + typedef typename TargetSpace::EmbeddedTangentVector EmbeddedTangentVector; + typedef typename TargetSpace::TangentVector TangentVector; + + this->A_.setSize(nDofs,nDofs); + + for (size_t col=0; col<nDofs; col++) { + + for (size_t subCol=0; subCol<blocksize; subCol++) { + + EmbeddedTangentVector z = orthonormalFrame[col][subCol]; + + // P_x \partial^2 f z + std::vector<EmbeddedTangentVector> semiEmbeddedProduct(nDofs); + + for (size_t row=0; row<nDofs; row++) { + embeddedHessian[row][col].mv(z,semiEmbeddedProduct[row]); + //tmp1 = localSolution[row].projectOntoTangentSpace(tmp1); + TangentVector tmp2; + orthonormalFrame[row].mv(semiEmbeddedProduct[row],tmp2); + + for (int subRow=0; subRow<blocksize; subRow++) + this->A_[row][col][subRow][subCol] = tmp2[subRow]; + } + + } + + } +#endif + ////////////////////////////////////////////////////////////////////////////////////// // Further correction due to non-planar configuration space // + \mathfrak{A}_x(z,P^\orth_x \partial f) -- GitLab