diff --git a/dumux/linear/amgbackend.hh b/dumux/linear/amgbackend.hh index 518f926de64dcda35cfd4853ea66c1833aede5d6..1f35a28577da375dc1c14c43a4abfd6ea3b88582 100644 --- a/dumux/linear/amgbackend.hh +++ b/dumux/linear/amgbackend.hh @@ -134,12 +134,18 @@ public: template<class Matrix, class Vector> bool solve(Matrix& A, Vector& x, Vector& b) { - int rank = 0; std::shared_ptr<Comm> comm; std::shared_ptr<LinearOperator> fop; std::shared_ptr<ScalarProduct> sp; - static const bool isParallel = AmgTraits::isParallel; - prepareLinearAlgebra_<Matrix, Vector, isParallel>(A, b, rank, comm, fop, sp); + +#if HAVE_MPI + if constexpr (AmgTraits::isParallel) + prepareLinearAlgebraParallel<AmgTraits>(A, b, comm, fop, sp, *phelper_, firstCall_); + else + prepareLinearAlgebraSequential<AmgTraits>(A, comm, fop, sp); +#else + prepareLinearAlgebraSequential<AmgTraits>(A, comm, fop, sp); +#endif using SmootherArgs = typename Dune::Amg::SmootherTraits<Smoother>::Arguments; using Criterion = Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<BCRSMat, Dune::Amg::FirstDiagonal>>; @@ -156,7 +162,7 @@ public: AMGType amg(*fop, criterion, smootherArgs, *comm); Dune::BiCGSTABSolver<VType> solver(*fop, *sp, amg, this->residReduction(), this->maxIter(), - rank == 0 ? this->verbosity() : 0); + comm->communicator().rank() == 0 ? this->verbosity() : 0); solver.apply(x, b, result_); firstCall_ = false; @@ -181,34 +187,6 @@ public: private: - /*! - * \brief Prepare the linear algebra member variables. - * - * At compile time, correct constructor calls have to be chosen, - * depending on whether the setting is parallel or sequential. - * Since several template parameters are present, this cannot be solved - * by a full function template specialization. Instead, class template - * specialization has to be used. - * This adapts example 4 from http://www.gotw.ca/publications/mill17.htm. - - * The function is called from the solve function. The call is - * forwarded to the corresponding function of a class template. - * - * \tparam Matrix the matrix type - * \tparam Vector the vector type - * \tparam isParallel decides if the setting is parallel or sequential - */ - template<class Matrix, class Vector, bool isParallel> - void prepareLinearAlgebra_(Matrix& A, Vector& b, int& rank, - std::shared_ptr<Comm>& comm, - std::shared_ptr<LinearOperator>& fop, - std::shared_ptr<ScalarProduct>& sp) - { - LinearAlgebraPreparator<GridView, AmgTraits, isParallel> - ::prepareLinearAlgebra(A, b, rank, comm, fop, sp, - *phelper_, firstCall_); - } - std::shared_ptr<ParallelISTLHelper<GridView, AmgTraits>> phelper_; Dune::InverseOperatorResult result_; bool firstCall_; diff --git a/dumux/linear/linearsolvertraits.hh b/dumux/linear/linearsolvertraits.hh index a004995278dbc2e2580263aea5d92fd59cb24b13..dad36f7cb8f01bbee347c51a963cc59164b709ee 100644 --- a/dumux/linear/linearsolvertraits.hh +++ b/dumux/linear/linearsolvertraits.hh @@ -42,9 +42,7 @@ #include <dune/grid/uggrid.hh> #endif // HAVE_UG -namespace Dumux { -namespace Temp { -namespace Capabilities { +namespace Dumux::Temp::Capabilities { template<class Grid, int codim> struct canCommunicate @@ -60,9 +58,7 @@ struct canCommunicate<Dune::UGGrid<dim>, codim> }; #endif // HAVE_UG -} // namespace Capabilities -} // namespace Temp -} // namespace Dumux +} // namespace Dumux::Temp::Capabilities // end workaround namespace Dumux { diff --git a/dumux/linear/parallelhelpers.hh b/dumux/linear/parallelhelpers.hh index 9a5ee74c3c54c91dafa678daad56850b473b18f5..26f180d085cf5d9656d7951f0337df9c4ac8e1fd 100644 --- a/dumux/linear/parallelhelpers.hh +++ b/dumux/linear/parallelhelpers.hh @@ -46,6 +46,9 @@ class ParallelISTLHelper using DofMapper = typename LinearSolverTraits::DofMapper; enum { dofCodim = LinearSolverTraits::dofCodim }; + // TODO: this is some large number (replace by limits?) + static constexpr std::size_t ghostMarker_ = 1<<24; + class BaseGatherScatter { public: @@ -63,7 +66,7 @@ class ParallelISTLHelper { return true; } template<class EntityType> - size_t size(EntityType& e) const + std::size_t size(EntityType& e) const { return 1; } template<class EntityType> @@ -99,7 +102,7 @@ class ParallelISTLHelper } template<class MessageBuffer, class EntityType> - void scatter(MessageBuffer& buff, const EntityType& e, size_t n) + void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { typename V::block_type block; buff.read(block); @@ -111,7 +114,7 @@ class ParallelISTLHelper /*! - * \brief Writes 1<<24 to each data item (of the container) that is gathered or scattered + * \brief Writes ghostMarker_ to each data item (of the container) that is gathered or scattered * and is neither interior nor border. * * Can be used to mark ghost cells. @@ -133,27 +136,27 @@ class ParallelISTLHelper template<class MessageBuffer, class EntityType> void gather(MessageBuffer& buff, const EntityType& e) const { - std::size_t& data = ranks_[this->index(e)]; // TODO: reference to size_t ? + auto& data = ranks_[this->index(e)]; if (this->isNeitherInteriorNorBorderEntity(e)) - data = (1<<24); + data = ghostMarker_; buff.write(data); } template<class MessageBuffer, class EntityType> - void scatter(MessageBuffer& buff, const EntityType& e, size_t n) + void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { std::size_t x; - std::size_t& data = ranks_[this->index(e)]; - buff.read(x); // TODO what is this good for? + buff.read(x); + auto& data = ranks_[this->index(e)]; if (this->isNeitherInteriorNorBorderEntity(e)) - data = (1<<24); + data = ghostMarker_; } private: std::vector<std::size_t>& ranks_; }; /*! - * \brief GatherScatter handle that sets 1<<24 for data items neither associated to + * \brief GatherScatter handle that sets ghostMarker_ for data items neither associated to * the interior or border and take the minimum when scattering. * * Used to compute an owner rank for each unknown. @@ -175,23 +178,20 @@ class ParallelISTLHelper template<class MessageBuffer, class EntityType> void gather(MessageBuffer& buff, const EntityType& e) const { - std::size_t& data = ranks_[this->index(e)]; // TODO: reference to size_t ? + auto& data = ranks_[this->index(e)]; if (this->isNeitherInteriorNorBorderEntity(e)) - data = (1<<24); + data = ghostMarker_; buff.write(data); } template<class MessageBuffer, class EntityType> void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { - using std::min; std::size_t x; - std::size_t& data = ranks_[this->index(e)]; buff.read(x); - if (this->isNeitherInteriorNorBorderEntity(e)) - data = x; - else - data = min(data,x); + auto& data = ranks_[this->index(e)]; + using std::min; + data = this->isNeitherInteriorNorBorderEntity(e) ? x : min(data,x); } private: std::vector<std::size_t>& ranks_; @@ -205,7 +205,7 @@ class ParallelISTLHelper : public BaseGatherScatter, public Dune::CommDataHandleIF<NeighbourGatherScatter,int> { - using DataType = int; // TODO: size_t? + using DataType = int; using BaseGatherScatter::contains; using BaseGatherScatter::fixedsize; using BaseGatherScatter::size; @@ -221,9 +221,9 @@ class ParallelISTLHelper } template<class MessageBuffer, class EntityType> - void scatter(MessageBuffer& buff, const EntityType& e, size_t n) + void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { - int x; // TODO: size_t? + int x; buff.read(x); neighbours_.insert(x); } @@ -258,11 +258,11 @@ class ParallelISTLHelper } template<class MessageBuffer, class EntityType> - void scatter(MessageBuffer& buff, const EntityType &e, size_t n) + void scatter(MessageBuffer& buff, const EntityType &e, std::size_t n) { int x; buff.read(x); - int& data = shared_[this->index(e)]; + auto& data = shared_[this->index(e)]; data = data || x; } private: @@ -273,89 +273,96 @@ class ParallelISTLHelper * \brief GatherScatter handle for finding out about neighbouring processor ranks. * */ - template<typename GI> + template<typename GlobalIndex> struct GlobalIndexGatherScatter : public BaseGatherScatter, - public Dune::CommDataHandleIF<GlobalIndexGatherScatter<GI>, GI> + public Dune::CommDataHandleIF<GlobalIndexGatherScatter<GlobalIndex>, GlobalIndex> { - using DataType = GI; + using DataType = GlobalIndex; using BaseGatherScatter::contains; using BaseGatherScatter::fixedsize; using BaseGatherScatter::size; - GlobalIndexGatherScatter(std::vector<GI>& gindices, const DofMapper& mapper) - : BaseGatherScatter(mapper), gindices_(gindices) + GlobalIndexGatherScatter(std::vector<GlobalIndex>& globalIndices, const DofMapper& mapper) + : BaseGatherScatter(mapper), globalIndices_(globalIndices) {} template<class MessageBuffer, class EntityType> void gather(MessageBuffer& buff, const EntityType& e) const { - buff.write(gindices_[this->index(e)]); + buff.write(globalIndices_[this->index(e)]); } template<class MessageBuffer, class EntityType> - void scatter(MessageBuffer& buff, const EntityType& e, size_t n) + void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { - using std::min; DataType x; buff.read(x); - gindices_[this->index(e)] = min(gindices_[this->index(e)], x); + using std::min; + auto& data = globalIndices_[this->index(e)]; + data = min(data, x); } private: - std::vector<GI>& gindices_; + std::vector<GlobalIndex>& globalIndices_; }; public: - ParallelISTLHelper (const GridView& gridView, const DofMapper& mapper, int verbose = 1) - : gridView_(gridView), mapper_(mapper), verbose_(verbose), initialized_(false) + ParallelISTLHelper(const GridView& gridView, const DofMapper& mapper) + : gridView_(gridView), mapper_(mapper), initialized_(false) + {} + + [[deprecated("The verbose argument has no effect. Use ParallelISTLHelper(gridView, mapper) instead. Will be removed after 3.2!")]] + ParallelISTLHelper(const GridView& gridView, const DofMapper& mapper, int verbose) + : gridView_(gridView), mapper_(mapper), initialized_(false) {} // \brief Initializes the markers for ghosts and owners with the correct size and values. // void initGhostsAndOwners() { - owner_.resize(mapper_.size(), - gridView_.comm().rank()); - isGhost_.resize(mapper_.size(),0.0); + const auto rank = gridView_.comm().rank(); + isOwned_.resize(mapper_.size(), rank); // find out about ghosts - GhostGatherScatter ggs(owner_, mapper_); + GhostGatherScatter ggs(isOwned_, mapper_); if (gridView_.comm().size() > 1) gridView_.communicate(ggs, Dune::InteriorBorder_All_Interface, Dune::ForwardCommunication); - isGhost_ = owner_; + isGhost_ = isOwned_; // partition interior/border - InteriorBorderGatherScatter dh(owner_, mapper_); + InteriorBorderGatherScatter dh(isOwned_, mapper_); if (gridView_.comm().size() > 1) gridView_.communicate(dh, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication); // convert vector into mask vector - for (auto& v : owner_) - v = (v == gridView_.comm().rank()) ? 1.0 : 0.0; + for (auto& v : isOwned_) + v = (v == rank) ? 1 : 0; initialized_ = true; } // keep only DOFs assigned to this processor template<class W> + [[deprecated("This function has no effect. Will be removed after 3.2!")]] void mask(W& w) const - { - auto v1 = w.begin(); - for (auto v2 = owner_.begin(), vend = owner_.end(); v2 != vend; ++v1, ++v2) - v1 *= v2; - } + {} // access to mask vector - double mask(std::size_t i) const - { return owner_[i]; } + [[deprecated("Will be removed after 3.2!")]] + std::size_t mask(std::size_t i) const + { return isOwned_[i]; } // access to ghost vector - std::size_t ghost (std::size_t i) const + [[deprecated("Will be removed after 3.2!")]] + std::size_t ghost(std::size_t i) const { return isGhost_[i]; } + bool isGhost(std::size_t i) const + { return isGhost_[i] == ghostMarker_; } + // \brief Make a vector of the box model consistent. template<class B, class A> void makeNonOverlappingConsistent(Dune::BlockVector<B,A>& v) @@ -371,20 +378,17 @@ public: #if HAVE_MPI + template<typename MatrixType, typename Comm> + [[deprecated("Use createParallelIndexSet(comm) instead. Will be removed after 3.2!")]] + void createIndexSetAndProjectForAMG(MatrixType& m, Comm& c) + { createParallelIndexSet(c); } + /*! - * \brief Creates a matrix suitable for parallel AMG and the parallel information + * \brief Creates a parallel index set * - * \tparam MatrixType The type of the ISTL matrix used. * \tparam Comm The type of the OwnerOverlapCopyCommunication - * \param m The local matrix. - * \param c The parallel information object providing index set, interfaces and * communicators. */ - template<typename MatrixType, typename Comm> - [[deprecated("Use createParallelIndexSet(comm) instead. Will be removed after 3.1!")]] - void createIndexSetAndProjectForAMG(MatrixType& m, Comm& c) - { createParallelIndexSet(c); } - template<class Comm> void createParallelIndexSet(Comm& comm) { @@ -396,105 +400,56 @@ public: initGhostsAndOwners(); } + if (gridView_.comm().size() <= 1) + { + comm.remoteIndices().template rebuild<false>(); + return; + } + // First find out which dofs we share with other processors - std::vector<int> sharedDofs(mapper_.size(), false); + std::vector<int> isShared(mapper_.size(), false); - SharedGatherScatter sgs(sharedDofs, mapper_); - - if (gridView_.comm().size() > 1) - gridView_.communicate(sgs, Dune::All_All_Interface, - Dune::ForwardCommunication); + SharedGatherScatter sgs(isShared, mapper_); + gridView_.communicate(sgs, Dune::All_All_Interface, Dune::ForwardCommunication); // Count shared dofs that we own using GlobalIndex = typename Comm::ParallelIndexSet::GlobalIndex; GlobalIndex count = 0; - auto owned = owner_.begin(); - - for (auto v = sharedDofs.begin(), vend=sharedDofs.end(); v != vend; ++v, ++owned) - if (*v && *owned == 1) + for (std::size_t i = 0; i < isShared.size(); ++i) + if (isShared[i] && isOwned_[i] == 1) ++count; - Dune::dverb << gridView_.comm().rank() << ": shared count is " << count.touint() - << std::endl; - std::vector<GlobalIndex> counts(gridView_.comm().size()); - gridView_.comm().allgather(&count, 1, &(counts[0])); + gridView_.comm().allgather(&count, 1, counts.data()); // Compute start index start_p = \sum_{i=0}^{i<p} counts_i - GlobalIndex start = 0; - for (int i = 0; i < gridView_.comm().rank(); ++i) - start = start + counts[i]; + const int rank = gridView_.comm().rank(); + auto start = std::accumulate(counts.begin(), counts.begin() + rank, GlobalIndex(0)); - std::vector<GlobalIndex> scalarIndices(mapper_.size(), - std::numeric_limits<GlobalIndex>::max()); + std::vector<GlobalIndex> globalIndices(mapper_.size(), std::numeric_limits<GlobalIndex>::max()); - auto shared = sharedDofs.begin(); - auto index = scalarIndices.begin(); - - for (auto i = owner_.begin(), iend = owner_.end(); i != iend; ++i, ++shared, ++index) + for (std::size_t i = 0; i < globalIndices.size(); ++i) { - if (*i==1 && *shared) + if (isOwned_[i] == 1 && isShared[i]) { - *index = start; + globalIndices[i] = start; // GlobalIndex does not implement postfix ++ ++start; } } // publish global indices for the shared DOFS to other processors. - GlobalIndexGatherScatter<GlobalIndex> gigs(scalarIndices, mapper_); - if (gridView_.comm().size() > 1) - gridView_.communicate(gigs, Dune::All_All_Interface, - Dune::ForwardCommunication); + GlobalIndexGatherScatter<GlobalIndex> gigs(globalIndices, mapper_); + gridView_.communicate(gigs, Dune::All_All_Interface, Dune::ForwardCommunication); - - // Setup the index set - comm.indexSet().beginResize(); - index = scalarIndices.begin(); - auto ghost = isGhost_.begin(); - - for (auto i = owner_.begin(), iend = owner_.end(); i != iend; ++i, ++ghost, ++index) - { - Dune::OwnerOverlapCopyAttributeSet::AttributeSet attr; - if (*index != std::numeric_limits<GlobalIndex>::max()) - { - // global index exist in index set - if (*i > 0) - { - // This dof is managed by us. - attr = Dune::OwnerOverlapCopyAttributeSet::owner; - } - #if DUNE_VERSION_GTE(DUNE_ISTL, 2, 7) - else if ( *ghost==(1<<24) && ( comm.category() == - static_cast<int>(Dune::SolverCategory::nonoverlapping)) ) - #else - else if ( *ghost==(1<<24) && ( comm.getSolverCategory() == - static_cast<int>(Dune::SolverCategory::nonoverlapping)) ) - #endif - { - //use attribute overlap for ghosts in novlp grids - attr = Dune::OwnerOverlapCopyAttributeSet::overlap; - } - else - { - attr = Dune::OwnerOverlapCopyAttributeSet::copy; - } - comm.indexSet().add(*index, typename Comm::ParallelIndexSet::LocalIndex(i-owner_.begin(), attr)); - } - } - comm.indexSet().endResize(); + resizeIndexSet_(comm, globalIndices); // Compute neighbours using communication std::set<int> neighbours; - NeighbourGatherScatter ngs(mapper_, gridView_.comm().rank(), - neighbours); - - if (gridView_.comm().size() > 1) - gridView_.communicate(ngs, Dune::All_All_Interface, - Dune::ForwardCommunication); - + NeighbourGatherScatter ngs(mapper_, gridView_.comm().rank(), neighbours); + gridView_.communicate(ngs, Dune::All_All_Interface, Dune::ForwardCommunication); comm.remoteIndices().setNeighbours(neighbours); - comm.remoteIndices().template rebuild<false>(); + comm.remoteIndices().template rebuild<false>(); } #endif @@ -507,12 +462,49 @@ public: const GridView& gridView() const { return gridView_; } + template<class Comm> + Dune::OwnerOverlapCopyAttributeSet::AttributeSet + getAttribute_(const Comm& comm, const bool isOwned, const bool isGhost) const + { + if (isOwned) + return Dune::OwnerOverlapCopyAttributeSet::owner; +#if DUNE_VERSION_GTE(DUNE_ISTL, 2, 7) + else if (isGhost && ( comm.category() == + static_cast<int>(Dune::SolverCategory::nonoverlapping)) ) +#else + else if (isGhost && ( comm.getSolverCategory() == + static_cast<int>(Dune::SolverCategory::nonoverlapping)) ) +#endif + return Dune::OwnerOverlapCopyAttributeSet::overlap; + else + return Dune::OwnerOverlapCopyAttributeSet::copy; + } + + template<class Comm, class GlobalIndices> + void resizeIndexSet_(Comm& comm, const GlobalIndices& globalIndices) const + { + comm.indexSet().beginResize(); + + for (std::size_t localIndex = 0; localIndex < globalIndices.size(); ++localIndex) + { + const auto globalIndex = globalIndices[localIndex]; + if (globalIndex != std::numeric_limits<typename GlobalIndices::value_type>::max()) + { + const bool isOwned = isOwned_[localIndex] > 0; + const auto attr = getAttribute_(comm, isOwned, isGhost(localIndex)); + using LocalIndex = typename Comm::ParallelIndexSet::LocalIndex; + comm.indexSet().add(globalIndex, LocalIndex{localIndex, attr}); + } + } + + comm.indexSet().endResize(); + } + private: const GridView gridView_; //!< the grid view const DofMapper& mapper_; //!< the dof mapper - std::vector<std::size_t> owner_; //!< vector to identify unique decomposition + std::vector<std::size_t> isOwned_; //!< vector to identify unique decomposition std::vector<std::size_t> isGhost_; //!< vector to identify ghost dofs - int verbose_; //!< verbosity bool initialized_; //!< whether isGhost and owner arrays are initialized }; // class ParallelISTLHelper @@ -533,37 +525,8 @@ class EntityExchanger using BlockType = typename Matrix::block_type; using IDS = typename Grid::Traits::GlobalIdSet; using IdType = typename IDS::IdType; - using RowIterator = typename Matrix::RowIterator; - using ColIterator = typename Matrix::ColIterator; using DofMapper = typename LinearSolverTraits::DofMapper; -public: - /*! \brief Constructor. Sets up the local to global relations. - \param[in] gridView The gridView on which we are operating - \param[in] mapper The local dof mapper - */ - EntityExchanger(const GridView& gridView, const DofMapper& mapper) - : gridView_(gridView), mapper_(mapper) - { - gid2Index_.clear(); - index2GID_.clear(); - - for (const auto& entity : entities(gridView_, Dune::Codim<dofCodim>())) - { - if (entity.partitionType() == Dune::BorderEntity) - { - int localIdx = mapper_.index(entity); - IdType dofIdxGlobal = gridView_.grid().globalIdSet().id(entity); - - std::pair<IdType, int> g2iPair(dofIdxGlobal, localIdx); - gid2Index_.insert(g2iPair); - - std::pair<int, IdType> i2gPair(localIdx, dofIdxGlobal); - index2GID_.insert(i2gPair); - } - } - } - /*! * \brief A DataHandle class to exchange matrix sparsity patterns. * @@ -582,63 +545,46 @@ public: * </pre> * If we look at vertex 7 and the corresponding entries in the matrix for P0, * there will be entries for (7,4) and (7,8), but not for (7,2). - * The MatPatternExchange class will find these entries and returns a vector "sparsity", + * The MatrixPatternExchange class will find these entries and returns a vector "sparsity", * that contains all missing connections. */ - class MatPatternExchange - : public Dune::CommDataHandleIF<MatPatternExchange, IdType> + struct MatrixPatternExchange + : public Dune::CommDataHandleIF<MatrixPatternExchange, IdType> { - using RowIterator = typename Matrix::RowIterator; - using ColIterator = typename Matrix::ColIterator; - public: //! Export type of data for message buffer using DataType = IdType; - /** \brief Constructor - \param[in] mapper The local dof mapper. - \param[in] g2i Global to local index map. - \param[in] i2g Local to global index map. - \param[in] A Matrix to operate on. - \param[in] helper parallel istl helper. - */ - MatPatternExchange (const DofMapper& mapper, - const std::map<IdType,int>& g2i, - const std::map<int,IdType>& i2g, Matrix& A, - const ParallelISTLHelper<GridView, LinearSolverTraits>& helper) - : mapper_(mapper), gid2Index_(g2i), index2GID_(i2g), - sparsity_(A.N()), A_(A), helper_(helper) + MatrixPatternExchange(const DofMapper& mapper, + const std::map<IdType,int>& globalToLocal, + const std::map<int,IdType>& localToGlobal, Matrix& A, + const ParallelISTLHelper<GridView, LinearSolverTraits>& helper) + : mapper_(mapper), idToIndex_(globalToLocal), indexToID_(localToGlobal) + , sparsity_(A.N()), A_(A), helper_(helper) {} /*! * \brief Returns true if data for given valid codim should be communicated */ bool contains (int dim, int codim) const - { - return (codim==dofCodim); - } + { return (codim == dofCodim); } /*! * \brief Returns true if size of data per entity of given dim and codim is a constant */ bool fixedsize (int dim, int codim) const - { - return false; - } + { return false; } /*! * \brief How many objects of type DataType have to be sent for a given entity */ template<class EntityType> - size_t size (EntityType& e) const + std::size_t size(EntityType& e) const { - int i = mapper_.index(e); - int n = 0; - for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) - { - typename std::map<int,IdType>::const_iterator it = index2GID_.find(j.index()); - if (it != index2GID_.end()) + const auto rowIdx = mapper_.index(e); + std::size_t n = 0; + for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) + if (indexToID_.count(colIt.index())) n++; - } return n; } @@ -647,35 +593,36 @@ public: * \brief Pack data from user to message buffer */ template<class MessageBuffer, class EntityType> - void gather (MessageBuffer& buff, const EntityType& e) const + void gather(MessageBuffer& buff, const EntityType& e) const { - int i = mapper_.index(e); - for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) + const auto rowIdx = mapper_.index(e); + for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) { - typename std::map<int,IdType>::const_iterator it=index2GID_.find(j.index()); - if (it != index2GID_.end()) + auto it = indexToID_.find(colIt.index()); + if (it != indexToID_.end()) buff.write(it->second); } - } /*! * \brief Unpack data from message buffer to user */ template<class MessageBuffer, class EntityType> - void scatter (MessageBuffer& buff, const EntityType& e, size_t n) + void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { - int i = mapper_.index(e); - for (size_t k = 0; k < n; k++) + const auto rowIdx = mapper_.index(e); + for (std::size_t k = 0; k < n; k++) { IdType id; buff.read(id); // only add entries corresponding to border entities - typename std::map<IdType,int>::const_iterator it = gid2Index_.find(id); - if (it != gid2Index_.end() - && sparsity_[i].find(it->second) == sparsity_[i].end() - && helper_.ghost(it->second) != 1<<24) - sparsity_[i].insert(it->second); + const auto it = idToIndex_.find(id); + if (it != idToIndex_.end()) + { + const auto colIdx = it->second; + if (!sparsity_[rowIdx].count(colIdx) && !helper_.isGhost(colIdx)) + sparsity_[rowIdx].insert(colIdx); + } } } @@ -683,83 +630,65 @@ public: * \brief Get the communicated sparsity pattern * \return the vector with the sparsity pattern */ - std::vector<std::set<int> >& sparsity () - { - return sparsity_; - } + std::vector<std::set<int>>& sparsity() + { return sparsity_; } private: const DofMapper& mapper_; - const std::map<IdType,int>& gid2Index_; - const std::map<int,IdType>& index2GID_; + const std::map<IdType,int>& idToIndex_; + const std::map<int,IdType>& indexToID_; std::vector<std::set<int> > sparsity_; Matrix& A_; const ParallelISTLHelper<GridView, LinearSolverTraits>& helper_; - }; // class MatPatternExchange + }; // class MatrixPatternExchange //! Local matrix blocks associated with the global id set - struct MatEntry + struct MatrixEntry { IdType first; BlockType second; - MatEntry (const IdType& f, const BlockType& s) : first(f), second(s) {} - MatEntry () {} + MatrixEntry (const IdType& f, const BlockType& s) : first(f), second(s) {} + MatrixEntry () {} }; //! A DataHandle class to exchange matrix entries - class MatEntryExchange - : public Dune::CommDataHandleIF<MatEntryExchange,MatEntry> + struct MatrixEntryExchange + : public Dune::CommDataHandleIF<MatrixEntryExchange,MatrixEntry> { - using RowIterator = typename Matrix::RowIterator; - using ColIterator = typename Matrix::ColIterator; - public: //! Export type of data for message buffer - using DataType = MatEntry; + using DataType = MatrixEntry; - /*! - * \brief Constructor - * \param[in] mapper The local dof mapper. - * \param[in] g2i Global to local index map. - * \param[in] i2g Local to global index map. - * \param[in] A Matrix to operate on. - */ - MatEntryExchange (const DofMapper& mapper, const std::map<IdType,int>& g2i, - const std::map<int,IdType>& i2g, - Matrix& A) - : mapper_(mapper), gid2Index_(g2i), index2GID_(i2g), A_(A) + MatrixEntryExchange(const DofMapper& mapper, + const std::map<IdType,int>& globalToLocal, + const std::map<int,IdType>& localToGlobal, + Matrix& A) + : mapper_(mapper), idToIndex_(globalToLocal), indexToID_(localToGlobal), A_(A) {} /*! * \brief Returns true if data for given valid codim should be communicated */ - bool contains (int dim, int codim) const - { - return (codim==dofCodim); - } + bool contains(int dim, int codim) const + { return (codim == dofCodim); } /*! * \brief Returns true if size of data per entity of given dim and codim is a constant */ - bool fixedsize (int dim, int codim) const - { - return false; - } + bool fixedsize(int dim, int codim) const + { return false; } /*! * \brief How many objects of type DataType have to be sent for a given entity */ template<class EntityType> - size_t size (EntityType& e) const + std::size_t size(EntityType& e) const { - int i = mapper_.index(e); - int n = 0; - for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) - { - typename std::map<int,IdType>::const_iterator it = index2GID_.find(j.index()); - if (it != index2GID_.end()) + const auto rowIdx = mapper_.index(e); + std::size_t n = 0; + for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) + if (indexToID_.count(colIt.index())) n++; - } return n; } @@ -768,46 +697,66 @@ public: * \brief Pack data from user to message buffer */ template<class MessageBuffer, class EntityType> - void gather (MessageBuffer& buff, const EntityType& e) const + void gather(MessageBuffer& buff, const EntityType& e) const { - int i = mapper_.index(e); - for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) + const auto rowIdx = mapper_.index(e); + for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) { - typename std::map<int,IdType>::const_iterator it=index2GID_.find(j.index()); - if (it != index2GID_.end()) - buff.write(MatEntry(it->second,*j)); + auto it = indexToID_.find(colIt.index()); + if (it != indexToID_.end()) + buff.write(MatrixEntry(it->second,*colIt)); } - } /*! * \brief Unpack data from message buffer to user */ template<class MessageBuffer, class EntityType> - void scatter (MessageBuffer& buff, const EntityType& e, size_t n) + void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) { - int i = mapper_.index(e); - for (size_t k = 0; k < n; k++) + const auto rowIdx = mapper_.index(e); + for (std::size_t k = 0; k < n; k++) { - MatEntry m; + MatrixEntry m; buff.read(m); // only add entries corresponding to border entities - typename std::map<IdType,int>::const_iterator it = gid2Index_.find(m.first); - if (it != gid2Index_.end()) - if (A_[i].find(it->second) != A_[i].end()) - A_[i][it->second] += m.second; + auto it = idToIndex_.find(m.first); + if (it != idToIndex_.end()) + if (A_[rowIdx].find(it->second) != A_[rowIdx].end()) + A_[rowIdx][it->second] += m.second; } } private: const DofMapper& mapper_; - const std::map<IdType,int>& gid2Index_; - const std::map<int,IdType>& index2GID_; + const std::map<IdType,int>& idToIndex_; + const std::map<int,IdType>& indexToID_; Matrix& A_; - }; // class MatEntryExchange + }; // class MatrixEntryExchange + +public: + + EntityExchanger(const GridView& gridView, const DofMapper& mapper) + : gridView_(gridView), mapper_(mapper) + { + idToIndex_.clear(); + indexToID_.clear(); + + for (const auto& entity : entities(gridView_, Dune::Codim<dofCodim>())) + { + if (entity.partitionType() == Dune::BorderEntity) + { + const int localIdx = mapper_.index(entity); + IdType dofIdxGlobal = gridView_.grid().globalIdSet().id(entity); + + idToIndex_.emplace(dofIdxGlobal, localIdx); + indexToID_.emplace(localIdx, dofIdxGlobal); + } + } + } - [[deprecated("Use extendMatrix instead. Will be removed after 3.1!")]] + [[deprecated("Use extendMatrix instead. Will be removed after 3.2!")]] void getExtendedMatrix (Matrix& A, const ParallelISTLHelper<GridView, LinearSolverTraits>& helper) { extendMatrix(A, helper); } @@ -818,122 +767,118 @@ public: */ void extendMatrix(Matrix& A, const ParallelISTLHelper<GridView, LinearSolverTraits>& helper) { - if (gridView_.comm().size() > 1) + if (gridView_.comm().size() <= 1) + return; + + Matrix tmp(A); + std::size_t nnz = 0; + // get entries from other processes + MatrixPatternExchange datahandle(mapper_, idToIndex_, indexToID_, A, helper); + gridView_.communicate(datahandle, Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); + std::vector<std::set<int>>& sparsity = datahandle.sparsity(); + // add own entries, count number of nonzeros + for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt) { - Matrix tmp(A); - std::size_t nnz = 0; - // get entries from other processes - MatPatternExchange datahandle(mapper_, gid2Index_, index2GID_, A, helper); - gridView_.communicate(datahandle, Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - std::vector<std::set<int> >& sparsity = datahandle.sparsity(); - // add own entries, count number of nonzeros - for (RowIterator i = A.begin(); i != A.end(); ++i) - { - for (ColIterator j = A[i.index()].begin(); j != A[i.index()].end(); ++j) - { - if (sparsity[i.index()].find(j.index()) == sparsity[i.index()].end()) - sparsity[i.index()].insert(j.index()); - } - nnz += sparsity[i.index()].size(); - } + for (auto colIt = A[rowIt.index()].begin(); colIt != A[rowIt.index()].end(); ++colIt) + if (!sparsity[rowIt.index()].count(colIt.index())) + sparsity[rowIt.index()].insert(colIt.index()); - A.setSize(tmp.N(), tmp.N(), nnz); - A.setBuildMode(Matrix::row_wise); - typename Matrix::CreateIterator citer = A.createbegin(); - using Iter = typename std::vector<std::set<int> >::const_iterator; - for (Iter i = sparsity.begin(), end = sparsity.end(); i!=end; ++i, ++citer) - { - using SIter = typename std::set<int>::const_iterator; - for (SIter si = i->begin(), send = i->end(); si!=send; ++si) - citer.insert(*si); - } + nnz += sparsity[rowIt.index()].size(); + } - // set matrix old values - A = 0; - for (RowIterator i = tmp.begin(); i != tmp.end(); ++i) - for (ColIterator j = tmp[i.index()].begin(); j != tmp[i.index()].end(); ++j) - A[i.index()][j.index()] = tmp[i.index()][j.index()]; + A.setSize(tmp.N(), tmp.N(), nnz); + A.setBuildMode(Matrix::row_wise); + auto citer = A.createbegin(); + for (auto i = sparsity.begin(), end = sparsity.end(); i!=end; ++i, ++citer) + { + for (auto si = i->begin(), send = i->end(); si!=send; ++si) + citer.insert(*si); } + + // set matrix old values + A = 0; + for (auto rowIt = tmp.begin(); rowIt != tmp.end(); ++rowIt) + for (auto colIt = tmp[rowIt.index()].begin(); colIt != tmp[rowIt.index()].end(); ++colIt) + A[rowIt.index()][colIt.index()] = tmp[rowIt.index()][colIt.index()]; } /*! * \brief Sums up the entries corresponding to border vertices. * \param A Matrix to operate on. */ - void sumEntries (Matrix& A) + void sumEntries(Matrix& A) { - if (gridView_.comm().size() > 1) - { - MatEntryExchange datahandle(mapper_, gid2Index_, index2GID_, A); - gridView_.communicate(datahandle, Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - } + if (gridView_.comm().size() <= 1) + return; + + MatrixEntryExchange datahandle(mapper_, idToIndex_, indexToID_, A); + gridView_.communicate(datahandle, Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); } -#if HAVE_MPI - /*! - * \brief Extends the sparsity pattern of the discretization matrix for AMG. - * \param A A reference to the matrix to change. - */ - [[deprecated("Use extendMatrix instead. Will be removed after 3.1!")]] - void getExtendedMatrix (Matrix& A) - { extendMatrix(A); } - /*! - * \brief Extends the sparsity pattern of the discretization matrix for AMG. - * \param A A reference to the matrix to change. - */ - void extendMatrix(Matrix& A) - { - if (gridView_.comm().size() > 1) - { - Matrix tmp(A); - std::size_t nnz = 0; - // get entries from other processes - MatPatternExchange datahandle(mapper_, gid2Index_, index2GID_, A, *this); - gridView_.communicate(datahandle, Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - std::vector<std::set<int> >& sparsity = datahandle.sparsity(); +private: + const GridView gridView_; + const DofMapper& mapper_; + std::map<IdType, int> idToIndex_; + std::map<int, IdType> indexToID_; - // add own entries, count number of nonzeros - for (RowIterator i = A.begin(); i != A.end(); ++i) - { - for (ColIterator j = A[i.index()].begin(); j != A[i.index()].end(); ++j) - { - if (sparsity[i.index()].find(j.index()) == sparsity[i.index()].end()) - sparsity[i.index()].insert(j.index()); - } - nnz += sparsity[i.index()].size(); - } +}; // class EntityExchanger - A.setSize(tmp.N(), tmp.N(), nnz); - A.setBuildMode(Matrix::row_wise); - typename Matrix::CreateIterator citer = A.createbegin(); - using Iter = typename std::vector<std::set<int> >::const_iterator; - for (Iter i = sparsity.begin(), end = sparsity.end(); i!=end; ++i, ++citer){ - using SIter = typename std::set<int>::const_iterator; - for (SIter si = i->begin(), send = i->end(); si!=send; ++si) - citer.insert(*si); - } +#if HAVE_MPI +/*! + * \brief Prepare linear algebra variables for parallel solvers + */ +template<class LinearSolverTraits, class Matrix, class Vector, class ParallelHelper> +void prepareLinearAlgebraParallel(Matrix& A, Vector& b, + std::shared_ptr<typename LinearSolverTraits::Comm>& comm, + std::shared_ptr<typename LinearSolverTraits::LinearOperator>& fop, + std::shared_ptr<typename LinearSolverTraits::ScalarProduct>& sp, + ParallelHelper& pHelper, + const bool firstCall) +{ + const auto category = LinearSolverTraits::isNonOverlapping ? + Dune::SolverCategory::nonoverlapping + : Dune::SolverCategory::overlapping; - // set matrix old values - A = 0; - for (RowIterator i = tmp.begin(); i != tmp.end(); ++i) - for (ColIterator j = tmp[i.index()].begin(); j != tmp[i.index()].end(); ++j) - A[i.index()][j.index()] = tmp[i.index()][j.index()]; + if (LinearSolverTraits::isNonOverlapping && firstCall) + pHelper.initGhostsAndOwners(); - sumEntries(A); - } + comm = std::make_shared<typename LinearSolverTraits::Comm>(pHelper.gridView().comm(), category); + + if (LinearSolverTraits::isNonOverlapping) + { + // extend the matrix pattern such that it is usable for a parallel solver + using GridView = std::decay_t<decltype(pHelper.gridView())>; + EntityExchanger<GridView, LinearSolverTraits> exchanger(pHelper.gridView(), pHelper.dofMapper()); + exchanger.extendMatrix(A, pHelper); + exchanger.sumEntries(A); } -#endif + pHelper.createParallelIndexSet(*comm); -private: - const GridView gridView_; - const DofMapper& mapper_; - std::map<IdType, int> gid2Index_; - std::map<int, IdType> index2GID_; + fop = std::make_shared<typename LinearSolverTraits::LinearOperator>(A, *comm); + sp = std::make_shared<typename LinearSolverTraits::ScalarProduct>(*comm); + + // make rhs consistent + if (LinearSolverTraits::isNonOverlapping) + pHelper.makeNonOverlappingConsistent(b); +} +#endif // HAVE_MPI + +/*! + * \brief Prepare linear algebra variables for sequential solvers + */ +template<class LinearSolverTraits, class Matrix> +void prepareLinearAlgebraSequential(Matrix& A, + std::shared_ptr<typename LinearSolverTraits::Comm>& comm, + std::shared_ptr<typename LinearSolverTraits::LinearOperator>& fop, + std::shared_ptr<typename LinearSolverTraits::ScalarProduct>& sp) +{ + comm = std::make_shared<typename LinearSolverTraits::Comm>(); + fop = std::make_shared<typename LinearSolverTraits::LinearOperator>(A); + sp = std::make_shared<typename LinearSolverTraits::ScalarProduct>(); +} -}; // class EntityExchanger /*! * \brief Prepare the linear algebra member variables. @@ -949,16 +894,16 @@ private: * * \tparam isParallel decides if the setting is parallel or sequential */ -template<class GridView, class LinearSolverTraits, bool isParallel> -struct LinearAlgebraPreparator +template<class GridView, class AmgTraits, bool isParallel> +struct LinearAlgebraPreparator // TODO: Deprecating the whole struct always triggers a warning even it is not used. Remove after 3.2 { - using DofMapper = typename LinearSolverTraits::DofMapper; - using ParallelHelper = ParallelISTLHelper<GridView, LinearSolverTraits>; - using Comm = typename LinearSolverTraits::Comm; - using LinearOperator = typename LinearSolverTraits::LinearOperator; - using ScalarProduct = typename LinearSolverTraits::ScalarProduct; + using ParallelHelper = ParallelISTLHelper<GridView, AmgTraits>; + using Comm = typename AmgTraits::Comm; + using LinearOperator = typename AmgTraits::LinearOperator; + using ScalarProduct = typename AmgTraits::ScalarProduct; template<class Matrix, class Vector> + [[deprecated("Use free function prepareLinearAlgebraSequential instead. Will be removed after 3.2!")]] static void prepareLinearAlgebra(Matrix& A, Vector& b, int& rank, std::shared_ptr<Comm>& comm, @@ -967,9 +912,7 @@ struct LinearAlgebraPreparator ParallelHelper& pHelper, const bool firstCall) { - comm = std::make_shared<Comm>(); - fop = std::make_shared<LinearOperator>(A); - sp = std::make_shared<ScalarProduct>(); + prepareLinearAlgebraSequential<AmgTraits>(A, comm, fop, sp); } }; @@ -977,16 +920,16 @@ struct LinearAlgebraPreparator /*! * \brief Specialization for the parallel case. */ -template<class GridView, class LinearSolverTraits> -struct LinearAlgebraPreparator<GridView, LinearSolverTraits, true> +template<class GridView, class AmgTraits> +struct LinearAlgebraPreparator<GridView, AmgTraits, true> // TODO: Deprecating the whole struct always triggers a warning even it is not used. Remove after 3.2 { - using DofMapper = typename LinearSolverTraits::DofMapper; - using ParallelHelper = ParallelISTLHelper<GridView, LinearSolverTraits>; - using Comm = typename LinearSolverTraits::Comm; - using LinearOperator = typename LinearSolverTraits::LinearOperator; - using ScalarProduct = typename LinearSolverTraits::ScalarProduct; + using ParallelHelper = ParallelISTLHelper<GridView, AmgTraits>; + using Comm = typename AmgTraits::Comm; + using LinearOperator = typename AmgTraits::LinearOperator; + using ScalarProduct = typename AmgTraits::ScalarProduct; template<class Matrix, class Vector> + [[deprecated("Use free function prepareLinearAlgebraParallel instead. Will be removed after 3.2!")]] static void prepareLinearAlgebra(Matrix& A, Vector& b, int& rank, std::shared_ptr<Comm>& comm, @@ -995,32 +938,11 @@ struct LinearAlgebraPreparator<GridView, LinearSolverTraits, true> ParallelHelper& pHelper, const bool firstCall) { - const auto category = LinearSolverTraits::isNonOverlapping ? - Dune::SolverCategory::nonoverlapping : Dune::SolverCategory::overlapping; - - if (LinearSolverTraits::isNonOverlapping && firstCall) - pHelper.initGhostsAndOwners(); - - comm = std::make_shared<Comm>(pHelper.gridView().comm(), category); - - if (LinearSolverTraits::isNonOverlapping) - { - // extend the matrix pattern such that it is usable for the parallel solver - EntityExchanger<GridView, LinearSolverTraits> exchanger(pHelper.gridView(), pHelper.dofMapper()); - exchanger.extendMatrix(A, pHelper); - exchanger.sumEntries(A); - } - pHelper.createParallelIndexSet(*comm); - - fop = std::make_shared<LinearOperator>(A, *comm); - sp = std::make_shared<ScalarProduct>(*comm); + prepareLinearAlgebraParallel<AmgTraits>(A, b, rank, comm, fop, sp, pHelper, firstCall); rank = comm->communicator().rank(); - - // Make rhs consistent - if (LinearSolverTraits::isNonOverlapping) - pHelper.makeNonOverlappingConsistent(b); } -}; + +}; // parallel LinearAlgebraPreparator #endif // HAVE_MPI