* into new degree of freedom indices.
*
*
- * @sect3{Boundaries}
- *
- * When projecting the traces of functions to the boundary or parts thereof, one
- * needs to built matrices and vectors with the degrees of freedom on the
- * boundary. What is needed in this case is a numbering of the boundary degrees
- * of freedom, starting from zero on and not considering the degrees of freedom
- * in the interior. The @p{map_dof_to_boundary_indices} function does exactly
- * this, by providing a vector with as many entries as there are degrees of
- * freedom on the whole domain, with each entry being the number in the
- * numbering of the boundary or @p{-1} if the dof is not on the boundary. You
- * should always use this function to get the mapping between local (boundary)
- * and the global numbers, for example to build the mass matrix on the
- * boundary, or to get the global index of a degree of freedom if we want to
- * use the solution of the projection onto the boundary to eliminate the
- * boundary degrees of freedom from the global matrix.
- *
- * The algorithm to provide this numbering mapping is simple, but you should
- * not rely on it since it may be changed sometimes: we loop over all faces,
- * check whether it is on the boundary, if so get the global numbers of the
- * degrees of freedom on that face, and for each of these we give a
- * subsequent boundary number if none has already been given to this dof.
- * But it should be emphasized again that you should not try to use this
- * internal knowledge about the used algorithm, you are better off if you
- * just accept the mapping `as is'.
- *
- * Actually, there are two @p{map_dof_to_boundary_indices} functions, one
- * producing a numbering for all boundary degrees of freedom and one producing
- * a numbering for only parts of the boundary, namely those parts for which
- * the boundary indicator is listed in a set of indicators given to the
- * function. The latter case is needed if, for example, we would only want to
- * project the boundary values for the Dirichlet part of the boundary, not for
- * the other boundary conditions. You then give the function a list of boundary
- * indicators referring to Dirichlet parts on which the projection is to be
- * performed. The parts of the boundary on which you want to project need not
- * be contiguous; however, it is not guaranteed that the indices of each of the
- * boundary parts are continuous, i.e. the indices of degrees of freedom on
- * different parts may be intermixed.
- *
- * Degrees of freedom on the boundary but not on one of the specified
- * boundary parts are given the index @p{invalid_dof_index}, as if they
- * were in the interior. If no boundary indicator was given or if no
- * face of a cell has a boundary indicator contained in the given
- * list, the vector of new indices consists solely of @p{invalid_dof_index}s.
- *
- * The question what a degree of freedom on the boundary is, is not so easy.
- * It should really be a degree of freedom of which the respective basis
- * function has nonzero values on the boundary. At least for Lagrange elements
- * this definition is equal to the statement that the off-point of the trial
- * function, i.e. the point where the function assumes its nominal value (for
- * Lagrange elements this is the point where it has the function value @p{1}), is
- * located on the boundary. We do not check this directly, the criterion is
- * rather defined through the information the finite element class gives: the
- * @ref{FiniteElementBase} class defines the numbers of basis functions per vertex,
- * per line, and so on and the basis functions are numbered after this
- * information; a basis function is to be considered to be on the face of a
- * cell (and thus on the boundary if the cell is at the boundary) according
- * to its belonging to a vertex, line, etc but not to the cell. The finite
- * element uses the same cell-wise numbering so that we can say that if a
- * degree of freedom was numbered as one of the dofs on lines, we assume that
- * it is located on the line. Where the off-point actually is, is a secret of
- * the finite element (well, you can ask it, but we don't do it here) and not
- * relevant in this context.
- *
*
* @author Wolfgang Bangerth, 1998
*/
*/
unsigned int max_couplings_between_boundary_dofs () const;
- /**
- * Create a mapping from degree
- * of freedom indices to the
- * index of that degree of
- * freedom on the boundary. After
- * this operation, @p{mapping[dof]}
- * gives the index of the 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
- * @p{mapping[dof]} 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.
- *
- * This function is not implemented for
- * one dimension. See the general doc
- * for more information on boundary
- * treatment.
- */
- void map_dof_to_boundary_indices (vector<unsigned int> &mapping) const;
-
- /**
- * Same as the previous function, except
- * that only selected parts of the
- * boundary are considered.
- *
- * See the general doc of this class for
- * more information.
- */
- void map_dof_to_boundary_indices (const FunctionMap &boundary_indicators,
- vector<unsigned int> &mapping) const;
-
/**
* @name Cell iterator functions
*/
#include <base/exceptions.h>
#include <vector>
+#include <map>
class SparsityPattern;
template <typename number> class Vector;
template <typename number> class FullMatrix;
+template <int dim> class Function;
template <int dim> class DoFHandler;
template <int dim> class MGDoFHandler;
class ConstraintMatrix;
template <template <int> class GridClass, int dim> class InterGridMap;
+
+
/**
* This is a collection of functions operating on, and manipulating
* the numbers of degrees of freedom. The documentation of the member
* All member functions are static, so there is no need to create an
* object of class @ref{DoFTools}.
*
+ *
* @sect3{Setting up sparsity patterns}
*
* When assembling system matrices, the entries are usually of the form
* other basis functions on a cell adjacent to the boundary vanish at the
* boundary itself, except for those which are located on the boundary.
*
+ *
+ *
+ * @sect3{DoF numberings on boundaries}
+ *
+ * When projecting the traces of functions to the boundary or parts
+ * thereof, one needs to build matrices and vectors with the degrees
+ * of freedom on the boundary. What is needed in this case is a
+ * numbering of the boundary degrees of freedom, starting from zero on
+ * and not considering the degrees of freedom in the interior. The
+ * @p{map_dof_to_boundary_indices} function does exactly this, by
+ * providing a vector with as many entries as there are degrees of
+ * freedom on the whole domain, with each entry being the number in
+ * the numbering of the boundary or
+ * @ref{DoFHandler}@p{::invalid_dof_index} if the dof is not on the
+ * boundary. You should always use this function to get the mapping
+ * between local (boundary) and the global numbers, for example to
+ * build the mass matrix on the boundary, or to get the global index
+ * of a degree of freedom if we want to use the solution of the
+ * projection onto the boundary to eliminate the boundary degrees of
+ * freedom from the global matrix.
+ *
+ * The algorithm to provide this numbering mapping is simple, but you
+ * should not rely on it since it may be changed sometimes: we loop
+ * over all faces, check whether it is on the boundary, if so get the
+ * global numbers of the degrees of freedom on that face, and for each
+ * of these we give a subsequent boundary number if none has already
+ * been given to this dof. But it should be emphasized again that you
+ * should not try to use this internal knowledge about the used
+ * algorithm, you are better off if you just accept the mapping `as
+ * is'.
+ *
+ * Actually, there are two @p{map_dof_to_boundary_indices} functions,
+ * one producing a numbering for all boundary degrees of freedom and
+ * one producing a numbering for only parts of the boundary, namely
+ * those parts for which the boundary indicator is listed in a set of
+ * indicators given to the function. The latter case is needed if, for
+ * example, we would only want to project the boundary values for the
+ * Dirichlet part of the boundary, not for the other boundary
+ * conditions. You then give the function a list of boundary
+ * indicators referring to Dirichlet parts on which the projection is
+ * to be performed. The parts of the boundary on which you want to
+ * project need not be contiguous; however, it is not guaranteed that
+ * the indices of each of the boundary parts are continuous, i.e. the
+ * indices of degrees of freedom on different parts may be intermixed.
+ *
+ * Degrees of freedom on the boundary but not on one of the specified
+ * boundary parts are given the index @p{invalid_dof_index}, as if
+ * they were in the interior. If no boundary indicator was given or if
+ * no face of a cell has a boundary indicator contained in the given
+ * list, the vector of new indices consists solely of
+ * @p{invalid_dof_index}s.
+ *
+ * The question what a degree of freedom on the boundary is, is not so
+ * easy. It should really be a degree of freedom of which the
+ * respective basis function has nonzero values on the boundary. At
+ * least for Lagrange elements this definition is equal to the
+ * statement that the off-point of the trial function, i.e. the point
+ * where the function assumes its nominal value (for Lagrange elements
+ * this is the point where it has the function value @p{1}), is
+ * located on the boundary. We do not check this directly, the
+ * criterion is rather defined through the information the finite
+ * element class gives: the @ref{FiniteElementBase} class defines the
+ * numbers of basis functions per vertex, per line, and so on and the
+ * basis functions are numbered after this information; a basis
+ * function is to be considered to be on the face of a cell (and thus
+ * on the boundary if the cell is at the boundary) according to its
+ * belonging to a vertex, line, etc but not to the cell. The finite
+ * element uses the same cell-wise numbering so that we can say that
+ * if a degree of freedom was numbered as one of the dofs on lines, we
+ * assume that it is located on the line. Where the off-point actually
+ * is, is a secret of the finite element (well, you can ask it, but we
+ * don't do it here) and not relevant in this context.
+ *
+ *
* @author Wolfgang Bangerth and others, 1998, 1999, 2000
*/
class DoFTools
const InterGridMap<DoFHandler,dim> &coarse_to_fine_grid_map,
ConstraintMatrix &constraints);
+ /**
+ * Create a mapping from degree
+ * of freedom indices to the
+ * index of that degree of
+ * freedom on the boundary. After
+ * this operation, @p{mapping[dof]}
+ * gives the index of the 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
+ * @p{mapping[dof]} 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.
+ *
+ * This function is not
+ * implemented for one
+ * dimension. See the general doc
+ * of this class for more
+ * information on boundary
+ * treatment.
+ */
+ template <int dim>
+ static void
+ map_dof_to_boundary_indices (const DoFHandler<dim> &dof_handler,
+ vector<unsigned int> &mapping);
+
+ /**
+ * Same as the previous function, except
+ * that only selected parts of the
+ * boundary are considered.
+ *
+ * See the general doc of this class for
+ * more information.
+ */
+ template <int dim>
+ static void
+ map_dof_to_boundary_indices (const DoFHandler<dim> &dof_handler,
+ const map<unsigned char,const Function<dim>*> &boundary_indicators,
+ vector<unsigned int> &mapping);
+
/**
* Exception
* Exception
*/
DeclException0 (ExcGridsDontMatch);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcNoFESelected);
+ /**
+ * Exception
+ */
+ DeclException0 (ExcInvalidBoundaryIndicator);
};
#endif
-#if deal_II_dimension == 1
-
-template <>
-void DoFHandler<1>::map_dof_to_boundary_indices (vector<unsigned int> &) const {
- Assert (selected_fe != 0, ExcNoFESelected());
- Assert (false, ExcNotImplemented());
-};
-
-
-template <>
-void DoFHandler<1>::map_dof_to_boundary_indices (const FunctionMap &,
- vector<unsigned int> &) const {
- Assert (selected_fe != 0, ExcNoFESelected());
- Assert (false, ExcNotImplemented());
-};
-
-#endif
-
-
-template <int dim>
-void DoFHandler<dim>::map_dof_to_boundary_indices (vector<unsigned int> &mapping) const
-{
- Assert (selected_fe != 0, ExcNoFESelected());
-
- mapping.clear ();
- mapping.insert (mapping.end(), n_dofs(), invalid_dof_index);
-
- const unsigned int dofs_per_face = selected_fe->dofs_per_face;
- vector<unsigned int> dofs_on_face(dofs_per_face);
- unsigned int next_boundary_index = 0;
-
- active_face_iterator face = begin_active_face(),
- endf = end_face();
- for (; face!=endf; ++face)
- if (face->at_boundary())
- {
- face->get_dof_indices (dofs_on_face);
- for (unsigned int i=0; i<dofs_per_face; ++i)
- if (mapping[dofs_on_face[i]] == invalid_dof_index)
- mapping[dofs_on_face[i]] = next_boundary_index++;
- };
-
- Assert (next_boundary_index == n_boundary_dofs(),
- ExcInternalError());
-};
-
-
-template <int dim>
-void DoFHandler<dim>::map_dof_to_boundary_indices (const FunctionMap &boundary_indicators,
- vector<unsigned int> &mapping) const
-{
- Assert (selected_fe != 0, ExcNoFESelected());
- Assert (boundary_indicators.find(255) == boundary_indicators.end(),
- ExcInvalidBoundaryIndicator());
-
- mapping.clear ();
- mapping.insert (mapping.end(), n_dofs(), invalid_dof_index);
-
- // return if there is nothing to do
- if (boundary_indicators.size() == 0)
- return;
-
- const unsigned int dofs_per_face = selected_fe->dofs_per_face;
- vector<unsigned int> dofs_on_face(dofs_per_face);
- unsigned int next_boundary_index = 0;
-
- active_face_iterator face = begin_active_face(),
- endf = end_face();
- for (; face!=endf; ++face)
- if (boundary_indicators.find(face->boundary_indicator()) !=
- boundary_indicators.end())
- {
- face->get_dof_indices (dofs_on_face);
- for (unsigned int i=0; i<dofs_per_face; ++i)
- if (mapping[dofs_on_face[i]] == invalid_dof_index)
- mapping[dofs_on_face[i]] = next_boundary_index++;
- };
-
- Assert (next_boundary_index == n_boundary_dofs(boundary_indicators),
- ExcInternalError());
-};
-
#if deal_II_dimension == 1
+#if deal_II_dimension == 1
+
+template <>
+void DoFTools::map_dof_to_boundary_indices (const DoFHandler<1> &dof_handler,
+ vector<unsigned int> &)
+{
+ Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
+ Assert (false, ExcNotImplemented());
+};
+
+
+
+template <>
+void DoFTools::map_dof_to_boundary_indices (const DoFHandler<1> &dof_handler,
+ const map<unsigned char,const Function<1>*> &,
+ vector<unsigned int> &)
+{
+ Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
+ Assert (false, ExcNotImplemented());
+};
+
+
+#else
+
+
+template <int dim>
+void DoFTools::map_dof_to_boundary_indices (const DoFHandler<dim> &dof_handler,
+ vector<unsigned int> &mapping)
+{
+ Assert (&dof_handler.get_fe() != 0, ExcNoFESelected());
+
+ mapping.clear ();
+ mapping.insert (mapping.end(), dof_handler.n_dofs(),
+ DoFHandler<dim>::invalid_dof_index);
+
+ const unsigned int dofs_per_face = dof_handler.get_fe().dofs_per_face;
+ vector<unsigned int> dofs_on_face(dofs_per_face);
+ unsigned int next_boundary_index = 0;
+
+ typename DoFHandler<dim>::active_face_iterator face = dof_handler.begin_active_face(),
+ endf = dof_handler.end_face();
+ for (; face!=endf; ++face)
+ if (face->at_boundary())
+ {
+ face->get_dof_indices (dofs_on_face);
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ if (mapping[dofs_on_face[i]] == DoFHandler<dim>::invalid_dof_index)
+ mapping[dofs_on_face[i]] = next_boundary_index++;
+ };
+
+ Assert (next_boundary_index == dof_handler.n_boundary_dofs(),
+ ExcInternalError());
+};
+
+
+
+template <int dim>
+void DoFTools::map_dof_to_boundary_indices (const DoFHandler<dim> &dof_handler,
+ const map<unsigned char,const Function<dim>*> &boundary_indicators,
+ 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(),
+ DoFHandler<dim>::invalid_dof_index);
+
+ // return if there is nothing to do
+ if (boundary_indicators.size() == 0)
+ return;
+
+ const unsigned int dofs_per_face = dof_handler.get_fe().dofs_per_face;
+ vector<unsigned int> dofs_on_face(dofs_per_face);
+ unsigned int next_boundary_index = 0;
+
+ typename DoFHandler<dim>::active_face_iterator face = dof_handler.begin_active_face(),
+ endf = dof_handler.end_face();
+ for (; face!=endf; ++face)
+ if (boundary_indicators.find(face->boundary_indicator()) !=
+ boundary_indicators.end())
+ {
+ face->get_dof_indices (dofs_on_face);
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ if (mapping[dofs_on_face[i]] == DoFHandler<dim>::invalid_dof_index)
+ mapping[dofs_on_face[i]] = next_boundary_index++;
+ };
+
+ Assert (next_boundary_index == dof_handler.n_boundary_dofs(boundary_indicators),
+ ExcInternalError());
+};
+
+#endif
+
// explicit instantiations
const unsigned int ,
const InterGridMap<DoFHandler,deal_II_dimension> &,
ConstraintMatrix &);
+
+
+
+#if deal_II_dimension != 1
+
+template
+void
+DoFTools::map_dof_to_boundary_indices (const DoFHandler<deal_II_dimension> &,
+ vector<unsigned int> &);
+
+template
+void
+DoFTools::map_dof_to_boundary_indices (const DoFHandler<deal_II_dimension> &,
+ const map<unsigned char,const Function<deal_II_dimension>*> &,
+ vector<unsigned int> &);
+
+#endif
#include <cmath>
-inline double sqr (const double x) {
+static inline double sqr (const double x)
+{
return x*x;
};
+
template <int dim>
-inline double sqr_point (const Tensor<1,dim> &p) {
+inline double sqr_point (const Tensor<1,dim> &p)
+{
return p * p;
};
+
template <int dim>
void VectorTools::interpolate (const DoFHandler<dim> &dof,
const Function<dim> &function,
}
+
template <int dim> void
VectorTools::interpolate (const DoFHandler<dim> &dof_1,
const DoFHandler<dim> &dof_2,
};
+
template <int dim>
void VectorTools::create_right_hand_side (const DoFHandler<dim> &dof_handler,
const Quadrature<dim> &quadrature,
};
+
#if deal_II_dimension == 1
template <>
}
+
template <int dim>
void
VectorTools::project_boundary_values (const DoFHandler<dim> &dof,
- const map<unsigned char,const Function<dim>*> &boundary_functions,
+ const map<unsigned char,const Function<dim>*> &boundary_functions,
const Quadrature<dim-1> &q,
map<unsigned int,double> &boundary_values)
{
ExcComponentMismatch());
vector<unsigned int> dof_to_boundary_mapping;
- dof.map_dof_to_boundary_indices (boundary_functions, dof_to_boundary_mapping);
+ DoFTools::map_dof_to_boundary_indices (dof, boundary_functions,
+ dof_to_boundary_mapping);
// set up sparsity structure
SparsityPattern sparsity(dof.n_boundary_dofs(boundary_functions),
};
+
template <int dim>
void
VectorTools::integrate_difference (const DoFHandler<dim> &dof,
+
// the following two functions are not derived from a template in 1d
// and thus need no explicit instantiation
#if deal_II_dimension > 1
<h3>deal.II</h3>
<ol>
+ <li> <p>
+ Changed: The
+ <code class="member">map_dof_to_boundary_index</code>
+ functions have been moved from the <code class="class">DoFHandler</code>
+ to the <code class="class">DoFTools</code> class, in order to
+ further remove code from the big classes which is necessarily
+ needed there.
+ <br>
+ (WB 2000/08/25)
+ </p>
+
<li> <p>
New: there is now a class <code class="class">DataOutRotation</code>
that can be used to output data which has been computed