Skip to content
Snippets Groups Projects
unitvector.hh 2.69 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef UNIT_VECTOR_HH
    #define UNIT_VECTOR_HH
    
    #include <dune/common/fvector.hh>
    
    template <int dim>
    class UnitVector
    {
    public:
    
    
        /** \brief The type used for coordinates */
        typedef double ctype;
    
    
        typedef Dune::FieldVector<double,dim> TangentVector;
        typedef Dune::FieldVector<double,dim> EmbeddedTangentVector;
    
        UnitVector<dim>& operator=(const Dune::FieldVector<double,dim>& vector)
        {
            data_ = vector;
            data_ /= data_.two_norm();
            return *this;
        }
    
    
         /** \brief The exponention map */
        static UnitVector exp(const UnitVector& p, const TangentVector& v) {
    
    
            assert( std::abs(p.data_*v) < 1e-7 );
    
    
            const double norm = v.two_norm();
            UnitVector result = p;
            result.data_ *= std::cos(norm);
            result.data_.axpy(std::sin(norm)/norm, v);
            return result;
        }
    
    
        /** \brief Length of the great arc connecting the two points */
         static double distance(const UnitVector& a, const UnitVector& b) {
            return std::acos(a.data_ * b.data_);
        }
    
    
        /** \brief Compute the gradient of the squared distance function keeping the first argument fixed
    
        Unlike the distance itself the squared distance is differentiable at zero
         */
        static EmbeddedTangentVector derivativeOfDistanceSquaredWRTSecondArgument(const UnitVector& a, const UnitVector& b) {
    
            double x = a.data_ * b.data_;
            const double eps = 1e-12;
    
    
            EmbeddedTangentVector result = a.data_;
    
    
            if (x > 1-eps) {  // regular expression is unstable, use the series expansion instead
                result *= -2 + 2*(x-1)/3 - 4/15*(x-1)*(x-1) + 4/35*(x-1)*(x-1)*(x-1);
            } else {
                result *= -2*std::acos(x) / std::sqrt(1-x*x);
            }
    
            // Project gradient onto the tangent plane at b in order to obtain the surface gradient
    
            result = b.projectOntoTangentSpace(result);
    
    
            // Gradient must be a tangent vector at b, in other words, orthogonal to it
            assert( std::abs(b.data_ * result) < 1e-7);
    
    
        /** \brief Project tangent vector of R^n onto the tangent space */
        EmbeddedTangentVector projectOntoTangentSpace(const EmbeddedTangentVector& v) const {
            EmbeddedTangentVector result = v;
            result.axpy(-1*(data_*result), data_);
            return result;
        }
    
    
        /** \brief The global coordinates, if you really want them */
        const Dune::FieldVector<double,dim>& globalCoordinates() const {
            return data_;
        }
    
    
        /** \brief Write LocalKey object to output stream */
        friend std::ostream& operator<< (std::ostream& s, const UnitVector& unitVector)
        {
            return s << unitVector.data_;
        }
    
    
    private:
    
        Dune::FieldVector<double,dim> data_;
    };
    
    #endif