deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
step-39.h
Go to the documentation of this file.
1
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);
1438 *   },
1439 *   /* copier: */
1440 *   [&](const MatrixCopyData<dim> &copy) {
1441 *   matrix.add(copy.local_dof_indices, copy.cell_matrix);
1442 *   for (const auto &face : copy.face_data)
1443 *   {
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);
1448 *   }
1449 *   },
1450 *   /* scratch and copy objects: */
1451 *   scratch,
1452 *   copy_data,
1453 *   /* where and how we want to integrate: */
1456 *   /* boundary face worker: */
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,
1463 *   face_no,
1464 *   scratch_data.boundary_fe_values,
1465 *   copy.cell_matrix);
1466 *   },
1467 *   /* interior face worker: */
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);
1477 *   if (subface_no == numbers::invalid_unsigned_int)
1478 *   {
1479 *   scratch_data.face_fe_values.reinit(cell, face_no);
1480 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
1481 *   {
1482 *   scratch_data.neighbor_face_values.reinit(neighbor,
1483 *   neighbor_face_no);
1484 *   MatrixIntegrator::face<dim>(cell,
1485 *   face_no,
1486 *   scratch_data.face_fe_values,
1487 *   neighbor,
1488 *   neighbor_face_no,
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);
1494 *   }
1495 *   else
1496 *   {
1497 *   scratch_data.neighbor_subface_values.reinit(
1498 *   neighbor, neighbor_face_no, neighbor_subface_no);
1499 *   MatrixIntegrator::face<dim>(
1500 *   cell,
1501 *   face_no,
1502 *   scratch_data.face_fe_values,
1503 *   neighbor,
1504 *   neighbor_face_no,
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);
1510 *   }
1511 *   }
1512 *   else
1513 *   {
1514 *   scratch_data.subface_values.reinit(cell, face_no, subface_no);
1515 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
1516 *   {
1517 *   scratch_data.neighbor_face_values.reinit(neighbor,
1518 *   neighbor_face_no);
1519 *   MatrixIntegrator::face<dim>(cell,
1520 *   face_no,
1521 *   scratch_data.subface_values,
1522 *   neighbor,
1523 *   neighbor_face_no,
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);
1529 *   }
1530 *   else
1531 *   {
1532 *   scratch_data.neighbor_subface_values.reinit(
1533 *   neighbor, neighbor_face_no, neighbor_subface_no);
1534 *   MatrixIntegrator::face<dim>(
1535 *   cell,
1536 *   face_no,
1537 *   scratch_data.subface_values,
1538 *   neighbor,
1539 *   neighbor_face_no,
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);
1545 *   }
1546 *   }
1547 *   });
1548 *   }
1549 *  
1550 *  
1551 * @endcode
1552 *
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
1556 * functions compute local matrix contributions without touching global data.
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.
1560 *
1561
1562 *
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.
1567 *
1568 * @code
1569 *   template <int dim>
1570 *   void InteriorPenaltyProblem<dim>::assemble_mg_matrix()
1571 *   {
1572 *   using CellIterator = typename DoFHandler<dim>::level_cell_iterator;
1573 *  
1574 *   const MatrixScratchData<dim> scratch(mapping,
1575 *   fe,
1576 *   QGauss<dim>(fe.degree + 1),
1577 *   QGauss<dim - 1>(fe.degree + 1),
1582 *   const MatrixCopyData<dim> copy_data(fe.n_dofs_per_cell());
1583 *  
1585 *   dof_handler.begin_mg(),
1586 *   dof_handler.end_mg(),
1587 *   /* cell worker: */
1588 *   [&](const CellIterator &cell,
1589 *   MatrixScratchData<dim> &scratch_data,
1590 *   MatrixCopyData<dim> &copy) {
1591 *   copy.reinit(cell, true);
1592 *   scratch_data.fe_values.reinit(cell);
1593 *   MatrixIntegrator::cell<dim>(scratch_data.fe_values, copy.cell_matrix);
1594 *   },
1595 *   /* copier: */
1596 *   [&](const MatrixCopyData<dim> &copy) {
1597 *   mg_matrix[copy.level].add(copy.local_dof_indices, copy.cell_matrix);
1598 *  
1599 *   for (const auto &face : copy.face_data)
1600 *   if (face.level_1 == face.level_2)
1601 *   {
1602 *   mg_matrix[face.level_1].add(face.dof_indices_1,
1603 *   face.dof_indices_1,
1604 *   face.matrix_11);
1605 *   mg_matrix[face.level_1].add(face.dof_indices_1,
1606 *   face.dof_indices_2,
1607 *   face.matrix_12);
1608 *   mg_matrix[face.level_1].add(face.dof_indices_2,
1609 *   face.dof_indices_1,
1610 *   face.matrix_21);
1611 *   mg_matrix[face.level_1].add(face.dof_indices_2,
1612 *   face.dof_indices_2,
1613 *   face.matrix_22);
1614 *   }
1615 *   else
1616 *   {
1617 *   Assert(face.level_1 > face.level_2, ExcInternalError());
1618 *  
1619 *   mg_matrix[face.level_1].add(face.dof_indices_1,
1620 *   face.dof_indices_1,
1621 *   face.matrix_11);
1622 *  
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)
1625 *   {
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));
1632 *   }
1633 *   }
1634 *   },
1635 *   /* scratch and copy objects: */
1636 *   scratch,
1637 *   copy_data,
1638 *   /* where and how we want to integrate: */
1641 *   /* boundary face worker: */
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,
1648 *   face_no,
1649 *   scratch_data.boundary_fe_values,
1650 *   copy.cell_matrix);
1651 *   },
1652 *   /* interior face worker: */
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);
1662 *   if (subface_no == numbers::invalid_unsigned_int)
1663 *   {
1664 *   scratch_data.face_fe_values.reinit(cell, face_no);
1665 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
1666 *   {
1667 *   scratch_data.neighbor_face_values.reinit(neighbor,
1668 *   neighbor_face_no);
1669 *   MatrixIntegrator::face<dim>(cell,
1670 *   face_no,
1671 *   scratch_data.face_fe_values,
1672 *   neighbor,
1673 *   neighbor_face_no,
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);
1679 *   }
1680 *   else
1681 *   {
1682 *   scratch_data.neighbor_subface_values.reinit(
1683 *   neighbor, neighbor_face_no, neighbor_subface_no);
1684 *   MatrixIntegrator::face<dim>(
1685 *   cell,
1686 *   face_no,
1687 *   scratch_data.face_fe_values,
1688 *   neighbor,
1689 *   neighbor_face_no,
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);
1695 *   }
1696 *   }
1697 *   else
1698 *   {
1699 *   scratch_data.subface_values.reinit(cell, face_no, subface_no);
1700 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
1701 *   {
1702 *   scratch_data.neighbor_face_values.reinit(neighbor,
1703 *   neighbor_face_no);
1704 *   MatrixIntegrator::face<dim>(cell,
1705 *   face_no,
1706 *   scratch_data.subface_values,
1707 *   neighbor,
1708 *   neighbor_face_no,
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);
1714 *   }
1715 *   else
1716 *   {
1717 *   scratch_data.neighbor_subface_values.reinit(
1718 *   neighbor, neighbor_face_no, neighbor_subface_no);
1719 *   MatrixIntegrator::face<dim>(
1720 *   cell,
1721 *   face_no,
1722 *   scratch_data.subface_values,
1723 *   neighbor,
1724 *   neighbor_face_no,
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);
1730 *   }
1731 *   }
1732 *   });
1733 *   }
1734 *  
1735 *  
1736 * @endcode
1737 *
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.
1740 *
1741
1742 *
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.
1749 *
1750 * @code
1751 *   template <int dim>
1752 *   void InteriorPenaltyProblem<dim>::assemble_right_hand_side()
1753 *   {
1754 *   using CellIterator = typename DoFHandler<dim>::active_cell_iterator;
1755 *  
1756 *   const RightHandSideScratchData<dim> scratch(mapping,
1757 *   fe,
1758 *   QGauss<dim - 1>(fe.degree + 1),
1760 *   update_values |
1764 *   const RightHandSideCopyData copy_data(fe.n_dofs_per_cell());
1765 *  
1767 *   dof_handler.begin_active(),
1768 *   dof_handler.end(),
1769 *   /* cell worker: */
1770 *   [&](const CellIterator &cell,
1771 *   RightHandSideScratchData<dim> &,
1772 *   RightHandSideCopyData &copy) { copy.reinit(cell); },
1773 *   /* copier: */
1774 *   [&](const RightHandSideCopyData &copy) {
1775 *   right_hand_side.add(copy.local_dof_indices, copy.cell_rhs);
1776 *   },
1777 *   /* scratch and copy objects: */
1778 *   scratch,
1779 *   copy_data,
1780 *   /* where and how we want to integrate: */
1782 *   /* boundary face worker: */
1783 *   [&](const CellIterator &cell,
1784 *   const unsigned int face_no,
1785 *   RightHandSideScratchData<dim> &scratch_data,
1786 *   RightHandSideCopyData &copy) {
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,
1792 *   face_no,
1793 *   scratch_data.boundary_fe_values,
1794 *   scratch_data.boundary_values,
1795 *   copy.cell_rhs);
1796 *   });
1797 *  
1798 *   right_hand_side *= -1.;
1799 *   }
1800 *  
1801 *  
1802 * @endcode
1803 *
1804 * Now that we have coded all functions building the discrete linear system,
1805 * it is about time that we actually solve it.
1806 *
1807 * @code
1808 *   template <int dim>
1809 *   void InteriorPenaltyProblem<dim>::solve()
1810 *   {
1811 * @endcode
1812 *
1813 * The solver of choice is conjugate gradient.
1814 *
1815 * @code
1816 *   SolverControl control(1000, 1.e-12);
1817 *   SolverCG<Vector<double>> solver(control);
1818 *  
1819 * @endcode
1820 *
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.
1824 *
1825 * @code
1827 *   mg_transfer.build(dof_handler);
1828 *  
1829 * @endcode
1830 *
1831 * Then, we need an exact solver for the matrix on the coarsest level.
1832 *
1833 * @code
1834 *   FullMatrix<double> coarse_matrix;
1835 *   coarse_matrix.copy_from(mg_matrix[0]);
1837 *   mg_coarse.initialize(coarse_matrix);
1838 *  
1839 * @endcode
1840 *
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.
1844 *
1845 * @code
1847 *   using RELAXATION = PreconditionSOR<SparseMatrix<double>>;
1849 *   RELAXATION::AdditionalData smoother_data(1.);
1850 *   mg_smoother.initialize(mg_matrix, smoother_data);
1851 *  
1852 * @endcode
1853 *
1854 * Do two smoothing steps on each level.
1855 *
1856 * @code
1857 *   mg_smoother.set_steps(2);
1858 * @endcode
1859 *
1860 * Since the SOR method is not symmetric, but we use conjugate gradient
1861 * iteration below, here is a trick to make the multilevel preconditioner
1862 * a symmetric operator even for nonsymmetric smoothers.
1863 *
1864 * @code
1865 *   mg_smoother.set_symmetric(true);
1866 * @endcode
1867 *
1868 * The smoother class optionally implements the variable V-cycle, which we
1869 * do not want here.
1870 *
1871 * @code
1872 *   mg_smoother.set_variable(false);
1873 *  
1874 * @endcode
1875 *
1876 * Finally, we must wrap our matrices in an object having the required
1877 * multiplication functions.
1878 *
1879 * @code
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);
1883 *  
1884 * @endcode
1885 *
1886 * Now, we are ready to set up the V-cycle operator and the multilevel
1887 * preconditioner.
1888 *
1889 * @code
1890 *   Multigrid<Vector<double>> mg(
1891 *   mgmatrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
1892 * @endcode
1893 *
1894 * Let us not forget the edge matrices needed because of the adaptive
1895 * refinement.
1896 *
1897 * @code
1898 *   mg.set_edge_flux_matrices(mgdown, mgup);
1899 *  
1900 * @endcode
1901 *
1902 * After all preparations, wrap the Multigrid object into another object,
1903 * which can be used as a regular preconditioner,
1904 *
1905 * @code
1906 *   PreconditionMG<dim, Vector<double>, MGTransferPrebuilt<Vector<double>>>
1907 *   preconditioner(dof_handler, mg, mg_transfer);
1908 * @endcode
1909 *
1910 * and use it to solve the system.
1911 *
1912 * @code
1913 *   solver.solve(matrix, solution, right_hand_side, preconditioner);
1914 *  
1915 *   std::cout << "Converged in " << control.last_step() << " iterations"
1916 *   << std::endl;
1917 *   }
1918 *  
1919 *  
1920 * @endcode
1921 *
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
1925 * per cell.
1926 *
1927
1928 *
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.
1936 *
1937 * @code
1938 *   template <int dim>
1939 *   double InteriorPenaltyProblem<dim>::estimate()
1940 *   {
1941 *   estimates.block(0).reinit(triangulation.n_active_cells());
1942 *   using CellIterator = typename DoFHandler<dim>::active_cell_iterator;
1943 *  
1944 *   const unsigned int n_gauss_points =
1945 *   dof_handler.get_fe().tensor_degree() + 1;
1946 *   const EstimatorScratchData<dim> scratch(mapping,
1947 *   fe,
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;
1960 *  
1961 *   MeshWorker::mesh_loop(
1962 *   dof_handler.begin_active(),
1963 *   dof_handler.end(),
1964 *   /* cell worker: */
1965 *   [&](const CellIterator &cell,
1966 *   EstimatorScratchData<dim> &scratch_data,
1967 *   ErrorCopyData<1> &copy) {
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);
1974 *   },
1975 *   /* copier: */
1976 *   [&](const ErrorCopyData<1> &copy) {
1977 *   estimates.block(0)(copy.cell_index) += copy.cell_values[0];
1978 *   for (const auto &face : copy.face_data)
1979 *   {
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];
1982 *   }
1983 *   },
1984 *   /* scratch and copy objects: */
1985 *   scratch,
1986 *   copy_data,
1987 *   /* where and how we want to integrate: */
1988 *   MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
1989 *   MeshWorker::assemble_own_interior_faces_once,
1990 *   /* boundary face worker: */
1991 *   [&](const CellIterator &cell,
1992 *   const unsigned int face_no,
1993 *   EstimatorScratchData<dim> &scratch_data,
1994 *   ErrorCopyData<1> &copy) {
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,
2004 *   face_no,
2005 *   fe_face_values,
2006 *   scratch_data.boundary_solution_values,
2007 *   scratch_data.boundary_exact_values);
2008 *   },
2009 *   /* interior face worker: */
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> &copy) {
2018 *   auto &face_data = copy.emplace_face_data(cell, neighbor);
2019 *  
2020 *   if (subface_no == numbers::invalid_unsigned_int)
2021 *   {
2022 *   scratch_data.face_fe_values.reinit(cell, face_no);
2023 *   const FEFaceValuesBase<dim> &fe_face_values =
2024 *   scratch_data.face_fe_values;
2025 *  
2026 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
2027 *   {
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;
2032 *  
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);
2041 *  
2042 *   face_data.values[0] = Estimator::face<dim>(
2043 *   cell,
2044 *   face_no,
2045 *   fe_face_values,
2046 *   scratch_data.face_solution_values,
2047 *   scratch_data.face_solution_gradients,
2048 *   neighbor,
2049 *   neighbor_face_no,
2050 *   scratch_data.neighbor_face_solution_values,
2051 *   scratch_data.neighbor_face_solution_gradients);
2052 *   }
2053 *   else
2054 *   {
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;
2059 *  
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);
2068 *  
2069 *   face_data.values[0] = Estimator::face<dim>(
2070 *   cell,
2071 *   face_no,
2072 *   fe_face_values,
2073 *   scratch_data.face_solution_values,
2074 *   scratch_data.face_solution_gradients,
2075 *   neighbor,
2076 *   neighbor_face_no,
2077 *   scratch_data.neighbor_face_solution_values,
2078 *   scratch_data.neighbor_face_solution_gradients);
2079 *   }
2080 *   }
2081 *   else
2082 *   {
2083 *   scratch_data.subface_values.reinit(cell, face_no, subface_no);
2084 *   const FEFaceValuesBase<dim> &fe_face_values =
2085 *   scratch_data.subface_values;
2086 *  
2087 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
2088 *   {
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;
2093 *  
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);
2102 *  
2103 *   face_data.values[0] = Estimator::face<dim>(
2104 *   cell,
2105 *   face_no,
2106 *   fe_face_values,
2107 *   scratch_data.face_solution_values,
2108 *   scratch_data.face_solution_gradients,
2109 *   neighbor,
2110 *   neighbor_face_no,
2111 *   scratch_data.neighbor_face_solution_values,
2112 *   scratch_data.neighbor_face_solution_gradients);
2113 *   }
2114 *   else
2115 *   {
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;
2120 *  
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);
2129 *  
2130 *   face_data.values[0] = Estimator::face<dim>(
2131 *   cell,
2132 *   face_no,
2133 *   fe_face_values,
2134 *   scratch_data.face_solution_values,
2135 *   scratch_data.face_solution_gradients,
2136 *   neighbor,
2137 *   neighbor_face_no,
2138 *   scratch_data.neighbor_face_solution_values,
2139 *   scratch_data.neighbor_face_solution_gradients);
2140 *   }
2141 *   }
2142 *   });
2143 *  
2144 *   return estimates.block(0).l2_norm();
2145 *   }
2146 *  
2147 * @endcode
2148 *
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.
2156 *
2157
2158 *
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.
2164 *
2165 * @code
2166 *   template <int dim>
2167 *   void InteriorPenaltyProblem<dim>::error()
2168 *   {
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;
2173 *  
2174 *   const unsigned int n_gauss_points =
2175 *   dof_handler.get_fe().tensor_degree() + 1;
2176 *   const ErrorScratchData<dim> scratch(mapping,
2177 *   fe,
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;
2188 *  
2189 *   MeshWorker::mesh_loop(
2190 *   dof_handler.begin_active(),
2191 *   dof_handler.end(),
2192 *   /* cell worker: */
2193 *   [&](const CellIterator &cell,
2194 *   ErrorScratchData<dim> &scratch_data,
2195 *   ErrorCopyData<2> &copy) {
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);
2213 *   },
2214 *   /* copier: */
2215 *   [&](const ErrorCopyData<2> &copy) {
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)
2219 *   {
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];
2222 *   }
2223 *   },
2224 *   /* scratch and copy objects: */
2225 *   scratch,
2226 *   copy_data,
2227 *   /* where and how we want to integrate: */
2228 *   MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
2229 *   MeshWorker::assemble_own_interior_faces_once,
2230 *   /* boundary face worker: */
2231 *   [&](const CellIterator &cell,
2232 *   const unsigned int face_no,
2233 *   ErrorScratchData<dim> &scratch_data,
2234 *   ErrorCopyData<2> &copy) {
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,
2244 *   face_no,
2245 *   fe_face_values,
2246 *   scratch_data.boundary_solution_values,
2247 *   scratch_data.boundary_exact_values);
2248 *   },
2249 *   /* interior face worker: */
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> &copy) {
2258 *   auto &face_data = copy.emplace_face_data(cell, neighbor);
2259 *  
2260 *   if (subface_no == numbers::invalid_unsigned_int)
2261 *   {
2262 *   scratch_data.face_fe_values.reinit(cell, face_no);
2263 *   const FEFaceValuesBase<dim> &fe_face_values =
2264 *   scratch_data.face_fe_values;
2265 *  
2266 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
2267 *   {
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;
2272 *  
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);
2277 *  
2278 *   face_data.values[0] = ErrorIntegrator::face<dim>(
2279 *   cell,
2280 *   face_no,
2281 *   fe_face_values,
2282 *   scratch_data.face_solution_values,
2283 *   neighbor,
2284 *   neighbor_face_no,
2285 *   scratch_data.neighbor_face_solution_values);
2286 *   }
2287 *   else
2288 *   {
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;
2293 *  
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);
2298 *  
2299 *   face_data.values[0] = ErrorIntegrator::face<dim>(
2300 *   cell,
2301 *   face_no,
2302 *   fe_face_values,
2303 *   scratch_data.face_solution_values,
2304 *   neighbor,
2305 *   neighbor_face_no,
2306 *   scratch_data.neighbor_face_solution_values);
2307 *   }
2308 *   }
2309 *   else
2310 *   {
2311 *   scratch_data.subface_values.reinit(cell, face_no, subface_no);
2312 *   const FEFaceValuesBase<dim> &fe_face_values =
2313 *   scratch_data.subface_values;
2314 *  
2315 *   if (neighbor_subface_no == numbers::invalid_unsigned_int)
2316 *   {
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;
2321 *  
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);
2326 *  
2327 *   face_data.values[0] = ErrorIntegrator::face<dim>(
2328 *   cell,
2329 *   face_no,
2330 *   fe_face_values,
2331 *   scratch_data.face_solution_values,
2332 *   neighbor,
2333 *   neighbor_face_no,
2334 *   scratch_data.neighbor_face_solution_values);
2335 *   }
2336 *   else
2337 *   {
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;
2342 *  
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);
2347 *  
2348 *   face_data.values[0] = ErrorIntegrator::face<dim>(
2349 *   cell,
2350 *   face_no,
2351 *   fe_face_values,
2352 *   scratch_data.face_solution_values,
2353 *   neighbor,
2354 *   neighbor_face_no,
2355 *   scratch_data.neighbor_face_solution_values);
2356 *   }
2357 *   }
2358 *   });
2359 *  
2360 *   std::cout << "energy-error: " << errors.block(0).l2_norm() << std::endl;
2361 *   std::cout << "L2-error: " << errors.block(1).l2_norm() << std::endl;
2362 *   }
2363 *  
2364 *  
2365 * @endcode
2366 *
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.
2370 *
2371 * @code
2372 *   template <int dim>
2373 *   void
2374 *   InteriorPenaltyProblem<dim>::output_results(const unsigned int cycle) const
2375 *   {
2376 *   const std::string filename =
2377 *   "sol-" + Utilities::int_to_string(cycle, 2) + ".gnuplot";
2378 *  
2379 *   std::cout << "Writing solution to <" << filename << ">..." << std::endl
2380 *   << std::endl;
2381 *   std::ofstream gnuplot_output(filename);
2382 *  
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");
2387 *  
2388 *   data_out.build_patches();
2389 *  
2390 *   data_out.write_gnuplot(gnuplot_output);
2391 *   }
2392 *  
2393 * @endcode
2394 *
2395 * And finally the adaptive loop, more or less like in previous examples.
2396 *
2397 * @code
2398 *   template <int dim>
2399 *   void InteriorPenaltyProblem<dim>::run(unsigned int n_steps)
2400 *   {
2401 *   std::cout << "Element: " << fe.get_name() << std::endl;
2402 *   for (unsigned int s = 0; s < n_steps; ++s)
2403 *   {
2404 *   std::cout << "Step " << s << std::endl;
2405 *   if (estimates.block(0).empty())
2406 *   triangulation.refine_global(1);
2407 *   else
2408 *   {
2409 *   GridRefinement::refine_and_coarsen_fixed_fraction(
2410 *   triangulation, estimates.block(0), 0.5, 0.0);
2411 *   triangulation.execute_coarsening_and_refinement();
2412 *   }
2413 *  
2414 *   std::cout << "Triangulation " << triangulation.n_active_cells()
2415 *   << " cells, " << triangulation.n_levels() << " levels"
2416 *   << std::endl;
2417 *  
2418 *   setup_system();
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;
2424 *  
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;
2432 *   solve();
2433 *   error();
2434 *   std::cout << "Estimate " << estimate() << std::endl;
2435 *   output_results(s);
2436 *   }
2437 *   }
2438 *   } // namespace Step39
2439 *  
2440 *  
2441 *  
2442 *   int main()
2443 *   {
2444 *   try
2445 *   {
2446 *   using namespace Step39;
2447 *  
2448 *   InteriorPenaltyProblem<2> test1;
2449 *   test1.run(12);
2450 *   }
2451 *   catch (std::exception &exc)
2452 *   {
2453 *   std::cerr << std::endl
2454 *   << std::endl
2455 *   << "----------------------------------------------------"
2456 *   << std::endl;
2457 *   std::cerr << "Exception on processing: " << std::endl
2458 *   << exc.what() << std::endl
2459 *   << "Aborting!" << std::endl
2460 *   << "----------------------------------------------------"
2461 *   << std::endl;
2462 *   return 1;
2463 *   }
2464 *   catch (...)
2465 *   {
2466 *   std::cerr << std::endl
2467 *   << std::endl
2468 *   << "----------------------------------------------------"
2469 *   << std::endl;
2470 *   std::cerr << "Unknown exception!" << std::endl
2471 *   << "Aborting!" << std::endl
2472 *   << "----------------------------------------------------"
2473 *   << std::endl;
2474 *   return 1;
2475 *   }
2476 *  
2477 *   return 0;
2478 *   }
2479 * @endcode
2480<a name="step_39-Results"></a><h1>Results</h1>
2481
2482
2483<a name="step_39-Logfileoutput"></a><h3>Logfile output</h3>
2484
2485First, the program produces the usual logfile here stored in <tt>deallog</tt>. It reads (with omission of intermediate steps)
2486
2487@code
2488Element: FE_DGQ<2>(3)
2489Step 0
2490Triangulation 16 cells, 2 levels
2491DoFHandler 256 dofs, level dofs 64 256
2492Assemble matrix
2493Assemble multilevel matrix
2494Assemble right hand side
2495Solve
2496Converged in 13 iterations
2497energy-error: 0.297419
2498L2-error: 0.00452447
2499Estimate 0.990460
2500Writing solution to <sol-00.gnuplot>...
2501
2502Step 1
2503Triangulation 25 cells, 3 levels
2504DoFHandler 400 dofs, level dofs 64 256 192
2505Assemble matrix
2506Assemble multilevel matrix
2507Assemble right hand side
2508Solve
2509Converged in 14 iterations
2510energy-error: 0.258559
2511L2-error: 0.00288510
2512Estimate 0.738624
2513Writing solution to <sol-01.gnuplot>...
2514
2515...
2516
2517Step 10
2518Triangulation 232 cells, 11 levels
2519DoFHandler 3712 dofs, level dofs 64 256 896 768 768 640 512 256 256 256 256
2520Assemble matrix
2521Assemble multilevel matrix
2522Assemble right hand side
2523Solve
2524Converged in 15 iterations
2525energy-error: 0.0132475
2526L2-error: 1.00423e-05
2527Estimate 0.0470724
2528Writing solution to <sol-10.gnuplot>...
2529
2530Step 11
2531Triangulation 322 cells, 12 levels
2532DoFHandler 5152 dofs, level dofs 64 256 1024 1024 896 768 768 640 448 320 320 320
2533Assemble matrix
2534Assemble multilevel matrix
2535Assemble right hand side
2536Solve
2537Converged in 15 iterations
2538energy-error: 0.00934891
2539L2-error: 5.41095e-06
2540Estimate 0.0329102
2541Writing solution to <sol-11.gnuplot>...
2542@endcode
2543
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.
2549
2550
2551<a name="step_39-Postprocessingofthelogfile"></a><h3>Postprocessing of the logfile</h3>
2552
2553
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
2559
2560@code
2561./step-39 | perl postprocess.pl >output.dat
2562gnuplot plot_errors.gpl
2563@endcode
2564
2565Reference data can be found in <tt>output.reference.dat</tt>.
2566 *
2567 *
2568<a name="step_39-PlainProg"></a>
2569<h1> The plain program</h1>
2570@include "step-39.cc"
2571*/
*  *  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)
unsigned int level
Definition grid_out.cc:4642
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)
Definition mesh_loop.h:279
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())
Definition loop.h:562
@ 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
Definition mpi.cc:734
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 char V
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)
Definition loop.h:68
Definition mg.h:79
constexpr unsigned int invalid_unsigned_int
Definition types.h:228