From c696c8203c478f0eb57b329fed600277ee29e4e6 Mon Sep 17 00:00:00 2001 From: hartmann Date: Tue, 8 Jul 2008 15:25:01 +0000 Subject: [PATCH] Merge branch_anisotropic to trunk: Extension of isotropic to anisotropic refinement. git-svn-id: https://svn.dealii.org/trunk@16430 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/base/include/base/geometry_info.h | 1209 ++- deal.II/base/include/base/qprojector.h | 64 +- deal.II/base/source/geometry_info.cc | 819 +- deal.II/base/source/quadrature.cc | 574 +- deal.II/deal.II/include/fe/fe.h | 189 +- deal.II/deal.II/include/fe/fe_dgp.h | 8 +- .../deal.II/include/fe/fe_dgp_nonparametric.h | 16 +- deal.II/deal.II/include/fe/fe_nedelec.h | 8 +- .../deal.II/include/fe/fe_poly.templates.h | 3 +- deal.II/deal.II/include/fe/fe_tools.h | 128 +- deal.II/deal.II/include/fe/fe_values.h | 91 + deal.II/deal.II/include/fe/mapping.h | 14 +- .../deal.II/include/fe/mapping_cartesian.h | 4 +- deal.II/deal.II/include/fe/mapping_q.h | 4 +- deal.II/deal.II/include/fe/mapping_q1.h | 62 +- deal.II/deal.II/include/grid/grid_tools.h | 79 +- deal.II/deal.II/include/grid/tria.h | 170 +- deal.II/deal.II/include/grid/tria_accessor.h | 562 +- .../include/grid/tria_accessor.templates.h | 520 +- deal.II/deal.II/include/grid/tria_levels.h | 32 +- deal.II/deal.II/include/grid/tria_object.h | 2 + deal.II/deal.II/include/grid/tria_objects.h | 206 +- .../include/multigrid/mg_transfer.templates.h | 4 +- .../numerics/derivative_approximation.h | 2 +- deal.II/deal.II/source/dofs/dof_accessor.cc | 11 +- deal.II/deal.II/source/dofs/dof_tools.cc | 76 +- deal.II/deal.II/source/fe/fe.cc | 197 +- deal.II/deal.II/source/fe/fe_abf.cc | 34 +- deal.II/deal.II/source/fe/fe_dgp.cc | 13 +- deal.II/deal.II/source/fe/fe_dgp_monomial.cc | 15 +- .../deal.II/source/fe/fe_dgp_nonparametric.cc | 33 +- deal.II/deal.II/source/fe/fe_dgq.cc | 25 +- deal.II/deal.II/source/fe/fe_nedelec.cc | 61 +- deal.II/deal.II/source/fe/fe_nedelec_1d.cc | 2 +- deal.II/deal.II/source/fe/fe_nedelec_2d.cc | 2 +- deal.II/deal.II/source/fe/fe_nedelec_3d.cc | 2 +- deal.II/deal.II/source/fe/fe_poly_tensor.cc | 3 +- deal.II/deal.II/source/fe/fe_q.cc | 34 +- .../deal.II/source/fe/fe_q_hierarchical.cc | 34 +- .../deal.II/source/fe/fe_raviart_thomas.cc | 48 +- .../source/fe/fe_raviart_thomas_nodal.cc | 24 +- deal.II/deal.II/source/fe/fe_system.cc | 186 +- deal.II/deal.II/source/fe/fe_tools.cc | 399 +- deal.II/deal.II/source/fe/fe_values.cc | 105 +- .../deal.II/source/fe/mapping_cartesian.cc | 72 +- deal.II/deal.II/source/fe/mapping_q.cc | 23 +- deal.II/deal.II/source/fe/mapping_q1.cc | 194 +- .../deal.II/source/grid/grid_refinement.cc | 40 +- deal.II/deal.II/source/grid/grid_tools.cc | 20 +- deal.II/deal.II/source/grid/intergrid_map.cc | 16 +- deal.II/deal.II/source/grid/tria.cc | 9564 ++++++++++++----- deal.II/deal.II/source/grid/tria_accessor.cc | 665 +- deal.II/deal.II/source/grid/tria_levels.cc | 24 +- .../grid/tria_objects.all_dimensions.cc | 595 + deal.II/deal.II/source/grid/tria_objects.cc | 565 +- deal.II/deal.II/source/hp/dof_handler.cc | 148 +- .../source/multigrid/mg_transfer_block.cc | 10 +- .../source/multigrid/mg_transfer_component.cc | 6 +- .../source/multigrid/mg_transfer_prebuilt.cc | 10 +- .../numerics/derivative_approximation.cc | 58 +- .../source/numerics/error_estimator.cc | 8 +- .../source/numerics/solution_transfer.cc | 17 +- .../deal.II/source/numerics/time_dependent.cc | 20 +- deal.II/doc/doxygen/deal.dox | 4 +- deal.II/doc/doxygen/tutorial/toc.html | 11 + deal.II/doc/news/anisotropic.html | 441 +- deal.II/doc/news/changes.h | 4 + deal.II/examples/step-12/step-12.cc | 11 +- deal.II/examples/step-28/step-28.cc | 2 +- deal.II/examples/step-30/Makefile | 156 + deal.II/examples/step-30/doc/intro.dox | 482 + deal.II/examples/step-30/doc/results.dox | 151 + .../step-30/doc/step-30.grid-3.aniso.png | Bin 0 -> 1354 bytes .../step-30/doc/step-30.sol-1.aniso.png | Bin 0 -> 2335 bytes .../step-30/doc/step-30.sol-1.iso.png | Bin 0 -> 2390 bytes .../step-30/doc/step-30.sol-5.aniso.png | Bin 0 -> 2254 bytes .../step-30/doc/step-30.sol-5.iso.png | Bin 0 -> 2112 bytes deal.II/examples/step-30/step-30.cc | 1196 +++ deal.II/examples/step-31/step-31.cc | 2 +- deal.II/examples/step-9/step-9.cc | 2 +- deal.II/todo | 144 + 81 files changed, 16009 insertions(+), 4726 deletions(-) create mode 100644 deal.II/deal.II/source/grid/tria_objects.all_dimensions.cc create mode 100644 deal.II/examples/step-30/Makefile create mode 100644 deal.II/examples/step-30/doc/intro.dox create mode 100644 deal.II/examples/step-30/doc/results.dox create mode 100644 deal.II/examples/step-30/doc/step-30.grid-3.aniso.png create mode 100644 deal.II/examples/step-30/doc/step-30.sol-1.aniso.png create mode 100644 deal.II/examples/step-30/doc/step-30.sol-1.iso.png create mode 100644 deal.II/examples/step-30/doc/step-30.sol-5.aniso.png create mode 100644 deal.II/examples/step-30/doc/step-30.sol-5.iso.png create mode 100644 deal.II/examples/step-30/step-30.cc create mode 100644 deal.II/todo diff --git a/deal.II/base/include/base/geometry_info.h b/deal.II/base/include/base/geometry_info.h index ea280e6b0d..79ca912a7c 100644 --- a/deal.II/base/include/base/geometry_info.h +++ b/deal.II/base/include/base/geometry_info.h @@ -2,7 +2,7 @@ // $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 @@ -20,6 +20,736 @@ 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 + * RefinementPossibilities@<1@>, + * RefinementPossibilities@<2@>, and + * RefinementPossibilities@<3@>. + * + * @ingroup aniso + * @author Ralf Hartmann, 2005, Wolfgang Bangerth, 2007 + */ +template +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 + * isotropic_refinement + * denotes isotropic refinement + * in the space dimension + * selected by the template + * argument of this class. + */ + enum Possibilities + { + no_refinement= 0, + + isotropic_refinement = static_cast(-1) + }; +}; + + + +/** + * A class that provides possible choices for isotropic and + * anisotropic refinement flags in the current space dimension. + * + * This specialization is used for dim=1, 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 + * isotropic_refinement + * 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 dim=2, 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 + * isotropic_refinement + * 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 dim=3, 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 + * isotropic_refinement + * 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 dim dimensions (for example, + * for a line dim=1 in whatever space dimension we are, + * for a quad dim=2, 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 +class RefinementCase : public RefinementPossibilities +{ + 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::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 + * switch + * (refinement_flag)... case + * RefinementCase::cut_x: + * ... , which can be + * written as switch + * (static_cast@(refinement_flag). 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 + * cut_x, then the + * returned value will be + * cut_y; if the + * current value is + * isotropic_refinement + * then the result will be + * no_refinement; + * etc. + */ + RefinementCase operator ~ () const; + + + /** + * Return the flag that + * corresponds to cutting a cell + * along the axis given as + * argument. For example, if + * i=0 then the + * returned value is + * RefinementPossibilities::cut_x. + */ + 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 dim=1 and dim=2 they + * correspond to the cases given in + * RefinementPossibilities@. However, + * SubfacePossibilities@<3@> includes the refinement + * cases of RefinementPossibilities@<2@>, 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 + * SubfacePossibilities@<1@>, + * SubfacePossibilities@<2@> and + * SubfacePossibilities@<3@>. + * + * @ingroup aniso + * @author Tobias Leicht 2007, Ralf Hartmann, 2008 + */ + template + struct SubfacePossibilities + { + /** + * Possible cases of faces + * being subdivided into + * subface. + */ + enum Possibilities + { + case_none = 0, + + case_isotropic = static_cast(-1) + }; + }; + + +/** + * A class that provides all possible situations a face (in the + * current space dimension @p dim) might be subdivided into + * subfaces. + * + * For dim=0 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 dim=1 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 dim=2, where it offers + * the following possibilities: a face (line) being refined + * (case_x) or not refined (case_no). + * + * @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 * + * (case_x) or not + * refined + * (case_no). + */ + 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, (case_x + * or (case_y), and in both directions + * (case_x which corresponds to + * (case_isotropic). 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 + * cut_x and afterwards the left child is again refined + * with cut_y, 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 cut_x and the other hex refines + * that face with cut_y. 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 + class SubfaceCase : public SubfacePossibilities + { + 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::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 + * switch + * (subface_case)... case + * SubfaceCase@::case_x: + * ... , which can be + * written as switch + * (static_cast@(subface_case). 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 class GeometryInfo; @@ -35,35 +765,50 @@ template 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. @@ -451,19 +1196,20 @@ struct GeometryInfo<0> * *

Children

* - * 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 @@ -503,6 +1249,107 @@ struct GeometryInfo<0> * orientation as additional argument to * GeometryInfo<3>::child_cell_on_face). * + * 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 + * GeometryInfo<3>::child_cell_on_face function. + * *

Coordinate systems

* * We define the following coordinate system for the explicit coordinates of @@ -539,28 +1386,43 @@ struct GeometryInfo<0> * 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 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::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::max_children_per_cell; /** * Number of vertices of a cell. @@ -672,7 +1534,6 @@ struct GeometryInfo */ static const unsigned int dx_to_deal[vertices_per_cell]; - /** * This field stores for each vertex * to which faces it belongs. In any @@ -684,7 +1545,88 @@ struct GeometryInfo * 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 ref_case. + */ + static unsigned int n_children(const RefinementCase &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 &subface_case); + + /** + * Given a face on the reference + * element with a + * internal::SubfaceCase@ + * @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 + * internal::SubfaceCase@<3@>::cut_xy + * the ratio is 1/4 for each of + * the subfaces. + */ + static double subface_ratio(const internal::SubfaceCase &subface_case, + const unsigned int subface_no); + + /** + * Given a cell refined with the + * RefinementCase + * @p cell_refinement_case + * return the + * SubfaceCase of + * the @p face_no th face. + */ + static RefinementCase face_refinement_case( + const RefinementCase &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 min_cell_refinement_case_for_face_refinement( + const RefinementCase &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 &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 min_cell_refinement_case_for_line_refinement(const unsigned int line_no); + /** * This field stores which child * cells are adjacent to a @@ -740,12 +1682,23 @@ struct GeometryInfo * 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, face_ref_case, + * 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 &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 &face_refinement_case = RefinementCase::isotropic_refinement); /** * Map line vertex number to cell @@ -921,7 +1874,7 @@ struct GeometryInfo * children, return any one of * their indices. The result is * always less than - * GeometryInfo::children_per_cell. + * GeometryInfo::max_children_per_cell. * * The order of child cells is described * the general documentation of this @@ -944,7 +1897,7 @@ struct GeometryInfo * child. */ static Point cell_to_child_coordinates (const Point &p, - const unsigned int child_index); + const unsigned int child_index); /** * The reverse function to the @@ -1076,6 +2029,14 @@ struct GeometryInfo double, << "The coordinates must satisfy 0 <= x_i <= 1, " << "but here we have x_i=" << arg1); + + /** + * Exception + */ + DeclException3 (ExcInvalidSubface, + int, int, int, + << "RefinementCase " << arg1 << ": face " << arg2 + << " has no subface " << arg3); }; @@ -1116,6 +2077,165 @@ const unsigned int GeometryInfo<4>::opposite_face[faces_per_cell]; /* -------------- inline functions ------------- */ +namespace internal +{ + + template + inline + SubfaceCase::SubfaceCase (const typename SubfacePossibilities::Possibilities subface_possibility) + : + value (subface_possibility) + {} + + + template + inline + SubfaceCase::operator unsigned char () const + { + return value; + } + + +} // namespace internal + + +template +inline +RefinementCase +RefinementCase::cut_axis (const unsigned int) +{ + Assert (false, ExcInternalError()); + return static_cast(-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 +inline +RefinementCase::RefinementCase (const typename RefinementPossibilities::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::isotropic_refinement) == + refinement_case, + ExcInvalidRefinementCase (refinement_case)); +} + + + +template +inline +RefinementCase::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::isotropic_refinement) == + refinement_case, + ExcInvalidRefinementCase (refinement_case)); +} + + + +template +inline +RefinementCase::operator unsigned char () const +{ + return value; +} + + + +template +inline +RefinementCase +RefinementCase::operator | (const RefinementCase &r) const +{ + return RefinementCase(value | r.value); +} + + + +template +inline +RefinementCase +RefinementCase::operator & (const RefinementCase &r) const +{ + return RefinementCase(value & r.value); +} + + + +template +inline +RefinementCase +RefinementCase::operator ~ () const +{ + return RefinementCase((~value) & RefinementPossibilities::isotropic_refinement); +} + + + + +template +inline +unsigned int +RefinementCase::memory_consumption () +{ + return sizeof(RefinementCase); +} + + + + template <> inline @@ -1232,8 +2352,8 @@ Point GeometryInfo::cell_to_child_coordinates (const Point &p, const unsigned int child_index) { - Assert (child_index < GeometryInfo::children_per_cell, - ExcIndexRange (child_index, 0, GeometryInfo::children_per_cell)); + Assert (child_index < GeometryInfo::max_children_per_cell, + ExcIndexRange (child_index, 0, GeometryInfo::max_children_per_cell)); return 2*p - unit_cell_vertex(child_index); } @@ -1246,8 +2366,8 @@ Point GeometryInfo::child_to_cell_coordinates (const Point &p, const unsigned int child_index) { - Assert (child_index < GeometryInfo::children_per_cell, - ExcIndexRange (child_index, 0, GeometryInfo::children_per_cell)); + Assert (child_index < GeometryInfo::max_children_per_cell, + ExcIndexRange (child_index, 0, GeometryInfo::max_children_per_cell)); return (p + unit_cell_vertex(child_index))/2; } @@ -1320,6 +2440,7 @@ GeometryInfo<3>::is_inside_unit_cell (const Point<3> &p, (p[2] >= l) && (p[2] <= u); } + #endif // DOXYGEN DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/base/include/base/qprojector.h b/deal.II/base/include/base/qprojector.h index df3fdb3c72..16339e32d3 100644 --- a/deal.II/base/include/base/qprojector.h +++ b/deal.II/base/include/base/qprojector.h @@ -2,7 +2,7 @@ // $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 @@ -15,6 +15,7 @@ #include +#include DEAL_II_NAMESPACE_OPEN /*!@addtogroup Quadrature */ @@ -107,28 +108,34 @@ class QProjector const unsigned int face_no); /** - * Compute the quadrature points - * on the cell if the given - * quadrature formula is used on - * face face_no, subface - * number subface_no. + * Compute the quadrature points on the + * cell if the given quadrature formula is + * used on face face_no, subface + * number subface_no corresponding + * to RefineCase::Type + * ref_case. 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 > &q_points); + static void project_to_subface (const SubQuadrature &quadrature, + const unsigned int face_no, + const unsigned int subface_no, + std::vector > &q_points, + const RefinementCase &ref_case=RefinementCase::isotropic_refinement); /** - * Compute the cell quadrature - * formula corresponding to using + * Compute the cell quadrature formula + * corresponding to using * quadrature on subface * subface_no of face - * face_no. + * face_no with + * RefinementCase + * ref_case. The last argument is + * only used in 3D. * * @note Only the points are * transformed. The quadrature @@ -136,9 +143,10 @@ class QProjector * of the original rule. */ static Quadrature - 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 &ref_case=RefinementCase::isotropic_refinement); /** * Take a face quadrature formula @@ -317,7 +325,7 @@ class QProjector * 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 @@ -325,6 +333,10 @@ class QProjector * one that has been * projected onto the faces) * has. + * + * Through the last argument + * anisotropic refinement can be + * respected. */ static DataSetDescriptor @@ -333,7 +345,8 @@ class QProjector 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 ref_case=internal::SubfaceCase::case_isotropic); /** * Conversion operator to an @@ -438,19 +451,22 @@ void QProjector<1>::project_to_subface (const Quadrature<0> &, const unsigned int, const unsigned int, - std::vector > &); + std::vector > &, + 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 > &q_points); + std::vector > &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 > &q_points); +QProjector<3>::project_to_subface (const Quadrature<2> &quadrature, + const unsigned int face_no, + const unsigned int subface_no, + std::vector > &q_points, + const RefinementCase<2> &face_ref_case); template <> Quadrature<1> diff --git a/deal.II/base/source/geometry_info.cc b/deal.II/base/source/geometry_info.cc index 0e006ca5c4..2b5ffb638d 100644 --- a/deal.II/base/source/geometry_info.cc +++ b/deal.II/base/source/geometry_info.cc @@ -2,7 +2,7 @@ // $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 @@ -17,9 +17,9 @@ DEAL_II_NAMESPACE_OPEN -template const unsigned int GeometryInfo::children_per_cell; +template const unsigned int GeometryInfo::max_children_per_cell; template const unsigned int GeometryInfo::faces_per_cell; -template const unsigned int GeometryInfo::subfaces_per_face; +template const unsigned int GeometryInfo::max_children_per_face; template const unsigned int GeometryInfo::vertices_per_cell; template const unsigned int GeometryInfo::vertices_per_face; template const unsigned int GeometryInfo::lines_per_face; @@ -131,21 +131,21 @@ const unsigned int GeometryInfo<3>::ucd_to_deal[GeometryInfo<3>::vertices_per_ce 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 <> @@ -163,21 +163,21 @@ const unsigned int GeometryInfo<3>::dx_to_deal[GeometryInfo<3>::vertices_per_cel 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 @@ -226,6 +226,473 @@ const unsigned int GeometryInfo<4>::vertex_to_face { invalid_unsigned_int, invalid_unsigned_int, invalid_unsigned_int, invalid_unsigned_int }}; +template +unsigned int +GeometryInfo::n_children(const RefinementCase &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::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::max_children_per_face; + break; + case internal::SubfaceCase::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::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::max_children_per_face; + break; + case internal::SubfaceCase::case_x: + case internal::SubfaceCase::case_y: + ratio=0.5; + break; + case internal::SubfaceCase::case_xy: + case internal::SubfaceCase::case_x1y2y: + case internal::SubfaceCase::case_y1x2x: + ratio=0.25; + break; + case internal::SubfaceCase::case_x1y: + case internal::SubfaceCase::case_y1x: + if (subface_no<2) + ratio=0.25; + else + ratio=0.5; + break; + case internal::SubfaceCase::case_x2y: + case internal::SubfaceCase::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::isotropic_refinement+1, + ExcIndexRange(cell_refinement_case, 0, RefinementCase::isotropic_refinement+1)); + Assert(face_no::faces_per_cell, + ExcIndexRange(face_no, 0, GeometryInfo::faces_per_cell)); + + static const RefinementCase + ref_cases[RefinementCase::isotropic_refinement+1][GeometryInfo::faces_per_cell/2]= + {{RefinementCase::no_refinement, // no_refinement + RefinementCase::no_refinement}, + + {RefinementCase::no_refinement, + RefinementCase::cut_x}, + + {RefinementCase::cut_x, + RefinementCase::no_refinement}, + + {RefinementCase::cut_x, // cut_xy + RefinementCase::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::isotropic_refinement+1, + ExcIndexRange(cell_refinement_case, 0, RefinementCase::isotropic_refinement+1)); + Assert(face_no::faces_per_cell, + ExcIndexRange(face_no, 0, GeometryInfo::faces_per_cell)); + + static const RefinementCase + ref_cases[RefinementCase::isotropic_refinement+1][GeometryInfo::faces_per_cell/2]= + {{RefinementCase::no_refinement, // no_refinement + RefinementCase::no_refinement, + RefinementCase::no_refinement}, + + {RefinementCase::no_refinement, // cut_x + RefinementCase::cut_y, + RefinementCase::cut_x}, + + {RefinementCase::cut_x, // cut_y + RefinementCase::no_refinement, + RefinementCase::cut_y}, + + {RefinementCase::cut_x, // cut_xy + RefinementCase::cut_y, + RefinementCase::cut_xy}, + + {RefinementCase::cut_y, // cut_z + RefinementCase::cut_x, + RefinementCase::no_refinement}, + + {RefinementCase::cut_y, // cut_xz + RefinementCase::cut_xy, + RefinementCase::cut_x}, + + {RefinementCase::cut_xy, // cut_yz + RefinementCase::cut_x, + RefinementCase::cut_y}, + + {RefinementCase::cut_xy, // cut_xyz + RefinementCase::cut_xy, + RefinementCase::cut_xy}, + }; + + const RefinementCase ref_case=ref_cases[cell_refinement_case][face_no/2]; + + static const RefinementCase flip[4]= + {RefinementCase::no_refinement, + RefinementCase::cut_y, + RefinementCase::cut_x, + RefinementCase::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 + // face_rotation==face_orientation, + // 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::isotropic_refinement+1, + ExcIndexRange(cell_refinement_case, 0, RefinementCase::isotropic_refinement+1)); + Assert(line_no::lines_per_cell, + ExcIndexRange(line_no, 0, GeometryInfo::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::isotropic_refinement+1, + ExcIndexRange(cell_refinement_case, 0, RefinementCase::isotropic_refinement+1)); + Assert(line_no::lines_per_cell, + ExcIndexRange(line_no, 0, GeometryInfo::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 + cut_one[dim] = + {RefinementCase::cut_x, + RefinementCase::cut_y, + RefinementCase::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::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::isotropic_refinement+1, + ExcIndexRange(face_refinement_case, 0, RefinementCase::isotropic_refinement+1)); + Assert(face_no::faces_per_cell, + ExcIndexRange(face_no, 0, GeometryInfo::faces_per_cell)); + + if (face_refinement_case==RefinementCase::cut_x) + return (face_no/2) ? RefinementCase::cut_x : RefinementCase::cut_y; + else + return RefinementCase::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::isotropic_refinement+1, + ExcIndexRange(face_refinement_case, 0, RefinementCase::isotropic_refinement+1)); + Assert(face_no::faces_per_cell, + ExcIndexRange(face_no, 0, GeometryInfo::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 + // face_rotation==face_orientation, + // 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 std_face_ref = (face_orientation==face_rotation) ? flip[face_refinement_case] : face_refinement_case; + + static const RefinementCase face_to_cell[3][4]= + {{RefinementCase::no_refinement, // faces 0 and 1 + RefinementCase::cut_y, // cut_x in face 0 means cut_y for the cell + RefinementCase::cut_z, + RefinementCase::cut_yz}, + + {RefinementCase::no_refinement, // faces 2 and 3 (note that x and y are "exchanged on faces 2 and 3") + RefinementCase::cut_z, + RefinementCase::cut_x, + RefinementCase::cut_xz}, + + {RefinementCase::no_refinement, // faces 4 and 5 + RefinementCase::cut_x, + RefinementCase::cut_y, + RefinementCase::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::lines_per_cell, + ExcIndexRange(line_no, 0, GeometryInfo::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::lines_per_cell, + ExcIndexRange(line_no, 0, GeometryInfo::lines_per_cell)); + + static const RefinementCase ref_cases[6]= + {RefinementCase::cut_y, // lines 0 and 1 + RefinementCase::cut_x, // lines 2 and 3 + RefinementCase::cut_y, // lines 4 and 5 + RefinementCase::cut_x, // lines 6 and 7 + RefinementCase::cut_z, // lines 8 and 9 + RefinementCase::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, @@ -500,13 +967,15 @@ GeometryInfo::real_to_standard_face_line(const unsigned int line, 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::child_cell_on_face (const unsigned int 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::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 (faceRefinementCase::no_refinement, ExcMessage("Cell has no children.")); + Assert (face::n_children(face_ref_case) || + (subface==0 && face_ref_case==RefinementCase::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 flip[4]= + {RefinementCase::no_refinement, + RefinementCase::cut_y, + RefinementCase::cut_x, + RefinementCase::cut_xy}; + // for face_orientation, 'true' is the + // default value whereas for face_rotation, + // 'false' is standard. If + // face_rotation==face_orientation, + // then one of them is non-standard and we + // have to swap cut_x and cut_y, otherwise no + // change is necessary. + const RefinementCase 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::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; @@ -588,7 +1274,7 @@ 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); } @@ -705,7 +1391,7 @@ GeometryInfo::face_to_cell_vertices (const unsigned int face, const bool face_flip, const bool face_rotation) { - return child_cell_on_face(face, vertex, + return child_cell_on_face(RefinementCase::isotropic_refinement, face, vertex, face_orientation, face_flip, face_rotation); } @@ -740,6 +1426,7 @@ GeometryInfo::distance_to_unit_cell (const Point &p) return result; } + template class GeometryInfo<1>; template class GeometryInfo<2>; template class GeometryInfo<3>; diff --git a/deal.II/base/source/quadrature.cc b/deal.II/base/source/quadrature.cc index 319043f901..ea04435538 100644 --- a/deal.II/base/source/quadrature.cc +++ b/deal.II/base/source/quadrature.cc @@ -2,7 +2,7 @@ // $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 @@ -522,7 +522,8 @@ void QProjector<1>::project_to_subface (const Quadrature<0> &, const unsigned int, const unsigned int, - std::vector > &) + std::vector > &, + const RefinementCase<0> &) { Assert(false, ExcNotImplemented()); } @@ -534,7 +535,8 @@ void QProjector<2>::project_to_subface (const Quadrature<1> &quadrature, const unsigned int face_no, const unsigned int subface_no, - std::vector > &q_points) + std::vector > &q_points, + const RefinementCase<1> &) { const unsigned int dim=2; Assert (face_no<2*dim, ExcIndexRange (face_no, 0, 2*dim)); @@ -612,7 +614,8 @@ void QProjector<3>::project_to_subface (const Quadrature<2> &quadrature, const unsigned int face_no, const unsigned int subface_no, - std::vector > &q_points) + std::vector > &q_points, + const RefinementCase<2> &ref_case) { const unsigned int dim=3; Assert (face_no<2*dim, ExcIndexRange (face_no, 0, 2*dim)); @@ -620,153 +623,78 @@ QProjector<3>::project_to_subface (const Quadrature<2> &quadrature, 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::cut_x: + xi_scale=0.5; + xi_translation=subface_no%2 * 0.5; + break; + case RefinementCase::cut_y: + eta_scale=0.5; + eta_translation=subface_no%2 * 0.5; + break; + case RefinementCase::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(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(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(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(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(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(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> &) @@ -899,7 +827,7 @@ QProjector<2>::project_to_all_subfaces (const SubQuadrature &quadrature) const unsigned int n_points = quadrature.size(), n_faces = GeometryInfo::faces_per_cell, - subfaces_per_face = GeometryInfo::subfaces_per_face; + subfaces_per_face = GeometryInfo::max_children_per_face; // first fix quadrature points std::vector > q_points; @@ -940,7 +868,6 @@ Quadrature<3> QProjector<3>::project_to_all_subfaces (const SubQuadrature &quadrature) { const unsigned int dim = 3; - SubQuadrature q_reflected=reflect (quadrature); SubQuadrature q[8]= {quadrature, @@ -954,15 +881,15 @@ QProjector<3>::project_to_all_subfaces (const SubQuadrature &quadrature) const unsigned int n_points = quadrature.size(), n_faces = GeometryInfo::faces_per_cell, - subfaces_per_face = GeometryInfo::subfaces_per_face; + total_subfaces_per_face = 2 + 2 + 4; // first fix quadrature points std::vector > 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 > help(n_points); std::vector 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 @@ -973,24 +900,31 @@ QProjector<3>::project_to_all_subfaces (const SubQuadrature &quadrature) // project to each face and copy // results for (unsigned int face=0; face::cut_xy; + ref_case>=RefinementCase::cut_x; + --ref_case) + for (unsigned int subface=0; subface::n_children(RefinementCase(ref_case)); ++subface) + { + project_to_subface(q[mutation], face, subface, help, + RefinementCase(ref_case)); + std::copy (help.begin(), help.end(), + std::back_inserter (q_points)); + } // next copy over weights for (unsigned int face=0; face::cut_xy; + ref_case>=RefinementCase::cut_x; + --ref_case) + for (unsigned int subface=0; subface::n_children(RefinementCase(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(q_points, weights); @@ -998,13 +932,14 @@ QProjector<3>::project_to_all_subfaces (const SubQuadrature &quadrature) +// This function is not used in the library template Quadrature QProjector::project_to_child (const Quadrature &quadrature, const unsigned int child_no) { - Assert (child_no < GeometryInfo::children_per_cell, - ExcIndexRange (child_no, 0, GeometryInfo::children_per_cell)); + Assert (child_no < GeometryInfo::max_children_per_cell, + ExcIndexRange (child_no, 0, GeometryInfo::max_children_per_cell)); const unsigned int n_q_points = quadrature.size(); @@ -1018,7 +953,7 @@ QProjector::project_to_child (const Quadrature &quadrature, // scale them std::vector weights = quadrature.get_weights (); for (unsigned int i=0; i::children_per_cell); + weights[i] *= (1./GeometryInfo::max_children_per_cell); return Quadrature (q_points, weights); } @@ -1115,28 +1050,88 @@ face (const unsigned int face_no, -template -typename QProjector::DataSetDescriptor -QProjector::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::faces_per_cell, ExcInternalError()); - // the trick with +1 prevents that we get a - // warning in 1d - Assert (subface_no+1 < GeometryInfo::subfaces_per_face+1, - ExcInternalError()); + Assert (subface_no < GeometryInfo::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 + // 4 + 2 + 2 = 8 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: @@ -1153,39 +1148,207 @@ subface (const unsigned int face_no, // 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::faces_per_cell*GeometryInfo::subfaces_per_face, - 5*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face}, + {4*GeometryInfo::faces_per_cell*total_subfaces_per_face, + 5*GeometryInfo::faces_per_cell*total_subfaces_per_face}, // face_orientation=false; face_flip=true; face_rotation=false and true - {6*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face, - 7*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face}}, + {6*GeometryInfo::faces_per_cell*total_subfaces_per_face, + 7*GeometryInfo::faces_per_cell*total_subfaces_per_face}}, { // face_orientation=true; face_flip=false; face_rotation=false and true - {0*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face, - 1*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face}, + {0*GeometryInfo::faces_per_cell*total_subfaces_per_face, + 1*GeometryInfo::faces_per_cell*total_subfaces_per_face}, // face_orientation=true; face_flip=true; face_rotation=false and true - {2*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face, - 3*GeometryInfo::faces_per_cell*GeometryInfo::subfaces_per_face}}}; + {2*GeometryInfo::faces_per_cell*total_subfaces_per_face, + 3*GeometryInfo::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 + equivalent_refine_case[internal::SubfaceCase::case_isotropic+1][GeometryInfo<3>::max_children_per_face] + = { - case 1: - case 2: - return ((face_no * GeometryInfo::subfaces_per_face + - subface_no) - * n_quadrature_points); - case 3: - return (((face_no * GeometryInfo::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::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy}, + // case_x + {RefinementCase::cut_x, + RefinementCase::cut_x, + RefinementCase::no_refinement, + RefinementCase::no_refinement}, + // case_x1y + {RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_x, + RefinementCase::no_refinement}, + // case_x2y + {RefinementCase::cut_x, + RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::no_refinement}, + // case_x1y2y + {RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy}, + // case_y + {RefinementCase::cut_y, + RefinementCase::cut_y, + RefinementCase::no_refinement, + RefinementCase::no_refinement}, + // case_y1x + {RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_y, + RefinementCase::no_refinement}, + // case_y2x + {RefinementCase::cut_y, + RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::no_refinement}, + // case_y1x2x + {RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy}, + // case_xy (case_isotropic) + {RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy, + RefinementCase::cut_xy} + }; + + static const unsigned int + equivalent_subface_number[internal::SubfaceCase::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 ref_case_permutation[4] + ={RefinementCase::no_refinement, + RefinementCase::cut_y, + RefinementCase::cut_x, + RefinementCase::cut_xy}; + + // set a corresponding (equivalent) + // RefineCase and subface number + const RefinementCase 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::no_refinement, ExcInternalError()); + Assert(equ_subface_no!=e, ExcInternalError()); + // now, finally respect non-standard faces + const RefinementCase + 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::child_cell_on_face(RefinementCase(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); } @@ -1227,12 +1390,13 @@ QProjector::project_to_face(const SubQuadrature &quadrature, template Quadrature -QProjector::project_to_subface(const SubQuadrature &quadrature, - const unsigned int face_no, - const unsigned int subface_no) +QProjector::project_to_subface(const SubQuadrature &quadrature, + const unsigned int face_no, + const unsigned int subface_no, + const RefinementCase &ref_case) { std::vector > 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(points, quadrature.get_weights()); } diff --git a/deal.II/deal.II/include/fe/fe.h b/deal.II/deal.II/include/fe/fe.h index 328f89fe10..5af016f891 100644 --- a/deal.II/deal.II/include/fe/fe.h +++ b/deal.II/deal.II/include/fe/fe.h @@ -14,8 +14,10 @@ #define __deal2__fe_h #include +#include #include + DEAL_II_NAMESPACE_OPEN template class FEValuesData; @@ -303,7 +305,7 @@ namespace hp for (unsigned int i=0; i::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 * *
Computing the #restriction matrices for error estimators
@@ -672,11 +674,18 @@ class FiniteElement : public Subscriptor, * 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 & - get_restriction_matrix (const unsigned int child) const; + get_restriction_matrix (const unsigned int child, + const RefinementCase &refinement_case=RefinementCase::isotropic_refinement) const; /** * Embedding matrix between grids. @@ -725,10 +734,14 @@ class FiniteElement : public Subscriptor, * 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 & - get_prolongation_matrix (const unsigned int child) const; + get_prolongation_matrix (const unsigned int child, + const RefinementCase &refinement_case=RefinementCase::isotropic_refinement) const; /** * Return whether this element implements @@ -737,6 +750,18 @@ class FiniteElement : public Subscriptor, * the get_prolongation_matrix() * function will generate an error or * not. + * + * Note, that this function + * returns true 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 @@ -758,6 +783,34 @@ class FiniteElement : public Subscriptor, */ 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 + * get_prolongation_matrix() 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 @@ -765,6 +818,18 @@ class FiniteElement : public Subscriptor, * the get_restriction_matrix() * function will generate an error or * not. + * + * Note, that this function + * returns true 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 @@ -786,6 +851,35 @@ class FiniteElement : public Subscriptor, */ 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 + * get_restriction_matrix() 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 @@ -826,7 +920,7 @@ class FiniteElement : public Subscriptor, * succeed or generate the * exception. */ - const FullMatrix & constraints () const; + const FullMatrix & constraints (const internal::SubfaceCase &subface_case=internal::SubfaceCase::case_isotropic) const; /** * Return whether this element @@ -858,7 +952,7 @@ class FiniteElement : public Subscriptor, * the lack of information this * just expresses. */ - bool constraints_are_implemented () const; + bool constraints_are_implemented (const internal::SubfaceCase &subface_case=internal::SubfaceCase::case_isotropic) const; /** @@ -1866,6 +1960,41 @@ class FiniteElement : public Subscriptor, 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 @@ -1878,7 +2007,7 @@ class FiniteElement : public Subscriptor, const bool cached_primitivity; /** - * Array of projection + * Vector of projection * matrices. See * get_restriction_matrix() * above. The constructor @@ -1886,11 +2015,27 @@ class FiniteElement : public Subscriptor, * zero dimensions, which can be * changed by derived classes * implementing them. - */ - FullMatrix restriction[GeometryInfo::children_per_cell]; + * + * Note, that + * restriction[refinement_case-1][child] + * includes the restriction + * matrix of child + * child for the + * RefinementCase + * refinement_case. Here, + * we use + * refinement_case-1 + * instead of + * refinement_case + * as for + * RefinementCase::no_refinement(=0) + * there are no restriction + * matrices available. + */ + std::vector > > restriction; /** - * Array of embedding + * Vector of embedding * matrices. See * get_prolongation_matrix() * above. The constructor @@ -1898,8 +2043,24 @@ class FiniteElement : public Subscriptor, * zero dimensions, which can be * changed by derived classes * implementing them. - */ - FullMatrix prolongation[GeometryInfo::children_per_cell]; + * + * Note, that + * prolongation[refinement_case-1][child] + * includes the prolongation + * matrix of child + * child for the + * RefinementCase + * refinement_case. Here, + * we use + * refinement_case-1 + * instead of + * refinement_case + * as for + * RefinementCase::no_refinement(=0) + * there are no prolongation + * matrices available. + */ + std::vector > > prolongation; /** * Specify the constraints which diff --git a/deal.II/deal.II/include/fe/fe_dgp.h b/deal.II/deal.II/include/fe/fe_dgp.h index ad6df6474f..c1775e82b1 100644 --- a/deal.II/deal.II/include/fe/fe_dgp.h +++ b/deal.II/deal.II/include/fe/fe_dgp.h @@ -311,7 +311,7 @@ class FE_DGP : public FE_Poly,dim> * As @p embedding but for * projection matrices. */ - static const double * const projection_matrices[][GeometryInfo::children_per_cell]; + static const double * const projection_matrices[][GeometryInfo::max_children_per_cell]; /** * As @@ -356,19 +356,19 @@ class FE_DGP : public FE_Poly,dim> // 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; diff --git a/deal.II/deal.II/include/fe/fe_dgp_nonparametric.h b/deal.II/deal.II/include/fe/fe_dgp_nonparametric.h index df034ede79..3f3e94928a 100644 --- a/deal.II/deal.II/include/fe/fe_dgp_nonparametric.h +++ b/deal.II/deal.II/include/fe/fe_dgp_nonparametric.h @@ -419,7 +419,7 @@ class FE_DGPNonparametric : public FiniteElement * polynomial degree starting * from constant elements */ - static const double * const embedding[][GeometryInfo::children_per_cell]; + static const double * const embedding[][GeometryInfo::max_children_per_cell]; /** * Number of elements (first @@ -436,7 +436,7 @@ class FE_DGPNonparametric : public FiniteElement * As @p embedding but for * projection matrices. */ - static const double * const projection_matrices[][GeometryInfo::children_per_cell]; + static const double * const projection_matrices[][GeometryInfo::max_children_per_cell]; /** * As @@ -614,37 +614,37 @@ class FE_DGPNonparametric : public FiniteElement // 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; diff --git a/deal.II/deal.II/include/fe/fe_nedelec.h b/deal.II/deal.II/include/fe/fe_nedelec.h index 2b65530bf3..6568e5cfa6 100644 --- a/deal.II/deal.II/include/fe/fe_nedelec.h +++ b/deal.II/deal.II/include/fe/fe_nedelec.h @@ -350,7 +350,7 @@ class FE_Nedelec : public FiniteElement * fields. */ static const double * const - embedding[][GeometryInfo::children_per_cell]; + embedding[][GeometryInfo::max_children_per_cell]; /** * Number of elements (first @@ -678,7 +678,7 @@ FE_Nedelec<3>::shape_grad_grad_component (const unsigned int , #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; @@ -691,7 +691,7 @@ const unsigned int FE_Nedelec<1>::Matrices::n_constraint_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; @@ -704,7 +704,7 @@ const unsigned int FE_Nedelec<2>::Matrices::n_constraint_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; diff --git a/deal.II/deal.II/include/fe/fe_poly.templates.h b/deal.II/deal.II/include/fe/fe_poly.templates.h index 91353175ef..e9a71d18e3 100644 --- a/deal.II/deal.II/include/fe/fe_poly.templates.h +++ b/deal.II/deal.II/include/fe/fe_poly.templates.h @@ -352,7 +352,8 @@ FE_Poly::fill_fe_subface_values (const Mapping 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); diff --git a/deal.II/deal.II/include/fe/fe_tools.h b/deal.II/deal.II/include/fe/fe_tools.h index e636a0d4d1..05754070ae 100644 --- a/deal.II/deal.II/include/fe/fe_tools.h +++ b/deal.II/deal.II/include/fe/fe_tools.h @@ -305,16 +305,18 @@ class FETools const FiniteElement& fe); /** - * Compute the embedding matrices - * from a coarse cell to - * 2dim 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 @@ -328,20 +330,49 @@ class FETools * the finite element spaces are * actually nested. * + * Note, that + * matrices[refinement_case-1][child] + * includes the embedding (or prolongation) + * matrix of child + * child for the + * RefinementCase + * refinement_case. Here, + * we use + * refinement_case-1 + * instead of + * refinement_case + * 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 - * GeometryInfo::children_per_cell=2dim FullMatrix - * objects. This is the format - * used in FiniteElement, - * where we want to use ths - * function mostly. + * embedding matrices. @param + * matrices A reference to + * RefinementCase::isotropic_refinement + * vectors of FullMatrix + * objects. Each vector + * corresponds to one + * RefinementCase @p + * refinement_case and is of the + * vector size + * GeometryInfo::n_children(refinement_case). This + * is the format used in + * FiniteElement, where we want + * to use this function mostly. */ template - static void - compute_embedding_matrices(const FiniteElement &fe, - FullMatrix (&matrices)[GeometryInfo::children_per_cell]); + static void compute_embedding_matrices(const FiniteElement &fe, + std::vector > >& matrices); /** * Compute the embedding matrices @@ -373,28 +404,61 @@ class FETools template static void compute_face_embedding_matrices(const FiniteElement& fe, - FullMatrix (&matrices)[GeometryInfo::subfaces_per_face], + FullMatrix (&matrices)[GeometryInfo::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 * L2-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 - * GeometryInfo::children_per_cell=2dim - * FullMatrix objects. This is the format - * used in FiniteElement, where we - * want to use this function mostly. + * Note, that + * matrices[refinement_case-1][child] + * includes the projection (or restriction) + * matrix of child + * child for the + * RefinementCase + * refinement_case. Here, + * we use + * refinement_case-1 + * instead of + * refinement_case + * 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 + * RefinementCase::isotropic_refinement + * vectors of FullMatrix + * objects. Each vector + * corresponds to one + * RefinementCase @p + * refinement_case and is of the + * vector size + * GeometryInfo::n_children(refinement_case). This + * is the format used in + * FiniteElement, where we want + * to use this function mostly. */ template - static void - compute_projection_matrices(const FiniteElement &fe, - FullMatrix (&matrices)[GeometryInfo::children_per_cell]); + static void compute_projection_matrices(const FiniteElement &fe, + std::vector > >& matrices); //TODO:[WB] Replace this documentation by something comprehensible diff --git a/deal.II/deal.II/include/fe/fe_values.h b/deal.II/deal.II/include/fe/fe_values.h index b14128ebfa..54edbc94e9 100644 --- a/deal.II/deal.II/include/fe/fe_values.h +++ b/deal.II/deal.II/include/fe/fe_values.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -556,6 +557,18 @@ class FEValuesData */ std::vector JxW_values; + /** + * Array of the Jacobian matrices at the + * quadrature points. + */ + std::vector > jacobians; + + /** + * Array of the derivatives of the Jacobian + * matrices at the quadrature points. + */ + std::vector > jacobian_grads; + /** * Store an array of weights * times the Jacobi determinant @@ -1591,6 +1604,36 @@ class FEValuesBase : protected FEValuesData, */ const std::vector & get_JxW_values () const; + /** + * Return the Jacobian of the + * transformation at the specified + * quadrature point, i.e. + * $J_{ij}=dx_i/d\hat x_j$ + */ + const Tensor<2,dim> & jacobian (const unsigned int quadrature_point) const; + + /** + * Pointer to the array holding + * the values returned by jacobian(). + */ + const std::vector > & get_jacobians () const; + + /** + * Return the second derivative of the + * transformation from unit to real cell, + * i.e. the first derivative of the + * Jacobian, at the specified quadrature + * point, i.e. $G_{ijk}=dJ_{jk}/d\hat x_i$. + */ + 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 > & get_jacobian_grads () const; + /** * Constant reference to the * selected mapping object. @@ -3973,6 +4016,28 @@ FEValuesBase::get_JxW_values () const +template +inline +const std::vector >& +FEValuesBase::get_jacobians () const +{ + Assert (this->update_flags & update_jacobians, ExcAccessToUninitializedField()); + return this->jacobians; +} + + + +template +inline +const std::vector >& +FEValuesBase::get_jacobian_grads () const +{ + Assert (this->update_flags & update_jacobian_grads, ExcAccessToUninitializedField()); + return this->jacobian_grads; +} + + + template inline const Point & @@ -4000,6 +4065,32 @@ FEValuesBase::JxW (const unsigned int i) const +template +inline +const Tensor<2,dim> & +FEValuesBase::jacobian (const unsigned int i) const +{ + Assert (this->update_flags & update_jacobians, ExcAccessToUninitializedField()); + Assert (ijacobians.size(), ExcIndexRange(i, 0, this->jacobians.size())); + + return this->jacobians[i]; +} + + + +template +inline +const Tensor<3,dim> & +FEValuesBase::jacobian_grad (const unsigned int i) const +{ + Assert (this->update_flags & update_jacobian_grads, ExcAccessToUninitializedField()); + Assert (ijacobian_grads.size(), ExcIndexRange(i, 0, this->jacobian_grads.size())); + + return this->jacobian_grads[i]; +} + + + template template inline diff --git a/deal.II/deal.II/include/fe/mapping.h b/deal.II/deal.II/include/fe/mapping.h index 5dd92c7553..88c3992a00 100644 --- a/deal.II/deal.II/include/fe/mapping.h +++ b/deal.II/deal.II/include/fe/mapping.h @@ -472,7 +472,7 @@ class Mapping : public Subscriptor * 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 @@ -484,18 +484,18 @@ class Mapping : public Subscriptor * 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::cell_iterator &cell, const Quadrature &quadrature, InternalDataBase &internal, std::vector > &quadrature_points, - std::vector &JxW_values) const = 0; + std::vector &JxW_values, + std::vector > &jacobians, + std::vector > &jacobian_grads) const = 0; /** * Performs the same as @p fill_fe_values diff --git a/deal.II/deal.II/include/fe/mapping_cartesian.h b/deal.II/deal.II/include/fe/mapping_cartesian.h index 826b7ee88c..d9bf66f544 100644 --- a/deal.II/deal.II/include/fe/mapping_cartesian.h +++ b/deal.II/deal.II/include/fe/mapping_cartesian.h @@ -59,7 +59,9 @@ class MappingCartesian : public Mapping const Quadrature& quadrature, typename Mapping::InternalDataBase &mapping_data, std::vector > &quadrature_points, - std::vector &JxW_values) const ; + std::vector &JxW_values, + std::vector > &jacobians, + std::vector > &jacobian_grads) const ; virtual void fill_fe_face_values (const typename Triangulation::cell_iterator &cell, diff --git a/deal.II/deal.II/include/fe/mapping_q.h b/deal.II/deal.II/include/fe/mapping_q.h index 2b19721dac..2f903a3e4f 100644 --- a/deal.II/deal.II/include/fe/mapping_q.h +++ b/deal.II/deal.II/include/fe/mapping_q.h @@ -231,7 +231,9 @@ class MappingQ : public MappingQ1 const Quadrature &quadrature, typename Mapping::InternalDataBase &mapping_data, typename std::vector > &quadrature_points, - std::vector &JxW_values) const ; + std::vector &JxW_values, + std::vector > &jacobians, + std::vector > &jacobian_grads) const ; /** * Implementation of the interface in diff --git a/deal.II/deal.II/include/fe/mapping_q1.h b/deal.II/deal.II/include/fe/mapping_q1.h index 9a75ebf402..c600375b5e 100644 --- a/deal.II/deal.II/include/fe/mapping_q1.h +++ b/deal.II/deal.II/include/fe/mapping_q1.h @@ -151,6 +151,22 @@ class MappingQ1 : public Mapping 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 @@ -177,6 +193,16 @@ class MappingQ1 : public Mapping */ std::vector > shape_derivatives; + /** + * Values of shape function + * second derivatives. Access + * by function + * @p second_derivative. + * + * Computed once. + */ + std::vector > shape_second_derivatives; + /** * Tensors of covariant * transformation at each of @@ -199,7 +225,7 @@ class MappingQ1 : public Mapping * 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. */ @@ -281,7 +307,9 @@ class MappingQ1 : public Mapping const Quadrature& quadrature, typename Mapping::InternalDataBase &mapping_data, typename std::vector > &quadrature_points, - std::vector &JxW_values) const ; + std::vector &JxW_values, + std::vector > &jacobians, + std::vector > &jacobian_grads) const ; /** * Implementation of the interface in @@ -375,7 +403,7 @@ class MappingQ1 : public Mapping */ void compute_fill_face (const typename Triangulation::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 &weights, @@ -652,6 +680,32 @@ MappingQ1::InternalData::derivative (const unsigned int qpoint, } +template +inline +Tensor<2,dim> +MappingQ1::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 +inline +Tensor<2,dim> & +MappingQ1::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]; +} + @@ -679,7 +733,7 @@ MappingQ1<1>::compute_face_data (const UpdateFlags, 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 &, diff --git a/deal.II/deal.II/include/grid/grid_tools.h b/deal.II/deal.II/include/grid/grid_tools.h index 84e1bd7d90..a4bce05c5d 100644 --- a/deal.II/deal.II/include/grid/grid_tools.h +++ b/deal.II/deal.II/include/grid/grid_tools.h @@ -2,7 +2,7 @@ // $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 @@ -426,7 +426,16 @@ class GridTools static std::vector 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 + static void + get_active_neighbors (const typename Container::active_cell_iterator &cell, + std::vector &active_neighbors); /** * Use the METIS partitioner to generate @@ -734,7 +743,7 @@ GridTools::get_active_child_cells (const typename DH::cell_iterator& cell) if (cell->has_children()) { for (unsigned int child=0; - child::children_per_cell; ++child) + childn_children(); ++child) if (cell->child (child)->has_children()) { const std::vector @@ -750,6 +759,70 @@ GridTools::get_active_child_cells (const typename DH::cell_iterator& cell) } + +#if deal_II_dimension == 1 + +template +void +GridTools::get_active_neighbors(const typename Container::active_cell_iterator &cell, + std::vector &active_neighbors) +{ + active_neighbors.clear (); + for (unsigned int n=0; n::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 +void +GridTools::get_active_neighbors(const typename Container::active_cell_iterator &cell, + std::vector &active_neighbors) +{ + active_neighbors.clear (); + for (unsigned int n=0; n::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; cface(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 diff --git a/deal.II/deal.II/include/grid/tria.h b/deal.II/deal.II/include/grid/tria.h index 329b645873..45fcc6da0c 100644 --- a/deal.II/deal.II/include/grid/tria.h +++ b/deal.II/deal.II/include/grid/tria.h @@ -724,6 +724,14 @@ namespace internal * @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. + * *
  • @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 @@ -820,6 +828,32 @@ namespace internal * This flag includes all the above ones and therefore combines all * smoothing algorithms implemented. * + *
  • @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". + * *
  • @p none: * Select no smoothing at all. * @@ -1134,7 +1168,7 @@ namespace internal * 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 @@ -1172,6 +1206,8 @@ class Triangulation : public Subscriptor 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, @@ -1183,7 +1219,7 @@ class Triangulation : public Subscriptor eliminate_refined_boundary_islands | do_not_produce_unrefined_islands), - maximum_smoothing = 0xffff + maximum_smoothing = 0xffff ^ allow_anisotropic_smoothing }; @@ -1735,6 +1771,12 @@ class Triangulation : public Subscriptor */ void load_coarsen_flags (const std::vector &v); + /** + * Return whether this triangulation has + * ever undergone anisotropic (as opposed + * to only isotropic) refinement. + */ + bool get_anisotropic_refinement_flag() const; /*@}*/ @@ -3052,6 +3094,23 @@ class Triangulation : public Subscriptor */ 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 @@ -3064,20 +3123,53 @@ class Triangulation : public Subscriptor * 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 &cell_count); + std::vector &line_cell_count, + std::vector &quad_cell_count); + + /** + * Set the neighbor information of all + * outer neighbor of all children of the + * given cell cell, if + * refining=true. In this + * constellation the function is called + * after the creation of children in @p + * execute_refinement. If + * refining=false, 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 &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 &cell_count); + void count_cells_at_quad (std::vector &quad_cell_count); /** * Some dimension dependent stuff for @@ -3098,12 +3190,36 @@ class Triangulation : public Subscriptor */ 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 @@ -3177,6 +3293,13 @@ class Triangulation : public Subscriptor */ SmartPointer > boundary[255]; + /** + * Flag indicating whether + * anisotropic refinement took + * place. + */ + bool anisotropic_refinement; + /** * Do some smoothing in the process * of refining the triangulation. See @@ -3276,6 +3399,7 @@ template <> void Triangulation<2>::clear_user_pointers (); 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 &) const; @@ -3286,11 +3410,14 @@ template <> void Triangulation<1>::save_user_flags_hex (std::ostream &) const; template <> void Triangulation<1>::save_user_flags_hex (std::vector &) const; template <> void Triangulation<1>::load_user_flags_hex (std::istream &); template <> void Triangulation<1>::load_user_flags_hex (const std::vector &); +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 &) const; template <> void Triangulation<2>::load_user_flags_hex (std::istream &); template <> void Triangulation<2>::load_user_flags_hex (const std::vector &); +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; @@ -3385,10 +3512,25 @@ template <> void Triangulation<1>::execute_refinement (); 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 &); -template <> void Triangulation<2>::delete_children (cell_iterator &cell, std::vector &); -template <> void Triangulation<3>::delete_children (cell_iterator &cell, std::vector &cell_count); -template <> void Triangulation<3>::count_cells_at_line (std::vector &cell_count); +template <> void Triangulation<1>::delete_children (cell_iterator &cell, + std::vector &, + std::vector &); +template <> void Triangulation<2>::delete_children (cell_iterator &cell, + std::vector &, + std::vector &); +template <> void Triangulation<3>::delete_children (cell_iterator &cell, + std::vector &line_cell_count, + std::vector &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 &line_cell_count); +template <> void Triangulation<3>::count_cells_at_quad (std::vector &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 (); diff --git a/deal.II/deal.II/include/grid/tria_accessor.h b/deal.II/deal.II/include/grid/tria_accessor.h index 0f59aedefc..83bb7515ca 100644 --- a/deal.II/deal.II/include/grid/tria_accessor.h +++ b/deal.II/deal.II/include/grid/tria_accessor.h @@ -16,6 +16,7 @@ #include #include +#include #include @@ -68,6 +69,10 @@ namespace TriaAccessorExceptions /** * @ingroup Exceptions */ + DeclException0 (ExcCellNotActive); + /** + * @ingroup Exceptions + */ DeclException1 (ExcInvalidNeighbor, int, << "Neighbor indices must be between 0 and 2^dim-1, but " @@ -116,6 +121,13 @@ namespace TriaAccessorExceptions * @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 << "."); } @@ -771,6 +783,42 @@ class TriaObjectAccessor : public TriaAccessor * function. */ void recursively_clear_user_index () const; + + /** + * Return the @p RefinementCase + * of this cell. + */ + RefinementCase refinement_case() const; + + /** + * Set the @p RefinementCase this + * TriaObject is refined with. + * Not defined for + * celldim=1 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 &ref_case) const; + + /** + * Clear the RefinementCase of + * this TriaObject, i.e. reset it + * to RefinementCase::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; /*@}*/ /** @@ -780,6 +828,17 @@ class TriaObjectAccessor : public TriaAccessor TriaIterator > 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 > + isotropic_child (const unsigned int i) const; + /** * Index of the @p ith child. * The level of the child is one @@ -793,17 +852,31 @@ class TriaObjectAccessor : public TriaAccessor 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, @@ -829,6 +902,22 @@ class TriaObjectAccessor : public TriaAccessor * has_children()==true. */ 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 + * numbers::invalid_unsigned_int. + */ + unsigned int middle_vertex_index() const; /** * Number of times that this @@ -985,9 +1074,9 @@ class TriaObjectAccessor : public TriaAccessor * 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. @@ -1423,6 +1512,12 @@ class TriaObjectAccessor<1, dim> : public TriaAccessor<1,dim> * A *a=static_cast(cell->user_pointer());. */ void * user_pointer () const; + + /** + * Return the @p RefinementCase + * of this cell. + */ + RefinementCase<1> refinement_case() const; /** * Set the user index @@ -1478,6 +1573,16 @@ class TriaObjectAccessor<1, dim> : public TriaAccessor<1,dim> TriaIterator > 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 + * child(i). + */ + TriaIterator > + isotropic_child (const unsigned int i) const; + /** * Return the index of the * @p ith child. The level of @@ -1492,12 +1597,30 @@ class TriaObjectAccessor<1, dim> : public TriaAccessor<1,dim> 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 @@ -1505,7 +1628,7 @@ class TriaObjectAccessor<1, dim> : public TriaAccessor<1,dim> * 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, @@ -1532,6 +1655,22 @@ class TriaObjectAccessor<1, dim> : public TriaAccessor<1,dim> */ 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 + * numbers::invalid_unsigned_int. + */ + unsigned int middle_vertex_index() const; + /** * Return the number of times * that this cell is @@ -2127,12 +2266,55 @@ class TriaObjectAccessor<2, dim> : public TriaAccessor<2,dim> * function. */ void recursively_clear_user_index () const; + /** + + * Return the @p RefinementCase + * of this cell. + */ + RefinementCase<2> refinement_case() const; + + /** + * Set the @p RefinementCase 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 of + * this TriaObject, i.e. reset it + * to RefinementCase::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 > 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 > + isotropic_child (const unsigned int i) const; + /** * Return the index of the * @p ith child. The level of @@ -2147,17 +2329,31 @@ class TriaObjectAccessor<2, dim> : public TriaAccessor<2,dim> 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, @@ -2184,6 +2380,22 @@ class TriaObjectAccessor<2, dim> : public TriaAccessor<2,dim> */ 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 + * numbers::invalid_unsigned_int. + */ + unsigned int middle_vertex_index() const; + /** * Return the number of times * that this cell is @@ -2379,9 +2591,10 @@ class TriaObjectAccessor<2, dim> : public TriaAccessor<2,dim> * 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. @@ -2836,6 +3049,37 @@ class TriaObjectAccessor<3, dim> : public TriaAccessor<3,dim> */ void recursively_clear_user_index () const; + /** + * Return the @p RefinementCase + * of this cell. + */ + RefinementCase<3> refinement_case() const; + + /** + * Set the @p RefinementCase 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 of + * this TriaObject, i.e. reset it + * to RefinementCase::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. @@ -2843,6 +3087,17 @@ class TriaObjectAccessor<3, dim> : public TriaAccessor<3,dim> TriaIterator > 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 > + isotropic_child (const unsigned int i) const; + /** * Return the index of the * @p ith child. The level of @@ -2854,17 +3109,31 @@ class TriaObjectAccessor<3, dim> : public TriaAccessor<3,dim> 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, @@ -2891,6 +3160,22 @@ class TriaObjectAccessor<3, dim> : public TriaAccessor<3,dim> */ 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 + * numbers::invalid_unsigned_int. + */ + unsigned int middle_vertex_index() const; + /** * Return the number of times * that this cell is @@ -3068,9 +3353,10 @@ class TriaObjectAccessor<3, dim> : public TriaAccessor<3,dim> * 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. @@ -3345,9 +3631,9 @@ class CellAccessor : public TriaObjectAccessor * Return the how-many'th * neighbor this cell is of * cell->neighbor(neighbor), - * i.e. return the number @p n + * i.e. return the @p face_no * such that - * cell->neighbor(neighbor)->neighbor(n)==cell. This + * cell->neighbor(neighbor)->neighbor(face_no)==cell. This * function is the right one if * you want to know how to get * back from a neighbor to the @@ -3355,26 +3641,52 @@ class CellAccessor : public TriaObjectAccessor * * Note that this operation is * only useful if the neighbor is - * not on a coarser level than - * the present cell - * (i.e. cell->neighbor(neighbor)->level() - * needs to be equal to - * cell->level(). 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: * cell->neighbor(neighbor)->neighbor_child_on_subface(face_no,subface_no)==cell. + * 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: + * cell->neighbor(neighbor)->face(face_no)->child(subface_no)==cell->face(neighbor). + * 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 dim==1. @@ -3382,6 +3694,17 @@ class CellAccessor : public TriaObjectAccessor std::pair 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 @@ -3428,24 +3751,66 @@ class CellAccessor : public TriaObjectAccessor bool has_boundary_lines () const; /** - * Return whether the refinement - * flag is set or not. + * Return the @p + * RefinementCase this cell + * was flagged to be refined + * with. */ - bool refine_flag_set () const; + RefinementCase 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 ref_case = RefinementCase::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 face_no, 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 &face_refinement_case=RefinementCase::isotropic_refinement) const; + + /** + * Modify the refinement flag of the cell + * to ensure that line face_no + * 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 + * face_no. Note that this is not + * identical to asking + * cell->face(face_no)->refinement_case() + * since the latter returns a RefinementCase + * 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 subface_case(const unsigned int face_no) const; + /** * Return whether the coarsen flag * is set or not. @@ -3527,7 +3892,7 @@ class CellAccessor : public TriaObjectAccessor * 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 @@ -3554,8 +3919,7 @@ class CellAccessor : public TriaObjectAccessor * 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 @@ -3572,12 +3936,22 @@ class CellAccessor : public TriaObjectAccessor * 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 > neighbor_child_on_subface (const unsigned int face_no, @@ -3664,6 +4038,42 @@ class CellAccessor : public TriaObjectAccessor */ 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 + * invalid_unsigned_int. + * + * 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 + * face_no 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: /** diff --git a/deal.II/deal.II/include/grid/tria_accessor.templates.h b/deal.II/deal.II/include/grid/tria_accessor.templates.h index 548d0c4b8e..87326b5840 100644 --- a/deal.II/deal.II/include/grid/tria_accessor.templates.h +++ b/deal.II/deal.II/include/grid/tria_accessor.templates.h @@ -311,6 +311,19 @@ TriaObjectAccessor<1,dim>::clear_user_flag () const } +template +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 inline @@ -336,6 +349,16 @@ TriaObjectAccessor<1,dim>::child_index (const unsigned int i) const +template +inline +int +TriaObjectAccessor<1,dim>::isotropic_child_index (const unsigned int i) const +{ + return child_index(i); +} + + + template inline TriaIterator > @@ -356,13 +379,36 @@ TriaObjectAccessor<1,dim>::child (const unsigned int i) const +template +inline +TriaIterator > +TriaObjectAccessor<1,dim>::isotropic_child (const unsigned int i) const +{ + // no anisotropic refinement in 1D + return child(i); +} + + + template 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 +inline +unsigned int +TriaObjectAccessor<1,dim>::middle_vertex_index () const +{ + if (has_children()) + return child(0)->vertex_index(1); + return numbers::invalid_unsigned_int; } @@ -432,7 +478,7 @@ TriaObjectAccessor<1,dim>::operator ++ () // has no level) if (this->present_index >= - static_cast(this->tria->faces->lines.cells.size())) + static_cast(objects().cells.size())) this->present_index = -1; } @@ -621,6 +667,55 @@ TriaObjectAccessor<2,dim>::line_index (const unsigned int i) const +template +inline +RefinementCase<2> +TriaObjectAccessor<2, dim>::refinement_case () const +{ + Assert (this->state() == IteratorState::valid, + TriaAccessorExceptions::ExcDereferenceInvalidObject()); + Assert (static_cast (this->present_index) < + objects().refinement_cases.size(), + ExcIndexRange(this->present_index, 0, + objects().refinement_cases.size())); + + return objects().refinement_cases[this->present_index]; +} + + + +template +inline +void +TriaObjectAccessor<2, dim>::set_refinement_case (const RefinementCase<2> &refinement_case) const +{ + Assert (this->state() == IteratorState::valid, + TriaAccessorExceptions::ExcDereferenceInvalidObject()); + Assert (static_cast (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 +inline +void +TriaObjectAccessor<2, dim>::clear_refinement_case () const +{ + Assert (this->state() == IteratorState::valid, + TriaAccessorExceptions::ExcDereferenceInvalidObject()); + Assert (static_cast (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 inline bool @@ -628,7 +723,7 @@ TriaObjectAccessor<2,dim>::has_children () const { Assert (this->state() == IteratorState::valid, TriaAccessorExceptions::ExcDereferenceInvalidObject()); - return (objects().children[this->present_index] != -1); + return (objects().children[2*this->present_index] != -1); } @@ -639,7 +734,43 @@ int TriaObjectAccessor<2,dim>::child_index (const unsigned int i) const { 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 +inline +int TriaObjectAccessor<2,dim>::isotropic_child_index (const unsigned int i) const +{ + switch (static_cast (refinement_case())) + { + case RefinementCase::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::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::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::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::cut_xy: + return child_index(i); + break; + default: + Assert(false, TriaAccessorExceptions::ExcCellHasNoChildren()); + break; + } + return -1; } @@ -664,13 +795,75 @@ TriaObjectAccessor<2,dim>::child (const unsigned int i) const +template +inline +TriaIterator > +TriaObjectAccessor<2,dim>::isotropic_child (const unsigned int i) const +{ + switch (static_cast (refinement_case())) + { + case RefinementCase::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::cut_y, + ExcMessage("This cell has no grandchildren equivalent to isotropic refinement")); + return child(i%2)->child(i/2); + break; + case RefinementCase::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::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::cut_xy, + TriaAccessorExceptions::ExcCellHasNoChildren()); + break; + } + return child(i); +} + + + template inline unsigned int TriaObjectAccessor<2,dim>::n_children () const { Assert (has_children()==true, TriaAccessorExceptions::ExcCellHasNoChildren()); - return GeometryInfo<2>::children_per_cell; + Assert (static_cast (this->present_index) < + objects().refinement_cases.size(), + ExcIndexRange(this->present_index, 0, + objects().refinement_cases.size())); + + return GeometryInfo<2>::n_children(refinement_case()); +} + + + +template +inline +unsigned int +TriaObjectAccessor<2,dim>::middle_vertex_index () const +{ + switch (static_cast (refinement_case())) + { + case RefinementCase::cut_x: + return child(0)->line(1)->middle_vertex_index(); + break; + case RefinementCase::cut_y: + return child(0)->line(3)->middle_vertex_index(); + break; + case RefinementCase::cut_xy: + return child(0)->vertex_index(3); + break; + default: + break; + } + return numbers::invalid_unsigned_int; } @@ -990,12 +1183,65 @@ TriaObjectAccessor<3,3>::quad_index (const unsigned int i) const template <> inline +RefinementCase<3> +TriaObjectAccessor<3, 3>::refinement_case () const +{ + Assert (this->state() == IteratorState::valid, + TriaAccessorExceptions::ExcDereferenceInvalidObject()); + Assert (static_cast (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 (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 (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); } @@ -1005,7 +1251,17 @@ int TriaObjectAccessor<3,3>::child_index (const unsigned int i) const { 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); } @@ -1029,16 +1285,70 @@ TriaObjectAccessor<3,3>::child (const unsigned int i) const -template +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 (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 +inline +unsigned int +TriaObjectAccessor<3,dim>::middle_vertex_index () const +{ + switch (static_cast (refinement_case())) + { + case RefinementCase::cut_x: + return child(0)->quad(1)->middle_vertex_index(); + break; + case RefinementCase::cut_y: + return child(0)->quad(3)->middle_vertex_index(); + break; + case RefinementCase::cut_z: + return child(0)->quad(5)->middle_vertex_index(); + break; + case RefinementCase::cut_xy: + return child(0)->line(11)->middle_vertex_index(); + break; + case RefinementCase::cut_xz: + return child(0)->line(5)->middle_vertex_index(); + break; + case RefinementCase::cut_yz: + return child(0)->line(7)->middle_vertex_index(); + break; + case RefinementCase::cut_xyz: + return child(0)->vertex_index(7); + break; + default: + break; + } + return numbers::invalid_unsigned_int; +} + + + template inline unsigned int @@ -1360,7 +1670,7 @@ CellAccessor::neighbor_level (const unsigned int i) const template inline -bool +RefinementCase CellAccessor::refine_flag_set () const { Assert (this->used(), TriaAccessorExceptions::ExcCellNotUsed()); @@ -1371,7 +1681,7 @@ CellAccessor::refine_flag_set () const // 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(this->tria->levels[this->present_level]->refine_flags[this->present_index]); } @@ -1379,13 +1689,13 @@ CellAccessor::refine_flag_set () const template inline void -CellAccessor::set_refine_flag () const +CellAccessor::set_refine_flag (const RefinementCase 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; } @@ -1396,7 +1706,165 @@ void CellAccessor::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::no_refinement; +} + + + +template +inline +bool +CellAccessor::flag_for_face_refinement (const unsigned int face_no, + const RefinementCase &face_refinement_case) const +{ + Assert (dim>1, ExcImpossibleInDim(dim)); + Assert (face_no::faces_per_cell, + ExcIndexRange(face_no,0,GeometryInfo::faces_per_cell)); + Assert (face_refinement_case < RefinementCase::isotropic_refinement+1, + ExcIndexRange(face_refinement_case,0,RefinementCase::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 old_ref_case = refine_flag_set(); + RefinementCase + new_ref_case = (old_ref_case + | GeometryInfo::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 +inline +bool +CellAccessor::flag_for_line_refinement (const unsigned int line_no) const +{ + Assert (dim>1, ExcImpossibleInDim(dim)); + Assert (line_no::lines_per_cell, + ExcIndexRange(line_no,0,GeometryInfo::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 old_ref_case=refine_flag_set(), + new_ref_case=old_ref_case + | GeometryInfo::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::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::faces_per_cell, + ExcIndexRange(face_no,0,GeometryInfo<3>::faces_per_cell)); + switch (static_cast (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; } @@ -1483,6 +1951,28 @@ CellAccessor::active () const return !this->has_children(); } + + +template +inline +unsigned int +CellAccessor::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 diff --git a/deal.II/deal.II/include/grid/tria_levels.h b/deal.II/deal.II/include/grid/tria_levels.h index 68acb12e98..1b3275815d 100644 --- a/deal.II/deal.II/include/grid/tria_levels.h +++ b/deal.II/deal.II/include/grid/tria_levels.h @@ -51,18 +51,24 @@ namespace internal 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 refine_flags; + /** + * @p RefinementCase::Type flags + * for the cells to be + * refined with or not + * (RefinementCase::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 refine_flags; /** * Same meaning as the one above, but @@ -204,7 +210,7 @@ namespace internal class TriaLevel<3> { public: - std::vector refine_flags; + std::vector refine_flags; std::vector coarsen_flags; std::vector > neighbors; std::vector subdomain_ids; diff --git a/deal.II/deal.II/include/grid/tria_object.h b/deal.II/deal.II/include/grid/tria_object.h index 657738423f..355fe2653d 100644 --- a/deal.II/deal.II/include/grid/tria_object.h +++ b/deal.II/deal.II/include/grid/tria_object.h @@ -38,6 +38,8 @@ namespace internal class TriaObject { public: + static const unsigned int dimension = structdim; + /** * Default constructor, * setting all face indices diff --git a/deal.II/deal.II/include/grid/tria_objects.h b/deal.II/deal.II/include/grid/tria_objects.h index 1211625a54..31a591e48d 100644 --- a/deal.II/deal.II/include/grid/tria_objects.h +++ b/deal.II/deal.II/include/grid/tria_objects.h @@ -2,7 +2,7 @@ // $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 @@ -29,6 +29,9 @@ DEAL_II_NAMESPACE_OPEN // declares mainly additional data. This would have to be changed in case of a // partial specialization. +template class Triangulation; + + namespace internal { namespace Triangulation @@ -40,7 +43,7 @@ namespace internal * 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 @@ -63,13 +66,13 @@ namespace internal */ std::vector 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 @@ -81,6 +84,19 @@ namespace internal */ std::vector children; + /** + * Store the refinement + * case each of the + * cells is refined + * with. This vector + * might be replaced by + * vector > + * (dim, vector + * (n_cells)) which is + * more memory efficient. + */ + std::vector > refinement_cases; + /** * Vector storing whether an object is * used in the @p cells vector. @@ -132,15 +148,80 @@ namespace internal std::vector material_id; /** - * Assert that enough space is - * allocated to accomodate - * new_objs new objects. - * This function does not only call - * vector::reserve(), but - * does really append the needed - * elements. + * Assert that enough space + * is allocated to + * accomodate + * new_objs_in_pairs + * new objects, stored in + * pairs, plus + * new_obj_single + * stored individually. + * This function does not + * only call + * vector::reserve(), + * 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 + * G=TriaObject<1> + * . + */ + template + typename dealii::Triangulation::raw_line_iterator next_free_single_line (const dealii::Triangulation &tria); + + /** + * Return an iterator to the + * next free slot for a pair + * of lines. Only implemented + * for G=TriaObject<1> + * . + */ + template + typename dealii::Triangulation::raw_line_iterator next_free_pair_line (const dealii::Triangulation &tria); + + /** + * Return an iterator to the + * next free slot for a + * single quad. Only + * implemented for + * G=TriaObject@<2@> + * . + */ + template + typename dealii::Triangulation::raw_quad_iterator next_free_single_quad (const dealii::Triangulation &tria); + + /** + * Return an iterator to the + * next free slot for a pair + * of quads. Only implemented + * for G=TriaObject@<2@> + * . + */ + template + typename dealii::Triangulation::raw_quad_iterator next_free_pair_quad (const dealii::Triangulation &tria); + + /** + * Return an iterator to the + * next free slot for a pair + * of hexes. Only implemented + * for + * G=Hexahedron. + */ + template + typename dealii::Triangulation::raw_hex_iterator next_free_hex (const dealii::Triangulation &tria, + const unsigned int level); /** * Clear all the data contained in this object. @@ -149,17 +230,17 @@ namespace internal /** * The orientation of the - * face number face + * face number face * of the cell with number - * cell. The return - * value is true, if + * cell. The return + * value is true, if * the normal vector points * the usual way * (GeometryInfo::unit_normal_orientation) - * and false else. + * and false else. * * The result is always - * true in this + * true in this * class, but derived classes * will reimplement this. * @@ -211,6 +292,11 @@ namespace internal */ void clear_user_data(); + /** + * Clear all user flags. + */ + void clear_user_flags(); + /** * Check the memory consistency of the * different containers. Should only be @@ -245,6 +331,14 @@ namespace internal << "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 @@ -259,6 +353,21 @@ namespace internal 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. @@ -324,14 +433,14 @@ namespace internal public: /** * The orientation of the - * face number face + * face number face * of the cell with number - * cell. The return - * value is true, if + * cell. The return + * value is true, if * the normal vector points * the usual way * (GeometryInfo::unit_normal_orientation) - * and false if they + * and false if they * point in opposite * direction. */ @@ -378,7 +487,7 @@ namespace internal * a @p false value. * * In effect, this field has - * 6*n_cells elements, + * 6*n_cells elements, * being the number of cells * times the six faces each * has. @@ -396,9 +505,9 @@ namespace internal /** * Assert that enough space is * allocated to accomodate - * new_objs new objects. + * new_objs new objects. * This function does not only call - * vector::reserve(), but + * vector::reserve(), but * does really append the needed * elements. */ @@ -441,14 +550,14 @@ namespace internal public: /** * The orientation of the - * face number face + * face number face * of the cell with number - * cell. The return - * value is true, if + * cell. The return + * value is true, if * the normal vector points * the usual way * (GeometryInfo::unit_normal_orientation) - * and false if they + * and false if they * point in opposite * direction. */ @@ -457,7 +566,7 @@ namespace internal /** * In effect, this field has - * 4*n_quads elements, + * 4*n_quads elements, * being the number of quads * times the four lines each * has. @@ -465,15 +574,22 @@ namespace internal std::vector line_orientations; /** - * Assert that enough space is - * allocated to accomodate - * new_objs new objects. - * This function does not only call - * vector::reserve(), but - * does really append the needed - * elements. + * Assert that enough space + * is allocated to + * accomodate + * new_quads_in_pairs + * new quads, stored in + * pairs, plus + * new_quads_single + * stored individually. + * This function does not + * only call + * vector::reserve(), + * 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. @@ -595,6 +711,14 @@ namespace internal user_data[i].p = 0; } + + template + inline + void TriaObjects::clear_user_flags () + { + user_flags.assign(user_flags.size(),false); + } + //----------------------------------------------------------------------// inline @@ -626,11 +750,13 @@ namespace internal template<> void - TriaObjects >::reserve_space (const unsigned int new_lines); + TriaObjects >::reserve_space (const unsigned int new_lines_in_pairs, + const unsigned int new_lines_single); template<> void - TriaObjects >::reserve_space (const unsigned int new_quads); + TriaObjects >::reserve_space (const unsigned int new_quads_in_pairs, + const unsigned int new_quads_single); template<> void diff --git a/deal.II/deal.II/include/multigrid/mg_transfer.templates.h b/deal.II/deal.II/include/multigrid/mg_transfer.templates.h index a09d838166..750a69bbca 100644 --- a/deal.II/deal.II/include/multigrid/mg_transfer.templates.h +++ b/deal.II/deal.II/include/multigrid/mg_transfer.templates.h @@ -1,6 +1,6 @@ //--------------------------------------------------------------------------- -// 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 // diff --git a/deal.II/deal.II/include/numerics/derivative_approximation.h b/deal.II/deal.II/include/numerics/derivative_approximation.h index 431afbd25f..dc16c01855 100644 --- a/deal.II/deal.II/include/numerics/derivative_approximation.h +++ b/deal.II/deal.II/include/numerics/derivative_approximation.h @@ -3,7 +3,7 @@ // $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 diff --git a/deal.II/deal.II/source/dofs/dof_accessor.cc b/deal.II/deal.II/source/dofs/dof_accessor.cc index 400ee6b74d..ab2ad3ed28 100644 --- a/deal.II/deal.II/source/dofs/dof_accessor.cc +++ b/deal.II/deal.II/source/dofs/dof_accessor.cc @@ -451,8 +451,7 @@ get_interpolated_dof_values (const InputVector &values, for (unsigned int i=0; i::children_per_cell; - ++child) + for (unsigned int child=0; childn_children(); ++child) { // get the values from the present // child, if necessary by @@ -461,7 +460,7 @@ get_interpolated_dof_values (const InputVector &values, 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 @@ -504,13 +503,13 @@ set_dof_values_by_interpolation (const Vector &local_values, { Vector tmp(dofs_per_cell); - for (unsigned int child=0; child::children_per_cell; - ++child) + for (unsigned int child=0; childn_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); } } diff --git a/deal.II/deal.II/source/dofs/dof_tools.cc b/deal.II/deal.II/source/dofs/dof_tools.cc index 1dce1176d4..0cfb89c377 100644 --- a/deal.II/deal.II/source/dofs/dof_tools.cc +++ b/deal.II/deal.II/source/dofs/dof_tools.cc @@ -518,19 +518,14 @@ DoFTools::make_flux_sparsity_pattern ( 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 @@ -555,7 +550,13 @@ DoFTools::make_flux_sparsity_pattern ( } 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); @@ -736,7 +737,7 @@ DoFTools::make_flux_sparsity_pattern ( 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); @@ -1426,7 +1427,7 @@ namespace internal get_most_dominating_subface_fe_index (const face_iterator &face) { unsigned int dominating_subface_no = 0; - for (; dominating_subface_no::subfaces_per_face; + for (; dominating_subface_non_children(); ++dominating_subface_no) { // each of the subfaces @@ -1447,7 +1448,7 @@ namespace internal FiniteElementDomination::Domination domination = FiniteElementDomination::either_element_can_dominate; - for (unsigned int sf=0; sf::subfaces_per_face; ++sf) + for (unsigned int sf=0; sfn_children(); ++sf) if (sf != dominating_subface_no) { const FiniteElement & @@ -1473,7 +1474,7 @@ namespace internal // check that we have // found one such subface - Assert (dominating_subface_no != GeometryInfo::subfaces_per_face, + Assert (dominating_subface_no < face->n_children(), ExcNotImplemented()); // return the finite element @@ -1721,7 +1722,7 @@ namespace internal Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) == true, ExcInternalError()); - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(face)->n_children(); ++c) Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, ExcInternalError()); @@ -1730,7 +1731,7 @@ namespace internal // the case that both // sides use the same // fe - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(face)->n_children(); ++c) Assert (cell->face(face)->child(c) ->fe_index_is_active(cell->active_fe_index()) == true, ExcNotImplemented()); @@ -1843,6 +1844,17 @@ namespace internal for (unsigned int face=0; face::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::isotropic_refinement, + ExcNotImplemented()); + // so now we've found a // face of an active // cell that has @@ -1867,7 +1879,7 @@ namespace internal Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) == true, ExcInternalError()); - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(face)->n_children(); ++c) Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, ExcInternalError()); @@ -1881,7 +1893,7 @@ namespace internal // this face and the // children have the // same fe - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(face)->n_children(); ++c) { Assert (cell->face(face)->child(c) ->fe_index_is_active(cell->active_fe_index()) == true, @@ -1916,7 +1928,8 @@ namespace internal 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); @@ -1951,7 +1964,9 @@ namespace internal // 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)) && @@ -2078,7 +2093,7 @@ namespace internal Table<3,boost::shared_ptr > > subface_interpolation_matrices (n_finite_elements (dof_handler), n_finite_elements (dof_handler), - GeometryInfo::subfaces_per_face); + GeometryInfo::max_children_per_face); // similarly have a cache for // the matrices that are split @@ -2115,6 +2130,17 @@ namespace internal for (unsigned int face=0; face::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::isotropic_refinement, + ExcNotImplemented()); + // so now we've found a // face of an active // cell that has @@ -2139,7 +2165,7 @@ namespace internal Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) == true, ExcInternalError()); - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(face)->n_children(); ++c) Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, ExcInternalError()); @@ -2160,7 +2186,7 @@ namespace internal mother_face_dominates = FiniteElementDomination::either_element_can_dominate; if (DoFHandlerSupportsDifferentP::value == true) - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(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())); @@ -2191,7 +2217,7 @@ namespace internal // Now create constraint matrix for // the subfaces and assemble it. - for (unsigned int c=0; c::subfaces_per_face; ++c) + for (unsigned int c=0; cface(face)->n_children(); ++c) { const typename DH::active_face_iterator subface = cell->face(face)->child(c); @@ -2456,7 +2482,7 @@ namespace internal // discussed in the // paper for (unsigned int sf=0; - sf::subfaces_per_face; ++sf) + sfface(face)->n_children(); ++sf) { Assert (cell->face(face)->child(sf) ->n_active_fe_indices() == 1, @@ -2544,8 +2570,8 @@ namespace internal (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); diff --git a/deal.II/deal.II/source/fe/fe.cc b/deal.II/deal.II/source/fe/fe.cc index b16f24bddf..6ee95da799 100644 --- a/deal.II/deal.II/source/fe/fe.cc +++ b/deal.II/deal.II/source/fe/fe.cc @@ -208,6 +208,24 @@ FiniteElement::FiniteElement ( // 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 initializes + // them with size zero + prolongation.resize(RefinementCase::isotropic_refinement); + restriction.resize(RefinementCase::isotropic_refinement); + for (unsigned int ref=RefinementCase::cut_x; + ref::isotropic_refinement+1; ++ref) + { + prolongation[ref-1].resize (GeometryInfo:: + n_children(RefinementCase(ref)), + FullMatrix()); + restriction[ref-1].resize (GeometryInfo:: + n_children(RefinementCase(ref)), + FullMatrix()); + } + adjust_quad_dof_index_for_face_orientation_table.fill(0); } @@ -288,26 +306,71 @@ FiniteElement::shape_grad_grad_component (const unsigned int, } + +template +void +FiniteElement::reinit_restriction_and_prolongation_matrices ( + const bool isotropic_restriction_only, + const bool isotropic_prolongation_only) +{ + for (unsigned int ref_case=RefinementCase::cut_x; + ref_case::isotropic_refinement+1; ++ref_case) + { + const unsigned int nc = GeometryInfo::n_children(RefinementCase(ref_case)); + + for (unsigned int i=0; i::isotropic_refinement) + this->restriction[ref_case-1][i].reinit (this->dofs_per_cell, + this->dofs_per_cell); + if (!isotropic_prolongation_only || ref_case==RefinementCase::isotropic_refinement) + this->prolongation[ref_case-1][i].reinit (this->dofs_per_cell, + this->dofs_per_cell); + } + } +} + + template const FullMatrix & -FiniteElement::get_restriction_matrix (const unsigned int child) const +FiniteElement::get_restriction_matrix (const unsigned int child, + const RefinementCase &refinement_case) const { - Assert (child::children_per_cell, - ExcIndexRange(child, 0, GeometryInfo::children_per_cell)); - Assert (restriction[child].n() != 0, ExcProjectionVoid()); - return restriction[child]; + Assert (refinement_case::isotropic_refinement+1, + ExcIndexRange(refinement_case,0,RefinementCase::isotropic_refinement+1)); + Assert (refinement_case!=RefinementCase::no_refinement, + ExcMessage("Restriction matrices are only available for refined cells!")); + Assert (child::n_children(RefinementCase(refinement_case)), + ExcIndexRange(child,0,GeometryInfo::n_children(RefinementCase(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 (restriction[refinement_case-1][child].n() != 0, ExcProjectionVoid()); + return restriction[refinement_case-1][child]; } template const FullMatrix & -FiniteElement::get_prolongation_matrix (const unsigned int child) const +FiniteElement::get_prolongation_matrix (const unsigned int child, + const RefinementCase &refinement_case) const { - Assert (child::children_per_cell, - ExcIndexRange(child, 0, GeometryInfo::children_per_cell)); - Assert (prolongation[child].n() != 0, ExcEmbeddingVoid()); - return prolongation[child]; + Assert (refinement_case::isotropic_refinement+1, + ExcIndexRange(refinement_case,0,RefinementCase::isotropic_refinement+1)); + Assert (refinement_case!=RefinementCase::no_refinement, + ExcMessage("Prolongation matrices are only available for refined cells!")); + Assert (child::n_children(RefinementCase(refinement_case)), + ExcIndexRange(child,0,GeometryInfo::n_children(RefinementCase(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]; } @@ -403,17 +466,68 @@ template bool FiniteElement::prolongation_is_implemented () const { - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int ref_case=RefinementCase::cut_x; + ref_case::isotropic_refinement+1; ++ref_case) + for (unsigned int c=0; + c::n_children(RefinementCase(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 +bool +FiniteElement::restriction_is_implemented () const +{ + for (unsigned int ref_case=RefinementCase::cut_x; + ref_case::isotropic_refinement+1; ++ref_case) + for (unsigned int c=0; + c::n_children(RefinementCase(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 +bool +FiniteElement::isotropic_prolongation_is_implemented () const +{ + const RefinementCase ref_case=RefinementCase::isotropic_refinement; + + for (unsigned int c=0; + c::n_children(RefinementCase(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; } @@ -422,19 +536,22 @@ FiniteElement::prolongation_is_implemented () const template bool -FiniteElement::restriction_is_implemented () const +FiniteElement::isotropic_restriction_is_implemented () const { - for (unsigned int c=0; c::children_per_cell; ++c) + const RefinementCase ref_case = RefinementCase::isotropic_refinement; + + for (unsigned int c=0; + c::n_children(RefinementCase(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; } @@ -443,9 +560,12 @@ FiniteElement::restriction_is_implemented () const template bool -FiniteElement::constraints_are_implemented () const +FiniteElement::constraints_are_implemented (const internal::SubfaceCase &subface_case) const { - return (this->dofs_per_face == 0) || (interface_constraints.m() != 0); + if (subface_case==internal::SubfaceCase::case_isotropic) + return (this->dofs_per_face == 0) || (interface_constraints.m() != 0); + else + return false; } @@ -461,8 +581,9 @@ FiniteElement::hp_constraints_are_implemented () const template const FullMatrix & -FiniteElement::constraints () const +FiniteElement::constraints (const internal::SubfaceCase &subface_case) const { + Assert (subface_case==internal::SubfaceCase::case_isotropic, ExcConstraintsVoid()); Assert ((this->dofs_per_face == 0) || (interface_constraints.m() != 0), ExcConstraintsVoid()); @@ -815,12 +936,8 @@ unsigned int FiniteElement::memory_consumption () const { return (sizeof(FiniteElementData) + - MemoryConsumption:: - memory_consumption, sizeof(restriction)/sizeof(restriction[0])> - (restriction)+ - MemoryConsumption::memory_consumption - , 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) + diff --git a/deal.II/deal.II/source/fe/fe_abf.cc b/deal.II/deal.II/source/fe/fe_abf.cc index ad07723a6c..ce017586d3 100644 --- a/deal.II/deal.II/source/fe/fe_abf.cc +++ b/deal.II/deal.II/source/fe/fe_abf.cc @@ -75,17 +75,18 @@ FE_ABF::FE_ABF (const unsigned int deg) // will be the correct ones, not // the raw shape functions anymore. - - // initialize the various matrices - for (unsigned int i=0; i::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 > face_embeddings(1<<(dim-1), FullMatrix(this->dofs_per_face, this->dofs_per_face)); @@ -338,8 +339,9 @@ template void FE_ABF::initialize_restriction() { - for (unsigned int i=0;i::children_per_cell;++i) - this->restriction[i].reinit(0,0); + unsigned int iso=RefinementCase::isotropic_refinement-1; + for (unsigned int i=0;i::max_children_per_cell;++i) + this->restriction[iso][i].reinit(0,0); } #else @@ -358,6 +360,7 @@ template void FE_ABF::initialize_restriction() { + unsigned int iso=RefinementCase::isotropic_refinement-1; QGauss q_base (rt_order+1); const unsigned int n_face_points = q_base.size(); // First, compute interpolation on @@ -380,7 +383,7 @@ FE_ABF::initialize_restriction() = this->shape_value_component(i, q_face.point(k), GeometryInfo::unit_normal_direction[face]); - for (unsigned int sub=0;sub::subfaces_per_face;++sub) + for (unsigned int sub=0;sub::max_children_per_face;++sub) { // The weight fuctions for // the coarse face are @@ -389,7 +392,8 @@ FE_ABF::initialize_restriction() Quadrature q_sub = QProjector::project_to_subface(q_base, face, sub); const unsigned int child - = GeometryInfo::child_cell_on_face(face, sub); + = GeometryInfo::child_cell_on_face( + RefinementCase::isotropic_refinement, face, sub); // On a certain face, we must // compute the moments of ALL @@ -412,7 +416,7 @@ FE_ABF::initialize_restriction() // 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(.5) * q_sub.weight(k) * cached_values(i_child, k) @@ -452,7 +456,7 @@ FE_ABF::initialize_restriction() for (unsigned int d=0;dshape_value_component(i, q_cell.point(k), d); - for (unsigned int child=0;child::children_per_cell;++child) + for (unsigned int child=0;child::max_children_per_cell;++child) { Quadrature q_sub = QProjector::project_to_child(q_cell, child); @@ -461,7 +465,7 @@ FE_ABF::initialize_restriction() for (unsigned int d=0;dn();++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) diff --git a/deal.II/deal.II/source/fe/fe_dgp.cc b/deal.II/deal.II/source/fe/fe_dgp.cc index d7c119fbc3..ed3e0b7802 100644 --- a/deal.II/deal.II/source/fe/fe_dgp.cc +++ b/deal.II/deal.II/source/fe/fe_dgp.cc @@ -2,7 +2,7 @@ // $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 @@ -28,14 +28,13 @@ FE_DGP::FE_DGP (const unsigned int degree) std::vector >(FiniteElementData( get_dpo_vector(degree), 1, degree).dofs_per_cell, std::vector(1,true))) { - for (unsigned int i=0; i::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::children_per_cell; ++i) - this->restriction[i].reinit (this->dofs_per_cell, - this->dofs_per_cell); FETools::compute_projection_matrices (*this, this->restriction); } diff --git a/deal.II/deal.II/source/fe/fe_dgp_monomial.cc b/deal.II/deal.II/source/fe/fe_dgp_monomial.cc index 0a3fcd2f12..03c88b2729 100644 --- a/deal.II/deal.II/source/fe/fe_dgp_monomial.cc +++ b/deal.II/deal.II/source/fe/fe_dgp_monomial.cc @@ -2,7 +2,7 @@ // $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 @@ -129,16 +129,13 @@ FE_DGPMonomial::FE_DGPMonomial (const unsigned int degree) // DG doesn't have constraints, so // leave them empty - // initialize the interpolation - // matrices - for (unsigned int i=0; i::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::children_per_cell; ++i) - this->restriction[i].reinit (this->dofs_per_cell, - this->dofs_per_cell); FETools::compute_projection_matrices (*this, this->restriction); } diff --git a/deal.II/deal.II/source/fe/fe_dgp_nonparametric.cc b/deal.II/deal.II/source/fe/fe_dgp_nonparametric.cc index f36d8ae490..5c27e698a2 100644 --- a/deal.II/deal.II/source/fe/fe_dgp_nonparametric.cc +++ b/deal.II/deal.II/source/fe/fe_dgp_nonparametric.cc @@ -2,7 +2,7 @@ // $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 @@ -39,12 +39,26 @@ FE_DGPNonparametric::FE_DGPNonparametric (const unsigned int degree) polynomial_space (Polynomials::Legendre::generate_complete_basis(degree)) { const unsigned int n_dofs = this->dofs_per_cell; - for (unsigned int i=0;i::children_per_cell;++i) + for (unsigned int ref_case = RefinementCase::cut_x; + ref_case::isotropic_refinement+1; ++ref_case) { - this->prolongation[i].reinit(n_dofs, n_dofs); - for (unsigned int j=0;jprolongation[i](j,j) = 1.; + if (dim!=2 && ref_case!=RefinementCase::isotropic_refinement) + // do nothing, as anisotropic + // refinement is not + // implemented so far + continue; + + const unsigned int nc = GeometryInfo::n_children(RefinementCase(ref_case)); + for (unsigned int i=0;iprolongation[ref_case-1][i].reinit (n_dofs, n_dofs); + // Fill prolongation matrices with + // embedding operators + for (unsigned int j=0;jprolongation[ref_case-1][i](j,j) = 1.; + } } + // restriction can be defined // through projection for // discontinuous elements, but is @@ -60,12 +74,13 @@ FE_DGPNonparametric::FE_DGPNonparametric (const unsigned int degree) // } // else // // matrix undefined, set size to zero -// for (unsigned int i=0;i::children_per_cell;++i) +// for (unsigned int i=0;i::max_children_per_cell;++i) // restriction[i].reinit(0, 0); // since not implemented, set to - // "empty" - for (unsigned int i=0;i::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::max_children_per_cell;++i) +// this->restriction[i].reinit(0, 0); // note further, that these // elements have neither support diff --git a/deal.II/deal.II/source/fe/fe_dgq.cc b/deal.II/deal.II/source/fe/fe_dgq.cc index 3e7326db4f..4b06ab4786 100644 --- a/deal.II/deal.II/source/fe/fe_dgq.cc +++ b/deal.II/deal.II/source/fe/fe_dgq.cc @@ -137,17 +137,15 @@ FE_DGQ::FE_DGQ (const unsigned int degree) std::vector >(FiniteElementData( get_dpo_vector(degree),1, degree).dofs_per_cell, std::vector(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::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::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) @@ -201,17 +199,16 @@ FE_DGQ::FE_DGQ (const Quadrature<1>& points) std::vector >(FiniteElementData( get_dpo_vector(points.size()-1),1, points.size()-1).dofs_per_cell, std::vector(1,true))) { - for (unsigned int i=0; i::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::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. diff --git a/deal.II/deal.II/source/fe/fe_nedelec.cc b/deal.II/deal.II/source/fe/fe_nedelec.cc index 34df091c8a..122a0d42ef 100644 --- a/deal.II/deal.II/source/fe/fe_nedelec.cc +++ b/deal.II/deal.II/source/fe/fe_nedelec.cc @@ -566,14 +566,15 @@ template void FE_Nedelec::initialize_embedding () { + unsigned int iso=RefinementCase::isotropic_refinement-1; if ((degree < Matrices::n_embedding_matrices+1) && (Matrices::embedding[degree-1][0] != 0)) - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; c::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 @@ -587,7 +588,7 @@ FE_Nedelec::initialize_embedding () { double sum = 0; for (unsigned int col=0; coldofs_per_cell; ++col) - sum += this->prolongation[c](row,col); + sum += this->prolongation[iso][c](row,col); Assert (std::fabs(sum-.5) < 1e-14, ExcInternalError()); }; @@ -600,6 +601,7 @@ template void FE_Nedelec::initialize_restriction () { + unsigned int iso=RefinementCase::isotropic_refinement-1; switch (dim) { case 2: // 2d @@ -689,14 +691,14 @@ FE_Nedelec::initialize_restriction () // always, in the // canonical direction // of lines - for (unsigned int c=0; c::children_per_cell; ++c) - this->restriction[c].reinit (this->dofs_per_cell, - this->dofs_per_cell); + for (unsigned int c=0; c::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; }; @@ -730,23 +732,23 @@ FE_Nedelec::initialize_restriction () // cell to get at the // values of each of // the 12 lines - for (unsigned int c=0; c::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::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; }; @@ -1285,7 +1287,8 @@ FE_Nedelec::fill_fe_subface_values (const Mapping &m 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 @@ -1307,7 +1310,7 @@ FE_Nedelec::fill_fe_subface_values (const Mapping &m if (flags & update_values) { Assert (fe_data.shape_values[0].size() == - GeometryInfo::subfaces_per_face * + GeometryInfo::max_children_per_face * GeometryInfo::faces_per_cell * n_q_points, ExcInternalError()); @@ -1339,7 +1342,7 @@ FE_Nedelec::fill_fe_subface_values (const Mapping &m { Assert (fe_data.shape_gradients.size() == GeometryInfo::faces_per_cell * - GeometryInfo::subfaces_per_face * + GeometryInfo::max_children_per_face * n_q_points, ExcInternalError()); diff --git a/deal.II/deal.II/source/fe/fe_nedelec_1d.cc b/deal.II/deal.II/source/fe/fe_nedelec_1d.cc index 9a74b050f2..1c5b27b1c1 100644 --- a/deal.II/deal.II/source/fe/fe_nedelec_1d.cc +++ b/deal.II/deal.II/source/fe/fe_nedelec_1d.cc @@ -25,7 +25,7 @@ DEAL_II_NAMESPACE_OPEN 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}}; diff --git a/deal.II/deal.II/source/fe/fe_nedelec_2d.cc b/deal.II/deal.II/source/fe/fe_nedelec_2d.cc index 30aa812bfe..5b30aadf17 100644 --- a/deal.II/deal.II/source/fe/fe_nedelec_2d.cc +++ b/deal.II/deal.II/source/fe/fe_nedelec_2d.cc @@ -73,7 +73,7 @@ namespace FE_Nedelec_2d 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 } diff --git a/deal.II/deal.II/source/fe/fe_nedelec_3d.cc b/deal.II/deal.II/source/fe/fe_nedelec_3d.cc index a61adb329b..0943d8f9fe 100644 --- a/deal.II/deal.II/source/fe/fe_nedelec_3d.cc +++ b/deal.II/deal.II/source/fe/fe_nedelec_3d.cc @@ -172,7 +172,7 @@ namespace FE_Nedelec_3d 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, diff --git a/deal.II/deal.II/source/fe/fe_poly_tensor.cc b/deal.II/deal.II/source/fe/fe_poly_tensor.cc index 5c1c895bf9..34cb8648c4 100644 --- a/deal.II/deal.II/source/fe/fe_poly_tensor.cc +++ b/deal.II/deal.II/source/fe/fe_poly_tensor.cc @@ -731,7 +731,8 @@ FE_PolyTensor::fill_fe_subface_values ( 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); diff --git a/deal.II/deal.II/source/fe/fe_q.cc b/deal.II/deal.II/source/fe/fe_q.cc index 9290fc67ce..29aa0d8eca 100644 --- a/deal.II/deal.II/source/fe/fe_q.cc +++ b/deal.II/deal.II/source/fe/fe_q.cc @@ -1124,7 +1124,7 @@ FE_Q<3>::initialize_constraints () // lines 9-16 for (unsigned int face=0; face::faces_per_cell; ++face) for (unsigned int subface=0; - subface::subfaces_per_face; ++subface) + subface::max_children_per_face; ++subface) { QProjector::project_to_subface(qline, face, subface, p_line); constraint_points.insert(constraint_points.end(), @@ -1139,7 +1139,7 @@ FE_Q<3>::initialize_constraints () inner_points[i++] = Point (ix*step, iy*step); for (unsigned int child=0; - child::children_per_cell; ++child) + child::max_children_per_cell; ++child) for (unsigned int i=0; i::child_to_cell_coordinates(inner_points[i], child)); @@ -1269,6 +1269,8 @@ template void FE_Q::initialize_embedding () { + unsigned int iso=RefinementCase::isotropic_refinement-1; + // compute the interpolation // matrices in much the same way as // we do for the constraints. it's @@ -1282,10 +1284,10 @@ FE_Q::initialize_embedding () const std::vector &index_map= this->poly_space.get_numbering(); - for (unsigned int child=0; child::children_per_cell; ++child) - this->prolongation[child].reinit (this->dofs_per_cell, - this->dofs_per_cell); - for (unsigned int child=0; child::children_per_cell; ++child) + for (unsigned int child=0; child::max_children_per_cell; ++child) + this->prolongation[iso][child].reinit (this->dofs_per_cell, + this->dofs_per_cell); + for (unsigned int child=0; child::max_children_per_cell; ++child) { for (unsigned int j=0; jdofs_per_cell; ++j) { @@ -1378,15 +1380,15 @@ FE_Q::initialize_embedding () // 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; idofs_per_cell; ++i) for (unsigned int j=0; jdofs_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 @@ -1396,7 +1398,7 @@ FE_Q::initialize_embedding () { double sum = 0; for (unsigned int col=0; coldofs_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()); } @@ -1409,6 +1411,8 @@ template void FE_Q::initialize_restriction () { + unsigned int iso=RefinementCase::isotropic_refinement-1; + // for these Lagrange interpolation // polynomials, construction of the // restriction matrices is @@ -1454,8 +1458,8 @@ FE_Q::initialize_restriction () // 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::children_per_cell; ++c) - this->restriction[c].reinit (this->dofs_per_cell, this->dofs_per_cell); + for (unsigned int c=0; c::max_children_per_cell; ++c) + this->restriction[iso][c].reinit (this->dofs_per_cell, this->dofs_per_cell); for (unsigned int i=0; idofs_per_cell; ++i) { const Point p_cell @@ -1487,13 +1491,13 @@ FE_Q::initialize_restriction () // then find the children on // which the interpolation // point is located - for (unsigned int child=0; child::children_per_cell; + for (unsigned int child=0; child::max_children_per_cell; ++child) { // first initialize this // column of the matrix for (unsigned int j=0; jdofs_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 @@ -1528,7 +1532,7 @@ FE_Q::initialize_restriction () // 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.; } } } diff --git a/deal.II/deal.II/source/fe/fe_q_hierarchical.cc b/deal.II/deal.II/source/fe/fe_q_hierarchical.cc index 7a4810a9d9..c00a74f450 100644 --- a/deal.II/deal.II/source/fe/fe_q_hierarchical.cc +++ b/deal.II/deal.II/source/fe/fe_q_hierarchical.cc @@ -68,11 +68,11 @@ FE_Q_Hierarchical::FE_Q_Hierarchical (const unsigned int degree) // @p{interface_constraints} matrices // for all dimensions. std::vector > - dofs_cell (GeometryInfo<1>::children_per_cell, + dofs_cell (GeometryInfo<1>::max_children_per_cell, FullMatrix (2*this->dofs_per_vertex + this->dofs_per_line, 2*this->dofs_per_vertex + this->dofs_per_line)); std::vector > - dofs_subcell (GeometryInfo<1>::children_per_cell, + dofs_subcell (GeometryInfo<1>::max_children_per_cell, FullMatrix (2*this->dofs_per_vertex + this->dofs_per_line, 2*this->dofs_per_vertex + this->dofs_per_line)); // build these fields, as they are @@ -132,7 +132,7 @@ FE_Q_Hierarchical::build_dofs_cell (std::vector > &dofs_ { const unsigned int dofs_1d = 2*this->dofs_per_vertex + this->dofs_per_line; - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; c::max_children_per_cell; ++c) for (unsigned int j=0; j > &dofs_subcell) for (unsigned int i=0; iinterface_constraints(0,i) = dofs_subcell[0](1,i); // edge nodes - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; c::max_children_per_cell; ++c) for (unsigned int i=0; iinterface_constraints(1 + c*(degree-1) + j - 2,i) = @@ -329,24 +329,26 @@ FE_Q_Hierarchical:: initialize_embedding_and_restriction (const std::vector > &dofs_cell, const std::vector > &dofs_subcell) { + unsigned int iso=RefinementCase::isotropic_refinement-1; + const unsigned int dofs_1d = 2*this->dofs_per_vertex + this->dofs_per_line; const std::vector &renumber= this->poly_space.get_numbering(); - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; c::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::children_per_cell; ++c) + for (unsigned int c=0; c::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; } @@ -367,20 +369,20 @@ initialize_embedding_and_restriction (const std::vector > &do { case 2: { - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; c::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, @@ -391,7 +393,7 @@ initialize_embedding_and_restriction (const std::vector > &do case 3: { - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; c::max_children_per_cell; ++c) { // left/right face: 0/1 const unsigned int c0 = c%2; @@ -400,7 +402,7 @@ initialize_embedding_and_restriction (const std::vector > &do // 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, @@ -408,7 +410,7 @@ initialize_embedding_and_restriction (const std::vector > &do 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, diff --git a/deal.II/deal.II/source/fe/fe_raviart_thomas.cc b/deal.II/deal.II/source/fe/fe_raviart_thomas.cc index 0fa237210c..4580642ebb 100644 --- a/deal.II/deal.II/source/fe/fe_raviart_thomas.cc +++ b/deal.II/deal.II/source/fe/fe_raviart_thomas.cc @@ -68,25 +68,25 @@ FE_RaviartThomas::FE_RaviartThomas (const unsigned int deg) // will be the correct ones, not // the raw shape functions anymore. - - // initialize the various matrices - for (unsigned int i=0; i::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 face_embeddings[GeometryInfo::subfaces_per_face]; - for (unsigned int i=0; i::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 face_embeddings[GeometryInfo::max_children_per_face]; + for (unsigned int i=0; i::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::subfaces_per_face;++d) + for (unsigned int d=0;d::max_children_per_face;++d) for (unsigned int i=0;i void FE_RaviartThomas<1>::initialize_restriction() { - for (unsigned int i=0;i::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::max_children_per_cell;++i) + this->restriction[0][i].reinit(0,0); } #endif @@ -281,6 +284,8 @@ template void FE_RaviartThomas::initialize_restriction() { + const unsigned int iso=RefinementCase::isotropic_refinement-1; + QGauss q_base (rt_order+1); const unsigned int n_face_points = q_base.size(); // First, compute interpolation on @@ -303,7 +308,7 @@ FE_RaviartThomas::initialize_restriction() = this->shape_value_component(i, q_face.point(k), GeometryInfo::unit_normal_direction[face]); - for (unsigned int sub=0;sub::subfaces_per_face;++sub) + for (unsigned int sub=0;sub::max_children_per_face;++sub) { // The weight fuctions for // the coarse face are @@ -312,7 +317,8 @@ FE_RaviartThomas::initialize_restriction() Quadrature q_sub = QProjector::project_to_subface(q_base, face, sub); const unsigned int child - = GeometryInfo::child_cell_on_face(face, sub); + = GeometryInfo::child_cell_on_face( + RefinementCase::isotropic_refinement, face, sub); // On a certain face, we must // compute the moments of ALL @@ -335,8 +341,8 @@ FE_RaviartThomas::initialize_restriction() // 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(.5) * q_sub.weight(k) * cached_values(i_child, k) * this->shape_value_component(face*this->dofs_per_face+i_face, @@ -375,7 +381,7 @@ FE_RaviartThomas::initialize_restriction() for (unsigned int d=0;dshape_value_component(i, q_cell.point(k), d); - for (unsigned int child=0;child::children_per_cell;++child) + for (unsigned int child=0;child::max_children_per_cell;++child) { Quadrature q_sub = QProjector::project_to_child(q_cell, child); @@ -384,8 +390,8 @@ FE_RaviartThomas::initialize_restriction() for (unsigned int d=0;dn();++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)); diff --git a/deal.II/deal.II/source/fe/fe_raviart_thomas_nodal.cc b/deal.II/deal.II/source/fe/fe_raviart_thomas_nodal.cc index b023fbd6cf..7948173b86 100644 --- a/deal.II/deal.II/source/fe/fe_raviart_thomas_nodal.cc +++ b/deal.II/deal.II/source/fe/fe_raviart_thomas_nodal.cc @@ -68,19 +68,29 @@ FE_RaviartThomasNodal::FE_RaviartThomasNodal (const unsigned int deg) // will be the correct ones, not // the raw shape functions anymore. - for (unsigned int i=0; i::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::cut_x; + ref_case::isotropic_refinement+1; ++ref_case) + { + const unsigned int nc = GeometryInfo::n_children(RefinementCase(ref_case)); + + for (unsigned int i=0;iprolongation[ref_case-1][i].reinit (n_dofs, n_dofs); + } + // Fill prolongation matrices with embedding operators FETools::compute_embedding_matrices (*this, this->prolongation); - - FullMatrix face_embeddings[GeometryInfo::subfaces_per_face]; - for (unsigned int i=0; i::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 face_embeddings[GeometryInfo::max_children_per_face]; + for (unsigned int i=0; i::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::subfaces_per_face;++d) + for (unsigned int d=0;d::max_children_per_face;++d) for (unsigned int i=0;i &mapping, { unsigned int offset = 0; if (face_no != invalid_face_number) - offset = (sub_no == invalid_face_number) - ? face_no * n_q_points - :(face_no * GeometryInfo::subfaces_per_face - + sub_no) * n_q_points; + if (sub_no == invalid_face_number) + offset=QProjector::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::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); } } @@ -1633,93 +1644,100 @@ void FESystem::initialize () { 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::cut_x; + ref_case::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::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::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::n_children(RefinementCase(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::n_children(RefinementCase(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; idofs_per_cell; ++i) - for (unsigned int j=0; jdofs_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::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; idofs_per_cell; ++i) + for (unsigned int j=0; jdofs_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::n_children(RefinementCase(ref_case)); ++child) + { + if (do_restriction) + this->restriction[ref_case-1][child] (i,j) + = (base_element(base) + .get_restriction_matrix(child, RefinementCase(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(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 diff --git a/deal.II/deal.II/source/fe/fe_tools.cc b/deal.II/deal.II/source/fe/fe_tools.cc index 8aecda9030..83f3e21908 100644 --- a/deal.II/deal.II/source/fe/fe_tools.cc +++ b/deal.II/deal.II/source/fe/fe_tools.cc @@ -560,112 +560,118 @@ FETools::compute_node_matrix( template void FETools::compute_embedding_matrices(const FiniteElement& fe, - FullMatrix (&matrices)[GeometryInfo::children_per_cell]) + std::vector > >& matrices) { - const unsigned int nc = GeometryInfo::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::cut_x; + ref_case::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::n_children(RefinementCase(ref_case)); + for (unsigned int i=0;i 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 tria; + GridGenerator::hyper_cube (tria, 0, 1); + tria.begin_active()->set_refine_flag(RefinementCase(ref_case)); + tria.execute_coarsening_and_refinement(); - MappingCartesian mapping; - QGauss q_fine(degree+1); - const unsigned int nq = q_fine.size(); + MappingCartesian mapping; + QGauss q_fine(degree+1); + const unsigned int nq = q_fine.size(); - FEValues fine (mapping, fe, q_fine, - update_quadrature_points | update_JxW_values | update_values); + FEValues 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 A(nq*nd, n); - for (unsigned int d=0;d A(nq*nd, n); + for (unsigned int d=0;d H(A); + Householder H(A); - Vector v_coarse(nq*nd); - Vector v_fine(n); + Vector v_coarse(nq*nd); + Vector v_fine(n); - unsigned int cell_number = 0; - for (typename Triangulation::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 q_coarse (fine.get_quadrature_points(), - fine.get_JxW_values()); - FEValues coarse (mapping, fe, q_coarse, update_values); - coarse.reinit(tria.begin(0)); - - FullMatrix &this_matrix = matrices[cell_number]; - - // Compute this once for each - // coarse grid basis function - for (unsigned int i=0;i::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 q_coarse (fine.get_quadrature_points(), + fine.get_JxW_values()); + FEValues coarse (mapping, fe, q_coarse, update_values); + coarse.reinit(tria.begin(0)); + + FullMatrix &this_matrix = matrices[ref_case-1][cell_number]; + + // Compute this once for each + // coarse grid basis function + for (unsigned int i=0;i::n_children(RefinementCase(ref_case)), + ExcInternalError()); } - Assert (cell_number == GeometryInfo::children_per_cell, - ExcInternalError()); } @@ -675,11 +681,11 @@ FETools::compute_embedding_matrices(const FiniteElement& fe, template void FETools::compute_face_embedding_matrices(const FiniteElement& fe, - FullMatrix (&matrices)[GeometryInfo::subfaces_per_face], + FullMatrix (&matrices)[GeometryInfo::max_children_per_face], const unsigned int face_coarse, const unsigned int face_fine) { - const unsigned int nc = GeometryInfo::subfaces_per_face; + const unsigned int nc = GeometryInfo::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; @@ -785,7 +791,7 @@ FETools::compute_face_embedding_matrices(const FiniteElement& fe, - for (unsigned int cell_number = 0; cell_number < GeometryInfo::subfaces_per_face; + for (unsigned int cell_number = 0; cell_number < GeometryInfo::max_children_per_face; ++cell_number) { const Quadrature q_coarse @@ -793,8 +799,8 @@ FETools::compute_face_embedding_matrices(const FiniteElement& fe, FEValues coarse (mapping, fe, q_coarse, update_values); typename Triangulation::active_cell_iterator fine_cell - = tria.begin(0)->child(GeometryInfo::child_cell_on_face(face_coarse, - cell_number)); + = tria.begin(0)->child(GeometryInfo::child_cell_on_face( + tria.begin(0)->refinement_case(), face_coarse, cell_number)); fine.reinit(fine_cell); coarse.reinit(tria.begin(0)); @@ -841,113 +847,127 @@ FETools::compute_face_embedding_matrices(const FiniteElement& fe, template void FETools::compute_projection_matrices(const FiniteElement& fe, - FullMatrix (&matrices)[GeometryInfo::children_per_cell]) + std::vector > >& matrices) { - const unsigned int nc = GeometryInfo::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::cut_x; + ref_case::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 tr; - GridGenerator::hyper_cube (tr, 0, 1); - tr.refine_global(1); - - MappingCartesian mapping; - QGauss q_fine(degree+1); - const unsigned int nq = q_fine.size(); - - FEValues coarse (mapping, fe, q_fine, - update_quadrature_points | update_JxW_values | update_values); - FEValues fine (mapping, fe, q_fine, - update_quadrature_points | update_JxW_values | update_values); - - typename Triangulation::cell_iterator coarse_cell - = tr.begin(0); - // Compute the coarse level mass - // matrix - coarse.reinit(coarse_cell); - FullMatrix A(n, n); - for (unsigned int k=0;k H(A); + const unsigned int + nc = GeometryInfo::n_children(RefinementCase(ref_case)); - Vector v_coarse(n); - Vector v_fine(n); + for (unsigned int i=0;i::children_per_cell;++cell_number) - { - FullMatrix &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 q_coarse (fine.get_quadrature_points(), - fine.get_JxW_values()); - FEValues coarse (mapping, fe, q_coarse, update_values); + Triangulation tr; + GridGenerator::hyper_cube (tr, 0, 1); + tr.begin_active()->set_refine_flag(RefinementCase(ref_case)); + tr.execute_coarsening_and_refinement(); + + MappingCartesian mapping; + QGauss q_fine(degree+1); + const unsigned int nq = q_fine.size(); + + FEValues coarse (mapping, fe, q_fine, + update_quadrature_points | + update_JxW_values | + update_values); + FEValues fine (mapping, fe, q_fine, + update_quadrature_points | + update_JxW_values | + update_values); + + typename Triangulation::cell_iterator coarse_cell + = tr.begin(0); + // Compute the coarse level mass + // matrix coarse.reinit(coarse_cell); + FullMatrix A(n, n); + for (unsigned int k=0;k H(A); + + Vector v_coarse(n); + Vector v_fine(n); + + for (unsigned int cell_number=0;cell_number &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 q_coarse (fine.get_quadrature_points(), + fine.get_JxW_values()); + FEValues 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 &dof1, // cell has active // children bool active_children=false; - for (unsigned int child_n=0; - child_n::children_per_cell; ++child_n) + for (unsigned int child_n=0; child_nn_children(); ++child_n) if (cell->child(child_n)->active()) { active_children=true; @@ -1875,16 +1894,16 @@ void FETools::get_projection_matrix template void FETools::compute_embedding_matrices -(const FiniteElement &, FullMatrix (&)[GeometryInfo::children_per_cell]); +(const FiniteElement &, std::vector > >&); template void FETools::compute_face_embedding_matrices -(const FiniteElement &, FullMatrix (&matrices)[GeometryInfo::subfaces_per_face], +(const FiniteElement &, FullMatrix (&matrices)[GeometryInfo::max_children_per_face], unsigned int, unsigned int); template void FETools::compute_projection_matrices -(const FiniteElement &, FullMatrix (&)[GeometryInfo::children_per_cell]); +(const FiniteElement &, std::vector > >&); template void FETools::interpolate diff --git a/deal.II/deal.II/source/fe/fe_values.cc b/deal.II/deal.II/source/fe/fe_values.cc index 62247421f5..991cd04fd8 100644 --- a/deal.II/deal.II/source/fe/fe_values.cc +++ b/deal.II/deal.II/source/fe/fe_values.cc @@ -308,6 +308,12 @@ FEValuesData::initialize (const unsigned int n_quadrature_points, 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); @@ -1378,7 +1384,9 @@ void FEValues::do_reinit () 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, @@ -1761,11 +1769,11 @@ void FESubfaceValues::reinit (const typename DoFHandler::cell_iterator // we must use following workaround // of two separate assertions Assert (cell->face(face_no)->has_children() || - subface_no < GeometryInfo::subfaces_per_face, - ExcIndexRange (subface_no, 0, GeometryInfo::subfaces_per_face)); + subface_no < GeometryInfo::max_children_per_face, + ExcIndexRange (subface_no, 0, GeometryInfo::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 " @@ -1806,8 +1814,8 @@ void FESubfaceValues::reinit (const typename hp::DoFHandler::cell_iter typename FEValuesBase::ExcFEDontMatch()); Assert (face_no < GeometryInfo::faces_per_cell, ExcIndexRange (face_no, 0, GeometryInfo::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 " @@ -1841,8 +1849,8 @@ void FESubfaceValues::reinit (const typename MGDoFHandler::cell_iterat typename FEValuesBase::ExcFEDontMatch()); Assert (face_no < GeometryInfo::faces_per_cell, ExcIndexRange (face_no, 0, GeometryInfo::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 " @@ -1899,18 +1907,77 @@ template void FESubfaceValues::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::cell_iterator cell=*this->present_cell; - unsigned int real_subface_no=subface_no; - if (dim==3) - real_subface_no=GeometryInfo::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, diff --git a/deal.II/deal.II/source/fe/mapping_cartesian.cc b/deal.II/deal.II/source/fe/mapping_cartesian.cc index 2a0d0010c9..323b5afc24 100644 --- a/deal.II/deal.II/source/fe/mapping_cartesian.cc +++ b/deal.II/deal.II/source/fe/mapping_cartesian.cc @@ -2,7 +2,7 @@ // $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 @@ -148,11 +148,25 @@ MappingCartesian::compute_fill (const typename Triangulation::cell_ite Assert (face_no+1 < GeometryInfo::faces_per_cell+1, ExcIndexRange (face_no, 0, GeometryInfo::faces_per_cell)); - Assert ((sub_no == invalid_face_number) - || - (sub_no+1 < GeometryInfo::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::max_children_per_face+1), ExcIndexRange (sub_no, 0, - GeometryInfo::subfaces_per_face)); + GeometryInfo::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 @@ -211,10 +225,11 @@ MappingCartesian::compute_fill (const typename Triangulation::cell_ite : // called from FESubfaceValues QProjector::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::cell_iterator& cell, const Quadrature& q, typename Mapping::InternalDataBase& mapping_data, std::vector >& quadrature_points, - std::vector& JxW_values) const + std::vector& JxW_values, + std::vector >& jacobians, + std::vector >& jacobian_grads) const { // convert data object to internal // data for this class. fails with @@ -314,6 +331,21 @@ fill_fe_values (const typename Triangulation::cell_iterator& cell, for (unsigned int i=0; i(); + for (unsigned int j=0; j(); } @@ -397,8 +429,24 @@ MappingCartesian::fill_fe_subface_values (const typename Triangulation J *= data.length[d]; if (data.current_update_flags() & update_JxW_values) - for (unsigned int i=0; i::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::max_children_per_face; + for (unsigned int i=0; i::compute_shapes_virtual (const std::vector > &unit_poin grads.resize(n_shape_functions); } - // dummy variable of size 0 +// // dummy variable of size 0 std::vector > 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) @@ -232,6 +238,10 @@ MappingQ::compute_shapes_virtual (const std::vector > &unit_poin if (data.shape_derivatives.size()!=0) for (unsigned int i=0; i::fill_fe_values (const typename Triangulation::cell_iterator const Quadrature &q, typename Mapping::InternalDataBase &mapping_data, std::vector > &quadrature_points, - std::vector &JxW_values) const + std::vector &JxW_values, + std::vector > &jacobians, + std::vector > &jacobian_grads) const { // convert data object to internal // data for this class. fails with @@ -321,7 +333,8 @@ MappingQ::fill_fe_values (const typename Triangulation::cell_iterator p_data=&data; MappingQ1::fill_fe_values(cell, q, *p_data, - quadrature_points, JxW_values); + quadrature_points, JxW_values, + jacobians, jacobian_grads); } @@ -371,7 +384,7 @@ MappingQ::fill_fe_face_values (const typename Triangulation::cell_iter 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::DataSetDescriptor:: face (face_no, @@ -435,7 +448,7 @@ MappingQ::fill_fe_subface_values (const typename Triangulation::cell_i 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::DataSetDescriptor:: subface (face_no, sub_no, diff --git a/deal.II/deal.II/source/fe/mapping_q1.cc b/deal.II/deal.II/source/fe/mapping_q1.cc index 1393441f89..877748f947 100644 --- a/deal.II/deal.II/source/fe/mapping_q1.cc +++ b/deal.II/deal.II/source/fe/mapping_q1.cc @@ -108,6 +108,14 @@ MappingQ1<1>::compute_shapes_virtual (const std::vector > &unit_points, 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; + } + } } @@ -149,6 +157,27 @@ MappingQ1<2>::compute_shapes_virtual (const std::vector > &unit_points, 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; + } } } @@ -211,6 +240,86 @@ MappingQ1<3>::compute_shapes_virtual (const std::vector > &unit_points, 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; + } } } @@ -232,7 +341,9 @@ MappingQ1::update_once (const UpdateFlags in) const | 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; @@ -252,7 +363,9 @@ MappingQ1::update_each (const UpdateFlags in) const | 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 @@ -280,6 +393,8 @@ MappingQ1::update_each (const UpdateFlags in) const if (out & (update_covariant_transformation | update_JxW_values + | update_jacobians + | update_jacobian_grads | update_boundary_forms | update_normal_vectors)) out |= update_contravariant_transformation; @@ -325,6 +440,9 @@ MappingQ1::compute_data (const UpdateFlags update_flags, 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); } @@ -488,14 +606,7 @@ MappingQ1::compute_fill (const typename Triangulation::cell_iterator & 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 @@ -530,10 +641,10 @@ MappingQ1::compute_fill (const typename Triangulation::cell_iterator & for (unsigned int k=0; k::fill_fe_values (const typename Triangulation::cell_iterator const Quadrature &q, typename Mapping::InternalDataBase &mapping_data, std::vector > &quadrature_points, - std::vector &JxW_values) const + std::vector &JxW_values, + std::vector > &jacobians, + std::vector > &jacobian_grads) const { InternalData *data_ptr = dynamic_cast (&mapping_data); Assert(data_ptr!=0, ExcInternalError()); @@ -588,6 +701,38 @@ MappingQ1::fill_fe_values (const typename Triangulation::cell_iterator for (unsigned int point=0; point()); + + for (unsigned int point=0; point void MappingQ1::compute_fill_face (const typename Triangulation::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 &weights, @@ -675,8 +820,12 @@ MappingQ1::compute_fill_face (const typename Triangulation::cell_itera if (update_flags & update_JxW_values) { JxW_values[i] = f * weights[i]; - if (is_subface) - JxW_values[i] /= GeometryInfo::subfaces_per_face; + if (subface_no!=deal_II_numbers::invalid_unsigned_int) + { + const double area_ratio=GeometryInfo::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; @@ -720,7 +869,7 @@ MappingQ1::fill_fe_face_values (const typename Triangulation::cell_ite 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), @@ -756,13 +905,14 @@ MappingQ1::fill_fe_subface_values (const typename Triangulation::cell_ 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, @@ -779,7 +929,7 @@ 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 &, diff --git a/deal.II/deal.II/source/grid/grid_refinement.cc b/deal.II/deal.II/source/grid/grid_refinement.cc index 0852d5a066..c1207500ff 100644 --- a/deal.II/deal.II/source/grid/grid_refinement.cc +++ b/deal.II/deal.II/source/grid/grid_refinement.cc @@ -205,26 +205,36 @@ GridRefinement::refine_and_coarsen_fixed_number (Triangulation &tria, // 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::children_per_cell / - (GeometryInfo::children_per_cell - 1); + GeometryInfo::max_children_per_cell / + (GeometryInfo::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::children_per_cell + // C=GeometryInfo::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 (tria.n_active_cells() - + refine_cells * (GeometryInfo::children_per_cell - 1) + + refine_cells * (GeometryInfo::max_children_per_cell - 1) - (coarsen_cells * - (GeometryInfo::children_per_cell - 1) / - GeometryInfo::children_per_cell)) + (GeometryInfo::max_children_per_cell - 1) / + GeometryInfo::max_children_per_cell)) > max_n_cells) { @@ -241,10 +251,10 @@ GridRefinement::refine_and_coarsen_fixed_number (Triangulation &tria, 1. * (max_n_cells - tria.n_active_cells()) / - (refine_cells * (GeometryInfo::children_per_cell - 1) + (refine_cells * (GeometryInfo::max_children_per_cell - 1) - (coarsen_cells * - (GeometryInfo::children_per_cell - 1) / - GeometryInfo::children_per_cell)); + (GeometryInfo::max_children_per_cell - 1) / + GeometryInfo::max_children_per_cell)); refine_cells = static_cast (refine_cells * alpha); coarsen_cells = static_cast (coarsen_cells * alpha); } @@ -325,16 +335,22 @@ GridRefinement::refine_and_coarsen_fixed_fraction (Triangulation &tria, // 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 (tria.n_active_cells() - + refine_cells * (GeometryInfo::children_per_cell - 1) + + refine_cells * (GeometryInfo::max_children_per_cell - 1) - (coarsen_cells * - (GeometryInfo::children_per_cell - 1) / - GeometryInfo::children_per_cell)) + (GeometryInfo::max_children_per_cell - 1) / + GeometryInfo::max_children_per_cell)) > max_n_cells) { diff --git a/deal.II/deal.II/source/grid/grid_tools.cc b/deal.II/deal.II/source/grid/grid_tools.cc index 487443be79..c4e4d402fe 100644 --- a/deal.II/deal.II/source/grid/grid_tools.cc +++ b/deal.II/deal.II/source/grid/grid_tools.cc @@ -950,8 +950,6 @@ GridTools::get_finest_common_cells (const Container &mesh_1, 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 @@ -994,7 +992,9 @@ GridTools::get_finest_common_cells (const Container &mesh_1, && cell_pair->second->has_children()) { - for (unsigned int c=0; c::children_per_cell; ++c) + Assert(cell_pair->first->refinement_case()== + cell_pair->second->refinement_case(), ExcNotImplemented()); + for (unsigned int c=0; cfirst->n_children(); ++c) cell_list.push_back (std::make_pair (cell_pair->first->child(c), cell_pair->second->child(c))); @@ -1016,13 +1016,17 @@ GridTools::get_finest_common_cells (const Container &mesh_1, ++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; diff --git a/deal.II/deal.II/source/grid/intergrid_map.cc b/deal.II/deal.II/source/grid/intergrid_map.cc index 0a77d6db36..d0ccbe2c55 100644 --- a/deal.II/deal.II/source/grid/intergrid_map.cc +++ b/deal.II/deal.II/source/grid/intergrid_map.cc @@ -133,9 +133,19 @@ InterGridMap::set_mapping (const cell_iterator &src_cell, // 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::children_per_cell; ++c) - set_mapping (src_cell->child(c), - dst_cell->child(c)); + { + Assert(src_cell->n_children()== + GeometryInfo::max_children_per_cell, + ExcNotImplemented()); + Assert(dst_cell->n_children()== + GeometryInfo::max_children_per_cell, + ExcNotImplemented()); + Assert(src_cell->refinement_case()==dst_cell->refinement_case(), + ExcNotImplemented()); + for (unsigned int c=0; c::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()) diff --git a/deal.II/deal.II/source/grid/tria.cc b/deal.II/deal.II/source/grid/tria.cc index ca121b498a..e17af5fadf 100644 --- a/deal.II/deal.II/source/grid/tria.cc +++ b/deal.II/deal.II/source/grid/tria.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,230 @@ 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 + bool cell_will_be_coarsened(const TriaIterator > &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; cchild(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; cchild(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 + bool face_will_be_refined_by_neighbor_internal(const TriaIterator > &cell, + const unsigned int face_no, + RefinementCase &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::no_refinement; + + const typename Triangulation::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 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 face_ref_case= + GeometryInfo::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::no_refinement) + { + const typename Triangulation::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; cn_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::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 + bool face_will_be_refined_by_neighbor(const TriaIterator > &cell, + const unsigned int face_no) + { + RefinementCase dummy = RefinementCase::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 + bool face_will_be_refined_by_neighbor(const TriaActiveIterator > &cell, + const unsigned int face_no, + RefinementCase &expected_face_ref_case) + { + return face_will_be_refined_by_neighbor_internal(cell, face_no, + expected_face_ref_case); + } + +}// end of anonymous namespace + + template const StraightBoundary Triangulation::straight_boundary = StraightBoundary(); @@ -50,6 +275,7 @@ template Triangulation::Triangulation (const MeshSmoothing smooth_grid) : Subscriptor (), faces(NULL), + anisotropic_refinement(false), smooth_grid(smooth_grid) { // set default boundary for all @@ -234,9 +460,10 @@ void Triangulation::copy_triangulation (const Triangulation &old_tria) // 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(*old_tria.faces); @@ -309,7 +536,7 @@ void Triangulation<1>::create_triangulation (const std::vector > &v, // reserve enough space levels.push_back (new internal::Triangulation::TriaLevel); 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 (); @@ -593,8 +820,8 @@ void Triangulation<2>::create_triangulation (const std::vector > &v, levels.push_back (new internal::Triangulation::TriaLevel); faces = new internal::Triangulation::TriaFaces; 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) @@ -1017,7 +1244,7 @@ Triangulation<3>::create_triangulation (const std::vector > &v, levels.push_back (new internal::Triangulation::TriaLevel); faces = new internal::Triangulation::TriaFaces; 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) @@ -1197,7 +1424,7 @@ Triangulation<3>::create_triangulation (const std::vector > &v, // 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) { @@ -2018,12 +2245,14 @@ void Triangulation::refine_global (const unsigned int times) template void Triangulation::save_refine_flags (std::vector &v) const { - v.resize (n_active_cells(), false); + v.resize (dim*n_active_cells(), false); std::vector::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; jrefine_flag_set() & (1<::load_refine_flags (std::istream &in) template void Triangulation::load_refine_flags (const std::vector &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::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::isotropic_refinement+1, + ExcGridReadError()); + if (ref_case>0) + cell->set_refine_flag(RefinementCase(ref_case)); + else + cell->clear_refine_flag(); + } } @@ -2118,6 +2356,13 @@ void Triangulation::load_coarsen_flags (const std::vector &v) } +template +bool Triangulation::get_anisotropic_refinement_flag() const +{ + return anisotropic_refinement; +} + + #if deal_II_dimension == 1 template <> @@ -2138,9 +2383,10 @@ void Triangulation<1>::clear_user_pointers () template <> -void Triangulation<1>::clear_user_flags () +void Triangulation<1>::clear_user_flags_line () { - clear_user_flags_line(); + for (unsigned int level=0; levelcells.clear_user_flags(); } @@ -2150,11 +2396,19 @@ void Triangulation<1>::clear_user_flags_quad () {} + template <> void Triangulation<1>::clear_user_flags_hex () {} + +template <> +void Triangulation<1>::clear_user_flags () +{ + clear_user_flags_line(); +} + #endif @@ -2179,10 +2433,10 @@ void Triangulation<2>::clear_user_pointers () 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; levelcells.clear_user_flags(); } @@ -2192,6 +2446,14 @@ void Triangulation<2>::clear_user_flags_hex () {} + +template <> +void Triangulation<2>::clear_user_flags () +{ + clear_user_flags_line (); + clear_user_flags_quad (); +} + #endif @@ -2217,49 +2479,44 @@ void Triangulation<3>::clear_user_pointers () 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 -void Triangulation::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; levelcells.clear_user_flags(); } -template -void Triangulation::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 -void Triangulation::clear_user_flags_hex () +void Triangulation::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 @@ -4987,12 +5244,14 @@ Triangulation<1>::execute_refinement () // 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; } @@ -5068,7 +5327,7 @@ Triangulation<1>::execute_refinement () 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), @@ -5212,12 +5471,27 @@ Triangulation<2>::execute_refinement () } - // 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 @@ -5227,7 +5501,6 @@ Triangulation<2>::execute_refinement () // - 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 @@ -5235,45 +5508,72 @@ Triangulation<2>::execute_refinement () // 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::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::faces_per_cell; ++line_no) { - line_iterator line = cell->line(line_no); - - if (line->has_children() == false) - line->set_user_flag (); + if (GeometryInfo::face_refinement_case( + cell->refine_flag_set(), line_no)==RefinementCase::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 @@ -5286,16 +5586,16 @@ Triangulation<2>::execute_refinement () // 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 @@ -5304,14 +5604,22 @@ Triangulation<2>::execute_refinement () 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 @@ -5337,16 +5645,16 @@ Triangulation<2>::execute_refinement () // 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()) { @@ -5371,24 +5679,37 @@ Triangulation<2>::execute_refinement () // 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 @@ -5423,463 +5744,98 @@ Triangulation<2>::execute_refinement () } } + // 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(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::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; levelcells.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::faces_per_cell; - ++face_no) - for (unsigned int child_no=0; - child_no::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::children_per_cell; - raw_cell_iterator subcells[n_children]; - for (unsigned int i=0; iused() == 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; iset_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::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::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::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::faces_per_cell, - ExcInternalError()); - - // and set - // the - // neighbors - // accordingly - for (unsigned int c=0; - c::subfaces_per_face; ++c) - { - neighbor_cells[face][c] - = neighbor->child(GeometryInfo:: - 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::faces_per_cell; ++nb) - for (unsigned int subface=0; - subface::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::faces_per_cell; ++face) - if (neighbor->neighbor(face) == cell) - break; - - Assert (face::faces_per_cell, - ExcInternalError()); - - neighbor->set_neighbor(face, subcells[ - GeometryInfo::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; levelcells.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 @@ -5905,12 +5861,23 @@ Triangulation<3>::execute_refinement () // 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 face_refinement_cases[4]= + {RefinementCase::no_refinement, + RefinementCase::cut_x, + RefinementCase::cut_y, + RefinementCase::cut_xy}; + // check how much space is needed // on every level // we need not check the highest @@ -5920,63 +5887,138 @@ Triangulation<3>::execute_refinement () // - 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 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::cut_x || + ref_case==RefinementCase::cut_y || + ref_case==RefinementCase::cut_z) + { + ++needed_quads_single; + new_cells+=2; + anisotropic_refinement=true; + } + else if (ref_case==RefinementCase::cut_xy || + ref_case==RefinementCase::cut_xz || + ref_case==RefinementCase::cut_yz) + { + ++needed_lines_single; + needed_quads_single += 4; + new_cells+=4; + anisotropic_refinement=true; + } + else if (ref_case==RefinementCase::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::faces_per_cell; ++face) { face_iterator aface = acell->face(face); + // get the RefineCase this + // faces has for the given + // RefineCase of the cell + RefinementCase face_ref_case= + GeometryInfo::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::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::isotropic_refinement || + aface->refinement_case()==RefinementCase::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::lines_per_cell; ++line) + if (GeometryInfo::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 @@ -5992,42 +6034,84 @@ Triangulation<3>::execute_refinement () // 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::isotropic_refinement, ExcInternalError()); + if ((face_refinement_cases[quad->user_index()]==RefinementCase::cut_x + && (quad->child(0)->line_index(1)+1!=quad->child(2)->line_index(1))) || + (face_refinement_cases[quad->user_index()]==RefinementCase::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 @@ -6086,14 +6170,13 @@ Triangulation<3>::execute_refinement () 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()) @@ -6122,9 +6205,11 @@ Triangulation<3>::execute_refinement () // 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 @@ -6132,11 +6217,11 @@ Triangulation<3>::execute_refinement () // 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 @@ -6175,312 +6260,871 @@ Triangulation<3>::execute_refinement () /////////////////////////////////////// // 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 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::cut_xy || + quad->refinement_case()==RefinementCase::no_refinement, + ExcInternalError()); + + // this quad needs to be refined + // anisotropically + Assert(quad->user_index() == RefinementCase::cut_x || + quad->user_index() == RefinementCase::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::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::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::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::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::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::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::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::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::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; qquads.cells.size(); ++q) + for (unsigned int l=0; l::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::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; lcells.cells.size(); ++h) + for (unsigned int q=0; q::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 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::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::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 quad_ref_case=quad->refinement_case(); + + if (quad_ref_case==RefinementCase::cut_x || + quad_ref_case==RefinementCase::cut_y) + { + // set the 'opposite' refine case for children + quad->child(0)->set_user_index(RefinementCase::cut_xy-quad_ref_case); + quad->child(1)->set_user_index(RefinementCase::cut_xy-quad_ref_case); + // refine the inner line + line_iterator middle_line; + if (quad_ref_case==RefinementCase::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::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::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 @@ -6491,127 +7135,60 @@ Triangulation<3>::execute_refinement () // can't do it anymore // once the cell has // children + const RefinementCase 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(); - // first add corners of hex - for (unsigned int vertex=0; - vertex::vertices_per_cell; ++vertex) - vertices[next_unused_vertex] += hex->vertex(vertex) / 128; - // now add center of lines - for (unsigned int line=0; - line::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::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 (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::cut_x: + case RefinementCase::cut_y: + case RefinementCase::cut_z: + n_new_lines=0; + n_new_quads=1; + n_new_hexes=2; + break; + case RefinementCase::cut_xy: + case RefinementCase::cut_xz: + case RefinementCase::cut_yz: + n_new_lines=1; + n_new_quads=4; + n_new_hexes=4; + break; + case RefinementCase::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 new_lines(n_new_lines); + for (unsigned int i=0; ilines.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(); @@ -6620,85 +7197,88 @@ Triangulation<3>::execute_refinement () new_lines[i]->set_boundary_indicator(255); } + // find some space for the newly to + // be created interior quads and + // initialize them. + std::vector new_quads(n_new_quads); + for (unsigned int i=0; iquads.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::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 new_hexes(n_new_hexes); + for (unsigned int i=0; icells.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::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; iset_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), @@ -6726,522 +7306,2411 @@ Triangulation<3>::execute_refinement () 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::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])) - ->line(GeometryInfo::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0])), //0 - hex->face(0)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])) - ->line(GeometryInfo::standard_to_real_face_line(0,f_or[0],f_fl[0],f_ro[0])), //1 - hex->face(0)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])) - ->line(GeometryInfo::standard_to_real_face_line(3,f_or[0],f_fl[0],f_ro[0])), //2 - hex->face(0)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])) - ->line(GeometryInfo::standard_to_real_face_line(2,f_or[0],f_fl[0],f_ro[0])), //3 - - hex->face(1)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])) - ->line(GeometryInfo::standard_to_real_face_line(1,f_or[1],f_fl[1],f_ro[1])), //4 - hex->face(1)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])) - ->line(GeometryInfo::standard_to_real_face_line(0,f_or[1],f_fl[1],f_ro[1])), //5 - hex->face(1)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])) - ->line(GeometryInfo::standard_to_real_face_line(3,f_or[1],f_fl[1],f_ro[1])), //6 - hex->face(1)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])) - ->line(GeometryInfo::standard_to_real_face_line(2,f_or[1],f_fl[1],f_ro[1])), //7 - - hex->face(2)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])) - ->line(GeometryInfo::standard_to_real_face_line(1,f_or[2],f_fl[2],f_ro[2])), //8 - hex->face(2)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])) - ->line(GeometryInfo::standard_to_real_face_line(0,f_or[2],f_fl[2],f_ro[2])), //9 - hex->face(2)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])) - ->line(GeometryInfo::standard_to_real_face_line(3,f_or[2],f_fl[2],f_ro[2])), //10 - hex->face(2)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])) - ->line(GeometryInfo::standard_to_real_face_line(2,f_or[2],f_fl[2],f_ro[2])), //11 - - hex->face(3)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])) - ->line(GeometryInfo::standard_to_real_face_line(1,f_or[3],f_fl[3],f_ro[3])), //12 - hex->face(3)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])) - ->line(GeometryInfo::standard_to_real_face_line(0,f_or[3],f_fl[3],f_ro[3])), //13 - hex->face(3)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])) - ->line(GeometryInfo::standard_to_real_face_line(3,f_or[3],f_fl[3],f_ro[3])), //14 - hex->face(3)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])) - ->line(GeometryInfo::standard_to_real_face_line(2,f_or[3],f_fl[3],f_ro[3])), //15 - - hex->face(4)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])) - ->line(GeometryInfo::standard_to_real_face_line(1,f_or[4],f_fl[4],f_ro[4])), //16 - hex->face(4)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])) - ->line(GeometryInfo::standard_to_real_face_line(0,f_or[4],f_fl[4],f_ro[4])), //17 - hex->face(4)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])) - ->line(GeometryInfo::standard_to_real_face_line(3,f_or[4],f_fl[4],f_ro[4])), //18 - hex->face(4)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])) - ->line(GeometryInfo::standard_to_real_face_line(2,f_or[4],f_fl[4],f_ro[4])), //19 - - hex->face(5)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])) - ->line(GeometryInfo::standard_to_real_face_line(1,f_or[5],f_fl[5],f_ro[5])), //20 - hex->face(5)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5])) - ->line(GeometryInfo::standard_to_real_face_line(0,f_or[5],f_fl[5],f_ro[5])), //21 - hex->face(5)->child(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])) - ->line(GeometryInfo::standard_to_real_face_line(3,f_or[5],f_fl[5],f_ro[5])), //22 - hex->face(5)->child(GeometryInfo::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5])) - ->line(GeometryInfo::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::cut_x, face_flip=false, face_rotation=false and true + { 1, 1 }}, // RefinementCase::cut_x, face_flip=true, face_rotation=false and true + { { 0, 1 }, // RefinementCase::cut_y, face_flip=false, face_rotation=false and true + { 1, 0 }}};// RefinementCase::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 (ref_case)) + { + case RefinementCase::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::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::cut_x) ? 1 : 3), //0 + hex->face(3)->child(0) + ->line((hex->face(3)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //1 + hex->face(4)->child(0) + ->line((hex->face(4)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //2 + hex->face(5)->child(0) + ->line((hex->face(5)->refinement_case() == RefinementCase::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::cut_y: + { + ////////////////////////////// + // + // RefinementCase::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::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::cut_x) ? 1 : 3), //0 + hex->face(1)->child(0) + ->line((hex->face(1)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //1 + hex->face(4)->child(0) + ->line((hex->face(4)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //2 + hex->face(5)->child(0) + ->line((hex->face(5)->refinement_case() == RefinementCase::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::cut_z: + { + ////////////////////////////// + // + // RefinementCase::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::cut_x) ? 1 : 3), //0 + hex->face(1)->child(0) + ->line((hex->face(1)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //1 + hex->face(2)->child(0) + ->line((hex->face(2)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //2 + hex->face(3)->child(0) + ->line((hex->face(3)->refinement_case() == RefinementCase::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::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])), //12 - hex->face(0)->child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[0],f_fl[0],f_ro[0])), - hex->face(0)->child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[0],f_fl[0],f_ro[0])), - hex->face(0)->child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])), - - hex->face(1)->child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])), //16 - hex->face(1)->child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[1],f_fl[1],f_ro[1])), - hex->face(1)->child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[1],f_fl[1],f_ro[1])), - hex->face(1)->child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])), - - hex->face(2)->child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])), //20 - hex->face(2)->child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[2],f_fl[2],f_ro[2])), - hex->face(2)->child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[2],f_fl[2],f_ro[2])), - hex->face(2)->child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])), - - hex->face(3)->child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])), //24 - hex->face(3)->child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[3],f_fl[3],f_ro[3])), - hex->face(3)->child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[3],f_fl[3],f_ro[3])), - hex->face(3)->child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])), - - hex->face(4)->child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])), //28 - hex->face(4)->child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[4],f_fl[4],f_ro[4])), - hex->face(4)->child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[4],f_fl[4],f_ro[4])), - hex->face(4)->child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])), - - hex->face(5)->child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])), //32 - hex->face(5)->child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[5],f_fl[5],f_ro[5])), - hex->face(5)->child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[5],f_fl[5],f_ro[5])), - hex->face(5)->child_index(GeometryInfo::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::cut_xy: + { + ////////////////////////////// + // + // RefinementCase::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::cut_x) ? 1 : 3), //0 + hex->face(1)->child(0) + ->line((hex->face(1)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //1 + hex->face(2)->child(0) + ->line((hex->face(2)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //2 + hex->face(3)->child(0) + ->line((hex->face(3)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //3 + + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[4],f_fl[4],f_ro[4])), //4 + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[4],f_fl[4],f_ro[4])), //5 + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[4],f_fl[4],f_ro[4])), //6 + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[4],f_fl[4],f_ro[4])), //7 + + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[5],f_fl[5],f_ro[5])), //8 + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[5],f_fl[5],f_ro[5])), //9 + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[5],f_fl[5],f_ro[5])), //10 + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::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::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])), //12 + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[4],f_fl[4],f_ro[4])), + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[4],f_fl[4],f_ro[4])), + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])), + + hex->face(5)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])), //16 + hex->face(5)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[5],f_fl[5],f_ro[5])), + hex->face(5)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[5],f_fl[5],f_ro[5])), + hex->face(5)->isotropic_child_index(GeometryInfo::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::cut_xz: + { + ////////////////////////////// + // + // RefinementCase::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::cut_x) ? 1 : 3), //0 + hex->face(1)->child(0) + ->line((hex->face(1)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //1 + hex->face(4)->child(0) + ->line((hex->face(4)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //2 + hex->face(5)->child(0) + ->line((hex->face(5)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //3 + + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[2],f_fl[2],f_ro[2])), //4 + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[2],f_fl[2],f_ro[2])), //5 + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[2],f_fl[2],f_ro[2])), //6 + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[2],f_fl[2],f_ro[2])), //7 + + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[3],f_fl[3],f_ro[3])), //8 + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[3],f_fl[3],f_ro[3])), //9 + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[3],f_fl[3],f_ro[3])), //10 + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::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::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])), //8 + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[2],f_fl[2],f_ro[2])), + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[2],f_fl[2],f_ro[2])), + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])), + + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])), //12 + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[3],f_fl[3],f_ro[3])), + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[3],f_fl[3],f_ro[3])), + hex->face(3)->isotropic_child_index(GeometryInfo::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::cut_yz: + { + ////////////////////////////// + // + // RefinementCase::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::cut_x) ? 1 : 3), //0 + hex->face(3)->child(0) + ->line((hex->face(3)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //1 + hex->face(4)->child(0) + ->line((hex->face(4)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //2 + hex->face(5)->child(0) + ->line((hex->face(5)->refinement_case() == RefinementCase::cut_x) ? 1 : 3), //3 + + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0])), //4 + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[0],f_fl[0],f_ro[0])), //5 + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[0],f_fl[0],f_ro[0])), //6 + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[0],f_fl[0],f_ro[0])), //7 + + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[1],f_fl[1],f_ro[1])), //8 + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[1],f_fl[1],f_ro[1])), //9 + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[1],f_fl[1],f_ro[1])), //10 + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::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::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])), //4 + hex->face(0)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[0],f_fl[0],f_ro[0])), + hex->face(0)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[0],f_fl[0],f_ro[0])), + hex->face(0)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])), + + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])), //8 + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[1],f_fl[1],f_ro[1])), + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[1],f_fl[1],f_ro[1])), + hex->face(1)->isotropic_child_index(GeometryInfo::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::cut_xyz: + { + ////////////////////////////// + // + // RefinementCase::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(); + // first add corners of hex + for (unsigned int vertex=0; + vertex::vertices_per_cell; ++vertex) + vertices[next_unused_vertex] += hex->vertex(vertex) / 128; + // now add center of lines + for (unsigned int line=0; + line::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::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::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[0],f_fl[0],f_ro[0])), //0 + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[0],f_fl[0],f_ro[0])), //1 + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[0],f_fl[0],f_ro[0])), //2 + hex->face(0)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[0],f_fl[0],f_ro[0])), //3 + + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[1],f_fl[1],f_ro[1])), //4 + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[1],f_fl[1],f_ro[1])), //5 + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[1],f_fl[1],f_ro[1])), //6 + hex->face(1)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[1],f_fl[1],f_ro[1])), //7 + + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[2],f_fl[2],f_ro[2])), //8 + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[2],f_fl[2],f_ro[2])), //9 + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[2],f_fl[2],f_ro[2])), //10 + hex->face(2)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[2],f_fl[2],f_ro[2])), //11 + + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[3],f_fl[3],f_ro[3])), //12 + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[3],f_fl[3],f_ro[3])), //13 + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[3],f_fl[3],f_ro[3])), //14 + hex->face(3)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[3],f_fl[3],f_ro[3])), //15 + + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[4],f_fl[4],f_ro[4])), //16 + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[4],f_fl[4],f_ro[4])), //17 + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[4],f_fl[4],f_ro[4])), //18 + hex->face(4)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])) + ->line(GeometryInfo::standard_to_real_face_line(2,f_or[4],f_fl[4],f_ro[4])), //19 + + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::standard_to_real_face_line(1,f_or[5],f_fl[5],f_ro[5])), //20 + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::standard_to_real_face_line(0,f_or[5],f_fl[5],f_ro[5])), //21 + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::standard_to_real_face_line(3,f_or[5],f_fl[5],f_ro[5])), //22 + hex->face(5)->isotropic_child(GeometryInfo::standard_to_real_face_vertex(3,f_or[5],f_fl[5],f_ro[5])) + ->line(GeometryInfo::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::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::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::standard_to_real_face_vertex(0,f_or[0],f_fl[0],f_ro[0])), //12 + hex->face(0)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[0],f_fl[0],f_ro[0])), + hex->face(0)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[0],f_fl[0],f_ro[0])), + hex->face(0)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[0],f_fl[0],f_ro[0])), + + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[1],f_fl[1],f_ro[1])), //16 + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[1],f_fl[1],f_ro[1])), + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[1],f_fl[1],f_ro[1])), + hex->face(1)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[1],f_fl[1],f_ro[1])), + + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[2],f_fl[2],f_ro[2])), //20 + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[2],f_fl[2],f_ro[2])), + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[2],f_fl[2],f_ro[2])), + hex->face(2)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[2],f_fl[2],f_ro[2])), + + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[3],f_fl[3],f_ro[3])), //24 + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[3],f_fl[3],f_ro[3])), + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[3],f_fl[3],f_ro[3])), + hex->face(3)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[3],f_fl[3],f_ro[3])), + + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[4],f_fl[4],f_ro[4])), //28 + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[4],f_fl[4],f_ro[4])), + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[4],f_fl[4],f_ro[4])), + hex->face(4)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(3,f_or[4],f_fl[4],f_ro[4])), + + hex->face(5)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(0,f_or[5],f_fl[5],f_ro[5])), //32 + hex->face(5)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(1,f_or[5],f_fl[5],f_ro[5])), + hex->face(5)->isotropic_child_index(GeometryInfo::standard_to_real_face_vertex(2,f_or[5],f_fl[5],f_ro[5])), + hex->face(5)->isotropic_child_index(GeometryInfo::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::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::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::faces_per_cell; ++f) - for (unsigned int s=0; s::subfaces_per_face; ++s) + for (unsigned int s=0; + s::n_children(GeometryInfo::face_refinement_case(ref_case,f)), + 1U); + ++s) { - new_hexes[GeometryInfo::child_cell_on_face(f,s)] - ->set_face_orientation(f, hex->face_orientation(f)); - new_hexes[GeometryInfo::child_cell_on_face(f,s)] - ->set_face_flip(f, hex->face_flip(f)); - new_hexes[GeometryInfo::child_cell_on_face(f,s)] - ->set_face_rotation(f, hex->face_rotation(f)); + const unsigned int current_child + =GeometryInfo::child_cell_on_face(ref_case, + f, + s, + f_or[f], + f_fl[f], + f_ro[f], + GeometryInfo::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::faces_per_cell; ++f) - for (unsigned int s=0; s::subfaces_per_face; ++s) - Assert(hex->face(f)->child(s)==hex->child( - GeometryInfo::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 @@ -7249,334 +9718,108 @@ Triangulation<3>::execute_refinement () // 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::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 (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::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::cut_x: + new_hexes[0]->set_neighbor(1, new_hexes[1]); + + new_hexes[1]->set_neighbor(0, new_hexes[0]); + break; + case RefinementCase::cut_y: + new_hexes[0]->set_neighbor(3, new_hexes[1]); + + new_hexes[1]->set_neighbor(2, new_hexes[0]); + break; + case RefinementCase::cut_z: + new_hexes[0]->set_neighbor(5, new_hexes[1]); + + new_hexes[1]->set_neighbor(4, new_hexes[0]); + break; + case RefinementCase::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::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::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::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::subfaces_per_face; ++c) - { - neighbor_cells[face][c] - = neighbor->child(GeometryInfo:: - 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::faces_per_cell; ++face) - for (unsigned int sub=0; sub::subfaces_per_face; ++sub) - new_hexes[GeometryInfo:: - 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::child_cell_on_face(0,0)==0, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(2,0)==0, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(1,0)==1, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(2,2)==1, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(0,1)==2, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(3,0)==2, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(1,1)==3, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(3,2)==3, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(0,2)==4, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(2,1)==4, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(1,2)==5, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(2,3)==5, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(0,3)==6, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(3,1)==6, ExcInternalError()); - Assert(GeometryInfo::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::child_cell_on_face(1,3)==7, ExcInternalError()); - Assert(GeometryInfo::child_cell_on_face(3,3)==7, ExcInternalError()); - Assert(GeometryInfo::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::faces_per_cell; ++nb) - for (unsigned int subface=0; - subface::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::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::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::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::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::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 @@ -7585,6 +9828,15 @@ Triangulation<3>::execute_refinement () } } + // 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 (); @@ -7617,10 +9869,20 @@ Triangulation<3>::execute_refinement () endc = end(); while (cell != endc) Assert (!(cell++)->refine_flag_set(), ExcInternalError ()); + + cell_iterator testcell=begin(), + ec=end(); + for (;testcell!=ec; ++testcell) + { + std::set verts; + for (unsigned int f=0; f::faces_per_cell; ++f) + for (unsigned int v=0; v::vertices_per_cell; ++v) + verts.insert(testcell->face(f)->vertex_index(v)); + Assert (verts.size()==GeometryInfo::vertices_per_cell, ExcInternalError()); + } #endif } - #endif @@ -7633,9 +9895,13 @@ void Triangulation::execute_coarsening () // is used later on to decide which lines can // be deleted after coarsening a cell. in // other dimensions it will be ignored - std::vector cell_count(0); + std::vector line_cell_count(0); + std::vector 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 @@ -7649,7 +9915,7 @@ void Triangulation::execute_coarsening () // 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 @@ -7662,8 +9928,7 @@ void Triangulation::execute_coarsening () if (cell->child(0)->coarsen_flag_set()) { cell->set_user_flag(); - for (unsigned int child=0; - child::children_per_cell; ++child) + for (unsigned int child=0; childn_children(); ++child) { Assert (cell->child(child)->coarsen_flag_set(), ExcInternalError()); @@ -7693,7 +9958,7 @@ void Triangulation::execute_coarsening () // 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 @@ -7709,6 +9974,93 @@ void Triangulation::execute_coarsening () } + +#if deal_II_dimension == 1 + +template<> +void +Triangulation<1>::prevent_distorted_boundary_cells () +{} + +#else + +template +void +Triangulation::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::isotropic_refinement) + { + // The cell is at the boundary + // and it is flagged for + // anisotropic + // refinement. Therefore, we have + // a closer look + const RefinementCase ref_case=cell->refine_flag_set(); + for (unsigned int face_no=0; + face_no::faces_per_cell; + ++face_no) + if (cell->face(face_no)->at_boundary()) + { + // this is the critical + // face at the boundary. + if (GeometryInfo::face_refinement_case(ref_case,face_no) + !=RefinementCase::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 new_bound=boundary[face->boundary_indicator()] + ->get_new_point_on_face (face); + // to check it, + // transform to the + // unit cell with + // Q1Mapping + Point new_unit=StaticMappingQ1::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 void Triangulation::prepare_refinement_dim_dependent () {} @@ -7726,6 +10078,11 @@ void Triangulation<3>::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 @@ -7743,16 +10100,30 @@ void Triangulation<3>::prepare_refinement_dim_dependent () 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::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::lines_per_cell; ++line) + if (GeometryInfo::line_refinement_case(cell->refine_flag_set(), line) + ==RefinementCase::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::lines_per_cell; ++line) + if (GeometryInfo::line_refinement_case(cell->refinement_case(), line) + ==RefinementCase::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 @@ -7792,14 +10163,33 @@ void Triangulation<3>::prepare_refinement_dim_dependent () ExcInternalError()); if (cell->line(line)->child(c)->user_flag_set () && - !cell->refine_flag_set()) + (GeometryInfo::line_refinement_case(cell->refine_flag_set(), + line) + ==RefinementCase::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::lines_per_cell; ++l) + if (GeometryInfo::line_refinement_case(cell->refine_flag_set(), line) + ==RefinementCase::cut_x) + // flag a line, + // that will be + // refined + cell->line(l)->set_user_flag(); // note that // we have // changed @@ -7815,7 +10205,10 @@ void Triangulation<3>::prepare_refinement_dim_dependent () // refinement for (unsigned int line=0; line::lines_per_cell; ++line) - if (!cell->line(line)->has_children()) + if (!cell->line(line)->has_children() && + (GeometryInfo::line_refinement_case(cell->refine_flag_set(), + line) + !=RefinementCase::no_refinement)) cell->line(line)->set_user_flag(); break; @@ -7835,148 +10228,41 @@ void Triangulation<3>::prepare_refinement_dim_dependent () // 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::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::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::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::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; cn_children(); ++c) + cell->child(c)->clear_coarsen_flag (); + cell->clear_user_flag(); + for (unsigned int l=0; l::lines_per_cell; ++l) + if (GeometryInfo::line_refinement_case(cell->refinement_case(), l) + ==RefinementCase::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); @@ -7985,6 +10271,90 @@ void Triangulation<3>::prepare_refinement_dim_dependent () #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 +bool +Triangulation::coarsening_allowed(cell_iterator& cell) +{ + const RefinementCase ref_case = cell->refinement_case(); + for (unsigned int n=0; n::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 face_ref_case = + GeometryInfo::face_refinement_case(cell->refinement_case(), n); + + unsigned int n_subfaces = GeometryInfo + ::n_children(face_ref_case); + + if (n_subfaces == 0 || cell->face(n)->at_boundary()) + continue; + for (unsigned int c=0; cchild(GeometryInfo:: + 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 void Triangulation::fix_coarsen_flags () { @@ -8009,30 +10379,29 @@ void Triangulation::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::children_per_cell; ++child) + continue; + + const unsigned int n_children=cell->n_children(); + unsigned int flagged_children=0; + for (unsigned int child=0; childchild(child)->active() && cell->child(child)->coarsen_flag_set()) { @@ -8045,7 +10414,7 @@ void Triangulation::fix_coarsen_flags () // flag this cell for // coarsening if all children // were flagged - if (flagged_children == GeometryInfo::children_per_cell) + if (flagged_children == n_children) cell->set_user_flag(); } @@ -8083,80 +10452,57 @@ void Triangulation::fix_coarsen_flags () // 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; cn_children(); ++c) { - for (unsigned int c=0; - (c::children_per_cell) && (coarsening_allowed==true); - ++c) - for (unsigned int n=0; n::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::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 -bool Triangulation::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 flags_before[2]; - save_coarsen_flags (flags_before[0]); - save_refine_flags (flags_before[1]); + std::vector 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 flags_after; + save_coarsen_flags (flags_after); + + return (flags_before != flags_after); +} + +#endif - std::vector 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 +bool Triangulation::prepare_coarsening_and_refinement () +{ + // save the flags to determine + // whether something was changed in + // the course of this function + std::vector 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 @@ -8227,6 +10573,9 @@ bool Triangulation::prepare_coarsening_and_refinement () // 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 @@ -8255,7 +10604,7 @@ bool Triangulation::prepare_coarsening_and_refinement () // 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 @@ -8298,29 +10647,29 @@ bool Triangulation::prepare_coarsening_and_refinement () // 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::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 @@ -8339,33 +10688,16 @@ bool Triangulation::prepare_coarsening_and_refinement () { 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::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::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::faces_per_cell; ++n) @@ -8374,46 +10706,29 @@ bool Triangulation::prepare_coarsening_and_refinement () 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::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::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::faces_per_cell)))) - for (unsigned int c=0; - c::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::faces_per_cell)) + for (unsigned int c=0; cn_children(); ++c) cell->child(c)->clear_coarsen_flag(); } - } // if (!cell->active()) } // for (all cells) } // if (smooth_grid & ...) - + ////////////////////////////////////// // STEP 2: // eliminate refined islands in the @@ -8450,7 +10765,7 @@ bool Triangulation::prepare_coarsening_and_refinement () // active bool all_children_active = true; if (!cell->active()) - for (unsigned int c=0; c::children_per_cell; ++c) + for (unsigned int c=0; cn_children(); ++c) if (!cell->child(c)->active()) { all_children_active = false; @@ -8482,31 +10797,13 @@ bool Triangulation::prepare_coarsening_and_refinement () { 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::children_per_cell; - ++c) - if (neighbor->child(c)->coarsen_flag_set()) - ++tagged_children; - if (tagged_children == - GeometryInfo::children_per_cell) - ++unrefined_neighbors; - } - } + if (!face_will_be_refined_by_neighbor(cell,n)) + ++unrefined_neighbors; + } + } // if all @@ -8549,17 +10846,14 @@ bool Triangulation::prepare_coarsening_and_refinement () (smooth_grid & eliminate_refined_boundary_islands)) ) && (total_neighbors != 0)) - { - if (!cell->active()) - for (unsigned int c=0; - c::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; cn_children(); ++c) + { + cell->child(c)->clear_refine_flag (); + cell->child(c)->set_coarsen_flag (); + } + else + cell->clear_refine_flag(); } } } @@ -8568,8 +10862,18 @@ bool Triangulation::prepare_coarsening_and_refinement () // 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 @@ -8641,46 +10945,158 @@ bool Triangulation::prepare_coarsening_and_refinement () 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::isotropic_refinement) continue; - - unsigned int refined_neighbors = 0, - unrefined_neighbors = 0; - for (unsigned int face=0; face::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::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 smoothing_cell_refinement_case=RefinementCase::no_refinement; + + // use second algorithm, do + // the check individually for + // each direction + for (unsigned int face_pair=0; face_pair::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 directional_cell_refinement_case=RefinementCase::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 expected_face_ref_case=RefinementCase::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::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::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. @@ -8731,13 +11147,14 @@ bool Triangulation::prepare_coarsening_and_refinement () // set_refine_flag and // clear_coarsen_flag of // all children. - unsigned int n_children=GeometryInfo::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 combined_ref_case = RefinementCase::no_refinement; for (unsigned int i=0; ichild(i); @@ -8748,21 +11165,21 @@ bool Triangulation::prepare_coarsening_and_refinement () // 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::no_refinement) { for (unsigned int i=0; ichild(i); child->clear_coarsen_flag(); - child->set_refine_flag(); + child->set_refine_flag(combined_ref_case); } } } @@ -8782,6 +11199,8 @@ bool Triangulation::prepare_coarsening_and_refinement () !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. @@ -8811,7 +11230,9 @@ bool Triangulation::prepare_coarsening_and_refinement () // child is // found to // be a patch - for (unsigned int cc=0; ccn_children(); + n_grandchildren += nn_children; + for (unsigned int cc=0; ccchild(cc); // check @@ -8826,7 +11247,7 @@ bool Triangulation::prepare_coarsening_and_refinement () } } - if (n_coarsen_flags!=n_children*n_children) + if (n_coarsen_flags!=n_grandchildren) { // clear all // grandchildren's @@ -8838,7 +11259,8 @@ bool Triangulation::prepare_coarsening_and_refinement () if (child->child(0)->active()) { - for (unsigned int cc=0; ccn_children(); + for (unsigned int cc=0; ccchild(cc); Assert(grand_child->active(), ExcInternalError()); @@ -8850,50 +11272,404 @@ bool Triangulation::prepare_coarsening_and_refinement () } } } + + ////////////////////////////////// + // + // 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::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::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::face_refinement_case(cell->refine_flag_set(), + i) + != RefinementCase::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::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 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 frc=cell->neighbor(i)->face(nb_indices.first)->refinement_case(); + if (frc & RefinementCase::cut_x) + ++refined_along_x; + if (frc & RefinementCase::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 flagged_frc= + GeometryInfo::face_refinement_case(cell->refine_flag_set(), + i, + cell->face_orientation(i), + cell->face_flip(i), + cell->face_rotation(i)); + if (flagged_frc & RefinementCase::cut_x) + ++to_be_refined_along_x; + if (flagged_frc & RefinementCase::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::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::cut_axis(1)); + } + else + { + if (cell->neighbor(i)->refine_flag_set()!=RefinementCase::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 nb_frc + = GeometryInfo::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::cut_x) && + !(refined_along_x || to_be_refined_along_x)) + changed |= cell->flag_for_face_refinement(i,RefinementCase::cut_axis(0)); + if ((nb_frc & RefinementCase::cut_y) && + !(refined_along_y || to_be_refined_along_y)) + changed |= cell->flag_for_face_refinement(i,RefinementCase::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 face_ref_case= + GeometryInfo::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 needed_face_ref_case + =GeometryInfo::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::cut_x && needed_face_ref_case==RefinementCase::cut_y) || + (face_ref_case==RefinementCase::cut_y && needed_face_ref_case==RefinementCase::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 face_ref_case = cell->face(i)->refinement_case(), + needed_face_ref_case = GeometryInfo::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::cut_x && needed_face_ref_case==RefinementCase::cut_y) || + (face_ref_case==RefinementCase::cut_y && needed_face_ref_case==RefinementCase::cut_x)) + changed=cell->flag_for_face_refinement(i, face_ref_case); + } + + + } + } + } + ////////////////////////////////////// // STEP 7: // take care that no double refinement @@ -8907,7 +11683,6 @@ bool Triangulation::prepare_coarsening_and_refinement () // cell are either flagged for coarsening // or none of the children is fix_coarsen_flags (); - // get the refinement and coarsening // flags std::vector flags_after_loop[2]; @@ -8922,8 +11697,8 @@ bool Triangulation::prepare_coarsening_and_refinement () // 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); @@ -8942,24 +11717,51 @@ bool Triangulation::prepare_coarsening_and_refinement () #if deal_II_dimension == 3 template <> -void Triangulation<3>::count_cells_at_line (std::vector &cell_count) +void Triangulation<3>::count_cells_at_line (std::vector &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::lines_per_cell; ++l) - ++cell_count[cell->line_index(l)]; + ++line_cell_count[cell->line_index(l)]; +} + +#else + +template +void Triangulation::count_cells_at_line (std::vector &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 &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::faces_per_cell; ++q) + ++quad_cell_count[cell->quad_index(q)]; } #else template -void Triangulation::count_cells_at_line (std::vector &cell_count) +void Triangulation::count_cells_at_quad (std::vector &quad_cell_count) { Assert(false, ExcNotImplemented()); - cell_count.clear(); + quad_cell_count.clear(); } #endif @@ -8970,9 +11772,9 @@ void Triangulation::count_cells_at_line (std::vector &cell_co template <> void Triangulation<1>::delete_children (cell_iterator &cell, + std::vector &, std::vector &) { - const unsigned int dim=1; // first we need to reset the // neighbor pointers of the // neighbors of this cell's @@ -9043,15 +11845,14 @@ void Triangulation<1>::delete_children (cell_iterator &cell, // 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::children_per_cell; ++child) + for (unsigned int child=0; childn_children(); ++child) { cell->child(child)->clear_user_data(); cell->child(child)->clear_user_flag(); @@ -9060,7 +11861,7 @@ void Triangulation<1>::delete_children (cell_iterator &cell, // delete pointer to children - cell->set_children (-1); + cell->clear_children (); cell->clear_user_flag(); } @@ -9071,391 +11872,1475 @@ void Triangulation<1>::delete_children (cell_iterator &cell, template <> void Triangulation<2>::delete_children (cell_iterator &cell, + std::vector &, std::vector &) { 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::children_per_cell; ++child) - for (unsigned int n=0; n::faces_per_cell; - ++n) + const RefinementCase ref_case=cell->refinement_case(); + + for (unsigned int face_no=0; face_no::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::face_refinement_case(ref_case, face_no) + ==RefinementCase::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::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::face_refinement_case(neighbor->refinement_case(), nb_nb) + ==RefinementCase::no_refinement)) + { + neighbor=neighbor->child(GeometryInfo + ::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::n_children( + GeometryInfo::face_refinement_case(neighbor->refinement_case(), nb_nb)); + Assert (n_subfaces>0, ExcInternalError()); + + for (unsigned int i=0; ichild( + GeometryInfo::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::face_refinement_case(neighbor_child->refinement_case(), + nb_nb) + == RefinementCase::no_refinement)) + { + neighbor_child=neighbor_child + ->child(GeometryInfo + ::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::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::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::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::face_refinement_case(ref_case,face) + !=RefinementCase::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::subfaces_per_face; ++subface) + subfacen_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; childn_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 &line_cell_count, + std::vector &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 ref_case=cell->refinement_case(); + // vectors to hold all lines and quads which + // may be deleted + std::vector lines_to_delete(0); + std::vector 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; cn_children(); ++c) + { + cell_iterator child=cell->child(c); + for (unsigned int l=0; l::lines_per_cell; ++l) + --line_cell_count[child->line_index(l)]; + for (unsigned int f=0; f::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 (ref_case)) + { + case RefinementCase::cut_x: + quads_to_delete.push_back(cell->child(0)->face(1)); + break; + case RefinementCase::cut_y: + quads_to_delete.push_back(cell->child(0)->face(3)); + break; + case RefinementCase::cut_z: + quads_to_delete.push_back(cell->child(0)->face(5)); + break; + case RefinementCase::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::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::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::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::children_per_cell; ++child) + for (unsigned int child=0; childn_children(); ++child) { cell->child(child)->clear_user_data(); cell->child(child)->clear_user_flag(); + + for (unsigned int f=0; f::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::faces_per_cell; ++quad_no) + { + quad_iterator quad=cell->face(quad_no); + + Assert((GeometryInfo::face_refinement_case(ref_case,quad_no) && quad->has_children()) || + GeometryInfo::face_refinement_case(ref_case,quad_no)==RefinementCase::no_refinement, + ExcInternalError()); + + switch (static_cast (quad->refinement_case())) + { + case RefinementCase::no_refinement: + // nothing to do as the quad + // is not refined + break; + case RefinementCase::cut_x: + case RefinementCase::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::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::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::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::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::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; lcells.cells.size(); ++h) + for (unsigned int q=0; q::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::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; childn_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::lines_per_cell; ++line_no) + { + line_iterator line=cell->line(line_no); + + Assert((GeometryInfo::line_refinement_case(ref_case,line_no) && line->has_children()) || + GeometryInfo::line_refinement_case(ref_case,line_no)==RefinementCase::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::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::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 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 &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::children_per_cell; ++child) - for (unsigned int n=0; n::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::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::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::faces_per_cell; + for (unsigned int face=0; face::faces_per_cell; ++face) + if (cell->face(face)->at_boundary()) + if (bound_face == GeometryInfo::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::faces_per_cell+1; + + if (bound_face::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 + ::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::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; lused() == 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::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::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::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::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::children_per_cell; ++child) + else if (ref_case==RefinementCase::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::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::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; lset_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::max_children_per_cell]; + while (next_unused_cell->used() == true) + ++next_unused_cell; + + const unsigned int n_children= + GeometryInfo::n_children(ref_case); + for (unsigned int i=0; iused() == false, + ExcCellShouldBeUnused()); + subcells[i] = next_unused_cell; + ++next_unused_cell; + if (i%2==1 && iused() == true) + ++next_unused_cell; + } - // delete pointer to children - cell->clear_children (); - cell->clear_user_flag(); + if (ref_case==RefinementCase::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::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::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; iline(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::max_children_per_face], + nb_child, + children[GeometryInfo::faces_per_cell][GeometryInfo::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::faces_per_cell; ++face) + for (unsigned int c=0; c::max_children_per_face; ++c) + children[face][c]=subcells[GeometryInfo::child_cell_on_face(ref_case, + face,c)]; + + + for (unsigned int face=0; face::faces_per_cell; + ++face) + { + const cell_iterator neighbor=cell->neighbor(face); + const RefinementCase face_ref_case=GeometryInfo::face_refinement_case(ref_case,face); + const unsigned int n_subfaces=std::max(GeometryInfo::n_children(face_ref_case), + static_cast(1)); + + + + // if no neighbor set invalid pointer for + // all children adjacent to that face + if (neighbor.state() != IteratorState::valid) + for (unsigned int c=0; cset_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; cset_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 nb_ref_case = neighbor->refinement_case(); + const RefinementCase nb_face_ref_case = GeometryInfo::face_refinement_case(nb_ref_case, + nb_nb); + const unsigned int nb_n_subfaces = std::max(GeometryInfo:: + n_children(nb_face_ref_case), + static_cast(1)); + + for (unsigned int c=0; c::max_children_per_face; ++c) + { + nb_child=neighbor->child(GeometryInfo:: + 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::face_refinement_case(nb_child->refinement_case(), + nb_nb) + == RefinementCase::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:: + 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::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:: + 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::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::cut_x) + { + // children: + // .--.--. + // | . | + // .0 . 1. + // | | | + // .--.--. + subcells[0]->set_neighbor (1, subcells[1]); + + subcells[1]->set_neighbor (0, subcells[0]); + } + else + { + Assert(ref_case==RefinementCase::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; iset_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 void Triangulation::write_bool_vector (const unsigned int magic_number1, const std::vector &v, @@ -9869,6 +13754,339 @@ Triangulation::remove_refinement_listener (RefinementListener &listener) co 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 ref_case=cell->refinement_case(); + + // visit each face in turn + for (unsigned int f=0; f::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::max_children_per_face; ++c) + cell->child(GeometryInfo::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::face_refinement_case(cell->refinement_case(), f) == RefinementCase::no_refinement) + { + const active_cell_iterator child_on_this_face=cell->child(GeometryInfo::child_cell_on_face(cell->refinement_case(), + f, + cell->face_orientation(f), + cell->face_flip(f), + cell->face_rotation(f), + RefinementCase::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::face_refinement_case(ref_case,f) == RefinementCase::no_refinement) && !cell->neighbor_is_coarser(f)) + if (refining) + neighbor->set_neighbor(cell->neighbor_of_neighbor(f), + cell->child(GeometryInfo::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 our_face_ref_case + =GeometryInfo::face_refinement_case(ref_case,f,f_or,f_fl,f_ro); + const RefinementCase face_ref_case + =cell->face(f)->refinement_case(); + + switch (static_cast (face_ref_case)) + { + case RefinementCase::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::cut_x: + case RefinementCase::cut_y: + case RefinementCase::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 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::n_children(our_face_ref_case),1U); ++c) + { + cell_iterator child= + cell->child(GeometryInfo::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 parents; + for (unsigned int face_child=0; face_childface(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::iterator cur_face=parents.begin(); + for (;cur_face!=parents.end(); ++cur_face) + if (cur_face->first->has_children()) + for (unsigned int fc=0; fcfirst->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 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::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 nb_face_ref_case + =GeometryInfo::face_refinement_case(it->second->refinement_case(), + nb_nb, + nb_f_or, + nb_f_fl, + nb_f_ro); + for (unsigned int c=0; c::n_children(nb_face_ref_case),1U); ++c) + { + cell_iterator child= + it->second->child(GeometryInfo::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::iterator our_it=our_children.begin(), + end_our_it=our_children.end(); + std::multimap ::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 +void +Triangulation::update_neighbors(cell_iterator &, + bool) +{ + Assert(false, ExcNotImplemented()); +} + +#endif + // explicit instantiations template class Triangulation; diff --git a/deal.II/deal.II/source/grid/tria_accessor.cc b/deal.II/deal.II/source/grid/tria_accessor.cc index 5b4a937e9d..9605514cc9 100644 --- a/deal.II/deal.II/source/grid/tria_accessor.cc +++ b/deal.II/deal.II/source/grid/tria_accessor.cc @@ -31,6 +31,97 @@ template const unsigned int TriaAccessor::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_non_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_nochild(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 @@ -224,9 +315,10 @@ TriaObjectAccessor<1, dim>::recursively_clear_user_index () const template -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)); @@ -239,7 +331,7 @@ void TriaObjectAccessor<1, dim>::set_children (const int index) const template void TriaObjectAccessor<1, dim>::clear_children () const { - set_children (-1); + set_children (0,-1); } @@ -538,15 +630,18 @@ TriaObjectAccessor<2, dim>::recursively_clear_user_index () const template -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; } @@ -554,7 +649,8 @@ void TriaObjectAccessor<2, dim>::set_children (const int index) const template void TriaObjectAccessor<2, dim>::clear_children () const { - set_children (-1); + set_children (0, -1); + set_children (2, -1); } @@ -1079,14 +1175,18 @@ TriaObjectAccessor<3, dim>::recursively_clear_user_index () const #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 @@ -1095,7 +1195,10 @@ void TriaObjectAccessor<3, 3>::set_children (const int index) const template 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); } @@ -2201,12 +2304,8 @@ void CellAccessor::set_neighbor (const unsigned int i, template -unsigned int CellAccessor::neighbor_of_neighbor (const unsigned int neighbor) const +unsigned int CellAccessor::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::faces_per_cell, TriaAccessorExceptions::ExcInvalidNeighbor(neighbor)); @@ -2235,39 +2334,129 @@ unsigned int CellAccessor::neighbor_of_neighbor (const unsigned int neighbo = GeometryInfo::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::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::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 +unsigned int CellAccessor::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 +bool +CellAccessor::neighbor_is_coarser (const unsigned int neighbor) const +{ + return neighbor_of_neighbor_internal(neighbor)==numbers::invalid_unsigned_int; +} + + +# if deal_II_dimension == 2 + template std::pair CellAccessor::neighbor_of_coarser_neighbor (const unsigned int neighbor) const { + Assert (neighbor < GeometryInfo::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 > 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::opposite_face[neighbor]; + + const TriaIterator > face_guess + =neighbor_cell->face(face_no_guess); + + if (face_guess->has_children()) + for (unsigned int subface_no=0; subface_non_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::faces_per_cell; ++face_no) + { + if (face_no!=face_no_guess) + { + const TriaIterator > face + =neighbor_cell->face(face_no); + if (face->has_children()) + for (unsigned int subface_no=0; subface_non_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 +std::pair +CellAccessor::neighbor_of_coarser_neighbor (const unsigned int neighbor) const +{ Assert (neighbor < GeometryInfo::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 > neighbor_cell = this->neighbor(neighbor); @@ -2279,7 +2468,7 @@ CellAccessor::neighbor_of_coarser_neighbor (const unsigned int neighbor) co // 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 @@ -2293,15 +2482,22 @@ CellAccessor::neighbor_of_coarser_neighbor (const unsigned int neighbor) co if (face_guess->has_children()) for (unsigned int subface_no=0; subface_non_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::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_nochild(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 @@ -2316,15 +2512,20 @@ CellAccessor::neighbor_of_coarser_neighbor (const unsigned int neighbor) co if (face->has_children()) for (unsigned int subface_no=0; subface_non_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::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_nochild(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)); } } @@ -2336,6 +2537,8 @@ CellAccessor::neighbor_of_coarser_neighbor (const unsigned int neighbor) co numbers::invalid_unsigned_int); } +#endif + template @@ -2398,17 +2601,33 @@ neighbor_child_on_subface (const unsigned int face, 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 @@ -2425,58 +2644,312 @@ neighbor_child_on_subface (const unsigned int face, 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 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::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 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 diff --git a/deal.II/deal.II/source/grid/tria_levels.cc b/deal.II/deal.II/source/grid/tria_levels.cc index bd8c62523c..7e33d3d3df 100644 --- a/deal.II/deal.II/source/grid/tria_levels.cc +++ b/deal.II/deal.II/source/grid/tria_levels.cc @@ -39,7 +39,7 @@ namespace internal refine_flags.reserve (total_cells); refine_flags.insert (refine_flags.end(), total_cells - refine_flags.size(), - false); + RefinementCase::no_refinement); coarsen_flags.reserve (total_cells); coarsen_flags.insert (coarsen_flags.end(), @@ -70,8 +70,8 @@ namespace internal // 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()::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 @@ -123,7 +123,7 @@ namespace internal 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(), @@ -153,8 +153,8 @@ namespace internal // 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()::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 diff --git a/deal.II/deal.II/source/grid/tria_objects.all_dimensions.cc b/deal.II/deal.II/source/grid/tria_objects.all_dimensions.cc new file mode 100644 index 0000000000..4950342b1d --- /dev/null +++ b/deal.II/deal.II/source/grid/tria_objects.all_dimensions.cc @@ -0,0 +1,595 @@ +//--------------------------------------------------------------------------- +// $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 +#include +#include +#include +#include + +#include +#include + + + +DEAL_II_NAMESPACE_OPEN + +namespace internal +{ + namespace Triangulation + { + template<> + void + TriaObjects >::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; i0) + 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 >::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; i0) + 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(), 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; i0) + new_size+=additional_single_quads; + + // see above... + if (new_size>cells.size()) + { + // reseve space for the base class + TriaObjects >::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 >::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() + void + TriaObjects >::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()::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 >::monitor_memory (3); + + } + + + template + void + TriaObjects::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 >::clear(); + face_orientations.clear(); + face_flips.clear(); + face_rotations.clear(); + } + + + void + TriaObjectsQuad3D::clear() + { + TriaObjects >::clear(); + line_orientations.clear(); + } + + + template + unsigned int + TriaObjects::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 >::memory_consumption() ); + } + + + unsigned int + TriaObjectsQuad3D::memory_consumption () const + { + return (MemoryConsumption::memory_consumption (line_orientations) + + this->TriaObjects >::memory_consumption() ); + } + + + + // explicit instantiations + + template class TriaObjects >; + template class TriaObjects >; + } +} + +DEAL_II_NAMESPACE_CLOSE + diff --git a/deal.II/deal.II/source/grid/tria_objects.cc b/deal.II/deal.II/source/grid/tria_objects.cc index 148eb1ab31..16fe8d842f 100644 --- a/deal.II/deal.II/source/grid/tria_objects.cc +++ b/deal.II/deal.II/source/grid/tria_objects.cc @@ -14,9 +14,9 @@ #include #include - -#include -#include +#include +#include +#include @@ -26,393 +26,262 @@ namespace internal { namespace Triangulation { - template<> - void - TriaObjects >::reserve_space (const unsigned int new_lines) + template <> + template + typename dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_single_line (const dealii::Triangulation &tria) { - const unsigned int new_size = new_lines + - std::count_if (used.begin(), - used.end(), - std::bind2nd (std::equal_to(), 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 >::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(), 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) + { + 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::raw_line_iterator(&tria,0,pos); } + + - - void - TriaObjectsHex::reserve_space (const unsigned int new_hexes) + template <> + template + typename dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_pair_line (const dealii::Triangulation &tria) { - const unsigned int new_size = new_hexes + - std::count_if (used.begin(), - used.end(), - std::bind2nd (std::equal_to(), 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) + // no free slot + return tria.end_line(); + else + next_free_pair=pos+2; + + return typename dealii::Triangulation::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(), true)); - - // see above... - if (new_size>cells.size()) - { - TriaObjects >::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 >::monitor_memory (const unsigned int) const + template <> + template + typename dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_single_quad (const dealii::Triangulation &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() - void - TriaObjects >::monitor_memory (const unsigned int) const + + template <> + template + typename dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_pair_quad (const dealii::Triangulation &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() + template + typename dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_single_quad (const dealii::Triangulation &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()::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) + { + 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::raw_quad_iterator(&tria,0,pos); } + + - - void - TriaObjectsQuad3D::monitor_memory (const unsigned int) const + template <> + template + typename dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_pair_quad (const dealii::Triangulation &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 >::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) + // no free slot + return tria.end_quad(); + else + next_free_pair=pos+2; + + return typename dealii::Triangulation::raw_quad_iterator(&tria,0,pos); } - template - void - TriaObjects::clear() + template <> + template + typename dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_single_line (const dealii::Triangulation &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 >::clear(); - face_orientations.clear(); - face_flips.clear(); - face_rotations.clear(); - } - void - TriaObjectsQuad3D::clear() - { - TriaObjects >::clear(); - line_orientations.clear(); - } - - - template - unsigned int - TriaObjects::memory_consumption () const + template <> + template + typename dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_pair_line (const dealii::Triangulation &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 >::memory_consumption() ); - } - unsigned int - TriaObjectsQuad3D::memory_consumption () const + template <> + template + typename dealii::Triangulation::raw_hex_iterator + TriaObjects >::next_free_hex (const dealii::Triangulation &tria, + const unsigned int level) { - return (MemoryConsumption::memory_consumption (line_orientations) + - this->TriaObjects >::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) + // no free slot + return tria.end_hex(); + else + next_free_pair=pos+2; + + return typename dealii::Triangulation::raw_hex_iterator(&tria,level,pos); } + + + + // explicit instantiations - template class TriaObjects >; - template class TriaObjects >; +#if deal_II_dimension > 1 + template dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_single_line(const dealii::Triangulation &); + template dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_pair_line(const dealii::Triangulation &); + template dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_single_quad(const dealii::Triangulation &); + template dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_pair_quad(const dealii::Triangulation &); + + template dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_single_line(const dealii::Triangulation &); + template dealii::Triangulation::raw_line_iterator + TriaObjects >::next_free_pair_line(const dealii::Triangulation &); + template dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_single_quad(const dealii::Triangulation &); + template dealii::Triangulation::raw_quad_iterator + TriaObjects >::next_free_pair_quad(const dealii::Triangulation &); +#endif +#if deal_II_dimension == 3 + template dealii::Triangulation::raw_hex_iterator + TriaObjects >::next_free_hex(const dealii::Triangulation &, const unsigned int); +#endif } } diff --git a/deal.II/deal.II/source/hp/dof_handler.cc b/deal.II/deal.II/source/hp/dof_handler.cc index 381747f7f6..61c82c7bac 100644 --- a/deal.II/deal.II/source/hp/dof_handler.cc +++ b/deal.II/deal.II/source/hp/dof_handler.cc @@ -3508,30 +3508,25 @@ namespace hp { // 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 @@ -3593,15 +3588,13 @@ namespace hp // 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()] @@ -3879,15 +3872,13 @@ namespace hp // 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 @@ -3952,15 +3943,13 @@ namespace hp // 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()] @@ -4323,16 +4312,9 @@ namespace hp } - template - void DoFHandler::pre_refinement_notification (const Triangulation &) - { - create_active_fe_table (); - } - -#if deal_II_dimension == 1 - template <> - void DoFHandler<1>::pre_refinement_notification (const Triangulation<1> &tria) + template + void DoFHandler::pre_refinement_notification (const Triangulation &tria) { create_active_fe_table (); @@ -4343,53 +4325,26 @@ namespace hp Assert (has_children.size () == 0, ExcInternalError ()); for (unsigned int i=0; i *has_children_level = - new std::vector (lines_on_level); + new std::vector (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(), -1)); + std::bind2nd (std::not_equal_to(), + static_cast(RefinementCase::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 *has_children_level = - new std::vector (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(), -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 (); @@ -4400,12 +4355,16 @@ namespace hp Assert (has_children.size () == 0, ExcInternalError ()); for (unsigned int i=0; i *has_children_level = - new std::vector (hexes_on_level); - - // Check for each cell, if it - // has children. + new std::vector (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 (), @@ -4416,6 +4375,7 @@ namespace hp } #endif + template void DoFHandler::post_refinement_notification (const Triangulation &tria) { diff --git a/deal.II/deal.II/source/multigrid/mg_transfer_block.cc b/deal.II/deal.II/source/multigrid/mg_transfer_block.cc index c80bd4db3e..8d815b1499 100644 --- a/deal.II/deal.II/source/multigrid/mg_transfer_block.cc +++ b/deal.II/deal.II/source/multigrid/mg_transfer_block.cc @@ -2,7 +2,7 @@ // $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 @@ -166,13 +166,15 @@ void MGTransferBlockBase::build_matrices ( { cell->get_mg_dof_indices (dof_indices_parent); + Assert(cell->n_children()==GeometryInfo::max_children_per_cell, + ExcNotImplemented()); for (unsigned int child=0; childn_children(); ++child) { // set an alias to the // prolongation matrix for // this child const FullMatrix &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); @@ -203,13 +205,15 @@ void MGTransferBlockBase::build_matrices ( { cell->get_mg_dof_indices (dof_indices_parent); + Assert(cell->n_children()==GeometryInfo::max_children_per_cell, + ExcNotImplemented()); for (unsigned int child=0; childn_children(); ++child) { // set an alias to the // prolongation matrix for // this child const FullMatrix &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); diff --git a/deal.II/deal.II/source/multigrid/mg_transfer_component.cc b/deal.II/deal.II/source/multigrid/mg_transfer_component.cc index 3c7411bea9..506a233f64 100644 --- a/deal.II/deal.II/source/multigrid/mg_transfer_component.cc +++ b/deal.II/deal.II/source/multigrid/mg_transfer_component.cc @@ -2,7 +2,7 @@ // $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 @@ -208,7 +208,7 @@ void MGTransferComponentBase::build_matrices ( // prolongation matrix for // this child const FullMatrix &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); @@ -245,7 +245,7 @@ void MGTransferComponentBase::build_matrices ( // prolongation matrix for // this child const FullMatrix &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); diff --git a/deal.II/deal.II/source/multigrid/mg_transfer_prebuilt.cc b/deal.II/deal.II/source/multigrid/mg_transfer_prebuilt.cc index b665fefebd..326add90f7 100644 --- a/deal.II/deal.II/source/multigrid/mg_transfer_prebuilt.cc +++ b/deal.II/deal.II/source/multigrid/mg_transfer_prebuilt.cc @@ -2,7 +2,7 @@ // $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 @@ -96,13 +96,15 @@ void MGTransferPrebuilt::build_matrices ( { cell->get_mg_dof_indices (dof_indices_parent); + Assert(cell->n_children()==GeometryInfo::max_children_per_cell, + ExcNotImplemented()); for (unsigned int child=0; childn_children(); ++child) { // set an alias to the // prolongation matrix for // this child const FullMatrix &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()); @@ -131,13 +133,15 @@ void MGTransferPrebuilt::build_matrices ( { cell->get_mg_dof_indices (dof_indices_parent); + Assert(cell->n_children()==GeometryInfo::max_children_per_cell, + ExcNotImplemented()); for (unsigned int child=0; childn_children(); ++child) { // set an alias to the // prolongation matrix for // this child const FullMatrix &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); diff --git a/deal.II/deal.II/source/numerics/derivative_approximation.cc b/deal.II/deal.II/source/numerics/derivative_approximation.cc index b69e68ab83..0472fc83d8 100644 --- a/deal.II/deal.II/source/numerics/derivative_approximation.cc +++ b/deal.II/deal.II/source/numerics/derivative_approximation.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -740,7 +741,7 @@ approximate_cell (const Mapping &mapping, // active neighbors std::vector::active_cell_iterator> active_neighbors; active_neighbors.reserve (GeometryInfo::faces_per_cell * - GeometryInfo::subfaces_per_face); + GeometryInfo::max_children_per_face); // vector // g=sum_i y_i (f(x+y_i)-f(x))/|y_i| @@ -776,57 +777,8 @@ approximate_cell (const Mapping &mapping, // first collect all neighbor // cells in a vector, and then // collect the data from them - active_neighbors.clear (); - for (unsigned int n=0; n::faces_per_cell; ++n) - if (! cell->at_boundary(n)) - { - typename DH::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::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; cn_children(); ++c) - for (unsigned int f=0; f::faces_per_cell; ++f) - if (neighbor->child(c)->neighbor(f) == cell) - active_neighbors.push_back (neighbor->child(c)); - }; - }; - + GridTools::template get_active_neighbors >(cell, active_neighbors); + // now loop over all active // neighbors and collect the // data we need @@ -1034,7 +986,6 @@ DerivativeApproximation:: derivative_norm(const Tensor<3,deal_II_dimension> &derivative); - // static variables // // on AIX, the linker is unhappy about some missing symbols. they @@ -1047,7 +998,6 @@ DerivativeApproximation::Gradient::update_flags; template const UpdateFlags DerivativeApproximation::SecondDerivative::update_flags; - template const UpdateFlags DerivativeApproximation::ThirdDerivative::update_flags; diff --git a/deal.II/deal.II/source/numerics/error_estimator.cc b/deal.II/deal.II/source/numerics/error_estimator.cc index 38f23b390a..119f06d710 100644 --- a/deal.II/deal.II/source/numerics/error_estimator.cc +++ b/deal.II/deal.II/source/numerics/error_estimator.cc @@ -745,8 +745,10 @@ estimate_some (const hp::MappingCollection &mapping, // 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 @@ -766,7 +768,7 @@ estimate_some (const hp::MappingCollection &mapping, // 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 diff --git a/deal.II/deal.II/source/numerics/solution_transfer.cc b/deal.II/deal.II/source/numerics/solution_transfer.cc index 8ad91606f6..8b71edda6e 100644 --- a/deal.II/deal.II/source/numerics/solution_transfer.cc +++ b/deal.II/deal.II/source/numerics/solution_transfer.cc @@ -201,13 +201,16 @@ prepare_for_coarsening_and_refinement(const std::vector > &all_in } Assert((n_cells_to_coarsen+n_cells_to_stay_or_refine)==n_active_cells, ExcInternalError()); - Assert(n_cells_to_coarsen%GeometryInfo::children_per_cell==0, - ExcInternalError()); - Assert(n_cells_to_coarsen%GeometryInfo::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::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 @@ -225,7 +228,7 @@ prepare_for_coarsening_and_refinement(const std::vector > &all_in // 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()) diff --git a/deal.II/deal.II/source/numerics/time_dependent.cc b/deal.II/deal.II/source/numerics/time_dependent.cc index 61d80668fc..64404ff0cc 100644 --- a/deal.II/deal.II/source/numerics/time_dependent.cc +++ b/deal.II/deal.II/source/numerics/time_dependent.cc @@ -2,7 +2,7 @@ // $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 @@ -859,17 +859,19 @@ void TimeStepBase_Tria::refine_grid (const RefinementData refinement_data) // 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::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::children_per_cell-1); + previous_cells += (GeometryInfo::max_children_per_cell-1); else if (cell->coarsen_flag_set()) - previous_cells -= (GeometryInfo::children_per_cell-1) / - GeometryInfo::children_per_cell; + previous_cells -= (GeometryInfo::max_children_per_cell-1) / + GeometryInfo::max_children_per_cell; // @p{previous_cells} now gives the // number of cells which would result @@ -892,11 +894,11 @@ void TimeStepBase_Tria::refine_grid (const RefinementData refinement_data) endc = tria->end(); for (; cell!=endc; ++cell) if (cell->refine_flag_set()) - estimated_cells += (GeometryInfo::children_per_cell-1); + estimated_cells += (GeometryInfo::max_children_per_cell-1); else if (cell->coarsen_flag_set()) - estimated_cells -= (GeometryInfo::children_per_cell-1) / - GeometryInfo::children_per_cell; + estimated_cells -= (GeometryInfo::max_children_per_cell-1) / + GeometryInfo::max_children_per_cell; // calculate the allowed delta in // cell numbers; be more lenient @@ -960,7 +962,7 @@ void TimeStepBase_Tria::refine_grid (const RefinementData refinement_data) // cells tagged for refinement for (unsigned int i=0; i::children_per_cell-1) + i += GeometryInfo::max_children_per_cell-1) if (p_refinement_threshold != sorted_criteria.end()) ++p_refinement_threshold; else @@ -1021,7 +1023,7 @@ void TimeStepBase_Tria::refine_grid (const RefinementData refinement_data) // of sorted_criteria, which is // sorted in ascending order for (unsigned int i=0; i::children_per_cell-1)) + i += (GeometryInfo::max_children_per_cell-1)) if (p_refinement_threshold != p_coarsening_threshold) --refinement_threshold; else diff --git a/deal.II/doc/doxygen/deal.dox b/deal.II/doc/doxygen/deal.dox index 00d9015210..550b427d67 100644 --- a/deal.II/doc/doxygen/deal.dox +++ b/deal.II/doc/doxygen/deal.dox @@ -10,8 +10,9 @@ INPUT = headers/ \ ../../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 @@ -47,5 +48,6 @@ IMAGE_PATH = images \ ../../examples/step-27/doc \ ../../examples/step-28/doc \ ../../examples/step-29/doc \ + ../../examples/step-30/doc ../../examples/step-31/doc \ ../../examples/step-33/doc diff --git a/deal.II/doc/doxygen/tutorial/toc.html b/deal.II/doc/doxygen/tutorial/toc.html index 56c15480ea..18aff051d3 100644 --- a/deal.II/doc/doxygen/tutorial/toc.html +++ b/deal.II/doc/doxygen/tutorial/toc.html @@ -241,6 +241,10 @@ searching for programs with a certain functionality. Solving a complex-valued Helmholtz equation. Sparse direct solvers. Dealing with parameter files. + Step-30 + Anisotropic refinement for DG finite element methods. + + Step-33 A nonlinear hyperbolic conservation law: The Euler equations of @@ -381,6 +385,13 @@ by topic: + + Step-30 + Anisotropic refinement for DG finite element methods. + + + + Step-16 Multilevel preconditioners diff --git a/deal.II/doc/news/anisotropic.html b/deal.II/doc/news/anisotropic.html index 5bb9a5f961..3d63a1b7bf 100644 --- a/deal.II/doc/news/anisotropic.html +++ b/deal.II/doc/news/anisotropic.html @@ -1,24 +1,13 @@ - - - - - The deal.II news page - - - - - - -

    Changes between the main branch and the anisotropic branch

    +/** + * @page anisotropic_changes Changes between the trunk and branch_anisotropic

    -This is the list of changes between the main subversion branch and the -anisotropic branch of deal.II library. It is -subdivided into changes made to the three sub-libraries base, lac, and deal.II, as well as changes to the general infrastructure, documentation, etc. +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 base, lac, and deal.II, as well as +changes to the general infrastructure, +documentation, etc.

    @@ -41,43 +30,40 @@ refinement.

    1. - Changed: The FiniteElement<dim>::get_prolongation_matrix and FiniteElement<dim>::get_restriction_matrix functions now have an - additional argument of type RefineCase::Type 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. -
      (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. +
      + (Tobias Leicht 2006/07/04)

    2. - Changed: GeometryInfo::children_per_cell 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 cell->n_children(), - which gives the number of children of a specific - cell which is refined iso- or anisotropically. + Changed: GeometryInfo::children_per_cell 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 + cell->n_children(), which gives the number of + children of a specific cell which is refined iso- + or anisotropically.
      (RH 2005/02/26)

    3. Changed: The analogous change applies to the number of children - of a face. GeometryInfo::subfaces_per_face 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 + of a face. GeometryInfo::subfaces_per_face 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 face->n_children(), which gives the number of @@ -88,15 +74,13 @@ refinement.

    4. - Changed: The GeometryInfo::child_cell_on_face is generalized to - anisotropic refinement and has now an additional - RefineCase::Type 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 cell->neighbor_child_on_subface rather than - through the GeometryInfo::child_cell_on_face function. + through the GeometryInfo::child_cell_on_face function.
      (RH 2005/02/27)

      @@ -129,55 +113,54 @@ refinement.
      1. - New: There is now a new GeometryInfo<dim>::min_cell_refine_case function which returns the - RefineCase::Type 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 RefineCase::cut_y if - the left line (line 0) shall be refined. Another refinement possibility - for the cell would be RefineCase::cut_xy, 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 RefinementCase::cut_xy, but that + is not the minimal case.
        (Tobias Leicht 2006/06/28)

      2. - New: There is now a new GeometryInfo<dim>::line_refine_case function which returns the - RefineCase::Type 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.
        (Tobias Leicht 2006/06/28)

      3. - New: The new GeometryInfo::n_children(ref_case) function returns the - number of children a cell/face has when refined with the - RefineCase::Type ref_case. + New: The new + GeometryInfo::n_children(refinement_case) + function returns the number of children a cell/face has when + refined with the RefinementCase refinement_case.
        (RH 2005/11/07)

      4. - New: Given a RefineCase::Type of a cell the new - GeometryInfo::face_refine_case function returns the - RefineCase::Type of a face.
        (RH 2005/11/07) + New: Given a RefinementCase of a cell the new + GeometryInfo::face_refinement_case function returns the + RefinementCase of a face. +
        + (RH 2005/11/07)

      5. - New: There is now a new GeometryInfo<dim>::isotropic_refinement variable of type - RefineCase::Type representing the isotropic + New: There is now a new RefinementCase + GeometryInfo::isotropic_refinement representing the isotropic refinement case in dim dimensions, - i.e. GeometryInfo<1>::isotropic_refinement=RefineCase::cut_x, - GeometryInfo<2>::isotropic_refinement=RefineCase::cut_xy + i.e. GeometryInfo<1>::isotropic_refinement=RefinementCase::cut_x, + GeometryInfo<2>::isotropic_refinement=RefinementCase::cut_xy and - GeometryInfo<3>::isotropic_refinement=RefineCase::cut_xyz. + GeometryInfo<3>::isotropic_refinement=RefinementCase::cut_xyz.
        (RH 2005/03/03)

        @@ -188,169 +171,119 @@ refinement.

        lac

        -
          -
        -

        deal.II

          -
        1. New: There is now a new Triangulation<dim>::prevent_distorted_boundary_cell 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 prepare_coarsening_and_refinement. Therefore this - should have no effect on user codes. -
          - (Tobias Leicht 2006/08/02) -

          -
        2. - New: There is now a new Triangulation<dim>::tria_post_processing 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 Triangulation<dim>::execute_coarsening_and_refinement will be all you - need. -
          - (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. +
          + (Tobias Leicht 2006/08/02)

        3. - Extended: TheTriangulation<dim>::delete_children now takes an additional argument - keep_outer_faces of type bool which has a - default value of false. If set to true, 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 Triangulation<dim>::execute_coarsening_and_refinement will be all you - need. -
          - (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. +
          + (Tobias Leicht 2006/06/29)

        4. - New: There is now a new Triangulation<dim>::create_children function which actually sets up the - children of a cell and updates the neighbor information. This work has - been done in Triangulation<dim>::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<dim>::execute_coarsening_and_refinement will be all you - need. -
          - (Tobias Leicht 2006/06/29) -

          -
        5. - New: A part of the functionality of Triangulation<dim>::execute_coarsening has been implemented in a new way - and shifted to the new function Triangulation<dim>::coarsening_allowed. 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 true is returned. This is a functionality which is partly dimension dependend. -
          - However, there should never be any reason to use this function in user codes. +
          + However, there should never be any reason to use this function in user codes.
          (Tobias Leicht 2006/06/28)

        6. - New: There is now a new accessor function coarser_neighbor, which returns a bool value - true, if the requested neighbor is a coarser one and - false if the neighbor is as refined as the current cell. This new - functionality is needed in the internals of the library to decide, if - neighbor_of_neighbor or - neighbor_of_coarser_neighbor 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 true, if the requested + neighbor is a coarser one and false if the + neighbor is as refined as the current cell. This new + functionality is needed in the internals of the library to + decide, if neighbor_of_neighbor or + neighbor_of_coarser_neighbor 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.
          (Tobias Leicht 2006/06/28)

        7. - New: There is now a new Triangulation<dim>::MeshSmoothing::allow_anisotropic_smoothing - 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. -
          - Therefore this functionality is off by default. However, in order to use + New: There is now a new + Triangulation::MeshSmoothing::allow_anisotropic_smoothing + 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. +
          + 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. -
          - Note, that for reasons of backwards compatibility this flag is NOT - included in the general - MeshSmoothing::maximum_smoothing flag. +
          + Note, that for reasons of backwards compatibility this flag is + NOT included in the general MeshSmoothing::maximum_smoothing + flag.
          (Tobias Leicht 2006/06/28)

        8. - New: There is now a new TriaObjectAccessor::clear_refine_case function. + New: There is now a new + TriaObjectAccessor::clear_refinement_case function.
          (RH 2005/12/19)

        9. - Extended: The CellAccessor<dim>::neighbor_of_neighbor function is now - extended to anisotropic refinement. + Extended: The CellAccessor::neighbor_of_neighbor function is + now extended to anisotropic refinement.
          (RH 2005/12/15)

        10. Extended (internal): Lines on level>0 have always - been stored pairwise. In order to allow the creation of - single interior lines we now also allow storage of single lines. The - TriangulationLevel<1>::reserve_space function now takes an - additional n_consecutive_lines parameter which - allows to create new single as well as pairs for lines - (n_consecutive_lines=1 or + been stored pairwise. In order to allow the creation of single + interior lines we now also allow storage of single lines. The + TriangulationLevel<1>::reserve_space function + now takes an additional n_consecutive_lines + parameter which allows to create new single as well as pairs + for lines n_consecutive_lines=1 or n_consecutive_lines=2, respectively.
          (RH 2005/12/15) @@ -359,18 +292,17 @@ refinement.

        11. Changed: When allowing anisotropic refinement it cannot be guaranteed that all children of a cell are stored in - consecutive components of the quads.quads or the - hexes.hexes 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 - cell->set_children - 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 - face->set_children - 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.
          Finally, we note that these functions are for internal use, only. @@ -379,12 +311,10 @@ refinement.

        12. - Changed: The cell->refine_flag_set function now returns a - RefineCase::Type argument instead of a boolean. Be - aware, that you now still can ask - if(!cell->refine_flag_set()) , - if(cell->refine_flag_set()==false) 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 if(!cell->refine_flag_set()) + , if(cell->refine_flag_set()==false) and if(cell->refine_flag_set()) , but you cannot ask if(cell->refine_flag_set()==true) any more.
          @@ -392,71 +322,64 @@ refinement.

        13. - Extended: The cell->set_refine_flag function now has a new - RefineCase::Type argument which defaults to GeometryInfo<dim>::isotropic_refinement. + Extended: The CellAccessor::set_refine_flag function now has a + new RefinementCase argument which defaults to + GeometryInfo::isotropic_refinement.
          (RH 2005/03/03)

        14. - New: There is now a new enum RefineCase::Type - defined in geometry_info.h, 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 + geometry_info.h, which allows to describe all + possible (anisotropic and isotropic) refinement cases in (1,) 2 + and 3 dimensions.
          (RH 2005/02/26)

        15. - 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. + 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.
          (RH 2005/02/26)

        16. - New: There is now a new TriaObjectAccessor::refine_case function which returns the - RefineCase::Type 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.
          (RH 2005/02/26)

        17. - New: There is now a new TriaObjectAccessor::set_refine_case function. This function - is mainly for internal use (required by Triangulation::execute_coarsening_and_refinement). It is - not provided for dim=1 as there the refinement - case defaults to isotropic refinement. -
          + 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 dim=1 as there the refinement case + defaults to isotropic refinement. +
          + 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. +
          (RH 2005/02/26)

        18. - New: New vector<RefineCase::Type> - refine_cases vectors have been introduced in TriangulationLevel<2>::QuadsData and - TriangulationLevel<3>::HexesData. For - memory efficiency (but with a penalty on run-time) they might - be replaced by vector<vector<bool> > (dim, - vector<bool> (n_quads/n_hexes)), later. + + New: New vector@ refinement_cases + vectors have been introduced in TriaObjects. For memory + efficiency (but with a penalty on run-time) they might be + replaced by vector@ @> (dim, vector@ + (n_quads/n_hexes)), later.
          (RH 2005/02/26)

        -
        -Last update $Date$ - - - +*/ diff --git a/deal.II/doc/news/changes.h b/deal.II/doc/news/changes.h index c1b26f949c..78c41006c5 100644 --- a/deal.II/doc/news/changes.h +++ b/deal.II/doc/news/changes.h @@ -8,6 +8,10 @@ made to the three sub-libraries base, lac, and deal.II, as well as changes to the general infrastructure, documentation, etc. +
        +Furthermore, all changes which have been performed en route to +extending deal.II from isotropic to anisotropic refinement are listed +in this list.

        diff --git a/deal.II/examples/step-12/step-12.cc b/deal.II/examples/step-12/step-12.cc index 586048b2b4..4d8f246278 100644 --- a/deal.II/examples/step-12/step-12.cc +++ b/deal.II/examples/step-12/step-12.cc @@ -176,12 +176,9 @@ void Beta::value_list(const std::vector > &points, for (unsigned int i=0; i &p=points[i]; - Point &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()); } } @@ -657,7 +654,7 @@ void DGMethod::setup_system () sparsity_pattern.reinit (dof_handler.n_dofs(), dof_handler.n_dofs(), (GeometryInfo::faces_per_cell - *GeometryInfo::subfaces_per_face+1)*fe.dofs_per_cell); + *GeometryInfo::max_children_per_face+1)*fe.dofs_per_cell); // For DG discretizations we call // the function analogue to diff --git a/deal.II/examples/step-28/step-28.cc b/deal.II/examples/step-28/step-28.cc index af63ba5f36..c635cc6320 100644 --- a/deal.II/examples/step-28/step-28.cc +++ b/deal.II/examples/step-28/step-28.cc @@ -1311,7 +1311,7 @@ assemble_cross_group_rhs_recursive (const EnergyGroup // cell that has children replaced // by one of its children: else - for (unsigned int child=0; child::children_per_cell;++child) + for (unsigned int child=0; child::max_children_per_cell;++child) { FullMatrix new_matrix (fe.dofs_per_cell, fe.dofs_per_cell); fe.get_prolongation_matrix(child).mmult (new_matrix, diff --git a/deal.II/examples/step-30/Makefile b/deal.II/examples/step-30/Makefile new file mode 100644 index 0000000000..2004c65130 --- /dev/null +++ b/deal.II/examples/step-30/Makefile @@ -0,0 +1,156 @@ +# $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========= $( $@ \ + || (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 + + diff --git a/deal.II/examples/step-30/doc/intro.dox b/deal.II/examples/step-30/doc/intro.dox new file mode 100644 index 0000000000..e6d260632b --- /dev/null +++ b/deal.II/examples/step-30/doc/intro.dox @@ -0,0 +1,482 @@ + +

        Introduction

        + + +

        Overview

        + +This example is devoted to anisotropic refinement, 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: +
          +
        1. Anisotropic refinement: What is the meaning of anisotropic refinement? +
        2. Implementation: Necessary modifications of code to work with anisotropically refined meshes. +
        3. Jump indicator: A simple indicator for anisotropic refinement in + the context of DG methods. +
        +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). + + +

        Anisotropic refinement

        + +All the adaptive processes in the preceding tutorial programs were based on +isotropic 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, anisotropic refinement 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. + +

        Motivation

        +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. + +

        Implementation

        + +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::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::children_per_cell has +consequently been removed. It has now been replaced by +GeometryInfo::max_children_per_cell which specifies the +maximum 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 cell-@>n_children(), +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::subfaces_per_face no +longer exists; the pertinent information can now be queried using +GeometryInfo::max_children_per_face or face->n_children(), +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 level 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: + +
          +
        • Finer neighbor: 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 if(face->has_children()). 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 cell->neighbor_child_on_subface(face_no, subface_no) + function. Still, in 3D there are two cases which need special consideration: +
            +
          • 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 face->n_children() and + face->number_of_children(). 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 face->number_of_children() 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. + +
          • 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. +
          + + However, it is comfortable to know, that + cell->neighbor_child_on_subface(face_no,subface_no) 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::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 + cell->neighbor_of_neighbor(face_no) function. If the neighbor is + coarser, however, you would have to use + cell->neighbor_of_coarser_neighbor(face_no).first instead. In order + to make this easy for you, there is the new + cell->neighbor_face_no(face_no) function which does the correct thing + for you and returns the desired result. + +
        • Neighbor is as fine as our cell: 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 + cell->coarser_neighbor(face_no) function returning a bool value. In + order to get the relevant case of a neighbor of the same coarseness we would + use else if (!cell->coarser_neighbor(face_no)). 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. + +
        • Coarser neighbor: 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 + else. The cell->neighbor_of_coarser_neighbor(face_no) + function takes care of all the complexity of anisotropic refinement combined + with possible non standard face orientation, flip and rotation on general 3D meshes. + +
        + +

        Mesh smoothing

        +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: +
          +
        1. MeshSmoothing::limit_level_difference_at_vertices: 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. + +
        2. MeshSmoothing::allow_anisotropic_smoothing: 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 allow_anisotropic_smoothing 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. +
        + + +

        Jump indicator

        + +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: +
          +
        1. Calculate an error indicator. +
        2. 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. +
        3. Evaluate a distinct anisotropic indicator only on the flagged cells. +
        4. Use the anisotropic indicator to set a new, anisotropic refinement flag + for cells where this is appropriate, leave the flags unchanged otherwise. +
        5. Call Triangulation::execute_coarsening_and_refinement to perform the + requested refinement, using the requested isotropic and anisotropic flags. +
        +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. + + + +

        The problem

        + +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. diff --git a/deal.II/examples/step-30/doc/results.dox b/deal.II/examples/step-30/doc/results.dox new file mode 100644 index 0000000000..c608df53b5 --- /dev/null +++ b/deal.II/examples/step-30/doc/results.dox @@ -0,0 +1,151 @@ +

        Results

        + + +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 ... +Writing grid to ... +Writing solution to ... +Cycle 1: + Number of active cells: 239 + Number of degrees of freedom: 956 +Time of assemble_system2: 0.072005 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 2: + Number of active cells: 491 + Number of degrees of freedom: 1964 +Time of assemble_system2: 0.144009 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 3: + Number of active cells: 1031 + Number of degrees of freedom: 4124 +Time of assemble_system2: 0.296019 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 4: + Number of active cells: 2027 + Number of degrees of freedom: 8108 +Time of assemble_system2: 0.576036 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 5: + Number of active cells: 4019 + Number of degrees of freedom: 16076 +Time of assemble_system2: 1.13607 +Writing grid to ... +Writing grid to ... +Writing solution to ... + +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 ... +Writing grid to ... +Writing solution to ... +Cycle 1: + Number of active cells: 171 + Number of degrees of freedom: 684 +Time of assemble_system2: 0.048003 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 2: + Number of active cells: 255 + Number of degrees of freedom: 1020 +Time of assemble_system2: 0.072005 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 3: + Number of active cells: 397 + Number of degrees of freedom: 1588 +Time of assemble_system2: 0.16401 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 4: + Number of active cells: 658 + Number of degrees of freedom: 2632 +Time of assemble_system2: 0.192012 +Writing grid to ... +Writing grid to ... +Writing solution to ... +Cycle 5: + Number of active cells: 1056 + Number of degrees of freedom: 4224 +Time of assemble_system2: 0.304019 +Writing grid to ... +Writing grid to ... +Writing solution to ... +@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). + + + + + + + + + + + + +
        + @image html step-30.sol-1.iso.png + + @image html step-30.sol-1.aniso.png +
        + @image html step-30.sol-5.iso.png + + @image html step-30.sol-5.aniso.png +
        + +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. + diff --git a/deal.II/examples/step-30/doc/step-30.grid-3.aniso.png b/deal.II/examples/step-30/doc/step-30.grid-3.aniso.png new file mode 100644 index 0000000000000000000000000000000000000000..89c9aaf075f6316c9d8a23d8f71a1d6890ae0c7b GIT binary patch literal 1354 zcmeAS@N?(olHy`uVBq!ia0y~yU|b4hU*%u|k`+%YdVmyXfk$L90|S2|2s5s*U!DmR zWH0gbb!ETKCCF!Pa_jo_=L`%iFFjoxLn>~)y?e1}wt)a^z>5$6_ph)wvdQipiky?Z@N0*7dPYh|o;^{daoY<8`mIww!h^e$n$S@!x)I&PTykdD+wbvJy|1r*6m$bR zz3jVs!Tsw^cHBNL_ZV>)faw>Qr3jgZ8T;O`|J(7??0~ggrI6vvYg?ym>b-IC_yxD! zWhU);UovXVPZ!?#5(x_phsE=McI|s_Dy4fU<6}Ahx|7zy`6u0?&pd6k<3@y;gU&VX zhKDf;1+|wV^%eeJKDv;5)665+(;4kfJ=ZqsH@nTxy|r@rj~AP_%bo3(tQB*Ze>Hu% z%-NX>_FPW?dUL^I)BLg@y=fs|BN=MLdM~BFzwGdRwxzE#NY%T|ai4$b06pTdc#6%WsX>2dqC=d$G2$l5TbXUonrZQd}?dW&(q;g$s@@2!5Vv75c>d|icc=lb(ZE-7_p zpEFKR`MkN=OgZ%4%O0R?^`@B{E~GO)k##Uw=iWHG(AMkozRLf4pD(9A`)YUI-1@(b z+lQ;{D*NoXKOA``P>^_ZN5SULUs<)nR$$9@ z;b(0_hv)OEDR&lImdKjFF0%D{x_{pL+z-3|zu3&6IAeb6b-%cnex>&cme&`nEI7|} z?)`&#wZ#|G-ha7ys^0b9LGIemnO&_>VGquW{}loT^z(9oWiGSlPc1ia?KHDreV*xr zb%XW{>89vuFVywlblcfy?`2pV`>mw#MO)vuf2rEuUtM+gyHEZBj*AK9pa?nf_1J}X zDUpqb_086(HSB2?a65nA>JU@`FcSb%-N`9Ihw6@qFG#)yOc!r6`0l>AxJyU-LXB|G z=ery1PSxH25}Ba1&b;lkpZT}`iRBY|e;dX*&1ao+pON|2YtQ*xy z=qZc+%`LpwE9dNK)|6WJZ57DT47Flbt8%8FogEt2U$pP$>fMcdnwjOJ^%MRdZMz*K z)Awxpit|j+4AWq37|(b(^xTTDbLW8}wQk>MSP(Ul@0F*6e>9bjmEr{ceZd zA)uT0y1m{P=Wtw=|5beuFzq527QkRY6e9`@uXj3&v~OQ~;HRugh*xDz)&Ji}c@>de rVA*m(qyH<$$ticW-T-}}F!lf0+liYG*KPq8hzty#u6{1-oD!M`?~Jy`RhqN>trvpeb06P0Aw6a z*qj4^O@YX_bE^bW$nM;BWdhLH-DO5NBX003bKfPuL=2#5RtG#Y{-GyvkL zAPnLF7=!@`4?qxr2O&HNfB+5#_36KVdBw97aolS4u{4e?P&Z44GA0?L?atwiP}33q0s<{%mP4Y9N|MC0D*WIae_>P zU>G?gC>3!8Ax4oazyMODLJ$?k<2MozfT;jDK2Ajzj7AJW07ONjsc0BPgwg1YX*dwX zZ>WNZID}AeFcn#Nn0gIHRDUYMFyx}y90>qho;%oBxkMKV3f*&)&~m^cU(7U9JT@p1 zR$MpZDjAo9 z7x^pF@47E_R>xcq3jdn(H+HSGBc!3DB2k|7mMG%~4%st1Q!NltnD=|AhXcMmo zjYO=wUT`8Wp~2)o)nq z9{T8N+Uk45beOTrdo5NyvUIP_m?Uk}ubcw_F?z`yW~enxM5LyNuXHD?Y_(0<6ZfB^ zu-o#y{FI$A&!BK6pbIOP=B*r7Tl##Ou`BX$oVKqb=~x=u?B)5RQEYM3%(6Q(HLDY| zQm@-A$SYs6MVSQ@HvLdoAvC?!zn>BLRebu11dH-CZP>9PwCl|Kx^j<~`KantZ7mm+9MZ@8ULL}&7`%_z_RsthvQ(!z)f1gUh65%%eCM{1by9-lAS zaNl2Xp8UhFEq0=JWs_^&a%AR*<03^%Z?#6@C^M&^Empi(qsIxDD{i(dbP+nBn)M9Y zl-Ngm?26J9;-JVp_*Fw+rS_O=qoLeCnu@KO{%Y9Kr)z`^9&ztZf=%mA=G90)j`@WI zw(WTQ#I;d^z;td*>VAMd-&n74YNl(Oa4M^4*5%s~e)M#6%RlDJt55+9CRkqKS(23m zDOok7;rBgXeXSVX@?}_(Yr^uoiJq0cCfLrCJZGVQ9A8I2Y}Id_qjQmCg&P^Eh24D{^H9CG&lvIHl_p1zWEu zDIREFbVfM)+}Snf58M&O!7a3=wTj}3Q=)!rb5U;Bz}W-6rbW{E4C@zeSt@}8OTL4) zo$zu9N7*;LCDx)cSDi?>`*{E3sr>F%$v{+z>4K<+iy>LW(hawzS(aq-=5FM4De8w( zbQ&?<73n_OBIq*VoOv@Zc+%Fz(^bbq`3bRp+hkNx*DniiU!H)_3CaEfg_WR3gC1-6fe|cM)?}7unav9Lfz7N zZg$n3p}Sc&1kAsU`JdCP?sV*1-$4t#OS%1L2>CCiTa$MD265WUo~{9G$fVD}F_L%p zhZaY(n#5>Ez&+ZI#m#WC)d3k#KTcO!9gn!n$!FM;+*mYpdat7R!DQ#St7%lkyjxCl zOIgWY?6w1Qh2B2U0BvE{NOprd$4`Ua8O}aSNn0d+tPG+Q2dJcbi9a;~4=U`1?=NFw zOroNT{Y_?fvo;02EG}cEpZ9Fko>B8KS2M95ldtDpZ7X{l|JN($4w=`dBZFJ4%^I5_DNSd++8&_3~OzK`e4BptrY(4~9H=%6g& zSFuNFrz$J36OW(iZB9|1k@tE_Ru)j?M>31#G_(0(Nb_XsVNG4WRcpTtniFSEJj9wW z^mUu0&);Gl==`EbVPvrd`tZK2WKB{t@bhF;IOLwHfO}Kl0wPh=f zt7;#$%i#XLIdgyBLG@A7ErzsHMsMmWe1>1Y{boxxrUy659s6J^B}X^N;`JkU z?OdhEKTxZsT)C;l!4@jAVro#3gv1`!Y4ub>fqnMzZ0L_`87 z`bi*zRX9O=U3Y^QSW#f)Cz!jr%2c91W8`%tl<*Xr3bGkrg`~NJHLo8<2SpgVSQAd9 zwedsXb}|8u3gZm2t*S?!bdpUH7F`}YiJxy-^c1*Vg_sg#p0hc&)cvw`TQ!AH>i#fo zKYO9aa0hE-wm>YaO~f;sY{sf3|9rU8u6Ap`VfT}BGpuOy#e3QQ#@oI2RF_%&tG_a~ z$Zocr3>oSSm8;&GQPc14a7qgMW~+xl!_DjK-ooFnEs=Qz?T)hvz3JYPrS1-GcLYBP z?kCqA^oa6*`?nTZua%vwbJCw>4(I&B>jf-t_wX4>10&mLf54FXPn zMn>dk-}zkF(;OB*-xMW`epZ(t*)3Uqqx+QM!*7Y747~BqiNP zKmA&TB@1lu`8Qg(ApmIV-H5Jz4j6&zhk_c vpO%Z$il%Sdc&5T9CUdNQ{Z#!Q0Vh@^whw4I{iqkTZO literal 0 HcmV?d00001 diff --git a/deal.II/examples/step-30/doc/step-30.sol-1.iso.png b/deal.II/examples/step-30/doc/step-30.sol-1.iso.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9e828c3a3bbfe4c48f4c47b169d2733664522d GIT binary patch literal 2390 zcmah~c|25mA3nW(yeeEG6w#3_$`-N?Lo>EXgmP0cU5tHe46X(zU0cF!xs-L9ED0%u zh&dM#LSwSM_AHHT#R$VV?{VKh-aq?(zUTaYzvuZq&-Xchoh1A7mO=-l4gdfkWNn3W z0DwK-==00Iy(sb^J&J}NRP4_=;SmHu5gLuQyTAYdAuxadOG_{oeE}c{BQOX+SQ>;t zSO9?#044%33=koh2mug)MIcQg1Q7u&S`cc1?nNLX5klErI|LvCQ!imG3=wHC5!Jyo zlt7h45WPhN(ZXUuEP5Rz?#j@@f)I! z&0$o6MQCUf5n3>Uy8h#cAh46tTQUIfv#oJvP7&FQ*~#f8pdkMGBoecFS6CAp3#Ex- zZjSnu(F^L2fKGmbz)wo>_G@Kf)9~%^XCfC*tT0ZF3#>;yj7=ZqV+v;B>rGrNe2-S1 zQ9mN-rq_x;72d5ON)0Fj+!ZBk38Dql!N`!-mr&2Zm>N@$n%{i!S+p}pE%V+<$C0Cj zHRKMoZItJT=PV!Sne*aj%2v-k6U|Xkke=%2%WXdv_2~#{G;cI-@rtcf$<}0*_S;Q0 z?^zoI5uS*M&`&Z08k0urPmsfs600kY3?TUAkWgBn+l`WA+kEkUiFiBX!coLM2rFQY z6KJ)2gw!FY=t;U?mtg8`gtA8Nm1kBKe{dx={%uOON?b^L+>Ns&^uL{8v~DXI;MNv{ zf{s38CmDNmv$`7YEwgil@nH&vyvm|kVV<+aj#TfH>zgq@beUqh23nub`Pb^L)R4Q7 z?6ifs)^PoOW*jA`gHDi-FZH>*{f%n!sjP^HwZF;qd~i2rYGD5OxIz|!F+%Ro3Y4`e z8FGi$VimF{KMYvx;OtDwYwbc4OT4=)tJJyUozwRiRfnuYYN}XB+LAzkrFvaRL#dml zor_paj7>S|U{n*i-Bgkjg470*k!riQd@>*Co0qVG_Ft!rqwdFV^@qmD?0J3n^6 z>3-Q4NSM};x;khY_hq`iS$owbn)Sh+vFxT{$S{BU(r(*-d*F}B+rJhrkBIipgcbT4 z9}$m9W_Q1LE6=^`TvL?AUhBK^<+TFSF@(+4=cgNaq#uvDw%|;z1tS^Rg<9nq7=~Hs zS@|yi;8f$a|3u;RdP=@6`-zSX_taX2vf>M#ydO^W98YRr@?X7)ceZG}LR#1!Y))2k zdr_YKtrW)*7h1i=E;HirKA&E4=O6Wpllpg zUR)J9mfiT{GBt=nFFeiiIN4RB+dKR)C#wl(6@g#*JR33kZMZL~+h+e_z9vPLD%%ML z&5LEIC@R~Q%ch*AKi6f{B(O!V5$0C+xz|&c)H59vy)=g+$2Mm?&-Za<1I4?<;t<0b z#*4ZD4He(ifs|U_JY9bFDpe+=mNLjR*wYn|z)tk+Zw`;YFcs3PjZ;3=zCLCpZJ;~U zLHJ^=hYf8y?Udc0=$gB=?C+CA;rBC9JqvlKgN7M{4~3VoI%!X9E@ubid4Vp(hIpmb zQ|B#K@nN9LZ*QXYvZNN*1ewRjmQ3nShDLMrqqT8_7Ois@AZZ+yQSwjlPEyN^JDg56 z57lOcUF25CN<=9y$ngtiH6FMa~8rWJ1;f~chLy@kHFhCD)J*f6BxW+4y^u{<>E;BCdmhKVj zIIlzrq7f{H>MnXDg;Qo_Aht;&8UOmniPDM-m*+cFmq)JV8IGxDN>m8y^_9Ia_ab0g z6v^RfoiRo1M(&s@@)upBR9%@d&k-5j;a*!AKfzUgjk%AQGpC%YF)OT5Q<yDKN9pjios*cf%W*EtNMZUK(`gF^+tB*;=K8EpYBacZbs*zWFa(pCkdMrKeF((e3 zTaPo<Sko z%=r(nN>ep5__5bBJ>%A1p%dEOq|)v-F->u%e|Yw{TB3NRxDaaKzw&HvoKJd+Y!ywj ztHPt0A3X>O*rH4+)4>rPMQHF=`>Q7MxsAPw3&BR zWh=q__8BCZ@j;zJYJktBah~?x_s$PUd`8YHpQp#4xplFT8_bpDktZh_Uv*pZ(qb&o{5~ XyGE$7DaN5+cR_3XdE5(gV(fnbqFsVu literal 0 HcmV?d00001 diff --git a/deal.II/examples/step-30/doc/step-30.sol-5.aniso.png b/deal.II/examples/step-30/doc/step-30.sol-5.aniso.png new file mode 100644 index 0000000000000000000000000000000000000000..140d0926be5506fa56e03102969a843fc5195ed0 GIT binary patch literal 2254 zcmZ`)eLRzU8^5dP9KCs2j#I*nLf&#jFIr=ctv%igd0CBh`bZ=rI(e(zIGCg*j?QA) zvx>@wj-|Zc&p|0;Cgz}w78Y%KA#bz$xt-7RZ`bE{-`910uj~3=-``)qoFhIY&5heP z0sx@t{%?XG0IWHKd|K<*AxJ^dB@U8U9`Onw!Z3^=91dsIK>z^45C8*8C4@(Q00slW z5C#D891sTa01UzaLWCp~9S47-9W~5r&}v^Tv1p(4e{#TmuqI6ztrh3e09;t`CMM z-YjjtjtLIvVa3yKn*RFUF|W(*aw#r`DSr6k;bE{SMP`DsLQ|Et~E4KzdC_Z&~ygIPfcbnA27-tn8a03cKr*bp(h z{x17SxT+A$NNL1leUU3A3KJfX$BdcRoT z-sXAmxpS%@dTc`}OwXJN$m4PO+XCO#;f1~i*^$HZ@?g2LuhWzq_cr?Du%$iiol2zh zVID0WGV=B|9CRYdJ`L_L9g@4~wA#b*GcqQlK)zXYnC_UBXXwmWLAQL}Mue4vQ_OoM zbxpTMN~1ediKUYvUk&VCDi_quEMFJ&*PtY=tj%BAe-QcN3@gJD{+3Q9d5X2Wj8>ZE z4l3-~Ef$wj+w#A-GF*r~TR%rThc2bX#@e-@R)nt~!q8wI;QDY&fLMiO=aYw!{Q#9-_q~NxGYu5uFH*8 zG;V{9SmTgO&}=gu`$EXgym3 z6Rdhz$4J1m+e`RT(`S<=XHJFG@;Tb*%yEx7?xc>vFt@>fIApx*&#PL`Q@FZ5)k7A} zrt=Et8|P<(PmNE?T|MWER5Y~Q3|Hx2vzqrT74#Tl31!+%P(r2 z+nTryU31Ysa;2n`mmIrJjE*7Loz;GGvODPzAte#DqSzSUL69u^5j0YHy1ml8IvOv; zRglix++dm37SCvtlLT2GZ3wWAh#|2L?AmY}#m+o+z~Z(-lOYL~^aPG{_!u5zgi6sA zrhK=eBD(O6mvZaM6J3%A@y4jW_~6o-kJ;d1!L|AJT@oi|(%F}` zrsVJec5JAKSMVU>rMv4ve!Bv30AGB+aE@6ggX=*HfK2dB7&v7^T1QpQb z6DT&kto?${l^;LdU;(Fbr&-aL-z^vWo+wrpI1P9Nm+9S{@m7z1;^=&mQXWjo8+qW2 z^))#eXHgW=b@y5n&e*0VN{>=CnGyaYx5lYe zYSbmv%fHlF|DbwaydjpycAJ`X|C}d6)0^LS+Q7#cDW~&25i;0{VBi>h+9)xuZY|Q1 ze220hVf>o=Z11blDP!?gu{D1Q*)^4McoWh#HzL}12FcjQ{2nT+KezMO)odWQXw@|Y zo?ev|6`EjOFf+`0$Z;3*g#n1H3)2R$)+;J&PBz&S!)@Brx!6JakM^2Se0;b>tx-Hx zC?&HleE8y^*Fh^2k`;x1cVD<1r8`u>Z@G%F^H-Kn6RJw|FFcg&`8;f0)2(aUTog|~ zQf2X zl;U*M@j>gDK*lp}p>4fns@@;h=tL~t7;3jxyfsbkd00;UEzR0T3Yw3PBtuj6rZ= z8Wo121y`6bM+gZO7ZMA?h4DDy`aee;M-HrSOauVE=f1R`51cF-6AU+$flH}FkEFP( zq9!@a*C^gDtur_0is(YQ{R*)l4ESc%*?vl?l*Vahs_i?NXb+>Lg=rFad@!G5el;)I zFUUT%B{L;VQ9WPfJUZx7$TH(q9X0hy%DfQf?=N~dr|vsT)`-UJdRIVeM_>O8Q+?% zruRy`hM|8o`OD&)WqSsF)?t$GX^Xy<8j0{wJ-|9Gw>N$)R$8sxe6cA@DfJFWDpgyh zH0y9N2gM(o)|-=UptSv3r_*V!m$23@_EdWZZq+~RZYr=eH?sxtxJl-VkbWwdrnC)c znIH1kXr;qU4W)mFLz-&TNs*h?5lR}h7$0YT71J+c6Y%_c%Cfo7rj`vNoub&ZOEai?ny0 z(?DWvASWes;NwG}6?1>Zf#% z{WUY8#&y=VT5D}t_+ZbJT{{*~li0vf=01L3Ht69PY;zTrS!zlnR#mPl*_xnDj7d`% zPW!EOgX+6~x7P19WHq%_XRq{}7eDGI(M4uwJk-VS?j%yqtrI;I&mNr>Z05`~sea=8 zd7Ttvs>pC*eT}-&;_NX0#HE>m258xZSL72_!|QZ+|JsMMtVjtt*a}U_xrr`k$7PAS z^x_w)NWn?xJVMmE?5nUXJ{ z`pZ_8HO9@LmoVo_W_r-%n+I5aUzV>jOn*m2|M>fh=P6X}L8aHF{Jc1JF}BF(^U|>+ z{TEffmM@u)azp4N7N?Ksm2MYpMvpD6h!O|qg8iW&ZyAx9(Y$p{e4 zJH69dqYl`zXw<@2t8*;v_VVdQjgxHGZOzq?IolCU?Ap)^T$KD)ZA$lO5G!e9(sf7PMW z`+8)J;kMM&dUaHGEN|w(Y_2I2s>@T~d}i06oi6;aeXr69jeWuvVyrV_h5GBT)lKg{ z-bC8m#*fvLlVt;n;w3{*no`P(@1HnoFyYpTg^(=@0wd4m#FDob1WK~UdlJL>XR(;x zNL-LT{wgsa`+*_*uqU)WN+Bo+46NbI@w(d?{90jVci44`p4@TUO&hyu=R=X)pOaVK z%9Xk7EYb_Mp*s=G(GWJ%wAQjnV>h=ZldD;_xBJ)Xr+zvkTlU#zMEsKA@ZW-e#t_1` zgR956B69*tH*40@lixYVlUqa8PZK&4`Yj#rD|wH};qj_mj2GX$4<~?s--Eu(h$!G` zYk!lu$QR>>WDtL-(c7J%-b_LU1Z8!H_Bp)zsmrEbzb~DP|JbajALe$qL;U0s3;Y@} zQEyr-=sdj~_Y5V>l{>v16m;U6l-vfDqGE?74|L(X*6}v84 zLuZ_b^HMhR14%JtFR8?3!~^Y9B*dnQFWVLb3Rac67H!M>g;Q`)@g%i0>UMI^>XS`- znQzv&WwIsM?N}-0ol|Wq|CD)@^4ZLbemPgP(oKiq-uZZTJ_RMMz*n>vW?}nfBXn?X ljS8^6TAQb literal 0 HcmV?d00001 diff --git a/deal.II/examples/step-30/step-30.cc b/deal.II/examples/step-30/step-30.cc new file mode 100644 index 0000000000..0f4137e2da --- /dev/null +++ b/deal.II/examples/step-30/step-30.cc @@ -0,0 +1,1196 @@ +/* $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + // And this again is C++: +#include +#include + + // 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 +class RHS: public Function +{ + public: + virtual void value_list (const std::vector > &points, + std::vector &values, + const unsigned int component=0) const; +}; + + +template +class BoundaryValues: public Function +{ + public: + virtual void value_list (const std::vector > &points, + std::vector &values, + const unsigned int component=0) const; +}; + + +template +class Beta +{ + public: + Beta () {} + void value_list (const std::vector > &points, + std::vector > &values) const; +}; + + +template +void RHS::value_list(const std::vector > &points, + std::vector &values, + const unsigned int) const +{ + Assert(values.size()==points.size(), + ExcDimensionMismatch(values.size(),points.size())); + + for (unsigned int i=0; i +void Beta::value_list(const std::vector > &points, + std::vector > &values) const +{ + Assert(values.size()==points.size(), + ExcDimensionMismatch(values.size(),points.size())); + + for (unsigned int i=0; i 0) + { + values[i](0) = -points[i](1); + values[i](1) = points[i](0); + } + else + { + values[i] = Point(); + values[i](0) = -points[i](1); + } + } +} + + +template +void BoundaryValues::value_list(const std::vector > &points, + std::vector &values, + const unsigned int) const +{ + Assert(values.size()==points.size(), + ExcDimensionMismatch(values.size(),points.size())); + + for (unsigned int i=0; i +class DGTransportEquation +{ + public: + DGTransportEquation(); + + void assemble_cell_term(const FEValues& fe_v, + FullMatrix &ui_vi_matrix, + Vector &cell_vector) const; + + void assemble_boundary_term(const FEFaceValues& fe_v, + FullMatrix &ui_vi_matrix, + Vector &cell_vector) const; + + void assemble_face_term2(const FEFaceValuesBase& fe_v, + const FEFaceValuesBase& fe_v_neighbor, + FullMatrix &ui_vi_matrix, + FullMatrix &ue_vi_matrix, + FullMatrix &ui_ve_matrix, + FullMatrix &ue_ve_matrix) const; + private: + const Beta beta_function; + const RHS rhs_function; + const BoundaryValues 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 +DGTransportEquation::DGTransportEquation () + : + beta_function (), + rhs_function (), + boundary_function () +{} + + +template +void DGTransportEquation::assemble_cell_term( + const FEValues &fe_v, + FullMatrix &ui_vi_matrix, + Vector &cell_vector) const +{ + const std::vector &JxW = fe_v.get_JxW_values (); + + std::vector > beta (fe_v.n_quadrature_points); + std::vector 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 +void DGTransportEquation::assemble_boundary_term( + const FEFaceValues& fe_v, + FullMatrix &ui_vi_matrix, + Vector &cell_vector) const +{ + const std::vector &JxW = fe_v.get_JxW_values (); + const std::vector > &normals = fe_v.get_normal_vectors (); + + std::vector > beta (fe_v.n_quadrature_points); + std::vector 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; point0) + for (unsigned int i=0; i +void DGTransportEquation::assemble_face_term2( + const FEFaceValuesBase& fe_v, + const FEFaceValuesBase& fe_v_neighbor, + FullMatrix &ui_vi_matrix, + FullMatrix &ue_vi_matrix, + FullMatrix &ui_ve_matrix, + FullMatrix &ue_ve_matrix) const +{ + const std::vector &JxW = fe_v.get_JxW_values (); + const std::vector > &normals = fe_v.get_normal_vectors (); + + std::vector > beta (fe_v.n_quadrature_points); + + beta_function.value_list (fe_v.get_quadrature_points(), beta); + + for (unsigned int point=0; point0) + { + for (unsigned int i=0; i +class DGMethod +{ + public: + DGMethod (const bool anisotropic); + ~DGMethod (); + + void run (); + + private: + void setup_system (); + void assemble_system1 (); + void assemble_system2 (); + void solve (Vector &solution); + void refine_grid (); + void set_anisotropic_flags (); + void output_results (const unsigned int cycle) const; + + Triangulation triangulation; + const MappingQ1 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 fe; + DoFHandler dof_handler; + + SparsityPattern sparsity_pattern; + SparseMatrix 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 quadrature; + const QGauss face_quadrature; + + Vector solution2; + Vector right_hand_side; + + const DGTransportEquation dg; +}; + + +template +DGMethod::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 + // degree+1 + // gauss points, + // which enables us + // to integrate + // exactly + // polynomials of + // degree + // 2*degree+1, + // enough for all the + // integrals we will + // perform in this + // program. + quadrature (degree+1), + face_quadrature (degree+1), + dg () +{} + + +template +DGMethod::~DGMethod () +{ + dof_handler.clear (); +} + + +template +void DGMethod::setup_system () +{ + dof_handler.distribute_dofs (fe); + sparsity_pattern.reinit (dof_handler.n_dofs(), + dof_handler.n_dofs(), + (GeometryInfo::faces_per_cell + *GeometryInfo::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 + // assemble_system2 function that + // implements the DG discretization in its + // second version. This function is very + // similar to the assemble_system2 + // 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 +void DGMethod::assemble_system2 () +{ + const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell; + std::vector dofs (dofs_per_cell); + std::vector 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 fe_v ( + mapping, fe, quadrature, update_flags); + FEFaceValues fe_v_face ( + mapping, fe, face_quadrature, face_update_flags); + FESubfaceValues fe_v_subface ( + mapping, fe, face_quadrature, face_update_flags); + FEFaceValues fe_v_face_neighbor ( + mapping, fe, face_quadrature, neighbor_face_update_flags); + + + FullMatrix ui_vi_matrix (dofs_per_cell, dofs_per_cell); + FullMatrix ue_vi_matrix (dofs_per_cell, dofs_per_cell); + + FullMatrix ui_ve_matrix (dofs_per_cell, dofs_per_cell); + FullMatrix ue_ve_matrix (dofs_per_cell, dofs_per_cell); + + Vector cell_vector (dofs_per_cell); + + typename DoFHandler::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::faces_per_cell; ++face_no) + { + typename DoFHandler::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::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_nonumber_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::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; ineighbor_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 +void DGMethod::solve (Vector &solution) +{ + SolverControl solver_control (1000, 1e-12, false, false); + SolverRichardson<> solver (solver_control); + + PreconditionBlockSSOR > 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 +void DGMethod::refine_grid () +{ + Vector 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::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 +void DGMethod::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 fe_v_face (mapping, fe, face_quadrature, face_update_flags); + FESubfaceValues fe_v_subface (mapping, fe, face_quadrature, face_update_flags); + FEFaceValues fe_v_face_neighbor (mapping, fe, face_quadrature, update_values); + + // Now we need to loop over all active cells. + typename DoFHandler::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 jump; + Point area; + + for (unsigned int face_no=0; face_no::faces_per_cell; ++face_no) + { + typename DoFHandler::face_iterator face = cell->face(face_no); + + if (!face->at_boundary()) + { + Assert (cell->neighbor(face_no).state() == IteratorState::valid, ExcInternalError()); + typename DoFHandler::cell_iterator neighbor = cell->neighbor(face_no); + + std::vector u (fe_v_face.n_quadrature_points); + std::vector 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_nonumber_of_children(); ++subface_no) + { + // get an iterator + // pointing to the cell + // behind the present + // subface... + typename DoFHandler::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 &JxW = fe_v_subface.get_JxW_values (); + // Now we loop over all + // quadrature points + for (unsigned int x=0; xdim + // 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 &JxW = fe_v_face.get_JxW_values (); + + for (unsigned int x=0; x neighbor_face_subface + = cell->neighbor_of_coarser_neighbor(face_no); + Assert (neighbor_face_subface.first::faces_per_cell, ExcInternalError()); + Assert (neighbor_face_subface.secondface(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 &JxW = fe_v_face.get_JxW_values (); + + for (unsigned int x=0; xdim + // 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 anisotropic_threshold_ratio*(sum_of_average_jumps-average_jumps[i])) + cell->set_refine_flag(RefinementCase::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 +void DGMethod::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 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 +void DGMethod::run () +{ + for (unsigned int cycle=0; cycle<6; ++cycle) + { + std::cout << "Cycle " << cycle << ':' << std::endl; + + if (cycle == 0) + { + // Create the rectangular domain. + Point p1,p2; + p1(0)=0; + p1(0)=-1; + for (unsigned int i=0; i 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 + // const unsigned int dim = 3;. + 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 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 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; +} + + diff --git a/deal.II/examples/step-31/step-31.cc b/deal.II/examples/step-31/step-31.cc index 3e7d66353e..f0d8925f55 100644 --- a/deal.II/examples/step-31/step-31.cc +++ b/deal.II/examples/step-31/step-31.cc @@ -944,7 +944,7 @@ void BoussinesqFlowProblem::assemble_rhs_T () // refined. loop over // all sub faces for (unsigned int subface_no=0; - subface_no::subfaces_per_face; + subface_no::max_children_per_face; ++subface_no) { fe_subface_values.reinit (cell, face_no, subface_no); diff --git a/deal.II/examples/step-9/step-9.cc b/deal.II/examples/step-9/step-9.cc index f9692f2b8b..602d2ba20e 100644 --- a/deal.II/examples/step-9/step-9.cc +++ b/deal.II/examples/step-9/step-9.cc @@ -1645,7 +1645,7 @@ GradientEstimation::estimate_interval (const DoFHandler &dof_handler, // neighbors is computed here. std::vector::active_cell_iterator> active_neighbors; active_neighbors.reserve (GeometryInfo::faces_per_cell * - GeometryInfo::subfaces_per_face); + GeometryInfo::max_children_per_face); // Well then, after all these // preliminaries, lets start the diff --git a/deal.II/todo b/deal.II/todo new file mode 100644 index 0000000000..ead9945545 --- /dev/null +++ b/deal.II/todo @@ -0,0 +1,144 @@ +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::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 + CLASS :: MEMBER. 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 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 ... instead of + .... More importantly, however, if you use a template + argument or <2> inside such a block, it needs to be written as + @<2@> -- 2.39.5