version 3.8
parallelhelpers.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_LINEAR_PARALLELHELPERS_HH
13#define DUMUX_LINEAR_PARALLELHELPERS_HH
14
15#include <dune/common/exceptions.hh>
16#include <dune/geometry/dimension.hh>
17#include <dune/grid/common/datahandleif.hh>
18#include <dune/grid/common/partitionset.hh>
19#include <dune/istl/owneroverlapcopy.hh>
20#include <dune/istl/paamg/pinfo.hh>
21#include <dune/istl/bvector.hh>
22#include <dune/istl/multitypeblockvector.hh>
25
26namespace Dumux::Detail {
27
28template<class LinearSolverTraits, bool canCommunicate = false>
30
31template<class LinearSolverTraits>
33{
34 using GridView = typename LinearSolverTraits::GridView;
35 using DofMapper = typename LinearSolverTraits::DofMapper;
36 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
37
38 // TODO: this is some large number (replace by limits?)
39 static constexpr std::size_t ghostMarker_ = 1<<24;
40
41 class BaseGatherScatter
42 {
43 public:
44 BaseGatherScatter(const DofMapper& mapper)
45 : mapper_(mapper) {}
46
47 template<class EntityType>
48 int index(const EntityType& e) const
49 { return mapper_.index(e); }
50
51 bool contains(int dim, int codim) const
52 { return dofCodim == codim; }
53
55 bool fixedSize(int dim, int codim) const
56 { return true; }
57
58 template<class EntityType>
59 std::size_t size(EntityType& e) const
60 { return 1; }
61
62 template<class EntityType>
63 bool isNeitherInteriorNorBorderEntity(EntityType& e) const
64 { return e.partitionType() != Dune::InteriorEntity && e.partitionType() != Dune::BorderEntity; }
65
66 private:
67 const DofMapper& mapper_;
68 };
69
76 class GhostGatherScatter
77 : public BaseGatherScatter
78 , public Dune::CommDataHandleIF<GhostGatherScatter, std::size_t>
79 {
80 public:
81 using DataType = std::size_t;
82 using BaseGatherScatter::contains;
83 using BaseGatherScatter::fixedSize;
84 using BaseGatherScatter::size;
85
86 GhostGatherScatter(std::vector<std::size_t>& ranks, const DofMapper& mapper)
87 : BaseGatherScatter(mapper)
88 , ranks_(ranks)
89 {}
90
91 template<class MessageBuffer, class EntityType>
92 void gather(MessageBuffer& buff, const EntityType& e) const
93 {
94 auto& data = ranks_[this->index(e)];
95 if (this->isNeitherInteriorNorBorderEntity(e))
96 data = ghostMarker_;
97 buff.write(data);
98 }
99
100 template<class MessageBuffer, class EntityType>
101 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
102 {
103 std::size_t x;
104 buff.read(x);
105 auto& data = ranks_[this->index(e)];
106 if (this->isNeitherInteriorNorBorderEntity(e))
107 data = ghostMarker_;
108 }
109 private:
110 std::vector<std::size_t>& ranks_;
111 };
112
119 class InteriorBorderGatherScatter
120 : public BaseGatherScatter
121 , public Dune::CommDataHandleIF<InteriorBorderGatherScatter, std::size_t>
122 {
123 public:
124 using DataType = std::size_t;
125 using BaseGatherScatter::contains;
126 using BaseGatherScatter::fixedSize;
127 using BaseGatherScatter::size;
128
129 InteriorBorderGatherScatter(std::vector<std::size_t>& ranks, const DofMapper& mapper)
130 : BaseGatherScatter(mapper)
131 , ranks_(ranks)
132 {}
133
137 template<class MessageBuffer, class EntityType>
138 void gather(MessageBuffer& buff, const EntityType& e) const
139 {
140 auto& data = ranks_[this->index(e)];
141 if (this->isNeitherInteriorNorBorderEntity(e))
142 data = ghostMarker_;
143 buff.write(data);
144 }
145
149 template<class MessageBuffer, class EntityType>
150 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
151 {
152 std::size_t x;
153 buff.read(x);
154 auto& data = ranks_[this->index(e)];
155
156 // we leave ghost unchanged
157 // for other dofs, the process with the lowest rank
158 // is assigned to be the (unique) owner
159 using std::min;
160 data = this->isNeitherInteriorNorBorderEntity(e) ? x : min(data, x);
161 }
162 private:
163 std::vector<std::size_t>& ranks_;
164 };
165
170 struct NeighbourGatherScatter
171 : public BaseGatherScatter
172 , public Dune::CommDataHandleIF<NeighbourGatherScatter, int>
173 {
174 using DataType = int;
175 using BaseGatherScatter::contains;
176 using BaseGatherScatter::fixedSize;
177 using BaseGatherScatter::size;
178
179 NeighbourGatherScatter(const DofMapper& mapper, int rank, std::set<int>& neighbours)
180 : BaseGatherScatter(mapper)
181 , rank_(rank)
182 , neighbours_(neighbours)
183 {}
184
185 template<class MessageBuffer, class EntityType>
186 void gather(MessageBuffer& buff, const EntityType& e) const
187 {
188 buff.write(rank_);
189 }
190
191 template<class MessageBuffer, class EntityType>
192 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
193 {
194 int x;
195 buff.read(x);
196 neighbours_.insert(x);
197 }
198 private:
199 int rank_;
200 std::set<int>& neighbours_;
201 };
202
203
208 struct SharedGatherScatter
209 : public BaseGatherScatter
210 , public Dune::CommDataHandleIF<SharedGatherScatter, int>
211 {
212 using DataType = int;
213 using BaseGatherScatter::contains;
214 using BaseGatherScatter::fixedSize;
215 using BaseGatherScatter::size;
216
217 SharedGatherScatter(std::vector<int>& shared, const DofMapper& mapper)
218 : BaseGatherScatter(mapper)
219 , shared_(shared)
220 {}
221
222 template<class MessageBuffer, class EntityType>
223 void gather(MessageBuffer& buff, EntityType& e) const
224 {
225 int data = true;
226 buff.write(data);
227 }
228
229 template<class MessageBuffer, class EntityType>
230 void scatter(MessageBuffer& buff, const EntityType &e, std::size_t n)
231 {
232 int x;
233 buff.read(x);
234 auto& data = shared_[this->index(e)];
235 data = data || x;
236 }
237 private:
238 std::vector<int>& shared_;
239 };
240
245 template<typename GlobalIndex>
246 struct GlobalIndexGatherScatter
247 : public BaseGatherScatter
248 , public Dune::CommDataHandleIF<GlobalIndexGatherScatter<GlobalIndex>, GlobalIndex>
249 {
250 using DataType = GlobalIndex;
251 using BaseGatherScatter::contains;
252 using BaseGatherScatter::fixedSize;
253 using BaseGatherScatter::size;
254
255 GlobalIndexGatherScatter(std::vector<GlobalIndex>& globalIndices, const DofMapper& mapper)
256 : BaseGatherScatter(mapper)
257 , globalIndices_(globalIndices)
258 {}
259
260 template<class MessageBuffer, class EntityType>
261 void gather(MessageBuffer& buff, const EntityType& e) const
262 {
263 buff.write(globalIndices_[this->index(e)]);
264 }
265
266 template<class MessageBuffer, class EntityType>
267 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
268 {
269 DataType x;
270 buff.read(x);
271 using std::min;
272 DataType& data = globalIndices_[this->index(e)];
273 data = min(data, x);
274 }
275 private:
276 std::vector<GlobalIndex>& globalIndices_;
277 };
278
279public:
280
281 ParallelISTLHelperImpl(const GridView& gridView, const DofMapper& mapper)
282 : gridView_(gridView), mapper_(mapper)
283 {
284 if constexpr (Detail::canCommunicate<typename GridView::Traits::Grid, dofCodim>)
285 initGhostsAndOwners_();
286 else
287 DUNE_THROW(Dune::InvalidStateException,
288 "Cannot initialize parallel helper for a grid that cannot communicate codim-" << dofCodim << "-entities."
289 );
290 }
291
292 bool isGhost(std::size_t i) const
293 { return isGhost_[i] == ghostMarker_; }
294
295 bool isOwned(std::size_t i) const
296 { return isOwned_[i] == 1; }
297
309 template<class Comm>
310 void createParallelIndexSet(Comm& comm) const
311 {
312 if constexpr (Detail::canCommunicate<typename GridView::Traits::Grid, dofCodim>)
313 {
314 if (gridView_.comm().size() <= 1)
315 {
316 comm.remoteIndices().template rebuild<false>();
317 return;
318 }
319
320 // First find out which dofs we share with other processors
321 std::vector<int> isShared(mapper_.size(), false);
322 SharedGatherScatter sgs(isShared, mapper_);
323 gridView_.communicate(sgs, Dune::All_All_Interface, Dune::ForwardCommunication);
324
325 // Count shared dofs that we own
326 using GlobalIndex = typename Comm::ParallelIndexSet::GlobalIndex;
327 GlobalIndex count = 0;
328 for (std::size_t i = 0; i < isShared.size(); ++i)
329 if (isShared[i] && isOwned_[i] == 1)
330 ++count;
331
332 std::vector<GlobalIndex> counts(gridView_.comm().size());
333 gridView_.comm().allgather(&count, 1, counts.data());
334
335 // Compute start index start_p = \sum_{i=0}^{i<p} counts_i
336 const int rank = gridView_.comm().rank();
337 auto start = std::accumulate(counts.begin(), counts.begin() + rank, GlobalIndex(0));
338
339 // starting from start (offset), number global indices owned by this process consecutively
340 std::vector<GlobalIndex> globalIndices(mapper_.size(), std::numeric_limits<GlobalIndex>::max());
341 for (std::size_t i = 0; i < globalIndices.size(); ++i)
342 {
343 if (isOwned_[i] == 1 && isShared[i])
344 {
345 globalIndices[i] = start;
346 ++start;
347 }
348 }
349
350 // publish global indices for the shared DOFS to other processors.
351 GlobalIndexGatherScatter<GlobalIndex> gigs(globalIndices, mapper_);
352 gridView_.communicate(gigs, Dune::All_All_Interface, Dune::ForwardCommunication);
353
354 // put the information into the parallel index set
355 resizeAndFillIndexSet_(comm, globalIndices);
356
357 // Compute neighbours using communication
358 std::set<int> neighbours;
359 NeighbourGatherScatter ngs(mapper_, gridView_.comm().rank(), neighbours);
360 gridView_.communicate(ngs, Dune::All_All_Interface, Dune::ForwardCommunication);
361 comm.remoteIndices().setNeighbours(neighbours);
362
363 comm.remoteIndices().template rebuild<false>();
364 }
365 else
366 DUNE_THROW(Dune::InvalidStateException,
367 "Cannot build parallel index set for a grid that cannot communicate codim-" << dofCodim << "-entities."
368 );
369 }
370
372 const DofMapper& dofMapper() const
373 { return mapper_; }
374
376 const GridView& gridView() const
377 { return gridView_; }
378
379private:
388 void initGhostsAndOwners_()
389 {
390 const auto rank = gridView_.comm().rank();
391 isOwned_.assign(mapper_.size(), rank);
392
393 // find out about ghosts
394 GhostGatherScatter ggs(isOwned_, mapper_);
395
396 if (gridView_.comm().size() > 1)
397 gridView_.communicate(ggs, Dune::InteriorBorder_All_Interface, Dune::ForwardCommunication);
398
399 // isGhost_ contains rank when the dof is not on a ghost entity (interior or border)
400 // and ghostMarker_ when the dof is on a ghost
401 isGhost_ = isOwned_;
402
403 // partition interior/border uniquely
404 // after the communication each dof is assigned to one unique owner process rank
405 InteriorBorderGatherScatter dh(isOwned_, mapper_);
406
407 if (gridView_.comm().size() > 1)
408 gridView_.communicate(dh, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication);
409
410 // convert vector into mask vector
411 for (auto& v : isOwned_)
412 v = (v == rank) ? 1 : 0;
413 }
414
415 template<class Comm, class GlobalIndices>
416 void resizeAndFillIndexSet_(Comm& comm, const GlobalIndices& globalIndices) const
417 {
418 comm.indexSet().beginResize();
419
420 // add triplets characterizing each dof in the parallel index set
421 // (globalIndex, (localIndex, attribute)) where attribute is owner, overlap or copy
422 for (std::size_t localIndex = 0; localIndex < globalIndices.size(); ++localIndex)
423 {
424 const auto globalIndex = globalIndices[localIndex];
425 if (globalIndex != std::numeric_limits<typename GlobalIndices::value_type>::max())
426 {
427 const bool isOwned = isOwned_[localIndex] > 0;
428 const auto attr = getAttribute_(comm, isOwned, isGhost(localIndex));
429 using LocalIndex = typename Comm::ParallelIndexSet::LocalIndex;
430 comm.indexSet().add(globalIndex, LocalIndex{localIndex, attr});
431 }
432 }
433
434 comm.indexSet().endResize();
435 }
436
437 template<class Comm>
438 Dune::OwnerOverlapCopyAttributeSet::AttributeSet
439 getAttribute_(const Comm& comm, const bool isOwned, const bool isGhost) const
440 {
441 if (isOwned) // this process owns the dof (uniquely)
442 return Dune::OwnerOverlapCopyAttributeSet::owner;
443 else if (isGhost && (comm.category() == Dune::SolverCategory::nonoverlapping) )
444 return Dune::OwnerOverlapCopyAttributeSet::overlap;
445 else
446 return Dune::OwnerOverlapCopyAttributeSet::copy;
447 }
448
449 const GridView gridView_;
450 const DofMapper& mapper_;
452 std::vector<std::size_t> isOwned_;
454 std::vector<std::size_t> isGhost_;
455
456};
457
458} // end namespace Dumux::Detail
459
460namespace Dumux {
461
467template<class LinearSolverTraits>
471 >;
472
473
474template<class GridView, class DofMapper, int dofCodim>
476{
477public:
478 ParallelVectorHelper(const GridView& gridView, const DofMapper& mapper)
479 : gridView_(gridView), mapper_(mapper)
480 {}
481
483 template<class Block, class Alloc>
484 void makeNonOverlappingConsistent(Dune::BlockVector<Block, Alloc>& v) const
485 {
486 if constexpr (Detail::canCommunicate<typename GridView::Traits::Grid, dofCodim>)
487 {
489 if (gridView_.comm().size() > 1)
490 gridView_.communicate(gs, Dune::InteriorBorder_InteriorBorder_Interface,
491 Dune::ForwardCommunication);
492 }
493 else
494 DUNE_THROW(Dune::InvalidStateException, "Cannot call makeNonOverlappingConsistent for a grid that cannot communicate codim-" << dofCodim << "-entities.");
495 }
496
498 template<class... Blocks>
500 {
501 DUNE_THROW(Dune::NotImplemented, "makeNonOverlappingConsistent for Dune::MultiTypeBlockVector");
502 }
503
504private:
505 const GridView gridView_;
506 const DofMapper& mapper_;
507};
508
517template<class Matrix, class GridView,
518 class RowDofMapper, int rowDofCodim>
520{
521 using IdType = typename GridView::Traits::Grid::Traits::GlobalIdSet::IdType;
522
544 template<class ColIsGhostFunc>
545 struct MatrixPatternExchange
546 : public Dune::CommDataHandleIF<MatrixPatternExchange<ColIsGhostFunc>, IdType>
547 {
549 using DataType = IdType;
550
561 MatrixPatternExchange(const RowDofMapper& rowEntityMapper,
562 const std::map<IdType,int>& globalToLocal,
563 const std::map<int,IdType>& localToGlobal,
564 Matrix& A,
565 std::vector<std::set<int>>& sparsityPattern,
566 const ColIsGhostFunc& isGhostColumDof)
567 : rowEntityMapper_(rowEntityMapper), idToIndex_(globalToLocal), indexToID_(localToGlobal)
568 , sparsityPattern_(sparsityPattern), A_(A), isGhostColumDof_(isGhostColumDof)
569 {
570 sparsityPattern_.resize(A.N());
571 }
572
576 bool contains (int dim, int codim) const
577 { return (codim == rowDofCodim); }
578
580 bool fixedSize(int dim, int codim) const
581 { return false; }
582
586 template<class EntityType>
587 std::size_t size(EntityType& e) const
588 {
589 const auto rowIdx = rowEntityMapper_.index(e);
590
591 // all column entity indices of this row that are in the index set
592 std::size_t n = 0;
593 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
594 if (indexToID_.count(colIt.index()))
595 n++;
596
597 return n;
598 }
599
603 template<class MessageBuffer, class EntityType>
604 void gather(MessageBuffer& buff, const EntityType& e) const
605 {
606 const auto rowIdx = rowEntityMapper_.index(e);
607
608 // send all column entity ids of this row that are in the index set
609 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
610 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
611 buff.write(it->second);
612 }
613
617 template<class MessageBuffer, class EntityType>
618 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
619 {
620 const auto rowIdx = rowEntityMapper_.index(e);
621 for (std::size_t k = 0; k < n; k++)
622 {
623 // receive n column entity IDs
624 IdType id;
625 buff.read(id);
626
627 // only add entries that are contained in the index set
628 if (const auto it = idToIndex_.find(id); it != idToIndex_.end())
629 {
630 const auto colIdx = it->second; // get local column index
631 // add this entry (if it doesn't exist yet)
632 // (and only if the column dof is not associated with a ghost entity)
633 if (!isGhostColumDof_(colIdx))
634 // std::set takes care that each index only is inserted once
635 sparsityPattern_[rowIdx].insert(colIdx);
636 }
637 }
638 }
639
640 private:
641 const RowDofMapper& rowEntityMapper_;
642 const std::map<IdType, int>& idToIndex_;
643 const std::map<int, IdType>& indexToID_;
644 std::vector<std::set<int>>& sparsityPattern_;
645 Matrix& A_;
646 const ColIsGhostFunc& isGhostColumDof_;
647
648 }; // class MatrixPatternExchange
649
651 struct MatrixEntry
652 {
653 IdType first;
654 typename Matrix::block_type second;
655 };
656
658 struct MatrixEntryExchange
659 : public Dune::CommDataHandleIF<MatrixEntryExchange, MatrixEntry>
660 {
662 using DataType = MatrixEntry;
663
664 MatrixEntryExchange(const RowDofMapper& rowEntityMapper,
665 const std::map<IdType, int>& globalToLocal,
666 const std::map<int, IdType>& localToGlobal,
667 Matrix& A)
668 : rowEntityMapper_(rowEntityMapper), idToIndex_(globalToLocal), indexToID_(localToGlobal), A_(A)
669 {}
670
674 bool contains(int dim, int codim) const
675 { return (codim == rowDofCodim); }
676
678 bool fixedSize(int dim, int codim) const
679 { return false; }
680
684 template<class EntityType>
685 std::size_t size(EntityType& e) const
686 {
687 const auto rowIdx = rowEntityMapper_.index(e);
688 std::size_t n = 0;
689 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
690 if (indexToID_.count(colIt.index()))
691 n++;
692
693 return n;
694 }
695
699 template<class MessageBuffer, class EntityType>
700 void gather(MessageBuffer& buff, const EntityType& e) const
701 {
702 const auto rowIdx = rowEntityMapper_.index(e);
703 // send all matrix entries for which the column index is in the index set
704 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
705 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
706 buff.write(MatrixEntry{ it->second, *colIt });
707 }
708
712 template<class MessageBuffer, class EntityType>
713 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
714 {
715 const auto rowIdx = rowEntityMapper_.index(e);
716 for (std::size_t k = 0; k < n; k++)
717 {
718 MatrixEntry m;
719 buff.read(m);
720 const auto& [colDofID, matrixBlock] = m; // unpack
721
722 // only add entries in the index set and for which A has allocated memory
723 if (auto it = idToIndex_.find(colDofID); it != idToIndex_.end())
724 if (A_[rowIdx].find(it->second) != A_[rowIdx].end())
725 A_[rowIdx][it->second] += matrixBlock;
726 }
727 }
728
729 private:
730 const RowDofMapper& rowEntityMapper_;
731 const std::map<IdType, int>& idToIndex_;
732 const std::map<int, IdType>& indexToID_;
733 Matrix& A_;
734
735 }; // class MatrixEntryExchange
736
737public:
738
739 ParallelMatrixHelper(const GridView& gridView, const RowDofMapper& mapper)
740 : gridView_(gridView), mapper_(mapper)
741 {
742 idToIndex_.clear();
743 indexToID_.clear();
744
745 std::vector<bool> handledDof(gridView_.size(rowDofCodim), false);
746 for (const auto& element : elements(gridView_))
747 {
748 for (int i = 0; i < element.subEntities(rowDofCodim); ++i)
749 {
750 const auto entity = element.template subEntity<rowDofCodim>(i);
751 if (entity.partitionType() == Dune::BorderEntity)
752 {
753 const auto localRowIdx = mapper_.index(entity);
754 if (!handledDof[localRowIdx])
755 {
756 IdType dofIdxGlobal = gridView_.grid().globalIdSet().id(entity);
757 idToIndex_.emplace(dofIdxGlobal, localRowIdx);
758 indexToID_.emplace(localRowIdx, dofIdxGlobal);
759 }
760 }
761 }
762 }
763 }
764
770 template<class IsGhostFunc>
771 void extendMatrix(Matrix& A, const IsGhostFunc& isGhost)
772 {
773 if constexpr (Detail::canCommunicate<typename GridView::Grid, rowDofCodim>)
774 {
775 if (gridView_.comm().size() <= 1)
776 return;
777
778 // make a copy of the matrix as originally assembled
779 Matrix matrixAsAssembled(A);
780
781 // first get entries in sparsity pattern from other processes
782 std::size_t numNonZeroEntries = 0;
783 std::vector<std::set<int>> sparsityPattern; // column indices for every row
784 MatrixPatternExchange<IsGhostFunc> dataHandle(mapper_, idToIndex_, indexToID_, A, sparsityPattern, isGhost);
785 gridView_.communicate(
786 dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication
787 );
788
789 // add own entries to the sparsity pattern and count number of non-zeros
790 for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt)
791 {
792 const auto colEndIt = A[rowIt.index()].end();
793 for (auto colIt = rowIt->begin(); colIt != colEndIt; ++colIt)
794 if (!sparsityPattern[rowIt.index()].count(colIt.index()))
795 sparsityPattern[rowIt.index()].insert(colIt.index());
796
797 numNonZeroEntries += sparsityPattern[rowIt.index()].size();
798 }
799
800 // insert any additional entries into the matrix
801 A.setSize(matrixAsAssembled.N(), matrixAsAssembled.M(), numNonZeroEntries);
802 A.setBuildMode(Matrix::row_wise);
803 auto citer = A.createbegin();
804 for (auto i = sparsityPattern.begin(), end = sparsityPattern.end(); i!=end; ++i, ++citer)
805 for (auto si = i->begin(), send = i->end(); si!=send; ++si)
806 citer.insert(*si);
807
808 // reset matrix to contain original values
809 A = 0;
810 const auto rowEndIt = matrixAsAssembled.end();
811 for (auto rowIt = matrixAsAssembled.begin(); rowIt != rowEndIt; ++rowIt)
812 for (auto colIt = matrixAsAssembled[rowIt.index()].begin(); colIt != matrixAsAssembled[rowIt.index()].end(); ++colIt)
813 A[rowIt.index()][colIt.index()] = *colIt;
814
815 // The matrix A has now a possible extended sparsity pattern but any additional entries are
816 // initialized to zero and have to be filled by the sumEntries function
817 }
818 else
819 DUNE_THROW(Dune::InvalidStateException, "Cannot call extendMatrix for a grid that cannot communicate codim-" << rowDofCodim << "-entities.");
820 }
821
835 void sumEntries(Matrix& A)
836 {
837 if constexpr (Detail::canCommunicate<typename GridView::Grid, rowDofCodim>)
838 {
839 if (gridView_.comm().size() <= 1)
840 return;
841
842 MatrixEntryExchange dataHandle(mapper_, idToIndex_, indexToID_, A);
843 gridView_.communicate(
844 dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication
845 );
846 }
847 else
848 DUNE_THROW(Dune::InvalidStateException,
849 "Cannot call sumEntries for a grid that cannot communicate codim-" << rowDofCodim << "-entities."
850 );
851 }
852
853private:
854 const GridView gridView_;
855 const RowDofMapper& mapper_;
856 std::map<IdType, int> idToIndex_;
857 std::map<int, IdType> indexToID_;
858
859};
860
864template<class LinearSolverTraits, class ParallelTraits,
865 class Matrix, class ParallelHelper>
866void prepareMatrixParallel(Matrix& A, ParallelHelper& pHelper)
867{
868 if constexpr (ParallelTraits::isNonOverlapping)
869 {
870 // extend the matrix pattern such that it is usable for a parallel solver
871 // and make right-hand side consistent
872 using GridView = typename LinearSolverTraits::GridView;
873 using DofMapper = typename LinearSolverTraits::DofMapper;
874 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
875 ParallelMatrixHelper<Matrix, GridView, DofMapper, dofCodim> matrixHelper(pHelper.gridView(), pHelper.dofMapper());
876 matrixHelper.extendMatrix(A, [&pHelper](auto idx){ return pHelper.isGhost(idx); });
877 matrixHelper.sumEntries(A);
878 }
879}
880
884template<class LinearSolverTraits, class ParallelTraits,
885 class Vector, class ParallelHelper>
886void prepareVectorParallel(Vector& b, ParallelHelper& pHelper)
887{
888 if constexpr (ParallelTraits::isNonOverlapping)
889 {
890 // extend the matrix pattern such that it is usable for a parallel solver
891 // and make right-hand side consistent
892 using GridView = typename LinearSolverTraits::GridView;
893 using DofMapper = typename LinearSolverTraits::DofMapper;
894 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
895 ParallelVectorHelper<GridView, DofMapper, dofCodim> vectorHelper(pHelper.gridView(), pHelper.dofMapper());
896 vectorHelper.makeNonOverlappingConsistent(b);
897 }
898}
899
903template<class LinearSolverTraits, class ParallelTraits,
904 class Matrix, class Vector, class ParallelHelper>
905void prepareLinearAlgebraParallel(Matrix& A, Vector& b, ParallelHelper& pHelper)
906{
907 prepareMatrixParallel<LinearSolverTraits, ParallelTraits>(A, pHelper);
908 prepareVectorParallel<LinearSolverTraits, ParallelTraits>(b, pHelper);
909}
910
914template<class LinearSolverTraits, class ParallelTraits,
915 class Matrix, class Vector, class ParallelHelper>
916void prepareLinearAlgebraParallel(Matrix& A, Vector& b,
917 std::shared_ptr<typename ParallelTraits::Comm>& comm,
918 std::shared_ptr<typename ParallelTraits::LinearOperator>& fop,
919 std::shared_ptr<typename ParallelTraits::ScalarProduct>& sp,
920 ParallelHelper& pHelper)
921{
922 prepareLinearAlgebraParallel<LinearSolverTraits, ParallelTraits>(A, b, pHelper);
923 const auto category = ParallelTraits::isNonOverlapping ?
924 Dune::SolverCategory::nonoverlapping : Dune::SolverCategory::overlapping;
925
926 comm = std::make_shared<typename ParallelTraits::Comm>(pHelper.gridView().comm(), category);
927 pHelper.createParallelIndexSet(*comm);
928 fop = std::make_shared<typename ParallelTraits::LinearOperator>(A, *comm);
929 sp = std::make_shared<typename ParallelTraits::ScalarProduct>(*comm);
930}
931
932} // end namespace Dumux
933
934#endif
const DofMapper & dofMapper() const
Return the dofMapper.
Definition: parallelhelpers.hh:372
ParallelISTLHelperImpl(const GridView &gridView, const DofMapper &mapper)
Definition: parallelhelpers.hh:281
bool isOwned(std::size_t i) const
Definition: parallelhelpers.hh:295
const GridView & gridView() const
Return the gridView.
Definition: parallelhelpers.hh:376
bool isGhost(std::size_t i) const
Definition: parallelhelpers.hh:292
void createParallelIndexSet(Comm &comm) const
Creates a parallel index set for a communicator.
Definition: parallelhelpers.hh:310
Definition: parallelhelpers.hh:29
Helper class for adding up matrix entries for border entities.
Definition: parallelhelpers.hh:520
ParallelMatrixHelper(const GridView &gridView, const RowDofMapper &mapper)
Definition: parallelhelpers.hh:739
void sumEntries(Matrix &A)
Sums up the entries corresponding to border entities (usually vertices or faces)
Definition: parallelhelpers.hh:835
void extendMatrix(Matrix &A, const IsGhostFunc &isGhost)
communicates values for the sparsity pattern of the new matrix.
Definition: parallelhelpers.hh:771
Definition: parallelhelpers.hh:476
void makeNonOverlappingConsistent(Dune::MultiTypeBlockVector< Blocks... > &v) const
Make a vector consistent for non-overlapping domain decomposition methods.
Definition: parallelhelpers.hh:499
ParallelVectorHelper(const GridView &gridView, const DofMapper &mapper)
Definition: parallelhelpers.hh:478
void makeNonOverlappingConsistent(Dune::BlockVector< Block, Alloc > &v) const
Make a vector consistent for non-overlapping domain decomposition methods.
Definition: parallelhelpers.hh:484
A data handle class to exchange entries of a vector.
Definition: vectorcommdatahandle.hh:66
Definition: variablesbackend.hh:31
dune-grid capabilities compatibility layer
Distance implementation details.
Definition: cvfelocalresidual.hh:25
static constexpr bool canCommunicate
Definition: gridcapabilities.hh:51
Definition: adapt.hh:17
void prepareMatrixParallel(Matrix &A, ParallelHelper &pHelper)
Prepare a matrix for parallel solvers.
Definition: parallelhelpers.hh:866
void prepareLinearAlgebraParallel(Matrix &A, Vector &b, ParallelHelper &pHelper)
Prepare linear algebra variables for parallel solvers.
Definition: parallelhelpers.hh:905
LinearSolverTraitsImpl< GridGeometry, typename GridGeometry::DiscretizationMethod > LinearSolverTraits
The type traits required for using the IstlFactoryBackend.
Definition: linearsolvertraits.hh:37
void prepareVectorParallel(Vector &b, ParallelHelper &pHelper)
Prepare a vector for parallel solvers.
Definition: parallelhelpers.hh:886
The implementation is specialized for the different discretizations.
Definition: linearsolvertraits.hh:31
Contains a class to exchange entries of a vector.