diff --git a/dune/gfe/localgeodesicfestiffness.hh b/dune/gfe/localgeodesicfestiffness.hh index 2b0f6c33cd0be2d7a269bbe7b541bb41cc9be818..b157f8e8d9df4c4e37ba864950e22136a1ecccf9 100644 --- a/dune/gfe/localgeodesicfestiffness.hh +++ b/dune/gfe/localgeodesicfestiffness.hh @@ -318,6 +318,9 @@ public: //! Each block is x, y, theta in 2d, T (R^3 \times SO(3)) in 3d enum { blocksize = TargetSpace::TangentVector::size }; + //! Each block is x, y, theta in 2d, T (R^3 \times SO(3)) in 3d + enum { embeddedBlocksize = TargetSpace::EmbeddedTangentVector::size }; + /** \brief Assemble the local stiffness matrix at the current position This default implementation used finite-difference approximations to compute the second derivatives @@ -341,6 +344,59 @@ public: virtual void assembleGradient(const Entity& element, const std::vector<TargetSpace>& solution, std::vector<typename TargetSpace::TangentVector>& gradient) const; + + void embeddedGradientOfEmbeddedGradient(const Entity& element, + const std::vector<TargetSpace>& localSolution, + int component, + std::vector<Dune::FieldMatrix<double,embeddedBlocksize,embeddedBlocksize> >& gradient) const { + + double eps = 1e-6; + + gradient.resize(localSolution.size()); + std::fill(gradient.begin(), gradient.end(), Dune::FieldMatrix<double,embeddedBlocksize,embeddedBlocksize>(0)); + + std::vector<TargetSpace> forwardSolution = localSolution; + std::vector<TargetSpace> backwardSolution = localSolution; + + + for (int j=0; j<blocksize; j++) { + + // The return value does not have unit norm. But assigning it to a UnitVector object + // will normalize it. This amounts to an extension of the energy functional + // to a neighborhood around S^n + forwardSolution[component] = infinitesimalVariation(localSolution[component], eps, j); + backwardSolution[component] = infinitesimalVariation(localSolution[component], -eps, j); + + std::vector<Dune::FieldVector<double,embeddedBlocksize> > forwardGradient; + std::vector<Dune::FieldVector<double,embeddedBlocksize> > backwardGradient; + assembleEmbeddedGradient(element, forwardSolution, forwardGradient); + assembleEmbeddedGradient(element, backwardSolution, backwardGradient); + + for (int k=0; k<localSolution.size(); k++) + for (int l=0; l<embeddedBlocksize; l++) + gradient[k][j][l] = (forwardGradient[k][l] - backwardGradient[k][l]) / (2*eps); + + forwardSolution[component] = localSolution[component]; + backwardSolution[component] = localSolution[component]; + + // Project each column vector onto the tangent space + + // Project gradient in embedding space onto the tangent space + for (size_t i=0; i<localSolution.size(); i++) + for (int j=0; j<embeddedBlocksize; j++) { + Dune::FieldVector<double,embeddedBlocksize> tmp; + for (int k=0; k<embeddedBlocksize; k++) + tmp[k] = gradient[i][k][j]; + tmp = localSolution[i].projectOntoTangentSpace(tmp); + for (int k=0; k<embeddedBlocksize; k++) + gradient[i][k][j] = tmp[k]; + } + + + } + + + } // assembled data Dune::Matrix<Dune::FieldMatrix<double,blocksize,blocksize> > A_; @@ -410,6 +466,9 @@ assembleGradient(const Entity& element, } +// /////////////////////////////////////////////////////////// +// Compute gradient by finite-difference approximation +// /////////////////////////////////////////////////////////// template <class GridType, int dim> void LocalGeodesicFEStiffness<GridType,UnitVector<dim> >:: assemble(const Entity& element, @@ -430,47 +489,49 @@ assemble(const Entity& element, A_[i][i][j][j] = 1; #else - // /////////////////////////////////////////////////////////// - // Compute gradient by finite-difference approximation - // /////////////////////////////////////////////////////////// - - double eps = 1e-6; + // first compute the Hessian in the embedding space + Dune::Matrix<Dune::FieldMatrix<double,embeddedBlocksize,embeddedBlocksize> > embeddedHessian(nDofs,nDofs); - std::vector<TargetSpace> forwardSolution = localSolution; - std::vector<TargetSpace> backwardSolution = localSolution; + std::vector<Dune::FieldMatrix<double,embeddedBlocksize,embeddedBlocksize> > embeddedGradient; for (size_t i=0; i<localSolution.size(); i++) { - - for (int j=0; j<blocksize; j++) { - - // The return value does not have unit norm. But assigning it to a UnitVector object - // will normalize it. This amounts to an extension of the energy functional - // to a neighborhood around S^n - forwardSolution[i] = infinitesimalVariation(localSolution[i], eps, j); - backwardSolution[i] = infinitesimalVariation(localSolution[i], -eps, j); - std::vector<Dune::FieldVector<double,blocksize> > forwardGradient; - std::vector<Dune::FieldVector<double,blocksize> > backwardGradient; - assembleGradient(element, forwardSolution, forwardGradient); - assembleGradient(element, backwardSolution, backwardGradient); + embeddedGradientOfEmbeddedGradient(element,localSolution, i, embeddedGradient); - for (int k=0; k<localSolution.size(); k++) - for (int l=0; l<blocksize; l++) - this->A[i][k][j][l] = (forwardGradient[k][l] - backwardGradient[k][l]) / (2*eps); + for (int j=0; j<localSolution.size(); j++) + embeddedHessian[i][j] = embeddedGradient[j]; - forwardSolution[i] = localSolution[i]; - backwardSolution[i] = localSolution[i]; + } - } + std::cout << "embeddedHessian" << std::endl; + printmatrix(std::cout, embeddedHessian, "embeddedHessian", "--"); - } + // transform to local tangent space bases + std::vector<Dune::FieldMatrix<double,blocksize,embeddedBlocksize> > orthonormalFrames(nDofs); + std::vector<Dune::FieldMatrix<double,embeddedBlocksize,blocksize> > orthonormalFramesTransposed(nDofs); - // Project gradient in embedding space onto the tangent space - for (size_t i=0; i<localSolution.size(); i++) - for (size_t j=0; j<localSolution.size(); j++) + for (size_t i=0; i<nDofs; i++) { + orthonormalFrames[i] = localSolution[i].orthonormalFrame(); + + for (int j=0; j<embeddedBlocksize; j++) for (int k=0; k<blocksize; k++) - this->A[i][j][k] = localSolution[j].projectOntoTangentSpace(this->A[i][j][k]); - + orthonormalFramesTransposed[i][j][k] = orthonormalFrames[i][k][j]; + + } + + for (size_t i=0; i<nDofs; i++) + for (size_t j=0; j<nDofs; j++) { + + Dune::FieldMatrix<double,blocksize,embeddedBlocksize> tmp; + Dune::FMatrixHelp::multMatrix(orthonormalFrames[i],embeddedHessian[i][j],tmp); + A_[i][j] = tmp.rightmultiplyany(orthonormalFramesTransposed[j]); + + + } + + std::cout << "localHessian" << std::endl; + printmatrix(std::cout, A_, "localHessian", "--"); + #endif }