Skip to content
Snippets Groups Projects
discretekirchhoffbendingisometry.hh 12.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef DUNE_GFE_FUNCTIONS_DISCRETEKIRCHHOFFBENDINGISOMETRY_HH
    #define DUNE_GFE_FUNCTIONS_DISCRETEKIRCHHOFFBENDINGISOMETRY_HH
    
    #include <vector>
    
    #include <dune/common/fvector.hh>
    
    #include <dune/gfe/spaces/productmanifold.hh>
    #include <dune/gfe/spaces/realtuple.hh>
    #include <dune/gfe/spaces/rotation.hh>
    #include <dune/gfe/functions/localisometrycomponentfunction.hh>
    #include <dune/gfe/functions/localprojectedfefunction.hh>
    #include <dune/gfe/bendingisometryhelper.hh>
    #include <dune/gfe/tensor3.hh>
    
    #include <dune/functions/functionspacebases/cubichermitebasis.hh>
    
    namespace Dune::GFE
    {
      /** \brief Interpolate a Discrete Kirchhoff finite element function from a set of RealTuple x Rotation coefficients
       *
       * The Discrete Kirchhoff finite element is a Hermite-type element.
       * The Rotation component of the coefficient set represents the deformation gradient.
       *
       * The class stores both a global coefficient vector 'coefficients_'
       * as well as a local coefficient vector 'localHermiteCoefficients_'
       * that is used for local evaluation after binding to an element.
       *
       *
       * \tparam DiscreteKirchhoffBasis The basis used to compute function values
       * \tparam CoefficientBasis The basis used to index the coefficient vector.
       * \tparam Coefficients The container of global coefficients
       */
      template <class DiscreteKirchhoffBasis, class CoefficientBasis, class Coefficients>
      class DiscreteKirchhoffBendingIsometry
      {
        using GridView = typename DiscreteKirchhoffBasis::GridView;
        using ctype = typename GridView::ctype;
    
      public:
        constexpr static int gridDim = GridView::dimension;
        using Coefficient = typename Coefficients::value_type;
        using RT = typename Coefficient::ctype;
    
        static constexpr int components_ = 3;
    
        typedef Dune::GFE::LocalProjectedFEFunction<GridView::dimension, ctype, typename CoefficientBasis::LocalView::Tree::FiniteElement, Dune::GFE::ProductManifold<RealTuple<RT,components_>, Rotation<RT,components_> > > LocalInterpolationRule;
    
        /** \brief The type used for derivatives */
        typedef Dune::FieldMatrix<RT, components_, gridDim> DerivativeType;
    
        /** \brief The type used for discrete Hessian */
        typedef Tensor3<RT, components_, gridDim, gridDim> discreteHessianType;
    
    
        /** \brief Constructor
         * \param basis An object of Hermite basis type
         * \param coefficientBasis An object of type LagrangeBasis<GridView,1>
         * \param globalIsometryCoefficients Values and derivatives of the function at the Lagrange points
         */
        DiscreteKirchhoffBendingIsometry(const DiscreteKirchhoffBasis& discreteKirchhoffBasis,
                                         const CoefficientBasis& coefficientBasis,
                                         Coefficients& globalIsometryCoefficients)
          : basis_(discreteKirchhoffBasis),
          coefficientBasis_(coefficientBasis),
          localView_(basis_),
          localViewCoefficient_(coefficientBasis_),
          globalIsometryCoefficients_(globalIsometryCoefficients)
        {}
    
        void bind(const typename GridView::template Codim<0>::Entity& element)
        {
          localView_.bind(element);
    
          /** extract the local coefficients from the global coefficient vector */
          std::vector<Coefficient> localIsometryCoefficients;
          getLocalIsometryCoefficients(localIsometryCoefficients,element);
          updateLocalHermiteCoefficients(localIsometryCoefficients,element);
    
          /**
           * @brief  Get Coefficients of the discrete Gradient
           *
           * The discrete Gradient is a special linear combination represented in a [P2]^2 - (Lagrange) space
           * The coefficients of this linear combination correspond to certain linear combinations of the Gradients of
           * the deformation (hermite) basis. The coefficients are stored in the form [Basisfunctions x components x gridDim]
           * in a BlockVector<FieldMatrix<RT, 3, gridDim>>.
           */
          Impl::discreteGradientCoefficients(discreteJacobianCoefficients_,rotationLFE_,*this,element);
        }
    
        /** bind to an element and update the coefficient member variables for a set of new local coefficients */
        void bind(const typename GridView::template Codim<0>::Entity& element,const Coefficients& newLocalCoefficients)
        {
          this->bind(element);
    
          // Update the global isometry coefficients.
          for (unsigned int vertex=0; vertex<3; ++vertex)
          {
            size_t localIdx = localViewCoefficient_.tree().localIndex(vertex);
            size_t globalIdx = localViewCoefficient_.index(localIdx);
            globalIsometryCoefficients_[globalIdx] = newLocalCoefficients[vertex];
          }
    
          // Update the local hermite coefficients.
          updateLocalHermiteCoefficients(newLocalCoefficients,element);
    
          // After setting a new local configurarion, the coefficients of the discrete Gradient need to be updated as well.
          Impl::discreteGradientCoefficients(discreteJacobianCoefficients_,rotationLFE_,*this,element);
        }
    
        /** \brief The type of the element we are bound to */
        Dune::GeometryType type() const
        {
          return localView_.element().type();
        }
    
    
        /** \brief Evaluate the function */
        auto evaluate(const Dune::FieldVector<ctype, gridDim>& local) const
        {
          const auto &localFiniteElement = localView_.tree().child(0).finiteElement();
    
          // Evaluate the shape functions
          std::vector<FieldVector<double, 1> > values;
          localFiniteElement.localBasis().evaluateFunction(local, values);
    
          FieldVector<RT,components_> result(0);
    
          for(size_t i=0; i<localFiniteElement.size(); i++)
            result.axpy(values[i][0], localHermiteCoefficients_[i]);
    
          return (RealTuple<RT, components_>)result;
        }
    
        /** \brief Evaluate the derivative of the function */
        DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, gridDim>& local) const
        {
          const auto &localFiniteElement = localView_.tree().child(0).finiteElement();
    
          const auto jacobianInverse = localView_.element().geometry().jacobianInverse(local);
          std::vector<FieldMatrix<double,1,gridDim> > jacobianValues;
          localFiniteElement.localBasis().evaluateJacobian(local, jacobianValues);
          for (size_t i = 0; i<jacobianValues.size(); i++)
            jacobianValues[i] = jacobianValues[i] * jacobianInverse;
    
          DerivativeType result(0);
    
          for(size_t i=0; i<localFiniteElement.size(); i++)
            for (unsigned int k = 0; k<components_; k++)
              for (unsigned int j = 0; j<gridDim; ++j)
                result[k][j] += (jacobianValues[i][0][j] * localHermiteCoefficients_[i][k]);
    
          return result;
        }
    
        /** \brief Evaluate the derivative of the function, if you happen to know the function value (much faster!)
         *        \param local Local coordinates in the reference element where to evaluate the derivative
         *        \param q Value of the local gfe function at 'local'.  If you provide something wrong here the result will be wrong, too!
         */
        DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, gridDim>& local,
                                          const Coefficient& q) const
        {
          return evaluateDerivative(local);
        }
    
    
    
        /** \brief Evaluate the discrete gradient operator (This quantity lives in the P2-rotation space) */
        DerivativeType evaluateDiscreteGradient(const Dune::FieldVector<ctype, gridDim>& local) const
        {
          //Get values of the P2-Basis functions on local point
          std::vector<FieldVector<double,1> > basisValues;
          rotationLFE_.localBasis().evaluateFunction(local, basisValues);
    
          DerivativeType discreteGradient(0);
    
          for (int k=0; k<components_; k++)
            for (int l=0; l<gridDim; l++)
              for (std::size_t i=0; i<rotationLFE_.size(); i++)
                discreteGradient[k][l]  += discreteJacobianCoefficients_[i][k][l]*basisValues[i];
    
          return discreteGradient;
        }
    
    
        /** \brief Evaluate the discrete hessian operator (This quantity lives in the P2-rotation space) */
        discreteHessianType evaluateDiscreteHessian(const Dune::FieldVector<ctype, gridDim>& local) const
        {
          // Get gradient values of the P2-Basis functions on local point
          const auto geometryJacobianInverse = localView_.element().geometry().jacobianInverse(local);
          std::vector<FieldMatrix<double,1,gridDim> > gradients;
          rotationLFE_.localBasis().evaluateJacobian(local, gradients);
    
          for (size_t i=0; i< gradients.size(); i++)
            gradients[i] = gradients[i] * geometryJacobianInverse;
    
          discreteHessianType discreteHessian(0);
    
          for (int k=0; k<components_; k++)
            for (int l=0; l<gridDim; l++)
              for (std::size_t i=0; i<rotationLFE_.size(); i++)
              {
                discreteHessian[k][l][0]  += discreteJacobianCoefficients_[i][k][l]*gradients[i][0][0];
                discreteHessian[k][l][1]  += discreteJacobianCoefficients_[i][k][l]*gradients[i][0][1];
              }
    
          return discreteHessian;
        }
    
    
        //! Obtain the grid view that the basis is defined on
        const GridView &gridView() const
        {
          return basis_.gridView();
        }
    
        void updateglobalIsometryCoefficients(const Coefficients& newCoefficients)
        {
          globalIsometryCoefficients_ = newCoefficients;
        }
    
        auto getDiscreteJacobianCoefficients()
        {
          return discreteJacobianCoefficients_;
        }
    
        /**
            Update the local hermite basis coefficient vector
         */
        void updateLocalHermiteCoefficients(const Coefficients& localIsometryCoefficients,const typename GridView::template Codim<0>::Entity& element)
        {
          localViewCoefficient_.bind(element);
    
          //Create a LocalProjected-Finite element from the local coefficients used for interpolation.
          auto P1LagrangeLFE = localViewCoefficient_.tree().finiteElement();
          LocalInterpolationRule localPBfunction(P1LagrangeLFE,localIsometryCoefficients);
    
          /**
              Interpolate into the local hermite space for each component.
           */
          const auto &localHermiteFiniteElement = localView_.tree().child(0).finiteElement();
    
          for(size_t k=0; k<components_; k++)
          {
            std::vector<RT> hermiteComponentCoefficients;
            Dune::GFE::Impl::LocalIsometryComponentFunction<double,LocalInterpolationRule> localIsometryComponentFunction(localPBfunction,k);
    
            localHermiteFiniteElement.localInterpolation().interpolate(localIsometryComponentFunction,hermiteComponentCoefficients);
    
            for(size_t i=0; i<localHermiteFiniteElement.size(); i++)
              localHermiteCoefficients_[i][k] = hermiteComponentCoefficients[i];
          }
        }
    
        /** Extract the local isometry coefficients. */
        void getLocalIsometryCoefficients(std::vector<Coefficient>& in,const typename GridView::template Codim<0>::Entity& element)
        {
          localViewCoefficient_.bind(element);
    
          in.resize(3);
          for (unsigned int vertex = 0; vertex<3; ++vertex)
          {
            size_t localIdx = localViewCoefficient_.tree().localIndex(vertex);
            size_t globalIdx = localViewCoefficient_.index(localIdx);
            in[vertex] = globalIsometryCoefficients_[globalIdx];
          }
        }
    
        /** \brief Return the representation LocalFiniteElement for the rotation space */
        auto const &getRotationFiniteElement() const
        {
          return rotationLFE_;
        }
    
        /** \brief Return the discrete Jacobian coefficients */
        BlockVector<FieldMatrix<RT, components_, gridDim> > getDiscreteJacobianCoefficients() const
        {
          return discreteJacobianCoefficients_;
        }
    
        /** \brief Get the i'th base coefficient. */
        Coefficients coefficient(int i) const
        {
          return globalIsometryCoefficients_[i];
        }
    
      private:
    
        /** \brief The Lagrange basis used to assign manifold-valued degrees of freedom */
        const CoefficientBasis& coefficientBasis_;
    
        /** \brief The hermite basis used to represent deformations */
        const DiscreteKirchhoffBasis& basis_;
    
        /** \brief LocalFiniteElement (P2-Lagrange) used to represent the discrete Jacobian (rotation) on the current element. */
        Dune::LagrangeSimplexLocalFiniteElement<ctype, double, gridDim, 2> rotationLFE_;
    
        /** \brief The coefficients of the discrete Gradient/Hessian operator */
        BlockVector<FieldMatrix<RT, components_, gridDim> > discreteJacobianCoefficients_;
    
        mutable typename DiscreteKirchhoffBasis::LocalView localView_;
        mutable typename CoefficientBasis::LocalView localViewCoefficient_;
    
        /** \brief The global coefficient vector */
        Coefficients& globalIsometryCoefficients_;
    
        static constexpr int localHermiteBasisSize_ = Dune::Functions::Impl::CubicHermiteLocalCoefficients<gridDim,true>::size();
    
        /** \brief The local coefficient vector of the hermite basis. */
        std::array<Dune::FieldVector<RT,components_>,localHermiteBasisSize_> localHermiteCoefficients_;
    
      };
    
    }  // end namespace Dune::GFE
    #endif   // DUNE_GFE_FUNCTIONS_DISCRETEKIRCHHOFFBENDINGISOMETRY_HH