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 for (const auto& element : elements(gridView_))
922 {
923 for (int i = 0; i < element.subEntities(codim); ++i)
924 {
925 const auto entity = element.template subEntity<codim>(i);
926 if (entity.partitionType() == Dune::BorderEntity)
927 {
928 const auto localIdx = mapper_.index(entity);
929 const DofIdKey key{codim, gridView_.grid().globalIdSet().id(entity)};
930 idToIndex_.emplace(key, localIdx);
931 indexToID_.emplace(localIdx, key);
932 }
933 }
934 }
935
937 }
938 }
939
945 template<class IsGhostFunc>
946 void extendMatrix(Matrix& A, const IsGhostFunc& isGhost)
947 {
948 if constexpr (Dune::Capabilities::canCommunicate<typename GridView::Grid, rowDofCodim>::v)
949 {
950 if (gridView_.comm().size() <= 1)
951 return;
952
953 // make a copy of the matrix as originally assembled
954 Matrix matrixAsAssembled(A);
955
956 // first get entries in sparsity pattern from other processes
957 std::size_t numNonZeroEntries = 0;
958 std::vector<std::set<int>> sparsityPattern; // column indices for every row
959 MatrixPatternExchange<IsGhostFunc> dataHandle(mapper_, idToIndex_, indexToID_, A, sparsityPattern, isGhost);
960 gridView_.communicate(
961 dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication
962 );
963
964 // add own entries to the sparsity pattern and count number of non-zeros
965 for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt)
966 {
967 const auto colEndIt = A[rowIt.index()].end();
968 for (auto colIt = rowIt->begin(); colIt != colEndIt; ++colIt)
969 if (!sparsityPattern[rowIt.index()].count(colIt.index()))
970 sparsityPattern[rowIt.index()].insert(colIt.index());
971
972 numNonZeroEntries += sparsityPattern[rowIt.index()].size();
973 }
974
975 // insert any additional entries into the matrix
976 A.setSize(matrixAsAssembled.N(), matrixAsAssembled.M(), numNonZeroEntries);
977 A.setBuildMode(Matrix::row_wise);
978 auto citer = A.createbegin();
979 for (auto i = sparsityPattern.begin(), end = sparsityPattern.end(); i!=end; ++i, ++citer)
980 for (auto si = i->begin(), send = i->end(); si!=send; ++si)
981 citer.insert(*si);
982
983 // reset matrix to contain original values
984 A = 0;
985 const auto rowEndIt = matrixAsAssembled.end();
986 for (auto rowIt = matrixAsAssembled.begin(); rowIt != rowEndIt; ++rowIt)
987 for (auto colIt = matrixAsAssembled[rowIt.index()].begin(); colIt != matrixAsAssembled[rowIt.index()].end(); ++colIt)
988 A[rowIt.index()][colIt.index()] = *colIt;
989
990 // The matrix A has now a possible extended sparsity pattern but any additional entries are
991 // initialized to zero and have to be filled by the sumEntries function
992 }
993 else
994 DUNE_THROW(Dune::InvalidStateException, "Cannot call extendMatrix for a grid that cannot communicate codim-" << rowDofCodim << "-entities.");
995 }
996
1010 void sumEntries(Matrix& A)
1011 {
1012 if constexpr (Dune::Capabilities::canCommunicate<typename GridView::Grid, rowDofCodim>::v)
1013 {
1014 if (gridView_.comm().size() <= 1)
1015 return;
1016
1017 MatrixEntryExchange dataHandle(mapper_, idToIndex_, indexToID_, A);
1018 gridView_.communicate(
1019 dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication
1020 );
1021 }
1022 else
1023 DUNE_THROW(Dune::InvalidStateException,
1024 "Cannot call sumEntries for a grid that cannot communicate codim-" << rowDofCodim << "-entities."
1025 );
1026 }
1027
1028private:
1029 const GridView gridView_;
1030 const RowDofMapper& mapper_;
1031 std::map<DofIdKey, int> idToIndex_;
1032 std::map<int, DofIdKey> indexToID_;
1033
1034};
1035
1040template<class Matrix, class GridView, class DofMapper, std::size_t numCodims>
1042{
1043 using IdType = typename GridView::Traits::Grid::Traits::GlobalIdSet::IdType;
1044
1045 struct DofIdKey
1046 {
1047 int codim;
1048 IdType id;
1049 int subIndex;
1050
1051 friend bool operator<(const DofIdKey& a, const DofIdKey& b)
1052 {
1053 if (a.codim != b.codim)
1054 return a.codim < b.codim;
1055 if (a.id != b.id)
1056 return a.id < b.id;
1057 return a.subIndex < b.subIndex;
1058 }
1059 };
1060
1061 // Each sent item encodes which row DOF within the entity and which column DOF.
1062 // This handles multi-DOF entities (e.g. PQ3 edges with 2 DOFs) correctly.
1063 struct PatternEntry
1064 {
1065 int rowSubIndex;
1066 DofIdKey colKey;
1067 };
1068
1069 template<class ColIsGhostFunc>
1070 struct MatrixPatternExchange
1071 : public Dune::CommDataHandleIF<MatrixPatternExchange<ColIsGhostFunc>, PatternEntry>
1072 {
1073 using DataType = PatternEntry;
1074
1075 MatrixPatternExchange(const DofMapper& dofMapper,
1076 const std::map<DofIdKey, int>& globalToLocal,
1077 const std::map<int, DofIdKey>& localToGlobal,
1078 Matrix& A,
1079 std::vector<std::set<int>>& sparsityPattern,
1080 const ColIsGhostFunc& isGhostColumDof,
1081 const std::bitset<numCodims>& activeCodims)
1082 : dofMapper_(dofMapper)
1083 , idToIndex_(globalToLocal)
1084 , indexToID_(localToGlobal)
1085 , sparsityPattern_(sparsityPattern)
1086 , A_(A)
1087 , isGhostColumDof_(isGhostColumDof)
1088 , activeCodims_(activeCodims)
1089 {
1090 sparsityPattern_.resize(A.N());
1091 }
1092
1093 bool contains(int dim, int codim) const
1094 {
1095 if (codim < 0 || codim >= static_cast<int>(numCodims))
1096 return false;
1097 return activeCodims_.test(codim);
1098 }
1099
1100 bool fixedSize(int dim, int codim) const
1101 { return false; }
1102
1104 template<class EntityType>
1105 std::size_t size(EntityType& e) const
1106 {
1107 std::size_t n = 0;
1108 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1109 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1110 if (indexToID_.count(colIt.index()))
1111 ++n;
1112 return n;
1113 }
1114
1116 template<class MessageBuffer, class EntityType>
1117 void gather(MessageBuffer& buff, const EntityType& e) const
1118 {
1119 int rowSub = 0;
1120 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1121 {
1122 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1123 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
1124 buff.write(PatternEntry{rowSub, it->second});
1125 ++rowSub;
1126 }
1127 }
1128
1130 template<class MessageBuffer, class EntityType>
1131 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
1132 {
1133 const auto baseIdx = dofMapper_.index(e);
1134 for (std::size_t k = 0; k < n; k++)
1135 {
1136 PatternEntry entry;
1137 buff.read(entry);
1138 const auto rowIdx = baseIdx + entry.rowSubIndex;
1139 if (const auto it = idToIndex_.find(entry.colKey); it != idToIndex_.end())
1140 {
1141 const auto colIdx = it->second;
1142 if (!isGhostColumDof_(colIdx))
1143 sparsityPattern_[rowIdx].insert(colIdx);
1144 }
1145 }
1146 }
1147
1148 private:
1149 const DofMapper& dofMapper_;
1150 const std::map<DofIdKey, int>& idToIndex_;
1151 const std::map<int, DofIdKey>& indexToID_;
1152 std::vector<std::set<int>>& sparsityPattern_;
1153 Matrix& A_;
1154 const ColIsGhostFunc& isGhostColumDof_;
1155 const std::bitset<numCodims>& activeCodims_;
1156 };
1157
1158 struct MatrixEntry
1159 {
1160 int rowSubIndex;
1161 DofIdKey colKey;
1162 typename Matrix::block_type block;
1163 };
1164
1165 struct MatrixEntryExchange
1166 : public Dune::CommDataHandleIF<MatrixEntryExchange, MatrixEntry>
1167 {
1168 using DataType = MatrixEntry;
1169
1170 MatrixEntryExchange(const DofMapper& dofMapper,
1171 const std::map<DofIdKey, int>& globalToLocal,
1172 const std::map<int, DofIdKey>& localToGlobal,
1173 Matrix& A,
1174 const std::bitset<numCodims>& activeCodims)
1175 : dofMapper_(dofMapper)
1176 , idToIndex_(globalToLocal)
1177 , indexToID_(localToGlobal)
1178 , A_(A)
1179 , activeCodims_(activeCodims)
1180 {}
1181
1182 bool contains(int dim, int codim) const
1183 {
1184 if (codim < 0 || codim >= static_cast<int>(numCodims))
1185 return false;
1186 return activeCodims_.test(codim);
1187 }
1188
1189 bool fixedSize(int dim, int codim) const
1190 { return false; }
1191
1193 template<class EntityType>
1194 std::size_t size(EntityType& e) const
1195 {
1196 std::size_t n = 0;
1197 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1198 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1199 if (indexToID_.count(colIt.index()))
1200 ++n;
1201 return n;
1202 }
1203
1205 template<class MessageBuffer, class EntityType>
1206 void gather(MessageBuffer& buff, const EntityType& e) const
1207 {
1208 int rowSub = 0;
1209 for (auto rowIdx : asMultiMapper(dofMapper_).indices(e))
1210 {
1211 for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt)
1212 if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end())
1213 buff.write(MatrixEntry{rowSub, it->second, *colIt});
1214 ++rowSub;
1215 }
1216 }
1217
1219 template<class MessageBuffer, class EntityType>
1220 void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n)
1221 {
1222 const auto baseIdx = dofMapper_.index(e);
1223 for (std::size_t k = 0; k < n; k++)
1224 {
1225 MatrixEntry m;
1226 buff.read(m);
1227 const auto rowIdx = baseIdx + m.rowSubIndex;
1228 if (auto it = idToIndex_.find(m.colKey); it != idToIndex_.end())
1229 {
1230 if (A_[rowIdx].find(it->second) != A_[rowIdx].end())
1231 A_[rowIdx][it->second] += m.block;
1232 }
1233 }
1234 }
1235
1236 private:
1237 const DofMapper& dofMapper_;
1238 const std::map<DofIdKey, int>& idToIndex_;
1239 const std::map<int, DofIdKey>& indexToID_;
1240 Matrix& A_;
1241 const std::bitset<numCodims>& activeCodims_;
1242 };
1243
1244public:
1245 // Standard constructor: only communicates border-entity DOF couplings.
1246 // Suitable for iterative solvers (ISTL AMG) where ghost DOF equations
1247 // are handled separately by the parallel operator mechanism.
1248 MultiCodimParallelMatrixHelper(const GridView& gridView,
1249 const DofMapper& mapper,
1250 const std::bitset<numCodims>& activeCodims)
1251 : gridView_(gridView)
1252 , mapper_(mapper)
1253 , activeCodims_(activeCodims)
1254 , includeGhostAndAdjacent_(false)
1255 , commInterface_(Dune::InteriorBorder_InteriorBorder_Interface)
1256 {
1257 initMapsForCodim_<0>();
1258 }
1259
1260 // Extended constructor for direct solvers (e.g. Trilinos/MUMPS):
1261 // also includes ghost entities and boundary-adjacent interior entities
1262 // so that element-interior DOF column entries in border DOF matrix rows
1263 // are correctly communicated across ranks.
1264 // Uses All_All_Interface so that ghost entities (GhostEntity on non-owner
1265 // rank) can participate in the scatter step and receive data from owners.
1266 MultiCodimParallelMatrixHelper(const GridView& gridView,
1267 const DofMapper& mapper,
1268 const std::bitset<numCodims>& activeCodims,
1269 bool includeGhostAndAdjacent)
1270 : gridView_(gridView)
1271 , mapper_(mapper)
1272 , activeCodims_(activeCodims)
1273 , includeGhostAndAdjacent_(includeGhostAndAdjacent)
1274 // InteriorBorder_All_Interface: owner (Interior/Border) gathers and
1275 // sends; ghost (All) scatters and receives. This propagates the
1276 // owner's physical stiffness to ghost DOFs without sending ghost-
1277 // treatment (identity) entries from the non-owner back to the owner.
1278 , commInterface_(includeGhostAndAdjacent ? Dune::InteriorBorder_All_Interface
1279 : Dune::InteriorBorder_InteriorBorder_Interface)
1280 {
1281 initMapsForCodim_<0>();
1282 }
1283
1284 template<class IsGhostFunc>
1285 void extendMatrix(Matrix& A, const IsGhostFunc& isGhost)
1286 {
1287 if (gridView_.comm().size() <= 1)
1288 return;
1289
1290 Matrix matrixAsAssembled(A);
1291 std::size_t numNonZeroEntries = 0;
1292 std::vector<std::set<int>> sparsityPattern;
1293 MatrixPatternExchange<IsGhostFunc> dataHandle(mapper_, idToIndex_, indexToID_, A, sparsityPattern, isGhost, activeCodims_);
1294 gridView_.communicate(dataHandle, commInterface_, Dune::ForwardCommunication);
1295
1296 for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt)
1297 {
1298 const auto colEndIt = A[rowIt.index()].end();
1299 for (auto colIt = rowIt->begin(); colIt != colEndIt; ++colIt)
1300 {
1301 if (!sparsityPattern[rowIt.index()].count(colIt.index()))
1302 sparsityPattern[rowIt.index()].insert(colIt.index());
1303 }
1304
1305 numNonZeroEntries += sparsityPattern[rowIt.index()].size();
1306 }
1307
1308 A.setSize(matrixAsAssembled.N(), matrixAsAssembled.M(), numNonZeroEntries);
1309 A.setBuildMode(Matrix::row_wise);
1310 auto citer = A.createbegin();
1311 for (auto i = sparsityPattern.begin(), end = sparsityPattern.end(); i != end; ++i, ++citer)
1312 for (auto si = i->begin(), send = i->end(); si != send; ++si)
1313 citer.insert(*si);
1314
1315 A = 0;
1316 const auto rowEndIt = matrixAsAssembled.end();
1317 for (auto rowIt = matrixAsAssembled.begin(); rowIt != rowEndIt; ++rowIt)
1318 for (auto colIt = matrixAsAssembled[rowIt.index()].begin(); colIt != matrixAsAssembled[rowIt.index()].end(); ++colIt)
1319 A[rowIt.index()][colIt.index()] = *colIt;
1320 }
1321
1322 void sumEntries(Matrix& A)
1323 {
1324 if (gridView_.comm().size() <= 1)
1325 return;
1326
1327 MatrixEntryExchange dataHandle(mapper_, idToIndex_, indexToID_, A, activeCodims_);
1328 gridView_.communicate(dataHandle, commInterface_, Dune::ForwardCommunication);
1329 }
1330
1331private:
1332 template<std::size_t codim>
1333 void initMapsForCodim_()
1334 {
1335 if constexpr (codim <= GridView::dimension)
1336 {
1337 if (activeCodims_.test(codim))
1338 {
1339 for (const auto& element : elements(gridView_))
1340 {
1341 for (int i = 0; i < element.subEntities(codim); ++i)
1342 {
1343 const auto entity = element.template subEntity<codim>(i);
1344 const auto pt = entity.partitionType();
1345
1346 // elements are never border entities, and the interior dofs of an element at the
1347 // processor border can be columns of border rows on the neighbouring process
1348 bool shouldProcess = (codim == 0) || (pt == Dune::BorderEntity)
1349 || (pt == Dune::InteriorEntity && elementHasBorderSubEntity_(element));
1350
1351 // the extended mode for direct solvers also includes ghost dofs
1352 if (!shouldProcess && includeGhostAndAdjacent_)
1353 shouldProcess = (pt == Dune::GhostEntity);
1354
1355 if (shouldProcess)
1356 {
1357 // Use asMultiMapper(mapper_).indices(entity) to handle multi-DOF entities
1358 // (e.g. PQ3 with 2 DOFs per edge). Each DOF gets a unique
1359 // DofIdKey that encodes both the entity ID and the DOF sub-index.
1360 const auto globalId = gridView_.grid().globalIdSet().id(entity);
1361 int subIdx = 0;
1362 for (auto dofIdx : asMultiMapper(mapper_).indices(entity))
1363 {
1364 const DofIdKey key{static_cast<int>(codim), globalId, subIdx};
1365 idToIndex_.emplace(key, dofIdx);
1366 indexToID_.emplace(dofIdx, key);
1367 ++subIdx;
1368 }
1369 }
1370 }
1371 }
1372 }
1373
1374 initMapsForCodim_<codim + 1>();
1375 }
1376 }
1377
1378 // Helper: returns true if element has at least one BorderEntity sub-entity
1379 template<class Element>
1380 static bool elementHasBorderSubEntity_(const Element& element)
1381 {
1382 for (int i = 0; i < element.subEntities(1); ++i)
1383 if (element.template subEntity<1>(i).partitionType() == Dune::BorderEntity)
1384 return true;
1385 if constexpr (Element::mydimension >= 2)
1386 for (int i = 0; i < element.subEntities(2); ++i)
1387 if (element.template subEntity<2>(i).partitionType() == Dune::BorderEntity)
1388 return true;
1389 if constexpr (Element::mydimension >= 3)
1390 for (int i = 0; i < element.subEntities(3); ++i)
1391 if (element.template subEntity<3>(i).partitionType() == Dune::BorderEntity)
1392 return true;
1393 return false;
1394 }
1395
1396 const GridView gridView_;
1397 const DofMapper& mapper_;
1398 std::bitset<numCodims> activeCodims_;
1399 bool includeGhostAndAdjacent_;
1400 Dune::InterfaceType commInterface_;
1401 std::map<DofIdKey, int> idToIndex_;
1402 std::map<int, DofIdKey> indexToID_;
1403};
1404
1408template<class LinearSolverTraits, class ParallelTraits,
1409 class Matrix, class ParallelHelper>
1410void prepareMatrixParallel(Matrix& A, ParallelHelper& pHelper)
1411{
1412 if constexpr (ParallelTraits::isNonOverlapping)
1413 {
1414 using GridView = typename LinearSolverTraits::GridView;
1415 using DofMapper = typename LinearSolverTraits::DofMapper;
1416
1417 if constexpr (requires { LinearSolverTraits::dofCodims; })
1418 {
1419 constexpr auto dofCodims = LinearSolverTraits::dofCodims;
1421 pHelper.gridView(), pHelper.dofMapper(), dofCodims
1422 );
1423 matrixHelper.extendMatrix(A, [&pHelper](auto idx){ return pHelper.isGhost(idx); });
1424 matrixHelper.sumEntries(A);
1425 }
1426 else
1427 {
1428 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
1429 ParallelMatrixHelper<Matrix, GridView, DofMapper, dofCodim> matrixHelper(pHelper.gridView(), pHelper.dofMapper());
1430 matrixHelper.extendMatrix(A, [&pHelper](auto idx){ return pHelper.isGhost(idx); });
1431 matrixHelper.sumEntries(A);
1432 }
1433 }
1434}
1435
1439template<class LinearSolverTraits, class ParallelTraits,
1440 class Vector, class ParallelHelper>
1441void prepareVectorParallel(Vector& b, ParallelHelper& pHelper)
1442{
1443 if constexpr (ParallelTraits::isNonOverlapping)
1444 {
1445 using GridView = typename LinearSolverTraits::GridView;
1446 using DofMapper = typename LinearSolverTraits::DofMapper;
1447
1448 if constexpr (requires { LinearSolverTraits::dofCodims; })
1449 {
1450 MultiCodimParallelVectorHelper<GridView, DofMapper> vectorHelper(pHelper.gridView(), pHelper.dofMapper());
1451 vectorHelper.makeNonOverlappingConsistent(b, LinearSolverTraits::dofCodims);
1452 }
1453 else
1454 {
1455 static constexpr int dofCodim = LinearSolverTraits::dofCodim;
1456 ParallelVectorHelper<GridView, DofMapper, dofCodim> vectorHelper(pHelper.gridView(), pHelper.dofMapper());
1457 vectorHelper.makeNonOverlappingConsistent(b);
1458 }
1459 }
1460}
1461
1465template<class LinearSolverTraits, class ParallelTraits,
1466 class Matrix, class Vector, class ParallelHelper>
1467void prepareLinearAlgebraParallel(Matrix& A, Vector& b, ParallelHelper& pHelper)
1468{
1471}
1472
1476template<class LinearSolverTraits, class ParallelTraits,
1477 class Matrix, class Vector, class ParallelHelper>
1478void prepareLinearAlgebraParallel(Matrix& A, Vector& b,
1479 std::shared_ptr<typename ParallelTraits::Comm>& comm,
1480 std::shared_ptr<typename ParallelTraits::LinearOperator>& fop,
1481 std::shared_ptr<typename ParallelTraits::ScalarProduct>& sp,
1482 ParallelHelper& pHelper)
1483{
1485 const auto category = ParallelTraits::isNonOverlapping ?
1486 Dune::SolverCategory::nonoverlapping : Dune::SolverCategory::overlapping;
1487
1488 comm = std::make_shared<typename ParallelTraits::Comm>(pHelper.gridView().comm(), category);
1489 pHelper.createParallelIndexSet(*comm);
1490 fop = std::make_shared<typename ParallelTraits::LinearOperator>(A, *comm);
1491 sp = std::make_shared<typename ParallelTraits::ScalarProduct>(*comm);
1492}
1493
1494} // end namespace Dumux
1495
1496#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:1042
void sumEntries(Matrix &A)
Definition parallelhelpers.hh:1322
MultiCodimParallelMatrixHelper(const GridView &gridView, const DofMapper &mapper, const std::bitset< numCodims > &activeCodims)
Definition parallelhelpers.hh:1248
MultiCodimParallelMatrixHelper(const GridView &gridView, const DofMapper &mapper, const std::bitset< numCodims > &activeCodims, bool includeGhostAndAdjacent)
Definition parallelhelpers.hh:1266
void extendMatrix(Matrix &A, const IsGhostFunc &isGhost)
Definition parallelhelpers.hh:1285
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:1010
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:946
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:1410
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:1467
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:1441
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.