/**
* Similar to the above function but also taking a @p policy for
- * repartitioning the triangulations on the coarser levels.
+ * repartitioning the triangulations on the coarser levels. If
+ * @p preserve_fine_triangulation is set, the input triangulation is not
+ * altered,
+ * else the triangulation is coarsened. If @p repartition_fine_triangulation
+ * is set, the triangulation on the finest level is repartitioned as well. If
+ * the flags are set to true/false, the input triangulation is simply used as
+ * the finest triangulation.
*
* @note For convenience, a reference to the input triangulation is stored in
* the last entry of the return vector.
*/
template <int dim, int spacedim>
std::vector<std::shared_ptr<const Triangulation<dim, spacedim>>>
+ create_geometric_coarsening_sequence(
+ Triangulation<dim, spacedim> & tria,
+ const RepartitioningPolicyTools::Base<dim, spacedim> &policy,
+ const bool preserve_fine_triangulation,
+ const bool repartition_fine_triangulation);
+
+ /**
+ * Similar to the above function but taking in a constant version of
+ * @p tria and as a consequence not allowing to directly use it for
+ * coarsening, requiring that internally a temporal copy is created.
+ */
+ template <int dim, int spacedim>
+ std::vector<std::shared_ptr<const Triangulation<dim, spacedim>>>
create_geometric_coarsening_sequence(
const Triangulation<dim, spacedim> & tria,
- const RepartitioningPolicyTools::Base<dim, spacedim> &policy);
+ const RepartitioningPolicyTools::Base<dim, spacedim> &policy,
+ const bool repartition_fine_triangulation = false);
} // namespace MGTransferGlobalCoarseningTools
template <int dim, int spacedim>
std::vector<std::shared_ptr<const Triangulation<dim, spacedim>>>
create_geometric_coarsening_sequence(
- const Triangulation<dim, spacedim> & fine_triangulation_in,
- const RepartitioningPolicyTools::Base<dim, spacedim> &policy)
+ Triangulation<dim, spacedim> & fine_triangulation_in,
+ const RepartitioningPolicyTools::Base<dim, spacedim> &policy,
+ const bool keep_fine_triangulation,
+ const bool repartition_fine_triangulation)
{
std::vector<std::shared_ptr<const Triangulation<dim, spacedim>>>
coarse_grid_triangulations(fine_triangulation_in.n_global_levels());
- coarse_grid_triangulations.back().reset(&fine_triangulation_in, [](auto *) {
- // empty deleter, since fine_triangulation_in is an external field and its
- // destructor is called somewhere else
- });
-
- // for a single level nothing has to be done
- if (fine_triangulation_in.n_global_levels() == 1)
- return coarse_grid_triangulations;
-
#ifndef DEAL_II_WITH_P4EST
Assert(false, ExcNotImplemented());
(void)policy;
+ (void)keep_fine_triangulation;
+ (void)repartition_fine_triangulation;
#else
const auto fine_triangulation =
- dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
+ dynamic_cast<parallel::distributed::Triangulation<dim, spacedim> *>(
&fine_triangulation_in);
Assert(fine_triangulation, ExcNotImplemented());
parallel::distributed::Triangulation<dim, spacedim> temp_triangulation(
comm, fine_triangulation->get_mesh_smoothing());
- temp_triangulation.copy_triangulation(*fine_triangulation);
+ if (keep_fine_triangulation == true &&
+ repartition_fine_triangulation == false)
+ {
+ coarse_grid_triangulations.back().reset(&fine_triangulation_in,
+ [](auto *) {
+ // empty deleter, since
+ // fine_triangulation_in is an
+ // external field and its
+ // destructor is called
+ // somewhere else
+ });
+ }
+ else
+ {
+ // create triangulation description
+ TriangulationDescription::Description<dim, spacedim> construction_data;
+
+ if (repartition_fine_triangulation == true)
+ {
+ const auto partition = policy.partition(*fine_triangulation);
+
+ construction_data =
+ (partition.size() == 0) ?
+ TriangulationDescription::Utilities::
+ create_description_from_triangulation(*fine_triangulation,
+ comm) :
+ construction_data = TriangulationDescription::Utilities::
+ create_description_from_triangulation(*fine_triangulation,
+ partition);
+ }
+ else
+ {
+ construction_data = TriangulationDescription::Utilities::
+ create_description_from_triangulation(*fine_triangulation, comm);
+ }
+
+ // create new triangulation
+ const auto new_fine_triangulation = std::make_shared<
+ parallel::fullydistributed::Triangulation<dim, spacedim>>(comm);
+
+ for (const auto i : fine_triangulation->get_manifold_ids())
+ if (i != numbers::flat_manifold_id)
+ new_fine_triangulation->set_manifold(
+ i, fine_triangulation->get_manifold(i));
+
+ new_fine_triangulation->create_triangulation(construction_data);
+
+ // save mesh
+ coarse_grid_triangulations.back() = new_fine_triangulation;
+ }
+
+ // for a single level nothing has to be done
+ if (fine_triangulation_in.n_global_levels() == 1)
+ return coarse_grid_triangulations;
+
+ if (keep_fine_triangulation == true)
+ temp_triangulation.copy_triangulation(*fine_triangulation);
+
+ auto *temp_triangulation_ptr =
+ keep_fine_triangulation ? &temp_triangulation : fine_triangulation;
const unsigned int max_level = fine_triangulation->n_global_levels() - 1;
for (unsigned int l = max_level; l > 0; --l)
{
// coarsen mesh
- temp_triangulation.coarsen_global();
+ temp_triangulation_ptr->coarsen_global();
// perform partition
- const auto partition = policy.partition(temp_triangulation);
+ const auto partition = policy.partition(*temp_triangulation_ptr);
partition.update_ghost_values();
// create triangulation description
const auto construction_data =
partition.size() == 0 ?
TriangulationDescription::Utilities::
- create_description_from_triangulation(temp_triangulation, comm) :
+ create_description_from_triangulation(*temp_triangulation_ptr,
+ comm) :
TriangulationDescription::Utilities::
- create_description_from_triangulation(temp_triangulation,
+ create_description_from_triangulation(*temp_triangulation_ptr,
partition);
// create new triangulation
return coarse_grid_triangulations;
}
+
+
+
+ template <int dim, int spacedim>
+ std::vector<std::shared_ptr<const Triangulation<dim, spacedim>>>
+ create_geometric_coarsening_sequence(
+ const Triangulation<dim, spacedim> & fine_triangulation_in,
+ const RepartitioningPolicyTools::Base<dim, spacedim> &policy,
+ const bool repartition_fine_triangulation)
+ {
+ // remove const and convert it to flag
+ return create_geometric_coarsening_sequence(
+ const_cast<Triangulation<dim, spacedim> &>(fine_triangulation_in),
+ policy,
+ true,
+ repartition_fine_triangulation);
+ }
+
} // namespace MGTransferGlobalCoarseningTools
const Triangulation<deal_II_dimension, deal_II_space_dimension>
&fine_triangulation_in);
+ template std::vector<std::shared_ptr<
+ const Triangulation<deal_II_dimension, deal_II_space_dimension>>>
+ MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence(
+ Triangulation<deal_II_dimension, deal_II_space_dimension> &
+ fine_triangulation_in,
+ const RepartitioningPolicyTools::Base<deal_II_dimension,
+ deal_II_space_dimension> &policy,
+ const bool keep_fine_triangulation,
+ const bool repartition_fine_triangulation);
+
template std::vector<std::shared_ptr<
const Triangulation<deal_II_dimension, deal_II_space_dimension>>>
MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence(
const Triangulation<deal_II_dimension, deal_II_space_dimension>
&fine_triangulation_in,
const RepartitioningPolicyTools::Base<deal_II_dimension,
- deal_II_space_dimension> &policy);
+ deal_II_space_dimension> &policy,
+ const bool repartition_fine_triangulation);
#endif
}
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Test MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence
+// with RepartitioningPolicyTools.
+
+
+#include <deal.II/base/mpi_consensus_algorithms.h>
+
+#include <deal.II/distributed/fully_distributed_tria.h>
+#include <deal.II/distributed/repartitioning_policy_tools.h>
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/tria_description.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/data_out.h>
+
+#include "tests.h"
+
+using namespace dealii;
+
+template <int dim, int spacedim>
+void
+create_triangulation(Triangulation<dim, spacedim> &tria)
+{
+ const unsigned int n_ref_global = 3;
+ const unsigned int n_ref_local = 3;
+ GridGenerator::hyper_cube(tria, -1.0, +1.0);
+ tria.refine_global(n_ref_global);
+
+ for (unsigned int i = 0; i < n_ref_local; ++i)
+ {
+ for (auto cell : tria.active_cell_iterators())
+ if (cell->is_locally_owned())
+ {
+ bool flag = true;
+ for (unsigned int d = 0; d < dim; d++)
+ if (cell->center()[d] > 0.0)
+ flag = false;
+ if (flag)
+ cell->set_refine_flag();
+ }
+ tria.execute_coarsening_and_refinement();
+ }
+}
+
+template <int dim, int spacedim>
+void
+output_grid(const Triangulation<dim, spacedim> &tria, const std::string &label)
+{
+ deallog.push(label);
+
+ FE_Q<dim> fe(2);
+ DoFHandler<dim> dof_handler(tria);
+ dof_handler.distribute_dofs(fe);
+
+ // print statistics
+ print_statistics(tria);
+ print_statistics(dof_handler);
+
+ deallog.pop();
+}
+
+int
+main(int argc, char **argv)
+{
+ Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+ MPILogInitAll all;
+
+ const unsigned int dim = 2;
+ const MPI_Comm comm = MPI_COMM_WORLD;
+
+ const auto test = [&](const bool keep_fine_triangulation,
+ const bool repartition_fine_triangulation) {
+ parallel::distributed::Triangulation<dim> tria(comm);
+ create_triangulation(tria);
+
+ const RepartitioningPolicyTools::DefaultPolicy<dim> policy;
+
+ std::string label =
+ (keep_fine_triangulation ? std::string("true") : std::string("false")) +
+ "_" +
+ (repartition_fine_triangulation ? std::string("true") :
+ std::string("false"));
+
+ const auto trias =
+ MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence(
+ tria, policy, keep_fine_triangulation, repartition_fine_triangulation);
+ output_grid(tria, label);
+ output_grid(*trias.back(), label);
+ };
+
+ test(true, false);
+ test(true, true);
+ test(false, false);
+ test(false, true);
+}
--- /dev/null
+
+DEAL:0:true_false::n_levels: 7
+DEAL:0:true_false::n_cells: 465
+DEAL:0:true_false::n_active_cells: 349
+DEAL:0:true_false::
+DEAL:0:true_false::n_dofs: 4813
+DEAL:0:true_false::n_locally_owned_dofs: 993
+DEAL:0:true_false::
+DEAL:0:true_false::n_levels: 7
+DEAL:0:true_false::n_cells: 465
+DEAL:0:true_false::n_active_cells: 349
+DEAL:0:true_false::
+DEAL:0:true_false::n_dofs: 4813
+DEAL:0:true_false::n_locally_owned_dofs: 993
+DEAL:0:true_false::
+DEAL:0:true_true::n_levels: 7
+DEAL:0:true_true::n_cells: 465
+DEAL:0:true_true::n_active_cells: 349
+DEAL:0:true_true::
+DEAL:0:true_true::n_dofs: 4813
+DEAL:0:true_true::n_locally_owned_dofs: 993
+DEAL:0:true_true::
+DEAL:0:true_true::n_levels: 7
+DEAL:0:true_true::n_cells: 465
+DEAL:0:true_true::n_active_cells: 349
+DEAL:0:true_true::
+DEAL:0:true_true::n_dofs: 4813
+DEAL:0:true_true::n_locally_owned_dofs: 993
+DEAL:0:true_true::
+DEAL:0:false_false::n_levels: 1
+DEAL:0:false_false::n_cells: 1
+DEAL:0:false_false::n_active_cells: 1
+DEAL:0:false_false::
+DEAL:0:false_false::n_dofs: 9
+DEAL:0:false_false::n_locally_owned_dofs: 0
+DEAL:0:false_false::
+DEAL:0:false_false::n_levels: 7
+DEAL:0:false_false::n_cells: 465
+DEAL:0:false_false::n_active_cells: 349
+DEAL:0:false_false::
+DEAL:0:false_false::n_dofs: 4813
+DEAL:0:false_false::n_locally_owned_dofs: 993
+DEAL:0:false_false::
+DEAL:0:false_true::n_levels: 1
+DEAL:0:false_true::n_cells: 1
+DEAL:0:false_true::n_active_cells: 1
+DEAL:0:false_true::
+DEAL:0:false_true::n_dofs: 9
+DEAL:0:false_true::n_locally_owned_dofs: 0
+DEAL:0:false_true::
+DEAL:0:false_true::n_levels: 7
+DEAL:0:false_true::n_cells: 465
+DEAL:0:false_true::n_active_cells: 349
+DEAL:0:false_true::
+DEAL:0:false_true::n_dofs: 4813
+DEAL:0:false_true::n_locally_owned_dofs: 993
+DEAL:0:false_true::
+
+DEAL:1:true_false::n_levels: 7
+DEAL:1:true_false::n_cells: 577
+DEAL:1:true_false::n_active_cells: 433
+DEAL:1:true_false::
+DEAL:1:true_false::n_dofs: 4813
+DEAL:1:true_false::n_locally_owned_dofs: 944
+DEAL:1:true_false::
+DEAL:1:true_false::n_levels: 7
+DEAL:1:true_false::n_cells: 577
+DEAL:1:true_false::n_active_cells: 433
+DEAL:1:true_false::
+DEAL:1:true_false::n_dofs: 4813
+DEAL:1:true_false::n_locally_owned_dofs: 944
+DEAL:1:true_false::
+DEAL:1:true_true::n_levels: 7
+DEAL:1:true_true::n_cells: 577
+DEAL:1:true_true::n_active_cells: 433
+DEAL:1:true_true::
+DEAL:1:true_true::n_dofs: 4813
+DEAL:1:true_true::n_locally_owned_dofs: 944
+DEAL:1:true_true::
+DEAL:1:true_true::n_levels: 7
+DEAL:1:true_true::n_cells: 577
+DEAL:1:true_true::n_active_cells: 433
+DEAL:1:true_true::
+DEAL:1:true_true::n_dofs: 4813
+DEAL:1:true_true::n_locally_owned_dofs: 944
+DEAL:1:true_true::
+DEAL:1:false_false::n_levels: 1
+DEAL:1:false_false::n_cells: 1
+DEAL:1:false_false::n_active_cells: 1
+DEAL:1:false_false::
+DEAL:1:false_false::n_dofs: 9
+DEAL:1:false_false::n_locally_owned_dofs: 0
+DEAL:1:false_false::
+DEAL:1:false_false::n_levels: 7
+DEAL:1:false_false::n_cells: 577
+DEAL:1:false_false::n_active_cells: 433
+DEAL:1:false_false::
+DEAL:1:false_false::n_dofs: 4813
+DEAL:1:false_false::n_locally_owned_dofs: 944
+DEAL:1:false_false::
+DEAL:1:false_true::n_levels: 1
+DEAL:1:false_true::n_cells: 1
+DEAL:1:false_true::n_active_cells: 1
+DEAL:1:false_true::
+DEAL:1:false_true::n_dofs: 9
+DEAL:1:false_true::n_locally_owned_dofs: 0
+DEAL:1:false_true::
+DEAL:1:false_true::n_levels: 7
+DEAL:1:false_true::n_cells: 577
+DEAL:1:false_true::n_active_cells: 433
+DEAL:1:false_true::
+DEAL:1:false_true::n_dofs: 4813
+DEAL:1:false_true::n_locally_owned_dofs: 944
+DEAL:1:false_true::
+
+
+DEAL:2:true_false::n_levels: 7
+DEAL:2:true_false::n_cells: 665
+DEAL:2:true_false::n_active_cells: 499
+DEAL:2:true_false::
+DEAL:2:true_false::n_dofs: 4813
+DEAL:2:true_false::n_locally_owned_dofs: 960
+DEAL:2:true_false::
+DEAL:2:true_false::n_levels: 7
+DEAL:2:true_false::n_cells: 665
+DEAL:2:true_false::n_active_cells: 499
+DEAL:2:true_false::
+DEAL:2:true_false::n_dofs: 4813
+DEAL:2:true_false::n_locally_owned_dofs: 960
+DEAL:2:true_false::
+DEAL:2:true_true::n_levels: 7
+DEAL:2:true_true::n_cells: 665
+DEAL:2:true_true::n_active_cells: 499
+DEAL:2:true_true::
+DEAL:2:true_true::n_dofs: 4813
+DEAL:2:true_true::n_locally_owned_dofs: 960
+DEAL:2:true_true::
+DEAL:2:true_true::n_levels: 7
+DEAL:2:true_true::n_cells: 665
+DEAL:2:true_true::n_active_cells: 499
+DEAL:2:true_true::
+DEAL:2:true_true::n_dofs: 4813
+DEAL:2:true_true::n_locally_owned_dofs: 960
+DEAL:2:true_true::
+DEAL:2:false_false::n_levels: 1
+DEAL:2:false_false::n_cells: 1
+DEAL:2:false_false::n_active_cells: 1
+DEAL:2:false_false::
+DEAL:2:false_false::n_dofs: 9
+DEAL:2:false_false::n_locally_owned_dofs: 0
+DEAL:2:false_false::
+DEAL:2:false_false::n_levels: 7
+DEAL:2:false_false::n_cells: 665
+DEAL:2:false_false::n_active_cells: 499
+DEAL:2:false_false::
+DEAL:2:false_false::n_dofs: 4813
+DEAL:2:false_false::n_locally_owned_dofs: 960
+DEAL:2:false_false::
+DEAL:2:false_true::n_levels: 1
+DEAL:2:false_true::n_cells: 1
+DEAL:2:false_true::n_active_cells: 1
+DEAL:2:false_true::
+DEAL:2:false_true::n_dofs: 9
+DEAL:2:false_true::n_locally_owned_dofs: 0
+DEAL:2:false_true::
+DEAL:2:false_true::n_levels: 7
+DEAL:2:false_true::n_cells: 665
+DEAL:2:false_true::n_active_cells: 499
+DEAL:2:false_true::
+DEAL:2:false_true::n_dofs: 4813
+DEAL:2:false_true::n_locally_owned_dofs: 960
+DEAL:2:false_true::
+
+
+DEAL:3:true_false::n_levels: 7
+DEAL:3:true_false::n_cells: 657
+DEAL:3:true_false::n_active_cells: 493
+DEAL:3:true_false::
+DEAL:3:true_false::n_dofs: 4813
+DEAL:3:true_false::n_locally_owned_dofs: 912
+DEAL:3:true_false::
+DEAL:3:true_false::n_levels: 7
+DEAL:3:true_false::n_cells: 657
+DEAL:3:true_false::n_active_cells: 493
+DEAL:3:true_false::
+DEAL:3:true_false::n_dofs: 4813
+DEAL:3:true_false::n_locally_owned_dofs: 912
+DEAL:3:true_false::
+DEAL:3:true_true::n_levels: 7
+DEAL:3:true_true::n_cells: 657
+DEAL:3:true_true::n_active_cells: 493
+DEAL:3:true_true::
+DEAL:3:true_true::n_dofs: 4813
+DEAL:3:true_true::n_locally_owned_dofs: 912
+DEAL:3:true_true::
+DEAL:3:true_true::n_levels: 7
+DEAL:3:true_true::n_cells: 657
+DEAL:3:true_true::n_active_cells: 493
+DEAL:3:true_true::
+DEAL:3:true_true::n_dofs: 4813
+DEAL:3:true_true::n_locally_owned_dofs: 912
+DEAL:3:true_true::
+DEAL:3:false_false::n_levels: 1
+DEAL:3:false_false::n_cells: 1
+DEAL:3:false_false::n_active_cells: 1
+DEAL:3:false_false::
+DEAL:3:false_false::n_dofs: 9
+DEAL:3:false_false::n_locally_owned_dofs: 0
+DEAL:3:false_false::
+DEAL:3:false_false::n_levels: 7
+DEAL:3:false_false::n_cells: 657
+DEAL:3:false_false::n_active_cells: 493
+DEAL:3:false_false::
+DEAL:3:false_false::n_dofs: 4813
+DEAL:3:false_false::n_locally_owned_dofs: 912
+DEAL:3:false_false::
+DEAL:3:false_true::n_levels: 1
+DEAL:3:false_true::n_cells: 1
+DEAL:3:false_true::n_active_cells: 1
+DEAL:3:false_true::
+DEAL:3:false_true::n_dofs: 9
+DEAL:3:false_true::n_locally_owned_dofs: 0
+DEAL:3:false_true::
+DEAL:3:false_true::n_levels: 7
+DEAL:3:false_true::n_cells: 657
+DEAL:3:false_true::n_active_cells: 493
+DEAL:3:false_true::
+DEAL:3:false_true::n_dofs: 4813
+DEAL:3:false_true::n_locally_owned_dofs: 912
+DEAL:3:false_true::
+
+
+DEAL:4:true_false::n_levels: 7
+DEAL:4:true_false::n_cells: 541
+DEAL:4:true_false::n_active_cells: 406
+DEAL:4:true_false::
+DEAL:4:true_false::n_dofs: 4813
+DEAL:4:true_false::n_locally_owned_dofs: 1004
+DEAL:4:true_false::
+DEAL:4:true_false::n_levels: 7
+DEAL:4:true_false::n_cells: 541
+DEAL:4:true_false::n_active_cells: 406
+DEAL:4:true_false::
+DEAL:4:true_false::n_dofs: 4813
+DEAL:4:true_false::n_locally_owned_dofs: 1004
+DEAL:4:true_false::
+DEAL:4:true_true::n_levels: 7
+DEAL:4:true_true::n_cells: 541
+DEAL:4:true_true::n_active_cells: 406
+DEAL:4:true_true::
+DEAL:4:true_true::n_dofs: 4813
+DEAL:4:true_true::n_locally_owned_dofs: 1004
+DEAL:4:true_true::
+DEAL:4:true_true::n_levels: 7
+DEAL:4:true_true::n_cells: 541
+DEAL:4:true_true::n_active_cells: 406
+DEAL:4:true_true::
+DEAL:4:true_true::n_dofs: 4813
+DEAL:4:true_true::n_locally_owned_dofs: 1004
+DEAL:4:true_true::
+DEAL:4:false_false::n_levels: 1
+DEAL:4:false_false::n_cells: 1
+DEAL:4:false_false::n_active_cells: 1
+DEAL:4:false_false::
+DEAL:4:false_false::n_dofs: 9
+DEAL:4:false_false::n_locally_owned_dofs: 9
+DEAL:4:false_false::
+DEAL:4:false_false::n_levels: 7
+DEAL:4:false_false::n_cells: 541
+DEAL:4:false_false::n_active_cells: 406
+DEAL:4:false_false::
+DEAL:4:false_false::n_dofs: 4813
+DEAL:4:false_false::n_locally_owned_dofs: 1004
+DEAL:4:false_false::
+DEAL:4:false_true::n_levels: 1
+DEAL:4:false_true::n_cells: 1
+DEAL:4:false_true::n_active_cells: 1
+DEAL:4:false_true::
+DEAL:4:false_true::n_dofs: 9
+DEAL:4:false_true::n_locally_owned_dofs: 9
+DEAL:4:false_true::
+DEAL:4:false_true::n_levels: 7
+DEAL:4:false_true::n_cells: 541
+DEAL:4:false_true::n_active_cells: 406
+DEAL:4:false_true::
+DEAL:4:false_true::n_dofs: 4813
+DEAL:4:false_true::n_locally_owned_dofs: 1004
+DEAL:4:false_true::
+