From: Peter Munch Date: Sun, 30 May 2021 10:58:05 +0000 (+0200) Subject: MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence(): make it... X-Git-Tag: v9.4.0-rc1~1276^2 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea917d47bcf5c7fded1f2e3a3122ae4b1b504ec9;p=dealii.git MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence(): make it optional to coarsen input tria --- diff --git a/include/deal.II/multigrid/mg_transfer_global_coarsening.h b/include/deal.II/multigrid/mg_transfer_global_coarsening.h index e8df694e2c..9187abc515 100644 --- a/include/deal.II/multigrid/mg_transfer_global_coarsening.h +++ b/include/deal.II/multigrid/mg_transfer_global_coarsening.h @@ -110,7 +110,13 @@ namespace MGTransferGlobalCoarseningTools /** * 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. @@ -120,9 +126,23 @@ namespace MGTransferGlobalCoarseningTools */ template std::vector>> + create_geometric_coarsening_sequence( + Triangulation & tria, + const RepartitioningPolicyTools::Base &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 + std::vector>> create_geometric_coarsening_sequence( const Triangulation & tria, - const RepartitioningPolicyTools::Base &policy); + const RepartitioningPolicyTools::Base &policy, + const bool repartition_fine_triangulation = false); } // namespace MGTransferGlobalCoarseningTools diff --git a/include/deal.II/multigrid/mg_transfer_global_coarsening.templates.h b/include/deal.II/multigrid/mg_transfer_global_coarsening.templates.h index a0106055b2..a035af2fba 100644 --- a/include/deal.II/multigrid/mg_transfer_global_coarsening.templates.h +++ b/include/deal.II/multigrid/mg_transfer_global_coarsening.templates.h @@ -2317,27 +2317,22 @@ namespace MGTransferGlobalCoarseningTools template std::vector>> create_geometric_coarsening_sequence( - const Triangulation & fine_triangulation_in, - const RepartitioningPolicyTools::Base &policy) + Triangulation & fine_triangulation_in, + const RepartitioningPolicyTools::Base &policy, + const bool keep_fine_triangulation, + const bool repartition_fine_triangulation) { std::vector>> 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 *>( + dynamic_cast *>( &fine_triangulation_in); Assert(fine_triangulation, ExcNotImplemented()); @@ -2347,7 +2342,66 @@ namespace MGTransferGlobalCoarseningTools parallel::distributed::Triangulation 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 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>(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; @@ -2355,19 +2409,20 @@ namespace MGTransferGlobalCoarseningTools 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 @@ -2388,6 +2443,24 @@ namespace MGTransferGlobalCoarseningTools return coarse_grid_triangulations; } + + + + template + std::vector>> + create_geometric_coarsening_sequence( + const Triangulation & fine_triangulation_in, + const RepartitioningPolicyTools::Base &policy, + const bool repartition_fine_triangulation) + { + // remove const and convert it to flag + return create_geometric_coarsening_sequence( + const_cast &>(fine_triangulation_in), + policy, + true, + repartition_fine_triangulation); + } + } // namespace MGTransferGlobalCoarseningTools diff --git a/source/multigrid/mg_transfer_global_coarsening.inst.in b/source/multigrid/mg_transfer_global_coarsening.inst.in index 45edf3be50..e9a9eb71d7 100644 --- a/source/multigrid/mg_transfer_global_coarsening.inst.in +++ b/source/multigrid/mg_transfer_global_coarsening.inst.in @@ -30,12 +30,23 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) const Triangulation &fine_triangulation_in); + template std::vector>> + MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence( + Triangulation & + fine_triangulation_in, + const RepartitioningPolicyTools::Base &policy, + const bool keep_fine_triangulation, + const bool repartition_fine_triangulation); + template std::vector>> MGTransferGlobalCoarseningTools::create_geometric_coarsening_sequence( const Triangulation &fine_triangulation_in, const RepartitioningPolicyTools::Base &policy); + deal_II_space_dimension> &policy, + const bool repartition_fine_triangulation); #endif } diff --git a/tests/fullydistributed_grids/repartitioning_04.cc b/tests/fullydistributed_grids/repartitioning_04.cc new file mode 100644 index 0000000000..2256bbfb03 --- /dev/null +++ b/tests/fullydistributed_grids/repartitioning_04.cc @@ -0,0 +1,119 @@ +// --------------------------------------------------------------------- +// +// 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 + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +#include "tests.h" + +using namespace dealii; + +template +void +create_triangulation(Triangulation &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 +void +output_grid(const Triangulation &tria, const std::string &label) +{ + deallog.push(label); + + FE_Q fe(2); + DoFHandler 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 tria(comm); + create_triangulation(tria); + + const RepartitioningPolicyTools::DefaultPolicy 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); +} diff --git a/tests/fullydistributed_grids/repartitioning_04.mpirun=5.output b/tests/fullydistributed_grids/repartitioning_04.mpirun=5.output new file mode 100644 index 0000000000..6aba998567 --- /dev/null +++ b/tests/fullydistributed_grids/repartitioning_04.mpirun=5.output @@ -0,0 +1,289 @@ + +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:: +