MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_LocalLexicographicIndexManager_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_LOCALLEXICOGRAPHICINDEXMANAGER_DEF_HPP_
11#define MUELU_LOCALLEXICOGRAPHICINDEXMANAGER_DEF_HPP_
12
14#include <Xpetra_MapFactory.hpp>
15
16namespace MueLu {
17
18template <class LocalOrdinal, class GlobalOrdinal, class Node>
20 LocalLexicographicIndexManager(const RCP<const Teuchos::Comm<int> > comm, const bool coupled,
21 const int NumDimensions, const int interpolationOrder,
22 const int MyRank, const int NumRanks,
23 const Array<GO> GFineNodesPerDir, const Array<LO> LFineNodesPerDir,
24 const Array<LO> CoarseRate, const Array<GO> MeshData)
25 : IndexManager(comm, coupled, false, NumDimensions, interpolationOrder, GFineNodesPerDir, LFineNodesPerDir)
26 , myRank(MyRank)
27 , numRanks(NumRanks) {
28 // Allocate data based on user input
29 meshData.resize(numRanks);
30 rankIndices.resize(numRanks);
32
33 // Load coarse rate, being careful about formating
34 for (int dim = 0; dim < 3; ++dim) {
35 if (dim < this->numDimensions) {
36 if (CoarseRate.size() == 1) {
37 this->coarseRate[dim] = CoarseRate[0];
38 } else if (CoarseRate.size() == this->numDimensions) {
39 this->coarseRate[dim] = CoarseRate[dim];
40 }
41 } else {
42 this->coarseRate[dim] = 1;
43 }
44 }
45
46 // Load meshData for local lexicographic case
47 for (int rank = 0; rank < numRanks; ++rank) {
48 meshData[rank].resize(10);
49 for (int entry = 0; entry < 10; ++entry) {
50 meshData[rank][entry] = MeshData[10 * rank + entry];
51 }
52 }
53
54 if (this->coupled_) {
57 }
58
59 // Start simple parameter calculation
61 for (int dim = 0; dim < 3; ++dim) {
62 this->startIndices[dim] = meshData[myRankIndex][2 * dim + 3];
63 this->startIndices[dim + 3] = meshData[myRankIndex][2 * dim + 4];
64 }
65
69} // Constructor
70
71template <class LocalOrdinal, class GlobalOrdinal, class Node>
74 this->gNumCoarseNodes10 = this->gCoarseNodesPerDir[0] * this->gCoarseNodesPerDir[1];
75 this->gNumCoarseNodes = this->gNumCoarseNodes10 * this->gCoarseNodesPerDir[2];
76}
77
78template <class LocalOrdinal, class GlobalOrdinal, class Node>
80 getGhostedNodesData(const RCP<const Map> /* fineMap */,
81 Array<LO>& ghostedNodeCoarseLIDs,
82 Array<int>& ghostedNodeCoarsePIDs,
83 Array<GO>& ghostedNodeCoarseGIDs) const {
84 // First we allocated memory for the outputs
85 ghostedNodeCoarseLIDs.resize(this->getNumLocalGhostedNodes());
86 ghostedNodeCoarsePIDs.resize(this->getNumLocalGhostedNodes());
87 ghostedNodeCoarseGIDs.resize(this->numGhostedNodes);
88
89 // Now the tricky part starts, the coarse nodes / ghosted coarse nodes need to be imported.
90 // This requires finding what their GID on the fine mesh is. They need to be ordered
91 // lexicographically to allow for fast sweeps through the mesh.
92
93 // We loop over all ghosted coarse nodes by increasing global lexicographic order
94 Array<LO> ghostedCoarseNodeCoarseIndices(3), ghostedCoarseNodeFineIndices(3);
95 Array<LO> lCoarseNodeCoarseIndices(3);
96 Array<GO> lCoarseNodeCoarseGIDs(this->lNumCoarseNodes);
97 LO currentIndex = -1, countCoarseNodes = 0;
98 for (int k = 0; k < this->ghostedNodesPerDir[2]; ++k) {
99 for (int j = 0; j < this->ghostedNodesPerDir[1]; ++j) {
100 for (int i = 0; i < this->ghostedNodesPerDir[0]; ++i) {
101 currentIndex = k * this->numGhostedNodes10 + j * this->ghostedNodesPerDir[0] + i;
102 ghostedCoarseNodeCoarseIndices[0] = this->startGhostedCoarseNode[0] + i;
103 ghostedCoarseNodeFineIndices[0] = ghostedCoarseNodeCoarseIndices[0] * this->coarseRate[0];
104 if (ghostedCoarseNodeFineIndices[0] > this->gFineNodesPerDir[0] - 1) {
105 ghostedCoarseNodeFineIndices[0] = this->gFineNodesPerDir[0] - 1;
106 }
107 ghostedCoarseNodeCoarseIndices[1] = this->startGhostedCoarseNode[1] + j;
108 ghostedCoarseNodeFineIndices[1] = ghostedCoarseNodeCoarseIndices[1] * this->coarseRate[1];
109 if (ghostedCoarseNodeFineIndices[1] > this->gFineNodesPerDir[1] - 1) {
110 ghostedCoarseNodeFineIndices[1] = this->gFineNodesPerDir[1] - 1;
111 }
112 ghostedCoarseNodeCoarseIndices[2] = this->startGhostedCoarseNode[2] + k;
113 ghostedCoarseNodeFineIndices[2] = ghostedCoarseNodeCoarseIndices[2] * this->coarseRate[2];
114 if (ghostedCoarseNodeFineIndices[2] > this->gFineNodesPerDir[2] - 1) {
115 ghostedCoarseNodeFineIndices[2] = this->gFineNodesPerDir[2] - 1;
116 }
117
118 GO myGID = -1, myCoarseGID = -1;
119 LO myLID = -1, myPID = -1, myCoarseLID = -1;
120 getGIDLocalLexicographic(i, j, k, ghostedCoarseNodeFineIndices, myGID, myPID, myLID);
121
122 int rankIndex = rankIndices[myPID];
123 for (int dim = 0; dim < 3; ++dim) {
124 if (dim < this->numDimensions) {
125 lCoarseNodeCoarseIndices[dim] = ghostedCoarseNodeCoarseIndices[dim] - coarseMeshData[rankIndex][3 + 2 * dim];
126 }
127 }
128 LO myRankIndexCoarseNodesInDir0 = coarseMeshData[rankIndex][4] - coarseMeshData[rankIndex][3] + 1;
129 LO myRankIndexCoarseNodes10 = (coarseMeshData[rankIndex][6] - coarseMeshData[rankIndex][5] + 1) * myRankIndexCoarseNodesInDir0;
130 myCoarseLID = lCoarseNodeCoarseIndices[2] * myRankIndexCoarseNodes10 + lCoarseNodeCoarseIndices[1] * myRankIndexCoarseNodesInDir0 + lCoarseNodeCoarseIndices[0];
131 myCoarseGID = myCoarseLID + coarseMeshData[rankIndex][9];
132
133 ghostedNodeCoarseLIDs[currentIndex] = myCoarseLID;
134 ghostedNodeCoarsePIDs[currentIndex] = myPID;
135 ghostedNodeCoarseGIDs[currentIndex] = myCoarseGID;
136
137 if (myPID == myRank) {
138 lCoarseNodeCoarseGIDs[countCoarseNodes] = myCoarseGID;
139 ++countCoarseNodes;
140 }
141 }
142 }
143 }
144}
145
146template <class LocalOrdinal, class GlobalOrdinal, class Node>
148 getCoarseNodesData(const RCP<const Map> fineCoordinatesMap,
149 Array<GO>& coarseNodeCoarseGIDs,
150 Array<GO>& coarseNodeFineGIDs) const {
151 // Allocate sufficient storage space for outputs
152 coarseNodeCoarseGIDs.resize(this->getNumLocalCoarseNodes());
153 coarseNodeFineGIDs.resize(this->getNumLocalCoarseNodes());
154
155 // Load all the GIDs on the fine mesh
156 ArrayView<const GO> fineNodeGIDs = fineCoordinatesMap->getLocalElementList();
157
158 Array<GO> coarseStartIndices(3);
159 for (int dim = 0; dim < 3; ++dim) {
160 coarseStartIndices[dim] = this->coarseMeshData[myRankIndex][2 * dim + 3];
161 }
162
163 // Extract the fine LIDs of the coarse nodes and store the corresponding GIDs
164 LO fineLID;
165 for (LO coarseLID = 0; coarseLID < this->getNumLocalCoarseNodes(); ++coarseLID) {
166 Array<LO> coarseIndices(3), fineIndices(3), gCoarseIndices(3);
167 this->getCoarseNodeLocalTuple(coarseLID,
168 coarseIndices[0],
169 coarseIndices[1],
170 coarseIndices[2]);
171 getCoarseNodeFineLID(coarseIndices[0], coarseIndices[1], coarseIndices[2], fineLID);
172 coarseNodeFineGIDs[coarseLID] = fineNodeGIDs[fineLID];
173
174 LO myRankIndexCoarseNodesInDir0 = coarseMeshData[myRankIndex][4] - coarseMeshData[myRankIndex][3] + 1;
175 LO myRankIndexCoarseNodes10 = (coarseMeshData[myRankIndex][6] - coarseMeshData[myRankIndex][5] + 1) * myRankIndexCoarseNodesInDir0;
176 LO myCoarseLID = coarseIndices[2] * myRankIndexCoarseNodes10 + coarseIndices[1] * myRankIndexCoarseNodesInDir0 + coarseIndices[0];
177 GO myCoarseGID = myCoarseLID + coarseMeshData[myRankIndex][9];
178 coarseNodeCoarseGIDs[coarseLID] = myCoarseGID;
179 }
180}
181
182template <class LocalOrdinal, class GlobalOrdinal, class Node>
184 getGIDLocalLexicographic(const LO iGhosted, const LO jGhosted, const LO kGhosted,
185 const Array<LO> coarseNodeFineIndices,
186 GO& myGID, LO& myPID, LO& myLID) const {
187 LO ni = -1, nj = -1, li = -1, lj = -1, lk = -1;
188 LO myRankGuess = myRankIndex;
189 // We try to make a logical guess as to which PID owns the current coarse node
190 if (iGhosted == 0 && this->ghostInterface[0]) {
191 --myRankGuess;
192 } else if ((iGhosted == this->ghostedNodesPerDir[0] - 1) && this->ghostInterface[1]) {
193 ++myRankGuess;
194 }
195 if (jGhosted == 0 && this->ghostInterface[2]) {
196 myRankGuess -= pi;
197 } else if ((jGhosted == this->ghostedNodesPerDir[1] - 1) && this->ghostInterface[3]) {
198 myRankGuess += pi;
199 }
200 if (kGhosted == 0 && this->ghostInterface[4]) {
201 myRankGuess -= pj * pi;
202 } else if ((kGhosted == this->ghostedNodesPerDir[2] - 1) && this->ghostInterface[5]) {
203 myRankGuess += pj * pi;
204 }
205 if (coarseNodeFineIndices[0] >= meshData[myRankGuess][3] && coarseNodeFineIndices[0] <= meshData[myRankGuess][4] && coarseNodeFineIndices[1] >= meshData[myRankGuess][5] && coarseNodeFineIndices[1] <= meshData[myRankGuess][6] && coarseNodeFineIndices[2] >= meshData[myRankGuess][7] && coarseNodeFineIndices[2] <= meshData[myRankGuess][8] && myRankGuess < numRanks - 1) {
206 myPID = meshData[myRankGuess][0];
207 ni = meshData[myRankGuess][4] - meshData[myRankGuess][3] + 1;
208 nj = meshData[myRankGuess][6] - meshData[myRankGuess][5] + 1;
209 li = coarseNodeFineIndices[0] - meshData[myRankGuess][3];
210 lj = coarseNodeFineIndices[1] - meshData[myRankGuess][5];
211 lk = coarseNodeFineIndices[2] - meshData[myRankGuess][7];
212 myLID = lk * nj * ni + lj * ni + li;
213 myGID = meshData[myRankGuess][9] + myLID;
214 } else { // The guess failed, let us use the heavy artilery: std::find_if()
215 // It could be interesting to monitor how many times this branch of the code gets
216 // used as it is far more expensive than the above one...
217 auto nodeRank = std::find_if(myBlockStart, myBlockEnd,
218 [coarseNodeFineIndices](const std::vector<GO>& vec) {
219 if (coarseNodeFineIndices[0] >= vec[3] && coarseNodeFineIndices[0] <= vec[4] && coarseNodeFineIndices[1] >= vec[5] && coarseNodeFineIndices[1] <= vec[6] && coarseNodeFineIndices[2] >= vec[7] && coarseNodeFineIndices[2] <= vec[8]) {
220 return true;
221 } else {
222 return false;
223 }
224 });
225 myPID = (*nodeRank)[0];
226 ni = (*nodeRank)[4] - (*nodeRank)[3] + 1;
227 nj = (*nodeRank)[6] - (*nodeRank)[5] + 1;
228 li = coarseNodeFineIndices[0] - (*nodeRank)[3];
229 lj = coarseNodeFineIndices[1] - (*nodeRank)[5];
230 lk = coarseNodeFineIndices[2] - (*nodeRank)[7];
231 myLID = lk * nj * ni + lj * ni + li;
232 myGID = (*nodeRank)[9] + myLID;
233 }
234}
235
236template <class LocalOrdinal, class GlobalOrdinal, class Node>
239 std::sort(meshData.begin(), meshData.end(),
240 [](const std::vector<GO>& a, const std::vector<GO>& b) -> bool {
241 // The below function sorts ranks by blockID, kmin, jmin and imin
242 if (a[2] < b[2]) {
243 return true;
244 } else if (a[2] == b[2]) {
245 if (a[7] < b[7]) {
246 return true;
247 } else if (a[7] == b[7]) {
248 if (a[5] < b[5]) {
249 return true;
250 } else if (a[5] == b[5]) {
251 if (a[3] < b[3]) {
252 return true;
253 }
254 }
255 }
256 }
257 return false;
258 });
259
260 numBlocks = meshData[numRanks - 1][2] + 1;
261 // Find the range of the current block
262 myBlockStart = std::lower_bound(meshData.begin(), meshData.end(), myBlock - 1,
263 [](const std::vector<GO>& vec, const GO val) -> bool {
264 return (vec[2] < val) ? true : false;
265 });
266 myBlockEnd = std::upper_bound(meshData.begin(), meshData.end(), myBlock,
267 [](const GO val, const std::vector<GO>& vec) -> bool {
268 return (val < vec[2]) ? true : false;
269 });
270 // Assuming that i,j,k and ranges are split in pi, pj and pk processors
271 // we search for these numbers as they will allow us to find quickly the PID of processors
272 // owning ghost nodes.
273 auto myKEnd = std::upper_bound(myBlockStart, myBlockEnd, (*myBlockStart)[3],
274 [](const GO val, const std::vector<GO>& vec) -> bool {
275 return (val < vec[7]) ? true : false;
276 });
277 auto myJEnd = std::upper_bound(myBlockStart, myKEnd, (*myBlockStart)[3],
278 [](const GO val, const std::vector<GO>& vec) -> bool {
279 return (val < vec[5]) ? true : false;
280 });
281 pi = std::distance(myBlockStart, myJEnd);
282 pj = std::distance(myBlockStart, myKEnd) / pi;
283 pk = std::distance(myBlockStart, myBlockEnd) / (pj * pi);
284
285 // We also look for the index of the local rank in the current block.
286 const int MyRank = myRank;
287 myRankIndex = std::distance(meshData.begin(),
288 std::find_if(myBlockStart, myBlockEnd,
289 [MyRank](const std::vector<GO>& vec) -> bool {
290 return (vec[0] == MyRank) ? true : false;
291 }));
292 // We also construct a mapping of rank to rankIndex in the meshData vector,
293 // this will allow us to access data quickly later on.
294 for (int rankIndex = 0; rankIndex < numRanks; ++rankIndex) {
295 rankIndices[meshData[rankIndex][0]] = rankIndex;
296 }
297}
298
299template <class LocalOrdinal, class GlobalOrdinal, class Node>
302 Array<LO> rankOffset(3);
303 for (int rank = 0; rank < numRanks; ++rank) {
304 coarseMeshData[rank].resize(10);
305 coarseMeshData[rank][0] = meshData[rank][0];
306 coarseMeshData[rank][1] = meshData[rank][1];
307 coarseMeshData[rank][2] = meshData[rank][2];
308 for (int dim = 0; dim < 3; ++dim) {
309 coarseMeshData[rank][3 + 2 * dim] = meshData[rank][3 + 2 * dim] / this->coarseRate[dim];
310 if (meshData[rank][3 + 2 * dim] % this->coarseRate[dim] > 0) {
311 ++coarseMeshData[rank][3 + 2 * dim];
312 }
313 coarseMeshData[rank][3 + 2 * dim + 1] = meshData[rank][3 + 2 * dim + 1] / this->coarseRate[dim];
314 if (meshData[rank][3 + 2 * dim + 1] == this->gFineNodesPerDir[dim] - 1 &&
315 meshData[rank][3 + 2 * dim + 1] % this->coarseRate[dim] > 0) {
316 // this->endRate[dim] < this->coarseRate[dim]) {
317 ++coarseMeshData[rank][3 + 2 * dim + 1];
318 }
319 }
320 if (rank > 0) {
321 coarseMeshData[rank][9] = coarseMeshData[rank - 1][9] + (coarseMeshData[rank - 1][8] - coarseMeshData[rank - 1][7] + 1) * (coarseMeshData[rank - 1][6] - coarseMeshData[rank - 1][5] + 1) * (coarseMeshData[rank - 1][4] - coarseMeshData[rank - 1][3] + 1);
322 }
323 }
324}
325
326template <class LocalOrdinal, class GlobalOrdinal, class Node>
328 getCoarseMeshData() const { return coarseMeshData; }
329
330template <class LocalOrdinal, class GlobalOrdinal, class Node>
332 getFineNodeGlobalTuple(const GO /* myGID */, GO& /* i */, GO& /* j */, GO& /* k */) const {
333}
334
335template <class LocalOrdinal, class GlobalOrdinal, class Node>
337 getFineNodeLocalTuple(const LO myLID, LO& i, LO& j, LO& k) const {
338 LO tmp;
339 k = myLID / this->lNumFineNodes10;
340 tmp = myLID % this->lNumFineNodes10;
341 j = tmp / this->lFineNodesPerDir[0];
342 i = tmp % this->lFineNodesPerDir[0];
343}
344
345template <class LocalOrdinal, class GlobalOrdinal, class Node>
347 getFineNodeGhostedTuple(const LO myLID, LO& i, LO& j, LO& k) const {
348 LO tmp;
349 k = myLID / this->lNumFineNodes10;
350 tmp = myLID % this->lNumFineNodes10;
351 j = tmp / this->lFineNodesPerDir[0];
352 i = tmp % this->lFineNodesPerDir[0];
353
354 k += this->offsets[2];
355 j += this->offsets[1];
356 i += this->offsets[0];
357}
358
359template <class LocalOrdinal, class GlobalOrdinal, class Node>
361 getFineNodeGID(const GO /* i */, const GO /* j */, const GO /* k */, GO& /* myGID */) const {
362}
363
364template <class LocalOrdinal, class GlobalOrdinal, class Node>
366 getFineNodeLID(const LO /* i */, const LO /* j */, const LO /* k */, LO& /* myLID */) const {
367}
368
369template <class LocalOrdinal, class GlobalOrdinal, class Node>
371 getCoarseNodeGlobalTuple(const GO /* myGID */, GO& /* i */, GO& /* j */, GO& /* k */) const {
372}
373
374template <class LocalOrdinal, class GlobalOrdinal, class Node>
376 getCoarseNodeLocalTuple(const LO myLID, LO& i, LO& j, LO& k) const {
377 LO tmp;
378 k = myLID / this->lNumCoarseNodes10;
379 tmp = myLID % this->lNumCoarseNodes10;
380 j = tmp / this->lCoarseNodesPerDir[0];
381 i = tmp % this->lCoarseNodesPerDir[0];
382}
383
384template <class LocalOrdinal, class GlobalOrdinal, class Node>
386 getCoarseNodeGID(const GO /* i */, const GO /* j */, const GO /* k */, GO& /* myGID */) const {
387}
388
389template <class LocalOrdinal, class GlobalOrdinal, class Node>
391 getCoarseNodeLID(const LO /* i */, const LO /* j */, const LO /* k */, LO& /* myLID */) const {
392}
393
394template <class LocalOrdinal, class GlobalOrdinal, class Node>
396 getCoarseNodeGhostedLID(const LO i, const LO j, const LO k, LO& myLID) const {
397 myLID = k * this->numGhostedNodes10 + j * this->ghostedNodesPerDir[0] + i;
398}
399
400template <class LocalOrdinal, class GlobalOrdinal, class Node>
402 getCoarseNodeFineLID(const LO i, const LO j, const LO k, LO& myLID) const {
403 // Assumptions: (i,j,k) is a tuple on the coarse mesh
404 // myLID is the corresponding local ID on the fine mesh
405 const LO multiplier[3] = {1, this->lFineNodesPerDir[0], this->lNumFineNodes10};
406 const LO indices[3] = {i, j, k};
407
408 myLID = 0;
409 for (int dim = 0; dim < 3; ++dim) {
410 if ((indices[dim] == this->getLocalCoarseNodesInDir(dim) - 1) && this->meshEdge[2 * dim + 1]) {
411 // We are dealing with the last node on the mesh in direction dim
412 // so we can simply use the number of nodes on the fine mesh in that direction
413 myLID += (this->getLocalFineNodesInDir(dim) - 1) * multiplier[dim];
414 } else {
415 myLID += (indices[dim] * this->getCoarseningRate(dim) + this->getCoarseNodeOffset(dim)) * multiplier[dim];
416 }
417 }
418}
419
420template <class LocalOrdinal, class GlobalOrdinal, class Node>
422 getGhostedNodeFineLID(const LO /* i */, const LO /* j */, const LO /* k */, LO& /* myLID */) const {
423}
424
425template <class LocalOrdinal, class GlobalOrdinal, class Node>
427 getGhostedNodeCoarseLID(const LO /* i */, const LO /* j */, const LO /* k */, LO& /* myLID */) const {
428}
429
430} // namespace MueLu
431
432#endif /* MUELU_LOCALLEXICOGRAPHICINDEXMANAGER_DEF_HPP_ */
Container class for mesh layout and indices calculation.
const bool coupled_
Flag for coupled vs uncoupled aggregation mode, if true aggregation is coupled.
Array< GO > startIndices
lowest global tuple (i,j,k) of a node on the local process
Array< int > coarseRate
coarsening rate in each direction
const int numDimensions
Number of spacial dimensions in the problem.
void getGhostedNodesData(const RCP< const Map > fineMap, Array< LO > &ghostedNodeCoarseLIDs, Array< int > &ghostedNodeCoarsePIDs, Array< GO > &ghostedNodeCoarseGIDs) const
const int numRanks
Number of ranks used to decompose the problem.
int myRankIndex
local process index for record in meshData after sorting.
void getGIDLocalLexicographic(const LO iGhosted, const LO jGhosted, const LO kGhosted, const Array< LO > coarseNodeFineIndices, GO &myGID, LO &myPID, LO &myLID) const
std::vector< std::vector< GO > > meshData
layout of indices accross all processes.
std::vector< std::vector< GO > > coarseMeshData
layout of indices accross all processes after coarsening.
Array< int > rankIndices
mapping between rank ID and reordered rank ID.
void getCoarseNodesData(const RCP< const Map > fineCoordinatesMap, Array< GO > &coarseNodeCoarseGIDs, Array< GO > &coarseNodeFineGIDs) const
Namespace for MueLu classes and methods.