Skip to content
Snippets Groups Projects
Forked from agnumpde / dune-fufem
367 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
p3nodalbasis.hh 8.65 KiB
#ifndef P3_NODALBASIS_HH
#define P3_NODALBASIS_HH

/*
#warning This file is deprecated.  All implementations of function space bases in dune-fufem \
  are in the process of being replaced by counterparts in the new dune-functions module. \
  Those are syntactically different, but semantically very close to the dune-fufem implementations. \
  To get rid of this warning, replace all occurrences of the Q1NodalBasis<...> class in your code \
  by DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<...,3> >.
*/

/**
   @file
   @brief The nodal basis for the space of 3rd-order Lagrangian finite elements

   @author Oliver Sander
 */


#include <dune/geometry/type.hh>
#include <dune/geometry/referenceelements.hh>
#include <dune/common/typetraits.hh>
#include <dune/grid/common/mcmgmapper.hh>
#include <dune/localfunctions/lagrange/pqkfactory.hh>

#include <dune/fufem/functionspacebases/functionspacebasis.hh>

/** \brief The nodal basis for the space of 3rd-order Lagrangian finite elements
 *
 * The main task of this class is to assign global indices to the local degrees of
 * freedom of a given element.  A P3 Lagrangian FE space has
 * - 1 dof per vertex
 * - 2 dofs per edge
 * - 1 dof per triangle
 * - 4 dofs per quadrilateral
 * - 0 dofs per tetrahedron
 * - 1 dof per pyramid
 * - 2 dofs per prism
 * - 8 dofs per hexahedron
 *
 * \tparam GV Grid view that the FE space is defined on
 * \tparam RT Value type of the shape functions
 */
template <class GV, class RT=double>
class P3NodalBasis :
    public FunctionSpaceBasis<
        GV,
        RT,
        typename Dune::PQkLocalFiniteElementCache<typename GV::Grid::ctype, RT, GV::dimension, 3>::FiniteElementType >
{
    protected:
        typedef typename GV::Grid::ctype ctype;

        typedef typename Dune::PQkLocalFiniteElementCache<typename GV::Grid::ctype, RT, GV::dimension, 3> FiniteElementCache;
        typedef typename FiniteElementCache::FiniteElementType LFE;

        typedef FunctionSpaceBasis<GV, RT, LFE> Base;
        typedef typename Base::Element Element;

        /** \brief Dimension of the grid */
        using Base::dim;
        using Base::gridview_;

    public:
        typedef typename Base::GridView GridView;
        typedef typename Base::ReturnType ReturnType;
        typedef typename Base::LocalFiniteElement LocalFiniteElement;
        typedef typename Base::LinearCombination LinearCombination;

        /** \brief Constructor for a given grid view */
        P3NodalBasis(const GridView& gridview) :
            Base(gridview)
        {
            updateMapper();
        }

        /** \brief The number of degrees of freedom of the function space */
        size_t size() const
        {
            switch (dim) {
                case 1:
                    // One for each vertex, and two for each element
                    return gridview_.size(1) + 2*gridview_.size(0);
                case 2: {
                    Dune::GeometryType triangle = Dune::GeometryTypes::triangle;
                    Dune::GeometryType quad = Dune::GeometryTypes::quadrilateral;
                    // One for each vertex, two for each edge,
                    // one for each triangle element, four for each quad element
                    return gridview_.size(dim) + 2*gridview_.size(1)
                         + gridview_.size(triangle) + 4*gridview_.size(quad);
                }
                case 3: {
                    Dune::GeometryType triangle = Dune::GeometryTypes::triangle;
                    Dune::GeometryType quad = Dune::GeometryTypes::quadrilateral;
                    Dune::GeometryType pyramid = Dune::GeometryTypes::pyramid;
                    Dune::GeometryType prism = Dune::GeometryTypes::prism;
                    Dune::GeometryType hexahedron = Dune::GeometryTypes::cube(3);
                    // One for each vertex, two for each edge,
                    // one for each triangle element, four for each quad element
                    return gridview_.size(dim) + 2*gridview_.size(2)
                         + gridview_.size(triangle) + 4*gridview_.size(quad)
                         + gridview_.size(pyramid) + 2*gridview_.size(prism) + 8*gridview_.size(hexahedron);
                }

                default:
                    DUNE_THROW(Dune::NotImplemented, "No size method for " << dim << "d grids available yet!");
            }
            return 0;
        }

        void update(const GridView& gridview)
        {
            Base::update(gridview);
            updateMapper();
        }

        /** \brief Get the local finite element for a given grid element */
        const LocalFiniteElement& getLocalFiniteElement(const Element& e) const
        {
            return cache_.get(e.type());
        }

        /** \brief Get the global index for the i-th local index on the given element */
        int index(const Element& e, const int i) const
        {
            Dune::LocalKey localKey = cache_.get(e.type()).localCoefficients().localKey(i);
            const typename GridView::IndexSet& indexSet = gridview_.indexSet();

            // The dimension of the entity that the current dof is related to
            size_t dofDim = dim - localKey.codim();

            if (dofDim==0) {  // vertex dof
                return indexSet.subIndex(e,localKey.subEntity(),dim);
            }

            if (dofDim==1) {  // edge dof
                if (dim==1)   // element dof -- any local numbering is fine
                    return edgeOffset_ + 2*indexSet.subIndex(e,0,0) + localKey.index();
                else {
                    const auto& refElement = Dune::ReferenceElements<double,dim>::general(e.type());

                    // we have to reverse the numbering if the local triangle edge is
                    // not aligned with the global edge
                    //
                    // This use of ReferenceElement::subEntity is OK, because
                    // the local finite element is defined on the reference element
                    // and hence the local keys correspond to the subentity embedding
                    // of the reference element.
                    size_t v0 = indexSet.subIndex(e,refElement.subEntity(localKey.subEntity(),localKey.codim(),0,dim),dim);
                    size_t v1 = indexSet.subIndex(e,refElement.subEntity(localKey.subEntity(),localKey.codim(),1,dim),dim);
                    bool flip = (v0 > v1);
                    return (flip)
                           ? edgeOffset_ + 2*indexSet.subIndex(e,localKey.subEntity(),localKey.codim()) + 1-localKey.index()
                           : edgeOffset_ + 2*indexSet.subIndex(e,localKey.subEntity(),localKey.codim()) + localKey.index();

                }
            }

            if (dofDim==2) {
                if (dim==2) {  // element dof -- any local numbering is fine
                    if (e.type().isTriangle())
                        return triangleOffset_ + 1*indexSet.subIndex(e,0,0) + localKey.index();
                    else if (e.type().isQuadrilateral())
                        return quadrilateralOffset_ + 4*indexSet.subIndex(e,0,0) + localKey.index();
                    else
                        DUNE_THROW(Dune::NotImplemented, "2d elements have to be triangles or quadrilaterals");
                } else {
                    const auto& refElement = Dune::ReferenceElements<double,dim>::general(e.type());

                    assert(refElement.type(localKey.subEntity(), localKey.codim()).isTriangle());
                    return triangleOffset_ + indexSet.subIndex(e,localKey.subEntity(),localKey.codim());
                }
            }
            return 0;
        }

    protected:

        void updateMapper()
        {
            vertexOffset_        = 0;
            edgeOffset_          = vertexOffset_        + gridview_.size(dim);
            triangleOffset_      = edgeOffset_          + 2*gridview_.size(dim-1);

            quadrilateralOffset_ = triangleOffset_  + 1*gridview_.size(Dune::GeometryTypes::triangle);

            if (dim==3) {
                tetrahedronOffset_   = quadrilateralOffset_ + 4*gridview_.size(Dune::GeometryTypes::quadrilateral);
                pyramidOffset_       = tetrahedronOffset_   +   0*gridview_.size(Dune::GeometryTypes::tetrahedron);
                prismOffset_         = tetrahedronOffset_   +   1*gridview_.size(Dune::GeometryTypes::pyramid);
                hexahedronOffset_    = tetrahedronOffset_   +   2*gridview_.size(Dune::GeometryTypes::prism);
            }
        }

        FiniteElementCache cache_;

        size_t vertexOffset_;
        size_t edgeOffset_;
        size_t triangleOffset_;
        size_t quadrilateralOffset_;
        size_t tetrahedronOffset_;
        size_t pyramidOffset_;
        size_t prismOffset_;
        size_t hexahedronOffset_;
};

#endif