version 3.11-dev
Loading...
Searching...
No Matches
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-FileCopyrightText: 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 <algorithm>
16#include <dune/common/exceptions.hh>
17#include <dune/geometry/dimension.hh>
18#include <dune/grid/common/datahandleif.hh>
19#include <dune/grid/common/partitionset.hh>
20#include <dune/grid/common/rangegenerators.hh>
21#include <dune/istl/owneroverlapcopy.hh>
22#include <dune/istl/paamg/pinfo.hh>
23#include <dune/istl/bvector.hh>
24#include <dune/istl/multitypeblockvector.hh>
29
30#include <string>
31#include <utility>
32
33namespace Dumux::Detail {
34
35template<class LinearSolverTraits, bool canCommunicate = false>
37
38template<class LinearSolverTraits>
40{
41 using GridView = typename LinearSolverTraits::GridView;
42 using DofMapper = typename LinearSolverTraits::DofMapper;
43
44 // TODO: this is some large number (replace by limits?)
45 static constexpr std::size_t ghostMarker_ = 1<<24;
46
47 class BaseGatherScatter
48 {
49 static constexpr int numCodims_ = GridView::dimension + 1;
50
51 static constexpr auto getActiveCodims_()
52 {
53 if constexpr (requires { LinearSolverTraits::dofCodims; })
54 return LinearSolverTraits::dofCodims;
55 else
56 return std::bitset<numCodims_>{ 1UL << LinearSolverTraits::dofCodim };
57 }
58
59 public:
60 BaseGatherScatter(const DofMapper& mapper)
61 : mapper_(mapper) {}
62
63 template<class EntityType>
64 int index(const EntityType& e) const
65 { return mapper_.index(e); }
66
67 template<class EntityType>
68 auto indices(const EntityType& e) const
69 { return asMultiMapper(mapper_).indices(e); }
70
71 bool contains(int dim, int codim) const
72 { return codim >= 0 && codim < numCodims_ && activeCodims_.test(codim); }
73
76 bool fixedSize(int dim, int codim) const
77 {
78 if (codim < 0 || codim >= numCodims_ || !activeCodims_.test(codim)) return true;
79 const auto& gtypes = mapper_.types(codim);
80 if (gtypes.empty()) return true;
81 const auto nDofs = mapper_.size(gtypes[0]);
82 for (const auto& gt : gtypes)
83 if (mapper_.size(gt) != nDofs) return false;
84 return true;
85 }
86
88 template<class EntityType>
89 std::size_t size(EntityType& e) const
90 { return asMultiMapper(mapper_).indices(e).size(); }
91
92 template<class EntityType>
93 bool isNeitherInteriorNorBorderEntity(EntityType& e) const
94 { return e.partitionType() != Dune::InteriorEntity && e.partitionType() != Dune::BorderEntity; }
95
96 protected:
97 const DofMapper& mapper_;
98 private:
99 static constexpr auto activeCodims_ = getActiveCodims_();
100 };
101
108 class GhostGatherScatter
109 : public BaseGatherScatter
110 , public Dune::CommDataHandleIF<GhostGatherScatter, std::size_t>
111 {
112 public:
113 using DataType = std::size_t;
114 using BaseGatherScatter::contains;
115 using BaseGatherScatter::fixedSize;
116 using BaseGatherScatter::size;
117
118 GhostGatherScatter(std::vector<std::size_t>& ranks, const DofMapper& mapper)
119 : BaseGatherScatter(mapper)
120 , ranks_(ranks)
121 {}
122
123 template<class MessageBuffer, class EntityType>
124 void gather(MessageBuffer& buff, const EntityType& e) const
125 {
126 const bool isGhost = this->isNeitherInteriorNorBorderEntity(e);
127 for (auto i : this->indices(e)) {
128 auto& data = ranks_[i];
129 if (isGhost) data = ghostMarker_;
130 buff.write(data);
131 }
132 }
133
134 template<class MessageBuffer, class EntityType>
135 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
136 {
137 const bool isGhost = this->isNeitherInteriorNorBorderEntity(e);
138 for (auto i : this->indices(e)) {
139 std::size_t x;
140 buff.read(x);
141 if (isGhost) ranks_[i] = ghostMarker_;
142 }
143 }
144 private:
145 std::vector<std::size_t>& ranks_;
146 };
147
154 class InteriorBorderGatherScatter
155 : public BaseGatherScatter
156 , public Dune::CommDataHandleIF<InteriorBorderGatherScatter, std::size_t>
157 {
158 public:
159 using DataType = std::size_t;
160 using BaseGatherScatter::contains;
161 using BaseGatherScatter::fixedSize;
162 using BaseGatherScatter::size;
163
164 InteriorBorderGatherScatter(std::vector<std::size_t>& ranks, const DofMapper& mapper)
165 : BaseGatherScatter(mapper)
166 , ranks_(ranks)
167 {}
168
172 template<class MessageBuffer, class EntityType>
173 void gather(MessageBuffer& buff, const EntityType& e) const
174 {
175 const bool isGhost = this->isNeitherInteriorNorBorderEntity(e);
176 for (auto i : this->indices(e)) {
177 auto& data = ranks_[i];
178 if (isGhost) data = ghostMarker_;
179 buff.write(data);
180 }
181 }
182
186 template<class MessageBuffer, class EntityType>
187 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
188 {
189 const bool isGhost = this->isNeitherInteriorNorBorderEntity(e);
190 for (auto i : this->indices(e)) {
191 std::size_t x;
192 buff.read(x);
193 auto& data = ranks_[i];
194 // we leave ghost unchanged
195 // for other dofs, the process with the lowest rank
196 // is assigned to be the (unique) owner
197 using std::min;
198 data = isGhost ? x : min(data, x);
199 }
200 }
201 private:
202 std::vector<std::size_t>& ranks_;
203 };
204
209 struct NeighbourGatherScatter
210 : public BaseGatherScatter
211 , public Dune::CommDataHandleIF<NeighbourGatherScatter, int>
212 {
213 using DataType = int;
214 using BaseGatherScatter::contains;
215 using BaseGatherScatter::fixedSize;
216 using BaseGatherScatter::size;
217
218 NeighbourGatherScatter(const DofMapper& mapper, int rank, std::set<int>& neighbours)
219 : BaseGatherScatter(mapper)
220 , rank_(rank)
221 , neighbours_(neighbours)
222 {}
223
224 // NeighbourGatherScatter sends exactly 1 rank value per entity (not per DOF).
225 template<class EntityType>
226 std::size_t size(EntityType& e) const { return 1; }
227 bool fixedSize(int dim, int codim) const { return true; }
228
229 template<class MessageBuffer, class EntityType>
230 void gather(MessageBuffer& buff, const EntityType& e) const
231 {
232 buff.write(rank_);
233 }
234
235 template<class MessageBuffer, class EntityType>
236 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
237 {
238 int x;
239 buff.read(x);
240 neighbours_.insert(x);
241 }
242 private:
243 int rank_;
244 std::set<int>& neighbours_;
245 };
246
251 struct SharedGatherScatter
252 : public BaseGatherScatter
253 , public Dune::CommDataHandleIF<SharedGatherScatter, int>
254 {
255 using DataType = int;
256 using BaseGatherScatter::contains;
257 using BaseGatherScatter::fixedSize;
258 using BaseGatherScatter::size;
259
260 SharedGatherScatter(std::vector<int>& shared, const DofMapper& mapper)
261 : BaseGatherScatter(mapper)
262 , shared_(shared)
263 {}
264
265 template<class MessageBuffer, class EntityType>
266 void gather(MessageBuffer& buff, EntityType& e) const
267 {
268 for (std::size_t k = 0; k < this->indices(e).size(); ++k)
269 buff.write(int(true));
270 }
271
272 template<class MessageBuffer, class EntityType>
273 void scatter(MessageBuffer& buff, const EntityType &e, std::size_t n)
274 {
275 for (auto i : this->indices(e)) {
276 int x;
277 buff.read(x);
278 shared_[i] = shared_[i] || x;
279 }
280 }
281 private:
282 std::vector<int>& shared_;
283 };
284
289 template<typename GlobalIndex>
290 struct GlobalIndexGatherScatter
291 : public BaseGatherScatter
292 , public Dune::CommDataHandleIF<GlobalIndexGatherScatter<GlobalIndex>, GlobalIndex>
293 {
294 using DataType = GlobalIndex;
295 using BaseGatherScatter::contains;
296 using BaseGatherScatter::fixedSize;
297 using BaseGatherScatter::size;
298
299 GlobalIndexGatherScatter(std::vector<GlobalIndex>& globalIndices, const DofMapper& mapper)
300 : BaseGatherScatter(mapper)
301 , globalIndices_(globalIndices)
302 {}
303
304 template<class MessageBuffer, class EntityType>
305 void gather(MessageBuffer& buff, const EntityType& e) const
306 {
307 for (auto i : this->indices(e))
308 buff.write(globalIndices_[i]);
309 }
310
311 template<class MessageBuffer, class EntityType>
312 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
313 {
314 for (auto i : this->indices(e)) {
315 DataType x;
316 buff.read(x);
317 using std::min;
318 globalIndices_[i] = min(globalIndices_[i], x);
319 }
320 }
321 private:
322 std::vector<GlobalIndex>& globalIndices_;
323 };
324
325public:
326
327 ParallelISTLHelperImpl(const GridView& gridView, const DofMapper& mapper)
328 : gridView_(gridView), mapper_(mapper)
329 {
330 if constexpr (LinearSolverTraits::canCommunicate)
331 initGhostsAndOwners_();
332 else
333 DUNE_THROW(Dune::InvalidStateException,
334 "Cannot initialize parallel helper for a grid that cannot communicate."
335 );
336 }
337
338 bool isGhost(std::size_t i) const
339 { return isGhost_[i] == ghostMarker_; }
340
341 bool isOwned(std::size_t i) const
342 { return isOwned_[i] == 1; }
343
355 template<class Comm>
356 void createParallelIndexSet(Comm& comm) const
357 {
358 if constexpr (LinearSolverTraits::canCommunicate)
359 {
360 if (gridView_.comm().size() <= 1)
361 {
362 comm.remoteIndices().template rebuild<false>();
363 return;
364 }
365
366 // First find out which dofs we share with other processors
367 std::vector<int> isShared(mapper_.size(), false);
368 SharedGatherScatter sgs(isShared, mapper_);
369 gridView_.communicate(sgs, Dune::All_All_Interface, Dune::ForwardCommunication);
370
371 // Count shared dofs that we own
372 using GlobalIndex = typename Comm::ParallelIndexSet::GlobalIndex;
373 GlobalIndex count = 0;
374 for (std::size_t i = 0; i < isShared.size(); ++i)
375 if (isShared[i] && isOwned_[i] == 1)
376 ++count;
377
378 std::vector<GlobalIndex> counts(gridView_.comm().size());
379 gridView_.comm().allgather(&count, 1, counts.data());
380
381 // Compute start index start_p = \sum_{i=0}^{i<p} counts_i
382 const int rank = gridView_.comm().rank();
383 auto start = std::accumulate(counts.begin(), counts.begin() + rank, GlobalIndex(0));
384
385 // starting from start (offset), number global indices owned by this process consecutively
386 std::vector<GlobalIndex> globalIndices(mapper_.size(), std::numeric_limits<GlobalIndex>::max());
387 for (std::size_t i = 0; i < globalIndices.size(); ++i)
388 {
389 if (isOwned_[i] == 1 && isShared[i])
390 {
391 globalIndices[i] = start;
392 ++start;
393 }
394 }
395
396 // publish global indices for the shared DOFS to other processors.
397 GlobalIndexGatherScatter<GlobalIndex> gigs(globalIndices, mapper_);
398 gridView_.communicate(gigs, Dune::All_All_Interface, Dune::ForwardCommunication);
399
400 // put the information into the parallel index set
401 resizeAndFillIndexSet_(comm, globalIndices);
402
403 // Compute neighbours using communication
404 std::set<int> neighbours;
405 NeighbourGatherScatter ngs(mapper_, gridView_.comm().rank(), neighbours);
406 gridView_.communicate(ngs, Dune::All_All_Interface, Dune::ForwardCommunication);
407 comm.remoteIndices().setNeighbours(neighbours);
408
409 comm.remoteIndices().template rebuild<false>();
410 }
411 else
412 DUNE_THROW(Dune::InvalidStateException,
413 "Cannot build parallel index set for a grid that cannot communicate."
414 );
415 }
416
418 const DofMapper& dofMapper() const
419 { return mapper_; }
420
422 const GridView& gridView() const
423 { return gridView_; }
424
425private:
434 void initGhostsAndOwners_()
435 {
436 const auto rank = gridView_.comm().rank();
437 isOwned_.assign(mapper_.size(), rank);
438
439 // find out about ghosts
440 GhostGatherScatter ggs(isOwned_, mapper_);
441
442 if (gridView_.comm().size() > 1)
443 gridView_.communicate(ggs, Dune::InteriorBorder_All_Interface, Dune::ForwardCommunication);
444
445 // isGhost_ contains rank when the dof is not on a ghost entity (interior or border)
446 // and ghostMarker_ when the dof is on a ghost
447 isGhost_ = isOwned_;
448
449 // partition interior/border uniquely
450 // after the communication each dof is assigned to one unique owner process rank
451 InteriorBorderGatherScatter dh(isOwned_, mapper_);
452
453 if (gridView_.comm().size() > 1)
454 gridView_.communicate(dh, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication);
455
456 // convert vector into mask vector
457 for (auto& v : isOwned_)
458 v = (v == rank) ? 1 : 0;
459 }
460
461 template<class Comm, class GlobalIndices>
462 void resizeAndFillIndexSet_(Comm& comm, const GlobalIndices& globalIndices) const
463 {
464 comm.indexSet().beginResize();
465
466 // add triplets characterizing each dof in the parallel index set
467 // (globalIndex, (localIndex, attribute)) where attribute is owner, overlap or copy
468 for (std::size_t localIndex = 0; localIndex < globalIndices.size(); ++localIndex)
469 {
470 const auto globalIndex = globalIndices[localIndex];
471 if (globalIndex != std::numeric_limits<typename GlobalIndices::value_type>::max())
472 {
473 const bool isOwned = isOwned_[localIndex] > 0;
474 const auto attr = getAttribute_(comm, isOwned, isGhost(localIndex));
475 using LocalIndex = typename Comm::ParallelIndexSet::LocalIndex;
476 comm.indexSet().add(globalIndex, LocalIndex{localIndex, attr});
477 }
478 }
479
480 comm.indexSet().endResize();
481 }
482
483 template<class Comm>
484 Dune::OwnerOverlapCopyAttributeSet::AttributeSet
485 getAttribute_(const Comm& comm, const bool isOwned, const bool isGhost) const
486 {
487 if (isOwned) // this process owns the dof (uniquely)
488 return Dune::OwnerOverlapCopyAttributeSet::owner;
489 else if (isGhost && (comm.category() == Dune::SolverCategory::nonoverlapping) )
490 return Dune::OwnerOverlapCopyAttributeSet::overlap;
491 else
492 return Dune::OwnerOverlapCopyAttributeSet::copy;
493 }
494
495 const GridView gridView_;
496 const DofMapper& mapper_;
498 std::vector<std::size_t> isOwned_;
500 std::vector<std::size_t> isGhost_;
501
502};
503
504} // end namespace Dumux::Detail
505
506namespace Dumux {
507
513template<class LinearSolverTraits>
516 LinearSolverTraits, LinearSolverTraits::canCommunicate
517 >;
518
519template<class GridView, class DofMapper, int dofCodim>
521{
522public:
523 ParallelVectorHelper(const GridView& gridView, const DofMapper& mapper)
524 : gridView_(gridView), mapper_(mapper)
525 {}
526
528 template<class Block, class Alloc>
529 void makeNonOverlappingConsistent(Dune::BlockVector<Block, Alloc>& v) const
530 {
531 if constexpr (Dune::Capabilities::canCommunicate<typename GridView::Traits::Grid, dofCodim>::v)
532 {
534 if (gridView_.comm().size() > 1)
535 gridView_.communicate(gs, Dune::InteriorBorder_InteriorBorder_Interface,
536 Dune::ForwardCommunication);
537 }
538 else
539 DUNE_THROW(Dune::InvalidStateException, "Cannot call makeNonOverlappingConsistent for a grid that cannot communicate codim-" << dofCodim << "-entities.");
540 }
541
543 template<class Block, class Alloc>
544 void makeOverlappingConsistent(Dune::BlockVector<Block, Alloc>& v) const
545 {
546 if constexpr (Dune::Capabilities::canCommunicate<typename GridView::Traits::Grid, dofCodim>::v)
547 {
548 // Iterate over the gridView_ to make overlap entries 0. This is necessary to make
549 // `VectorCommDataHandleSum` work properly.
550 for (const auto& element : elements(gridView_))
551 if (element.partitionType() == Dune::OverlapEntity)
552 v[gridView_.indexSet().index(element)] = 0;
553
554 if (gridView_.comm().size() > 1)
555 {
557 gridView_.communicate(gs, Dune::Overlap_All_Interface,
558 Dune::ForwardCommunication);
559 }
560 }
561 else
562 DUNE_THROW(Dune::InvalidStateException, "Cannot call makeNonOverlappingConsistent for a grid that cannot communicate codim-" << dofCodim << "-entities.");
563 }
564
566 template<class... Blocks>
568 {
569 DUNE_THROW(Dune::NotImplemented, "makeNonOverlappingConsistent for Dune::MultiTypeBlockVector");
570 }
571
572private:
573 const GridView gridView_;
574 const DofMapper& mapper_;
575};
576
577template<class GridView, class DofMapper>
579{
580public:
581 MultiCodimParallelVectorHelper(const GridView& gridView, const DofMapper& mapper)
582 : gridView_(gridView), mapper_(mapper)
583 {}
584
586 template<class Block, class Alloc, std::size_t numCodims>
588 Dune::BlockVector<Block, Alloc>& v,
589 const std::bitset<numCodims>& activeCodims
590 ) const
591 {
592 static_assert(numCodims == GridView::dimension + 1,
593 "Number of codims must match GridView::dimension+1");
594
595 if (gridView_.comm().size() > 1)
596 {
598 mapper_, v, activeCodims
599 );
600 gridView_.communicate(gs, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication);
601 }
602 }
603
605 template<class Block, class Alloc, std::size_t numCodims>
607 Dune::BlockVector<Block, Alloc>& v,
608 const std::bitset<numCodims>& activeCodims
609 ) const
610 {
611 static_assert(numCodims == GridView::dimension + 1,
612 "Number of codims must match GridView::dimension+1");
613
614 zeroOverlapEntries_<0>(v, activeCodims);
615
616 if (gridView_.comm().size() > 1)
617 {
619 mapper_, v, activeCodims
620 );
621 gridView_.communicate(gs, Dune::Overlap_All_Interface, Dune::ForwardCommunication);
622 }
623 }
624
625private:
626 template<int codim, class Block, class Alloc, std::size_t numCodims>
627 void zeroOverlapEntries_(Dune::BlockVector<Block, Alloc>& v,
628 const std::bitset<numCodims>& activeCodims) const
629 {
630 if constexpr (codim <= GridView::dimension)
631 {
632 if (activeCodims.test(codim))
633 {
634 for (const auto& element : elements(gridView_))
635 {
636 for (int i = 0; i < element.subEntities(codim); ++i)
637 {
638 const auto entity = element.template subEntity<codim>(i);
639 if (entity.partitionType() == Dune::OverlapEntity)
640 for (auto i : asMultiMapper(mapper_).indices(entity))
641 v[i] = 0;
642 }
643 }
644 }
645
646 zeroOverlapEntries_<codim + 1>(v, activeCodims);
647 }
648 }
649
650 const GridView gridView_;
651 const DofMapper& mapper_;
652};
653
662template<class Matrix, class GridView,
663 class RowDofMapper, int rowDofCodim>
665{
666 using IdType = typename GridView::Traits::Grid::Traits::GlobalIdSet::IdType;
667
668 struct DofIdKey
669 {
670 int codim;
671 IdType id;
672
673 friend bool operator<(const DofIdKey& a, const DofIdKey& b)
674 {
675 if (a.codim != b.codim)
676 return a.codim < b.codim;
677 return a.id < b.id;
678 }
679 };
680
702 template<class ColIsGhostFunc>
703 struct MatrixPatternExchange
704 : public Dune::CommDataHandleIF<MatrixPatternExchange<ColIsGhostFunc>, DofIdKey>
705 {
707 using DataType = DofIdKey;
708
719 MatrixPatternExchange(const RowDofMapper& rowEntityMapper,
720 const std::map<DofIdKey,int>& globalToLocal,
721 const std::map<int,DofIdKey>& localToGlobal,
722 Matrix& A,
723 std::vector<std::set<int>>& sparsityPattern,
724 const ColIsGhostFunc& isGhostColumDof)
725 : rowEntityMapper_(rowEntityMapper)
726 , idToIndex_(globalToLocal), indexToID_(localToGlobal)
727 , sparsityPattern_(sparsityPattern), A_(A), isGhostColumDof_(isGhostColumDof)
728 {
729 sparsityPattern_.resize(A.N());
730 }
731
735 bool contains (int dim, int codim) const
736 { return (codim == rowDofCodim); }
737
739 bool fixedSize(int dim, int codim) const
740 { return false; }
741
745 template<class EntityType>
746 std::size_t size(EntityType& e) const
747 {
748 const auto rowIdx = rowEntityMapper_.index(e);
749
750 // all column entity indices of this row that are in the index set
751 std::size_t n = 0;
752 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
753 {
754 if (indexToID_.count(colIt.index()))
755 ++n;
756 }
757
758 return n;
759 }
760
764 template<class MessageBuffer, class EntityType>
765 void gather(MessageBuffer& buff, const EntityType& e) const
766 {
767 const auto rowIdx = rowEntityMapper_.index(e);
768
769 // send all column entity ids of this row that are in the index set
770 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
771 {
772 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
773 buff.write(it->second);
774 }
775 }
776
780 template<class MessageBuffer, class EntityType>
781 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
782 {
783 const auto rowIdx = rowEntityMapper_.index(e);
784 for (std::size_t k = 0; k < n; k++)
785 {
786 // receive n column entity IDs
787 DofIdKey key;
788 buff.read(key);
789
790 // only add entries that are contained in the index set
791 if (const auto it = idToIndex_.find(key); it != idToIndex_.end())
792 {
793 const auto colIdx = it->second;
794 if (!isGhostColumDof_(colIdx))
795 sparsityPattern_[rowIdx].insert(colIdx);
796 }
797 }
798 }
799
800 private:
801 const RowDofMapper& rowEntityMapper_;
802 const std::map<DofIdKey, int>& idToIndex_;
803 const std::map<int, DofIdKey>& indexToID_;
804 std::vector<std::set<int>>& sparsityPattern_;
805 Matrix& A_;
806 const ColIsGhostFunc& isGhostColumDof_;
807
808 }; // class MatrixPatternExchange
809
811 struct MatrixEntry
812 {
813 DofIdKey first;
814 typename Matrix::block_type second;
815 };
816
818 struct MatrixEntryExchange
819 : public Dune::CommDataHandleIF<MatrixEntryExchange, MatrixEntry>
820 {
822 using DataType = MatrixEntry;
823
824 MatrixEntryExchange(const RowDofMapper& rowEntityMapper,
825 const std::map<DofIdKey, int>& globalToLocal,
826 const std::map<int, DofIdKey>& localToGlobal,
827 Matrix& A)
828 : rowEntityMapper_(rowEntityMapper)
829 , idToIndex_(globalToLocal), indexToID_(localToGlobal)
830 , A_(A)
831 {}
832
836 bool contains(int dim, int codim) const
837 { return (codim == rowDofCodim); }
838
840 bool fixedSize(int dim, int codim) const
841 { return false; }
842
846 template<class EntityType>
847 std::size_t size(EntityType& e) const
848 {
849 const auto rowIdx = rowEntityMapper_.index(e);
850 std::size_t n = 0;
851 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
852 {
853 if (indexToID_.count(colIt.index()))
854 ++n;
855 }
856
857 return n;
858 }
859
863 template<class MessageBuffer, class EntityType>
864 void gather(MessageBuffer& buff, const EntityType& e) const
865 {
866 const auto rowIdx = rowEntityMapper_.index(e);
867 // send all matrix entries for which the column index is in the index set
868 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
869 {
870 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
871 buff.write(MatrixEntry{ it->second, *colIt });
872 }
873 }
874
878 template<class MessageBuffer, class EntityType>
879 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
880 {
881 const auto rowIdx = rowEntityMapper_.index(e);
882 for (std::size_t k = 0; k < n; k++)
883 {
884 MatrixEntry m;
885 buff.read(m);
886 const auto& [colDofID, matrixBlock] = m; // unpack
887
888 // only add entries in the index set and for which A has allocated memory
889 if (auto it = idToIndex_.find(colDofID); it != idToIndex_.end())
890 {
891 if (A_[rowIdx].find(it->second) != A_[rowIdx].end())
892 A_[rowIdx][it->second] += matrixBlock;
893 }
894 }
895 }
896
897 private:
898 const RowDofMapper& rowEntityMapper_;
899 const std::map<DofIdKey, int>& idToIndex_;
900 const std::map<int, DofIdKey>& indexToID_;
901 Matrix& A_;
902
903 }; // class MatrixEntryExchange
904
905public:
906
907 ParallelMatrixHelper(const GridView& gridView, const RowDofMapper& mapper)
908 : gridView_(gridView), mapper_(mapper)
909 {
910 idToIndex_.clear();
911 indexToID_.clear();
912
914 }
915
916 template<int codim>
918 {
919 if constexpr (codim <= GridView::dimension)
920 {
921 // the mapper only provides indices for the codims carrying dofs
922 if (!mapper_.types(codim).empty())
923 {
924 for (const auto& element : elements(gridView_))
925 {
926 for (int i = 0; i < element.subEntities(codim); ++i)
927 {
928 const auto entity = element.template subEntity<codim>(i);
929 if (entity.partitionType() == Dune::BorderEntity)
930 {
931 const auto localIdx = mapper_.index(entity);
932 const DofIdKey key{codim, gridView_.grid().globalIdSet().id(entity)};
933 idToIndex_.emplace(key, localIdx);
934 indexToID_.emplace(localIdx, key);
935 }
936 }
937 }
938 }
939
941 }
942 }
943
949 template<class IsGhostFunc>
950 void extendMatrix(Matrix& A, const IsGhostFunc& isGhost)
951 {
952 if constexpr (Dune::Capabilities::canCommunicate<typename GridView::Grid, rowDofCodim>::v)
953 {
954 if (gridView_.comm().size() <= 1)
955 return;
956
957 // make a copy of the matrix as originally assembled
958 Matrix matrixAsAssembled(A);
959
960 // first get entries in sparsity pattern from other processes
961 std::size_t numNonZeroEntries = 0;
962 std::vector<std::set<int>> sparsityPattern; // column indices for every row
963 MatrixPatternExchange<IsGhostFunc> dataHandle(mapper_, idToIndex_, indexToID_, A, sparsityPattern, isGhost);
964 gridView_.communicate(
965 dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication
966 );
967
968 // add own entries to the sparsity pattern and count number of non-zeros
969 for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt)
970 {
971 const auto colEndIt = A[rowIt.index()].end();
972 for (auto colIt = rowIt->begin(); colIt != colEndIt; ++colIt)
973 if (!sparsityPattern[rowIt.index()].count(colIt.index()))
974 sparsityPattern[rowIt.index()].insert(colIt.index());
975
976 numNonZeroEntries += sparsityPattern[rowIt.index()].size();
977 }
978
979 // insert any additional entries into the matrix
980 A.setSize(matrixAsAssembled.N(), matrixAsAssembled.M(), numNonZeroEntries);
981 A.setBuildMode(Matrix::row_wise);
982 auto citer = A.createbegin();
983 for (auto i = sparsityPattern.begin(), end = sparsityPattern.end(); i!=end; ++i, ++citer)
984 for (auto si = i->begin(), send = i->end(); si!=send; ++si)
985 citer.insert(*si);
986
987 // reset matrix to contain original values
988 A = 0;
989 const auto rowEndIt = matrixAsAssembled.end();
990 for (auto rowIt = matrixAsAssembled.begin(); rowIt != rowEndIt; ++rowIt)
991 for (auto colIt = matrixAsAssembled[rowIt.index()].begin(); colIt != matrixAsAssembled[rowIt.index()].end(); ++colIt)
992 A[rowIt.index()][colIt.index()] = *colIt;
993
994 // The matrix A has now a possible extended sparsity pattern but any additional entries are
995 // initialized to zero and have to be filled by the sumEntries function
996 }
997 else
998 DUNE_THROW(Dune::InvalidStateException, "Cannot call extendMatrix for a grid that cannot communicate codim-" << rowDofCodim << "-entities.");
999 }
1000
1014 void sumEntries(Matrix& A)
1015 {
1016 if constexpr (Dune::Capabilities::canCommunicate<typename GridView::Grid, rowDofCodim>::v)
1017 {
1018 if (gridView_.comm().size() <= 1)
1019 return;
1020
1021 MatrixEntryExchange dataHandle(mapper_, idToIndex_, indexToID_, A);
1022 gridView_.communicate(
1023 dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication
1024 );
1025 }
1026 else
1027 DUNE_THROW(Dune::InvalidStateException,
1028 "Cannot call sumEntries for a grid that cannot communicate codim-" << rowDofCodim << "-entities."
1029 );
1030 }
1031
1032private:
1033 const GridView gridView_;
1034 const RowDofMapper& mapper_;
1035 std::map<DofIdKey, int> idToIndex_;
1036 std::map<int, DofIdKey> indexToID_;
1037
1038};
1039
1044template<class Matrix, class GridView, class DofMapper, std::size_t numCodims>
1046{
1047 using IdType = typename GridView::Traits::Grid::Traits::GlobalIdSet::IdType;
1048
1049 struct DofIdKey
1050 {
1051 int codim;
1052 IdType id;
1053 int subIndex;
1054
1055 friend bool operator<(const DofIdKey& a, const DofIdKey& b)
1056 {
1057 if (a.codim != b.codim)
1058 return a.codim < b.codim;
1059 if (a.id != b.id)
1060 return a.id < b.id;
1061 return a.subIndex < b.subIndex;
1062 }
1063 };
1064
1065 // Each sent item encodes which row DOF within the entity and which column DOF.
1066 // This handles multi-DOF entities (e.g. PQ3 edges with 2 DOFs) correctly.
1067 struct PatternEntry
1068 {
1069 int rowSubIndex;
1070 DofIdKey colKey;
1071 };
1072
1073 template<class ColIsGhostFunc>
1074 struct MatrixPatternExchange
1075 : public Dune::CommDataHandleIF<MatrixPatternExchange<ColIsGhostFunc>, PatternEntry>
1076 {
1077 using DataType = PatternEntry;
1078
1079 MatrixPatternExchange(const DofMapper& dofMapper,
1080 const std::map<DofIdKey, int>& globalToLocal,
1081 const std::map<int, DofIdKey>& localToGlobal,
1082 Matrix& A,
1083 std::vector<std::set<int>>& sparsityPattern,
1084 const ColIsGhostFunc& isGhostColumDof,
1085 const std::bitset<numCodims>& activeCodims)
1086 : dofMapper_(dofMapper)
1087 , idToIndex_(globalToLocal)
1088 , indexToID_(localToGlobal)
1089 , sparsityPattern_(sparsityPattern)
1090 , A_(A)
1091 , isGhostColumDof_(isGhostColumDof)
1092 , activeCodims_(activeCodims)
1093 {
1094 sparsityPattern_.resize(A.N());
1095 }
1096
1097 bool contains(int dim, int codim) const
1098 {
1099 if (codim < 0 || codim >= static_cast<int>(numCodims))
1100 return false;
1101 return activeCodims_.test(codim);
1102 }
1103
1104 bool fixedSize(int dim, int codim) const
1105 { return false; }
1106
1108 template<class EntityType>
1109 std::size_t size(EntityType& e) const
1110 {
1111 std::size_t n = 0;
1112 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1113 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1114 if (indexToID_.count(colIt.index()))
1115 ++n;
1116 return n;
1117 }
1118
1120 template<class MessageBuffer, class EntityType>
1121 void gather(MessageBuffer& buff, const EntityType& e) const
1122 {
1123 int rowSub = 0;
1124 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1125 {
1126 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1127 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
1128 buff.write(PatternEntry{rowSub, it->second});
1129 ++rowSub;
1130 }
1131 }
1132
1134 template<class MessageBuffer, class EntityType>
1135 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
1136 {
1137 const auto baseIdx = dofMapper_.index(e);
1138 for (std::size_t k = 0; k < n; k++)
1139 {
1140 PatternEntry entry;
1141 buff.read(entry);
1142 const auto rowIdx = baseIdx + entry.rowSubIndex;
1143 if (const auto it = idToIndex_.find(entry.colKey); it != idToIndex_.end())
1144 {
1145 const auto colIdx = it->second;
1146 if (!isGhostColumDof_(colIdx))
1147 sparsityPattern_[rowIdx].insert(colIdx);
1148 }
1149 }
1150 }
1151
1152 private:
1153 const DofMapper& dofMapper_;
1154 const std::map<DofIdKey, int>& idToIndex_;
1155 const std::map<int, DofIdKey>& indexToID_;
1156 std::vector<std::set<int>>& sparsityPattern_;
1157 Matrix& A_;
1158 const ColIsGhostFunc& isGhostColumDof_;
1159 const std::bitset<numCodims>& activeCodims_;
1160 };
1161
1162 struct MatrixEntry
1163 {
1164 int rowSubIndex;
1165 DofIdKey colKey;
1166 typename Matrix::block_type block;
1167 };
1168
1169 struct MatrixEntryExchange
1170 : public Dune::CommDataHandleIF<MatrixEntryExchange, MatrixEntry>
1171 {
1172 using DataType = MatrixEntry;
1173
1174 MatrixEntryExchange(const DofMapper& dofMapper,
1175 const std::map<DofIdKey, int>& globalToLocal,
1176 const std::map<int, DofIdKey>& localToGlobal,
1177 Matrix& A,
1178 const std::bitset<numCodims>& activeCodims)
1179 : dofMapper_(dofMapper)
1180 , idToIndex_(globalToLocal)
1181 , indexToID_(localToGlobal)
1182 , A_(A)
1183 , activeCodims_(activeCodims)
1184 {}
1185
1186 bool contains(int dim, int codim) const
1187 {
1188 if (codim < 0 || codim >= static_cast<int>(numCodims))
1189 return false;
1190 return activeCodims_.test(codim);
1191 }
1192
1193 bool fixedSize(int dim, int codim) const
1194 { return false; }
1195
1197 template<class EntityType>
1198 std::size_t size(EntityType& e) const
1199 {
1200 std::size_t n = 0;
1201 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1202 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1203 if (indexToID_.count(colIt.index()))
1204 ++n;
1205 return n;
1206 }
1207
1209 template<class MessageBuffer, class EntityType>
1210 void gather(MessageBuffer& buff, const EntityType& e) const
1211 {
1212 int rowSub = 0;
1213 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1214 {
1215 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1216 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
1217 buff.write(MatrixEntry{rowSub, it->second, *colIt});
1218 ++rowSub;
1219 }
1220 }
1221
1223 template<class MessageBuffer, class EntityType>
1224 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
1225 {
1226 const auto baseIdx = dofMapper_.index(e);
1227 for (std::size_t k = 0; k < n; k++)
1228 {
1229 MatrixEntry m;
1230 buff.read(m);
1231 const auto rowIdx = baseIdx + m.rowSubIndex;
1232 if (auto it = idToIndex_.find(m.colKey); it != idToIndex_.end())
1233 {
1234 if (A_[rowIdx].find(it->second) != A_[rowIdx].end())
1235 A_[rowIdx][it->second] += m.block;
1236 }
1237 }
1238 }
1239
1240 private:
1241 const DofMapper& dofMapper_;
1242 const std::map<DofIdKey, int>& idToIndex_;
1243 const std::map<int, DofIdKey>& indexToID_;
1244 Matrix& A_;
1245 const std::bitset<numCodims>& activeCodims_;
1246 };
1247
1248public:
1249 // Standard constructor: only communicates border-entity DOF couplings.
1250 // Suitable for iterative solvers (ISTL AMG) where ghost DOF equations
1251 // are handled separately by the parallel operator mechanism.
1252 MultiCodimParallelMatrixHelper(const GridView& gridView,
1253 const DofMapper& mapper,
1254 const std::bitset<numCodims>& activeCodims)
1255 : gridView_(gridView)
1256 , mapper_(mapper)
1257 , activeCodims_(activeCodims)
1258 , includeGhostAndAdjacent_(false)
1259 , commInterface_(Dune::InteriorBorder_InteriorBorder_Interface)
1260 {
1261 initMapsForCodim_<0>();
1262 }
1263
1264 // Extended constructor for direct solvers (e.g. Trilinos/MUMPS):
1265 // also includes ghost entities and boundary-adjacent interior entities
1266 // so that element-interior DOF column entries in border DOF matrix rows
1267 // are correctly communicated across ranks.
1268 // Uses All_All_Interface so that ghost entities (GhostEntity on non-owner
1269 // rank) can participate in the scatter step and receive data from owners.
1270 MultiCodimParallelMatrixHelper(const GridView& gridView,
1271 const DofMapper& mapper,
1272 const std::bitset<numCodims>& activeCodims,
1273 bool includeGhostAndAdjacent)
1274 : gridView_(gridView)
1275 , mapper_(mapper)
1276 , activeCodims_(activeCodims)
1277 , includeGhostAndAdjacent_(includeGhostAndAdjacent)
1278 // InteriorBorder_All_Interface: owner (Interior/Border) gathers and
1279 // sends; ghost (All) scatters and receives. This propagates the
1280 // owner's physical stiffness to ghost DOFs without sending ghost-
1281 // treatment (identity) entries from the non-owner back to the owner.
1282 , commInterface_(includeGhostAndAdjacent ? Dune::InteriorBorder_All_Interface
1283 : Dune::InteriorBorder_InteriorBorder_Interface)
1284 {
1285 initMapsForCodim_<0>();
1286 }
1287
1288 template<class IsGhostFunc>
1289 void extendMatrix(Matrix& A, const IsGhostFunc& isGhost)
1290 {
1291 if (gridView_.comm().size() <= 1)
1292 return;
1293
1294 Matrix matrixAsAssembled(A);
1295 std::size_t numNonZeroEntries = 0;
1296 std::vector<std::set<int>> sparsityPattern;
1297 MatrixPatternExchange<IsGhostFunc> dataHandle(mapper_, idToIndex_, indexToID_, A, sparsityPattern, isGhost, activeCodims_);
1298 gridView_.communicate(dataHandle, commInterface_, Dune::ForwardCommunication);
1299
1300 for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt)
1301 {
1302 const auto colEndIt = A[rowIt.index()].end();
1303 for (auto colIt = rowIt->begin(); colIt != colEndIt; ++colIt)
1304 {
1305 if (!sparsityPattern[rowIt.index()].count(colIt.index()))
1306 sparsityPattern[rowIt.index()].insert(colIt.index());
1307 }
1308
1309 numNonZeroEntries += sparsityPattern[rowIt.index()].size();
1310 }
1311
1312 A.setSize(matrixAsAssembled.N(), matrixAsAssembled.M(), numNonZeroEntries);
1313 A.setBuildMode(Matrix::row_wise);
1314 auto citer = A.createbegin();
1315 for (auto i = sparsityPattern.begin(), end = sparsityPattern.end(); i != end; ++i, ++citer)
1316 for (auto si = i->begin(), send = i->end(); si != send; ++si)
1317 citer.insert(*si);
1318
1319 A = 0;
1320 const auto rowEndIt = matrixAsAssembled.end();
1321 for (auto rowIt = matrixAsAssembled.begin(); rowIt != rowEndIt; ++rowIt)
1322 for (auto colIt = matrixAsAssembled[rowIt.index()].begin(); colIt != matrixAsAssembled[rowIt.index()].end(); ++colIt)
1323 A[rowIt.index()][colIt.index()] = *colIt;
1324 }
1325
1326 void sumEntries(Matrix& A)
1327 {
1328 if (gridView_.comm().size() <= 1)
1329 return;
1330
1331 MatrixEntryExchange dataHandle(mapper_, idToIndex_, indexToID_, A, activeCodims_);
1332 gridView_.communicate(dataHandle, commInterface_, Dune::ForwardCommunication);
1333 }
1334
1335private:
1336 template<std::size_t codim>
1337 void initMapsForCodim_()
1338 {
1339 if constexpr (codim <= GridView::dimension)
1340 {
1341 if (activeCodims_.test(codim))
1342 {
1343 for (const auto& element : elements(gridView_))
1344 {
1345 for (int i = 0; i < element.subEntities(codim); ++i)
1346 {
1347 const auto entity = element.template subEntity<codim>(i);
1348 const auto pt = entity.partitionType();
1349
1350 // elements are never border entities, and the interior dofs of an element at the
1351 // processor border can be columns of border rows on the neighbouring process
1352 bool shouldProcess = (codim == 0) || (pt == Dune::BorderEntity)
1353 || (pt == Dune::InteriorEntity && elementHasBorderSubEntity_(element));
1354
1355 // the extended mode for direct solvers also includes ghost dofs
1356 if (!shouldProcess && includeGhostAndAdjacent_)
1357 shouldProcess = (pt == Dune::GhostEntity);
1358
1359 if (shouldProcess)
1360 {
1361 // Use asMultiMapper(mapper_).indices(entity) to handle multi-DOF entities
1362 // (e.g. PQ3 with 2 DOFs per edge). Each DOF gets a unique
1363 // DofIdKey that encodes both the entity ID and the DOF sub-index.
1364 const auto globalId = gridView_.grid().globalIdSet().id(entity);
1365 int subIdx = 0;
1366 for (auto dofIdx : asMultiMapper(mapper_).indices(entity))
1367 {
1368 const DofIdKey key{static_cast<int>(codim), globalId, subIdx};
1369 idToIndex_.emplace(key, dofIdx);
1370 indexToID_.emplace(dofIdx, key);
1371 ++subIdx;
1372 }
1373 }
1374 }
1375 }
1376 }
1377
1378 initMapsForCodim_<codim + 1>();
1379 }
1380 }
1381
1382 // Helper: returns true if element has at least one BorderEntity sub-entity
1383 template<class Element>
1384 static bool elementHasBorderSubEntity_(const Element& element)
1385 {
1386 for (int i = 0; i < element.subEntities(1); ++i)
1387 if (element.template subEntity<1>(i).partitionType() == Dune::BorderEntity)
1388 return true;
1389 if constexpr (Element::mydimension >= 2)
1390 for (int i = 0; i < element.subEntities(2); ++i)
1391 if (element.template subEntity<2>(i).partitionType() == Dune::BorderEntity)
1392 return true;
1393 if constexpr (Element::mydimension >= 3)
1394 for (int i = 0; i < element.subEntities(3); ++i)
1395 if (element.template subEntity<3>(i).partitionType() == Dune::BorderEntity)
1396 return true;
1397 return false;
1398 }
1399
1400 const GridView gridView_;
1401 const DofMapper& mapper_;
1402 std::bitset<numCodims> activeCodims_;
1403 bool includeGhostAndAdjacent_;
1404 Dune::InterfaceType commInterface_;
1405 std::map<DofIdKey, int> idToIndex_;
1406 std::map<int, DofIdKey> indexToID_;
1407};
1408
1412template<class LinearSolverTraits, class ParallelTraits,
1413 class Matrix, class ParallelHelper>
1414void prepareMatrixParallel(Matrix& A, ParallelHelper& pHelper)
1415{
1416 if constexpr (ParallelTraits::isNonOverlapping)
1417 {
1418 using GridView = typename LinearSolverTraits::GridView;
1419 using DofMapper = typename LinearSolverTraits::DofMapper;
1420
1421 if constexpr (requires { LinearSolverTraits::dofCodims; })
1422 {
1423 constexpr auto dofCodims = LinearSolverTraits::dofCodims;
1425 pHelper.gridView(), pHelper.dofMapper(), dofCodims
1426 );
1427 matrixHelper.extendMatrix(A, [&pHelper](auto idx){ return pHelper.isGhost(idx); });
1428 matrixHelper.sumEntries(A);
1429 }
1430 else
1431 {
1432 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
1433 ParallelMatrixHelper<Matrix, GridView, DofMapper, dofCodim> matrixHelper(pHelper.gridView(), pHelper.dofMapper());
1434 matrixHelper.extendMatrix(A, [&pHelper](auto idx){ return pHelper.isGhost(idx); });
1435 matrixHelper.sumEntries(A);
1436 }
1437 }
1438}
1439
1443template<class LinearSolverTraits, class ParallelTraits,
1444 class Vector, class ParallelHelper>
1445void prepareVectorParallel(Vector& b, ParallelHelper& pHelper)
1446{
1447 if constexpr (ParallelTraits::isNonOverlapping)
1448 {
1449 using GridView = typename LinearSolverTraits::GridView;
1450 using DofMapper = typename LinearSolverTraits::DofMapper;
1451
1452 if constexpr (requires { LinearSolverTraits::dofCodims; })
1453 {
1454 MultiCodimParallelVectorHelper<GridView, DofMapper> vectorHelper(pHelper.gridView(), pHelper.dofMapper());
1455 vectorHelper.makeNonOverlappingConsistent(b, LinearSolverTraits::dofCodims);
1456 }
1457 else
1458 {
1459 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
1460 ParallelVectorHelper<GridView, DofMapper, dofCodim> vectorHelper(pHelper.gridView(), pHelper.dofMapper());
1461 vectorHelper.makeNonOverlappingConsistent(b);
1462 }
1463 }
1464}
1465
1469template<class LinearSolverTraits, class ParallelTraits,
1470 class Matrix, class Vector, class ParallelHelper>
1471void prepareLinearAlgebraParallel(Matrix& A, Vector& b, ParallelHelper& pHelper)
1472{
1475}
1476
1480template<class LinearSolverTraits, class ParallelTraits,
1481 class Matrix, class Vector, class ParallelHelper>
1482void prepareLinearAlgebraParallel(Matrix& A, Vector& b,
1483 std::shared_ptr<typename ParallelTraits::Comm>& comm,
1484 std::shared_ptr<typename ParallelTraits::LinearOperator>& fop,
1485 std::shared_ptr<typename ParallelTraits::ScalarProduct>& sp,
1486 ParallelHelper& pHelper)
1487{
1489 const auto category = ParallelTraits::isNonOverlapping ?
1490 Dune::SolverCategory::nonoverlapping : Dune::SolverCategory::overlapping;
1491
1492 comm = std::make_shared<typename ParallelTraits::Comm>(pHelper.gridView().comm(), category);
1493 pHelper.createParallelIndexSet(*comm);
1494 fop = std::make_shared<typename ParallelTraits::LinearOperator>(A, *comm);
1495 sp = std::make_shared<typename ParallelTraits::ScalarProduct>(*comm);
1496}
1497
1498} // end namespace Dumux
1499
1500#endif
const DofMapper & dofMapper() const
Return the dofMapper.
Definition parallelhelpers.hh:418
ParallelISTLHelperImpl(const GridView &gridView, const DofMapper &mapper)
Definition parallelhelpers.hh:327
bool isOwned(std::size_t i) const
Definition parallelhelpers.hh:341
const GridView & gridView() const
Return the gridView.
Definition parallelhelpers.hh:422
bool isGhost(std::size_t i) const
Definition parallelhelpers.hh:338
void createParallelIndexSet(Comm &comm) const
Creates a parallel index set for a communicator.
Definition parallelhelpers.hh:356
Definition parallelhelpers.hh:36
Dedicated helper that exchanges matrix pattern and entries for multiple active codims in one pass.
Definition parallelhelpers.hh:1046
void sumEntries(Matrix &A)
Definition parallelhelpers.hh:1326
MultiCodimParallelMatrixHelper(const GridView &gridView, const DofMapper &mapper, const std::bitset< numCodims > &activeCodims)
Definition parallelhelpers.hh:1252
MultiCodimParallelMatrixHelper(const GridView &gridView, const DofMapper &mapper, const std::bitset< numCodims > &activeCodims, bool includeGhostAndAdjacent)
Definition parallelhelpers.hh:1270
void extendMatrix(Matrix &A, const IsGhostFunc &isGhost)
Definition parallelhelpers.hh:1289
Definition parallelhelpers.hh:579
MultiCodimParallelVectorHelper(const GridView &gridView, const DofMapper &mapper)
Definition parallelhelpers.hh:581
void makeOverlappingConsistent(Dune::BlockVector< Block, Alloc > &v, const std::bitset< numCodims > &activeCodims) const
Make a vector consistent for overlapping domain decomposition methods.
Definition parallelhelpers.hh:606
void makeNonOverlappingConsistent(Dune::BlockVector< Block, Alloc > &v, const std::bitset< numCodims > &activeCodims) const
Make a vector consistent for non-overlapping domain decomposition methods.
Definition parallelhelpers.hh:587
Helper class for adding up matrix entries for border entities.
Definition parallelhelpers.hh:665
ParallelMatrixHelper(const GridView &gridView, const RowDofMapper &mapper)
Definition parallelhelpers.hh:907
void sumEntries(Matrix &A)
Sums up the entries corresponding to border entities (usually vertices or faces).
Definition parallelhelpers.hh:1014
void initMapsForCodim_()
Definition parallelhelpers.hh:917
void extendMatrix(Matrix &A, const IsGhostFunc &isGhost)
communicates values for the sparsity pattern of the new matrix.
Definition parallelhelpers.hh:950
Definition parallelhelpers.hh:521
void makeNonOverlappingConsistent(Dune::MultiTypeBlockVector< Blocks... > &v) const
Make a vector consistent for non-overlapping domain decomposition methods.
Definition parallelhelpers.hh:567
ParallelVectorHelper(const GridView &gridView, const DofMapper &mapper)
Definition parallelhelpers.hh:523
void makeOverlappingConsistent(Dune::BlockVector< Block, Alloc > &v) const
Make a vector consistent for overlapping domain decomposition methods.
Definition parallelhelpers.hh:544
void makeNonOverlappingConsistent(Dune::BlockVector< Block, Alloc > &v) const
Make a vector consistent for non-overlapping domain decomposition methods.
Definition parallelhelpers.hh:529
Definition variablesbackend.hh:34
dune-grid capabilities compatibility layer
@ element
Definition fieldtype.hh:23
Detail::ParallelISTLHelperImpl< LinearSolverTraits, LinearSolverTraits::canCommunicate > ParallelISTLHelper
A parallel helper class providing a parallel decomposition of all degrees of freedom.
Definition parallelhelpers.hh:514
Adapter to expose a multi-DOF mapper interface for single- and multi-DOF mappers.
Definition cvfelocalresidual.hh:25
Definition adapt.hh:17
VectorCommDataHandle< Mapper, Vector, codim, Detail::Sum, DataType > VectorCommDataHandleSum
Definition vectorcommdatahandle.hh:214
void prepareMatrixParallel(Matrix &A, ParallelHelper &pHelper)
Prepare a matrix for parallel solvers.
Definition parallelhelpers.hh:1414
LinearSolverTraitsImpl< GridGeometry, typename GridGeometry::DiscretizationMethod > LinearSolverTraits
The type traits required for using the IstlFactoryBackend.
Definition linearsolvertraits.hh:39
void prepareLinearAlgebraParallel(Matrix &A, Vector &b, ParallelHelper &pHelper)
Prepare linear algebra variables for parallel solvers.
Definition parallelhelpers.hh:1471
constexpr auto asMultiMapper(const Mapper &mapper)
Definition multimapperview.hh:48
void prepareVectorParallel(Vector &b, ParallelHelper &pHelper)
Prepare a vector for parallel solvers.
Definition parallelhelpers.hh:1445
MultiCodimVectorCommDataHandle< Mapper, Vector, dim, Detail::Sum, DataType > MultiCodimVectorCommDataHandleSum
Definition vectorcommdatahandle.hh:226
Definition common/pdesolver.hh:24
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Contains a class to exchange entries of a vector.