diff --git a/cpp/dolfinx/common/Scatterer.h b/cpp/dolfinx/common/Scatterer.h index 2efb61f6c3..f1af073b21 100644 --- a/cpp/dolfinx/common/Scatterer.h +++ b/cpp/dolfinx/common/Scatterer.h @@ -294,7 +294,7 @@ class Scatterer for (std::size_t i = 0; i < _src.size(); ++i) { int ierr = MPI_Irecv(recv_buffer + _displs_remote[i], _sizes_remote[i], - dolfinx::MPI::mpi_t, _src[i], MPI_ANY_TAG, + dolfinx::MPI::mpi_t, _src[i], p2p_tag_fwd, _comm0.comm(), &requests[i]); dolfinx::MPI::check_error(_comm0.comm(), ierr); } @@ -302,8 +302,8 @@ class Scatterer for (std::size_t i = 0; i < _dest.size(); ++i) { int ierr = MPI_Isend(send_buffer + _displs_local[i], _sizes_local[i], - dolfinx::MPI::mpi_t, _dest[i], 0, _comm0.comm(), - &requests[i + _src.size()]); + dolfinx::MPI::mpi_t, _dest[i], p2p_tag_fwd, + _comm0.comm(), &requests[i + _src.size()]); dolfinx::MPI::check_error(_comm0.comm(), ierr); } } @@ -380,7 +380,7 @@ class Scatterer for (std::size_t i = 0; i < _dest.size(); i++) { int ierr = MPI_Irecv(recv_buffer + _displs_local[i], _sizes_local[i], - dolfinx::MPI::mpi_t, _dest[i], MPI_ANY_TAG, + dolfinx::MPI::mpi_t, _dest[i], p2p_tag_rev, _comm0.comm(), &requests[i]); dolfinx::MPI::check_error(_comm0.comm(), ierr); } @@ -390,8 +390,8 @@ class Scatterer for (std::size_t i = 0; i < _src.size(); i++) { int ierr = MPI_Isend(send_buffer + _displs_remote[i], _sizes_remote[i], - dolfinx::MPI::mpi_t, _src[i], 0, _comm0.comm(), - &requests[i + _dest.size()]); + dolfinx::MPI::mpi_t, _src[i], p2p_tag_rev, + _comm0.comm(), &requests[i + _dest.size()]); dolfinx::MPI::check_error(_comm0.comm(), ierr); } } @@ -495,6 +495,14 @@ class Scatterer } private: + // MPI tags for point-to-point forward/reverse scatter messages. + // Both directions share communicator _comm0, so a fixed, distinct + // tag per direction is required to stop a forward message being + // matched against a reverse receive (or vice versa) irrespective of + // the relative order in which the two directions are posted. + static constexpr int p2p_tag_fwd = 0; + static constexpr int p2p_tag_rev = 1; + // Communicator where the source ranks own the indices in the callers // halo, and the destination ranks 'ghost' indices owned by the // caller. I.e., diff --git a/cpp/dolfinx/fem/Function.h b/cpp/dolfinx/fem/Function.h index bc8e2eb58f..e84702d181 100644 --- a/cpp/dolfinx/fem/Function.h +++ b/cpp/dolfinx/fem/Function.h @@ -55,9 +55,7 @@ class Function /// @brief Create function on given function space. /// @param[in] V The function space explicit Function(std::shared_ptr> V) - : _function_space(V), _x(std::make_shared>( - V->dofmaps().front()->index_map, - V->dofmaps().front()->index_map_bs())) + : _function_space(V), _x(std::make_shared>(*V)) { if (!V->component().empty()) { @@ -122,8 +120,7 @@ class Function auto [V, map] = _function_space->collapse(); // Create new vector - auto x = std::make_shared>( - V.dofmap()->index_map, V.dofmap()->index_map_bs()); + auto x = std::make_shared>(V); // Copy values into new vector std::span x_old = _x->array(); diff --git a/cpp/dolfinx/fem/FunctionSpace.h b/cpp/dolfinx/fem/FunctionSpace.h index 81d30e3f6d..f84d86d595 100644 --- a/cpp/dolfinx/fem/FunctionSpace.h +++ b/cpp/dolfinx/fem/FunctionSpace.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,10 @@ namespace dolfinx::fem /// degrees-of-freedom. /// @tparam T The floating point (real) type of the mesh geometry and /// the finite element basis. -template +/// @tparam ScatterT Scatterer type used to scatter/gather dof data +/// between the local (owned + ghost) and global dof layouts. +template >> class FunctionSpace { public: @@ -45,6 +49,8 @@ class FunctionSpace std::shared_ptr> element, std::shared_ptr dofmap) : _mesh(mesh), _elements{element}, _dofmaps{std::move(dofmap)}, + _scatterer(std::make_shared( + *_dofmaps.front()->index_map, _dofmaps.front()->index_map_bs())), _id(boost::uuids::random_generator()()), _root_space_id(_id) { // Do nothing @@ -63,6 +69,8 @@ class FunctionSpace std::vector>> elements, std::vector> dofmaps) : _mesh(mesh), _elements(elements), _dofmaps(std::move(dofmaps)), + _scatterer(std::make_shared( + *_dofmaps.front()->index_map, _dofmaps.front()->index_map_bs())), _id(boost::uuids::random_generator()()), _root_space_id(_id) { std::vector cell_types = mesh->topology()->cell_types(); @@ -400,6 +408,12 @@ class FunctionSpace return _dofmaps; } + /// @brief The scatterer associated with the function space. + /// + /// Used to scatter data between the local (owned + ghost) dof layout + /// and the global layout. + std::shared_ptr scatterer() const { return _scatterer; } + private: // The mesh std::shared_ptr> _mesh; @@ -410,6 +424,10 @@ class FunctionSpace // The dofmap std::vector> _dofmaps; + // An associated scatterer for the function space. This is used to scatter + // data from the local dof layout to the global dof layout and vice versa. + std::shared_ptr _scatterer; + // The component w.r.t. to root space std::vector _component; diff --git a/cpp/dolfinx/fem/assembler.h b/cpp/dolfinx/fem/assembler.h index b9259b8da4..0e6199562b 100644 --- a/cpp/dolfinx/fem/assembler.h +++ b/cpp/dolfinx/fem/assembler.h @@ -37,8 +37,6 @@ template class Expression; template class Form; -template -class FunctionSpace; /// @brief Evaluate an Expression on cells or facets. /// diff --git a/cpp/dolfinx/io/vtk_utils.h b/cpp/dolfinx/io/vtk_utils.h index 001c2b6ed5..b4578408eb 100644 --- a/cpp/dolfinx/io/vtk_utils.h +++ b/cpp/dolfinx/io/vtk_utils.h @@ -26,12 +26,6 @@ namespace dolfinx { -namespace fem -{ -template -class FunctionSpace; -} - namespace mesh { enum class CellType : std::int8_t; diff --git a/cpp/dolfinx/la/Vector.h b/cpp/dolfinx/la/Vector.h index faafa47991..2dce824fcd 100644 --- a/cpp/dolfinx/la/Vector.h +++ b/cpp/dolfinx/la/Vector.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,12 @@ #include #include +namespace dolfinx::fem +{ +template +class FunctionSpace; +} // namespace dolfinx::fem + namespace dolfinx::la { /// @brief la::Vector scatter pack/unpack function concept. @@ -137,6 +144,22 @@ class Vector { } + /// @brief Create a distributed vector from a FunctionSpace, inheriting a + /// shared Scatterer. + /// @tparam U Floating point (geometry) type of the FunctionSpace. + /// @param V FunctionSpace defining the block size and dofmap layout of the + /// vector, and sharing a common Scatterer. + template + explicit Vector( + const fem::FunctionSpace>& V) + : _map(V.dofmap()->index_map), _bs(V.dofmap()->index_map_bs()), + _x(_bs * (_map->size_local() + _map->num_ghosts())), + _scatterer(V.scatterer()), + _buffer_local(_scatterer->local_indices().size()), + _buffer_remote(_scatterer->remote_indices().size()) + { + } + /// Copy constructor Vector(const Vector& x) = default;