Skip to content
Snippets Groups Projects
localquickanddirtyfefunction.hh 5.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef DUNE_GFE_LOCALQUICKANDDIRTYFEFUNCTION_HH
    #define DUNE_GFE_LOCALQUICKANDDIRTYFEFUNCTION_HH
    
    #include <vector>
    
    #include <dune/common/fvector.hh>
    
    #include <dune/geometry/type.hh>
    
    #include <dune/gfe/rotation.hh>
    #include <dune/gfe/linearalgebra.hh>
    
    namespace Dune {
    
      namespace GFE {
    
        /** \brief Interpolate on a manifold, as fast as we can
         *
         * This class implements interpolation of values on a manifold in a 'quick-and-dirty' way.
         * No particular interpolation rule is used consistenly for all manifolds.  Rather, it is
         * used whatever is quickest and 'reasonable' for any given space.  The reason to have this
         * is to provide initial iterates for the iterative solvers used to solve the local
         * geodesic-FE minimization problems.
         *
         * \note In particular, we currently do not implement the derivative of the interpolation,
         *   because it is not needed for producing initial iterates!
         *
         * \tparam dim Dimension of the reference element
         * \tparam ctype Type used for coordinates on the reference element
         * \tparam LocalFiniteElement A Lagrangian finite element whose shape functions define the interpolation weights
         * \tparam TargetSpace The manifold that the function takes its values in
         */
        template <int dim, class ctype, class LocalFiniteElement, class TS>
        class LocalQuickAndDirtyFEFunction
        {
        public:
          using TargetSpace=TS;
        private:
          typedef typename TargetSpace::ctype RT;
    
          typedef typename TargetSpace::EmbeddedTangentVector EmbeddedTangentVector;
          static const int embeddedDim = EmbeddedTangentVector::dimension;
    
          static const int spaceDim = TargetSpace::TangentVector::dimension;
    
        public:
    
          /** \brief The type used for derivatives */
          typedef Dune::FieldMatrix<RT, embeddedDim, dim> DerivativeType;
    
          /** \brief Constructor
           * \param localFiniteElement A Lagrangian finite element that provides the interpolation points
           * \param coefficients Values of the function at the Lagrange points
           */
          LocalQuickAndDirtyFEFunction(const LocalFiniteElement& localFiniteElement,
                                   const std::vector<TargetSpace>& coefficients)
          : localFiniteElement_(localFiniteElement),
          coefficients_(coefficients)
          {
            assert(localFiniteElement_.localBasis().size() == coefficients_.size());
          }
    
          /** \brief The number of Lagrange points */
          unsigned int size() const
          {
            return localFiniteElement_.localBasis().size();
          }
    
          /** \brief The type of the reference element */
          Dune::GeometryType type() const
          {
            return localFiniteElement_.type();
          }
    
          /** \brief Evaluate the function */
          TargetSpace evaluate(const Dune::FieldVector<ctype, dim>& local) const;
    
          /** \brief Get the i'th base coefficient. */
          TargetSpace coefficient(int i) const
          {
            return coefficients_[i];
          }
        private:
    
          /** \brief The scalar local finite element, which provides the weighting factors
           *        \todo We really only need the local basis
           */
          const LocalFiniteElement& localFiniteElement_;
    
          /** \brief The coefficient vector */
          std::vector<TargetSpace> coefficients_;
    
        };
    
        template <int dim, class ctype, class LocalFiniteElement, class TargetSpace>
        TargetSpace LocalQuickAndDirtyFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>::
        evaluate(const Dune::FieldVector<ctype, dim>& local) const
        {
          // Evaluate the weighting factors---these are the Lagrangian shape function values at 'local'
          std::vector<Dune::FieldVector<ctype,1> > w;
          localFiniteElement_.localBasis().evaluateFunction(local,w);
    
    
          // Special-casing for the Rotations.  This is quite a challenge:
          //
          // Projection-based interpolation in the
          // unit quaternions is not a good idea, here, because you may end up on the
          // wrong sheet of the covering of SO(3) by the unit quaternions.  The minimization
          // solver for the weighted distance functional may then actually converge
          // to the wrong local minimizer -- the interpolating functions wraps "the wrong way"
          // around SO(3).
          //
          // Projection-based interpolation in SO(3) is not a good idea, because it is about as
          // expensive as the geodesic interpolation itself.  That's not good if all we want
          // is an initial iterate.
          //
          // Averaging in R^{3x3} followed by QR decomposition is not a good idea either:
          // The averaging can give you singular matrices quite quickly (try two matrices that
          // differ by a rotation of pi/2).  Then, the QR factorization of the identity may
          // not be the identity (but differ in sign)!  I tried that with the implementation
          // from Numerical recipies.
          //
          // What do we do instead?  We start from the coefficient that produces the lowest
          // value of the objective functional.
          if constexpr (std::is_same<TargetSpace,Rotation<double,3> >::value)
          {
            AverageDistanceAssembler averageDistance(coefficients_,w);
    
            auto minDistance = averageDistance.value(coefficients_[0]);
            std::size_t minCoefficient = 0;
    
            for (std::size_t i=1; i<coefficients_.size(); i++)
            {
              auto distance = averageDistance.value(coefficients_[i]);
              if (distance < minDistance)
              {
                minDistance = distance;
                minCoefficient = i;
              }
            }
    
            return coefficients_[minCoefficient];
          }
          else
          {
            typename TargetSpace::CoordinateType c(0);
            for (size_t i=0; i<coefficients_.size(); i++)
              c.axpy(w[i][0], coefficients_[i].globalCoordinates());