From afd79096e3dff81c904c02151270d7794fd67659 Mon Sep 17 00:00:00 2001 From: Oliver Sander <oliver.sander@tu-dresden.de> Date: Mon, 8 Feb 2016 14:01:10 +0100 Subject: [PATCH] Allow the possibility to have a periodic 1d function space if the grid is 1d --- dune/gfe/periodic1dpq1nodalbasis.hh | 256 ++++++++++++++++++++++++++++ src/gradient-flow.cc | 2 + 2 files changed, 258 insertions(+) create mode 100644 dune/gfe/periodic1dpq1nodalbasis.hh diff --git a/dune/gfe/periodic1dpq1nodalbasis.hh b/dune/gfe/periodic1dpq1nodalbasis.hh new file mode 100644 index 00000000..df31bc5a --- /dev/null +++ b/dune/gfe/periodic1dpq1nodalbasis.hh @@ -0,0 +1,256 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_GFE_PERIODIC_1D_PQ1NODALBASIS_HH +#define DUNE_GFE_PERIODIC_1D_PQ1NODALBASIS_HH + +#include <dune/common/exceptions.hh> + +#include <dune/localfunctions/lagrange/pqkfactory.hh> + +#include <dune/typetree/leafnode.hh> + +#include <dune/functions/functionspacebases/nodes.hh> +#include <dune/functions/functionspacebases/defaultglobalbasis.hh> +#include <dune/functions/functionspacebases/flatmultiindex.hh> + + +namespace Dune { +namespace Functions { + +// ***************************************************************************** +// This is the reusable part of the basis. It contains +// +// PQ1NodeFactory +// PQ1NodeIndexSet +// PQ1Node +// +// The factory allows to create the others and is the owner of possible shared +// state. These three components do _not_ depend on the global basis or index +// set and can be used without a global basis. +// ***************************************************************************** + +template<typename GV, typename ST, typename TP> +class Periodic1DPQ1Node; + +template<typename GV, class MI, class TP, class ST> +class Periodic1DPQ1NodeIndexSet; + +template<typename GV, class MI, class ST> +class Periodic1DPQ1NodeFactory; + +template<typename GV, class MI, class ST> +class Periodic1DPQ1NodeFactory +{ + static const int dim = GV::dimension; + +public: + + /** \brief The grid view that the FE space is defined on */ + using GridView = GV; + using size_type = ST; + + template<class TP> + using Node = Periodic1DPQ1Node<GV, size_type, TP>; + + template<class TP> + using IndexSet = Periodic1DPQ1NodeIndexSet<GV, MI, TP, ST>; + + /** \brief Type used for global numbering of the basis vectors */ + using MultiIndex = MI; + + using SizePrefix = Dune::ReservedVector<size_type, 2>; + + /** \brief Constructor for a given grid view object */ + Periodic1DPQ1NodeFactory(const GridView& gv) : + gridView_(gv) + {} + + void initializeIndices() + {} + + /** \brief Obtain the grid view that the basis is defined on + */ + const GridView& gridView() const + { + return gridView_; + } + + template<class TP> + Node<TP> node(const TP& tp) const + { + return Node<TP>{tp}; + } + + template<class TP> + IndexSet<TP> indexSet() const + { + return IndexSet<TP>{*this}; + } + + size_type size() const + { + return gridView_.size(dim)-1; + } + + //! Return number possible values for next position in multi index + size_type size(const SizePrefix prefix) const + { + if (prefix.size() == 0) + return size(); + if (prefix.size() == 1) + return 0; + DUNE_THROW(RangeError, "Method size() can only be called for prefixes of length up to one"); + } + + /** \todo This method has been added to the interface without prior discussion. */ + size_type dimension() const + { + return size()-1; + } + + size_type maxNodeSize() const + { + return StaticPower<2,GV::dimension>::power; + } + +//protected: + const GridView gridView_; +}; + + + +template<typename GV, typename ST, typename TP> +class Periodic1DPQ1Node : + public LeafBasisNode<ST, TP> +{ + static const int dim = GV::dimension; + static const int maxSize = StaticPower<2,GV::dimension>::power; + + using Base = LeafBasisNode<ST,TP>; + using FiniteElementCache = typename Dune::PQkLocalFiniteElementCache<typename GV::ctype, double, dim, 1>; + +public: + + using size_type = ST; + using TreePath = TP; + using Element = typename GV::template Codim<0>::Entity; + using FiniteElement = typename FiniteElementCache::FiniteElementType; + + Periodic1DPQ1Node(const TreePath& treePath) : + Base(treePath), + finiteElement_(nullptr), + element_(nullptr) + {} + + //! Return current element, throw if unbound + const Element& element() const + { + return *element_; + } + + /** \brief Return the LocalFiniteElement for the element we are bound to + * + * The LocalFiniteElement implements the corresponding interfaces of the dune-localfunctions module + */ + const FiniteElement& finiteElement() const + { + return *finiteElement_; + } + + //! Bind to element. + void bind(const Element& e) + { + element_ = &e; + finiteElement_ = &(cache_.get(element_->type())); + this->setSize(finiteElement_->size()); + } + +protected: + + FiniteElementCache cache_; + const FiniteElement* finiteElement_; + const Element* element_; +}; + + + +template<typename GV, class MI, class TP, class ST> +class Periodic1DPQ1NodeIndexSet +{ + enum {dim = GV::dimension}; + +public: + + using size_type = ST; + + /** \brief Type used for global numbering of the basis vectors */ + using MultiIndex = MI; + + using NodeFactory = Periodic1DPQ1NodeFactory<GV, MI, ST>; + + using Node = typename NodeFactory::template Node<TP>; + + Periodic1DPQ1NodeIndexSet(const NodeFactory& nodeFactory) : + nodeFactory_(&nodeFactory) + {} + + /** \brief Bind the view to a grid element + * + * Having to bind the view to an element before being able to actually access any of its data members + * offers to centralize some expensive setup code in the 'bind' method, which can save a lot of run-time. + */ + void bind(const Node& node) + { + node_ = &node; + } + + /** \brief Unbind the view + */ + void unbind() + { + node_ = nullptr; + } + + /** \brief Size of subtree rooted in this node (element-local) + */ + size_type size() const + { + return node_->finiteElement().size(); + } + + //! Maps from subtree index set [0..size-1] to a globally unique multi index in global basis + MultiIndex index(size_type i) const + { + Dune::LocalKey localKey = node_->finiteElement().localCoefficients().localKey(i); + const auto& gridIndexSet = nodeFactory_->gridView().indexSet(); + const auto& element = node_->element(); + + //return {{ gridIndexSet.subIndex(element,localKey.subEntity(),dim) }}; + + MultiIndex idx{{gridIndexSet.subIndex(element,localKey.subEntity(),dim) }}; + + // make periodic + if (idx == gridIndexSet.size(dim)-1) + idx = {{0}}; + + return idx; + } + +protected: + const NodeFactory* nodeFactory_; + + const Node* node_; +}; + +/** \brief Nodal basis of a scalar first-order Lagrangian finite element space + * + * \tparam GV The GridView that the space is defined on + * \tparam ST The type used for local indices; global indices are FlatMultiIndex<ST> + */ +template<typename GV, class ST = std::size_t> +using Periodic1DPQ1NodalBasis = DefaultGlobalBasis<Periodic1DPQ1NodeFactory<GV, FlatMultiIndex<ST>, ST> >; + +} // end namespace Functions +} // end namespace Dune + +#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_PQ1NODALBASIS_HH diff --git a/src/gradient-flow.cc b/src/gradient-flow.cc index 57de84e0..957881a7 100644 --- a/src/gradient-flow.cc +++ b/src/gradient-flow.cc @@ -44,6 +44,7 @@ #include <dune/gfe/harmonicenergystiffness.hh> #include <dune/gfe/l2distancesquaredenergy.hh> #include <dune/gfe/weightedsumenergy.hh> +#include <dune/gfe/periodic1dpq1nodalbasis.hh> // grid dimension const int dim = 1; @@ -142,6 +143,7 @@ int main (int argc, char *argv[]) try ////////////////////////////////////////////////////////////////////////////////// typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView, order> FEBasis; + //typedef Dune::Functions::Periodic1DPQ1NodalBasis<typename GridType::LeafGridView> FEBasis; FEBasis feBasis(grid->leafGridView()); /////////////////////////////////////////// -- GitLab