// $Id$
// Version: $Name$
//
-// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
DEAL_II_NAMESPACE_OPEN
+
+
+/**
+ * A class that provides possible choices for isotropic and
+ * anisotropic refinement flags in the current space dimension.
+ *
+ * This general template is unused except in some weird template
+ * constructs. Actual is made, however, of the specializations
+ * <code>RefinementPossibilities@<1@></code>,
+ * <code>RefinementPossibilities@<2@></code>, and
+ * <code>RefinementPossibilities@<3@></code>.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2005, Wolfgang Bangerth, 2007
+ */
+template <int dim>
+struct RefinementPossibilities
+{
+ /**
+ * Possible values for refinement
+ * cases in the current
+ * dimension.
+ *
+ * Note the construction of the
+ * values: the lowest bit
+ * describes a cut of the x-axis,
+ * the second to lowest bit
+ * corresponds to a cut of the
+ * y-axis and the third to lowest
+ * bit corresponds to a cut of
+ * the z-axis. Thus, the
+ * following relations hold
+ * (among others):
+ *
+ * @code
+ * cut_xy == cut_x | cut_y
+ * cut_xyz == cut_xy | cut_xz
+ * cut_x == cut_xy & cut_xz
+ * @endcode
+ *
+ * Only those cuts that are
+ * reasonable in a given space
+ * dimension are offered, of
+ * course.
+ *
+ * In addition, the tag
+ * <code>isotropic_refinement</code>
+ * denotes isotropic refinement
+ * in the space dimension
+ * selected by the template
+ * argument of this class.
+ */
+ enum Possibilities
+ {
+ no_refinement= 0,
+
+ isotropic_refinement = static_cast<unsigned char>(-1)
+ };
+};
+
+
+
+/**
+ * A class that provides possible choices for isotropic and
+ * anisotropic refinement flags in the current space dimension.
+ *
+ * This specialization is used for <code>dim=1</code>, where it offers
+ * refinement in x-direction.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2005, Wolfgang Bangerth, 2007
+ */
+template <>
+struct RefinementPossibilities<1>
+{
+ /**
+ * Possible values for refinement
+ * cases in the current
+ * dimension.
+ *
+ * Note the construction of the
+ * values: the lowest bit
+ * describes a cut of the x-axis,
+ * the second to lowest bit
+ * corresponds to a cut of the
+ * y-axis and the third to lowest
+ * bit corresponds to a cut of
+ * the z-axis. Thus, the
+ * following relations hold
+ * (among others):
+ *
+ * @code
+ * cut_xy == cut_x | cut_y
+ * cut_xyz == cut_xy | cut_xz
+ * cut_x == cut_xy & cut_xz
+ * @endcode
+ *
+ * Only those cuts that are
+ * reasonable in a given space
+ * dimension are offered, of
+ * course.
+ *
+ * In addition, the tag
+ * <code>isotropic_refinement</code>
+ * denotes isotropic refinement
+ * in the space dimension
+ * selected by the template
+ * argument of this class.
+ */
+ enum Possibilities
+ {
+ no_refinement= 0,
+ cut_x = 1,
+
+ isotropic_refinement = cut_x
+ };
+};
+
+
+
+/**
+ * A class that provides possible choices for isotropic and
+ * anisotropic refinement flags in the current space dimension.
+ *
+ * This specialization is used for <code>dim=2</code>, where it offers
+ * refinement in x- and y-direction separately, as well as isotropic
+ * refinement in both directions at the same time.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2005, Wolfgang Bangerth, 2007
+ */
+template <>
+struct RefinementPossibilities<2>
+{
+ /**
+ * Possible values for refinement
+ * cases in the current
+ * dimension.
+ *
+ * Note the construction of the
+ * values: the lowest bit
+ * describes a cut of the x-axis,
+ * the second to lowest bit
+ * corresponds to a cut of the
+ * y-axis and the third to lowest
+ * bit corresponds to a cut of
+ * the z-axis. Thus, the
+ * following relations hold
+ * (among others):
+ *
+ * @code
+ * cut_xy == cut_x | cut_y
+ * cut_xyz == cut_xy | cut_xz
+ * cut_x == cut_xy & cut_xz
+ * @endcode
+ *
+ * Only those cuts that are
+ * reasonable in a given space
+ * dimension are offered, of
+ * course.
+ *
+ * In addition, the tag
+ * <code>isotropic_refinement</code>
+ * denotes isotropic refinement
+ * in the space dimension
+ * selected by the template
+ * argument of this class.
+ */
+ enum Possibilities
+ {
+ no_refinement= 0,
+ cut_x = 1,
+ cut_y = 2,
+ cut_xy = cut_x | cut_y,
+
+ isotropic_refinement = cut_xy
+ };
+};
+
+
+
+/**
+ * A class that provides possible choices for isotropic and
+ * anisotropic refinement flags in the current space dimension.
+ *
+ * This specialization is used for <code>dim=3</code>, where it offers
+ * refinement in x-, y- and z-direction separately, as well as
+ * combinations of these and isotropic refinement in all directions at
+ * the same time.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2005, Wolfgang Bangerth, 2007
+ */
+template <>
+struct RefinementPossibilities<3>
+{
+ /**
+ * Possible values for refinement
+ * cases in the current
+ * dimension.
+ *
+ * Note the construction of the
+ * values: the lowest bit
+ * describes a cut of the x-axis,
+ * the second to lowest bit
+ * corresponds to a cut of the
+ * y-axis and the third to lowest
+ * bit corresponds to a cut of
+ * the z-axis. Thus, the
+ * following relations hold
+ * (among others):
+ *
+ * @code
+ * cut_xy == cut_x | cut_y
+ * cut_xyz == cut_xy | cut_xz
+ * cut_x == cut_xy & cut_xz
+ * @endcode
+ *
+ * Only those cuts that are
+ * reasonable in a given space
+ * dimension are offered, of
+ * course.
+ *
+ * In addition, the tag
+ * <code>isotropic_refinement</code>
+ * denotes isotropic refinement
+ * in the space dimension
+ * selected by the template
+ * argument of this class.
+ */
+ enum Possibilities
+ {
+ no_refinement= 0,
+ cut_x = 1,
+ cut_y = 2,
+ cut_xy = cut_x | cut_y,
+ cut_z = 4,
+ cut_xz = cut_x | cut_z,
+ cut_yz = cut_y | cut_z,
+ cut_xyz = cut_x | cut_y | cut_z,
+
+ isotropic_refinement = cut_xyz
+ };
+};
+
+
+
+/**
+ * A class storing the possible anisotropic and isotropic refinement
+ * cases of an object with <code>dim</code> dimensions (for example,
+ * for a line <code>dim=1</code> in whatever space dimension we are,
+ * for a quad <code>dim=2</code>, etc.). Possible values of this class
+ * are the ones listed in the enumeration declared within the class.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2005, Wolfgang Bangerth, 2007
+ */
+template <int dim>
+class RefinementCase : public RefinementPossibilities<dim>
+{
+ public:
+ /**
+ * Constructor. Take and store a
+ * value indicating a particular
+ * refinement from the list of
+ * possible refinements specified
+ * in the base class.
+ */
+ RefinementCase (const typename RefinementPossibilities<dim>::Possibilities refinement_case);
+
+ /**
+ * Constructor. Take and store a
+ * value indicating a particular
+ * refinement as a bit field. To
+ * avoid implicit conversions to
+ * and from integral values, this
+ * constructor is marked as
+ * explicit.
+ */
+ explicit RefinementCase (const unsigned char refinement_case);
+
+ /**
+ * Return the numeric value
+ * stored by this class. While
+ * the presence of this operator
+ * might seem dangerous, it is
+ * useful in cases where one
+ * would like to have code like
+ * <tt>switch
+ * (refinement_flag)... case
+ * RefinementCase<dim>::cut_x:
+ * ... </tt>, which can be
+ * written as <code>switch
+ * (static_cast@<unsigned
+ * char@>(refinement_flag)</code>. Another
+ * application is to use an
+ * object of the current type as
+ * an index into an array;
+ * however, this use is
+ * deprecated as it assumes a
+ * certain mapping from the
+ * symbolic flags defined in the
+ * RefinementPossibilities base
+ * class to actual numerical
+ * values (the array indices).
+ */
+ operator unsigned char () const;
+
+ /**
+ * Return the union of the
+ * refinement flags represented
+ * by the current object and the
+ * one given as argument.
+ */
+ RefinementCase operator | (const RefinementCase &r) const;
+
+ /**
+ * Return the intersection of the
+ * refinement flags represented
+ * by the current object and the
+ * one given as argument.
+ */
+ RefinementCase operator & (const RefinementCase &r) const;
+
+ /**
+ * Return the negation of the
+ * refinement flags represented
+ * by the current object. For
+ * example, in 2d, if the current
+ * object holds the flag
+ * <code>cut_x</code>, then the
+ * returned value will be
+ * <code>cut_y</code>; if the
+ * current value is
+ * <code>isotropic_refinement</code>
+ * then the result will be
+ * <code>no_refinement</code>;
+ * etc.
+ */
+ RefinementCase operator ~ () const;
+
+
+ /**
+ * Return the flag that
+ * corresponds to cutting a cell
+ * along the axis given as
+ * argument. For example, if
+ * <code>i=0</code> then the
+ * returned value is
+ * <tt>RefinementPossibilities<dim>::cut_x</tt>.
+ */
+ static
+ RefinementCase cut_axis (const unsigned int i);
+
+ /**
+ * Return the amount of memory
+ * occupied by an object of this
+ * type.
+ */
+ static unsigned int memory_consumption ();
+
+ /**
+ * Exception.
+ */
+ DeclException1 (ExcInvalidRefinementCase,
+ int,
+ << "The refinement flags given (" << arg1 << ") contain set bits that do not "
+ << "make sense for the space dimension of the object to which they are applied.");
+
+ private:
+ /**
+ * Store the refinement case as a
+ * bit field with as many bits as
+ * are necessary in any given
+ * dimension.
+ */
+ unsigned char value : (dim > 0 ? dim : 1);
+};
+
+
+
+namespace internal
+{
+
+
+/**
+ * A class that provides all possible situations a face (in the
+ * current space dimension @p dim) might be subdivided into
+ * subfaces. For <code>dim=1</code> and <code>dim=2</code> they
+ * correspond to the cases given in
+ * <code>RefinementPossibilities@<dim-1@></code>. However,
+ * <code>SubfacePossibilities@<3@></code> includes the refinement
+ * cases of <code>RefinementPossibilities@<2@></code>, but
+ * additionally some subface possibilities a face might be subdivided
+ * into which occur through repeated anisotropic refinement steps
+ * performed on one of two neighboring cells.
+ *
+ * This general template is unused except in some weird template
+ * constructs. Actual is made, however, of the specializations
+ * <code>SubfacePossibilities@<1@></code>,
+ * <code>SubfacePossibilities@<2@></code> and
+ * <code>SubfacePossibilities@<3@></code>.
+ *
+ * @ingroup aniso
+ * @author Tobias Leicht 2007, Ralf Hartmann, 2008
+ */
+ template <int dim>
+ struct SubfacePossibilities
+ {
+ /**
+ * Possible cases of faces
+ * being subdivided into
+ * subface.
+ */
+ enum Possibilities
+ {
+ case_none = 0,
+
+ case_isotropic = static_cast<unsigned char>(-1)
+ };
+ };
+
+
+/**
+ * A class that provides all possible situations a face (in the
+ * current space dimension @p dim) might be subdivided into
+ * subfaces.
+ *
+ * For <code>dim=0</code> we provide a dummy implementation only.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2008
+ */
+ template <>
+ struct SubfacePossibilities<0>
+ {
+ /**
+ * Possible cases of faces
+ * being subdivided into
+ * subface.
+ *
+ * Dummy implementation.
+ */
+ enum Possibilities
+ {
+ case_none = 0,
+
+ case_isotropic = case_none
+ };
+ };
+
+
+
+/**
+ * A class that provides all possible situations a face (in the
+ * current space dimension @p dim) might be subdivided into
+ * subfaces.
+ *
+ * For <code>dim=1</code> there are no faces. Thereby, there are no
+ * subface possibilities.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2008
+ */
+ template <>
+ struct SubfacePossibilities<1>
+ {
+ /**
+ * Possible cases of faces
+ * being subdivided into
+ * subface.
+ *
+ * In 1d there are no faces,
+ * thus no subface
+ * possibilities.
+ */
+ enum Possibilities
+ {
+ case_none = 0,
+
+ case_isotropic = case_none
+ };
+ };
+
+
+
+/**
+ * A class that provides all possible situations a face (in the
+ * current space dimension @p dim) might be subdivided into
+ * subfaces.
+ *
+ * This specialization is used for <code>dim=2</code>, where it offers
+ * the following possibilities: a face (line) being refined
+ * (<code>case_x</code>) or not refined (<code>case_no</code>).
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2008
+ */
+ template <>
+ struct SubfacePossibilities<2>
+ {
+ /**
+ * Possible cases of faces
+ * being subdivided into
+ * subface.
+ *
+ * In 2d there are following
+ * possibilities: a face (line)
+ * being refined *
+ * (<code>case_x</code>) or not
+ * refined
+ * (<code>case_no</code>).
+ */
+ enum Possibilities
+ {
+ case_none = 0,
+ case_x = 1,
+
+ case_isotropic = case_x
+ };
+ };
+
+
+
+/**
+ * A class that provides all possible situations a face (in the
+ * current space dimension @p dim) might be subdivided into
+ * subfaces.
+ *
+ * This specialization is used for dim=3, where it offers following
+ * possibilities: a face (quad) being refined in x- or y-direction (in
+ * the face-intern coordinate system) separately, (<code>case_x</code>
+ * or (<code>case_y</code>), and in both directions
+ * (<code>case_x</code> which corresponds to
+ * (<code>case_isotropic</code>). Additionally, it offers the
+ * possibilities a face can have through repeated anisotropic
+ * refinement steps performed on one of the two neighboring cells. It
+ * might be possible for example, that a face (quad) is refined with
+ * <code>cut_x</code> and afterwards the left child is again refined
+ * with <code>cut_y</code>, so that there are three active
+ * subfaces. Note, however, that only refinement cases are allowed
+ * such that each line on a face between two hexes has not more than
+ * one hanging node. Furthermore, it is not allowed that two
+ * neighboring hexes are refined such that one of the hexes refines
+ * the common face with <code>cut_x</code> and the other hex refines
+ * that face with <code>cut_y</code>. In fact,
+ * Triangulation::prepare_coarsening_and_refinement takes care of this
+ * situation and ensures that each face of a refined cell is
+ * completely contained in a single face of neighboring cells.
+ *
+ * The following drawings explain the SubfacePossibilities and give
+ * the corresponding subface numbers:
+ * @code
+
+ *-------*
+ | |
+ | 0 | case_none
+ | |
+ *-------*
+
+ *---*---*
+ | | |
+ | 0 | 1 | case_x
+ | | |
+ *---*---*
+
+ *---*---*
+ | 1 | |
+ *---* 2 | case_x1y
+ | 0 | |
+ *---*---*
+
+ *---*---*
+ | | 2 |
+ | 0 *---* case_x2y
+ | | 1 |
+ *---*---*
+
+ *---*---*
+ | 1 | 3 |
+ *---*---* case_x1y2y (successive refinement: first cut_x, then cut_y for both children)
+ | 0 | 2 |
+ *---*---*
+
+ *-------*
+ | 1 |
+ *-------* case_y
+ | 0 |
+ *-------*
+
+ *-------*
+ | 2 |
+ *---*---* case_y1x
+ | 0 | 1 |
+ *---*---*
+
+ *---*---*
+ | 1 | 2 |
+ *---*---* case_y2x
+ | 0 |
+ *-------*
+
+ *---*---*
+ | 2 | 3 |
+ *---*---* case_y1x2x (successive refinement: first cut_y, then cut_x for both children)
+ | 0 | 1 |
+ *---+---*
+
+ *---*---*
+ | 2 | 3 |
+ *---*---* case_xy (one isotropic refinement step)
+ | 0 | 1 |
+ *---*---*
+
+ * @endcode
+ *
+ * @ingroup aniso
+ * @author Tobias Leicht 2007, Ralf Hartmann, 2008
+ */
+ template <>
+ struct SubfacePossibilities<3>
+ {
+ /**
+ * Possible cases of faces
+ * being subdivided into
+ * subface.
+ *
+ * See documentation to the
+ * SubfacePossibilities<3> for
+ * more details on the subface
+ * possibilities.
+ */
+ enum Possibilities
+ {
+ case_none = 0,
+ case_x = 1,
+ case_x1y = 2,
+ case_x2y = 3,
+ case_x1y2y = 4,
+ case_y = 5,
+ case_y1x = 6,
+ case_y2x = 7,
+ case_y1x2x = 8,
+ case_xy = 9,
+
+ case_isotropic = case_xy
+ };
+ };
+
+
+
+
+/**
+ * A class that provides all possible cases a face (in the
+ * current space dimension @p dim) might be subdivided into
+ * subfaces.
+ *
+ * @ingroup aniso
+ * @author Ralf Hartmann, 2008
+ */
+ template <int dim>
+ class SubfaceCase : public SubfacePossibilities<dim>
+ {
+ public:
+ /**
+ * Constructor. Take and store
+ * a value indicating a
+ * particular subface
+ * possibility in the list of
+ * possible situations
+ * specified in the base class.
+ */
+ SubfaceCase (const typename SubfacePossibilities<dim>::Possibilities subface_possibility);
+
+ /**
+ * Return the numeric value
+ * stored by this class. While
+ * the presence of this operator
+ * might seem dangerous, it is
+ * useful in cases where one
+ * would like to have code like
+ * <code>switch
+ * (subface_case)... case
+ * SubfaceCase@<dim@>::case_x:
+ * ... </code>, which can be
+ * written as <code>switch
+ * (static_cast@<unsigned
+ * char@>(subface_case)</code>. Another
+ * application is to use an
+ * object of the current type as
+ * an index into an array;
+ * however, this use is
+ * deprecated as it assumes a
+ * certain mapping from the
+ * symbolic flags defined in the
+ * SubfacePossibilities
+ * base class to actual numerical
+ * values (the array indices).
+ */
+ operator unsigned char () const;
+
+ /**
+ * Return the amount of memory
+ * occupied by an object of this
+ * type.
+ */
+ static unsigned int memory_consumption ();
+
+ /**
+ * Exception.
+ */
+ DeclException1 (ExcInvalidSubfaceCase,
+ int,
+ << "The subface case given (" << arg1 << ") does not make sense "
+ << "for the space dimension of the object to which they are applied.");
+
+ private:
+ /**
+ * Store the refinement case as a
+ * bit field with as many bits as
+ * are necessary in any given
+ * dimension.
+ */
+ unsigned char value : (dim == 3 ? 4 : 1);
+ };
+
+} // namespace internal
+
+
+
template <int dim> class GeometryInfo;
* This class contains as static members information on vertices and
* faces of a @p dim-dimensional grid cell. The interface is the same
* for all dimensions. If a value is of no use in a low dimensional
- * cell, it is (correctly) set to zero, e.g. #subfaces_per_face in
+ * cell, it is (correctly) set to zero, e.g. #max_children_per_face in
* 1d.
*
* This information should always replace hard-coded numbers of
* vertices, neighbors and so on, since it can be used dimension
* independently.
*
- * @ingroup grid geomprimitives
+ * @ingroup grid geomprimitives aniso
* @author Wolfgang Bangerth, 1998
*/
template <>
struct GeometryInfo<0>
{
- /**
- * Number of children a cell has.
- */
- static const unsigned int children_per_cell = 1;
+ /**
+ * Maximum number of children of
+ * a cell, i.e. the number of
+ * children of an isotropically
+ * refined cell.
+ *
+ * If a cell is refined
+ * anisotropically, the actual
+ * number of children may be less
+ * than the value given here.
+ */
+ static const unsigned int max_children_per_cell = 1;
/**
* Number of faces a cell has.
*/
static const unsigned int faces_per_cell = 0;
- /**
- * Number of children each face has
- * when the adjacent cell is refined.
- */
- static const unsigned int subfaces_per_face = 0;
+ /**
+ * Maximum number of children of
+ * a refined face, i.e. the
+ * number of children of an
+ * isotropically refined face.
+ *
+ * If a cell is refined
+ * anisotropically, the actual
+ * number of children may be less
+ * than the value given here.
+ */
+ static const unsigned int max_children_per_face = 0;
/**
* Number of vertices a cell has.
*
* <h4>Children</h4>
*
- * The eight children of a cell are numbered according to the vertices they
- * are adjacent to:
+ * The eight children of an isotropically refined cell are numbered according to
+ * the vertices they are adjacent to:
* @verbatim
- * *-------* *-------*
- * /| 6 7 | / 6 7 /|
- * /6| | / /7|
- * / | | / 4 5 / |
- * * | 2 3 | *-------*5 3|
- * |4 2*-------* | 4 5 | *
- * | / 2 3 / | | /
- * |0/ / | |1/
- * |/0 1 / | 0 1 |/
- * *-------* *-------*
+ * *----*----* *----*----*
+ * /| 6 | 7 | / 6 / 7 /|
+ * *6| | | *----*----*7|
+ * /| *----*----* / 4 / 5 /| *
+ * * |/| | | *----*----* |/|
+ * |4* | 2 | 3 | | 4 | 5 |5*3|
+ * |/|2*----*----* | | |/| *
+ * * |/ 2 / 3 / *----*----* |/
+ * |0*----*----* | | |1*
+ * |/0 / 1 / | 0 | 1 |/
+ * *----*----* *----*----*
* @endverbatim
*
* Taking into account the orientation of the faces, the following
* orientation as additional argument to
* <tt>GeometryInfo<3>::child_cell_on_face</tt>).
*
+ * For anisotropic refinement, the child cells can not be numbered according to
+ * adjacent vertices, thus the following conventions are used:
+ * @verbatim
+ * RefinementCase<3>::cut_x
+ *
+ * *----*----* *----*----*
+ * /| | | / / /|
+ * / | | | / 0 / 1 / |
+ * / | 0 | 1 | / / / |
+ * * | | | *----*----* |
+ * | 0 | | | | | | 1 |
+ * | *----*----* | | | *
+ * | / / / | 0 | 1 | /
+ * | / 0 / 1 / | | | /
+ * |/ / / | | |/
+ * *----*----* *----*----*
+ * @endverbatim
+ *
+ * @verbatim
+ * RefinementCase<3>::cut_y
+ *
+ * *---------* *---------*
+ * /| | / 1 /|
+ * * | | *---------* |
+ * /| | 1 | / 0 /| |
+ * * |1| | *---------* |1|
+ * | | | | | | | |
+ * |0| *---------* | |0| *
+ * | |/ 1 / | 0 | |/
+ * | *---------* | | *
+ * |/ 0 / | |/
+ * *---------* *---------*
+ * @endverbatim
+ *
+ * @verbatim
+ * RefinementCase<3>::cut_z
+ *
+ * *---------* *---------*
+ * /| 1 | / /|
+ * / | | / 1 / |
+ * / *---------* / / *
+ * * 1/| | *---------* 1/|
+ * | / | 0 | | 1 | / |
+ * |/ *---------* | |/ *
+ * * 0/ / *---------* 0/
+ * | / 0 / | | /
+ * |/ / | 0 |/
+ * *---------* *---------*
+ * @endverbatim
+ *
+ * @verbatim
+ * RefinementCase<3>::cut_xy
+ *
+ * *----*----* *----*----*
+ * /| | | / 2 / 3 /|
+ * * | | | *----*----* |
+ * /| | 2 | 3 | / 0 / 1 /| |
+ * * |2| | | *----*----* |3|
+ * | | | | | | | | | |
+ * |0| *----*----* | | |1| *
+ * | |/ 2 / 3 / | 0 | 1 | |/
+ * | *----*----* | | | *
+ * |/ 0 / 1 / | | |/
+ * *----*----* *----*----*
+ * @endverbatim
+ *
+ * @verbatim
+ * RefinementCase<3>::cut_xz
+ *
+ * *----*----* *----*----*
+ * /| 1 | 3 | / / /|
+ * / | | | / 1 / 3 / |
+ * / *----*----* / / / *
+ * * 1/| | | *----*----* 3/|
+ * | / | 0 | 2 | | 1 | 3 | / |
+ * |/ *----*----* | | |/ *
+ * * 0/ / / *----*----* 2/
+ * | / 0 / 2 / | | | /
+ * |/ / / | 0 | 2 |/
+ * *----*----* *----*----*
+ * @endverbatim
+ *
+ * @verbatim
+ * RefinementCase<3>::cut_yz
+ *
+ * *---------* *---------*
+ * /| 3 | / 3 /|
+ * * | | *---------* |
+ * /|3*---------* / 2 /|3*
+ * * |/| | *---------* |/|
+ * |2* | 1 | | 2 |2* |
+ * |/|1*---------* | |/|1*
+ * * |/ 1 / *---------* |/
+ * |0*---------* | |0*
+ * |/ 0 / | 0 |/
+ * *---------* *---------*
+ * @endverbatim
+ *
+ * This information can also be obtained by the
+ * <tt>GeometryInfo<3>::child_cell_on_face</tt> function.
+ *
* <h4>Coordinate systems</h4>
*
* We define the following coordinate system for the explicit coordinates of
* and there is a specialization for dim=0 (see the section on @ref
* Instantiations in the manual).
*
- * @ingroup grid geomprimitives
+ * @ingroup grid geomprimitives aniso
* @author Wolfgang Bangerth, 1998, Ralf Hartmann, 2005, Tobias Leicht, 2007
*/
template <int dim>
struct GeometryInfo
{
- /**
- * Number of children of a refined cell.
- */
- static const unsigned int children_per_cell = 1 << dim;
+ /**
+ * Maximum number of children of
+ * a refined cell, i.e. the
+ * number of children of an
+ * isotropically refined cell.
+ *
+ * If a cell is refined
+ * anisotropically, the actual
+ * number of children may be less
+ * than the value given here.
+ */
+ static const unsigned int max_children_per_cell = 1 << dim;
/**
* Number of faces of a cell.
*/
static const unsigned int faces_per_cell = 2 * dim;
- /**
- * Number of children each face has
- * when the adjacent cell is refined.
- */
- static const unsigned int subfaces_per_face = GeometryInfo<dim-1>::children_per_cell;
+ /**
+ * Maximum number of children of
+ * a refined face, i.e. the
+ * number of children of an
+ * isotropically refined face.
+ *
+ * If a cell is refined
+ * anisotropically, the actual
+ * number of children may be less
+ * than the value given here.
+ */
+ static const unsigned int max_children_per_face = GeometryInfo<dim-1>::max_children_per_cell;
/**
* Number of vertices of a cell.
*/
static const unsigned int dx_to_deal[vertices_per_cell];
-
/**
* This field stores for each vertex
* to which faces it belongs. In any
* the vertex belongs
*/
static const unsigned int vertex_to_face[vertices_per_cell][dim];
-
+
+ /**
+ * Return the number of children
+ * of a cell (or face) refined
+ * with <tt>ref_case</tt>.
+ */
+ static unsigned int n_children(const RefinementCase<dim> &refinement_case);
+
+ /**
+ * Return the number of subfaces
+ * of a face refined according to
+ * internal::SubfaceCase
+ * @p face_ref_case.
+ */
+ static unsigned int n_subfaces(const internal::SubfaceCase<dim> &subface_case);
+
+ /**
+ * Given a face on the reference
+ * element with a
+ * <code>internal::SubfaceCase@<dim@></code>
+ * @p face_refinement_case this
+ * function returns the ratio
+ * between the area of the @p
+ * subface_no th subface and the
+ * area(=1) of the face.
+ *
+ * E.g. for
+ * <code>internal::SubfaceCase@<3@>::cut_xy</code>
+ * the ratio is 1/4 for each of
+ * the subfaces.
+ */
+ static double subface_ratio(const internal::SubfaceCase<dim> &subface_case,
+ const unsigned int subface_no);
+
+ /**
+ * Given a cell refined with the
+ * <code>RefinementCase</code>
+ * @p cell_refinement_case
+ * return the
+ * <code>SubfaceCase</code> of
+ * the @p face_no th face.
+ */
+ static RefinementCase<dim-1> face_refinement_case(
+ const RefinementCase<dim> &cell_refinement_case,
+ const unsigned int face_no,
+ const bool face_orientation = true,
+ const bool face_flip = false,
+ const bool face_rotation = false);
+
+ /**
+ * Given the SubfaceCase @p
+ * face_refinement_case of the @p
+ * face_no th face, return the
+ * smallest RefinementCase of the
+ * cell, which corresponds to
+ * that refinement of the face.
+ */
+ static RefinementCase<dim> min_cell_refinement_case_for_face_refinement(
+ const RefinementCase<dim-1> &face_refinement_case,
+ const unsigned int face_no,
+ const bool face_orientation = true,
+ const bool face_flip = false,
+ const bool face_rotation = false);
+
+ /**
+ * Given a cell refined with the
+ * RefinementCase @p
+ * cell_refinement_case return
+ * the RefinementCase of the @p
+ * line_no th face.
+ */
+ static RefinementCase<1> line_refinement_case(const RefinementCase<dim> &cell_refinement_case,
+ const unsigned int line_no);
+
+ /**
+ * Return the minimal / smallest
+ * RefinementCase of the cell, which
+ * ensures refinement of line
+ * @p line_no.
+ */
+ static RefinementCase<dim> min_cell_refinement_case_for_line_refinement(const unsigned int line_no);
+
/**
* This field stores which child
* cells are adjacent to a
* face orientations is explained in this
* @ref GlossFaceOrientation "glossary"
* entry.
+ *
+ * In the case of anisotropically refined
+ * cells and faces, the @p RefineCase of
+ * the face, <tt>face_ref_case</tt>,
+ * might have an influence on
+ * which child is behind which given
+ * subface, thus this is an additional
+ * argument, defaulting to isotropic
+ * refinement of the face.
*/
- static unsigned int child_cell_on_face (const unsigned int face,
+ static unsigned int child_cell_on_face (const RefinementCase<dim> &ref_case,
+ const unsigned int face,
const unsigned int subface,
const bool face_orientation = true,
const bool face_flip = false,
- const bool face_rotation = false);
+ const bool face_rotation = false,
+ const RefinementCase<dim-1> &face_refinement_case = RefinementCase<dim-1>::isotropic_refinement);
/**
* Map line vertex number to cell
* children, return any one of
* their indices. The result is
* always less than
- * GeometryInfo<dimension>::children_per_cell.
+ * GeometryInfo<dimension>::max_children_per_cell.
*
* The order of child cells is described
* the general documentation of this
* child.
*/
static Point<dim> cell_to_child_coordinates (const Point<dim> &p,
- const unsigned int child_index);
+ const unsigned int child_index);
/**
* The reverse function to the
double,
<< "The coordinates must satisfy 0 <= x_i <= 1, "
<< "but here we have x_i=" << arg1);
+
+ /**
+ * Exception
+ */
+ DeclException3 (ExcInvalidSubface,
+ int, int, int,
+ << "RefinementCase<dim> " << arg1 << ": face " << arg2
+ << " has no subface " << arg3);
};
/* -------------- inline functions ------------- */
+namespace internal
+{
+
+ template <int dim>
+ inline
+ SubfaceCase<dim>::SubfaceCase (const typename SubfacePossibilities<dim>::Possibilities subface_possibility)
+ :
+ value (subface_possibility)
+ {}
+
+
+ template <int dim>
+ inline
+ SubfaceCase<dim>::operator unsigned char () const
+ {
+ return value;
+ }
+
+
+} // namespace internal
+
+
+template <int dim>
+inline
+RefinementCase<dim>
+RefinementCase<dim>::cut_axis (const unsigned int)
+{
+ Assert (false, ExcInternalError());
+ return static_cast<unsigned char>(-1);
+}
+
+
+template <>
+inline
+RefinementCase<1>
+RefinementCase<1>::cut_axis (const unsigned int i)
+{
+ const unsigned int dim = 1;
+ Assert (i < dim, ExcIndexRange(i, 0, dim));
+
+ static const RefinementCase options[dim] = { cut_x };
+ return options[i];
+}
+
+
+
+template <>
+inline
+RefinementCase<2>
+RefinementCase<2>::cut_axis (const unsigned int i)
+{
+ const unsigned int dim = 2;
+ Assert (i < dim, ExcIndexRange(i, 0, dim));
+
+ static const RefinementCase options[dim] = { cut_x, cut_y };
+ return options[i];
+}
+
+
+
+template <>
+inline
+RefinementCase<3>
+RefinementCase<3>::cut_axis (const unsigned int i)
+{
+ const unsigned int dim = 3;
+ Assert (i < dim, ExcIndexRange(i, 0, dim));
+
+ static const RefinementCase options[dim] = { cut_x, cut_y, cut_z };
+ return options[i];
+}
+
+
+
+template <int dim>
+inline
+RefinementCase<dim>::RefinementCase (const typename RefinementPossibilities<dim>::Possibilities refinement_case)
+ :
+ value (refinement_case)
+{
+ // check that only those bits of
+ // the given argument are set that
+ // make sense for a given space
+ // dimension
+ Assert ((refinement_case & RefinementPossibilities<dim>::isotropic_refinement) ==
+ refinement_case,
+ ExcInvalidRefinementCase (refinement_case));
+}
+
+
+
+template <int dim>
+inline
+RefinementCase<dim>::RefinementCase (const unsigned char refinement_case)
+ :
+ value (refinement_case)
+{
+ // check that only those bits of
+ // the given argument are set that
+ // make sense for a given space
+ // dimension
+ Assert ((refinement_case & RefinementPossibilities<dim>::isotropic_refinement) ==
+ refinement_case,
+ ExcInvalidRefinementCase (refinement_case));
+}
+
+
+
+template <int dim>
+inline
+RefinementCase<dim>::operator unsigned char () const
+{
+ return value;
+}
+
+
+
+template <int dim>
+inline
+RefinementCase<dim>
+RefinementCase<dim>::operator | (const RefinementCase<dim> &r) const
+{
+ return RefinementCase<dim>(value | r.value);
+}
+
+
+
+template <int dim>
+inline
+RefinementCase<dim>
+RefinementCase<dim>::operator & (const RefinementCase<dim> &r) const
+{
+ return RefinementCase<dim>(value & r.value);
+}
+
+
+
+template <int dim>
+inline
+RefinementCase<dim>
+RefinementCase<dim>::operator ~ () const
+{
+ return RefinementCase<dim>((~value) & RefinementPossibilities<dim>::isotropic_refinement);
+}
+
+
+
+
+template <int dim>
+inline
+unsigned int
+RefinementCase<dim>::memory_consumption ()
+{
+ return sizeof(RefinementCase<dim>);
+}
+
+
+
+
template <>
inline
GeometryInfo<dim>::cell_to_child_coordinates (const Point<dim> &p,
const unsigned int child_index)
{
- Assert (child_index < GeometryInfo<dim>::children_per_cell,
- ExcIndexRange (child_index, 0, GeometryInfo<dim>::children_per_cell));
+ Assert (child_index < GeometryInfo<dim>::max_children_per_cell,
+ ExcIndexRange (child_index, 0, GeometryInfo<dim>::max_children_per_cell));
return 2*p - unit_cell_vertex(child_index);
}
GeometryInfo<dim>::child_to_cell_coordinates (const Point<dim> &p,
const unsigned int child_index)
{
- Assert (child_index < GeometryInfo<dim>::children_per_cell,
- ExcIndexRange (child_index, 0, GeometryInfo<dim>::children_per_cell));
+ Assert (child_index < GeometryInfo<dim>::max_children_per_cell,
+ ExcIndexRange (child_index, 0, GeometryInfo<dim>::max_children_per_cell));
return (p + unit_cell_vertex(child_index))/2;
}
(p[2] >= l) && (p[2] <= u);
}
+
#endif // DOXYGEN
DEAL_II_NAMESPACE_CLOSE
// $Id$
// Version: $Name$
//
-// Copyright (C) 2005, 2006 by the deal.II authors
+// Copyright (C) 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
#include <base/quadrature.h>
+#include <base/geometry_info.h>
DEAL_II_NAMESPACE_OPEN
/*!@addtogroup Quadrature */
const unsigned int face_no);
/**
- * Compute the quadrature points
- * on the cell if the given
- * quadrature formula is used on
- * face <tt>face_no</tt>, subface
- * number <tt>subface_no</tt>.
+ * Compute the quadrature points on the
+ * cell if the given quadrature formula is
+ * used on face <tt>face_no</tt>, subface
+ * number <tt>subface_no</tt> corresponding
+ * to RefineCase::Type
+ * <tt>ref_case</tt>. The last argument is
+ * only used in 3D.
*
* @note Only the points are
* transformed. The quadrature
* weights are the same as those
* of the original rule.
*/
- static void project_to_subface (const SubQuadrature &quadrature,
- const unsigned int face_no,
- const unsigned int subface_no,
- std::vector<Point<dim> > &q_points);
+ static void project_to_subface (const SubQuadrature &quadrature,
+ const unsigned int face_no,
+ const unsigned int subface_no,
+ std::vector<Point<dim> > &q_points,
+ const RefinementCase<dim-1> &ref_case=RefinementCase<dim-1>::isotropic_refinement);
/**
- * Compute the cell quadrature
- * formula corresponding to using
+ * Compute the cell quadrature formula
+ * corresponding to using
* <tt>quadrature</tt> on subface
* <tt>subface_no</tt> of face
- * <tt>face_no</tt>.
+ * <tt>face_no</tt> with
+ * RefinementCase<dim-1>
+ * <tt>ref_case</tt>. The last argument is
+ * only used in 3D.
*
* @note Only the points are
* transformed. The quadrature
* of the original rule.
*/
static Quadrature<dim>
- project_to_subface (const SubQuadrature &quadrature,
- const unsigned int face_no,
- const unsigned int subface_no);
+ project_to_subface (const SubQuadrature &quadrature,
+ const unsigned int face_no,
+ const unsigned int subface_no,
+ const RefinementCase<dim-1> &ref_case=RefinementCase<dim-1>::isotropic_refinement);
/**
* Take a face quadrature formula
* ignored if the space dimension
* equals 2.
*
- * The last argument denotes
+ * The last but one argument denotes
* the number of quadrature
* points the
* lower-dimensional face
* one that has been
* projected onto the faces)
* has.
+ *
+ * Through the last argument
+ * anisotropic refinement can be
+ * respected.
*/
static
DataSetDescriptor
const bool face_orientation,
const bool face_flip,
const bool face_rotation,
- const unsigned int n_quadrature_points);
+ const unsigned int n_quadrature_points,
+ const internal::SubfaceCase<dim> ref_case=internal::SubfaceCase<dim>::case_isotropic);
/**
* Conversion operator to an
QProjector<1>::project_to_subface (const Quadrature<0> &,
const unsigned int,
const unsigned int,
- std::vector<Point<1> > &);
+ std::vector<Point<1> > &,
+ const RefinementCase<0> &);
template <>
void
QProjector<2>::project_to_subface (const Quadrature<1> &quadrature,
const unsigned int face_no,
const unsigned int subface_no,
- std::vector<Point<2> > &q_points);
+ std::vector<Point<2> > &q_points,
+ const RefinementCase<1> &);
template <>
void
-QProjector<3>::project_to_subface (const Quadrature<2> &quadrature,
- const unsigned int face_no,
- const unsigned int subface_no,
- std::vector<Point<3> > &q_points);
+QProjector<3>::project_to_subface (const Quadrature<2> &quadrature,
+ const unsigned int face_no,
+ const unsigned int subface_no,
+ std::vector<Point<3> > &q_points,
+ const RefinementCase<2> &face_ref_case);
template <>
Quadrature<1>
// $Id$
// Version: $Name$
//
-// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by the deal.II authors
+// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
DEAL_II_NAMESPACE_OPEN
-template <int dim> const unsigned int GeometryInfo<dim>::children_per_cell;
+template <int dim> const unsigned int GeometryInfo<dim>::max_children_per_cell;
template <int dim> const unsigned int GeometryInfo<dim>::faces_per_cell;
-template <int dim> const unsigned int GeometryInfo<dim>::subfaces_per_face;
+template <int dim> const unsigned int GeometryInfo<dim>::max_children_per_face;
template <int dim> const unsigned int GeometryInfo<dim>::vertices_per_cell;
template <int dim> const unsigned int GeometryInfo<dim>::vertices_per_face;
template <int dim> const unsigned int GeometryInfo<dim>::lines_per_face;
template <>
const unsigned int GeometryInfo<4>::ucd_to_deal[GeometryInfo<4>::vertices_per_cell]
= { invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int};
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int};
template <>
template <>
const unsigned int GeometryInfo<4>::dx_to_deal[GeometryInfo<4>::vertices_per_cell]
= { invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int,
- invalid_unsigned_int};
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int,
+ invalid_unsigned_int};
template <>
const unsigned int GeometryInfo<1>::vertex_to_face
{ invalid_unsigned_int, invalid_unsigned_int, invalid_unsigned_int, invalid_unsigned_int }};
+template<int dim>
+unsigned int
+GeometryInfo<dim>::n_children(const RefinementCase<dim> &ref_case)
+{
+ static const unsigned int n_children[RefinementCase<3>::cut_xyz+1]=
+ {0, 2, 2, 4, 2, 4, 4, 8};
+
+ return n_children[ref_case];
+}
+
+
+template<>
+unsigned int
+GeometryInfo<1>::n_subfaces(const internal::SubfaceCase<1> &)
+{
+ Assert(false, ExcImpossibleInDim(1));
+ return 0;
+}
+
+
+
+template<>
+unsigned int
+GeometryInfo<2>::n_subfaces(const internal::SubfaceCase<2> &subface_case)
+{
+ return (subface_case == internal::SubfaceCase<2>::case_x) ? 2 : 0;
+}
+
+
+
+template<>
+unsigned int
+GeometryInfo<3>::n_subfaces(const internal::SubfaceCase<3> &subface_case)
+{
+ static const unsigned int nsubs[internal::SubfaceCase<3>::case_isotropic+1]=
+ {0, 2, 3, 3, 4, 2, 3, 3, 4, 4};
+ return nsubs[subface_case];
+}
+
+
+template<>
+double
+GeometryInfo<1>::subface_ratio(const internal::SubfaceCase<1> &,
+ const unsigned int)
+{
+ Assert(false, ExcImpossibleInDim(1));
+ return 1;
+}
+
+
+template<>
+double
+GeometryInfo<2>::subface_ratio(const internal::SubfaceCase<2> &subface_case,
+ const unsigned int)
+{
+ const unsigned int dim=2;
+
+ double ratio=1;
+ switch (subface_case)
+ {
+ case internal::SubfaceCase<dim>::case_none:
+ // Here, an
+ // Assert(false,ExcInternalError())
+ // would be the right
+ // choice, but
+ // unfortunately the
+ // current function is
+ // also called for faces
+ // without children (see
+ // tests/fe/mapping.cc).
+// Assert(false, ExcMessage("Face has no subfaces."));
+ // Furthermore, assign
+ // following value as
+ // otherwise the
+ // bits/volume_x tests
+ // break
+ ratio=1./GeometryInfo<dim>::max_children_per_face;
+ break;
+ case internal::SubfaceCase<dim>::case_x:
+ ratio=0.5;
+ break;
+ default:
+ // there should be no
+ // cases left
+ Assert(false, ExcInternalError());
+ break;
+ }
+
+ return ratio;
+}
+
+
+template<>
+double
+GeometryInfo<3>::subface_ratio(const internal::SubfaceCase<3> &subface_case,
+ const unsigned int subface_no)
+{
+ const unsigned int dim=3;
+
+ double ratio=1;
+ switch (subface_case)
+ {
+ case internal::SubfaceCase<dim>::case_none:
+ // Here, an
+ // Assert(false,ExcInternalError())
+ // would be the right
+ // choice, but
+ // unfortunately the
+ // current function is
+ // also called for faces
+ // without children (see
+ // tests/bits/mesh_3d_16.cc). Add
+ // following switch to
+ // avoid diffs in
+ // tests/bits/mesh_3d_16
+ ratio=1./GeometryInfo<dim>::max_children_per_face;
+ break;
+ case internal::SubfaceCase<dim>::case_x:
+ case internal::SubfaceCase<dim>::case_y:
+ ratio=0.5;
+ break;
+ case internal::SubfaceCase<dim>::case_xy:
+ case internal::SubfaceCase<dim>::case_x1y2y:
+ case internal::SubfaceCase<dim>::case_y1x2x:
+ ratio=0.25;
+ break;
+ case internal::SubfaceCase<dim>::case_x1y:
+ case internal::SubfaceCase<dim>::case_y1x:
+ if (subface_no<2)
+ ratio=0.25;
+ else
+ ratio=0.5;
+ break;
+ case internal::SubfaceCase<dim>::case_x2y:
+ case internal::SubfaceCase<dim>::case_y2x:
+ if (subface_no==0)
+ ratio=0.5;
+ else
+ ratio=0.25;
+ break;
+ default:
+ // there should be no
+ // cases left
+ Assert(false, ExcInternalError());
+ break;
+ }
+
+ return ratio;
+}
+
+
+
+template<>
+RefinementCase<0>
+GeometryInfo<1>::face_refinement_case(const RefinementCase<1> &,
+ const unsigned int,
+ const bool,
+ const bool,
+ const bool)
+{
+ Assert(false, ExcImpossibleInDim(1));
+
+ return RefinementCase<0>::no_refinement;
+}
+
+
+template<>
+RefinementCase<1>
+GeometryInfo<2>::face_refinement_case(const RefinementCase<2> &cell_refinement_case,
+ const unsigned int face_no,
+ const bool,
+ const bool,
+ const bool)
+{
+ const unsigned int dim=2;
+ Assert(cell_refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(cell_refinement_case, 0, RefinementCase<dim>::isotropic_refinement+1));
+ Assert(face_no<GeometryInfo<dim>::faces_per_cell,
+ ExcIndexRange(face_no, 0, GeometryInfo<dim>::faces_per_cell));
+
+ static const RefinementCase<dim-1>
+ ref_cases[RefinementCase<dim>::isotropic_refinement+1][GeometryInfo<dim>::faces_per_cell/2]=
+ {{RefinementCase<dim-1>::no_refinement, // no_refinement
+ RefinementCase<dim-1>::no_refinement},
+
+ {RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::cut_x},
+
+ {RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::no_refinement},
+
+ {RefinementCase<dim-1>::cut_x, // cut_xy
+ RefinementCase<dim-1>::cut_x}
+ };
+
+ return ref_cases[cell_refinement_case][face_no/2];
+}
+
+
+template<>
+RefinementCase<2>
+GeometryInfo<3>::face_refinement_case(const RefinementCase<3> &cell_refinement_case,
+ const unsigned int face_no,
+ const bool face_orientation,
+ const bool /*face_flip*/,
+ const bool face_rotation)
+{
+ const unsigned int dim=3;
+ Assert(cell_refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(cell_refinement_case, 0, RefinementCase<dim>::isotropic_refinement+1));
+ Assert(face_no<GeometryInfo<dim>::faces_per_cell,
+ ExcIndexRange(face_no, 0, GeometryInfo<dim>::faces_per_cell));
+
+ static const RefinementCase<dim-1>
+ ref_cases[RefinementCase<dim>::isotropic_refinement+1][GeometryInfo<dim>::faces_per_cell/2]=
+ {{RefinementCase<dim-1>::no_refinement, // no_refinement
+ RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::no_refinement},
+
+ {RefinementCase<dim-1>::no_refinement, // cut_x
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_x},
+
+ {RefinementCase<dim-1>::cut_x, // cut_y
+ RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::cut_y},
+
+ {RefinementCase<dim-1>::cut_x, // cut_xy
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_xy},
+
+ {RefinementCase<dim-1>::cut_y, // cut_z
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::no_refinement},
+
+ {RefinementCase<dim-1>::cut_y, // cut_xz
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_x},
+
+ {RefinementCase<dim-1>::cut_xy, // cut_yz
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_y},
+
+ {RefinementCase<dim-1>::cut_xy, // cut_xyz
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy},
+ };
+
+ const RefinementCase<dim-1> ref_case=ref_cases[cell_refinement_case][face_no/2];
+
+ static const RefinementCase<dim-1> flip[4]=
+ {RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_xy};
+
+ // correct the ref_case for face_orientation
+ // and face_rotation. for face_orientation,
+ // 'true' is the default value whereas for
+ // face_rotation, 'false' is standard. If
+ // <tt>face_rotation==face_orientation</tt>,
+ // then one of them is non-standard and we
+ // have to swap cut_x and cut_y, otherwise no
+ // change is necessary. face_flip has no
+ // influence. however, in order to keep the
+ // interface consistent with other functions,
+ // we still include it as an argument to this
+ // function
+ return (face_orientation==face_rotation) ? flip[ref_case] : ref_case;
+}
+
+
+
+template<>
+RefinementCase<1>
+GeometryInfo<1>::line_refinement_case(const RefinementCase<1> &cell_refinement_case,
+ const unsigned int line_no)
+{
+ const unsigned int dim = 1;
+ Assert(cell_refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(cell_refinement_case, 0, RefinementCase<dim>::isotropic_refinement+1));
+ Assert(line_no<GeometryInfo<dim>::lines_per_cell,
+ ExcIndexRange(line_no, 0, GeometryInfo<dim>::lines_per_cell));
+
+ return cell_refinement_case;
+}
+
+
+template<>
+RefinementCase<1>
+GeometryInfo<2>::line_refinement_case(const RefinementCase<2> &cell_refinement_case,
+ const unsigned int line_no)
+{
+ // Assertions are in face_refinement_case()
+ return face_refinement_case(cell_refinement_case, line_no);
+}
+
+
+template<>
+RefinementCase<1>
+GeometryInfo<3>::line_refinement_case(const RefinementCase<3> &cell_refinement_case,
+ const unsigned int line_no)
+{
+ const unsigned int dim=3;
+ Assert(cell_refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(cell_refinement_case, 0, RefinementCase<dim>::isotropic_refinement+1));
+ Assert(line_no<GeometryInfo<dim>::lines_per_cell,
+ ExcIndexRange(line_no, 0, GeometryInfo<dim>::lines_per_cell));
+
+ // array indicating, which simple refine
+ // case cuts a line in dirextion x, y or
+ // z. For example, cut_y and everything
+ // containing cut_y (cut_xy, cut_yz,
+ // cut_xyz) cuts lines, which are in y
+ // direction.
+ static const RefinementCase<dim>
+ cut_one[dim] =
+ {RefinementCase<dim>::cut_x,
+ RefinementCase<dim>::cut_y,
+ RefinementCase<dim>::cut_z};
+
+ // order the direction of lines
+ // 0->x, 1->y, 2->z
+ static const unsigned int direction[lines_per_cell]=
+ {1,1,0,0,1,1,0,0,2,2,2,2};
+
+ return ((cell_refinement_case & cut_one[direction[line_no]]) ?
+ RefinementCase<1>::cut_x : RefinementCase<1>::no_refinement);
+}
+
+
+
+template<>
+RefinementCase<1>
+GeometryInfo<1>::min_cell_refinement_case_for_face_refinement(const RefinementCase<0> &,
+ const unsigned int,
+ const bool,
+ const bool,
+ const bool)
+{
+ const unsigned int dim = 1;
+ Assert(false, ExcImpossibleInDim(dim));
+
+ return RefinementCase<dim>::no_refinement;
+}
+
+
+template<>
+RefinementCase<2>
+GeometryInfo<2>::min_cell_refinement_case_for_face_refinement(const RefinementCase<1> &face_refinement_case,
+ const unsigned int face_no,
+ const bool,
+ const bool,
+ const bool)
+{
+ const unsigned int dim = 2;
+ Assert(face_refinement_case<RefinementCase<dim-1>::isotropic_refinement+1,
+ ExcIndexRange(face_refinement_case, 0, RefinementCase<dim-1>::isotropic_refinement+1));
+ Assert(face_no<GeometryInfo<dim>::faces_per_cell,
+ ExcIndexRange(face_no, 0, GeometryInfo<dim>::faces_per_cell));
+
+ if (face_refinement_case==RefinementCase<dim>::cut_x)
+ return (face_no/2) ? RefinementCase<dim>::cut_x : RefinementCase<dim>::cut_y;
+ else
+ return RefinementCase<dim>::no_refinement;
+}
+
+
+template<>
+RefinementCase<3>
+GeometryInfo<3>::min_cell_refinement_case_for_face_refinement(const RefinementCase<2> &face_refinement_case,
+ const unsigned int face_no,
+ const bool face_orientation,
+ const bool /*face_flip*/,
+ const bool face_rotation)
+{
+ const unsigned int dim=3;
+ Assert(face_refinement_case<RefinementCase<dim-1>::isotropic_refinement+1,
+ ExcIndexRange(face_refinement_case, 0, RefinementCase<dim-1>::isotropic_refinement+1));
+ Assert(face_no<GeometryInfo<dim>::faces_per_cell,
+ ExcIndexRange(face_no, 0, GeometryInfo<dim>::faces_per_cell));
+
+ static const RefinementCase<2> flip[4]=
+ {RefinementCase<2>::no_refinement,
+ RefinementCase<2>::cut_y,
+ RefinementCase<2>::cut_x,
+ RefinementCase<2>::cut_xy};
+
+ // correct the face_refinement_case for
+ // face_orientation and face_rotation. for
+ // face_orientation, 'true' is the default
+ // value whereas for face_rotation, 'false'
+ // is standard. If
+ // <tt>face_rotation==face_orientation</tt>,
+ // then one of them is non-standard and we
+ // have to swap cut_x and cut_y, otherwise no
+ // change is necessary. face_flip has no
+ // influence. however, in order to keep the
+ // interface consistent with other functions,
+ // we still include it as an argument to this
+ // function
+ const RefinementCase<dim-1> std_face_ref = (face_orientation==face_rotation) ? flip[face_refinement_case] : face_refinement_case;
+
+ static const RefinementCase<dim> face_to_cell[3][4]=
+ {{RefinementCase<dim>::no_refinement, // faces 0 and 1
+ RefinementCase<dim>::cut_y, // cut_x in face 0 means cut_y for the cell
+ RefinementCase<dim>::cut_z,
+ RefinementCase<dim>::cut_yz},
+
+ {RefinementCase<dim>::no_refinement, // faces 2 and 3 (note that x and y are "exchanged on faces 2 and 3")
+ RefinementCase<dim>::cut_z,
+ RefinementCase<dim>::cut_x,
+ RefinementCase<dim>::cut_xz},
+
+ {RefinementCase<dim>::no_refinement, // faces 4 and 5
+ RefinementCase<dim>::cut_x,
+ RefinementCase<dim>::cut_y,
+ RefinementCase<dim>::cut_xy}};
+
+ return face_to_cell[face_no/2][std_face_ref];
+}
+
+
+
+template<>
+RefinementCase<1>
+GeometryInfo<1>::min_cell_refinement_case_for_line_refinement(const unsigned int line_no)
+{
+ Assert(line_no==0, ExcIndexRange(line_no,0,1));
+
+ return RefinementCase<1>::cut_x;
+}
+
+
+template<>
+RefinementCase<2>
+GeometryInfo<2>::min_cell_refinement_case_for_line_refinement(const unsigned int line_no)
+{
+ const unsigned int dim = 2;
+ Assert(line_no<GeometryInfo<dim>::lines_per_cell,
+ ExcIndexRange(line_no, 0, GeometryInfo<dim>::lines_per_cell));
+
+ return (line_no/2) ? RefinementCase<2>::cut_x : RefinementCase<2>::cut_y;
+}
+
+
+template<>
+RefinementCase<3>
+GeometryInfo<3>::min_cell_refinement_case_for_line_refinement(const unsigned int line_no)
+{
+ const unsigned int dim=3;
+ Assert(line_no<GeometryInfo<dim>::lines_per_cell,
+ ExcIndexRange(line_no, 0, GeometryInfo<dim>::lines_per_cell));
+
+ static const RefinementCase<dim> ref_cases[6]=
+ {RefinementCase<dim>::cut_y, // lines 0 and 1
+ RefinementCase<dim>::cut_x, // lines 2 and 3
+ RefinementCase<dim>::cut_y, // lines 4 and 5
+ RefinementCase<dim>::cut_x, // lines 6 and 7
+ RefinementCase<dim>::cut_z, // lines 8 and 9
+ RefinementCase<dim>::cut_z}; // lines 10 and 11
+
+ return ref_cases[line_no/2];
+}
+
+
+
template <>
unsigned int
GeometryInfo<3>::standard_to_real_face_vertex(const unsigned int vertex,
template <>
unsigned int
-GeometryInfo<1>::child_cell_on_face (const unsigned int face,
+GeometryInfo<1>::child_cell_on_face (const RefinementCase<1> &,
+ const unsigned int face,
const unsigned int subface,
- const bool, const bool, const bool)
+ const bool, const bool, const bool,
+ const RefinementCase<0> &)
{
Assert (face<faces_per_cell, ExcIndexRange(face, 0, faces_per_cell));
- Assert (subface<subfaces_per_face,
- ExcIndexRange(subface, 0, subfaces_per_face));
+ Assert (subface<max_children_per_face,
+ ExcIndexRange(subface, 0, max_children_per_face));
return face;
}
template <>
unsigned int
-GeometryInfo<2>::child_cell_on_face (const unsigned int face,
+GeometryInfo<2>::child_cell_on_face (const RefinementCase<2> &ref_case,
+ const unsigned int face,
const unsigned int subface,
- const bool, const bool, const bool)
+ const bool, const bool, const bool,
+ const RefinementCase<1> &)
{
Assert (face<faces_per_cell, ExcIndexRange(face, 0, faces_per_cell));
- Assert (subface<subfaces_per_face, ExcIndexRange(subface, 0, subfaces_per_face));
+ Assert (subface<max_children_per_face,
+ ExcIndexRange(subface, 0, max_children_per_face));
+
+ // always return the child adjacent to the specified
+ // subface. if the face of a cell is not refined, don't
+ // throw an assertion but deliver the child adjacent to
+ // the face nevertheless, i.e. deliver the child of
+ // this cell adjacent to the subface of a possibly
+ // refined neighbor. this simplifies setting neighbor
+ // information in execute_refinement.
+ static const unsigned int
+ subcells[RefinementCase<2>::isotropic_refinement][faces_per_cell][max_children_per_face] =
+ {{{0,0},{1,1},{0,1},{0,1}}, // cut_x
+ {{0,1},{0,1},{0,0},{1,1}}, // cut_y
+ {{0,2},{1,3},{0,1},{2,3}}}; // cut_xy
- static const unsigned
- subcells[faces_per_cell][subfaces_per_face] = {{0,2},
- {1,3},
- {0,1},
- {2,3}};
-
- return subcells[face][subface];
+ return subcells[ref_case-1][face][subface];
}
template <>
unsigned int
-GeometryInfo<3>::child_cell_on_face (const unsigned int face,
+GeometryInfo<3>::child_cell_on_face (const RefinementCase<3> &ref_case,
+ const unsigned int face,
const unsigned int subface,
const bool face_orientation,
const bool face_flip,
- const bool face_rotation)
+ const bool face_rotation,
+ const RefinementCase<2> &face_ref_case)
{
- Assert (face<faces_per_cell, ExcIndexRange(face, 0, faces_per_cell));
- Assert (subface<subfaces_per_face, ExcIndexRange(subface, 0, subfaces_per_face));
+ const unsigned int dim = 3;
- static const unsigned
- subcells[faces_per_cell][subfaces_per_face] = {{0, 2, 4, 6},
- {1, 3, 5, 7},
- {0, 4, 1, 5},
- {2, 6, 3, 7},
- {0, 1, 2, 3},
- {4, 5, 6, 7}};
- return subcells[face][real_to_standard_face_vertex(subface,
- face_orientation,
- face_flip,
- face_rotation)];
+ Assert (ref_case>RefinementCase<dim-1>::no_refinement, ExcMessage("Cell has no children."));
+ Assert (face<faces_per_cell, ExcIndexRange(face, 0, faces_per_cell));
+ Assert (subface<GeometryInfo<dim-1>::n_children(face_ref_case) ||
+ (subface==0 && face_ref_case==RefinementCase<dim-1>::no_refinement),
+ ExcIndexRange(subface, 0, GeometryInfo<2>::n_children(face_ref_case)));
+
+ // invalid number used for invalid cases,
+ // e.g. when the children are more refined at
+ // a given face than the face itself
+ static const unsigned int e=invalid_unsigned_int;
+
+ // the whole process of finding a child cell
+ // at a given subface considering the
+ // possibly anisotropic refinement cases of
+ // the cell and the face as well as
+ // orientation, flip and rotation of the face
+ // is quite complicated. thus, we break it
+ // down into several steps.
+
+ // first step: convert the given face refine
+ // case to a face refine case concerning the
+ // face in standard orientation (, flip and
+ // rotation). This only affects cut_x and
+ // cut_y
+ static const RefinementCase<dim-1> flip[4]=
+ {RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_xy};
+ // for face_orientation, 'true' is the
+ // default value whereas for face_rotation,
+ // 'false' is standard. If
+ // <tt>face_rotation==face_orientation</tt>,
+ // then one of them is non-standard and we
+ // have to swap cut_x and cut_y, otherwise no
+ // change is necessary.
+ const RefinementCase<dim-1> std_face_ref = (face_orientation==face_rotation) ? flip[face_ref_case] : face_ref_case;
+
+ // second step: convert the given subface
+ // index to the one for a standard face
+ // respecting face_orientation, face_flip and
+ // face_rotation
+
+ // first index: face_ref_case
+ // second index: face_orientation
+ // third index: face_flip
+ // forth index: face_rotation
+ // fifth index: subface index
+ static const unsigned int subface_exchange[4][2][2][2][4]=
+ {
+ // no_refinement (subface 0 stays 0,
+ // all others are invalid)
+ {{{{0,e,e,e},
+ {0,e,e,e}},
+ {{0,e,e,e},
+ {0,e,e,e}}},
+ {{{0,e,e,e},
+ {0,e,e,e}},
+ {{0,e,e,e},
+ {0,e,e,e}}}},
+ // cut_x (here, if the face is only
+ // rotated OR only falsely oriented,
+ // then subface 0 of the non-standard
+ // face does NOT correspond to one of
+ // the subfaces of a standard
+ // face. Thus we indicate the subface
+ // which is located at the lower left
+ // corner (the origin of the face's
+ // local coordinate system) with
+ // '0'. The rest of this issue is
+ // taken care of using the above
+ // conversion to a 'standard face
+ // refine case')
+ {{{{0,1,e,e},
+ {0,1,e,e}},
+ {{1,0,e,e},
+ {1,0,e,e}}},
+ {{{0,1,e,e},
+ {0,1,e,e}},
+ {{1,0,e,e},
+ {1,0,e,e}}}},
+ // cut_y (the same applies as for
+ // cut_x)
+ {{{{0,1,e,e},
+ {1,0,e,e}},
+ {{1,0,e,e},
+ {0,1,e,e}}},
+ {{{0,1,e,e},
+ {1,0,e,e}},
+ {{1,0,e,e},
+ {0,1,e,e}}}},
+ // cut_xyz: this information is
+ // identical to the information
+ // returned by
+ // GeometryInfo<3>::real_to_standard_face_vertex()
+ {{{{0,2,1,3}, // face_orientation=false, face_flip=false, face_rotation=false, subfaces 0,1,2,3
+ {2,3,0,1}}, // face_orientation=false, face_flip=false, face_rotation=true, subfaces 0,1,2,3
+ {{3,1,2,0}, // face_orientation=false, face_flip=true, face_rotation=false, subfaces 0,1,2,3
+ {1,0,3,2}}}, // face_orientation=false, face_flip=true, face_rotation=true, subfaces 0,1,2,3
+ {{{0,1,2,3}, // face_orientation=true, face_flip=false, face_rotation=false, subfaces 0,1,2,3
+ {1,3,0,2}}, // face_orientation=true, face_flip=false, face_rotation=true, subfaces 0,1,2,3
+ {{3,2,1,0}, // face_orientation=true, face_flip=true, face_rotation=false, subfaces 0,1,2,3
+ {2,0,3,1}}}}};// face_orientation=true, face_flip=true, face_rotation=true, subfaces 0,1,2,3
+
+ const unsigned int std_subface=subface_exchange
+ [face_ref_case]
+ [face_orientation]
+ [face_flip]
+ [face_rotation]
+ [subface];
+ Assert (std_subface!=e, ExcInternalError());
+
+ // third step: these are the children, which
+ // can be found at the given subfaces of an
+ // isotropically refined (standard) face
+ //
+ // first index: (refinement_case-1)
+ // second index: face_index
+ // third index: subface_index (isotropic refinement)
+ static const unsigned int
+ iso_children[RefinementCase<dim>::cut_xyz][faces_per_cell][max_children_per_face] =
+ {
+ // cut_x
+ {{0, 0, 0, 0}, // face 0, subfaces 0,1,2,3
+ {1, 1, 1, 1}, // face 1, subfaces 0,1,2,3
+ {0, 0, 1, 1}, // face 2, subfaces 0,1,2,3
+ {0, 0, 1, 1}, // face 3, subfaces 0,1,2,3
+ {0, 1, 0, 1}, // face 4, subfaces 0,1,2,3
+ {0, 1, 0, 1}}, // face 5, subfaces 0,1,2,3
+ // cut_y
+ {{0, 1, 0, 1},
+ {0, 1, 0, 1},
+ {0, 0, 0, 0},
+ {1, 1, 1, 1},
+ {0, 0, 1, 1},
+ {0, 0, 1, 1}},
+ // cut_xy
+ {{0, 2, 0, 2},
+ {1, 3, 1, 3},
+ {0, 0, 1, 1},
+ {2, 2, 3, 3},
+ {0, 1, 2, 3},
+ {0, 1, 2, 3}},
+ // cut_z
+ {{0, 0, 1, 1},
+ {0, 0, 1, 1},
+ {0, 1, 0, 1},
+ {0, 1, 0, 1},
+ {0, 0, 0, 0},
+ {1, 1, 1, 1}},
+ // cut_xz
+ {{0, 0, 1, 1},
+ {2, 2, 3, 3},
+ {0, 1, 2, 3},
+ {0, 1, 2, 3},
+ {0, 2, 0, 2},
+ {1, 3, 1, 3}},
+ // cut_yz
+ {{0, 1, 2, 3},
+ {0, 1, 2, 3},
+ {0, 2, 0, 2},
+ {1, 3, 1, 3},
+ {0, 0, 1, 1},
+ {2, 2, 3, 3}},
+ // cut_xyz
+ {{0, 2, 4, 6},
+ {1, 3, 5, 7},
+ {0, 4, 1, 5},
+ {2, 6, 3, 7},
+ {0, 1, 2, 3},
+ {4, 5, 6, 7}}};
+
+ // forth step: check, whether the given face
+ // refine case is valid for the given cell
+ // refine case. this is the case, if the
+ // given face refine case is at least as
+ // refined as the face is for the given cell
+ // refine case
+
+ // note, that we are considering standard
+ // face refinement cases here and thus must
+ // not pass the given orientation, flip and
+ // rotation flags
+ if ((std_face_ref & face_refinement_case(ref_case, face))
+ == face_refinement_case(ref_case, face))
+ {
+ // all is fine. for anisotropic face
+ // refine cases, select one of the
+ // isotropic subfaces which neighbors the
+ // same child
+
+ // first index: (standard) face refine case
+ // second index: subface index
+ static const unsigned int equivalent_iso_subface[4][4]=
+ {{0,e,e,e}, // no_refinement
+ {0,3,e,e}, // cut_x
+ {0,3,e,e}, // cut_y
+ {0,1,2,3}}; // cut_xy
+
+ const unsigned int equ_std_subface
+ =equivalent_iso_subface[std_face_ref][std_subface];
+ Assert (equ_std_subface!=e, ExcInternalError());
+
+ return iso_children[ref_case-1][face][equ_std_subface];
+ }
+ else
+ {
+ // the face_ref_case was too coarse,
+ // throw an error
+ Assert(false,
+ ExcMessage("The face RefineCase is too coarse "
+ "for the given cell RefineCase."));
+ }
+ // we only get here in case of an error
+ return e;
}
template <>
unsigned int
-GeometryInfo<4>::child_cell_on_face (const unsigned int,
+GeometryInfo<4>::child_cell_on_face (const RefinementCase<4> &,
const unsigned int,
- const bool, const bool, const bool)
+ const unsigned int,
+ const bool, const bool, const bool,
+ const RefinementCase<3> &)
{
Assert(false, ExcNotImplemented());
return invalid_unsigned_int;
GeometryInfo<2>::line_to_cell_vertices (const unsigned int line,
const unsigned int vertex)
{
- return child_cell_on_face(line, vertex);
+ return child_cell_on_face(RefinementCase<2>::isotropic_refinement, line, vertex);
}
const bool face_flip,
const bool face_rotation)
{
- return child_cell_on_face(face, vertex,
+ return child_cell_on_face(RefinementCase<dim>::isotropic_refinement, face, vertex,
face_orientation, face_flip, face_rotation);
}
return result;
}
+
template class GeometryInfo<1>;
template class GeometryInfo<2>;
template class GeometryInfo<3>;
// $Id$
// Version: $Name$
//
-// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
QProjector<1>::project_to_subface (const Quadrature<0> &,
const unsigned int,
const unsigned int,
- std::vector<Point<1> > &)
+ std::vector<Point<1> > &,
+ const RefinementCase<0> &)
{
Assert(false, ExcNotImplemented());
}
QProjector<2>::project_to_subface (const Quadrature<1> &quadrature,
const unsigned int face_no,
const unsigned int subface_no,
- std::vector<Point<2> > &q_points)
+ std::vector<Point<2> > &q_points,
+ const RefinementCase<1> &)
{
const unsigned int dim=2;
Assert (face_no<2*dim, ExcIndexRange (face_no, 0, 2*dim));
QProjector<3>::project_to_subface (const Quadrature<2> &quadrature,
const unsigned int face_no,
const unsigned int subface_no,
- std::vector<Point<3> > &q_points)
+ std::vector<Point<3> > &q_points,
+ const RefinementCase<2> &ref_case)
{
const unsigned int dim=3;
Assert (face_no<2*dim, ExcIndexRange (face_no, 0, 2*dim));
Assert (q_points.size() == quadrature.size(),
ExcDimensionMismatch (q_points.size(), quadrature.size()));
-
- // for all faces and subfaces:
- // first project onto the first
- // subface of each face, then move
- // it to the right place
+ // one coordinate is at a const value. for
+ // faces 0, 2 and 4 this value is 0.0, for
+ // faces 1, 3 and 5 it is 1.0
+ double const_value=face_no%2;
+ // local 2d coordinates are xi and eta,
+ // global 3d coordinates are x, y and
+ // z. those have to be mapped. the following
+ // indices tell, which global coordinate
+ // (0->x, 1->y, 2->z) corresponds to which
+ // local one
+ unsigned int xi_index = deal_II_numbers::invalid_unsigned_int,
+ eta_index = deal_II_numbers::invalid_unsigned_int,
+ const_index = face_no/2;
+ // the xi and eta values have to be scaled
+ // (by factor 0.5 or factor 1.0) depending on
+ // the refinement case and translated (by 0.0
+ // or 0.5) depending on the refinement case
+ // and subface_no.
+ double xi_scale=1.0,
+ eta_scale=1.0,
+ xi_translation=0.0,
+ eta_translation=0.0;
+ // set the index mapping between local and
+ // global coordinates
+ switch(face_no/2)
+ {
+ case 0:
+ xi_index=1;
+ eta_index=2;
+ break;
+ case 1:
+ xi_index=2;
+ eta_index=0;
+ break;
+ case 2:
+ xi_index=0;
+ eta_index=1;
+ break;
+ }
+ // set the scale and translation parameter
+ // for individual subfaces
+ switch((unsigned char)ref_case)
+ {
+ case RefinementCase<dim-1>::cut_x:
+ xi_scale=0.5;
+ xi_translation=subface_no%2 * 0.5;
+ break;
+ case RefinementCase<dim-1>::cut_y:
+ eta_scale=0.5;
+ eta_translation=subface_no%2 * 0.5;
+ break;
+ case RefinementCase<dim-1>::cut_xy:
+ xi_scale= 0.5;
+ eta_scale=0.5;
+ xi_translation =subface_no%2 * 0.5;
+ eta_translation=subface_no/2 * 0.5;
+ break;
+ default:
+ Assert(false,ExcInternalError());
+ break;
+ }
+ // finally, compute the scaled, translated,
+ // projected quadrature points
for (unsigned int p=0; p<quadrature.size(); ++p)
- switch (face_no)
- {
- case 0:
- q_points[p] = Point<dim>(0,
- quadrature.point(p)(0)/2,
- quadrature.point(p)(1)/2);
- switch (subface_no)
- {
- case 0:
- break;
- case 1:
- q_points[p][1] += 1./2.;
- break;
- case 2:
- q_points[p][2] += 1./2.;
- break;
- case 3:
- q_points[p][1] += 1./2.;
- q_points[p][2] += 1./2.;
- break;
- default:
- Assert (false, ExcInternalError());
- };
- break;
- case 1:
- q_points[p] = Point<dim>(1,
- quadrature.point(p)(0)/2,
- quadrature.point(p)(1)/2);
- switch (subface_no)
- {
- case 0:
- break;
- case 1:
- q_points[p][1] += 1./2.;
- break;
- case 2:
- q_points[p][2] += 1./2.;
- break;
- case 3:
- q_points[p][1] += 1./2.;
- q_points[p][2] += 1./2.;
- break;
- default:
- Assert (false, ExcInternalError());
- };
- break;
- case 2:
- q_points[p] = Point<dim>(quadrature.point(p)(1)/2,
- 0,
- quadrature.point(p)(0)/2);
- switch (subface_no)
- {
- case 0:
- break;
- case 1:
- q_points[p][2] += 1./2.;
- break;
- case 2:
- q_points[p][0] += 1./2.;
- break;
- case 3:
- q_points[p][0] += 1./2.;
- q_points[p][2] += 1./2.;
- break;
- default:
- Assert (false, ExcInternalError());
- };
- break;
- case 3:
- q_points[p] = Point<dim>(quadrature.point(p)(1)/2,
- 1,
- quadrature.point(p)(0)/2);
- switch (subface_no)
- {
- case 0:
- break;
- case 1:
- q_points[p][2] += 1./2.;
- break;
- case 2:
- q_points[p][0] += 1./2.;
- break;
- case 3:
- q_points[p][0] += 1./2.;
- q_points[p][2] += 1./2.;
- break;
- default:
- Assert (false, ExcInternalError());
- };
- break;
- case 4:
- q_points[p] = Point<dim>(quadrature.point(p)(0)/2,
- quadrature.point(p)(1)/2,
- 0);
- switch (subface_no)
- {
- case 0:
- break;
- case 1:
- q_points[p][0] += 1./2.;
- break;
- case 2:
- q_points[p][1] += 1./2.;
- break;
- case 3:
- q_points[p][0] += 1./2.;
- q_points[p][1] += 1./2.;
- break;
- default:
- Assert (false, ExcInternalError());
- };
- break;
- case 5:
- q_points[p] = Point<dim>(quadrature.point(p)(0)/2,
- quadrature.point(p)(1)/2,
- 1);
- switch (subface_no)
- {
- case 0:
- break;
- case 1:
- q_points[p][0] += 1./2.;
- break;
- case 2:
- q_points[p][1] += 1./2.;
- break;
- case 3:
- q_points[p][0] += 1./2.;
- q_points[p][1] += 1./2.;
- break;
- default:
- Assert (false, ExcInternalError());
- };
- break;
- default:
- Assert (false, ExcInternalError());
- };
+ {
+ q_points[p][xi_index] = xi_scale * quadrature.point(p)(0) + xi_translation;
+ q_points[p][eta_index] = eta_scale * quadrature.point(p)(1) + eta_translation;
+ q_points[p][const_index] = const_value;
+ }
}
-
template <>
Quadrature<1>
QProjector<1>::project_to_all_faces (const Quadrature<0> &)
const unsigned int n_points = quadrature.size(),
n_faces = GeometryInfo<dim>::faces_per_cell,
- subfaces_per_face = GeometryInfo<dim>::subfaces_per_face;
+ subfaces_per_face = GeometryInfo<dim>::max_children_per_face;
// first fix quadrature points
std::vector<Point<dim> > q_points;
QProjector<3>::project_to_all_subfaces (const SubQuadrature &quadrature)
{
const unsigned int dim = 3;
-
SubQuadrature q_reflected=reflect (quadrature);
SubQuadrature q[8]=
{quadrature,
const unsigned int n_points = quadrature.size(),
n_faces = GeometryInfo<dim>::faces_per_cell,
- subfaces_per_face = GeometryInfo<dim>::subfaces_per_face;
+ total_subfaces_per_face = 2 + 2 + 4;
// first fix quadrature points
std::vector<Point<dim> > q_points;
- q_points.reserve (n_points * n_faces * subfaces_per_face * 8);
+ q_points.reserve (n_points * n_faces * total_subfaces_per_face * 8);
std::vector <Point<dim> > help(n_points);
std::vector<double> weights;
- weights.reserve (n_points * n_faces * subfaces_per_face * 8);
+ weights.reserve (n_points * n_faces * total_subfaces_per_face * 8);
// do the following for all possible
// mutations of a face (mutation==0
// project to each face and copy
// results
for (unsigned int face=0; face<n_faces; ++face)
- for (unsigned int subface=0; subface<subfaces_per_face; ++subface)
- {
- project_to_subface(q[mutation], face, subface, help);
- std::copy (help.begin(), help.end(),
- std::back_inserter (q_points));
- }
+ for (unsigned int ref_case=RefinementCase<dim-1>::cut_xy;
+ ref_case>=RefinementCase<dim-1>::cut_x;
+ --ref_case)
+ for (unsigned int subface=0; subface<GeometryInfo<dim-1>::n_children(RefinementCase<dim-1>(ref_case)); ++subface)
+ {
+ project_to_subface(q[mutation], face, subface, help,
+ RefinementCase<dim-1>(ref_case));
+ std::copy (help.begin(), help.end(),
+ std::back_inserter (q_points));
+ }
// next copy over weights
for (unsigned int face=0; face<n_faces; ++face)
- for (unsigned int subface=0; subface<subfaces_per_face; ++subface)
- std::copy (q[mutation].get_weights().begin(),
- q[mutation].get_weights().end(),
- std::back_inserter (weights));
+ for (unsigned int ref_case=RefinementCase<dim-1>::cut_xy;
+ ref_case>=RefinementCase<dim-1>::cut_x;
+ --ref_case)
+ for (unsigned int subface=0; subface<GeometryInfo<dim-1>::n_children(RefinementCase<dim-1>(ref_case)); ++subface)
+ std::copy (q[mutation].get_weights().begin(),
+ q[mutation].get_weights().end(),
+ std::back_inserter (weights));
}
- Assert (q_points.size() == n_points * n_faces * subfaces_per_face * 8,
+ Assert (q_points.size() == n_points * n_faces * total_subfaces_per_face * 8,
ExcInternalError());
- Assert (weights.size() == n_points * n_faces * subfaces_per_face * 8,
+ Assert (weights.size() == n_points * n_faces * total_subfaces_per_face * 8,
ExcInternalError());
return Quadrature<dim>(q_points, weights);
+// This function is not used in the library
template <int dim>
Quadrature<dim>
QProjector<dim>::project_to_child (const Quadrature<dim> &quadrature,
const unsigned int child_no)
{
- Assert (child_no < GeometryInfo<dim>::children_per_cell,
- ExcIndexRange (child_no, 0, GeometryInfo<dim>::children_per_cell));
+ Assert (child_no < GeometryInfo<dim>::max_children_per_cell,
+ ExcIndexRange (child_no, 0, GeometryInfo<dim>::max_children_per_cell));
const unsigned int n_q_points = quadrature.size();
// scale them
std::vector<double> weights = quadrature.get_weights ();
for (unsigned int i=0; i<n_q_points; ++i)
- weights[i] *= (1./GeometryInfo<dim>::children_per_cell);
+ weights[i] *= (1./GeometryInfo<dim>::max_children_per_cell);
return Quadrature<dim> (q_points, weights);
}
-template <int dim>
-typename QProjector<dim>::DataSetDescriptor
-QProjector<dim>::DataSetDescriptor::
+template <>
+QProjector<1>::DataSetDescriptor
+QProjector<1>::DataSetDescriptor::
+subface (const unsigned int,
+ const unsigned int,
+ const bool,
+ const bool,
+ const bool,
+ const unsigned int,
+ const internal::SubfaceCase<1>)
+{
+ Assert (false, ExcInternalError());
+ return deal_II_numbers::invalid_unsigned_int;
+}
+
+
+
+template <>
+QProjector<2>::DataSetDescriptor
+QProjector<2>::DataSetDescriptor::
+subface (const unsigned int face_no,
+ const unsigned int subface_no,
+ const bool,
+ const bool,
+ const bool,
+ const unsigned int n_quadrature_points,
+ const internal::SubfaceCase<2>)
+{
+ Assert (face_no < GeometryInfo<2>::faces_per_cell,
+ ExcInternalError());
+ Assert (subface_no < GeometryInfo<2>::max_children_per_face,
+ ExcInternalError());
+
+ return ((face_no * GeometryInfo<2>::max_children_per_face +
+ subface_no)
+ * n_quadrature_points);
+}
+
+
+template <>
+QProjector<3>::DataSetDescriptor
+QProjector<3>::DataSetDescriptor::
subface (const unsigned int face_no,
const unsigned int subface_no,
const bool face_orientation,
const bool face_flip,
const bool face_rotation,
- const unsigned int n_quadrature_points)
+ const unsigned int n_quadrature_points,
+ const internal::SubfaceCase<3> ref_case)
{
- Assert (dim != 1, ExcInternalError());
+ const unsigned int dim = 3;
+
Assert (face_no < GeometryInfo<dim>::faces_per_cell,
ExcInternalError());
- // the trick with +1 prevents that we get a
- // warning in 1d
- Assert (subface_no+1 < GeometryInfo<dim>::subfaces_per_face+1,
- ExcInternalError());
+ Assert (subface_no < GeometryInfo<dim>::max_children_per_face,
+ ExcInternalError());
+
+ // As the quadrature points created by
+ // QProjector are on subfaces in their
+ // "standard location" we have to use a
+ // permutation of the equivalent subface
+ // number in order to respect face
+ // orientation, flip and rotation. The
+ // information we need here is exactly the
+ // same as the
+ // GeometryInfo<3>::child_cell_on_face info
+ // for the bottom face (face 4) of a hex, as
+ // on this the RefineCase of the cell matches
+ // that of the face and the subfaces are
+ // numbered in the same way as the child
+ // cells.
// in 3d, we have to account for faces that
// have non-standard face orientation, flip
// and rotation. thus, we have to store
// _eight_ data sets per face or subface
+ // already for the isotropic
+ // case. Additionally, we have three
+ // different refinement cases, resulting in
+ // <tt>4 + 2 + 2 = 8</tt> differnt subfaces
+ // for each face.
+ const unsigned int total_subfaces_per_face=8;
// set up a table with the according offsets
// for non-standard orientation, first index:
// a face in standard orientation. therefore
// we use the offsets 4,5,6,7,0,1,2,3 here to
// stick to that (implicit) convention
- static const unsigned int offset[2][2][2]=
+ static const unsigned int orientation_offset[2][2][2]=
{{
// face_orientation=false; face_flip=false; face_rotation=false and true
- {4*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face,
- 5*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face},
+ {4*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face,
+ 5*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face},
// face_orientation=false; face_flip=true; face_rotation=false and true
- {6*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face,
- 7*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face}},
+ {6*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face,
+ 7*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face}},
{
// face_orientation=true; face_flip=false; face_rotation=false and true
- {0*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face,
- 1*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face},
+ {0*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face,
+ 1*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face},
// face_orientation=true; face_flip=true; face_rotation=false and true
- {2*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face,
- 3*GeometryInfo<dim>::faces_per_cell*GeometryInfo<dim>::subfaces_per_face}}};
+ {2*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face,
+ 3*GeometryInfo<dim>::faces_per_cell*total_subfaces_per_face}}};
+
+ // set up a table with the offsets for a
+ // given refinement case respecting the
+ // corresponding number of subfaces. the
+ // index corresponds to (RefineCase::Type - 1)
+
+ // note, that normally we should use the
+ // obvious offsets 0,2,6. However, prior to
+ // the implementation of anisotropic
+ // refinement, in many places of the library
+ // the convention was used, that the first
+ // dataset with offset 0 corresponds to a
+ // standard (isotropic) face
+ // refinement. therefore we use the offsets
+ // 6,4,0 here to stick to that (implicit)
+ // convention
+ static const unsigned int ref_case_offset[3]=
+ {
+ 6, //cut_x
+ 4, //cut_y
+ 0 //cut_xy
+ };
+
+
+ // for each subface of a given FaceRefineCase
+ // there is a corresponding equivalent
+ // subface number of one of the "standard"
+ // RefineCases (cut_x, cut_y, cut_xy). Map
+ // the given values to those equivalent
+ // ones.
+
+ // first, define an invalid number
+ static const unsigned int e = deal_II_numbers::invalid_unsigned_int;
- switch (dim)
+ static const RefinementCase<dim-1>
+ equivalent_refine_case[internal::SubfaceCase<dim>::case_isotropic+1][GeometryInfo<3>::max_children_per_face]
+ =
{
- case 1:
- case 2:
- return ((face_no * GeometryInfo<dim>::subfaces_per_face +
- subface_no)
- * n_quadrature_points);
- case 3:
- return (((face_no * GeometryInfo<dim>::subfaces_per_face +
- subface_no)
- + offset[face_orientation][face_flip][face_rotation]
- )
- * n_quadrature_points);
- default:
- Assert (false, ExcInternalError());
- }
- return numbers::invalid_unsigned_int;
+ // case_none. there should be only
+ // invalid values here. However, as
+ // this function is also called (in
+ // tests) for cells which have no
+ // refined faces, use isotropic
+ // refinement instead
+ {RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy},
+ // case_x
+ {RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::no_refinement},
+ // case_x1y
+ {RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::no_refinement},
+ // case_x2y
+ {RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::no_refinement},
+ // case_x1y2y
+ {RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy},
+ // case_y
+ {RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::no_refinement},
+ // case_y1x
+ {RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::no_refinement},
+ // case_y2x
+ {RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::no_refinement},
+ // case_y1x2x
+ {RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy},
+ // case_xy (case_isotropic)
+ {RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy,
+ RefinementCase<dim-1>::cut_xy}
+ };
+
+ static const unsigned int
+ equivalent_subface_number[internal::SubfaceCase<dim>::case_isotropic+1][GeometryInfo<3>::max_children_per_face]
+ =
+ {
+ // case_none, see above
+ {0,1,2,3},
+ // case_x
+ {0,1,e,e},
+ // case_x1y
+ {0,2,1,e},
+ // case_x2y
+ {0,1,3,e},
+ // case_x1y2y
+ {0,2,1,3},
+ // case_y
+ {0,1,e,e},
+ // case_y1x
+ {0,1,1,e},
+ // case_y2x
+ {0,2,3,e},
+ // case_y1x2x
+ {0,1,2,3},
+ // case_xy (case_isotropic)
+ {0,1,2,3}
+ };
+
+ // If face-orientation or face_rotation are
+ // non-standard, cut_x and cut_y have to be
+ // exchanged.
+ static const RefinementCase<dim-1> ref_case_permutation[4]
+ ={RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_xy};
+
+ // set a corresponding (equivalent)
+ // RefineCase and subface number
+ const RefinementCase<dim-1> equ_ref_case=equivalent_refine_case[ref_case][subface_no];
+ const unsigned int equ_subface_no=equivalent_subface_number[ref_case][subface_no];
+ // make sure, that we got a valid subface and RefineCase
+ Assert(equ_ref_case!=RefinementCase<dim>::no_refinement, ExcInternalError());
+ Assert(equ_subface_no!=e, ExcInternalError());
+ // now, finally respect non-standard faces
+ const RefinementCase<dim-1>
+ final_ref_case = (face_orientation==face_rotation
+ ?
+ ref_case_permutation[equ_ref_case]
+ :
+ equ_ref_case);
+
+ // what we have now is the number of
+ // the subface in the natural
+ // orientation of the *face*. what we
+ // need to know is the number of the
+ // subface concerning the standard face
+ // orientation as seen from the *cell*.
+
+ // this mapping is not trivial, but we
+ // have done exactly this stuff in the
+ // child_cell_on_face function. in
+ // order to reduce the amount of code
+ // as well as to make maintaining the
+ // functionality easier we want to
+ // reuse that information. So we note
+ // that on the bottom face (face 4) of
+ // a hex cell the local x and y
+ // coordinates of the face and the cell
+ // coincide, thus also the refinement
+ // case of the face corresponds to the
+ // refinement case of the cell
+ // (ignoring cell refinement along the
+ // z direction). Using this knowledge
+ // we can (ab)use the
+ // child_cell_on_face function to do
+ // exactly the transformation we are in
+ // need of now
+ const unsigned int
+ final_subface_no = GeometryInfo<dim>::child_cell_on_face(RefinementCase<dim>(final_ref_case),
+ 4,
+ equ_subface_no,
+ face_orientation,
+ face_flip,
+ face_rotation,
+ equ_ref_case);
+
+ return (((face_no * total_subfaces_per_face
+ + ref_case_offset[final_ref_case-1]
+ + final_subface_no)
+ + orientation_offset[face_orientation][face_flip][face_rotation]
+ )
+ * n_quadrature_points);
}
template <int dim>
Quadrature<dim>
-QProjector<dim>::project_to_subface(const SubQuadrature &quadrature,
- const unsigned int face_no,
- const unsigned int subface_no)
+QProjector<dim>::project_to_subface(const SubQuadrature &quadrature,
+ const unsigned int face_no,
+ const unsigned int subface_no,
+ const RefinementCase<dim-1> &ref_case)
{
std::vector<Point<dim> > points(quadrature.size());
- project_to_subface(quadrature, face_no, subface_no, points);
+ project_to_subface(quadrature, face_no, subface_no, points, ref_case);
return Quadrature<dim>(points, quadrature.get_weights());
}
#define __deal2__fe_h
#include <base/config.h>
+#include <base/geometry_info.h>
#include <fe/fe_base.h>
+
DEAL_II_NAMESPACE_OPEN
template <int dim> class FEValuesData;
for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
this->prolongation[i].reinit (this->dofs_per_cell,
this->dofs_per_cell);
- FETools::compute_embedding_matrices (*this, &this->prolongation[0]);
+ FETools::compute_embedding_matrices (*this, this->prolongation);
* @endcode
*
* <h5>Computing the #restriction matrices for error estimators</h5>
* If projection matrices are not
* implemented in the derived
* finite element class, this
- * function aborts with
- * ExcProjectionVoid.
+ * function aborts with
+ * ExcProjectionVoid. You can
+ * check whether this is the case
+ * by calling the
+ * restriction_is_implemented()
+ * or the
+ * isotropic_restriction_is_implemented()
+ * function.
*/
const FullMatrix<double> &
- get_restriction_matrix (const unsigned int child) const;
+ get_restriction_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
/**
* Embedding matrix between grids.
* ExcEmbeddingVoid. You can
* check whether this is the case
* by calling the
- * prolongation_is_implemented().
+ * prolongation_is_implemented()
+ * or the
+ * isotropic_prolongation_is_implemented()
+ * function.
*/
const FullMatrix<double> &
- get_prolongation_matrix (const unsigned int child) const;
+ get_prolongation_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
/**
* Return whether this element implements
* the get_prolongation_matrix()
* function will generate an error or
* not.
+ *
+ * Note, that this function
+ * returns <code>true</code> only
+ * if the prolongation matrices of
+ * the isotropic and all
+ * anisotropic refinement cases
+ * are implemented. If you are
+ * interested in the prolongation
+ * matrices for isotropic
+ * refinement only, use the
+ * isotropic_prolongation_is_implemented
+ * function instead.
*
* This function is mostly here in order
* to allow us to write more efficient
*/
bool prolongation_is_implemented () const;
+ /**
+ * Return whether this element implements
+ * its prolongation matrices for isotropic
+ * children. The return value also
+ * indicates whether a call to the @p
+ * get_prolongation_matrix function will
+ * generate an error or not.
+ *
+ * This function is mostly here in order
+ * to allow us to write more efficient
+ * test programs which we run on all
+ * kinds of weird elements, and for which
+ * we simply need to exclude certain
+ * tests in case something is not
+ * implemented. It will in general
+ * probably not be a great help in
+ * applications, since there is not much
+ * one can do if one needs these features
+ * and they are not implemented. This
+ * function could be used to check
+ * whether a call to
+ * <tt>get_prolongation_matrix()</tt> will
+ * succeed; however, one then still needs
+ * to cope with the lack of information
+ * this just expresses.
+ */
+ bool isotropic_prolongation_is_implemented () const;
+
/**
* Return whether this element implements
* its restriction matrices. The return
* the get_restriction_matrix()
* function will generate an error or
* not.
+ *
+ * Note, that this function
+ * returns <code>true</code> only
+ * if the restriction matrices of
+ * the isotropic and all
+ * anisotropic refinement cases
+ * are implemented. If you are
+ * interested in the restriction
+ * matrices for isotropic
+ * refinement only, use the
+ * isotropic_restriction_is_implemented
+ * function instead.
*
* This function is mostly here in order
* to allow us to write more efficient
*/
bool restriction_is_implemented () const;
+ /**
+ * Return whether this element implements
+ * its restriction matrices for isotropic
+ * children. The return value also
+ * indicates whether a call to the @p
+ * get_restriction_matrix function will
+ * generate an error or not.
+ *
+ * This function is mostly here in order
+ * to allow us to write more efficient
+ * test programs which we run on all
+ * kinds of weird elements, and for which
+ * we simply need to exclude certain
+ * tests in case something is not
+ * implemented. It will in general
+ * probably not be a great help in
+ * applications, since there is not much
+ * one can do if one needs these features
+ * and they are not implemented. This
+ * function could be used to check
+ * whether a call to
+ * <tt>get_restriction_matrix()</tt> will
+ * succeed; however, one then still needs
+ * to cope with the lack of information
+ * this just expresses.
+ */
+ bool isotropic_restriction_is_implemented () const;
+
+
/**
* Access the
* #restriction_is_additive_flags
* succeed or generate the
* exception.
*/
- const FullMatrix<double> & constraints () const;
+ const FullMatrix<double> & constraints (const internal::SubfaceCase<dim> &subface_case=internal::SubfaceCase<dim>::case_isotropic) const;
/**
* Return whether this element
* the lack of information this
* just expresses.
*/
- bool constraints_are_implemented () const;
+ bool constraints_are_implemented (const internal::SubfaceCase<dim> &subface_case=internal::SubfaceCase<dim>::case_isotropic) const;
/**
DeclException0 (ExcJacobiDeterminantHasWrongSign);
protected:
+
+ /**
+ * Reinit the vectors of
+ * restriction and prolongation
+ * matrices to the right sizes:
+ * For every refinement case,
+ * except for
+ * RefinementCase::no_refinement,
+ * and for every child of that
+ * refinement case the space of
+ * one restriction and
+ * prolongation matrix is
+ * allocated, see the
+ * documentation of the
+ * restriction and prolongation
+ * vectors for more detail on the
+ * actual vector sizes.
+ *
+ * @param
+ * isotropic_restriction_only:
+ * only the restriction matrices
+ * required for isotropic
+ * refinement are reinited to the
+ * right size.
+ * @param
+ * isotropic_prolongation_only:
+ * only the prolongation matrices
+ * required for isotropic
+ * refinement are reinited to the
+ * right size.
+ */
+ void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false,
+ const bool isotropic_prolongation_only=false);
+
+
/**
* Store whether all shape
* functions are primitive. Since
const bool cached_primitivity;
/**
- * Array of projection
+ * Vector of projection
* matrices. See
* get_restriction_matrix()
* above. The constructor
* zero dimensions, which can be
* changed by derived classes
* implementing them.
- */
- FullMatrix<double> restriction[GeometryInfo<dim>::children_per_cell];
+ *
+ * Note, that
+ * <code>restriction[refinement_case-1][child]</code>
+ * includes the restriction
+ * matrix of child
+ * <code>child</code> for the
+ * RefinementCase
+ * <code>refinement_case</code>. Here,
+ * we use
+ * <code>refinement_case-1</code>
+ * instead of
+ * <code>refinement_case</code>
+ * as for
+ * RefinementCase::no_refinement(=0)
+ * there are no restriction
+ * matrices available.
+ */
+ std::vector<std::vector<FullMatrix<double> > > restriction;
/**
- * Array of embedding
+ * Vector of embedding
* matrices. See
* <tt>get_prolongation_matrix()</tt>
* above. The constructor
* zero dimensions, which can be
* changed by derived classes
* implementing them.
- */
- FullMatrix<double> prolongation[GeometryInfo<dim>::children_per_cell];
+ *
+ * Note, that
+ * <code>prolongation[refinement_case-1][child]</code>
+ * includes the prolongation
+ * matrix of child
+ * <code>child</code> for the
+ * RefinementCase
+ * <code>refinement_case</code>. Here,
+ * we use
+ * <code>refinement_case-1</code>
+ * instead of
+ * <code>refinement_case</code>
+ * as for
+ * RefinementCase::no_refinement(=0)
+ * there are no prolongation
+ * matrices available.
+ */
+ std::vector<std::vector<FullMatrix<double> > > prolongation;
/**
* Specify the constraints which
* As @p embedding but for
* projection matrices.
*/
- static const double * const projection_matrices[][GeometryInfo<dim>::children_per_cell];
+ static const double * const projection_matrices[][GeometryInfo<dim>::max_children_per_cell];
/**
* As
// compiler allows us to do that (the standard says we must)
#ifndef DEAL_II_MEMBER_VAR_SPECIALIZATION_BUG
template <>
-const double * const FE_DGP<1>::Matrices::projection_matrices[][GeometryInfo<1>::children_per_cell];
+const double * const FE_DGP<1>::Matrices::projection_matrices[][GeometryInfo<1>::max_children_per_cell];
template <>
const unsigned int FE_DGP<1>::Matrices::n_projection_matrices;
template <>
-const double * const FE_DGP<2>::Matrices::projection_matrices[][GeometryInfo<2>::children_per_cell];
+const double * const FE_DGP<2>::Matrices::projection_matrices[][GeometryInfo<2>::max_children_per_cell];
template <>
const unsigned int FE_DGP<2>::Matrices::n_projection_matrices;
template <>
-const double * const FE_DGP<3>::Matrices::projection_matrices[][GeometryInfo<3>::children_per_cell];
+const double * const FE_DGP<3>::Matrices::projection_matrices[][GeometryInfo<3>::max_children_per_cell];
template <>
const unsigned int FE_DGP<3>::Matrices::n_projection_matrices;
* polynomial degree starting
* from constant elements
*/
- static const double * const embedding[][GeometryInfo<dim>::children_per_cell];
+ static const double * const embedding[][GeometryInfo<dim>::max_children_per_cell];
/**
* Number of elements (first
* As @p embedding but for
* projection matrices.
*/
- static const double * const projection_matrices[][GeometryInfo<dim>::children_per_cell];
+ static const double * const projection_matrices[][GeometryInfo<dim>::max_children_per_cell];
/**
* As
// compiler allows us to do that (the standard says we must)
#ifndef DEAL_II_MEMBER_VAR_SPECIALIZATION_BUG
template <>
-const double * const FE_DGPNonparametric<1>::Matrices::embedding[][GeometryInfo<1>::children_per_cell];
+const double * const FE_DGPNonparametric<1>::Matrices::embedding[][GeometryInfo<1>::max_children_per_cell];
template <>
const unsigned int FE_DGPNonparametric<1>::Matrices::n_embedding_matrices;
template <>
-const double * const FE_DGPNonparametric<1>::Matrices::projection_matrices[][GeometryInfo<1>::children_per_cell];
+const double * const FE_DGPNonparametric<1>::Matrices::projection_matrices[][GeometryInfo<1>::max_children_per_cell];
template <>
const unsigned int FE_DGPNonparametric<1>::Matrices::n_projection_matrices;
template <>
-const double * const FE_DGPNonparametric<2>::Matrices::embedding[][GeometryInfo<2>::children_per_cell];
+const double * const FE_DGPNonparametric<2>::Matrices::embedding[][GeometryInfo<2>::max_children_per_cell];
template <>
const unsigned int FE_DGPNonparametric<2>::Matrices::n_embedding_matrices;
template <>
-const double * const FE_DGPNonparametric<2>::Matrices::projection_matrices[][GeometryInfo<2>::children_per_cell];
+const double * const FE_DGPNonparametric<2>::Matrices::projection_matrices[][GeometryInfo<2>::max_children_per_cell];
template <>
const unsigned int FE_DGPNonparametric<2>::Matrices::n_projection_matrices;
template <>
-const double * const FE_DGPNonparametric<3>::Matrices::embedding[][GeometryInfo<3>::children_per_cell];
+const double * const FE_DGPNonparametric<3>::Matrices::embedding[][GeometryInfo<3>::max_children_per_cell];
template <>
const unsigned int FE_DGPNonparametric<3>::Matrices::n_embedding_matrices;
template <>
-const double * const FE_DGPNonparametric<3>::Matrices::projection_matrices[][GeometryInfo<3>::children_per_cell];
+const double * const FE_DGPNonparametric<3>::Matrices::projection_matrices[][GeometryInfo<3>::max_children_per_cell];
template <>
const unsigned int FE_DGPNonparametric<3>::Matrices::n_projection_matrices;
* fields.
*/
static const double * const
- embedding[][GeometryInfo<dim>::children_per_cell];
+ embedding[][GeometryInfo<dim>::max_children_per_cell];
/**
* Number of elements (first
#ifndef DEAL_II_MEMBER_VAR_SPECIALIZATION_BUG
template <>
const double * const
-FE_Nedelec<1>::Matrices::embedding[][GeometryInfo<1>::children_per_cell];
+FE_Nedelec<1>::Matrices::embedding[][GeometryInfo<1>::max_children_per_cell];
template <>
const unsigned int FE_Nedelec<1>::Matrices::n_embedding_matrices;
template <>
const double * const
-FE_Nedelec<2>::Matrices::embedding[][GeometryInfo<2>::children_per_cell];
+FE_Nedelec<2>::Matrices::embedding[][GeometryInfo<2>::max_children_per_cell];
template <>
const unsigned int FE_Nedelec<2>::Matrices::n_embedding_matrices;
template <>
const double * const
-FE_Nedelec<3>::Matrices::embedding[][GeometryInfo<3>::children_per_cell];
+FE_Nedelec<3>::Matrices::embedding[][GeometryInfo<3>::max_children_per_cell];
template <>
const unsigned int FE_Nedelec<3>::Matrices::n_embedding_matrices;
cell->face_orientation(face),
cell->face_flip(face),
cell->face_rotation(face),
- quadrature.size());
+ quadrature.size(),
+ cell->subface_case(face));
const UpdateFlags flags(fe_data.update_once | fe_data.update_each);
const FiniteElement<dim>& fe);
/**
- * Compute the embedding matrices
- * from a coarse cell to
- * 2<sup>dim</sup> child
- * cells. Each column of the
- * resulting matrices contains
- * the representation of a coarse
- * grid basis functon by the fine
- * grid basis; the matrices are
- * split such that there is one
- * matrix for every child.
+ * For all possible (isotropic
+ * and anisotropic) refinement
+ * cases compute the embedding
+ * matrices from a coarse cell to
+ * the child cells. Each column
+ * of the resulting matrices
+ * contains the representation of
+ * a coarse grid basis functon by
+ * the fine grid basis; the
+ * matrices are split such that
+ * there is one matrix for every
+ * child.
*
* This function computes the
* coarse grid function in a
* the finite element spaces are
* actually nested.
*
+ * Note, that
+ * <code>matrices[refinement_case-1][child]</code>
+ * includes the embedding (or prolongation)
+ * matrix of child
+ * <code>child</code> for the
+ * RefinementCase
+ * <code>refinement_case</code>. Here,
+ * we use
+ * <code>refinement_case-1</code>
+ * instead of
+ * <code>refinement_case</code>
+ * as for
+ * RefinementCase::no_refinement(=0)
+ * there are no prolongation
+ * matrices available.
+ *
+ * Typically this function is
+ * called by the various
+ * implementations of
+ * FiniteElement classes in order
+ * to fill the respective
+ * FiniteElement::prolongation
+ * matrices.
+ *
* @param fe The finite element
* class for which we compute the
- * embedding matrices.
- * @param matrices A pointer to
- * <i>GeometryInfo::children_per_cell=2<sup>dim</sup></i> FullMatrix
- * objects. This is the format
- * used in FiniteElement,
- * where we want to use ths
- * function mostly.
+ * embedding matrices. @param
+ * matrices A reference to
+ * <tt>RefinementCase<dim>::isotropic_refinement</tt>
+ * vectors of FullMatrix
+ * objects. Each vector
+ * corresponds to one
+ * RefinementCase @p
+ * refinement_case and is of the
+ * vector size
+ * <tt>GeometryInfo<dim>::n_children(refinement_case)</tt>. This
+ * is the format used in
+ * FiniteElement, where we want
+ * to use this function mostly.
*/
template <int dim, typename number>
- static void
- compute_embedding_matrices(const FiniteElement<dim> &fe,
- FullMatrix<number> (&matrices)[GeometryInfo<dim>::children_per_cell]);
+ static void compute_embedding_matrices(const FiniteElement<dim> &fe,
+ std::vector<std::vector<FullMatrix<number> > >& matrices);
/**
* Compute the embedding matrices
template<int dim, typename number>
static void
compute_face_embedding_matrices(const FiniteElement<dim>& fe,
- FullMatrix<number> (&matrices)[GeometryInfo<dim>::subfaces_per_face],
+ FullMatrix<number> (&matrices)[GeometryInfo<dim>::max_children_per_face],
const unsigned int face_coarse,
const unsigned int face_fine);
/**
- * Compute the
+ * For all possible (isotropic
+ * and anisotropic) refinement
+ * cases compute the
* <i>L<sup>2</sup></i>-projection
* matrices from the children to
* a coarse cell.
*
- * @arg fe The finite element class for
- * which we compute the projection
- * matrices. @arg matrices A pointer to
- * <tt>GeometryInfo::children_per_cell</tt>=2<sup>dim</sup>
- * FullMatrix objects. This is the format
- * used in FiniteElement, where we
- * want to use this function mostly.
+ * Note, that
+ * <code>matrices[refinement_case-1][child]</code>
+ * includes the projection (or restriction)
+ * matrix of child
+ * <code>child</code> for the
+ * RefinementCase
+ * <code>refinement_case</code>. Here,
+ * we use
+ * <code>refinement_case-1</code>
+ * instead of
+ * <code>refinement_case</code>
+ * as for
+ * RefinementCase::no_refinement(=0)
+ * there are no projection
+ * matrices available.
+ *
+ * Typically this function is
+ * called by the various
+ * implementations of
+ * FiniteElement classes in order
+ * to fill the respective
+ * FiniteElement::restriction
+ * matrices.
+ *
+ * @arg fe The finite element
+ * class for which we compute the
+ * projection matrices. @arg
+ * matrices A reference to
+ * <tt>RefinementCase<dim>::isotropic_refinement</tt>
+ * vectors of FullMatrix
+ * objects. Each vector
+ * corresponds to one
+ * RefinementCase @p
+ * refinement_case and is of the
+ * vector size
+ * <tt>GeometryInfo<dim>::n_children(refinement_case)</tt>. This
+ * is the format used in
+ * FiniteElement, where we want
+ * to use this function mostly.
*/
template <int dim, typename number>
- static void
- compute_projection_matrices(const FiniteElement<dim> &fe,
- FullMatrix<number> (&matrices)[GeometryInfo<dim>::children_per_cell]);
+ static void compute_projection_matrices(const FiniteElement<dim> &fe,
+ std::vector<std::vector<FullMatrix<number> > >& matrices);
//TODO:[WB] Replace this documentation by something comprehensible
#include <fe/fe.h>
#include <fe/fe_update_flags.h>
#include <fe/mapping.h>
+#include <fe/mapping_q.h>
#include <multigrid/mg_dof_handler.h>
#include <multigrid/mg_dof_accessor.h>
*/
std::vector<double> JxW_values;
+ /**
+ * Array of the Jacobian matrices at the
+ * quadrature points.
+ */
+ std::vector<Tensor<2,dim> > jacobians;
+
+ /**
+ * Array of the derivatives of the Jacobian
+ * matrices at the quadrature points.
+ */
+ std::vector<Tensor<3,dim> > jacobian_grads;
+
/**
* Store an array of weights
* times the Jacobi determinant
*/
const std::vector<double> & get_JxW_values () const;
+ /**
+ * Return the Jacobian of the
+ * transformation at the specified
+ * quadrature point, i.e.
+ * $J_{ij}=dx_i/d\hat x_j$
+ */
+ const Tensor<2,dim> & jacobian (const unsigned int quadrature_point) const;
+
+ /**
+ * Pointer to the array holding
+ * the values returned by jacobian().
+ */
+ const std::vector<Tensor<2,dim> > & get_jacobians () const;
+
+ /**
+ * Return the second derivative of the
+ * transformation from unit to real cell,
+ * i.e. the first derivative of the
+ * Jacobian, at the specified quadrature
+ * point, i.e. $G_{ijk}=dJ_{jk}/d\hat x_i$.
+ */
+ const Tensor<3,dim> & jacobian_grad (const unsigned int quadrature_point) const;
+
+ /**
+ * Pointer to the array holding
+ * the values returned by
+ * jacobian_grads().
+ */
+ const std::vector<Tensor<3,dim> > & get_jacobian_grads () const;
+
/**
* Constant reference to the
* selected mapping object.
+template <int dim>
+inline
+const std::vector<Tensor<2,dim> >&
+FEValuesBase<dim>::get_jacobians () const
+{
+ Assert (this->update_flags & update_jacobians, ExcAccessToUninitializedField());
+ return this->jacobians;
+}
+
+
+
+template <int dim>
+inline
+const std::vector<Tensor<3,dim> >&
+FEValuesBase<dim>::get_jacobian_grads () const
+{
+ Assert (this->update_flags & update_jacobian_grads, ExcAccessToUninitializedField());
+ return this->jacobian_grads;
+}
+
+
+
template <int dim>
inline
const Point<dim> &
+template <int dim>
+inline
+const Tensor<2,dim> &
+FEValuesBase<dim>::jacobian (const unsigned int i) const
+{
+ Assert (this->update_flags & update_jacobians, ExcAccessToUninitializedField());
+ Assert (i<this->jacobians.size(), ExcIndexRange(i, 0, this->jacobians.size()));
+
+ return this->jacobians[i];
+}
+
+
+
+template <int dim>
+inline
+const Tensor<3,dim> &
+FEValuesBase<dim>::jacobian_grad (const unsigned int i) const
+{
+ Assert (this->update_flags & update_jacobian_grads, ExcAccessToUninitializedField());
+ Assert (i<this->jacobian_grads.size(), ExcIndexRange(i, 0, this->jacobian_grads.size()));
+
+ return this->jacobian_grads[i];
+}
+
+
+
template <int dim>
template <class InputVector>
inline
* filled have to have the
* correct size.
*
- * Values are split into three
+ * Values are split into two
* groups: first,
* @p quadrature_points and
* @p JxW_values are
* matrices needed to transform
* vector-valued functions,
* namely
- * @p covariant_transformation,
- * @p contravariant_transformation and the
- * derivatives
- * @p covariant_grads.
- *
+ * @p jacobians
+ * and the derivatives
+ * @p jacobian_grads.
*/
virtual void
fill_fe_values (const typename Triangulation<dim>::cell_iterator &cell,
const Quadrature<dim> &quadrature,
InternalDataBase &internal,
std::vector<Point<dim> > &quadrature_points,
- std::vector<double> &JxW_values) const = 0;
+ std::vector<double> &JxW_values,
+ std::vector<Tensor<2,dim> > &jacobians,
+ std::vector<Tensor<3,dim> > &jacobian_grads) const = 0;
/**
* Performs the same as @p fill_fe_values
const Quadrature<dim>& quadrature,
typename Mapping<dim>::InternalDataBase &mapping_data,
std::vector<Point<dim> > &quadrature_points,
- std::vector<double> &JxW_values) const ;
+ std::vector<double> &JxW_values,
+ std::vector<Tensor<2,dim> > &jacobians,
+ std::vector<Tensor<3,dim> > &jacobian_grads) const ;
virtual void
fill_fe_face_values (const typename Triangulation<dim>::cell_iterator &cell,
const Quadrature<dim> &quadrature,
typename Mapping<dim>::InternalDataBase &mapping_data,
typename std::vector<Point<dim> > &quadrature_points,
- std::vector<double> &JxW_values) const ;
+ std::vector<double> &JxW_values,
+ std::vector<Tensor<2,dim> > &jacobians,
+ std::vector<Tensor<3,dim> > &jacobian_grads) const ;
/**
* Implementation of the interface in
Tensor<1,dim> &derivative (const unsigned int qpoint,
const unsigned int shape_nr);
+ /**
+ * Second derivative of shape
+ * function in quadrature
+ * point. See above.
+ */
+ Tensor<2,dim> second_derivative (const unsigned int qpoint,
+ const unsigned int shape_nr) const;
+
+ /**
+ * Second derivative of shape
+ * function in quadrature
+ * point. See above.
+ */
+ Tensor<2,dim> &second_derivative (const unsigned int qpoint,
+ const unsigned int shape_nr);
+
/**
* Return an estimate (in
* bytes) or the memory
*/
std::vector<Tensor<1,dim> > shape_derivatives;
+ /**
+ * Values of shape function
+ * second derivatives. Access
+ * by function
+ * @p second_derivative.
+ *
+ * Computed once.
+ */
+ std::vector<Tensor<2,dim> > shape_second_derivatives;
+
/**
* Tensors of covariant
* transformation at each of
* contravariant matrix is
* the Jacobian of the
* transformation,
- * i.e. $J_ij=dx_i/d\hat x_j$.
+ * i.e. $J_{ij}=dx_i/d\hat x_j$.
*
* Computed on each cell.
*/
const Quadrature<dim>& quadrature,
typename Mapping<dim>::InternalDataBase &mapping_data,
typename std::vector<Point<dim> > &quadrature_points,
- std::vector<double> &JxW_values) const ;
+ std::vector<double> &JxW_values,
+ std::vector<Tensor<2,dim> > &jacobians,
+ std::vector<Tensor<3,dim> > &jacobian_grads) const ;
/**
* Implementation of the interface in
*/
void compute_fill_face (const typename Triangulation<dim>::cell_iterator &cell,
const unsigned int face_no,
- const bool is_subface,
+ const unsigned int subface_no,
const unsigned int npts,
const DataSetDescriptor data_set,
const std::vector<double> &weights,
}
+template <int dim>
+inline
+Tensor<2,dim>
+MappingQ1<dim>::InternalData::second_derivative (const unsigned int qpoint,
+ const unsigned int shape_nr) const
+{
+ Assert(qpoint*n_shape_functions + shape_nr < shape_second_derivatives.size(),
+ ExcIndexRange(qpoint*n_shape_functions + shape_nr, 0,
+ shape_second_derivatives.size()));
+ return shape_second_derivatives [qpoint*n_shape_functions + shape_nr];
+}
+
+
+
+template <int dim>
+inline
+Tensor<2,dim> &
+MappingQ1<dim>::InternalData::second_derivative (const unsigned int qpoint,
+ const unsigned int shape_nr)
+{
+ Assert(qpoint*n_shape_functions + shape_nr < shape_second_derivatives.size(),
+ ExcIndexRange(qpoint*n_shape_functions + shape_nr, 0,
+ shape_second_derivatives.size()));
+ return shape_second_derivatives [qpoint*n_shape_functions + shape_nr];
+}
+
template <> void MappingQ1<1>::compute_fill_face (
const Triangulation<1>::cell_iterator &,
const unsigned int,
- const bool,
+ const unsigned int,
const unsigned int,
const DataSetDescriptor,
const std::vector<double> &,
// $Id$
// Version: $Name$
//
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
static
std::vector<typename Container::active_cell_iterator>
get_active_child_cells (const typename Container::cell_iterator &cell);
-
+
+ /**
+ * Extract the active cells around a given
+ * cell @p cell and return them in the
+ * vector @p active_neighbors.
+ */
+ template <class Container>
+ static void
+ get_active_neighbors (const typename Container::active_cell_iterator &cell,
+ std::vector<typename Container::active_cell_iterator> &active_neighbors);
/**
* Use the METIS partitioner to generate
if (cell->has_children())
{
for (unsigned int child=0;
- child<GeometryInfo<DH::dimension>::children_per_cell; ++child)
+ child<cell->n_children(); ++child)
if (cell->child (child)->has_children())
{
const std::vector<typename DH::active_cell_iterator>
}
+
+#if deal_II_dimension == 1
+
+template <class Container>
+void
+GridTools::get_active_neighbors(const typename Container::active_cell_iterator &cell,
+ std::vector<typename Container::active_cell_iterator> &active_neighbors)
+{
+ active_neighbors.clear ();
+ for (unsigned int n=0; n<GeometryInfo<1>::faces_per_cell; ++n)
+ if (! cell->at_boundary(n))
+ {
+ // check children of neighbor. note
+ // that in 1d children of the neighbor
+ // may be further refined. In 1d the
+ // case is simple since we know what
+ // children bound to the present cell
+ typename Container::cell_iterator
+ neighbor_child = cell->neighbor(n);
+ if (!neighbor_child->active())
+ {
+ while (neighbor_child->has_children())
+ neighbor_child = neighbor_child->child (n==0 ? 1 : 0);
+
+ Assert (neighbor_child->neighbor(n==0 ? 1 : 0)==cell,
+ ExcInternalError());
+ }
+ active_neighbors.push_back (neighbor_child);
+ }
+}
+
+#else
+
+template <class Container>
+void
+GridTools::get_active_neighbors(const typename Container::active_cell_iterator &cell,
+ std::vector<typename Container::active_cell_iterator> &active_neighbors)
+{
+ active_neighbors.clear ();
+ for (unsigned int n=0; n<GeometryInfo<Container::dimension>::faces_per_cell; ++n)
+ if (! cell->at_boundary(n))
+ {
+ if (cell->face(n)->has_children())
+ // this neighbor has children. find
+ // out which border to the present
+ // cell
+ for (unsigned int c=0; c<cell->face(n)->number_of_children(); ++c)
+ active_neighbors.push_back (cell->neighbor_child_on_subface(n,c));
+ else
+ {
+ // the neighbor must be active
+ // himself
+ Assert(cell->neighbor(n)->active(), ExcInternalError());
+ active_neighbors.push_back(cell->neighbor(n));
+ }
+ }
+}
+
+
+#endif
+
+
+
+
// declaration of explicit specializations
template <>
double
* @p limit_level_difference_at_vertices, situations as the above one are
* eliminated by also marking the lower left cell for refinement.
*
+ * In case of anisotropic refinement, the level of a cell is not linked to
+ * the refinement of a cell as directly as in case of isotropic
+ * refinement. Furthermore, a cell can be strongly refined in one direction
+ * and not or at least much less refined in another. Therefore, it is very
+ * difficult to decide, which cases should be excluded from the refinement
+ * process. As a consequence, when using anisotropic refinement, the @p
+ * limit_level_difference_at_vertices flag must not be set.
+ *
* <li> @p eliminate_unrefined_islands:
* Single cells which are not refined and are surrounded by cells which are
* refined usually also lead to a sharp decline in approximation properties
* This flag includes all the above ones and therefore combines all
* smoothing algorithms implemented.
*
+ * <li> @p allow_anisotropic_smoothing:
+ * This flag is not included in @p maximum_smoothing. The flag is
+ * concerned with the following case: consider the case that an
+ * unrefined and a refined cell share a common face and that one
+ * of the children of the refined cell along the common face is
+ * flagged for further refinement. In that case, the resulting
+ * mesh would have more than one hanging node along one or more of
+ * the edges of the triangulation, a situation that is not
+ * allowed. Consequently, in order to perform the refinement, the
+ * coarser of the two original cells is also going to be refined.
+ *
+ * However, in many cases it is sufficient to refine the coarser
+ * of the two original cells in an anisotropic way to avoid the
+ * case of multiple hanging vertices on a single edge. Doing only
+ * the minimal anisotropic refinement can save cells and degrees
+ * of freedom. By specifying this flag, the library can produce
+ * these anisotropic refinements.
+ *
+ * The flag is not included by default since it may lead to
+ * anisotropically refined meshes even though no cell has ever
+ * been refined anisotropically explicitly by a user command. This
+ * surprising fact may lead to programs that do the wrong thing
+ * since they are not written for the additional cases that can
+ * happen with anisotropic meshes, see the discussion in the
+ * introduction to @ref step_30 "step-30".
+ *
* <li> @p none:
* Select no smoothing at all.
* </ul>
* object, you should be well aware that you might involuntarily alter the
* data stored in the triangulation.
*
- * @ingroup grid
+ * @ingroup grid aniso
* @author Wolfgang Bangerth, 1998; Ralf Hartmann, 2005
*/
template <int dim>
eliminate_unrefined_islands = 0x2,
patch_level_1 = 0x4,
coarsest_level_1 = 0x8,
+
+ allow_anisotropic_smoothing = 0x10,
eliminate_refined_inner_islands = 0x100,
eliminate_refined_boundary_islands = 0x200,
eliminate_refined_boundary_islands |
do_not_produce_unrefined_islands),
- maximum_smoothing = 0xffff
+ maximum_smoothing = 0xffff ^ allow_anisotropic_smoothing
};
*/
void load_coarsen_flags (const std::vector<bool> &v);
+ /**
+ * Return whether this triangulation has
+ * ever undergone anisotropic (as opposed
+ * to only isotropic) refinement.
+ */
+ bool get_anisotropic_refinement_flag() const;
/*@}*/
*/
void execute_coarsening ();
+ /**
+ * Actually refine a cell, i.e. create its
+ * children. The faces of the cell have to
+ * be refined already, whereas the inner
+ * lines in 2D or lines and quads in 3D
+ * will be created in this
+ * function. Therefore iterator pointers
+ * into the vectors of lines, quads and
+ * cells have to be passed, which point at
+ * (or "before") the reserved space.
+ */
+ void create_children (unsigned int &next_unused_vertex,
+ raw_line_iterator &next_unused_line,
+ raw_quad_iterator &next_unused_quad,
+ raw_cell_iterator &next_unused_cell,
+ cell_iterator &cell);
+
/**
* Actually delete a cell, or rather all
* its children, which is the main step for
* decide whether a refined line may be
* coarsened or not in 3D. In 1D and 2D
* this argument is not needed and thus
- * ignored.
+ * ignored. The same applies for the last
+ * argument and quads instead of lines.
*/
void delete_children (cell_iterator &cell,
- std::vector<unsigned int> &cell_count);
+ std::vector<unsigned int> &line_cell_count,
+ std::vector<unsigned int> &quad_cell_count);
+
+ /**
+ * Set the neighbor information of all
+ * outer neighbor of all children of the
+ * given cell <tt>cell</tt>, if
+ * <tt>refining=true</tt>. In this
+ * constellation the function is called
+ * after the creation of children in @p
+ * execute_refinement. If
+ * <tt>refining=false</tt>, it is assumed,
+ * that the given cell is just coarsened,
+ * i.e. that its children are about to be
+ * deleted, thus they do not need new
+ * neighbor information.
+ *
+ * In both cases, the neighbor information
+ * of the cell's neighbors are updated, if
+ * necessary.
+ */
+ void update_neighbors (cell_iterator &cell,
+ bool refining);
+
+ /**
+ * Fill the vector @p line_cell_count
+ * needed by @p delete_children with the
+ * number of cells containing a given
+ * line. As this is only needed in 3D, it
+ * is only implemented there and throws an
+ * exception otherwise.
+ */
+ void count_cells_at_line (std::vector<unsigned int> &line_cell_count);
/**
- * Fill the vector @p cell_count needed by
- * @p delete_children with the number of
- * cells containing a given line. As this
- * is only needed in 3D, it is only
- * implemented there and throws an
+ * Fill the vector @p quad_cell_count
+ * needed by @p delete_children with the
+ * number of cells containing a given
+ * quad. As this is only needed in 3D, it
+ * is only implemented there and throws an
* exception otherwise.
*/
- void count_cells_at_line (std::vector<unsigned int> &cell_count);
+ void count_cells_at_quad (std::vector<unsigned int> &quad_cell_count);
/**
* Some dimension dependent stuff for
*/
void prepare_refinement_dim_dependent ();
+ /**
+ * At the boundary of the domain, the new
+ * point on the face may be far inside the
+ * current cell, if the boundary has a
+ * strong curvature. If we allow anisotropic
+ * refinement here, the resulting cell may
+ * be strongly distorted. To prevent this,
+ * this function flags such cells for
+ * isotropic refinement. It is called
+ * automatically from
+ * prepare_coarsening_and_refinement().
+ */
+ void prevent_distorted_boundary_cells ();
+
/**
* Make sure that either all or none of
* the children of a cell are tagged for
* coarsening.
*/
void fix_coarsen_flags ();
+
+ /**
+ * Helper function for
+ * @p fix_coarsen_flags. Return wether
+ * coarsening of this cell is allowed.
+ * Coarsening can be forbidden if the
+ * neighboring cells are or will be
+ * refined twice along the common face.
+ */
+ bool coarsening_allowed (cell_iterator& cell);
/**
* Re-compute the number of
*/
SmartPointer<const Boundary<dim> > boundary[255];
+ /**
+ * Flag indicating whether
+ * anisotropic refinement took
+ * place.
+ */
+ bool anisotropic_refinement;
+
/**
* Do some smoothing in the process
* of refining the triangulation. See
template <> void Triangulation<2>::clear_user_flags ();
template <> void Triangulation<3>::clear_user_pointers ();
template <> void Triangulation<3>::clear_user_flags ();
+template <> void Triangulation<1>::clear_user_flags_line ();
template <> void Triangulation<1>::clear_user_flags_quad ();
template <> void Triangulation<1>::save_user_flags_quad (std::ostream &) const;
template <> void Triangulation<1>::save_user_flags_quad (std::vector<bool> &) const;
template <> void Triangulation<1>::save_user_flags_hex (std::vector<bool> &) const;
template <> void Triangulation<1>::load_user_flags_hex (std::istream &);
template <> void Triangulation<1>::load_user_flags_hex (const std::vector<bool> &);
+template <> void Triangulation<2>::clear_user_flags_quad ();
template <> void Triangulation<2>::clear_user_flags_hex ();
template <> void Triangulation<2>::save_user_flags_hex (std::ostream &) const;
template <> void Triangulation<2>::save_user_flags_hex (std::vector<bool> &) const;
template <> void Triangulation<2>::load_user_flags_hex (std::istream &);
template <> void Triangulation<2>::load_user_flags_hex (const std::vector<bool> &);
+template <> void Triangulation<3>::clear_user_flags_quad ();
+template <> void Triangulation<3>::clear_user_flags_hex ();
template <> Triangulation<1>::raw_cell_iterator Triangulation<1>::begin_raw (const unsigned int level) const;
template <> Triangulation<1>::active_cell_iterator Triangulation<1>::begin_active (const unsigned int level) const;
template <> Triangulation<1>::raw_cell_iterator Triangulation<1>::last_raw () const;
template <> void Triangulation<2>::execute_refinement ();
template <> void Triangulation<3>::execute_refinement ();
template <> void Triangulation<3>::prepare_refinement_dim_dependent ();
-template <> void Triangulation<1>::delete_children (cell_iterator &cell, std::vector<unsigned int> &);
-template <> void Triangulation<2>::delete_children (cell_iterator &cell, std::vector<unsigned int> &);
-template <> void Triangulation<3>::delete_children (cell_iterator &cell, std::vector<unsigned int> &cell_count);
-template <> void Triangulation<3>::count_cells_at_line (std::vector<unsigned int> &cell_count);
+template <> void Triangulation<1>::delete_children (cell_iterator &cell,
+ std::vector<unsigned int> &,
+ std::vector<unsigned int> &);
+template <> void Triangulation<2>::delete_children (cell_iterator &cell,
+ std::vector<unsigned int> &,
+ std::vector<unsigned int> &);
+template <> void Triangulation<3>::delete_children (cell_iterator &cell,
+ std::vector<unsigned int> &line_cell_count,
+ std::vector<unsigned int> &quad_cell_count);
+template <> void Triangulation<2>::create_children (unsigned int &next_unused_vertex,
+ raw_line_iterator &next_unused_line,
+ raw_quad_iterator &next_unused_quad,
+ raw_cell_iterator &next_unused_cell,
+ cell_iterator &cell);
+template <> void Triangulation<3>::update_neighbors (cell_iterator &cell,
+ bool refining);
+template <> void Triangulation<3>::count_cells_at_line (std::vector<unsigned int> &line_cell_count);
+template <> void Triangulation<3>::count_cells_at_quad (std::vector<unsigned int> &quad_cell_count);
+template <> void Triangulation<1>::prevent_distorted_boundary_cells ();
template <> void Triangulation<1>::update_number_cache_quads ();
template <> void Triangulation<1>::update_number_cache_hexes ();
template <> void Triangulation<2>::update_number_cache_hexes ();
#include <base/config.h>
#include <base/exceptions.h>
+#include <base/geometry_info.h>
#include <grid/tria_iterator_base.h>
/**
* @ingroup Exceptions
*/
+ DeclException0 (ExcCellNotActive);
+ /**
+ * @ingroup Exceptions
+ */
DeclException1 (ExcInvalidNeighbor,
int,
<< "Neighbor indices must be between 0 and 2^dim-1, but "
* @ingroup Exceptions
*/
DeclException0 (ExcFacesHaveNoLevel);
+ /**
+ * @ingroup Exceptions
+ */
+ DeclException1 (ExcSetOnlyEvenChildren,
+ int,
+ << "You can only set the child index of an even numbered child."
+ << "The number of the child given was " << arg1 << ".");
}
* function.
*/
void recursively_clear_user_index () const;
+
+ /**
+ * Return the @p RefinementCase<dim>
+ * of this cell.
+ */
+ RefinementCase<celldim> refinement_case() const;
+
+ /**
+ * Set the @p RefinementCase<dim> this
+ * TriaObject is refined with.
+ * Not defined for
+ * <tt>celldim=1</tt> as lines
+ * are always refined resulting
+ * in 2 children lines (isotropic
+ * refinement).
+ *
+ * You should know quite exactly
+ * what you are doing if you
+ * touch this function. It is
+ * exclusively for internal use
+ * in the library.
+ */
+ void set_refinement_case (const RefinementCase<celldim> &ref_case) const;
+
+ /**
+ * Clear the RefinementCase<dim> of
+ * this TriaObject, i.e. reset it
+ * to RefinementCase<dim>::no_refinement.
+ *
+ * You should know quite exactly
+ * what you are doing if you
+ * touch this function. It is
+ * exclusively for internal use
+ * in the library.
+ */
+ void clear_refinement_case () const;
/*@}*/
/**
TriaIterator<dim,TriaObjectAccessor<celldim,dim> >
child (const unsigned int i) const;
+ /**
+ * Pointer to the @p object, which is
+ * identical to the ith child for
+ * isotropic refinement. If the object is
+ * refined anisotropically, the returned
+ * child will in fact be a grandchild of
+ * the object.
+ */
+ TriaIterator<dim,TriaObjectAccessor<celldim,dim> >
+ isotropic_child (const unsigned int i) const;
+
/**
* Index of the @p ith child.
* The level of the child is one
int child_index (const unsigned int i) const;
/**
- * Set the child field. Since we
- * only store the index of the
- * first child (the others
- * follow directly) only one
- * child index is to be
- * given. The level of the child
- * is one level up of the level
- * of the cell to which this
- * iterator points.
+ * Index of the @p ith isotropic_child.
+ * The level of the (grand-)child is
+ * higher than that of the
+ * present cell, if the children
+ * of a cell are accessed. The
+ * children of faces have no level.
+ * If the child does not exist, -1
+ * is returned.
+ */
+ int isotropic_child_index (const unsigned int i) const;
+
+ /**
+ * Set the index of the ith
+ * child. Since the children
+ * come at least in pairs, we
+ * need to store the index of
+ * only every second child,
+ * i.e. of the even numbered
+ * children. Make sure, that the
+ * index of child i=0 is set
+ * first. Calling this function
+ * for odd numbered children is
+ * not allowed.
*/
- void set_children (const int index) const;
+ void set_children (const unsigned int i, const int index) const;
/**
* Clear the child field,
* <tt>has_children()==true</tt>.
*/
unsigned int n_children() const;
+
+ /**
+ * Return the index of the vertex
+ * in the middle of this object,
+ * if it exists. In order to
+ * exist, the object needs to be
+ * refined - for 2D and 3D it
+ * needs to be refined
+ * isotropically or else the
+ * anisotropic children have to
+ * be refined again. If the
+ * middle vertex does not exist,
+ * return
+ * <tt>numbers::invalid_unsigned_int</tt>.
+ */
+ unsigned int middle_vertex_index() const;
/**
* Number of times that this
* which are not further
* refined. Thus, if all of the
* eight children of a hex are
- * further refined exactly once,
- * the returned number will be
- * 64, not 80.
+ * further refined isotropically
+ * exactly once, the returned
+ * number will be 64, not 80.
*
* If the present cell is not refined,
* one is returned.
* <tt>A *a=static_cast<A*>(cell->user_pointer());</tt>.
*/
void * user_pointer () const;
+
+ /**
+ * Return the @p RefinementCase<dim>
+ * of this cell.
+ */
+ RefinementCase<1> refinement_case() const;
/**
* Set the user index
TriaIterator<dim,TriaObjectAccessor<1, dim> >
child (const unsigned int i) const;
+ /**
+ * Pointer to the @p object, which is
+ * identical to the ith child for
+ * isotropic refinement. For lines this
+ * does exactly the same as
+ * <tt>child(i)</tt>.
+ */
+ TriaIterator<dim,TriaObjectAccessor<1,dim> >
+ isotropic_child (const unsigned int i) const;
+
/**
* Return the index of the
* @p ith child. The level of
int child_index (const unsigned int i) const;
/**
- * Set the child field. Since we
- * only store the index of the
- * first child (the others
- * follow directly) only one
- * child index is to be
- * given. The level of the child
+ * Index of the @p ith isotropic_child.
+ * The level of the (grand-)child is
+ * higher than that of the
+ * present cell, if the children
+ * of a cell are accessed. The
+ * children of faces have no level.
+ * If the child does not exist, -1
+ * is returned.
+ */
+ int isotropic_child_index (const unsigned int i) const;
+
+ /**
+ * Set the index of the ith
+ * child. Since the children
+ * come at least in pairs, we
+ * need to store the index of
+ * only every second child,
+ * i.e. of the even numbered
+ * children. Make sure, that the
+ * index of child i=0 is set
+ * first. Calling this function
+ * for odd numbered children is
+ * not allowed.
+ * The level of the child
* is one level up of the level
* of the cell to which this
* iterator points if
* Otherwise the line and its children
* have no level.
*/
- void set_children (const int index) const;
+ void set_children (const unsigned int i, const int index) const;
/**
* Clear the child field,
*/
unsigned int n_children() const;
+ /**
+ * Return the index of the vertex
+ * in the middle of this object,
+ * if it exists. In order to
+ * exist, the object needs to be
+ * refined - for 2D and 3D it
+ * needs to be refined
+ * isotropically or else the
+ * anisotropic children have to
+ * be refined again. If the
+ * middle vertex does not exist,
+ * return
+ * <tt>numbers::invalid_unsigned_int</tt>.
+ */
+ unsigned int middle_vertex_index() const;
+
/**
* Return the number of times
* that this cell is
* function.
*/
void recursively_clear_user_index () const;
+ /**
+
+ * Return the @p RefinementCase<dim>
+ * of this cell.
+ */
+ RefinementCase<2> refinement_case() const;
+
+ /**
+ * Set the @p RefinementCase<dim> this
+ * TriaObject is refined with.
+ *
+ * You should know quite exactly
+ * what you are doing if you
+ * touch this function. It is
+ * exclusively for internal use
+ * in the library.
+ */
+ void set_refinement_case (const RefinementCase<2> &refinement_case) const;
+
+ /**
+ * Clear the RefinementCase<dim> of
+ * this TriaObject, i.e. reset it
+ * to RefinementCase<dim>::no_refinement.
+ *
+ * You should know quite exactly
+ * what you are doing if you
+ * touch this function. It is
+ * exclusively for internal use
+ * in the library.
+ */
+ void clear_refinement_case () const;
+
/**
* Return a pointer to the @p ith
* child.
*/
TriaIterator<dim,TriaObjectAccessor<2, dim> > child (const unsigned int i) const;
+ /**
+ * Pointer to the @p object, which is
+ * identical to the ith child for
+ * isotropic refinement. If the object is
+ * refined anisotropically, the returned
+ * child will in fact be a grandchild of
+ * the object.
+ */
+ TriaIterator<dim,TriaObjectAccessor<2,dim> >
+ isotropic_child (const unsigned int i) const;
+
/**
* Return the index of the
* @p ith child. The level of
int child_index (const unsigned int i) const;
/**
- * Set the child field. Since we
- * only store the index of the
- * first child (the others
- * follow directly) only one
- * child index is to be
- * given. The level of the child
- * is one level up of the level
- * of the cell to which this
- * iterator points.
+ * Index of the @p ith isotropic_child.
+ * The level of the (grand-)child is
+ * higher than that of the
+ * present cell, if the children
+ * of a cell are accessed. The
+ * children of faces have no level.
+ * If the child does not exist, -1
+ * is returned.
+ */
+ int isotropic_child_index (const unsigned int i) const;
+
+ /**
+ * Set the index of the ith
+ * child. Since the children
+ * come at least in pairs, we
+ * need to store the index of
+ * only every second child,
+ * i.e. of the even numbered
+ * children. Make sure, that the
+ * index of child i=0 is set
+ * first. Calling this function
+ * for odd numbered children is
+ * not allowed.
*/
- void set_children (const int index) const;
+ void set_children (const unsigned int i, const int index) const;
/**
* Clear the child field,
*/
unsigned int n_children() const;
+ /**
+ * Return the index of the vertex
+ * in the middle of this object,
+ * if it exists. In order to
+ * exist, the object needs to be
+ * refined - for 2D and 3D it
+ * needs to be refined
+ * isotropically or else the
+ * anisotropic children have to
+ * be refined again. If the
+ * middle vertex does not exist,
+ * return
+ * <tt>numbers::invalid_unsigned_int</tt>.
+ */
+ unsigned int middle_vertex_index() const;
+
/**
* Return the number of times
* that this cell is
* number if quads which are not
* further refined. Thus, if all
* of the four children of a quad
- * are further refined exactly
- * once, the returned number will
- * be 16, not 20.
+ * are further refined
+ * isotropically exactly once,
+ * the returned number will be
+ * 16, not 20.
*
* If the present cell is not
* refined, one is returned.
*/
void recursively_clear_user_index () const;
+ /**
+ * Return the @p RefinementCase<dim>
+ * of this cell.
+ */
+ RefinementCase<3> refinement_case() const;
+
+ /**
+ * Set the @p RefinementCase<dim> this
+ * TriaObject is refined with.
+ *
+ * You should know quite exactly
+ * what you are doing if you
+ * touch this function. It is
+ * exclusively for internal use
+ * in the library.
+ */
+ void set_refinement_case (const RefinementCase<3> &ref_case) const;
+
+ /**
+ * Clear the RefinementCase<dim> of
+ * this TriaObject, i.e. reset it
+ * to RefinementCase<dim>::no_refinement.
+ *
+ * You should know quite exactly
+ * what you are doing if you
+ * touch this function. It is
+ * exclusively for internal use
+ * in the library.
+ */
+ void clear_refinement_case () const;
+
/**
* Return a pointer to the
* @p ith child.
TriaIterator<dim,TriaObjectAccessor<3, dim> >
child (const unsigned int i) const;
+ /**
+ * Pointer to the @p object, which is
+ * identical to the ith child for
+ * isotropic refinement. If the object is
+ * refined anisotropically, the returned
+ * child will in fact be a grandchild of
+ * the object.
+ */
+ TriaIterator<dim,TriaObjectAccessor<3,dim> >
+ isotropic_child (const unsigned int i) const;
+
/**
* Return the index of the
* @p ith child. The level of
int child_index (const unsigned int i) const;
/**
- * Set the child field. Since we
- * only store the index of the
- * first child (the others
- * follow directly) only one
- * child index is to be
- * given. The level of the child
- * is one level up of the level
- * of the cell to which this
- * iterator points.
+ * Index of the @p ith isotropic_child.
+ * The level of the (grand-)child is
+ * higher than that of the
+ * present cell, if the children
+ * of a cell are accessed. The
+ * children of faces have no level.
+ * If the child does not exist, -1
+ * is returned.
+ */
+ int isotropic_child_index (const unsigned int i) const;
+
+ /**
+ * Set the index of the ith
+ * child. Since the children
+ * come at least in pairs, we
+ * need to store the index of
+ * only every second child,
+ * i.e. of the even numbered
+ * children. Make sure, that the
+ * index of child i=0 is set
+ * first. Calling this function
+ * for odd numbered children is
+ * not allowed.
*/
- void set_children (const int index) const;
+ void set_children (const unsigned int i, const int index) const;
/**
* Clear the child field,
*/
unsigned int n_children() const;
+ /**
+ * Return the index of the vertex
+ * in the middle of this object,
+ * if it exists. In order to
+ * exist, the object needs to be
+ * refined - for 2D and 3D it
+ * needs to be refined
+ * isotropically or else the
+ * anisotropic children have to
+ * be refined again. If the
+ * middle vertex does not exist,
+ * return
+ * <tt>numbers::invalid_unsigned_int</tt>.
+ */
+ unsigned int middle_vertex_index() const;
+
/**
* Return the number of times
* that this cell is
* number if hexs which are not
* further refined. Thus, if all
* of the eight children of a hex
- * are further refined exactly
- * once, the returned number will
- * be 64, not 80.
+ * are further refined
+ * isotropically exactly once,
+ * the returned number will be
+ * 64, not 80.
*
* If the present cell is not
* refined, one is returned.
* Return the how-many'th
* neighbor this cell is of
* <tt>cell->neighbor(neighbor)</tt>,
- * i.e. return the number @p n
+ * i.e. return the @p face_no
* such that
- * <tt>cell->neighbor(neighbor)->neighbor(n)==cell</tt>. This
+ * <tt>cell->neighbor(neighbor)->neighbor(face_no)==cell</tt>. This
* function is the right one if
* you want to know how to get
* back from a neighbor to the
*
* Note that this operation is
* only useful if the neighbor is
- * not on a coarser level than
- * the present cell
- * (i.e. <tt>cell->neighbor(neighbor)->level()</tt>
- * needs to be equal to
- * <tt>cell->level()</tt>. Use the
- * @p neighbor_of_coarser_neighbor
+ * not coarser than the present
+ * cell. If the neighbor is
+ * coarser this function throws
+ * an exception. Use the @p
+ * neighbor_of_coarser_neighbor
* function in that case.
*/
unsigned int neighbor_of_neighbor (const unsigned int neighbor) const;
+
+ /**
+ * Return, whether the neighbor
+ * is coarser then the present
+ * cell. This is important in
+ * case of ansiotropic
+ * refinement where this
+ * information does not depend on
+ * the levels of the cells.
+ *
+ * Note, that in an anisotropic
+ * setting, a cell can only be
+ * coarser than another one at a
+ * given face, not on a general
+ * basis. The face of the finer
+ * cell is contained in the
+ * corresponding face of the
+ * coarser cell, the finer face
+ * is either a child or a
+ * grandchild of the coarser
+ * face.
+ */
+ bool neighbor_is_coarser (const unsigned int neighbor) const;
/**
- * This function is a
- * generalization of the
- * @p neighbor_of_neighbor
- * function for the case of a
- * coarser neighbor. It returns a
- * pair of numbers, face_no and
- * subface_no, with the following
- * property:
+ * This function is a generalization of the
+ * @p neighbor_of_neighbor function for the
+ * case of a coarser neighbor. It returns a
+ * pair of numbers, face_no and subface_no,
+ * with the following property, if the
+ * neighbor is not refined:
* <tt>cell->neighbor(neighbor)->neighbor_child_on_subface(face_no,subface_no)==cell</tt>.
+ * In 3D, a coarser neighbor can still be
+ * refined. In that case subface_no denotes the child index of the neighbors face that relates to our face:
+ * <tt>cell->neighbor(neighbor)->face(face_no)->child(subface_no)==cell->face(neighbor)</tt>.
+ * This case in 3d and how it can happen
+ * is discussed in the introduction of the
+ * @ref step_30 "step-30" tutorial program.
*
* This function is impossible
* for <tt>dim==1</tt>.
std::pair<unsigned int, unsigned int>
neighbor_of_coarser_neighbor (const unsigned int neighbor) const;
+ /**
+ * This function is a generalization of the
+ * @p neighbor_of_neighbor and the @p
+ * neighbor_of_coarser_neighbor
+ * functions. It checks whether the
+ * neighbor is coarser or not and calls the
+ * respective function. In both cases, only
+ * the face_no is returned.
+ */
+ unsigned int neighbor_face_no (const unsigned int neighbor) const;
+
/**
* Return whether the @p ith
* vertex or face (depending on
bool has_boundary_lines () const;
/**
- * Return whether the refinement
- * flag is set or not.
+ * Return the @p
+ * RefinementCase<dim> this cell
+ * was flagged to be refined
+ * with.
*/
- bool refine_flag_set () const;
+ RefinementCase<dim> refine_flag_set () const;
/**
- * Flag the cell pointed to fo
+ * Flag the cell pointed to for
* refinement. This function is
* only allowed for active
* cells.
*/
- void set_refine_flag () const;
+ void set_refine_flag (const RefinementCase<dim> ref_case = RefinementCase<dim>::isotropic_refinement) const;
/**
* Clear the refinement flag.
*/
void clear_refine_flag () const;
+ /**
+ * Modify the refinement flag of the cell
+ * to ensure (at least) the given
+ * refinement case @p face_refinement_case at
+ * face <tt>face_no</tt>, taking into
+ * account orientation, flip and rotation
+ * of the face. Return, whether the
+ * refinement flag had to be
+ * modified. This function is only allowed
+ * for active cells.
+ */
+ bool flag_for_face_refinement (const unsigned int face_no,
+ const RefinementCase<dim-1> &face_refinement_case=RefinementCase<dim-1>::isotropic_refinement) const;
+
+ /**
+ * Modify the refinement flag of the cell
+ * to ensure that line <tt>face_no</tt>
+ * will be refined. Return, whether the
+ * refinement flag had to be
+ * modified. This function is only allowed
+ * for active cells.
+ */
+ bool flag_for_line_refinement (const unsigned int line_no) const;
+
+ /**
+ * Return the SubfaceCase of face
+ * <tt>face_no</tt>. Note that this is not
+ * identical to asking
+ * <tt>cell->face(face_no)->refinement_case()</tt>
+ * since the latter returns a RefinementCase<dim-1>
+ * and thus only considers one
+ * (anisotropic) refinement, whereas this
+ * function considers the complete
+ * refinement situation including possible
+ * refinement of the face's children. This
+ * function may only be called for active
+ * cells in 2d and 3d.
+ */
+ internal::SubfaceCase<dim> subface_case(const unsigned int face_no) const;
+
/**
* Return whether the coarsen flag
* is set or not.
* for the index of the
* child.
*
- * However, the function is more
+ * However, the situation is more
* complicated in 3d, since there faces may
* have more than one orientation, and we
* have to use @p face_orientation, @p
* necessarily the @p sf-th child
* of the face of this cell. This
* is so because the @p
- * subface_no parameter to this
- * function corresponds to the
+ * subface_no on a cell corresponds to the
* subface with respect to the
* intrinsic ordering of the
* present cell, whereas children
* of which indicate a non-standard face
* have to be considered.
*
- * Fortunately, this is only very rarely
- * of concern, since one is usually only
- * concerned either in the exact number
- * of a subface, or in the cell that is
- * behind it, not in both at the same
- * time.
+ * Fortunately, this is only very rarely of
+ * concern, since usually one simply wishes
+ * to loop over all finer neighbors at a
+ * given face of an active cell. Only in
+ * the process of refinement of a
+ * Triangulation we want to set neighbor
+ * information for both our child cells and
+ * the neighbor's children. Since we can
+ * respect orientation of faces from our
+ * current cell in that case, we do NOT
+ * respect face_orientation, face_flip and
+ * face_rotation of the present cell within
+ * this function, i.e. the returned
+ * neighbor's child is behind subface @p
+ * subface concerning the intrinsic
+ * ordering of the given face.
*/
TriaIterator<dim,CellAccessor<dim> >
neighbor_child_on_subface (const unsigned int face_no,
*/
DeclException0 (ExcCellFlaggedForCoarsening);
+ protected:
+ /**
+ * This function assumes that the
+ * neighbor is not coarser than
+ * the current cell. In this case
+ * it returns the
+ * neighbor_of_neighbor() value.
+ * If, however, the neighbor is
+ * coarser this function returns
+ * an
+ * <code>invalid_unsigned_int</code>.
+ *
+ * This function is not for
+ * public use. Use the function
+ * neighbor_of_neighbor() instead
+ * which throws an exception if
+ * called for a coarser
+ * neighbor. If neighbor is
+ * indeed coarser (you get to
+ * know this by e.g. the
+ * neighbor_is_coarser()
+ * function) then the
+ * neighbor_of_coarser_neighbor()
+ * function should be call. If
+ * you'd like to know only the
+ * <code>face_no</code> which is
+ * required to get back from the
+ * neighbor to the present cell
+ * then simply use the
+ * neighbor_face_no() function
+ * which can be used for coarser
+ * as well as noncoarser
+ * neighbors.
+ */
+ unsigned int neighbor_of_neighbor_internal (const unsigned int neighbor) const;
+
private:
/**
}
+template <int dim>
+inline
+RefinementCase<1>
+TriaObjectAccessor<1, dim>::refinement_case() const
+{
+ Assert (this->state() == IteratorState::valid,
+ TriaAccessorExceptions::ExcDereferenceInvalidObject());
+
+ return objects().children[this->present_index] != -1 ?
+ RefinementCase<1>::cut_x : RefinementCase<1>::no_refinement;
+}
+
+
template <int dim>
inline
+template <int dim>
+inline
+int
+TriaObjectAccessor<1,dim>::isotropic_child_index (const unsigned int i) const
+{
+ return child_index(i);
+}
+
+
+
template <int dim>
inline
TriaIterator<dim,TriaObjectAccessor<1,dim> >
+template <int dim>
+inline
+TriaIterator<dim,TriaObjectAccessor<1,dim> >
+TriaObjectAccessor<1,dim>::isotropic_child (const unsigned int i) const
+{
+ // no anisotropic refinement in 1D
+ return child(i);
+}
+
+
+
template <int dim>
inline
unsigned int
TriaObjectAccessor<1,dim>::n_children () const
{
Assert (has_children()==true, TriaAccessorExceptions::ExcCellHasNoChildren());
- return GeometryInfo<1>::children_per_cell;
+ return GeometryInfo<1>::max_children_per_cell;
+}
+
+
+
+template <int dim>
+inline
+unsigned int
+TriaObjectAccessor<1,dim>::middle_vertex_index () const
+{
+ if (has_children())
+ return child(0)->vertex_index(1);
+ return numbers::invalid_unsigned_int;
}
// has no level)
if (this->present_index
>=
- static_cast<int>(this->tria->faces->lines.cells.size()))
+ static_cast<int>(objects().cells.size()))
this->present_index = -1;
}
+template <int dim>
+inline
+RefinementCase<2>
+TriaObjectAccessor<2, dim>::refinement_case () const
+{
+ Assert (this->state() == IteratorState::valid,
+ TriaAccessorExceptions::ExcDereferenceInvalidObject());
+ Assert (static_cast<unsigned int> (this->present_index) <
+ objects().refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ objects().refinement_cases.size()));
+
+ return objects().refinement_cases[this->present_index];
+}
+
+
+
+template <int dim>
+inline
+void
+TriaObjectAccessor<2, dim>::set_refinement_case (const RefinementCase<2> &refinement_case) const
+{
+ Assert (this->state() == IteratorState::valid,
+ TriaAccessorExceptions::ExcDereferenceInvalidObject());
+ Assert (static_cast<unsigned int> (this->present_index) <
+ objects().refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ objects().refinement_cases.size()));
+
+ objects().refinement_cases[this->present_index] = refinement_case;
+}
+
+
+template <int dim>
+inline
+void
+TriaObjectAccessor<2, dim>::clear_refinement_case () const
+{
+ Assert (this->state() == IteratorState::valid,
+ TriaAccessorExceptions::ExcDereferenceInvalidObject());
+ Assert (static_cast<unsigned int> (this->present_index) <
+ objects().refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ objects().refinement_cases.size()));
+
+ objects().refinement_cases[this->present_index] = RefinementCase<2>::no_refinement;
+}
+
+
template <int dim>
inline
bool
{
Assert (this->state() == IteratorState::valid,
TriaAccessorExceptions::ExcDereferenceInvalidObject());
- return (objects().children[this->present_index] != -1);
+ return (objects().children[2*this->present_index] != -1);
}
{
Assert (i<4, ExcIndexRange(i,0,4));
Assert (has_children(), TriaAccessorExceptions::ExcCellHasNoChildren());
- return objects().children[this->present_index]+i;
+ return objects().children[2*this->present_index+i/2]+i%2;
+}
+
+
+
+template <int dim>
+inline
+int TriaObjectAccessor<2,dim>::isotropic_child_index (const unsigned int i) const
+{
+ switch (static_cast<unsigned char> (refinement_case()))
+ {
+ case RefinementCase<dim>::cut_x:
+ // this cell is refined with cut_x,
+ // so the child has to be refined
+ // with cut_y
+ if(child(i%2)->refinement_case()==RefinementCase<dim>::cut_y)
+ return child(i%2)->child_index(i/2);
+ else
+ Assert(false, ExcMessage("This cell has no grandchildren equivalent to isotropic refinement"));
+ break;
+ case RefinementCase<dim>::cut_y:
+ // this cell is refined with cut_y,
+ // so the child has to be refined
+ // with cut_x
+ if (child(i/2)->refinement_case()==RefinementCase<dim>::cut_x)
+ return child(i/2)->child_index(i%2);
+ else
+ Assert(false, ExcMessage("This cell has no grandchildren equivalent to isotropic refinement"));
+ break;
+ case RefinementCase<dim>::cut_xy:
+ return child_index(i);
+ break;
+ default:
+ Assert(false, TriaAccessorExceptions::ExcCellHasNoChildren());
+ break;
+ }
+ return -1;
}
+template <int dim>
+inline
+TriaIterator<dim,TriaObjectAccessor<2,dim> >
+TriaObjectAccessor<2,dim>::isotropic_child (const unsigned int i) const
+{
+ switch (static_cast<unsigned char> (refinement_case()))
+ {
+ case RefinementCase<dim>::cut_x:
+ // this cell is refined with cut_x,
+ // so the child has to be refined
+ // with cut_y
+ Assert(child(i%2)->refinement_case()==RefinementCase<dim>::cut_y,
+ ExcMessage("This cell has no grandchildren equivalent to isotropic refinement"));
+ return child(i%2)->child(i/2);
+ break;
+ case RefinementCase<dim>::cut_y:
+ // this cell is refined with cut_y,
+ // so the child has to be refined
+ // with cut_x
+ Assert(child(i/2)->refinement_case()==RefinementCase<dim>::cut_x,
+ ExcMessage("This cell has no grandchildren equivalent to isotropic refinement"));
+ return child(i/2)->child(i%2);
+ break;
+ default:
+ Assert(refinement_case()==RefinementCase<dim>::cut_xy,
+ TriaAccessorExceptions::ExcCellHasNoChildren());
+ break;
+ }
+ return child(i);
+}
+
+
+
template <int dim>
inline
unsigned int
TriaObjectAccessor<2,dim>::n_children () const
{
Assert (has_children()==true, TriaAccessorExceptions::ExcCellHasNoChildren());
- return GeometryInfo<2>::children_per_cell;
+ Assert (static_cast<unsigned int> (this->present_index) <
+ objects().refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ objects().refinement_cases.size()));
+
+ return GeometryInfo<2>::n_children(refinement_case());
+}
+
+
+
+template <int dim>
+inline
+unsigned int
+TriaObjectAccessor<2,dim>::middle_vertex_index () const
+{
+ switch (static_cast<unsigned char> (refinement_case()))
+ {
+ case RefinementCase<dim>::cut_x:
+ return child(0)->line(1)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_y:
+ return child(0)->line(3)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_xy:
+ return child(0)->vertex_index(3);
+ break;
+ default:
+ break;
+ }
+ return numbers::invalid_unsigned_int;
}
template <>
inline
+RefinementCase<3>
+TriaObjectAccessor<3, 3>::refinement_case () const
+{
+ Assert (this->state() == IteratorState::valid,
+ TriaAccessorExceptions::ExcDereferenceInvalidObject());
+ Assert (static_cast<unsigned int> (this->present_index) <
+ this->tria->levels[this->present_level]->cells.refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ this->tria->levels[this->present_level]->
+ cells.refinement_cases.size()));
+
+ return this->tria->levels[this->present_level]->cells.refinement_cases[this->present_index];
+}
+
+
+
+template <>
+inline
+void
+TriaObjectAccessor<3, 3>::set_refinement_case (const RefinementCase<3> &refinement_case) const
+{
+ Assert (static_cast<unsigned int> (this->present_index) <
+ this->tria->levels[this->present_level]->cells.refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ this->tria->levels[this->present_level]->
+ cells.refinement_cases.size()));
+
+ this->tria->levels[this->present_level]->
+ cells.refinement_cases[this->present_index] = refinement_case;
+}
+
+
+template <>
+inline
+void
+TriaObjectAccessor<3, 3>::clear_refinement_case () const
+{
+ Assert (this->state() == IteratorState::valid,
+ TriaAccessorExceptions::ExcDereferenceInvalidObject());
+ Assert (static_cast<unsigned int> (this->present_index) <
+ this->tria->levels[this->present_level]->cells.refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ this->tria->levels[this->present_level]->
+ cells.refinement_cases.size()));
+
+ this->tria->levels[this->present_level]->
+ cells.refinement_cases[this->present_index] = RefinementCase<3>::no_refinement;
+}
+
+
+
+template<>
+inline
bool
TriaObjectAccessor<3,3>::has_children () const
{
Assert (this->state() == IteratorState::valid,
TriaAccessorExceptions::ExcDereferenceInvalidObject());
- return (this->tria->levels[this->present_level]->cells.children[this->present_index] != -1);
+ return (this->tria->levels[this->present_level]->cells.children[4*this->present_index] != -1);
}
{
Assert (i<8, ExcIndexRange(i,0,8));
Assert (has_children(), TriaAccessorExceptions::ExcCellHasNoChildren());
- return this->tria->levels[this->present_level]->cells.children[this->present_index]+i;
+ return this->tria->levels[this->present_level]->cells.children[4*this->present_index+i/2]+i%2;
+}
+
+
+
+template <>
+inline
+int TriaObjectAccessor<3,3>::isotropic_child_index (const unsigned int i) const
+{
+ AssertThrow(false, ExcNotImplemented());
+ return child_index(i);
}
-template <int dim>
+template <>
+inline
+TriaIterator<3,TriaObjectAccessor<3,3> >
+TriaObjectAccessor<3,3>::isotropic_child (const unsigned int i) const
+{
+ AssertThrow(false, ExcNotImplemented());
+ return child(i);
+}
+
+
+
+template <>
inline
unsigned int
-TriaObjectAccessor<3,dim>::n_children () const
+TriaObjectAccessor<3,3>::n_children () const
{
Assert (has_children()==true, TriaAccessorExceptions::ExcCellHasNoChildren());
- return GeometryInfo<3>::children_per_cell;
+ Assert (static_cast<unsigned int> (this->present_index) <
+ this->tria->levels[this->present_level]->cells.refinement_cases.size(),
+ ExcIndexRange(this->present_index, 0,
+ this->tria->levels[this->present_level]->
+ cells.refinement_cases.size()));
+
+ return GeometryInfo<3>::n_children(refinement_case());
}
+
+template <int dim>
+inline
+unsigned int
+TriaObjectAccessor<3,dim>::middle_vertex_index () const
+{
+ switch (static_cast<unsigned char> (refinement_case()))
+ {
+ case RefinementCase<dim>::cut_x:
+ return child(0)->quad(1)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_y:
+ return child(0)->quad(3)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_z:
+ return child(0)->quad(5)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_xy:
+ return child(0)->line(11)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_xz:
+ return child(0)->line(5)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_yz:
+ return child(0)->line(7)->middle_vertex_index();
+ break;
+ case RefinementCase<dim>::cut_xyz:
+ return child(0)->vertex_index(7);
+ break;
+ default:
+ break;
+ }
+ return numbers::invalid_unsigned_int;
+}
+
+
+
template <int dim>
inline
unsigned int
template <int dim>
inline
-bool
+RefinementCase<dim>
CellAccessor<dim>::refine_flag_set () const
{
Assert (this->used(), TriaAccessorExceptions::ExcCellNotUsed());
// flag is not cleared).
Assert (this->active() || !this->tria->levels[this->present_level]->refine_flags[this->present_index],
ExcRefineCellNotActive());
- return this->tria->levels[this->present_level]->refine_flags[this->present_index];
+ return RefinementCase<dim>(this->tria->levels[this->present_level]->refine_flags[this->present_index]);
}
template <int dim>
inline
void
-CellAccessor<dim>::set_refine_flag () const
+CellAccessor<dim>::set_refine_flag (const RefinementCase<dim> refinement_case) const
{
Assert (this->used() && this->active(), ExcRefineCellNotActive());
Assert (!coarsen_flag_set(),
ExcCellFlaggedForCoarsening());
- this->tria->levels[this->present_level]->refine_flags[this->present_index] = true;
+ this->tria->levels[this->present_level]->refine_flags[this->present_index] = refinement_case;
}
CellAccessor<dim>::clear_refine_flag () const
{
Assert (this->used() && this->active(), ExcRefineCellNotActive());
- this->tria->levels[this->present_level]->refine_flags[this->present_index] = false;
+ this->tria->levels[this->present_level]->refine_flags[this->present_index] =
+ RefinementCase<dim>::no_refinement;
+}
+
+
+
+template <int dim>
+inline
+bool
+CellAccessor<dim>::flag_for_face_refinement (const unsigned int face_no,
+ const RefinementCase<dim-1> &face_refinement_case) const
+{
+ Assert (dim>1, ExcImpossibleInDim(dim));
+ Assert (face_no<GeometryInfo<dim>::faces_per_cell,
+ ExcIndexRange(face_no,0,GeometryInfo<dim>::faces_per_cell));
+ Assert (face_refinement_case < RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(face_refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+
+ // the new refinement case is a combination
+ // of the minimum required one for the given
+ // face refinement and the already existing
+ // flagged refinement case
+ RefinementCase<dim> old_ref_case = refine_flag_set();
+ RefinementCase<dim>
+ new_ref_case = (old_ref_case
+ | GeometryInfo<dim>::min_cell_refinement_case_for_face_refinement(face_refinement_case,
+ face_no,
+ this->face_orientation(face_no),
+ this->face_flip(face_no),
+ this->face_rotation(face_no)));
+ set_refine_flag(new_ref_case);
+ // return, whether we had to change the
+ // refinement flag
+ return new_ref_case != old_ref_case;
+}
+
+
+
+template <int dim>
+inline
+bool
+CellAccessor<dim>::flag_for_line_refinement (const unsigned int line_no) const
+{
+ Assert (dim>1, ExcImpossibleInDim(dim));
+ Assert (line_no<GeometryInfo<dim>::lines_per_cell,
+ ExcIndexRange(line_no,0,GeometryInfo<dim>::lines_per_cell));
+
+ // the new refinement case is a combination
+ // of the minimum required one for the given
+ // line refinement and the already existing
+ // flagged refinement case
+ RefinementCase<dim> old_ref_case=refine_flag_set(),
+ new_ref_case=old_ref_case
+ | GeometryInfo<dim>::min_cell_refinement_case_for_line_refinement(line_no);
+ set_refine_flag(new_ref_case);
+ // return, whether we had to change the
+ // refinement flag
+ return new_ref_case != old_ref_case;
+}
+
+
+
+template <>
+inline
+internal::SubfaceCase<1>
+CellAccessor<1>::subface_case(const unsigned int) const
+{
+ Assert(false, ExcImpossibleInDim(1));
+ return internal::SubfaceCase<1>::case_none;
+}
+
+
+
+template <>
+inline
+internal::SubfaceCase<2>
+CellAccessor<2>::subface_case(const unsigned int face_no) const
+{
+ Assert(active(), TriaAccessorExceptions::ExcCellNotActive());
+ Assert(face_no<GeometryInfo<2>::faces_per_cell,
+ ExcIndexRange(face_no,0,GeometryInfo<2>::faces_per_cell));
+ return (face(face_no)->has_children()) ? internal::SubfaceCase<2>::case_x : internal::SubfaceCase<2>::case_none;
+}
+
+
+
+template <>
+inline
+internal::SubfaceCase<3>
+CellAccessor<3>::subface_case(const unsigned int face_no) const
+{
+ Assert(active(), TriaAccessorExceptions::ExcCellNotActive());
+ Assert(face_no<GeometryInfo<3>::faces_per_cell,
+ ExcIndexRange(face_no,0,GeometryInfo<3>::faces_per_cell));
+ switch (static_cast<unsigned char> (face(face_no)->refinement_case()))
+ {
+ case RefinementCase<3>::no_refinement:
+ return internal::SubfaceCase<3>::case_none;
+ break;
+ case RefinementCase<3>::cut_x:
+ if (face(face_no)->child(0)->has_children())
+ {
+ Assert(face(face_no)->child(0)->refinement_case()==RefinementCase<3>::cut_y,
+ ExcInternalError());
+ if (face(face_no)->child(1)->has_children())
+ {
+ Assert(face(face_no)->child(1)->refinement_case()==RefinementCase<3>::cut_y,
+ ExcInternalError());
+ return internal::SubfaceCase<3>::case_x1y2y;
+ }
+ else
+ return internal::SubfaceCase<3>::case_x1y;
+ }
+ else
+ {
+ if (face(face_no)->child(1)->has_children())
+ {
+ Assert(face(face_no)->child(1)->refinement_case()==RefinementCase<3>::cut_y,
+ ExcInternalError());
+ return internal::SubfaceCase<3>::case_x2y;
+ }
+ else
+ return internal::SubfaceCase<3>::case_x;
+ }
+ break;
+ case RefinementCase<3>::cut_y:
+ if (face(face_no)->child(0)->has_children())
+ {
+ Assert(face(face_no)->child(0)->refinement_case()==RefinementCase<3>::cut_x,
+ ExcInternalError());
+ if (face(face_no)->child(1)->has_children())
+ {
+ Assert(face(face_no)->child(1)->refinement_case()==RefinementCase<3>::cut_x,
+ ExcInternalError());
+ return internal::SubfaceCase<3>::case_y1x2x;
+ }
+ else
+ return internal::SubfaceCase<3>::case_y1x;
+ }
+ else
+ {
+ if (face(face_no)->child(1)->has_children())
+ {
+ Assert(face(face_no)->child(1)->refinement_case()==RefinementCase<3>::cut_x,
+ ExcInternalError());
+ return internal::SubfaceCase<3>::case_y2x;
+ }
+ else
+ return internal::SubfaceCase<3>::case_y;
+ }
+ break;
+ case RefinementCase<3>::cut_xy:
+ return internal::SubfaceCase<3>::case_xy;
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ }
+ // we should never get here
+ return internal::SubfaceCase<3>::case_none;
}
return !this->has_children();
}
+
+
+template <int dim>
+inline
+unsigned int
+CellAccessor<dim>::neighbor_face_no (const unsigned int neighbor) const
+{
+ if (dim==1)
+ return neighbor_of_neighbor(neighbor);
+ else
+ {
+ const unsigned int n2=neighbor_of_neighbor_internal(neighbor);
+ if (n2!=numbers::invalid_unsigned_int)
+ // return this value as the
+ // neighbor is not coarser
+ return n2;
+ else
+ // the neighbor is coarser
+ return neighbor_of_coarser_neighbor(neighbor).first;
+ }
+}
+
DEAL_II_NAMESPACE_CLOSE
#endif
class TriaLevel
{
public:
- /**
- * Flags for the cells whether they are
- * to be refined or not. The meaning
- * what a cell is, is dimension specific,
- * therefore also the length of this
- * vector depends on the dimension: in
- * one dimension, the length of this
- * vector equals the length of the
- * @p lines vector, in two dimensions
- * that of the @p quads vector, etc.
- */
- std::vector<bool> refine_flags;
+ /**
+ * @p RefinementCase<dim>::Type flags
+ * for the cells to be
+ * refined with or not
+ * (RefinementCase<dim>::no_refinement). The
+ * meaning what a cell is,
+ * is dimension specific,
+ * therefore also the length
+ * of this vector depends on
+ * the dimension: in one
+ * dimension, the length of
+ * this vector equals the
+ * length of the @p lines
+ * vector, in two dimensions
+ * that of the @p quads
+ * vector, etc.
+ */
+ std::vector<unsigned char> refine_flags;
/**
* Same meaning as the one above, but
class TriaLevel<3>
{
public:
- std::vector<bool> refine_flags;
+ std::vector<unsigned char> refine_flags;
std::vector<bool> coarsen_flags;
std::vector<std::pair<int,int> > neighbors;
std::vector<unsigned int> subdomain_ids;
class TriaObject
{
public:
+ static const unsigned int dimension = structdim;
+
/**
* Default constructor,
* setting all face indices
// $Id$
// Version: $Name$
//
-// Copyright (C) 2006, 2007 by the deal.II authors
+// Copyright (C) 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
// declares mainly additional data. This would have to be changed in case of a
// partial specialization.
+template <int dim> class Triangulation;
+
+
namespace internal
{
namespace Triangulation
* objects additional information is included, namely vectors indicating the
* children, the used-status, user-flags, material-ids..
*
- * Objects of these classes are include in the TriaLevel and TriaFaces
+ * Objects of these classes are included in the TriaLevel and TriaFaces
* classes.
*
* @ingroup grid
*/
std::vector<G> cells;
/**
- * Index of the first child of an object.
+ * Index of the even children of an object.
* Since when objects are refined, all
* children are created at the same
* time, they are appended to the list
- * after each other.
+ * at least in pairs after each other.
* We therefore only store the index
- * of the first child, the others
+ * of the even children, the uneven
* follow immediately afterwards.
*
* If an object has no children, -1 is
*/
std::vector<int> children;
+ /**
+ * Store the refinement
+ * case each of the
+ * cells is refined
+ * with. This vector
+ * might be replaced by
+ * vector<vector<bool> >
+ * (dim, vector<bool>
+ * (n_cells)) which is
+ * more memory efficient.
+ */
+ std::vector<RefinementCase<G::dimension> > refinement_cases;
+
/**
* Vector storing whether an object is
* used in the @p cells vector.
std::vector<unsigned char> material_id;
/**
- * Assert that enough space is
- * allocated to accomodate
- * <tt>new_objs</tt> new objects.
- * This function does not only call
- * <tt>vector::reserve()</tt>, but
- * does really append the needed
- * elements.
+ * Assert that enough space
+ * is allocated to
+ * accomodate
+ * <code>new_objs_in_pairs</code>
+ * new objects, stored in
+ * pairs, plus
+ * <code>new_obj_single</code>
+ * stored individually.
+ * This function does not
+ * only call
+ * <code>vector::reserve()</code>,
+ * but does really append
+ * the needed elements.
+ *
+ * In 2D e.g. refined lines have to be
+ * stored in pairs, whereas new lines in the
+ * interior of refined cells can be stored as
+ * single lines.
*/
- void reserve_space (const unsigned int new_objs);
+ void reserve_space (const unsigned int new_objs_in_pairs,
+ const unsigned int new_objs_single = 0);
+
+ /**
+ * Return an iterator to the
+ * next free slot for a
+ * single line. Only
+ * implemented for
+ * <code>G=TriaObject<1>
+ * </code>.
+ */
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_line_iterator next_free_single_line (const dealii::Triangulation<dim> &tria);
+
+ /**
+ * Return an iterator to the
+ * next free slot for a pair
+ * of lines. Only implemented
+ * for <code>G=TriaObject<1>
+ * </code>.
+ */
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_line_iterator next_free_pair_line (const dealii::Triangulation<dim> &tria);
+
+ /**
+ * Return an iterator to the
+ * next free slot for a
+ * single quad. Only
+ * implemented for
+ * <code>G=TriaObject@<2@>
+ * </code>.
+ */
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_quad_iterator next_free_single_quad (const dealii::Triangulation<dim> &tria);
+
+ /**
+ * Return an iterator to the
+ * next free slot for a pair
+ * of quads. Only implemented
+ * for <code>G=TriaObject@<2@>
+ * </code>.
+ */
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_quad_iterator next_free_pair_quad (const dealii::Triangulation<dim> &tria);
+
+ /**
+ * Return an iterator to the
+ * next free slot for a pair
+ * of hexes. Only implemented
+ * for
+ * <code>G=Hexahedron</code>.
+ */
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_hex_iterator next_free_hex (const dealii::Triangulation<dim> &tria,
+ const unsigned int level);
/**
* Clear all the data contained in this object.
/**
* The orientation of the
- * face number <tt>face</tt>
+ * face number <code>face</code>
* of the cell with number
- * <tt>cell</tt>. The return
- * value is <tt>true</tt>, if
+ * <code>cell</code>. The return
+ * value is <code>true</code>, if
* the normal vector points
* the usual way
* (GeometryInfo::unit_normal_orientation)
- * and <tt>false</tt> else.
+ * and <code>false</code> else.
*
* The result is always
- * <tt>true</tt> in this
+ * <code>true</code> in this
* class, but derived classes
* will reimplement this.
*
*/
void clear_user_data();
+ /**
+ * Clear all user flags.
+ */
+ void clear_user_flags();
+
/**
* Check the memory consistency of the
* different containers. Should only be
<< "The containers have sizes " << arg1 << " and "
<< arg2 << ", which is not as expected.");
+ /**
+ * Exception
+ */
+ DeclException2 (ExcWrongIterator,
+ char*, char*,
+ << "You asked for the next free " << arg1 << "_iterator, "
+ "but you can only ask for " << arg2 <<"_iterators.");
+
/**
* Triangulation objacts can
* either access a user
DeclException0 (ExcPointerIndexClash);
protected:
+ /**
+ * Counter for next_free_single_* functions
+ */
+ unsigned int next_free_single;
+
+ /**
+ * Counter for next_free_pair_* functions
+ */
+ unsigned int next_free_pair;
+
+ /**
+ * Bool flag for next_free_single_* functions
+ */
+ bool reverse_order_next_free_single;
+
/**
* The data type storing user
* pointers or user indices.
public:
/**
* The orientation of the
- * face number <tt>face</tt>
+ * face number <code>face</code>
* of the cell with number
- * <tt>cell</tt>. The return
- * value is <tt>true</tt>, if
+ * <code>cell</code>. The return
+ * value is <code>true</code>, if
* the normal vector points
* the usual way
* (GeometryInfo::unit_normal_orientation)
- * and <tt>false</tt> if they
+ * and <code>false</code> if they
* point in opposite
* direction.
*/
* a @p false value.
*
* In effect, this field has
- * <tt>6*n_cells</tt> elements,
+ * <code>6*n_cells</code> elements,
* being the number of cells
* times the six faces each
* has.
/**
* Assert that enough space is
* allocated to accomodate
- * <tt>new_objs</tt> new objects.
+ * <code>new_objs</code> new objects.
* This function does not only call
- * <tt>vector::reserve()</tt>, but
+ * <code>vector::reserve()</code>, but
* does really append the needed
* elements.
*/
public:
/**
* The orientation of the
- * face number <tt>face</tt>
+ * face number <code>face</code>
* of the cell with number
- * <tt>cell</tt>. The return
- * value is <tt>true</tt>, if
+ * <code>cell</code>. The return
+ * value is <code>true</code>, if
* the normal vector points
* the usual way
* (GeometryInfo::unit_normal_orientation)
- * and <tt>false</tt> if they
+ * and <code>false</code> if they
* point in opposite
* direction.
*/
/**
* In effect, this field has
- * <tt>4*n_quads</tt> elements,
+ * <code>4*n_quads</code> elements,
* being the number of quads
* times the four lines each
* has.
std::vector<bool> line_orientations;
/**
- * Assert that enough space is
- * allocated to accomodate
- * <tt>new_objs</tt> new objects.
- * This function does not only call
- * <tt>vector::reserve()</tt>, but
- * does really append the needed
- * elements.
+ * Assert that enough space
+ * is allocated to
+ * accomodate
+ * <code>new_quads_in_pairs</code>
+ * new quads, stored in
+ * pairs, plus
+ * <code>new_quads_single</code>
+ * stored individually.
+ * This function does not
+ * only call
+ * <code>vector::reserve()</code>,
+ * but does really append
+ * the needed elements.
*/
- void reserve_space (const unsigned int new_objs);
+ void reserve_space (const unsigned int new_quads_in_pairs,
+ const unsigned int new_quads_single = 0);
/**
* Clear all the data contained in this object.
user_data[i].p = 0;
}
+
+ template<typename G>
+ inline
+ void TriaObjects<G>::clear_user_flags ()
+ {
+ user_flags.assign(user_flags.size(),false);
+ }
+
//----------------------------------------------------------------------//
inline
template<>
void
- TriaObjects<TriaObject<1> >::reserve_space (const unsigned int new_lines);
+ TriaObjects<TriaObject<1> >::reserve_space (const unsigned int new_lines_in_pairs,
+ const unsigned int new_lines_single);
template<>
void
- TriaObjects<TriaObject<2> >::reserve_space (const unsigned int new_quads);
+ TriaObjects<TriaObject<2> >::reserve_space (const unsigned int new_quads_in_pairs,
+ const unsigned int new_quads_single);
template<>
void
//---------------------------------------------------------------------------
-// mg_transfer.templates.h,v 1.22 2006/01/29 15:03:55 guido Exp
-// Version:
+// $Id$
+// Version: $Name$
//
// Copyright (C) 2003, 2004, 2005, 2006, 2007 by the deal.II authors
//
// $Id$
// Version: $Name$
//
-// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 by the deal.II authors
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
for (unsigned int i=0; i<dofs_per_cell; ++i)
restriction_is_additive[i] = fe.restriction_is_additive(i);
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell;
- ++child)
+ for (unsigned int child=0; child<this->n_children(); ++child)
{
// get the values from the present
// child, if necessary by
tmp1);
// interpolate these to the mother
// cell
- fe.get_restriction_matrix(child).vmult (tmp2, tmp1);
+ fe.get_restriction_matrix(child, this->refinement_case()).vmult (tmp2, tmp1);
// and add up or set them
// in the output vector
{
Vector<number> tmp(dofs_per_cell);
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell;
- ++child)
+ for (unsigned int child=0; child<this->n_children(); ++child)
{
// prolong the given data
// to the present cell
- this->get_fe().get_prolongation_matrix(child)
+ this->get_fe().get_prolongation_matrix(child, this->refinement_case())
.vmult (tmp, local_values);
+
this->child(child)->set_dof_values_by_interpolation (tmp, values);
}
}
if (! cell_face->at_boundary() )
{
typename DH::cell_iterator neighbor = cell->neighbor(face);
- // Refinement edges are
- // taken care of by
- // coarser cells
- if (neighbor->level() < cell->level())
- continue;
const unsigned int neighbor_face
- = cell->neighbor_of_neighbor(face);
+ = cell->neighbor_face_no(face);
if (cell_face->has_children())
{
for (unsigned int sub_nr = 0;
- sub_nr != cell_face->n_children();
+ sub_nr != cell_face->number_of_children();
++sub_nr)
{
const typename DH::cell_iterator
}
else
{
- const unsigned int n_dofs_on_neighbor
+ // Refinement edges are
+ // taken care of by
+ // coarser cells
+ 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 = cell->neighbor(face);
// Refinement edges are taken care of
// by coarser cells
- if (neighbor->level() < cell->level())
+ if (cell->neighbor_is_coarser(face))
continue;
typename DH::face_iterator cell_face = cell->face(face);
get_most_dominating_subface_fe_index (const face_iterator &face)
{
unsigned int dominating_subface_no = 0;
- for (; dominating_subface_no<GeometryInfo<dim>::subfaces_per_face;
+ for (; dominating_subface_no<face->n_children();
++dominating_subface_no)
{
// each of the subfaces
FiniteElementDomination::Domination
domination = FiniteElementDomination::either_element_can_dominate;
- for (unsigned int sf=0; sf<GeometryInfo<dim>::subfaces_per_face; ++sf)
+ for (unsigned int sf=0; sf<face->n_children(); ++sf)
if (sf != dominating_subface_no)
{
const FiniteElement<dim> &
// check that we have
// found one such subface
- Assert (dominating_subface_no != GeometryInfo<dim>::subfaces_per_face,
+ Assert (dominating_subface_no < face->n_children(),
ExcNotImplemented());
// return the finite element
Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index())
== true,
ExcInternalError());
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->n_children(); ++c)
Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1,
ExcInternalError());
// the case that both
// sides use the same
// fe
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->n_children(); ++c)
Assert (cell->face(face)->child(c)
->fe_index_is_active(cell->active_fe_index()) == true,
ExcNotImplemented());
for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
if (cell->face(face)->has_children())
{
+ // first of all, make sure that
+ // we treat a case which is
+ // possible, i.e. either no dofs
+ // on the face at all or no
+ // anisotropic refinement
+ if (cell->get_fe().dofs_per_face == 0)
+ continue;
+
+ Assert(cell->face(face)->refinement_case()==RefinementCase<dim-1>::isotropic_refinement,
+ ExcNotImplemented());
+
// so now we've found a
// face of an active
// cell that has
Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index())
== true,
ExcInternalError());
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->n_children(); ++c)
Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1,
ExcInternalError());
// this face and the
// children have the
// same fe
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->n_children(); ++c)
{
Assert (cell->face(face)->child(c)
->fe_index_is_active(cell->active_fe_index()) == true,
fe.dofs_per_quad),
n_dofs_on_children = (5*fe.dofs_per_vertex+
12*fe.dofs_per_line+
- 4*fe.dofs_per_quad);
+ 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);
dofs_on_children.resize (n_dofs_on_children);
// assert some consistency
// assumptions
- Assert ((this_face->child(0)->vertex_index(3) ==
+ //TODO[TL]: think about this in case of anisotropic refinement
+ Assert (dof_handler.get_tria().get_anisotropic_refinement_flag() ||
+ (this_face->child(0)->vertex_index(3) ==
this_face->child(1)->vertex_index(2)) &&
(this_face->child(0)->vertex_index(3) ==
this_face->child(2)->vertex_index(1)) &&
Table<3,boost::shared_ptr<FullMatrix<double> > >
subface_interpolation_matrices (n_finite_elements (dof_handler),
n_finite_elements (dof_handler),
- GeometryInfo<dim>::subfaces_per_face);
+ GeometryInfo<dim>::max_children_per_face);
// similarly have a cache for
// the matrices that are split
for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
if (cell->face(face)->has_children())
{
+ // first of all, make sure that
+ // we treat a case which is
+ // possible, i.e. either no dofs
+ // on the face at all or no
+ // anisotropic refinement
+ if (cell->get_fe().dofs_per_face == 0)
+ continue;
+
+ Assert(cell->face(face)->refinement_case()==RefinementCase<dim-1>::isotropic_refinement,
+ ExcNotImplemented());
+
// so now we've found a
// face of an active
// cell that has
Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index())
== true,
ExcInternalError());
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->n_children(); ++c)
Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1,
ExcInternalError());
mother_face_dominates = FiniteElementDomination::either_element_can_dominate;
if (DoFHandlerSupportsDifferentP<DH>::value == true)
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->number_of_children(); ++c)
mother_face_dominates = mother_face_dominates &
(cell->get_fe().compare_for_face_domination
(cell->neighbor_child_on_subface (face, c)->get_fe()));
// Now create constraint matrix for
// the subfaces and assemble it.
- for (unsigned int c=0; c<GeometryInfo<dim>::subfaces_per_face; ++c)
+ for (unsigned int c=0; c<cell->face(face)->n_children(); ++c)
{
const typename DH::active_face_iterator
subface = cell->face(face)->child(c);
// discussed in the
// paper
for (unsigned int sf=0;
- sf<GeometryInfo<dim>::subfaces_per_face; ++sf)
+ sf<cell->face(face)->n_children(); ++sf)
{
Assert (cell->face(face)->child(sf)
->n_active_fe_indices() == 1,
(cell->neighbor(face)->active_fe_index () !=
cell->active_fe_index ())
&&
- (cell->neighbor(face)->level () ==
- cell->level ()))
+ (!cell->face(face)->has_children() &&
+ !cell->neighbor_is_coarser(face) ))
{
const typename DH::cell_iterator neighbor = cell->neighbor (face);
// changed by constructor of
// derived class.
first_block_of_base_table.resize(1,0);
+
+ // initialize the restriction and
+ // prolongation matrices. the default
+ // contructur of FullMatrix<dim> initializes
+ // them with size zero
+ prolongation.resize(RefinementCase<dim>::isotropic_refinement);
+ restriction.resize(RefinementCase<dim>::isotropic_refinement);
+ for (unsigned int ref=RefinementCase<dim>::cut_x;
+ ref<RefinementCase<dim>::isotropic_refinement+1; ++ref)
+ {
+ prolongation[ref-1].resize (GeometryInfo<dim>::
+ n_children(RefinementCase<dim>(ref)),
+ FullMatrix<double>());
+ restriction[ref-1].resize (GeometryInfo<dim>::
+ n_children(RefinementCase<dim>(ref)),
+ FullMatrix<double>());
+ }
+
adjust_quad_dof_index_for_face_orientation_table.fill(0);
}
}
+
+template <int dim>
+void
+FiniteElement<dim>::reinit_restriction_and_prolongation_matrices (
+ const bool isotropic_restriction_only,
+ const bool isotropic_prolongation_only)
+{
+ for (unsigned int ref_case=RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
+ {
+ const unsigned int nc = GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));
+
+ for (unsigned int i=0; i<nc; ++i)
+ {
+ if (!isotropic_restriction_only || ref_case==RefinementCase<dim>::isotropic_refinement)
+ this->restriction[ref_case-1][i].reinit (this->dofs_per_cell,
+ this->dofs_per_cell);
+ if (!isotropic_prolongation_only || ref_case==RefinementCase<dim>::isotropic_refinement)
+ this->prolongation[ref_case-1][i].reinit (this->dofs_per_cell,
+ this->dofs_per_cell);
+ }
+ }
+}
+
+
template <int dim>
const FullMatrix<double> &
-FiniteElement<dim>::get_restriction_matrix (const unsigned int child) const
+FiniteElement<dim>::get_restriction_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case) const
{
- Assert (child<GeometryInfo<dim>::children_per_cell,
- ExcIndexRange(child, 0, GeometryInfo<dim>::children_per_cell));
- Assert (restriction[child].n() != 0, ExcProjectionVoid());
- return restriction[child];
+ Assert (refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+ Assert (refinement_case!=RefinementCase<dim>::no_refinement,
+ ExcMessage("Restriction matrices are only available for refined cells!"));
+ Assert (child<GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case)),
+ ExcIndexRange(child,0,GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case))));
+ // we use refinement_case-1 here. the -1 takes care
+ // of the origin of the vector, as for
+ // RefinementCase<dim>::no_refinement (=0) there is no
+ // data available and so the vector indices
+ // are shifted
+ Assert (restriction[refinement_case-1][child].n() != 0, ExcProjectionVoid());
+ return restriction[refinement_case-1][child];
}
template <int dim>
const FullMatrix<double> &
-FiniteElement<dim>::get_prolongation_matrix (const unsigned int child) const
+FiniteElement<dim>::get_prolongation_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case) const
{
- Assert (child<GeometryInfo<dim>::children_per_cell,
- ExcIndexRange(child, 0, GeometryInfo<dim>::children_per_cell));
- Assert (prolongation[child].n() != 0, ExcEmbeddingVoid());
- return prolongation[child];
+ Assert (refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+ Assert (refinement_case!=RefinementCase<dim>::no_refinement,
+ ExcMessage("Prolongation matrices are only available for refined cells!"));
+ Assert (child<GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case)),
+ ExcIndexRange(child,0,GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case))));
+ // we use refinement_case-1 here. the -1 takes care
+ // of the origin of the vector, as for
+ // RefinementCase::no_refinement (=0) there is no
+ // data available and so the vector indices
+ // are shifted
+ Assert (prolongation[refinement_case-1][child].n() != 0, ExcEmbeddingVoid());
+ return prolongation[refinement_case-1][child];
}
bool
FiniteElement<dim>::prolongation_is_implemented () const
{
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ for (unsigned int ref_case=RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
+ for (unsigned int c=0;
+ c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
+ {
+ Assert ((prolongation[ref_case-1][c].m() == this->dofs_per_cell) ||
+ (prolongation[ref_case-1][c].m() == 0),
+ ExcInternalError());
+ Assert ((prolongation[ref_case-1][c].n() == this->dofs_per_cell) ||
+ (prolongation[ref_case-1][c].n() == 0),
+ ExcInternalError());
+ if ((prolongation[ref_case-1][c].m() == 0) ||
+ (prolongation[ref_case-1][c].n() == 0))
+ return false;
+ }
+ return true;
+}
+
+
+
+template <int dim>
+bool
+FiniteElement<dim>::restriction_is_implemented () const
+{
+ for (unsigned int ref_case=RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
+ for (unsigned int c=0;
+ c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
+ {
+ Assert ((restriction[ref_case-1][c].m() == this->dofs_per_cell) ||
+ (restriction[ref_case-1][c].m() == 0),
+ ExcInternalError());
+ Assert ((restriction[ref_case-1][c].n() == this->dofs_per_cell) ||
+ (restriction[ref_case-1][c].n() == 0),
+ ExcInternalError());
+ if ((restriction[ref_case-1][c].m() == 0) ||
+ (restriction[ref_case-1][c].n() == 0))
+ return false;
+ }
+ return true;
+}
+
+
+
+template <int dim>
+bool
+FiniteElement<dim>::isotropic_prolongation_is_implemented () const
+{
+ const RefinementCase<dim> ref_case=RefinementCase<dim>::isotropic_refinement;
+
+ for (unsigned int c=0;
+ c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
{
- Assert ((prolongation[c].m() == this->dofs_per_cell) ||
- (prolongation[c].m() == 0),
- ExcInternalError());
- Assert ((prolongation[c].n() == this->dofs_per_cell) ||
- (prolongation[c].n() == 0),
- ExcInternalError());
- if ((prolongation[c].m() == 0) ||
- (prolongation[c].n() == 0))
- return false;
+ Assert ((prolongation[ref_case-1][c].m() == this->dofs_per_cell) ||
+ (prolongation[ref_case-1][c].m() == 0),
+ ExcInternalError());
+ Assert ((prolongation[ref_case-1][c].n() == this->dofs_per_cell) ||
+ (prolongation[ref_case-1][c].n() == 0),
+ ExcInternalError());
+ if ((prolongation[ref_case-1][c].m() == 0) ||
+ (prolongation[ref_case-1][c].n() == 0))
+ return false;
}
return true;
}
template <int dim>
bool
-FiniteElement<dim>::restriction_is_implemented () const
+FiniteElement<dim>::isotropic_restriction_is_implemented () const
{
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ const RefinementCase<dim> ref_case = RefinementCase<dim>::isotropic_refinement;
+
+ for (unsigned int c=0;
+ c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
{
- Assert ((restriction[c].m() == this->dofs_per_cell) ||
- (restriction[c].m() == 0),
- ExcInternalError());
- Assert ((restriction[c].n() == this->dofs_per_cell) ||
- (restriction[c].n() == 0),
- ExcInternalError());
- if ((restriction[c].m() == 0) ||
- (restriction[c].n() == 0))
- return false;
+ Assert ((restriction[ref_case-1][c].m() == this->dofs_per_cell) ||
+ (restriction[ref_case-1][c].m() == 0),
+ ExcInternalError());
+ Assert ((restriction[ref_case-1][c].n() == this->dofs_per_cell) ||
+ (restriction[ref_case-1][c].n() == 0),
+ ExcInternalError());
+ if ((restriction[ref_case-1][c].m() == 0) ||
+ (restriction[ref_case-1][c].n() == 0))
+ return false;
}
return true;
}
template <int dim>
bool
-FiniteElement<dim>::constraints_are_implemented () const
+FiniteElement<dim>::constraints_are_implemented (const internal::SubfaceCase<dim> &subface_case) const
{
- return (this->dofs_per_face == 0) || (interface_constraints.m() != 0);
+ if (subface_case==internal::SubfaceCase<dim>::case_isotropic)
+ return (this->dofs_per_face == 0) || (interface_constraints.m() != 0);
+ else
+ return false;
}
template <int dim>
const FullMatrix<double> &
-FiniteElement<dim>::constraints () const
+FiniteElement<dim>::constraints (const internal::SubfaceCase<dim> &subface_case) const
{
+ Assert (subface_case==internal::SubfaceCase<dim>::case_isotropic, ExcConstraintsVoid());
Assert ((this->dofs_per_face == 0) || (interface_constraints.m() != 0),
ExcConstraintsVoid());
FiniteElement<dim>::memory_consumption () const
{
return (sizeof(FiniteElementData<dim>) +
- MemoryConsumption::
- memory_consumption<FullMatrix<double>, sizeof(restriction)/sizeof(restriction[0])>
- (restriction)+
- MemoryConsumption::memory_consumption
- <FullMatrix<double>, sizeof(prolongation)/sizeof(prolongation[0])>
- (prolongation) +
+ MemoryConsumption::memory_consumption (restriction)+
+ MemoryConsumption::memory_consumption (prolongation) +
MemoryConsumption::memory_consumption (interface_constraints) +
MemoryConsumption::memory_consumption (system_to_component_table) +
MemoryConsumption::memory_consumption (face_system_to_component_table) +
// will be the correct ones, not
// the raw shape functions anymore.
-
- // initialize the various matrices
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- {
- this->prolongation[i].reinit (n_dofs, n_dofs);
- this->restriction[i].reinit (n_dofs, n_dofs);
- }
-
+ // Reinit the vectors of
+ // restriction and prolongation
+ // matrices to the right sizes.
+ // Restriction only for isotropic
+ // refinement
+ this->reinit_restriction_and_prolongation_matrices(true);
+ // Fill prolongation matrices with embedding operators
FETools::compute_embedding_matrices (*this, this->prolongation);
+
initialize_restriction ();
+ // TODO[TL]: for anisotropic refinement we will probably need a table of submatrices with an array for each refine case
std::vector<FullMatrix<double> >
face_embeddings(1<<(dim-1), FullMatrix<double>(this->dofs_per_face,
this->dofs_per_face));
void
FE_ABF<dim>::initialize_restriction()
{
- for (unsigned int i=0;i<GeometryInfo<dim>::children_per_cell;++i)
- this->restriction[i].reinit(0,0);
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
+ for (unsigned int i=0;i<GeometryInfo<dim>::max_children_per_cell;++i)
+ this->restriction[iso][i].reinit(0,0);
}
#else
void
FE_ABF<dim>::initialize_restriction()
{
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
QGauss<dim-1> q_base (rt_order+1);
const unsigned int n_face_points = q_base.size();
// First, compute interpolation on
= this->shape_value_component(i, q_face.point(k),
GeometryInfo<dim>::unit_normal_direction[face]);
- for (unsigned int sub=0;sub<GeometryInfo<dim>::subfaces_per_face;++sub)
+ for (unsigned int sub=0;sub<GeometryInfo<dim>::max_children_per_face;++sub)
{
// The weight fuctions for
// the coarse face are
Quadrature<dim> q_sub
= QProjector<dim>::project_to_subface(q_base, face, sub);
const unsigned int child
- = GeometryInfo<dim>::child_cell_on_face(face, sub);
+ = GeometryInfo<dim>::child_cell_on_face(
+ RefinementCase<dim>::isotropic_refinement, face, sub);
// On a certain face, we must
// compute the moments of ALL
// subcell are NOT
// transformed, so we
// have to do it here.
- this->restriction[child](face*this->dofs_per_face+i_face,
+ this->restriction[iso][child](face*this->dofs_per_face+i_face,
i_child)
+= Utilities::fixed_power<dim-1>(.5) * q_sub.weight(k)
* cached_values(i_child, k)
for (unsigned int d=0;d<dim;++d)
cached_values(i,k,d) = this->shape_value_component(i, q_cell.point(k), d);
- for (unsigned int child=0;child<GeometryInfo<dim>::children_per_cell;++child)
+ for (unsigned int child=0;child<GeometryInfo<dim>::max_children_per_cell;++child)
{
Quadrature<dim> q_sub = QProjector<dim>::project_to_child(q_cell, child);
for (unsigned int d=0;d<dim;++d)
for (unsigned int i_weight=0;i_weight<polynomials[d]->n();++i_weight)
{
- this->restriction[child](start_cell_dofs+i_weight*dim+d,
+ this->restriction[iso][child](start_cell_dofs+i_weight*dim+d,
i_child)
+= q_sub.weight(k)
* cached_values(i_child, k, d)
// $Id$
// Version: $Name$
//
-// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
std::vector<std::vector<bool> >(FiniteElementData<dim>(
get_dpo_vector(degree), 1, degree).dofs_per_cell, std::vector<bool>(1,true)))
{
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->prolongation[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
+ // Reinit the vectors of
+ // restriction and prolongation
+ // matrices to the right sizes
+ this->reinit_restriction_and_prolongation_matrices();
+ // Fill prolongation matrices with embedding operators
FETools::compute_embedding_matrices (*this, this->prolongation);
// Fill restriction matrices with L2-projection
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->restriction[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
FETools::compute_projection_matrices (*this, this->restriction);
}
// $Id$
// Version: $Name$
//
-// Copyright (C) 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
// DG doesn't have constraints, so
// leave them empty
- // initialize the interpolation
- // matrices
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->prolongation[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
+ // Reinit the vectors of
+ // restriction and prolongation
+ // matrices to the right sizes
+ this->reinit_restriction_and_prolongation_matrices();
+ // Fill prolongation matrices with embedding operators
FETools::compute_embedding_matrices (*this, this->prolongation);
// Fill restriction matrices with L2-projection
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->restriction[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
FETools::compute_projection_matrices (*this, this->restriction);
}
// $Id$
// Version: $Name$
//
-// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
polynomial_space (Polynomials::Legendre::generate_complete_basis(degree))
{
const unsigned int n_dofs = this->dofs_per_cell;
- for (unsigned int i=0;i<GeometryInfo<dim>::children_per_cell;++i)
+ for (unsigned int ref_case = RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
{
- this->prolongation[i].reinit(n_dofs, n_dofs);
- for (unsigned int j=0;j<n_dofs;++j)
- this->prolongation[i](j,j) = 1.;
+ if (dim!=2 && ref_case!=RefinementCase<dim>::isotropic_refinement)
+ // do nothing, as anisotropic
+ // refinement is not
+ // implemented so far
+ continue;
+
+ const unsigned int nc = GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));
+ for (unsigned int i=0;i<nc;++i)
+ {
+ this->prolongation[ref_case-1][i].reinit (n_dofs, n_dofs);
+ // Fill prolongation matrices with
+ // embedding operators
+ for (unsigned int j=0;j<n_dofs;++j)
+ this->prolongation[ref_case-1][i](j,j) = 1.;
+ }
}
+
// restriction can be defined
// through projection for
// discontinuous elements, but is
// }
// else
// // matrix undefined, set size to zero
-// for (unsigned int i=0;i<GeometryInfo<dim>::children_per_cell;++i)
+// for (unsigned int i=0;i<GeometryInfo<dim>::max_children_per_cell;++i)
// restriction[i].reinit(0, 0);
// since not implemented, set to
- // "empty"
- for (unsigned int i=0;i<GeometryInfo<dim>::children_per_cell;++i)
- this->restriction[i].reinit(0, 0);
+ // "empty". however, that is done in the
+ // default constructor already, so do nothing
+// for (unsigned int i=0;i<GeometryInfo<dim>::max_children_per_cell;++i)
+// this->restriction[i].reinit(0, 0);
// note further, that these
// elements have neither support
std::vector<std::vector<bool> >(FiniteElementData<dim>(
get_dpo_vector(degree),1, degree).dofs_per_cell, std::vector<bool>(1,true)))
{
+ // Reinit the vectors of
+ // restriction and prolongation
+ // matrices to the right sizes
+ this->reinit_restriction_and_prolongation_matrices();
// Fill prolongation matrices with embedding operators
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->prolongation[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
FETools::compute_embedding_matrices (*this, this->prolongation);
// Fill restriction matrices with L2-projection
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->restriction[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
FETools::compute_projection_matrices (*this, this->restriction);
-
+
// finally fill in support points
if (degree == 0)
std::vector<std::vector<bool> >(FiniteElementData<dim>(
get_dpo_vector(points.size()-1),1, points.size()-1).dofs_per_cell, std::vector<bool>(1,true)))
{
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->prolongation[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
+ // Reinit the vectors of
+ // restriction and prolongation
+ // matrices to the right sizes
+ this->reinit_restriction_and_prolongation_matrices();
+ // Fill prolongation matrices with embedding operators
FETools::compute_embedding_matrices (*this, this->prolongation);
// Fill restriction matrices with L2-projection
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->restriction[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
FETools::compute_projection_matrices (*this, this->restriction);
- // Compute support points, whivh
+ // Compute support points, which
// are the tensor product of the
// Lagrange interpolation points in
// the constructor.
void
FE_Nedelec<dim>::initialize_embedding ()
{
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
if ((degree < Matrices::n_embedding_matrices+1) &&
(Matrices::embedding[degree-1][0] != 0))
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
{
// copy
- this->prolongation[c].reinit (this->dofs_per_cell,
+ this->prolongation[iso][c].reinit (this->dofs_per_cell,
this->dofs_per_cell);
- this->prolongation[c].fill (Matrices::embedding[degree-1][c]);
+ this->prolongation[iso][c].fill (Matrices::embedding[degree-1][c]);
// and make sure that the row
// sum is 0.5 (for usual
// elements, the row sum must
{
double sum = 0;
for (unsigned int col=0; col<this->dofs_per_cell; ++col)
- sum += this->prolongation[c](row,col);
+ sum += this->prolongation[iso][c](row,col);
Assert (std::fabs(sum-.5) < 1e-14,
ExcInternalError());
};
void
FE_Nedelec<dim>::initialize_restriction ()
{
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
switch (dim)
{
case 2: // 2d
// always, in the
// canonical direction
// of lines
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
- this->restriction[c].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
+ this->restriction[iso][c].reinit (this->dofs_per_cell,
+ this->dofs_per_cell);
- this->restriction[0](0,0) = 2.;
- this->restriction[1](1,1) = 2.;
- this->restriction[0](2,2) = 2.;
- this->restriction[2](3,3) = 2.;
+ this->restriction[iso][0](0,0) = 2.;
+ this->restriction[iso][1](1,1) = 2.;
+ this->restriction[iso][0](2,2) = 2.;
+ this->restriction[iso][2](3,3) = 2.;
break;
};
// cell to get at the
// values of each of
// the 12 lines
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
- this->restriction[c].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
- this->restriction[0](0,0) = 2.;
- this->restriction[1](1,1) = 2.;
- this->restriction[0](2,2) = 2.;
- this->restriction[2](3,3) = 2.;
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
+ this->restriction[iso][c].reinit (this->dofs_per_cell,
+ this->dofs_per_cell);
+ this->restriction[iso][0](0,0) = 2.;
+ this->restriction[iso][1](1,1) = 2.;
+ this->restriction[iso][0](2,2) = 2.;
+ this->restriction[iso][2](3,3) = 2.;
- this->restriction[4](4,4) = 2.;
- this->restriction[5](5,5) = 2.;
- this->restriction[4](6,6) = 2.;
- this->restriction[6](7,7) = 2.;
+ this->restriction[iso][4](4,4) = 2.;
+ this->restriction[iso][5](5,5) = 2.;
+ this->restriction[iso][4](6,6) = 2.;
+ this->restriction[iso][6](7,7) = 2.;
- this->restriction[0](8,8) = 2.;
- this->restriction[1](9,9) = 2.;
- this->restriction[2](10,10) = 2.;
- this->restriction[3](11,11) = 2.;
+ this->restriction[iso][0](8,8) = 2.;
+ this->restriction[iso][1](9,9) = 2.;
+ this->restriction[iso][2](10,10) = 2.;
+ this->restriction[iso][3](11,11) = 2.;
break;
};
cell->face_orientation(face),
cell->face_flip(face),
cell->face_rotation(face),
- quadrature.size()));
+ quadrature.size(),
+ cell->subface_case(face)));
// get the flags indicating the
// fields that have to be filled
if (flags & update_values)
{
Assert (fe_data.shape_values[0].size() ==
- GeometryInfo<dim>::subfaces_per_face *
+ GeometryInfo<dim>::max_children_per_face *
GeometryInfo<dim>::faces_per_cell *
n_q_points,
ExcInternalError());
{
Assert (fe_data.shape_gradients.size() ==
GeometryInfo<dim>::faces_per_cell *
- GeometryInfo<dim>::subfaces_per_face *
+ GeometryInfo<dim>::max_children_per_face *
n_q_points,
ExcInternalError());
template <>
const double * const
-FE_Nedelec<1>::Matrices::embedding[][GeometryInfo<1>::children_per_cell] =
+FE_Nedelec<1>::Matrices::embedding[][GeometryInfo<1>::max_children_per_cell] =
{{0}};
template <>
const double * const
-FE_Nedelec<2>::Matrices::embedding[][GeometryInfo<2>::children_per_cell] =
+FE_Nedelec<2>::Matrices::embedding[][GeometryInfo<2>::max_children_per_cell] =
{
{ FE_Nedelec_2d::q1_into_q1_refined_0, FE_Nedelec_2d::q1_into_q1_refined_1,
FE_Nedelec_2d::q1_into_q1_refined_2, FE_Nedelec_2d::q1_into_q1_refined_3 }
template <>
const double * const
-FE_Nedelec<3>::Matrices::embedding[][GeometryInfo<3>::children_per_cell] =
+FE_Nedelec<3>::Matrices::embedding[][GeometryInfo<3>::max_children_per_cell] =
{
{ FE_Nedelec_3d::q1_into_q1_refined_0, FE_Nedelec_3d::q1_into_q1_refined_1,
FE_Nedelec_3d::q1_into_q1_refined_2, FE_Nedelec_3d::q1_into_q1_refined_3,
cell->face_orientation(face),
cell->face_flip(face),
cell->face_rotation(face),
- n_q_points);
+ n_q_points,
+ cell->subface_case(face));
const UpdateFlags flags(fe_data.update_once | fe_data.update_each);
// lines 9-16
for (unsigned int face=0; face<GeometryInfo<dim-1>::faces_per_cell; ++face)
for (unsigned int subface=0;
- subface<GeometryInfo<dim-1>::subfaces_per_face; ++subface)
+ subface<GeometryInfo<dim-1>::max_children_per_face; ++subface)
{
QProjector<dim-1>::project_to_subface(qline, face, subface, p_line);
constraint_points.insert(constraint_points.end(),
inner_points[i++] = Point<dim-1> (ix*step, iy*step);
for (unsigned int child=0;
- child<GeometryInfo<dim-1>::children_per_cell; ++child)
+ child<GeometryInfo<dim-1>::max_children_per_cell; ++child)
for (unsigned int i=0; i<inner_points.size(); ++i)
constraint_points.push_back (
GeometryInfo<dim-1>::child_to_cell_coordinates(inner_points[i], child));
void
FE_Q<dim>::initialize_embedding ()
{
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
+
// compute the interpolation
// matrices in much the same way as
// we do for the constraints. it's
const std::vector<unsigned int> &index_map=
this->poly_space.get_numbering();
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
- this->prolongation[child].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
+ for (unsigned int child=0; child<GeometryInfo<dim>::max_children_per_cell; ++child)
+ this->prolongation[iso][child].reinit (this->dofs_per_cell,
+ this->dofs_per_cell);
+ for (unsigned int child=0; child<GeometryInfo<dim>::max_children_per_cell; ++child)
{
for (unsigned int j=0; j<this->dofs_per_cell; ++j)
{
// of the identity matrix and
// its inverse is also its
// transpose
- subcell_interpolation.Tmmult (this->prolongation[child],
+ subcell_interpolation.Tmmult (this->prolongation[iso][child],
cell_interpolation);
// cut off very small values
// here
for (unsigned int i=0; i<this->dofs_per_cell; ++i)
for (unsigned int j=0; j<this->dofs_per_cell; ++j)
- if (std::fabs(this->prolongation[child](i,j)) < 2e-13*this->degree*dim)
- this->prolongation[child](i,j) = 0.;
+ if (std::fabs(this->prolongation[iso][child](i,j)) < 2e-13*this->degree*dim)
+ this->prolongation[iso][child](i,j) = 0.;
// and make sure that the row
// sum is 1. this must be so
{
double sum = 0;
for (unsigned int col=0; col<this->dofs_per_cell; ++col)
- sum += this->prolongation[child](row,col);
+ sum += this->prolongation[iso][child](row,col);
Assert (std::fabs(sum-1.) < 2e-13*this->degree*this->degree*dim,
ExcInternalError());
}
void
FE_Q<dim>::initialize_restriction ()
{
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
+
// for these Lagrange interpolation
// polynomials, construction of the
// restriction matrices is
// one child) by the same value
// (compute on a later child), so
// we don't have to care about this
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
- this->restriction[c].reinit (this->dofs_per_cell, this->dofs_per_cell);
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
+ this->restriction[iso][c].reinit (this->dofs_per_cell, this->dofs_per_cell);
for (unsigned int i=0; i<this->dofs_per_cell; ++i)
{
const Point<dim> p_cell
// then find the children on
// which the interpolation
// point is located
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell;
+ for (unsigned int child=0; child<GeometryInfo<dim>::max_children_per_cell;
++child)
{
// first initialize this
// column of the matrix
for (unsigned int j=0; j<this->dofs_per_cell; ++j)
- this->restriction[child](mother_dof, j) = 0.;
+ this->restriction[iso][child](mother_dof, j) = 0.;
// then check whether this
// interpolation point is
// it, set the
// corresponding value
// in the matrix
- this->restriction[child](mother_dof, child_dof) = 1.;
+ this->restriction[iso][child](mother_dof, child_dof) = 1.;
}
}
}
// @p{interface_constraints} matrices
// for all dimensions.
std::vector<FullMatrix<double> >
- dofs_cell (GeometryInfo<1>::children_per_cell,
+ dofs_cell (GeometryInfo<1>::max_children_per_cell,
FullMatrix<double> (2*this->dofs_per_vertex + this->dofs_per_line,
2*this->dofs_per_vertex + this->dofs_per_line));
std::vector<FullMatrix<double> >
- dofs_subcell (GeometryInfo<1>::children_per_cell,
+ dofs_subcell (GeometryInfo<1>::max_children_per_cell,
FullMatrix<double> (2*this->dofs_per_vertex + this->dofs_per_line,
2*this->dofs_per_vertex + this->dofs_per_line));
// build these fields, as they are
{
const unsigned int dofs_1d = 2*this->dofs_per_vertex + this->dofs_per_line;
- for (unsigned int c=0; c<GeometryInfo<1>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<1>::max_children_per_cell; ++c)
for (unsigned int j=0; j<dofs_1d; ++j)
for (unsigned int k=0; k<dofs_1d; ++k)
{
for (unsigned int i=0; i<dofs_1d; ++i)
this->interface_constraints(0,i) = dofs_subcell[0](1,i);
// edge nodes
- for (unsigned int c=0; c<GeometryInfo<1>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<1>::max_children_per_cell; ++c)
for (unsigned int i=0; i<dofs_1d; ++i)
for (unsigned int j=2; j<dofs_1d; ++j)
this->interface_constraints(1 + c*(degree-1) + j - 2,i) =
initialize_embedding_and_restriction (const std::vector<FullMatrix<double> > &dofs_cell,
const std::vector<FullMatrix<double> > &dofs_subcell)
{
+ unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
+
const unsigned int dofs_1d = 2*this->dofs_per_vertex + this->dofs_per_line;
const std::vector<unsigned int> &renumber=
this->poly_space.get_numbering();
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
{
- this->prolongation[c].reinit (this->dofs_per_cell, this->dofs_per_cell);
- this->restriction[c].reinit (this->dofs_per_cell, this->dofs_per_cell);
+ this->prolongation[iso][c].reinit (this->dofs_per_cell, this->dofs_per_cell);
+ this->restriction[iso][c].reinit (this->dofs_per_cell, this->dofs_per_cell);
}
// the 1d case is particularly
// simple, so special case it:
if (dim==1)
{
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_cell; ++c)
{
- this->prolongation[c].fill (dofs_subcell[c]);
- this->restriction[c].fill (dofs_cell[c]);
+ this->prolongation[iso][c].fill (dofs_subcell[c]);
+ this->restriction[iso][c].fill (dofs_cell[c]);
}
return;
}
{
case 2:
{
- for (unsigned int c=0; c<GeometryInfo<2>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<2>::max_children_per_cell; ++c)
{
// left/right line: 0/1
const unsigned int c0 = c%2;
// bottom/top line: 0/1
const unsigned int c1 = c/2;
- this->prolongation[c](j,i) =
+ this->prolongation[iso][c](j,i) =
dofs_subcell[c0](renumber[j] % dofs_1d,
renumber[i] % dofs_1d) *
dofs_subcell[c1]((renumber[j] - (renumber[j] % dofs_1d)) / dofs_1d,
(renumber[i] - (renumber[i] % dofs_1d)) / dofs_1d);
- this->restriction[c](j,i) =
+ this->restriction[iso][c](j,i) =
dofs_cell[c0](renumber[j] % dofs_1d,
renumber[i] % dofs_1d) *
dofs_cell[c1]((renumber[j] - (renumber[j] % dofs_1d)) / dofs_1d,
case 3:
{
- for (unsigned int c=0; c<GeometryInfo<3>::children_per_cell; ++c)
+ for (unsigned int c=0; c<GeometryInfo<3>::max_children_per_cell; ++c)
{
// left/right face: 0/1
const unsigned int c0 = c%2;
// bottom/top face: 0/1
const unsigned int c2 = c/4;
- this->prolongation[c](j,i) =
+ this->prolongation[iso][c](j,i) =
dofs_subcell[c0](renumber[j] % dofs_1d,
renumber[i] % dofs_1d) *
dofs_subcell[c1](((renumber[j] - (renumber[j] % dofs_1d)) / dofs_1d) % dofs_1d,
dofs_subcell[c2](((renumber[j] - (renumber[j] % dofs_1d)) / dofs_1d - (((renumber[j] - (renumber[j] % dofs_1d)) / dofs_1d ) % dofs_1d)) / dofs_1d,
((renumber[i] - (renumber[i] % dofs_1d)) / dofs_1d - (((renumber[i] - (renumber[i] % dofs_1d)) / dofs_1d ) % dofs_1d)) / dofs_1d);
- this->restriction[c](j,i) =
+ this->restriction[iso][c](j,i) =
dofs_cell[c0](renumber[j] % dofs_1d,
renumber[i] % dofs_1d) *
dofs_cell[c1](((renumber[j] - (renumber[j] % dofs_1d)) / dofs_1d) % dofs_1d,
// will be the correct ones, not
// the raw shape functions anymore.
-
- // initialize the various matrices
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- {
- this->prolongation[i].reinit (n_dofs, n_dofs);
- this->restriction[i].reinit (n_dofs, n_dofs);
- }
-
+ // Reinit the vectors of
+ // restriction and prolongation
+ // matrices to the right sizes.
+ // Restriction only for isotropic
+ // refinement
+ this->reinit_restriction_and_prolongation_matrices(true);
+ // Fill prolongation matrices with embedding operators
FETools::compute_embedding_matrices (*this, this->prolongation);
initialize_restriction();
-
- FullMatrix<double> face_embeddings[GeometryInfo<dim>::subfaces_per_face];
- for (unsigned int i=0; i<GeometryInfo<dim>::subfaces_per_face; ++i)
+
+ // TODO[TL]: for anisotropic refinement we will probably need a table of submatrices with an array for each refine case
+ FullMatrix<double> face_embeddings[GeometryInfo<dim>::max_children_per_face];
+ for (unsigned int i=0; i<GeometryInfo<dim>::max_children_per_face; ++i)
face_embeddings[i].reinit (this->dofs_per_face, this->dofs_per_face);
FETools::compute_face_embedding_matrices(*this, face_embeddings, 0, 0);
this->interface_constraints.reinit((1<<(dim-1)) * this->dofs_per_face,
this->dofs_per_face);
unsigned int target_row=0;
- for (unsigned int d=0;d<GeometryInfo<dim>::subfaces_per_face;++d)
+ for (unsigned int d=0;d<GeometryInfo<dim>::max_children_per_face;++d)
for (unsigned int i=0;i<face_embeddings[d].m();++i)
{
for (unsigned int j=0;j<face_embeddings[d].n();++j)
void
FE_RaviartThomas<1>::initialize_restriction()
{
- for (unsigned int i=0;i<GeometryInfo<1>::children_per_cell;++i)
- this->restriction[i].reinit(0,0);
+ // there is only one refinement case in 1d,
+ // which is the isotropic one (first index of
+ // the matrix array has to be 0)
+ for (unsigned int i=0;i<GeometryInfo<1>::max_children_per_cell;++i)
+ this->restriction[0][i].reinit(0,0);
}
#endif
void
FE_RaviartThomas<dim>::initialize_restriction()
{
+ const unsigned int iso=RefinementCase<dim>::isotropic_refinement-1;
+
QGauss<dim-1> q_base (rt_order+1);
const unsigned int n_face_points = q_base.size();
// First, compute interpolation on
= this->shape_value_component(i, q_face.point(k),
GeometryInfo<dim>::unit_normal_direction[face]);
- for (unsigned int sub=0;sub<GeometryInfo<dim>::subfaces_per_face;++sub)
+ for (unsigned int sub=0;sub<GeometryInfo<dim>::max_children_per_face;++sub)
{
// The weight fuctions for
// the coarse face are
Quadrature<dim> q_sub
= QProjector<dim>::project_to_subface(q_base, face, sub);
const unsigned int child
- = GeometryInfo<dim>::child_cell_on_face(face, sub);
+ = GeometryInfo<dim>::child_cell_on_face(
+ RefinementCase<dim>::isotropic_refinement, face, sub);
// On a certain face, we must
// compute the moments of ALL
// subcell are NOT
// transformed, so we
// have to do it here.
- this->restriction[child](face*this->dofs_per_face+i_face,
- i_child)
+ this->restriction[iso][child](face*this->dofs_per_face+i_face,
+ i_child)
+= Utilities::fixed_power<dim-1>(.5) * q_sub.weight(k)
* cached_values(i_child, k)
* this->shape_value_component(face*this->dofs_per_face+i_face,
for (unsigned int d=0;d<dim;++d)
cached_values(i,k,d) = this->shape_value_component(i, q_cell.point(k), d);
- for (unsigned int child=0;child<GeometryInfo<dim>::children_per_cell;++child)
+ for (unsigned int child=0;child<GeometryInfo<dim>::max_children_per_cell;++child)
{
Quadrature<dim> q_sub = QProjector<dim>::project_to_child(q_cell, child);
for (unsigned int d=0;d<dim;++d)
for (unsigned int i_weight=0;i_weight<polynomials[d]->n();++i_weight)
{
- this->restriction[child](start_cell_dofs+i_weight*dim+d,
- i_child)
+ this->restriction[iso][child](start_cell_dofs+i_weight*dim+d,
+ i_child)
+= q_sub.weight(k)
* cached_values(i_child, k, d)
* polynomials[d]->compute_value(i_weight, q_sub.point(k));
// will be the correct ones, not
// the raw shape functions anymore.
- for (unsigned int i=0; i<GeometryInfo<dim>::children_per_cell; ++i)
- this->prolongation[i].reinit (this->dofs_per_cell,
- this->dofs_per_cell);
+ // Reinit the vectors of
+ // prolongation matrices to the
+ // right sizes. There are no
+ // restriction matrices implemented
+ for (unsigned int ref_case=RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
+ {
+ const unsigned int nc = GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));
+
+ for (unsigned int i=0;i<nc;++i)
+ this->prolongation[ref_case-1][i].reinit (n_dofs, n_dofs);
+ }
+ // Fill prolongation matrices with embedding operators
FETools::compute_embedding_matrices (*this, this->prolongation);
-
- FullMatrix<double> face_embeddings[GeometryInfo<dim>::subfaces_per_face];
- for (unsigned int i=0; i<GeometryInfo<dim>::subfaces_per_face; ++i)
+ // TODO[TL]: for anisotropic refinement we will probably need a table of submatrices with an array for each refine case
+ FullMatrix<double> face_embeddings[GeometryInfo<dim>::max_children_per_face];
+ for (unsigned int i=0; i<GeometryInfo<dim>::max_children_per_face; ++i)
face_embeddings[i].reinit (this->dofs_per_face, this->dofs_per_face);
FETools::compute_face_embedding_matrices(*this, face_embeddings, 0, 0);
this->interface_constraints.reinit((1<<(dim-1)) * this->dofs_per_face,
this->dofs_per_face);
unsigned int target_row=0;
- for (unsigned int d=0;d<GeometryInfo<dim>::subfaces_per_face;++d)
+ for (unsigned int d=0;d<GeometryInfo<dim>::max_children_per_face;++d)
for (unsigned int i=0;i<face_embeddings[d].m();++i)
{
for (unsigned int j=0;j<face_embeddings[d].n();++j)
{
unsigned int offset = 0;
if (face_no != invalid_face_number)
- offset = (sub_no == invalid_face_number)
- ? face_no * n_q_points
- :(face_no * GeometryInfo<dim>::subfaces_per_face
- + sub_no) * n_q_points;
+ if (sub_no == invalid_face_number)
+ offset=QProjector<dim>::DataSetDescriptor
+ ::face(face_no,
+ cell->face_orientation(face_no),
+ cell->face_flip(face_no),
+ cell->face_rotation(face_no),
+ n_q_points);
+ else
+ offset=QProjector<dim>::DataSetDescriptor
+ ::subface(face_no, sub_no,
+ cell->face_orientation(face_no),
+ cell->face_flip(face_no),
+ cell->face_rotation(face_no),
+ n_q_points,
+ cell->subface_case(face_no));
this->compute_2nd (mapping, cell, offset, mapping_data, fe_data, data);
}
}
{
build_cell_tables();
build_face_tables();
-
- // Check if some of the matrices of
- // the base elements are void.
- bool do_restriction = true;
- bool do_prolongation = true;
- for (unsigned int i=0; i<n_base_elements(); ++i)
+ for (unsigned int ref_case=RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1;
+ ++ref_case)
{
- if (base_element(i).restriction[0].n() == 0)
- do_restriction = false;
- if (base_element(i).prolongation[0].n() == 0)
- do_prolongation = false;
- }
+ // Check if some of the matrices of
+ // the base elements are void.
+ // repeat this check for each RefineCase
+ bool do_restriction = true;
+ bool do_prolongation = true;
+
+ for (unsigned int i=0; i<n_base_elements(); ++i)
+ {
+ if (base_element(i).restriction[ref_case-1][0].n() == 0)
+ do_restriction = false;
+ if (base_element(i).prolongation[ref_case-1][0].n() == 0)
+ do_prolongation = false;
+ }
- // if we did not encounter void
- // matrices, initialize the
- // respective matrix sizes
- if (do_restriction)
- for (unsigned int i=0;i<GeometryInfo<dim>::children_per_cell;++i)
- this->restriction[i].reinit(this->dofs_per_cell,
- this->dofs_per_cell);
- if (do_prolongation)
- for (unsigned int i=0;i<GeometryInfo<dim>::children_per_cell;++i)
- this->prolongation[i].reinit(this->dofs_per_cell,
- this->dofs_per_cell);
+ // if we did not encounter void
+ // matrices, initialize the
+ // respective matrix sizes
+ if (do_restriction)
+ for (unsigned int i=0;i<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));++i)
+ this->restriction[ref_case-1][i].reinit(this->dofs_per_cell,
+ this->dofs_per_cell);
+ if (do_prolongation)
+ for (unsigned int i=0;i<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));++i)
+ this->prolongation[ref_case-1][i].reinit(this->dofs_per_cell,
+ this->dofs_per_cell);
- // distribute the matrices of the
- // base finite elements to the
- // matrices of this object. for
- // this, loop over all degrees of
- // freedom and take the respective
- // entry of the underlying base
- // element.
- //
- // note that we by definition of a
- // base element, they are
- // independent, i.e. do not
- // couple. only DoFs that belong to
- // the same instance of a base
- // element may couple
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- for (unsigned int j=0; j<this->dofs_per_cell; ++j)
- {
- // first find out to which
- // base element indices i and
- // j belong, and which
- // instance thereof in case
- // the base element has a
- // multiplicity greater than
- // one. if they should not
- // happen to belong to the
- // same instance of a base
- // element, then they cannot
- // couple, so go on with the
- // next index
- if (this->system_to_base_table[i].first !=
- this->system_to_base_table[j].first)
- continue;
-
- // so get the common base
- // element and the indices
- // therein:
- const unsigned int
- base = this->system_to_base_table[i].first.first;
-
- const unsigned int
- base_index_i = this->system_to_base_table[i].second,
- base_index_j = this->system_to_base_table[j].second;
-
- // if we are sure that DoFs i
- // and j may couple, then
- // copy entries of the
- // matrices:
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
+ // distribute the matrices of the
+ // base finite elements to the
+ // matrices of this object. for
+ // this, loop over all degrees of
+ // freedom and take the respective
+ // entry of the underlying base
+ // element.
+ //
+ // note that we by definition of a
+ // base element, they are
+ // independent, i.e. do not
+ // couple. only DoFs that belong to
+ // the same instance of a base
+ // element may couple
+ for (unsigned int i=0; i<this->dofs_per_cell; ++i)
+ for (unsigned int j=0; j<this->dofs_per_cell; ++j)
{
- if (do_restriction)
- this->restriction[child] (i,j)
- = (base_element(base)
- .get_restriction_matrix(child)(base_index_i,base_index_j));
+ // first find out to which
+ // base element indices i and
+ // j belong, and which
+ // instance thereof in case
+ // the base element has a
+ // multiplicity greater than
+ // one. if they should not
+ // happen to belong to the
+ // same instance of a base
+ // element, then they cannot
+ // couple, so go on with the
+ // next index
+ if (this->system_to_base_table[i].first !=
+ this->system_to_base_table[j].first)
+ continue;
+
+ // so get the common base
+ // element and the indices
+ // therein:
+ const unsigned int
+ base = this->system_to_base_table[i].first.first;
+
+ const unsigned int
+ base_index_i = this->system_to_base_table[i].second,
+ base_index_j = this->system_to_base_table[j].second;
+
+ // if we are sure that DoFs i
+ // and j may couple, then
+ // copy entries of the
+ // matrices:
+ for (unsigned int child=0; child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++child)
+ {
+ if (do_restriction)
+ this->restriction[ref_case-1][child] (i,j)
+ = (base_element(base)
+ .get_restriction_matrix(child, RefinementCase<dim>(ref_case))(
+ base_index_i,base_index_j));
- if (do_prolongation)
- this->prolongation[child] (i,j)
- = (base_element(base)
- .get_prolongation_matrix(child)(base_index_i,base_index_j));
+ if (do_prolongation)
+ this->prolongation[ref_case-1][child] (i,j)
+ = (base_element(base)
+ .get_prolongation_matrix(child, RefinementCase<dim>(ref_case))(
+ base_index_i,base_index_j));
+ };
};
- };
-
+ }
// now set up the interface constraints.
// this is kind'o hairy, so don't try
// to do it dimension independent
template<int dim, typename number>
void
FETools::compute_embedding_matrices(const FiniteElement<dim>& fe,
- FullMatrix<number> (&matrices)[GeometryInfo<dim>::children_per_cell])
+ std::vector<std::vector<FullMatrix<number> > >& matrices)
{
- const unsigned int nc = GeometryInfo<dim>::children_per_cell;
const unsigned int n = fe.dofs_per_cell;
const unsigned int nd = fe.n_components();
const unsigned int degree = fe.degree;
-
- for (unsigned int i=0;i<nc;++i)
+
+ // loop over all possible refinement cases
+ for (unsigned int ref_case=RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
{
- Assert(matrices[i].n() == n, ExcDimensionMismatch(matrices[i].n(),n));
- Assert(matrices[i].m() == n, ExcDimensionMismatch(matrices[i].m(),n));
- }
+ const unsigned int nc = GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));
+ for (unsigned int i=0;i<nc;++i)
+ {
+ Assert(matrices[ref_case-1][i].n() == n, ExcDimensionMismatch(matrices[ref_case-1][i].n(),n));
+ Assert(matrices[ref_case-1][i].m() == n, ExcDimensionMismatch(matrices[ref_case-1][i].m(),n));
+ }
- // Set up a meshes, one with a single
- // reference cell and refine it once
- Triangulation<dim> tria;
- GridGenerator::hyper_cube (tria, 0, 1);
- tria.refine_global(1);
+ // Set up meshes, one with a single
+ // reference cell and refine it once
+ Triangulation<dim> tria;
+ GridGenerator::hyper_cube (tria, 0, 1);
+ tria.begin_active()->set_refine_flag(RefinementCase<dim>(ref_case));
+ tria.execute_coarsening_and_refinement();
- MappingCartesian<dim> mapping;
- QGauss<dim> q_fine(degree+1);
- const unsigned int nq = q_fine.size();
+ MappingCartesian<dim> mapping;
+ QGauss<dim> q_fine(degree+1);
+ const unsigned int nq = q_fine.size();
- FEValues<dim> fine (mapping, fe, q_fine,
- update_quadrature_points | update_JxW_values | update_values);
+ FEValues<dim> fine (mapping, fe, q_fine,
+ update_quadrature_points | update_JxW_values | update_values);
- // We search for the polynomial on
- // the small cell, being equal to
- // the coarse polynomial in all
- // quadrature points.
+ // We search for the polynomial on
+ // the small cell, being equal to
+ // the coarse polynomial in all
+ // quadrature points.
- // First build the matrix for this
- // least squares problem. This
- // contains the values of the fine
- // cell polynomials in the fine
- // cell grid points.
+ // First build the matrix for this
+ // least squares problem. This
+ // contains the values of the fine
+ // cell polynomials in the fine
+ // cell grid points.
- // This matrix is the same for all
- // children.
- fine.reinit(tria.begin_active());
- FullMatrix<number> A(nq*nd, n);
- for (unsigned int d=0;d<nd;++d)
- for (unsigned int k=0;k<nq;++k)
- for (unsigned int j=0;j<n;++j)
- A(k*nd+d,j) = fine.shape_value_component(j,k,d);
+ // This matrix is the same for all
+ // children.
+ fine.reinit(tria.begin_active());
+ FullMatrix<number> A(nq*nd, n);
+ for (unsigned int d=0;d<nd;++d)
+ for (unsigned int k=0;k<nq;++k)
+ for (unsigned int j=0;j<n;++j)
+ A(k*nd+d,j) = fine.shape_value_component(j,k,d);
- Householder<double> H(A);
+ Householder<double> H(A);
- Vector<number> v_coarse(nq*nd);
- Vector<number> v_fine(n);
+ Vector<number> v_coarse(nq*nd);
+ Vector<number> v_fine(n);
- unsigned int cell_number = 0;
- for (typename Triangulation<dim>::active_cell_iterator fine_cell
- = tria.begin_active();
- fine_cell != tria.end(); ++fine_cell, ++cell_number)
- {
- fine.reinit(fine_cell);
-
- // evaluate on the coarse cell (which
- // is the first -- inactive -- cell on
- // the lowest level of the
- // triangulation we have created)
- const Quadrature<dim> q_coarse (fine.get_quadrature_points(),
- fine.get_JxW_values());
- FEValues<dim> coarse (mapping, fe, q_coarse, update_values);
- coarse.reinit(tria.begin(0));
-
- FullMatrix<double> &this_matrix = matrices[cell_number];
-
- // Compute this once for each
- // coarse grid basis function
- for (unsigned int i=0;i<n;++i)
+ unsigned int cell_number = 0;
+ for (typename Triangulation<dim>::active_cell_iterator fine_cell
+ = tria.begin_active();
+ fine_cell != tria.end(); ++fine_cell, ++cell_number)
{
- // The right hand side of
- // the least squares
- // problem consists of the
- // function values of the
- // coarse grid function in
- // each quadrature point.
- for (unsigned int d=0;d<nd;++d)
- for (unsigned int k=0;k<nq;++k)
- v_coarse(k*nd+d) = coarse.shape_value_component(i,k,d);
-
- // solve the least squares
- // problem.
- const double result = H.least_squares(v_fine, v_coarse);
- Assert (result < 1.e-12, ExcLeastSquaresError(result));
+ fine.reinit(fine_cell);
+
+ // evaluate on the coarse cell (which
+ // is the first -- inactive -- cell on
+ // the lowest level of the
+ // triangulation we have created)
+ const Quadrature<dim> q_coarse (fine.get_quadrature_points(),
+ fine.get_JxW_values());
+ FEValues<dim> coarse (mapping, fe, q_coarse, update_values);
+ coarse.reinit(tria.begin(0));
+
+ FullMatrix<double> &this_matrix = matrices[ref_case-1][cell_number];
+
+ // Compute this once for each
+ // coarse grid basis function
+ for (unsigned int i=0;i<n;++i)
+ {
+ // The right hand side of
+ // the least squares
+ // problem consists of the
+ // function values of the
+ // coarse grid function in
+ // each quadrature point.
+ for (unsigned int d=0;d<nd;++d)
+ for (unsigned int k=0;k<nq;++k)
+ v_coarse(k*nd+d) = coarse.shape_value_component(i,k,d);
+
+ // solve the least squares
+ // problem.
+ const double result = H.least_squares(v_fine, v_coarse);
+ Assert (result < 1.e-12, ExcLeastSquaresError(result));
- // Copy into the result
- // matrix. Since the matrix
- // maps a coarse grid
- // function to a fine grid
- // function, the columns
- // are fine grid.
- for (unsigned int j=0;j<n;++j)
- this_matrix(j,i) = v_fine(j);
+ // Copy into the result
+ // matrix. Since the matrix
+ // maps a coarse grid
+ // function to a fine grid
+ // function, the columns
+ // are fine grid.
+ for (unsigned int j=0;j<n;++j)
+ this_matrix(j,i) = v_fine(j);
+ }
+ // Remove small entries from
+ // the matrix
+ for (unsigned int i=0; i<this_matrix.m(); ++i)
+ for (unsigned int j=0; j<this_matrix.n(); ++j)
+ if (std::fabs(this_matrix(i,j)) < 1e-12)
+ this_matrix(i,j) = 0.;
}
- // Remove small entries from
- // the matrix
- for (unsigned int i=0; i<this_matrix.m(); ++i)
- for (unsigned int j=0; j<this_matrix.n(); ++j)
- if (std::fabs(this_matrix(i,j)) < 1e-12)
- this_matrix(i,j) = 0.;
+ Assert (cell_number == GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)),
+ ExcInternalError());
}
- Assert (cell_number == GeometryInfo<dim>::children_per_cell,
- ExcInternalError());
}
template<int dim, typename number>
void
FETools::compute_face_embedding_matrices(const FiniteElement<dim>& fe,
- FullMatrix<number> (&matrices)[GeometryInfo<dim>::subfaces_per_face],
+ FullMatrix<number> (&matrices)[GeometryInfo<dim>::max_children_per_face],
const unsigned int face_coarse,
const unsigned int face_fine)
{
- const unsigned int nc = GeometryInfo<dim>::subfaces_per_face;
+ const unsigned int nc = GeometryInfo<dim>::max_children_per_face;
const unsigned int n = fe.dofs_per_face;
const unsigned int nd = fe.n_components();
const unsigned int degree = fe.degree;
- for (unsigned int cell_number = 0; cell_number < GeometryInfo<dim>::subfaces_per_face;
+ for (unsigned int cell_number = 0; cell_number < GeometryInfo<dim>::max_children_per_face;
++cell_number)
{
const Quadrature<dim> q_coarse
FEValues<dim> coarse (mapping, fe, q_coarse, update_values);
typename Triangulation<dim>::active_cell_iterator fine_cell
- = tria.begin(0)->child(GeometryInfo<dim>::child_cell_on_face(face_coarse,
- cell_number));
+ = tria.begin(0)->child(GeometryInfo<dim>::child_cell_on_face(
+ tria.begin(0)->refinement_case(), face_coarse, cell_number));
fine.reinit(fine_cell);
coarse.reinit(tria.begin(0));
template<int dim, typename number>
void
FETools::compute_projection_matrices(const FiniteElement<dim>& fe,
- FullMatrix<number> (&matrices)[GeometryInfo<dim>::children_per_cell])
+ std::vector<std::vector<FullMatrix<number> > >& matrices)
{
- const unsigned int nc = GeometryInfo<dim>::children_per_cell;
const unsigned int n = fe.dofs_per_cell;
const unsigned int nd = fe.n_components();
const unsigned int degree = fe.degree;
-
- for (unsigned int i=0;i<nc;++i)
+
+ // loop over all possible refinement cases
+ for (unsigned int ref_case = RefinementCase<dim>::cut_x;
+ ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
{
- Assert(matrices[i].n() == n, ExcDimensionMismatch(matrices[i].n(),n));
- Assert(matrices[i].m() == n, ExcDimensionMismatch(matrices[i].m(),n));
- }
-
- Triangulation<dim> tr;
- GridGenerator::hyper_cube (tr, 0, 1);
- tr.refine_global(1);
-
- MappingCartesian<dim> mapping;
- QGauss<dim> q_fine(degree+1);
- const unsigned int nq = q_fine.size();
-
- FEValues<dim> coarse (mapping, fe, q_fine,
- update_quadrature_points | update_JxW_values | update_values);
- FEValues<dim> fine (mapping, fe, q_fine,
- update_quadrature_points | update_JxW_values | update_values);
-
- typename Triangulation<dim>::cell_iterator coarse_cell
- = tr.begin(0);
- // Compute the coarse level mass
- // matrix
- coarse.reinit(coarse_cell);
- FullMatrix<number> A(n, n);
- for (unsigned int k=0;k<nq;++k)
- for (unsigned int i=0;i<n;++i)
- for (unsigned int j=0;j<n;++j)
- if (fe.is_primitive())
- A(i,j) += coarse.JxW(k)
- * coarse.shape_value(i,k)
- * coarse.shape_value(j,k);
- else
- for (unsigned int d=0;d<nd;++d)
- A(i,j) = coarse.JxW(k)
- * coarse.shape_value_component(i,k,d)
- * coarse.shape_value_component(j,k,d);
-
- Householder<double> H(A);
+ const unsigned int
+ nc = GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));
- Vector<number> v_coarse(n);
- Vector<number> v_fine(n);
+ for (unsigned int i=0;i<nc;++i)
+ {
+ Assert(matrices[ref_case-1][i].n() == n,
+ ExcDimensionMismatch(matrices[ref_case-1][i].n(),n));
+ Assert(matrices[ref_case-1][i].m() == n,
+ ExcDimensionMismatch(matrices[ref_case-1][i].m(),n));
+ }
- for (unsigned int cell_number=0;cell_number<GeometryInfo<dim>::children_per_cell;++cell_number)
- {
- FullMatrix<double> &this_matrix = matrices[cell_number];
-
- // Compute right hand side,
- // which is a fine level basis
- // function tested with the
- // coarse level functions.
- fine.reinit(coarse_cell->child(cell_number));
- Quadrature<dim> q_coarse (fine.get_quadrature_points(),
- fine.get_JxW_values());
- FEValues<dim> coarse (mapping, fe, q_coarse, update_values);
+ Triangulation<dim> tr;
+ GridGenerator::hyper_cube (tr, 0, 1);
+ tr.begin_active()->set_refine_flag(RefinementCase<dim>(ref_case));
+ tr.execute_coarsening_and_refinement();
+
+ MappingCartesian<dim> mapping;
+ QGauss<dim> q_fine(degree+1);
+ const unsigned int nq = q_fine.size();
+
+ FEValues<dim> coarse (mapping, fe, q_fine,
+ update_quadrature_points |
+ update_JxW_values |
+ update_values);
+ FEValues<dim> fine (mapping, fe, q_fine,
+ update_quadrature_points |
+ update_JxW_values |
+ update_values);
+
+ typename Triangulation<dim>::cell_iterator coarse_cell
+ = tr.begin(0);
+ // Compute the coarse level mass
+ // matrix
coarse.reinit(coarse_cell);
+ FullMatrix<number> A(n, n);
+ for (unsigned int k=0;k<nq;++k)
+ for (unsigned int i=0;i<n;++i)
+ for (unsigned int j=0;j<n;++j)
+ if (fe.is_primitive())
+ A(i,j) += coarse.JxW(k)
+ * coarse.shape_value(i,k)
+ * coarse.shape_value(j,k);
+ else
+ for (unsigned int d=0;d<nd;++d)
+ A(i,j) = coarse.JxW(k)
+ * coarse.shape_value_component(i,k,d)
+ * coarse.shape_value_component(j,k,d);
+
+ Householder<double> H(A);
+
+ Vector<number> v_coarse(n);
+ Vector<number> v_fine(n);
+
+ for (unsigned int cell_number=0;cell_number<nc;++cell_number)
+ {
+ FullMatrix<double> &this_matrix = matrices[ref_case-1][cell_number];
+
+ // Compute right hand side,
+ // which is a fine level basis
+ // function tested with the
+ // coarse level functions.
+ fine.reinit(coarse_cell->child(cell_number));
+ Quadrature<dim> q_coarse (fine.get_quadrature_points(),
+ fine.get_JxW_values());
+ FEValues<dim> coarse (mapping, fe, q_coarse, update_values);
+ coarse.reinit(coarse_cell);
- // Build RHS
+ // Build RHS
- // Outer loop over all fine
- // grid shape functions phi_j
- for (unsigned int j=0;j<fe.dofs_per_cell;++j)
- {
- v_fine = 0.;
- // Loop over all quadrature points
- for (unsigned int k=0;k<fine.n_quadrature_points;++k)
+ // Outer loop over all fine
+ // grid shape functions phi_j
+ for (unsigned int j=0;j<fe.dofs_per_cell;++j)
{
- // integrate the scalar
- // product
- // (phi_i,phi_j) for
- // all coarse shape
- // functions to get the
- // right hand side
- for (unsigned int i=0;i<fe.dofs_per_cell;++i)
+ v_fine = 0.;
+ // Loop over all quadrature points
+ for (unsigned int k=0;k<fine.n_quadrature_points;++k)
{
- if (fe.is_primitive())
- v_fine(i) += fine.JxW(k)
- * coarse.shape_value(i,k)
- * fine.shape_value(j,k);
- else
- for (unsigned int d=0;d<nd;++d)
- v_fine(i) += fine.JxW(k)
- * coarse.shape_value_component(i,k,d)
- * fine.shape_value_component(j,k,d);
+ // integrate the scalar
+ // product
+ // (phi_i,phi_j) for
+ // all coarse shape
+ // functions to get the
+ // right hand side
+ for (unsigned int i=0;i<fe.dofs_per_cell;++i)
+ {
+ if (fe.is_primitive())
+ v_fine(i) += fine.JxW(k)
+ * coarse.shape_value(i,k)
+ * fine.shape_value(j,k);
+ else
+ for (unsigned int d=0;d<nd;++d)
+ v_fine(i) += fine.JxW(k)
+ * coarse.shape_value_component(i,k,d)
+ * fine.shape_value_component(j,k,d);
+ }
}
+ // RHS ready. Solve system
+ // and enter row into
+ // matrix
+ H.least_squares(v_coarse, v_fine);
+ for (unsigned int i=0;i<fe.dofs_per_cell;++i)
+ this_matrix(i,j) = v_coarse(i);
}
- // RHS ready. Solve system
- // and enter row into
- // matrix
- H.least_squares(v_coarse, v_fine);
- for (unsigned int i=0;i<fe.dofs_per_cell;++i)
- this_matrix(i,j) = v_coarse(i);
- }
- // Remove small entries from
- // the matrix
- for (unsigned int i=0; i<this_matrix.m(); ++i)
- for (unsigned int j=0; j<this_matrix.n(); ++j)
- if (std::fabs(this_matrix(i,j)) < 1e-12)
- this_matrix(i,j) = 0.;
+ // Remove small entries from
+ // the matrix
+ for (unsigned int i=0; i<this_matrix.m(); ++i)
+ for (unsigned int j=0; j<this_matrix.n(); ++j)
+ if (std::fabs(this_matrix(i,j)) < 1e-12)
+ this_matrix(i,j) = 0.;
+ }
}
}
// cell has active
// children
bool active_children=false;
- for (unsigned int child_n=0;
- child_n<GeometryInfo<dim>::children_per_cell; ++child_n)
+ for (unsigned int child_n=0; child_n<cell->n_children(); ++child_n)
if (cell->child(child_n)->active())
{
active_children=true;
template
void FETools::compute_embedding_matrices<deal_II_dimension>
-(const FiniteElement<deal_II_dimension> &, FullMatrix<double> (&)[GeometryInfo<deal_II_dimension>::children_per_cell]);
+(const FiniteElement<deal_II_dimension> &, std::vector<std::vector<FullMatrix<double> > >&);
template
void FETools::compute_face_embedding_matrices<deal_II_dimension>
-(const FiniteElement<deal_II_dimension> &, FullMatrix<double> (&matrices)[GeometryInfo<deal_II_dimension>::subfaces_per_face],
+(const FiniteElement<deal_II_dimension> &, FullMatrix<double> (&matrices)[GeometryInfo<deal_II_dimension>::max_children_per_face],
unsigned int, unsigned int);
template
void FETools::compute_projection_matrices<deal_II_dimension>
-(const FiniteElement<deal_II_dimension> &, FullMatrix<double> (&)[GeometryInfo<deal_II_dimension>::children_per_cell]);
+(const FiniteElement<deal_II_dimension> &, std::vector<std::vector<FullMatrix<double> > >&);
template
void FETools::interpolate<deal_II_dimension>
if (flags & update_JxW_values)
this->JxW_values.resize(n_quadrature_points);
+ if (flags & update_jacobians)
+ this->jacobians.resize(n_quadrature_points);
+
+ if (flags & update_jacobian_grads)
+ this->jacobian_grads.resize(n_quadrature_points);
+
if (flags & update_boundary_forms)
this->boundary_forms.resize(n_quadrature_points);
quadrature,
*this->mapping_data,
this->quadrature_points,
- this->JxW_values);
+ this->JxW_values,
+ this->jacobians,
+ this->jacobian_grads);
this->get_fe().fill_fe_values(this->get_mapping(),
*this->present_cell,
// we must use following workaround
// of two separate assertions
Assert (cell->face(face_no)->has_children() ||
- subface_no < GeometryInfo<dim>::subfaces_per_face,
- ExcIndexRange (subface_no, 0, GeometryInfo<dim>::subfaces_per_face));
+ subface_no < GeometryInfo<dim>::max_children_per_face,
+ ExcIndexRange (subface_no, 0, GeometryInfo<dim>::max_children_per_face));
Assert (!cell->face(face_no)->has_children() ||
- subface_no < cell->face(face_no)->n_children(),
- ExcIndexRange (subface_no, 0, cell->face(face_no)->n_children()));
+ subface_no < cell->face(face_no)->number_of_children(),
+ ExcIndexRange (subface_no, 0, cell->face(face_no)->number_of_children()));
Assert (cell->has_children() == false,
ExcMessage ("You can't use subface data for cells that are "
typename FEValuesBase<dim>::ExcFEDontMatch());
Assert (face_no < GeometryInfo<dim>::faces_per_cell,
ExcIndexRange (face_no, 0, GeometryInfo<dim>::faces_per_cell));
- Assert (subface_no < cell->face(face_no)->n_children(),
- ExcIndexRange (subface_no, 0, cell->face(face_no)->n_children()));
+ Assert (subface_no < cell->face(face_no)->number_of_children(),
+ ExcIndexRange (subface_no, 0, cell->face(face_no)->number_of_children()));
Assert (cell->has_children() == false,
ExcMessage ("You can't use subface data for cells that are "
"already refined. Iterate over their children "
typename FEValuesBase<dim>::ExcFEDontMatch());
Assert (face_no < GeometryInfo<dim>::faces_per_cell,
ExcIndexRange (face_no, 0, GeometryInfo<dim>::faces_per_cell));
- Assert (subface_no < cell->face(face_no)->n_children(),
- ExcIndexRange (subface_no, 0, cell->face(face_no)->n_children()));
+ Assert (subface_no < cell->face(face_no)->number_of_children(),
+ ExcIndexRange (subface_no, 0, cell->face(face_no)->number_of_children()));
Assert (cell->has_children() == false,
ExcMessage ("You can't use subface data for cells that are "
"already refined. Iterate over their children "
void FESubfaceValues<dim>::do_reinit (const unsigned int face_no,
const unsigned int subface_no)
{
-
- // set the present face index
+ // first of all, set the present_face_index
+ // (if available)
const typename Triangulation<dim>::cell_iterator cell=*this->present_cell;
- unsigned int real_subface_no=subface_no;
- if (dim==3)
- real_subface_no=GeometryInfo<dim>::standard_to_real_face_vertex(
- subface_no, cell->face_orientation(face_no), cell->face_flip(face_no), cell->face_rotation(face_no));
- if (cell->face(face_no)->has_children())
- this->present_face_index=cell->face(face_no)->child_index(real_subface_no);
- else
- this->present_face_index=cell->face_index(face_no);
+ if (!cell->face(face_no)->has_children())
+ // no subfaces at all, so set
+ // present_face_index to this face rather
+ // than any subface
+ this->present_face_index=cell->face_index(face_no);
+ else
+ if (dim!=3)
+ this->present_face_index=cell->face(face_no)->child_index(subface_no);
+ else
+ {
+ // this is the same logic we use in
+ // cell->neighbor_child_on_subface(). See
+ // there for an explanation of the
+ // different cases
+ unsigned int subface_index=numbers::invalid_unsigned_int;
+ switch (cell->subface_case(face_no))
+ {
+ case internal::SubfaceCase<3>::case_x:
+ case internal::SubfaceCase<3>::case_y:
+ case internal::SubfaceCase<3>::case_xy:
+ subface_index=cell->face(face_no)->child_index(subface_no);
+ break;
+ case internal::SubfaceCase<3>::case_x1y2y:
+ case internal::SubfaceCase<3>::case_y1x2x:
+ subface_index=cell->face(face_no)->child(subface_no/2)->child_index(subface_no%2);
+ break;
+ case internal::SubfaceCase<3>::case_x1y:
+ case internal::SubfaceCase<3>::case_y1x:
+ switch (subface_no)
+ {
+ case 0:
+ case 1:
+ subface_index=cell->face(face_no)->child(0)->child_index(subface_no);
+ break;
+ case 2:
+ subface_index=cell->face(face_no)->child_index(1);
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ }
+ break;
+ case internal::SubfaceCase<3>::case_x2y:
+ case internal::SubfaceCase<3>::case_y2x:
+ switch (subface_no)
+ {
+ case 0:
+ subface_index=cell->face(face_no)->child_index(0);
+ break;
+ case 1:
+ case 2:
+ subface_index=cell->face(face_no)->child(1)->child_index(subface_no-1);
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ }
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ break;
+ }
+ Assert(subface_index!=numbers::invalid_unsigned_int,
+ ExcInternalError());
+ this->present_face_index=subface_index;
+ }
+
+ // now ask the mapping and the finite element
+ // to do the actual work
this->get_mapping().fill_fe_subface_values(*this->present_cell,
face_no, subface_no,
this->quadrature,
// $Id$
// Version: $Name$
//
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
Assert (face_no+1 < GeometryInfo<dim>::faces_per_cell+1,
ExcIndexRange (face_no, 0, GeometryInfo<dim>::faces_per_cell));
- Assert ((sub_no == invalid_face_number)
- ||
- (sub_no+1 < GeometryInfo<dim>::subfaces_per_face+1),
+ // We would like to check for
+ // sub_no < cell->face(face_no)->n_children(),
+ // but unfortunately the current
+ // function is also called for
+ // faces without children (see
+ // tests/fe/mapping.cc). Therefore,
+ // we must use following workaround
+ // of two separate assertions
+#if deal_II_dimension != 1
+ Assert ((sub_no == invalid_face_number) ||
+ cell->face(face_no)->has_children() ||
+ (sub_no+1 < GeometryInfo<dim>::max_children_per_face+1),
ExcIndexRange (sub_no, 0,
- GeometryInfo<dim>::subfaces_per_face));
+ GeometryInfo<dim>::max_children_per_face));
+ Assert ((sub_no == invalid_face_number) ||
+ !cell->face(face_no)->has_children() ||
+ (sub_no < cell->face(face_no)->n_children()),
+ ExcIndexRange (sub_no, 0, cell->face(face_no)->n_children()));
+#endif
}
else
// invalid face number, so
:
// called from FESubfaceValues
QProjector<dim>::DataSetDescriptor::subface (face_no, sub_no,
- cell->face_orientation(face_no),
- cell->face_flip(face_no),
- cell->face_rotation(face_no),
- quadrature_points.size())
+ cell->face_orientation(face_no),
+ cell->face_flip(face_no),
+ cell->face_rotation(face_no),
+ quadrature_points.size(),
+ cell->subface_case(face_no))
));
for (unsigned int i=0; i<quadrature_points.size(); ++i)
const Quadrature<dim>& q,
typename Mapping<dim>::InternalDataBase& mapping_data,
std::vector<Point<dim> >& quadrature_points,
- std::vector<double>& JxW_values) const
+ std::vector<double>& JxW_values,
+ std::vector<Tensor<2,dim> >& jacobians,
+ std::vector<Tensor<3,dim> >& jacobian_grads) const
{
// convert data object to internal
// data for this class. fails with
for (unsigned int i=0; i<JxW_values.size();++i)
JxW_values[i] = J * q.weight(i);
}
+ // "compute" Jacobian at the quadrature
+ // points, which are all the same
+ if (data.current_update_flags() & update_jacobians)
+ for (unsigned int i=0; i<jacobians.size();++i)
+ {
+ jacobians[i]=Tensor<2,dim>();
+ for (unsigned int j=0; j<dim; ++j)
+ jacobians[j][j]=data.length[j];
+ }
+ // "compute" the derivative of the Jacobian
+ // at the quadrature points, which are all
+ // zero of course
+ if (data.current_update_flags() & update_jacobian_grads)
+ for (unsigned int i=0; i<jacobian_grads.size();++i)
+ jacobian_grads[i]=Tensor<3,dim>();
}
J *= data.length[d];
if (data.current_update_flags() & update_JxW_values)
- for (unsigned int i=0; i<JxW_values.size();++i)
- JxW_values[i] = J * q.weight(i) / GeometryInfo<dim>::subfaces_per_face;
+ {
+ // Here,
+ // cell->face(face_no)->n_children()
+ // would be the right choice,
+ // but unfortunately the
+ // current function is also
+ // called for faces without
+ // children (see
+ // tests/fe/mapping.cc). Add
+ // following switch to avoid
+ // diffs in tests/fe/mapping.OK
+ const unsigned int n_subfaces=
+ cell->face(face_no)->has_children() ?
+ cell->face(face_no)->n_children() :
+ GeometryInfo<dim>::max_children_per_face;
+ for (unsigned int i=0; i<JxW_values.size();++i)
+ JxW_values[i] = J * q.weight(i) / n_subfaces;
+ }
if (data.current_update_flags() & update_boundary_forms)
for (unsigned int i=0; i<boundary_forms.size();++i)
grads.resize(n_shape_functions);
}
- // dummy variable of size 0
+// // dummy variable of size 0
std::vector<Tensor<2,dim> > grad2;
+ if (data.shape_second_derivatives.size()!=0)
+ {
+ Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
+ ExcInternalError());
+ grad2.resize(n_shape_functions);
+ }
if (data.shape_values.size()!=0 || data.shape_derivatives.size()!=0)
if (data.shape_derivatives.size()!=0)
for (unsigned int i=0; i<n_shape_functions; ++i)
data.derivative(point,renumber[i]) = grads[i];
+
+ if (data.shape_second_derivatives.size()!=0)
+ for (unsigned int i=0; i<n_shape_functions; ++i)
+ data.second_derivative(point,renumber[i]) = grad2[i];
}
}
const Quadrature<dim> &q,
typename Mapping<dim>::InternalDataBase &mapping_data,
std::vector<Point<dim> > &quadrature_points,
- std::vector<double> &JxW_values) const
+ std::vector<double> &JxW_values,
+ std::vector<Tensor<2,dim> > &jacobians,
+ std::vector<Tensor<3,dim> > &jacobian_grads) const
{
// convert data object to internal
// data for this class. fails with
p_data=&data;
MappingQ1<dim>::fill_fe_values(cell, q, *p_data,
- quadrature_points, JxW_values);
+ quadrature_points, JxW_values,
+ jacobians, jacobian_grads);
}
p_data=&data;
const unsigned int n_q_points=q.size();
- this->compute_fill_face (cell, face_no, false,
+ this->compute_fill_face (cell, face_no, deal_II_numbers::invalid_unsigned_int,
n_q_points,
QProjector<dim>::DataSetDescriptor::
face (face_no,
p_data=&data;
const unsigned int n_q_points=q.size();
- this->compute_fill_face (cell, face_no, true,
+ this->compute_fill_face (cell, face_no, sub_no,
n_q_points,
QProjector<dim>::DataSetDescriptor::
subface (face_no, sub_no,
data.derivative(k,0)[0] = -1.;
data.derivative(k,1)[0] = 1.;
}
+ if (data.shape_second_derivatives.size()!=0)
+ {
+ Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
+ ExcInternalError());
+ data.second_derivative(k,0)[0][0] = 0;
+ data.second_derivative(k,1)[0][0] = 0;
+ }
+
}
}
data.derivative(k,2)[1] = (1.-x);
data.derivative(k,3)[1] = x;
}
+ if (data.shape_second_derivatives.size()!=0)
+ {
+ Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
+ ExcInternalError());
+ data.second_derivative(k,0)[0][0] = 0;
+ data.second_derivative(k,1)[0][0] = 0;
+ data.second_derivative(k,2)[0][0] = 0;
+ data.second_derivative(k,3)[0][0] = 0;
+ data.second_derivative(k,0)[0][1] = 1.;
+ data.second_derivative(k,1)[0][1] = -1.;
+ data.second_derivative(k,2)[0][1] = -1.;
+ data.second_derivative(k,3)[0][1] = 1.;
+ data.second_derivative(k,0)[1][0] = 1.;
+ data.second_derivative(k,1)[1][0] = -1.;
+ data.second_derivative(k,2)[1][0] = -1.;
+ data.second_derivative(k,3)[1][0] = 1.;
+ data.second_derivative(k,0)[1][1] = 0;
+ data.second_derivative(k,1)[1][1] = 0;
+ data.second_derivative(k,2)[1][1] = 0;
+ data.second_derivative(k,3)[1][1] = 0;
+ }
}
}
data.derivative(k,6)[2] = (1.-x)*y;
data.derivative(k,7)[2] = x*y;
}
+ if (data.shape_second_derivatives.size()!=0)
+ {
+ Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
+ ExcInternalError());
+ data.second_derivative(k,0)[0][0] = 0;
+ data.second_derivative(k,1)[0][0] = 0;
+ data.second_derivative(k,2)[0][0] = 0;
+ data.second_derivative(k,3)[0][0] = 0;
+ data.second_derivative(k,4)[0][0] = 0;
+ data.second_derivative(k,5)[0][0] = 0;
+ data.second_derivative(k,6)[0][0] = 0;
+ data.second_derivative(k,7)[0][0] = 0;
+ data.second_derivative(k,0)[1][1] = 0;
+ data.second_derivative(k,1)[1][1] = 0;
+ data.second_derivative(k,2)[1][1] = 0;
+ data.second_derivative(k,3)[1][1] = 0;
+ data.second_derivative(k,4)[1][1] = 0;
+ data.second_derivative(k,5)[1][1] = 0;
+ data.second_derivative(k,6)[1][1] = 0;
+ data.second_derivative(k,7)[1][1] = 0;
+ data.second_derivative(k,0)[2][2] = 0;
+ data.second_derivative(k,1)[2][2] = 0;
+ data.second_derivative(k,2)[2][2] = 0;
+ data.second_derivative(k,3)[2][2] = 0;
+ data.second_derivative(k,4)[2][2] = 0;
+ data.second_derivative(k,5)[2][2] = 0;
+ data.second_derivative(k,6)[2][2] = 0;
+ data.second_derivative(k,7)[2][2] = 0;
+
+ data.second_derivative(k,0)[0][1] = (1.-z);
+ data.second_derivative(k,1)[0][1] = -(1.-z);
+ data.second_derivative(k,2)[0][1] = -(1.-z);
+ data.second_derivative(k,3)[0][1] = (1.-z);
+ data.second_derivative(k,4)[0][1] = z;
+ data.second_derivative(k,5)[0][1] = -z;
+ data.second_derivative(k,6)[0][1] = -z;
+ data.second_derivative(k,7)[0][1] = z;
+ data.second_derivative(k,0)[1][0] = (1.-z);
+ data.second_derivative(k,1)[1][0] = -(1.-z);
+ data.second_derivative(k,2)[1][0] = -(1.-z);
+ data.second_derivative(k,3)[1][0] = (1.-z);
+ data.second_derivative(k,4)[1][0] = z;
+ data.second_derivative(k,5)[1][0] = -z;
+ data.second_derivative(k,6)[1][0] = -z;
+ data.second_derivative(k,7)[1][0] = z;
+
+ data.second_derivative(k,0)[0][2] = (1.-y);
+ data.second_derivative(k,1)[0][2] = -(1.-y);
+ data.second_derivative(k,2)[0][2] = y;
+ data.second_derivative(k,3)[0][2] = -y;
+ data.second_derivative(k,4)[0][2] = -(1.-y);
+ data.second_derivative(k,5)[0][2] = (1.-y);
+ data.second_derivative(k,6)[0][2] = -y;
+ data.second_derivative(k,7)[0][2] = y;
+ data.second_derivative(k,0)[2][0] = (1.-y);
+ data.second_derivative(k,1)[2][0] = -(1.-y);
+ data.second_derivative(k,2)[2][0] = y;
+ data.second_derivative(k,3)[2][0] = -y;
+ data.second_derivative(k,4)[2][0] = -(1.-y);
+ data.second_derivative(k,5)[2][0] = (1.-y);
+ data.second_derivative(k,6)[2][0] = -y;
+ data.second_derivative(k,7)[2][0] = y;
+
+ data.second_derivative(k,0)[1][2] = (1.-x);
+ data.second_derivative(k,1)[1][2] = x;
+ data.second_derivative(k,2)[1][2] = -(1.-x);
+ data.second_derivative(k,3)[1][2] = -x;
+ data.second_derivative(k,4)[1][2] = -(1.-x);
+ data.second_derivative(k,5)[1][2] = -x;
+ data.second_derivative(k,6)[1][2] = (1.-x);
+ data.second_derivative(k,7)[1][2] = x;
+ data.second_derivative(k,0)[2][1] = (1.-x);
+ data.second_derivative(k,1)[2][1] = x;
+ data.second_derivative(k,2)[2][1] = -(1.-x);
+ data.second_derivative(k,3)[2][1] = -x;
+ data.second_derivative(k,4)[2][1] = -(1.-x);
+ data.second_derivative(k,5)[2][1] = -x;
+ data.second_derivative(k,6)[2][1] = (1.-x);
+ data.second_derivative(k,7)[2][1] = x;
+ }
}
}
| update_contravariant_transformation
| update_JxW_values
| update_boundary_forms
- | update_normal_vectors))
+ | update_normal_vectors
+ | update_jacobians
+ | update_jacobian_grads))
out |= update_transformation_gradients;
return out;
| update_JxW_values
| update_cell_JxW_values
| update_boundary_forms
- | update_normal_vectors));
+ | update_normal_vectors
+ | update_jacobians
+ | update_jacobian_grads));
// add a few flags. note that some
// flags appear in both conditions
if (out & (update_covariant_transformation
| update_JxW_values
+ | update_jacobians
+ | update_jacobian_grads
| update_boundary_forms
| update_normal_vectors))
out |= update_contravariant_transformation;
if (flags & update_contravariant_transformation)
data.contravariant.resize(n_original_q_points);
+ if (flags & update_jacobian_grads)
+ data.shape_second_derivatives.resize(data.n_shape_functions * n_q_points);
+
compute_shapes (q.get_points(), data);
}
data.contravariant.end(),
Tensor<2,dim>());
}
-
- if (update_flags & update_jacobian_grads)
- {
- Assert(false, ExcNotImplemented());
-// Assert (covariant_grads.size () == n_q_points,
-// ExcDimensionMismatch(covariant_grads.size(), n_q_points));
- }
-
+
// if necessary, recompute the
// support points of the
// transformation of this cell
for (unsigned int k=0; k<data.n_shape_functions; ++k)
for (unsigned int i=0; i<dim; ++i)
for (unsigned int j=0; j<dim; ++j)
- data.contravariant[point][i][j]
- += (data.derivative(point+data_set, k)[j]
- *
- data.mapping_support_points[k][i]);
+ data.contravariant[point][i][j]
+ += (data.derivative(point+data_set, k)[j]
+ *
+ data.mapping_support_points[k][i]);
// invert contravariant for
// covariant transformation
const Quadrature<dim> &q,
typename Mapping<dim>::InternalDataBase &mapping_data,
std::vector<Point<dim> > &quadrature_points,
- std::vector<double> &JxW_values) const
+ std::vector<double> &JxW_values,
+ std::vector<Tensor<2,dim> > &jacobians,
+ std::vector<Tensor<3,dim> > &jacobian_grads) const
{
InternalData *data_ptr = dynamic_cast<InternalData *> (&mapping_data);
Assert(data_ptr!=0, ExcInternalError());
for (unsigned int point=0; point<n_q_points; ++point)
JxW_values[point]
= determinant(data.contravariant[point])*weights[point];
+ }
+
+ // copy values from InternalData to vector
+ // given by reference
+ if (update_flags & update_jacobians)
+ {
+ Assert (jacobians.size() == n_q_points,
+ ExcDimensionMismatch(jacobians.size(), n_q_points));
+ for (unsigned int point=0; point<n_q_points; ++point)
+ jacobians[point]
+ = data.contravariant[point];
+ }
+ // calculate values of the derivatives of the
+ // Jacobians. do it here, since we only do it
+ // for cells, not faces.
+ if (update_flags & update_jacobian_grads)
+ {
+ Assert (jacobian_grads.size() == n_q_points,
+ ExcDimensionMismatch(jacobian_grads.size(), n_q_points));
+ std::fill(jacobian_grads.begin(),
+ jacobian_grads.end(),
+ Tensor<3,dim>());
+
+ for (unsigned int point=0; point<n_q_points; ++point)
+ for (unsigned int k=0; k<data.n_shape_functions; ++k)
+ for (unsigned int i=0; i<dim; ++i)
+ for (unsigned int j=0; j<dim; ++j)
+ for (unsigned int l=0; l<dim; ++l)
+ jacobian_grads[point][i][j][l]
+ += (data.second_derivative(point+DataSetDescriptor::cell (), k)[j][l]
+ *
+ data.mapping_support_points[k][i]);
}
}
void
MappingQ1<dim>::compute_fill_face (const typename Triangulation<dim>::cell_iterator &cell,
const unsigned int face_no,
- const bool is_subface,
+ const unsigned int subface_no,
const unsigned int n_q_points,
const DataSetDescriptor data_set,
const std::vector<double> &weights,
if (update_flags & update_JxW_values)
{
JxW_values[i] = f * weights[i];
- if (is_subface)
- JxW_values[i] /= GeometryInfo<dim>::subfaces_per_face;
+ if (subface_no!=deal_II_numbers::invalid_unsigned_int)
+ {
+ const double area_ratio=GeometryInfo<dim>::subface_ratio(
+ cell->subface_case(face_no), subface_no);
+ JxW_values[i] *= area_ratio;
+ }
}
if (update_flags & update_normal_vectors)
normal_vectors[i] = boundary_forms[i] / f;
const unsigned int n_q_points = q.size();
- compute_fill_face (cell, face_no, false,
+ compute_fill_face (cell, face_no, deal_II_numbers::invalid_unsigned_int,
n_q_points,
DataSetDescriptor::face (face_no,
cell->face_orientation(face_no),
const unsigned int n_q_points = q.size();
- compute_fill_face (cell, face_no, true,
+ compute_fill_face (cell, face_no, sub_no,
n_q_points,
DataSetDescriptor::subface (face_no, sub_no,
cell->face_orientation(face_no),
cell->face_flip(face_no),
cell->face_rotation(face_no),
- n_q_points),
+ n_q_points,
+ cell->subface_case(face_no)),
q.get_weights(),
data,
quadrature_points,
void
MappingQ1<1>::compute_fill_face (const Triangulation<1>::cell_iterator &,
const unsigned int,
- const bool,
+ const unsigned int,
const unsigned int,
const DataSetDescriptor,
const std::vector<double> &,
// refining cells and instead try to
// only coarsen as many as it would
// take to get to the target
+
+ // as we have no information on cells
+ // being refined isotropically or
+ // anisotropically, assume isotropic
+ // refinement here, though that may
+ // result in a worse approximation
refine_cells = 0;
coarsen_cells = (tria.n_active_cells() - max_n_cells) *
- GeometryInfo<dim>::children_per_cell /
- (GeometryInfo<dim>::children_per_cell - 1);
+ GeometryInfo<dim>::max_children_per_cell /
+ (GeometryInfo<dim>::max_children_per_cell - 1);
}
// otherwise, see if we would exceed the
// maximum desired number of cells with the
// number of cells that are likely going to
// result from refinement. here, each cell
// to be refined is replaced by
- // C=GeometryInfo<dim>::children_per_cell
+ // C=GeometryInfo<dim>::max_children_per_cell
// new cells, i.e. there will be C-1 more
// cells than before. similarly, C cells
// will be replaced by 1
+
+ // again, this is true for isotropically
+ // refined cells. we take this as an
+ // approximation of a mixed refinement.
else if (static_cast<unsigned int>
(tria.n_active_cells()
- + refine_cells * (GeometryInfo<dim>::children_per_cell - 1)
+ + refine_cells * (GeometryInfo<dim>::max_children_per_cell - 1)
- (coarsen_cells *
- (GeometryInfo<dim>::children_per_cell - 1) /
- GeometryInfo<dim>::children_per_cell))
+ (GeometryInfo<dim>::max_children_per_cell - 1) /
+ GeometryInfo<dim>::max_children_per_cell))
>
max_n_cells)
{
1. *
(max_n_cells - tria.n_active_cells())
/
- (refine_cells * (GeometryInfo<dim>::children_per_cell - 1)
+ (refine_cells * (GeometryInfo<dim>::max_children_per_cell - 1)
- (coarsen_cells *
- (GeometryInfo<dim>::children_per_cell - 1) /
- GeometryInfo<dim>::children_per_cell));
+ (GeometryInfo<dim>::max_children_per_cell - 1) /
+ GeometryInfo<dim>::max_children_per_cell));
refine_cells = static_cast<int> (refine_cells * alpha);
coarsen_cells = static_cast<int> (coarsen_cells * alpha);
}
// over the limit and if so use a function
// that knows how to deal with this
// situation
+
+ // note, that at this point, we have no
+ // information about anisotropically refined
+ // cells, thus use the situation of purely
+ // isotropic refinement as guess for a mixed
+ // refinemnt as well.
{
const unsigned int refine_cells = pp - tmp.begin(),
coarsen_cells = tmp.end() - qq;
if (static_cast<unsigned int>
(tria.n_active_cells()
- + refine_cells * (GeometryInfo<dim>::children_per_cell - 1)
+ + refine_cells * (GeometryInfo<dim>::max_children_per_cell - 1)
- (coarsen_cells *
- (GeometryInfo<dim>::children_per_cell - 1) /
- GeometryInfo<dim>::children_per_cell))
+ (GeometryInfo<dim>::max_children_per_cell - 1) /
+ GeometryInfo<dim>::max_children_per_cell))
>
max_n_cells)
{
ExcMessage ("The two containers must be represent triangulations that "
"have the same coarse meshes"));
- const unsigned int dim = Container::dimension;
-
// the algorithm goes as follows:
// first, we fill a list with pairs
// of iterators common to the two
&&
cell_pair->second->has_children())
{
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ Assert(cell_pair->first->refinement_case()==
+ cell_pair->second->refinement_case(), ExcNotImplemented());
+ for (unsigned int c=0; c<cell_pair->first->n_children(); ++c)
cell_list.push_back (std::make_pair (cell_pair->first->child(c),
cell_pair->second->child(c)));
++cell_pair;
}
- // just to make sure everything is
- // ok, validate that all pairs have
- // at least one active iterator
+ // just to make sure everything is ok,
+ // validate that all pairs have at least one
+ // active iterator or have different
+ // refinement_cases
for (cell_pair = cell_list.begin(); cell_pair != cell_list.end(); ++cell_pair)
- Assert (!cell_pair->first->has_children()
+ Assert (cell_pair->first->active()
||
- !cell_pair->second->has_children(),
+ cell_pair->second->active()
+ ||
+ (cell_pair->first->refinement_case()
+ != cell_pair->second->refinement_case()),
ExcInternalError());
return cell_list;
// if both cells have children, we may
// recurse further into the hierarchy
if (src_cell->has_children() && dst_cell->has_children())
- for (unsigned int c=0; c<GeometryInfo<GridClass::dimension>::children_per_cell; ++c)
- set_mapping (src_cell->child(c),
- dst_cell->child(c));
+ {
+ Assert(src_cell->n_children()==
+ GeometryInfo<GridClass::dimension>::max_children_per_cell,
+ ExcNotImplemented());
+ Assert(dst_cell->n_children()==
+ GeometryInfo<GridClass::dimension>::max_children_per_cell,
+ ExcNotImplemented());
+ Assert(src_cell->refinement_case()==dst_cell->refinement_case(),
+ ExcNotImplemented());
+ for (unsigned int c=0; c<GeometryInfo<GridClass::dimension>::max_children_per_cell; ++c)
+ set_mapping (src_cell->child(c),
+ dst_cell->child(c));
+ }
else
if (src_cell->has_children() &&
!dst_cell->has_children())
#include <base/geometry_info.h>
#include <grid/grid_tools.h>
#include <grid/magic_numbers.h>
+#include <fe/mapping_q1.h>
#include <lac/vector.h>
#include <algorithm>
DEAL_II_NAMESPACE_OPEN
+// anonymous namespace for internal helper functions
+namespace{
+ // return, wheter a given @p cell will be
+ // coarsened, which is the case if all
+ // children are active and have their coarsen
+ // flag set. In case only part of the coarsen
+ // flags are set, remove them.
+ template <int dim>
+ bool cell_will_be_coarsened(const TriaIterator<dim, dealii::CellAccessor<dim> > &cell)
+ {
+ // only cells with children should be
+ // considered for coarsening
+
+ if (cell->has_children())
+ {
+ unsigned int children_to_coarsen=0;
+ const unsigned int n_children=cell->n_children();
+
+ for (unsigned int c=0; c<n_children; ++c)
+ if (cell->child(c)->active() &&
+ cell->child(c)->coarsen_flag_set())
+ ++children_to_coarsen;
+ if (children_to_coarsen==n_children)
+ return true;
+ else
+ for (unsigned int c=0; c<n_children; ++c)
+ if (cell->child(c)->active())
+ cell->child(c)->clear_coarsen_flag();
+ }
+ // no children, so no coarsening
+ // possible. however, no children also
+ // means that this cell will be in the same
+ // state as if it had children and was
+ // coarsened. So, what should we return -
+ // false or true?
+ // make sure we do not have to do this at
+ // all...
+ Assert(cell->has_children(), ExcInternalError());
+ // ... and then simply return false
+ return false;
+ }
+
+
+ // return, whether the face @p face_no of the
+ // given @p cell will be refined after the
+ // current refinement step, considering
+ // refine and coarsen flags and considering
+ // only those refinemnts that will be caused
+ // by the neighboring cell.
+
+ // this function is used on both active cells
+ // and cells with children. on cells with
+ // children it also of interest to know 'how'
+ // the face will be refined. thus there is an
+ // additional third argument @p
+ // expected_face_ref_case returning just
+ // that. be aware, that this vriable will
+ // only contain useful information if this
+ // function is called for an active cell.
+ //
+ // thus, this is an internal function, users
+ // should call one of the two alternatives
+ // following below.
+ template <int dim>
+ bool face_will_be_refined_by_neighbor_internal(const TriaIterator<dim, dealii::CellAccessor<dim> > &cell,
+ const unsigned int face_no,
+ RefinementCase<dim-1> &expected_face_ref_case)
+ {
+ // first of all: set the default value for
+ // expected_face_ref_case, which is no
+ // refinement at all
+ expected_face_ref_case=RefinementCase<dim-1>::no_refinement;
+
+ const typename Triangulation<dim>::cell_iterator neighbor=cell->neighbor(face_no);
+
+ // If we are at the boundary, there is no
+ // neighbor which could refine the face
+ if (neighbor.state()!=IteratorState::valid)
+ return false;
+
+ if (neighbor->has_children())
+ // if the neighbor is refined, he may be
+ // coarsened. if so, then it won't refine
+ // the face, no matter what else happens
+ if (cell_will_be_coarsened(neighbor))
+ return false;
+ else
+ // if the neighor is refined, then he
+ // is also refined at our current
+ // face. He will stay so without
+ // coarsening, so return true in that
+ // case.
+ {
+ expected_face_ref_case=cell->face(face_no)->refinement_case();
+ return true;
+ }
+
+ // now, the neighbor is not refined, but
+ // perhaps he will be
+ const RefinementCase<dim> nb_ref_flag=neighbor->refine_flag_set();
+ if (nb_ref_flag)
+ {
+ // now we need to know, which of the
+ // neighbors faces points towards us
+ const unsigned int neighbor_neighbor=cell->neighbor_face_no(face_no);
+ // check, whether the cell will be
+ // refined in a way that refines our
+ // face
+ const RefinementCase<dim-1> face_ref_case=
+ GeometryInfo<dim>::face_refinement_case(nb_ref_flag,
+ neighbor_neighbor,
+ neighbor->face_orientation(neighbor_neighbor),
+ neighbor->face_flip(neighbor_neighbor),
+ neighbor->face_rotation(neighbor_neighbor));
+ if (face_ref_case != RefinementCase<dim-1>::no_refinement)
+ {
+ const typename Triangulation<dim>::face_iterator neighbor_face=neighbor->face(neighbor_neighbor);
+ const int this_face_index=cell->face_index(face_no);
+
+ // there are still two basic
+ // possibilities here: the neighbor
+ // might be coarser or as coarse
+ // as we are
+ if (neighbor_face->index()==this_face_index)
+ // the neighbor is as coarse as
+ // we are and will be refined at
+ // the face of consideration, so
+ // return true
+ {
+ expected_face_ref_case = face_ref_case;
+ return true;
+ }
+ else
+ {
+
+ // the neighbor is coarser.
+ // this is the most complicated
+ // case. It might be, that the
+ // neighbor's face will be
+ // refined, but that we will
+ // not see this, as we are
+ // refined in a similar way.
+
+ // so, the neighbor's face must
+ // have children. check, if our
+ // cell's face is one of these
+ // (it could also be a
+ // grand_child)
+ for (unsigned int c=0; c<neighbor_face->n_children(); ++c)
+ if (neighbor_face->child_index(c)==this_face_index)
+ // if the flagged refine
+ // case of the face is a
+ // subset or the same as
+ // the current refine case,
+ // then the face, as seen
+ // from our cell, won't be
+ // refined by the neighbor
+ if ((neighbor_face->refinement_case() | face_ref_case)
+ == neighbor_face->refinement_case())
+ return false;
+ else
+ {
+ // if we are active, we
+ // must be an
+ // anisotropic child
+ // and the coming
+ // face_ref_case is
+ // isotropic. Thus,
+ // from our cell we
+ // will see exactly the
+ // opposite refine case
+ // that the face has
+ // now...
+ Assert(face_ref_case==RefinementCase<dim-1>::isotropic_refinement, ExcInternalError());
+ expected_face_ref_case = ~neighbor_face->refinement_case();
+ return true;
+ }
+
+ // so, obviously we were not
+ // one of the children, but a
+ // grandchild. This is only
+ // possible in 3d.
+ Assert(dim==3, ExcInternalError());
+ // In that case, however, no
+ // matter what the neighbor
+ // does, he won't be finer
+ // after the next refinement
+ // step.
+ return false;
+ }
+ }// if face will be refined
+ }// if neighbor is flagged for refinement
+
+ // no cases left, so the neighbor will not
+ // refine the face
+ return false;
+ }
+
+ // verison of above function for both active
+ // and non-active cells
+ template <int dim>
+ bool face_will_be_refined_by_neighbor(const TriaIterator<dim, dealii::CellAccessor<dim> > &cell,
+ const unsigned int face_no)
+ {
+ RefinementCase<dim-1> dummy = RefinementCase<dim-1>::no_refinement;
+ return face_will_be_refined_by_neighbor_internal(cell, face_no, dummy);
+ }
+
+ // version of above function for active cells
+ // only. Additionally returning the refine
+ // case (to come) of the face under
+ // consideration
+ template <int dim>
+ bool face_will_be_refined_by_neighbor(const TriaActiveIterator<dim, dealii::CellAccessor<dim> > &cell,
+ const unsigned int face_no,
+ RefinementCase<dim-1> &expected_face_ref_case)
+ {
+ return face_will_be_refined_by_neighbor_internal(cell, face_no,
+ expected_face_ref_case);
+ }
+
+}// end of anonymous namespace
+
+
template <int dim>
const StraightBoundary<dim>
Triangulation<dim>::straight_boundary = StraightBoundary<dim>();
Triangulation<dim>::Triangulation (const MeshSmoothing smooth_grid) :
Subscriptor (),
faces(NULL),
+ anisotropic_refinement(false),
smooth_grid(smooth_grid)
{
// set default boundary for all
// copy normal elements
- vertices = old_tria.vertices;
- vertices_used = old_tria.vertices_used;
- smooth_grid = old_tria.smooth_grid;
+ vertices = old_tria.vertices;
+ vertices_used = old_tria.vertices_used;
+ anisotropic_refinement = old_tria.anisotropic_refinement;
+ smooth_grid = old_tria.smooth_grid;
faces = new internal::Triangulation::TriaFaces<dim>(*old_tria.faces);
// reserve enough space
levels.push_back (new internal::Triangulation::TriaLevel<dim>);
levels[0]->reserve_space (cells.size(), dim);
- levels[0]->cells.reserve_space (cells.size());
+ levels[0]->cells.reserve_space (0,cells.size());
// make up cells
raw_line_iterator next_free_line = begin_raw_line ();
levels.push_back (new internal::Triangulation::TriaLevel<dim>);
faces = new internal::Triangulation::TriaFaces<dim>;
levels[0]->reserve_space (cells.size(), dim);
- faces->lines.reserve_space (needed_lines.size());
- levels[0]->cells.reserve_space (cells.size());
+ faces->lines.reserve_space (0,needed_lines.size());
+ levels[0]->cells.reserve_space (0,cells.size());
// make up lines
if (true)
levels.push_back (new internal::Triangulation::TriaLevel<dim>);
faces = new internal::Triangulation::TriaFaces<dim>;
levels[0]->reserve_space (cells.size(), dim);
- faces->lines.reserve_space (needed_lines.size());
+ faces->lines.reserve_space (0,needed_lines.size());
// make up lines
if (true)
// the arrays of the Triangulation
//
// first reserve enough space
- faces->quads.reserve_space (needed_quads.size());
+ faces->quads.reserve_space (0,needed_quads.size());
if (true)
{
template <int dim>
void Triangulation<dim>::save_refine_flags (std::vector<bool> &v) const
{
- v.resize (n_active_cells(), false);
+ v.resize (dim*n_active_cells(), false);
std::vector<bool>::iterator i = v.begin();
active_cell_iterator cell = begin_active(),
endc = end();
- for (; cell!=endc; ++cell, ++i)
- *i = cell->refine_flag_set();
+ for (; cell!=endc; ++cell)
+ for (unsigned int j=0; j<dim; ++j,++i)
+ if (cell->refine_flag_set() & (1<<j) )
+ *i = true;
}
template <int dim>
void Triangulation<dim>::load_refine_flags (const std::vector<bool> &v)
{
- AssertThrow (v.size() == n_active_cells(), ExcGridReadError());
+ AssertThrow (v.size() == dim*n_active_cells(), ExcGridReadError());
active_cell_iterator cell = begin_active(),
endc = end();
std::vector<bool>::const_iterator i = v.begin();
- for (; cell!=endc; ++cell, ++i)
- if (*i == true)
- cell->set_refine_flag();
- else
- cell->clear_refine_flag();
+ for (; cell!=endc; ++cell)
+ {
+ unsigned int ref_case=0;
+
+ for(unsigned int j=0; j<dim; ++j, ++i)
+ if (*i == true)
+ ref_case+=1<<j;
+ Assert(ref_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcGridReadError());
+ if (ref_case>0)
+ cell->set_refine_flag(RefinementCase<dim>(ref_case));
+ else
+ cell->clear_refine_flag();
+ }
}
}
+template <int dim>
+bool Triangulation<dim>::get_anisotropic_refinement_flag() const
+{
+ return anisotropic_refinement;
+}
+
+
#if deal_II_dimension == 1
template <>
template <>
-void Triangulation<1>::clear_user_flags ()
+void Triangulation<1>::clear_user_flags_line ()
{
- clear_user_flags_line();
+ for (unsigned int level=0; level<levels.size(); ++level)
+ levels[level]->cells.clear_user_flags();
}
{}
+
template <>
void Triangulation<1>::clear_user_flags_hex ()
{}
+
+template <>
+void Triangulation<1>::clear_user_flags ()
+{
+ clear_user_flags_line();
+}
+
#endif
template <>
-void Triangulation<2>::clear_user_flags ()
+void Triangulation<2>::clear_user_flags_quad ()
{
- clear_user_flags_line ();
- clear_user_flags_quad ();
+ for (unsigned int level=0; level<levels.size(); ++level)
+ levels[level]->cells.clear_user_flags();
}
{}
+
+template <>
+void Triangulation<2>::clear_user_flags ()
+{
+ clear_user_flags_line ();
+ clear_user_flags_quad ();
+}
+
#endif
template <>
-void Triangulation<3>::clear_user_flags ()
+void Triangulation<3>::clear_user_flags_quad ()
{
- clear_user_flags_line ();
- clear_user_flags_quad ();
- clear_user_flags_hex ();
+ faces->quads.clear_user_flags();
}
-#endif
-
-
-template <int dim>
-void Triangulation<dim>::clear_user_flags_line ()
+template <>
+void Triangulation<3>::clear_user_flags_hex ()
{
- line_iterator line = begin_line(),
- endl = end_line();
- for (; line!=endl; ++line)
- line->clear_user_flag ();
+ for (unsigned int level=0; level<levels.size(); ++level)
+ levels[level]->cells.clear_user_flags();
}
-template <int dim>
-void Triangulation<dim>::clear_user_flags_quad ()
+template <>
+void Triangulation<3>::clear_user_flags ()
{
- quad_iterator quad = begin_quad(),
- endq = end_quad();
- for (; quad!=endq; ++quad)
- quad->clear_user_flag ();
+ clear_user_flags_line ();
+ clear_user_flags_quad ();
+ clear_user_flags_hex ();
}
+#endif
+
+#if deal_II_dimension > 1
template <int dim>
-void Triangulation<dim>::clear_user_flags_hex ()
+void Triangulation<dim>::clear_user_flags_line ()
{
- hex_iterator hex = begin_hex(),
- endh = end_hex();
- for (; hex!=endh; ++hex)
- hex->clear_user_flag ();
+ faces->lines.clear_user_flags();
}
+#endif
+
+
template <int dim>
// created on that level
levels[level+1]->reserve_space(
used_cells+
- GeometryInfo<1>::children_per_cell * flagged_cells, 1);
+ GeometryInfo<1>::max_children_per_cell * flagged_cells, 1);
// reserve space for
// 2*flagged_cells new lines on
+ // the next higher level to be
+ // stored in pairs
// the next higher level
levels[level+1]->cells.
- reserve_space (GeometryInfo<1>::children_per_cell*flagged_cells);
+ reserve_space (GeometryInfo<1>::max_children_per_cell*flagged_cells, 0);
needed_vertices += flagged_cells;
}
second_child->clear_user_data ();
// insert first child
- cell->set_children (first_child->index());
+ cell->set_children (0, first_child->index());
first_child->clear_children ();
first_child->set (internal::Triangulation
::TriaObject<1> (cell->vertex_index(0),
}
- // first clear user flags for
- // lines; we're going to use them
- // to flag which lines need
- // refinement
+ // first clear user flags and
+ // pointers of lines; we're going
+ // to use them to flag which lines
+ // need refinement
for (line_iterator line=begin_line(); line!=end_line(); ++line)
- line->clear_user_flag();
+ {
+ line->clear_user_flag();
+ line->clear_user_data();
+ }
+ // running over all cells and lines
+ // count the number
+ // n_single_lines of lines
+ // which can be stored as
+ // single lines, e.g. inner lines
+ unsigned int n_single_lines=0;
+ // New lines to be created:
+ // number lines which are
+ // stored in pairs (the
+ // children of lines must be
+ // stored in pairs)
+ unsigned int n_lines_in_pairs = 0;
// check how much space is needed
// on every level we need not check
// - there are, but prepare_refinement
// added another empty level
unsigned int needed_vertices = 0;
- unsigned int needed_lines = 0;
for (int level=levels.size()-2; level>=0; --level)
{
// count number of flagged
// compute how many new
// vertices and new lines will
// be needed
- unsigned int flagged_cells = 0;
+ unsigned int needed_cells = 0;
+
active_cell_iterator cell = begin_active(level),
endc = begin_active(level+1);
for (; cell!=endc; ++cell)
if (cell->refine_flag_set())
{
- ++flagged_cells;
+ if (cell->refine_flag_set()==RefinementCase<dim>::cut_xy)
+ {
+ needed_cells += 4;
+
+ // new vertex at
+ // center of cell is
+ // needed in any case
+ ++needed_vertices;
+ // the four inner
+ // lines can be
+ // stored as singles
+ n_single_lines += 4;
+ }
+ else // cut_x || cut_y
+ {
+ // set the flag showing that
+ // anisotropic refinement is
+ // used for at least one cell
+ anisotropic_refinement=true;
+
+ needed_cells += 2;
+ // no vertex at center
+
+ // the inner line can
+ // be stored as
+ // single
+ n_single_lines += 1;
- // new vertex at center
- // of cell is needed in
- // any case
- ++needed_vertices;
- // also the four inner
- // lines
- needed_lines += 4;
+ }
- // mark all faces (lines)
- // for refinement;
- // checking locally
- // whether the neighbor
- // would also like to
- // refine them is rather
- // difficult for lines so
- // we only flag them and
- // after visiting all
- // cells, we decide which
- // lines need refinement;
+ // mark all faces
+ // (lines) for
+ // refinement;
+ // checking locally
+ // whether the
+ // neighbor would
+ // also like to
+ // refine them is
+ // rather difficult
+ // for lines so we
+ // only flag them and
+ // after visiting all
+ // cells, we decide
+ // which lines need
+ // refinement;
for (unsigned int line_no=0; line_no<GeometryInfo<dim>::faces_per_cell;
++line_no)
{
- line_iterator line = cell->line(line_no);
-
- if (line->has_children() == false)
- line->set_user_flag ();
+ if (GeometryInfo<dim>::face_refinement_case(
+ cell->refine_flag_set(), line_no)==RefinementCase<dim>::cut_x)
+ {
+ line_iterator line = cell->line(line_no);
+ if (line->has_children() == false)
+ line->set_user_flag ();
+ }
}
}
-
// count number of used cells
// on the next higher level
const unsigned int used_cells
// used_cells cells already
// existing on the next higher
// level as well as for the
- // 4*flagged_cells that will be
+ // needed_cells that will be
// created on that level
- levels[level+1]->reserve_space (used_cells+4*flagged_cells, 2);
+ levels[level+1]->reserve_space (used_cells+needed_cells, 2);
// reserve space for
- // 4*flagged_cells
+ // needed_cells
// new quads on the next higher
// level
levels[level+1]->cells.
- reserve_space (4*flagged_cells);
+ reserve_space (needed_cells,0);
}
// now count the lines which
if (line->user_flag_set())
{
Assert (line->has_children() == false, ExcInternalError());
- needed_lines += 2;
- needed_vertices += 1;
+ n_lines_in_pairs += 2;
+ needed_vertices += 1;
}
-
// reserve space for
- // needed_lines new lines
+ // n_lines_in_pairs new lines.
+ // note, that we can't reserve space
+ // for the single lines here as well,
+ // as all the space reserved for lines
+ // in pairs would be counted as unused
+ // and we would end up with too little
+ // space to store all lines. memory
+ // reservation for n_single_lines can
+ // only be done AFTER we refined the lines
+ // of the current cells
faces->lines.
- reserve_space (needed_lines);
+ reserve_space (n_lines_in_pairs, 0);
// add to needed vertices how many
// vertices are already in use
// index of next unused vertex
unsigned int next_unused_vertex = 0;
- // first for lines
- //
- // only active objects can be
- // refined further
+ // first the refinement of lines.
+ // children are stored pairwise
if (true)
{
+ // only active objects can be
+ // refined further
active_line_iterator line = begin_active_line(),
endl = end_line();
raw_line_iterator next_unused_line = begin_raw_line ();
-
+
for (; line!=endl; ++line)
if (line->user_flag_set())
{
// now that we created
// the right point, make
- // up the two child lines
- // (++ takes care of the
- // end of the vector)
- while (next_unused_line->used() == true)
- ++next_unused_line;
- // there should always be
- // two consecutive unused
+ // up the two child
+ // lines. To this end,
+ // find a pair of unused
+ // lines
+ bool pair_found=false;
+ for (; next_unused_line!=endl; ++next_unused_line)
+ if (!next_unused_line->used() &&
+ !(++next_unused_line)->used())
+ {
+ // go back to the
+ // first of the two
+ // unused lines
+ --next_unused_line;
+ pair_found=true;
+ break;
+ }
+ Assert (pair_found, ExcInternalError());
+
+ // there are now two
+ // consecutive unused
// lines, such that the
// children of a line
// will be consecutive.
// then set the child
// pointer of the present
// line
- line->set_children (next_unused_line->index());
+ line->set_children (0, next_unused_line->index());
// set the two new lines
- raw_line_iterator children[2] = { next_unused_line,
- ++next_unused_line };
+ const raw_line_iterator children[2] = { next_unused_line,
+ ++next_unused_line };
// some tests; if any of
// the iterators should
// be invalid, then
}
}
+
// Now set up the new cells
+
+ // reserve space for inner
+ // lines (can be stored as
+ // single lines)
+ faces->lines.
+ reserve_space (0,n_single_lines);
+
+ // reset next_unused_line, as
+ // now also single empty places
+ // in the vector can be used
+ raw_line_iterator next_unused_line = begin_raw_line ();
+ // dummy argument needed for the call to
+ // create_children()
+ raw_quad_iterator dummy_quad;
+
for (int level=0; level<static_cast<int>(levels.size())-1; ++level)
{
+ // Remember: as we don't operate
+ // on the finest level, begin_*(level+1)
+ // is allowed
active_cell_iterator cell = begin_active(level),
endc = begin_active(level+1);
- raw_line_iterator next_unused_line = begin_raw_line ();
raw_cell_iterator next_unused_cell = begin_raw (level+1);
for (; cell!=endc; ++cell)
if (cell->refine_flag_set())
{
- // clear refinement flag
- cell->clear_refine_flag ();
-
- // do some additional
- // checks.
-#ifdef DEBUG
- for (unsigned int neighbor=0;
- neighbor<GeometryInfo<dim>::faces_per_cell; ++neighbor)
- if (cell->neighbor(neighbor).state() == IteratorState::valid)
- Assert (((cell->neighbor(neighbor)->level() == cell->level()) &&
- (cell->neighbor(neighbor)->coarsen_flag_set() == false)) ||
- ((cell->neighbor(neighbor)->level() == cell->level()-1) &&
- (cell->neighbor(neighbor)->refine_flag_set() == true)),
- ExcInternalError());
-#endif
+ // set the user flag to
+ // indicate, that at least one
+ // line is at the boundary
-/* For the refinement process: since we go the levels up from the lowest, there
- are (unlike above) only two possibilities: a neighbor cell is on the same
- level or one level up (in both cases, it may or may not be refined later on,
- but we don't care here).
-
- First:
- Set up an array of the 3x3 vertices, which are distributed on the cell
- (the array consists of indices into the @p{vertices} std::vector
-
- 2--7--3
- | | |
- 4--8--5
- | | |
- 0--6--1
-
- Second:
- Set up an array of the new lines (the array consists of iterator pointers
- into the lines arrays)
-
- .-6-.-7-. The directions are: .->-.->-.
- 1 9 3 ^ ^ ^
- .-10.11-. .->-.->-.
- 0 8 2 ^ ^ ^
- .-4-.-5-. .->-.->-.
+ // TODO[Tobias Leicht] find a
+ // better place to set this flag,
+ // so that we do not need so much
+ // time to check each cell here
+ if (cell->at_boundary())
+ cell->set_user_flag();
+
+ // actually set up the children and
+ // update neighbor information
+ create_children(next_unused_vertex,
+ next_unused_line,
+ dummy_quad,
+ next_unused_cell,
+ cell);
+ }
+ }
-
- Third:
- Set up an array of neighbors:
-
- 6 7
- .--.--.
- 1| | |3
- .--.--.
- 0| | |2
- .--.--.
- 4 5
+ // re-compute number of lines and
+ // quads
+ update_number_cache ();
- We need this array for two reasons: first to get the lines which will
- bound the four subcells (if the neighboring cell is refined, these
- lines already exist), and second to update neighborship information.
- Since if a neighbor is not refined, its neighborship record only
- points to the present, unrefined, cell rather than the children we
- are presently creating, we only need the neighborship information
- if the neighbor cells are refined. In all other cases, we store
- the unrefined neighbor address
- We also need for every neighbor (if refined) which number among its
- neighbors the present (unrefined) cell has, since that number is to
- be replaced and because that also is the number of the subline which
- will be the interface between that neighbor and the to be created cell.
- We will store this number (between 0 and 3) in the field
- @p{neighbors_neighbor}.
+#ifdef DEBUG
+ for (unsigned int level=0; level<levels.size(); ++level)
+ levels[level]->cells.monitor_memory (2);
- It would be sufficient to use the children of the common line to the
- neighbor, if we only wanted to get the new sublines and the new vertex,
- but because we need to update the neighborship information of the
- two refined subcells of the neighbor, we need to search these anyway.
+ // check whether really all
+ // refinement flags are reset (also
+ // of previously non-active cells
+ // which we may not have
+ // touched. If the refinement flag
+ // of a non-active cell is set,
+ // something went wrong since the
+ // cell-accessors should have
+ // caught this)
+ line_iterator line = begin_line(),
+ endl = end_line();
+ while (line != endl)
+ Assert (!(line++)->user_flag_set(), ExcInternalError ());
- Convention:
- The created children are numbered like this:
+ cell_iterator cell = begin(),
+ endc = end();
+ while (cell != endc)
+ Assert (!(cell++)->refine_flag_set(), ExcInternalError ());
+#endif
+}
- .--.--.
- |2 . 3|
- .--.--.
- |0 | 1|
- .--.--.
-*/
-
- // find the next unused
- // vertex and set it
- // appropriately
- while (vertices_used[next_unused_vertex] == true)
- ++next_unused_vertex;
- Assert (next_unused_vertex < vertices.size(),
- ExcTooFewVerticesAllocated());
- vertices_used[next_unused_vertex] = true;
+#endif
- // collect the indices
- // all vertices
- int new_vertices[9] = {cell->vertex_index(0),
- cell->vertex_index(1),
- cell->vertex_index(2),
- cell->vertex_index(3),
- cell->line(0)->child(0)->vertex_index(1),
- cell->line(1)->child(0)->vertex_index(1),
- cell->line(2)->child(0)->vertex_index(1),
- cell->line(3)->child(0)->vertex_index(1),
- next_unused_vertex};
-
- // new vertex is placed
- // at the arithmetic mean
- // of all 8 neighboring
- // points.
- Point<2> new_point(0,0);
- for (unsigned int i=0; i<8; ++i)
- new_point += vertices[new_vertices[i]];
- new_point /= 8.0;
-
- vertices[new_vertices[8]] = new_point;
-
- // Now the lines:
-
- // lines 0-7 already
- // exist, create only the
- // four interior lines
- // 8-11
- raw_line_iterator new_lines[12];
- unsigned int l=0;
- for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell;
- ++face_no)
- for (unsigned int child_no=0;
- child_no<GeometryInfo<dim>::subfaces_per_face; ++child_no, ++l)
- new_lines[l]=cell->line(face_no)->child(child_no);
- Assert(l==8, ExcInternalError());
-
- for (; l<12; ++l)
- {
- while (next_unused_line->used() == true)
- ++next_unused_line;
- new_lines[l] = next_unused_line;
- ++next_unused_line;
- Assert (new_lines[l]->used() == false,
- ExcCellShouldBeUnused());
- }
+#if deal_II_dimension == 3
- new_lines[8] ->set (internal::Triangulation
- ::TriaObject<1>(new_vertices[6], new_vertices[8]));
- new_lines[9] ->set (internal::Triangulation
- ::TriaObject<1>(new_vertices[8], new_vertices[7]));
- new_lines[10]->set (internal::Triangulation
- ::TriaObject<1>(new_vertices[4], new_vertices[8]));
- new_lines[11]->set (internal::Triangulation
- ::TriaObject<1>(new_vertices[8], new_vertices[5]));
-
- for (l=8; l<12; ++l)
- {
- new_lines[l]->set_used_flag();
- new_lines[l]->clear_user_flag();
- new_lines[l]->clear_user_data();
- new_lines[l]->clear_children();
- // interior line
- new_lines[l]->set_boundary_indicator(255);
- }
-
- // Now add the four new
- // cells!
-
- // search for next unused
- // cell the four children
- // have to be put into
- // the array
- // consecutively
- while (next_unused_cell->used() == true)
- ++next_unused_cell;
-
- const unsigned int n_children=GeometryInfo<dim>::children_per_cell;
- raw_cell_iterator subcells[n_children];
- for (unsigned int i=0; i<n_children; ++i)
- {
- Assert (next_unused_cell->used() == false,
- ExcCellShouldBeUnused());
- subcells[i] = next_unused_cell;
- ++next_unused_cell;
- }
-
-
- cell->set_children (subcells[0]->index());
-
- Assert(n_children==4, ExcNotImplemented());
- subcells[0]->set (internal::Triangulation
- ::TriaObject<2> (new_lines[0]->index(),
- new_lines[8]->index(),
- new_lines[4]->index(),
- new_lines[10]->index()));
- subcells[1]->set (internal::Triangulation
- ::TriaObject<2> (new_lines[8]->index(),
- new_lines[2]->index(),
- new_lines[5]->index(),
- new_lines[11]->index()));
- subcells[2]->set (internal::Triangulation
- ::TriaObject<2> (new_lines[1]->index(),
- new_lines[9]->index(),
- new_lines[10]->index(),
- new_lines[6]->index()));
- subcells[3]->set (internal::Triangulation
- ::TriaObject<2> (new_lines[9]->index(),
- new_lines[3]->index(),
- new_lines[11]->index(),
- new_lines[7]->index()));
-
- for (unsigned int i=0; i<n_children; ++i)
- {
- subcells[i]->set_used_flag();
- subcells[i]->clear_user_flag();
- subcells[i]->clear_user_data();
- subcells[i]->clear_children();
- // inherit material
- // properties
- subcells[i]->set_material_id (cell->material_id());
- subcells[i]->set_subdomain_id (cell->subdomain_id());
- }
-
- // now the only thing
- // still to be done is
- // setting neighborship
- // information.
- //
- // to do so, first
- // collect the iterators
- // pointing to the 4x2
- // neighbors of this
- // cell.
- //
- // note that in case the
- // neighboring cell is
- // not refined, the
- // neighbor iterators
- // point to the common
- // mother cell. the same
- // applies if there is no
- // neighbor: the
- // iterators are past the
- // end
- cell_iterator neighbor_cells[n_children][2];
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell;
- ++face)
- {
- const cell_iterator neighbor = cell->neighbor(face);
-
- // if no neighbor
- if (neighbor.state() != IteratorState::valid)
- for (unsigned int child_face=0;
- child_face<GeometryInfo<dim>::subfaces_per_face;
- ++child_face)
- neighbor_cells[face][child_face] = neighbor;
-
- else
- // neighbor exists
- {
- // neighbor's
- // level must not
- // be higher
- // (else
- // something went
- // wrong when
- // constructing
- // either of the
- // two cells) and
- // not lower
- // since then
- // this cell
- // should not
- // have been
- // refined.
- Assert (neighbor->level() == cell->level(),
- ExcInternalError());
-
- // now there are
- // two
- // possibilities:
- // either the
- // neighbor has
- // no children or
- // it has
- // children. these
- // must be
- // terminal then.
- if (!neighbor->has_children())
- for (unsigned int child_face=0;
- child_face<GeometryInfo<dim>::subfaces_per_face;
- ++child_face)
- neighbor_cells[face][child_face] = neighbor;
- else
- // neighbor has
- // children
- {
- // first find
- // the face
- // of the
- // neighbor
- // adjacent
- // to which
- // the
- // present
- // cell is
- const unsigned int nb_nb = cell->neighbor_of_neighbor(face);
- Assert (nb_nb<GeometryInfo<dim>::faces_per_cell,
- ExcInternalError());
-
- // and set
- // the
- // neighbors
- // accordingly
- for (unsigned int c=0;
- c<GeometryInfo<dim>::subfaces_per_face; ++c)
- {
- neighbor_cells[face][c]
- = neighbor->child(GeometryInfo<dim>::
- child_cell_on_face(nb_nb, c));
-
- Assert (neighbor_cells[face][c].state() ==
- IteratorState::valid,
- ExcInternalError());
- Assert (!neighbor_cells[face][c]->has_children(),
- ExcInternalError());
- }
- }
- }
- }
-
- // now we've got all
- // neighbors, so set them
- // in the new cells
- subcells[0]->set_neighbor (0, neighbor_cells[0][0]);
- subcells[0]->set_neighbor (1, subcells[1]);
- subcells[0]->set_neighbor (2, neighbor_cells[2][0]);
- subcells[0]->set_neighbor (3, subcells[2]);
-
- subcells[1]->set_neighbor (0, subcells[0]);
- subcells[1]->set_neighbor (1, neighbor_cells[1][0]);
- subcells[1]->set_neighbor (2, neighbor_cells[2][1]);
- subcells[1]->set_neighbor (3, subcells[3]);
-
- subcells[2]->set_neighbor (0, neighbor_cells[0][1]);
- subcells[2]->set_neighbor (1, subcells[3]);
- subcells[2]->set_neighbor (2, subcells[0]);
- subcells[2]->set_neighbor (3, neighbor_cells[3][0]);
-
- subcells[3]->set_neighbor (0, subcells[2]);
- subcells[3]->set_neighbor (1, neighbor_cells[1][1]);
- subcells[3]->set_neighbor (2, subcells[1]);
- subcells[3]->set_neighbor (3, neighbor_cells[3][1]);
-
- // now we need to set the
- // neighbors' neighborship
- // information; this is
- // only necessary if the
- // neighboring cell is
- // refined, i.e. is on
- // the same level as the
- // new children of the
- // present cell
- for (unsigned int nb=0; nb<GeometryInfo<dim>::faces_per_cell; ++nb)
- for (unsigned int subface=0;
- subface<GeometryInfo<dim>::subfaces_per_face; ++subface)
- if ((neighbor_cells[nb][subface].state() ==
- IteratorState::valid) &&
- (neighbor_cells[nb][subface]->level() ==
- cell->level()+1))
- {
- // ok, the
- // neighbor is a
- // refined one
- // and we need to
- // set one of the
- // new children
- // as its
- // neighbor
- const cell_iterator neighbor = neighbor_cells[nb][subface];
-
- // find which
- // neighbor
- // pointer is to
- // be reset; this
- // pointer still
- // points to the
- // present cell
- unsigned int face;
- for (face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if (neighbor->neighbor(face) == cell)
- break;
-
- Assert (face<GeometryInfo<dim>::faces_per_cell,
- ExcInternalError());
-
- neighbor->set_neighbor(face, subcells[
- GeometryInfo<dim>::child_cell_on_face(nb, subface)]);
- }
-
- // note that the
- // refinement flag was
- // already cleared at the
- // beginning of this loop
-
- }
- }
-
- // re-compute number of lines and
- // quads
- update_number_cache ();
-
-
-#ifdef DEBUG
- for (unsigned int level=0; level<levels.size(); ++level)
- levels[level]->cells.monitor_memory (2);
-
- // check whether really all
- // refinement flags are reset (also
- // of previously non-active cells
- // which we may not have
- // touched. If the refinement flag
- // of a non-active cell is set,
- // something went wrong since the
- // cell-accessors should have
- // caught this)
- line_iterator line = begin_line(),
- endl = end_line();
- while (line != endl)
- Assert (!(line++)->user_flag_set(), ExcInternalError ());
-
- cell_iterator cell = begin(),
- endc = end();
- while (cell != endc)
- Assert (!(cell++)->refine_flag_set(), ExcInternalError ());
-#endif
-}
-
-#endif
-
-
-#if deal_II_dimension == 3
-
-template <>
-void
-Triangulation<3>::execute_refinement ()
-{
- const unsigned int dim = 3;
+template <>
+void
+Triangulation<3>::execute_refinement ()
+{
+ const unsigned int dim = 3;
// check whether a new level is
// needed we have to check for this
// and lines; we're going to use them
// to flag which lines and quads
// need refinement
+ faces->quads.clear_user_data();
+
for (line_iterator line=begin_line(); line!=end_line(); ++line)
line->clear_user_flag();
for (quad_iterator quad=begin_quad(); quad!=end_quad(); ++quad)
- quad->clear_user_flag();
-
-
+ {
+ quad->clear_user_flag();
+ }
+ // create an array of face refine cases. User
+ // indices of faces will be set to values
+ // corresponding with indices in this array.
+ const RefinementCase<dim-1> face_refinement_cases[4]=
+ {RefinementCase<dim-1>::no_refinement,
+ RefinementCase<dim-1>::cut_x,
+ RefinementCase<dim-1>::cut_y,
+ RefinementCase<dim-1>::cut_xy};
+
// check how much space is needed
// on every level
// we need not check the highest
// - there are, but prepare_refinement
// added another empty level which
// then is the highest level
+
+ // variables to hold the number of newly to
+ // be created vertices, lines and quads. as
+ // these are stored globally, declare them
+ // outside the loop over al levels. we need
+ // lines and quads in pairs for refinement of
+ // old ones and lines and quads, that can be
+ // stored as single ones, as they are newly
+ // created in the inside of an existing cell
unsigned int needed_vertices = 0;
- unsigned int needed_lines = 0;
- unsigned int needed_quads = 0;
- int level;
- for (level=levels.size()-2; level>=0; --level)
+ unsigned int needed_lines_single = 0;
+ unsigned int needed_quads_single = 0;
+ unsigned int needed_lines_pair = 0;
+ unsigned int needed_quads_pair = 0;
+ for (int level=levels.size()-2; level>=0; --level)
{
// count number of flagged
// cells on this level and
// compute how many new
// vertices and new lines will
// be needed
- unsigned int flagged_cells = 0;
-
+ unsigned int new_cells = 0;
active_cell_iterator acell = begin_active(level),
aendc = begin_active(level+1);
for (; acell!=aendc; ++acell)
if (acell->refine_flag_set())
{
- ++flagged_cells;
-
- // new vertex at center
- // of cell is needed in
+ RefinementCase<dim> ref_case=acell->refine_flag_set();
+
+ // now for interior vertices, lines
+ // and quads, which are needed in
// any case
- ++needed_vertices;
- // also the six inner
- // lines
- needed_lines += 6;
- // and the 12 inner quads
- needed_quads += 12;
+ if (ref_case==RefinementCase<dim>::cut_x ||
+ ref_case==RefinementCase<dim>::cut_y ||
+ ref_case==RefinementCase<dim>::cut_z)
+ {
+ ++needed_quads_single;
+ new_cells+=2;
+ anisotropic_refinement=true;
+ }
+ else if (ref_case==RefinementCase<dim>::cut_xy ||
+ ref_case==RefinementCase<dim>::cut_xz ||
+ ref_case==RefinementCase<dim>::cut_yz)
+ {
+ ++needed_lines_single;
+ needed_quads_single += 4;
+ new_cells+=4;
+ anisotropic_refinement=true;
+ }
+ else if (ref_case==RefinementCase<dim>::cut_xyz)
+ {
+ ++needed_vertices;
+ needed_lines_single += 6;
+ needed_quads_single += 12;
+ new_cells+=8;
+ }
+ else
+ {
+ // we should never get here
+ Assert(false, ExcInternalError());
+ }
- // mark all faces and
- // lines for refinement;
+ // mark all faces for refinement;
// checking locally
- // whether the neighbor
- // would also like to
- // refine them is rather
- // difficult for lines so
+ // if and how the neighbor
+ // would like to
+ // refine these is
+ // difficult so
// we only flag them and
// after visiting all
// cells, we decide which
- // lines need refinement;
- // same for the quads
+ // faces need which refinement;
for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell;
++face)
{
face_iterator aface = acell->face(face);
+ // get the RefineCase this
+ // faces has for the given
+ // RefineCase of the cell
+ RefinementCase<dim-1> face_ref_case=
+ GeometryInfo<dim>::face_refinement_case(ref_case,
+ face,
+ acell->face_orientation(face),
+ acell->face_flip(face),
+ acell->face_rotation(face));
+ // only do something, if this
+ // face has to be refined
+ if (face_ref_case)
+ if (face_ref_case==RefinementCase<dim-1>::isotropic_refinement)
+ {
+ if (aface->number_of_children()<4)
+ // we use user_flags to
+ // denote needed isotropic
+ // refinement
+ aface->set_user_flag();
+ }
+ else if (aface->refinement_case()!=face_ref_case)
+ // we use user_indices
+ // to denote needed
+ // anisotropic
+ // refinement. note, that
+ // we can have at most
+ // one anisotropic
+ // refinement case for
+ // this face, as
+ // otherwise
+ // prepare_refinement()
+ // would have changed one
+ // of the cells to yield
+ // isotropic refinement
+ // at this
+ // face. therefore we set
+ // the user_index
+ // uniquely
+ {
+ Assert(aface->refinement_case()==RefinementCase<dim-1>::isotropic_refinement ||
+ aface->refinement_case()==RefinementCase<dim-1>::no_refinement,
+ ExcInternalError());
+ aface->set_user_index(face_ref_case);
+ }
+ }// for all faces
+
+ // flag all lines, that have to be
+ // refined
+ for (unsigned int line=0; line<GeometryInfo<dim>::lines_per_cell; ++line)
+ if (GeometryInfo<dim>::line_refinement_case(ref_case,line) &&
+ !acell->line(line)->has_children())
+ acell->line(line)->set_user_flag();
- if (aface->has_children() == false)
- {
- aface->set_user_flag ();
- for (unsigned int line=0; line<4; ++line)
- if (aface->line(line)->has_children() == false)
- aface->line(line)->set_user_flag ();
- }
- }
- }
+ }// if refine_flag set and for all cells on this level
+
// count number of used cells on
// the next higher level
// level as well as for the
// 8*flagged_cells that will be
// created on that level
- levels[level+1]->reserve_space (used_cells+8*flagged_cells, 3);
+ levels[level+1]->reserve_space (used_cells+new_cells, 3);
// reserve space for
// 8*flagged_cells
// new hexes on the next higher
// level
- levels[level+1]->cells.reserve_space (8*flagged_cells);
- }
-
+ levels[level+1]->cells.reserve_space (new_cells);
+ }// for all levels
// now count the quads and
// lines which were flagged for
// refinement
for (quad_iterator quad=begin_quad(); quad!=end_quad(); ++quad)
- if (quad->user_flag_set())
- {
- Assert (quad->has_children() == false, ExcInternalError());
- needed_quads += 4;
- needed_lines += 4;
- needed_vertices += 1;
- }
+ {
+ if (quad->user_flag_set())
+ {
+ // isotropic refinement: 1 interior
+ // vertex, 4 quads and 4 interior
+ // lines. we store the interior lines
+ // in pairs in case the face is
+ // already or will be refined
+ // anisotropically
+ needed_quads_pair += 4;
+ needed_lines_pair += 4;
+ needed_vertices += 1;
+ }
+ if (quad->user_index())
+ {
+ // anisotropic refinement: 1 interior
+ // line and two quads
+ needed_quads_pair += 2;
+ needed_lines_single += 1;
+ // there is a kind of complicated
+ // situation here which requires our
+ // attention. if the quad is refined
+ // isotropcally, two of the interior
+ // lines will get a new mother line -
+ // the interior line of our
+ // anisotropically refined quad. if
+ // those two lines are not
+ // consecutive, we cannot do so and
+ // have to replace them by two lines
+ // that are consecutive. we try to
+ // avoid that situation, but it may
+ // happen nevertheless throug
+ // repeated refinement and
+ // coarsening. thus we have to check
+ // here, as we will need some
+ // additional space to store those
+ // new lines in case we need them...
+ if (quad->has_children())
+ {
+ Assert(quad->refinement_case()==RefinementCase<dim-1>::isotropic_refinement, ExcInternalError());
+ if ((face_refinement_cases[quad->user_index()]==RefinementCase<dim-1>::cut_x
+ && (quad->child(0)->line_index(1)+1!=quad->child(2)->line_index(1))) ||
+ (face_refinement_cases[quad->user_index()]==RefinementCase<dim-1>::cut_y
+ && (quad->child(0)->line_index(3)+1!=quad->child(1)->line_index(3))))
+ needed_lines_pair +=2;
+ }
+ }
+ }
for (line_iterator line=begin_line(); line!=end_line(); ++line)
if (line->user_flag_set())
{
- Assert (line->has_children() == false, ExcInternalError());
- needed_lines += 2;
+ needed_lines_pair += 2;
needed_vertices += 1;
}
// reserve space for
// needed_lines new lines
+ // stored in pairs
faces->lines.
- reserve_space (needed_lines);
+ reserve_space (needed_lines_pair,needed_lines_single);
// reserve space for
// needed_quads new quads
+ // stored in pairs
faces->quads.
- reserve_space (needed_quads);
+ reserve_space (needed_quads_pair,needed_quads_single);
+
// add to needed vertices how many
// vertices are already in use
unsigned int next_unused_vertex = 0;
// first for lines
- // only active objects can be
- // refined further;
if (true)
{
+ // only active objects can be
+ // refined further
active_line_iterator line = begin_active_line(),
endl = end_line();
raw_line_iterator next_unused_line = begin_raw_line ();
-
for (; line!=endl; ++line)
if (line->user_flag_set())
// up the two child lines
// (++ takes care of the
// end of the vector)
- while (next_unused_line->used() == true)
- ++next_unused_line;
- // there should always be
+ next_unused_line=faces->lines.next_free_pair_line(*this);
+ Assert(next_unused_line.state() == IteratorState::valid,
+ ExcInternalError());
+
+ // now we found
// two consecutive unused
// lines, such that the
// children of a line
// then set the child
// pointer of the present
// line
- line->set_children (next_unused_line->index());
+ line->set_children (0, next_unused_line->index());
// set the two new lines
- raw_line_iterator children[2] = { next_unused_line,
- ++next_unused_line };
+ const raw_line_iterator children[2] = { next_unused_line,
+ ++next_unused_line };
// some tests; if any of
// the iterators should
// be invalid, then
///////////////////////////////////////
// now refine marked quads
///////////////////////////////////////
- //
- // only active objects can be
- // refined further;
- if (true)
- {
- active_quad_iterator quad = begin_active_quad(),
- endq = end_quad();
- raw_line_iterator next_unused_line = begin_raw_line ();
- raw_quad_iterator next_unused_quad = begin_raw_quad ();
-
- for (; quad!=endq; ++quad)
- if (quad->user_flag_set())
- {
- // this quad needs to be
- // refined
-
- // find the next unused
- // vertex and set it
- // appropriately
- while (vertices_used[next_unused_vertex] == true)
- ++next_unused_vertex;
- Assert (next_unused_vertex < vertices.size(),
- ExcTooFewVerticesAllocated());
- vertices_used[next_unused_vertex] = true;
-
- if (quad->at_boundary())
- vertices[next_unused_vertex]
- = boundary[quad->boundary_indicator()]->get_new_point_on_quad (quad);
- else
- // it might be that the
- // quad itself is not
- // at the boundary, but
- // that one of its lines
- // actually is. in this
- // case, the newly
- // created vertices at
- // the centers of the
- // lines are not
- // necessarily the mean
- // values of the
- // adjacent vertices,
- // so do not compute
- // the new vertex as
- // the mean value of
- // the 4 vertices of
- // the face, but rather
- // as a weighted mean
- // value of the 8
- // vertices which we
- // already have (the
- // four old ones, and
- // the four ones
- // inserted as middle
- // points for the four
- // lines). summing up
- // some more points is
- // generally cheaper
- // than first asking
- // whether one of the
- // lines is at the
- // boundary
- //
- // note that the exact
- // weights are chosen
- // such as to minimize
- // the distortion of
- // the four new quads
- // from the optimal
- // shape; their
- // derivation and
- // values is copied
- // over from the
- // @p{MappingQ::set_laplace_on_vector}
- // function
- vertices[next_unused_vertex]
- = (quad->vertex(0) + quad->vertex(1) +
- quad->vertex(2) + quad->vertex(3) +
- 3*(quad->line(0)->child(0)->vertex(1) +
- quad->line(1)->child(0)->vertex(1) +
- quad->line(2)->child(0)->vertex(1) +
- quad->line(3)->child(0)->vertex(1)) ) / 16;
-
- // now that we created
- // the right point, make
- // up the four lines
- // interior to the quad
- // (++ takes care of the
- // end of the vector)
- raw_line_iterator new_lines[4];
- for (unsigned int i=0; i<4; ++i)
- {
- while (next_unused_line->used() == true)
- ++next_unused_line;
- new_lines[i] = next_unused_line;
- ++next_unused_line;
+ // here we encounter several cases:
- Assert (new_lines[i]->used() == false,
- ExcCellShouldBeUnused());
- }
+ // a) the quad is unrefined and shall be
+ // refined isotropically
- // set the data of the
- // four lines.
- // first collect the
- // indices of the five
- // vertices:
- // *--3--*
- // | | |
- // 0--4--1
- // | | |
- // *--2--*
- // the lines are numbered
- // as follows:
- // *--*--*
- // | 1 |
- // *2-*-3*
- // | 0 |
- // *--*--*
- const unsigned int vertex_indices[5]
- = { quad->line(0)->child(0)->vertex_index(1),
- quad->line(1)->child(0)->vertex_index(1),
- quad->line(2)->child(0)->vertex_index(1),
- quad->line(3)->child(0)->vertex_index(1),
- next_unused_vertex
- };
-
- new_lines[0]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[2], vertex_indices[4]));
- new_lines[1]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[4], vertex_indices[3]));
- new_lines[2]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[0], vertex_indices[4]));
- new_lines[3]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[4], vertex_indices[1]));
-
- for (unsigned int i=0; i<4; ++i)
- {
- new_lines[i]->set_used_flag();
- new_lines[i]->clear_user_flag();
- new_lines[i]->clear_user_data();
- new_lines[i]->clear_children();
- new_lines[i]->set_boundary_indicator(quad->boundary_indicator());
- }
+ // b) the quad is unrefined and shall be
+ // refined anisotropically
+ // c) the quad is unrefined and shall be
+ // refined both anisotropically and
+ // isotropically (this is reduced to case b)
+ // and then case b) for the children again)
- // now for the
- // quads. again, first
- // collect some data
- // about the indices of
- // the lines, with the
- // following numbering:
- // .-6-.-7-.
- // 1 9 3
- // .-10.11-.
- // 0 8 2
- // .-4-.-5-.
-
- // child 0 and 1 of a line are
- // switched if the line orientation
- // is false. set up a miniature
- // table, indicating which child to
- // take for line orientations false
- // and true. first index: child
- // index in standard orientation,
- // second index: line orientation
- unsigned int index[2][2]=
- {{1,0}, // child 0, line_orientation=false and true
- {0,1}}; // child 1, line_orientation=false and true
-
- const unsigned int line_indices[12]
- = { quad->line(0)->child(index[0][quad->line_orientation(0)])->index(),
- quad->line(0)->child(index[1][quad->line_orientation(0)])->index(),
- quad->line(1)->child(index[0][quad->line_orientation(1)])->index(),
- quad->line(1)->child(index[1][quad->line_orientation(1)])->index(),
- quad->line(2)->child(index[0][quad->line_orientation(2)])->index(),
- quad->line(2)->child(index[1][quad->line_orientation(2)])->index(),
- quad->line(3)->child(index[0][quad->line_orientation(3)])->index(),
- quad->line(3)->child(index[1][quad->line_orientation(3)])->index(),
- new_lines[0]->index(),
- new_lines[1]->index(),
- new_lines[2]->index(),
- new_lines[3]->index()
- };
-
- // find some space for
- // the four newly to be
- // created quads. note
- // that there should
- // always be four
- // consecutive free slots
- // for them
- raw_quad_iterator new_quads[4];
-
- while (next_unused_quad->used() == true)
- ++next_unused_quad;
+ // d) the quad is refined anisotropically and
+ // shall be refined isotropically (this is
+ // reduced to case b) for the anisotropic
+ // children)
- new_quads[0] = next_unused_quad;
- Assert (new_quads[0]->used() == false, ExcCellShouldBeUnused());
+ // e) the quad is refined isotropically and
+ // shall be refined anisotropically (this is
+ // transformed to case c), however we might
+ // have to renumber/rename children...)
- ++next_unused_quad;
- new_quads[1] = next_unused_quad;
- Assert (new_quads[1]->used() == false, ExcCellShouldBeUnused());
+ // we need a loop in cases c) and d), as the
+ // anisotropic children migt have a lower
+ // index than the mother quad
+ for (unsigned int loop=0; loop<2; ++loop)
+ {
+ // usually, only active objects can be
+ // refined further. however, in cases d)
+ // and e) that is not true, so we have to
+ // use 'normal' iterators here
+ quad_iterator quad = begin_quad(),
+ endq = end_quad();
+ raw_line_iterator next_unused_line = begin_raw_line (),
+ endl = end_line();
+ raw_quad_iterator next_unused_quad = begin_raw_quad ();
- ++next_unused_quad;
- new_quads[2] = next_unused_quad;
- Assert (new_quads[2]->used() == false, ExcCellShouldBeUnused());
+ for (; quad!=endq; ++quad)
+ {
+ if (quad->user_index())
+ {
+ RefinementCase<dim-1> aniso_quad_ref_case=face_refinement_cases[quad->user_index()];
+ // there is one unlikely event
+ // here, where we already have
+ // refind the face: if the face
+ // was refined anisotropically
+ // and we want to refine it
+ // isotropically, both children
+ // are flagged for anisotropic
+ // refinement. however, if those
+ // children were already flagged
+ // for anisotropic refinement,
+ // they might already be
+ // processed and refined.
+ if (aniso_quad_ref_case == quad->refinement_case())
+ continue;
+
+ Assert(quad->refinement_case()==RefinementCase<dim>::cut_xy ||
+ quad->refinement_case()==RefinementCase<dim>::no_refinement,
+ ExcInternalError());
+
+ // this quad needs to be refined
+ // anisotropically
+ Assert(quad->user_index() == RefinementCase<dim>::cut_x ||
+ quad->user_index() == RefinementCase<dim>::cut_y,
+ ExcInternalError());
+
+ // make the new line interior to
+ // the quad
+ raw_line_iterator new_line;
+
+ new_line=faces->lines.next_free_single_line(*this);
+ Assert (new_line->used() == false,
+ ExcCellShouldBeUnused());
+
+ // first collect the
+ // indices of the vertices:
+ // *--1--*
+ // | | |
+ // | | | cut_x
+ // | | |
+ // *--0--*
+ //
+ // *-----*
+ // | |
+ // 0-----1 cut_y
+ // | |
+ // *-----*
+ unsigned int vertex_indices[2];
+ if (aniso_quad_ref_case==RefinementCase<dim>::cut_x)
+ {
+ vertex_indices[0]=quad->line(2)->child(0)->vertex_index(1);
+ vertex_indices[1]=quad->line(3)->child(0)->vertex_index(1);
+ }
+ else
+ {
+ vertex_indices[0]=quad->line(0)->child(0)->vertex_index(1);
+ vertex_indices[1]=quad->line(1)->child(0)->vertex_index(1);
+ }
- ++next_unused_quad;
- new_quads[3] = next_unused_quad;
- Assert (new_quads[3]->used() == false, ExcCellShouldBeUnused());
+ new_line->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[0], vertex_indices[1]));
+ new_line->set_used_flag();
+ new_line->clear_user_flag();
+ new_line->clear_user_data();
+ new_line->clear_children();
+ new_line->set_boundary_indicator(quad->boundary_indicator());
+
+ // child 0 and 1 of a line are
+ // switched if the line
+ // orientation is false. set up a
+ // miniature table, indicating
+ // which child to take for line
+ // orientations false and
+ // true. first index: child index
+ // in standard orientation,
+ // second index: line orientation
+ const unsigned int index[2][2]=
+ {{1,0}, // child 0, line_orientation=false and true
+ {0,1}}; // child 1, line_orientation=false and true
+
+ // find some space (consecutive)
+ // for the two newly to be
+ // created quads.
+ raw_quad_iterator new_quads[2];
+
+ next_unused_quad=faces->quads.next_free_pair_quad(*this);
+ new_quads[0] = next_unused_quad;
+ Assert (new_quads[0]->used() == false, ExcCellShouldBeUnused());
+
+ ++next_unused_quad;
+ new_quads[1] = next_unused_quad;
+ Assert (new_quads[1]->used() == false, ExcCellShouldBeUnused());
- // note these quads as
- // children to the
- // present one
- quad->set_children (new_quads[0]->index());
-
- new_quads[0]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[0],
- line_indices[8],
- line_indices[4],
- line_indices[10]));
- new_quads[1]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[8],
- line_indices[2],
- line_indices[5],
- line_indices[11]));
- new_quads[2]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[1],
- line_indices[9],
- line_indices[10],
- line_indices[6]));
- new_quads[3]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[9],
- line_indices[3],
- line_indices[11],
- line_indices[7]));
- for (unsigned int i=0; i<4; ++i)
- {
- new_quads[i]->set_used_flag();
- new_quads[i]->clear_user_flag();
- new_quads[i]->clear_user_data();
- new_quads[i]->clear_children();
- new_quads[i]->set_boundary_indicator (quad->boundary_indicator());
- // set all line orientations to
- // true, change this after the
- // loop, as we have to consider
- // different lines for each
- // child
- for (unsigned int j=0; j<GeometryInfo<dim>::lines_per_face; ++j)
- new_quads[i]->set_line_orientation(j,true);
- }
- // now set the line orientation of
- // children of outer lines
- // correctly, the lines in the
- // interior of the refined quad are
- // automatically oriented
- // conforming to the standard
- new_quads[0]->set_line_orientation(0,quad->line_orientation(0));
- new_quads[0]->set_line_orientation(2,quad->line_orientation(2));
- new_quads[1]->set_line_orientation(1,quad->line_orientation(1));
- new_quads[1]->set_line_orientation(2,quad->line_orientation(2));
- new_quads[2]->set_line_orientation(0,quad->line_orientation(0));
- new_quads[2]->set_line_orientation(3,quad->line_orientation(3));
- new_quads[3]->set_line_orientation(1,quad->line_orientation(1));
- new_quads[3]->set_line_orientation(3,quad->line_orientation(3));
-
-
- // finally clear flag
- // indicating the need
- // for refinement
- quad->clear_user_flag ();
- }
- }
- ///////////////////////////////////
- // Now, finally, set up the new
- // cells
- ///////////////////////////////////
- for (unsigned int level=0; level!=levels.size()-1; ++level)
- {
- // only active objects can be
- // refined further; remember
- // that we won't operate on the
- // finest level, so
- // begin_*(level+1) is allowed
- active_hex_iterator hex = begin_active_hex(level),
- endh = begin_active_hex(level+1);
- raw_line_iterator next_unused_line = begin_raw_line ();
- raw_quad_iterator next_unused_quad = begin_raw_quad ();
- raw_hex_iterator next_unused_hex = begin_raw_hex (level+1);
+ if (aniso_quad_ref_case==RefinementCase<dim>::cut_x)
+ {
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(quad->line_index(0),
+ new_line->index(),
+ quad->line(2)->child(index[0][quad->line_orientation(2)])->index(),
+ quad->line(3)->child(index[0][quad->line_orientation(3)])->index()));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(new_line->index(),
+ quad->line_index(1),
+ quad->line(2)->child(index[1][quad->line_orientation(2)])->index(),
+ quad->line(3)->child(index[1][quad->line_orientation(3)])->index()));
+ }
+ else
+ {
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(quad->line(0)->child(index[0][quad->line_orientation(0)])->index(),
+ quad->line(1)->child(index[0][quad->line_orientation(1)])->index(),
+ quad->line_index(2),
+ new_line->index()));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(quad->line(0)->child(index[1][quad->line_orientation(0)])->index(),
+ quad->line(1)->child(index[1][quad->line_orientation(1)])->index(),
+ new_line->index(),
+ quad->line_index(3)));
+ }
+
+ for (unsigned int i=0; i<2; ++i)
+ {
+ new_quads[i]->set_used_flag();
+ new_quads[i]->clear_user_flag();
+ new_quads[i]->clear_user_data();
+ new_quads[i]->clear_children();
+ new_quads[i]->set_boundary_indicator (quad->boundary_indicator());
+ // set all line orientations to
+ // true, change this after the
+ // loop, as we have to consider
+ // different lines for each
+ // child
+ for (unsigned int j=0; j<GeometryInfo<dim>::lines_per_face; ++j)
+ new_quads[i]->set_line_orientation(j,true);
+ }
+ // now set the line orientation of
+ // children of outer lines
+ // correctly, the lines in the
+ // interior of the refined quad are
+ // automatically oriented
+ // conforming to the standard
+ new_quads[0]->set_line_orientation(0,quad->line_orientation(0));
+ new_quads[0]->set_line_orientation(2,quad->line_orientation(2));
+ new_quads[1]->set_line_orientation(1,quad->line_orientation(1));
+ new_quads[1]->set_line_orientation(2,quad->line_orientation(3));
+ if (aniso_quad_ref_case==RefinementCase<dim>::cut_x)
+ {
+ new_quads[0]->set_line_orientation(3,quad->line_orientation(3));
+ new_quads[1]->set_line_orientation(2,quad->line_orientation(2));
+ }
+ else
+ {
+ new_quads[0]->set_line_orientation(1,quad->line_orientation(1));
+ new_quads[1]->set_line_orientation(0,quad->line_orientation(0));
+ }
- for (; hex!=endh; ++hex)
- if (hex->refine_flag_set())
- {
- // do some additional
- // checks.
-#ifdef DEBUG
- for (unsigned int neighbor=0;
- neighbor<GeometryInfo<dim>::faces_per_cell; ++neighbor)
- if (hex->neighbor(neighbor).state() == IteratorState::valid)
- Assert (((hex->neighbor(neighbor)->level() == hex->level()) &&
- (hex->neighbor(neighbor)->coarsen_flag_set() == false)) ||
- ((hex->neighbor(neighbor)->level() == hex->level()-1) &&
- (hex->neighbor(neighbor)->refine_flag_set() == true)),
- ExcInternalError());
-#endif
+ // test, whether this face is
+ // refined isotropically
+ // already. if so, set the
+ // correct children pointers.
+ if (quad->refinement_case()==RefinementCase<dim>::cut_xy)
+ {
+ // we will put a new
+ // refinemnt level of
+ // anisotropic refinement
+ // between the unrefined and
+ // isotropically refined quad
+ // ending up with the same
+ // fine quads but introducing
+ // anisotropically refined
+ // ones as children of the
+ // unrefined quad and mother
+ // cells of the original fine
+ // ones.
+
+ // this process includes the
+ // creation of a new middle
+ // line which we will assign
+ // as the mother line of two
+ // of the existing inner
+ // lines. If those inner
+ // lines are not consecutive
+ // in memory, we won't find
+ // them later on, so we have
+ // to create new ones instead
+ // and replace all occurances
+ // of the old ones with those
+ // new ones. As this is kind
+ // of ugly, we hope we don't
+ // have to do it often...
+ line_iterator old_child[2];
+ if (aniso_quad_ref_case==RefinementCase<dim>::cut_x)
+ {
+ old_child[0]=quad->child(0)->line(1);
+ old_child[1]=quad->child(2)->line(1);
+ }
+ else
+ {
+ Assert(aniso_quad_ref_case==RefinementCase<dim>::cut_y, ExcInternalError());
+
+ old_child[0]=quad->child(0)->line(3);
+ old_child[1]=quad->child(1)->line(3);
+ }
+
+ if (old_child[0]->index()+1 != old_child[1]->index())
+ {
+ // this is exactly the
+ // ugly case we taked
+ // about. so, no
+ // coimplaining, lets get
+ // two new lines and copy
+ // all info
+ raw_line_iterator new_child[2];
+
+ new_child[0]=new_child[1]=faces->lines.next_free_pair_line(*this);
+ ++new_child[1];
+
+ new_child[0]->set_used_flag();
+ new_child[1]->set_used_flag();
+
+ const int old_index_0=old_child[0]->index(),
+ old_index_1=old_child[1]->index(),
+ new_index_0=new_child[0]->index(),
+ new_index_1=new_child[1]->index();
+
+ // loop over all quads
+ // and replace the old
+ // lines
+ for (unsigned int q=0; q<faces->quads.cells.size(); ++q)
+ for (unsigned int l=0; l<GeometryInfo<dim>::lines_per_face; ++l)
+ {
+ const int index=faces->quads.cells[q].face(l);
+ if (index==old_index_0)
+ faces->quads.cells[q].set_face(l,new_index_0);
+ else if (index==old_index_1)
+ faces->quads.cells[q].set_face(l,new_index_1);
+ }
+ // now we have to copy
+ // all information of the
+ // two lines
+ for (unsigned int i=0; i<2; ++i)
+ {
+ Assert(!old_child[i]->has_children(), ExcInternalError());
+
+ new_child[i]->set(internal::Triangulation::TriaObject<1>(old_child[i]->vertex_index(0),
+ old_child[i]->vertex_index(1)));
+ new_child[i]->set_boundary_indicator(old_child[i]->boundary_indicator());
+ new_child[i]->set_user_index(old_child[i]->user_index());
+ if (old_child[i]->user_flag_set())
+ new_child[i]->set_user_flag();
+ else
+ new_child[i]->clear_user_flag();
+
+ new_child[i]->clear_children();
+
+ old_child[i]->clear_user_flag();
+ old_child[i]->clear_user_index();
+ old_child[i]->clear_used_flag();
+ }
+ }
+ // now that we cared
+ // about the lines, go on
+ // with the quads
+ // themselves, where we
+ // might encounter
+ // similar situations...
+ if (aniso_quad_ref_case==RefinementCase<dim>::cut_x)
+ {
+ new_line->set_children(0, quad->child(0)->line_index(1));
+ Assert(new_line->child(1)==quad->child(2)->line(1),
+ ExcInternalError());
+ // now evereything is
+ // quite complicated. we
+ // have the children
+ // numbered according to
+ //
+ // *---*---*
+ // |n+2|n+3|
+ // *---*---*
+ // | n |n+1|
+ // *---*---*
+ //
+ // from the original
+ // isotropic
+ // refinement. we have to
+ // reorder them as
+ //
+ // *---*---*
+ // |n+1|n+3|
+ // *---*---*
+ // | n |n+2|
+ // *---*---*
+ //
+ // such that n and n+1
+ // are consecutive
+ // children of m and n+2
+ // and n+3 are
+ // consecutive children
+ // of m+1, where m and
+ // m+1 are given as in
+ //
+ // *---*---*
+ // | | |
+ // | m |m+1|
+ // | | |
+ // *---*---*
+ //
+ // this is a bit ugly, of
+ // course: loop over all
+ // cells on all levels
+ // and look for faces n+1
+ // (switch_1) and n+2
+ // (switch_2).
+ const quad_iterator switch_1=quad->child(1);
+ const quad_iterator switch_2=quad->child(2);
+ const int switch_1_index=switch_1->index();
+ const int switch_2_index=switch_2->index();
+ for (unsigned int l=0; l<levels.size(); ++l)
+ for (unsigned int h=0; h<levels[l]->cells.cells.size(); ++h)
+ for (unsigned int q=0; q<GeometryInfo<dim>::faces_per_cell; ++q)
+ {
+ const int index=levels[l]->cells.cells[h].face(q);
+ if (index==switch_1_index)
+ levels[l]->cells.cells[h].set_face(q,switch_2_index);
+ else if (index==switch_2_index)
+ levels[l]->cells.cells[h].set_face(q,switch_1_index);
+ }
+ // now we have to copy
+ // all information of the
+ // two quads
+ const int switch_1_lines[4]=
+ {switch_1->line_index(0),
+ switch_1->line_index(1),
+ switch_1->line_index(2),
+ switch_1->line_index(3)};
+ const bool switch_1_line_orientations[4]=
+ {switch_1->line_orientation(0),
+ switch_1->line_orientation(1),
+ switch_1->line_orientation(2),
+ switch_1->line_orientation(3)};
+ const unsigned char switch_1_boundary_indicator=switch_1->boundary_indicator();
+ const unsigned int switch_1_user_index=switch_1->user_index();
+ const bool switch_1_user_flag=switch_1->user_flag_set();
+ const RefinementCase<dim-1> switch_1_refinement_case=switch_1->refinement_case();
+ const int switch_1_first_child_pair=(switch_1_refinement_case ? switch_1->child_index(0) : -1);
+ const int switch_1_second_child_pair=(switch_1_refinement_case==RefinementCase<dim>::cut_xy ? switch_1->child_index(2) : -1);
+
+ switch_1->set(internal::Triangulation::TriaObject<2>(switch_2->line_index(0),
+ switch_2->line_index(1),
+ switch_2->line_index(2),
+ switch_2->line_index(3)));
+ switch_1->set_line_orientation(0, switch_2->line_orientation(0));
+ switch_1->set_line_orientation(1, switch_2->line_orientation(1));
+ switch_1->set_line_orientation(2, switch_2->line_orientation(2));
+ switch_1->set_line_orientation(3, switch_2->line_orientation(3));
+ switch_1->set_boundary_indicator(switch_2->boundary_indicator());
+ switch_1->set_user_index(switch_2->user_index());
+ if (switch_2->user_flag_set())
+ switch_1->set_user_flag();
+ else
+ switch_1->clear_user_flag();
+ switch_1->clear_refinement_case();
+ switch_1->set_refinement_case(switch_2->refinement_case());
+ switch_1->clear_children();
+ if (switch_2->refinement_case())
+ switch_1->set_children(0, switch_2->child_index(0));
+ if (switch_2->refinement_case()==RefinementCase<dim>::cut_xy)
+ switch_1->set_children(2, switch_2->child_index(2));
+
+ switch_2->set(internal::Triangulation::TriaObject<2>(switch_1_lines[0],
+ switch_1_lines[1],
+ switch_1_lines[2],
+ switch_1_lines[3]));
+ switch_2->set_line_orientation(0, switch_1_line_orientations[0]);
+ switch_2->set_line_orientation(1, switch_1_line_orientations[1]);
+ switch_2->set_line_orientation(2, switch_1_line_orientations[2]);
+ switch_2->set_line_orientation(3, switch_1_line_orientations[3]);
+ switch_2->set_boundary_indicator(switch_1_boundary_indicator);
+ switch_2->set_user_index(switch_1_user_index);
+ if (switch_1_user_flag)
+ switch_2->set_user_flag();
+ else
+ switch_2->clear_user_flag();
+ switch_2->clear_refinement_case();
+ switch_2->set_refinement_case(switch_1_refinement_case);
+ switch_2->clear_children();
+ switch_2->set_children(0, switch_1_first_child_pair);
+ switch_2->set_children(2, switch_1_second_child_pair);
+
+ new_quads[0]->set_refinement_case(RefinementCase<2>::cut_y);
+ new_quads[0]->set_children(0, quad->child_index(0));
+ new_quads[1]->set_refinement_case(RefinementCase<2>::cut_y);
+ new_quads[1]->set_children(0, quad->child_index(2));
+ }
+ else
+ {
+ new_quads[0]->set_refinement_case(RefinementCase<2>::cut_x);
+ new_quads[0]->set_children(0, quad->child_index(0));
+ new_quads[1]->set_refinement_case(RefinementCase<2>::cut_x);
+ new_quads[1]->set_children(0, quad->child_index(2));
+ new_line->set_children(0, quad->child(0)->line_index(3));
+ Assert(new_line->child(1)==quad->child(1)->line(3),
+ ExcInternalError());
+ }
+ quad->clear_children();
+ }
+
+ // note these quads as children
+ // to the present one
+ quad->set_children (0, new_quads[0]->index());
+
+ quad->set_refinement_case(aniso_quad_ref_case);
+
+ // finally clear flag
+ // indicating the need
+ // for refinement
+ quad->clear_user_data ();
+ } // if (anisotropic refinement)
+
+ if (quad->user_flag_set())
+ {
+ // this quad needs to be
+ // refined isotropically
+
+ // first of all: we only get here
+ // in the first run of the loop
+ Assert(loop==0,ExcInternalError());
+
+ // find the next unused
+ // vertex. we'll need this in any
+ // case
+ while (vertices_used[next_unused_vertex] == true)
+ ++next_unused_vertex;
+ Assert (next_unused_vertex < vertices.size(),
+ ExcTooFewVerticesAllocated());
+
+ // now: if the quad is refined
+ // anisotropically already, set
+ // the anisotropic refinement
+ // flag for both
+ // children. Additionally, we
+ // have to refine the inner line,
+ // as it is an outer line of the
+ // two (anisotropic) children
+ const RefinementCase<dim-1> quad_ref_case=quad->refinement_case();
+
+ if (quad_ref_case==RefinementCase<dim>::cut_x ||
+ quad_ref_case==RefinementCase<dim>::cut_y)
+ {
+ // set the 'opposite' refine case for children
+ quad->child(0)->set_user_index(RefinementCase<dim>::cut_xy-quad_ref_case);
+ quad->child(1)->set_user_index(RefinementCase<dim>::cut_xy-quad_ref_case);
+ // refine the inner line
+ line_iterator middle_line;
+ if (quad_ref_case==RefinementCase<dim>::cut_x)
+ middle_line=quad->child(0)->line(1);
+ else
+ middle_line=quad->child(0)->line(3);
+
+ // if the face has been
+ // refined anisotropically in
+ // the last refinement step
+ // it might be, that it is
+ // flagged already and that
+ // the middle line is thus
+ // refined already. if not
+ // create children.
+ if (!middle_line->has_children())
+ {
+ // set the middle vertex
+ // appropriately. double
+ // refinement of quads can only
+ // happen in the interior of
+ // the domain, so we need not
+ // care about boundary quads
+ // here
+ vertices[next_unused_vertex]
+ = (middle_line->vertex(0) + middle_line->vertex(1)) / 2;
+ vertices_used[next_unused_vertex] = true;
+
+ // now search a slot for the two
+ // child lines
+ next_unused_line=faces->lines.next_free_pair_line(*this);
+
+ // set the child
+ // pointer of the present
+ // line
+ middle_line->set_children (0, next_unused_line->index());
+
+ // set the two new lines
+ const raw_line_iterator children[2] = { next_unused_line,
+ ++next_unused_line };
+ // some tests; if any of
+ // the iterators should
+ // be invalid, then
+ // already dereferencing
+ // will fail
+ Assert (children[0]->used() == false, ExcCellShouldBeUnused());
+ Assert (children[1]->used() == false, ExcCellShouldBeUnused());
+
+ children[0]->set (internal::Triangulation::
+ TriaObject<1>(middle_line->vertex_index(0),
+ next_unused_vertex));
+ children[1]->set (internal::Triangulation::
+ TriaObject<1>(next_unused_vertex,
+ middle_line->vertex_index(1)));
+
+ children[0]->set_used_flag();
+ children[1]->set_used_flag();
+ children[0]->clear_children();
+ children[1]->clear_children();
+ children[0]->clear_user_data();
+ children[1]->clear_user_data();
+ children[0]->clear_user_flag();
+ children[1]->clear_user_flag();
+
+ children[0]->set_boundary_indicator (middle_line->boundary_indicator());
+ children[1]->set_boundary_indicator (middle_line->boundary_indicator());
+ }
+ // now remove the flag from the
+ // quad and go to the next
+ // quad, the actual refinement
+ // of the quad takes place
+ // later on in this pass of the
+ // loop or in the next one
+ quad->clear_user_flag();
+ continue;
+ } // if (several refinement cases)
+
+ // if we got here, we have an
+ // unrefined quad and have to do
+ // the usual work like in an purely
+ // isotropic refinement
+ Assert(quad_ref_case==RefinementCase<dim>::no_refinement, ExcInternalError());
+
+ // set the middle vertex
+ // appropriately
+ if (quad->at_boundary())
+ vertices[next_unused_vertex]
+ = boundary[quad->boundary_indicator()]->get_new_point_on_quad (quad);
+ else
+ // it might be that the
+ // quad itself is not
+ // at the boundary, but
+ // that one of its lines
+ // actually is. in this
+ // case, the newly
+ // created vertices at
+ // the centers of the
+ // lines are not
+ // necessarily the mean
+ // values of the
+ // adjacent vertices,
+ // so do not compute
+ // the new vertex as
+ // the mean value of
+ // the 4 vertices of
+ // the face, but rather
+ // as a weighted mean
+ // value of the 8
+ // vertices which we
+ // already have (the
+ // four old ones, and
+ // the four ones
+ // inserted as middle
+ // points for the four
+ // lines). summing up
+ // some more points is
+ // generally cheaper
+ // than first asking
+ // whether one of the
+ // lines is at the
+ // boundary
+ //
+ // note that the exact
+ // weights are chosen
+ // such as to minimize
+ // the distortion of
+ // the four new quads
+ // from the optimal
+ // shape; their
+ // derivation and
+ // values is copied
+ // over from the
+ // @p{MappingQ::set_laplace_on_vector}
+ // function
+ vertices[next_unused_vertex]
+ = (quad->vertex(0) + quad->vertex(1) +
+ quad->vertex(2) + quad->vertex(3) +
+ 3*(quad->line(0)->child(0)->vertex(1) +
+ quad->line(1)->child(0)->vertex(1) +
+ quad->line(2)->child(0)->vertex(1) +
+ quad->line(3)->child(0)->vertex(1)) ) / 16;
+
+ vertices_used[next_unused_vertex] = true;
+
+ // now that we created
+ // the right point, make
+ // up the four lines
+ // interior to the quad
+ // (++ takes care of the
+ // end of the vector)
+ raw_line_iterator new_lines[4];
+
+ for (unsigned int i=0; i<4; ++i)
+ {
+ if (i%2==0)
+ // search a free pair of
+ // lines for 0. and 2. line,
+ // so that two of them end up
+ // together, which is
+ // necessary if later on we
+ // want to refine the quad
+ // anisotropically and the
+ // two lines end up as
+ // children of new line
+ next_unused_line=faces->lines.next_free_pair_line(*this);
+
+ new_lines[i] = next_unused_line;
+ ++next_unused_line;
+
+ Assert (new_lines[i]->used() == false,
+ ExcCellShouldBeUnused());
+ }
+
+ // set the data of the
+ // four lines.
+ // first collect the
+ // indices of the five
+ // vertices:
+ // *--3--*
+ // | | |
+ // 0--4--1
+ // | | |
+ // *--2--*
+ // the lines are numbered
+ // as follows:
+ // *--*--*
+ // | 1 |
+ // *2-*-3*
+ // | 0 |
+ // *--*--*
+
+ const unsigned int vertex_indices[5]
+ = { quad->line(0)->child(0)->vertex_index(1),
+ quad->line(1)->child(0)->vertex_index(1),
+ quad->line(2)->child(0)->vertex_index(1),
+ quad->line(3)->child(0)->vertex_index(1),
+ next_unused_vertex
+ };
+
+ new_lines[0]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[2], vertex_indices[4]));
+ new_lines[1]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[4], vertex_indices[3]));
+ new_lines[2]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[0], vertex_indices[4]));
+ new_lines[3]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[4], vertex_indices[1]));
+
+ for (unsigned int i=0; i<4; ++i)
+ {
+ new_lines[i]->set_used_flag();
+ new_lines[i]->clear_user_flag();
+ new_lines[i]->clear_user_data();
+ new_lines[i]->clear_children();
+ new_lines[i]->set_boundary_indicator(quad->boundary_indicator());
+ }
+
+ // now for the
+ // quads. again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
+ // .-6-.-7-.
+ // 1 9 3
+ // .-10.11-.
+ // 0 8 2
+ // .-4-.-5-.
+
+ // child 0 and 1 of a line are
+ // switched if the line orientation
+ // is false. set up a miniature
+ // table, indicating which child to
+ // take for line orientations false
+ // and true. first index: child
+ // index in standard orientation,
+ // second index: line orientation
+ const unsigned int index[2][2]=
+ {{1,0}, // child 0, line_orientation=false and true
+ {0,1}}; // child 1, line_orientation=false and true
+
+ const unsigned int line_indices[12]
+ = { quad->line(0)->child(index[0][quad->line_orientation(0)])->index(),
+ quad->line(0)->child(index[1][quad->line_orientation(0)])->index(),
+ quad->line(1)->child(index[0][quad->line_orientation(1)])->index(),
+ quad->line(1)->child(index[1][quad->line_orientation(1)])->index(),
+ quad->line(2)->child(index[0][quad->line_orientation(2)])->index(),
+ quad->line(2)->child(index[1][quad->line_orientation(2)])->index(),
+ quad->line(3)->child(index[0][quad->line_orientation(3)])->index(),
+ quad->line(3)->child(index[1][quad->line_orientation(3)])->index(),
+ new_lines[0]->index(),
+ new_lines[1]->index(),
+ new_lines[2]->index(),
+ new_lines[3]->index()
+ };
+
+ // find some space (consecutive)
+ // for the first two newly to be
+ // created quads.
+ raw_quad_iterator new_quads[4];
+
+ next_unused_quad=faces->quads.next_free_pair_quad(*this);
+
+ new_quads[0] = next_unused_quad;
+ Assert (new_quads[0]->used() == false, ExcCellShouldBeUnused());
+
+ ++next_unused_quad;
+ new_quads[1] = next_unused_quad;
+ Assert (new_quads[1]->used() == false, ExcCellShouldBeUnused());
+
+ next_unused_quad=faces->quads.next_free_pair_quad(*this);
+ new_quads[2] = next_unused_quad;
+ Assert (new_quads[2]->used() == false, ExcCellShouldBeUnused());
+
+ ++next_unused_quad;
+ new_quads[3] = next_unused_quad;
+ Assert (new_quads[3]->used() == false, ExcCellShouldBeUnused());
+
+ // note these quads as
+ // children to the
+ // present one
+ quad->set_children (0, new_quads[0]->index());
+ quad->set_children (2, new_quads[2]->index());
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[0],
+ line_indices[8],
+ line_indices[4],
+ line_indices[10]));
+
+ quad->set_refinement_case(RefinementCase<2>::cut_xy);
+
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[0],
+ line_indices[8],
+ line_indices[4],
+ line_indices[10]));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[8],
+ line_indices[2],
+ line_indices[5],
+ line_indices[11]));
+ new_quads[2]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[1],
+ line_indices[9],
+ line_indices[10],
+ line_indices[6]));
+ new_quads[3]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[9],
+ line_indices[3],
+ line_indices[11],
+ line_indices[7]));
+ for (unsigned int i=0; i<4; ++i)
+ {
+ new_quads[i]->set_used_flag();
+ new_quads[i]->clear_user_flag();
+ new_quads[i]->clear_user_data();
+ new_quads[i]->clear_children();
+ new_quads[i]->set_boundary_indicator (quad->boundary_indicator());
+ // set all line orientations to
+ // true, change this after the
+ // loop, as we have to consider
+ // different lines for each
+ // child
+ for (unsigned int j=0; j<GeometryInfo<dim>::lines_per_face; ++j)
+ new_quads[i]->set_line_orientation(j,true);
+ }
+ // now set the line orientation of
+ // children of outer lines
+ // correctly, the lines in the
+ // interior of the refined quad are
+ // automatically oriented
+ // conforming to the standard
+ new_quads[0]->set_line_orientation(0,quad->line_orientation(0));
+ new_quads[0]->set_line_orientation(2,quad->line_orientation(2));
+ new_quads[1]->set_line_orientation(1,quad->line_orientation(1));
+ new_quads[1]->set_line_orientation(2,quad->line_orientation(2));
+ new_quads[2]->set_line_orientation(0,quad->line_orientation(0));
+ new_quads[2]->set_line_orientation(3,quad->line_orientation(3));
+ new_quads[3]->set_line_orientation(1,quad->line_orientation(1));
+ new_quads[3]->set_line_orientation(3,quad->line_orientation(3));
+
+ // finally clear flag
+ // indicating the need
+ // for refinement
+ quad->clear_user_flag ();
+ } // if (isotropic refinement)
+ } // for all quads
+ } // looped two times over all quads, all quads refined now
+
+ ///////////////////////////////////
+ // Now, finally, set up the new
+ // cells
+ ///////////////////////////////////
+ for (unsigned int level=0; level!=levels.size()-1; ++level)
+ {
+ // only active objects can be
+ // refined further; remember
+ // that we won't operate on the
+ // finest level, so
+ // begin_*(level+1) is allowed
+ active_hex_iterator hex = begin_active_hex(level),
+ endh = begin_active_hex(level+1);
+ raw_line_iterator next_unused_line = begin_raw_line ();
+ raw_quad_iterator next_unused_quad = begin_raw_quad ();
+ raw_hex_iterator next_unused_hex = begin_raw_hex (level+1);
+
+ for (; hex!=endh; ++hex)
+ if (hex->refine_flag_set())
+ {
// this hex needs to be
// refined
// can't do it anymore
// once the cell has
// children
+ const RefinementCase<dim> ref_case=hex->refine_flag_set();
hex->clear_refine_flag ();
-
- // find the next unused
- // vertex and set it
- // appropriately
- while (vertices_used[next_unused_vertex] == true)
- ++next_unused_vertex;
- Assert (next_unused_vertex < vertices.size(),
- ExcTooFewVerticesAllocated());
- vertices_used[next_unused_vertex] = true;
-
- // the new vertex is
- // definitely in the
- // interior, so we need
- // not worry about the
- // boundary. let it be
- // the average of the 26
- // vertices surrounding
- // it. weight these
- // vertices in the same
- // way as they are
- // weighted in the
- // @p{MappingQ::set_laplace_on_hex_vector}
- // function, and like the
- // new vertex at the
- // center of the quad is
- // weighted (see above)
- vertices[next_unused_vertex] = Point<dim>();
- // first add corners of hex
- for (unsigned int vertex=0;
- vertex<GeometryInfo<dim>::vertices_per_cell; ++vertex)
- vertices[next_unused_vertex] += hex->vertex(vertex) / 128;
- // now add center of lines
- for (unsigned int line=0;
- line<GeometryInfo<dim>::lines_per_cell; ++line)
- vertices[next_unused_vertex] += hex->line(line)->child(0)->vertex(1) *
- 7./192.;
- // finally add centers of
- // faces. note that
- // vertex 3 of child 0 is an
- // invariant with respect
- // to the face
- // orientation, flip and rotation
- for (unsigned int face=0;
- face<GeometryInfo<dim>::faces_per_cell; ++face)
- vertices[next_unused_vertex] += hex->face(face)->child(0)->vertex(3) *
- 1./12.;
-
- // now that we created
- // the right point, make
- // up the six lines
- // interior to the hex
- // (++ takes care of the
- // end of the vector)
- raw_line_iterator new_lines[6];
-
- for (unsigned int i=0; i<6; ++i)
+ hex->set_refinement_case(ref_case);
+
+ // depending on the refine case we
+ // might have to create additional
+ // vertices, lines and quads
+ // interior of the hex before the
+ // actual children can be set up.
+
+ // in a first step: reserve the
+ // needed space for lines, quads
+ // and hexes and initialize them
+ // correctly
+
+ unsigned int n_new_lines=0;
+ unsigned int n_new_quads=0;
+ unsigned int n_new_hexes=0;
+ switch (static_cast<unsigned char> (ref_case))
{
- while (next_unused_line->used() == true)
- ++next_unused_line;
- new_lines[i] = next_unused_line;
- ++next_unused_line;
-
- Assert (new_lines[i]->used() == false,
- ExcCellShouldBeUnused());
+ case RefinementCase<dim>::cut_x:
+ case RefinementCase<dim>::cut_y:
+ case RefinementCase<dim>::cut_z:
+ n_new_lines=0;
+ n_new_quads=1;
+ n_new_hexes=2;
+ break;
+ case RefinementCase<dim>::cut_xy:
+ case RefinementCase<dim>::cut_xz:
+ case RefinementCase<dim>::cut_yz:
+ n_new_lines=1;
+ n_new_quads=4;
+ n_new_hexes=4;
+ break;
+ case RefinementCase<dim>::cut_xyz:
+ n_new_lines=6;
+ n_new_quads=12;
+ n_new_hexes=8;
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ break;
}
-
- // set the data of the
- // six lines. first
- // collect the indices of
- // the seven vertices
- // (consider the two
- // planes to be crossed
- // to form the planes
- // cutting the hex in two
- // vertically and
- // horizontally)
- // *--3--* *--5--*
- // / / / | | |
- // 0--6--1 0--6--1
- // / / / | | |
- // *--2--* *--4--*
- // the lines are numbered
- // as follows:
- // *--*--* *--*--*
- // / 1 / | 5 |
- // *2-*-3* *2-*-3*
- // / 0 / | 4 |
- // *--*--* *--*--*
- //
- // note that asking for child 0 and
- // vertex 3 within that is
- // invariant with respect to the
- // face orientation, rotation and
- // flip, so we do not have to ask
- // here
- const unsigned int vertex_indices[7]
- = { hex->face(0)->child(0)->vertex_index(3),
- hex->face(1)->child(0)->vertex_index(3),
- hex->face(2)->child(0)->vertex_index(3),
- hex->face(3)->child(0)->vertex_index(3),
- hex->face(4)->child(0)->vertex_index(3),
- hex->face(5)->child(0)->vertex_index(3),
- next_unused_vertex
- };
- new_lines[0]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[2], vertex_indices[6]));
- new_lines[1]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[6], vertex_indices[3]));
- new_lines[2]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[0], vertex_indices[6]));
- new_lines[3]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[6], vertex_indices[1]));
- new_lines[4]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[4], vertex_indices[6]));
- new_lines[5]->set (internal::Triangulation
- ::TriaObject<1>(vertex_indices[6], vertex_indices[5]));
-
- for (unsigned int i=0; i<6; ++i)
+ // find some space for the newly to
+ // be created interior lines and
+ // initialize them.
+ std::vector<raw_line_iterator> new_lines(n_new_lines);
+ for (unsigned int i=0; i<n_new_lines; ++i)
{
+ new_lines[i] = faces->lines.next_free_single_line(*this);
+
+ Assert (new_lines[i]->used() == false,
+ ExcCellShouldBeUnused());
new_lines[i]->set_used_flag();
new_lines[i]->clear_user_flag();
new_lines[i]->clear_user_data();
new_lines[i]->set_boundary_indicator(255);
}
+ // find some space for the newly to
+ // be created interior quads and
+ // initialize them.
+ std::vector<raw_quad_iterator> new_quads(n_new_quads);
+ for (unsigned int i=0; i<n_new_quads; ++i)
+ {
+ new_quads[i] = faces->quads.next_free_single_quad(*this);
+
+ Assert (new_quads[i]->used() == false,
+ ExcCellShouldBeUnused());
+ new_quads[i]->set_used_flag();
+ new_quads[i]->clear_user_flag();
+ new_quads[i]->clear_user_data();
+ new_quads[i]->clear_children();
+ // interior quad
+ new_quads[i]->set_boundary_indicator (255);
+ // set all line orientation
+ // flags to true by default,
+ // change this afterwards, if
+ // necessary
+ for (unsigned int j=0; j<GeometryInfo<dim>::lines_per_face; ++j)
+ new_quads[i]->set_line_orientation(j,true);
+ }
+
+ // find some space for the newly to
+ // be created hexes and initialize
+ // them.
+ std::vector<raw_hex_iterator> new_hexes(n_new_hexes);
+ for (unsigned int i=0; i<n_new_hexes; ++i)
+ {
+ if (i%2==0)
+ next_unused_hex=levels[level+1]->cells.next_free_hex(*this,level+1);
+ else
+ ++next_unused_hex;
+
+ new_hexes[i]=next_unused_hex;
+
+ Assert (new_hexes[i]->used() == false,
+ ExcCellShouldBeUnused());
+ new_hexes[i]->set_used_flag();
+ new_hexes[i]->clear_user_flag();
+ new_hexes[i]->clear_user_data();
+ new_hexes[i]->clear_children();
+ // inherit material
+ // properties
+ new_hexes[i]->set_material_id (hex->material_id());
+ new_hexes[i]->set_subdomain_id (hex->subdomain_id());
+ // set the face_orientation
+ // flag to true for all faces
+ // initially, as this is the
+ // default value which is true
+ // for all faces interior to
+ // the hex. later on go the
+ // other way round and reset
+ // faces that are at the
+ // boundary of the mother cube
+ //
+ // the same is true for the
+ // face_flip and face_rotation
+ // flags. however, the latter
+ // two are set to false by
+ // default as this is the
+ // standard value
+ for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
+ {
+ new_hexes[i]->set_face_orientation(f, true);
+ new_hexes[i]->set_face_flip(f, false);
+ new_hexes[i]->set_face_rotation(f, false);
+ }
+ }
+ // note these hexes as
+ // children to the
+ // present cell
+ for (unsigned int i=0; i<n_new_hexes/2; ++i)
+ hex->set_children (2*i, new_hexes[2*i]->index());
+
+ // we have to take into account
+ // whether the different faces are
+ // oriented correctly or in the
+ // opposite direction, so store
+ // that up front
- // now for the
- // quads. again, first
- // collect some data
- // about the indices of
- // the lines, with the
- // following numbering:
- // (note that face 0 and
- // 1 each are shown twice
- // for better
- // readability)
-
- // face 0: left plane
- // * *
- // /| /|
- // * | * |
- // /| * /| *
- // * 1/| * |3|
- // | * | | * |
- // |/| * |2| *
- // * 0/ * |/
- // | * | *
- // |/ |/
- // * *
- // face 1: right plane
- // * *
- // /| /|
- // * | * |
- // /| * /| *
- // * 5/| * |7|
- // | * | | * |
- // |/| * |6| *
- // * 4/ * |/
- // | * | *
- // |/ |/
- // * *
- // face 2: front plane
- // (note: x,y exchanged)
- // *---*---*
- // | 11 |
- // *-8-*-9-*
- // | 10 |
- // *---*---*
- // face 3: back plane
- // (note: x,y exchanged)
- // *---*---*
- // | 15 |
- // *12-*-13*
- // | 14 |
- // *---*---*
- // face 4: bottom plane
- // *---*---*
- // / 17 /
- // *18-*-19*
- // / 16 /
- // *---*---*
- // face 5: top plane
- // *---*---*
- // / 21 /
- // *22-*-23*
- // / 20 /
- // *---*---*
- // middle planes
- // *---*---* *---*---*
- // / 25 / | 29 |
- // *26-*-27* *26-*-27*
- // / 24 / | 28 |
- // *---*---* *---*---*
- //
- // this time we have to
- // take into account
- // whether the different
- // faces are oriented
- // correctly or in the
- // opposite direction, so
- // store that up front
-
- // TODO: shorten this
-
// face_orientation
const bool f_or[6]
= { hex->face_orientation (0),
hex->face_rotation (4),
hex->face_rotation (5) };
- // set up a list of line iterators
- // first. from this, construct
- // lists of line_indices and
- // line orientations later on
- const raw_line_iterator lines[30]
- = {
- hex->face(0)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0])), //0
- hex->face(0)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[0],f_fl[0],f_ro[0])), //1
- hex->face(0)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[0],f_fl[0],f_ro[0])), //2
- hex->face(0)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[0],f_fl[0],f_ro[0])), //3
-
- hex->face(1)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[1],f_fl[1],f_ro[1])), //4
- hex->face(1)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[1],f_fl[1],f_ro[1])), //5
- hex->face(1)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[1],f_fl[1],f_ro[1])), //6
- hex->face(1)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[1],f_fl[1],f_ro[1])), //7
-
- hex->face(2)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[2],f_fl[2],f_ro[2])), //8
- hex->face(2)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[2],f_fl[2],f_ro[2])), //9
- hex->face(2)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[2],f_fl[2],f_ro[2])), //10
- hex->face(2)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[2],f_fl[2],f_ro[2])), //11
-
- hex->face(3)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[3],f_fl[3],f_ro[3])), //12
- hex->face(3)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[3],f_fl[3],f_ro[3])), //13
- hex->face(3)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[3],f_fl[3],f_ro[3])), //14
- hex->face(3)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[3],f_fl[3],f_ro[3])), //15
-
- hex->face(4)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[4],f_fl[4],f_ro[4])), //16
- hex->face(4)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[4],f_fl[4],f_ro[4])), //17
- hex->face(4)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[4],f_fl[4],f_ro[4])), //18
- hex->face(4)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[4],f_fl[4],f_ro[4])), //19
-
- hex->face(5)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[5],f_fl[5],f_ro[5])), //20
- hex->face(5)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[5],f_fl[5],f_ro[5])), //21
- hex->face(5)->child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[5],f_fl[5],f_ro[5])), //22
- hex->face(5)->child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
- ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[5],f_fl[5],f_ro[5])), //23
-
- new_lines[0], //24
- new_lines[1], //25
- new_lines[2], //26
- new_lines[3], //27
- new_lines[4], //28
- new_lines[5] //29
- };
-
- unsigned int line_indices[30];
- for (unsigned int i=0; i<30; ++i)
- line_indices[i]=lines[i]->index();
-
- // the orientation of lines for the
- // inner quads is quite tricky. as
- // these lines are newly created
- // ones and thus have no parents,
- // they cannot inherit this
- // property. set up an array and
- // fill it with the respective
- // values
- bool line_orientation[30];
- // note: for the first 24 lines
- // (inner lines of the outer quads)
- // the following holds: the second
- // vertex of the even lines in
- // standard orientation is the
- // vertex in the middle of the
- // quad, whereas for odd lines the
- // first vertex is the same middle
- // vertex.
- for (unsigned int i=0; i<24; ++i)
- if (lines[i]->vertex_index((i+1)%2)==vertex_indices[i/4])
- line_orientation[i]=true;
- else
+ // some commonly used fields which
+ // have varying size
+ const unsigned int *vertex_indices=0;
+ const raw_line_iterator *lines=0;
+ const unsigned int *line_indices=0;
+ const bool *line_orientation=0;
+ const unsigned int *quad_indices=0;
+
+ // little helper table, indicating,
+ // whether the child with index 0
+ // or with index 1 can be found at
+ // the standard origin of an
+ // anisotropically refined quads in
+ // real orientation
+ // index 1: (RefineCase - 1)
+ // index 2: face_flip
+
+ // index 3: face rotation
+ // note: face orientation has no influence
+ const unsigned int child_at_origin[2][2][2]=
+ { { { 0, 0 }, // RefinementCase<dim>::cut_x, face_flip=false, face_rotation=false and true
+ { 1, 1 }}, // RefinementCase<dim>::cut_x, face_flip=true, face_rotation=false and true
+ { { 0, 1 }, // RefinementCase<dim>::cut_y, face_flip=false, face_rotation=false and true
+ { 1, 0 }}};// RefinementCase<dim>::cut_y, face_flip=true, face_rotation=false and true
+
+ ///////////////////////////////////////
+ //
+ // in the following we will do the
+ // same thing for each refinement
+ // case: create a new vertex (if
+ // needed), create new interior
+ // lines (if needed), create new
+ // interior quads and afterwards
+ // build the children hexes out of
+ // these and the existing subfaces
+ // of the outer quads (which have
+ // been created above). However,
+ // even if the steps are quite
+ // similar, the actual work
+ // strongly depends on the actual
+ // refinement case. therefore, we
+ // use seperate blocks of code for
+ // each of these cases, which
+ // hopefully increases the
+ // readability to some extend.
+
+ switch (static_cast<unsigned char> (ref_case))
+ {
+ case RefinementCase<dim>::cut_x:
{
- // it must be the other way
- // round then
- Assert(lines[i]->vertex_index(i%2)==vertex_indices[i/4],
- ExcInternalError());
- line_orientation[i]=false;
- }
- // for the last 6 lines the line
- // orientation is always true,
- // since they were just constructed
- // that way
- for (unsigned int i=24; i<30; ++i)
- line_orientation[i]=true;
-
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_x
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *----*----*
+ // / / /|
+ // / / / |
+ // / / / |
+ // *----*----* |
+ // | | | |
+ // | | | *
+ // | | | /
+ // | | | /
+ // | | |/
+ // *----*----*
+ //
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
- // find some space for
- // the 12 newly to be
- // created quads.
- raw_quad_iterator new_quads[12];
-
- for (unsigned int i=0; i<12; ++i)
- {
- while (next_unused_quad->used() == true)
- ++next_unused_quad;
- new_quads[i] = next_unused_quad;
- ++next_unused_quad;
-
- Assert (new_quads[i]->used() == false,
- ExcCellShouldBeUnused());
- }
+ // face 2: front plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | | |
+ // | 0 |
+ // | | |
+ // *---*---*
+ // m0
+ // face 3: back plane
+ // (note: x,y exchanged)
+ // m1
+ // *---*---*
+ // | | |
+ // | 1 |
+ // | | |
+ // *---*---*
+ // face 4: bottom plane
+ // *---*---*
+ // / / /
+ // / 2 /
+ // / / /
+ // *---*---*
+ // m0
+ // face 5: top plane
+ // m1
+ // *---*---*
+ // / / /
+ // / 3 /
+ // / / /
+ // *---*---*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_x[4]
+ = {
+ hex->face(2)->child(0)
+ ->line((hex->face(2)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //0
+ hex->face(3)->child(0)
+ ->line((hex->face(3)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //1
+ hex->face(4)->child(0)
+ ->line((hex->face(4)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //2
+ hex->face(5)->child(0)
+ ->line((hex->face(5)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3) //3
+ };
+
+ lines=&lines_x[0];
+
+ unsigned int line_indices_x[4];
+
+ for (unsigned int i=0; i<4; ++i)
+ line_indices_x[i]=lines[i]->index();
+ line_indices=&line_indices_x[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_x[4];
+
+ // the middle vertice marked
+ // as m0 above is the start
+ // vertex for lines 0 and 2
+ // in standard orientation,
+ // whereas m1 is the end
+ // vertex of lines 1 and 3 in
+ // standard orientation
+ const unsigned int middle_vertices[2]=
+ {
+ hex->line(2)->child(0)->vertex_index(1),
+ hex->line(7)->child(0)->vertex_index(1)
+ };
- // set up the 12 quads,
- // numbered as follows
- // (left quad numbering,
- // right line numbering
- // extracted from above)
- //
- // * *
- // /| 21|
- // * | * 15
- // y/|3* 20| *
- // * |/| * |/|
- // |2* |x 11 * 14
- // |/|1* |/| *
- // * |/ * |17
- // |0* 10 *
- // |/ |16
- // * *
- //
- // x
- // *---*---* *22-*-23*
- // | 5 | 7 | 1 29 5
- // *---*---* *26-*-27*
- // | 4 | 6 | 0 28 4
- // *---*---*y *18-*-19*
- //
- // y
- // *----*----* *-12-*-13-*
- // / 10 / 11 / 3 25 7
- // *----*----* *-26-*-27-*
- // / 8 / 9 / 2 24 6
- // *----*----*x *--8-*--9-*
+ for (unsigned int i=0; i<4; ++i)
+ if (lines[i]->vertex_index(i%2)==middle_vertices[i%2])
+ line_orientation_x[i]=true;
+ else
+ {
+ // it must be the other
+ // way round then
+ Assert(lines[i]->vertex_index((i+1)%2)==middle_vertices[i%2],
+ ExcInternalError());
+ line_orientation_x[i]=false;
+ }
+
+ line_orientation=&line_orientation_x[0];
+
+ // set up the new quad, line
+ // numbering is as indicated
+ // above
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[0],
+ line_indices[1],
+ line_indices[2],
+ line_indices[3]));
+
+ new_quads[0]->set_line_orientation(0,line_orientation[0]);
+ new_quads[0]->set_line_orientation(1,line_orientation[1]);
+ new_quads[0]->set_line_orientation(2,line_orientation[2]);
+ new_quads[0]->set_line_orientation(3,line_orientation[3]);
+
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // / | x
+ // / | *-------* *---------*
+ // * | | | / /
+ // | 0 | | | / /
+ // | * | | / /
+ // | / *-------*y *---------*x
+ // | /
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *---*---* *---*---*
+ // /| | | / / /|
+ // / | | | / 9 / 10/ |
+ // / | 5 | 6 | / / / |
+ // * | | | *---*---* |
+ // | 1 *---*---* | | | 2 *
+ // | / / / | | | /
+ // | / 7 / 8 / | 3 | 4 | /
+ // |/ / / | | |/
+ // *---*---* *---*---*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_x[11]
+ = {
+ new_quads[0]->index(), //0
+
+ hex->face(0)->index(), //1
+
+ hex->face(1)->index(), //2
+
+ hex->face(2)->child_index( child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]), //3
+ hex->face(2)->child_index(1-child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]),
+
+ hex->face(3)->child_index( child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]), //5
+ hex->face(3)->child_index(1-child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]),
+
+ hex->face(4)->child_index( child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]), //7
+ hex->face(4)->child_index(1-child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]),
+
+ hex->face(5)->child_index( child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]]), //9
+ hex->face(5)->child_index(1-child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]])
+
+ };
+ quad_indices=&quad_indices_x[0];
+
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[1],
+ quad_indices[0],
+ quad_indices[3],
+ quad_indices[5],
+ quad_indices[7],
+ quad_indices[9]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[0],
+ quad_indices[2],
+ quad_indices[4],
+ quad_indices[6],
+ quad_indices[8],
+ quad_indices[10]));
+ break;
+ }
+ case RefinementCase<dim>::cut_y:
+ {
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_y
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *---------*
+ // / /|
+ // *---------* |
+ // / /| |
+ // *---------* | |
+ // | | | |
+ // | | | *
+ // | | |/
+ // | | *
+ // | |/
+ // *---------*
+ //
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
- new_quads[0]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[10],
- line_indices[28],
- line_indices[16],
- line_indices[24]));
- new_quads[1]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[28],
- line_indices[14],
- line_indices[17],
- line_indices[25]));
- new_quads[2]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[11],
- line_indices[29],
- line_indices[24],
- line_indices[20]));
- new_quads[3]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[29],
- line_indices[15],
- line_indices[25],
- line_indices[21]));
- new_quads[4]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[18],
- line_indices[26],
- line_indices[0],
- line_indices[28]));
- new_quads[5]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[26],
- line_indices[22],
- line_indices[1],
- line_indices[29]));
- new_quads[6]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[19],
- line_indices[27],
- line_indices[28],
- line_indices[4]));
- new_quads[7]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[27],
- line_indices[23],
- line_indices[29],
- line_indices[5]));
- new_quads[8]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[2],
- line_indices[24],
- line_indices[8],
- line_indices[26]));
- new_quads[9]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[24],
- line_indices[6],
- line_indices[9],
- line_indices[27]));
- new_quads[10]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[3],
- line_indices[25],
- line_indices[26],
- line_indices[12]));
- new_quads[11]->set (internal::Triangulation
- ::TriaObject<2> (line_indices[25],
- line_indices[7],
- line_indices[27],
- line_indices[13]));
-
- // set flags
- for (unsigned int i=0; i<12; ++i)
- {
- new_quads[i]->set_used_flag();
- new_quads[i]->clear_user_flag();
- new_quads[i]->clear_user_data();
- new_quads[i]->clear_children();
- // interior quad
- new_quads[i]->set_boundary_indicator (255);
- // set all line orientation
- // flags to true, chnage this
- // afterwards, if necessary
- for (unsigned int j=0; j<GeometryInfo<dim>::lines_per_face; ++j)
- new_quads[i]->set_line_orientation(j,true);
- }
- // now reset the line_orientation
- // flags of outer lines as they
- // cannot be set in a loop (at
- // least not easily)
- new_quads[0]->set_line_orientation(0,line_orientation[10]);
- new_quads[0]->set_line_orientation(2,line_orientation[16]);
-
- new_quads[1]->set_line_orientation(1,line_orientation[14]);
- new_quads[1]->set_line_orientation(2,line_orientation[17]);
-
- new_quads[2]->set_line_orientation(0,line_orientation[11]);
- new_quads[2]->set_line_orientation(3,line_orientation[20]);
-
- new_quads[3]->set_line_orientation(1,line_orientation[15]);
- new_quads[3]->set_line_orientation(3,line_orientation[21]);
-
- new_quads[4]->set_line_orientation(0,line_orientation[18]);
- new_quads[4]->set_line_orientation(2,line_orientation[0]);
-
- new_quads[5]->set_line_orientation(1,line_orientation[22]);
- new_quads[5]->set_line_orientation(2,line_orientation[1]);
-
- new_quads[6]->set_line_orientation(0,line_orientation[19]);
- new_quads[6]->set_line_orientation(3,line_orientation[4]);
-
- new_quads[7]->set_line_orientation(1,line_orientation[23]);
- new_quads[7]->set_line_orientation(3,line_orientation[5]);
-
- new_quads[8]->set_line_orientation(0,line_orientation[2]);
- new_quads[8]->set_line_orientation(2,line_orientation[8]);
-
- new_quads[9]->set_line_orientation(1,line_orientation[6]);
- new_quads[9]->set_line_orientation(2,line_orientation[9]);
-
- new_quads[10]->set_line_orientation(0,line_orientation[3]);
- new_quads[10]->set_line_orientation(3,line_orientation[12]);
-
- new_quads[11]->set_line_orientation(1,line_orientation[7]);
- new_quads[11]->set_line_orientation(3,line_orientation[13]);
+ // face 0: left plane
+ // *
+ // /|
+ // * |
+ // /| |
+ // * | |
+ // | 0 |
+ // | | *
+ // | |/
+ // | *m0
+ // |/
+ // *
+ // face 1: right plane
+ // *
+ // /|
+ // m1* |
+ // /| |
+ // * | |
+ // | 1 |
+ // | | *
+ // | |/
+ // | *
+ // |/
+ // *
+ // face 4: bottom plane
+ // *-------*
+ // / /
+ // m0*---2---*
+ // / /
+ // *-------*
+ // face 5: top plane
+ // *-------*
+ // / /
+ // *---3---*m1
+ // / /
+ // *-------*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_y[4]
+ = {
+ hex->face(0)->child(0)
+ ->line((hex->face(0)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //0
+ hex->face(1)->child(0)
+ ->line((hex->face(1)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //1
+ hex->face(4)->child(0)
+ ->line((hex->face(4)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //2
+ hex->face(5)->child(0)
+ ->line((hex->face(5)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3) //3
+ };
+
+ lines=&lines_y[0];
+
+ unsigned int line_indices_y[4];
+
+ for (unsigned int i=0; i<4; ++i)
+ line_indices_y[i]=lines[i]->index();
+ line_indices=&line_indices_y[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_y[4];
+
+ // the middle vertice marked
+ // as m0 above is the start
+ // vertex for lines 0 and 2
+ // in standard orientation,
+ // whereas m1 is the end
+ // vertex of lines 1 and 3 in
+ // standard orientation
+ const unsigned int middle_vertices[2]=
+ {
+ hex->line(0)->child(0)->vertex_index(1),
+ hex->line(5)->child(0)->vertex_index(1)
+ };
+ for (unsigned int i=0; i<4; ++i)
+ if (lines[i]->vertex_index(i%2)==middle_vertices[i%2])
+ line_orientation_y[i]=true;
+ else
+ {
+ // it must be the other way round then
+ Assert(lines[i]->vertex_index((i+1)%2)==middle_vertices[i%2],
+ ExcInternalError());
+ line_orientation_y[i]=false;
+ }
+
+ line_orientation=&line_orientation_y[0];
+
+ // set up the new quad, line
+ // numbering is as indicated
+ // above
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[2],
+ line_indices[3],
+ line_indices[0],
+ line_indices[1]));
+
+ new_quads[0]->set_line_orientation(0,line_orientation[2]);
+ new_quads[0]->set_line_orientation(1,line_orientation[3]);
+ new_quads[0]->set_line_orientation(2,line_orientation[0]);
+ new_quads[0]->set_line_orientation(3,line_orientation[1]);
+
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // / | x
+ // / | *-------* *---------*
+ // * | | | / /
+ // | | | 0 | / /
+ // | * | | / /
+ // | / *-------*y *---------*x
+ // | /
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *-------* *-------*
+ // /| | / 10 /|
+ // * | | *-------* |
+ // /| | 6 | / 9 /| |
+ // * |2| | *-------* |4|
+ // | | *-------* | | | *
+ // |1|/ 8 / | |3|/
+ // | *-------* | 5 | *
+ // |/ 7 / | |/
+ // *-------* *-------*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_y[11]
+ = {
+ new_quads[0]->index(), //0
+
+ hex->face(0)->child_index( child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]), //1
+ hex->face(0)->child_index(1-child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]),
+
+ hex->face(1)->child_index( child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]), //3
+ hex->face(1)->child_index(1-child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]),
+
+ hex->face(2)->index(), //5
+
+ hex->face(3)->index(), //6
+
+ hex->face(4)->child_index( child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]), //7
+ hex->face(4)->child_index(1-child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]),
+
+ hex->face(5)->child_index( child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]]), //9
+ hex->face(5)->child_index(1-child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]])
+
+ };
+ quad_indices=&quad_indices_y[0];
+
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[1],
+ quad_indices[3],
+ quad_indices[5],
+ quad_indices[0],
+ quad_indices[7],
+ quad_indices[9]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[2],
+ quad_indices[4],
+ quad_indices[0],
+ quad_indices[6],
+ quad_indices[8],
+ quad_indices[10]));
+ break;
+ }
+ case RefinementCase<dim>::cut_z:
+ {
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_z
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *---------*
+ // / /|
+ // / / |
+ // / / *
+ // *---------* /|
+ // | | / |
+ // | |/ *
+ // *---------* /
+ // | | /
+ // | |/
+ // *---------*
+ //
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
+
+ // face 0: left plane
+ // *
+ // /|
+ // / |
+ // / *
+ // * /|
+ // | 0 |
+ // |/ *
+ // m0* /
+ // | /
+ // |/
+ // *
+ // face 1: right plane
+ // *
+ // /|
+ // / |
+ // / *m1
+ // * /|
+ // | 1 |
+ // |/ *
+ // * /
+ // | /
+ // |/
+ // *
+ // face 2: front plane
+ // (note: x,y exchanged)
+ // *-------*
+ // | |
+ // m0*---2---*
+ // | |
+ // *-------*
+ // face 3: back plane
+ // (note: x,y exchanged)
+ // *-------*
+ // | |
+ // *---3---*m1
+ // | |
+ // *-------*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_z[4]
+ = {
+ hex->face(0)->child(0)
+ ->line((hex->face(0)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //0
+ hex->face(1)->child(0)
+ ->line((hex->face(1)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //1
+ hex->face(2)->child(0)
+ ->line((hex->face(2)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //2
+ hex->face(3)->child(0)
+ ->line((hex->face(3)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3) //3
+ };
+
+ lines=&lines_z[0];
+
+ unsigned int line_indices_z[4];
+
+ for (unsigned int i=0; i<4; ++i)
+ line_indices_z[i]=lines[i]->index();
+ line_indices=&line_indices_z[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_z[4];
+
+ // the middle vertex marked
+ // as m0 above is the start
+ // vertex for lines 0 and 2
+ // in standard orientation,
+ // whereas m1 is the end
+ // vertex of lines 1 and 3 in
+ // standard orientation
+ const unsigned int middle_vertices[2]=
+ {
+ hex->line(8)->middle_vertex_index(),
+ hex->line(11)->middle_vertex_index()
+ };
- /////////////////////////////////
- // create the eight new hexes
- //
- // again first collect
- // some data. here, we
- // need the indices of a
- // whole lotta
- // quads. they are
- // numbered as follows:
- //
- // planes in the interior
- // of the old hex:
- // *
- // /|
- // * |
- // /|3* *---*---* *----*----*
- // * |/| | 5 | 7 | / 10 / 11 /
- // |2* | *---*---* *----*----*
- // |/|1* | 4 | 6 | / 8 / 9 /
- // * |/ *---*---*y *----*----*x
- // |0*
- // |/
- // *
- //
- // children of the faces
- // of the old hex
- // *-------* *-------*
- // /|25 27| /34 35/|
- // 15| | / /19
- // / | | /32 33/ |
- // * |24 26| *-------*18 |
- // 1413*-------* |21 23| 17*
- // | /30 31/ | | /
- // 12/ / | |16
- // |/28 29/ |20 22|/
- // *-------* *-------*
- //
- // note that we have to
- // take care of the
- // orientation of
- // faces.
- //
- // TODO: simplify this
- const unsigned int quad_indices[36]
- = {
- new_quads[0]->index(), //0
- new_quads[1]->index(),
- new_quads[2]->index(),
- new_quads[3]->index(),
- new_quads[4]->index(),
- new_quads[5]->index(),
- new_quads[6]->index(),
- new_quads[7]->index(),
- new_quads[8]->index(),
- new_quads[9]->index(),
- new_quads[10]->index(),
- new_quads[11]->index(), //11
-
- hex->face(0)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])), //12
- hex->face(0)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[0],f_fl[0],f_ro[0])),
- hex->face(0)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[0],f_fl[0],f_ro[0])),
- hex->face(0)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])),
-
- hex->face(1)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])), //16
- hex->face(1)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[1],f_fl[1],f_ro[1])),
- hex->face(1)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[1],f_fl[1],f_ro[1])),
- hex->face(1)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])),
-
- hex->face(2)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])), //20
- hex->face(2)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[2],f_fl[2],f_ro[2])),
- hex->face(2)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[2],f_fl[2],f_ro[2])),
- hex->face(2)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])),
-
- hex->face(3)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])), //24
- hex->face(3)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[3],f_fl[3],f_ro[3])),
- hex->face(3)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[3],f_fl[3],f_ro[3])),
- hex->face(3)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])),
-
- hex->face(4)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])), //28
- hex->face(4)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[4],f_fl[4],f_ro[4])),
- hex->face(4)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[4],f_fl[4],f_ro[4])),
- hex->face(4)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])),
-
- hex->face(5)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])), //32
- hex->face(5)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[5],f_fl[5],f_ro[5])),
- hex->face(5)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[5],f_fl[5],f_ro[5])),
- hex->face(5)->child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
- };
-
-
- // find some space for
- // the eight newly to be
- // created hexes. note
- // that there should
- // always be eight
- // consecutive free slots
- // for them
- raw_hex_iterator new_hexes[8];
-
- while (next_unused_hex->used() == true)
- ++next_unused_hex;
-
- for (unsigned int i=0; i<8; ++i)
- {
- new_hexes[i] = next_unused_hex;
- Assert (new_hexes[i]->used() == false,
- ExcCellShouldBeUnused());
- ++next_unused_hex;
- }
+ for (unsigned int i=0; i<4; ++i)
+ if (lines[i]->vertex_index(i%2)==middle_vertices[i%2])
+ line_orientation_z[i]=true;
+ else
+ {
+ // it must be the other way round then
+ Assert(lines[i]->vertex_index((i+1)%2)==middle_vertices[i%2],
+ ExcInternalError());
+ line_orientation_z[i]=false;
+ }
+
+ line_orientation=&line_orientation_z[0];
+
+ // set up the new quad, line
+ // numbering is as indicated
+ // above
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[0],
+ line_indices[1],
+ line_indices[2],
+ line_indices[3]));
+
+ new_quads[0]->set_line_orientation(0,line_orientation[0]);
+ new_quads[0]->set_line_orientation(1,line_orientation[1]);
+ new_quads[0]->set_line_orientation(2,line_orientation[2]);
+ new_quads[0]->set_line_orientation(3,line_orientation[3]);
+
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // / | x
+ // / | *-------* *---------*
+ // * | | | / /
+ // | | | | / 0 /
+ // | * | | / /
+ // | / *-------*y *---------*x
+ // | /
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *---*---* *-------*
+ // /| 8 | / /|
+ // / | | / 10 / |
+ // / *-------* / / *
+ // * 2/| | *-------* 4/|
+ // | / | 7 | | 6 | / |
+ // |/1 *-------* | |/3 *
+ // * / / *-------* /
+ // | / 9 / | | /
+ // |/ / | 5 |/
+ // *-------* *---*---*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_z[11]
+ = {
+ new_quads[0]->index(), //0
+
+ hex->face(0)->child_index( child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]), //1
+ hex->face(0)->child_index(1-child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]),
+
+ hex->face(1)->child_index( child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]), //3
+ hex->face(1)->child_index(1-child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]),
+
+ hex->face(2)->child_index( child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]), //5
+ hex->face(2)->child_index(1-child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]),
+
+ hex->face(3)->child_index( child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]), //7
+ hex->face(3)->child_index(1-child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]),
+
+ hex->face(4)->index(), //9
+
+ hex->face(5)->index() //10
+ };
+ quad_indices=&quad_indices_z[0];
+
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[1],
+ quad_indices[3],
+ quad_indices[5],
+ quad_indices[7],
+ quad_indices[9],
+ quad_indices[0]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[2],
+ quad_indices[4],
+ quad_indices[6],
+ quad_indices[8],
+ quad_indices[0],
+ quad_indices[10]));
+ break;
+ }
+ case RefinementCase<dim>::cut_xy:
+ {
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_xy
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *----*----*
+ // / / /|
+ // *----*----* |
+ // / / /| |
+ // *----*----* | |
+ // | | | | |
+ // | | | | *
+ // | | | |/
+ // | | | *
+ // | | |/
+ // *----*----*
+ //
+
+ // first, create the new
+ // internal line
+ new_lines[0]->set (internal::Triangulation::
+ TriaObject<1>(hex->face(4)->middle_vertex_index(),
+ hex->face(5)->middle_vertex_index()));
+
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
+
+ // face 0: left plane
+ // *
+ // /|
+ // * |
+ // /| |
+ // * | |
+ // | 0 |
+ // | | *
+ // | |/
+ // | *
+ // |/
+ // *
+ // face 1: right plane
+ // *
+ // /|
+ // * |
+ // /| |
+ // * | |
+ // | 1 |
+ // | | *
+ // | |/
+ // | *
+ // |/
+ // *
+ // face 2: front plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | | |
+ // | 2 |
+ // | | |
+ // *-------*
+ // face 3: back plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | | |
+ // | 3 |
+ // | | |
+ // *---*---*
+ // face 4: bottom plane
+ // *---*---*
+ // / 5 /
+ // *-6-*-7-*
+ // / 4 /
+ // *---*---*
+ // face 5: top plane
+ // *---*---*
+ // / 9 /
+ // *10-*-11*
+ // / 8 /
+ // *---*---*
+ // middle planes
+ // *-------* *---*---*
+ // / / | | |
+ // / / | 12 |
+ // / / | | |
+ // *-------* *---*---*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_xy[13]
+ = {
+ hex->face(0)->child(0)
+ ->line((hex->face(0)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //0
+ hex->face(1)->child(0)
+ ->line((hex->face(1)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //1
+ hex->face(2)->child(0)
+ ->line((hex->face(2)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //2
+ hex->face(3)->child(0)
+ ->line((hex->face(3)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //3
+
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[4],f_fl[4],f_ro[4])), //4
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[4],f_fl[4],f_ro[4])), //5
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[4],f_fl[4],f_ro[4])), //6
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[4],f_fl[4],f_ro[4])), //7
+
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[5],f_fl[5],f_ro[5])), //8
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[5],f_fl[5],f_ro[5])), //9
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[5],f_fl[5],f_ro[5])), //10
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[5],f_fl[5],f_ro[5])), //11
+
+ new_lines[0] //12
+ };
+
+ lines=&lines_xy[0];
+
+ unsigned int line_indices_xy[13];
+
+ for (unsigned int i=0; i<13; ++i)
+ line_indices_xy[i]=lines[i]->index();
+ line_indices=&line_indices_xy[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_xy[13];
+
+ // the middle vertices of the
+ // lines of our bottom face
+ const unsigned int middle_vertices[4]=
+ {
+ hex->line(0)->child(0)->vertex_index(1),
+ hex->line(1)->child(0)->vertex_index(1),
+ hex->line(2)->child(0)->vertex_index(1),
+ hex->line(3)->child(0)->vertex_index(1),
+ };
+
+ // note: for lines 0 to 3 the
+ // orientation of the line
+ // is 'true', if vertex 0 is
+ // on the bottom face
+ for (unsigned int i=0; i<4; ++i)
+ if (lines[i]->vertex_index(0)==middle_vertices[i])
+ line_orientation_xy[i]=true;
+ else
+ {
+ // it must be the other way round then
+ Assert(lines[i]->vertex_index(1)==middle_vertices[i],
+ ExcInternalError());
+ line_orientation_xy[i]=false;
+ }
+
+ // note: for lines 4 to 11
+ // (inner lines of the outer quads)
+ // the following holds: the second
+ // vertex of the even lines in
+ // standard orientation is the
+ // vertex in the middle of the
+ // quad, whereas for odd lines the
+ // first vertex is the same middle
+ // vertex.
+ for (unsigned int i=4; i<12; ++i)
+ if (lines[i]->vertex_index((i+1)%2)==hex->face(3+i/4)->middle_vertex_index())
+ line_orientation_xy[i]=true;
+ else
+ {
+ // it must be the other way
+ // round then
+ Assert(lines[i]->vertex_index(i%2)==hex->face(3+i/4)->middle_vertex_index(),
+ ExcInternalError());
+ line_orientation_xy[i]=false;
+ }
+ // for the last line the line
+ // orientation is always true,
+ // since it was just constructed
+ // that way
+
+ line_orientation_xy[12]=true;
+ line_orientation=&line_orientation_xy[0];
+
+ // set up the 4 quads,
+ // numbered as follows
+ // (left quad numbering,
+ // right line numbering
+ // extracted from above)
+ //
+ // * *
+ // /| 9|
+ // * | * |
+ // y/| | 8| 3
+ // * |1| * | |
+ // | | |x | 12|
+ // |0| * | | *
+ // | |/ 2 |5
+ // | * | *
+ // |/ |4
+ // * *
+ //
+ // x
+ // *---*---* *10-*-11*
+ // | | | | | |
+ // | 2 | 3 | 0 12 1
+ // | | | | | |
+ // *---*---*y *-6-*-7-*
+
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[2],
+ line_indices[12],
+ line_indices[4],
+ line_indices[8]));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[12],
+ line_indices[3],
+ line_indices[5],
+ line_indices[9]));
+ new_quads[2]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[6],
+ line_indices[10],
+ line_indices[0],
+ line_indices[12]));
+ new_quads[3]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[7],
+ line_indices[11],
+ line_indices[12],
+ line_indices[1]));
+
+ new_quads[0]->set_line_orientation(0,line_orientation[2]);
+ new_quads[0]->set_line_orientation(2,line_orientation[4]);
+ new_quads[0]->set_line_orientation(3,line_orientation[8]);
+
+ new_quads[1]->set_line_orientation(1,line_orientation[3]);
+ new_quads[1]->set_line_orientation(2,line_orientation[5]);
+ new_quads[1]->set_line_orientation(3,line_orientation[9]);
+
+ new_quads[2]->set_line_orientation(0,line_orientation[6]);
+ new_quads[2]->set_line_orientation(1,line_orientation[10]);
+ new_quads[2]->set_line_orientation(2,line_orientation[0]);
+
+ new_quads[3]->set_line_orientation(0,line_orientation[7]);
+ new_quads[3]->set_line_orientation(1,line_orientation[11]);
+ new_quads[3]->set_line_orientation(3,line_orientation[1]);
+
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // * | x
+ // /| | *---*---* *---------*
+ // * |1| | | | / /
+ // | | | | 2 | 3 | / /
+ // |0| * | | | / /
+ // | |/ *---*---*y *---------*x
+ // | *
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *---*---* *---*---*
+ // /| | | /18 / 19/|
+ // * |10 | 11| /---/---* |
+ // /| | | | /16 / 17/| |
+ // * |5| | | *---*---* |7|
+ // | | *---*---* | | | | *
+ // |4|/14 / 15/ | | |6|/
+ // | *---/---/ | 8 | 9 | *
+ // |/12 / 13/ | | |/
+ // *---*---* *---*---*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_xy[20]
+ = {
+ new_quads[0]->index(), //0
+ new_quads[1]->index(),
+ new_quads[2]->index(),
+ new_quads[3]->index(),
+
+ hex->face(0)->child_index( child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]), //4
+ hex->face(0)->child_index(1-child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]),
+
+ hex->face(1)->child_index( child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]), //6
+ hex->face(1)->child_index(1-child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]),
+
+ hex->face(2)->child_index( child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]), //8
+ hex->face(2)->child_index(1-child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]),
+
+ hex->face(3)->child_index( child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]), //10
+ hex->face(3)->child_index(1-child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]),
+
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])), //12
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[4],f_fl[4],f_ro[4])),
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[4],f_fl[4],f_ro[4])),
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])),
+
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])), //16
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[5],f_fl[5],f_ro[5])),
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[5],f_fl[5],f_ro[5])),
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
+ };
+ quad_indices=&quad_indices_xy[0];
+
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[4],
+ quad_indices[0],
+ quad_indices[8],
+ quad_indices[2],
+ quad_indices[12],
+ quad_indices[16]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[0],
+ quad_indices[6],
+ quad_indices[9],
+ quad_indices[3],
+ quad_indices[13],
+ quad_indices[17]));
+ new_hexes[2]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[5],
+ quad_indices[1],
+ quad_indices[2],
+ quad_indices[10],
+ quad_indices[14],
+ quad_indices[18]));
+ new_hexes[3]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[1],
+ quad_indices[7],
+ quad_indices[3],
+ quad_indices[11],
+ quad_indices[15],
+ quad_indices[19]));
+ break;
+ }
+ case RefinementCase<dim>::cut_xz:
+ {
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_xz
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *----*----*
+ // / / /|
+ // / / / |
+ // / / / *
+ // *----*----* /|
+ // | | | / |
+ // | | |/ *
+ // *----*----* /
+ // | | | /
+ // | | |/
+ // *----*----*
+ //
+
+ // first, create the new
+ // internal line
+ new_lines[0]->set (internal::Triangulation::
+ TriaObject<1>(hex->face(2)->middle_vertex_index(),
+ hex->face(3)->middle_vertex_index()));
+
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
+
+ // face 0: left plane
+ // *
+ // /|
+ // / |
+ // / *
+ // * /|
+ // | 0 |
+ // |/ *
+ // * /
+ // | /
+ // |/
+ // *
+ // face 1: right plane
+ // *
+ // /|
+ // / |
+ // / *
+ // * /|
+ // | 1 |
+ // |/ *
+ // * /
+ // | /
+ // |/
+ // *
+ // face 2: front plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | 5 |
+ // *-6-*-7-*
+ // | 4 |
+ // *---*---*
+ // face 3: back plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | 9 |
+ // *10-*-11*
+ // | 8 |
+ // *---*---*
+ // face 4: bottom plane
+ // *---*---*
+ // / / /
+ // / 2 /
+ // / / /
+ // *---*---*
+ // face 5: top plane
+ // *---*---*
+ // / / /
+ // / 3 /
+ // / / /
+ // *---*---*
+ // middle planes
+ // *---*---* *-------*
+ // / / / | |
+ // / 12 / | |
+ // / / / | |
+ // *---*---* *-------*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_xz[13]
+ = {
+ hex->face(0)->child(0)
+ ->line((hex->face(0)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //0
+ hex->face(1)->child(0)
+ ->line((hex->face(1)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //1
+ hex->face(4)->child(0)
+ ->line((hex->face(4)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //2
+ hex->face(5)->child(0)
+ ->line((hex->face(5)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //3
+
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[2],f_fl[2],f_ro[2])), //4
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[2],f_fl[2],f_ro[2])), //5
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[2],f_fl[2],f_ro[2])), //6
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[2],f_fl[2],f_ro[2])), //7
+
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[3],f_fl[3],f_ro[3])), //8
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[3],f_fl[3],f_ro[3])), //9
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[3],f_fl[3],f_ro[3])), //10
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[3],f_fl[3],f_ro[3])), //11
+
+ new_lines[0] //12
+ };
+
+ lines=&lines_xz[0];
+
+ unsigned int line_indices_xz[13];
+
+ for (unsigned int i=0; i<13; ++i)
+ line_indices_xz[i]=lines[i]->index();
+ line_indices=&line_indices_xz[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_xz[13];
+
+ // the middle vertices of the
+ // lines of our front face
+ const unsigned int middle_vertices[4]=
+ {
+ hex->line(8)->child(0)->vertex_index(1),
+ hex->line(9)->child(0)->vertex_index(1),
+ hex->line(2)->child(0)->vertex_index(1),
+ hex->line(6)->child(0)->vertex_index(1),
+ };
+
+ // note: for lines 0 to 3 the
+ // orientation of the line
+ // is 'true', if vertex 0 is
+ // on the front
+ for (unsigned int i=0; i<4; ++i)
+ if (lines[i]->vertex_index(0)==middle_vertices[i])
+ line_orientation_xz[i]=true;
+ else
+ {
+ // it must be the other way round then
+ Assert(lines[i]->vertex_index(1)==middle_vertices[i],
+ ExcInternalError());
+ line_orientation_xz[i]=false;
+ }
+
+ // note: for lines 4 to 11
+ // (inner lines of the outer quads)
+ // the following holds: the second
+ // vertex of the even lines in
+ // standard orientation is the
+ // vertex in the middle of the
+ // quad, whereas for odd lines the
+ // first vertex is the same middle
+ // vertex.
+ for (unsigned int i=4; i<12; ++i)
+ if (lines[i]->vertex_index((i+1)%2)==hex->face(1+i/4)->middle_vertex_index())
+ line_orientation_xz[i]=true;
+ else
+ {
+ // it must be the other way
+ // round then
+ Assert(lines[i]->vertex_index(i%2)==hex->face(1+i/4)->middle_vertex_index(),
+ ExcInternalError());
+ line_orientation_xz[i]=false;
+ }
+ // for the last line the line
+ // orientation is always true,
+ // since it was just constructed
+ // that way
+
+ line_orientation_xz[12]=true;
+ line_orientation=&line_orientation_xz[0];
+
+ // set up the 4 quads,
+ // numbered as follows
+ // (left quad numbering,
+ // right line numbering
+ // extracted from above),
+ // the drawings denote
+ // middle planes
+ //
+ // * *
+ // /| /|
+ // / | 3 9
+ // y/ * / *
+ // * 3/| * /|
+ // | / |x 5 12|8
+ // |/ * |/ *
+ // * 2/ * /
+ // | / 4 2
+ // |/ |/
+ // * *
+ //
+ // y
+ // *----*----* *-10-*-11-*
+ // / / / / / /
+ // / 0 / 1 / 0 12 1
+ // / / / / / /
+ // *----*----*x *--6-*--7-*
+
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[0],
+ line_indices[12],
+ line_indices[6],
+ line_indices[10]));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[12],
+ line_indices[1],
+ line_indices[7],
+ line_indices[11]));
+ new_quads[2]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[4],
+ line_indices[8],
+ line_indices[2],
+ line_indices[12]));
+ new_quads[3]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[5],
+ line_indices[9],
+ line_indices[12],
+ line_indices[3]));
+
+ new_quads[0]->set_line_orientation(0,line_orientation[0]);
+ new_quads[0]->set_line_orientation(2,line_orientation[6]);
+ new_quads[0]->set_line_orientation(3,line_orientation[10]);
+
+ new_quads[1]->set_line_orientation(1,line_orientation[1]);
+ new_quads[1]->set_line_orientation(2,line_orientation[7]);
+ new_quads[1]->set_line_orientation(3,line_orientation[11]);
+
+ new_quads[2]->set_line_orientation(0,line_orientation[4]);
+ new_quads[2]->set_line_orientation(1,line_orientation[8]);
+ new_quads[2]->set_line_orientation(2,line_orientation[2]);
+
+ new_quads[3]->set_line_orientation(0,line_orientation[5]);
+ new_quads[3]->set_line_orientation(1,line_orientation[9]);
+ new_quads[3]->set_line_orientation(3,line_orientation[3]);
+
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // / | x
+ // /3 * *-------* *----*----*
+ // * /| | | / / /
+ // | / | | | / 0 / 1 /
+ // |/ * | | / / /
+ // * 2/ *-------*y *----*----*x
+ // | /
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *---*---* *---*---*
+ // /|13 | 15| / / /|
+ // / | | | /18 / 19/ |
+ // / *---*---* / / / *
+ // * 5/| | | *---*---* 7/|
+ // | / |12 | 14| | 9 | 11| / |
+ // |/4 *---*---* | | |/6 *
+ // * / / / *---*---* /
+ // | /16 / 17/ | | | /
+ // |/ / / | 8 | 10|/
+ // *---*---* *---*---*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_xz[20]
+ = {
+ new_quads[0]->index(), //0
+ new_quads[1]->index(),
+ new_quads[2]->index(),
+ new_quads[3]->index(),
+
+ hex->face(0)->child_index( child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]), //4
+ hex->face(0)->child_index(1-child_at_origin[hex->face(0)->refinement_case()-1][f_fl[0]][f_ro[0]]),
+
+ hex->face(1)->child_index( child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]), //6
+ hex->face(1)->child_index(1-child_at_origin[hex->face(1)->refinement_case()-1][f_fl[1]][f_ro[1]]),
+
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])), //8
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[2],f_fl[2],f_ro[2])),
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[2],f_fl[2],f_ro[2])),
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])),
+
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])), //12
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[3],f_fl[3],f_ro[3])),
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[3],f_fl[3],f_ro[3])),
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])),
+
+ hex->face(4)->child_index( child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]), //16
+ hex->face(4)->child_index(1-child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]),
+
+ hex->face(5)->child_index( child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]]), //18
+ hex->face(5)->child_index(1-child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]])
+ };
+ quad_indices=&quad_indices_xz[0];
+
+ // due to the exchange of x
+ // and y for the front and
+ // back face, we order the
+ // children according to
+ //
+ // *---*---*
+ // | 1 | 3 |
+ // *---*---*
+ // | 0 | 2 |
+ // *---*---*
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[4],
+ quad_indices[2],
+ quad_indices[8],
+ quad_indices[12],
+ quad_indices[16],
+ quad_indices[0]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[5],
+ quad_indices[3],
+ quad_indices[9],
+ quad_indices[13],
+ quad_indices[0],
+ quad_indices[18]));
+ new_hexes[2]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[2],
+ quad_indices[6],
+ quad_indices[10],
+ quad_indices[14],
+ quad_indices[17],
+ quad_indices[1]));
+ new_hexes[3]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[3],
+ quad_indices[7],
+ quad_indices[11],
+ quad_indices[15],
+ quad_indices[1],
+ quad_indices[19]));
+ break;
+ }
+ case RefinementCase<dim>::cut_yz:
+ {
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_yz
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *---------*
+ // / /|
+ // *---------* |
+ // / /| |
+ // *---------* |/|
+ // | | * |
+ // | |/| *
+ // *---------* |/
+ // | | *
+ // | |/
+ // *---------*
+ //
+
+ // first, create the new
+ // internal line
+ new_lines[0]->set (internal::Triangulation::
+ TriaObject<1>(hex->face(0)->middle_vertex_index(),
+ hex->face(1)->middle_vertex_index()));
+
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
+ // (note that face 0 and
+ // 1 each are shown twice
+ // for better
+ // readability)
+
+ // face 0: left plane
+ // * *
+ // /| /|
+ // * | * |
+ // /| * /| *
+ // * 5/| * |7|
+ // | * | | * |
+ // |/| * |6| *
+ // * 4/ * |/
+ // | * | *
+ // |/ |/
+ // * *
+ // face 1: right plane
+ // * *
+ // /| /|
+ // * | * |
+ // /| * /| *
+ // * 9/| * |11
+ // | * | | * |
+ // |/| * |10 *
+ // * 8/ * |/
+ // | * | *
+ // |/ |/
+ // * *
+ // face 2: front plane
+ // (note: x,y exchanged)
+ // *-------*
+ // | |
+ // *---0---*
+ // | |
+ // *-------*
+ // face 3: back plane
+ // (note: x,y exchanged)
+ // *-------*
+ // | |
+ // *---1---*
+ // | |
+ // *-------*
+ // face 4: bottom plane
+ // *-------*
+ // / /
+ // *---2---*
+ // / /
+ // *-------*
+ // face 5: top plane
+ // *-------*
+ // / /
+ // *---3---*
+ // / /
+ // *-------*
+ // middle planes
+ // *-------* *-------*
+ // / / | |
+ // *---12--* | |
+ // / / | |
+ // *-------* *-------*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_yz[13]
+ = {
+ hex->face(2)->child(0)
+ ->line((hex->face(2)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //0
+ hex->face(3)->child(0)
+ ->line((hex->face(3)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //1
+ hex->face(4)->child(0)
+ ->line((hex->face(4)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //2
+ hex->face(5)->child(0)
+ ->line((hex->face(5)->refinement_case() == RefinementCase<dim>::cut_x) ? 1 : 3), //3
+
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0])), //4
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[0],f_fl[0],f_ro[0])), //5
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[0],f_fl[0],f_ro[0])), //6
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[0],f_fl[0],f_ro[0])), //7
+
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[1],f_fl[1],f_ro[1])), //8
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[1],f_fl[1],f_ro[1])), //9
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[1],f_fl[1],f_ro[1])), //10
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[1],f_fl[1],f_ro[1])), //11
+
+ new_lines[0] //12
+ };
+
+ lines=&lines_yz[0];
+
+ unsigned int line_indices_yz[13];
+
+ for (unsigned int i=0; i<13; ++i)
+ line_indices_yz[i]=lines[i]->index();
+ line_indices=&line_indices_yz[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_yz[13];
+
+ // the middle vertices of the
+ // lines of our front face
+ const unsigned int middle_vertices[4]=
+ {
+ hex->line(8)->child(0)->vertex_index(1),
+ hex->line(10)->child(0)->vertex_index(1),
+ hex->line(0)->child(0)->vertex_index(1),
+ hex->line(4)->child(0)->vertex_index(1),
+ };
+
+ // note: for lines 0 to 3 the
+ // orientation of the line
+ // is 'true', if vertex 0 is
+ // on the front
+ for (unsigned int i=0; i<4; ++i)
+ if (lines[i]->vertex_index(0)==middle_vertices[i])
+ line_orientation_yz[i]=true;
+ else
+ {
+ // it must be the other way round then
+ Assert(lines[i]->vertex_index(1)==middle_vertices[i],
+ ExcInternalError());
+ line_orientation_yz[i]=false;
+ }
+
+ // note: for lines 4 to 11
+ // (inner lines of the outer quads)
+ // the following holds: the second
+ // vertex of the even lines in
+ // standard orientation is the
+ // vertex in the middle of the
+ // quad, whereas for odd lines the
+ // first vertex is the same middle
+ // vertex.
+ for (unsigned int i=4; i<12; ++i)
+ if (lines[i]->vertex_index((i+1)%2)==hex->face(-1+i/4)->middle_vertex_index())
+ line_orientation_yz[i]=true;
+ else
+ {
+ // it must be the other way
+ // round then
+ Assert(lines[i]->vertex_index(i%2)==hex->face(-1+i/4)->middle_vertex_index(),
+ ExcInternalError());
+ line_orientation_yz[i]=false;
+ }
+ // for the last line the line
+ // orientation is always true,
+ // since it was just constructed
+ // that way
+
+ line_orientation_yz[12]=true;
+ line_orientation=&line_orientation_yz[0];
+
+ // set up the 4 quads,
+ // numbered as follows (left
+ // quad numbering, right line
+ // numbering extracted from
+ // above)
+ //
+ // x
+ // *-------* *---3---*
+ // | 3 | 5 9
+ // *-------* *---12--*
+ // | 2 | 4 8
+ // *-------*y *---2---*
+ //
+ // y
+ // *---------* *----1----*
+ // / 1 / 7 11
+ // *---------* *----12---*
+ // / 0 / 6 10
+ // *---------*x *----0----*
+
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[6],
+ line_indices[10],
+ line_indices[0],
+ line_indices[12]));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[7],
+ line_indices[11],
+ line_indices[12],
+ line_indices[1]));
+ new_quads[2]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[2],
+ line_indices[12],
+ line_indices[4],
+ line_indices[8]));
+ new_quads[3]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[12],
+ line_indices[3],
+ line_indices[5],
+ line_indices[9]));
+
+ new_quads[0]->set_line_orientation(0,line_orientation[6]);
+ new_quads[0]->set_line_orientation(1,line_orientation[10]);
+ new_quads[0]->set_line_orientation(2,line_orientation[0]);
+
+ new_quads[1]->set_line_orientation(0,line_orientation[7]);
+ new_quads[1]->set_line_orientation(1,line_orientation[11]);
+ new_quads[1]->set_line_orientation(3,line_orientation[1]);
+
+ new_quads[2]->set_line_orientation(0,line_orientation[2]);
+ new_quads[2]->set_line_orientation(2,line_orientation[4]);
+ new_quads[2]->set_line_orientation(3,line_orientation[8]);
+
+ new_quads[3]->set_line_orientation(1,line_orientation[3]);
+ new_quads[3]->set_line_orientation(2,line_orientation[5]);
+ new_quads[3]->set_line_orientation(3,line_orientation[9]);
+
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // / | x
+ // / | *-------* *---------*
+ // * | | 3 | / 1 /
+ // | | *-------* *---------*
+ // | * | 2 | / 0 /
+ // | / *-------*y *---------*x
+ // | /
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *-------* *-------*
+ // /| | / 19 /|
+ // * | 15 | *-------* |
+ // /|7*-------* / 18 /|11
+ // * |/| | *-------* |/|
+ // |6* | 14 | | 10* |
+ // |/|5*-------* | 13 |/|9*
+ // * |/ 17 / *-------* |/
+ // |4*-------* | |8*
+ // |/ 16 / | 12 |/
+ // *-------* *-------*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_yz[20]
+ = {
+ new_quads[0]->index(), //0
+ new_quads[1]->index(),
+ new_quads[2]->index(),
+ new_quads[3]->index(),
+
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])), //4
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[0],f_fl[0],f_ro[0])),
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[0],f_fl[0],f_ro[0])),
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])),
+
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])), //8
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[1],f_fl[1],f_ro[1])),
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[1],f_fl[1],f_ro[1])),
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])),
+
+ hex->face(2)->child_index( child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]), //12
+ hex->face(2)->child_index(1-child_at_origin[hex->face(2)->refinement_case()-1][f_fl[2]][f_ro[2]]),
+
+ hex->face(3)->child_index( child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]), //14
+ hex->face(3)->child_index(1-child_at_origin[hex->face(3)->refinement_case()-1][f_fl[3]][f_ro[3]]),
+
+ hex->face(4)->child_index( child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]), //16
+ hex->face(4)->child_index(1-child_at_origin[hex->face(4)->refinement_case()-1][f_fl[4]][f_ro[4]]),
+
+ hex->face(5)->child_index( child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]]), //18
+ hex->face(5)->child_index(1-child_at_origin[hex->face(5)->refinement_case()-1][f_fl[5]][f_ro[5]])
+ };
+ quad_indices=&quad_indices_yz[0];
+
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[4],
+ quad_indices[8],
+ quad_indices[12],
+ quad_indices[2],
+ quad_indices[16],
+ quad_indices[0]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[5],
+ quad_indices[9],
+ quad_indices[2],
+ quad_indices[14],
+ quad_indices[17],
+ quad_indices[1]));
+ new_hexes[2]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[6],
+ quad_indices[10],
+ quad_indices[13],
+ quad_indices[3],
+ quad_indices[0],
+ quad_indices[18]));
+ new_hexes[3]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[7],
+ quad_indices[11],
+ quad_indices[3],
+ quad_indices[15],
+ quad_indices[1],
+ quad_indices[19]));
+ break;
+ }
+ case RefinementCase<dim>::cut_xyz:
+ {
+ //////////////////////////////
+ //
+ // RefinementCase<dim>::cut_xyz
+ // isotropic refinement
+ //
+ // the refined cube will look
+ // like this:
+ //
+ // *----*----*
+ // / / /|
+ // *----*----* |
+ // / / /| *
+ // *----*----* |/|
+ // | | | * |
+ // | | |/| *
+ // *----*----* |/
+ // | | | *
+ // | | |/
+ // *----*----*
+ //
+
+ // find the next unused
+ // vertex and set it
+ // appropriately
+ while (vertices_used[next_unused_vertex] == true)
+ ++next_unused_vertex;
+ Assert (next_unused_vertex < vertices.size(),
+ ExcTooFewVerticesAllocated());
+ vertices_used[next_unused_vertex] = true;
+
+ // the new vertex is
+ // definitely in the
+ // interior, so we need not
+ // worry about the boundary.
+ // let it be the average of
+ // the 26 vertices
+ // surrounding it. weight
+ // these vertices in the same
+ // way as they are weighted
+ // in the
+ // @p{MappingQ::set_laplace_on_hex_vector}
+ // function, and like the new
+ // vertex at the center of
+ // the quad is weighted (see
+ // above)
+ vertices[next_unused_vertex] = Point<dim>();
+ // first add corners of hex
+ for (unsigned int vertex=0;
+ vertex<GeometryInfo<dim>::vertices_per_cell; ++vertex)
+ vertices[next_unused_vertex] += hex->vertex(vertex) / 128;
+ // now add center of lines
+ for (unsigned int line=0;
+ line<GeometryInfo<dim>::lines_per_cell; ++line)
+ vertices[next_unused_vertex] += hex->line(line)->child(0)->vertex(1) *
+ 7./192.;
+ // finally add centers of
+ // faces. note that vertex 3
+ // of child 0 is an invariant
+ // with respect to the face
+ // orientation, flip and
+ // rotation
+ for (unsigned int face=0;
+ face<GeometryInfo<dim>::faces_per_cell; ++face)
+ vertices[next_unused_vertex] += hex->face(face)->isotropic_child(0)->vertex(3) *
+ 1./12.;
+
+ // set the data of the
+ // six lines. first
+ // collect the indices of
+ // the seven vertices
+ // (consider the two
+ // planes to be crossed
+ // to form the planes
+ // cutting the hex in two
+ // vertically and
+ // horizontally)
+ // *--3--* *--5--*
+ // / / / | | |
+ // 0--6--1 0--6--1
+ // / / / | | |
+ // *--2--* *--4--*
+ // the lines are numbered
+ // as follows:
+ // *--*--* *--*--*
+ // / 1 / | 5 |
+ // *2-*-3* *2-*-3*
+ // / 0 / | 4 |
+ // *--*--* *--*--*
+ //
+ const unsigned int vertex_indices_xyz[7]
+ = { hex->face(0)->middle_vertex_index(),
+ hex->face(1)->middle_vertex_index(),
+ hex->face(2)->middle_vertex_index(),
+ hex->face(3)->middle_vertex_index(),
+ hex->face(4)->middle_vertex_index(),
+ hex->face(5)->middle_vertex_index(),
+ next_unused_vertex
+ };
+ vertex_indices=&vertex_indices_xyz[0];
+
+ new_lines[0]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[2], vertex_indices[6]));
+ new_lines[1]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[6], vertex_indices[3]));
+ new_lines[2]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[0], vertex_indices[6]));
+ new_lines[3]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[6], vertex_indices[1]));
+ new_lines[4]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[4], vertex_indices[6]));
+ new_lines[5]->set (internal::Triangulation::
+ TriaObject<1>(vertex_indices[6], vertex_indices[5]));
+
+ // again, first
+ // collect some data
+ // about the indices of
+ // the lines, with the
+ // following numbering:
+ // (note that face 0 and
+ // 1 each are shown twice
+ // for better
+ // readability)
+
+ // face 0: left plane
+ // * *
+ // /| /|
+ // * | * |
+ // /| * /| *
+ // * 1/| * |3|
+ // | * | | * |
+ // |/| * |2| *
+ // * 0/ * |/
+ // | * | *
+ // |/ |/
+ // * *
+ // face 1: right plane
+ // * *
+ // /| /|
+ // * | * |
+ // /| * /| *
+ // * 5/| * |7|
+ // | * | | * |
+ // |/| * |6| *
+ // * 4/ * |/
+ // | * | *
+ // |/ |/
+ // * *
+ // face 2: front plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | 11 |
+ // *-8-*-9-*
+ // | 10 |
+ // *---*---*
+ // face 3: back plane
+ // (note: x,y exchanged)
+ // *---*---*
+ // | 15 |
+ // *12-*-13*
+ // | 14 |
+ // *---*---*
+ // face 4: bottom plane
+ // *---*---*
+ // / 17 /
+ // *18-*-19*
+ // / 16 /
+ // *---*---*
+ // face 5: top plane
+ // *---*---*
+ // / 21 /
+ // *22-*-23*
+ // / 20 /
+ // *---*---*
+ // middle planes
+ // *---*---* *---*---*
+ // / 25 / | 29 |
+ // *26-*-27* *26-*-27*
+ // / 24 / | 28 |
+ // *---*---* *---*---*
+
+ // set up a list of line iterators
+ // first. from this, construct
+ // lists of line_indices and
+ // line orientations later on
+ const raw_line_iterator lines_xyz[30]
+ = {
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0])), //0
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[0],f_fl[0],f_ro[0])), //1
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[0],f_fl[0],f_ro[0])), //2
+ hex->face(0)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[0],f_fl[0],f_ro[0])), //3
+
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[1],f_fl[1],f_ro[1])), //4
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[1],f_fl[1],f_ro[1])), //5
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[1],f_fl[1],f_ro[1])), //6
+ hex->face(1)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[1],f_fl[1],f_ro[1])), //7
+
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[2],f_fl[2],f_ro[2])), //8
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[2],f_fl[2],f_ro[2])), //9
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[2],f_fl[2],f_ro[2])), //10
+ hex->face(2)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[2],f_fl[2],f_ro[2])), //11
+
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[3],f_fl[3],f_ro[3])), //12
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[3],f_fl[3],f_ro[3])), //13
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[3],f_fl[3],f_ro[3])), //14
+ hex->face(3)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[3],f_fl[3],f_ro[3])), //15
+
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[4],f_fl[4],f_ro[4])), //16
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[4],f_fl[4],f_ro[4])), //17
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[4],f_fl[4],f_ro[4])), //18
+ hex->face(4)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[4],f_fl[4],f_ro[4])), //19
+
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[5],f_fl[5],f_ro[5])), //20
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(0,f_or[5],f_fl[5],f_ro[5])), //21
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(3,f_or[5],f_fl[5],f_ro[5])), //22
+ hex->face(5)->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(2,f_or[5],f_fl[5],f_ro[5])), //23
+
+ new_lines[0], //24
+ new_lines[1], //25
+ new_lines[2], //26
+ new_lines[3], //27
+ new_lines[4], //28
+ new_lines[5] //29
+ };
+
+ lines=&lines_xyz[0];
+
+ unsigned int line_indices_xyz[30];
+ for (unsigned int i=0; i<30; ++i)
+ line_indices_xyz[i]=lines[i]->index();
+ line_indices=&line_indices_xyz[0];
+
+ // the orientation of lines for the
+ // inner quads is quite tricky. as
+ // these lines are newly created
+ // ones and thus have no parents,
+ // they cannot inherit this
+ // property. set up an array and
+ // fill it with the respective
+ // values
+ bool line_orientation_xyz[30];
+
+ // note: for the first 24 lines
+ // (inner lines of the outer quads)
+ // the following holds: the second
+ // vertex of the even lines in
+ // standard orientation is the
+ // vertex in the middle of the
+ // quad, whereas for odd lines the
+ // first vertex is the same middle
+ // vertex.
+ // DEBUG
+ face_iterator face_0=hex->face(0);
+ face_iterator face_0_child_0=face_0->isotropic_child(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0]));
+ line_iterator face_0_child_0_line_1=face_0_child_0
+ ->line(GeometryInfo<dim>::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0]));
+ // END DEBUG
+ for (unsigned int i=0; i<24; ++i)
+ if (lines[i]->vertex_index((i+1)%2)==vertex_indices[i/4])
+ line_orientation_xyz[i]=true;
+ else
+ {
+ // it must be the other way
+ // round then
+ Assert(lines[i]->vertex_index(i%2)==vertex_indices[i/4],
+ ExcInternalError());
+ line_orientation_xyz[i]=false;
+ }
+ // for the last 6 lines the line
+ // orientation is always true,
+ // since they were just constructed
+ // that way
+ for (unsigned int i=24; i<30; ++i)
+ line_orientation_xyz[i]=true;
+ line_orientation=&line_orientation_xyz[0];
+
+ // set up the 12 quads,
+ // numbered as follows
+ // (left quad numbering,
+ // right line numbering
+ // extracted from above)
+ //
+ // * *
+ // /| 21|
+ // * | * 15
+ // y/|3* 20| *
+ // * |/| * |/|
+ // |2* |x 11 * 14
+ // |/|1* |/| *
+ // * |/ * |17
+ // |0* 10 *
+ // |/ |16
+ // * *
+ //
+ // x
+ // *---*---* *22-*-23*
+ // | 5 | 7 | 1 29 5
+ // *---*---* *26-*-27*
+ // | 4 | 6 | 0 28 4
+ // *---*---*y *18-*-19*
+ //
+ // y
+ // *----*----* *-12-*-13-*
+ // / 10 / 11 / 3 25 7
+ // *----*----* *-26-*-27-*
+ // / 8 / 9 / 2 24 6
+ // *----*----*x *--8-*--9-*
+
+ new_quads[0]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[10],
+ line_indices[28],
+ line_indices[16],
+ line_indices[24]));
+ new_quads[1]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[28],
+ line_indices[14],
+ line_indices[17],
+ line_indices[25]));
+ new_quads[2]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[11],
+ line_indices[29],
+ line_indices[24],
+ line_indices[20]));
+ new_quads[3]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[29],
+ line_indices[15],
+ line_indices[25],
+ line_indices[21]));
+ new_quads[4]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[18],
+ line_indices[26],
+ line_indices[0],
+ line_indices[28]));
+ new_quads[5]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[26],
+ line_indices[22],
+ line_indices[1],
+ line_indices[29]));
+ new_quads[6]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[19],
+ line_indices[27],
+ line_indices[28],
+ line_indices[4]));
+ new_quads[7]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[27],
+ line_indices[23],
+ line_indices[29],
+ line_indices[5]));
+ new_quads[8]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[2],
+ line_indices[24],
+ line_indices[8],
+ line_indices[26]));
+ new_quads[9]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[24],
+ line_indices[6],
+ line_indices[9],
+ line_indices[27]));
+ new_quads[10]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[3],
+ line_indices[25],
+ line_indices[26],
+ line_indices[12]));
+ new_quads[11]->set (internal::Triangulation
+ ::TriaObject<2>(line_indices[25],
+ line_indices[7],
+ line_indices[27],
+ line_indices[13]));
+
+ // now reset the line_orientation
+ // flags of outer lines as they
+ // cannot be set in a loop (at
+ // least not easily)
+ new_quads[0]->set_line_orientation(0,line_orientation[10]);
+ new_quads[0]->set_line_orientation(2,line_orientation[16]);
+
+ new_quads[1]->set_line_orientation(1,line_orientation[14]);
+ new_quads[1]->set_line_orientation(2,line_orientation[17]);
+
+ new_quads[2]->set_line_orientation(0,line_orientation[11]);
+ new_quads[2]->set_line_orientation(3,line_orientation[20]);
- // note these hexes as
- // children to the
- // present cell
- hex->set_children (new_hexes[0]->index());
-
- // bottom children
- new_hexes[0]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[12],
- quad_indices[0],
- quad_indices[20],
- quad_indices[4],
- quad_indices[28],
- quad_indices[8]));
- new_hexes[1]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[0],
- quad_indices[16],
- quad_indices[22],
- quad_indices[6],
- quad_indices[29],
- quad_indices[9]));
- new_hexes[2]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[13],
- quad_indices[1],
- quad_indices[4],
- quad_indices[24],
- quad_indices[30],
- quad_indices[10]));
- new_hexes[3]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[1],
- quad_indices[17],
- quad_indices[6],
- quad_indices[26],
- quad_indices[31],
- quad_indices[11]));
+ new_quads[3]->set_line_orientation(1,line_orientation[15]);
+ new_quads[3]->set_line_orientation(3,line_orientation[21]);
+
+ new_quads[4]->set_line_orientation(0,line_orientation[18]);
+ new_quads[4]->set_line_orientation(2,line_orientation[0]);
+
+ new_quads[5]->set_line_orientation(1,line_orientation[22]);
+ new_quads[5]->set_line_orientation(2,line_orientation[1]);
+
+ new_quads[6]->set_line_orientation(0,line_orientation[19]);
+ new_quads[6]->set_line_orientation(3,line_orientation[4]);
+
+ new_quads[7]->set_line_orientation(1,line_orientation[23]);
+ new_quads[7]->set_line_orientation(3,line_orientation[5]);
+
+ new_quads[8]->set_line_orientation(0,line_orientation[2]);
+ new_quads[8]->set_line_orientation(2,line_orientation[8]);
+
+ new_quads[9]->set_line_orientation(1,line_orientation[6]);
+ new_quads[9]->set_line_orientation(2,line_orientation[9]);
+
+ new_quads[10]->set_line_orientation(0,line_orientation[3]);
+ new_quads[10]->set_line_orientation(3,line_orientation[12]);
+
+ new_quads[11]->set_line_orientation(1,line_orientation[7]);
+ new_quads[11]->set_line_orientation(3,line_orientation[13]);
+
+ /////////////////////////////////
+ // create the eight new hexes
+ //
+ // again first collect
+ // some data. here, we
+ // need the indices of a
+ // whole lotta
+ // quads.
- // top children
- new_hexes[4]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[14],
- quad_indices[2],
- quad_indices[21],
- quad_indices[5],
- quad_indices[8],
- quad_indices[32]));
- new_hexes[5]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[2],
- quad_indices[18],
- quad_indices[23],
- quad_indices[7],
- quad_indices[9],
- quad_indices[33]));
- new_hexes[6]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[15],
- quad_indices[3],
- quad_indices[5],
- quad_indices[25],
- quad_indices[10],
- quad_indices[34]));
- new_hexes[7]->set (internal::Triangulation
- ::TriaObject<3>(quad_indices[3],
- quad_indices[19],
- quad_indices[7],
- quad_indices[27],
- quad_indices[11],
- quad_indices[35]));
-
-
- for (unsigned int i=0; i<8; ++i)
- {
- new_hexes[i]->set_used_flag();
- new_hexes[i]->clear_user_flag();
- new_hexes[i]->clear_user_data();
- new_hexes[i]->clear_children();
- // inherit material
- // properties
- new_hexes[i]->set_material_id (hex->material_id());
- new_hexes[i]->set_subdomain_id (hex->subdomain_id());
- }
-
- // and set face
- // orientation
- // flags. note that
- // new faces in the
- // interior of the
- // mother cell always
- // have a correctly
- // oriented face, but
- // the ones on the
- // outer faces will
- // inherit this flag
+ // the quads are
+ // numbered as follows:
+ //
+ // planes in the interior
+ // of the old hex:
+ // *
+ // /|
+ // * |
+ // /|3* *---*---* *----*----*
+ // * |/| | 5 | 7 | / 10 / 11 /
+ // |2* | *---*---* *----*----*
+ // |/|1* | 4 | 6 | / 8 / 9 /
+ // * |/ *---*---*y *----*----*x
+ // |0*
+ // |/
+ // *
+ //
+ // children of the faces
+ // of the old hex
+ // *-------* *-------*
+ // /|25 27| /34 35/|
+ // 15| | / /19
+ // / | | /32 33/ |
+ // * |24 26| *-------*18 |
+ // 1413*-------* |21 23| 17*
+ // | /30 31/ | | /
+ // 12/ / | |16
+ // |/28 29/ |20 22|/
+ // *-------* *-------*
+ //
+ // note that we have to
+ // take care of the
+ // orientation of
+ // faces.
+ const unsigned int quad_indices_xyz[36]
+ = {
+ new_quads[0]->index(), //0
+ new_quads[1]->index(),
+ new_quads[2]->index(),
+ new_quads[3]->index(),
+ new_quads[4]->index(),
+ new_quads[5]->index(),
+ new_quads[6]->index(),
+ new_quads[7]->index(),
+ new_quads[8]->index(),
+ new_quads[9]->index(),
+ new_quads[10]->index(),
+ new_quads[11]->index(), //11
+
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])), //12
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[0],f_fl[0],f_ro[0])),
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[0],f_fl[0],f_ro[0])),
+ hex->face(0)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])),
+
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])), //16
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[1],f_fl[1],f_ro[1])),
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[1],f_fl[1],f_ro[1])),
+ hex->face(1)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])),
+
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])), //20
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[2],f_fl[2],f_ro[2])),
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[2],f_fl[2],f_ro[2])),
+ hex->face(2)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])),
+
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])), //24
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[3],f_fl[3],f_ro[3])),
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[3],f_fl[3],f_ro[3])),
+ hex->face(3)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])),
+
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])), //28
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[4],f_fl[4],f_ro[4])),
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[4],f_fl[4],f_ro[4])),
+ hex->face(4)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])),
+
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])), //32
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(1,f_or[5],f_fl[5],f_ro[5])),
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(2,f_or[5],f_fl[5],f_ro[5])),
+ hex->face(5)->isotropic_child_index(GeometryInfo<dim>::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5]))
+ };
+ quad_indices=&quad_indices_xyz[0];
+
+ // bottom children
+ new_hexes[0]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[12],
+ quad_indices[0],
+ quad_indices[20],
+ quad_indices[4],
+ quad_indices[28],
+ quad_indices[8]));
+ new_hexes[1]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[0],
+ quad_indices[16],
+ quad_indices[22],
+ quad_indices[6],
+ quad_indices[29],
+ quad_indices[9]));
+ new_hexes[2]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[13],
+ quad_indices[1],
+ quad_indices[4],
+ quad_indices[24],
+ quad_indices[30],
+ quad_indices[10]));
+ new_hexes[3]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[1],
+ quad_indices[17],
+ quad_indices[6],
+ quad_indices[26],
+ quad_indices[31],
+ quad_indices[11]));
+
+ // top children
+ new_hexes[4]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[14],
+ quad_indices[2],
+ quad_indices[21],
+ quad_indices[5],
+ quad_indices[8],
+ quad_indices[32]));
+ new_hexes[5]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[2],
+ quad_indices[18],
+ quad_indices[23],
+ quad_indices[7],
+ quad_indices[9],
+ quad_indices[33]));
+ new_hexes[6]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[15],
+ quad_indices[3],
+ quad_indices[5],
+ quad_indices[25],
+ quad_indices[10],
+ quad_indices[34]));
+ new_hexes[7]->set (internal::Triangulation
+ ::TriaObject<3>(quad_indices[3],
+ quad_indices[19],
+ quad_indices[7],
+ quad_indices[27],
+ quad_indices[11],
+ quad_indices[35]));
+ break;
+ }
+ default:
+ // all refinement cases
+ // have been treated,
+ // there only remains
+ // RefinementCase<dim>::no_refinement
+ // as untreated
+ // enumeration
+ // value. However, in
+ // that case we should
+ // have aborted much
+ // earlier. thus we
+ // should never get here
+ Assert(false, ExcInternalError());
+ break;
+ }//switch (ref_case)
+
+ // and set face orientation
+ // flags. note that new faces in
+ // the interior of the mother cell
+ // always have a correctly oriented
+ // face, but the ones on the outer
+ // faces will inherit this flag
//
- // set the flag to true
- // for all faces
- // initially, then go the
- // other way round and
- // reset faces that are
- // at the boundary of the
- // mother cube
+ // the flag have been set to true
+ // for all faces initially, now go
+ // the other way round and reset
+ // faces that are at the boundary
+ // of the mother cube
//
// the same is true for the
// face_flip and face_rotation
// flags. however, the latter two
// are set to false by default as
// this is the standard value
- for (unsigned int i=0; i<8; ++i)
- for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
- {
- new_hexes[i]->set_face_orientation(f, true);
- new_hexes[i]->set_face_flip(f, false);
- new_hexes[i]->set_face_rotation(f, false);
- }
+ // loop over all faces and all
+ // (relevant) subfaces of that in
+ // order to set the correct values
+ // for face_orientation, face_flip
+ // and face_rotation, which are
+ // inherited from the corresponding
+ // face of the mother cube
for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
- for (unsigned int s=0; s<GeometryInfo<dim>::subfaces_per_face; ++s)
+ for (unsigned int s=0;
+ s<std::max(GeometryInfo<dim-1>::n_children(GeometryInfo<dim>::face_refinement_case(ref_case,f)),
+ 1U);
+ ++s)
{
- new_hexes[GeometryInfo<dim>::child_cell_on_face(f,s)]
- ->set_face_orientation(f, hex->face_orientation(f));
- new_hexes[GeometryInfo<dim>::child_cell_on_face(f,s)]
- ->set_face_flip(f, hex->face_flip(f));
- new_hexes[GeometryInfo<dim>::child_cell_on_face(f,s)]
- ->set_face_rotation(f, hex->face_rotation(f));
+ const unsigned int current_child
+ =GeometryInfo<dim>::child_cell_on_face(ref_case,
+ f,
+ s,
+ f_or[f],
+ f_fl[f],
+ f_ro[f],
+ GeometryInfo<dim>::face_refinement_case(ref_case,
+ f,
+ f_or[f],
+ f_fl[f],
+ f_ro[f]));
+ new_hexes[current_child]->set_face_orientation (f, f_or[f]);
+ new_hexes[current_child]->set_face_flip (f, f_fl[f]);
+ new_hexes[current_child]->set_face_rotation (f, f_ro[f]);
}
-
-#ifdef DEBUG
- // check consistency
- // against
- // GeometryInfo<3>::child_cell_on_face
- for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
- for (unsigned int s=0; s<GeometryInfo<dim>::subfaces_per_face; ++s)
- Assert(hex->face(f)->child(s)==hex->child(
- GeometryInfo<dim>::child_cell_on_face(
- f, s, hex->face_orientation(f), hex->face_flip(f), hex->face_rotation(f)))->face(f), ExcInternalError());
-#endif
/////////////////////////////////
// now the only thing still
// neighborship
// information.
//
- // to do so, first
- // collect the iterators
- // pointing to the 6x4
- // neighbors of this
- // cell.
- //
- // note that in case the
- // neighboring cell is
- // not refined, the
- // neighbor iterators
- // point to the common
- // mother cell. the same
- // applies if there is no
- // neighbor: the
- // iterators are past the
- // end
- cell_iterator neighbor_cells[6][4];
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell;
- ++face)
+ // the easiest part is setting the
+ // inner neighbors, i.e. children
+ // neighboring other children of
+ // the same mother cube.
+ switch (static_cast<unsigned char> (ref_case))
{
- const cell_iterator neighbor = hex->neighbor(face);
-
- // if no neighbor
- if (neighbor.state() != IteratorState::valid)
- for (unsigned int child_face=0;
- child_face<GeometryInfo<dim>::subfaces_per_face;
- ++child_face)
- neighbor_cells[face][child_face] = neighbor;
-
- else
- // neighbor exists
- {
- // neighbor's
- // level must not
- // be higher
- // (else
- // something went
- // wrong when
- // constructing
- // either of the
- // two cells) and
- // not lower
- // since then
- // this cell
- // should not
- // have been
- // refined.
- Assert (neighbor->level() == hex->level(),
- ExcInternalError());
+ case RefinementCase<dim>::cut_x:
+ new_hexes[0]->set_neighbor(1, new_hexes[1]);
+
+ new_hexes[1]->set_neighbor(0, new_hexes[0]);
+ break;
+ case RefinementCase<dim>::cut_y:
+ new_hexes[0]->set_neighbor(3, new_hexes[1]);
+
+ new_hexes[1]->set_neighbor(2, new_hexes[0]);
+ break;
+ case RefinementCase<dim>::cut_z:
+ new_hexes[0]->set_neighbor(5, new_hexes[1]);
+
+ new_hexes[1]->set_neighbor(4, new_hexes[0]);
+ break;
+ case RefinementCase<dim>::cut_xy:
+ new_hexes[0]->set_neighbor(1, new_hexes[1]);
+ new_hexes[0]->set_neighbor(3, new_hexes[2]);
+
+ new_hexes[1]->set_neighbor(0, new_hexes[0]);
+ new_hexes[1]->set_neighbor(3, new_hexes[3]);
+
+ new_hexes[2]->set_neighbor(1, new_hexes[3]);
+ new_hexes[2]->set_neighbor(2, new_hexes[0]);
+
+ new_hexes[3]->set_neighbor(0, new_hexes[2]);
+ new_hexes[3]->set_neighbor(2, new_hexes[1]);
+ break;
+ case RefinementCase<dim>::cut_xz:
+ new_hexes[0]->set_neighbor(1, new_hexes[2]);
+ new_hexes[0]->set_neighbor(5, new_hexes[1]);
- // now there are
- // two
- // possibilities:
- // either the
- // neighbor has
- // no children or
- // it has
- // children. these
- // must be
- // terminal then.
- if (!neighbor->has_children())
- for (unsigned int child_face=0;
- child_face<GeometryInfo<dim>::subfaces_per_face;
- ++child_face)
- neighbor_cells[face][child_face] = neighbor;
- else
- // neighbor has
- // children;
- // now it's
- // getting
- // complicated
- {
- // first find
- // the face
- // of the
- // neighbor
- // adjacent
- // to which
- // the
- // present
- // cell is
- const unsigned int nb_nb = hex->neighbor_of_neighbor(face);
- Assert (nb_nb<GeometryInfo<dim>::faces_per_cell,
- ExcInternalError());
-
- // now the
- // four child
- // cells of
- // neighbor
- // adjacent
- // to the
- // present
- // cell can
- // be
- // obtained
- // by a
- // function
- // of
- // GeometryInfo. however,
- // if our face or the
- // neighbor's
- // face has
- // non-standard
- // orientation, flip or rotation,
- // then we
- // run into
- // trouble
- // and have
- // to swap
- // subfaces
- // to account
- // for
- // that.
- //
- // it is quite
- // difficult to find
- // out, which neighbors
- // child is adjacent to
- // a given child of our
- // current cell. it is
- // easier to determine
- // the children
- // adjacent to a given
- // subface in both
- // cases. here, we
- // consider that for
- // the neighbor, when
- // we set the neighbors
- // of our children we
- // will consider it for
- // the children of our
- // current cell.
-
- for (unsigned int c=0;
- c<GeometryInfo<dim>::subfaces_per_face; ++c)
- {
- neighbor_cells[face][c]
- = neighbor->child(GeometryInfo<dim>::
- child_cell_on_face(nb_nb, c,
- neighbor->face_orientation(nb_nb),
- neighbor->face_flip(nb_nb),
- neighbor->face_rotation(nb_nb)));
-
- Assert (neighbor_cells[face][c].state() ==
- IteratorState::valid,
- ExcInternalError());
- Assert (!neighbor_cells[face][c]->has_children(),
- ExcInternalError());
- }
- }
- }
- }
+ new_hexes[1]->set_neighbor(1, new_hexes[3]);
+ new_hexes[1]->set_neighbor(4, new_hexes[0]);
- // now we've got all
- // neighbors, so set them
- // in the new cells
-
- // the subface ordering
- // is as follows
- // face 0 and 1:
- // *
- // /|
- // * |
- // y/|3*
- // * |/|
- // |2* |x
- // |/|1*
- // * |/
- // |0*
- // |/
- // *
- // face 2 and 3:
- // x
- // *---*---*
- // | 1 | 3 |
- // *---*---*
- // | 0 | 2 |
- // *---*---*y
- // face 4 and 5:
- // y
- // *---*---*
- // / 2 / 3 /
- // *---*---*
- // / 0 / 1 /
- // *---*---*x
-
- // Step 1: set all 'outer neighbors'
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- for (unsigned int sub=0; sub<GeometryInfo<dim>::subfaces_per_face; ++sub)
- new_hexes[GeometryInfo<dim>::
- child_cell_on_face(face,sub,
- hex->face_orientation(face),
- hex->face_flip(face),
- hex->face_rotation(face))]
- ->set_neighbor(face,neighbor_cells[face][sub]);
- // Step 2: set all 'inner
- // neighbors', i.e. neighbors that
- // are itself children of our
- // current cell
-
- // TODO: do we really want to test
- // (assert) this static information
- // for each cell?
- new_hexes[0]->set_neighbor (1, new_hexes[1]);
- new_hexes[0]->set_neighbor (3, new_hexes[2]);
- new_hexes[0]->set_neighbor (5, new_hexes[4]);
- Assert(GeometryInfo<dim>::child_cell_on_face(0,0)==0, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(2,0)==0, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(4,0)==0, ExcInternalError());
-
- new_hexes[1]->set_neighbor (0, new_hexes[0]);
- new_hexes[1]->set_neighbor (3, new_hexes[3]);
- new_hexes[1]->set_neighbor (5, new_hexes[5]);
- Assert(GeometryInfo<dim>::child_cell_on_face(1,0)==1, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(2,2)==1, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(4,1)==1, ExcInternalError());
-
- new_hexes[2]->set_neighbor (1, new_hexes[3]);
- new_hexes[2]->set_neighbor (2, new_hexes[0]);
- new_hexes[2]->set_neighbor (5, new_hexes[6]);
- Assert(GeometryInfo<dim>::child_cell_on_face(0,1)==2, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(3,0)==2, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(4,2)==2, ExcInternalError());
-
- new_hexes[3]->set_neighbor (0, new_hexes[2]);
- new_hexes[3]->set_neighbor (2, new_hexes[1]);
- new_hexes[3]->set_neighbor (5, new_hexes[7]);
- Assert(GeometryInfo<dim>::child_cell_on_face(1,1)==3, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(3,2)==3, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(4,3)==3, ExcInternalError());
-
- new_hexes[4]->set_neighbor (1, new_hexes[5]);
- new_hexes[4]->set_neighbor (3, new_hexes[6]);
- new_hexes[4]->set_neighbor (4, new_hexes[0]);
- Assert(GeometryInfo<dim>::child_cell_on_face(0,2)==4, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(2,1)==4, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(5,0)==4, ExcInternalError());
-
- new_hexes[5]->set_neighbor (0, new_hexes[4]);
- new_hexes[5]->set_neighbor (3, new_hexes[7]);
- new_hexes[5]->set_neighbor (4, new_hexes[1]);
- Assert(GeometryInfo<dim>::child_cell_on_face(1,2)==5, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(2,3)==5, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(5,1)==5, ExcInternalError());
-
- new_hexes[6]->set_neighbor (1, new_hexes[7]);
- new_hexes[6]->set_neighbor (2, new_hexes[4]);
- new_hexes[6]->set_neighbor (4, new_hexes[2]);
- Assert(GeometryInfo<dim>::child_cell_on_face(0,3)==6, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(3,1)==6, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(5,2)==6, ExcInternalError());
-
- new_hexes[7]->set_neighbor (0, new_hexes[6]);
- new_hexes[7]->set_neighbor (2, new_hexes[5]);
- new_hexes[7]->set_neighbor (4, new_hexes[3]);
- Assert(GeometryInfo<dim>::child_cell_on_face(1,3)==7, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(3,3)==7, ExcInternalError());
- Assert(GeometryInfo<dim>::child_cell_on_face(5,3)==7, ExcInternalError());
-
-
- // now we need to set the
- // neighbors' neighborship
- // information; this is
- // only necessary if the
- // neighboring cell is
- // refined, i.e. is on
- // the same level as the
- // new children of the
- // present cell
- for (unsigned int nb=0; nb<GeometryInfo<dim>::faces_per_cell; ++nb)
- for (unsigned int subface=0;
- subface<GeometryInfo<dim>::subfaces_per_face; ++subface)
- if ((neighbor_cells[nb][subface].state() ==
- IteratorState::valid) &&
- (neighbor_cells[nb][subface]->level() ==
- hex->level()+1))
- {
- // ok, the
- // neighbor is a
- // refined one
- // and we need to
- // set one of the
- // new children
- // as its
- // neighbor
- const cell_iterator neighbor = neighbor_cells[nb][subface];
-
- // find which
- // neighbor
- // pointer is to
- // be reset; this
- // pointer still
- // points to the
- // present cell
- unsigned int face;
- for (face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if (neighbor->neighbor(face) == hex)
- break;
+ new_hexes[2]->set_neighbor(0, new_hexes[0]);
+ new_hexes[2]->set_neighbor(5, new_hexes[3]);
- Assert (face<GeometryInfo<dim>::faces_per_cell,
- ExcInternalError());
- // check, that the face we
- // found is consistent with
- // the information obtained
- // by the
- // neighbor_of_neighbor()
- // function
- Assert (face==hex->neighbor_of_neighbor(nb),
- ExcInternalError());
+ new_hexes[3]->set_neighbor(0, new_hexes[1]);
+ new_hexes[3]->set_neighbor(4, new_hexes[2]);
+ break;
+ case RefinementCase<dim>::cut_yz:
+ new_hexes[0]->set_neighbor(3, new_hexes[1]);
+ new_hexes[0]->set_neighbor(5, new_hexes[2]);
- // then figure out which of the new
- // cells points to this neighbor.
- //
- // We have considered
- // face-orientation, -flip
- // and -rotation issues in
- // the construction of the
- // neighbor_cells array,
- // now we have to consider
- // it for this cell as
- // well.
- int c = GeometryInfo<dim>::child_cell_on_face(nb,subface,
- hex->face_orientation(nb),
- hex->face_flip(nb),
- hex->face_rotation(nb));
- neighbor->set_neighbor(face,new_hexes[c]);
- }
+ new_hexes[1]->set_neighbor(2, new_hexes[0]);
+ new_hexes[1]->set_neighbor(5, new_hexes[3]);
+
+ new_hexes[2]->set_neighbor(3, new_hexes[3]);
+ new_hexes[2]->set_neighbor(4, new_hexes[0]);
+ new_hexes[3]->set_neighbor(2, new_hexes[2]);
+ new_hexes[3]->set_neighbor(4, new_hexes[1]);
+ break;
+ case RefinementCase<dim>::cut_xyz:
+ new_hexes[0]->set_neighbor(1, new_hexes[1]);
+ new_hexes[0]->set_neighbor(3, new_hexes[2]);
+ new_hexes[0]->set_neighbor(5, new_hexes[4]);
+
+ new_hexes[1]->set_neighbor(0, new_hexes[0]);
+ new_hexes[1]->set_neighbor(3, new_hexes[3]);
+ new_hexes[1]->set_neighbor(5, new_hexes[5]);
+
+ new_hexes[2]->set_neighbor(1, new_hexes[3]);
+ new_hexes[2]->set_neighbor(2, new_hexes[0]);
+ new_hexes[2]->set_neighbor(5, new_hexes[6]);
+
+ new_hexes[3]->set_neighbor(0, new_hexes[2]);
+ new_hexes[3]->set_neighbor(2, new_hexes[1]);
+ new_hexes[3]->set_neighbor(5, new_hexes[7]);
+
+ new_hexes[4]->set_neighbor(1, new_hexes[5]);
+ new_hexes[4]->set_neighbor(3, new_hexes[6]);
+ new_hexes[4]->set_neighbor(4, new_hexes[0]);
+
+ new_hexes[5]->set_neighbor(0, new_hexes[4]);
+ new_hexes[5]->set_neighbor(3, new_hexes[7]);
+ new_hexes[5]->set_neighbor(4, new_hexes[1]);
+
+ new_hexes[6]->set_neighbor(1, new_hexes[7]);
+ new_hexes[6]->set_neighbor(2, new_hexes[4]);
+ new_hexes[6]->set_neighbor(4, new_hexes[2]);
+
+ new_hexes[7]->set_neighbor(0, new_hexes[6]);
+ new_hexes[7]->set_neighbor(2, new_hexes[5]);
+ new_hexes[7]->set_neighbor(4, new_hexes[3]);
+ break;
+ default:
+ Assert (false, ExcInternalError());
+ break;
+ }
+
+ // it's a bit more complicated for
+ // outer neighbors. Leave this to a
+ // separate function
+ update_neighbors(hex, true);
// note that the
// refinement flag was
}
}
+ // clear user data on quads. we used some of
+ // this data to indicate anisotropic
+ // refinemnt cases on faces. all data should
+ // be cleared by now, but the information
+ // whether we used indices or pointers is
+ // still present. reset it now to enable the
+ // user to use whichever he likes later on.
+ faces->quads.clear_user_data();
+
// re-compute number of lines and
// quads
update_number_cache ();
endc = end();
while (cell != endc)
Assert (!(cell++)->refine_flag_set(), ExcInternalError ());
+
+ cell_iterator testcell=begin(),
+ ec=end();
+ for (;testcell!=ec; ++testcell)
+ {
+ std::set<unsigned int> verts;
+ for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
+ for (unsigned int v=0; v<GeometryInfo<dim-1>::vertices_per_cell; ++v)
+ verts.insert(testcell->face(f)->vertex_index(v));
+ Assert (verts.size()==GeometryInfo<dim>::vertices_per_cell, ExcInternalError());
+ }
#endif
}
-
#endif
// is used later on to decide which lines can
// be deleted after coarsening a cell. in
// other dimensions it will be ignored
- std::vector<unsigned int> cell_count(0);
+ std::vector<unsigned int> line_cell_count(0);
+ std::vector<unsigned int> quad_cell_count(0);
if (dim==3)
- count_cells_at_line(cell_count);
+ {
+ count_cells_at_line(line_cell_count);
+ count_cells_at_quad(quad_cell_count);
+ }
// loop over all cells. Flag all
// cells of which all children are
// used, to avoid confusion and because
// non-active cells can't be flagged for
// coarsening. Note that because of the
- // effects of @p{prepare_coarsening}, of a
+ // effects of @p{fix_coarsen_flags}, of a
// cell either all or no children must
// be flagged for coarsening, so it is
// ok to only check the first child
if (cell->child(0)->coarsen_flag_set())
{
cell->set_user_flag();
- for (unsigned int child=0;
- child<GeometryInfo<dim>::children_per_cell; ++child)
+ for (unsigned int child=0; child<cell->n_children(); ++child)
{
Assert (cell->child(child)->coarsen_flag_set(),
ExcInternalError());
// use a separate function,
// since this is dimension
// specific
- delete_children (cell, cell_count);
+ delete_children (cell, line_cell_count, quad_cell_count);
// re-compute number of lines and
// quads
}
+
+#if deal_II_dimension == 1
+
+template<>
+void
+Triangulation<1>::prevent_distorted_boundary_cells ()
+{}
+
+#else
+
+template<int dim>
+void
+Triangulation<dim>::prevent_distorted_boundary_cells ()
+{
+ for (cell_iterator cell=begin(); cell!=end(); ++cell)
+ if (cell->at_boundary() &&
+ cell->refine_flag_set() &&
+ cell->refine_flag_set()!=RefinementCase<dim>::isotropic_refinement)
+ {
+ // The cell is at the boundary
+ // and it is flagged for
+ // anisotropic
+ // refinement. Therefore, we have
+ // a closer look
+ const RefinementCase<dim> ref_case=cell->refine_flag_set();
+ for (unsigned int face_no=0;
+ face_no<GeometryInfo<dim>::faces_per_cell;
+ ++face_no)
+ if (cell->face(face_no)->at_boundary())
+ {
+ // this is the critical
+ // face at the boundary.
+ if (GeometryInfo<dim>::face_refinement_case(ref_case,face_no)
+ !=RefinementCase<dim-1>::isotropic_refinement)
+ {
+ // up to now, we do not
+ // want to refine this
+ // cell along the face
+ // under consideration
+ // here.
+ face_iterator face=cell->face(face_no);
+ // the new point on the
+ // boundary would be
+ // this one.
+ Point<dim> new_bound=boundary[face->boundary_indicator()]
+ ->get_new_point_on_face (face);
+ // to check it,
+ // transform to the
+ // unit cell with
+ // Q1Mapping
+ Point<dim> new_unit=StaticMappingQ1<dim>::mapping.
+ transform_real_to_unit_cell(cell,
+ new_bound);
+ // Now, we have to
+ // calculate the
+ // distance from the
+ // face in the unit
+ // cell.
+
+ // take the correct
+ // coordinate direction (0
+ // for faces 0 and 1, 1 for
+ // faces 2 and 3, 2 for faces
+ // 4 and 5) and substract the
+ // correct boundary value of
+ // the face (0 for faces 0,
+ // 2, and 4; 1 for faces 1, 3
+ // and 5)
+ double dist=fabs(new_unit[face_no/2] - face_no%2);
+ // compare this with
+ // the empirical value
+ // allowed. if it is
+ // too big, flag the
+ // cell for isotropic
+ // refinement
+ const double allowed=0.25;
+
+ if (dist>allowed)
+ cell->flag_for_face_refinement(face_no);
+ }//if flagged for anistropic refinement
+ }//if (cell->face(face)->at_boundary())
+ }//for all cells
+}
+#endif
+
+
+
template <int dim>
void Triangulation<dim>::prepare_refinement_dim_dependent ()
{}
// which lines will be refined
clear_user_flags_line();
+ // also clear flags on hexes, since we need
+ // them to mark those cells which are to be
+ // coarsened
+ clear_user_flags_hex();
+
// variable to store whether the
// mesh was changed in the present
// loop and in the whole process
fix_coarsen_flags ();
- // flag those lines that will
- // be refined
- for (active_cell_iterator cell=begin_active(); cell!=end(); ++cell)
+ // flag those lines that are refined and
+ // will not be coarsened and those that
+ // will be refined
+ for (cell_iterator cell=begin(); cell!=end(); ++cell)
if (cell->refine_flag_set())
- for (unsigned int line=0; line<GeometryInfo<dim>::lines_per_cell; ++line)
- // if the line is not yet
- // refined, it will be in
- // the process
- if (!cell->line(line)->has_children())
- cell->line(line)->set_user_flag();
+ {
+ for (unsigned int line=0; line<GeometryInfo<dim>::lines_per_cell; ++line)
+ if (GeometryInfo<dim>::line_refinement_case(cell->refine_flag_set(), line)
+ ==RefinementCase<dim>::cut_x)
+ // flag a line, that will be
+ // refined
+ cell->line(line)->set_user_flag();
+ }
+ else if(cell->has_children() && !cell->child(0)->coarsen_flag_set())
+ {
+ for (unsigned int line=0; line<GeometryInfo<dim>::lines_per_cell; ++line)
+ if (GeometryInfo<dim>::line_refinement_case(cell->refinement_case(), line)
+ ==RefinementCase<dim>::cut_x)
+ // flag a line, that is refined
+ // and will stay so
+ cell->line(line)->set_user_flag();
+ }
+ else if(cell->has_children() && cell->child(0)->coarsen_flag_set())
+ cell->set_user_flag();
// now check whether there are
ExcInternalError());
if (cell->line(line)->child(c)->user_flag_set () &&
- !cell->refine_flag_set())
+ (GeometryInfo<dim>::line_refinement_case(cell->refine_flag_set(),
+ line)
+ ==RefinementCase<dim>::no_refinement))
{
// tag this
// cell for
// refinement
cell->clear_coarsen_flag ();
- cell->set_refine_flag();
+ // if anisotropic
+ // coarsening is
+ // allowed: extend the
+ // refine_flag in the
+ // needed direction,
+ // else set refine_flag
+ // (isotropic)
+ if (smooth_grid & allow_anisotropic_smoothing)
+ cell->flag_for_line_refinement(line);
+ else
+ cell->set_refine_flag();
+ for (unsigned int l=0; l<GeometryInfo<dim>::lines_per_cell; ++l)
+ if (GeometryInfo<dim>::line_refinement_case(cell->refine_flag_set(), line)
+ ==RefinementCase<dim>::cut_x)
+ // flag a line,
+ // that will be
+ // refined
+ cell->line(l)->set_user_flag();
// note that
// we have
// changed
// refinement
for (unsigned int line=0;
line<GeometryInfo<dim>::lines_per_cell; ++line)
- if (!cell->line(line)->has_children())
+ if (!cell->line(line)->has_children() &&
+ (GeometryInfo<dim>::line_refinement_case(cell->refine_flag_set(),
+ line)
+ !=RefinementCase<dim>::no_refinement))
cell->line(line)->set_user_flag();
break;
// if any of the lines will be
// refined, then we may not
// coarsen the present cell
- for (active_cell_iterator cell=last_active(); cell!=end(); --cell)
+ // similarly, if any of the lines
+ // *is* already refined, we may
+ // not coarsen the current
+ // cell. however, there's a
+ // catch: if the line is refined,
+ // but the cell behind it is
+ // going to be coarsened, then
+ // the situation changes. if we
+ // forget this second condition,
+ // the refine_and_coarsen_3d test
+ // will start to fail. note that
+ // to know which cells are going
+ // to be coarsened, the call for
+ // fix_coarsen_flags above is
+ // necessary
+ for (cell_iterator cell=last(); cell!=end(); --cell)
{
- if (cell->coarsen_flag_set())
+ if (cell->user_flag_set())
for (unsigned int line=0; line<GeometryInfo<dim>::lines_per_cell; ++line)
- {
- if (cell->line(line)->user_flag_set())
- {
- cell->clear_coarsen_flag ();
- mesh_changed = true;
-
- goto next_cell;
- }
-
- // similarly, if any of the lines
- // *is* already refined, we may
- // not coarsen the current
- // cell. however, there's a
- // catch: if the line is refined,
- // but the cell behind it is
- // going to be coarsened, then
- // the situation changes. if we
- // forget this second condition,
- // the refine_and_coarsen_3d test
- // will start to fail. note that
- // to know which cells are going
- // to be coarsened, the call for
- // fix_coarsen_flags above is
- // necessary
- //
- // the problem is that finding
- // all cells that are behind an
- // edge in 3d is somewhat of a
- // pain and worst of all
- // introduces a quadratic
- // behavior in this algorithm. on
- // the other hand, not many cells
- // have their coarsen flag set
- // usually, and fixing
- // refine_and_coarsen_3d is a
- // somewhat important case
- if (cell->line(line)->has_children())
- {
- bool cant_be_coarsened = false;
-
- // loop over all cells of this
- // level to find neighbors of
- // this cell and edge
- for (cell_iterator edge_neighbor=begin(cell->level());
- ((cant_be_coarsened == false)
- &&
- (edge_neighbor != end(cell->level())));
- ++edge_neighbor)
- if (edge_neighbor != cell)
- for (unsigned int e=0; e<GeometryInfo<dim>::lines_per_cell; ++e)
- if (edge_neighbor->line(e) == cell->line(line))
- {
- // this is a cell
- // that is adjacent
- // to the present
- // cell across this
- // edge. so treat
- // it, but only if
- // it is actually
- // refined or will
- // be refined
- if (! (edge_neighbor->has_children()
- ||
- (!edge_neighbor->has_children() &&
- edge_neighbor->refine_flag_set())))
- break;
-
- // figure out if
- // the neighbor is
- // going to be
- // coarsened. as a
- // post-condition
- // of the call to
- // fix_coarsen_flags(),
- // either all
- // children of a
- // cell must be
- // flagged for
- // coarsening, or
- // none may. above
- // we delete some
- // coarsen flags,
- // and in the next
- // call to
- // fix_coarsen_flags()
- // the flags to all
- // siblings will be
- // removed. we will
- // check here if
- // still all
- // children have
- // that flag set
- unsigned int n_children_flagged = 0;
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
- if ((edge_neighbor->child(c)->has_children() == false)
- &&
- edge_neighbor->child(c)->coarsen_flag_set())
- ++n_children_flagged;
-
- // now, if not all
- // children are
- // flagged, then
- // the neighboring
- // cell isn't going
- // to be
- // coarsened. that
- // means that the
- // common edge
- // isn't going to
- // be coarsened and
- // that we can't
- // coarsen the
- // present cell
- if (n_children_flagged !=
- GeometryInfo<dim>::children_per_cell)
- cant_be_coarsened = true;
-
-
- // neighbor was
- // found. no reason
- // to keep looping
- // over edges of
- // the possible
- // edge_neighbor
- break;
- }
-
- if (cant_be_coarsened == true)
- {
- cell->clear_coarsen_flag ();
- mesh_changed = true;
-
- goto next_cell;
- }
- }
- }
- next_cell:
- ;
+ if (cell->line(line)->has_children() &&
+ (cell->line(line)->child(0)->user_flag_set() ||
+ cell->line(line)->child(1)->user_flag_set()))
+ {
+ for (unsigned int c=0; c<cell->n_children(); ++c)
+ cell->child(c)->clear_coarsen_flag ();
+ cell->clear_user_flag();
+ for (unsigned int l=0; l<GeometryInfo<dim>::lines_per_cell; ++l)
+ if (GeometryInfo<dim>::line_refinement_case(cell->refinement_case(), l)
+ ==RefinementCase<dim>::cut_x)
+ // flag a line, that is refined
+ // and will stay so
+ cell->line(l)->set_user_flag();
+ mesh_changed = true;
+ break;
+ }
}
}
while (mesh_changed == true);
#endif
+
+#if deal_II_dimension == 1
+template<>
+bool
+Triangulation<1>::coarsening_allowed(cell_iterator&)
+{
+ // in 1D the difference in refinement
+ // level is not limited for neighboring
+ // cells, so we simply return true
+ return true;
+}
+#endif
+
+
+template<int dim>
+bool
+Triangulation<dim>::coarsening_allowed(cell_iterator& cell)
+{
+ const RefinementCase<dim> ref_case = cell->refinement_case();
+ for (unsigned int n=0; n<GeometryInfo<dim>::faces_per_cell; ++n)
+ {
+ // if the cell is not refined
+ // along that face, coarsening
+ // will not change anything, so
+ // do nothing. the same applies,
+ // if the face is at the boandary
+ const RefinementCase<dim-1> face_ref_case =
+ GeometryInfo<dim>::face_refinement_case(cell->refinement_case(), n);
+
+ unsigned int n_subfaces = GeometryInfo<dim-1>
+ ::n_children(face_ref_case);
+
+ if (n_subfaces == 0 || cell->face(n)->at_boundary())
+ continue;
+ for (unsigned int c=0; c<n_subfaces; ++c)
+ {
+ const cell_iterator child = cell->child(GeometryInfo<dim>::
+ child_cell_on_face(ref_case,
+ n,c));
+
+ const cell_iterator child_neighbor = child->neighbor(n);
+ if (!child->neighbor_is_coarser(n))
+ // in 2d, if the child's neighbor
+ // is coarser, then it has no
+ // children. however, in 3d it
+ // might be otherwise. consider
+ // for example, that our face
+ // might be refined with cut_x,
+ // but the neighbor is refined
+ // with cut_xy at that face. then
+ // the neighbor pointers of the
+ // children of our cell will point
+ // to the common neighbor cell,
+ // not to its children. what we
+ // really want to know in the
+ // following is, wether the
+ // neighbor cell is refined twice
+ // with reference to our cell.
+ // that only has to be asked, if
+ // the child's neighbor is not a
+ // coarser one.
+ if ((child_neighbor->has_children() &&
+ !child_neighbor->user_flag_set())||
+ // neighbor has children, which
+ // are further refined along
+ // the face, otherwise
+ // something went wrong in the
+ // contruction of neighbor
+ // pointers. then only allow
+ // coarsening if this neighbor
+ // will be coarsened as well
+ // (user_pointer is set). the
+ // same applies, if the
+ // neighbors children are not
+ // refined but will be after
+ // refinement
+ child_neighbor->refine_flag_set())
+ return false;
+ }
+ }
+ return true;
+}
+
+
template <int dim>
void Triangulation<dim>::fix_coarsen_flags ()
{
// turned into user flags of the
// mother cell if coarsening is
// possible or deleted
- // otherwise. Coarsen flags of
+ // otherwise.
+ clear_user_flags ();
+ // Coarsen flags of
// cells with no mother cell,
// i.e. on the coarsest level are
// deleted explicitly.
- clear_user_flags ();
-
+ active_cell_iterator acell = begin_active(0),
+ end_ac = end_active(0);
+ for (; acell!=end_ac; ++acell)
+ acell->clear_coarsen_flag();
+
cell_iterator cell = begin(),
endc = end();
for (; cell!=endc; ++cell)
{
// nothing to do if we are
- // already on the finest level;
- // if we are on the coarsest
- // level, delete coarsen flag
- // since no coarsening possible
+ // already on the finest level
if (cell->active())
- {
- if (cell->level() == 0)
- cell->clear_coarsen_flag();
- continue;
- }
-
- unsigned int flagged_children = 0;
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
+ continue;
+
+ const unsigned int n_children=cell->n_children();
+ unsigned int flagged_children=0;
+ for (unsigned int child=0; child<n_children; ++child)
if (cell->child(child)->active() &&
cell->child(child)->coarsen_flag_set())
{
// flag this cell for
// coarsening if all children
// were flagged
- if (flagged_children == GeometryInfo<dim>::children_per_cell)
+ if (flagged_children == n_children)
cell->set_user_flag();
}
// to be sure that these flags are final
for (cell=last(); cell!=endc; --cell)
if (cell->user_flag_set())
- {
- bool coarsening_allowed = true;
-
- if (dim > 1)
+ // if allowed: flag the
+ // children for coarsening
+ if (coarsening_allowed(cell))
+ for (unsigned int c=0; c<cell->n_children(); ++c)
{
- for (unsigned int c=0;
- (c<GeometryInfo<dim>::children_per_cell) && (coarsening_allowed==true);
- ++c)
- for (unsigned int n=0; n<GeometryInfo<dim>::faces_per_cell; ++n)
- {
- const cell_iterator child_neighbor = cell->child(c)->neighbor(n);
- if ((child_neighbor.state() == IteratorState::valid)
- &&
- (child_neighbor->level()==cell->level()+1)
- &&
- ((child_neighbor->has_children()
- &&
- !child_neighbor->user_flag_set())
- ||
- (child_neighbor->has_children()
- &&
- child_neighbor->refine_flag_set())))
- {
- coarsening_allowed = false;
- break;
- }
- }
+ Assert (cell->child(c)->refine_flag_set()==false,
+ ExcInternalError());
+
+ cell->child(c)->set_coarsen_flag();
}
-
- // if allowed: tag the
- // children for coarsening
- if (coarsening_allowed)
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
- {
- Assert (cell->child(c)->refine_flag_set()==false,
- ExcInternalError());
-
- cell->child(c)->set_coarsen_flag();
- }
- }
-
+
// clear all user flags again, now that we
// don't need them any more
clear_user_flags ();
}
+#if deal_II_dimension == 1
-template <int dim>
-bool Triangulation<dim>::prepare_coarsening_and_refinement ()
+template <>
+bool Triangulation<1>::prepare_coarsening_and_refinement ()
{
-
// save the flags to determine
// whether something was changed in
// the course of this function
- std::vector<bool> flags_before[2];
- save_coarsen_flags (flags_before[0]);
- save_refine_flags (flags_before[1]);
+ std::vector<bool> flags_before;
+ save_coarsen_flags (flags_before);
// do nothing in 1d, except setting
// the coarsening flags correctly
- if (dim == 1)
- {
- fix_coarsen_flags ();
+ fix_coarsen_flags ();
+
+ std::vector<bool> flags_after;
+ save_coarsen_flags (flags_after);
+
+ return (flags_before != flags_after);
+}
+
+#endif
- std::vector<bool> flags_after[2];
- save_coarsen_flags (flags_after[0]);
- save_refine_flags (flags_after[1]);
- return ((flags_before[0] != flags_after[0]) ||
- (flags_before[1] != flags_after[1]));
- }
- // for all other dimensions
+template <int dim>
+bool Triangulation<dim>::prepare_coarsening_and_refinement ()
+{
+ // save the flags to determine
+ // whether something was changed in
+ // the course of this function
+ std::vector<bool> flags_before[2];
+ save_coarsen_flags (flags_before[0]);
+ save_refine_flags (flags_before[1]);
// save the flags at the outset of
// each loop. we do so in order to
// clear all coarsen flags on level 1
// to avoid level 0 cells being
// created by coarsening.
+ // As coarsen flags will never be added,
+ // this can be done once and for all
+ // before the actual loop starts.
// 1/ do not coarsen a cell if
// 'most of the neighbors' will be
// refined after the step. This is
// need to be refined. This step
// only sets refinement flags and does
// not set coarsening flags.
- // If the path_level_1 flag is set, then
+ // If the patch_level_1 flag is set, then
// eliminate_unrefined_islands,
// eliminate_refined_inner_islands and
// eliminate_refined_boundary_islands will
// refinement for which some
// neighbors are more refined or
// will be refined.
+
+ //////////////////////////////////////
+ // STEP 0:
+ // Only if coarsest_level_1 or
+ // patch_level_1 is set:
+ // clear all coarsen flags on level 1
+ // to avoid level 0 cells being
+ // created by coarsening.
+ if (((smooth_grid & coarsest_level_1) ||
+ (smooth_grid & patch_level_1)) && n_levels()>=2)
+ {
+ active_cell_iterator
+ cell=begin_active(1),
+ endc=end_active(1);
+
+ for (; cell!=endc; ++cell)
+ cell->clear_coarsen_flag();
+ }
+
+
bool mesh_changed_in_this_loop = false;
do
{
-
- //////////////////////////////////////
- // STEP 0:
- // Only if coarsest_level_1 or
- // patch_level_1 is set:
- // clear all coarsen flags on level 1
- // to avoid level 0 cells being
- // created by coarsening.
- if (((smooth_grid & coarsest_level_1) ||
- (smooth_grid & patch_level_1)) && n_levels()>=2)
- {
- typename Triangulation<dim>::active_cell_iterator
- cell=begin_active(1),
- endc=end_active(1);
-
- for (; cell!=endc; ++cell)
- cell->clear_coarsen_flag();
- }
-
-
//////////////////////////////////////
// STEP 1:
// do not coarsen a cell if 'most of
{
if (!cell->active())
{
- // count the children whose
- // coarsen_flags are set
- unsigned int n_childrens_coarsen_flags_set=0;
- for (unsigned int c=0;
- c<GeometryInfo<dim>::children_per_cell; ++c)
- if (cell->child(c)->active() &&
- cell->child(c)->coarsen_flag_set())
- ++n_childrens_coarsen_flags_set;
-
- // only do
- // something if all
- // children are
- // flagged for
- // coarsening since
- // only then are
- // they coarsened
- // anyway.
- if (n_childrens_coarsen_flags_set==
- GeometryInfo<dim>::children_per_cell)
+ // only do something if this
+ // cell will be coarsened
+ if (cell_will_be_coarsened(cell))
{
unsigned int n_neighbors=0;
- // count all
- // neighbors
- // that will be
- // refined
- // after the
- // next step
+ // count all neighbors
+ // that will be refined
+ // along the face of our
+ // cell after the next
+ // step
unsigned int count=0;
for (unsigned int n=0;
n<GeometryInfo<dim>::faces_per_cell; ++n)
if (neighbor.state() == IteratorState::valid)
{
++n_neighbors;
-
- bool not_active_neighbor_will_be_coarsened=false;
- unsigned int
- n_neighbors_childrens_coarsen_flags_set=0;
- if (!neighbor->active())
- {
- for (unsigned int c=0;
- c<GeometryInfo<dim>::children_per_cell; ++c)
- if (neighbor->child(c)->active() &&
- neighbor->child(c)->coarsen_flag_set())
- ++n_neighbors_childrens_coarsen_flags_set;
-
- if (n_neighbors_childrens_coarsen_flags_set
- ==GeometryInfo<dim>::children_per_cell)
- not_active_neighbor_will_be_coarsened=true;
- }
-
-
- if ((neighbor->active() &&
- neighbor->refine_flag_set()) ||
- !not_active_neighbor_will_be_coarsened)
+ if (face_will_be_refined_by_neighbor(cell,n))
++count;
}
}
-
- if ((dim==1 && count==n_neighbors) ||
- (dim>1 && (count==n_neighbors ||
- (count>=n_neighbors-1 &&
- n_neighbors==
- GeometryInfo<dim>::faces_per_cell))))
- for (unsigned int c=0;
- c<GeometryInfo<dim>::children_per_cell; ++c)
+ // clear coarsen flags if
+ // either all existing
+ // neighbors will be
+ // refined or all but one
+ // will be and the cell
+ // is in the interior of
+ // the domain
+ if (count==n_neighbors ||
+ (count>=n_neighbors-1 &&
+ n_neighbors==
+ GeometryInfo<dim>::faces_per_cell))
+ for (unsigned int c=0; c<cell->n_children(); ++c)
cell->child(c)->clear_coarsen_flag();
}
-
} // if (!cell->active())
} // for (all cells)
} // if (smooth_grid & ...)
-
+
//////////////////////////////////////
// STEP 2:
// eliminate refined islands in the
// active
bool all_children_active = true;
if (!cell->active())
- for (unsigned int c=0; c<GeometryInfo<dim>::children_per_cell; ++c)
+ for (unsigned int c=0; c<cell->n_children(); ++c)
if (!cell->child(c)->active())
{
all_children_active = false;
{
const cell_iterator neighbor = cell->neighbor(n);
if (neighbor.state() == IteratorState::valid)
+ {
++total_neighbors;
- if (neighbor.state() == IteratorState::valid)
- {
- if ((neighbor->active() &&
- !neighbor->refine_flag_set()) ||
- (neighbor->level() == cell->level()-1))
- ++unrefined_neighbors;
- else
- if (!neighbor->active())
- // maybe this cell's
- // children will be
- // coarsened
- {
- unsigned int tagged_children = 0;
- for (unsigned int c=0;
- c<GeometryInfo<dim>::children_per_cell;
- ++c)
- if (neighbor->child(c)->coarsen_flag_set())
- ++tagged_children;
- if (tagged_children ==
- GeometryInfo<dim>::children_per_cell)
- ++unrefined_neighbors;
- }
- }
+ if (!face_will_be_refined_by_neighbor(cell,n))
+ ++unrefined_neighbors;
+ }
+
}
// if all
(smooth_grid & eliminate_refined_boundary_islands)) )
&&
(total_neighbors != 0))
- {
- if (!cell->active())
- for (unsigned int c=0;
- c<GeometryInfo<dim>::children_per_cell; ++c)
- {
- cell->child(c)->clear_refine_flag ();
- cell->child(c)->set_coarsen_flag ();
- }
- else
- cell->clear_refine_flag();
- }
+ if (!cell->active())
+ for (unsigned int c=0; c<cell->n_children(); ++c)
+ {
+ cell->child(c)->clear_refine_flag ();
+ cell->child(c)->set_coarsen_flag ();
+ }
+ else
+ cell->clear_refine_flag();
}
}
}
// STEP 3:
// limit the level difference of
// neighboring cells at each vertex.
- if (smooth_grid & limit_level_difference_at_vertices)
+ //
+ // in case of anisotropic refinement
+ // this does not make sense. as soon
+ // as one cell is anisotropically
+ // refined, an Assertion is
+ // thrown. therefore we can ignore
+ // this problem later on
+ if (smooth_grid & limit_level_difference_at_vertices)
{
+ Assert(!anisotropic_refinement,
+ ExcMessage("In case of anisotropic refinement the limit_level_difference_at_vertices flag for mesh smoothing must not be set!"));
+
// store highest level one
// of the cells adjacent to
// a vertex belongs to
for (; cell!=endc; ++cell)
{
// if cell is already
- // flagged for
+ // flagged for (isotropic)
// refinement: nothing
// to do anymore
- if (cell->refine_flag_set())
+ if (cell->refine_flag_set()==RefinementCase<dim>::isotropic_refinement)
continue;
-
- unsigned int refined_neighbors = 0,
- unrefined_neighbors = 0;
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if (!cell->at_boundary(face))
- {
- // neighbor may
- // only be on the
- // same level or
- // one level
- // below because
- // of the
- // regularisation
- // above
- Assert ((cell->neighbor_level(face)==cell->level()) ||
- (cell->neighbor_level(face)==cell->level()-1),
- ExcInternalError());
- if ((cell->neighbor_level(face) == cell->level()) &&
- (cell->neighbor(face)->refine_flag_set() ||
- cell->neighbor(face)->has_children()))
- ++refined_neighbors;
- else
- ++unrefined_neighbors;
- }
- if (unrefined_neighbors < refined_neighbors)
+ // now we provide two
+ // algorithms. the first one is
+ // the standard one, coming from
+ // the time, where only isotropic
+ // refinement was possible. it
+ // simply counts the neighbors
+ // that are or will be refined
+ // and compares to the number of
+ // other ones. the second one
+ // does this check independently
+ // for each direction: if all
+ // neighbors in one direction
+ // (normally two, at the boundary
+ // only one) are refined, the
+ // current cell is flagged to be
+ // refined in an according
+ // direction.
+
+ if (!(smooth_grid & allow_anisotropic_smoothing))
{
- if (cell->coarsen_flag_set())
- cell->clear_coarsen_flag();
- cell->set_refine_flag ();
+ // use first algorithm
+ unsigned int refined_neighbors = 0,
+ unrefined_neighbors = 0;
+ for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
+ if (!cell->at_boundary(face))
+ {
+ if (face_will_be_refined_by_neighbor(cell,face))
+ ++refined_neighbors;
+ else
+ ++unrefined_neighbors;
+ }
+
+ if (unrefined_neighbors < refined_neighbors)
+ {
+ if (cell->coarsen_flag_set())
+ cell->clear_coarsen_flag();
+ cell->set_refine_flag ();
+ }
}
- }
+ else
+ {
+ // variable to store the cell
+ // refine case needed to
+ // fulfill all smoothing
+ // requirements
+ RefinementCase<dim> smoothing_cell_refinement_case=RefinementCase<dim>::no_refinement;
+
+ // use second algorithm, do
+ // the check individually for
+ // each direction
+ for (unsigned int face_pair=0; face_pair<GeometryInfo<dim>::faces_per_cell/2; ++face_pair)
+ {
+ // variable to store the
+ // cell refine case
+ // needed to refine at
+ // the current face pair
+ // in the same way as the
+ // neighbors do...
+ RefinementCase<dim> directional_cell_refinement_case=RefinementCase<dim>::isotropic_refinement;
+
+ for (unsigned int face_index=0; face_index<2; ++face_index)
+ {
+ unsigned int face=2*face_pair+face_index;
+ // variable to store
+ // the refine case
+ // (to come) of the
+ // face under
+ // consideration
+ RefinementCase<dim-1> expected_face_ref_case=RefinementCase<dim-1>::no_refinement;
+
+ if (cell->neighbor(face).state() == IteratorState::valid)
+ face_will_be_refined_by_neighbor(cell,face,expected_face_ref_case);
+ // now extract which
+ // refine case would
+ // be necessary to
+ // achive the same
+ // face
+ // refinement. set
+ // the intersection
+ // with other
+ // requirements for
+ // the same
+ // direction.
+
+ // note: using the
+ // intersection is
+ // not an obvious
+ // decision, we could
+ // also argue that it
+ // is more natural to
+ // use the
+ // union. however,
+ // intersection is
+ // the less
+ // aggressive tactic
+ // and favours a
+ // smaller number of
+ // refined cells over
+ // an intensive
+ // smoothing. this
+ // way we try not to
+ // loose too much of
+ // the effort we put
+ // in anisotropic
+ // refinement
+ // indicators due to
+ // overly aggressive
+ // smoothing...
+ directional_cell_refinement_case = directional_cell_refinement_case &
+ GeometryInfo<dim>::min_cell_refinement_case_for_face_refinement(
+ expected_face_ref_case,
+ face,
+ cell->face_orientation(face),
+ cell->face_flip(face),
+ cell->face_rotation(face));
+ }//for both face indices
+ // if both requirements
+ // sum up to something
+ // useful, add this to
+ // the refine case for
+ // smoothing. note: if
+ // directional_cell_refinement_case
+ // is isotropic still,
+ // then something went
+ // wrong...
+ Assert(directional_cell_refinement_case < RefinementCase<dim>::isotropic_refinement,
+ ExcInternalError());
+ smoothing_cell_refinement_case = smoothing_cell_refinement_case |
+ directional_cell_refinement_case;
+ }//for all face_pairs
+ // no we collected
+ // contributions from all
+ // directions. combine the
+ // new flags with the
+ // existing refine case, but
+ // only if smoothing is
+ // required
+ if (smoothing_cell_refinement_case)
+ {
+ cell->clear_coarsen_flag();
+ cell->set_refine_flag(cell->refine_flag_set() | smoothing_cell_refinement_case);
+ }
+ }//else -> allow_anisotropic_smoothing
+ }// for all cells
}
-
/////////////////////////////////
// STEP 5:
// ensure patch level 1.
// set_refine_flag and
// clear_coarsen_flag of
// all children.
- unsigned int n_children=GeometryInfo<dim>::children_per_cell;
for (cell_iterator cell = begin(); cell != end(); ++cell)
if (!cell->active() && cell->child(0)->active())
{
+ const unsigned int n_children=cell->n_children();
+
// cell is found to
// be a patch
- bool any_refine_flag_set=false;
+ RefinementCase<dim> combined_ref_case = RefinementCase<dim>::no_refinement;
for (unsigned int i=0; i<n_children; ++i)
{
cell_iterator child=cell->child(i);
// i.e. no child
// is refined.
Assert(child->active(), ExcInternalError());
+ // combine the refine cases
+ // of all children
+ combined_ref_case=combined_ref_case |
+ child->refine_flag_set();
+
- if (child->refine_flag_set())
- {
- any_refine_flag_set=true;
- break;
- }
}
- if (any_refine_flag_set)
+ if (combined_ref_case != RefinementCase<dim>::no_refinement)
{
for (unsigned int i=0; i<n_children; ++i)
{
cell_iterator child=cell->child(i);
child->clear_coarsen_flag();
- child->set_refine_flag();
+ child->set_refine_flag(combined_ref_case);
}
}
}
!cell->child(0)->active() &&
cell->child(0)->child(0)->active())
{
+ const unsigned int n_children=cell->n_children();
+ unsigned int n_grandchildren=0;
// count all coarsen
// flags of the
// grandchildren.
// child is
// found to
// be a patch
- for (unsigned int cc=0; cc<n_children; ++cc)
+ const unsigned int nn_children=child->n_children();
+ n_grandchildren += nn_children;
+ for (unsigned int cc=0; cc<nn_children; ++cc)
{
cell_iterator grand_child=child->child(cc);
// check
}
}
- if (n_coarsen_flags!=n_children*n_children)
+ if (n_coarsen_flags!=n_grandchildren)
{
// clear all
// grandchildren's
if (child->child(0)->active())
{
- for (unsigned int cc=0; cc<n_children; ++cc)
+ const unsigned int nn_children=child->n_children();
+ for (unsigned int cc=0; cc<nn_children; ++cc)
{
cell_iterator grand_child=child->child(cc);
Assert(grand_child->active(), ExcInternalError());
}
}
}
+
+ //////////////////////////////////
+ //
+ // at the boundary we could end up with
+ // cells with negative volume or at
+ // least with a part, that is negative,
+ // if the cell is refined
+ // anisotropically. we have to check,
+ // whether that can happen
-
+ prevent_distorted_boundary_cells();
/////////////////////////////////
// STEP 6:
// take care of the requirement that no
// double refinement is done at each face
- for (active_cell_iterator cell = last_active(); cell != end(); --cell)
- if (cell->refine_flag_set() == true)
- {
- // loop over neighbors of cell
- for (unsigned int i=0; i<GeometryInfo<dim>::faces_per_cell; ++i)
- if (cell->neighbor(i).state() == IteratorState::valid)
- {
- // regularisation?
- if ((cell->neighbor_level(i) == cell->level()-1)
- &&
- (cell->neighbor(i)->refine_flag_set() == false))
- {
- cell->neighbor(i)->clear_coarsen_flag();
- cell->neighbor(i)->set_refine_flag();
- }
- else
- if ((cell->neighbor_level(i) == cell->level())
- &&
- (cell->neighbor(i)->coarsen_flag_set() == true))
- // if this cell will
- // be refined and the
- // neighbor may or may
- // not be coarsened
- // (depending on whether
- // all children of its
- // mother cell are tagged
- // for coarsening), then
- // disallow coarsening.
- // to do so, it suffices
- // to delete the coarsen
- // flag from one child,
- // namely our present
- // neighbor
- cell->neighbor(i)->clear_coarsen_flag ();
- }
- }
-
+ //
+ // in case of anisotropic refinement
+ // it is only likely, but not sure,
+ // that the cells, which are more
+ // refined along a certain face common
+ // to two cells are on a higher
+ // level. therefore we cannot be sure,
+ // that the requirement of no double
+ // refinement is fulfilled after a
+ // single pass of the following
+ // actions. We could just wait for the
+ // next global loop. when this
+ // function terminates, the
+ // requirement will be
+ // fullfilled. However, it might be
+ // faster to insert an inner loop
+ // here.
+ bool changed = true;
+ while (changed)
+ {
+ changed=false;
+ active_cell_iterator cell=last_active(),
+ endc=end();
+
+ for (; cell != endc; --cell)
+ if (cell->refine_flag_set())
+ {
+ // loop over neighbors of cell
+ for (unsigned int i=0; i<GeometryInfo<dim>::faces_per_cell; ++i)
+ {
+ // only do something if the
+ // face is not at the boundary
+ // and if the face will be
+ // refined with the RefineCase
+ // currently flagged for
+ if (cell->neighbor(i).state() == IteratorState::valid &&
+ (GeometryInfo<dim>::face_refinement_case(cell->refine_flag_set(),
+ i)
+ != RefinementCase<dim>::no_refinement))
+
+ // 1) if the neighbor has
+ // children: nothing to
+ // worry about.
+ // 2) if the neighbor is
+ // active and a coarser
+ // one, ensure, that its
+ // refine_flag is set
+ // 3) if the neighbor is
+ // active and as
+ // refined along the face
+ // as our current cell,
+ // make sure, that no
+ // coarsen_flag is set. if
+ // we remove the coarsen
+ // flag of our neighbor,
+ // fix_coarsen_flags() makes
+ // sure, that the mother
+ // cell will not be
+ // coarsened
+ if (cell->neighbor(i)->active())
+ {
+ if (cell->neighbor_is_coarser(i))
+ {
+ if (cell->neighbor(i)->coarsen_flag_set())
+ cell->neighbor(i)->clear_coarsen_flag();
+ // we'll set the
+ // refine flag
+ // for this
+ // neighbor
+ // below. we
+ // note, that we
+ // have changed
+ // something by
+ // setting the
+ // changed flag
+ // to true. We do
+ // not need to do
+ // so, if we just
+ // removed the
+ // coarsen flag,
+ // as the changed
+ // flag only
+ // indicates the
+ // need to re-run
+ // the inner
+ // loop. however,
+ // we only loop
+ // over cells
+ // flagged for
+ // refinement
+ // here, so
+ // nothing to
+ // worry about if
+ // we remove
+ // coarsen flags
+
+ if (dim==2)
+ if (smooth_grid & allow_anisotropic_smoothing)
+ changed=cell->neighbor(i)->flag_for_face_refinement(cell->neighbor_of_coarser_neighbor(i).first,
+ RefinementCase<dim-1>::cut_x);
+ else
+ {
+ if (!cell->neighbor(i)->refine_flag_set())
+ changed=true;
+ cell->neighbor(i)->set_refine_flag();
+ }
+ else //i.e. if (dim==3)
+ {
+// ugly situations might arise here, consider the following situation, which
+// shows neighboring cells at the common face, where the upper right element is
+// coarser at the given face. Now the upper child element of the lower left
+// wants to refine according to cut_z, such that there is a 'horizontal'
+// refinement of the face marked with #####
+//
+// / /
+// / /
+// *---------------*
+// | |
+// | |
+// | |
+// | |
+// | |
+// | | /
+// | |/
+// *---------------*
+//
+//
+// *---------------*
+// /| /|
+// / | ##### / |
+// | |
+// *---------------*
+// /| /|
+// / | / |
+// | |
+// *---------------*
+// / /
+// / /
+//
+// this introduces too many hanging nodes and the neighboring (coarser) cell
+// (upper right) has to be refined. If it is only refined according to cut_z,
+// then everything is ok:
+//
+// / /
+// / /
+// *---------------*
+// | |
+// | | /
+// | |/
+// *---------------*
+// | |
+// | | /
+// | |/
+// *---------------*
+//
+//
+// *---------------*
+// /| /|
+// / *---------------*
+// /| /|
+// *---------------*
+// /| /|
+// / | / |
+// | |
+// *---------------*
+// / /
+// / /
+//
+// if however the cell wants to refine itself in an other way, or if we disallow
+// anisotropic smoothing, then simply refining the neighbor isotropically is not
+// going to work, since this introduces a refinement of face ##### with both
+// cut_x and cut_y, which is not possible:
+//
+// / / /
+// / / /
+// *-------*-------*
+// | | |
+// | | | /
+// | | |/
+// *-------*-------*
+// | | |
+// | | | /
+// | | |/
+// *-------*-------*
+//
+//
+// *---------------*
+// /| /|
+// / *---------------*
+// /| /|
+// *---------------*
+// /| /|
+// / | / |
+// | |
+// *---------------*
+// / /
+// / /
+//
+// thus, in this case we also need to refine our current cell in the new
+// direction:
+//
+// / / /
+// / / /
+// *-------*-------*
+// | | |
+// | | | /
+// | | |/
+// *-------*-------*
+// | | |
+// | | | /
+// | | |/
+// *-------*-------*
+//
+//
+// *-------*-------*
+// /| /| /|
+// / *-------*-------*
+// /| /| /|
+// *-------*-------*
+// /| / /|
+// / | / |
+// | |
+// *---------------*
+// / /
+// / /
+
+ std::pair<unsigned int, unsigned int> nb_indices
+ =cell->neighbor_of_coarser_neighbor(i);
+ unsigned int refined_along_x=0,
+ refined_along_y=0,
+ to_be_refined_along_x=0,
+ to_be_refined_along_y=0;
+
+ const int this_face_index=cell->face_index(i);
+
+// step 1: detect, along which axis the face is currently refined
+ if ((this_face_index
+ == cell->neighbor(i)->face(nb_indices.first)->child_index(0)) ||
+ (this_face_index
+ == cell->neighbor(i)->face(nb_indices.first)->child_index(1)))
+ {
+ // this
+ // might
+ // be an
+ // anisotropic
+ // child. get
+ // the
+ // face
+ // refine
+ // case
+ // of the
+ // neighbors
+ // face
+ // and
+ // count
+ // refinements
+ // in x
+ // and y
+ // direction.
+ RefinementCase<dim-1> frc=cell->neighbor(i)->face(nb_indices.first)->refinement_case();
+ if (frc & RefinementCase<dim>::cut_x)
+ ++refined_along_x;
+ if (frc & RefinementCase<dim>::cut_y)
+ ++refined_along_y;
+ }
+ else
+ // this has
+ // to be an
+ // isotropic
+ // child
+ {
+ ++refined_along_x;
+ ++refined_along_y;
+ }
+// step 2: detect, along which axis the face has to be refined given the current
+// refine flag
+ RefinementCase<dim-1> flagged_frc=
+ GeometryInfo<dim>::face_refinement_case(cell->refine_flag_set(),
+ i,
+ cell->face_orientation(i),
+ cell->face_flip(i),
+ cell->face_rotation(i));
+ if (flagged_frc & RefinementCase<dim>::cut_x)
+ ++to_be_refined_along_x;
+ if (flagged_frc & RefinementCase<dim>::cut_y)
+ ++to_be_refined_along_y;
+
+// step 3: set the refine flag of the (coarser and active) neighbor.
+ if ((smooth_grid & allow_anisotropic_smoothing) ||
+ cell->neighbor(i)->refine_flag_set())
+ {
+ if (refined_along_x + to_be_refined_along_x > 1)
+ changed |= cell->neighbor(i)->flag_for_face_refinement(nb_indices.first,
+ RefinementCase<dim-1>::cut_axis(0));
+ if (refined_along_y + to_be_refined_along_y > 1)
+ changed |= cell->neighbor(i)->flag_for_face_refinement(nb_indices.first,
+ RefinementCase<dim-1>::cut_axis(1));
+ }
+ else
+ {
+ if (cell->neighbor(i)->refine_flag_set()!=RefinementCase<dim>::isotropic_refinement)
+ changed=true;
+ cell->neighbor(i)->set_refine_flag();
+ }
+
+// step 4: if necessary (see above) add to the refine flag of the current cell
+ cell_iterator nb=cell->neighbor(i);
+ RefinementCase<dim-1> nb_frc
+ = GeometryInfo<dim>::face_refinement_case(nb->refine_flag_set(),
+ nb_indices.first,
+ nb->face_orientation(nb_indices.first),
+ nb->face_flip(nb_indices.first),
+ nb->face_rotation(nb_indices.first));
+ if ((nb_frc & RefinementCase<dim>::cut_x) &&
+ !(refined_along_x || to_be_refined_along_x))
+ changed |= cell->flag_for_face_refinement(i,RefinementCase<dim-1>::cut_axis(0));
+ if ((nb_frc & RefinementCase<dim>::cut_y) &&
+ !(refined_along_y || to_be_refined_along_y))
+ changed |= cell->flag_for_face_refinement(i,RefinementCase<dim-1>::cut_axis(1));
+ }
+ }// if neighbor is coarser
+ else // -> now the neighbor is not coarser
+ {
+ cell->neighbor(i)->clear_coarsen_flag();
+ const unsigned int nb_nb=cell->neighbor_of_neighbor(i);
+ const cell_iterator neighbor=cell->neighbor(i);
+ RefinementCase<dim-1> face_ref_case=
+ GeometryInfo<dim>::face_refinement_case(neighbor->refine_flag_set(),
+ nb_nb,
+ neighbor->face_orientation(nb_nb),
+ neighbor->face_flip(nb_nb),
+ neighbor->face_rotation(nb_nb));
+ RefinementCase<dim-1> needed_face_ref_case
+ =GeometryInfo<dim>::face_refinement_case(cell->refine_flag_set(),
+ i,
+ cell->face_orientation(i),
+ cell->face_flip(i),
+ cell->face_rotation(i));
+ // if the
+ // neighbor wants
+ // to refine the
+ // face with
+ // cut_x and we
+ // want cut_y or
+ // vice versa, we
+ // have to refine
+ // isotropically
+ // at the given
+ // face
+ if ((face_ref_case==RefinementCase<dim>::cut_x && needed_face_ref_case==RefinementCase<dim>::cut_y) ||
+ (face_ref_case==RefinementCase<dim>::cut_y && needed_face_ref_case==RefinementCase<dim>::cut_x))
+ {
+ changed=cell->flag_for_face_refinement(i, face_ref_case);
+ neighbor->flag_for_face_refinement(nb_nb, needed_face_ref_case);
+ }
+ }
+ }
+ else //-> the neighbor is not active
+ {
+ RefinementCase<dim-1> face_ref_case = cell->face(i)->refinement_case(),
+ needed_face_ref_case = GeometryInfo<dim>::face_refinement_case(cell->refine_flag_set(),
+ i,
+ cell->face_orientation(i),
+ cell->face_flip(i),
+ cell->face_rotation(i));
+ // if the face is
+ // refined with cut_x
+ // and we want cut_y
+ // or vice versa, we
+ // have to refine
+ // isotropically at
+ // the given face
+ if ((face_ref_case==RefinementCase<dim>::cut_x && needed_face_ref_case==RefinementCase<dim>::cut_y) ||
+ (face_ref_case==RefinementCase<dim>::cut_y && needed_face_ref_case==RefinementCase<dim>::cut_x))
+ changed=cell->flag_for_face_refinement(i, face_ref_case);
+ }
+
+
+ }
+ }
+ }
+
//////////////////////////////////////
// STEP 7:
// take care that no double refinement
// cell are either flagged for coarsening
// or none of the children is
fix_coarsen_flags ();
-
// get the refinement and coarsening
// flags
std::vector<bool> flags_after_loop[2];
// set the flags for the next loop
// already
- flags_before_loop[0] = flags_after_loop[0];
- flags_before_loop[1] = flags_after_loop[1];
+ flags_before_loop[0].swap(flags_after_loop[0]);
+ flags_before_loop[1].swap(flags_after_loop[1]);
}
while (mesh_changed_in_this_loop);
#if deal_II_dimension == 3
template <>
-void Triangulation<3>::count_cells_at_line (std::vector<unsigned int> &cell_count)
+void Triangulation<3>::count_cells_at_line (std::vector<unsigned int> &line_cell_count)
{
- cell_count.clear();
- cell_count.resize(n_raw_lines(),0);
+ line_cell_count.clear();
+ line_cell_count.resize(n_raw_lines(),0);
cell_iterator cell=begin(),
endc=end();
for (; cell!=endc; ++cell)
for (unsigned int l=0; l<GeometryInfo<3>::lines_per_cell; ++l)
- ++cell_count[cell->line_index(l)];
+ ++line_cell_count[cell->line_index(l)];
+}
+
+#else
+
+template <int dim>
+void Triangulation<dim>::count_cells_at_line (std::vector<unsigned int> &line_cell_count)
+{
+ Assert(false, ExcNotImplemented());
+ line_cell_count.clear();
+}
+
+#endif
+
+
+
+#if deal_II_dimension == 3
+
+template <>
+void Triangulation<3>::count_cells_at_quad (std::vector<unsigned int> &quad_cell_count)
+{
+ quad_cell_count.clear();
+ quad_cell_count.resize(n_raw_quads(),0);
+ cell_iterator cell=begin(),
+ endc=end();
+ for (; cell!=endc; ++cell)
+ for (unsigned int q=0; q<GeometryInfo<3>::faces_per_cell; ++q)
+ ++quad_cell_count[cell->quad_index(q)];
}
#else
template <int dim>
-void Triangulation<dim>::count_cells_at_line (std::vector<unsigned int> &cell_count)
+void Triangulation<dim>::count_cells_at_quad (std::vector<unsigned int> &quad_cell_count)
{
Assert(false, ExcNotImplemented());
- cell_count.clear();
+ quad_cell_count.clear();
}
#endif
template <>
void Triangulation<1>::delete_children (cell_iterator &cell,
+ std::vector<unsigned int> &,
std::vector<unsigned int> &)
{
- const unsigned int dim=1;
// first we need to reset the
// neighbor pointers of the
// neighbors of this cell's
// delete the vertex which will not
// be needed anymore. This vertex
- // is the second of the second line
- // of the first child
+ // is the second of the first child
vertices_used[cell->child(0)->vertex_index(1)] = false;
// invalidate children. clear user
// pointers, to avoid that they may
// appear at unwanted places later
// on...
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
+ for (unsigned int child=0; child<cell->n_children(); ++child)
{
cell->child(child)->clear_user_data();
cell->child(child)->clear_user_flag();
// delete pointer to children
- cell->set_children (-1);
+ cell->clear_children ();
cell->clear_user_flag();
}
template <>
void Triangulation<2>::delete_children (cell_iterator &cell,
+ std::vector<unsigned int> &,
std::vector<unsigned int> &)
{
const unsigned int dim=2;
- // first we need to reset the
- // neighbor pointers of the
- // neighbors of this cell's
- // children to this cell. This is
- // different for one dimension,
- // since there neighbors can have a
- // refinement level differing from
- // that of this cell's children by
- // more than one level. For two or
- // more dimensions, the neighbors
- // of the children may only be on
- // the same level or on the level
- // of this cell (the case that the
- // neighbors are more refined than
- // the children was eliminated in
- // @p{prepare_coarsening}
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
- for (unsigned int n=0; n<GeometryInfo<dim>::faces_per_cell;
- ++n)
+ const RefinementCase<dim> ref_case=cell->refinement_case();
+
+ for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+ if (!cell->at_boundary(face_no))
{
- const cell_iterator neighbor = cell->child(child)->neighbor(n);
- // do nothing if at boundary
- if (neighbor.state() != IteratorState::valid)
- continue;
+ if (GeometryInfo<dim>::face_refinement_case(ref_case, face_no)
+ ==RefinementCase<dim>::no_refinement)
+ cell->set_neighbor(face_no,cell->child(face_no%2)->neighbor(face_no));
+
+ cell_iterator neighbor=cell->neighbor(face_no);
- Assert ((neighbor->level()==cell->level()) ||
- (neighbor->level()==cell->level()+1),
- ExcInternalError());
+ // it is possible that the neighbor is
+ // coarser if it has already been
+ // coarsened earlier in this cycle. for
+ // anisotropic refinement that can
+ // happen, even if the neighbor is on a
+ // higher level.
- // if the neighbor's level is
- // the same as that of
- // @p{cell}, then it's
- // neighbor pointers points
- // to this cell rather than
- // to this cell's child. In
- // that case we need not do
- // anything. If the neighbor
- // is refined as often as are
- // the children, we need to
- // reset those neigbor
- // pointers that point to the
- // child of this cell; when
- // resetting the neighbor
- // pointers of neighbors of
- // one of the children, we
- // will also reset the
- // neighbor pointers other
- // children to the present
- // cell, but this does no
- // harm since we delete the
- // children afterwards anyway
- if (neighbor->level() == cell->level()+1)
- for (unsigned int neighbor_neighbor=0;
- neighbor_neighbor<GeometryInfo<dim>::faces_per_cell;
- ++neighbor_neighbor)
- if (neighbor->neighbor(neighbor_neighbor) == cell->child(child))
- neighbor->set_neighbor(neighbor_neighbor, cell);
+ // it is also possible, that the
+ // neighbor information of cell was not
+ // the best information currently
+ // available. however, the neighbor
+ // information now set should be
+ // accurate, as we have taken the
+ // pointer from one of our children, if
+ // that could be mor accurate and these
+ // children can't be further refined.
+
+ // if the neighbor is coarser, do
+ // nothing: we won't have to reset our
+ // pointer of course and the coarser
+ // neighbor does not point to this cell
+ if (cell->neighbor_is_coarser(face_no))
+ {
+ Assert(neighbor->active(),
+ ExcInternalError());
+ continue;
+ }
+
+ const unsigned int nb_nb=cell->neighbor_of_neighbor(face_no);
+ neighbor->set_neighbor(nb_nb, cell);
+ // go down the list of children which
+ // are not refined along the face (if
+ // any)
+ while (neighbor->has_children() &&
+ (GeometryInfo<dim>::face_refinement_case(neighbor->refinement_case(), nb_nb)
+ ==RefinementCase<dim>::no_refinement))
+ {
+ neighbor=neighbor->child(GeometryInfo<dim>
+ ::child_cell_on_face(neighbor->refinement_case(),
+ nb_nb,
+ 0));
+ neighbor->set_neighbor(nb_nb, cell);
+ }
+
+ // now we can safely set the cells
+ // neighbor
+ cell->set_neighbor(face_no,neighbor);
+
+ // if there are still children, they
+ // have to be refined along the face
+ // currently under consideration
+ if (neighbor->has_children())
+ {
+ unsigned int n_subfaces=GeometryInfo<dim-1>::n_children(
+ GeometryInfo<dim>::face_refinement_case(neighbor->refinement_case(), nb_nb));
+ Assert (n_subfaces>0, ExcInternalError());
+
+ for (unsigned int i=0; i<n_subfaces; ++i)
+ {
+ cell_iterator neighbor_child=neighbor->child(
+ GeometryInfo<dim>::child_cell_on_face(neighbor->refinement_case(),
+ nb_nb, i));
+ neighbor_child->set_neighbor(nb_nb, cell);
+ // once again, this
+ // neighbor_child can be
+ // refined several times,
+ // as long as this
+ // refinement is not along
+ // the current subface. if
+ // there are children
+ // refined along the
+ // subface they will be
+ // coarsened away later in
+ // this process, so we
+ // don't care about them
+ // here
+ while (neighbor_child->has_children() &&
+ (GeometryInfo<dim>::face_refinement_case(neighbor_child->refinement_case(),
+ nb_nb)
+ == RefinementCase<dim>::no_refinement))
+ {
+ neighbor_child=neighbor_child
+ ->child(GeometryInfo<dim>
+ ::child_cell_on_face(neighbor_child->refinement_case(),
+ nb_nb,
+ 0));
+ neighbor_child->set_neighbor(nb_nb, cell);
+ }
+ }
+ }
}
-
// delete the vertex which will not
// be needed anymore. This vertex
// is the second of the second line
- // of the first child
- vertices_used[cell->child(0)->line(1)->vertex_index(1)] = false;
-
- // clear user pointers, to avoid
- // that they may appear at unwanted
- // places later on...
- cell->child(0)->line(1)->clear_user_data();
- cell->child(0)->line(3)->clear_user_data();
- cell->child(3)->line(0)->clear_user_data();
- cell->child(3)->line(2)->clear_user_data();
-
- // same for user flags
- cell->child(0)->line(1)->clear_user_flag();
- cell->child(0)->line(3)->clear_user_flag();
- cell->child(3)->line(0)->clear_user_flag();
- cell->child(3)->line(2)->clear_user_flag();
-
- // delete the four interior lines
- cell->child(0)->line(1)->clear_used_flag();
- cell->child(0)->line(3)->clear_used_flag();
- cell->child(3)->line(0)->clear_used_flag();
- cell->child(3)->line(2)->clear_used_flag();
-
- // for the four faces: if the
- // neighbor does not itself need
- // the subfaces, delete them. note
- // that since dim>1 the level of a
- // neighbor is either one less or
- // the same as that of cell
+ // of the first child, if the cell
+ // is refined with cut_xy, else there
+ // is no inner vertex.
+ // additionally delete unneeded inner
+ // lines
+ if (ref_case==RefinementCase<dim>::cut_xy)
+ {
+ vertices_used[cell->child(0)->line(1)->vertex_index(1)] = false;
+
+ // clear user pointers, to
+ // avoid that they may appear
+ // at unwanted places later
+ // on...
+ cell->child(0)->line(1)->clear_user_data();
+ cell->child(0)->line(3)->clear_user_data();
+ cell->child(3)->line(0)->clear_user_data();
+ cell->child(3)->line(2)->clear_user_data();
+
+ // same for user flags
+ cell->child(0)->line(1)->clear_user_flag();
+ cell->child(0)->line(3)->clear_user_flag();
+ cell->child(3)->line(0)->clear_user_flag();
+ cell->child(3)->line(2)->clear_user_flag();
+
+ // delete the four interior
+ // lines
+ cell->child(0)->line(1)->clear_used_flag();
+ cell->child(0)->line(3)->clear_used_flag();
+ cell->child(3)->line(0)->clear_used_flag();
+ cell->child(3)->line(2)->clear_used_flag();
+ }
+ else
+ {
+ unsigned int inner_face_no=ref_case==RefinementCase<dim>::cut_x ? 1 : 3;
+
+ // the inner line will not be
+ // used any more
+ cell->child(0)->line(inner_face_no)->clear_user_data();
+ cell->child(0)->line(inner_face_no)->clear_user_flag();
+ cell->child(0)->line(inner_face_no)->clear_used_flag();
+ }
+
+ // if the neighbor does not need
+ // the subfaces, delete them. in case of
+ // anisotropic refinement we can't just
+ // ask the neighbor's level here to
+ // assure, that he is not refined along
+ // the face
for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if ((cell->neighbor(face).state() != IteratorState::valid) ||
- (cell->neighbor(face)->level() == cell->level()-1) ||
- ((cell->neighbor(face)->level() == cell->level()) &&
- !cell->neighbor(face)->has_children()))
+ if (((cell->neighbor(face).state() != IteratorState::valid) ||
+ (!cell->neighbor(face)->has_children())) &&
+ (GeometryInfo<dim>::face_refinement_case(ref_case,face)
+ !=RefinementCase<dim>::no_refinement))
{
+ line_iterator line=cell->face(face);
// delete middle vertex
- vertices_used[cell->face(face)->child(0)->vertex_index(1)] = false;
+ vertices_used[line->child(0)->vertex_index(1)] = false;
// delete the two subfaces
for (unsigned int subface=0;
- subface<GeometryInfo<dim>::subfaces_per_face; ++subface)
+ subface<line->n_children(); ++subface)
{
- cell->face(face)->child(subface)->clear_user_data ();
- cell->face(face)->child(subface)->clear_user_flag ();
- cell->face(face)->child(subface)->clear_used_flag ();
+ line->child(subface)->clear_user_data ();
+ line->child(subface)->clear_user_flag ();
+ line->child(subface)->clear_used_flag ();
}
- cell->face(face)->clear_children();
+ line->clear_children();
}
+ // invalidate children
+ for (unsigned int child=0; child<cell->n_children(); ++child)
+ {
+ cell->child(child)->clear_user_data();
+ cell->child(child)->clear_user_flag();
+ cell->child(child)->clear_used_flag();
+ }
+
+
+ // delete pointer to children
+ cell->clear_children ();
+ cell->clear_refinement_case();
+ cell->clear_user_flag();
+}
+
+#endif
+
+
+#if deal_II_dimension == 3
+
+
+template <>
+void Triangulation<3>::delete_children (cell_iterator &cell,
+ std::vector<unsigned int> &line_cell_count,
+ std::vector<unsigned int> &quad_cell_count)
+{
+ const unsigned int dim=3;
+ Assert(line_cell_count.size()==n_raw_lines(), ExcInternalError());
+ Assert(quad_cell_count.size()==n_raw_quads(), ExcInternalError());
+
+ // first of all, we store the RefineCase of
+ // this cell
+ const RefinementCase<dim> ref_case=cell->refinement_case();
+ // vectors to hold all lines and quads which
+ // may be deleted
+ std::vector<line_iterator> lines_to_delete(0);
+ std::vector<quad_iterator> quads_to_delete(0);
+ lines_to_delete.reserve(12*2+6*4+6);
+ quads_to_delete.reserve(6*4+12);
+
+ // now we decrease the counters for lines and
+ // quads contained in the child cells
+ for (unsigned int c=0; c<cell->n_children(); ++c)
+ {
+ cell_iterator child=cell->child(c);
+ for (unsigned int l=0; l<GeometryInfo<dim>::lines_per_cell; ++l)
+ --line_cell_count[child->line_index(l)];
+ for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
+ --quad_cell_count[child->quad_index(f)];
+ }
+
+ // first we need to reset the neighbor
+ // pointers of the neighbors from this cell's
+ // children to this cell. This is done by a
+ // seperate function.
+ update_neighbors(cell, false);
+
+ ///////////////////////////////////////
+ // delete interior quads and lines and the
+ // interior vertex, depending on the
+ // refinement case of the cell
+ //
+ // for append quads and lines: only append
+ // them to the list of objects to be deleted
+
+ switch (static_cast<unsigned char> (ref_case))
+ {
+ case RefinementCase<dim>::cut_x:
+ quads_to_delete.push_back(cell->child(0)->face(1));
+ break;
+ case RefinementCase<dim>::cut_y:
+ quads_to_delete.push_back(cell->child(0)->face(3));
+ break;
+ case RefinementCase<dim>::cut_z:
+ quads_to_delete.push_back(cell->child(0)->face(5));
+ break;
+ case RefinementCase<dim>::cut_xy:
+ quads_to_delete.push_back(cell->child(0)->face(1));
+ quads_to_delete.push_back(cell->child(0)->face(3));
+ quads_to_delete.push_back(cell->child(3)->face(0));
+ quads_to_delete.push_back(cell->child(3)->face(2));
+
+ lines_to_delete.push_back(cell->child(0)->line(11));
+ break;
+ case RefinementCase<dim>::cut_xz:
+ quads_to_delete.push_back(cell->child(0)->face(1));
+ quads_to_delete.push_back(cell->child(0)->face(5));
+ quads_to_delete.push_back(cell->child(3)->face(0));
+ quads_to_delete.push_back(cell->child(3)->face(4));
+
+ lines_to_delete.push_back(cell->child(0)->line(5));
+ break;
+ case RefinementCase<dim>::cut_yz:
+ quads_to_delete.push_back(cell->child(0)->face(3));
+ quads_to_delete.push_back(cell->child(0)->face(5));
+ quads_to_delete.push_back(cell->child(3)->face(2));
+ quads_to_delete.push_back(cell->child(3)->face(4));
+
+ lines_to_delete.push_back(cell->child(0)->line(7));
+ break;
+ case RefinementCase<dim>::cut_xyz:
+ quads_to_delete.push_back(cell->child(0)->face(1));
+ quads_to_delete.push_back(cell->child(2)->face(1));
+ quads_to_delete.push_back(cell->child(4)->face(1));
+ quads_to_delete.push_back(cell->child(6)->face(1));
+
+ quads_to_delete.push_back(cell->child(0)->face(3));
+ quads_to_delete.push_back(cell->child(1)->face(3));
+ quads_to_delete.push_back(cell->child(4)->face(3));
+ quads_to_delete.push_back(cell->child(5)->face(3));
+
+ quads_to_delete.push_back(cell->child(0)->face(5));
+ quads_to_delete.push_back(cell->child(1)->face(5));
+ quads_to_delete.push_back(cell->child(2)->face(5));
+ quads_to_delete.push_back(cell->child(3)->face(5));
+
+ lines_to_delete.push_back(cell->child(0)->line(5));
+ lines_to_delete.push_back(cell->child(0)->line(7));
+ lines_to_delete.push_back(cell->child(0)->line(11));
+ lines_to_delete.push_back(cell->child(7)->line(0));
+ lines_to_delete.push_back(cell->child(7)->line(2));
+ lines_to_delete.push_back(cell->child(7)->line(8));
+ // delete the vertex which will not
+ // be needed anymore. This vertex
+ // is the vertex at the heart of
+ // this cell, which is the sixth of
+ // the first child
+ vertices_used[cell->child(0)->vertex_index(7)] = false;
+ break;
+ default:
+ // only remaining case is
+ // no_refinement, thus an error
+ Assert(false, ExcInternalError());
+ break;
+ }
+
// invalidate children
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
+ for (unsigned int child=0; child<cell->n_children(); ++child)
{
cell->child(child)->clear_user_data();
cell->child(child)->clear_user_flag();
+
+ for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
+ {
+ // set flags denoting deviations from
+ // standard orientation of faces back
+ // to initialization values
+ cell->child(child)->set_face_orientation (f, true);
+ cell->child(child)->set_face_flip(f,false);
+ cell->child(child)->set_face_rotation(f,false);
+ }
+
cell->child(child)->clear_used_flag();
}
- // delete pointer to children
- cell->set_children (-1);
- cell->clear_user_flag();
-}
+ // delete pointer to children
+ cell->clear_children ();
+ cell->clear_refinement_case ();
+ cell->clear_user_flag();
+
+ // so far we only looked at inner quads,
+ // lines and vertices. Now we have to
+ // consider outer ones as well. here, we have
+ // to check, whether there are other cells
+ // still needing these objects. oherwise we
+ // can delete them. first for quads (and
+ // their inner lines).
+
+ for (unsigned int quad_no=0; quad_no<GeometryInfo<dim>::faces_per_cell; ++quad_no)
+ {
+ quad_iterator quad=cell->face(quad_no);
+
+ Assert((GeometryInfo<dim>::face_refinement_case(ref_case,quad_no) && quad->has_children()) ||
+ GeometryInfo<dim>::face_refinement_case(ref_case,quad_no)==RefinementCase<dim>::no_refinement,
+ ExcInternalError());
+
+ switch (static_cast<unsigned char> (quad->refinement_case()))
+ {
+ case RefinementCase<dim>::no_refinement:
+ // nothing to do as the quad
+ // is not refined
+ break;
+ case RefinementCase<dim>::cut_x:
+ case RefinementCase<dim>::cut_y:
+ {
+ // if one of the cell counters is
+ // zero, the other has to be as
+ // well
+ Assert((quad_cell_count[quad->child_index(0)] == 0 &&
+ quad_cell_count[quad->child_index(1)] == 0) ||
+ (quad_cell_count[quad->child_index(0)] > 0 &&
+ quad_cell_count[quad->child_index(1)] > 0),
+ ExcInternalError());
+ // it might be, that the quad is
+ // refined twice anisotropically,
+ // first check, whether we may
+ // delete possible grand_children
+ unsigned int deleted_grandchildren=0;
+ unsigned int number_of_child_refinements=0;
+
+ for (unsigned int c=0; c<2; ++c)
+ if (quad->child(c)->has_children())
+ {
+ ++number_of_child_refinements;
+ // if one of the cell counters is
+ // zero, the other has to be as
+ // well
+ Assert((quad_cell_count[quad->child(c)->child_index(0)] == 0 &&
+ quad_cell_count[quad->child(c)->child_index(1)] == 0) ||
+ (quad_cell_count[quad->child(c)->child_index(0)] > 0 &&
+ quad_cell_count[quad->child(c)->child_index(1)] > 0),
+ ExcInternalError());
+ if (quad_cell_count[quad->child(c)->child_index(0)]==0)
+ {
+ // Assert, that the two
+ // anisotropic
+ // refinements add up to
+ // isotropic refinement
+ Assert(quad->refinement_case()+quad->child(c)->refinement_case()==RefinementCase<dim>::cut_xy,
+ ExcInternalError());
+ // we may delete the
+ // quad's children and
+ // the inner line as no
+ // cell references them
+ // anymore
+ quads_to_delete.push_back(quad->child(c)->child(0));
+ quads_to_delete.push_back(quad->child(c)->child(1));
+ if (quad->child(c)->refinement_case()==RefinementCase<dim>::cut_x)
+ lines_to_delete.push_back(quad->child(c)->child(0)->line(1));
+ else
+ lines_to_delete.push_back(quad->child(c)->child(0)->line(3));
+ quad->child(c)->clear_children();
+ quad->child(c)->clear_refinement_case();
+ ++deleted_grandchildren;
+ }
+ }
+ // if no grandchildren are left, we
+ // may as well delete the
+ // refinement of the inner line
+ // between our children and the
+ // corresponding vertex
+ if (number_of_child_refinements>0 &&
+ deleted_grandchildren==number_of_child_refinements)
+ {
+ line_iterator middle_line;
+ if (quad->refinement_case()==RefinementCase<dim>::cut_x)
+ middle_line=quad->child(0)->line(1);
+ else
+ middle_line=quad->child(0)->line(3);
+
+ lines_to_delete.push_back(middle_line->child(0));
+ lines_to_delete.push_back(middle_line->child(1));
+ vertices_used[middle_line->middle_vertex_index()]=false;
+ middle_line->clear_children();
+ }
+
+ // now consider the direct children
+ // of the given quad
+ if (quad_cell_count[quad->child_index(0)]==0)
+ {
+ // we may delete the quad's
+ // children and the inner line
+ // as no cell references them
+ // anymore
+ quads_to_delete.push_back(quad->child(0));
+ quads_to_delete.push_back(quad->child(1));
+ if (quad->refinement_case()==RefinementCase<dim>::cut_x)
+ lines_to_delete.push_back(quad->child(0)->line(1));
+ else
+ lines_to_delete.push_back(quad->child(0)->line(3));
+
+ // if the counters just dropped
+ // to zero, otherwise the
+ // children would have been
+ // deleted earlier, then this
+ // cell's children must have
+ // contained the anisotropic
+ // quad children. thus, if
+ // those have again anisotropic
+ // children, which are in
+ // effect isotropic children of
+ // the original quad, those are
+ // still needed by a
+ // neighboring cell and we
+ // cannot delete them. instead,
+ // we have to reset this quad's
+ // refine case to isotropic and
+ // set the children
+ // accordingly.
+ if (quad->child(0)->has_children())
+ if (quad->refinement_case()==RefinementCase<dim>::cut_x)
+ {
+ // now evereything is
+ // quite complicated. we
+ // have the children
+ // numbered according to
+ //
+ // *---*---*
+ // |n+1|m+1|
+ // *---*---*
+ // | n | m |
+ // *---*---*
+ //
+ // from the original
+ // anisotropic
+ // refinement. we have to
+ // reorder them as
+ //
+ // *---*---*
+ // | m |m+1|
+ // *---*---*
+ // | n |n+1|
+ // *---*---*
+ //
+ // for isotropic refinement.
+ //
+ // this is a bit ugly, of
+ // course: loop over all
+ // cells on all levels
+ // and look for faces n+1
+ // (switch_1) and m
+ // (switch_2).
+ const quad_iterator switch_1=quad->child(0)->child(1);
+ const quad_iterator switch_2=quad->child(1)->child(0);
+
+ Assert(!switch_1->has_children(), ExcInternalError());
+ Assert(!switch_2->has_children(), ExcInternalError());
+
+ const int switch_1_index=switch_1->index();
+ const int switch_2_index=switch_2->index();
+ for (unsigned int l=0; l<levels.size(); ++l)
+ for (unsigned int h=0; h<levels[l]->cells.cells.size(); ++h)
+ for (unsigned int q=0; q<GeometryInfo<dim>::faces_per_cell; ++q)
+ {
+ const int index=levels[l]->cells.cells[h].face(q);
+ if (index==switch_1_index)
+ levels[l]->cells.cells[h].set_face(q,switch_2_index);
+ else if (index==switch_2_index)
+ levels[l]->cells.cells[h].set_face(q,switch_1_index);
+ }
+ // now we have to copy
+ // all information of the
+ // two quads
+ const int switch_1_lines[4]=
+ {switch_1->line_index(0),
+ switch_1->line_index(1),
+ switch_1->line_index(2),
+ switch_1->line_index(3)};
+ const bool switch_1_line_orientations[4]=
+ {switch_1->line_orientation(0),
+ switch_1->line_orientation(1),
+ switch_1->line_orientation(2),
+ switch_1->line_orientation(3)};
+ const unsigned char switch_1_boundary_indicator=switch_1->boundary_indicator();
+ const unsigned int switch_1_user_index=switch_1->user_index();
+ const bool switch_1_user_flag=switch_1->user_flag_set();
+
+ switch_1->set(internal::Triangulation::TriaObject<2>(switch_2->line_index(0),
+ switch_2->line_index(1),
+ switch_2->line_index(2),
+ switch_2->line_index(3)));
+ switch_1->set_line_orientation(0, switch_2->line_orientation(0));
+ switch_1->set_line_orientation(1, switch_2->line_orientation(1));
+ switch_1->set_line_orientation(2, switch_2->line_orientation(2));
+ switch_1->set_line_orientation(3, switch_2->line_orientation(3));
+ switch_1->set_boundary_indicator(switch_2->boundary_indicator());
+ switch_1->set_user_index(switch_2->user_index());
+ if (switch_2->user_flag_set())
+ switch_1->set_user_flag();
+ else
+ switch_1->clear_user_flag();
+
+ switch_2->set(internal::Triangulation::TriaObject<2>(switch_1_lines[0],
+ switch_1_lines[1],
+ switch_1_lines[2],
+ switch_1_lines[3]));
+ switch_2->set_line_orientation(0, switch_1_line_orientations[0]);
+ switch_2->set_line_orientation(1, switch_1_line_orientations[1]);
+ switch_2->set_line_orientation(2, switch_1_line_orientations[2]);
+ switch_2->set_line_orientation(3, switch_1_line_orientations[3]);
+ switch_2->set_boundary_indicator(switch_1_boundary_indicator);
+ switch_2->set_user_index(switch_1_user_index);
+ if (switch_1_user_flag)
+ switch_2->set_user_flag();
+ else
+ switch_2->clear_user_flag();
+
+ const unsigned int child_0=quad->child(0)->child_index(0);
+ const unsigned int child_2=quad->child(1)->child_index(0);
+ quad->clear_children();
+ quad->clear_refinement_case();
+ quad->set_refinement_case(RefinementCase<2>::cut_xy);
+ quad->set_children(0,child_0);
+ quad->set_children(2,child_2);
+ std::swap(quad_cell_count[child_0+1],quad_cell_count[child_2]);
+ }
+ else
+ {
+ // the face was refined
+ // with cut_y, thus the
+ // children are already
+ // in correct order. we
+ // only have to set them
+ // correctly, deleting
+ // the indirection of two
+ // anisotropic refinement
+ // and going directly
+ // from the quad to
+ // isotropic children
+ const unsigned int child_0=quad->child(0)->child_index(0);
+ const unsigned int child_2=quad->child(1)->child_index(0);
+ quad->clear_children();
+ quad->clear_refinement_case();
+ quad->set_refinement_case(RefinementCase<2>::cut_xy);
+ quad->set_children(0,child_0);
+ quad->set_children(2,child_2);
+ }
+ else
+ {
+ quad->clear_children();
+ quad->clear_refinement_case();
+ }
+
+
+ }
+ break;
+ }
+ case RefinementCase<dim>::cut_xy:
+ {
+ // if one of the cell counters is
+ // zero, the others have to be as
+ // well
+
+ Assert((quad_cell_count[quad->child_index(0)] == 0 &&
+ quad_cell_count[quad->child_index(1)] == 0 &&
+ quad_cell_count[quad->child_index(2)] == 0 &&
+ quad_cell_count[quad->child_index(3)] == 0) ||
+ (quad_cell_count[quad->child_index(0)] > 0 &&
+ quad_cell_count[quad->child_index(1)] > 0 &&
+ quad_cell_count[quad->child_index(2)] > 0 &&
+ quad_cell_count[quad->child_index(3)] > 0),
+ ExcInternalError());
+
+ if (quad_cell_count[quad->child_index(0)]==0)
+ {
+ // we may delete the quad's
+ // children, the inner lines
+ // and the middle vertex as no
+ // cell references them anymore
+ lines_to_delete.push_back(quad->child(0)->line(1));
+ lines_to_delete.push_back(quad->child(3)->line(0));
+ lines_to_delete.push_back(quad->child(0)->line(3));
+ lines_to_delete.push_back(quad->child(3)->line(2));
+
+ for (unsigned int child=0; child<quad->n_children(); ++child)
+ quads_to_delete.push_back(quad->child(child));
+
+ vertices_used[quad->child(0)->vertex_index(3)] = false;
+
+ quad->clear_children();
+ quad->clear_refinement_case();
+ }
+ }
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ break;
+ }
+
+ }
+
+ // now we repeat a similar procedure for the
+ // outer lines of this cell.
+
+ // if in debug mode: check that each of the
+ // lines for which we consider deleting the
+ // children in fact has children (the
+ // bits/coarsening_3d test tripped over this
+ // initially)
+ for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no)
+ {
+ line_iterator line=cell->line(line_no);
+
+ Assert((GeometryInfo<dim>::line_refinement_case(ref_case,line_no) && line->has_children()) ||
+ GeometryInfo<dim>::line_refinement_case(ref_case,line_no)==RefinementCase<dim>::no_refinement,
+ ExcInternalError());
+
+ if (line->has_children())
+ {
+ // if one of the cell counters is
+ // zero, the other has to be as well
+
+ Assert((line_cell_count[line->child_index(0)] == 0 &&
+ line_cell_count[line->child_index(1)] == 0) ||
+ (line_cell_count[line->child_index(0)] > 0 &&
+ line_cell_count[line->child_index(1)] > 0),
+ ExcInternalError());
+
+ if (line_cell_count[line->child_index(0)]==0)
+ {
+ for (unsigned int c=0; c<2; ++c)
+ Assert (!line->child(c)->has_children(),
+ ExcInternalError());
+
+ // we may delete the line's
+ // children and the middle vertex
+ // as no cell references them
+ // anymore
+ vertices_used[line->child(0)->vertex_index(1)] = false;
+
+ lines_to_delete.push_back(line->child(0));
+ lines_to_delete.push_back(line->child(1));
+
+ line->clear_children();
+ }
+ }
+ }
+
+ // finally, delete unneeded quads and lines
+
+ // clear user pointers, to avoid that
+ // they may appear at unwanted places
+ // later on...
+ // same for user flags, then finally
+ // delete the quads and lines
+ std::vector<line_iterator>::iterator line=lines_to_delete.begin(),
+ endline=lines_to_delete.end();
+ for (; line!=endline; ++line)
+ {
+ (*line)->clear_user_data();
+ (*line)->clear_user_flag();
+ (*line)->clear_used_flag();
+ }
+
+ std::vector<quad_iterator>::iterator quad=quads_to_delete.begin(),
+ endquad=quads_to_delete.end();
+ for (; quad!=endquad; ++quad)
+ {
+ (*quad)->clear_user_data();
+ (*quad)->clear_children();
+ (*quad)->clear_refinement_case();
+ (*quad)->clear_user_flag();
+ (*quad)->clear_used_flag();
+ }
+}
+
+#endif
+
+
+
+#if deal_II_dimension == 2
+template<>
+void Triangulation<2>::create_children (unsigned int &next_unused_vertex,
+ raw_line_iterator &next_unused_line,
+ raw_quad_iterator &,
+ raw_cell_iterator &next_unused_cell,
+ cell_iterator &cell)
+{
+ const unsigned int dim=2;
+ // clear refinement flag
+ const RefinementCase<dim> ref_case=cell->refine_flag_set();
+ cell->clear_refine_flag ();
+
+/* For the refinement process: since we go the levels up from the lowest, there
+ are (unlike above) only two possibilities: a neighbor cell is on the same
+ level or one level up (in both cases, it may or may not be refined later on,
+ but we don't care here).
+
+ First:
+ Set up an array of the 3x3 vertices, which are distributed on the cell
+ (the array consists of indices into the @p{vertices} std::vector
+
+ 2--7--3
+ | | |
+ 4--8--5
+ | | |
+ 0--6--1
+
+ note: in case of cut_x or cut_y not all these vertices are needed for the new
+ cells
+
+ Second:
+ Set up an array of the new lines (the array consists of iterator pointers
+ into the lines arrays)
+
+ .-6-.-7-. The directions are: .->-.->-.
+ 1 9 3 ^ ^ ^
+ .-10.11-. .->-.->-.
+ 0 8 2 ^ ^ ^
+ .-4-.-5-. .->-.->-.
+
+ cut_x:
+ .-4-.-5-.
+ | | |
+ 0 6 1
+ | | |
+ .-2-.-3-.
+
+ cut_y:
+ .---5---.
+ 1 3
+ .---6---.
+ 0 2
+ .---4---.
+
+
+ Third:
+ Set up an array of neighbors:
+
+ 6 7
+ .--.--.
+ 1| | |3
+ .--.--.
+ 0| | |2
+ .--.--.
+ 4 5
+
+ We need this array for two reasons: first to get the lines which will
+ bound the four subcells (if the neighboring cell is refined, these
+ lines already exist), and second to update neighborship information.
+ Since if a neighbor is not refined, its neighborship record only
+ points to the present, unrefined, cell rather than the children we
+ are presently creating, we only need the neighborship information
+ if the neighbor cells are refined. In all other cases, we store
+ the unrefined neighbor address
-#endif
+ We also need for every neighbor (if refined) which number among its
+ neighbors the present (unrefined) cell has, since that number is to
+ be replaced and because that also is the number of the subline which
+ will be the interface between that neighbor and the to be created cell.
+ We will store this number (between 0 and 3) in the field
+ @p{neighbors_neighbor}.
+ It would be sufficient to use the children of the common line to the
+ neighbor, if we only wanted to get the new sublines and the new vertex,
+ but because we need to update the neighborship information of the
+ two refined subcells of the neighbor, we need to search these anyway.
-#if deal_II_dimension == 3
+ Convention:
+ The created children are numbered like this:
+ .--.--.
+ |2 . 3|
+ .--.--.
+ |0 | 1|
+ .--.--.
+*/
-template <>
-void Triangulation<3>::delete_children (cell_iterator &cell,
- std::vector<unsigned int> &cell_count)
-{
- const unsigned int dim=3;
- Assert(cell_count.size()==n_raw_lines(), ExcInternalError());
-
- // first we need to reset the
- // neighbor pointers of the
- // neighbors of this cell's
- // children to this cell. This is
- // different for one dimension,
- // since there neighbors can have a
- // refinement level differing from
- // that of this cell's children by
- // more than one level. For two or
- // more dimensions, the neighbors
- // of the children may only be on
- // the same level or on the level
- // of this cell (the case that the
- // neighbors are more refined than
- // the children was eliminated in
- // @p{prepare_coarsening}
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
- for (unsigned int n=0; n<GeometryInfo<dim>::faces_per_cell; ++n)
- {
- const cell_iterator neighbor = cell->child(child)->neighbor(n);
- // do nothing if at boundary
- if (neighbor.state() != IteratorState::valid)
- continue;
-
- Assert ((neighbor->level()==cell->level()) ||
- (neighbor->level()==cell->level()+1),
- ExcInternalError());
-
- // if the neighbor's level is
- // the same as that of
- // @p{cell}, then it's
- // neighbor pointers points
- // to this cell rather than
- // to this cell's child. In
- // that case we need not do
- // anything. If the neighbor
- // is refined as often as are
- // the children, we need to
- // reset those neigbor
- // pointers that point to the
- // child of this cell; when
- // resetting the neighbor
- // pointers of neighbors of
- // one of the children, we
- // will also reset the
- // neighbor pointers other
- // children to the present
- // cell, but this does no
- // harm since we delete the
- // children afterwards anyway
- if (neighbor->level() == cell->level()+1)
- for (unsigned int neighbor_neighbor=0;
- neighbor_neighbor<GeometryInfo<dim>::faces_per_cell;
- ++neighbor_neighbor)
- if (neighbor->neighbor(neighbor_neighbor) == cell->child(child))
- neighbor->set_neighbor(neighbor_neighbor, cell);
- }
+ // collect the indices
+ // all vertices
+ // 2--7--3
+ // | | |
+ // 4--8--5
+ // | | |
+ // 0--6--1
+ int new_vertices[9];
+ for (unsigned int vertex_no=0; vertex_no<4; ++vertex_no)
+ new_vertices[vertex_no]=cell->vertex_index(vertex_no);
+ for (unsigned int line_no=0; line_no<4; ++line_no)
+ if (cell->line(line_no)->has_children())
+ new_vertices[4+line_no]=cell->line(line_no)->child(0)->vertex_index(1);
+
+ if (ref_case==RefinementCase<dim>::cut_xy)
+ {
+ // find the next
+ // unused vertex and
+ // set it
+ // appropriately
+ while (vertices_used[next_unused_vertex] == true)
+ ++next_unused_vertex;
+ Assert (next_unused_vertex < vertices.size(),
+ ExcTooFewVerticesAllocated());
+ vertices_used[next_unused_vertex] = true;
- // delete the vertex which will not
- // be needed anymore. This vertex
- // is the vertex at the heart of
- // this cell, which is the sixth of
- // the first child
- vertices_used[cell->child(0)->vertex_index(7)] = false;
+ new_vertices[8]=next_unused_vertex;
+
+ // new vertex is
+ // placed at the
+ // arithmetic mean of
+ // all 8 neighboring
+ // points.
+ Point<2> new_point(0,0);
+ for (unsigned int i=0; i<8; ++i)
+ new_point += vertices[new_vertices[i]];
+ new_point /= 8.0;
+
+ vertices[new_vertices[8]] = new_point;
+
- ///////////////////////////////////////
- // delete interior quads and lines
- //
- // first set up a list of these
- // line's and quad's indices
- const quad_iterator interior_quads[12]
- = { cell->child(0)->face(1),
- cell->child(2)->face(1),
- cell->child(4)->face(1),
- cell->child(6)->face(1),
-
- cell->child(0)->face(3),
- cell->child(1)->face(3),
- cell->child(4)->face(3),
- cell->child(5)->face(3),
-
- cell->child(0)->face(5),
- cell->child(1)->face(5),
- cell->child(2)->face(5),
- cell->child(3)->face(5)
- };
-
- const line_iterator interior_lines[6]
- = { cell->child(0)->line(5),
- cell->child(0)->line(7),
- cell->child(0)->line(11),
-
- cell->child(7)->line(0),
- cell->child(7)->line(2),
- cell->child(7)->line(8),
- };
-
- // clear user pointers, to avoid that
- // they may appear at unwanted places
- // later on...
- // same for user flags, then finally
- // delete thes quads and lines
- for (unsigned int q=0; q<12; ++q)
+ // if the user_flag is set, i.e. if the
+ // cell is at the boundary, use a
+ // different calculation of the middle
+ // vertex here. this is of advantage, if
+ // the boundary is strongly curved and
+ // the cell has a high aspect ratio. this
+ // can happen for example, if it was
+ // refined anisotropically before.
+ if (cell->user_flag_set())
+ {
+ // first reset the user_flag
+ cell->clear_user_flag();
+ // the user flag indicates: at least
+ // one face is at the boundary. if it
+ // is only one, set the new middle
+ // vertex in a different way to avoid
+ // some mis-shaped elements if the
+ // new point on the boundary is not
+ // where we expect it, especially if
+ // it is to far inside the current
+ // cell
+ unsigned int bound_face=GeometryInfo<dim>::faces_per_cell;
+ for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
+ if (cell->face(face)->at_boundary())
+ if (bound_face == GeometryInfo<dim>::faces_per_cell)
+ // no boundary face found so
+ // far, so set it now
+ bound_face=face;
+ else
+ // there is another boundary
+ // face, so reset bound_face to
+ // invalid value as a flag to
+ // do nothing in the following
+ bound_face=GeometryInfo<dim>::faces_per_cell+1;
+
+ if (bound_face<GeometryInfo<dim>::faces_per_cell)
+ // reset the cell's middle vertex
+ // to the middle of the straight
+ // connection between the new
+ // points on this face and on the
+ // opposite face
+ vertices[new_vertices[8]]=0.5*(cell->face(bound_face)
+ ->child(0)->vertex(1)+
+ cell->face(GeometryInfo<dim>
+ ::opposite_face[bound_face])
+ ->child(0)->vertex(1));
+ }
+ }
+
+
+ // Now the lines:
+ raw_line_iterator new_lines[12];
+ unsigned int lmin=8;
+ unsigned int lmax=12;
+ if (ref_case!=RefinementCase<dim>::cut_xy)
{
- interior_quads[q]->clear_user_data();
- interior_quads[q]->clear_user_flag();
- interior_quads[q]->clear_used_flag();
+ lmin=6;
+ lmax=7;
}
+
+ for (unsigned int l=lmin; l<lmax; ++l)
+ {
+ while (next_unused_line->used() == true)
+ ++next_unused_line;
+ new_lines[l] = next_unused_line;
+ ++next_unused_line;
- for (unsigned int l=0; l<6; ++l)
+ Assert (new_lines[l]->used() == false,
+ ExcCellShouldBeUnused());
+ }
+
+ if (ref_case==RefinementCase<dim>::cut_xy)
{
- interior_lines[l]->clear_user_data();
- interior_lines[l]->clear_user_flag();
- interior_lines[l]->clear_used_flag();
+ // .-6-.-7-.
+ // 1 9 3
+ // .-10.11-.
+ // 0 8 2
+ // .-4-.-5-.
+
+ // lines 0-7 already
+ // exist, create only
+ // the four interior
+ // lines 8-11
+ unsigned int l=0;
+ for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+ for (unsigned int c=0; c<2; ++c, ++l)
+ new_lines[l]=cell->line(face_no)->child(c);
+ Assert(l==8, ExcInternalError());
+
+ new_lines[8] ->set (internal::Triangulation::
+ TriaObject<1>(new_vertices[6], new_vertices[8]));
+ new_lines[9] ->set (internal::Triangulation::
+ TriaObject<1>(new_vertices[8], new_vertices[7]));
+ new_lines[10]->set (internal::Triangulation::
+ TriaObject<1>(new_vertices[4], new_vertices[8]));
+ new_lines[11]->set (internal::Triangulation::
+ TriaObject<1>(new_vertices[8], new_vertices[5]));
}
-
- // for the six faces: if the
- // neighbor does not itself need
- // the subfaces, delete them. note
- // that since dim>1 the level of a
- // neighbor is either one less or
- // the same as that of cell
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if ((cell->neighbor(face).state() != IteratorState::valid) ||
- (cell->neighbor(face)->level() == cell->level()-1) ||
- ((cell->neighbor(face)->level() == cell->level()) &&
- !cell->neighbor(face)->has_children()))
- {
- quad_iterator quad = cell->face(face);
-
- // delete middle vertex
- vertices_used[quad->child(0)->vertex_index(3)] = false;
-
- const line_iterator interior_lines[4]
- = { quad->child(0)->line(1),
- quad->child(0)->line(3),
- quad->child(3)->line(0),
- quad->child(3)->line(2)
- };
-
- // delete interior lines
- for (unsigned int l=0; l<4; ++l)
- {
- interior_lines[l]->clear_user_data ();
- interior_lines[l]->clear_user_flag ();
- interior_lines[l]->clear_used_flag ();
- }
-
- // delete the four subfaces
- for (unsigned int subface=0;
- subface<GeometryInfo<dim>::subfaces_per_face; ++subface)
- {
- quad->child(subface)->clear_user_data ();
- quad->child(subface)->clear_user_flag ();
- quad->child(subface)->clear_used_flag ();
- }
-
- quad->clear_children();
- }
-
- // invalidate children
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell; ++child)
+ else if (ref_case==RefinementCase<dim>::cut_x)
{
- cell->child(child)->clear_user_data();
- cell->child(child)->clear_user_flag();
+ // .-4-.-5-.
+ // | | |
+ // 0 6 1
+ // | | |
+ // .-2-.-3-.
+ new_lines[0]=cell->line(0);
+ new_lines[1]=cell->line(1);
+ new_lines[2]=cell->line(2)->child(0);
+ new_lines[3]=cell->line(2)->child(1);
+ new_lines[4]=cell->line(3)->child(0);
+ new_lines[5]=cell->line(3)->child(1);
+ new_lines[6]->set (internal::Triangulation::
+ TriaObject<1>(new_vertices[6], new_vertices[7]));
+ }
+ else
+ {
+ Assert(ref_case==RefinementCase<dim>::cut_y, ExcInternalError());
+ // .---5---.
+ // 1 3
+ // .---6---.
+ // 0 2
+ // .---4---.
+ new_lines[0]=cell->line(0)->child(0);
+ new_lines[1]=cell->line(0)->child(1);
+ new_lines[2]=cell->line(1)->child(0);
+ new_lines[3]=cell->line(1)->child(1);
+ new_lines[4]=cell->line(2);
+ new_lines[5]=cell->line(3);
+ new_lines[6]->set (internal::Triangulation::
+ TriaObject<1>(new_vertices[4], new_vertices[5]));
+ }
- for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
- {
- // set flags denoting deviations from
- // standard orientation of faces back
- // to initialization values
- cell->child(child)->set_face_orientation (f, true);
- cell->child(child)->set_face_flip(f,false);
- cell->child(child)->set_face_rotation(f,false);
- }
-
- cell->child(child)->clear_used_flag();
+ for (unsigned int l=lmin; l<lmax; ++l)
+ {
+ new_lines[l]->set_used_flag();
+ new_lines[l]->clear_user_flag();
+ new_lines[l]->clear_user_data();
+ new_lines[l]->clear_children();
+ // interior line
+ new_lines[l]->set_boundary_indicator(255);
}
+ // Now add the four (two)
+ // new cells!
+ raw_cell_iterator subcells[GeometryInfo<dim>::max_children_per_cell];
+ while (next_unused_cell->used() == true)
+ ++next_unused_cell;
+
+ const unsigned int n_children=
+ GeometryInfo<dim>::n_children(ref_case);
+ for (unsigned int i=0; i<n_children; ++i)
+ {
+ Assert (next_unused_cell->used() == false,
+ ExcCellShouldBeUnused());
+ subcells[i] = next_unused_cell;
+ ++next_unused_cell;
+ if (i%2==1 && i<n_children-1)
+ while (next_unused_cell->used() == true)
+ ++next_unused_cell;
+ }
- // delete pointer to children
- cell->clear_children ();
- cell->clear_user_flag();
+ if (ref_case==RefinementCase<dim>::cut_xy)
+ {
+ // children:
+ // .--.--.
+ // |2 . 3|
+ // .--.--.
+ // |0 | 1|
+ // .--.--.
+ // lines:
+ // .-6-.-7-.
+ // 1 9 3
+ // .-10.11-.
+ // 0 8 2
+ // .-4-.-5-.
+ subcells[0]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[0]->index(),
+ new_lines[8]->index(),
+ new_lines[4]->index(),
+ new_lines[10]->index()));
+ subcells[1]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[8]->index(),
+ new_lines[2]->index(),
+ new_lines[5]->index(),
+ new_lines[11]->index()));
+ subcells[2]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[1]->index(),
+ new_lines[9]->index(),
+ new_lines[10]->index(),
+ new_lines[6]->index()));
+ subcells[3]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[9]->index(),
+ new_lines[3]->index(),
+ new_lines[11]->index(),
+ new_lines[7]->index()));
+ }
+ else if (ref_case==RefinementCase<dim>::cut_x)
+ {
+ // children:
+ // .--.--.
+ // | . |
+ // .0 . 1.
+ // | | |
+ // .--.--.
+ // lines:
+ // .-4-.-5-.
+ // | | |
+ // 0 6 1
+ // | | |
+ // .-2-.-3-.
+ subcells[0]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[0]->index(),
+ new_lines[6]->index(),
+ new_lines[2]->index(),
+ new_lines[4]->index()));
+ subcells[1]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[6]->index(),
+ new_lines[1]->index(),
+ new_lines[3]->index(),
+ new_lines[5]->index()));
+ }
+ else
+ {
+ Assert(ref_case==RefinementCase<dim>::cut_y, ExcInternalError());
+ // children:
+ // .-----.
+ // | 1 |
+ // .-----.
+ // | 0 |
+ // .-----.
+ // lines:
+ // .---5---.
+ // 1 3
+ // .---6---.
+ // 0 2
+ // .---4---.
+ subcells[0]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[0]->index(),
+ new_lines[2]->index(),
+ new_lines[4]->index(),
+ new_lines[6]->index()));
+ subcells[1]->set (internal::Triangulation::
+ TriaObject<2>(new_lines[1]->index(),
+ new_lines[3]->index(),
+ new_lines[6]->index(),
+ new_lines[5]->index()));
+ }
+
- // now there still are the 12 lines of this
- // hex which are refined and which may need
- // coarsening. As we got the number of cells
- // containing this line, we can simply use
- // that information here.
-
- // if in debug mode: make sure that
- // none of the lines of this cell
- // is twice refined; else, deleting
- // this cell's children will result
- // in an invalid state. also check
- // that each of the lines for which
- // we consider deleting the
- // children in fact has children
- // (the bits/coarsening_3d test
- // tripped over this initially)
- for (unsigned int line_no=0; line_no<12; ++line_no)
+ for (unsigned int i=0; i<n_children; ++i)
{
- line_iterator line=cell->line(line_no);
-
- Assert (line->has_children(),
- ExcInternalError());
- for (unsigned int c=0; c<2; ++c)
- {
- Assert (!line->child(c)->has_children(),
- ExcInternalError());
- // decrease the number of cells
- // referencing this line by one, as
- // one of those was one of our former
- // children
- --cell_count[line->child_index(c)];
- }
- // the cell counters for both
- // line_children have to be the same
- Assert(cell_count[line->child_index(0)] ==
- cell_count[line->child_index(1)],
- ExcInternalError());
+ subcells[i]->set_used_flag();
+ subcells[i]->clear_refine_flag();
+ subcells[i]->clear_user_flag();
+ subcells[i]->clear_user_data();
+ subcells[i]->clear_children();
+ // inherit material
+ // properties
+ subcells[i]->set_material_id (cell->material_id());
+ subcells[i]->set_subdomain_id (cell->subdomain_id());
+ }
+
+ // now the only thing
+ // still to be done is
+ // setting neighborship
+ // information.
+ //
+ // we have to do that for
+ // all children of our
+ // current cell. if the
+ // neighbor is a refined
+ // one or if we use anisotropic
+ // refinement and there is only
+ // one child of the current cell
+ // adjacent to a certain face,
+ // we also have to reset the
+ // neighbors neighbor pointers.
+ // In earlier versions of the
+ // library these tasks were done one
+ // after the other. here we combine
+ // these steps, as otherwise we
+ // would have to gather the same
+ // information on the refinement
+ // situation along a certain face
+ // twice. As this is a more
+ // complicated task for anisotropic
+ // refinement, we prefer to do it
+ // only once.
+ //
+ // note that in case the
+ // neighboring cell is
+ // not refined along the
+ // common face, the
+ // neighbor iterators
+ // point to the common
+ // mother cell. the same
+ // applies if there is no
+ // neighbor: the
+ // iterators are past the
+ // end
+ cell_iterator nb_children[GeometryInfo<dim>::max_children_per_face],
+ nb_child,
+ children[GeometryInfo<dim>::faces_per_cell][GeometryInfo<dim>::max_children_per_face];
+
+ // first, set up an array of our current
+ // children / subcells. for all faces and
+ // subfaces store the info, which subcell is
+ // adjacent to that subface
+ for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_face; ++c)
+ children[face][c]=subcells[GeometryInfo<dim>::child_cell_on_face(ref_case,
+ face,c)];
+
+
+ for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell;
+ ++face)
+ {
+ const cell_iterator neighbor=cell->neighbor(face);
+ const RefinementCase<dim-1> face_ref_case=GeometryInfo<dim>::face_refinement_case(ref_case,face);
+ const unsigned int n_subfaces=std::max(GeometryInfo<dim-1>::n_children(face_ref_case),
+ static_cast<unsigned int>(1));
+
+
+
+ // if no neighbor set invalid pointer for
+ // all children adjacent to that face
+ if (neighbor.state() != IteratorState::valid)
+ for (unsigned int c=0; c<n_subfaces; ++c)
+ children[face][c]
+ ->set_neighbor(face,neighbor);
- if (cell_count[line->child_index(0)]==0)
+ else
+ // neighbor exists
{
- // we may delete the line's children
- // and the middle vertex as no cell
- // references them anymore
- vertices_used[line->child(0)->vertex_index(1)] = false;
-
- for (unsigned int child=0; child<2; ++child)
+ // now there are two possibilities:
+ // either the neighbor is not refined
+ // along the common face or it is
+ // refined along the common face once,
+ // this must be terminal then
+ // (otherwise something went wrong in
+ // prepare_refinement_and_coarsening()).
+ // however, if at any time the neighbor
+ // has children, which are not refined
+ // along the face currently under
+ // consideration, one of these children
+ // would have been set as the neighbor
+ // of our current cell. therefore the
+ // question wether the neighbor is
+ // refined along the common face is
+ // equivalent to the question, wether
+ // the neighbor has children. if our
+ // current cell is not refined along
+ // the face face_no, then we have to
+ // set the current neighbor as the new
+ // neighbor, even if the neighbor is
+ // further refined
+ if (!neighbor->has_children())
{
- line->child(child)->clear_user_data();
- line->child(child)->clear_user_flag();
- line->child(child)->clear_used_flag();
+ // if the neighbor has no children,
+ // set the neighbor-pointer of all
+ // children to this neighbor cell
+ for (unsigned int c=0; c<n_subfaces; ++c)
+ children[face][c]
+ ->set_neighbor(face,neighbor);
+ // if the current cell is not
+ // refined along the face we have
+ // to update the neighbors neighbor
+ // pointer. we have to do this only,
+ // if the neighbor is not coarser
+ if (n_subfaces==1 && !cell->neighbor_is_coarser(face))
+ {
+ const unsigned int nb_nb = cell->neighbor_of_neighbor(face);
+ neighbor->set_neighbor(nb_nb, children[face][0]);
+ }
}
+ else
+ {
+ // neighbor has children
+ const unsigned int nb_nb = cell->neighbor_of_neighbor(face);
+ const RefinementCase<dim> nb_ref_case = neighbor->refinement_case();
+ const RefinementCase<dim-1> nb_face_ref_case = GeometryInfo<dim>::face_refinement_case(nb_ref_case,
+ nb_nb);
+ const unsigned int nb_n_subfaces = std::max(GeometryInfo<dim-1>::
+ n_children(nb_face_ref_case),
+ static_cast<unsigned int>(1));
+
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_face; ++c)
+ {
+ nb_child=neighbor->child(GeometryInfo<dim>::
+ child_cell_on_face(nb_ref_case,
+ nb_nb,
+ c));
+ // there could be an unknown
+ // number of refinements for
+ // nb_child that do
+ // not refine the common
+ // face.
+
+ // consider for example the
+ // following case, where the
+ // lower cell has been refined
+ // in this step into c1 and c2.
+
+ // ---------------
+ // | | |
+ // | | n2.1 |
+ // | | |
+ // | n1 -------
+ // | | |
+ // | | n2.2 |
+ // | | |
+ // ---------------
+ // | | |
+ // | | |
+ // | | |
+ // | c1 | c2 |
+ // | | |
+ // | | |
+ // ---------------
- line->clear_children();
- }
+ // the neighbor of cell c was
+ // the whole of cell n. what we
+ // have done so far is setting
+ // the right neighbor
+ // information for cells c1 and
+ // n1 as well as c2 and n2,
+ // where n2 is the mother cell
+ // of n2.1 and n2.2. however,
+ // n2 is further refined and we
+ // would have to set n2.2 as
+ // neighbor of child c2 and
+ // vice versa. this is specific
+ // to anisotropic refinement.
+
+ // note that n2.2 could be
+ // further refined with cut_y
+ // (if n1 was also refined with
+ // cut_y).
+
+ // go down that list to
+ // the end. note, that nb_nb
+ // stays constant, for all
+ // children of a cell have
+ // their faces in the same
+ // direction and orientation as
+ // the mother cell
+ while(nb_child->has_children()
+ && (GeometryInfo<dim>::face_refinement_case(nb_child->refinement_case(),
+ nb_nb)
+ == RefinementCase<dim>::no_refinement))
+ // nb_child has children
+ // which are not refined at
+ // the current (sub)face,
+ // therefore one of these
+ // children is the true
+ // neighbor of our cell
+ nb_child = nb_child
+ ->child(GeometryInfo<dim>::
+ child_cell_on_face(nb_child->refinement_case(),
+ nb_nb,
+ 0));
+ // there's one more possibility
+ // here, if the current cell is
+ // refined along the face: the
+ // last child found above could
+ // still be refined once along
+ // the common face, e.g. n1 or
+ // n2.2 in the above picture
+ // could be refined with
+ // cut_x. this refinement leeds
+ // to an inreased number of
+ // hanging nodes. therefore it
+ // was introduced in this
+ // refinement cycle and the
+ // additional hanging nodes
+ // will be removed now, as the
+ // current cell is also
+ // refined. this temporaray
+ // effect can occur during
+ // anisotropic refinement, as
+ // it is possible there, that a
+ // coarser cell (along the face
+ // between the cells) is on a
+ // higher level and therefore
+ // refined after the already
+ // refined neighbor.
+ if (nb_child->has_children())
+ {
+ // This is only valid, if
+ // the current cell is
+ // refined along the face
+ // considered here
+ Assert(n_subfaces > 1, ExcInternalError());
+ for (unsigned int sub=0;
+ sub<GeometryInfo<dim>::max_children_per_face; ++sub)
+ {
+ // collect all the
+ // children of nb_child
+ // and set their
+ // neighbor
+ // pointers. we will
+ // care for our own
+ // children later on
+ nb_children[sub]=nb_child->
+ child(GeometryInfo<dim>::
+ child_cell_on_face(nb_child->refinement_case(),
+ nb_nb, sub));
+ nb_children[sub]->set_neighbor(nb_nb, children[face][c]);
+ }
+ }
+
+
+ // now set the neighbor
+ // pointers of the neighbor's
+ // children.
+ nb_child->set_neighbor(nb_nb, children[face][c]);
+ // if this cell is as refined
+ // as the neighbor, set the
+ // neighbor pointers of the
+ // subcells to the
+ // corresponting
+ // neighbor_child. else, set
+ // the neighbor pointers to the
+ // common neighbor mother cell
+ if (nb_n_subfaces==n_subfaces)
+ children[face][c]->set_neighbor(face,nb_child);
+ else
+ children[face][c]->set_neighbor(face,neighbor);
+ }
+ }
+ }
}
-}
+ // by now, all the outer neighbors have been
+ // set, the inner neighbors have to be
+ // considered in the following
+
+ if (ref_case==RefinementCase<dim>::cut_xy)
+ {
+ // children:
+ // .--.--.
+ // |2 . 3|
+ // .--.--.
+ // |0 | 1|
+ // .--.--.
+ subcells[0]->set_neighbor (1, subcells[1]);
+ subcells[0]->set_neighbor (3, subcells[2]);
+
+ subcells[1]->set_neighbor (0, subcells[0]);
+ subcells[1]->set_neighbor (3, subcells[3]);
+
+ subcells[2]->set_neighbor (1, subcells[3]);
+ subcells[2]->set_neighbor (2, subcells[0]);
+
+ subcells[3]->set_neighbor (0, subcells[2]);
+ subcells[3]->set_neighbor (2, subcells[1]);
+ }
+ else if (ref_case==RefinementCase<dim>::cut_x)
+ {
+ // children:
+ // .--.--.
+ // | . |
+ // .0 . 1.
+ // | | |
+ // .--.--.
+ subcells[0]->set_neighbor (1, subcells[1]);
+
+ subcells[1]->set_neighbor (0, subcells[0]);
+ }
+ else
+ {
+ Assert(ref_case==RefinementCase<dim>::cut_y, ExcInternalError());
+ // children:
+ // .-----.
+ // | 1 |
+ // .-----.
+ // | 0 |
+ // .-----.
+ subcells[0]->set_neighbor (3, subcells[1]);
+
+ subcells[1]->set_neighbor (2, subcells[0]);
+ }
+
+
+ // set child index for
+ // even children children
+ // i=0,2 (0)
+ for (unsigned int i=0; i<n_children/2; ++i)
+ cell->set_children (2*i, subcells[2*i]->index());
+ // set the refine case
+ cell->set_refinement_case(ref_case);
+
+ // note that the
+ // refinement flag was
+ // already cleared at the
+ // beginning of this function
+}
#endif
+
template <int dim>
void Triangulation<dim>::write_bool_vector (const unsigned int magic_number1,
const std::vector<bool> &v,
refinement_listeners.erase (p);
}
+#if deal_II_dimension == 3
+
+template<>
+void
+Triangulation<3>::update_neighbors(cell_iterator &cell,
+ bool refining)
+{
+ const unsigned int dim=3;
+
+ Assert(cell->has_children(),
+ ExcMessage("Only cells with children can ask for an update of neighbor information."));
+
+ const RefinementCase<dim> ref_case=cell->refinement_case();
+
+ // visit each face in turn
+ for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
+ {
+ cell_iterator neighbor=cell->neighbor(f);
+ // as default: set all children neighbors
+ // to the cell's neighbor first, if we
+ // are to set neighbors after refining.
+ if (refining)
+ for (unsigned int c=0; c<GeometryInfo<dim>::max_children_per_face; ++c)
+ cell->child(GeometryInfo<dim>::child_cell_on_face(ref_case,f,c))
+ ->set_neighbor(f, neighbor);
+ else
+ // in this case, if we are refined
+ // anisotropically in a way that does
+ // not refine the current face, then
+ // set our child's neighbor as our
+ // neighbor (the child's neighbor might
+ // be more current...).
+ if (GeometryInfo<dim>::face_refinement_case(cell->refinement_case(), f) == RefinementCase<dim>::no_refinement)
+ {
+ const active_cell_iterator child_on_this_face=cell->child(GeometryInfo<dim>::child_cell_on_face(cell->refinement_case(),
+ f,
+ cell->face_orientation(f),
+ cell->face_flip(f),
+ cell->face_rotation(f),
+ RefinementCase<dim>::no_refinement));
+ neighbor=child_on_this_face->neighbor(f);
+ cell->set_neighbor(f, child_on_this_face->neighbor(f));
+ }
+
+ if (neighbor.state()!=IteratorState::valid)
+ // the neighbor is at the
+ // boundary, so simply copy
+ // this to all children at
+ // this face. As this has
+ // been done already, there
+ // is nothing more to do here
+ {}
+ else if (neighbor->active())
+ {
+
+ // the neighbor is active,
+ // so it cannot be refined
+ // along the given face. We
+ // have to set the neighbor
+ // of our children to this
+ // neighbor. This has been
+ // done already. If our
+ // face is not refined AND
+ // if the neighbor is not
+ // coarser we also have to
+ // adjust the neighbor's
+ // neighborship info.
+ if ((GeometryInfo<dim>::face_refinement_case(ref_case,f) == RefinementCase<dim>::no_refinement) && !cell->neighbor_is_coarser(f))
+ if (refining)
+ neighbor->set_neighbor(cell->neighbor_of_neighbor(f),
+ cell->child(GeometryInfo<dim>::child_cell_on_face(ref_case,f,0)));
+ else
+ neighbor->set_neighbor(cell->neighbor_of_neighbor(f),
+ cell);
+
+ }// else if (neighbor->active())
+ else
+ {
+ const bool f_or=cell->face_orientation(f);
+ const bool f_fl=cell->face_flip(f);
+ const bool f_ro=cell->face_rotation(f);
+
+ // now the neighbor has children, so
+ // it is kind of complicated.
+ const RefinementCase<dim-1> our_face_ref_case
+ =GeometryInfo<dim>::face_refinement_case(ref_case,f,f_or,f_fl,f_ro);
+ const RefinementCase<dim-1> face_ref_case
+ =cell->face(f)->refinement_case();
+
+ switch (static_cast<unsigned char> (face_ref_case))
+ {
+ case RefinementCase<dim>::no_refinement:
+ // in this case neither our
+ // cell nor the neighbor is
+ // refined along face
+ // f. however, the above
+ // case should have caught
+ // this situation, as the
+ // neighbor has to be
+ // active then.
+ Assert (false, ExcInternalError());
+ break;
+ case RefinementCase<dim>::cut_x:
+ case RefinementCase<dim>::cut_y:
+ case RefinementCase<dim>::cut_xy:
+ {
+
+ // this is really tricky and
+ // originally there were some
+ // 800 lines of code which were
+ // still buggy. thus we use a
+ // different kind of approach
+ // here: we create a map of our
+ // child cells at the given
+ // face with the (sub)face as
+ // key. Then create a
+ // corresponding (multi-)map of
+ // the neighbor and its
+ // children. As a third
+ // ingredient, we need a map
+ // pointing us from a face to
+ // its parent.
+ const unsigned int nb_nb=cell->neighbor_face_no(f);
+
+ std::map<face_iterator,cell_iterator> our_children;
+ // we only need to fill this
+ // map, if the cell was just
+ // refined. after coarsening,
+ // we should use our own cell
+ // instead
+ if (refining)
+ for (unsigned int c=0; c<std::max(GeometryInfo<dim-1>::n_children(our_face_ref_case),1U); ++c)
+ {
+ cell_iterator child=
+ cell->child(GeometryInfo<dim>::child_cell_on_face(ref_case,
+ f,c,
+ f_or,
+ f_fl,
+ f_ro,
+ our_face_ref_case));
+ our_children.insert(std::make_pair(child->face(f),child));
+ }
+ else
+ our_children.insert(std::make_pair(cell->face(f),cell));
+
+ std::map<face_iterator,face_iterator> parents;
+ for (unsigned int face_child=0; face_child<neighbor->face(nb_nb)->n_children(); ++face_child)
+ parents.insert(std::make_pair(neighbor->face(nb_nb)->child(face_child),neighbor->face(nb_nb)));
+ bool inserted=true;
+ while (inserted)
+ {
+ inserted=false;
+ std::map<face_iterator,face_iterator>::iterator cur_face=parents.begin();
+ for (;cur_face!=parents.end(); ++cur_face)
+ if (cur_face->first->has_children())
+ for (unsigned int fc=0; fc<cur_face->first->n_children(); ++fc)
+ if (parents.find(cur_face->first->child(fc))==parents.end())
+ {
+ parents.insert(std::make_pair(cur_face->first->child(fc),cur_face->first));
+ inserted=true;
+ }
+ }
+
+ const bool nb_f_or=neighbor->face_orientation(nb_nb);
+ const bool nb_f_fl=neighbor->face_flip(nb_nb);
+ const bool nb_f_ro=neighbor->face_rotation(nb_nb);
+
+ std::multimap<face_iterator,cell_iterator> nb_children;
+ nb_children.insert(std::make_pair(neighbor->face(nb_nb),neighbor));
+
+ int current_level=neighbor->level();
+ inserted=true;
+ while (inserted)
+ {
+ inserted=false;
+ std::multimap<face_iterator,cell_iterator>::iterator it=nb_children.begin();
+ for (;it!=nb_children.end(); ++it)
+ // only treat
+ // untreated
+ // cells,
+ // i.e. those
+ // with
+ // level()==current_level
+ if (it->second->level()==current_level &&
+ it->second->has_children())
+ {
+ RefinementCase<dim-1> nb_face_ref_case
+ =GeometryInfo<dim>::face_refinement_case(it->second->refinement_case(),
+ nb_nb,
+ nb_f_or,
+ nb_f_fl,
+ nb_f_ro);
+ for (unsigned int c=0; c<std::max(GeometryInfo<dim-1>::n_children(nb_face_ref_case),1U); ++c)
+ {
+ cell_iterator child=
+ it->second->child(GeometryInfo<dim>::child_cell_on_face(it->second->refinement_case(),
+ nb_nb,c,
+ nb_f_or,
+ nb_f_fl,
+ nb_f_ro,
+ nb_face_ref_case));
+ nb_children.insert(std::make_pair(child->face(nb_nb),child));
+ inserted=true;
+ }
+ }
+ ++current_level;
+ }
+
+ // now loop over all of our
+ // children and set their
+ // neighbor, if available. only
+ // necessary, if we are
+ // refining.
+
+ // declare some iterator which
+ // are needed in any case
+ std::map<face_iterator,cell_iterator>::iterator our_it=our_children.begin(),
+ end_our_it=our_children.end();
+ std::multimap <face_iterator,cell_iterator>::iterator nb_it, end_nb_it;
+
+ if (refining)
+ {
+ for (; our_it!=end_our_it; ++our_it)
+ {
+ face_iterator parent_face=our_it->first;
+ bool further_parents=true;
+
+ while(further_parents &&
+ nb_children.find(parent_face)==nb_children.end())
+ {
+ if (parents.find(parent_face)==parents.end())
+ further_parents=false;
+ parent_face=parents.find(parent_face)->second;
+ }
+
+ if (further_parents)
+ // we found a
+ // corresponding
+ // neighbor_child. if
+ // not, do nothing,
+ // as the default
+ // neighbor set above
+ // is correct.
+ {
+ nb_it=nb_children.lower_bound(parent_face);
+ end_nb_it=nb_children.upper_bound(parent_face);
+
+ // advance to
+ // the last
+ // child at
+ // the given
+ // face, as
+ // this is on
+ // the
+ // highest
+ // level and
+ // thus the
+ // finest one
+ // possible
+ for (; nb_it!=end_nb_it; ++nb_it)
+ our_it->second->set_neighbor(f, nb_it->second);
+ }
+ }
+ }
+
+ // now do the same for the
+ // neighbor and its
+ // children. this is also
+ // necessary if we are
+ // coarsening
+ nb_it=nb_children.begin();
+ end_nb_it=nb_children.end();
+
+ for (; nb_it!=end_nb_it; ++nb_it)
+ {
+ face_iterator parent_face=nb_it->first;
+ bool further_parents=true;
+
+ while(further_parents &&
+ our_children.find(parent_face)==our_children.end())
+ {
+ if (parents.find(parent_face)==parents.end())
+ further_parents=false;
+ parent_face=parents.find(parent_face)->second;
+ }
+
+ if (further_parents)
+ // we found a
+ // corresponding
+ // child. if
+ // not, do
+ // nothing, as
+ // the old
+ // neighbor is
+ // still
+ // correct.
+ {
+ // here, we
+ // only have
+ // one child
+ // at any
+ // given
+ // face, so
+ // we do not
+ // need a
+ // loop.
+ our_it=our_children.find(parent_face);
+ nb_it->second->set_neighbor(nb_nb, our_it->second);
+ }
+ }
+ break;
+ }
+ default:
+ Assert(false, ExcInternalError());
+ break;
+ }// switch (our_face_ref_case)
+
+ }// else -> neighbor has children
+ }// for all faces
+}
+
+#else
+
+template<int dim>
+void
+Triangulation<dim>::update_neighbors(cell_iterator &,
+ bool)
+{
+ Assert(false, ExcNotImplemented());
+}
+
+#endif
+
// explicit instantiations
template class Triangulation<deal_II_dimension>;
const unsigned int TriaAccessor<structdim,dim>::objectdim;
+// anonymous namespace with two little helper functions
+namespace{
+ // given the number of face's child
+ // (subface_no), return the number of the
+ // subface concerning the FaceRefineCase of
+ // the face
+ inline
+ unsigned int translate_subface_no(const TriaIterator<3,TriaObjectAccessor<2, 3> > &face,
+ const unsigned int subface_no)
+ {
+ Assert(face->has_children(), ExcInternalError());
+ Assert(subface_no<face->n_children(), ExcInternalError());
+
+ if(face->child(subface_no)->has_children())
+ // although the subface is refine, it
+ // still matches the face of the cell
+ // invoking the
+ // neighbor_of_coarser_neighbor
+ // function. this means that we are
+ // looking from one cell (anisotropic
+ // child) to a coarser neighbor which is
+ // refined stronger than we are
+ // (isotropically). So we won't be able
+ // to use the neighbor_child_on_subface
+ // function anyway, as the neighbor is
+ // not active. In this case, simply
+ // return the subface_no.
+ return subface_no;
+
+ const bool first_child_has_children=face->child(0)->has_children();
+ // if the first child has children
+ // (FaceRefineCase case_x1y or case_y1x),
+ // then the current subface_no needs to be
+ // 1 and the result of this function is 2,
+ // else simply return the given number,
+ // which is 0 or 1 in an anisotropic case
+ // (case_x, case_y, casex2y or casey2x) or
+ // 0...3 in an isotropic case (case_xy)
+ return subface_no + first_child_has_children;
+ }
+
+
+
+ // given the number of face's child
+ // (subface_no) and grandchild
+ // (subsubface_no), return the number of the
+ // subface concerning the FaceRefineCase of
+ // the face
+ inline
+ unsigned int translate_subface_no(const TriaIterator<3,TriaObjectAccessor<2, 3> > &face,
+ const unsigned int subface_no,
+ const unsigned int subsubface_no)
+ {
+ Assert(face->has_children(), ExcInternalError());
+ // the subface must be refined, otherwise
+ // we would have ended up in the second
+ // function of this name...
+ Assert(face->child(subface_no)->has_children(), ExcInternalError());
+ Assert(subsubface_no<face->child(subface_no)->n_children(), ExcInternalError());
+ // This can only be an anisotropic refinement case
+ Assert(face->refinement_case() < RefinementCase<2>::isotropic_refinement,
+ ExcInternalError());
+
+ const bool first_child_has_children=face->child(0)->has_children();
+
+ const unsigned int e = deal_II_numbers::invalid_unsigned_int;
+
+ // array containing the translation of the
+ // numbers,
+ //
+ // first index: subface_no
+ // second index: subsubface_no
+ // third index: does the first subface have children? -> no and yes
+ unsigned int translated_subface_no[2][2][2]
+ =
+ {{{e,0}, // first subface, first subsubface, first_child_has_children==no and yes
+ {e,1}}, // first subface, second subsubface, first_child_has_children==no and yes
+ {{1,2}, // second subface, first subsubface, first_child_has_children==no and yes
+ {2,3}}}; // second subface, second subsubface, first_child_has_children==no and yes
+
+ Assert(translated_subface_no[subface_no][subsubface_no][first_child_has_children]!=e,
+ ExcInternalError());
+
+ return translated_subface_no[subface_no][subsubface_no][first_child_has_children];
+ }
+}
+
+
+
+
+
/*------------------------ Functions: LineAccessor ---------------------------*/
template <int dim>
template <int dim>
-void TriaObjectAccessor<1, dim>::set_children (const int index) const
+void TriaObjectAccessor<1, dim>::set_children (const unsigned int i, const int index) const
{
Assert (used(), TriaAccessorExceptions::ExcCellNotUsed());
+ Assert (i%2==0, TriaAccessorExceptions::ExcSetOnlyEvenChildren(i));
Assert ((index==-1) ||
(!has_children() && (index>=0)),
TriaAccessorExceptions::ExcCantSetChildren(index));
template <int dim>
void TriaObjectAccessor<1, dim>::clear_children () const
{
- set_children (-1);
+ set_children (0,-1);
}
template <int dim>
-void TriaObjectAccessor<2, dim>::set_children (const int index) const
+void TriaObjectAccessor<2, dim>::set_children (const unsigned int i, const int index) const
{
Assert (used(),
TriaAccessorExceptions::ExcCellNotUsed());
+ Assert (i%2==0, TriaAccessorExceptions::ExcSetOnlyEvenChildren(i));
Assert ((index==-1) ||
- (!has_children() && (index>=0)),
+ (i==0 && !has_children() && (index>=0)) ||
+ (i>0 && has_children() && (index>=0) &&
+ objects().children[2*this->present_index+i/2] == -1),
TriaAccessorExceptions::ExcCantSetChildren(index));
- objects().children[this->present_index] = index;
+ objects().children[2*this->present_index+i/2] = index;
}
template <int dim>
void TriaObjectAccessor<2, dim>::clear_children () const
{
- set_children (-1);
+ set_children (0, -1);
+ set_children (2, -1);
}
#if deal_II_dimension == 3
template <>
-void TriaObjectAccessor<3, 3>::set_children (const int index) const
+void TriaObjectAccessor<3,3>::set_children (const unsigned int i, const int index) const
{
Assert (used(), TriaAccessorExceptions::ExcCellNotUsed());
+ Assert (i%2==0, TriaAccessorExceptions::ExcSetOnlyEvenChildren(i));
Assert ((index==-1) ||
- (!has_children() && (index>=0)),
+ (i==0 && !has_children() && (index>=0)) ||
+ (i>0 && has_children() && (index>=0) &&
+ this->tria->levels[this->present_level]->
+ cells.children[4*this->present_index+i/2] == -1),
TriaAccessorExceptions::ExcCantSetChildren(index));
- this->tria->levels[this->present_level]->cells.children[this->present_index] = index;
+ this->tria->levels[this->present_level]->cells.children[4*this->present_index+i/2] = index;
}
#endif
template <int dim>
void TriaObjectAccessor<3, dim>::clear_children () const
{
- set_children (-1);
+ set_children (0,-1);
+ set_children (2,-1);
+ set_children (4,-1);
+ set_children (6,-1);
}
template <int dim>
-unsigned int CellAccessor<dim>::neighbor_of_neighbor (const unsigned int neighbor) const
+unsigned int CellAccessor<dim>::neighbor_of_neighbor_internal (const unsigned int neighbor) const
{
- // make sure that the neighbor is
- // not on a coarser level
- Assert (neighbor_level(neighbor) == this->present_level,
- TriaAccessorExceptions::ExcNeighborIsCoarser());
Assert (neighbor < GeometryInfo<dim>::faces_per_cell,
TriaAccessorExceptions::ExcInvalidNeighbor(neighbor));
= GeometryInfo<dim>::opposite_face[neighbor];
if (neighbor_cell->face_index (neighbor_guess) == this_face_index)
- return neighbor_guess;
+ return neighbor_guess;
else
// if the guess was false, then
// we need to loop over all
// neighbors and find the number
// the hard way
{
- for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
- if (neighbor_cell->face_index (face) == this_face_index)
- return face;
-
- // we should never get here,
- // since then we did not find
- // our way back...
- Assert (false, ExcInternalError());
+ for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+ if (neighbor_cell->face_index (face_no) == this_face_index)
+ return face_no;
+
+ // running over all neighbors
+ // faces we did not find the
+ // present face. Thereby the
+ // neighbor must be coarser
+ // than the present
+ // cell. Return an invalid
+ // unsigned int in this case.
return numbers::invalid_unsigned_int;
}
}
+template <int dim>
+unsigned int CellAccessor<dim>::neighbor_of_neighbor (const unsigned int neighbor) const
+{
+ const unsigned int n2=neighbor_of_neighbor_internal(neighbor);
+ Assert (n2!=numbers::invalid_unsigned_int, TriaAccessorExceptions::ExcNeighborIsCoarser());
+
+ return n2;
+}
+
+
+
+template <int dim>
+bool
+CellAccessor<dim>::neighbor_is_coarser (const unsigned int neighbor) const
+{
+ return neighbor_of_neighbor_internal(neighbor)==numbers::invalid_unsigned_int;
+}
+
+
+# if deal_II_dimension == 2
+
template <int dim>
std::pair<unsigned int, unsigned int>
CellAccessor<dim>::neighbor_of_coarser_neighbor (const unsigned int neighbor) const
{
+ Assert (neighbor < GeometryInfo<dim>::faces_per_cell,
+ TriaAccessorExceptions::ExcInvalidNeighbor(neighbor));
// make sure that the neighbor is
// on a coarser level
- Assert (neighbor_level(neighbor) < this->present_level,
+ Assert (neighbor_is_coarser(neighbor),
TriaAccessorExceptions::ExcNeighborIsNotCoarser());
+
+ const int this_face_index=face_index(neighbor);
+ const TriaIterator<dim,CellAccessor<dim> > neighbor_cell = this->neighbor(neighbor);
+
+ // usually, on regular patches of
+ // the grid, this cell is just on
+ // the opposite side of the
+ // neighbor that the neighbor is of
+ // this cell. for example in 2d, if
+ // we want to know the
+ // neighbor_of_neighbor if
+ // neighbor==1 (the right
+ // neighbor), then we will get 0
+ // (the left neighbor) in most
+ // cases. look up this relationship
+ // in the table provided by
+ // GeometryInfo and try it
+ const unsigned int face_no_guess
+ = GeometryInfo<dim>::opposite_face[neighbor];
+
+ const TriaIterator<dim,TriaObjectAccessor<dim-1, dim> > face_guess
+ =neighbor_cell->face(face_no_guess);
+
+ if (face_guess->has_children())
+ for (unsigned int subface_no=0; subface_no<face_guess->n_children(); ++subface_no)
+ if (face_guess->child_index(subface_no)==this_face_index)
+ return std::make_pair (face_no_guess, subface_no);
+
+ // if the guess was false, then
+ // we need to loop over all faces
+ // and subfaces and find the
+ // number the hard way
+ for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+ {
+ if (face_no!=face_no_guess)
+ {
+ const TriaIterator<dim,TriaObjectAccessor<dim-1, dim> > face
+ =neighbor_cell->face(face_no);
+ if (face->has_children())
+ for (unsigned int subface_no=0; subface_no<face->n_children(); ++subface_no)
+ if (face->child_index(subface_no)==this_face_index)
+ return std::make_pair (face_no, subface_no);
+ }
+ }
+
+ // we should never get here,
+ // since then we did not find
+ // our way back...
+ Assert (false, ExcInternalError());
+ return std::make_pair (deal_II_numbers::invalid_unsigned_int,
+ deal_II_numbers::invalid_unsigned_int);
+}
+
+#endif
+
+#if deal_II_dimension == 3
+
+template <int dim>
+std::pair<unsigned int, unsigned int>
+CellAccessor<dim>::neighbor_of_coarser_neighbor (const unsigned int neighbor) const
+{
Assert (neighbor < GeometryInfo<dim>::faces_per_cell,
TriaAccessorExceptions::ExcInvalidNeighbor(neighbor));
- Assert (dim>1, ExcImpossibleInDim(dim));
-
+ // make sure that the neighbor is
+ // on a coarser level
+ Assert (neighbor_is_coarser(neighbor),
+ TriaAccessorExceptions::ExcNeighborIsNotCoarser());
+
const int this_face_index=face_index(neighbor);
const TriaIterator<dim,CellAccessor<dim> > neighbor_cell = this->neighbor(neighbor);
// we want to know the
// neighbor_of_neighbor if
// neighbor==1 (the right
- // neighbor), then we will get 3
+ // neighbor), then we will get 0
// (the left neighbor) in most
// cases. look up this relationship
// in the table provided by
if (face_guess->has_children())
for (unsigned int subface_no=0; subface_no<face_guess->n_children(); ++subface_no)
if (face_guess->child_index(subface_no)==this_face_index)
- // return the result, but don't forget
- // to take care of possible rotation,
- // flip and wrong orientation of the
- // neighbor's face...
- return std::make_pair (face_no_guess,
- GeometryInfo<dim>::real_to_standard_face_vertex(subface_no,
- neighbor_cell->face_orientation(face_no_guess),
- neighbor_cell->face_flip(face_no_guess),
- neighbor_cell->face_rotation(face_no_guess)));
+ // call a helper function, that
+ // translates the current subface
+ // number to a subface number for
+ // the current FaceRefineCase
+ return std::make_pair (face_no_guess, translate_subface_no(face_guess, subface_no));
+ else if (face_guess->child(subface_no)->has_children())
+ for (unsigned int subsub_no=0; subsub_no<face_guess->child(subface_no)->n_children(); ++subsub_no)
+ if (face_guess->child(subface_no)->child_index(subsub_no)==this_face_index)
+ // call a helper function, that
+ // translates the current subface
+ // number and subsubface number to
+ // a subface number for the current
+ // FaceRefineCase
+ return std::make_pair (face_no_guess, translate_subface_no(face_guess, subface_no, subsub_no));
+
+
// if the guess was false, then
// we need to loop over all faces
if (face->has_children())
for (unsigned int subface_no=0; subface_no<face->n_children(); ++subface_no)
if (face->child_index(subface_no)==this_face_index)
- // return the result, but don't forget
- // to take care of possible rotation,
- // flip and wrong orientation of the
- // neighbor's face...
- return std::make_pair (face_no,
- GeometryInfo<dim>::real_to_standard_face_vertex(subface_no,
- neighbor_cell->face_orientation(face_no),
- neighbor_cell->face_flip(face_no),
- neighbor_cell->face_rotation(face_no)));
+ // call a helper function, that
+ // translates the current subface
+ // number to a subface number for
+ // the current FaceRefineCase
+ return std::make_pair (face_no, translate_subface_no(face, subface_no));
+ else if (face->child(subface_no)->has_children())
+ for (unsigned int subsub_no=0; subsub_no<face->child(subface_no)->n_children(); ++subsub_no)
+ if (face->child(subface_no)->child_index(subsub_no)==this_face_index)
+ // call a helper function, that
+ // translates the current subface
+ // number and subsubface number to
+ // a subface number for the current
+ // FaceRefineCase
+ return std::make_pair (face_no, translate_subface_no(face, subface_no, subsub_no));
}
}
numbers::invalid_unsigned_int);
}
+#endif
+
template <int dim>
ExcMessage ("The present cell must not have children!"));
Assert (!this->at_boundary(face),
ExcMessage ("The present cell must have a valid neighbor!"));
- Assert (this->neighbor(face)->level() == this->level(),
- ExcMessage ("The neighbor must be on the same level as this cell!"));
Assert (this->neighbor(face)->has_children() == true,
ExcMessage ("The neighbor must have children!"));
const unsigned int neighbor_neighbor
= this->neighbor_of_neighbor (face);
const unsigned int neighbor_child_index
- = GeometryInfo<2>::child_cell_on_face(neighbor_neighbor,subface);
-
- return this->neighbor(face)->child(neighbor_child_index);
+ = GeometryInfo<2>::child_cell_on_face(
+ this->neighbor(face)->refinement_case(),neighbor_neighbor,subface);
+
+ TriaIterator<2,CellAccessor<2> > sub_neighbor = this->neighbor(face)->child(neighbor_child_index);
+ // the neighbors child can have children,
+ // which are not further refined along the
+ // face under consideration. as we are
+ // normally interested in one of this
+ // child's child, search for the right one.
+ while(sub_neighbor->has_children())
+ {
+ Assert ((GeometryInfo<2>::face_refinement_case(sub_neighbor->refinement_case(),
+ neighbor_neighbor) ==
+ RefinementCase<2>::no_refinement),
+ ExcInternalError());
+ sub_neighbor = sub_neighbor->child(GeometryInfo<2>::child_cell_on_face(
+ sub_neighbor->refinement_case(),neighbor_neighbor,0));
+
+ }
+
+ return sub_neighbor;
}
#endif
ExcMessage ("The present cell must not have children!"));
Assert (!this->at_boundary(face),
ExcMessage ("The present cell must have a valid neighbor!"));
- Assert (this->neighbor(face)->level() == this->level(),
- ExcMessage ("The neighbor must be on the same level as this cell!"));
Assert (this->neighbor(face)->has_children() == true,
ExcMessage ("The neighbor must have children!"));
- // this function returns they neighbor's
+ // this function returns the neighbor's
// child on a given face and
- // subface. However, irrespective of the
- // actual face orientation, flip and rotation
- // of the cells face it returns that child,
- // which is neighboring the subface which
- // would be subface number @p subface, if the
- // face was in standard orientation. thus,
- // our first task is to extract the
- // information, which real_subface_no
- // corresponds to that for the actual face,
- // which might have non-standard orientation,
- // flip and rotation.
-
- // to this end: the subfaces are numbered
- // according to the vertices of the
- // face. thus we can use the
- // standard_to_real_face_vertex function in
- // GeometryInfo<dim> to translate the given
- // subface to the real_subface_no
- unsigned int real_subface_no=GeometryInfo<3>::
- standard_to_real_face_vertex(subface,
- this->face_orientation(face),
- this->face_flip(face),
- this->face_rotation(face));
- // get the neighbor's number for the given
- // face and the neighbor
- const unsigned int neighbor_neighbor
- = this->neighbor_of_neighbor (face);
+ // subface.
+
+ // we have to consider one other aspect here:
+ // The face might be refined
+ // anisotropically. In this case, the subface
+ // number refers to the following, where we
+ // look at the face from the current cell,
+ // thus the subfaces are in standard
+ // orientation concerning the cell
+ //
+ // for isotropic refinement
+ //
+ // *---*---*
+ // | 2 | 3 |
+ // *---*---*
+ // | 0 | 1 |
+ // *---*---*
+ //
+ // for 2*anisotropic refinement
+ // (first cut_y, then cut_x)
+ //
+ // *---*---*
+ // | 2 | 3 |
+ // *---*---*
+ // | 0 | 1 |
+ // *---*---*
+ //
+ // for 2*anisotropic refinement
+ // (first cut_x, then cut_y)
+ //
+ // *---*---*
+ // | 1 | 3 |
+ // *---*---*
+ // | 0 | 2 |
+ // *---*---*
+ //
+ // for purely anisotropic refinement:
+ //
+ // *---*---* *-------*
+ // | | | | 1 |
+ // | 0 | 1 | or *-------*
+ // | | | | 0 |
+ // *---*---* *-------*
+ //
+ // for "mixed" refinement:
+ //
+ // *---*---* *---*---* *---*---* *-------*
+ // | | 2 | | 1 | | | 1 | 2 | | 2 |
+ // | 0 *---* or *---* 2 | or *---*---* or *---*---*
+ // | | 1 | | 0 | | | 0 | | 0 | 1 |
+ // *---*---* *---*---* *-------* *---*---*
+
+ const Triangulation<3>::face_iterator mother_face=this->face(face);
+ const unsigned int total_children=mother_face->number_of_children();
+ Assert (subface<total_children,ExcIndexRange(subface,0,total_children));
+ Assert(total_children<=GeometryInfo<3>::max_children_per_face, ExcInternalError());
+
+ unsigned int neighbor_neighbor;
+ TriaIterator<3,CellAccessor<3> > neighbor_child;
const TriaIterator<3,CellAccessor<3> > neighbor=this->neighbor(face);
+
- // now use the info provided by GeometryInfo
- // to extract the neighbors child number
- const unsigned int neighbor_child_index
- = GeometryInfo<3>::child_cell_on_face(neighbor_neighbor, real_subface_no,
- neighbor->face_orientation(neighbor_neighbor),
- neighbor->face_flip(neighbor_neighbor),
- neighbor->face_rotation(neighbor_neighbor));
- const TriaIterator<3,CellAccessor<3> > neighbor_child=
- neighbor->child(neighbor_child_index);
-
- // make sure that the neighbor child cell we
- // have found shares the desired subface.
- Assert((this->face(face)->child(real_subface_no) ==
- neighbor_child->face(neighbor_neighbor)),
- ExcInternalError());
+ const RefinementCase<2> mother_face_ref_case=mother_face->refinement_case();
+ if (mother_face_ref_case==RefinementCase<2>::cut_xy) // total_children==4
+ {
+ // this case is quite easy. we are sure,
+ // that the neighbor is not coarser.
+
+ // get the neighbor's number for the given
+ // face and the neighbor
+ neighbor_neighbor
+ = this->neighbor_of_neighbor (face);
+
+ // now use the info provided by GeometryInfo
+ // to extract the neighbors child number
+ const unsigned int neighbor_child_index
+ = GeometryInfo<3>::child_cell_on_face(neighbor->refinement_case(),
+ neighbor_neighbor, subface,
+ neighbor->face_orientation(neighbor_neighbor),
+ neighbor->face_flip(neighbor_neighbor),
+ neighbor->face_rotation(neighbor_neighbor));
+ neighbor_child=
+ neighbor->child(neighbor_child_index);
+
+ // make sure that the neighbor child cell we
+ // have found shares the desired subface.
+ Assert((this->face(face)->child(subface) ==
+ neighbor_child->face(neighbor_neighbor)),
+ ExcInternalError());
+ }
+ else //-> the face is refined anisotropically
+ {
+ // first of all, we have to find the
+ // neighbor at one of the anisotropic
+ // children of the
+ // mother_face. determine, which of
+ // these we need.
+ unsigned int first_child_to_find;
+ unsigned int neighbor_child_index;
+ if (total_children==2)
+ first_child_to_find=subface;
+ else
+ {
+ first_child_to_find=subface/2;
+ if (total_children==3 &&
+ subface==1 &&
+ !mother_face->child(0)->has_children())
+ first_child_to_find=1;
+ }
+ if (neighbor_is_coarser(face))
+ {
+ std::pair<unsigned int, unsigned int> indices=neighbor_of_coarser_neighbor(face);
+ neighbor_neighbor=indices.first;
+
+
+ // we have to translate our
+ // subface_index according to the
+ // RefineCase and subface index of
+ // the coarser face (our face is an
+ // anisotropic child of the coarser
+ // face), 'a' denotes our
+ // subface_index 0 and 'b' denotes
+ // our subface_index 1, whereas 0...3
+ // denote isotropic subfaces of the
+ // coarser face
+ //
+ // cut_x and coarser_subface_index=0
+ //
+ // *---*---*
+ // |b=2| |
+ // | | |
+ // |a=0| |
+ // *---*---*
+ //
+ // cut_x and coarser_subface_index=1
+ //
+ // *---*---*
+ // | |b=3|
+ // | | |
+ // | |a=1|
+ // *---*---*
+ //
+ // cut_y and coarser_subface_index=0
+ //
+ // *-------*
+ // | |
+ // *-------*
+ // |a=0 b=1|
+ // *-------*
+ //
+ // cut_y and coarser_subface_index=1
+ //
+ // *-------*
+ // |a=2 b=3|
+ // *-------*
+ // | |
+ // *-------*
+ unsigned int iso_subface;
+ if (neighbor->face(neighbor_neighbor)->refinement_case()==RefinementCase<2>::cut_x)
+ iso_subface=2*first_child_to_find + indices.second;
+ else
+ {
+ Assert(neighbor->face(neighbor_neighbor)->refinement_case()==RefinementCase<2>::cut_y,
+ ExcInternalError());
+ iso_subface=first_child_to_find + 2*indices.second;
+ }
+ neighbor_child_index
+ =GeometryInfo<3>::child_cell_on_face(neighbor->refinement_case(),
+ neighbor_neighbor,
+ iso_subface,
+ neighbor->face_orientation(neighbor_neighbor),
+ neighbor->face_flip(neighbor_neighbor),
+ neighbor->face_rotation(neighbor_neighbor));
+ }
+ else //neighbor is not coarser
+ {
+ neighbor_neighbor=neighbor_of_neighbor(face);
+ neighbor_child_index
+ =GeometryInfo<3>::child_cell_on_face(neighbor->refinement_case(),
+ neighbor_neighbor,
+ first_child_to_find,
+ neighbor->face_orientation(neighbor_neighbor),
+ neighbor->face_flip(neighbor_neighbor),
+ neighbor->face_rotation(neighbor_neighbor),
+ mother_face_ref_case);
+ }
+
+ neighbor_child=neighbor->child(neighbor_child_index);
+ // it might be, that the neighbor_child
+ // has children, which are not refined
+ // along the given subface. go down that
+ // list and deliver the last of those.
+ while (neighbor_child->has_children() &&
+ GeometryInfo<3>::face_refinement_case(neighbor_child->refinement_case(),neighbor_neighbor)==RefinementCase<2>::no_refinement)
+ neighbor_child=neighbor_child->child(GeometryInfo<3>::child_cell_on_face(neighbor_child->refinement_case(),
+ neighbor_neighbor,0));
+
+ // if there are two total subfaces, we
+ // are finished. if there are four we
+ // have to get a child of our current
+ // neighbor_child. If there are three,
+ // we have to check which of the two
+ // possibilities applies.
+ if (total_children==3)
+ {
+ if (mother_face->child(0)->has_children())
+ {
+ if (subface<2)
+ neighbor_child=neighbor_child->child(GeometryInfo<3>::child_cell_on_face(neighbor_child->refinement_case(),
+ neighbor_neighbor,subface,
+ neighbor_child->face_orientation(neighbor_neighbor),
+ neighbor_child->face_flip(neighbor_neighbor),
+ neighbor_child->face_rotation(neighbor_neighbor),
+ mother_face->child(0)->refinement_case()));
+ }
+ else
+ {
+ Assert(mother_face->child(1)->has_children(), ExcInternalError());
+ if (subface>0)
+ neighbor_child=neighbor_child->child(GeometryInfo<3>::child_cell_on_face(neighbor_child->refinement_case(),
+ neighbor_neighbor,subface-1,
+ neighbor_child->face_orientation(neighbor_neighbor),
+ neighbor_child->face_flip(neighbor_neighbor),
+ neighbor_child->face_rotation(neighbor_neighbor),
+ mother_face->child(1)->refinement_case()));
+ }
+ }
+ else if (total_children==4)
+ {
+ neighbor_child=neighbor_child->child(GeometryInfo<3>::child_cell_on_face(neighbor_child->refinement_case(),
+ neighbor_neighbor,subface%2,
+ neighbor_child->face_orientation(neighbor_neighbor),
+ neighbor_child->face_flip(neighbor_neighbor),
+ neighbor_child->face_rotation(neighbor_neighbor),
+ mother_face->child(subface/2)->refinement_case()));
+ }
+ }
+
+ // it might be, that the neighbor_child has
+ // children, which are not refined along the
+ // given subface. go down that list and
+ // deliver the last of those.
+ while (neighbor_child->has_children())
+ neighbor_child=neighbor_child->child(GeometryInfo<3>::child_cell_on_face(neighbor_child->refinement_case(),
+ neighbor_neighbor,0));
+
+#ifdef DEBUG
+ // check, whether the face neighbor_child
+ // matches the requested subface
+ Triangulation<3>::face_iterator requested;
+ switch (this->subface_case(face))
+ {
+ case internal::SubfaceCase<3>::case_x:
+ case internal::SubfaceCase<3>::case_y:
+ case internal::SubfaceCase<3>::case_xy:
+ requested=mother_face->child(subface);
+ break;
+ case internal::SubfaceCase<3>::case_x1y2y:
+ case internal::SubfaceCase<3>::case_y1x2x:
+ requested=mother_face->child(subface/2)->child(subface%2);
+ break;
+
+ case internal::SubfaceCase<3>::case_x1y:
+ case internal::SubfaceCase<3>::case_y1x:
+ switch (subface)
+ {
+ case 0:
+ case 1:
+ requested=mother_face->child(0)->child(subface);
+ break;
+ case 2:
+ requested=mother_face->child(1);
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ }
+ break;
+ case internal::SubfaceCase<3>::case_x2y:
+ case internal::SubfaceCase<3>::case_y2x:
+ switch (subface)
+ {
+ case 0:
+ requested=mother_face->child(0);
+ break;
+ case 1:
+ case 2:
+ requested=mother_face->child(1)->child(subface-1);
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ }
+ break;
+ default:
+ Assert(false, ExcInternalError());
+ break;
+ }
+ Assert(requested==neighbor_child->face(neighbor_neighbor),
+ ExcInternalError());
+#endif
return neighbor_child;
+
}
#endif
refine_flags.reserve (total_cells);
refine_flags.insert (refine_flags.end(),
total_cells - refine_flags.size(),
- false);
+ RefinementCase<dim>::no_refinement);
coarsen_flags.reserve (total_cells);
coarsen_flags.insert (coarsen_flags.end(),
// they may over-allocate by up to
// as many elements as an integer
// has bits
- Assert (refine_flags.size() <= refine_flags.capacity() + sizeof(int)*8 ||
- refine_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ Assert (refine_flags.size() <=
+ refine_flags.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
ExcMemoryWasted ("refine_flags",
refine_flags.size(), refine_flags.capacity()));
Assert (coarsen_flags.size() <= coarsen_flags.capacity() + sizeof(int)*8 ||
unsigned int
TriaLevel<dim>::memory_consumption () const
{
- return (MemoryConsumption::memory_consumption (refine_flags) +
- MemoryConsumption::memory_consumption (coarsen_flags) +
+ return (MemoryConsumption::memory_consumption (coarsen_flags) +
MemoryConsumption::memory_consumption (neighbors) +
- MemoryConsumption::memory_consumption (cells));
+ MemoryConsumption::memory_consumption (cells) +
+ MemoryConsumption::memory_consumption (refine_flags));
}
// This specialization should be only temporary, until the TriaObjects
refine_flags.reserve (total_cells);
refine_flags.insert (refine_flags.end(),
total_cells - refine_flags.size(),
- false);
+ RefinementCase<3>::no_refinement);
coarsen_flags.reserve (total_cells);
coarsen_flags.insert (coarsen_flags.end(),
// they may over-allocate by up to
// as many elements as an integer
// has bits
- Assert (refine_flags.size() <= refine_flags.capacity() + sizeof(int)*8 ||
- refine_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ Assert (refine_flags.size() <=
+ refine_flags.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
ExcMemoryWasted ("refine_flags",
refine_flags.size(), refine_flags.capacity()));
Assert (coarsen_flags.size() <= coarsen_flags.capacity() + sizeof(int)*8 ||
unsigned int
TriaLevel<3>::memory_consumption () const
{
- return (MemoryConsumption::memory_consumption (refine_flags) +
- MemoryConsumption::memory_consumption (coarsen_flags) +
+ return (MemoryConsumption::memory_consumption (coarsen_flags) +
MemoryConsumption::memory_consumption (neighbors) +
- MemoryConsumption::memory_consumption (cells));
+ MemoryConsumption::memory_consumption (cells) +
+ MemoryConsumption::memory_consumption (refine_flags));
}
#endif
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2006, 2007 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
+
+#include <base/memory_consumption.h>
+#include <grid/tria_objects.h>
+#include <grid/tria.h>
+#include <grid/tria_iterator.h>
+#include <grid/tria_accessor.h>
+
+#include <algorithm>
+#include <functional>
+
+
+
+DEAL_II_NAMESPACE_OPEN
+
+namespace internal
+{
+ namespace Triangulation
+ {
+ template<>
+ void
+ TriaObjects<TriaObject<1> >::reserve_space (const unsigned int new_lines_in_pairs,
+ const unsigned int new_lines_single)
+ {
+ Assert(new_lines_in_pairs%2==0, ExcInternalError());
+
+ next_free_single=0;
+ next_free_pair=0;
+ reverse_order_next_free_single=false;
+
+ // count the number of lines, of
+ // unused single lines and of
+ // unused pairs of lines
+ unsigned int n_lines=0;
+ unsigned int n_unused_pairs=0;
+ unsigned int n_unused_singles=0;
+ for (unsigned int i=0; i<used.size(); ++i)
+ {
+ if (used[i])
+ ++n_lines;
+ else if (i+1<used.size())
+ {
+ if (used[i+1])
+ {
+ ++n_unused_singles;
+ if (next_free_single==0)
+ next_free_single=i;
+ }
+ else
+ {
+ ++n_unused_pairs;
+ if (next_free_pair==0)
+ next_free_pair=i;
+ ++i;
+ }
+ }
+ else
+ ++n_unused_singles;
+ }
+ Assert(n_lines+2*n_unused_pairs+n_unused_singles==used.size(),
+ ExcInternalError());
+
+ // how many single lines are needed in
+ // addition to n_unused_singles?
+ const int additional_single_lines=
+ new_lines_single-n_unused_singles;
+
+ unsigned int new_size=
+ used.size() + new_lines_in_pairs - 2*n_unused_pairs;
+ if (additional_single_lines>0)
+ new_size+=additional_single_lines;
+
+ // only allocate space if necessary
+ if (new_size>cells.size())
+ {
+ cells.reserve (new_size);
+ cells.insert (cells.end(),
+ new_size-cells.size(),
+ TriaObject<1> ());
+
+ used.reserve (new_size);
+ used.insert (used.end(),
+ new_size-used.size(),
+ false);
+
+ user_flags.reserve (new_size);
+ user_flags.insert (user_flags.end(),
+ new_size-user_flags.size(),
+ false);
+
+ children.reserve (new_size);
+ children.insert (children.end(),
+ new_size-children.size(),
+ -1);
+
+ material_id.reserve (new_size);
+ material_id.insert (material_id.end(),
+ new_size-material_id.size(),
+ 255);
+
+ user_data.reserve (new_size);
+ user_data.insert (user_data.end(),
+ new_size-user_data.size(),
+ UserData());
+ }
+
+ if (n_unused_singles==0)
+ {
+ next_free_single=new_size-1;
+ reverse_order_next_free_single=true;
+ }
+ }
+
+
+ template<>
+ void
+ TriaObjects<TriaObject<2> >::reserve_space (const unsigned int new_quads_in_pairs,
+ const unsigned int new_quads_single)
+ {
+ Assert(new_quads_in_pairs%2==0, ExcInternalError());
+
+ next_free_single=0;
+ next_free_pair=0;
+ reverse_order_next_free_single=false;
+
+ // count the number of lines, of
+ // unused single lines and of
+ // unused pairs of lines
+ unsigned int n_quads=0;
+ unsigned int n_unused_pairs=0;
+ unsigned int n_unused_singles=0;
+ for (unsigned int i=0; i<used.size(); ++i)
+ {
+ if (used[i])
+ ++n_quads;
+ else if (i+1<used.size())
+ {
+ if (used[i+1])
+ {
+ ++n_unused_singles;
+ if (next_free_single==0)
+ next_free_single=i;
+ }
+ else
+ {
+ ++n_unused_pairs;
+ if (next_free_pair==0)
+ next_free_pair=i;
+ ++i;
+ }
+ }
+ else
+ ++n_unused_singles;
+ }
+ Assert(n_quads+2*n_unused_pairs+n_unused_singles==used.size(),
+ ExcInternalError());
+
+ // how many single quads are needed in
+ // addition to n_unused_quads?
+ const int additional_single_quads=
+ new_quads_single-n_unused_singles;
+
+ unsigned int new_size=
+ used.size() + new_quads_in_pairs - 2*n_unused_pairs;
+ if (additional_single_quads>0)
+ new_size+=additional_single_quads;
+
+ // only allocate space if necessary
+ if (new_size>cells.size())
+ {
+ cells.reserve (new_size);
+ cells.insert (cells.end(),
+ new_size-cells.size(),
+ TriaObject<2> ());
+
+ used.reserve (new_size);
+ used.insert (used.end(),
+ new_size-used.size(),
+ false);
+
+ user_flags.reserve (new_size);
+ user_flags.insert (user_flags.end(),
+ new_size-user_flags.size(),
+ false);
+
+ children.reserve (2*new_size);
+ children.insert (children.end(),
+ 2*new_size-children.size(),
+ -1);
+
+ refinement_cases.reserve (new_size);
+ refinement_cases.insert (refinement_cases.end(),
+ new_size - refinement_cases.size(),
+ RefinementCase<2>::no_refinement);
+
+
+ material_id.reserve (new_size);
+ material_id.insert (material_id.end(),
+ new_size-material_id.size(),
+ 255);
+
+ user_data.reserve (new_size);
+ user_data.insert (user_data.end(),
+ new_size-user_data.size(),
+ UserData());
+ }
+
+ if (n_unused_singles==0)
+ {
+ next_free_single=new_size-1;
+ reverse_order_next_free_single=true;
+ }
+ }
+
+
+ void
+ TriaObjectsHex::reserve_space (const unsigned int new_hexes)
+ {
+ const unsigned int new_size = new_hexes +
+ std::count_if (used.begin(),
+ used.end(),
+ std::bind2nd (std::equal_to<bool>(), true));
+
+ // see above...
+ if (new_size>cells.size())
+ {
+ cells.reserve (new_size);
+ cells.insert (cells.end(),
+ new_size-cells.size(),
+ TriaObject<3> ());
+
+ used.reserve (new_size);
+ used.insert (used.end(),
+ new_size-used.size(),
+ false);
+
+ user_flags.reserve (new_size);
+ user_flags.insert (user_flags.end(),
+ new_size-user_flags.size(),
+ false);
+
+ children.reserve (4*new_size);
+ children.insert (children.end(),
+ 4*new_size-children.size(),
+ -1);
+
+ material_id.reserve (new_size);
+ material_id.insert (material_id.end(),
+ new_size-material_id.size(),
+ 255);
+
+ user_data.reserve (new_size);
+ user_data.insert (user_data.end(),
+ new_size-user_data.size(),
+ UserData());
+
+ face_orientations.reserve (new_size * GeometryInfo<3>::faces_per_cell);
+ face_orientations.insert (face_orientations.end(),
+ new_size * GeometryInfo<3>::faces_per_cell
+ - face_orientations.size(),
+ true);
+
+ refinement_cases.reserve (new_size);
+ refinement_cases.insert (refinement_cases.end(),
+ new_size-refinement_cases.size(),
+ RefinementCase<3>::no_refinement);
+
+ face_flips.reserve (new_size * GeometryInfo<3>::faces_per_cell);
+ face_flips.insert (face_flips.end(),
+ new_size * GeometryInfo<3>::faces_per_cell
+ - face_flips.size(),
+ false);
+ face_rotations.reserve (new_size * GeometryInfo<3>::faces_per_cell);
+ face_rotations.insert (face_rotations.end(),
+ new_size * GeometryInfo<3>::faces_per_cell
+ - face_rotations.size(),
+ false);
+ }
+ next_free_single=next_free_pair=0;
+ }
+
+
+ void
+ TriaObjectsQuad3D::reserve_space (const unsigned int new_quads_in_pairs,
+ const unsigned int new_quads_single)
+ {
+ Assert(new_quads_in_pairs%2==0, ExcInternalError());
+
+ next_free_single=0;
+ next_free_pair=0;
+ reverse_order_next_free_single=false;
+
+ // count the number of lines, of unused
+ // single lines and of unused pairs of
+ // lines
+ unsigned int n_quads=0;
+ unsigned int n_unused_pairs=0;
+ unsigned int n_unused_singles=0;
+ for (unsigned int i=0; i<used.size(); ++i)
+ {
+ if (used[i])
+ ++n_quads;
+ else if (i+1<used.size())
+ {
+ if (used[i+1])
+ {
+ ++n_unused_singles;
+ if (next_free_single==0)
+ next_free_single=i;
+ }
+ else
+ {
+ ++n_unused_pairs;
+ if (next_free_pair==0)
+ next_free_pair=i;
+ ++i;
+ }
+ }
+ else
+ ++n_unused_singles;
+ }
+ Assert(n_quads+2*n_unused_pairs+n_unused_singles==used.size(),
+ ExcInternalError());
+
+ // how many single quads are needed in
+ // addition to n_unused_quads?
+ const int additional_single_quads=
+ new_quads_single-n_unused_singles;
+
+ unsigned int new_size=
+ used.size() + new_quads_in_pairs - 2*n_unused_pairs;
+ if (additional_single_quads>0)
+ new_size+=additional_single_quads;
+
+ // see above...
+ if (new_size>cells.size())
+ {
+ // reseve space for the base class
+ TriaObjects<TriaObject<2> >::reserve_space(new_quads_in_pairs,new_quads_single);
+ // reserve the field of the derived
+ // class
+ line_orientations.reserve (new_size * GeometryInfo<2>::lines_per_cell);
+ line_orientations.insert (line_orientations.end(),
+ new_size * GeometryInfo<2>::lines_per_cell
+ - line_orientations.size(),
+ true);
+ }
+
+ if (n_unused_singles==0)
+ {
+ next_free_single=new_size-1;
+ reverse_order_next_free_single=true;
+ }
+ }
+
+
+ template<>
+ void
+ TriaObjects<TriaObject<1> >::monitor_memory (const unsigned int) const
+ {
+ // check that we have not allocated
+ // too much memory. note that bool
+ // vectors allocate their memory in
+ // chunks of whole integers, so
+ // they may over-allocate by up to
+ // as many elements as an integer
+ // has bits
+ Assert (cells.size() <=
+ cells.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
+ ExcMemoryWasted ("lines",
+ cells.size(), cells.capacity()));
+ Assert (children.size() <=
+ children.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
+ ExcMemoryWasted ("children",
+ children.size(), children.capacity()));
+ Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
+ used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ ExcMemoryWasted ("used",
+ used.size(), used.capacity()));
+ Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
+ user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ ExcMemoryWasted ("user_flags",
+ user_flags.size(), user_flags.capacity()));
+ Assert (cells.size() == used.size(),
+ ExcMemoryInexact (cells.size(), used.size()));
+ Assert (cells.size() == user_flags.size(),
+ ExcMemoryInexact (cells.size(), user_flags.size()));
+ Assert (cells.size() == children.size(),
+ ExcMemoryInexact (cells.size(), children.size()));
+ Assert (cells.size() == material_id.size(),
+ ExcMemoryInexact (cells.size(), material_id.size()));
+ Assert (cells.size() == user_data.size(),
+ ExcMemoryInexact (cells.size(), user_data.size()));
+ }
+
+
+ template<>
+ void
+ TriaObjects<TriaObject<2> >::monitor_memory (const unsigned int) const
+ {
+ // check that we have not allocated
+ // too much memory. note that bool
+ // vectors allocate their memory in
+ // chunks of whole integers, so
+ // they may over-allocate by up to
+ // as many elements as an integer
+ // has bits
+ Assert (cells.size() <=
+ cells.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
+ ExcMemoryWasted ("quads",
+ cells.size(), cells.capacity()));
+ Assert (children.size() <=
+ children.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
+ ExcMemoryWasted ("children",
+ children.size(), children.capacity()));
+ Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
+ used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ ExcMemoryWasted ("used",
+ used.size(), used.capacity()));
+ Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
+ user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ ExcMemoryWasted ("user_flags",
+ user_flags.size(), user_flags.capacity()));
+ Assert (cells.size() == used.size(),
+ ExcMemoryInexact (cells.size(), used.size()));
+ Assert (cells.size() == user_flags.size(),
+ ExcMemoryInexact (cells.size(), user_flags.size()));
+ Assert (2*cells.size() == children.size(),
+ ExcMemoryInexact (cells.size(), children.size()));
+ Assert (cells.size() == refinement_cases.size(),
+ ExcMemoryInexact (cells.size(), refinement_cases.size()));
+ Assert (cells.size() == material_id.size(),
+ ExcMemoryInexact (cells.size(), material_id.size()));
+ Assert (cells.size() == user_data.size(),
+ ExcMemoryInexact (cells.size(), user_data.size()));
+ }
+
+
+ void
+ TriaObjectsHex::monitor_memory (const unsigned int) const
+ {
+ // check that we have not allocated
+ // too much memory. note that bool
+ // vectors allocate their memory in
+ // chunks of whole integers, so
+ // they may over-allocate by up to
+ // as many elements as an integer
+ // has bits
+ Assert (cells.size() <=
+ cells.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
+ ExcMemoryWasted ("hexes",
+ cells.size(), cells.capacity()));
+ Assert (children.size() <=
+ children.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
+ ExcMemoryWasted ("children",
+ children.size(), children.capacity()));
+ Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
+ used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ ExcMemoryWasted ("used",
+ used.size(), used.capacity()));
+ Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
+ user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
+ ExcMemoryWasted ("user_flags",
+ user_flags.size(), user_flags.capacity()));
+ Assert (cells.size() == used.size(),
+ ExcMemoryInexact (cells.size(), used.size()));
+ Assert (cells.size() == user_flags.size(),
+ ExcMemoryInexact (cells.size(), user_flags.size()));
+ Assert (4*cells.size() == children.size(),
+ ExcMemoryInexact (cells.size(), children.size()));
+ Assert (cells.size() == material_id.size(),
+ ExcMemoryInexact (cells.size(), material_id.size()));
+ Assert (cells.size() == user_data.size(),
+ ExcMemoryInexact (cells.size(), user_data.size()));
+ Assert (cells.size() * GeometryInfo<3>::faces_per_cell
+ == face_orientations.size(),
+ ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
+ face_orientations.size()));
+ Assert (cells.size() * GeometryInfo<3>::faces_per_cell
+ == face_flips.size(),
+ ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
+ face_flips.size()));
+ Assert (cells.size() * GeometryInfo<3>::faces_per_cell
+ == face_rotations.size(),
+ ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
+ face_rotations.size()));
+ }
+
+
+ void
+ TriaObjectsQuad3D::monitor_memory (const unsigned int) const
+ {
+ // check that we have not allocated
+ // too much memory. note that bool
+ // vectors allocate their memory in
+ // chunks of whole integers, so
+ // they may over-allocate by up to
+ // as many elements as an integer
+ // has bits
+ Assert (cells.size() * GeometryInfo<2>::lines_per_cell
+ == line_orientations.size(),
+ ExcMemoryInexact (cells.size() * GeometryInfo<2>::lines_per_cell,
+ line_orientations.size()));
+ TriaObjects<TriaObject<2> >::monitor_memory (3);
+
+ }
+
+
+ template <typename G>
+ void
+ TriaObjects<G>::clear()
+ {
+ cells.clear();
+ children.clear();
+ refinement_cases.clear();
+ used.clear();
+ user_flags.clear();
+ material_id.clear();
+ user_data.clear();
+ user_data_type = data_unknown;
+ }
+
+
+ void
+ TriaObjectsHex::clear()
+ {
+ TriaObjects<TriaObject<3> >::clear();
+ face_orientations.clear();
+ face_flips.clear();
+ face_rotations.clear();
+ }
+
+
+ void
+ TriaObjectsQuad3D::clear()
+ {
+ TriaObjects<TriaObject<2> >::clear();
+ line_orientations.clear();
+ }
+
+
+ template<typename G>
+ unsigned int
+ TriaObjects<G>::memory_consumption () const
+ {
+ return (MemoryConsumption::memory_consumption (cells) +
+ MemoryConsumption::memory_consumption (children) +
+ MemoryConsumption::memory_consumption (used) +
+ MemoryConsumption::memory_consumption (user_flags) +
+ MemoryConsumption::memory_consumption (material_id) +
+ MemoryConsumption::memory_consumption (refinement_cases) +
+ user_data.capacity() * sizeof(UserData) + sizeof(user_data));
+ }
+
+
+ unsigned int
+ TriaObjectsHex::memory_consumption () const
+ {
+ return (MemoryConsumption::memory_consumption (face_orientations) +
+ MemoryConsumption::memory_consumption (face_flips) +
+ MemoryConsumption::memory_consumption (face_rotations) +
+ TriaObjects<TriaObject<3> >::memory_consumption() );
+ }
+
+
+ unsigned int
+ TriaObjectsQuad3D::memory_consumption () const
+ {
+ return (MemoryConsumption::memory_consumption (line_orientations) +
+ this->TriaObjects<TriaObject<2> >::memory_consumption() );
+ }
+
+
+
+ // explicit instantiations
+
+ template class TriaObjects<TriaObject<1> >;
+ template class TriaObjects<TriaObject<2> >;
+ }
+}
+
+DEAL_II_NAMESPACE_CLOSE
+
#include <base/memory_consumption.h>
#include <grid/tria_objects.h>
-
-#include <algorithm>
-#include <functional>
+#include <grid/tria.h>
+#include <grid/tria_iterator.h>
+#include <grid/tria_accessor.h>
{
namespace Triangulation
{
- template<>
- void
- TriaObjects<TriaObject<1> >::reserve_space (const unsigned int new_lines)
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_line_iterator
+ TriaObjects<TriaObject<1> >::next_free_single_line (const dealii::Triangulation<dim> &tria)
{
- const unsigned int new_size = new_lines +
- std::count_if (used.begin(),
- used.end(),
- std::bind2nd (std::equal_to<bool>(), true));
-
- // only allocate space if necessary
- if (new_size>cells.size())
- {
- cells.reserve (new_size);
- cells.insert (cells.end(),
- new_size-cells.size(),
- TriaObject<1> ());
-
- used.reserve (new_size);
- used.insert (used.end(),
- new_size-used.size(),
- false);
-
- user_flags.reserve (new_size);
- user_flags.insert (user_flags.end(),
- new_size-user_flags.size(),
- false);
+ // TODO: Think of a way to ensure that we are using the correct triangulation, i.e. the one containing *this.
- children.reserve (new_size);
- children.insert (children.end(),
- new_size-children.size(),
- -1);
-
- material_id.reserve (new_size);
- material_id.insert (material_id.end(),
- new_size-material_id.size(),
- 255);
-
- user_data.reserve (new_size);
- user_data.insert (user_data.end(),
- new_size-user_data.size(),
- UserData());
- };
- }
-
-
- template<>
- void
- TriaObjects<TriaObject<2> >::reserve_space (const unsigned int new_quads)
- {
- const unsigned int new_size = new_quads +
- std::count_if (used.begin(),
- used.end(),
- std::bind2nd (std::equal_to<bool>(), true));
-
- // see above...
- if (new_size>cells.size())
- {
- cells.reserve (new_size);
- cells.insert (cells.end(),
- new_size-cells.size(),
- TriaObject<2> ());
+ int pos=next_free_single,
+ last=used.size()-1;
+ if (!reverse_order_next_free_single)
+ {
+ // first sweep forward, only use
+ // really single slots, do not use
+ // pair slots
+ for (; pos<last; ++pos)
+ if (!used[pos])
+ if (used[++pos])
+ {
+ // this was a single slot
+ pos-=1;
+ break;
+ }
+ if (pos>=last)
+ {
+ reverse_order_next_free_single=true;
+ next_free_single=used.size()-1;
+ pos=used.size()-1;
+ }
+ else
+ next_free_single=pos+1;
+ }
- used.reserve (new_size);
- used.insert (used.end(),
- new_size-used.size(),
- false);
-
- user_flags.reserve (new_size);
- user_flags.insert (user_flags.end(),
- new_size-user_flags.size(),
- false);
-
- children.reserve (new_size);
- children.insert (children.end(),
- new_size-children.size(),
- -1);
-
- material_id.reserve (new_size);
- material_id.insert (material_id.end(),
- new_size-material_id.size(),
- 255);
-
- user_data.reserve (new_size);
- user_data.insert (user_data.end(),
- new_size-user_data.size(),
- UserData());
- };
+ if(reverse_order_next_free_single)
+ {
+ // second sweep, use all slots, even
+ // in pairs
+ for(;pos>=0;--pos)
+ if (!used[pos])
+ break;
+ if (pos>0)
+ next_free_single=pos-1;
+ else
+ // no valid single line anymore
+ return tria.end_line();
+ }
+
+ return typename dealii::Triangulation<dim>::raw_line_iterator(&tria,0,pos);
}
+
+
-
- void
- TriaObjectsHex::reserve_space (const unsigned int new_hexes)
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_line_iterator
+ TriaObjects<TriaObject<1> >::next_free_pair_line (const dealii::Triangulation<dim> &tria)
{
- const unsigned int new_size = new_hexes +
- std::count_if (used.begin(),
- used.end(),
- std::bind2nd (std::equal_to<bool>(), true));
-
- // see above...
- if (new_size>cells.size())
- {
- cells.reserve (new_size);
- cells.insert (cells.end(),
- new_size-cells.size(),
- TriaObject<3> ());
+ // TODO: Think of a way to ensure that we are using the correct triangulation, i.e. the one containing *this.
- used.reserve (new_size);
- used.insert (used.end(),
- new_size-used.size(),
- false);
-
- user_flags.reserve (new_size);
- user_flags.insert (user_flags.end(),
- new_size-user_flags.size(),
- false);
-
- children.reserve (new_size);
- children.insert (children.end(),
- new_size-children.size(),
- -1);
-
- material_id.reserve (new_size);
- material_id.insert (material_id.end(),
- new_size-material_id.size(),
- 255);
-
- user_data.reserve (new_size);
- user_data.insert (user_data.end(),
- new_size-user_data.size(),
- UserData());
-
- face_orientations.reserve (new_size * GeometryInfo<3>::faces_per_cell);
- face_orientations.insert (face_orientations.end(),
- new_size * GeometryInfo<3>::faces_per_cell
- - face_orientations.size(),
- true);
- face_flips.reserve (new_size * GeometryInfo<3>::faces_per_cell);
- face_flips.insert (face_flips.end(),
- new_size * GeometryInfo<3>::faces_per_cell
- - face_flips.size(),
- false);
- face_rotations.reserve (new_size * GeometryInfo<3>::faces_per_cell);
- face_rotations.insert (face_rotations.end(),
- new_size * GeometryInfo<3>::faces_per_cell
- - face_rotations.size(),
- false);
- };
+ int pos=next_free_pair,
+ last=used.size()-1;
+ for (; pos<last; ++pos)
+ if (!used[pos])
+ if (!used[++pos])
+ {
+ // this was a pair slot
+ pos-=1;
+ break;
+ }
+ if (pos>=last)
+ // no free slot
+ return tria.end_line();
+ else
+ next_free_pair=pos+2;
+
+ return typename dealii::Triangulation<dim>::raw_line_iterator(&tria,0,pos);
}
- void
- TriaObjectsQuad3D::reserve_space (const unsigned int new_quads)
- {
- const unsigned int new_size = new_quads +
- std::count_if (used.begin(),
- used.end(),
- std::bind2nd (std::equal_to<bool>(), true));
-
- // see above...
- if (new_size>cells.size())
- {
- TriaObjects<TriaObject<2> >::reserve_space(new_quads);
- line_orientations.reserve (new_size * GeometryInfo<2>::lines_per_cell);
- line_orientations.insert (line_orientations.end(),
- new_size * GeometryInfo<2>::lines_per_cell
- - line_orientations.size(),
- true);
- };
- }
-
- template<>
- void
- TriaObjects<TriaObject<1> >::monitor_memory (const unsigned int) const
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_quad_iterator
+ TriaObjects<TriaObject<1> >::next_free_single_quad (const dealii::Triangulation<dim> &tria)
{
- // check that we have not allocated
- // too much memory. note that bool
- // vectors allocate their memory in
- // chunks of whole integers, so
- // they may over-allocate by up to
- // as many elements as an integer
- // has bits
- Assert (cells.size() <=
- cells.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
- ExcMemoryWasted ("lines",
- cells.size(), cells.capacity()));
- Assert (children.size() <=
- children.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
- ExcMemoryWasted ("children",
- children.size(), children.capacity()));
- Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
- used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
- ExcMemoryWasted ("used",
- used.size(), used.capacity()));
- Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
- user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
- ExcMemoryWasted ("user_flags",
- user_flags.size(), user_flags.capacity()));
- Assert (cells.size() == used.size(),
- ExcMemoryInexact (cells.size(), used.size()));
- Assert (cells.size() == user_flags.size(),
- ExcMemoryInexact (cells.size(), user_flags.size()));
- Assert (cells.size() == children.size(),
- ExcMemoryInexact (cells.size(), children.size()));
- Assert (cells.size() == material_id.size(),
- ExcMemoryInexact (cells.size(), material_id.size()));
- Assert (cells.size() == user_data.size(),
- ExcMemoryInexact (cells.size(), user_data.size()));
+ Assert(false, ExcWrongIterator("quad","line"));
+ return tria.end_quad();
}
- template<>
- void
- TriaObjects<TriaObject<2> >::monitor_memory (const unsigned int) const
+
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_quad_iterator
+ TriaObjects<TriaObject<1> >::next_free_pair_quad (const dealii::Triangulation<dim> &tria)
{
- // check that we have not allocated
- // too much memory. note that bool
- // vectors allocate their memory in
- // chunks of whole integers, so
- // they may over-allocate by up to
- // as many elements as an integer
- // has bits
- Assert (cells.size() <=
- cells.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
- ExcMemoryWasted ("quads",
- cells.size(), cells.capacity()));
- Assert (children.size() <=
- children.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
- ExcMemoryWasted ("children",
- children.size(), children.capacity()));
- Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
- used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
- ExcMemoryWasted ("used",
- used.size(), used.capacity()));
- Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
- user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
- ExcMemoryWasted ("user_flags",
- user_flags.size(), user_flags.capacity()));
- Assert (cells.size() == used.size(),
- ExcMemoryInexact (cells.size(), used.size()));
- Assert (cells.size() == user_flags.size(),
- ExcMemoryInexact (cells.size(), user_flags.size()));
- Assert (cells.size() == children.size(),
- ExcMemoryInexact (cells.size(), children.size()));
- Assert (cells.size() == material_id.size(),
- ExcMemoryInexact (cells.size(), material_id.size()));
- Assert (cells.size() == user_data.size(),
- ExcMemoryInexact (cells.size(), user_data.size()));
+ Assert(false, ExcWrongIterator("quad","line"));
+ return tria.end_quad();
}
- void
- TriaObjectsHex::monitor_memory (const unsigned int) const
+
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_quad_iterator
+ TriaObjects<TriaObject<2> >::next_free_single_quad (const dealii::Triangulation<dim> &tria)
{
- // check that we have not allocated
- // too much memory. note that bool
- // vectors allocate their memory in
- // chunks of whole integers, so
- // they may over-allocate by up to
- // as many elements as an integer
- // has bits
- Assert (cells.size() <=
- cells.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
- ExcMemoryWasted ("hexes",
- cells.size(), cells.capacity()));
- Assert (children.size() <=
- children.capacity() + DEAL_II_MIN_VECTOR_CAPACITY,
- ExcMemoryWasted ("children",
- children.size(), children.capacity()));
- Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
- used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
- ExcMemoryWasted ("used",
- used.size(), used.capacity()));
- Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
- user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
- ExcMemoryWasted ("user_flags",
- user_flags.size(), user_flags.capacity()));
- Assert (cells.size() == used.size(),
- ExcMemoryInexact (cells.size(), used.size()));
- Assert (cells.size() == user_flags.size(),
- ExcMemoryInexact (cells.size(), user_flags.size()));
- Assert (cells.size() == children.size(),
- ExcMemoryInexact (cells.size(), children.size()));
- Assert (cells.size() == material_id.size(),
- ExcMemoryInexact (cells.size(), material_id.size()));
- Assert (cells.size() == user_data.size(),
- ExcMemoryInexact (cells.size(), user_data.size()));
- Assert (cells.size() * GeometryInfo<3>::faces_per_cell
- == face_orientations.size(),
- ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
- face_orientations.size()));
- Assert (cells.size() * GeometryInfo<3>::faces_per_cell
- == face_flips.size(),
- ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
- face_flips.size()));
- Assert (cells.size() * GeometryInfo<3>::faces_per_cell
- == face_rotations.size(),
- ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
- face_rotations.size()));
+ // TODO: Think of a way to ensure that we are using the correct triangulation, i.e. the one containing *this.
+
+ int pos=next_free_single,
+ last=used.size()-1;
+ if (!reverse_order_next_free_single)
+ {
+ // first sweep forward, only use
+ // really single slots, do not use
+ // pair slots
+ for (; pos<last; ++pos)
+ if (!used[pos])
+ if (used[++pos])
+ {
+ // this was a single slot
+ pos-=1;
+ break;
+ }
+ if (pos>=last)
+ {
+ reverse_order_next_free_single=true;
+ next_free_single=used.size()-1;
+ pos=used.size()-1;
+ }
+ else
+ next_free_single=pos+1;
+ }
+
+ if(reverse_order_next_free_single)
+ {
+ // second sweep, use all slots, even
+ // in pairs
+ for(;pos>=0;--pos)
+ if (!used[pos])
+ break;
+ if (pos>0)
+ next_free_single=pos-1;
+ else
+ // no valid single quad anymore
+ return tria.end_quad();
+ }
+
+ return typename dealii::Triangulation<dim>::raw_quad_iterator(&tria,0,pos);
}
+
+
-
- void
- TriaObjectsQuad3D::monitor_memory (const unsigned int) const
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_quad_iterator
+ TriaObjects<TriaObject<2> >::next_free_pair_quad (const dealii::Triangulation<dim> &tria)
{
- // check that we have not allocated
- // too much memory. note that bool
- // vectors allocate their memory in
- // chunks of whole integers, so
- // they may over-allocate by up to
- // as many elements as an integer
- // has bits
- Assert (cells.size() * GeometryInfo<2>::lines_per_cell
- == line_orientations.size(),
- ExcMemoryInexact (cells.size() * GeometryInfo<2>::lines_per_cell,
- line_orientations.size()));
- TriaObjects<TriaObject<2> >::monitor_memory (3);
+ // TODO: Think of a way to ensure that we are using the correct triangulation, i.e. the one containing *this.
+ int pos=next_free_pair,
+ last=used.size()-1;
+ for (; pos<last; ++pos)
+ if (!used[pos])
+ if (!used[++pos])
+ {
+ // this was a pair slot
+ pos-=1;
+ break;
+ }
+ if (pos>=last)
+ // no free slot
+ return tria.end_quad();
+ else
+ next_free_pair=pos+2;
+
+ return typename dealii::Triangulation<dim>::raw_quad_iterator(&tria,0,pos);
}
- template <typename G>
- void
- TriaObjects<G>::clear()
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_line_iterator
+ TriaObjects<TriaObject<2> >::next_free_single_line (const dealii::Triangulation<dim> &tria)
{
- cells.clear();
- children.clear();
- used.clear();
- user_flags.clear();
- material_id.clear();
- user_data.clear();
- user_data_type = data_unknown;
+ Assert(false, ExcWrongIterator("line","quad"));
+ return tria.end_line();
}
-
- void
- TriaObjectsHex::clear()
- {
- TriaObjects<TriaObject<3> >::clear();
- face_orientations.clear();
- face_flips.clear();
- face_rotations.clear();
- }
- void
- TriaObjectsQuad3D::clear()
- {
- TriaObjects<TriaObject<2> >::clear();
- line_orientations.clear();
- }
-
-
- template<typename G>
- unsigned int
- TriaObjects<G>::memory_consumption () const
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_line_iterator
+ TriaObjects<TriaObject<2> >::next_free_pair_line (const dealii::Triangulation<dim> &tria)
{
- return (MemoryConsumption::memory_consumption (cells) +
- MemoryConsumption::memory_consumption (children) +
- MemoryConsumption::memory_consumption (used) +
- MemoryConsumption::memory_consumption (user_flags) +
- MemoryConsumption::memory_consumption (material_id) +
- user_data.capacity() * sizeof(UserData) + sizeof(user_data));
+ Assert(false, ExcWrongIterator("line","quad"));
+ return tria.end_line();
}
-
- unsigned int
- TriaObjectsHex::memory_consumption () const
- {
- return (MemoryConsumption::memory_consumption (face_orientations) +
- MemoryConsumption::memory_consumption (face_flips) +
- MemoryConsumption::memory_consumption (face_rotations) +
- TriaObjects<TriaObject<3> >::memory_consumption() );
- }
- unsigned int
- TriaObjectsQuad3D::memory_consumption () const
+ template <>
+ template <int dim>
+ typename dealii::Triangulation<dim>::raw_hex_iterator
+ TriaObjects<TriaObject<3> >::next_free_hex (const dealii::Triangulation<dim> &tria,
+ const unsigned int level)
{
- return (MemoryConsumption::memory_consumption (line_orientations) +
- this->TriaObjects<TriaObject<2> >::memory_consumption() );
+ // TODO: Think of a way to ensure that we are using the correct triangulation, i.e. the one containing *this.
+
+ int pos=next_free_pair,
+ last=used.size()-1;
+ for (; pos<last; ++pos)
+ if (!used[pos])
+ {
+ // this should be a pair slot
+ Assert(!used[pos+1], ExcInternalError());
+ break;
+ }
+ if (pos>=last)
+ // no free slot
+ return tria.end_hex();
+ else
+ next_free_pair=pos+2;
+
+ return typename dealii::Triangulation<dim>::raw_hex_iterator(&tria,level,pos);
}
+
+
+
+
// explicit instantiations
- template class TriaObjects<TriaObject<1> >;
- template class TriaObjects<TriaObject<2> >;
+#if deal_II_dimension > 1
+ template dealii::Triangulation<deal_II_dimension>::raw_line_iterator
+ TriaObjects<TriaObject<1> >::next_free_single_line(const dealii::Triangulation<deal_II_dimension> &);
+ template dealii::Triangulation<deal_II_dimension>::raw_line_iterator
+ TriaObjects<TriaObject<1> >::next_free_pair_line(const dealii::Triangulation<deal_II_dimension> &);
+ template dealii::Triangulation<deal_II_dimension>::raw_quad_iterator
+ TriaObjects<TriaObject<1> >::next_free_single_quad(const dealii::Triangulation<deal_II_dimension> &);
+ template dealii::Triangulation<deal_II_dimension>::raw_quad_iterator
+ TriaObjects<TriaObject<1> >::next_free_pair_quad(const dealii::Triangulation<deal_II_dimension> &);
+
+ template dealii::Triangulation<deal_II_dimension>::raw_line_iterator
+ TriaObjects<TriaObject<2> >::next_free_single_line(const dealii::Triangulation<deal_II_dimension> &);
+ template dealii::Triangulation<deal_II_dimension>::raw_line_iterator
+ TriaObjects<TriaObject<2> >::next_free_pair_line(const dealii::Triangulation<deal_II_dimension> &);
+ template dealii::Triangulation<deal_II_dimension>::raw_quad_iterator
+ TriaObjects<TriaObject<2> >::next_free_single_quad(const dealii::Triangulation<deal_II_dimension> &);
+ template dealii::Triangulation<deal_II_dimension>::raw_quad_iterator
+ TriaObjects<TriaObject<2> >::next_free_pair_quad(const dealii::Triangulation<deal_II_dimension> &);
+#endif
+#if deal_II_dimension == 3
+ template dealii::Triangulation<deal_II_dimension>::raw_hex_iterator
+ TriaObjects<TriaObject<3> >::next_free_hex(const dealii::Triangulation<deal_II_dimension> &, const unsigned int);
+#endif
}
}
{
// ok, face has not been
// visited. so we need to
- // allocate space for
- // it. let's see how much
- // we need: we need one
- // set if a) there is no
- // neighbor behind this
- // face, or b) the
- // neighbor is not on the
- // same level or further
- // refined, or c) the
- // neighbor is on the
- // same level, but
- // happens to have the
- // same active_fe_index:
+ // allocate space for it. let's
+ // see how much we need: we need
+ // one set if a) there is no
+ // neighbor behind this face, or
+ // b) the neighbor is either
+ // coarser or finer than we are,
+ // or c) the neighbor is neither
+ // coarser nor finer, but has
+ // happens to have the same
+ // active_fe_index:
if (cell->at_boundary(face)
||
- (cell->neighbor(face)->level() < cell->level())
- ||
- cell->neighbor(face)->has_children()
+ cell->face(face)->has_children()
||
- ((cell->neighbor(face)->level() == cell->level())
- &&
- !cell->neighbor(face)->has_children()
- &&
- (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
+ cell->neighbor_is_coarser(face)
+ ||
+ (!cell->at_boundary(face)
+ &&
+ (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
// ok, one set of
// dofs. that makes
// one index, 1 times
// as before
if (cell->at_boundary(face)
||
- (cell->neighbor(face)->level() < cell->level())
+ cell->face(face)->has_children()
||
- cell->neighbor(face)->has_children()
- ||
- ((cell->neighbor(face)->level() == cell->level())
- &&
- !cell->neighbor(face)->has_children()
- &&
- (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
+ cell->neighbor_is_coarser(face)
+ ||
+ (!cell->at_boundary(face)
+ &&
+ (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
{
faces
->lines.dof_offsets[cell->face(face)->index()]
// same active_fe_index:
if (cell->at_boundary(face)
||
- (cell->neighbor(face)->level() < cell->level())
- ||
- cell->neighbor(face)->has_children()
+ cell->face(face)->has_children()
||
- ((cell->neighbor(face)->level() == cell->level())
- &&
- !cell->neighbor(face)->has_children()
- &&
- (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
+ cell->neighbor_is_coarser(face)
+ ||
+ (!cell->at_boundary(face)
+ &&
+ (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
// ok, one set of
// dofs. that makes
// one index, 1 times
// as before
if (cell->at_boundary(face)
||
- (cell->neighbor(face)->level() < cell->level())
+ cell->face(face)->has_children()
||
- cell->neighbor(face)->has_children()
- ||
- ((cell->neighbor(face)->level() == cell->level())
- &&
- !cell->neighbor(face)->has_children()
- &&
- (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
+ cell->neighbor_is_coarser(face)
+ ||
+ (!cell->at_boundary(face)
+ &&
+ (cell->active_fe_index() == cell->neighbor(face)->active_fe_index())))
{
faces
->quads.dof_offsets[cell->face(face)->index()]
}
- template <int dim>
- void DoFHandler<dim>::pre_refinement_notification (const Triangulation<dim> &)
- {
- create_active_fe_table ();
- }
-
-#if deal_II_dimension == 1
- template <>
- void DoFHandler<1>::pre_refinement_notification (const Triangulation<1> &tria)
+ template <int dim>
+ void DoFHandler<dim>::pre_refinement_notification (const Triangulation<dim> &tria)
{
create_active_fe_table ();
Assert (has_children.size () == 0, ExcInternalError ());
for (unsigned int i=0; i<levels.size(); ++i)
{
- const unsigned int lines_on_level = tria.n_raw_lines(i);
+ const unsigned int cells_on_level = tria.n_raw_cells(i);
std::vector<bool> *has_children_level =
- new std::vector<bool> (lines_on_level);
+ new std::vector<bool> (cells_on_level);
// Check for each cell, if it has children.
- std::transform (tria.levels[i]->cells.children.begin (),
- tria.levels[i]->cells.children.end (),
+ std::transform (tria.levels[i]->cells.refinement_cases.begin (),
+ tria.levels[i]->cells.refinement_cases.end (),
has_children_level->begin (),
- std::bind2nd (std::not_equal_to<int>(), -1));
+ std::bind2nd (std::not_equal_to<unsigned char>(),
+ static_cast<unsigned char>(RefinementCase<dim>::no_refinement)));
has_children.push_back (has_children_level);
}
}
-#endif
-
-
-#if deal_II_dimension == 2
- template <>
- void DoFHandler<2>::pre_refinement_notification (const Triangulation<2> &tria)
- {
- create_active_fe_table ();
-
- // Remember if the cells have already
- // children. That will make the transfer
- // of the active_fe_index to the finer
- // levels easier.
- Assert (has_children.size () == 0, ExcInternalError ());
- for (unsigned int i=0; i<levels.size(); ++i)
- {
- const unsigned int quads_on_level = tria.n_raw_quads (i);
- std::vector<bool> *has_children_level =
- new std::vector<bool> (quads_on_level);
- // Check for each cell, if it has children.
- std::transform (tria.levels[i]->cells.children.begin (),
- tria.levels[i]->cells.children.end (),
- has_children_level->begin (),
- std::bind2nd (std::not_equal_to<int>(), -1));
- has_children.push_back (has_children_level);
- }
- }
-#endif
-#if deal_II_dimension == 3
+#if deal_II_dimension == 1
template <>
- void DoFHandler<3>::pre_refinement_notification (const Triangulation<3> &tria)
+ void DoFHandler<1>::pre_refinement_notification (const Triangulation<1> &tria)
{
create_active_fe_table ();
Assert (has_children.size () == 0, ExcInternalError ());
for (unsigned int i=0; i<levels.size(); ++i)
{
- const unsigned int hexes_on_level = tria.n_raw_hexs(i);
+ const unsigned int cells_on_level = tria.n_raw_cells (i);
std::vector<bool> *has_children_level =
- new std::vector<bool> (hexes_on_level);
-
- // Check for each cell, if it
- // has children.
+ new std::vector<bool> (cells_on_level);
+
+ // Check for each cell, if it has
+ // children. here we cannot use
+ // refinement_cases, since it is unused in
+ // 1d (as there is only one choice
+ // anyway). use the 'children' vector
+ // instead
std::transform (tria.levels[i]->cells.children.begin (),
tria.levels[i]->cells.children.end (),
has_children_level->begin (),
}
#endif
+
template <int dim>
void DoFHandler<dim>::post_refinement_notification (const Triangulation<dim> &tria)
{
// $Id$
// Version: $Name$
//
-// Copyright (C) 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
{
cell->get_mg_dof_indices (dof_indices_parent);
+ Assert(cell->n_children()==GeometryInfo<dim>::max_children_per_cell,
+ ExcNotImplemented());
for (unsigned int child=0; child<cell->n_children(); ++child)
{
// set an alias to the
// prolongation matrix for
// this child
const FullMatrix<double> &prolongation
- = mg_dof.get_fe().get_prolongation_matrix (child);
+ = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
cell->child(child)->get_mg_dof_indices (dof_indices_child);
{
cell->get_mg_dof_indices (dof_indices_parent);
+ Assert(cell->n_children()==GeometryInfo<dim>::max_children_per_cell,
+ ExcNotImplemented());
for (unsigned int child=0; child<cell->n_children(); ++child)
{
// set an alias to the
// prolongation matrix for
// this child
const FullMatrix<double> &prolongation
- = mg_dof.get_fe().get_prolongation_matrix (child);
+ = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
cell->child(child)->get_mg_dof_indices (dof_indices_child);
// $Id$
// Version: $Name$
//
-// Copyright (C) 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
// prolongation matrix for
// this child
const FullMatrix<double> &prolongation
- = mg_dof.get_fe().get_prolongation_matrix (child);
+ = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
cell->child(child)->get_mg_dof_indices (dof_indices_child);
// prolongation matrix for
// this child
const FullMatrix<double> &prolongation
- = mg_dof.get_fe().get_prolongation_matrix (child);
+ = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
cell->child(child)->get_mg_dof_indices (dof_indices_child);
// $Id$
// Version: $Name$
//
-// Copyright (C) 2003, 2004, 2005, 2006, 2007 by the deal.II authors
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
{
cell->get_mg_dof_indices (dof_indices_parent);
+ Assert(cell->n_children()==GeometryInfo<dim>::max_children_per_cell,
+ ExcNotImplemented());
for (unsigned int child=0; child<cell->n_children(); ++child)
{
// set an alias to the
// prolongation matrix for
// this child
const FullMatrix<double> &prolongation
- = mg_dof.get_fe().get_prolongation_matrix (child);
+ = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
Assert (prolongation.n() != 0, ExcNoProlongation());
{
cell->get_mg_dof_indices (dof_indices_parent);
+ Assert(cell->n_children()==GeometryInfo<dim>::max_children_per_cell,
+ ExcNotImplemented());
for (unsigned int child=0; child<cell->n_children(); ++child)
{
// set an alias to the
// prolongation matrix for
// this child
const FullMatrix<double> &prolongation
- = mg_dof.get_fe().get_prolongation_matrix (child);
+ = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
cell->child(child)->get_mg_dof_indices (dof_indices_child);
#include <lac/petsc_vector.h>
#include <lac/petsc_block_vector.h>
#include <grid/tria_iterator.h>
+#include <grid/grid_tools.h>
#include <dofs/dof_accessor.h>
#include <dofs/dof_handler.h>
#include <fe/fe.h>
// active neighbors
std::vector<typename DH<dim>::active_cell_iterator> active_neighbors;
active_neighbors.reserve (GeometryInfo<dim>::faces_per_cell *
- GeometryInfo<dim>::subfaces_per_face);
+ GeometryInfo<dim>::max_children_per_face);
// vector
// g=sum_i y_i (f(x+y_i)-f(x))/|y_i|
// first collect all neighbor
// cells in a vector, and then
// collect the data from them
- active_neighbors.clear ();
- for (unsigned int n=0; n<GeometryInfo<dim>::faces_per_cell; ++n)
- if (! cell->at_boundary(n))
- {
- typename DH<dim>::cell_iterator
- neighbor = cell->neighbor(n);
- if (neighbor->active())
- active_neighbors.push_back (neighbor);
- else
- {
- // check children
- // of
- // neighbor. note
- // that in 1d
- // children of
- // the neighbor
- // may be further
- // refined, while
- // they can't in
- // more than one
- // dimension. however,
- // in 1d the case
- // is simpler
- // since we know
- // what children
- // bound to the
- // present cell
- if (dim == 1)
- {
- typename DH<dim>::cell_iterator
- neighbor_child = neighbor;
- while (neighbor_child->has_children())
- neighbor_child = neighbor_child->child (n==0 ? 1 : 0);
-
- Assert (neighbor_child->neighbor(n==0 ? 1 : 0)==cell,
- ExcInternalError());
-
- active_neighbors.push_back (neighbor_child);
- }
- else
- // this neighbor has
- // children. find out
- // which border to the
- // present cell
- for (unsigned int c=0; c<neighbor->n_children(); ++c)
- for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
- if (neighbor->child(c)->neighbor(f) == cell)
- active_neighbors.push_back (neighbor->child(c));
- };
- };
-
+ GridTools::template get_active_neighbors<DH<dim> >(cell, active_neighbors);
+
// now loop over all active
// neighbors and collect the
// data we need
derivative_norm(const Tensor<3,deal_II_dimension> &derivative);
-
// static variables
//
// on AIX, the linker is unhappy about some missing symbols. they
template
const UpdateFlags
DerivativeApproximation::SecondDerivative<deal_II_dimension>::update_flags;
-
template
const UpdateFlags
DerivativeApproximation::ThirdDerivative<deal_II_dimension>::update_flags;
// then do the work below
if ((face->has_children() == false) &&
!cell->at_boundary(face_no) &&
- (cell->neighbor(face_no)->level() == cell->level()) &&
- (cell->neighbor(face_no)->index() < cell->index()))
+ (!cell->neighbor_is_coarser(face_no) &&
+ (cell->neighbor(face_no)->index() < cell->index() ||
+ (cell->neighbor(face_no)->index() == cell->index() &&
+ cell->neighbor(face_no)->level() < cell->level()))))
continue;
// if we already visited
// integrate over the subfaces when
// we visit the coarse cells.
if (cell->at_boundary(face_no) == false)
- if (cell->neighbor(face_no)->level() < cell->level())
+ if (cell->neighbor_is_coarser(face_no))
continue;
// if this face is part of the
}
Assert((n_cells_to_coarsen+n_cells_to_stay_or_refine)==n_active_cells,
ExcInternalError());
- Assert(n_cells_to_coarsen%GeometryInfo<dim>::children_per_cell==0,
- ExcInternalError());
- Assert(n_cells_to_coarsen%GeometryInfo<dim>::children_per_cell==0,
- ExcTriaPrepCoarseningNotCalledBefore());
+
+ unsigned int n_coarsen_fathers=0;
+ typename DH::cell_iterator
+ cell=dof_handler->begin();
+ for (; cell!=endc; ++cell)
+ if (!cell->active() && cell->child(0)->coarsen_flag_set())
+ ++n_coarsen_fathers;
- const unsigned int n_coarsen_fathers = n_cells_to_coarsen /
- GeometryInfo<dim>::children_per_cell;
+ if (n_cells_to_coarsen)
+ Assert(n_cells_to_coarsen>=2*n_coarsen_fathers, ExcInternalError());
// allocate the needed memory. initialize
// the following arrays in an efficient
// the 'to_stay_or_refine' cells 'n_sr' and
// the 'coarsen_fathers' cells 'n_cf',
unsigned int n_sr=0, n_cf=0;
- typename DH::cell_iterator cell = dof_handler->begin();
+ cell = dof_handler->begin();
for (; cell!=endc; ++cell)
{
if (cell->active() && !cell->coarsen_flag_set())
// $Id$
// Version: $Name$
//
-// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006 by the deal.II authors
+// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
// new. but since we loop over flagged
// cells, we have to subtract 3/4 of
// a cell for each flagged cell
+ Assert(!tria->get_anisotropic_refinement_flag(), ExcNotImplemented());
+ Assert(!previous_tria->get_anisotropic_refinement_flag(), ExcNotImplemented());
double previous_cells = previous_tria->n_active_cells();
typename Triangulation<dim>::active_cell_iterator cell, endc;
cell = previous_tria->begin_active();
endc = previous_tria->end();
for (; cell!=endc; ++cell)
if (cell->refine_flag_set())
- previous_cells += (GeometryInfo<dim>::children_per_cell-1);
+ previous_cells += (GeometryInfo<dim>::max_children_per_cell-1);
else
if (cell->coarsen_flag_set())
- previous_cells -= (GeometryInfo<dim>::children_per_cell-1) /
- GeometryInfo<dim>::children_per_cell;
+ previous_cells -= (GeometryInfo<dim>::max_children_per_cell-1) /
+ GeometryInfo<dim>::max_children_per_cell;
// @p{previous_cells} now gives the
// number of cells which would result
endc = tria->end();
for (; cell!=endc; ++cell)
if (cell->refine_flag_set())
- estimated_cells += (GeometryInfo<dim>::children_per_cell-1);
+ estimated_cells += (GeometryInfo<dim>::max_children_per_cell-1);
else
if (cell->coarsen_flag_set())
- estimated_cells -= (GeometryInfo<dim>::children_per_cell-1) /
- GeometryInfo<dim>::children_per_cell;
+ estimated_cells -= (GeometryInfo<dim>::max_children_per_cell-1) /
+ GeometryInfo<dim>::max_children_per_cell;
// calculate the allowed delta in
// cell numbers; be more lenient
// cells tagged for refinement
for (unsigned int i=0; i<delta_cells;
- i += GeometryInfo<dim>::children_per_cell-1)
+ i += GeometryInfo<dim>::max_children_per_cell-1)
if (p_refinement_threshold != sorted_criteria.end())
++p_refinement_threshold;
else
// of sorted_criteria, which is
// sorted in ascending order
for (unsigned int i=0; i<delta_cells;
- i += (GeometryInfo<dim>::children_per_cell-1))
+ i += (GeometryInfo<dim>::max_children_per_cell-1))
if (p_refinement_threshold != p_coarsening_threshold)
--refinement_threshold;
else
../../deal.II/include/multigrid \
../../deal.II/include/numerics \
tutorial/doxygen \
+ ../news/changes.h \
../news/6.0.0-vs-6.1.0.h \
- ../news/changes.h
+ ../news/anisotropic.html
HTML_OUTPUT = deal.II
LATEX_OUTPUT = LaTeX/deal.II
../../examples/step-27/doc \
../../examples/step-28/doc \
../../examples/step-29/doc \
+ ../../examples/step-30/doc
../../examples/step-31/doc \
../../examples/step-33/doc
<td> Solving a complex-valued Helmholtz equation. Sparse direct
solvers. Dealing with parameter files. </td></tr>
+ <tr><td><a href="../../doxygen/deal.II/step_30.html">Step-30</a></td>
+ <td> Anisotropic refinement for DG finite element methods.
+ </td></tr>
+
<tr valign="top">
<td><a href="../../doxygen/deal.II/step_33.html">Step-33</a></td>
<td> A nonlinear hyperbolic conservation law: The Euler equations of
</tr>
<tr valign="top">
+ <td></td>
+ <td><a href="../../doxygen/deal.II/step_30.html">Step-30</a></td>
+ <td> Anisotropic refinement for DG finite element methods.
+ </td>
+ </tr>
+
+ <tr>
<td></td>
<td><a href="../../doxygen/deal.II/step_16.html">Step-16</a></td>
<td> Multilevel preconditioners
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN"
- "http://www.w3.org/TR/REC-html40/frameset.dtd">
-<html>
- <head>
- <link href="../screen.css" rel="StyleSheet">
- <title>The deal.II news page</title>
- <meta name="author" content="the deal.II authors <authors@dealii.org>">
- <meta name="keywords" content="deal.II"></head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-<body>
-
-
-<h2>Changes between the main branch and the anisotropic branch</h2>
+/**
+ * @page anisotropic_changes Changes between the trunk and branch_anisotropic
<p>
-This is the list of changes between the main subversion branch and the
-anisotropic branch of <acronym>deal.II</acronym> library. It is
-subdivided into changes made to the three sub-libraries <a
-href="#base">base</a>, <a href="#lac">lac</a>, and <a
-href="#deal.II">deal.II</a>, as well as changes to the <a
-href="#general">general infrastructure, documentation, etc</a>.
+This is the list of changes between the subversion trunk and the
+anisotropic branch of the deal.II library. It is subdivided into
+changes made to the three sub-libraries <a href="#base">base</a>, <a
+href="#lac">lac</a>, and <a href="#deal.II">deal.II</a>, as well as
+changes to the <a href="#general">general infrastructure,
+documentation, etc</a>.
</p>
<p>
<ol>
<li> <p>
- Changed: The <code class="class">FiniteElement<dim></code>::<code
- class="member">get_prolongation_matrix</code> and <code
- class="class">FiniteElement<dim></code>::<code
- class="member">get_restriction_matrix</code> functions now have an
- additional argument of type <code>RefineCase::Type</code> to enable a
- meaningful use of these matrices in case of anisotropic refinement. These
- matrices are used for solution transfer and multigrid operations, but
- there should be no need to use them in user codes directly. Note, that
- the matrices are not fully implemented for all finite elements up to now.
- <br> (Tobias Leicht 2006/07/04)
+ Changed: The FiniteElement::get_prolongation_matrix and
+ FiniteElement::get_restriction_matrix functions now have an
+ additional argument of type RefinementCase to enable a
+ meaningful use of these matrices in case of anisotropic
+ refinement. These matrices are used for solution transfer and
+ multigrid operations, but there should be no need to use them
+ in user codes directly. Note, that the matrices are not fully
+ implemented for all finite elements up to now.
+ <br>
+ (Tobias Leicht 2006/07/04)
</p>
<li> <p>
- Changed: <code class="class">GeometryInfo</code>::<code
- class="member">children_per_cell</code> has been replaced by
- <code class="class">GeometryInfo</code>::<code
- class="member">max_children_per_cell</code>, which represents
- the maximum number of children a cell might have, i.e. the
- number of children in the case of isotropic refinement. But
- note, that this number will rarely be needed in user codes. In
- general, the number of children of a cell varies from cell to
- cell and can be obtained by <code>cell->n_children()</code>,
- which gives the number of children of a specific
- <code>cell</code> which is refined iso- or anisotropically.
+ Changed: <code>GeometryInfo::children_per_cell</code> has been
+ replaced by GeometryInfo::max_children_per_cell, which
+ represents the maximum number of children a cell might have,
+ i.e. the number of children in the case of isotropic
+ refinement. But note, that this number will rarely be needed in
+ user codes. In general, the number of children of a cell varies
+ from cell to cell and can be obtained by
+ <code>cell->n_children()</code>, which gives the number of
+ children of a specific <code>cell</code> which is refined iso-
+ or anisotropically.
<br>
(RH 2005/02/26)
</p>
<li> <p>
Changed: The analogous change applies to the number of children
- of a face. <code class="class">GeometryInfo</code>::<code
- class="member">subfaces_per_face</code> has been replaced by
- <code class="class">GeometryInfo</code>::<code
- class="member">max_children_per_face</code>, which represents
- the maximum number of children a face might have, i.e. the
- number of children in the case of an isotropic refined face.
- But note, that this number will rarely be needed in user
+ of a face. <code>GeometryInfo::subfaces_per_face</code> has
+ been replaced by GeometryInfo::max_children_per_face, which
+ represents the maximum number of children a face might have,
+ i.e. the number of children in the case of an isotropic refined
+ face. But note, that this number will rarely be needed in user
codes. In general, the number of children of a face varies from
face to face and can be obtained by
<code>face->n_children()</code>, which gives the number of
</p>
<li> <p>
- Changed: The <code class="class">GeometryInfo</code>::<code
- class="member">child_cell_on_face</code> is generalized to
- anisotropic refinement and has now an additional
- <code>RefineCase::Type</code> argument. This function will
- rarely be used in user codes, as e.g. the neighbor's child at a
- specific face and subface should be accessed through
+ Changed: The GeometryInfo::child_cell_on_face function is
+ generalized to anisotropic refinement and has now an additional
+ RefinementCase argument. This function will rarely be used in
+ user codes, as e.g. the neighbor's child at a specific face and
+ subface should be accessed through
<code>cell->neighbor_child_on_subface</code> rather than
- through the <code class="class">GeometryInfo</code>::<code
- class="member">child_cell_on_face</code> function.
+ through the GeometryInfo::child_cell_on_face function.
<br>
(RH 2005/02/27)
</p>
<ol>
<li> <p>
- New: There is now a new <code
- class="class">GeometryInfo<dim></code>::<code
- class="member">min_cell_refine_case</code> function which returns the
- <code>RefineCase::Type</code> representing the smallest refinement case
- of a cell for a given refinement of one of its faces. In 2D for example a
- cell has to be refined at least with <code>RefineCase::cut_y</code> if
- the left line (line 0) shall be refined. Another refinement possibility
- for the cell would be <code>RefineCase::cut_xy</code>, but that is not
- the minimal case.
+ New: There are now a new
+ GeometryInfo::min_cell_refinement_case_for_face_refinement
+ (resp. GeometryInfo::min_cell_refinement_case_for_line_refinement)
+ function which returns the RefinementCase representing the
+ smallest refinement case of a cell for a given refinement of
+ one of its faces (resp. lines). In 2D for example a cell has to
+ be refined at least with RefinementCase::cut_y if the left line
+ (line 0) shall be refined. Another refinement possibility for
+ the cell would be <code>RefinementCase::cut_xy</code>, but that
+ is not the minimal case.
<br>
(Tobias Leicht 2006/06/28)
</p>
<li> <p>
- New: There is now a new <code
- class="class">GeometryInfo<dim></code>::<code
- class="member">line_refine_case</code> function which returns the
- <code>RefineCase::Type</code> representing the refinement case of a line
- for a given refinement case of the corresponding cell.
+ New: There is now a new GeometryInfo::line_refinement_case
+ function which returns the RefinementCase representing the
+ refinement case of a line for a given refinement case of the
+ corresponding cell.
<br>
(Tobias Leicht 2006/06/28)
</p>
<li> <p>
- New: The new <code class="class">GeometryInfo</code>::<code
- class="member">n_children(ref_case)</code> function returns the
- number of children a cell/face has when refined with the
- <code>RefineCase::Type</code> <code>ref_case</code>.
+ New: The new
+ <tt>GeometryInfo<dim>::n_children(refinement_case)</tt>
+ function returns the number of children a cell/face has when
+ refined with the RefinementCase <tt>refinement_case</tt>.
<br>
(RH 2005/11/07)
</p>
<li> <p>
- New: Given a <code>RefineCase::Type</code> of a cell the new
- <code class="class">GeometryInfo</code>::<code
- class="member">face_refine_case</code> function returns the
- <code>RefineCase::Type</code> of a face. <br> (RH 2005/11/07)
+ New: Given a RefinementCase of a cell the new
+ GeometryInfo::face_refinement_case function returns the
+ RefinementCase of a face.
+ <br>
+ (RH 2005/11/07)
</p>
<li> <p>
- New: There is now a new <code
- class="class">GeometryInfo<dim></code>::<code
- class="member">isotropic_refinement</code> variable of type
- <code>RefineCase::Type</code> representing the isotropic
+ New: There is now a new RefinementCase
+ GeometryInfo::isotropic_refinement representing the isotropic
refinement case in <code>dim</code> dimensions,
- i.e. <code>GeometryInfo<1>::isotropic_refinement=RefineCase::cut_x</code>,
- <code>GeometryInfo<2>::isotropic_refinement=RefineCase::cut_xy</code>
+ i.e. <tt>GeometryInfo<1>::isotropic_refinement=RefinementCase::cut_x</tt>,
+ <tt>GeometryInfo<2>::isotropic_refinement=RefinementCase::cut_xy</tt>
and
- <code>GeometryInfo<3>::isotropic_refinement=RefineCase::cut_xyz</code>.
+ <tt>GeometryInfo<3>::isotropic_refinement=RefinementCase::cut_xyz</tt>.
<br>
(RH 2005/03/03)
</p>
<a name="lac"></a>
<h3>lac</h3>
-<ol>
-</ol>
-
<a name="deal.II"></a>
<h3>deal.II</h3>
<ol>
- <li> <p> New: There is now a new <code
- class="class">Triangulation<dim></code>::<code
- class="member">prevent_distorted_boundary_cell</code> function which is
- only useful in case of anisotropic refinement. At the boundary of the
- domain, the new point on the face may be far inside the current cell, if
- the boundary has a strong curvature. If we allow anistropic refinement
- here, the resulting cell may be strongly distorted, especially if it is
- refined again later on. To prevent this problem, this function flags such
- cells for isotropic refinement. It is called automatically from <code
- class="member">prepare_coarsening_and_refinement</code>. Therefore this
- should have no effect on user codes.
- <br>
- (Tobias Leicht 2006/08/02)
- </p>
-
<li> <p>
- New: There is now a new <code
- class="class">Triangulation<dim></code>::<code
- class="member">tria_post_processing</code> function which is only useful
- in case of anisotropic refinement. It is possible, that a cell is refined
- only in one direciton and later all the children are refined in another
- one. Summing up, this would be the same as isotropic refinement, but with
- a higher number of cells, faces and levels involved. Therefore, after the
- refinement process, this function is called automatically and catches
- cells, for which the described conditions apply. They are coarsened and
- refined isotropically again. However, this is really something
- internal to the library and there should never be the need to use this
- function in user_codes. Calling <code
- class="class">Triangulation<dim></code>::<code
- class="member">execute_coarsening_and_refinement</code> will be all you
- need.
- <br>
- (Tobias Leicht 2006/06/29)
+ New: There is now a new
+ Triangulation::prevent_distorted_boundary_cells function which
+ only useful in case of anisotropic refinement. At the boundary
+ of the domain, the new point on the face may be far inside the
+ current cell, if the boundary has a strong curvature. If we
+ allow anistropic refinement here, the resulting cell may be
+ strongly distorted, especially if it is refined again later
+ on. To prevent this problem, this function flags such cells for
+ isotropic refinement. It is called automatically from
+ Triangulation::prepare_coarsening_and_refinement. Therefore
+ this should have no effect on user codes.
+ <br>
+ (Tobias Leicht 2006/08/02)
</p>
<li> <p>
- Extended: The<code
- class="class">Triangulation<dim></code>::<code
- class="member">delete_children</code> now takes an additional argument
- <code>keep_outer_faces</code> of type <code>bool</code> which has a
- default value of <code>false</code>. If set to <code>true</code>, the
- children of the cells faces are never deleted, even if the neighbor does
- not need them. Normally, this would leed to wasted memory, therefore
- this should only be done, if they are needed afterwards, e.g. if the cell
- is refined again. However, this is really something
- internal to the library and there should never be the need to use this
- function in user_codes. Calling <code
- class="class">Triangulation<dim></code>::<code
- class="member">execute_coarsening_and_refinement</code> will be all you
- need.
- <br>
- (Tobias Leicht 2006/06/29)
+ New: There is now a new Triangulation::create_children function
+ which actually sets up the children of a cell and updates the
+ neighbor information. This work has been done in
+ Triangulation::execute_refinement so far. Memory allocation has
+ to be done prior to the function call. However, this is really
+ something internal to the library and there should never be the
+ need to use this function in user_codes. Calling
+ Triangulation::execute_coarsening_and_refinement will be all
+ you need.
+ <br>
+ (Tobias Leicht 2006/06/29)
</p>
<li> <p>
- New: There is now a new <code
- class="class">Triangulation<dim></code>::<code
- class="member">create_children</code> function which actually sets up the
- children of a cell and updates the neighbor information. This work has
- been done in <code class="class">Triangulation<dim></code>::<code
- class="member">execute_refinement</code> so far. Memory allocation has to
- be done prior to the function call. However, this is really something
- internal to the library and there should never be the need to use this
- function in user_codes. Calling <code
- class="class">Triangulation<dim></code>::<code
- class="member">execute_coarsening_and_refinement</code> will be all you
- need.
- <br>
- (Tobias Leicht 2006/06/29)
- </p>
- <li> <p>
- New: A part of the functionality of <code
- class="class">Triangulation<dim></code>::<code
- class="member">execute_coarsening</code> has been implemented in a new way
- and shifted to the new function <code
- class="class">Triangulation<dim></code>::<code
- class="member">coarsening_allowed</code>. This function decides,
+ New: A part of the functionality of Triangulation::execute_coarsening has been implemented in a new way
+ and shifted to the new function Triangulation::coarsening_allowed. This function decides,
depending on the refinement situation of all a cells neighbors, if the
cell may be coarsened, in which case the bool value <code>true</code> is
returned. This is a functionality which is partly dimension dependend.
- <br>
- However, there should never be any reason to use this function in user codes.
+ <br>
+ However, there should never be any reason to use this function in user codes.
<br>
(Tobias Leicht 2006/06/28)
</p>
<li> <p>
- New: There is now a new accessor function <code
- class="member">coarser_neighbor</code>, which returns a bool value
- <code>true</code>, if the requested neighbor is a coarser one and
- <code>false</code> if the neighbor is as refined as the current cell. This new
- functionality is needed in the internals of the library to decide, if
- <code>neighbor_of_neighbor</code> or
- <code>neighbor_of_coarser_neighbor</code> has to be called. This decision
- is trivial in case of isotropic refinement, where the level of the cell
- and its neighbor is all the information needed. In case of aniostropic
- refinement, this new function can be used.
+ New: There is now a new CellAccessor::neighbor_is_coarser function,
+ which returns a bool value <code>true</code>, if the requested
+ neighbor is a coarser one and <code>false</code> if the
+ neighbor is as refined as the current cell. This new
+ functionality is needed in the internals of the library to
+ decide, if <code>neighbor_of_neighbor</code> or
+ <code>neighbor_of_coarser_neighbor</code> has to be
+ called. This decision is trivial in case of isotropic
+ refinement, where the level of the cell and its neighbor is all
+ the information needed. In case of aniostropic refinement, this
+ new function can be used.
<br>
(Tobias Leicht 2006/06/28)
</p>
<li> <p>
- New: There is now a new <code
- class="class">Triangulation<dim></code>::<code
- class="member">MeshSmoothing</code>::<code>allow_anisotropic_smoothing</code>
- smoothing flag for triangulations. An important part of the smoothing
- process for refinement and coarsen flags is to ensure, that no double
- refinement takes places at any face. If a cell is refined twice, its
- neighbor has to be refined at least once. However, technically it is not
- always necessary to refine the neighbor isotropically, it may be
- sufficient to choose only one direction for the refinement. While this
- allows to reduce the number of newly created cells to a minimum, it is incompatible
- with older versions of the library, as anisotropic refinement takes
- place, even if all the explicitly set refinement flags ask for
- isotropic refinement.
- <br>
- Therefore this functionality is off by default. However, in order to use
+ New: There is now a new
+ <code>Triangulation::MeshSmoothing::allow_anisotropic_smoothing</code>
+ smoothing flag for triangulations. An important part of the
+ smoothing process for refinement and coarsen flags is to
+ ensure, that no double refinement takes places at any face. If
+ a cell is refined twice, its neighbor has to be refined at
+ least once. However, technically it is not always necessary to
+ refine the neighbor isotropically, it may be sufficient to
+ choose only one direction for the refinement. While this allows
+ to reduce the number of newly created cells to a minimum, it is
+ incompatible with older versions of the library, as anisotropic
+ refinement takes place, even if all the explicitly set
+ refinement flags ask for isotropic refinement.
+ <br>
+ Therefore this functionality is off by default. However, in order to use
the new feature of anisotropic refinement to full extend, this flag should
be set explicitly.
- <br>
- Note, that for reasons of backwards compatibility this flag is NOT
- included in the general
- <code>MeshSmoothing</code>::<code>maximum_smoothing</code> flag.
+ <br>
+ Note, that for reasons of backwards compatibility this flag is
+ NOT included in the general <code>MeshSmoothing::maximum_smoothing</code>
+ flag.
<br>
(Tobias Leicht 2006/06/28)
</p>
<li> <p>
- New: There is now a new <code
- class="class">TriaObjectAccessor</code>::<code
- class="member">clear_refine_case</code> function.
+ New: There is now a new
+ TriaObjectAccessor::clear_refinement_case function.
<br>
(RH 2005/12/19)
</p>
<li> <p>
- Extended: The <code
- class="class">CellAccessor<dim></code>::<code
- class="member">neighbor_of_neighbor</code> function is now
- extended to anisotropic refinement.
+ Extended: The CellAccessor::neighbor_of_neighbor function is
+ now extended to anisotropic refinement.
<br>
(RH 2005/12/15)
</p>
<li> <p>
Extended (internal): Lines on <code>level>0</code> have always
- been stored pairwise. In order to allow the creation of
- single interior lines we now also allow storage of single lines. The
- <code class="class">TriangulationLevel<1></code>::<code
- class="member">reserve_space</code> function now takes an
- additional <code>n_consecutive_lines</code> parameter which
- allows to create new single as well as pairs for lines
- (<code>n_consecutive_lines=1</code> or
+ been stored pairwise. In order to allow the creation of single
+ interior lines we now also allow storage of single lines. The
+ <tt>TriangulationLevel<1>::reserve_space</tt> function
+ now takes an additional <code>n_consecutive_lines</code>
+ parameter which allows to create new single as well as pairs
+ for lines <code>n_consecutive_lines=1</code> or
<code>n_consecutive_lines=2</code>, respectively.
<br>
(RH 2005/12/15)
<li> <p>
Changed: When allowing anisotropic refinement it cannot be
guaranteed that all children of a cell are stored in
- consecutive components of the <code>quads.quads</code> or the
- <code>hexes.hexes</code> vector, respectively. It is only known
- that children are stored at least in pairs. Therefore, it is
- not sufficient any more to store the index of the first child
- of a cell, only. Now the indices of every second child, i.e. of
- the even numbered children, must be stored. For this, the
- <code>cell-></code><code class="member">set_children</code>
- function now has a new argument representing the number of the
- child for which the index shall be set. This function can only
- be called for even numbered children. The same applies to the
- <code>face-></code><code class="member">set_children</code>
- function.
+ consecutive components of the TriaLevel::cells vector,
+ respectively. It is only known that children are stored at
+ least in pairs. Therefore, it is not sufficient any more to
+ store the index of the first child of a cell, only. Now the
+ indices of every second child, i.e. of the even numbered
+ children, must be stored. For this, the
+ TriaObjectAccessor::set_children function for cells now has a
+ new argument representing the number of the child for which the
+ index shall be set. This function can only be called for even
+ numbered children. The same applies to the respective function
+ for faces.
<br>
Finally, we note that these functions are for internal use,
only.
</p>
<li> <p>
- Changed: The <code>cell-></code><code
- class="member">refine_flag_set</code> function now returns a
- <code>RefineCase::Type</code> argument instead of a boolean. Be
- aware, that you now still can ask
- <code>if(!cell->refine_flag_set())</code> ,
- <code>if(cell->refine_flag_set()==false)</code> and
+ Changed: The CellAccessor::refine_flag_set function now returns
+ a RefinementCase argument instead of a boolean. Be aware, that
+ you now still can ask <code>if(!cell->refine_flag_set())</code>
+ , <code>if(cell->refine_flag_set()==false)</code> and
<code>if(cell->refine_flag_set())</code> , but you cannot ask
<code>if(cell->refine_flag_set()==true)</code> any more.
<br>
</p>
<li> <p>
- Extended: The <code>cell-></code><code
- class="member">set_refine_flag</code> function now has a new
- <code>RefineCase::Type</code> argument which defaults to <code
- class="class">GeometryInfo<dim></code>::<code
- class="member">isotropic_refinement</code>.
+ Extended: The CellAccessor::set_refine_flag function now has a
+ new RefinementCase argument which defaults to
+ <tt>GeometryInfo<dim>::isotropic_refinement</tt>.
<br>
(RH 2005/03/03)
</p>
<li> <p>
- New: There is now a new enum <code>RefineCase::Type</code>
- defined in <code>geometry_info.h</code>, which allows to
- describe all possible (anisotropic and isotropic) refinement
- cases in (1,) 2 and 3 dimensions.
+ New: There is now a new class RefinementCase defined in
+ <code>geometry_info.h</code>, which allows to describe all
+ possible (anisotropic and isotropic) refinement cases in (1,) 2
+ and 3 dimensions.
<br>
(RH 2005/02/26)
</p>
<li> <p>
- New: There is now a new <code
- class="class">TriaObjectAccessor</code>::<code
- class="member">n_children</code> function which returns the
- number of children of the cell or face it was invoked for.
+ New: There is now a new TriaObjectAccessor::n_children function
+ which returns the number of children of the cell or face it was
+ invoked for.
<br>
(RH 2005/02/26)
</p>
<li> <p>
- New: There is now a new <code
- class="class">TriaObjectAccessor</code>::<code
- class="member">refine_case</code> function which returns the
- <code>RefineCase::Type</code> a cell or face is refined with.
+ New: There is now a new TriaObjectAccessor::refinement_case
+ function which returns the RefinementCase a cell or face is
+ refined with.
<br>
(RH 2005/02/26)
</p>
<li> <p>
- New: There is now a new <code
- class="class">TriaObjectAccessor</code>::<code
- class="member">set_refine_case</code> function. This function
- is mainly for internal use (required by <code
- class="class">Triangulation</code>::<code
- class="member">execute_coarsening_and_refinement</code>). It is
- not provided for <code>dim=1</code> as there the refinement
- case defaults to isotropic refinement.
- <br>
+ New (for internal use only): There is now a new
+ TriaObjectAccessor::set_refinement_case function. This function
+ is mainly for internal use (required by
+ Triangulation::execute_coarsening_and_refinement). It is not
+ provided for <code>dim=1</code> as there the refinement case
+ defaults to isotropic refinement.
+ <br>
+ Note, that users should still use the
+ CellAccessor::set_refine_flag function for setting the
+ RefinementCase of cells to be refined within the next
+ Triangulation::execute_coarsening_and_refinement function.
+ <br>
(RH 2005/02/26)
</p>
<li> <p>
- New: New <code>vector<RefineCase::Type>
- refine_cases</code> vectors have been introduced in <code
- class="class">TriangulationLevel<2>::QuadsData</code> and
- <code
- class="class">TriangulationLevel<3>::HexesData</code>. For
- memory efficiency (but with a penalty on run-time) they might
- be replaced by <code>vector<vector<bool> > (dim,
- vector<bool> (n_quads/n_hexes))</code>, later.
+
+ New: New <code>vector@<RefinementCase@> refinement_cases</code>
+ vectors have been introduced in TriaObjects. For memory
+ efficiency (but with a penalty on run-time) they might be
+ replaced by <code>vector@<vector@<bool@> @> (dim, vector@<bool@>
+ (n_quads/n_hexes))</code>, later.
<br>
(RH 2005/02/26)
</p>
</ol>
-<hr>
-Last update $Date$
-
-</body>
-</html>
+*/
<a href="#lac">lac</a>, and <a href="#deal.II">deal.II</a>, as well as
changes to the <a href="#general">general infrastructure,
documentation, etc</a>.
+<br>
+Furthermore, all changes which have been performed en route to
+extending deal.II from isotropic to anisotropic refinement are listed
+in this <a href="anisotropic_changes.html">list</a>.
</p>
<p>
for (unsigned int i=0; i<points.size(); ++i)
{
- const Point<dim> &p=points[i];
- Point<dim> &beta=values[i];
-
- beta(0) = -p(1);
- beta(1) = p(0);
- beta /= std::sqrt(beta.square());
+ values[i](0) = -points[i](1);
+ values[i](1) = points[i](0);
+ values[i] /= std::sqrt(values[i].square());
}
}
sparsity_pattern.reinit (dof_handler.n_dofs(),
dof_handler.n_dofs(),
(GeometryInfo<dim>::faces_per_cell
- *GeometryInfo<dim>::subfaces_per_face+1)*fe.dofs_per_cell);
+ *GeometryInfo<dim>::max_children_per_face+1)*fe.dofs_per_cell);
// For DG discretizations we call
// the function analogue to
// cell that has children replaced
// by one of its children:
else
- for (unsigned int child=0; child<GeometryInfo<dim>::children_per_cell;++child)
+ for (unsigned int child=0; child<GeometryInfo<dim>::max_children_per_cell;++child)
{
FullMatrix<double> new_matrix (fe.dofs_per_cell, fe.dofs_per_cell);
fe.get_prolongation_matrix(child).mmult (new_matrix,
--- /dev/null
+# $Id$
+
+
+# For the small projects Makefile, you basically need to fill in only
+# four fields.
+#
+# The first is the name of the application. It is assumed that the
+# application name is the same as the base file name of the single C++
+# file from which the application is generated.
+target = $(basename $(shell echo step-*.cc))
+
+# The second field determines whether you want to run your program in
+# debug or optimized mode. The latter is significantly faster, but no
+# run-time checking of parameters and internal states is performed, so
+# you should set this value to `on' while you develop your program,
+# and to `off' when running production computations.
+debug-mode = on
+
+
+# As third field, we need to give the path to the top-level deal.II
+# directory. You need to adjust this to your needs. Since this path is
+# probably the most often needed one in the Makefile internals, it is
+# designated by a single-character variable, since that can be
+# reference using $D only, i.e. without the parentheses that are
+# required for most other parameters, as e.g. in $(target).
+D = ../../
+
+
+# The last field specifies the names of data and other files that
+# shall be deleted when calling `make clean'. Object and backup files,
+# executables and the like are removed anyway. Here, we give a list of
+# files in the various output formats that deal.II supports.
+clean-up-files = *gmv *gnuplot *gpl *eps *pov
+
+
+
+
+#
+#
+# Usually, you will not need to change something beyond this point.
+#
+#
+# The next statement tell the `make' program where to find the
+# deal.II top level directory and to include the file with the global
+# settings
+include $D/common/Make.global_options
+
+
+# Since the whole project consists of only one file, we need not
+# consider difficult dependencies. We only have to declare the
+# libraries which we want to link to the object file, and there need
+# to be two sets of libraries: one for the debug mode version of the
+# application and one for the optimized mode. Here we have selected
+# the versions for 2d. Note that the order in which the libraries are
+# given here is important and that your applications won't link
+# properly if they are given in another order.
+#
+# You may need to augment the lists of libraries when compiling your
+# program for other dimensions, or when using third party libraries
+libs.g = $(lib-deal2-2d.g) \
+ $(lib-deal2-3d.g) \
+ $(lib-lac.g) \
+ $(lib-base.g)
+libs.o = $(lib-deal2-2d.o) \
+ $(lib-deal2-3d.o) \
+ $(lib-lac.o) \
+ $(lib-base.o)
+
+
+# We now use the variable defined above which switch between debug and
+# optimized mode to select the set of libraries to link with. Included
+# in the list of libraries is the name of the object file which we
+# will produce from the single C++ file. Note that by default we use
+# the extension .g.o for object files compiled in debug mode and .o for
+# object files in optimized mode (or whatever the local default on your
+# system is instead of .o).
+ifeq ($(debug-mode),on)
+ libraries = $(target).g.$(OBJEXT) $(libs.g)
+else
+ libraries = $(target).$(OBJEXT) $(libs.o)
+endif
+
+
+# Now comes the first production rule: how to link the single object
+# file produced from the single C++ file into the executable. Since
+# this is the first rule in the Makefile, it is the one `make' selects
+# if you call it without arguments.
+$(target) : $(libraries)
+ @echo ============================ Linking $@
+ @$(CXX) -o $@$(EXEEXT) $^ $(LIBS) $(LDFLAGS)
+
+
+# To make running the application somewhat independent of the actual
+# program name, we usually declare a rule `run' which simply runs the
+# program. You can then run it by typing `make run'. This is also
+# useful if you want to call the executable with arguments which do
+# not change frequently. You may then want to add them to the
+# following rule:
+run: $(target)
+ @echo ============================ Running $<
+ @./$(target)$(EXEEXT)
+
+
+# As a last rule to the `make' program, we define what to do when
+# cleaning up a directory. This usually involves deleting object files
+# and other automatically created files such as the executable itself,
+# backup files, and data files. Since the latter are not usually quite
+# diverse, you needed to declare them at the top of this file.
+clean:
+ -rm -f *.$(OBJEXT) *~ Makefile.dep $(target)$(EXEEXT) $(clean-up-files)
+
+
+# Since we have not yet stated how to make an object file from a C++
+# file, we should do so now. Since the many flags passed to the
+# compiler are usually not of much interest, we suppress the actual
+# command line using the `at' sign in the first column of the rules
+# and write the string indicating what we do instead.
+./%.g.$(OBJEXT) :
+ @echo ==============debug========= $(<F)
+ @$(CXX) $(CXXFLAGS.g) -c $< -o $@
+./%.$(OBJEXT) :
+ @echo ==============optimized===== $(<F)
+ @$(CXX) $(CXXFLAGS.o) -c $< -o $@
+
+
+# The following statement tells make that the rules `run' and `clean'
+# are not expected to produce files of the same name as Makefile rules
+# usually do.
+.PHONY: run clean
+
+
+# Finally there is a rule which you normally need not care much about:
+# since the executable depends on some include files from the library,
+# besides the C++ application file of course, it is necessary to
+# re-generate the executable when one of the files it depends on has
+# changed. The following rule to created a dependency file
+# `Makefile.dep', which `make' uses to determine when to regenerate
+# the executable. This file is automagically remade whenever needed,
+# i.e. whenever one of the cc-/h-files changed. Make detects whether
+# to remake this file upon inclusion at the bottom of this file.
+#
+# If the creation of Makefile.dep fails, blow it away and fail
+Makefile.dep: $(target).cc Makefile \
+ $(shell echo $D/*/include/*/*.h)
+ @echo ============================ Remaking $@
+ @$D/common/scripts/make_dependencies $(INCLUDE) -B. $(target).cc \
+ > $@ \
+ || (rm -f $@ ; false)
+ @if test -s $@ ; then : else rm $@ ; fi
+
+
+# To make the dependencies known to `make', we finally have to include
+# them:
+include Makefile.dep
+
+
--- /dev/null
+<a name="Intro"></a>
+<h1>Introduction</h1>
+
+
+<h3>Overview</h3>
+
+This example is devoted to <em>anisotropic refinement</em>, which extends to
+possibilities of local refinement. In most parts, this is a modification of the
+@ref step_12 "step-12" tutorial program, we use the same DG method for a linear transport
+equation. This program will cover the following topics:
+<ol>
+ <li> <em>Anisotropic refinement</em>: What is the meaning of anisotropic refinement?
+ <li> <em>Implementation</em>: Necessary modifications of code to work with anisotropically refined meshes.
+ <li> <em>Jump indicator</em>: A simple indicator for anisotropic refinement in
+ the context of DG methods.
+</ol>
+The discretization itself will not be discussed, and neither will
+implementation techniques not specific to anisotropic refinement used
+here. Please refer to @ref step_12 "step-12" for this.
+
+Please note, at the moment of writing this tutorial program, anisotropic
+refinement is only fully implemented for discontinuous Galerkin Finite
+Elements. This may later change (or may already have).
+
+
+<h3>Anisotropic refinement</h3>
+
+All the adaptive processes in the preceding tutorial programs were based on
+<em>isotropic</em> refinement of cells, which cuts all edges in half and forms
+new cells of these split edges (plus some additional edges, faces and vertices,
+of course). In deal.II, <em>anisotropic refinement</em> refers to the process of
+splitting only part of the edges while leaving the others unchanged. Consider a
+simple square cell, for example:
+@code
+ *-------*
+ | |
+ | |
+ | |
+ *-------*
+@endcode
+After the usual refinement it will consist of four children and look like this:
+@code
+ *---*---*
+ | | |
+ *---*---* RefinementCase<2>::cut_xy
+ | | |
+ *---*---*
+@endcode
+The new anisotropic refinement may take two forms: either we can split the edges
+which are parallel to the horizontal x-axis, resulting in these two child cells:
+@code
+ *---*---*
+ | | |
+ | | | RefinementCase<2>::cut_x
+ | | |
+ *---*---*
+@endcode
+or we can split the two edges which run along the y-axis, resulting again in two
+children, which look that way, however:
+@code
+ *-------*
+ | |
+ *-------* RefinementCase<2>::cut_y
+ | |
+ *-------*
+@endcode
+All refinement cases of cells are described by an enumeration
+RefinementPossibilities::Possibilities, and the above anisotropic
+cases are called @p cut_x and @p cut_y for obvious reasons. The
+isotropic refinement case is called @p cut_xy in 2D and can be
+requested from the GeometryInfo class via
+GeometryInfo<2>::isotropic_refinement.
+
+In 3D, there is a third axis which can be split, the z-axis, and thus we
+have an additional refinement case @p cut_z here. Isotropic refinement will now
+refine a cell along the x-, y- and z-axes and thus be referred to as @p
+cut_xyz. Additional cases @p cut_xy, @p cut_xz and @p cut_yz exist, which refine
+a cell along two of the axes, but not along the third one. Given a hex cell with
+x-axis running to the right, y-axis 'into the page' and z-axis to the top,
+@code
+ *-----------*
+ / /|
+ / / |
+ / / |
+ *-----------* |
+ | | |
+ | | *
+ | | /
+ | | /
+ | |/
+ *-----------*
+@endcode
+we have the isotropic refinement case,
+@code
+ *-----*-----*
+ / / /|
+ *-----*-----* |
+ / / /| *
+ *-----*-----* |/|
+ | | | * |
+ | | |/| *
+ *-----*-----* |/
+ | | | *
+ | | |/
+ *-----*-----*
+
+ cut_xyz
+@endcode
+three anisotropic cases which refine only one axis:
+@code
+ *-----*-----* *-----------* *-----------*
+ / / /| / /| / /|
+ / / / | *-----------* | / / |
+ / / / | / /| | / / *
+ *-----*-----* | *-----------* | | *-----------* /|
+ | | | | | | | | | | / |
+ | | | * | | | * | |/ *
+ | | | / | | |/ *-----------* /
+ | | | / | | * | | /
+ | | |/ | |/ | |/
+ *-----*-----* *-----------* *-----------*
+
+ cut_x cut_y cut_z
+@endcode
+and three cases which refine two of the three axes:
+@code
+ *-----*-----* *-----*-----* *-----------*
+ / / /| / / /| / /|
+ *-----*-----* | / / / | *-----------* |
+ / / /| | / / / * / /| *
+ *-----*-----* | | *-----*-----* /| *-----------* |/|
+ | | | | | | | | / | | | * |
+ | | | | * | | |/ * | |/| *
+ | | | |/ *-----*-----* / *-----------* |/
+ | | | * | | | / | | *
+ | | |/ | | |/ | |/
+ *-----*-----* *-----*-----* *-----------*
+
+ cut_xy cut_xz cut_yz
+@endcode
+For 1D problems, anisotropic refinement can make no difference, as there is only
+one coordinate direction for a cell, so it is not possible to split it
+in any other way than isotropically.
+
+<h4>Motivation</h4>
+Adaptive local refinement is used to obtain fine meshes which are well adapted
+to solving the problem at hand efficiently. In short, the size of cells which
+produce a large error is reduced to obtain a better approximation of the
+solution to the problem at hand. However, a lot of problems contain anisotropic
+features. Prominent examples are shocks or boundary layers in compressible
+viscous flows. An efficient mesh approximates these features with cells of higher aspect ratio
+which are oriented according to the mentioned features. Using only isotropic
+refinement, the aspect ratios of the original mesh cells are preserved, as they
+are inherited by the children of a cell. Thus, starting from an isotropic mesh, a
+boundary layer will be refined in order to catch the rapid variation of the flow
+field in the wall normal direction, thus leading to cells with very small edge
+lengths both in normal and tangential direction. Usually, much higher edge
+lengths in tangential direction and thus significantly less cells could be used
+without a significant loss in approximation accuracy. An anisotropic
+refinement process can modify the aspect ratio from mother to child cells by a
+factor of two for each refinement step. In the course of several refinements,
+the aspect ratio of the fine cells can be optimized, saving a considerable
+number of cells and correspondingly degrees of freedom and thus computational
+resources, memory as well as CPU time.
+
+<h3>Implementation</h3>
+
+Most of the time, when we do finite element computations, we only consider one
+cell at a time, for example to calculate cell contributions to the global
+matrix, or to interpolate boundary values. However, sometimes we have to look
+at how cells are related in our algorithms. Relationships between cells come
+in two forms: neighborship and mother-child relationship. For the case of
+isotropic refinement, deal.II uses certain conventions (invariants) for cell
+relationships that are always maintained. For example, a refined cell always
+has exactly $2^{dim}$ children. And (except for the 1d case), two neighboring
+cells may differ by at most one refinement level: they are equally often
+refined or one of them is exactly once more refined, leaving exactly one
+hanging node on the common face. Almost all of the time these invariants are
+only of concern in the internal implementation of the library. However, there
+are cases where knowledge of them is also relevant to an application program.
+
+In the current context, it is worth noting that the kind of mesh refinement
+affects some of the most fundamental assumptions. Consequently, some of the
+usual code found in application programs will need modifications to exploit
+the features of meshes which were created using anisotropic
+refinement. For those interested in how deal.II evolved, it may be of
+interest that the losening of such invariants required some
+incompatible changes. For example, the library used to have a member
+GeometryInfo<dim>::children_per_cell that specified how many children
+a cell has once it is refined. For isotropic refinement, this number
+is equal to $2^{dim}$, as mentioned above. However, for anisotropic refinement, this number
+does not exist, as is can be either two or four in 2D and two, four or eight in
+3D, and the member GeometryInfo<dim>::children_per_cell has
+consequently been removed. It has now been replaced by
+GeometryInfo<dim>::max_children_per_cell which specifies the
+<i>maximum</i> number of children a cell can have. How many children a
+refined cell has was previously available as static informtion, but
+now it depends on the actual refinement state of a cell and can be
+retrieved using the function call <code>cell-@>n_children()</code>,
+a call that works equally well for both isotropic and anisotropic
+refinement. A very similar situation can be found for
+faces and their subfaces: the previously available variable
+GeometryInfo<dim>::subfaces_per_face no
+longer exists; the pertinent information can now be queried using
+GeometryInfo<dim>::max_children_per_face or <code>face->n_children()</code>,
+depending on the context.
+
+Another important aspect, and the most important one in this tutorial, is
+the treatment of neighbor-relations when assembling jump terms on the
+faces between cells. Looking at the documentation of the
+assemble_system functions in @ref step_12 "step-12" we notice, that we need to decide if a
+neighboring cell is coarser, finer or on the same (refinement) level as our
+current cell. These decisions do not work in the same way for anisotropic
+refinement as the information given by the <em>level</em> of a cell is not
+enough to completely characterize anisotropic cells; for example, are
+the terminal children of a two-dimensional
+cell that is first cut in $x$-direction and whose children are then
+cut in $y$-direction on level 2, or are they on level 1 as they would
+be if the cell would have been refined once isotropically, resulting
+in the same set of finest cells?
+
+After anisotropic refinement, a coarser neighbor is not necessarily
+exactly one level below ours, but can pretty much have any level
+relative to the current one; in fact, it can even be on a higher
+level even though it is coarser. Thus the decisions
+have to be made on a different basis, whereas the intention of the
+decisions stays the same.
+
+In the following, we will discuss the cases that can happen when we
+want to compute contributions to the matrix (or right hand side) of
+the form
+@f[
+ \int_{\partial K} \varphi_i(x) \varphi_j(x) \; dx
+@f]
+or similar; remember that we integrate terms like this using the
+FEFaceValues and FESubfaceValues classes. We will also show how to
+write code that works for both isotropic and anisotropic refinement:
+
+<ul>
+ <li> <em>Finer neighbor</em>: If we are on an active cell and want
+ to integrate over a face $f\subset \partial K$, the first
+ possibility is that the neighbor behind this face is more refined,
+ i.e. has children occupying only part of the
+ common face. In this case, the face
+ under consideration has to be a refined one, which can determine by
+ asking <code>if(face->has_children())</code>. If this is true, we need to
+ loop over
+ all subfaces and get the neighbors' child behind this subface, so that we can
+ reinit an FEFaceValues object with the neighbor and an FESubfaceValues object
+ with our cell and the respective subface.
+
+ For isotropic refinement, this kind is reasonably simple because we
+ know that an invariant of the isotropically refined adaptive meshes
+ in deal.II is that neighbors can only differ by exactly one
+ refinement level. However, this isn't quite true any more for
+ anisotropically refined meshes, in particular in 3d; there,
+ the active cell we are interested on the other side of $f$ might not
+ actually be a child of our
+ neighbor, but perhaps a grandchild or even a farther offspring. Fortunately,
+ this complexity is hidden in the internals of the library. All we need to do
+ is call the <code>cell->neighbor_child_on_subface(face_no, subface_no)</code>
+ function. Still, in 3D there are two cases which need special consideration:
+ <ul>
+ <li> If the neighbor is refined more than once anisotropically, it might be
+ that here are not two or four but actually three subfaces to
+ consider. Imagine
+ the following refinement process of the (two-dimensional) face of
+ the (three-dimensional) neighbor cell we are considering: first the
+ face is refined along x, later on only the left subface is refined along y.
+@code
+ *-------* *---*---* *---*---*
+ | | | | | | | |
+ | | ---> | | | ---> *---* |
+ | | | | | | | |
+ *-------* *---*---* *---*---*
+@endcode
+ Here the number of subfaces is three. It is important to note the subtle
+ differences between <code>face->n_children()</code> and
+ <code>face->number_of_children()</code>. The first function returns the number of
+ immediate children, which would be two for the above example, whereas the
+ second returns the number of active offsprings, which is the correct three in
+ the example above. Using <code>face->number_of_children()</code> works for
+ isotropic and anisotropic as well as 2D and 3D cases, so it should always be
+ used. It should be noted that if any of the cells behind the two
+ small subfaces on the left side of the rightmost image is further
+ refined, then the current cell (i.e. the side from which we are
+ viewing this common face) is going to be refined as well: this is so
+ because otherwise the invariant of having only one hanging node per
+ edge would be violated.
+
+ <li> It might be, that the neighbor is coarser, but still has children which
+ are finer than our current cell. This situation can occur if two equally
+ coarse cells are refined, where one of the cells has two children at the face
+ under consideration and the other one four. The cells in the next graphic are
+ only separated from each other to show the individual refinement cases.
+@code
+ *-----------* *-----------*
+ / /| / /|
+ ############# | +++++++++++++ |
+ # ## | + ++ *
+ ############# # | +++++++++++++ +/|
+ # # # | + + + |
+ # # # * + +++ *
+ # # #/ +++++++++++++ +/
+ # # # + + +
+ # ## + ++
+ ############# +++++++++++++
+@endcode
+
+ Here, the left two cells resulted from an anisotropic bisection of
+ the mother cell in $y$-direction, whereas the right four cells
+ resulted from a simultaneous anisotropic refinement in both the $y$-
+ and $z$-directions.
+ The left cell marked with # has two finer neighbors marked with +, but the
+ actual neighbor of the left cell is the complete right mother cell, as the
+ two cells marked with + are finer and their direct mother is the one
+ large cell.
+ </ul>
+
+ However, it is comfortable to know, that
+ <code>cell->neighbor_child_on_subface(face_no,subface_no)</code> takes care of
+ these situations by itself, if you loop over the correct number of subfaces,
+ in the above example this is two. The FESubfaceValues<dim>::reinit function
+ takes care of this too, so that the resulting state is always correct. There
+ is one little aspect, however: For reiniting the neighbors FEFaceValues object
+ you need to know the index of the face that points toward the current
+ cell. Usually you assume that the neighbor you get directly is as coarse or as
+ fine as you, if it has children, thus this information can be obtained by the
+ <code>cell->neighbor_of_neighbor(face_no)</code> function. If the neighbor is
+ coarser, however, you would have to use
+ <code>cell->neighbor_of_coarser_neighbor(face_no).first</code> instead. In order
+ to make this easy for you, there is the new
+ <code>cell->neighbor_face_no(face_no)</code> function which does the correct thing
+ for you and returns the desired result.
+
+ <li> <em>Neighbor is as fine as our cell</em>: After we ruled out all cases in
+ which there are finer children, we only need to decide, whether the neighbor
+ is coarser here. For this, there is the
+ <code>cell->coarser_neighbor(face_no)</code> function returning a bool value. In
+ order to get the relevant case of a neighbor of the same coarseness we would
+ use <code>else if (!cell->coarser_neighbor(face_no))</code>. The code inside this
+ block can be left untouched. However, there is one thing to mention here: If
+ we want to use a rule, which cell should assemble certain terms on a given
+ face we might think of the rule presented in @ref step_12 "step-12". We know that we have to
+ leave out the part about comparing our cell's level with that of the neighbor
+ and replace it with the test for a coarser neighbor presented above. However,
+ we also have to consider the possibility that neighboring cells of same
+ coarseness have the same index (on different levels). Thus we have to include
+ the case where the cells have the same index, and give an additional
+ condition, which of the cells should assemble the terms, e.g. we can choose
+ the cell with lower level. The details of this concept can be seen in the
+ implementation below.
+
+ <li> <em>Coarser neighbor</em>: The remaining case is obvious: If there are no
+ refined neighbors and the neighbor is not as fine as the current cell, then it needs
+ to be coarser. Thus we can leave the old condition phrase, simply using
+ <code>else</code>. The <code>cell->neighbor_of_coarser_neighbor(face_no)</code>
+ function takes care of all the complexity of anisotropic refinement combined
+ with possible non standard face orientation, flip and rotation on general 3D meshes.
+
+</ul>
+
+<h4>Mesh smoothing</h4>
+When a triangulation is refined, cells which were not flagged for refinement may
+be refined nonetheless. This is due to additional smoothing algorithms which are
+either necessary or requested explicitly. In particular, the restriction that there
+be at most one hanging node on each edge frequently forces the refinement of additional
+cells neighboring ones that are already finer and are flagged for
+further refinement.
+
+However, deal.II also implements a number of algorithms that make sure
+that resulting meshes are smoother than just the bare minimum, for
+example ensuring that there are no isolated refined cells surrounded
+by non-refined ones, since the additional degrees of freedom on these
+islands would almost all be constrained by hanging node
+constraints. (See the documentation of the Triangulation class and its
+Triangulation::MeshSmoothing member for more information on mesh
+smoothing.)
+
+Most of the smoothing algorithms that were originally developed for
+the isotropic case have been adapted to work in a very similar
+way for both anisotropic and isotropic refinement. There are two
+algorithms worth mentioning, however:
+<ol>
+ <li> <code>MeshSmoothing::limit_level_difference_at_vertices</code>: In an isotropic environment,
+ this algorithm tries to ensure a good approximation quality by reducing the
+ difference in refinement level of cells meeting at a common vertex. However,
+ there is no clear corresponding concept for anisotropic refinement, thus this
+ algorithm may not be used in combination with anisotropic refinement. This
+ restriction is enforced by an assertion which throws an error as soon as the
+ algorithm is called on a triangulation which has been refined anisotropically.
+
+ <li> <code>MeshSmoothing::allow_anisotropic_smoothing</code>: If refinement is introduced to
+ limit the number of hanging nodes, the additional cells are often not needed
+ to improve the approximation quality. This is especially true for DG
+ methods. If you set the flag <code>allow_anisotropic_smoothing</code> the
+ smoothing algorithm tries to minimize the number of probably unneeded
+ additional cells by using anisotropic refinement for the smoothing. If you set
+ this smoothing flag you might get anisotropically refined cells, even if you
+ never set a single refinement flag to anisotropic refinement. Be aware that
+ you should only use this flag, if your code respects the possibility of
+ anisotropic meshes. Combined with a suitable anisotropic indicator this flag
+ can help save additional cells and thus effort.
+</ol>
+
+
+<h3>Jump indicator</h3>
+
+Using the benefits of anisotropic refinement requires an indicator to catch
+anisotropic features of the solution and exploit them for the refinement
+process. Generally the anisotropic refinement process will consist of several
+steps:
+<ol>
+ <li> Calculate an error indicator.
+ <li> Use the error indicator to flag cells for refinement, e.g. using a fixed
+ number or fraction of cells. Those cells will be flagged for isotropic
+ refinement automatically.
+ <li> Evaluate a distinct anisotropic indicator only on the flagged cells.
+ <li> Use the anisotropic indicator to set a new, anisotropic refinement flag
+ for cells where this is appropriate, leave the flags unchanged otherwise.
+ <li> Call Triangulation<dim>::execute_coarsening_and_refinement to perform the
+ requested refinement, using the requested isotropic and anisotropic flags.
+</ol>
+This approach is similar to the one we have used in @ref step_27 "step-27"
+for hp refinement and
+has the great advantage of flexibility: Any error indicator can be
+used in the anisotropic process, i.e. if you have quite involved a posteriori
+goal-oriented error indicators available you can use them as easily as a simple
+Kelly error estimator. The anisotropic part of the refinement process is not
+influenced by this choice. Furthermore, simply leaving out the third and forth
+steps leads to the same isotropic refinement you used to get before any
+anisotropic changes in deal.II or your application program.
+As a last advantage, working only
+on cells flagged for refinement results in a faster evaluation of the
+anisotropic indicator, which can become noticeable on finer meshes with a lot of
+cells if the indicator is quite involved.
+
+Here, we use a very simple approach which is only applicable to DG
+methods. The general idea is quite simple: DG methods allow the discrete
+solution to jump over the faces of a cell, whereas it is smooth within each
+cell. Of course, in the limit we expect that the jumps tend to zero as
+we refine the mesh and approximate the true solution better and better.
+Thus, a large jump
+across a given face indicates that the cell should be refined (at least)
+orthogonal to that face, whereas a small jump does not lead to this
+conclusion. It is possible, of course, that the exact solution is not smooth and
+that it also features a jump. In that case, however, a large jump over one face
+indicates, that this face is more or less parallel to the jump and in the
+vicinity of it, thus again we would expect a refinement orthogonal to the face
+under consideration to be effective.
+
+The proposed indicator calculates the average jump $K_j$, i.e. the mean value of
+the absolute jump $|[u]|$ of the discrete solution $u$ over the two faces
+$f_i^j$, $i=1,2$, $j=1..d$ orthogonal to coordinate direction $j$ on the unit
+cell.
+@f[
+K_j = \frac{\sum_{i=1}^2 \int_{f_i^j}|[u]| dx}{\sum_{i=1}^2 |f_i^j|} .
+@f]
+If the average jump in one direction is larger than the average of the
+jumps in the other directions by a
+certain factor $\kappa$, i.e. if
+$K_i > \kappa \frac 1{d-1} \sum_{j=1, j\neq i}^d K_j$, the cell is refined only along that particular
+direction $i$, otherwise the cell is refined isotropically.
+
+Such a criterion is easily generalized to systems of equations: the
+absolute value of the jump would be replaced by an appropriate norm of
+the vector-valued jump.
+
+
+
+<h3>The problem</h3>
+
+We solve the linear transport equation presented in @ref step_12 "step-12". The domain is
+extended to cover $[-1,1]\times[0,1]$ in 2D, where the flow field $\beta$ describes a
+counterclockwise quarter circle around the origin in the right half of the
+domain and is parallel to the x-axis in the left part of the domain. The inflow
+boundary is again located at $x=1$ and along the positive part of the x-axis,
+and the boundary conditions are chosen as in @ref step_12 "step-12". Compared to @ref step_12 "step-12" we
+only use the more effective second assembling technique. In order to make
+comparisons more effective, we decided to keep function names like @p
+assemble_system2 even if there is only one of these routines in this tutorial
+program.
--- /dev/null
+<h1>Results</h1>
+
+
+The output of this program consist of the console output, the eps
+files containing the grids, and the grids and solutions given in gnuplot format.
+@code
+Performing a 2D run with isotropic refinement...
+------------------------------------------------
+Cycle 0:
+ Number of active cells: 128
+ Number of degrees of freedom: 512
+Time of assemble_system2: 0.040003
+Writing grid to <grid-0.iso.eps>...
+Writing grid to <grid-0.iso.gnuplot>...
+Writing solution to <sol-0.iso.gnuplot>...
+Cycle 1:
+ Number of active cells: 239
+ Number of degrees of freedom: 956
+Time of assemble_system2: 0.072005
+Writing grid to <grid-1.iso.eps>...
+Writing grid to <grid-1.iso.gnuplot>...
+Writing solution to <sol-1.iso.gnuplot>...
+Cycle 2:
+ Number of active cells: 491
+ Number of degrees of freedom: 1964
+Time of assemble_system2: 0.144009
+Writing grid to <grid-2.iso.eps>...
+Writing grid to <grid-2.iso.gnuplot>...
+Writing solution to <sol-2.iso.gnuplot>...
+Cycle 3:
+ Number of active cells: 1031
+ Number of degrees of freedom: 4124
+Time of assemble_system2: 0.296019
+Writing grid to <grid-3.iso.eps>...
+Writing grid to <grid-3.iso.gnuplot>...
+Writing solution to <sol-3.iso.gnuplot>...
+Cycle 4:
+ Number of active cells: 2027
+ Number of degrees of freedom: 8108
+Time of assemble_system2: 0.576036
+Writing grid to <grid-4.iso.eps>...
+Writing grid to <grid-4.iso.gnuplot>...
+Writing solution to <sol-4.iso.gnuplot>...
+Cycle 5:
+ Number of active cells: 4019
+ Number of degrees of freedom: 16076
+Time of assemble_system2: 1.13607
+Writing grid to <grid-5.iso.eps>...
+Writing grid to <grid-5.iso.gnuplot>...
+Writing solution to <sol-5.iso.gnuplot>...
+
+Performing a 2D run with anisotropic refinement...
+--------------------------------------------------
+Cycle 0:
+ Number of active cells: 128
+ Number of degrees of freedom: 512
+Time of assemble_system2: 0.040003
+Writing grid to <grid-0.aniso.eps>...
+Writing grid to <grid-0.aniso.gnuplot>...
+Writing solution to <sol-0.aniso.gnuplot>...
+Cycle 1:
+ Number of active cells: 171
+ Number of degrees of freedom: 684
+Time of assemble_system2: 0.048003
+Writing grid to <grid-1.aniso.eps>...
+Writing grid to <grid-1.aniso.gnuplot>...
+Writing solution to <sol-1.aniso.gnuplot>...
+Cycle 2:
+ Number of active cells: 255
+ Number of degrees of freedom: 1020
+Time of assemble_system2: 0.072005
+Writing grid to <grid-2.aniso.eps>...
+Writing grid to <grid-2.aniso.gnuplot>...
+Writing solution to <sol-2.aniso.gnuplot>...
+Cycle 3:
+ Number of active cells: 397
+ Number of degrees of freedom: 1588
+Time of assemble_system2: 0.16401
+Writing grid to <grid-3.aniso.eps>...
+Writing grid to <grid-3.aniso.gnuplot>...
+Writing solution to <sol-3.aniso.gnuplot>...
+Cycle 4:
+ Number of active cells: 658
+ Number of degrees of freedom: 2632
+Time of assemble_system2: 0.192012
+Writing grid to <grid-4.aniso.eps>...
+Writing grid to <grid-4.aniso.gnuplot>...
+Writing solution to <sol-4.aniso.gnuplot>...
+Cycle 5:
+ Number of active cells: 1056
+ Number of degrees of freedom: 4224
+Time of assemble_system2: 0.304019
+Writing grid to <grid-5.aniso.eps>...
+Writing grid to <grid-5.aniso.gnuplot>...
+Writing solution to <sol-5.aniso.gnuplot>...
+@endcode
+
+This text output shows the reduction in the number of cells which results from
+the successive application of anisotropic refinement. After the last refinement
+step the savings have accumulated so much, that almost four times as many cells
+and thus dofs are needed in the isotropic case. The time needed for assembly
+scales with a similar factor.
+
+Now we show the solutions on the mesh after one and after five adaptive
+refinement steps for both the isotropic (left) and anisotropic refinement
+algorithms (right).
+
+<TABLE WIDTH="60%" ALIGN="center">
+ <tr>
+ <td ALIGN="center">
+ @image html step-30.sol-1.iso.png
+ </td>
+
+ <td ALIGN="center">
+ @image html step-30.sol-1.aniso.png
+ </td>
+ </tr>
+ <tr>
+ <td ALIGN="center">
+ @image html step-30.sol-5.iso.png
+ </td>
+
+ <td ALIGN="center">
+ @image html step-30.sol-5.aniso.png
+ </td>
+ </tr>
+</table>
+
+We see, that the solution on the anisotropically refined mesh is very similar to
+the solution obtained on the isotropically refined mesh. Thus the anisotropic
+indicator seems to effectively select the appropriate cells for anisotropic
+refinement. This observation is strengthened by the plot of the an adapted
+anisotropic grid, e.g. the grid after three refinement steps.
+
+@image html step-30.grid-3.aniso.png
+
+In the whole left part of the domain refinement is only performed along the
+y-axis of cells. In the right part of the domain the refinement is dominated by
+isotropic refinement, as the anisotropic feature of the solution - the jump from
+one to zero - is not well aligned with the mesh. However, at the bottom and
+leftmost parts of the quarter circle this jumps becomes more and more aligned
+with the mesh and the refinement algorithm reacts by creating anisotropic cells
+of increasing aspect ratio.
+
+It might seem that the necessary alignment of anisotropic features and the
+coarse mesh can decrease performance significantly for real world
+problems. However, that is not always the case. Considering boundary layers in
+compressible viscous flows, for example, the mesh is always aligned with the
+anisotropic features, thus anisotropic refinement will almost alway increase the
+efficiency of computations on adapted grids for these cases.
+
--- /dev/null
+/* $Id$ */
+/* Author: Tobias Leicht, 2007 */
+
+/* $Id$ */
+/* Version: $Name$ */
+/* */
+/* Copyright (C) 2007, 2008 by the deal.II authors */
+/* */
+/* This file is subject to QPL and may not be distributed */
+/* without copyright and license information. Please refer */
+/* to the file deal.II/doc/license.html for the text and */
+/* further information on this license. */
+
+ // The deal.II include files have already
+ // been covered in previous examples
+ // and will thus not be further
+ // commented on.
+#include <base/quadrature_lib.h>
+#include <base/function.h>
+#include <lac/vector.h>
+#include <lac/sparse_matrix.h>
+#include <grid/tria.h>
+#include <grid/grid_generator.h>
+#include <grid/grid_out.h>
+#include <grid/grid_refinement.h>
+#include <grid/tria_accessor.h>
+#include <grid/tria_iterator.h>
+#include <fe/fe_values.h>
+#include <dofs/dof_handler.h>
+#include <dofs/dof_accessor.h>
+#include <dofs/dof_tools.h>
+#include <numerics/data_out.h>
+#include <fe/mapping_q1.h>
+#include <fe/fe_dgq.h>
+#include <lac/solver_richardson.h>
+#include <lac/precondition_block.h>
+#include <numerics/derivative_approximation.h>
+#include <base/timer.h>
+
+ // And this again is C++:
+#include <iostream>
+#include <fstream>
+
+ // The last step is as in all
+ // previous programs:
+using namespace dealii;
+
+ // @sect3{Equation data}
+ //
+ // The classes describing equation data and the
+ // actual assembly of individual terms are
+ // almost entirely copied from step-12. We will
+ // comment on differences.
+template <int dim>
+class RHS: public Function<dim>
+{
+ public:
+ virtual void value_list (const std::vector<Point<dim> > &points,
+ std::vector<double> &values,
+ const unsigned int component=0) const;
+};
+
+
+template <int dim>
+class BoundaryValues: public Function<dim>
+{
+ public:
+ virtual void value_list (const std::vector<Point<dim> > &points,
+ std::vector<double> &values,
+ const unsigned int component=0) const;
+};
+
+
+template <int dim>
+class Beta
+{
+ public:
+ Beta () {}
+ void value_list (const std::vector<Point<dim> > &points,
+ std::vector<Point<dim> > &values) const;
+};
+
+
+template <int dim>
+void RHS<dim>::value_list(const std::vector<Point<dim> > &points,
+ std::vector<double> &values,
+ const unsigned int) const
+{
+ Assert(values.size()==points.size(),
+ ExcDimensionMismatch(values.size(),points.size()));
+
+ for (unsigned int i=0; i<values.size(); ++i)
+ values[i]=0;
+}
+
+
+ // The flow field is chosen to be a
+ // quarter circle with
+ // counterclockwise flow direction
+ // and with the origin as midpoint
+ // for the right half of the domain
+ // with positive $x$ values, whereas
+ // the flow simply goes to the left
+ // in the left part of the domain at
+ // a velocity that matches the one
+ // coming in from the right. In the
+ // circular part the magnitude of the
+ // flow velocity is proportional to
+ // the distance from the origin. This
+ // is a difference to step-12, where
+ // the magnitude was 1
+ // evereywhere. the new definition
+ // leads to a linear variation of
+ // $\beta$ along each given face of a
+ // cell. On the other hand, the
+ // solution $u(x,y)$ is exactly the
+ // same as before.
+template <int dim>
+void Beta<dim>::value_list(const std::vector<Point<dim> > &points,
+ std::vector<Point<dim> > &values) const
+{
+ Assert(values.size()==points.size(),
+ ExcDimensionMismatch(values.size(),points.size()));
+
+ for (unsigned int i=0; i<points.size(); ++i)
+ {
+ if (points[i](0) > 0)
+ {
+ values[i](0) = -points[i](1);
+ values[i](1) = points[i](0);
+ }
+ else
+ {
+ values[i] = Point<dim>();
+ values[i](0) = -points[i](1);
+ }
+ }
+}
+
+
+template <int dim>
+void BoundaryValues<dim>::value_list(const std::vector<Point<dim> > &points,
+ std::vector<double> &values,
+ const unsigned int) const
+{
+ Assert(values.size()==points.size(),
+ ExcDimensionMismatch(values.size(),points.size()));
+
+ for (unsigned int i=0; i<values.size(); ++i)
+ {
+ if (points[i](0)<0.5)
+ values[i]=1.;
+ else
+ values[i]=0.;
+ }
+}
+
+
+ // @sect3{Class: DGTransportEquation}
+ //
+ // This declaration of this
+ // class is utterly unaffected by our
+ // current changes. The only
+ // substantial change is that we use
+ // only the second assembly scheme
+ // described in step-12.
+template <int dim>
+class DGTransportEquation
+{
+ public:
+ DGTransportEquation();
+
+ void assemble_cell_term(const FEValues<dim>& fe_v,
+ FullMatrix<double> &ui_vi_matrix,
+ Vector<double> &cell_vector) const;
+
+ void assemble_boundary_term(const FEFaceValues<dim>& fe_v,
+ FullMatrix<double> &ui_vi_matrix,
+ Vector<double> &cell_vector) const;
+
+ void assemble_face_term2(const FEFaceValuesBase<dim>& fe_v,
+ const FEFaceValuesBase<dim>& fe_v_neighbor,
+ FullMatrix<double> &ui_vi_matrix,
+ FullMatrix<double> &ue_vi_matrix,
+ FullMatrix<double> &ui_ve_matrix,
+ FullMatrix<double> &ue_ve_matrix) const;
+ private:
+ const Beta<dim> beta_function;
+ const RHS<dim> rhs_function;
+ const BoundaryValues<dim> boundary_function;
+};
+
+
+ // Likewise, the constructor of the
+ // class as well as the functions
+ // assembling the terms corresponding
+ // to cell interiors and boundary
+ // faces are unchanged from
+ // before. The function that
+ // assembles face terms between cells
+ // also did not change because all it
+ // does is operate on two objects of
+ // type FEFaceValuesBase (which is
+ // the base class of both
+ // FEFaceValues and
+ // FESubfaceValues). Where these
+ // objects come from, i.e. how they
+ // are initialized, is of no concern
+ // to this function: it simply
+ // assumes that the quadrature points
+ // on faces or subfaces represented
+ // by the two objects correspond to
+ // the same points in physical space.
+template <int dim>
+DGTransportEquation<dim>::DGTransportEquation ()
+ :
+ beta_function (),
+ rhs_function (),
+ boundary_function ()
+{}
+
+
+template <int dim>
+void DGTransportEquation<dim>::assemble_cell_term(
+ const FEValues<dim> &fe_v,
+ FullMatrix<double> &ui_vi_matrix,
+ Vector<double> &cell_vector) const
+{
+ const std::vector<double> &JxW = fe_v.get_JxW_values ();
+
+ std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
+ std::vector<double> rhs (fe_v.n_quadrature_points);
+
+ beta_function.value_list (fe_v.get_quadrature_points(), beta);
+ rhs_function.value_list (fe_v.get_quadrature_points(), rhs);
+
+ for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
+ for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+ {
+ for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+ ui_vi_matrix(i,j) -= beta[point]*fe_v.shape_grad(i,point)*
+ fe_v.shape_value(j,point) *
+ JxW[point];
+
+ cell_vector(i) += rhs[point] * fe_v.shape_value(i,point) * JxW[point];
+ }
+}
+
+
+template <int dim>
+void DGTransportEquation<dim>::assemble_boundary_term(
+ const FEFaceValues<dim>& fe_v,
+ FullMatrix<double> &ui_vi_matrix,
+ Vector<double> &cell_vector) const
+{
+ const std::vector<double> &JxW = fe_v.get_JxW_values ();
+ const std::vector<Point<dim> > &normals = fe_v.get_normal_vectors ();
+
+ std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
+ std::vector<double> g(fe_v.n_quadrature_points);
+
+ beta_function.value_list (fe_v.get_quadrature_points(), beta);
+ boundary_function.value_list (fe_v.get_quadrature_points(), g);
+
+ for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
+ {
+ const double beta_n=beta[point] * normals[point];
+ if (beta_n>0)
+ for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+ for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+ ui_vi_matrix(i,j) += beta_n *
+ fe_v.shape_value(j,point) *
+ fe_v.shape_value(i,point) *
+ JxW[point];
+ else
+ for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+ cell_vector(i) -= beta_n *
+ g[point] *
+ fe_v.shape_value(i,point) *
+ JxW[point];
+ }
+}
+
+
+template <int dim>
+void DGTransportEquation<dim>::assemble_face_term2(
+ const FEFaceValuesBase<dim>& fe_v,
+ const FEFaceValuesBase<dim>& fe_v_neighbor,
+ FullMatrix<double> &ui_vi_matrix,
+ FullMatrix<double> &ue_vi_matrix,
+ FullMatrix<double> &ui_ve_matrix,
+ FullMatrix<double> &ue_ve_matrix) const
+{
+ const std::vector<double> &JxW = fe_v.get_JxW_values ();
+ const std::vector<Point<dim> > &normals = fe_v.get_normal_vectors ();
+
+ std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
+
+ beta_function.value_list (fe_v.get_quadrature_points(), beta);
+
+ for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
+ {
+ const double beta_n=beta[point] * normals[point];
+ if (beta_n>0)
+ {
+ for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+ for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+ ui_vi_matrix(i,j) += beta_n *
+ fe_v.shape_value(j,point) *
+ fe_v.shape_value(i,point) *
+ JxW[point];
+
+ for (unsigned int k=0; k<fe_v_neighbor.dofs_per_cell; ++k)
+ for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+ ui_ve_matrix(k,j) -= beta_n *
+ fe_v.shape_value(j,point) *
+ fe_v_neighbor.shape_value(k,point) *
+ JxW[point];
+ }
+ else
+ {
+ for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+ for (unsigned int l=0; l<fe_v_neighbor.dofs_per_cell; ++l)
+ ue_vi_matrix(i,l) += beta_n *
+ fe_v_neighbor.shape_value(l,point) *
+ fe_v.shape_value(i,point) *
+ JxW[point];
+
+ for (unsigned int k=0; k<fe_v_neighbor.dofs_per_cell; ++k)
+ for (unsigned int l=0; l<fe_v_neighbor.dofs_per_cell; ++l)
+ ue_ve_matrix(k,l) -= beta_n *
+ fe_v_neighbor.shape_value(l,point) *
+ fe_v_neighbor.shape_value(k,point) *
+ JxW[point];
+ }
+ }
+}
+
+
+ // @sect3{Class: DGMethod}
+ //
+ // Even the main class of this
+ // program stays more or less the
+ // same. We omit one of the assembly
+ // routines and use only the second,
+ // more effective one of the two
+ // presented in step-12. However, we
+ // introduce a new routine
+ // (set_anisotropic_flags) and modify
+ // another one (refine_grid).
+template <int dim>
+class DGMethod
+{
+ public:
+ DGMethod (const bool anisotropic);
+ ~DGMethod ();
+
+ void run ();
+
+ private:
+ void setup_system ();
+ void assemble_system1 ();
+ void assemble_system2 ();
+ void solve (Vector<double> &solution);
+ void refine_grid ();
+ void set_anisotropic_flags ();
+ void output_results (const unsigned int cycle) const;
+
+ Triangulation<dim> triangulation;
+ const MappingQ1<dim> mapping;
+ // Again we want to use DG elements of
+ // degree 1 (but this is only specified in
+ // the constructor). If you want to use a
+ // DG method of a different degree replace
+ // 1 in the constructor by the new degree.
+ const unsigned int degree;
+ FE_DGQ<dim> fe;
+ DoFHandler<dim> dof_handler;
+
+ SparsityPattern sparsity_pattern;
+ SparseMatrix<double> system_matrix;
+ // This is new, the threshold value used in
+ // the evaluation of the anisotropic jump
+ // indicator explained in the
+ // introduction. Its value is set to 3.0 in
+ // the constructor, but it can easily be
+ // changed to a different value greater
+ // than 1.
+ const double anisotropic_threshold_ratio;
+ // This is a bool flag indicating whether
+ // anisotropic refinement shall be used or
+ // not. It is set by the constructor, which
+ // takes an argument of the same name.
+ const bool anisotropic;
+
+ const QGauss<dim> quadrature;
+ const QGauss<dim-1> face_quadrature;
+
+ Vector<double> solution2;
+ Vector<double> right_hand_side;
+
+ const DGTransportEquation<dim> dg;
+};
+
+
+template <int dim>
+DGMethod<dim>::DGMethod (const bool anisotropic)
+ :
+ mapping (),
+ // Change here for DG
+ // methods of
+ // different degrees.
+ degree(1),
+ fe (degree),
+ dof_handler (triangulation),
+ anisotropic_threshold_ratio(3.),
+ anisotropic(anisotropic),
+ // As beta is a
+ // linear function,
+ // we can choose the
+ // degree of the
+ // quadrature for
+ // which the
+ // resulting
+ // integration is
+ // correct. Thus, we
+ // choose to use
+ // <code>degree+1</code>
+ // gauss points,
+ // which enables us
+ // to integrate
+ // exactly
+ // polynomials of
+ // degree
+ // <code>2*degree+1</code>,
+ // enough for all the
+ // integrals we will
+ // perform in this
+ // program.
+ quadrature (degree+1),
+ face_quadrature (degree+1),
+ dg ()
+{}
+
+
+template <int dim>
+DGMethod<dim>::~DGMethod ()
+{
+ dof_handler.clear ();
+}
+
+
+template <int dim>
+void DGMethod<dim>::setup_system ()
+{
+ dof_handler.distribute_dofs (fe);
+ sparsity_pattern.reinit (dof_handler.n_dofs(),
+ dof_handler.n_dofs(),
+ (GeometryInfo<dim>::faces_per_cell
+ *GeometryInfo<dim>::max_children_per_face+1)*fe.dofs_per_cell);
+
+ DoFTools::make_flux_sparsity_pattern (dof_handler, sparsity_pattern);
+
+ sparsity_pattern.compress();
+
+ system_matrix.reinit (sparsity_pattern);
+
+ solution2.reinit (dof_handler.n_dofs());
+ right_hand_side.reinit (dof_handler.n_dofs());
+}
+
+
+ // @sect4{Function: assemble_system2}
+ //
+ // We proceed with the
+ // <code>assemble_system2</code> function that
+ // implements the DG discretization in its
+ // second version. This function is very
+ // similar to the <code>assemble_system2</code>
+ // function from step-12, even the four cases
+ // considered for the neighbor-relations of a
+ // cell are the same, namely a) cell is at the
+ // boundary, b) there are finer neighboring
+ // cells, c) the neighbor is neither coarser
+ // nor finer and d) the neighbor is coarser.
+ // However, the way in which we decide upon
+ // which case we have are modified in the way
+ // described in the introduction.
+template <int dim>
+void DGMethod<dim>::assemble_system2 ()
+{
+ const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
+ std::vector<unsigned int> dofs (dofs_per_cell);
+ std::vector<unsigned int> dofs_neighbor (dofs_per_cell);
+
+ const UpdateFlags update_flags = update_values
+ | update_gradients
+ | update_quadrature_points
+ | update_JxW_values;
+
+ const UpdateFlags face_update_flags = update_values
+ | update_quadrature_points
+ | update_JxW_values
+ | update_normal_vectors;
+
+ const UpdateFlags neighbor_face_update_flags = update_values;
+
+ FEValues<dim> fe_v (
+ mapping, fe, quadrature, update_flags);
+ FEFaceValues<dim> fe_v_face (
+ mapping, fe, face_quadrature, face_update_flags);
+ FESubfaceValues<dim> fe_v_subface (
+ mapping, fe, face_quadrature, face_update_flags);
+ FEFaceValues<dim> fe_v_face_neighbor (
+ mapping, fe, face_quadrature, neighbor_face_update_flags);
+
+
+ FullMatrix<double> ui_vi_matrix (dofs_per_cell, dofs_per_cell);
+ FullMatrix<double> ue_vi_matrix (dofs_per_cell, dofs_per_cell);
+
+ FullMatrix<double> ui_ve_matrix (dofs_per_cell, dofs_per_cell);
+ FullMatrix<double> ue_ve_matrix (dofs_per_cell, dofs_per_cell);
+
+ Vector<double> cell_vector (dofs_per_cell);
+
+ typename DoFHandler<dim>::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (;cell!=endc; ++cell)
+ {
+ ui_vi_matrix = 0;
+ cell_vector = 0;
+
+ fe_v.reinit (cell);
+
+ dg.assemble_cell_term(fe_v,
+ ui_vi_matrix,
+ cell_vector);
+
+ cell->get_dof_indices (dofs);
+
+ for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+ {
+ typename DoFHandler<dim>::face_iterator face=
+ cell->face(face_no);
+
+ // Case a)
+ if (face->at_boundary())
+ {
+ fe_v_face.reinit (cell, face_no);
+
+ dg.assemble_boundary_term(fe_v_face,
+ ui_vi_matrix,
+ cell_vector);
+ }
+ else
+ {
+ Assert (cell->neighbor(face_no).state() == IteratorState::valid,
+ ExcInternalError());
+ typename DoFHandler<dim>::cell_iterator neighbor=
+ cell->neighbor(face_no);
+ // Case b), we decide that there
+ // are finer cells as neighbors
+ // by asking the face, whether it
+ // has children. if so, then
+ // there must also be finer cells
+ // which are children or farther
+ // offsprings of our neighbor.
+ if (face->has_children())
+ {
+ // We need to know, which of
+ // the neighbors faces points
+ // in the direction of our
+ // cell. Using the @p
+ // neighbor_face_no function
+ // we get this information
+ // for both coarser and
+ // non-coarser neighbors.
+ const unsigned int neighbor2=
+ cell->neighbor_face_no(face_no);
+
+ // Now we loop over all
+ // subfaces, i.e. the
+ // children and possibly
+ // grandchildren of the
+ // current face.
+ for (unsigned int subface_no=0;
+ subface_no<face->number_of_children(); ++subface_no)
+ {
+ // To get the cell behind
+ // the current subface we
+ // can use the @p
+ // neighbor_child_on_subface
+ // function. it takes
+ // care of all the
+ // complicated situations
+ // of anisotropic
+ // refinement and
+ // non-standard faces.
+ typename DoFHandler<dim>::cell_iterator neighbor_child
+ = cell->neighbor_child_on_subface (face_no, subface_no);
+ Assert (!neighbor_child->has_children(), ExcInternalError());
+
+ // The remaining part of
+ // this case is
+ // unchanged.
+ ue_vi_matrix = 0;
+ ui_ve_matrix = 0;
+ ue_ve_matrix = 0;
+
+ fe_v_subface.reinit (cell, face_no, subface_no);
+ fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
+
+ dg.assemble_face_term2(fe_v_subface,
+ fe_v_face_neighbor,
+ ui_vi_matrix,
+ ue_vi_matrix,
+ ui_ve_matrix,
+ ue_ve_matrix);
+
+ neighbor_child->get_dof_indices (dofs_neighbor);
+
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ for (unsigned int j=0; j<dofs_per_cell; ++j)
+ {
+ system_matrix.add(dofs[i], dofs_neighbor[j],
+ ue_vi_matrix(i,j));
+ system_matrix.add(dofs_neighbor[i], dofs[j],
+ ui_ve_matrix(i,j));
+ system_matrix.add(dofs_neighbor[i], dofs_neighbor[j],
+ ue_ve_matrix(i,j));
+ }
+ }
+ }
+ else
+ {
+ // Case c). We simply ask,
+ // whether the neighbor is
+ // coarser. If not, then it
+ // is neither coarser nor
+ // finer, since finer
+ // neighbor would have been
+ // reated above withz case
+ // b). Of all the cases with
+ // thesame refinement
+ // situation of our cell and
+ // the neighbor we want to
+ // treat only one half, so
+ // that each face is
+ // considered only once. Thus
+ // we have the additional
+ // condition, that the cell
+ // with the lower index does
+ // the work. In the rare case
+ // that both cells have the
+ // same index, the cell with
+ // lower level is selected.
+ if (!cell->neighbor_is_coarser(face_no) &&
+ (neighbor->index() > cell->index() ||
+ (neighbor->level() < cell->level() &&
+ neighbor->index() == cell->index())))
+ {
+ // Here we know, that the
+ // neigbor is not coarser
+ // so we can use the
+ // usual @p
+ // neighbor_of_neighbor
+ // function. However, we
+ // could also use the
+ // more general @p
+ // neighbor_face_no
+ // function.
+ const unsigned int neighbor2=cell->neighbor_of_neighbor(face_no);
+
+ ue_vi_matrix = 0;
+ ui_ve_matrix = 0;
+ ue_ve_matrix = 0;
+
+ fe_v_face.reinit (cell, face_no);
+ fe_v_face_neighbor.reinit (neighbor, neighbor2);
+
+ dg.assemble_face_term2(fe_v_face,
+ fe_v_face_neighbor,
+ ui_vi_matrix,
+ ue_vi_matrix,
+ ui_ve_matrix,
+ ue_ve_matrix);
+
+ neighbor->get_dof_indices (dofs_neighbor);
+
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ for (unsigned int j=0; j<dofs_per_cell; ++j)
+ {
+ system_matrix.add(dofs[i], dofs_neighbor[j],
+ ue_vi_matrix(i,j));
+ system_matrix.add(dofs_neighbor[i], dofs[j],
+ ui_ve_matrix(i,j));
+ system_matrix.add(dofs_neighbor[i], dofs_neighbor[j],
+ ue_ve_matrix(i,j));
+ }
+ }
+
+ // We do not need to consider
+ // case d), as those faces
+ // are treated 'from the
+ // other side within case b).
+ }
+ }
+ }
+
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ for (unsigned int j=0; j<dofs_per_cell; ++j)
+ system_matrix.add(dofs[i], dofs[j], ui_vi_matrix(i,j));
+
+ for (unsigned int i=0; i<dofs_per_cell; ++i)
+ right_hand_side(dofs[i]) += cell_vector(i);
+ }
+}
+
+
+ // @sect3{Solver}
+ //
+ // For this simple problem we use the simple
+ // Richardson iteration again. The solver is
+ // completely unaffected by our anisotropic
+ // changes.
+template <int dim>
+void DGMethod<dim>::solve (Vector<double> &solution)
+{
+ SolverControl solver_control (1000, 1e-12, false, false);
+ SolverRichardson<> solver (solver_control);
+
+ PreconditionBlockSSOR<SparseMatrix<double> > preconditioner;
+
+ preconditioner.initialize(system_matrix, fe.dofs_per_cell);
+
+ solver.solve (system_matrix, solution, right_hand_side,
+ preconditioner);
+}
+
+
+ // @sect3{Refinement}
+ //
+ // We refine the grid according to the same
+ // simple refinement criterion used in step-12,
+ // namely an approximation to the
+ // gradient of the solution.
+template <int dim>
+void DGMethod<dim>::refine_grid ()
+{
+ Vector<float> gradient_indicator (triangulation.n_active_cells());
+
+ // We approximate the gradient,
+ DerivativeApproximation::approximate_gradient (mapping,
+ dof_handler,
+ solution2,
+ gradient_indicator);
+
+ // and scale it to obtain an error indicator.
+ typename DoFHandler<dim>::active_cell_iterator
+ cell = dof_handler.begin_active(),
+ endc = dof_handler.end();
+ for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
+ gradient_indicator(cell_no)*=std::pow(cell->diameter(), 1+1.0*dim/2);
+ // Then we use this indicator to flag the 30
+ // percent of the cells with highest error
+ // indicator to be refined.
+ GridRefinement::refine_and_coarsen_fixed_number (triangulation,
+ gradient_indicator,
+ 0.3, 0.1);
+ // Now the refinement flags are set for those
+ // cells with a large error indicator. If
+ // nothing is done to change this, those
+ // cells will be refined isotropically. If
+ // the @p anisotropic flag given to this
+ // function is set, we now call the
+ // set_anisotropic_flags() function, which
+ // uses the jump indicator to reset some of
+ // the refinement flags to anisotropic
+ // refinement.
+ if (anisotropic)
+ set_anisotropic_flags();
+ // Now execute the refinement considering
+ // anisotropic as well as isotropic
+ // refinement flags.
+ triangulation.execute_coarsening_and_refinement ();
+}
+
+ // Once an error indicator has been evaluated
+ // and the cells with largerst error are
+ // flagged for refinement we want to loop over
+ // the flagged cells again to decide whether
+ // they need isotropic refinemnt or whether
+ // anisotropic refinement is more
+ // appropriate. This is the anisotropic jump
+ // indicator explained in the introduction.
+template <int dim>
+void DGMethod<dim>::set_anisotropic_flags ()
+{
+ // We want to evaluate the jump over faces of
+ // the flagged cells, so we need some objects
+ // to evaluate values of the solution on
+ // faces.
+ UpdateFlags face_update_flags
+ = UpdateFlags(update_values | update_JxW_values);
+
+ FEFaceValues<dim> fe_v_face (mapping, fe, face_quadrature, face_update_flags);
+ FESubfaceValues<dim> fe_v_subface (mapping, fe, face_quadrature, face_update_flags);
+ FEFaceValues<dim> fe_v_face_neighbor (mapping, fe, face_quadrature, update_values);
+
+ // Now we need to loop over all active cells.
+ typename DoFHandler<dim>::active_cell_iterator cell=dof_handler.begin_active(),
+ endc=dof_handler.end();
+
+ for (; cell!=endc; ++cell)
+ // We only need to consider cells which are
+ // flaged for refinement.
+ if (cell->refine_flag_set())
+ {
+ Point<dim> jump;
+ Point<dim> area;
+
+ for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+ {
+ typename DoFHandler<dim>::face_iterator face = cell->face(face_no);
+
+ if (!face->at_boundary())
+ {
+ Assert (cell->neighbor(face_no).state() == IteratorState::valid, ExcInternalError());
+ typename DoFHandler<dim>::cell_iterator neighbor = cell->neighbor(face_no);
+
+ std::vector<double> u (fe_v_face.n_quadrature_points);
+ std::vector<double> u_neighbor (fe_v_face.n_quadrature_points);
+
+ // The four cases of different
+ // neighbor relations senn in
+ // the assembly routines are
+ // repeated much in the same
+ // way here.
+ if (face->has_children())
+ {
+ // The neighbor is refined.
+ // First we store the
+ // information, which of
+ // the neighbor's faces
+ // points in the direction
+ // of our current
+ // cell. This property is
+ // inherited to the
+ // children.
+ unsigned int neighbor2=cell->neighbor_face_no(face_no);
+ // Now we loop over all subfaces,
+ for (unsigned int subface_no=0; subface_no<face->number_of_children(); ++subface_no)
+ {
+ // get an iterator
+ // pointing to the cell
+ // behind the present
+ // subface...
+ typename DoFHandler<dim>::cell_iterator neighbor_child = cell->neighbor_child_on_subface(face_no,subface_no);
+ Assert (!neighbor_child->has_children(), ExcInternalError());
+ // ... and reinit the
+ // respective
+ // FEFaceValues und
+ // FESubFaceValues
+ // objects.
+ fe_v_subface.reinit (cell, face_no, subface_no);
+ fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
+ // We obtain the function values
+ fe_v_subface.get_function_values(solution2, u);
+ fe_v_face_neighbor.get_function_values(solution2, u_neighbor);
+ // as well as the
+ // quadrature weights,
+ // multiplied by the
+ // jacobian determinant.
+ const std::vector<double> &JxW = fe_v_subface.get_JxW_values ();
+ // Now we loop over all
+ // quadrature points
+ for (unsigned int x=0; x<fe_v_subface.n_quadrature_points; ++x)
+ {
+ // and integrate
+ // the absolute
+ // value of the
+ // jump of the
+ // solution,
+ // i.e. the
+ // absolute value
+ // of the
+ // difference
+ // between the
+ // function value
+ // seen from the
+ // current cell and
+ // the neighboring
+ // cell,
+ // respectively. We
+ // know, that the
+ // first two faces
+ // are orthogonal
+ // to the first
+ // coordinate
+ // direction on the
+ // unit cell, the
+ // second two faces
+ // are orthogonal
+ // to the second
+ // coordinate
+ // direction and so
+ // on, so we
+ // accumulate these
+ // values ito
+ // vectors with
+ // <code>dim</code>
+ // components.
+ jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
+ // We also sum up
+ // the scaled
+ // weights to
+ // obtain the
+ // measure of the
+ // face.
+ area[face_no/2]+=JxW[x];
+ }
+ }
+ }
+ else
+ {
+ if (!cell->neighbor_is_coarser(face_no))
+ {
+ // Our current cell and
+ // the neighbor have
+ // the same refinement
+ // along the face under
+ // consideration. Apart
+ // from that, we do
+ // much the same as
+ // with one of the
+ // subcells in the
+ // above case.
+ unsigned int neighbor2=cell->neighbor_of_neighbor(face_no);
+
+ fe_v_face.reinit (cell, face_no);
+ fe_v_face_neighbor.reinit (neighbor, neighbor2);
+
+ fe_v_face.get_function_values(solution2, u);
+ fe_v_face_neighbor.get_function_values(solution2, u_neighbor);
+
+ const std::vector<double> &JxW = fe_v_face.get_JxW_values ();
+
+ for (unsigned int x=0; x<fe_v_face.n_quadrature_points; ++x)
+ {
+ jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
+ area[face_no/2]+=JxW[x];
+ }
+ }
+ else //i.e. neighbor is coarser than cell
+ {
+ // Now the neighbor is
+ // actually
+ // coarser. This case
+ // is new, in that it
+ // did not occur in the
+ // assembly
+ // routine. Here, we
+ // have to consider it,
+ // but this is not
+ // overly
+ // complicated. We
+ // simply use the @p
+ // neighbor_of_coarser_neighbor
+ // function, which
+ // again takes care of
+ // anisotropic
+ // refinement and
+ // non-standard face
+ // orientation by
+ // itself.
+ std::pair<unsigned int,unsigned int> neighbor_face_subface
+ = cell->neighbor_of_coarser_neighbor(face_no);
+ Assert (neighbor_face_subface.first<GeometryInfo<dim>::faces_per_cell, ExcInternalError());
+ Assert (neighbor_face_subface.second<neighbor->face(neighbor_face_subface.first)->number_of_children(),
+ ExcInternalError());
+ Assert (neighbor->neighbor_child_on_subface(neighbor_face_subface.first, neighbor_face_subface.second)
+ == cell, ExcInternalError());
+
+ fe_v_face.reinit (cell, face_no);
+ fe_v_subface.reinit (neighbor, neighbor_face_subface.first,
+ neighbor_face_subface.second);
+
+ fe_v_face.get_function_values(solution2, u);
+ fe_v_subface.get_function_values(solution2, u_neighbor);
+
+ const std::vector<double> &JxW = fe_v_face.get_JxW_values ();
+
+ for (unsigned int x=0; x<fe_v_face.n_quadrature_points; ++x)
+ {
+ jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
+ area[face_no/2]+=JxW[x];
+ }
+ }
+ }
+ }
+ }
+ // Now we analyze the size of the mean
+ // jumps, which we get dividing the
+ // jumps by the measure of the
+ // respective faces.
+ double average_jumps[dim];
+ double sum_of_average_jumps=0.;
+ for (unsigned int i=0; i<dim; ++i)
+ {
+ average_jumps[i] = jump(i)/area(i);
+ sum_of_average_jumps += average_jumps[i];
+ }
+
+ // Now we loop over the <code>dim</code>
+ // coordinate directions of the unit
+ // cell and compare the average jump
+ // over the faces orthogional to that
+ // direction with the average jumnps
+ // over faces orthogonal to the
+ // remining direction(s). If the first
+ // is larger than the latter by a given
+ // factor, we refine only along hat
+ // axis. Otherwise we leave the
+ // refinement flag unchanged, resulting
+ // in isotropic refinement.
+ for (unsigned int i=0; i<dim; ++i)
+ if (average_jumps[i] > anisotropic_threshold_ratio*(sum_of_average_jumps-average_jumps[i]))
+ cell->set_refine_flag(RefinementCase<dim>::cut_axis(i));
+ }
+}
+
+ // @sect3{The Rest}
+ //
+ // The remaining part of the program is again
+ // unmodified. Only the creation of the
+ // original triangulation is changed in order
+ // to reproduce the new domain.
+template <int dim>
+void DGMethod<dim>::output_results (const unsigned int cycle) const
+{
+ std::string refine_type;
+ if (anisotropic)
+ refine_type=".aniso";
+ else
+ refine_type=".iso";
+
+ std::string filename = "grid-";
+ filename += ('0' + cycle);
+ Assert (cycle < 10, ExcInternalError());
+
+ filename += refine_type + ".eps";
+ std::cout << "Writing grid to <" << filename << ">..." << std::endl;
+ std::ofstream eps_output (filename.c_str());
+
+ GridOut grid_out;
+ grid_out.write_eps (triangulation, eps_output);
+
+ filename = "grid-";
+ filename += ('0' + cycle);
+ Assert (cycle < 10, ExcInternalError());
+
+ filename += refine_type + ".gnuplot";
+ std::cout << "Writing grid to <" << filename << ">..." << std::endl;
+ std::ofstream gnuplot_grid_output (filename.c_str());
+
+ grid_out.write_gnuplot (triangulation, gnuplot_grid_output);
+
+ filename = "sol-";
+ filename += ('0' + cycle);
+ Assert (cycle < 10, ExcInternalError());
+
+ filename += refine_type + ".gnuplot";
+ std::cout << "Writing solution to <" << filename << ">..."
+ << std::endl;
+ std::ofstream gnuplot_output (filename.c_str());
+
+ DataOut<dim> data_out;
+ data_out.attach_dof_handler (dof_handler);
+ data_out.add_data_vector (solution2, "u");
+
+ data_out.build_patches (degree);
+
+ data_out.write_gnuplot(gnuplot_output);
+}
+
+
+template <int dim>
+void DGMethod<dim>::run ()
+{
+ for (unsigned int cycle=0; cycle<6; ++cycle)
+ {
+ std::cout << "Cycle " << cycle << ':' << std::endl;
+
+ if (cycle == 0)
+ {
+ // Create the rectangular domain.
+ Point<dim> p1,p2;
+ p1(0)=0;
+ p1(0)=-1;
+ for (unsigned int i=0; i<dim; ++i)
+ p2(i)=1.;
+ // Adjust the number of cells in
+ // different directions to obtain
+ // completely isotropic cells for the
+ // original mesh.
+ std::vector<unsigned int> repetitions(dim,1);
+ repetitions[0]=2;
+ GridGenerator::subdivided_hyper_rectangle (triangulation,
+ repetitions,
+ p1,
+ p2);
+
+ triangulation.refine_global (5-dim);
+ }
+ else
+ refine_grid ();
+
+
+ std::cout << " Number of active cells: "
+ << triangulation.n_active_cells()
+ << std::endl;
+
+ setup_system ();
+
+ std::cout << " Number of degrees of freedom: "
+ << dof_handler.n_dofs()
+ << std::endl;
+
+ Timer assemble_timer;
+ assemble_system2 ();
+ std::cout << "Time of assemble_system2: "
+ << assemble_timer()
+ << std::endl;
+ solve (solution2);
+
+ output_results (cycle);
+ }
+}
+
+int main ()
+{
+ try
+ {
+ // If you want to run the program in 3D,
+ // simply change the following line to
+ // <code>const unsigned int dim = 3;</code>.
+ const unsigned int dim = 2;
+
+ {
+ // First, we perform a run with
+ // isotropic refinement.
+ std::cout << "Performing a " << dim << "D run with isotropic refinement..." << std::endl
+ << "------------------------------------------------" << std::endl;
+ DGMethod<dim> dgmethod_iso(false);
+ dgmethod_iso.run ();
+ }
+
+ {
+ // Now we do a second run, this time
+ // with anisotropic refinement.
+ std::cout << std::endl
+ << "Performing a " << dim << "D run with anisotropic refinement..." << std::endl
+ << "--------------------------------------------------" << std::endl;
+ DGMethod<dim> dgmethod_aniso(true);
+ dgmethod_aniso.run ();
+ }
+ }
+ catch (std::exception &exc)
+ {
+ std::cerr << std::endl << std::endl
+ << "----------------------------------------------------"
+ << std::endl;
+ std::cerr << "Exception on processing: " << std::endl
+ << exc.what() << std::endl
+ << "Aborting!" << std::endl
+ << "----------------------------------------------------"
+ << std::endl;
+ return 1;
+ }
+ catch (...)
+ {
+ std::cerr << std::endl << std::endl
+ << "----------------------------------------------------"
+ << std::endl;
+ std::cerr << "Unknown exception!" << std::endl
+ << "Aborting!" << std::endl
+ << "----------------------------------------------------"
+ << std::endl;
+ return 1;
+ };
+
+ return 0;
+}
+
+
// refined. loop over
// all sub faces
for (unsigned int subface_no=0;
- subface_no<GeometryInfo<dim>::subfaces_per_face;
+ subface_no<GeometryInfo<dim>::max_children_per_face;
++subface_no)
{
fe_subface_values.reinit (cell, face_no, subface_no);
// neighbors is computed here.
std::vector<typename DoFHandler<dim>::active_cell_iterator> active_neighbors;
active_neighbors.reserve (GeometryInfo<dim>::faces_per_cell *
- GeometryInfo<dim>::subfaces_per_face);
+ GeometryInfo<dim>::max_children_per_face);
// Well then, after all these
// preliminaries, lets start the
--- /dev/null
+1[DONE] rename RefineCase -> RefinementCase
+
+2[DONE] rename FaceRefineCase -> FaceRefinementCase
+
+3[DONE] move FaceRefinementCase into internal namespace
+ [2,3:DONE: FaceRefineCase has been renamed to internal::SubfaceCase which
+ is now derived from internal::SubfacePossibilities in analogy to
+ RefinementCase and RefinementPossibilities]
+
+4[DONE] move global anisotropic_refinement parameter to Triangulation,
+ throw exceptions when aniso data is required but not implemented
+
+5 one or two tests on aniso for continuous FE in 2d.
+
+6 make the DG tests in tests/aniso/ work
+
+7[DONE] add docu to FaceRefinementFlags.
+ "R: I think it is already there! W: What I meant is that the
+ documentation about which cases occur is there, but the explanation
+ why it is these cases and exactly these is missing. This was the
+ question about invariants. If you could add a couple of sentences that
+ would be helpful.
+
+8[DONE] modify FaceRefinementFlags according to the changes in RefinementFlags
+
+9[DONE] add some docu to the neighbor_is_coarser function like
+ "T: In an anisotropic setting, a cell con only be coarser than another
+ one at a given face, not on a general basis. The face of the finer
+cell is contained in the corresponding face of the coarser cell, the
+finer face is either a child or a grandchild of the coarser face. Of
+coarse we could try to add some sentences explaining this. By the way:
+consider two cells neighboring cells on an initial grid. We can NOT
+refine the cells in a way that one cell refines a face with cut_x and
+the neighboring one refines the same face with
+cut_y. Triangulation<dim>::prepare_coarsening_and_refinement() takes
+care of this situation and ensures that each face of a refined cell is
+completely contained in a single face of neighboring cells."
+
+10[DONE] setup a (doxygen) module for anisotropic, it should
+ "W: list the relevant classes, links to step-30, and links to a
+paper reference of the relevant algorithms. If we had a module
+anisotropic, we could for example list the RefinementCase and
+GeometryInfo, the Triangulation. Note, that classes can be part
+of several modules so the module would list everything that is related to
+anisotropic refinement"
+
+11[DONE] Swap arguments to FE::get_{restriction,prolongation}_matrix and
+give the refinement flag a default value to keep things compatible.
+
+12[DONE] Document FiniteElement::restriction and FiniteElement::prolongation
+indices and layout
+
+13[DONE] Modify documentation for changed FETools functions:
+ FETools::compute_{embedding,projection}_matrices
+
+14[DONE] Move the code that initializes the sizes of the
+FiniteElement::restriction and FiniteElement::prolongation members
+from individual FE implementations to a function in the base class,
+since it is always the same.
+
+15[DONE] doc/news/anisotropic.html:
+ I guess you started this file before we switched to using doxygen for
+ the changes file: It is no longer necessary to do things like
+ <code class="class">CLASS</code> :: <code
+ class="member">MEMBER</code>. Since we run the changes.h file through
+ doxygen, it will automatically be linked to the right function if you
+ omit all the HTML stuff. Simply use the style in changes.h
+
+16[DONE] deal.II/source/grid/tria.cc:
+ In this file, you now have code like this:
+ ------------------------------
+ + Point<dim> new_bound=boundary[face->boundary_indicator()]
+ +#if deal_II_dimension == 2
+ + ->get_new_point_on_line (face);
+ +#else
+ + ->get_new_point_on_quad (face);
+ +#endif
+ ------------------------------
+ We've tried to avoid this because we always thought that eventually we
+ may want to go to a scheme where each file is only compiled once for
+ all space dimensions at the same time, by simply deleting all the #if
+ deal_II_dimension lines. This isn't going to work here. Would you mind
+ changing this somehow? I guess one way might be to give the Boundary
+ base class a method get_new_point_on_face and let it call either of
+ the two functions above.
+
+16a[DONE] As a sidenote: this (and a great number of other) variables could well
+ have been made const, to allow the compiler to optimize and make it
+ clear to the reader that no further assignments are happening below.
+
+17 changes to Mapping*, FEValuesBase:
+ Can these be committed separately? I forgot what we said about the
+ name jacobian_grad -- I think we should settle on 'hessian' as unified
+ by Guido a while back. Are there any testcases that test the new
+ functionality?
+
+18[DONE] deal.II/include/fe/fe.h:
+ Add a comment to restriction_is_implemented() that it tests the stronger
+ requirement that the element does not only implement isotropic
+ restriction as tested by the isotropic_restriction_is_implemented()
+ function, but also anisotropic. Same for prolongation.
+
+19[DONE] deal.II/include/numerics/derivative_approximation.h:
+ The new function get_active_neighbors() would appear to be generally
+ useful. Could it be moved into the GridTools class? There are already
+ a few similar functions there.
+19a Could be committed separately.
+
+20 deal.II/include/grid/tria_accessor.h:
+20a[DONE] The new function neighbor_is_coarser_internal() returns two values,
+ one as return value and one as reference argument. I find this
+ weird. Please let it return either a std::pair<...>
+ [20a DONE: The neighbor_is_coarser_internal has been replaced by a
+ new neighbor_of_coarser_internal function with simple interface]
+
+20b[DONE] In the functions flag_for_*_refinement(), make input arguments const.
+
+20c[DONE] iso_set_children(): please spell it out as "isotropic". We'll forget
+ what "iso" stood for once the anisotropic work has become normal for
+ us. Same for iso_child() etc.
+
+20d[DONE] middle_vertex_index(): please make it return an unsigned int and
+ return numbers::invalid_unsigned_int in case of an error. This is how
+ we do it all through the library.
+
+20e[DONE] there are several refine_case, clear_refine_case, set_refine_case
+ functions. please rename them to use refinement_case instead of
+ refine_case to match the name of the argument type.
+
+21[DONE] deal.II/include/grid/tria_accessor.templates.h:
+ many of the new functions in this file take input arguments that they
+ don't change but which are not marked as 'const'. please fix, they're
+ easy to find by searching for "(unsigned" or "(Refinement" for example.
+
+22[DONE] deal.II/include/grid/tria_levels.h:
+ please rename fields to refinement_case from refine_case. it would be
+ useful to also grep for any other occurrences of refine_case anywhere
+ left over.
+
+23[DONE] deal.II/include/grid/tria_objects.h:
+ in the documentation, use <code>...</code> instead of
+ <tt>...</tt>. More importantly, however, if you use a template
+ argument <dim> or <2> inside such a block, it needs to be written as
+ @<2@>