1432 *
[&](
const CellIterator &cell,
1433 *
MatrixScratchData<dim> &scratch_data,
1434 *
MatrixCopyData<dim> &
copy) {
1435 *
copy.reinit(cell);
1436 *
scratch_data.fe_values.reinit(cell);
1437 *
MatrixIntegrator::cell<dim>(scratch_data.fe_values,
copy.cell_matrix);
1440 *
[&](
const MatrixCopyData<dim> &
copy) {
1442 *
for (
const auto &face :
copy.face_data)
1444 *
matrix.add(face.dof_indices_1, face.dof_indices_1, face.matrix_11);
1445 *
matrix.add(face.dof_indices_1, face.dof_indices_2, face.matrix_12);
1446 *
matrix.add(face.dof_indices_2, face.dof_indices_1, face.matrix_21);
1447 *
matrix.add(face.dof_indices_2, face.dof_indices_2, face.matrix_22);
1457 *
[&](
const CellIterator &cell,
1458 *
const unsigned int face_no,
1459 *
MatrixScratchData<dim> &scratch_data,
1460 *
MatrixCopyData<dim> &
copy) {
1461 *
scratch_data.boundary_fe_values.reinit(cell, face_no);
1462 *
MatrixIntegrator::boundary<dim>(cell,
1464 *
scratch_data.boundary_fe_values,
1465 *
copy.cell_matrix);
1468 *
[&](
const CellIterator &cell,
1469 *
const unsigned int face_no,
1470 *
const unsigned int subface_no,
1471 *
const CellIterator &neighbor,
1472 *
const unsigned int neighbor_face_no,
1473 *
const unsigned int neighbor_subface_no,
1474 *
MatrixScratchData<dim> &scratch_data,
1475 *
MatrixCopyData<dim> &
copy) {
1476 *
FaceCopyData &face_copy =
copy.emplace_face_data(cell, neighbor);
1479 *
scratch_data.face_fe_values.reinit(cell, face_no);
1482 *
scratch_data.neighbor_face_values.reinit(neighbor,
1483 *
neighbor_face_no);
1484 *
MatrixIntegrator::face<dim>(cell,
1486 *
scratch_data.face_fe_values,
1489 *
scratch_data.neighbor_face_values,
1490 *
face_copy.matrix_11,
1491 *
face_copy.matrix_12,
1492 *
face_copy.matrix_21,
1493 *
face_copy.matrix_22);
1497 *
scratch_data.neighbor_subface_values.reinit(
1498 *
neighbor, neighbor_face_no, neighbor_subface_no);
1499 *
MatrixIntegrator::face<dim>(
1502 *
scratch_data.face_fe_values,
1505 *
scratch_data.neighbor_subface_values,
1506 *
face_copy.matrix_11,
1507 *
face_copy.matrix_12,
1508 *
face_copy.matrix_21,
1509 *
face_copy.matrix_22);
1514 *
scratch_data.subface_values.reinit(cell, face_no, subface_no);
1517 *
scratch_data.neighbor_face_values.reinit(neighbor,
1518 *
neighbor_face_no);
1519 *
MatrixIntegrator::face<dim>(cell,
1521 *
scratch_data.subface_values,
1524 *
scratch_data.neighbor_face_values,
1525 *
face_copy.matrix_11,
1526 *
face_copy.matrix_12,
1527 *
face_copy.matrix_21,
1528 *
face_copy.matrix_22);
1532 *
scratch_data.neighbor_subface_values.reinit(
1533 *
neighbor, neighbor_face_no, neighbor_subface_no);
1534 *
MatrixIntegrator::face<dim>(
1537 *
scratch_data.subface_values,
1540 *
scratch_data.neighbor_subface_values,
1541 *
face_copy.matrix_11,
1542 *
face_copy.matrix_12,
1543 *
face_copy.matrix_21,
1544 *
face_copy.matrix_22);
1553 * Now, we
do the same
for the
level matrices. Not too surprisingly,
this
1554 * function looks like a twin of the previous
one. The mesh
loop again
1555 * traverses cells, boundary faces, and interior faces, and the worker
1557 * The scratch
object provides the
FEValues-like
data needed
for those local
1558 * computations, and the
copy object collects the local cell
matrix together
1559 * with the face blocks.
1563 * The
main difference lies in the copier. Rather than assembling into a
1564 * single global
matrix, it dispatches the local
data into the appropriate
1565 *
level matrix and, on refinement edges, into the up- and down-transfer
1566 * matrices that are required by the multigrid algorithm.
1569 *
template <
int dim>
1570 *
void InteriorPenaltyProblem<dim>::assemble_mg_matrix()
1574 *
const MatrixScratchData<dim> scratch(mapping,
1582 *
const MatrixCopyData<dim> copy_data(fe.n_dofs_per_cell());
1585 *
dof_handler.begin_mg(),
1586 *
dof_handler.end_mg(),
1588 *
[&](
const CellIterator &cell,
1589 *
MatrixScratchData<dim> &scratch_data,
1590 *
MatrixCopyData<dim> ©) {
1591 * copy.reinit(cell, true);
1592 * scratch_data.fe_values.reinit(cell);
1593 * MatrixIntegrator::cell<dim>(scratch_data.fe_values, copy.cell_matrix);
1596 *
[&](
const MatrixCopyData<dim> ©) {
1597 * mg_matrix[copy.level].add(copy.local_dof_indices, copy.cell_matrix);
1599 * for (const auto &face : copy.face_data)
1600 * if (face.level_1 == face.level_2)
1602 * mg_matrix[face.level_1].add(face.dof_indices_1,
1603 * face.dof_indices_1,
1605 * mg_matrix[face.level_1].add(face.dof_indices_1,
1606 * face.dof_indices_2,
1608 * mg_matrix[face.level_1].add(face.dof_indices_2,
1609 * face.dof_indices_1,
1611 * mg_matrix[face.level_1].add(face.dof_indices_2,
1612 * face.dof_indices_2,
1617 * Assert(face.level_1 > face.level_2, ExcInternalError());
1619 * mg_matrix[face.level_1].add(face.dof_indices_1,
1620 * face.dof_indices_1,
1623 * for (unsigned int j = 0; j < face.dof_indices_2.size(); ++j)
1624 * for (unsigned int k = 0; k < face.dof_indices_1.size(); ++k)
1626 * mg_matrix_dg_up[face.level_1].add(face.dof_indices_2[j],
1627 * face.dof_indices_1[k],
1628 * face.matrix_12(k, j));
1629 * mg_matrix_dg_down[face.level_1].add(face.dof_indices_2[j],
1630 * face.dof_indices_1[k],
1631 * face.matrix_21(j, k));
1642 *
[&](
const CellIterator &cell,
1643 *
const unsigned int face_no,
1644 *
MatrixScratchData<dim> &scratch_data,
1645 *
MatrixCopyData<dim> &
copy) {
1646 *
scratch_data.boundary_fe_values.reinit(cell, face_no);
1647 *
MatrixIntegrator::boundary<dim>(cell,
1649 *
scratch_data.boundary_fe_values,
1650 *
copy.cell_matrix);
1653 *
[&](
const CellIterator &cell,
1654 *
const unsigned int face_no,
1655 *
const unsigned int subface_no,
1656 *
const CellIterator &neighbor,
1657 *
const unsigned int neighbor_face_no,
1658 *
const unsigned int neighbor_subface_no,
1659 *
MatrixScratchData<dim> &scratch_data,
1660 *
MatrixCopyData<dim> &
copy) {
1661 *
FaceCopyData &face_copy =
copy.emplace_face_data(cell, neighbor,
true);
1664 *
scratch_data.face_fe_values.reinit(cell, face_no);
1667 *
scratch_data.neighbor_face_values.reinit(neighbor,
1668 *
neighbor_face_no);
1669 *
MatrixIntegrator::face<dim>(cell,
1671 *
scratch_data.face_fe_values,
1674 *
scratch_data.neighbor_face_values,
1675 *
face_copy.matrix_11,
1676 *
face_copy.matrix_12,
1677 *
face_copy.matrix_21,
1678 *
face_copy.matrix_22);
1682 *
scratch_data.neighbor_subface_values.reinit(
1683 *
neighbor, neighbor_face_no, neighbor_subface_no);
1684 *
MatrixIntegrator::face<dim>(
1687 *
scratch_data.face_fe_values,
1690 *
scratch_data.neighbor_subface_values,
1691 *
face_copy.matrix_11,
1692 *
face_copy.matrix_12,
1693 *
face_copy.matrix_21,
1694 *
face_copy.matrix_22);
1699 *
scratch_data.subface_values.reinit(cell, face_no, subface_no);
1702 *
scratch_data.neighbor_face_values.reinit(neighbor,
1703 *
neighbor_face_no);
1704 *
MatrixIntegrator::face<dim>(cell,
1706 *
scratch_data.subface_values,
1709 *
scratch_data.neighbor_face_values,
1710 *
face_copy.matrix_11,
1711 *
face_copy.matrix_12,
1712 *
face_copy.matrix_21,
1713 *
face_copy.matrix_22);
1717 *
scratch_data.neighbor_subface_values.reinit(
1718 *
neighbor, neighbor_face_no, neighbor_subface_no);
1719 *
MatrixIntegrator::face<dim>(
1722 *
scratch_data.subface_values,
1725 *
scratch_data.neighbor_subface_values,
1726 *
face_copy.matrix_11,
1727 *
face_copy.matrix_12,
1728 *
face_copy.matrix_21,
1729 *
face_copy.matrix_22);
1738 * Here we have another clone of the assembly function. The difference to
1739 * assembling the system
matrix consists in that we
assemble a vector here.
1743 * The mesh
loop still uses the same worker/copier
split. The cell worker is
1744 * only responsible
for initializing the
copy object for the current cell,
1745 * whereas the actual local work happens on boundary faces: there, the worker
1746 * evaluates the inhomogeneous boundary
values and accumulates the associated
1747 * Nitsche terms into the local right-hand-side vector. The copier then adds
1748 * that local vector to the global right-hand side.
1751 *
template <
int dim>
1752 *
void InteriorPenaltyProblem<dim>::assemble_right_hand_side()
1756 *
const RightHandSideScratchData<dim> scratch(mapping,
1764 *
const RightHandSideCopyData copy_data(fe.n_dofs_per_cell());
1767 *
dof_handler.begin_active(),
1768 *
dof_handler.end(),
1770 *
[&](
const CellIterator &cell,
1771 *
RightHandSideScratchData<dim> &,
1772 *
RightHandSideCopyData ©) { copy.reinit(cell); },
1774 *
[&](
const RightHandSideCopyData ©) {
1775 * right_hand_side.add(copy.local_dof_indices, copy.cell_rhs);
1783 *
[&](
const CellIterator &cell,
1784 *
const unsigned int face_no,
1785 *
RightHandSideScratchData<dim> &scratch_data,
1786 *
RightHandSideCopyData ©) {
1787 * scratch_data.boundary_fe_values.reinit(cell, face_no);
1788 * exact_solution.value_list(
1789 * scratch_data.boundary_fe_values.get_quadrature_points(),
1790 * scratch_data.boundary_values);
1791 * RHSIntegrator::boundary<dim>(cell,
1793 * scratch_data.boundary_fe_values,
1794 * scratch_data.boundary_values,
1798 *
right_hand_side *= -1.;
1804 * Now that we have coded all
functions building the discrete linear system,
1805 * it is about time that we actually solve it.
1808 *
template <
int dim>
1809 *
void InteriorPenaltyProblem<dim>::solve()
1813 * The solver of choice is conjugate
gradient.
1821 * Now we are setting up the components of the multilevel
1822 * preconditioner. First, we need transfer between grid levels. The
object
1823 * we are
using here generates sparse matrices
for these transfers.
1827 *
mg_transfer.
build(dof_handler);
1831 * Then, we need an exact solver
for the
matrix on the coarsest
level.
1835 *
coarse_matrix.
copy_from(mg_matrix[0]);
1841 * While transfer and coarse grid solver are pretty much
generic, more
1842 * flexibility is offered
for the smoother. First, we choose Gauss-Seidel
1843 * as our smoothing method.
1849 *
RELAXATION::AdditionalData smoother_data(1.);
1850 *
mg_smoother.initialize(mg_matrix, smoother_data);
1854 * Do two smoothing steps on each
level.
1857 *
mg_smoother.set_steps(2);
1861 * iteration below, here is a trick to make the multilevel preconditioner
1862 * a
symmetric operator even
for nonsymmetric smoothers.
1865 *
mg_smoother.set_symmetric(
true);
1868 * The smoother
class optionally
implements the variable
V-cycle, which we
1872 *
mg_smoother.set_variable(false);
1876 * Finally, we must wrap our matrices in an object having the required
1880 *
mg::Matrix<Vector<double>> mgmatrix(mg_matrix);
1881 *
mg::Matrix<Vector<double>> mgdown(mg_matrix_dg_down);
1882 *
mg::Matrix<Vector<double>> mgup(mg_matrix_dg_up);
1886 * Now, we are ready to
set up the
V-cycle operator and the multilevel
1891 * mgmatrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
1894 * Let us not forget the edge matrices needed because of the adaptive
1898 *
mg.set_edge_flux_matrices(mgdown, mgup);
1902 * After all preparations, wrap the
Multigrid object into another object,
1903 * which can be used as a regular preconditioner,
1906 *
PreconditionMG<dim, Vector<double>, MGTransferPrebuilt<Vector<double>>>
1907 *
preconditioner(dof_handler, mg, mg_transfer);
1910 * and use it to solve the system.
1913 *
solver.solve(matrix, solution, right_hand_side, preconditioner);
1915 *
std::cout << "Converged in " << control.last_step() << " iterations"
1922 * The next function estimates the error. The big difference to the previous
1923 * mesh loop functions is that we now also read from the discrete solution
1924 * vector. The results of the estimator are stored in a vector with one entry
1929 * As before, MeshWorker::mesh_loop() separates the local work from the
1930 * accumulation into the global output vector. The workers evaluate the
1931 * current solution on cells and faces, compute the cell, boundary, and jump
1932 * contributions to the estimator, and store them in the copy object. The
1933 * copier then distributes these local indicators to the per-cell entries of
1934 * the global estimator vector, splitting face terms evenly between the two
1935 * cells that share the face.
1938 * template <int dim>
1939 * double InteriorPenaltyProblem<dim>::estimate()
1941 * estimates.block(0).reinit(triangulation.n_active_cells());
1942 * using CellIterator = typename DoFHandler<dim>::active_cell_iterator;
1944 * const unsigned int n_gauss_points =
1945 * dof_handler.get_fe().tensor_degree() + 1;
1946 * const EstimatorScratchData<dim> scratch(mapping,
1948 * QGauss<dim>(n_gauss_points),
1949 * QGauss<dim - 1>(n_gauss_points + 1),
1950 * QGauss<dim - 1>(n_gauss_points),
1951 * update_hessians | update_JxW_values,
1952 * update_quadrature_points |
1953 * update_values | update_gradients |
1954 * update_JxW_values |
1955 * update_normal_vectors,
1956 * update_values | update_gradients |
1957 * update_JxW_values |
1958 * update_normal_vectors);
1959 * const ErrorCopyData<1> copy_data;
1961 * MeshWorker::mesh_loop(
1962 * dof_handler.begin_active(),
1963 * dof_handler.end(),
1965 * [&](const CellIterator &cell,
1966 * EstimatorScratchData<dim> &scratch_data,
1967 * ErrorCopyData<1> ©) {
1968 * copy.reinit(cell);
1969 * scratch_data.fe_values.reinit(cell);
1970 * const FEValues<dim> &fe_values = scratch_data.fe_values;
1971 * fe_values.get_function_hessians(solution, scratch_data.cell_hessians);
1972 * copy.cell_values[0] =
1973 * Estimator::cell<dim>(cell, fe_values, scratch_data.cell_hessians);
1976 * [&](const ErrorCopyData<1> ©) {
1977 * estimates.block(0)(copy.cell_index) += copy.cell_values[0];
1978 * for (const auto &face : copy.face_data)
1980 * estimates.block(0)(face.cell_index_1) += 0.5 * face.values[0];
1981 * estimates.block(0)(face.cell_index_2) += 0.5 * face.values[0];
1988 * MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
1989 * MeshWorker::assemble_own_interior_faces_once,
1991 * [&](const CellIterator &cell,
1992 * const unsigned int face_no,
1993 * EstimatorScratchData<dim> &scratch_data,
1994 * ErrorCopyData<1> ©) {
1995 * scratch_data.boundary_fe_values.reinit(cell, face_no);
1996 * const FEFaceValues<dim> &fe_face_values =
1997 * scratch_data.boundary_fe_values;
1998 * fe_face_values.get_function_values(
1999 * solution, scratch_data.boundary_solution_values);
2000 * exact_solution.value_list(fe_face_values.get_quadrature_points(),
2001 * scratch_data.boundary_exact_values);
2002 * copy.cell_values[0] +=
2003 * Estimator::boundary<dim>(cell,
2006 * scratch_data.boundary_solution_values,
2007 * scratch_data.boundary_exact_values);
2010 * [&](const CellIterator &cell,
2011 * const unsigned int face_no,
2012 * const unsigned int subface_no,
2013 * const CellIterator &neighbor,
2014 * const unsigned int neighbor_face_no,
2015 * const unsigned int neighbor_subface_no,
2016 * EstimatorScratchData<dim> &scratch_data,
2017 * ErrorCopyData<1> ©) {
2018 * auto &face_data = copy.emplace_face_data(cell, neighbor);
2020 * if (subface_no == numbers::invalid_unsigned_int)
2022 * scratch_data.face_fe_values.reinit(cell, face_no);
2023 * const FEFaceValuesBase<dim> &fe_face_values =
2024 * scratch_data.face_fe_values;
2026 * if (neighbor_subface_no == numbers::invalid_unsigned_int)
2028 * scratch_data.neighbor_face_values.reinit(neighbor,
2029 * neighbor_face_no);
2030 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2031 * scratch_data.neighbor_face_values;
2033 * fe_face_values.get_function_values(
2034 * solution, scratch_data.face_solution_values);
2035 * neighbor_fe_face_values.get_function_values(
2036 * solution, scratch_data.neighbor_face_solution_values);
2037 * fe_face_values.get_function_gradients(
2038 * solution, scratch_data.face_solution_gradients);
2039 * neighbor_fe_face_values.get_function_gradients(
2040 * solution, scratch_data.neighbor_face_solution_gradients);
2042 * face_data.values[0] = Estimator::face<dim>(
2046 * scratch_data.face_solution_values,
2047 * scratch_data.face_solution_gradients,
2050 * scratch_data.neighbor_face_solution_values,
2051 * scratch_data.neighbor_face_solution_gradients);
2055 * scratch_data.neighbor_subface_values.reinit(
2056 * neighbor, neighbor_face_no, neighbor_subface_no);
2057 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2058 * scratch_data.neighbor_subface_values;
2060 * fe_face_values.get_function_values(
2061 * solution, scratch_data.face_solution_values);
2062 * neighbor_fe_face_values.get_function_values(
2063 * solution, scratch_data.neighbor_face_solution_values);
2064 * fe_face_values.get_function_gradients(
2065 * solution, scratch_data.face_solution_gradients);
2066 * neighbor_fe_face_values.get_function_gradients(
2067 * solution, scratch_data.neighbor_face_solution_gradients);
2069 * face_data.values[0] = Estimator::face<dim>(
2073 * scratch_data.face_solution_values,
2074 * scratch_data.face_solution_gradients,
2077 * scratch_data.neighbor_face_solution_values,
2078 * scratch_data.neighbor_face_solution_gradients);
2083 * scratch_data.subface_values.reinit(cell, face_no, subface_no);
2084 * const FEFaceValuesBase<dim> &fe_face_values =
2085 * scratch_data.subface_values;
2087 * if (neighbor_subface_no == numbers::invalid_unsigned_int)
2089 * scratch_data.neighbor_face_values.reinit(neighbor,
2090 * neighbor_face_no);
2091 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2092 * scratch_data.neighbor_face_values;
2094 * fe_face_values.get_function_values(
2095 * solution, scratch_data.face_solution_values);
2096 * neighbor_fe_face_values.get_function_values(
2097 * solution, scratch_data.neighbor_face_solution_values);
2098 * fe_face_values.get_function_gradients(
2099 * solution, scratch_data.face_solution_gradients);
2100 * neighbor_fe_face_values.get_function_gradients(
2101 * solution, scratch_data.neighbor_face_solution_gradients);
2103 * face_data.values[0] = Estimator::face<dim>(
2107 * scratch_data.face_solution_values,
2108 * scratch_data.face_solution_gradients,
2111 * scratch_data.neighbor_face_solution_values,
2112 * scratch_data.neighbor_face_solution_gradients);
2116 * scratch_data.neighbor_subface_values.reinit(
2117 * neighbor, neighbor_face_no, neighbor_subface_no);
2118 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2119 * scratch_data.neighbor_subface_values;
2121 * fe_face_values.get_function_values(
2122 * solution, scratch_data.face_solution_values);
2123 * neighbor_fe_face_values.get_function_values(
2124 * solution, scratch_data.neighbor_face_solution_values);
2125 * fe_face_values.get_function_gradients(
2126 * solution, scratch_data.face_solution_gradients);
2127 * neighbor_fe_face_values.get_function_gradients(
2128 * solution, scratch_data.neighbor_face_solution_gradients);
2130 * face_data.values[0] = Estimator::face<dim>(
2134 * scratch_data.face_solution_values,
2135 * scratch_data.face_solution_gradients,
2138 * scratch_data.neighbor_face_solution_values,
2139 * scratch_data.neighbor_face_solution_gradients);
2144 * return estimates.block(0).l2_norm();
2149 * Here we compare our finite element solution with the known exact solution
2150 * and compute the mean quadratic error of the gradient and the function
2151 * itself. This function is a close relative of the estimation function right
2152 * above: the mesh loop again visits cells, boundary faces, and interior
2153 * faces; the workers evaluate local quantities with the help of the scratch
2154 * object; and the copier writes the resulting indicators into global data
2155 * structures only after the local computation is finished.
2159 * Since we compute the error in the energy and the
2160 * <i>L<sup>2</sup></i>-norm, respectively, our block vector needs two
2161 * blocks here. Consequently, the copy object stores two local values per
2162 * cell and per face contribution, and the copier accumulates each of them
2163 * into the corresponding block.
2166 * template <int dim>
2167 * void InteriorPenaltyProblem<dim>::error()
2169 * BlockVector<double> errors(2);
2170 * errors.block(0).reinit(triangulation.n_active_cells());
2171 * errors.block(1).reinit(triangulation.n_active_cells());
2172 * using CellIterator = typename DoFHandler<dim>::active_cell_iterator;
2174 * const unsigned int n_gauss_points =
2175 * dof_handler.get_fe().tensor_degree() + 1;
2176 * const ErrorScratchData<dim> scratch(mapping,
2178 * QGauss<dim>(n_gauss_points),
2179 * QGauss<dim - 1>(n_gauss_points + 1),
2180 * QGauss<dim - 1>(n_gauss_points),
2181 * update_quadrature_points |
2182 * update_values | update_gradients |
2183 * update_JxW_values,
2184 * update_quadrature_points |
2185 * update_values | update_JxW_values,
2186 * update_values | update_JxW_values);
2187 * const ErrorCopyData<2> copy_data;
2189 * MeshWorker::mesh_loop(
2190 * dof_handler.begin_active(),
2191 * dof_handler.end(),
2193 * [&](const CellIterator &cell,
2194 * ErrorScratchData<dim> &scratch_data,
2195 * ErrorCopyData<2> ©) {
2196 * copy.reinit(cell);
2197 * scratch_data.fe_values.reinit(cell);
2198 * const FEValues<dim> &fe_values = scratch_data.fe_values;
2199 * fe_values.get_function_values(solution,
2200 * scratch_data.cell_solution_values);
2201 * fe_values.get_function_gradients(solution,
2202 * scratch_data.cell_solution_gradients);
2203 * exact_solution.value_list(fe_values.get_quadrature_points(),
2204 * scratch_data.cell_exact_values);
2205 * exact_solution.gradient_list(fe_values.get_quadrature_points(),
2206 * scratch_data.cell_exact_gradients);
2207 * copy.cell_values =
2208 * ErrorIntegrator::cell<dim>(fe_values,
2209 * scratch_data.cell_solution_values,
2210 * scratch_data.cell_solution_gradients,
2211 * scratch_data.cell_exact_values,
2212 * scratch_data.cell_exact_gradients);
2215 * [&](const ErrorCopyData<2> ©) {
2216 * errors.block(0)(copy.cell_index) += copy.cell_values[0];
2217 * errors.block(1)(copy.cell_index) += copy.cell_values[1];
2218 * for (const auto &face : copy.face_data)
2220 * errors.block(0)(face.cell_index_1) += 0.5 * face.values[0];
2221 * errors.block(0)(face.cell_index_2) += 0.5 * face.values[0];
2228 * MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
2229 * MeshWorker::assemble_own_interior_faces_once,
2231 * [&](const CellIterator &cell,
2232 * const unsigned int face_no,
2233 * ErrorScratchData<dim> &scratch_data,
2234 * ErrorCopyData<2> ©) {
2235 * scratch_data.boundary_fe_values.reinit(cell, face_no);
2236 * const FEFaceValues<dim> &fe_face_values =
2237 * scratch_data.boundary_fe_values;
2238 * fe_face_values.get_function_values(
2239 * solution, scratch_data.boundary_solution_values);
2240 * exact_solution.value_list(fe_face_values.get_quadrature_points(),
2241 * scratch_data.boundary_exact_values);
2242 * copy.cell_values[0] +=
2243 * ErrorIntegrator::boundary<dim>(cell,
2246 * scratch_data.boundary_solution_values,
2247 * scratch_data.boundary_exact_values);
2250 * [&](const CellIterator &cell,
2251 * const unsigned int face_no,
2252 * const unsigned int subface_no,
2253 * const CellIterator &neighbor,
2254 * const unsigned int neighbor_face_no,
2255 * const unsigned int neighbor_subface_no,
2256 * ErrorScratchData<dim> &scratch_data,
2257 * ErrorCopyData<2> ©) {
2258 * auto &face_data = copy.emplace_face_data(cell, neighbor);
2260 * if (subface_no == numbers::invalid_unsigned_int)
2262 * scratch_data.face_fe_values.reinit(cell, face_no);
2263 * const FEFaceValuesBase<dim> &fe_face_values =
2264 * scratch_data.face_fe_values;
2266 * if (neighbor_subface_no == numbers::invalid_unsigned_int)
2268 * scratch_data.neighbor_face_values.reinit(neighbor,
2269 * neighbor_face_no);
2270 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2271 * scratch_data.neighbor_face_values;
2273 * fe_face_values.get_function_values(
2274 * solution, scratch_data.face_solution_values);
2275 * neighbor_fe_face_values.get_function_values(
2276 * solution, scratch_data.neighbor_face_solution_values);
2278 * face_data.values[0] = ErrorIntegrator::face<dim>(
2282 * scratch_data.face_solution_values,
2285 * scratch_data.neighbor_face_solution_values);
2289 * scratch_data.neighbor_subface_values.reinit(
2290 * neighbor, neighbor_face_no, neighbor_subface_no);
2291 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2292 * scratch_data.neighbor_subface_values;
2294 * fe_face_values.get_function_values(
2295 * solution, scratch_data.face_solution_values);
2296 * neighbor_fe_face_values.get_function_values(
2297 * solution, scratch_data.neighbor_face_solution_values);
2299 * face_data.values[0] = ErrorIntegrator::face<dim>(
2303 * scratch_data.face_solution_values,
2306 * scratch_data.neighbor_face_solution_values);
2311 * scratch_data.subface_values.reinit(cell, face_no, subface_no);
2312 * const FEFaceValuesBase<dim> &fe_face_values =
2313 * scratch_data.subface_values;
2315 * if (neighbor_subface_no == numbers::invalid_unsigned_int)
2317 * scratch_data.neighbor_face_values.reinit(neighbor,
2318 * neighbor_face_no);
2319 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2320 * scratch_data.neighbor_face_values;
2322 * fe_face_values.get_function_values(
2323 * solution, scratch_data.face_solution_values);
2324 * neighbor_fe_face_values.get_function_values(
2325 * solution, scratch_data.neighbor_face_solution_values);
2327 * face_data.values[0] = ErrorIntegrator::face<dim>(
2331 * scratch_data.face_solution_values,
2334 * scratch_data.neighbor_face_solution_values);
2338 * scratch_data.neighbor_subface_values.reinit(
2339 * neighbor, neighbor_face_no, neighbor_subface_no);
2340 * const FEFaceValuesBase<dim> &neighbor_fe_face_values =
2341 * scratch_data.neighbor_subface_values;
2343 * fe_face_values.get_function_values(
2344 * solution, scratch_data.face_solution_values);
2345 * neighbor_fe_face_values.get_function_values(
2346 * solution, scratch_data.neighbor_face_solution_values);
2348 * face_data.values[0] = ErrorIntegrator::face<dim>(
2352 * scratch_data.face_solution_values,
2355 * scratch_data.neighbor_face_solution_values);
2360 * std::cout << "energy-error: " << errors.block(0).l2_norm() << std::endl;
2361 * std::cout << "L2-error: " << errors.block(1).l2_norm() << std::endl;
2367 * Create graphical output. We produce the filename by collating the
2368 * name from its various components, including the refinement cycle
2369 * that we output with two digits.
2372 * template <int dim>
2374 * InteriorPenaltyProblem<dim>::output_results(const unsigned int cycle) const
2376 * const std::string filename =
2377 * "sol-" + Utilities::int_to_string(cycle, 2) + ".gnuplot";
2379 * std::cout << "Writing solution to <" << filename << ">..." << std::endl
2381 * std::ofstream gnuplot_output(filename);
2383 * DataOut<dim> data_out;
2384 * data_out.attach_dof_handler(dof_handler);
2385 * data_out.add_data_vector(solution, "u");
2386 * data_out.add_data_vector(estimates.block(0), "est");
2388 * data_out.build_patches();
2390 * data_out.write_gnuplot(gnuplot_output);
2395 * And finally the adaptive loop, more or less like in previous examples.
2398 * template <int dim>
2399 * void InteriorPenaltyProblem<dim>::run(unsigned int n_steps)
2401 * std::cout << "Element: " << fe.get_name() << std::endl;
2402 * for (unsigned int s = 0; s < n_steps; ++s)
2404 * std::cout << "Step " << s << std::endl;
2405 * if (estimates.block(0).empty())
2406 * triangulation.refine_global(1);
2409 * GridRefinement::refine_and_coarsen_fixed_fraction(
2410 * triangulation, estimates.block(0), 0.5, 0.0);
2411 * triangulation.execute_coarsening_and_refinement();
2414 * std::cout << "Triangulation " << triangulation.n_active_cells()
2415 * << " cells, " << triangulation.n_levels() << " levels"
2419 * std::cout << "DoFHandler " << dof_handler.n_dofs()
2420 * << " dofs, level dofs";
2421 * for (unsigned int l = 0; l < triangulation.n_levels(); ++l)
2422 * std::cout << ' ' << dof_handler.n_dofs(l);
2423 * std::cout << std::endl;
2425 * std::cout << "Assemble matrix" << std::endl;
2426 * assemble_matrix();
2427 * std::cout << "Assemble multilevel matrix" << std::endl;
2428 * assemble_mg_matrix();
2429 * std::cout << "Assemble right hand side" << std::endl;
2430 * assemble_right_hand_side();
2431 * std::cout << "Solve" << std::endl;
2434 * std::cout << "Estimate " << estimate() << std::endl;
2435 * output_results(s);
2446 * using namespace Step39;
2448 * InteriorPenaltyProblem<2> test1;
2451 * catch (std::exception &exc)
2453 * std::cerr << std::endl
2455 * << "----------------------------------------------------"
2457 * std::cerr << "Exception on processing: " << std::endl
2458 * << exc.what() << std::endl
2459 * << "Aborting!" << std::endl
2460 * << "----------------------------------------------------"
2466 * std::cerr << std::endl
2468 * << "----------------------------------------------------"
2470 * std::cerr << "Unknown exception!" << std::endl
2471 * << "Aborting!" << std::endl
2472 * << "----------------------------------------------------"
2480<a name="step_39-Results"></a><h1>Results</h1>
2483<a name="step_39-Logfileoutput"></a><h3>Logfile output</h3>
2485First, the program produces the usual logfile here stored in <tt>deallog</tt>. It reads (with omission of intermediate steps)
2488Element: FE_DGQ<2>(3)
2490Triangulation 16 cells, 2 levels
2491DoFHandler 256 dofs, level dofs 64 256
2493Assemble multilevel matrix
2494Assemble right hand side
2496Converged in 13 iterations
2497energy-error: 0.297419
2500Writing solution to <sol-00.gnuplot>...
2503Triangulation 25 cells, 3 levels
2504DoFHandler 400 dofs, level dofs 64 256 192
2506Assemble multilevel matrix
2507Assemble right hand side
2509Converged in 14 iterations
2510energy-error: 0.258559
2513Writing solution to <sol-01.gnuplot>...
2518Triangulation 232 cells, 11 levels
2519DoFHandler 3712 dofs, level dofs 64 256 896 768 768 640 512 256 256 256 256
2521Assemble multilevel matrix
2522Assemble right hand side
2524Converged in 15 iterations
2525energy-error: 0.0132475
2526L2-error: 1.00423e-05
2528Writing solution to <sol-10.gnuplot>...
2531Triangulation 322 cells, 12 levels
2532DoFHandler 5152 dofs, level dofs 64 256 1024 1024 896 768 768 640 448 320 320 320
2534Assemble multilevel matrix
2535Assemble right hand side
2537Converged in 15 iterations
2538energy-error: 0.00934891
2539L2-error: 5.41095e-06
2541Writing solution to <sol-11.gnuplot>...
2544This log for instance shows that the number of conjugate gradient
2545iteration steps is constant at approximately 15.
2546This is the key qualitative result of the example: despite adaptive mesh
2547refinement and the discontinuous Galerkin discretization, the multigrid
2548preconditioner keeps the iteration count essentially mesh-independent.
2551<a name="step_39-Postprocessingofthelogfile"></a><h3>Postprocessing of the logfile</h3>
2554<img src="https://dealii.org/images/steps/developer/step-39-convergence.svg" alt="">
2555Using the perl script <tt>postprocess.pl</tt>, we extract relevant
2556data into <tt>output.dat</tt>, which can be used to plot graphs with
2557<tt>gnuplot</tt>. The graph above for instance was produced using the gnuplot
2558script <tt>plot_errors.gpl</tt> via
2561./step-39 | perl postprocess.pl >output.dat
2562gnuplot plot_errors.gpl
2565Reference data can be found in <tt>output.reference.dat</tt>.
2568<a name="step_39-PlainProg"></a>
2569<h1> The plain program</h1>
2570@include "step-39.cc"
* * int main(int argc, char **argv)
* x_component_mask set(0, true)
* * * struct InterferenceTaperTransform *
typename LevelSelector::cell_iterator level_cell_iterator
void copy_from(const MatrixType &)
void initialize(const FullMatrix< number > &A)
void build(const DoFHandler< dim, spacedim > &dof_handler)
typename ActiveSelector::active_cell_iterator active_cell_iterator
void mesh_loop(const CellIteratorType &begin, const CellIteratorType &end, const CellWorkerFunctionType &cell_worker, const CopierType &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const AssembleFlags flags=assemble_own_cells, const BoundaryWorkerFunctionType &boundary_worker=BoundaryWorkerFunctionType(), const FaceWorkerFunctionType &face_worker=FaceWorkerFunctionType(), const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
void loop(IteratorType begin, std_cxx20::type_identity_t< IteratorType > end, DOFINFO &dinfo, INFOBOX &info, const std::function< void(std_cxx20::type_identity_t< DOFINFO > &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(std_cxx20::type_identity_t< DOFINFO > &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(std_cxx20::type_identity_t< DOFINFO > &, std_cxx20::type_identity_t< DOFINFO > &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, AssemblerType &assembler, const LoopControl &lctrl=LoopControl())
@ update_values
Shape function values.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
std::vector< index_type > data
std::vector< value_type > split(const typename ::Triangulation< dim, spacedim >::cell_iterator &parent, const value_type parent_value)
@ matrix
Contents is actually a matrix.
@ symmetric
Matrix is symmetric.
constexpr types::blas_int one
@ assemble_boundary_faces
@ assemble_own_interior_faces_once
void copy(const T *begin, const T *end, U *dest)
int(&) functions(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
constexpr unsigned int invalid_unsigned_int