*
*
* @ingroup dofs
- * @author Wolfgang Bangerth, Guido Kanschat and others, 1998 - 2008
+ * @author Wolfgang Bangerth, Guido Kanschat and others
*/
-class DoFTools
+namespace DoFTools
{
- public:
- /**
- * The flags used in tables by certain
- * <tt>make_*_pattern</tt> functions to
- * describe whether two components of the
- * solution couple in the bilinear forms
- * corresponding to cell or face
- * terms. An example of using these flags
- * is shown in the introduction of
- * step-46.
- *
- * In the descriptions of the individual
- * elements below, remember that these
- * flags are used as elements of tables
- * of size FiniteElement::n_components
- * times FiniteElement::n_components
- * where each element indicates whether
- * two components do or do not couple.
- */
- enum Coupling
- {
- /**
- * Two components do not
- * couple.
- */
- none,
- /**
- * Two components do couple.
- */
- always,
- /**
- * Two components couple only
- * if their shape functions are
- * both nonzero on a given
- * face. This flag is only used
- * when computing integrals over
- * faces of cells.
- */
- nonzero
- };
-
- /**
- * @name Auxiliary functions
- * @{
- */
- /**
- * Maximal number of degrees of
- * freedom on a cell.
- */
- template <int dim, int spacedim>
- static unsigned int
- max_dofs_per_cell (const DoFHandler<dim,spacedim> &dh);
-
- template <int dim, int spacedim>
- static unsigned int
- max_dofs_per_cell (const hp::DoFHandler<dim,spacedim> &dh);
-
-
- /**
- * Maximal number of degrees of
- * freedom on a face.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static unsigned int
- max_dofs_per_face (const DoFHandler<dim,spacedim> &dh);
-
- /**
- * Maximal number of degrees of
- * freedom on a face.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static unsigned int
- max_dofs_per_face (const hp::DoFHandler<dim,spacedim> &dh);
-
- /**
- * Maximal number of degrees of
- * freedom on a vertex.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static unsigned int
- max_dofs_per_vertex (const DoFHandler<dim,spacedim> &dh);
-
- /**
- * Maximal number of degrees of
- * freedom on a vertex.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static unsigned int
- max_dofs_per_vertex (const hp::DoFHandler<dim,spacedim> &dh);
-
- /**
- * Number of vector components in the
- * finite element object used by this
- * DoFHandler.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static unsigned int
- n_components (const DoFHandler<dim,spacedim> &dh);
-
- /**
- * Number of vector components in the
- * finite element object used by this
- * DoFHandler.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static unsigned int
- n_components (const hp::DoFHandler<dim,spacedim> &dh);
-
- /**
- * Find out whether the FiniteElement
- * used by this DoFHandler is primitive
- * or not.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static bool
- fe_is_primitive (const DoFHandler<dim,spacedim> &dh);
-
- /**
- * Find out whether the FiniteElement
- * used by this DoFHandler is primitive
- * or not.
- *
- * This function exists for both non-hp
- * and hp DoFHandlers, to allow for a
- * uniform interface to query this
- * property.
- */
- template <int dim, int spacedim>
- static bool
- fe_is_primitive (const hp::DoFHandler<dim,spacedim> &dh);
-
- /**
- * @}
- */
-
- /**
- * @name Sparsity Pattern Generation
- * @{
- */
-
- /**
- * Locate non-zero entries of the
- * system matrix.
- *
- * This function computes the
- * possible positions of non-zero
- * entries in the global system
- * matrix. We assume that a
- * certain finite element basis
- * function is non-zero on a cell
- * only if its degree of freedom
- * is associated with the
- * interior, a face, an edge or a
- * vertex of this cell. As a
- * result, the matrix entry
- * between two basis functions
- * can be non-zero only if they
- * correspond to degrees of
- * freedom of at least one common
- * cell. Therefore,
- * @p make_sparsity_pattern just
- * loops over all cells and
- * enters all couplings local to
- * that cell. As the generation
- * of the sparsity pattern is
- * irrespective of the equation
- * which is solved later on, the
- * resulting sparsity pattern is
- * symmetric.
- *
- * Remember using
- * SparsityPattern::compress()
- * after generating the pattern.
- *
- * The actual type of the
- * sparsity pattern may be
- * SparsityPattern,
- * CompressedSparsityPattern,
- * BlockSparsityPattern,
- * BlockCompressedSparsityPattern,
- * BlockCompressedSetSparsityPattern,
- * BlockCompressedSimpleSparsityPattern,
- * or any other class that
- * satisfies similar
- * requirements. It is assumed
- * that the size of the sparsity
- * pattern matches the number of
- * degrees of freedom and that
- * enough unused nonzero entries
- * are left to fill the sparsity
- * pattern. The nonzero entries
- * generated by this function are
- * overlaid to possible previous
- * content of the object, that is
- * previously added entries are
- * not deleted.
- *
- * Since this process is purely local,
- * the sparsity pattern does not provide
- * for entries introduced by the
- * elimination of hanging nodes. They
- * have to be taken care of by a call to
- * ConstraintMatrix::condense()
- * afterwards.
- *
- * Alternatively, the constraints on
- * degrees of freedom can already be
- * taken into account at the time of
- * creating the sparsity pattern. For
- * this, pass the ConstraintMatrix object
- * as the third argument to the current
- * function. No call to
- * ConstraintMatrix::condense() is then
- * necessary. This process is explained
- * in step-27.
- *
- * In case the constraints are
- * already taken care of in this
- * function, it is possible to
- * neglect off-diagonal entries
- * in the sparsity pattern. When
- * using
- * ConstraintMatrix::distribute_local_to_global
- * during assembling, no entries
- * will ever be written into
- * these matrix position, so that
- * one can save some computing
- * time in matrix-vector products
- * by not even creating these
- * elements. In that case, the
- * variable
- * <tt>keep_constrained_dofs</tt>
- * needs to be set to
- * <tt>false</tt>.
- *
- * If the @p subdomain_id parameter is
- * given, the sparsity pattern is built
- * only on cells that have a subdomain_id
- * equal to the given argument. This is
- * useful in parallel contexts where the
- * matrix and sparsity pattern (for
- * example a
- * TrilinosWrappers::SparsityPattern) may
- * be distributed and not every MPI
- * process needs to build the entire
- * sparsity pattern; in that case, it is
- * sufficient if every process only
- * builds that part of the sparsity
- * pattern that corresponds to the
- * subdomain_id for which it is
- * responsible. This feature is
- * used in step-32.
- *
- * @ingroup constraints
- */
- template <class DH, class SparsityPattern>
- static
- void
- make_sparsity_pattern (const DH &dof,
- SparsityPattern &sparsity_pattern,
- const ConstraintMatrix &constraints = ConstraintMatrix(),
- const bool keep_constrained_dofs = true,
- const types::subdomain_id_t subdomain_id = types::invalid_subdomain_id);
-
- /**
- * Locate non-zero entries for
- * vector valued finite elements.
- * This function does mostly the
- * same as the previous
- * @p make_sparsity_pattern, but
- * it is specialized for vector
- * finite elements and allows to
- * specify which variables couple
- * in which equation. For
- * example, if wanted to solve
- * the Stokes equations,
- * @f{align*}
- * -\Delta \mathbf u + \nabla p &= 0,\\
- * \text{div}\ u &= 0
- * @f}
- * in two space dimensions,
- * using stable Q2/Q1 mixed
- * elements (using the FESystem
- * class), then you don't want
- * all degrees of freedom to
- * couple in each equation. You
- * rather may want to give the
- * following pattern of
- * couplings:
- * @f[
- * \begin{array}{ccc}
- * 1 & 0 & 1 \\
- * 0 & 1 & 1 \\
- * 1 & 1 & 0
- * \end{array}
- * @f]
- * where "1" indicates that two
- * variables (i.e. components of
- * the FESystem) couple in the
- * respective equation, and a "0"
- * means no coupling, in which
- * case it is not necessary to
- * allocate space in the matrix
- * structure. Obviously, the mask
- * refers to components of the
- * composed FESystem, rather
- * than to the degrees of freedom
- * contained in there.
- *
- * This function is designed to
- * accept a coupling pattern, like the one
- * shown above, through the
- * @p couplings parameter, which
- * contains values of type #Coupling. It
- * builds the matrix structure
- * just like the previous
- * function, but does not create
- * matrix elements if not
- * specified by the coupling pattern. If the
- * couplings are symmetric, then so
- * will be the resulting sparsity
- * pattern.
- *
- * The actual type of the
- * sparsity pattern may be
- * SparsityPattern,
- * CompressedSparsityPattern,
- * BlockSparsityPattern,
- * BlockCompressedSparsityPattern,
- * BlockCompressedSetSparsityPattern,
- * or any other class that
- * satisfies similar
- * requirements.
- *
- * There is a complication if
- * some or all of the shape
- * functions of the finite
- * element in use are non-zero in
- * more than one component (in
- * deal.II speak: they are
- * non-primitive). In this case,
- * the coupling element
- * correspoding to the first
- * non-zero component is taken
- * and additional ones for this
- * component are ignored.
- *
- * Not implemented for
- * hp::DoFHandler.
- *
- * As mentioned before, the
- * creation of the sparsity
- * pattern is a purely local
- * process and the sparsity
- * pattern does not provide for
- * entries introduced by the
- * elimination of hanging
- * nodes. They have to be taken
- * care of by a call to
- * ConstraintMatrix::condense()
- * afterwards.
- *
- * Alternatively, the constraints
- * on degrees of freedom can
- * already be taken into account
- * at the time of creating the
- * sparsity pattern. For this,
- * pass the ConstraintMatrix
- * object as the third argument
- * to the current function. No
- * call to
- * ConstraintMatrix::condense()
- * is then necessary. This
- * process is explained in @ref
- * step_27 "step-27".
- *
- * In case the constraints are
- * already taken care of in this
- * function, it is possible to
- * neglect off-diagonal entries
- * in the sparsity pattern. When
- * using
- * ConstraintMatrix::distribute_local_to_global
- * during assembling, no entries
- * will ever be written into
- * these matrix position, so that
- * one can save some computing
- * time in matrix-vector products
- * by not even creating these
- * elements. In that case, the
- * variable
- * <tt>keep_constrained_dofs</tt>
- * needs to be set to
- * <tt>false</tt>.
- *
- * If the @p subdomain_id parameter is
- * given, the sparsity pattern is built
- * only on cells that have a subdomain_id
- * equal to the given argument. This is
- * useful in parallel contexts where the
- * matrix and sparsity pattern (for
- * example a
- * TrilinosWrappers::SparsityPattern) may
- * be distributed and not every MPI
- * process needs to build the entire
- * sparsity pattern; in that case, it is
- * sufficient if every process only
- * builds that part of the sparsity
- * pattern that corresponds to the
- * subdomain_id for which it is
- * responsible. This feature is
- * used in step-32.
- *
- * @ingroup constraints
- */
- template <class DH, class SparsityPattern>
- static
- void
- make_sparsity_pattern (const DH &dof,
- const Table<2, Coupling> &coupling,
- SparsityPattern &sparsity_pattern,
- const ConstraintMatrix &constraints = ConstraintMatrix(),
- const bool keep_constrained_dofs = true,
- const types::subdomain_id_t subdomain_id = types::invalid_subdomain_id);
-
- /**
- * @deprecated This is the old
- * form of the previous
- * function. It generates a table
- * of DoFTools::Coupling values
- * (where a <code>true</code>
- * value in the mask is
- * translated into a
- * Coupling::always value in the
- * table) and calls the function
- * above.
- */
- template <class DH, class SparsityPattern>
- static
- void
- make_sparsity_pattern (const DH &dof,
- const std::vector<std::vector<bool> > &mask,
- SparsityPattern &sparsity_pattern);
-
- /**
- * Construct a sparsity pattern that
- * allows coupling degrees of freedom on
- * two different but related meshes.
- *
- * The idea is that if the two given
- * DoFHandler objects correspond to two
- * different meshes (and potentially to
- * different finite elements used on
- * these cells), but that if the two
- * triangulations they are based on are
- * derived from the same coarse mesh
- * through hierarchical refinement, then
- * one may set up a problem where one
- * would like to test shape functions
- * from one mesh against the shape
- * functions from another mesh. In
- * particular, this means that shape
- * functions from a cell on the first
- * mesh are tested against those on the
- * second cell that are located on the
- * corresponding cell; this
- * correspondence is something that the
- * IntergridMap class can determine.
- *
- * This function then constructs a
- * sparsity pattern for which the degrees
- * of freedom that represent the rows
- * come from the first given DoFHandler,
- * whereas the ones that correspond to
- * columns come from the second
- * DoFHandler.
- */
- template <class DH, class SparsityPattern>
- static
- void
- make_sparsity_pattern (const DH &dof_row,
- const DH &dof_col,
- SparsityPattern &sparsity);
-
- /**
- * Create the sparsity pattern for
- * boundary matrices. See the general
- * documentation of this class for more
- * information.
- *
- * The actual type of the sparsity
- * pattern may be SparsityPattern,
- * CompressedSparsityPattern,
- * BlockSparsityPattern,
- * BlockCompressedSparsityPattern,
- * BlockCompressedSetSparsityPattern, or
- * any other class that satisfies similar
- * requirements. It is assumed that the
- * size of the sparsity pattern is
- * already correct.
- */
- template <class DH, class SparsityPattern>
- static void
- make_boundary_sparsity_pattern (const DH &dof,
- const std::vector<unsigned int> &dof_to_boundary_mapping,
- SparsityPattern &sparsity_pattern);
-
- /**
- * Write the sparsity structure of the
- * matrix composed of the basis functions
- * on the boundary into the
- * matrix structure. In contrast to the
- * previous function, only those parts
- * of the boundary are considered of which
- * the boundary indicator is listed in the
- * set of numbers passed to this function.
- *
- * In fact, rather than a @p set
- * of boundary indicators, a
- * @p map needs to be passed,
- * since most of the functions
- * handling with boundary
- * indicators take a mapping of
- * boundary indicators and the
- * respective boundary
- * functions. The boundary
- * function, however, is ignored
- * in this function. If you have
- * no functions at hand, but only
- * the boundary indicators, set
- * the function pointers to null
- * pointers.
- *
- * For the type of the sparsity
- * pattern, the same holds as
- * said above.
- */
- template <class DH, class SparsityPattern>
- static void
- make_boundary_sparsity_pattern (const DH &dof,
- const typename FunctionMap<DH::space_dimension>::type &boundary_indicators,
- const std::vector<unsigned int> &dof_to_boundary_mapping,
- SparsityPattern &sparsity);
-
- /**
- * Generate sparsity pattern for
- * fluxes, i.e. formulations of
- * the discrete problem with
- * discontinuous elements which
- * couple across faces of cells.
- * This is a replacement of the
- * function
- * @p make_sparsity_pattern for
- * discontinuous methods. Since
- * the fluxes include couplings
- * between neighboring elements,
- * the normal couplings and these
- * extra matrix entries are
- * considered.
- */
- template<class DH, class SparsityPattern>
- static void
- make_flux_sparsity_pattern (const DH &dof_handler,
- SparsityPattern &sparsity_pattern);
-
- /**
- * This function does the same as
- * the other with the same name,
- * but it gets a ConstraintMatrix
- * additionally.
- * This is for the case where you
- * have fluxes but constraints as
- * well.
- * Not implemented for
- * hp::DoFHandler.
- *
- * @ingroup constraints
- */
- template<class DH, class SparsityPattern>
- static void
- make_flux_sparsity_pattern (const DH &dof_handler,
- SparsityPattern &sparsity_pattern,
- const ConstraintMatrix &constraints,
- const bool keep_constrained_dofs = true,
- const types::subdomain_id_t subdomain_id = numbers::invalid_unsigned_int);
-
- /**
- * This function does the same as
- * the other with the same name,
- * but it gets two additional
- * coefficient matrices. A matrix
- * entry will only be generated
- * for two basis functions, if
- * there is a non-zero entry
- * linking their associated
- * components in the coefficient
- * matrix.
- *
- * There is one matrix for
- * couplings in a cell and one
- * for the couplings occuring in
- * fluxes.
- *
- * Not implemented for
- * hp::DoFHandler.
- */
- template <class DH, class SparsityPattern>
- static void
- make_flux_sparsity_pattern (const DH &dof,
- SparsityPattern &sparsity,
- const Table<2,Coupling> &int_mask,
- const Table<2,Coupling> &flux_mask);
-
- //@}
- /**
- * @name Hanging Nodes
- * @{
- */
-
- /**
- * Compute the constraints resulting from
- * the presence of hanging nodes. Hanging
- * nodes are best explained using a small
- * picture:
- *
- * @image html hanging_nodes.png
- *
- * In order to make a finite element
- * function globally continuous, we have
- * to make sure that the dark red nodes
- * have values that are compatible with
- * the adjacent yellow nodes, so that the
- * function has no jump when coming from
- * the small cells to the large one at
- * the top right. We therefore have to
- * add conditions that constrain those
- * "hanging nodes".
- *
- * The object into
- * which these are inserted is
- * later used to condense the
- * global system matrix and right
- * hand side, and to extend the
- * solution vectors from the true
- * degrees of freedom also to the
- * constraint nodes. This
- * function is explained in
- * detail in the @ref step_6
- * "step-6" tutorial program and
- * is used in almost all
- * following programs as well.
- *
- * This function does not clear
- * the constraint matrix object
- * before use, in order to allow
- * adding constraints from
- * different sources to the same
- * object. You therefore need to
- * make sure it contains only
- * constraints you still want;
- * otherwise call the
- * ConstraintMatrix::clear()
- * function. Likewise, this
- * function does not close the
- * object since you may want to
- * enter other constraints later
- * on yourself.
- *
- * In the hp-case, i.e. when the
- * argument is of type
- * hp::DoFHandler, we consider
- * constraints due to different
- * finite elements used on two
- * sides of a face between cells
- * as hanging nodes as well. In
- * other words, for hp finite
- * elements, this function
- * computes all constraints due
- * to differing mesh sizes (h) or
- * polynomial degrees (p) between
- * adjacent cells.
- *
- * The template argument (and by
- * consequence the type of the
- * first argument to this
- * function) can be either a
- * ::DoFHandler, hp::DoFHandler,
- * or MGDoFHandler.
- *
- * @ingroup constraints
- */
- template <class DH>
- static void
- make_hanging_node_constraints (const DH &dof_handler,
- ConstraintMatrix &constraints);
- //@}
-
- /**
- * Take a vector of values which live on
- * cells (e.g. an error per cell) and
- * distribute it to the dofs in such a
- * way that a finite element field
- * results, which can then be further
- * processed, e.g. for output. You should
- * note that the resulting field will not
- * be continuous at hanging nodes. This
- * can, however, easily be arranged by
- * calling the appropriate @p distribute
- * function of a ConstraintMatrix
- * object created for this
- * DoFHandler object, after the
- * vector has been fully assembled.
- *
- * It is assumed that the number
- * of elements in @p cell_data
- * equals the number of active
- * cells and that the number of
- * elements in @p dof_data equals
- * <tt>dof_handler.n_dofs()</tt>.
- *
- * Note that the input vector may
- * be a vector of any data type
- * as long as it is convertible
- * to @p double. The output
- * vector, being a data vector on
- * a DoF handler, always consists of
- * elements of type @p double.
- *
- * In case the finite element
- * used by this DoFHandler
- * consists of more than one
- * component, you need to specify
- * which component in the output
- * vector should be used to store
- * the finite element field in;
- * the default is zero (no other
- * value is allowed if the finite
- * element consists only of one
- * component). All other
- * components of the vector
- * remain untouched, i.e. their
- * contents are not changed.
- *
- * This function cannot be used
- * if the finite element in use
- * has shape functions that are
- * non-zero in more than one
- * vector component (in deal.II
- * speak: they are
- * non-primitive).
- */
- template <class DH, typename Number>
- static void
- distribute_cell_to_dof_vector (const DH &dof_handler,
- const Vector<Number> &cell_data,
- Vector<double> &dof_data,
- const unsigned int component = 0);
-
- /**
- * Extract the indices of the
- * degrees of freedom belonging
- * to certain vector components
- * or blocks (if the last
- * argument is <tt>true</tt>) of
- * a vector-valued finite
- * element. The bit vector @p
- * select defines, which
- * components or blocks of an
- * FESystem are to be extracted
- * from the DoFHandler @p
- * dof. The entries in @p
- * selected_dofs corresponding to
- * degrees of freedom belonging
- * to these components are then
- * flagged @p true, while all
- * others are set to @p false.
- *
- * The size of @p select must
- * equal the number of components
- * or blocks in the FiniteElement
- * used by @p dof, depending on
- * the argument
- * <tt>blocks</tt>. The size of
- * @p selected_dofs must equal
- * DoFHandler::n_dofs(). Previous
- * contents of this array are
- * overwritten.
- *
- * If the finite element under
- * consideration is not
- * primitive, that is some or all
- * of its shape functions are
- * non-zero in more than one
- * vector component (which holds,
- * for example, for FE_Nedelec or
- * FE_RaviartThomas elements), then
- * shape functions cannot be
- * associated with a single
- * vector component. In this
- * case, if <em>one</em> shape
- * vector component of this
- * element is flagged in
- * @p component_select, then
- * this is equivalent to
- * selecting <em>all</em> vector
- * components corresponding to
- * this non-primitive base
- * element.
- */
- template <int dim, int spacedim>
- static void
- extract_dofs (const DoFHandler<dim,spacedim> &dof_handler,
- const std::vector<bool> &select,
- std::vector<bool> &selected_dofs,
- const bool blocks = false);
-
- /**
- * The same function as above,
- * but for a hp::DoFHandler.
- */
- template <int dim, int spacedim>
- static void
- extract_dofs (const hp::DoFHandler<dim,spacedim> &dof_handler,
- const std::vector<bool> &select,
- std::vector<bool> &selected_dofs,
- const bool blocks = false);
-
- /**
- * Do the same thing as
- * extract_dofs() for one level
- * of a multi-grid DoF numbering.
- */
- template <int dim, int spacedim>
- static void
- extract_level_dofs (const unsigned int level,
- const MGDoFHandler<dim,spacedim> &dof,
- const std::vector<bool> &select,
- std::vector<bool> &selected_dofs,
- const bool blocks = false);
-
- /**
- * Extract all degrees of freedom
- * which are at the boundary and
- * belong to specified components
- * of the solution. The function
- * returns its results in the
- * last non-default-valued
- * parameter which contains
- * @p true if a degree of
- * freedom is at the boundary and
- * belongs to one of the selected
- * components, and @p false
- * otherwise.
- *
- * By specifying the
- * @p boundary_indicator
- * variable, you can select which
- * boundary indicators the faces
- * have to have on which the
- * degrees of freedom are located
- * that shall be extracted. If it
- * is an empty list, then all
- * boundary indicators are
- * accepted.
- *
- * The size of @p component_select
- * shall equal the number of
- * components in the finite
- * element used by @p dof. The
- * size of @p selected_dofs shall
- * equal
- * <tt>dof_handler.n_dofs()</tt>. Previous
- * contents of this array or
- * overwritten.
- *
- * Using the usual convention, if
- * a shape function is non-zero
- * in more than one component
- * (i.e. it is non-primitive),
- * then the element in the
- * component mask is used that
- * corresponds to the first
- * non-zero components. Elements
- * in the mask corresponding to
- * later components are ignored.
- */
- template <class DH>
- static void
- extract_boundary_dofs (const DH &dof_handler,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const std::set<unsigned char> &boundary_indicators = std::set<unsigned char>());
-
- /**
- * This function is similar to
- * the extract_boundary_dofs()
- * function but it extracts those
- * degrees of freedom whose shape
- * functions are nonzero on at
- * least part of the selected
- * boundary. For continuous
- * elements, this is exactly the
- * set of shape functions whose
- * degrees of freedom are defined
- * on boundary faces. On the
- * other hand, if the finite
- * element in used is a
- * discontinuous element, all
- * degrees of freedom are defined
- * in the inside of cells and
- * consequently none would be
- * boundary degrees of
- * freedom. Several of those
- * would have shape functions
- * that are nonzero on the
- * boundary, however. This
- * function therefore extracts
- * all those for which the
- * FiniteElement::has_support_on_face
- * function says that it is
- * nonzero on any face on one of
- * the selected boundary parts.
- */
- template <class DH>
- static void
- extract_dofs_with_support_on_boundary (const DH &dof_handler,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const std::set<unsigned char> &boundary_indicators = std::set<unsigned char>());
-
- /**
- * @name Hanging Nodes
- * @{
- */
-
- /**
- * Select all dofs that will be
- * constrained by interface
- * constraints, i.e. all hanging
- * nodes.
- *
- * The size of @p selected_dofs
- * shall equal
- * <tt>dof_handler.n_dofs()</tt>. Previous
- * contents of this array or
- * overwritten.
- */
- template <int dim, int spacedim>
- static void
- extract_hanging_node_dofs (const DoFHandler<dim,spacedim> &dof_handler,
- std::vector<bool> &selected_dofs);
- //@}
-
- /**
- * Flag all those degrees of
- * freedom which are on cells
- * with the given subdomain
- * id. Note that DoFs on faces
- * can belong to cells with
- * differing subdomain ids, so
- * the sets of flagged degrees of
- * freedom are not mutually
- * exclusive for different
- * subdomain ids.
- *
- * If you want to get a unique
- * association of degree of freedom with
- * subdomains, use the
- * @p get_subdomain_association
- * function.
- */
- template <class DH>
- static void
- extract_subdomain_dofs (const DH &dof_handler,
- const types::subdomain_id_t subdomain_id,
- std::vector<bool> &selected_dofs);
-
-
- /**
- * Extract the set of global DoF
- * indices that are owned by the
- * current processor. For regular
- * DoFHandler objects, this set
- * is the complete set with all
- * DoF indices. In either case,
- * it equals what
- * DoFHandler::locally_owned_dofs()
- * returns.
- */
- template <class DH>
- static void
- extract_locally_owned_dofs (const DH & dof_handler,
- IndexSet & dof_set);
-
-
- /**
- * Extract the set of global DoF
- * indices that are active on the
- * current DoFHandler. For
- * regular DoFHandlers, these are
- * all DoF indices, but for
- * DoFHandler objects built on
- * parallel::distributed::Triangulation
- * this set is a superset of
- * DoFHandler::locally_owned_dofs()
- * and contains all DoF indices
- * that live on all locally owned
- * cells (including on the
- * interface to ghost
- * cells). However, it does not
- * contain the DoF indices that
- * are exclusively defined on
- * ghost or artificial cells (see
- * @ref GlossArtificialCell "the
- * glossary").
- *
- * The degrees of freedom identified by
- * this function equal those obtained
- * from the
- * dof_indices_with_subdomain_association()
- * function when called with the locally
- * owned subdomain id.
- */
- template <class DH>
- static void
- extract_locally_active_dofs (const DH & dof_handler,
+ /**
+ * The flags used in tables by certain
+ * <tt>make_*_pattern</tt> functions to
+ * describe whether two components of the
+ * solution couple in the bilinear forms
+ * corresponding to cell or face
+ * terms. An example of using these flags
+ * is shown in the introduction of
+ * step-46.
+ *
+ * In the descriptions of the individual
+ * elements below, remember that these
+ * flags are used as elements of tables
+ * of size FiniteElement::n_components
+ * times FiniteElement::n_components
+ * where each element indicates whether
+ * two components do or do not couple.
+ */
+ enum Coupling
+ {
+ /**
+ * Two components do not
+ * couple.
+ */
+ none,
+ /**
+ * Two components do couple.
+ */
+ always,
+ /**
+ * Two components couple only
+ * if their shape functions are
+ * both nonzero on a given
+ * face. This flag is only used
+ * when computing integrals over
+ * faces of cells.
+ */
+ nonzero
+ };
+
+ /**
+ * @name Auxiliary functions
+ * @{
+ */
+ /**
+ * Maximal number of degrees of
+ * freedom on a cell.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ max_dofs_per_cell (const DoFHandler<dim,spacedim> &dh);
+
+ template <int dim, int spacedim>
+ unsigned int
+ max_dofs_per_cell (const hp::DoFHandler<dim,spacedim> &dh);
+
+
+ /**
+ * Maximal number of degrees of
+ * freedom on a face.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ max_dofs_per_face (const DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Maximal number of degrees of
+ * freedom on a face.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ max_dofs_per_face (const hp::DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Maximal number of degrees of
+ * freedom on a vertex.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ max_dofs_per_vertex (const DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Maximal number of degrees of
+ * freedom on a vertex.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ max_dofs_per_vertex (const hp::DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Number of vector components in the
+ * finite element object used by this
+ * DoFHandler.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ n_components (const DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Number of vector components in the
+ * finite element object used by this
+ * DoFHandler.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ n_components (const hp::DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Find out whether the FiniteElement
+ * used by this DoFHandler is primitive
+ * or not.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ bool
+ fe_is_primitive (const DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * Find out whether the FiniteElement
+ * used by this DoFHandler is primitive
+ * or not.
+ *
+ * This function exists for both non-hp
+ * and hp DoFHandlers, to allow for a
+ * uniform interface to query this
+ * property.
+ */
+ template <int dim, int spacedim>
+ bool
+ fe_is_primitive (const hp::DoFHandler<dim,spacedim> &dh);
+
+ /**
+ * @}
+ */
+
+ /**
+ * @name Sparsity Pattern Generation
+ * @{
+ */
+
+ /**
+ * Locate non-zero entries of the
+ * system matrix.
+ *
+ * This function computes the
+ * possible positions of non-zero
+ * entries in the global system
+ * matrix. We assume that a
+ * certain finite element basis
+ * function is non-zero on a cell
+ * only if its degree of freedom
+ * is associated with the
+ * interior, a face, an edge or a
+ * vertex of this cell. As a
+ * result, the matrix entry
+ * between two basis functions
+ * can be non-zero only if they
+ * correspond to degrees of
+ * freedom of at least one common
+ * cell. Therefore,
+ * @p make_sparsity_pattern just
+ * loops over all cells and
+ * enters all couplings local to
+ * that cell. As the generation
+ * of the sparsity pattern is
+ * irrespective of the equation
+ * which is solved later on, the
+ * resulting sparsity pattern is
+ * symmetric.
+ *
+ * Remember using
+ * SparsityPattern::compress()
+ * after generating the pattern.
+ *
+ * The actual type of the
+ * sparsity pattern may be
+ * SparsityPattern,
+ * CompressedSparsityPattern,
+ * BlockSparsityPattern,
+ * BlockCompressedSparsityPattern,
+ * BlockCompressedSetSparsityPattern,
+ * BlockCompressedSimpleSparsityPattern,
+ * or any other class that
+ * satisfies similar
+ * requirements. It is assumed
+ * that the size of the sparsity
+ * pattern matches the number of
+ * degrees of freedom and that
+ * enough unused nonzero entries
+ * are left to fill the sparsity
+ * pattern. The nonzero entries
+ * generated by this function are
+ * overlaid to possible previous
+ * content of the object, that is
+ * previously added entries are
+ * not deleted.
+ *
+ * Since this process is purely local,
+ * the sparsity pattern does not provide
+ * for entries introduced by the
+ * elimination of hanging nodes. They
+ * have to be taken care of by a call to
+ * ConstraintMatrix::condense()
+ * afterwards.
+ *
+ * Alternatively, the constraints on
+ * degrees of freedom can already be
+ * taken into account at the time of
+ * creating the sparsity pattern. For
+ * this, pass the ConstraintMatrix object
+ * as the third argument to the current
+ * function. No call to
+ * ConstraintMatrix::condense() is then
+ * necessary. This process is explained
+ * in step-27.
+ *
+ * In case the constraints are
+ * already taken care of in this
+ * function, it is possible to
+ * neglect off-diagonal entries
+ * in the sparsity pattern. When
+ * using
+ * ConstraintMatrix::distribute_local_to_global
+ * during assembling, no entries
+ * will ever be written into
+ * these matrix position, so that
+ * one can save some computing
+ * time in matrix-vector products
+ * by not even creating these
+ * elements. In that case, the
+ * variable
+ * <tt>keep_constrained_dofs</tt>
+ * needs to be set to
+ * <tt>false</tt>.
+ *
+ * If the @p subdomain_id parameter is
+ * given, the sparsity pattern is built
+ * only on cells that have a subdomain_id
+ * equal to the given argument. This is
+ * useful in parallel contexts where the
+ * matrix and sparsity pattern (for
+ * example a
+ * TrilinosWrappers::SparsityPattern) may
+ * be distributed and not every MPI
+ * process needs to build the entire
+ * sparsity pattern; in that case, it is
+ * sufficient if every process only
+ * builds that part of the sparsity
+ * pattern that corresponds to the
+ * subdomain_id for which it is
+ * responsible. This feature is
+ * used in step-32.
+ *
+ * @ingroup constraints
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (const DH &dof,
+ SparsityPattern &sparsity_pattern,
+ const ConstraintMatrix &constraints = ConstraintMatrix(),
+ const bool keep_constrained_dofs = true,
+ const types::subdomain_id_t subdomain_id = types::invalid_subdomain_id);
+
+ /**
+ * Locate non-zero entries for
+ * vector valued finite elements.
+ * This function does mostly the
+ * same as the previous
+ * @p make_sparsity_pattern, but
+ * it is specialized for vector
+ * finite elements and allows to
+ * specify which variables couple
+ * in which equation. For
+ * example, if wanted to solve
+ * the Stokes equations,
+ * @f{align*}
+ * -\Delta \mathbf u + \nabla p &= 0,\\
+ * \text{div}\ u &= 0
+ * @f}
+ * in two space dimensions,
+ * using stable Q2/Q1 mixed
+ * elements (using the FESystem
+ * class), then you don't want
+ * all degrees of freedom to
+ * couple in each equation. You
+ * rather may want to give the
+ * following pattern of
+ * couplings:
+ * @f[
+ * \begin{array}{ccc}
+ * 1 & 0 & 1 \\
+ * 0 & 1 & 1 \\
+ * 1 & 1 & 0
+ * \end{array}
+ * @f]
+ * where "1" indicates that two
+ * variables (i.e. components of
+ * the FESystem) couple in the
+ * respective equation, and a "0"
+ * means no coupling, in which
+ * case it is not necessary to
+ * allocate space in the matrix
+ * structure. Obviously, the mask
+ * refers to components of the
+ * composed FESystem, rather
+ * than to the degrees of freedom
+ * contained in there.
+ *
+ * This function is designed to
+ * accept a coupling pattern, like the one
+ * shown above, through the
+ * @p couplings parameter, which
+ * contains values of type #Coupling. It
+ * builds the matrix structure
+ * just like the previous
+ * function, but does not create
+ * matrix elements if not
+ * specified by the coupling pattern. If the
+ * couplings are symmetric, then so
+ * will be the resulting sparsity
+ * pattern.
+ *
+ * The actual type of the
+ * sparsity pattern may be
+ * SparsityPattern,
+ * CompressedSparsityPattern,
+ * BlockSparsityPattern,
+ * BlockCompressedSparsityPattern,
+ * BlockCompressedSetSparsityPattern,
+ * or any other class that
+ * satisfies similar
+ * requirements.
+ *
+ * There is a complication if
+ * some or all of the shape
+ * functions of the finite
+ * element in use are non-zero in
+ * more than one component (in
+ * deal.II speak: they are
+ * non-primitive). In this case,
+ * the coupling element
+ * correspoding to the first
+ * non-zero component is taken
+ * and additional ones for this
+ * component are ignored.
+ *
+ * Not implemented for
+ * hp::DoFHandler.
+ *
+ * As mentioned before, the
+ * creation of the sparsity
+ * pattern is a purely local
+ * process and the sparsity
+ * pattern does not provide for
+ * entries introduced by the
+ * elimination of hanging
+ * nodes. They have to be taken
+ * care of by a call to
+ * ConstraintMatrix::condense()
+ * afterwards.
+ *
+ * Alternatively, the constraints
+ * on degrees of freedom can
+ * already be taken into account
+ * at the time of creating the
+ * sparsity pattern. For this,
+ * pass the ConstraintMatrix
+ * object as the third argument
+ * to the current function. No
+ * call to
+ * ConstraintMatrix::condense()
+ * is then necessary. This
+ * process is explained in @ref
+ * step_27 "step-27".
+ *
+ * In case the constraints are
+ * already taken care of in this
+ * function, it is possible to
+ * neglect off-diagonal entries
+ * in the sparsity pattern. When
+ * using
+ * ConstraintMatrix::distribute_local_to_global
+ * during assembling, no entries
+ * will ever be written into
+ * these matrix position, so that
+ * one can save some computing
+ * time in matrix-vector products
+ * by not even creating these
+ * elements. In that case, the
+ * variable
+ * <tt>keep_constrained_dofs</tt>
+ * needs to be set to
+ * <tt>false</tt>.
+ *
+ * If the @p subdomain_id parameter is
+ * given, the sparsity pattern is built
+ * only on cells that have a subdomain_id
+ * equal to the given argument. This is
+ * useful in parallel contexts where the
+ * matrix and sparsity pattern (for
+ * example a
+ * TrilinosWrappers::SparsityPattern) may
+ * be distributed and not every MPI
+ * process needs to build the entire
+ * sparsity pattern; in that case, it is
+ * sufficient if every process only
+ * builds that part of the sparsity
+ * pattern that corresponds to the
+ * subdomain_id for which it is
+ * responsible. This feature is
+ * used in step-32.
+ *
+ * @ingroup constraints
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (const DH &dof,
+ const Table<2, Coupling> &coupling,
+ SparsityPattern &sparsity_pattern,
+ const ConstraintMatrix &constraints = ConstraintMatrix(),
+ const bool keep_constrained_dofs = true,
+ const types::subdomain_id_t subdomain_id = types::invalid_subdomain_id);
+
+ /**
+ * @deprecated This is the old
+ * form of the previous
+ * function. It generates a table
+ * of DoFTools::Coupling values
+ * (where a <code>true</code>
+ * value in the mask is
+ * translated into a
+ * Coupling::always value in the
+ * table) and calls the function
+ * above.
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (const DH &dof,
+ const std::vector<std::vector<bool> > &mask,
+ SparsityPattern &sparsity_pattern);
+
+ /**
+ * Construct a sparsity pattern that
+ * allows coupling degrees of freedom on
+ * two different but related meshes.
+ *
+ * The idea is that if the two given
+ * DoFHandler objects correspond to two
+ * different meshes (and potentially to
+ * different finite elements used on
+ * these cells), but that if the two
+ * triangulations they are based on are
+ * derived from the same coarse mesh
+ * through hierarchical refinement, then
+ * one may set up a problem where one
+ * would like to test shape functions
+ * from one mesh against the shape
+ * functions from another mesh. In
+ * particular, this means that shape
+ * functions from a cell on the first
+ * mesh are tested against those on the
+ * second cell that are located on the
+ * corresponding cell; this
+ * correspondence is something that the
+ * IntergridMap class can determine.
+ *
+ * This function then constructs a
+ * sparsity pattern for which the degrees
+ * of freedom that represent the rows
+ * come from the first given DoFHandler,
+ * whereas the ones that correspond to
+ * columns come from the second
+ * DoFHandler.
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (const DH &dof_row,
+ const DH &dof_col,
+ SparsityPattern &sparsity);
+
+ /**
+ * Create the sparsity pattern for
+ * boundary matrices. See the general
+ * documentation of this class for more
+ * information.
+ *
+ * The actual type of the sparsity
+ * pattern may be SparsityPattern,
+ * CompressedSparsityPattern,
+ * BlockSparsityPattern,
+ * BlockCompressedSparsityPattern,
+ * BlockCompressedSetSparsityPattern, or
+ * any other class that satisfies similar
+ * requirements. It is assumed that the
+ * size of the sparsity pattern is
+ * already correct.
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_boundary_sparsity_pattern (const DH &dof,
+ const std::vector<unsigned int> &dof_to_boundary_mapping,
+ SparsityPattern &sparsity_pattern);
+
+ /**
+ * Write the sparsity structure of the
+ * matrix composed of the basis functions
+ * on the boundary into the
+ * matrix structure. In contrast to the
+ * previous function, only those parts
+ * of the boundary are considered of which
+ * the boundary indicator is listed in the
+ * set of numbers passed to this function.
+ *
+ * In fact, rather than a @p set
+ * of boundary indicators, a
+ * @p map needs to be passed,
+ * since most of the functions
+ * handling with boundary
+ * indicators take a mapping of
+ * boundary indicators and the
+ * respective boundary
+ * functions. The boundary
+ * function, however, is ignored
+ * in this function. If you have
+ * no functions at hand, but only
+ * the boundary indicators, set
+ * the function pointers to null
+ * pointers.
+ *
+ * For the type of the sparsity
+ * pattern, the same holds as
+ * said above.
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_boundary_sparsity_pattern (const DH &dof,
+ const typename FunctionMap<DH::space_dimension>::type &boundary_indicators,
+ const std::vector<unsigned int> &dof_to_boundary_mapping,
+ SparsityPattern &sparsity);
+
+ /**
+ * Generate sparsity pattern for
+ * fluxes, i.e. formulations of
+ * the discrete problem with
+ * discontinuous elements which
+ * couple across faces of cells.
+ * This is a replacement of the
+ * function
+ * @p make_sparsity_pattern for
+ * discontinuous methods. Since
+ * the fluxes include couplings
+ * between neighboring elements,
+ * the normal couplings and these
+ * extra matrix entries are
+ * considered.
+ */
+ template<class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const DH &dof_handler,
+ SparsityPattern &sparsity_pattern);
+
+ /**
+ * This function does the same as
+ * the other with the same name,
+ * but it gets a ConstraintMatrix
+ * additionally.
+ * This is for the case where you
+ * have fluxes but constraints as
+ * well.
+ * Not implemented for
+ * hp::DoFHandler.
+ *
+ * @ingroup constraints
+ */
+ template<class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const DH &dof_handler,
+ SparsityPattern &sparsity_pattern,
+ const ConstraintMatrix &constraints,
+ const bool keep_constrained_dofs = true,
+ const types::subdomain_id_t subdomain_id = numbers::invalid_unsigned_int);
+
+ /**
+ * This function does the same as
+ * the other with the same name,
+ * but it gets two additional
+ * coefficient matrices. A matrix
+ * entry will only be generated
+ * for two basis functions, if
+ * there is a non-zero entry
+ * linking their associated
+ * components in the coefficient
+ * matrix.
+ *
+ * There is one matrix for
+ * couplings in a cell and one
+ * for the couplings occuring in
+ * fluxes.
+ *
+ * Not implemented for
+ * hp::DoFHandler.
+ */
+ template <class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const DH &dof,
+ SparsityPattern &sparsity,
+ const Table<2,Coupling> &int_mask,
+ const Table<2,Coupling> &flux_mask);
+
+ //@}
+ /**
+ * @name Hanging Nodes
+ * @{
+ */
+
+ /**
+ * Compute the constraints resulting from
+ * the presence of hanging nodes. Hanging
+ * nodes are best explained using a small
+ * picture:
+ *
+ * @image html hanging_nodes.png
+ *
+ * In order to make a finite element
+ * function globally continuous, we have
+ * to make sure that the dark red nodes
+ * have values that are compatible with
+ * the adjacent yellow nodes, so that the
+ * function has no jump when coming from
+ * the small cells to the large one at
+ * the top right. We therefore have to
+ * add conditions that constrain those
+ * "hanging nodes".
+ *
+ * The object into
+ * which these are inserted is
+ * later used to condense the
+ * global system matrix and right
+ * hand side, and to extend the
+ * solution vectors from the true
+ * degrees of freedom also to the
+ * constraint nodes. This
+ * function is explained in
+ * detail in the @ref step_6
+ * "step-6" tutorial program and
+ * is used in almost all
+ * following programs as well.
+ *
+ * This function does not clear
+ * the constraint matrix object
+ * before use, in order to allow
+ * adding constraints from
+ * different sources to the same
+ * object. You therefore need to
+ * make sure it contains only
+ * constraints you still want;
+ * otherwise call the
+ * ConstraintMatrix::clear()
+ * function. Likewise, this
+ * function does not close the
+ * object since you may want to
+ * enter other constraints later
+ * on yourself.
+ *
+ * In the hp-case, i.e. when the
+ * argument is of type
+ * hp::DoFHandler, we consider
+ * constraints due to different
+ * finite elements used on two
+ * sides of a face between cells
+ * as hanging nodes as well. In
+ * other words, for hp finite
+ * elements, this function
+ * computes all constraints due
+ * to differing mesh sizes (h) or
+ * polynomial degrees (p) between
+ * adjacent cells.
+ *
+ * The template argument (and by
+ * consequence the type of the
+ * first argument to this
+ * function) can be either a
+ * ::DoFHandler, hp::DoFHandler,
+ * or MGDoFHandler.
+ *
+ * @ingroup constraints
+ */
+ template <class DH>
+ void
+ make_hanging_node_constraints (const DH &dof_handler,
+ ConstraintMatrix &constraints);
+ //@}
+
+ /**
+ * Take a vector of values which live on
+ * cells (e.g. an error per cell) and
+ * distribute it to the dofs in such a
+ * way that a finite element field
+ * results, which can then be further
+ * processed, e.g. for output. You should
+ * note that the resulting field will not
+ * be continuous at hanging nodes. This
+ * can, however, easily be arranged by
+ * calling the appropriate @p distribute
+ * function of a ConstraintMatrix
+ * object created for this
+ * DoFHandler object, after the
+ * vector has been fully assembled.
+ *
+ * It is assumed that the number
+ * of elements in @p cell_data
+ * equals the number of active
+ * cells and that the number of
+ * elements in @p dof_data equals
+ * <tt>dof_handler.n_dofs()</tt>.
+ *
+ * Note that the input vector may
+ * be a vector of any data type
+ * as long as it is convertible
+ * to @p double. The output
+ * vector, being a data vector on
+ * a DoF handler, always consists of
+ * elements of type @p double.
+ *
+ * In case the finite element
+ * used by this DoFHandler
+ * consists of more than one
+ * component, you need to specify
+ * which component in the output
+ * vector should be used to store
+ * the finite element field in;
+ * the default is zero (no other
+ * value is allowed if the finite
+ * element consists only of one
+ * component). All other
+ * components of the vector
+ * remain untouched, i.e. their
+ * contents are not changed.
+ *
+ * This function cannot be used
+ * if the finite element in use
+ * has shape functions that are
+ * non-zero in more than one
+ * vector component (in deal.II
+ * speak: they are
+ * non-primitive).
+ */
+ template <class DH, typename Number>
+ void
+ distribute_cell_to_dof_vector (const DH &dof_handler,
+ const Vector<Number> &cell_data,
+ Vector<double> &dof_data,
+ const unsigned int component = 0);
+
+ /**
+ * Extract the indices of the
+ * degrees of freedom belonging
+ * to certain vector components
+ * or blocks (if the last
+ * argument is <tt>true</tt>) of
+ * a vector-valued finite
+ * element. The bit vector @p
+ * select defines, which
+ * components or blocks of an
+ * FESystem are to be extracted
+ * from the DoFHandler @p
+ * dof. The entries in @p
+ * selected_dofs corresponding to
+ * degrees of freedom belonging
+ * to these components are then
+ * flagged @p true, while all
+ * others are set to @p false.
+ *
+ * The size of @p select must
+ * equal the number of components
+ * or blocks in the FiniteElement
+ * used by @p dof, depending on
+ * the argument
+ * <tt>blocks</tt>. The size of
+ * @p selected_dofs must equal
+ * DoFHandler::n_dofs(). Previous
+ * contents of this array are
+ * overwritten.
+ *
+ * If the finite element under
+ * consideration is not
+ * primitive, that is some or all
+ * of its shape functions are
+ * non-zero in more than one
+ * vector component (which holds,
+ * for example, for FE_Nedelec or
+ * FE_RaviartThomas elements), then
+ * shape functions cannot be
+ * associated with a single
+ * vector component. In this
+ * case, if <em>one</em> shape
+ * vector component of this
+ * element is flagged in
+ * @p component_select, then
+ * this is equivalent to
+ * selecting <em>all</em> vector
+ * components corresponding to
+ * this non-primitive base
+ * element.
+ */
+ template <int dim, int spacedim>
+ void
+ extract_dofs (const DoFHandler<dim,spacedim> &dof_handler,
+ const std::vector<bool> &select,
+ std::vector<bool> &selected_dofs,
+ const bool blocks = false);
+
+ /**
+ * The same function as above,
+ * but for a hp::DoFHandler.
+ */
+ template <int dim, int spacedim>
+ void
+ extract_dofs (const hp::DoFHandler<dim,spacedim> &dof_handler,
+ const std::vector<bool> &select,
+ std::vector<bool> &selected_dofs,
+ const bool blocks = false);
+
+ /**
+ * Do the same thing as
+ * extract_dofs() for one level
+ * of a multi-grid DoF numbering.
+ */
+ template <int dim, int spacedim>
+ void
+ extract_level_dofs (const unsigned int level,
+ const MGDoFHandler<dim,spacedim> &dof,
+ const std::vector<bool> &select,
+ std::vector<bool> &selected_dofs,
+ const bool blocks = false);
+
+ /**
+ * Extract all degrees of freedom
+ * which are at the boundary and
+ * belong to specified components
+ * of the solution. The function
+ * returns its results in the
+ * last non-default-valued
+ * parameter which contains
+ * @p true if a degree of
+ * freedom is at the boundary and
+ * belongs to one of the selected
+ * components, and @p false
+ * otherwise.
+ *
+ * By specifying the
+ * @p boundary_indicator
+ * variable, you can select which
+ * boundary indicators the faces
+ * have to have on which the
+ * degrees of freedom are located
+ * that shall be extracted. If it
+ * is an empty list, then all
+ * boundary indicators are
+ * accepted.
+ *
+ * The size of @p component_select
+ * shall equal the number of
+ * components in the finite
+ * element used by @p dof. The
+ * size of @p selected_dofs shall
+ * equal
+ * <tt>dof_handler.n_dofs()</tt>. Previous
+ * contents of this array or
+ * overwritten.
+ *
+ * Using the usual convention, if
+ * a shape function is non-zero
+ * in more than one component
+ * (i.e. it is non-primitive),
+ * then the element in the
+ * component mask is used that
+ * corresponds to the first
+ * non-zero components. Elements
+ * in the mask corresponding to
+ * later components are ignored.
+ */
+ template <class DH>
+ void
+ extract_boundary_dofs (const DH &dof_handler,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const std::set<unsigned char> &boundary_indicators = std::set<unsigned char>());
+
+ /**
+ * This function is similar to
+ * the extract_boundary_dofs()
+ * function but it extracts those
+ * degrees of freedom whose shape
+ * functions are nonzero on at
+ * least part of the selected
+ * boundary. For continuous
+ * elements, this is exactly the
+ * set of shape functions whose
+ * degrees of freedom are defined
+ * on boundary faces. On the
+ * other hand, if the finite
+ * element in used is a
+ * discontinuous element, all
+ * degrees of freedom are defined
+ * in the inside of cells and
+ * consequently none would be
+ * boundary degrees of
+ * freedom. Several of those
+ * would have shape functions
+ * that are nonzero on the
+ * boundary, however. This
+ * function therefore extracts
+ * all those for which the
+ * FiniteElement::has_support_on_face
+ * function says that it is
+ * nonzero on any face on one of
+ * the selected boundary parts.
+ */
+ template <class DH>
+ void
+ extract_dofs_with_support_on_boundary (const DH &dof_handler,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const std::set<unsigned char> &boundary_indicators = std::set<unsigned char>());
+
+ /**
+ * @name Hanging Nodes
+ * @{
+ */
+
+ /**
+ * Select all dofs that will be
+ * constrained by interface
+ * constraints, i.e. all hanging
+ * nodes.
+ *
+ * The size of @p selected_dofs
+ * shall equal
+ * <tt>dof_handler.n_dofs()</tt>. Previous
+ * contents of this array or
+ * overwritten.
+ */
+ template <int dim, int spacedim>
+ void
+ extract_hanging_node_dofs (const DoFHandler<dim,spacedim> &dof_handler,
+ std::vector<bool> &selected_dofs);
+ //@}
+
+ /**
+ * Flag all those degrees of
+ * freedom which are on cells
+ * with the given subdomain
+ * id. Note that DoFs on faces
+ * can belong to cells with
+ * differing subdomain ids, so
+ * the sets of flagged degrees of
+ * freedom are not mutually
+ * exclusive for different
+ * subdomain ids.
+ *
+ * If you want to get a unique
+ * association of degree of freedom with
+ * subdomains, use the
+ * @p get_subdomain_association
+ * function.
+ */
+ template <class DH>
+ void
+ extract_subdomain_dofs (const DH &dof_handler,
+ const types::subdomain_id_t subdomain_id,
+ std::vector<bool> &selected_dofs);
+
+
+ /**
+ * Extract the set of global DoF
+ * indices that are owned by the
+ * current processor. For regular
+ * DoFHandler objects, this set
+ * is the complete set with all
+ * DoF indices. In either case,
+ * it equals what
+ * DoFHandler::locally_owned_dofs()
+ * returns.
+ */
+ template <class DH>
+ void
+ extract_locally_owned_dofs (const DH & dof_handler,
+ IndexSet & dof_set);
+
+
+ /**
+ * Extract the set of global DoF
+ * indices that are active on the
+ * current DoFHandler. For
+ * regular DoFHandlers, these are
+ * all DoF indices, but for
+ * DoFHandler objects built on
+ * parallel::distributed::Triangulation
+ * this set is a superset of
+ * DoFHandler::locally_owned_dofs()
+ * and contains all DoF indices
+ * that live on all locally owned
+ * cells (including on the
+ * interface to ghost
+ * cells). However, it does not
+ * contain the DoF indices that
+ * are exclusively defined on
+ * ghost or artificial cells (see
+ * @ref GlossArtificialCell "the
+ * glossary").
+ *
+ * The degrees of freedom identified by
+ * this function equal those obtained
+ * from the
+ * dof_indices_with_subdomain_association()
+ * function when called with the locally
+ * owned subdomain id.
+ */
+ template <class DH>
+ void
+ extract_locally_active_dofs (const DH & dof_handler,
+ IndexSet & dof_set);
+
+ /**
+ * Extract the set of global DoF
+ * indices that are active on the
+ * current DoFHandler. For
+ * regular DoFHandlers, these are
+ * all DoF indices, but for
+ * DoFHandler objects built on
+ * parallel::distributed::Triangulation
+ * this set is the union of
+ * DoFHandler::locally_owned_dofs()
+ * and the DoF indices on all
+ * ghost cells. In essence, it is
+ * the DoF indices on all cells
+ * that are not artificial (see
+ * @ref GlossArtificialCell "the glossary").
+ */
+ template <class DH>
+ void
+ extract_locally_relevant_dofs (const DH & dof_handler,
IndexSet & dof_set);
- /**
- * Extract the set of global DoF
- * indices that are active on the
- * current DoFHandler. For
- * regular DoFHandlers, these are
- * all DoF indices, but for
- * DoFHandler objects built on
- * parallel::distributed::Triangulation
- * this set is the union of
- * DoFHandler::locally_owned_dofs()
- * and the DoF indices on all
- * ghost cells. In essence, it is
- * the DoF indices on all cells
- * that are not artificial (see
- * @ref GlossArtificialCell "the glossary").
- */
- template <class DH>
- static void
- extract_locally_relevant_dofs (const DH & dof_handler,
- IndexSet & dof_set);
-
- /**
- * Extract a vector that represents the
- * constant modes of the DoFHandler for
- * the components chosen by
- * <tt>component_select</tt>. The
- * constant modes on a discretization are
- * the null space of a Laplace operator
- * on the selected components with
- * Neumann boundary conditions
- * applied. The null space is a necessary
- * ingredient for obtaining a good AMG
- * preconditioner when using the class
- * TrilinosWrappers::PreconditionAMG.
- * Since the ML AMG package only works on
- * algebraic properties of the respective
- * matrix, it has no chance to detect
- * whether the matrix comes from a scalar
- * or a vector valued problem. However, a
- * near null space supplies exactly the
- * needed information about these
- * components. The null space will
- * consist of as many vectors as there
- * are true arguments in
- * <tt>component_select</tt>, each of
- * which will be one in one vector component and
- * zero in all others. We store this
- * object in a vector of vectors, where
- * the outer vector is of the size of the
- * number of selected components, and
- * each inner vector has as many
- * components as there are (locally owned) degrees of
- * freedom in the selected
- * components. Note that any matrix
- * associated with this null space must
- * have been constructed using the same
- * <tt>component_select</tt> argument,
- * since the numbering of DoFs is done
- * relative to the selected dofs, not to
- * all dofs.
- *
- * The main reason for this
- * program is the use of the
- * null space with the
- * AMG preconditioner.
- */
- template <class DH>
- static void
- extract_constant_modes (const DH &dof_handler,
- const std::vector<bool> &component_select,
- std::vector<std::vector<bool> > &constant_modes);
-
- /**
- * For each active cell of a DoFHandler
- * or hp::DoFHandler, extract the active
- * finite element index and fill the
- * vector given as second argument. This
- * vector is assumed to have as many
- * entries as there are active cells.
- *
- * For non-hp DoFHandler objects given as
- * first argument, the returned vector
- * will consist of only zeros, indicating
- * that all cells use the same finite
- * element. For a hp::DoFHandler, the
- * values may be different, though.
- */
- template <class DH>
- static void
- get_active_fe_indices (const DH &dof_handler,
- std::vector<unsigned int> &active_fe_indices);
-
- /**
- * For each DoF, return in the output
- * array to which subdomain (as given by
- * the <tt>cell->subdomain_id()</tt> function)
- * it belongs. The output array is
- * supposed to have the right size
- * already when calling this function.
- *
- * Note that degrees of freedom
- * associated with faces, edges, and
- * vertices may be associated with
- * multiple subdomains if they are
- * sitting on partition boundaries. In
- * these cases, we put them into one of
- * the associated partitions in an
- * undefined way. This may sometimes lead
- * to different numbers of degrees of
- * freedom in partitions, even if the
- * number of cells is perfectly
- * equidistributed. While this is
- * regrettable, it is not a problem in
- * practice since the number of degrees
- * of freedom on partition boundaries is
- * asymptotically vanishing as we refine
- * the mesh as long as the number of
- * partitions is kept constant.
- *
- * This function returns the association
- * of each DoF with one subdomain. If you
- * are looking for the association of
- * each @em cell with a subdomain, either
- * query the
- * <tt>cell->subdomain_id()</tt>
- * function, or use the
- * <tt>GridTools::get_subdomain_association</tt>
- * function.
- *
- * Note that this function is of
- * questionable use for DoFHandler objects built on
- * parallel::distributed::Triangulation
- * since in that case ownership of
- * individual degrees of freedom by MPI
- * processes is controlled by the DoF
- * handler object, not based on some
- * geometric algorithm in conjunction
- * with subdomain id. In particular, the
- * degrees of freedom identified by the
- * functions in this namespace as
- * associated with a subdomain are not
- * the same the
- * DoFHandler class
- * identifies as those it owns.
- */
- template <class DH>
- static void
- get_subdomain_association (const DH &dof_handler,
- std::vector<types::subdomain_id_t> &subdomain);
-
- /**
- * Count how many degrees of freedom are
- * uniquely associated with the given
- * @p subdomain index.
- *
- * Note that there may be rare cases
- * where cells with the given @p
- * subdomain index exist, but none of its
- * degrees of freedom are actually
- * associated with it. In that case, the
- * returned value will be zero.
- *
- * This function will generate an
- * exception if there are no cells with
- * the given @p subdomain index.
- *
- * This function returns the number of
- * DoFs associated with one subdomain. If
- * you are looking for the association of
- * @em cells with this subdomain, use the
- * <tt>GridTools::count_cells_with_subdomain_association</tt>
- * function.
- *
- * Note that this function is of
- * questionable use for DoFHandler objects built on
- * parallel::distributed::Triangulation
- * since in that case ownership of
- * individual degrees of freedom by MPI
- * processes is controlled by the DoF
- * handler object, not based on some
- * geometric algorithm in conjunction
- * with subdomain id. In particular, the
- * degrees of freedom identified by the
- * functions in this namespace as
- * associated with a subdomain are not
- * the same the
- * DoFHandler class
- * identifies as those it owns.
- */
- template <class DH>
- static unsigned int
- count_dofs_with_subdomain_association (const DH &dof_handler,
- const types::subdomain_id_t subdomain);
-
- /**
- * Count how many degrees of freedom are
- * uniquely associated with the given
- * @p subdomain index.
- *
- * This function does what the previous
- * one does except that it splits the
- * result among the vector components of
- * the finite element in use by the
- * DoFHandler object. The last argument
- * (which must have a length equal to the
- * number of vector components) will
- * therefore store how many degrees of
- * freedom of each vector component are
- * associated with the given subdomain.
- *
- * Note that this function is of
- * questionable use for DoFHandler objects built on
- * parallel::distributed::Triangulation
- * since in that case ownership of
- * individual degrees of freedom by MPI
- * processes is controlled by the DoF
- * handler object, not based on some
- * geometric algorithm in conjunction
- * with subdomain id. In particular, the
- * degrees of freedom identified by the
- * functions in this namespace as
- * associated with a subdomain are not
- * the same the
- * DoFHandler class
- * identifies as those it owns.
- */
- template <class DH>
- static void
- count_dofs_with_subdomain_association (const DH &dof_handler,
- const types::subdomain_id_t subdomain,
- std::vector<unsigned int> &n_dofs_on_subdomain);
-
- /**
- * Return a set of indices that denotes
- * the degrees of freedom that live on
- * the given subdomain, i.e. that are on
- * cells owned by the current
- * processor. Note that this includes the
- * ones that this subdomain "owns"
- * (i.e. the ones for which
- * get_subdomain_association() returns a
- * value equal to the subdomain given
- * here and that are selected by the
- * extract_locally_owned() function) but
- * also all of those that sit on the
- * boundary between the given subdomain
- * and other subdomain. In essence,
- * degrees of freedom that sit on
- * boundaries between subdomain will be
- * in the index sets returned by this
- * function for more than one subdomain.
- *
- * Note that this function is of
- * questionable use for DoFHandler objects built on
- * parallel::distributed::Triangulation
- * since in that case ownership of
- * individual degrees of freedom by MPI
- * processes is controlled by the DoF
- * handler object, not based on some
- * geometric algorithm in conjunction
- * with subdomain id. In particular, the
- * degrees of freedom identified by the
- * functions in this namespace as
- * associated with a subdomain are not
- * the same the
- * DoFHandler class
- * identifies as those it owns.
- */
- template <class DH>
- static
- IndexSet
- dof_indices_with_subdomain_association (const DH &dof_handler,
- const types::subdomain_id_t subdomain);
-
- /**
- * Count how many degrees of
- * freedom out of the total
- * number belong to each
- * component. If the number of
- * components the finite element
- * has is one (i.e. you only have
- * one scalar variable), then the
- * number in this component
- * obviously equals the total
- * number of degrees of
- * freedom. Otherwise, the sum of
- * the DoFs in all the components
- * needs to equal the total
- * number.
- *
- * However, the last statement
- * does not hold true if the
- * finite element is not
- * primitive, i.e. some or all of
- * its shape functions are
- * non-zero in more than one
- * vector component. This
- * applies, for example, to the
- * Nedelec or Raviart-Thomas
- * elements. In this case, a
- * degree of freedom is counted
- * in each component in which it
- * is non-zero, so that the sum
- * mentioned above is greater
- * than the total number of
- * degrees of freedom.
- *
- * This behavior can be switched
- * off by the optional parameter
- * <tt>vector_valued_once</tt>. If
- * this is <tt>true</tt>, the
- * number of components of a
- * nonprimitive vector valued
- * element is collected only in
- * the first component. All other
- * components will have a count
- * of zero.
- *
- * The additional optional
- * argument @p target_component
- * allows for a re-sorting and
- * grouping of components. To
- * this end, it contains for each
- * component the component number
- * it shall be counted as. Having
- * the same number entered
- * several times sums up several
- * components as the same. One of
- * the applications of this
- * argument is when you want to
- * form block matrices and
- * vectors, but want to pack
- * several components into the
- * same block (for example, when
- * you have @p dim velocities
- * and one pressure, to put all
- * velocities into one block, and
- * the pressure into another).
- *
- * The result is returned in @p
- * dofs_per_component. Note that
- * the size of @p
- * dofs_per_component needs to be
- * enough to hold all the indices
- * specified in @p
- * target_component. If this is
- * not the case, an assertion is
- * thrown. The indices not
- * targetted by target_components
- * are left untouched.
- */
- template <int dim, int spacedim>
- static void
- count_dofs_per_component (const DoFHandler<dim,spacedim>& dof_handler,
- std::vector<unsigned int>& dofs_per_component,
- const bool vector_valued_once = false,
- std::vector<unsigned int> target_component
- = std::vector<unsigned int>());
-
- /**
- * Count the degrees of freedom
- * in each block. This function
- * is similar to
- * count_dofs_per_component(),
- * with the difference that the
- * counting is done by
- * blocks. See @ref GlossBlock
- * "blocks" in the glossary for
- * details. Again the vectors are
- * assumed to have the correct
- * size before calling this
- * function. If this is not the
- * case, an assertion is thrown.
- *
- * This function is used in the
- * step-22,
- * step-31, and
- * step-32 tutorial
- * programs.
- *
- * @pre The dofs_per_block
- * variable has as many
- * components as the finite
- * element used by the
- * dof_handler argument has
- * blocks, or alternatively as
- * many blocks as are enumerated
- * in the target_blocks argument
- * if given.
- */
- template <int dim, int spacedim>
- static void
- count_dofs_per_block (const DoFHandler<dim,spacedim>& dof_handler,
- std::vector<unsigned int>& dofs_per_block,
- std::vector<unsigned int> target_blocks
- = std::vector<unsigned int>());
-
- /**
- * @deprecated See the previous
- * function with the same name
- * for a description. This
- * function exists for
- * compatibility with older
- * versions only.
- */
- template <int dim, int spacedim>
- static void
- count_dofs_per_component (const DoFHandler<dim,spacedim>& dof_handler,
- std::vector<unsigned int>& dofs_per_component,
- std::vector<unsigned int> target_component);
-
- /**
- * This function can be used when
- * different variables shall be
- * discretized on different
- * grids, where one grid is
- * coarser than the other. This
- * idea might seem nonsensical at
- * first, but has reasonable
- * applications in inverse
- * (parameter estimation)
- * problems, where there might
- * not be enough information to
- * recover the parameter on the
- * same grid as the state
- * variable; furthermore, the
- * smoothness properties of state
- * variable and parameter might
- * not be too much related, so
- * using different grids might be
- * an alternative to using
- * stronger regularization of the
- * problem.
- *
- * The basic idea of this
- * function is explained in the
- * following. Let us, for
- * convenience, denote by
- * ``parameter grid'' the coarser
- * of the two grids, and by
- * ``state grid'' the finer of
- * the two. We furthermore assume
- * that the finer grid can be
- * obtained by refinement of the
- * coarser one, i.e. the fine
- * grid is at least as much
- * refined as the coarse grid at
- * each point of the
- * domain. Then, each shape
- * function on the coarse grid
- * can be represented as a linear
- * combination of shape functions
- * on the fine grid (assuming
- * identical ansatz
- * spaces). Thus, if we
- * discretize as usual, using
- * shape functions on the fine
- * grid, we can consider the
- * restriction that the parameter
- * variable shall in fact be
- * discretized by shape functions
- * on the coarse grid as a
- * constraint. These constraints
- * are linear and happen to have
- * the form managed by the
- * ``ConstraintMatrix'' class.
- *
- * The construction of these
- * constraints is done as
- * follows: for each of the
- * degrees of freedom (i.e. shape
- * functions) on the coarse grid,
- * we compute its representation
- * on the fine grid, i.e. how the
- * linear combination of shape
- * functions on the fine grid
- * looks like that resembles the
- * shape function on the coarse
- * grid. From this information,
- * we can then compute the
- * constraints which have to hold
- * if a solution of a linear
- * equation on the fine grid
- * shall be representable on the
- * coarse grid. The exact
- * algorithm how these
- * constraints can be computed is
- * rather complicated and is best
- * understood by reading the
- * source code, which contains
- * many comments.
- *
- * Before explaining the use of
- * this function, we would like
- * to state that the total number
- * of degrees of freedom used for
- * the discretization is not
- * reduced by the use of this
- * function, i.e. even though we
- * discretize one variable on a
- * coarser grid, the total number
- * of degrees of freedom is that
- * of the fine grid. This seems
- * to be counter-productive,
- * since it does not give us a
- * benefit from using a coarser
- * grid. The reason why it may be
- * useful to choose this approach
- * nonetheless is three-fold:
- * first, as stated above, there
- * might not be enough
- * information to recover a
- * parameter on a fine grid,
- * i.e. we chose to discretize it
- * on the coarse grid not to save
- * DoFs, but for other
- * reasons. Second, the
- * ``ConstraintMatrix'' includes
- * the constraints into the
- * linear system of equations, by
- * which constrained nodes become
- * dummy nodes; we may therefore
- * exclude them from the linear
- * algebra, for example by
- * sorting them to the back of
- * the DoF numbers and simply
- * calling the solver for the
- * upper left block of the matrix
- * which works on the
- * non-constrained nodes only,
- * thus actually realizing the
- * savings in numerical effort
- * from the reduced number of
- * actual degrees of freedom. The
- * third reason is that for some
- * or other reason we have chosen
- * to use two different grids, it
- * may be actually quite
- * difficult to write a function
- * that assembles the system
- * matrix for finite element
- * spaces on different grids;
- * using the approach of
- * constraints as with this
- * function allows to use
- * standard techniques when
- * discretizing on only one grid
- * (the finer one) without having
- * to take care of the fact that
- * one or several of the variable
- * actually belong to different
- * grids.
- *
- * The use of this function is as
- * follows: it accepts as
- * parameters two DoF Handlers,
- * the first of which refers to
- * the coarse grid and the second
- * of which is the fine grid. On
- * both, a finite element is
- * represented by the DoF handler
- * objects, which will usually
- * have several components, which
- * may belong to different finite
- * elements. The second and
- * fourth parameter of this
- * function therefore state which
- * variable on the coarse grid
- * shall be used to restrict the
- * stated component on the fine
- * grid. Of course, the finite
- * elements used for the
- * respective components on the
- * two grids need to be the
- * same. An example may clarify
- * this: consider the parameter
- * estimation mentioned briefly
- * above; there, on the fine grid
- * the whole discretization is
- * done, thus the variables are
- * ``u'', ``q'', and the Lagrange
- * multiplier ``lambda'', which
- * are discretized using
- * continuous linear, piecewise
- * constant discontinuous, and
- * continuous linear elements,
- * respectively. Only the
- * parameter ``q'' shall be
- * represented on the coarse
- * grid, thus the DoFHandler
- * object on the coarse grid
- * represents only one variable,
- * discretized using piecewise
- * constant discontinuous
- * elements. Then, the parameter
- * denoting the component on the
- * coarse grid would be zero (the
- * only possible choice, since
- * the variable on the coarse
- * grid is scalar), and one on
- * the fine grid (corresponding
- * to the variable ``q''; zero
- * would be ``u'', two would be
- * ``lambda''). Furthermore, an
- * object of type IntergridMap
- * is needed; this could in
- * principle be generated by the
- * function itself from the two
- * DoFHandler objects, but since
- * it is probably available
- * anyway in programs that use
- * this function, we shall use it
- * instead of re-generating
- * it. Finally, the computed
- * constraints are entered into a
- * variable of type
- * ConstraintMatrix; the
- * constraints are added,
- * i.e. previous contents which
- * may have, for example, be
- * obtained from hanging nodes,
- * are not deleted, so that you
- * only need one object of this
- * type.
- */
- template <int dim, int spacedim>
- static void
- compute_intergrid_constraints (const DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const DoFHandler<dim,spacedim> &fine_grid,
- const unsigned int fine_component,
- const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- ConstraintMatrix &constraints);
-
-
- /**
- * This function generates a
- * matrix such that when a vector
- * of data with as many elements
- * as there are degrees of
- * freedom of this component on
- * the coarse grid is multiplied
- * to this matrix, we obtain a
- * vector with as many elements
- * are there are global degrees
- * of freedom on the fine
- * grid. All the elements of the
- * other components of the finite
- * element fields on the fine
- * grid are not touched.
- *
- * The output of this function is
- * a compressed format that can
- * be given to the @p reinit
- * functions of the
- * SparsityPattern ad
- * SparseMatrix classes.
- */
- template <int dim, int spacedim>
- static void
- compute_intergrid_transfer_representation (const DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const DoFHandler<dim,spacedim> &fine_grid,
- const unsigned int fine_component,
- const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- std::vector<std::map<unsigned int, float> > &transfer_representation);
-
- /**
- * Create a mapping from degree
- * of freedom indices to the
- * index of that degree of
- * freedom on the boundary. After
- * this operation, <tt>mapping[dof]</tt>
- * gives the index of the
- * degree of freedom with global
- * number @p dof in the list of
- * degrees of freedom on the
- * boundary. If the degree of
- * freedom requested is not on
- * the boundary, the value of
- * <tt>mapping[dof]</tt> is
- * @p invalid_dof_index. This
- * function is mainly used when
- * setting up matrices and
- * vectors on the boundary from
- * the trial functions, which
- * have global numbers, while the
- * matrices and vectors use
- * numbers of the trial functions
- * local to the boundary.
- *
- * Prior content of @p mapping
- * is deleted.
- */
- template <class DH>
- static void
- map_dof_to_boundary_indices (const DH &dof_handler,
- std::vector<unsigned int> &mapping);
-
- /**
- * Same as the previous function,
- * except that only those parts
- * of the boundary are considered
- * for which the boundary
- * indicator is listed in the
- * second argument.
- *
- * See the general doc of this
- * class for more information.
- */
- template <class DH>
- static void
- map_dof_to_boundary_indices (const DH &dof_handler,
- const std::set<unsigned char> &boundary_indicators,
- std::vector<unsigned int> &mapping);
-
- /**
- * Return a list of support
- * points for all the degrees of
- * freedom handled by this DoF
- * handler object. This function,
- * of course, only works if the
- * finite element object used by
- * the DoF handler object
- * actually provides support
- * points, i.e. no edge elements
- * or the like. Otherwise, an
- * exception is thrown.
- *
- * The given array must have a
- * length of as many elements as
- * there are degrees of freedom.
- */
- template <int dim, int spacedim>
- static void
- map_dofs_to_support_points (const Mapping<dim,spacedim> &mapping,
- const DoFHandler<dim,spacedim> &dof_handler,
- std::vector<Point<spacedim> > &support_points);
-
- /**
- * This is the opposite function
- * to the one above. It generates
- * a map where the keys are the
- * support points of the degrees
- * of freedom, while the values
- * are the DoF indices.
- *
- * Since there is no natural
- * order in the space of points
- * (except for the 1d case), you
- * have to provide a map with an
- * explicitly specified
- * comparator object. This
- * function is therefore
- * templatized on the comparator
- * object. Previous content of
- * the map object is deleted in
- * this function.
- *
- * Just as with the function
- * above, it is assumed that the
- * finite element in use here
- * actually supports the notion
- * of support points of all its
- * components.
- */
- template <class DH, class Comp>
- static void
- map_support_points_to_dofs (const Mapping<DH::dimension, DH::space_dimension> &mapping,
- const DH &dof_handler,
- std::map<Point<DH::space_dimension>, unsigned int, Comp> &point_to_index_map);
-
- /**
- * Map a coupling table from the
- * user friendly organization by
- * components to the organization
- * by blocks. Specializations of
- * this function for DoFHandler
- * and hp::DoFHandler are
- * required due to the different
- * results of their finite
- * element access.
- *
- * The return vector will be
- * initialized to the correct
- * length inside this function.
- */
- template <int dim, int spacedim>
- static void
- convert_couplings_to_blocks (const hp::DoFHandler<dim,spacedim>& dof_handler,
- const Table<2, Coupling>& table_by_component,
- std::vector<Table<2,Coupling> >& tables_by_block);
-
- /**
- * Make a constraint matrix for the
- * constraints that result from zero
- * boundary values.
- *
- * This function constrains all
- * degrees of freedom on the
- * boundary. Optionally, you can
- * add a component mask, which
- * restricts this functionality
- * to a subset of an FESystem.
- *
- * For non-@ref GlossPrimitive "primitive"
- * shape functions, any degree of freedom
- * is affected that belongs to a
- * shape function where at least
- * one of its nonzero components
- * is affected.
- *
- * This function is used
- * in step-36, for
- * example.
- *
- * @ingroup constraints
- */
- template <int dim, int spacedim, template <int, int> class DH>
- static void
- make_zero_boundary_constraints (const DH<dim,spacedim> &dof,
- ConstraintMatrix &zero_boundary_constraints,
- const std::vector<bool> &component_mask_=std::vector<bool>());
-
- /**
- * Map a coupling table from the
- * user friendly organization by
- * components to the organization
- * by blocks. Specializations of
- * this function for DoFHandler
- * and hp::DoFHandler are
- * required due to the different
- * results of their finite
- * element access.
- *
- * The return vector will be
- * initialized to the correct
- * length inside this function.
- */
- template <int dim, int spacedim>
- static void
- convert_couplings_to_blocks (const DoFHandler<dim,spacedim>& dof_handler,
- const Table<2, Coupling>& table_by_component,
- std::vector<Table<2,Coupling> >& tables_by_block);
-
- /**
- * Given a finite element and a table how
- * the vector components of it couple
- * with each other, compute and return a
- * table that describes how the
- * individual shape functions couple with
- * each other.
- */
- template <int dim, int spacedim>
- static
- Table<2,Coupling>
- dof_couplings_from_component_couplings (const FiniteElement<dim,spacedim> &fe,
- const Table<2,Coupling> &component_couplings);
-
- /**
- * Same function as above for a
- * collection of finite elements,
- * returning a collection of tables.
- *
- * The function currently treats
- * DoFTools::Couplings::nonzero the same
- * as DoFTools::Couplings::always .
- */
- template <int dim, int spacedim>
- static
- std::vector<Table<2,Coupling> >
- dof_couplings_from_component_couplings (const hp::FECollection<dim,spacedim> &fe,
- const Table<2,Coupling> &component_couplings);
+ /**
+ * Extract a vector that represents the
+ * constant modes of the DoFHandler for
+ * the components chosen by
+ * <tt>component_select</tt>. The
+ * constant modes on a discretization are
+ * the null space of a Laplace operator
+ * on the selected components with
+ * Neumann boundary conditions
+ * applied. The null space is a necessary
+ * ingredient for obtaining a good AMG
+ * preconditioner when using the class
+ * TrilinosWrappers::PreconditionAMG.
+ * Since the ML AMG package only works on
+ * algebraic properties of the respective
+ * matrix, it has no chance to detect
+ * whether the matrix comes from a scalar
+ * or a vector valued problem. However, a
+ * near null space supplies exactly the
+ * needed information about these
+ * components. The null space will
+ * consist of as many vectors as there
+ * are true arguments in
+ * <tt>component_select</tt>, each of
+ * which will be one in one vector component and
+ * zero in all others. We store this
+ * object in a vector of vectors, where
+ * the outer vector is of the size of the
+ * number of selected components, and
+ * each inner vector has as many
+ * components as there are (locally owned) degrees of
+ * freedom in the selected
+ * components. Note that any matrix
+ * associated with this null space must
+ * have been constructed using the same
+ * <tt>component_select</tt> argument,
+ * since the numbering of DoFs is done
+ * relative to the selected dofs, not to
+ * all dofs.
+ *
+ * The main reason for this
+ * program is the use of the
+ * null space with the
+ * AMG preconditioner.
+ */
+ template <class DH>
+ void
+ extract_constant_modes (const DH &dof_handler,
+ const std::vector<bool> &component_select,
+ std::vector<std::vector<bool> > &constant_modes);
+
+ /**
+ * For each active cell of a DoFHandler
+ * or hp::DoFHandler, extract the active
+ * finite element index and fill the
+ * vector given as second argument. This
+ * vector is assumed to have as many
+ * entries as there are active cells.
+ *
+ * For non-hp DoFHandler objects given as
+ * first argument, the returned vector
+ * will consist of only zeros, indicating
+ * that all cells use the same finite
+ * element. For a hp::DoFHandler, the
+ * values may be different, though.
+ */
+ template <class DH>
+ void
+ get_active_fe_indices (const DH &dof_handler,
+ std::vector<unsigned int> &active_fe_indices);
+
+ /**
+ * For each DoF, return in the output
+ * array to which subdomain (as given by
+ * the <tt>cell->subdomain_id()</tt> function)
+ * it belongs. The output array is
+ * supposed to have the right size
+ * already when calling this function.
+ *
+ * Note that degrees of freedom
+ * associated with faces, edges, and
+ * vertices may be associated with
+ * multiple subdomains if they are
+ * sitting on partition boundaries. In
+ * these cases, we put them into one of
+ * the associated partitions in an
+ * undefined way. This may sometimes lead
+ * to different numbers of degrees of
+ * freedom in partitions, even if the
+ * number of cells is perfectly
+ * equidistributed. While this is
+ * regrettable, it is not a problem in
+ * practice since the number of degrees
+ * of freedom on partition boundaries is
+ * asymptotically vanishing as we refine
+ * the mesh as long as the number of
+ * partitions is kept constant.
+ *
+ * This function returns the association
+ * of each DoF with one subdomain. If you
+ * are looking for the association of
+ * each @em cell with a subdomain, either
+ * query the
+ * <tt>cell->subdomain_id()</tt>
+ * function, or use the
+ * <tt>GridTools::get_subdomain_association</tt>
+ * function.
+ *
+ * Note that this function is of
+ * questionable use for DoFHandler objects built on
+ * parallel::distributed::Triangulation
+ * since in that case ownership of
+ * individual degrees of freedom by MPI
+ * processes is controlled by the DoF
+ * handler object, not based on some
+ * geometric algorithm in conjunction
+ * with subdomain id. In particular, the
+ * degrees of freedom identified by the
+ * functions in this namespace as
+ * associated with a subdomain are not
+ * the same the
+ * DoFHandler class
+ * identifies as those it owns.
+ */
+ template <class DH>
+ void
+ get_subdomain_association (const DH &dof_handler,
+ std::vector<types::subdomain_id_t> &subdomain);
+
+ /**
+ * Count how many degrees of freedom are
+ * uniquely associated with the given
+ * @p subdomain index.
+ *
+ * Note that there may be rare cases
+ * where cells with the given @p
+ * subdomain index exist, but none of its
+ * degrees of freedom are actually
+ * associated with it. In that case, the
+ * returned value will be zero.
+ *
+ * This function will generate an
+ * exception if there are no cells with
+ * the given @p subdomain index.
+ *
+ * This function returns the number of
+ * DoFs associated with one subdomain. If
+ * you are looking for the association of
+ * @em cells with this subdomain, use the
+ * <tt>GridTools::count_cells_with_subdomain_association</tt>
+ * function.
+ *
+ * Note that this function is of
+ * questionable use for DoFHandler objects built on
+ * parallel::distributed::Triangulation
+ * since in that case ownership of
+ * individual degrees of freedom by MPI
+ * processes is controlled by the DoF
+ * handler object, not based on some
+ * geometric algorithm in conjunction
+ * with subdomain id. In particular, the
+ * degrees of freedom identified by the
+ * functions in this namespace as
+ * associated with a subdomain are not
+ * the same the
+ * DoFHandler class
+ * identifies as those it owns.
+ */
+ template <class DH>
+ unsigned int
+ count_dofs_with_subdomain_association (const DH &dof_handler,
+ const types::subdomain_id_t subdomain);
+
+ /**
+ * Count how many degrees of freedom are
+ * uniquely associated with the given
+ * @p subdomain index.
+ *
+ * This function does what the previous
+ * one does except that it splits the
+ * result among the vector components of
+ * the finite element in use by the
+ * DoFHandler object. The last argument
+ * (which must have a length equal to the
+ * number of vector components) will
+ * therefore store how many degrees of
+ * freedom of each vector component are
+ * associated with the given subdomain.
+ *
+ * Note that this function is of
+ * questionable use for DoFHandler objects built on
+ * parallel::distributed::Triangulation
+ * since in that case ownership of
+ * individual degrees of freedom by MPI
+ * processes is controlled by the DoF
+ * handler object, not based on some
+ * geometric algorithm in conjunction
+ * with subdomain id. In particular, the
+ * degrees of freedom identified by the
+ * functions in this namespace as
+ * associated with a subdomain are not
+ * the same the
+ * DoFHandler class
+ * identifies as those it owns.
+ */
+ template <class DH>
+ void
+ count_dofs_with_subdomain_association (const DH &dof_handler,
+ const types::subdomain_id_t subdomain,
+ std::vector<unsigned int> &n_dofs_on_subdomain);
+
+ /**
+ * Return a set of indices that denotes
+ * the degrees of freedom that live on
+ * the given subdomain, i.e. that are on
+ * cells owned by the current
+ * processor. Note that this includes the
+ * ones that this subdomain "owns"
+ * (i.e. the ones for which
+ * get_subdomain_association() returns a
+ * value equal to the subdomain given
+ * here and that are selected by the
+ * extract_locally_owned() function) but
+ * also all of those that sit on the
+ * boundary between the given subdomain
+ * and other subdomain. In essence,
+ * degrees of freedom that sit on
+ * boundaries between subdomain will be
+ * in the index sets returned by this
+ * function for more than one subdomain.
+ *
+ * Note that this function is of
+ * questionable use for DoFHandler objects built on
+ * parallel::distributed::Triangulation
+ * since in that case ownership of
+ * individual degrees of freedom by MPI
+ * processes is controlled by the DoF
+ * handler object, not based on some
+ * geometric algorithm in conjunction
+ * with subdomain id. In particular, the
+ * degrees of freedom identified by the
+ * functions in this namespace as
+ * associated with a subdomain are not
+ * the same the
+ * DoFHandler class
+ * identifies as those it owns.
+ */
+ template <class DH>
+ IndexSet
+ dof_indices_with_subdomain_association (const DH &dof_handler,
+ const types::subdomain_id_t subdomain);
+
+ /**
+ * Count how many degrees of
+ * freedom out of the total
+ * number belong to each
+ * component. If the number of
+ * components the finite element
+ * has is one (i.e. you only have
+ * one scalar variable), then the
+ * number in this component
+ * obviously equals the total
+ * number of degrees of
+ * freedom. Otherwise, the sum of
+ * the DoFs in all the components
+ * needs to equal the total
+ * number.
+ *
+ * However, the last statement
+ * does not hold true if the
+ * finite element is not
+ * primitive, i.e. some or all of
+ * its shape functions are
+ * non-zero in more than one
+ * vector component. This
+ * applies, for example, to the
+ * Nedelec or Raviart-Thomas
+ * elements. In this case, a
+ * degree of freedom is counted
+ * in each component in which it
+ * is non-zero, so that the sum
+ * mentioned above is greater
+ * than the total number of
+ * degrees of freedom.
+ *
+ * This behavior can be switched
+ * off by the optional parameter
+ * <tt>vector_valued_once</tt>. If
+ * this is <tt>true</tt>, the
+ * number of components of a
+ * nonprimitive vector valued
+ * element is collected only in
+ * the first component. All other
+ * components will have a count
+ * of zero.
+ *
+ * The additional optional
+ * argument @p target_component
+ * allows for a re-sorting and
+ * grouping of components. To
+ * this end, it contains for each
+ * component the component number
+ * it shall be counted as. Having
+ * the same number entered
+ * several times sums up several
+ * components as the same. One of
+ * the applications of this
+ * argument is when you want to
+ * form block matrices and
+ * vectors, but want to pack
+ * several components into the
+ * same block (for example, when
+ * you have @p dim velocities
+ * and one pressure, to put all
+ * velocities into one block, and
+ * the pressure into another).
+ *
+ * The result is returned in @p
+ * dofs_per_component. Note that
+ * the size of @p
+ * dofs_per_component needs to be
+ * enough to hold all the indices
+ * specified in @p
+ * target_component. If this is
+ * not the case, an assertion is
+ * thrown. The indices not
+ * targetted by target_components
+ * are left untouched.
+ */
+ template <int dim, int spacedim>
+ void
+ count_dofs_per_component (const DoFHandler<dim,spacedim>& dof_handler,
+ std::vector<unsigned int>& dofs_per_component,
+ const bool vector_valued_once = false,
+ std::vector<unsigned int> target_component
+ = std::vector<unsigned int>());
+
+ /**
+ * Count the degrees of freedom
+ * in each block. This function
+ * is similar to
+ * count_dofs_per_component(),
+ * with the difference that the
+ * counting is done by
+ * blocks. See @ref GlossBlock
+ * "blocks" in the glossary for
+ * details. Again the vectors are
+ * assumed to have the correct
+ * size before calling this
+ * function. If this is not the
+ * case, an assertion is thrown.
+ *
+ * This function is used in the
+ * step-22,
+ * step-31, and
+ * step-32 tutorial
+ * programs.
+ *
+ * @pre The dofs_per_block
+ * variable has as many
+ * components as the finite
+ * element used by the
+ * dof_handler argument has
+ * blocks, or alternatively as
+ * many blocks as are enumerated
+ * in the target_blocks argument
+ * if given.
+ */
+ template <int dim, int spacedim>
+ void
+ count_dofs_per_block (const DoFHandler<dim,spacedim>& dof_handler,
+ std::vector<unsigned int>& dofs_per_block,
+ std::vector<unsigned int> target_blocks
+ = std::vector<unsigned int>());
+
+ /**
+ * @deprecated See the previous
+ * function with the same name
+ * for a description. This
+ * function exists for
+ * compatibility with older
+ * versions only.
+ */
+ template <int dim, int spacedim>
+ void
+ count_dofs_per_component (const DoFHandler<dim,spacedim>& dof_handler,
+ std::vector<unsigned int>& dofs_per_component,
+ std::vector<unsigned int> target_component);
+
+ /**
+ * This function can be used when
+ * different variables shall be
+ * discretized on different
+ * grids, where one grid is
+ * coarser than the other. This
+ * idea might seem nonsensical at
+ * first, but has reasonable
+ * applications in inverse
+ * (parameter estimation)
+ * problems, where there might
+ * not be enough information to
+ * recover the parameter on the
+ * same grid as the state
+ * variable; furthermore, the
+ * smoothness properties of state
+ * variable and parameter might
+ * not be too much related, so
+ * using different grids might be
+ * an alternative to using
+ * stronger regularization of the
+ * problem.
+ *
+ * The basic idea of this
+ * function is explained in the
+ * following. Let us, for
+ * convenience, denote by
+ * ``parameter grid'' the coarser
+ * of the two grids, and by
+ * ``state grid'' the finer of
+ * the two. We furthermore assume
+ * that the finer grid can be
+ * obtained by refinement of the
+ * coarser one, i.e. the fine
+ * grid is at least as much
+ * refined as the coarse grid at
+ * each point of the
+ * domain. Then, each shape
+ * function on the coarse grid
+ * can be represented as a linear
+ * combination of shape functions
+ * on the fine grid (assuming
+ * identical ansatz
+ * spaces). Thus, if we
+ * discretize as usual, using
+ * shape functions on the fine
+ * grid, we can consider the
+ * restriction that the parameter
+ * variable shall in fact be
+ * discretized by shape functions
+ * on the coarse grid as a
+ * constraint. These constraints
+ * are linear and happen to have
+ * the form managed by the
+ * ``ConstraintMatrix'' class.
+ *
+ * The construction of these
+ * constraints is done as
+ * follows: for each of the
+ * degrees of freedom (i.e. shape
+ * functions) on the coarse grid,
+ * we compute its representation
+ * on the fine grid, i.e. how the
+ * linear combination of shape
+ * functions on the fine grid
+ * looks like that resembles the
+ * shape function on the coarse
+ * grid. From this information,
+ * we can then compute the
+ * constraints which have to hold
+ * if a solution of a linear
+ * equation on the fine grid
+ * shall be representable on the
+ * coarse grid. The exact
+ * algorithm how these
+ * constraints can be computed is
+ * rather complicated and is best
+ * understood by reading the
+ * source code, which contains
+ * many comments.
+ *
+ * Before explaining the use of
+ * this function, we would like
+ * to state that the total number
+ * of degrees of freedom used for
+ * the discretization is not
+ * reduced by the use of this
+ * function, i.e. even though we
+ * discretize one variable on a
+ * coarser grid, the total number
+ * of degrees of freedom is that
+ * of the fine grid. This seems
+ * to be counter-productive,
+ * since it does not give us a
+ * benefit from using a coarser
+ * grid. The reason why it may be
+ * useful to choose this approach
+ * nonetheless is three-fold:
+ * first, as stated above, there
+ * might not be enough
+ * information to recover a
+ * parameter on a fine grid,
+ * i.e. we chose to discretize it
+ * on the coarse grid not to save
+ * DoFs, but for other
+ * reasons. Second, the
+ * ``ConstraintMatrix'' includes
+ * the constraints into the
+ * linear system of equations, by
+ * which constrained nodes become
+ * dummy nodes; we may therefore
+ * exclude them from the linear
+ * algebra, for example by
+ * sorting them to the back of
+ * the DoF numbers and simply
+ * calling the solver for the
+ * upper left block of the matrix
+ * which works on the
+ * non-constrained nodes only,
+ * thus actually realizing the
+ * savings in numerical effort
+ * from the reduced number of
+ * actual degrees of freedom. The
+ * third reason is that for some
+ * or other reason we have chosen
+ * to use two different grids, it
+ * may be actually quite
+ * difficult to write a function
+ * that assembles the system
+ * matrix for finite element
+ * spaces on different grids;
+ * using the approach of
+ * constraints as with this
+ * function allows to use
+ * standard techniques when
+ * discretizing on only one grid
+ * (the finer one) without having
+ * to take care of the fact that
+ * one or several of the variable
+ * actually belong to different
+ * grids.
+ *
+ * The use of this function is as
+ * follows: it accepts as
+ * parameters two DoF Handlers,
+ * the first of which refers to
+ * the coarse grid and the second
+ * of which is the fine grid. On
+ * both, a finite element is
+ * represented by the DoF handler
+ * objects, which will usually
+ * have several components, which
+ * may belong to different finite
+ * elements. The second and
+ * fourth parameter of this
+ * function therefore state which
+ * variable on the coarse grid
+ * shall be used to restrict the
+ * stated component on the fine
+ * grid. Of course, the finite
+ * elements used for the
+ * respective components on the
+ * two grids need to be the
+ * same. An example may clarify
+ * this: consider the parameter
+ * estimation mentioned briefly
+ * above; there, on the fine grid
+ * the whole discretization is
+ * done, thus the variables are
+ * ``u'', ``q'', and the Lagrange
+ * multiplier ``lambda'', which
+ * are discretized using
+ * continuous linear, piecewise
+ * constant discontinuous, and
+ * continuous linear elements,
+ * respectively. Only the
+ * parameter ``q'' shall be
+ * represented on the coarse
+ * grid, thus the DoFHandler
+ * object on the coarse grid
+ * represents only one variable,
+ * discretized using piecewise
+ * constant discontinuous
+ * elements. Then, the parameter
+ * denoting the component on the
+ * coarse grid would be zero (the
+ * only possible choice, since
+ * the variable on the coarse
+ * grid is scalar), and one on
+ * the fine grid (corresponding
+ * to the variable ``q''; zero
+ * would be ``u'', two would be
+ * ``lambda''). Furthermore, an
+ * object of type IntergridMap
+ * is needed; this could in
+ * principle be generated by the
+ * function itself from the two
+ * DoFHandler objects, but since
+ * it is probably available
+ * anyway in programs that use
+ * this function, we shall use it
+ * instead of re-generating
+ * it. Finally, the computed
+ * constraints are entered into a
+ * variable of type
+ * ConstraintMatrix; the
+ * constraints are added,
+ * i.e. previous contents which
+ * may have, for example, be
+ * obtained from hanging nodes,
+ * are not deleted, so that you
+ * only need one object of this
+ * type.
+ */
+ template <int dim, int spacedim>
+ void
+ compute_intergrid_constraints (const DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const DoFHandler<dim,spacedim> &fine_grid,
+ const unsigned int fine_component,
+ const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ ConstraintMatrix &constraints);
+
+
+ /**
+ * This function generates a
+ * matrix such that when a vector
+ * of data with as many elements
+ * as there are degrees of
+ * freedom of this component on
+ * the coarse grid is multiplied
+ * to this matrix, we obtain a
+ * vector with as many elements
+ * are there are global degrees
+ * of freedom on the fine
+ * grid. All the elements of the
+ * other components of the finite
+ * element fields on the fine
+ * grid are not touched.
+ *
+ * The output of this function is
+ * a compressed format that can
+ * be given to the @p reinit
+ * functions of the
+ * SparsityPattern ad
+ * SparseMatrix classes.
+ */
+ template <int dim, int spacedim>
+ void
+ compute_intergrid_transfer_representation (const DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const DoFHandler<dim,spacedim> &fine_grid,
+ const unsigned int fine_component,
+ const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ std::vector<std::map<unsigned int, float> > &transfer_representation);
+
+ /**
+ * Create a mapping from degree
+ * of freedom indices to the
+ * index of that degree of
+ * freedom on the boundary. After
+ * this operation, <tt>mapping[dof]</tt>
+ * gives the index of the
+ * degree of freedom with global
+ * number @p dof in the list of
+ * degrees of freedom on the
+ * boundary. If the degree of
+ * freedom requested is not on
+ * the boundary, the value of
+ * <tt>mapping[dof]</tt> is
+ * @p invalid_dof_index. This
+ * function is mainly used when
+ * setting up matrices and
+ * vectors on the boundary from
+ * the trial functions, which
+ * have global numbers, while the
+ * matrices and vectors use
+ * numbers of the trial functions
+ * local to the boundary.
+ *
+ * Prior content of @p mapping
+ * is deleted.
+ */
+ template <class DH>
+ void
+ map_dof_to_boundary_indices (const DH &dof_handler,
+ std::vector<unsigned int> &mapping);
+
+ /**
+ * Same as the previous function,
+ * except that only those parts
+ * of the boundary are considered
+ * for which the boundary
+ * indicator is listed in the
+ * second argument.
+ *
+ * See the general doc of this
+ * class for more information.
+ */
+ template <class DH>
+ void
+ map_dof_to_boundary_indices (const DH &dof_handler,
+ const std::set<unsigned char> &boundary_indicators,
+ std::vector<unsigned int> &mapping);
+
+ /**
+ * Return a list of support
+ * points for all the degrees of
+ * freedom handled by this DoF
+ * handler object. This function,
+ * of course, only works if the
+ * finite element object used by
+ * the DoF handler object
+ * actually provides support
+ * points, i.e. no edge elements
+ * or the like. Otherwise, an
+ * exception is thrown.
+ *
+ * The given array must have a
+ * length of as many elements as
+ * there are degrees of freedom.
+ */
+ template <int dim, int spacedim>
+ void
+ map_dofs_to_support_points (const Mapping<dim,spacedim> &mapping,
+ const DoFHandler<dim,spacedim> &dof_handler,
+ std::vector<Point<spacedim> > &support_points);
+
+ /**
+ * This is the opposite function
+ * to the one above. It generates
+ * a map where the keys are the
+ * support points of the degrees
+ * of freedom, while the values
+ * are the DoF indices.
+ *
+ * Since there is no natural
+ * order in the space of points
+ * (except for the 1d case), you
+ * have to provide a map with an
+ * explicitly specified
+ * comparator object. This
+ * function is therefore
+ * templatized on the comparator
+ * object. Previous content of
+ * the map object is deleted in
+ * this function.
+ *
+ * Just as with the function
+ * above, it is assumed that the
+ * finite element in use here
+ * actually supports the notion
+ * of support points of all its
+ * components.
+ */
+ template <class DH, class Comp>
+ void
+ map_support_points_to_dofs (const Mapping<DH::dimension, DH::space_dimension> &mapping,
+ const DH &dof_handler,
+ std::map<Point<DH::space_dimension>, unsigned int, Comp> &point_to_index_map);
+
+ /**
+ * Map a coupling table from the
+ * user friendly organization by
+ * components to the organization
+ * by blocks. Specializations of
+ * this function for DoFHandler
+ * and hp::DoFHandler are
+ * required due to the different
+ * results of their finite
+ * element access.
+ *
+ * The return vector will be
+ * initialized to the correct
+ * length inside this function.
+ */
+ template <int dim, int spacedim>
+ void
+ convert_couplings_to_blocks (const hp::DoFHandler<dim,spacedim>& dof_handler,
+ const Table<2, Coupling>& table_by_component,
+ std::vector<Table<2,Coupling> >& tables_by_block);
+
+ /**
+ * Make a constraint matrix for the
+ * constraints that result from zero
+ * boundary values.
+ *
+ * This function constrains all
+ * degrees of freedom on the
+ * boundary. Optionally, you can
+ * add a component mask, which
+ * restricts this functionality
+ * to a subset of an FESystem.
+ *
+ * For non-@ref GlossPrimitive "primitive"
+ * shape functions, any degree of freedom
+ * is affected that belongs to a
+ * shape function where at least
+ * one of its nonzero components
+ * is affected.
+ *
+ * This function is used
+ * in step-36, for
+ * example.
+ *
+ * @ingroup constraints
+ */
+ template <int dim, int spacedim, template <int, int> class DH>
+ void
+ make_zero_boundary_constraints (const DH<dim,spacedim> &dof,
+ ConstraintMatrix &zero_boundary_constraints,
+ const std::vector<bool> &component_mask_=std::vector<bool>());
+
+ /**
+ * Map a coupling table from the
+ * user friendly organization by
+ * components to the organization
+ * by blocks. Specializations of
+ * this function for DoFHandler
+ * and hp::DoFHandler are
+ * required due to the different
+ * results of their finite
+ * element access.
+ *
+ * The return vector will be
+ * initialized to the correct
+ * length inside this function.
+ */
+ template <int dim, int spacedim>
+ void
+ convert_couplings_to_blocks (const DoFHandler<dim,spacedim>& dof_handler,
+ const Table<2, Coupling>& table_by_component,
+ std::vector<Table<2,Coupling> >& tables_by_block);
+
+ /**
+ * Given a finite element and a table how
+ * the vector components of it couple
+ * with each other, compute and return a
+ * table that describes how the
+ * individual shape functions couple with
+ * each other.
+ */
+ template <int dim, int spacedim>
+ Table<2,Coupling>
+ dof_couplings_from_component_couplings (const FiniteElement<dim,spacedim> &fe,
+ const Table<2,Coupling> &component_couplings);
+
+ /**
+ * Same function as above for a
+ * collection of finite elements,
+ * returning a collection of tables.
+ *
+ * The function currently treats
+ * DoFTools::Couplings::nonzero the same
+ * as DoFTools::Couplings::always .
+ */
+ template <int dim, int spacedim>
+ std::vector<Table<2,Coupling> >
+ dof_couplings_from_component_couplings (const hp::FECollection<dim,spacedim> &fe,
+ const Table<2,Coupling> &component_couplings);
- /**
- * Exception
- */
- DeclException0 (ExcFEHasNoSupportPoints);
- /**
- * Exception
- */
- DeclException0 (ExcFENotPrimitive);
- /**
- * Exception
- */
- DeclException2 (ExcWrongSize,
- int, int,
- << "The dimension " << arg1 << " of the vector is wrong. "
- << "It should be " << arg2);
- /**
- * Exception
- */
- DeclException2 (ExcInvalidComponent,
- int, int,
- << "The component you gave (" << arg1 << ") "
- << "is invalid with respect to the number "
- << "of components in the finite element "
- << "(" << arg2 << ")");
- /**
- * Exception
- */
- DeclException0 (ExcFiniteElementsDontMatch);
- /**
- * Exception
- */
- DeclException0 (ExcGridNotCoarser);
- /**
- * Exception
- */
- DeclException0 (ExcGridsDontMatch);
- /**
- * Exception
- */
- DeclException0 (ExcNoFESelected);
- /**
- * Exception
- */
- DeclException0 (ExcInvalidBoundaryIndicator);
-};
+ /**
+ * Exception
+ */
+ DeclException0 (ExcFEHasNoSupportPoints);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcFENotPrimitive);
+ /**
+ * Exception
+ */
+ DeclException2 (ExcWrongSize,
+ int, int,
+ << "The dimension " << arg1 << " of the vector is wrong. "
+ << "It should be " << arg2);
+ /**
+ * Exception
+ */
+ DeclException2 (ExcInvalidComponent,
+ int, int,
+ << "The component you gave (" << arg1 << ") "
+ << "is invalid with respect to the number "
+ << "of components in the finite element "
+ << "(" << arg2 << ")");
+ /**
+ * Exception
+ */
+ DeclException0 (ExcFiniteElementsDontMatch);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcGridNotCoarser);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcGridsDontMatch);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcNoFESelected);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcInvalidBoundaryIndicator);
+}
/* ------------------------- inline functions -------------- */
+#ifndef DOXYGEN
+namespace DoFTools
+{
/**
* Operator computing the maximum coupling out of two.
*
* @relates DoFTools
*/
-inline
-DoFTools::Coupling operator |= (DoFTools::Coupling& c1,
- const DoFTools::Coupling c2)
-{
- if (c2 == DoFTools::always)
- c1 = DoFTools::always;
- else if (c1 != DoFTools::always && c2 == DoFTools::nonzero)
- return c1 = DoFTools::nonzero;
- return c1;
-}
+ inline
+ Coupling operator |= (Coupling& c1,
+ const Coupling c2)
+ {
+ if (c2 == Coupling::always)
+ c1 = Coupling::always;
+ else if (c1 != Coupling::always && c2 == Coupling::nonzero)
+ return c1 = Coupling::nonzero;
+ return c1;
+ }
/**
*
* @relates DoFTools
*/
-inline
-DoFTools::Coupling operator | (const DoFTools::Coupling c1,
- const DoFTools::Coupling c2)
-{
- if (c1 == DoFTools::always || c2 == DoFTools::always)
- return DoFTools::always;
- if (c1 == DoFTools::nonzero || c2 == DoFTools::nonzero)
- return DoFTools::nonzero;
- return DoFTools::none;
-}
+ inline
+ Coupling operator | (const Coupling c1,
+ const Coupling c2)
+ {
+ if (c1 == Coupling::always || c2 == Coupling::always)
+ return Coupling::always;
+ if (c1 == Coupling::nonzero || c2 == Coupling::nonzero)
+ return Coupling::nonzero;
+ return Coupling::none;
+ }
// ---------------------- inline and template functions --------------------
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::max_dofs_per_cell (const DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().dofs_per_cell;
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::max_dofs_per_face (const DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().dofs_per_face;
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::max_dofs_per_vertex (const DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().dofs_per_vertex;
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::n_components (const DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().n_components();
-}
-
-
-
-template <int dim, int spacedim>
-inline
-bool
-DoFTools::fe_is_primitive (const DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().is_primitive();
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::max_dofs_per_cell (const hp::DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().max_dofs_per_cell ();
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::max_dofs_per_face (const hp::DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().max_dofs_per_face ();
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::max_dofs_per_vertex (const hp::DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe().max_dofs_per_vertex ();
-}
-
-
-template <int dim, int spacedim>
-inline unsigned int
-DoFTools::n_components (const hp::DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe()[0].n_components();
-}
-
-
-template <int dim, int spacedim>
-inline
-bool
-DoFTools::fe_is_primitive (const hp::DoFHandler<dim,spacedim> &dh)
-{
- return dh.get_fe()[0].is_primitive();
-}
-
-
-template <class DH, class SparsityPattern>
-inline
-void
-DoFTools::make_sparsity_pattern (const DH &dof,
- const std::vector<std::vector<bool> > &mask,
- SparsityPattern &sparsity_pattern)
-{
- const unsigned int ncomp = dof.get_fe().n_components();
-
- Assert (mask.size() == ncomp,
- ExcDimensionMismatch(mask.size(), ncomp));
- for (unsigned int i=0; i<mask.size(); ++i)
- Assert (mask[i].size() == ncomp,
- ExcDimensionMismatch(mask[i].size(), ncomp));
- // Create a coupling table out of the mask
- Table<2,DoFTools::Coupling> couplings(ncomp, ncomp);
- for (unsigned int i=0;i<ncomp;++i)
- for (unsigned int j=0;j<ncomp;++j)
- if (mask[i][j])
- couplings(i,j) = always;
- else
- couplings(i,j) = none;
-
- // Call the new function
- make_sparsity_pattern(dof, couplings, sparsity_pattern);
-}
-
-
-template <class DH, class Comp>
-void
-DoFTools::map_support_points_to_dofs (
- const Mapping<DH::dimension,DH::space_dimension> &mapping,
- const DH &dof_handler,
- std::map<Point<DH::space_dimension>, unsigned int, Comp> &point_to_index_map)
-{
- // let the checking of arguments be
- // done by the function first
- // called
- std::vector<Point<DH::space_dimension> > support_points (dof_handler.n_dofs());
- map_dofs_to_support_points (mapping, dof_handler, support_points);
- // now copy over the results of the
- // previous function into the
- // output arg
- point_to_index_map.clear ();
- for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
- point_to_index_map[support_points[i]] = i;
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ max_dofs_per_cell (const DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().dofs_per_cell;
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ max_dofs_per_face (const DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().dofs_per_face;
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ max_dofs_per_vertex (const DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().dofs_per_vertex;
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ n_components (const DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().n_components();
+ }
+
+
+
+ template <int dim, int spacedim>
+ inline
+ bool
+ fe_is_primitive (const DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().is_primitive();
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ max_dofs_per_cell (const hp::DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().max_dofs_per_cell ();
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ max_dofs_per_face (const hp::DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().max_dofs_per_face ();
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ max_dofs_per_vertex (const hp::DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe().max_dofs_per_vertex ();
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ unsigned int
+ n_components (const hp::DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe()[0].n_components();
+ }
+
+
+ template <int dim, int spacedim>
+ inline
+ bool
+ fe_is_primitive (const hp::DoFHandler<dim,spacedim> &dh)
+ {
+ return dh.get_fe()[0].is_primitive();
+ }
+
+
+ template <class DH, class SparsityPattern>
+ inline
+ void
+ make_sparsity_pattern (const DH &dof,
+ const std::vector<std::vector<bool> > &mask,
+ SparsityPattern &sparsity_pattern)
+ {
+ const unsigned int ncomp = dof.get_fe().n_components();
+
+ Assert (mask.size() == ncomp,
+ ExcDimensionMismatch(mask.size(), ncomp));
+ for (unsigned int i=0; i<mask.size(); ++i)
+ Assert (mask[i].size() == ncomp,
+ ExcDimensionMismatch(mask[i].size(), ncomp));
+ // Create a coupling table out of the mask
+ Table<2,DoFTools::Coupling> couplings(ncomp, ncomp);
+ for (unsigned int i=0;i<ncomp;++i)
+ for (unsigned int j=0;j<ncomp;++j)
+ if (mask[i][j])
+ couplings(i,j) = always;
+ else
+ couplings(i,j) = none;
+
+ // Call the new function
+ make_sparsity_pattern(dof, couplings, sparsity_pattern);
+ }
+
+
+ template <class DH, class Comp>
+ void
+ map_support_points_to_dofs (
+ const Mapping<DH::dimension,DH::space_dimension> &mapping,
+ const DH &dof_handler,
+ std::map<Point<DH::space_dimension>, unsigned int, Comp> &point_to_index_map)
+ {
+ // let the checking of arguments be
+ // done by the function first
+ // called
+ std::vector<Point<DH::space_dimension> > support_points (dof_handler.n_dofs());
+ map_dofs_to_support_points (mapping, dof_handler, support_points);
+ // now copy over the results of the
+ // previous function into the
+ // output arg
+ point_to_index_map.clear ();
+ for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
+ point_to_index_map[support_points[i]] = i;
+ }
}
+#endif
DEAL_II_NAMESPACE_CLOSE
-template <class DH, class SparsityPattern>
-void
-DoFTools::make_sparsity_pattern (const DH &dof,
- SparsityPattern &sparsity,
- const ConstraintMatrix &constraints,
- const bool keep_constrained_dofs,
- const types::subdomain_id_t subdomain_id)
+namespace DoFTools
{
- const unsigned int n_dofs = dof.n_dofs();
-
- Assert (sparsity.n_rows() == n_dofs,
- ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
- Assert (sparsity.n_cols() == n_dofs,
- ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
-
- std::vector<unsigned int> dofs_on_this_cell;
- dofs_on_this_cell.reserve (max_dofs_per_cell(dof));
- typename DH::active_cell_iterator cell = dof.begin_active(),
- endc = dof.end();
-
- // In case we work with a distributed
- // sparsity pattern of Trilinos type, we
- // only have to do the work if the
- // current cell is owned by the calling
- // processor. Otherwise, just continue.
- for (; cell!=endc; ++cell)
- if (((subdomain_id == types::invalid_subdomain_id)
- ||
- (subdomain_id == cell->subdomain_id()))
- &&
- !cell->is_artificial()
- &&
- !cell->is_ghost())
- {
- const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
- dofs_on_this_cell.resize (dofs_per_cell);
- cell->get_dof_indices (dofs_on_this_cell);
-
- // make sparsity pattern for this
- // cell. if no constraints pattern was
- // given, then the following call acts
- // as if simply no constraints existed
- constraints.add_entries_local_to_global (dofs_on_this_cell,
- sparsity,
- keep_constrained_dofs);
- }
-}
+
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (const DH &dof,
+ SparsityPattern &sparsity,
+ const ConstraintMatrix &constraints,
+ const bool keep_constrained_dofs,
+ const types::subdomain_id_t subdomain_id)
+ {
+ const unsigned int n_dofs = dof.n_dofs();
+
+ Assert (sparsity.n_rows() == n_dofs,
+ ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
+ Assert (sparsity.n_cols() == n_dofs,
+ ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
+
+ std::vector<unsigned int> dofs_on_this_cell;
+ dofs_on_this_cell.reserve (max_dofs_per_cell(dof));
+ typename DH::active_cell_iterator cell = dof.begin_active(),
+ endc = dof.end();
+
+ // In case we work with a distributed
+ // sparsity pattern of Trilinos type, we
+ // only have to do the work if the
+ // current cell is owned by the calling
+ // processor. Otherwise, just continue.
+ for (; cell!=endc; ++cell)
+ if (((subdomain_id == types::invalid_subdomain_id)
+ ||
+ (subdomain_id == cell->subdomain_id()))
+ &&
+ !cell->is_artificial()
+ &&
+ !cell->is_ghost())
+ {
+ const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
+ dofs_on_this_cell.resize (dofs_per_cell);
+ cell->get_dof_indices (dofs_on_this_cell);
+ // make sparsity pattern for this
+ // cell. if no constraints pattern was
+ // given, then the following call acts
+ // as if simply no constraints existed
+ constraints.add_entries_local_to_global (dofs_on_this_cell,
+ sparsity,
+ keep_constrained_dofs);
+ }
+ }
-template <class DH, class SparsityPattern>
-void
-DoFTools::make_sparsity_pattern (const DH &dof,
- const Table<2,Coupling> &couplings,
- SparsityPattern &sparsity,
- const ConstraintMatrix &constraints,
- const bool keep_constrained_dofs,
- const types::subdomain_id_t subdomain_id)
-{
- const unsigned int n_dofs = dof.n_dofs();
-
- Assert (sparsity.n_rows() == n_dofs,
- ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
- Assert (sparsity.n_cols() == n_dofs,
- ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
- Assert (couplings.n_rows() == dof.get_fe().n_components(),
- ExcDimensionMismatch(couplings.n_rows(), dof.get_fe().n_components()));
- Assert (couplings.n_cols() == dof.get_fe().n_components(),
- ExcDimensionMismatch(couplings.n_cols(), dof.get_fe().n_components()));
-
- const hp::FECollection<DH::dimension,DH::space_dimension> fe_collection (dof.get_fe());
-
- // first, for each finite element, build a
- // mask for each dof, not like the one
- // given which represents components. make
- // sure we do the right thing also with
- // respect to non-primitive shape
- // functions, which takes some additional
- // thought
- std::vector<Table<2,bool> > dof_mask(fe_collection.size());
-
- // check whether the table of couplings
- // contains only true arguments, i.e., we
- // do not exclude any index. that is the
- // easy case, since we don't have to set
- // up the tables
- bool need_dof_mask = false;
- for (unsigned int i=0; i<couplings.n_rows(); ++i)
- for (unsigned int j=0; j<couplings.n_cols(); ++j)
- if (couplings(i,j) == none)
- need_dof_mask = true;
-
- if (need_dof_mask == true)
- for (unsigned int f=0; f<fe_collection.size(); ++f)
- {
- const unsigned int dofs_per_cell = fe_collection[f].dofs_per_cell;
- dof_mask[f].reinit (dofs_per_cell, dofs_per_cell);
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (const DH &dof,
+ const Table<2,Coupling> &couplings,
+ SparsityPattern &sparsity,
+ const ConstraintMatrix &constraints,
+ const bool keep_constrained_dofs,
+ const types::subdomain_id_t subdomain_id)
+ {
+ const unsigned int n_dofs = dof.n_dofs();
+
+ Assert (sparsity.n_rows() == n_dofs,
+ ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
+ Assert (sparsity.n_cols() == n_dofs,
+ ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
+ Assert (couplings.n_rows() == dof.get_fe().n_components(),
+ ExcDimensionMismatch(couplings.n_rows(), dof.get_fe().n_components()));
+ Assert (couplings.n_cols() == dof.get_fe().n_components(),
+ ExcDimensionMismatch(couplings.n_cols(), dof.get_fe().n_components()));
+
+ const hp::FECollection<DH::dimension,DH::space_dimension> fe_collection (dof.get_fe());
+
+ // first, for each finite element, build a
+ // mask for each dof, not like the one
+ // given which represents components. make
+ // sure we do the right thing also with
+ // respect to non-primitive shape
+ // functions, which takes some additional
+ // thought
+ std::vector<Table<2,bool> > dof_mask(fe_collection.size());
+
+ // check whether the table of couplings
+ // contains only true arguments, i.e., we
+ // do not exclude any index. that is the
+ // easy case, since we don't have to set
+ // up the tables
+ bool need_dof_mask = false;
+ for (unsigned int i=0; i<couplings.n_rows(); ++i)
+ for (unsigned int j=0; j<couplings.n_cols(); ++j)
+ if (couplings(i,j) == none)
+ need_dof_mask = true;
+
+ if (need_dof_mask == true)
+ for (unsigned int f=0; f<fe_collection.size(); ++f)
+ {
+ const unsigned int dofs_per_cell = fe_collection[f].dofs_per_cell;
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- for (unsigned int j=0; j<dofs_per_cell; ++j)
- if (fe_collection[f].is_primitive(i) &&
- fe_collection[f].is_primitive(j))
- dof_mask[f](i,j)
- = (couplings(fe_collection[f].system_to_component_index(i).first,
- fe_collection[f].system_to_component_index(j).first) != none);
- else
- {
- const unsigned int first_nonzero_comp_i
- = (std::find (fe_collection[f].get_nonzero_components(i).begin(),
- fe_collection[f].get_nonzero_components(i).end(),
- true)
- -
- fe_collection[f].get_nonzero_components(i).begin());
- const unsigned int first_nonzero_comp_j
- = (std::find (fe_collection[f].get_nonzero_components(j).begin(),
- fe_collection[f].get_nonzero_components(j).end(),
- true)
- -
- fe_collection[f].get_nonzero_components(j).begin());
- Assert (first_nonzero_comp_i < fe_collection[f].n_components(),
- ExcInternalError());
- Assert (first_nonzero_comp_j < fe_collection[f].n_components(),
- ExcInternalError());
+ dof_mask[f].reinit (dofs_per_cell, dofs_per_cell);
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ for (unsigned int j=0; j<dofs_per_cell; ++j)
+ if (fe_collection[f].is_primitive(i) &&
+ fe_collection[f].is_primitive(j))
dof_mask[f](i,j)
- = (couplings(first_nonzero_comp_i,first_nonzero_comp_j) != none);
- }
- }
+ = (couplings(fe_collection[f].system_to_component_index(i).first,
+ fe_collection[f].system_to_component_index(j).first) != none);
+ else
+ {
+ const unsigned int first_nonzero_comp_i
+ = (std::find (fe_collection[f].get_nonzero_components(i).begin(),
+ fe_collection[f].get_nonzero_components(i).end(),
+ true)
+ -
+ fe_collection[f].get_nonzero_components(i).begin());
+ const unsigned int first_nonzero_comp_j
+ = (std::find (fe_collection[f].get_nonzero_components(j).begin(),
+ fe_collection[f].get_nonzero_components(j).end(),
+ true)
+ -
+ fe_collection[f].get_nonzero_components(j).begin());
+ Assert (first_nonzero_comp_i < fe_collection[f].n_components(),
+ ExcInternalError());
+ Assert (first_nonzero_comp_j < fe_collection[f].n_components(),
+ ExcInternalError());
+ dof_mask[f](i,j)
+ = (couplings(first_nonzero_comp_i,first_nonzero_comp_j) != none);
+ }
+ }
- std::vector<unsigned int> dofs_on_this_cell(fe_collection.max_dofs_per_cell());
- typename DH::active_cell_iterator cell = dof.begin_active(),
- endc = dof.end();
-
- // In case we work with a distributed
- // sparsity pattern of Trilinos type, we
- // only have to do the work if the
- // current cell is owned by the calling
- // processor. Otherwise, just continue.
- for (; cell!=endc; ++cell)
- if (((subdomain_id == types::invalid_subdomain_id)
- ||
- (subdomain_id == cell->subdomain_id()))
- &&
- !cell->is_artificial()
- &&
- !cell->is_ghost())
- {
- const unsigned int fe_index = cell->active_fe_index();
- const unsigned int dofs_per_cell =fe_collection[fe_index].dofs_per_cell;
- dofs_on_this_cell.resize (dofs_per_cell);
- cell->get_dof_indices (dofs_on_this_cell);
+ std::vector<unsigned int> dofs_on_this_cell(fe_collection.max_dofs_per_cell());
+ typename DH::active_cell_iterator cell = dof.begin_active(),
+ endc = dof.end();
+
+ // In case we work with a distributed
+ // sparsity pattern of Trilinos type, we
+ // only have to do the work if the
+ // current cell is owned by the calling
+ // processor. Otherwise, just continue.
+ for (; cell!=endc; ++cell)
+ if (((subdomain_id == types::invalid_subdomain_id)
+ ||
+ (subdomain_id == cell->subdomain_id()))
+ &&
+ !cell->is_artificial()
+ &&
+ !cell->is_ghost())
+ {
+ const unsigned int fe_index = cell->active_fe_index();
+ const unsigned int dofs_per_cell =fe_collection[fe_index].dofs_per_cell;
+ dofs_on_this_cell.resize (dofs_per_cell);
+ cell->get_dof_indices (dofs_on_this_cell);
- // make sparsity pattern for this
- // cell. if no constraints pattern was
- // given, then the following call acts
- // as if simply no constraints existed
- constraints.add_entries_local_to_global (dofs_on_this_cell,
- sparsity,
- keep_constrained_dofs,
- dof_mask[fe_index]);
- }
-}
+ // make sparsity pattern for this
+ // cell. if no constraints pattern was
+ // given, then the following call acts
+ // as if simply no constraints existed
+ constraints.add_entries_local_to_global (dofs_on_this_cell,
+ sparsity,
+ keep_constrained_dofs,
+ dof_mask[fe_index]);
+ }
+ }
-template <class DH, class SparsityPattern>
-void
-DoFTools::make_sparsity_pattern (
- const DH &dof_row,
- const DH &dof_col,
- SparsityPattern &sparsity)
-{
- const unsigned int n_dofs_row = dof_row.n_dofs();
- const unsigned int n_dofs_col = dof_col.n_dofs();
- Assert (sparsity.n_rows() == n_dofs_row,
- ExcDimensionMismatch (sparsity.n_rows(), n_dofs_row));
- Assert (sparsity.n_cols() == n_dofs_col,
- ExcDimensionMismatch (sparsity.n_cols(), n_dofs_col));
+ template <class DH, class SparsityPattern>
+ void
+ make_sparsity_pattern (
+ const DH &dof_row,
+ const DH &dof_col,
+ SparsityPattern &sparsity)
+ {
+ const unsigned int n_dofs_row = dof_row.n_dofs();
+ const unsigned int n_dofs_col = dof_col.n_dofs();
+ Assert (sparsity.n_rows() == n_dofs_row,
+ ExcDimensionMismatch (sparsity.n_rows(), n_dofs_row));
+ Assert (sparsity.n_cols() == n_dofs_col,
+ ExcDimensionMismatch (sparsity.n_cols(), n_dofs_col));
- const std::list<std::pair<typename DH::cell_iterator,
- typename DH::cell_iterator> >
- cell_list
- = GridTools::get_finest_common_cells (dof_row, dof_col);
+ const std::list<std::pair<typename DH::cell_iterator,
+ typename DH::cell_iterator> >
+ cell_list
+ = GridTools::get_finest_common_cells (dof_row, dof_col);
- typename std::list<std::pair<typename DH::cell_iterator,
- typename DH::cell_iterator> >
- ::const_iterator
- cell_iter = cell_list.begin();
- for (; cell_iter!=cell_list.end(); ++cell_iter)
- {
- const typename DH::cell_iterator cell_row = cell_iter->first;
- const typename DH::cell_iterator cell_col = cell_iter->second;
-
- if (!cell_row->has_children() && !cell_col->has_children())
- {
- const unsigned int dofs_per_cell_row =
- cell_row->get_fe().dofs_per_cell;
- const unsigned int dofs_per_cell_col =
- cell_col->get_fe().dofs_per_cell;
- std::vector<unsigned int>
- local_dof_indices_row(dofs_per_cell_row);
- std::vector<unsigned int>
- local_dof_indices_col(dofs_per_cell_col);
- cell_row->get_dof_indices (local_dof_indices_row);
- cell_col->get_dof_indices (local_dof_indices_col);
- for (unsigned int i=0; i<dofs_per_cell_row; ++i)
- sparsity.add_entries (local_dof_indices_row[i],
- local_dof_indices_col.begin(),
- local_dof_indices_col.end());
- }
- else if (cell_row->has_children())
- {
- const std::vector<typename DH::active_cell_iterator >
- child_cells = GridTools::get_active_child_cells<DH> (cell_row);
- for (unsigned int i=0; i<child_cells.size(); i++)
- {
- const typename DH::active_cell_iterator
- cell_row_child = child_cells[i];
- const unsigned int dofs_per_cell_row =
- cell_row_child->get_fe().dofs_per_cell;
- const unsigned int dofs_per_cell_col =
- cell_col->get_fe().dofs_per_cell;
- std::vector<unsigned int>
- local_dof_indices_row(dofs_per_cell_row);
- std::vector<unsigned int>
- local_dof_indices_col(dofs_per_cell_col);
- cell_row_child->get_dof_indices (local_dof_indices_row);
- cell_col->get_dof_indices (local_dof_indices_col);
- for (unsigned int i=0; i<dofs_per_cell_row; ++i)
- sparsity.add_entries (local_dof_indices_row[i],
- local_dof_indices_col.begin(),
- local_dof_indices_col.end());
- }
- }
- else
- {
- std::vector<typename DH::active_cell_iterator>
- child_cells = GridTools::get_active_child_cells<DH> (cell_col);
- for (unsigned int i=0; i<child_cells.size(); i++)
- {
- const typename DH::active_cell_iterator
- cell_col_child = child_cells[i];
- const unsigned int dofs_per_cell_row =
- cell_row->get_fe().dofs_per_cell;
- const unsigned int dofs_per_cell_col =
- cell_col_child->get_fe().dofs_per_cell;
- std::vector<unsigned int>
- local_dof_indices_row(dofs_per_cell_row);
- std::vector<unsigned int>
- local_dof_indices_col(dofs_per_cell_col);
- cell_row->get_dof_indices (local_dof_indices_row);
- cell_col_child->get_dof_indices (local_dof_indices_col);
- for (unsigned int i=0; i<dofs_per_cell_row; ++i)
- sparsity.add_entries (local_dof_indices_row[i],
- local_dof_indices_col.begin(),
- local_dof_indices_col.end());
- }
- }
- }
-}
+ typename std::list<std::pair<typename DH::cell_iterator,
+ typename DH::cell_iterator> >
+ ::const_iterator
+ cell_iter = cell_list.begin();
+ for (; cell_iter!=cell_list.end(); ++cell_iter)
+ {
+ const typename DH::cell_iterator cell_row = cell_iter->first;
+ const typename DH::cell_iterator cell_col = cell_iter->second;
+ if (!cell_row->has_children() && !cell_col->has_children())
+ {
+ const unsigned int dofs_per_cell_row =
+ cell_row->get_fe().dofs_per_cell;
+ const unsigned int dofs_per_cell_col =
+ cell_col->get_fe().dofs_per_cell;
+ std::vector<unsigned int>
+ local_dof_indices_row(dofs_per_cell_row);
+ std::vector<unsigned int>
+ local_dof_indices_col(dofs_per_cell_col);
+ cell_row->get_dof_indices (local_dof_indices_row);
+ cell_col->get_dof_indices (local_dof_indices_col);
+ for (unsigned int i=0; i<dofs_per_cell_row; ++i)
+ sparsity.add_entries (local_dof_indices_row[i],
+ local_dof_indices_col.begin(),
+ local_dof_indices_col.end());
+ }
+ else if (cell_row->has_children())
+ {
+ const std::vector<typename DH::active_cell_iterator >
+ child_cells = GridTools::get_active_child_cells<DH> (cell_row);
+ for (unsigned int i=0; i<child_cells.size(); i++)
+ {
+ const typename DH::active_cell_iterator
+ cell_row_child = child_cells[i];
+ const unsigned int dofs_per_cell_row =
+ cell_row_child->get_fe().dofs_per_cell;
+ const unsigned int dofs_per_cell_col =
+ cell_col->get_fe().dofs_per_cell;
+ std::vector<unsigned int>
+ local_dof_indices_row(dofs_per_cell_row);
+ std::vector<unsigned int>
+ local_dof_indices_col(dofs_per_cell_col);
+ cell_row_child->get_dof_indices (local_dof_indices_row);
+ cell_col->get_dof_indices (local_dof_indices_col);
+ for (unsigned int i=0; i<dofs_per_cell_row; ++i)
+ sparsity.add_entries (local_dof_indices_row[i],
+ local_dof_indices_col.begin(),
+ local_dof_indices_col.end());
+ }
+ }
+ else
+ {
+ std::vector<typename DH::active_cell_iterator>
+ child_cells = GridTools::get_active_child_cells<DH> (cell_col);
+ for (unsigned int i=0; i<child_cells.size(); i++)
+ {
+ const typename DH::active_cell_iterator
+ cell_col_child = child_cells[i];
+ const unsigned int dofs_per_cell_row =
+ cell_row->get_fe().dofs_per_cell;
+ const unsigned int dofs_per_cell_col =
+ cell_col_child->get_fe().dofs_per_cell;
+ std::vector<unsigned int>
+ local_dof_indices_row(dofs_per_cell_row);
+ std::vector<unsigned int>
+ local_dof_indices_col(dofs_per_cell_col);
+ cell_row->get_dof_indices (local_dof_indices_row);
+ cell_col_child->get_dof_indices (local_dof_indices_col);
+ for (unsigned int i=0; i<dofs_per_cell_row; ++i)
+ sparsity.add_entries (local_dof_indices_row[i],
+ local_dof_indices_col.begin(),
+ local_dof_indices_col.end());
+ }
+ }
+ }
+ }
-template <class DH, class SparsityPattern>
-void
-DoFTools::make_boundary_sparsity_pattern (
- const DH &dof,
- const std::vector<unsigned int> &dof_to_boundary_mapping,
- SparsityPattern &sparsity)
-{
- if (DH::dimension == 1)
- {
- // there are only 2 boundary
- // indicators in 1d, so it is no
- // performance problem to call the
- // other function
- typename DH::FunctionMap boundary_indicators;
- boundary_indicators[0] = 0;
- boundary_indicators[1] = 0;
- make_boundary_sparsity_pattern<DH, SparsityPattern> (dof,
- boundary_indicators,
- dof_to_boundary_mapping,
- sparsity);
- return;
- }
- const unsigned int n_dofs = dof.n_dofs();
- AssertDimension (dof_to_boundary_mapping.size(), n_dofs);
- AssertDimension (sparsity.n_rows(), dof.n_boundary_dofs());
- AssertDimension (sparsity.n_cols(), dof.n_boundary_dofs());
+ template <class DH, class SparsityPattern>
+ void
+ make_boundary_sparsity_pattern (
+ const DH &dof,
+ const std::vector<unsigned int> &dof_to_boundary_mapping,
+ SparsityPattern &sparsity)
+ {
+ if (DH::dimension == 1)
+ {
+ // there are only 2 boundary
+ // indicators in 1d, so it is no
+ // performance problem to call the
+ // other function
+ typename DH::FunctionMap boundary_indicators;
+ boundary_indicators[0] = 0;
+ boundary_indicators[1] = 0;
+ make_boundary_sparsity_pattern<DH, SparsityPattern> (dof,
+ boundary_indicators,
+ dof_to_boundary_mapping,
+ sparsity);
+ return;
+ }
+
+ const unsigned int n_dofs = dof.n_dofs();
+
+ AssertDimension (dof_to_boundary_mapping.size(), n_dofs);
+ AssertDimension (sparsity.n_rows(), dof.n_boundary_dofs());
+ AssertDimension (sparsity.n_cols(), dof.n_boundary_dofs());
#ifdef DEBUG
- if (sparsity.n_rows() != 0)
- {
- unsigned int max_element = 0;
- for (std::vector<unsigned int>::const_iterator i=dof_to_boundary_mapping.begin();
- i!=dof_to_boundary_mapping.end(); ++i)
- if ((*i != DH::invalid_dof_index) &&
- (*i > max_element))
- max_element = *i;
- AssertDimension (max_element, sparsity.n_rows()-1);
- };
+ if (sparsity.n_rows() != 0)
+ {
+ unsigned int max_element = 0;
+ for (std::vector<unsigned int>::const_iterator i=dof_to_boundary_mapping.begin();
+ i!=dof_to_boundary_mapping.end(); ++i)
+ if ((*i != DH::invalid_dof_index) &&
+ (*i > max_element))
+ max_element = *i;
+ AssertDimension (max_element, sparsity.n_rows()-1);
+ };
#endif
- std::vector<unsigned int> dofs_on_this_face;
- dofs_on_this_face.reserve (max_dofs_per_face(dof));
-
- // loop over all faces to check
- // whether they are at a
- // boundary. note that we need not
- // take special care of single
- // lines (using
- // @p{cell->has_boundary_lines}),
- // since we do not support
- // boundaries of dimension dim-2,
- // and so every boundary line is
- // also part of a boundary face.
- typename DH::active_cell_iterator cell = dof.begin_active(),
- endc = dof.end();
- for (; cell!=endc; ++cell)
- for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
- if (cell->at_boundary(f))
- {
- const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
- dofs_on_this_face.resize (dofs_per_face);
- cell->face(f)->get_dof_indices (dofs_on_this_face,
- cell->active_fe_index());
-
- // make sparsity pattern for this cell
- for (unsigned int i=0; i<dofs_per_face; ++i)
- for (unsigned int j=0; j<dofs_per_face; ++j)
- sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
- dof_to_boundary_mapping[dofs_on_this_face[j]]);
- }
-}
+ std::vector<unsigned int> dofs_on_this_face;
+ dofs_on_this_face.reserve (max_dofs_per_face(dof));
+
+ // loop over all faces to check
+ // whether they are at a
+ // boundary. note that we need not
+ // take special care of single
+ // lines (using
+ // @p{cell->has_boundary_lines}),
+ // since we do not support
+ // boundaries of dimension dim-2,
+ // and so every boundary line is
+ // also part of a boundary face.
+ typename DH::active_cell_iterator cell = dof.begin_active(),
+ endc = dof.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
+ if (cell->at_boundary(f))
+ {
+ const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
+ dofs_on_this_face.resize (dofs_per_face);
+ cell->face(f)->get_dof_indices (dofs_on_this_face,
+ cell->active_fe_index());
+
+ // make sparsity pattern for this cell
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ for (unsigned int j=0; j<dofs_per_face; ++j)
+ sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
+ dof_to_boundary_mapping[dofs_on_this_face[j]]);
+ }
+ }
-template <class DH, class SparsityPattern>
-void DoFTools::make_boundary_sparsity_pattern (
- const DH &dof,
- const typename FunctionMap<DH::space_dimension>::type &boundary_indicators,
- const std::vector<unsigned int> &dof_to_boundary_mapping,
- SparsityPattern &sparsity)
-{
- if (DH::dimension == 1)
- {
- // first check left, then right
- // boundary point
- for (unsigned int direction=0; direction<2; ++direction)
- {
- // if this boundary is not
- // requested, then go on with next one
- if (boundary_indicators.find(direction) ==
- boundary_indicators.end())
- continue;
-
- // find active cell at that
- // boundary: first go to
- // left/right, then to children
- typename DH::cell_iterator cell = dof.begin(0);
- while (!cell->at_boundary(direction))
- cell = cell->neighbor(direction);
- while (!cell->active())
- cell = cell->child(direction);
-
- const unsigned int dofs_per_vertex = cell->get_fe().dofs_per_vertex;
- std::vector<unsigned int> boundary_dof_boundary_indices (dofs_per_vertex);
-
- // next get boundary mapped dof
- // indices of boundary dofs
- for (unsigned int i=0; i<dofs_per_vertex; ++i)
- boundary_dof_boundary_indices[i]
- = dof_to_boundary_mapping[cell->vertex_dof_index(direction,i)];
-
- for (unsigned int i=0; i<dofs_per_vertex; ++i)
- sparsity.add_entries (boundary_dof_boundary_indices[i],
- boundary_dof_boundary_indices.begin(),
- boundary_dof_boundary_indices.end());
- };
- return;
- }
+ template <class DH, class SparsityPattern>
+ void make_boundary_sparsity_pattern (
+ const DH &dof,
+ const typename FunctionMap<DH::space_dimension>::type &boundary_indicators,
+ const std::vector<unsigned int> &dof_to_boundary_mapping,
+ SparsityPattern &sparsity)
+ {
+ if (DH::dimension == 1)
+ {
+ // first check left, then right
+ // boundary point
+ for (unsigned int direction=0; direction<2; ++direction)
+ {
+ // if this boundary is not
+ // requested, then go on with next one
+ if (boundary_indicators.find(direction) ==
+ boundary_indicators.end())
+ continue;
+
+ // find active cell at that
+ // boundary: first go to
+ // left/right, then to children
+ typename DH::cell_iterator cell = dof.begin(0);
+ while (!cell->at_boundary(direction))
+ cell = cell->neighbor(direction);
+ while (!cell->active())
+ cell = cell->child(direction);
+
+ const unsigned int dofs_per_vertex = cell->get_fe().dofs_per_vertex;
+ std::vector<unsigned int> boundary_dof_boundary_indices (dofs_per_vertex);
+
+ // next get boundary mapped dof
+ // indices of boundary dofs
+ for (unsigned int i=0; i<dofs_per_vertex; ++i)
+ boundary_dof_boundary_indices[i]
+ = dof_to_boundary_mapping[cell->vertex_dof_index(direction,i)];
+
+ for (unsigned int i=0; i<dofs_per_vertex; ++i)
+ sparsity.add_entries (boundary_dof_boundary_indices[i],
+ boundary_dof_boundary_indices.begin(),
+ boundary_dof_boundary_indices.end());
+ };
+ return;
+ }
- const unsigned int n_dofs = dof.n_dofs();
+ const unsigned int n_dofs = dof.n_dofs();
- AssertDimension (dof_to_boundary_mapping.size(), n_dofs);
- Assert (boundary_indicators.find(255) == boundary_indicators.end(),
- typename DH::ExcInvalidBoundaryIndicator());
- Assert (sparsity.n_rows() == dof.n_boundary_dofs (boundary_indicators),
- ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs (boundary_indicators)));
- Assert (sparsity.n_cols() == dof.n_boundary_dofs (boundary_indicators),
- ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs (boundary_indicators)));
+ AssertDimension (dof_to_boundary_mapping.size(), n_dofs);
+ Assert (boundary_indicators.find(255) == boundary_indicators.end(),
+ typename DH::ExcInvalidBoundaryIndicator());
+ Assert (sparsity.n_rows() == dof.n_boundary_dofs (boundary_indicators),
+ ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs (boundary_indicators)));
+ Assert (sparsity.n_cols() == dof.n_boundary_dofs (boundary_indicators),
+ ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs (boundary_indicators)));
#ifdef DEBUG
- if (sparsity.n_rows() != 0)
- {
- unsigned int max_element = 0;
- for (std::vector<unsigned int>::const_iterator i=dof_to_boundary_mapping.begin();
- i!=dof_to_boundary_mapping.end(); ++i)
- if ((*i != DH::invalid_dof_index) &&
- (*i > max_element))
- max_element = *i;
- AssertDimension (max_element, sparsity.n_rows()-1);
- };
+ if (sparsity.n_rows() != 0)
+ {
+ unsigned int max_element = 0;
+ for (std::vector<unsigned int>::const_iterator i=dof_to_boundary_mapping.begin();
+ i!=dof_to_boundary_mapping.end(); ++i)
+ if ((*i != DH::invalid_dof_index) &&
+ (*i > max_element))
+ max_element = *i;
+ AssertDimension (max_element, sparsity.n_rows()-1);
+ };
#endif
- std::vector<unsigned int> dofs_on_this_face;
- dofs_on_this_face.reserve (max_dofs_per_face(dof));
- typename DH::active_cell_iterator cell = dof.begin_active(),
- endc = dof.end();
- for (; cell!=endc; ++cell)
- for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
- if (boundary_indicators.find(cell->face(f)->boundary_indicator()) !=
- boundary_indicators.end())
- {
- const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
- dofs_on_this_face.resize (dofs_per_face);
- cell->face(f)->get_dof_indices (dofs_on_this_face,
- cell->active_fe_index());
-
- // make sparsity pattern for this cell
- for (unsigned int i=0; i<dofs_per_face; ++i)
- for (unsigned int j=0; j<dofs_per_face; ++j)
- sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
- dof_to_boundary_mapping[dofs_on_this_face[j]]);
- }
-}
+ std::vector<unsigned int> dofs_on_this_face;
+ dofs_on_this_face.reserve (max_dofs_per_face(dof));
+ typename DH::active_cell_iterator cell = dof.begin_active(),
+ endc = dof.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
+ if (boundary_indicators.find(cell->face(f)->boundary_indicator()) !=
+ boundary_indicators.end())
+ {
+ const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
+ dofs_on_this_face.resize (dofs_per_face);
+ cell->face(f)->get_dof_indices (dofs_on_this_face,
+ cell->active_fe_index());
+
+ // make sparsity pattern for this cell
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ for (unsigned int j=0; j<dofs_per_face; ++j)
+ sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
+ dof_to_boundary_mapping[dofs_on_this_face[j]]);
+ }
+ }
-template <class DH, class SparsityPattern>
-void
-DoFTools::make_flux_sparsity_pattern (const DH &dof,
- SparsityPattern &sparsity,
- const ConstraintMatrix &constraints,
- const bool keep_constrained_dofs,
- const types::subdomain_id_t subdomain_id)
-{
- const unsigned int n_dofs = dof.n_dofs();
-
- AssertDimension (sparsity.n_rows(), n_dofs);
- AssertDimension (sparsity.n_cols(), n_dofs);
-
- std::vector<unsigned int> dofs_on_this_cell;
- std::vector<unsigned int> dofs_on_other_cell;
- dofs_on_this_cell.reserve (max_dofs_per_cell(dof));
- dofs_on_other_cell.reserve (max_dofs_per_cell(dof));
- typename DH::active_cell_iterator cell = dof.begin_active(),
- endc = dof.end();
-
- // TODO: in an old implementation, we used
- // user flags before to tag faces that were
- // already touched. this way, we could reduce
- // the work a little bit. now, we instead add
- // only data from one side. this should be OK,
- // but we need to actually verify it.
-
- // In case we work with a distributed
- // sparsity pattern of Trilinos type, we
- // only have to do the work if the
- // current cell is owned by the calling
- // processor. Otherwise, just continue.
- for (; cell!=endc; ++cell)
- if ((subdomain_id == types::invalid_subdomain_id)
- ||
- (subdomain_id == cell->subdomain_id()))
- {
- const unsigned int n_dofs_on_this_cell = cell->get_fe().dofs_per_cell;
- dofs_on_this_cell.resize (n_dofs_on_this_cell);
- cell->get_dof_indices (dofs_on_this_cell);
-
- // make sparsity pattern for this
- // cell. if no constraints pattern was
- // given, then the following call acts
- // as if simply no constraints existed
- constraints.add_entries_local_to_global (dofs_on_this_cell,
- sparsity,
- keep_constrained_dofs);
-
- for (unsigned int face = 0;
- face < GeometryInfo<DH::dimension>::faces_per_cell;
- ++face)
+ template <class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const DH &dof,
+ SparsityPattern &sparsity,
+ const ConstraintMatrix &constraints,
+ const bool keep_constrained_dofs,
+ const types::subdomain_id_t subdomain_id)
+ {
+ const unsigned int n_dofs = dof.n_dofs();
+
+ AssertDimension (sparsity.n_rows(), n_dofs);
+ AssertDimension (sparsity.n_cols(), n_dofs);
+
+ std::vector<unsigned int> dofs_on_this_cell;
+ std::vector<unsigned int> dofs_on_other_cell;
+ dofs_on_this_cell.reserve (max_dofs_per_cell(dof));
+ dofs_on_other_cell.reserve (max_dofs_per_cell(dof));
+ typename DH::active_cell_iterator cell = dof.begin_active(),
+ endc = dof.end();
+
+ // TODO: in an old implementation, we used
+ // user flags before to tag faces that were
+ // already touched. this way, we could reduce
+ // the work a little bit. now, we instead add
+ // only data from one side. this should be OK,
+ // but we need to actually verify it.
+
+ // In case we work with a distributed
+ // sparsity pattern of Trilinos type, we
+ // only have to do the work if the
+ // current cell is owned by the calling
+ // processor. Otherwise, just continue.
+ for (; cell!=endc; ++cell)
+ if ((subdomain_id == types::invalid_subdomain_id)
+ ||
+ (subdomain_id == cell->subdomain_id()))
{
- typename DH::face_iterator cell_face = cell->face(face);
- if (! cell->at_boundary(face) )
- {
- typename DH::cell_iterator neighbor = cell->neighbor(face);
+ const unsigned int n_dofs_on_this_cell = cell->get_fe().dofs_per_cell;
+ dofs_on_this_cell.resize (n_dofs_on_this_cell);
+ cell->get_dof_indices (dofs_on_this_cell);
- if (cell_face->has_children())
+ // make sparsity pattern for this
+ // cell. if no constraints pattern was
+ // given, then the following call acts
+ // as if simply no constraints existed
+ constraints.add_entries_local_to_global (dofs_on_this_cell,
+ sparsity,
+ keep_constrained_dofs);
+
+ for (unsigned int face = 0;
+ face < GeometryInfo<DH::dimension>::faces_per_cell;
+ ++face)
+ {
+ typename DH::face_iterator cell_face = cell->face(face);
+ if (! cell->at_boundary(face) )
{
- for (unsigned int sub_nr = 0;
- sub_nr != cell_face->number_of_children();
- ++sub_nr)
+ typename DH::cell_iterator neighbor = cell->neighbor(face);
+
+ if (cell_face->has_children())
+ {
+ for (unsigned int sub_nr = 0;
+ sub_nr != cell_face->number_of_children();
+ ++sub_nr)
+ {
+ const typename DH::cell_iterator
+ sub_neighbor
+ = cell->neighbor_child_on_subface (face, sub_nr);
+
+ const unsigned int n_dofs_on_neighbor
+ = sub_neighbor->get_fe().dofs_per_cell;
+ dofs_on_other_cell.resize (n_dofs_on_neighbor);
+ sub_neighbor->get_dof_indices (dofs_on_other_cell);
+
+ constraints.add_entries_local_to_global
+ (dofs_on_this_cell, dofs_on_other_cell,
+ sparsity, keep_constrained_dofs);
+ constraints.add_entries_local_to_global
+ (dofs_on_other_cell, dofs_on_this_cell,
+ sparsity, keep_constrained_dofs);
+ }
+ }
+ else
{
- const typename DH::cell_iterator
- sub_neighbor
- = cell->neighbor_child_on_subface (face, sub_nr);
+ // Refinement edges are taken care of
+ // by coarser cells
+
+ // TODO: in the distributed case, we miss out
+ // the constraints when the neighbor cell is
+ // coarser, but only the current cell is owned
+ // locally!
+ if (cell->neighbor_is_coarser(face))
+ continue;
const unsigned int n_dofs_on_neighbor
- = sub_neighbor->get_fe().dofs_per_cell;
+ = neighbor->get_fe().dofs_per_cell;
dofs_on_other_cell.resize (n_dofs_on_neighbor);
- sub_neighbor->get_dof_indices (dofs_on_other_cell);
+
+ neighbor->get_dof_indices (dofs_on_other_cell);
constraints.add_entries_local_to_global
(dofs_on_this_cell, dofs_on_other_cell,
sparsity, keep_constrained_dofs);
- constraints.add_entries_local_to_global
- (dofs_on_other_cell, dofs_on_this_cell,
- sparsity, keep_constrained_dofs);
+
+ // only need to add these in case the neighbor
+ // cell is not locally owned - otherwise, we
+ // touch each face twice and hence put the
+ // indices the other way around
+ if (cell->neighbor(face)->subdomain_id() !=
+ cell->subdomain_id())
+ constraints.add_entries_local_to_global
+ (dofs_on_other_cell, dofs_on_this_cell,
+ sparsity, keep_constrained_dofs);
}
}
- else
- {
- // Refinement edges are taken care of
- // by coarser cells
-
- // TODO: in the distributed case, we miss out
- // the constraints when the neighbor cell is
- // coarser, but only the current cell is owned
- // locally!
- if (cell->neighbor_is_coarser(face))
- continue;
-
- const unsigned int n_dofs_on_neighbor
- = neighbor->get_fe().dofs_per_cell;
- dofs_on_other_cell.resize (n_dofs_on_neighbor);
-
- neighbor->get_dof_indices (dofs_on_other_cell);
-
- constraints.add_entries_local_to_global
- (dofs_on_this_cell, dofs_on_other_cell,
- sparsity, keep_constrained_dofs);
-
- // only need to add these in case the neighbor
- // cell is not locally owned - otherwise, we
- // touch each face twice and hence put the
- // indices the other way around
- if (cell->neighbor(face)->subdomain_id() !=
- cell->subdomain_id())
- constraints.add_entries_local_to_global
- (dofs_on_other_cell, dofs_on_this_cell,
- sparsity, keep_constrained_dofs);
- }
}
}
- }
-}
+ }
-template <class DH, class SparsityPattern>
-void
-DoFTools::make_flux_sparsity_pattern (
- const DH &dof,
- SparsityPattern &sparsity)
-{
- ConstraintMatrix constraints;
- make_flux_sparsity_pattern (dof, sparsity, constraints);
-}
+ template <class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (
+ const DH &dof,
+ SparsityPattern &sparsity)
+ {
+ ConstraintMatrix constraints;
+ make_flux_sparsity_pattern (dof, sparsity, constraints);
+ }
-template <int dim, int spacedim>
-Table<2,DoFTools::Coupling>
-DoFTools::dof_couplings_from_component_couplings
-(const FiniteElement<dim,spacedim> &fe,
- const Table<2,Coupling> &component_couplings)
-{
- Assert(component_couplings.n_rows() == fe.n_components(),
- ExcDimensionMismatch(component_couplings.n_rows(),
- fe.n_components()));
- Assert(component_couplings.n_cols() == fe.n_components(),
- ExcDimensionMismatch(component_couplings.n_cols(),
- fe.n_components()));
+ template <int dim, int spacedim>
+ Table<2,Coupling>
+ dof_couplings_from_component_couplings
+ (const FiniteElement<dim,spacedim> &fe,
+ const Table<2,Coupling> &component_couplings)
+ {
+ Assert(component_couplings.n_rows() == fe.n_components(),
+ ExcDimensionMismatch(component_couplings.n_rows(),
+ fe.n_components()));
+ Assert(component_couplings.n_cols() == fe.n_components(),
+ ExcDimensionMismatch(component_couplings.n_cols(),
+ fe.n_components()));
- const unsigned int n_dofs = fe.dofs_per_cell;
+ const unsigned int n_dofs = fe.dofs_per_cell;
- Table<2,DoFTools::Coupling> dof_couplings (n_dofs, n_dofs);
+ Table<2,Coupling> dof_couplings (n_dofs, n_dofs);
- for (unsigned int i=0; i<n_dofs; ++i)
- {
- const unsigned int ii
- = (fe.is_primitive(i) ?
- fe.system_to_component_index(i).first
- :
- (std::find (fe.get_nonzero_components(i).begin(),
- fe.get_nonzero_components(i).end(),
- true)
- -
- fe.get_nonzero_components(i).begin())
- );
- Assert (ii < fe.n_components(), ExcInternalError());
-
- for (unsigned int j=0; j<n_dofs; ++j)
- {
- const unsigned int jj
- = (fe.is_primitive(j) ?
- fe.system_to_component_index(j).first
- :
- (std::find (fe.get_nonzero_components(j).begin(),
- fe.get_nonzero_components(j).end(),
- true)
- -
- fe.get_nonzero_components(j).begin())
- );
- Assert (jj < fe.n_components(), ExcInternalError());
-
- dof_couplings(i,j) = component_couplings(ii,jj);
- }
- }
- return dof_couplings;
-}
+ for (unsigned int i=0; i<n_dofs; ++i)
+ {
+ const unsigned int ii
+ = (fe.is_primitive(i) ?
+ fe.system_to_component_index(i).first
+ :
+ (std::find (fe.get_nonzero_components(i).begin(),
+ fe.get_nonzero_components(i).end(),
+ true)
+ -
+ fe.get_nonzero_components(i).begin())
+ );
+ Assert (ii < fe.n_components(), ExcInternalError());
+
+ for (unsigned int j=0; j<n_dofs; ++j)
+ {
+ const unsigned int jj
+ = (fe.is_primitive(j) ?
+ fe.system_to_component_index(j).first
+ :
+ (std::find (fe.get_nonzero_components(j).begin(),
+ fe.get_nonzero_components(j).end(),
+ true)
+ -
+ fe.get_nonzero_components(j).begin())
+ );
+ Assert (jj < fe.n_components(), ExcInternalError());
+
+ dof_couplings(i,j) = component_couplings(ii,jj);
+ }
+ }
+ return dof_couplings;
+ }
-template <int dim, int spacedim>
-std::vector<Table<2,DoFTools::Coupling> >
-DoFTools::dof_couplings_from_component_couplings
-(const hp::FECollection<dim,spacedim> &fe,
- const Table<2,Coupling> &component_couplings)
-{
- std::vector<Table<2,DoFTools::Coupling> > return_value (fe.size());
- for (unsigned int i=0; i<fe.size(); ++i)
- return_value[i]
- = dof_couplings_from_component_couplings(fe[i], component_couplings);
+ template <int dim, int spacedim>
+ std::vector<Table<2,Coupling> >
+ dof_couplings_from_component_couplings
+ (const hp::FECollection<dim,spacedim> &fe,
+ const Table<2,Coupling> &component_couplings)
+ {
+ std::vector<Table<2,Coupling> > return_value (fe.size());
+ for (unsigned int i=0; i<fe.size(); ++i)
+ return_value[i]
+ = dof_couplings_from_component_couplings(fe[i], component_couplings);
- return return_value;
-}
+ return return_value;
+ }
-namespace internal
-{
- namespace DoFTools
+ namespace internal
{
- // implementation of the same function in
- // namespace DoFTools for non-hp
- // DoFHandlers
- template <class DH, class SparsityPattern>
- void
- make_flux_sparsity_pattern (const DH &dof,
- SparsityPattern &sparsity,
- const Table<2,dealii::DoFTools::Coupling> &int_mask,
- const Table<2,dealii::DoFTools::Coupling> &flux_mask)
+ namespace
{
- const FiniteElement<DH::dimension> &fe = dof.get_fe();
-
- std::vector<unsigned int> dofs_on_this_cell(fe.dofs_per_cell);
- std::vector<unsigned int> dofs_on_other_cell(fe.dofs_per_cell);
-
- const Table<2,dealii::DoFTools::Coupling>
- int_dof_mask = dealii::DoFTools::dof_couplings_from_component_couplings(fe, int_mask),
- flux_dof_mask = dealii::DoFTools::dof_couplings_from_component_couplings(fe, flux_mask);
-
- Table<2,bool> support_on_face(fe.dofs_per_cell,
- GeometryInfo<DH::dimension>::faces_per_cell);
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell;++f)
- support_on_face(i,f) = fe.has_support_on_face(i,f);
-
- typename DH::active_cell_iterator cell = dof.begin_active(),
- endc = dof.end();
- for (; cell!=endc; ++cell)
- {
- cell->get_dof_indices (dofs_on_this_cell);
- // make sparsity pattern for this cell
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- if (int_dof_mask(i,j) != dealii::DoFTools::none)
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
-
- // Loop over all interior neighbors
- for (unsigned int face = 0;
- face < GeometryInfo<DH::dimension>::faces_per_cell;
- ++face)
- {
- const typename DH::face_iterator
- cell_face = cell->face(face);
- if (cell_face->user_flag_set ())
- continue;
+
+ // implementation of the same function in
+ // namespace DoFTools for non-hp
+ // DoFHandlers
+ template <class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const DH &dof,
+ SparsityPattern &sparsity,
+ const Table<2,Coupling> &int_mask,
+ const Table<2,Coupling> &flux_mask)
+ {
+ const FiniteElement<DH::dimension> &fe = dof.get_fe();
- if (cell->at_boundary (face) )
- {
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- {
- const bool i_non_zero_i = support_on_face (i, face);
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- {
- const bool j_non_zero_i = support_on_face (j, face);
+ std::vector<unsigned int> dofs_on_this_cell(fe.dofs_per_cell);
+ std::vector<unsigned int> dofs_on_other_cell(fe.dofs_per_cell);
- if ((flux_dof_mask(i,j) == dealii::DoFTools::always)
- ||
- (flux_dof_mask(i,j) == dealii::DoFTools::nonzero
- &&
- i_non_zero_i
- &&
- j_non_zero_i))
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
- }
- }
- }
- else
- {
- typename DH::cell_iterator
- neighbor = cell->neighbor(face);
- // Refinement edges are taken care of
- // by coarser cells
- if (cell->neighbor_is_coarser(face))
- continue;
+ const Table<2,Coupling>
+ int_dof_mask = dof_couplings_from_component_couplings(fe, int_mask),
+ flux_dof_mask = dof_couplings_from_component_couplings(fe, flux_mask);
- typename DH::face_iterator cell_face = cell->face(face);
- const unsigned int
- neighbor_face = cell->neighbor_of_neighbor(face);
+ Table<2,bool> support_on_face(fe.dofs_per_cell,
+ GeometryInfo<DH::dimension>::faces_per_cell);
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell;++f)
+ support_on_face(i,f) = fe.has_support_on_face(i,f);
- if (cell_face->has_children())
- {
- for (unsigned int sub_nr = 0;
- sub_nr != cell_face->n_children();
- ++sub_nr)
- {
- const typename DH::cell_iterator
- sub_neighbor
- = cell->neighbor_child_on_subface (face, sub_nr);
+ typename DH::active_cell_iterator cell = dof.begin_active(),
+ endc = dof.end();
+ for (; cell!=endc; ++cell)
+ {
+ cell->get_dof_indices (dofs_on_this_cell);
+ // make sparsity pattern for this cell
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
+ if (int_dof_mask(i,j) != Coupling::none)
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+
+ // Loop over all interior neighbors
+ for (unsigned int face = 0;
+ face < GeometryInfo<DH::dimension>::faces_per_cell;
+ ++face)
+ {
+ const typename DH::face_iterator
+ cell_face = cell->face(face);
+ if (cell_face->user_flag_set ())
+ continue;
- sub_neighbor->get_dof_indices (dofs_on_other_cell);
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- {
- const bool i_non_zero_i = support_on_face (i, face);
- const bool i_non_zero_e = support_on_face (i, neighbor_face);
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- {
- const bool j_non_zero_i = support_on_face (j, face);
- const bool j_non_zero_e = support_on_face (j, neighbor_face);
-
- if (flux_dof_mask(i,j) == dealii::DoFTools::always)
- {
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_other_cell[j]);
- sparsity.add (dofs_on_other_cell[i],
- dofs_on_this_cell[j]);
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
- sparsity.add (dofs_on_other_cell[i],
- dofs_on_other_cell[j]);
- }
- else if (flux_dof_mask(i,j) == dealii::DoFTools::nonzero)
- {
- if (i_non_zero_i && j_non_zero_e)
+ if (cell->at_boundary (face) )
+ {
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ {
+ const bool i_non_zero_i = support_on_face (i, face);
+ for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
+ {
+ const bool j_non_zero_i = support_on_face (j, face);
+
+ if ((flux_dof_mask(i,j) == Coupling::always)
+ ||
+ (flux_dof_mask(i,j) == Coupling::nonzero
+ &&
+ i_non_zero_i
+ &&
+ j_non_zero_i))
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+ }
+ }
+ }
+ else
+ {
+ typename DH::cell_iterator
+ neighbor = cell->neighbor(face);
+ // Refinement edges are taken care of
+ // by coarser cells
+ if (cell->neighbor_is_coarser(face))
+ continue;
+
+ typename DH::face_iterator cell_face = cell->face(face);
+ const unsigned int
+ neighbor_face = cell->neighbor_of_neighbor(face);
+
+ if (cell_face->has_children())
+ {
+ for (unsigned int sub_nr = 0;
+ sub_nr != cell_face->n_children();
+ ++sub_nr)
+ {
+ const typename DH::cell_iterator
+ sub_neighbor
+ = cell->neighbor_child_on_subface (face, sub_nr);
+
+ sub_neighbor->get_dof_indices (dofs_on_other_cell);
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ {
+ const bool i_non_zero_i = support_on_face (i, face);
+ const bool i_non_zero_e = support_on_face (i, neighbor_face);
+ for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
+ {
+ const bool j_non_zero_i = support_on_face (j, face);
+ const bool j_non_zero_e = support_on_face (j, neighbor_face);
+
+ if (flux_dof_mask(i,j) == Coupling::always)
+ {
sparsity.add (dofs_on_this_cell[i],
dofs_on_other_cell[j]);
- if (i_non_zero_e && j_non_zero_i)
sparsity.add (dofs_on_other_cell[i],
dofs_on_this_cell[j]);
- if (i_non_zero_i && j_non_zero_i)
sparsity.add (dofs_on_this_cell[i],
dofs_on_this_cell[j]);
- if (i_non_zero_e && j_non_zero_e)
sparsity.add (dofs_on_other_cell[i],
dofs_on_other_cell[j]);
- }
-
- if (flux_dof_mask(j,i) == dealii::DoFTools::always)
- {
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_other_cell[i]);
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_this_cell[i]);
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_this_cell[i]);
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_other_cell[i]);
- }
- else if (flux_dof_mask(j,i) == dealii::DoFTools::nonzero)
- {
- if (j_non_zero_i && i_non_zero_e)
+ }
+ else if (flux_dof_mask(i,j) == Coupling::nonzero)
+ {
+ if (i_non_zero_i && j_non_zero_e)
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_other_cell[j]);
+ if (i_non_zero_e && j_non_zero_i)
+ sparsity.add (dofs_on_other_cell[i],
+ dofs_on_this_cell[j]);
+ if (i_non_zero_i && j_non_zero_i)
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+ if (i_non_zero_e && j_non_zero_e)
+ sparsity.add (dofs_on_other_cell[i],
+ dofs_on_other_cell[j]);
+ }
+
+ if (flux_dof_mask(j,i) == Coupling::always)
+ {
sparsity.add (dofs_on_this_cell[j],
dofs_on_other_cell[i]);
- if (j_non_zero_e && i_non_zero_i)
sparsity.add (dofs_on_other_cell[j],
dofs_on_this_cell[i]);
- if (j_non_zero_i && i_non_zero_i)
sparsity.add (dofs_on_this_cell[j],
dofs_on_this_cell[i]);
- if (j_non_zero_e && i_non_zero_e)
sparsity.add (dofs_on_other_cell[j],
dofs_on_other_cell[i]);
- }
- }
- }
- sub_neighbor->face(neighbor_face)->set_user_flag ();
- }
- }
- else
- {
- neighbor->get_dof_indices (dofs_on_other_cell);
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- {
- const bool i_non_zero_i = support_on_face (i, face);
- const bool i_non_zero_e = support_on_face (i, neighbor_face);
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- {
- const bool j_non_zero_i = support_on_face (j, face);
- const bool j_non_zero_e = support_on_face (j, neighbor_face);
- if (flux_dof_mask(i,j) == dealii::DoFTools::always)
- {
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_other_cell[j]);
- sparsity.add (dofs_on_other_cell[i],
- dofs_on_this_cell[j]);
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
- sparsity.add (dofs_on_other_cell[i],
- dofs_on_other_cell[j]);
- }
- if (flux_dof_mask(i,j) == dealii::DoFTools::nonzero)
- {
- if (i_non_zero_i && j_non_zero_e)
+ }
+ else if (flux_dof_mask(j,i) == Coupling::nonzero)
+ {
+ if (j_non_zero_i && i_non_zero_e)
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_other_cell[i]);
+ if (j_non_zero_e && i_non_zero_i)
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_this_cell[i]);
+ if (j_non_zero_i && i_non_zero_i)
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_this_cell[i]);
+ if (j_non_zero_e && i_non_zero_e)
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_other_cell[i]);
+ }
+ }
+ }
+ sub_neighbor->face(neighbor_face)->set_user_flag ();
+ }
+ }
+ else
+ {
+ neighbor->get_dof_indices (dofs_on_other_cell);
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ {
+ const bool i_non_zero_i = support_on_face (i, face);
+ const bool i_non_zero_e = support_on_face (i, neighbor_face);
+ for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
+ {
+ const bool j_non_zero_i = support_on_face (j, face);
+ const bool j_non_zero_e = support_on_face (j, neighbor_face);
+ if (flux_dof_mask(i,j) == Coupling::always)
+ {
sparsity.add (dofs_on_this_cell[i],
dofs_on_other_cell[j]);
- if (i_non_zero_e && j_non_zero_i)
sparsity.add (dofs_on_other_cell[i],
dofs_on_this_cell[j]);
- if (i_non_zero_i && j_non_zero_i)
sparsity.add (dofs_on_this_cell[i],
dofs_on_this_cell[j]);
- if (i_non_zero_e && j_non_zero_e)
sparsity.add (dofs_on_other_cell[i],
dofs_on_other_cell[j]);
- }
-
- if (flux_dof_mask(j,i) == dealii::DoFTools::always)
- {
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_other_cell[i]);
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_this_cell[i]);
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_this_cell[i]);
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_other_cell[i]);
- }
- if (flux_dof_mask(j,i) == dealii::DoFTools::nonzero)
- {
- if (j_non_zero_i && i_non_zero_e)
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_other_cell[i]);
- if (j_non_zero_e && i_non_zero_i)
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_this_cell[i]);
- if (j_non_zero_i && i_non_zero_i)
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_this_cell[i]);
- if (j_non_zero_e && i_non_zero_e)
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_other_cell[i]);
- }
- }
- }
- neighbor->face(neighbor_face)->set_user_flag ();
- }
- }
- }
- }
- }
-
-
- // implementation of the same function in
- // namespace DoFTools for non-hp
- // DoFHandlers
- template <int dim, int spacedim, class SparsityPattern>
- void
- make_flux_sparsity_pattern (const dealii::hp::DoFHandler<dim,spacedim> &dof,
- SparsityPattern &sparsity,
- const Table<2,dealii::DoFTools::Coupling> &int_mask,
- const Table<2,dealii::DoFTools::Coupling> &flux_mask)
- {
- // while the implementation above is
- // quite optimized and caches a lot of
- // data (see e.g. the int/flux_dof_mask
- // tables), this is no longer practical
- // for the hp version since we would
- // have to have it for all combinations
- // of elements in the
- // hp::FECollection. consequently, the
- // implementation here is simpler and
- // probably less efficient but at least
- // readable...
-
- const dealii::hp::FECollection<dim,spacedim> &fe = dof.get_fe();
-
- std::vector<unsigned int> dofs_on_this_cell(dealii::DoFTools::max_dofs_per_cell(dof));
- std::vector<unsigned int> dofs_on_other_cell(dealii::DoFTools::max_dofs_per_cell(dof));
-
- const std::vector<Table<2,dealii::DoFTools::Coupling> >
- int_dof_mask
- = dealii::DoFTools::dof_couplings_from_component_couplings(fe, int_mask);
-
- typename dealii::hp::DoFHandler<dim,spacedim>::active_cell_iterator
- cell = dof.begin_active(),
- endc = dof.end();
- for (; cell!=endc; ++cell)
- {
- dofs_on_this_cell.resize (cell->get_fe().dofs_per_cell);
- cell->get_dof_indices (dofs_on_this_cell);
- // make sparsity pattern for this cell
- for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
- for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j)
- if (int_dof_mask[cell->active_fe_index()](i,j) != dealii::DoFTools::none)
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
-
- // Loop over all interior neighbors
- for (unsigned int face = 0;
- face < GeometryInfo<dim>::faces_per_cell;
- ++face)
- {
- const typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator
- cell_face = cell->face(face);
- if (cell_face->user_flag_set ())
- continue;
-
- if (cell->at_boundary (face) )
- {
- for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
- for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j)
- if ((flux_mask(cell->get_fe().system_to_component_index(i).first,
- cell->get_fe().system_to_component_index(j).first)
- == dealii::DoFTools::always)
- ||
- (flux_mask(cell->get_fe().system_to_component_index(i).first,
- cell->get_fe().system_to_component_index(j).first)
- == dealii::DoFTools::nonzero))
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
- }
- else
- {
- typename dealii::hp::DoFHandler<dim,spacedim>::cell_iterator
- neighbor = cell->neighbor(face);
- // Refinement edges are taken care of
- // by coarser cells
- if (cell->neighbor_is_coarser(face))
- continue;
-
- typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator
- cell_face = cell->face(face);
- const unsigned int
- neighbor_face = cell->neighbor_of_neighbor(face);
-
- if (cell_face->has_children())
- {
- for (unsigned int sub_nr = 0;
- sub_nr != cell_face->n_children();
- ++sub_nr)
- {
- const typename dealii::hp::DoFHandler<dim,spacedim>::cell_iterator
- sub_neighbor
- = cell->neighbor_child_on_subface (face, sub_nr);
-
- dofs_on_other_cell.resize (sub_neighbor->get_fe().dofs_per_cell);
- sub_neighbor->get_dof_indices (dofs_on_other_cell);
- for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
- {
- for (unsigned int j=0; j<sub_neighbor->get_fe().dofs_per_cell;
- ++j)
- {
- if ((flux_mask(cell->get_fe().system_to_component_index(i).first,
- sub_neighbor->get_fe().system_to_component_index(j).first)
- == dealii::DoFTools::always)
- ||
- (flux_mask(cell->get_fe().system_to_component_index(i).first,
- sub_neighbor->get_fe().system_to_component_index(j).first)
- == dealii::DoFTools::nonzero))
- {
+ }
+ if (flux_dof_mask(i,j) == Coupling::nonzero)
+ {
+ if (i_non_zero_i && j_non_zero_e)
sparsity.add (dofs_on_this_cell[i],
dofs_on_other_cell[j]);
+ if (i_non_zero_e && j_non_zero_i)
sparsity.add (dofs_on_other_cell[i],
dofs_on_this_cell[j]);
+ if (i_non_zero_i && j_non_zero_i)
sparsity.add (dofs_on_this_cell[i],
dofs_on_this_cell[j]);
+ if (i_non_zero_e && j_non_zero_e)
sparsity.add (dofs_on_other_cell[i],
dofs_on_other_cell[j]);
- }
-
- if ((flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first,
- cell->get_fe().system_to_component_index(i).first)
- == dealii::DoFTools::always)
- ||
- (flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first,
- cell->get_fe().system_to_component_index(i).first)
- == dealii::DoFTools::nonzero))
- {
+ }
+
+ if (flux_dof_mask(j,i) == Coupling::always)
+ {
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_other_cell[i]);
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_this_cell[i]);
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_this_cell[i]);
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_other_cell[i]);
+ }
+ if (flux_dof_mask(j,i) == Coupling::nonzero)
+ {
+ if (j_non_zero_i && i_non_zero_e)
sparsity.add (dofs_on_this_cell[j],
dofs_on_other_cell[i]);
+ if (j_non_zero_e && i_non_zero_i)
sparsity.add (dofs_on_other_cell[j],
dofs_on_this_cell[i]);
+ if (j_non_zero_i && i_non_zero_i)
sparsity.add (dofs_on_this_cell[j],
dofs_on_this_cell[i]);
+ if (j_non_zero_e && i_non_zero_e)
sparsity.add (dofs_on_other_cell[j],
dofs_on_other_cell[i]);
- }
- }
- }
- sub_neighbor->face(neighbor_face)->set_user_flag ();
- }
- }
- else
- {
- dofs_on_other_cell.resize (neighbor->get_fe().dofs_per_cell);
- neighbor->get_dof_indices (dofs_on_other_cell);
- for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
- {
- for (unsigned int j=0; j<neighbor->get_fe().dofs_per_cell; ++j)
- {
- if ((flux_mask(cell->get_fe().system_to_component_index(i).first,
- neighbor->get_fe().system_to_component_index(j).first)
- == dealii::DoFTools::always)
- ||
- (flux_mask(cell->get_fe().system_to_component_index(i).first,
- neighbor->get_fe().system_to_component_index(j).first)
- == dealii::DoFTools::nonzero))
- {
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_other_cell[j]);
- sparsity.add (dofs_on_other_cell[i],
- dofs_on_this_cell[j]);
- sparsity.add (dofs_on_this_cell[i],
- dofs_on_this_cell[j]);
- sparsity.add (dofs_on_other_cell[i],
- dofs_on_other_cell[j]);
- }
-
- if ((flux_mask(neighbor->get_fe().system_to_component_index(j).first,
- cell->get_fe().system_to_component_index(i).first)
- == dealii::DoFTools::always)
- ||
- (flux_mask(neighbor->get_fe().system_to_component_index(j).first,
- cell->get_fe().system_to_component_index(i).first)
- == dealii::DoFTools::nonzero))
- {
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_other_cell[i]);
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_this_cell[i]);
- sparsity.add (dofs_on_this_cell[j],
- dofs_on_this_cell[i]);
- sparsity.add (dofs_on_other_cell[j],
- dofs_on_other_cell[i]);
- }
- }
- }
- neighbor->face(neighbor_face)->set_user_flag ();
- }
- }
- }
- }
+ }
+ }
+ }
+ neighbor->face(neighbor_face)->set_user_flag ();
+ }
+ }
+ }
+ }
+ }
+
+
+ // implementation of the same function in
+ // namespace DoFTools for non-hp
+ // DoFHandlers
+ template <int dim, int spacedim, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const dealii::hp::DoFHandler<dim,spacedim> &dof,
+ SparsityPattern &sparsity,
+ const Table<2,Coupling> &int_mask,
+ const Table<2,Coupling> &flux_mask)
+ {
+ // while the implementation above is
+ // quite optimized and caches a lot of
+ // data (see e.g. the int/flux_dof_mask
+ // tables), this is no longer practical
+ // for the hp version since we would
+ // have to have it for all combinations
+ // of elements in the
+ // hp::FECollection. consequently, the
+ // implementation here is simpler and
+ // probably less efficient but at least
+ // readable...
+
+ const dealii::hp::FECollection<dim,spacedim> &fe = dof.get_fe();
+
+ std::vector<unsigned int> dofs_on_this_cell(DoFTools::max_dofs_per_cell(dof));
+ std::vector<unsigned int> dofs_on_other_cell(DoFTools::max_dofs_per_cell(dof));
+
+ const std::vector<Table<2,Coupling> >
+ int_dof_mask
+ = dof_couplings_from_component_couplings(fe, int_mask);
+
+ typename dealii::hp::DoFHandler<dim,spacedim>::active_cell_iterator
+ cell = dof.begin_active(),
+ endc = dof.end();
+ for (; cell!=endc; ++cell)
+ {
+ dofs_on_this_cell.resize (cell->get_fe().dofs_per_cell);
+ cell->get_dof_indices (dofs_on_this_cell);
+ // make sparsity pattern for this cell
+ for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
+ for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j)
+ if (int_dof_mask[cell->active_fe_index()](i,j) != Coupling::none)
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+
+ // Loop over all interior neighbors
+ for (unsigned int face = 0;
+ face < GeometryInfo<dim>::faces_per_cell;
+ ++face)
+ {
+ const typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator
+ cell_face = cell->face(face);
+ if (cell_face->user_flag_set ())
+ continue;
+
+ if (cell->at_boundary (face) )
+ {
+ for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
+ for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j)
+ if ((flux_mask(cell->get_fe().system_to_component_index(i).first,
+ cell->get_fe().system_to_component_index(j).first)
+ == Coupling::always)
+ ||
+ (flux_mask(cell->get_fe().system_to_component_index(i).first,
+ cell->get_fe().system_to_component_index(j).first)
+ == Coupling::nonzero))
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+ }
+ else
+ {
+ typename dealii::hp::DoFHandler<dim,spacedim>::cell_iterator
+ neighbor = cell->neighbor(face);
+ // Refinement edges are taken care of
+ // by coarser cells
+ if (cell->neighbor_is_coarser(face))
+ continue;
+
+ typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator
+ cell_face = cell->face(face);
+ const unsigned int
+ neighbor_face = cell->neighbor_of_neighbor(face);
+
+ if (cell_face->has_children())
+ {
+ for (unsigned int sub_nr = 0;
+ sub_nr != cell_face->n_children();
+ ++sub_nr)
+ {
+ const typename dealii::hp::DoFHandler<dim,spacedim>::cell_iterator
+ sub_neighbor
+ = cell->neighbor_child_on_subface (face, sub_nr);
+
+ dofs_on_other_cell.resize (sub_neighbor->get_fe().dofs_per_cell);
+ sub_neighbor->get_dof_indices (dofs_on_other_cell);
+ for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
+ {
+ for (unsigned int j=0; j<sub_neighbor->get_fe().dofs_per_cell;
+ ++j)
+ {
+ if ((flux_mask(cell->get_fe().system_to_component_index(i).first,
+ sub_neighbor->get_fe().system_to_component_index(j).first)
+ == Coupling::always)
+ ||
+ (flux_mask(cell->get_fe().system_to_component_index(i).first,
+ sub_neighbor->get_fe().system_to_component_index(j).first)
+ == Coupling::nonzero))
+ {
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_other_cell[j]);
+ sparsity.add (dofs_on_other_cell[i],
+ dofs_on_this_cell[j]);
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+ sparsity.add (dofs_on_other_cell[i],
+ dofs_on_other_cell[j]);
+ }
+
+ if ((flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first,
+ cell->get_fe().system_to_component_index(i).first)
+ == Coupling::always)
+ ||
+ (flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first,
+ cell->get_fe().system_to_component_index(i).first)
+ == Coupling::nonzero))
+ {
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_other_cell[i]);
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_this_cell[i]);
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_this_cell[i]);
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_other_cell[i]);
+ }
+ }
+ }
+ sub_neighbor->face(neighbor_face)->set_user_flag ();
+ }
+ }
+ else
+ {
+ dofs_on_other_cell.resize (neighbor->get_fe().dofs_per_cell);
+ neighbor->get_dof_indices (dofs_on_other_cell);
+ for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
+ {
+ for (unsigned int j=0; j<neighbor->get_fe().dofs_per_cell; ++j)
+ {
+ if ((flux_mask(cell->get_fe().system_to_component_index(i).first,
+ neighbor->get_fe().system_to_component_index(j).first)
+ == Coupling::always)
+ ||
+ (flux_mask(cell->get_fe().system_to_component_index(i).first,
+ neighbor->get_fe().system_to_component_index(j).first)
+ == Coupling::nonzero))
+ {
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_other_cell[j]);
+ sparsity.add (dofs_on_other_cell[i],
+ dofs_on_this_cell[j]);
+ sparsity.add (dofs_on_this_cell[i],
+ dofs_on_this_cell[j]);
+ sparsity.add (dofs_on_other_cell[i],
+ dofs_on_other_cell[j]);
+ }
+
+ if ((flux_mask(neighbor->get_fe().system_to_component_index(j).first,
+ cell->get_fe().system_to_component_index(i).first)
+ == Coupling::always)
+ ||
+ (flux_mask(neighbor->get_fe().system_to_component_index(j).first,
+ cell->get_fe().system_to_component_index(i).first)
+ == Coupling::nonzero))
+ {
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_other_cell[i]);
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_this_cell[i]);
+ sparsity.add (dofs_on_this_cell[j],
+ dofs_on_this_cell[i]);
+ sparsity.add (dofs_on_other_cell[j],
+ dofs_on_other_cell[i]);
+ }
+ }
+ }
+ neighbor->face(neighbor_face)->set_user_flag ();
+ }
+ }
+ }
+ }
+ }
}
}
-}
-template <class DH, class SparsityPattern>
-void
-DoFTools::
-make_flux_sparsity_pattern (const DH &dof,
- SparsityPattern &sparsity,
- const Table<2,Coupling> &int_mask,
- const Table<2,Coupling> &flux_mask)
-{
- // do the error checking and frame code
- // here, and then pass on to more
- // specialized functions in the internal
- // namespace
- const unsigned int n_dofs = dof.n_dofs();
- const unsigned int n_comp = dof.get_fe().n_components();
-
- Assert (sparsity.n_rows() == n_dofs,
- ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
- Assert (sparsity.n_cols() == n_dofs,
- ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
- Assert (int_mask.n_rows() == n_comp,
- ExcDimensionMismatch (int_mask.n_rows(), n_comp));
- Assert (int_mask.n_cols() == n_comp,
- ExcDimensionMismatch (int_mask.n_cols(), n_comp));
- Assert (flux_mask.n_rows() == n_comp,
- ExcDimensionMismatch (flux_mask.n_rows(), n_comp));
- Assert (flux_mask.n_cols() == n_comp,
- ExcDimensionMismatch (flux_mask.n_cols(), n_comp));
+
+ template <class DH, class SparsityPattern>
+ void
+ make_flux_sparsity_pattern (const DH &dof,
+ SparsityPattern &sparsity,
+ const Table<2,Coupling> &int_mask,
+ const Table<2,Coupling> &flux_mask)
+ {
+ // do the error checking and frame code
+ // here, and then pass on to more
+ // specialized functions in the internal
+ // namespace
+ const unsigned int n_dofs = dof.n_dofs();
+ const unsigned int n_comp = dof.get_fe().n_components();
+
+ Assert (sparsity.n_rows() == n_dofs,
+ ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
+ Assert (sparsity.n_cols() == n_dofs,
+ ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
+ Assert (int_mask.n_rows() == n_comp,
+ ExcDimensionMismatch (int_mask.n_rows(), n_comp));
+ Assert (int_mask.n_cols() == n_comp,
+ ExcDimensionMismatch (int_mask.n_cols(), n_comp));
+ Assert (flux_mask.n_rows() == n_comp,
+ ExcDimensionMismatch (flux_mask.n_rows(), n_comp));
+ Assert (flux_mask.n_cols() == n_comp,
+ ExcDimensionMismatch (flux_mask.n_cols(), n_comp));
- // Clear user flags because we will
- // need them. But first we save
- // them and make sure that we
- // restore them later such that at
- // the end of this function the
- // Triangulation will be in the
- // same state as it was at the
- // beginning of this function.
- std::vector<bool> user_flags;
- dof.get_tria().save_user_flags(user_flags);
- const_cast<Triangulation<DH::dimension> &>(dof.get_tria()).clear_user_flags ();
-
- internal::DoFTools::make_flux_sparsity_pattern (dof, sparsity,
- int_mask, flux_mask);
+ // Clear user flags because we will
+ // need them. But first we save
+ // them and make sure that we
+ // restore them later such that at
+ // the end of this function the
+ // Triangulation will be in the
+ // same state as it was at the
+ // beginning of this function.
+ std::vector<bool> user_flags;
+ dof.get_tria().save_user_flags(user_flags);
+ const_cast<Triangulation<DH::dimension> &>(dof.get_tria()).clear_user_flags ();
+
+ internal::make_flux_sparsity_pattern (dof, sparsity,
+ int_mask, flux_mask);
- // finally restore the user flags
- const_cast<Triangulation<DH::dimension> &>(dof.get_tria()).load_user_flags(user_flags);
-}
+ // finally restore the user flags
+ const_cast<Triangulation<DH::dimension> &>(dof.get_tria()).load_user_flags(user_flags);
+ }
-namespace internal
-{
- namespace DoFTools
+ namespace internal
{
namespace
{
}
- /**
- * Make sure that the given @p
- * face_interpolation_matrix
- * pointer points to a valid
- * matrix. If the pointer is zero
- * beforehand, create an entry
- * with the correct data. If it
- * is nonzero, don't touch it.
- */
+ /**
+ * Make sure that the given @p
+ * face_interpolation_matrix
+ * pointer points to a valid
+ * matrix. If the pointer is zero
+ * beforehand, create an entry
+ * with the correct data. If it
+ * is nonzero, don't touch it.
+ */
template <int dim, int spacedim>
void
ensure_existence_of_face_matrix (const FiniteElement<dim,spacedim> &fe1,
- const FiniteElement<dim,spacedim> &fe2,
- std_cxx1x::shared_ptr<FullMatrix<double> > &matrix)
+ const FiniteElement<dim,spacedim> &fe2,
+ std_cxx1x::shared_ptr<FullMatrix<double> > &matrix)
{
- if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >())
- {
- matrix = std_cxx1x::shared_ptr<FullMatrix<double> >
- (new FullMatrix<double> (fe2.dofs_per_face,
- fe1.dofs_per_face));
- fe1.get_face_interpolation_matrix (fe2,
- *matrix);
- }
+ if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >())
+ {
+ matrix = std_cxx1x::shared_ptr<FullMatrix<double> >
+ (new FullMatrix<double> (fe2.dofs_per_face,
+ fe1.dofs_per_face));
+ fe1.get_face_interpolation_matrix (fe2,
+ *matrix);
+ }
}
template <int dim, int spacedim>
void
ensure_existence_of_subface_matrix (const FiniteElement<dim,spacedim> &fe1,
- const FiniteElement<dim,spacedim> &fe2,
- const unsigned int subface,
- std_cxx1x::shared_ptr<FullMatrix<double> > &matrix)
+ const FiniteElement<dim,spacedim> &fe2,
+ const unsigned int subface,
+ std_cxx1x::shared_ptr<FullMatrix<double> > &matrix)
{
- if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >())
- {
- matrix = std_cxx1x::shared_ptr<FullMatrix<double> >
- (new FullMatrix<double> (fe2.dofs_per_face,
- fe1.dofs_per_face));
- fe1.get_subface_interpolation_matrix (fe2,
- subface,
- *matrix);
- }
+ if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >())
+ {
+ matrix = std_cxx1x::shared_ptr<FullMatrix<double> >
+ (new FullMatrix<double> (fe2.dofs_per_face,
+ fe1.dofs_per_face));
+ fe1.get_subface_interpolation_matrix (fe2,
+ subface,
+ *matrix);
+ }
}
* master part as explained in
* the @ref hp_paper "hp paper".
*/
-#ifdef DEAL_II_ANON_NAMESPACE_BUG
- static
-#endif
void
ensure_existence_of_split_face_matrix (const FullMatrix<double> &face_interpolation_matrix,
const std::vector<bool> &master_dof_mask,
static_cast<signed int>(face_interpolation_matrix.n()),
ExcInternalError());
- if (split_matrix ==
+ if (split_matrix ==
std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > >())
- {
- split_matrix
+ {
+ split_matrix
= std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > >
(new std::pair<FullMatrix<double>,FullMatrix<double> >());
}
- // a template that can
- // determine statically whether
- // a given DoFHandler class
- // supports different finite
- // element elements
+ // a template that can
+ // determine statically whether
+ // a given DoFHandler class
+ // supports different finite
+ // element elements
template <typename>
struct DoFHandlerSupportsDifferentFEs
{
- static const bool value = true;
+ static const bool value = true;
};
template <int dim, int spacedim>
struct DoFHandlerSupportsDifferentFEs< dealii::DoFHandler<dim,spacedim> >
{
- static const bool value = false;
+ static const bool value = false;
};
template <int dim, int spacedim>
struct DoFHandlerSupportsDifferentFEs< dealii::MGDoFHandler<dim,spacedim> >
{
- static const bool value = false;
+ static const bool value = false;
};
- /**
- * A function that returns how
- * many different finite
- * elements a dof handler
- * uses. This is one for non-hp
- * DoFHandlers and
- * dof_handler.get_fe().size()
- * for the hp-versions.
- */
+ /**
+ * A function that returns how
+ * many different finite
+ * elements a dof handler
+ * uses. This is one for non-hp
+ * DoFHandlers and
+ * dof_handler.get_fe().size()
+ * for the hp-versions.
+ */
template <int dim, int spacedim>
unsigned int
n_finite_elements (const dealii::hp::DoFHandler<dim,spacedim> &dof_handler)
{
- return dof_handler.get_fe().size();
+ return dof_handler.get_fe().size();
}
unsigned int
n_finite_elements (const DH &)
{
- return 1;
+ return 1;
}
- /**
- * For a given face belonging
- * to an active cell that
- * borders to a more refined
- * cell, return the fe_index of
- * the most dominating finite
- * element used on any of the
- * face's subfaces.
- */
+ /**
+ * For a given face belonging
+ * to an active cell that
+ * borders to a more refined
+ * cell, return the fe_index of
+ * the most dominating finite
+ * element used on any of the
+ * face's subfaces.
+ */
template <typename face_iterator>
unsigned int
get_most_dominating_subface_fe_index (const face_iterator &face)
const unsigned int spacedim
= face_iterator::AccessorType::space_dimension;
- unsigned int dominating_subface_no = 0;
- for (; dominating_subface_no<face->n_children();
- ++dominating_subface_no)
- {
- // each of the subfaces
- // can have only a single
- // fe_index associated
- // with them, since there
- // is no cell on the
- // other side
- Assert (face->child(dominating_subface_no)
- ->n_active_fe_indices()
- == 1,
- ExcInternalError());
-
- const FiniteElement<dim,spacedim> &
- this_subface_fe = (face->child(dominating_subface_no)
- ->get_fe (face->child(dominating_subface_no)
- ->nth_active_fe_index(0)));
-
- FiniteElementDomination::Domination
- domination = FiniteElementDomination::either_element_can_dominate;
- for (unsigned int sf=0; sf<face->n_children(); ++sf)
- if (sf != dominating_subface_no)
- {
- const FiniteElement<dim,spacedim> &
- that_subface_fe = (face->child(sf)
- ->get_fe (face->child(sf)
- ->nth_active_fe_index(0)));
-
- domination = domination &
- this_subface_fe.compare_for_face_domination(that_subface_fe);
- }
-
- // see if the element
- // on this subface is
- // able to dominate
- // the ones on all
- // other subfaces,
- // and if so take it
- if ((domination == FiniteElementDomination::this_element_dominates)
- ||
- (domination == FiniteElementDomination::either_element_can_dominate))
- break;
- }
-
- // check that we have
- // found one such subface
- Assert (dominating_subface_no < face->n_children(),
- ExcNotImplemented());
-
- // return the finite element
- // index used on it. note
- // that only a single fe can
- // be active on such subfaces
- return face->child (dominating_subface_no)->nth_active_fe_index(0);
+ unsigned int dominating_subface_no = 0;
+ for (; dominating_subface_no<face->n_children();
+ ++dominating_subface_no)
+ {
+ // each of the subfaces
+ // can have only a single
+ // fe_index associated
+ // with them, since there
+ // is no cell on the
+ // other side
+ Assert (face->child(dominating_subface_no)
+ ->n_active_fe_indices()
+ == 1,
+ ExcInternalError());
+
+ const FiniteElement<dim,spacedim> &
+ this_subface_fe = (face->child(dominating_subface_no)
+ ->get_fe (face->child(dominating_subface_no)
+ ->nth_active_fe_index(0)));
+
+ FiniteElementDomination::Domination
+ domination = FiniteElementDomination::either_element_can_dominate;
+ for (unsigned int sf=0; sf<face->n_children(); ++sf)
+ if (sf != dominating_subface_no)
+ {
+ const FiniteElement<dim,spacedim> &
+ that_subface_fe = (face->child(sf)
+ ->get_fe (face->child(sf)
+ ->nth_active_fe_index(0)));
+
+ domination = domination &
+ this_subface_fe.compare_for_face_domination(that_subface_fe);
+ }
+
+ // see if the element
+ // on this subface is
+ // able to dominate
+ // the ones on all
+ // other subfaces,
+ // and if so take it
+ if ((domination == FiniteElementDomination::this_element_dominates)
+ ||
+ (domination == FiniteElementDomination::either_element_can_dominate))
+ break;
+ }
+
+ // check that we have
+ // found one such subface
+ Assert (dominating_subface_no < face->n_children(),
+ ExcNotImplemented());
+
+ // return the finite element
+ // index used on it. note
+ // that only a single fe can
+ // be active on such subfaces
+ return face->child (dominating_subface_no)->nth_active_fe_index(0);
}
- /**
+ /**
* Copy constraints into a constraint
* matrix object.
*
- * This function removes zero
- * constraints and those, which
- * constrain a DoF which was
- * already eliminated in one of
- * the previous steps of the hp
- * hanging node procedure.
+ * This function removes zero
+ * constraints and those, which
+ * constrain a DoF which was
+ * already eliminated in one of
+ * the previous steps of the hp
+ * hanging node procedure.
*
* It also suppresses very small
* entries in the constraint matrix to
* avoid making the sparsity pattern
* fuller than necessary.
- */
-#ifdef DEAL_II_ANON_NAMESPACE_BUG
- static
-#endif
+ */
void
filter_constraints (const std::vector<unsigned int> &master_dofs,
const std::vector<unsigned int> &slave_dofs,
for (unsigned int row=0; row!=n_slave_dofs; ++row)
- if (constraints.is_constrained (slave_dofs[row]) == false)
- {
- bool constraint_already_satisfied = false;
-
- // Check if we have an identity
- // constraint, which is already
- // satisfied by unification of
- // the corresponding global dof
- // indices
- for (unsigned int i=0; i<n_master_dofs; ++i)
- if (face_constraints (row,i) == 1.0)
- if (master_dofs[i] == slave_dofs[row])
- {
- constraint_already_satisfied = true;
- break;
- }
-
- if (constraint_already_satisfied == false)
- {
+ if (constraints.is_constrained (slave_dofs[row]) == false)
+ {
+ bool constraint_already_satisfied = false;
+
+ // Check if we have an identity
+ // constraint, which is already
+ // satisfied by unification of
+ // the corresponding global dof
+ // indices
+ for (unsigned int i=0; i<n_master_dofs; ++i)
+ if (face_constraints (row,i) == 1.0)
+ if (master_dofs[i] == slave_dofs[row])
+ {
+ constraint_already_satisfied = true;
+ break;
+ }
+
+ if (constraint_already_satisfied == false)
+ {
// add up the absolute
// values of all
// constraints in this line
// than necessary without
// producing any
// significant effect
- constraints.add_line (slave_dofs[row]);
- for (unsigned int i=0; i<n_master_dofs; ++i)
- if ((face_constraints(row,i) != 0)
+ constraints.add_line (slave_dofs[row]);
+ for (unsigned int i=0; i<n_master_dofs; ++i)
+ if ((face_constraints(row,i) != 0)
&&
(std::fabs(face_constraints(row,i)) >= 1e-14*abs_sum))
constraints.add_entry (slave_dofs[row],
master_dofs[i],
face_constraints (row,i));
constraints.set_inhomogeneity (slave_dofs[row], 0.);
- }
- }
+ }
+ }
}
}
- static
void
make_hp_hanging_node_constraints (const dealii::DoFHandler<1> &,
ConstraintMatrix &)
- static
void
make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1> &,
ConstraintMatrix &,
}
- static
void
make_hp_hanging_node_constraints (const dealii::MGDoFHandler<1> &,
ConstraintMatrix &)
- static
void
make_oldstyle_hanging_node_constraints (const dealii::MGDoFHandler<1> &,
ConstraintMatrix &,
}
- static
void
make_hp_hanging_node_constraints (const dealii::hp::DoFHandler<1> &/*dof_handler*/,
ConstraintMatrix &/*constraints*/)
- static
void
make_oldstyle_hanging_node_constraints (const dealii::hp::DoFHandler<1> &/*dof_handler*/,
ConstraintMatrix &/*constraints*/,
}
- static
void
make_hp_hanging_node_constraints (const dealii::DoFHandler<1,2> &,
ConstraintMatrix &)
- static
void
make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,2> &,
ConstraintMatrix &,
// currently not used but may be in the future:
-// static
// void
// make_hp_hanging_node_constraints (const dealii::MGDoFHandler<1,2> &,
// ConstraintMatrix &)
-// static
// void
// make_oldstyle_hanging_node_constraints (const dealii::MGDoFHandler<1,2> &,
// ConstraintMatrix &,
// }
-// static
// void
// make_oldstyle_hanging_node_constraints (const dealii::hp::DoFHandler<1,2> &/*dof_handler*/,
// ConstraintMatrix &/*constraints*/,
template <class DH>
- static
void
make_oldstyle_hanging_node_constraints (const DH &dof_handler,
ConstraintMatrix &constraints,
template <class DH>
- static
void
make_oldstyle_hanging_node_constraints (const DH &dof_handler,
ConstraintMatrix &constraints,
const FiniteElement<dim> &fe = cell->get_fe();
const unsigned int fe_index = cell->active_fe_index();
- const unsigned int n_dofs_on_mother = fe.dofs_per_face;
- const unsigned int n_dofs_on_children = (5*fe.dofs_per_vertex+
- 12*fe.dofs_per_line+
- 4*fe.dofs_per_quad);
+ const unsigned int n_dofs_on_mother = fe.dofs_per_face;
+ const unsigned int n_dofs_on_children = (5*fe.dofs_per_vertex+
+ 12*fe.dofs_per_line+
+ 4*fe.dofs_per_quad);
//TODO[TL]: think about this and the following in case of anisotropic refinement
dofs_on_mother.resize (n_dofs_on_mother);
template <class DH>
- static
void
make_hp_hanging_node_constraints (const DH &dof_handler,
ConstraintMatrix &constraints)
const unsigned int spacedim = DH::space_dimension;
- // a matrix to be used for
- // constraints below. declared
- // here and simply resized down
- // below to avoid permanent
- // re-allocation of memory
+ // a matrix to be used for
+ // constraints below. declared
+ // here and simply resized down
+ // below to avoid permanent
+ // re-allocation of memory
FullMatrix<double> constraint_matrix;
// similarly have arrays that
std::vector<unsigned int> slave_dofs;
std::vector<unsigned int> scratch_dofs;
- // caches for the face and
- // subface interpolation
- // matrices between different
- // (or the same) finite
- // elements. we compute them
- // only once, namely the first
- // time they are needed, and
- // then just reuse them
+ // caches for the face and
+ // subface interpolation
+ // matrices between different
+ // (or the same) finite
+ // elements. we compute them
+ // only once, namely the first
+ // time they are needed, and
+ // then just reuse them
Table<2,std_cxx1x::shared_ptr<FullMatrix<double> > >
- face_interpolation_matrices (n_finite_elements (dof_handler),
- n_finite_elements (dof_handler));
+ face_interpolation_matrices (n_finite_elements (dof_handler),
+ n_finite_elements (dof_handler));
Table<3,std_cxx1x::shared_ptr<FullMatrix<double> > >
- subface_interpolation_matrices (n_finite_elements (dof_handler),
- n_finite_elements (dof_handler),
- GeometryInfo<dim>::max_children_per_face);
+ subface_interpolation_matrices (n_finite_elements (dof_handler),
+ n_finite_elements (dof_handler),
+ GeometryInfo<dim>::max_children_per_face);
// similarly have a cache for
// the matrices that are split
// interpolation matrix as
// described in the @ref hp_paper "hp paper"
Table<2,std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > >
- split_face_interpolation_matrices (n_finite_elements (dof_handler),
+ split_face_interpolation_matrices (n_finite_elements (dof_handler),
n_finite_elements (dof_handler));
// finally, for each pair of finite
}
}
}
-}
-
-template <class DH>
-void
-DoFTools::make_hanging_node_constraints (const DH &dof_handler,
- ConstraintMatrix &constraints)
-{
- // Decide whether to use the
- // new or old make_hanging_node_constraints
- // function. If all the FiniteElement
- // or all elements in a FECollection support
- // the new face constraint matrix, the
- // new code will be used.
- // Otherwise, the old implementation is used
- // for the moment.
- if (dof_handler.get_fe().hp_constraints_are_implemented ())
- internal::DoFTools::
- make_hp_hanging_node_constraints (dof_handler,
- constraints);
- else
- internal::DoFTools::
- make_oldstyle_hanging_node_constraints (dof_handler,
- constraints,
- dealii::internal::int2type<DH::dimension>());
-}
-
-
-namespace internal
-{
- // this internal function assigns to each dof
- // the respective component of the vector
- // system. if use_blocks is set, then the
- // assignment is done by blocks, not by
- // components, as specified by
- // component_select. The additional argument
- // component_select only is used for
- // non-primitive FEs, where we need it since
- // more components couple, and no unique
- // component can be assigned. Then, we sort
- // them to the first selected component of the
- // vector system.
template <class DH>
- inline
void
- extract_dofs_by_component (const DH &dof,
- const std::vector<bool> &component_select,
- const bool sort_by_blocks,
- std::vector<unsigned char> &dofs_by_component)
+ make_hanging_node_constraints (const DH &dof_handler,
+ ConstraintMatrix &constraints)
{
- const dealii::hp::FECollection<DH::dimension,DH::space_dimension>
- fe_collection (dof.get_fe());
- Assert (fe_collection.n_components() < 256, ExcNotImplemented());
- Assert (dofs_by_component.size() == dof.n_locally_owned_dofs(),
- ExcDimensionMismatch(dofs_by_component.size(),
- dof.n_locally_owned_dofs()));
-
- // next set up a table for the
- // degrees of freedom on each of
- // the cells whether it is
- // something interesting or not
- std::vector<std::vector<unsigned char> > local_component_association
- (fe_collection.size());
- for (unsigned int f=0; f<fe_collection.size(); ++f)
- {
- const FiniteElement<DH::dimension,DH::space_dimension> &fe =
- fe_collection[f];
- local_component_association[f].resize(fe.dofs_per_cell);
- if (sort_by_blocks == true)
- {
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- local_component_association[f][i]
- = fe.system_to_block_index(i).first;
- }
- else
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- if (fe.is_primitive(i))
- local_component_association[f][i] =
- fe.system_to_component_index(i).first;
- else
- // if this shape function is
- // not primitive, then we have
- // to work harder. we have to
- // find out whether _any_ of
- // the vector components of
- // this element is selected or
- // not
- //
- // to do so, get the a list of
- // nonzero elements and see which are
- // actually active
- {
- const unsigned int first_comp =
- (std::find(fe.get_nonzero_components(i).begin(),
- fe.get_nonzero_components(i).end(),
- true) -
- fe.get_nonzero_components(i).begin());
- const unsigned int end_comp =
- (std::find(fe.get_nonzero_components(i).begin()+first_comp,
- fe.get_nonzero_components(i).end(),
- false)-
- fe.get_nonzero_components(i).begin());
-
- // now check whether any of
- // the components in between
- // is set
- if (component_select.size() == 0 ||
- (component_select[first_comp] == true ||
- std::count(component_select.begin()+first_comp,
- component_select.begin()+end_comp, true) == 0))
- local_component_association[f][i] = first_comp;
- else
- for (unsigned int c=first_comp; c<end_comp; ++c)
- if (component_select[c] == true)
- {
- local_component_association[f][i] = c;
- break;
- }
- }
- }
-
- // then loop over all cells and do
- // the work
- std::vector<unsigned int> indices;
- for (typename DH::active_cell_iterator c=dof.begin_active();
- c!=dof.end(); ++ c)
- if (!c->is_artificial() && !c->is_ghost())
- {
- const unsigned int fe_index = c->active_fe_index();
- const unsigned int dofs_per_cell = c->get_fe().dofs_per_cell;
- indices.resize(dofs_per_cell);
- c->get_dof_indices(indices);
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- if (dof.locally_owned_dofs().is_element(indices[i]))
- dofs_by_component[dof.locally_owned_dofs().index_within_set(indices[i])]
- = local_component_association[fe_index][i];
- }
+ // Decide whether to use the
+ // new or old make_hanging_node_constraints
+ // function. If all the FiniteElement
+ // or all elements in a FECollection support
+ // the new face constraint matrix, the
+ // new code will be used.
+ // Otherwise, the old implementation is used
+ // for the moment.
+ if (dof_handler.get_fe().hp_constraints_are_implemented ())
+ internal::
+ make_hp_hanging_node_constraints (dof_handler,
+ constraints);
+ else
+ internal::
+ make_oldstyle_hanging_node_constraints (dof_handler,
+ constraints,
+ dealii::internal::int2type<DH::dimension>());
}
-}
-template <class DH, typename Number>
-void DoFTools::distribute_cell_to_dof_vector (
- const DH &dof_handler,
- const Vector<Number> &cell_data,
- Vector<double> &dof_data,
- const unsigned int component)
-{
- const Triangulation<DH::dimension> &tria = dof_handler.get_tria();
-
- Assert (cell_data.size()==tria.n_active_cells(),
- ExcWrongSize (cell_data.size(), tria.n_active_cells()));
- Assert (dof_data.size()==dof_handler.n_dofs(),
- ExcWrongSize (dof_data.size(), dof_handler.n_dofs()));
- Assert (component < n_components(dof_handler),
- ExcInvalidComponent(component, n_components(dof_handler)));
- Assert (fe_is_primitive(dof_handler) == true,
- ExcFENotPrimitive());
-
- // store a flag whether we should care
- // about different components. this is
- // just a simplification, we could ask
- // for this at every single place
- // equally well
- const bool consider_components = (n_components(dof_handler) != 1);
-
- // zero out the components that we
- // will touch
- if (consider_components == false)
- dof_data = 0;
- else
+ namespace internal
+ {
+ // this internal function assigns to each dof
+ // the respective component of the vector
+ // system. if use_blocks is set, then the
+ // assignment is done by blocks, not by
+ // components, as specified by
+ // component_select. The additional argument
+ // component_select only is used for
+ // non-primitive FEs, where we need it since
+ // more components couple, and no unique
+ // component can be assigned. Then, we sort
+ // them to the first selected component of the
+ // vector system.
+ template <class DH>
+ inline
+ void
+ extract_dofs_by_component (const DH &dof,
+ const std::vector<bool> &component_select,
+ const bool sort_by_blocks,
+ std::vector<unsigned char> &dofs_by_component)
{
- std::vector<unsigned char> component_dofs (dof_handler.n_locally_owned_dofs());
- std::vector<bool> component_mask (dof_handler.get_fe().n_components(),
- false);
- component_mask[component] = true;
- internal::extract_dofs_by_component (dof_handler, component_mask,
- false, component_dofs);
-
- for (unsigned int i=0; i<dof_data.size(); ++i)
- if (component_dofs[i] == static_cast<unsigned char>(component))
- dof_data(i) = 0;
- }
-
- // count how often we have added a value
- // in the sum for each dof
- std::vector<unsigned char> touch_count (dof_handler.n_dofs(), 0);
-
- typename DH::active_cell_iterator cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- std::vector<unsigned int> dof_indices;
- dof_indices.reserve (max_dofs_per_cell(dof_handler));
+ const dealii::hp::FECollection<DH::dimension,DH::space_dimension>
+ fe_collection (dof.get_fe());
+ Assert (fe_collection.n_components() < 256, ExcNotImplemented());
+ Assert (dofs_by_component.size() == dof.n_locally_owned_dofs(),
+ ExcDimensionMismatch(dofs_by_component.size(),
+ dof.n_locally_owned_dofs()));
+
+ // next set up a table for the
+ // degrees of freedom on each of
+ // the cells whether it is
+ // something interesting or not
+ std::vector<std::vector<unsigned char> > local_component_association
+ (fe_collection.size());
+ for (unsigned int f=0; f<fe_collection.size(); ++f)
+ {
+ const FiniteElement<DH::dimension,DH::space_dimension> &fe =
+ fe_collection[f];
+ local_component_association[f].resize(fe.dofs_per_cell);
+ if (sort_by_blocks == true)
+ {
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ local_component_association[f][i]
+ = fe.system_to_block_index(i).first;
+ }
+ else
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ if (fe.is_primitive(i))
+ local_component_association[f][i] =
+ fe.system_to_component_index(i).first;
+ else
+ // if this shape function is
+ // not primitive, then we have
+ // to work harder. we have to
+ // find out whether _any_ of
+ // the vector components of
+ // this element is selected or
+ // not
+ //
+ // to do so, get the a list of
+ // nonzero elements and see which are
+ // actually active
+ {
+ const unsigned int first_comp =
+ (std::find(fe.get_nonzero_components(i).begin(),
+ fe.get_nonzero_components(i).end(),
+ true) -
+ fe.get_nonzero_components(i).begin());
+ const unsigned int end_comp =
+ (std::find(fe.get_nonzero_components(i).begin()+first_comp,
+ fe.get_nonzero_components(i).end(),
+ false)-
+ fe.get_nonzero_components(i).begin());
+
+ // now check whether any of
+ // the components in between
+ // is set
+ if (component_select.size() == 0 ||
+ (component_select[first_comp] == true ||
+ std::count(component_select.begin()+first_comp,
+ component_select.begin()+end_comp, true) == 0))
+ local_component_association[f][i] = first_comp;
+ else
+ for (unsigned int c=first_comp; c<end_comp; ++c)
+ if (component_select[c] == true)
+ {
+ local_component_association[f][i] = c;
+ break;
+ }
+ }
+ }
- for (unsigned int present_cell = 0; cell!=endc; ++cell, ++present_cell)
- {
- const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
- dof_indices.resize (dofs_per_cell);
- cell->get_dof_indices (dof_indices);
-
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- // consider this dof only if it
- // is the right component. if there
- // is only one component, short cut
- // the test
- if (!consider_components ||
- (cell->get_fe().system_to_component_index(i).first == component))
+ // then loop over all cells and do
+ // the work
+ std::vector<unsigned int> indices;
+ for (typename DH::active_cell_iterator c=dof.begin_active();
+ c!=dof.end(); ++ c)
+ if (!c->is_artificial() && !c->is_ghost())
{
- // sum up contribution of the
- // present_cell to this dof
- dof_data(dof_indices[i]) += cell_data(present_cell);
- // note that we added another
- // summand
- ++touch_count[dof_indices[i]];
+ const unsigned int fe_index = c->active_fe_index();
+ const unsigned int dofs_per_cell = c->get_fe().dofs_per_cell;
+ indices.resize(dofs_per_cell);
+ c->get_dof_indices(indices);
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ if (dof.locally_owned_dofs().is_element(indices[i]))
+ dofs_by_component[dof.locally_owned_dofs().index_within_set(indices[i])]
+ = local_component_association[fe_index][i];
}
}
+ }
- // compute the mean value on all the
- // dofs by dividing with the number
- // of summands.
- for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
- {
- // assert that each dof was used
- // at least once. this needs not be
- // the case if the vector has more than
- // one component
- Assert (consider_components || (touch_count[i]!=0),
- ExcInternalError());
- if (touch_count[i] != 0)
- dof_data(i) /= touch_count[i];
- }
-}
+ template <class DH, typename Number>
+ void distribute_cell_to_dof_vector (
+ const DH &dof_handler,
+ const Vector<Number> &cell_data,
+ Vector<double> &dof_data,
+ const unsigned int component)
+ {
+ const Triangulation<DH::dimension> &tria = dof_handler.get_tria();
+
+ Assert (cell_data.size()==tria.n_active_cells(),
+ ExcWrongSize (cell_data.size(), tria.n_active_cells()));
+ Assert (dof_data.size()==dof_handler.n_dofs(),
+ ExcWrongSize (dof_data.size(), dof_handler.n_dofs()));
+ Assert (component < n_components(dof_handler),
+ ExcInvalidComponent(component, n_components(dof_handler)));
+ Assert (fe_is_primitive(dof_handler) == true,
+ ExcFENotPrimitive());
+
+ // store a flag whether we should care
+ // about different components. this is
+ // just a simplification, we could ask
+ // for this at every single place
+ // equally well
+ const bool consider_components = (n_components(dof_handler) != 1);
+
+ // zero out the components that we
+ // will touch
+ if (consider_components == false)
+ dof_data = 0;
+ else
+ {
+ std::vector<unsigned char> component_dofs (dof_handler.n_locally_owned_dofs());
+ std::vector<bool> component_mask (dof_handler.get_fe().n_components(),
+ false);
+ component_mask[component] = true;
+ internal::extract_dofs_by_component (dof_handler, component_mask,
+ false, component_dofs);
+
+ for (unsigned int i=0; i<dof_data.size(); ++i)
+ if (component_dofs[i] == static_cast<unsigned char>(component))
+ dof_data(i) = 0;
+ }
-template <int dim, int spacedim>
-void
-DoFTools::extract_dofs (
- const DoFHandler<dim,spacedim> &dof,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const bool count_by_blocks)
-{
- const FiniteElement<dim,spacedim> &fe = dof.get_fe();
+ // count how often we have added a value
+ // in the sum for each dof
+ std::vector<unsigned char> touch_count (dof_handler.n_dofs(), 0);
- if (count_by_blocks == true)
- {
- Assert(component_select.size() == fe.n_blocks(),
- ExcDimensionMismatch(component_select.size(), fe.n_blocks()));
- }
- else
- {
- Assert(component_select.size() == n_components(dof),
- ExcDimensionMismatch(component_select.size(), n_components(dof)));
- }
+ typename DH::active_cell_iterator cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ std::vector<unsigned int> dof_indices;
+ dof_indices.reserve (max_dofs_per_cell(dof_handler));
- Assert(selected_dofs.size() == dof.n_locally_owned_dofs(),
- ExcDimensionMismatch(selected_dofs.size(), dof.n_locally_owned_dofs()));
+ for (unsigned int present_cell = 0; cell!=endc; ++cell, ++present_cell)
+ {
+ const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
+ dof_indices.resize (dofs_per_cell);
+ cell->get_dof_indices (dof_indices);
- // two special cases: no component
- // is selected, and all components
- // are selected; both rather
- // stupid, but easy to catch
- if (std::count (component_select.begin(), component_select.end(), true)
- == 0)
- {
- std::fill_n (selected_dofs.begin(), dof.n_locally_owned_dofs(), false);
- return;
- }
- else if (std::count (component_select.begin(), component_select.end(), true)
- == static_cast<signed int>(component_select.size()))
- {
- std::fill_n (selected_dofs.begin(), dof.n_locally_owned_dofs(), true);
- return;
- }
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ // consider this dof only if it
+ // is the right component. if there
+ // is only one component, short cut
+ // the test
+ if (!consider_components ||
+ (cell->get_fe().system_to_component_index(i).first == component))
+ {
+ // sum up contribution of the
+ // present_cell to this dof
+ dof_data(dof_indices[i]) += cell_data(present_cell);
+ // note that we added another
+ // summand
+ ++touch_count[dof_indices[i]];
+ }
+ }
+ // compute the mean value on all the
+ // dofs by dividing with the number
+ // of summands.
+ for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
+ {
+ // assert that each dof was used
+ // at least once. this needs not be
+ // the case if the vector has more than
+ // one component
+ Assert (consider_components || (touch_count[i]!=0),
+ ExcInternalError());
+ if (touch_count[i] != 0)
+ dof_data(i) /= touch_count[i];
+ }
+ }
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof.n_locally_owned_dofs(), false);
- // if we count by blocks, we need to extract
- // the association of blocks with local dofs,
- // and then go through all the cells and set
- // the properties according to this
- // info. Otherwise, we let the function
- // extract_dofs_by_component function do the
- // job.
- std::vector<unsigned char> dofs_by_component (dof.n_locally_owned_dofs());
- internal::extract_dofs_by_component (dof, component_select, count_by_blocks,
- dofs_by_component);
- for (unsigned int i=0; i<dof.n_locally_owned_dofs(); ++i)
- if (component_select[dofs_by_component[i]] == true)
- selected_dofs[i] = true;
-}
+ template <int dim, int spacedim>
+ void
+ extract_dofs (
+ const DoFHandler<dim,spacedim> &dof,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const bool count_by_blocks)
+ {
+ const FiniteElement<dim,spacedim> &fe = dof.get_fe();
+ if (count_by_blocks == true)
+ {
+ Assert(component_select.size() == fe.n_blocks(),
+ ExcDimensionMismatch(component_select.size(), fe.n_blocks()));
+ }
+ else
+ {
+ Assert(component_select.size() == n_components(dof),
+ ExcDimensionMismatch(component_select.size(), n_components(dof)));
+ }
+ Assert(selected_dofs.size() == dof.n_locally_owned_dofs(),
+ ExcDimensionMismatch(selected_dofs.size(), dof.n_locally_owned_dofs()));
-template <int dim, int spacedim>
-void
-DoFTools::extract_dofs (
- const hp::DoFHandler<dim,spacedim> &dof,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const bool count_by_blocks)
-{
- const FiniteElement<dim,spacedim> &fe = dof.begin_active()->get_fe();
+ // two special cases: no component
+ // is selected, and all components
+ // are selected; both rather
+ // stupid, but easy to catch
+ if (std::count (component_select.begin(), component_select.end(), true)
+ == 0)
+ {
+ std::fill_n (selected_dofs.begin(), dof.n_locally_owned_dofs(), false);
+ return;
+ }
+ else if (std::count (component_select.begin(), component_select.end(), true)
+ == static_cast<signed int>(component_select.size()))
+ {
+ std::fill_n (selected_dofs.begin(), dof.n_locally_owned_dofs(), true);
+ return;
+ }
- if (count_by_blocks == true)
- {
- Assert(component_select.size() == fe.n_blocks(),
- ExcDimensionMismatch(component_select.size(), fe.n_blocks()));
- }
- else
- {
- Assert(component_select.size() == n_components(dof),
- ExcDimensionMismatch(component_select.size(), n_components(dof)));
- }
- Assert(selected_dofs.size() == dof.n_dofs(),
- ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs()));
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof.n_locally_owned_dofs(), false);
- // two special cases: no component
- // is selected, and all components
- // are selected; both rather
- // stupid, but easy to catch
- if (std::count (component_select.begin(), component_select.end(), true)
- == 0)
- {
- std::fill_n (selected_dofs.begin(), dof.n_dofs(), false);
- return;
- };
- if (std::count (component_select.begin(), component_select.end(), true)
- == static_cast<signed int>(component_select.size()))
- {
- std::fill_n (selected_dofs.begin(), dof.n_dofs(), true);
- return;
- };
-
-
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof.n_dofs(), false);
-
- // if we count by blocks, we need to extract
- // the association of blocks with local dofs,
- // and then go through all the cells and set
- // the properties according to this
- // info. Otherwise, we let the function
- // extract_dofs_by_component function do the
- // job.
- std::vector<unsigned char> dofs_by_component (dof.n_dofs());
- internal::extract_dofs_by_component (dof, component_select, count_by_blocks,
- dofs_by_component);
-
- for (unsigned int i=0; i<dof.n_dofs(); ++i)
- if (component_select[dofs_by_component[i]] == true)
- selected_dofs[i] = true;
-}
+ // if we count by blocks, we need to extract
+ // the association of blocks with local dofs,
+ // and then go through all the cells and set
+ // the properties according to this
+ // info. Otherwise, we let the function
+ // extract_dofs_by_component function do the
+ // job.
+ std::vector<unsigned char> dofs_by_component (dof.n_locally_owned_dofs());
+ internal::extract_dofs_by_component (dof, component_select, count_by_blocks,
+ dofs_by_component);
+ for (unsigned int i=0; i<dof.n_locally_owned_dofs(); ++i)
+ if (component_select[dofs_by_component[i]] == true)
+ selected_dofs[i] = true;
+ }
-template<int dim, int spacedim>
-void
-DoFTools::extract_level_dofs(
- const unsigned int level,
- const MGDoFHandler<dim,spacedim> &dof,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const bool count_by_blocks)
-{
- const FiniteElement<dim,spacedim>& fe = dof.get_fe();
- if (count_by_blocks == true)
- {
- Assert(component_select.size() == fe.n_blocks(),
- ExcDimensionMismatch(component_select.size(), fe.n_blocks()));
- }
- else
- {
- Assert(component_select.size() == fe.n_components(),
- ExcDimensionMismatch(component_select.size(), fe.n_components()));
- }
+ template <int dim, int spacedim>
+ void
+ extract_dofs (
+ const hp::DoFHandler<dim,spacedim> &dof,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const bool count_by_blocks)
+ {
+ const FiniteElement<dim,spacedim> &fe = dof.begin_active()->get_fe();
- Assert(selected_dofs.size() == dof.n_dofs(level),
- ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs(level)));
+ if (count_by_blocks == true)
+ {
+ Assert(component_select.size() == fe.n_blocks(),
+ ExcDimensionMismatch(component_select.size(), fe.n_blocks()));
+ }
+ else
+ {
+ Assert(component_select.size() == n_components(dof),
+ ExcDimensionMismatch(component_select.size(), n_components(dof)));
+ }
- // two special cases: no component
- // is selected, and all components
- // are selected, both rather
- // stupid, but easy to catch
- if (std::count (component_select.begin(), component_select.end(), true)
- == 0)
- {
- std::fill_n (selected_dofs.begin(), dof.n_dofs(level), false);
- return;
- };
- if (std::count (component_select.begin(), component_select.end(), true)
- == static_cast<signed int>(component_select.size()))
- {
- std::fill_n (selected_dofs.begin(), dof.n_dofs(level), true);
- return;
- };
+ Assert(selected_dofs.size() == dof.n_dofs(),
+ ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs()));
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof.n_dofs(level), false);
+ // two special cases: no component
+ // is selected, and all components
+ // are selected; both rather
+ // stupid, but easy to catch
+ if (std::count (component_select.begin(), component_select.end(), true)
+ == 0)
+ {
+ std::fill_n (selected_dofs.begin(), dof.n_dofs(), false);
+ return;
+ };
+ if (std::count (component_select.begin(), component_select.end(), true)
+ == static_cast<signed int>(component_select.size()))
+ {
+ std::fill_n (selected_dofs.begin(), dof.n_dofs(), true);
+ return;
+ };
- // next set up a table for the
- // degrees of freedom on each of
- // the cells whether it is
- // something interesting or not
- std::vector<bool> local_selected_dofs (fe.dofs_per_cell, false);
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- if (count_by_blocks == true)
- local_selected_dofs[i]
- = component_select[fe.system_to_block_index(i).first];
- else
- if (fe.is_primitive(i))
- local_selected_dofs[i]
- = component_select[fe.system_to_component_index(i).first];
- else
- // if this shape function is
- // not primitive, then we have
- // to work harder. we have to
- // find out whether _any_ of
- // the vector components of
- // this element is selected or
- // not
- //
- // to do so, get the first and
- // last vector components of
- // the base element to which
- // the local dof with index i
- // belongs
- {
- unsigned int first_comp = 0;
- const unsigned int this_base = fe.system_to_base_index(i).first.first;
- const unsigned int this_multiplicity
- = fe.system_to_base_index(i).first.second;
-
- for (unsigned int b=0; b<this_base; ++b)
- first_comp += fe.base_element(b).n_components() *
- fe.element_multiplicity(b);
- for (unsigned int m=0; m<this_multiplicity; ++m)
- first_comp += fe.base_element(this_base).n_components();
- const unsigned int end_comp = first_comp +
- fe.base_element(this_base).n_components();
-
- Assert (first_comp < fe.n_components(), ExcInternalError());
- Assert (end_comp <= fe.n_components(), ExcInternalError());
-
- // now check whether any of
- // the components in between
- // is set
- for (unsigned int c=first_comp; c<end_comp; ++c)
- if (component_select[c] == true)
- {
- local_selected_dofs[i] = true;
- break;
- }
- }
- // then loop over all cells and do
- // work
- std::vector<unsigned int> indices(fe.dofs_per_cell);
- typename MGDoFHandler<dim,spacedim>::cell_iterator c;
- for (c = dof.begin(level) ; c != dof.end(level) ; ++ c)
- {
- c->get_mg_dof_indices(indices);
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- selected_dofs[indices[i]] = local_selected_dofs[i];
- }
-}
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof.n_dofs(), false);
+ // if we count by blocks, we need to extract
+ // the association of blocks with local dofs,
+ // and then go through all the cells and set
+ // the properties according to this
+ // info. Otherwise, we let the function
+ // extract_dofs_by_component function do the
+ // job.
+ std::vector<unsigned char> dofs_by_component (dof.n_dofs());
+ internal::extract_dofs_by_component (dof, component_select, count_by_blocks,
+ dofs_by_component);
+ for (unsigned int i=0; i<dof.n_dofs(); ++i)
+ if (component_select[dofs_by_component[i]] == true)
+ selected_dofs[i] = true;
+ }
-template <class DH>
-void
-DoFTools::extract_boundary_dofs (const DH &dof_handler,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const std::set<unsigned char> &boundary_indicators)
-{
- Assert (component_select.size() == n_components(dof_handler),
- ExcWrongSize (component_select.size(),
- n_components(dof_handler)));
- Assert (boundary_indicators.find (255) == boundary_indicators.end(),
- ExcInvalidBoundaryIndicator());
- const unsigned int dim=DH::dimension;
-
- // let's see whether we have to
- // check for certain boundary
- // indicators or whether we can
- // accept all
- const bool check_boundary_indicator = (boundary_indicators.size() != 0);
-
- // also see whether we have to
- // check whether a certain vector
- // component is selected, or all
- const bool check_vector_component
- = (component_select != std::vector<bool>(component_select.size(),
- true));
-
- // clear and reset array by default
- // values
- selected_dofs.clear ();
- selected_dofs.resize (dof_handler.n_dofs(), false);
- std::vector<unsigned int> face_dof_indices;
- face_dof_indices.reserve (max_dofs_per_face(dof_handler));
-
- // now loop over all cells and
- // check whether their faces are at
- // the boundary. note that we need
- // not take special care of single
- // lines being at the boundary
- // (using
- // @p{cell->has_boundary_lines}),
- // since we do not support
- // boundaries of dimension dim-2,
- // and so every isolated boundary
- // line is also part of a boundary
- // face which we will be visiting
- // sooner or later
- for (typename DH::active_cell_iterator cell=dof_handler.begin_active();
- cell!=dof_handler.end(); ++cell)
- for (unsigned int face=0;
- face<GeometryInfo<DH::dimension>::faces_per_cell; ++face)
- if (cell->at_boundary(face))
- if (! check_boundary_indicator ||
- (boundary_indicators.find (cell->face(face)->boundary_indicator())
- != boundary_indicators.end()))
- {
- const FiniteElement<DH::dimension> &fe = cell->get_fe();
-
- const unsigned int dofs_per_face = fe.dofs_per_face;
- face_dof_indices.resize (dofs_per_face);
- cell->face(face)->get_dof_indices (face_dof_indices,
- cell->active_fe_index());
-
- for (unsigned int i=0; i<fe.dofs_per_face; ++i)
- if (!check_vector_component)
- selected_dofs[face_dof_indices[i]] = true;
- else
- // check for
- // component is
- // required. somewhat
- // tricky as usual
- // for the case that
- // the shape function
- // is non-primitive,
- // but use usual
- // convention (see
- // docs)
- {
- // first get at the
- // cell-global
- // number of a face
- // dof, to ask the
- // fe certain
- // questions
- const unsigned int cell_index
- = (dim == 1 ?
- i
- :
- (dim == 2 ?
- (i<2*fe.dofs_per_vertex ? i : i+2*fe.dofs_per_vertex)
- :
- (dim == 3 ?
- (i<4*fe.dofs_per_vertex ?
- i
- :
- (i<4*fe.dofs_per_vertex+4*fe.dofs_per_line ?
- i+4*fe.dofs_per_vertex
- :
- i+4*fe.dofs_per_vertex+8*fe.dofs_per_line))
- :
- numbers::invalid_unsigned_int)));
- if (fe.is_primitive (cell_index))
- selected_dofs[face_dof_indices[i]]
- = (component_select[fe.face_system_to_component_index(i).first]
- == true);
- else // not primitive
- {
- const unsigned int first_nonzero_comp
- = (std::find (fe.get_nonzero_components(cell_index).begin(),
- fe.get_nonzero_components(cell_index).end(),
- true)
- -
- fe.get_nonzero_components(cell_index).begin());
- Assert (first_nonzero_comp < fe.n_components(),
- ExcInternalError());
-
- selected_dofs[face_dof_indices[i]]
- = (component_select[first_nonzero_comp]
- == true);
- }
- }
- }
-}
+ template<int dim, int spacedim>
+ void
+ extract_level_dofs(
+ const unsigned int level,
+ const MGDoFHandler<dim,spacedim> &dof,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const bool count_by_blocks)
+ {
+ const FiniteElement<dim,spacedim>& fe = dof.get_fe();
-template <class DH>
-void
-DoFTools::extract_dofs_with_support_on_boundary (const DH &dof_handler,
- const std::vector<bool> &component_select,
- std::vector<bool> &selected_dofs,
- const std::set<unsigned char> &boundary_indicators)
-{
- Assert (component_select.size() == n_components(dof_handler),
- ExcWrongSize (component_select.size(),
- n_components(dof_handler)));
- Assert (boundary_indicators.find (255) == boundary_indicators.end(),
- ExcInvalidBoundaryIndicator());
-
- // let's see whether we have to
- // check for certain boundary
- // indicators or whether we can
- // accept all
- const bool check_boundary_indicator = (boundary_indicators.size() != 0);
-
- // also see whether we have to
- // check whether a certain vector
- // component is selected, or all
- const bool check_vector_component
- = (component_select != std::vector<bool>(component_select.size(),
- true));
-
- // clear and reset array by default
- // values
- selected_dofs.clear ();
- selected_dofs.resize (dof_handler.n_dofs(), false);
- std::vector<unsigned int> cell_dof_indices;
- cell_dof_indices.reserve (max_dofs_per_cell(dof_handler));
-
- // now loop over all cells and
- // check whether their faces are at
- // the boundary. note that we need
- // not take special care of single
- // lines being at the boundary
- // (using
- // @p{cell->has_boundary_lines}),
- // since we do not support
- // boundaries of dimension dim-2,
- // and so every isolated boundary
- // line is also part of a boundary
- // face which we will be visiting
- // sooner or later
- for (typename DH::active_cell_iterator cell=dof_handler.begin_active();
- cell!=dof_handler.end(); ++cell)
- for (unsigned int face=0;
- face<GeometryInfo<DH::dimension>::faces_per_cell; ++face)
- if (cell->at_boundary(face))
- if (! check_boundary_indicator ||
- (boundary_indicators.find (cell->face(face)->boundary_indicator())
- != boundary_indicators.end()))
- {
- const FiniteElement<DH::dimension> &fe = cell->get_fe();
+ if (count_by_blocks == true)
+ {
+ Assert(component_select.size() == fe.n_blocks(),
+ ExcDimensionMismatch(component_select.size(), fe.n_blocks()));
+ }
+ else
+ {
+ Assert(component_select.size() == fe.n_components(),
+ ExcDimensionMismatch(component_select.size(), fe.n_components()));
+ }
- const unsigned int dofs_per_cell = fe.dofs_per_cell;
- cell_dof_indices.resize (dofs_per_cell);
- cell->get_dof_indices (cell_dof_indices);
+ Assert(selected_dofs.size() == dof.n_dofs(level),
+ ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs(level)));
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- if (fe.has_support_on_face(i,face))
- {
- if (!check_vector_component)
- selected_dofs[cell_dof_indices[i]] = true;
- else
- // check for
- // component is
- // required. somewhat
- // tricky as usual
- // for the case that
- // the shape function
- // is non-primitive,
- // but use usual
- // convention (see
- // docs)
- {
- if (fe.is_primitive (i))
- selected_dofs[cell_dof_indices[i]]
- = (component_select[fe.system_to_component_index(i).first]
- == true);
- else // not primitive
- {
- const unsigned int first_nonzero_comp
- = (std::find (fe.get_nonzero_components(i).begin(),
- fe.get_nonzero_components(i).end(),
- true)
- -
- fe.get_nonzero_components(i).begin());
- Assert (first_nonzero_comp < fe.n_components(),
- ExcInternalError());
+ // two special cases: no component
+ // is selected, and all components
+ // are selected, both rather
+ // stupid, but easy to catch
+ if (std::count (component_select.begin(), component_select.end(), true)
+ == 0)
+ {
+ std::fill_n (selected_dofs.begin(), dof.n_dofs(level), false);
+ return;
+ };
+ if (std::count (component_select.begin(), component_select.end(), true)
+ == static_cast<signed int>(component_select.size()))
+ {
+ std::fill_n (selected_dofs.begin(), dof.n_dofs(level), true);
+ return;
+ };
- selected_dofs[cell_dof_indices[i]]
- = (component_select[first_nonzero_comp]
- == true);
- }
- }
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof.n_dofs(level), false);
+
+ // next set up a table for the
+ // degrees of freedom on each of
+ // the cells whether it is
+ // something interesting or not
+ std::vector<bool> local_selected_dofs (fe.dofs_per_cell, false);
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ if (count_by_blocks == true)
+ local_selected_dofs[i]
+ = component_select[fe.system_to_block_index(i).first];
+ else
+ if (fe.is_primitive(i))
+ local_selected_dofs[i]
+ = component_select[fe.system_to_component_index(i).first];
+ else
+ // if this shape function is
+ // not primitive, then we have
+ // to work harder. we have to
+ // find out whether _any_ of
+ // the vector components of
+ // this element is selected or
+ // not
+ //
+ // to do so, get the first and
+ // last vector components of
+ // the base element to which
+ // the local dof with index i
+ // belongs
+ {
+ unsigned int first_comp = 0;
+ const unsigned int this_base = fe.system_to_base_index(i).first.first;
+ const unsigned int this_multiplicity
+ = fe.system_to_base_index(i).first.second;
+
+ for (unsigned int b=0; b<this_base; ++b)
+ first_comp += fe.base_element(b).n_components() *
+ fe.element_multiplicity(b);
+ for (unsigned int m=0; m<this_multiplicity; ++m)
+ first_comp += fe.base_element(this_base).n_components();
+ const unsigned int end_comp = first_comp +
+ fe.base_element(this_base).n_components();
+
+ Assert (first_comp < fe.n_components(), ExcInternalError());
+ Assert (end_comp <= fe.n_components(), ExcInternalError());
+
+ // now check whether any of
+ // the components in between
+ // is set
+ for (unsigned int c=first_comp; c<end_comp; ++c)
+ if (component_select[c] == true)
+ {
+ local_selected_dofs[i] = true;
+ break;
}
}
-}
+ // then loop over all cells and do
+ // work
+ std::vector<unsigned int> indices(fe.dofs_per_cell);
+ typename MGDoFHandler<dim,spacedim>::cell_iterator c;
+ for (c = dof.begin(level) ; c != dof.end(level) ; ++ c)
+ {
+ c->get_mg_dof_indices(indices);
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ selected_dofs[indices[i]] = local_selected_dofs[i];
+ }
+ }
-namespace internal
-{
- namespace DoFTools
+ template <class DH>
+ void
+ extract_boundary_dofs (const DH &dof_handler,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const std::set<unsigned char> &boundary_indicators)
{
- template <int spacedim>
- void extract_hanging_node_dofs (const dealii::DoFHandler<1,spacedim> &dof_handler,
- std::vector<bool> &selected_dofs)
- {
- Assert(selected_dofs.size() == dof_handler.n_dofs(),
- ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
-
- // there are no hanging nodes in 1d
- }
+ Assert (component_select.size() == n_components(dof_handler),
+ ExcWrongSize (component_select.size(),
+ n_components(dof_handler)));
+ Assert (boundary_indicators.find (255) == boundary_indicators.end(),
+ ExcInvalidBoundaryIndicator());
+ const unsigned int dim=DH::dimension;
+
+ // let's see whether we have to
+ // check for certain boundary
+ // indicators or whether we can
+ // accept all
+ const bool check_boundary_indicator = (boundary_indicators.size() != 0);
+
+ // also see whether we have to
+ // check whether a certain vector
+ // component is selected, or all
+ const bool check_vector_component
+ = (component_select != std::vector<bool>(component_select.size(),
+ true));
+
+ // clear and reset array by default
+ // values
+ selected_dofs.clear ();
+ selected_dofs.resize (dof_handler.n_dofs(), false);
+ std::vector<unsigned int> face_dof_indices;
+ face_dof_indices.reserve (max_dofs_per_face(dof_handler));
+
+ // now loop over all cells and
+ // check whether their faces are at
+ // the boundary. note that we need
+ // not take special care of single
+ // lines being at the boundary
+ // (using
+ // @p{cell->has_boundary_lines}),
+ // since we do not support
+ // boundaries of dimension dim-2,
+ // and so every isolated boundary
+ // line is also part of a boundary
+ // face which we will be visiting
+ // sooner or later
+ for (typename DH::active_cell_iterator cell=dof_handler.begin_active();
+ cell!=dof_handler.end(); ++cell)
+ for (unsigned int face=0;
+ face<GeometryInfo<DH::dimension>::faces_per_cell; ++face)
+ if (cell->at_boundary(face))
+ if (! check_boundary_indicator ||
+ (boundary_indicators.find (cell->face(face)->boundary_indicator())
+ != boundary_indicators.end()))
+ {
+ const FiniteElement<DH::dimension> &fe = cell->get_fe();
+ const unsigned int dofs_per_face = fe.dofs_per_face;
+ face_dof_indices.resize (dofs_per_face);
+ cell->face(face)->get_dof_indices (face_dof_indices,
+ cell->active_fe_index());
- template <int spacedim>
- void extract_hanging_node_dofs (const dealii::DoFHandler<2,spacedim> &dof_handler,
- std::vector<bool> &selected_dofs)
- {
- const unsigned int dim = 2;
+ for (unsigned int i=0; i<fe.dofs_per_face; ++i)
+ if (!check_vector_component)
+ selected_dofs[face_dof_indices[i]] = true;
+ else
+ // check for
+ // component is
+ // required. somewhat
+ // tricky as usual
+ // for the case that
+ // the shape function
+ // is non-primitive,
+ // but use usual
+ // convention (see
+ // docs)
+ {
+ // first get at the
+ // cell-global
+ // number of a face
+ // dof, to ask the
+ // fe certain
+ // questions
+ const unsigned int cell_index
+ = (dim == 1 ?
+ i
+ :
+ (dim == 2 ?
+ (i<2*fe.dofs_per_vertex ? i : i+2*fe.dofs_per_vertex)
+ :
+ (dim == 3 ?
+ (i<4*fe.dofs_per_vertex ?
+ i
+ :
+ (i<4*fe.dofs_per_vertex+4*fe.dofs_per_line ?
+ i+4*fe.dofs_per_vertex
+ :
+ i+4*fe.dofs_per_vertex+8*fe.dofs_per_line))
+ :
+ numbers::invalid_unsigned_int)));
+ if (fe.is_primitive (cell_index))
+ selected_dofs[face_dof_indices[i]]
+ = (component_select[fe.face_system_to_component_index(i).first]
+ == true);
+ else // not primitive
+ {
+ const unsigned int first_nonzero_comp
+ = (std::find (fe.get_nonzero_components(cell_index).begin(),
+ fe.get_nonzero_components(cell_index).end(),
+ true)
+ -
+ fe.get_nonzero_components(cell_index).begin());
+ Assert (first_nonzero_comp < fe.n_components(),
+ ExcInternalError());
+
+ selected_dofs[face_dof_indices[i]]
+ = (component_select[first_nonzero_comp]
+ == true);
+ }
+ }
+ }
+ }
- Assert(selected_dofs.size() == dof_handler.n_dofs(),
- ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
- const FiniteElement<dim,spacedim> &fe = dof_handler.get_fe();
- // this function is similar to the
- // make_sparsity_pattern function,
- // see there for more information
- typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if (cell->face(face)->has_children())
+ template <class DH>
+ void
+ extract_dofs_with_support_on_boundary (const DH &dof_handler,
+ const std::vector<bool> &component_select,
+ std::vector<bool> &selected_dofs,
+ const std::set<unsigned char> &boundary_indicators)
+ {
+ Assert (component_select.size() == n_components(dof_handler),
+ ExcWrongSize (component_select.size(),
+ n_components(dof_handler)));
+ Assert (boundary_indicators.find (255) == boundary_indicators.end(),
+ ExcInvalidBoundaryIndicator());
+
+ // let's see whether we have to
+ // check for certain boundary
+ // indicators or whether we can
+ // accept all
+ const bool check_boundary_indicator = (boundary_indicators.size() != 0);
+
+ // also see whether we have to
+ // check whether a certain vector
+ // component is selected, or all
+ const bool check_vector_component
+ = (component_select != std::vector<bool>(component_select.size(),
+ true));
+
+ // clear and reset array by default
+ // values
+ selected_dofs.clear ();
+ selected_dofs.resize (dof_handler.n_dofs(), false);
+ std::vector<unsigned int> cell_dof_indices;
+ cell_dof_indices.reserve (max_dofs_per_cell(dof_handler));
+
+ // now loop over all cells and
+ // check whether their faces are at
+ // the boundary. note that we need
+ // not take special care of single
+ // lines being at the boundary
+ // (using
+ // @p{cell->has_boundary_lines}),
+ // since we do not support
+ // boundaries of dimension dim-2,
+ // and so every isolated boundary
+ // line is also part of a boundary
+ // face which we will be visiting
+ // sooner or later
+ for (typename DH::active_cell_iterator cell=dof_handler.begin_active();
+ cell!=dof_handler.end(); ++cell)
+ for (unsigned int face=0;
+ face<GeometryInfo<DH::dimension>::faces_per_cell; ++face)
+ if (cell->at_boundary(face))
+ if (! check_boundary_indicator ||
+ (boundary_indicators.find (cell->face(face)->boundary_indicator())
+ != boundary_indicators.end()))
{
- const typename dealii::DoFHandler<dim,spacedim>::line_iterator
- line = cell->face(face);
+ const FiniteElement<DH::dimension> &fe = cell->get_fe();
- for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof)
- selected_dofs[line->child(0)->vertex_dof_index(1,dof)] = true;
+ const unsigned int dofs_per_cell = fe.dofs_per_cell;
+ cell_dof_indices.resize (dofs_per_cell);
+ cell->get_dof_indices (cell_dof_indices);
- for (unsigned int child=0; child<2; ++child)
- for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof)
- selected_dofs[line->child(child)->dof_index(dof)] = true;
+ for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+ if (fe.has_support_on_face(i,face))
+ {
+ if (!check_vector_component)
+ selected_dofs[cell_dof_indices[i]] = true;
+ else
+ // check for
+ // component is
+ // required. somewhat
+ // tricky as usual
+ // for the case that
+ // the shape function
+ // is non-primitive,
+ // but use usual
+ // convention (see
+ // docs)
+ {
+ if (fe.is_primitive (i))
+ selected_dofs[cell_dof_indices[i]]
+ = (component_select[fe.system_to_component_index(i).first]
+ == true);
+ else // not primitive
+ {
+ const unsigned int first_nonzero_comp
+ = (std::find (fe.get_nonzero_components(i).begin(),
+ fe.get_nonzero_components(i).end(),
+ true)
+ -
+ fe.get_nonzero_components(i).begin());
+ Assert (first_nonzero_comp < fe.n_components(),
+ ExcInternalError());
+
+ selected_dofs[cell_dof_indices[i]]
+ = (component_select[first_nonzero_comp]
+ == true);
+ }
+ }
+ }
}
- }
+ }
- template <int spacedim>
- void extract_hanging_node_dofs (const dealii::DoFHandler<3,spacedim> &dof_handler,
- std::vector<bool> &selected_dofs)
- {
- const unsigned int dim = 3;
- Assert(selected_dofs.size() == dof_handler.n_dofs(),
- ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
- const FiniteElement<dim,spacedim> &fe = dof_handler.get_fe();
+ namespace internal
+ {
+ namespace
+ {
+ template <int spacedim>
+ void extract_hanging_node_dofs (const dealii::DoFHandler<1,spacedim> &dof_handler,
+ std::vector<bool> &selected_dofs)
+ {
+ Assert(selected_dofs.size() == dof_handler.n_dofs(),
+ ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
- // this function is similar to the
- // make_sparsity_pattern function,
- // see there for more information
+ // there are no hanging nodes in 1d
+ }
- typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
- if (cell->face(f)->has_children())
- {
- const typename dealii::DoFHandler<dim,spacedim>::face_iterator
- face = cell->face(f);
- for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof)
- selected_dofs[face->child(0)->vertex_dof_index(2,dof)] = true;
+ template <int spacedim>
+ void extract_hanging_node_dofs (const dealii::DoFHandler<2,spacedim> &dof_handler,
+ std::vector<bool> &selected_dofs)
+ {
+ const unsigned int dim = 2;
+
+ Assert(selected_dofs.size() == dof_handler.n_dofs(),
+ ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
+
+ const FiniteElement<dim,spacedim> &fe = dof_handler.get_fe();
+
+ // this function is similar to the
+ // make_sparsity_pattern function,
+ // see there for more information
+ typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
+ if (cell->face(face)->has_children())
+ {
+ const typename dealii::DoFHandler<dim,spacedim>::line_iterator
+ line = cell->face(face);
- // dof numbers on the centers of
- // the lines bounding this face
- for (unsigned int line=0; line<4; ++line)
for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof)
- selected_dofs[face->line(line)->child(0)->vertex_dof_index(1,dof)] = true;
-
- // next the dofs on the lines interior
- // to the face; the order of these
- // lines is laid down in the
- // FiniteElement class documentation
- for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
- selected_dofs[face->child(0)->line(1)->dof_index(dof)] = true;
- for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
- selected_dofs[face->child(1)->line(2)->dof_index(dof)] = true;
- for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
- selected_dofs[face->child(2)->line(3)->dof_index(dof)] = true;
- for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
- selected_dofs[face->child(3)->line(0)->dof_index(dof)] = true;
-
- // dofs on the bordering lines
- for (unsigned int line=0; line<4; ++line)
+ selected_dofs[line->child(0)->vertex_dof_index(1,dof)] = true;
+
for (unsigned int child=0; child<2; ++child)
for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof)
- selected_dofs[face->line(line)->child(child)->dof_index(dof)] = true;
-
- // finally, for the dofs interior
- // to the four child faces
- for (unsigned int child=0; child<4; ++child)
- for (unsigned int dof=0; dof!=fe.dofs_per_quad; ++dof)
- selected_dofs[face->child(child)->dof_index(dof)] = true;
- }
- }
- }
-}
-
+ selected_dofs[line->child(child)->dof_index(dof)] = true;
+ }
+ }
-template <int dim, int spacedim>
-void
-DoFTools::
-extract_hanging_node_dofs (const DoFHandler<dim,spacedim> &dof_handler,
- std::vector<bool> &selected_dofs)
-{
- internal::DoFTools::extract_hanging_node_dofs (dof_handler,
- selected_dofs);
-}
+ template <int spacedim>
+ void extract_hanging_node_dofs (const dealii::DoFHandler<3,spacedim> &dof_handler,
+ std::vector<bool> &selected_dofs)
+ {
+ const unsigned int dim = 3;
+ Assert(selected_dofs.size() == dof_handler.n_dofs(),
+ ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
+ const FiniteElement<dim,spacedim> &fe = dof_handler.get_fe();
-template <class DH>
-void
-DoFTools::extract_subdomain_dofs (const DH &dof_handler,
- const types::subdomain_id_t subdomain_id,
- std::vector<bool> &selected_dofs)
-{
- Assert(selected_dofs.size() == dof_handler.n_dofs(),
- ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
-
- // preset all values by false
- std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
-
- std::vector<unsigned int> local_dof_indices;
- local_dof_indices.reserve (max_dofs_per_cell(dof_handler));
-
- // this function is similar to the
- // make_sparsity_pattern function,
- // see there for more information
- typename DH::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- if (cell->subdomain_id() == subdomain_id)
- {
- const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
- local_dof_indices.resize (dofs_per_cell);
- cell->get_dof_indices (local_dof_indices);
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- selected_dofs[local_dof_indices[i]] = true;
- };
-}
+ // this function is similar to the
+ // make_sparsity_pattern function,
+ // see there for more information
+ typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
+ if (cell->face(f)->has_children())
+ {
+ const typename dealii::DoFHandler<dim,spacedim>::face_iterator
+ face = cell->face(f);
+ for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof)
+ selected_dofs[face->child(0)->vertex_dof_index(2,dof)] = true;
-template <class DH>
-void
-DoFTools::extract_locally_owned_dofs (const DH & dof_handler,
- IndexSet & dof_set)
-{
- // collect all the locally owned dofs
- dof_set = dof_handler.locally_owned_dofs();
- dof_set.compress ();
-}
+ // dof numbers on the centers of
+ // the lines bounding this face
+ for (unsigned int line=0; line<4; ++line)
+ for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof)
+ selected_dofs[face->line(line)->child(0)->vertex_dof_index(1,dof)] = true;
+ // next the dofs on the lines interior
+ // to the face; the order of these
+ // lines is laid down in the
+ // FiniteElement class documentation
+ for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
+ selected_dofs[face->child(0)->line(1)->dof_index(dof)] = true;
+ for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
+ selected_dofs[face->child(1)->line(2)->dof_index(dof)] = true;
+ for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
+ selected_dofs[face->child(2)->line(3)->dof_index(dof)] = true;
+ for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof)
+ selected_dofs[face->child(3)->line(0)->dof_index(dof)] = true;
+ // dofs on the bordering lines
+ for (unsigned int line=0; line<4; ++line)
+ for (unsigned int child=0; child<2; ++child)
+ for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof)
+ selected_dofs[face->line(line)->child(child)->dof_index(dof)] = true;
-template <class DH>
-void
-DoFTools::extract_locally_active_dofs (const DH & dof_handler,
- IndexSet & dof_set)
-{
- // collect all the locally owned dofs
- dof_set = dof_handler.locally_owned_dofs();
-
- // add the DoF on the adjacent ghost cells
- // to the IndexSet, cache them in a
- // set. need to check each dof manually
- // because we can't be sure that the dof
- // range of locally_owned_dofs is really
- // contiguous.
- std::vector<unsigned int> dof_indices;
- std::set<unsigned int> global_dof_indices;
-
- typename DH::active_cell_iterator cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- if (!cell->is_ghost() && !cell->is_artificial())
- {
- dof_indices.resize(cell->get_fe().dofs_per_cell);
- cell->get_dof_indices(dof_indices);
-
- for (std::vector<unsigned int>::iterator it=dof_indices.begin();
- it!=dof_indices.end();
- ++it)
- if (!dof_set.is_element(*it))
- global_dof_indices.insert(*it);
+ // finally, for the dofs interior
+ // to the four child faces
+ for (unsigned int child=0; child<4; ++child)
+ for (unsigned int dof=0; dof!=fe.dofs_per_quad; ++dof)
+ selected_dofs[face->child(child)->dof_index(dof)] = true;
+ }
}
+ }
+ }
- dof_set.add_indices(global_dof_indices.begin(), global_dof_indices.end());
- dof_set.compress();
-}
+
+ template <int dim, int spacedim>
+ void
+
+ extract_hanging_node_dofs (const DoFHandler<dim,spacedim> &dof_handler,
+ std::vector<bool> &selected_dofs)
+ {
+ internal::extract_hanging_node_dofs (dof_handler,
+ selected_dofs);
+ }
-template <class DH>
-void
-DoFTools::extract_locally_relevant_dofs (const DH & dof_handler,
- IndexSet & dof_set)
-{
- // collect all the locally owned dofs
- dof_set = dof_handler.locally_owned_dofs();
-
- // add the DoF on the adjacent ghost cells
- // to the IndexSet, cache them in a
- // set. need to check each dof manually
- // because we can't be sure that the dof
- // range of locally_owned_dofs is really
- // contiguous.
- std::vector<unsigned int> dof_indices;
- std::set<unsigned int> global_dof_indices;
-
- typename DH::active_cell_iterator cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- if (cell->is_ghost())
- {
- dof_indices.resize(cell->get_fe().dofs_per_cell);
- cell->get_dof_indices(dof_indices);
-
- for (std::vector<unsigned int>::iterator it=dof_indices.begin();
- it!=dof_indices.end();
- ++it)
- if (!dof_set.is_element(*it))
- global_dof_indices.insert(*it);
- }
+ template <class DH>
+ void
+ extract_subdomain_dofs (const DH &dof_handler,
+ const types::subdomain_id_t subdomain_id,
+ std::vector<bool> &selected_dofs)
+ {
+ Assert(selected_dofs.size() == dof_handler.n_dofs(),
+ ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
+
+ // preset all values by false
+ std::fill_n (selected_dofs.begin(), dof_handler.n_dofs(), false);
+
+ std::vector<unsigned int> local_dof_indices;
+ local_dof_indices.reserve (max_dofs_per_cell(dof_handler));
+
+ // this function is similar to the
+ // make_sparsity_pattern function,
+ // see there for more information
+ typename DH::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ if (cell->subdomain_id() == subdomain_id)
+ {
+ const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
+ local_dof_indices.resize (dofs_per_cell);
+ cell->get_dof_indices (local_dof_indices);
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ selected_dofs[local_dof_indices[i]] = true;
+ };
+ }
- dof_set.add_indices(global_dof_indices.begin(), global_dof_indices.end());
- dof_set.compress();
-}
+ template <class DH>
+ void
+ extract_locally_owned_dofs (const DH & dof_handler,
+ IndexSet & dof_set)
+ {
+ // collect all the locally owned dofs
+ dof_set = dof_handler.locally_owned_dofs();
+ dof_set.compress ();
+ }
-template <class DH>
-void
-DoFTools::extract_constant_modes (const DH &dof_handler,
- const std::vector<bool> &component_select,
- std::vector<std::vector<bool> > &constant_modes)
-{
- const unsigned int n_components = dof_handler.get_fe().n_components();
- Assert (n_components == component_select.size(),
- ExcDimensionMismatch(n_components,
- component_select.size()));
- std::vector<unsigned int> localized_component (n_components,
- numbers::invalid_unsigned_int);
- unsigned int n_components_selected = 0;
- for (unsigned int i=0; i<n_components; ++i)
- if (component_select[i] == true)
- localized_component[i] = n_components_selected++;
-
- std::vector<unsigned char> dofs_by_component (dof_handler.n_locally_owned_dofs());
- internal::extract_dofs_by_component (dof_handler, component_select, false,
- dofs_by_component);
- unsigned int n_selected_dofs = 0;
- for (unsigned int i=0; i<n_components; ++i)
- if (component_select[i] == true)
- n_selected_dofs += std::count (dofs_by_component.begin(),
- dofs_by_component.end(), i);
-
- // First count the number of dofs
- // in the current component.
- constant_modes.resize (n_components_selected, std::vector<bool>(n_selected_dofs,
- false));
- std::vector<unsigned int> component_list (n_components, 0);
- for (unsigned int d=0; d<n_components; ++d)
- component_list[d] = component_select[d];
-
- unsigned int counter = 0;
- for (unsigned int i=0; i<dof_handler.n_locally_owned_dofs(); ++i)
- if (component_select[dofs_by_component[i]])
- {
- constant_modes[localized_component[dofs_by_component[i]]][counter] = true;
- ++counter;
- }
-}
+ template <class DH>
+ void
+ extract_locally_active_dofs (const DH & dof_handler,
+ IndexSet & dof_set)
+ {
+ // collect all the locally owned dofs
+ dof_set = dof_handler.locally_owned_dofs();
+
+ // add the DoF on the adjacent ghost cells
+ // to the IndexSet, cache them in a
+ // set. need to check each dof manually
+ // because we can't be sure that the dof
+ // range of locally_owned_dofs is really
+ // contiguous.
+ std::vector<unsigned int> dof_indices;
+ std::set<unsigned int> global_dof_indices;
+
+ typename DH::active_cell_iterator cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ if (!cell->is_ghost() && !cell->is_artificial())
+ {
+ dof_indices.resize(cell->get_fe().dofs_per_cell);
+ cell->get_dof_indices(dof_indices);
+
+ for (std::vector<unsigned int>::iterator it=dof_indices.begin();
+ it!=dof_indices.end();
+ ++it)
+ if (!dof_set.is_element(*it))
+ global_dof_indices.insert(*it);
+ }
+ dof_set.add_indices(global_dof_indices.begin(), global_dof_indices.end());
-template <class DH>
-void
-DoFTools::get_active_fe_indices (const DH &dof_handler,
- std::vector<unsigned int> &active_fe_indices)
-{
- Assert (active_fe_indices.size() == dof_handler.get_tria().n_active_cells(),
- ExcWrongSize (active_fe_indices.size(),
- dof_handler.get_tria().n_active_cells()));
-
- typename DH::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (unsigned int index=0; cell!=endc; ++cell, ++index)
- active_fe_indices[index] = cell->active_fe_index();
-}
+ dof_set.compress();
+ }
-template <class DH>
-void
-DoFTools::get_subdomain_association (const DH &dof_handler,
- std::vector<types::subdomain_id_t> &subdomain_association)
-{
- // if the Triangulation is distributed, the
- // only thing we can usefully ask is for
- // its locally owned subdomain
- Assert ((dynamic_cast<const parallel::distributed::
- Triangulation<DH::dimension,DH::space_dimension>*>
- (&dof_handler.get_tria()) == 0),
- ExcMessage ("For parallel::distributed::Triangulation objects and "
- "associated DoF handler objects, asking for any subdomain other "
- "than the locally owned one does not make sense."));
-
- Assert(subdomain_association.size() == dof_handler.n_dofs(),
- ExcDimensionMismatch(subdomain_association.size(),
- dof_handler.n_dofs()));
-
- // preset all values by an invalid value
- std::fill_n (subdomain_association.begin(), dof_handler.n_dofs(),
- types::invalid_subdomain_id);
-
- std::vector<unsigned int> local_dof_indices;
- local_dof_indices.reserve (max_dofs_per_cell(dof_handler));
-
- // pseudo-randomly assign variables
- // which lie on the interface
- // between subdomains to each of
- // the two or more
- bool coin_flip = true;
-
- // loop over all cells and record
- // which subdomain a DoF belongs
- // to. toss a coin in case it is on
- // an interface
- typename DH::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- {
- Assert (cell->is_artificial() == false,
- ExcMessage ("You can't call this function for meshes that "
- "have artificial cells."));
-
- const types::subdomain_id_t subdomain_id = cell->subdomain_id();
- const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
- local_dof_indices.resize (dofs_per_cell);
- cell->get_dof_indices (local_dof_indices);
-
- // set subdomain ids. if dofs
- // already have their values
- // set then they must be on
- // partition interfaces. in
- // that case randomly assign
- // them to either the previous
- // association or the current
- // one, where we take "random"
- // to be "once this way once
- // that way"
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- if (subdomain_association[local_dof_indices[i]] ==
- numbers::invalid_unsigned_int)
- subdomain_association[local_dof_indices[i]] = subdomain_id;
- else
- {
- if (coin_flip == true)
- subdomain_association[local_dof_indices[i]] = subdomain_id;
- coin_flip = !coin_flip;
- }
- }
+ template <class DH>
+ void
+ extract_locally_relevant_dofs (const DH & dof_handler,
+ IndexSet & dof_set)
+ {
+ // collect all the locally owned dofs
+ dof_set = dof_handler.locally_owned_dofs();
+
+ // add the DoF on the adjacent ghost cells
+ // to the IndexSet, cache them in a
+ // set. need to check each dof manually
+ // because we can't be sure that the dof
+ // range of locally_owned_dofs is really
+ // contiguous.
+ std::vector<unsigned int> dof_indices;
+ std::set<unsigned int> global_dof_indices;
+
+ typename DH::active_cell_iterator cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ if (cell->is_ghost())
+ {
+ dof_indices.resize(cell->get_fe().dofs_per_cell);
+ cell->get_dof_indices(dof_indices);
+
+ for (std::vector<unsigned int>::iterator it=dof_indices.begin();
+ it!=dof_indices.end();
+ ++it)
+ if (!dof_set.is_element(*it))
+ global_dof_indices.insert(*it);
+ }
- Assert (std::find (subdomain_association.begin(),
- subdomain_association.end(),
- types::invalid_subdomain_id)
- == subdomain_association.end(),
- ExcInternalError());
-}
+ dof_set.add_indices(global_dof_indices.begin(), global_dof_indices.end());
+ dof_set.compress();
+ }
-template <class DH>
-unsigned int
-DoFTools::count_dofs_with_subdomain_association (const DH &dof_handler,
- const types::subdomain_id_t subdomain)
-{
- std::vector<types::subdomain_id_t> subdomain_association (dof_handler.n_dofs());
- get_subdomain_association (dof_handler, subdomain_association);
- return std::count (subdomain_association.begin(),
- subdomain_association.end(),
- subdomain);
-}
+ template <class DH>
+ void
+ extract_constant_modes (const DH &dof_handler,
+ const std::vector<bool> &component_select,
+ std::vector<std::vector<bool> > &constant_modes)
+ {
+ const unsigned int n_components = dof_handler.get_fe().n_components();
+ Assert (n_components == component_select.size(),
+ ExcDimensionMismatch(n_components,
+ component_select.size()));
+ std::vector<unsigned int> localized_component (n_components,
+ numbers::invalid_unsigned_int);
+ unsigned int n_components_selected = 0;
+ for (unsigned int i=0; i<n_components; ++i)
+ if (component_select[i] == true)
+ localized_component[i] = n_components_selected++;
+
+ std::vector<unsigned char> dofs_by_component (dof_handler.n_locally_owned_dofs());
+ internal::extract_dofs_by_component (dof_handler, component_select, false,
+ dofs_by_component);
+ unsigned int n_selected_dofs = 0;
+ for (unsigned int i=0; i<n_components; ++i)
+ if (component_select[i] == true)
+ n_selected_dofs += std::count (dofs_by_component.begin(),
+ dofs_by_component.end(), i);
+
+ // First count the number of dofs
+ // in the current component.
+ constant_modes.resize (n_components_selected, std::vector<bool>(n_selected_dofs,
+ false));
+ std::vector<unsigned int> component_list (n_components, 0);
+ for (unsigned int d=0; d<n_components; ++d)
+ component_list[d] = component_select[d];
+
+ unsigned int counter = 0;
+ for (unsigned int i=0; i<dof_handler.n_locally_owned_dofs(); ++i)
+ if (component_select[dofs_by_component[i]])
+ {
+ constant_modes[localized_component[dofs_by_component[i]]][counter] = true;
+ ++counter;
+ }
+ }
-template <class DH>
-IndexSet
-DoFTools::dof_indices_with_subdomain_association (const DH &dof_handler,
- const types::subdomain_id_t subdomain)
-{
-#ifdef DEAL_II_USE_P4EST
- // if the DoFHandler is distributed, the
- // only thing we can usefully ask is for
- // its locally owned subdomain
- Assert ((dynamic_cast<const parallel::distributed::
- Triangulation<DH::dimension,DH::space_dimension>*>
- (&dof_handler.get_tria()) == 0)
- ||
- (subdomain ==
- dynamic_cast<const parallel::distributed::
- Triangulation<DH::dimension,DH::space_dimension>*>
- (&dof_handler.get_tria())->locally_owned_subdomain()),
- ExcMessage ("For parallel::distributed::Triangulation objects and "
- "associated DoF handler objects, asking for any subdomain other "
- "than the locally owned one does not make sense."));
-#endif
+ template <class DH>
+ void
+ get_active_fe_indices (const DH &dof_handler,
+ std::vector<unsigned int> &active_fe_indices)
+ {
+ Assert (active_fe_indices.size() == dof_handler.get_tria().n_active_cells(),
+ ExcWrongSize (active_fe_indices.size(),
+ dof_handler.get_tria().n_active_cells()));
+
+ typename DH::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (unsigned int index=0; cell!=endc; ++cell, ++index)
+ active_fe_indices[index] = cell->active_fe_index();
+ }
- IndexSet index_set (dof_handler.n_dofs());
- std::vector<unsigned int> local_dof_indices;
- local_dof_indices.reserve (max_dofs_per_cell(dof_handler));
- typename DH::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- if ((cell->is_artificial() == false)
- &&
- (cell->subdomain_id() == subdomain))
+ template <class DH>
+ void
+ get_subdomain_association (const DH &dof_handler,
+ std::vector<types::subdomain_id_t> &subdomain_association)
+ {
+ // if the Triangulation is distributed, the
+ // only thing we can usefully ask is for
+ // its locally owned subdomain
+ Assert ((dynamic_cast<const parallel::distributed::
+ Triangulation<DH::dimension,DH::space_dimension>*>
+ (&dof_handler.get_tria()) == 0),
+ ExcMessage ("For parallel::distributed::Triangulation objects and "
+ "associated DoF handler objects, asking for any subdomain other "
+ "than the locally owned one does not make sense."));
+
+ Assert(subdomain_association.size() == dof_handler.n_dofs(),
+ ExcDimensionMismatch(subdomain_association.size(),
+ dof_handler.n_dofs()));
+
+ // preset all values by an invalid value
+ std::fill_n (subdomain_association.begin(), dof_handler.n_dofs(),
+ types::invalid_subdomain_id);
+
+ std::vector<unsigned int> local_dof_indices;
+ local_dof_indices.reserve (max_dofs_per_cell(dof_handler));
+
+ // pseudo-randomly assign variables
+ // which lie on the interface
+ // between subdomains to each of
+ // the two or more
+ bool coin_flip = true;
+
+ // loop over all cells and record
+ // which subdomain a DoF belongs
+ // to. toss a coin in case it is on
+ // an interface
+ typename DH::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
{
+ Assert (cell->is_artificial() == false,
+ ExcMessage ("You can't call this function for meshes that "
+ "have artificial cells."));
+
+ const types::subdomain_id_t subdomain_id = cell->subdomain_id();
const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
local_dof_indices.resize (dofs_per_cell);
cell->get_dof_indices (local_dof_indices);
- index_set.add_indices (local_dof_indices.begin(),
- local_dof_indices.end());
+
+ // set subdomain ids. if dofs
+ // already have their values
+ // set then they must be on
+ // partition interfaces. in
+ // that case randomly assign
+ // them to either the previous
+ // association or the current
+ // one, where we take "random"
+ // to be "once this way once
+ // that way"
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ if (subdomain_association[local_dof_indices[i]] ==
+ numbers::invalid_unsigned_int)
+ subdomain_association[local_dof_indices[i]] = subdomain_id;
+ else
+ {
+ if (coin_flip == true)
+ subdomain_association[local_dof_indices[i]] = subdomain_id;
+ coin_flip = !coin_flip;
+ }
}
- index_set.compress ();
- return index_set;
-}
+ Assert (std::find (subdomain_association.begin(),
+ subdomain_association.end(),
+ types::invalid_subdomain_id)
+ == subdomain_association.end(),
+ ExcInternalError());
+ }
-template <class DH>
-void
-DoFTools::count_dofs_with_subdomain_association (const DH &dof_handler,
- const types::subdomain_id_t subdomain,
- std::vector<unsigned int> &n_dofs_on_subdomain)
-{
- Assert (n_dofs_on_subdomain.size() == dof_handler.get_fe().n_components(),
- ExcDimensionMismatch (n_dofs_on_subdomain.size(),
- dof_handler.get_fe().n_components()));
- std::fill (n_dofs_on_subdomain.begin(), n_dofs_on_subdomain.end(), 0);
-
- // in debug mode, make sure that there are
- // some cells at least with this subdomain
- // id
-#ifdef DEBUG
+ template <class DH>
+ unsigned int
+ count_dofs_with_subdomain_association (const DH &dof_handler,
+ const types::subdomain_id_t subdomain)
{
- bool found = false;
- for (typename Triangulation<DH::dimension,DH::space_dimension>::active_cell_iterator
- cell=dof_handler.get_tria().begin_active();
- cell!=dof_handler.get_tria().end(); ++cell)
- if (cell->subdomain_id() == subdomain)
- {
- found = true;
- break;
- }
- Assert (found == true,
- ExcMessage ("There are no cells for the given subdomain!"));
+ std::vector<types::subdomain_id_t> subdomain_association (dof_handler.n_dofs());
+ get_subdomain_association (dof_handler, subdomain_association);
+
+ return std::count (subdomain_association.begin(),
+ subdomain_association.end(),
+ subdomain);
}
+
+
+
+ template <class DH>
+ IndexSet
+ dof_indices_with_subdomain_association (const DH &dof_handler,
+ const types::subdomain_id_t subdomain)
+ {
+#ifdef DEAL_II_USE_P4EST
+ // if the DoFHandler is distributed, the
+ // only thing we can usefully ask is for
+ // its locally owned subdomain
+ Assert ((dynamic_cast<const parallel::distributed::
+ Triangulation<DH::dimension,DH::space_dimension>*>
+ (&dof_handler.get_tria()) == 0)
+ ||
+ (subdomain ==
+ dynamic_cast<const parallel::distributed::
+ Triangulation<DH::dimension,DH::space_dimension>*>
+ (&dof_handler.get_tria())->locally_owned_subdomain()),
+ ExcMessage ("For parallel::distributed::Triangulation objects and "
+ "associated DoF handler objects, asking for any subdomain other "
+ "than the locally owned one does not make sense."));
#endif
- std::vector<types::subdomain_id_t> subdomain_association (dof_handler.n_dofs());
- get_subdomain_association (dof_handler, subdomain_association);
+ IndexSet index_set (dof_handler.n_dofs());
- std::vector<unsigned char> component_association (dof_handler.n_dofs());
- internal::extract_dofs_by_component (dof_handler, std::vector<bool>(), false,
- component_association);
+ std::vector<unsigned int> local_dof_indices;
+ local_dof_indices.reserve (max_dofs_per_cell(dof_handler));
- for (unsigned int c=0; c<dof_handler.get_fe().n_components(); ++c)
- {
- for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
- if ((subdomain_association[i] == subdomain) &&
- (component_association[i] == static_cast<unsigned char>(c)))
- ++n_dofs_on_subdomain[c];
- }
-}
+ typename DH::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ if ((cell->is_artificial() == false)
+ &&
+ (cell->subdomain_id() == subdomain))
+ {
+ const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
+ local_dof_indices.resize (dofs_per_cell);
+ cell->get_dof_indices (local_dof_indices);
+ index_set.add_indices (local_dof_indices.begin(),
+ local_dof_indices.end());
+ }
+ index_set.compress ();
+ return index_set;
+ }
-namespace internal
-{
- template <int dim, int spacedim>
+
+ template <class DH>
void
- resolve_components (const FiniteElement<dim,spacedim>&fe,
- const std::vector<unsigned char> &dofs_by_component,
- const std::vector<unsigned int> &target_component,
- const bool only_once,
- std::vector<unsigned int> &dofs_per_component,
- unsigned int &component)
+ count_dofs_with_subdomain_association (const DH &dof_handler,
+ const types::subdomain_id_t subdomain,
+ std::vector<unsigned int> &n_dofs_on_subdomain)
{
- for (unsigned int b=0;b<fe.n_base_elements();++b)
- {
- const FiniteElement<dim,spacedim>& base = fe.base_element(b);
- // Dimension of base element
- unsigned int d = base.n_components();
-
- for (unsigned int m=0;m<fe.element_multiplicity(b);++m)
+ Assert (n_dofs_on_subdomain.size() == dof_handler.get_fe().n_components(),
+ ExcDimensionMismatch (n_dofs_on_subdomain.size(),
+ dof_handler.get_fe().n_components()));
+ std::fill (n_dofs_on_subdomain.begin(), n_dofs_on_subdomain.end(), 0);
+
+ // in debug mode, make sure that there are
+ // some cells at least with this subdomain
+ // id
+#ifdef DEBUG
+ {
+ bool found = false;
+ for (typename Triangulation<DH::dimension,DH::space_dimension>::active_cell_iterator
+ cell=dof_handler.get_tria().begin_active();
+ cell!=dof_handler.get_tria().end(); ++cell)
+ if (cell->subdomain_id() == subdomain)
{
- if (base.n_base_elements() > 1)
- resolve_components(base, dofs_by_component, target_component,
- only_once, dofs_per_component, component);
- else
- {
- for (unsigned int dd=0;dd<d;++dd,++component)
- dofs_per_component[target_component[component]]
- += std::count(dofs_by_component.begin(),
- dofs_by_component.end(),
- component);
-
- // if we have non-primitive FEs and want all
- // components to show the number of dofs, need
- // to copy the result to those components
- if (!base.is_primitive() && !only_once)
- for (unsigned int dd=1;dd<d;++dd)
- dofs_per_component[target_component[component-d+dd]] =
- dofs_per_component[target_component[component-d]];
- }
+ found = true;
+ break;
}
+ Assert (found == true,
+ ExcMessage ("There are no cells for the given subdomain!"));
+ }
+#endif
+
+ std::vector<types::subdomain_id_t> subdomain_association (dof_handler.n_dofs());
+ get_subdomain_association (dof_handler, subdomain_association);
+
+ std::vector<unsigned char> component_association (dof_handler.n_dofs());
+ internal::extract_dofs_by_component (dof_handler, std::vector<bool>(), false,
+ component_association);
+
+ for (unsigned int c=0; c<dof_handler.get_fe().n_components(); ++c)
+ {
+ for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
+ if ((subdomain_association[i] == subdomain) &&
+ (component_association[i] == static_cast<unsigned char>(c)))
+ ++n_dofs_on_subdomain[c];
}
}
-}
-
-template <int dim, int spacedim>
-void
-DoFTools::count_dofs_per_component (
- const DoFHandler<dim,spacedim>& dof_handler,
- std::vector<unsigned int>& dofs_per_component,
- bool only_once,
- std::vector<unsigned int> target_component)
-{
- const FiniteElement<dim,spacedim>& fe = dof_handler.get_fe();
- std::fill (dofs_per_component.begin(), dofs_per_component.end(), 0U);
- // If the empty vector was given as
- // default argument, set up this
- // vector as identity.
- if (target_component.size()==0)
+ namespace internal
+ {
+ template <int dim, int spacedim>
+ void
+ resolve_components (const FiniteElement<dim,spacedim>&fe,
+ const std::vector<unsigned char> &dofs_by_component,
+ const std::vector<unsigned int> &target_component,
+ const bool only_once,
+ std::vector<unsigned int> &dofs_per_component,
+ unsigned int &component)
{
- target_component.resize(fe.n_components());
- for (unsigned int i=0; i<fe.n_components(); ++i)
- target_component[i] = i;
+ for (unsigned int b=0;b<fe.n_base_elements();++b)
+ {
+ const FiniteElement<dim,spacedim>& base = fe.base_element(b);
+ // Dimension of base element
+ unsigned int d = base.n_components();
+
+ for (unsigned int m=0;m<fe.element_multiplicity(b);++m)
+ {
+ if (base.n_base_elements() > 1)
+ resolve_components(base, dofs_by_component, target_component,
+ only_once, dofs_per_component, component);
+ else
+ {
+ for (unsigned int dd=0;dd<d;++dd,++component)
+ dofs_per_component[target_component[component]]
+ += std::count(dofs_by_component.begin(),
+ dofs_by_component.end(),
+ component);
+
+ // if we have non-primitive FEs and want all
+ // components to show the number of dofs, need
+ // to copy the result to those components
+ if (!base.is_primitive() && !only_once)
+ for (unsigned int dd=1;dd<d;++dd)
+ dofs_per_component[target_component[component-d+dd]] =
+ dofs_per_component[target_component[component-d]];
+ }
+ }
+ }
}
- else
- Assert (target_component.size()==fe.n_components(),
- ExcDimensionMismatch(target_component.size(),
- fe.n_components()));
+ }
- const unsigned int max_component
- = *std::max_element (target_component.begin(),
- target_component.end());
- const unsigned int n_target_components = max_component + 1;
- const unsigned int n_components = fe.n_components();
+ template <int dim, int spacedim>
+ void
+ count_dofs_per_component (
+ const DoFHandler<dim,spacedim>& dof_handler,
+ std::vector<unsigned int>& dofs_per_component,
+ bool only_once,
+ std::vector<unsigned int> target_component)
+ {
+ const FiniteElement<dim,spacedim>& fe = dof_handler.get_fe();
- AssertDimension (dofs_per_component.size(), n_target_components);
+ std::fill (dofs_per_component.begin(), dofs_per_component.end(), 0U);
- // special case for only one
- // component. treat this first
- // since it does not require any
- // computations
- if (n_components == 1)
- {
- dofs_per_component[0] = dof_handler.n_locally_owned_dofs();
- return;
- }
+ // If the empty vector was given as
+ // default argument, set up this
+ // vector as identity.
+ if (target_component.size()==0)
+ {
+ target_component.resize(fe.n_components());
+ for (unsigned int i=0; i<fe.n_components(); ++i)
+ target_component[i] = i;
+ }
+ else
+ Assert (target_component.size()==fe.n_components(),
+ ExcDimensionMismatch(target_component.size(),
+ fe.n_components()));
- // otherwise determine the number
- // of dofs in each component
- // separately. do so in parallel
- std::vector<unsigned char> dofs_by_component (dof_handler.n_locally_owned_dofs());
- internal::extract_dofs_by_component (dof_handler, std::vector<bool>(), false,
- dofs_by_component);
-
- // next count what we got
- unsigned int component = 0;
- internal::resolve_components(fe, dofs_by_component, target_component,
- only_once, dofs_per_component, component);
- Assert (n_components == component, ExcInternalError());
-
- // finally sanity check. this is
- // only valid if the finite element
- // is actually primitive, so
- // exclude other elements from this
- Assert (!dof_handler.get_fe().is_primitive()
- ||
- (std::accumulate (dofs_per_component.begin(),
- dofs_per_component.end(), 0U)
- == dof_handler.n_locally_owned_dofs()),
- ExcInternalError());
+ const unsigned int max_component
+ = *std::max_element (target_component.begin(),
+ target_component.end());
+ const unsigned int n_target_components = max_component + 1;
+ const unsigned int n_components = fe.n_components();
+
+ AssertDimension (dofs_per_component.size(), n_target_components);
+
+ // special case for only one
+ // component. treat this first
+ // since it does not require any
+ // computations
+ if (n_components == 1)
+ {
+ dofs_per_component[0] = dof_handler.n_locally_owned_dofs();
+ return;
+ }
+
+
+ // otherwise determine the number
+ // of dofs in each component
+ // separately. do so in parallel
+ std::vector<unsigned char> dofs_by_component (dof_handler.n_locally_owned_dofs());
+ internal::extract_dofs_by_component (dof_handler, std::vector<bool>(), false,
+ dofs_by_component);
+
+ // next count what we got
+ unsigned int component = 0;
+ internal::resolve_components(fe, dofs_by_component, target_component,
+ only_once, dofs_per_component, component);
+ Assert (n_components == component, ExcInternalError());
+
+ // finally sanity check. this is
+ // only valid if the finite element
+ // is actually primitive, so
+ // exclude other elements from this
+ Assert (!dof_handler.get_fe().is_primitive()
+ ||
+ (std::accumulate (dofs_per_component.begin(),
+ dofs_per_component.end(), 0U)
+ == dof_handler.n_locally_owned_dofs()),
+ ExcInternalError());
// reduce information from all CPUs
#ifdef DEAL_II_USE_P4EST
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
- if (const parallel::distributed::Triangulation<dim> * tria
- = (dynamic_cast<const parallel::distributed::Triangulation<dim>*>
- (&dof_handler.get_tria())))
- {
- std::vector<unsigned int> local_dof_count = dofs_per_component;
+ if (const parallel::distributed::Triangulation<dim> * tria
+ = (dynamic_cast<const parallel::distributed::Triangulation<dim>*>
+ (&dof_handler.get_tria())))
+ {
+ std::vector<unsigned int> local_dof_count = dofs_per_component;
- MPI_Allreduce ( &local_dof_count[0], &dofs_per_component[0], n_target_components,
- MPI_UNSIGNED, MPI_SUM, tria->get_communicator());
- }
+ MPI_Allreduce ( &local_dof_count[0], &dofs_per_component[0], n_target_components,
+ MPI_UNSIGNED, MPI_SUM, tria->get_communicator());
+ }
#endif
#endif
-}
+ }
-template <int dim, int spacedim>
-void
-DoFTools::
-count_dofs_per_block (const DoFHandler<dim,spacedim>& dof_handler,
- std::vector<unsigned int> &dofs_per_block,
- std::vector<unsigned int> target_block)
-{
- const FiniteElement<dim,spacedim>& fe = dof_handler.get_fe();
+ template <int dim, int spacedim>
+ void
+ count_dofs_per_block (const DoFHandler<dim,spacedim>& dof_handler,
+ std::vector<unsigned int> &dofs_per_block,
+ std::vector<unsigned int> target_block)
+ {
+ const FiniteElement<dim,spacedim>& fe = dof_handler.get_fe();
- std::fill (dofs_per_block.begin(), dofs_per_block.end(), 0U);
+ std::fill (dofs_per_block.begin(), dofs_per_block.end(), 0U);
- // If the empty vector was given as
- // default argument, set up this
- // vector as identity.
- if (target_block.size()==0)
- {
- target_block.resize(fe.n_blocks());
- for (unsigned int i=0; i<fe.n_blocks(); ++i)
- target_block[i] = i;
- }
- else
- Assert (target_block.size()==fe.n_blocks(),
- ExcDimensionMismatch(target_block.size(),
- fe.n_blocks()));
+ // If the empty vector was given as
+ // default argument, set up this
+ // vector as identity.
+ if (target_block.size()==0)
+ {
+ target_block.resize(fe.n_blocks());
+ for (unsigned int i=0; i<fe.n_blocks(); ++i)
+ target_block[i] = i;
+ }
+ else
+ Assert (target_block.size()==fe.n_blocks(),
+ ExcDimensionMismatch(target_block.size(),
+ fe.n_blocks()));
- const unsigned int max_block
- = *std::max_element (target_block.begin(),
- target_block.end());
- const unsigned int n_target_blocks = max_block + 1;
- const unsigned int n_blocks = fe.n_blocks();
+ const unsigned int max_block
+ = *std::max_element (target_block.begin(),
+ target_block.end());
+ const unsigned int n_target_blocks = max_block + 1;
+ const unsigned int n_blocks = fe.n_blocks();
- AssertDimension (dofs_per_block.size(), n_target_blocks);
+ AssertDimension (dofs_per_block.size(), n_target_blocks);
- // special case for only one
- // block. treat this first
- // since it does not require any
- // computations
- if (n_blocks == 1)
- {
- dofs_per_block[0] = dof_handler.n_dofs();
- return;
- }
- // otherwise determine the number
- // of dofs in each block
- // separately.
- std::vector<unsigned char> dofs_by_block (dof_handler.n_locally_owned_dofs());
- internal::extract_dofs_by_component (dof_handler, std::vector<bool>(),
- true, dofs_by_block);
-
- // next count what we got
- for (unsigned int block=0; block<fe.n_blocks(); ++block)
- dofs_per_block[target_block[block]]
- += std::count(dofs_by_block.begin(), dofs_by_block.end(),
- block);
+ // special case for only one
+ // block. treat this first
+ // since it does not require any
+ // computations
+ if (n_blocks == 1)
+ {
+ dofs_per_block[0] = dof_handler.n_dofs();
+ return;
+ }
+ // otherwise determine the number
+ // of dofs in each block
+ // separately.
+ std::vector<unsigned char> dofs_by_block (dof_handler.n_locally_owned_dofs());
+ internal::extract_dofs_by_component (dof_handler, std::vector<bool>(),
+ true, dofs_by_block);
+
+ // next count what we got
+ for (unsigned int block=0; block<fe.n_blocks(); ++block)
+ dofs_per_block[target_block[block]]
+ += std::count(dofs_by_block.begin(), dofs_by_block.end(),
+ block);
#ifdef DEAL_II_USE_P4EST
#if DEAL_II_COMPILER_SUPPORTS_MPI
- // if we are working on a parallel
- // mesh, we now need to collect
- // this information from all
- // processors
- if (const parallel::distributed::Triangulation<dim> * tria
- = (dynamic_cast<const parallel::distributed::Triangulation<dim>*>
- (&dof_handler.get_tria())))
- {
- std::vector<unsigned int> local_dof_count = dofs_per_block;
- MPI_Allreduce ( &local_dof_count[0], &dofs_per_block[0], n_target_blocks,
- MPI_UNSIGNED, MPI_SUM, tria->get_communicator());
- }
+ // if we are working on a parallel
+ // mesh, we now need to collect
+ // this information from all
+ // processors
+ if (const parallel::distributed::Triangulation<dim> * tria
+ = (dynamic_cast<const parallel::distributed::Triangulation<dim>*>
+ (&dof_handler.get_tria())))
+ {
+ std::vector<unsigned int> local_dof_count = dofs_per_block;
+ MPI_Allreduce ( &local_dof_count[0], &dofs_per_block[0], n_target_blocks,
+ MPI_UNSIGNED, MPI_SUM, tria->get_communicator());
+ }
#endif
#endif
-}
+ }
-template <int dim, int spacedim>
-void
-DoFTools::
-count_dofs_per_component (const DoFHandler<dim,spacedim> &dof_handler,
- std::vector<unsigned int> &dofs_per_component,
- std::vector<unsigned int> target_component)
-{
- count_dofs_per_component (dof_handler, dofs_per_component,
- false, target_component);
-}
+ template <int dim, int spacedim>
+ void
+ count_dofs_per_component (const DoFHandler<dim,spacedim> &dof_handler,
+ std::vector<unsigned int> &dofs_per_component,
+ std::vector<unsigned int> target_component)
+ {
+ count_dofs_per_component (dof_handler, dofs_per_component,
+ false, target_component);
+ }
-namespace internal
-{
- namespace
+ namespace internal
{
- /**
- * This is a helper function that
- * is used in the computation of
- * integrid constraints. See the
- * function for a thorough
- * description of how it works.
- */
- template <int dim, int spacedim>
- unsigned int
- compute_intergrid_weights_1 (
- const dealii::DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const dealii::DoFHandler<dim,spacedim> &fine_grid,
- const unsigned int fine_component,
- const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- std::vector<std::map<unsigned int, float> > &weights,
- std::vector<int> &weight_mapping)
+ namespace
{
- // aliases to the finite elements
- // used by the dof handlers:
- const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe(),
- &fine_fe = fine_grid.get_fe();
-
- // global numbers of dofs
- const unsigned int n_coarse_dofs = coarse_grid.n_dofs(),
- n_fine_dofs = fine_grid.n_dofs();
-
- // local numbers of dofs
- const unsigned int fine_dofs_per_cell = fine_fe.dofs_per_cell;
-
- // alias the number of dofs per
- // cell belonging to the
- // coarse_component which is to be
- // the restriction of the fine
- // grid:
- const unsigned int coarse_dofs_per_cell_component
- = coarse_fe.base_element(coarse_fe.component_to_base_index(coarse_component).first).dofs_per_cell;
-
-
- // Try to find out whether the
- // grids stem from the same coarse
- // grid. This is a rather crude
- // test, but better than nothing
- Assert (coarse_grid.get_tria().n_cells(0) == fine_grid.get_tria().n_cells(0),
- dealii::DoFTools::ExcGridsDontMatch());
-
- // check whether the map correlates
- // the right objects
- Assert (&coarse_to_fine_grid_map.get_source_grid() == &coarse_grid,
- dealii::DoFTools::ExcGridsDontMatch ());
- Assert (&coarse_to_fine_grid_map.get_destination_grid() == &fine_grid,
- dealii::DoFTools::ExcGridsDontMatch ());
-
-
- // check whether component numbers
- // are valid
- Assert (coarse_component < coarse_fe.n_components(),
- dealii::DoFTools::ExcInvalidComponent (coarse_component, coarse_fe.n_components()));
- Assert (fine_component < fine_fe.n_components(),
- dealii::DoFTools::ExcInvalidComponent (fine_component, fine_fe.n_components()));
- // check whether respective finite
- // elements are equal
- Assert (coarse_fe.base_element (coarse_fe.component_to_base_index(coarse_component).first)
- ==
- fine_fe.base_element (fine_fe.component_to_base_index(fine_component).first),
- dealii::DoFTools::ExcFiniteElementsDontMatch());
+ /**
+ * This is a helper function that
+ * is used in the computation of
+ * integrid constraints. See the
+ * function for a thorough
+ * description of how it works.
+ */
+ template <int dim, int spacedim>
+ unsigned int
+ compute_intergrid_weights_1 (
+ const dealii::DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const dealii::DoFHandler<dim,spacedim> &fine_grid,
+ const unsigned int fine_component,
+ const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ std::vector<std::map<unsigned int, float> > &weights,
+ std::vector<int> &weight_mapping)
+ {
+ // aliases to the finite elements
+ // used by the dof handlers:
+ const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe(),
+ &fine_fe = fine_grid.get_fe();
+
+ // global numbers of dofs
+ const unsigned int n_coarse_dofs = coarse_grid.n_dofs(),
+ n_fine_dofs = fine_grid.n_dofs();
+
+ // local numbers of dofs
+ const unsigned int fine_dofs_per_cell = fine_fe.dofs_per_cell;
+
+ // alias the number of dofs per
+ // cell belonging to the
+ // coarse_component which is to be
+ // the restriction of the fine
+ // grid:
+ const unsigned int coarse_dofs_per_cell_component
+ = coarse_fe.base_element(coarse_fe.component_to_base_index(coarse_component).first).dofs_per_cell;
+
+
+ // Try to find out whether the
+ // grids stem from the same coarse
+ // grid. This is a rather crude
+ // test, but better than nothing
+ Assert (coarse_grid.get_tria().n_cells(0) == fine_grid.get_tria().n_cells(0),
+ ExcGridsDontMatch());
+
+ // check whether the map correlates
+ // the right objects
+ Assert (&coarse_to_fine_grid_map.get_source_grid() == &coarse_grid,
+ ExcGridsDontMatch ());
+ Assert (&coarse_to_fine_grid_map.get_destination_grid() == &fine_grid,
+ ExcGridsDontMatch ());
+
+
+ // check whether component numbers
+ // are valid
+ Assert (coarse_component < coarse_fe.n_components(),
+ ExcInvalidComponent (coarse_component, coarse_fe.n_components()));
+ Assert (fine_component < fine_fe.n_components(),
+ ExcInvalidComponent (fine_component, fine_fe.n_components()));
+ // check whether respective finite
+ // elements are equal
+ Assert (coarse_fe.base_element (coarse_fe.component_to_base_index(coarse_component).first)
+ ==
+ fine_fe.base_element (fine_fe.component_to_base_index(fine_component).first),
+ ExcFiniteElementsDontMatch());
#ifdef DEBUG
- // if in debug mode, check whether
- // the coarse grid is indeed
- // coarser everywhere than the fine
- // grid
- for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
- cell=coarse_grid.begin_active();
- cell != coarse_grid.end(); ++cell)
- Assert (cell->level() <= coarse_to_fine_grid_map[cell]->level(),
- dealii::DoFTools::ExcGridNotCoarser());
+ // if in debug mode, check whether
+ // the coarse grid is indeed
+ // coarser everywhere than the fine
+ // grid
+ for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
+ cell=coarse_grid.begin_active();
+ cell != coarse_grid.end(); ++cell)
+ Assert (cell->level() <= coarse_to_fine_grid_map[cell]->level(),
+ ExcGridNotCoarser());
#endif
- // set up vectors of cell-local
- // data; each vector represents one
- // degree of freedom of the
- // coarse-grid variable in the
- // fine-grid element
- std::vector<dealii::Vector<double> >
- parameter_dofs (coarse_dofs_per_cell_component,
- dealii::Vector<double>(fine_dofs_per_cell));
- // for each coarse dof: find its
- // position within the fine element
- // and set this value to one in the
- // respective vector (all other values
- // are zero by construction)
- for (unsigned int local_coarse_dof=0;
- local_coarse_dof<coarse_dofs_per_cell_component;
- ++local_coarse_dof)
- for (unsigned int fine_dof=0; fine_dof<fine_fe.dofs_per_cell; ++fine_dof)
- if (fine_fe.system_to_component_index(fine_dof)
- ==
- std::make_pair (fine_component, local_coarse_dof))
- {
- parameter_dofs[local_coarse_dof](fine_dof) = 1.;
- break;
- };
-
+ // set up vectors of cell-local
+ // data; each vector represents one
+ // degree of freedom of the
+ // coarse-grid variable in the
+ // fine-grid element
+ std::vector<dealii::Vector<double> >
+ parameter_dofs (coarse_dofs_per_cell_component,
+ dealii::Vector<double>(fine_dofs_per_cell));
+ // for each coarse dof: find its
+ // position within the fine element
+ // and set this value to one in the
+ // respective vector (all other values
+ // are zero by construction)
+ for (unsigned int local_coarse_dof=0;
+ local_coarse_dof<coarse_dofs_per_cell_component;
+ ++local_coarse_dof)
+ for (unsigned int fine_dof=0; fine_dof<fine_fe.dofs_per_cell; ++fine_dof)
+ if (fine_fe.system_to_component_index(fine_dof)
+ ==
+ std::make_pair (fine_component, local_coarse_dof))
+ {
+ parameter_dofs[local_coarse_dof](fine_dof) = 1.;
+ break;
+ };
- // find out how many DoFs there are
- // on the grids belonging to the
- // components we want to match
- unsigned int n_parameters_on_fine_grid=0;
- if (true)
- {
- // have a flag for each dof on
- // the fine grid and set it
- // to true if this is an
- // interesting dof. finally count
- // how many true's there
- std::vector<bool> dof_is_interesting (fine_grid.n_dofs(), false);
- std::vector<unsigned int> local_dof_indices (fine_fe.dofs_per_cell);
-
- for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
- cell=fine_grid.begin_active();
- cell!=fine_grid.end(); ++cell)
- {
- cell->get_dof_indices (local_dof_indices);
- for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i)
- if (fine_fe.system_to_component_index(i).first == fine_component)
- dof_is_interesting[local_dof_indices[i]] = true;
- };
- n_parameters_on_fine_grid = std::count (dof_is_interesting.begin(),
- dof_is_interesting.end(),
- true);
- };
+ // find out how many DoFs there are
+ // on the grids belonging to the
+ // components we want to match
+ unsigned int n_parameters_on_fine_grid=0;
+ if (true)
+ {
+ // have a flag for each dof on
+ // the fine grid and set it
+ // to true if this is an
+ // interesting dof. finally count
+ // how many true's there
+ std::vector<bool> dof_is_interesting (fine_grid.n_dofs(), false);
+ std::vector<unsigned int> local_dof_indices (fine_fe.dofs_per_cell);
+
+ for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
+ cell=fine_grid.begin_active();
+ cell!=fine_grid.end(); ++cell)
+ {
+ cell->get_dof_indices (local_dof_indices);
+ for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i)
+ if (fine_fe.system_to_component_index(i).first == fine_component)
+ dof_is_interesting[local_dof_indices[i]] = true;
+ };
+
+ n_parameters_on_fine_grid = std::count (dof_is_interesting.begin(),
+ dof_is_interesting.end(),
+ true);
+ };
- // set up the weights mapping
- weights.clear ();
- weights.resize (n_coarse_dofs);
+ // set up the weights mapping
+ weights.clear ();
+ weights.resize (n_coarse_dofs);
- weight_mapping.clear ();
- weight_mapping.resize (n_fine_dofs, -1);
+ weight_mapping.clear ();
+ weight_mapping.resize (n_fine_dofs, -1);
- if (true)
- {
- std::vector<unsigned int> local_dof_indices(fine_fe.dofs_per_cell);
- unsigned int next_free_index=0;
- for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
- cell=fine_grid.begin_active();
- cell != fine_grid.end(); ++cell)
- {
- cell->get_dof_indices (local_dof_indices);
- for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i)
- // if this DoF is a
- // parameter dof and has
- // not yet been numbered,
- // then do so
- if ((fine_fe.system_to_component_index(i).first == fine_component) &&
- (weight_mapping[local_dof_indices[i]] == -1))
- {
- weight_mapping[local_dof_indices[i]] = next_free_index;
- ++next_free_index;
- };
- };
+ if (true)
+ {
+ std::vector<unsigned int> local_dof_indices(fine_fe.dofs_per_cell);
+ unsigned int next_free_index=0;
+ for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator
+ cell=fine_grid.begin_active();
+ cell != fine_grid.end(); ++cell)
+ {
+ cell->get_dof_indices (local_dof_indices);
+ for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i)
+ // if this DoF is a
+ // parameter dof and has
+ // not yet been numbered,
+ // then do so
+ if ((fine_fe.system_to_component_index(i).first == fine_component) &&
+ (weight_mapping[local_dof_indices[i]] == -1))
+ {
+ weight_mapping[local_dof_indices[i]] = next_free_index;
+ ++next_free_index;
+ };
+ };
- Assert (next_free_index == n_parameters_on_fine_grid,
- ExcInternalError());
- };
+ Assert (next_free_index == n_parameters_on_fine_grid,
+ ExcInternalError());
+ };
- // for each cell on the parameter grid:
- // find out which degrees of freedom on the
- // fine grid correspond in which way to
- // the degrees of freedom on the parameter
- // grid
- //
- // do this in a separate function
- // to allow for multithreading
- // there. see this function also if
- // you want to read more
- // information on the algorithm
- // used.
- compute_intergrid_weights_2 (coarse_grid, coarse_component,
- coarse_to_fine_grid_map, parameter_dofs,
- weight_mapping, weights);
-
-
- // ok, now we have all weights for each
- // dof on the fine grid. if in debug
- // mode lets see if everything went smooth,
- // i.e. each dof has sum of weights one
- //
- // in other words this means that
- // if the sum of all shape
- // functions on the parameter grid
- // is one (which is always the
- // case), then the representation
- // on the state grid should be as
- // well (division of unity)
- //
- // if the parameter grid has more
- // than one component, then the
- // respective dofs of the other
- // components have sum of weights
- // zero, of course. we do not
- // explicitly ask which component
- // a dof belongs to, but this at
- // least tests some errors
+ // for each cell on the parameter grid:
+ // find out which degrees of freedom on the
+ // fine grid correspond in which way to
+ // the degrees of freedom on the parameter
+ // grid
+ //
+ // do this in a separate function
+ // to allow for multithreading
+ // there. see this function also if
+ // you want to read more
+ // information on the algorithm
+ // used.
+ compute_intergrid_weights_2 (coarse_grid, coarse_component,
+ coarse_to_fine_grid_map, parameter_dofs,
+ weight_mapping, weights);
+
+
+ // ok, now we have all weights for each
+ // dof on the fine grid. if in debug
+ // mode lets see if everything went smooth,
+ // i.e. each dof has sum of weights one
+ //
+ // in other words this means that
+ // if the sum of all shape
+ // functions on the parameter grid
+ // is one (which is always the
+ // case), then the representation
+ // on the state grid should be as
+ // well (division of unity)
+ //
+ // if the parameter grid has more
+ // than one component, then the
+ // respective dofs of the other
+ // components have sum of weights
+ // zero, of course. we do not
+ // explicitly ask which component
+ // a dof belongs to, but this at
+ // least tests some errors
#ifdef DEBUG
- for (unsigned int col=0; col<n_parameters_on_fine_grid; ++col)
- {
- double sum=0;
- for (unsigned int row=0; row<n_coarse_dofs; ++row)
- if (weights[row].find(col) != weights[row].end())
- sum += weights[row][col];
- Assert ((std::fabs(sum-1) < 1.e-12) ||
- ((coarse_fe.n_components()>1) && (sum==0)), ExcInternalError());
- };
+ for (unsigned int col=0; col<n_parameters_on_fine_grid; ++col)
+ {
+ double sum=0;
+ for (unsigned int row=0; row<n_coarse_dofs; ++row)
+ if (weights[row].find(col) != weights[row].end())
+ sum += weights[row][col];
+ Assert ((std::fabs(sum-1) < 1.e-12) ||
+ ((coarse_fe.n_components()>1) && (sum==0)), ExcInternalError());
+ };
#endif
- return n_parameters_on_fine_grid;
- }
+ return n_parameters_on_fine_grid;
+ }
- /**
- * This is a function that is
- * called by the _2 function and
- * that operates on a range of
- * cells only. It is used to
- * split up the whole range of
- * cells into chunks which are
- * then worked on in parallel, if
- * multithreading is available.
- */
- template <int dim, int spacedim>
- void
- compute_intergrid_weights_3 (
- const dealii::DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- const std::vector<dealii::Vector<double> > ¶meter_dofs,
- const std::vector<int> &weight_mapping,
- std::vector<std::map<unsigned int, float> > &weights,
- const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &begin,
- const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &end)
- {
- // aliases to the finite elements
- // used by the dof handlers:
- const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe();
-
- // for each cell on the parameter grid:
- // find out which degrees of freedom on the
- // fine grid correspond in which way to
- // the degrees of freedom on the parameter
- // grid
- //
- // since for continuous FEs some
- // dofs exist on more than one
- // cell, we have to track which
- // ones were already visited. the
- // problem is that if we visit a
- // dof first on one cell and
- // compute its weight with respect
- // to some global dofs to be
- // non-zero, and later visit the
- // dof again on another cell and
- // (since we are on another cell)
- // recompute the weights with
- // respect to the same dofs as
- // above to be zero now, we have to
- // preserve them. we therefore
- // overwrite all weights if they
- // are nonzero and do not enforce
- // zero weights since that might be
- // only due to the fact that we are
- // on another cell.
- //
- // example:
- // coarse grid
- // | | |
- // *-----*-----*
- // | cell|cell |
- // | 1 | 2 |
- // | | |
- // 0-----1-----*
- //
- // fine grid
- // | | | | |
- // *--*--*--*--*
- // | | | | |
- // *--*--*--*--*
- // | | | | |
- // *--x--y--*--*
- //
- // when on cell 1, we compute the
- // weights of dof 'x' to be 1/2
- // from parameter dofs 0 and 1,
- // respectively. however, when
- // later we are on cell 2, we again
- // compute the prolongation of
- // shape function 1 restricted to
- // cell 2 to the globla grid and
- // find that the weight of global
- // dof 'x' now is zero. however, we
- // should not overwrite the old
- // value.
- //
- // we therefore always only set
- // nonzero values. why adding up is
- // not useful: dof 'y' would get
- // weight 1 from parameter dof 1 on
- // both cells 1 and 2, but the
- // correct weight is nevertheless
- // only 1.
-
- // vector to hold the representation of
- // a single degree of freedom on the
- // coarse grid (for the selected fe)
- // on the fine grid
- const unsigned int n_fine_dofs = weight_mapping.size();
- dealii::Vector<double> global_parameter_representation (n_fine_dofs);
-
- typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator cell;
- std::vector<unsigned int> parameter_dof_indices (coarse_fe.dofs_per_cell);
-
- for (cell=begin; cell!=end; ++cell)
- {
- // get the global indices of the
- // parameter dofs on this parameter
- // grid cell
- cell->get_dof_indices (parameter_dof_indices);
-
- // loop over all dofs on this
- // cell and check whether they
- // are interesting for us
- for (unsigned int local_dof=0;
- local_dof<coarse_fe.dofs_per_cell;
- ++local_dof)
- if (coarse_fe.system_to_component_index(local_dof).first
- ==
- coarse_component)
- {
- // the how-many-th
- // parameter is this on
- // this cell?
- const unsigned int local_parameter_dof
- = coarse_fe.system_to_component_index(local_dof).second;
-
- global_parameter_representation = 0;
-
- // distribute the representation of
- // @p{local_parameter_dof} on the
- // parameter grid cell @p{cell} to
- // the global data space
- coarse_to_fine_grid_map[cell]->
- set_dof_values_by_interpolation (parameter_dofs[local_parameter_dof],
- global_parameter_representation);
- // now that we've got the global
- // representation of each parameter
- // dof, we've only got to clobber the
- // non-zero entries in that vector and
- // store the result
- //
- // what we have learned: if entry @p{i}
- // of the global vector holds the value
- // @p{v[i]}, then this is the weight with
- // which the present dof contributes
- // to @p{i}. there may be several such
- // @p{i}s and their weights' sum should
- // be one. Then, @p{v[i]} should be
- // equal to @p{\sum_j w_{ij} p[j]} with
- // @p{p[j]} be the values of the degrees
- // of freedom on the coarse grid. we
- // can thus compute constraints which
- // link the degrees of freedom @p{v[i]}
- // on the fine grid to those on the
- // coarse grid, @p{p[j]}. Now to use
- // these as real constraints, rather
- // than as additional equations, we
- // have to identify representants
- // among the @p{i} for each @p{j}. this will
- // be done by simply taking the first
- // @p{i} for which @p{w_{ij}==1}.
- //
- // guard modification of
- // the weights array by a
- // Mutex. since it should
- // happen rather rarely
- // that there are several
- // threads operating on
- // different intergrid
- // weights, have only one
- // mutex for all of them
- static Threads::ThreadMutex mutex;
- Threads::ThreadMutex::ScopedLock lock (mutex);
- for (unsigned int i=0; i<global_parameter_representation.size(); ++i)
- // set this weight if it belongs
- // to a parameter dof.
- if (weight_mapping[i] != -1)
- {
- // only overwrite old
- // value if not by
- // zero
- if (global_parameter_representation(i) != 0)
- {
- const unsigned int wi = parameter_dof_indices[local_dof],
- wj = weight_mapping[i];
- weights[wi][wj] = global_parameter_representation(i);
- };
- }
- else
- Assert (global_parameter_representation(i) == 0,
- ExcInternalError());
- }
- }
- }
+ /**
+ * This is a function that is
+ * called by the _2 function and
+ * that operates on a range of
+ * cells only. It is used to
+ * split up the whole range of
+ * cells into chunks which are
+ * then worked on in parallel, if
+ * multithreading is available.
+ */
+ template <int dim, int spacedim>
+ void
+ compute_intergrid_weights_3 (
+ const dealii::DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ const std::vector<dealii::Vector<double> > ¶meter_dofs,
+ const std::vector<int> &weight_mapping,
+ std::vector<std::map<unsigned int, float> > &weights,
+ const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &begin,
+ const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &end)
+ {
+ // aliases to the finite elements
+ // used by the dof handlers:
+ const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe();
+
+ // for each cell on the parameter grid:
+ // find out which degrees of freedom on the
+ // fine grid correspond in which way to
+ // the degrees of freedom on the parameter
+ // grid
+ //
+ // since for continuous FEs some
+ // dofs exist on more than one
+ // cell, we have to track which
+ // ones were already visited. the
+ // problem is that if we visit a
+ // dof first on one cell and
+ // compute its weight with respect
+ // to some global dofs to be
+ // non-zero, and later visit the
+ // dof again on another cell and
+ // (since we are on another cell)
+ // recompute the weights with
+ // respect to the same dofs as
+ // above to be zero now, we have to
+ // preserve them. we therefore
+ // overwrite all weights if they
+ // are nonzero and do not enforce
+ // zero weights since that might be
+ // only due to the fact that we are
+ // on another cell.
+ //
+ // example:
+ // coarse grid
+ // | | |
+ // *-----*-----*
+ // | cell|cell |
+ // | 1 | 2 |
+ // | | |
+ // 0-----1-----*
+ //
+ // fine grid
+ // | | | | |
+ // *--*--*--*--*
+ // | | | | |
+ // *--*--*--*--*
+ // | | | | |
+ // *--x--y--*--*
+ //
+ // when on cell 1, we compute the
+ // weights of dof 'x' to be 1/2
+ // from parameter dofs 0 and 1,
+ // respectively. however, when
+ // later we are on cell 2, we again
+ // compute the prolongation of
+ // shape function 1 restricted to
+ // cell 2 to the globla grid and
+ // find that the weight of global
+ // dof 'x' now is zero. however, we
+ // should not overwrite the old
+ // value.
+ //
+ // we therefore always only set
+ // nonzero values. why adding up is
+ // not useful: dof 'y' would get
+ // weight 1 from parameter dof 1 on
+ // both cells 1 and 2, but the
+ // correct weight is nevertheless
+ // only 1.
+
+ // vector to hold the representation of
+ // a single degree of freedom on the
+ // coarse grid (for the selected fe)
+ // on the fine grid
+ const unsigned int n_fine_dofs = weight_mapping.size();
+ dealii::Vector<double> global_parameter_representation (n_fine_dofs);
+
+ typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator cell;
+ std::vector<unsigned int> parameter_dof_indices (coarse_fe.dofs_per_cell);
+
+ for (cell=begin; cell!=end; ++cell)
+ {
+ // get the global indices of the
+ // parameter dofs on this parameter
+ // grid cell
+ cell->get_dof_indices (parameter_dof_indices);
+
+ // loop over all dofs on this
+ // cell and check whether they
+ // are interesting for us
+ for (unsigned int local_dof=0;
+ local_dof<coarse_fe.dofs_per_cell;
+ ++local_dof)
+ if (coarse_fe.system_to_component_index(local_dof).first
+ ==
+ coarse_component)
+ {
+ // the how-many-th
+ // parameter is this on
+ // this cell?
+ const unsigned int local_parameter_dof
+ = coarse_fe.system_to_component_index(local_dof).second;
+
+ global_parameter_representation = 0;
+
+ // distribute the representation of
+ // @p{local_parameter_dof} on the
+ // parameter grid cell @p{cell} to
+ // the global data space
+ coarse_to_fine_grid_map[cell]->
+ set_dof_values_by_interpolation (parameter_dofs[local_parameter_dof],
+ global_parameter_representation);
+ // now that we've got the global
+ // representation of each parameter
+ // dof, we've only got to clobber the
+ // non-zero entries in that vector and
+ // store the result
+ //
+ // what we have learned: if entry @p{i}
+ // of the global vector holds the value
+ // @p{v[i]}, then this is the weight with
+ // which the present dof contributes
+ // to @p{i}. there may be several such
+ // @p{i}s and their weights' sum should
+ // be one. Then, @p{v[i]} should be
+ // equal to @p{\sum_j w_{ij} p[j]} with
+ // @p{p[j]} be the values of the degrees
+ // of freedom on the coarse grid. we
+ // can thus compute constraints which
+ // link the degrees of freedom @p{v[i]}
+ // on the fine grid to those on the
+ // coarse grid, @p{p[j]}. Now to use
+ // these as real constraints, rather
+ // than as additional equations, we
+ // have to identify representants
+ // among the @p{i} for each @p{j}. this will
+ // be done by simply taking the first
+ // @p{i} for which @p{w_{ij}==1}.
+ //
+ // guard modification of
+ // the weights array by a
+ // Mutex. since it should
+ // happen rather rarely
+ // that there are several
+ // threads operating on
+ // different intergrid
+ // weights, have only one
+ // mutex for all of them
+ static Threads::ThreadMutex mutex;
+ Threads::ThreadMutex::ScopedLock lock (mutex);
+ for (unsigned int i=0; i<global_parameter_representation.size(); ++i)
+ // set this weight if it belongs
+ // to a parameter dof.
+ if (weight_mapping[i] != -1)
+ {
+ // only overwrite old
+ // value if not by
+ // zero
+ if (global_parameter_representation(i) != 0)
+ {
+ const unsigned int wi = parameter_dof_indices[local_dof],
+ wj = weight_mapping[i];
+ weights[wi][wj] = global_parameter_representation(i);
+ };
+ }
+ else
+ Assert (global_parameter_representation(i) == 0,
+ ExcInternalError());
+ }
+ }
+ }
- /**
- * This is a helper function that
- * is used in the computation of
- * integrid constraints. See the
- * function for a thorough
- * description of how it works.
- */
- template <int dim, int spacedim>
- void
- compute_intergrid_weights_2 (
- const dealii::DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- const std::vector<dealii::Vector<double> > ¶meter_dofs,
- const std::vector<int> &weight_mapping,
- std::vector<std::map<unsigned int,float> > &weights)
- {
- // simply distribute the range of
- // cells to different threads
- typedef typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator active_cell_iterator;
- std::vector<std::pair<active_cell_iterator,active_cell_iterator> >
- cell_intervals = Threads::split_range<active_cell_iterator> (coarse_grid.begin_active(),
- coarse_grid.end(),
- multithread_info.n_default_threads);
+ /**
+ * This is a helper function that
+ * is used in the computation of
+ * integrid constraints. See the
+ * function for a thorough
+ * description of how it works.
+ */
+ template <int dim, int spacedim>
+ void
+ compute_intergrid_weights_2 (
+ const dealii::DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ const std::vector<dealii::Vector<double> > ¶meter_dofs,
+ const std::vector<int> &weight_mapping,
+ std::vector<std::map<unsigned int,float> > &weights)
+ {
+ // simply distribute the range of
+ // cells to different threads
+ typedef typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator active_cell_iterator;
+ std::vector<std::pair<active_cell_iterator,active_cell_iterator> >
+ cell_intervals = Threads::split_range<active_cell_iterator> (coarse_grid.begin_active(),
+ coarse_grid.end(),
+ multithread_info.n_default_threads);
//TODO: use WorkStream here
- Threads::TaskGroup<> tasks;
- void (*fun_ptr) (const dealii::DoFHandler<dim,spacedim> &,
- const unsigned int ,
- const InterGridMap<dealii::DoFHandler<dim,spacedim> > &,
- const std::vector<dealii::Vector<double> > &,
- const std::vector<int> &,
- std::vector<std::map<unsigned int, float> > &,
- const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &,
- const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &)
- = &compute_intergrid_weights_3<dim>;
- for (unsigned int i=0; i<multithread_info.n_default_threads; ++i)
- tasks += Threads::new_task (fun_ptr,
- coarse_grid, coarse_component,
- coarse_to_fine_grid_map, parameter_dofs,
- weight_mapping, weights,
- cell_intervals[i].first,
- cell_intervals[i].second);
-
- // wait for the tasks to finish
- tasks.join_all ();
+ Threads::TaskGroup<> tasks;
+ void (*fun_ptr) (const dealii::DoFHandler<dim,spacedim> &,
+ const unsigned int ,
+ const InterGridMap<dealii::DoFHandler<dim,spacedim> > &,
+ const std::vector<dealii::Vector<double> > &,
+ const std::vector<int> &,
+ std::vector<std::map<unsigned int, float> > &,
+ const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &,
+ const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &)
+ = &compute_intergrid_weights_3<dim>;
+ for (unsigned int i=0; i<multithread_info.n_default_threads; ++i)
+ tasks += Threads::new_task (fun_ptr,
+ coarse_grid, coarse_component,
+ coarse_to_fine_grid_map, parameter_dofs,
+ weight_mapping, weights,
+ cell_intervals[i].first,
+ cell_intervals[i].second);
+
+ // wait for the tasks to finish
+ tasks.join_all ();
+ }
}
}
-}
-template <int dim, int spacedim>
-void
-DoFTools::compute_intergrid_constraints (
- const DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const DoFHandler<dim,spacedim> &fine_grid,
- const unsigned int fine_component,
- const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- ConstraintMatrix &constraints)
-{
- // store the weights with which a dof
- // on the parameter grid contributes
- // to a dof on the fine grid. see the
- // long doc below for more info
- //
- // allocate as many rows as there are
- // parameter dofs on the coarse grid
- // and as many columns as there are
- // parameter dofs on the fine grid.
- //
- // weight_mapping is used to map the
- // global (fine grid) parameter dof
- // indices to the columns
- //
- // in the original implementation,
- // the weights array was actually
- // of FullMatrix<double> type. this
- // wasted huge amounts of memory,
- // but was fast. nonetheless, since
- // the memory consumption was
- // quadratic in the number of
- // degrees of freedom, this was not
- // very practical, so we now use a
- // vector of rows of the matrix,
- // and in each row a vector of
- // pairs (colnum,value). this seems
- // like the best tradeoff between
- // memory and speed, as it is now
- // linear in memory and still fast
- // enough.
- //
- // to save some memory and since
- // the weights are usually
- // (negative) powers of 2, we
- // choose the value type of the
- // matrix to be @p{float} rather
- // than @p{double}.
- std::vector<std::map<unsigned int, float> > weights;
-
- // this is this mapping. there is one
- // entry for each dof on the fine grid;
- // if it is a parameter dof, then its
- // value is the column in weights for
- // that parameter dof, if it is any
- // other dof, then its value is -1,
- // indicating an error
- std::vector<int> weight_mapping;
-
- const unsigned int n_parameters_on_fine_grid
- = internal::compute_intergrid_weights_1 (coarse_grid, coarse_component,
- fine_grid, fine_component,
- coarse_to_fine_grid_map,
- weights, weight_mapping);
-
- // global numbers of dofs
- const unsigned int n_coarse_dofs = coarse_grid.n_dofs(),
- n_fine_dofs = fine_grid.n_dofs();
-
-
- // get an array in which we store
- // which dof on the coarse grid is
- // a parameter and which is not
- std::vector<bool> coarse_dof_is_parameter (coarse_grid.n_dofs());
- if (true)
- {
- std::vector<bool> mask (coarse_grid.get_fe().n_components(),
- false);
- mask[coarse_component] = true;
- extract_dofs (coarse_grid, mask, coarse_dof_is_parameter);
- };
-
- // now we know that the weights in
- // each row constitute a
- // constraint. enter this into the
- // constraints object
- //
- // first task: for each parameter
- // dof on the parameter grid, find
- // a representant on the fine,
- // global grid. this is possible
- // since we use conforming finite
- // element. we take this
- // representant to be the first
- // element in this row with weight
- // identical to one. the
- // representant will become an
- // unconstrained degree of freedom,
- // while all others will be
- // constrained to this dof (and
- // possibly others)
- std::vector<int> representants(n_coarse_dofs, -1);
- for (unsigned int parameter_dof=0; parameter_dof<n_coarse_dofs;
- ++parameter_dof)
- if (coarse_dof_is_parameter[parameter_dof] == true)
- {
- // if this is the line of a
- // parameter dof on the
- // coarse grid, then it
- // should have at least one
- // dependent node on the fine
- // grid
- Assert (weights[parameter_dof].size() > 0, ExcInternalError());
-
- // find the column where the
- // representant is mentioned
- std::map<unsigned int,float>::const_iterator i = weights[parameter_dof].begin();
- for (; i!=weights[parameter_dof].end(); ++i)
- if (i->second == 1)
- break;
- Assert (i!=weights[parameter_dof].end(), ExcInternalError());
- const unsigned int column = i->first;
-
- // now we know in which column of
- // weights the representant is, but
- // we don't know its global index. get
- // it using the inverse operation of
- // the weight_mapping
- unsigned int global_dof=0;
- for (; global_dof<weight_mapping.size(); ++global_dof)
- if (weight_mapping[global_dof] == static_cast<int>(column))
- break;
- Assert (global_dof < weight_mapping.size(), ExcInternalError());
-
- // now enter the representants global
- // index into our list
- representants[parameter_dof] = global_dof;
- }
- else
+ template <int dim, int spacedim>
+ void
+ compute_intergrid_constraints (
+ const DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const DoFHandler<dim,spacedim> &fine_grid,
+ const unsigned int fine_component,
+ const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ ConstraintMatrix &constraints)
+ {
+ // store the weights with which a dof
+ // on the parameter grid contributes
+ // to a dof on the fine grid. see the
+ // long doc below for more info
+ //
+ // allocate as many rows as there are
+ // parameter dofs on the coarse grid
+ // and as many columns as there are
+ // parameter dofs on the fine grid.
+ //
+ // weight_mapping is used to map the
+ // global (fine grid) parameter dof
+ // indices to the columns
+ //
+ // in the original implementation,
+ // the weights array was actually
+ // of FullMatrix<double> type. this
+ // wasted huge amounts of memory,
+ // but was fast. nonetheless, since
+ // the memory consumption was
+ // quadratic in the number of
+ // degrees of freedom, this was not
+ // very practical, so we now use a
+ // vector of rows of the matrix,
+ // and in each row a vector of
+ // pairs (colnum,value). this seems
+ // like the best tradeoff between
+ // memory and speed, as it is now
+ // linear in memory and still fast
+ // enough.
+ //
+ // to save some memory and since
+ // the weights are usually
+ // (negative) powers of 2, we
+ // choose the value type of the
+ // matrix to be @p{float} rather
+ // than @p{double}.
+ std::vector<std::map<unsigned int, float> > weights;
+
+ // this is this mapping. there is one
+ // entry for each dof on the fine grid;
+ // if it is a parameter dof, then its
+ // value is the column in weights for
+ // that parameter dof, if it is any
+ // other dof, then its value is -1,
+ // indicating an error
+ std::vector<int> weight_mapping;
+
+ const unsigned int n_parameters_on_fine_grid
+ = internal::compute_intergrid_weights_1 (coarse_grid, coarse_component,
+ fine_grid, fine_component,
+ coarse_to_fine_grid_map,
+ weights, weight_mapping);
+
+ // global numbers of dofs
+ const unsigned int n_coarse_dofs = coarse_grid.n_dofs(),
+ n_fine_dofs = fine_grid.n_dofs();
+
+
+ // get an array in which we store
+ // which dof on the coarse grid is
+ // a parameter and which is not
+ std::vector<bool> coarse_dof_is_parameter (coarse_grid.n_dofs());
+ if (true)
{
- // consistency check: if this
- // is no parameter dof on the
- // coarse grid, then the
- // respective row must be
- // empty!
- Assert (weights[parameter_dof].size() == 0, ExcInternalError());
+ std::vector<bool> mask (coarse_grid.get_fe().n_components(),
+ false);
+ mask[coarse_component] = true;
+ extract_dofs (coarse_grid, mask, coarse_dof_is_parameter);
};
+ // now we know that the weights in
+ // each row constitute a
+ // constraint. enter this into the
+ // constraints object
+ //
+ // first task: for each parameter
+ // dof on the parameter grid, find
+ // a representant on the fine,
+ // global grid. this is possible
+ // since we use conforming finite
+ // element. we take this
+ // representant to be the first
+ // element in this row with weight
+ // identical to one. the
+ // representant will become an
+ // unconstrained degree of freedom,
+ // while all others will be
+ // constrained to this dof (and
+ // possibly others)
+ std::vector<int> representants(n_coarse_dofs, -1);
+ for (unsigned int parameter_dof=0; parameter_dof<n_coarse_dofs;
+ ++parameter_dof)
+ if (coarse_dof_is_parameter[parameter_dof] == true)
+ {
+ // if this is the line of a
+ // parameter dof on the
+ // coarse grid, then it
+ // should have at least one
+ // dependent node on the fine
+ // grid
+ Assert (weights[parameter_dof].size() > 0, ExcInternalError());
+
+ // find the column where the
+ // representant is mentioned
+ std::map<unsigned int,float>::const_iterator i = weights[parameter_dof].begin();
+ for (; i!=weights[parameter_dof].end(); ++i)
+ if (i->second == 1)
+ break;
+ Assert (i!=weights[parameter_dof].end(), ExcInternalError());
+ const unsigned int column = i->first;
+
+ // now we know in which column of
+ // weights the representant is, but
+ // we don't know its global index. get
+ // it using the inverse operation of
+ // the weight_mapping
+ unsigned int global_dof=0;
+ for (; global_dof<weight_mapping.size(); ++global_dof)
+ if (weight_mapping[global_dof] == static_cast<int>(column))
+ break;
+ Assert (global_dof < weight_mapping.size(), ExcInternalError());
+ // now enter the representants global
+ // index into our list
+ representants[parameter_dof] = global_dof;
+ }
+ else
+ {
+ // consistency check: if this
+ // is no parameter dof on the
+ // coarse grid, then the
+ // respective row must be
+ // empty!
+ Assert (weights[parameter_dof].size() == 0, ExcInternalError());
+ };
- // note for people that want to
- // optimize this function: the
- // largest part of the computing
- // time is spent in the following,
- // rather innocent block of
- // code. basically, it must be the
- // ConstraintMatrix::add_entry call
- // which takes the bulk of the
- // time, but it is not known to the
- // author how to make it faster...
- std::vector<std::pair<unsigned int,double> > constraint_line;
- for (unsigned int global_dof=0; global_dof<n_fine_dofs; ++global_dof)
- if (weight_mapping[global_dof] != -1)
- // this global dof is a parameter
- // dof, so it may carry a constraint
- // note that for each global dof,
- // the sum of weights shall be one,
- // so we can find out whether this
- // dof is constrained in the following
- // way: if the only weight in this row
- // is a one, and the representant for
- // the parameter dof of the line in
- // which this one is is the present
- // dof, then we consider this dof
- // to be unconstrained. otherwise,
- // all other dofs are constrained
- {
- const unsigned int col = weight_mapping[global_dof];
- Assert (col < n_parameters_on_fine_grid, ExcInternalError());
- unsigned int first_used_row=0;
+ // note for people that want to
+ // optimize this function: the
+ // largest part of the computing
+ // time is spent in the following,
+ // rather innocent block of
+ // code. basically, it must be the
+ // ConstraintMatrix::add_entry call
+ // which takes the bulk of the
+ // time, but it is not known to the
+ // author how to make it faster...
+ std::vector<std::pair<unsigned int,double> > constraint_line;
+ for (unsigned int global_dof=0; global_dof<n_fine_dofs; ++global_dof)
+ if (weight_mapping[global_dof] != -1)
+ // this global dof is a parameter
+ // dof, so it may carry a constraint
+ // note that for each global dof,
+ // the sum of weights shall be one,
+ // so we can find out whether this
+ // dof is constrained in the following
+ // way: if the only weight in this row
+ // is a one, and the representant for
+ // the parameter dof of the line in
+ // which this one is is the present
+ // dof, then we consider this dof
+ // to be unconstrained. otherwise,
+ // all other dofs are constrained
{
- Assert (weights.size() > 0, ExcInternalError());
- std::map<unsigned int,float>::const_iterator
- col_entry = weights[0].end();
- for (; first_used_row<n_coarse_dofs; ++first_used_row)
- {
- col_entry = weights[first_used_row].find(col);
- if (col_entry != weights[first_used_row].end())
- break;
- }
-
- Assert (col_entry != weights[first_used_row].end(), ExcInternalError());
-
- if ((col_entry->second == 1) &&
- (representants[first_used_row] == static_cast<int>(global_dof)))
- // dof unconstrained or
- // constrained to itself
- // (in case this cell is
- // mapped to itself, rather
- // than to children of
- // itself)
- continue;
- }
+ const unsigned int col = weight_mapping[global_dof];
+ Assert (col < n_parameters_on_fine_grid, ExcInternalError());
+ unsigned int first_used_row=0;
- // otherwise enter all constraints
- constraints.add_line (global_dof);
-
- constraint_line.clear ();
- for (unsigned int row=first_used_row; row<n_coarse_dofs; ++row)
{
- const std::map<unsigned int,float>::const_iterator
- j = weights[row].find(col);
- if ((j != weights[row].end()) && (j->second != 0))
- constraint_line.push_back (std::make_pair(representants[row],
- j->second));
- };
+ Assert (weights.size() > 0, ExcInternalError());
+ std::map<unsigned int,float>::const_iterator
+ col_entry = weights[0].end();
+ for (; first_used_row<n_coarse_dofs; ++first_used_row)
+ {
+ col_entry = weights[first_used_row].find(col);
+ if (col_entry != weights[first_used_row].end())
+ break;
+ }
- constraints.add_entries (global_dof, constraint_line);
- };
-}
+ Assert (col_entry != weights[first_used_row].end(), ExcInternalError());
+
+ if ((col_entry->second == 1) &&
+ (representants[first_used_row] == static_cast<int>(global_dof)))
+ // dof unconstrained or
+ // constrained to itself
+ // (in case this cell is
+ // mapped to itself, rather
+ // than to children of
+ // itself)
+ continue;
+ }
+ // otherwise enter all constraints
+ constraints.add_line (global_dof);
-template <int dim, int spacedim>
-void
-DoFTools::
-compute_intergrid_transfer_representation (
- const DoFHandler<dim,spacedim> &coarse_grid,
- const unsigned int coarse_component,
- const DoFHandler<dim,spacedim> &fine_grid,
- const unsigned int fine_component,
- const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
- std::vector<std::map<unsigned int, float> > &transfer_representation)
-{
- // store the weights with which a dof
- // on the parameter grid contributes
- // to a dof on the fine grid. see the
- // long doc below for more info
- //
- // allocate as many rows as there are
- // parameter dofs on the coarse grid
- // and as many columns as there are
- // parameter dofs on the fine grid.
- //
- // weight_mapping is used to map the
- // global (fine grid) parameter dof
- // indices to the columns
- //
- // in the original implementation,
- // the weights array was actually
- // of FullMatrix<double> type. this
- // wasted huge amounts of memory,
- // but was fast. nonetheless, since
- // the memory consumption was
- // quadratic in the number of
- // degrees of freedom, this was not
- // very practical, so we now use a
- // vector of rows of the matrix,
- // and in each row a vector of
- // pairs (colnum,value). this seems
- // like the best tradeoff between
- // memory and speed, as it is now
- // linear in memory and still fast
- // enough.
- //
- // to save some memory and since
- // the weights are usually
- // (negative) powers of 2, we
- // choose the value type of the
- // matrix to be @p{float} rather
- // than @p{double}.
- std::vector<std::map<unsigned int, float> > weights;
-
- // this is this mapping. there is one
- // entry for each dof on the fine grid;
- // if it is a parameter dof, then its
- // value is the column in weights for
- // that parameter dof, if it is any
- // other dof, then its value is -1,
- // indicating an error
- std::vector<int> weight_mapping;
-
- internal::compute_intergrid_weights_1 (coarse_grid, coarse_component,
- fine_grid, fine_component,
- coarse_to_fine_grid_map,
- weights, weight_mapping);
-
- // now compute the requested
- // representation
- const unsigned int n_global_parm_dofs
- = std::count_if (weight_mapping.begin(), weight_mapping.end(),
- std::bind2nd (std::not_equal_to<int> (), -1));
-
- // first construct the inverse
- // mapping of weight_mapping
- std::vector<unsigned int> inverse_weight_mapping (n_global_parm_dofs,
- DoFHandler<dim,spacedim>::invalid_dof_index);
- for (unsigned int i=0; i<weight_mapping.size(); ++i)
- {
- const unsigned int parameter_dof = weight_mapping[i];
- // if this global dof is a
- // parameter
- if (parameter_dof != numbers::invalid_unsigned_int)
- {
- Assert (parameter_dof < n_global_parm_dofs, ExcInternalError());
- Assert ((inverse_weight_mapping[parameter_dof] == DoFHandler<dim,spacedim>::invalid_dof_index),
- ExcInternalError());
+ constraint_line.clear ();
+ for (unsigned int row=first_used_row; row<n_coarse_dofs; ++row)
+ {
+ const std::map<unsigned int,float>::const_iterator
+ j = weights[row].find(col);
+ if ((j != weights[row].end()) && (j->second != 0))
+ constraint_line.push_back (std::make_pair(representants[row],
+ j->second));
+ };
- inverse_weight_mapping[parameter_dof] = i;
+ constraints.add_entries (global_dof, constraint_line);
};
- };
+ }
- // next copy over weights array
- // and replace respective
- // numbers
- const unsigned int n_rows = weight_mapping.size();
- transfer_representation.clear ();
- transfer_representation.resize (n_rows);
- const unsigned int n_coarse_dofs = coarse_grid.n_dofs();
- for (unsigned int i=0; i<n_coarse_dofs; ++i)
- {
- std::map<unsigned int, float>::const_iterator j = weights[i].begin();
- for (; j!=weights[i].end(); ++j)
- {
- const unsigned int p = inverse_weight_mapping[j->first];
- Assert (p<n_rows, ExcInternalError());
+ template <int dim, int spacedim>
+ void
+ compute_intergrid_transfer_representation (
+ const DoFHandler<dim,spacedim> &coarse_grid,
+ const unsigned int coarse_component,
+ const DoFHandler<dim,spacedim> &fine_grid,
+ const unsigned int fine_component,
+ const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map,
+ std::vector<std::map<unsigned int, float> > &transfer_representation)
+ {
+ // store the weights with which a dof
+ // on the parameter grid contributes
+ // to a dof on the fine grid. see the
+ // long doc below for more info
+ //
+ // allocate as many rows as there are
+ // parameter dofs on the coarse grid
+ // and as many columns as there are
+ // parameter dofs on the fine grid.
+ //
+ // weight_mapping is used to map the
+ // global (fine grid) parameter dof
+ // indices to the columns
+ //
+ // in the original implementation,
+ // the weights array was actually
+ // of FullMatrix<double> type. this
+ // wasted huge amounts of memory,
+ // but was fast. nonetheless, since
+ // the memory consumption was
+ // quadratic in the number of
+ // degrees of freedom, this was not
+ // very practical, so we now use a
+ // vector of rows of the matrix,
+ // and in each row a vector of
+ // pairs (colnum,value). this seems
+ // like the best tradeoff between
+ // memory and speed, as it is now
+ // linear in memory and still fast
+ // enough.
+ //
+ // to save some memory and since
+ // the weights are usually
+ // (negative) powers of 2, we
+ // choose the value type of the
+ // matrix to be @p{float} rather
+ // than @p{double}.
+ std::vector<std::map<unsigned int, float> > weights;
+
+ // this is this mapping. there is one
+ // entry for each dof on the fine grid;
+ // if it is a parameter dof, then its
+ // value is the column in weights for
+ // that parameter dof, if it is any
+ // other dof, then its value is -1,
+ // indicating an error
+ std::vector<int> weight_mapping;
+
+ internal::compute_intergrid_weights_1 (coarse_grid, coarse_component,
+ fine_grid, fine_component,
+ coarse_to_fine_grid_map,
+ weights, weight_mapping);
+
+ // now compute the requested
+ // representation
+ const unsigned int n_global_parm_dofs
+ = std::count_if (weight_mapping.begin(), weight_mapping.end(),
+ std::bind2nd (std::not_equal_to<int> (), -1));
+
+ // first construct the inverse
+ // mapping of weight_mapping
+ std::vector<unsigned int> inverse_weight_mapping (n_global_parm_dofs,
+ DoFHandler<dim,spacedim>::invalid_dof_index);
+ for (unsigned int i=0; i<weight_mapping.size(); ++i)
+ {
+ const unsigned int parameter_dof = weight_mapping[i];
+ // if this global dof is a
+ // parameter
+ if (parameter_dof != numbers::invalid_unsigned_int)
+ {
+ Assert (parameter_dof < n_global_parm_dofs, ExcInternalError());
+ Assert ((inverse_weight_mapping[parameter_dof] == DoFHandler<dim,spacedim>::invalid_dof_index),
+ ExcInternalError());
- transfer_representation[p][i] = j->second;
- };
- };
-}
+ inverse_weight_mapping[parameter_dof] = i;
+ };
+ };
+ // next copy over weights array
+ // and replace respective
+ // numbers
+ const unsigned int n_rows = weight_mapping.size();
+ transfer_representation.clear ();
+ transfer_representation.resize (n_rows);
-template <class DH>
-void
-DoFTools::map_dof_to_boundary_indices (const DH &dof_handler,
- std::vector<unsigned int> &mapping)
-{
- Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
-
- mapping.clear ();
- mapping.insert (mapping.end(), dof_handler.n_dofs(),
- DH::invalid_dof_index);
-
- std::vector<unsigned int> dofs_on_face;
- dofs_on_face.reserve (max_dofs_per_face(dof_handler));
- unsigned int next_boundary_index = 0;
-
- // now loop over all cells and
- // check whether their faces are at
- // the boundary. note that we need
- // not take special care of single
- // lines being at the boundary
- // (using
- // @p{cell->has_boundary_lines}),
- // since we do not support
- // boundaries of dimension dim-2,
- // and so every isolated boundary
- // line is also part of a boundary
- // face which we will be visiting
- // sooner or later
- typename DH::active_cell_iterator cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
- if (cell->at_boundary(f))
- {
- const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
- dofs_on_face.resize (dofs_per_face);
- cell->face(f)->get_dof_indices (dofs_on_face,
- cell->active_fe_index());
- for (unsigned int i=0; i<dofs_per_face; ++i)
- if (mapping[dofs_on_face[i]] == DH::invalid_dof_index)
- mapping[dofs_on_face[i]] = next_boundary_index++;
- }
-
- AssertDimension (next_boundary_index, dof_handler.n_boundary_dofs());
-}
+ const unsigned int n_coarse_dofs = coarse_grid.n_dofs();
+ for (unsigned int i=0; i<n_coarse_dofs; ++i)
+ {
+ std::map<unsigned int, float>::const_iterator j = weights[i].begin();
+ for (; j!=weights[i].end(); ++j)
+ {
+ const unsigned int p = inverse_weight_mapping[j->first];
+ Assert (p<n_rows, ExcInternalError());
+
+ transfer_representation[p][i] = j->second;
+ };
+ };
+ }
-template <class DH>
-void DoFTools::map_dof_to_boundary_indices (
- const DH &dof_handler,
- const std::set<unsigned char> &boundary_indicators,
- std::vector<unsigned int> &mapping)
-{
- Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
- Assert (boundary_indicators.find (255) == boundary_indicators.end(),
- ExcInvalidBoundaryIndicator());
-
- mapping.clear ();
- mapping.insert (mapping.end(), dof_handler.n_dofs(),
- DH::invalid_dof_index);
-
- // return if there is nothing to do
- if (boundary_indicators.size() == 0)
- return;
-
- std::vector<unsigned int> dofs_on_face;
- dofs_on_face.reserve (max_dofs_per_face(dof_handler));
- unsigned int next_boundary_index = 0;
-
- typename DH::active_cell_iterator cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
- if (boundary_indicators.find (cell->face(f)->boundary_indicator()) !=
- boundary_indicators.end())
- {
- const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
- dofs_on_face.resize (dofs_per_face);
- cell->face(f)->get_dof_indices (dofs_on_face, cell->active_fe_index());
- for (unsigned int i=0; i<dofs_per_face; ++i)
- if (mapping[dofs_on_face[i]] == DH::invalid_dof_index)
- mapping[dofs_on_face[i]] = next_boundary_index++;
- }
+ template <class DH>
+ void
+ map_dof_to_boundary_indices (const DH &dof_handler,
+ std::vector<unsigned int> &mapping)
+ {
+ Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
+
+ mapping.clear ();
+ mapping.insert (mapping.end(), dof_handler.n_dofs(),
+ DH::invalid_dof_index);
+
+ std::vector<unsigned int> dofs_on_face;
+ dofs_on_face.reserve (max_dofs_per_face(dof_handler));
+ unsigned int next_boundary_index = 0;
+
+ // now loop over all cells and
+ // check whether their faces are at
+ // the boundary. note that we need
+ // not take special care of single
+ // lines being at the boundary
+ // (using
+ // @p{cell->has_boundary_lines}),
+ // since we do not support
+ // boundaries of dimension dim-2,
+ // and so every isolated boundary
+ // line is also part of a boundary
+ // face which we will be visiting
+ // sooner or later
+ typename DH::active_cell_iterator cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
+ if (cell->at_boundary(f))
+ {
+ const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
+ dofs_on_face.resize (dofs_per_face);
+ cell->face(f)->get_dof_indices (dofs_on_face,
+ cell->active_fe_index());
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ if (mapping[dofs_on_face[i]] == DH::invalid_dof_index)
+ mapping[dofs_on_face[i]] = next_boundary_index++;
+ }
- AssertDimension (next_boundary_index, dof_handler.n_boundary_dofs (boundary_indicators));
-}
+ AssertDimension (next_boundary_index, dof_handler.n_boundary_dofs());
+ }
-template <int dim, int spacedim>
-void
-DoFTools::map_dofs_to_support_points (const Mapping<dim,spacedim> &mapping,
- const DoFHandler<dim,spacedim> &dof_handler,
- std::vector<Point<spacedim> > &support_points)
-{
- const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
-
- // check whether fe has support
- // points
- Assert (dof_handler.get_fe().has_support_points(),
- ExcFEHasNoSupportPoints());
- Assert (support_points.size() == dof_handler.n_dofs(),
- ExcWrongSize (support_points.size(), dof_handler.n_dofs()));
-
- // now loop over all cells and
- // enquire the support points on
- // each of these. use a dummy
- // quadrature formula where the
- // quadrature points are located at
- // the unit support points to
- // enquire the location of the
- // support points in real space
- //
- // the weights of the quadrature
- // rule are set to invalid values
- // by the used constructor.
- Quadrature<dim> q_dummy(dof_handler.get_fe().get_unit_support_points());
- FEValues<dim,spacedim> fe_values (mapping, dof_handler.get_fe(),
- q_dummy, update_quadrature_points);
- typename DoFHandler<dim,spacedim>::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
-
- std::vector<unsigned int> local_dof_indices (dofs_per_cell);
- for (; cell!=endc; ++cell)
- {
- fe_values.reinit (cell);
- cell->get_dof_indices (local_dof_indices);
- const std::vector<Point<spacedim> > & points
- = fe_values.get_quadrature_points ();
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- support_points[local_dof_indices[i]] = points[i];
- };
-}
+ template <class DH>
+ void map_dof_to_boundary_indices (
+ const DH &dof_handler,
+ const std::set<unsigned char> &boundary_indicators,
+ std::vector<unsigned int> &mapping)
+ {
+ Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
+ Assert (boundary_indicators.find (255) == boundary_indicators.end(),
+ ExcInvalidBoundaryIndicator());
+ mapping.clear ();
+ mapping.insert (mapping.end(), dof_handler.n_dofs(),
+ DH::invalid_dof_index);
-template<int dim, int spacedim>
-void
-DoFTools::convert_couplings_to_blocks (
- const DoFHandler<dim,spacedim>& dof_handler,
- const Table<2, Coupling>& table,
- std::vector<Table<2,Coupling> >& tables_by_block)
-{
- const FiniteElement<dim,spacedim>& fe = dof_handler.get_fe();
- const unsigned int nb = fe.n_blocks();
+ // return if there is nothing to do
+ if (boundary_indicators.size() == 0)
+ return;
- tables_by_block.resize(1);
- tables_by_block[0].reinit(nb, nb);
- tables_by_block[0].fill(none);
+ std::vector<unsigned int> dofs_on_face;
+ dofs_on_face.reserve (max_dofs_per_face(dof_handler));
+ unsigned int next_boundary_index = 0;
- for (unsigned int i=0;i<fe.n_components();++i)
- {
- const unsigned int ib = fe.component_to_block_index(i);
- for (unsigned int j=0;j<fe.n_components();++j)
- {
- const unsigned int jb = fe.component_to_block_index(j);
- tables_by_block[0](ib,jb) |= table(i,j);
- }
- }
-}
+ typename DH::active_cell_iterator cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f)
+ if (boundary_indicators.find (cell->face(f)->boundary_indicator()) !=
+ boundary_indicators.end())
+ {
+ const unsigned int dofs_per_face = cell->get_fe().dofs_per_face;
+ dofs_on_face.resize (dofs_per_face);
+ cell->face(f)->get_dof_indices (dofs_on_face, cell->active_fe_index());
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ if (mapping[dofs_on_face[i]] == DH::invalid_dof_index)
+ mapping[dofs_on_face[i]] = next_boundary_index++;
+ }
+ AssertDimension (next_boundary_index,
+ dof_handler.n_boundary_dofs (boundary_indicators));
+ }
-template<int dim, int spacedim>
-void
-DoFTools::convert_couplings_to_blocks (
- const hp::DoFHandler<dim,spacedim>& dof_handler,
- const Table<2, Coupling>& table,
- std::vector<Table<2,Coupling> >& tables_by_block)
-{
- const hp::FECollection<dim>& fe_collection = dof_handler.get_fe();
- tables_by_block.resize(fe_collection.size());
- for (unsigned int f=0;f<fe_collection.size();++f)
- {
- const FiniteElement<dim,spacedim>& fe = fe_collection[f];
- const unsigned int nb = fe.n_blocks();
- tables_by_block[f].reinit(nb, nb);
- tables_by_block[f].fill(none);
- for (unsigned int i=0;i<fe.n_components();++i)
- {
- const unsigned int ib = fe.component_to_block_index(i);
- for (unsigned int j=0;j<fe.n_components();++j)
- {
- const unsigned int jb = fe.component_to_block_index(j);
- tables_by_block[f](ib,jb) |= table(i,j);
- }
- }
- }
-}
+ template <int dim, int spacedim>
+ void
+ map_dofs_to_support_points (const Mapping<dim,spacedim> &mapping,
+ const DoFHandler<dim,spacedim> &dof_handler,
+ std::vector<Point<spacedim> > &support_points)
+ {
+ const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
+
+ // check whether fe has support
+ // points
+ Assert (dof_handler.get_fe().has_support_points(),
+ ExcFEHasNoSupportPoints());
+ Assert (support_points.size() == dof_handler.n_dofs(),
+ ExcWrongSize (support_points.size(), dof_handler.n_dofs()));
+
+ // now loop over all cells and
+ // enquire the support points on
+ // each of these. use a dummy
+ // quadrature formula where the
+ // quadrature points are located at
+ // the unit support points to
+ // enquire the location of the
+ // support points in real space
+ //
+ // the weights of the quadrature
+ // rule are set to invalid values
+ // by the used constructor.
+ Quadrature<dim> q_dummy(dof_handler.get_fe().get_unit_support_points());
+ FEValues<dim,spacedim> fe_values (mapping, dof_handler.get_fe(),
+ q_dummy, update_quadrature_points);
+ typename DoFHandler<dim,spacedim>::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+
+ std::vector<unsigned int> local_dof_indices (dofs_per_cell);
+ for (; cell!=endc; ++cell)
+ {
+ fe_values.reinit (cell);
+ cell->get_dof_indices (local_dof_indices);
+ const std::vector<Point<spacedim> > & points
+ = fe_values.get_quadrature_points ();
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ support_points[local_dof_indices[i]] = points[i];
+ };
+ }
+ template<int dim, int spacedim>
+ void
+ convert_couplings_to_blocks (
+ const DoFHandler<dim,spacedim>& dof_handler,
+ const Table<2, Coupling>& table,
+ std::vector<Table<2,Coupling> >& tables_by_block)
+ {
+ const FiniteElement<dim,spacedim>& fe = dof_handler.get_fe();
+ const unsigned int nb = fe.n_blocks();
-template <int dim, int spacedim, template <int,int> class DH>
-void
-DoFTools::make_zero_boundary_constraints (const DH<dim, spacedim> &dof,
- ConstraintMatrix &zero_boundary_constraints,
- const std::vector<bool> &component_mask_)
-{
- Assert ((component_mask_.size() == 0) ||
- (component_mask_.size() == dof.get_fe().n_components()),
- ExcMessage ("The number of components in the mask has to be either "
- "zero or equal to the number of components in the finite "
- "element."));
-
- const unsigned int n_components = DoFTools::n_components(dof);
-
- // set the component mask to either
- // the original value or a vector
- // of trues
- const std::vector<bool> component_mask ((component_mask_.size() == 0) ?
- std::vector<bool> (n_components, true) :
- component_mask_);
- Assert (std::count(component_mask.begin(), component_mask.end(), true) > 0,
- VectorTools::ExcNoComponentSelected());
-
- // a field to store the indices
- std::vector<unsigned int> face_dofs;
- face_dofs.reserve (DoFTools::max_dofs_per_face(dof));
-
- typename DH<dim,spacedim>::active_cell_iterator
- cell = dof.begin_active(),
- endc = dof.end();
- for (; cell!=endc; ++cell)
- for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell;
- ++face_no)
+ tables_by_block.resize(1);
+ tables_by_block[0].reinit(nb, nb);
+ tables_by_block[0].fill(none);
+
+ for (unsigned int i=0;i<fe.n_components();++i)
{
- const FiniteElement<dim,spacedim> &fe = cell->get_fe();
+ const unsigned int ib = fe.component_to_block_index(i);
+ for (unsigned int j=0;j<fe.n_components();++j)
+ {
+ const unsigned int jb = fe.component_to_block_index(j);
+ tables_by_block[0](ib,jb) |= table(i,j);
+ }
+ }
+ }
+
+
+ template<int dim, int spacedim>
+ void
+ convert_couplings_to_blocks (
+ const hp::DoFHandler<dim,spacedim>& dof_handler,
+ const Table<2, Coupling>& table,
+ std::vector<Table<2,Coupling> >& tables_by_block)
+ {
+ const hp::FECollection<dim>& fe_collection = dof_handler.get_fe();
+ tables_by_block.resize(fe_collection.size());
- typename DH<dim,spacedim>::face_iterator face = cell->face(face_no);
- if (face->boundary_indicator () == 0)
- // face is of the right component
+ for (unsigned int f=0;f<fe_collection.size();++f)
+ {
+ const FiniteElement<dim,spacedim>& fe = fe_collection[f];
+
+ const unsigned int nb = fe.n_blocks();
+ tables_by_block[f].reinit(nb, nb);
+ tables_by_block[f].fill(none);
+ for (unsigned int i=0;i<fe.n_components();++i)
{
- // get indices and physical
- // location on this face
- face_dofs.resize (fe.dofs_per_face);
- face->get_dof_indices (face_dofs, cell->active_fe_index());
-
- // enter those dofs into the list
- // that match the component
- // signature.
- for (unsigned int i=0; i<face_dofs.size(); ++i)
+ const unsigned int ib = fe.component_to_block_index(i);
+ for (unsigned int j=0;j<fe.n_components();++j)
{
- // Find out if a dof
- // has a contribution
- // in this component,
- // and if so, add it
- // to the list
- const std::vector<bool> &nonzero_component_array
- = cell->get_fe().get_nonzero_components (i);
- bool nonzero = false;
- for (unsigned int c=0; c<n_components; ++c)
- if (nonzero_component_array[c] && component_mask[c])
- {
- nonzero = true;
- break;
- }
-
- if (nonzero)
- zero_boundary_constraints.add_line (face_dofs[i]);
+ const unsigned int jb = fe.component_to_block_index(j);
+ tables_by_block[f](ib,jb) |= table(i,j);
}
}
}
+ }
+
+
+
+ template <int dim, int spacedim, template <int,int> class DH>
+ void
+ make_zero_boundary_constraints (const DH<dim, spacedim> &dof,
+ ConstraintMatrix &zero_boundary_constraints,
+ const std::vector<bool> &component_mask_)
+ {
+ Assert ((component_mask_.size() == 0) ||
+ (component_mask_.size() == dof.get_fe().n_components()),
+ ExcMessage ("The number of components in the mask has to be either "
+ "zero or equal to the number of components in the finite "
+ "element."));
+
+ const unsigned int n_components = DoFTools::n_components(dof);
+
+ // set the component mask to either
+ // the original value or a vector
+ // of trues
+ const std::vector<bool> component_mask ((component_mask_.size() == 0) ?
+ std::vector<bool> (n_components, true) :
+ component_mask_);
+ Assert (std::count(component_mask.begin(), component_mask.end(), true) > 0,
+ VectorTools::ExcNoComponentSelected());
+
+ // a field to store the indices
+ std::vector<unsigned int> face_dofs;
+ face_dofs.reserve (max_dofs_per_face(dof));
+
+ typename DH<dim,spacedim>::active_cell_iterator
+ cell = dof.begin_active(),
+ endc = dof.end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell;
+ ++face_no)
+ {
+ const FiniteElement<dim,spacedim> &fe = cell->get_fe();
+
+ typename DH<dim,spacedim>::face_iterator face = cell->face(face_no);
+ if (face->boundary_indicator () == 0)
+ // face is of the right component
+ {
+ // get indices and physical
+ // location on this face
+ face_dofs.resize (fe.dofs_per_face);
+ face->get_dof_indices (face_dofs, cell->active_fe_index());
+
+ // enter those dofs into the list
+ // that match the component
+ // signature.
+ for (unsigned int i=0; i<face_dofs.size(); ++i)
+ {
+ // Find out if a dof
+ // has a contribution
+ // in this component,
+ // and if so, add it
+ // to the list
+ const std::vector<bool> &nonzero_component_array
+ = cell->get_fe().get_nonzero_components (i);
+ bool nonzero = false;
+ for (unsigned int c=0; c<n_components; ++c)
+ if (nonzero_component_array[c] && component_mask[c])
+ {
+ nonzero = true;
+ break;
+ }
+
+ if (nonzero)
+ zero_boundary_constraints.add_line (face_dofs[i]);
+ }
+ }
+ }
+ }
}