Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup Linear | ||
10 | * \brief Provides a helper class for nonoverlapping decomposition | ||
11 | */ | ||
12 | #ifndef DUMUX_LINEAR_PARALLELHELPERS_HH | ||
13 | #define DUMUX_LINEAR_PARALLELHELPERS_HH | ||
14 | |||
15 | #include <dune/common/exceptions.hh> | ||
16 | #include <dune/geometry/dimension.hh> | ||
17 | #include <dune/grid/common/datahandleif.hh> | ||
18 | #include <dune/grid/common/partitionset.hh> | ||
19 | #include <dune/istl/owneroverlapcopy.hh> | ||
20 | #include <dune/istl/paamg/pinfo.hh> | ||
21 | #include <dune/istl/bvector.hh> | ||
22 | #include <dune/istl/multitypeblockvector.hh> | ||
23 | #include <dumux/parallel/vectorcommdatahandle.hh> | ||
24 | #include <dumux/common/gridcapabilities.hh> | ||
25 | |||
26 | namespace Dumux::Detail { | ||
27 | |||
28 | template<class LinearSolverTraits, bool canCommunicate = false> | ||
29 | class ParallelISTLHelperImpl {}; | ||
30 | |||
31 | template<class LinearSolverTraits> | ||
32 | class ParallelISTLHelperImpl<LinearSolverTraits, true> | ||
33 | { | ||
34 | using GridView = typename LinearSolverTraits::GridView; | ||
35 | using DofMapper = typename LinearSolverTraits::DofMapper; | ||
36 | static constexpr int dofCodim = LinearSolverTraits::dofCodim; | ||
37 | |||
38 | // TODO: this is some large number (replace by limits?) | ||
39 | static constexpr std::size_t ghostMarker_ = 1<<24; | ||
40 | |||
41 | class BaseGatherScatter | ||
42 | { | ||
43 | public: | ||
44 | 250 | BaseGatherScatter(const DofMapper& mapper) | |
45 | 250 | : mapper_(mapper) {} | |
46 | |||
47 | template<class EntityType> | ||
48 | ✗ | int index(const EntityType& e) const | |
49 | 62660 | { return mapper_.index(e); } | |
50 | |||
51 | ✗ | bool contains(int dim, int codim) const | |
52 | 916 | { return dofCodim == codim; } | |
53 | |||
54 | //! returns true if size per entity of given dim and codim is a constant | ||
55 | ✗ | bool fixedSize(int dim, int codim) const | |
56 | ✗ | { return true; } | |
57 | |||
58 | template<class EntityType> | ||
59 | ✗ | std::size_t size(EntityType& e) const | |
60 | ✗ | { return 1; } | |
61 | |||
62 | template<class EntityType> | ||
63 | ✗ | bool isNeitherInteriorNorBorderEntity(EntityType& e) const | |
64 |
19/72✓ Branch 0 taken 610 times.
✓ Branch 1 taken 888 times.
✓ Branch 2 taken 786 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 838 times.
✓ Branch 5 taken 1596 times.
✓ Branch 6 taken 1016 times.
✓ Branch 7 taken 160 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 176 times.
✓ Branch 13 taken 772 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 176 times.
✓ Branch 16 taken 554 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 554 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 782 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 678 times.
✓ Branch 23 taken 104 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 28 taken 104 times.
✓ Branch 29 taken 112 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 104 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✓ Branch 67 taken 400 times.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
|
9602 | { return e.partitionType() != Dune::InteriorEntity && e.partitionType() != Dune::BorderEntity; } |
65 | |||
66 | private: | ||
67 | const DofMapper& mapper_; | ||
68 | }; | ||
69 | |||
70 | /*! | ||
71 | * \brief Writes ghostMarker_ to each data item (of the container) that is gathered or scattered | ||
72 | * and is neither interior nor border. | ||
73 | * | ||
74 | * Can be used to mark ghost cells. | ||
75 | */ | ||
76 | class GhostGatherScatter | ||
77 | : public BaseGatherScatter | ||
78 | , public Dune::CommDataHandleIF<GhostGatherScatter, std::size_t> | ||
79 | { | ||
80 | public: | ||
81 | using DataType = std::size_t; | ||
82 | using BaseGatherScatter::contains; | ||
83 | using BaseGatherScatter::fixedSize; | ||
84 | using BaseGatherScatter::size; | ||
85 | |||
86 | 50 | GhostGatherScatter(std::vector<std::size_t>& ranks, const DofMapper& mapper) | |
87 | : BaseGatherScatter(mapper) | ||
88 | 100 | , ranks_(ranks) | |
89 | {} | ||
90 | |||
91 | template<class MessageBuffer, class EntityType> | ||
92 | 11056 | void gather(MessageBuffer& buff, const EntityType& e) const | |
93 | { | ||
94 |
2/2✓ Branch 1 taken 3942 times.
✓ Branch 2 taken 440 times.
|
11056 | auto& data = ranks_[this->index(e)]; |
95 |
3/3✓ Branch 0 taken 3942 times.
✓ Branch 1 taken 440 times.
✓ Branch 2 taken 302 times.
|
11056 | if (this->isNeitherInteriorNorBorderEntity(e)) |
96 | ✗ | data = ghostMarker_; | |
97 | 11056 | buff.write(data); | |
98 | 11056 | } | |
99 | |||
100 | template<class MessageBuffer, class EntityType> | ||
101 | 7224 | void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) | |
102 | { | ||
103 | std::size_t x; | ||
104 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
7224 | buff.read(x); |
105 |
2/5✓ Branch 1 taken 1128 times.
✓ Branch 2 taken 2484 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
7224 | auto& data = ranks_[this->index(e)]; |
106 |
2/5✓ Branch 0 taken 1128 times.
✓ Branch 1 taken 2484 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7224 | if (this->isNeitherInteriorNorBorderEntity(e)) |
107 | 4968 | data = ghostMarker_; | |
108 | 7224 | } | |
109 | private: | ||
110 | std::vector<std::size_t>& ranks_; | ||
111 | }; | ||
112 | |||
113 | /*! | ||
114 | * \brief GatherScatter handle that sets ghostMarker_ for data items neither associated to | ||
115 | * the interior or border and take the minimum when scattering. | ||
116 | * | ||
117 | * Used to compute an owner rank for each unknown. | ||
118 | */ | ||
119 | class InteriorBorderGatherScatter | ||
120 | : public BaseGatherScatter | ||
121 | , public Dune::CommDataHandleIF<InteriorBorderGatherScatter, std::size_t> | ||
122 | { | ||
123 | public: | ||
124 | using DataType = std::size_t; | ||
125 | using BaseGatherScatter::contains; | ||
126 | using BaseGatherScatter::fixedSize; | ||
127 | using BaseGatherScatter::size; | ||
128 | |||
129 | 50 | InteriorBorderGatherScatter(std::vector<std::size_t>& ranks, const DofMapper& mapper) | |
130 | : BaseGatherScatter(mapper) | ||
131 | 100 | , ranks_(ranks) | |
132 | {} | ||
133 | |||
134 | /*! | ||
135 | * \brief Pack data (to be send to other processes) from this process to message buffer | ||
136 | */ | ||
137 | template<class MessageBuffer, class EntityType> | ||
138 | 2852 | void gather(MessageBuffer& buff, const EntityType& e) const | |
139 | { | ||
140 |
1/2✓ Branch 1 taken 1392 times.
✗ Branch 2 not taken.
|
2852 | auto& data = ranks_[this->index(e)]; |
141 |
2/3✓ Branch 0 taken 1392 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
|
2852 | if (this->isNeitherInteriorNorBorderEntity(e)) |
142 | ✗ | data = ghostMarker_; | |
143 | 2852 | buff.write(data); | |
144 | 2852 | } | |
145 | |||
146 | /*! | ||
147 | * \brief Unpack data (received from other process) from message buffer to this process | ||
148 | */ | ||
149 | template<class MessageBuffer, class EntityType> | ||
150 | 2784 | void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) | |
151 | { | ||
152 | std::size_t x; | ||
153 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
2784 | buff.read(x); |
154 |
1/4✓ Branch 1 taken 1392 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2784 | auto& data = ranks_[this->index(e)]; |
155 | |||
156 | // we leave ghost unchanged | ||
157 | // for other dofs, the process with the lowest rank | ||
158 | // is assigned to be the (unique) owner | ||
159 | using std::min; | ||
160 |
3/7✓ Branch 0 taken 1392 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 696 times.
✓ Branch 3 taken 696 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
6960 | data = this->isNeitherInteriorNorBorderEntity(e) ? x : min(data, x); |
161 | 2784 | } | |
162 | private: | ||
163 | std::vector<std::size_t>& ranks_; | ||
164 | }; | ||
165 | |||
166 | /*! | ||
167 | * \brief GatherScatter handle for finding out about neighbouring processor ranks. | ||
168 | * | ||
169 | */ | ||
170 | struct NeighbourGatherScatter | ||
171 | : public BaseGatherScatter | ||
172 | , public Dune::CommDataHandleIF<NeighbourGatherScatter, int> | ||
173 | { | ||
174 | using DataType = int; | ||
175 | using BaseGatherScatter::contains; | ||
176 | using BaseGatherScatter::fixedSize; | ||
177 | using BaseGatherScatter::size; | ||
178 | |||
179 | 50 | NeighbourGatherScatter(const DofMapper& mapper, int rank, std::set<int>& neighbours) | |
180 | : BaseGatherScatter(mapper) | ||
181 | , rank_(rank) | ||
182 | 100 | , neighbours_(neighbours) | |
183 | {} | ||
184 | |||
185 | template<class MessageBuffer, class EntityType> | ||
186 | ✗ | void gather(MessageBuffer& buff, const EntityType& e) const | |
187 | { | ||
188 |
1/8✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 800 times.
|
9888 | buff.write(rank_); |
189 | ✗ | } | |
190 | |||
191 | template<class MessageBuffer, class EntityType> | ||
192 | ✗ | void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) | |
193 | { | ||
194 | int x; | ||
195 |
0/13✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
202 | buff.read(x); |
196 |
0/13✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
202 | neighbours_.insert(x); |
197 | ✗ | } | |
198 | private: | ||
199 | int rank_; | ||
200 | std::set<int>& neighbours_; | ||
201 | }; | ||
202 | |||
203 | |||
204 | /*! | ||
205 | * \brief GatherScatter handle for finding out about neighbouring processor ranks. | ||
206 | * | ||
207 | */ | ||
208 | struct SharedGatherScatter | ||
209 | : public BaseGatherScatter | ||
210 | , public Dune::CommDataHandleIF<SharedGatherScatter, int> | ||
211 | { | ||
212 | using DataType = int; | ||
213 | using BaseGatherScatter::contains; | ||
214 | using BaseGatherScatter::fixedSize; | ||
215 | using BaseGatherScatter::size; | ||
216 | |||
217 | 50 | SharedGatherScatter(std::vector<int>& shared, const DofMapper& mapper) | |
218 | : BaseGatherScatter(mapper) | ||
219 | 100 | , shared_(shared) | |
220 | {} | ||
221 | |||
222 | template<class MessageBuffer, class EntityType> | ||
223 | ✗ | void gather(MessageBuffer& buff, EntityType& e) const | |
224 | { | ||
225 | 9686 | int data = true; | |
226 |
1/8✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 800 times.
|
9888 | buff.write(data); |
227 | ✗ | } | |
228 | |||
229 | template<class MessageBuffer, class EntityType> | ||
230 | ✗ | void scatter(MessageBuffer& buff, const EntityType &e, std::size_t n) | |
231 | { | ||
232 | int x; | ||
233 | ✗ | buff.read(x); | |
234 | ✗ | auto& data = shared_[this->index(e)]; | |
235 | ✗ | data = data || x; | |
236 | ✗ | } | |
237 | private: | ||
238 | std::vector<int>& shared_; | ||
239 | }; | ||
240 | |||
241 | /*! | ||
242 | * \brief GatherScatter handle for finding out about neighbouring processor ranks. | ||
243 | * | ||
244 | */ | ||
245 | template<typename GlobalIndex> | ||
246 | struct GlobalIndexGatherScatter | ||
247 | : public BaseGatherScatter | ||
248 | , public Dune::CommDataHandleIF<GlobalIndexGatherScatter<GlobalIndex>, GlobalIndex> | ||
249 | { | ||
250 | using DataType = GlobalIndex; | ||
251 | using BaseGatherScatter::contains; | ||
252 | using BaseGatherScatter::fixedSize; | ||
253 | using BaseGatherScatter::size; | ||
254 | |||
255 | 50 | GlobalIndexGatherScatter(std::vector<GlobalIndex>& globalIndices, const DofMapper& mapper) | |
256 | : BaseGatherScatter(mapper) | ||
257 | 100 | , globalIndices_(globalIndices) | |
258 | {} | ||
259 | |||
260 | template<class MessageBuffer, class EntityType> | ||
261 | 19372 | void gather(MessageBuffer& buff, const EntityType& e) const | |
262 | { | ||
263 | 19372 | buff.write(globalIndices_[this->index(e)]); | |
264 | 19372 | } | |
265 | |||
266 | template<class MessageBuffer, class EntityType> | ||
267 | 19372 | void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) | |
268 | { | ||
269 | 19372 | DataType x; | |
270 | 19372 | buff.read(x); | |
271 | using std::min; | ||
272 | 19372 | DataType& data = globalIndices_[this->index(e)]; | |
273 | 19372 | data = min(data, x); | |
274 | 19372 | } | |
275 | private: | ||
276 | std::vector<GlobalIndex>& globalIndices_; | ||
277 | }; | ||
278 | |||
279 | public: | ||
280 | |||
281 | 50 | ParallelISTLHelperImpl(const GridView& gridView, const DofMapper& mapper) | |
282 |
5/12✓ Branch 1 taken 48 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
146 | : gridView_(gridView), mapper_(mapper) |
283 | { | ||
284 | if constexpr (Detail::canCommunicate<typename GridView::Traits::Grid, dofCodim>) | ||
285 |
1/2✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
|
50 | initGhostsAndOwners_(); |
286 | else | ||
287 | DUNE_THROW(Dune::InvalidStateException, | ||
288 | "Cannot initialize parallel helper for a grid that cannot communicate codim-" << dofCodim << "-entities." | ||
289 | ); | ||
290 | 50 | } | |
291 | |||
292 | bool isGhost(std::size_t i) const | ||
293 | 554974 | { return isGhost_[i] == ghostMarker_; } | |
294 | |||
295 | bool isOwned(std::size_t i) const | ||
296 | { return isOwned_[i] == 1; } | ||
297 | |||
298 | /*! | ||
299 | * \brief Creates a parallel index set for a communicator | ||
300 | * \param comm The OwnerOverlapCopyCommunication communicators | ||
301 | * | ||
302 | * The parallel index set contains for each dof index, | ||
303 | * the triplet (globalIndex, (localIndex, attribute)) | ||
304 | * where attribute is owner, overlap or copy. Each dof | ||
305 | * is uniquely owned by exactly one process. This allows | ||
306 | * to apply local operators additively to get a global operator | ||
307 | * without communication. | ||
308 | */ | ||
309 | template<class Comm> | ||
310 | 50 | void createParallelIndexSet(Comm& comm) const | |
311 | { | ||
312 | if constexpr (Detail::canCommunicate<typename GridView::Traits::Grid, dofCodim>) | ||
313 | { | ||
314 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 30 times.
|
54 | if (gridView_.comm().size() <= 1) |
315 | { | ||
316 | ✗ | comm.remoteIndices().template rebuild<false>(); | |
317 | ✗ | return; | |
318 | } | ||
319 | |||
320 | // First find out which dofs we share with other processors | ||
321 |
5/10✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
174 | std::vector<int> isShared(mapper_.size(), false); |
322 | 100 | SharedGatherScatter sgs(isShared, mapper_); | |
323 |
2/4✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
50 | gridView_.communicate(sgs, Dune::All_All_Interface, Dune::ForwardCommunication); |
324 | |||
325 | // Count shared dofs that we own | ||
326 | using GlobalIndex = typename Comm::ParallelIndexSet::GlobalIndex; | ||
327 |
1/2✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
|
50 | GlobalIndex count = 0; |
328 |
4/4✓ Branch 0 taken 49665 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 49665 times.
✓ Branch 3 taken 50 times.
|
49765 | for (std::size_t i = 0; i < isShared.size(); ++i) |
329 |
8/8✓ Branch 0 taken 8229 times.
✓ Branch 1 taken 41436 times.
✓ Branch 2 taken 8229 times.
✓ Branch 3 taken 41436 times.
✓ Branch 4 taken 3422 times.
✓ Branch 5 taken 4807 times.
✓ Branch 6 taken 3422 times.
✓ Branch 7 taken 4807 times.
|
99330 | if (isShared[i] && isOwned_[i] == 1) |
330 | ++count; | ||
331 | |||
332 |
9/16✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 48 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 30 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
154 | std::vector<GlobalIndex> counts(gridView_.comm().size()); |
333 |
7/9✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 20 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
54 | gridView_.comm().allgather(&count, 1, counts.data()); |
334 | |||
335 | // Compute start index start_p = \sum_{i=0}^{i<p} counts_i | ||
336 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
52 | const int rank = gridView_.comm().rank(); |
337 |
1/2✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
|
50 | auto start = std::accumulate(counts.begin(), counts.begin() + rank, GlobalIndex(0)); |
338 | |||
339 | // starting from start (offset), number global indices owned by this process consecutively | ||
340 |
4/11✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
224 | std::vector<GlobalIndex> globalIndices(mapper_.size(), std::numeric_limits<GlobalIndex>::max()); |
341 |
4/4✓ Branch 0 taken 49665 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 49665 times.
✓ Branch 3 taken 50 times.
|
49715 | for (std::size_t i = 0; i < globalIndices.size(); ++i) |
342 | { | ||
343 |
8/8✓ Branch 0 taken 44858 times.
✓ Branch 1 taken 4807 times.
✓ Branch 2 taken 44858 times.
✓ Branch 3 taken 4807 times.
✓ Branch 4 taken 3422 times.
✓ Branch 5 taken 41436 times.
✓ Branch 6 taken 3422 times.
✓ Branch 7 taken 41436 times.
|
99330 | if (isOwned_[i] == 1 && isShared[i]) |
344 | { | ||
345 | 3422 | globalIndices[i] = start; | |
346 | 3422 | ++start; | |
347 | } | ||
348 | } | ||
349 | |||
350 | // publish global indices for the shared DOFS to other processors. | ||
351 | 100 | GlobalIndexGatherScatter<GlobalIndex> gigs(globalIndices, mapper_); | |
352 |
2/4✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
50 | gridView_.communicate(gigs, Dune::All_All_Interface, Dune::ForwardCommunication); |
353 | |||
354 | // put the information into the parallel index set | ||
355 |
1/2✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
|
50 | resizeAndFillIndexSet_(comm, globalIndices); |
356 | |||
357 | // Compute neighbours using communication | ||
358 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
100 | std::set<int> neighbours; |
359 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
52 | NeighbourGatherScatter ngs(mapper_, gridView_.comm().rank(), neighbours); |
360 |
2/4✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
50 | gridView_.communicate(ngs, Dune::All_All_Interface, Dune::ForwardCommunication); |
361 |
2/4✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 50 times.
✗ Branch 5 not taken.
|
100 | comm.remoteIndices().setNeighbours(neighbours); |
362 | |||
363 |
1/2✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
|
50 | comm.remoteIndices().template rebuild<false>(); |
364 | } | ||
365 | else | ||
366 | DUNE_THROW(Dune::InvalidStateException, | ||
367 | "Cannot build parallel index set for a grid that cannot communicate codim-" << dofCodim << "-entities." | ||
368 | ); | ||
369 | } | ||
370 | |||
371 | //! Return the dofMapper | ||
372 | ✗ | const DofMapper& dofMapper() const | |
373 | ✗ | { return mapper_; } | |
374 | |||
375 | //! Return the gridView | ||
376 | const GridView& gridView() const | ||
377 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
|
844 | { return gridView_; } |
378 | |||
379 | private: | ||
380 | /*! | ||
381 | * \brief Initialize ghost and owner flags | ||
382 | * | ||
383 | * All dofs on ghost entities are marked. | ||
384 | * All dofs are assigned a unique owner process. This will help us to create a unique partition | ||
385 | * and unique representations of a vector according to Definition 2.5 in Blatt and Bastian (2009) | ||
386 | * https://doi.org/10.1504/IJCSE.2008.021112 | ||
387 | */ | ||
388 | 50 | void initGhostsAndOwners_() | |
389 | { | ||
390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
52 | const auto rank = gridView_.comm().rank(); |
391 | 74 | isOwned_.assign(mapper_.size(), rank); | |
392 | |||
393 | // find out about ghosts | ||
394 | 100 | GhostGatherScatter ggs(isOwned_, mapper_); | |
395 | |||
396 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
|
54 | if (gridView_.comm().size() > 1) |
397 | 50 | gridView_.communicate(ggs, Dune::InteriorBorder_All_Interface, Dune::ForwardCommunication); | |
398 | |||
399 | // isGhost_ contains rank when the dof is not on a ghost entity (interior or border) | ||
400 | // and ghostMarker_ when the dof is on a ghost | ||
401 | 50 | isGhost_ = isOwned_; | |
402 | |||
403 | // partition interior/border uniquely | ||
404 | // after the communication each dof is assigned to one unique owner process rank | ||
405 | 100 | InteriorBorderGatherScatter dh(isOwned_, mapper_); | |
406 | |||
407 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
|
54 | if (gridView_.comm().size() > 1) |
408 | 50 | gridView_.communicate(dh, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication); | |
409 | |||
410 | // convert vector into mask vector | ||
411 |
4/4✓ Branch 0 taken 49665 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 49665 times.
✓ Branch 3 taken 50 times.
|
99480 | for (auto& v : isOwned_) |
412 |
2/2✓ Branch 0 taken 4807 times.
✓ Branch 1 taken 44858 times.
|
54472 | v = (v == rank) ? 1 : 0; |
413 | 50 | } | |
414 | |||
415 | template<class Comm, class GlobalIndices> | ||
416 | 50 | void resizeAndFillIndexSet_(Comm& comm, const GlobalIndices& globalIndices) const | |
417 | { | ||
418 | 50 | comm.indexSet().beginResize(); | |
419 | |||
420 | // add triplets characterizing each dof in the parallel index set | ||
421 | // (globalIndex, (localIndex, attribute)) where attribute is owner, overlap or copy | ||
422 |
4/4✓ Branch 1 taken 49665 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 49665 times.
✓ Branch 4 taken 50 times.
|
49715 | for (std::size_t localIndex = 0; localIndex < globalIndices.size(); ++localIndex) |
423 | { | ||
424 | 49665 | const auto globalIndex = globalIndices[localIndex]; | |
425 |
2/2✓ Branch 0 taken 8229 times.
✓ Branch 1 taken 41436 times.
|
148995 | if (globalIndex != std::numeric_limits<typename GlobalIndices::value_type>::max()) |
426 | { | ||
427 |
2/2✓ Branch 0 taken 4807 times.
✓ Branch 1 taken 3422 times.
|
8229 | const bool isOwned = isOwned_[localIndex] > 0; |
428 |
2/2✓ Branch 0 taken 4807 times.
✓ Branch 1 taken 3422 times.
|
8229 | const auto attr = getAttribute_(comm, isOwned, isGhost(localIndex)); |
429 | using LocalIndex = typename Comm::ParallelIndexSet::LocalIndex; | ||
430 | 16458 | comm.indexSet().add(globalIndex, LocalIndex{localIndex, attr}); | |
431 | } | ||
432 | } | ||
433 | |||
434 | 50 | comm.indexSet().endResize(); | |
435 | 50 | } | |
436 | |||
437 | template<class Comm> | ||
438 | Dune::OwnerOverlapCopyAttributeSet::AttributeSet | ||
439 | getAttribute_(const Comm& comm, const bool isOwned, const bool isGhost) const | ||
440 | { | ||
441 |
2/2✓ Branch 0 taken 4807 times.
✓ Branch 1 taken 3422 times.
|
8229 | if (isOwned) // this process owns the dof (uniquely) |
442 | return Dune::OwnerOverlapCopyAttributeSet::owner; | ||
443 |
4/4✓ Branch 0 taken 4094 times.
✓ Branch 1 taken 713 times.
✓ Branch 2 taken 1576 times.
✓ Branch 3 taken 2518 times.
|
4807 | else if (isGhost && (comm.category() == Dune::SolverCategory::nonoverlapping) ) |
444 | return Dune::OwnerOverlapCopyAttributeSet::overlap; | ||
445 | else | ||
446 | return Dune::OwnerOverlapCopyAttributeSet::copy; | ||
447 | } | ||
448 | |||
449 | const GridView gridView_; //!< the grid view | ||
450 | const DofMapper& mapper_; //!< the dof mapper | ||
451 | //! vector to identify unique decomposition (1: this rank owns the dof; 0: owned by remote process) | ||
452 | std::vector<std::size_t> isOwned_; | ||
453 | //!< vector to identify ghost dofs (ghostMarker_: this dof is on a ghost entity; contains and unspecified value otherwise) | ||
454 | std::vector<std::size_t> isGhost_; | ||
455 | |||
456 | }; | ||
457 | |||
458 | } // end namespace Dumux::Detail | ||
459 | |||
460 | namespace Dumux { | ||
461 | |||
462 | /*! | ||
463 | * \ingroup Linear | ||
464 | * \brief A parallel helper class providing a parallel | ||
465 | * decomposition of all degrees of freedom | ||
466 | */ | ||
467 | template<class LinearSolverTraits> | ||
468 | using ParallelISTLHelper = | ||
469 | Detail::ParallelISTLHelperImpl< | ||
470 | LinearSolverTraits, LinearSolverTraits::canCommunicate | ||
471 | >; | ||
472 | |||
473 | |||
474 | template<class GridView, class DofMapper, int dofCodim> | ||
475 | ✗ | class ParallelVectorHelper | |
476 | { | ||
477 | public: | ||
478 | 448 | ParallelVectorHelper(const GridView& gridView, const DofMapper& mapper) | |
479 |
2/4✓ Branch 1 taken 162 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 162 times.
✗ Branch 5 not taken.
|
324 | : gridView_(gridView), mapper_(mapper) |
480 | {} | ||
481 | |||
482 | //! \brief Make a vector consistent for non-overlapping domain decomposition methods | ||
483 | template<class Block, class Alloc> | ||
484 | 1200 | void makeNonOverlappingConsistent(Dune::BlockVector<Block, Alloc>& v) const | |
485 | { | ||
486 | if constexpr (Detail::canCommunicate<typename GridView::Traits::Grid, dofCodim>) | ||
487 | { | ||
488 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
|
1200 | VectorCommDataHandleSum<DofMapper, Dune::BlockVector<Block, Alloc>, dofCodim, Block> gs(mapper_, v); |
489 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
✓ Branch 2 taken 308 times.
✓ Branch 3 taken 892 times.
✓ Branch 4 taken 308 times.
✗ Branch 5 not taken.
|
1200 | if (gridView_.comm().size() > 1) |
490 | 1200 | gridView_.communicate(gs, Dune::InteriorBorder_InteriorBorder_Interface, | |
491 | Dune::ForwardCommunication); | ||
492 | } | ||
493 | else | ||
494 | DUNE_THROW(Dune::InvalidStateException, "Cannot call makeNonOverlappingConsistent for a grid that cannot communicate codim-" << dofCodim << "-entities."); | ||
495 | 1200 | } | |
496 | |||
497 | //! \brief Make a vector consistent for non-overlapping domain decomposition methods | ||
498 | template<class... Blocks> | ||
499 | void makeNonOverlappingConsistent(Dune::MultiTypeBlockVector<Blocks...>& v) const | ||
500 | { | ||
501 | DUNE_THROW(Dune::NotImplemented, "makeNonOverlappingConsistent for Dune::MultiTypeBlockVector"); | ||
502 | } | ||
503 | |||
504 | private: | ||
505 | const GridView gridView_; //!< the grid view | ||
506 | const DofMapper& mapper_; //!< the dof mapper | ||
507 | }; | ||
508 | |||
509 | /*! | ||
510 | * \ingroup Linear | ||
511 | * \brief Helper class for adding up matrix entries for border entities | ||
512 | * | ||
513 | * Border means all degrees of freedom located | ||
514 | * on lower-dimensional entities (faces, edges, vertices) | ||
515 | * that form the the process boundary | ||
516 | */ | ||
517 | template<class Matrix, class GridView, | ||
518 | class RowDofMapper, int rowDofCodim> | ||
519 | class ParallelMatrixHelper | ||
520 | { | ||
521 | using IdType = typename GridView::Traits::Grid::Traits::GlobalIdSet::IdType; | ||
522 | |||
523 | /*! | ||
524 | * \brief A DataHandle class to exchange matrix sparsity patterns. | ||
525 | * | ||
526 | * We look at a 2D example with a nonoverlapping grid, | ||
527 | * two processes and no ghosts with Q1 discretization. | ||
528 | * Process 0 has the left part of the domain | ||
529 | * with three cells and eight vertices (1-8), | ||
530 | * Process 1 the right part with three cells | ||
531 | * and eight vertices (2,4,7-12). | ||
532 | * <pre> | ||
533 | * 1 _ 2 2 _ 9 _ 10 | ||
534 | * | | | | | | ||
535 | * 3 _ 4 _ 7 4 _ 7 _ 11 | ||
536 | * | | | | | | ||
537 | * 5 _ 6 _ 8 8 _ 12 | ||
538 | * </pre> | ||
539 | * If we look at vertex 7 and the corresponding entries in the matrix for P0, | ||
540 | * there will be entries for (7,4) and (7,8), but not for (7,2). | ||
541 | * The MatrixPatternExchange class will find these entries and fills a vector "sparsity", | ||
542 | * that contains all missing connections. | ||
543 | */ | ||
544 | template<class ColIsGhostFunc> | ||
545 | struct MatrixPatternExchange | ||
546 | : public Dune::CommDataHandleIF<MatrixPatternExchange<ColIsGhostFunc>, IdType> | ||
547 | { | ||
548 | //! Export type of data for message buffer | ||
549 | using DataType = IdType; | ||
550 | |||
551 | /*! | ||
552 | * \brief Construct a new sparsity pattern exchange handle | ||
553 | * | ||
554 | * \param rowEntityMapper an index mapper for entities associated with row entities | ||
555 | * \param globalToLocal map (column dof) from global ID to processor-local index | ||
556 | * \param localToGlobal map (column dof) from processor-local index to global ID | ||
557 | * \param A the matrix for which we want to extend the pattern | ||
558 | * \param[out] sparsityPattern the extended sparsity pattern | ||
559 | * \param isGhostColumDof a function that returns whether a given column index is associated with a ghost entity | ||
560 | */ | ||
561 | 940 | MatrixPatternExchange(const RowDofMapper& rowEntityMapper, | |
562 | const std::map<IdType,int>& globalToLocal, | ||
563 | const std::map<int,IdType>& localToGlobal, | ||
564 | Matrix& A, | ||
565 | std::vector<std::set<int>>& sparsityPattern, | ||
566 | const ColIsGhostFunc& isGhostColumDof) | ||
567 | : rowEntityMapper_(rowEntityMapper), idToIndex_(globalToLocal), indexToID_(localToGlobal) | ||
568 | 940 | , sparsityPattern_(sparsityPattern), A_(A), isGhostColumDof_(isGhostColumDof) | |
569 | { | ||
570 | 940 | sparsityPattern_.resize(A.N()); | |
571 | } | ||
572 | |||
573 | /*! | ||
574 | * \brief Returns true if data for given valid codim should be communicated | ||
575 | */ | ||
576 | ✗ | bool contains (int dim, int codim) const | |
577 | 48 | { return (codim == rowDofCodim); } | |
578 | |||
579 | //! returns true if size per entity of given dim and codim is a constant | ||
580 | ✗ | bool fixedSize(int dim, int codim) const | |
581 | ✗ | { return false; } | |
582 | |||
583 | /*! | ||
584 | * \brief How many objects of type DataType have to be sent for a given entity | ||
585 | */ | ||
586 | template<class EntityType> | ||
587 | 186600 | std::size_t size(EntityType& e) const | |
588 | { | ||
589 | 186600 | const auto rowIdx = rowEntityMapper_.index(e); | |
590 | |||
591 | // all column entity indices of this row that are in the index set | ||
592 | 186600 | std::size_t n = 0; | |
593 |
6/6✓ Branch 0 taken 908884 times.
✓ Branch 1 taken 93300 times.
✓ Branch 2 taken 908884 times.
✓ Branch 3 taken 93300 times.
✓ Branch 4 taken 908884 times.
✓ Branch 5 taken 93300 times.
|
2190968 | for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) |
594 | 3635536 | if (indexToID_.count(colIt.index())) | |
595 | 565392 | n++; | |
596 | |||
597 | 186600 | return n; | |
598 | } | ||
599 | |||
600 | /*! | ||
601 | * \brief Pack data from user to message buffer | ||
602 | */ | ||
603 | template<class MessageBuffer, class EntityType> | ||
604 | 143760 | void gather(MessageBuffer& buff, const EntityType& e) const | |
605 | { | ||
606 | 143760 | const auto rowIdx = rowEntityMapper_.index(e); | |
607 | |||
608 | // send all column entity ids of this row that are in the index set | ||
609 |
8/8✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 795468 times.
✓ Branch 2 taken 8896 times.
✓ Branch 3 taken 795468 times.
✓ Branch 4 taken 8896 times.
✓ Branch 5 taken 795468 times.
✓ Branch 6 taken 723588 times.
✓ Branch 7 taken 70336 times.
|
1752488 | for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) |
610 |
4/4✓ Branch 0 taken 269466 times.
✓ Branch 1 taken 463018 times.
✓ Branch 2 taken 269466 times.
✓ Branch 3 taken 463018 times.
|
5859872 | if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end()) |
611 | 1077864 | buff.write(it->second); | |
612 | 143760 | } | |
613 | |||
614 | /*! | ||
615 | * \brief Unpack data from message buffer to user | ||
616 | */ | ||
617 | template<class MessageBuffer, class EntityType> | ||
618 | 143760 | void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) | |
619 | { | ||
620 | 143760 | const auto rowIdx = rowEntityMapper_.index(e); | |
621 |
2/2✓ Branch 1 taken 269466 times.
✓ Branch 2 taken 71880 times.
|
682692 | for (std::size_t k = 0; k < n; k++) |
622 | { | ||
623 | // receive n column entity IDs | ||
624 | 530112 | IdType id; | |
625 | 538932 | buff.read(id); | |
626 | |||
627 | // only add entries that are contained in the index set | ||
628 |
5/5✓ Branch 0 taken 4410 times.
✓ Branch 1 taken 264848 times.
✓ Branch 2 taken 4618 times.
✓ Branch 3 taken 264848 times.
✓ Branch 4 taken 208 times.
|
556572 | if (const auto it = idToIndex_.find(id); it != idToIndex_.end()) |
629 | { | ||
630 |
1/2✓ Branch 0 taken 269258 times.
✗ Branch 1 not taken.
|
538516 | const auto colIdx = it->second; // get local column index |
631 | // add this entry (if it doesn't exist yet) | ||
632 | // (and only if the column dof is not associated with a ghost entity) | ||
633 | 1077032 | if (!isGhostColumDof_(colIdx)) | |
634 | // std::set takes care that each index only is inserted once | ||
635 | 1077032 | sparsityPattern_[rowIdx].insert(colIdx); | |
636 | } | ||
637 | } | ||
638 | 143760 | } | |
639 | |||
640 | private: | ||
641 | const RowDofMapper& rowEntityMapper_; | ||
642 | const std::map<IdType, int>& idToIndex_; | ||
643 | const std::map<int, IdType>& indexToID_; | ||
644 | std::vector<std::set<int>>& sparsityPattern_; | ||
645 | Matrix& A_; | ||
646 | const ColIsGhostFunc& isGhostColumDof_; | ||
647 | |||
648 | }; // class MatrixPatternExchange | ||
649 | |||
650 | //! Local matrix blocks associated with the global id set | ||
651 | 1345874 | struct MatrixEntry | |
652 | { | ||
653 | IdType first; | ||
654 | typename Matrix::block_type second; | ||
655 | }; | ||
656 | |||
657 | //! A DataHandle class to exchange matrix entries | ||
658 | struct MatrixEntryExchange | ||
659 | : public Dune::CommDataHandleIF<MatrixEntryExchange, MatrixEntry> | ||
660 | { | ||
661 | //! Export type of data for message buffer | ||
662 | using DataType = MatrixEntry; | ||
663 | |||
664 | 940 | MatrixEntryExchange(const RowDofMapper& rowEntityMapper, | |
665 | const std::map<IdType, int>& globalToLocal, | ||
666 | const std::map<int, IdType>& localToGlobal, | ||
667 | Matrix& A) | ||
668 | 940 | : rowEntityMapper_(rowEntityMapper), idToIndex_(globalToLocal), indexToID_(localToGlobal), A_(A) | |
669 | {} | ||
670 | |||
671 | /*! | ||
672 | * \brief Returns true if data for given valid codim should be communicated | ||
673 | */ | ||
674 | ✗ | bool contains(int dim, int codim) const | |
675 | 48 | { return (codim == rowDofCodim); } | |
676 | |||
677 | //! returns true if size per entity of given dim and codim is a constant | ||
678 | ✗ | bool fixedSize(int dim, int codim) const | |
679 | ✗ | { return false; } | |
680 | |||
681 | /*! | ||
682 | * \brief How many objects of type DataType have to be sent for a given entity | ||
683 | */ | ||
684 | template<class EntityType> | ||
685 | 186600 | std::size_t size(EntityType& e) const | |
686 | { | ||
687 | 186600 | const auto rowIdx = rowEntityMapper_.index(e); | |
688 | 186600 | std::size_t n = 0; | |
689 |
6/6✓ Branch 0 taken 909386 times.
✓ Branch 1 taken 93300 times.
✓ Branch 2 taken 909386 times.
✓ Branch 3 taken 93300 times.
✓ Branch 4 taken 909386 times.
✓ Branch 5 taken 93300 times.
|
2191972 | for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) |
690 | 3637544 | if (indexToID_.count(colIt.index())) | |
691 | 566396 | n++; | |
692 | |||
693 | 186600 | return n; | |
694 | } | ||
695 | |||
696 | /*! | ||
697 | * \brief Pack data from user to message buffer | ||
698 | */ | ||
699 | template<class MessageBuffer, class EntityType> | ||
700 | 143760 | void gather(MessageBuffer& buff, const EntityType& e) const | |
701 | { | ||
702 | 143760 | const auto rowIdx = rowEntityMapper_.index(e); | |
703 | // send all matrix entries for which the column index is in the index set | ||
704 |
8/8✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 795970 times.
✓ Branch 2 taken 8896 times.
✓ Branch 3 taken 795970 times.
✓ Branch 4 taken 8896 times.
✓ Branch 5 taken 795970 times.
✓ Branch 6 taken 724090 times.
✓ Branch 7 taken 70336 times.
|
1753492 | for (auto colIt = A_[rowIdx].begin(); colIt != A_[rowIdx].end(); ++colIt) |
705 |
4/4✓ Branch 0 taken 269968 times.
✓ Branch 1 taken 463018 times.
✓ Branch 2 taken 269968 times.
✓ Branch 3 taken 463018 times.
|
5863888 | if (auto it = indexToID_.find(colIt.index()); it != indexToID_.end()) |
706 | 2159744 | buff.write(MatrixEntry{ it->second, *colIt }); | |
707 | 143760 | } | |
708 | |||
709 | /*! | ||
710 | * \brief Unpack data from message buffer to user | ||
711 | */ | ||
712 | template<class MessageBuffer, class EntityType> | ||
713 | 143760 | void scatter(MessageBuffer& buff, const EntityType& e, std::size_t n) | |
714 | { | ||
715 | 143760 | const auto rowIdx = rowEntityMapper_.index(e); | |
716 |
2/2✓ Branch 1 taken 269968 times.
✓ Branch 2 taken 71880 times.
|
683696 | for (std::size_t k = 0; k < n; k++) |
717 | { | ||
718 | 539936 | MatrixEntry m; | |
719 | 539936 | buff.read(m); | |
720 | 539936 | const auto& [colDofID, matrixBlock] = m; // unpack | |
721 | |||
722 | // only add entries in the index set and for which A has allocated memory | ||
723 |
5/5✓ Branch 0 taken 4410 times.
✓ Branch 1 taken 265350 times.
✓ Branch 2 taken 4618 times.
✓ Branch 3 taken 265350 times.
✓ Branch 4 taken 208 times.
|
557576 | if (auto it = idToIndex_.find(colDofID); it != idToIndex_.end()) |
724 |
2/4✗ Branch 4 not taken.
✓ Branch 5 taken 269760 times.
✓ Branch 6 taken 269760 times.
✗ Branch 7 not taken.
|
2158080 | if (A_[rowIdx].find(it->second) != A_[rowIdx].end()) |
725 | 1649416 | A_[rowIdx][it->second] += matrixBlock; | |
726 | } | ||
727 | 143760 | } | |
728 | |||
729 | private: | ||
730 | const RowDofMapper& rowEntityMapper_; | ||
731 | const std::map<IdType, int>& idToIndex_; | ||
732 | const std::map<int, IdType>& indexToID_; | ||
733 | Matrix& A_; | ||
734 | |||
735 | }; // class MatrixEntryExchange | ||
736 | |||
737 | public: | ||
738 | |||
739 | 940 | ParallelMatrixHelper(const GridView& gridView, const RowDofMapper& mapper) | |
740 |
0/2✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2820 | : gridView_(gridView), mapper_(mapper) |
741 | { | ||
742 | 940 | idToIndex_.clear(); | |
743 | 940 | indexToID_.clear(); | |
744 | |||
745 |
6/10✓ Branch 1 taken 850 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 850 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 90 times.
✓ Branch 7 taken 850 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 850 times.
✗ Branch 11 not taken.
|
1970 | std::vector<bool> handledDof(gridView_.size(rowDofCodim), false); |
746 |
13/16✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36128 times.
✓ Branch 4 taken 848 times.
✓ Branch 5 taken 18720 times.
✓ Branch 6 taken 90 times.
✓ Branch 7 taken 758 times.
✓ Branch 8 taken 18720 times.
✓ Branch 9 taken 1290386 times.
✓ Branch 10 taken 758 times.
✓ Branch 11 taken 1290386 times.
✓ Branch 12 taken 758 times.
✓ Branch 14 taken 1290386 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1290386 times.
✗ Branch 18 not taken.
|
1328212 | for (const auto& element : elements(gridView_)) |
747 | { | ||
748 |
5/5✓ Branch 0 taken 69264 times.
✓ Branch 1 taken 6555570 times.
✓ Branch 2 taken 69264 times.
✓ Branch 3 taken 5246464 times.
✓ Branch 4 taken 1309106 times.
|
6642150 | for (int i = 0; i < element.subEntities(rowDofCodim); ++i) |
749 | { | ||
750 |
1/6✓ Branch 1 taken 5229148 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
10452680 | const auto entity = element.template subEntity<rowDofCodim>(i); |
751 |
5/5✓ Branch 0 taken 5024050 times.
✓ Branch 1 taken 274362 times.
✓ Branch 2 taken 6390 times.
✓ Branch 3 taken 68634 times.
✓ Branch 4 taken 69120 times.
|
5367676 | if (entity.partitionType() == Dune::BorderEntity) |
752 | { | ||
753 |
1/2✓ Branch 1 taken 5760 times.
✗ Branch 2 not taken.
|
284302 | const auto localRowIdx = mapper_.index(entity); |
754 |
3/6✓ Branch 0 taken 284302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 284302 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 284302 times.
✗ Branch 5 not taken.
|
852906 | if (!handledDof[localRowIdx]) |
755 | { | ||
756 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 284302 times.
✓ Branch 3 taken 284302 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 284302 times.
✗ Branch 7 not taken.
|
284302 | IdType dofIdxGlobal = gridView_.grid().globalIdSet().id(entity); |
757 |
1/2✓ Branch 1 taken 284302 times.
✗ Branch 2 not taken.
|
284302 | idToIndex_.emplace(dofIdxGlobal, localRowIdx); |
758 |
1/2✓ Branch 1 taken 284302 times.
✗ Branch 2 not taken.
|
284302 | indexToID_.emplace(localRowIdx, dofIdxGlobal); |
759 | } | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | 940 | } | |
764 | |||
765 | /*! | ||
766 | * \brief communicates values for the sparsity pattern of the new matrix. | ||
767 | * \param A Matrix to operate on. | ||
768 | * \param isGhost Function returning if a column dof index is on a ghost entity | ||
769 | */ | ||
770 | template<class IsGhostFunc> | ||
771 | 940 | void extendMatrix(Matrix& A, const IsGhostFunc& isGhost) | |
772 | { | ||
773 | if constexpr (Detail::canCommunicate<typename GridView::Grid, rowDofCodim>) | ||
774 | { | ||
775 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 758 times.
✓ Branch 3 taken 182 times.
✓ Branch 4 taken 758 times.
✓ Branch 5 taken 182 times.
|
940 | if (gridView_.comm().size() <= 1) |
776 | ✗ | return; | |
777 | |||
778 | // make a copy of the matrix as originally assembled | ||
779 | 1880 | Matrix matrixAsAssembled(A); | |
780 | |||
781 | // first get entries in sparsity pattern from other processes | ||
782 | 940 | std::size_t numNonZeroEntries = 0; | |
783 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
940 | std::vector<std::set<int>> sparsityPattern; // column indices for every row |
784 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
940 | MatrixPatternExchange<IsGhostFunc> dataHandle(mapper_, idToIndex_, indexToID_, A, sparsityPattern, isGhost); |
785 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
940 | gridView_.communicate( |
786 | dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication | ||
787 | ); | ||
788 | |||
789 | // add own entries to the sparsity pattern and count number of non-zeros | ||
790 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 1485606 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1485606 times.
✓ Branch 4 taken 1484666 times.
✓ Branch 5 taken 940 times.
|
2970272 | for (auto rowIt = A.begin(); rowIt != A.end(); ++rowIt) |
791 | { | ||
792 | 2969332 | const auto colEndIt = A[rowIt.index()].end(); | |
793 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 13905886 times.
✓ Branch 2 taken 12421220 times.
✓ Branch 3 taken 1484666 times.
|
15390552 | for (auto colIt = rowIt->begin(); colIt != colEndIt; ++colIt) |
794 | 37263660 | if (!sparsityPattern[rowIt.index()].count(colIt.index())) | |
795 |
1/2✓ Branch 1 taken 12152464 times.
✗ Branch 2 not taken.
|
12152464 | sparsityPattern[rowIt.index()].insert(colIt.index()); |
796 | |||
797 | 4453998 | numNonZeroEntries += sparsityPattern[rowIt.index()].size(); | |
798 | } | ||
799 | |||
800 | // insert any additional entries into the matrix | ||
801 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
940 | A.setSize(matrixAsAssembled.N(), matrixAsAssembled.M(), numNonZeroEntries); |
802 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
940 | A.setBuildMode(Matrix::row_wise); |
803 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
1880 | auto citer = A.createbegin(); |
804 |
6/8✓ Branch 0 taken 1484666 times.
✓ Branch 1 taken 940 times.
✓ Branch 2 taken 1484666 times.
✓ Branch 3 taken 940 times.
✓ Branch 5 taken 1484666 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1484666 times.
✗ Branch 9 not taken.
|
2972152 | for (auto i = sparsityPattern.begin(), end = sparsityPattern.end(); i!=end; ++i, ++citer) |
805 |
2/2✓ Branch 0 taken 12421722 times.
✓ Branch 1 taken 1484666 times.
|
16875720 | for (auto si = i->begin(), send = i->end(); si!=send; ++si) |
806 |
2/4✓ Branch 1 taken 12421722 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12421722 times.
✗ Branch 5 not taken.
|
24843444 | citer.insert(*si); |
807 | |||
808 | // reset matrix to contain original values | ||
809 |
1/4✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
940 | A = 0; |
810 | 940 | const auto rowEndIt = matrixAsAssembled.end(); | |
811 |
4/4✓ Branch 0 taken 1484666 times.
✓ Branch 1 taken 940 times.
✓ Branch 2 taken 1484666 times.
✓ Branch 3 taken 940 times.
|
1485606 | for (auto rowIt = matrixAsAssembled.begin(); rowIt != rowEndIt; ++rowIt) |
812 |
5/8✗ Branch 0 not taken.
✓ Branch 1 taken 13905886 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13905886 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 13905886 times.
✓ Branch 6 taken 12421220 times.
✓ Branch 7 taken 1484666 times.
|
40232992 | for (auto colIt = matrixAsAssembled[rowIt.index()].begin(); colIt != matrixAsAssembled[rowIt.index()].end(); ++colIt) |
813 |
4/8✓ Branch 1 taken 12421220 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12421220 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12421220 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 12421220 times.
✗ Branch 11 not taken.
|
49684880 | A[rowIt.index()][colIt.index()] = *colIt; |
814 | |||
815 | // The matrix A has now a possible extended sparsity pattern but any additional entries are | ||
816 | // initialized to zero and have to be filled by the sumEntries function | ||
817 | } | ||
818 | else | ||
819 | DUNE_THROW(Dune::InvalidStateException, "Cannot call extendMatrix for a grid that cannot communicate codim-" << rowDofCodim << "-entities."); | ||
820 | } | ||
821 | |||
822 | /*! | ||
823 | * \brief Sums up the entries corresponding to border entities (usually vertices or faces) | ||
824 | * \param A Matrix to operate on | ||
825 | * | ||
826 | * The idea is as follows: (Blatt and Bastian (2009) https://doi.org/10.1504/IJCSE.2008.021112) | ||
827 | * The local matrix operator stores for each row that corresponds to a dof (uniquely) owned by this process | ||
828 | * the full row of the global operator with the same entries as the global operator. | ||
829 | |||
830 | * This, together with some masking procedure (end of Section 2.4.1) allows to compute a matrix-vector product | ||
831 | * given a consistent vector representation such that the result is in a valid representation. Each valid | ||
832 | * representation can be transformed to a additive unique representation by setting all entries for | ||
833 | * dofs that are not (uniquely) owned by the process to zero. | ||
834 | */ | ||
835 | 940 | void sumEntries(Matrix& A) | |
836 | { | ||
837 | if constexpr (Detail::canCommunicate<typename GridView::Grid, rowDofCodim>) | ||
838 | { | ||
839 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 758 times.
✓ Branch 3 taken 182 times.
✓ Branch 4 taken 758 times.
✓ Branch 5 taken 182 times.
|
940 | if (gridView_.comm().size() <= 1) |
840 | ✗ | return; | |
841 | |||
842 | 1880 | MatrixEntryExchange dataHandle(mapper_, idToIndex_, indexToID_, A); | |
843 | 940 | gridView_.communicate( | |
844 | dataHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication | ||
845 | ); | ||
846 | } | ||
847 | else | ||
848 | DUNE_THROW(Dune::InvalidStateException, | ||
849 | "Cannot call sumEntries for a grid that cannot communicate codim-" << rowDofCodim << "-entities." | ||
850 | ); | ||
851 | } | ||
852 | |||
853 | private: | ||
854 | const GridView gridView_; | ||
855 | const RowDofMapper& mapper_; | ||
856 | std::map<IdType, int> idToIndex_; | ||
857 | std::map<int, IdType> indexToID_; | ||
858 | |||
859 | }; | ||
860 | |||
861 | /*! | ||
862 | * \brief Prepare a matrix for parallel solvers | ||
863 | */ | ||
864 | template<class LinearSolverTraits, class ParallelTraits, | ||
865 | class Matrix, class ParallelHelper> | ||
866 | 1880 | void prepareMatrixParallel(Matrix& A, ParallelHelper& pHelper) | |
867 | { | ||
868 | if constexpr (ParallelTraits::isNonOverlapping) | ||
869 | { | ||
870 | // extend the matrix pattern such that it is usable for a parallel solver | ||
871 | // and make right-hand side consistent | ||
872 | using GridView = typename LinearSolverTraits::GridView; | ||
873 | using DofMapper = typename LinearSolverTraits::DofMapper; | ||
874 | static constexpr int dofCodim = LinearSolverTraits::dofCodim; | ||
875 | 3760 | ParallelMatrixHelper<Matrix, GridView, DofMapper, dofCodim> matrixHelper(pHelper.gridView(), pHelper.dofMapper()); | |
876 |
7/24✓ Branch 0 taken 262476 times.
✓ Branch 1 taken 940 times.
✓ Branch 2 taken 262476 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2334 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2334 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4448 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4448 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
540396 | matrixHelper.extendMatrix(A, [&pHelper](auto idx){ return pHelper.isGhost(idx); }); |
877 |
1/2✓ Branch 1 taken 940 times.
✗ Branch 2 not taken.
|
1880 | matrixHelper.sumEntries(A); |
878 | } | ||
879 | 1880 | } | |
880 | |||
881 | /*! | ||
882 | * \brief Prepare a vector for parallel solvers | ||
883 | */ | ||
884 | template<class LinearSolverTraits, class ParallelTraits, | ||
885 | class Vector, class ParallelHelper> | ||
886 | ✗ | void prepareVectorParallel(Vector& b, ParallelHelper& pHelper) | |
887 | { | ||
888 | if constexpr (ParallelTraits::isNonOverlapping) | ||
889 | { | ||
890 | // extend the matrix pattern such that it is usable for a parallel solver | ||
891 | // and make right-hand side consistent | ||
892 | using GridView = typename LinearSolverTraits::GridView; | ||
893 | using DofMapper = typename LinearSolverTraits::DofMapper; | ||
894 | static constexpr int dofCodim = LinearSolverTraits::dofCodim; | ||
895 |
0/5✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
858 | ParallelVectorHelper<GridView, DofMapper, dofCodim> vectorHelper(pHelper.gridView(), pHelper.dofMapper()); |
896 |
0/5✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
286 | vectorHelper.makeNonOverlappingConsistent(b); |
897 | } | ||
898 | ✗ | } | |
899 | |||
900 | /*! | ||
901 | * \brief Prepare linear algebra variables for parallel solvers | ||
902 | */ | ||
903 | template<class LinearSolverTraits, class ParallelTraits, | ||
904 | class Matrix, class Vector, class ParallelHelper> | ||
905 | 572 | void prepareLinearAlgebraParallel(Matrix& A, Vector& b, ParallelHelper& pHelper) | |
906 | { | ||
907 | 966 | prepareMatrixParallel<LinearSolverTraits, ParallelTraits>(A, pHelper); | |
908 | 966 | prepareVectorParallel<LinearSolverTraits, ParallelTraits>(b, pHelper); | |
909 | 572 | } | |
910 | |||
911 | /*! | ||
912 | * \brief Prepare linear algebra variables for parallel solvers | ||
913 | */ | ||
914 | template<class LinearSolverTraits, class ParallelTraits, | ||
915 | class Matrix, class Vector, class ParallelHelper> | ||
916 | void prepareLinearAlgebraParallel(Matrix& A, Vector& b, | ||
917 | std::shared_ptr<typename ParallelTraits::Comm>& comm, | ||
918 | std::shared_ptr<typename ParallelTraits::LinearOperator>& fop, | ||
919 | std::shared_ptr<typename ParallelTraits::ScalarProduct>& sp, | ||
920 | ParallelHelper& pHelper) | ||
921 | { | ||
922 | prepareLinearAlgebraParallel<LinearSolverTraits, ParallelTraits>(A, b, pHelper); | ||
923 | const auto category = ParallelTraits::isNonOverlapping ? | ||
924 | Dune::SolverCategory::nonoverlapping : Dune::SolverCategory::overlapping; | ||
925 | |||
926 | comm = std::make_shared<typename ParallelTraits::Comm>(pHelper.gridView().comm(), category); | ||
927 | pHelper.createParallelIndexSet(*comm); | ||
928 | fop = std::make_shared<typename ParallelTraits::LinearOperator>(A, *comm); | ||
929 | sp = std::make_shared<typename ParallelTraits::ScalarProduct>(*comm); | ||
930 | } | ||
931 | |||
932 | } // end namespace Dumux | ||
933 | |||
934 | #endif | ||
935 |