#include <deal.II/fe/block_mask.h>
#include <deal.II/fe/component_mask.h>
-#include <deal.II/fe/fe_base.h>
+#include <deal.II/fe/fe_data.h>
#include <deal.II/fe/fe_update_flags.h>
#include <deal.II/fe/fe_values_extractors.h>
#include <deal.II/fe/mapping.h>
#include <deal.II/base/config.h>
-#include <deal.II/base/exceptions.h>
-
-#include <deal.II/grid/reference_cell.h>
-
-#include <deal.II/lac/block_indices.h>
-
-#include <vector>
-
-DEAL_II_NAMESPACE_OPEN
-
-// Forward declarations:
-#ifndef DOXYGEN
-template <int dim>
-class FiniteElementData;
-#endif
-
-/**
- * A namespace solely for the purpose of defining the Domination enum as well
- * as associated operators.
- */
-namespace FiniteElementDomination
-{
- /**
- * An enum that describes the outcome of comparing two elements for mutual
- * domination. If one element dominates another, then the restriction of the
- * space described by the dominated element to a face of the cell is
- * strictly larger than that of the dominating element. For example, in 2-d
- * Q(2) elements dominate Q(4) elements, because the traces of Q(4) elements
- * are quartic polynomials which is a space strictly larger than the
- * quadratic polynomials (the restriction of the Q(2) element). Similar
- * reasonings apply for vertices and cells as well. In general, Q(k) dominates
- * Q(k') if $k\le k'$.
- *
- * This enum is used in the FiniteElement::compare_for_domination() function
- * that is used in the context of hp-finite element methods when determining
- * what to do at faces where two different finite elements meet (see the
- * @ref hp_paper "hp-paper"
- * for a more detailed description of the following). In that case, the
- * degrees of freedom of one side need to be constrained to those on the
- * other side. The determination which side is which is based on the outcome
- * of a comparison for mutual domination: the dominated side is constrained
- * to the dominating one.
- *
- * Note that there are situations where neither side dominates. The
- * @ref hp_paper "hp-paper"
- * lists two case, with the simpler one being that a $Q_2\times Q_1$ vector-
- * valued element (i.e. a <code>FESystem(FE_Q(2),1,FE_Q(1),1)</code>) meets
- * a $Q_1\times Q_2$ element: here, for each of the two vector-components,
- * we can define a domination relationship, but it is different for the two
- * components.
- *
- * It is clear that the concept of domination doesn't matter for
- * discontinuous elements. However, discontinuous elements may be part of
- * vector-valued elements and may therefore be compared against each other
- * for domination. They should return
- * <code>either_element_can_dominate</code> in that case. Likewise, when
- * comparing two identical finite elements, they should return this code;
- * the reason is that we can not decide which element will dominate at the
- * time we look at the first component of, for example, two $Q_2\times Q_1$
- * and $Q_2\times Q_2$ elements, and have to keep our options open until we
- * get to the second base element.
- *
- * Finally, the code no_requirements exists for cases where elements impose
- * no continuity requirements. The case is primarily meant for FE_Nothing
- * which is an element that has no degrees of freedom in a subdomain. It
- * could also be used by discontinuous elements, for example.
- *
- * More details on domination can be found in the
- * @ref hp_paper "hp-paper".
- */
- enum Domination
- {
- /**
- * The current element dominates.
- */
- this_element_dominates,
- /**
- * The other element dominates.
- */
- other_element_dominates,
- /**
- * Neither element dominates.
- */
- neither_element_dominates,
- /**
- * Either element may dominate.
- */
- either_element_can_dominate,
- /**
- * There are no requirements.
- */
- no_requirements
- };
-
-
- /**
- * A generalization of the binary <code>and</code> operator to a comparison
- * relationship. The way this works is pretty much as when you would want to
- * define a comparison relationship for vectors: either all elements of the
- * first vector are smaller, equal, or larger than those of the second
- * vector, or some are and some are not.
- *
- * This operator is pretty much the same: if both arguments are
- * <code>this_element_dominates</code> or
- * <code>other_element_dominates</code>, then the returned value is that
- * value. On the other hand, if one of the values is
- * <code>either_element_can_dominate</code>, then the returned value is that
- * of the other argument. If either argument is
- * <code>neither_element_dominates</code>, or if the two arguments are
- * <code>this_element_dominates</code> and
- * <code>other_element_dominates</code>, then the returned value is
- * <code>neither_element_dominates</code>.
- */
- inline Domination
- operator&(const Domination d1, const Domination d2);
-} // namespace FiniteElementDomination
-
-namespace internal
-{
- /**
- * Internal data structure for setting up FiniteElementData. It stores for
- * each object the (inclusive/exclusive) number of degrees of freedoms, as
- * well as, the index of its first degree of freedom within a cell and the
- * index of the first d-dimensional object within each face.
- *
- * The information is saved as a vector of vectors. One can query the
- * inclusive number of dofs of the i-th d-dimensional object via:
- * dofs_per_object_inclusive[d][i].
- *
- * As an example, the data is shown for a quadratic wedge. Which consists of
- * 6 vertices, 9 lines, and 5 faces (two triangles and three quadrilaterals).
- * @code
- * vertices lines faces cell
- * dpo_excl 1 1 1 1 1 1 | 1 1 1 1 1 1 1 1 1 | 0 0 1 1 1 | 0
- * dpo_incl 1 1 1 1 1 1 | 3 3 3 3 3 3 3 3 3 | 6 6 9 9 9 | 18
- * obj_index 0 1 2 3 4 5 | 6 7 8 9 10 11 12 13 14 | 15 15 15 16 17 | 18
- * @endcode
- *
- * Since the above table looks as follows for:
- *
- * - a triangle:
- * @code
- * dpo_excl 1 1 1 | 1 1 1 | 0
- * obj_index 0 1 2 | 3 4 5 | 6
- * @endcode
- *
- * - quadrilateral:
- * @code
- * dpo_excl 1 1 1 1 | 1 1 1 1 | 1
- * obj_index 0 1 2 3 | 4 5 6 7 | 8
- * @endcode
- *
- * The index of the first d-dimensional object within each face results as:
- * @code
- * vertices lines face
- * first_obj_index_on_face 0 0 0 0 0 | 3 3 4 4 4 | 6 6 8 8 8
- * @endcode
- *
- */
- struct GenericDoFsPerObject
- {
- /**
- * Exclusive number of degrees of freedom per object.
- */
- std::vector<std::vector<unsigned int>> dofs_per_object_exclusive;
-
- /**
- * Inclusive number of degrees of freedom per object.
- */
- std::vector<std::vector<unsigned int>> dofs_per_object_inclusive;
-
- /**
- * First index of an object.
- */
- std::vector<std::vector<unsigned int>> object_index;
-
- /**
- * First index of an object within a face.
- */
- std::vector<std::vector<unsigned int>> first_object_index_on_face;
-
- /**
- * Function that fills the fields based on a provided finite element.
- */
- template <int dim>
- static GenericDoFsPerObject
- generate(const FiniteElementData<dim> &fe);
- };
-} // namespace internal
-
-/**
- * A class that declares a number of scalar constant variables that describe
- * basic properties of a finite element implementation. This includes, for
- * example, the number of degrees of freedom per vertex, line, or cell; the
- * number of vector components; etc.
- *
- * The kind of information stored here is computed during initialization of a
- * finite element object and is passed down to this class via its constructor.
- * The data stored by this class is part of the public interface of the
- * FiniteElement class (which derives from the current class). See there for
- * more information.
- *
- * @ingroup febase
- */
-template <int dim>
-class FiniteElementData
-{
-public:
- /**
- * Enumerator for the different types of continuity a finite element may
- * have. Continuity is measured by the Sobolev space containing the
- * constructed finite element space and is also called this way.
- *
- * Note that certain continuities may imply others. For instance, a function
- * in <i>H<sup>1</sup></i> is in <i>H<sup>curl</sup></i> and
- * <i>H<sup>div</sup></i> as well.
- *
- * If you are interested in continuity in the classical sense, then the
- * following relations hold:
- *
- * <ol>
- *
- * <li> <i>H<sup>1</sup></i> implies that the function is continuous over
- * cell boundaries.
- *
- * <li> <i>H<sup>2</sup></i> implies that the function is continuously
- * differentiable over cell boundaries.
- *
- * <li> <i>L<sup>2</sup></i> indicates that the element is discontinuous.
- * Since discontinuous elements have no topological couplings between grid
- * cells and code may actually depend on this property, <i>L<sup>2</sup></i>
- * conformity is handled in a special way in the sense that it is <b>not</b>
- * implied by any higher conformity.
- * </ol>
- *
- * In order to test if a finite element conforms to a certain space, use
- * FiniteElementData<dim>::conforms().
- */
- enum Conformity
- {
- /**
- * Indicates incompatible continuities of a system.
- */
- unknown = 0x00,
-
- /**
- * Discontinuous elements. See above!
- */
- L2 = 0x01,
-
- /**
- * Conformity with the space <i>H<sup>curl</sup></i> (continuous
- * tangential component of a vector field)
- */
- Hcurl = 0x02,
-
- /**
- * Conformity with the space <i>H<sup>div</sup></i> (continuous normal
- * component of a vector field)
- */
- Hdiv = 0x04,
-
- /**
- * Conformity with the space <i>H<sup>1</sup></i> (continuous)
- */
- H1 = Hcurl | Hdiv,
-
- /**
- * Conformity with the space <i>H<sup>2</sup></i> (continuously
- * differentiable)
- */
- H2 = 0x0e
- };
-
- /**
- * The dimension of the finite element, which is the template parameter
- * <tt>dim</tt>
- */
- static constexpr unsigned int dimension = dim;
-
-private:
- /**
- * Reference cell type.
- */
- const ReferenceCell reference_cell_kind;
-
- /**
- * Number of unique quads. If all quads have the same type, the value is
- * one; else it equals the number of quads.
- */
- const unsigned int number_unique_quads;
-
- /**
- * Number of unique faces. If all faces have the same type, the value is
- * one; else it equals the number of faces.
- */
- const unsigned int number_unique_faces;
-
-public:
- /**
- * Number of degrees of freedom on a vertex.
- */
- const unsigned int dofs_per_vertex;
-
- /**
- * Number of degrees of freedom in a line; not including the degrees of
- * freedom on the vertices of the line.
- */
- const unsigned int dofs_per_line;
-
-private:
- /**
- * Number of degrees of freedom on quads. If all quads have the same
- * number of degrees freedoms the values equal dofs_per_quad.
- */
- const std::vector<unsigned int> n_dofs_on_quad;
-
-public:
- /**
- * Number of degrees of freedom in a quadrilateral; not including the
- * degrees of freedom on the lines and vertices of the quadrilateral.
- */
- const unsigned int dofs_per_quad;
-
-private:
- /**
- * Maximum number of degrees of freedom on any quad.
- */
- const unsigned int dofs_per_quad_max;
-
-public:
- /**
- * Number of degrees of freedom in a hexahedron; not including the degrees
- * of freedom on the quadrilaterals, lines and vertices of the hexahedron.
- */
- const unsigned int dofs_per_hex;
-
- /**
- * First index of dof on a line.
- */
- const unsigned int first_line_index;
-
-private:
- /**
- * First index of a quad. If all quads have the same number of degrees of
- * freedom, only the first index of the first quad is stored since the
- * indices of the others can be simply recomputed.
- */
- const std::vector<unsigned int> first_index_of_quads;
-
-public:
- /**
- * First index of dof on a quad.
- */
- const unsigned int first_quad_index;
-
- /**
- * First index of dof on a hexahedron.
- */
- const unsigned int first_hex_index;
-
-private:
- /**
- * Index of the first line of all faces.
- */
- const std::vector<unsigned int> first_line_index_of_faces;
-
-public:
- /**
- * First index of dof on a line for face data.
- */
- const unsigned int first_face_line_index;
-
-private:
- /**
- * Index of the first quad of all faces.
- */
- const std::vector<unsigned int> first_quad_index_of_faces;
-
-public:
- /**
- * First index of dof on a quad for face data.
- */
- const unsigned int first_face_quad_index;
-
-private:
- /**
- * Number of degrees of freedom on faces. If all faces have the same
- * number of degrees freedoms the values equal dofs_per_quad.
- */
- const std::vector<unsigned int> n_dofs_on_face;
-
-public:
- /**
- * Number of degrees of freedom on a face. This is the accumulated number of
- * degrees of freedom on all the objects of dimension up to <tt>dim-1</tt>
- * constituting a face.
- */
- const unsigned int dofs_per_face;
-
-private:
- /**
- * Maximum number of degrees of freedom on any face.
- */
- const unsigned int dofs_per_face_max;
-
-public:
- /**
- * Total number of degrees of freedom on a cell. This is the accumulated
- * number of degrees of freedom on all the objects of dimension up to
- * <tt>dim</tt> constituting a cell.
- */
- const unsigned int dofs_per_cell;
-
- /**
- * Number of vector components of this finite element, and dimension of the
- * image space. For vector-valued finite elements (i.e. when this number is
- * greater than one), the number of vector components is in many cases equal
- * to the number of base elements glued together with the help of the
- * FESystem class. However, for elements like the Nedelec element, the
- * number is greater than one even though we only have one base element.
- */
- const unsigned int components;
-
- /**
- * Maximal polynomial degree of a shape function in a single coordinate
- * direction.
- */
- const unsigned int degree;
-
- /**
- * Indicate the space this element conforms to.
- */
- const Conformity conforming_space;
-
- /**
- * Storage for an object describing the sizes of each block of a compound
- * element. For an element which is not an FESystem, this contains only a
- * single block with length #dofs_per_cell.
- */
- const BlockIndices block_indices_data;
-
- /**
- * Constructor, computing all necessary values from the distribution of dofs
- * to geometrical objects.
- *
- * @param[in] dofs_per_object A vector that describes the number of degrees
- * of freedom on geometrical objects for each dimension. This vector must
- * have size dim+1, and entry 0 describes the number of degrees of freedom
- * per vertex, entry 1 the number of degrees of freedom per line, etc. As an
- * example, for the common $Q_1$ Lagrange element in 2d, this vector would
- * have elements <code>(1,0,0)</code>. On the other hand, for a $Q_3$
- * element in 3d, it would have entries <code>(1,2,4,8)</code>.
- *
- * @param[in] n_components Number of vector components of the element.
- *
- * @param[in] degree The maximal polynomial degree of any of the shape
- * functions of this element in any variable on the reference element. For
- * example, for the $Q_1$ element (in any space dimension), this would be
- * one; this is so despite the fact that the element has a shape function of
- * the form $\hat x\hat y$ (in 2d) and $\hat x\hat y\hat z$ (in 3d), which,
- * although quadratic and cubic polynomials, are still only linear in each
- * reference variable separately. The information provided by this variable
- * is typically used in determining what an appropriate quadrature formula
- * is.
- *
- * @param[in] conformity A variable describing which Sobolev space this
- * element conforms to. For example, the $Q_p$ Lagrange elements
- * (implemented by the FE_Q class) are $H^1$ conforming, whereas the
- * Raviart-Thomas element (implemented by the FE_RaviartThomas class) is
- * $H_\text{div}$ conforming; finally, completely discontinuous elements
- * (implemented by the FE_DGQ class) are only $L_2$ conforming.
- *
- * @param[in] block_indices An argument that describes how the base elements
- * of a finite element are grouped. The default value constructs a single
- * block that consists of all @p dofs_per_cell degrees of freedom. This is
- * appropriate for all "atomic" elements (including non-primitive ones) and
- * these can therefore omit this argument. On the other hand, composed
- * elements such as FESystem will want to pass a different value here.
- */
- FiniteElementData(const std::vector<unsigned int> &dofs_per_object,
- const unsigned int n_components,
- const unsigned int degree,
- const Conformity conformity = unknown,
- const BlockIndices &block_indices = BlockIndices());
-
- /**
- * The same as above but with the difference that also the type of the
- * underlying geometric entity can be specified.
- */
- FiniteElementData(const std::vector<unsigned int> &dofs_per_object,
- const ReferenceCell reference_cell,
- const unsigned int n_components,
- const unsigned int degree,
- const Conformity conformity = unknown,
- const BlockIndices &block_indices = BlockIndices());
-
- /**
- * The same as above but instead of passing a vector containing the degrees
- * of freedoms per object a struct of type GenericDoFsPerObject. This allows
- * that 2D objects might have different number of degrees of freedoms, which
- * is particular useful for cells with triangles and quadrilaterals as faces.
- */
- FiniteElementData(const internal::GenericDoFsPerObject &data,
- const ReferenceCell reference_cell,
- const unsigned int n_components,
- const unsigned int degree,
- const Conformity conformity = unknown,
- const BlockIndices &block_indices = BlockIndices());
-
- /**
- * Return the kind of reference cell this element is defined on: For
- * example, whether the element's reference cell is a square or
- * triangle, or similar choices in higher dimensions.
- */
- ReferenceCell
- reference_cell() const;
-
- /**
- * Number of unique quads. If all quads have the same type, the value is
- * one; else it equals the number of quads.
- */
- unsigned int
- n_unique_quads() const;
-
- /**
- * Number of unique faces. If all faces have the same type, the value is
- * one; else it equals the number of faces.
- */
- unsigned int
- n_unique_faces() const;
-
- /**
- * Number of dofs per vertex.
- */
- unsigned int
- n_dofs_per_vertex() const;
-
- /**
- * Number of dofs per line. Not including dofs on lower dimensional objects.
- */
- unsigned int
- n_dofs_per_line() const;
-
- /**
- * Number of dofs per quad. Not including dofs on lower dimensional objects.
- */
- unsigned int
- n_dofs_per_quad(unsigned int face_no = 0) const;
-
- /**
- * Maximum number of dofs per quad. Not including dofs on lower dimensional
- * objects.
- */
- unsigned int
- max_dofs_per_quad() const;
-
- /**
- * Number of dofs per hex. Not including dofs on lower dimensional objects.
- */
- unsigned int
- n_dofs_per_hex() const;
-
- /**
- * Number of dofs per face, accumulating degrees of freedom of all lower
- * dimensional objects.
- */
- unsigned int
- n_dofs_per_face(unsigned int face_no = 0, unsigned int child = 0) const;
-
- /**
- * Maximum number of dofs per face, accumulating degrees of freedom of all
- * lower dimensional objects.
- */
- unsigned int
- max_dofs_per_face() const;
-
- /**
- * Number of dofs per cell, accumulating degrees of freedom of all lower
- * dimensional objects.
- */
- unsigned int
- n_dofs_per_cell() const;
-
- /**
- * Return the number of degrees per structdim-dimensional object. For
- * structdim==0, the function therefore returns dofs_per_vertex, for
- * structdim==1 dofs_per_line, etc. This function is mostly used to allow
- * some template trickery for functions that should work on all sorts of
- * objects without wanting to use the different names (vertex, line, ...)
- * associated with these objects.
- */
- template <int structdim>
- unsigned int
- n_dofs_per_object(const unsigned int i = 0) const;
-
- /**
- * Number of components. See
- * @ref GlossComponent "the glossary"
- * for more information.
- */
- unsigned int
- n_components() const;
-
- /**
- * Number of blocks. See
- * @ref GlossBlock "the glossary"
- * for more information.
- */
- unsigned int
- n_blocks() const;
-
- /**
- * Detailed information on block sizes.
- */
- const BlockIndices &
- block_indices() const;
-
- /**
- * Maximal polynomial degree of a shape function in a single coordinate
- * direction.
- *
- * This function can be used to determine the optimal quadrature rule.
- */
- unsigned int
- tensor_degree() const;
-
- /**
- * Test whether a finite element space conforms to a certain Sobolev space.
- *
- * @note This function will return a true value even if the finite element
- * space has higher regularity than asked for.
- */
- bool
- conforms(const Conformity) const;
-
- /**
- * Comparison operator.
- */
- bool
- operator==(const FiniteElementData &) const;
-
- /**
- * Return first index of dof on a line.
- */
- unsigned int
- get_first_line_index() const;
-
- /**
- * Return first index of dof on a quad.
- */
- unsigned int
- get_first_quad_index(const unsigned int quad_no = 0) const;
-
- /**
- * Return first index of dof on a hexahedron.
- */
- unsigned int
- get_first_hex_index() const;
-
- /**
- * Return first index of dof on a line for face data.
- */
- unsigned int
- get_first_face_line_index(const unsigned int face_no = 0) const;
-
- /**
- * Return first index of dof on a quad for face data.
- */
- unsigned int
- get_first_face_quad_index(const unsigned int face_no = 0) const;
-};
-
-namespace internal
-{
- /**
- * Utility function to convert "dofs per object" information
- * of a @p dim dimensional reference cell @p reference_cell.
- */
- internal::GenericDoFsPerObject
- expand(const unsigned int dim,
- const std::vector<unsigned int> &dofs_per_object,
- const dealii::ReferenceCell reference_cell);
-} // namespace internal
-
-
-
-// --------- inline and template functions ---------------
-
-
-#ifndef DOXYGEN
-
-namespace FiniteElementDomination
-{
- inline Domination
- operator&(const Domination d1, const Domination d2)
- {
- // go through the entire list of possibilities. note that if we were into
- // speed, obfuscation and cared enough, we could implement this operator
- // by doing a bitwise & (and) if we gave these values to the enum values:
- // neither_element_dominates=0, this_element_dominates=1,
- // other_element_dominates=2, either_element_can_dominate=3
- // =this_element_dominates|other_element_dominates
- switch (d1)
- {
- case this_element_dominates:
- if ((d2 == this_element_dominates) ||
- (d2 == either_element_can_dominate) || (d2 == no_requirements))
- return this_element_dominates;
- else
- return neither_element_dominates;
-
- case other_element_dominates:
- if ((d2 == other_element_dominates) ||
- (d2 == either_element_can_dominate) || (d2 == no_requirements))
- return other_element_dominates;
- else
- return neither_element_dominates;
-
- case neither_element_dominates:
- return neither_element_dominates;
-
- case either_element_can_dominate:
- if (d2 == no_requirements)
- return either_element_can_dominate;
- else
- return d2;
-
- case no_requirements:
- return d2;
-
- default:
- // shouldn't get here
- Assert(false, ExcInternalError());
- }
-
- return neither_element_dominates;
- }
-} // namespace FiniteElementDomination
-
-
-template <int dim>
-inline ReferenceCell
-FiniteElementData<dim>::reference_cell() const
-{
- return reference_cell_kind;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_unique_quads() const
-{
- return number_unique_quads;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_unique_faces() const
-{
- return number_unique_faces;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_vertex() const
-{
- return dofs_per_vertex;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_line() const
-{
- return dofs_per_line;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_quad(unsigned int face_no) const
-{
- return n_dofs_on_quad[n_dofs_on_quad.size() == 1 ? 0 : face_no];
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::max_dofs_per_quad() const
-{
- return dofs_per_quad_max;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_hex() const
-{
- return dofs_per_hex;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_face(unsigned int face_no,
- unsigned int child_no) const
-{
- (void)child_no;
-
- return n_dofs_on_face[n_dofs_on_face.size() == 1 ? 0 : face_no];
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::max_dofs_per_face() const
-{
- return dofs_per_face_max;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_cell() const
-{
- return dofs_per_cell;
-}
-
-
-
-template <int dim>
-template <int structdim>
-inline unsigned int
-FiniteElementData<dim>::n_dofs_per_object(const unsigned int i) const
-{
- switch (structdim)
- {
- case 0:
- return n_dofs_per_vertex();
- case 1:
- return n_dofs_per_line();
- case 2:
- return n_dofs_per_quad((structdim == 2 && dim == 3) ? i : 0);
- case 3:
- return n_dofs_per_hex();
- default:
- Assert(false, ExcInternalError());
- }
- return numbers::invalid_unsigned_int;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_components() const
-{
- return components;
-}
-
-
-
-template <int dim>
-inline const BlockIndices &
-FiniteElementData<dim>::block_indices() const
-{
- return block_indices_data;
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::n_blocks() const
-{
- return block_indices_data.size();
-}
-
-
-
-template <int dim>
-inline unsigned int
-FiniteElementData<dim>::tensor_degree() const
-{
- return degree;
-}
-
-
-template <int dim>
-inline bool
-FiniteElementData<dim>::conforms(const Conformity space) const
-{
- return ((space & conforming_space) == space);
-}
-
-
-
-template <int dim>
-unsigned int
-FiniteElementData<dim>::get_first_line_index() const
-{
- return first_line_index;
-}
-
-template <int dim>
-unsigned int
-FiniteElementData<dim>::get_first_quad_index(const unsigned int quad_no) const
-{
- if (first_index_of_quads.size() == 1)
- return first_index_of_quads[0] + quad_no * n_dofs_per_quad(0);
- else
- return first_index_of_quads[quad_no];
-}
-
-template <int dim>
-unsigned int
-FiniteElementData<dim>::get_first_hex_index() const
-{
- return first_hex_index;
-}
-
-template <int dim>
-unsigned int
-FiniteElementData<dim>::get_first_face_line_index(
- const unsigned int face_no) const
-{
- return first_line_index_of_faces[first_line_index_of_faces.size() == 1 ?
- 0 :
- face_no];
-}
-
-template <int dim>
-unsigned int
-FiniteElementData<dim>::get_first_face_quad_index(
- const unsigned int face_no) const
-{
- return first_quad_index_of_faces[first_quad_index_of_faces.size() == 1 ?
- 0 :
- face_no];
-}
-
-template <int dim>
-internal::GenericDoFsPerObject
-internal::GenericDoFsPerObject::generate(const FiniteElementData<dim> &fe)
-{
- const auto reference_cell = fe.reference_cell();
-
- internal::GenericDoFsPerObject result;
-
- result.dofs_per_object_exclusive.resize(4);
- result.dofs_per_object_inclusive.resize(4);
- result.object_index.resize(4);
-
- unsigned int counter = 0;
-
- for (unsigned int v : reference_cell.vertex_indices())
- {
- const auto c = fe.template n_dofs_per_object<0>(v);
-
- result.dofs_per_object_exclusive[0].emplace_back(c);
- result.dofs_per_object_inclusive[0].emplace_back(c);
- result.object_index[0].emplace_back(counter);
-
- counter += c;
- }
-
- if (dim >= 2)
- for (unsigned int l : reference_cell.line_indices())
- {
- const auto c = fe.template n_dofs_per_object<1>(l);
-
- result.dofs_per_object_exclusive[1].emplace_back(c);
- result.dofs_per_object_inclusive[1].emplace_back(
- c + 2 * fe.template n_dofs_per_object<0>());
- result.object_index[1].emplace_back(counter);
-
- counter += c;
- }
-
- if (dim == 3)
- for (unsigned int f : reference_cell.face_indices())
- {
- const auto c = fe.template n_dofs_per_object<2>(f);
-
- result.dofs_per_object_exclusive[2].emplace_back(c);
- result.dofs_per_object_inclusive[2].emplace_back(fe.n_dofs_per_face(f));
- result.object_index[2].emplace_back(counter);
-
- counter += c;
- }
-
- {
- const auto c = fe.template n_dofs_per_object<dim>();
-
- result.dofs_per_object_exclusive[dim].emplace_back(c);
- result.dofs_per_object_inclusive[dim].emplace_back(fe.n_dofs_per_cell());
- result.object_index[dim].emplace_back(counter);
-
- counter += c;
- }
-
- for (unsigned int d = dim + 1; d <= 3; ++d)
- {
- result.dofs_per_object_exclusive[d].emplace_back(0);
- result.dofs_per_object_inclusive[d].emplace_back(0);
- result.object_index[d].emplace_back(counter);
- }
-
- result.first_object_index_on_face.resize(3);
- for (unsigned int face_no : reference_cell.face_indices())
- {
- result.first_object_index_on_face[0].emplace_back(0);
-
- result.first_object_index_on_face[1].emplace_back(
- fe.get_first_face_line_index(face_no));
-
- result.first_object_index_on_face[2].emplace_back(
- fe.get_first_face_quad_index(face_no));
- }
-
- return result;
-}
-
-
-#endif // DOXYGEN
-
-
-DEAL_II_NAMESPACE_CLOSE
+DEAL_II_WARNING("This file is deprecated. Simply use <deal.II/fe/fe_data.h>.")
#endif
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2000 - 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 dealii_fe_data_h
+#define dealii_fe_data_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/exceptions.h>
+
+#include <deal.II/grid/reference_cell.h>
+
+#include <deal.II/lac/block_indices.h>
+
+#include <vector>
+
+DEAL_II_NAMESPACE_OPEN
+
+// Forward declarations:
+#ifndef DOXYGEN
+template <int dim>
+class FiniteElementData;
+#endif
+
+/**
+ * A namespace solely for the purpose of defining the Domination enum as well
+ * as associated operators.
+ */
+namespace FiniteElementDomination
+{
+ /**
+ * An enum that describes the outcome of comparing two elements for mutual
+ * domination. If one element dominates another, then the restriction of the
+ * space described by the dominated element to a face of the cell is
+ * strictly larger than that of the dominating element. For example, in 2-d
+ * Q(2) elements dominate Q(4) elements, because the traces of Q(4) elements
+ * are quartic polynomials which is a space strictly larger than the
+ * quadratic polynomials (the restriction of the Q(2) element). Similar
+ * reasonings apply for vertices and cells as well. In general, Q(k) dominates
+ * Q(k') if $k\le k'$.
+ *
+ * This enum is used in the FiniteElement::compare_for_domination() function
+ * that is used in the context of hp-finite element methods when determining
+ * what to do at faces where two different finite elements meet (see the
+ * @ref hp_paper "hp-paper"
+ * for a more detailed description of the following). In that case, the
+ * degrees of freedom of one side need to be constrained to those on the
+ * other side. The determination which side is which is based on the outcome
+ * of a comparison for mutual domination: the dominated side is constrained
+ * to the dominating one.
+ *
+ * Note that there are situations where neither side dominates. The
+ * @ref hp_paper "hp-paper"
+ * lists two case, with the simpler one being that a $Q_2\times Q_1$ vector-
+ * valued element (i.e. a <code>FESystem(FE_Q(2),1,FE_Q(1),1)</code>) meets
+ * a $Q_1\times Q_2$ element: here, for each of the two vector-components,
+ * we can define a domination relationship, but it is different for the two
+ * components.
+ *
+ * It is clear that the concept of domination doesn't matter for
+ * discontinuous elements. However, discontinuous elements may be part of
+ * vector-valued elements and may therefore be compared against each other
+ * for domination. They should return
+ * <code>either_element_can_dominate</code> in that case. Likewise, when
+ * comparing two identical finite elements, they should return this code;
+ * the reason is that we can not decide which element will dominate at the
+ * time we look at the first component of, for example, two $Q_2\times Q_1$
+ * and $Q_2\times Q_2$ elements, and have to keep our options open until we
+ * get to the second base element.
+ *
+ * Finally, the code no_requirements exists for cases where elements impose
+ * no continuity requirements. The case is primarily meant for FE_Nothing
+ * which is an element that has no degrees of freedom in a subdomain. It
+ * could also be used by discontinuous elements, for example.
+ *
+ * More details on domination can be found in the
+ * @ref hp_paper "hp-paper".
+ */
+ enum Domination
+ {
+ /**
+ * The current element dominates.
+ */
+ this_element_dominates,
+ /**
+ * The other element dominates.
+ */
+ other_element_dominates,
+ /**
+ * Neither element dominates.
+ */
+ neither_element_dominates,
+ /**
+ * Either element may dominate.
+ */
+ either_element_can_dominate,
+ /**
+ * There are no requirements.
+ */
+ no_requirements
+ };
+
+
+ /**
+ * A generalization of the binary <code>and</code> operator to a comparison
+ * relationship. The way this works is pretty much as when you would want to
+ * define a comparison relationship for vectors: either all elements of the
+ * first vector are smaller, equal, or larger than those of the second
+ * vector, or some are and some are not.
+ *
+ * This operator is pretty much the same: if both arguments are
+ * <code>this_element_dominates</code> or
+ * <code>other_element_dominates</code>, then the returned value is that
+ * value. On the other hand, if one of the values is
+ * <code>either_element_can_dominate</code>, then the returned value is that
+ * of the other argument. If either argument is
+ * <code>neither_element_dominates</code>, or if the two arguments are
+ * <code>this_element_dominates</code> and
+ * <code>other_element_dominates</code>, then the returned value is
+ * <code>neither_element_dominates</code>.
+ */
+ inline Domination
+ operator&(const Domination d1, const Domination d2);
+} // namespace FiniteElementDomination
+
+namespace internal
+{
+ /**
+ * Internal data structure for setting up FiniteElementData. It stores for
+ * each object the (inclusive/exclusive) number of degrees of freedoms, as
+ * well as, the index of its first degree of freedom within a cell and the
+ * index of the first d-dimensional object within each face.
+ *
+ * The information is saved as a vector of vectors. One can query the
+ * inclusive number of dofs of the i-th d-dimensional object via:
+ * dofs_per_object_inclusive[d][i].
+ *
+ * As an example, the data is shown for a quadratic wedge. Which consists of
+ * 6 vertices, 9 lines, and 5 faces (two triangles and three quadrilaterals).
+ * @code
+ * vertices lines faces cell
+ * dpo_excl 1 1 1 1 1 1 | 1 1 1 1 1 1 1 1 1 | 0 0 1 1 1 | 0
+ * dpo_incl 1 1 1 1 1 1 | 3 3 3 3 3 3 3 3 3 | 6 6 9 9 9 | 18
+ * obj_index 0 1 2 3 4 5 | 6 7 8 9 10 11 12 13 14 | 15 15 15 16 17 | 18
+ * @endcode
+ *
+ * Since the above table looks as follows for:
+ *
+ * - a triangle:
+ * @code
+ * dpo_excl 1 1 1 | 1 1 1 | 0
+ * obj_index 0 1 2 | 3 4 5 | 6
+ * @endcode
+ *
+ * - quadrilateral:
+ * @code
+ * dpo_excl 1 1 1 1 | 1 1 1 1 | 1
+ * obj_index 0 1 2 3 | 4 5 6 7 | 8
+ * @endcode
+ *
+ * The index of the first d-dimensional object within each face results as:
+ * @code
+ * vertices lines face
+ * first_obj_index_on_face 0 0 0 0 0 | 3 3 4 4 4 | 6 6 8 8 8
+ * @endcode
+ *
+ */
+ struct GenericDoFsPerObject
+ {
+ /**
+ * Exclusive number of degrees of freedom per object.
+ */
+ std::vector<std::vector<unsigned int>> dofs_per_object_exclusive;
+
+ /**
+ * Inclusive number of degrees of freedom per object.
+ */
+ std::vector<std::vector<unsigned int>> dofs_per_object_inclusive;
+
+ /**
+ * First index of an object.
+ */
+ std::vector<std::vector<unsigned int>> object_index;
+
+ /**
+ * First index of an object within a face.
+ */
+ std::vector<std::vector<unsigned int>> first_object_index_on_face;
+
+ /**
+ * Function that fills the fields based on a provided finite element.
+ */
+ template <int dim>
+ static GenericDoFsPerObject
+ generate(const FiniteElementData<dim> &fe);
+ };
+} // namespace internal
+
+/**
+ * A class that declares a number of scalar constant variables that describe
+ * basic properties of a finite element implementation. This includes, for
+ * example, the number of degrees of freedom per vertex, line, or cell; the
+ * number of vector components; etc.
+ *
+ * The kind of information stored here is computed during initialization of a
+ * finite element object and is passed down to this class via its constructor.
+ * The data stored by this class is part of the public interface of the
+ * FiniteElement class (which derives from the current class). See there for
+ * more information.
+ *
+ * @ingroup febase
+ */
+template <int dim>
+class FiniteElementData
+{
+public:
+ /**
+ * Enumerator for the different types of continuity a finite element may
+ * have. Continuity is measured by the Sobolev space containing the
+ * constructed finite element space and is also called this way.
+ *
+ * Note that certain continuities may imply others. For instance, a function
+ * in <i>H<sup>1</sup></i> is in <i>H<sup>curl</sup></i> and
+ * <i>H<sup>div</sup></i> as well.
+ *
+ * If you are interested in continuity in the classical sense, then the
+ * following relations hold:
+ *
+ * <ol>
+ *
+ * <li> <i>H<sup>1</sup></i> implies that the function is continuous over
+ * cell boundaries.
+ *
+ * <li> <i>H<sup>2</sup></i> implies that the function is continuously
+ * differentiable over cell boundaries.
+ *
+ * <li> <i>L<sup>2</sup></i> indicates that the element is discontinuous.
+ * Since discontinuous elements have no topological couplings between grid
+ * cells and code may actually depend on this property, <i>L<sup>2</sup></i>
+ * conformity is handled in a special way in the sense that it is <b>not</b>
+ * implied by any higher conformity.
+ * </ol>
+ *
+ * In order to test if a finite element conforms to a certain space, use
+ * FiniteElementData<dim>::conforms().
+ */
+ enum Conformity
+ {
+ /**
+ * Indicates incompatible continuities of a system.
+ */
+ unknown = 0x00,
+
+ /**
+ * Discontinuous elements. See above!
+ */
+ L2 = 0x01,
+
+ /**
+ * Conformity with the space <i>H<sup>curl</sup></i> (continuous
+ * tangential component of a vector field)
+ */
+ Hcurl = 0x02,
+
+ /**
+ * Conformity with the space <i>H<sup>div</sup></i> (continuous normal
+ * component of a vector field)
+ */
+ Hdiv = 0x04,
+
+ /**
+ * Conformity with the space <i>H<sup>1</sup></i> (continuous)
+ */
+ H1 = Hcurl | Hdiv,
+
+ /**
+ * Conformity with the space <i>H<sup>2</sup></i> (continuously
+ * differentiable)
+ */
+ H2 = 0x0e
+ };
+
+ /**
+ * The dimension of the finite element, which is the template parameter
+ * <tt>dim</tt>
+ */
+ static constexpr unsigned int dimension = dim;
+
+private:
+ /**
+ * Reference cell type.
+ */
+ const ReferenceCell reference_cell_kind;
+
+ /**
+ * Number of unique quads. If all quads have the same type, the value is
+ * one; else it equals the number of quads.
+ */
+ const unsigned int number_unique_quads;
+
+ /**
+ * Number of unique faces. If all faces have the same type, the value is
+ * one; else it equals the number of faces.
+ */
+ const unsigned int number_unique_faces;
+
+public:
+ /**
+ * Number of degrees of freedom on a vertex.
+ */
+ const unsigned int dofs_per_vertex;
+
+ /**
+ * Number of degrees of freedom in a line; not including the degrees of
+ * freedom on the vertices of the line.
+ */
+ const unsigned int dofs_per_line;
+
+private:
+ /**
+ * Number of degrees of freedom on quads. If all quads have the same
+ * number of degrees freedoms the values equal dofs_per_quad.
+ */
+ const std::vector<unsigned int> n_dofs_on_quad;
+
+public:
+ /**
+ * Number of degrees of freedom in a quadrilateral; not including the
+ * degrees of freedom on the lines and vertices of the quadrilateral.
+ */
+ const unsigned int dofs_per_quad;
+
+private:
+ /**
+ * Maximum number of degrees of freedom on any quad.
+ */
+ const unsigned int dofs_per_quad_max;
+
+public:
+ /**
+ * Number of degrees of freedom in a hexahedron; not including the degrees
+ * of freedom on the quadrilaterals, lines and vertices of the hexahedron.
+ */
+ const unsigned int dofs_per_hex;
+
+ /**
+ * First index of dof on a line.
+ */
+ const unsigned int first_line_index;
+
+private:
+ /**
+ * First index of a quad. If all quads have the same number of degrees of
+ * freedom, only the first index of the first quad is stored since the
+ * indices of the others can be simply recomputed.
+ */
+ const std::vector<unsigned int> first_index_of_quads;
+
+public:
+ /**
+ * First index of dof on a quad.
+ */
+ const unsigned int first_quad_index;
+
+ /**
+ * First index of dof on a hexahedron.
+ */
+ const unsigned int first_hex_index;
+
+private:
+ /**
+ * Index of the first line of all faces.
+ */
+ const std::vector<unsigned int> first_line_index_of_faces;
+
+public:
+ /**
+ * First index of dof on a line for face data.
+ */
+ const unsigned int first_face_line_index;
+
+private:
+ /**
+ * Index of the first quad of all faces.
+ */
+ const std::vector<unsigned int> first_quad_index_of_faces;
+
+public:
+ /**
+ * First index of dof on a quad for face data.
+ */
+ const unsigned int first_face_quad_index;
+
+private:
+ /**
+ * Number of degrees of freedom on faces. If all faces have the same
+ * number of degrees freedoms the values equal dofs_per_quad.
+ */
+ const std::vector<unsigned int> n_dofs_on_face;
+
+public:
+ /**
+ * Number of degrees of freedom on a face. This is the accumulated number of
+ * degrees of freedom on all the objects of dimension up to <tt>dim-1</tt>
+ * constituting a face.
+ */
+ const unsigned int dofs_per_face;
+
+private:
+ /**
+ * Maximum number of degrees of freedom on any face.
+ */
+ const unsigned int dofs_per_face_max;
+
+public:
+ /**
+ * Total number of degrees of freedom on a cell. This is the accumulated
+ * number of degrees of freedom on all the objects of dimension up to
+ * <tt>dim</tt> constituting a cell.
+ */
+ const unsigned int dofs_per_cell;
+
+ /**
+ * Number of vector components of this finite element, and dimension of the
+ * image space. For vector-valued finite elements (i.e. when this number is
+ * greater than one), the number of vector components is in many cases equal
+ * to the number of base elements glued together with the help of the
+ * FESystem class. However, for elements like the Nedelec element, the
+ * number is greater than one even though we only have one base element.
+ */
+ const unsigned int components;
+
+ /**
+ * Maximal polynomial degree of a shape function in a single coordinate
+ * direction.
+ */
+ const unsigned int degree;
+
+ /**
+ * Indicate the space this element conforms to.
+ */
+ const Conformity conforming_space;
+
+ /**
+ * Storage for an object describing the sizes of each block of a compound
+ * element. For an element which is not an FESystem, this contains only a
+ * single block with length #dofs_per_cell.
+ */
+ const BlockIndices block_indices_data;
+
+ /**
+ * Constructor, computing all necessary values from the distribution of dofs
+ * to geometrical objects.
+ *
+ * @param[in] dofs_per_object A vector that describes the number of degrees
+ * of freedom on geometrical objects for each dimension. This vector must
+ * have size dim+1, and entry 0 describes the number of degrees of freedom
+ * per vertex, entry 1 the number of degrees of freedom per line, etc. As an
+ * example, for the common $Q_1$ Lagrange element in 2d, this vector would
+ * have elements <code>(1,0,0)</code>. On the other hand, for a $Q_3$
+ * element in 3d, it would have entries <code>(1,2,4,8)</code>.
+ *
+ * @param[in] n_components Number of vector components of the element.
+ *
+ * @param[in] degree The maximal polynomial degree of any of the shape
+ * functions of this element in any variable on the reference element. For
+ * example, for the $Q_1$ element (in any space dimension), this would be
+ * one; this is so despite the fact that the element has a shape function of
+ * the form $\hat x\hat y$ (in 2d) and $\hat x\hat y\hat z$ (in 3d), which,
+ * although quadratic and cubic polynomials, are still only linear in each
+ * reference variable separately. The information provided by this variable
+ * is typically used in determining what an appropriate quadrature formula
+ * is.
+ *
+ * @param[in] conformity A variable describing which Sobolev space this
+ * element conforms to. For example, the $Q_p$ Lagrange elements
+ * (implemented by the FE_Q class) are $H^1$ conforming, whereas the
+ * Raviart-Thomas element (implemented by the FE_RaviartThomas class) is
+ * $H_\text{div}$ conforming; finally, completely discontinuous elements
+ * (implemented by the FE_DGQ class) are only $L_2$ conforming.
+ *
+ * @param[in] block_indices An argument that describes how the base elements
+ * of a finite element are grouped. The default value constructs a single
+ * block that consists of all @p dofs_per_cell degrees of freedom. This is
+ * appropriate for all "atomic" elements (including non-primitive ones) and
+ * these can therefore omit this argument. On the other hand, composed
+ * elements such as FESystem will want to pass a different value here.
+ */
+ FiniteElementData(const std::vector<unsigned int> &dofs_per_object,
+ const unsigned int n_components,
+ const unsigned int degree,
+ const Conformity conformity = unknown,
+ const BlockIndices &block_indices = BlockIndices());
+
+ /**
+ * The same as above but with the difference that also the type of the
+ * underlying geometric entity can be specified.
+ */
+ FiniteElementData(const std::vector<unsigned int> &dofs_per_object,
+ const ReferenceCell reference_cell,
+ const unsigned int n_components,
+ const unsigned int degree,
+ const Conformity conformity = unknown,
+ const BlockIndices &block_indices = BlockIndices());
+
+ /**
+ * The same as above but instead of passing a vector containing the degrees
+ * of freedoms per object a struct of type GenericDoFsPerObject. This allows
+ * that 2D objects might have different number of degrees of freedoms, which
+ * is particular useful for cells with triangles and quadrilaterals as faces.
+ */
+ FiniteElementData(const internal::GenericDoFsPerObject &data,
+ const ReferenceCell reference_cell,
+ const unsigned int n_components,
+ const unsigned int degree,
+ const Conformity conformity = unknown,
+ const BlockIndices &block_indices = BlockIndices());
+
+ /**
+ * Return the kind of reference cell this element is defined on: For
+ * example, whether the element's reference cell is a square or
+ * triangle, or similar choices in higher dimensions.
+ */
+ ReferenceCell
+ reference_cell() const;
+
+ /**
+ * Number of unique quads. If all quads have the same type, the value is
+ * one; else it equals the number of quads.
+ */
+ unsigned int
+ n_unique_quads() const;
+
+ /**
+ * Number of unique faces. If all faces have the same type, the value is
+ * one; else it equals the number of faces.
+ */
+ unsigned int
+ n_unique_faces() const;
+
+ /**
+ * Number of dofs per vertex.
+ */
+ unsigned int
+ n_dofs_per_vertex() const;
+
+ /**
+ * Number of dofs per line. Not including dofs on lower dimensional objects.
+ */
+ unsigned int
+ n_dofs_per_line() const;
+
+ /**
+ * Number of dofs per quad. Not including dofs on lower dimensional objects.
+ */
+ unsigned int
+ n_dofs_per_quad(unsigned int face_no = 0) const;
+
+ /**
+ * Maximum number of dofs per quad. Not including dofs on lower dimensional
+ * objects.
+ */
+ unsigned int
+ max_dofs_per_quad() const;
+
+ /**
+ * Number of dofs per hex. Not including dofs on lower dimensional objects.
+ */
+ unsigned int
+ n_dofs_per_hex() const;
+
+ /**
+ * Number of dofs per face, accumulating degrees of freedom of all lower
+ * dimensional objects.
+ */
+ unsigned int
+ n_dofs_per_face(unsigned int face_no = 0, unsigned int child = 0) const;
+
+ /**
+ * Maximum number of dofs per face, accumulating degrees of freedom of all
+ * lower dimensional objects.
+ */
+ unsigned int
+ max_dofs_per_face() const;
+
+ /**
+ * Number of dofs per cell, accumulating degrees of freedom of all lower
+ * dimensional objects.
+ */
+ unsigned int
+ n_dofs_per_cell() const;
+
+ /**
+ * Return the number of degrees per structdim-dimensional object. For
+ * structdim==0, the function therefore returns dofs_per_vertex, for
+ * structdim==1 dofs_per_line, etc. This function is mostly used to allow
+ * some template trickery for functions that should work on all sorts of
+ * objects without wanting to use the different names (vertex, line, ...)
+ * associated with these objects.
+ */
+ template <int structdim>
+ unsigned int
+ n_dofs_per_object(const unsigned int i = 0) const;
+
+ /**
+ * Number of components. See
+ * @ref GlossComponent "the glossary"
+ * for more information.
+ */
+ unsigned int
+ n_components() const;
+
+ /**
+ * Number of blocks. See
+ * @ref GlossBlock "the glossary"
+ * for more information.
+ */
+ unsigned int
+ n_blocks() const;
+
+ /**
+ * Detailed information on block sizes.
+ */
+ const BlockIndices &
+ block_indices() const;
+
+ /**
+ * Maximal polynomial degree of a shape function in a single coordinate
+ * direction.
+ *
+ * This function can be used to determine the optimal quadrature rule.
+ */
+ unsigned int
+ tensor_degree() const;
+
+ /**
+ * Test whether a finite element space conforms to a certain Sobolev space.
+ *
+ * @note This function will return a true value even if the finite element
+ * space has higher regularity than asked for.
+ */
+ bool
+ conforms(const Conformity) const;
+
+ /**
+ * Comparison operator.
+ */
+ bool
+ operator==(const FiniteElementData &) const;
+
+ /**
+ * Return first index of dof on a line.
+ */
+ unsigned int
+ get_first_line_index() const;
+
+ /**
+ * Return first index of dof on a quad.
+ */
+ unsigned int
+ get_first_quad_index(const unsigned int quad_no = 0) const;
+
+ /**
+ * Return first index of dof on a hexahedron.
+ */
+ unsigned int
+ get_first_hex_index() const;
+
+ /**
+ * Return first index of dof on a line for face data.
+ */
+ unsigned int
+ get_first_face_line_index(const unsigned int face_no = 0) const;
+
+ /**
+ * Return first index of dof on a quad for face data.
+ */
+ unsigned int
+ get_first_face_quad_index(const unsigned int face_no = 0) const;
+};
+
+namespace internal
+{
+ /**
+ * Utility function to convert "dofs per object" information
+ * of a @p dim dimensional reference cell @p reference_cell.
+ */
+ internal::GenericDoFsPerObject
+ expand(const unsigned int dim,
+ const std::vector<unsigned int> &dofs_per_object,
+ const dealii::ReferenceCell reference_cell);
+} // namespace internal
+
+
+
+// --------- inline and template functions ---------------
+
+
+#ifndef DOXYGEN
+
+namespace FiniteElementDomination
+{
+ inline Domination
+ operator&(const Domination d1, const Domination d2)
+ {
+ // go through the entire list of possibilities. note that if we were into
+ // speed, obfuscation and cared enough, we could implement this operator
+ // by doing a bitwise & (and) if we gave these values to the enum values:
+ // neither_element_dominates=0, this_element_dominates=1,
+ // other_element_dominates=2, either_element_can_dominate=3
+ // =this_element_dominates|other_element_dominates
+ switch (d1)
+ {
+ case this_element_dominates:
+ if ((d2 == this_element_dominates) ||
+ (d2 == either_element_can_dominate) || (d2 == no_requirements))
+ return this_element_dominates;
+ else
+ return neither_element_dominates;
+
+ case other_element_dominates:
+ if ((d2 == other_element_dominates) ||
+ (d2 == either_element_can_dominate) || (d2 == no_requirements))
+ return other_element_dominates;
+ else
+ return neither_element_dominates;
+
+ case neither_element_dominates:
+ return neither_element_dominates;
+
+ case either_element_can_dominate:
+ if (d2 == no_requirements)
+ return either_element_can_dominate;
+ else
+ return d2;
+
+ case no_requirements:
+ return d2;
+
+ default:
+ // shouldn't get here
+ Assert(false, ExcInternalError());
+ }
+
+ return neither_element_dominates;
+ }
+} // namespace FiniteElementDomination
+
+
+template <int dim>
+inline ReferenceCell
+FiniteElementData<dim>::reference_cell() const
+{
+ return reference_cell_kind;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_unique_quads() const
+{
+ return number_unique_quads;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_unique_faces() const
+{
+ return number_unique_faces;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_vertex() const
+{
+ return dofs_per_vertex;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_line() const
+{
+ return dofs_per_line;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_quad(unsigned int face_no) const
+{
+ return n_dofs_on_quad[n_dofs_on_quad.size() == 1 ? 0 : face_no];
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::max_dofs_per_quad() const
+{
+ return dofs_per_quad_max;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_hex() const
+{
+ return dofs_per_hex;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_face(unsigned int face_no,
+ unsigned int child_no) const
+{
+ (void)child_no;
+
+ return n_dofs_on_face[n_dofs_on_face.size() == 1 ? 0 : face_no];
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::max_dofs_per_face() const
+{
+ return dofs_per_face_max;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_cell() const
+{
+ return dofs_per_cell;
+}
+
+
+
+template <int dim>
+template <int structdim>
+inline unsigned int
+FiniteElementData<dim>::n_dofs_per_object(const unsigned int i) const
+{
+ switch (structdim)
+ {
+ case 0:
+ return n_dofs_per_vertex();
+ case 1:
+ return n_dofs_per_line();
+ case 2:
+ return n_dofs_per_quad((structdim == 2 && dim == 3) ? i : 0);
+ case 3:
+ return n_dofs_per_hex();
+ default:
+ Assert(false, ExcInternalError());
+ }
+ return numbers::invalid_unsigned_int;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_components() const
+{
+ return components;
+}
+
+
+
+template <int dim>
+inline const BlockIndices &
+FiniteElementData<dim>::block_indices() const
+{
+ return block_indices_data;
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::n_blocks() const
+{
+ return block_indices_data.size();
+}
+
+
+
+template <int dim>
+inline unsigned int
+FiniteElementData<dim>::tensor_degree() const
+{
+ return degree;
+}
+
+
+template <int dim>
+inline bool
+FiniteElementData<dim>::conforms(const Conformity space) const
+{
+ return ((space & conforming_space) == space);
+}
+
+
+
+template <int dim>
+unsigned int
+FiniteElementData<dim>::get_first_line_index() const
+{
+ return first_line_index;
+}
+
+template <int dim>
+unsigned int
+FiniteElementData<dim>::get_first_quad_index(const unsigned int quad_no) const
+{
+ if (first_index_of_quads.size() == 1)
+ return first_index_of_quads[0] + quad_no * n_dofs_per_quad(0);
+ else
+ return first_index_of_quads[quad_no];
+}
+
+template <int dim>
+unsigned int
+FiniteElementData<dim>::get_first_hex_index() const
+{
+ return first_hex_index;
+}
+
+template <int dim>
+unsigned int
+FiniteElementData<dim>::get_first_face_line_index(
+ const unsigned int face_no) const
+{
+ return first_line_index_of_faces[first_line_index_of_faces.size() == 1 ?
+ 0 :
+ face_no];
+}
+
+template <int dim>
+unsigned int
+FiniteElementData<dim>::get_first_face_quad_index(
+ const unsigned int face_no) const
+{
+ return first_quad_index_of_faces[first_quad_index_of_faces.size() == 1 ?
+ 0 :
+ face_no];
+}
+
+template <int dim>
+internal::GenericDoFsPerObject
+internal::GenericDoFsPerObject::generate(const FiniteElementData<dim> &fe)
+{
+ const auto reference_cell = fe.reference_cell();
+
+ internal::GenericDoFsPerObject result;
+
+ result.dofs_per_object_exclusive.resize(4);
+ result.dofs_per_object_inclusive.resize(4);
+ result.object_index.resize(4);
+
+ unsigned int counter = 0;
+
+ for (unsigned int v : reference_cell.vertex_indices())
+ {
+ const auto c = fe.template n_dofs_per_object<0>(v);
+
+ result.dofs_per_object_exclusive[0].emplace_back(c);
+ result.dofs_per_object_inclusive[0].emplace_back(c);
+ result.object_index[0].emplace_back(counter);
+
+ counter += c;
+ }
+
+ if (dim >= 2)
+ for (unsigned int l : reference_cell.line_indices())
+ {
+ const auto c = fe.template n_dofs_per_object<1>(l);
+
+ result.dofs_per_object_exclusive[1].emplace_back(c);
+ result.dofs_per_object_inclusive[1].emplace_back(
+ c + 2 * fe.template n_dofs_per_object<0>());
+ result.object_index[1].emplace_back(counter);
+
+ counter += c;
+ }
+
+ if (dim == 3)
+ for (unsigned int f : reference_cell.face_indices())
+ {
+ const auto c = fe.template n_dofs_per_object<2>(f);
+
+ result.dofs_per_object_exclusive[2].emplace_back(c);
+ result.dofs_per_object_inclusive[2].emplace_back(fe.n_dofs_per_face(f));
+ result.object_index[2].emplace_back(counter);
+
+ counter += c;
+ }
+
+ {
+ const auto c = fe.template n_dofs_per_object<dim>();
+
+ result.dofs_per_object_exclusive[dim].emplace_back(c);
+ result.dofs_per_object_inclusive[dim].emplace_back(fe.n_dofs_per_cell());
+ result.object_index[dim].emplace_back(counter);
+
+ counter += c;
+ }
+
+ for (unsigned int d = dim + 1; d <= 3; ++d)
+ {
+ result.dofs_per_object_exclusive[d].emplace_back(0);
+ result.dofs_per_object_inclusive[d].emplace_back(0);
+ result.object_index[d].emplace_back(counter);
+ }
+
+ result.first_object_index_on_face.resize(3);
+ for (unsigned int face_no : reference_cell.face_indices())
+ {
+ result.first_object_index_on_face[0].emplace_back(0);
+
+ result.first_object_index_on_face[1].emplace_back(
+ fe.get_first_face_line_index(face_no));
+
+ result.first_object_index_on_face[2].emplace_back(
+ fe.get_first_face_quad_index(face_no));
+ }
+
+ return result;
+}
+
+
+#endif // DOXYGEN
+
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
#include <deal.II/base/polynomials_rannacher_turek.h>
-#include <deal.II/fe/fe_base.h>
+#include <deal.II/fe/fe_data.h>
#include <deal.II/fe/fe_poly.h>
#include <string>
#include <deal.II/dofs/dof_renumbering.h>
#include <deal.II/dofs/dof_tools.h>
-#include <deal.II/fe/fe_base.h>
+#include <deal.II/fe/fe_data.h>
#include <deal.II/fe/fe_nedelec.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/dofs/dof_renumbering.h>
#include <deal.II/dofs/dof_tools.h>
-#include <deal.II/fe/fe_base.h>
+#include <deal.II/fe/fe_data.h>
#include <deal.II/fe/fe_nedelec.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/dofs/dof_renumbering.h>
#include <deal.II/dofs/dof_tools.h>
-#include <deal.II/fe/fe_base.h>
+#include <deal.II/fe/fe_data.h>
#include <deal.II/fe/fe_nedelec.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe.h>
-#include <deal.II/fe/fe_base.h>
+#include <deal.II/fe/fe_data.h>
#include <deal.II/fe/fe_interface_values.h>
#include <deal.II/fe/fe_tools.h>
#include <deal.II/fe/fe_values.h>