]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Split fe_values.h and fe_values.cc into three files each. 15829/head
authorDavid Wells <drwells@email.unc.edu>
Mon, 10 Jul 2023 19:03:56 +0000 (15:03 -0400)
committerDavid Wells <drwells@email.unc.edu>
Wed, 2 Aug 2023 21:49:23 +0000 (17:49 -0400)
In 367243a1614 (PR 15575) I removed SPLIT_INSTANTIATIONS_INDEX et al from
fe_values.cc. This was fine for -O2 but with -O3 -march=native this file now
takes several minutes to compile.

The majority of our compilation time here is in FEValuesViews - ultimately I'd
like to split that up. This commit performs one step towards splitting that up
by splitting up fe_values.h and corresponding source files into files for
FEValuesViews, FEValues, and FEValuesBase.

include/deal.II/fe/fe_values.h
include/deal.II/fe/fe_values_base.h [new file with mode: 0644]
include/deal.II/fe/fe_values_views.h [new file with mode: 0644]
source/fe/CMakeLists.txt
source/fe/fe_values.cc
source/fe/fe_values.inst.in
source/fe/fe_values_base.cc [new file with mode: 0644]
source/fe/fe_values_base.inst.in [new file with mode: 0644]
source/fe/fe_values_views.cc [new file with mode: 0644]
source/fe/fe_values_views.inst.in [new file with mode: 0644]

index 4e93cb514c3de7e08a6f873ea7bb6473810cdafe..60ebb50faac393d51bd6303708bcf6a4ff316fb1 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <deal.II/fe/fe.h>
 #include <deal.II/fe/fe_update_flags.h>
+#include <deal.II/fe/fe_values_base.h>
 #include <deal.II/fe/fe_values_extractors.h>
 #include <deal.II/fe/mapping.h>
 #include <deal.II/fe/mapping_related_data.h>
 #include <memory>
 #include <type_traits>
 
-
-// dummy include in order to have the
-// definition of PetscScalar available
-// without including other PETSc stuff
-#ifdef DEAL_II_WITH_PETSC
-#  include <petsc.h>
-#endif
-
 DEAL_II_NAMESPACE_OPEN
 
-// Forward declaration
-#ifndef DOXYGEN
+/**
+ * Finite element evaluated in quadrature points of a cell.
+ *
+ * This function implements the initialization routines for FEValuesBase, if
+ * values in quadrature points of a cell are needed. For further documentation
+ * see this class.
+ *
+ * @ingroup feaccess
+ */
 template <int dim, int spacedim = dim>
-class FEValuesBase;
-#endif
-
-namespace internal
+class FEValues : public FEValuesBase<dim, spacedim>
 {
+public:
   /**
-   * A class whose specialization is used to define what type the curl of a
-   * vector valued function corresponds to.
+   * Dimension of the object over which we integrate. For the present class,
+   * this is equal to <code>dim</code>.
    */
-  template <int dim, typename NumberType = double>
-  struct CurlType;
+  static constexpr unsigned int integral_dimension = dim;
 
   /**
-   * A class whose specialization is used to define what type the curl of a
-   * vector valued function corresponds to.
-   *
-   * In 1d, the curl is a scalar.
+   * Constructor. Gets cell independent data from mapping and finite element
+   * objects, matching the quadrature rule and update flags.
    */
-  template <typename NumberType>
-  struct CurlType<1, NumberType>
-  {
-    using type = Tensor<1, 1, NumberType>;
-  };
+  FEValues(const Mapping<dim, spacedim> &      mapping,
+           const FiniteElement<dim, spacedim> &fe,
+           const Quadrature<dim> &             quadrature,
+           const UpdateFlags                   update_flags);
 
   /**
-   * A class whose specialization is used to define what type the curl of a
-   * vector valued function corresponds to.
+   * Like the function above, but taking a collection of quadrature rules.
    *
-   * In 2d, the curl is a scalar.
+   * @note We require, in contrast to FEFaceValues, that the number of quadrature
+   *   rules in the collection is one.
    */
-  template <typename NumberType>
-  struct CurlType<2, NumberType>
-  {
-    using type = Tensor<1, 1, NumberType>;
-  };
+  FEValues(const Mapping<dim, spacedim> &      mapping,
+           const FiniteElement<dim, spacedim> &fe,
+           const hp::QCollection<dim> &        quadrature,
+           const UpdateFlags                   update_flags);
 
   /**
-   * A class whose specialization is used to define what type the curl of a
-   * vector valued function corresponds to.
-   *
-   * In 3d, the curl is a vector.
+   * Constructor. This constructor is equivalent to the other one except that
+   * it makes the object use a $Q_1$ mapping (i.e., an object of type
+   * MappingQ(1)) implicitly.
    */
-  template <typename NumberType>
-  struct CurlType<3, NumberType>
-  {
-    using type = Tensor<1, 3, NumberType>;
-  };
-} // namespace internal
-
-
+  FEValues(const FiniteElement<dim, spacedim> &fe,
+           const Quadrature<dim> &             quadrature,
+           const UpdateFlags                   update_flags);
 
-/**
- * A namespace for "views" on a FEValues, FEFaceValues, or FESubfaceValues
- * object. A view represents only a certain part of the whole: whereas the
- * FEValues object represents <i>all</i> values, gradients, or second
- * derivatives of all components of a vector-valued element, views restrict
- * the attention to only a single component or a subset of components. You
- * typically get objects of classes defined in this namespace by applying
- * FEValuesExtractors objects to a FEValues, FEFaceValues or FESubfaceValues
- * objects using the square bracket operator.
- *
- * There are classes that present views for single scalar components, vector
- * components consisting of <code>dim</code> elements, and symmetric second
- * order tensor components consisting of <code>(dim*dim + dim)/2</code>
- * elements
- *
- * See the description of the
- * @ref vector_valued
- * module for examples how to use the features of this namespace.
- *
- * @ingroup feaccess vector_valued
- */
-namespace FEValuesViews
-{
   /**
-   * A class representing a view to a single scalar component of a possibly
-   * vector-valued finite element. Views are discussed in the
-   * @ref vector_valued
-   * module.
-   *
-   * You get an object of this type if you apply a FEValuesExtractors::Scalar
-   * to an FEValues, FEFaceValues or FESubfaceValues object.
+   * Like the function above, but taking a collection of quadrature rules.
    *
-   * @ingroup feaccess vector_valued
+   * @note We require, in contrast to FEFaceValues, that the number of quadrature
+   *   rules in the collection is one.
    */
-  template <int dim, int spacedim = dim>
-  class Scalar
-  {
-  public:
-    /**
-     * An alias for the data type of values of the view this class
-     * represents. Since we deal with a single components, the value type is a
-     * scalar double.
-     */
-    using value_type = double;
-
-    /**
-     * An alias for the type of gradients of the view this class represents.
-     * Here, for a scalar component of the finite element, the gradient is a
-     * <code>Tensor@<1,dim@></code>.
-     */
-    using gradient_type = dealii::Tensor<1, spacedim>;
-
-    /**
-     * An alias for the type of second derivatives of the view this class
-     * represents. Here, for a scalar component of the finite element, the
-     * Hessian is a <code>Tensor@<2,dim@></code>.
-     */
-    using hessian_type = dealii::Tensor<2, spacedim>;
-
-    /**
-     * An alias for the type of third derivatives of the view this class
-     * represents. Here, for a scalar component of the finite element, the
-     * Third derivative is a <code>Tensor@<3,dim@></code>.
-     */
-    using third_derivative_type = dealii::Tensor<3, spacedim>;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * values of the view this class provides. This is the data type of
-     * scalar components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_value_type = typename ProductType<Number, value_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * gradients of the view this class provides. This is the data type of
-     * scalar components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_gradient_type =
-      typename ProductType<Number, gradient_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * laplacians of the view this class provides. This is the data type of
-     * scalar components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_laplacian_type =
-      typename ProductType<Number, value_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * hessians of the view this class provides. This is the data type of
-     * scalar components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_hessian_type =
-      typename ProductType<Number, hessian_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * third derivatives of the view this class provides. This is the data type
-     * of scalar components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_third_derivative_type =
-      typename ProductType<Number, third_derivative_type>::type;
-
-    /**
-     * A structure where for each shape function we pre-compute a bunch of
-     * data that will make later accesses much cheaper.
-     */
-    struct ShapeFunctionData
-    {
-      /**
-       * For each shape function, store whether the selected vector component
-       * may be nonzero. For primitive shape functions we know for sure
-       * whether a certain scalar component of a given shape function is
-       * nonzero, whereas for non-primitive shape functions this may not be
-       * entirely clear (e.g. for RT elements it depends on the shape of a
-       * cell).
-       */
-      bool is_nonzero_shape_function_component;
-
-      /**
-       * For each shape function, store the row index within the shape_values,
-       * shape_gradients, and shape_hessians tables (the column index is the
-       * quadrature point index). If the shape function is primitive, then we
-       * can get this information from the shape_function_to_row_table of the
-       * FEValues object; otherwise, we have to work a bit harder to compute
-       * this information.
-       */
-      unsigned int row_index;
-    };
-
-    /**
-     * Default constructor. Creates an invalid object.
-     */
-    Scalar();
-
-    /**
-     * Constructor for an object that represents a single scalar component of
-     * a FEValuesBase object (or of one of the classes derived from
-     * FEValuesBase).
-     */
-    Scalar(const FEValuesBase<dim, spacedim> &fe_values_base,
-           const unsigned int                 component);
-
-    /**
-     * Copy constructor. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    Scalar(const Scalar<dim, spacedim> &) = delete;
-
-    /**
-     * Move constructor.
-     */
-    // NOLINTNEXTLINE OSX does not compile with noexcept
-    Scalar(Scalar<dim, spacedim> &&) = default;
-
-    /**
-     * Destructor.
-     */
-    ~Scalar() = default;
-
-    /**
-     * Copy operator. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    Scalar &
-    operator=(const Scalar<dim, spacedim> &) = delete;
-
-    /**
-     * Move assignment operator.
-     */
-    Scalar &
-    operator=(Scalar<dim, spacedim> &&) noexcept = default;
-
-    /**
-     * Return the value of the vector component selected by this view, for the
-     * shape function and quadrature point selected by the arguments.
-     *
-     * @param shape_function Number of the shape function to be evaluated.
-     * Note that this number runs from zero to dofs_per_cell, even in the case
-     * of an FEFaceValues or FESubfaceValues object.
-     *
-     * @param q_point Number of the quadrature point at which function is to
-     * be evaluated.
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    value_type
-    value(const unsigned int shape_function, const unsigned int q_point) const;
-
-    /**
-     * Return the gradient (a tensor of rank 1) of the vector component
-     * selected by this view, for the shape function and quadrature point
-     * selected by the arguments.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    gradient_type
-    gradient(const unsigned int shape_function,
-             const unsigned int q_point) const;
-
-    /**
-     * Return the Hessian (the tensor of rank 2 of all second derivatives) of
-     * the vector component selected by this view, for the shape function and
-     * quadrature point selected by the arguments.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_hessians}
-     */
-    hessian_type
-    hessian(const unsigned int shape_function,
-            const unsigned int q_point) const;
-
-    /**
-     * Return the tensor of rank 3 of all third derivatives of the vector
-     * component selected by this view, for the shape function and quadrature
-     * point selected by the arguments.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_third_derivatives}
-     */
-    third_derivative_type
-    third_derivative(const unsigned int shape_function,
-                     const unsigned int q_point) const;
-
-    /**
-     * Return the values of the selected scalar component of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_values function but it only works on the
-     * selected scalar component.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the values of shape functions (i.e., @p value_type) times the
-     * type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    template <typename Number>
-    void
-    get_function_values(const ReadVector<Number> &                fe_function,
-                        std::vector<solution_value_type<Number>> &values) const;
-
-    /**
-     * Same as above, but using a vector of local degree-of-freedom values. In
-     * other words, instead of extracting the nodal values of the degrees of
-     * freedom located on the current cell from a global vector associated with
-     * a DoFHandler object (as the function above does), this function instead
-     * takes these local nodal values through its first argument. A typical
-     * way to obtain such a vector is by calling code such as
-     * @code
-     *   cell->get_dof_values (dof_values, local_dof_values);
-     * @endcode
-     * (See DoFCellAccessor::get_dof_values() for more information on this
-     * function.) The point of the current function is then that one could
-     * modify these local values first, for example by applying a limiter
-     * or by ensuring that all nodal values are positive, before evaluating
-     * the finite element field that corresponds to these local values on the
-     * current cell. Another application is where one wants to postprocess
-     * the solution on a cell into a different finite element space on every
-     * cell, without actually creating a corresponding DoFHandler -- in that
-     * case, all one would compute is a local representation of that
-     * postprocessed function, characterized by its nodal values; this function
-     * then allows the evaluation of that representation at quadrature points.
-     *
-     * @param[in] dof_values A vector of local nodal values. This vector must
-     *   have a length equal to number of DoFs on the current cell, and must
-     *   be ordered in the same order as degrees of freedom are numbered on
-     *   the reference cell.
-     *
-     * @param[out] values A vector of values of the given finite element field,
-     *   at the quadrature points on the current object.
-     *
-     * @tparam InputVector The @p InputVector type must allow creation
-     *   of an ArrayView object from it; this is satisfied by the
-     *   `std::vector` class, among others.
-     */
-    template <class InputVector>
-    void
-    get_function_values_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_value_type<typename InputVector::value_type>>
-        &values) const;
-
-    /**
-     * Return the gradients of the selected scalar component of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_gradients function but it only works on the
-     * selected scalar component.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the gradients of shape functions (i.e., @p gradient_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_gradients(
-      const ReadVector<Number> &                   fe_function,
-      std::vector<solution_gradient_type<Number>> &gradients) const;
-
-    /**
-     * This function relates to get_function_gradients() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_gradients_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_gradient_type<typename InputVector::value_type>>
-        &gradients) const;
-
-    /**
-     * Return the Hessians of the selected scalar component of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_hessians function but it only works on the
-     * selected scalar component.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the Hessians of shape functions (i.e., @p hessian_type) times
-     * the type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_hessians}
-     */
-    template <typename Number>
-    void
-    get_function_hessians(
-      const ReadVector<Number> &                  fe_function,
-      std::vector<solution_hessian_type<Number>> &hessians) const;
-
-    /**
-     * This function relates to get_function_hessians() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_hessians_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_hessian_type<typename InputVector::value_type>>
-        &hessians) const;
+  FEValues(const FiniteElement<dim, spacedim> &fe,
+           const hp::QCollection<dim> &        quadrature,
+           const UpdateFlags                   update_flags);
 
+  /**
+   * Reinitialize the gradients, Jacobi determinants, etc for the given cell
+   * of type "iterator into a DoFHandler object", and the finite element
+   * associated with this object. It is assumed that the finite element used
+   * by the given cell is also the one used by this FEValues object.
+   */
+  template <bool level_dof_access>
+  void
+  reinit(
+    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell);
 
-    /**
-     * Return the Laplacians of the selected scalar component of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called. The
-     * Laplacians are the trace of the Hessians.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_laplacians function but it only works on the
-     * selected scalar component.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the Laplacians of shape functions (i.e., @p value_type) times
-     * the type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_hessians}
-     */
-    template <typename Number>
-    void
-    get_function_laplacians(
-      const ReadVector<Number> &                    fe_function,
-      std::vector<solution_laplacian_type<Number>> &laplacians) const;
+  /**
+   * Reinitialize the gradients, Jacobi determinants, etc for the given cell
+   * of type "iterator into a Triangulation object", and the given finite
+   * element. Since iterators into triangulation alone only convey information
+   * about the geometry of a cell, but not about degrees of freedom possibly
+   * associated with this cell, you will not be able to call some functions of
+   * this class if they need information about degrees of freedom. These
+   * functions are, above all, the
+   * <tt>get_function_value/gradients/hessians/laplacians/third_derivatives</tt>
+   * functions. If you want to call these functions, you have to call the @p
+   * reinit variants that take iterators into DoFHandler or other DoF handler
+   * type objects.
+   */
+  void
+  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell);
 
-    /**
-     * This function relates to get_function_laplacians() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_laplacians_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_laplacian_type<typename InputVector::value_type>>
-        &laplacians) const;
+  /**
+   * Return a reference to the copy of the quadrature formula stored by this
+   * object.
+   */
+  const Quadrature<dim> &
+  get_quadrature() const;
 
+  /**
+   * Determine an estimate for the memory consumption (in bytes) of this
+   * object.
+   */
+  std::size_t
+  memory_consumption() const;
 
-    /**
-     * Return the third derivatives of the selected scalar component of the
-     * finite element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_third_derivatives function but it only works
-     * on the selected scalar component.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the third derivatives of shape functions (i.e., @p
-     * third_derivative_type) times the type used to store the values of the
-     * unknowns $U_j$ of your finite element vector $U$ (represented by the @p
-     * fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_third_derivatives}
-     */
-    template <typename Number>
-    void
-    get_function_third_derivatives(
-      const ReadVector<Number> &                           fe_function,
-      std::vector<solution_third_derivative_type<Number>> &third_derivatives)
-      const;
+  /**
+   * Return a reference to this very object.
+   *
+   * Though it seems that it is not very useful, this function is there to
+   * provide capability to the hp::FEValues class, in which case it provides
+   * the FEValues object for the present cell (remember that for hp-finite
+   * elements, the actual FE object used may change from cell to cell, so we
+   * also need different FEValues objects for different cells; once you
+   * reinitialize the hp::FEValues object for a specific cell, it retrieves
+   * the FEValues object for the FE on that cell and returns it through a
+   * function of the same name as this one; this function here therefore only
+   * provides the same interface so that one can templatize on FEValues and
+   * hp::FEValues).
+   */
+  const FEValues<dim, spacedim> &
+  get_present_fe_values() const;
 
-    /**
-     * This function relates to get_function_third_derivatives() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_third_derivatives_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<
-        solution_third_derivative_type<typename InputVector::value_type>>
-        &third_derivatives) const;
+private:
+  /**
+   * Store a copy of the quadrature formula here.
+   */
+  const Quadrature<dim> quadrature;
 
+  /**
+   * Do work common to the two constructors.
+   */
+  void
+  initialize(const UpdateFlags update_flags);
 
-  private:
-    /**
-     * A pointer to the FEValuesBase object we operate on.
-     */
-    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
+  /**
+   * The reinit() functions do only that part of the work that requires
+   * knowledge of the type of iterator. After setting present_cell(), they
+   * pass on to this function, which does the real work, and which is
+   * independent of the actual type of the cell iterator.
+   */
+  void
+  do_reinit();
+};
 
-    /**
-     * The single scalar component this view represents of the FEValuesBase
-     * object.
-     */
-    const unsigned int component;
 
-    /**
-     * Store the data about shape functions.
-     */
-    std::vector<ShapeFunctionData> shape_function_data;
-  };
+/**
+ * Extend the interface of FEValuesBase to values that only make sense when
+ * evaluating something on the surface of a cell. All the data that is
+ * available in the interior of cells is also available here.
+ *
+ * See FEValuesBase
+ *
+ * @ingroup feaccess
+ */
+template <int dim, int spacedim = dim>
+class FEFaceValuesBase : public FEValuesBase<dim, spacedim>
+{
+public:
+  /**
+   * Dimension of the object over which we integrate. For the present class,
+   * this is equal to <code>dim-1</code>.
+   */
+  static constexpr unsigned int integral_dimension = dim - 1;
 
+  /**
+   * Constructor. Call the constructor of the base class and set up the arrays
+   * of this class with the right sizes.  Actually filling these arrays is a
+   * duty of the derived class's constructors.
+   *
+   * @p n_faces_or_subfaces is the number of faces or subfaces that this
+   * object is to store. The actual number depends on the derived class, for
+   * FEFaceValues it is <tt>2*dim</tt>, while for the FESubfaceValues class it
+   * is <tt>2*dim*(1<<(dim-1))</tt>, i.e. the number of faces times the number
+   * of subfaces per face.
+   */
+  FEFaceValuesBase(const unsigned int                  dofs_per_cell,
+                   const UpdateFlags                   update_flags,
+                   const Mapping<dim, spacedim> &      mapping,
+                   const FiniteElement<dim, spacedim> &fe,
+                   const Quadrature<dim - 1> &         quadrature);
 
+  /**
+   * Like the function above, but taking a collection of quadrature rules. This
+   * allows to assign each face a different quadrature rule. In the case that
+   * the collection only contains a single face quadrature, this quadrature
+   * rule is use on all faces.
+   */
+  FEFaceValuesBase(const unsigned int                  dofs_per_cell,
+                   const UpdateFlags                   update_flags,
+                   const Mapping<dim, spacedim> &      mapping,
+                   const FiniteElement<dim, spacedim> &fe,
+                   const hp::QCollection<dim - 1> &    quadrature);
 
   /**
-   * A class representing a view to a set of <code>spacedim</code> components
-   * forming a vector part of a vector-valued finite element. Views are
-   * discussed in the
-   * @ref vector_valued
-   * module.
-   *
-   * Note that in the current context, a vector is meant in the sense physics
-   * uses it: it has <code>spacedim</code> components that behave in specific
-   * ways under coordinate system transformations. Examples include velocity
-   * or displacement fields. This is opposed to how mathematics uses the word
-   * "vector" (and how we use this word in other contexts in the library, for
-   * example in the Vector class), where it really stands for a collection of
-   * numbers. An example of this latter use of the word could be the set of
-   * concentrations of chemical species in a flame; however, these are really
-   * just a collection of scalar variables, since they do not change if the
-   * coordinate system is rotated, unlike the components of a velocity vector,
-   * and consequently, this class should not be used for this context.
-   *
-   * This class allows to query the value, gradient and divergence of
-   * (components of) shape functions and solutions representing vectors. The
-   * gradient of a vector $d_{k}, 0\le k<\text{dim}$ is defined as $S_{ij} =
-   * \frac{\partial d_{i}}{\partial x_j}, 0\le i,j<\text{dim}$.
+   * Boundary form of the transformation of the cell at the <tt>q_point</tt>th
+   * quadrature point.  See
+   * @ref GlossBoundaryForm.
    *
-   * You get an object of this type if you apply a FEValuesExtractors::Vector
-   * to an FEValues, FEFaceValues or FESubfaceValues object.
+   * @dealiiRequiresUpdateFlags{update_boundary_forms}
+   */
+  const Tensor<1, spacedim> &
+  boundary_form(const unsigned int q_point) const;
+
+  /**
+   * Return the list of outward normal vectors times the Jacobian of the
+   * surface mapping.
    *
-   * @ingroup feaccess vector_valued
+   * @dealiiRequiresUpdateFlags{update_boundary_forms}
    */
-  template <int dim, int spacedim = dim>
-  class Vector
-  {
-  public:
-    /**
-     * An alias for the data type of values of the view this class
-     * represents. Since we deal with a set of <code>dim</code> components,
-     * the value type is a Tensor<1,spacedim>.
-     */
-    using value_type = dealii::Tensor<1, spacedim>;
+  const std::vector<Tensor<1, spacedim>> &
+  get_boundary_forms() const;
 
-    /**
-     * An alias for the type of gradients of the view this class represents.
-     * Here, for a set of <code>dim</code> components of the finite element,
-     * the gradient is a <code>Tensor@<2,spacedim@></code>.
-     *
-     * See the general documentation of this class for how exactly the
-     * gradient of a vector is defined.
-     */
-    using gradient_type = dealii::Tensor<2, spacedim>;
+  /**
+   * Return the number of the face selected the last time the reinit() function
+   * was called.
+   */
+  unsigned int
+  get_face_number() const;
 
-    /**
-     * An alias for the type of symmetrized gradients of the view this class
-     * represents. Here, for a set of <code>dim</code> components of the
-     * finite element, the symmetrized gradient is a
-     * <code>SymmetricTensor@<2,spacedim@></code>.
-     *
-     * The symmetric gradient of a vector field $\mathbf v$ is defined as
-     * $\varepsilon(\mathbf v)=\frac 12 (\nabla \mathbf v + \nabla \mathbf
-     * v^T)$.
-     */
-    using symmetric_gradient_type = dealii::SymmetricTensor<2, spacedim>;
+  /**
+   * Return the index of the face selected the last time the reinit() function
+   * was called.
+   */
+  unsigned int
+  get_face_index() const;
 
-    /**
-     * An alias for the type of the divergence of the view this class
-     * represents. Here, for a set of <code>dim</code> components of the
-     * finite element, the divergence of course is a scalar.
-     */
-    using divergence_type = double;
+  /**
+   * Return a reference to the copy of the quadrature formula stored by this
+   * object.
+   */
+  const Quadrature<dim - 1> &
+  get_quadrature() const;
 
-    /**
-     * An alias for the type of the curl of the view this class represents.
-     * Here, for a set of <code>spacedim=2</code> components of the finite
-     * element, the curl is a <code>Tensor@<1, 1@></code>. For
-     * <code>spacedim=3</code> it is a <code>Tensor@<1, dim@></code>.
-     */
-    using curl_type = typename dealii::internal::CurlType<spacedim>::type;
+  /**
+   * Determine an estimate for the memory consumption (in bytes) of this
+   * object.
+   */
+  std::size_t
+  memory_consumption() const;
 
-    /**
-     * An alias for the type of second derivatives of the view this class
-     * represents. Here, for a set of <code>dim</code> components of the
-     * finite element, the Hessian is a <code>Tensor@<3,dim@></code>.
-     */
-    using hessian_type = dealii::Tensor<3, spacedim>;
+protected:
+  /**
+   * Number of the face selected the last time the reinit() function was
+   * called.
+   */
+  unsigned int present_face_no;
 
-    /**
-     * An alias for the type of third derivatives of the view this class
-     * represents. Here, for a set of <code>dim</code> components of the
-     * finite element, the third derivative is a <code>Tensor@<4,dim@></code>.
-     */
-    using third_derivative_type = dealii::Tensor<4, spacedim>;
+  /**
+   * Index of the face selected the last time the reinit() function was
+   * called.
+   */
+  unsigned int present_face_index;
 
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * values of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_value_type = typename ProductType<Number, value_type>::type;
+  /**
+   * Store a copy of the quadrature formula here.
+   */
+  const hp::QCollection<dim - 1> quadrature;
+};
 
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * gradients of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_gradient_type =
-      typename ProductType<Number, gradient_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * symmetric gradients of the view this class provides. This is the data
-     * type of vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_symmetric_gradient_type =
-      typename ProductType<Number, symmetric_gradient_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * divergences of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_divergence_type =
-      typename ProductType<Number, divergence_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * laplacians of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_laplacian_type =
-      typename ProductType<Number, value_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * curls of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_curl_type = typename ProductType<Number, curl_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * hessians of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_hessian_type =
-      typename ProductType<Number, hessian_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * third derivatives of the view this class provides. This is the data type
-     * of vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_third_derivative_type =
-      typename ProductType<Number, third_derivative_type>::type;
-
-    /**
-     * A structure where for each shape function we pre-compute a bunch of
-     * data that will make later accesses much cheaper.
-     */
-    struct ShapeFunctionData
-    {
-      /**
-       * For each pair (shape function,component within vector), store whether
-       * the selected vector component may be nonzero. For primitive shape
-       * functions we know for sure whether a certain scalar component of a
-       * given shape function is nonzero, whereas for non-primitive shape
-       * functions this may not be entirely clear (e.g. for RT elements it
-       * depends on the shape of a cell).
-       */
-      bool is_nonzero_shape_function_component[spacedim];
-
-      /**
-       * For each pair (shape function, component within vector), store the
-       * row index within the shape_values, shape_gradients, and
-       * shape_hessians tables (the column index is the quadrature point
-       * index). If the shape function is primitive, then we can get this
-       * information from the shape_function_to_row_table of the FEValues
-       * object; otherwise, we have to work a bit harder to compute this
-       * information.
-       */
-      unsigned int row_index[spacedim];
-
-      /**
-       * For each shape function say the following: if only a single entry in
-       * is_nonzero_shape_function_component for this shape function is
-       * nonzero, then store the corresponding value of row_index and
-       * single_nonzero_component_index represents the index between 0 and dim
-       * for which it is attained. If multiple components are nonzero, then
-       * store -1. If no components are nonzero then store -2.
-       */
-      int          single_nonzero_component;
-      unsigned int single_nonzero_component_index;
-    };
-
-    /**
-     * Default constructor. Creates an invalid object.
-     */
-    Vector();
-
-    /**
-     * Constructor for an object that represents dim components of a
-     * FEValuesBase object (or of one of the classes derived from
-     * FEValuesBase), representing a vector-valued variable.
-     *
-     * The second argument denotes the index of the first component of the
-     * selected vector.
-     */
-    Vector(const FEValuesBase<dim, spacedim> &fe_values_base,
-           const unsigned int                 first_vector_component);
-
-    /**
-     * Copy constructor. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    Vector(const Vector<dim, spacedim> &) = delete;
-
-    /**
-     * Move constructor.
-     */
-    // NOLINTNEXTLINE OSX does not compile with noexcept
-    Vector(Vector<dim, spacedim> &&) = default;
-
-    /**
-     * Destructor.
-     */
-    ~Vector() = default;
-
-    /**
-     * Copy operator. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    Vector &
-    operator=(const Vector<dim, spacedim> &) = delete;
-
-    /**
-     * Move assignment operator.
-     */
-    // NOLINTNEXTLINE OSX does not compile with noexcept
-    Vector &
-    operator=(Vector<dim, spacedim> &&) = default; // NOLINT
-
-    /**
-     * Return the value of the vector components selected by this view, for
-     * the shape function and quadrature point selected by the arguments.
-     * Here, since the view represents a vector-valued part of the FEValues
-     * object with <code>dim</code> components, the return type is a tensor of
-     * rank 1 with <code>dim</code> components.
-     *
-     * @param shape_function Number of the shape function to be evaluated.
-     * Note that this number runs from zero to dofs_per_cell, even in the case
-     * of an FEFaceValues or FESubfaceValues object.
-     *
-     * @param q_point Number of the quadrature point at which function is to
-     * be evaluated.
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    value_type
-    value(const unsigned int shape_function, const unsigned int q_point) const;
-
-    /**
-     * Return the gradient (a tensor of rank 2) of the vector component
-     * selected by this view, for the shape function and quadrature point
-     * selected by the arguments.
-     *
-     * See the general documentation of this class for how exactly the
-     * gradient of a vector is defined.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    gradient_type
-    gradient(const unsigned int shape_function,
-             const unsigned int q_point) const;
-
-    /**
-     * Return the symmetric gradient (a symmetric tensor of rank 2) of the
-     * vector component selected by this view, for the shape function and
-     * quadrature point selected by the arguments.
-     *
-     * The symmetric gradient is defined as $\frac 12 [(\nabla \phi_i(x_q)) +
-     * (\nabla \phi_i(x_q))^T]$, where $\phi_i$ represents the
-     * <code>dim</code> components selected from the FEValuesBase object, and
-     * $x_q$ is the location of the $q$-th quadrature point.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    symmetric_gradient_type
-    symmetric_gradient(const unsigned int shape_function,
-                       const unsigned int q_point) const;
-
-    /**
-     * Return the scalar divergence of the vector components selected by this
-     * view, for the shape function and quadrature point selected by the
-     * arguments.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    divergence_type
-    divergence(const unsigned int shape_function,
-               const unsigned int q_point) const;
-
-    /**
-     * Return the vector curl of the vector components selected by this view,
-     * for the shape function and quadrature point selected by the arguments.
-     * For 1d this function does not make any sense. Thus it is not
-     * implemented for <code>spacedim=1</code>.  In 2d the curl is defined as
-     * @f{equation*}{
-     * \operatorname{curl}(u) \dealcoloneq \frac{du_2}{dx} -\frac{du_1}{dy},
-     * @f}
-     * whereas in 3d it is given by
-     * @f{equation*}{
-     * \operatorname{curl}(u) \dealcoloneq \left( \begin{array}{c}
-     * \frac{du_3}{dy}-\frac{du_2}{dz}\\ \frac{du_1}{dz}-\frac{du_3}{dx}\\
-     * \frac{du_2}{dx}-\frac{du_1}{dy} \end{array} \right).
-     * @f}
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    curl_type
-    curl(const unsigned int shape_function, const unsigned int q_point) const;
-
-    /**
-     * Return the Hessian (the tensor of rank 2 of all second derivatives) of
-     * the vector components selected by this view, for the shape function and
-     * quadrature point selected by the arguments.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_hessians}
-     */
-    hessian_type
-    hessian(const unsigned int shape_function,
-            const unsigned int q_point) const;
-
-    /**
-     * Return the tensor of rank 3 of all third derivatives of the vector
-     * components selected by this view, for the shape function and quadrature
-     * point selected by the arguments.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
-     */
-    third_derivative_type
-    third_derivative(const unsigned int shape_function,
-                     const unsigned int q_point) const;
-
-    /**
-     * Return the values of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_values function but it only works on the
-     * selected vector components.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the values of shape functions (i.e., @p value_type) times the
-     * type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    template <typename Number>
-    void
-    get_function_values(const ReadVector<Number> &                fe_function,
-                        std::vector<solution_value_type<Number>> &values) const;
-
-    /**
-     * Same as above, but using a vector of local degree-of-freedom values. In
-     * other words, instead of extracting the nodal values of the degrees of
-     * freedom located on the current cell from a global vector associated with
-     * a DoFHandler object (as the function above does), this function instead
-     * takes these local nodal values through its first argument. A typical
-     * way to obtain such a vector is by calling code such as
-     * @code
-     *   cell->get_dof_values (dof_values, local_dof_values);
-     * @endcode
-     * (See DoFCellAccessor::get_dof_values() for more information on this
-     * function.) The point of the current function is then that one could
-     * modify these local values first, for example by applying a limiter
-     * or by ensuring that all nodal values are positive, before evaluating
-     * the finite element field that corresponds to these local values on the
-     * current cell. Another application is where one wants to postprocess
-     * the solution on a cell into a different finite element space on every
-     * cell, without actually creating a corresponding DoFHandler -- in that
-     * case, all one would compute is a local representation of that
-     * postprocessed function, characterized by its nodal values; this function
-     * then allows the evaluation of that representation at quadrature points.
-     *
-     * @param[in] dof_values A vector of local nodal values. This vector must
-     *   have a length equal to number of DoFs on the current cell, and must
-     *   be ordered in the same order as degrees of freedom are numbered on
-     *   the reference cell.
-     *
-     * @param[out] values A vector of values of the given finite element field,
-     *   at the quadrature points on the current object.
-     *
-     * @tparam InputVector The @p InputVector type must allow creation
-     *   of an ArrayView object from it; this is satisfied by the
-     *   `std::vector` class, among others.
-     */
-    template <class InputVector>
-    void
-    get_function_values_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_value_type<typename InputVector::value_type>>
-        &values) const;
-
-    /**
-     * Return the gradients of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_gradients function but it only works on the
-     * selected vector components.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the gradients of shape functions (i.e., @p gradient_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_gradients(
-      const ReadVector<Number> &                   fe_function,
-      std::vector<solution_gradient_type<Number>> &gradients) const;
-
-    /**
-     * This function relates to get_function_gradients() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_gradients_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_gradient_type<typename InputVector::value_type>>
-        &gradients) const;
-
-    /**
-     * Return the symmetrized gradients of the selected vector components of
-     * the finite element function characterized by <tt>fe_function</tt> at
-     * the quadrature points of the cell, face or subface selected the last
-     * time the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * The symmetric gradient of a vector field $\mathbf v$ is defined as
-     * $\varepsilon(\mathbf v)=\frac 12 (\nabla \mathbf v + \nabla \mathbf
-     * v^T)$.
-     *
-     * @note There is no equivalent function such as
-     * FEValuesBase::get_function_symmetric_gradients in the FEValues classes
-     * but the information can be obtained from
-     * FEValuesBase::get_function_gradients, of course.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the symmetric gradients of shape functions (i.e., @p
-     * symmetric_gradient_type) times the type used to store the values of the
-     * unknowns $U_j$ of your finite element vector $U$ (represented by the @p
-     * fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_symmetric_gradients(
-      const ReadVector<Number> &fe_function,
-      std::vector<solution_symmetric_gradient_type<Number>>
-        &symmetric_gradients) const;
-
-    /**
-     * This function relates to get_function_symmetric_gradients() in the same
-     * way as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_symmetric_gradients_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<
-        solution_symmetric_gradient_type<typename InputVector::value_type>>
-        &symmetric_gradients) const;
-
-    /**
-     * Return the divergence of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * There is no equivalent function such as
-     * FEValuesBase::get_function_divergences in the FEValues classes but the
-     * information can be obtained from FEValuesBase::get_function_gradients,
-     * of course.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the divergences of shape functions (i.e., @p divergence_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_divergences(
-      const ReadVector<Number> &                     fe_function,
-      std::vector<solution_divergence_type<Number>> &divergences) const;
-
-    /**
-     * This function relates to get_function_divergences() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_divergences_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_divergence_type<typename InputVector::value_type>>
-        &divergences) const;
-
-    /**
-     * Return the curl of the selected vector components of the finite element
-     * function characterized by <tt>fe_function</tt> at the quadrature points
-     * of the cell, face or subface selected the last time the <tt>reinit</tt>
-     * function of the FEValues object was called.
-     *
-     * There is no equivalent function such as
-     * FEValuesBase::get_function_curls in the FEValues classes but the
-     * information can be obtained from FEValuesBase::get_function_gradients,
-     * of course.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the curls of shape functions (i.e., @p curl_type) times the
-     * type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_curls(const ReadVector<Number> &               fe_function,
-                       std::vector<solution_curl_type<Number>> &curls) const;
-
-    /**
-     * This function relates to get_function_curls() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_curls_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_curl_type<typename InputVector::value_type>> &curls)
-      const;
-
-    /**
-     * Return the Hessians of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_hessians function but it only works on the
-     * selected vector components.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the Hessians of shape functions (i.e., @p hessian_type) times
-     * the type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_hessians}
-     */
-    template <typename Number>
-    void
-    get_function_hessians(
-      const ReadVector<Number> &                  fe_function,
-      std::vector<solution_hessian_type<Number>> &hessians) const;
-
-    /**
-     * This function relates to get_function_hessians() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_hessians_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_hessian_type<typename InputVector::value_type>>
-        &hessians) const;
-
-    /**
-     * Return the Laplacians of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called. The
-     * Laplacians are the trace of the Hessians.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_laplacians function but it only works on the
-     * selected vector components.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the Laplacians of shape functions (i.e., @p laplacian_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_hessians}
-     */
-    template <typename Number>
-    void
-    get_function_laplacians(
-      const ReadVector<Number> &                    fe_function,
-      std::vector<solution_laplacian_type<Number>> &laplacians) const;
-
-    /**
-     * This function relates to get_function_laplacians() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_laplacians_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_laplacian_type<typename InputVector::value_type>>
-        &laplacians) const;
-
-    /**
-     * Return the third derivatives of the selected scalar component of the
-     * finite element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_third_derivatives function but it only works
-     * on the selected scalar component.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the third derivatives of shape functions (i.e., @p
-     * third_derivative_type) times the type used to store the values of the
-     * unknowns $U_j$ of your finite element vector $U$ (represented by the @p
-     * fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_third_derivatives}
-     */
-    template <typename Number>
-    void
-    get_function_third_derivatives(
-      const ReadVector<Number> &                           fe_function,
-      std::vector<solution_third_derivative_type<Number>> &third_derivatives)
-      const;
-
-    /**
-     * This function relates to get_function_third_derivatives() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_third_derivatives_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<
-        solution_third_derivative_type<typename InputVector::value_type>>
-        &third_derivatives) const;
-
-  private:
-    /**
-     * A pointer to the FEValuesBase object we operate on.
-     */
-    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
-
-    /**
-     * The first component of the vector this view represents of the
-     * FEValuesBase object.
-     */
-    const unsigned int first_vector_component;
-
-    /**
-     * Store the data about shape functions.
-     */
-    std::vector<ShapeFunctionData> shape_function_data;
-  };
-
-
-  template <int rank, int dim, int spacedim = dim>
-  class SymmetricTensor;
-
-  /**
-   * A class representing a view to a set of <code>(dim*dim + dim)/2</code>
-   * components forming a symmetric second-order tensor from a vector-valued
-   * finite element. Views are discussed in the
-   * @ref vector_valued
-   * module.
-   *
-   * This class allows to query the value and divergence of (components of)
-   * shape functions and solutions representing symmetric tensors. The
-   * divergence of a symmetric tensor $S_{ij}, 0\le i,j<\text{dim}$ is defined
-   * as $d_i = \sum_j \frac{\partial S_{ij}}{\partial x_j}, 0\le
-   * i<\text{dim}$, which due to the symmetry of the tensor is also $d_i =
-   * \sum_j \frac{\partial S_{ji}}{\partial x_j}$.  In other words, it due to
-   * the symmetry of $S$ it does not matter whether we apply the nabla
-   * operator by row or by column to get the divergence.
-   *
-   * You get an object of this type if you apply a
-   * FEValuesExtractors::SymmetricTensor to an FEValues, FEFaceValues or
-   * FESubfaceValues object.
-   *
-   * @ingroup feaccess vector_valued
-   */
-  template <int dim, int spacedim>
-  class SymmetricTensor<2, dim, spacedim>
-  {
-  public:
-    /**
-     * An alias for the data type of values of the view this class
-     * represents. Since we deal with a set of <code>(dim*dim + dim)/2</code>
-     * components (i.e. the unique components of a symmetric second-order
-     * tensor), the value type is a SymmetricTensor<2,spacedim>.
-     */
-    using value_type = dealii::SymmetricTensor<2, spacedim>;
-
-    /**
-     * An alias for the type of the divergence of the view this class
-     * represents. Here, for a set of <code>(dim*dim + dim)/2</code> unique
-     * components of the finite element representing a symmetric second-order
-     * tensor, the divergence of course is a * <code>Tensor@<1,dim@></code>.
-     *
-     * See the general discussion of this class for a definition of the
-     * divergence.
-     */
-    using divergence_type = dealii::Tensor<1, spacedim>;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * values of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_value_type = typename ProductType<Number, value_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * divergences of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_divergence_type =
-      typename ProductType<Number, divergence_type>::type;
-
-
-    /**
-     * A structure where for each shape function we pre-compute a bunch of
-     * data that will make later accesses much cheaper.
-     */
-    struct ShapeFunctionData
-    {
-      /**
-       * For each pair (shape function,component within vector), store whether
-       * the selected vector component may be nonzero. For primitive shape
-       * functions we know for sure whether a certain scalar component of a
-       * given shape function is nonzero, whereas for non-primitive shape
-       * functions this may not be entirely clear (e.g. for RT elements it
-       * depends on the shape of a cell).
-       */
-      bool is_nonzero_shape_function_component
-        [value_type::n_independent_components];
-
-      /**
-       * For each pair (shape function, component within vector), store the
-       * row index within the shape_values, shape_gradients, and
-       * shape_hessians tables (the column index is the quadrature point
-       * index). If the shape function is primitive, then we can get this
-       * information from the shape_function_to_row_table of the FEValues
-       * object; otherwise, we have to work a bit harder to compute this
-       * information.
-       */
-      unsigned int row_index[value_type::n_independent_components];
-
-      /**
-       * For each shape function say the following: if only a single entry in
-       * is_nonzero_shape_function_component for this shape function is
-       * nonzero, then store the corresponding value of row_index and
-       * single_nonzero_component_index represents the index between 0 and
-       * (dim^2 + dim)/2 for which it is attained. If multiple components are
-       * nonzero, then store -1. If no components are nonzero then store -2.
-       */
-      int single_nonzero_component;
-
-      /**
-       * Index of the @p single_nonzero_component .
-       */
-      unsigned int single_nonzero_component_index;
-    };
-
-    /**
-     * Default constructor. Creates an invalid object.
-     */
-    SymmetricTensor();
-
-    /**
-     * Constructor for an object that represents <code>(dim*dim +
-     * dim)/2</code> components of a FEValuesBase object (or of one of the
-     * classes derived from FEValuesBase), representing the unique components
-     * comprising a symmetric second- order tensor valued variable.
-     *
-     * The second argument denotes the index of the first component of the
-     * selected symmetric second order tensor.
-     */
-    SymmetricTensor(const FEValuesBase<dim, spacedim> &fe_values_base,
-                    const unsigned int                 first_tensor_component);
-
-    /**
-     * Copy constructor. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    SymmetricTensor(const SymmetricTensor<2, dim, spacedim> &) = delete;
-
-    /**
-     * Move constructor.
-     */
-    // NOLINTNEXTLINE OSX does not compile with noexcept
-    SymmetricTensor(SymmetricTensor<2, dim, spacedim> &&) = default;
-
-    /**
-     * Copy operator. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    SymmetricTensor &
-    operator=(const SymmetricTensor<2, dim, spacedim> &) = delete;
-
-    /**
-     * Move assignment operator.
-     */
-    SymmetricTensor &
-    operator=(SymmetricTensor<2, dim, spacedim> &&) noexcept = default;
-
-    /**
-     * Return the value of the vector components selected by this view, for
-     * the shape function and quadrature point selected by the arguments.
-     * Here, since the view represents a vector-valued part of the FEValues
-     * object with <code>(dim*dim + dim)/2</code> components (the unique
-     * components of a symmetric second-order tensor), the return type is a
-     * symmetric tensor of rank 2.
-     *
-     * @param shape_function Number of the shape function to be evaluated.
-     * Note that this number runs from zero to dofs_per_cell, even in the case
-     * of an FEFaceValues or FESubfaceValues object.
-     *
-     * @param q_point Number of the quadrature point at which function is to
-     * be evaluated.
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    value_type
-    value(const unsigned int shape_function, const unsigned int q_point) const;
-
-    /**
-     * Return the vector divergence of the vector components selected by this
-     * view, for the shape function and quadrature point selected by the
-     * arguments.
-     *
-     * See the general discussion of this class for a definition of the
-     * divergence.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    divergence_type
-    divergence(const unsigned int shape_function,
-               const unsigned int q_point) const;
-
-    /**
-     * Return the values of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_values function but it only works on the
-     * selected vector components.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the values of shape functions (i.e., @p value_type) times the
-     * type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    template <typename Number>
-    void
-    get_function_values(const ReadVector<Number> &                fe_function,
-                        std::vector<solution_value_type<Number>> &values) const;
-
-    /**
-     * Same as above, but using a vector of local degree-of-freedom values. In
-     * other words, instead of extracting the nodal values of the degrees of
-     * freedom located on the current cell from a global vector associated with
-     * a DoFHandler object (as the function above does), this function instead
-     * takes these local nodal values through its first argument. A typical
-     * way to obtain such a vector is by calling code such as
-     * @code
-     *   cell->get_dof_values (dof_values, local_dof_values);
-     * @endcode
-     * (See DoFCellAccessor::get_dof_values() for more information on this
-     * function.) The point of the current function is then that one could
-     * modify these local values first, for example by applying a limiter
-     * or by ensuring that all nodal values are positive, before evaluating
-     * the finite element field that corresponds to these local values on the
-     * current cell. Another application is where one wants to postprocess
-     * the solution on a cell into a different finite element space on every
-     * cell, without actually creating a corresponding DoFHandler -- in that
-     * case, all one would compute is a local representation of that
-     * postprocessed function, characterized by its nodal values; this function
-     * then allows the evaluation of that representation at quadrature points.
-     *
-     * @param[in] dof_values A vector of local nodal values. This vector must
-     *   have a length equal to number of DoFs on the current cell, and must
-     *   be ordered in the same order as degrees of freedom are numbered on
-     *   the reference cell.
-     *
-     * @param[out] values A vector of values of the given finite element field,
-     *   at the quadrature points on the current object.
-     *
-     * @tparam InputVector The @p InputVector type must allow creation
-     *   of an ArrayView object from it; this is satisfied by the
-     *   `std::vector` class, among others.
-     */
-    template <class InputVector>
-    void
-    get_function_values_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_value_type<typename InputVector::value_type>>
-        &values) const;
-
-    /**
-     * Return the divergence of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * There is no equivalent function such as
-     * FEValuesBase::get_function_divergences in the FEValues classes but the
-     * information can be obtained from FEValuesBase::get_function_gradients,
-     * of course.
-     *
-     * See the general discussion of this class for a definition of the
-     * divergence.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the divergences of shape functions (i.e., @p divergence_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_divergences(
-      const ReadVector<Number> &                     fe_function,
-      std::vector<solution_divergence_type<Number>> &divergences) const;
-
-    /**
-     * This function relates to get_function_divergences() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_divergences_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_divergence_type<typename InputVector::value_type>>
-        &divergences) const;
-
-  private:
-    /**
-     * A pointer to the FEValuesBase object we operate on.
-     */
-    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
-
-    /**
-     * The first component of the vector this view represents of the
-     * FEValuesBase object.
-     */
-    const unsigned int first_tensor_component;
-
-    /**
-     * Store the data about shape functions.
-     */
-    std::vector<ShapeFunctionData> shape_function_data;
-  };
-
-
-  template <int rank, int dim, int spacedim = dim>
-  class Tensor;
-
-  /**
-   * A class representing a view to a set of <code>dim*dim</code> components
-   * forming a second-order tensor from a vector-valued finite element. Views
-   * are discussed in the
-   * @ref vector_valued
-   * module.
-   *
-   * This class allows to query the value, gradient and divergence of
-   * (components of) shape functions and solutions representing tensors. The
-   * divergence of a tensor $T_{ij},\, 0\le i,j<\text{dim}$ is defined as $d_i =
-   * \sum_j \frac{\partial T_{ij}}{\partial x_j}, \, 0\le i<\text{dim}$, whereas
-   * its gradient is $G_{ijk} = \frac{\partial T_{ij}}{\partial x_k}$.
-   *
-   * You get an object of this type if you apply a FEValuesExtractors::Tensor
-   * to an FEValues, FEFaceValues or FESubfaceValues object.
-   *
-   * @ingroup feaccess vector_valued
-   */
-  template <int dim, int spacedim>
-  class Tensor<2, dim, spacedim>
-  {
-  public:
-    /**
-     * Data type for what you get when you apply an extractor of this kind to
-     * a vector-valued finite element.
-     */
-    using value_type = dealii::Tensor<2, spacedim>;
-
-    /**
-     * Data type for taking the divergence of a tensor: a vector.
-     */
-    using divergence_type = dealii::Tensor<1, spacedim>;
-
-    /**
-     * Data type for taking the gradient of a second order tensor: a third order
-     * tensor.
-     */
-    using gradient_type = dealii::Tensor<3, spacedim>;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * values of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_value_type = typename ProductType<Number, value_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * divergences of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_divergence_type =
-      typename ProductType<Number, divergence_type>::type;
-
-    /**
-     * An alias for the data type of the product of a @p Number and the
-     * gradient of the view this class provides. This is the data type of
-     * vector components of a finite element field whose degrees of
-     * freedom are described by a vector with elements of type @p Number.
-     */
-    template <typename Number>
-    using solution_gradient_type =
-      typename ProductType<Number, gradient_type>::type;
-
-
-    /**
-     * A structure where for each shape function we pre-compute a bunch of
-     * data that will make later accesses much cheaper.
-     */
-    struct ShapeFunctionData
-    {
-      /**
-       * For each pair (shape function,component within vector), store whether
-       * the selected vector component may be nonzero. For primitive shape
-       * functions we know for sure whether a certain scalar component of a
-       * given shape function is nonzero, whereas for non-primitive shape
-       * functions this may not be entirely clear (e.g. for RT elements it
-       * depends on the shape of a cell).
-       */
-      bool is_nonzero_shape_function_component
-        [value_type::n_independent_components];
-
-      /**
-       * For each pair (shape function, component within vector), store the
-       * row index within the shape_values, shape_gradients, and
-       * shape_hessians tables (the column index is the quadrature point
-       * index). If the shape function is primitive, then we can get this
-       * information from the shape_function_to_row_table of the FEValues
-       * object; otherwise, we have to work a bit harder to compute this
-       * information.
-       */
-      unsigned int row_index[value_type::n_independent_components];
-
-      /**
-       * For each shape function say the following: if only a single entry in
-       * is_nonzero_shape_function_component for this shape function is
-       * nonzero, then store the corresponding value of row_index and
-       * single_nonzero_component_index represents the index between 0 and
-       * (dim^2) for which it is attained. If multiple components are nonzero,
-       * then store -1. If no components are nonzero then store -2.
-       */
-      int single_nonzero_component;
-
-      /**
-       * Index of the @p single_nonzero_component .
-       */
-      unsigned int single_nonzero_component_index;
-    };
-
-    /**
-     * Default constructor. Creates an invalid object.
-     */
-    Tensor();
-
-    /**
-     * Copy constructor. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    Tensor(const Tensor<2, dim, spacedim> &) = delete;
-
-    /**
-     * Move constructor.
-     */
-    // NOLINTNEXTLINE OSX does not compile with noexcept
-    Tensor(Tensor<2, dim, spacedim> &&) = default;
-
-    /**
-     * Destructor.
-     */
-    ~Tensor() = default;
-
-    /**
-     * Constructor for an object that represents <code>(dim*dim)</code>
-     * components of a FEValuesBase object (or of one of the classes derived
-     * from FEValuesBase), representing the unique components comprising a
-     * second-order tensor valued variable.
-     *
-     * The second argument denotes the index of the first component of the
-     * selected symmetric second order tensor.
-     */
-    Tensor(const FEValuesBase<dim, spacedim> &fe_values_base,
-           const unsigned int                 first_tensor_component);
-
-
-    /**
-     * Copy operator. This is not a lightweight object so we don't allow
-     * copying and generate a compile-time error if this function is called.
-     */
-    Tensor &
-    operator=(const Tensor<2, dim, spacedim> &) = delete;
-
-    /**
-     * Move assignment operator.
-     */
-    Tensor &
-    operator=(Tensor<2, dim, spacedim> &&) = default; // NOLINT
-
-    /**
-     * Return the value of the vector components selected by this view, for
-     * the shape function and quadrature point selected by the arguments.
-     * Here, since the view represents a vector-valued part of the FEValues
-     * object with <code>(dim*dim)</code> components (the unique components of
-     * a second-order tensor), the return type is a tensor of rank 2.
-     *
-     * @param shape_function Number of the shape function to be evaluated.
-     * Note that this number runs from zero to dofs_per_cell, even in the case
-     * of an FEFaceValues or FESubfaceValues object.
-     *
-     * @param q_point Number of the quadrature point at which function is to
-     * be evaluated.
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    value_type
-    value(const unsigned int shape_function, const unsigned int q_point) const;
-
-    /**
-     * Return the vector divergence of the vector components selected by this
-     * view, for the shape function and quadrature point selected by the
-     * arguments.
-     *
-     * See the general discussion of this class for a definition of the
-     * divergence.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    divergence_type
-    divergence(const unsigned int shape_function,
-               const unsigned int q_point) const;
-
-    /**
-     * Return the gradient (3-rd order tensor) of the vector components selected
-     * by this view, for the shape function and quadrature point selected by the
-     * arguments.
-     *
-     * See the general discussion of this class for a definition of the
-     * gradient.
-     *
-     * @note The meaning of the arguments is as documented for the value()
-     * function.
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    gradient_type
-    gradient(const unsigned int shape_function,
-             const unsigned int q_point) const;
-
-    /**
-     * Return the values of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * This function is the equivalent of the
-     * FEValuesBase::get_function_values function but it only works on the
-     * selected vector components.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the values of shape functions (i.e., @p value_type) times the
-     * type used to store the values of the unknowns $U_j$ of your finite
-     * element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_values}
-     */
-    template <typename Number>
-    void
-    get_function_values(const ReadVector<Number> &                fe_function,
-                        std::vector<solution_value_type<Number>> &values) const;
-
-    /**
-     * Same as above, but using a vector of local degree-of-freedom values. In
-     * other words, instead of extracting the nodal values of the degrees of
-     * freedom located on the current cell from a global vector associated with
-     * a DoFHandler object (as the function above does), this function instead
-     * takes these local nodal values through its first argument. A typical
-     * way to obtain such a vector is by calling code such as
-     * @code
-     *   cell->get_dof_values (dof_values, local_dof_values);
-     * @endcode
-     * (See DoFCellAccessor::get_dof_values() for more information on this
-     * function.) The point of the current function is then that one could
-     * modify these local values first, for example by applying a limiter
-     * or by ensuring that all nodal values are positive, before evaluating
-     * the finite element field that corresponds to these local values on the
-     * current cell. Another application is where one wants to postprocess
-     * the solution on a cell into a different finite element space on every
-     * cell, without actually creating a corresponding DoFHandler -- in that
-     * case, all one would compute is a local representation of that
-     * postprocessed function, characterized by its nodal values; this function
-     * then allows the evaluation of that representation at quadrature points.
-     *
-     * @param[in] dof_values A vector of local nodal values. This vector must
-     *   have a length equal to number of DoFs on the current cell, and must
-     *   be ordered in the same order as degrees of freedom are numbered on
-     *   the reference cell.
-     *
-     * @param[out] values A vector of values of the given finite element field,
-     *   at the quadrature points on the current object.
-     *
-     * @tparam InputVector The @p InputVector type must allow creation
-     *   of an ArrayView object from it; this is satisfied by the
-     *   `std::vector` class, among others.
-     */
-    template <class InputVector>
-    void
-    get_function_values_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_value_type<typename InputVector::value_type>>
-        &values) const;
-
-    /**
-     * Return the divergence of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * There is no equivalent function such as
-     * FEValuesBase::get_function_divergences in the FEValues classes but the
-     * information can be obtained from FEValuesBase::get_function_gradients,
-     * of course.
-     *
-     * See the general discussion of this class for a definition of the
-     * divergence.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the divergences of shape functions (i.e., @p divergence_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_divergences(
-      const ReadVector<Number> &                     fe_function,
-      std::vector<solution_divergence_type<Number>> &divergences) const;
-
-    /**
-     * This function relates to get_function_divergences() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_divergences_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_divergence_type<typename InputVector::value_type>>
-        &divergences) const;
-
-    /**
-     * Return the gradient of the selected vector components of the finite
-     * element function characterized by <tt>fe_function</tt> at the
-     * quadrature points of the cell, face or subface selected the last time
-     * the <tt>reinit</tt> function of the FEValues object was called.
-     *
-     * See the general discussion of this class for a definition of the
-     * gradient.
-     *
-     * The data type stored by the output vector must be what you get when you
-     * multiply the gradients of shape functions (i.e., @p gradient_type)
-     * times the type used to store the values of the unknowns $U_j$ of your
-     * finite element vector $U$ (represented by the @p fe_function argument).
-     *
-     * @dealiiRequiresUpdateFlags{update_gradients}
-     */
-    template <typename Number>
-    void
-    get_function_gradients(
-      const ReadVector<Number> &                   fe_function,
-      std::vector<solution_gradient_type<Number>> &gradients) const;
-
-    /**
-     * This function relates to get_function_gradients() in the same way
-     * as get_function_values_from_local_dof_values() relates to
-     * get_function_values(). See the documentation of
-     * get_function_values_from_local_dof_values() for more information.
-     */
-    template <class InputVector>
-    void
-    get_function_gradients_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_gradient_type<typename InputVector::value_type>>
-        &gradients) const;
-
-  private:
-    /**
-     * A pointer to the FEValuesBase object we operate on.
-     */
-    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
-
-    /**
-     * The first component of the vector this view represents of the
-     * FEValuesBase object.
-     */
-    const unsigned int first_tensor_component;
-
-    /**
-     * Store the data about shape functions.
-     */
-    std::vector<ShapeFunctionData> shape_function_data;
-  };
-
-} // namespace FEValuesViews
-
-
-namespace internal
-{
-  namespace FEValuesViews
-  {
-    /**
-     * A class whose specialization is used to define what FEValuesViews
-     * object corresponds to the given FEValuesExtractors object.
-     */
-    template <int dim, int spacedim, typename Extractor>
-    struct ViewType
-    {};
-
-    /**
-     * A class whose specialization is used to define what FEValuesViews
-     * object corresponds to the given FEValuesExtractors object.
-     *
-     * When using FEValuesExtractors::Scalar, the corresponding view is an
-     * FEValuesViews::Scalar<dim, spacedim>.
-     */
-    template <int dim, int spacedim>
-    struct ViewType<dim, spacedim, FEValuesExtractors::Scalar>
-    {
-      using type = typename dealii::FEValuesViews::Scalar<dim, spacedim>;
-    };
-
-    /**
-     * A class whose specialization is used to define what FEValuesViews
-     * object corresponds to the given FEValuesExtractors object.
-     *
-     * When using FEValuesExtractors::Vector, the corresponding view is an
-     * FEValuesViews::Vector<dim, spacedim>.
-     */
-    template <int dim, int spacedim>
-    struct ViewType<dim, spacedim, FEValuesExtractors::Vector>
-    {
-      using type = typename dealii::FEValuesViews::Vector<dim, spacedim>;
-    };
-
-    /**
-     * A class whose specialization is used to define what FEValuesViews
-     * object corresponds to the given FEValuesExtractors object.
-     *
-     * When using FEValuesExtractors::Tensor<rank>, the corresponding view is an
-     * FEValuesViews::Tensor<rank, dim, spacedim>.
-     */
-    template <int dim, int spacedim, int rank>
-    struct ViewType<dim, spacedim, FEValuesExtractors::Tensor<rank>>
-    {
-      using type = typename dealii::FEValuesViews::Tensor<rank, dim, spacedim>;
-    };
-
-    /**
-     * A class whose specialization is used to define what FEValuesViews
-     * object corresponds to the given FEValuesExtractors object.
-     *
-     * When using FEValuesExtractors::SymmetricTensor<rank>, the corresponding
-     * view is an FEValuesViews::SymmetricTensor<rank, dim, spacedim>.
-     */
-    template <int dim, int spacedim, int rank>
-    struct ViewType<dim, spacedim, FEValuesExtractors::SymmetricTensor<rank>>
-    {
-      using type =
-        typename dealii::FEValuesViews::SymmetricTensor<rank, dim, spacedim>;
-    };
-
-    /**
-     * A class objects of which store a collection of FEValuesViews::Scalar,
-     * FEValuesViews::Vector, etc object. The FEValuesBase class uses it to
-     * generate all possible Views classes upon construction time; we do this
-     * at construction time since the Views classes cache some information and
-     * are therefore relatively expensive to create.
-     */
-    template <int dim, int spacedim>
-    struct Cache
-    {
-      /**
-       * Caches for scalar and vector, and symmetric second-order tensor
-       * valued views.
-       */
-      std::vector<dealii::FEValuesViews::Scalar<dim, spacedim>> scalars;
-      std::vector<dealii::FEValuesViews::Vector<dim, spacedim>> vectors;
-      std::vector<dealii::FEValuesViews::SymmetricTensor<2, dim, spacedim>>
-        symmetric_second_order_tensors;
-      std::vector<dealii::FEValuesViews::Tensor<2, dim, spacedim>>
-        second_order_tensors;
-
-      /**
-       * Constructor.
-       */
-      Cache(const FEValuesBase<dim, spacedim> &fe_values);
-    };
-  } // namespace FEValuesViews
-} // namespace internal
-
-namespace FEValuesViews
-{
-  /**
-   * A templated alias that associates to a given Extractor class
-   * the corresponding view in FEValuesViews.
-   */
-  template <int dim, int spacedim, typename Extractor>
-  using View = typename dealii::internal::FEValuesViews::
-    ViewType<dim, spacedim, Extractor>::type;
-} // namespace FEValuesViews
 
 
 /**
- * FEValues, FEFaceValues and FESubfaceValues objects are interfaces to finite
- * element and mapping classes on the one hand side, to cells and quadrature
- * rules on the other side. They allow to evaluate values or derivatives of
- * shape functions at the quadrature points of a quadrature formula when
- * projected by a mapping from the unit cell onto a cell in real space. The
- * reason for this abstraction is possible optimization: Depending on the type
- * of finite element and mapping, some values can be computed once on the unit
- * cell. Others must be computed on each cell, but maybe computation of
- * several values at the same time offers ways for optimization. Since this
- * interplay may be complex and depends on the actual finite element, it
- * cannot be left to the applications programmer.
- *
- * FEValues, FEFaceValues and FESubfaceValues provide only data handling:
- * computations are left to objects of type Mapping and FiniteElement. These
- * provide functions <tt>get_*_data</tt> and <tt>fill_*_values</tt> which are
- * called by the constructor and <tt>reinit</tt> functions of
- * <tt>FEValues*</tt>, respectively.
- *
- * <h3>General usage</h3>
- *
- * Usually, an object of <tt>FEValues*</tt> is used in integration loops over
- * all cells of a triangulation (or faces of cells). To take full advantage of
- * the optimization features, it should be constructed before the loop so that
- * information that does not depend on the location and shape of cells can be
- * computed once and for all (this includes, for example, the values of shape
- * functions at quadrature points for the most common elements: we can
- * evaluate them on the unit cell and they will be the same when mapped to the
- * real cell). Then, in the loop over all cells, it must be re-initialized for
- * each grid cell to compute that part of the information that changes
- * depending on the actual cell (for example, the gradient of shape functions
- * equals the gradient on the unit cell -- which can be computed once and for
- * all -- times the Jacobian matrix of the mapping between unit and real cell,
- * which needs to be recomputed for each cell).
- *
- * A typical piece of code, adding up local contributions to the Laplace
- * matrix looks like this:
- *
- * @code
- * FEValues values (mapping, finite_element, quadrature, flags);
- * for (const auto &cell : dof_handler.active_cell_iterators())
- *   {
- *     values.reinit(cell);
- *     for (unsigned int q=0; q<quadrature.size(); ++q)
- *       for (unsigned int i=0; i<finite_element.n_dofs_per_cell(); ++i)
- *         for (unsigned int j=0; j<finite_element.n_dofs_per_cell(); ++j)
- *           A(i,j) += fe_values.shape_value(i,q) *
- *                     fe_values.shape_value(j,q) *
- *                     fe_values.JxW(q);
- *     ...
- *   }
- * @endcode
- *
- * The individual functions used here are described below. Note that by
- * design, the order of quadrature points used inside the FEValues object is
- * the same as defined by the quadrature formula passed to the constructor of
- * the FEValues object above.
- *
- * <h3>Member functions</h3>
- *
- * The functions of this class fall into different categories:
- * <ul>
- * <li> shape_value(), shape_grad(), etc: return one of the values of this
- * object at a time. These functions are inlined, so this is the suggested
- * access to all finite element values. There should be no loss in performance
- * with an optimizing compiler. If the finite element is vector valued, then
- * these functions return the only non-zero component of the requested shape
- * function. However, some finite elements have shape functions that have more
- * than one non-zero component (we call them non-"primitive"), and in this
- * case this set of functions will throw an exception since they cannot
- * generate a useful result. Rather, use the next set of functions.
- *
- * <li> shape_value_component(), shape_grad_component(), etc: This is the same
- * set of functions as above, except that for vector valued finite elements
- * they return only one vector component. This is useful for elements of which
- * shape functions have more than one non-zero component, since then the above
- * functions cannot be used, and you have to walk over all (or only the non-
- * zero) components of the shape function using this set of functions.
- *
- * <li> get_function_values(), get_function_gradients(), etc.: Compute a
- * finite element function or its derivative in quadrature points.
- *
- * <li> reinit: initialize the FEValues object for a certain cell. This
- * function is not in the present class but only in the derived classes and
- * has a variable call syntax. See the docs for the derived classes for more
- * information.
- * </ul>
- *
- *
- * <h3>Internals about the implementation</h3>
+ * Finite element evaluated in quadrature points on a face.
  *
- * The mechanisms by which this class work are discussed on the page on
- * @ref UpdateFlags "Update flags"
- * and about the
- * @ref FE_vs_Mapping_vs_FEValues "How Mapping, FiniteElement, and FEValues work together".
+ * This class adds the functionality of FEFaceValuesBase to FEValues; see
+ * there for more documentation.
  *
+ * Since finite element functions and their derivatives may be discontinuous
+ * at cell boundaries, there is no restriction of this function to a mesh
+ * face. But, there are limits of these values approaching the face from
+ * either of the neighboring cells.
  *
  * @ingroup feaccess
  */
-template <int dim, int spacedim>
-class FEValuesBase : public Subscriptor
+template <int dim, int spacedim = dim>
+class FEFaceValues : public FEFaceValuesBase<dim, spacedim>
 {
 public:
   /**
    * Dimension in which this object operates.
    */
+
   static constexpr unsigned int dimension = dim;
 
-  /**
-   * Dimension of the space in which this object operates.
-   */
   static constexpr unsigned int space_dimension = spacedim;
 
   /**
-   * Number of quadrature points of the current object. Its value is
-   * initialized by the value of max_n_quadrature_points and is updated,
-   * e.g., if FEFaceValues::reinit() is called for a new cell/face.
-   *
-   * @note The default value equals to the value of max_n_quadrature_points.
-   */
-  const unsigned int n_quadrature_points;
-
-  /**
-   * Maximum number of quadrature points. This value might be different from
-   * n_quadrature_points, e.g., if a QCollection with different face quadrature
-   * rules has been passed to initialize FEFaceValues.
-   *
-   * This is mostly useful to initialize arrays to allocate the maximum amount
-   * of memory that may be used when re-sizing later on to a the current
-   * number of quadrature points given by n_quadrature_points.
-   */
-  const unsigned int max_n_quadrature_points;
-
-  /**
-   * Number of shape functions per cell. If we use this base class to evaluate
-   * a finite element on faces of cells, this is still the number of degrees
-   * of freedom per cell, not per face.
+   * Dimension of the object over which we integrate. For the present class,
+   * this is equal to <code>dim-1</code>.
    */
-  const unsigned int dofs_per_cell;
-
+  static constexpr unsigned int integral_dimension = dim - 1;
 
   /**
-   * Constructor. Set up the array sizes with <tt>n_q_points</tt> quadrature
-   * points, <tt>dofs_per_cell</tt> trial functions per cell and with the
-   * given pattern to update the fields when the <tt>reinit</tt> function of
-   * the derived classes is called. The fields themselves are not set up, this
-   * must happen in the constructor of the derived class.
+   * Constructor. Gets cell independent data from mapping and finite element
+   * objects, matching the quadrature rule and update flags.
    */
-  FEValuesBase(const unsigned int                  n_q_points,
-               const unsigned int                  dofs_per_cell,
-               const UpdateFlags                   update_flags,
-               const Mapping<dim, spacedim> &      mapping,
-               const FiniteElement<dim, spacedim> &fe);
+  FEFaceValues(const Mapping<dim, spacedim> &      mapping,
+               const FiniteElement<dim, spacedim> &fe,
+               const Quadrature<dim - 1> &         quadrature,
+               const UpdateFlags                   update_flags);
 
   /**
-   * The copy assignment is deleted since objects of this class are not
-   * copyable.
+   * Like the function above, but taking a collection of quadrature rules. This
+   * allows to assign each face a different quadrature rule. In the case that
+   * the collection only contains a single face quadrature, this quadrature
+   * rule is use on all faces.
    */
-  FEValuesBase &
-  operator=(const FEValuesBase &) = delete;
+  FEFaceValues(const Mapping<dim, spacedim> &      mapping,
+               const FiniteElement<dim, spacedim> &fe,
+               const hp::QCollection<dim - 1> &    quadrature,
+               const UpdateFlags                   update_flags);
 
   /**
-   * The copy constructor is deleted since objects of this class are not
-   * copyable.
+   * Constructor. This constructor is equivalent to the other one except that
+   * it makes the object use a $Q_1$ mapping (i.e., an object of type
+   * MappingQ(1)) implicitly.
    */
-  FEValuesBase(const FEValuesBase &) = delete;
+  FEFaceValues(const FiniteElement<dim, spacedim> &fe,
+               const Quadrature<dim - 1> &         quadrature,
+               const UpdateFlags                   update_flags);
 
   /**
-   * Destructor.
+   * Like the function above, but taking a collection of quadrature rules. This
+   * allows to assign each face a different quadrature rule. In the case that
+   * the collection only contains a single face quadrature, this quadrature
+   * rule is use on all faces.
    */
-  virtual ~FEValuesBase() override;
-
-
-  /// @name Access to shape function values
-  ///
-  /// These fields are filled by the finite element.
-  /** @{ */
+  FEFaceValues(const FiniteElement<dim, spacedim> &fe,
+               const hp::QCollection<dim - 1> &    quadrature,
+               const UpdateFlags                   update_flags);
 
   /**
-   * Value of a shape function at a quadrature point on the cell, face or
-   * subface selected the last time the <tt>reinit</tt> function of the
-   * derived class was called.
-   *
-   * If the shape function is vector-valued, then this returns the only non-
-   * zero component. If the shape function has more than one non-zero
-   * component (i.e. it is not primitive), then throw an exception of type
-   * ExcShapeFunctionNotPrimitive. In that case, use the
-   * shape_value_component() function.
-   *
-   * @param i Number of the shape function $\varphi_i$ to be evaluated. Note
-   * that this number runs from zero to dofs_per_cell, even in the case of an
-   * FEFaceValues or FESubfaceValues object.
-   *
-   * @param q_point Number of the quadrature point at which function is to be
-   * evaluated
-   *
-   * @dealiiRequiresUpdateFlags{update_values}
+   * Reinitialize the gradients, Jacobi determinants, etc for the face with
+   * number @p face_no of @p cell and the given finite element.
    */
-  const double &
-  shape_value(const unsigned int i, const unsigned int q_point) const;
+  template <bool level_dof_access>
+  void
+  reinit(
+    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
+    const unsigned int face_no);
 
   /**
-   * Compute one vector component of the value of a shape function at a
-   * quadrature point. If the finite element is scalar, then only component
-   * zero is allowed and the return value equals that of the shape_value()
-   * function. If the finite element is vector valued but all shape functions
-   * are primitive (i.e. they are non-zero in only one component), then the
-   * value returned by shape_value() equals that of this function for exactly
-   * one component. This function is therefore only of greater interest if the
-   * shape function is not primitive, but then it is necessary since the other
-   * function cannot be used.
-   *
-   * @param i Number of the shape function $\varphi_i$ to be evaluated.
-   *
-   * @param q_point Number of the quadrature point at which function is to be
-   * evaluated.
-   *
-   * @param component vector component to be evaluated.
+   * Reinitialize the gradients, Jacobi determinants, etc for face @p face
+   * and cell @p cell.
    *
-   * @dealiiRequiresUpdateFlags{update_values}
+   * @note @p face must be one of @p cell's face iterators.
    */
-  double
-  shape_value_component(const unsigned int i,
-                        const unsigned int q_point,
-                        const unsigned int component) const;
+  template <bool level_dof_access>
+  void
+  reinit(
+    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
+    const typename Triangulation<dim, spacedim>::face_iterator &          face);
 
   /**
-   * Compute the gradient of the <tt>i</tt>th shape function at the
-   * <tt>quadrature_point</tt>th quadrature point with respect to real cell
-   * coordinates.  If you want to get the derivative in one of the coordinate
-   * directions, use the appropriate function of the Tensor class to extract
-   * one component of the Tensor returned by this function. Since only a
-   * reference to the gradient's value is returned, there should be no major
-   * performance drawback.
-   *
-   * If the shape function is vector-valued, then this returns the only non-
-   * zero component. If the shape function has more than one non-zero
-   * component (i.e. it is not primitive), then it will throw an exception of
-   * type ExcShapeFunctionNotPrimitive. In that case, use the
-   * shape_grad_component() function.
-   *
-   * The same holds for the arguments of this function as for the
-   * shape_value() function.
-   *
-   * @param i Number of the shape function $\varphi_i$ to be evaluated.
-   *
-   * @param q_point Number of the quadrature point at which function
-   * is to be evaluated.
-   *
-   * @dealiiRequiresUpdateFlags{update_gradients}
+   * Reinitialize the gradients, Jacobi determinants, etc for the given face
+   * on a given cell of type "iterator into a Triangulation object", and the
+   * given finite element. Since iterators into a triangulation alone only
+   * convey information about the geometry of a cell, but not about degrees of
+   * freedom possibly associated with this cell, you will not be able to call
+   * some functions of this class if they need information about degrees of
+   * freedom. These functions are, above all, the
+   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
+   * functions. If you want to call these functions, you have to call the @p
+   * reinit variants that take iterators into DoFHandler or other DoF handler
+   * type objects.
    */
-  const Tensor<1, spacedim> &
-  shape_grad(const unsigned int i, const unsigned int q_point) const;
+  void
+  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
+         const unsigned int                                          face_no);
 
-  /**
-   * Return one vector component of the gradient of a shape function at a
-   * quadrature point. If the finite element is scalar, then only component
-   * zero is allowed and the return value equals that of the shape_grad()
-   * function. If the finite element is vector valued but all shape functions
-   * are primitive (i.e. they are non-zero in only one component), then the
-   * value returned by shape_grad() equals that of this function for exactly
-   * one component. This function is therefore only of greater interest if the
-   * shape function is not primitive, but then it is necessary since the other
-   * function cannot be used.
-   *
-   * The same holds for the arguments of this function as for the
-   * shape_value_component() function.
+  /*
+   * Reinitialize the gradients, Jacobi determinants, etc for the given face
+   * on a given cell of type "iterator into a Triangulation object", and the
+   * given finite element. Since iterators into a triangulation alone only
+   * convey information about the geometry of a cell, but not about degrees of
+   * freedom possibly associated with this cell, you will not be able to call
+   * some functions of this class if they need information about degrees of
+   * freedom. These functions are, above all, the
+   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
+   * functions. If you want to call these functions, you have to call the @p
+   * reinit variants that take iterators into DoFHandler or other DoF handler
+   * type objects.
    *
-   * @dealiiRequiresUpdateFlags{update_gradients}
+   * @note @p face must be one of @p cell's face iterators.
    */
-  Tensor<1, spacedim>
-  shape_grad_component(const unsigned int i,
-                       const unsigned int q_point,
-                       const unsigned int component) const;
+  void
+  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
+         const typename Triangulation<dim, spacedim>::face_iterator &face);
 
   /**
-   * Second derivatives of the <tt>i</tt>th shape function at the
-   * <tt>q_point</tt>th quadrature point with respect to real cell
-   * coordinates. If you want to get the derivatives in one of the coordinate
-   * directions, use the appropriate function of the Tensor class to extract
-   * one component. Since only a reference to the hessian values is returned,
-   * there should be no major performance drawback.
-   *
-   * If the shape function is vector-valued, then this returns the only non-
-   * zero component. If the shape function has more than one non-zero
-   * component (i.e. it is not primitive), then throw an exception of type
-   * ExcShapeFunctionNotPrimitive. In that case, use the
-   * shape_hessian_component() function.
-   *
-   * The same holds for the arguments of this function as for the
-   * shape_value() function.
+   * Return a reference to this very object.
    *
-   * @dealiiRequiresUpdateFlags{update_hessians}
-   */
-  const Tensor<2, spacedim> &
-  shape_hessian(const unsigned int i, const unsigned int q_point) const;
-
-  /**
-   * Return one vector component of the hessian of a shape function at a
-   * quadrature point. If the finite element is scalar, then only component
-   * zero is allowed and the return value equals that of the shape_hessian()
-   * function. If the finite element is vector valued but all shape functions
-   * are primitive (i.e. they are non-zero in only one component), then the
-   * value returned by shape_hessian() equals that of this function for
-   * exactly one component. This function is therefore only of greater
-   * interest if the shape function is not primitive, but then it is necessary
-   * since the other function cannot be used.
-   *
-   * The same holds for the arguments of this function as for the
-   * shape_value_component() function.
-   *
-   * @dealiiRequiresUpdateFlags{update_hessians}
-   */
-  Tensor<2, spacedim>
-  shape_hessian_component(const unsigned int i,
-                          const unsigned int q_point,
-                          const unsigned int component) const;
-
-  /**
-   * Third derivatives of the <tt>i</tt>th shape function at the
-   * <tt>q_point</tt>th quadrature point with respect to real cell
-   * coordinates. If you want to get the 3rd derivatives in one of the
-   * coordinate directions, use the appropriate function of the Tensor class
-   * to extract one component. Since only a reference to the 3rd derivative
-   * values is returned, there should be no major performance drawback.
-   *
-   * If the shape function is vector-valued, then this returns the only non-
-   * zero component. If the shape function has more than one non-zero
-   * component (i.e. it is not primitive), then throw an exception of type
-   * ExcShapeFunctionNotPrimitive. In that case, use the
-   * shape_3rdderivative_component() function.
-   *
-   * The same holds for the arguments of this function as for the
-   * shape_value() function.
-   *
-   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
-   */
-  const Tensor<3, spacedim> &
-  shape_3rd_derivative(const unsigned int i, const unsigned int q_point) const;
-
-  /**
-   * Return one vector component of the third derivative of a shape function
-   * at a quadrature point. If the finite element is scalar, then only
-   * component zero is allowed and the return value equals that of the
-   * shape_3rdderivative() function. If the finite element is vector valued
-   * but all shape functions are primitive (i.e. they are non-zero in only one
-   * component), then the value returned by shape_3rdderivative() equals that
-   * of this function for exactly one component. This function is therefore
-   * only of greater interest if the shape function is not primitive, but then
-   * it is necessary since the other function cannot be used.
-   *
-   * The same holds for the arguments of this function as for the
-   * shape_value_component() function.
-   *
-   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
-   */
-  Tensor<3, spacedim>
-  shape_3rd_derivative_component(const unsigned int i,
-                                 const unsigned int q_point,
-                                 const unsigned int component) const;
-
-  /** @} */
-  /// @name Access to values of global finite element fields
-  /** @{ */
-
-  /**
-   * Return the values of a finite element function at the quadrature points
-   * of the current cell, face, or subface (selected the last time the reinit()
-   * function was called). That is, if the first argument @p fe_function is a
-   * vector of nodal values of a finite element function $u_h(\mathbf x)$
-   * defined on a DoFHandler object, then the output vector (the second
-   * argument,
-   * @p values) is the vector of values $u_h(\mathbf x_q^K)$ where $x_q^K$ are
-   * the quadrature points on the current cell $K$.
-   * This function is first discussed in the Results
-   * section of step-4, and the related get_function_gradients() function
-   * is also used in step-15 along with numerous other
-   * tutorial programs.
-   *
-   * If the current cell is not active (i.e., it has children), then the finite
-   * element function is, strictly speaking, defined by shape functions
-   * that live on these child cells. Rather than evaluating the shape functions
-   * on the child cells, with the quadrature points defined on the current
-   * cell, this function first interpolates the finite element function to shape
-   * functions defined on the current cell, and then evaluates this interpolated
-   * function.
-   *
-   * This function may only be used if the finite element in use is a scalar
-   * one, i.e. has only one vector component.  To get values of multi-component
-   * elements, there is another get_function_values() below,
-   * returning a vector of vectors of results.
-   *
-   * @param[in] fe_function A vector of values that describes (globally) the
-   * finite element function that this function should evaluate at the
-   * quadrature points of the current cell.
-   *
-   * @param[out] values The values of the function specified by fe_function at
-   * the quadrature points of the current cell.  The object is assume to
-   * already have the correct size. The data type stored by this output vector
-   * must be what you get when you multiply the values of shape function times
-   * the type used to store the values of the unknowns $U_j$ of your finite
-   * element vector $U$ (represented by the @p fe_function argument). This
-   * happens to be equal to the type of the elements of the solution vector.
-   *
-   * @post <code>values[q]</code> will contain the value of the field
-   * described by fe_function at the $q$th quadrature point.
-   *
-   * @dealiiRequiresUpdateFlags{update_values}
-   */
-  template <typename Number>
-  void
-  get_function_values(const ReadVector<Number> &fe_function,
-                      std::vector<Number> &     values) const;
-
-  /**
-   * This function does the same as the other get_function_values(), but
-   * applied to multi-component (vector-valued) elements. The meaning of the
-   * arguments is as explained there.
-   *
-   * @post <code>values[q]</code> is a vector of values of the field described
-   * by fe_function at the $q$th quadrature point. The size of the vector
-   * accessed by <code>values[q]</code> equals the number of components of the
-   * finite element, i.e. <code>values[q](c)</code> returns the value of the
-   * $c$th vector component at the $q$th quadrature point.
-   *
-   * @dealiiRequiresUpdateFlags{update_values}
-   */
-  template <typename Number>
-  void
-  get_function_values(const ReadVector<Number> &   fe_function,
-                      std::vector<Vector<Number>> &values) const;
-
-  /**
-   * Generate function values from an arbitrary vector. This function
-   * does in essence the same as the first function of this name above,
-   * except that it does not make the assumption that the input vector
-   * corresponds to a DoFHandler that describes the unknowns of a finite
-   * element field (and for which we would then assume that
-   * `fe_function.size() == dof_handler.n_dofs()`). Rather, the nodal
-   * values corresponding to the current cell are elements of an otherwise
-   * arbitrary vector, and these elements are indexed by the second
-   * argument to this function. What the rest of the `fe_function` input
-   * argument corresponds to is of no consequence to this function.
-   *
-   * Given this, the function above corresponds to passing `fe_function`
-   * as first argument to the current function, and using the
-   * `local_dof_indices` array that results from the following call as
-   * second argument to the current function:
-   * @code
-   *   cell->get_dof_indices (local_dof_indices);
-   * @endcode
-   * (See DoFCellAccessor::get_dof_indices() for more information.)
-   *
-   * Likewise, the function above is equivalent to calling
-   * @code
-   *   cell->get_dof_values (fe_function, local_dof_values);
-   * @endcode
-   * and then calling the current function with `local_dof_values` as
-   * first argument, and an array with indices `{0,...,fe.dofs_per_cell-1}`
-   * as second argument.
-   *
-   * The point of the current function is that one sometimes wants to
-   * evaluate finite element functions at quadrature points with nodal
-   * values that are not stored in a global vector -- for example, one could
-   * modify these local values first, such as by applying a limiter
-   * or by ensuring that all nodal values are positive, before evaluating
-   * the finite element field that corresponds to these local values on the
-   * current cell. Another application is where one wants to postprocess
-   * the solution on a cell into a different finite element space on every
-   * cell, without actually creating a corresponding DoFHandler -- in that
-   * case, all one would compute is a local representation of that
-   * postprocessed function, characterized by its nodal values; this function
-   * then allows the evaluation of that representation at quadrature points.
-   *
-   * @param[in] fe_function A vector of nodal values. This vector can have
-   *   an arbitrary size, as long as all elements index by `indices` can
-   *   actually be accessed.
-   *
-   * @param[in] indices A vector of indices into `fe_function`. This vector
-   *   must have length equal to the number of degrees of freedom on the
-   *   current cell, and must identify elements in `fe_function` in the
-   *   order in which degrees of freedom are indexed on the reference cell.
-   *
-   * @param[out] values A vector of values of the given finite element field,
-   *   at the quadrature points on the current object.
-   *
-   * @dealiiRequiresUpdateFlags{update_values}
+   * Though it seems that it is not very useful, this function is there to
+   * provide capability to the hp::FEValues class, in which case it provides
+   * the FEValues object for the present cell (remember that for hp-finite
+   * elements, the actual FE object used may change from cell to cell, so we
+   * also need different FEValues objects for different cells; once you
+   * reinitialize the hp::FEValues object for a specific cell, it retrieves
+   * the FEValues object for the FE on that cell and returns it through a
+   * function of the same name as this one; this function here therefore only
+   * provides the same interface so that one can templatize on FEValues and
+   * hp::FEValues).
    */
-  template <typename Number>
-  void
-  get_function_values(const ReadVector<Number> &fe_function,
-                      const ArrayView<const types::global_dof_index> &indices,
-                      std::vector<Number> &values) const;
+  const FEFaceValues<dim, spacedim> &
+  get_present_fe_values() const;
 
+private:
   /**
-   * Generate vector function values from an arbitrary vector.
-   *
-   * This function corresponds to the previous one, just for the vector-valued
-   * case.
-   *
-   * @dealiiRequiresUpdateFlags{update_values}
+   * Do work common to the two constructors.
    */
-  template <typename Number>
   void
-  get_function_values(const ReadVector<Number> &fe_function,
-                      const ArrayView<const types::global_dof_index> &indices,
-                      std::vector<Vector<Number>> &values) const;
-
+  initialize(const UpdateFlags update_flags);
 
   /**
-   * Generate vector function values from an arbitrary vector. This
-   * function is similar to the previous one, but the `indices`
-   * vector may also be a multiple of the number of dofs per
-   * cell. Then, the vectors in <tt>value</tt> should allow for the same
-   * multiple of the components of the finite element.
-   *
-   * Depending on the value of the last argument, the outer vector of
-   * <tt>values</tt> has either the length of the quadrature rule
-   * (<tt>quadrature_points_fastest == false</tt>) or the length of components
-   * to be filled <tt>quadrature_points_fastest == true</tt>. If <tt>p</tt> is
-   * the current quadrature point number and <tt>i</tt> is the vector
-   * component of the solution desired, the access to <tt>values</tt> is
-   * <tt>values[p][i]</tt> if <tt>quadrature_points_fastest == false</tt>, and
-   * <tt>values[i][p]</tt> otherwise.
-   *
-   * Since this function allows for fairly general combinations of argument
-   * sizes, be aware that the checks on the arguments may not detect errors.
-   *
-   * @dealiiRequiresUpdateFlags{update_values}
+   * The reinit() functions do only that part of the work that requires
+   * knowledge of the type of iterator. After setting present_cell(), they
+   * pass on to this function, which does the real work, and which is
+   * independent of the actual type of the cell iterator.
    */
-  template <typename Number>
   void
-  get_function_values(const ReadVector<Number> &fe_function,
-                      const ArrayView<const types::global_dof_index> &indices,
-                      ArrayView<std::vector<Number>>                  values,
-                      const bool quadrature_points_fastest) const;
+  do_reinit(const unsigned int face_no);
+};
 
-  /** @} */
-  /// @name Access to derivatives of global finite element fields
-  /** @{ */
 
+/**
+ * Finite element evaluated in quadrature points on a face.
+ *
+ * This class adds the functionality of FEFaceValuesBase to FEValues; see
+ * there for more documentation.
+ *
+ * This class is used for faces lying on a refinement edge. In this case, the
+ * neighboring cell is refined. To be able to compute differences between
+ * interior and exterior function values, the refinement of the neighboring
+ * cell must be simulated on this cell. This is achieved by applying a
+ * quadrature rule that simulates the refinement. The resulting data fields
+ * are split up to reflect the refinement structure of the neighbor: a subface
+ * number corresponds to the number of the child of the neighboring face.
+ *
+ * @ingroup feaccess
+ */
+template <int dim, int spacedim = dim>
+class FESubfaceValues : public FEFaceValuesBase<dim, spacedim>
+{
+public:
   /**
-   * Return the gradients of a finite element function at the quadrature points
-   * of the current cell, face, or subface (selected the last time the reinit()
-   * function was called). That is, if the first argument @p fe_function is a
-   * vector of nodal values of a finite element function $u_h(\mathbf x)$
-   * defined on a DoFHandler object, then the output vector (the second
-   * argument,
-   * @p values) is the vector of values $\nabla u_h(\mathbf x_q^K)$ where
-   * $x_q^K$ are the quadrature points on the current cell $K$. This function is
-   * first discussed in the Results section of step-4, and it is also used in
-   * step-15 along with numerous other tutorial programs.
-   *
-   * This function may only be used if the finite element in use is a scalar
-   * one, i.e. has only one vector component. There is a corresponding
-   * function of the same name for vector-valued finite elements.
-   *
-   * @param[in] fe_function A vector of values that describes (globally) the
-   * finite element function that this function should evaluate at the
-   * quadrature points of the current cell.
-   *
-   * @param[out] gradients The gradients of the function specified by
-   * fe_function at the quadrature points of the current cell.  The gradients
-   * are computed in real space (as opposed to on the unit cell).  The object
-   * is assume to already have the correct size. The data type stored by this
-   * output vector must be what you get when you multiply the gradients of
-   * shape function times the type used to store the values of the unknowns
-   * $U_j$ of your finite element vector $U$ (represented by the @p
-   * fe_function argument).
-   *
-   * @post <code>gradients[q]</code> will contain the gradient of the field
-   * described by fe_function at the $q$th quadrature point.
-   * <code>gradients[q][d]</code> represents the derivative in coordinate
-   * direction $d$ at quadrature point $q$.
-   *
-   * @note The actual data type of the input vector may be either a
-   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
-   * vector wrapper classes. It represents a global vector of DoF values
-   * associated with the DoFHandler object with which this FEValues object was
-   * last initialized.
-   *
-   * @dealiiRequiresUpdateFlags{update_gradients}
+   * Dimension in which this object operates.
    */
-  template <typename Number>
-  void
-  get_function_gradients(
-    const ReadVector<Number> &                fe_function,
-    std::vector<Tensor<1, spacedim, Number>> &gradients) const;
+  static constexpr unsigned int dimension = dim;
 
   /**
-   * This function does the same as the other get_function_gradients(), but
-   * applied to multi-component (vector-valued) elements. The meaning of the
-   * arguments is as explained there.
-   *
-   * @post <code>gradients[q]</code> is a vector of gradients of the field
-   * described by fe_function at the $q$th quadrature point. The size of the
-   * vector accessed by <code>gradients[q]</code> equals the number of
-   * components of the finite element, i.e. <code>gradients[q][c]</code>
-   * returns the gradient of the $c$th vector component at the $q$th
-   * quadrature point. Consequently, <code>gradients[q][c][d]</code> is the
-   * derivative in coordinate direction $d$ of the $c$th vector component of
-   * the vector field at quadrature point $q$ of the current cell.
-   *
-   * @dealiiRequiresUpdateFlags{update_gradients}
+   * Dimension of the space in which this object operates.
    */
-  template <typename Number>
-  void
-  get_function_gradients(
-    const ReadVector<Number> &                             fe_function,
-    std::vector<std::vector<Tensor<1, spacedim, Number>>> &gradients) const;
+  static constexpr unsigned int space_dimension = spacedim;
 
   /**
-   * This function relates to the first of the get_function_gradients() function
-   * above in the same way as the get_function_values() with similar arguments
-   * relates to the first of the get_function_values() functions. See there for
-   * more information.
-   *
-   * @dealiiRequiresUpdateFlags{update_gradients}
+   * Dimension of the object over which we integrate. For the present class,
+   * this is equal to <code>dim-1</code>.
    */
-  template <typename Number>
-  void
-  get_function_gradients(
-    const ReadVector<Number> &                      fe_function,
-    const ArrayView<const types::global_dof_index> &indices,
-    std::vector<Tensor<1, spacedim, Number>> &      gradients) const;
+  static constexpr unsigned int integral_dimension = dim - 1;
 
   /**
-   * This function relates to the first of the get_function_gradients() function
-   * above in the same way as the get_function_values() with similar arguments
-   * relates to the first of the get_function_values() functions. See there for
-   * more information.
-   *
-   * @dealiiRequiresUpdateFlags{update_gradients}
+   * Constructor. Gets cell independent data from mapping and finite element
+   * objects, matching the quadrature rule and update flags.
    */
-  template <typename Number>
-  void
-  get_function_gradients(
-    const ReadVector<Number> &                          fe_function,
-    const ArrayView<const types::global_dof_index> &    indices,
-    ArrayView<std::vector<Tensor<1, spacedim, Number>>> gradients,
-    const bool quadrature_points_fastest = false) const;
-
-  /** @} */
-  /// @name Access to second derivatives
-  ///
-  /// Hessian matrices and Laplacians of global finite element fields
-  /** @{ */
+  FESubfaceValues(const Mapping<dim, spacedim> &      mapping,
+                  const FiniteElement<dim, spacedim> &fe,
+                  const Quadrature<dim - 1> &         face_quadrature,
+                  const UpdateFlags                   update_flags);
 
   /**
-   * Compute the tensor of second derivatives of a finite element at the
-   * quadrature points of a cell. This function is the equivalent of the
-   * corresponding get_function_values() function (see there for more
-   * information) but evaluates the finite element field's second derivatives
-   * instead of its value.
-   *
-   * This function may only be used if the finite element in use is a scalar
-   * one, i.e. has only one vector component. There is a corresponding
-   * function of the same name for vector-valued finite elements.
-   *
-   * @param[in] fe_function A vector of values that describes (globally) the
-   * finite element function that this function should evaluate at the
-   * quadrature points of the current cell.
-   *
-   * @param[out] hessians The Hessians of the function specified by
-   * fe_function at the quadrature points of the current cell.  The Hessians
-   * are computed in real space (as opposed to on the unit cell).  The object
-   * is assume to already have the correct size. The data type stored by this
-   * output vector must be what you get when you multiply the Hessians of
-   * shape function times the type used to store the values of the unknowns
-   * $U_j$ of your finite element vector $U$ (represented by the @p
-   * fe_function argument).
-   *
-   * @post <code>hessians[q]</code> will contain the Hessian of the field
-   * described by fe_function at the $q$th quadrature point.
-   * <code>hessians[q][i][j]</code> represents the $(i,j)$th component of the
-   * matrix of second derivatives at quadrature point $q$.
-   *
-   * @note The actual data type of the input vector may be either a
-   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
-   * vector wrapper classes. It represents a global vector of DoF values
-   * associated with the DoFHandler object with which this FEValues object was
-   * last initialized.
+   * Like the function above, but taking a collection of quadrature rules.
    *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * @note We require, in contrast to FEFaceValues, that the number of quadrature
+   *   rules in the collection is one.
    */
-  template <typename Number>
-  void
-  get_function_hessians(
-    const ReadVector<Number> &                fe_function,
-    std::vector<Tensor<2, spacedim, Number>> &hessians) const;
+  FESubfaceValues(const Mapping<dim, spacedim> &      mapping,
+                  const FiniteElement<dim, spacedim> &fe,
+                  const hp::QCollection<dim - 1> &    face_quadrature,
+                  const UpdateFlags                   update_flags);
 
   /**
-   * This function does the same as the other get_function_hessians(), but
-   * applied to multi-component (vector-valued) elements. The meaning of the
-   * arguments is as explained there.
-   *
-   * @post <code>hessians[q]</code> is a vector of Hessians of the field
-   * described by fe_function at the $q$th quadrature point. The size of the
-   * vector accessed by <code>hessians[q]</code> equals the number of
-   * components of the finite element, i.e. <code>hessians[q][c]</code>
-   * returns the Hessian of the $c$th vector component at the $q$th quadrature
-   * point. Consequently, <code>hessians[q][c][i][j]</code> is the $(i,j)$th
-   * component of the matrix of second derivatives of the $c$th vector
-   * component of the vector field at quadrature point $q$ of the current
-   * cell.
-   *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * Constructor. This constructor is equivalent to the other one except that
+   * it makes the object use a $Q_1$ mapping (i.e., an object of type
+   * MappingQ(1)) implicitly.
    */
-  template <typename Number>
-  void
-  get_function_hessians(
-    const ReadVector<Number> &                             fe_function,
-    std::vector<std::vector<Tensor<2, spacedim, Number>>> &hessians,
-    const bool quadrature_points_fastest = false) const;
+  FESubfaceValues(const FiniteElement<dim, spacedim> &fe,
+                  const Quadrature<dim - 1> &         face_quadrature,
+                  const UpdateFlags                   update_flags);
 
   /**
-   * This function relates to the first of the get_function_hessians() function
-   * above in the same way as the get_function_values() with similar arguments
-   * relates to the first of the get_function_values() functions. See there for
-   * more information.
+   * Like the function above, but taking a collection of quadrature rules.
    *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * @note We require, in contrast to FEFaceValues, that the number of quadrature
+   *   rules in the collection is one.
    */
-  template <typename Number>
-  void
-  get_function_hessians(
-    const ReadVector<Number> &                      fe_function,
-    const ArrayView<const types::global_dof_index> &indices,
-    std::vector<Tensor<2, spacedim, Number>> &      hessians) const;
+  FESubfaceValues(const FiniteElement<dim, spacedim> &fe,
+                  const hp::QCollection<dim - 1> &    face_quadrature,
+                  const UpdateFlags                   update_flags);
 
   /**
-   * This function relates to the first of the get_function_hessians() function
-   * above in the same way as the get_function_values() with similar arguments
-   * relates to the first of the get_function_values() functions. See there for
-   * more information.
-   *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * Reinitialize the gradients, Jacobi determinants, etc for the given cell
+   * of type "iterator into a DoFHandler object", and the finite element
+   * associated with this object. It is assumed that the finite element used
+   * by the given cell is also the one used by this FESubfaceValues object.
    */
-  template <typename Number>
+  template <bool level_dof_access>
   void
-  get_function_hessians(
-    const ReadVector<Number> &                          fe_function,
-    const ArrayView<const types::global_dof_index> &    indices,
-    ArrayView<std::vector<Tensor<2, spacedim, Number>>> hessians,
-    const bool quadrature_points_fastest = false) const;
+  reinit(
+    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
+    const unsigned int face_no,
+    const unsigned int subface_no);
 
   /**
-   * Compute the (scalar) Laplacian (i.e. the trace of the tensor of second
-   * derivatives) of a finite element at the quadrature points of a cell. This
-   * function is the equivalent of the corresponding get_function_values()
-   * function (see there for more information) but evaluates the finite
-   * element field's second derivatives instead of its value.
-   *
-   * This function may only be used if the finite element in use is a scalar
-   * one, i.e. has only one vector component. There is a corresponding
-   * function of the same name for vector-valued finite elements.
-   *
-   * @param[in] fe_function A vector of values that describes (globally) the
-   * finite element function that this function should evaluate at the
-   * quadrature points of the current cell.
-   *
-   * @param[out] laplacians The Laplacians of the function specified by
-   * fe_function at the quadrature points of the current cell.  The Laplacians
-   * are computed in real space (as opposed to on the unit cell).  The object
-   * is assume to already have the correct size. The data type stored by this
-   * output vector must be what you get when you multiply the Laplacians of
-   * shape function times the type used to store the values of the unknowns
-   * $U_j$ of your finite element vector $U$ (represented by the @p
-   * fe_function argument). This happens to be equal to the type of the
-   * elements of the input vector.
-   *
-   * @post <code>laplacians[q]</code> will contain the Laplacian of the field
-   * described by fe_function at the $q$th quadrature point.
-   *
-   * @post For each component of the output vector, there holds
-   * <code>laplacians[q]=trace(hessians[q])</code>, where <tt>hessians</tt>
-   * would be the output of the get_function_hessians() function.
-   *
-   * @note The actual data type of the input vector may be either a
-   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
-   * vector wrapper classes. It represents a global vector of DoF values
-   * associated with the DoFHandler object with which this FEValues object was
-   * last initialized.
-   *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * Alternative reinitialization function that takes, as arguments, iterators
+   * to the face and subface instead of their numbers.
    */
-  template <typename Number>
+  template <bool level_dof_access>
   void
-  get_function_laplacians(const ReadVector<Number> &fe_function,
-                          std::vector<Number> &     laplacians) const;
+  reinit(
+    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
+    const typename Triangulation<dim, spacedim>::face_iterator &          face,
+    const typename Triangulation<dim, spacedim>::face_iterator &subface);
 
   /**
-   * This function does the same as the other get_function_laplacians(), but
-   * applied to multi-component (vector-valued) elements. The meaning of the
-   * arguments is as explained there.
-   *
-   * @post <code>laplacians[q]</code> is a vector of Laplacians of the field
-   * described by fe_function at the $q$th quadrature point. The size of the
-   * vector accessed by <code>laplacians[q]</code> equals the number of
-   * components of the finite element, i.e. <code>laplacians[q][c]</code>
-   * returns the Laplacian of the $c$th vector component at the $q$th
-   * quadrature point.
-   *
-   * @post For each component of the output vector, there holds
-   * <code>laplacians[q][c]=trace(hessians[q][c])</code>, where
-   * <tt>hessians</tt> would be the output of the get_function_hessians()
-   * function.
-   *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * Reinitialize the gradients, Jacobi determinants, etc for the given
+   * subface on a given cell of type "iterator into a Triangulation object", and
+   * the given finite element. Since iterators into a triangulation alone only
+   * convey information about the geometry of a cell, but not about degrees of
+   * freedom possibly associated with this cell, you will not be able to call
+   * some functions of this class if they need information about degrees of
+   * freedom. These functions are, above all, the
+   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
+   * functions. If you want to call these functions, you have to call the @p
+   * reinit variants that take iterators into DoFHandler or other DoF handler
+   * type objects.
    */
-  template <typename Number>
   void
-  get_function_laplacians(const ReadVector<Number> &   fe_function,
-                          std::vector<Vector<Number>> &laplacians) const;
+  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
+         const unsigned int                                          face_no,
+         const unsigned int subface_no);
 
   /**
-   * This function relates to the first of the get_function_laplacians()
-   * function above in the same way as the get_function_values() with similar
-   * arguments relates to the first of the get_function_values() functions. See
-   * there for more information.
+   * Reinitialize the gradients, Jacobi determinants, etc for the given
+   * subface on a given cell of type "iterator into a Triangulation object", and
+   * the given finite element. Since iterators into a triangulation alone only
+   * convey information about the geometry of a cell, but not about degrees of
+   * freedom possibly associated with this cell, you will not be able to call
+   * some functions of this class if they need information about degrees of
+   * freedom. These functions are, above all, the
+   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
+   * functions. If you want to call these functions, you have to call the @p
+   * reinit variants that take iterators into DoFHandler or other DoF handler
+   * type objects.
    *
-   * @dealiiRequiresUpdateFlags{update_hessians}
-   */
-  template <typename Number>
-  void
-  get_function_laplacians(
-    const ReadVector<Number> &                      fe_function,
-    const ArrayView<const types::global_dof_index> &indices,
-    std::vector<Number> &                           laplacians) const;
-
-  /**
-   * This function relates to the first of the get_function_laplacians()
-   * function above in the same way as the get_function_values() with similar
-   * arguments relates to the first of the get_function_values() functions. See
-   * there for more information.
+   * This does the same thing as the previous function but takes iterators
+   * instead of numbers as arguments.
    *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * @note @p face and @p subface must correspond to a face (and a subface of
+   * that face) of @p cell.
    */
-  template <typename Number>
   void
-  get_function_laplacians(
-    const ReadVector<Number> &                      fe_function,
-    const ArrayView<const types::global_dof_index> &indices,
-    std::vector<Vector<Number>> &                   laplacians) const;
+  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
+         const typename Triangulation<dim, spacedim>::face_iterator &face,
+         const typename Triangulation<dim, spacedim>::face_iterator &subface);
 
   /**
-   * This function relates to the first of the get_function_laplacians()
-   * function above in the same way as the get_function_values() with similar
-   * arguments relates to the first of the get_function_values() functions. See
-   * there for more information.
+   * Return a reference to this very object.
    *
-   * @dealiiRequiresUpdateFlags{update_hessians}
+   * Though it seems that it is not very useful, this function is there to
+   * provide capability to the hp::FEValues class, in which case it provides
+   * the FEValues object for the present cell (remember that for hp-finite
+   * elements, the actual FE object used may change from cell to cell, so we
+   * also need different FEValues objects for different cells; once you
+   * reinitialize the hp::FEValues object for a specific cell, it retrieves
+   * the FEValues object for the FE on that cell and returns it through a
+   * function of the same name as this one; this function here therefore only
+   * provides the same interface so that one can templatize on FEValues and
+   * hp::FEValues).
    */
-  template <typename Number>
-  void
-  get_function_laplacians(
-    const ReadVector<Number> &                      fe_function,
-    const ArrayView<const types::global_dof_index> &indices,
-    std::vector<std::vector<Number>> &              laplacians,
-    const bool quadrature_points_fastest = false) const;
-
-  /** @} */
-  /// @name Access to third derivatives of global finite element fields
-  /** @{ */
+  const FESubfaceValues<dim, spacedim> &
+  get_present_fe_values() const;
 
   /**
-   * Compute the tensor of third derivatives of a finite element at the
-   * quadrature points of a cell. This function is the equivalent of the
-   * corresponding get_function_values() function (see there for more
-   * information) but evaluates the finite element field's third derivatives
-   * instead of its value.
-   *
-   * This function may only be used if the finite element in use is a scalar
-   * one, i.e. has only one vector component. There is a corresponding
-   * function of the same name for vector-valued finite elements.
-   *
-   * @param[in] fe_function A vector of values that describes (globally) the
-   * finite element function that this function should evaluate at the
-   * quadrature points of the current cell.
-   *
-   * @param[out] third_derivatives The third derivatives of the function
-   * specified by fe_function at the quadrature points of the current cell.
-   * The third derivatives are computed in real space (as opposed to on the
-   * unit cell).  The object is assumed to already have the correct size. The
-   * data type stored by this output vector must be what you get when you
-   * multiply the third derivatives of shape function times the type used to
-   * store the values of the unknowns $U_j$ of your finite element vector $U$
-   * (represented by the @p fe_function argument).
-   *
-   * @post <code>third_derivatives[q]</code> will contain the third
-   * derivatives of the field described by fe_function at the $q$th quadrature
-   * point. <code>third_derivatives[q][i][j][k]</code> represents the
-   * $(i,j,k)$th component of the 3rd order tensor of third derivatives at
-   * quadrature point $q$.
-   *
-   * @note The actual data type of the input vector may be either a
-   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
-   * vector wrapper classes. It represents a global vector of DoF values
-   * associated with the DoFHandler object with which this FEValues object was
-   * last initialized.
+   * @todo Document this
    *
-   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   * @ingroup Exceptions
    */
-  template <typename Number>
-  void
-  get_function_third_derivatives(
-    const ReadVector<Number> &                fe_function,
-    std::vector<Tensor<3, spacedim, Number>> &third_derivatives) const;
+  DeclException0(ExcReinitCalledWithBoundaryFace);
 
   /**
-   * This function does the same as the other
-   * get_function_third_derivatives(), but applied to multi-component (vector-
-   * valued) elements. The meaning of the arguments is as explained there.
-   *
-   * @post <code>third_derivatives[q]</code> is a vector of third derivatives
-   * of the field described by fe_function at the $q$th quadrature point. The
-   * size of the vector accessed by <code>third_derivatives[q]</code> equals
-   * the number of components of the finite element, i.e.
-   * <code>third_derivatives[q][c]</code> returns the third derivative of the
-   * $c$th vector component at the $q$th quadrature point. Consequently,
-   * <code>third_derivatives[q][c][i][j][k]</code> is the $(i,j,k)$th
-   * component of the tensor of third derivatives of the $c$th vector
-   * component of the vector field at quadrature point $q$ of the current
-   * cell.
+   * @todo Document this
    *
-   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   * @ingroup Exceptions
    */
-  template <typename Number>
-  void
-  get_function_third_derivatives(
-    const ReadVector<Number> &                             fe_function,
-    std::vector<std::vector<Tensor<3, spacedim, Number>>> &third_derivatives,
-    const bool quadrature_points_fastest = false) const;
+  DeclException0(ExcFaceHasNoSubfaces);
 
+private:
   /**
-   * This function relates to the first of the get_function_third_derivatives()
-   * function above in the same way as the get_function_values() with similar
-   * arguments relates to the first of the get_function_values() functions. See
-   * there for more information.
-   *
-   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   * Do work common to the two constructors.
    */
-  template <typename Number>
   void
-  get_function_third_derivatives(
-    const ReadVector<Number> &                      fe_function,
-    const ArrayView<const types::global_dof_index> &indices,
-    std::vector<Tensor<3, spacedim, Number>> &      third_derivatives) const;
+  initialize(const UpdateFlags update_flags);
 
   /**
-   * This function relates to the first of the get_function_third_derivatives()
-   * function above in the same way as the get_function_values() with similar
-   * arguments relates to the first of the get_function_values() functions. See
-   * there for more information.
-   *
-   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   * The reinit() functions do only that part of the work that requires
+   * knowledge of the type of iterator. After setting present_cell(), they
+   * pass on to this function, which does the real work, and which is
+   * independent of the actual type of the cell iterator.
    */
-  template <typename Number>
   void
-  get_function_third_derivatives(
-    const ReadVector<Number> &                          fe_function,
-    const ArrayView<const types::global_dof_index> &    indices,
-    ArrayView<std::vector<Tensor<3, spacedim, Number>>> third_derivatives,
-    const bool quadrature_points_fastest = false) const;
-  /** @} */
-
-  /// @name Cell degrees of freedom
-  /** @{ */
+  do_reinit(const unsigned int face_no, const unsigned int subface_no);
+};
 
-  /**
-   * Return an object that can be thought of as an array containing all
-   * indices from zero (inclusive) to `dofs_per_cell` (exclusive). This allows
-   * one to write code using range-based `for` loops of the following kind:
-   * @code
-   *   FEValues<dim>      fe_values (...);
-   *   FullMatrix<double> cell_matrix (...);
-   *
-   *   for (auto &cell : dof_handler.active_cell_iterators())
-   *     {
-   *       cell_matrix = 0;
-   *       fe_values.reinit(cell);
-   *       for (const auto q : fe_values.quadrature_point_indices())
-   *         for (const auto i : fe_values.dof_indices())
-   *           for (const auto j : fe_values.dof_indices())
-   *             cell_matrix(i,j) += ...; // Do something for DoF indices (i,j)
-   *                                      // at quadrature point q
-   *     }
-   * @endcode
-   * Here, we are looping over all degrees of freedom on all cells, with
-   * `i` and `j` taking on all valid indices for cell degrees of freedom, as
-   * defined by the finite element passed to `fe_values`.
-   */
-  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-  dof_indices() const;
-
-  /**
-   * Return an object that can be thought of as an array containing all
-   * indices from @p start_dof_index (inclusive) to `dofs_per_cell` (exclusive).
-   * This allows one to write code using range-based `for` loops of the
-   * following kind:
-   * @code
-   *   FEValues<dim>      fe_values (...);
-   *   FullMatrix<double> cell_matrix (...);
-   *
-   *   for (auto &cell : dof_handler.active_cell_iterators())
-   *     {
-   *       cell_matrix = 0;
-   *       fe_values.reinit(cell);
-   *       for (const auto q : fe_values.quadrature_point_indices())
-   *         for (const auto i : fe_values.dof_indices())
-   *           for (const auto j : fe_values.dof_indices_starting_at(i))
-   *             cell_matrix(i,j) += ...; // Do something for DoF indices (i,j)
-   *                                      // at quadrature point q
-   *     }
-   * @endcode
-   * Here, we are looping over all local degrees of freedom on all cells, with
-   * `i` taking on all valid indices for cell degrees of freedom, as
-   * defined by the finite element passed to `fe_values`, and `j` taking
-   * on a specified subset of `i`'s range, starting at `i` itself and ending at
-   * the number of cell degrees of freedom. In this way, we can construct the
-   * upper half and the diagonal of a @ref GlossStiffnessMatrix "stiffness matrix" contribution (assuming it
-   * is symmetric, and that only one half of it needs to be computed), for
-   * example.
-   *
-   * @note If the @p start_dof_index is equal to the number of DoFs in the cell,
-   * then the returned index range is empty.
-   */
-  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-  dof_indices_starting_at(const unsigned int start_dof_index) const;
-
-  /**
-   * Return an object that can be thought of as an array containing all
-   * indices from zero (inclusive) to @p end_dof_index (inclusive). This allows
-   * one to write code using range-based `for` loops of the following kind:
-   * @code
-   *   FEValues<dim>      fe_values (...);
-   *   FullMatrix<double> cell_matrix (...);
-   *
-   *   for (auto &cell : dof_handler.active_cell_iterators())
-   *     {
-   *       cell_matrix = 0;
-   *       fe_values.reinit(cell);
-   *       for (const auto q : fe_values.quadrature_point_indices())
-   *         for (const auto i : fe_values.dof_indices())
-   *           for (const auto j : fe_values.dof_indices_ending_at(i))
-   *             cell_matrix(i,j) += ...; // Do something for DoF indices (i,j)
-   *                                      // at quadrature point q
-   *     }
-   * @endcode
-   * Here, we are looping over all local degrees of freedom on all cells, with
-   * `i` taking on all valid indices for cell degrees of freedom, as
-   * defined by the finite element passed to `fe_values`, and `j` taking
-   * on a specified subset of `i`'s range, starting at zero and ending at
-   * `i` itself. In this way, we can construct the lower half and the
-   * diagonal of a @ref GlossStiffnessMatrix "stiffness matrix" contribution (assuming it is symmetric, and
-   * that only one half of it needs to be computed), for example.
-   *
-   * @note If the @p end_dof_index is equal to zero, then the returned index
-   * range is empty.
-   */
-  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-  dof_indices_ending_at(const unsigned int end_dof_index) const;
-
-  /** @} */
-
-  /// @name Geometry of the cell
-  /** @{ */
-
-  /**
-   * Return an object that can be thought of as an array containing all
-   * indices from zero to `n_quadrature_points`. This allows to write code
-   * using range-based `for` loops of the following kind:
-   * @code
-   *   FEValues<dim> fe_values (...);
-   *
-   *   for (auto &cell : dof_handler.active_cell_iterators())
-   *     {
-   *       fe_values.reinit(cell);
-   *       for (const auto q_point : fe_values.quadrature_point_indices())
-   *         ... do something at the quadrature point ...
-   *     }
-   * @endcode
-   * Here, we are looping over all quadrature points on all cells, with
-   * `q_point` taking on all valid indices for quadrature points, as defined
-   * by the quadrature rule passed to `fe_values`.
-   *
-   * @see CPP11
-   */
-  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-  quadrature_point_indices() const;
-
-  /**
-   * Return the location of the <tt>q_point</tt>th quadrature point in
-   * real space.
-   *
-   * @dealiiRequiresUpdateFlags{update_quadrature_points}
-   */
-  const Point<spacedim> &
-  quadrature_point(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the vector of quadrature points in real space.
-   *
-   * @dealiiRequiresUpdateFlags{update_quadrature_points}
-   */
-  const std::vector<Point<spacedim>> &
-  get_quadrature_points() const;
-
-  /**
-   * Mapped quadrature weight. If this object refers to a volume evaluation
-   * (i.e. the derived class is of type FEValues), then this is the Jacobi
-   * determinant times the weight of the <tt>q_point</tt>th unit quadrature
-   * point.
-   *
-   * For surface evaluations (i.e. classes FEFaceValues or FESubfaceValues),
-   * it is the mapped surface element times the weight of the quadrature
-   * point.
-   *
-   * You can think of the quantity returned by this function as the volume or
-   * surface element $dx, ds$ in the integral that we implement here by
-   * quadrature.
-   *
-   * @dealiiRequiresUpdateFlags{update_JxW_values}
-   */
-  double
-  JxW(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by JxW().
-   */
-  const std::vector<double> &
-  get_JxW_values() const;
-
-  /**
-   * Return the Jacobian of the transformation at the specified quadrature
-   * point, i.e.  $J_{ij}=dx_i/d\hat x_j$
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobians}
-   */
-  const DerivativeForm<1, dim, spacedim> &
-  jacobian(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobians}
-   */
-  const std::vector<DerivativeForm<1, dim, spacedim>> &
-  get_jacobians() const;
-
-  /**
-   * Return the second derivative of the transformation from unit to real
-   * cell, i.e. the first derivative of the Jacobian, at the specified
-   * quadrature point, i.e. $G_{ijk}=dJ_{jk}/d\hat x_i$.
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_grads}
-   */
-  const DerivativeForm<2, dim, spacedim> &
-  jacobian_grad(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian_grads().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_grads}
-   */
-  const std::vector<DerivativeForm<2, dim, spacedim>> &
-  get_jacobian_grads() const;
-
-  /**
-   * Return the second derivative of the transformation from unit to real
-   * cell, i.e. the first derivative of the Jacobian, at the specified
-   * quadrature point, pushed forward to the real cell coordinates, i.e.
-   * $G_{ijk}=dJ_{iJ}/d\hat x_K (J_{jJ})^{-1} (J_{kK})^{-1}$.
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_grads}
-   */
-  const Tensor<3, spacedim> &
-  jacobian_pushed_forward_grad(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian_pushed_forward_grads().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_grads}
-   */
-  const std::vector<Tensor<3, spacedim>> &
-  get_jacobian_pushed_forward_grads() const;
-
-  /**
-   * Return the third derivative of the transformation from unit to real cell,
-   * i.e. the second derivative of the Jacobian, at the specified quadrature
-   * point, i.e. $G_{ijkl}=\frac{d^2J_{ij}}{d\hat x_k d\hat x_l}$.
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_2nd_derivatives}
-   */
-  const DerivativeForm<3, dim, spacedim> &
-  jacobian_2nd_derivative(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian_2nd_derivatives().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_2nd_derivatives}
-   */
-  const std::vector<DerivativeForm<3, dim, spacedim>> &
-  get_jacobian_2nd_derivatives() const;
-
-  /**
-   * Return the third derivative of the transformation from unit to real cell,
-   * i.e. the second derivative of the Jacobian, at the specified quadrature
-   * point, pushed forward to the real cell coordinates, i.e.
-   * $G_{ijkl}=\frac{d^2J_{iJ}}{d\hat x_K d\hat x_L} (J_{jJ})^{-1}
-   * (J_{kK})^{-1}(J_{lL})^{-1}$.
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_2nd_derivatives}
-   */
-  const Tensor<4, spacedim> &
-  jacobian_pushed_forward_2nd_derivative(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian_pushed_forward_2nd_derivatives().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_2nd_derivatives}
-   */
-  const std::vector<Tensor<4, spacedim>> &
-  get_jacobian_pushed_forward_2nd_derivatives() const;
-
-  /**
-   * Return the fourth derivative of the transformation from unit to real
-   * cell, i.e. the third derivative of the Jacobian, at the specified
-   * quadrature point, i.e. $G_{ijklm}=\frac{d^2J_{ij}}{d\hat x_k d\hat x_l
-   * d\hat x_m}$.
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_3rd_derivatives}
-   */
-  const DerivativeForm<4, dim, spacedim> &
-  jacobian_3rd_derivative(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian_3rd_derivatives().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_3rd_derivatives}
-   */
-  const std::vector<DerivativeForm<4, dim, spacedim>> &
-  get_jacobian_3rd_derivatives() const;
-
-  /**
-   * Return the fourth derivative of the transformation from unit to real
-   * cell, i.e. the third derivative of the Jacobian, at the specified
-   * quadrature point, pushed forward to the real cell coordinates, i.e.
-   * $G_{ijklm}=\frac{d^3J_{iJ}}{d\hat x_K d\hat x_L d\hat x_M} (J_{jJ})^{-1}
-   * (J_{kK})^{-1} (J_{lL})^{-1} (J_{mM})^{-1}$.
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_3rd_derivatives}
-   */
-  const Tensor<5, spacedim> &
-  jacobian_pushed_forward_3rd_derivative(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * jacobian_pushed_forward_3rd_derivatives().
-   *
-   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_2nd_derivatives}
-   */
-  const std::vector<Tensor<5, spacedim>> &
-  get_jacobian_pushed_forward_3rd_derivatives() const;
-
-  /**
-   * Return the inverse Jacobian of the transformation at the specified
-   * quadrature point, i.e.  $J_{ij}=d\hat x_i/dx_j$
-   *
-   * @dealiiRequiresUpdateFlags{update_inverse_jacobians}
-   */
-  const DerivativeForm<1, spacedim, dim> &
-  inverse_jacobian(const unsigned int q_point) const;
-
-  /**
-   * Return a reference to the array holding the values returned by
-   * inverse_jacobian().
-   *
-   * @dealiiRequiresUpdateFlags{update_inverse_jacobians}
-   */
-  const std::vector<DerivativeForm<1, spacedim, dim>> &
-  get_inverse_jacobians() const;
-
-  /**
-   * Return the normal vector at a quadrature point. If you call this
-   * function for a face (i.e., when using a FEFaceValues or FESubfaceValues
-   * object), then this function returns the outward normal vector to
-   * the cell at the <tt>q_point</tt>th quadrature point of the face.
-   *
-   * In contrast, if you call this function for a cell of codimension one
-   * (i.e., when using a `FEValues<dim,spacedim>` object with
-   * `spacedim>dim`), then this function returns the normal vector to the
-   * cell -- in other words, an approximation to the normal vector to the
-   * manifold in which the triangulation is embedded. There are of
-   * course two normal directions to a manifold in that case, and this
-   * function returns the "up" direction as induced by the numbering of the
-   * vertices.
-   *
-   * The length of the vector is normalized to one.
-   *
-   * @dealiiRequiresUpdateFlags{update_normal_vectors}
-   */
-  const Tensor<1, spacedim> &
-  normal_vector(const unsigned int q_point) const;
-
-  /**
-   * Return the normal vectors at all quadrature points represented by
-   * this object. See the normal_vector() function for what the normal
-   * vectors represent.
-   *
-   * @dealiiRequiresUpdateFlags{update_normal_vectors}
-   */
-  const std::vector<Tensor<1, spacedim>> &
-  get_normal_vectors() const;
-
-  /** @} */
-
-  /// @name Extractors Methods to extract individual components
-  /** @{ */
-
-  /**
-   * Create a view of the current FEValues object that represents a particular
-   * scalar component of the possibly vector-valued finite element. The
-   * concept of views is explained in the documentation of the namespace
-   * FEValuesViews and in particular in the
-   * @ref vector_valued
-   * module.
-   */
-  const FEValuesViews::Scalar<dim, spacedim> &
-  operator[](const FEValuesExtractors::Scalar &scalar) const;
-
-  /**
-   * Create a view of the current FEValues object that represents a set of
-   * <code>dim</code> scalar components (i.e. a vector) of the vector-valued
-   * finite element. The concept of views is explained in the documentation of
-   * the namespace FEValuesViews and in particular in the
-   * @ref vector_valued
-   * module.
-   */
-  const FEValuesViews::Vector<dim, spacedim> &
-  operator[](const FEValuesExtractors::Vector &vector) const;
-
-  /**
-   * Create a view of the current FEValues object that represents a set of
-   * <code>(dim*dim + dim)/2</code> scalar components (i.e. a symmetric 2nd
-   * order tensor) of the vector-valued finite element. The concept of views
-   * is explained in the documentation of the namespace FEValuesViews and in
-   * particular in the
-   * @ref vector_valued
-   * module.
-   */
-  const FEValuesViews::SymmetricTensor<2, dim, spacedim> &
-  operator[](const FEValuesExtractors::SymmetricTensor<2> &tensor) const;
-
-
-  /**
-   * Create a view of the current FEValues object that represents a set of
-   * <code>(dim*dim)</code> scalar components (i.e. a 2nd order tensor) of the
-   * vector-valued finite element. The concept of views is explained in the
-   * documentation of the namespace FEValuesViews and in particular in the
-   * @ref vector_valued
-   * module.
-   */
-  const FEValuesViews::Tensor<2, dim, spacedim> &
-  operator[](const FEValuesExtractors::Tensor<2> &tensor) const;
-
-  /** @} */
-
-  /// @name Access to the raw data
-  /** @{ */
-
-  /**
-   * Constant reference to the selected mapping object.
-   */
-  const Mapping<dim, spacedim> &
-  get_mapping() const;
-
-  /**
-   * Constant reference to the selected finite element object.
-   */
-  const FiniteElement<dim, spacedim> &
-  get_fe() const;
-
-  /**
-   * Return the update flags set for this object.
-   */
-  UpdateFlags
-  get_update_flags() const;
-
-  /**
-   * Return a triangulation iterator to the current cell.
-   */
-  typename Triangulation<dim, spacedim>::cell_iterator
-  get_cell() const;
-
-  /**
-   * Return the relation of the current cell to the previous cell. This allows
-   * re-use of some cell data (like local matrices for equations with constant
-   * coefficients) if the result is <tt>CellSimilarity::translation</tt>.
-   */
-  CellSimilarity::Similarity
-  get_cell_similarity() const;
-
-  /**
-   * Determine an estimate for the memory consumption (in bytes) of this
-   * object.
-   */
-  std::size_t
-  memory_consumption() const;
-  /** @} */
-
-
-  /**
-   * This exception is thrown if FEValuesBase is asked to return the value of
-   * a field which was not required by the UpdateFlags for this FEValuesBase.
-   *
-   * @ingroup Exceptions
-   */
-  DeclException1(
-    ExcAccessToUninitializedField,
-    std::string,
-    << "You are requesting information from an FEValues/FEFaceValues/FESubfaceValues "
-    << "object for which this kind of information has not been computed. What "
-    << "information these objects compute is determined by the update_* flags you "
-    << "pass to the constructor. Here, the operation you are attempting requires "
-    << "the <" << arg1
-    << "> flag to be set, but it was apparently not specified "
-    << "upon construction.");
-
-  /**
-   * FEValues::reinit() has not been called for any cell.
-   *
-   * @ingroup Exceptions
-   */
-  DeclExceptionMsg(ExcNotReinited,
-                   "FEValues object is not reinit'ed to any cell");
-
-  /**
-   * Mismatch between the FEValues FiniteElement and
-   * cell->get_dof_handler().get_fe()
-   *
-   * @ingroup Exceptions
-   */
-  DeclExceptionMsg(
-    ExcFEDontMatch,
-    "The FiniteElement you provided to FEValues and the FiniteElement that belongs "
-    "to the DoFHandler that provided the cell iterator do not match.");
-  /**
-   * A given shape function is not primitive, but it needs to be.
-   *
-   * @ingroup Exceptions
-   */
-  DeclException1(ExcShapeFunctionNotPrimitive,
-                 int,
-                 << "The shape function with index " << arg1
-                 << " is not primitive, i.e. it is vector-valued and "
-                 << "has more than one non-zero vector component. This "
-                 << "function cannot be called for these shape functions. "
-                 << "Maybe you want to use the same function with the "
-                 << "_component suffix?");
-
-  /**
-   * The given FiniteElement is not a primitive element, see
-   * FiniteElement::is_primitive().
-   *
-   * @ingroup Exceptions
-   */
-  DeclExceptionMsg(
-    ExcFENotPrimitive,
-    "The given FiniteElement is not a primitive element but the requested operation "
-    "only works for those. See FiniteElement::is_primitive() for more information.");
-
-protected:
-  /**
-   * Objects of the FEValues class need to store an iterator
-   * to the present cell in order to be able to extract the values of the
-   * degrees of freedom on this cell in the get_function_values() and assorted
-   * functions.
-   */
-  class CellIteratorContainer
-  {
-  public:
-    DeclExceptionMsg(
-      ExcNeedsDoFHandler,
-      "You have previously called the FEValues::reinit() function with a "
-      "cell iterator of type Triangulation<dim,spacedim>::cell_iterator. However, "
-      "when you do this, you cannot call some functions in the FEValues "
-      "class, such as the get_function_values/gradients/hessians/third_derivatives "
-      "functions. If you need these functions, then you need to call "
-      "FEValues::reinit() with an iterator type that allows to extract "
-      "degrees of freedom, such as DoFHandler<dim,spacedim>::cell_iterator.");
-
-    /**
-     * Constructor.
-     */
-    CellIteratorContainer();
-
-    /**
-     * Constructor.
-     */
-    template <bool lda>
-    CellIteratorContainer(
-      const TriaIterator<DoFCellAccessor<dim, spacedim, lda>> &cell);
-
-    /**
-     * Constructor.
-     */
-    CellIteratorContainer(
-      const typename Triangulation<dim, spacedim>::cell_iterator &cell);
-
-    /**
-     * Indicate whether FEValues::reinit() was called.
-     */
-    bool
-    is_initialized() const;
-
-    /**
-     * Conversion operator to an iterator for triangulations. This
-     * conversion is implicit for the original iterators, since they are derived
-     * classes. However, since here we have kind of a parallel class hierarchy,
-     * we have to have a conversion operator.
-     */
-    operator typename Triangulation<dim, spacedim>::cell_iterator() const;
-
-    /**
-     * Return the number of degrees of freedom the DoF
-     * handler object has to which the iterator belongs to.
-     */
-    types::global_dof_index
-    n_dofs_for_dof_handler() const;
-
-    /**
-     * Call @p get_interpolated_dof_values of the iterator with the
-     * given arguments.
-     */
-    template <typename Number>
-    void
-    get_interpolated_dof_values(const ReadVector<Number> &in,
-                                Vector<Number> &          out) const;
-
-    /**
-     * Call @p get_interpolated_dof_values of the iterator with the
-     * given arguments.
-     */
-    void
-    get_interpolated_dof_values(const IndexSet &              in,
-                                Vector<IndexSet::value_type> &out) const;
-
-  private:
-    bool                                                 initialized;
-    typename Triangulation<dim, spacedim>::cell_iterator cell;
-    const DoFHandler<dim, spacedim> *                    dof_handler;
-    bool                                                 level_dof_access;
-  };
-
-  /**
-   * Store the cell selected last time the reinit() function was called.  This
-   * is necessary for the <tt>get_function_*</tt> functions as well as the
-   * functions of same name in the extractor classes.
-   */
-  CellIteratorContainer present_cell;
-
-  /**
-   * A signal connection we use to ensure we get informed whenever the
-   * triangulation changes by refinement. We need to know about that because
-   * it invalidates all cell iterators and, as part of that, the
-   * 'present_cell' iterator we keep around between subsequent calls to
-   * reinit() in order to compute the cell similarity.
-   */
-  boost::signals2::connection tria_listener_refinement;
-
-  /**
-   * A signal connection we use to ensure we get informed whenever the
-   * triangulation changes by mesh transformations. We need to know about that
-   * because it invalidates all cell iterators and, as part of that, the
-   * 'present_cell' iterator we keep around between subsequent calls to
-   * reinit() in order to compute the cell similarity.
-   */
-  boost::signals2::connection tria_listener_mesh_transform;
-
-  /**
-   * A function that is connected to the triangulation in order to reset the
-   * stored 'present_cell' iterator to an invalid one whenever the
-   * triangulation is changed and the iterator consequently becomes invalid.
-   */
-  void
-  invalidate_present_cell();
-
-  /**
-   * This function is called by the various reinit() functions in derived
-   * classes. Given the cell indicated by the argument, test whether we have
-   * to throw away the previously stored present_cell argument because it
-   * would require us to compare cells from different triangulations. In
-   * checking all this, also make sure that we have tria_listener connected to
-   * the triangulation to which we will set present_cell right after calling
-   * this function.
-   */
-  void
-  maybe_invalidate_previous_present_cell(
-    const typename Triangulation<dim, spacedim>::cell_iterator &cell);
-
-  /**
-   * A pointer to the mapping object associated with this FEValues object.
-   */
-  const SmartPointer<const Mapping<dim, spacedim>, FEValuesBase<dim, spacedim>>
-    mapping;
-
-  /**
-   * A pointer to the internal data object of mapping, obtained from
-   * Mapping::get_data(), Mapping::get_face_data(), or
-   * Mapping::get_subface_data().
-   */
-  std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
-    mapping_data;
-
-  /**
-   * An object into which the Mapping::fill_fe_values() and similar functions
-   * place their output.
-   */
-  internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
-    mapping_output;
-
-  /**
-   * A pointer to the finite element object associated with this FEValues
-   * object.
-   */
-  const SmartPointer<const FiniteElement<dim, spacedim>,
-                     FEValuesBase<dim, spacedim>>
-    fe;
-
-  /**
-   * A pointer to the internal data object of finite element, obtained from
-   * FiniteElement::get_data(), Mapping::get_face_data(), or
-   * FiniteElement::get_subface_data().
-   */
-  std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
-    fe_data;
-
-  /**
-   * An object into which the FiniteElement::fill_fe_values() and similar
-   * functions place their output.
-   */
-  dealii::internal::FEValuesImplementation::FiniteElementRelatedData<dim,
-                                                                     spacedim>
-    finite_element_output;
-
-
-  /**
-   * Original update flags handed to the constructor of FEValues.
-   */
-  UpdateFlags update_flags;
-
-  /**
-   * Initialize some update flags. Called from the @p initialize functions of
-   * derived classes, which are in turn called from their constructors.
-   *
-   * Basically, this function finds out using the finite element and mapping
-   * object already stored which flags need to be set to compute everything
-   * the user wants, as expressed through the flags passed as argument.
-   */
-  UpdateFlags
-  compute_update_flags(const UpdateFlags update_flags) const;
-
-  /**
-   * An enum variable that can store different states of the current cell in
-   * comparison to the previously visited cell. If wanted, additional states
-   * can be checked here and used in one of the methods used during reinit.
-   */
-  CellSimilarity::Similarity cell_similarity;
-
-  /**
-   * A function that checks whether the new cell is similar to the one
-   * previously used. Then, a significant amount of the data can be reused,
-   * e.g. the derivatives of the basis functions in real space, shape_grad.
-   */
-  void
-  check_cell_similarity(
-    const typename Triangulation<dim, spacedim>::cell_iterator &cell);
-
-private:
-  /**
-   * A cache for all possible FEValuesViews objects.
-   */
-  dealii::internal::FEValuesViews::Cache<dim, spacedim> fe_values_views_cache;
-
-  // Make the view classes friends of this class, since they access internal
-  // data.
-  template <int, int>
-  friend class FEValuesViews::Scalar;
-  template <int, int>
-  friend class FEValuesViews::Vector;
-  template <int, int, int>
-  friend class FEValuesViews::SymmetricTensor;
-  template <int, int, int>
-  friend class FEValuesViews::Tensor;
-};
-
-
-
-/**
- * Finite element evaluated in quadrature points of a cell.
- *
- * This function implements the initialization routines for FEValuesBase, if
- * values in quadrature points of a cell are needed. For further documentation
- * see this class.
- *
- * @ingroup feaccess
- */
-template <int dim, int spacedim = dim>
-class FEValues : public FEValuesBase<dim, spacedim>
-{
-public:
-  /**
-   * Dimension of the object over which we integrate. For the present class,
-   * this is equal to <code>dim</code>.
-   */
-  static constexpr unsigned int integral_dimension = dim;
-
-  /**
-   * Constructor. Gets cell independent data from mapping and finite element
-   * objects, matching the quadrature rule and update flags.
-   */
-  FEValues(const Mapping<dim, spacedim> &      mapping,
-           const FiniteElement<dim, spacedim> &fe,
-           const Quadrature<dim> &             quadrature,
-           const UpdateFlags                   update_flags);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules.
-   *
-   * @note We require, in contrast to FEFaceValues, that the number of quadrature
-   *   rules in the collection is one.
-   */
-  FEValues(const Mapping<dim, spacedim> &      mapping,
-           const FiniteElement<dim, spacedim> &fe,
-           const hp::QCollection<dim> &        quadrature,
-           const UpdateFlags                   update_flags);
-
-  /**
-   * Constructor. This constructor is equivalent to the other one except that
-   * it makes the object use a $Q_1$ mapping (i.e., an object of type
-   * MappingQ(1)) implicitly.
-   */
-  FEValues(const FiniteElement<dim, spacedim> &fe,
-           const Quadrature<dim> &             quadrature,
-           const UpdateFlags                   update_flags);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules.
-   *
-   * @note We require, in contrast to FEFaceValues, that the number of quadrature
-   *   rules in the collection is one.
-   */
-  FEValues(const FiniteElement<dim, spacedim> &fe,
-           const hp::QCollection<dim> &        quadrature,
-           const UpdateFlags                   update_flags);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the given cell
-   * of type "iterator into a DoFHandler object", and the finite element
-   * associated with this object. It is assumed that the finite element used
-   * by the given cell is also the one used by this FEValues object.
-   */
-  template <bool level_dof_access>
-  void
-  reinit(
-    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the given cell
-   * of type "iterator into a Triangulation object", and the given finite
-   * element. Since iterators into triangulation alone only convey information
-   * about the geometry of a cell, but not about degrees of freedom possibly
-   * associated with this cell, you will not be able to call some functions of
-   * this class if they need information about degrees of freedom. These
-   * functions are, above all, the
-   * <tt>get_function_value/gradients/hessians/laplacians/third_derivatives</tt>
-   * functions. If you want to call these functions, you have to call the @p
-   * reinit variants that take iterators into DoFHandler or other DoF handler
-   * type objects.
-   */
-  void
-  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell);
-
-  /**
-   * Return a reference to the copy of the quadrature formula stored by this
-   * object.
-   */
-  const Quadrature<dim> &
-  get_quadrature() const;
-
-  /**
-   * Determine an estimate for the memory consumption (in bytes) of this
-   * object.
-   */
-  std::size_t
-  memory_consumption() const;
-
-  /**
-   * Return a reference to this very object.
-   *
-   * Though it seems that it is not very useful, this function is there to
-   * provide capability to the hp::FEValues class, in which case it provides
-   * the FEValues object for the present cell (remember that for hp-finite
-   * elements, the actual FE object used may change from cell to cell, so we
-   * also need different FEValues objects for different cells; once you
-   * reinitialize the hp::FEValues object for a specific cell, it retrieves
-   * the FEValues object for the FE on that cell and returns it through a
-   * function of the same name as this one; this function here therefore only
-   * provides the same interface so that one can templatize on FEValues and
-   * hp::FEValues).
-   */
-  const FEValues<dim, spacedim> &
-  get_present_fe_values() const;
-
-private:
-  /**
-   * Store a copy of the quadrature formula here.
-   */
-  const Quadrature<dim> quadrature;
-
-  /**
-   * Do work common to the two constructors.
-   */
-  void
-  initialize(const UpdateFlags update_flags);
-
-  /**
-   * The reinit() functions do only that part of the work that requires
-   * knowledge of the type of iterator. After setting present_cell(), they
-   * pass on to this function, which does the real work, and which is
-   * independent of the actual type of the cell iterator.
-   */
-  void
-  do_reinit();
-};
-
-
-/**
- * Extend the interface of FEValuesBase to values that only make sense when
- * evaluating something on the surface of a cell. All the data that is
- * available in the interior of cells is also available here.
- *
- * See FEValuesBase
- *
- * @ingroup feaccess
- */
-template <int dim, int spacedim = dim>
-class FEFaceValuesBase : public FEValuesBase<dim, spacedim>
-{
-public:
-  /**
-   * Dimension of the object over which we integrate. For the present class,
-   * this is equal to <code>dim-1</code>.
-   */
-  static constexpr unsigned int integral_dimension = dim - 1;
-
-  /**
-   * Constructor. Call the constructor of the base class and set up the arrays
-   * of this class with the right sizes.  Actually filling these arrays is a
-   * duty of the derived class's constructors.
-   *
-   * @p n_faces_or_subfaces is the number of faces or subfaces that this
-   * object is to store. The actual number depends on the derived class, for
-   * FEFaceValues it is <tt>2*dim</tt>, while for the FESubfaceValues class it
-   * is <tt>2*dim*(1<<(dim-1))</tt>, i.e. the number of faces times the number
-   * of subfaces per face.
-   */
-  FEFaceValuesBase(const unsigned int                  dofs_per_cell,
-                   const UpdateFlags                   update_flags,
-                   const Mapping<dim, spacedim> &      mapping,
-                   const FiniteElement<dim, spacedim> &fe,
-                   const Quadrature<dim - 1> &         quadrature);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules. This
-   * allows to assign each face a different quadrature rule. In the case that
-   * the collection only contains a single face quadrature, this quadrature
-   * rule is use on all faces.
-   */
-  FEFaceValuesBase(const unsigned int                  dofs_per_cell,
-                   const UpdateFlags                   update_flags,
-                   const Mapping<dim, spacedim> &      mapping,
-                   const FiniteElement<dim, spacedim> &fe,
-                   const hp::QCollection<dim - 1> &    quadrature);
-
-  /**
-   * Boundary form of the transformation of the cell at the <tt>q_point</tt>th
-   * quadrature point.  See
-   * @ref GlossBoundaryForm.
-   *
-   * @dealiiRequiresUpdateFlags{update_boundary_forms}
-   */
-  const Tensor<1, spacedim> &
-  boundary_form(const unsigned int q_point) const;
-
-  /**
-   * Return the list of outward normal vectors times the Jacobian of the
-   * surface mapping.
-   *
-   * @dealiiRequiresUpdateFlags{update_boundary_forms}
-   */
-  const std::vector<Tensor<1, spacedim>> &
-  get_boundary_forms() const;
-
-  /**
-   * Return the number of the face selected the last time the reinit() function
-   * was called.
-   */
-  unsigned int
-  get_face_number() const;
-
-  /**
-   * Return the index of the face selected the last time the reinit() function
-   * was called.
-   */
-  unsigned int
-  get_face_index() const;
-
-  /**
-   * Return a reference to the copy of the quadrature formula stored by this
-   * object.
-   */
-  const Quadrature<dim - 1> &
-  get_quadrature() const;
-
-  /**
-   * Determine an estimate for the memory consumption (in bytes) of this
-   * object.
-   */
-  std::size_t
-  memory_consumption() const;
-
-protected:
-  /**
-   * Number of the face selected the last time the reinit() function was
-   * called.
-   */
-  unsigned int present_face_no;
-
-  /**
-   * Index of the face selected the last time the reinit() function was
-   * called.
-   */
-  unsigned int present_face_index;
-
-  /**
-   * Store a copy of the quadrature formula here.
-   */
-  const hp::QCollection<dim - 1> quadrature;
-};
-
-
-
-/**
- * Finite element evaluated in quadrature points on a face.
- *
- * This class adds the functionality of FEFaceValuesBase to FEValues; see
- * there for more documentation.
- *
- * Since finite element functions and their derivatives may be discontinuous
- * at cell boundaries, there is no restriction of this function to a mesh
- * face. But, there are limits of these values approaching the face from
- * either of the neighboring cells.
- *
- * @ingroup feaccess
- */
-template <int dim, int spacedim = dim>
-class FEFaceValues : public FEFaceValuesBase<dim, spacedim>
-{
-public:
-  /**
-   * Dimension in which this object operates.
-   */
-
-  static constexpr unsigned int dimension = dim;
-
-  static constexpr unsigned int space_dimension = spacedim;
-
-  /**
-   * Dimension of the object over which we integrate. For the present class,
-   * this is equal to <code>dim-1</code>.
-   */
-  static constexpr unsigned int integral_dimension = dim - 1;
-
-  /**
-   * Constructor. Gets cell independent data from mapping and finite element
-   * objects, matching the quadrature rule and update flags.
-   */
-  FEFaceValues(const Mapping<dim, spacedim> &      mapping,
-               const FiniteElement<dim, spacedim> &fe,
-               const Quadrature<dim - 1> &         quadrature,
-               const UpdateFlags                   update_flags);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules. This
-   * allows to assign each face a different quadrature rule. In the case that
-   * the collection only contains a single face quadrature, this quadrature
-   * rule is use on all faces.
-   */
-  FEFaceValues(const Mapping<dim, spacedim> &      mapping,
-               const FiniteElement<dim, spacedim> &fe,
-               const hp::QCollection<dim - 1> &    quadrature,
-               const UpdateFlags                   update_flags);
-
-  /**
-   * Constructor. This constructor is equivalent to the other one except that
-   * it makes the object use a $Q_1$ mapping (i.e., an object of type
-   * MappingQ(1)) implicitly.
-   */
-  FEFaceValues(const FiniteElement<dim, spacedim> &fe,
-               const Quadrature<dim - 1> &         quadrature,
-               const UpdateFlags                   update_flags);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules. This
-   * allows to assign each face a different quadrature rule. In the case that
-   * the collection only contains a single face quadrature, this quadrature
-   * rule is use on all faces.
-   */
-  FEFaceValues(const FiniteElement<dim, spacedim> &fe,
-               const hp::QCollection<dim - 1> &    quadrature,
-               const UpdateFlags                   update_flags);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the face with
-   * number @p face_no of @p cell and the given finite element.
-   */
-  template <bool level_dof_access>
-  void
-  reinit(
-    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
-    const unsigned int face_no);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for face @p face
-   * and cell @p cell.
-   *
-   * @note @p face must be one of @p cell's face iterators.
-   */
-  template <bool level_dof_access>
-  void
-  reinit(
-    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
-    const typename Triangulation<dim, spacedim>::face_iterator &          face);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the given face
-   * on a given cell of type "iterator into a Triangulation object", and the
-   * given finite element. Since iterators into a triangulation alone only
-   * convey information about the geometry of a cell, but not about degrees of
-   * freedom possibly associated with this cell, you will not be able to call
-   * some functions of this class if they need information about degrees of
-   * freedom. These functions are, above all, the
-   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
-   * functions. If you want to call these functions, you have to call the @p
-   * reinit variants that take iterators into DoFHandler or other DoF handler
-   * type objects.
-   */
-  void
-  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
-         const unsigned int                                          face_no);
-
-  /*
-   * Reinitialize the gradients, Jacobi determinants, etc for the given face
-   * on a given cell of type "iterator into a Triangulation object", and the
-   * given finite element. Since iterators into a triangulation alone only
-   * convey information about the geometry of a cell, but not about degrees of
-   * freedom possibly associated with this cell, you will not be able to call
-   * some functions of this class if they need information about degrees of
-   * freedom. These functions are, above all, the
-   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
-   * functions. If you want to call these functions, you have to call the @p
-   * reinit variants that take iterators into DoFHandler or other DoF handler
-   * type objects.
-   *
-   * @note @p face must be one of @p cell's face iterators.
-   */
-  void
-  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
-         const typename Triangulation<dim, spacedim>::face_iterator &face);
-
-  /**
-   * Return a reference to this very object.
-   *
-   * Though it seems that it is not very useful, this function is there to
-   * provide capability to the hp::FEValues class, in which case it provides
-   * the FEValues object for the present cell (remember that for hp-finite
-   * elements, the actual FE object used may change from cell to cell, so we
-   * also need different FEValues objects for different cells; once you
-   * reinitialize the hp::FEValues object for a specific cell, it retrieves
-   * the FEValues object for the FE on that cell and returns it through a
-   * function of the same name as this one; this function here therefore only
-   * provides the same interface so that one can templatize on FEValues and
-   * hp::FEValues).
-   */
-  const FEFaceValues<dim, spacedim> &
-  get_present_fe_values() const;
-
-private:
-  /**
-   * Do work common to the two constructors.
-   */
-  void
-  initialize(const UpdateFlags update_flags);
-
-  /**
-   * The reinit() functions do only that part of the work that requires
-   * knowledge of the type of iterator. After setting present_cell(), they
-   * pass on to this function, which does the real work, and which is
-   * independent of the actual type of the cell iterator.
-   */
-  void
-  do_reinit(const unsigned int face_no);
-};
-
-
-/**
- * Finite element evaluated in quadrature points on a face.
- *
- * This class adds the functionality of FEFaceValuesBase to FEValues; see
- * there for more documentation.
- *
- * This class is used for faces lying on a refinement edge. In this case, the
- * neighboring cell is refined. To be able to compute differences between
- * interior and exterior function values, the refinement of the neighboring
- * cell must be simulated on this cell. This is achieved by applying a
- * quadrature rule that simulates the refinement. The resulting data fields
- * are split up to reflect the refinement structure of the neighbor: a subface
- * number corresponds to the number of the child of the neighboring face.
- *
- * @ingroup feaccess
- */
-template <int dim, int spacedim = dim>
-class FESubfaceValues : public FEFaceValuesBase<dim, spacedim>
-{
-public:
-  /**
-   * Dimension in which this object operates.
-   */
-  static constexpr unsigned int dimension = dim;
-
-  /**
-   * Dimension of the space in which this object operates.
-   */
-  static constexpr unsigned int space_dimension = spacedim;
-
-  /**
-   * Dimension of the object over which we integrate. For the present class,
-   * this is equal to <code>dim-1</code>.
-   */
-  static constexpr unsigned int integral_dimension = dim - 1;
-
-  /**
-   * Constructor. Gets cell independent data from mapping and finite element
-   * objects, matching the quadrature rule and update flags.
-   */
-  FESubfaceValues(const Mapping<dim, spacedim> &      mapping,
-                  const FiniteElement<dim, spacedim> &fe,
-                  const Quadrature<dim - 1> &         face_quadrature,
-                  const UpdateFlags                   update_flags);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules.
-   *
-   * @note We require, in contrast to FEFaceValues, that the number of quadrature
-   *   rules in the collection is one.
-   */
-  FESubfaceValues(const Mapping<dim, spacedim> &      mapping,
-                  const FiniteElement<dim, spacedim> &fe,
-                  const hp::QCollection<dim - 1> &    face_quadrature,
-                  const UpdateFlags                   update_flags);
-
-  /**
-   * Constructor. This constructor is equivalent to the other one except that
-   * it makes the object use a $Q_1$ mapping (i.e., an object of type
-   * MappingQ(1)) implicitly.
-   */
-  FESubfaceValues(const FiniteElement<dim, spacedim> &fe,
-                  const Quadrature<dim - 1> &         face_quadrature,
-                  const UpdateFlags                   update_flags);
-
-  /**
-   * Like the function above, but taking a collection of quadrature rules.
-   *
-   * @note We require, in contrast to FEFaceValues, that the number of quadrature
-   *   rules in the collection is one.
-   */
-  FESubfaceValues(const FiniteElement<dim, spacedim> &fe,
-                  const hp::QCollection<dim - 1> &    face_quadrature,
-                  const UpdateFlags                   update_flags);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the given cell
-   * of type "iterator into a DoFHandler object", and the finite element
-   * associated with this object. It is assumed that the finite element used
-   * by the given cell is also the one used by this FESubfaceValues object.
-   */
-  template <bool level_dof_access>
-  void
-  reinit(
-    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
-    const unsigned int face_no,
-    const unsigned int subface_no);
-
-  /**
-   * Alternative reinitialization function that takes, as arguments, iterators
-   * to the face and subface instead of their numbers.
-   */
-  template <bool level_dof_access>
-  void
-  reinit(
-    const TriaIterator<DoFCellAccessor<dim, spacedim, level_dof_access>> &cell,
-    const typename Triangulation<dim, spacedim>::face_iterator &          face,
-    const typename Triangulation<dim, spacedim>::face_iterator &subface);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the given
-   * subface on a given cell of type "iterator into a Triangulation object", and
-   * the given finite element. Since iterators into a triangulation alone only
-   * convey information about the geometry of a cell, but not about degrees of
-   * freedom possibly associated with this cell, you will not be able to call
-   * some functions of this class if they need information about degrees of
-   * freedom. These functions are, above all, the
-   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
-   * functions. If you want to call these functions, you have to call the @p
-   * reinit variants that take iterators into DoFHandler or other DoF handler
-   * type objects.
-   */
-  void
-  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
-         const unsigned int                                          face_no,
-         const unsigned int subface_no);
-
-  /**
-   * Reinitialize the gradients, Jacobi determinants, etc for the given
-   * subface on a given cell of type "iterator into a Triangulation object", and
-   * the given finite element. Since iterators into a triangulation alone only
-   * convey information about the geometry of a cell, but not about degrees of
-   * freedom possibly associated with this cell, you will not be able to call
-   * some functions of this class if they need information about degrees of
-   * freedom. These functions are, above all, the
-   * <tt>get_function_value/gradients/hessians/third_derivatives</tt>
-   * functions. If you want to call these functions, you have to call the @p
-   * reinit variants that take iterators into DoFHandler or other DoF handler
-   * type objects.
-   *
-   * This does the same thing as the previous function but takes iterators
-   * instead of numbers as arguments.
-   *
-   * @note @p face and @p subface must correspond to a face (and a subface of
-   * that face) of @p cell.
-   */
-  void
-  reinit(const typename Triangulation<dim, spacedim>::cell_iterator &cell,
-         const typename Triangulation<dim, spacedim>::face_iterator &face,
-         const typename Triangulation<dim, spacedim>::face_iterator &subface);
-
-  /**
-   * Return a reference to this very object.
-   *
-   * Though it seems that it is not very useful, this function is there to
-   * provide capability to the hp::FEValues class, in which case it provides
-   * the FEValues object for the present cell (remember that for hp-finite
-   * elements, the actual FE object used may change from cell to cell, so we
-   * also need different FEValues objects for different cells; once you
-   * reinitialize the hp::FEValues object for a specific cell, it retrieves
-   * the FEValues object for the FE on that cell and returns it through a
-   * function of the same name as this one; this function here therefore only
-   * provides the same interface so that one can templatize on FEValues and
-   * hp::FEValues).
-   */
-  const FESubfaceValues<dim, spacedim> &
-  get_present_fe_values() const;
-
-  /**
-   * @todo Document this
-   *
-   * @ingroup Exceptions
-   */
-  DeclException0(ExcReinitCalledWithBoundaryFace);
-
-  /**
-   * @todo Document this
-   *
-   * @ingroup Exceptions
-   */
-  DeclException0(ExcFaceHasNoSubfaces);
-
-private:
-  /**
-   * Do work common to the two constructors.
-   */
-  void
-  initialize(const UpdateFlags update_flags);
-
-  /**
-   * The reinit() functions do only that part of the work that requires
-   * knowledge of the type of iterator. After setting present_cell(), they
-   * pass on to this function, which does the real work, and which is
-   * independent of the actual type of the cell iterator.
-   */
-  void
-  do_reinit(const unsigned int face_no, const unsigned int subface_no);
-};
-
-
-#ifndef DOXYGEN
-
-
-/*------------------------ Inline functions: namespace FEValuesViews --------*/
-
-namespace FEValuesViews
-{
-  template <int dim, int spacedim>
-  inline typename Scalar<dim, spacedim>::value_type
-  Scalar<dim, spacedim>::value(const unsigned int shape_function,
-                               const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(
-      fe_values->update_flags & update_values,
-      ((typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-        "update_values"))));
-
-    // an adaptation of the FEValuesBase::shape_value_component function
-    // except that here we know the component as fixed and we have
-    // pre-computed and cached a bunch of information. See the comments there.
-    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
-      return fe_values->finite_element_output.shape_values(
-        shape_function_data[shape_function].row_index, q_point);
-    else
-      return 0;
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Scalar<dim, spacedim>::gradient_type
-  Scalar<dim, spacedim>::gradient(const unsigned int shape_function,
-                                  const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    // an adaptation of the FEValuesBase::shape_grad_component
-    // function except that here we know the component as fixed and we have
-    // pre-computed and cached a bunch of information. See the comments there.
-    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
-      return fe_values->finite_element_output
-        .shape_gradients[shape_function_data[shape_function].row_index]
-                        [q_point];
-    else
-      return gradient_type();
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Scalar<dim, spacedim>::hessian_type
-  Scalar<dim, spacedim>::hessian(const unsigned int shape_function,
-                                 const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-
-    // an adaptation of the FEValuesBase::shape_hessian_component
-    // function except that here we know the component as fixed and we have
-    // pre-computed and cached a bunch of information. See the comments there.
-    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
-      return fe_values->finite_element_output
-        .shape_hessians[shape_function_data[shape_function].row_index][q_point];
-    else
-      return hessian_type();
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Scalar<dim, spacedim>::third_derivative_type
-  Scalar<dim, spacedim>::third_derivative(const unsigned int shape_function,
-                                          const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_3rd_derivatives,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_3rd_derivatives")));
-
-    // an adaptation of the FEValuesBase::shape_3rdderivative_component
-    // function except that here we know the component as fixed and we have
-    // pre-computed and cached a bunch of information. See the comments there.
-    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
-      return fe_values->finite_element_output
-        .shape_3rd_derivatives[shape_function_data[shape_function].row_index]
-                              [q_point];
-    else
-      return third_derivative_type();
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::value_type
-  Vector<dim, spacedim>::value(const unsigned int shape_function,
-                               const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-    if (snc == -2)
-      return value_type();
-    else if (snc != -1)
-      {
-        value_type return_value;
-        return_value[shape_function_data[shape_function]
-                       .single_nonzero_component_index] =
-          fe_values->finite_element_output.shape_values(snc, q_point);
-        return return_value;
-      }
-    else
-      {
-        value_type return_value;
-        for (unsigned int d = 0; d < dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value[d] = fe_values->finite_element_output.shape_values(
-              shape_function_data[shape_function].row_index[d], q_point);
-
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::gradient_type
-  Vector<dim, spacedim>::gradient(const unsigned int shape_function,
-                                  const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-    if (snc == -2)
-      return gradient_type();
-    else if (snc != -1)
-      {
-        gradient_type return_value;
-        return_value[shape_function_data[shape_function]
-                       .single_nonzero_component_index] =
-          fe_values->finite_element_output.shape_gradients[snc][q_point];
-        return return_value;
-      }
-    else
-      {
-        gradient_type return_value;
-        for (unsigned int d = 0; d < dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value[d] =
-              fe_values->finite_element_output.shape_gradients
-                [shape_function_data[shape_function].row_index[d]][q_point];
-
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::divergence_type
-  Vector<dim, spacedim>::divergence(const unsigned int shape_function,
-                                    const unsigned int q_point) const
-  {
-    // this function works like in the case above
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-    if (snc == -2)
-      return divergence_type();
-    else if (snc != -1)
-      return fe_values->finite_element_output
-        .shape_gradients[snc][q_point][shape_function_data[shape_function]
-                                         .single_nonzero_component_index];
-    else
-      {
-        divergence_type return_value = 0;
-        for (unsigned int d = 0; d < dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value +=
-              fe_values->finite_element_output.shape_gradients
-                [shape_function_data[shape_function].row_index[d]][q_point][d];
-
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::curl_type
-  Vector<dim, spacedim>::curl(const unsigned int shape_function,
-                              const unsigned int q_point) const
-  {
-    // this function works like in the case above
-
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-
-    if (snc == -2)
-      return curl_type();
-
-    else
-      switch (dim)
-        {
-          case 1:
-            {
-              Assert(false,
-                     ExcMessage(
-                       "Computing the curl in 1d is not a useful operation"));
-              return curl_type();
-            }
-
-          case 2:
-            {
-              if (snc != -1)
-                {
-                  curl_type return_value;
-
-                  // the single nonzero component can only be zero or one in 2d
-                  if (shape_function_data[shape_function]
-                        .single_nonzero_component_index == 0)
-                    return_value[0] =
-                      -1.0 * fe_values->finite_element_output
-                               .shape_gradients[snc][q_point][1];
-                  else
-                    return_value[0] = fe_values->finite_element_output
-                                        .shape_gradients[snc][q_point][0];
-
-                  return return_value;
-                }
-
-              else
-                {
-                  curl_type return_value;
-
-                  return_value[0] = 0.0;
-
-                  if (shape_function_data[shape_function]
-                        .is_nonzero_shape_function_component[0])
-                    return_value[0] -=
-                      fe_values->finite_element_output
-                        .shape_gradients[shape_function_data[shape_function]
-                                           .row_index[0]][q_point][1];
-
-                  if (shape_function_data[shape_function]
-                        .is_nonzero_shape_function_component[1])
-                    return_value[0] +=
-                      fe_values->finite_element_output
-                        .shape_gradients[shape_function_data[shape_function]
-                                           .row_index[1]][q_point][0];
-
-                  return return_value;
-                }
-            }
-
-          case 3:
-            {
-              if (snc != -1)
-                {
-                  curl_type return_value;
-
-                  switch (shape_function_data[shape_function]
-                            .single_nonzero_component_index)
-                    {
-                      case 0:
-                        {
-                          return_value[0] = 0;
-                          return_value[1] = fe_values->finite_element_output
-                                              .shape_gradients[snc][q_point][2];
-                          return_value[2] =
-                            -1.0 * fe_values->finite_element_output
-                                     .shape_gradients[snc][q_point][1];
-                          return return_value;
-                        }
-
-                      case 1:
-                        {
-                          return_value[0] =
-                            -1.0 * fe_values->finite_element_output
-                                     .shape_gradients[snc][q_point][2];
-                          return_value[1] = 0;
-                          return_value[2] = fe_values->finite_element_output
-                                              .shape_gradients[snc][q_point][0];
-                          return return_value;
-                        }
-
-                      default:
-                        {
-                          return_value[0] = fe_values->finite_element_output
-                                              .shape_gradients[snc][q_point][1];
-                          return_value[1] =
-                            -1.0 * fe_values->finite_element_output
-                                     .shape_gradients[snc][q_point][0];
-                          return_value[2] = 0;
-                          return return_value;
-                        }
-                    }
-                }
-
-              else
-                {
-                  curl_type return_value;
-
-                  for (unsigned int i = 0; i < dim; ++i)
-                    return_value[i] = 0.0;
-
-                  if (shape_function_data[shape_function]
-                        .is_nonzero_shape_function_component[0])
-                    {
-                      return_value[1] +=
-                        fe_values->finite_element_output
-                          .shape_gradients[shape_function_data[shape_function]
-                                             .row_index[0]][q_point][2];
-                      return_value[2] -=
-                        fe_values->finite_element_output
-                          .shape_gradients[shape_function_data[shape_function]
-                                             .row_index[0]][q_point][1];
-                    }
-
-                  if (shape_function_data[shape_function]
-                        .is_nonzero_shape_function_component[1])
-                    {
-                      return_value[0] -=
-                        fe_values->finite_element_output
-                          .shape_gradients[shape_function_data[shape_function]
-                                             .row_index[1]][q_point][2];
-                      return_value[2] +=
-                        fe_values->finite_element_output
-                          .shape_gradients[shape_function_data[shape_function]
-                                             .row_index[1]][q_point][0];
-                    }
-
-                  if (shape_function_data[shape_function]
-                        .is_nonzero_shape_function_component[2])
-                    {
-                      return_value[0] +=
-                        fe_values->finite_element_output
-                          .shape_gradients[shape_function_data[shape_function]
-                                             .row_index[2]][q_point][1];
-                      return_value[1] -=
-                        fe_values->finite_element_output
-                          .shape_gradients[shape_function_data[shape_function]
-                                             .row_index[2]][q_point][0];
-                    }
-
-                  return return_value;
-                }
-            }
-        }
-    // should not end up here
-    Assert(false, ExcInternalError());
-    return curl_type();
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::hessian_type
-  Vector<dim, spacedim>::hessian(const unsigned int shape_function,
-                                 const unsigned int q_point) const
-  {
-    // this function works like in the case above
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-    if (snc == -2)
-      return hessian_type();
-    else if (snc != -1)
-      {
-        hessian_type return_value;
-        return_value[shape_function_data[shape_function]
-                       .single_nonzero_component_index] =
-          fe_values->finite_element_output.shape_hessians[snc][q_point];
-        return return_value;
-      }
-    else
-      {
-        hessian_type return_value;
-        for (unsigned int d = 0; d < dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value[d] =
-              fe_values->finite_element_output.shape_hessians
-                [shape_function_data[shape_function].row_index[d]][q_point];
-
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::third_derivative_type
-  Vector<dim, spacedim>::third_derivative(const unsigned int shape_function,
-                                          const unsigned int q_point) const
-  {
-    // this function works like in the case above
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_3rd_derivatives,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_3rd_derivatives")));
-
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-    if (snc == -2)
-      return third_derivative_type();
-    else if (snc != -1)
-      {
-        third_derivative_type return_value;
-        return_value[shape_function_data[shape_function]
-                       .single_nonzero_component_index] =
-          fe_values->finite_element_output.shape_3rd_derivatives[snc][q_point];
-        return return_value;
-      }
-    else
-      {
-        third_derivative_type return_value;
-        for (unsigned int d = 0; d < dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value[d] =
-              fe_values->finite_element_output.shape_3rd_derivatives
-                [shape_function_data[shape_function].row_index[d]][q_point];
-
-        return return_value;
-      }
-  }
-
-
-
-  namespace internal
-  {
-    /**
-     * Return the symmetrized version of a tensor whose n'th row equals the
-     * second argument, with all other rows equal to zero.
-     */
-    inline dealii::SymmetricTensor<2, 1>
-    symmetrize_single_row(const unsigned int n, const dealii::Tensor<1, 1> &t)
-    {
-      AssertIndexRange(n, 1);
-      (void)n;
-
-      return {{t[0]}};
-    }
-
-
-
-    inline dealii::SymmetricTensor<2, 2>
-    symmetrize_single_row(const unsigned int n, const dealii::Tensor<1, 2> &t)
-    {
-      switch (n)
-        {
-          case 0:
-            {
-              return {{t[0], 0, t[1] / 2}};
-            }
-          case 1:
-            {
-              return {{0, t[1], t[0] / 2}};
-            }
-          default:
-            {
-              AssertIndexRange(n, 2);
-              return {};
-            }
-        }
-    }
-
-
-
-    inline dealii::SymmetricTensor<2, 3>
-    symmetrize_single_row(const unsigned int n, const dealii::Tensor<1, 3> &t)
-    {
-      switch (n)
-        {
-          case 0:
-            {
-              return {{t[0], 0, 0, t[1] / 2, t[2] / 2, 0}};
-            }
-          case 1:
-            {
-              return {{0, t[1], 0, t[0] / 2, 0, t[2] / 2}};
-            }
-          case 2:
-            {
-              return {{0, 0, t[2], 0, t[0] / 2, t[1] / 2}};
-            }
-          default:
-            {
-              AssertIndexRange(n, 3);
-              return {};
-            }
-        }
-    }
-  } // namespace internal
-
-
-
-  template <int dim, int spacedim>
-  inline typename Vector<dim, spacedim>::symmetric_gradient_type
-  Vector<dim, spacedim>::symmetric_gradient(const unsigned int shape_function,
-                                            const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    // same as for the scalar case except that we have one more index
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-    if (snc == -2)
-      return symmetric_gradient_type();
-    else if (snc != -1)
-      return internal::symmetrize_single_row(
-        shape_function_data[shape_function].single_nonzero_component_index,
-        fe_values->finite_element_output.shape_gradients[snc][q_point]);
-    else
-      {
-        gradient_type return_value;
-        for (unsigned int d = 0; d < dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value[d] =
-              fe_values->finite_element_output.shape_gradients
-                [shape_function_data[shape_function].row_index[d]][q_point];
-
-        return symmetrize(return_value);
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename SymmetricTensor<2, dim, spacedim>::value_type
-  SymmetricTensor<2, dim, spacedim>::value(const unsigned int shape_function,
-                                           const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-
-    // similar to the vector case where we have more then one index and we need
-    // to convert between unrolled and component indexing for tensors
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-
-    if (snc == -2)
-      {
-        // shape function is zero for the selected components
-        return value_type();
-      }
-    else if (snc != -1)
-      {
-        value_type         return_value;
-        const unsigned int comp =
-          shape_function_data[shape_function].single_nonzero_component_index;
-        return_value[value_type::unrolled_to_component_indices(comp)] =
-          fe_values->finite_element_output.shape_values(snc, q_point);
-        return return_value;
-      }
-    else
-      {
-        value_type return_value;
-        for (unsigned int d = 0; d < value_type::n_independent_components; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            return_value[value_type::unrolled_to_component_indices(d)] =
-              fe_values->finite_element_output.shape_values(
-                shape_function_data[shape_function].row_index[d], q_point);
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename SymmetricTensor<2, dim, spacedim>::divergence_type
-  SymmetricTensor<2, dim, spacedim>::divergence(
-    const unsigned int shape_function,
-    const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-
-    if (snc == -2)
-      {
-        // shape function is zero for the selected components
-        return divergence_type();
-      }
-    else if (snc != -1)
-      {
-        // we have a single non-zero component when the symmetric tensor is
-        // represented in unrolled form. this implies we potentially have
-        // two non-zero components when represented in component form!  we
-        // will only have one non-zero entry if the non-zero component lies on
-        // the diagonal of the tensor.
-        //
-        // the divergence of a second-order tensor is a first order tensor.
-        //
-        // assume the second-order tensor is A with components A_{ij}.  then
-        // A_{ij} = A_{ji} and there is only one (if diagonal) or two non-zero
-        // entries in the tensorial representation.  define the
-        // divergence as:
-        // b_i \dealcoloneq \dfrac{\partial phi_{ij}}{\partial x_j}.
-        // (which is incidentally also
-        // b_j \dealcoloneq \dfrac{\partial phi_{ij}}{\partial x_i}).
-        // In both cases, a sum is implied.
-        //
-        // Now, we know the nonzero component in unrolled form: it is indicated
-        // by 'snc'. we can figure out which tensor components belong to this:
-        const unsigned int comp =
-          shape_function_data[shape_function].single_nonzero_component_index;
-        const unsigned int ii =
-          value_type::unrolled_to_component_indices(comp)[0];
-        const unsigned int jj =
-          value_type::unrolled_to_component_indices(comp)[1];
-
-        // given the form of the divergence above, if ii=jj there is only a
-        // single nonzero component of the full tensor and the gradient
-        // equals
-        // b_ii \dealcoloneq \dfrac{\partial phi_{ii,ii}}{\partial x_ii}.
-        // all other entries of 'b' are zero
-        //
-        // on the other hand, if ii!=jj, then there are two nonzero entries in
-        // the full tensor and
-        // b_ii \dealcoloneq \dfrac{\partial phi_{ii,jj}}{\partial x_ii}.
-        // b_jj \dealcoloneq \dfrac{\partial phi_{ii,jj}}{\partial x_jj}.
-        // again, all other entries of 'b' are zero
-        const dealii::Tensor<1, spacedim> &phi_grad =
-          fe_values->finite_element_output.shape_gradients[snc][q_point];
-
-        divergence_type return_value;
-        return_value[ii] = phi_grad[jj];
-
-        if (ii != jj)
-          return_value[jj] = phi_grad[ii];
-
-        return return_value;
-      }
-    else
-      {
-        Assert(false, ExcNotImplemented());
-        divergence_type return_value;
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Tensor<2, dim, spacedim>::value_type
-  Tensor<2, dim, spacedim>::value(const unsigned int shape_function,
-                                  const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-
-    // similar to the vector case where we have more then one index and we need
-    // to convert between unrolled and component indexing for tensors
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-
-    if (snc == -2)
-      {
-        // shape function is zero for the selected components
-        return value_type();
-      }
-    else if (snc != -1)
-      {
-        value_type         return_value;
-        const unsigned int comp =
-          shape_function_data[shape_function].single_nonzero_component_index;
-        const TableIndices<2> indices =
-          dealii::Tensor<2, spacedim>::unrolled_to_component_indices(comp);
-        return_value[indices] =
-          fe_values->finite_element_output.shape_values(snc, q_point);
-        return return_value;
-      }
-    else
-      {
-        value_type return_value;
-        for (unsigned int d = 0; d < dim * dim; ++d)
-          if (shape_function_data[shape_function]
-                .is_nonzero_shape_function_component[d])
-            {
-              const TableIndices<2> indices =
-                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(d);
-              return_value[indices] =
-                fe_values->finite_element_output.shape_values(
-                  shape_function_data[shape_function].row_index[d], q_point);
-            }
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Tensor<2, dim, spacedim>::divergence_type
-  Tensor<2, dim, spacedim>::divergence(const unsigned int shape_function,
-                                       const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-
-    if (snc == -2)
-      {
-        // shape function is zero for the selected components
-        return divergence_type();
-      }
-    else if (snc != -1)
-      {
-        // we have a single non-zero component when the tensor is
-        // represented in unrolled form.
-        //
-        // the divergence of a second-order tensor is a first order tensor.
-        //
-        // assume the second-order tensor is A with components A_{ij},
-        // then divergence is d_i := \frac{\partial A_{ij}}{\partial x_j}
-        //
-        // Now, we know the nonzero component in unrolled form: it is indicated
-        // by 'snc'. we can figure out which tensor components belong to this:
-        const unsigned int comp =
-          shape_function_data[shape_function].single_nonzero_component_index;
-        const TableIndices<2> indices =
-          dealii::Tensor<2, spacedim>::unrolled_to_component_indices(comp);
-        const unsigned int ii = indices[0];
-        const unsigned int jj = indices[1];
-
-        const dealii::Tensor<1, spacedim> &phi_grad =
-          fe_values->finite_element_output.shape_gradients[snc][q_point];
-
-        divergence_type return_value;
-        // note that we contract \nabla from the right
-        return_value[ii] = phi_grad[jj];
-
-        return return_value;
-      }
-    else
-      {
-        Assert(false, ExcNotImplemented());
-        divergence_type return_value;
-        return return_value;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  inline typename Tensor<2, dim, spacedim>::gradient_type
-  Tensor<2, dim, spacedim>::gradient(const unsigned int shape_function,
-                                     const unsigned int q_point) const
-  {
-    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-
-    const int snc =
-      shape_function_data[shape_function].single_nonzero_component;
-
-    if (snc == -2)
-      {
-        // shape function is zero for the selected components
-        return gradient_type();
-      }
-    else if (snc != -1)
-      {
-        // we have a single non-zero component when the tensor is
-        // represented in unrolled form.
-        //
-        // the gradient of a second-order tensor is a third order tensor.
-        //
-        // assume the second-order tensor is A with components A_{ij},
-        // then gradient is B_{ijk} := \frac{\partial A_{ij}}{\partial x_k}
-        //
-        // Now, we know the nonzero component in unrolled form: it is indicated
-        // by 'snc'. we can figure out which tensor components belong to this:
-        const unsigned int comp =
-          shape_function_data[shape_function].single_nonzero_component_index;
-        const TableIndices<2> indices =
-          dealii::Tensor<2, spacedim>::unrolled_to_component_indices(comp);
-        const unsigned int ii = indices[0];
-        const unsigned int jj = indices[1];
-
-        const dealii::Tensor<1, spacedim> &phi_grad =
-          fe_values->finite_element_output.shape_gradients[snc][q_point];
-
-        gradient_type return_value;
-        return_value[ii][jj] = phi_grad;
-
-        return return_value;
-      }
-    else
-      {
-        Assert(false, ExcNotImplemented());
-        gradient_type return_value;
-        return return_value;
-      }
-  }
-
-} // namespace FEValuesViews
-
-
-
-/*---------------------- Inline functions: FEValuesBase ---------------------*/
-
-
-
-template <int dim, int spacedim>
-template <bool lda>
-inline FEValuesBase<dim, spacedim>::CellIteratorContainer::
-  CellIteratorContainer(
-    const TriaIterator<DoFCellAccessor<dim, spacedim, lda>> &cell)
-  : initialized(true)
-  , cell(cell)
-  , dof_handler(&cell->get_dof_handler())
-  , level_dof_access(lda)
-{}
-
-
-
-template <int dim, int spacedim>
-inline const FEValuesViews::Scalar<dim, spacedim> &
-FEValuesBase<dim, spacedim>::operator[](
-  const FEValuesExtractors::Scalar &scalar) const
-{
-  AssertIndexRange(scalar.component, fe_values_views_cache.scalars.size());
-
-  return fe_values_views_cache.scalars[scalar.component];
-}
-
-
-
-template <int dim, int spacedim>
-inline const FEValuesViews::Vector<dim, spacedim> &
-FEValuesBase<dim, spacedim>::operator[](
-  const FEValuesExtractors::Vector &vector) const
-{
-  AssertIndexRange(vector.first_vector_component,
-                   fe_values_views_cache.vectors.size());
-
-  return fe_values_views_cache.vectors[vector.first_vector_component];
-}
-
-
-
-template <int dim, int spacedim>
-inline const FEValuesViews::SymmetricTensor<2, dim, spacedim> &
-FEValuesBase<dim, spacedim>::operator[](
-  const FEValuesExtractors::SymmetricTensor<2> &tensor) const
-{
-  Assert(
-    tensor.first_tensor_component <
-      fe_values_views_cache.symmetric_second_order_tensors.size(),
-    ExcIndexRange(tensor.first_tensor_component,
-                  0,
-                  fe_values_views_cache.symmetric_second_order_tensors.size()));
-
-  return fe_values_views_cache
-    .symmetric_second_order_tensors[tensor.first_tensor_component];
-}
-
-
-
-template <int dim, int spacedim>
-inline const FEValuesViews::Tensor<2, dim, spacedim> &
-FEValuesBase<dim, spacedim>::operator[](
-  const FEValuesExtractors::Tensor<2> &tensor) const
-{
-  AssertIndexRange(tensor.first_tensor_component,
-                   fe_values_views_cache.second_order_tensors.size());
-
-  return fe_values_views_cache
-    .second_order_tensors[tensor.first_tensor_component];
-}
-
-
-
-template <int dim, int spacedim>
-inline const double &
-FEValuesBase<dim, spacedim>::shape_value(const unsigned int i,
-                                         const unsigned int q_point) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // if the entire FE is primitive,
-  // then we can take a short-cut:
-  if (fe->is_primitive())
-    return this->finite_element_output.shape_values(i, q_point);
-  else
-    {
-      // otherwise, use the mapping
-      // between shape function
-      // numbers and rows. note that
-      // by the assertions above, we
-      // know that this particular
-      // shape function is primitive,
-      // so we can call
-      // system_to_component_index
-      const unsigned int row =
-        this->finite_element_output
-          .shape_function_to_row_table[i * fe->n_components() +
-                                       fe->system_to_component_index(i).first];
-      return this->finite_element_output.shape_values(row, q_point);
-    }
-}
-
-
-
-template <int dim, int spacedim>
-inline double
-FEValuesBase<dim, spacedim>::shape_value_component(
-  const unsigned int i,
-  const unsigned int q_point,
-  const unsigned int component) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-  AssertIndexRange(component, fe->n_components());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  // check whether the shape function
-  // is non-zero at all within
-  // this component:
-  if (fe->get_nonzero_components(i)[component] == false)
-    return 0;
-
-  // look up the right row in the
-  // table and take the data from
-  // there
-  const unsigned int row =
-    this->finite_element_output
-      .shape_function_to_row_table[i * fe->n_components() + component];
-  return this->finite_element_output.shape_values(row, q_point);
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<1, spacedim> &
-FEValuesBase<dim, spacedim>::shape_grad(const unsigned int i,
-                                        const unsigned int q_point) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_gradients,
-         ExcAccessToUninitializedField("update_gradients"));
-  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // if the entire FE is primitive,
-  // then we can take a short-cut:
-  if (fe->is_primitive())
-    return this->finite_element_output.shape_gradients[i][q_point];
-  else
-    {
-      // otherwise, use the mapping
-      // between shape function
-      // numbers and rows. note that
-      // by the assertions above, we
-      // know that this particular
-      // shape function is primitive,
-      // so we can call
-      // system_to_component_index
-      const unsigned int row =
-        this->finite_element_output
-          .shape_function_to_row_table[i * fe->n_components() +
-                                       fe->system_to_component_index(i).first];
-      return this->finite_element_output.shape_gradients[row][q_point];
-    }
-}
-
-
-
-template <int dim, int spacedim>
-inline Tensor<1, spacedim>
-FEValuesBase<dim, spacedim>::shape_grad_component(
-  const unsigned int i,
-  const unsigned int q_point,
-  const unsigned int component) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_gradients,
-         ExcAccessToUninitializedField("update_gradients"));
-  AssertIndexRange(component, fe->n_components());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // check whether the shape function
-  // is non-zero at all within
-  // this component:
-  if (fe->get_nonzero_components(i)[component] == false)
-    return Tensor<1, spacedim>();
-
-  // look up the right row in the
-  // table and take the data from
-  // there
-  const unsigned int row =
-    this->finite_element_output
-      .shape_function_to_row_table[i * fe->n_components() + component];
-  return this->finite_element_output.shape_gradients[row][q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<2, spacedim> &
-FEValuesBase<dim, spacedim>::shape_hessian(const unsigned int i,
-                                           const unsigned int q_point) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // if the entire FE is primitive,
-  // then we can take a short-cut:
-  if (fe->is_primitive())
-    return this->finite_element_output.shape_hessians[i][q_point];
-  else
-    {
-      // otherwise, use the mapping
-      // between shape function
-      // numbers and rows. note that
-      // by the assertions above, we
-      // know that this particular
-      // shape function is primitive,
-      // so we can call
-      // system_to_component_index
-      const unsigned int row =
-        this->finite_element_output
-          .shape_function_to_row_table[i * fe->n_components() +
-                                       fe->system_to_component_index(i).first];
-      return this->finite_element_output.shape_hessians[row][q_point];
-    }
-}
-
-
-
-template <int dim, int spacedim>
-inline Tensor<2, spacedim>
-FEValuesBase<dim, spacedim>::shape_hessian_component(
-  const unsigned int i,
-  const unsigned int q_point,
-  const unsigned int component) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  AssertIndexRange(component, fe->n_components());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // check whether the shape function
-  // is non-zero at all within
-  // this component:
-  if (fe->get_nonzero_components(i)[component] == false)
-    return Tensor<2, spacedim>();
-
-  // look up the right row in the
-  // table and take the data from
-  // there
-  const unsigned int row =
-    this->finite_element_output
-      .shape_function_to_row_table[i * fe->n_components() + component];
-  return this->finite_element_output.shape_hessians[row][q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<3, spacedim> &
-FEValuesBase<dim, spacedim>::shape_3rd_derivative(
-  const unsigned int i,
-  const unsigned int q_point) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_3rd_derivatives,
-         ExcAccessToUninitializedField("update_3rd_derivatives"));
-  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // if the entire FE is primitive,
-  // then we can take a short-cut:
-  if (fe->is_primitive())
-    return this->finite_element_output.shape_3rd_derivatives[i][q_point];
-  else
-    {
-      // otherwise, use the mapping
-      // between shape function
-      // numbers and rows. note that
-      // by the assertions above, we
-      // know that this particular
-      // shape function is primitive,
-      // so we can call
-      // system_to_component_index
-      const unsigned int row =
-        this->finite_element_output
-          .shape_function_to_row_table[i * fe->n_components() +
-                                       fe->system_to_component_index(i).first];
-      return this->finite_element_output.shape_3rd_derivatives[row][q_point];
-    }
-}
-
-
-
-template <int dim, int spacedim>
-inline Tensor<3, spacedim>
-FEValuesBase<dim, spacedim>::shape_3rd_derivative_component(
-  const unsigned int i,
-  const unsigned int q_point,
-  const unsigned int component) const
-{
-  AssertIndexRange(i, fe->n_dofs_per_cell());
-  Assert(this->update_flags & update_3rd_derivatives,
-         ExcAccessToUninitializedField("update_3rd_derivatives"));
-  AssertIndexRange(component, fe->n_components());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  // check whether the shape function
-  // is non-zero at all within
-  // this component:
-  if (fe->get_nonzero_components(i)[component] == false)
-    return Tensor<3, spacedim>();
-
-  // look up the right row in the
-  // table and take the data from
-  // there
-  const unsigned int row =
-    this->finite_element_output
-      .shape_function_to_row_table[i * fe->n_components() + component];
-  return this->finite_element_output.shape_3rd_derivatives[row][q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const FiniteElement<dim, spacedim> &
-FEValuesBase<dim, spacedim>::get_fe() const
-{
-  return *fe;
-}
-
-
-
-template <int dim, int spacedim>
-inline const Mapping<dim, spacedim> &
-FEValuesBase<dim, spacedim>::get_mapping() const
-{
-  return *mapping;
-}
-
-
-
-template <int dim, int spacedim>
-inline UpdateFlags
-FEValuesBase<dim, spacedim>::get_update_flags() const
-{
-  return this->update_flags;
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<Point<spacedim>> &
-FEValuesBase<dim, spacedim>::get_quadrature_points() const
-{
-  Assert(this->update_flags & update_quadrature_points,
-         ExcAccessToUninitializedField("update_quadrature_points"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.quadrature_points;
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<double> &
-FEValuesBase<dim, spacedim>::get_JxW_values() const
-{
-  Assert(this->update_flags & update_JxW_values,
-         ExcAccessToUninitializedField("update_JxW_values"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.JxW_values;
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<DerivativeForm<1, dim, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobians() const
-{
-  Assert(this->update_flags & update_jacobians,
-         ExcAccessToUninitializedField("update_jacobians"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobians;
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<DerivativeForm<2, dim, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobian_grads() const
-{
-  Assert(this->update_flags & update_jacobian_grads,
-         ExcAccessToUninitializedField("update_jacobians_grads"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_grads;
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<3, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian_pushed_forward_grad(
-  const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobian_pushed_forward_grads,
-         ExcAccessToUninitializedField("update_jacobian_pushed_forward_grads"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_pushed_forward_grads[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<Tensor<3, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobian_pushed_forward_grads() const
-{
-  Assert(this->update_flags & update_jacobian_pushed_forward_grads,
-         ExcAccessToUninitializedField("update_jacobian_pushed_forward_grads"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_pushed_forward_grads;
-}
-
-
-
-template <int dim, int spacedim>
-inline const DerivativeForm<3, dim, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian_2nd_derivative(
-  const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobian_2nd_derivatives,
-         ExcAccessToUninitializedField("update_jacobian_2nd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_2nd_derivatives[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<DerivativeForm<3, dim, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobian_2nd_derivatives() const
-{
-  Assert(this->update_flags & update_jacobian_2nd_derivatives,
-         ExcAccessToUninitializedField("update_jacobian_2nd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_2nd_derivatives;
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<4, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian_pushed_forward_2nd_derivative(
-  const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobian_pushed_forward_2nd_derivatives,
-         ExcAccessToUninitializedField(
-           "update_jacobian_pushed_forward_2nd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_pushed_forward_2nd_derivatives[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<Tensor<4, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobian_pushed_forward_2nd_derivatives() const
-{
-  Assert(this->update_flags & update_jacobian_pushed_forward_2nd_derivatives,
-         ExcAccessToUninitializedField(
-           "update_jacobian_pushed_forward_2nd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_pushed_forward_2nd_derivatives;
-}
-
-
-
-template <int dim, int spacedim>
-inline const DerivativeForm<4, dim, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian_3rd_derivative(
-  const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobian_3rd_derivatives,
-         ExcAccessToUninitializedField("update_jacobian_3rd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_3rd_derivatives[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<DerivativeForm<4, dim, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobian_3rd_derivatives() const
-{
-  Assert(this->update_flags & update_jacobian_3rd_derivatives,
-         ExcAccessToUninitializedField("update_jacobian_3rd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_3rd_derivatives;
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<5, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian_pushed_forward_3rd_derivative(
-  const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobian_pushed_forward_3rd_derivatives,
-         ExcAccessToUninitializedField(
-           "update_jacobian_pushed_forward_3rd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_pushed_forward_3rd_derivatives[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<Tensor<5, spacedim>> &
-FEValuesBase<dim, spacedim>::get_jacobian_pushed_forward_3rd_derivatives() const
-{
-  Assert(this->update_flags & update_jacobian_pushed_forward_3rd_derivatives,
-         ExcAccessToUninitializedField(
-           "update_jacobian_pushed_forward_3rd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.jacobian_pushed_forward_3rd_derivatives;
-}
-
-
-
-template <int dim, int spacedim>
-inline const std::vector<DerivativeForm<1, spacedim, dim>> &
-FEValuesBase<dim, spacedim>::get_inverse_jacobians() const
-{
-  Assert(this->update_flags & update_inverse_jacobians,
-         ExcAccessToUninitializedField("update_inverse_jacobians"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  return this->mapping_output.inverse_jacobians;
-}
-
-
-
-template <int dim, int spacedim>
-inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-FEValuesBase<dim, spacedim>::dof_indices() const
-{
-  return {0U, dofs_per_cell};
-}
-
-
-
-template <int dim, int spacedim>
-inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-FEValuesBase<dim, spacedim>::dof_indices_starting_at(
-  const unsigned int start_dof_index) const
-{
-  Assert(start_dof_index <= dofs_per_cell,
-         ExcIndexRange(start_dof_index, 0, dofs_per_cell + 1));
-  return {start_dof_index, dofs_per_cell};
-}
-
-
-
-template <int dim, int spacedim>
-inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-FEValuesBase<dim, spacedim>::dof_indices_ending_at(
-  const unsigned int end_dof_index) const
-{
-  Assert(end_dof_index < dofs_per_cell,
-         ExcIndexRange(end_dof_index, 0, dofs_per_cell));
-  return {0U, end_dof_index + 1};
-}
-
-
-
-template <int dim, int spacedim>
-inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
-FEValuesBase<dim, spacedim>::quadrature_point_indices() const
-{
-  return {0U, n_quadrature_points};
-}
-
-
-
-template <int dim, int spacedim>
-inline const Point<spacedim> &
-FEValuesBase<dim, spacedim>::quadrature_point(const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_quadrature_points,
-         ExcAccessToUninitializedField("update_quadrature_points"));
-  AssertIndexRange(q_point, this->mapping_output.quadrature_points.size());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  return this->mapping_output.quadrature_points[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline double
-FEValuesBase<dim, spacedim>::JxW(const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_JxW_values,
-         ExcAccessToUninitializedField("update_JxW_values"));
-  AssertIndexRange(q_point, this->mapping_output.JxW_values.size());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  return this->mapping_output.JxW_values[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const DerivativeForm<1, dim, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian(const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobians,
-         ExcAccessToUninitializedField("update_jacobians"));
-  AssertIndexRange(q_point, this->mapping_output.jacobians.size());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  return this->mapping_output.jacobians[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const DerivativeForm<2, dim, spacedim> &
-FEValuesBase<dim, spacedim>::jacobian_grad(const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_jacobian_grads,
-         ExcAccessToUninitializedField("update_jacobians_grads"));
-  AssertIndexRange(q_point, this->mapping_output.jacobian_grads.size());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  return this->mapping_output.jacobian_grads[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const DerivativeForm<1, spacedim, dim> &
-FEValuesBase<dim, spacedim>::inverse_jacobian(const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_inverse_jacobians,
-         ExcAccessToUninitializedField("update_inverse_jacobians"));
-  AssertIndexRange(q_point, this->mapping_output.inverse_jacobians.size());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  return this->mapping_output.inverse_jacobians[q_point];
-}
-
-
-
-template <int dim, int spacedim>
-inline const Tensor<1, spacedim> &
-FEValuesBase<dim, spacedim>::normal_vector(const unsigned int q_point) const
-{
-  Assert(this->update_flags & update_normal_vectors,
-         (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-           "update_normal_vectors")));
-  AssertIndexRange(q_point, this->mapping_output.normal_vectors.size());
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  return this->mapping_output.normal_vectors[q_point];
-}
 
+#ifndef DOXYGEN
 
 
 /*--------------------- Inline functions: FEValues --------------------------*/
diff --git a/include/deal.II/fe/fe_values_base.h b/include/deal.II/fe/fe_values_base.h
new file mode 100644 (file)
index 0000000..82e593e
--- /dev/null
@@ -0,0 +1,2429 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2023 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_fe_values_base_h
+#define dealii_fe_values_base_h
+
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/derivative_form.h>
+#include <deal.II/base/exceptions.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/quadrature.h>
+#include <deal.II/base/std_cxx20/iota_view.h>
+#include <deal.II/base/subscriptor.h>
+#include <deal.II/base/symmetric_tensor.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe.h>
+#include <deal.II/fe/fe_update_flags.h>
+#include <deal.II/fe/fe_values_extractors.h>
+#include <deal.II/fe/fe_values_views.h>
+#include <deal.II/fe/mapping.h>
+#include <deal.II/fe/mapping_related_data.h>
+
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/hp/q_collection.h>
+
+#include <deal.II/lac/read_vector.h>
+
+#include <algorithm>
+#include <memory>
+#include <type_traits>
+
+DEAL_II_NAMESPACE_OPEN
+
+/**
+ * FEValues, FEFaceValues and FESubfaceValues objects are interfaces to finite
+ * element and mapping classes on the one hand side, to cells and quadrature
+ * rules on the other side. They allow to evaluate values or derivatives of
+ * shape functions at the quadrature points of a quadrature formula when
+ * projected by a mapping from the unit cell onto a cell in real space. The
+ * reason for this abstraction is possible optimization: Depending on the type
+ * of finite element and mapping, some values can be computed once on the unit
+ * cell. Others must be computed on each cell, but maybe computation of
+ * several values at the same time offers ways for optimization. Since this
+ * interplay may be complex and depends on the actual finite element, it
+ * cannot be left to the applications programmer.
+ *
+ * FEValues, FEFaceValues and FESubfaceValues provide only data handling:
+ * computations are left to objects of type Mapping and FiniteElement. These
+ * provide functions <tt>get_*_data</tt> and <tt>fill_*_values</tt> which are
+ * called by the constructor and <tt>reinit</tt> functions of
+ * <tt>FEValues*</tt>, respectively.
+ *
+ * <h3>General usage</h3>
+ *
+ * Usually, an object of <tt>FEValues*</tt> is used in integration loops over
+ * all cells of a triangulation (or faces of cells). To take full advantage of
+ * the optimization features, it should be constructed before the loop so that
+ * information that does not depend on the location and shape of cells can be
+ * computed once and for all (this includes, for example, the values of shape
+ * functions at quadrature points for the most common elements: we can
+ * evaluate them on the unit cell and they will be the same when mapped to the
+ * real cell). Then, in the loop over all cells, it must be re-initialized for
+ * each grid cell to compute that part of the information that changes
+ * depending on the actual cell (for example, the gradient of shape functions
+ * equals the gradient on the unit cell -- which can be computed once and for
+ * all -- times the Jacobian matrix of the mapping between unit and real cell,
+ * which needs to be recomputed for each cell).
+ *
+ * A typical piece of code, adding up local contributions to the Laplace
+ * matrix looks like this:
+ *
+ * @code
+ * FEValues values (mapping, finite_element, quadrature, flags);
+ * for (const auto &cell : dof_handler.active_cell_iterators())
+ *   {
+ *     values.reinit(cell);
+ *     for (unsigned int q=0; q<quadrature.size(); ++q)
+ *       for (unsigned int i=0; i<finite_element.n_dofs_per_cell(); ++i)
+ *         for (unsigned int j=0; j<finite_element.n_dofs_per_cell(); ++j)
+ *           A(i,j) += fe_values.shape_value(i,q) *
+ *                     fe_values.shape_value(j,q) *
+ *                     fe_values.JxW(q);
+ *     ...
+ *   }
+ * @endcode
+ *
+ * The individual functions used here are described below. Note that by
+ * design, the order of quadrature points used inside the FEValues object is
+ * the same as defined by the quadrature formula passed to the constructor of
+ * the FEValues object above.
+ *
+ * <h3>Member functions</h3>
+ *
+ * The functions of this class fall into different categories:
+ * <ul>
+ * <li> shape_value(), shape_grad(), etc: return one of the values of this
+ * object at a time. These functions are inlined, so this is the suggested
+ * access to all finite element values. There should be no loss in performance
+ * with an optimizing compiler. If the finite element is vector valued, then
+ * these functions return the only non-zero component of the requested shape
+ * function. However, some finite elements have shape functions that have more
+ * than one non-zero component (we call them non-"primitive"), and in this
+ * case this set of functions will throw an exception since they cannot
+ * generate a useful result. Rather, use the next set of functions.
+ *
+ * <li> shape_value_component(), shape_grad_component(), etc: This is the same
+ * set of functions as above, except that for vector valued finite elements
+ * they return only one vector component. This is useful for elements of which
+ * shape functions have more than one non-zero component, since then the above
+ * functions cannot be used, and you have to walk over all (or only the non-
+ * zero) components of the shape function using this set of functions.
+ *
+ * <li> get_function_values(), get_function_gradients(), etc.: Compute a
+ * finite element function or its derivative in quadrature points.
+ *
+ * <li> reinit: initialize the FEValues object for a certain cell. This
+ * function is not in the present class but only in the derived classes and
+ * has a variable call syntax. See the docs for the derived classes for more
+ * information.
+ * </ul>
+ *
+ *
+ * <h3>Internals about the implementation</h3>
+ *
+ * The mechanisms by which this class work are discussed on the page on
+ * @ref UpdateFlags "Update flags"
+ * and about the
+ * @ref FE_vs_Mapping_vs_FEValues "How Mapping, FiniteElement, and FEValues work together".
+ *
+ *
+ * @ingroup feaccess
+ */
+template <int dim, int spacedim>
+class FEValuesBase : public Subscriptor
+{
+public:
+  /**
+   * Dimension in which this object operates.
+   */
+  static constexpr unsigned int dimension = dim;
+
+  /**
+   * Dimension of the space in which this object operates.
+   */
+  static constexpr unsigned int space_dimension = spacedim;
+
+  /**
+   * Number of quadrature points of the current object. Its value is
+   * initialized by the value of max_n_quadrature_points and is updated,
+   * e.g., if FEFaceValues::reinit() is called for a new cell/face.
+   *
+   * @note The default value equals to the value of max_n_quadrature_points.
+   */
+  const unsigned int n_quadrature_points;
+
+  /**
+   * Maximum number of quadrature points. This value might be different from
+   * n_quadrature_points, e.g., if a QCollection with different face quadrature
+   * rules has been passed to initialize FEFaceValues.
+   *
+   * This is mostly useful to initialize arrays to allocate the maximum amount
+   * of memory that may be used when re-sizing later on to a the current
+   * number of quadrature points given by n_quadrature_points.
+   */
+  const unsigned int max_n_quadrature_points;
+
+  /**
+   * Number of shape functions per cell. If we use this base class to evaluate
+   * a finite element on faces of cells, this is still the number of degrees
+   * of freedom per cell, not per face.
+   */
+  const unsigned int dofs_per_cell;
+
+
+  /**
+   * Constructor. Set up the array sizes with <tt>n_q_points</tt> quadrature
+   * points, <tt>dofs_per_cell</tt> trial functions per cell and with the
+   * given pattern to update the fields when the <tt>reinit</tt> function of
+   * the derived classes is called. The fields themselves are not set up, this
+   * must happen in the constructor of the derived class.
+   */
+  FEValuesBase(const unsigned int                  n_q_points,
+               const unsigned int                  dofs_per_cell,
+               const UpdateFlags                   update_flags,
+               const Mapping<dim, spacedim> &      mapping,
+               const FiniteElement<dim, spacedim> &fe);
+
+  /**
+   * The copy assignment is deleted since objects of this class are not
+   * copyable.
+   */
+  FEValuesBase &
+  operator=(const FEValuesBase &) = delete;
+
+  /**
+   * The copy constructor is deleted since objects of this class are not
+   * copyable.
+   */
+  FEValuesBase(const FEValuesBase &) = delete;
+
+  /**
+   * Destructor.
+   */
+  virtual ~FEValuesBase() override;
+
+
+  /// @name Access to shape function values
+  ///
+  /// These fields are filled by the finite element.
+  /** @{ */
+
+  /**
+   * Value of a shape function at a quadrature point on the cell, face or
+   * subface selected the last time the <tt>reinit</tt> function of the
+   * derived class was called.
+   *
+   * If the shape function is vector-valued, then this returns the only non-
+   * zero component. If the shape function has more than one non-zero
+   * component (i.e. it is not primitive), then throw an exception of type
+   * ExcShapeFunctionNotPrimitive. In that case, use the
+   * shape_value_component() function.
+   *
+   * @param i Number of the shape function $\varphi_i$ to be evaluated. Note
+   * that this number runs from zero to dofs_per_cell, even in the case of an
+   * FEFaceValues or FESubfaceValues object.
+   *
+   * @param q_point Number of the quadrature point at which function is to be
+   * evaluated
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  const double &
+  shape_value(const unsigned int i, const unsigned int q_point) const;
+
+  /**
+   * Compute one vector component of the value of a shape function at a
+   * quadrature point. If the finite element is scalar, then only component
+   * zero is allowed and the return value equals that of the shape_value()
+   * function. If the finite element is vector valued but all shape functions
+   * are primitive (i.e. they are non-zero in only one component), then the
+   * value returned by shape_value() equals that of this function for exactly
+   * one component. This function is therefore only of greater interest if the
+   * shape function is not primitive, but then it is necessary since the other
+   * function cannot be used.
+   *
+   * @param i Number of the shape function $\varphi_i$ to be evaluated.
+   *
+   * @param q_point Number of the quadrature point at which function is to be
+   * evaluated.
+   *
+   * @param component vector component to be evaluated.
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  double
+  shape_value_component(const unsigned int i,
+                        const unsigned int q_point,
+                        const unsigned int component) const;
+
+  /**
+   * Compute the gradient of the <tt>i</tt>th shape function at the
+   * <tt>quadrature_point</tt>th quadrature point with respect to real cell
+   * coordinates.  If you want to get the derivative in one of the coordinate
+   * directions, use the appropriate function of the Tensor class to extract
+   * one component of the Tensor returned by this function. Since only a
+   * reference to the gradient's value is returned, there should be no major
+   * performance drawback.
+   *
+   * If the shape function is vector-valued, then this returns the only non-
+   * zero component. If the shape function has more than one non-zero
+   * component (i.e. it is not primitive), then it will throw an exception of
+   * type ExcShapeFunctionNotPrimitive. In that case, use the
+   * shape_grad_component() function.
+   *
+   * The same holds for the arguments of this function as for the
+   * shape_value() function.
+   *
+   * @param i Number of the shape function $\varphi_i$ to be evaluated.
+   *
+   * @param q_point Number of the quadrature point at which function
+   * is to be evaluated.
+   *
+   * @dealiiRequiresUpdateFlags{update_gradients}
+   */
+  const Tensor<1, spacedim> &
+  shape_grad(const unsigned int i, const unsigned int q_point) const;
+
+  /**
+   * Return one vector component of the gradient of a shape function at a
+   * quadrature point. If the finite element is scalar, then only component
+   * zero is allowed and the return value equals that of the shape_grad()
+   * function. If the finite element is vector valued but all shape functions
+   * are primitive (i.e. they are non-zero in only one component), then the
+   * value returned by shape_grad() equals that of this function for exactly
+   * one component. This function is therefore only of greater interest if the
+   * shape function is not primitive, but then it is necessary since the other
+   * function cannot be used.
+   *
+   * The same holds for the arguments of this function as for the
+   * shape_value_component() function.
+   *
+   * @dealiiRequiresUpdateFlags{update_gradients}
+   */
+  Tensor<1, spacedim>
+  shape_grad_component(const unsigned int i,
+                       const unsigned int q_point,
+                       const unsigned int component) const;
+
+  /**
+   * Second derivatives of the <tt>i</tt>th shape function at the
+   * <tt>q_point</tt>th quadrature point with respect to real cell
+   * coordinates. If you want to get the derivatives in one of the coordinate
+   * directions, use the appropriate function of the Tensor class to extract
+   * one component. Since only a reference to the hessian values is returned,
+   * there should be no major performance drawback.
+   *
+   * If the shape function is vector-valued, then this returns the only non-
+   * zero component. If the shape function has more than one non-zero
+   * component (i.e. it is not primitive), then throw an exception of type
+   * ExcShapeFunctionNotPrimitive. In that case, use the
+   * shape_hessian_component() function.
+   *
+   * The same holds for the arguments of this function as for the
+   * shape_value() function.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  const Tensor<2, spacedim> &
+  shape_hessian(const unsigned int i, const unsigned int q_point) const;
+
+  /**
+   * Return one vector component of the hessian of a shape function at a
+   * quadrature point. If the finite element is scalar, then only component
+   * zero is allowed and the return value equals that of the shape_hessian()
+   * function. If the finite element is vector valued but all shape functions
+   * are primitive (i.e. they are non-zero in only one component), then the
+   * value returned by shape_hessian() equals that of this function for
+   * exactly one component. This function is therefore only of greater
+   * interest if the shape function is not primitive, but then it is necessary
+   * since the other function cannot be used.
+   *
+   * The same holds for the arguments of this function as for the
+   * shape_value_component() function.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  Tensor<2, spacedim>
+  shape_hessian_component(const unsigned int i,
+                          const unsigned int q_point,
+                          const unsigned int component) const;
+
+  /**
+   * Third derivatives of the <tt>i</tt>th shape function at the
+   * <tt>q_point</tt>th quadrature point with respect to real cell
+   * coordinates. If you want to get the 3rd derivatives in one of the
+   * coordinate directions, use the appropriate function of the Tensor class
+   * to extract one component. Since only a reference to the 3rd derivative
+   * values is returned, there should be no major performance drawback.
+   *
+   * If the shape function is vector-valued, then this returns the only non-
+   * zero component. If the shape function has more than one non-zero
+   * component (i.e. it is not primitive), then throw an exception of type
+   * ExcShapeFunctionNotPrimitive. In that case, use the
+   * shape_3rdderivative_component() function.
+   *
+   * The same holds for the arguments of this function as for the
+   * shape_value() function.
+   *
+   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   */
+  const Tensor<3, spacedim> &
+  shape_3rd_derivative(const unsigned int i, const unsigned int q_point) const;
+
+  /**
+   * Return one vector component of the third derivative of a shape function
+   * at a quadrature point. If the finite element is scalar, then only
+   * component zero is allowed and the return value equals that of the
+   * shape_3rdderivative() function. If the finite element is vector valued
+   * but all shape functions are primitive (i.e. they are non-zero in only one
+   * component), then the value returned by shape_3rdderivative() equals that
+   * of this function for exactly one component. This function is therefore
+   * only of greater interest if the shape function is not primitive, but then
+   * it is necessary since the other function cannot be used.
+   *
+   * The same holds for the arguments of this function as for the
+   * shape_value_component() function.
+   *
+   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   */
+  Tensor<3, spacedim>
+  shape_3rd_derivative_component(const unsigned int i,
+                                 const unsigned int q_point,
+                                 const unsigned int component) const;
+
+  /** @} */
+  /// @name Access to values of global finite element fields
+  /** @{ */
+
+  /**
+   * Return the values of a finite element function at the quadrature points
+   * of the current cell, face, or subface (selected the last time the reinit()
+   * function was called). That is, if the first argument @p fe_function is a
+   * vector of nodal values of a finite element function $u_h(\mathbf x)$
+   * defined on a DoFHandler object, then the output vector (the second
+   * argument,
+   * @p values) is the vector of values $u_h(\mathbf x_q^K)$ where $x_q^K$ are
+   * the quadrature points on the current cell $K$.
+   * This function is first discussed in the Results
+   * section of step-4, and the related get_function_gradients() function
+   * is also used in step-15 along with numerous other
+   * tutorial programs.
+   *
+   * If the current cell is not active (i.e., it has children), then the finite
+   * element function is, strictly speaking, defined by shape functions
+   * that live on these child cells. Rather than evaluating the shape functions
+   * on the child cells, with the quadrature points defined on the current
+   * cell, this function first interpolates the finite element function to shape
+   * functions defined on the current cell, and then evaluates this interpolated
+   * function.
+   *
+   * This function may only be used if the finite element in use is a scalar
+   * one, i.e. has only one vector component.  To get values of multi-component
+   * elements, there is another get_function_values() below,
+   * returning a vector of vectors of results.
+   *
+   * @param[in] fe_function A vector of values that describes (globally) the
+   * finite element function that this function should evaluate at the
+   * quadrature points of the current cell.
+   *
+   * @param[out] values The values of the function specified by fe_function at
+   * the quadrature points of the current cell.  The object is assume to
+   * already have the correct size. The data type stored by this output vector
+   * must be what you get when you multiply the values of shape function times
+   * the type used to store the values of the unknowns $U_j$ of your finite
+   * element vector $U$ (represented by the @p fe_function argument). This
+   * happens to be equal to the type of the elements of the solution vector.
+   *
+   * @post <code>values[q]</code> will contain the value of the field
+   * described by fe_function at the $q$th quadrature point.
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  template <typename Number>
+  void
+  get_function_values(const ReadVector<Number> &fe_function,
+                      std::vector<Number> &     values) const;
+
+  /**
+   * This function does the same as the other get_function_values(), but
+   * applied to multi-component (vector-valued) elements. The meaning of the
+   * arguments is as explained there.
+   *
+   * @post <code>values[q]</code> is a vector of values of the field described
+   * by fe_function at the $q$th quadrature point. The size of the vector
+   * accessed by <code>values[q]</code> equals the number of components of the
+   * finite element, i.e. <code>values[q](c)</code> returns the value of the
+   * $c$th vector component at the $q$th quadrature point.
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  template <typename Number>
+  void
+  get_function_values(const ReadVector<Number> &   fe_function,
+                      std::vector<Vector<Number>> &values) const;
+
+  /**
+   * Generate function values from an arbitrary vector. This function
+   * does in essence the same as the first function of this name above,
+   * except that it does not make the assumption that the input vector
+   * corresponds to a DoFHandler that describes the unknowns of a finite
+   * element field (and for which we would then assume that
+   * `fe_function.size() == dof_handler.n_dofs()`). Rather, the nodal
+   * values corresponding to the current cell are elements of an otherwise
+   * arbitrary vector, and these elements are indexed by the second
+   * argument to this function. What the rest of the `fe_function` input
+   * argument corresponds to is of no consequence to this function.
+   *
+   * Given this, the function above corresponds to passing `fe_function`
+   * as first argument to the current function, and using the
+   * `local_dof_indices` array that results from the following call as
+   * second argument to the current function:
+   * @code
+   *   cell->get_dof_indices (local_dof_indices);
+   * @endcode
+   * (See DoFCellAccessor::get_dof_indices() for more information.)
+   *
+   * Likewise, the function above is equivalent to calling
+   * @code
+   *   cell->get_dof_values (fe_function, local_dof_values);
+   * @endcode
+   * and then calling the current function with `local_dof_values` as
+   * first argument, and an array with indices `{0,...,fe.dofs_per_cell-1}`
+   * as second argument.
+   *
+   * The point of the current function is that one sometimes wants to
+   * evaluate finite element functions at quadrature points with nodal
+   * values that are not stored in a global vector -- for example, one could
+   * modify these local values first, such as by applying a limiter
+   * or by ensuring that all nodal values are positive, before evaluating
+   * the finite element field that corresponds to these local values on the
+   * current cell. Another application is where one wants to postprocess
+   * the solution on a cell into a different finite element space on every
+   * cell, without actually creating a corresponding DoFHandler -- in that
+   * case, all one would compute is a local representation of that
+   * postprocessed function, characterized by its nodal values; this function
+   * then allows the evaluation of that representation at quadrature points.
+   *
+   * @param[in] fe_function A vector of nodal values. This vector can have
+   *   an arbitrary size, as long as all elements index by `indices` can
+   *   actually be accessed.
+   *
+   * @param[in] indices A vector of indices into `fe_function`. This vector
+   *   must have length equal to the number of degrees of freedom on the
+   *   current cell, and must identify elements in `fe_function` in the
+   *   order in which degrees of freedom are indexed on the reference cell.
+   *
+   * @param[out] values A vector of values of the given finite element field,
+   *   at the quadrature points on the current object.
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  template <typename Number>
+  void
+  get_function_values(const ReadVector<Number> &fe_function,
+                      const ArrayView<const types::global_dof_index> &indices,
+                      std::vector<Number> &values) const;
+
+  /**
+   * Generate vector function values from an arbitrary vector.
+   *
+   * This function corresponds to the previous one, just for the vector-valued
+   * case.
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  template <typename Number>
+  void
+  get_function_values(const ReadVector<Number> &fe_function,
+                      const ArrayView<const types::global_dof_index> &indices,
+                      std::vector<Vector<Number>> &values) const;
+
+
+  /**
+   * Generate vector function values from an arbitrary vector. This
+   * function is similar to the previous one, but the `indices`
+   * vector may also be a multiple of the number of dofs per
+   * cell. Then, the vectors in <tt>value</tt> should allow for the same
+   * multiple of the components of the finite element.
+   *
+   * Depending on the value of the last argument, the outer vector of
+   * <tt>values</tt> has either the length of the quadrature rule
+   * (<tt>quadrature_points_fastest == false</tt>) or the length of components
+   * to be filled <tt>quadrature_points_fastest == true</tt>. If <tt>p</tt> is
+   * the current quadrature point number and <tt>i</tt> is the vector
+   * component of the solution desired, the access to <tt>values</tt> is
+   * <tt>values[p][i]</tt> if <tt>quadrature_points_fastest == false</tt>, and
+   * <tt>values[i][p]</tt> otherwise.
+   *
+   * Since this function allows for fairly general combinations of argument
+   * sizes, be aware that the checks on the arguments may not detect errors.
+   *
+   * @dealiiRequiresUpdateFlags{update_values}
+   */
+  template <typename Number>
+  void
+  get_function_values(const ReadVector<Number> &fe_function,
+                      const ArrayView<const types::global_dof_index> &indices,
+                      ArrayView<std::vector<Number>>                  values,
+                      const bool quadrature_points_fastest) const;
+
+  /** @} */
+  /// @name Access to derivatives of global finite element fields
+  /** @{ */
+
+  /**
+   * Return the gradients of a finite element function at the quadrature points
+   * of the current cell, face, or subface (selected the last time the reinit()
+   * function was called). That is, if the first argument @p fe_function is a
+   * vector of nodal values of a finite element function $u_h(\mathbf x)$
+   * defined on a DoFHandler object, then the output vector (the second
+   * argument,
+   * @p values) is the vector of values $\nabla u_h(\mathbf x_q^K)$ where
+   * $x_q^K$ are the quadrature points on the current cell $K$. This function is
+   * first discussed in the Results section of step-4, and it is also used in
+   * step-15 along with numerous other tutorial programs.
+   *
+   * This function may only be used if the finite element in use is a scalar
+   * one, i.e. has only one vector component. There is a corresponding
+   * function of the same name for vector-valued finite elements.
+   *
+   * @param[in] fe_function A vector of values that describes (globally) the
+   * finite element function that this function should evaluate at the
+   * quadrature points of the current cell.
+   *
+   * @param[out] gradients The gradients of the function specified by
+   * fe_function at the quadrature points of the current cell.  The gradients
+   * are computed in real space (as opposed to on the unit cell).  The object
+   * is assume to already have the correct size. The data type stored by this
+   * output vector must be what you get when you multiply the gradients of
+   * shape function times the type used to store the values of the unknowns
+   * $U_j$ of your finite element vector $U$ (represented by the @p
+   * fe_function argument).
+   *
+   * @post <code>gradients[q]</code> will contain the gradient of the field
+   * described by fe_function at the $q$th quadrature point.
+   * <code>gradients[q][d]</code> represents the derivative in coordinate
+   * direction $d$ at quadrature point $q$.
+   *
+   * @note The actual data type of the input vector may be either a
+   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
+   * vector wrapper classes. It represents a global vector of DoF values
+   * associated with the DoFHandler object with which this FEValues object was
+   * last initialized.
+   *
+   * @dealiiRequiresUpdateFlags{update_gradients}
+   */
+  template <typename Number>
+  void
+  get_function_gradients(
+    const ReadVector<Number> &                fe_function,
+    std::vector<Tensor<1, spacedim, Number>> &gradients) const;
+
+  /**
+   * This function does the same as the other get_function_gradients(), but
+   * applied to multi-component (vector-valued) elements. The meaning of the
+   * arguments is as explained there.
+   *
+   * @post <code>gradients[q]</code> is a vector of gradients of the field
+   * described by fe_function at the $q$th quadrature point. The size of the
+   * vector accessed by <code>gradients[q]</code> equals the number of
+   * components of the finite element, i.e. <code>gradients[q][c]</code>
+   * returns the gradient of the $c$th vector component at the $q$th
+   * quadrature point. Consequently, <code>gradients[q][c][d]</code> is the
+   * derivative in coordinate direction $d$ of the $c$th vector component of
+   * the vector field at quadrature point $q$ of the current cell.
+   *
+   * @dealiiRequiresUpdateFlags{update_gradients}
+   */
+  template <typename Number>
+  void
+  get_function_gradients(
+    const ReadVector<Number> &                             fe_function,
+    std::vector<std::vector<Tensor<1, spacedim, Number>>> &gradients) const;
+
+  /**
+   * This function relates to the first of the get_function_gradients() function
+   * above in the same way as the get_function_values() with similar arguments
+   * relates to the first of the get_function_values() functions. See there for
+   * more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_gradients}
+   */
+  template <typename Number>
+  void
+  get_function_gradients(
+    const ReadVector<Number> &                      fe_function,
+    const ArrayView<const types::global_dof_index> &indices,
+    std::vector<Tensor<1, spacedim, Number>> &      gradients) const;
+
+  /**
+   * This function relates to the first of the get_function_gradients() function
+   * above in the same way as the get_function_values() with similar arguments
+   * relates to the first of the get_function_values() functions. See there for
+   * more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_gradients}
+   */
+  template <typename Number>
+  void
+  get_function_gradients(
+    const ReadVector<Number> &                          fe_function,
+    const ArrayView<const types::global_dof_index> &    indices,
+    ArrayView<std::vector<Tensor<1, spacedim, Number>>> gradients,
+    const bool quadrature_points_fastest = false) const;
+
+  /** @} */
+  /// @name Access to second derivatives
+  ///
+  /// Hessian matrices and Laplacians of global finite element fields
+  /** @{ */
+
+  /**
+   * Compute the tensor of second derivatives of a finite element at the
+   * quadrature points of a cell. This function is the equivalent of the
+   * corresponding get_function_values() function (see there for more
+   * information) but evaluates the finite element field's second derivatives
+   * instead of its value.
+   *
+   * This function may only be used if the finite element in use is a scalar
+   * one, i.e. has only one vector component. There is a corresponding
+   * function of the same name for vector-valued finite elements.
+   *
+   * @param[in] fe_function A vector of values that describes (globally) the
+   * finite element function that this function should evaluate at the
+   * quadrature points of the current cell.
+   *
+   * @param[out] hessians The Hessians of the function specified by
+   * fe_function at the quadrature points of the current cell.  The Hessians
+   * are computed in real space (as opposed to on the unit cell).  The object
+   * is assume to already have the correct size. The data type stored by this
+   * output vector must be what you get when you multiply the Hessians of
+   * shape function times the type used to store the values of the unknowns
+   * $U_j$ of your finite element vector $U$ (represented by the @p
+   * fe_function argument).
+   *
+   * @post <code>hessians[q]</code> will contain the Hessian of the field
+   * described by fe_function at the $q$th quadrature point.
+   * <code>hessians[q][i][j]</code> represents the $(i,j)$th component of the
+   * matrix of second derivatives at quadrature point $q$.
+   *
+   * @note The actual data type of the input vector may be either a
+   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
+   * vector wrapper classes. It represents a global vector of DoF values
+   * associated with the DoFHandler object with which this FEValues object was
+   * last initialized.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_hessians(
+    const ReadVector<Number> &                fe_function,
+    std::vector<Tensor<2, spacedim, Number>> &hessians) const;
+
+  /**
+   * This function does the same as the other get_function_hessians(), but
+   * applied to multi-component (vector-valued) elements. The meaning of the
+   * arguments is as explained there.
+   *
+   * @post <code>hessians[q]</code> is a vector of Hessians of the field
+   * described by fe_function at the $q$th quadrature point. The size of the
+   * vector accessed by <code>hessians[q]</code> equals the number of
+   * components of the finite element, i.e. <code>hessians[q][c]</code>
+   * returns the Hessian of the $c$th vector component at the $q$th quadrature
+   * point. Consequently, <code>hessians[q][c][i][j]</code> is the $(i,j)$th
+   * component of the matrix of second derivatives of the $c$th vector
+   * component of the vector field at quadrature point $q$ of the current
+   * cell.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_hessians(
+    const ReadVector<Number> &                             fe_function,
+    std::vector<std::vector<Tensor<2, spacedim, Number>>> &hessians,
+    const bool quadrature_points_fastest = false) const;
+
+  /**
+   * This function relates to the first of the get_function_hessians() function
+   * above in the same way as the get_function_values() with similar arguments
+   * relates to the first of the get_function_values() functions. See there for
+   * more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_hessians(
+    const ReadVector<Number> &                      fe_function,
+    const ArrayView<const types::global_dof_index> &indices,
+    std::vector<Tensor<2, spacedim, Number>> &      hessians) const;
+
+  /**
+   * This function relates to the first of the get_function_hessians() function
+   * above in the same way as the get_function_values() with similar arguments
+   * relates to the first of the get_function_values() functions. See there for
+   * more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_hessians(
+    const ReadVector<Number> &                          fe_function,
+    const ArrayView<const types::global_dof_index> &    indices,
+    ArrayView<std::vector<Tensor<2, spacedim, Number>>> hessians,
+    const bool quadrature_points_fastest = false) const;
+
+  /**
+   * Compute the (scalar) Laplacian (i.e. the trace of the tensor of second
+   * derivatives) of a finite element at the quadrature points of a cell. This
+   * function is the equivalent of the corresponding get_function_values()
+   * function (see there for more information) but evaluates the finite
+   * element field's second derivatives instead of its value.
+   *
+   * This function may only be used if the finite element in use is a scalar
+   * one, i.e. has only one vector component. There is a corresponding
+   * function of the same name for vector-valued finite elements.
+   *
+   * @param[in] fe_function A vector of values that describes (globally) the
+   * finite element function that this function should evaluate at the
+   * quadrature points of the current cell.
+   *
+   * @param[out] laplacians The Laplacians of the function specified by
+   * fe_function at the quadrature points of the current cell.  The Laplacians
+   * are computed in real space (as opposed to on the unit cell).  The object
+   * is assume to already have the correct size. The data type stored by this
+   * output vector must be what you get when you multiply the Laplacians of
+   * shape function times the type used to store the values of the unknowns
+   * $U_j$ of your finite element vector $U$ (represented by the @p
+   * fe_function argument). This happens to be equal to the type of the
+   * elements of the input vector.
+   *
+   * @post <code>laplacians[q]</code> will contain the Laplacian of the field
+   * described by fe_function at the $q$th quadrature point.
+   *
+   * @post For each component of the output vector, there holds
+   * <code>laplacians[q]=trace(hessians[q])</code>, where <tt>hessians</tt>
+   * would be the output of the get_function_hessians() function.
+   *
+   * @note The actual data type of the input vector may be either a
+   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
+   * vector wrapper classes. It represents a global vector of DoF values
+   * associated with the DoFHandler object with which this FEValues object was
+   * last initialized.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_laplacians(const ReadVector<Number> &fe_function,
+                          std::vector<Number> &     laplacians) const;
+
+  /**
+   * This function does the same as the other get_function_laplacians(), but
+   * applied to multi-component (vector-valued) elements. The meaning of the
+   * arguments is as explained there.
+   *
+   * @post <code>laplacians[q]</code> is a vector of Laplacians of the field
+   * described by fe_function at the $q$th quadrature point. The size of the
+   * vector accessed by <code>laplacians[q]</code> equals the number of
+   * components of the finite element, i.e. <code>laplacians[q][c]</code>
+   * returns the Laplacian of the $c$th vector component at the $q$th
+   * quadrature point.
+   *
+   * @post For each component of the output vector, there holds
+   * <code>laplacians[q][c]=trace(hessians[q][c])</code>, where
+   * <tt>hessians</tt> would be the output of the get_function_hessians()
+   * function.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_laplacians(const ReadVector<Number> &   fe_function,
+                          std::vector<Vector<Number>> &laplacians) const;
+
+  /**
+   * This function relates to the first of the get_function_laplacians()
+   * function above in the same way as the get_function_values() with similar
+   * arguments relates to the first of the get_function_values() functions. See
+   * there for more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_laplacians(
+    const ReadVector<Number> &                      fe_function,
+    const ArrayView<const types::global_dof_index> &indices,
+    std::vector<Number> &                           laplacians) const;
+
+  /**
+   * This function relates to the first of the get_function_laplacians()
+   * function above in the same way as the get_function_values() with similar
+   * arguments relates to the first of the get_function_values() functions. See
+   * there for more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_laplacians(
+    const ReadVector<Number> &                      fe_function,
+    const ArrayView<const types::global_dof_index> &indices,
+    std::vector<Vector<Number>> &                   laplacians) const;
+
+  /**
+   * This function relates to the first of the get_function_laplacians()
+   * function above in the same way as the get_function_values() with similar
+   * arguments relates to the first of the get_function_values() functions. See
+   * there for more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_hessians}
+   */
+  template <typename Number>
+  void
+  get_function_laplacians(
+    const ReadVector<Number> &                      fe_function,
+    const ArrayView<const types::global_dof_index> &indices,
+    std::vector<std::vector<Number>> &              laplacians,
+    const bool quadrature_points_fastest = false) const;
+
+  /** @} */
+  /// @name Access to third derivatives of global finite element fields
+  /** @{ */
+
+  /**
+   * Compute the tensor of third derivatives of a finite element at the
+   * quadrature points of a cell. This function is the equivalent of the
+   * corresponding get_function_values() function (see there for more
+   * information) but evaluates the finite element field's third derivatives
+   * instead of its value.
+   *
+   * This function may only be used if the finite element in use is a scalar
+   * one, i.e. has only one vector component. There is a corresponding
+   * function of the same name for vector-valued finite elements.
+   *
+   * @param[in] fe_function A vector of values that describes (globally) the
+   * finite element function that this function should evaluate at the
+   * quadrature points of the current cell.
+   *
+   * @param[out] third_derivatives The third derivatives of the function
+   * specified by fe_function at the quadrature points of the current cell.
+   * The third derivatives are computed in real space (as opposed to on the
+   * unit cell).  The object is assumed to already have the correct size. The
+   * data type stored by this output vector must be what you get when you
+   * multiply the third derivatives of shape function times the type used to
+   * store the values of the unknowns $U_j$ of your finite element vector $U$
+   * (represented by the @p fe_function argument).
+   *
+   * @post <code>third_derivatives[q]</code> will contain the third
+   * derivatives of the field described by fe_function at the $q$th quadrature
+   * point. <code>third_derivatives[q][i][j][k]</code> represents the
+   * $(i,j,k)$th component of the 3rd order tensor of third derivatives at
+   * quadrature point $q$.
+   *
+   * @note The actual data type of the input vector may be either a
+   * Vector&lt;T&gt;, BlockVector&lt;T&gt;, or one of the PETSc or Trilinos
+   * vector wrapper classes. It represents a global vector of DoF values
+   * associated with the DoFHandler object with which this FEValues object was
+   * last initialized.
+   *
+   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   */
+  template <typename Number>
+  void
+  get_function_third_derivatives(
+    const ReadVector<Number> &                fe_function,
+    std::vector<Tensor<3, spacedim, Number>> &third_derivatives) const;
+
+  /**
+   * This function does the same as the other
+   * get_function_third_derivatives(), but applied to multi-component (vector-
+   * valued) elements. The meaning of the arguments is as explained there.
+   *
+   * @post <code>third_derivatives[q]</code> is a vector of third derivatives
+   * of the field described by fe_function at the $q$th quadrature point. The
+   * size of the vector accessed by <code>third_derivatives[q]</code> equals
+   * the number of components of the finite element, i.e.
+   * <code>third_derivatives[q][c]</code> returns the third derivative of the
+   * $c$th vector component at the $q$th quadrature point. Consequently,
+   * <code>third_derivatives[q][c][i][j][k]</code> is the $(i,j,k)$th
+   * component of the tensor of third derivatives of the $c$th vector
+   * component of the vector field at quadrature point $q$ of the current
+   * cell.
+   *
+   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   */
+  template <typename Number>
+  void
+  get_function_third_derivatives(
+    const ReadVector<Number> &                             fe_function,
+    std::vector<std::vector<Tensor<3, spacedim, Number>>> &third_derivatives,
+    const bool quadrature_points_fastest = false) const;
+
+  /**
+   * This function relates to the first of the get_function_third_derivatives()
+   * function above in the same way as the get_function_values() with similar
+   * arguments relates to the first of the get_function_values() functions. See
+   * there for more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   */
+  template <typename Number>
+  void
+  get_function_third_derivatives(
+    const ReadVector<Number> &                      fe_function,
+    const ArrayView<const types::global_dof_index> &indices,
+    std::vector<Tensor<3, spacedim, Number>> &      third_derivatives) const;
+
+  /**
+   * This function relates to the first of the get_function_third_derivatives()
+   * function above in the same way as the get_function_values() with similar
+   * arguments relates to the first of the get_function_values() functions. See
+   * there for more information.
+   *
+   * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+   */
+  template <typename Number>
+  void
+  get_function_third_derivatives(
+    const ReadVector<Number> &                          fe_function,
+    const ArrayView<const types::global_dof_index> &    indices,
+    ArrayView<std::vector<Tensor<3, spacedim, Number>>> third_derivatives,
+    const bool quadrature_points_fastest = false) const;
+  /** @} */
+
+  /// @name Cell degrees of freedom
+  /** @{ */
+
+  /**
+   * Return an object that can be thought of as an array containing all
+   * indices from zero (inclusive) to `dofs_per_cell` (exclusive). This allows
+   * one to write code using range-based `for` loops of the following kind:
+   * @code
+   *   FEValues<dim>      fe_values (...);
+   *   FullMatrix<double> cell_matrix (...);
+   *
+   *   for (auto &cell : dof_handler.active_cell_iterators())
+   *     {
+   *       cell_matrix = 0;
+   *       fe_values.reinit(cell);
+   *       for (const auto q : fe_values.quadrature_point_indices())
+   *         for (const auto i : fe_values.dof_indices())
+   *           for (const auto j : fe_values.dof_indices())
+   *             cell_matrix(i,j) += ...; // Do something for DoF indices (i,j)
+   *                                      // at quadrature point q
+   *     }
+   * @endcode
+   * Here, we are looping over all degrees of freedom on all cells, with
+   * `i` and `j` taking on all valid indices for cell degrees of freedom, as
+   * defined by the finite element passed to `fe_values`.
+   */
+  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+  dof_indices() const;
+
+  /**
+   * Return an object that can be thought of as an array containing all
+   * indices from @p start_dof_index (inclusive) to `dofs_per_cell` (exclusive).
+   * This allows one to write code using range-based `for` loops of the
+   * following kind:
+   * @code
+   *   FEValues<dim>      fe_values (...);
+   *   FullMatrix<double> cell_matrix (...);
+   *
+   *   for (auto &cell : dof_handler.active_cell_iterators())
+   *     {
+   *       cell_matrix = 0;
+   *       fe_values.reinit(cell);
+   *       for (const auto q : fe_values.quadrature_point_indices())
+   *         for (const auto i : fe_values.dof_indices())
+   *           for (const auto j : fe_values.dof_indices_starting_at(i))
+   *             cell_matrix(i,j) += ...; // Do something for DoF indices (i,j)
+   *                                      // at quadrature point q
+   *     }
+   * @endcode
+   * Here, we are looping over all local degrees of freedom on all cells, with
+   * `i` taking on all valid indices for cell degrees of freedom, as
+   * defined by the finite element passed to `fe_values`, and `j` taking
+   * on a specified subset of `i`'s range, starting at `i` itself and ending at
+   * the number of cell degrees of freedom. In this way, we can construct the
+   * upper half and the diagonal of a @ref GlossStiffnessMatrix "stiffness matrix" contribution (assuming it
+   * is symmetric, and that only one half of it needs to be computed), for
+   * example.
+   *
+   * @note If the @p start_dof_index is equal to the number of DoFs in the cell,
+   * then the returned index range is empty.
+   */
+  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+  dof_indices_starting_at(const unsigned int start_dof_index) const;
+
+  /**
+   * Return an object that can be thought of as an array containing all
+   * indices from zero (inclusive) to @p end_dof_index (inclusive). This allows
+   * one to write code using range-based `for` loops of the following kind:
+   * @code
+   *   FEValues<dim>      fe_values (...);
+   *   FullMatrix<double> cell_matrix (...);
+   *
+   *   for (auto &cell : dof_handler.active_cell_iterators())
+   *     {
+   *       cell_matrix = 0;
+   *       fe_values.reinit(cell);
+   *       for (const auto q : fe_values.quadrature_point_indices())
+   *         for (const auto i : fe_values.dof_indices())
+   *           for (const auto j : fe_values.dof_indices_ending_at(i))
+   *             cell_matrix(i,j) += ...; // Do something for DoF indices (i,j)
+   *                                      // at quadrature point q
+   *     }
+   * @endcode
+   * Here, we are looping over all local degrees of freedom on all cells, with
+   * `i` taking on all valid indices for cell degrees of freedom, as
+   * defined by the finite element passed to `fe_values`, and `j` taking
+   * on a specified subset of `i`'s range, starting at zero and ending at
+   * `i` itself. In this way, we can construct the lower half and the
+   * diagonal of a @ref GlossStiffnessMatrix "stiffness matrix" contribution (assuming it is symmetric, and
+   * that only one half of it needs to be computed), for example.
+   *
+   * @note If the @p end_dof_index is equal to zero, then the returned index
+   * range is empty.
+   */
+  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+  dof_indices_ending_at(const unsigned int end_dof_index) const;
+
+  /** @} */
+
+  /// @name Geometry of the cell
+  /** @{ */
+
+  /**
+   * Return an object that can be thought of as an array containing all
+   * indices from zero to `n_quadrature_points`. This allows to write code
+   * using range-based `for` loops of the following kind:
+   * @code
+   *   FEValues<dim> fe_values (...);
+   *
+   *   for (auto &cell : dof_handler.active_cell_iterators())
+   *     {
+   *       fe_values.reinit(cell);
+   *       for (const auto q_point : fe_values.quadrature_point_indices())
+   *         ... do something at the quadrature point ...
+   *     }
+   * @endcode
+   * Here, we are looping over all quadrature points on all cells, with
+   * `q_point` taking on all valid indices for quadrature points, as defined
+   * by the quadrature rule passed to `fe_values`.
+   *
+   * @see CPP11
+   */
+  std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+  quadrature_point_indices() const;
+
+  /**
+   * Return the location of the <tt>q_point</tt>th quadrature point in
+   * real space.
+   *
+   * @dealiiRequiresUpdateFlags{update_quadrature_points}
+   */
+  const Point<spacedim> &
+  quadrature_point(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the vector of quadrature points in real space.
+   *
+   * @dealiiRequiresUpdateFlags{update_quadrature_points}
+   */
+  const std::vector<Point<spacedim>> &
+  get_quadrature_points() const;
+
+  /**
+   * Mapped quadrature weight. If this object refers to a volume evaluation
+   * (i.e. the derived class is of type FEValues), then this is the Jacobi
+   * determinant times the weight of the <tt>q_point</tt>th unit quadrature
+   * point.
+   *
+   * For surface evaluations (i.e. classes FEFaceValues or FESubfaceValues),
+   * it is the mapped surface element times the weight of the quadrature
+   * point.
+   *
+   * You can think of the quantity returned by this function as the volume or
+   * surface element $dx, ds$ in the integral that we implement here by
+   * quadrature.
+   *
+   * @dealiiRequiresUpdateFlags{update_JxW_values}
+   */
+  double
+  JxW(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by JxW().
+   */
+  const std::vector<double> &
+  get_JxW_values() const;
+
+  /**
+   * Return the Jacobian of the transformation at the specified quadrature
+   * point, i.e.  $J_{ij}=dx_i/d\hat x_j$
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobians}
+   */
+  const DerivativeForm<1, dim, spacedim> &
+  jacobian(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobians}
+   */
+  const std::vector<DerivativeForm<1, dim, spacedim>> &
+  get_jacobians() const;
+
+  /**
+   * Return the second derivative of the transformation from unit to real
+   * cell, i.e. the first derivative of the Jacobian, at the specified
+   * quadrature point, i.e. $G_{ijk}=dJ_{jk}/d\hat x_i$.
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_grads}
+   */
+  const DerivativeForm<2, dim, spacedim> &
+  jacobian_grad(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian_grads().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_grads}
+   */
+  const std::vector<DerivativeForm<2, dim, spacedim>> &
+  get_jacobian_grads() const;
+
+  /**
+   * Return the second derivative of the transformation from unit to real
+   * cell, i.e. the first derivative of the Jacobian, at the specified
+   * quadrature point, pushed forward to the real cell coordinates, i.e.
+   * $G_{ijk}=dJ_{iJ}/d\hat x_K (J_{jJ})^{-1} (J_{kK})^{-1}$.
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_grads}
+   */
+  const Tensor<3, spacedim> &
+  jacobian_pushed_forward_grad(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian_pushed_forward_grads().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_grads}
+   */
+  const std::vector<Tensor<3, spacedim>> &
+  get_jacobian_pushed_forward_grads() const;
+
+  /**
+   * Return the third derivative of the transformation from unit to real cell,
+   * i.e. the second derivative of the Jacobian, at the specified quadrature
+   * point, i.e. $G_{ijkl}=\frac{d^2J_{ij}}{d\hat x_k d\hat x_l}$.
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_2nd_derivatives}
+   */
+  const DerivativeForm<3, dim, spacedim> &
+  jacobian_2nd_derivative(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian_2nd_derivatives().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_2nd_derivatives}
+   */
+  const std::vector<DerivativeForm<3, dim, spacedim>> &
+  get_jacobian_2nd_derivatives() const;
+
+  /**
+   * Return the third derivative of the transformation from unit to real cell,
+   * i.e. the second derivative of the Jacobian, at the specified quadrature
+   * point, pushed forward to the real cell coordinates, i.e.
+   * $G_{ijkl}=\frac{d^2J_{iJ}}{d\hat x_K d\hat x_L} (J_{jJ})^{-1}
+   * (J_{kK})^{-1}(J_{lL})^{-1}$.
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_2nd_derivatives}
+   */
+  const Tensor<4, spacedim> &
+  jacobian_pushed_forward_2nd_derivative(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian_pushed_forward_2nd_derivatives().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_2nd_derivatives}
+   */
+  const std::vector<Tensor<4, spacedim>> &
+  get_jacobian_pushed_forward_2nd_derivatives() const;
+
+  /**
+   * Return the fourth derivative of the transformation from unit to real
+   * cell, i.e. the third derivative of the Jacobian, at the specified
+   * quadrature point, i.e. $G_{ijklm}=\frac{d^2J_{ij}}{d\hat x_k d\hat x_l
+   * d\hat x_m}$.
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_3rd_derivatives}
+   */
+  const DerivativeForm<4, dim, spacedim> &
+  jacobian_3rd_derivative(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian_3rd_derivatives().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_3rd_derivatives}
+   */
+  const std::vector<DerivativeForm<4, dim, spacedim>> &
+  get_jacobian_3rd_derivatives() const;
+
+  /**
+   * Return the fourth derivative of the transformation from unit to real
+   * cell, i.e. the third derivative of the Jacobian, at the specified
+   * quadrature point, pushed forward to the real cell coordinates, i.e.
+   * $G_{ijklm}=\frac{d^3J_{iJ}}{d\hat x_K d\hat x_L d\hat x_M} (J_{jJ})^{-1}
+   * (J_{kK})^{-1} (J_{lL})^{-1} (J_{mM})^{-1}$.
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_3rd_derivatives}
+   */
+  const Tensor<5, spacedim> &
+  jacobian_pushed_forward_3rd_derivative(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * jacobian_pushed_forward_3rd_derivatives().
+   *
+   * @dealiiRequiresUpdateFlags{update_jacobian_pushed_forward_2nd_derivatives}
+   */
+  const std::vector<Tensor<5, spacedim>> &
+  get_jacobian_pushed_forward_3rd_derivatives() const;
+
+  /**
+   * Return the inverse Jacobian of the transformation at the specified
+   * quadrature point, i.e.  $J_{ij}=d\hat x_i/dx_j$
+   *
+   * @dealiiRequiresUpdateFlags{update_inverse_jacobians}
+   */
+  const DerivativeForm<1, spacedim, dim> &
+  inverse_jacobian(const unsigned int q_point) const;
+
+  /**
+   * Return a reference to the array holding the values returned by
+   * inverse_jacobian().
+   *
+   * @dealiiRequiresUpdateFlags{update_inverse_jacobians}
+   */
+  const std::vector<DerivativeForm<1, spacedim, dim>> &
+  get_inverse_jacobians() const;
+
+  /**
+   * Return the normal vector at a quadrature point. If you call this
+   * function for a face (i.e., when using a FEFaceValues or FESubfaceValues
+   * object), then this function returns the outward normal vector to
+   * the cell at the <tt>q_point</tt>th quadrature point of the face.
+   *
+   * In contrast, if you call this function for a cell of codimension one
+   * (i.e., when using a `FEValues<dim,spacedim>` object with
+   * `spacedim>dim`), then this function returns the normal vector to the
+   * cell -- in other words, an approximation to the normal vector to the
+   * manifold in which the triangulation is embedded. There are of
+   * course two normal directions to a manifold in that case, and this
+   * function returns the "up" direction as induced by the numbering of the
+   * vertices.
+   *
+   * The length of the vector is normalized to one.
+   *
+   * @dealiiRequiresUpdateFlags{update_normal_vectors}
+   */
+  const Tensor<1, spacedim> &
+  normal_vector(const unsigned int q_point) const;
+
+  /**
+   * Return the normal vectors at all quadrature points represented by
+   * this object. See the normal_vector() function for what the normal
+   * vectors represent.
+   *
+   * @dealiiRequiresUpdateFlags{update_normal_vectors}
+   */
+  const std::vector<Tensor<1, spacedim>> &
+  get_normal_vectors() const;
+
+  /** @} */
+
+  /// @name Extractors Methods to extract individual components
+  /** @{ */
+
+  /**
+   * Create a view of the current FEValues object that represents a particular
+   * scalar component of the possibly vector-valued finite element. The
+   * concept of views is explained in the documentation of the namespace
+   * FEValuesViews and in particular in the
+   * @ref vector_valued
+   * module.
+   */
+  const FEValuesViews::Scalar<dim, spacedim> &
+  operator[](const FEValuesExtractors::Scalar &scalar) const;
+
+  /**
+   * Create a view of the current FEValues object that represents a set of
+   * <code>dim</code> scalar components (i.e. a vector) of the vector-valued
+   * finite element. The concept of views is explained in the documentation of
+   * the namespace FEValuesViews and in particular in the
+   * @ref vector_valued
+   * module.
+   */
+  const FEValuesViews::Vector<dim, spacedim> &
+  operator[](const FEValuesExtractors::Vector &vector) const;
+
+  /**
+   * Create a view of the current FEValues object that represents a set of
+   * <code>(dim*dim + dim)/2</code> scalar components (i.e. a symmetric 2nd
+   * order tensor) of the vector-valued finite element. The concept of views
+   * is explained in the documentation of the namespace FEValuesViews and in
+   * particular in the
+   * @ref vector_valued
+   * module.
+   */
+  const FEValuesViews::SymmetricTensor<2, dim, spacedim> &
+  operator[](const FEValuesExtractors::SymmetricTensor<2> &tensor) const;
+
+
+  /**
+   * Create a view of the current FEValues object that represents a set of
+   * <code>(dim*dim)</code> scalar components (i.e. a 2nd order tensor) of the
+   * vector-valued finite element. The concept of views is explained in the
+   * documentation of the namespace FEValuesViews and in particular in the
+   * @ref vector_valued
+   * module.
+   */
+  const FEValuesViews::Tensor<2, dim, spacedim> &
+  operator[](const FEValuesExtractors::Tensor<2> &tensor) const;
+
+  /** @} */
+
+  /// @name Access to the raw data
+  /** @{ */
+
+  /**
+   * Constant reference to the selected mapping object.
+   */
+  const Mapping<dim, spacedim> &
+  get_mapping() const;
+
+  /**
+   * Constant reference to the selected finite element object.
+   */
+  const FiniteElement<dim, spacedim> &
+  get_fe() const;
+
+  /**
+   * Return the update flags set for this object.
+   */
+  UpdateFlags
+  get_update_flags() const;
+
+  /**
+   * Return a triangulation iterator to the current cell.
+   */
+  typename Triangulation<dim, spacedim>::cell_iterator
+  get_cell() const;
+
+  /**
+   * Return the relation of the current cell to the previous cell. This allows
+   * re-use of some cell data (like local matrices for equations with constant
+   * coefficients) if the result is <tt>CellSimilarity::translation</tt>.
+   */
+  CellSimilarity::Similarity
+  get_cell_similarity() const;
+
+  /**
+   * Determine an estimate for the memory consumption (in bytes) of this
+   * object.
+   */
+  std::size_t
+  memory_consumption() const;
+  /** @} */
+
+
+  /**
+   * This exception is thrown if FEValuesBase is asked to return the value of
+   * a field which was not required by the UpdateFlags for this FEValuesBase.
+   *
+   * @ingroup Exceptions
+   */
+  DeclException1(
+    ExcAccessToUninitializedField,
+    std::string,
+    << "You are requesting information from an FEValues/FEFaceValues/FESubfaceValues "
+    << "object for which this kind of information has not been computed. What "
+    << "information these objects compute is determined by the update_* flags you "
+    << "pass to the constructor. Here, the operation you are attempting requires "
+    << "the <" << arg1
+    << "> flag to be set, but it was apparently not specified "
+    << "upon construction.");
+
+  /**
+   * FEValues::reinit() has not been called for any cell.
+   *
+   * @ingroup Exceptions
+   */
+  DeclExceptionMsg(ExcNotReinited,
+                   "FEValues object is not reinit'ed to any cell");
+
+  /**
+   * Mismatch between the FEValues FiniteElement and
+   * cell->get_dof_handler().get_fe()
+   *
+   * @ingroup Exceptions
+   */
+  DeclExceptionMsg(
+    ExcFEDontMatch,
+    "The FiniteElement you provided to FEValues and the FiniteElement that belongs "
+    "to the DoFHandler that provided the cell iterator do not match.");
+  /**
+   * A given shape function is not primitive, but it needs to be.
+   *
+   * @ingroup Exceptions
+   */
+  DeclException1(ExcShapeFunctionNotPrimitive,
+                 int,
+                 << "The shape function with index " << arg1
+                 << " is not primitive, i.e. it is vector-valued and "
+                 << "has more than one non-zero vector component. This "
+                 << "function cannot be called for these shape functions. "
+                 << "Maybe you want to use the same function with the "
+                 << "_component suffix?");
+
+  /**
+   * The given FiniteElement is not a primitive element, see
+   * FiniteElement::is_primitive().
+   *
+   * @ingroup Exceptions
+   */
+  DeclExceptionMsg(
+    ExcFENotPrimitive,
+    "The given FiniteElement is not a primitive element but the requested operation "
+    "only works for those. See FiniteElement::is_primitive() for more information.");
+
+protected:
+  /**
+   * Objects of the FEValues class need to store an iterator
+   * to the present cell in order to be able to extract the values of the
+   * degrees of freedom on this cell in the get_function_values() and assorted
+   * functions.
+   */
+  class CellIteratorContainer
+  {
+  public:
+    DeclExceptionMsg(
+      ExcNeedsDoFHandler,
+      "You have previously called the FEValues::reinit() function with a "
+      "cell iterator of type Triangulation<dim,spacedim>::cell_iterator. However, "
+      "when you do this, you cannot call some functions in the FEValues "
+      "class, such as the get_function_values/gradients/hessians/third_derivatives "
+      "functions. If you need these functions, then you need to call "
+      "FEValues::reinit() with an iterator type that allows to extract "
+      "degrees of freedom, such as DoFHandler<dim,spacedim>::cell_iterator.");
+
+    /**
+     * Constructor.
+     */
+    CellIteratorContainer();
+
+    /**
+     * Constructor.
+     */
+    template <bool lda>
+    CellIteratorContainer(
+      const TriaIterator<DoFCellAccessor<dim, spacedim, lda>> &cell);
+
+    /**
+     * Constructor.
+     */
+    CellIteratorContainer(
+      const typename Triangulation<dim, spacedim>::cell_iterator &cell);
+
+    /**
+     * Indicate whether FEValues::reinit() was called.
+     */
+    bool
+    is_initialized() const;
+
+    /**
+     * Conversion operator to an iterator for triangulations. This
+     * conversion is implicit for the original iterators, since they are derived
+     * classes. However, since here we have kind of a parallel class hierarchy,
+     * we have to have a conversion operator.
+     */
+    operator typename Triangulation<dim, spacedim>::cell_iterator() const;
+
+    /**
+     * Return the number of degrees of freedom the DoF
+     * handler object has to which the iterator belongs to.
+     */
+    types::global_dof_index
+    n_dofs_for_dof_handler() const;
+
+    /**
+     * Call @p get_interpolated_dof_values of the iterator with the
+     * given arguments.
+     */
+    template <typename Number>
+    void
+    get_interpolated_dof_values(const ReadVector<Number> &in,
+                                Vector<Number> &          out) const;
+
+    /**
+     * Call @p get_interpolated_dof_values of the iterator with the
+     * given arguments.
+     */
+    void
+    get_interpolated_dof_values(const IndexSet &              in,
+                                Vector<IndexSet::value_type> &out) const;
+
+  private:
+    bool                                                 initialized;
+    typename Triangulation<dim, spacedim>::cell_iterator cell;
+    const DoFHandler<dim, spacedim> *                    dof_handler;
+    bool                                                 level_dof_access;
+  };
+
+  /**
+   * Store the cell selected last time the reinit() function was called.  This
+   * is necessary for the <tt>get_function_*</tt> functions as well as the
+   * functions of same name in the extractor classes.
+   */
+  CellIteratorContainer present_cell;
+
+  /**
+   * A signal connection we use to ensure we get informed whenever the
+   * triangulation changes by refinement. We need to know about that because
+   * it invalidates all cell iterators and, as part of that, the
+   * 'present_cell' iterator we keep around between subsequent calls to
+   * reinit() in order to compute the cell similarity.
+   */
+  boost::signals2::connection tria_listener_refinement;
+
+  /**
+   * A signal connection we use to ensure we get informed whenever the
+   * triangulation changes by mesh transformations. We need to know about that
+   * because it invalidates all cell iterators and, as part of that, the
+   * 'present_cell' iterator we keep around between subsequent calls to
+   * reinit() in order to compute the cell similarity.
+   */
+  boost::signals2::connection tria_listener_mesh_transform;
+
+  /**
+   * A function that is connected to the triangulation in order to reset the
+   * stored 'present_cell' iterator to an invalid one whenever the
+   * triangulation is changed and the iterator consequently becomes invalid.
+   */
+  void
+  invalidate_present_cell();
+
+  /**
+   * This function is called by the various reinit() functions in derived
+   * classes. Given the cell indicated by the argument, test whether we have
+   * to throw away the previously stored present_cell argument because it
+   * would require us to compare cells from different triangulations. In
+   * checking all this, also make sure that we have tria_listener connected to
+   * the triangulation to which we will set present_cell right after calling
+   * this function.
+   */
+  void
+  maybe_invalidate_previous_present_cell(
+    const typename Triangulation<dim, spacedim>::cell_iterator &cell);
+
+  /**
+   * A pointer to the mapping object associated with this FEValues object.
+   */
+  const SmartPointer<const Mapping<dim, spacedim>, FEValuesBase<dim, spacedim>>
+    mapping;
+
+  /**
+   * A pointer to the internal data object of mapping, obtained from
+   * Mapping::get_data(), Mapping::get_face_data(), or
+   * Mapping::get_subface_data().
+   */
+  std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
+    mapping_data;
+
+  /**
+   * An object into which the Mapping::fill_fe_values() and similar functions
+   * place their output.
+   */
+  internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
+    mapping_output;
+
+  /**
+   * A pointer to the finite element object associated with this FEValues
+   * object.
+   */
+  const SmartPointer<const FiniteElement<dim, spacedim>,
+                     FEValuesBase<dim, spacedim>>
+    fe;
+
+  /**
+   * A pointer to the internal data object of finite element, obtained from
+   * FiniteElement::get_data(), Mapping::get_face_data(), or
+   * FiniteElement::get_subface_data().
+   */
+  std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
+    fe_data;
+
+  /**
+   * An object into which the FiniteElement::fill_fe_values() and similar
+   * functions place their output.
+   */
+  dealii::internal::FEValuesImplementation::FiniteElementRelatedData<dim,
+                                                                     spacedim>
+    finite_element_output;
+
+
+  /**
+   * Original update flags handed to the constructor of FEValues.
+   */
+  UpdateFlags update_flags;
+
+  /**
+   * Initialize some update flags. Called from the @p initialize functions of
+   * derived classes, which are in turn called from their constructors.
+   *
+   * Basically, this function finds out using the finite element and mapping
+   * object already stored which flags need to be set to compute everything
+   * the user wants, as expressed through the flags passed as argument.
+   */
+  UpdateFlags
+  compute_update_flags(const UpdateFlags update_flags) const;
+
+  /**
+   * An enum variable that can store different states of the current cell in
+   * comparison to the previously visited cell. If wanted, additional states
+   * can be checked here and used in one of the methods used during reinit.
+   */
+  CellSimilarity::Similarity cell_similarity;
+
+  /**
+   * A function that checks whether the new cell is similar to the one
+   * previously used. Then, a significant amount of the data can be reused,
+   * e.g. the derivatives of the basis functions in real space, shape_grad.
+   */
+  void
+  check_cell_similarity(
+    const typename Triangulation<dim, spacedim>::cell_iterator &cell);
+
+private:
+  /**
+   * A cache for all possible FEValuesViews objects.
+   */
+  dealii::internal::FEValuesViews::Cache<dim, spacedim> fe_values_views_cache;
+
+  // Make the view classes friends of this class, since they access internal
+  // data.
+  template <int, int>
+  friend class FEValuesViews::Scalar;
+  template <int, int>
+  friend class FEValuesViews::Vector;
+  template <int, int, int>
+  friend class FEValuesViews::SymmetricTensor;
+  template <int, int, int>
+  friend class FEValuesViews::Tensor;
+};
+
+#ifndef DOXYGEN
+
+/*---------------------- Inline functions: FEValuesBase ---------------------*/
+
+template <int dim, int spacedim>
+template <bool lda>
+inline FEValuesBase<dim, spacedim>::CellIteratorContainer::
+  CellIteratorContainer(
+    const TriaIterator<DoFCellAccessor<dim, spacedim, lda>> &cell)
+  : initialized(true)
+  , cell(cell)
+  , dof_handler(&cell->get_dof_handler())
+  , level_dof_access(lda)
+{}
+
+
+
+template <int dim, int spacedim>
+inline const FEValuesViews::Scalar<dim, spacedim> &
+FEValuesBase<dim, spacedim>::operator[](
+  const FEValuesExtractors::Scalar &scalar) const
+{
+  AssertIndexRange(scalar.component, fe_values_views_cache.scalars.size());
+
+  return fe_values_views_cache.scalars[scalar.component];
+}
+
+
+
+template <int dim, int spacedim>
+inline const FEValuesViews::Vector<dim, spacedim> &
+FEValuesBase<dim, spacedim>::operator[](
+  const FEValuesExtractors::Vector &vector) const
+{
+  AssertIndexRange(vector.first_vector_component,
+                   fe_values_views_cache.vectors.size());
+
+  return fe_values_views_cache.vectors[vector.first_vector_component];
+}
+
+
+
+template <int dim, int spacedim>
+inline const FEValuesViews::SymmetricTensor<2, dim, spacedim> &
+FEValuesBase<dim, spacedim>::operator[](
+  const FEValuesExtractors::SymmetricTensor<2> &tensor) const
+{
+  Assert(
+    tensor.first_tensor_component <
+      fe_values_views_cache.symmetric_second_order_tensors.size(),
+    ExcIndexRange(tensor.first_tensor_component,
+                  0,
+                  fe_values_views_cache.symmetric_second_order_tensors.size()));
+
+  return fe_values_views_cache
+    .symmetric_second_order_tensors[tensor.first_tensor_component];
+}
+
+
+
+template <int dim, int spacedim>
+inline const FEValuesViews::Tensor<2, dim, spacedim> &
+FEValuesBase<dim, spacedim>::operator[](
+  const FEValuesExtractors::Tensor<2> &tensor) const
+{
+  AssertIndexRange(tensor.first_tensor_component,
+                   fe_values_views_cache.second_order_tensors.size());
+
+  return fe_values_views_cache
+    .second_order_tensors[tensor.first_tensor_component];
+}
+
+
+
+template <int dim, int spacedim>
+inline const double &
+FEValuesBase<dim, spacedim>::shape_value(const unsigned int i,
+                                         const unsigned int q_point) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // if the entire FE is primitive,
+  // then we can take a short-cut:
+  if (fe->is_primitive())
+    return this->finite_element_output.shape_values(i, q_point);
+  else
+    {
+      // otherwise, use the mapping
+      // between shape function
+      // numbers and rows. note that
+      // by the assertions above, we
+      // know that this particular
+      // shape function is primitive,
+      // so we can call
+      // system_to_component_index
+      const unsigned int row =
+        this->finite_element_output
+          .shape_function_to_row_table[i * fe->n_components() +
+                                       fe->system_to_component_index(i).first];
+      return this->finite_element_output.shape_values(row, q_point);
+    }
+}
+
+
+
+template <int dim, int spacedim>
+inline double
+FEValuesBase<dim, spacedim>::shape_value_component(
+  const unsigned int i,
+  const unsigned int q_point,
+  const unsigned int component) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+  AssertIndexRange(component, fe->n_components());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  // check whether the shape function
+  // is non-zero at all within
+  // this component:
+  if (fe->get_nonzero_components(i)[component] == false)
+    return 0;
+
+  // look up the right row in the
+  // table and take the data from
+  // there
+  const unsigned int row =
+    this->finite_element_output
+      .shape_function_to_row_table[i * fe->n_components() + component];
+  return this->finite_element_output.shape_values(row, q_point);
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<1, spacedim> &
+FEValuesBase<dim, spacedim>::shape_grad(const unsigned int i,
+                                        const unsigned int q_point) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_gradients,
+         ExcAccessToUninitializedField("update_gradients"));
+  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // if the entire FE is primitive,
+  // then we can take a short-cut:
+  if (fe->is_primitive())
+    return this->finite_element_output.shape_gradients[i][q_point];
+  else
+    {
+      // otherwise, use the mapping
+      // between shape function
+      // numbers and rows. note that
+      // by the assertions above, we
+      // know that this particular
+      // shape function is primitive,
+      // so we can call
+      // system_to_component_index
+      const unsigned int row =
+        this->finite_element_output
+          .shape_function_to_row_table[i * fe->n_components() +
+                                       fe->system_to_component_index(i).first];
+      return this->finite_element_output.shape_gradients[row][q_point];
+    }
+}
+
+
+
+template <int dim, int spacedim>
+inline Tensor<1, spacedim>
+FEValuesBase<dim, spacedim>::shape_grad_component(
+  const unsigned int i,
+  const unsigned int q_point,
+  const unsigned int component) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_gradients,
+         ExcAccessToUninitializedField("update_gradients"));
+  AssertIndexRange(component, fe->n_components());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // check whether the shape function
+  // is non-zero at all within
+  // this component:
+  if (fe->get_nonzero_components(i)[component] == false)
+    return Tensor<1, spacedim>();
+
+  // look up the right row in the
+  // table and take the data from
+  // there
+  const unsigned int row =
+    this->finite_element_output
+      .shape_function_to_row_table[i * fe->n_components() + component];
+  return this->finite_element_output.shape_gradients[row][q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<2, spacedim> &
+FEValuesBase<dim, spacedim>::shape_hessian(const unsigned int i,
+                                           const unsigned int q_point) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // if the entire FE is primitive,
+  // then we can take a short-cut:
+  if (fe->is_primitive())
+    return this->finite_element_output.shape_hessians[i][q_point];
+  else
+    {
+      // otherwise, use the mapping
+      // between shape function
+      // numbers and rows. note that
+      // by the assertions above, we
+      // know that this particular
+      // shape function is primitive,
+      // so we can call
+      // system_to_component_index
+      const unsigned int row =
+        this->finite_element_output
+          .shape_function_to_row_table[i * fe->n_components() +
+                                       fe->system_to_component_index(i).first];
+      return this->finite_element_output.shape_hessians[row][q_point];
+    }
+}
+
+
+
+template <int dim, int spacedim>
+inline Tensor<2, spacedim>
+FEValuesBase<dim, spacedim>::shape_hessian_component(
+  const unsigned int i,
+  const unsigned int q_point,
+  const unsigned int component) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  AssertIndexRange(component, fe->n_components());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // check whether the shape function
+  // is non-zero at all within
+  // this component:
+  if (fe->get_nonzero_components(i)[component] == false)
+    return Tensor<2, spacedim>();
+
+  // look up the right row in the
+  // table and take the data from
+  // there
+  const unsigned int row =
+    this->finite_element_output
+      .shape_function_to_row_table[i * fe->n_components() + component];
+  return this->finite_element_output.shape_hessians[row][q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<3, spacedim> &
+FEValuesBase<dim, spacedim>::shape_3rd_derivative(
+  const unsigned int i,
+  const unsigned int q_point) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_3rd_derivatives,
+         ExcAccessToUninitializedField("update_3rd_derivatives"));
+  Assert(fe->is_primitive(i), ExcShapeFunctionNotPrimitive(i));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // if the entire FE is primitive,
+  // then we can take a short-cut:
+  if (fe->is_primitive())
+    return this->finite_element_output.shape_3rd_derivatives[i][q_point];
+  else
+    {
+      // otherwise, use the mapping
+      // between shape function
+      // numbers and rows. note that
+      // by the assertions above, we
+      // know that this particular
+      // shape function is primitive,
+      // so we can call
+      // system_to_component_index
+      const unsigned int row =
+        this->finite_element_output
+          .shape_function_to_row_table[i * fe->n_components() +
+                                       fe->system_to_component_index(i).first];
+      return this->finite_element_output.shape_3rd_derivatives[row][q_point];
+    }
+}
+
+
+
+template <int dim, int spacedim>
+inline Tensor<3, spacedim>
+FEValuesBase<dim, spacedim>::shape_3rd_derivative_component(
+  const unsigned int i,
+  const unsigned int q_point,
+  const unsigned int component) const
+{
+  AssertIndexRange(i, fe->n_dofs_per_cell());
+  Assert(this->update_flags & update_3rd_derivatives,
+         ExcAccessToUninitializedField("update_3rd_derivatives"));
+  AssertIndexRange(component, fe->n_components());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  // check whether the shape function
+  // is non-zero at all within
+  // this component:
+  if (fe->get_nonzero_components(i)[component] == false)
+    return Tensor<3, spacedim>();
+
+  // look up the right row in the
+  // table and take the data from
+  // there
+  const unsigned int row =
+    this->finite_element_output
+      .shape_function_to_row_table[i * fe->n_components() + component];
+  return this->finite_element_output.shape_3rd_derivatives[row][q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const FiniteElement<dim, spacedim> &
+FEValuesBase<dim, spacedim>::get_fe() const
+{
+  return *fe;
+}
+
+
+
+template <int dim, int spacedim>
+inline const Mapping<dim, spacedim> &
+FEValuesBase<dim, spacedim>::get_mapping() const
+{
+  return *mapping;
+}
+
+
+
+template <int dim, int spacedim>
+inline UpdateFlags
+FEValuesBase<dim, spacedim>::get_update_flags() const
+{
+  return this->update_flags;
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<Point<spacedim>> &
+FEValuesBase<dim, spacedim>::get_quadrature_points() const
+{
+  Assert(this->update_flags & update_quadrature_points,
+         ExcAccessToUninitializedField("update_quadrature_points"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.quadrature_points;
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<double> &
+FEValuesBase<dim, spacedim>::get_JxW_values() const
+{
+  Assert(this->update_flags & update_JxW_values,
+         ExcAccessToUninitializedField("update_JxW_values"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.JxW_values;
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<DerivativeForm<1, dim, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobians() const
+{
+  Assert(this->update_flags & update_jacobians,
+         ExcAccessToUninitializedField("update_jacobians"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobians;
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<DerivativeForm<2, dim, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobian_grads() const
+{
+  Assert(this->update_flags & update_jacobian_grads,
+         ExcAccessToUninitializedField("update_jacobians_grads"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_grads;
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<3, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian_pushed_forward_grad(
+  const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobian_pushed_forward_grads,
+         ExcAccessToUninitializedField("update_jacobian_pushed_forward_grads"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_pushed_forward_grads[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<Tensor<3, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobian_pushed_forward_grads() const
+{
+  Assert(this->update_flags & update_jacobian_pushed_forward_grads,
+         ExcAccessToUninitializedField("update_jacobian_pushed_forward_grads"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_pushed_forward_grads;
+}
+
+
+
+template <int dim, int spacedim>
+inline const DerivativeForm<3, dim, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian_2nd_derivative(
+  const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobian_2nd_derivatives,
+         ExcAccessToUninitializedField("update_jacobian_2nd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_2nd_derivatives[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<DerivativeForm<3, dim, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobian_2nd_derivatives() const
+{
+  Assert(this->update_flags & update_jacobian_2nd_derivatives,
+         ExcAccessToUninitializedField("update_jacobian_2nd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_2nd_derivatives;
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<4, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian_pushed_forward_2nd_derivative(
+  const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobian_pushed_forward_2nd_derivatives,
+         ExcAccessToUninitializedField(
+           "update_jacobian_pushed_forward_2nd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_pushed_forward_2nd_derivatives[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<Tensor<4, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobian_pushed_forward_2nd_derivatives() const
+{
+  Assert(this->update_flags & update_jacobian_pushed_forward_2nd_derivatives,
+         ExcAccessToUninitializedField(
+           "update_jacobian_pushed_forward_2nd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_pushed_forward_2nd_derivatives;
+}
+
+
+
+template <int dim, int spacedim>
+inline const DerivativeForm<4, dim, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian_3rd_derivative(
+  const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobian_3rd_derivatives,
+         ExcAccessToUninitializedField("update_jacobian_3rd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_3rd_derivatives[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<DerivativeForm<4, dim, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobian_3rd_derivatives() const
+{
+  Assert(this->update_flags & update_jacobian_3rd_derivatives,
+         ExcAccessToUninitializedField("update_jacobian_3rd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_3rd_derivatives;
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<5, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian_pushed_forward_3rd_derivative(
+  const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobian_pushed_forward_3rd_derivatives,
+         ExcAccessToUninitializedField(
+           "update_jacobian_pushed_forward_3rd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_pushed_forward_3rd_derivatives[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<Tensor<5, spacedim>> &
+FEValuesBase<dim, spacedim>::get_jacobian_pushed_forward_3rd_derivatives() const
+{
+  Assert(this->update_flags & update_jacobian_pushed_forward_3rd_derivatives,
+         ExcAccessToUninitializedField(
+           "update_jacobian_pushed_forward_3rd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.jacobian_pushed_forward_3rd_derivatives;
+}
+
+
+
+template <int dim, int spacedim>
+inline const std::vector<DerivativeForm<1, spacedim, dim>> &
+FEValuesBase<dim, spacedim>::get_inverse_jacobians() const
+{
+  Assert(this->update_flags & update_inverse_jacobians,
+         ExcAccessToUninitializedField("update_inverse_jacobians"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  return this->mapping_output.inverse_jacobians;
+}
+
+
+
+template <int dim, int spacedim>
+inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+FEValuesBase<dim, spacedim>::dof_indices() const
+{
+  return {0U, dofs_per_cell};
+}
+
+
+
+template <int dim, int spacedim>
+inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+FEValuesBase<dim, spacedim>::dof_indices_starting_at(
+  const unsigned int start_dof_index) const
+{
+  Assert(start_dof_index <= dofs_per_cell,
+         ExcIndexRange(start_dof_index, 0, dofs_per_cell + 1));
+  return {start_dof_index, dofs_per_cell};
+}
+
+
+
+template <int dim, int spacedim>
+inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+FEValuesBase<dim, spacedim>::dof_indices_ending_at(
+  const unsigned int end_dof_index) const
+{
+  Assert(end_dof_index < dofs_per_cell,
+         ExcIndexRange(end_dof_index, 0, dofs_per_cell));
+  return {0U, end_dof_index + 1};
+}
+
+
+
+template <int dim, int spacedim>
+inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
+FEValuesBase<dim, spacedim>::quadrature_point_indices() const
+{
+  return {0U, n_quadrature_points};
+}
+
+
+
+template <int dim, int spacedim>
+inline const Point<spacedim> &
+FEValuesBase<dim, spacedim>::quadrature_point(const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_quadrature_points,
+         ExcAccessToUninitializedField("update_quadrature_points"));
+  AssertIndexRange(q_point, this->mapping_output.quadrature_points.size());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  return this->mapping_output.quadrature_points[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline double
+FEValuesBase<dim, spacedim>::JxW(const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_JxW_values,
+         ExcAccessToUninitializedField("update_JxW_values"));
+  AssertIndexRange(q_point, this->mapping_output.JxW_values.size());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  return this->mapping_output.JxW_values[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const DerivativeForm<1, dim, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian(const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobians,
+         ExcAccessToUninitializedField("update_jacobians"));
+  AssertIndexRange(q_point, this->mapping_output.jacobians.size());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  return this->mapping_output.jacobians[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const DerivativeForm<2, dim, spacedim> &
+FEValuesBase<dim, spacedim>::jacobian_grad(const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_jacobian_grads,
+         ExcAccessToUninitializedField("update_jacobians_grads"));
+  AssertIndexRange(q_point, this->mapping_output.jacobian_grads.size());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  return this->mapping_output.jacobian_grads[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const DerivativeForm<1, spacedim, dim> &
+FEValuesBase<dim, spacedim>::inverse_jacobian(const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_inverse_jacobians,
+         ExcAccessToUninitializedField("update_inverse_jacobians"));
+  AssertIndexRange(q_point, this->mapping_output.inverse_jacobians.size());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  return this->mapping_output.inverse_jacobians[q_point];
+}
+
+
+
+template <int dim, int spacedim>
+inline const Tensor<1, spacedim> &
+FEValuesBase<dim, spacedim>::normal_vector(const unsigned int q_point) const
+{
+  Assert(this->update_flags & update_normal_vectors,
+         (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+           "update_normal_vectors")));
+  AssertIndexRange(q_point, this->mapping_output.normal_vectors.size());
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  return this->mapping_output.normal_vectors[q_point];
+}
+
+#endif
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
diff --git a/include/deal.II/fe/fe_values_views.h b/include/deal.II/fe/fe_values_views.h
new file mode 100644 (file)
index 0000000..5c03c9d
--- /dev/null
@@ -0,0 +1,2951 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2023 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_fe_values_views_h
+#define dealii_fe_values_views_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/derivative_form.h>
+#include <deal.II/base/exceptions.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/quadrature.h>
+#include <deal.II/base/std_cxx20/iota_view.h>
+#include <deal.II/base/subscriptor.h>
+#include <deal.II/base/symmetric_tensor.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe.h>
+#include <deal.II/fe/fe_update_flags.h>
+#include <deal.II/fe/fe_values_extractors.h>
+#include <deal.II/fe/mapping.h>
+#include <deal.II/fe/mapping_related_data.h>
+
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/hp/q_collection.h>
+
+#include <deal.II/lac/read_vector.h>
+
+#include <algorithm>
+#include <memory>
+#include <type_traits>
+
+DEAL_II_NAMESPACE_OPEN
+
+// Forward declaration
+#ifndef DOXYGEN
+template <int dim, int spacedim = dim>
+class FEValuesBase;
+#endif
+
+namespace internal
+{
+  /**
+   * A class whose specialization is used to define what type the curl of a
+   * vector valued function corresponds to.
+   */
+  template <int dim, typename NumberType = double>
+  struct CurlType;
+
+  /**
+   * A class whose specialization is used to define what type the curl of a
+   * vector valued function corresponds to.
+   *
+   * In 1d, the curl is a scalar.
+   */
+  template <typename NumberType>
+  struct CurlType<1, NumberType>
+  {
+    using type = Tensor<1, 1, NumberType>;
+  };
+
+  /**
+   * A class whose specialization is used to define what type the curl of a
+   * vector valued function corresponds to.
+   *
+   * In 2d, the curl is a scalar.
+   */
+  template <typename NumberType>
+  struct CurlType<2, NumberType>
+  {
+    using type = Tensor<1, 1, NumberType>;
+  };
+
+  /**
+   * A class whose specialization is used to define what type the curl of a
+   * vector valued function corresponds to.
+   *
+   * In 3d, the curl is a vector.
+   */
+  template <typename NumberType>
+  struct CurlType<3, NumberType>
+  {
+    using type = Tensor<1, 3, NumberType>;
+  };
+} // namespace internal
+
+
+
+/**
+ * A namespace for "views" on a FEValues, FEFaceValues, or FESubfaceValues
+ * object. A view represents only a certain part of the whole: whereas the
+ * FEValues object represents <i>all</i> values, gradients, or second
+ * derivatives of all components of a vector-valued element, views restrict
+ * the attention to only a single component or a subset of components. You
+ * typically get objects of classes defined in this namespace by applying
+ * FEValuesExtractors objects to a FEValues, FEFaceValues or FESubfaceValues
+ * objects using the square bracket operator.
+ *
+ * There are classes that present views for single scalar components, vector
+ * components consisting of <code>dim</code> elements, and symmetric second
+ * order tensor components consisting of <code>(dim*dim + dim)/2</code>
+ * elements
+ *
+ * See the description of the
+ * @ref vector_valued
+ * module for examples how to use the features of this namespace.
+ *
+ * @ingroup feaccess vector_valued
+ */
+namespace FEValuesViews
+{
+  /**
+   * A class representing a view to a single scalar component of a possibly
+   * vector-valued finite element. Views are discussed in the
+   * @ref vector_valued
+   * module.
+   *
+   * You get an object of this type if you apply a FEValuesExtractors::Scalar
+   * to an FEValues, FEFaceValues or FESubfaceValues object.
+   *
+   * @ingroup feaccess vector_valued
+   */
+  template <int dim, int spacedim = dim>
+  class Scalar
+  {
+  public:
+    /**
+     * An alias for the data type of values of the view this class
+     * represents. Since we deal with a single components, the value type is a
+     * scalar double.
+     */
+    using value_type = double;
+
+    /**
+     * An alias for the type of gradients of the view this class represents.
+     * Here, for a scalar component of the finite element, the gradient is a
+     * <code>Tensor@<1,dim@></code>.
+     */
+    using gradient_type = dealii::Tensor<1, spacedim>;
+
+    /**
+     * An alias for the type of second derivatives of the view this class
+     * represents. Here, for a scalar component of the finite element, the
+     * Hessian is a <code>Tensor@<2,dim@></code>.
+     */
+    using hessian_type = dealii::Tensor<2, spacedim>;
+
+    /**
+     * An alias for the type of third derivatives of the view this class
+     * represents. Here, for a scalar component of the finite element, the
+     * Third derivative is a <code>Tensor@<3,dim@></code>.
+     */
+    using third_derivative_type = dealii::Tensor<3, spacedim>;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * values of the view this class provides. This is the data type of
+     * scalar components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_value_type = typename ProductType<Number, value_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * gradients of the view this class provides. This is the data type of
+     * scalar components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_gradient_type =
+      typename ProductType<Number, gradient_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * laplacians of the view this class provides. This is the data type of
+     * scalar components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_laplacian_type =
+      typename ProductType<Number, value_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * hessians of the view this class provides. This is the data type of
+     * scalar components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_hessian_type =
+      typename ProductType<Number, hessian_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * third derivatives of the view this class provides. This is the data type
+     * of scalar components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_third_derivative_type =
+      typename ProductType<Number, third_derivative_type>::type;
+
+    /**
+     * A structure where for each shape function we pre-compute a bunch of
+     * data that will make later accesses much cheaper.
+     */
+    struct ShapeFunctionData
+    {
+      /**
+       * For each shape function, store whether the selected vector component
+       * may be nonzero. For primitive shape functions we know for sure
+       * whether a certain scalar component of a given shape function is
+       * nonzero, whereas for non-primitive shape functions this may not be
+       * entirely clear (e.g. for RT elements it depends on the shape of a
+       * cell).
+       */
+      bool is_nonzero_shape_function_component;
+
+      /**
+       * For each shape function, store the row index within the shape_values,
+       * shape_gradients, and shape_hessians tables (the column index is the
+       * quadrature point index). If the shape function is primitive, then we
+       * can get this information from the shape_function_to_row_table of the
+       * FEValues object; otherwise, we have to work a bit harder to compute
+       * this information.
+       */
+      unsigned int row_index;
+    };
+
+    /**
+     * Default constructor. Creates an invalid object.
+     */
+    Scalar();
+
+    /**
+     * Constructor for an object that represents a single scalar component of
+     * a FEValuesBase object (or of one of the classes derived from
+     * FEValuesBase).
+     */
+    Scalar(const FEValuesBase<dim, spacedim> &fe_values_base,
+           const unsigned int                 component);
+
+    /**
+     * Copy constructor. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    Scalar(const Scalar<dim, spacedim> &) = delete;
+
+    /**
+     * Move constructor.
+     */
+    // NOLINTNEXTLINE OSX does not compile with noexcept
+    Scalar(Scalar<dim, spacedim> &&) = default;
+
+    /**
+     * Destructor.
+     */
+    ~Scalar() = default;
+
+    /**
+     * Copy operator. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    Scalar &
+    operator=(const Scalar<dim, spacedim> &) = delete;
+
+    /**
+     * Move assignment operator.
+     */
+    Scalar &
+    operator=(Scalar<dim, spacedim> &&) noexcept = default;
+
+    /**
+     * Return the value of the vector component selected by this view, for the
+     * shape function and quadrature point selected by the arguments.
+     *
+     * @param shape_function Number of the shape function to be evaluated.
+     * Note that this number runs from zero to dofs_per_cell, even in the case
+     * of an FEFaceValues or FESubfaceValues object.
+     *
+     * @param q_point Number of the quadrature point at which function is to
+     * be evaluated.
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    value_type
+    value(const unsigned int shape_function, const unsigned int q_point) const;
+
+    /**
+     * Return the gradient (a tensor of rank 1) of the vector component
+     * selected by this view, for the shape function and quadrature point
+     * selected by the arguments.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    gradient_type
+    gradient(const unsigned int shape_function,
+             const unsigned int q_point) const;
+
+    /**
+     * Return the Hessian (the tensor of rank 2 of all second derivatives) of
+     * the vector component selected by this view, for the shape function and
+     * quadrature point selected by the arguments.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_hessians}
+     */
+    hessian_type
+    hessian(const unsigned int shape_function,
+            const unsigned int q_point) const;
+
+    /**
+     * Return the tensor of rank 3 of all third derivatives of the vector
+     * component selected by this view, for the shape function and quadrature
+     * point selected by the arguments.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_third_derivatives}
+     */
+    third_derivative_type
+    third_derivative(const unsigned int shape_function,
+                     const unsigned int q_point) const;
+
+    /**
+     * Return the values of the selected scalar component of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_values function but it only works on the
+     * selected scalar component.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the values of shape functions (i.e., @p value_type) times the
+     * type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    template <typename Number>
+    void
+    get_function_values(const ReadVector<Number> &                fe_function,
+                        std::vector<solution_value_type<Number>> &values) const;
+
+    /**
+     * Same as above, but using a vector of local degree-of-freedom values. In
+     * other words, instead of extracting the nodal values of the degrees of
+     * freedom located on the current cell from a global vector associated with
+     * a DoFHandler object (as the function above does), this function instead
+     * takes these local nodal values through its first argument. A typical
+     * way to obtain such a vector is by calling code such as
+     * @code
+     *   cell->get_dof_values (dof_values, local_dof_values);
+     * @endcode
+     * (See DoFCellAccessor::get_dof_values() for more information on this
+     * function.) The point of the current function is then that one could
+     * modify these local values first, for example by applying a limiter
+     * or by ensuring that all nodal values are positive, before evaluating
+     * the finite element field that corresponds to these local values on the
+     * current cell. Another application is where one wants to postprocess
+     * the solution on a cell into a different finite element space on every
+     * cell, without actually creating a corresponding DoFHandler -- in that
+     * case, all one would compute is a local representation of that
+     * postprocessed function, characterized by its nodal values; this function
+     * then allows the evaluation of that representation at quadrature points.
+     *
+     * @param[in] dof_values A vector of local nodal values. This vector must
+     *   have a length equal to number of DoFs on the current cell, and must
+     *   be ordered in the same order as degrees of freedom are numbered on
+     *   the reference cell.
+     *
+     * @param[out] values A vector of values of the given finite element field,
+     *   at the quadrature points on the current object.
+     *
+     * @tparam InputVector The @p InputVector type must allow creation
+     *   of an ArrayView object from it; this is satisfied by the
+     *   `std::vector` class, among others.
+     */
+    template <class InputVector>
+    void
+    get_function_values_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_value_type<typename InputVector::value_type>>
+        &values) const;
+
+    /**
+     * Return the gradients of the selected scalar component of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_gradients function but it only works on the
+     * selected scalar component.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the gradients of shape functions (i.e., @p gradient_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_gradients(
+      const ReadVector<Number> &                   fe_function,
+      std::vector<solution_gradient_type<Number>> &gradients) const;
+
+    /**
+     * This function relates to get_function_gradients() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_gradients_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_gradient_type<typename InputVector::value_type>>
+        &gradients) const;
+
+    /**
+     * Return the Hessians of the selected scalar component of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_hessians function but it only works on the
+     * selected scalar component.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the Hessians of shape functions (i.e., @p hessian_type) times
+     * the type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_hessians}
+     */
+    template <typename Number>
+    void
+    get_function_hessians(
+      const ReadVector<Number> &                  fe_function,
+      std::vector<solution_hessian_type<Number>> &hessians) const;
+
+    /**
+     * This function relates to get_function_hessians() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_hessians_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_hessian_type<typename InputVector::value_type>>
+        &hessians) const;
+
+
+    /**
+     * Return the Laplacians of the selected scalar component of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called. The
+     * Laplacians are the trace of the Hessians.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_laplacians function but it only works on the
+     * selected scalar component.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the Laplacians of shape functions (i.e., @p value_type) times
+     * the type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_hessians}
+     */
+    template <typename Number>
+    void
+    get_function_laplacians(
+      const ReadVector<Number> &                    fe_function,
+      std::vector<solution_laplacian_type<Number>> &laplacians) const;
+
+    /**
+     * This function relates to get_function_laplacians() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_laplacians_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_laplacian_type<typename InputVector::value_type>>
+        &laplacians) const;
+
+
+    /**
+     * Return the third derivatives of the selected scalar component of the
+     * finite element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_third_derivatives function but it only works
+     * on the selected scalar component.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the third derivatives of shape functions (i.e., @p
+     * third_derivative_type) times the type used to store the values of the
+     * unknowns $U_j$ of your finite element vector $U$ (represented by the @p
+     * fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_third_derivatives}
+     */
+    template <typename Number>
+    void
+    get_function_third_derivatives(
+      const ReadVector<Number> &                           fe_function,
+      std::vector<solution_third_derivative_type<Number>> &third_derivatives)
+      const;
+
+    /**
+     * This function relates to get_function_third_derivatives() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_third_derivatives_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<
+        solution_third_derivative_type<typename InputVector::value_type>>
+        &third_derivatives) const;
+
+
+  private:
+    /**
+     * A pointer to the FEValuesBase object we operate on.
+     */
+    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
+
+    /**
+     * The single scalar component this view represents of the FEValuesBase
+     * object.
+     */
+    const unsigned int component;
+
+    /**
+     * Store the data about shape functions.
+     */
+    std::vector<ShapeFunctionData> shape_function_data;
+  };
+
+
+
+  /**
+   * A class representing a view to a set of <code>spacedim</code> components
+   * forming a vector part of a vector-valued finite element. Views are
+   * discussed in the
+   * @ref vector_valued
+   * module.
+   *
+   * Note that in the current context, a vector is meant in the sense physics
+   * uses it: it has <code>spacedim</code> components that behave in specific
+   * ways under coordinate system transformations. Examples include velocity
+   * or displacement fields. This is opposed to how mathematics uses the word
+   * "vector" (and how we use this word in other contexts in the library, for
+   * example in the Vector class), where it really stands for a collection of
+   * numbers. An example of this latter use of the word could be the set of
+   * concentrations of chemical species in a flame; however, these are really
+   * just a collection of scalar variables, since they do not change if the
+   * coordinate system is rotated, unlike the components of a velocity vector,
+   * and consequently, this class should not be used for this context.
+   *
+   * This class allows to query the value, gradient and divergence of
+   * (components of) shape functions and solutions representing vectors. The
+   * gradient of a vector $d_{k}, 0\le k<\text{dim}$ is defined as $S_{ij} =
+   * \frac{\partial d_{i}}{\partial x_j}, 0\le i,j<\text{dim}$.
+   *
+   * You get an object of this type if you apply a FEValuesExtractors::Vector
+   * to an FEValues, FEFaceValues or FESubfaceValues object.
+   *
+   * @ingroup feaccess vector_valued
+   */
+  template <int dim, int spacedim = dim>
+  class Vector
+  {
+  public:
+    /**
+     * An alias for the data type of values of the view this class
+     * represents. Since we deal with a set of <code>dim</code> components,
+     * the value type is a Tensor<1,spacedim>.
+     */
+    using value_type = dealii::Tensor<1, spacedim>;
+
+    /**
+     * An alias for the type of gradients of the view this class represents.
+     * Here, for a set of <code>dim</code> components of the finite element,
+     * the gradient is a <code>Tensor@<2,spacedim@></code>.
+     *
+     * See the general documentation of this class for how exactly the
+     * gradient of a vector is defined.
+     */
+    using gradient_type = dealii::Tensor<2, spacedim>;
+
+    /**
+     * An alias for the type of symmetrized gradients of the view this class
+     * represents. Here, for a set of <code>dim</code> components of the
+     * finite element, the symmetrized gradient is a
+     * <code>SymmetricTensor@<2,spacedim@></code>.
+     *
+     * The symmetric gradient of a vector field $\mathbf v$ is defined as
+     * $\varepsilon(\mathbf v)=\frac 12 (\nabla \mathbf v + \nabla \mathbf
+     * v^T)$.
+     */
+    using symmetric_gradient_type = dealii::SymmetricTensor<2, spacedim>;
+
+    /**
+     * An alias for the type of the divergence of the view this class
+     * represents. Here, for a set of <code>dim</code> components of the
+     * finite element, the divergence of course is a scalar.
+     */
+    using divergence_type = double;
+
+    /**
+     * An alias for the type of the curl of the view this class represents.
+     * Here, for a set of <code>spacedim=2</code> components of the finite
+     * element, the curl is a <code>Tensor@<1, 1@></code>. For
+     * <code>spacedim=3</code> it is a <code>Tensor@<1, dim@></code>.
+     */
+    using curl_type = typename dealii::internal::CurlType<spacedim>::type;
+
+    /**
+     * An alias for the type of second derivatives of the view this class
+     * represents. Here, for a set of <code>dim</code> components of the
+     * finite element, the Hessian is a <code>Tensor@<3,dim@></code>.
+     */
+    using hessian_type = dealii::Tensor<3, spacedim>;
+
+    /**
+     * An alias for the type of third derivatives of the view this class
+     * represents. Here, for a set of <code>dim</code> components of the
+     * finite element, the third derivative is a <code>Tensor@<4,dim@></code>.
+     */
+    using third_derivative_type = dealii::Tensor<4, spacedim>;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * values of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_value_type = typename ProductType<Number, value_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * gradients of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_gradient_type =
+      typename ProductType<Number, gradient_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * symmetric gradients of the view this class provides. This is the data
+     * type of vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_symmetric_gradient_type =
+      typename ProductType<Number, symmetric_gradient_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * divergences of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_divergence_type =
+      typename ProductType<Number, divergence_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * laplacians of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_laplacian_type =
+      typename ProductType<Number, value_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * curls of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_curl_type = typename ProductType<Number, curl_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * hessians of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_hessian_type =
+      typename ProductType<Number, hessian_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * third derivatives of the view this class provides. This is the data type
+     * of vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_third_derivative_type =
+      typename ProductType<Number, third_derivative_type>::type;
+
+    /**
+     * A structure where for each shape function we pre-compute a bunch of
+     * data that will make later accesses much cheaper.
+     */
+    struct ShapeFunctionData
+    {
+      /**
+       * For each pair (shape function,component within vector), store whether
+       * the selected vector component may be nonzero. For primitive shape
+       * functions we know for sure whether a certain scalar component of a
+       * given shape function is nonzero, whereas for non-primitive shape
+       * functions this may not be entirely clear (e.g. for RT elements it
+       * depends on the shape of a cell).
+       */
+      bool is_nonzero_shape_function_component[spacedim];
+
+      /**
+       * For each pair (shape function, component within vector), store the
+       * row index within the shape_values, shape_gradients, and
+       * shape_hessians tables (the column index is the quadrature point
+       * index). If the shape function is primitive, then we can get this
+       * information from the shape_function_to_row_table of the FEValues
+       * object; otherwise, we have to work a bit harder to compute this
+       * information.
+       */
+      unsigned int row_index[spacedim];
+
+      /**
+       * For each shape function say the following: if only a single entry in
+       * is_nonzero_shape_function_component for this shape function is
+       * nonzero, then store the corresponding value of row_index and
+       * single_nonzero_component_index represents the index between 0 and dim
+       * for which it is attained. If multiple components are nonzero, then
+       * store -1. If no components are nonzero then store -2.
+       */
+      int          single_nonzero_component;
+      unsigned int single_nonzero_component_index;
+    };
+
+    /**
+     * Default constructor. Creates an invalid object.
+     */
+    Vector();
+
+    /**
+     * Constructor for an object that represents dim components of a
+     * FEValuesBase object (or of one of the classes derived from
+     * FEValuesBase), representing a vector-valued variable.
+     *
+     * The second argument denotes the index of the first component of the
+     * selected vector.
+     */
+    Vector(const FEValuesBase<dim, spacedim> &fe_values_base,
+           const unsigned int                 first_vector_component);
+
+    /**
+     * Copy constructor. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    Vector(const Vector<dim, spacedim> &) = delete;
+
+    /**
+     * Move constructor.
+     */
+    // NOLINTNEXTLINE OSX does not compile with noexcept
+    Vector(Vector<dim, spacedim> &&) = default;
+
+    /**
+     * Destructor.
+     */
+    ~Vector() = default;
+
+    /**
+     * Copy operator. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    Vector &
+    operator=(const Vector<dim, spacedim> &) = delete;
+
+    /**
+     * Move assignment operator.
+     */
+    // NOLINTNEXTLINE OSX does not compile with noexcept
+    Vector &
+    operator=(Vector<dim, spacedim> &&) = default; // NOLINT
+
+    /**
+     * Return the value of the vector components selected by this view, for
+     * the shape function and quadrature point selected by the arguments.
+     * Here, since the view represents a vector-valued part of the FEValues
+     * object with <code>dim</code> components, the return type is a tensor of
+     * rank 1 with <code>dim</code> components.
+     *
+     * @param shape_function Number of the shape function to be evaluated.
+     * Note that this number runs from zero to dofs_per_cell, even in the case
+     * of an FEFaceValues or FESubfaceValues object.
+     *
+     * @param q_point Number of the quadrature point at which function is to
+     * be evaluated.
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    value_type
+    value(const unsigned int shape_function, const unsigned int q_point) const;
+
+    /**
+     * Return the gradient (a tensor of rank 2) of the vector component
+     * selected by this view, for the shape function and quadrature point
+     * selected by the arguments.
+     *
+     * See the general documentation of this class for how exactly the
+     * gradient of a vector is defined.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    gradient_type
+    gradient(const unsigned int shape_function,
+             const unsigned int q_point) const;
+
+    /**
+     * Return the symmetric gradient (a symmetric tensor of rank 2) of the
+     * vector component selected by this view, for the shape function and
+     * quadrature point selected by the arguments.
+     *
+     * The symmetric gradient is defined as $\frac 12 [(\nabla \phi_i(x_q)) +
+     * (\nabla \phi_i(x_q))^T]$, where $\phi_i$ represents the
+     * <code>dim</code> components selected from the FEValuesBase object, and
+     * $x_q$ is the location of the $q$-th quadrature point.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    symmetric_gradient_type
+    symmetric_gradient(const unsigned int shape_function,
+                       const unsigned int q_point) const;
+
+    /**
+     * Return the scalar divergence of the vector components selected by this
+     * view, for the shape function and quadrature point selected by the
+     * arguments.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    divergence_type
+    divergence(const unsigned int shape_function,
+               const unsigned int q_point) const;
+
+    /**
+     * Return the vector curl of the vector components selected by this view,
+     * for the shape function and quadrature point selected by the arguments.
+     * For 1d this function does not make any sense. Thus it is not
+     * implemented for <code>spacedim=1</code>.  In 2d the curl is defined as
+     * @f{equation*}{
+     * \operatorname{curl}(u) \dealcoloneq \frac{du_2}{dx} -\frac{du_1}{dy},
+     * @f}
+     * whereas in 3d it is given by
+     * @f{equation*}{
+     * \operatorname{curl}(u) \dealcoloneq \left( \begin{array}{c}
+     * \frac{du_3}{dy}-\frac{du_2}{dz}\\ \frac{du_1}{dz}-\frac{du_3}{dx}\\
+     * \frac{du_2}{dx}-\frac{du_1}{dy} \end{array} \right).
+     * @f}
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    curl_type
+    curl(const unsigned int shape_function, const unsigned int q_point) const;
+
+    /**
+     * Return the Hessian (the tensor of rank 2 of all second derivatives) of
+     * the vector components selected by this view, for the shape function and
+     * quadrature point selected by the arguments.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_hessians}
+     */
+    hessian_type
+    hessian(const unsigned int shape_function,
+            const unsigned int q_point) const;
+
+    /**
+     * Return the tensor of rank 3 of all third derivatives of the vector
+     * components selected by this view, for the shape function and quadrature
+     * point selected by the arguments.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_3rd_derivatives}
+     */
+    third_derivative_type
+    third_derivative(const unsigned int shape_function,
+                     const unsigned int q_point) const;
+
+    /**
+     * Return the values of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_values function but it only works on the
+     * selected vector components.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the values of shape functions (i.e., @p value_type) times the
+     * type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    template <typename Number>
+    void
+    get_function_values(const ReadVector<Number> &                fe_function,
+                        std::vector<solution_value_type<Number>> &values) const;
+
+    /**
+     * Same as above, but using a vector of local degree-of-freedom values. In
+     * other words, instead of extracting the nodal values of the degrees of
+     * freedom located on the current cell from a global vector associated with
+     * a DoFHandler object (as the function above does), this function instead
+     * takes these local nodal values through its first argument. A typical
+     * way to obtain such a vector is by calling code such as
+     * @code
+     *   cell->get_dof_values (dof_values, local_dof_values);
+     * @endcode
+     * (See DoFCellAccessor::get_dof_values() for more information on this
+     * function.) The point of the current function is then that one could
+     * modify these local values first, for example by applying a limiter
+     * or by ensuring that all nodal values are positive, before evaluating
+     * the finite element field that corresponds to these local values on the
+     * current cell. Another application is where one wants to postprocess
+     * the solution on a cell into a different finite element space on every
+     * cell, without actually creating a corresponding DoFHandler -- in that
+     * case, all one would compute is a local representation of that
+     * postprocessed function, characterized by its nodal values; this function
+     * then allows the evaluation of that representation at quadrature points.
+     *
+     * @param[in] dof_values A vector of local nodal values. This vector must
+     *   have a length equal to number of DoFs on the current cell, and must
+     *   be ordered in the same order as degrees of freedom are numbered on
+     *   the reference cell.
+     *
+     * @param[out] values A vector of values of the given finite element field,
+     *   at the quadrature points on the current object.
+     *
+     * @tparam InputVector The @p InputVector type must allow creation
+     *   of an ArrayView object from it; this is satisfied by the
+     *   `std::vector` class, among others.
+     */
+    template <class InputVector>
+    void
+    get_function_values_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_value_type<typename InputVector::value_type>>
+        &values) const;
+
+    /**
+     * Return the gradients of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_gradients function but it only works on the
+     * selected vector components.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the gradients of shape functions (i.e., @p gradient_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_gradients(
+      const ReadVector<Number> &                   fe_function,
+      std::vector<solution_gradient_type<Number>> &gradients) const;
+
+    /**
+     * This function relates to get_function_gradients() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_gradients_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_gradient_type<typename InputVector::value_type>>
+        &gradients) const;
+
+    /**
+     * Return the symmetrized gradients of the selected vector components of
+     * the finite element function characterized by <tt>fe_function</tt> at
+     * the quadrature points of the cell, face or subface selected the last
+     * time the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * The symmetric gradient of a vector field $\mathbf v$ is defined as
+     * $\varepsilon(\mathbf v)=\frac 12 (\nabla \mathbf v + \nabla \mathbf
+     * v^T)$.
+     *
+     * @note There is no equivalent function such as
+     * FEValuesBase::get_function_symmetric_gradients in the FEValues classes
+     * but the information can be obtained from
+     * FEValuesBase::get_function_gradients, of course.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the symmetric gradients of shape functions (i.e., @p
+     * symmetric_gradient_type) times the type used to store the values of the
+     * unknowns $U_j$ of your finite element vector $U$ (represented by the @p
+     * fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_symmetric_gradients(
+      const ReadVector<Number> &fe_function,
+      std::vector<solution_symmetric_gradient_type<Number>>
+        &symmetric_gradients) const;
+
+    /**
+     * This function relates to get_function_symmetric_gradients() in the same
+     * way as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_symmetric_gradients_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<
+        solution_symmetric_gradient_type<typename InputVector::value_type>>
+        &symmetric_gradients) const;
+
+    /**
+     * Return the divergence of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * There is no equivalent function such as
+     * FEValuesBase::get_function_divergences in the FEValues classes but the
+     * information can be obtained from FEValuesBase::get_function_gradients,
+     * of course.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the divergences of shape functions (i.e., @p divergence_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_divergences(
+      const ReadVector<Number> &                     fe_function,
+      std::vector<solution_divergence_type<Number>> &divergences) const;
+
+    /**
+     * This function relates to get_function_divergences() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_divergences_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_divergence_type<typename InputVector::value_type>>
+        &divergences) const;
+
+    /**
+     * Return the curl of the selected vector components of the finite element
+     * function characterized by <tt>fe_function</tt> at the quadrature points
+     * of the cell, face or subface selected the last time the <tt>reinit</tt>
+     * function of the FEValues object was called.
+     *
+     * There is no equivalent function such as
+     * FEValuesBase::get_function_curls in the FEValues classes but the
+     * information can be obtained from FEValuesBase::get_function_gradients,
+     * of course.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the curls of shape functions (i.e., @p curl_type) times the
+     * type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_curls(const ReadVector<Number> &               fe_function,
+                       std::vector<solution_curl_type<Number>> &curls) const;
+
+    /**
+     * This function relates to get_function_curls() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_curls_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_curl_type<typename InputVector::value_type>> &curls)
+      const;
+
+    /**
+     * Return the Hessians of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_hessians function but it only works on the
+     * selected vector components.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the Hessians of shape functions (i.e., @p hessian_type) times
+     * the type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_hessians}
+     */
+    template <typename Number>
+    void
+    get_function_hessians(
+      const ReadVector<Number> &                  fe_function,
+      std::vector<solution_hessian_type<Number>> &hessians) const;
+
+    /**
+     * This function relates to get_function_hessians() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_hessians_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_hessian_type<typename InputVector::value_type>>
+        &hessians) const;
+
+    /**
+     * Return the Laplacians of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called. The
+     * Laplacians are the trace of the Hessians.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_laplacians function but it only works on the
+     * selected vector components.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the Laplacians of shape functions (i.e., @p laplacian_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_hessians}
+     */
+    template <typename Number>
+    void
+    get_function_laplacians(
+      const ReadVector<Number> &                    fe_function,
+      std::vector<solution_laplacian_type<Number>> &laplacians) const;
+
+    /**
+     * This function relates to get_function_laplacians() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_laplacians_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_laplacian_type<typename InputVector::value_type>>
+        &laplacians) const;
+
+    /**
+     * Return the third derivatives of the selected scalar component of the
+     * finite element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_third_derivatives function but it only works
+     * on the selected scalar component.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the third derivatives of shape functions (i.e., @p
+     * third_derivative_type) times the type used to store the values of the
+     * unknowns $U_j$ of your finite element vector $U$ (represented by the @p
+     * fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_third_derivatives}
+     */
+    template <typename Number>
+    void
+    get_function_third_derivatives(
+      const ReadVector<Number> &                           fe_function,
+      std::vector<solution_third_derivative_type<Number>> &third_derivatives)
+      const;
+
+    /**
+     * This function relates to get_function_third_derivatives() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_third_derivatives_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<
+        solution_third_derivative_type<typename InputVector::value_type>>
+        &third_derivatives) const;
+
+  private:
+    /**
+     * A pointer to the FEValuesBase object we operate on.
+     */
+    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
+
+    /**
+     * The first component of the vector this view represents of the
+     * FEValuesBase object.
+     */
+    const unsigned int first_vector_component;
+
+    /**
+     * Store the data about shape functions.
+     */
+    std::vector<ShapeFunctionData> shape_function_data;
+  };
+
+
+  template <int rank, int dim, int spacedim = dim>
+  class SymmetricTensor;
+
+  /**
+   * A class representing a view to a set of <code>(dim*dim + dim)/2</code>
+   * components forming a symmetric second-order tensor from a vector-valued
+   * finite element. Views are discussed in the
+   * @ref vector_valued
+   * module.
+   *
+   * This class allows to query the value and divergence of (components of)
+   * shape functions and solutions representing symmetric tensors. The
+   * divergence of a symmetric tensor $S_{ij}, 0\le i,j<\text{dim}$ is defined
+   * as $d_i = \sum_j \frac{\partial S_{ij}}{\partial x_j}, 0\le
+   * i<\text{dim}$, which due to the symmetry of the tensor is also $d_i =
+   * \sum_j \frac{\partial S_{ji}}{\partial x_j}$.  In other words, it due to
+   * the symmetry of $S$ it does not matter whether we apply the nabla
+   * operator by row or by column to get the divergence.
+   *
+   * You get an object of this type if you apply a
+   * FEValuesExtractors::SymmetricTensor to an FEValues, FEFaceValues or
+   * FESubfaceValues object.
+   *
+   * @ingroup feaccess vector_valued
+   */
+  template <int dim, int spacedim>
+  class SymmetricTensor<2, dim, spacedim>
+  {
+  public:
+    /**
+     * An alias for the data type of values of the view this class
+     * represents. Since we deal with a set of <code>(dim*dim + dim)/2</code>
+     * components (i.e. the unique components of a symmetric second-order
+     * tensor), the value type is a SymmetricTensor<2,spacedim>.
+     */
+    using value_type = dealii::SymmetricTensor<2, spacedim>;
+
+    /**
+     * An alias for the type of the divergence of the view this class
+     * represents. Here, for a set of <code>(dim*dim + dim)/2</code> unique
+     * components of the finite element representing a symmetric second-order
+     * tensor, the divergence of course is a * <code>Tensor@<1,dim@></code>.
+     *
+     * See the general discussion of this class for a definition of the
+     * divergence.
+     */
+    using divergence_type = dealii::Tensor<1, spacedim>;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * values of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_value_type = typename ProductType<Number, value_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * divergences of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_divergence_type =
+      typename ProductType<Number, divergence_type>::type;
+
+
+    /**
+     * A structure where for each shape function we pre-compute a bunch of
+     * data that will make later accesses much cheaper.
+     */
+    struct ShapeFunctionData
+    {
+      /**
+       * For each pair (shape function,component within vector), store whether
+       * the selected vector component may be nonzero. For primitive shape
+       * functions we know for sure whether a certain scalar component of a
+       * given shape function is nonzero, whereas for non-primitive shape
+       * functions this may not be entirely clear (e.g. for RT elements it
+       * depends on the shape of a cell).
+       */
+      bool is_nonzero_shape_function_component
+        [value_type::n_independent_components];
+
+      /**
+       * For each pair (shape function, component within vector), store the
+       * row index within the shape_values, shape_gradients, and
+       * shape_hessians tables (the column index is the quadrature point
+       * index). If the shape function is primitive, then we can get this
+       * information from the shape_function_to_row_table of the FEValues
+       * object; otherwise, we have to work a bit harder to compute this
+       * information.
+       */
+      unsigned int row_index[value_type::n_independent_components];
+
+      /**
+       * For each shape function say the following: if only a single entry in
+       * is_nonzero_shape_function_component for this shape function is
+       * nonzero, then store the corresponding value of row_index and
+       * single_nonzero_component_index represents the index between 0 and
+       * (dim^2 + dim)/2 for which it is attained. If multiple components are
+       * nonzero, then store -1. If no components are nonzero then store -2.
+       */
+      int single_nonzero_component;
+
+      /**
+       * Index of the @p single_nonzero_component .
+       */
+      unsigned int single_nonzero_component_index;
+    };
+
+    /**
+     * Default constructor. Creates an invalid object.
+     */
+    SymmetricTensor();
+
+    /**
+     * Constructor for an object that represents <code>(dim*dim +
+     * dim)/2</code> components of a FEValuesBase object (or of one of the
+     * classes derived from FEValuesBase), representing the unique components
+     * comprising a symmetric second- order tensor valued variable.
+     *
+     * The second argument denotes the index of the first component of the
+     * selected symmetric second order tensor.
+     */
+    SymmetricTensor(const FEValuesBase<dim, spacedim> &fe_values_base,
+                    const unsigned int                 first_tensor_component);
+
+    /**
+     * Copy constructor. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    SymmetricTensor(const SymmetricTensor<2, dim, spacedim> &) = delete;
+
+    /**
+     * Move constructor.
+     */
+    // NOLINTNEXTLINE OSX does not compile with noexcept
+    SymmetricTensor(SymmetricTensor<2, dim, spacedim> &&) = default;
+
+    /**
+     * Copy operator. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    SymmetricTensor &
+    operator=(const SymmetricTensor<2, dim, spacedim> &) = delete;
+
+    /**
+     * Move assignment operator.
+     */
+    SymmetricTensor &
+    operator=(SymmetricTensor<2, dim, spacedim> &&) noexcept = default;
+
+    /**
+     * Return the value of the vector components selected by this view, for
+     * the shape function and quadrature point selected by the arguments.
+     * Here, since the view represents a vector-valued part of the FEValues
+     * object with <code>(dim*dim + dim)/2</code> components (the unique
+     * components of a symmetric second-order tensor), the return type is a
+     * symmetric tensor of rank 2.
+     *
+     * @param shape_function Number of the shape function to be evaluated.
+     * Note that this number runs from zero to dofs_per_cell, even in the case
+     * of an FEFaceValues or FESubfaceValues object.
+     *
+     * @param q_point Number of the quadrature point at which function is to
+     * be evaluated.
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    value_type
+    value(const unsigned int shape_function, const unsigned int q_point) const;
+
+    /**
+     * Return the vector divergence of the vector components selected by this
+     * view, for the shape function and quadrature point selected by the
+     * arguments.
+     *
+     * See the general discussion of this class for a definition of the
+     * divergence.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    divergence_type
+    divergence(const unsigned int shape_function,
+               const unsigned int q_point) const;
+
+    /**
+     * Return the values of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_values function but it only works on the
+     * selected vector components.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the values of shape functions (i.e., @p value_type) times the
+     * type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    template <typename Number>
+    void
+    get_function_values(const ReadVector<Number> &                fe_function,
+                        std::vector<solution_value_type<Number>> &values) const;
+
+    /**
+     * Same as above, but using a vector of local degree-of-freedom values. In
+     * other words, instead of extracting the nodal values of the degrees of
+     * freedom located on the current cell from a global vector associated with
+     * a DoFHandler object (as the function above does), this function instead
+     * takes these local nodal values through its first argument. A typical
+     * way to obtain such a vector is by calling code such as
+     * @code
+     *   cell->get_dof_values (dof_values, local_dof_values);
+     * @endcode
+     * (See DoFCellAccessor::get_dof_values() for more information on this
+     * function.) The point of the current function is then that one could
+     * modify these local values first, for example by applying a limiter
+     * or by ensuring that all nodal values are positive, before evaluating
+     * the finite element field that corresponds to these local values on the
+     * current cell. Another application is where one wants to postprocess
+     * the solution on a cell into a different finite element space on every
+     * cell, without actually creating a corresponding DoFHandler -- in that
+     * case, all one would compute is a local representation of that
+     * postprocessed function, characterized by its nodal values; this function
+     * then allows the evaluation of that representation at quadrature points.
+     *
+     * @param[in] dof_values A vector of local nodal values. This vector must
+     *   have a length equal to number of DoFs on the current cell, and must
+     *   be ordered in the same order as degrees of freedom are numbered on
+     *   the reference cell.
+     *
+     * @param[out] values A vector of values of the given finite element field,
+     *   at the quadrature points on the current object.
+     *
+     * @tparam InputVector The @p InputVector type must allow creation
+     *   of an ArrayView object from it; this is satisfied by the
+     *   `std::vector` class, among others.
+     */
+    template <class InputVector>
+    void
+    get_function_values_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_value_type<typename InputVector::value_type>>
+        &values) const;
+
+    /**
+     * Return the divergence of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * There is no equivalent function such as
+     * FEValuesBase::get_function_divergences in the FEValues classes but the
+     * information can be obtained from FEValuesBase::get_function_gradients,
+     * of course.
+     *
+     * See the general discussion of this class for a definition of the
+     * divergence.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the divergences of shape functions (i.e., @p divergence_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_divergences(
+      const ReadVector<Number> &                     fe_function,
+      std::vector<solution_divergence_type<Number>> &divergences) const;
+
+    /**
+     * This function relates to get_function_divergences() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_divergences_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_divergence_type<typename InputVector::value_type>>
+        &divergences) const;
+
+  private:
+    /**
+     * A pointer to the FEValuesBase object we operate on.
+     */
+    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
+
+    /**
+     * The first component of the vector this view represents of the
+     * FEValuesBase object.
+     */
+    const unsigned int first_tensor_component;
+
+    /**
+     * Store the data about shape functions.
+     */
+    std::vector<ShapeFunctionData> shape_function_data;
+  };
+
+
+  template <int rank, int dim, int spacedim = dim>
+  class Tensor;
+
+  /**
+   * A class representing a view to a set of <code>dim*dim</code> components
+   * forming a second-order tensor from a vector-valued finite element. Views
+   * are discussed in the
+   * @ref vector_valued
+   * module.
+   *
+   * This class allows to query the value, gradient and divergence of
+   * (components of) shape functions and solutions representing tensors. The
+   * divergence of a tensor $T_{ij},\, 0\le i,j<\text{dim}$ is defined as $d_i =
+   * \sum_j \frac{\partial T_{ij}}{\partial x_j}, \, 0\le i<\text{dim}$, whereas
+   * its gradient is $G_{ijk} = \frac{\partial T_{ij}}{\partial x_k}$.
+   *
+   * You get an object of this type if you apply a FEValuesExtractors::Tensor
+   * to an FEValues, FEFaceValues or FESubfaceValues object.
+   *
+   * @ingroup feaccess vector_valued
+   */
+  template <int dim, int spacedim>
+  class Tensor<2, dim, spacedim>
+  {
+  public:
+    /**
+     * Data type for what you get when you apply an extractor of this kind to
+     * a vector-valued finite element.
+     */
+    using value_type = dealii::Tensor<2, spacedim>;
+
+    /**
+     * Data type for taking the divergence of a tensor: a vector.
+     */
+    using divergence_type = dealii::Tensor<1, spacedim>;
+
+    /**
+     * Data type for taking the gradient of a second order tensor: a third order
+     * tensor.
+     */
+    using gradient_type = dealii::Tensor<3, spacedim>;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * values of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_value_type = typename ProductType<Number, value_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * divergences of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_divergence_type =
+      typename ProductType<Number, divergence_type>::type;
+
+    /**
+     * An alias for the data type of the product of a @p Number and the
+     * gradient of the view this class provides. This is the data type of
+     * vector components of a finite element field whose degrees of
+     * freedom are described by a vector with elements of type @p Number.
+     */
+    template <typename Number>
+    using solution_gradient_type =
+      typename ProductType<Number, gradient_type>::type;
+
+
+    /**
+     * A structure where for each shape function we pre-compute a bunch of
+     * data that will make later accesses much cheaper.
+     */
+    struct ShapeFunctionData
+    {
+      /**
+       * For each pair (shape function,component within vector), store whether
+       * the selected vector component may be nonzero. For primitive shape
+       * functions we know for sure whether a certain scalar component of a
+       * given shape function is nonzero, whereas for non-primitive shape
+       * functions this may not be entirely clear (e.g. for RT elements it
+       * depends on the shape of a cell).
+       */
+      bool is_nonzero_shape_function_component
+        [value_type::n_independent_components];
+
+      /**
+       * For each pair (shape function, component within vector), store the
+       * row index within the shape_values, shape_gradients, and
+       * shape_hessians tables (the column index is the quadrature point
+       * index). If the shape function is primitive, then we can get this
+       * information from the shape_function_to_row_table of the FEValues
+       * object; otherwise, we have to work a bit harder to compute this
+       * information.
+       */
+      unsigned int row_index[value_type::n_independent_components];
+
+      /**
+       * For each shape function say the following: if only a single entry in
+       * is_nonzero_shape_function_component for this shape function is
+       * nonzero, then store the corresponding value of row_index and
+       * single_nonzero_component_index represents the index between 0 and
+       * (dim^2) for which it is attained. If multiple components are nonzero,
+       * then store -1. If no components are nonzero then store -2.
+       */
+      int single_nonzero_component;
+
+      /**
+       * Index of the @p single_nonzero_component .
+       */
+      unsigned int single_nonzero_component_index;
+    };
+
+    /**
+     * Default constructor. Creates an invalid object.
+     */
+    Tensor();
+
+    /**
+     * Copy constructor. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    Tensor(const Tensor<2, dim, spacedim> &) = delete;
+
+    /**
+     * Move constructor.
+     */
+    // NOLINTNEXTLINE OSX does not compile with noexcept
+    Tensor(Tensor<2, dim, spacedim> &&) = default;
+
+    /**
+     * Destructor.
+     */
+    ~Tensor() = default;
+
+    /**
+     * Constructor for an object that represents <code>(dim*dim)</code>
+     * components of a FEValuesBase object (or of one of the classes derived
+     * from FEValuesBase), representing the unique components comprising a
+     * second-order tensor valued variable.
+     *
+     * The second argument denotes the index of the first component of the
+     * selected symmetric second order tensor.
+     */
+    Tensor(const FEValuesBase<dim, spacedim> &fe_values_base,
+           const unsigned int                 first_tensor_component);
+
+
+    /**
+     * Copy operator. This is not a lightweight object so we don't allow
+     * copying and generate a compile-time error if this function is called.
+     */
+    Tensor &
+    operator=(const Tensor<2, dim, spacedim> &) = delete;
+
+    /**
+     * Move assignment operator.
+     */
+    Tensor &
+    operator=(Tensor<2, dim, spacedim> &&) = default; // NOLINT
+
+    /**
+     * Return the value of the vector components selected by this view, for
+     * the shape function and quadrature point selected by the arguments.
+     * Here, since the view represents a vector-valued part of the FEValues
+     * object with <code>(dim*dim)</code> components (the unique components of
+     * a second-order tensor), the return type is a tensor of rank 2.
+     *
+     * @param shape_function Number of the shape function to be evaluated.
+     * Note that this number runs from zero to dofs_per_cell, even in the case
+     * of an FEFaceValues or FESubfaceValues object.
+     *
+     * @param q_point Number of the quadrature point at which function is to
+     * be evaluated.
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    value_type
+    value(const unsigned int shape_function, const unsigned int q_point) const;
+
+    /**
+     * Return the vector divergence of the vector components selected by this
+     * view, for the shape function and quadrature point selected by the
+     * arguments.
+     *
+     * See the general discussion of this class for a definition of the
+     * divergence.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    divergence_type
+    divergence(const unsigned int shape_function,
+               const unsigned int q_point) const;
+
+    /**
+     * Return the gradient (3-rd order tensor) of the vector components selected
+     * by this view, for the shape function and quadrature point selected by the
+     * arguments.
+     *
+     * See the general discussion of this class for a definition of the
+     * gradient.
+     *
+     * @note The meaning of the arguments is as documented for the value()
+     * function.
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    gradient_type
+    gradient(const unsigned int shape_function,
+             const unsigned int q_point) const;
+
+    /**
+     * Return the values of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * This function is the equivalent of the
+     * FEValuesBase::get_function_values function but it only works on the
+     * selected vector components.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the values of shape functions (i.e., @p value_type) times the
+     * type used to store the values of the unknowns $U_j$ of your finite
+     * element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_values}
+     */
+    template <typename Number>
+    void
+    get_function_values(const ReadVector<Number> &                fe_function,
+                        std::vector<solution_value_type<Number>> &values) const;
+
+    /**
+     * Same as above, but using a vector of local degree-of-freedom values. In
+     * other words, instead of extracting the nodal values of the degrees of
+     * freedom located on the current cell from a global vector associated with
+     * a DoFHandler object (as the function above does), this function instead
+     * takes these local nodal values through its first argument. A typical
+     * way to obtain such a vector is by calling code such as
+     * @code
+     *   cell->get_dof_values (dof_values, local_dof_values);
+     * @endcode
+     * (See DoFCellAccessor::get_dof_values() for more information on this
+     * function.) The point of the current function is then that one could
+     * modify these local values first, for example by applying a limiter
+     * or by ensuring that all nodal values are positive, before evaluating
+     * the finite element field that corresponds to these local values on the
+     * current cell. Another application is where one wants to postprocess
+     * the solution on a cell into a different finite element space on every
+     * cell, without actually creating a corresponding DoFHandler -- in that
+     * case, all one would compute is a local representation of that
+     * postprocessed function, characterized by its nodal values; this function
+     * then allows the evaluation of that representation at quadrature points.
+     *
+     * @param[in] dof_values A vector of local nodal values. This vector must
+     *   have a length equal to number of DoFs on the current cell, and must
+     *   be ordered in the same order as degrees of freedom are numbered on
+     *   the reference cell.
+     *
+     * @param[out] values A vector of values of the given finite element field,
+     *   at the quadrature points on the current object.
+     *
+     * @tparam InputVector The @p InputVector type must allow creation
+     *   of an ArrayView object from it; this is satisfied by the
+     *   `std::vector` class, among others.
+     */
+    template <class InputVector>
+    void
+    get_function_values_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_value_type<typename InputVector::value_type>>
+        &values) const;
+
+    /**
+     * Return the divergence of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * There is no equivalent function such as
+     * FEValuesBase::get_function_divergences in the FEValues classes but the
+     * information can be obtained from FEValuesBase::get_function_gradients,
+     * of course.
+     *
+     * See the general discussion of this class for a definition of the
+     * divergence.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the divergences of shape functions (i.e., @p divergence_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_divergences(
+      const ReadVector<Number> &                     fe_function,
+      std::vector<solution_divergence_type<Number>> &divergences) const;
+
+    /**
+     * This function relates to get_function_divergences() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_divergences_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_divergence_type<typename InputVector::value_type>>
+        &divergences) const;
+
+    /**
+     * Return the gradient of the selected vector components of the finite
+     * element function characterized by <tt>fe_function</tt> at the
+     * quadrature points of the cell, face or subface selected the last time
+     * the <tt>reinit</tt> function of the FEValues object was called.
+     *
+     * See the general discussion of this class for a definition of the
+     * gradient.
+     *
+     * The data type stored by the output vector must be what you get when you
+     * multiply the gradients of shape functions (i.e., @p gradient_type)
+     * times the type used to store the values of the unknowns $U_j$ of your
+     * finite element vector $U$ (represented by the @p fe_function argument).
+     *
+     * @dealiiRequiresUpdateFlags{update_gradients}
+     */
+    template <typename Number>
+    void
+    get_function_gradients(
+      const ReadVector<Number> &                   fe_function,
+      std::vector<solution_gradient_type<Number>> &gradients) const;
+
+    /**
+     * This function relates to get_function_gradients() in the same way
+     * as get_function_values_from_local_dof_values() relates to
+     * get_function_values(). See the documentation of
+     * get_function_values_from_local_dof_values() for more information.
+     */
+    template <class InputVector>
+    void
+    get_function_gradients_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_gradient_type<typename InputVector::value_type>>
+        &gradients) const;
+
+  private:
+    /**
+     * A pointer to the FEValuesBase object we operate on.
+     */
+    const SmartPointer<const FEValuesBase<dim, spacedim>> fe_values;
+
+    /**
+     * The first component of the vector this view represents of the
+     * FEValuesBase object.
+     */
+    const unsigned int first_tensor_component;
+
+    /**
+     * Store the data about shape functions.
+     */
+    std::vector<ShapeFunctionData> shape_function_data;
+  };
+
+} // namespace FEValuesViews
+
+
+namespace internal
+{
+  namespace FEValuesViews
+  {
+    /**
+     * A class whose specialization is used to define what FEValuesViews
+     * object corresponds to the given FEValuesExtractors object.
+     */
+    template <int dim, int spacedim, typename Extractor>
+    struct ViewType
+    {};
+
+    /**
+     * A class whose specialization is used to define what FEValuesViews
+     * object corresponds to the given FEValuesExtractors object.
+     *
+     * When using FEValuesExtractors::Scalar, the corresponding view is an
+     * FEValuesViews::Scalar<dim, spacedim>.
+     */
+    template <int dim, int spacedim>
+    struct ViewType<dim, spacedim, FEValuesExtractors::Scalar>
+    {
+      using type = typename dealii::FEValuesViews::Scalar<dim, spacedim>;
+    };
+
+    /**
+     * A class whose specialization is used to define what FEValuesViews
+     * object corresponds to the given FEValuesExtractors object.
+     *
+     * When using FEValuesExtractors::Vector, the corresponding view is an
+     * FEValuesViews::Vector<dim, spacedim>.
+     */
+    template <int dim, int spacedim>
+    struct ViewType<dim, spacedim, FEValuesExtractors::Vector>
+    {
+      using type = typename dealii::FEValuesViews::Vector<dim, spacedim>;
+    };
+
+    /**
+     * A class whose specialization is used to define what FEValuesViews
+     * object corresponds to the given FEValuesExtractors object.
+     *
+     * When using FEValuesExtractors::Tensor<rank>, the corresponding view is an
+     * FEValuesViews::Tensor<rank, dim, spacedim>.
+     */
+    template <int dim, int spacedim, int rank>
+    struct ViewType<dim, spacedim, FEValuesExtractors::Tensor<rank>>
+    {
+      using type = typename dealii::FEValuesViews::Tensor<rank, dim, spacedim>;
+    };
+
+    /**
+     * A class whose specialization is used to define what FEValuesViews
+     * object corresponds to the given FEValuesExtractors object.
+     *
+     * When using FEValuesExtractors::SymmetricTensor<rank>, the corresponding
+     * view is an FEValuesViews::SymmetricTensor<rank, dim, spacedim>.
+     */
+    template <int dim, int spacedim, int rank>
+    struct ViewType<dim, spacedim, FEValuesExtractors::SymmetricTensor<rank>>
+    {
+      using type =
+        typename dealii::FEValuesViews::SymmetricTensor<rank, dim, spacedim>;
+    };
+
+    /**
+     * A class objects of which store a collection of FEValuesViews::Scalar,
+     * FEValuesViews::Vector, etc object. The FEValuesBase class uses it to
+     * generate all possible Views classes upon construction time; we do this
+     * at construction time since the Views classes cache some information and
+     * are therefore relatively expensive to create.
+     */
+    template <int dim, int spacedim>
+    struct Cache
+    {
+      /**
+       * Caches for scalar and vector, and symmetric second-order tensor
+       * valued views.
+       */
+      std::vector<dealii::FEValuesViews::Scalar<dim, spacedim>> scalars;
+      std::vector<dealii::FEValuesViews::Vector<dim, spacedim>> vectors;
+      std::vector<dealii::FEValuesViews::SymmetricTensor<2, dim, spacedim>>
+        symmetric_second_order_tensors;
+      std::vector<dealii::FEValuesViews::Tensor<2, dim, spacedim>>
+        second_order_tensors;
+
+      /**
+       * Constructor.
+       */
+      Cache(const FEValuesBase<dim, spacedim> &fe_values);
+    };
+  } // namespace FEValuesViews
+} // namespace internal
+
+namespace FEValuesViews
+{
+  /**
+   * A templated alias that associates to a given Extractor class
+   * the corresponding view in FEValuesViews.
+   */
+  template <int dim, int spacedim, typename Extractor>
+  using View = typename dealii::internal::FEValuesViews::
+    ViewType<dim, spacedim, Extractor>::type;
+} // namespace FEValuesViews
+
+#ifndef DOXYGEN
+
+/*---------------- Inline functions: namespace FEValuesViews -----------------*/
+
+namespace FEValuesViews
+{
+  template <int dim, int spacedim>
+  inline typename Scalar<dim, spacedim>::value_type
+  Scalar<dim, spacedim>::value(const unsigned int shape_function,
+                               const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(
+      fe_values->update_flags & update_values,
+      ((typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+        "update_values"))));
+
+    // an adaptation of the FEValuesBase::shape_value_component function
+    // except that here we know the component as fixed and we have
+    // pre-computed and cached a bunch of information. See the comments there.
+    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
+      return fe_values->finite_element_output.shape_values(
+        shape_function_data[shape_function].row_index, q_point);
+    else
+      return 0;
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Scalar<dim, spacedim>::gradient_type
+  Scalar<dim, spacedim>::gradient(const unsigned int shape_function,
+                                  const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    // an adaptation of the FEValuesBase::shape_grad_component
+    // function except that here we know the component as fixed and we have
+    // pre-computed and cached a bunch of information. See the comments there.
+    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
+      return fe_values->finite_element_output
+        .shape_gradients[shape_function_data[shape_function].row_index]
+                        [q_point];
+    else
+      return gradient_type();
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Scalar<dim, spacedim>::hessian_type
+  Scalar<dim, spacedim>::hessian(const unsigned int shape_function,
+                                 const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+
+    // an adaptation of the FEValuesBase::shape_hessian_component
+    // function except that here we know the component as fixed and we have
+    // pre-computed and cached a bunch of information. See the comments there.
+    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
+      return fe_values->finite_element_output
+        .shape_hessians[shape_function_data[shape_function].row_index][q_point];
+    else
+      return hessian_type();
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Scalar<dim, spacedim>::third_derivative_type
+  Scalar<dim, spacedim>::third_derivative(const unsigned int shape_function,
+                                          const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_3rd_derivatives,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_3rd_derivatives")));
+
+    // an adaptation of the FEValuesBase::shape_3rdderivative_component
+    // function except that here we know the component as fixed and we have
+    // pre-computed and cached a bunch of information. See the comments there.
+    if (shape_function_data[shape_function].is_nonzero_shape_function_component)
+      return fe_values->finite_element_output
+        .shape_3rd_derivatives[shape_function_data[shape_function].row_index]
+                              [q_point];
+    else
+      return third_derivative_type();
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::value_type
+  Vector<dim, spacedim>::value(const unsigned int shape_function,
+                               const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+    if (snc == -2)
+      return value_type();
+    else if (snc != -1)
+      {
+        value_type return_value;
+        return_value[shape_function_data[shape_function]
+                       .single_nonzero_component_index] =
+          fe_values->finite_element_output.shape_values(snc, q_point);
+        return return_value;
+      }
+    else
+      {
+        value_type return_value;
+        for (unsigned int d = 0; d < dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value[d] = fe_values->finite_element_output.shape_values(
+              shape_function_data[shape_function].row_index[d], q_point);
+
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::gradient_type
+  Vector<dim, spacedim>::gradient(const unsigned int shape_function,
+                                  const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+    if (snc == -2)
+      return gradient_type();
+    else if (snc != -1)
+      {
+        gradient_type return_value;
+        return_value[shape_function_data[shape_function]
+                       .single_nonzero_component_index] =
+          fe_values->finite_element_output.shape_gradients[snc][q_point];
+        return return_value;
+      }
+    else
+      {
+        gradient_type return_value;
+        for (unsigned int d = 0; d < dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value[d] =
+              fe_values->finite_element_output.shape_gradients
+                [shape_function_data[shape_function].row_index[d]][q_point];
+
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::divergence_type
+  Vector<dim, spacedim>::divergence(const unsigned int shape_function,
+                                    const unsigned int q_point) const
+  {
+    // this function works like in the case above
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+    if (snc == -2)
+      return divergence_type();
+    else if (snc != -1)
+      return fe_values->finite_element_output
+        .shape_gradients[snc][q_point][shape_function_data[shape_function]
+                                         .single_nonzero_component_index];
+    else
+      {
+        divergence_type return_value = 0;
+        for (unsigned int d = 0; d < dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value +=
+              fe_values->finite_element_output.shape_gradients
+                [shape_function_data[shape_function].row_index[d]][q_point][d];
+
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::curl_type
+  Vector<dim, spacedim>::curl(const unsigned int shape_function,
+                              const unsigned int q_point) const
+  {
+    // this function works like in the case above
+
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      return curl_type();
+
+    else
+      switch (dim)
+        {
+          case 1:
+            {
+              Assert(false,
+                     ExcMessage(
+                       "Computing the curl in 1d is not a useful operation"));
+              return curl_type();
+            }
+
+          case 2:
+            {
+              if (snc != -1)
+                {
+                  curl_type return_value;
+
+                  // the single nonzero component can only be zero or one in 2d
+                  if (shape_function_data[shape_function]
+                        .single_nonzero_component_index == 0)
+                    return_value[0] =
+                      -1.0 * fe_values->finite_element_output
+                               .shape_gradients[snc][q_point][1];
+                  else
+                    return_value[0] = fe_values->finite_element_output
+                                        .shape_gradients[snc][q_point][0];
+
+                  return return_value;
+                }
+
+              else
+                {
+                  curl_type return_value;
+
+                  return_value[0] = 0.0;
+
+                  if (shape_function_data[shape_function]
+                        .is_nonzero_shape_function_component[0])
+                    return_value[0] -=
+                      fe_values->finite_element_output
+                        .shape_gradients[shape_function_data[shape_function]
+                                           .row_index[0]][q_point][1];
+
+                  if (shape_function_data[shape_function]
+                        .is_nonzero_shape_function_component[1])
+                    return_value[0] +=
+                      fe_values->finite_element_output
+                        .shape_gradients[shape_function_data[shape_function]
+                                           .row_index[1]][q_point][0];
+
+                  return return_value;
+                }
+            }
+
+          case 3:
+            {
+              if (snc != -1)
+                {
+                  curl_type return_value;
+
+                  switch (shape_function_data[shape_function]
+                            .single_nonzero_component_index)
+                    {
+                      case 0:
+                        {
+                          return_value[0] = 0;
+                          return_value[1] = fe_values->finite_element_output
+                                              .shape_gradients[snc][q_point][2];
+                          return_value[2] =
+                            -1.0 * fe_values->finite_element_output
+                                     .shape_gradients[snc][q_point][1];
+                          return return_value;
+                        }
+
+                      case 1:
+                        {
+                          return_value[0] =
+                            -1.0 * fe_values->finite_element_output
+                                     .shape_gradients[snc][q_point][2];
+                          return_value[1] = 0;
+                          return_value[2] = fe_values->finite_element_output
+                                              .shape_gradients[snc][q_point][0];
+                          return return_value;
+                        }
+
+                      default:
+                        {
+                          return_value[0] = fe_values->finite_element_output
+                                              .shape_gradients[snc][q_point][1];
+                          return_value[1] =
+                            -1.0 * fe_values->finite_element_output
+                                     .shape_gradients[snc][q_point][0];
+                          return_value[2] = 0;
+                          return return_value;
+                        }
+                    }
+                }
+
+              else
+                {
+                  curl_type return_value;
+
+                  for (unsigned int i = 0; i < dim; ++i)
+                    return_value[i] = 0.0;
+
+                  if (shape_function_data[shape_function]
+                        .is_nonzero_shape_function_component[0])
+                    {
+                      return_value[1] +=
+                        fe_values->finite_element_output
+                          .shape_gradients[shape_function_data[shape_function]
+                                             .row_index[0]][q_point][2];
+                      return_value[2] -=
+                        fe_values->finite_element_output
+                          .shape_gradients[shape_function_data[shape_function]
+                                             .row_index[0]][q_point][1];
+                    }
+
+                  if (shape_function_data[shape_function]
+                        .is_nonzero_shape_function_component[1])
+                    {
+                      return_value[0] -=
+                        fe_values->finite_element_output
+                          .shape_gradients[shape_function_data[shape_function]
+                                             .row_index[1]][q_point][2];
+                      return_value[2] +=
+                        fe_values->finite_element_output
+                          .shape_gradients[shape_function_data[shape_function]
+                                             .row_index[1]][q_point][0];
+                    }
+
+                  if (shape_function_data[shape_function]
+                        .is_nonzero_shape_function_component[2])
+                    {
+                      return_value[0] +=
+                        fe_values->finite_element_output
+                          .shape_gradients[shape_function_data[shape_function]
+                                             .row_index[2]][q_point][1];
+                      return_value[1] -=
+                        fe_values->finite_element_output
+                          .shape_gradients[shape_function_data[shape_function]
+                                             .row_index[2]][q_point][0];
+                    }
+
+                  return return_value;
+                }
+            }
+        }
+    // should not end up here
+    Assert(false, ExcInternalError());
+    return curl_type();
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::hessian_type
+  Vector<dim, spacedim>::hessian(const unsigned int shape_function,
+                                 const unsigned int q_point) const
+  {
+    // this function works like in the case above
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+    if (snc == -2)
+      return hessian_type();
+    else if (snc != -1)
+      {
+        hessian_type return_value;
+        return_value[shape_function_data[shape_function]
+                       .single_nonzero_component_index] =
+          fe_values->finite_element_output.shape_hessians[snc][q_point];
+        return return_value;
+      }
+    else
+      {
+        hessian_type return_value;
+        for (unsigned int d = 0; d < dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value[d] =
+              fe_values->finite_element_output.shape_hessians
+                [shape_function_data[shape_function].row_index[d]][q_point];
+
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::third_derivative_type
+  Vector<dim, spacedim>::third_derivative(const unsigned int shape_function,
+                                          const unsigned int q_point) const
+  {
+    // this function works like in the case above
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_3rd_derivatives,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_3rd_derivatives")));
+
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+    if (snc == -2)
+      return third_derivative_type();
+    else if (snc != -1)
+      {
+        third_derivative_type return_value;
+        return_value[shape_function_data[shape_function]
+                       .single_nonzero_component_index] =
+          fe_values->finite_element_output.shape_3rd_derivatives[snc][q_point];
+        return return_value;
+      }
+    else
+      {
+        third_derivative_type return_value;
+        for (unsigned int d = 0; d < dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value[d] =
+              fe_values->finite_element_output.shape_3rd_derivatives
+                [shape_function_data[shape_function].row_index[d]][q_point];
+
+        return return_value;
+      }
+  }
+
+
+
+  namespace internal
+  {
+    /**
+     * Return the symmetrized version of a tensor whose n'th row equals the
+     * second argument, with all other rows equal to zero.
+     */
+    inline dealii::SymmetricTensor<2, 1>
+    symmetrize_single_row(const unsigned int n, const dealii::Tensor<1, 1> &t)
+    {
+      AssertIndexRange(n, 1);
+      (void)n;
+
+      return {{t[0]}};
+    }
+
+
+
+    inline dealii::SymmetricTensor<2, 2>
+    symmetrize_single_row(const unsigned int n, const dealii::Tensor<1, 2> &t)
+    {
+      switch (n)
+        {
+          case 0:
+            {
+              return {{t[0], 0, t[1] / 2}};
+            }
+          case 1:
+            {
+              return {{0, t[1], t[0] / 2}};
+            }
+          default:
+            {
+              AssertIndexRange(n, 2);
+              return {};
+            }
+        }
+    }
+
+
+
+    inline dealii::SymmetricTensor<2, 3>
+    symmetrize_single_row(const unsigned int n, const dealii::Tensor<1, 3> &t)
+    {
+      switch (n)
+        {
+          case 0:
+            {
+              return {{t[0], 0, 0, t[1] / 2, t[2] / 2, 0}};
+            }
+          case 1:
+            {
+              return {{0, t[1], 0, t[0] / 2, 0, t[2] / 2}};
+            }
+          case 2:
+            {
+              return {{0, 0, t[2], 0, t[0] / 2, t[1] / 2}};
+            }
+          default:
+            {
+              AssertIndexRange(n, 3);
+              return {};
+            }
+        }
+    }
+  } // namespace internal
+
+
+
+  template <int dim, int spacedim>
+  inline typename Vector<dim, spacedim>::symmetric_gradient_type
+  Vector<dim, spacedim>::symmetric_gradient(const unsigned int shape_function,
+                                            const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    // same as for the scalar case except that we have one more index
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+    if (snc == -2)
+      return symmetric_gradient_type();
+    else if (snc != -1)
+      return internal::symmetrize_single_row(
+        shape_function_data[shape_function].single_nonzero_component_index,
+        fe_values->finite_element_output.shape_gradients[snc][q_point]);
+    else
+      {
+        gradient_type return_value;
+        for (unsigned int d = 0; d < dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value[d] =
+              fe_values->finite_element_output.shape_gradients
+                [shape_function_data[shape_function].row_index[d]][q_point];
+
+        return symmetrize(return_value);
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename SymmetricTensor<2, dim, spacedim>::value_type
+  SymmetricTensor<2, dim, spacedim>::value(const unsigned int shape_function,
+                                           const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+
+    // similar to the vector case where we have more then one index and we need
+    // to convert between unrolled and component indexing for tensors
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      {
+        // shape function is zero for the selected components
+        return value_type();
+      }
+    else if (snc != -1)
+      {
+        value_type         return_value;
+        const unsigned int comp =
+          shape_function_data[shape_function].single_nonzero_component_index;
+        return_value[value_type::unrolled_to_component_indices(comp)] =
+          fe_values->finite_element_output.shape_values(snc, q_point);
+        return return_value;
+      }
+    else
+      {
+        value_type return_value;
+        for (unsigned int d = 0; d < value_type::n_independent_components; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            return_value[value_type::unrolled_to_component_indices(d)] =
+              fe_values->finite_element_output.shape_values(
+                shape_function_data[shape_function].row_index[d], q_point);
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename SymmetricTensor<2, dim, spacedim>::divergence_type
+  SymmetricTensor<2, dim, spacedim>::divergence(
+    const unsigned int shape_function,
+    const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      {
+        // shape function is zero for the selected components
+        return divergence_type();
+      }
+    else if (snc != -1)
+      {
+        // we have a single non-zero component when the symmetric tensor is
+        // represented in unrolled form. this implies we potentially have
+        // two non-zero components when represented in component form!  we
+        // will only have one non-zero entry if the non-zero component lies on
+        // the diagonal of the tensor.
+        //
+        // the divergence of a second-order tensor is a first order tensor.
+        //
+        // assume the second-order tensor is A with components A_{ij}.  then
+        // A_{ij} = A_{ji} and there is only one (if diagonal) or two non-zero
+        // entries in the tensorial representation.  define the
+        // divergence as:
+        // b_i \dealcoloneq \dfrac{\partial phi_{ij}}{\partial x_j}.
+        // (which is incidentally also
+        // b_j \dealcoloneq \dfrac{\partial phi_{ij}}{\partial x_i}).
+        // In both cases, a sum is implied.
+        //
+        // Now, we know the nonzero component in unrolled form: it is indicated
+        // by 'snc'. we can figure out which tensor components belong to this:
+        const unsigned int comp =
+          shape_function_data[shape_function].single_nonzero_component_index;
+        const unsigned int ii =
+          value_type::unrolled_to_component_indices(comp)[0];
+        const unsigned int jj =
+          value_type::unrolled_to_component_indices(comp)[1];
+
+        // given the form of the divergence above, if ii=jj there is only a
+        // single nonzero component of the full tensor and the gradient
+        // equals
+        // b_ii \dealcoloneq \dfrac{\partial phi_{ii,ii}}{\partial x_ii}.
+        // all other entries of 'b' are zero
+        //
+        // on the other hand, if ii!=jj, then there are two nonzero entries in
+        // the full tensor and
+        // b_ii \dealcoloneq \dfrac{\partial phi_{ii,jj}}{\partial x_ii}.
+        // b_jj \dealcoloneq \dfrac{\partial phi_{ii,jj}}{\partial x_jj}.
+        // again, all other entries of 'b' are zero
+        const dealii::Tensor<1, spacedim> &phi_grad =
+          fe_values->finite_element_output.shape_gradients[snc][q_point];
+
+        divergence_type return_value;
+        return_value[ii] = phi_grad[jj];
+
+        if (ii != jj)
+          return_value[jj] = phi_grad[ii];
+
+        return return_value;
+      }
+    else
+      {
+        Assert(false, ExcNotImplemented());
+        divergence_type return_value;
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Tensor<2, dim, spacedim>::value_type
+  Tensor<2, dim, spacedim>::value(const unsigned int shape_function,
+                                  const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+
+    // similar to the vector case where we have more then one index and we need
+    // to convert between unrolled and component indexing for tensors
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      {
+        // shape function is zero for the selected components
+        return value_type();
+      }
+    else if (snc != -1)
+      {
+        value_type         return_value;
+        const unsigned int comp =
+          shape_function_data[shape_function].single_nonzero_component_index;
+        const TableIndices<2> indices =
+          dealii::Tensor<2, spacedim>::unrolled_to_component_indices(comp);
+        return_value[indices] =
+          fe_values->finite_element_output.shape_values(snc, q_point);
+        return return_value;
+      }
+    else
+      {
+        value_type return_value;
+        for (unsigned int d = 0; d < dim * dim; ++d)
+          if (shape_function_data[shape_function]
+                .is_nonzero_shape_function_component[d])
+            {
+              const TableIndices<2> indices =
+                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(d);
+              return_value[indices] =
+                fe_values->finite_element_output.shape_values(
+                  shape_function_data[shape_function].row_index[d], q_point);
+            }
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Tensor<2, dim, spacedim>::divergence_type
+  Tensor<2, dim, spacedim>::divergence(const unsigned int shape_function,
+                                       const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      {
+        // shape function is zero for the selected components
+        return divergence_type();
+      }
+    else if (snc != -1)
+      {
+        // we have a single non-zero component when the tensor is
+        // represented in unrolled form.
+        //
+        // the divergence of a second-order tensor is a first order tensor.
+        //
+        // assume the second-order tensor is A with components A_{ij},
+        // then divergence is d_i := \frac{\partial A_{ij}}{\partial x_j}
+        //
+        // Now, we know the nonzero component in unrolled form: it is indicated
+        // by 'snc'. we can figure out which tensor components belong to this:
+        const unsigned int comp =
+          shape_function_data[shape_function].single_nonzero_component_index;
+        const TableIndices<2> indices =
+          dealii::Tensor<2, spacedim>::unrolled_to_component_indices(comp);
+        const unsigned int ii = indices[0];
+        const unsigned int jj = indices[1];
+
+        const dealii::Tensor<1, spacedim> &phi_grad =
+          fe_values->finite_element_output.shape_gradients[snc][q_point];
+
+        divergence_type return_value;
+        // note that we contract \nabla from the right
+        return_value[ii] = phi_grad[jj];
+
+        return return_value;
+      }
+    else
+      {
+        Assert(false, ExcNotImplemented());
+        divergence_type return_value;
+        return return_value;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  inline typename Tensor<2, dim, spacedim>::gradient_type
+  Tensor<2, dim, spacedim>::gradient(const unsigned int shape_function,
+                                     const unsigned int q_point) const
+  {
+    AssertIndexRange(shape_function, fe_values->fe->n_dofs_per_cell());
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+
+    const int snc =
+      shape_function_data[shape_function].single_nonzero_component;
+
+    if (snc == -2)
+      {
+        // shape function is zero for the selected components
+        return gradient_type();
+      }
+    else if (snc != -1)
+      {
+        // we have a single non-zero component when the tensor is
+        // represented in unrolled form.
+        //
+        // the gradient of a second-order tensor is a third order tensor.
+        //
+        // assume the second-order tensor is A with components A_{ij},
+        // then gradient is B_{ijk} := \frac{\partial A_{ij}}{\partial x_k}
+        //
+        // Now, we know the nonzero component in unrolled form: it is indicated
+        // by 'snc'. we can figure out which tensor components belong to this:
+        const unsigned int comp =
+          shape_function_data[shape_function].single_nonzero_component_index;
+        const TableIndices<2> indices =
+          dealii::Tensor<2, spacedim>::unrolled_to_component_indices(comp);
+        const unsigned int ii = indices[0];
+        const unsigned int jj = indices[1];
+
+        const dealii::Tensor<1, spacedim> &phi_grad =
+          fe_values->finite_element_output.shape_gradients[snc][q_point];
+
+        gradient_type return_value;
+        return_value[ii][jj] = phi_grad;
+
+        return return_value;
+      }
+    else
+      {
+        Assert(false, ExcNotImplemented());
+        gradient_type return_value;
+        return return_value;
+      }
+  }
+} // namespace FEValuesViews
+
+#endif
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
index c356007e1188017f4fe464f62627bdde4976c0a1..57b6cc663e0c5990291a018ff3c4c0b970607e19 100644 (file)
@@ -68,6 +68,8 @@ set(_unity_include_src
 
 set(_separate_src
   fe_values.cc
+  fe_values_base.cc
+  fe_values_views.cc
   mapping_fe_field.cc
   mapping_fe_field_inst2.cc
   fe_tools.cc
@@ -123,6 +125,8 @@ set(_inst
   fe_tools_interpolate.inst.in
   fe_tools_extrapolate.inst.in
   fe_trace.inst.in
+  fe_values_base.inst.in
+  fe_values_views.inst.in
   fe_values.inst.in
   fe_wedge_p.inst.in
   mapping_c1.inst.in
index 325932363ee7ee19cce74188486c3bd71ed543d7..9fe7158f8fa5d9bbcb7e5b17386e45e49995d5ca 100644 (file)
@@ -71,3894 +71,85 @@ namespace internal
 
     return shape_function_to_row_table;
   }
-
-  namespace
-  {
-    // Check to see if a DoF value is zero, implying that subsequent operations
-    // with the value have no effect.
-    template <typename Number, typename T = void>
-    struct CheckForZero
-    {
-      static bool
-      value(const Number &value)
-      {
-        return value == dealii::internal::NumberType<Number>::value(0.0);
-      }
-    };
-
-    // For auto-differentiable numbers, the fact that a DoF value is zero
-    // does not imply that its derivatives are zero as well. So we
-    // can't filter by value for these number types.
-    // Note that we also want to avoid actually checking the value itself,
-    // since some AD numbers are not contextually convertible to booleans.
-    template <typename Number>
-    struct CheckForZero<
-      Number,
-      std::enable_if_t<Differentiation::AD::is_ad_number<Number>::value>>
-    {
-      static bool
-      value(const Number & /*value*/)
-      {
-        return false;
-      }
-    };
-  } // namespace
 } // namespace internal
 
 
 
-namespace FEValuesViews
+namespace internal
 {
-  template <int dim, int spacedim>
-  Scalar<dim, spacedim>::Scalar(const FEValuesBase<dim, spacedim> &fe_values,
-                                const unsigned int                 component)
-    : fe_values(&fe_values)
-    , component(component)
-    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
-  {
-    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
-    AssertIndexRange(component, fe.n_components());
-
-    // TODO: we'd like to use the fields with the same name as these
-    // variables from FEValuesBase, but they aren't initialized yet
-    // at the time we get here, so re-create it all
-    const std::vector<unsigned int> shape_function_to_row_table =
-      dealii::internal::make_shape_function_to_row_table(fe);
-
-    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-      {
-        const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
-
-        if (is_primitive == true)
-          shape_function_data[i].is_nonzero_shape_function_component =
-            (component == fe.system_to_component_index(i).first);
-        else
-          shape_function_data[i].is_nonzero_shape_function_component =
-            (fe.get_nonzero_components(i)[component] == true);
-
-        if (shape_function_data[i].is_nonzero_shape_function_component == true)
-          shape_function_data[i].row_index =
-            shape_function_to_row_table[i * fe.n_components() + component];
-        else
-          shape_function_data[i].row_index = numbers::invalid_unsigned_int;
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  Scalar<dim, spacedim>::Scalar()
-    : fe_values(nullptr)
-    , component(numbers::invalid_unsigned_int)
-  {}
-
-
-
-  template <int dim, int spacedim>
-  Vector<dim, spacedim>::Vector(const FEValuesBase<dim, spacedim> &fe_values,
-                                const unsigned int first_vector_component)
-    : fe_values(&fe_values)
-    , first_vector_component(first_vector_component)
-    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
-  {
-    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
-    AssertIndexRange(first_vector_component + spacedim - 1, fe.n_components());
-
-    // TODO: we'd like to use the fields with the same name as these
-    // variables from FEValuesBase, but they aren't initialized yet
-    // at the time we get here, so re-create it all
-    const std::vector<unsigned int> shape_function_to_row_table =
-      dealii::internal::make_shape_function_to_row_table(fe);
-
-    for (unsigned int d = 0; d < spacedim; ++d)
-      {
-        const unsigned int component = first_vector_component + d;
-
-        for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-          {
-            const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
-
-            if (is_primitive == true)
-              shape_function_data[i].is_nonzero_shape_function_component[d] =
-                (component == fe.system_to_component_index(i).first);
-            else
-              shape_function_data[i].is_nonzero_shape_function_component[d] =
-                (fe.get_nonzero_components(i)[component] == true);
-
-            if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
-                true)
-              shape_function_data[i].row_index[d] =
-                shape_function_to_row_table[i * fe.n_components() + component];
-            else
-              shape_function_data[i].row_index[d] =
-                numbers::invalid_unsigned_int;
-          }
-      }
-
-    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-      {
-        unsigned int n_nonzero_components = 0;
-        for (unsigned int d = 0; d < spacedim; ++d)
-          if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
-              true)
-            ++n_nonzero_components;
-
-        if (n_nonzero_components == 0)
-          shape_function_data[i].single_nonzero_component = -2;
-        else if (n_nonzero_components > 1)
-          shape_function_data[i].single_nonzero_component = -1;
-        else
-          {
-            for (unsigned int d = 0; d < spacedim; ++d)
-              if (shape_function_data[i]
-                    .is_nonzero_shape_function_component[d] == true)
-                {
-                  shape_function_data[i].single_nonzero_component =
-                    shape_function_data[i].row_index[d];
-                  shape_function_data[i].single_nonzero_component_index = d;
-                  break;
-                }
-          }
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  Vector<dim, spacedim>::Vector()
-    : fe_values(nullptr)
-    , first_vector_component(numbers::invalid_unsigned_int)
-  {}
-
-
-
-  template <int dim, int spacedim>
-  SymmetricTensor<2, dim, spacedim>::SymmetricTensor(
-    const FEValuesBase<dim, spacedim> &fe_values,
-    const unsigned int                 first_tensor_component)
-    : fe_values(&fe_values)
-    , first_tensor_component(first_tensor_component)
-    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
-  {
-    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
-    Assert(first_tensor_component + (dim * dim + dim) / 2 - 1 <
-             fe.n_components(),
-           ExcIndexRange(
-             first_tensor_component +
-               dealii::SymmetricTensor<2, dim>::n_independent_components - 1,
-             0,
-             fe.n_components()));
-    // TODO: we'd like to use the fields with the same name as these
-    // variables from FEValuesBase, but they aren't initialized yet
-    // at the time we get here, so re-create it all
-    const std::vector<unsigned int> shape_function_to_row_table =
-      dealii::internal::make_shape_function_to_row_table(fe);
-
-    for (unsigned int d = 0;
-         d < dealii::SymmetricTensor<2, dim>::n_independent_components;
-         ++d)
-      {
-        const unsigned int component = first_tensor_component + d;
-
-        for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-          {
-            const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
-
-            if (is_primitive == true)
-              shape_function_data[i].is_nonzero_shape_function_component[d] =
-                (component == fe.system_to_component_index(i).first);
-            else
-              shape_function_data[i].is_nonzero_shape_function_component[d] =
-                (fe.get_nonzero_components(i)[component] == true);
-
-            if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
-                true)
-              shape_function_data[i].row_index[d] =
-                shape_function_to_row_table[i * fe.n_components() + component];
-            else
-              shape_function_data[i].row_index[d] =
-                numbers::invalid_unsigned_int;
-          }
-      }
-
-    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-      {
-        unsigned int n_nonzero_components = 0;
-        for (unsigned int d = 0;
-             d < dealii::SymmetricTensor<2, dim>::n_independent_components;
-             ++d)
-          if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
-              true)
-            ++n_nonzero_components;
-
-        if (n_nonzero_components == 0)
-          shape_function_data[i].single_nonzero_component = -2;
-        else if (n_nonzero_components > 1)
-          shape_function_data[i].single_nonzero_component = -1;
-        else
-          {
-            for (unsigned int d = 0;
-                 d < dealii::SymmetricTensor<2, dim>::n_independent_components;
-                 ++d)
-              if (shape_function_data[i]
-                    .is_nonzero_shape_function_component[d] == true)
-                {
-                  shape_function_data[i].single_nonzero_component =
-                    shape_function_data[i].row_index[d];
-                  shape_function_data[i].single_nonzero_component_index = d;
-                  break;
-                }
-          }
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  SymmetricTensor<2, dim, spacedim>::SymmetricTensor()
-    : fe_values(nullptr)
-    , first_tensor_component(numbers::invalid_unsigned_int)
-  {}
-
-
-
-  template <int dim, int spacedim>
-  Tensor<2, dim, spacedim>::Tensor(const FEValuesBase<dim, spacedim> &fe_values,
-                                   const unsigned int first_tensor_component)
-    : fe_values(&fe_values)
-    , first_tensor_component(first_tensor_component)
-    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
-  {
-    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
-    AssertIndexRange(first_tensor_component + dim * dim - 1, fe.n_components());
-    // TODO: we'd like to use the fields with the same name as these
-    // variables from FEValuesBase, but they aren't initialized yet
-    // at the time we get here, so re-create it all
-    const std::vector<unsigned int> shape_function_to_row_table =
-      dealii::internal::make_shape_function_to_row_table(fe);
-
-    for (unsigned int d = 0; d < dim * dim; ++d)
-      {
-        const unsigned int component = first_tensor_component + d;
-
-        for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-          {
-            const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
-
-            if (is_primitive == true)
-              shape_function_data[i].is_nonzero_shape_function_component[d] =
-                (component == fe.system_to_component_index(i).first);
-            else
-              shape_function_data[i].is_nonzero_shape_function_component[d] =
-                (fe.get_nonzero_components(i)[component] == true);
-
-            if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
-                true)
-              shape_function_data[i].row_index[d] =
-                shape_function_to_row_table[i * fe.n_components() + component];
-            else
-              shape_function_data[i].row_index[d] =
-                numbers::invalid_unsigned_int;
-          }
-      }
-
-    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-      {
-        unsigned int n_nonzero_components = 0;
-        for (unsigned int d = 0; d < dim * dim; ++d)
-          if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
-              true)
-            ++n_nonzero_components;
-
-        if (n_nonzero_components == 0)
-          shape_function_data[i].single_nonzero_component = -2;
-        else if (n_nonzero_components > 1)
-          shape_function_data[i].single_nonzero_component = -1;
-        else
-          {
-            for (unsigned int d = 0; d < dim * dim; ++d)
-              if (shape_function_data[i]
-                    .is_nonzero_shape_function_component[d] == true)
-                {
-                  shape_function_data[i].single_nonzero_component =
-                    shape_function_data[i].row_index[d];
-                  shape_function_data[i].single_nonzero_component_index = d;
-                  break;
-                }
-          }
-      }
-  }
-
-
-
-  template <int dim, int spacedim>
-  Tensor<2, dim, spacedim>::Tensor()
-    : fe_values(nullptr)
-    , first_tensor_component(numbers::invalid_unsigned_int)
-  {}
-
-
-
-  namespace internal
+  namespace FEValuesImplementation
   {
-    // Given values of degrees of freedom, evaluate the
-    // values/gradients/... at quadrature points
-
-    // ------------------------- scalar functions --------------------------
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_values(
-      const ArrayView<Number> &dof_values,
-      const Table<2, double> & shape_values,
-      const std::vector<typename Scalar<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename ProductType<Number, double>::type> &values)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = values.size();
-
-      std::fill(values.begin(),
-                values.end(),
-                dealii::internal::NumberType<Number>::value(0.0));
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        if (shape_function_data[shape_function]
-              .is_nonzero_shape_function_component)
-          {
-            const Number &value = dof_values[shape_function];
-            // For auto-differentiable numbers, the fact that a DoF value is
-            // zero does not imply that its derivatives are zero as well. So we
-            // can't filter by value for these number types.
-            if (dealii::internal::CheckForZero<Number>::value(value) == true)
-              continue;
-
-            const double *shape_value_ptr =
-              &shape_values(shape_function_data[shape_function].row_index, 0);
-            for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                 ++q_point)
-              values[q_point] += value * (*shape_value_ptr++);
-          }
-    }
-
-
-
-    // same code for gradient and Hessian, template argument 'order' to give
-    // the order of the derivative (= rank of gradient/Hessian tensor)
-    template <int order, int dim, int spacedim, typename Number>
-    void
-    do_function_derivatives(
-      const ArrayView<Number> &                        dof_values,
-      const Table<2, dealii::Tensor<order, spacedim>> &shape_derivatives,
-      const std::vector<typename Scalar<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<
-        typename ProductType<Number, dealii::Tensor<order, spacedim>>::type>
-        &derivatives)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = derivatives.size();
-
-      std::fill(
-        derivatives.begin(),
-        derivatives.end(),
-        typename ProductType<Number, dealii::Tensor<order, spacedim>>::type());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        if (shape_function_data[shape_function]
-              .is_nonzero_shape_function_component)
-          {
-            const Number &value = dof_values[shape_function];
-            // For auto-differentiable numbers, the fact that a DoF value is
-            // zero does not imply that its derivatives are zero as well. So we
-            // can't filter by value for these number types.
-            if (dealii::internal::CheckForZero<Number>::value(value) == true)
-              continue;
-
-            const dealii::Tensor<order, spacedim> *shape_derivative_ptr =
-              &shape_derivatives[shape_function_data[shape_function].row_index]
-                                [0];
-            for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                 ++q_point)
-              derivatives[q_point] += value * (*shape_derivative_ptr++);
-          }
-    }
-
-
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_laplacians(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians,
-      const std::vector<typename Scalar<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename Scalar<dim, spacedim>::
-                    template solution_laplacian_type<Number>> &laplacians)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = laplacians.size();
-
-      std::fill(
-        laplacians.begin(),
-        laplacians.end(),
-        typename Scalar<dim,
-                        spacedim>::template solution_laplacian_type<Number>());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        if (shape_function_data[shape_function]
-              .is_nonzero_shape_function_component)
-          {
-            const Number &value = dof_values[shape_function];
-            // For auto-differentiable numbers, the fact that a DoF value is
-            // zero does not imply that its derivatives are zero as well. So we
-            // can't filter by value for these number types.
-            if (dealii::internal::CheckForZero<Number>::value(value) == true)
-              continue;
-
-            const dealii::Tensor<2, spacedim> *shape_hessian_ptr =
-              &shape_hessians[shape_function_data[shape_function].row_index][0];
-            for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                 ++q_point)
-              laplacians[q_point] += value * trace(*shape_hessian_ptr++);
-          }
-    }
-
-
-
-    // ----------------------------- vector part ---------------------------
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_values(
-      const ArrayView<Number> &dof_values,
-      const Table<2, double> & shape_values,
-      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<
-        typename ProductType<Number, dealii::Tensor<1, spacedim>>::type>
-        &values)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = values.size();
-
-      std::fill(
-        values.begin(),
-        values.end(),
-        typename ProductType<Number, dealii::Tensor<1, spacedim>>::type());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-              const double *shape_value_ptr = &shape_values(snc, 0);
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                values[q_point][comp] += value * (*shape_value_ptr++);
-            }
-          else
-            for (unsigned int d = 0; d < spacedim; ++d)
-              if (shape_function_data[shape_function]
-                    .is_nonzero_shape_function_component[d])
-                {
-                  const double *shape_value_ptr = &shape_values(
-                    shape_function_data[shape_function].row_index[d], 0);
-                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                       ++q_point)
-                    values[q_point][d] += value * (*shape_value_ptr++);
-                }
-        }
-    }
-
-
-
-    template <int order, int dim, int spacedim, typename Number>
-    void
-    do_function_derivatives(
-      const ArrayView<Number> &                        dof_values,
-      const Table<2, dealii::Tensor<order, spacedim>> &shape_derivatives,
-      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<
-        typename ProductType<Number, dealii::Tensor<order + 1, spacedim>>::type>
-        &derivatives)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = derivatives.size();
-
-      std::fill(
-        derivatives.begin(),
-        derivatives.end(),
-        typename ProductType<Number,
-                             dealii::Tensor<order + 1, spacedim>>::type());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-              const dealii::Tensor<order, spacedim> *shape_derivative_ptr =
-                &shape_derivatives[snc][0];
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                derivatives[q_point][comp] += value * (*shape_derivative_ptr++);
-            }
-          else
-            for (unsigned int d = 0; d < spacedim; ++d)
-              if (shape_function_data[shape_function]
-                    .is_nonzero_shape_function_component[d])
-                {
-                  const dealii::Tensor<order, spacedim> *shape_derivative_ptr =
-                    &shape_derivatives[shape_function_data[shape_function]
-                                         .row_index[d]][0];
-                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                       ++q_point)
-                    derivatives[q_point][d] +=
-                      value * (*shape_derivative_ptr++);
-                }
-        }
-    }
-
-
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_symmetric_gradients(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
-      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<
-        typename ProductType<Number,
-                             dealii::SymmetricTensor<2, spacedim>>::type>
-        &symmetric_gradients)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = symmetric_gradients.size();
-
-      std::fill(
-        symmetric_gradients.begin(),
-        symmetric_gradients.end(),
-        typename ProductType<Number,
-                             dealii::SymmetricTensor<2, spacedim>>::type());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                &shape_gradients[snc][0];
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                symmetric_gradients[q_point] +=
-                  value * dealii::SymmetricTensor<2, spacedim>(
-                            symmetrize_single_row(comp, *shape_gradient_ptr++));
-            }
-          else
-            for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                 ++q_point)
-              {
-                typename ProductType<Number, dealii::Tensor<2, spacedim>>::type
-                  grad;
-                for (unsigned int d = 0; d < spacedim; ++d)
-                  if (shape_function_data[shape_function]
-                        .is_nonzero_shape_function_component[d])
-                    grad[d] =
-                      value *
-                      shape_gradients[shape_function_data[shape_function]
-                                        .row_index[d]][q_point];
-                symmetric_gradients[q_point] += symmetrize(grad);
-              }
-        }
-    }
-
-
-
-    template <int dim, int spacedim, typename Number>
+    template <int dim, int spacedim>
     void
-    do_function_divergences(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
-      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename Vector<dim, spacedim>::
-                    template solution_divergence_type<Number>> &divergences)
+    FiniteElementRelatedData<dim, spacedim>::initialize(
+      const unsigned int                  n_quadrature_points,
+      const FiniteElement<dim, spacedim> &fe,
+      const UpdateFlags                   flags)
     {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = divergences.size();
+      // initialize the table mapping from shape function number to
+      // the rows in the tables storing the data by shape function and
+      // nonzero component
+      this->shape_function_to_row_table =
+        dealii::internal::make_shape_function_to_row_table(fe);
 
-      std::fill(
-        divergences.begin(),
-        divergences.end(),
-        typename Vector<dim,
-                        spacedim>::template solution_divergence_type<Number>());
+      // count the total number of non-zero components accumulated
+      // over all shape functions
+      unsigned int n_nonzero_shape_components = 0;
+      for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+        n_nonzero_shape_components += fe.n_nonzero_components(i);
+      Assert(n_nonzero_shape_components >= fe.n_dofs_per_cell(),
+             ExcInternalError());
 
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
+      // with the number of rows now known, initialize those fields
+      // that we will need to their correct size
+      if (flags & update_values)
         {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                &shape_gradients[snc][0];
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                divergences[q_point] += value * (*shape_gradient_ptr++)[comp];
-            }
-          else
-            for (unsigned int d = 0; d < spacedim; ++d)
-              if (shape_function_data[shape_function]
-                    .is_nonzero_shape_function_component[d])
-                {
-                  const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                    &shape_gradients[shape_function_data[shape_function]
-                                       .row_index[d]][0];
-                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                       ++q_point)
-                    divergences[q_point] += value * (*shape_gradient_ptr++)[d];
-                }
+          this->shape_values.reinit(n_nonzero_shape_components,
+                                    n_quadrature_points);
+          this->shape_values.fill(numbers::signaling_nan<double>());
         }
-    }
-
-
 
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_curls(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
-      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename ProductType<
-        Number,
-        typename dealii::internal::CurlType<spacedim>::type>::type> &curls)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = curls.size();
-
-      std::fill(curls.begin(),
-                curls.end(),
-                typename ProductType<
-                  Number,
-                  typename dealii::internal::CurlType<spacedim>::type>::type());
-
-      switch (spacedim)
+      if (flags & update_gradients)
         {
-          case 1:
-            {
-              Assert(false,
-                     ExcMessage(
-                       "Computing the curl in 1d is not a useful operation"));
-              break;
-            }
-
-          case 2:
-            {
-              for (unsigned int shape_function = 0;
-                   shape_function < dofs_per_cell;
-                   ++shape_function)
-                {
-                  const int snc = shape_function_data[shape_function]
-                                    .single_nonzero_component;
-
-                  if (snc == -2)
-                    // shape function is zero for the selected components
-                    continue;
-
-                  const Number &value = dof_values[shape_function];
-                  // For auto-differentiable numbers, the fact that a DoF value
-                  // is zero does not imply that its derivatives are zero as
-                  // well. So we can't filter by value for these number types.
-                  if (dealii::internal::CheckForZero<Number>::value(value) ==
-                      true)
-                    continue;
-
-                  if (snc != -1)
-                    {
-                      const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                        &shape_gradients[snc][0];
-
-                      Assert(shape_function_data[shape_function]
-                                 .single_nonzero_component >= 0,
-                             ExcInternalError());
-                      // we're in 2d, so the formula for the curl is simple:
-                      if (shape_function_data[shape_function]
-                            .single_nonzero_component_index == 0)
-                        for (unsigned int q_point = 0;
-                             q_point < n_quadrature_points;
-                             ++q_point)
-                          curls[q_point][0] -=
-                            value * (*shape_gradient_ptr++)[1];
-                      else
-                        for (unsigned int q_point = 0;
-                             q_point < n_quadrature_points;
-                             ++q_point)
-                          curls[q_point][0] +=
-                            value * (*shape_gradient_ptr++)[0];
-                    }
-                  else
-                    // we have multiple non-zero components in the shape
-                    // functions. not all of them must necessarily be within the
-                    // 2-component window this FEValuesViews::Vector object
-                    // considers, however.
-                    {
-                      if (shape_function_data[shape_function]
-                            .is_nonzero_shape_function_component[0])
-                        {
-                          const dealii::Tensor<1,
-                                               spacedim> *shape_gradient_ptr =
-                            &shape_gradients[shape_function_data[shape_function]
-                                               .row_index[0]][0];
-
-                          for (unsigned int q_point = 0;
-                               q_point < n_quadrature_points;
-                               ++q_point)
-                            curls[q_point][0] -=
-                              value * (*shape_gradient_ptr++)[1];
-                        }
-
-                      if (shape_function_data[shape_function]
-                            .is_nonzero_shape_function_component[1])
-                        {
-                          const dealii::Tensor<1,
-                                               spacedim> *shape_gradient_ptr =
-                            &shape_gradients[shape_function_data[shape_function]
-                                               .row_index[1]][0];
-
-                          for (unsigned int q_point = 0;
-                               q_point < n_quadrature_points;
-                               ++q_point)
-                            curls[q_point][0] +=
-                              value * (*shape_gradient_ptr++)[0];
-                        }
-                    }
-                }
-              break;
-            }
-
-          case 3:
-            {
-              for (unsigned int shape_function = 0;
-                   shape_function < dofs_per_cell;
-                   ++shape_function)
-                {
-                  const int snc = shape_function_data[shape_function]
-                                    .single_nonzero_component;
-
-                  if (snc == -2)
-                    // shape function is zero for the selected components
-                    continue;
-
-                  const Number &value = dof_values[shape_function];
-                  // For auto-differentiable numbers, the fact that a DoF value
-                  // is zero does not imply that its derivatives are zero as
-                  // well. So we can't filter by value for these number types.
-                  if (dealii::internal::CheckForZero<Number>::value(value) ==
-                      true)
-                    continue;
-
-                  if (snc != -1)
-                    {
-                      const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                        &shape_gradients[snc][0];
-
-                      switch (shape_function_data[shape_function]
-                                .single_nonzero_component_index)
-                        {
-                          case 0:
-                            {
-                              for (unsigned int q_point = 0;
-                                   q_point < n_quadrature_points;
-                                   ++q_point)
-                                {
-                                  curls[q_point][1] +=
-                                    value * (*shape_gradient_ptr)[2];
-                                  curls[q_point][2] -=
-                                    value * (*shape_gradient_ptr++)[1];
-                                }
-
-                              break;
-                            }
-
-                          case 1:
-                            {
-                              for (unsigned int q_point = 0;
-                                   q_point < n_quadrature_points;
-                                   ++q_point)
-                                {
-                                  curls[q_point][0] -=
-                                    value * (*shape_gradient_ptr)[2];
-                                  curls[q_point][2] +=
-                                    value * (*shape_gradient_ptr++)[0];
-                                }
-
-                              break;
-                            }
-
-                          case 2:
-                            {
-                              for (unsigned int q_point = 0;
-                                   q_point < n_quadrature_points;
-                                   ++q_point)
-                                {
-                                  curls[q_point][0] +=
-                                    value * (*shape_gradient_ptr)[1];
-                                  curls[q_point][1] -=
-                                    value * (*shape_gradient_ptr++)[0];
-                                }
-                              break;
-                            }
-
-                          default:
-                            Assert(false, ExcInternalError());
-                        }
-                    }
-
-                  else
-                    // we have multiple non-zero components in the shape
-                    // functions. not all of them must necessarily be within the
-                    // 3-component window this FEValuesViews::Vector object
-                    // considers, however.
-                    {
-                      if (shape_function_data[shape_function]
-                            .is_nonzero_shape_function_component[0])
-                        {
-                          const dealii::Tensor<1,
-                                               spacedim> *shape_gradient_ptr =
-                            &shape_gradients[shape_function_data[shape_function]
-                                               .row_index[0]][0];
-
-                          for (unsigned int q_point = 0;
-                               q_point < n_quadrature_points;
-                               ++q_point)
-                            {
-                              curls[q_point][1] +=
-                                value * (*shape_gradient_ptr)[2];
-                              curls[q_point][2] -=
-                                value * (*shape_gradient_ptr++)[1];
-                            }
-                        }
-
-                      if (shape_function_data[shape_function]
-                            .is_nonzero_shape_function_component[1])
-                        {
-                          const dealii::Tensor<1,
-                                               spacedim> *shape_gradient_ptr =
-                            &shape_gradients[shape_function_data[shape_function]
-                                               .row_index[1]][0];
-
-                          for (unsigned int q_point = 0;
-                               q_point < n_quadrature_points;
-                               ++q_point)
-                            {
-                              curls[q_point][0] -=
-                                value * (*shape_gradient_ptr)[2];
-                              curls[q_point][2] +=
-                                value * (*shape_gradient_ptr++)[0];
-                            }
-                        }
-
-                      if (shape_function_data[shape_function]
-                            .is_nonzero_shape_function_component[2])
-                        {
-                          const dealii::Tensor<1,
-                                               spacedim> *shape_gradient_ptr =
-                            &shape_gradients[shape_function_data[shape_function]
-                                               .row_index[2]][0];
-
-                          for (unsigned int q_point = 0;
-                               q_point < n_quadrature_points;
-                               ++q_point)
-                            {
-                              curls[q_point][0] +=
-                                value * (*shape_gradient_ptr)[1];
-                              curls[q_point][1] -=
-                                value * (*shape_gradient_ptr++)[0];
-                            }
-                        }
-                    }
-                }
-            }
+          this->shape_gradients.reinit(n_nonzero_shape_components,
+                                       n_quadrature_points);
+          this->shape_gradients.fill(
+            numbers::signaling_nan<Tensor<1, spacedim>>());
         }
-    }
-
-
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_laplacians(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians,
-      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename Vector<dim, spacedim>::
-                    template solution_laplacian_type<Number>> &laplacians)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = laplacians.size();
-
-      std::fill(
-        laplacians.begin(),
-        laplacians.end(),
-        typename Vector<dim,
-                        spacedim>::template solution_laplacian_type<Number>());
 
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
+      if (flags & update_hessians)
         {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-              const dealii::Tensor<2, spacedim> *shape_hessian_ptr =
-                &shape_hessians[snc][0];
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                laplacians[q_point][comp] +=
-                  value * trace(*shape_hessian_ptr++);
-            }
-          else
-            for (unsigned int d = 0; d < spacedim; ++d)
-              if (shape_function_data[shape_function]
-                    .is_nonzero_shape_function_component[d])
-                {
-                  const dealii::Tensor<2, spacedim> *shape_hessian_ptr =
-                    &shape_hessians[shape_function_data[shape_function]
-                                      .row_index[d]][0];
-                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                       ++q_point)
-                    laplacians[q_point][d] +=
-                      value * trace(*shape_hessian_ptr++);
-                }
+          this->shape_hessians.reinit(n_nonzero_shape_components,
+                                      n_quadrature_points);
+          this->shape_hessians.fill(
+            numbers::signaling_nan<Tensor<2, spacedim>>());
         }
-    }
-
-
-
-    // ---------------------- symmetric tensor part ------------------------
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_values(
-      const ArrayView<Number> &       dof_values,
-      const dealii::Table<2, double> &shape_values,
-      const std::vector<
-        typename SymmetricTensor<2, dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<
-        typename ProductType<Number,
-                             dealii::SymmetricTensor<2, spacedim>>::type>
-        &values)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = values.size();
-
-      std::fill(
-        values.begin(),
-        values.end(),
-        typename ProductType<Number,
-                             dealii::SymmetricTensor<2, spacedim>>::type());
 
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
+      if (flags & update_3rd_derivatives)
         {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const TableIndices<2> comp = dealii::
-                SymmetricTensor<2, spacedim>::unrolled_to_component_indices(
-                  shape_function_data[shape_function]
-                    .single_nonzero_component_index);
-              const double *shape_value_ptr = &shape_values(snc, 0);
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                values[q_point][comp] += value * (*shape_value_ptr++);
-            }
-          else
-            for (unsigned int d = 0;
-                 d <
-                 dealii::SymmetricTensor<2, spacedim>::n_independent_components;
-                 ++d)
-              if (shape_function_data[shape_function]
-                    .is_nonzero_shape_function_component[d])
-                {
-                  const TableIndices<2> comp =
-                    dealii::SymmetricTensor<2, spacedim>::
-                      unrolled_to_component_indices(d);
-                  const double *shape_value_ptr = &shape_values(
-                    shape_function_data[shape_function].row_index[d], 0);
-                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                       ++q_point)
-                    values[q_point][comp] += value * (*shape_value_ptr++);
-                }
+          this->shape_3rd_derivatives.reinit(n_nonzero_shape_components,
+                                             n_quadrature_points);
+          this->shape_3rd_derivatives.fill(
+            numbers::signaling_nan<Tensor<3, spacedim>>());
         }
     }
 
 
 
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_divergences(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
-      const std::vector<
-        typename SymmetricTensor<2, dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename SymmetricTensor<2, dim, spacedim>::
-                    template solution_divergence_type<Number>> &divergences)
+    template <int dim, int spacedim>
+    std::size_t
+    FiniteElementRelatedData<dim, spacedim>::memory_consumption() const
     {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = divergences.size();
-
-      std::fill(divergences.begin(),
-                divergences.end(),
-                typename SymmetricTensor<2, dim, spacedim>::
-                  template solution_divergence_type<Number>());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-
-              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                &shape_gradients[snc][0];
-
-              const unsigned int ii = dealii::SymmetricTensor<2, spacedim>::
-                unrolled_to_component_indices(comp)[0];
-              const unsigned int jj = dealii::SymmetricTensor<2, spacedim>::
-                unrolled_to_component_indices(comp)[1];
-
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point, ++shape_gradient_ptr)
-                {
-                  divergences[q_point][ii] += value * (*shape_gradient_ptr)[jj];
-
-                  if (ii != jj)
-                    divergences[q_point][jj] +=
-                      value * (*shape_gradient_ptr)[ii];
-                }
-            }
-          else
-            {
-              for (unsigned int d = 0;
-                   d <
-                   dealii::SymmetricTensor<2,
-                                           spacedim>::n_independent_components;
-                   ++d)
-                if (shape_function_data[shape_function]
-                      .is_nonzero_shape_function_component[d])
-                  {
-                    Assert(false, ExcNotImplemented());
-
-                    // the following implementation needs to be looked over -- I
-                    // think it can't be right, because we are in a case where
-                    // there is no single nonzero component
-                    //
-                    // the following is not implemented! we need to consider the
-                    // interplay between multiple non-zero entries in shape
-                    // function and the representation as a symmetric
-                    // second-order tensor
-                    const unsigned int comp =
-                      shape_function_data[shape_function]
-                        .single_nonzero_component_index;
-
-                    const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                      &shape_gradients[shape_function_data[shape_function]
-                                         .row_index[d]][0];
-                    for (unsigned int q_point = 0;
-                         q_point < n_quadrature_points;
-                         ++q_point, ++shape_gradient_ptr)
-                      {
-                        for (unsigned int j = 0; j < spacedim; ++j)
-                          {
-                            const unsigned int vector_component =
-                              dealii::SymmetricTensor<2, spacedim>::
-                                component_to_unrolled_index(
-                                  TableIndices<2>(comp, j));
-                            divergences[q_point][vector_component] +=
-                              value * (*shape_gradient_ptr++)[j];
-                          }
-                      }
-                  }
-            }
-        }
+      return (
+        MemoryConsumption::memory_consumption(shape_values) +
+        MemoryConsumption::memory_consumption(shape_gradients) +
+        MemoryConsumption::memory_consumption(shape_hessians) +
+        MemoryConsumption::memory_consumption(shape_3rd_derivatives) +
+        MemoryConsumption::memory_consumption(shape_function_to_row_table));
     }
-
-    // ---------------------- non-symmetric tensor part ------------------------
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_values(
-      const ArrayView<Number> &       dof_values,
-      const dealii::Table<2, double> &shape_values,
-      const std::vector<typename Tensor<2, dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<
-        typename ProductType<Number, dealii::Tensor<2, spacedim>>::type>
-        &values)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = values.size();
-
-      std::fill(
-        values.begin(),
-        values.end(),
-        typename ProductType<Number, dealii::Tensor<2, spacedim>>::type());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-
-              const TableIndices<2> indices =
-                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
-                  comp);
-
-              const double *shape_value_ptr = &shape_values(snc, 0);
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point)
-                values[q_point][indices] += value * (*shape_value_ptr++);
-            }
-          else
-            for (unsigned int d = 0; d < dim * dim; ++d)
-              if (shape_function_data[shape_function]
-                    .is_nonzero_shape_function_component[d])
-                {
-                  const TableIndices<2> indices =
-                    dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
-                      d);
-
-                  const double *shape_value_ptr = &shape_values(
-                    shape_function_data[shape_function].row_index[d], 0);
-                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                       ++q_point)
-                    values[q_point][indices] += value * (*shape_value_ptr++);
-                }
-        }
-    }
-
-
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_divergences(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
-      const std::vector<typename Tensor<2, dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename Tensor<2, dim, spacedim>::
-                    template solution_divergence_type<Number>> &divergences)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = divergences.size();
-
-      std::fill(
-        divergences.begin(),
-        divergences.end(),
-        typename Tensor<2, dim, spacedim>::template solution_divergence_type<
-          Number>());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-
-              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                &shape_gradients[snc][0];
-
-              const TableIndices<2> indices =
-                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
-                  comp);
-              const unsigned int ii = indices[0];
-              const unsigned int jj = indices[1];
-
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point, ++shape_gradient_ptr)
-                {
-                  divergences[q_point][ii] += value * (*shape_gradient_ptr)[jj];
-                }
-            }
-          else
-            {
-              for (unsigned int d = 0; d < dim * dim; ++d)
-                if (shape_function_data[shape_function]
-                      .is_nonzero_shape_function_component[d])
-                  {
-                    Assert(false, ExcNotImplemented());
-                  }
-            }
-        }
-    }
-
-
-
-    template <int dim, int spacedim, typename Number>
-    void
-    do_function_gradients(
-      const ArrayView<Number> &                    dof_values,
-      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
-      const std::vector<typename Tensor<2, dim, spacedim>::ShapeFunctionData>
-        &shape_function_data,
-      std::vector<typename Tensor<2, dim, spacedim>::
-                    template solution_gradient_type<Number>> &gradients)
-    {
-      const unsigned int dofs_per_cell       = dof_values.size();
-      const unsigned int n_quadrature_points = gradients.size();
-
-      std::fill(
-        gradients.begin(),
-        gradients.end(),
-        typename Tensor<2, dim, spacedim>::template solution_gradient_type<
-          Number>());
-
-      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
-           ++shape_function)
-        {
-          const int snc =
-            shape_function_data[shape_function].single_nonzero_component;
-
-          if (snc == -2)
-            // shape function is zero for the selected components
-            continue;
-
-          const Number &value = dof_values[shape_function];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (snc != -1)
-            {
-              const unsigned int comp = shape_function_data[shape_function]
-                                          .single_nonzero_component_index;
-
-              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
-                &shape_gradients[snc][0];
-
-              const TableIndices<2> indices =
-                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
-                  comp);
-              const unsigned int ii = indices[0];
-              const unsigned int jj = indices[1];
-
-              for (unsigned int q_point = 0; q_point < n_quadrature_points;
-                   ++q_point, ++shape_gradient_ptr)
-                {
-                  gradients[q_point][ii][jj] += value * (*shape_gradient_ptr);
-                }
-            }
-          else
-            {
-              for (unsigned int d = 0; d < dim * dim; ++d)
-                if (shape_function_data[shape_function]
-                      .is_nonzero_shape_function_component[d])
-                  {
-                    Assert(false, ExcNotImplemented());
-                  }
-            }
-        }
-    }
-
-  } // end of namespace internal
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Scalar<dim, spacedim>::get_function_values(
-    const ReadVector<Number> &                fe_function,
-    std::vector<solution_value_type<Number>> &values) const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-
-    // get function values of dofs on this cell and call internal worker
-    // function
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Scalar<dim, spacedim>::get_function_values_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_value_type<typename InputVector::value_type>> &values)
-    const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Scalar<dim, spacedim>::get_function_gradients(
-    const ReadVector<Number> &                   fe_function,
-    std::vector<solution_gradient_type<Number>> &gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_derivatives<1, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename InputVector>
-  void
-  Scalar<dim, spacedim>::get_function_gradients_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_gradient_type<typename InputVector::value_type>>
-      &gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_derivatives<1, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Scalar<dim, spacedim>::get_function_hessians(
-    const ReadVector<Number> &                  fe_function,
-    std::vector<solution_hessian_type<Number>> &hessians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_derivatives<2, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      hessians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Scalar<dim, spacedim>::get_function_hessians_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_hessian_type<typename InputVector::value_type>>
-      &hessians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_derivatives<2, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      hessians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Scalar<dim, spacedim>::get_function_laplacians(
-    const ReadVector<Number> &                    fe_function,
-    std::vector<solution_laplacian_type<Number>> &laplacians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_laplacians<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      laplacians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Scalar<dim, spacedim>::get_function_laplacians_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_laplacian_type<typename InputVector::value_type>>
-      &laplacians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_laplacians<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      laplacians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Scalar<dim, spacedim>::get_function_third_derivatives(
-    const ReadVector<Number> &                           fe_function,
-    std::vector<solution_third_derivative_type<Number>> &third_derivatives)
-    const
-  {
-    Assert(fe_values->update_flags & update_3rd_derivatives,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_3rd_derivatives")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_derivatives<3, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_3rd_derivatives,
-      shape_function_data,
-      third_derivatives);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Scalar<dim, spacedim>::get_function_third_derivatives_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<
-      solution_third_derivative_type<typename InputVector::value_type>>
-      &third_derivatives) const
-  {
-    Assert(fe_values->update_flags & update_3rd_derivatives,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_3rd_derivatives")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_derivatives<3, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_3rd_derivatives,
-      shape_function_data,
-      third_derivatives);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_values(
-    const ReadVector<Number> &                fe_function,
-    std::vector<solution_value_type<Number>> &values) const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_values_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_value_type<typename InputVector::value_type>> &values)
-    const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_gradients(
-    const ReadVector<Number> &                   fe_function,
-    std::vector<solution_gradient_type<Number>> &gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_derivatives<1, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename InputVector>
-  void
-  Vector<dim, spacedim>::get_function_gradients_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_gradient_type<typename InputVector::value_type>>
-      &gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_derivatives<1, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_symmetric_gradients(
-    const ReadVector<Number> &                             fe_function,
-    std::vector<solution_symmetric_gradient_type<Number>> &symmetric_gradients)
-    const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_symmetric_gradients<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      symmetric_gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_symmetric_gradients_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<
-      solution_symmetric_gradient_type<typename InputVector::value_type>>
-      &symmetric_gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_symmetric_gradients<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      symmetric_gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_divergences(
-    const ReadVector<Number> &                     fe_function,
-    std::vector<solution_divergence_type<Number>> &divergences) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs
-    // on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_divergences<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      divergences);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_divergences_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_divergence_type<typename InputVector::value_type>>
-      &divergences) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_divergences<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      divergences);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_curls(
-    const ReadVector<Number> &               fe_function,
-    std::vector<solution_curl_type<Number>> &curls) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           ExcMessage("FEValues object is not reinited to any cell"));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_curls<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      curls);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_curls_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_curl_type<typename InputVector::value_type>> &curls)
-    const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           ExcMessage("FEValues object is not reinited to any cell"));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_curls<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      curls);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_hessians(
-    const ReadVector<Number> &                  fe_function,
-    std::vector<solution_hessian_type<Number>> &hessians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_derivatives<2, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      hessians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_hessians_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_hessian_type<typename InputVector::value_type>>
-      &hessians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_derivatives<2, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      hessians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_laplacians(
-    const ReadVector<Number> &                fe_function,
-    std::vector<solution_value_type<Number>> &laplacians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(laplacians.size() == fe_values->n_quadrature_points,
-           ExcDimensionMismatch(laplacians.size(),
-                                fe_values->n_quadrature_points));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    Assert(
-      fe_function.size() == fe_values->present_cell.n_dofs_for_dof_handler(),
-      ExcDimensionMismatch(fe_function.size(),
-                           fe_values->present_cell.n_dofs_for_dof_handler()));
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_laplacians<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      laplacians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_laplacians_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_laplacian_type<typename InputVector::value_type>>
-      &laplacians) const
-  {
-    Assert(fe_values->update_flags & update_hessians,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_hessians")));
-    Assert(laplacians.size() == fe_values->n_quadrature_points,
-           ExcDimensionMismatch(laplacians.size(),
-                                fe_values->n_quadrature_points));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_laplacians<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_hessians,
-      shape_function_data,
-      laplacians);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Vector<dim, spacedim>::get_function_third_derivatives(
-    const ReadVector<Number> &                           fe_function,
-    std::vector<solution_third_derivative_type<Number>> &third_derivatives)
-    const
-  {
-    Assert(fe_values->update_flags & update_3rd_derivatives,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_3rd_derivatives")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_derivatives<3, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_3rd_derivatives,
-      shape_function_data,
-      third_derivatives);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Vector<dim, spacedim>::get_function_third_derivatives_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<
-      solution_third_derivative_type<typename InputVector::value_type>>
-      &third_derivatives) const
-  {
-    Assert(fe_values->update_flags & update_3rd_derivatives,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_3rd_derivatives")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_derivatives<3, dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_3rd_derivatives,
-      shape_function_data,
-      third_derivatives);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  SymmetricTensor<2, dim, spacedim>::get_function_values(
-    const ReadVector<Number> &                fe_function,
-    std::vector<solution_value_type<Number>> &values) const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  SymmetricTensor<2, dim, spacedim>::get_function_values_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_value_type<typename InputVector::value_type>> &values)
-    const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  SymmetricTensor<2, dim, spacedim>::get_function_divergences(
-    const ReadVector<Number> &                     fe_function,
-    std::vector<solution_divergence_type<Number>> &divergences) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs
-    // on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_divergences<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      divergences);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  SymmetricTensor<2, dim, spacedim>::
-    get_function_divergences_from_local_dof_values(
-      const InputVector &dof_values,
-      std::vector<solution_divergence_type<typename InputVector::value_type>>
-        &divergences) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_divergences<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      divergences);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Tensor<2, dim, spacedim>::get_function_values(
-    const ReadVector<Number> &                fe_function,
-    std::vector<solution_value_type<Number>> &values) const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-
-    // get function values of dofs on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Tensor<2, dim, spacedim>::get_function_values_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_value_type<typename InputVector::value_type>> &values)
-    const
-  {
-    Assert(fe_values->update_flags & update_values,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_values")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_values<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_values,
-      shape_function_data,
-      values);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Tensor<2, dim, spacedim>::get_function_divergences(
-    const ReadVector<Number> &                     fe_function,
-    std::vector<solution_divergence_type<Number>> &divergences) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs
-    // on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_divergences<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      divergences);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Tensor<2, dim, spacedim>::get_function_divergences_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_divergence_type<typename InputVector::value_type>>
-      &divergences) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_divergences<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      divergences);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <typename Number>
-  void
-  Tensor<2, dim, spacedim>::get_function_gradients(
-    const ReadVector<Number> &                   fe_function,
-    std::vector<solution_gradient_type<Number>> &gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(fe_function.size(),
-                    fe_values->present_cell.n_dofs_for_dof_handler());
-
-    // get function values of dofs
-    // on this cell
-    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
-    fe_values->present_cell.get_interpolated_dof_values(fe_function,
-                                                        dof_values);
-    internal::do_function_gradients<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      gradients);
-  }
-
-
-
-  template <int dim, int spacedim>
-  template <class InputVector>
-  void
-  Tensor<2, dim, spacedim>::get_function_gradients_from_local_dof_values(
-    const InputVector &dof_values,
-    std::vector<solution_gradient_type<typename InputVector::value_type>>
-      &gradients) const
-  {
-    Assert(fe_values->update_flags & update_gradients,
-           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-             "update_gradients")));
-    Assert(fe_values->present_cell.is_initialized(),
-           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
-    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
-
-    internal::do_function_gradients<dim, spacedim>(
-      make_array_view(dof_values.begin(), dof_values.end()),
-      fe_values->finite_element_output.shape_gradients,
-      shape_function_data,
-      gradients);
-  }
-
-} // namespace FEValuesViews
-
-
-namespace internal
-{
-  namespace FEValuesViews
-  {
-    template <int dim, int spacedim>
-    Cache<dim, spacedim>::Cache(const FEValuesBase<dim, spacedim> &fe_values)
-    {
-      const FiniteElement<dim, spacedim> &fe = fe_values.get_fe();
-
-      const unsigned int n_scalars = fe.n_components();
-      scalars.reserve(n_scalars);
-      for (unsigned int component = 0; component < n_scalars; ++component)
-        scalars.emplace_back(fe_values, component);
-
-      // compute number of vectors that we can fit into this finite element.
-      // note that this is based on the dimensionality 'dim' of the manifold,
-      // not 'spacedim' of the output vector
-      const unsigned int n_vectors =
-        (fe.n_components() >= Tensor<1, spacedim>::n_independent_components ?
-           fe.n_components() - Tensor<1, spacedim>::n_independent_components +
-             1 :
-           0);
-      vectors.reserve(n_vectors);
-      for (unsigned int component = 0; component < n_vectors; ++component)
-        vectors.emplace_back(fe_values, component);
-
-      // compute number of symmetric tensors in the same way as above
-      const unsigned int n_symmetric_second_order_tensors =
-        (fe.n_components() >=
-             SymmetricTensor<2, spacedim>::n_independent_components ?
-           fe.n_components() -
-             SymmetricTensor<2, spacedim>::n_independent_components + 1 :
-           0);
-      symmetric_second_order_tensors.reserve(n_symmetric_second_order_tensors);
-      for (unsigned int component = 0;
-           component < n_symmetric_second_order_tensors;
-           ++component)
-        symmetric_second_order_tensors.emplace_back(fe_values, component);
-
-
-      // compute number of symmetric tensors in the same way as above
-      const unsigned int n_second_order_tensors =
-        (fe.n_components() >= Tensor<2, spacedim>::n_independent_components ?
-           fe.n_components() - Tensor<2, spacedim>::n_independent_components +
-             1 :
-           0);
-      second_order_tensors.reserve(n_second_order_tensors);
-      for (unsigned int component = 0; component < n_second_order_tensors;
-           ++component)
-        second_order_tensors.emplace_back(fe_values, component);
-    }
-  } // namespace FEValuesViews
-} // namespace internal
-
-
-/* ---------------- FEValuesBase<dim,spacedim>::CellIteratorContainer ---------
- */
-
-template <int dim, int spacedim>
-FEValuesBase<dim, spacedim>::CellIteratorContainer::CellIteratorContainer()
-  : initialized(false)
-  , cell(typename Triangulation<dim, spacedim>::cell_iterator(nullptr, -1, -1))
-  , dof_handler(nullptr)
-  , level_dof_access(false)
-{}
-
-
-
-template <int dim, int spacedim>
-FEValuesBase<dim, spacedim>::CellIteratorContainer::CellIteratorContainer(
-  const typename Triangulation<dim, spacedim>::cell_iterator &cell)
-  : initialized(true)
-  , cell(cell)
-  , dof_handler(nullptr)
-  , level_dof_access(false)
-{}
-
-
-
-template <int dim, int spacedim>
-bool
-FEValuesBase<dim, spacedim>::CellIteratorContainer::is_initialized() const
-{
-  return initialized;
-}
-
-
-
-template <int dim, int spacedim>
-FEValuesBase<dim, spacedim>::CellIteratorContainer::
-operator typename Triangulation<dim, spacedim>::cell_iterator() const
-{
-  Assert(is_initialized(), ExcNotReinited());
-
-  return cell;
-}
-
-
-
-template <int dim, int spacedim>
-types::global_dof_index
-FEValuesBase<dim, spacedim>::CellIteratorContainer::n_dofs_for_dof_handler()
-  const
-{
-  Assert(is_initialized(), ExcNotReinited());
-  Assert(dof_handler != nullptr, ExcNeedsDoFHandler());
-
-  return dof_handler->n_dofs();
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::CellIteratorContainer::get_interpolated_dof_values(
-  const ReadVector<Number> &in,
-  Vector<Number> &          out) const
-{
-  Assert(is_initialized(), ExcNotReinited());
-  Assert(dof_handler != nullptr, ExcNeedsDoFHandler());
-
-  if (level_dof_access)
-    DoFCellAccessor<dim, spacedim, true>(&cell->get_triangulation(),
-                                         cell->level(),
-                                         cell->index(),
-                                         dof_handler)
-      .get_interpolated_dof_values(in, out);
-  else
-    DoFCellAccessor<dim, spacedim, false>(&cell->get_triangulation(),
-                                          cell->level(),
-                                          cell->index(),
-                                          dof_handler)
-      .get_interpolated_dof_values(in, out);
-}
-
-
-
-template <int dim, int spacedim>
-void
-FEValuesBase<dim, spacedim>::CellIteratorContainer::get_interpolated_dof_values(
-  const IndexSet &              in,
-  Vector<IndexSet::value_type> &out) const
-{
-  Assert(is_initialized(), ExcNotReinited());
-  Assert(dof_handler != nullptr, ExcNeedsDoFHandler());
-  Assert(level_dof_access == false, ExcNotImplemented());
-
-  const DoFCellAccessor<dim, spacedim, false> cell_dofs(
-    &cell->get_triangulation(), cell->level(), cell->index(), dof_handler);
-
-  std::vector<types::global_dof_index> dof_indices(
-    cell_dofs.get_fe().n_dofs_per_cell());
-  cell_dofs.get_dof_indices(dof_indices);
-
-  for (unsigned int i = 0; i < cell_dofs.get_fe().n_dofs_per_cell(); ++i)
-    out[i] = (in.is_element(dof_indices[i]) ? 1 : 0);
-}
-
-
-
-namespace internal
-{
-  namespace FEValuesImplementation
-  {
-    template <int dim, int spacedim>
-    void
-    FiniteElementRelatedData<dim, spacedim>::initialize(
-      const unsigned int                  n_quadrature_points,
-      const FiniteElement<dim, spacedim> &fe,
-      const UpdateFlags                   flags)
-    {
-      // initialize the table mapping from shape function number to
-      // the rows in the tables storing the data by shape function and
-      // nonzero component
-      this->shape_function_to_row_table =
-        dealii::internal::make_shape_function_to_row_table(fe);
-
-      // count the total number of non-zero components accumulated
-      // over all shape functions
-      unsigned int n_nonzero_shape_components = 0;
-      for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
-        n_nonzero_shape_components += fe.n_nonzero_components(i);
-      Assert(n_nonzero_shape_components >= fe.n_dofs_per_cell(),
-             ExcInternalError());
-
-      // with the number of rows now known, initialize those fields
-      // that we will need to their correct size
-      if (flags & update_values)
-        {
-          this->shape_values.reinit(n_nonzero_shape_components,
-                                    n_quadrature_points);
-          this->shape_values.fill(numbers::signaling_nan<double>());
-        }
-
-      if (flags & update_gradients)
-        {
-          this->shape_gradients.reinit(n_nonzero_shape_components,
-                                       n_quadrature_points);
-          this->shape_gradients.fill(
-            numbers::signaling_nan<Tensor<1, spacedim>>());
-        }
-
-      if (flags & update_hessians)
-        {
-          this->shape_hessians.reinit(n_nonzero_shape_components,
-                                      n_quadrature_points);
-          this->shape_hessians.fill(
-            numbers::signaling_nan<Tensor<2, spacedim>>());
-        }
-
-      if (flags & update_3rd_derivatives)
-        {
-          this->shape_3rd_derivatives.reinit(n_nonzero_shape_components,
-                                             n_quadrature_points);
-          this->shape_3rd_derivatives.fill(
-            numbers::signaling_nan<Tensor<3, spacedim>>());
-        }
-    }
-
-
-
-    template <int dim, int spacedim>
-    std::size_t
-    FiniteElementRelatedData<dim, spacedim>::memory_consumption() const
-    {
-      return (
-        MemoryConsumption::memory_consumption(shape_values) +
-        MemoryConsumption::memory_consumption(shape_gradients) +
-        MemoryConsumption::memory_consumption(shape_hessians) +
-        MemoryConsumption::memory_consumption(shape_3rd_derivatives) +
-        MemoryConsumption::memory_consumption(shape_function_to_row_table));
-    }
-  } // namespace FEValuesImplementation
-} // namespace internal
-
-
-
-/*------------------------------- FEValuesBase ---------------------------*/
-
-
-template <int dim, int spacedim>
-FEValuesBase<dim, spacedim>::FEValuesBase(
-  const unsigned int                  n_q_points,
-  const unsigned int                  dofs_per_cell,
-  const UpdateFlags                   flags,
-  const Mapping<dim, spacedim> &      mapping,
-  const FiniteElement<dim, spacedim> &fe)
-  : n_quadrature_points(n_q_points)
-  , max_n_quadrature_points(n_q_points)
-  , dofs_per_cell(dofs_per_cell)
-  , mapping(&mapping, typeid(*this).name())
-  , fe(&fe, typeid(*this).name())
-  , cell_similarity(CellSimilarity::Similarity::none)
-  , fe_values_views_cache(*this)
-{
-  Assert(n_q_points > 0,
-         ExcMessage("There is nothing useful you can do with an FEValues "
-                    "object when using a quadrature formula with zero "
-                    "quadrature points!"));
-  this->update_flags = flags;
-}
-
-
-
-template <int dim, int spacedim>
-FEValuesBase<dim, spacedim>::~FEValuesBase()
-{
-  tria_listener_refinement.disconnect();
-  tria_listener_mesh_transform.disconnect();
-}
-
-
-
-namespace internal
-{
-  // put shape function part of get_function_xxx methods into separate
-  // internal functions. this allows us to reuse the same code for several
-  // functions (e.g. both the versions with and without indices) as well as
-  // the same code for gradients and Hessians. Moreover, this speeds up
-  // compilation and reduces the size of the final file since all the
-  // different global vectors get channeled through the same code.
-
-  template <typename Number, typename Number2>
-  void
-  do_function_values(const ArrayView<Number2> &      dof_values,
-                     const dealii::Table<2, double> &shape_values,
-                     std::vector<Number> &           values)
-  {
-    // scalar finite elements, so shape_values.size() == dofs_per_cell
-    const unsigned int dofs_per_cell       = shape_values.n_rows();
-    const unsigned int n_quadrature_points = values.size();
-
-    // initialize with zero
-    std::fill_n(values.begin(),
-                n_quadrature_points,
-                dealii::internal::NumberType<Number>::value(0.0));
-
-    // add up contributions of trial functions. note that here we deal with
-    // scalar finite elements, so no need to check for non-primitivity of
-    // shape functions. in order to increase the speed of this function, we
-    // directly access the data in the shape_values array, and increment
-    // pointers for accessing the data. this saves some lookup time and
-    // indexing. moreover, the order of the loops is such that we can access
-    // the shape_values data stored contiguously
-    for (unsigned int shape_func = 0; shape_func < dofs_per_cell; ++shape_func)
-      {
-        const Number2 value = dof_values[shape_func];
-        // For auto-differentiable numbers, the fact that a DoF value is zero
-        // does not imply that its derivatives are zero as well. So we
-        // can't filter by value for these number types.
-        if (!Differentiation::AD::is_ad_number<Number2>::value)
-          if (value == dealii::internal::NumberType<Number2>::value(0.0))
-            continue;
-
-        const double *shape_value_ptr = &shape_values(shape_func, 0);
-        for (unsigned int point = 0; point < n_quadrature_points; ++point)
-          values[point] += value * (*shape_value_ptr++);
-      }
-  }
-
-
-
-  template <int dim, int spacedim, typename VectorType>
-  void
-  do_function_values(
-    const ArrayView<typename VectorType::value_type> &dof_values,
-    const dealii::Table<2, double> &                  shape_values,
-    const FiniteElement<dim, spacedim> &              fe,
-    const std::vector<unsigned int> &shape_function_to_row_table,
-    ArrayView<VectorType>            values,
-    const bool                       quadrature_points_fastest = false,
-    const unsigned int               component_multiple        = 1)
-  {
-    using Number = typename VectorType::value_type;
-    // initialize with zero
-    for (unsigned int i = 0; i < values.size(); ++i)
-      std::fill_n(values[i].begin(),
-                  values[i].size(),
-                  typename VectorType::value_type());
-
-    // see if there the current cell has DoFs at all, and if not
-    // then there is nothing else to do.
-    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
-    if (dofs_per_cell == 0)
-      return;
-
-    const unsigned int n_quadrature_points =
-      quadrature_points_fastest ? values[0].size() : values.size();
-    const unsigned int n_components = fe.n_components();
-
-    // Assert that we can write all components into the result vectors
-    const unsigned result_components = n_components * component_multiple;
-    (void)result_components;
-    if (quadrature_points_fastest)
-      {
-        AssertDimension(values.size(), result_components);
-        for (unsigned int i = 0; i < values.size(); ++i)
-          AssertDimension(values[i].size(), n_quadrature_points);
-      }
-    else
-      {
-        AssertDimension(values.size(), n_quadrature_points);
-        for (unsigned int i = 0; i < values.size(); ++i)
-          AssertDimension(values[i].size(), result_components);
-      }
-
-    // add up contributions of trial functions.  now check whether the shape
-    // function is primitive or not. if it is, then set its only non-zero
-    // component, otherwise loop over components
-    for (unsigned int mc = 0; mc < component_multiple; ++mc)
-      for (unsigned int shape_func = 0; shape_func < dofs_per_cell;
-           ++shape_func)
-        {
-          const Number &value = dof_values[shape_func + mc * dofs_per_cell];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (fe.is_primitive(shape_func))
-            {
-              const unsigned int comp =
-                fe.system_to_component_index(shape_func).first +
-                mc * n_components;
-              const unsigned int row =
-                shape_function_to_row_table[shape_func * n_components + comp];
-
-              const double *shape_value_ptr = &shape_values(row, 0);
-
-              if (quadrature_points_fastest)
-                {
-                  VectorType &values_comp = values[comp];
-                  for (unsigned int point = 0; point < n_quadrature_points;
-                       ++point)
-                    values_comp[point] += value * (*shape_value_ptr++);
-                }
-              else
-                for (unsigned int point = 0; point < n_quadrature_points;
-                     ++point)
-                  values[point][comp] += value * (*shape_value_ptr++);
-            }
-          else
-            for (unsigned int c = 0; c < n_components; ++c)
-              {
-                if (fe.get_nonzero_components(shape_func)[c] == false)
-                  continue;
-
-                const unsigned int row =
-                  shape_function_to_row_table[shape_func * n_components + c];
-
-                const double *     shape_value_ptr = &shape_values(row, 0);
-                const unsigned int comp            = c + mc * n_components;
-
-                if (quadrature_points_fastest)
-                  {
-                    VectorType &values_comp = values[comp];
-                    for (unsigned int point = 0; point < n_quadrature_points;
-                         ++point)
-                      values_comp[point] += value * (*shape_value_ptr++);
-                  }
-                else
-                  for (unsigned int point = 0; point < n_quadrature_points;
-                       ++point)
-                    values[point][comp] += value * (*shape_value_ptr++);
-              }
-        }
-  }
-
-
-
-  // use the same implementation for gradients and Hessians, distinguish them
-  // by the rank of the tensors
-  template <int order, int spacedim, typename Number>
-  void
-  do_function_derivatives(
-    const ArrayView<Number> &                        dof_values,
-    const dealii::Table<2, Tensor<order, spacedim>> &shape_derivatives,
-    std::vector<Tensor<order, spacedim, Number>> &   derivatives)
-  {
-    const unsigned int dofs_per_cell       = shape_derivatives.size()[0];
-    const unsigned int n_quadrature_points = derivatives.size();
-
-    // initialize with zero
-    std::fill_n(derivatives.begin(),
-                n_quadrature_points,
-                Tensor<order, spacedim, Number>());
-
-    // add up contributions of trial functions. note that here we deal with
-    // scalar finite elements, so no need to check for non-primitivity of
-    // shape functions. in order to increase the speed of this function, we
-    // directly access the data in the shape_gradients/hessians array, and
-    // increment pointers for accessing the data. this saves some lookup time
-    // and indexing. moreover, the order of the loops is such that we can
-    // access the shape_gradients/hessians data stored contiguously
-    for (unsigned int shape_func = 0; shape_func < dofs_per_cell; ++shape_func)
-      {
-        const Number &value = dof_values[shape_func];
-        // For auto-differentiable numbers, the fact that a DoF value is zero
-        // does not imply that its derivatives are zero as well. So we
-        // can't filter by value for these number types.
-        if (dealii::internal::CheckForZero<Number>::value(value) == true)
-          continue;
-
-        const Tensor<order, spacedim> *shape_derivative_ptr =
-          &shape_derivatives[shape_func][0];
-        for (unsigned int point = 0; point < n_quadrature_points; ++point)
-          derivatives[point] += value * (*shape_derivative_ptr++);
-      }
-  }
-
-
-
-  template <int order, int dim, int spacedim, typename Number>
-  void
-  do_function_derivatives(
-    const ArrayView<Number> &                        dof_values,
-    const dealii::Table<2, Tensor<order, spacedim>> &shape_derivatives,
-    const FiniteElement<dim, spacedim> &             fe,
-    const std::vector<unsigned int> &shape_function_to_row_table,
-    ArrayView<std::vector<Tensor<order, spacedim, Number>>> derivatives,
-    const bool         quadrature_points_fastest = false,
-    const unsigned int component_multiple        = 1)
-  {
-    // initialize with zero
-    for (unsigned int i = 0; i < derivatives.size(); ++i)
-      std::fill_n(derivatives[i].begin(),
-                  derivatives[i].size(),
-                  Tensor<order, spacedim, Number>());
-
-    // see if there the current cell has DoFs at all, and if not
-    // then there is nothing else to do.
-    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
-    if (dofs_per_cell == 0)
-      return;
-
-
-    const unsigned int n_quadrature_points =
-      quadrature_points_fastest ? derivatives[0].size() : derivatives.size();
-    const unsigned int n_components = fe.n_components();
-
-    // Assert that we can write all components into the result vectors
-    const unsigned result_components = n_components * component_multiple;
-    (void)result_components;
-    if (quadrature_points_fastest)
-      {
-        AssertDimension(derivatives.size(), result_components);
-        for (unsigned int i = 0; i < derivatives.size(); ++i)
-          AssertDimension(derivatives[i].size(), n_quadrature_points);
-      }
-    else
-      {
-        AssertDimension(derivatives.size(), n_quadrature_points);
-        for (unsigned int i = 0; i < derivatives.size(); ++i)
-          AssertDimension(derivatives[i].size(), result_components);
-      }
-
-    // add up contributions of trial functions.  now check whether the shape
-    // function is primitive or not. if it is, then set its only non-zero
-    // component, otherwise loop over components
-    for (unsigned int mc = 0; mc < component_multiple; ++mc)
-      for (unsigned int shape_func = 0; shape_func < dofs_per_cell;
-           ++shape_func)
-        {
-          const Number &value = dof_values[shape_func + mc * dofs_per_cell];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (fe.is_primitive(shape_func))
-            {
-              const unsigned int comp =
-                fe.system_to_component_index(shape_func).first +
-                mc * n_components;
-              const unsigned int row =
-                shape_function_to_row_table[shape_func * n_components + comp];
-
-              const Tensor<order, spacedim> *shape_derivative_ptr =
-                &shape_derivatives[row][0];
-
-              if (quadrature_points_fastest)
-                for (unsigned int point = 0; point < n_quadrature_points;
-                     ++point)
-                  derivatives[comp][point] += value * (*shape_derivative_ptr++);
-              else
-                for (unsigned int point = 0; point < n_quadrature_points;
-                     ++point)
-                  derivatives[point][comp] += value * (*shape_derivative_ptr++);
-            }
-          else
-            for (unsigned int c = 0; c < n_components; ++c)
-              {
-                if (fe.get_nonzero_components(shape_func)[c] == false)
-                  continue;
-
-                const unsigned int row =
-                  shape_function_to_row_table[shape_func * n_components + c];
-
-                const Tensor<order, spacedim> *shape_derivative_ptr =
-                  &shape_derivatives[row][0];
-                const unsigned int comp = c + mc * n_components;
-
-                if (quadrature_points_fastest)
-                  for (unsigned int point = 0; point < n_quadrature_points;
-                       ++point)
-                    derivatives[comp][point] +=
-                      value * (*shape_derivative_ptr++);
-                else
-                  for (unsigned int point = 0; point < n_quadrature_points;
-                       ++point)
-                    derivatives[point][comp] +=
-                      value * (*shape_derivative_ptr++);
-              }
-        }
-  }
-
-
-
-  template <int spacedim, typename Number, typename Number2>
-  void
-  do_function_laplacians(
-    const ArrayView<Number2> &                   dof_values,
-    const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians,
-    std::vector<Number> &                        laplacians)
-  {
-    const unsigned int dofs_per_cell       = shape_hessians.size()[0];
-    const unsigned int n_quadrature_points = laplacians.size();
-
-    // initialize with zero
-    std::fill_n(laplacians.begin(),
-                n_quadrature_points,
-                dealii::internal::NumberType<Number>::value(0.0));
-
-    // add up contributions of trial functions. note that here we deal with
-    // scalar finite elements and also note that the Laplacian is
-    // the trace of the Hessian.
-    for (unsigned int shape_func = 0; shape_func < dofs_per_cell; ++shape_func)
-      {
-        const Number2 value = dof_values[shape_func];
-        // For auto-differentiable numbers, the fact that a DoF value is zero
-        // does not imply that its derivatives are zero as well. So we
-        // can't filter by value for these number types.
-        if (!Differentiation::AD::is_ad_number<Number2>::value)
-          if (value == dealii::internal::NumberType<Number2>::value(0.0))
-            continue;
-
-        const Tensor<2, spacedim> *shape_hessian_ptr =
-          &shape_hessians[shape_func][0];
-        for (unsigned int point = 0; point < n_quadrature_points; ++point)
-          laplacians[point] += value * trace(*shape_hessian_ptr++);
-      }
-  }
-
-
-
-  template <int dim, int spacedim, typename VectorType, typename Number>
-  void
-  do_function_laplacians(
-    const ArrayView<Number> &                    dof_values,
-    const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians,
-    const FiniteElement<dim, spacedim> &         fe,
-    const std::vector<unsigned int> &            shape_function_to_row_table,
-    std::vector<VectorType> &                    laplacians,
-    const bool         quadrature_points_fastest = false,
-    const unsigned int component_multiple        = 1)
-  {
-    // initialize with zero
-    for (unsigned int i = 0; i < laplacians.size(); ++i)
-      std::fill_n(laplacians[i].begin(),
-                  laplacians[i].size(),
-                  typename VectorType::value_type());
-
-    // see if there the current cell has DoFs at all, and if not
-    // then there is nothing else to do.
-    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
-    if (dofs_per_cell == 0)
-      return;
-
-
-    const unsigned int n_quadrature_points = laplacians.size();
-    const unsigned int n_components        = fe.n_components();
-
-    // Assert that we can write all components into the result vectors
-    const unsigned result_components = n_components * component_multiple;
-    (void)result_components;
-    if (quadrature_points_fastest)
-      {
-        AssertDimension(laplacians.size(), result_components);
-        for (unsigned int i = 0; i < laplacians.size(); ++i)
-          AssertDimension(laplacians[i].size(), n_quadrature_points);
-      }
-    else
-      {
-        AssertDimension(laplacians.size(), n_quadrature_points);
-        for (unsigned int i = 0; i < laplacians.size(); ++i)
-          AssertDimension(laplacians[i].size(), result_components);
-      }
-
-    // add up contributions of trial functions.  now check whether the shape
-    // function is primitive or not. if it is, then set its only non-zero
-    // component, otherwise loop over components
-    for (unsigned int mc = 0; mc < component_multiple; ++mc)
-      for (unsigned int shape_func = 0; shape_func < dofs_per_cell;
-           ++shape_func)
-        {
-          const Number &value = dof_values[shape_func + mc * dofs_per_cell];
-          // For auto-differentiable numbers, the fact that a DoF value is zero
-          // does not imply that its derivatives are zero as well. So we
-          // can't filter by value for these number types.
-          if (dealii::internal::CheckForZero<Number>::value(value) == true)
-            continue;
-
-          if (fe.is_primitive(shape_func))
-            {
-              const unsigned int comp =
-                fe.system_to_component_index(shape_func).first +
-                mc * n_components;
-              const unsigned int row =
-                shape_function_to_row_table[shape_func * n_components + comp];
-
-              const Tensor<2, spacedim> *shape_hessian_ptr =
-                &shape_hessians[row][0];
-              if (quadrature_points_fastest)
-                {
-                  VectorType &laplacians_comp = laplacians[comp];
-                  for (unsigned int point = 0; point < n_quadrature_points;
-                       ++point)
-                    laplacians_comp[point] +=
-                      value * trace(*shape_hessian_ptr++);
-                }
-              else
-                for (unsigned int point = 0; point < n_quadrature_points;
-                     ++point)
-                  laplacians[point][comp] +=
-                    value * trace(*shape_hessian_ptr++);
-            }
-          else
-            for (unsigned int c = 0; c < n_components; ++c)
-              {
-                if (fe.get_nonzero_components(shape_func)[c] == false)
-                  continue;
-
-                const unsigned int row =
-                  shape_function_to_row_table[shape_func * n_components + c];
-
-                const Tensor<2, spacedim> *shape_hessian_ptr =
-                  &shape_hessians[row][0];
-                const unsigned int comp = c + mc * n_components;
-
-                if (quadrature_points_fastest)
-                  {
-                    VectorType &laplacians_comp = laplacians[comp];
-                    for (unsigned int point = 0; point < n_quadrature_points;
-                         ++point)
-                      laplacians_comp[point] +=
-                        value * trace(*shape_hessian_ptr++);
-                  }
-                else
-                  for (unsigned int point = 0; point < n_quadrature_points;
-                       ++point)
-                    laplacians[point][comp] +=
-                      value * trace(*shape_hessian_ptr++);
-              }
-        }
-  }
+  } // namespace FEValuesImplementation
 } // namespace internal
 
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_values(
-  const ReadVector<Number> &fe_function,
-  std::vector<Number> &     values) const
-{
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-  AssertDimension(fe->n_components(), 1);
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_values(make_array_view(dof_values.begin(),
-                                               dof_values.end()),
-                               this->finite_element_output.shape_values,
-                               values);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_values(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Number> &                           values) const
-{
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-  AssertDimension(fe->n_components(), 1);
-  AssertDimension(indices.size(), dofs_per_cell);
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_values(view,
-                               this->finite_element_output.shape_values,
-                               values);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_values(
-  const ReadVector<Number> &   fe_function,
-  std::vector<Vector<Number>> &values) const
-{
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_values(
-    make_array_view(dof_values.begin(), dof_values.end()),
-    this->finite_element_output.shape_values,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(values.begin(), values.end()));
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_values(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Vector<Number>> &                   values) const
-{
-  // Size of indices must be a multiple of dofs_per_cell such that an integer
-  // number of function values is generated in each point.
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_values(
-    view,
-    this->finite_element_output.shape_values,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(values.begin(), values.end()),
-    false,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_values(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  ArrayView<std::vector<Number>>                  values,
-  const bool quadrature_points_fastest) const
-{
-  Assert(this->update_flags & update_values,
-         ExcAccessToUninitializedField("update_values"));
-
-  // Size of indices must be a multiple of dofs_per_cell such that an integer
-  // number of function values is generated in each point.
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_values(
-    view,
-    this->finite_element_output.shape_values,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(values.begin(), values.end()),
-    quadrature_points_fastest,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_gradients(
-  const ReadVector<Number> &                fe_function,
-  std::vector<Tensor<1, spacedim, Number>> &gradients) const
-{
-  Assert(this->update_flags & update_gradients,
-         ExcAccessToUninitializedField("update_gradients"));
-  AssertDimension(fe->n_components(), 1);
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_derivatives(make_array_view(dof_values.begin(),
-                                                    dof_values.end()),
-                                    this->finite_element_output.shape_gradients,
-                                    gradients);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_gradients(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Tensor<1, spacedim, Number>> &      gradients) const
-{
-  Assert(this->update_flags & update_gradients,
-         ExcAccessToUninitializedField("update_gradients"));
-  AssertDimension(fe->n_components(), 1);
-  AssertDimension(indices.size(), dofs_per_cell);
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_derivatives(view,
-                                    this->finite_element_output.shape_gradients,
-                                    gradients);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_gradients(
-  const ReadVector<Number> &                             fe_function,
-  std::vector<std::vector<Tensor<1, spacedim, Number>>> &gradients) const
-{
-  Assert(this->update_flags & update_gradients,
-         ExcAccessToUninitializedField("update_gradients"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_derivatives(
-    make_array_view(dof_values.begin(), dof_values.end()),
-    this->finite_element_output.shape_gradients,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(gradients.begin(), gradients.end()));
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_gradients(
-  const ReadVector<Number> &                          fe_function,
-  const ArrayView<const types::global_dof_index> &    indices,
-  ArrayView<std::vector<Tensor<1, spacedim, Number>>> gradients,
-  const bool quadrature_points_fastest) const
-{
-  // Size of indices must be a multiple of dofs_per_cell such that an integer
-  // number of function values is generated in each point.
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-  Assert(this->update_flags & update_gradients,
-         ExcAccessToUninitializedField("update_gradients"));
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_derivatives(
-    view,
-    this->finite_element_output.shape_gradients,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(gradients.begin(), gradients.end()),
-    quadrature_points_fastest,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_hessians(
-  const ReadVector<Number> &                fe_function,
-  std::vector<Tensor<2, spacedim, Number>> &hessians) const
-{
-  AssertDimension(fe->n_components(), 1);
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_derivatives(make_array_view(dof_values.begin(),
-                                                    dof_values.end()),
-                                    this->finite_element_output.shape_hessians,
-                                    hessians);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_hessians(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Tensor<2, spacedim, Number>> &      hessians) const
-{
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-  AssertDimension(indices.size(), dofs_per_cell);
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_derivatives(view,
-                                    this->finite_element_output.shape_hessians,
-                                    hessians);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_hessians(
-  const ReadVector<Number> &                             fe_function,
-  std::vector<std::vector<Tensor<2, spacedim, Number>>> &hessians,
-  const bool quadrature_points_fastest) const
-{
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_derivatives(
-    make_array_view(dof_values.begin(), dof_values.end()),
-    this->finite_element_output.shape_hessians,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(hessians.begin(), hessians.end()),
-    quadrature_points_fastest);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_hessians(
-  const ReadVector<Number> &                          fe_function,
-  const ArrayView<const types::global_dof_index> &    indices,
-  ArrayView<std::vector<Tensor<2, spacedim, Number>>> hessians,
-  const bool quadrature_points_fastest) const
-{
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-
-  boost::container::small_vector<Number, 200> dof_values(indices.size());
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_derivatives(
-    view,
-    this->finite_element_output.shape_hessians,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(hessians.begin(), hessians.end()),
-    quadrature_points_fastest,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_laplacians(
-  const ReadVector<Number> &fe_function,
-  std::vector<Number> &     laplacians) const
-{
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  AssertDimension(fe->n_components(), 1);
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_laplacians(make_array_view(dof_values.begin(),
-                                                   dof_values.end()),
-                                   this->finite_element_output.shape_hessians,
-                                   laplacians);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_laplacians(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Number> &                           laplacians) const
-{
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  AssertDimension(fe->n_components(), 1);
-  AssertDimension(indices.size(), dofs_per_cell);
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_laplacians(view,
-                                   this->finite_element_output.shape_hessians,
-                                   laplacians);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_laplacians(
-  const ReadVector<Number> &   fe_function,
-  std::vector<Vector<Number>> &laplacians) const
-{
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_laplacians(
-    make_array_view(dof_values.begin(), dof_values.end()),
-    this->finite_element_output.shape_hessians,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    laplacians);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_laplacians(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Vector<Number>> &                   laplacians) const
-{
-  // Size of indices must be a multiple of dofs_per_cell such that an integer
-  // number of function values is generated in each point.
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-
-  boost::container::small_vector<Number, 200> dof_values(indices.size());
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_laplacians(
-    view,
-    this->finite_element_output.shape_hessians,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    laplacians,
-    false,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_laplacians(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<std::vector<Number>> &              laplacians,
-  const bool quadrature_points_fastest) const
-{
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-  Assert(this->update_flags & update_hessians,
-         ExcAccessToUninitializedField("update_hessians"));
-
-  boost::container::small_vector<Number, 200> dof_values(indices.size());
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_laplacians(
-    view,
-    this->finite_element_output.shape_hessians,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    laplacians,
-    quadrature_points_fastest,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_third_derivatives(
-  const ReadVector<Number> &                fe_function,
-  std::vector<Tensor<3, spacedim, Number>> &third_derivatives) const
-{
-  AssertDimension(fe->n_components(), 1);
-  Assert(this->update_flags & update_3rd_derivatives,
-         ExcAccessToUninitializedField("update_3rd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_derivatives(
-    make_array_view(dof_values.begin(), dof_values.end()),
-    this->finite_element_output.shape_3rd_derivatives,
-    third_derivatives);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_third_derivatives(
-  const ReadVector<Number> &                      fe_function,
-  const ArrayView<const types::global_dof_index> &indices,
-  std::vector<Tensor<3, spacedim, Number>> &      third_derivatives) const
-{
-  Assert(this->update_flags & update_3rd_derivatives,
-         ExcAccessToUninitializedField("update_3rd_derivatives"));
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-  AssertDimension(indices.size(), dofs_per_cell);
-
-  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_derivatives(
-    view, this->finite_element_output.shape_3rd_derivatives, third_derivatives);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_third_derivatives(
-  const ReadVector<Number> &                             fe_function,
-  std::vector<std::vector<Tensor<3, spacedim, Number>>> &third_derivatives,
-  const bool quadrature_points_fastest) const
-{
-  Assert(this->update_flags & update_3rd_derivatives,
-         ExcAccessToUninitializedField("update_3rd_derivatives"));
-  Assert(present_cell.is_initialized(), ExcNotReinited());
-  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
-
-  // get function values of dofs on this cell
-  Vector<Number> dof_values(dofs_per_cell);
-  present_cell.get_interpolated_dof_values(fe_function, dof_values);
-  internal::do_function_derivatives(
-    make_array_view(dof_values.begin(), dof_values.end()),
-    this->finite_element_output.shape_3rd_derivatives,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(third_derivatives.begin(), third_derivatives.end()),
-    quadrature_points_fastest);
-}
-
-
-
-template <int dim, int spacedim>
-template <typename Number>
-void
-FEValuesBase<dim, spacedim>::get_function_third_derivatives(
-  const ReadVector<Number> &                          fe_function,
-  const ArrayView<const types::global_dof_index> &    indices,
-  ArrayView<std::vector<Tensor<3, spacedim, Number>>> third_derivatives,
-  const bool quadrature_points_fastest) const
-{
-  Assert(this->update_flags & update_3rd_derivatives,
-         ExcAccessToUninitializedField("update_3rd_derivatives"));
-  Assert(indices.size() % dofs_per_cell == 0,
-         ExcNotMultiple(indices.size(), dofs_per_cell));
-
-  boost::container::small_vector<Number, 200> dof_values(indices.size());
-  auto view = make_array_view(dof_values.begin(), dof_values.end());
-  fe_function.extract_subvector_to(indices, view);
-  internal::do_function_derivatives(
-    view,
-    this->finite_element_output.shape_3rd_derivatives,
-    *fe,
-    this->finite_element_output.shape_function_to_row_table,
-    make_array_view(third_derivatives.begin(), third_derivatives.end()),
-    quadrature_points_fastest,
-    indices.size() / dofs_per_cell);
-}
-
-
-
-template <int dim, int spacedim>
-typename Triangulation<dim, spacedim>::cell_iterator
-FEValuesBase<dim, spacedim>::get_cell() const
-{
-  return present_cell;
-}
-
-
-
-template <int dim, int spacedim>
-const std::vector<Tensor<1, spacedim>> &
-FEValuesBase<dim, spacedim>::get_normal_vectors() const
-{
-  Assert(this->update_flags & update_normal_vectors,
-         (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
-           "update_normal_vectors")));
-
-  return this->mapping_output.normal_vectors;
-}
-
-
-
-template <int dim, int spacedim>
-std::size_t
-FEValuesBase<dim, spacedim>::memory_consumption() const
-{
-  return (sizeof(this->update_flags) +
-          MemoryConsumption::memory_consumption(n_quadrature_points) +
-          MemoryConsumption::memory_consumption(max_n_quadrature_points) +
-          sizeof(cell_similarity) +
-          MemoryConsumption::memory_consumption(dofs_per_cell) +
-          MemoryConsumption::memory_consumption(mapping) +
-          MemoryConsumption::memory_consumption(mapping_data) +
-          MemoryConsumption::memory_consumption(*mapping_data) +
-          MemoryConsumption::memory_consumption(mapping_output) +
-          MemoryConsumption::memory_consumption(fe) +
-          MemoryConsumption::memory_consumption(fe_data) +
-          MemoryConsumption::memory_consumption(*fe_data) +
-          MemoryConsumption::memory_consumption(finite_element_output));
-}
-
-
-
-template <int dim, int spacedim>
-UpdateFlags
-FEValuesBase<dim, spacedim>::compute_update_flags(
-  const UpdateFlags update_flags) const
-{
-  // first find out which objects need to be recomputed on each
-  // cell we visit. this we have to ask the finite element and mapping.
-  // elements are first since they might require update in mapping
-  //
-  // there is no need to iterate since mappings will never require
-  // the finite element to compute something for them
-  UpdateFlags flags = update_flags | fe->requires_update_flags(update_flags);
-  flags |= mapping->requires_update_flags(flags);
-
-  return flags;
-}
-
-
-
-template <int dim, int spacedim>
-void
-FEValuesBase<dim, spacedim>::invalidate_present_cell()
-{
-  // if there is no present cell, then we shouldn't be
-  // connected via a signal to a triangulation
-  Assert(present_cell.is_initialized(), ExcInternalError());
-
-  // so delete the present cell and
-  // disconnect from the signal we have with
-  // it
-  tria_listener_refinement.disconnect();
-  tria_listener_mesh_transform.disconnect();
-  present_cell = {};
-}
-
-
-
-template <int dim, int spacedim>
-void
-FEValuesBase<dim, spacedim>::maybe_invalidate_previous_present_cell(
-  const typename Triangulation<dim, spacedim>::cell_iterator &cell)
-{
-  if (present_cell.is_initialized())
-    {
-      if (&cell->get_triangulation() !=
-          &present_cell
-             .
-             operator typename Triangulation<dim, spacedim>::cell_iterator()
-             ->get_triangulation())
-        {
-          // the triangulations for the previous cell and the current cell
-          // do not match. disconnect from the previous triangulation and
-          // connect to the current one; also invalidate the previous
-          // cell because we shouldn't be comparing cells from different
-          // triangulations
-          invalidate_present_cell();
-          tria_listener_refinement =
-            cell->get_triangulation().signals.any_change.connect(
-              [this]() { this->invalidate_present_cell(); });
-          tria_listener_mesh_transform =
-            cell->get_triangulation().signals.mesh_movement.connect(
-              [this]() { this->invalidate_present_cell(); });
-        }
-    }
-  else
-    {
-      // if this FEValues has never been set to any cell at all, then
-      // at least subscribe to the triangulation to get notified of
-      // changes
-      tria_listener_refinement =
-        cell->get_triangulation().signals.post_refinement.connect(
-          [this]() { this->invalidate_present_cell(); });
-      tria_listener_mesh_transform =
-        cell->get_triangulation().signals.mesh_movement.connect(
-          [this]() { this->invalidate_present_cell(); });
-    }
-}
-
-
-
-template <int dim, int spacedim>
-inline void
-FEValuesBase<dim, spacedim>::check_cell_similarity(
-  const typename Triangulation<dim, spacedim>::cell_iterator &cell)
-{
-  // Unfortunately, the detection of simple geometries with CellSimilarity is
-  // sensitive to the first cell detected. When doing this with multiple
-  // threads, each thread will get its own scratch data object with an
-  // FEValues object in the implementation framework from late 2013, which is
-  // initialized to the first cell the thread sees. As this number might
-  // different between different runs (after all, the tasks are scheduled
-  // dynamically onto threads), this slight deviation leads to difference in
-  // roundoff errors that propagate through the program. Therefore, we need to
-  // disable CellSimilarity in case there is more than one thread in the
-  // problem. This will likely not affect many MPI test cases as there
-  // multithreading is disabled on default, but in many other situations
-  // because we rarely explicitly set the number of threads.
-  //
-  // TODO: Is it reasonable to introduce a flag "unsafe" in the constructor of
-  // FEValues to re-enable this feature?
-  if (MultithreadInfo::n_threads() > 1)
-    {
-      cell_similarity = CellSimilarity::none;
-      return;
-    }
-
-  // case that there has not been any cell before
-  if (this->present_cell.is_initialized() == false)
-    cell_similarity = CellSimilarity::none;
-  else
-    // in MappingQ, data can have been modified during the last call. Then, we
-    // can't use that data on the new cell.
-    if (cell_similarity == CellSimilarity::invalid_next_cell)
-    cell_similarity = CellSimilarity::none;
-  else
-    cell_similarity =
-      (cell->is_translation_of(
-         static_cast<const typename Triangulation<dim, spacedim>::cell_iterator
-                       &>(this->present_cell)) ?
-         CellSimilarity::translation :
-         CellSimilarity::none);
-
-  if ((dim < spacedim) && (cell_similarity == CellSimilarity::translation))
-    {
-      if (static_cast<const typename Triangulation<dim, spacedim>::cell_iterator
-                        &>(this->present_cell)
-            ->direction_flag() != cell->direction_flag())
-        cell_similarity = CellSimilarity::inverted_translation;
-    }
-  // TODO: here, one could implement other checks for similarity, e.g. for
-  // children of a parallelogram.
-}
-
-
-
-template <int dim, int spacedim>
-CellSimilarity::Similarity
-FEValuesBase<dim, spacedim>::get_cell_similarity() const
-{
-  return cell_similarity;
-}
-
-
-
-template <int dim, int spacedim>
-const unsigned int FEValuesBase<dim, spacedim>::dimension;
-
-
-
-template <int dim, int spacedim>
-const unsigned int FEValuesBase<dim, spacedim>::space_dimension;
-
 /*------------------------------- FEValues -------------------------------*/
 
 template <int dim, int spacedim>
@@ -4802,7 +993,7 @@ FESubfaceValues<dim, spacedim>::do_reinit(const unsigned int face_no,
 }
 
 
-/*------------------------------- Explicit Instantiations -------------*/
+/*------------------------- Explicit Instantiations --------------------------*/
 
 #include "fe_values.inst"
 
index d75f616bd7d089ad56fcd13394b36f838caac6bd..26ee78053837782dcdb39df1b934f5582f865218 100644 (file)
 for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
   {
 #  if deal_II_dimension <= deal_II_space_dimension
-    template class FEValuesBase<deal_II_dimension, deal_II_space_dimension>;
     template class FEValues<deal_II_dimension, deal_II_space_dimension>;
 
     template class FEFaceValuesBase<deal_II_dimension, deal_II_space_dimension>;
     template class FEFaceValues<deal_II_dimension, deal_II_space_dimension>;
     template class FESubfaceValues<deal_II_dimension, deal_II_space_dimension>;
 
-
-    namespace FEValuesViews
-    \{
-      template class Scalar<deal_II_dimension, deal_II_space_dimension>;
-      template class Vector<deal_II_dimension, deal_II_space_dimension>;
-      template class SymmetricTensor<2,
-                                     deal_II_dimension,
-                                     deal_II_space_dimension>;
-      template class Tensor<2, deal_II_dimension, deal_II_space_dimension>;
-    \}
-
     namespace internal
     \{
       namespace FEValuesImplementation
@@ -86,391 +74,6 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS;
       const TriaIterator<TriaAccessor<deal_II_dimension - 1,
                                       deal_II_dimension,
                                       deal_II_space_dimension>> &);
-#  endif
-  }
-for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
-     deal_II_space_dimension : SPACE_DIMENSIONS)
-  {
-#  if deal_II_dimension <= deal_II_space_dimension
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(const dealii::ReadVector<S> &,
-                             std::vector<ProductType<S, value_type>::type> &)
-        const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void FEValuesViews::SymmetricTensor<2,
-                                                 deal_II_dimension,
-                                                 deal_II_space_dimension>::
-      get_function_values<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<ProductType<
-          S,
-          dealii::SymmetricTensor<2, deal_II_space_dimension>>::type> &) const;
-
-    template void
-    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<2, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(const ReadVector<S> &, std::vector<S> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(const ReadVector<S> &,
-                             const ArrayView<const types::global_dof_index> &,
-                             std::vector<S> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(const ReadVector<S> &, std::vector<Vector<S>> &)
-        const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(const ReadVector<S> &,
-                             const ArrayView<const types::global_dof_index> &,
-                             std::vector<Vector<S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values<S>(const ReadVector<S> &,
-                             const ArrayView<const types::global_dof_index> &,
-                             ArrayView<std::vector<S>>,
-                             bool) const;
-
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<2, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void
-    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<3, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        std::vector<dealii::Tensor<1, deal_II_space_dimension, S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        std::vector<dealii::Tensor<1, deal_II_space_dimension, S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        std::vector<std::vector<dealii::Tensor<1, deal_II_space_dimension, S>>>
-          &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        ArrayView<std::vector<dealii::Tensor<1, deal_II_space_dimension, S>>>,
-        bool) const;
-#  endif
-  }
-
-
-
-for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
-     deal_II_space_dimension : SPACE_DIMENSIONS)
-  {
-#  if deal_II_dimension <= deal_II_space_dimension
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<2, deal_II_space_dimension>>::type> &)
-        const;
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(const dealii::ReadVector<S> &,
-                                 std::vector<ProductType<S, double>::type> &)
-        const;
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<3, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_symmetric_gradients<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<ProductType<
-          S,
-          dealii::SymmetricTensor<2, deal_II_space_dimension>>::type> &) const;
-    template void FEValuesViews::
-      Vector<deal_II_dimension, deal_II_space_dimension>::get_function_curls<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<ProductType<S, curl_type>::type> &) const;
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_divergences<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<ProductType<S, divergence_type>::type> &) const;
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<3, deal_II_space_dimension>>::type> &)
-        const;
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
-        const;
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<4, deal_II_space_dimension>>::type> &)
-        const;
-
-    template void FEValuesViews::
-      SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>::
-        get_function_divergences<S>(
-          const dealii::ReadVector<S> &,
-          std::vector<
-            ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
-          const;
-
-    template void
-    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
-      get_function_divergences<S>(
-        const dealii::ReadVector<S> &,
-        std::vector<
-          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
-        const;
-#  endif
-  }
-
-
-for (VEC : GENERAL_CONTAINER_TYPES; Number : ALL_SCALAR_TYPES;
-     deal_II_dimension : DIMENSIONS;
-     deal_II_space_dimension : SPACE_DIMENSIONS)
-  {
-#  if deal_II_dimension <= deal_II_space_dimension
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_gradient_type<Number>> &)
-        const;
-
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_hessian_type<Number>> &)
-        const;
-
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &,
-        std::vector<solution_third_derivative_type<Number>> &) const;
-
-
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_values_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_gradient_type<Number>> &)
-        const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_symmetric_gradients_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &,
-        std::vector<solution_symmetric_gradient_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_divergences_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_divergence_type<Number>> &)
-        const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_curls_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_curl_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_hessian_type<Number>> &)
-        const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &,
-        std::vector<solution_third_derivative_type<Number>> &) const;
-
-
-
-    template void FEValuesViews::SymmetricTensor<2,
-                                                 deal_II_dimension,
-                                                 deal_II_space_dimension>::
-      get_function_values_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
-
-    template void FEValuesViews::
-      SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>::
-        get_function_divergences_from_local_dof_values<VEC<Number>>(
-          const VEC<Number> &, std::vector<solution_divergence_type<Number>> &)
-          const;
-
-
-
-    template void
-    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
-      get_function_values_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
-
-    template void
-    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
-      get_function_divergences_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_divergence_type<Number>> &)
-        const;
-
-    template void
-    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
-      get_function_gradients_from_local_dof_values<VEC<Number>>(
-        const VEC<Number> &, std::vector<solution_gradient_type<Number>> &)
-        const;
-#  endif
-  }
-
-
-for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
-     deal_II_space_dimension : SPACE_DIMENSIONS)
-  {
-#  if deal_II_dimension <= deal_II_space_dimension
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians<S>(
-        const ReadVector<S> &,
-        std::vector<dealii::Tensor<2, deal_II_space_dimension, S>> &) const;
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        std::vector<dealii::Tensor<2, deal_II_space_dimension, S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians<S>(
-        const ReadVector<S> &,
-        std::vector<std::vector<dealii::Tensor<2, deal_II_space_dimension, S>>>
-          &,
-        bool) const;
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_hessians<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        ArrayView<std::vector<dealii::Tensor<2, deal_II_space_dimension, S>>>,
-        bool) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(const ReadVector<S> &, std::vector<S> &) const;
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        std::vector<S> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(const ReadVector<S> &,
-                                 std::vector<Vector<S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        std::vector<Vector<S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_laplacians<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        std::vector<std::vector<S>> &,
-        bool) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives<S>(
-        const ReadVector<S> &,
-        std::vector<dealii::Tensor<3, deal_II_space_dimension, S>> &) const;
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        std::vector<dealii::Tensor<3, deal_II_space_dimension, S>> &) const;
-
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives<S>(
-        const ReadVector<S> &,
-        std::vector<std::vector<dealii::Tensor<3, deal_II_space_dimension, S>>>
-          &,
-        bool) const;
-    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
-      get_function_third_derivatives<S>(
-        const ReadVector<S> &,
-        const ArrayView<const types::global_dof_index> &,
-        ArrayView<std::vector<dealii::Tensor<3, deal_II_space_dimension, S>>>,
-        bool) const;
-
 #  endif
   }
 #endif
diff --git a/source/fe/fe_values_base.cc b/source/fe/fe_values_base.cc
new file mode 100644 (file)
index 0000000..4c9c4f4
--- /dev/null
@@ -0,0 +1,1481 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2023 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.
+//
+// ---------------------------------------------------------------------
+
+#include <deal.II/base/array_view.h>
+#include <deal.II/base/memory_consumption.h>
+#include <deal.II/base/multithread_info.h>
+#include <deal.II/base/numbers.h>
+#include <deal.II/base/quadrature.h>
+#include <deal.II/base/signaling_nan.h>
+#include <deal.II/base/thread_management.h>
+
+#include <deal.II/differentiation/ad.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+
+#include <deal.II/fe/fe.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping.h>
+
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/lac/vector.h>
+
+#include <boost/container/small_vector.hpp>
+
+#include <iomanip>
+#include <memory>
+#include <type_traits>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+namespace internal
+{
+  template <int dim, int spacedim>
+  inline std::vector<unsigned int>
+  make_shape_function_to_row_table(const FiniteElement<dim, spacedim> &fe)
+  {
+    std::vector<unsigned int> shape_function_to_row_table(
+      fe.n_dofs_per_cell() * fe.n_components(), numbers::invalid_unsigned_int);
+    unsigned int row = 0;
+    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+      {
+        // loop over all components that are nonzero for this particular
+        // shape function. if a component is zero then we leave the
+        // value in the table unchanged (at the invalid value)
+        // otherwise it is mapped to the next free entry
+        unsigned int nth_nonzero_component = 0;
+        for (unsigned int c = 0; c < fe.n_components(); ++c)
+          if (fe.get_nonzero_components(i)[c] == true)
+            {
+              shape_function_to_row_table[i * fe.n_components() + c] =
+                row + nth_nonzero_component;
+              ++nth_nonzero_component;
+            }
+        row += fe.n_nonzero_components(i);
+      }
+
+    return shape_function_to_row_table;
+  }
+
+  namespace
+  {
+    // Check to see if a DoF value is zero, implying that subsequent operations
+    // with the value have no effect.
+    template <typename Number, typename T = void>
+    struct CheckForZero
+    {
+      static bool
+      value(const Number &value)
+      {
+        return value == dealii::internal::NumberType<Number>::value(0.0);
+      }
+    };
+
+    // For auto-differentiable numbers, the fact that a DoF value is zero
+    // does not imply that its derivatives are zero as well. So we
+    // can't filter by value for these number types.
+    // Note that we also want to avoid actually checking the value itself,
+    // since some AD numbers are not contextually convertible to booleans.
+    template <typename Number>
+    struct CheckForZero<
+      Number,
+      std::enable_if_t<Differentiation::AD::is_ad_number<Number>::value>>
+    {
+      static bool
+      value(const Number & /*value*/)
+      {
+        return false;
+      }
+    };
+  } // namespace
+} // namespace internal
+
+/* ------------ FEValuesBase<dim,spacedim>::CellIteratorContainer ----------- */
+
+template <int dim, int spacedim>
+FEValuesBase<dim, spacedim>::CellIteratorContainer::CellIteratorContainer()
+  : initialized(false)
+  , cell(typename Triangulation<dim, spacedim>::cell_iterator(nullptr, -1, -1))
+  , dof_handler(nullptr)
+  , level_dof_access(false)
+{}
+
+
+
+template <int dim, int spacedim>
+FEValuesBase<dim, spacedim>::CellIteratorContainer::CellIteratorContainer(
+  const typename Triangulation<dim, spacedim>::cell_iterator &cell)
+  : initialized(true)
+  , cell(cell)
+  , dof_handler(nullptr)
+  , level_dof_access(false)
+{}
+
+
+
+template <int dim, int spacedim>
+bool
+FEValuesBase<dim, spacedim>::CellIteratorContainer::is_initialized() const
+{
+  return initialized;
+}
+
+
+
+template <int dim, int spacedim>
+FEValuesBase<dim, spacedim>::CellIteratorContainer::
+operator typename Triangulation<dim, spacedim>::cell_iterator() const
+{
+  Assert(is_initialized(), ExcNotReinited());
+
+  return cell;
+}
+
+
+
+template <int dim, int spacedim>
+types::global_dof_index
+FEValuesBase<dim, spacedim>::CellIteratorContainer::n_dofs_for_dof_handler()
+  const
+{
+  Assert(is_initialized(), ExcNotReinited());
+  Assert(dof_handler != nullptr, ExcNeedsDoFHandler());
+
+  return dof_handler->n_dofs();
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::CellIteratorContainer::get_interpolated_dof_values(
+  const ReadVector<Number> &in,
+  Vector<Number> &          out) const
+{
+  Assert(is_initialized(), ExcNotReinited());
+  Assert(dof_handler != nullptr, ExcNeedsDoFHandler());
+
+  if (level_dof_access)
+    DoFCellAccessor<dim, spacedim, true>(&cell->get_triangulation(),
+                                         cell->level(),
+                                         cell->index(),
+                                         dof_handler)
+      .get_interpolated_dof_values(in, out);
+  else
+    DoFCellAccessor<dim, spacedim, false>(&cell->get_triangulation(),
+                                          cell->level(),
+                                          cell->index(),
+                                          dof_handler)
+      .get_interpolated_dof_values(in, out);
+}
+
+
+
+template <int dim, int spacedim>
+void
+FEValuesBase<dim, spacedim>::CellIteratorContainer::get_interpolated_dof_values(
+  const IndexSet &              in,
+  Vector<IndexSet::value_type> &out) const
+{
+  Assert(is_initialized(), ExcNotReinited());
+  Assert(dof_handler != nullptr, ExcNeedsDoFHandler());
+  Assert(level_dof_access == false, ExcNotImplemented());
+
+  const DoFCellAccessor<dim, spacedim, false> cell_dofs(
+    &cell->get_triangulation(), cell->level(), cell->index(), dof_handler);
+
+  std::vector<types::global_dof_index> dof_indices(
+    cell_dofs.get_fe().n_dofs_per_cell());
+  cell_dofs.get_dof_indices(dof_indices);
+
+  for (unsigned int i = 0; i < cell_dofs.get_fe().n_dofs_per_cell(); ++i)
+    out[i] = (in.is_element(dof_indices[i]) ? 1 : 0);
+}
+
+
+
+/*------------------------------- FEValuesBase ---------------------------*/
+
+
+template <int dim, int spacedim>
+FEValuesBase<dim, spacedim>::FEValuesBase(
+  const unsigned int                  n_q_points,
+  const unsigned int                  dofs_per_cell,
+  const UpdateFlags                   flags,
+  const Mapping<dim, spacedim> &      mapping,
+  const FiniteElement<dim, spacedim> &fe)
+  : n_quadrature_points(n_q_points)
+  , max_n_quadrature_points(n_q_points)
+  , dofs_per_cell(dofs_per_cell)
+  , mapping(&mapping, typeid(*this).name())
+  , fe(&fe, typeid(*this).name())
+  , cell_similarity(CellSimilarity::Similarity::none)
+  , fe_values_views_cache(*this)
+{
+  Assert(n_q_points > 0,
+         ExcMessage("There is nothing useful you can do with an FEValues "
+                    "object when using a quadrature formula with zero "
+                    "quadrature points!"));
+  this->update_flags = flags;
+}
+
+
+
+template <int dim, int spacedim>
+FEValuesBase<dim, spacedim>::~FEValuesBase()
+{
+  tria_listener_refinement.disconnect();
+  tria_listener_mesh_transform.disconnect();
+}
+
+
+
+namespace internal
+{
+  // put shape function part of get_function_xxx methods into separate
+  // internal functions. this allows us to reuse the same code for several
+  // functions (e.g. both the versions with and without indices) as well as
+  // the same code for gradients and Hessians. Moreover, this speeds up
+  // compilation and reduces the size of the final file since all the
+  // different global vectors get channeled through the same code.
+
+  template <typename Number, typename Number2>
+  void
+  do_function_values(const ArrayView<Number2> &      dof_values,
+                     const dealii::Table<2, double> &shape_values,
+                     std::vector<Number> &           values)
+  {
+    // scalar finite elements, so shape_values.size() == dofs_per_cell
+    const unsigned int dofs_per_cell       = shape_values.n_rows();
+    const unsigned int n_quadrature_points = values.size();
+
+    // initialize with zero
+    std::fill_n(values.begin(),
+                n_quadrature_points,
+                dealii::internal::NumberType<Number>::value(0.0));
+
+    // add up contributions of trial functions. note that here we deal with
+    // scalar finite elements, so no need to check for non-primitivity of
+    // shape functions. in order to increase the speed of this function, we
+    // directly access the data in the shape_values array, and increment
+    // pointers for accessing the data. this saves some lookup time and
+    // indexing. moreover, the order of the loops is such that we can access
+    // the shape_values data stored contiguously
+    for (unsigned int shape_func = 0; shape_func < dofs_per_cell; ++shape_func)
+      {
+        const Number2 value = dof_values[shape_func];
+        // For auto-differentiable numbers, the fact that a DoF value is zero
+        // does not imply that its derivatives are zero as well. So we
+        // can't filter by value for these number types.
+        if (!Differentiation::AD::is_ad_number<Number2>::value)
+          if (value == dealii::internal::NumberType<Number2>::value(0.0))
+            continue;
+
+        const double *shape_value_ptr = &shape_values(shape_func, 0);
+        for (unsigned int point = 0; point < n_quadrature_points; ++point)
+          values[point] += value * (*shape_value_ptr++);
+      }
+  }
+
+
+
+  template <int dim, int spacedim, typename VectorType>
+  void
+  do_function_values(
+    const ArrayView<typename VectorType::value_type> &dof_values,
+    const dealii::Table<2, double> &                  shape_values,
+    const FiniteElement<dim, spacedim> &              fe,
+    const std::vector<unsigned int> &shape_function_to_row_table,
+    ArrayView<VectorType>            values,
+    const bool                       quadrature_points_fastest = false,
+    const unsigned int               component_multiple        = 1)
+  {
+    using Number = typename VectorType::value_type;
+    // initialize with zero
+    for (unsigned int i = 0; i < values.size(); ++i)
+      std::fill_n(values[i].begin(),
+                  values[i].size(),
+                  typename VectorType::value_type());
+
+    // see if there the current cell has DoFs at all, and if not
+    // then there is nothing else to do.
+    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
+    if (dofs_per_cell == 0)
+      return;
+
+    const unsigned int n_quadrature_points =
+      quadrature_points_fastest ? values[0].size() : values.size();
+    const unsigned int n_components = fe.n_components();
+
+    // Assert that we can write all components into the result vectors
+    const unsigned result_components = n_components * component_multiple;
+    (void)result_components;
+    if (quadrature_points_fastest)
+      {
+        AssertDimension(values.size(), result_components);
+        for (unsigned int i = 0; i < values.size(); ++i)
+          AssertDimension(values[i].size(), n_quadrature_points);
+      }
+    else
+      {
+        AssertDimension(values.size(), n_quadrature_points);
+        for (unsigned int i = 0; i < values.size(); ++i)
+          AssertDimension(values[i].size(), result_components);
+      }
+
+    // add up contributions of trial functions.  now check whether the shape
+    // function is primitive or not. if it is, then set its only non-zero
+    // component, otherwise loop over components
+    for (unsigned int mc = 0; mc < component_multiple; ++mc)
+      for (unsigned int shape_func = 0; shape_func < dofs_per_cell;
+           ++shape_func)
+        {
+          const Number &value = dof_values[shape_func + mc * dofs_per_cell];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (fe.is_primitive(shape_func))
+            {
+              const unsigned int comp =
+                fe.system_to_component_index(shape_func).first +
+                mc * n_components;
+              const unsigned int row =
+                shape_function_to_row_table[shape_func * n_components + comp];
+
+              const double *shape_value_ptr = &shape_values(row, 0);
+
+              if (quadrature_points_fastest)
+                {
+                  VectorType &values_comp = values[comp];
+                  for (unsigned int point = 0; point < n_quadrature_points;
+                       ++point)
+                    values_comp[point] += value * (*shape_value_ptr++);
+                }
+              else
+                for (unsigned int point = 0; point < n_quadrature_points;
+                     ++point)
+                  values[point][comp] += value * (*shape_value_ptr++);
+            }
+          else
+            for (unsigned int c = 0; c < n_components; ++c)
+              {
+                if (fe.get_nonzero_components(shape_func)[c] == false)
+                  continue;
+
+                const unsigned int row =
+                  shape_function_to_row_table[shape_func * n_components + c];
+
+                const double *     shape_value_ptr = &shape_values(row, 0);
+                const unsigned int comp            = c + mc * n_components;
+
+                if (quadrature_points_fastest)
+                  {
+                    VectorType &values_comp = values[comp];
+                    for (unsigned int point = 0; point < n_quadrature_points;
+                         ++point)
+                      values_comp[point] += value * (*shape_value_ptr++);
+                  }
+                else
+                  for (unsigned int point = 0; point < n_quadrature_points;
+                       ++point)
+                    values[point][comp] += value * (*shape_value_ptr++);
+              }
+        }
+  }
+
+
+
+  // use the same implementation for gradients and Hessians, distinguish them
+  // by the rank of the tensors
+  template <int order, int spacedim, typename Number>
+  void
+  do_function_derivatives(
+    const ArrayView<Number> &                        dof_values,
+    const dealii::Table<2, Tensor<order, spacedim>> &shape_derivatives,
+    std::vector<Tensor<order, spacedim, Number>> &   derivatives)
+  {
+    const unsigned int dofs_per_cell       = shape_derivatives.size()[0];
+    const unsigned int n_quadrature_points = derivatives.size();
+
+    // initialize with zero
+    std::fill_n(derivatives.begin(),
+                n_quadrature_points,
+                Tensor<order, spacedim, Number>());
+
+    // add up contributions of trial functions. note that here we deal with
+    // scalar finite elements, so no need to check for non-primitivity of
+    // shape functions. in order to increase the speed of this function, we
+    // directly access the data in the shape_gradients/hessians array, and
+    // increment pointers for accessing the data. this saves some lookup time
+    // and indexing. moreover, the order of the loops is such that we can
+    // access the shape_gradients/hessians data stored contiguously
+    for (unsigned int shape_func = 0; shape_func < dofs_per_cell; ++shape_func)
+      {
+        const Number &value = dof_values[shape_func];
+        // For auto-differentiable numbers, the fact that a DoF value is zero
+        // does not imply that its derivatives are zero as well. So we
+        // can't filter by value for these number types.
+        if (dealii::internal::CheckForZero<Number>::value(value) == true)
+          continue;
+
+        const Tensor<order, spacedim> *shape_derivative_ptr =
+          &shape_derivatives[shape_func][0];
+        for (unsigned int point = 0; point < n_quadrature_points; ++point)
+          derivatives[point] += value * (*shape_derivative_ptr++);
+      }
+  }
+
+
+
+  template <int order, int dim, int spacedim, typename Number>
+  void
+  do_function_derivatives(
+    const ArrayView<Number> &                        dof_values,
+    const dealii::Table<2, Tensor<order, spacedim>> &shape_derivatives,
+    const FiniteElement<dim, spacedim> &             fe,
+    const std::vector<unsigned int> &shape_function_to_row_table,
+    ArrayView<std::vector<Tensor<order, spacedim, Number>>> derivatives,
+    const bool         quadrature_points_fastest = false,
+    const unsigned int component_multiple        = 1)
+  {
+    // initialize with zero
+    for (unsigned int i = 0; i < derivatives.size(); ++i)
+      std::fill_n(derivatives[i].begin(),
+                  derivatives[i].size(),
+                  Tensor<order, spacedim, Number>());
+
+    // see if there the current cell has DoFs at all, and if not
+    // then there is nothing else to do.
+    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
+    if (dofs_per_cell == 0)
+      return;
+
+
+    const unsigned int n_quadrature_points =
+      quadrature_points_fastest ? derivatives[0].size() : derivatives.size();
+    const unsigned int n_components = fe.n_components();
+
+    // Assert that we can write all components into the result vectors
+    const unsigned result_components = n_components * component_multiple;
+    (void)result_components;
+    if (quadrature_points_fastest)
+      {
+        AssertDimension(derivatives.size(), result_components);
+        for (unsigned int i = 0; i < derivatives.size(); ++i)
+          AssertDimension(derivatives[i].size(), n_quadrature_points);
+      }
+    else
+      {
+        AssertDimension(derivatives.size(), n_quadrature_points);
+        for (unsigned int i = 0; i < derivatives.size(); ++i)
+          AssertDimension(derivatives[i].size(), result_components);
+      }
+
+    // add up contributions of trial functions.  now check whether the shape
+    // function is primitive or not. if it is, then set its only non-zero
+    // component, otherwise loop over components
+    for (unsigned int mc = 0; mc < component_multiple; ++mc)
+      for (unsigned int shape_func = 0; shape_func < dofs_per_cell;
+           ++shape_func)
+        {
+          const Number &value = dof_values[shape_func + mc * dofs_per_cell];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (fe.is_primitive(shape_func))
+            {
+              const unsigned int comp =
+                fe.system_to_component_index(shape_func).first +
+                mc * n_components;
+              const unsigned int row =
+                shape_function_to_row_table[shape_func * n_components + comp];
+
+              const Tensor<order, spacedim> *shape_derivative_ptr =
+                &shape_derivatives[row][0];
+
+              if (quadrature_points_fastest)
+                for (unsigned int point = 0; point < n_quadrature_points;
+                     ++point)
+                  derivatives[comp][point] += value * (*shape_derivative_ptr++);
+              else
+                for (unsigned int point = 0; point < n_quadrature_points;
+                     ++point)
+                  derivatives[point][comp] += value * (*shape_derivative_ptr++);
+            }
+          else
+            for (unsigned int c = 0; c < n_components; ++c)
+              {
+                if (fe.get_nonzero_components(shape_func)[c] == false)
+                  continue;
+
+                const unsigned int row =
+                  shape_function_to_row_table[shape_func * n_components + c];
+
+                const Tensor<order, spacedim> *shape_derivative_ptr =
+                  &shape_derivatives[row][0];
+                const unsigned int comp = c + mc * n_components;
+
+                if (quadrature_points_fastest)
+                  for (unsigned int point = 0; point < n_quadrature_points;
+                       ++point)
+                    derivatives[comp][point] +=
+                      value * (*shape_derivative_ptr++);
+                else
+                  for (unsigned int point = 0; point < n_quadrature_points;
+                       ++point)
+                    derivatives[point][comp] +=
+                      value * (*shape_derivative_ptr++);
+              }
+        }
+  }
+
+
+
+  template <int spacedim, typename Number, typename Number2>
+  void
+  do_function_laplacians(
+    const ArrayView<Number2> &                   dof_values,
+    const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians,
+    std::vector<Number> &                        laplacians)
+  {
+    const unsigned int dofs_per_cell       = shape_hessians.size()[0];
+    const unsigned int n_quadrature_points = laplacians.size();
+
+    // initialize with zero
+    std::fill_n(laplacians.begin(),
+                n_quadrature_points,
+                dealii::internal::NumberType<Number>::value(0.0));
+
+    // add up contributions of trial functions. note that here we deal with
+    // scalar finite elements and also note that the Laplacian is
+    // the trace of the Hessian.
+    for (unsigned int shape_func = 0; shape_func < dofs_per_cell; ++shape_func)
+      {
+        const Number2 value = dof_values[shape_func];
+        // For auto-differentiable numbers, the fact that a DoF value is zero
+        // does not imply that its derivatives are zero as well. So we
+        // can't filter by value for these number types.
+        if (!Differentiation::AD::is_ad_number<Number2>::value)
+          if (value == dealii::internal::NumberType<Number2>::value(0.0))
+            continue;
+
+        const Tensor<2, spacedim> *shape_hessian_ptr =
+          &shape_hessians[shape_func][0];
+        for (unsigned int point = 0; point < n_quadrature_points; ++point)
+          laplacians[point] += value * trace(*shape_hessian_ptr++);
+      }
+  }
+
+
+
+  template <int dim, int spacedim, typename VectorType, typename Number>
+  void
+  do_function_laplacians(
+    const ArrayView<Number> &                    dof_values,
+    const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians,
+    const FiniteElement<dim, spacedim> &         fe,
+    const std::vector<unsigned int> &            shape_function_to_row_table,
+    std::vector<VectorType> &                    laplacians,
+    const bool         quadrature_points_fastest = false,
+    const unsigned int component_multiple        = 1)
+  {
+    // initialize with zero
+    for (unsigned int i = 0; i < laplacians.size(); ++i)
+      std::fill_n(laplacians[i].begin(),
+                  laplacians[i].size(),
+                  typename VectorType::value_type());
+
+    // see if there the current cell has DoFs at all, and if not
+    // then there is nothing else to do.
+    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
+    if (dofs_per_cell == 0)
+      return;
+
+
+    const unsigned int n_quadrature_points = laplacians.size();
+    const unsigned int n_components        = fe.n_components();
+
+    // Assert that we can write all components into the result vectors
+    const unsigned result_components = n_components * component_multiple;
+    (void)result_components;
+    if (quadrature_points_fastest)
+      {
+        AssertDimension(laplacians.size(), result_components);
+        for (unsigned int i = 0; i < laplacians.size(); ++i)
+          AssertDimension(laplacians[i].size(), n_quadrature_points);
+      }
+    else
+      {
+        AssertDimension(laplacians.size(), n_quadrature_points);
+        for (unsigned int i = 0; i < laplacians.size(); ++i)
+          AssertDimension(laplacians[i].size(), result_components);
+      }
+
+    // add up contributions of trial functions.  now check whether the shape
+    // function is primitive or not. if it is, then set its only non-zero
+    // component, otherwise loop over components
+    for (unsigned int mc = 0; mc < component_multiple; ++mc)
+      for (unsigned int shape_func = 0; shape_func < dofs_per_cell;
+           ++shape_func)
+        {
+          const Number &value = dof_values[shape_func + mc * dofs_per_cell];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (fe.is_primitive(shape_func))
+            {
+              const unsigned int comp =
+                fe.system_to_component_index(shape_func).first +
+                mc * n_components;
+              const unsigned int row =
+                shape_function_to_row_table[shape_func * n_components + comp];
+
+              const Tensor<2, spacedim> *shape_hessian_ptr =
+                &shape_hessians[row][0];
+              if (quadrature_points_fastest)
+                {
+                  VectorType &laplacians_comp = laplacians[comp];
+                  for (unsigned int point = 0; point < n_quadrature_points;
+                       ++point)
+                    laplacians_comp[point] +=
+                      value * trace(*shape_hessian_ptr++);
+                }
+              else
+                for (unsigned int point = 0; point < n_quadrature_points;
+                     ++point)
+                  laplacians[point][comp] +=
+                    value * trace(*shape_hessian_ptr++);
+            }
+          else
+            for (unsigned int c = 0; c < n_components; ++c)
+              {
+                if (fe.get_nonzero_components(shape_func)[c] == false)
+                  continue;
+
+                const unsigned int row =
+                  shape_function_to_row_table[shape_func * n_components + c];
+
+                const Tensor<2, spacedim> *shape_hessian_ptr =
+                  &shape_hessians[row][0];
+                const unsigned int comp = c + mc * n_components;
+
+                if (quadrature_points_fastest)
+                  {
+                    VectorType &laplacians_comp = laplacians[comp];
+                    for (unsigned int point = 0; point < n_quadrature_points;
+                         ++point)
+                      laplacians_comp[point] +=
+                        value * trace(*shape_hessian_ptr++);
+                  }
+                else
+                  for (unsigned int point = 0; point < n_quadrature_points;
+                       ++point)
+                    laplacians[point][comp] +=
+                      value * trace(*shape_hessian_ptr++);
+              }
+        }
+  }
+} // namespace internal
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_values(
+  const ReadVector<Number> &fe_function,
+  std::vector<Number> &     values) const
+{
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+  AssertDimension(fe->n_components(), 1);
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_values(make_array_view(dof_values.begin(),
+                                               dof_values.end()),
+                               this->finite_element_output.shape_values,
+                               values);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_values(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Number> &                           values) const
+{
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+  AssertDimension(fe->n_components(), 1);
+  AssertDimension(indices.size(), dofs_per_cell);
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_values(view,
+                               this->finite_element_output.shape_values,
+                               values);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_values(
+  const ReadVector<Number> &   fe_function,
+  std::vector<Vector<Number>> &values) const
+{
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_values(
+    make_array_view(dof_values.begin(), dof_values.end()),
+    this->finite_element_output.shape_values,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(values.begin(), values.end()));
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_values(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Vector<Number>> &                   values) const
+{
+  // Size of indices must be a multiple of dofs_per_cell such that an integer
+  // number of function values is generated in each point.
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_values(
+    view,
+    this->finite_element_output.shape_values,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(values.begin(), values.end()),
+    false,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_values(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  ArrayView<std::vector<Number>>                  values,
+  const bool quadrature_points_fastest) const
+{
+  Assert(this->update_flags & update_values,
+         ExcAccessToUninitializedField("update_values"));
+
+  // Size of indices must be a multiple of dofs_per_cell such that an integer
+  // number of function values is generated in each point.
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_values(
+    view,
+    this->finite_element_output.shape_values,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(values.begin(), values.end()),
+    quadrature_points_fastest,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_gradients(
+  const ReadVector<Number> &                fe_function,
+  std::vector<Tensor<1, spacedim, Number>> &gradients) const
+{
+  Assert(this->update_flags & update_gradients,
+         ExcAccessToUninitializedField("update_gradients"));
+  AssertDimension(fe->n_components(), 1);
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_derivatives(make_array_view(dof_values.begin(),
+                                                    dof_values.end()),
+                                    this->finite_element_output.shape_gradients,
+                                    gradients);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_gradients(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Tensor<1, spacedim, Number>> &      gradients) const
+{
+  Assert(this->update_flags & update_gradients,
+         ExcAccessToUninitializedField("update_gradients"));
+  AssertDimension(fe->n_components(), 1);
+  AssertDimension(indices.size(), dofs_per_cell);
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_derivatives(view,
+                                    this->finite_element_output.shape_gradients,
+                                    gradients);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_gradients(
+  const ReadVector<Number> &                             fe_function,
+  std::vector<std::vector<Tensor<1, spacedim, Number>>> &gradients) const
+{
+  Assert(this->update_flags & update_gradients,
+         ExcAccessToUninitializedField("update_gradients"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_derivatives(
+    make_array_view(dof_values.begin(), dof_values.end()),
+    this->finite_element_output.shape_gradients,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(gradients.begin(), gradients.end()));
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_gradients(
+  const ReadVector<Number> &                          fe_function,
+  const ArrayView<const types::global_dof_index> &    indices,
+  ArrayView<std::vector<Tensor<1, spacedim, Number>>> gradients,
+  const bool quadrature_points_fastest) const
+{
+  // Size of indices must be a multiple of dofs_per_cell such that an integer
+  // number of function values is generated in each point.
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+  Assert(this->update_flags & update_gradients,
+         ExcAccessToUninitializedField("update_gradients"));
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_derivatives(
+    view,
+    this->finite_element_output.shape_gradients,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(gradients.begin(), gradients.end()),
+    quadrature_points_fastest,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_hessians(
+  const ReadVector<Number> &                fe_function,
+  std::vector<Tensor<2, spacedim, Number>> &hessians) const
+{
+  AssertDimension(fe->n_components(), 1);
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_derivatives(make_array_view(dof_values.begin(),
+                                                    dof_values.end()),
+                                    this->finite_element_output.shape_hessians,
+                                    hessians);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_hessians(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Tensor<2, spacedim, Number>> &      hessians) const
+{
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+  AssertDimension(indices.size(), dofs_per_cell);
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_derivatives(view,
+                                    this->finite_element_output.shape_hessians,
+                                    hessians);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_hessians(
+  const ReadVector<Number> &                             fe_function,
+  std::vector<std::vector<Tensor<2, spacedim, Number>>> &hessians,
+  const bool quadrature_points_fastest) const
+{
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_derivatives(
+    make_array_view(dof_values.begin(), dof_values.end()),
+    this->finite_element_output.shape_hessians,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(hessians.begin(), hessians.end()),
+    quadrature_points_fastest);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_hessians(
+  const ReadVector<Number> &                          fe_function,
+  const ArrayView<const types::global_dof_index> &    indices,
+  ArrayView<std::vector<Tensor<2, spacedim, Number>>> hessians,
+  const bool quadrature_points_fastest) const
+{
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+
+  boost::container::small_vector<Number, 200> dof_values(indices.size());
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_derivatives(
+    view,
+    this->finite_element_output.shape_hessians,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(hessians.begin(), hessians.end()),
+    quadrature_points_fastest,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_laplacians(
+  const ReadVector<Number> &fe_function,
+  std::vector<Number> &     laplacians) const
+{
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  AssertDimension(fe->n_components(), 1);
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_laplacians(make_array_view(dof_values.begin(),
+                                                   dof_values.end()),
+                                   this->finite_element_output.shape_hessians,
+                                   laplacians);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_laplacians(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Number> &                           laplacians) const
+{
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  AssertDimension(fe->n_components(), 1);
+  AssertDimension(indices.size(), dofs_per_cell);
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_laplacians(view,
+                                   this->finite_element_output.shape_hessians,
+                                   laplacians);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_laplacians(
+  const ReadVector<Number> &   fe_function,
+  std::vector<Vector<Number>> &laplacians) const
+{
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_laplacians(
+    make_array_view(dof_values.begin(), dof_values.end()),
+    this->finite_element_output.shape_hessians,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    laplacians);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_laplacians(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Vector<Number>> &                   laplacians) const
+{
+  // Size of indices must be a multiple of dofs_per_cell such that an integer
+  // number of function values is generated in each point.
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+
+  boost::container::small_vector<Number, 200> dof_values(indices.size());
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_laplacians(
+    view,
+    this->finite_element_output.shape_hessians,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    laplacians,
+    false,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_laplacians(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<std::vector<Number>> &              laplacians,
+  const bool quadrature_points_fastest) const
+{
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+  Assert(this->update_flags & update_hessians,
+         ExcAccessToUninitializedField("update_hessians"));
+
+  boost::container::small_vector<Number, 200> dof_values(indices.size());
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_laplacians(
+    view,
+    this->finite_element_output.shape_hessians,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    laplacians,
+    quadrature_points_fastest,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_third_derivatives(
+  const ReadVector<Number> &                fe_function,
+  std::vector<Tensor<3, spacedim, Number>> &third_derivatives) const
+{
+  AssertDimension(fe->n_components(), 1);
+  Assert(this->update_flags & update_3rd_derivatives,
+         ExcAccessToUninitializedField("update_3rd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_derivatives(
+    make_array_view(dof_values.begin(), dof_values.end()),
+    this->finite_element_output.shape_3rd_derivatives,
+    third_derivatives);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_third_derivatives(
+  const ReadVector<Number> &                      fe_function,
+  const ArrayView<const types::global_dof_index> &indices,
+  std::vector<Tensor<3, spacedim, Number>> &      third_derivatives) const
+{
+  Assert(this->update_flags & update_3rd_derivatives,
+         ExcAccessToUninitializedField("update_3rd_derivatives"));
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+  AssertDimension(indices.size(), dofs_per_cell);
+
+  boost::container::small_vector<Number, 200> dof_values(dofs_per_cell);
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_derivatives(
+    view, this->finite_element_output.shape_3rd_derivatives, third_derivatives);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_third_derivatives(
+  const ReadVector<Number> &                             fe_function,
+  std::vector<std::vector<Tensor<3, spacedim, Number>>> &third_derivatives,
+  const bool quadrature_points_fastest) const
+{
+  Assert(this->update_flags & update_3rd_derivatives,
+         ExcAccessToUninitializedField("update_3rd_derivatives"));
+  Assert(present_cell.is_initialized(), ExcNotReinited());
+  AssertDimension(fe_function.size(), present_cell.n_dofs_for_dof_handler());
+
+  // get function values of dofs on this cell
+  Vector<Number> dof_values(dofs_per_cell);
+  present_cell.get_interpolated_dof_values(fe_function, dof_values);
+  internal::do_function_derivatives(
+    make_array_view(dof_values.begin(), dof_values.end()),
+    this->finite_element_output.shape_3rd_derivatives,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(third_derivatives.begin(), third_derivatives.end()),
+    quadrature_points_fastest);
+}
+
+
+
+template <int dim, int spacedim>
+template <typename Number>
+void
+FEValuesBase<dim, spacedim>::get_function_third_derivatives(
+  const ReadVector<Number> &                          fe_function,
+  const ArrayView<const types::global_dof_index> &    indices,
+  ArrayView<std::vector<Tensor<3, spacedim, Number>>> third_derivatives,
+  const bool quadrature_points_fastest) const
+{
+  Assert(this->update_flags & update_3rd_derivatives,
+         ExcAccessToUninitializedField("update_3rd_derivatives"));
+  Assert(indices.size() % dofs_per_cell == 0,
+         ExcNotMultiple(indices.size(), dofs_per_cell));
+
+  boost::container::small_vector<Number, 200> dof_values(indices.size());
+  auto view = make_array_view(dof_values.begin(), dof_values.end());
+  fe_function.extract_subvector_to(indices, view);
+  internal::do_function_derivatives(
+    view,
+    this->finite_element_output.shape_3rd_derivatives,
+    *fe,
+    this->finite_element_output.shape_function_to_row_table,
+    make_array_view(third_derivatives.begin(), third_derivatives.end()),
+    quadrature_points_fastest,
+    indices.size() / dofs_per_cell);
+}
+
+
+
+template <int dim, int spacedim>
+typename Triangulation<dim, spacedim>::cell_iterator
+FEValuesBase<dim, spacedim>::get_cell() const
+{
+  return present_cell;
+}
+
+
+
+template <int dim, int spacedim>
+const std::vector<Tensor<1, spacedim>> &
+FEValuesBase<dim, spacedim>::get_normal_vectors() const
+{
+  Assert(this->update_flags & update_normal_vectors,
+         (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+           "update_normal_vectors")));
+
+  return this->mapping_output.normal_vectors;
+}
+
+
+
+template <int dim, int spacedim>
+std::size_t
+FEValuesBase<dim, spacedim>::memory_consumption() const
+{
+  return (sizeof(this->update_flags) +
+          MemoryConsumption::memory_consumption(n_quadrature_points) +
+          MemoryConsumption::memory_consumption(max_n_quadrature_points) +
+          sizeof(cell_similarity) +
+          MemoryConsumption::memory_consumption(dofs_per_cell) +
+          MemoryConsumption::memory_consumption(mapping) +
+          MemoryConsumption::memory_consumption(mapping_data) +
+          MemoryConsumption::memory_consumption(*mapping_data) +
+          MemoryConsumption::memory_consumption(mapping_output) +
+          MemoryConsumption::memory_consumption(fe) +
+          MemoryConsumption::memory_consumption(fe_data) +
+          MemoryConsumption::memory_consumption(*fe_data) +
+          MemoryConsumption::memory_consumption(finite_element_output));
+}
+
+
+
+template <int dim, int spacedim>
+UpdateFlags
+FEValuesBase<dim, spacedim>::compute_update_flags(
+  const UpdateFlags update_flags) const
+{
+  // first find out which objects need to be recomputed on each
+  // cell we visit. this we have to ask the finite element and mapping.
+  // elements are first since they might require update in mapping
+  //
+  // there is no need to iterate since mappings will never require
+  // the finite element to compute something for them
+  UpdateFlags flags = update_flags | fe->requires_update_flags(update_flags);
+  flags |= mapping->requires_update_flags(flags);
+
+  return flags;
+}
+
+
+
+template <int dim, int spacedim>
+void
+FEValuesBase<dim, spacedim>::invalidate_present_cell()
+{
+  // if there is no present cell, then we shouldn't be
+  // connected via a signal to a triangulation
+  Assert(present_cell.is_initialized(), ExcInternalError());
+
+  // so delete the present cell and
+  // disconnect from the signal we have with
+  // it
+  tria_listener_refinement.disconnect();
+  tria_listener_mesh_transform.disconnect();
+  present_cell = {};
+}
+
+
+
+template <int dim, int spacedim>
+void
+FEValuesBase<dim, spacedim>::maybe_invalidate_previous_present_cell(
+  const typename Triangulation<dim, spacedim>::cell_iterator &cell)
+{
+  if (present_cell.is_initialized())
+    {
+      if (&cell->get_triangulation() !=
+          &present_cell
+             .
+             operator typename Triangulation<dim, spacedim>::cell_iterator()
+             ->get_triangulation())
+        {
+          // the triangulations for the previous cell and the current cell
+          // do not match. disconnect from the previous triangulation and
+          // connect to the current one; also invalidate the previous
+          // cell because we shouldn't be comparing cells from different
+          // triangulations
+          invalidate_present_cell();
+          tria_listener_refinement =
+            cell->get_triangulation().signals.any_change.connect(
+              [this]() { this->invalidate_present_cell(); });
+          tria_listener_mesh_transform =
+            cell->get_triangulation().signals.mesh_movement.connect(
+              [this]() { this->invalidate_present_cell(); });
+        }
+    }
+  else
+    {
+      // if this FEValues has never been set to any cell at all, then
+      // at least subscribe to the triangulation to get notified of
+      // changes
+      tria_listener_refinement =
+        cell->get_triangulation().signals.post_refinement.connect(
+          [this]() { this->invalidate_present_cell(); });
+      tria_listener_mesh_transform =
+        cell->get_triangulation().signals.mesh_movement.connect(
+          [this]() { this->invalidate_present_cell(); });
+    }
+}
+
+
+
+template <int dim, int spacedim>
+inline void
+FEValuesBase<dim, spacedim>::check_cell_similarity(
+  const typename Triangulation<dim, spacedim>::cell_iterator &cell)
+{
+  // Unfortunately, the detection of simple geometries with CellSimilarity is
+  // sensitive to the first cell detected. When doing this with multiple
+  // threads, each thread will get its own scratch data object with an
+  // FEValues object in the implementation framework from late 2013, which is
+  // initialized to the first cell the thread sees. As this number might
+  // different between different runs (after all, the tasks are scheduled
+  // dynamically onto threads), this slight deviation leads to difference in
+  // roundoff errors that propagate through the program. Therefore, we need to
+  // disable CellSimilarity in case there is more than one thread in the
+  // problem. This will likely not affect many MPI test cases as there
+  // multithreading is disabled on default, but in many other situations
+  // because we rarely explicitly set the number of threads.
+  //
+  // TODO: Is it reasonable to introduce a flag "unsafe" in the constructor of
+  // FEValues to re-enable this feature?
+  if (MultithreadInfo::n_threads() > 1)
+    {
+      cell_similarity = CellSimilarity::none;
+      return;
+    }
+
+  // case that there has not been any cell before
+  if (this->present_cell.is_initialized() == false)
+    cell_similarity = CellSimilarity::none;
+  else
+    // in MappingQ, data can have been modified during the last call. Then, we
+    // can't use that data on the new cell.
+    if (cell_similarity == CellSimilarity::invalid_next_cell)
+    cell_similarity = CellSimilarity::none;
+  else
+    cell_similarity =
+      (cell->is_translation_of(
+         static_cast<const typename Triangulation<dim, spacedim>::cell_iterator
+                       &>(this->present_cell)) ?
+         CellSimilarity::translation :
+         CellSimilarity::none);
+
+  if ((dim < spacedim) && (cell_similarity == CellSimilarity::translation))
+    {
+      if (static_cast<const typename Triangulation<dim, spacedim>::cell_iterator
+                        &>(this->present_cell)
+            ->direction_flag() != cell->direction_flag())
+        cell_similarity = CellSimilarity::inverted_translation;
+    }
+  // TODO: here, one could implement other checks for similarity, e.g. for
+  // children of a parallelogram.
+}
+
+
+
+template <int dim, int spacedim>
+CellSimilarity::Similarity
+FEValuesBase<dim, spacedim>::get_cell_similarity() const
+{
+  return cell_similarity;
+}
+
+
+
+template <int dim, int spacedim>
+const unsigned int FEValuesBase<dim, spacedim>::dimension;
+
+
+
+template <int dim, int spacedim>
+const unsigned int FEValuesBase<dim, spacedim>::space_dimension;
+
+/*-------------------------- Explicit Instantiations -------------------------*/
+
+
+#include "fe_values_base.inst"
+
+DEAL_II_NAMESPACE_CLOSE
diff --git a/source/fe/fe_values_base.inst.in b/source/fe/fe_values_base.inst.in
new file mode 100644 (file)
index 0000000..012d897
--- /dev/null
@@ -0,0 +1,164 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2022 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 DOXYGEN
+
+for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template class FEValuesBase<deal_II_dimension, deal_II_space_dimension>;
+#  endif
+  }
+
+for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
+     deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      CellIteratorContainer::get_interpolated_dof_values<S>(
+        const ReadVector<S> &, Vector<S> &) const;
+#  endif
+  }
+
+for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
+     deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(const ReadVector<S> &, std::vector<S> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(const ReadVector<S> &,
+                             const ArrayView<const types::global_dof_index> &,
+                             std::vector<S> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(const ReadVector<S> &, std::vector<Vector<S>> &)
+        const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(const ReadVector<S> &,
+                             const ArrayView<const types::global_dof_index> &,
+                             std::vector<Vector<S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(const ReadVector<S> &,
+                             const ArrayView<const types::global_dof_index> &,
+                             ArrayView<std::vector<S>>,
+                             bool) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        std::vector<dealii::Tensor<1, deal_II_space_dimension, S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        std::vector<dealii::Tensor<1, deal_II_space_dimension, S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        std::vector<std::vector<dealii::Tensor<1, deal_II_space_dimension, S>>>
+          &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        ArrayView<std::vector<dealii::Tensor<1, deal_II_space_dimension, S>>>,
+        bool) const;
+#  endif
+  }
+
+for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
+     deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians<S>(
+        const ReadVector<S> &,
+        std::vector<dealii::Tensor<2, deal_II_space_dimension, S>> &) const;
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        std::vector<dealii::Tensor<2, deal_II_space_dimension, S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians<S>(
+        const ReadVector<S> &,
+        std::vector<std::vector<dealii::Tensor<2, deal_II_space_dimension, S>>>
+          &,
+        bool) const;
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        ArrayView<std::vector<dealii::Tensor<2, deal_II_space_dimension, S>>>,
+        bool) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(const ReadVector<S> &, std::vector<S> &) const;
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        std::vector<S> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(const ReadVector<S> &,
+                                 std::vector<Vector<S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        std::vector<Vector<S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        std::vector<std::vector<S>> &,
+        bool) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives<S>(
+        const ReadVector<S> &,
+        std::vector<dealii::Tensor<3, deal_II_space_dimension, S>> &) const;
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        std::vector<dealii::Tensor<3, deal_II_space_dimension, S>> &) const;
+
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives<S>(
+        const ReadVector<S> &,
+        std::vector<std::vector<dealii::Tensor<3, deal_II_space_dimension, S>>>
+          &,
+        bool) const;
+    template void FEValuesBase<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives<S>(
+        const ReadVector<S> &,
+        const ArrayView<const types::global_dof_index> &,
+        ArrayView<std::vector<dealii::Tensor<3, deal_II_space_dimension, S>>>,
+        bool) const;
+#  endif
+  }
+#endif
diff --git a/source/fe/fe_values_views.cc b/source/fe/fe_values_views.cc
new file mode 100644 (file)
index 0000000..a620da2
--- /dev/null
@@ -0,0 +1,2519 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2023 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.
+//
+// ---------------------------------------------------------------------
+
+#include <deal.II/base/array_view.h>
+#include <deal.II/base/memory_consumption.h>
+#include <deal.II/base/multithread_info.h>
+#include <deal.II/base/numbers.h>
+#include <deal.II/base/quadrature.h>
+#include <deal.II/base/signaling_nan.h>
+#include <deal.II/base/thread_management.h>
+
+#include <deal.II/differentiation/ad.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+
+#include <deal.II/fe/fe.h>
+#include <deal.II/fe/fe_values_base.h>
+#include <deal.II/fe/fe_values_views.h>
+#include <deal.II/fe/mapping.h>
+
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/lac/vector.h>
+
+#include <boost/container/small_vector.hpp>
+
+#include <iomanip>
+#include <memory>
+#include <type_traits>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+namespace internal
+{
+  template <int dim, int spacedim>
+  inline std::vector<unsigned int>
+  make_shape_function_to_row_table(const FiniteElement<dim, spacedim> &fe)
+  {
+    std::vector<unsigned int> shape_function_to_row_table(
+      fe.n_dofs_per_cell() * fe.n_components(), numbers::invalid_unsigned_int);
+    unsigned int row = 0;
+    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+      {
+        // loop over all components that are nonzero for this particular
+        // shape function. if a component is zero then we leave the
+        // value in the table unchanged (at the invalid value)
+        // otherwise it is mapped to the next free entry
+        unsigned int nth_nonzero_component = 0;
+        for (unsigned int c = 0; c < fe.n_components(); ++c)
+          if (fe.get_nonzero_components(i)[c] == true)
+            {
+              shape_function_to_row_table[i * fe.n_components() + c] =
+                row + nth_nonzero_component;
+              ++nth_nonzero_component;
+            }
+        row += fe.n_nonzero_components(i);
+      }
+
+    return shape_function_to_row_table;
+  }
+
+  namespace
+  {
+    // Check to see if a DoF value is zero, implying that subsequent operations
+    // with the value have no effect.
+    template <typename Number, typename T = void>
+    struct CheckForZero
+    {
+      static bool
+      value(const Number &value)
+      {
+        return value == dealii::internal::NumberType<Number>::value(0.0);
+      }
+    };
+
+    // For auto-differentiable numbers, the fact that a DoF value is zero
+    // does not imply that its derivatives are zero as well. So we
+    // can't filter by value for these number types.
+    // Note that we also want to avoid actually checking the value itself,
+    // since some AD numbers are not contextually convertible to booleans.
+    template <typename Number>
+    struct CheckForZero<
+      Number,
+      std::enable_if_t<Differentiation::AD::is_ad_number<Number>::value>>
+    {
+      static bool
+      value(const Number & /*value*/)
+      {
+        return false;
+      }
+    };
+  } // namespace
+} // namespace internal
+
+
+
+namespace FEValuesViews
+{
+  template <int dim, int spacedim>
+  Scalar<dim, spacedim>::Scalar(const FEValuesBase<dim, spacedim> &fe_values,
+                                const unsigned int                 component)
+    : fe_values(&fe_values)
+    , component(component)
+    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
+  {
+    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
+    AssertIndexRange(component, fe.n_components());
+
+    // TODO: we'd like to use the fields with the same name as these
+    // variables from FEValuesBase, but they aren't initialized yet
+    // at the time we get here, so re-create it all
+    const std::vector<unsigned int> shape_function_to_row_table =
+      dealii::internal::make_shape_function_to_row_table(fe);
+
+    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+      {
+        const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
+
+        if (is_primitive == true)
+          shape_function_data[i].is_nonzero_shape_function_component =
+            (component == fe.system_to_component_index(i).first);
+        else
+          shape_function_data[i].is_nonzero_shape_function_component =
+            (fe.get_nonzero_components(i)[component] == true);
+
+        if (shape_function_data[i].is_nonzero_shape_function_component == true)
+          shape_function_data[i].row_index =
+            shape_function_to_row_table[i * fe.n_components() + component];
+        else
+          shape_function_data[i].row_index = numbers::invalid_unsigned_int;
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  Scalar<dim, spacedim>::Scalar()
+    : fe_values(nullptr)
+    , component(numbers::invalid_unsigned_int)
+  {}
+
+
+
+  template <int dim, int spacedim>
+  Vector<dim, spacedim>::Vector(const FEValuesBase<dim, spacedim> &fe_values,
+                                const unsigned int first_vector_component)
+    : fe_values(&fe_values)
+    , first_vector_component(first_vector_component)
+    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
+  {
+    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
+    AssertIndexRange(first_vector_component + spacedim - 1, fe.n_components());
+
+    // TODO: we'd like to use the fields with the same name as these
+    // variables from FEValuesBase, but they aren't initialized yet
+    // at the time we get here, so re-create it all
+    const std::vector<unsigned int> shape_function_to_row_table =
+      dealii::internal::make_shape_function_to_row_table(fe);
+
+    for (unsigned int d = 0; d < spacedim; ++d)
+      {
+        const unsigned int component = first_vector_component + d;
+
+        for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+          {
+            const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
+
+            if (is_primitive == true)
+              shape_function_data[i].is_nonzero_shape_function_component[d] =
+                (component == fe.system_to_component_index(i).first);
+            else
+              shape_function_data[i].is_nonzero_shape_function_component[d] =
+                (fe.get_nonzero_components(i)[component] == true);
+
+            if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
+                true)
+              shape_function_data[i].row_index[d] =
+                shape_function_to_row_table[i * fe.n_components() + component];
+            else
+              shape_function_data[i].row_index[d] =
+                numbers::invalid_unsigned_int;
+          }
+      }
+
+    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+      {
+        unsigned int n_nonzero_components = 0;
+        for (unsigned int d = 0; d < spacedim; ++d)
+          if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
+              true)
+            ++n_nonzero_components;
+
+        if (n_nonzero_components == 0)
+          shape_function_data[i].single_nonzero_component = -2;
+        else if (n_nonzero_components > 1)
+          shape_function_data[i].single_nonzero_component = -1;
+        else
+          {
+            for (unsigned int d = 0; d < spacedim; ++d)
+              if (shape_function_data[i]
+                    .is_nonzero_shape_function_component[d] == true)
+                {
+                  shape_function_data[i].single_nonzero_component =
+                    shape_function_data[i].row_index[d];
+                  shape_function_data[i].single_nonzero_component_index = d;
+                  break;
+                }
+          }
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  Vector<dim, spacedim>::Vector()
+    : fe_values(nullptr)
+    , first_vector_component(numbers::invalid_unsigned_int)
+  {}
+
+
+
+  template <int dim, int spacedim>
+  SymmetricTensor<2, dim, spacedim>::SymmetricTensor(
+    const FEValuesBase<dim, spacedim> &fe_values,
+    const unsigned int                 first_tensor_component)
+    : fe_values(&fe_values)
+    , first_tensor_component(first_tensor_component)
+    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
+  {
+    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
+    Assert(first_tensor_component + (dim * dim + dim) / 2 - 1 <
+             fe.n_components(),
+           ExcIndexRange(
+             first_tensor_component +
+               dealii::SymmetricTensor<2, dim>::n_independent_components - 1,
+             0,
+             fe.n_components()));
+    // TODO: we'd like to use the fields with the same name as these
+    // variables from FEValuesBase, but they aren't initialized yet
+    // at the time we get here, so re-create it all
+    const std::vector<unsigned int> shape_function_to_row_table =
+      dealii::internal::make_shape_function_to_row_table(fe);
+
+    for (unsigned int d = 0;
+         d < dealii::SymmetricTensor<2, dim>::n_independent_components;
+         ++d)
+      {
+        const unsigned int component = first_tensor_component + d;
+
+        for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+          {
+            const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
+
+            if (is_primitive == true)
+              shape_function_data[i].is_nonzero_shape_function_component[d] =
+                (component == fe.system_to_component_index(i).first);
+            else
+              shape_function_data[i].is_nonzero_shape_function_component[d] =
+                (fe.get_nonzero_components(i)[component] == true);
+
+            if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
+                true)
+              shape_function_data[i].row_index[d] =
+                shape_function_to_row_table[i * fe.n_components() + component];
+            else
+              shape_function_data[i].row_index[d] =
+                numbers::invalid_unsigned_int;
+          }
+      }
+
+    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+      {
+        unsigned int n_nonzero_components = 0;
+        for (unsigned int d = 0;
+             d < dealii::SymmetricTensor<2, dim>::n_independent_components;
+             ++d)
+          if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
+              true)
+            ++n_nonzero_components;
+
+        if (n_nonzero_components == 0)
+          shape_function_data[i].single_nonzero_component = -2;
+        else if (n_nonzero_components > 1)
+          shape_function_data[i].single_nonzero_component = -1;
+        else
+          {
+            for (unsigned int d = 0;
+                 d < dealii::SymmetricTensor<2, dim>::n_independent_components;
+                 ++d)
+              if (shape_function_data[i]
+                    .is_nonzero_shape_function_component[d] == true)
+                {
+                  shape_function_data[i].single_nonzero_component =
+                    shape_function_data[i].row_index[d];
+                  shape_function_data[i].single_nonzero_component_index = d;
+                  break;
+                }
+          }
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  SymmetricTensor<2, dim, spacedim>::SymmetricTensor()
+    : fe_values(nullptr)
+    , first_tensor_component(numbers::invalid_unsigned_int)
+  {}
+
+
+
+  template <int dim, int spacedim>
+  Tensor<2, dim, spacedim>::Tensor(const FEValuesBase<dim, spacedim> &fe_values,
+                                   const unsigned int first_tensor_component)
+    : fe_values(&fe_values)
+    , first_tensor_component(first_tensor_component)
+    , shape_function_data(this->fe_values->fe->n_dofs_per_cell())
+  {
+    const FiniteElement<dim, spacedim> &fe = *this->fe_values->fe;
+    AssertIndexRange(first_tensor_component + dim * dim - 1, fe.n_components());
+    // TODO: we'd like to use the fields with the same name as these
+    // variables from FEValuesBase, but they aren't initialized yet
+    // at the time we get here, so re-create it all
+    const std::vector<unsigned int> shape_function_to_row_table =
+      dealii::internal::make_shape_function_to_row_table(fe);
+
+    for (unsigned int d = 0; d < dim * dim; ++d)
+      {
+        const unsigned int component = first_tensor_component + d;
+
+        for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+          {
+            const bool is_primitive = fe.is_primitive() || fe.is_primitive(i);
+
+            if (is_primitive == true)
+              shape_function_data[i].is_nonzero_shape_function_component[d] =
+                (component == fe.system_to_component_index(i).first);
+            else
+              shape_function_data[i].is_nonzero_shape_function_component[d] =
+                (fe.get_nonzero_components(i)[component] == true);
+
+            if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
+                true)
+              shape_function_data[i].row_index[d] =
+                shape_function_to_row_table[i * fe.n_components() + component];
+            else
+              shape_function_data[i].row_index[d] =
+                numbers::invalid_unsigned_int;
+          }
+      }
+
+    for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
+      {
+        unsigned int n_nonzero_components = 0;
+        for (unsigned int d = 0; d < dim * dim; ++d)
+          if (shape_function_data[i].is_nonzero_shape_function_component[d] ==
+              true)
+            ++n_nonzero_components;
+
+        if (n_nonzero_components == 0)
+          shape_function_data[i].single_nonzero_component = -2;
+        else if (n_nonzero_components > 1)
+          shape_function_data[i].single_nonzero_component = -1;
+        else
+          {
+            for (unsigned int d = 0; d < dim * dim; ++d)
+              if (shape_function_data[i]
+                    .is_nonzero_shape_function_component[d] == true)
+                {
+                  shape_function_data[i].single_nonzero_component =
+                    shape_function_data[i].row_index[d];
+                  shape_function_data[i].single_nonzero_component_index = d;
+                  break;
+                }
+          }
+      }
+  }
+
+
+
+  template <int dim, int spacedim>
+  Tensor<2, dim, spacedim>::Tensor()
+    : fe_values(nullptr)
+    , first_tensor_component(numbers::invalid_unsigned_int)
+  {}
+
+
+
+  namespace internal
+  {
+    // Given values of degrees of freedom, evaluate the
+    // values/gradients/... at quadrature points
+
+    // ------------------------- scalar functions --------------------------
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_values(
+      const ArrayView<Number> &dof_values,
+      const Table<2, double> & shape_values,
+      const std::vector<typename Scalar<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename ProductType<Number, double>::type> &values)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = values.size();
+
+      std::fill(values.begin(),
+                values.end(),
+                dealii::internal::NumberType<Number>::value(0.0));
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        if (shape_function_data[shape_function]
+              .is_nonzero_shape_function_component)
+          {
+            const Number &value = dof_values[shape_function];
+            // For auto-differentiable numbers, the fact that a DoF value is
+            // zero does not imply that its derivatives are zero as well. So we
+            // can't filter by value for these number types.
+            if (dealii::internal::CheckForZero<Number>::value(value) == true)
+              continue;
+
+            const double *shape_value_ptr =
+              &shape_values(shape_function_data[shape_function].row_index, 0);
+            for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                 ++q_point)
+              values[q_point] += value * (*shape_value_ptr++);
+          }
+    }
+
+
+
+    // same code for gradient and Hessian, template argument 'order' to give
+    // the order of the derivative (= rank of gradient/Hessian tensor)
+    template <int order, int dim, int spacedim, typename Number>
+    void
+    do_function_derivatives(
+      const ArrayView<Number> &                        dof_values,
+      const Table<2, dealii::Tensor<order, spacedim>> &shape_derivatives,
+      const std::vector<typename Scalar<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<
+        typename ProductType<Number, dealii::Tensor<order, spacedim>>::type>
+        &derivatives)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = derivatives.size();
+
+      std::fill(
+        derivatives.begin(),
+        derivatives.end(),
+        typename ProductType<Number, dealii::Tensor<order, spacedim>>::type());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        if (shape_function_data[shape_function]
+              .is_nonzero_shape_function_component)
+          {
+            const Number &value = dof_values[shape_function];
+            // For auto-differentiable numbers, the fact that a DoF value is
+            // zero does not imply that its derivatives are zero as well. So we
+            // can't filter by value for these number types.
+            if (dealii::internal::CheckForZero<Number>::value(value) == true)
+              continue;
+
+            const dealii::Tensor<order, spacedim> *shape_derivative_ptr =
+              &shape_derivatives[shape_function_data[shape_function].row_index]
+                                [0];
+            for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                 ++q_point)
+              derivatives[q_point] += value * (*shape_derivative_ptr++);
+          }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_laplacians(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians,
+      const std::vector<typename Scalar<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename Scalar<dim, spacedim>::
+                    template solution_laplacian_type<Number>> &laplacians)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = laplacians.size();
+
+      std::fill(
+        laplacians.begin(),
+        laplacians.end(),
+        typename Scalar<dim,
+                        spacedim>::template solution_laplacian_type<Number>());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        if (shape_function_data[shape_function]
+              .is_nonzero_shape_function_component)
+          {
+            const Number &value = dof_values[shape_function];
+            // For auto-differentiable numbers, the fact that a DoF value is
+            // zero does not imply that its derivatives are zero as well. So we
+            // can't filter by value for these number types.
+            if (dealii::internal::CheckForZero<Number>::value(value) == true)
+              continue;
+
+            const dealii::Tensor<2, spacedim> *shape_hessian_ptr =
+              &shape_hessians[shape_function_data[shape_function].row_index][0];
+            for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                 ++q_point)
+              laplacians[q_point] += value * trace(*shape_hessian_ptr++);
+          }
+    }
+
+
+
+    // ----------------------------- vector part ---------------------------
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_values(
+      const ArrayView<Number> &dof_values,
+      const Table<2, double> & shape_values,
+      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<
+        typename ProductType<Number, dealii::Tensor<1, spacedim>>::type>
+        &values)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = values.size();
+
+      std::fill(
+        values.begin(),
+        values.end(),
+        typename ProductType<Number, dealii::Tensor<1, spacedim>>::type());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+              const double *shape_value_ptr = &shape_values(snc, 0);
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                values[q_point][comp] += value * (*shape_value_ptr++);
+            }
+          else
+            for (unsigned int d = 0; d < spacedim; ++d)
+              if (shape_function_data[shape_function]
+                    .is_nonzero_shape_function_component[d])
+                {
+                  const double *shape_value_ptr = &shape_values(
+                    shape_function_data[shape_function].row_index[d], 0);
+                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                       ++q_point)
+                    values[q_point][d] += value * (*shape_value_ptr++);
+                }
+        }
+    }
+
+
+
+    template <int order, int dim, int spacedim, typename Number>
+    void
+    do_function_derivatives(
+      const ArrayView<Number> &                        dof_values,
+      const Table<2, dealii::Tensor<order, spacedim>> &shape_derivatives,
+      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<
+        typename ProductType<Number, dealii::Tensor<order + 1, spacedim>>::type>
+        &derivatives)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = derivatives.size();
+
+      std::fill(
+        derivatives.begin(),
+        derivatives.end(),
+        typename ProductType<Number,
+                             dealii::Tensor<order + 1, spacedim>>::type());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+              const dealii::Tensor<order, spacedim> *shape_derivative_ptr =
+                &shape_derivatives[snc][0];
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                derivatives[q_point][comp] += value * (*shape_derivative_ptr++);
+            }
+          else
+            for (unsigned int d = 0; d < spacedim; ++d)
+              if (shape_function_data[shape_function]
+                    .is_nonzero_shape_function_component[d])
+                {
+                  const dealii::Tensor<order, spacedim> *shape_derivative_ptr =
+                    &shape_derivatives[shape_function_data[shape_function]
+                                         .row_index[d]][0];
+                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                       ++q_point)
+                    derivatives[q_point][d] +=
+                      value * (*shape_derivative_ptr++);
+                }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_symmetric_gradients(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
+      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<
+        typename ProductType<Number,
+                             dealii::SymmetricTensor<2, spacedim>>::type>
+        &symmetric_gradients)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = symmetric_gradients.size();
+
+      std::fill(
+        symmetric_gradients.begin(),
+        symmetric_gradients.end(),
+        typename ProductType<Number,
+                             dealii::SymmetricTensor<2, spacedim>>::type());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                &shape_gradients[snc][0];
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                symmetric_gradients[q_point] +=
+                  value * dealii::SymmetricTensor<2, spacedim>(
+                            symmetrize_single_row(comp, *shape_gradient_ptr++));
+            }
+          else
+            for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                 ++q_point)
+              {
+                typename ProductType<Number, dealii::Tensor<2, spacedim>>::type
+                  grad;
+                for (unsigned int d = 0; d < spacedim; ++d)
+                  if (shape_function_data[shape_function]
+                        .is_nonzero_shape_function_component[d])
+                    grad[d] =
+                      value *
+                      shape_gradients[shape_function_data[shape_function]
+                                        .row_index[d]][q_point];
+                symmetric_gradients[q_point] += symmetrize(grad);
+              }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_divergences(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
+      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename Vector<dim, spacedim>::
+                    template solution_divergence_type<Number>> &divergences)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = divergences.size();
+
+      std::fill(
+        divergences.begin(),
+        divergences.end(),
+        typename Vector<dim,
+                        spacedim>::template solution_divergence_type<Number>());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                &shape_gradients[snc][0];
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                divergences[q_point] += value * (*shape_gradient_ptr++)[comp];
+            }
+          else
+            for (unsigned int d = 0; d < spacedim; ++d)
+              if (shape_function_data[shape_function]
+                    .is_nonzero_shape_function_component[d])
+                {
+                  const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                    &shape_gradients[shape_function_data[shape_function]
+                                       .row_index[d]][0];
+                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                       ++q_point)
+                    divergences[q_point] += value * (*shape_gradient_ptr++)[d];
+                }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_curls(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
+      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename ProductType<
+        Number,
+        typename dealii::internal::CurlType<spacedim>::type>::type> &curls)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = curls.size();
+
+      std::fill(curls.begin(),
+                curls.end(),
+                typename ProductType<
+                  Number,
+                  typename dealii::internal::CurlType<spacedim>::type>::type());
+
+      switch (spacedim)
+        {
+          case 1:
+            {
+              Assert(false,
+                     ExcMessage(
+                       "Computing the curl in 1d is not a useful operation"));
+              break;
+            }
+
+          case 2:
+            {
+              for (unsigned int shape_function = 0;
+                   shape_function < dofs_per_cell;
+                   ++shape_function)
+                {
+                  const int snc = shape_function_data[shape_function]
+                                    .single_nonzero_component;
+
+                  if (snc == -2)
+                    // shape function is zero for the selected components
+                    continue;
+
+                  const Number &value = dof_values[shape_function];
+                  // For auto-differentiable numbers, the fact that a DoF value
+                  // is zero does not imply that its derivatives are zero as
+                  // well. So we can't filter by value for these number types.
+                  if (dealii::internal::CheckForZero<Number>::value(value) ==
+                      true)
+                    continue;
+
+                  if (snc != -1)
+                    {
+                      const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                        &shape_gradients[snc][0];
+
+                      Assert(shape_function_data[shape_function]
+                                 .single_nonzero_component >= 0,
+                             ExcInternalError());
+                      // we're in 2d, so the formula for the curl is simple:
+                      if (shape_function_data[shape_function]
+                            .single_nonzero_component_index == 0)
+                        for (unsigned int q_point = 0;
+                             q_point < n_quadrature_points;
+                             ++q_point)
+                          curls[q_point][0] -=
+                            value * (*shape_gradient_ptr++)[1];
+                      else
+                        for (unsigned int q_point = 0;
+                             q_point < n_quadrature_points;
+                             ++q_point)
+                          curls[q_point][0] +=
+                            value * (*shape_gradient_ptr++)[0];
+                    }
+                  else
+                    // we have multiple non-zero components in the shape
+                    // functions. not all of them must necessarily be within the
+                    // 2-component window this FEValuesViews::Vector object
+                    // considers, however.
+                    {
+                      if (shape_function_data[shape_function]
+                            .is_nonzero_shape_function_component[0])
+                        {
+                          const dealii::Tensor<1,
+                                               spacedim> *shape_gradient_ptr =
+                            &shape_gradients[shape_function_data[shape_function]
+                                               .row_index[0]][0];
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_quadrature_points;
+                               ++q_point)
+                            curls[q_point][0] -=
+                              value * (*shape_gradient_ptr++)[1];
+                        }
+
+                      if (shape_function_data[shape_function]
+                            .is_nonzero_shape_function_component[1])
+                        {
+                          const dealii::Tensor<1,
+                                               spacedim> *shape_gradient_ptr =
+                            &shape_gradients[shape_function_data[shape_function]
+                                               .row_index[1]][0];
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_quadrature_points;
+                               ++q_point)
+                            curls[q_point][0] +=
+                              value * (*shape_gradient_ptr++)[0];
+                        }
+                    }
+                }
+              break;
+            }
+
+          case 3:
+            {
+              for (unsigned int shape_function = 0;
+                   shape_function < dofs_per_cell;
+                   ++shape_function)
+                {
+                  const int snc = shape_function_data[shape_function]
+                                    .single_nonzero_component;
+
+                  if (snc == -2)
+                    // shape function is zero for the selected components
+                    continue;
+
+                  const Number &value = dof_values[shape_function];
+                  // For auto-differentiable numbers, the fact that a DoF value
+                  // is zero does not imply that its derivatives are zero as
+                  // well. So we can't filter by value for these number types.
+                  if (dealii::internal::CheckForZero<Number>::value(value) ==
+                      true)
+                    continue;
+
+                  if (snc != -1)
+                    {
+                      const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                        &shape_gradients[snc][0];
+
+                      switch (shape_function_data[shape_function]
+                                .single_nonzero_component_index)
+                        {
+                          case 0:
+                            {
+                              for (unsigned int q_point = 0;
+                                   q_point < n_quadrature_points;
+                                   ++q_point)
+                                {
+                                  curls[q_point][1] +=
+                                    value * (*shape_gradient_ptr)[2];
+                                  curls[q_point][2] -=
+                                    value * (*shape_gradient_ptr++)[1];
+                                }
+
+                              break;
+                            }
+
+                          case 1:
+                            {
+                              for (unsigned int q_point = 0;
+                                   q_point < n_quadrature_points;
+                                   ++q_point)
+                                {
+                                  curls[q_point][0] -=
+                                    value * (*shape_gradient_ptr)[2];
+                                  curls[q_point][2] +=
+                                    value * (*shape_gradient_ptr++)[0];
+                                }
+
+                              break;
+                            }
+
+                          case 2:
+                            {
+                              for (unsigned int q_point = 0;
+                                   q_point < n_quadrature_points;
+                                   ++q_point)
+                                {
+                                  curls[q_point][0] +=
+                                    value * (*shape_gradient_ptr)[1];
+                                  curls[q_point][1] -=
+                                    value * (*shape_gradient_ptr++)[0];
+                                }
+                              break;
+                            }
+
+                          default:
+                            Assert(false, ExcInternalError());
+                        }
+                    }
+
+                  else
+                    // we have multiple non-zero components in the shape
+                    // functions. not all of them must necessarily be within the
+                    // 3-component window this FEValuesViews::Vector object
+                    // considers, however.
+                    {
+                      if (shape_function_data[shape_function]
+                            .is_nonzero_shape_function_component[0])
+                        {
+                          const dealii::Tensor<1,
+                                               spacedim> *shape_gradient_ptr =
+                            &shape_gradients[shape_function_data[shape_function]
+                                               .row_index[0]][0];
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_quadrature_points;
+                               ++q_point)
+                            {
+                              curls[q_point][1] +=
+                                value * (*shape_gradient_ptr)[2];
+                              curls[q_point][2] -=
+                                value * (*shape_gradient_ptr++)[1];
+                            }
+                        }
+
+                      if (shape_function_data[shape_function]
+                            .is_nonzero_shape_function_component[1])
+                        {
+                          const dealii::Tensor<1,
+                                               spacedim> *shape_gradient_ptr =
+                            &shape_gradients[shape_function_data[shape_function]
+                                               .row_index[1]][0];
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_quadrature_points;
+                               ++q_point)
+                            {
+                              curls[q_point][0] -=
+                                value * (*shape_gradient_ptr)[2];
+                              curls[q_point][2] +=
+                                value * (*shape_gradient_ptr++)[0];
+                            }
+                        }
+
+                      if (shape_function_data[shape_function]
+                            .is_nonzero_shape_function_component[2])
+                        {
+                          const dealii::Tensor<1,
+                                               spacedim> *shape_gradient_ptr =
+                            &shape_gradients[shape_function_data[shape_function]
+                                               .row_index[2]][0];
+
+                          for (unsigned int q_point = 0;
+                               q_point < n_quadrature_points;
+                               ++q_point)
+                            {
+                              curls[q_point][0] +=
+                                value * (*shape_gradient_ptr)[1];
+                              curls[q_point][1] -=
+                                value * (*shape_gradient_ptr++)[0];
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_laplacians(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians,
+      const std::vector<typename Vector<dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename Vector<dim, spacedim>::
+                    template solution_laplacian_type<Number>> &laplacians)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = laplacians.size();
+
+      std::fill(
+        laplacians.begin(),
+        laplacians.end(),
+        typename Vector<dim,
+                        spacedim>::template solution_laplacian_type<Number>());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+              const dealii::Tensor<2, spacedim> *shape_hessian_ptr =
+                &shape_hessians[snc][0];
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                laplacians[q_point][comp] +=
+                  value * trace(*shape_hessian_ptr++);
+            }
+          else
+            for (unsigned int d = 0; d < spacedim; ++d)
+              if (shape_function_data[shape_function]
+                    .is_nonzero_shape_function_component[d])
+                {
+                  const dealii::Tensor<2, spacedim> *shape_hessian_ptr =
+                    &shape_hessians[shape_function_data[shape_function]
+                                      .row_index[d]][0];
+                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                       ++q_point)
+                    laplacians[q_point][d] +=
+                      value * trace(*shape_hessian_ptr++);
+                }
+        }
+    }
+
+
+
+    // ---------------------- symmetric tensor part ------------------------
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_values(
+      const ArrayView<Number> &       dof_values,
+      const dealii::Table<2, double> &shape_values,
+      const std::vector<
+        typename SymmetricTensor<2, dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<
+        typename ProductType<Number,
+                             dealii::SymmetricTensor<2, spacedim>>::type>
+        &values)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = values.size();
+
+      std::fill(
+        values.begin(),
+        values.end(),
+        typename ProductType<Number,
+                             dealii::SymmetricTensor<2, spacedim>>::type());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const TableIndices<2> comp = dealii::
+                SymmetricTensor<2, spacedim>::unrolled_to_component_indices(
+                  shape_function_data[shape_function]
+                    .single_nonzero_component_index);
+              const double *shape_value_ptr = &shape_values(snc, 0);
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                values[q_point][comp] += value * (*shape_value_ptr++);
+            }
+          else
+            for (unsigned int d = 0;
+                 d <
+                 dealii::SymmetricTensor<2, spacedim>::n_independent_components;
+                 ++d)
+              if (shape_function_data[shape_function]
+                    .is_nonzero_shape_function_component[d])
+                {
+                  const TableIndices<2> comp =
+                    dealii::SymmetricTensor<2, spacedim>::
+                      unrolled_to_component_indices(d);
+                  const double *shape_value_ptr = &shape_values(
+                    shape_function_data[shape_function].row_index[d], 0);
+                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                       ++q_point)
+                    values[q_point][comp] += value * (*shape_value_ptr++);
+                }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_divergences(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
+      const std::vector<
+        typename SymmetricTensor<2, dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename SymmetricTensor<2, dim, spacedim>::
+                    template solution_divergence_type<Number>> &divergences)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = divergences.size();
+
+      std::fill(divergences.begin(),
+                divergences.end(),
+                typename SymmetricTensor<2, dim, spacedim>::
+                  template solution_divergence_type<Number>());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+
+              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                &shape_gradients[snc][0];
+
+              const unsigned int ii = dealii::SymmetricTensor<2, spacedim>::
+                unrolled_to_component_indices(comp)[0];
+              const unsigned int jj = dealii::SymmetricTensor<2, spacedim>::
+                unrolled_to_component_indices(comp)[1];
+
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point, ++shape_gradient_ptr)
+                {
+                  divergences[q_point][ii] += value * (*shape_gradient_ptr)[jj];
+
+                  if (ii != jj)
+                    divergences[q_point][jj] +=
+                      value * (*shape_gradient_ptr)[ii];
+                }
+            }
+          else
+            {
+              for (unsigned int d = 0;
+                   d <
+                   dealii::SymmetricTensor<2,
+                                           spacedim>::n_independent_components;
+                   ++d)
+                if (shape_function_data[shape_function]
+                      .is_nonzero_shape_function_component[d])
+                  {
+                    Assert(false, ExcNotImplemented());
+
+                    // the following implementation needs to be looked over -- I
+                    // think it can't be right, because we are in a case where
+                    // there is no single nonzero component
+                    //
+                    // the following is not implemented! we need to consider the
+                    // interplay between multiple non-zero entries in shape
+                    // function and the representation as a symmetric
+                    // second-order tensor
+                    const unsigned int comp =
+                      shape_function_data[shape_function]
+                        .single_nonzero_component_index;
+
+                    const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                      &shape_gradients[shape_function_data[shape_function]
+                                         .row_index[d]][0];
+                    for (unsigned int q_point = 0;
+                         q_point < n_quadrature_points;
+                         ++q_point, ++shape_gradient_ptr)
+                      {
+                        for (unsigned int j = 0; j < spacedim; ++j)
+                          {
+                            const unsigned int vector_component =
+                              dealii::SymmetricTensor<2, spacedim>::
+                                component_to_unrolled_index(
+                                  TableIndices<2>(comp, j));
+                            divergences[q_point][vector_component] +=
+                              value * (*shape_gradient_ptr++)[j];
+                          }
+                      }
+                  }
+            }
+        }
+    }
+
+    // ---------------------- non-symmetric tensor part ------------------------
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_values(
+      const ArrayView<Number> &       dof_values,
+      const dealii::Table<2, double> &shape_values,
+      const std::vector<typename Tensor<2, dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<
+        typename ProductType<Number, dealii::Tensor<2, spacedim>>::type>
+        &values)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = values.size();
+
+      std::fill(
+        values.begin(),
+        values.end(),
+        typename ProductType<Number, dealii::Tensor<2, spacedim>>::type());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+
+              const TableIndices<2> indices =
+                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
+                  comp);
+
+              const double *shape_value_ptr = &shape_values(snc, 0);
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point)
+                values[q_point][indices] += value * (*shape_value_ptr++);
+            }
+          else
+            for (unsigned int d = 0; d < dim * dim; ++d)
+              if (shape_function_data[shape_function]
+                    .is_nonzero_shape_function_component[d])
+                {
+                  const TableIndices<2> indices =
+                    dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
+                      d);
+
+                  const double *shape_value_ptr = &shape_values(
+                    shape_function_data[shape_function].row_index[d], 0);
+                  for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                       ++q_point)
+                    values[q_point][indices] += value * (*shape_value_ptr++);
+                }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_divergences(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
+      const std::vector<typename Tensor<2, dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename Tensor<2, dim, spacedim>::
+                    template solution_divergence_type<Number>> &divergences)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = divergences.size();
+
+      std::fill(
+        divergences.begin(),
+        divergences.end(),
+        typename Tensor<2, dim, spacedim>::template solution_divergence_type<
+          Number>());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+
+              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                &shape_gradients[snc][0];
+
+              const TableIndices<2> indices =
+                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
+                  comp);
+              const unsigned int ii = indices[0];
+              const unsigned int jj = indices[1];
+
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point, ++shape_gradient_ptr)
+                {
+                  divergences[q_point][ii] += value * (*shape_gradient_ptr)[jj];
+                }
+            }
+          else
+            {
+              for (unsigned int d = 0; d < dim * dim; ++d)
+                if (shape_function_data[shape_function]
+                      .is_nonzero_shape_function_component[d])
+                  {
+                    Assert(false, ExcNotImplemented());
+                  }
+            }
+        }
+    }
+
+
+
+    template <int dim, int spacedim, typename Number>
+    void
+    do_function_gradients(
+      const ArrayView<Number> &                    dof_values,
+      const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients,
+      const std::vector<typename Tensor<2, dim, spacedim>::ShapeFunctionData>
+        &shape_function_data,
+      std::vector<typename Tensor<2, dim, spacedim>::
+                    template solution_gradient_type<Number>> &gradients)
+    {
+      const unsigned int dofs_per_cell       = dof_values.size();
+      const unsigned int n_quadrature_points = gradients.size();
+
+      std::fill(
+        gradients.begin(),
+        gradients.end(),
+        typename Tensor<2, dim, spacedim>::template solution_gradient_type<
+          Number>());
+
+      for (unsigned int shape_function = 0; shape_function < dofs_per_cell;
+           ++shape_function)
+        {
+          const int snc =
+            shape_function_data[shape_function].single_nonzero_component;
+
+          if (snc == -2)
+            // shape function is zero for the selected components
+            continue;
+
+          const Number &value = dof_values[shape_function];
+          // For auto-differentiable numbers, the fact that a DoF value is zero
+          // does not imply that its derivatives are zero as well. So we
+          // can't filter by value for these number types.
+          if (dealii::internal::CheckForZero<Number>::value(value) == true)
+            continue;
+
+          if (snc != -1)
+            {
+              const unsigned int comp = shape_function_data[shape_function]
+                                          .single_nonzero_component_index;
+
+              const dealii::Tensor<1, spacedim> *shape_gradient_ptr =
+                &shape_gradients[snc][0];
+
+              const TableIndices<2> indices =
+                dealii::Tensor<2, spacedim>::unrolled_to_component_indices(
+                  comp);
+              const unsigned int ii = indices[0];
+              const unsigned int jj = indices[1];
+
+              for (unsigned int q_point = 0; q_point < n_quadrature_points;
+                   ++q_point, ++shape_gradient_ptr)
+                {
+                  gradients[q_point][ii][jj] += value * (*shape_gradient_ptr);
+                }
+            }
+          else
+            {
+              for (unsigned int d = 0; d < dim * dim; ++d)
+                if (shape_function_data[shape_function]
+                      .is_nonzero_shape_function_component[d])
+                  {
+                    Assert(false, ExcNotImplemented());
+                  }
+            }
+        }
+    }
+
+  } // end of namespace internal
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Scalar<dim, spacedim>::get_function_values(
+    const ReadVector<Number> &                fe_function,
+    std::vector<solution_value_type<Number>> &values) const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+
+    // get function values of dofs on this cell and call internal worker
+    // function
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Scalar<dim, spacedim>::get_function_values_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_value_type<typename InputVector::value_type>> &values)
+    const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Scalar<dim, spacedim>::get_function_gradients(
+    const ReadVector<Number> &                   fe_function,
+    std::vector<solution_gradient_type<Number>> &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_derivatives<1, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename InputVector>
+  void
+  Scalar<dim, spacedim>::get_function_gradients_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_gradient_type<typename InputVector::value_type>>
+      &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_derivatives<1, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Scalar<dim, spacedim>::get_function_hessians(
+    const ReadVector<Number> &                  fe_function,
+    std::vector<solution_hessian_type<Number>> &hessians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_derivatives<2, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      hessians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Scalar<dim, spacedim>::get_function_hessians_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_hessian_type<typename InputVector::value_type>>
+      &hessians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_derivatives<2, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      hessians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Scalar<dim, spacedim>::get_function_laplacians(
+    const ReadVector<Number> &                    fe_function,
+    std::vector<solution_laplacian_type<Number>> &laplacians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_laplacians<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      laplacians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Scalar<dim, spacedim>::get_function_laplacians_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_laplacian_type<typename InputVector::value_type>>
+      &laplacians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_laplacians<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      laplacians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Scalar<dim, spacedim>::get_function_third_derivatives(
+    const ReadVector<Number> &                           fe_function,
+    std::vector<solution_third_derivative_type<Number>> &third_derivatives)
+    const
+  {
+    Assert(fe_values->update_flags & update_3rd_derivatives,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_3rd_derivatives")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_derivatives<3, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_3rd_derivatives,
+      shape_function_data,
+      third_derivatives);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Scalar<dim, spacedim>::get_function_third_derivatives_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<
+      solution_third_derivative_type<typename InputVector::value_type>>
+      &third_derivatives) const
+  {
+    Assert(fe_values->update_flags & update_3rd_derivatives,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_3rd_derivatives")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_derivatives<3, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_3rd_derivatives,
+      shape_function_data,
+      third_derivatives);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_values(
+    const ReadVector<Number> &                fe_function,
+    std::vector<solution_value_type<Number>> &values) const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_values_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_value_type<typename InputVector::value_type>> &values)
+    const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_gradients(
+    const ReadVector<Number> &                   fe_function,
+    std::vector<solution_gradient_type<Number>> &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_derivatives<1, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename InputVector>
+  void
+  Vector<dim, spacedim>::get_function_gradients_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_gradient_type<typename InputVector::value_type>>
+      &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_derivatives<1, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_symmetric_gradients(
+    const ReadVector<Number> &                             fe_function,
+    std::vector<solution_symmetric_gradient_type<Number>> &symmetric_gradients)
+    const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_symmetric_gradients<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      symmetric_gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_symmetric_gradients_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<
+      solution_symmetric_gradient_type<typename InputVector::value_type>>
+      &symmetric_gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_symmetric_gradients<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      symmetric_gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_divergences(
+    const ReadVector<Number> &                     fe_function,
+    std::vector<solution_divergence_type<Number>> &divergences) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs
+    // on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_divergences<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      divergences);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_divergences_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_divergence_type<typename InputVector::value_type>>
+      &divergences) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_divergences<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      divergences);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_curls(
+    const ReadVector<Number> &               fe_function,
+    std::vector<solution_curl_type<Number>> &curls) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           ExcMessage("FEValues object is not reinited to any cell"));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_curls<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      curls);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_curls_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_curl_type<typename InputVector::value_type>> &curls)
+    const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           ExcMessage("FEValues object is not reinited to any cell"));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_curls<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      curls);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_hessians(
+    const ReadVector<Number> &                  fe_function,
+    std::vector<solution_hessian_type<Number>> &hessians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_derivatives<2, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      hessians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_hessians_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_hessian_type<typename InputVector::value_type>>
+      &hessians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_derivatives<2, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      hessians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_laplacians(
+    const ReadVector<Number> &                fe_function,
+    std::vector<solution_value_type<Number>> &laplacians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(laplacians.size() == fe_values->n_quadrature_points,
+           ExcDimensionMismatch(laplacians.size(),
+                                fe_values->n_quadrature_points));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    Assert(
+      fe_function.size() == fe_values->present_cell.n_dofs_for_dof_handler(),
+      ExcDimensionMismatch(fe_function.size(),
+                           fe_values->present_cell.n_dofs_for_dof_handler()));
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_laplacians<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      laplacians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_laplacians_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_laplacian_type<typename InputVector::value_type>>
+      &laplacians) const
+  {
+    Assert(fe_values->update_flags & update_hessians,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_hessians")));
+    Assert(laplacians.size() == fe_values->n_quadrature_points,
+           ExcDimensionMismatch(laplacians.size(),
+                                fe_values->n_quadrature_points));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_laplacians<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_hessians,
+      shape_function_data,
+      laplacians);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Vector<dim, spacedim>::get_function_third_derivatives(
+    const ReadVector<Number> &                           fe_function,
+    std::vector<solution_third_derivative_type<Number>> &third_derivatives)
+    const
+  {
+    Assert(fe_values->update_flags & update_3rd_derivatives,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_3rd_derivatives")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_derivatives<3, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_3rd_derivatives,
+      shape_function_data,
+      third_derivatives);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Vector<dim, spacedim>::get_function_third_derivatives_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<
+      solution_third_derivative_type<typename InputVector::value_type>>
+      &third_derivatives) const
+  {
+    Assert(fe_values->update_flags & update_3rd_derivatives,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_3rd_derivatives")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_derivatives<3, dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_3rd_derivatives,
+      shape_function_data,
+      third_derivatives);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  SymmetricTensor<2, dim, spacedim>::get_function_values(
+    const ReadVector<Number> &                fe_function,
+    std::vector<solution_value_type<Number>> &values) const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  SymmetricTensor<2, dim, spacedim>::get_function_values_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_value_type<typename InputVector::value_type>> &values)
+    const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  SymmetricTensor<2, dim, spacedim>::get_function_divergences(
+    const ReadVector<Number> &                     fe_function,
+    std::vector<solution_divergence_type<Number>> &divergences) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs
+    // on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_divergences<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      divergences);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  SymmetricTensor<2, dim, spacedim>::
+    get_function_divergences_from_local_dof_values(
+      const InputVector &dof_values,
+      std::vector<solution_divergence_type<typename InputVector::value_type>>
+        &divergences) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_divergences<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      divergences);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Tensor<2, dim, spacedim>::get_function_values(
+    const ReadVector<Number> &                fe_function,
+    std::vector<solution_value_type<Number>> &values) const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+
+    // get function values of dofs on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Tensor<2, dim, spacedim>::get_function_values_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_value_type<typename InputVector::value_type>> &values)
+    const
+  {
+    Assert(fe_values->update_flags & update_values,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_values")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_values<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_values,
+      shape_function_data,
+      values);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Tensor<2, dim, spacedim>::get_function_divergences(
+    const ReadVector<Number> &                     fe_function,
+    std::vector<solution_divergence_type<Number>> &divergences) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs
+    // on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_divergences<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      divergences);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Tensor<2, dim, spacedim>::get_function_divergences_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_divergence_type<typename InputVector::value_type>>
+      &divergences) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_divergences<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      divergences);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <typename Number>
+  void
+  Tensor<2, dim, spacedim>::get_function_gradients(
+    const ReadVector<Number> &                   fe_function,
+    std::vector<solution_gradient_type<Number>> &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(fe_function.size(),
+                    fe_values->present_cell.n_dofs_for_dof_handler());
+
+    // get function values of dofs
+    // on this cell
+    dealii::Vector<Number> dof_values(fe_values->dofs_per_cell);
+    fe_values->present_cell.get_interpolated_dof_values(fe_function,
+                                                        dof_values);
+    internal::do_function_gradients<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      gradients);
+  }
+
+
+
+  template <int dim, int spacedim>
+  template <class InputVector>
+  void
+  Tensor<2, dim, spacedim>::get_function_gradients_from_local_dof_values(
+    const InputVector &dof_values,
+    std::vector<solution_gradient_type<typename InputVector::value_type>>
+      &gradients) const
+  {
+    Assert(fe_values->update_flags & update_gradients,
+           (typename FEValuesBase<dim, spacedim>::ExcAccessToUninitializedField(
+             "update_gradients")));
+    Assert(fe_values->present_cell.is_initialized(),
+           (typename FEValuesBase<dim, spacedim>::ExcNotReinited()));
+    AssertDimension(dof_values.size(), fe_values->dofs_per_cell);
+
+    internal::do_function_gradients<dim, spacedim>(
+      make_array_view(dof_values.begin(), dof_values.end()),
+      fe_values->finite_element_output.shape_gradients,
+      shape_function_data,
+      gradients);
+  }
+} // namespace FEValuesViews
+
+
+namespace internal
+{
+  namespace FEValuesViews
+  {
+    template <int dim, int spacedim>
+    Cache<dim, spacedim>::Cache(const FEValuesBase<dim, spacedim> &fe_values)
+    {
+      const FiniteElement<dim, spacedim> &fe = fe_values.get_fe();
+
+      const unsigned int n_scalars = fe.n_components();
+      scalars.reserve(n_scalars);
+      for (unsigned int component = 0; component < n_scalars; ++component)
+        scalars.emplace_back(fe_values, component);
+
+      // compute number of vectors that we can fit into this finite element.
+      // note that this is based on the dimensionality 'dim' of the manifold,
+      // not 'spacedim' of the output vector
+      const unsigned int n_vectors =
+        (fe.n_components() >= Tensor<1, spacedim>::n_independent_components ?
+           fe.n_components() - Tensor<1, spacedim>::n_independent_components +
+             1 :
+           0);
+      vectors.reserve(n_vectors);
+      for (unsigned int component = 0; component < n_vectors; ++component)
+        vectors.emplace_back(fe_values, component);
+
+      // compute number of symmetric tensors in the same way as above
+      const unsigned int n_symmetric_second_order_tensors =
+        (fe.n_components() >=
+             SymmetricTensor<2, spacedim>::n_independent_components ?
+           fe.n_components() -
+             SymmetricTensor<2, spacedim>::n_independent_components + 1 :
+           0);
+      symmetric_second_order_tensors.reserve(n_symmetric_second_order_tensors);
+      for (unsigned int component = 0;
+           component < n_symmetric_second_order_tensors;
+           ++component)
+        symmetric_second_order_tensors.emplace_back(fe_values, component);
+
+
+      // compute number of symmetric tensors in the same way as above
+      const unsigned int n_second_order_tensors =
+        (fe.n_components() >= Tensor<2, spacedim>::n_independent_components ?
+           fe.n_components() - Tensor<2, spacedim>::n_independent_components +
+             1 :
+           0);
+      second_order_tensors.reserve(n_second_order_tensors);
+      for (unsigned int component = 0; component < n_second_order_tensors;
+           ++component)
+        second_order_tensors.emplace_back(fe_values, component);
+    }
+  } // namespace FEValuesViews
+} // namespace internal
+
+/*------------------------------- Explicit Instantiations -------------*/
+
+#include "fe_values_views.inst"
+
+DEAL_II_NAMESPACE_CLOSE
diff --git a/source/fe/fe_values_views.inst.in b/source/fe/fe_values_views.inst.in
new file mode 100644 (file)
index 0000000..3d7f707
--- /dev/null
@@ -0,0 +1,293 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2022 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 DOXYGEN
+
+for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    namespace FEValuesViews
+    \{
+      template class Scalar<deal_II_dimension, deal_II_space_dimension>;
+      template class Vector<deal_II_dimension, deal_II_space_dimension>;
+      template class SymmetricTensor<2,
+                                     deal_II_dimension,
+                                     deal_II_space_dimension>;
+      template class Tensor<2, deal_II_dimension, deal_II_space_dimension>;
+    \}
+
+    namespace internal
+    \{
+      namespace FEValuesViews
+      \{
+        template struct Cache<deal_II_dimension, deal_II_space_dimension>;
+      \}
+    \}
+#  endif
+  }
+
+for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
+     deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(const dealii::ReadVector<S> &,
+                             std::vector<ProductType<S, value_type>::type> &)
+        const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
+        const;
+
+    template void FEValuesViews::SymmetricTensor<2,
+                                                 deal_II_dimension,
+                                                 deal_II_space_dimension>::
+      get_function_values<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<ProductType<
+          S,
+          dealii::SymmetricTensor<2, deal_II_space_dimension>>::type> &) const;
+
+    template void
+    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
+      get_function_values<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<2, deal_II_space_dimension>>::type> &)
+        const;
+
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
+        const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<2, deal_II_space_dimension>>::type> &)
+        const;
+
+    template void
+    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients<S>(
+        const ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<3, deal_II_space_dimension>>::type> &)
+        const;
+#  endif
+  }
+
+
+
+for (S : REAL_AND_COMPLEX_SCALARS; deal_II_dimension : DIMENSIONS;
+     deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<2, deal_II_space_dimension>>::type> &)
+        const;
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(const dealii::ReadVector<S> &,
+                                 std::vector<ProductType<S, double>::type> &)
+        const;
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<3, deal_II_space_dimension>>::type> &)
+        const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_symmetric_gradients<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<ProductType<
+          S,
+          dealii::SymmetricTensor<2, deal_II_space_dimension>>::type> &) const;
+    template void FEValuesViews::
+      Vector<deal_II_dimension, deal_II_space_dimension>::get_function_curls<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<ProductType<S, curl_type>::type> &) const;
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_divergences<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<ProductType<S, divergence_type>::type> &) const;
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<3, deal_II_space_dimension>>::type> &)
+        const;
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
+        const;
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<4, deal_II_space_dimension>>::type> &)
+        const;
+
+    template void FEValuesViews::
+      SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>::
+        get_function_divergences<S>(
+          const dealii::ReadVector<S> &,
+          std::vector<
+            ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
+          const;
+
+    template void
+    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
+      get_function_divergences<S>(
+        const dealii::ReadVector<S> &,
+        std::vector<
+          ProductType<S, dealii::Tensor<1, deal_II_space_dimension>>::type> &)
+        const;
+#  endif
+  }
+
+
+for (VEC : GENERAL_CONTAINER_TYPES; Number : ALL_SCALAR_TYPES;
+     deal_II_dimension : DIMENSIONS;
+     deal_II_space_dimension : SPACE_DIMENSIONS)
+  {
+#  if deal_II_dimension <= deal_II_space_dimension
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_gradient_type<Number>> &)
+        const;
+
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_hessian_type<Number>> &)
+        const;
+
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Scalar<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &,
+        std::vector<solution_third_derivative_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_values_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_gradient_type<Number>> &)
+        const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_symmetric_gradients_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &,
+        std::vector<solution_symmetric_gradient_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_divergences_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_divergence_type<Number>> &)
+        const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_curls_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_curl_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_hessians_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_hessian_type<Number>> &)
+        const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_laplacians_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Vector<deal_II_dimension, deal_II_space_dimension>::
+      get_function_third_derivatives_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &,
+        std::vector<solution_third_derivative_type<Number>> &) const;
+
+    template void FEValuesViews::SymmetricTensor<2,
+                                                 deal_II_dimension,
+                                                 deal_II_space_dimension>::
+      get_function_values_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
+
+    template void FEValuesViews::
+      SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>::
+        get_function_divergences_from_local_dof_values<VEC<Number>>(
+          const VEC<Number> &, std::vector<solution_divergence_type<Number>> &)
+          const;
+
+    template void
+    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
+      get_function_values_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_value_type<Number>> &) const;
+
+    template void
+    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
+      get_function_divergences_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_divergence_type<Number>> &)
+        const;
+
+    template void
+    FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>::
+      get_function_gradients_from_local_dof_values<VEC<Number>>(
+        const VEC<Number> &, std::vector<solution_gradient_type<Number>> &)
+        const;
+#  endif
+  }
+#endif

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.