From d210a39e0038a775a295597d1cb6fe1ba6fef322 Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Tue, 3 Sep 2013 16:29:27 +0000 Subject: [PATCH] New local assembler using ADOL-C to compute energy gradient and Hessian [[Imported from SVN: r9395]] --- dune/gfe/localgeodesicfeadolcstiffness.hh | 247 ++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 dune/gfe/localgeodesicfeadolcstiffness.hh diff --git a/dune/gfe/localgeodesicfeadolcstiffness.hh b/dune/gfe/localgeodesicfeadolcstiffness.hh new file mode 100644 index 00000000..dfd1de44 --- /dev/null +++ b/dune/gfe/localgeodesicfeadolcstiffness.hh @@ -0,0 +1,247 @@ +#ifndef DUNE_GFE_LOCAL_GEODESIC_FE_ADOL_C_STIFFNESS_HH +#define DUNE_GFE_LOCAL_GEODESIC_FE_ADOL_C_STIFFNESS_HH + +#include <adolc/adouble.h> // use of active doubles +#include <adolc/drivers/drivers.h> // use of "Easy to Use" drivers +// gradient(.) and hessian(.) +#include <adolc/taping.h> // use of taping + +#undef overwrite // stupid: ADOL-C sets this to 1, so the name cannot be used + +#include <dune/gfe/adolcnamespaceinjections.hh> + +#include <dune/common/fmatrix.hh> +#include <dune/istl/matrix.hh> + +#include <dune/gfe/localgeodesicfestiffness.hh> + +/** \brief Assembles energy gradient and Hessian with ADOL-C (automatic differentiation) + */ +template<class GridView, class LocalFiniteElement, class TargetSpace> +class LocalGeodesicFEADOLCStiffness + : public LocalGeodesicFEStiffness<GridView,LocalFiniteElement,TargetSpace> +{ + // grid types + typedef typename GridView::Grid::ctype DT; + typedef typename TargetSpace::ctype RT; + typedef typename GridView::template Codim<0>::Entity Entity; + + typedef typename TargetSpace::template rebind<adouble>::other ATargetSpace; + + // some other sizes + enum {gridDim=GridView::dimension}; + +public: + + //! Dimension of a tangent space + enum { blocksize = TargetSpace::TangentVector::dimension }; + + //! Dimension of the embedding space + enum { embeddedBlocksize = TargetSpace::EmbeddedTangentVector::dimension }; + + LocalGeodesicFEADOLCStiffness(const LocalGeodesicFEStiffness<GridView, LocalFiniteElement, ATargetSpace>* energy) + : localEnergy_(energy) + {} + + /** \brief Compute the energy at the current configuration */ + virtual RT energy (const Entity& e, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) const; + + /** \brief Assemble the element gradient of the energy functional + + This uses the automatic differentiation toolbox ADOL_C. + */ + virtual void assembleGradient(const Entity& element, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& solution, + std::vector<typename TargetSpace::TangentVector>& gradient) const; + + /** \brief Assemble the local stiffness matrix at the current position + + This uses the automatic differentiation toolbox ADOL_C. + */ + virtual void assembleHessian(const Entity& e, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution); + + const LocalGeodesicFEStiffness<GridView, LocalFiniteElement, ATargetSpace>* localEnergy_; + +}; + + +template <class GridView, class LocalFiniteElement, class TargetSpace> +typename LocalGeodesicFEADOLCStiffness<GridView, LocalFiniteElement, TargetSpace>::RT +LocalGeodesicFEADOLCStiffness<GridView, LocalFiniteElement, TargetSpace>:: +energy(const Entity& element, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) const +{ + double pureEnergy; + + std::vector<ATargetSpace> localASolution(localSolution.size()); + + trace_on(1); + + adouble energy = 0; + + for (size_t i=0; i<localSolution.size(); i++) + localASolution[i] <<=localSolution[i]; + + energy = localEnergy_->energy(element,localFiniteElement,localASolution); + + energy >>= pureEnergy; + + trace_off(); +#if 0 + size_t tape_stats[STAT_SIZE]; + tapestats(1,tape_stats); // reading of tape statistics + cout<<"maxlive "<<tape_stats[NUM_MAX_LIVES]<<"\n"; + // ..... print other tape stats +#endif + return pureEnergy; +} + + +template <class GridView, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEADOLCStiffness<GridView, LocalFiniteElement, TargetSpace>:: +assembleGradient(const Entity& element, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution, + std::vector<typename TargetSpace::TangentVector>& localGradient) const +{ + double pureEnergy; + + std::vector<ATargetSpace> localASolution(localSolution.size()); + + trace_on(1); + + adouble energy = 0; + + for (size_t i=0; i<localSolution.size(); i++) + localASolution[i] <<=localSolution[i]; + + energy = localEnergy_->energy(element,localFiniteElement,localASolution); + + energy >>= pureEnergy; + + trace_off(0); + //std::cout << "ADOL-C energy: " << pureEnergy << std::endl; +#if 0 + size_t tape_stats[STAT_SIZE]; + tapestats(1,tape_stats); // reading of tape statistics + cout<<"maxlive "<<tape_stats[NUM_MAX_LIVES]<<"\n"; + // ..... print other tape stats +#endif + // Compute the actual gradient + size_t nDofs = localSolution.size(); + size_t nDoubles = nDofs*embeddedBlocksize; + std::vector<double> xp(nDoubles); + int idx=0; + for (size_t i=0; i<nDofs; i++) + for (size_t j=0; j<embeddedBlocksize; j++) + xp[idx++] = localSolution[i].globalCoordinates()[j]; + + // Compute gradient + std::vector<double> g(nDoubles); + gradient(1,nDoubles,xp.data(),g.data()); // gradient evaluation + + // Copy into Dune type + std::vector<typename TargetSpace::EmbeddedTangentVector> localEmbeddedGradient(localSolution.size()); + + idx=0; + for (size_t i=0; i<nDofs; i++) + for (size_t j=0; j<embeddedBlocksize; j++) + localEmbeddedGradient[i][j] = g[idx++]; + +// std::cout << "localEmbeddedGradient:\n"; +// for (size_t i=0; i<nDofs; i++) +// std::cout << localEmbeddedGradient[i] << std::endl; + + // Express gradient in local coordinate system + for (size_t i=0; i<nDofs; i++) { + Dune::FieldMatrix<RT,blocksize,embeddedBlocksize> orthonormalFrame = localSolution[i].orthonormalFrame(); + orthonormalFrame.mv(localEmbeddedGradient[i],localGradient[i]); + } +} + + +// /////////////////////////////////////////////////////////// +// Compute gradient by finite-difference approximation +// /////////////////////////////////////////////////////////// +template <class GridType, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEADOLCStiffness<GridType, LocalFiniteElement, TargetSpace>:: +assembleHessian(const Entity& element, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) +{ + double pureEnergy; + + std::vector<ATargetSpace> localASolution(localSolution.size()); + + trace_on(1,1); + + adouble energy = 0; + + for (size_t i=0; i<localSolution.size(); i++) + localASolution[i] <<=localSolution[i]; + + energy = localEnergy_->energy(element,localFiniteElement,localASolution); + + energy >>= pureEnergy; + + trace_off(0); + + // Compute Hessian + size_t nDofs = localSolution.size(); + size_t nDoubles = nDofs*embeddedBlocksize; + std::vector<double> xp(nDoubles); + int idx=0; + for (size_t i=0; i<nDofs; i++) + for (size_t j=0; j<embeddedBlocksize; j++) + xp[idx++] = localSolution[i].globalCoordinates()[j]; + + double** H = (double**) malloc(nDoubles*sizeof(double*)); + for(size_t i=0; i<nDoubles; i++) + H[i] = (double*)malloc((i+1)*sizeof(double)); + hessian(1,nDoubles,xp.data(),H); // H equals (n-1)g since g is + + // Copy Hessian into Dune data type + Dune::Matrix<Dune::FieldMatrix<double,embeddedBlocksize, embeddedBlocksize> > embeddedHessian(nDofs,nDofs); + for(size_t i=0; i<nDoubles; i++) { + for (size_t j=0; j<nDoubles; j++) { + double value = (j<=i) ? H[i][j] : H[j][i]; + embeddedHessian[i/embeddedBlocksize][j/embeddedBlocksize][i%embeddedBlocksize][j%embeddedBlocksize] = value; + } + } + + // Express Hessian in local coordinate system + this->A_.setSize(nDofs,nDofs); + std::vector<Dune::FieldMatrix<RT,blocksize,embeddedBlocksize> > orthonormalFrame(nDofs); + + for (size_t i=0; i<nDofs; i++) + orthonormalFrame[i] = localSolution[i].orthonormalFrame(); + + for (size_t row=0; row<nDofs; row++) { + + for (size_t col=0; col<nDofs; col++) { + + // this is frame * embeddedHessian * frame^T + for (int i=0; i<blocksize; i++) + for (int j=0; j<blocksize; j++) { + this->A_[row][col][i][j] = 0; + for (int k=0; k<embeddedBlocksize; k++) + for (int l=0; l<embeddedBlocksize; l++) + this->A_[row][col][i][j] += orthonormalFrame[row][i][k] + *embeddedHessian[row][col][k][l] + *orthonormalFrame[col][j][l]; + } + } + } + +// std::cout << "ADOL-C stiffness:\n"; +// printmatrix(std::cout, this->A_, "foo", "--"); +} + +#endif + -- GitLab