From 2d0daceb8bfccdfabcfba1d7f079e9789c09ea55 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Wed, 24 Feb 2021 11:22:33 -0700 Subject: [PATCH] Bugfix: DoFHandler connected to Triangulation::Signals only in hp-mode. --- include/deal.II/dofs/dof_handler.h | 12 +- source/distributed/solution_transfer.cc | 7 ++ source/dofs/dof_handler.cc | 58 +++++---- tests/dofs/clear_signal.cc | 118 ++++++++++++++++++ ...h_mpi=true.with_p4est=true.mpirun=1.output | 5 + .../solution_transfer_01.cc | 1 + 6 files changed, 176 insertions(+), 25 deletions(-) create mode 100644 tests/dofs/clear_signal.cc create mode 100644 tests/dofs/clear_signal.with_mpi=true.with_p4est=true.mpirun=1.output diff --git a/include/deal.II/dofs/dof_handler.h b/include/deal.II/dofs/dof_handler.h index 99601c45c7..d3dd609226 100644 --- a/include/deal.II/dofs/dof_handler.h +++ b/include/deal.II/dofs/dof_handler.h @@ -1666,6 +1666,13 @@ private: */ std::vector tria_listeners; + /** + * A list of connections with which this object connects to the + * triangulation. They get triggered specifially when data needs to be + * transferred due to refinement or repartitioning. Only active in hp-mode. + */ + std::vector tria_listeners_for_transfer; + /** * Free all memory used for non-multigrid data structures. */ @@ -1700,14 +1707,13 @@ private: const types::global_dof_index global_index) const; /** - * Setup DoFHandler policy. + * Set up DoFHandler policy. */ void setup_policy(); /** - * Setup connections to refinement signals of the underlying triangulation. - * Necessary for the hp-mode. + * Set up connections to signals of the underlying triangulation. */ void connect_to_triangulation_signals(); diff --git a/source/distributed/solution_transfer.cc b/source/distributed/solution_transfer.cc index 6f8ac3e08f..50104891cd 100644 --- a/source/distributed/solution_transfer.cc +++ b/source/distributed/solution_transfer.cc @@ -137,6 +137,10 @@ namespace parallel prepare_for_coarsening_and_refinement( const std::vector &all_in) { + for (unsigned int i = 0; i < all_in.size(); ++i) + Assert(all_in[i]->size() == dof_handler->n_dofs(), + ExcDimensionMismatch(all_in[i]->size(), dof_handler->n_dofs())); + input_vectors = all_in; register_data_attach(); } @@ -230,6 +234,9 @@ namespace parallel { Assert(input_vectors.size() == all_out.size(), ExcDimensionMismatch(input_vectors.size(), all_out.size())); + for (unsigned int i = 0; i < all_out.size(); ++i) + Assert(all_out[i]->size() == dof_handler->n_dofs(), + ExcDimensionMismatch(all_out[i]->size(), dof_handler->n_dofs())); // TODO: casting away constness is bad auto *tria = (dynamic_cast::DoFHandler(const Triangulation &tria) template DoFHandler::~DoFHandler() { - // unsubscribe all attachments to refinement signals of the underlying - // triangulation + // unsubscribe all attachments to signals of the underlying triangulation for (auto &connection : this->tria_listeners) connection.disconnect(); this->tria_listeners.clear(); + for (auto &connection : this->tria_listeners_for_transfer) + connection.disconnect(); + this->tria_listeners_for_transfer.clear(); + // release allocated memory // virtual functions called in constructors and destructors never use the // override in a derived class @@ -2052,6 +2055,10 @@ DoFHandler::reinit(const Triangulation &tria) connection.disconnect(); this->tria_listeners.clear(); + for (auto &connection : this->tria_listeners_for_transfer) + connection.disconnect(); + this->tria_listeners_for_transfer.clear(); + // release allocated memory and policy DoFHandler::clear(); this->policy.reset(); @@ -2431,10 +2438,11 @@ DoFHandler::set_fe(const hp::FECollection &ff) { hp_capability_enabled = false; - // unsubscribe connections to signals - for (auto &connection : this->tria_listeners) + // unsubscribe connections to signals that are only relevant for + // hp-mode, since we only have a single element here + for (auto &connection : this->tria_listeners_for_transfer) connection.disconnect(); - this->tria_listeners.clear(); + this->tria_listeners_for_transfer.clear(); // release active and future finite element tables this->hp_cell_active_fe_indices.clear(); @@ -2510,10 +2518,11 @@ DoFHandler::distribute_dofs( { hp_capability_enabled = false; - // unsubscribe connections to signals - for (auto &connection : this->tria_listeners) + // unsubscribe connections to signals that are only relevant for + // hp-mode, since we only have a single element here + for (auto &connection : this->tria_listeners_for_transfer) connection.disconnect(); - this->tria_listeners.clear(); + this->tria_listeners_for_transfer.clear(); // release active and future finite element tables this->hp_cell_active_fe_indices.clear(); @@ -3025,6 +3034,9 @@ template void DoFHandler::connect_to_triangulation_signals() { + // make sure this is called during initialization in hp-mode + Assert(hp_capability_enabled, ExcOnlyAvailableWithHP()); + // connect functions to signals of the underlying triangulation this->tria_listeners.push_back(this->tria->signals.create.connect( [this]() { this->reinit(*(this->tria)); })); @@ -3038,31 +3050,31 @@ DoFHandler::connect_to_triangulation_signals() &this->get_triangulation())) { // repartitioning signals - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.pre_distributed_repartition.connect([this]() { internal::hp::DoFHandlerImplementation::Implementation:: ensure_absence_of_future_fe_indices(*this); })); - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.pre_distributed_repartition.connect( [this]() { this->pre_distributed_transfer_action(); })); - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.post_distributed_repartition.connect( [this] { this->post_distributed_transfer_action(); })); // refinement signals - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.pre_distributed_refinement.connect( [this]() { this->pre_distributed_transfer_action(); })); - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.post_distributed_refinement.connect( [this]() { this->post_distributed_transfer_action(); })); // serialization signals - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.post_distributed_save.connect( [this]() { this->active_fe_index_transfer.reset(); })); - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.post_distributed_load.connect( [this]() { this->update_active_fe_table(); })); } @@ -3071,25 +3083,27 @@ DoFHandler::connect_to_triangulation_signals() &this->get_triangulation()) != nullptr) { // partitioning signals - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( this->tria->signals.pre_partition.connect([this]() { internal::hp::DoFHandlerImplementation::Implementation:: ensure_absence_of_future_fe_indices(*this); })); // refinement signals - this->tria_listeners.push_back(this->tria->signals.pre_refinement.connect( - [this] { this->pre_transfer_action(); })); - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( + this->tria->signals.pre_refinement.connect( + [this] { this->pre_transfer_action(); })); + this->tria_listeners_for_transfer.push_back( this->tria->signals.post_refinement.connect( [this] { this->post_transfer_action(); })); } else { // refinement signals - this->tria_listeners.push_back(this->tria->signals.pre_refinement.connect( - [this] { this->pre_transfer_action(); })); - this->tria_listeners.push_back( + this->tria_listeners_for_transfer.push_back( + this->tria->signals.pre_refinement.connect( + [this] { this->pre_transfer_action(); })); + this->tria_listeners_for_transfer.push_back( this->tria->signals.post_refinement.connect( [this] { this->post_transfer_action(); })); } diff --git a/tests/dofs/clear_signal.cc b/tests/dofs/clear_signal.cc new file mode 100644 index 0000000000..1ed76cb039 --- /dev/null +++ b/tests/dofs/clear_signal.cc @@ -0,0 +1,118 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2020 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. +// +// --------------------------------------------------------------------- + + + +// check that DoFHandler::clear() will be called +// whenever Triangulation::Signals::clear is triggered + + +#include +#include +#include + +#include + +#include + +#include +#include + +#include "../tests.h" + + +void +test_serial() +{ + constexpr const unsigned dim = 2; + + Triangulation tria; + GridGenerator::hyper_cube(tria); + + DoFHandler dh(tria); + dh.distribute_dofs(FE_Q(1)); + + tria.clear(); + deallog << "ndofs:" << dh.n_dofs() << std::endl; +} + + +void +test_parallel_shared() +{ + constexpr const unsigned dim = 2; + + parallel::shared::Triangulation tria(MPI_COMM_WORLD); + GridGenerator::hyper_cube(tria); + + DoFHandler dh(tria); + dh.distribute_dofs(FE_Q(1)); + + tria.clear(); + deallog << "ndofs:" << dh.n_dofs() << std::endl; +} + + +void +test_parallel_distributed() +{ + constexpr const unsigned dim = 2; + + parallel::distributed::Triangulation tria(MPI_COMM_WORLD); + GridGenerator::hyper_cube(tria); + + DoFHandler dh(tria); + dh.distribute_dofs(FE_Q(1)); + + tria.clear(); + deallog << "ndofs:" << dh.n_dofs() << std::endl; +} + + +void +test_parallel_fullydistributed() +{ + constexpr const unsigned dim = 2; + + parallel::distributed::Triangulation tria_base(MPI_COMM_WORLD); + GridGenerator::hyper_cube(tria_base); + + const auto description = + TriangulationDescription::Utilities::create_description_from_triangulation( + tria_base, MPI_COMM_WORLD); + + parallel::fullydistributed::Triangulation tria(MPI_COMM_WORLD); + tria.create_triangulation(description); + + DoFHandler dh(tria); + dh.distribute_dofs(FE_Q(1)); + + tria.clear(); + deallog << "ndofs:" << dh.n_dofs() << std::endl; +} + + +int +main(int argc, char *argv[]) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + test_serial(); + test_parallel_shared(); + test_parallel_distributed(); + test_parallel_fullydistributed(); +} diff --git a/tests/dofs/clear_signal.with_mpi=true.with_p4est=true.mpirun=1.output b/tests/dofs/clear_signal.with_mpi=true.with_p4est=true.mpirun=1.output new file mode 100644 index 0000000000..6c2ac32c44 --- /dev/null +++ b/tests/dofs/clear_signal.with_mpi=true.with_p4est=true.mpirun=1.output @@ -0,0 +1,5 @@ + +DEAL::ndofs:0 +DEAL::ndofs:0 +DEAL::ndofs:0 +DEAL::ndofs:0 diff --git a/tests/fullydistributed_grids/solution_transfer_01.cc b/tests/fullydistributed_grids/solution_transfer_01.cc index 1750f1a1c1..0aedae0de2 100644 --- a/tests/fullydistributed_grids/solution_transfer_01.cc +++ b/tests/fullydistributed_grids/solution_transfer_01.cc @@ -89,6 +89,7 @@ test(TriangulationType &triangulation) { triangulation.load(filename); + dof_handler.distribute_dofs(FE_Q(2)); parallel::distributed::SolutionTransfer solution_transfer( dof_handler); -- 2.39.5