From bc51fb4e7acd09e7c3426726e719bc1913745313 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Mon, 21 Jul 2014 18:33:10 -0500 Subject: [PATCH] Update documentation of this file. - Rename a documentation section to be more descriptive. - Reshuffle some more functions and group them into appropriate categories. Not all functions are in categories yet, though, see http://www.dealii.org/developer/doxygen/deal.II/namespaceDoFTools.html --- include/deal.II/dofs/dof_tools.h | 388 +++++++++++++++++-------------- 1 file changed, 207 insertions(+), 181 deletions(-) diff --git a/include/deal.II/dofs/dof_tools.h b/include/deal.II/dofs/dof_tools.h index 72a3791bfe..5daf49d9de 100644 --- a/include/deal.II/dofs/dof_tools.h +++ b/include/deal.II/dofs/dof_tools.h @@ -219,7 +219,7 @@ namespace DoFTools }; /** - * @name Auxiliary functions + * @name Functions to support code that generically uses both DoFHandler and hp::DoFHandler * @{ */ /** @@ -346,7 +346,7 @@ namespace DoFTools */ /** - * @name Sparsity Pattern Generation + * @name Sparsity pattern generation * @{ */ @@ -649,9 +649,11 @@ namespace DoFTools const Table<2,Coupling> &int_mask, const Table<2,Coupling> &flux_mask); - //@} /** - * @name Hanging Nodes + * @} + */ + /** + * @name Hanging nodes and other constraints * @{ */ @@ -700,11 +702,142 @@ namespace DoFTools void make_hanging_node_constraints (const DH &dof_handler, ConstraintMatrix &constraints); + + /** + * This function can be used when different variables shall be + * discretized on different grids, where one grid is coarser than + * the other. This idea might seem nonsensical at first, but has + * reasonable applications in inverse (parameter estimation) + * problems, where there might not be enough information to recover + * the parameter on the same grid as the state variable; + * furthermore, the smoothness properties of state variable and + * parameter might not be too much related, so using different grids + * might be an alternative to using stronger regularization of the + * problem. + * + * The basic idea of this function is explained in the + * following. Let us, for convenience, denote by ``parameter grid'' + * the coarser of the two grids, and by ``state grid'' the finer of + * the two. We furthermore assume that the finer grid can be + * obtained by refinement of the coarser one, i.e. the fine grid is + * at least as much refined as the coarse grid at each point of the + * domain. Then, each shape function on the coarse grid can be + * represented as a linear combination of shape functions on the + * fine grid (assuming identical ansatz spaces). Thus, if we + * discretize as usual, using shape functions on the fine grid, we + * can consider the restriction that the parameter variable shall in + * fact be discretized by shape functions on the coarse grid as a + * constraint. These constraints are linear and happen to have the + * form managed by the ``ConstraintMatrix'' class. + * + * The construction of these constraints is done as follows: for + * each of the degrees of freedom (i.e. shape functions) on the + * coarse grid, we compute its representation on the fine grid, + * i.e. how the linear combination of shape functions on the fine + * grid looks like that resembles the shape function on the coarse + * grid. From this information, we can then compute the constraints + * which have to hold if a solution of a linear equation on the fine + * grid shall be representable on the coarse grid. The exact + * algorithm how these constraints can be computed is rather + * complicated and is best understood by reading the source code, + * which contains many comments. + * + * Before explaining the use of this function, we would like to + * state that the total number of degrees of freedom used for the + * discretization is not reduced by the use of this function, + * i.e. even though we discretize one variable on a coarser grid, + * the total number of degrees of freedom is that of the fine + * grid. This seems to be counter-productive, since it does not give + * us a benefit from using a coarser grid. The reason why it may be + * useful to choose this approach nonetheless is three-fold: first, + * as stated above, there might not be enough information to recover + * a parameter on a fine grid, i.e. we chose to discretize it on the + * coarse grid not to save DoFs, but for other reasons. Second, the + * ``ConstraintMatrix'' includes the constraints into the linear + * system of equations, by which constrained nodes become dummy + * nodes; we may therefore exclude them from the linear algebra, for + * example by sorting them to the back of the DoF numbers and simply + * calling the solver for the upper left block of the matrix which + * works on the non-constrained nodes only, thus actually realizing + * the savings in numerical effort from the reduced number of actual + * degrees of freedom. The third reason is that for some or other + * reason we have chosen to use two different grids, it may be + * actually quite difficult to write a function that assembles the + * system matrix for finite element spaces on different grids; using + * the approach of constraints as with this function allows to use + * standard techniques when discretizing on only one grid (the finer + * one) without having to take care of the fact that one or several + * of the variable actually belong to different grids. + * + * The use of this function is as follows: it accepts as parameters + * two DoF Handlers, the first of which refers to the coarse grid + * and the second of which is the fine grid. On both, a finite + * element is represented by the DoF handler objects, which will + * usually have several components, which may belong to different + * finite elements. The second and fourth parameter of this function + * therefore state which variable on the coarse grid shall be used + * to restrict the stated component on the fine grid. Of course, the + * finite elements used for the respective components on the two + * grids need to be the same. An example may clarify this: consider + * the parameter estimation mentioned briefly above; there, on the + * fine grid the whole discretization is done, thus the variables + * are ``u'', ``q'', and the Lagrange multiplier ``lambda'', which + * are discretized using continuous linear, piecewise constant + * discontinuous, and continuous linear elements, respectively. Only + * the parameter ``q'' shall be represented on the coarse grid, thus + * the DoFHandler object on the coarse grid represents only one + * variable, discretized using piecewise constant discontinuous + * elements. Then, the parameter denoting the component on the + * coarse grid would be zero (the only possible choice, since the + * variable on the coarse grid is scalar), and one on the fine grid + * (corresponding to the variable ``q''; zero would be ``u'', two + * would be ``lambda''). Furthermore, an object of type IntergridMap + * is needed; this could in principle be generated by the function + * itself from the two DoFHandler objects, but since it is probably + * available anyway in programs that use this function, we shall use + * it instead of re-generating it. Finally, the computed constraints + * are entered into a variable of type ConstraintMatrix; the + * constraints are added, i.e. previous contents which may have, for + * example, be obtained from hanging nodes, are not deleted, so that + * you only need one object of this type. + */ + template + void + compute_intergrid_constraints (const DoFHandler &coarse_grid, + const unsigned int coarse_component, + const DoFHandler &fine_grid, + const unsigned int fine_component, + const InterGridMap > &coarse_to_fine_grid_map, + ConstraintMatrix &constraints); + + + /** + * This function generates a matrix such that when a vector of data + * with as many elements as there are degrees of freedom of this + * component on the coarse grid is multiplied to this matrix, we + * obtain a vector with as many elements as there are global + * degrees of freedom on the fine grid. All the elements of the + * other components of the finite element fields on the fine grid + * are not touched. + * + * The output of this function is a compressed format that can be + * given to the @p reinit functions of the SparsityPattern ad + * SparseMatrix classes. + */ + template + void + compute_intergrid_transfer_representation (const DoFHandler &coarse_grid, + const unsigned int coarse_component, + const DoFHandler &fine_grid, + const unsigned int fine_component, + const InterGridMap > &coarse_to_fine_grid_map, + std::vector > &transfer_representation); + //@} /** - * @name Periodic Boundary Conditions + * @name Periodic boundary conditions * @{ */ @@ -1074,6 +1207,14 @@ namespace DoFTools Vector &dof_data, const unsigned int component = 0); + /** + * @} + */ + /** + * @name Identifying subsets of degrees of freedom with particular properties + * @{ + */ + /** * Extract the indices of the degrees of freedom belonging to * certain vector components of a vector-valued finite element. The @@ -1288,7 +1429,49 @@ namespace DoFTools const std::set &boundary_indicators = std::set()); /** - * @name Hanging Nodes + * Extract a vector that represents the constant modes of the + * DoFHandler for the components chosen by component_mask + * (see @ref GlossComponentMask). The constant modes on a + * discretization are the null space of a Laplace operator on the + * selected components with Neumann boundary conditions applied. The + * null space is a necessary ingredient for obtaining a good AMG + * preconditioner when using the class + * TrilinosWrappers::PreconditionAMG. Since the ML AMG package only + * works on algebraic properties of the respective matrix, it has no + * chance to detect whether the matrix comes from a scalar or a + * vector valued problem. However, a near null space supplies + * exactly the needed information about the components placement of vector + * components within the matrix. The null space (or rather, the constant + * modes) is provided by the finite element underlying the given DoFHandler + * and for most elements, the null space will consist of as many vectors as + * there are true arguments in component_mask (see @ref + * GlossComponentMask), each of which will be one in one vector component + * and zero in all others. However, the representation of the constant + * function for e.g. FE_DGP is different (the first component on each + * element one, all other components zero), and some scalar elements may + * even have two constant modes (FE_Q_DG0). Therefore, we store this object + * in a vector of vectors, where the outer vector contains the collection of + * the actual constant modes on the DoFHandler. Each inner vector has as + * many components as there are (locally owned) degrees of freedom in the + * selected components. Note that any matrix associated with this null space + * must have been constructed using the same component_mask + * argument, since the numbering of DoFs is done relative to the selected + * dofs, not to all dofs. + * + * The main reason for this program is the use of the null space + * with the AMG preconditioner. + */ + template + void + extract_constant_modes (const DH &dof_handler, + const ComponentMask &component_mask, + std::vector > &constant_modes); + + /** + * @} + */ + /** + * @name Hanging nodes * @{ */ @@ -1495,7 +1678,7 @@ namespace DoFTools const types::subdomain_id subdomain); // @} /** - * @name Dof indices for patches + * @name DoF indices on patches of cells * * Create structures containing a large set of degrees of freedom * for small patches of cells. The resulting objects can be used in @@ -1643,61 +1826,13 @@ namespace DoFTools const unsigned int level, const bool interior_dofs_only = false); - //@} /** - * Extract a vector that represents the constant modes of the - * DoFHandler for the components chosen by component_mask - * (see @ref GlossComponentMask). The constant modes on a - * discretization are the null space of a Laplace operator on the - * selected components with Neumann boundary conditions applied. The - * null space is a necessary ingredient for obtaining a good AMG - * preconditioner when using the class - * TrilinosWrappers::PreconditionAMG. Since the ML AMG package only - * works on algebraic properties of the respective matrix, it has no - * chance to detect whether the matrix comes from a scalar or a - * vector valued problem. However, a near null space supplies - * exactly the needed information about the components placement of vector - * components within the matrix. The null space (or rather, the constant - * modes) is provided by the finite element underlying the given DoFHandler - * and for most elements, the null space will consist of as many vectors as - * there are true arguments in component_mask (see @ref - * GlossComponentMask), each of which will be one in one vector component - * and zero in all others. However, the representation of the constant - * function for e.g. FE_DGP is different (the first component on each - * element one, all other components zero), and some scalar elements may - * even have two constant modes (FE_Q_DG0). Therefore, we store this object - * in a vector of vectors, where the outer vector contains the collection of - * the actual constant modes on the DoFHandler. Each inner vector has as - * many components as there are (locally owned) degrees of freedom in the - * selected components. Note that any matrix associated with this null space - * must have been constructed using the same component_mask - * argument, since the numbering of DoFs is done relative to the selected - * dofs, not to all dofs. - * - * The main reason for this program is the use of the null space - * with the AMG preconditioner. + * @} */ - template - void - extract_constant_modes (const DH &dof_handler, - const ComponentMask &component_mask, - std::vector > &constant_modes); - /** - * For each active cell of a DoFHandler or hp::DoFHandler, extract - * the active finite element index and fill the vector given as - * second argument. This vector is assumed to have as many entries - * as there are active cells. - * - * For non-hp DoFHandler objects given as first argument, the - * returned vector will consist of only zeros, indicating that all - * cells use the same finite element. For a hp::DoFHandler, the - * values may be different, though. + * @name Counting degrees of freedom and related functions + * @{ */ - template - void - get_active_fe_indices (const DH &dof_handler, - std::vector &active_fe_indices); /** * Count how many degrees of freedom out of the total number belong @@ -1779,136 +1914,27 @@ namespace DoFTools std::vector &dofs_per_component, std::vector target_component) DEAL_II_DEPRECATED; + /** - * This function can be used when different variables shall be - * discretized on different grids, where one grid is coarser than - * the other. This idea might seem nonsensical at first, but has - * reasonable applications in inverse (parameter estimation) - * problems, where there might not be enough information to recover - * the parameter on the same grid as the state variable; - * furthermore, the smoothness properties of state variable and - * parameter might not be too much related, so using different grids - * might be an alternative to using stronger regularization of the - * problem. - * - * The basic idea of this function is explained in the - * following. Let us, for convenience, denote by ``parameter grid'' - * the coarser of the two grids, and by ``state grid'' the finer of - * the two. We furthermore assume that the finer grid can be - * obtained by refinement of the coarser one, i.e. the fine grid is - * at least as much refined as the coarse grid at each point of the - * domain. Then, each shape function on the coarse grid can be - * represented as a linear combination of shape functions on the - * fine grid (assuming identical ansatz spaces). Thus, if we - * discretize as usual, using shape functions on the fine grid, we - * can consider the restriction that the parameter variable shall in - * fact be discretized by shape functions on the coarse grid as a - * constraint. These constraints are linear and happen to have the - * form managed by the ``ConstraintMatrix'' class. - * - * The construction of these constraints is done as follows: for - * each of the degrees of freedom (i.e. shape functions) on the - * coarse grid, we compute its representation on the fine grid, - * i.e. how the linear combination of shape functions on the fine - * grid looks like that resembles the shape function on the coarse - * grid. From this information, we can then compute the constraints - * which have to hold if a solution of a linear equation on the fine - * grid shall be representable on the coarse grid. The exact - * algorithm how these constraints can be computed is rather - * complicated and is best understood by reading the source code, - * which contains many comments. - * - * Before explaining the use of this function, we would like to - * state that the total number of degrees of freedom used for the - * discretization is not reduced by the use of this function, - * i.e. even though we discretize one variable on a coarser grid, - * the total number of degrees of freedom is that of the fine - * grid. This seems to be counter-productive, since it does not give - * us a benefit from using a coarser grid. The reason why it may be - * useful to choose this approach nonetheless is three-fold: first, - * as stated above, there might not be enough information to recover - * a parameter on a fine grid, i.e. we chose to discretize it on the - * coarse grid not to save DoFs, but for other reasons. Second, the - * ``ConstraintMatrix'' includes the constraints into the linear - * system of equations, by which constrained nodes become dummy - * nodes; we may therefore exclude them from the linear algebra, for - * example by sorting them to the back of the DoF numbers and simply - * calling the solver for the upper left block of the matrix which - * works on the non-constrained nodes only, thus actually realizing - * the savings in numerical effort from the reduced number of actual - * degrees of freedom. The third reason is that for some or other - * reason we have chosen to use two different grids, it may be - * actually quite difficult to write a function that assembles the - * system matrix for finite element spaces on different grids; using - * the approach of constraints as with this function allows to use - * standard techniques when discretizing on only one grid (the finer - * one) without having to take care of the fact that one or several - * of the variable actually belong to different grids. + * For each active cell of a DoFHandler or hp::DoFHandler, extract + * the active finite element index and fill the vector given as + * second argument. This vector is assumed to have as many entries + * as there are active cells. * - * The use of this function is as follows: it accepts as parameters - * two DoF Handlers, the first of which refers to the coarse grid - * and the second of which is the fine grid. On both, a finite - * element is represented by the DoF handler objects, which will - * usually have several components, which may belong to different - * finite elements. The second and fourth parameter of this function - * therefore state which variable on the coarse grid shall be used - * to restrict the stated component on the fine grid. Of course, the - * finite elements used for the respective components on the two - * grids need to be the same. An example may clarify this: consider - * the parameter estimation mentioned briefly above; there, on the - * fine grid the whole discretization is done, thus the variables - * are ``u'', ``q'', and the Lagrange multiplier ``lambda'', which - * are discretized using continuous linear, piecewise constant - * discontinuous, and continuous linear elements, respectively. Only - * the parameter ``q'' shall be represented on the coarse grid, thus - * the DoFHandler object on the coarse grid represents only one - * variable, discretized using piecewise constant discontinuous - * elements. Then, the parameter denoting the component on the - * coarse grid would be zero (the only possible choice, since the - * variable on the coarse grid is scalar), and one on the fine grid - * (corresponding to the variable ``q''; zero would be ``u'', two - * would be ``lambda''). Furthermore, an object of type IntergridMap - * is needed; this could in principle be generated by the function - * itself from the two DoFHandler objects, but since it is probably - * available anyway in programs that use this function, we shall use - * it instead of re-generating it. Finally, the computed constraints - * are entered into a variable of type ConstraintMatrix; the - * constraints are added, i.e. previous contents which may have, for - * example, be obtained from hanging nodes, are not deleted, so that - * you only need one object of this type. + * For non-hp DoFHandler objects given as first argument, the + * returned vector will consist of only zeros, indicating that all + * cells use the same finite element. For a hp::DoFHandler, the + * values may be different, though. */ - template + template void - compute_intergrid_constraints (const DoFHandler &coarse_grid, - const unsigned int coarse_component, - const DoFHandler &fine_grid, - const unsigned int fine_component, - const InterGridMap > &coarse_to_fine_grid_map, - ConstraintMatrix &constraints); - + get_active_fe_indices (const DH &dof_handler, + std::vector &active_fe_indices); /** - * This function generates a matrix such that when a vector of data - * with as many elements as there are degrees of freedom of this - * component on the coarse grid is multiplied to this matrix, we - * obtain a vector with as many elements as there are global - * degrees of freedom on the fine grid. All the elements of the - * other components of the finite element fields on the fine grid - * are not touched. - * - * The output of this function is a compressed format that can be - * given to the @p reinit functions of the SparsityPattern ad - * SparseMatrix classes. + * @} */ - template - void - compute_intergrid_transfer_representation (const DoFHandler &coarse_grid, - const unsigned int coarse_component, - const DoFHandler &fine_grid, - const unsigned int fine_component, - const InterGridMap > &coarse_to_fine_grid_map, - std::vector > &transfer_representation); - + /** * Create a mapping from degree of freedom indices to the index of * that degree of freedom on the boundary. After this operation, -- 2.39.5