// ---------------------------------------------------------------------
//
// Copyright (C) 2005 - 2018 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#ifndef dealii_hp_dof_handler_h
#define dealii_hp_dof_handler_h



#include <deal.II/base/config.h>
#include <deal.II/base/exceptions.h>
#include <deal.II/base/template_constraints.h>
#include <deal.II/base/smartpointer.h>
#include <deal.II/base/iterator_range.h>
#include <deal.II/dofs/function_map.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_iterator_selector.h>
#include <deal.II/dofs/number_cache.h>
#include <deal.II/hp/fe_collection.h>
#include <deal.II/hp/dof_faces.h>
#include <deal.II/hp/dof_level.h>

#include <vector>
#include <map>
#include <set>

DEAL_II_NAMESPACE_OPEN

template <int dim, int spacedim> class Triangulation;

namespace internal
{
  namespace DoFHandlerImplementation
  {
    struct Implementation;

    namespace Policy
    {
      template <int dim, int spacedim> class PolicyBase;
      struct Implementation;
    }
  }

  namespace hp
  {
    class DoFLevel;

    namespace DoFHandlerImplementation
    {
      struct Implementation;
    }
  }
}

namespace internal
{
  namespace DoFAccessorImplementation
  {
    struct Implementation;
  }

  namespace DoFCellAccessorImplementation
  {
    struct Implementation;
  }
}



namespace hp
{

  /**
   * Manage the distribution and numbering of the degrees of freedom for hp-
   * FEM algorithms. This class satisfies the
   * @ref ConceptMeshType "MeshType concept"
   * requirements.
   *
   * The purpose of this class is to allow for an enumeration of degrees of
   * freedom in the same way as the ::DoFHandler class, but it allows to use a
   * different finite element on every cell. To this end, one assigns an
   * <code>active_fe_index</code> to every cell that indicates which element
   * within a collection of finite elements (represented by an object of type
   * hp::FECollection) is the one that lives on this cell. The class then
   * enumerates the degree of freedom associated with these finite elements on
   * each cell of a triangulation and, if possible, identifies degrees of
   * freedom at the interfaces of cells if they match. If neighboring cells
   * have degrees of freedom along the common interface that do not immediate
   * match (for example, if you have $Q_2$ and $Q_3$ elements meeting at a
   * common face), then one needs to compute constraints to ensure that the
   * resulting finite element space on the mesh remains conforming.
   *
   * The whole process of working with objects of this type is explained in
   * step-27. Many of the algorithms this class implements are described in
   * the
   * @ref hp_paper "hp paper".
   *
   *
   * <h3>Active FE indices and their behavior under mesh refinement</h3>
   *
   * The typical workflow for using this class is to create a mesh, assign an
   * active FE index to every active cell, calls
   * hp::DoFHandler::distribute_dofs(), and then assemble a linear system and
   * solve a problem on this finite element space. However, one can skip
   * assigning active FE indices upon mesh refinement in certain
   * circumstances. In particular, the following rules apply:
   * - Upon mesh refinement, child cells inherit the active FE index of
   *   the parent.
   * - On the other hand, when coarsening cells, the (now active)
   *   parent cell will not have an active FE index set and you will
   *   have to set it explicitly before calling
   *   hp::DoFHandler::distribute_dofs(). In particular, to avoid
   *   stale information to be used by accident, this class deletes
   *   the active FE index of cells that are refined after inheriting
   *   this index to the children; this implies that if the children
   *   are coarsened away, the old value is no longer available on the
   *   parent cell.
   *
   *
   * <h3>Active FE indices and parallel meshes</h3>
   *
   * When this class is used with either a parallel::shared::Triangulation
   * or a parallel::distributed::Triangulation, you can only set active
   * FE indices on cells that are locally owned,
   * using a call such as <code>cell-@>set_active_fe_index(...)</code>.
   * On the other hand, setting the active FE index on ghost
   * or artificial cells is not allowed.
   *
   * Ghost cells do acquire the information what element
   * is active on them, however: whenever
   * you call hp::DoFHandler::distribute_dofs(), all processors that
   * participate in the parallel mesh exchange information in such a way
   * that the active FE index on ghost cells equals the active FE index
   * that was set on that processor that owned that particular ghost cell.
   * Consequently, one can <i>query</i> the @p active_fe_index on ghost
   * cells, just not set it by hand.
   *
   * On artificial cells, no information is available about the
   * @p active_fe_index used there. That's because we don't even know
   * whether these cells exist at all, and even if they did, the
   * current processor does not know anything specific about them.
   * See
   * @ref GlossArtificialCell "the glossary entry on artificial cells"
   * for more information.
   *
   *
   * @ingroup dofs
   * @ingroup hp
   *
   * @author Wolfgang Bangerth, Oliver Kayser-Herold, 2003, 2004, 2017
   */
  template <int dim, int spacedim=dim>
  class DoFHandler : public Subscriptor
  {
    typedef dealii::internal::DoFHandlerImplementation::Iterators<DoFHandler<dim,spacedim>, false> ActiveSelector;
    typedef dealii::internal::DoFHandlerImplementation::Iterators<DoFHandler<dim,spacedim>, true> LevelSelector;
  public:
    typedef typename ActiveSelector::CellAccessor         cell_accessor;
    typedef typename ActiveSelector::FaceAccessor         face_accessor;

    typedef typename ActiveSelector::line_iterator        line_iterator;
    typedef typename ActiveSelector::active_line_iterator active_line_iterator;

    typedef typename ActiveSelector::quad_iterator        quad_iterator;
    typedef typename ActiveSelector::active_quad_iterator active_quad_iterator;

    typedef typename ActiveSelector::hex_iterator         hex_iterator;
    typedef typename ActiveSelector::active_hex_iterator  active_hex_iterator;

    /**
     * @copydoc ::DoFHandler::active_cell_iterator
     * @ingroup Iterators
     */
#ifndef _MSC_VER
    typedef typename ActiveSelector::active_cell_iterator active_cell_iterator;
#else
    typedef TriaActiveIterator < dealii::DoFCellAccessor < DoFHandler < dim, spacedim >, false > > active_cell_iterator;
#endif

    typedef typename LevelSelector::cell_iterator         level_cell_iterator;

    /**
     * @copydoc ::DoFHandler::cell_iterator
     * @ingroup Iterators
     */
#ifndef _MSC_VER
    typedef typename ActiveSelector::cell_iterator        cell_iterator;
#else
    typedef TriaIterator < dealii::DoFCellAccessor < DoFHandler < dim, spacedim >, false > >        cell_iterator;
#endif

    /**
     * @copydoc ::DoFHandler::face_iterator
     * @ingroup Iterators
     */
    typedef typename ActiveSelector::face_iterator        face_iterator;

    /**
     * @copydoc ::DoFHandler::active_face_iterator
     * @ingroup Iterators
     */
    typedef typename ActiveSelector::active_face_iterator active_face_iterator;

    typedef typename LevelSelector::CellAccessor          level_cell_accessor;
    typedef typename LevelSelector::FaceAccessor          level_face_accessor;

    typedef typename LevelSelector::face_iterator         level_face_iterator;

    /**
     * Make the dimension available in function templates.
     */
    static const unsigned int dimension = dim;

    /**
     * Make the space dimension available in function templates.
     */
    static const unsigned int space_dimension = spacedim;

    /**
     * When the arrays holding the DoF indices are set up, but before they are
     * filled with actual values, they are set to an invalid value, in order
     * to monitor possible problems. This invalid value is the constant
     * defined here.
     *
     * Please note that you should not rely on it having a certain value, but
     * rather take its symbolic name.
     *
     * @deprecated Use numbers::invalid_dof_index instead.
     */
    DEAL_II_DEPRECATED
    static const types::global_dof_index invalid_dof_index = numbers::invalid_dof_index;

    /**
     * The default index of the finite element to be used on a given cell. For
     * the usual, non-hp dealii::DoFHandler class that only supports the same
     * finite element to be used on all cells, the index of the finite element
     * needs to be the same on all cells anyway, and by convention we pick
     * zero for this value. The situation here is different, since the hp
     * classes support the case where different finite element indices may be
     * used on different cells. The default index consequently corresponds to
     * an invalid value.
     */
    static const unsigned int default_fe_index = numbers::invalid_unsigned_int;


    /**
     * Default Constructor.
     */
    DoFHandler ();

    /**
     * Constructor. Take @p tria as the triangulation to work on.
     */
    DoFHandler (const Triangulation<dim,spacedim> &tria);

    /**
     * Copy constructor. DoFHandler objects are large and expensive.
     * They should not be copied, in particular not by accident, but
     * rather deliberately constructed. As a consequence, this constructor
     * is explicitly removed from the interface of this class.
     */
    DoFHandler (const DoFHandler &) = delete;

    /**
     * Destructor.
     */
    virtual ~DoFHandler ();

    /**
     * Copy operator. DoFHandler objects are large and expensive.
     * They should not be copied, in particular not by accident, but
     * rather deliberately constructed. As a consequence, this operator
     * is explicitly removed from the interface of this class.
     */
    DoFHandler &operator = (const DoFHandler &) = delete;

    /**
     * Assign a Triangulation and a FECollection to the DoFHandler and compute
     * the distribution of degrees of freedom over the mesh.
     */
    void initialize(const Triangulation<dim,spacedim> &tria,
                    const hp::FECollection<dim,spacedim> &fe);

    /**
     * Go through the triangulation and "distribute" the degrees of
     * freedoms needed for the given finite element. "Distributing"
     * degrees of freedom involves allocating memory to store the
     * indices on all entities on which degrees of freedom can be
     * located (e.g., vertices, edges, faces, etc.) and to then enumerate
     * all degrees of freedom. In other words, while the mesh and the
     * finite element object by themselves simply define a finite
     * element space $V_h$, the process of distributing degrees of
     * freedom makes sure that there is a basis for this space and that
     * the shape functions of this basis are enumerated in an indexable,
     * predictable way.
     *
     * The exact order in which degrees of freedom on a mesh are
     * ordered, i.e., the order in which basis functions of the finite
     * element space are enumerated, is something that deal.II treats as
     * an implementation detail. By and large, degrees of freedom are
     * enumerated in the same order in which we traverse cells, but you
     * should not rely on any specific numbering. In contrast, if you
     * want a particular ordering, use the functions in namespace
     * DoFRenumbering.
     *
     * @note In accordance with dealii::DoFHandler::distribute_dofs(),
     * this function also makes a copy of the object given as argument.
     */
    virtual void distribute_dofs (const hp::FECollection<dim,spacedim> &fe);

    /**
     * Go through the triangulation and set the active FE indices of all
     * active cells to the values given in @p active_fe_indices.
     */
    void set_active_fe_indices (const std::vector<unsigned int> &active_fe_indices);

    /**
     * Go through the triangulation and store the active FE indices of all
     * active cells to the vector @p active_fe_indices. This vector is
     * resized, if necessary.
     */
    void get_active_fe_indices (std::vector<unsigned int> &active_fe_indices) const;

    /**
     * Clear all data of this object and especially delete the lock this
     * object has to the finite element used the last time when @p
     * distribute_dofs was called.
     */
    virtual void clear ();

    /**
     * Renumber degrees of freedom based on a list of new DoF indices for each
     * of the degrees of freedom.
     *
     * This function is called by the functions in DoFRenumbering function after
     * computing a new ordering of the degree of freedom indices. However, it
     * can of course also be called from user code.
     *
     * @arg new_number This array must have a size equal to the number of
     * degrees of freedom owned by the current processor, i.e. the size must be
     * equal to what n_locally_owned_dofs() returns. If only one processor
     * participates in storing the current mesh, then this equals the total
     * number of degrees of freedom, i.e. the result of n_dofs(). The contents
     * of this array are the new global indices for each freedom listed in the
     * IndexSet returned by locally_owned_dofs(). In the case of a sequential
     * mesh this means that the array is a list of new indices for each of the
     * degrees of freedom on the current mesh. In the case that we have a
     * parallel::shared::Triangulation or
     * parallel::distributed::Triangulation underlying this DoFHandler object,
     * the array is a list of new indices for all the locally owned degrees of
     * freedom, enumerated in the same order as the currently locally owned
     * DoFs. In other words, assume that degree of freedom <code>i</code> is
     * currently locally owned, then
     * <code>new_numbers[locally_owned_dofs().index_within_set(i)]</code>
     * returns the new global DoF index of <code>i</code>. Since the IndexSet of
     * locally_owned_dofs() is complete in the sequential case, the latter
     * convention for the content of the array reduces to the former in the case
     * that only one processor participates in the mesh.
     *
     * @note While it follows from the above, it may be surprising to know that
     *   the <i>number</i> of locally owned degrees of freedom in a parallel
     *   computation is an invariant
     *   under renumbering, even if the <i>indices</i> associated with these
     *   locally owned degrees of freedom are not. At a fundamental level,
     *   this invariant exists because the <i>decision</i> whether a degree of
     *   freedom is locally owned or not has nothing to do with that
     *   degree of freedom's (old or new) index. Indeed, degrees of freedom
     *   are locally owned if they are on a locally owned cell and not on
     *   an interface between cells where the neighboring cell has a lower
     *   @ref GlossSubdomainId "subdomain id". Since both of these conditions
     *   are independent of the index associated with the DoF, a locally
     *   owned degree of freedom will also be locally owned after renumbering.
     *   On the other hand, properties such as whether the set of indices
     *   of locally owned DoFs forms a contiguous range or not
     *   (i.e., whether the locally_owned_dofs() returns an IndexSet object
     *   for which IndexSet::is_contiguous() returns @p true) are of
     *   course affected by the exact renumbering performed here. For example,
     *   while the initial numbering of DoF indices done in distribute_dofs()
     *   yields a contiguous numbering, the renumbering performed by
     *   DoFRenumbering::component_wise() will, in general, not yield
     *   contiguous locally owned DoF indices.
     */
    void renumber_dofs (const std::vector<types::global_dof_index> &new_numbers);

    /**
     * Return the maximum number of degrees of freedom a degree of freedom in
     * the given triangulation with the given finite element may couple with.
     * This is the maximum number of entries per line in the system matrix;
     * this information can therefore be used upon construction of the
     * SparsityPattern object.
     *
     * The returned number is not really the maximum number but an estimate
     * based on the finite element and the maximum number of cells meeting at
     * a vertex. The number holds for the constrained matrix also.
     *
     * As for ::DoFHandler::max_couplings_between_dofs(), the result of this
     * function is often not very accurate for 3d and/or high polynomial
     * degrees. The consequences are discussed in the documentation of the
     * module on
     * @ref Sparsity.
     */
    unsigned int max_couplings_between_dofs () const;

    /**
     * Return the number of degrees of freedom located on the boundary another
     * dof on the boundary can couple with.
     *
     * The number is the same as for @p max_coupling_between_dofs in one
     * dimension less.
     *
     * @note The same applies to this function as to max_couplings_per_dofs()
     * as regards the performance of this function. Think about one of the
     * dynamic sparsity pattern classes instead (see
     * @ref Sparsity).
     */
    unsigned int max_couplings_between_boundary_dofs () const;

    /**
     * @name Cell iterator functions
     */
    /*@{*/
    /**
     * Iterator to the first used cell on level @p level.
     */
    cell_iterator        begin       (const unsigned int level = 0) const;

    /**
     * Iterator to the first active cell on level @p level. If the given level
     * does not contain any active cells (i.e., all cells on this level are
     * further refined, then this function returns
     * <code>end_active(level)</code> so that loops of the kind
     *  @code
     *    for (cell=dof_handler.begin_active(level); cell!=dof_handler.end_active(level); ++cell)
     *      ...
     *  @endcode
     * have zero iterations, as may be expected if there are no active cells
     * on this level.
     */
    active_cell_iterator begin_active(const unsigned int level = 0) const;

    /**
     * Iterator past the end; this iterator serves for comparisons of
     * iterators with past-the-end or before-the-beginning states.
     */
    cell_iterator        end () const;

    /**
     * Return an iterator which is the first iterator not on level. If @p
     * level is the last level, then this returns <tt>end()</tt>.
     */
    cell_iterator        end (const unsigned int level) const;

    /**
     * Return an active iterator which is the first active iterator not on the
     * given level. If @p level is the last level, then this returns
     * <tt>end()</tt>.
     */
    active_cell_iterator end_active (const unsigned int level) const;

    /**
     * @name Cell iterator functions returning ranges of iterators
     */

    /**
     * Return an iterator range that contains all cells (active or not) that
     * make up this DoFHandler. Such a range is useful to initialize range-
     * based for loops as supported by C++11. See the example in the
     * documentation of active_cell_iterators().
     *
     * @return The half open range <code>[this->begin(), this->end())</code>
     *
     * @ingroup CPP11
     */
    IteratorRange<cell_iterator>        cell_iterators () const;

    /**
     * Return an iterator range that contains all active cells that make up
     * this DoFHandler. Such a range is useful to initialize range-based for
     * loops as supported by C++11, see also
     * @ref CPP11 "C++11 standard".
     *
     * Range-based for loops are useful in that they require much less code
     * than traditional loops (see <a
     * href="http://en.wikipedia.org/wiki/C%2B%2B11#Range-
     * based_for_loop">here</a> for a discussion of how they work). An example
     * is that without range-based for loops, one often writes code such as
     * the following:
     * @code
     *   DoFHandler<dim> dof_handler;
     *   ...
     *   typename DoFHandler<dim>::active_cell_iterator
     *     cell = dof_handler.begin_active(),
     *     endc = dof_handler.end();
     *   for (; cell!=endc; ++cell)
     *     {
     *       fe_values.reinit (cell);
     *       ...do the local integration on 'cell'...;
     *     }
     * @endcode
     * Using C++11's range-based for loops, this is now entirely equivalent to
     * the following:
     * @code
     *   DoFHandler<dim> dof_handler;
     *   ...
     *   for (auto cell : dof_handler.active_cell_iterators())
     *     {
     *       fe_values.reinit (cell);
     *       ...do the local integration on 'cell'...;
     *     }
     * @endcode
     *
     * @return The half open range <code>[this->begin_active(),
     * this->end())</code>
     *
     * @ingroup CPP11
     */
    IteratorRange<active_cell_iterator> active_cell_iterators () const;

    /**
     * Return an iterator range that contains all cells (active or not) that
     * make up the given level of this DoFHandler. Such a range is useful to
     * initialize range-based for loops as supported by C++11. See the example
     * in the documentation of active_cell_iterators().
     *
     * @param[in] level A given level in the refinement hierarchy of this
     * triangulation.
     * @return The half open range <code>[this->begin(level),
     * this->end(level))</code>
     *
     * @pre level must be less than this->n_levels().
     *
     * @ingroup CPP11
     */
    IteratorRange<cell_iterator>        cell_iterators_on_level (const unsigned int level) const;

    /**
     * Return an iterator range that contains all active cells that make up
     * the given level of this DoFHandler. Such a range is useful to
     * initialize range-based for loops as supported by C++11. See the example
     * in the documentation of active_cell_iterators().
     *
     * @param[in] level A given level in the refinement hierarchy of this
     * triangulation.
     * @return The half open range <code>[this->begin_active(level),
     * this->end(level))</code>
     *
     * @pre level must be less than this->n_levels().
     *
     * @ingroup CPP11
     */
    IteratorRange<active_cell_iterator> active_cell_iterators_on_level (const unsigned int level) const;

    /*
     * @}
     */

    /*---------------------------------------*/


    /**
     * Return the global number of degrees of freedom. If the current object
     * handles all degrees of freedom itself (even if you may intend to solve
     * your linear system in parallel, such as in step-17 or step-18), then
     * this number equals the number of locally owned degrees of freedom since
     * this object doesn't know anything about what you want to do with it and
     * believes that it owns every degree of freedom it knows about.
     *
     * On the other hand, if this object operates on a
     * parallel::distributed::Triangulation object, then this function returns
     * the global number of degrees of freedom, accumulated over all
     * processors.
     *
     * In either case, included in the returned number are those DoFs which
     * are constrained by hanging nodes, see
     * @ref constraints.
     *
     * Mathematically speaking, the number returned by this function equals the
     * dimension of the finite element space (without taking into account
     * constraints) that corresponds to (i) the mesh on which it is defined,
     * and (ii) the finite element that is used by the current object. It
     * also, of course, equals the number of shape functions that span this
     * space.
     */
    types::global_dof_index n_dofs () const;

    /**
     * The number of multilevel dofs on given level. Since hp::DoFHandler does
     * not support multilevel methods yet, this function throws an exception
     * ExcNotImplemented() independent of its argument.
     */
    types::global_dof_index n_dofs(const unsigned int level) const;

    /**
     * Return the number of degrees of freedom located on the boundary.
     */
    types::global_dof_index n_boundary_dofs () const;

    /**
     * Return the number of degrees of freedom located on those parts of the
     * boundary which have a boundary indicator listed in the given set. The
     * reason that a @p map rather than a @p set is used is the same as
     * described in the documentation of that variant of
     * DoFTools::make_boundary_sparsity_pattern() that takes a map.
     * To this end, the type of the @p boundary_ids argument is the same
     * as typename FunctionMap<spacedim,number>::type.
     *
     * There is, however, another overload of this function that takes
     * a @p set argument (see below).
     */
    template <typename number>
    types::global_dof_index
    n_boundary_dofs (const std::map<types::boundary_id, const Function<spacedim,number>*> &boundary_ids) const;

    /**
     * Return the number of degrees of freedom located on those parts of the
     * boundary which have a boundary indicator listed in the given set. The
     */
    types::global_dof_index
    n_boundary_dofs (const std::set<types::boundary_id> &boundary_ids) const;

    /**
     * Return the number of degrees of freedom that belong to this process.
     *
     * If this is a sequential DoFHandler, then the result equals that produced by
     * n_dofs(). (Here, "sequential" means that either
     * the whole program does not use MPI, or that it uses MPI
     * but only uses a single MPI process, or that there are multiple MPI
     * processes but the Triangulation on which this DoFHandler builds
     * works only on one MPI process.) On the other hand, if we are operating on a
     * parallel::distributed::Triangulation or parallel::shared::Triangulation,
     * then it includes only the degrees
     * of freedom that the current processor owns. Note that in this case this
     * does not include all degrees of freedom that have been distributed on
     * the current processor's image of the mesh: in particular, some of the
     * degrees of freedom on the interface between the cells owned by this
     * processor and cells owned by other processors may be theirs, and
     * degrees of freedom on ghost cells are also not necessarily included.
     */
    types::global_dof_index n_locally_owned_dofs() const;

    /**
     * Return an IndexSet describing the set of locally owned DoFs as a subset
     * of 0..n_dofs(). The number of elements of this set equals
     * n_locally_owned_dofs().
     */
    const IndexSet &locally_owned_dofs() const;

    /**
     * Return a vector that stores the locally owned DoFs of each processor.
     * If you are only interested in the number of elements each processor
     * owns then n_dofs_per_processor() is a better choice.
     *
     * If this is a sequential DoFHandler, then the vector has a single element that
     * equals the IndexSet representing the entire range [0,n_dofs()].
     * (Here, "sequential" means that either
     * the whole program does not use MPI, or that it uses MPI
     * but only uses a single MPI process, or that there are multiple MPI
     * processes but the Triangulation on which this DoFHandler builds
     * works only on one MPI process.)
     */
    const std::vector<IndexSet> &
    locally_owned_dofs_per_processor () const;

    /**
     * Return a vector that stores the number of degrees of freedom each
     * processor that participates in this triangulation owns locally. The sum
     * of all these numbers equals the number of degrees of freedom that exist
     * globally, i.e. what n_dofs() returns.
     *
     * Each element of the vector returned by this function equals the number
     * of elements of the corresponding sets returned by global_dof_indices().
     *
     * If this is a sequential DoFHandler, then the vector has a single element equal
     * to n_dofs(). (Here, "sequential" means that either
     * the whole program does not use MPI, or that it uses MPI
     * but only uses a single MPI process, or that there are multiple MPI
     * processes but the Triangulation on which this DoFHandler builds
     * works only on one MPI process.)
     */
    const std::vector<types::global_dof_index> &
    n_locally_owned_dofs_per_processor () const;

    /**
     * Return an IndexSet describing the set of locally owned DoFs used for
     * the given multigrid level. Since hp::DoFHandler does not support
     * multilevel methods yet, this function throws an exception
     * ExcNotImplemented() independent of its argument.
     */
    const IndexSet &locally_owned_mg_dofs(const unsigned int level) const;

    /**
     * Return a vector that stores the locally owned level DoFs of each
     * processor on the given level @p level. Since hp::DoFHandler does not
     * support multilevel methods yet, this function throws an exception
     * ExcNotImplemented() independent of its argument.
     */
    const std::vector<IndexSet> &
    locally_owned_mg_dofs_per_processor (const unsigned int level) const;

    /**
     * Return a constant reference to the set of finite element objects that
     * are used by this @p DoFHandler.
     *
     * @deprecated Use get_fe_collection() instead.
     */
    DEAL_II_DEPRECATED
    const hp::FECollection<dim,spacedim> &get_fe () const;

    /**
     * Return a constant reference to the indexth finite element object that is
     * used by this @p DoFHandler.
     */
    const FiniteElement<dim,spacedim> &
    get_fe (const unsigned int index) const;

    /**
     * Return a constant reference to the set of finite element objects that
     * are used by this @p DoFHandler.
     */
    const hp::FECollection<dim,spacedim> &get_fe_collection () const;

    /**
     * Return a constant reference to the triangulation underlying this
     * object.
     */
    const Triangulation<dim,spacedim> &get_triangulation () const;

    /**
     * Determine an estimate for the memory consumption (in bytes) of this
     * object.
     *
     * This function is made virtual, since a dof handler object might be
     * accessed through a pointers to this base class, although the actual
     * object might be a derived class.
     */
    virtual std::size_t memory_consumption () const;

    /**
     * Write the data of this object to a stream for the purpose of
     * serialization.
     */
    template <class Archive>
    void save(Archive &ar, const unsigned int version) const;

    /**
     * Read the data of this object from a stream for the purpose of
     * serialization.
     */
    template <class Archive>
    void load(Archive &ar, const unsigned int version);

    BOOST_SERIALIZATION_SPLIT_MEMBER()

    /**
     * Exception
     */
    DeclException0 (ExcNoFESelected);
    /**
     * Exception
     */
    DeclException0 (ExcGridsDoNotMatch);
    /**
     * Exception
     */
    DeclException0 (ExcInvalidBoundaryIndicator);
    /**
     * Exception
     */
    DeclException1 (ExcMatrixHasWrongSize,
                    int,
                    << "The matrix has the wrong dimension " << arg1);
    /**
     * Exception
     */
    DeclException0 (ExcFunctionNotUseful);
    /**
     * Exception
     */
    DeclException1 (ExcNewNumbersNotConsecutive,
                    types::global_dof_index,
                    << "The given list of new dof indices is not consecutive: "
                    << "the index " << arg1 << " does not exist.");
    /**
     * Exception
     */
    DeclException2 (ExcInvalidFEIndex,
                    int, int,
                    << "The mesh contains a cell with an active_fe_index of "
                    << arg1 << ", but the finite element collection only has "
                    << arg2 << " elements");
    /**
     * Exception
     */
    DeclException1 (ExcInvalidLevel,
                    int,
                    << "The given level " << arg1
                    << " is not in the valid range!");
    /**
     * Exception
     */
    DeclException0 (ExcFacesHaveNoLevel);
    /**
     * The triangulation level you accessed is empty.
     */
    DeclException1 (ExcEmptyLevel,
                    int,
                    << "You tried to do something on level " << arg1
                    << ", but this level is empty.");

  private:

    /**
     * Address of the triangulation to work on.
     */
    SmartPointer<const Triangulation<dim,spacedim>,DoFHandler<dim,spacedim> > tria;

    /**
     * Store a copy of the finite element set given latest to distribute_dofs().
     */
    hp::FECollection<dim,spacedim> fe_collection;

    /**
     * An object that describes how degrees of freedom should be distributed and
     * renumbered.
     */
    std::unique_ptr<dealii::internal::DoFHandlerImplementation::Policy::PolicyBase<dim,spacedim> > policy;


    /**
     * Setup policy and listeners based on the underlying Triangulation.
     */
    void setup_policy_and_listeners ();

    /**
     * Free all used memory.
     */
    void clear_space ();

    template <int structdim>
    types::global_dof_index get_dof_index (const unsigned int obj_level,
                                           const unsigned int obj_index,
                                           const unsigned int fe_index,
                                           const unsigned int local_index) const;

    template <int structdim>
    void set_dof_index (const unsigned int obj_level,
                        const unsigned int obj_index,
                        const unsigned int fe_index,
                        const unsigned int local_index,
                        const types::global_dof_index global_index) const;

    /**
     * Create default tables for the active_fe_indices in the
     * dealii::internal::hp::DoFLevel. They are initialized with a zero
     * indicator, meaning that fe[0] is going to be used by default.  This
     * method is called before refinement and before distribute_dofs is
     * called. It ensures each cell has a valid active_fe_index.
     */
    void create_active_fe_table ();

    /**
     * Functions that will be triggered through signals whenever the
     * triangulation is modified.
     *
     * Here they are used to administrate the active_fe_fields during the
     * spatial refinement.
     */
    void pre_refinement_action ();
    void post_refinement_action ();

    /**
     * Space to store the DoF numbers for the different levels. Analogous to
     * the <tt>levels[]</tt> tree of the Triangulation objects.
     */
    std::vector<std::unique_ptr<dealii::internal::hp::DoFLevel> > levels;

    /**
     * Space to store the DoF numbers for the faces. Analogous to the
     * <tt>faces</tt> pointer of the Triangulation objects.
     */
    std::unique_ptr<dealii::internal::hp::DoFIndicesOnFaces<dim> > faces;

    /**
     * A structure that contains all sorts of numbers that characterize the
     * degrees of freedom this object works on.
     *
     * For most members of this structure, there is an accessor function in
     * this class that returns its value.
     */
    dealii::internal::DoFHandlerImplementation::NumberCache number_cache;

    /**
     * A structure that contains all sorts of numbers that characterize the
     * degrees of freedom on multigrid levels. Since multigrid is not currently
     * supported, this table is not filled with valid entries.
     */
    std::vector<dealii::internal::DoFHandlerImplementation::NumberCache> mg_number_cache;

    /**
     * Array to store the indices for degrees of freedom located at vertices.
     *
     * The format used here, in the form of a linked list, is the same as used
     * for the arrays used in the internal::hp::DoFLevel hierarchy. Starting
     * indices into this array are provided by the vertex_dof_offsets field.
     *
     * Access to this field is generally through the
     * DoFAccessor::get_vertex_dof_index() and
     * DoFAccessor::set_vertex_dof_index() functions, encapsulating the actual
     * data format used to the present class.
     */
    std::vector<types::global_dof_index> vertex_dofs;

    /**
     * For each vertex in the triangulation, store the offset within the
     * vertex_dofs array where the dofs for this vertex start.
     *
     * As for that array, the format is the same as described in the
     * documentation of hp::DoFLevel.
     *
     * Access to this field is generally through the
     * Accessor::get_vertex_dof_index() and Accessor::set_vertex_dof_index()
     * functions, encapsulating the actual data format used to the present
     * class.
     */
    std::vector<unsigned int>      vertex_dof_offsets;

    /**
     * Array to store the information if a cell on some level has children or
     * not. It is used by the signal slots as a persistent buffer during the
     * refinement, i.e. from between when pre_refinement_action is called and
     * when post_refinement_action runs.
     */
    std::vector<std::unique_ptr<std::vector<bool> > > has_children;

    /**
     * A list of connections with which this object connects to the
     * triangulation to get information about when the triangulation changes.
     */
    std::vector<boost::signals2::connection> tria_listeners;

    /**
     * Make accessor objects friends.
     */
    template <int, class, bool> friend class dealii::DoFAccessor;
    template <class, bool> friend class dealii::DoFCellAccessor;
    friend struct dealii::internal::DoFAccessorImplementation::Implementation;
    friend struct dealii::internal::DoFCellAccessorImplementation::Implementation;

    /**
     * Likewise for DoFLevel objects since they need to access the vertex dofs
     * in the functions that set and retrieve vertex dof indices.
     */
    template <int> friend class dealii::internal::hp::DoFIndicesOnFacesOrEdges;
    friend struct dealii::internal::hp::DoFHandlerImplementation::Implementation;
    friend struct dealii::internal::DoFHandlerImplementation::Policy::Implementation;
  };



#ifndef DOXYGEN


  /* ----------------------- Inline functions ---------------------------------- */


  template <int dim, int spacedim>
  template <typename number>
  types::global_dof_index
  DoFHandler<dim,spacedim>::n_boundary_dofs (const std::map<types::boundary_id, const Function<spacedim,number>*> &boundary_ids) const
  {
    // extract the set of boundary ids and forget about the function object pointers
    std::set<types::boundary_id> boundary_ids_only;
    for (typename std::map<types::boundary_id, const Function<spacedim,number>*>::const_iterator
         p = boundary_ids.begin();
         p != boundary_ids.end(); ++p)
      boundary_ids_only.insert (p->first);

    // then just hand everything over to the other function that does the work
    return n_boundary_dofs(boundary_ids_only);
  }
}


namespace internal
{
  /**
   * Return a string representing the dynamic type of the given argument.
   * This is basically the same what typeid(...).name() does, but it turns out
   * this is broken on Intel 13+.
   *
   * Defined in source/dofs/dof_handler.cc.
   */
  template <int dim, int spacedim>
  std::string policy_to_string(const dealii::internal::DoFHandlerImplementation::Policy::PolicyBase<dim,spacedim> &policy);
}


namespace hp
{
  template <int dim, int spacedim>
  template <class Archive>
  void DoFHandler<dim, spacedim>::save(Archive &ar, unsigned int) const
  {
    ar &vertex_dofs;
    ar &vertex_dof_offsets;
    ar &number_cache;
    ar &mg_number_cache;

    // some versions of gcc have trouble with loading vectors of
    // std::unique_ptr objects because std::unique_ptr does not
    // have a copy constructor. do it one level at a time
    const unsigned int n_levels = levels.size();
    ar &n_levels;
    for (unsigned int i = 0; i < n_levels; ++i)
      ar &levels[i];

    // boost dereferences a nullptr when serializing a nullptr
    // at least up to 1.65.1. This causes problems with clang-5.
    // Therefore, work around it.
    bool faces_is_nullptr = (faces.get()==nullptr);
    ar &faces_is_nullptr;
    if (!faces_is_nullptr)
      ar &faces;

    // the same issue as above
    const unsigned int n_has_children = has_children.size();
    ar &n_has_children;
    for (unsigned int i = 0; i < n_has_children; ++i)
      ar &has_children[i];

    // write out the number of triangulation cells and later check during
    // loading that this number is indeed correct; same with something that
    // identifies the policy
    const unsigned int n_cells = tria->n_cells();
    std::string  policy_name = dealii::internal::policy_to_string(*policy);

    ar &n_cells &policy_name;
  }



  template <int dim, int spacedim>
  template <class Archive>
  void DoFHandler<dim, spacedim>::load(Archive &ar, unsigned int)
  {
    ar &vertex_dofs;
    ar &vertex_dof_offsets;
    ar &number_cache;
    ar &mg_number_cache;

    // boost::serialization can restore pointers just fine, but if the
    // pointer object still points to something useful, that object is not
    // destroyed and we end up with a memory leak. consequently, first delete
    // previous content before re-loading stuff
    levels.clear ();
    has_children.clear ();
    faces.reset ();

    // some versions of gcc have trouble with loading vectors of
    // std::unique_ptr objects because std::unique_ptr does not
    // have a copy constructor. do it one level at a time
    unsigned int size;
    ar &size;
    levels.resize(size);
    for (unsigned int i = 0; i < size; ++i)
      {
        std::unique_ptr<dealii::internal::hp::DoFLevel> level;
        ar &level;
        levels[i] = std::move(level);
      }

    //Workaround for nullptr, see in save().
    bool faces_is_nullptr = true;
    ar &faces_is_nullptr;
    if (!faces_is_nullptr)
      ar &faces;

    // the same issue as above
    ar &size;
    has_children.resize(size);
    for (unsigned int i = 0; i < size; ++i)
      {
        std::unique_ptr<std::vector<bool> > has_children_on_level;
        ar &has_children_on_level;
        has_children[i] = std::move(has_children_on_level);
      }

    // these are the checks that correspond to the last block in the save()
    // function
    unsigned int n_cells;
    std::string  policy_name;

    ar &n_cells &policy_name;

    AssertThrow (n_cells == tria->n_cells(),
                 ExcMessage ("The object being loaded into does not match the triangulation "
                             "that has been stored previously."));
    AssertThrow (policy_name == dealii::internal::policy_to_string(*policy),
                 ExcMessage ("The policy currently associated with this DoFHandler ("
                             + dealii::internal::policy_to_string(*policy)
                             + ") does not match the one that was associated with the "
                             "DoFHandler previously stored ("
                             + policy_name
                             + ")."));
  }

  template <int dim, int spacedim>
  inline
  types::global_dof_index
  DoFHandler<dim,spacedim>::n_dofs () const
  {
    return number_cache.n_global_dofs;
  }



  template <int dim, int spacedim>
  inline
  types::global_dof_index
  DoFHandler<dim,spacedim>::n_dofs (const unsigned int) const
  {
    Assert(false, ExcNotImplemented());
    return numbers::invalid_dof_index;
  }



  template <int dim, int spacedim>
  types::global_dof_index
  DoFHandler<dim, spacedim>::n_locally_owned_dofs() const
  {
    return number_cache.n_locally_owned_dofs;
  }



  template <int dim, int spacedim>
  const IndexSet &
  DoFHandler<dim, spacedim>::locally_owned_dofs() const
  {
    return number_cache.locally_owned_dofs;
  }



  template <int dim, int spacedim>
  const std::vector<types::global_dof_index> &
  DoFHandler<dim, spacedim>::n_locally_owned_dofs_per_processor() const
  {
    return number_cache.n_locally_owned_dofs_per_processor;
  }



  template <int dim, int spacedim>
  const std::vector<IndexSet> &
  DoFHandler<dim, spacedim>::locally_owned_dofs_per_processor () const
  {
    return number_cache.locally_owned_dofs_per_processor;
  }



  template <int dim, int spacedim>
  const IndexSet &
  DoFHandler<dim, spacedim>::locally_owned_mg_dofs (const unsigned int level) const
  {
    Assert(false, ExcNotImplemented());
    (void)level;
    Assert(level < this->get_triangulation().n_global_levels(),
           ExcMessage("invalid level in locally_owned_mg_dofs"));
    return mg_number_cache[0].locally_owned_dofs;
  }


  template <int dim, int spacedim>
  const std::vector<IndexSet> &
  DoFHandler<dim, spacedim>::locally_owned_mg_dofs_per_processor (const unsigned int level) const
  {
    Assert(false, ExcNotImplemented());
    (void)level;
    Assert(level < this->get_triangulation().n_global_levels(),
           ExcMessage("invalid level in locally_owned_mg_dofs_per_processor"));
    return mg_number_cache[0].locally_owned_dofs_per_processor;
  }



  template <int dim, int spacedim>
  inline
  const hp::FECollection<dim,spacedim> &
  DoFHandler<dim,spacedim>::get_fe () const
  {
    Assert (fe_collection.size() > 0,
            ExcMessage ("No finite element collection is associated with "
                        "this DoFHandler"));
    return fe_collection;
  }



  template <int dim, int spacedim>
  inline
  const FiniteElement<dim,spacedim> &
  DoFHandler<dim,spacedim>::get_fe
  (const unsigned int number) const
  {
    Assert (fe_collection.size() > 0,
            ExcMessage ("No finite element collection is associated with "
                        "this DoFHandler"));
    return fe_collection[number];
  }



  template <int dim, int spacedim>
  inline
  const hp::FECollection<dim,spacedim> &
  DoFHandler<dim,spacedim>::get_fe_collection () const
  {
    Assert (fe_collection.size() > 0,
            ExcMessage ("No finite element collection is associated with "
                        "this DoFHandler"));
    return fe_collection;
  }



  template <int dim, int spacedim>
  inline
  const Triangulation<dim,spacedim> &
  DoFHandler<dim,spacedim>::get_triangulation () const
  {
    Assert(tria != nullptr,
           ExcMessage("This DoFHandler object has not been associated "
                      "with a triangulation."));
    return *tria;
  }

#endif

}

DEAL_II_NAMESPACE_CLOSE

#endif
