From: David Wells Date: Mon, 10 Jul 2023 19:03:56 +0000 (-0400) Subject: Split fe_values.h and fe_values.cc into three files each. X-Git-Tag: relicensing~622^2 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F15829%2Fhead;p=dealii.git Split fe_values.h and fe_values.cc into three files each. 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. --- diff --git a/include/deal.II/fe/fe_values.h b/include/deal.II/fe/fe_values.h index 4e93cb514c..60ebb50faa 100644 --- a/include/deal.II/fe/fe_values.h +++ b/include/deal.II/fe/fe_values.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -47,5899 +48,617 @@ #include #include - -// dummy include in order to have the -// definition of PetscScalar available -// without including other PETSc stuff -#ifdef DEAL_II_WITH_PETSC -# include -#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 -class FEValuesBase; -#endif - -namespace internal +class FEValues : public FEValuesBase { +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 dim. */ - template - 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 - struct CurlType<1, NumberType> - { - using type = Tensor<1, 1, NumberType>; - }; + FEValues(const Mapping & mapping, + const FiniteElement &fe, + const Quadrature & 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 - struct CurlType<2, NumberType> - { - using type = Tensor<1, 1, NumberType>; - }; + FEValues(const Mapping & mapping, + const FiniteElement &fe, + const hp::QCollection & 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 - struct CurlType<3, NumberType> - { - using type = Tensor<1, 3, NumberType>; - }; -} // namespace internal - - + FEValues(const FiniteElement &fe, + const Quadrature & 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 all 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 dim elements, and symmetric second - * order tensor components consisting of (dim*dim + dim)/2 - * 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 - 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 - * Tensor@<1,dim@>. - */ - 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 Tensor@<2,dim@>. - */ - 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 Tensor@<3,dim@>. - */ - 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 - using solution_value_type = typename ProductType::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 - using solution_gradient_type = - typename ProductType::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 - using solution_laplacian_type = - typename ProductType::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 - using solution_hessian_type = - typename ProductType::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 - using solution_third_derivative_type = - typename ProductType::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 &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 &) = delete; - - /** - * Move constructor. - */ - // NOLINTNEXTLINE OSX does not compile with noexcept - Scalar(Scalar &&) = 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 &) = delete; - - /** - * Move assignment operator. - */ - Scalar & - operator=(Scalar &&) 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 fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_values(const ReadVector & fe_function, - std::vector> &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 - void - get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &values) const; - - /** - * Return the gradients of the selected scalar component of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_gradients( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &gradients) const; - - /** - * Return the Hessians of the selected scalar component of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_hessians( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_hessians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &hessians) const; + FEValues(const FiniteElement &fe, + const hp::QCollection & 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 + void + reinit( + const TriaIterator> &cell); - /** - * Return the Laplacians of the selected scalar component of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_laplacians( - const ReadVector & fe_function, - std::vector> &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 + * get_function_value/gradients/hessians/laplacians/third_derivatives + * 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::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 - void - get_function_laplacians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &laplacians) const; + /** + * Return a reference to the copy of the quadrature formula stored by this + * object. + */ + const Quadrature & + 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 fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_third_derivatives( - const ReadVector & fe_function, - std::vector> &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 & + 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 - void - get_function_third_derivatives_from_local_dof_values( - const InputVector &dof_values, - std::vector< - solution_third_derivative_type> - &third_derivatives) const; +private: + /** + * Store a copy of the quadrature formula here. + */ + const Quadrature 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> 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 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 +class FEFaceValuesBase : public FEValuesBase +{ +public: + /** + * Dimension of the object over which we integrate. For the present class, + * this is equal to dim-1. + */ + 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 2*dim, while for the FESubfaceValues class it + * is 2*dim*(1<<(dim-1)), 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 & mapping, + const FiniteElement &fe, + const Quadrature & 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 & mapping, + const FiniteElement &fe, + const hp::QCollection & quadrature); /** - * A class representing a view to a set of spacedim 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 spacedim 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 q_pointth + * 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 - class Vector - { - public: - /** - * An alias for the data type of values of the view this class - * represents. Since we deal with a set of dim components, - * the value type is a Tensor<1,spacedim>. - */ - using value_type = dealii::Tensor<1, spacedim>; + const std::vector> & + get_boundary_forms() const; - /** - * An alias for the type of gradients of the view this class represents. - * Here, for a set of dim components of the finite element, - * the gradient is a Tensor@<2,spacedim@>. - * - * 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 dim components of the - * finite element, the symmetrized gradient is a - * SymmetricTensor@<2,spacedim@>. - * - * 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 dim 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 & + get_quadrature() const; - /** - * An alias for the type of the curl of the view this class represents. - * Here, for a set of spacedim=2 components of the finite - * element, the curl is a Tensor@<1, 1@>. For - * spacedim=3 it is a Tensor@<1, dim@>. - */ - using curl_type = typename dealii::internal::CurlType::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 dim components of the - * finite element, the Hessian is a Tensor@<3,dim@>. - */ - 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 dim components of the - * finite element, the third derivative is a Tensor@<4,dim@>. - */ - 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 - using solution_value_type = typename ProductType::type; + /** + * Store a copy of the quadrature formula here. + */ + const hp::QCollection 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 - using solution_gradient_type = - typename ProductType::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 - using solution_symmetric_gradient_type = - typename ProductType::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 - using solution_divergence_type = - typename ProductType::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 - using solution_laplacian_type = - typename ProductType::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 - using solution_curl_type = typename ProductType::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 - using solution_hessian_type = - typename ProductType::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 - using solution_third_derivative_type = - typename ProductType::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 &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 &) = delete; - - /** - * Move constructor. - */ - // NOLINTNEXTLINE OSX does not compile with noexcept - Vector(Vector &&) = 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 &) = delete; - - /** - * Move assignment operator. - */ - // NOLINTNEXTLINE OSX does not compile with noexcept - Vector & - operator=(Vector &&) = 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 dim components, the return type is a tensor of - * rank 1 with dim 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 - * dim 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 spacedim=1. 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 fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_values(const ReadVector & fe_function, - std::vector> &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 - void - get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &values) const; - - /** - * Return the gradients of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_gradients( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &gradients) const; - - /** - * Return the symmetrized gradients of the selected vector components of - * the finite element function characterized by fe_function at - * the quadrature points of the cell, face or subface selected the last - * time the reinit 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 - void - get_function_symmetric_gradients( - const ReadVector &fe_function, - std::vector> - &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 - void - get_function_symmetric_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector< - solution_symmetric_gradient_type> - &symmetric_gradients) const; - - /** - * Return the divergence of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_divergences( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_divergences_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &divergences) const; - - /** - * Return the curl of the selected vector components of the finite element - * function characterized by fe_function at the quadrature points - * of the cell, face or subface selected the last time the reinit - * 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 - void - get_function_curls(const ReadVector & fe_function, - std::vector> &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 - void - get_function_curls_from_local_dof_values( - const InputVector &dof_values, - std::vector> &curls) - const; - - /** - * Return the Hessians of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_hessians( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_hessians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &hessians) const; - - /** - * Return the Laplacians of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_laplacians( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_laplacians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &laplacians) const; - - /** - * Return the third derivatives of the selected scalar component of the - * finite element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_third_derivatives( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_third_derivatives_from_local_dof_values( - const InputVector &dof_values, - std::vector< - solution_third_derivative_type> - &third_derivatives) const; - - private: - /** - * A pointer to the FEValuesBase object we operate on. - */ - const SmartPointer> 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 shape_function_data; - }; - - - template - class SymmetricTensor; - - /** - * A class representing a view to a set of (dim*dim + dim)/2 - * 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 - 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 (dim*dim + dim)/2 - * 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 (dim*dim + dim)/2 unique - * components of the finite element representing a symmetric second-order - * tensor, the divergence of course is a * Tensor@<1,dim@>. - * - * 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 - using solution_value_type = typename ProductType::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 - using solution_divergence_type = - typename ProductType::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 (dim*dim + - * dim)/2 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 &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 (dim*dim + dim)/2 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 fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_values(const ReadVector & fe_function, - std::vector> &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 - void - get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &values) const; - - /** - * Return the divergence of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_divergences( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_divergences_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &divergences) const; - - private: - /** - * A pointer to the FEValuesBase object we operate on. - */ - const SmartPointer> 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 shape_function_data; - }; - - - template - class Tensor; - - /** - * A class representing a view to a set of dim*dim 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 - 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 - using solution_value_type = typename ProductType::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 - using solution_divergence_type = - typename ProductType::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 - using solution_gradient_type = - typename ProductType::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 (dim*dim) - * 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 &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 (dim*dim) 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 fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_values(const ReadVector & fe_function, - std::vector> &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 - void - get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &values) const; - - /** - * Return the divergence of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_divergences( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_divergences_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &divergences) const; - - /** - * Return the gradient of the selected vector components of the finite - * element function characterized by fe_function at the - * quadrature points of the cell, face or subface selected the last time - * the reinit 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 - void - get_function_gradients( - const ReadVector & fe_function, - std::vector> &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 - void - get_function_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &gradients) const; - - private: - /** - * A pointer to the FEValuesBase object we operate on. - */ - const SmartPointer> 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 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 - 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. - */ - template - struct ViewType - { - using type = typename dealii::FEValuesViews::Scalar; - }; - - /** - * 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. - */ - template - struct ViewType - { - using type = typename dealii::FEValuesViews::Vector; - }; - - /** - * A class whose specialization is used to define what FEValuesViews - * object corresponds to the given FEValuesExtractors object. - * - * When using FEValuesExtractors::Tensor, the corresponding view is an - * FEValuesViews::Tensor. - */ - template - struct ViewType> - { - using type = typename dealii::FEValuesViews::Tensor; - }; - - /** - * A class whose specialization is used to define what FEValuesViews - * object corresponds to the given FEValuesExtractors object. - * - * When using FEValuesExtractors::SymmetricTensor, the corresponding - * view is an FEValuesViews::SymmetricTensor. - */ - template - struct ViewType> - { - using type = - typename dealii::FEValuesViews::SymmetricTensor; - }; - - /** - * 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 - struct Cache - { - /** - * Caches for scalar and vector, and symmetric second-order tensor - * valued views. - */ - std::vector> scalars; - std::vector> vectors; - std::vector> - symmetric_second_order_tensors; - std::vector> - second_order_tensors; - - /** - * Constructor. - */ - Cache(const FEValuesBase &fe_values); - }; - } // namespace FEValuesViews -} // namespace internal - -namespace FEValuesViews -{ - /** - * A templated alias that associates to a given Extractor class - * the corresponding view in FEValuesViews. - */ - template - using View = typename dealii::internal::FEValuesViews:: - ViewType::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 get_*_data and fill_*_values which are - * called by the constructor and reinit functions of - * FEValues*, respectively. - * - *

General usage

- * - * Usually, an object of FEValues* 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; qMember functions - * - * The functions of this class fall into different categories: - *
    - *
  • 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. - * - *
  • 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. - * - *
  • get_function_values(), get_function_gradients(), etc.: Compute a - * finite element function or its derivative in quadrature points. - * - *
  • 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. - *
- * - * - *

Internals about the implementation

+ * 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 -class FEValuesBase : public Subscriptor +template +class FEFaceValues : public FEFaceValuesBase { 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 dim-1. */ - const unsigned int dofs_per_cell; - + static constexpr unsigned int integral_dimension = dim - 1; /** - * Constructor. Set up the array sizes with n_q_points quadrature - * points, dofs_per_cell trial functions per cell and with the - * given pattern to update the fields when the reinit 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 & mapping, - const FiniteElement &fe); + FEFaceValues(const Mapping & mapping, + const FiniteElement &fe, + const Quadrature & 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 & mapping, + const FiniteElement &fe, + const hp::QCollection & 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 &fe, + const Quadrature & 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 &fe, + const hp::QCollection & 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 reinit 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 + void + reinit( + const TriaIterator> &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 + void + reinit( + const TriaIterator> &cell, + const typename Triangulation::face_iterator & face); /** - * Compute the gradient of the ith shape function at the - * quadrature_pointth 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 + * get_function_value/gradients/hessians/third_derivatives + * 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::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 + * get_function_value/gradients/hessians/third_derivatives + * 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::cell_iterator &cell, + const typename Triangulation::face_iterator &face); /** - * Second derivatives of the ith shape function at the - * q_pointth 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 ith shape function at the - * q_pointth 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 values[q] will contain the value of the field - * described by fe_function at the $q$th quadrature point. - * - * @dealiiRequiresUpdateFlags{update_values} - */ - template - void - get_function_values(const ReadVector &fe_function, - std::vector & 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 values[q] 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 values[q] equals the number of components of the - * finite element, i.e. values[q](c) returns the value of the - * $c$th vector component at the $q$th quadrature point. - * - * @dealiiRequiresUpdateFlags{update_values} - */ - template - void - get_function_values(const ReadVector & fe_function, - std::vector> &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 - void - get_function_values(const ReadVector &fe_function, - const ArrayView &indices, - std::vector &values) const; + const FEFaceValues & + 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 void - get_function_values(const ReadVector &fe_function, - const ArrayView &indices, - std::vector> &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 value 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 - * values has either the length of the quadrature rule - * (quadrature_points_fastest == false) or the length of components - * to be filled quadrature_points_fastest == true. If p is - * the current quadrature point number and i is the vector - * component of the solution desired, the access to values is - * values[p][i] if quadrature_points_fastest == false, and - * values[i][p] 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 void - get_function_values(const ReadVector &fe_function, - const ArrayView &indices, - ArrayView> 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 +class FESubfaceValues : public FEFaceValuesBase +{ +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 gradients[q] will contain the gradient of the field - * described by fe_function at the $q$th quadrature point. - * gradients[q][d] 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<T>, BlockVector<T>, 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 - void - get_function_gradients( - const ReadVector & fe_function, - std::vector> &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 gradients[q] 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 gradients[q] equals the number of - * components of the finite element, i.e. gradients[q][c] - * returns the gradient of the $c$th vector component at the $q$th - * quadrature point. Consequently, gradients[q][c][d] 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 - void - get_function_gradients( - const ReadVector & fe_function, - std::vector>> &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 dim-1. */ - template - void - get_function_gradients( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 - void - get_function_gradients( - const ReadVector & fe_function, - const ArrayView & indices, - ArrayView>> 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 & mapping, + const FiniteElement &fe, + const Quadrature & 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 hessians[q] will contain the Hessian of the field - * described by fe_function at the $q$th quadrature point. - * hessians[q][i][j] 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<T>, BlockVector<T>, 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 - void - get_function_hessians( - const ReadVector & fe_function, - std::vector> &hessians) const; + FESubfaceValues(const Mapping & mapping, + const FiniteElement &fe, + const hp::QCollection & 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 hessians[q] 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 hessians[q] equals the number of - * components of the finite element, i.e. hessians[q][c] - * returns the Hessian of the $c$th vector component at the $q$th quadrature - * point. Consequently, hessians[q][c][i][j] 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 - void - get_function_hessians( - const ReadVector & fe_function, - std::vector>> &hessians, - const bool quadrature_points_fastest = false) const; + FESubfaceValues(const FiniteElement &fe, + const Quadrature & 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 - void - get_function_hessians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & hessians) const; + FESubfaceValues(const FiniteElement &fe, + const hp::QCollection & 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 + template void - get_function_hessians( - const ReadVector & fe_function, - const ArrayView & indices, - ArrayView>> hessians, - const bool quadrature_points_fastest = false) const; + reinit( + const TriaIterator> &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 laplacians[q] 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 - * laplacians[q]=trace(hessians[q]), where hessians - * would be the output of the get_function_hessians() function. - * - * @note The actual data type of the input vector may be either a - * Vector<T>, BlockVector<T>, 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 + template void - get_function_laplacians(const ReadVector &fe_function, - std::vector & laplacians) const; + reinit( + const TriaIterator> &cell, + const typename Triangulation::face_iterator & face, + const typename Triangulation::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 laplacians[q] 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 laplacians[q] equals the number of - * components of the finite element, i.e. laplacians[q][c] - * 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 - * laplacians[q][c]=trace(hessians[q][c]), where - * hessians 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 + * get_function_value/gradients/hessians/third_derivatives + * 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 void - get_function_laplacians(const ReadVector & fe_function, - std::vector> &laplacians) const; + reinit(const typename Triangulation::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 + * get_function_value/gradients/hessians/third_derivatives + * 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 - void - get_function_laplacians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector & 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 void - get_function_laplacians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & laplacians) const; + reinit(const typename Triangulation::cell_iterator &cell, + const typename Triangulation::face_iterator &face, + const typename Triangulation::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 - void - get_function_laplacians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & laplacians, - const bool quadrature_points_fastest = false) const; - - /** @} */ - /// @name Access to third derivatives of global finite element fields - /** @{ */ + const FESubfaceValues & + 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 third_derivatives[q] will contain the third - * derivatives of the field described by fe_function at the $q$th quadrature - * point. third_derivatives[q][i][j][k] 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<T>, BlockVector<T>, 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 - void - get_function_third_derivatives( - const ReadVector & fe_function, - std::vector> &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 third_derivatives[q] 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 third_derivatives[q] equals - * the number of components of the finite element, i.e. - * third_derivatives[q][c] returns the third derivative of the - * $c$th vector component at the $q$th quadrature point. Consequently, - * third_derivatives[q][c][i][j][k] 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 - void - get_function_third_derivatives( - const ReadVector & fe_function, - std::vector>> &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 void - get_function_third_derivatives( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 void - get_function_third_derivatives( - const ReadVector & fe_function, - const ArrayView & indices, - ArrayView>> 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 fe_values (...); - * FullMatrix 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 - 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 fe_values (...); - * FullMatrix 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 - 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 fe_values (...); - * FullMatrix 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 - 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 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 - quadrature_point_indices() const; - - /** - * Return the location of the q_pointth quadrature point in - * real space. - * - * @dealiiRequiresUpdateFlags{update_quadrature_points} - */ - const Point & - 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> & - 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 q_pointth 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 & - 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> & - 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> & - 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> & - 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> & - 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> & - 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> & - 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> & - 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> & - 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 q_pointth quadrature point of the face. - * - * In contrast, if you call this function for a cell of codimension one - * (i.e., when using a `FEValues` 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> & - 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 & - operator[](const FEValuesExtractors::Scalar &scalar) const; - - /** - * Create a view of the current FEValues object that represents a set of - * dim 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 & - operator[](const FEValuesExtractors::Vector &vector) const; - - /** - * Create a view of the current FEValues object that represents a set of - * (dim*dim + dim)/2 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 - * (dim*dim) 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 & - get_mapping() const; - - /** - * Constant reference to the selected finite element object. - */ - const FiniteElement & - 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::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 CellSimilarity::translation. - */ - 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::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::cell_iterator."); - - /** - * Constructor. - */ - CellIteratorContainer(); - - /** - * Constructor. - */ - template - CellIteratorContainer( - const TriaIterator> &cell); - - /** - * Constructor. - */ - CellIteratorContainer( - const typename Triangulation::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::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 - void - get_interpolated_dof_values(const ReadVector &in, - Vector & out) const; - - /** - * Call @p get_interpolated_dof_values of the iterator with the - * given arguments. - */ - void - get_interpolated_dof_values(const IndexSet & in, - Vector &out) const; - - private: - bool initialized; - typename Triangulation::cell_iterator cell; - const DoFHandler * dof_handler; - bool level_dof_access; - }; - - /** - * Store the cell selected last time the reinit() function was called. This - * is necessary for the get_function_* 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::cell_iterator &cell); - - /** - * A pointer to the mapping object associated with this FEValues object. - */ - const SmartPointer, FEValuesBase> - 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::InternalDataBase> - mapping_data; - - /** - * An object into which the Mapping::fill_fe_values() and similar functions - * place their output. - */ - internal::FEValuesImplementation::MappingRelatedData - mapping_output; - - /** - * A pointer to the finite element object associated with this FEValues - * object. - */ - const SmartPointer, - FEValuesBase> - 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::InternalDataBase> - fe_data; - - /** - * An object into which the FiniteElement::fill_fe_values() and similar - * functions place their output. - */ - dealii::internal::FEValuesImplementation::FiniteElementRelatedData - 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::cell_iterator &cell); - -private: - /** - * A cache for all possible FEValuesViews objects. - */ - dealii::internal::FEValuesViews::Cache fe_values_views_cache; - - // Make the view classes friends of this class, since they access internal - // data. - template - friend class FEValuesViews::Scalar; - template - friend class FEValuesViews::Vector; - template - friend class FEValuesViews::SymmetricTensor; - template - 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 -class FEValues : public FEValuesBase -{ -public: - /** - * Dimension of the object over which we integrate. For the present class, - * this is equal to dim. - */ - 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 & mapping, - const FiniteElement &fe, - const Quadrature & 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 & mapping, - const FiniteElement &fe, - const hp::QCollection & 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 &fe, - const Quadrature & 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 &fe, - const hp::QCollection & 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 - void - reinit( - const TriaIterator> &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 - * get_function_value/gradients/hessians/laplacians/third_derivatives - * 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::cell_iterator &cell); - - /** - * Return a reference to the copy of the quadrature formula stored by this - * object. - */ - const Quadrature & - 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 & - get_present_fe_values() const; - -private: - /** - * Store a copy of the quadrature formula here. - */ - const Quadrature 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 -class FEFaceValuesBase : public FEValuesBase -{ -public: - /** - * Dimension of the object over which we integrate. For the present class, - * this is equal to dim-1. - */ - 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 2*dim, while for the FESubfaceValues class it - * is 2*dim*(1<<(dim-1)), 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 & mapping, - const FiniteElement &fe, - const Quadrature & 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 & mapping, - const FiniteElement &fe, - const hp::QCollection & quadrature); - - /** - * Boundary form of the transformation of the cell at the q_pointth - * 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> & - 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 & - 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 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 -class FEFaceValues : public FEFaceValuesBase -{ -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 dim-1. - */ - 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 & mapping, - const FiniteElement &fe, - const Quadrature & 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 & mapping, - const FiniteElement &fe, - const hp::QCollection & 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 &fe, - const Quadrature & 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 &fe, - const hp::QCollection & 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 - void - reinit( - const TriaIterator> &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 - void - reinit( - const TriaIterator> &cell, - const typename Triangulation::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 - * get_function_value/gradients/hessians/third_derivatives - * 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::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 - * get_function_value/gradients/hessians/third_derivatives - * 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::cell_iterator &cell, - const typename Triangulation::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 & - 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 -class FESubfaceValues : public FEFaceValuesBase -{ -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 dim-1. - */ - 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 & mapping, - const FiniteElement &fe, - const Quadrature & 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 & mapping, - const FiniteElement &fe, - const hp::QCollection & 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 &fe, - const Quadrature & 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 &fe, - const hp::QCollection & 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 - void - reinit( - const TriaIterator> &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 - void - reinit( - const TriaIterator> &cell, - const typename Triangulation::face_iterator & face, - const typename Triangulation::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 - * get_function_value/gradients/hessians/third_derivatives - * 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::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 - * get_function_value/gradients/hessians/third_derivatives - * 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::cell_iterator &cell, - const typename Triangulation::face_iterator &face, - const typename Triangulation::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 & - 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 - inline typename Scalar::value_type - Scalar::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::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 - inline typename Scalar::gradient_type - Scalar::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::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 - inline typename Scalar::hessian_type - Scalar::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::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 - inline typename Scalar::third_derivative_type - Scalar::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::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 - inline typename Vector::value_type - Vector::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::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 - inline typename Vector::gradient_type - Vector::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::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 - inline typename Vector::divergence_type - Vector::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::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 - inline typename Vector::curl_type - Vector::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::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 - inline typename Vector::hessian_type - Vector::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::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 - inline typename Vector::third_derivative_type - Vector::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::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 - inline typename Vector::symmetric_gradient_type - Vector::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::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 - 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::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 - 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::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 - 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::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 - 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::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 - 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::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 -template -inline FEValuesBase::CellIteratorContainer:: - CellIteratorContainer( - const TriaIterator> &cell) - : initialized(true) - , cell(cell) - , dof_handler(&cell->get_dof_handler()) - , level_dof_access(lda) -{} - - - -template -inline const FEValuesViews::Scalar & -FEValuesBase::operator[]( - const FEValuesExtractors::Scalar &scalar) const -{ - AssertIndexRange(scalar.component, fe_values_views_cache.scalars.size()); - - return fe_values_views_cache.scalars[scalar.component]; -} - - - -template -inline const FEValuesViews::Vector & -FEValuesBase::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 -inline const FEValuesViews::SymmetricTensor<2, dim, spacedim> & -FEValuesBase::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 -inline const FEValuesViews::Tensor<2, dim, spacedim> & -FEValuesBase::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 -inline const double & -FEValuesBase::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 -inline double -FEValuesBase::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 -inline const Tensor<1, spacedim> & -FEValuesBase::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 -inline Tensor<1, spacedim> -FEValuesBase::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 -inline const Tensor<2, spacedim> & -FEValuesBase::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 -inline Tensor<2, spacedim> -FEValuesBase::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 -inline const Tensor<3, spacedim> & -FEValuesBase::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 -inline Tensor<3, spacedim> -FEValuesBase::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 -inline const FiniteElement & -FEValuesBase::get_fe() const -{ - return *fe; -} - - - -template -inline const Mapping & -FEValuesBase::get_mapping() const -{ - return *mapping; -} - - - -template -inline UpdateFlags -FEValuesBase::get_update_flags() const -{ - return this->update_flags; -} - - - -template -inline const std::vector> & -FEValuesBase::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 -inline const std::vector & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::get_jacobians() const -{ - Assert(this->update_flags & update_jacobians, - ExcAccessToUninitializedField("update_jacobians")); - Assert(present_cell.is_initialized(), ExcNotReinited()); - return this->mapping_output.jacobians; -} - - - -template -inline const std::vector> & -FEValuesBase::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 -inline const Tensor<3, spacedim> & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::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 -inline const DerivativeForm<3, dim, spacedim> & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::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 -inline const Tensor<4, spacedim> & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::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 -inline const DerivativeForm<4, dim, spacedim> & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::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 -inline const Tensor<5, spacedim> & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::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 -inline const std::vector> & -FEValuesBase::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 -inline std_cxx20::ranges::iota_view -FEValuesBase::dof_indices() const -{ - return {0U, dofs_per_cell}; -} - - - -template -inline std_cxx20::ranges::iota_view -FEValuesBase::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 -inline std_cxx20::ranges::iota_view -FEValuesBase::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 -inline std_cxx20::ranges::iota_view -FEValuesBase::quadrature_point_indices() const -{ - return {0U, n_quadrature_points}; -} - - - -template -inline const Point & -FEValuesBase::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 -inline double -FEValuesBase::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 -inline const DerivativeForm<1, dim, spacedim> & -FEValuesBase::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 -inline const DerivativeForm<2, dim, spacedim> & -FEValuesBase::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 -inline const DerivativeForm<1, spacedim, dim> & -FEValuesBase::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 -inline const Tensor<1, spacedim> & -FEValuesBase::normal_vector(const unsigned int q_point) const -{ - Assert(this->update_flags & update_normal_vectors, - (typename FEValuesBase::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 index 0000000000..82e593ee46 --- /dev/null +++ b/include/deal.II/fe/fe_values_base.h @@ -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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +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 get_*_data and fill_*_values which are + * called by the constructor and reinit functions of + * FEValues*, respectively. + * + *

General usage

+ * + * Usually, an object of FEValues* 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; qMember functions + * + * The functions of this class fall into different categories: + *
    + *
  • 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. + * + *
  • 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. + * + *
  • get_function_values(), get_function_gradients(), etc.: Compute a + * finite element function or its derivative in quadrature points. + * + *
  • 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. + *
+ * + * + *

Internals about the implementation

+ * + * 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 +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 n_q_points quadrature + * points, dofs_per_cell trial functions per cell and with the + * given pattern to update the fields when the reinit 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 & mapping, + const FiniteElement &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 reinit 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 ith shape function at the + * quadrature_pointth 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 ith shape function at the + * q_pointth 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 ith shape function at the + * q_pointth 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 values[q] will contain the value of the field + * described by fe_function at the $q$th quadrature point. + * + * @dealiiRequiresUpdateFlags{update_values} + */ + template + void + get_function_values(const ReadVector &fe_function, + std::vector & 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 values[q] 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 values[q] equals the number of components of the + * finite element, i.e. values[q](c) returns the value of the + * $c$th vector component at the $q$th quadrature point. + * + * @dealiiRequiresUpdateFlags{update_values} + */ + template + void + get_function_values(const ReadVector & fe_function, + std::vector> &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 + void + get_function_values(const ReadVector &fe_function, + const ArrayView &indices, + std::vector &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 + void + get_function_values(const ReadVector &fe_function, + const ArrayView &indices, + std::vector> &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 value 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 + * values has either the length of the quadrature rule + * (quadrature_points_fastest == false) or the length of components + * to be filled quadrature_points_fastest == true. If p is + * the current quadrature point number and i is the vector + * component of the solution desired, the access to values is + * values[p][i] if quadrature_points_fastest == false, and + * values[i][p] 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 + void + get_function_values(const ReadVector &fe_function, + const ArrayView &indices, + ArrayView> 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 gradients[q] will contain the gradient of the field + * described by fe_function at the $q$th quadrature point. + * gradients[q][d] 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<T>, BlockVector<T>, 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 + void + get_function_gradients( + const ReadVector & fe_function, + std::vector> &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 gradients[q] 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 gradients[q] equals the number of + * components of the finite element, i.e. gradients[q][c] + * returns the gradient of the $c$th vector component at the $q$th + * quadrature point. Consequently, gradients[q][c][d] 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 + void + get_function_gradients( + const ReadVector & fe_function, + std::vector>> &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 + void + get_function_gradients( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 + void + get_function_gradients( + const ReadVector & fe_function, + const ArrayView & indices, + ArrayView>> 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 hessians[q] will contain the Hessian of the field + * described by fe_function at the $q$th quadrature point. + * hessians[q][i][j] 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<T>, BlockVector<T>, 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 + void + get_function_hessians( + const ReadVector & fe_function, + std::vector> &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 hessians[q] 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 hessians[q] equals the number of + * components of the finite element, i.e. hessians[q][c] + * returns the Hessian of the $c$th vector component at the $q$th quadrature + * point. Consequently, hessians[q][c][i][j] 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 + void + get_function_hessians( + const ReadVector & fe_function, + std::vector>> &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 + void + get_function_hessians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 + void + get_function_hessians( + const ReadVector & fe_function, + const ArrayView & indices, + ArrayView>> 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 laplacians[q] 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 + * laplacians[q]=trace(hessians[q]), where hessians + * would be the output of the get_function_hessians() function. + * + * @note The actual data type of the input vector may be either a + * Vector<T>, BlockVector<T>, 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 + void + get_function_laplacians(const ReadVector &fe_function, + std::vector & 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 laplacians[q] 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 laplacians[q] equals the number of + * components of the finite element, i.e. laplacians[q][c] + * 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 + * laplacians[q][c]=trace(hessians[q][c]), where + * hessians would be the output of the get_function_hessians() + * function. + * + * @dealiiRequiresUpdateFlags{update_hessians} + */ + template + void + get_function_laplacians(const ReadVector & fe_function, + std::vector> &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 + void + get_function_laplacians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector & 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 + void + get_function_laplacians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 + void + get_function_laplacians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 third_derivatives[q] will contain the third + * derivatives of the field described by fe_function at the $q$th quadrature + * point. third_derivatives[q][i][j][k] 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<T>, BlockVector<T>, 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 + void + get_function_third_derivatives( + const ReadVector & fe_function, + std::vector> &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 third_derivatives[q] 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 third_derivatives[q] equals + * the number of components of the finite element, i.e. + * third_derivatives[q][c] returns the third derivative of the + * $c$th vector component at the $q$th quadrature point. Consequently, + * third_derivatives[q][c][i][j][k] 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 + void + get_function_third_derivatives( + const ReadVector & fe_function, + std::vector>> &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 + void + get_function_third_derivatives( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 + void + get_function_third_derivatives( + const ReadVector & fe_function, + const ArrayView & indices, + ArrayView>> 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 fe_values (...); + * FullMatrix 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 + 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 fe_values (...); + * FullMatrix 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 + 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 fe_values (...); + * FullMatrix 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 + 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 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 + quadrature_point_indices() const; + + /** + * Return the location of the q_pointth quadrature point in + * real space. + * + * @dealiiRequiresUpdateFlags{update_quadrature_points} + */ + const Point & + 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> & + 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 q_pointth 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 & + 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> & + 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> & + 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> & + 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> & + 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> & + 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> & + 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> & + 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> & + 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 q_pointth quadrature point of the face. + * + * In contrast, if you call this function for a cell of codimension one + * (i.e., when using a `FEValues` 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> & + 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 & + operator[](const FEValuesExtractors::Scalar &scalar) const; + + /** + * Create a view of the current FEValues object that represents a set of + * dim 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 & + operator[](const FEValuesExtractors::Vector &vector) const; + + /** + * Create a view of the current FEValues object that represents a set of + * (dim*dim + dim)/2 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 + * (dim*dim) 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 & + get_mapping() const; + + /** + * Constant reference to the selected finite element object. + */ + const FiniteElement & + 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::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 CellSimilarity::translation. + */ + 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::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::cell_iterator."); + + /** + * Constructor. + */ + CellIteratorContainer(); + + /** + * Constructor. + */ + template + CellIteratorContainer( + const TriaIterator> &cell); + + /** + * Constructor. + */ + CellIteratorContainer( + const typename Triangulation::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::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 + void + get_interpolated_dof_values(const ReadVector &in, + Vector & out) const; + + /** + * Call @p get_interpolated_dof_values of the iterator with the + * given arguments. + */ + void + get_interpolated_dof_values(const IndexSet & in, + Vector &out) const; + + private: + bool initialized; + typename Triangulation::cell_iterator cell; + const DoFHandler * dof_handler; + bool level_dof_access; + }; + + /** + * Store the cell selected last time the reinit() function was called. This + * is necessary for the get_function_* 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::cell_iterator &cell); + + /** + * A pointer to the mapping object associated with this FEValues object. + */ + const SmartPointer, FEValuesBase> + 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::InternalDataBase> + mapping_data; + + /** + * An object into which the Mapping::fill_fe_values() and similar functions + * place their output. + */ + internal::FEValuesImplementation::MappingRelatedData + mapping_output; + + /** + * A pointer to the finite element object associated with this FEValues + * object. + */ + const SmartPointer, + FEValuesBase> + 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::InternalDataBase> + fe_data; + + /** + * An object into which the FiniteElement::fill_fe_values() and similar + * functions place their output. + */ + dealii::internal::FEValuesImplementation::FiniteElementRelatedData + 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::cell_iterator &cell); + +private: + /** + * A cache for all possible FEValuesViews objects. + */ + dealii::internal::FEValuesViews::Cache fe_values_views_cache; + + // Make the view classes friends of this class, since they access internal + // data. + template + friend class FEValuesViews::Scalar; + template + friend class FEValuesViews::Vector; + template + friend class FEValuesViews::SymmetricTensor; + template + friend class FEValuesViews::Tensor; +}; + +#ifndef DOXYGEN + +/*---------------------- Inline functions: FEValuesBase ---------------------*/ + +template +template +inline FEValuesBase::CellIteratorContainer:: + CellIteratorContainer( + const TriaIterator> &cell) + : initialized(true) + , cell(cell) + , dof_handler(&cell->get_dof_handler()) + , level_dof_access(lda) +{} + + + +template +inline const FEValuesViews::Scalar & +FEValuesBase::operator[]( + const FEValuesExtractors::Scalar &scalar) const +{ + AssertIndexRange(scalar.component, fe_values_views_cache.scalars.size()); + + return fe_values_views_cache.scalars[scalar.component]; +} + + + +template +inline const FEValuesViews::Vector & +FEValuesBase::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 +inline const FEValuesViews::SymmetricTensor<2, dim, spacedim> & +FEValuesBase::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 +inline const FEValuesViews::Tensor<2, dim, spacedim> & +FEValuesBase::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 +inline const double & +FEValuesBase::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 +inline double +FEValuesBase::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 +inline const Tensor<1, spacedim> & +FEValuesBase::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 +inline Tensor<1, spacedim> +FEValuesBase::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 +inline const Tensor<2, spacedim> & +FEValuesBase::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 +inline Tensor<2, spacedim> +FEValuesBase::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 +inline const Tensor<3, spacedim> & +FEValuesBase::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 +inline Tensor<3, spacedim> +FEValuesBase::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 +inline const FiniteElement & +FEValuesBase::get_fe() const +{ + return *fe; +} + + + +template +inline const Mapping & +FEValuesBase::get_mapping() const +{ + return *mapping; +} + + + +template +inline UpdateFlags +FEValuesBase::get_update_flags() const +{ + return this->update_flags; +} + + + +template +inline const std::vector> & +FEValuesBase::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 +inline const std::vector & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::get_jacobians() const +{ + Assert(this->update_flags & update_jacobians, + ExcAccessToUninitializedField("update_jacobians")); + Assert(present_cell.is_initialized(), ExcNotReinited()); + return this->mapping_output.jacobians; +} + + + +template +inline const std::vector> & +FEValuesBase::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 +inline const Tensor<3, spacedim> & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::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 +inline const DerivativeForm<3, dim, spacedim> & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::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 +inline const Tensor<4, spacedim> & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::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 +inline const DerivativeForm<4, dim, spacedim> & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::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 +inline const Tensor<5, spacedim> & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::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 +inline const std::vector> & +FEValuesBase::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 +inline std_cxx20::ranges::iota_view +FEValuesBase::dof_indices() const +{ + return {0U, dofs_per_cell}; +} + + + +template +inline std_cxx20::ranges::iota_view +FEValuesBase::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 +inline std_cxx20::ranges::iota_view +FEValuesBase::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 +inline std_cxx20::ranges::iota_view +FEValuesBase::quadrature_point_indices() const +{ + return {0U, n_quadrature_points}; +} + + + +template +inline const Point & +FEValuesBase::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 +inline double +FEValuesBase::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 +inline const DerivativeForm<1, dim, spacedim> & +FEValuesBase::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 +inline const DerivativeForm<2, dim, spacedim> & +FEValuesBase::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 +inline const DerivativeForm<1, spacedim, dim> & +FEValuesBase::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 +inline const Tensor<1, spacedim> & +FEValuesBase::normal_vector(const unsigned int q_point) const +{ + Assert(this->update_flags & update_normal_vectors, + (typename FEValuesBase::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 index 0000000000..5c03c9d153 --- /dev/null +++ b/include/deal.II/fe/fe_values_views.h @@ -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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + +// Forward declaration +#ifndef DOXYGEN +template +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 + 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 + 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 + 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 + 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 all 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 dim elements, and symmetric second + * order tensor components consisting of (dim*dim + dim)/2 + * 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 + 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 + * Tensor@<1,dim@>. + */ + 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 Tensor@<2,dim@>. + */ + 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 Tensor@<3,dim@>. + */ + 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 + using solution_value_type = typename ProductType::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 + using solution_gradient_type = + typename ProductType::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 + using solution_laplacian_type = + typename ProductType::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 + using solution_hessian_type = + typename ProductType::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 + using solution_third_derivative_type = + typename ProductType::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 &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 &) = delete; + + /** + * Move constructor. + */ + // NOLINTNEXTLINE OSX does not compile with noexcept + Scalar(Scalar &&) = 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 &) = delete; + + /** + * Move assignment operator. + */ + Scalar & + operator=(Scalar &&) 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 fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_values(const ReadVector & fe_function, + std::vector> &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 + void + get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &values) const; + + /** + * Return the gradients of the selected scalar component of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_gradients( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &gradients) const; + + /** + * Return the Hessians of the selected scalar component of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_hessians( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_hessians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &hessians) const; + + + /** + * Return the Laplacians of the selected scalar component of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_laplacians( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_laplacians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &laplacians) const; + + + /** + * Return the third derivatives of the selected scalar component of the + * finite element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_third_derivatives( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_third_derivatives_from_local_dof_values( + const InputVector &dof_values, + std::vector< + solution_third_derivative_type> + &third_derivatives) const; + + + private: + /** + * A pointer to the FEValuesBase object we operate on. + */ + const SmartPointer> 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 shape_function_data; + }; + + + + /** + * A class representing a view to a set of spacedim 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 spacedim 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 + class Vector + { + public: + /** + * An alias for the data type of values of the view this class + * represents. Since we deal with a set of dim 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 dim components of the finite element, + * the gradient is a Tensor@<2,spacedim@>. + * + * 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 dim components of the + * finite element, the symmetrized gradient is a + * SymmetricTensor@<2,spacedim@>. + * + * 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 dim 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 spacedim=2 components of the finite + * element, the curl is a Tensor@<1, 1@>. For + * spacedim=3 it is a Tensor@<1, dim@>. + */ + using curl_type = typename dealii::internal::CurlType::type; + + /** + * An alias for the type of second derivatives of the view this class + * represents. Here, for a set of dim components of the + * finite element, the Hessian is a Tensor@<3,dim@>. + */ + 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 dim components of the + * finite element, the third derivative is a Tensor@<4,dim@>. + */ + 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 + using solution_value_type = typename ProductType::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 + using solution_gradient_type = + typename ProductType::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 + using solution_symmetric_gradient_type = + typename ProductType::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 + using solution_divergence_type = + typename ProductType::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 + using solution_laplacian_type = + typename ProductType::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 + using solution_curl_type = typename ProductType::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 + using solution_hessian_type = + typename ProductType::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 + using solution_third_derivative_type = + typename ProductType::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 &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 &) = delete; + + /** + * Move constructor. + */ + // NOLINTNEXTLINE OSX does not compile with noexcept + Vector(Vector &&) = 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 &) = delete; + + /** + * Move assignment operator. + */ + // NOLINTNEXTLINE OSX does not compile with noexcept + Vector & + operator=(Vector &&) = 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 dim components, the return type is a tensor of + * rank 1 with dim 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 + * dim 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 spacedim=1. 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 fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_values(const ReadVector & fe_function, + std::vector> &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 + void + get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &values) const; + + /** + * Return the gradients of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_gradients( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &gradients) const; + + /** + * Return the symmetrized gradients of the selected vector components of + * the finite element function characterized by fe_function at + * the quadrature points of the cell, face or subface selected the last + * time the reinit 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 + void + get_function_symmetric_gradients( + const ReadVector &fe_function, + std::vector> + &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 + void + get_function_symmetric_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector< + solution_symmetric_gradient_type> + &symmetric_gradients) const; + + /** + * Return the divergence of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_divergences( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_divergences_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &divergences) const; + + /** + * Return the curl of the selected vector components of the finite element + * function characterized by fe_function at the quadrature points + * of the cell, face or subface selected the last time the reinit + * 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 + void + get_function_curls(const ReadVector & fe_function, + std::vector> &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 + void + get_function_curls_from_local_dof_values( + const InputVector &dof_values, + std::vector> &curls) + const; + + /** + * Return the Hessians of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_hessians( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_hessians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &hessians) const; + + /** + * Return the Laplacians of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_laplacians( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_laplacians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &laplacians) const; + + /** + * Return the third derivatives of the selected scalar component of the + * finite element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_third_derivatives( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_third_derivatives_from_local_dof_values( + const InputVector &dof_values, + std::vector< + solution_third_derivative_type> + &third_derivatives) const; + + private: + /** + * A pointer to the FEValuesBase object we operate on. + */ + const SmartPointer> 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 shape_function_data; + }; + + + template + class SymmetricTensor; + + /** + * A class representing a view to a set of (dim*dim + dim)/2 + * 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 + 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 (dim*dim + dim)/2 + * 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 (dim*dim + dim)/2 unique + * components of the finite element representing a symmetric second-order + * tensor, the divergence of course is a * Tensor@<1,dim@>. + * + * 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 + using solution_value_type = typename ProductType::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 + using solution_divergence_type = + typename ProductType::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 (dim*dim + + * dim)/2 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 &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 (dim*dim + dim)/2 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 fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_values(const ReadVector & fe_function, + std::vector> &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 + void + get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &values) const; + + /** + * Return the divergence of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_divergences( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_divergences_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &divergences) const; + + private: + /** + * A pointer to the FEValuesBase object we operate on. + */ + const SmartPointer> 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 shape_function_data; + }; + + + template + class Tensor; + + /** + * A class representing a view to a set of dim*dim 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 + 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 + using solution_value_type = typename ProductType::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 + using solution_divergence_type = + typename ProductType::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 + using solution_gradient_type = + typename ProductType::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 (dim*dim) + * 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 &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 (dim*dim) 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 fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_values(const ReadVector & fe_function, + std::vector> &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 + void + get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &values) const; + + /** + * Return the divergence of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_divergences( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_divergences_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &divergences) const; + + /** + * Return the gradient of the selected vector components of the finite + * element function characterized by fe_function at the + * quadrature points of the cell, face or subface selected the last time + * the reinit 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 + void + get_function_gradients( + const ReadVector & fe_function, + std::vector> &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 + void + get_function_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &gradients) const; + + private: + /** + * A pointer to the FEValuesBase object we operate on. + */ + const SmartPointer> 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 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 + 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. + */ + template + struct ViewType + { + using type = typename dealii::FEValuesViews::Scalar; + }; + + /** + * 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. + */ + template + struct ViewType + { + using type = typename dealii::FEValuesViews::Vector; + }; + + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * When using FEValuesExtractors::Tensor, the corresponding view is an + * FEValuesViews::Tensor. + */ + template + struct ViewType> + { + using type = typename dealii::FEValuesViews::Tensor; + }; + + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * When using FEValuesExtractors::SymmetricTensor, the corresponding + * view is an FEValuesViews::SymmetricTensor. + */ + template + struct ViewType> + { + using type = + typename dealii::FEValuesViews::SymmetricTensor; + }; + + /** + * 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 + struct Cache + { + /** + * Caches for scalar and vector, and symmetric second-order tensor + * valued views. + */ + std::vector> scalars; + std::vector> vectors; + std::vector> + symmetric_second_order_tensors; + std::vector> + second_order_tensors; + + /** + * Constructor. + */ + Cache(const FEValuesBase &fe_values); + }; + } // namespace FEValuesViews +} // namespace internal + +namespace FEValuesViews +{ + /** + * A templated alias that associates to a given Extractor class + * the corresponding view in FEValuesViews. + */ + template + using View = typename dealii::internal::FEValuesViews:: + ViewType::type; +} // namespace FEValuesViews + +#ifndef DOXYGEN + +/*---------------- Inline functions: namespace FEValuesViews -----------------*/ + +namespace FEValuesViews +{ + template + inline typename Scalar::value_type + Scalar::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::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 + inline typename Scalar::gradient_type + Scalar::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::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 + inline typename Scalar::hessian_type + Scalar::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::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 + inline typename Scalar::third_derivative_type + Scalar::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::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 + inline typename Vector::value_type + Vector::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::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 + inline typename Vector::gradient_type + Vector::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::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 + inline typename Vector::divergence_type + Vector::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::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 + inline typename Vector::curl_type + Vector::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::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 + inline typename Vector::hessian_type + Vector::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::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 + inline typename Vector::third_derivative_type + Vector::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::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 + inline typename Vector::symmetric_gradient_type + Vector::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::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 + 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::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 + 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::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 + 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::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 + 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::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 + 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::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 diff --git a/source/fe/CMakeLists.txt b/source/fe/CMakeLists.txt index c356007e11..57b6cc663e 100644 --- a/source/fe/CMakeLists.txt +++ b/source/fe/CMakeLists.txt @@ -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 diff --git a/source/fe/fe_values.cc b/source/fe/fe_values.cc index 325932363e..9fe7158f8f 100644 --- a/source/fe/fe_values.cc +++ b/source/fe/fe_values.cc @@ -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 - struct CheckForZero - { - static bool - value(const Number &value) - { - return value == dealii::internal::NumberType::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 - struct CheckForZero< - Number, - std::enable_if_t::value>> - { - static bool - value(const Number & /*value*/) - { - return false; - } - }; - } // namespace } // namespace internal -namespace FEValuesViews +namespace internal { - template - Scalar::Scalar(const FEValuesBase &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 &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 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 - Scalar::Scalar() - : fe_values(nullptr) - , component(numbers::invalid_unsigned_int) - {} - - - - template - Vector::Vector(const FEValuesBase &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 &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 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 - Vector::Vector() - : fe_values(nullptr) - , first_vector_component(numbers::invalid_unsigned_int) - {} - - - - template - SymmetricTensor<2, dim, spacedim>::SymmetricTensor( - const FEValuesBase &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 &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 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 - SymmetricTensor<2, dim, spacedim>::SymmetricTensor() - : fe_values(nullptr) - , first_tensor_component(numbers::invalid_unsigned_int) - {} - - - - template - Tensor<2, dim, spacedim>::Tensor(const FEValuesBase &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 &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 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 - 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 - void - do_function_values( - const ArrayView &dof_values, - const Table<2, double> & shape_values, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector::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::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::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 - void - do_function_derivatives( - const ArrayView & dof_values, - const Table<2, dealii::Tensor> &shape_derivatives, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector< - typename ProductType>::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>::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::value(value) == true) - continue; - - const dealii::Tensor *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 - void - do_function_laplacians( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector:: - template solution_laplacian_type> &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::template solution_laplacian_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::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 - void - do_function_values( - const ArrayView &dof_values, - const Table<2, double> & shape_values, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector< - typename ProductType>::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>::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::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 - void - do_function_derivatives( - const ArrayView & dof_values, - const Table<2, dealii::Tensor> &shape_derivatives, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector< - typename ProductType>::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>::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::value(value) == true) - continue; - - if (snc != -1) - { - const unsigned int comp = shape_function_data[shape_function] - .single_nonzero_component_index; - const dealii::Tensor *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 *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 - void - do_function_symmetric_gradients( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector< - typename ProductType>::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>::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::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>::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 + template void - do_function_divergences( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector:: - template solution_divergence_type> &divergences) + FiniteElementRelatedData::initialize( + const unsigned int n_quadrature_points, + const FiniteElement &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::template solution_divergence_type()); + // 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::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()); } - } - - - template - void - do_function_curls( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector::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::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::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::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>()); } - } - - - - template - void - do_function_laplacians( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector:: - template solution_laplacian_type> &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::template solution_laplacian_type()); - 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::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>()); } - } - - - - // ---------------------- symmetric tensor part ------------------------ - - template - void - do_function_values( - const ArrayView & 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>::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>::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::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>()); } } - template - void - do_function_divergences( - const ArrayView & 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:: - template solution_divergence_type> &divergences) + template + std::size_t + FiniteElementRelatedData::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()); - - 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::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 - void - do_function_values( - const ArrayView & dof_values, - const dealii::Table<2, double> &shape_values, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector< - typename ProductType>::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>::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::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 - void - do_function_divergences( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector:: - template solution_divergence_type> &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::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 - void - do_function_gradients( - const ArrayView & dof_values, - const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, - const std::vector::ShapeFunctionData> - &shape_function_data, - std::vector:: - template solution_gradient_type> &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::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 - template - void - Scalar::get_function_values( - const ReadVector & fe_function, - std::vector> &values) const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - - // get function values of dofs on this cell and call internal worker - // function - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - Scalar::get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> &values) - const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - Scalar::get_function_gradients( - const ReadVector & fe_function, - std::vector> &gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector 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 - template - void - Scalar::get_function_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::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 - template - void - Scalar::get_function_hessians( - const ReadVector & fe_function, - std::vector> &hessians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_hessians"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector 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 - template - void - Scalar::get_function_hessians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &hessians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_hessians"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::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 - template - void - Scalar::get_function_laplacians( - const ReadVector & fe_function, - std::vector> &laplacians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_hessians"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_laplacians( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_hessians, - shape_function_data, - laplacians); - } - - - - template - template - void - Scalar::get_function_laplacians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &laplacians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_hessians"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_laplacians( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_hessians, - shape_function_data, - laplacians); - } - - - - template - template - void - Scalar::get_function_third_derivatives( - const ReadVector & fe_function, - std::vector> &third_derivatives) - const - { - Assert(fe_values->update_flags & update_3rd_derivatives, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_3rd_derivatives"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector 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 - template - void - Scalar::get_function_third_derivatives_from_local_dof_values( - const InputVector &dof_values, - std::vector< - solution_third_derivative_type> - &third_derivatives) const - { - Assert(fe_values->update_flags & update_3rd_derivatives, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_3rd_derivatives"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::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 - template - void - Vector::get_function_values( - const ReadVector & fe_function, - std::vector> &values) const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - - // get function values of dofs on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - Vector::get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> &values) - const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - Vector::get_function_gradients( - const ReadVector & fe_function, - std::vector> &gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector 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 - template - void - Vector::get_function_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::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 - template - void - Vector::get_function_symmetric_gradients( - const ReadVector & fe_function, - std::vector> &symmetric_gradients) - const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_symmetric_gradients( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - symmetric_gradients); - } - - - - template - template - void - Vector::get_function_symmetric_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector< - solution_symmetric_gradient_type> - &symmetric_gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_symmetric_gradients( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - symmetric_gradients); - } - - - - template - template - void - Vector::get_function_divergences( - const ReadVector & fe_function, - std::vector> &divergences) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs - // on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_divergences( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - divergences); - } - - - - template - template - void - Vector::get_function_divergences_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &divergences) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_divergences( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - divergences); - } - - - - template - template - void - Vector::get_function_curls( - const ReadVector & fe_function, - std::vector> &curls) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::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 dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_curls( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - curls); - } - - - - template - template - void - Vector::get_function_curls_from_local_dof_values( - const InputVector &dof_values, - std::vector> &curls) - const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::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( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - curls); - } - - - - template - template - void - Vector::get_function_hessians( - const ReadVector & fe_function, - std::vector> &hessians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_hessians"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector 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 - template - void - Vector::get_function_hessians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &hessians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_hessians"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::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 - template - void - Vector::get_function_laplacians( - const ReadVector & fe_function, - std::vector> &laplacians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::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::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 dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_laplacians( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_hessians, - shape_function_data, - laplacians); - } - - - - template - template - void - Vector::get_function_laplacians_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &laplacians) const - { - Assert(fe_values->update_flags & update_hessians, - (typename FEValuesBase::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::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_laplacians( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_hessians, - shape_function_data, - laplacians); - } - - - - template - template - void - Vector::get_function_third_derivatives( - const ReadVector & fe_function, - std::vector> &third_derivatives) - const - { - Assert(fe_values->update_flags & update_3rd_derivatives, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_3rd_derivatives"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs on this cell - dealii::Vector 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 - template - void - Vector::get_function_third_derivatives_from_local_dof_values( - const InputVector &dof_values, - std::vector< - solution_third_derivative_type> - &third_derivatives) const - { - Assert(fe_values->update_flags & update_3rd_derivatives, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_3rd_derivatives"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::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 - template - void - SymmetricTensor<2, dim, spacedim>::get_function_values( - const ReadVector & fe_function, - std::vector> &values) const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - - // get function values of dofs on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - SymmetricTensor<2, dim, spacedim>::get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> &values) - const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - SymmetricTensor<2, dim, spacedim>::get_function_divergences( - const ReadVector & fe_function, - std::vector> &divergences) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs - // on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_divergences( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - divergences); - } - - - - template - template - void - SymmetricTensor<2, dim, spacedim>:: - get_function_divergences_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &divergences) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_divergences( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - divergences); - } - - - - template - template - void - Tensor<2, dim, spacedim>::get_function_values( - const ReadVector & fe_function, - std::vector> &values) const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - - // get function values of dofs on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - Tensor<2, dim, spacedim>::get_function_values_from_local_dof_values( - const InputVector &dof_values, - std::vector> &values) - const - { - Assert(fe_values->update_flags & update_values, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_values"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_values( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_values, - shape_function_data, - values); - } - - - - template - template - void - Tensor<2, dim, spacedim>::get_function_divergences( - const ReadVector & fe_function, - std::vector> &divergences) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs - // on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_divergences( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - divergences); - } - - - - template - template - void - Tensor<2, dim, spacedim>::get_function_divergences_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &divergences) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_divergences( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - divergences); - } - - - - template - template - void - Tensor<2, dim, spacedim>::get_function_gradients( - const ReadVector & fe_function, - std::vector> &gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(fe_function.size(), - fe_values->present_cell.n_dofs_for_dof_handler()); - - // get function values of dofs - // on this cell - dealii::Vector dof_values(fe_values->dofs_per_cell); - fe_values->present_cell.get_interpolated_dof_values(fe_function, - dof_values); - internal::do_function_gradients( - make_array_view(dof_values.begin(), dof_values.end()), - fe_values->finite_element_output.shape_gradients, - shape_function_data, - gradients); - } - - - - template - template - void - Tensor<2, dim, spacedim>::get_function_gradients_from_local_dof_values( - const InputVector &dof_values, - std::vector> - &gradients) const - { - Assert(fe_values->update_flags & update_gradients, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_gradients"))); - Assert(fe_values->present_cell.is_initialized(), - (typename FEValuesBase::ExcNotReinited())); - AssertDimension(dof_values.size(), fe_values->dofs_per_cell); - - internal::do_function_gradients( - 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 - Cache::Cache(const FEValuesBase &fe_values) - { - const FiniteElement &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::CellIteratorContainer --------- - */ - -template -FEValuesBase::CellIteratorContainer::CellIteratorContainer() - : initialized(false) - , cell(typename Triangulation::cell_iterator(nullptr, -1, -1)) - , dof_handler(nullptr) - , level_dof_access(false) -{} - - - -template -FEValuesBase::CellIteratorContainer::CellIteratorContainer( - const typename Triangulation::cell_iterator &cell) - : initialized(true) - , cell(cell) - , dof_handler(nullptr) - , level_dof_access(false) -{} - - - -template -bool -FEValuesBase::CellIteratorContainer::is_initialized() const -{ - return initialized; -} - - - -template -FEValuesBase::CellIteratorContainer:: -operator typename Triangulation::cell_iterator() const -{ - Assert(is_initialized(), ExcNotReinited()); - - return cell; -} - - - -template -types::global_dof_index -FEValuesBase::CellIteratorContainer::n_dofs_for_dof_handler() - const -{ - Assert(is_initialized(), ExcNotReinited()); - Assert(dof_handler != nullptr, ExcNeedsDoFHandler()); - - return dof_handler->n_dofs(); -} - - - -template -template -void -FEValuesBase::CellIteratorContainer::get_interpolated_dof_values( - const ReadVector &in, - Vector & out) const -{ - Assert(is_initialized(), ExcNotReinited()); - Assert(dof_handler != nullptr, ExcNeedsDoFHandler()); - - if (level_dof_access) - DoFCellAccessor(&cell->get_triangulation(), - cell->level(), - cell->index(), - dof_handler) - .get_interpolated_dof_values(in, out); - else - DoFCellAccessor(&cell->get_triangulation(), - cell->level(), - cell->index(), - dof_handler) - .get_interpolated_dof_values(in, out); -} - - - -template -void -FEValuesBase::CellIteratorContainer::get_interpolated_dof_values( - const IndexSet & in, - Vector &out) const -{ - Assert(is_initialized(), ExcNotReinited()); - Assert(dof_handler != nullptr, ExcNeedsDoFHandler()); - Assert(level_dof_access == false, ExcNotImplemented()); - - const DoFCellAccessor cell_dofs( - &cell->get_triangulation(), cell->level(), cell->index(), dof_handler); - - std::vector 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 - void - FiniteElementRelatedData::initialize( - const unsigned int n_quadrature_points, - const FiniteElement &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()); - } - - if (flags & update_gradients) - { - this->shape_gradients.reinit(n_nonzero_shape_components, - n_quadrature_points); - this->shape_gradients.fill( - numbers::signaling_nan>()); - } - - if (flags & update_hessians) - { - this->shape_hessians.reinit(n_nonzero_shape_components, - n_quadrature_points); - this->shape_hessians.fill( - numbers::signaling_nan>()); - } - - 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>()); - } - } - - - - template - std::size_t - FiniteElementRelatedData::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 -FEValuesBase::FEValuesBase( - const unsigned int n_q_points, - const unsigned int dofs_per_cell, - const UpdateFlags flags, - const Mapping & mapping, - const FiniteElement &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 -FEValuesBase::~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 - void - do_function_values(const ArrayView & dof_values, - const dealii::Table<2, double> &shape_values, - std::vector & 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::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::value) - if (value == dealii::internal::NumberType::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 - void - do_function_values( - const ArrayView &dof_values, - const dealii::Table<2, double> & shape_values, - const FiniteElement & fe, - const std::vector &shape_function_to_row_table, - ArrayView 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::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 - void - do_function_derivatives( - const ArrayView & dof_values, - const dealii::Table<2, Tensor> &shape_derivatives, - std::vector> & 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()); - - // 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::value(value) == true) - continue; - - const Tensor *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 - void - do_function_derivatives( - const ArrayView & dof_values, - const dealii::Table<2, Tensor> &shape_derivatives, - const FiniteElement & fe, - const std::vector &shape_function_to_row_table, - ArrayView>> 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()); - - // 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::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 *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 *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 - void - do_function_laplacians( - const ArrayView & dof_values, - const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians, - std::vector & 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::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::value) - if (value == dealii::internal::NumberType::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 - void - do_function_laplacians( - const ArrayView & dof_values, - const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians, - const FiniteElement & fe, - const std::vector & shape_function_to_row_table, - std::vector & 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::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 -template -void -FEValuesBase::get_function_values( - const ReadVector &fe_function, - std::vector & 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 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 -template -void -FEValuesBase::get_function_values( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector & 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 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 -template -void -FEValuesBase::get_function_values( - const ReadVector & fe_function, - std::vector> &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 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 -template -void -FEValuesBase::get_function_values( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 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 -template -void -FEValuesBase::get_function_values( - const ReadVector & fe_function, - const ArrayView &indices, - ArrayView> 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 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 -template -void -FEValuesBase::get_function_gradients( - const ReadVector & fe_function, - std::vector> &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 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 -template -void -FEValuesBase::get_function_gradients( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 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 -template -void -FEValuesBase::get_function_gradients( - const ReadVector & fe_function, - std::vector>> &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 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 -template -void -FEValuesBase::get_function_gradients( - const ReadVector & fe_function, - const ArrayView & indices, - ArrayView>> 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 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 -template -void -FEValuesBase::get_function_hessians( - const ReadVector & fe_function, - std::vector> &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 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 -template -void -FEValuesBase::get_function_hessians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 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 -template -void -FEValuesBase::get_function_hessians( - const ReadVector & fe_function, - std::vector>> &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 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 -template -void -FEValuesBase::get_function_hessians( - const ReadVector & fe_function, - const ArrayView & indices, - ArrayView>> 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 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 -template -void -FEValuesBase::get_function_laplacians( - const ReadVector &fe_function, - std::vector & 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 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 -template -void -FEValuesBase::get_function_laplacians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector & 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 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 -template -void -FEValuesBase::get_function_laplacians( - const ReadVector & fe_function, - std::vector> &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 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 -template -void -FEValuesBase::get_function_laplacians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 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 -template -void -FEValuesBase::get_function_laplacians( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 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 -template -void -FEValuesBase::get_function_third_derivatives( - const ReadVector & fe_function, - std::vector> &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 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 -template -void -FEValuesBase::get_function_third_derivatives( - const ReadVector & fe_function, - const ArrayView &indices, - std::vector> & 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 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 -template -void -FEValuesBase::get_function_third_derivatives( - const ReadVector & fe_function, - std::vector>> &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 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 -template -void -FEValuesBase::get_function_third_derivatives( - const ReadVector & fe_function, - const ArrayView & indices, - ArrayView>> 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 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 -typename Triangulation::cell_iterator -FEValuesBase::get_cell() const -{ - return present_cell; -} - - - -template -const std::vector> & -FEValuesBase::get_normal_vectors() const -{ - Assert(this->update_flags & update_normal_vectors, - (typename FEValuesBase::ExcAccessToUninitializedField( - "update_normal_vectors"))); - - return this->mapping_output.normal_vectors; -} - - - -template -std::size_t -FEValuesBase::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 -UpdateFlags -FEValuesBase::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 -void -FEValuesBase::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 -void -FEValuesBase::maybe_invalidate_previous_present_cell( - const typename Triangulation::cell_iterator &cell) -{ - if (present_cell.is_initialized()) - { - if (&cell->get_triangulation() != - &present_cell - . - operator typename Triangulation::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 -inline void -FEValuesBase::check_cell_similarity( - const typename Triangulation::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::cell_iterator - &>(this->present_cell)) ? - CellSimilarity::translation : - CellSimilarity::none); - - if ((dim < spacedim) && (cell_similarity == CellSimilarity::translation)) - { - if (static_cast::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 -CellSimilarity::Similarity -FEValuesBase::get_cell_similarity() const -{ - return cell_similarity; -} - - - -template -const unsigned int FEValuesBase::dimension; - - - -template -const unsigned int FEValuesBase::space_dimension; - /*------------------------------- FEValues -------------------------------*/ template @@ -4802,7 +993,7 @@ FESubfaceValues::do_reinit(const unsigned int face_no, } -/*------------------------------- Explicit Instantiations -------------*/ +/*------------------------- Explicit Instantiations --------------------------*/ #include "fe_values.inst" diff --git a/source/fe/fe_values.inst.in b/source/fe/fe_values.inst.in index d75f616bd7..26ee780538 100644 --- a/source/fe/fe_values.inst.in +++ b/source/fe/fe_values.inst.in @@ -18,24 +18,12 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) { # if deal_II_dimension <= deal_II_space_dimension - template class FEValuesBase; template class FEValues; template class FEFaceValuesBase; template class FEFaceValues; template class FESubfaceValues; - - namespace FEValuesViews - \{ - template class Scalar; - template class Vector; - 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> &); -# 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:: - get_function_values(const dealii::ReadVector &, - std::vector::type> &) - const; - - template void - FEValuesViews::Vector:: - get_function_values( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void FEValuesViews::SymmetricTensor<2, - deal_II_dimension, - deal_II_space_dimension>:: - get_function_values( - const dealii::ReadVector &, - std::vector>::type> &) const; - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_values( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void FEValuesBase:: - get_function_values(const ReadVector &, std::vector &) const; - - template void FEValuesBase:: - get_function_values(const ReadVector &, - const ArrayView &, - std::vector &) const; - - template void FEValuesBase:: - get_function_values(const ReadVector &, std::vector> &) - const; - - template void FEValuesBase:: - get_function_values(const ReadVector &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_values(const ReadVector &, - const ArrayView &, - ArrayView>, - bool) const; - - template void - FEValuesViews::Scalar:: - get_function_gradients( - const ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void - FEValuesViews::Vector:: - get_function_gradients( - const ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_gradients( - const ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void FEValuesBase:: - get_function_gradients( - const ReadVector &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_gradients( - const ReadVector &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_gradients( - const ReadVector &, - std::vector>> - &) const; - - template void FEValuesBase:: - get_function_gradients( - const ReadVector &, - const ArrayView &, - ArrayView>>, - 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:: - get_function_hessians( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Scalar:: - get_function_laplacians(const dealii::ReadVector &, - std::vector::type> &) - const; - template void - FEValuesViews::Scalar:: - get_function_third_derivatives( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void - FEValuesViews::Vector:: - get_function_symmetric_gradients( - const dealii::ReadVector &, - std::vector>::type> &) const; - template void FEValuesViews:: - Vector::get_function_curls( - const dealii::ReadVector &, - std::vector::type> &) const; - template void - FEValuesViews::Vector:: - get_function_divergences( - const dealii::ReadVector &, - std::vector::type> &) const; - template void - FEValuesViews::Vector:: - get_function_hessians( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_laplacians( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_third_derivatives( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void FEValuesViews:: - SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_divergences( - const dealii::ReadVector &, - std::vector< - ProductType>::type> &) - const; - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_divergences( - const dealii::ReadVector &, - std::vector< - ProductType>::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:: - get_function_values_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void - FEValuesViews::Scalar:: - get_function_gradients_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - template void - FEValuesViews::Scalar:: - get_function_hessians_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - template void - FEValuesViews::Scalar:: - get_function_laplacians_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void - FEValuesViews::Scalar:: - get_function_third_derivatives_from_local_dof_values>( - const VEC &, - std::vector> &) const; - - - - template void - FEValuesViews::Vector:: - get_function_values_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void - FEValuesViews::Vector:: - get_function_gradients_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - template void - FEValuesViews::Vector:: - get_function_symmetric_gradients_from_local_dof_values>( - const VEC &, - std::vector> &) const; - - template void - FEValuesViews::Vector:: - get_function_divergences_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - template void - FEValuesViews::Vector:: - get_function_curls_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void - FEValuesViews::Vector:: - get_function_hessians_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - template void - FEValuesViews::Vector:: - get_function_laplacians_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void - FEValuesViews::Vector:: - get_function_third_derivatives_from_local_dof_values>( - const VEC &, - std::vector> &) const; - - - - template void FEValuesViews::SymmetricTensor<2, - deal_II_dimension, - deal_II_space_dimension>:: - get_function_values_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void FEValuesViews:: - SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_divergences_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_values_from_local_dof_values>( - const VEC &, std::vector> &) const; - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_divergences_from_local_dof_values>( - const VEC &, std::vector> &) - const; - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_gradients_from_local_dof_values>( - const VEC &, std::vector> &) - 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:: - get_function_hessians( - const ReadVector &, - std::vector> &) const; - template void FEValuesBase:: - get_function_hessians( - const ReadVector &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_hessians( - const ReadVector &, - std::vector>> - &, - bool) const; - template void FEValuesBase:: - get_function_hessians( - const ReadVector &, - const ArrayView &, - ArrayView>>, - bool) const; - - template void FEValuesBase:: - get_function_laplacians(const ReadVector &, std::vector &) const; - template void FEValuesBase:: - get_function_laplacians( - const ReadVector &, - const ArrayView &, - std::vector &) const; - - template void FEValuesBase:: - get_function_laplacians(const ReadVector &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_laplacians( - const ReadVector &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_laplacians( - const ReadVector &, - const ArrayView &, - std::vector> &, - bool) const; - - template void FEValuesBase:: - get_function_third_derivatives( - const ReadVector &, - std::vector> &) const; - template void FEValuesBase:: - get_function_third_derivatives( - const ReadVector &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_third_derivatives( - const ReadVector &, - std::vector>> - &, - bool) const; - template void FEValuesBase:: - get_function_third_derivatives( - const ReadVector &, - const ArrayView &, - ArrayView>>, - bool) const; - # endif } #endif diff --git a/source/fe/fe_values_base.cc b/source/fe/fe_values_base.cc new file mode 100644 index 0000000000..4c9c4f4a12 --- /dev/null +++ b/source/fe/fe_values_base.cc @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + + +namespace internal +{ + template + inline std::vector + make_shape_function_to_row_table(const FiniteElement &fe) + { + std::vector 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 + struct CheckForZero + { + static bool + value(const Number &value) + { + return value == dealii::internal::NumberType::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 + struct CheckForZero< + Number, + std::enable_if_t::value>> + { + static bool + value(const Number & /*value*/) + { + return false; + } + }; + } // namespace +} // namespace internal + +/* ------------ FEValuesBase::CellIteratorContainer ----------- */ + +template +FEValuesBase::CellIteratorContainer::CellIteratorContainer() + : initialized(false) + , cell(typename Triangulation::cell_iterator(nullptr, -1, -1)) + , dof_handler(nullptr) + , level_dof_access(false) +{} + + + +template +FEValuesBase::CellIteratorContainer::CellIteratorContainer( + const typename Triangulation::cell_iterator &cell) + : initialized(true) + , cell(cell) + , dof_handler(nullptr) + , level_dof_access(false) +{} + + + +template +bool +FEValuesBase::CellIteratorContainer::is_initialized() const +{ + return initialized; +} + + + +template +FEValuesBase::CellIteratorContainer:: +operator typename Triangulation::cell_iterator() const +{ + Assert(is_initialized(), ExcNotReinited()); + + return cell; +} + + + +template +types::global_dof_index +FEValuesBase::CellIteratorContainer::n_dofs_for_dof_handler() + const +{ + Assert(is_initialized(), ExcNotReinited()); + Assert(dof_handler != nullptr, ExcNeedsDoFHandler()); + + return dof_handler->n_dofs(); +} + + + +template +template +void +FEValuesBase::CellIteratorContainer::get_interpolated_dof_values( + const ReadVector &in, + Vector & out) const +{ + Assert(is_initialized(), ExcNotReinited()); + Assert(dof_handler != nullptr, ExcNeedsDoFHandler()); + + if (level_dof_access) + DoFCellAccessor(&cell->get_triangulation(), + cell->level(), + cell->index(), + dof_handler) + .get_interpolated_dof_values(in, out); + else + DoFCellAccessor(&cell->get_triangulation(), + cell->level(), + cell->index(), + dof_handler) + .get_interpolated_dof_values(in, out); +} + + + +template +void +FEValuesBase::CellIteratorContainer::get_interpolated_dof_values( + const IndexSet & in, + Vector &out) const +{ + Assert(is_initialized(), ExcNotReinited()); + Assert(dof_handler != nullptr, ExcNeedsDoFHandler()); + Assert(level_dof_access == false, ExcNotImplemented()); + + const DoFCellAccessor cell_dofs( + &cell->get_triangulation(), cell->level(), cell->index(), dof_handler); + + std::vector 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 +FEValuesBase::FEValuesBase( + const unsigned int n_q_points, + const unsigned int dofs_per_cell, + const UpdateFlags flags, + const Mapping & mapping, + const FiniteElement &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 +FEValuesBase::~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 + void + do_function_values(const ArrayView & dof_values, + const dealii::Table<2, double> &shape_values, + std::vector & 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::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::value) + if (value == dealii::internal::NumberType::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 + void + do_function_values( + const ArrayView &dof_values, + const dealii::Table<2, double> & shape_values, + const FiniteElement & fe, + const std::vector &shape_function_to_row_table, + ArrayView 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::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 + void + do_function_derivatives( + const ArrayView & dof_values, + const dealii::Table<2, Tensor> &shape_derivatives, + std::vector> & 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()); + + // 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::value(value) == true) + continue; + + const Tensor *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 + void + do_function_derivatives( + const ArrayView & dof_values, + const dealii::Table<2, Tensor> &shape_derivatives, + const FiniteElement & fe, + const std::vector &shape_function_to_row_table, + ArrayView>> 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()); + + // 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::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 *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 *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 + void + do_function_laplacians( + const ArrayView & dof_values, + const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians, + std::vector & 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::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::value) + if (value == dealii::internal::NumberType::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 + void + do_function_laplacians( + const ArrayView & dof_values, + const dealii::Table<2, Tensor<2, spacedim>> &shape_hessians, + const FiniteElement & fe, + const std::vector & shape_function_to_row_table, + std::vector & 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::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 +template +void +FEValuesBase::get_function_values( + const ReadVector &fe_function, + std::vector & 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 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 +template +void +FEValuesBase::get_function_values( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector & 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 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 +template +void +FEValuesBase::get_function_values( + const ReadVector & fe_function, + std::vector> &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 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 +template +void +FEValuesBase::get_function_values( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 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 +template +void +FEValuesBase::get_function_values( + const ReadVector & fe_function, + const ArrayView &indices, + ArrayView> 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 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 +template +void +FEValuesBase::get_function_gradients( + const ReadVector & fe_function, + std::vector> &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 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 +template +void +FEValuesBase::get_function_gradients( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 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 +template +void +FEValuesBase::get_function_gradients( + const ReadVector & fe_function, + std::vector>> &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 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 +template +void +FEValuesBase::get_function_gradients( + const ReadVector & fe_function, + const ArrayView & indices, + ArrayView>> 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 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 +template +void +FEValuesBase::get_function_hessians( + const ReadVector & fe_function, + std::vector> &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 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 +template +void +FEValuesBase::get_function_hessians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 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 +template +void +FEValuesBase::get_function_hessians( + const ReadVector & fe_function, + std::vector>> &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 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 +template +void +FEValuesBase::get_function_hessians( + const ReadVector & fe_function, + const ArrayView & indices, + ArrayView>> 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 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 +template +void +FEValuesBase::get_function_laplacians( + const ReadVector &fe_function, + std::vector & 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 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 +template +void +FEValuesBase::get_function_laplacians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector & 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 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 +template +void +FEValuesBase::get_function_laplacians( + const ReadVector & fe_function, + std::vector> &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 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 +template +void +FEValuesBase::get_function_laplacians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 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 +template +void +FEValuesBase::get_function_laplacians( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 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 +template +void +FEValuesBase::get_function_third_derivatives( + const ReadVector & fe_function, + std::vector> &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 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 +template +void +FEValuesBase::get_function_third_derivatives( + const ReadVector & fe_function, + const ArrayView &indices, + std::vector> & 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 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 +template +void +FEValuesBase::get_function_third_derivatives( + const ReadVector & fe_function, + std::vector>> &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 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 +template +void +FEValuesBase::get_function_third_derivatives( + const ReadVector & fe_function, + const ArrayView & indices, + ArrayView>> 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 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 +typename Triangulation::cell_iterator +FEValuesBase::get_cell() const +{ + return present_cell; +} + + + +template +const std::vector> & +FEValuesBase::get_normal_vectors() const +{ + Assert(this->update_flags & update_normal_vectors, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_normal_vectors"))); + + return this->mapping_output.normal_vectors; +} + + + +template +std::size_t +FEValuesBase::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 +UpdateFlags +FEValuesBase::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 +void +FEValuesBase::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 +void +FEValuesBase::maybe_invalidate_previous_present_cell( + const typename Triangulation::cell_iterator &cell) +{ + if (present_cell.is_initialized()) + { + if (&cell->get_triangulation() != + &present_cell + . + operator typename Triangulation::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 +inline void +FEValuesBase::check_cell_similarity( + const typename Triangulation::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::cell_iterator + &>(this->present_cell)) ? + CellSimilarity::translation : + CellSimilarity::none); + + if ((dim < spacedim) && (cell_similarity == CellSimilarity::translation)) + { + if (static_cast::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 +CellSimilarity::Similarity +FEValuesBase::get_cell_similarity() const +{ + return cell_similarity; +} + + + +template +const unsigned int FEValuesBase::dimension; + + + +template +const unsigned int FEValuesBase::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 index 0000000000..012d897f66 --- /dev/null +++ b/source/fe/fe_values_base.inst.in @@ -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; +# 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:: + CellIteratorContainer::get_interpolated_dof_values( + const ReadVector &, Vector &) 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:: + get_function_values(const ReadVector &, std::vector &) const; + + template void FEValuesBase:: + get_function_values(const ReadVector &, + const ArrayView &, + std::vector &) const; + + template void FEValuesBase:: + get_function_values(const ReadVector &, std::vector> &) + const; + + template void FEValuesBase:: + get_function_values(const ReadVector &, + const ArrayView &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_values(const ReadVector &, + const ArrayView &, + ArrayView>, + bool) const; + + template void FEValuesBase:: + get_function_gradients( + const ReadVector &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_gradients( + const ReadVector &, + const ArrayView &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_gradients( + const ReadVector &, + std::vector>> + &) const; + + template void FEValuesBase:: + get_function_gradients( + const ReadVector &, + const ArrayView &, + ArrayView>>, + 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:: + get_function_hessians( + const ReadVector &, + std::vector> &) const; + template void FEValuesBase:: + get_function_hessians( + const ReadVector &, + const ArrayView &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_hessians( + const ReadVector &, + std::vector>> + &, + bool) const; + template void FEValuesBase:: + get_function_hessians( + const ReadVector &, + const ArrayView &, + ArrayView>>, + bool) const; + + template void FEValuesBase:: + get_function_laplacians(const ReadVector &, std::vector &) const; + template void FEValuesBase:: + get_function_laplacians( + const ReadVector &, + const ArrayView &, + std::vector &) const; + + template void FEValuesBase:: + get_function_laplacians(const ReadVector &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_laplacians( + const ReadVector &, + const ArrayView &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_laplacians( + const ReadVector &, + const ArrayView &, + std::vector> &, + bool) const; + + template void FEValuesBase:: + get_function_third_derivatives( + const ReadVector &, + std::vector> &) const; + template void FEValuesBase:: + get_function_third_derivatives( + const ReadVector &, + const ArrayView &, + std::vector> &) const; + + template void FEValuesBase:: + get_function_third_derivatives( + const ReadVector &, + std::vector>> + &, + bool) const; + template void FEValuesBase:: + get_function_third_derivatives( + const ReadVector &, + const ArrayView &, + ArrayView>>, + bool) const; +# endif + } +#endif diff --git a/source/fe/fe_values_views.cc b/source/fe/fe_values_views.cc new file mode 100644 index 0000000000..a620da229b --- /dev/null +++ b/source/fe/fe_values_views.cc @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + + +namespace internal +{ + template + inline std::vector + make_shape_function_to_row_table(const FiniteElement &fe) + { + std::vector 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 + struct CheckForZero + { + static bool + value(const Number &value) + { + return value == dealii::internal::NumberType::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 + struct CheckForZero< + Number, + std::enable_if_t::value>> + { + static bool + value(const Number & /*value*/) + { + return false; + } + }; + } // namespace +} // namespace internal + + + +namespace FEValuesViews +{ + template + Scalar::Scalar(const FEValuesBase &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 &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 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 + Scalar::Scalar() + : fe_values(nullptr) + , component(numbers::invalid_unsigned_int) + {} + + + + template + Vector::Vector(const FEValuesBase &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 &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 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 + Vector::Vector() + : fe_values(nullptr) + , first_vector_component(numbers::invalid_unsigned_int) + {} + + + + template + SymmetricTensor<2, dim, spacedim>::SymmetricTensor( + const FEValuesBase &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 &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 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 + SymmetricTensor<2, dim, spacedim>::SymmetricTensor() + : fe_values(nullptr) + , first_tensor_component(numbers::invalid_unsigned_int) + {} + + + + template + Tensor<2, dim, spacedim>::Tensor(const FEValuesBase &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 &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 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 + 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 + void + do_function_values( + const ArrayView &dof_values, + const Table<2, double> & shape_values, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector::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::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::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 + void + do_function_derivatives( + const ArrayView & dof_values, + const Table<2, dealii::Tensor> &shape_derivatives, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector< + typename ProductType>::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>::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::value(value) == true) + continue; + + const dealii::Tensor *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 + void + do_function_laplacians( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector:: + template solution_laplacian_type> &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::template solution_laplacian_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::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 + void + do_function_values( + const ArrayView &dof_values, + const Table<2, double> & shape_values, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector< + typename ProductType>::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>::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::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 + void + do_function_derivatives( + const ArrayView & dof_values, + const Table<2, dealii::Tensor> &shape_derivatives, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector< + typename ProductType>::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>::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::value(value) == true) + continue; + + if (snc != -1) + { + const unsigned int comp = shape_function_data[shape_function] + .single_nonzero_component_index; + const dealii::Tensor *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 *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 + void + do_function_symmetric_gradients( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector< + typename ProductType>::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>::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::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>::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 + void + do_function_divergences( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector:: + template solution_divergence_type> &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::template solution_divergence_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::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 + void + do_function_curls( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector::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::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::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::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 + void + do_function_laplacians( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<2, spacedim>> &shape_hessians, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector:: + template solution_laplacian_type> &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::template solution_laplacian_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::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 + void + do_function_values( + const ArrayView & 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>::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>::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::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 + void + do_function_divergences( + const ArrayView & 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:: + template solution_divergence_type> &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()); + + 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::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 + void + do_function_values( + const ArrayView & dof_values, + const dealii::Table<2, double> &shape_values, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector< + typename ProductType>::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>::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::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 + void + do_function_divergences( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector:: + template solution_divergence_type> &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::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 + void + do_function_gradients( + const ArrayView & dof_values, + const Table<2, dealii::Tensor<1, spacedim>> &shape_gradients, + const std::vector::ShapeFunctionData> + &shape_function_data, + std::vector:: + template solution_gradient_type> &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::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 + template + void + Scalar::get_function_values( + const ReadVector & fe_function, + std::vector> &values) const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + + // get function values of dofs on this cell and call internal worker + // function + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + Scalar::get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> &values) + const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + Scalar::get_function_gradients( + const ReadVector & fe_function, + std::vector> &gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector 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 + template + void + Scalar::get_function_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::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 + template + void + Scalar::get_function_hessians( + const ReadVector & fe_function, + std::vector> &hessians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_hessians"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector 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 + template + void + Scalar::get_function_hessians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &hessians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_hessians"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::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 + template + void + Scalar::get_function_laplacians( + const ReadVector & fe_function, + std::vector> &laplacians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_hessians"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_laplacians( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_hessians, + shape_function_data, + laplacians); + } + + + + template + template + void + Scalar::get_function_laplacians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &laplacians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_hessians"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_laplacians( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_hessians, + shape_function_data, + laplacians); + } + + + + template + template + void + Scalar::get_function_third_derivatives( + const ReadVector & fe_function, + std::vector> &third_derivatives) + const + { + Assert(fe_values->update_flags & update_3rd_derivatives, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_3rd_derivatives"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector 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 + template + void + Scalar::get_function_third_derivatives_from_local_dof_values( + const InputVector &dof_values, + std::vector< + solution_third_derivative_type> + &third_derivatives) const + { + Assert(fe_values->update_flags & update_3rd_derivatives, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_3rd_derivatives"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::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 + template + void + Vector::get_function_values( + const ReadVector & fe_function, + std::vector> &values) const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + + // get function values of dofs on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + Vector::get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> &values) + const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + Vector::get_function_gradients( + const ReadVector & fe_function, + std::vector> &gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector 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 + template + void + Vector::get_function_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::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 + template + void + Vector::get_function_symmetric_gradients( + const ReadVector & fe_function, + std::vector> &symmetric_gradients) + const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_symmetric_gradients( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + symmetric_gradients); + } + + + + template + template + void + Vector::get_function_symmetric_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector< + solution_symmetric_gradient_type> + &symmetric_gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_symmetric_gradients( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + symmetric_gradients); + } + + + + template + template + void + Vector::get_function_divergences( + const ReadVector & fe_function, + std::vector> &divergences) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs + // on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_divergences( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + divergences); + } + + + + template + template + void + Vector::get_function_divergences_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &divergences) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_divergences( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + divergences); + } + + + + template + template + void + Vector::get_function_curls( + const ReadVector & fe_function, + std::vector> &curls) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::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 dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_curls( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + curls); + } + + + + template + template + void + Vector::get_function_curls_from_local_dof_values( + const InputVector &dof_values, + std::vector> &curls) + const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::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( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + curls); + } + + + + template + template + void + Vector::get_function_hessians( + const ReadVector & fe_function, + std::vector> &hessians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_hessians"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector 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 + template + void + Vector::get_function_hessians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &hessians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_hessians"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::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 + template + void + Vector::get_function_laplacians( + const ReadVector & fe_function, + std::vector> &laplacians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::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::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 dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_laplacians( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_hessians, + shape_function_data, + laplacians); + } + + + + template + template + void + Vector::get_function_laplacians_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &laplacians) const + { + Assert(fe_values->update_flags & update_hessians, + (typename FEValuesBase::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::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_laplacians( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_hessians, + shape_function_data, + laplacians); + } + + + + template + template + void + Vector::get_function_third_derivatives( + const ReadVector & fe_function, + std::vector> &third_derivatives) + const + { + Assert(fe_values->update_flags & update_3rd_derivatives, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_3rd_derivatives"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs on this cell + dealii::Vector 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 + template + void + Vector::get_function_third_derivatives_from_local_dof_values( + const InputVector &dof_values, + std::vector< + solution_third_derivative_type> + &third_derivatives) const + { + Assert(fe_values->update_flags & update_3rd_derivatives, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_3rd_derivatives"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::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 + template + void + SymmetricTensor<2, dim, spacedim>::get_function_values( + const ReadVector & fe_function, + std::vector> &values) const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + + // get function values of dofs on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + SymmetricTensor<2, dim, spacedim>::get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> &values) + const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + SymmetricTensor<2, dim, spacedim>::get_function_divergences( + const ReadVector & fe_function, + std::vector> &divergences) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs + // on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_divergences( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + divergences); + } + + + + template + template + void + SymmetricTensor<2, dim, spacedim>:: + get_function_divergences_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &divergences) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_divergences( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + divergences); + } + + + + template + template + void + Tensor<2, dim, spacedim>::get_function_values( + const ReadVector & fe_function, + std::vector> &values) const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + + // get function values of dofs on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + Tensor<2, dim, spacedim>::get_function_values_from_local_dof_values( + const InputVector &dof_values, + std::vector> &values) + const + { + Assert(fe_values->update_flags & update_values, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_values"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_values( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_values, + shape_function_data, + values); + } + + + + template + template + void + Tensor<2, dim, spacedim>::get_function_divergences( + const ReadVector & fe_function, + std::vector> &divergences) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs + // on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_divergences( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + divergences); + } + + + + template + template + void + Tensor<2, dim, spacedim>::get_function_divergences_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &divergences) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_divergences( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + divergences); + } + + + + template + template + void + Tensor<2, dim, spacedim>::get_function_gradients( + const ReadVector & fe_function, + std::vector> &gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(fe_function.size(), + fe_values->present_cell.n_dofs_for_dof_handler()); + + // get function values of dofs + // on this cell + dealii::Vector dof_values(fe_values->dofs_per_cell); + fe_values->present_cell.get_interpolated_dof_values(fe_function, + dof_values); + internal::do_function_gradients( + make_array_view(dof_values.begin(), dof_values.end()), + fe_values->finite_element_output.shape_gradients, + shape_function_data, + gradients); + } + + + + template + template + void + Tensor<2, dim, spacedim>::get_function_gradients_from_local_dof_values( + const InputVector &dof_values, + std::vector> + &gradients) const + { + Assert(fe_values->update_flags & update_gradients, + (typename FEValuesBase::ExcAccessToUninitializedField( + "update_gradients"))); + Assert(fe_values->present_cell.is_initialized(), + (typename FEValuesBase::ExcNotReinited())); + AssertDimension(dof_values.size(), fe_values->dofs_per_cell); + + internal::do_function_gradients( + 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 + Cache::Cache(const FEValuesBase &fe_values) + { + const FiniteElement &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 index 0000000000..3d7f70728b --- /dev/null +++ b/source/fe/fe_values_views.inst.in @@ -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; + template class Vector; + 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; + \} + \} +# 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:: + get_function_values(const dealii::ReadVector &, + std::vector::type> &) + const; + + template void + FEValuesViews::Vector:: + get_function_values( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void FEValuesViews::SymmetricTensor<2, + deal_II_dimension, + deal_II_space_dimension>:: + get_function_values( + const dealii::ReadVector &, + std::vector>::type> &) const; + + template void + FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_values( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void + FEValuesViews::Scalar:: + get_function_gradients( + const ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void + FEValuesViews::Vector:: + get_function_gradients( + const ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void + FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_gradients( + const ReadVector &, + std::vector< + ProductType>::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:: + get_function_hessians( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + template void + FEValuesViews::Scalar:: + get_function_laplacians(const dealii::ReadVector &, + std::vector::type> &) + const; + template void + FEValuesViews::Scalar:: + get_function_third_derivatives( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void + FEValuesViews::Vector:: + get_function_symmetric_gradients( + const dealii::ReadVector &, + std::vector>::type> &) const; + template void FEValuesViews:: + Vector::get_function_curls( + const dealii::ReadVector &, + std::vector::type> &) const; + template void + FEValuesViews::Vector:: + get_function_divergences( + const dealii::ReadVector &, + std::vector::type> &) const; + template void + FEValuesViews::Vector:: + get_function_hessians( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + template void + FEValuesViews::Vector:: + get_function_laplacians( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + template void + FEValuesViews::Vector:: + get_function_third_derivatives( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void FEValuesViews:: + SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_divergences( + const dealii::ReadVector &, + std::vector< + ProductType>::type> &) + const; + + template void + FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_divergences( + const dealii::ReadVector &, + std::vector< + ProductType>::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:: + get_function_values_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void + FEValuesViews::Scalar:: + get_function_gradients_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Scalar:: + get_function_hessians_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Scalar:: + get_function_laplacians_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void + FEValuesViews::Scalar:: + get_function_third_derivatives_from_local_dof_values>( + const VEC &, + std::vector> &) const; + + template void + FEValuesViews::Vector:: + get_function_values_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void + FEValuesViews::Vector:: + get_function_gradients_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Vector:: + get_function_symmetric_gradients_from_local_dof_values>( + const VEC &, + std::vector> &) const; + + template void + FEValuesViews::Vector:: + get_function_divergences_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Vector:: + get_function_curls_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void + FEValuesViews::Vector:: + get_function_hessians_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Vector:: + get_function_laplacians_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void + FEValuesViews::Vector:: + get_function_third_derivatives_from_local_dof_values>( + const VEC &, + std::vector> &) const; + + template void FEValuesViews::SymmetricTensor<2, + deal_II_dimension, + deal_II_space_dimension>:: + get_function_values_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void FEValuesViews:: + SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_divergences_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_values_from_local_dof_values>( + const VEC &, std::vector> &) const; + + template void + FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_divergences_from_local_dof_values>( + const VEC &, std::vector> &) + const; + + template void + FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: + get_function_gradients_from_local_dof_values>( + const VEC &, std::vector> &) + const; +# endif + } +#endif