Skip to content
Snippets Groups Projects
localgeodesicfestiffness.hh 11.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef LOCAL_GEODESIC_FE_STIFFNESS_HH
    #define LOCAL_GEODESIC_FE_STIFFNESS_HH
    
    #include <dune/istl/bcrsmatrix.hh>
    #include <dune/common/fmatrix.hh>
    #include <dune/istl/matrixindexset.hh>
    #include <dune/istl/matrix.hh>
    
    
    Oliver Sander's avatar
    Oliver Sander committed
    #include "rigidbodymotion.hh"
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    // Forward declaration
    template<class GridView, class TargetSpace>
    class LocalGeodesicFEStiffness;
    
    
    template<class GridView, class TargetSpace>
    
    class LocalGeodesicFEStiffnessImp
    
    
        typedef typename GridView::template Codim<0>::Entity Entity;
        
        public:
    
        static void infinitesimalVariation(RealTuple<N>& c, double eps, int i)
    
        {
            Dune::FieldVector<double,N> v(0);
            v[i] = eps;
    
            c = RealTuple<N>::exp(c,v).globalCoordinates();
    
        static void infinitesimalVariation(UnitVector<N>& c, double eps, int i)
    
        {
            Dune::FieldVector<double,N> result = c.globalCoordinates();
            result[i] += eps;
    
        /** \brief For the fd approximations 
         */
        static void infinitesimalVariation(RigidBodyMotion<3>& c, double eps, int i)
        {
            if (i<3)
                c.r[i] += eps;
            else
                c.q = c.q.mult(Rotation<3,double>::exp((i==3)*eps, 
                                                       (i==4)*eps, 
                                                       (i==5)*eps));
        }
    
        /** \brief For the fd approximations 
        */
        static void infinitesimalVariation(RigidBodyMotion<2>& c, double eps, int i)
        {
            if (i<2)
                c.r[i] += eps;
            else
                c.q = c.q.mult(Rotation<2,double>::exp(Dune::FieldVector<double,1>(eps)));
        }
    
        static void infinitesimalVariation(Rotation<3,double>& c, double eps, int i)
        {
            c = c.mult(Rotation<3,double>::exp((i==0)*eps, 
                                               (i==1)*eps, 
                                               (i==2)*eps));
        }
    
        static void infinitesimalVariation(Rotation<2,double>& c, double eps, int i)
        {
            Dune::FieldVector<double,1> v(eps);
            c = Rotation<2,double>::exp(c,v);
        }
    
    
        static void assembleEmbeddedGradient(const Entity& element,
                                      const std::vector<TargetSpace>& localSolution,
                                      std::vector<typename TargetSpace::EmbeddedTangentVector>& localGradient,
                                      const LocalGeodesicFEStiffness<GridView,TargetSpace>* energyObject)
        {
    
            const int embeddedBlocksize = TargetSpace::EmbeddedTangentVector::size;
    
            // ///////////////////////////////////////////////////////////
            //   Compute gradient by finite-difference approximation
            // ///////////////////////////////////////////////////////////
    
            double eps = 1e-6;
    
            localGradient.resize(localSolution.size());
    
            std::vector<TargetSpace> forwardSolution = localSolution;
            std::vector<TargetSpace> backwardSolution = localSolution;
    
            for (size_t i=0; i<localSolution.size(); i++) {
            
                for (int j=0; j<embeddedBlocksize; 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]  = localSolution[i];
                    backwardSolution[i] = localSolution[i];
    
                    LocalGeodesicFEStiffnessImp<GridView,TargetSpace>::infinitesimalVariation(forwardSolution[i],  eps, j);
                    LocalGeodesicFEStiffnessImp<GridView,TargetSpace>::infinitesimalVariation(backwardSolution[i], -eps, j);
    
    
                    localGradient[i][j] = (energyObject->energy(element,forwardSolution) - energyObject->energy(element,backwardSolution)) / (2*eps);
    
                    forwardSolution[i]  = localSolution[i];
                    backwardSolution[i] = localSolution[i];
                }
    
                // Project gradient in embedding space onto the tangent space
                localGradient[i] = localSolution[i].projectOntoTangentSpace(localGradient[i]);
            
            }
    
        }
    
    
    };
    
    
    template<class GridView, class TargetSpace>
    class LocalGeodesicFEStiffness 
    {
    
        // grid types
        typedef typename GridView::Grid::ctype DT;
        typedef typename TargetSpace::ctype RT;
        typedef typename GridView::template Codim<0>::Entity Entity;
        
        // some other sizes
        enum {gridDim=GridView::dimension};
    
    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
    
    
        The formula for the Riemannian Hessian has been taken from Absil, Mahony, Sepulchre:
        'Optimization algorithms on matrix manifolds', page 107
    
    
        virtual void assembleHessian(const Entity& e,
    
                      const std::vector<TargetSpace>& localSolution);
        
        virtual RT energy (const Entity& e,
                           const std::vector<TargetSpace>& localSolution) const = 0;
    
    
        /** \brief Assemble the element gradient of the energy functional using a finite-difference approximation
    
        This is mainly for debugging purposes.
        */
        virtual void assembleEmbeddedFDGradient(const Entity& element,
                                                const std::vector<TargetSpace>& solution,
                                                std::vector<typename TargetSpace::EmbeddedTangentVector>& gradient) const;
    
        /** \brief Assemble the element gradient of the energy functional 
    
    
        The default implementation in this class uses a finite difference approximation */
        virtual void assembleGradient(const Entity& element,
                                      const std::vector<TargetSpace>& solution,
    
                                      std::vector<typename TargetSpace::TangentVector>& gradient) const;
    
        // assembled data
        Dune::Matrix<Dune::FieldMatrix<double,blocksize,blocksize> > A_;
    
    template <class GridView, class TargetSpace>
    void LocalGeodesicFEStiffness<GridView, TargetSpace>::
    
    assembleGradient(const Entity& element,
                     const std::vector<TargetSpace>& localSolution,
                     std::vector<typename TargetSpace::TangentVector>& localGradient) const
    {
    
        std::vector<typename TargetSpace::EmbeddedTangentVector> embeddedLocalGradient;
    
        // first compute the gradient in embedded coordinates
        LocalGeodesicFEStiffnessImp<GridView,TargetSpace>::assembleEmbeddedGradient(element, localSolution, embeddedLocalGradient, this);
    
        // transform to coordinates on the tangent space
        localGradient.resize(embeddedLocalGradient.size());
    
        for (size_t i=0; i<localGradient.size(); i++)
            localSolution[i].orthonormalFrame().mv(embeddedLocalGradient[i], localGradient[i]);
    
    template <class GridView, class TargetSpace>
    void LocalGeodesicFEStiffness<GridView, TargetSpace>::
    
    assembleEmbeddedFDGradient(const Entity& element,
                     const std::vector<TargetSpace>& localSolution,
                     std::vector<typename TargetSpace::EmbeddedTangentVector>& localGradient) const
    {
    
        LocalGeodesicFEStiffnessImp<GridView,TargetSpace>::assembleEmbeddedGradient(element, localSolution, localGradient, this);
    
    // ///////////////////////////////////////////////////////////
    //   Compute gradient by finite-difference approximation
    // ///////////////////////////////////////////////////////////
    
    template <class GridType, class TargetSpace>
    void LocalGeodesicFEStiffness<GridType, TargetSpace>::
    
    assembleHessian(const Entity& element,
    
             const std::vector<TargetSpace>& localSolution)
    {
        // 1 degree of freedom per element vertex
    
        size_t nDofs = element.template count<gridDim>();
    
        A_.setSize(nDofs, nDofs);
    
        
        
        const double eps = 1e-4;
            
        std::vector<Dune::FieldMatrix<double,blocksize,embeddedBlocksize> > B(localSolution.size());
        for (size_t i=0; i<B.size(); i++)
            B[i] = localSolution[i].orthonormalFrame();
    
        for (size_t i=0; i<localSolution.size(); i++) {
    
            for (size_t i2=0; i2<blocksize; i2++) {
                for (size_t j=0; j<localSolution.size(); j++) {
                    for (size_t j2=0; j2<blocksize; j2++) {
    
                        Dune::FieldVector<double,embeddedBlocksize> epsXi  = B[i][i2];    epsXi *= eps;
                        Dune::FieldVector<double,embeddedBlocksize> epsEta = B[j][j2];   epsEta *= eps;
                
                        Dune::FieldVector<double,embeddedBlocksize> minusEpsXi  = epsXi;   minusEpsXi  *= -1;
                        Dune::FieldVector<double,embeddedBlocksize> minusEpsEta = epsEta;  minusEpsEta *= -1;
                            
                        std::vector<TargetSpace> forwardSolutionXiEta  = localSolution;
                        std::vector<TargetSpace> forwardSolutionXi     = localSolution;
                        std::vector<TargetSpace> forwardSolutionEta    = localSolution;
                        std::vector<TargetSpace> backwardSolutionXiEta  = localSolution;
                        std::vector<TargetSpace> backwardSolutionXi     = localSolution;
                        std::vector<TargetSpace> backwardSolutionEta    = localSolution;
    
                        if (i==j)
                            forwardSolutionXiEta[i] = TargetSpace::exp(localSolution[i],epsXi+epsEta);
                        else {
                            forwardSolutionXiEta[i] = TargetSpace::exp(localSolution[i],epsXi);
                            forwardSolutionXiEta[j] = TargetSpace::exp(localSolution[j],epsEta);
                        }
                        forwardSolutionXi[i]    = TargetSpace::exp(localSolution[i],epsXi);
                        forwardSolutionEta[j]   = TargetSpace::exp(localSolution[j],epsEta);
                            
                        if (i==j)
                            backwardSolutionXiEta[i] = TargetSpace::exp(localSolution[i],minusEpsXi+minusEpsEta);
                        else {
                            backwardSolutionXiEta[i] = TargetSpace::exp(localSolution[i],minusEpsXi);
                            backwardSolutionXiEta[j] = TargetSpace::exp(localSolution[j],minusEpsEta);
                        }
                            
                        backwardSolutionXi[i]    = TargetSpace::exp(localSolution[i],minusEpsXi);
                        backwardSolutionEta[j]   = TargetSpace::exp(localSolution[j],minusEpsEta);
    
                        double forwardValue  = energy(element, forwardSolutionXiEta) - energy(element, forwardSolutionXi) - energy(element, forwardSolutionEta);
                        double centerValue   = -energy(element, localSolution);
                        double backwardValue = energy(element, backwardSolutionXiEta) - energy(element, backwardSolutionXi) - energy(element, backwardSolutionEta);
                
                        A_[i][j][i2][j2] = 0.5 * (forwardValue - 2*centerValue + backwardValue) / (eps*eps);
                            
                    }
                }