]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Split vector_tools.h
authorDaniel Arndt <arndtd@ornl.gov>
Mon, 20 Apr 2020 16:35:42 +0000 (12:35 -0400)
committerDaniel Arndt <arndtd@ornl.gov>
Tue, 21 Apr 2020 23:14:07 +0000 (19:14 -0400)
20 files changed:
include/deal.II/numerics/vector_tools.h
include/deal.II/numerics/vector_tools_boundary.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_boundary.templates.h
include/deal.II/numerics/vector_tools_common.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_constraints.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_constraints.templates.h
include/deal.II/numerics/vector_tools_integrate_difference.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_integrate_difference.templates.h
include/deal.II/numerics/vector_tools_interpolate.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_interpolate.templates.h
include/deal.II/numerics/vector_tools_mean_value.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_mean_value.templates.h
include/deal.II/numerics/vector_tools_point_gradient.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_point_gradient.templates.h
include/deal.II/numerics/vector_tools_point_value.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_point_value.templates.h
include/deal.II/numerics/vector_tools_project.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_project.templates.h
include/deal.II/numerics/vector_tools_rhs.h [new file with mode: 0644]
include/deal.II/numerics/vector_tools_rhs.templates.h

index fafa5d3d7b40b6de66a396687c941fc25de60649..855e3aecb9d66eb423cf803161ac7f028b27a0a9 100644 (file)
 
 #include <deal.II/base/config.h>
 
-#include <deal.II/base/exceptions.h>
-#include <deal.II/base/function.h>
-#include <deal.II/base/patterns.h>
-#include <deal.II/base/point.h>
-#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/numerics/vector_tools_boundary.h>
+#include <deal.II/numerics/vector_tools_common.h>
+#include <deal.II/numerics/vector_tools_constraints.h>
+#include <deal.II/numerics/vector_tools_integrate_difference.h>
+#include <deal.II/numerics/vector_tools_interpolate.h>
+#include <deal.II/numerics/vector_tools_mean_value.h>
+#include <deal.II/numerics/vector_tools_point_gradient.h>
+#include <deal.II/numerics/vector_tools_point_value.h>
+#include <deal.II/numerics/vector_tools_project.h>
+#include <deal.II/numerics/vector_tools_rhs.h>
 
-#include <deal.II/dofs/deprecated_function_map.h>
-#include <deal.II/dofs/dof_handler.h>
-
-#include <deal.II/hp/dof_handler.h>
-#include <deal.II/hp/mapping_collection.h>
-
-#include <functional>
-#include <map>
-#include <set>
-#include <vector>
 
 DEAL_II_NAMESPACE_OPEN
 
-// Forward declarations
-#ifndef DOXYGEN
-template <int dim, typename RangeNumberType>
-class Function;
-template <int dim>
-class Quadrature;
-template <int dim>
-class QGauss;
-template <int dim, typename number, typename VectorizedArrayType>
-class MatrixFree;
-
-template <typename number>
-class Vector;
-template <typename number>
-class FullMatrix;
-template <int dim, int spacedim>
-class Mapping;
-template <typename gridtype>
-class InterGridMap;
-namespace hp
-{
-  template <int dim>
-  class QCollection;
-}
-template <typename number>
-class AffineConstraints;
-#endif
-
 // TODO: Move documentation of functions to the functions!
 
 /**
@@ -334,3187 +301,7 @@ class AffineConstraints;
  * 2001
  */
 namespace VectorTools
-{
-  /**
-   * Denote which norm/integral is to be computed by the
-   * integrate_difference() function on each cell and compute_global_error()
-   * for the whole domain.
-   * Let $f:\Omega \rightarrow \mathbb{R}^c$ be a finite element function
-   * with $c$ components where component $c$ is denoted by $f_c$ and $\hat{f}$
-   * be the reference function (the @p fe_function and @p exact_solution
-   * arguments to integrate_difference()). Let $e_c = \hat{f}_c - f_c$
-   * be the difference or error between the two. Further,
-   * let  $w:\Omega \rightarrow \mathbb{R}^c$ be the @p weight function of integrate_difference(), which is
-   * assumed to be equal to one if not supplied. Finally, let $p$ be the
-   * @p exponent argument (for $L_p$-norms).
-   *
-   * In the following,we denote by $E_K$ the local error computed by
-   * integrate_difference() on cell $K$, whereas $E$ is the global error
-   * computed by compute_global_error(). Note that integrals are
-   * approximated by quadrature in the usual way:
-   * @f[
-   * \int_A f(x) dx \approx \sum_q f(x_q) \omega_q.
-   * @f]
-   * Similarly for suprema over a cell $T$:
-   * @f[
-   * \sup_{x\in T} |f(x)| dx \approx \max_q |f(x_q)|.
-   * @f]
-   */
-  enum NormType
-  {
-    /**
-     * The function or difference of functions is integrated on each cell $K$:
-     * @f[
-     *   E_K
-     * = \int_K \sum_c (\hat{f}_c - f_c) \, w_c
-     * = \int_K \sum_c e_c \, w_c
-     * @f]
-     * and summed up to get
-     * @f[
-     *   E = \sum_K E_K
-     *     = \int_\Omega \sum_c (\hat{f}_c - f_c) \, w_c
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \int_\Omega (\hat{f} - f)
-     *     = \int_\Omega e.
-     * @f]
-     *
-     * Note: This differs from what is typically known as
-     * the mean of a function by a factor of $\frac{1}{|\Omega|}$. To
-     * compute the mean you can also use compute_mean_value(). Finally,
-     * pay attention to the sign: if $\hat{f}=0$, this will compute the
-     * negative of the mean of $f$.
-     */
-    mean,
-
-    /**
-     * The absolute value of the function is integrated:
-     * @f[
-     *   E_K = \int_K \sum_c |e_c| \, w_c
-     * @f]
-     * and
-     * @f[
-     *   E = \sum_K E_K = \int_\Omega \sum_c |e_c| w_c,
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E  = \| e \|_{L^1}.
-     * @f]
-     */
-    L1_norm,
-
-    /**
-     * The square of the function is integrated and the square root of the
-     * result is computed on each cell:
-     * @f[
-     *   E_K = \sqrt{ \int_K \sum_c e_c^2 \, w_c }
-     * @f]
-     * and
-     * @f[
-     *   E = \sqrt{\sum_K E_K^2} = \sqrt{ \int_\Omega  \sum_c e_c^2 \, w_c }
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \sqrt{ \int_\Omega e^2 }
-     *     = \| e \|_{L^2}
-     * @f]
-     */
-    L2_norm,
-
-    /**
-     * The absolute value to the $p$-th power is integrated and the $p$-th
-     * root is computed on each cell. The exponent $p$ is the @p
-     * exponent argument of integrate_difference() and compute_mean_value():
-     * @f[
-     *   E_K = \left( \int_K \sum_c |e_c|^p \, w_c \right)^{1/p}
-     * @f]
-     * and
-     * @f[
-     *   E = \left( \sum_K E_K^p \right)^{1/p}
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \| e \|_{L^p}.
-     * @f]
-     */
-    Lp_norm,
-
-    /**
-     * The maximum absolute value of the function:
-     * @f[
-     *   E_K = \sup_K \max_c |e_c| \, w_c
-     * @f]
-     * and
-     * @f[
-     *   E = \max_K E_K
-     * = \sup_\Omega \max_c |e_c| \, w_c
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E  = \sup_\Omega \|e\|_\infty = \| e \|_{L^\infty}.
-     * @f]
-     */
-    Linfty_norm,
-
-    /**
-     * #L2_norm of the gradient:
-     * @f[
-     *   E_K = \sqrt{ \int_K \sum_c (\nabla e_c)^2 \, w_c }
-     * @f]
-     * and
-     * @f[
-     *   E = \sqrt{\sum_K E_K^2} = \sqrt{ \int_\Omega \sum_c (\nabla e_c)^2 \,
-     * w_c }
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \| \nabla e \|_{L^2}.
-     * @f]
-     */
-    H1_seminorm,
-
-    /**
-     * #L2_norm of the divergence of a vector field. The function $f$ is
-     * expected to have $c \geq \text{dim}$ components and the first @p dim
-     * will be used to compute the divergence:
-     * @f[
-     *   E_K = \sqrt{ \int_K \left( \sum_c \frac{\partial e_c}{\partial x_c} \,
-     * \sqrt{w_c} \right)^2 }
-     * @f]
-     * and
-     * @f[
-     *   E = \sqrt{\sum_K E_K^2}
-     *     = \sqrt{ \int_\Omega \left( \sum_c \frac{\partial e_c}{\partial x_c}
-     * \, \sqrt{w_c} \right)^2  }
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \| \nabla \cdot e \|_{L^2}.
-     * @f]
-     */
-    Hdiv_seminorm,
-
-    /**
-     * The square of this norm is the square of the #L2_norm plus the square
-     * of the #H1_seminorm:
-     * @f[
-     *   E_K = \sqrt{ \int_K \sum_c (e_c^2 + (\nabla e_c)^2) \, w_c }
-     * @f]
-     * and
-     * @f[
-     *   E = \sqrt{\sum_K E_K^2} = \sqrt{ \int_\Omega \sum_c (e_c^2 + (\nabla
-     * e_c)^2) \, w_c }
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \left( \| e \|_{L^2}^2 + \| \nabla e \|_{L^2}^2 \right)^{1/2}.
-     * @f]
-     */
-    H1_norm,
-
-    /**
-     * #Lp_norm of the gradient:
-     * @f[
-     *   E_K = \left( \int_K \sum_c |\nabla e_c|^p \, w_c \right)^{1/p}
-     * @f]
-     * and
-     * @f[
-     *   E = \left( \sum_K E_K^p \right)^{1/p}
-     *     = \left( \int_\Omega \sum_c |\nabla e_c|^p \, w_c \right)^{1/p}
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \| \nabla e \|_{L^p}.
-     * @f]
-     */
-    W1p_seminorm,
-
-    /**
-     * The same as the #H1_norm but using <i>L<sup>p</sup></i>:
-     * @f[
-     *   E_K = \left( \int_K \sum_c (|e_c|^p + |\nabla e_c|^p) \, w_c
-     * \right)^{1/p}
-     * @f]
-     * and
-     * @f[
-     *   E = \left( \sum_K E_K^p \right)^{1/p}
-     *     = \left( \int_\Omega \sum_c (|e_c|^p + |\nabla e_c|^p) \, w_c
-     * \right)^{1/p}
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \left( \| e \|_{L^p}^p + \| \nabla e \|_{L^p}^p \right)^{1/p}.
-     * @f]
-     */
-    W1p_norm,
-
-    /**
-     * #Linfty_norm of the gradient:
-     * @f[
-     *   E_K = \sup_K \max_c |\nabla e_c| \, w_c
-     * @f]
-     * and
-     * @f[
-     *   E = \max_K E_K
-     *     = \sup_\Omega \max_c |\nabla e_c| \, w_c
-     * @f]
-     * or, for $w \equiv 1$:
-     * @f[
-     *   E = \| \nabla e \|_{L^\infty}.
-     * @f]
-     *
-     */
-    W1infty_seminorm,
-
-    /**
-     * The sum of #Linfty_norm and #W1infty_seminorm:
-     * @f[
-     *   E_K = \sup_K \max_c |e_c| \, w_c + \sup_K \max_c |\nabla e_c| \, w_c.
-     * @f]
-     * The global norm is not implemented in compute_global_error(),
-     * because it is impossible to compute the sum of the global
-     * norms from the values $E_K$. As a work-around, you can compute the
-     * global #Linfty_norm and #W1infty_seminorm separately and then add them
-     * to get (with $w \equiv 1$):
-     * @f[
-     *   E = \| e \|_{L^\infty} + \| \nabla e \|_{L^\infty}.
-     * @f]
-     */
-    W1infty_norm
-
-  };
-  /**
-   * @name Interpolation and projection
-   */
-  //@{
-
-
-
-  /**
-   * Compute the interpolation of @p function at the support points to the
-   * finite element space described by the Triangulation and FiniteElement
-   * object with which the given DoFHandler argument is initialized. It is
-   * assumed that the number of components of @p function matches that of the
-   * finite element used by @p dof.
-   *
-   * Note that you may have to call <tt>hanging_nodes.distribute(vec)</tt>
-   * with the hanging nodes from space @p dof afterwards, to make the result
-   * continuous again.
-   *
-   * The template argument <code>DoFHandlerType</code> may either be of type
-   * DoFHandler or hp::DoFHandler.
-   *
-   * See the general documentation of this namespace for further information.
-   *
-   * @todo The @p mapping argument should be replaced by a
-   * hp::MappingCollection in case of a hp::DoFHandler.
-   */
-  template <int dim,
-            int spacedim,
-            typename VectorType,
-            template <int, int> class DoFHandlerType>
-  void
-  interpolate(
-    const Mapping<dim, spacedim> &                             mapping,
-    const DoFHandlerType<dim, spacedim> &                      dof,
-    const Function<spacedim, typename VectorType::value_type> &function,
-    VectorType &                                               vec,
-    const ComponentMask &component_mask = ComponentMask());
-
-  /**
-   * Call the @p interpolate() function above with
-   * <tt>mapping=MappingQGeneric1@<dim>@()</tt>.
-   */
-  template <int dim,
-            int spacedim,
-            typename VectorType,
-            template <int, int> class DoFHandlerType>
-  void
-  interpolate(
-    const DoFHandlerType<dim, spacedim> &                      dof,
-    const Function<spacedim, typename VectorType::value_type> &function,
-    VectorType &                                               vec,
-    const ComponentMask &component_mask = ComponentMask());
-
-  /**
-   * Interpolate different finite element spaces. The interpolation of vector
-   * @p data_1 (which is assumed to be ghosted, see @ref GlossGhostedVector)
-   * is executed from the FE space represented by @p dof_1
-   * to the vector @p data_2 on FE space @p dof_2.
-   * The interpolation on each cell is represented by the matrix @p transfer.
-   * Curved boundaries are neglected so far.
-   *
-   * Note that you may have to call <tt>hanging_nodes.distribute(data_2)</tt>
-   * with the hanging nodes from space @p dof_2 afterwards, to make the result
-   * continuous again.
-   *
-   * @note Instantiations for this template are provided for some vector types
-   * (see the general documentation of the namespace), but only the same
-   * vector for InVector and OutVector. Other combinations must be
-   * instantiated by hand.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  void
-  interpolate(const DoFHandler<dim, spacedim> &dof_1,
-              const DoFHandler<dim, spacedim> &dof_2,
-              const FullMatrix<double> &       transfer,
-              const InVector &                 data_1,
-              OutVector &                      data_2);
-
-  /**
-   * This function is a kind of generalization or modification of the very
-   * first interpolate() function in the series. It interpolates a set of
-   * functions onto the finite element space defined by the DoFHandler argument,
-   * where the determination which function to use on each cell is made
-   * based on the material id (see
-   * @ref GlossMaterialId)
-   * of each cell.
-   *
-   * @param[in] mapping        The mapping to use to determine the location of
-   *   support points at which the functions are to be evaluated.
-   * @param[in] dof_handler    DoFHandler initialized with Triangulation and
-   *   FiniteElement objects and that defines the finite element space.
-   * @param[in] function_map   A std::map reflecting the correspondence between
-   *   material ids on those cells on which something should be interpolated,
-   *   and the functions to be interpolated onto the finite element space.
-   * @param[out] dst           The global finie element vector holding the
-   *   output of the interpolated values.
-   * @param[in] component_mask A mask of components that shall be interpolated.
-   *
-   * @note If the algorithm encounters a cell whose material id is not listed
-   * in the given @p function_map, then @p dst will not be updated in the
-   * respective degrees of freedom of the output vector. For example, if
-   * @p dst was initialized to zero, then those zeros which correspond to
-   * the missed material ids will still remain in @p dst after calling
-   * this function.
-   *
-   * @note Degrees of freedom located on faces between cells of different
-   * material ids will get their value by that cell which was called last in
-   * the respective loop over cells implemented in this function. Since the
-   * order of cells is somewhat arbitrary, you cannot control it. However, if
-   * you want to have control over the order in which cells are visited, let us
-   * take a
-   * look at the following example: Let @p u be a variable of interest which
-   * is approximated by some CG finite element. Let @p 0, @p 1 and @p 2 be
-   * material ids of cells on the triangulation. Let 0: 0.0, 1: 1.0, 2: 2.0 be
-   * the whole @p function_map that you want to pass to this function, where
-   * @p key is a material id and @p value is a value of @p u. By using the
-   * whole @p function_map you do not really know which values will be
-   * assigned to the face DoFs. On the other hand, if you split the whole @p
-   * function_map into three smaller independent objects 0: 0.0 and 1: 1.0 and
-   * 2: 2.0 and make three distinct calls of this function passing each of
-   * these objects separately (the order depends on what you want to get
-   * between cells), then each subsequent call will rewrite the intercell @p
-   * dofs of the previous one.
-   *
-   * @author Valentin Zingan, 2013
-   */
-  template <int dim,
-            int spacedim,
-            typename VectorType,
-            template <int, int> class DoFHandlerType>
-  void
-  interpolate_based_on_material_id(
-    const Mapping<dim, spacedim> &       mapping,
-    const DoFHandlerType<dim, spacedim> &dof_handler,
-    const std::map<types::material_id,
-                   const Function<spacedim, typename VectorType::value_type> *>
-      &                  function_map,
-    VectorType &         dst,
-    const ComponentMask &component_mask = ComponentMask());
-
-  /**
-   * Compute the interpolation of a @p dof1-function @p u1 to a @p dof2-function
-   * @p u2, where @p dof1 and @p dof2 represent different triangulations with
-   * a common coarse grid.
-   *
-   * dof1 and dof2 need to have the same finite element discretization.
-   *
-   * Note that for continuous elements on grids with hanging nodes (i.e.
-   * locally refined grids) this function does not give the expected output.
-   * Indeed, the resulting output vector does not necessarily respect
-   * continuity requirements at hanging nodes, due to local cellwise
-   * interpolation.
-   *
-   * For this case (continuous elements on grids with hanging nodes), please
-   * use the interpolate_to_different_mesh function with an additional
-   * AffineConstraints argument, see below, or make the field conforming
-   * yourself by calling the @p AffineConstraints::distribute function of your
-   * hanging node constraints object.
-   *
-   * @note This function works with parallel::distributed::Triangulation, but
-   * only if the parallel partitioning is the same for both meshes (see the
-   * parallel::distributed::Triangulation<dim>::no_automatic_repartitioning
-   * flag).
-   */
-  template <int dim,
-            int spacedim,
-            typename VectorType,
-            template <int, int> class DoFHandlerType>
-  void
-  interpolate_to_different_mesh(const DoFHandlerType<dim, spacedim> &dof1,
-                                const VectorType &                   u1,
-                                const DoFHandlerType<dim, spacedim> &dof2,
-                                VectorType &                         u2);
-
-  /**
-   * Compute the interpolation of a @p dof1-function @p u1 to a @p dof2-function
-   * @p u2, where @p dof1 and @p dof2 represent different triangulations with
-   * a common coarse grid.
-   *
-   * dof1 and dof2 need to have the same finite element discretization.
-   *
-   * @p constraints is a hanging node constraints object corresponding to @p
-   * dof2. This object is particularly important when interpolating onto
-   * continuous elements on grids with hanging nodes (locally refined grids):
-   * Without it - due to cellwise interpolation - the resulting output vector
-   * does not necessarily respect continuity requirements at hanging nodes.
-   */
-  template <int dim,
-            int spacedim,
-            typename VectorType,
-            template <int, int> class DoFHandlerType>
-  void
-  interpolate_to_different_mesh(
-    const DoFHandlerType<dim, spacedim> &                     dof1,
-    const VectorType &                                        u1,
-    const DoFHandlerType<dim, spacedim> &                     dof2,
-    const AffineConstraints<typename VectorType::value_type> &constraints,
-    VectorType &                                              u2);
-
-  /**
-   * The same function as above, but takes an InterGridMap object directly as
-   * a parameter. Useful for interpolating several vectors at the same time.
-   *
-   * @p intergridmap has to be initialized via InterGridMap::make_mapping
-   * pointing from a source DoFHandler to a destination DoFHandler.
-   */
-  template <int dim,
-            int spacedim,
-            typename VectorType,
-            template <int, int> class DoFHandlerType>
-  void
-  interpolate_to_different_mesh(
-    const InterGridMap<DoFHandlerType<dim, spacedim>> &       intergridmap,
-    const VectorType &                                        u1,
-    const AffineConstraints<typename VectorType::value_type> &constraints,
-    VectorType &                                              u2);
-
-  /**
-   * Compute the projection of @p function to the finite element space. In other
-   * words, given a function $f(\mathbf x)$, the current function computes a
-   * finite element function $f_h(\mathbf x)=\sum_j F_j \varphi_j(\mathbf x)$
-   * characterized by the (output) vector of nodal values $F$ that satisfies
-   * the equation
-   * @f{align*}{
-   *   (\varphi_i, f_h)_\Omega = (\varphi_i,f)_\Omega
-   * @f}
-   * for all test functions $\varphi_i$. This requires solving a linear system
-   * involving the mass matrix since the equation above is equivalent to
-   * the linear system
-   * @f{align*}{
-   *   \sum_j (\varphi_i, \varphi_j)_\Omega F_j = (\varphi_i,f)_\Omega
-   * @f}
-   * which can also be written as $MF = \Phi$ with
-   * $M_{ij} = (\varphi_i, \varphi_j)_\Omega$ and
-   * $\Phi_i = (\varphi_i,f)_\Omega$.
-   *
-   * By default, no boundary values for $f_h$ are needed nor
-   * imposed, but there are optional parameters to this function that allow
-   * imposing either zero boundary values or, in a first step, to project
-   * the boundary values of $f$ onto the finite element space on the boundary
-   * of the mesh in a similar way to above, and then using these values as the
-   * imposed boundary values for $f_h$. The ordering of arguments to this
-   * function is such that you need not give a second quadrature formula (of
-   * type `Quadrature<dim-1>` and used for the computation of the matrix and
-   * right hand side for the projection of boundary values) if you
-   * don't want to project to the boundary first, but that you must if you want
-   * to do so.
-   *
-   * A MatrixFree implementation is used if the following conditions are met:
-   * - @p enforce_zero_boundary is false,
-   * - @p project_to_boundary_first is false,
-   * - the FiniteElement is supported by the MatrixFree class,
-   * - the FiniteElement has less than five components
-   * - the degree of the FiniteElement is less than nine.
-   * - dim==spacedim
-   *
-   * In this case, this function performs numerical quadrature using the given
-   * quadrature formula for integration of the right hand side $\Phi_i$ while a
-   * QGauss(fe_degree+2) object is used for the mass operator. You should
-   * therefore make sure that the given quadrature formula is sufficiently
-   * accurate for creating the right-hand side.
-   *
-   * Otherwise, only serial Triangulations are supported and the mass matrix
-   * is assembled using MatrixTools::create_mass_matrix. The given
-   * quadrature rule is then used for both the matrix and the right-hand side.
-   * You should therefore make sure that the given quadrature formula is also
-   * sufficient for creating the mass matrix. In particular, the degree of the
-   * quadrature formula must be sufficiently high to ensure that the mass
-   * matrix is invertible. For example, if you are using a FE_Q(k) element,
-   * then the integrand of the matrix entries $M_{ij}$ is of polynomial
-   * degree $2k$ in each variable, and you need a Gauss quadrature formula
-   * with $k+1$ points in each coordinate direction to ensure that $M$
-   * is invertible.
-   *
-   * See the general documentation of this namespace for further information.
-   *
-   * In 1d, the default value of the boundary quadrature formula is an invalid
-   * object since integration on the boundary doesn't happen in 1d.
-   *
-   * @param[in] mapping The mapping object to use.
-   * @param[in] dof The DoFHandler the describes the finite element space to
-   * project into and that corresponds to @p vec.
-   * @param[in] constraints Constraints to be used when assembling the mass
-   * matrix, typically needed when you have hanging nodes.
-   * @param[in] quadrature The quadrature formula to be used for assembling the
-   * mass matrix.
-   * @param[in] function The function to project into the finite element space.
-   * @param[out] vec The output vector where the projected function will be
-   * stored in. This vector is required to be already initialized and must not
-   * have ghost elements.
-   * @param[in] enforce_zero_boundary If true, @p vec will have zero boundary
-   * conditions.
-   * @param[in] q_boundary Quadrature rule to be used if @p project_to_boundary_first
-   * is true.
-   * @param[in] project_to_boundary_first If true, perform a projection on the
-   * boundary before projecting the interior of the function.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  project(const Mapping<dim, spacedim> &                            mapping,
-          const DoFHandler<dim, spacedim> &                         dof,
-          const AffineConstraints<typename VectorType::value_type> &constraints,
-          const Quadrature<dim> &                                   quadrature,
-          const Function<spacedim, typename VectorType::value_type> &function,
-          VectorType &                                               vec,
-          const bool                 enforce_zero_boundary     = false,
-          const Quadrature<dim - 1> &q_boundary                = (dim > 1 ?
-                                                     QGauss<dim - 1>(2) :
-                                                     Quadrature<dim - 1>(0)),
-          const bool                 project_to_boundary_first = false);
-
-  /**
-   * Call the project() function above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  project(const DoFHandler<dim, spacedim> &                         dof,
-          const AffineConstraints<typename VectorType::value_type> &constraints,
-          const Quadrature<dim> &                                   quadrature,
-          const Function<spacedim, typename VectorType::value_type> &function,
-          VectorType &                                               vec,
-          const bool                 enforce_zero_boundary     = false,
-          const Quadrature<dim - 1> &q_boundary                = (dim > 1 ?
-                                                     QGauss<dim - 1>(2) :
-                                                     Quadrature<dim - 1>(0)),
-          const bool                 project_to_boundary_first = false);
-
-  /**
-   * Same as above, but for arguments of type hp::DoFHandler, hp::QCollection,
-   * and hp::MappingCollection.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  project(const hp::MappingCollection<dim, spacedim> &              mapping,
-          const hp::DoFHandler<dim, spacedim> &                     dof,
-          const AffineConstraints<typename VectorType::value_type> &constraints,
-          const hp::QCollection<dim> &                              quadrature,
-          const Function<spacedim, typename VectorType::value_type> &function,
-          VectorType &                                               vec,
-          const bool                      enforce_zero_boundary = false,
-          const hp::QCollection<dim - 1> &q_boundary = hp::QCollection<dim - 1>(
-            dim > 1 ? QGauss<dim - 1>(2) : Quadrature<dim - 1>(0)),
-          const bool project_to_boundary_first = false);
-
-  /**
-   * Call the project() function above, with a collection of $Q_1$ mapping
-   * objects, i.e., with hp::StaticMappingQ1::mapping_collection.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  project(const hp::DoFHandler<dim, spacedim> &                     dof,
-          const AffineConstraints<typename VectorType::value_type> &constraints,
-          const hp::QCollection<dim> &                              quadrature,
-          const Function<spacedim, typename VectorType::value_type> &function,
-          VectorType &                                               vec,
-          const bool                      enforce_zero_boundary = false,
-          const hp::QCollection<dim - 1> &q_boundary = hp::QCollection<dim - 1>(
-            dim > 1 ? QGauss<dim - 1>(2) : Quadrature<dim - 1>(0)),
-          const bool project_to_boundary_first = false);
-
-  /**
-   * The same as above for projection of scalar-valued quadrature data.
-   * The user provided function should return a value at the quadrature point
-   * based on the cell iterator and quadrature number and of course should be
-   * consistent with the provided @p quadrature object, which will be used
-   * to assemble the right-hand-side.
-   *
-   * This function can be used with lambdas:
-   * @code
-   * VectorTools::project
-   * (mapping,
-   *  dof_handler,
-   *  constraints,
-   *  quadrature_formula,
-   *  [&] (const typename DoFHandler<dim>::active_cell_iterator & cell,
-   *       const unsigned int q) -> double
-   *  {
-   *    return qp_data.get_data(cell)[q]->density;
-   *  },
-   *  field);
-   * @endcode
-   * where <code>qp_data</code> is a CellDataStorage object, which stores
-   * quadrature point data.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  project(const Mapping<dim, spacedim> &                            mapping,
-          const DoFHandler<dim, spacedim> &                         dof,
-          const AffineConstraints<typename VectorType::value_type> &constraints,
-          const Quadrature<dim> &                                   quadrature,
-          const std::function<typename VectorType::value_type(
-            const typename DoFHandler<dim, spacedim>::active_cell_iterator &,
-            const unsigned int)> &                                  func,
-          VectorType &                                              vec_result);
-
-  /**
-   * The same as above for projection of scalar-valued MatrixFree quadrature
-   * data.
-   * The user provided function @p func should return a VectorizedArray value
-   * at the quadrature point based on the cell number and quadrature number and
-   * should be consistent with the @p n_q_points_1d.
-   *
-   * This function can be used with lambdas:
-   * @code
-   * VectorTools::project
-   * (matrix_free_data,
-   *  constraints,
-   *  3,
-   *  [&] (const unsigned int cell,
-   *       const unsigned int q) -> VectorizedArray<double>
-   *  {
-   *    return qp_data(cell,q);
-   *  },
-   *  field);
-   * @endcode
-   * where <code>qp_data</code> is a an object of type Table<2,
-   * VectorizedArray<double> >, which stores quadrature point data.
-   *
-   * @p fe_component allow to additionally specify which component of @p data
-   * to use in case it was constructed with an <code>std::vector<const
-   * DoFHandler<dim>*></code>. It will be used internally in constructor of
-   * FEEvaluation object.
-   */
-  template <int dim, typename VectorType>
-  void
-  project(
-    std::shared_ptr<
-      const MatrixFree<dim,
-                       typename VectorType::value_type,
-                       VectorizedArray<typename VectorType::value_type>>> data,
-    const AffineConstraints<typename VectorType::value_type> &constraints,
-    const unsigned int                                        n_q_points_1d,
-    const std::function<VectorizedArray<typename VectorType::value_type>(
-      const unsigned int,
-      const unsigned int)> &                                  func,
-    VectorType &                                              vec_result,
-    const unsigned int                                        fe_component = 0);
-
-  /**
-   * Same as above but for <code>n_q_points_1d =
-   * matrix_free.get_dof_handler().get_fe().degree+1</code>.
-   */
-  template <int dim, typename VectorType>
-  void
-  project(
-    std::shared_ptr<
-      const MatrixFree<dim,
-                       typename VectorType::value_type,
-                       VectorizedArray<typename VectorType::value_type>>> data,
-    const AffineConstraints<typename VectorType::value_type> &constraints,
-    const std::function<VectorizedArray<typename VectorType::value_type>(
-      const unsigned int,
-      const unsigned int)> &                                  func,
-    VectorType &                                              vec_result,
-    const unsigned int                                        fe_component = 0);
-
-  /**
-   * Compute Dirichlet boundary conditions.  This function makes up a map of
-   * degrees of freedom subject to Dirichlet boundary conditions and the
-   * corresponding values to be assigned to them, by interpolation around the
-   * boundary. For each degree of freedom at the boundary, if its index
-   * already exists in @p boundary_values then its boundary value will be
-   * overwritten, otherwise a new entry with proper index and boundary value
-   * for this degree of freedom will be inserted into @p boundary_values.
-   *
-   * The parameter @p function_map provides a list of boundary indicators to
-   * be handled by this function and corresponding boundary value functions.
-   * The keys of this map correspond to the number @p boundary_id of the face.
-   * numbers::internal_face_boundary_id is an illegal value for this key since
-   * it is reserved for interior faces. For an example of how to use this
-   * argument with a non-empty map, see the step-16 tutorial program.
-   *
-   * The flags in the last parameter, @p component_mask denote which
-   * components of the finite element space shall be interpolated. If it is
-   * left as specified by the default value (i.e. an empty array), all
-   * components are interpolated. If it is different from the default value,
-   * it is assumed that the number of entries equals the number of components
-   * in the boundary functions and the finite element, and those components in
-   * the given boundary function will be used for which the respective flag
-   * was set in the component mask. See also
-   * @ref GlossComponentMask.
-   * As an example, assume that you are solving the Stokes equations in 2d,
-   * with variables $(u,v,p)$ and that you only want to interpolate boundary
-   * values for the velocity, then the component mask should correspond to
-   * <code>(true,true,false)</code>.
-   *
-   * @note Whether a component mask has been specified or not, the number of
-   * components of the functions in @p function_map must match that of the
-   * finite element used by @p dof. In other words, for the example above, you
-   * need to provide a Function object that has 3 components (the two
-   * velocities and the pressure), even though you are only interested in the
-   * first two of them. interpolate_boundary_values() will then call this
-   * function to obtain a vector of 3 values at each interpolation point but
-   * only take the first two and discard the third. In other words, you are
-   * free to return whatever you like in the third component of the vector
-   * returned by Function::vector_value, but the Function object must state
-   * that it has 3 components.
-   *
-   * If the finite element used has shape functions that are non-zero in more
-   * than one component (in deal.II speak: they are non-primitive), then these
-   * components can presently not be used for interpolating boundary values.
-   * Thus, the elements in the component mask corresponding to the components
-   * of these non-primitive shape functions must be @p false.
-   *
-   * See the general documentation of this namespace for more information.
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const Mapping<dim, spacedim> &       mapping,
-    const DoFHandlerType<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        function_map,
-    std::map<types::global_dof_index, number> &boundary_values,
-    const ComponentMask &component_mask = ComponentMask());
-
-  /**
-   * Like the previous function, but take a mapping collection to go with the
-   * hp::DoFHandler object.
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  interpolate_boundary_values(
-    const hp::MappingCollection<dim, spacedim> &mapping,
-    const hp::DoFHandler<dim, spacedim> &       dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        function_map,
-    std::map<types::global_dof_index, number> &boundary_values,
-    const ComponentMask &component_mask = ComponentMask());
-
-  /**
-   * Same function as above, but taking only one pair of boundary indicator
-   * and corresponding boundary function. The same comments apply as for the
-   * previous function, in particular about the use of the component mask and
-   * the requires size of the function object.
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const Mapping<dim, spacedim> &             mapping,
-    const DoFHandlerType<dim, spacedim> &      dof,
-    const types::boundary_id                   boundary_component,
-    const Function<spacedim, number> &         boundary_function,
-    std::map<types::global_dof_index, number> &boundary_values,
-    const ComponentMask &component_mask = ComponentMask());
-
-  /**
-   * Call the other interpolate_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
-   * apply as for the previous function, in particular about the use of the
-   * component mask and the requires size of the function object.
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const DoFHandlerType<dim, spacedim> &      dof,
-    const types::boundary_id                   boundary_component,
-    const Function<spacedim, number> &         boundary_function,
-    std::map<types::global_dof_index, number> &boundary_values,
-    const ComponentMask &component_mask = ComponentMask());
-
-
-  /**
-   * Call the other interpolate_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
-   * apply as for the previous function, in particular about the use of the
-   * component mask and the requires size of the function object.
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const DoFHandlerType<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        function_map,
-    std::map<types::global_dof_index, number> &boundary_values,
-    const ComponentMask &component_mask = ComponentMask());
-
-
-  /**
-   * Insert the (algebraic) constraints due to Dirichlet boundary conditions
-   * into a AffineConstraints @p constraints. This function identifies the
-   * degrees of freedom subject to Dirichlet boundary conditions, adds them to
-   * the list of constrained DoFs in @p constraints and sets the respective
-   * inhomogeneity to the value interpolated around the boundary. If this
-   * routine encounters a DoF that already is constrained (for instance by a
-   * hanging node constraint, see below, or any other type of constraint, e.g.
-   * from periodic boundary conditions), the old setting of the constraint
-   * (dofs the entry is constrained to, inhomogeneities) is kept and nothing
-   * happens.
-   *
-   * @note When combining adaptively refined meshes with hanging node
-   * constraints and boundary conditions like from the current function within
-   * one AffineConstraints object, the hanging node constraints should always
-   * be set first, and then the boundary conditions since boundary conditions
-   * are not set in the second operation on degrees of freedom that are
-   * already constrained. This makes sure that the discretization remains
-   * conforming as is needed. See the discussion on conflicting constraints in
-   * the module on
-   * @ref constraints.
-   *
-   * The parameter @p boundary_component corresponds to the number @p
-   * boundary_id of the face.
-   *
-   * The flags in the last parameter, @p component_mask denote which
-   * components of the finite element space shall be interpolated. If it is
-   * left as specified by the default value (i.e. an empty array), all
-   * components are interpolated. If it is different from the default value,
-   * it is assumed that the number of entries equals the number of components
-   * in the boundary functions and the finite element, and those components in
-   * the given boundary function will be used for which the respective flag
-   * was set in the component mask. See also
-   * @ref GlossComponentMask.
-   * As an example, assume that you are solving the Stokes equations in 2d,
-   * with variables $(u,v,p)$ and that you only want to interpolate boundary
-   * values for the pressure, then the component mask should correspond to
-   * <code>(true,true,false)</code>.
-   *
-   * @note Whether a component mask has been specified or not, the number of
-   * components of the functions in @p function_map must match that of the
-   * finite element used by @p dof. In other words, for the example above, you
-   * need to provide a Function object that has 3 components (the two
-   * velocities and the pressure), even though you are only interested in the
-   * first two of them. interpolate_boundary_values() will then call this
-   * function to obtain a vector of 3 values at each interpolation point but
-   * only take the first two and discard the third. In other words, you are
-   * free to return whatever you like in the third component of the vector
-   * returned by Function::vector_value, but the Function object must state
-   * that it has 3 components.
-   *
-   * If the finite element used has shape functions that are non-zero in more
-   * than one component (in deal.II speak: they are non-primitive), then these
-   * components can presently not be used for interpolating boundary values.
-   * Thus, the elements in the component mask corresponding to the components
-   * of these non-primitive shape functions must be @p false.
-   *
-   * See the general documentation of this namespace for more information.
-   *
-   * @ingroup constraints
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const Mapping<dim, spacedim> &       mapping,
-    const DoFHandlerType<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                        function_map,
-    AffineConstraints<number> &constraints,
-    const ComponentMask &      component_mask = ComponentMask());
-
-  /**
-   * Same function as above, but taking only one pair of boundary indicator
-   * and corresponding boundary function. The same comments apply as for the
-   * previous function, in particular about the use of the component mask and
-   * the requires size of the function object.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const Mapping<dim, spacedim> &       mapping,
-    const DoFHandlerType<dim, spacedim> &dof,
-    const types::boundary_id             boundary_component,
-    const Function<spacedim, number> &   boundary_function,
-    AffineConstraints<number> &          constraints,
-    const ComponentMask &                component_mask = ComponentMask());
-
-  /**
-   * Call the other interpolate_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
-   * apply as for the previous function, in particular about the use of the
-   * component mask and the requires size of the function object.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const DoFHandlerType<dim, spacedim> &dof,
-    const types::boundary_id             boundary_component,
-    const Function<spacedim, number> &   boundary_function,
-    AffineConstraints<number> &          constraints,
-    const ComponentMask &                component_mask = ComponentMask());
-
-
-  /**
-   * Call the other interpolate_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
-   * apply as for the previous function, in particular about the use of the
-   * component mask and the requires size of the function object.
-   *
-   * @ingroup constraints
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename number>
-  void
-  interpolate_boundary_values(
-    const DoFHandlerType<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                        function_map,
-    AffineConstraints<number> &constraints,
-    const ComponentMask &      component_mask = ComponentMask());
-
-
-  /**
-   * Project a function or a set of functions to the boundary of the domain.
-   * In other words, compute the solution of the following problem: Find $u_h
-   * \in V_h$ (where $V_h$ is the finite element space represented by the
-   * DoFHandler argument of this function) so that
-   * @f{align*}{
-   * \int_{\Gamma} \varphi_i u_h
-   * = \sum_{k \in {\cal K}} \int_{\Gamma_k} \varphi_i f_k,
-   * \qquad \forall \varphi_i \in V_h
-   * @f}
-   * where $\Gamma = \bigcup_{k \in {\cal K}} \Gamma_k$, $\Gamma_k \subset
-   * \partial\Omega$, $\cal K$ is the set of indices and $f_k$ the
-   * corresponding boundary functions represented in the function map argument
-   * @p boundary_values to this function, and the integrals are evaluated by
-   * quadrature. This problem has a non-unique solution in the interior, but
-   * it is well defined for the degrees of freedom on the part of the
-   * boundary, $\Gamma$, for which we do the integration. The values of
-   * $u_h|_\Gamma$, i.e., the nodal values of the degrees of freedom of this
-   * function along the boundary, are then what is computed by this function.
-   *
-   * In case this function is used with $H_{div}$ conforming finite element
-   * space, the solution of a different problem is computed, namely: Find
-   * $\vec{u}_h \in V_h \subset H(\text{div}; \Omega)$ so that
-   * @f{align*}{
-   * \int_{\Gamma} (\vec{\varphi}_i \cdot \vec{n}) (\vec{u}_h \cdot \vec{n})
-   * = \sum_{k \in {\cal K}} \int_{\Gamma_k} (\vec{\varphi}_i \cdot \vec{n})
-   * (\vec{f}_k \cdot \vec{n}),
-   * \qquad \forall \vec{\varphi_i} \in V_h,
-   * @f}
-   * where $\vec{n}$ is an outward normal vector.
-   *
-   * This function throws exception if used with $H_{curl}$ conforming elements,
-   * so the project_boundary_values_curl_conforming() should be used instead.
-   *
-   * @param[in] mapping The mapping that will be used in the transformations
-   * necessary to integrate along the boundary.
-   * @param[in] dof The DoFHandler that describes the finite element space and
-   * the numbering of degrees of freedom.
-   * @param[in] boundary_functions A map from boundary indicators to pointers
-   * to functions that describe the desired values on those parts of the
-   * boundary marked with this boundary indicator (see
-   * @ref GlossBoundaryIndicator "Boundary indicator").
-   * The projection happens on only those parts of the boundary whose
-   * indicators are represented in this map.
-   * @param[in] q The face quadrature used in the integration necessary to
-   * compute the mass matrix and right hand side of the projection.
-   * @param[out] boundary_values The result of this function. It is a map
-   * containing all indices of degrees of freedom at the boundary (as covered
-   * by the boundary parts in @p boundary_functions) and the computed dof
-   * value for this degree of freedom. For each degree of freedom at the
-   * boundary, if its index already exists in @p boundary_values then its
-   * boundary value will be overwritten, otherwise a new entry with proper
-   * index and boundary value for this degree of freedom will be inserted into
-   * @p boundary_values.
-   * @param[in] component_mapping It is sometimes convenient to project a
-   * vector-valued function onto only parts of a finite element space (for
-   * example, to project a function with <code>dim</code> components onto the
-   * velocity components of a <code>dim+1</code> component DoFHandler for a
-   * Stokes problem). To allow for this, this argument allows components to be
-   * remapped. If the vector is not empty, it has to have one entry for each
-   * vector component of the finite element used in @p dof. This entry is the
-   * component number in @p boundary_functions that should be used for this
-   * component in @p dof. By default, no remapping is applied.
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  project_boundary_values(
-    const Mapping<dim, spacedim> &   mapping,
-    const DoFHandler<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        boundary_functions,
-    const Quadrature<dim - 1> &                q,
-    std::map<types::global_dof_index, number> &boundary_values,
-    std::vector<unsigned int>                  component_mapping = {});
-
-  /**
-   * Call the project_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>.
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  project_boundary_values(
-    const DoFHandler<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        boundary_function,
-    const Quadrature<dim - 1> &                q,
-    std::map<types::global_dof_index, number> &boundary_values,
-    std::vector<unsigned int>                  component_mapping = {});
-
-  /**
-   * Same as above, but for objects of type hp::DoFHandler
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  project_boundary_values(
-    const hp::MappingCollection<dim, spacedim> &mapping,
-    const hp::DoFHandler<dim, spacedim> &       dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        boundary_functions,
-    const hp::QCollection<dim - 1> &           q,
-    std::map<types::global_dof_index, number> &boundary_values,
-    std::vector<unsigned int>                  component_mapping = {});
-
-  /**
-   * Call the project_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>.
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  project_boundary_values(
-    const hp::DoFHandler<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                                        boundary_function,
-    const hp::QCollection<dim - 1> &           q,
-    std::map<types::global_dof_index, number> &boundary_values,
-    std::vector<unsigned int>                  component_mapping = {});
-
-  /**
-   * Project a function to the boundary of the domain, using the given
-   * quadrature formula for the faces. This function identifies the degrees of
-   * freedom subject to Dirichlet boundary conditions, adds them to the list
-   * of constrained DoFs in @p constraints and sets the respective
-   * inhomogeneity to the value resulting from the projection operation. If
-   * this routine encounters a DoF that already is constrained (for instance
-   * by a hanging node constraint, see below, or any other type of constraint,
-   * e.g. from periodic boundary conditions), the old setting of the
-   * constraint (dofs the entry is constrained to, inhomogeneities) is kept
-   * and nothing happens.
-   *
-   * @note When combining adaptively refined meshes with hanging node
-   * constraints and boundary conditions like from the current function within
-   * one AffineConstraints object, the hanging node constraints should always
-   * be set first, and then the boundary conditions since boundary conditions
-   * are not set in the second operation on degrees of freedom that are
-   * already constrained. This makes sure that the discretization remains
-   * conforming as is needed. See the discussion on conflicting constraints in
-   * the module on
-   * @ref constraints.
-   *
-   * If @p component_mapping is empty, it is assumed that the number of
-   * components of @p boundary_function matches that of the finite element
-   * used by @p dof.
-   *
-   * In 1d, projection equals interpolation. Therefore,
-   * interpolate_boundary_values is called.
-   *
-   * @arg @p component_mapping: if the components in @p boundary_functions and
-   * @p dof do not coincide, this vector allows them to be remapped. If the
-   * vector is not empty, it has to have one entry for each component in @p
-   * dof. This entry is the component number in @p boundary_functions that
-   * should be used for this component in @p dof. By default, no remapping is
-   * applied.
-   *
-   * @ingroup constraints
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  project_boundary_values(
-    const Mapping<dim, spacedim> &   mapping,
-    const DoFHandler<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                        boundary_functions,
-    const Quadrature<dim - 1> &q,
-    AffineConstraints<number> &constraints,
-    std::vector<unsigned int>  component_mapping = {});
-
-  /**
-   * Call the project_boundary_values() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>.
-   *
-   * @ingroup constraints
-   */
-  template <int dim, int spacedim, typename number>
-  void
-  project_boundary_values(
-    const DoFHandler<dim, spacedim> &dof,
-    const std::map<types::boundary_id, const Function<spacedim, number> *>
-      &                        boundary_function,
-    const Quadrature<dim - 1> &q,
-    AffineConstraints<number> &constraints,
-    std::vector<unsigned int>  component_mapping = {});
-
-
-  /**
-   * Compute constraints that correspond to boundary conditions of the form
-   * $\vec{n}\times\vec{u}=\vec{n}\times\vec{f}$, i.e. the tangential
-   * components of $u$ and $f$ shall coincide.
-   *
-   * If the AffineConstraints @p constraints contained values or other
-   * constraints before, the new ones are added or the old ones overwritten,
-   * if a node of the boundary part to be used was already in the list of
-   * constraints. This is handled by using inhomogeneous constraints. Please
-   * note that when combining adaptive meshes and this kind of constraints,
-   * the Dirichlet conditions should be set first, and then completed by
-   * hanging node constraints, in order to make sure that the discretization
-   * remains consistent. See the discussion on conflicting constraints in the
-   * module on
-   * @ref constraints.
-   *
-   * This function is explicitly written to use with the FE_Nedelec elements.
-   * Thus it throws an exception, if it is called with other finite elements.
-   *
-   * The second argument of this function denotes the first vector component
-   * in the finite element that corresponds to the vector function that you
-   * want to constrain. For example, if we want to solve Maxwell's equations
-   * in 3d and the finite element has components $(E_x,E_y,E_z,B_x,B_y,B_z)$
-   * and we want the boundary conditions
-   * $\vec{n}\times\vec{B}=\vec{n}\times\vec{f}$, then @p
-   * first_vector_component would be 3. Vectors are implicitly assumed to have
-   * exactly <code>dim</code> components that are ordered in the same way as
-   * we usually order the coordinate directions, i.e. $x$-, $y$-, and finally
-   * $z$-component.
-   *
-   * The parameter @p boundary_component corresponds to the number @p
-   * boundary_id of the face. numbers::internal_face_boundary_id is an illegal
-   * value, since it is reserved for interior faces.
-   *
-   * The last argument is denoted to compute the normal vector $\vec{n}$ at
-   * the boundary points.
-   *
-   * <h4>Computing constraints</h4>
-   *
-   * To compute the constraints we use projection-based interpolation as
-   * proposed in Solin, Segeth and Dolezel (Higher order finite elements,
-   * Chapman&amp;Hall, 2004) on every face located at the boundary.
-   *
-   * First one projects $\vec{f}$ on the lowest-order edge shape functions.
-   * Then the remaining part $(I-P_0)\vec{f}$ of the function is projected on
-   * the remaining higher-order edge shape functions. In the last step we
-   * project $(I-P_0-P_e)\vec{f}$ on the bubble shape functions defined on the
-   * face.
-   *
-   * @deprecated Use the project_boundary_values_curl_conforming_l2() function
-   * instead of this one.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim>
-  DEAL_II_DEPRECATED void
-  project_boundary_values_curl_conforming(
-    const DoFHandler<dim> &      dof_handler,
-    const unsigned int           first_vector_component,
-    const Function<dim, double> &boundary_function,
-    const types::boundary_id     boundary_component,
-    AffineConstraints<double> &  constraints,
-    const Mapping<dim> &         mapping = StaticMappingQ1<dim>::mapping);
-
-  /**
-   * Same as above for the hp-namespace.
-   *
-   * @deprecated Use the project_boundary_values_curl_conforming_l2() function
-   * instead of this one.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim>
-  DEAL_II_DEPRECATED void
-  project_boundary_values_curl_conforming(
-    const hp::DoFHandler<dim> &            dof_handler,
-    const unsigned int                     first_vector_component,
-    const Function<dim, double> &          boundary_function,
-    const types::boundary_id               boundary_component,
-    AffineConstraints<double> &            constraints,
-    const hp::MappingCollection<dim, dim> &mapping_collection =
-      hp::StaticMappingQ1<dim>::mapping_collection);
-
-  /**
-   * This function is an updated version of the
-   * project_boundary_values_curl_conforming function. The intention is to fix
-   * a problem when using the previous function in conjunction with non-
-   * rectangular geometries (i.e. elements with non-rectangular faces). The
-   * L2-projection method used has been taken from the paper "Electromagnetic
-   * scattering simulation using an H (curl) conforming hp finite element
-   * method in three dimensions" by PD Ledger, K Morgan and O Hassan ( Int. J.
-   * Num. Meth. Fluids, Volume 53, Issue 8, pages 1267–1296).
-   *
-   * This function will compute constraints that correspond to Dirichlet
-   * boundary conditions of the form
-   * $\vec{n}\times\vec{E}=\vec{n}\times\vec{F}$ i.e. the tangential
-   * components of $\vec{E}$ and $f$ shall coincide.
-   *
-   * <h4>Computing constraints</h4>
-   *
-   * To compute the constraints we use a projection method based upon the
-   * paper mentioned above. In 2D this is done in a single stage for the edge-
-   * based shape functions, regardless of the order of the finite element. In
-   * 3D this is done in two stages, edges first and then faces.
-   *
-   * For each cell, each edge, $e$, is projected by solving the linear system
-   * $Ax=b$ where $x$ is the vector of constraints on degrees of freedom on the
-   * edge and
-   *
-   * $A_{ij} = \int_{e} (\vec{s}_{i}\cdot\vec{t})(\vec{s}_{j}\cdot\vec{t}) dS$
-   *
-   * $b_{i} = \int_{e} (\vec{s}_{i}\cdot\vec{t})(\vec{F}\cdot\vec{t}) dS$
-   *
-   * with $\vec{s}_{i}$ the $i^{th}$ shape function and $\vec{t}$ the tangent
-   * vector.
-   *
-   * Once all edge constraints, $x$, have been computed, we may compute the
-   * face constraints in a similar fashion, taking into account the residuals
-   * from the edges.
-   *
-   * For each face on the cell, $f$, we solve the linear system $By=c$ where
-   * $y$ is the vector of constraints on degrees of freedom on the face and
-   *
-   * $B_{ij} = \int_{f} (\vec{n} \times \vec{s}_{i}) \cdot (\vec{n} \times
-   * \vec{s}_{j}) dS$
-   *
-   * $c_{i} = \int_{f} (\vec{n} \times \vec{r}) \cdot (\vec{n} \times
-   * \vec{s}_i) dS$
-   *
-   * and $\vec{r} = \vec{F} - \sum_{e \in f} \sum{i \in e} x_{i}\vec{s}_i$,
-   * the edge residual.
-   *
-   * The resulting constraints are then given in the solutions $x$ and $y$.
-   *
-   * If the AffineConstraints @p constraints contained values or other
-   * constraints before, the new ones are added or the old ones overwritten,
-   * if a node of the boundary part to be used was already in the list of
-   * constraints. This is handled by using inhomogeneous constraints. Please
-   * note that when combining adaptive meshes and this kind of constraints,
-   * the Dirichlet conditions should be set first, and then completed by
-   * hanging node constraints, in order to make sure that the discretization
-   * remains consistent. See the discussion on conflicting constraints in the
-   * module on
-   * @ref constraints.
-   *
-   * <h4>Arguments to this function</h4>
-   *
-   * This function is explicitly for use with FE_Nedelec elements, or with
-   * FESystem elements which contain FE_Nedelec elements. It will throw an
-   * exception if called with any other finite element. The user must ensure
-   * that FESystem elements are correctly setup when using this function as
-   * this check not possible in this case.
-   *
-   * The second argument of this function denotes the first vector component
-   * of the finite element which corresponds to the vector function that you
-   * wish to constrain. For example, if we are solving Maxwell's equations in
-   * 3D and have components $(E_x,E_y,E_z,B_x,B_y,B_z)$ and we want the
-   * boundary conditions $\vec{n}\times\vec{B}=\vec{n}\times\vec{f}$, then @p
-   * first_vector_component would be 3. The @p boundary_function must return 6
-   * components in this example, with the first 3 corresponding to $\vec{E}$
-   * and the second 3 corresponding to $\vec{B}$. Vectors are implicitly
-   * assumed to have exactly <code>dim</code> components that are ordered in
-   * the same way as we usually order the coordinate directions, i.e. $x$-,
-   * $y$-, and finally $z$-component.
-   *
-   * The parameter @p boundary_component corresponds to the number @p
-   * boundary_id of the face. numbers::internal_face_boundary_id is an illegal
-   * value, since it is reserved for interior faces.
-   *
-   * The last argument is denoted to compute the normal vector $\vec{n}$ at
-   * the boundary points.
-   *
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, typename number>
-  void
-  project_boundary_values_curl_conforming_l2(
-    const DoFHandler<dim> &      dof_handler,
-    const unsigned int           first_vector_component,
-    const Function<dim, number> &boundary_function,
-    const types::boundary_id     boundary_component,
-    AffineConstraints<number> &  constraints,
-    const Mapping<dim> &         mapping = StaticMappingQ1<dim>::mapping);
-
-
-  /**
-   * hp-namespace version of project_boundary_values_curl_conforming_l2
-   * (above).
-   *
-   * @ingroup constraints
-   */
-  template <int dim, typename number>
-  void
-  project_boundary_values_curl_conforming_l2(
-    const hp::DoFHandler<dim> &            dof_handler,
-    const unsigned int                     first_vector_component,
-    const Function<dim, number> &          boundary_function,
-    const types::boundary_id               boundary_component,
-    AffineConstraints<number> &            constraints,
-    const hp::MappingCollection<dim, dim> &mapping_collection =
-      hp::StaticMappingQ1<dim>::mapping_collection);
-
-
-  /**
-   * Compute constraints that correspond to boundary conditions of the form
-   * $\vec{n}^T\vec{u}=\vec{n}^T\vec{f}$, i.e. the normal components of the
-   * solution $u$ and a given $f$ shall coincide. The function $f$ is given by
-   * @p boundary_function and the resulting constraints are added to @p
-   * constraints for faces with boundary indicator @p boundary_component.
-   *
-   * This function is explicitly written to use with the FE_RaviartThomas
-   * elements. Thus it throws an exception, if it is called with other finite
-   * elements.
-   *
-   * If the AffineConstraints object @p constraints contained values or other
-   * constraints before, the new ones are added or the old ones overwritten,
-   * if a node of the boundary part to be used was already in the list of
-   * constraints. This is handled by using inhomogeneous constraints. Please
-   * note that when combining adaptive meshes and this kind of constraints,
-   * the Dirichlet conditions should be set first, and then completed by
-   * hanging node constraints, in order to make sure that the discretization
-   * remains consistent. See the discussion on conflicting constraints in the
-   * module on
-   * @ref constraints.
-   *
-   * The argument @p first_vector_component denotes the first vector component
-   * in the finite element that corresponds to the vector function $\vec{u}$
-   * that you want to constrain. Vectors are implicitly assumed to have
-   * exactly <code>dim</code> components that are ordered in the same way as
-   * we usually order the coordinate directions, i.e., $x$-, $y$-, and finally
-   * $z$-component.
-   *
-   * The parameter @p boundary_component corresponds to the @p boundary_id of
-   * the faces where the boundary conditions are applied.
-   * numbers::internal_face_boundary_id is an illegal value, since it is
-   * reserved for interior faces. The @p mapping is used to compute the normal
-   * vector $\vec{n}$ at the boundary points.
-   *
-   * <h4>Computing constraints</h4>
-   *
-   * To compute the constraints we use interpolation operator proposed in
-   * Brezzi, Fortin (Mixed and Hybrid (Finite Element Methods, Springer, 1991)
-   * on every face located at the boundary.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim>
-  void
-  project_boundary_values_div_conforming(
-    const DoFHandler<dim> &      dof_handler,
-    const unsigned int           first_vector_component,
-    const Function<dim, double> &boundary_function,
-    const types::boundary_id     boundary_component,
-    AffineConstraints<double> &  constraints,
-    const Mapping<dim> &         mapping = StaticMappingQ1<dim>::mapping);
-
-  /**
-   * Same as above for the hp-namespace.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim>
-  void
-  project_boundary_values_div_conforming(
-    const hp::DoFHandler<dim> &            dof_handler,
-    const unsigned int                     first_vector_component,
-    const Function<dim, double> &          boundary_function,
-    const types::boundary_id               boundary_component,
-    AffineConstraints<double> &            constraints,
-    const hp::MappingCollection<dim, dim> &mapping_collection =
-      hp::StaticMappingQ1<dim>::mapping_collection);
-
-
-  /**
-   * This function computes the constraints that correspond to boundary
-   * conditions of the form $\vec u \cdot \vec n=\vec u_\Gamma \cdot \vec n$,
-   * i.e., normal flux constraints where $\vec u$ is a vector-valued solution
-   * variable and $\vec u_\Gamma$ is a prescribed vector field whose normal
-   * component we want to be equal to the normal component of the solution.
-   * These conditions have exactly the form handled by the
-   * AffineConstraints class, in that they relate a <i>linear
-   * combination</i> of boundary degrees of freedom to a corresponding
-   * value (the inhomogeneity of the constraint). Consequently, the current
-   * function creates a list of constraints that are written into an
-   * AffineConstraints container. This object may already have some
-   * content, for example from hanging node constraints, that remains
-   * untouched. These constraints have to be applied to the linear system
-   * like any other such constraints, i.e., you have to condense the linear
-   * system with the constraints before solving, and you have to distribute
-   * the solution vector afterwards.
-   *
-   * This function treats a more general case than
-   * VectorTools::compute_no_normal_flux_constraints() (which can only handle
-   * the case where $\vec u_\Gamma \cdot \vec n = 0$, and is used in
-   * step-31 and step-32). However, because everything that would apply
-   * to that function also applies as a special case to the current
-   * function, the following discussion is relevant to both.
-   *
-   * @note This function doesn't make much sense in 1d, so it throws an
-   *   exception if @p dim equals one.
-   *
-   *
-   * <h4>Arguments to this function</h4>
-   *
-   * The second argument of this function denotes the first vector component
-   * in the finite element that corresponds to the vector function that you
-   * want to constrain. For example, if we were solving a Stokes equation in
-   * 2d and the finite element had components $(u,v,p)$, then @p
-   * first_vector_component needs to be zero if you intend to constraint
-   * the vector $(u,v)^T \cdot \vec n = \vec u_\Gamma \cdot \vec n$.
-   * On the other hand, if we solved the
-   * Maxwell equations in 3d and the finite element has components
-   * $(E_x,E_y,E_z,B_x,B_y,B_z)$ and we want the boundary condition $\vec
-   * B\cdot \vec n=\vec B_\Gamma\cdot \vec n$, then @p first_vector_component
-   * would be 3. Vectors are implicitly assumed to have exactly
-   * <code>dim</code> components that are ordered in the same way as we
-   * usually order the coordinate directions, i.e. $x$-, $y$-, and finally
-   * $z$-component. The function assumes, but can't check, that the vector
-   * components in the range
-   * <code>[first_vector_component,first_vector_component+dim)</code> come
-   * from the same base finite element. For example, in the Stokes example
-   * above, it would not make sense to use a
-   * <code>FESystem@<dim@>(FE_Q@<dim@>(2), 1, FE_Q@<dim@>(1), dim)</code>
-   * (note that the first velocity vector component is a $Q_2$ element,
-   * whereas all the other ones are $Q_1$ elements) as there would be points
-   * on the boundary where the $x$-velocity is defined but no corresponding
-   * $y$- or $z$-velocities.
-   *
-   * The third argument denotes the set of boundary indicators on which the
-   * boundary condition is to be enforced. Note that, as explained below, this
-   * is one of the few functions where it makes a difference where we call the
-   * function multiple times with only one boundary indicator, or whether we
-   * call the function once with the whole set of boundary indicators at once.
-   *
-   * Argument four (@p function_map) describes the boundary function $\vec
-   * u_\Gamma$ for each boundary id. The function <code>function_map[id]</code>
-   * is used on boundary with id @p id taken from the set @p boundary_ids.
-   * Each function in @p function_map is expected to have @p dim
-   * components, which are used independent of @p first_vector_component.
-   *
-   * The mapping argument is used to compute the boundary points at which the
-   * function needs to request the normal vector $\vec n$ from the boundary
-   * description.
-   *
-   * @note When combining adaptively refined meshes with hanging node
-   * constraints and boundary conditions like from the current function within
-   * one AffineConstraints object, the hanging node constraints should always
-   * be set first, and then the boundary conditions since boundary conditions
-   * are not set in the second operation on degrees of freedom that are
-   * already constrained. This makes sure that the discretization remains
-   * conforming as is needed. See the discussion on conflicting constraints in
-   * the module on
-   * @ref constraints.
-   *
-   *
-   * <h4>Computing constraints in 2d</h4>
-   *
-   * Computing these constraints requires some smarts. The main question
-   * revolves around the question what the normal vector is. Consider the
-   * following situation:
-   *
-   * <p ALIGN="center">
-   * @image html no_normal_flux_1.png
-   * </p>
-   *
-   * Here, we have two cells that use a bilinear mapping (i.e.,
-   * MappingQGeneric(1)). Consequently, for each of the cells, the normal
-   * vector is perpendicular to the straight edge. If the two edges at the top
-   * and right are meant to approximate a curved boundary (as indicated by the
-   * dashed line), then neither of the two computed normal vectors are equal
-   * to the exact normal vector (though they approximate it as the mesh is
-   * refined further). What is worse, if we constrain $\vec u \cdot \vec n=
-   * \vec u_\Gamma \cdot \vec n$ at the common vertex with the normal vector
-   * from both cells, then we constrain the vector $\vec u$ with respect to
-   * two linearly independent vectors; consequently, the constraint would be
-   * $\vec u=\vec u_\Gamma$ at this point (i.e. <i>all</i> components of the
-   * vector), which is not what we wanted.
-   *
-   * To deal with this situation, the algorithm works in the following way: at
-   * each point where we want to constrain $\vec u$, we first collect all
-   * normal vectors that adjacent cells might compute at this point. We then
-   * do not constrain $\vec u \cdot \vec n=\vec u_\Gamma \cdot \vec n$ for
-   * <i>each</i> of these normal vectors but only for the <i>average</i> of
-   * the normal vectors. In the example above, we therefore record only a
-   * single constraint $\vec u \cdot \vec {\bar n}=\vec u_\Gamma \cdot \vec
-   * {\bar n}$, where $\vec {\bar n}$ is the average of the two indicated
-   * normal vectors.
-   *
-   * Unfortunately, this is not quite enough. Consider the situation here:
-   *
-   * <p ALIGN="center">
-   * @image html no_normal_flux_2.png
-   * </p>
-   *
-   * If again the top and right edges approximate a curved boundary, and the
-   * left boundary a separate boundary (for example straight) so that the
-   * exact boundary has indeed a corner at the top left vertex, then the above
-   * construction would not work: here, we indeed want the constraint that
-   * $\vec u$ at this point (because the normal velocities with respect to
-   * both the left normal as well as the top normal vector should be zero),
-   * not that the velocity in the direction of the average normal vector is
-   * zero.
-   *
-   * Consequently, we use the following heuristic to determine whether all
-   * normal vectors computed at one point are to be averaged: if two normal
-   * vectors for the same point are computed on <i>different</i> cells, then
-   * they are to be averaged. This covers the first example above. If they are
-   * computed from the same cell, then the fact that they are different is
-   * considered indication that they come from different parts of the boundary
-   * that might be joined by a real corner, and must not be averaged.
-   *
-   * There is one problem with this scheme. If, for example, the same domain
-   * we have considered above, is discretized with the following mesh, then we
-   * get into trouble:
-   *
-   * <p ALIGN="center">
-   * @image html no_normal_flux_3.png
-   * </p>
-   *
-   * Here, the algorithm assumes that the boundary does not have a corner at
-   * the point where faces $F1$ and $F2$ join because at that point there are
-   * two different normal vectors computed from different cells. If you intend
-   * for there to be a corner of the exact boundary at this point, the only
-   * way to deal with this is to assign the two parts of the boundary
-   * different boundary indicators and call this function twice, once for each
-   * boundary indicators; doing so will yield only one normal vector at this
-   * point per invocation (because we consider only one boundary part at a
-   * time), with the result that the normal vectors will not be averaged. This
-   * situation also needs to be taken into account when using this function
-   * around reentrant corners on Cartesian meshes. If normal-flux boundary
-   * conditions are to be enforced on non-Cartesian meshes around reentrant
-   * corners, one may even get cycles in the constraints as one will in
-   * general constrain different components from the two sides. In that case,
-   * set a no-slip constraint on the reentrant vertex first.
-   *
-   *
-   * <h4>Computing constraints in 3d</h4>
-   *
-   * The situation is more complicated in 3d. Consider the following case
-   * where we want to compute the constraints at the marked vertex:
-   *
-   * <p ALIGN="center">
-   * @image html no_normal_flux_4.png
-   * </p>
-   *
-   * Here, we get four different normal vectors, one from each of the four
-   * faces that meet at the vertex. Even though they may form a complete set
-   * of vectors, it is not our intent to constrain all components of the
-   * vector field at this point. Rather, we would like to still allow
-   * tangential flow, where the term "tangential" has to be suitably defined.
-   *
-   * In a case like this, the algorithm proceeds as follows: for each cell
-   * that has computed two tangential vectors at this point, we compute the
-   * unconstrained direction as the outer product of the two tangential
-   * vectors (if necessary multiplied by minus one). We then average these
-   * tangential vectors. Finally, we compute constraints for the two
-   * directions perpendicular to this averaged tangential direction.
-   *
-   * There are cases where one cell contributes two tangential directions and
-   * another one only one; for example, this would happen if both top and
-   * front faces of the left cell belong to the boundary selected whereas only
-   * the top face of the right cell belongs to it, maybe indicating that the
-   * entire front part of the domain is a smooth manifold whereas the top
-   * really forms two separate manifolds that meet in a ridge, and that
-   * normal-flux boundary conditions are only desired on the front manifold
-   * and the right one on top. In cases like these, it's difficult to define
-   * what should happen. The current implementation simply ignores the one
-   * contribution from the cell that only contributes one normal vector. In
-   * the example shown, this is acceptable because the normal vector for the
-   * front face of the left cell is the same as the normal vector provided by
-   * the front face of the right cell (the surface is planar) but it would be
-   * a problem if the front manifold would be curved. Regardless, it is
-   * unclear how one would proceed in this case and ignoring the single cell
-   * is likely the best one can do.
-   *
-   *
-   * <h4>Results</h4>
-   *
-   * Because it makes for good pictures, here are two images of vector fields
-   * on a circle and on a sphere to which the constraints computed by this
-   * function have been applied (for illustration purposes, we enforce zero
-   * normal flux, which can more easily be computed using
-   * VectorTools::compute_no_normal_flux_constraints(), as this must
-   * lead to a <i>tangential</i> vector field):
-   *
-   * <p ALIGN="center">
-   * @image html no_normal_flux_5.png
-   * @image html no_normal_flux_6.png
-   * </p>
-   *
-   * The vectors fields are not physically reasonable but the tangentiality
-   * constraint is clearly enforced. The fact that the vector fields are zero
-   * at some points on the boundary is an artifact of the way it is created,
-   * it is not constrained to be zero at these points.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
-  void
-  compute_nonzero_normal_flux_constraints(
-    const DoFHandlerType<dim, spacedim> &dof_handler,
-    const unsigned int                   first_vector_component,
-    const std::set<types::boundary_id> & boundary_ids,
-    const std::map<types::boundary_id, const Function<spacedim> *>
-      &                           function_map,
-    AffineConstraints<double> &   constraints,
-    const Mapping<dim, spacedim> &mapping = StaticMappingQ1<dim>::mapping);
-
-  /**
-   * This function does the same as the
-   * compute_nonzero_normal_flux_constraints() function (see there for more
-   * information), but for the simpler case of homogeneous normal-flux
-   * constraints, i.e., for imposing the condition
-   * $\vec u \cdot \vec n= 0$. This function is used in step-31 and step-32.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
-  void
-  compute_no_normal_flux_constraints(
-    const DoFHandlerType<dim, spacedim> &dof_handler,
-    const unsigned int                   first_vector_component,
-    const std::set<types::boundary_id> & boundary_ids,
-    AffineConstraints<double> &          constraints,
-    const Mapping<dim, spacedim> &mapping = StaticMappingQ1<dim>::mapping);
-
-  /**
-   * Compute the constraints that correspond to boundary conditions of the
-   * form $\vec u \times \vec n=\vec u_\Gamma \times \vec n$, i.e., tangential
-   * flow constraints where $\vec u$ is a vector-valued solution
-   * variable and $\vec u_\Gamma$ is prescribed vector field whose tangential
-   * component(s) we want to be equal to the tangential component(s) of the
-   * solution. This function constrains exactly those dim-1 vector-valued
-   * components that are left unconstrained by
-   * VectorTools::compute_no_normal_flux_constraints(), and leaves the one
-   * component unconstrained that is constrained by that function.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
-  void
-  compute_nonzero_tangential_flux_constraints(
-    const DoFHandlerType<dim, spacedim> &dof_handler,
-    const unsigned int                   first_vector_component,
-    const std::set<types::boundary_id> & boundary_ids,
-    const std::map<types::boundary_id, const Function<spacedim> *>
-      &                           function_map,
-    AffineConstraints<double> &   constraints,
-    const Mapping<dim, spacedim> &mapping = StaticMappingQ1<dim>::mapping);
-
-  /**
-   * Same as above for homogeneous tangential-flux constraints.
-   *
-   * @ingroup constraints
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
-  void
-  compute_normal_flux_constraints(
-    const DoFHandlerType<dim, spacedim> &dof_handler,
-    const unsigned int                   first_vector_component,
-    const std::set<types::boundary_id> & boundary_ids,
-    AffineConstraints<double> &          constraints,
-    const Mapping<dim, spacedim> &mapping = StaticMappingQ1<dim>::mapping);
-
-
-  //@}
-  /**
-   * @name Assembling of right hand sides
-   */
-  //@{
-
-  /**
-   * Create a right hand side vector. Prior content of the given @p rhs_vector
-   * vector is deleted.
-   *
-   * See the general documentation of this namespace for further information.
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_right_hand_side(
-    const Mapping<dim, spacedim> &                             mapping,
-    const DoFHandler<dim, spacedim> &                          dof,
-    const Quadrature<dim> &                                    q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const AffineConstraints<typename VectorType::value_type> & constraints =
-      AffineConstraints<typename VectorType::value_type>());
-
-  /**
-   * Call the create_right_hand_side() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_right_hand_side(
-    const DoFHandler<dim, spacedim> &                          dof,
-    const Quadrature<dim> &                                    q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const AffineConstraints<typename VectorType::value_type> & constraints =
-      AffineConstraints<typename VectorType::value_type>());
-
-  /**
-   * Like the previous set of functions, but for hp objects.
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_right_hand_side(
-    const hp::MappingCollection<dim, spacedim> &               mapping,
-    const hp::DoFHandler<dim, spacedim> &                      dof,
-    const hp::QCollection<dim> &                               q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const AffineConstraints<typename VectorType::value_type> & constraints =
-      AffineConstraints<typename VectorType::value_type>());
-
-  /**
-   * Like the previous set of functions, but for hp objects.
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_right_hand_side(
-    const hp::DoFHandler<dim, spacedim> &                      dof,
-    const hp::QCollection<dim> &                               q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const AffineConstraints<typename VectorType::value_type> & constraints =
-      AffineConstraints<typename VectorType::value_type>());
-
-  /**
-   * Create a right hand side vector for a point source at point @p p. In
-   * other words, it creates a vector $F$ so that $F_i = \int_\Omega
-   * \delta(x-p) \varphi_i(x) dx$ where $\varphi_i$ are the shape functions
-   * described by @p dof_handler and @p p is the point at which the delta
-   * function is located. Prior content of the given @p rhs_vector
-   * vector is deleted. This function is for the case of a scalar finite
-   * element.
-   *
-   * This function is typically used in one of these two contexts:
-   * - Let's say you want to solve the same kind of problems many times
-   *   over, with different values for right hand sides or coefficients,
-   *   and then evaluate the solution at the same point every time. You
-   *   could do this by calling VectorTools::point_value() after each
-   *   solve, or you could realize that to evaluate the solution $u_h$
-   *   at a point $p$, you could rearrange operations like this:
-   *   @f{align*}{
-   *     u_h(p) &= \sum_j U_j \varphi_j(p) = \sum_j U_j F_j
-   *       \\   &= U \cdot F
-   *   @f}
-   *   with the vector as defined above. In other words, point evaluation
-   *   can be achieved with just a single vector-vector product, and the
-   *   vector $F$ can be computed once and for all and reused
-   *   for each solve, without having to go through the mesh every time
-   *   to find out which cell (and where in the cell) the point $p$ is
-   *   located.
-   * - This function is also useful if you wanted to compute the Green's
-   *   function for the problem you are solving. This is because the
-   *   Green's function $G(x,p)$ is defined by
-   *   @f{align*}{
-   *     L G(x,p) &= \delta(x-p)
-   *   @f}
-   *   where $L$ is the differential operator of your problem. The discrete
-   *   version then requires computing the right hand side vector
-   *   $F_i = \int_\Omega \varphi_i(x) \delta(x-p)$, which is exactly
-   *   the vector computed by the current function.
-   *
-   * While maybe not relevant for documenting <i>what</i> this
-   * function does, it may be interesting to note that delta functions
-   * do not exist in reality, and consequently, using this function
-   * does not model any real situation. This is, because no real
-   * object is able to focus an infinite force density at an
-   * infinitesimally small part of the domain (rather, all real
-   * devices will spread out the force over a finite area); nor is it
-   * possible to measure values at individual points (but all
-   * measurements will somehow be averaged over small areas). Only if
-   * this area is so small that it cannot be resolved by any mesh does
-   * it make sense to model the situation in a way that uses a delta
-   * function with the same overall force or sensitivity. On the other
-   * hand, a situation that is probably more fruitfully simulated with
-   * a delta function is the electric potential of a point source; in
-   * this case, the solution is known to have a logarithmic
-   * singularity (in 2d) or a $\frac{1}{r}$ singularity (in 3d),
-   * neither of which is bounded.
-   *
-   * Mathematically, the use of delta functions typically leads to exact
-   * solutions to which the numerically obtained, approximate solution does
-   * not converge. This is because, taking the Laplace equation as an example,
-   * the error between exact and numerical solution can be bounded by the
-   * expression
-   * @f{align*}{
-   *   \| u-u_h \|_{L_2} \le C h \| \nabla u \|_{L_2}
-   * @f}
-   * but when using a delta function on the right hand side, the term
-   * $\| \nabla u \|_{L_2} = |u|_{H^1}$ is not finite. This can be seen
-   * by using the a-priori bound for solutions of the Laplace equation
-   * $-\Delta u = f$ that states that $|u|_{H^1} \le \|f\|_{H^{-1}}$.
-   * When using a delta function as right hand side, $f(x)=\delta(x-p)$,
-   * one would need to take the $H^{-1}$ norm of a delta function, which
-   * however is not finite because $\delta(\cdot-p) \not\in H^{-1}$.
-   *
-   * The consequence of all of this is that the exact solution of the
-   * Laplace equation with a delta function on the right hand side --
-   * i.e., the <i>Green's function</i> -- has a singularity at $p$ that
-   * is so strong that it cannot be resolved by a finite element
-   * solution, and consequently finite element approximations do not
-   * converge towards the exact solution in any of the usual norms.
-   *
-   * All of this is also the case for all of the other usual second-order
-   * partial differential equations in dimensions two or higher. (Because
-   * in dimension two and higher, $H^1$ functions are not necessarily
-   * continuous, and consequently the delta function is not in the dual
-   * space $H^{-1}$.)
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(const Mapping<dim, spacedim> &   mapping,
-                             const DoFHandler<dim, spacedim> &dof_handler,
-                             const Point<spacedim> &          p,
-                             Vector<double> &                 rhs_vector);
-
-  /**
-   * Call the create_point_source_vector() function, see above, with
-   * an implied default $Q_1$ mapping object.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(const DoFHandler<dim, spacedim> &dof_handler,
-                             const Point<spacedim> &          p,
-                             Vector<double> &                 rhs_vector);
-
-  /**
-   * Like the previous set of functions, but for hp objects.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(
-    const hp::MappingCollection<dim, spacedim> &mapping,
-    const hp::DoFHandler<dim, spacedim> &       dof_handler,
-    const Point<spacedim> &                     p,
-    Vector<double> &                            rhs_vector);
-
-  /**
-   * Like the previous set of functions, but for hp objects. The function uses
-   * an implied default $Q_1$ mapping object. Note that if your hp::DoFHandler
-   * uses any active fe index other than zero, then you need to call the
-   * function above that provides a mapping object for each active fe index.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(const hp::DoFHandler<dim, spacedim> &dof_handler,
-                             const Point<spacedim> &              p,
-                             Vector<double> &                     rhs_vector);
-
-  /**
-   * Create a right hand side vector for a point source at point @p p. This
-   * variation of the function is meant for vector-valued problems with
-   * exactly dim components (it will also work for problems with more than dim
-   * components, and in this case simply consider only the first dim
-   * components of the shape functions). It computes a right hand side that
-   * corresponds to a forcing function that is equal to a delta function times
-   * a given direction. In other words, it creates a vector $F$ so that $F_i =
-   * \int_\Omega [\mathbf d \delta(x-p)] \cdot \varphi_i(x) dx$. Note here that
-   * $\varphi_i$ is a vector-valued function. $\mathbf d$ is the given direction
-   * of the source term $\mathbf d \delta(x-p)$ and corresponds to the @p
-   * direction argument to be passed to this function.
-   *
-   * Prior content of the given @p rhs_vector vector is deleted.
-   *
-   * See the discussion of the first create_point_source_vector() variant for
-   * more on the use of delta functions.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(const Mapping<dim, spacedim> &   mapping,
-                             const DoFHandler<dim, spacedim> &dof_handler,
-                             const Point<spacedim> &          p,
-                             const Point<dim> &               direction,
-                             Vector<double> &                 rhs_vector);
-
-  /**
-   * Call the create_point_source_vector() function for vector-valued finite
-   * elements, see above, with an implied default $Q_1$ mapping object.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(const DoFHandler<dim, spacedim> &dof_handler,
-                             const Point<spacedim> &          p,
-                             const Point<dim> &               direction,
-                             Vector<double> &                 rhs_vector);
-
-  /**
-   * Like the previous set of functions, but for hp objects.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(
-    const hp::MappingCollection<dim, spacedim> &mapping,
-    const hp::DoFHandler<dim, spacedim> &       dof_handler,
-    const Point<spacedim> &                     p,
-    const Point<dim> &                          direction,
-    Vector<double> &                            rhs_vector);
-
-  /**
-   * Like the previous set of functions, but for hp objects. The function uses
-   * an implied default $Q_1$ mapping object. Note that if your hp::DoFHandler
-   * uses any active fe index other than zero, then you need to call the
-   * function above that provides a mapping object for each active fe index.
-   */
-  template <int dim, int spacedim>
-  void
-  create_point_source_vector(const hp::DoFHandler<dim, spacedim> &dof_handler,
-                             const Point<spacedim> &              p,
-                             const Point<dim> &                   direction,
-                             Vector<double> &                     rhs_vector);
-
-  /**
-   * Create a right hand side vector from boundary forces. Prior content of
-   * the given @p rhs_vector vector is deleted.
-   *
-   * See the general documentation of this namespace for further information.
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_boundary_right_hand_side(
-    const Mapping<dim, spacedim> &                             mapping,
-    const DoFHandler<dim, spacedim> &                          dof,
-    const Quadrature<dim - 1> &                                q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const std::set<types::boundary_id> &                       boundary_ids =
-      std::set<types::boundary_id>());
-
-  /**
-   * Call the create_boundary_right_hand_side() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_boundary_right_hand_side(
-    const DoFHandler<dim, spacedim> &                          dof,
-    const Quadrature<dim - 1> &                                q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const std::set<types::boundary_id> &                       boundary_ids =
-      std::set<types::boundary_id>());
-
-  /**
-   * Same as the set of functions above, but for hp objects.
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_boundary_right_hand_side(
-    const hp::MappingCollection<dim, spacedim> &               mapping,
-    const hp::DoFHandler<dim, spacedim> &                      dof,
-    const hp::QCollection<dim - 1> &                           q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const std::set<types::boundary_id> &                       boundary_ids =
-      std::set<types::boundary_id>());
-
-  /**
-   * Call the create_boundary_right_hand_side() function, see above, with a
-   * single Q1 mapping as collection. This function therefore will only work
-   * if the only active fe index in use is zero.
-   *
-   * @see
-   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
-   */
-  template <int dim, int spacedim, typename VectorType>
-  void
-  create_boundary_right_hand_side(
-    const hp::DoFHandler<dim, spacedim> &                      dof,
-    const hp::QCollection<dim - 1> &                           q,
-    const Function<spacedim, typename VectorType::value_type> &rhs,
-    VectorType &                                               rhs_vector,
-    const std::set<types::boundary_id> &                       boundary_ids =
-      std::set<types::boundary_id>());
-
-  //@}
-  /**
-   * @name Evaluation of functions and errors
-   */
-  //@{
-
-  /**
-   * Compute the cellwise error of the finite element solution.  Integrate the
-   * difference between a reference function which is given as a continuous
-   * function object, and a finite element function. The result of this
-   * function is the vector @p difference that contains one value per active
-   * cell $K$ of the triangulation. Each of the values of this vector $d$
-   * equals
-   * @f{align*}{
-   * d_K = \| u-u_h \|_X
-   * @f}
-   * where $X$ denotes the norm chosen and $u$ represents the exact solution.
-   *
-   * It is assumed that the number of components of the function @p
-   * exact_solution matches that of the finite element used by @p dof.
-   *
-   * To compute a global error norm of a finite element solution, use
-   * VectorTools::compute_global_error() with the output vector computed with
-   * this function.
-   *
-   * @param[in] mapping The mapping that is used when integrating the
-   * difference $u-u_h$.
-   * @param[in] dof The DoFHandler object that describes the finite element
-   * space in which the solution vector lives.
-   * @param[in] fe_function A vector with nodal values representing the
-   * numerical approximation $u_h$. This vector needs to correspond to the
-   * finite element space represented by @p dof.
-   * @param[in] exact_solution The exact solution that is used to compute the
-   * error.
-   * @param[out] difference The vector of values $d_K$ computed as above.
-   * @param[in] q The quadrature formula used to approximate the integral
-   * shown above. Note that some quadrature formulas are more useful than
-   * other in integrating $u-u_h$. For example, it is known that the $Q_1$
-   * approximation $u_h$ to the exact solution $u$ of a Laplace equation is
-   * particularly accurate (in fact, superconvergent, i.e. accurate to higher
-   * order) at the 4 Gauss points of a cell in 2d (or 8 points in 3d) that
-   * correspond to a QGauss(2) object. Consequently, because a QGauss(2)
-   * formula only evaluates the two solutions at these particular points,
-   * choosing this quadrature formula may indicate an error far smaller than
-   * it actually is.
-   * @param[in] norm The norm $X$ shown above that should be computed. If the
-   * norm is NormType::Hdiv_seminorm, then the finite element on which this
-   * function is called needs to have at least dim vector components, and the
-   * divergence will be computed on the first div components. This works, for
-   * example, on the finite elements used for the mixed Laplace (step-20) and
-   * the Stokes equations (step-22).
-   * @param[in] weight The additional argument @p weight allows to evaluate
-   * weighted norms.  The weight function may be scalar, establishing a
-   * spatially variable weight in the domain for all components equally. This
-   * may be used, for instance, to only integrate over parts of the domain.
-   * The weight function may also be vector-valued, with as many components as
-   * the finite element: Then, different components get different weights. A
-   * typical application is when the error with respect to only one or a
-   * subset of the solution variables is to be computed, in which case the
-   * other components would have weight values equal to zero. The
-   * ComponentSelectFunction class is particularly useful for this purpose as
-   * it provides such a "mask" weight. The weight function is expected to be
-   * positive, but negative values are not filtered. The default value of this
-   * function, a null pointer, is interpreted as "no weighting function",
-   * i.e., weight=1 in the whole domain for all vector components uniformly.
-   * @param[in] exponent This value denotes the $p$ used in computing
-   * $L^p$-norms and $W^{1,p}$-norms. The value is ignored if a @p norm other
-   * than NormType::Lp_norm, NormType::W1p_norm, or NormType::W1p_seminorm
-   * is chosen.
-   *
-   *
-   * See the general documentation of this namespace for more information.
-   *
-   * @note If the integration here happens over the cells of a
-   * parallel::distribute::Triangulation object, then this function computes
-   * the vector elements $d_K$ for an output vector with as many cells as
-   * there are active cells of the triangulation object of the current
-   * processor. However, not all active cells are in fact locally owned: some
-   * may be ghost or artificial cells (see
-   * @ref GlossGhostCell "here"
-   * and
-   * @ref GlossArtificialCell "here").
-   * The vector computed will, in the case of a distributed triangulation,
-   * contain zeros for cells that are not locally owned. As a consequence, in
-   * order to compute the <i>global</i> $L_2$ error (for example), the errors
-   * from different processors need to be combined, see
-   * VectorTools::compute_global_error().
-   *
-   * Instantiations for this template are provided for some vector types (see
-   * the general documentation of the namespace), but only for InVectors as in
-   * the documentation of the namespace, OutVector only Vector<double> and
-   * Vector<float>.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  void
-  integrate_difference(
-    const Mapping<dim, spacedim> &                           mapping,
-    const DoFHandler<dim, spacedim> &                        dof,
-    const InVector &                                         fe_function,
-    const Function<spacedim, typename InVector::value_type> &exact_solution,
-    OutVector &                                              difference,
-    const Quadrature<dim> &                                  q,
-    const NormType &                                         norm,
-    const Function<spacedim, double> *                       weight   = nullptr,
-    const double                                             exponent = 2.);
-
-  /**
-   * Call the integrate_difference() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  void
-  integrate_difference(
-    const DoFHandler<dim, spacedim> &                        dof,
-    const InVector &                                         fe_function,
-    const Function<spacedim, typename InVector::value_type> &exact_solution,
-    OutVector &                                              difference,
-    const Quadrature<dim> &                                  q,
-    const NormType &                                         norm,
-    const Function<spacedim, double> *                       weight   = nullptr,
-    const double                                             exponent = 2.);
-
-  /**
-   * Same as above for hp.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  void
-  integrate_difference(
-    const hp::MappingCollection<dim, spacedim> &             mapping,
-    const hp::DoFHandler<dim, spacedim> &                    dof,
-    const InVector &                                         fe_function,
-    const Function<spacedim, typename InVector::value_type> &exact_solution,
-    OutVector &                                              difference,
-    const hp::QCollection<dim> &                             q,
-    const NormType &                                         norm,
-    const Function<spacedim, double> *                       weight   = nullptr,
-    const double                                             exponent = 2.);
-
-  /**
-   * Call the integrate_difference() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  void
-  integrate_difference(
-    const hp::DoFHandler<dim, spacedim> &                    dof,
-    const InVector &                                         fe_function,
-    const Function<spacedim, typename InVector::value_type> &exact_solution,
-    OutVector &                                              difference,
-    const hp::QCollection<dim> &                             q,
-    const NormType &                                         norm,
-    const Function<spacedim, double> *                       weight   = nullptr,
-    const double                                             exponent = 2.);
-
-  /**
-   * Compute the cellwise error of the finite element solution.  Integrate the
-   * difference between a reference function which is given as a continuous
-   * function object, and a finite element function. The result of this
-   * function is the vector @p difference that contains one value per active
-   * cell $K$ of the triangulation. Each of the values of this vector $d$
-   * equals
-   * @f{align*}{
-   * d_K = \| u-u_h \|_X
-   * @f}
-   * where $X$ denotes the norm chosen and $u$ represents the exact solution.
-   *
-   * @deprecated Use integrate_difference(const Mapping<dim, spacedim> &, const DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &, OutVector &, const Quadrature<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  DEAL_II_DEPRECATED typename std::enable_if<
-    !std::is_same<typename InVector::value_type, double>::value>::type
-  integrate_difference(const Mapping<dim, spacedim> &    mapping,
-                       const DoFHandler<dim, spacedim> & dof,
-                       const InVector &                  fe_function,
-                       const Function<spacedim, double> &exact_solution,
-                       OutVector &                       difference,
-                       const Quadrature<dim> &           q,
-                       const NormType &                  norm,
-                       const Function<spacedim, double> *weight   = nullptr,
-                       const double                      exponent = 2.);
-
-  /**
-   * Call the integrate_difference() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   *
-   * @deprecated Use integrate_difference(const DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &exact_solution, OutVector &, const Quadrature<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  DEAL_II_DEPRECATED typename std::enable_if<
-    !std::is_same<typename InVector::value_type, double>::value>::type
-  integrate_difference(const DoFHandler<dim, spacedim> & dof,
-                       const InVector &                  fe_function,
-                       const Function<spacedim, double> &exact_solution,
-                       OutVector &                       difference,
-                       const Quadrature<dim> &           q,
-                       const NormType &                  norm,
-                       const Function<spacedim, double> *weight   = nullptr,
-                       const double                      exponent = 2.);
-
-  /**
-   * Same as above for hp.
-   *
-   * @deprecated Use integrate_difference(const hp::MappingCollection<dim, spacedim> &, const hp::DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &, OutVector &, const hp::QCollection<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  DEAL_II_DEPRECATED typename std::enable_if<
-    !std::is_same<typename InVector::value_type, double>::value>::type
-  integrate_difference(const hp::MappingCollection<dim, spacedim> &mapping,
-                       const hp::DoFHandler<dim, spacedim> &       dof,
-                       const InVector &                            fe_function,
-                       const Function<spacedim, double> &exact_solution,
-                       OutVector &                       difference,
-                       const hp::QCollection<dim> &      q,
-                       const NormType &                  norm,
-                       const Function<spacedim, double> *weight   = nullptr,
-                       const double                      exponent = 2.);
-
-  /**
-   * Call the integrate_difference() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   *
-   * @deprecated Use integrate_difference(const hp::DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &, OutVector &, const hp::QCollection<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
-   */
-  template <int dim, class InVector, class OutVector, int spacedim>
-  DEAL_II_DEPRECATED typename std::enable_if<
-    !std::is_same<typename InVector::value_type, double>::value>::type
-  integrate_difference(const hp::DoFHandler<dim, spacedim> &dof,
-                       const InVector &                     fe_function,
-                       const Function<spacedim, double> &   exact_solution,
-                       OutVector &                          difference,
-                       const hp::QCollection<dim> &         q,
-                       const NormType &                     norm,
-                       const Function<spacedim, double> *   weight   = nullptr,
-                       const double                         exponent = 2.);
-
-  /**
-   * Take a Vector @p cellwise_error of errors on each cell with
-   * <tt>tria.n_active_cells()</tt> entries and return the global
-   * error as given by @p norm.
-   *
-   * The @p cellwise_error vector is typically an output produced by
-   * VectorTools::integrate_difference() and you normally want to supply the
-   * same value for @p norm as you used in VectorTools::integrate_difference().
-   *
-   * If the given Triangulation is a parallel::TriangulationBase, entries
-   * in @p cellwise_error that do not correspond to locally owned cells are
-   * assumed to be 0.0 and a parallel reduction using MPI is done to compute
-   * the global error.
-   *
-   * @param tria The Triangulation with active cells corresponding with the
-   * entries in @p cellwise_error.
-   * @param cellwise_error Vector of errors on each active cell.
-   * @param norm The type of norm to compute.
-   * @param exponent The exponent $p$ to use for $L^p$-norms and
-   * $W^{1,p}$-norms. The value is ignored if a @p norm other
-   * than NormType::Lp_norm, NormType::W1p_norm, or NormType::W1p_seminorm
-   * is chosen.
-   *
-   * @note Instantiated for type Vector<double> and Vector<float>.
-   */
-  template <int dim, int spacedim, class InVector>
-  double
-  compute_global_error(const Triangulation<dim, spacedim> &tria,
-                       const InVector &                    cellwise_error,
-                       const NormType &                    norm,
-                       const double                        exponent = 2.);
-
-  /**
-   * Point error evaluation. Find the first cell containing the given point
-   * and compute the difference of a (possibly vector-valued) finite element
-   * function and a continuous function (with as many vector components as the
-   * finite element) at this point.
-   *
-   * This is a wrapper function using a Q1-mapping for cell boundaries to call
-   * the other point_difference() function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_difference(
-    const DoFHandler<dim, spacedim> &                          dof,
-    const VectorType &                                         fe_function,
-    const Function<spacedim, typename VectorType::value_type> &exact_solution,
-    Vector<typename VectorType::value_type> &                  difference,
-    const Point<spacedim> &                                    point);
-
-  /**
-   * Point error evaluation. Find the first cell containing the given point
-   * and compute the difference of a (possibly vector-valued) finite element
-   * function and a continuous function (with as many vector components as the
-   * finite element) at this point.
-   *
-   * Compared with the other function of the same name, this function uses an
-   * arbitrary mapping to evaluate the difference.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_difference(
-    const Mapping<dim, spacedim> &                             mapping,
-    const DoFHandler<dim, spacedim> &                          dof,
-    const VectorType &                                         fe_function,
-    const Function<spacedim, typename VectorType::value_type> &exact_solution,
-    Vector<typename VectorType::value_type> &                  difference,
-    const Point<spacedim> &                                    point);
-
-  /**
-   * Evaluate a possibly vector-valued finite element function defined by the
-   * given DoFHandler and nodal vector @p fe_function at the given point @p
-   * point, and return the (vector) value of this function through the last
-   * argument.
-   *
-   * This function uses a $Q_1$-mapping for the cell the point is evaluated
-   * in. If you need to evaluate using a different mapping (for example when
-   * using curved boundaries), use the point_difference() function that takes
-   * a mapping.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   *   exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_value(const DoFHandler<dim, spacedim> &        dof,
-              const VectorType &                       fe_function,
-              const Point<spacedim> &                  point,
-              Vector<typename VectorType::value_type> &value);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_value(const hp::DoFHandler<dim, spacedim> &    dof,
-              const VectorType &                       fe_function,
-              const Point<spacedim> &                  point,
-              Vector<typename VectorType::value_type> &value);
-
-  /**
-   * Evaluate a scalar finite element function defined by the given DoFHandler
-   * and nodal vector @p fe_function at the given point @p point, and return
-   * the value of this function.
-   *
-   * This function uses a Q1-mapping for the cell the point is evaluated
-   * in. If you need to evaluate using a different mapping (for example when
-   * using curved boundaries), use the point_difference() function that takes
-   * a mapping.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * This function is used in the "Possibilities for extensions" part of the
-   * results section of
-   * @ref step_3 "step-3".
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  typename VectorType::value_type
-  point_value(const DoFHandler<dim, spacedim> &dof,
-              const VectorType &               fe_function,
-              const Point<spacedim> &          point);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  typename VectorType::value_type
-  point_value(const hp::DoFHandler<dim, spacedim> &dof,
-              const VectorType &                   fe_function,
-              const Point<spacedim> &              point);
-
-  /**
-   * Evaluate a possibly vector-valued finite element function defined by the
-   * given DoFHandler and nodal vector @p fe_function at the given point @p
-   * point, and return the (vector) value of this function through the last
-   * argument.
-   *
-   * Compared with the other function of the same name, this function uses an
-   * arbitrary mapping to evaluate the point value.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_value(const Mapping<dim, spacedim> &           mapping,
-              const DoFHandler<dim, spacedim> &        dof,
-              const VectorType &                       fe_function,
-              const Point<spacedim> &                  point,
-              Vector<typename VectorType::value_type> &value);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_value(const hp::MappingCollection<dim, spacedim> &mapping,
-              const hp::DoFHandler<dim, spacedim> &       dof,
-              const VectorType &                          fe_function,
-              const Point<spacedim> &                     point,
-              Vector<typename VectorType::value_type> &   value);
-
-  /**
-   * Evaluate a scalar finite element function defined by the given DoFHandler
-   * and nodal vector @p fe_function at the given point @p point, and return
-   * the value of this function.
-   *
-   * Compared with the other function of the same name, this function uses an
-   * arbitrary mapping to evaluate the difference.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  typename VectorType::value_type
-  point_value(const Mapping<dim, spacedim> &   mapping,
-              const DoFHandler<dim, spacedim> &dof,
-              const VectorType &               fe_function,
-              const Point<spacedim> &          point);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the value of the finite element field either
-   *   here or there, depending on which cell the point is found in. This
-   *   does not matter (to within the same tolerance) if the finite element
-   *   field is continuous. On the other hand, if the finite element in use
-   *   is <i>not</i> continuous, then you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  typename VectorType::value_type
-  point_value(const hp::MappingCollection<dim, spacedim> &mapping,
-              const hp::DoFHandler<dim, spacedim> &       dof,
-              const VectorType &                          fe_function,
-              const Point<spacedim> &                     point);
-
-  /**
-   * Evaluate a possibly vector-valued finite element function defined by the
-   * given DoFHandler and nodal vector at the given point, and return the
-   * (vector) gradient of this function through the last argument.
-   *
-   * This is a wrapper function using a Q1-mapping for cell boundaries to call
-   * the other point_gradient() function.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_gradient(
-    const DoFHandler<dim, spacedim> &dof,
-    const VectorType &               fe_function,
-    const Point<spacedim> &          point,
-    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_gradient(
-    const hp::DoFHandler<dim, spacedim> &dof,
-    const VectorType &                   fe_function,
-    const Point<spacedim> &              point,
-    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
-
-  /**
-   * Evaluate a scalar finite element function defined by the given DoFHandler
-   * and nodal vector at the given point, and return the gradient of this
-   * function.
-   *
-   * Compared with the other function of the same name, this is a wrapper
-   * function using a Q1-mapping for cells.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  Tensor<1, spacedim, typename VectorType::value_type>
-  point_gradient(const DoFHandler<dim, spacedim> &dof,
-                 const VectorType &               fe_function,
-                 const Point<spacedim> &          point);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  Tensor<1, spacedim, typename VectorType::value_type>
-  point_gradient(const hp::DoFHandler<dim, spacedim> &dof,
-                 const VectorType &                   fe_function,
-                 const Point<spacedim> &              point);
-
-  /**
-   * Evaluate a possibly vector-valued finite element function defined by the
-   * given DoFHandler and nodal vector at the given point, and return the
-   * gradients of this function through the last argument.
-   *
-   * Compared with the other function of the same name, this function uses an
-   * arbitrary mapping for evaluation.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_gradient(
-    const Mapping<dim, spacedim> &   mapping,
-    const DoFHandler<dim, spacedim> &dof,
-    const VectorType &               fe_function,
-    const Point<spacedim> &          point,
-    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  void
-  point_gradient(
-    const hp::MappingCollection<dim, spacedim> &mapping,
-    const hp::DoFHandler<dim, spacedim> &       dof,
-    const VectorType &                          fe_function,
-    const Point<spacedim> &                     point,
-    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
-
-  /**
-   * Evaluate a scalar finite element function defined by the given DoFHandler
-   * and nodal vector at the given point, and return the gradient of this
-   * function.
-   *
-   * Compared with the other function of the same name, this function uses an
-   * arbitrary mapping for evaluation.
-   *
-   * This function is not particularly cheap. This is because it first
-   * needs to find which cell a given point is in, then find the point
-   * on the reference cell that matches the given evaluation point,
-   * and then evaluate the shape functions there. You probably do not
-   * want to use this function to evaluate the solution at <i>many</i>
-   * points. For this kind of application, the FEFieldFunction class
-   * offers at least some optimizations. On the other hand, if you
-   * want to evaluate <i>many solutions</i> at the same point, you may
-   * want to look at the VectorTools::create_point_source_vector()
-   * function.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  Tensor<1, spacedim, typename VectorType::value_type>
-  point_gradient(const Mapping<dim, spacedim> &   mapping,
-                 const DoFHandler<dim, spacedim> &dof,
-                 const VectorType &               fe_function,
-                 const Point<spacedim> &          point);
-
-  /**
-   * Same as above for hp.
-   *
-   * @note If the cell in which the point is found is not locally owned, an
-   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
-   *
-   * @note This function needs to find the cell within which a point lies,
-   *   and this can only be done up to a certain numerical tolerance of course.
-   *   Consequently, for points that are on, or close to, the boundary of
-   *   a cell, you may get the gradient of the finite element field either
-   *   here or there, depending on which cell the point is found in. Since
-   *   the gradient is, for most elements, discontinuous from one cell or
-   *   the other, you will get unpredictable values for
-   *   points on or close to the boundary of the cell, as one would expect
-   *   when trying to evaluate point values of discontinuous functions.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  Tensor<1, spacedim, typename VectorType::value_type>
-  point_gradient(const hp::MappingCollection<dim, spacedim> &mapping,
-                 const hp::DoFHandler<dim, spacedim> &       dof,
-                 const VectorType &                          fe_function,
-                 const Point<spacedim> &                     point);
-
-  //@}
-  /**
-   * Mean value operations
-   */
-  //@{
-
-  /**
-   * Subtract the (algebraic) mean value from a vector.
-   *
-   * This function is most frequently used as a mean-value filter for Stokes:
-   * The pressure in Stokes' equations with only Dirichlet boundaries for the
-   * velocities is only determined up to a constant. This function allows to
-   * subtract the mean value of the pressure. It is usually called in a
-   * preconditioner and generates updates with mean value zero. The mean value
-   * is computed as the mean value of the degrees of freedom values as given
-   * by the input vector; they are not weighted by the area of cells, i.e. the
-   * mean is computed as $\sum_i v_i$, rather than as $\int_\Omega v(x) =
-   * \int_\Omega \sum_i v_i \phi_i(x)$. The latter can be obtained from the
-   * VectorTools::compute_mean_function, however.
-   *
-   * Apart from the vector @p v to operate on, this function takes a boolean
-   * mask @p p_select that has a true entry for every element of the vector
-   * for which the mean value shall be computed and later subtracted. The
-   * argument is used to denote which components of the solution vector
-   * correspond to the pressure, and avoid touching all other components of
-   * the vector, such as the velocity components. (Note, however, that the
-   * mask is not a
-   * @ref GlossComponentMask
-   * operating on the vector components of the finite element the solution
-   * vector @p v may be associated with; rather, it is a mask on the entire
-   * vector, without reference to what the vector elements mean.)
-   *
-   * The boolean mask @p p_select has an empty vector as default value, which
-   * will be interpreted as selecting all vector elements, hence, subtracting
-   * the algebraic mean value on the whole vector. This allows to call this
-   * function without a boolean mask if the whole vector should be processed.
-   *
-   * @note In the context of using this function to filter out the kernel of
-   * an operator (such as the null space of the Stokes operator that consists
-   * of the constant pressures), this function only makes sense for finite
-   * elements for which the null space indeed consists of the vector
-   * $(1,1,\ldots,1)^T$. This is the case for example for the usual Lagrange
-   * elements where the sum of all shape functions equals the function that is
-   * constant one. However, it is not true for some other functions: for
-   * example, for the FE_DGP element (another valid choice for the pressure in
-   * Stokes discretizations), the first shape function on each cell is
-   * constant while further elements are $L_2$ orthogonal to it (on the
-   * reference cell); consequently, the sum of all shape functions is not
-   * equal to one, and the vector that is associated with the constant mode is
-   * not equal to $(1,1,\ldots,1)^T$. For such elements, a different procedure
-   * has to be used when subtracting the mean value.
-   *
-   * @warning This function can only be used for distributed vector classes
-   * provided the boolean mask is empty, i.e. selecting the whole vector.
-   */
-  template <typename VectorType>
-  void
-  subtract_mean_value(VectorType &v, const std::vector<bool> &p_select = {});
-
-
-  /**
-   * Compute the mean value of one component of the solution.
-   *
-   * This function integrates the chosen component over the whole domain and
-   * returns the result, i.e. it computes $\frac{1}{|\Omega|}\int_\Omega
-   * [u_h(x)]_c \; dx$ where $c$ is the vector component and $u_h$ is the
-   * function representation of the nodal vector given as fourth argument. The
-   * integral is evaluated numerically using the quadrature formula given as
-   * third argument.
-   *
-   * This function is used in the "Possibilities for extensions" part of the
-   * results section of
-   * @ref step_3 "step-3".
-   *
-   * @note The function is most often used when solving a problem whose
-   * solution is only defined up to a constant, for example a pure Neumann
-   * problem or the pressure in a Stokes or Navier-Stokes problem. In both
-   * cases, subtracting the mean value as computed by the current function,
-   * from the nodal vector does not generally yield the desired result of a
-   * finite element function with mean value zero. In fact, it only works for
-   * Lagrangian elements. For all other elements, you will need to compute the
-   * mean value and subtract it right inside the evaluation routine.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  typename VectorType::value_type
-  compute_mean_value(const Mapping<dim, spacedim> &   mapping,
-                     const DoFHandler<dim, spacedim> &dof,
-                     const Quadrature<dim> &          quadrature,
-                     const VectorType &               v,
-                     const unsigned int               component);
-
-  /**
-   * Call the other compute_mean_value() function, see above, with
-   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
-   */
-  template <int dim, typename VectorType, int spacedim>
-  typename VectorType::value_type
-  compute_mean_value(const DoFHandler<dim, spacedim> &dof,
-                     const Quadrature<dim> &          quadrature,
-                     const VectorType &               v,
-                     const unsigned int               component);
-  //@}
-  /**
-   * Geometrical interpolation
-   */
-  //@{
-  /**
-   * Given a DoFHandler containing at least a spacedim vector field, this
-   * function interpolates the Triangulation at the support points of a FE_Q()
-   * finite element of the same degree as the degree of the required
-   * components.
-   *
-   * Curved manifold are respected, and the resulting VectorType will be
-   * geometrically consistent. The resulting map is guaranteed to be
-   * interpolatory at the support points of a FE_Q() finite element of the
-   * same degree as the degree of the required components.
-   *
-   * If the underlying finite element is an FE_Q(1)^spacedim, then the
-   * resulting @p VectorType is a finite element field representation of the
-   * vertices of the Triangulation.
-   *
-   * The optional ComponentMask argument can be used to specify what
-   * components of the FiniteElement to use to describe the geometry. If no
-   * mask is specified at construction time, then a default one is used, i.e.,
-   * the first spacedim components of the FiniteElement are assumed to
-   * represent the geometry of the problem.
-   *
-   * This function is only implemented for FiniteElements where the specified
-   * components are primitive.
-   *
-   * @author Luca Heltai, 2015
-   */
-  template <int dim,
-            int spacedim,
-            template <int, int> class DoFHandlerType,
-            typename VectorType>
-  void
-  get_position_vector(const DoFHandlerType<dim, spacedim> &dh,
-                      VectorType &                         vector,
-                      const ComponentMask &mask = ComponentMask());
-
-  //@}
-
-  /**
-   * Exception
-   */
-  DeclExceptionMsg(ExcPointNotAvailableHere,
-                   "The given point is inside a cell of a "
-                   "parallel::distributed::Triangulation that is not "
-                   "locally owned by this processor.");
-} // namespace VectorTools
-
-
-// Make sure we can use NormType with Patterns.
-namespace Patterns
-{
-  namespace Tools
-  {
-    template <>
-    struct Convert<VectorTools::NormType, void>
-    {
-      /**
-       * Return the Correct pattern for NormType.
-       */
-      static std::unique_ptr<Patterns::PatternBase>
-      to_pattern()
-      {
-        return std_cxx14::make_unique<Patterns::Selection>(
-          "mean|L1_norm|L2_norm|Lp_norm|"
-          "Linfty_norm|H1_seminorm|Hdiv_seminorm|"
-          "H1_norm|W1p_seminorm|W1p_norm|"
-          "W1infty_seminorm|W1infty_norm");
-      }
-
-
-
-      /**
-       * Convert a NormType to a string.
-       */
-      static std::string
-      to_string(const VectorTools::NormType &                 s,
-                const std::unique_ptr<Patterns::PatternBase> &p =
-                  Convert<VectorTools::NormType>::to_pattern())
-      {
-        std::string str;
-        if (s == VectorTools::mean)
-          str = "mean";
-        else if (s == VectorTools::L1_norm)
-          str = "L1_norm";
-        else if (s == VectorTools::L2_norm)
-          str = "L2_norm";
-        else if (s == VectorTools::Lp_norm)
-          str = "Lp_norm";
-        else if (s == VectorTools::Linfty_norm)
-          str = "Linfty_norm";
-        else if (s == VectorTools::H1_seminorm)
-          str = "H1_seminorm";
-        else if (s == VectorTools::Hdiv_seminorm)
-          str = "Hdiv_seminorm";
-        else if (s == VectorTools::H1_norm)
-          str = "H1_norm";
-        else if (s == VectorTools::W1p_seminorm)
-          str = "W1p_seminorm";
-        else if (s == VectorTools::W1infty_seminorm)
-          str = "W1infty_seminorm";
-        else if (s == VectorTools::W1infty_norm)
-          str = "W1infty_norm";
-        else if (s == VectorTools::W1p_norm)
-          str = "W1p_norm";
-        else
-          {
-            AssertThrow(false, ExcMessage("Didn't recognize a norm type."));
-          }
-        AssertThrow(p->match(str), ExcInternalError());
-        return str;
-      }
-
-
-      /**
-       * Convert a string to a NormType.
-       */
-      static VectorTools::NormType
-      to_value(const std::string &                           str,
-               const std::unique_ptr<Patterns::PatternBase> &p =
-                 Convert<VectorTools::NormType>::to_pattern())
-      {
-        VectorTools::NormType norm = VectorTools::mean;
-        AssertThrow(p->match(str),
-                    ExcMessage(
-                      "String " + str +
-                      " cannot be converted to VectorTools::NormType"));
-
-        if (str == "mean")
-          norm = VectorTools::mean;
-        else if (str == "L1_norm")
-          norm = VectorTools::L1_norm;
-        else if (str == "L2_norm")
-          norm = VectorTools::L2_norm;
-        else if (str == "Lp_norm")
-          norm = VectorTools::Lp_norm;
-        else if (str == "Linfty_norm")
-          norm = VectorTools::Linfty_norm;
-        else if (str == "H1_seminorm")
-          norm = VectorTools::H1_seminorm;
-        else if (str == "Hdiv_seminorm")
-          norm = VectorTools::Hdiv_seminorm;
-        else if (str == "H1_norm")
-          norm = VectorTools::H1_norm;
-        else if (str == "W1p_seminorm")
-          norm = VectorTools::W1p_seminorm;
-        else if (str == "W1infty_seminorm")
-          norm = VectorTools::W1infty_seminorm;
-        else if (str == "W1infty_norm")
-          norm = VectorTools::W1infty_norm;
-        else if (str == "W1p_norm")
-          norm = VectorTools::W1p_norm;
-        else
-          {
-            AssertThrow(false, ExcMessage("Didn't recognize a norm type."));
-          }
-        return norm;
-      }
-    };
-  } // namespace Tools
-} // namespace Patterns
+{}
 
 DEAL_II_NAMESPACE_CLOSE
 
diff --git a/include/deal.II/numerics/vector_tools_boundary.h b/include/deal.II/numerics/vector_tools_boundary.h
new file mode 100644 (file)
index 0000000..684310c
--- /dev/null
@@ -0,0 +1,808 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2017 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+#ifndef dealii_vector_tools_boundary_h
+#define dealii_vector_tools_boundary_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/hp/mapping_collection.h>
+
+#include <map>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <typename number>
+class AffineConstraints;
+template <int dim, int spacedim>
+class DoFHandler;
+template <int dim, typename Number>
+class Function;
+namespace hp
+{
+  template <int dim, int spacedim>
+  class DoFHandler;
+  template <int dim>
+  class QCollection;
+} // namespace hp
+
+namespace VectorTools
+{
+  /**
+   * @name Interpolation and projection
+   */
+  //@{
+
+  /**
+   * Compute Dirichlet boundary conditions.  This function makes up a map of
+   * degrees of freedom subject to Dirichlet boundary conditions and the
+   * corresponding values to be assigned to them, by interpolation around the
+   * boundary. For each degree of freedom at the boundary, if its index
+   * already exists in @p boundary_values then its boundary value will be
+   * overwritten, otherwise a new entry with proper index and boundary value
+   * for this degree of freedom will be inserted into @p boundary_values.
+   *
+   * The parameter @p function_map provides a list of boundary indicators to
+   * be handled by this function and corresponding boundary value functions.
+   * The keys of this map correspond to the number @p boundary_id of the face.
+   * numbers::internal_face_boundary_id is an illegal value for this key since
+   * it is reserved for interior faces. For an example of how to use this
+   * argument with a non-empty map, see the step-16 tutorial program.
+   *
+   * The flags in the last parameter, @p component_mask denote which
+   * components of the finite element space shall be interpolated. If it is
+   * left as specified by the default value (i.e. an empty array), all
+   * components are interpolated. If it is different from the default value,
+   * it is assumed that the number of entries equals the number of components
+   * in the boundary functions and the finite element, and those components in
+   * the given boundary function will be used for which the respective flag
+   * was set in the component mask. See also
+   * @ref GlossComponentMask.
+   * As an example, assume that you are solving the Stokes equations in 2d,
+   * with variables $(u,v,p)$ and that you only want to interpolate boundary
+   * values for the velocity, then the component mask should correspond to
+   * <code>(true,true,false)</code>.
+   *
+   * @note Whether a component mask has been specified or not, the number of
+   * components of the functions in @p function_map must match that of the
+   * finite element used by @p dof. In other words, for the example above, you
+   * need to provide a Function object that has 3 components (the two
+   * velocities and the pressure), even though you are only interested in the
+   * first two of them. interpolate_boundary_values() will then call this
+   * function to obtain a vector of 3 values at each interpolation point but
+   * only take the first two and discard the third. In other words, you are
+   * free to return whatever you like in the third component of the vector
+   * returned by Function::vector_value, but the Function object must state
+   * that it has 3 components.
+   *
+   * If the finite element used has shape functions that are non-zero in more
+   * than one component (in deal.II speak: they are non-primitive), then these
+   * components can presently not be used for interpolating boundary values.
+   * Thus, the elements in the component mask corresponding to the components
+   * of these non-primitive shape functions must be @p false.
+   *
+   * See the general documentation of this namespace for more information.
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const Mapping<dim, spacedim> &       mapping,
+    const DoFHandlerType<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        function_map,
+    std::map<types::global_dof_index, number> &boundary_values,
+    const ComponentMask &component_mask = ComponentMask());
+
+  /**
+   * Like the previous function, but take a mapping collection to go with the
+   * hp::DoFHandler object.
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  interpolate_boundary_values(
+    const hp::MappingCollection<dim, spacedim> &mapping,
+    const hp::DoFHandler<dim, spacedim> &       dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        function_map,
+    std::map<types::global_dof_index, number> &boundary_values,
+    const ComponentMask &component_mask = ComponentMask());
+
+  /**
+   * Same function as above, but taking only one pair of boundary indicator
+   * and corresponding boundary function. The same comments apply as for the
+   * previous function, in particular about the use of the component mask and
+   * the requires size of the function object.
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const Mapping<dim, spacedim> &             mapping,
+    const DoFHandlerType<dim, spacedim> &      dof,
+    const types::boundary_id                   boundary_component,
+    const Function<spacedim, number> &         boundary_function,
+    std::map<types::global_dof_index, number> &boundary_values,
+    const ComponentMask &component_mask = ComponentMask());
+
+  /**
+   * Call the other interpolate_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
+   * apply as for the previous function, in particular about the use of the
+   * component mask and the requires size of the function object.
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const DoFHandlerType<dim, spacedim> &      dof,
+    const types::boundary_id                   boundary_component,
+    const Function<spacedim, number> &         boundary_function,
+    std::map<types::global_dof_index, number> &boundary_values,
+    const ComponentMask &component_mask = ComponentMask());
+
+
+  /**
+   * Call the other interpolate_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
+   * apply as for the previous function, in particular about the use of the
+   * component mask and the requires size of the function object.
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const DoFHandlerType<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        function_map,
+    std::map<types::global_dof_index, number> &boundary_values,
+    const ComponentMask &component_mask = ComponentMask());
+
+
+  /**
+   * Insert the (algebraic) constraints due to Dirichlet boundary conditions
+   * into a AffineConstraints @p constraints. This function identifies the
+   * degrees of freedom subject to Dirichlet boundary conditions, adds them to
+   * the list of constrained DoFs in @p constraints and sets the respective
+   * inhomogeneity to the value interpolated around the boundary. If this
+   * routine encounters a DoF that already is constrained (for instance by a
+   * hanging node constraint, see below, or any other type of constraint, e.g.
+   * from periodic boundary conditions), the old setting of the constraint
+   * (dofs the entry is constrained to, inhomogeneities) is kept and nothing
+   * happens.
+   *
+   * @note When combining adaptively refined meshes with hanging node
+   * constraints and boundary conditions like from the current function within
+   * one AffineConstraints object, the hanging node constraints should always
+   * be set first, and then the boundary conditions since boundary conditions
+   * are not set in the second operation on degrees of freedom that are
+   * already constrained. This makes sure that the discretization remains
+   * conforming as is needed. See the discussion on conflicting constraints in
+   * the module on
+   * @ref constraints.
+   *
+   * The parameter @p boundary_component corresponds to the number @p
+   * boundary_id of the face.
+   *
+   * The flags in the last parameter, @p component_mask denote which
+   * components of the finite element space shall be interpolated. If it is
+   * left as specified by the default value (i.e. an empty array), all
+   * components are interpolated. If it is different from the default value,
+   * it is assumed that the number of entries equals the number of components
+   * in the boundary functions and the finite element, and those components in
+   * the given boundary function will be used for which the respective flag
+   * was set in the component mask. See also
+   * @ref GlossComponentMask.
+   * As an example, assume that you are solving the Stokes equations in 2d,
+   * with variables $(u,v,p)$ and that you only want to interpolate boundary
+   * values for the pressure, then the component mask should correspond to
+   * <code>(true,true,false)</code>.
+   *
+   * @note Whether a component mask has been specified or not, the number of
+   * components of the functions in @p function_map must match that of the
+   * finite element used by @p dof. In other words, for the example above, you
+   * need to provide a Function object that has 3 components (the two
+   * velocities and the pressure), even though you are only interested in the
+   * first two of them. interpolate_boundary_values() will then call this
+   * function to obtain a vector of 3 values at each interpolation point but
+   * only take the first two and discard the third. In other words, you are
+   * free to return whatever you like in the third component of the vector
+   * returned by Function::vector_value, but the Function object must state
+   * that it has 3 components.
+   *
+   * If the finite element used has shape functions that are non-zero in more
+   * than one component (in deal.II speak: they are non-primitive), then these
+   * components can presently not be used for interpolating boundary values.
+   * Thus, the elements in the component mask corresponding to the components
+   * of these non-primitive shape functions must be @p false.
+   *
+   * See the general documentation of this namespace for more information.
+   *
+   * @ingroup constraints
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const Mapping<dim, spacedim> &       mapping,
+    const DoFHandlerType<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                        function_map,
+    AffineConstraints<number> &constraints,
+    const ComponentMask &      component_mask = ComponentMask());
+
+  /**
+   * Same function as above, but taking only one pair of boundary indicator
+   * and corresponding boundary function. The same comments apply as for the
+   * previous function, in particular about the use of the component mask and
+   * the requires size of the function object.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const Mapping<dim, spacedim> &       mapping,
+    const DoFHandlerType<dim, spacedim> &dof,
+    const types::boundary_id             boundary_component,
+    const Function<spacedim, number> &   boundary_function,
+    AffineConstraints<number> &          constraints,
+    const ComponentMask &                component_mask = ComponentMask());
+
+  /**
+   * Call the other interpolate_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
+   * apply as for the previous function, in particular about the use of the
+   * component mask and the requires size of the function object.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const DoFHandlerType<dim, spacedim> &dof,
+    const types::boundary_id             boundary_component,
+    const Function<spacedim, number> &   boundary_function,
+    AffineConstraints<number> &          constraints,
+    const ComponentMask &                component_mask = ComponentMask());
+
+
+  /**
+   * Call the other interpolate_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>. The same comments
+   * apply as for the previous function, in particular about the use of the
+   * component mask and the requires size of the function object.
+   *
+   * @ingroup constraints
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename number>
+  void
+  interpolate_boundary_values(
+    const DoFHandlerType<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                        function_map,
+    AffineConstraints<number> &constraints,
+    const ComponentMask &      component_mask = ComponentMask());
+
+
+  /**
+   * Project a function or a set of functions to the boundary of the domain.
+   * In other words, compute the solution of the following problem: Find $u_h
+   * \in V_h$ (where $V_h$ is the finite element space represented by the
+   * DoFHandler argument of this function) so that
+   * @f{align*}{
+   * \int_{\Gamma} \varphi_i u_h
+   * = \sum_{k \in {\cal K}} \int_{\Gamma_k} \varphi_i f_k,
+   * \qquad \forall \varphi_i \in V_h
+   * @f}
+   * where $\Gamma = \bigcup_{k \in {\cal K}} \Gamma_k$, $\Gamma_k \subset
+   * \partial\Omega$, $\cal K$ is the set of indices and $f_k$ the
+   * corresponding boundary functions represented in the function map argument
+   * @p boundary_values to this function, and the integrals are evaluated by
+   * quadrature. This problem has a non-unique solution in the interior, but
+   * it is well defined for the degrees of freedom on the part of the
+   * boundary, $\Gamma$, for which we do the integration. The values of
+   * $u_h|_\Gamma$, i.e., the nodal values of the degrees of freedom of this
+   * function along the boundary, are then what is computed by this function.
+   *
+   * In case this function is used with $H_{div}$ conforming finite element
+   * space, the solution of a different problem is computed, namely: Find
+   * $\vec{u}_h \in V_h \subset H(\text{div}; \Omega)$ so that
+   * @f{align*}{
+   * \int_{\Gamma} (\vec{\varphi}_i \cdot \vec{n}) (\vec{u}_h \cdot \vec{n})
+   * = \sum_{k \in {\cal K}} \int_{\Gamma_k} (\vec{\varphi}_i \cdot \vec{n})
+   * (\vec{f}_k \cdot \vec{n}),
+   * \qquad \forall \vec{\varphi_i} \in V_h,
+   * @f}
+   * where $\vec{n}$ is an outward normal vector.
+   *
+   * This function throws exception if used with $H_{curl}$ conforming elements,
+   * so the project_boundary_values_curl_conforming() should be used instead.
+   *
+   * @param[in] mapping The mapping that will be used in the transformations
+   * necessary to integrate along the boundary.
+   * @param[in] dof The DoFHandler that describes the finite element space and
+   * the numbering of degrees of freedom.
+   * @param[in] boundary_functions A map from boundary indicators to pointers
+   * to functions that describe the desired values on those parts of the
+   * boundary marked with this boundary indicator (see
+   * @ref GlossBoundaryIndicator "Boundary indicator").
+   * The projection happens on only those parts of the boundary whose
+   * indicators are represented in this map.
+   * @param[in] q The face quadrature used in the integration necessary to
+   * compute the mass matrix and right hand side of the projection.
+   * @param[out] boundary_values The result of this function. It is a map
+   * containing all indices of degrees of freedom at the boundary (as covered
+   * by the boundary parts in @p boundary_functions) and the computed dof
+   * value for this degree of freedom. For each degree of freedom at the
+   * boundary, if its index already exists in @p boundary_values then its
+   * boundary value will be overwritten, otherwise a new entry with proper
+   * index and boundary value for this degree of freedom will be inserted into
+   * @p boundary_values.
+   * @param[in] component_mapping It is sometimes convenient to project a
+   * vector-valued function onto only parts of a finite element space (for
+   * example, to project a function with <code>dim</code> components onto the
+   * velocity components of a <code>dim+1</code> component DoFHandler for a
+   * Stokes problem). To allow for this, this argument allows components to be
+   * remapped. If the vector is not empty, it has to have one entry for each
+   * vector component of the finite element used in @p dof. This entry is the
+   * component number in @p boundary_functions that should be used for this
+   * component in @p dof. By default, no remapping is applied.
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  project_boundary_values(
+    const Mapping<dim, spacedim> &   mapping,
+    const DoFHandler<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        boundary_functions,
+    const Quadrature<dim - 1> &                q,
+    std::map<types::global_dof_index, number> &boundary_values,
+    std::vector<unsigned int>                  component_mapping = {});
+
+  /**
+   * Call the project_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>.
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  project_boundary_values(
+    const DoFHandler<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        boundary_function,
+    const Quadrature<dim - 1> &                q,
+    std::map<types::global_dof_index, number> &boundary_values,
+    std::vector<unsigned int>                  component_mapping = {});
+
+  /**
+   * Same as above, but for objects of type hp::DoFHandler
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  project_boundary_values(
+    const hp::MappingCollection<dim, spacedim> &mapping,
+    const hp::DoFHandler<dim, spacedim> &       dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        boundary_functions,
+    const hp::QCollection<dim - 1> &           q,
+    std::map<types::global_dof_index, number> &boundary_values,
+    std::vector<unsigned int>                  component_mapping = {});
+
+  /**
+   * Call the project_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>.
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  project_boundary_values(
+    const hp::DoFHandler<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                                        boundary_function,
+    const hp::QCollection<dim - 1> &           q,
+    std::map<types::global_dof_index, number> &boundary_values,
+    std::vector<unsigned int>                  component_mapping = {});
+
+  /**
+   * Project a function to the boundary of the domain, using the given
+   * quadrature formula for the faces. This function identifies the degrees of
+   * freedom subject to Dirichlet boundary conditions, adds them to the list
+   * of constrained DoFs in @p constraints and sets the respective
+   * inhomogeneity to the value resulting from the projection operation. If
+   * this routine encounters a DoF that already is constrained (for instance
+   * by a hanging node constraint, see below, or any other type of constraint,
+   * e.g. from periodic boundary conditions), the old setting of the
+   * constraint (dofs the entry is constrained to, inhomogeneities) is kept
+   * and nothing happens.
+   *
+   * @note When combining adaptively refined meshes with hanging node
+   * constraints and boundary conditions like from the current function within
+   * one AffineConstraints object, the hanging node constraints should always
+   * be set first, and then the boundary conditions since boundary conditions
+   * are not set in the second operation on degrees of freedom that are
+   * already constrained. This makes sure that the discretization remains
+   * conforming as is needed. See the discussion on conflicting constraints in
+   * the module on
+   * @ref constraints.
+   *
+   * If @p component_mapping is empty, it is assumed that the number of
+   * components of @p boundary_function matches that of the finite element
+   * used by @p dof.
+   *
+   * In 1d, projection equals interpolation. Therefore,
+   * interpolate_boundary_values is called.
+   *
+   * @arg @p component_mapping: if the components in @p boundary_functions and
+   * @p dof do not coincide, this vector allows them to be remapped. If the
+   * vector is not empty, it has to have one entry for each component in @p
+   * dof. This entry is the component number in @p boundary_functions that
+   * should be used for this component in @p dof. By default, no remapping is
+   * applied.
+   *
+   * @ingroup constraints
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  project_boundary_values(
+    const Mapping<dim, spacedim> &   mapping,
+    const DoFHandler<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                        boundary_functions,
+    const Quadrature<dim - 1> &q,
+    AffineConstraints<number> &constraints,
+    std::vector<unsigned int>  component_mapping = {});
+
+  /**
+   * Call the project_boundary_values() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim,spacedim@>(1)</tt>.
+   *
+   * @ingroup constraints
+   */
+  template <int dim, int spacedim, typename number>
+  void
+  project_boundary_values(
+    const DoFHandler<dim, spacedim> &dof,
+    const std::map<types::boundary_id, const Function<spacedim, number> *>
+      &                        boundary_function,
+    const Quadrature<dim - 1> &q,
+    AffineConstraints<number> &constraints,
+    std::vector<unsigned int>  component_mapping = {});
+
+
+  /**
+   * Compute constraints that correspond to boundary conditions of the form
+   * $\vec{n}\times\vec{u}=\vec{n}\times\vec{f}$, i.e. the tangential
+   * components of $u$ and $f$ shall coincide.
+   *
+   * If the AffineConstraints @p constraints contained values or other
+   * constraints before, the new ones are added or the old ones overwritten,
+   * if a node of the boundary part to be used was already in the list of
+   * constraints. This is handled by using inhomogeneous constraints. Please
+   * note that when combining adaptive meshes and this kind of constraints,
+   * the Dirichlet conditions should be set first, and then completed by
+   * hanging node constraints, in order to make sure that the discretization
+   * remains consistent. See the discussion on conflicting constraints in the
+   * module on
+   * @ref constraints.
+   *
+   * This function is explicitly written to use with the FE_Nedelec elements.
+   * Thus it throws an exception, if it is called with other finite elements.
+   *
+   * The second argument of this function denotes the first vector component
+   * in the finite element that corresponds to the vector function that you
+   * want to constrain. For example, if we want to solve Maxwell's equations
+   * in 3d and the finite element has components $(E_x,E_y,E_z,B_x,B_y,B_z)$
+   * and we want the boundary conditions
+   * $\vec{n}\times\vec{B}=\vec{n}\times\vec{f}$, then @p
+   * first_vector_component would be 3. Vectors are implicitly assumed to have
+   * exactly <code>dim</code> components that are ordered in the same way as
+   * we usually order the coordinate directions, i.e. $x$-, $y$-, and finally
+   * $z$-component.
+   *
+   * The parameter @p boundary_component corresponds to the number @p
+   * boundary_id of the face. numbers::internal_face_boundary_id is an illegal
+   * value, since it is reserved for interior faces.
+   *
+   * The last argument is denoted to compute the normal vector $\vec{n}$ at
+   * the boundary points.
+   *
+   * <h4>Computing constraints</h4>
+   *
+   * To compute the constraints we use projection-based interpolation as
+   * proposed in Solin, Segeth and Dolezel (Higher order finite elements,
+   * Chapman&amp;Hall, 2004) on every face located at the boundary.
+   *
+   * First one projects $\vec{f}$ on the lowest-order edge shape functions.
+   * Then the remaining part $(I-P_0)\vec{f}$ of the function is projected on
+   * the remaining higher-order edge shape functions. In the last step we
+   * project $(I-P_0-P_e)\vec{f}$ on the bubble shape functions defined on the
+   * face.
+   *
+   * @deprecated Use the project_boundary_values_curl_conforming_l2() function
+   * instead of this one.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim>
+  DEAL_II_DEPRECATED void
+  project_boundary_values_curl_conforming(
+    const DoFHandler<dim, dim> & dof_handler,
+    const unsigned int           first_vector_component,
+    const Function<dim, double> &boundary_function,
+    const types::boundary_id     boundary_component,
+    AffineConstraints<double> &  constraints,
+    const Mapping<dim> &         mapping = StaticMappingQ1<dim>::mapping);
+
+  /**
+   * Same as above for the hp-namespace.
+   *
+   * @deprecated Use the project_boundary_values_curl_conforming_l2() function
+   * instead of this one.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim>
+  DEAL_II_DEPRECATED void
+  project_boundary_values_curl_conforming(
+    const hp::DoFHandler<dim, dim> &       dof_handler,
+    const unsigned int                     first_vector_component,
+    const Function<dim, double> &          boundary_function,
+    const types::boundary_id               boundary_component,
+    AffineConstraints<double> &            constraints,
+    const hp::MappingCollection<dim, dim> &mapping_collection =
+      hp::StaticMappingQ1<dim>::mapping_collection);
+
+  /**
+   * This function is an updated version of the
+   * project_boundary_values_curl_conforming function. The intention is to fix
+   * a problem when using the previous function in conjunction with non-
+   * rectangular geometries (i.e. elements with non-rectangular faces). The
+   * L2-projection method used has been taken from the paper "Electromagnetic
+   * scattering simulation using an H (curl) conforming hp finite element
+   * method in three dimensions" by PD Ledger, K Morgan and O Hassan ( Int. J.
+   * Num. Meth. Fluids, Volume 53, Issue 8, pages 1267–1296).
+   *
+   * This function will compute constraints that correspond to Dirichlet
+   * boundary conditions of the form
+   * $\vec{n}\times\vec{E}=\vec{n}\times\vec{F}$ i.e. the tangential
+   * components of $\vec{E}$ and $f$ shall coincide.
+   *
+   * <h4>Computing constraints</h4>
+   *
+   * To compute the constraints we use a projection method based upon the
+   * paper mentioned above. In 2D this is done in a single stage for the edge-
+   * based shape functions, regardless of the order of the finite element. In
+   * 3D this is done in two stages, edges first and then faces.
+   *
+   * For each cell, each edge, $e$, is projected by solving the linear system
+   * $Ax=b$ where $x$ is the vector of constraints on degrees of freedom on the
+   * edge and
+   *
+   * $A_{ij} = \int_{e} (\vec{s}_{i}\cdot\vec{t})(\vec{s}_{j}\cdot\vec{t}) dS$
+   *
+   * $b_{i} = \int_{e} (\vec{s}_{i}\cdot\vec{t})(\vec{F}\cdot\vec{t}) dS$
+   *
+   * with $\vec{s}_{i}$ the $i^{th}$ shape function and $\vec{t}$ the tangent
+   * vector.
+   *
+   * Once all edge constraints, $x$, have been computed, we may compute the
+   * face constraints in a similar fashion, taking into account the residuals
+   * from the edges.
+   *
+   * For each face on the cell, $f$, we solve the linear system $By=c$ where
+   * $y$ is the vector of constraints on degrees of freedom on the face and
+   *
+   * $B_{ij} = \int_{f} (\vec{n} \times \vec{s}_{i}) \cdot (\vec{n} \times
+   * \vec{s}_{j}) dS$
+   *
+   * $c_{i} = \int_{f} (\vec{n} \times \vec{r}) \cdot (\vec{n} \times
+   * \vec{s}_i) dS$
+   *
+   * and $\vec{r} = \vec{F} - \sum_{e \in f} \sum{i \in e} x_{i}\vec{s}_i$,
+   * the edge residual.
+   *
+   * The resulting constraints are then given in the solutions $x$ and $y$.
+   *
+   * If the AffineConstraints @p constraints contained values or other
+   * constraints before, the new ones are added or the old ones overwritten,
+   * if a node of the boundary part to be used was already in the list of
+   * constraints. This is handled by using inhomogeneous constraints. Please
+   * note that when combining adaptive meshes and this kind of constraints,
+   * the Dirichlet conditions should be set first, and then completed by
+   * hanging node constraints, in order to make sure that the discretization
+   * remains consistent. See the discussion on conflicting constraints in the
+   * module on
+   * @ref constraints.
+   *
+   * <h4>Arguments to this function</h4>
+   *
+   * This function is explicitly for use with FE_Nedelec elements, or with
+   * FESystem elements which contain FE_Nedelec elements. It will throw an
+   * exception if called with any other finite element. The user must ensure
+   * that FESystem elements are correctly setup when using this function as
+   * this check not possible in this case.
+   *
+   * The second argument of this function denotes the first vector component
+   * of the finite element which corresponds to the vector function that you
+   * wish to constrain. For example, if we are solving Maxwell's equations in
+   * 3D and have components $(E_x,E_y,E_z,B_x,B_y,B_z)$ and we want the
+   * boundary conditions $\vec{n}\times\vec{B}=\vec{n}\times\vec{f}$, then @p
+   * first_vector_component would be 3. The @p boundary_function must return 6
+   * components in this example, with the first 3 corresponding to $\vec{E}$
+   * and the second 3 corresponding to $\vec{B}$. Vectors are implicitly
+   * assumed to have exactly <code>dim</code> components that are ordered in
+   * the same way as we usually order the coordinate directions, i.e. $x$-,
+   * $y$-, and finally $z$-component.
+   *
+   * The parameter @p boundary_component corresponds to the number @p
+   * boundary_id of the face. numbers::internal_face_boundary_id is an illegal
+   * value, since it is reserved for interior faces.
+   *
+   * The last argument is denoted to compute the normal vector $\vec{n}$ at
+   * the boundary points.
+   *
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, typename number>
+  void
+  project_boundary_values_curl_conforming_l2(
+    const DoFHandler<dim, dim> & dof_handler,
+    const unsigned int           first_vector_component,
+    const Function<dim, number> &boundary_function,
+    const types::boundary_id     boundary_component,
+    AffineConstraints<number> &  constraints,
+    const Mapping<dim> &         mapping = StaticMappingQ1<dim>::mapping);
+
+
+  /**
+   * hp-namespace version of project_boundary_values_curl_conforming_l2
+   * (above).
+   *
+   * @ingroup constraints
+   */
+  template <int dim, typename number>
+  void
+  project_boundary_values_curl_conforming_l2(
+    const hp::DoFHandler<dim, dim> &       dof_handler,
+    const unsigned int                     first_vector_component,
+    const Function<dim, number> &          boundary_function,
+    const types::boundary_id               boundary_component,
+    AffineConstraints<number> &            constraints,
+    const hp::MappingCollection<dim, dim> &mapping_collection =
+      hp::StaticMappingQ1<dim>::mapping_collection);
+
+
+  /**
+   * Compute constraints that correspond to boundary conditions of the form
+   * $\vec{n}^T\vec{u}=\vec{n}^T\vec{f}$, i.e. the normal components of the
+   * solution $u$ and a given $f$ shall coincide. The function $f$ is given by
+   * @p boundary_function and the resulting constraints are added to @p
+   * constraints for faces with boundary indicator @p boundary_component.
+   *
+   * This function is explicitly written to use with the FE_RaviartThomas
+   * elements. Thus it throws an exception, if it is called with other finite
+   * elements.
+   *
+   * If the AffineConstraints object @p constraints contained values or other
+   * constraints before, the new ones are added or the old ones overwritten,
+   * if a node of the boundary part to be used was already in the list of
+   * constraints. This is handled by using inhomogeneous constraints. Please
+   * note that when combining adaptive meshes and this kind of constraints,
+   * the Dirichlet conditions should be set first, and then completed by
+   * hanging node constraints, in order to make sure that the discretization
+   * remains consistent. See the discussion on conflicting constraints in the
+   * module on
+   * @ref constraints.
+   *
+   * The argument @p first_vector_component denotes the first vector component
+   * in the finite element that corresponds to the vector function $\vec{u}$
+   * that you want to constrain. Vectors are implicitly assumed to have
+   * exactly <code>dim</code> components that are ordered in the same way as
+   * we usually order the coordinate directions, i.e., $x$-, $y$-, and finally
+   * $z$-component.
+   *
+   * The parameter @p boundary_component corresponds to the @p boundary_id of
+   * the faces where the boundary conditions are applied.
+   * numbers::internal_face_boundary_id is an illegal value, since it is
+   * reserved for interior faces. The @p mapping is used to compute the normal
+   * vector $\vec{n}$ at the boundary points.
+   *
+   * <h4>Computing constraints</h4>
+   *
+   * To compute the constraints we use interpolation operator proposed in
+   * Brezzi, Fortin (Mixed and Hybrid (Finite Element Methods, Springer, 1991)
+   * on every face located at the boundary.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim>
+  void
+  project_boundary_values_div_conforming(
+    const DoFHandler<dim, dim> & dof_handler,
+    const unsigned int           first_vector_component,
+    const Function<dim, double> &boundary_function,
+    const types::boundary_id     boundary_component,
+    AffineConstraints<double> &  constraints,
+    const Mapping<dim> &         mapping = StaticMappingQ1<dim>::mapping);
+
+  /**
+   * Same as above for the hp-namespace.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim>
+  void
+  project_boundary_values_div_conforming(
+    const hp::DoFHandler<dim, dim> &       dof_handler,
+    const unsigned int                     first_vector_component,
+    const Function<dim, double> &          boundary_function,
+    const types::boundary_id               boundary_component,
+    AffineConstraints<double> &            constraints,
+    const hp::MappingCollection<dim, dim> &mapping_collection =
+      hp::StaticMappingQ1<dim>::mapping_collection);
+
+  // @}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_boundary_h
index 92352fc3c4847ab3e54c2145e49642aa9bb57cc3..37c58a95341e317a8e31e8850eec360fdd99fe6c 100644 (file)
@@ -38,7 +38,7 @@
 #include <deal.II/lac/sparsity_pattern.h>
 
 #include <deal.II/numerics/matrix_tools.h>
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_boundary.h>
 
 
 DEAL_II_NAMESPACE_OPEN
diff --git a/include/deal.II/numerics/vector_tools_common.h b/include/deal.II/numerics/vector_tools_common.h
new file mode 100644 (file)
index 0000000..0dcb69f
--- /dev/null
@@ -0,0 +1,401 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_common_h
+#define dealii_vector_tools_common_h
+
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/patterns.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+namespace VectorTools
+{
+  /**
+   * Denote which norm/integral is to be computed by the
+   * integrate_difference() function on each cell and compute_global_error()
+   * for the whole domain.
+   * Let $f:\Omega \rightarrow \mathbb{R}^c$ be a finite element function
+   * with $c$ components where component $c$ is denoted by $f_c$ and $\hat{f}$
+   * be the reference function (the @p fe_function and @p exact_solution
+   * arguments to integrate_difference()). Let $e_c = \hat{f}_c - f_c$
+   * be the difference or error between the two. Further,
+   * let  $w:\Omega \rightarrow \mathbb{R}^c$ be the @p weight function of integrate_difference(), which is
+   * assumed to be equal to one if not supplied. Finally, let $p$ be the
+   * @p exponent argument (for $L_p$-norms).
+   *
+   * In the following,we denote by $E_K$ the local error computed by
+   * integrate_difference() on cell $K$, whereas $E$ is the global error
+   * computed by compute_global_error(). Note that integrals are
+   * approximated by quadrature in the usual way:
+   * @f[
+   * \int_A f(x) dx \approx \sum_q f(x_q) \omega_q.
+   * @f]
+   * Similarly for suprema over a cell $T$:
+   * @f[
+   * \sup_{x\in T} |f(x)| dx \approx \max_q |f(x_q)|.
+   * @f]
+   */
+  enum NormType
+  {
+    /**
+     * The function or difference of functions is integrated on each cell $K$:
+     * @f[
+     *   E_K
+     * = \int_K \sum_c (\hat{f}_c - f_c) \, w_c
+     * = \int_K \sum_c e_c \, w_c
+     * @f]
+     * and summed up to get
+     * @f[
+     *   E = \sum_K E_K
+     *     = \int_\Omega \sum_c (\hat{f}_c - f_c) \, w_c
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \int_\Omega (\hat{f} - f)
+     *     = \int_\Omega e.
+     * @f]
+     *
+     * Note: This differs from what is typically known as
+     * the mean of a function by a factor of $\frac{1}{|\Omega|}$. To
+     * compute the mean you can also use compute_mean_value(). Finally,
+     * pay attention to the sign: if $\hat{f}=0$, this will compute the
+     * negative of the mean of $f$.
+     */
+    mean,
+
+    /**
+     * The absolute value of the function is integrated:
+     * @f[
+     *   E_K = \int_K \sum_c |e_c| \, w_c
+     * @f]
+     * and
+     * @f[
+     *   E = \sum_K E_K = \int_\Omega \sum_c |e_c| w_c,
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E  = \| e \|_{L^1}.
+     * @f]
+     */
+    L1_norm,
+
+    /**
+     * The square of the function is integrated and the square root of the
+     * result is computed on each cell:
+     * @f[
+     *   E_K = \sqrt{ \int_K \sum_c e_c^2 \, w_c }
+     * @f]
+     * and
+     * @f[
+     *   E = \sqrt{\sum_K E_K^2} = \sqrt{ \int_\Omega  \sum_c e_c^2 \, w_c }
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \sqrt{ \int_\Omega e^2 }
+     *     = \| e \|_{L^2}
+     * @f]
+     */
+    L2_norm,
+
+    /**
+     * The absolute value to the $p$-th power is integrated and the $p$-th
+     * root is computed on each cell. The exponent $p$ is the @p
+     * exponent argument of integrate_difference() and compute_mean_value():
+     * @f[
+     *   E_K = \left( \int_K \sum_c |e_c|^p \, w_c \right)^{1/p}
+     * @f]
+     * and
+     * @f[
+     *   E = \left( \sum_K E_K^p \right)^{1/p}
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \| e \|_{L^p}.
+     * @f]
+     */
+    Lp_norm,
+
+    /**
+     * The maximum absolute value of the function:
+     * @f[
+     *   E_K = \sup_K \max_c |e_c| \, w_c
+     * @f]
+     * and
+     * @f[
+     *   E = \max_K E_K
+     * = \sup_\Omega \max_c |e_c| \, w_c
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E  = \sup_\Omega \|e\|_\infty = \| e \|_{L^\infty}.
+     * @f]
+     */
+    Linfty_norm,
+
+    /**
+     * #L2_norm of the gradient:
+     * @f[
+     *   E_K = \sqrt{ \int_K \sum_c (\nabla e_c)^2 \, w_c }
+     * @f]
+     * and
+     * @f[
+     *   E = \sqrt{\sum_K E_K^2} = \sqrt{ \int_\Omega \sum_c (\nabla e_c)^2 \,
+     * w_c }
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \| \nabla e \|_{L^2}.
+     * @f]
+     */
+    H1_seminorm,
+
+    /**
+     * #L2_norm of the divergence of a vector field. The function $f$ is
+     * expected to have $c \geq \text{dim}$ components and the first @p dim
+     * will be used to compute the divergence:
+     * @f[
+     *   E_K = \sqrt{ \int_K \left( \sum_c \frac{\partial e_c}{\partial x_c} \,
+     * \sqrt{w_c} \right)^2 }
+     * @f]
+     * and
+     * @f[
+     *   E = \sqrt{\sum_K E_K^2}
+     *     = \sqrt{ \int_\Omega \left( \sum_c \frac{\partial e_c}{\partial x_c}
+     * \, \sqrt{w_c} \right)^2  }
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \| \nabla \cdot e \|_{L^2}.
+     * @f]
+     */
+    Hdiv_seminorm,
+
+    /**
+     * The square of this norm is the square of the #L2_norm plus the square
+     * of the #H1_seminorm:
+     * @f[
+     *   E_K = \sqrt{ \int_K \sum_c (e_c^2 + (\nabla e_c)^2) \, w_c }
+     * @f]
+     * and
+     * @f[
+     *   E = \sqrt{\sum_K E_K^2} = \sqrt{ \int_\Omega \sum_c (e_c^2 + (\nabla
+     * e_c)^2) \, w_c }
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \left( \| e \|_{L^2}^2 + \| \nabla e \|_{L^2}^2 \right)^{1/2}.
+     * @f]
+     */
+    H1_norm,
+
+    /**
+     * #Lp_norm of the gradient:
+     * @f[
+     *   E_K = \left( \int_K \sum_c |\nabla e_c|^p \, w_c \right)^{1/p}
+     * @f]
+     * and
+     * @f[
+     *   E = \left( \sum_K E_K^p \right)^{1/p}
+     *     = \left( \int_\Omega \sum_c |\nabla e_c|^p \, w_c \right)^{1/p}
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \| \nabla e \|_{L^p}.
+     * @f]
+     */
+    W1p_seminorm,
+
+    /**
+     * The same as the #H1_norm but using <i>L<sup>p</sup></i>:
+     * @f[
+     *   E_K = \left( \int_K \sum_c (|e_c|^p + |\nabla e_c|^p) \, w_c
+     * \right)^{1/p}
+     * @f]
+     * and
+     * @f[
+     *   E = \left( \sum_K E_K^p \right)^{1/p}
+     *     = \left( \int_\Omega \sum_c (|e_c|^p + |\nabla e_c|^p) \, w_c
+     * \right)^{1/p}
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \left( \| e \|_{L^p}^p + \| \nabla e \|_{L^p}^p \right)^{1/p}.
+     * @f]
+     */
+    W1p_norm,
+
+    /**
+     * #Linfty_norm of the gradient:
+     * @f[
+     *   E_K = \sup_K \max_c |\nabla e_c| \, w_c
+     * @f]
+     * and
+     * @f[
+     *   E = \max_K E_K
+     *     = \sup_\Omega \max_c |\nabla e_c| \, w_c
+     * @f]
+     * or, for $w \equiv 1$:
+     * @f[
+     *   E = \| \nabla e \|_{L^\infty}.
+     * @f]
+     *
+     */
+    W1infty_seminorm,
+
+    /**
+     * The sum of #Linfty_norm and #W1infty_seminorm:
+     * @f[
+     *   E_K = \sup_K \max_c |e_c| \, w_c + \sup_K \max_c |\nabla e_c| \, w_c.
+     * @f]
+     * The global norm is not implemented in compute_global_error(),
+     * because it is impossible to compute the sum of the global
+     * norms from the values $E_K$. As a work-around, you can compute the
+     * global #Linfty_norm and #W1infty_seminorm separately and then add them
+     * to get (with $w \equiv 1$):
+     * @f[
+     *   E = \| e \|_{L^\infty} + \| \nabla e \|_{L^\infty}.
+     * @f]
+     */
+    W1infty_norm
+  };
+
+  /**
+   * Exception
+   */
+  DeclExceptionMsg(ExcPointNotAvailableHere,
+                   "The given point is inside a cell of a "
+                   "parallel::distributed::Triangulation that is not "
+                   "locally owned by this processor.");
+} // namespace VectorTools
+
+// Make sure we can use NormType with Patterns.
+namespace Patterns
+{
+  namespace Tools
+  {
+    template <>
+    struct Convert<VectorTools::NormType, void>
+    {
+      /**
+       * Return the Correct pattern for NormType.
+       */
+      static std::unique_ptr<Patterns::PatternBase>
+      to_pattern()
+      {
+        return std_cxx14::make_unique<Patterns::Selection>(
+          "mean|L1_norm|L2_norm|Lp_norm|"
+          "Linfty_norm|H1_seminorm|Hdiv_seminorm|"
+          "H1_norm|W1p_seminorm|W1p_norm|"
+          "W1infty_seminorm|W1infty_norm");
+      }
+
+
+
+      /**
+       * Convert a NormType to a string.
+       */
+      static std::string
+      to_string(const VectorTools::NormType &                 s,
+                const std::unique_ptr<Patterns::PatternBase> &p =
+                  Convert<VectorTools::NormType>::to_pattern())
+      {
+        std::string str;
+        if (s == VectorTools::mean)
+          str = "mean";
+        else if (s == VectorTools::L1_norm)
+          str = "L1_norm";
+        else if (s == VectorTools::L2_norm)
+          str = "L2_norm";
+        else if (s == VectorTools::Lp_norm)
+          str = "Lp_norm";
+        else if (s == VectorTools::Linfty_norm)
+          str = "Linfty_norm";
+        else if (s == VectorTools::H1_seminorm)
+          str = "H1_seminorm";
+        else if (s == VectorTools::Hdiv_seminorm)
+          str = "Hdiv_seminorm";
+        else if (s == VectorTools::H1_norm)
+          str = "H1_norm";
+        else if (s == VectorTools::W1p_seminorm)
+          str = "W1p_seminorm";
+        else if (s == VectorTools::W1infty_seminorm)
+          str = "W1infty_seminorm";
+        else if (s == VectorTools::W1infty_norm)
+          str = "W1infty_norm";
+        else if (s == VectorTools::W1p_norm)
+          str = "W1p_norm";
+        else
+          {
+            AssertThrow(false, ExcMessage("Didn't recognize a norm type."));
+          }
+        AssertThrow(p->match(str), ExcInternalError());
+        return str;
+      }
+
+
+      /**
+       * Convert a string to a NormType.
+       */
+      static VectorTools::NormType
+      to_value(const std::string &                           str,
+               const std::unique_ptr<Patterns::PatternBase> &p =
+                 Convert<VectorTools::NormType>::to_pattern())
+      {
+        VectorTools::NormType norm = VectorTools::mean;
+        AssertThrow(p->match(str),
+                    ExcMessage(
+                      "String " + str +
+                      " cannot be converted to VectorTools::NormType"));
+
+        if (str == "mean")
+          norm = VectorTools::mean;
+        else if (str == "L1_norm")
+          norm = VectorTools::L1_norm;
+        else if (str == "L2_norm")
+          norm = VectorTools::L2_norm;
+        else if (str == "Lp_norm")
+          norm = VectorTools::Lp_norm;
+        else if (str == "Linfty_norm")
+          norm = VectorTools::Linfty_norm;
+        else if (str == "H1_seminorm")
+          norm = VectorTools::H1_seminorm;
+        else if (str == "Hdiv_seminorm")
+          norm = VectorTools::Hdiv_seminorm;
+        else if (str == "H1_norm")
+          norm = VectorTools::H1_norm;
+        else if (str == "W1p_seminorm")
+          norm = VectorTools::W1p_seminorm;
+        else if (str == "W1infty_seminorm")
+          norm = VectorTools::W1infty_seminorm;
+        else if (str == "W1infty_norm")
+          norm = VectorTools::W1infty_norm;
+        else if (str == "W1p_norm")
+          norm = VectorTools::W1p_norm;
+        else
+          {
+            AssertThrow(false, ExcMessage("Didn't recognize a norm type."));
+          }
+        return norm;
+      }
+    };
+  } // namespace Tools
+} // namespace Patterns
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_common_h
diff --git a/include/deal.II/numerics/vector_tools_constraints.h b/include/deal.II/numerics/vector_tools_constraints.h
new file mode 100644 (file)
index 0000000..1d88a31
--- /dev/null
@@ -0,0 +1,356 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2014 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+#ifndef dealii_vector_tools_constraints_h
+#define dealii_vector_tools_constraints_h
+
+#include <deal.II/base/config.h>
+
+#include <map>
+#include <set>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <typename number>
+class AffineConstraints;
+template <int dim, int spacedim>
+struct StaticMappingQ1;
+template <int dim, typename Number>
+class Function;
+template <int dim, int spacedim>
+class Mapping;
+
+
+namespace VectorTools
+{
+  /**
+   * @name Interpolation and projection
+   */
+  //@{
+
+  /**
+   * This function computes the constraints that correspond to boundary
+   * conditions of the form $\vec u \cdot \vec n=\vec u_\Gamma \cdot \vec n$,
+   * i.e., normal flux constraints where $\vec u$ is a vector-valued solution
+   * variable and $\vec u_\Gamma$ is a prescribed vector field whose normal
+   * component we want to be equal to the normal component of the solution.
+   * These conditions have exactly the form handled by the
+   * AffineConstraints class, in that they relate a <i>linear
+   * combination</i> of boundary degrees of freedom to a corresponding
+   * value (the inhomogeneity of the constraint). Consequently, the current
+   * function creates a list of constraints that are written into an
+   * AffineConstraints container. This object may already have some
+   * content, for example from hanging node constraints, that remains
+   * untouched. These constraints have to be applied to the linear system
+   * like any other such constraints, i.e., you have to condense the linear
+   * system with the constraints before solving, and you have to distribute
+   * the solution vector afterwards.
+   *
+   * This function treats a more general case than
+   * VectorTools::compute_no_normal_flux_constraints() (which can only handle
+   * the case where $\vec u_\Gamma \cdot \vec n = 0$, and is used in
+   * step-31 and step-32). However, because everything that would apply
+   * to that function also applies as a special case to the current
+   * function, the following discussion is relevant to both.
+   *
+   * @note This function doesn't make much sense in 1d, so it throws an
+   *   exception if @p dim equals one.
+   *
+   *
+   * <h4>Arguments to this function</h4>
+   *
+   * The second argument of this function denotes the first vector component
+   * in the finite element that corresponds to the vector function that you
+   * want to constrain. For example, if we were solving a Stokes equation in
+   * 2d and the finite element had components $(u,v,p)$, then @p
+   * first_vector_component needs to be zero if you intend to constraint
+   * the vector $(u,v)^T \cdot \vec n = \vec u_\Gamma \cdot \vec n$.
+   * On the other hand, if we solved the
+   * Maxwell equations in 3d and the finite element has components
+   * $(E_x,E_y,E_z,B_x,B_y,B_z)$ and we want the boundary condition $\vec
+   * B\cdot \vec n=\vec B_\Gamma\cdot \vec n$, then @p first_vector_component
+   * would be 3. Vectors are implicitly assumed to have exactly
+   * <code>dim</code> components that are ordered in the same way as we
+   * usually order the coordinate directions, i.e. $x$-, $y$-, and finally
+   * $z$-component. The function assumes, but can't check, that the vector
+   * components in the range
+   * <code>[first_vector_component,first_vector_component+dim)</code> come
+   * from the same base finite element. For example, in the Stokes example
+   * above, it would not make sense to use a
+   * <code>FESystem@<dim@>(FE_Q@<dim@>(2), 1, FE_Q@<dim@>(1), dim)</code>
+   * (note that the first velocity vector component is a $Q_2$ element,
+   * whereas all the other ones are $Q_1$ elements) as there would be points
+   * on the boundary where the $x$-velocity is defined but no corresponding
+   * $y$- or $z$-velocities.
+   *
+   * The third argument denotes the set of boundary indicators on which the
+   * boundary condition is to be enforced. Note that, as explained below, this
+   * is one of the few functions where it makes a difference where we call the
+   * function multiple times with only one boundary indicator, or whether we
+   * call the function once with the whole set of boundary indicators at once.
+   *
+   * Argument four (@p function_map) describes the boundary function $\vec
+   * u_\Gamma$ for each boundary id. The function <code>function_map[id]</code>
+   * is used on boundary with id @p id taken from the set @p boundary_ids.
+   * Each function in @p function_map is expected to have @p dim
+   * components, which are used independent of @p first_vector_component.
+   *
+   * The mapping argument is used to compute the boundary points at which the
+   * function needs to request the normal vector $\vec n$ from the boundary
+   * description.
+   *
+   * @note When combining adaptively refined meshes with hanging node
+   * constraints and boundary conditions like from the current function within
+   * one AffineConstraints object, the hanging node constraints should always
+   * be set first, and then the boundary conditions since boundary conditions
+   * are not set in the second operation on degrees of freedom that are
+   * already constrained. This makes sure that the discretization remains
+   * conforming as is needed. See the discussion on conflicting constraints in
+   * the module on
+   * @ref constraints.
+   *
+   *
+   * <h4>Computing constraints in 2d</h4>
+   *
+   * Computing these constraints requires some smarts. The main question
+   * revolves around the question what the normal vector is. Consider the
+   * following situation:
+   *
+   * <p ALIGN="center">
+   * @image html no_normal_flux_1.png
+   * </p>
+   *
+   * Here, we have two cells that use a bilinear mapping (i.e.,
+   * MappingQGeneric(1)). Consequently, for each of the cells, the normal
+   * vector is perpendicular to the straight edge. If the two edges at the top
+   * and right are meant to approximate a curved boundary (as indicated by the
+   * dashed line), then neither of the two computed normal vectors are equal
+   * to the exact normal vector (though they approximate it as the mesh is
+   * refined further). What is worse, if we constrain $\vec u \cdot \vec n=
+   * \vec u_\Gamma \cdot \vec n$ at the common vertex with the normal vector
+   * from both cells, then we constrain the vector $\vec u$ with respect to
+   * two linearly independent vectors; consequently, the constraint would be
+   * $\vec u=\vec u_\Gamma$ at this point (i.e. <i>all</i> components of the
+   * vector), which is not what we wanted.
+   *
+   * To deal with this situation, the algorithm works in the following way: at
+   * each point where we want to constrain $\vec u$, we first collect all
+   * normal vectors that adjacent cells might compute at this point. We then
+   * do not constrain $\vec u \cdot \vec n=\vec u_\Gamma \cdot \vec n$ for
+   * <i>each</i> of these normal vectors but only for the <i>average</i> of
+   * the normal vectors. In the example above, we therefore record only a
+   * single constraint $\vec u \cdot \vec {\bar n}=\vec u_\Gamma \cdot \vec
+   * {\bar n}$, where $\vec {\bar n}$ is the average of the two indicated
+   * normal vectors.
+   *
+   * Unfortunately, this is not quite enough. Consider the situation here:
+   *
+   * <p ALIGN="center">
+   * @image html no_normal_flux_2.png
+   * </p>
+   *
+   * If again the top and right edges approximate a curved boundary, and the
+   * left boundary a separate boundary (for example straight) so that the
+   * exact boundary has indeed a corner at the top left vertex, then the above
+   * construction would not work: here, we indeed want the constraint that
+   * $\vec u$ at this point (because the normal velocities with respect to
+   * both the left normal as well as the top normal vector should be zero),
+   * not that the velocity in the direction of the average normal vector is
+   * zero.
+   *
+   * Consequently, we use the following heuristic to determine whether all
+   * normal vectors computed at one point are to be averaged: if two normal
+   * vectors for the same point are computed on <i>different</i> cells, then
+   * they are to be averaged. This covers the first example above. If they are
+   * computed from the same cell, then the fact that they are different is
+   * considered indication that they come from different parts of the boundary
+   * that might be joined by a real corner, and must not be averaged.
+   *
+   * There is one problem with this scheme. If, for example, the same domain
+   * we have considered above, is discretized with the following mesh, then we
+   * get into trouble:
+   *
+   * <p ALIGN="center">
+   * @image html no_normal_flux_3.png
+   * </p>
+   *
+   * Here, the algorithm assumes that the boundary does not have a corner at
+   * the point where faces $F1$ and $F2$ join because at that point there are
+   * two different normal vectors computed from different cells. If you intend
+   * for there to be a corner of the exact boundary at this point, the only
+   * way to deal with this is to assign the two parts of the boundary
+   * different boundary indicators and call this function twice, once for each
+   * boundary indicators; doing so will yield only one normal vector at this
+   * point per invocation (because we consider only one boundary part at a
+   * time), with the result that the normal vectors will not be averaged. This
+   * situation also needs to be taken into account when using this function
+   * around reentrant corners on Cartesian meshes. If normal-flux boundary
+   * conditions are to be enforced on non-Cartesian meshes around reentrant
+   * corners, one may even get cycles in the constraints as one will in
+   * general constrain different components from the two sides. In that case,
+   * set a no-slip constraint on the reentrant vertex first.
+   *
+   *
+   * <h4>Computing constraints in 3d</h4>
+   *
+   * The situation is more complicated in 3d. Consider the following case
+   * where we want to compute the constraints at the marked vertex:
+   *
+   * <p ALIGN="center">
+   * @image html no_normal_flux_4.png
+   * </p>
+   *
+   * Here, we get four different normal vectors, one from each of the four
+   * faces that meet at the vertex. Even though they may form a complete set
+   * of vectors, it is not our intent to constrain all components of the
+   * vector field at this point. Rather, we would like to still allow
+   * tangential flow, where the term "tangential" has to be suitably defined.
+   *
+   * In a case like this, the algorithm proceeds as follows: for each cell
+   * that has computed two tangential vectors at this point, we compute the
+   * unconstrained direction as the outer product of the two tangential
+   * vectors (if necessary multiplied by minus one). We then average these
+   * tangential vectors. Finally, we compute constraints for the two
+   * directions perpendicular to this averaged tangential direction.
+   *
+   * There are cases where one cell contributes two tangential directions and
+   * another one only one; for example, this would happen if both top and
+   * front faces of the left cell belong to the boundary selected whereas only
+   * the top face of the right cell belongs to it, maybe indicating that the
+   * entire front part of the domain is a smooth manifold whereas the top
+   * really forms two separate manifolds that meet in a ridge, and that
+   * normal-flux boundary conditions are only desired on the front manifold
+   * and the right one on top. In cases like these, it's difficult to define
+   * what should happen. The current implementation simply ignores the one
+   * contribution from the cell that only contributes one normal vector. In
+   * the example shown, this is acceptable because the normal vector for the
+   * front face of the left cell is the same as the normal vector provided by
+   * the front face of the right cell (the surface is planar) but it would be
+   * a problem if the front manifold would be curved. Regardless, it is
+   * unclear how one would proceed in this case and ignoring the single cell
+   * is likely the best one can do.
+   *
+   *
+   * <h4>Results</h4>
+   *
+   * Because it makes for good pictures, here are two images of vector fields
+   * on a circle and on a sphere to which the constraints computed by this
+   * function have been applied (for illustration purposes, we enforce zero
+   * normal flux, which can more easily be computed using
+   * VectorTools::compute_no_normal_flux_constraints(), as this must
+   * lead to a <i>tangential</i> vector field):
+   *
+   * <p ALIGN="center">
+   * @image html no_normal_flux_5.png
+   * @image html no_normal_flux_6.png
+   * </p>
+   *
+   * The vectors fields are not physically reasonable but the tangentiality
+   * constraint is clearly enforced. The fact that the vector fields are zero
+   * at some points on the boundary is an artifact of the way it is created,
+   * it is not constrained to be zero at these points.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
+  void
+  compute_nonzero_normal_flux_constraints(
+    const DoFHandlerType<dim, spacedim> &dof_handler,
+    const unsigned int                   first_vector_component,
+    const std::set<types::boundary_id> & boundary_ids,
+    const std::map<types::boundary_id, const Function<spacedim, double> *>
+      &                           function_map,
+    AffineConstraints<double> &   constraints,
+    const Mapping<dim, spacedim> &mapping =
+      StaticMappingQ1<dim, spacedim>::mapping);
+
+  /**
+   * This function does the same as the
+   * compute_nonzero_normal_flux_constraints() function (see there for more
+   * information), but for the simpler case of homogeneous normal-flux
+   * constraints, i.e., for imposing the condition
+   * $\vec u \cdot \vec n= 0$. This function is used in step-31 and step-32.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
+  void
+  compute_no_normal_flux_constraints(
+    const DoFHandlerType<dim, spacedim> &dof_handler,
+    const unsigned int                   first_vector_component,
+    const std::set<types::boundary_id> & boundary_ids,
+    AffineConstraints<double> &          constraints,
+    const Mapping<dim, spacedim> &       mapping =
+      StaticMappingQ1<dim, spacedim>::mapping);
+
+  /**
+   * Compute the constraints that correspond to boundary conditions of the
+   * form $\vec u \times \vec n=\vec u_\Gamma \times \vec n$, i.e., tangential
+   * flow constraints where $\vec u$ is a vector-valued solution
+   * variable and $\vec u_\Gamma$ is prescribed vector field whose tangential
+   * component(s) we want to be equal to the tangential component(s) of the
+   * solution. This function constrains exactly those dim-1 vector-valued
+   * components that are left unconstrained by
+   * VectorTools::compute_no_normal_flux_constraints(), and leaves the one
+   * component unconstrained that is constrained by that function.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
+  void
+  compute_nonzero_tangential_flux_constraints(
+    const DoFHandlerType<dim, spacedim> &dof_handler,
+    const unsigned int                   first_vector_component,
+    const std::set<types::boundary_id> & boundary_ids,
+    const std::map<types::boundary_id, const Function<spacedim, double> *>
+      &                           function_map,
+    AffineConstraints<double> &   constraints,
+    const Mapping<dim, spacedim> &mapping =
+      StaticMappingQ1<dim, spacedim>::mapping);
+
+  /**
+   * Same as above for homogeneous tangential-flux constraints.
+   *
+   * @ingroup constraints
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, template <int, int> class DoFHandlerType>
+  void
+  compute_normal_flux_constraints(
+    const DoFHandlerType<dim, spacedim> &dof_handler,
+    const unsigned int                   first_vector_component,
+    const std::set<types::boundary_id> & boundary_ids,
+    AffineConstraints<double> &          constraints,
+    const Mapping<dim, spacedim> &       mapping =
+      StaticMappingQ1<dim, spacedim>::mapping);
+
+  //@}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_constraints_h
index ea4bc8f2b90d381261d11794676a1040df6721bd..875785d3334209a24d67a877ac2d6ae3494bff4e 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <deal.II/hp/fe_values.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_constraints.h>
 
 DEAL_II_NAMESPACE_OPEN
 
diff --git a/include/deal.II/numerics/vector_tools_integrate_difference.h b/include/deal.II/numerics/vector_tools_integrate_difference.h
new file mode 100644 (file)
index 0000000..402956a
--- /dev/null
@@ -0,0 +1,320 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_integrate_difference_h
+#define dealii_vector_tools_integrate_difference_h
+
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/numerics/vector_tools_common.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <int dim, int spacedim>
+class DoFHandler;
+template <int dim, typename Number>
+class Function;
+template <int dim, int spacedim>
+class Mapping;
+template <int dim>
+class Quadrature;
+template <int dim, int spacedim>
+class Triangulation;
+namespace hp
+{
+  template <int dim, int spacedim>
+  class DoFHandler;
+  template <int dim, int spacedim>
+  class MappingCollection;
+  template <int dim>
+  class QCollection;
+} // namespace hp
+
+
+namespace VectorTools
+{
+  /**
+   * @name Evaluation of functions and errors
+   */
+  //@{
+
+  /**
+   * Compute the cellwise error of the finite element solution.  Integrate the
+   * difference between a reference function which is given as a continuous
+   * function object, and a finite element function. The result of this
+   * function is the vector @p difference that contains one value per active
+   * cell $K$ of the triangulation. Each of the values of this vector $d$
+   * equals
+   * @f{align*}{
+   * d_K = \| u-u_h \|_X
+   * @f}
+   * where $X$ denotes the norm chosen and $u$ represents the exact solution.
+   *
+   * It is assumed that the number of components of the function @p
+   * exact_solution matches that of the finite element used by @p dof.
+   *
+   * To compute a global error norm of a finite element solution, use
+   * VectorTools::compute_global_error() with the output vector computed with
+   * this function.
+   *
+   * @param[in] mapping The mapping that is used when integrating the
+   * difference $u-u_h$.
+   * @param[in] dof The DoFHandler object that describes the finite element
+   * space in which the solution vector lives.
+   * @param[in] fe_function A vector with nodal values representing the
+   * numerical approximation $u_h$. This vector needs to correspond to the
+   * finite element space represented by @p dof.
+   * @param[in] exact_solution The exact solution that is used to compute the
+   * error.
+   * @param[out] difference The vector of values $d_K$ computed as above.
+   * @param[in] q The quadrature formula used to approximate the integral
+   * shown above. Note that some quadrature formulas are more useful than
+   * other in integrating $u-u_h$. For example, it is known that the $Q_1$
+   * approximation $u_h$ to the exact solution $u$ of a Laplace equation is
+   * particularly accurate (in fact, superconvergent, i.e. accurate to higher
+   * order) at the 4 Gauss points of a cell in 2d (or 8 points in 3d) that
+   * correspond to a QGauss(2) object. Consequently, because a QGauss(2)
+   * formula only evaluates the two solutions at these particular points,
+   * choosing this quadrature formula may indicate an error far smaller than
+   * it actually is.
+   * @param[in] norm The norm $X$ shown above that should be computed. If the
+   * norm is NormType::Hdiv_seminorm, then the finite element on which this
+   * function is called needs to have at least dim vector components, and the
+   * divergence will be computed on the first div components. This works, for
+   * example, on the finite elements used for the mixed Laplace (step-20) and
+   * the Stokes equations (step-22).
+   * @param[in] weight The additional argument @p weight allows to evaluate
+   * weighted norms.  The weight function may be scalar, establishing a
+   * spatially variable weight in the domain for all components equally. This
+   * may be used, for instance, to only integrate over parts of the domain.
+   * The weight function may also be vector-valued, with as many components as
+   * the finite element: Then, different components get different weights. A
+   * typical application is when the error with respect to only one or a
+   * subset of the solution variables is to be computed, in which case the
+   * other components would have weight values equal to zero. The
+   * ComponentSelectFunction class is particularly useful for this purpose as
+   * it provides such a "mask" weight. The weight function is expected to be
+   * positive, but negative values are not filtered. The default value of this
+   * function, a null pointer, is interpreted as "no weighting function",
+   * i.e., weight=1 in the whole domain for all vector components uniformly.
+   * @param[in] exponent This value denotes the $p$ used in computing
+   * $L^p$-norms and $W^{1,p}$-norms. The value is ignored if a @p norm other
+   * than NormType::Lp_norm, NormType::W1p_norm, or NormType::W1p_seminorm
+   * is chosen.
+   *
+   *
+   * See the general documentation of this namespace for more information.
+   *
+   * @note If the integration here happens over the cells of a
+   * parallel::distribute::Triangulation object, then this function computes
+   * the vector elements $d_K$ for an output vector with as many cells as
+   * there are active cells of the triangulation object of the current
+   * processor. However, not all active cells are in fact locally owned: some
+   * may be ghost or artificial cells (see
+   * @ref GlossGhostCell "here"
+   * and
+   * @ref GlossArtificialCell "here").
+   * The vector computed will, in the case of a distributed triangulation,
+   * contain zeros for cells that are not locally owned. As a consequence, in
+   * order to compute the <i>global</i> $L_2$ error (for example), the errors
+   * from different processors need to be combined, see
+   * VectorTools::compute_global_error().
+   *
+   * Instantiations for this template are provided for some vector types (see
+   * the general documentation of the namespace), but only for InVectors as in
+   * the documentation of the namespace, OutVector only Vector<double> and
+   * Vector<float>.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  void
+  integrate_difference(
+    const Mapping<dim, spacedim> &                           mapping,
+    const DoFHandler<dim, spacedim> &                        dof,
+    const InVector &                                         fe_function,
+    const Function<spacedim, typename InVector::value_type> &exact_solution,
+    OutVector &                                              difference,
+    const Quadrature<dim> &                                  q,
+    const NormType &                                         norm,
+    const Function<spacedim, double> *                       weight   = nullptr,
+    const double                                             exponent = 2.);
+
+  /**
+   * Call the integrate_difference() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  void
+  integrate_difference(
+    const DoFHandler<dim, spacedim> &                        dof,
+    const InVector &                                         fe_function,
+    const Function<spacedim, typename InVector::value_type> &exact_solution,
+    OutVector &                                              difference,
+    const Quadrature<dim> &                                  q,
+    const NormType &                                         norm,
+    const Function<spacedim, double> *                       weight   = nullptr,
+    const double                                             exponent = 2.);
+
+  /**
+   * Same as above for hp.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  void
+  integrate_difference(
+    const hp::MappingCollection<dim, spacedim> &             mapping,
+    const hp::DoFHandler<dim, spacedim> &                    dof,
+    const InVector &                                         fe_function,
+    const Function<spacedim, typename InVector::value_type> &exact_solution,
+    OutVector &                                              difference,
+    const hp::QCollection<dim> &                             q,
+    const NormType &                                         norm,
+    const Function<spacedim, double> *                       weight   = nullptr,
+    const double                                             exponent = 2.);
+
+  /**
+   * Call the integrate_difference() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  void
+  integrate_difference(
+    const hp::DoFHandler<dim, spacedim> &                    dof,
+    const InVector &                                         fe_function,
+    const Function<spacedim, typename InVector::value_type> &exact_solution,
+    OutVector &                                              difference,
+    const hp::QCollection<dim> &                             q,
+    const NormType &                                         norm,
+    const Function<spacedim, double> *                       weight   = nullptr,
+    const double                                             exponent = 2.);
+
+  /**
+   * Compute the cellwise error of the finite element solution.  Integrate the
+   * difference between a reference function which is given as a continuous
+   * function object, and a finite element function. The result of this
+   * function is the vector @p difference that contains one value per active
+   * cell $K$ of the triangulation. Each of the values of this vector $d$
+   * equals
+   * @f{align*}{
+   * d_K = \| u-u_h \|_X
+   * @f}
+   * where $X$ denotes the norm chosen and $u$ represents the exact solution.
+   *
+   * @deprecated Use integrate_difference(const Mapping<dim, spacedim> &, const DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &, OutVector &, const Quadrature<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  DEAL_II_DEPRECATED typename std::enable_if<
+    !std::is_same<typename InVector::value_type, double>::value>::type
+  integrate_difference(const Mapping<dim, spacedim> &    mapping,
+                       const DoFHandler<dim, spacedim> & dof,
+                       const InVector &                  fe_function,
+                       const Function<spacedim, double> &exact_solution,
+                       OutVector &                       difference,
+                       const Quadrature<dim> &           q,
+                       const NormType &                  norm,
+                       const Function<spacedim, double> *weight   = nullptr,
+                       const double                      exponent = 2.);
+
+  /**
+   * Call the integrate_difference() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   *
+   * @deprecated Use integrate_difference(const DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &exact_solution, OutVector &, const Quadrature<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  DEAL_II_DEPRECATED typename std::enable_if<
+    !std::is_same<typename InVector::value_type, double>::value>::type
+  integrate_difference(const DoFHandler<dim, spacedim> & dof,
+                       const InVector &                  fe_function,
+                       const Function<spacedim, double> &exact_solution,
+                       OutVector &                       difference,
+                       const Quadrature<dim> &           q,
+                       const NormType &                  norm,
+                       const Function<spacedim, double> *weight   = nullptr,
+                       const double                      exponent = 2.);
+
+  /**
+   * Same as above for hp.
+   *
+   * @deprecated Use integrate_difference(const hp::MappingCollection<dim, spacedim> &, const hp::DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &, OutVector &, const hp::QCollection<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  DEAL_II_DEPRECATED typename std::enable_if<
+    !std::is_same<typename InVector::value_type, double>::value>::type
+  integrate_difference(const hp::MappingCollection<dim, spacedim> &mapping,
+                       const hp::DoFHandler<dim, spacedim> &       dof,
+                       const InVector &                            fe_function,
+                       const Function<spacedim, double> &exact_solution,
+                       OutVector &                       difference,
+                       const hp::QCollection<dim> &      q,
+                       const NormType &                  norm,
+                       const Function<spacedim, double> *weight   = nullptr,
+                       const double                      exponent = 2.);
+
+  /**
+   * Call the integrate_difference() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   *
+   * @deprecated Use integrate_difference(const hp::DoFHandler<dim, spacedim> &, const InVector &, const Function<spacedim, typename InVector::value_type> &, OutVector &, const hp::QCollection<dim> &, const NormType &, const Function<spacedim, double> *, const double) instead.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  DEAL_II_DEPRECATED typename std::enable_if<
+    !std::is_same<typename InVector::value_type, double>::value>::type
+  integrate_difference(const hp::DoFHandler<dim, spacedim> &dof,
+                       const InVector &                     fe_function,
+                       const Function<spacedim, double> &   exact_solution,
+                       OutVector &                          difference,
+                       const hp::QCollection<dim> &         q,
+                       const NormType &                     norm,
+                       const Function<spacedim, double> *   weight   = nullptr,
+                       const double                         exponent = 2.);
+
+  /**
+   * Take a Vector @p cellwise_error of errors on each cell with
+   * <tt>tria.n_active_cells()</tt> entries and return the global
+   * error as given by @p norm.
+   *
+   * The @p cellwise_error vector is typically an output produced by
+   * VectorTools::integrate_difference() and you normally want to supply the
+   * same value for @p norm as you used in VectorTools::integrate_difference().
+   *
+   * If the given Triangulation is a parallel::TriangulationBase, entries
+   * in @p cellwise_error that do not correspond to locally owned cells are
+   * assumed to be 0.0 and a parallel reduction using MPI is done to compute
+   * the global error.
+   *
+   * @param tria The Triangulation with active cells corresponding with the
+   * entries in @p cellwise_error.
+   * @param cellwise_error Vector of errors on each active cell.
+   * @param norm The type of norm to compute.
+   * @param exponent The exponent $p$ to use for $L^p$-norms and
+   * $W^{1,p}$-norms. The value is ignored if a @p norm other
+   * than NormType::Lp_norm, NormType::W1p_norm, or NormType::W1p_seminorm
+   * is chosen.
+   *
+   * @note Instantiated for type Vector<double> and Vector<float>.
+   */
+  template <int dim, int spacedim, class InVector>
+  double
+  compute_global_error(const Triangulation<dim, spacedim> &tria,
+                       const InVector &                    cellwise_error,
+                       const NormType &                    norm,
+                       const double                        exponent = 2.);
+
+  //@}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_integrate_difference_h
index 5893ac557b2222b2b5afe24854f068fb590326d5..b17bcfee5dacb118ba495cccbca53e1f0b744215 100644 (file)
@@ -29,7 +29,7 @@
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_integrate_difference.h>
 
 DEAL_II_NAMESPACE_OPEN
 
diff --git a/include/deal.II/numerics/vector_tools_interpolate.h b/include/deal.II/numerics/vector_tools_interpolate.h
new file mode 100644 (file)
index 0000000..c1bbcfd
--- /dev/null
@@ -0,0 +1,302 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_interpolate_h
+#define dealii_vector_tools_interpolate_h
+
+#include <deal.II/base/config.h>
+
+#include <map>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <typename number>
+class AffineConstraints;
+class ComponentMask;
+template <int dim, int spacedim>
+class DoFHandler;
+template <typename number>
+class FullMatrix;
+template <int dim, typename Number>
+class Function;
+template <class MeshType>
+class InterGridMap;
+template <int dim, int spacedim>
+class Mapping;
+
+namespace VectorTools
+{
+  /**
+   * @name Interpolation and projection
+   */
+  //@{
+
+  /**
+   * Compute the interpolation of @p function at the support points to the
+   * finite element space described by the Triangulation and FiniteElement
+   * object with which the given DoFHandler argument is initialized. It is
+   * assumed that the number of components of @p function matches that of the
+   * finite element used by @p dof.
+   *
+   * Note that you may have to call <tt>hanging_nodes.distribute(vec)</tt>
+   * with the hanging nodes from space @p dof afterwards, to make the result
+   * continuous again.
+   *
+   * The template argument <code>DoFHandlerType</code> may either be of type
+   * DoFHandler or hp::DoFHandler.
+   *
+   * See the general documentation of this namespace for further information.
+   *
+   * @todo The @p mapping argument should be replaced by a
+   * hp::MappingCollection in case of a hp::DoFHandler.
+   */
+  template <int dim,
+            int spacedim,
+            typename VectorType,
+            template <int, int> class DoFHandlerType>
+  void
+  interpolate(
+    const Mapping<dim, spacedim> &                             mapping,
+    const DoFHandlerType<dim, spacedim> &                      dof,
+    const Function<spacedim, typename VectorType::value_type> &function,
+    VectorType &                                               vec,
+    const ComponentMask &component_mask = ComponentMask());
+
+  /**
+   * Call the @p interpolate() function above with
+   * <tt>mapping=MappingQGeneric1@<dim>@()</tt>.
+   */
+  template <int dim,
+            int spacedim,
+            typename VectorType,
+            template <int, int> class DoFHandlerType>
+  void
+  interpolate(
+    const DoFHandlerType<dim, spacedim> &                      dof,
+    const Function<spacedim, typename VectorType::value_type> &function,
+    VectorType &                                               vec,
+    const ComponentMask &component_mask = ComponentMask());
+
+  /**
+   * Interpolate different finite element spaces. The interpolation of vector
+   * @p data_1 (which is assumed to be ghosted, see @ref GlossGhostedVector)
+   * is executed from the FE space represented by @p dof_1
+   * to the vector @p data_2 on FE space @p dof_2.
+   * The interpolation on each cell is represented by the matrix @p transfer.
+   * Curved boundaries are neglected so far.
+   *
+   * Note that you may have to call <tt>hanging_nodes.distribute(data_2)</tt>
+   * with the hanging nodes from space @p dof_2 afterwards, to make the result
+   * continuous again.
+   *
+   * @note Instantiations for this template are provided for some vector types
+   * (see the general documentation of the namespace), but only the same
+   * vector for InVector and OutVector. Other combinations must be
+   * instantiated by hand.
+   */
+  template <int dim, class InVector, class OutVector, int spacedim>
+  void
+  interpolate(const DoFHandler<dim, spacedim> &dof_1,
+              const DoFHandler<dim, spacedim> &dof_2,
+              const FullMatrix<double> &       transfer,
+              const InVector &                 data_1,
+              OutVector &                      data_2);
+
+  /**
+   * This function is a kind of generalization or modification of the very
+   * first interpolate() function in the series. It interpolates a set of
+   * functions onto the finite element space defined by the DoFHandler argument,
+   * where the determination which function to use on each cell is made
+   * based on the material id (see
+   * @ref GlossMaterialId)
+   * of each cell.
+   *
+   * @param[in] mapping        The mapping to use to determine the location of
+   *   support points at which the functions are to be evaluated.
+   * @param[in] dof_handler    DoFHandler initialized with Triangulation and
+   *   FiniteElement objects and that defines the finite element space.
+   * @param[in] function_map   A std::map reflecting the correspondence between
+   *   material ids on those cells on which something should be interpolated,
+   *   and the functions to be interpolated onto the finite element space.
+   * @param[out] dst           The global finie element vector holding the
+   *   output of the interpolated values.
+   * @param[in] component_mask A mask of components that shall be interpolated.
+   *
+   * @note If the algorithm encounters a cell whose material id is not listed
+   * in the given @p function_map, then @p dst will not be updated in the
+   * respective degrees of freedom of the output vector. For example, if
+   * @p dst was initialized to zero, then those zeros which correspond to
+   * the missed material ids will still remain in @p dst after calling
+   * this function.
+   *
+   * @note Degrees of freedom located on faces between cells of different
+   * material ids will get their value by that cell which was called last in
+   * the respective loop over cells implemented in this function. Since the
+   * order of cells is somewhat arbitrary, you cannot control it. However, if
+   * you want to have control over the order in which cells are visited, let us
+   * take a
+   * look at the following example: Let @p u be a variable of interest which
+   * is approximated by some CG finite element. Let @p 0, @p 1 and @p 2 be
+   * material ids of cells on the triangulation. Let 0: 0.0, 1: 1.0, 2: 2.0 be
+   * the whole @p function_map that you want to pass to this function, where
+   * @p key is a material id and @p value is a value of @p u. By using the
+   * whole @p function_map you do not really know which values will be
+   * assigned to the face DoFs. On the other hand, if you split the whole @p
+   * function_map into three smaller independent objects 0: 0.0 and 1: 1.0 and
+   * 2: 2.0 and make three distinct calls of this function passing each of
+   * these objects separately (the order depends on what you want to get
+   * between cells), then each subsequent call will rewrite the intercell @p
+   * dofs of the previous one.
+   *
+   * @author Valentin Zingan, 2013
+   */
+  template <int dim,
+            int spacedim,
+            typename VectorType,
+            template <int, int> class DoFHandlerType>
+  void
+  interpolate_based_on_material_id(
+    const Mapping<dim, spacedim> &       mapping,
+    const DoFHandlerType<dim, spacedim> &dof_handler,
+    const std::map<types::material_id,
+                   const Function<spacedim, typename VectorType::value_type> *>
+      &                  function_map,
+    VectorType &         dst,
+    const ComponentMask &component_mask = ComponentMask());
+
+  /**
+   * Compute the interpolation of a @p dof1-function @p u1 to a @p dof2-function
+   * @p u2, where @p dof1 and @p dof2 represent different triangulations with
+   * a common coarse grid.
+   *
+   * dof1 and dof2 need to have the same finite element discretization.
+   *
+   * Note that for continuous elements on grids with hanging nodes (i.e.
+   * locally refined grids) this function does not give the expected output.
+   * Indeed, the resulting output vector does not necessarily respect
+   * continuity requirements at hanging nodes, due to local cellwise
+   * interpolation.
+   *
+   * For this case (continuous elements on grids with hanging nodes), please
+   * use the interpolate_to_different_mesh function with an additional
+   * AffineConstraints argument, see below, or make the field conforming
+   * yourself by calling the @p AffineConstraints::distribute function of your
+   * hanging node constraints object.
+   *
+   * @note This function works with parallel::distributed::Triangulation, but
+   * only if the parallel partitioning is the same for both meshes (see the
+   * parallel::distributed::Triangulation<dim>::no_automatic_repartitioning
+   * flag).
+   */
+  template <int dim,
+            int spacedim,
+            typename VectorType,
+            template <int, int> class DoFHandlerType>
+  void
+  interpolate_to_different_mesh(const DoFHandlerType<dim, spacedim> &dof1,
+                                const VectorType &                   u1,
+                                const DoFHandlerType<dim, spacedim> &dof2,
+                                VectorType &                         u2);
+
+  /**
+   * Compute the interpolation of a @p dof1-function @p u1 to a @p dof2-function
+   * @p u2, where @p dof1 and @p dof2 represent different triangulations with
+   * a common coarse grid.
+   *
+   * dof1 and dof2 need to have the same finite element discretization.
+   *
+   * @p constraints is a hanging node constraints object corresponding to @p
+   * dof2. This object is particularly important when interpolating onto
+   * continuous elements on grids with hanging nodes (locally refined grids):
+   * Without it - due to cellwise interpolation - the resulting output vector
+   * does not necessarily respect continuity requirements at hanging nodes.
+   */
+  template <int dim,
+            int spacedim,
+            typename VectorType,
+            template <int, int> class DoFHandlerType>
+  void
+  interpolate_to_different_mesh(
+    const DoFHandlerType<dim, spacedim> &                     dof1,
+    const VectorType &                                        u1,
+    const DoFHandlerType<dim, spacedim> &                     dof2,
+    const AffineConstraints<typename VectorType::value_type> &constraints,
+    VectorType &                                              u2);
+
+  /**
+   * The same function as above, but takes an InterGridMap object directly as
+   * a parameter. Useful for interpolating several vectors at the same time.
+   *
+   * @p intergridmap has to be initialized via InterGridMap::make_mapping
+   * pointing from a source DoFHandler to a destination DoFHandler.
+   */
+  template <int dim,
+            int spacedim,
+            typename VectorType,
+            template <int, int> class DoFHandlerType>
+  void
+  interpolate_to_different_mesh(
+    const InterGridMap<DoFHandlerType<dim, spacedim>> &       intergridmap,
+    const VectorType &                                        u1,
+    const AffineConstraints<typename VectorType::value_type> &constraints,
+    VectorType &                                              u2);
+
+  //@}
+
+  /**
+   * Geometrical interpolation
+   */
+  //@{
+  /**
+   * Given a DoFHandler containing at least a spacedim vector field, this
+   * function interpolates the Triangulation at the support points of a FE_Q()
+   * finite element of the same degree as the degree of the required
+   * components.
+   *
+   * Curved manifold are respected, and the resulting VectorType will be
+   * geometrically consistent. The resulting map is guaranteed to be
+   * interpolatory at the support points of a FE_Q() finite element of the
+   * same degree as the degree of the required components.
+   *
+   * If the underlying finite element is an FE_Q(1)^spacedim, then the
+   * resulting @p VectorType is a finite element field representation of the
+   * vertices of the Triangulation.
+   *
+   * The optional ComponentMask argument can be used to specify what
+   * components of the FiniteElement to use to describe the geometry. If no
+   * mask is specified at construction time, then a default one is used, i.e.,
+   * the first spacedim components of the FiniteElement are assumed to
+   * represent the geometry of the problem.
+   *
+   * This function is only implemented for FiniteElements where the specified
+   * components are primitive.
+   *
+   * @author Luca Heltai, 2015
+   */
+  template <int dim,
+            int spacedim,
+            template <int, int> class DoFHandlerType,
+            typename VectorType>
+  void
+  get_position_vector(const DoFHandlerType<dim, spacedim> &dh,
+                      VectorType &                         vector,
+                      const ComponentMask &mask = ComponentMask());
+
+  //@}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_interpolate_h
index 88d5a14f4d1283bf0c18a3c6e37c5a435c14214d..ab82c4c5988c83dbc5c69a8a63cc506139c62b7c 100644 (file)
@@ -34,7 +34,7 @@
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_interpolate.h>
 
 DEAL_II_NAMESPACE_OPEN
 
diff --git a/include/deal.II/numerics/vector_tools_mean_value.h b/include/deal.II/numerics/vector_tools_mean_value.h
new file mode 100644 (file)
index 0000000..e231bb8
--- /dev/null
@@ -0,0 +1,136 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_mean_value_h
+#define dealii_vector_tools_mean_value_h
+
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/fe/mapping_q1.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <int dim, int spacedim>
+class DoFHandler;
+
+namespace VectorTools
+{
+  /**
+   * Mean value operations
+   */
+  //@{
+
+  /**
+   * Subtract the (algebraic) mean value from a vector.
+   *
+   * This function is most frequently used as a mean-value filter for Stokes:
+   * The pressure in Stokes' equations with only Dirichlet boundaries for the
+   * velocities is only determined up to a constant. This function allows to
+   * subtract the mean value of the pressure. It is usually called in a
+   * preconditioner and generates updates with mean value zero. The mean value
+   * is computed as the mean value of the degrees of freedom values as given
+   * by the input vector; they are not weighted by the area of cells, i.e. the
+   * mean is computed as $\sum_i v_i$, rather than as $\int_\Omega v(x) =
+   * \int_\Omega \sum_i v_i \phi_i(x)$. The latter can be obtained from the
+   * VectorTools::compute_mean_function, however.
+   *
+   * Apart from the vector @p v to operate on, this function takes a boolean
+   * mask @p p_select that has a true entry for every element of the vector
+   * for which the mean value shall be computed and later subtracted. The
+   * argument is used to denote which components of the solution vector
+   * correspond to the pressure, and avoid touching all other components of
+   * the vector, such as the velocity components. (Note, however, that the
+   * mask is not a
+   * @ref GlossComponentMask
+   * operating on the vector components of the finite element the solution
+   * vector @p v may be associated with; rather, it is a mask on the entire
+   * vector, without reference to what the vector elements mean.)
+   *
+   * The boolean mask @p p_select has an empty vector as default value, which
+   * will be interpreted as selecting all vector elements, hence, subtracting
+   * the algebraic mean value on the whole vector. This allows to call this
+   * function without a boolean mask if the whole vector should be processed.
+   *
+   * @note In the context of using this function to filter out the kernel of
+   * an operator (such as the null space of the Stokes operator that consists
+   * of the constant pressures), this function only makes sense for finite
+   * elements for which the null space indeed consists of the vector
+   * $(1,1,\ldots,1)^T$. This is the case for example for the usual Lagrange
+   * elements where the sum of all shape functions equals the function that is
+   * constant one. However, it is not true for some other functions: for
+   * example, for the FE_DGP element (another valid choice for the pressure in
+   * Stokes discretizations), the first shape function on each cell is
+   * constant while further elements are $L_2$ orthogonal to it (on the
+   * reference cell); consequently, the sum of all shape functions is not
+   * equal to one, and the vector that is associated with the constant mode is
+   * not equal to $(1,1,\ldots,1)^T$. For such elements, a different procedure
+   * has to be used when subtracting the mean value.
+   *
+   * @warning This function can only be used for distributed vector classes
+   * provided the boolean mask is empty, i.e. selecting the whole vector.
+   */
+  template <typename VectorType>
+  void
+  subtract_mean_value(VectorType &v, const std::vector<bool> &p_select = {});
+
+
+  /**
+   * Compute the mean value of one component of the solution.
+   *
+   * This function integrates the chosen component over the whole domain and
+   * returns the result, i.e. it computes $\frac{1}{|\Omega|}\int_\Omega
+   * [u_h(x)]_c \; dx$ where $c$ is the vector component and $u_h$ is the
+   * function representation of the nodal vector given as fourth argument. The
+   * integral is evaluated numerically using the quadrature formula given as
+   * third argument.
+   *
+   * This function is used in the "Possibilities for extensions" part of the
+   * results section of
+   * @ref step_3 "step-3".
+   *
+   * @note The function is most often used when solving a problem whose
+   * solution is only defined up to a constant, for example a pure Neumann
+   * problem or the pressure in a Stokes or Navier-Stokes problem. In both
+   * cases, subtracting the mean value as computed by the current function,
+   * from the nodal vector does not generally yield the desired result of a
+   * finite element function with mean value zero. In fact, it only works for
+   * Lagrangian elements. For all other elements, you will need to compute the
+   * mean value and subtract it right inside the evaluation routine.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  typename VectorType::value_type
+  compute_mean_value(const Mapping<dim, spacedim> &   mapping,
+                     const DoFHandler<dim, spacedim> &dof,
+                     const Quadrature<dim> &          quadrature,
+                     const VectorType &               v,
+                     const unsigned int               component);
+
+  /**
+   * Call the other compute_mean_value() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  typename VectorType::value_type
+  compute_mean_value(const DoFHandler<dim, spacedim> &dof,
+                     const Quadrature<dim> &          quadrature,
+                     const VectorType &               v,
+                     const unsigned int               component);
+  //@}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_mean_value_h
index ea15f69e153c5d96f8ca14e93b229b103dec0ee8..c154cc04d2084aa2783b00bdc5255d896a2a63e2 100644 (file)
@@ -28,7 +28,7 @@
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_mean_value.h>
 
 
 DEAL_II_NAMESPACE_OPEN
diff --git a/include/deal.II/numerics/vector_tools_point_gradient.h b/include/deal.II/numerics/vector_tools_point_gradient.h
new file mode 100644 (file)
index 0000000..40cfc86
--- /dev/null
@@ -0,0 +1,309 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_point_gradient_h
+#define dealii_vector_tools_point_gradient_h
+
+
+#include <deal.II/base/config.h>
+
+
+DEAL_II_NAMESPACE_OPEN
+
+template <int dim, int spacedim>
+class DoFHandler;
+template <int dim, typename Number>
+class Function;
+template <int dim, int spacedim>
+class Mapping;
+template <int dim, typename Number>
+class Point;
+template <int rank_, int dim, typename Number>
+class Tensor;
+template <typename Number>
+class Vector;
+namespace hp
+{
+  template <int dim, int spacedim>
+  class DoFHandler;
+  template <int dim, int spacedim>
+  class MappingCollection;
+} // namespace hp
+
+namespace VectorTools
+{
+  /**
+   * @name Evaluation of functions and errors
+   */
+  //@{
+
+  /**
+   * Evaluate a possibly vector-valued finite element function defined by the
+   * given DoFHandler and nodal vector at the given point, and return the
+   * (vector) gradient of this function through the last argument.
+   *
+   * This is a wrapper function using a Q1-mapping for cell boundaries to call
+   * the other point_gradient() function.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_gradient(
+    const DoFHandler<dim, spacedim> &dof,
+    const VectorType &               fe_function,
+    const Point<spacedim, double> &  point,
+    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_gradient(
+    const hp::DoFHandler<dim, spacedim> &dof,
+    const VectorType &                   fe_function,
+    const Point<spacedim, double> &      point,
+    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
+
+  /**
+   * Evaluate a scalar finite element function defined by the given DoFHandler
+   * and nodal vector at the given point, and return the gradient of this
+   * function.
+   *
+   * Compared with the other function of the same name, this is a wrapper
+   * function using a Q1-mapping for cells.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  Tensor<1, spacedim, typename VectorType::value_type>
+  point_gradient(const DoFHandler<dim, spacedim> &dof,
+                 const VectorType &               fe_function,
+                 const Point<spacedim, double> &  point);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  Tensor<1, spacedim, typename VectorType::value_type>
+  point_gradient(const hp::DoFHandler<dim, spacedim> &dof,
+                 const VectorType &                   fe_function,
+                 const Point<spacedim, double> &      point);
+
+  /**
+   * Evaluate a possibly vector-valued finite element function defined by the
+   * given DoFHandler and nodal vector at the given point, and return the
+   * gradients of this function through the last argument.
+   *
+   * Compared with the other function of the same name, this function uses an
+   * arbitrary mapping for evaluation.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_gradient(
+    const Mapping<dim, spacedim> &   mapping,
+    const DoFHandler<dim, spacedim> &dof,
+    const VectorType &               fe_function,
+    const Point<spacedim, double> &  point,
+    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_gradient(
+    const hp::MappingCollection<dim, spacedim> &mapping,
+    const hp::DoFHandler<dim, spacedim> &       dof,
+    const VectorType &                          fe_function,
+    const Point<spacedim, double> &             point,
+    std::vector<Tensor<1, spacedim, typename VectorType::value_type>> &value);
+
+  /**
+   * Evaluate a scalar finite element function defined by the given DoFHandler
+   * and nodal vector at the given point, and return the gradient of this
+   * function.
+   *
+   * Compared with the other function of the same name, this function uses an
+   * arbitrary mapping for evaluation.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  Tensor<1, spacedim, typename VectorType::value_type>
+  point_gradient(const Mapping<dim, spacedim> &   mapping,
+                 const DoFHandler<dim, spacedim> &dof,
+                 const VectorType &               fe_function,
+                 const Point<spacedim, double> &  point);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the gradient of the finite element field either
+   *   here or there, depending on which cell the point is found in. Since
+   *   the gradient is, for most elements, discontinuous from one cell or
+   *   the other, you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  Tensor<1, spacedim, typename VectorType::value_type>
+  point_gradient(const hp::MappingCollection<dim, spacedim> &mapping,
+                 const hp::DoFHandler<dim, spacedim> &       dof,
+                 const VectorType &                          fe_function,
+                 const Point<spacedim, double> &             point);
+
+  //@}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_point_gradient_h
index 3499088de4f14ad1239f25c91128775b4b4ee1ba..68b171e9f5bc8b0d7cffb6e80c06428adb2dc9aa 100644 (file)
@@ -32,7 +32,8 @@
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_common.h>
+#include <deal.II/numerics/vector_tools_point_gradient.h>
 
 DEAL_II_NAMESPACE_OPEN
 
diff --git a/include/deal.II/numerics/vector_tools_point_value.h b/include/deal.II/numerics/vector_tools_point_value.h
new file mode 100644 (file)
index 0000000..53a1d91
--- /dev/null
@@ -0,0 +1,555 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_point_value_h
+#define dealii_vector_tools_point_value_h
+
+
+#include <deal.II/base/config.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <int dim, int spacedim>
+class DoFHandler;
+template <int dim, typename Number>
+class Function;
+template <int dim, int spacedim>
+class Mapping;
+template <int dim, typename Number>
+class Point;
+template <typename Number>
+class Vector;
+namespace hp
+{
+  template <int dim, int spacedim>
+  class DoFHandler;
+  template <int dim, int spacedim>
+  class MappingCollection;
+} // namespace hp
+
+namespace VectorTools
+{
+  /**
+   * @name Assembling of right hand sides
+   */
+  //@{
+
+  /**
+   * Create a right hand side vector for a point source at point @p p. In
+   * other words, it creates a vector $F$ so that $F_i = \int_\Omega
+   * \delta(x-p) \varphi_i(x) dx$ where $\varphi_i$ are the shape functions
+   * described by @p dof_handler and @p p is the point at which the delta
+   * function is located. Prior content of the given @p rhs_vector
+   * vector is deleted. This function is for the case of a scalar finite
+   * element.
+   *
+   * This function is typically used in one of these two contexts:
+   * - Let's say you want to solve the same kind of problems many times
+   *   over, with different values for right hand sides or coefficients,
+   *   and then evaluate the solution at the same point every time. You
+   *   could do this by calling VectorTools::point_value() after each
+   *   solve, or you could realize that to evaluate the solution $u_h$
+   *   at a point $p$, you could rearrange operations like this:
+   *   @f{align*}{
+   *     u_h(p) &= \sum_j U_j \varphi_j(p) = \sum_j U_j F_j
+   *       \\   &= U \cdot F
+   *   @f}
+   *   with the vector as defined above. In other words, point evaluation
+   *   can be achieved with just a single vector-vector product, and the
+   *   vector $F$ can be computed once and for all and reused
+   *   for each solve, without having to go through the mesh every time
+   *   to find out which cell (and where in the cell) the point $p$ is
+   *   located.
+   * - This function is also useful if you wanted to compute the Green's
+   *   function for the problem you are solving. This is because the
+   *   Green's function $G(x,p)$ is defined by
+   *   @f{align*}{
+   *     L G(x,p) &= \delta(x-p)
+   *   @f}
+   *   where $L$ is the differential operator of your problem. The discrete
+   *   version then requires computing the right hand side vector
+   *   $F_i = \int_\Omega \varphi_i(x) \delta(x-p)$, which is exactly
+   *   the vector computed by the current function.
+   *
+   * While maybe not relevant for documenting <i>what</i> this
+   * function does, it may be interesting to note that delta functions
+   * do not exist in reality, and consequently, using this function
+   * does not model any real situation. This is, because no real
+   * object is able to focus an infinite force density at an
+   * infinitesimally small part of the domain (rather, all real
+   * devices will spread out the force over a finite area); nor is it
+   * possible to measure values at individual points (but all
+   * measurements will somehow be averaged over small areas). Only if
+   * this area is so small that it cannot be resolved by any mesh does
+   * it make sense to model the situation in a way that uses a delta
+   * function with the same overall force or sensitivity. On the other
+   * hand, a situation that is probably more fruitfully simulated with
+   * a delta function is the electric potential of a point source; in
+   * this case, the solution is known to have a logarithmic
+   * singularity (in 2d) or a $\frac{1}{r}$ singularity (in 3d),
+   * neither of which is bounded.
+   *
+   * Mathematically, the use of delta functions typically leads to exact
+   * solutions to which the numerically obtained, approximate solution does
+   * not converge. This is because, taking the Laplace equation as an example,
+   * the error between exact and numerical solution can be bounded by the
+   * expression
+   * @f{align*}{
+   *   \| u-u_h \|_{L_2} \le C h \| \nabla u \|_{L_2}
+   * @f}
+   * but when using a delta function on the right hand side, the term
+   * $\| \nabla u \|_{L_2} = |u|_{H^1}$ is not finite. This can be seen
+   * by using the a-priori bound for solutions of the Laplace equation
+   * $-\Delta u = f$ that states that $|u|_{H^1} \le \|f\|_{H^{-1}}$.
+   * When using a delta function as right hand side, $f(x)=\delta(x-p)$,
+   * one would need to take the $H^{-1}$ norm of a delta function, which
+   * however is not finite because $\delta(\cdot-p) \not\in H^{-1}$.
+   *
+   * The consequence of all of this is that the exact solution of the
+   * Laplace equation with a delta function on the right hand side --
+   * i.e., the <i>Green's function</i> -- has a singularity at $p$ that
+   * is so strong that it cannot be resolved by a finite element
+   * solution, and consequently finite element approximations do not
+   * converge towards the exact solution in any of the usual norms.
+   *
+   * All of this is also the case for all of the other usual second-order
+   * partial differential equations in dimensions two or higher. (Because
+   * in dimension two and higher, $H^1$ functions are not necessarily
+   * continuous, and consequently the delta function is not in the dual
+   * space $H^{-1}$.)
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(const Mapping<dim, spacedim> &   mapping,
+                             const DoFHandler<dim, spacedim> &dof_handler,
+                             const Point<spacedim, double> &  p,
+                             Vector<double> &                 rhs_vector);
+
+  /**
+   * Call the create_point_source_vector() function, see above, with
+   * an implied default $Q_1$ mapping object.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(const DoFHandler<dim, spacedim> &dof_handler,
+                             const Point<spacedim, double> &  p,
+                             Vector<double> &                 rhs_vector);
+
+  /**
+   * Like the previous set of functions, but for hp objects.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(
+    const hp::MappingCollection<dim, spacedim> &mapping,
+    const hp::DoFHandler<dim, spacedim> &       dof_handler,
+    const Point<spacedim, double> &             p,
+    Vector<double> &                            rhs_vector);
+
+  /**
+   * Like the previous set of functions, but for hp objects. The function uses
+   * an implied default $Q_1$ mapping object. Note that if your hp::DoFHandler
+   * uses any active fe index other than zero, then you need to call the
+   * function above that provides a mapping object for each active fe index.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(const hp::DoFHandler<dim, spacedim> &dof_handler,
+                             const Point<spacedim, double> &      p,
+                             Vector<double> &                     rhs_vector);
+
+  /**
+   * Create a right hand side vector for a point source at point @p p. This
+   * variation of the function is meant for vector-valued problems with
+   * exactly dim components (it will also work for problems with more than dim
+   * components, and in this case simply consider only the first dim
+   * components of the shape functions). It computes a right hand side that
+   * corresponds to a forcing function that is equal to a delta function times
+   * a given direction. In other words, it creates a vector $F$ so that $F_i =
+   * \int_\Omega [\mathbf d \delta(x-p)] \cdot \varphi_i(x) dx$. Note here that
+   * $\varphi_i$ is a vector-valued function. $\mathbf d$ is the given direction
+   * of the source term $\mathbf d \delta(x-p)$ and corresponds to the @p
+   * direction argument to be passed to this function.
+   *
+   * Prior content of the given @p rhs_vector vector is deleted.
+   *
+   * See the discussion of the first create_point_source_vector() variant for
+   * more on the use of delta functions.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(const Mapping<dim, spacedim> &   mapping,
+                             const DoFHandler<dim, spacedim> &dof_handler,
+                             const Point<spacedim, double> &  p,
+                             const Point<dim, double> &       direction,
+                             Vector<double> &                 rhs_vector);
+
+  /**
+   * Call the create_point_source_vector() function for vector-valued finite
+   * elements, see above, with an implied default $Q_1$ mapping object.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(const DoFHandler<dim, spacedim> &dof_handler,
+                             const Point<spacedim, double> &  p,
+                             const Point<dim, double> &       direction,
+                             Vector<double> &                 rhs_vector);
+
+  /**
+   * Like the previous set of functions, but for hp objects.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(
+    const hp::MappingCollection<dim, spacedim> &mapping,
+    const hp::DoFHandler<dim, spacedim> &       dof_handler,
+    const Point<spacedim, double> &             p,
+    const Point<dim, double> &                  direction,
+    Vector<double> &                            rhs_vector);
+
+  /**
+   * Like the previous set of functions, but for hp objects. The function uses
+   * an implied default $Q_1$ mapping object. Note that if your hp::DoFHandler
+   * uses any active fe index other than zero, then you need to call the
+   * function above that provides a mapping object for each active fe index.
+   */
+  template <int dim, int spacedim>
+  void
+  create_point_source_vector(const hp::DoFHandler<dim, spacedim> &dof_handler,
+                             const Point<spacedim, double> &      p,
+                             const Point<dim, double> &           direction,
+                             Vector<double> &                     rhs_vector);
+
+  // @}
+
+  /**
+   * @name Evaluation of functions and errors
+   */
+  //@{
+
+  /**
+   * Point error evaluation. Find the first cell containing the given point
+   * and compute the difference of a (possibly vector-valued) finite element
+   * function and a continuous function (with as many vector components as the
+   * finite element) at this point.
+   *
+   * This is a wrapper function using a Q1-mapping for cell boundaries to call
+   * the other point_difference() function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_difference(
+    const DoFHandler<dim, spacedim> &                          dof,
+    const VectorType &                                         fe_function,
+    const Function<spacedim, typename VectorType::value_type> &exact_solution,
+    Vector<typename VectorType::value_type> &                  difference,
+    const Point<spacedim, double> &                            point);
+
+  /**
+   * Point error evaluation. Find the first cell containing the given point
+   * and compute the difference of a (possibly vector-valued) finite element
+   * function and a continuous function (with as many vector components as the
+   * finite element) at this point.
+   *
+   * Compared with the other function of the same name, this function uses an
+   * arbitrary mapping to evaluate the difference.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_difference(
+    const Mapping<dim, spacedim> &                             mapping,
+    const DoFHandler<dim, spacedim> &                          dof,
+    const VectorType &                                         fe_function,
+    const Function<spacedim, typename VectorType::value_type> &exact_solution,
+    Vector<typename VectorType::value_type> &                  difference,
+    const Point<spacedim, double> &                            point);
+
+  /**
+   * Evaluate a possibly vector-valued finite element function defined by the
+   * given DoFHandler and nodal vector @p fe_function at the given point @p
+   * point, and return the (vector) value of this function through the last
+   * argument.
+   *
+   * This function uses a $Q_1$-mapping for the cell the point is evaluated
+   * in. If you need to evaluate using a different mapping (for example when
+   * using curved boundaries), use the point_difference() function that takes
+   * a mapping.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   *   exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_value(const DoFHandler<dim, spacedim> &        dof,
+              const VectorType &                       fe_function,
+              const Point<spacedim, double> &          point,
+              Vector<typename VectorType::value_type> &value);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_value(const hp::DoFHandler<dim, spacedim> &    dof,
+              const VectorType &                       fe_function,
+              const Point<spacedim, double> &          point,
+              Vector<typename VectorType::value_type> &value);
+
+  /**
+   * Evaluate a scalar finite element function defined by the given DoFHandler
+   * and nodal vector @p fe_function at the given point @p point, and return
+   * the value of this function.
+   *
+   * This function uses a Q1-mapping for the cell the point is evaluated
+   * in. If you need to evaluate using a different mapping (for example when
+   * using curved boundaries), use the point_difference() function that takes
+   * a mapping.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * This function is used in the "Possibilities for extensions" part of the
+   * results section of
+   * @ref step_3 "step-3".
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  typename VectorType::value_type
+  point_value(const DoFHandler<dim, spacedim> &dof,
+              const VectorType &               fe_function,
+              const Point<spacedim, double> &  point);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  typename VectorType::value_type
+  point_value(const hp::DoFHandler<dim, spacedim> &dof,
+              const VectorType &                   fe_function,
+              const Point<spacedim, double> &      point);
+
+  /**
+   * Evaluate a possibly vector-valued finite element function defined by the
+   * given DoFHandler and nodal vector @p fe_function at the given point @p
+   * point, and return the (vector) value of this function through the last
+   * argument.
+   *
+   * Compared with the other function of the same name, this function uses an
+   * arbitrary mapping to evaluate the point value.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_value(const Mapping<dim, spacedim> &           mapping,
+              const DoFHandler<dim, spacedim> &        dof,
+              const VectorType &                       fe_function,
+              const Point<spacedim, double> &          point,
+              Vector<typename VectorType::value_type> &value);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  point_value(const hp::MappingCollection<dim, spacedim> &mapping,
+              const hp::DoFHandler<dim, spacedim> &       dof,
+              const VectorType &                          fe_function,
+              const Point<spacedim, double> &             point,
+              Vector<typename VectorType::value_type> &   value);
+
+  /**
+   * Evaluate a scalar finite element function defined by the given DoFHandler
+   * and nodal vector @p fe_function at the given point @p point, and return
+   * the value of this function.
+   *
+   * Compared with the other function of the same name, this function uses an
+   * arbitrary mapping to evaluate the difference.
+   *
+   * This function is not particularly cheap. This is because it first
+   * needs to find which cell a given point is in, then find the point
+   * on the reference cell that matches the given evaluation point,
+   * and then evaluate the shape functions there. You probably do not
+   * want to use this function to evaluate the solution at <i>many</i>
+   * points. For this kind of application, the FEFieldFunction class
+   * offers at least some optimizations. On the other hand, if you
+   * want to evaluate <i>many solutions</i> at the same point, you may
+   * want to look at the VectorTools::create_point_source_vector()
+   * function.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  typename VectorType::value_type
+  point_value(const Mapping<dim, spacedim> &   mapping,
+              const DoFHandler<dim, spacedim> &dof,
+              const VectorType &               fe_function,
+              const Point<spacedim, double> &  point);
+
+  /**
+   * Same as above for hp.
+   *
+   * @note If the cell in which the point is found is not locally owned, an
+   * exception of type VectorTools::ExcPointNotAvailableHere is thrown.
+   *
+   * @note This function needs to find the cell within which a point lies,
+   *   and this can only be done up to a certain numerical tolerance of course.
+   *   Consequently, for points that are on, or close to, the boundary of
+   *   a cell, you may get the value of the finite element field either
+   *   here or there, depending on which cell the point is found in. This
+   *   does not matter (to within the same tolerance) if the finite element
+   *   field is continuous. On the other hand, if the finite element in use
+   *   is <i>not</i> continuous, then you will get unpredictable values for
+   *   points on or close to the boundary of the cell, as one would expect
+   *   when trying to evaluate point values of discontinuous functions.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  typename VectorType::value_type
+  point_value(const hp::MappingCollection<dim, spacedim> &mapping,
+              const hp::DoFHandler<dim, spacedim> &       dof,
+              const VectorType &                          fe_function,
+              const Point<spacedim, double> &             point);
+  //@}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_point_value_h
index fc0b2230590e733d77ad5f40f4213504643745e0..9f59e2066026f98ca78b92d28e8532cbc5d53d36 100644 (file)
@@ -32,7 +32,8 @@
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_common.h>
+#include <deal.II/numerics/vector_tools_point_value.h>
 
 
 DEAL_II_NAMESPACE_OPEN
diff --git a/include/deal.II/numerics/vector_tools_project.h b/include/deal.II/numerics/vector_tools_project.h
new file mode 100644 (file)
index 0000000..9c98590
--- /dev/null
@@ -0,0 +1,306 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2019 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_project_h
+#define dealii_vector_tools_project_h
+
+
+#include <deal.II/base/config.h>
+
+#include <memory>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <typename number>
+class AffineConstraints;
+template <int dim, int spacedim>
+class DoFHandler;
+template <int dim, typename Number>
+class Function;
+template <int dim, int spacedim>
+class Mapping;
+template <int dim, typename number, typename VectorizedArrayType>
+class MatrixFree;
+template <int dim>
+class Quadrature;
+template <int dim>
+class QGauss;
+template <typename Number, std::size_t width>
+class VectorizedArray;
+namespace hp
+{
+  template <int dim, int spacedim>
+  class DoFHandler;
+  template <int dim, int spacedim>
+  class MappingCollection;
+  template <int dim>
+  class QCollection;
+} // namespace hp
+
+
+namespace VectorTools
+{
+  /**
+   * @name Interpolation and projection
+   */
+  //@{
+
+  /**
+   * Compute the projection of @p function to the finite element space. In other
+   * words, given a function $f(\mathbf x)$, the current function computes a
+   * finite element function $f_h(\mathbf x)=\sum_j F_j \varphi_j(\mathbf x)$
+   * characterized by the (output) vector of nodal values $F$ that satisfies
+   * the equation
+   * @f{align*}{
+   *   (\varphi_i, f_h)_\Omega = (\varphi_i,f)_\Omega
+   * @f}
+   * for all test functions $\varphi_i$. This requires solving a linear system
+   * involving the mass matrix since the equation above is equivalent to
+   * the linear system
+   * @f{align*}{
+   *   \sum_j (\varphi_i, \varphi_j)_\Omega F_j = (\varphi_i,f)_\Omega
+   * @f}
+   * which can also be written as $MF = \Phi$ with
+   * $M_{ij} = (\varphi_i, \varphi_j)_\Omega$ and
+   * $\Phi_i = (\varphi_i,f)_\Omega$.
+   *
+   * By default, no boundary values for $f_h$ are needed nor
+   * imposed, but there are optional parameters to this function that allow
+   * imposing either zero boundary values or, in a first step, to project
+   * the boundary values of $f$ onto the finite element space on the boundary
+   * of the mesh in a similar way to above, and then using these values as the
+   * imposed boundary values for $f_h$. The ordering of arguments to this
+   * function is such that you need not give a second quadrature formula (of
+   * type `Quadrature<dim-1>` and used for the computation of the matrix and
+   * right hand side for the projection of boundary values) if you
+   * don't want to project to the boundary first, but that you must if you want
+   * to do so.
+   *
+   * A MatrixFree implementation is used if the following conditions are met:
+   * - @p enforce_zero_boundary is false,
+   * - @p project_to_boundary_first is false,
+   * - the FiniteElement is supported by the MatrixFree class,
+   * - the FiniteElement has less than five components
+   * - the degree of the FiniteElement is less than nine.
+   * - dim==spacedim
+   *
+   * In this case, this function performs numerical quadrature using the given
+   * quadrature formula for integration of the right hand side $\Phi_i$ while a
+   * QGauss(fe_degree+2) object is used for the mass operator. You should
+   * therefore make sure that the given quadrature formula is sufficiently
+   * accurate for creating the right-hand side.
+   *
+   * Otherwise, only serial Triangulations are supported and the mass matrix
+   * is assembled using MatrixTools::create_mass_matrix. The given
+   * quadrature rule is then used for both the matrix and the right-hand side.
+   * You should therefore make sure that the given quadrature formula is also
+   * sufficient for creating the mass matrix. In particular, the degree of the
+   * quadrature formula must be sufficiently high to ensure that the mass
+   * matrix is invertible. For example, if you are using a FE_Q(k) element,
+   * then the integrand of the matrix entries $M_{ij}$ is of polynomial
+   * degree $2k$ in each variable, and you need a Gauss quadrature formula
+   * with $k+1$ points in each coordinate direction to ensure that $M$
+   * is invertible.
+   *
+   * See the general documentation of this namespace for further information.
+   *
+   * In 1d, the default value of the boundary quadrature formula is an invalid
+   * object since integration on the boundary doesn't happen in 1d.
+   *
+   * @param[in] mapping The mapping object to use.
+   * @param[in] dof The DoFHandler the describes the finite element space to
+   * project into and that corresponds to @p vec.
+   * @param[in] constraints Constraints to be used when assembling the mass
+   * matrix, typically needed when you have hanging nodes.
+   * @param[in] quadrature The quadrature formula to be used for assembling the
+   * mass matrix.
+   * @param[in] function The function to project into the finite element space.
+   * @param[out] vec The output vector where the projected function will be
+   * stored in. This vector is required to be already initialized and must not
+   * have ghost elements.
+   * @param[in] enforce_zero_boundary If true, @p vec will have zero boundary
+   * conditions.
+   * @param[in] q_boundary Quadrature rule to be used if @p project_to_boundary_first
+   * is true.
+   * @param[in] project_to_boundary_first If true, perform a projection on the
+   * boundary before projecting the interior of the function.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  project(const Mapping<dim, spacedim> &                            mapping,
+          const DoFHandler<dim, spacedim> &                         dof,
+          const AffineConstraints<typename VectorType::value_type> &constraints,
+          const Quadrature<dim> &                                   quadrature,
+          const Function<spacedim, typename VectorType::value_type> &function,
+          VectorType &                                               vec,
+          const bool                 enforce_zero_boundary     = false,
+          const Quadrature<dim - 1> &q_boundary                = (dim > 1 ?
+                                                     QGauss<dim - 1>(2) :
+                                                     Quadrature<dim - 1>(0)),
+          const bool                 project_to_boundary_first = false);
+
+  /**
+   * Call the project() function above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  project(const DoFHandler<dim, spacedim> &                         dof,
+          const AffineConstraints<typename VectorType::value_type> &constraints,
+          const Quadrature<dim> &                                   quadrature,
+          const Function<spacedim, typename VectorType::value_type> &function,
+          VectorType &                                               vec,
+          const bool                 enforce_zero_boundary     = false,
+          const Quadrature<dim - 1> &q_boundary                = (dim > 1 ?
+                                                     QGauss<dim - 1>(2) :
+                                                     Quadrature<dim - 1>(0)),
+          const bool                 project_to_boundary_first = false);
+
+  /**
+   * Same as above, but for arguments of type hp::DoFHandler, hp::QCollection,
+   * and hp::MappingCollection.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  project(const hp::MappingCollection<dim, spacedim> &              mapping,
+          const hp::DoFHandler<dim, spacedim> &                     dof,
+          const AffineConstraints<typename VectorType::value_type> &constraints,
+          const hp::QCollection<dim> &                              quadrature,
+          const Function<spacedim, typename VectorType::value_type> &function,
+          VectorType &                                               vec,
+          const bool                      enforce_zero_boundary = false,
+          const hp::QCollection<dim - 1> &q_boundary = hp::QCollection<dim - 1>(
+            dim > 1 ? QGauss<dim - 1>(2) : Quadrature<dim - 1>(0)),
+          const bool project_to_boundary_first = false);
+
+  /**
+   * Call the project() function above, with a collection of $Q_1$ mapping
+   * objects, i.e., with hp::StaticMappingQ1::mapping_collection.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  project(const hp::DoFHandler<dim, spacedim> &                     dof,
+          const AffineConstraints<typename VectorType::value_type> &constraints,
+          const hp::QCollection<dim> &                              quadrature,
+          const Function<spacedim, typename VectorType::value_type> &function,
+          VectorType &                                               vec,
+          const bool                      enforce_zero_boundary = false,
+          const hp::QCollection<dim - 1> &q_boundary = hp::QCollection<dim - 1>(
+            dim > 1 ? QGauss<dim - 1>(2) : Quadrature<dim - 1>(0)),
+          const bool project_to_boundary_first = false);
+
+  /**
+   * The same as above for projection of scalar-valued quadrature data.
+   * The user provided function should return a value at the quadrature point
+   * based on the cell iterator and quadrature number and of course should be
+   * consistent with the provided @p quadrature object, which will be used
+   * to assemble the right-hand-side.
+   *
+   * This function can be used with lambdas:
+   * @code
+   * VectorTools::project
+   * (mapping,
+   *  dof_handler,
+   *  constraints,
+   *  quadrature_formula,
+   *  [&] (const typename DoFHandler<dim>::active_cell_iterator & cell,
+   *       const unsigned int q) -> double
+   *  {
+   *    return qp_data.get_data(cell)[q]->density;
+   *  },
+   *  field);
+   * @endcode
+   * where <code>qp_data</code> is a CellDataStorage object, which stores
+   * quadrature point data.
+   */
+  template <int dim, typename VectorType, int spacedim>
+  void
+  project(const Mapping<dim, spacedim> &                            mapping,
+          const DoFHandler<dim, spacedim> &                         dof,
+          const AffineConstraints<typename VectorType::value_type> &constraints,
+          const Quadrature<dim> &                                   quadrature,
+          const std::function<typename VectorType::value_type(
+            const typename DoFHandler<dim, spacedim>::active_cell_iterator &,
+            const unsigned int)> &                                  func,
+          VectorType &                                              vec_result);
+
+  /**
+   * The same as above for projection of scalar-valued MatrixFree quadrature
+   * data.
+   * The user provided function @p func should return a VectorizedArray value
+   * at the quadrature point based on the cell number and quadrature number and
+   * should be consistent with the @p n_q_points_1d.
+   *
+   * This function can be used with lambdas:
+   * @code
+   * VectorTools::project
+   * (matrix_free_data,
+   *  constraints,
+   *  3,
+   *  [&] (const unsigned int cell,
+   *       const unsigned int q) -> VectorizedArray<double>
+   *  {
+   *    return qp_data(cell,q);
+   *  },
+   *  field);
+   * @endcode
+   * where <code>qp_data</code> is a an object of type Table<2,
+   * VectorizedArray<double> >, which stores quadrature point data.
+   *
+   * @p fe_component allow to additionally specify which component of @p data
+   * to use in case it was constructed with an <code>std::vector<const
+   * DoFHandler<dim>*></code>. It will be used internally in constructor of
+   * FEEvaluation object.
+   */
+  template <int dim, typename VectorType>
+  void
+  project(
+    std::shared_ptr<
+      const MatrixFree<dim,
+                       typename VectorType::value_type,
+                       VectorizedArray<typename VectorType::value_type>>> data,
+    const AffineConstraints<typename VectorType::value_type> &constraints,
+    const unsigned int                                        n_q_points_1d,
+    const std::function<VectorizedArray<typename VectorType::value_type>(
+      const unsigned int,
+      const unsigned int)> &                                  func,
+    VectorType &                                              vec_result,
+    const unsigned int                                        fe_component = 0);
+
+  /**
+   * Same as above but for <code>n_q_points_1d =
+   * matrix_free.get_dof_handler().get_fe().degree+1</code>.
+   */
+  template <int dim, typename VectorType>
+  void
+  project(
+    std::shared_ptr<
+      const MatrixFree<dim,
+                       typename VectorType::value_type,
+                       VectorizedArray<typename VectorType::value_type>>> data,
+    const AffineConstraints<typename VectorType::value_type> &constraints,
+    const std::function<VectorizedArray<typename VectorType::value_type>(
+      const unsigned int,
+      const unsigned int)> &                                  func,
+    VectorType &                                              vec_result,
+    const unsigned int                                        fe_component = 0);
+
+  // @}
+
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_project_h
index b401e8019ba47e9b4aa2c7723dc776f2f6f7049d..408f3fcc4b4f1d70a129a0bec84503d5b2b46064 100644 (file)
@@ -33,7 +33,9 @@
 #include <deal.II/matrix_free/operators.h>
 
 #include <deal.II/numerics/matrix_tools.h>
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_boundary.h>
+#include <deal.II/numerics/vector_tools_project.h>
+#include <deal.II/numerics/vector_tools_rhs.h>
 
 DEAL_II_NAMESPACE_OPEN
 
diff --git a/include/deal.II/numerics/vector_tools_rhs.h b/include/deal.II/numerics/vector_tools_rhs.h
new file mode 100644 (file)
index 0000000..48f2a9d
--- /dev/null
@@ -0,0 +1,187 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 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.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_vector_tools_rhs_h
+#define dealii_vector_tools_rhs_h
+
+#include <deal.II/base/config.h>
+
+#include <set>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <typename number>
+class AffineConstraints;
+template <int dim, int spacedim>
+class DoFHandler;
+template <int dim, typename Number>
+class Function;
+template <int dim, int spacedim>
+class Mapping;
+template <int dim>
+class Quadrature;
+namespace hp
+{
+  template <int dim, int spacedim>
+  class DoFHandler;
+  template <int dim, int spacedim>
+  class MappingCollection;
+  template <int dim>
+  class QCollection;
+} // namespace hp
+
+
+namespace VectorTools
+{
+  /**
+   * @name Assembling of right hand sides
+   */
+  //@{
+
+  /**
+   * Create a right hand side vector. Prior content of the given @p rhs_vector
+   * vector is deleted.
+   *
+   * See the general documentation of this namespace for further information.
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_right_hand_side(
+    const Mapping<dim, spacedim> &                             mapping,
+    const DoFHandler<dim, spacedim> &                          dof,
+    const Quadrature<dim> &                                    q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const AffineConstraints<typename VectorType::value_type> & constraints =
+      AffineConstraints<typename VectorType::value_type>());
+
+  /**
+   * Call the create_right_hand_side() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_right_hand_side(
+    const DoFHandler<dim, spacedim> &                          dof,
+    const Quadrature<dim> &                                    q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const AffineConstraints<typename VectorType::value_type> & constraints =
+      AffineConstraints<typename VectorType::value_type>());
+
+  /**
+   * Like the previous set of functions, but for hp objects.
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_right_hand_side(
+    const hp::MappingCollection<dim, spacedim> &               mapping,
+    const hp::DoFHandler<dim, spacedim> &                      dof,
+    const hp::QCollection<dim> &                               q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const AffineConstraints<typename VectorType::value_type> & constraints =
+      AffineConstraints<typename VectorType::value_type>());
+
+  /**
+   * Like the previous set of functions, but for hp objects.
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_right_hand_side(
+    const hp::DoFHandler<dim, spacedim> &                      dof,
+    const hp::QCollection<dim> &                               q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const AffineConstraints<typename VectorType::value_type> & constraints =
+      AffineConstraints<typename VectorType::value_type>());
+
+  /**
+   * Create a right hand side vector from boundary forces. Prior content of
+   * the given @p rhs_vector vector is deleted.
+   *
+   * See the general documentation of this namespace for further information.
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_boundary_right_hand_side(
+    const Mapping<dim, spacedim> &                             mapping,
+    const DoFHandler<dim, spacedim> &                          dof,
+    const Quadrature<dim - 1> &                                q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const std::set<types::boundary_id> &                       boundary_ids =
+      std::set<types::boundary_id>());
+
+  /**
+   * Call the create_boundary_right_hand_side() function, see above, with
+   * <tt>mapping=MappingQGeneric@<dim@>(1)</tt>.
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_boundary_right_hand_side(
+    const DoFHandler<dim, spacedim> &                          dof,
+    const Quadrature<dim - 1> &                                q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const std::set<types::boundary_id> &                       boundary_ids =
+      std::set<types::boundary_id>());
+
+  /**
+   * Same as the set of functions above, but for hp objects.
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_boundary_right_hand_side(
+    const hp::MappingCollection<dim, spacedim> &               mapping,
+    const hp::DoFHandler<dim, spacedim> &                      dof,
+    const hp::QCollection<dim - 1> &                           q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const std::set<types::boundary_id> &                       boundary_ids =
+      std::set<types::boundary_id>());
+
+  /**
+   * Call the create_boundary_right_hand_side() function, see above, with a
+   * single Q1 mapping as collection. This function therefore will only work
+   * if the only active fe index in use is zero.
+   *
+   * @see
+   * @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
+   */
+  template <int dim, int spacedim, typename VectorType>
+  void
+  create_boundary_right_hand_side(
+    const hp::DoFHandler<dim, spacedim> &                      dof,
+    const hp::QCollection<dim - 1> &                           q,
+    const Function<spacedim, typename VectorType::value_type> &rhs,
+    VectorType &                                               rhs_vector,
+    const std::set<types::boundary_id> &                       boundary_ids =
+      std::set<types::boundary_id>());
+  // @}
+} // namespace VectorTools
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // dealii_vector_tools_rhs_h
index 1bef5a35cca4d7943861a400f7f0c8d0abe6d405..3b67981a8eb3a823c30023bd1388582a17dbc508 100644 (file)
@@ -28,7 +28,7 @@
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/numerics/vector_tools_rhs.h>
 
 
 DEAL_II_NAMESPACE_OPEN

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.