MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_AggregationStructuredAlgorithm_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_AGGREGATIONSTRUCTUREDALGORITHM_DEF_HPP_
11#define MUELU_AGGREGATIONSTRUCTUREDALGORITHM_DEF_HPP_
12
13#include <Teuchos_Comm.hpp>
14#include <Teuchos_CommHelpers.hpp>
15
16#include <Xpetra_MapFactory.hpp>
17#include <Xpetra_Map.hpp>
18#include <Xpetra_CrsGraphFactory.hpp>
19#include <Xpetra_CrsGraph.hpp>
20
22
23#include "MueLu_LWGraph.hpp"
24#include "MueLu_LWGraph_kokkos.hpp"
25#include "MueLu_Aggregates.hpp"
26#include "MueLu_IndexManager.hpp"
27#include "MueLu_Exceptions.hpp"
28#include "MueLu_Monitor.hpp"
29#include "MueLu_IndexManager_kokkos.hpp"
30
31namespace MueLu {
32
33template <class LocalOrdinal, class GlobalOrdinal, class Node>
35 BuildAggregatesNonKokkos(const Teuchos::ParameterList& /* params */, const LWGraph& graph,
36 Aggregates& aggregates,
38 LO& numNonAggregatedNodes) const {
39 Monitor m(*this, "BuildAggregates");
40
41 RCP<Teuchos::FancyOStream> out;
42 if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
43 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
44 out->setShowAllFrontMatter(false).setShowProcRank(true);
45 } else {
46 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
47 }
48
49 RCP<IndexManager> geoData = aggregates.GetIndexManager();
50 const bool coupled = geoData->isAggregationCoupled();
51 const bool singleCoarsePoint = geoData->isSingleCoarsePoint();
52 ArrayRCP<LO> vertex2AggId = aggregates.GetVertex2AggId()->getDataNonConst(0);
53 ArrayRCP<LO> procWinner = aggregates.GetProcWinner()->getDataNonConst(0);
54 Array<LO> ghostedCoarseNodeCoarseLIDs;
55 Array<int> ghostedCoarseNodeCoarsePIDs;
56 Array<GO> ghostedCoarseNodeCoarseGIDs;
57
58 *out << "Extract data for ghosted nodes" << std::endl;
59 geoData->getGhostedNodesData(graph.GetDomainMap(), ghostedCoarseNodeCoarseLIDs,
60 ghostedCoarseNodeCoarsePIDs, ghostedCoarseNodeCoarseGIDs);
61
62 LO rem, rate;
63 Array<LO> ghostedIdx(3), coarseIdx(3);
64 LO ghostedCoarseNodeCoarseLID, aggId;
65 *out << "Loop over fine nodes and assign them to an aggregate and a rank" << std::endl;
66 for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
67 // Compute coarse ID associated with fine LID
68 geoData->getFineNodeGhostedTuple(nodeIdx, ghostedIdx[0], ghostedIdx[1], ghostedIdx[2]);
69
70 for (int dim = 0; dim < 3; ++dim) {
71 if (singleCoarsePoint && (geoData->getLocalFineNodesInDir(dim) - 1 < geoData->getCoarseningRate(dim))) {
72 coarseIdx[dim] = 0;
73 } else {
74 coarseIdx[dim] = ghostedIdx[dim] / geoData->getCoarseningRate(dim);
75 rem = ghostedIdx[dim] % geoData->getCoarseningRate(dim);
76 if (ghostedIdx[dim] - geoData->getOffset(dim) < geoData->getLocalFineNodesInDir(dim) - geoData->getCoarseningEndRate(dim)) {
77 rate = geoData->getCoarseningRate(dim);
78 } else {
79 rate = geoData->getCoarseningEndRate(dim);
80 }
81 if (rem > (rate / 2)) {
82 ++coarseIdx[dim];
83 }
84 if (coupled && (geoData->getStartGhostedCoarseNode(dim) * geoData->getCoarseningRate(dim) > geoData->getStartIndex(dim))) {
85 --coarseIdx[dim];
86 }
87 }
88 }
89
90 geoData->getCoarseNodeGhostedLID(coarseIdx[0], coarseIdx[1], coarseIdx[2],
91 ghostedCoarseNodeCoarseLID);
92
93 aggId = ghostedCoarseNodeCoarseLIDs[ghostedCoarseNodeCoarseLID];
94 vertex2AggId[nodeIdx] = aggId;
95 procWinner[nodeIdx] = ghostedCoarseNodeCoarsePIDs[ghostedCoarseNodeCoarseLID];
96 aggStat[nodeIdx] = AGGREGATED;
97 --numNonAggregatedNodes;
98
99 } // Loop over fine points
100} // BuildAggregates()
101
102template <class LocalOrdinal, class GlobalOrdinal, class Node>
104 BuildGraphOnHost(const LWGraph& graph, RCP<IndexManager>& geoData, const LO dofsPerNode,
105 RCP<CrsGraph>& myGraph, RCP<const Map>& coarseCoordinatesFineMap,
106 RCP<const Map>& coarseCoordinatesMap) const {
107 Monitor m(*this, "BuildGraphP");
108
109 RCP<Teuchos::FancyOStream> out;
110 if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
111 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
112 out->setShowAllFrontMatter(false).setShowProcRank(true);
113 } else {
114 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
115 }
116
117 const bool coupled = geoData->isAggregationCoupled();
118
119 // Compute the number of coarse points needed to interpolate quantities to a fine point
120 int numInterpolationPoints = 0;
121 if (geoData->getInterpolationOrder() == 0) {
122 numInterpolationPoints = 1;
123 } else if (geoData->getInterpolationOrder() == 1) {
124 // Compute 2^numDimensions using bit logic to avoid round-off errors
125 numInterpolationPoints = 1 << geoData->getNumDimensions();
126 }
127 *out << "numInterpolationPoints=" << numInterpolationPoints << std::endl;
128
129 Array<LO> colIndex((geoData->getNumLocalCoarseNodes() + numInterpolationPoints *
130 (geoData->getNumLocalFineNodes() - geoData->getNumLocalCoarseNodes())) *
131 dofsPerNode);
132 Array<size_t> rowPtr(geoData->getNumLocalFineNodes() * dofsPerNode + 1);
133 rowPtr[0] = 0;
134 ArrayRCP<size_t> nnzOnRow(geoData->getNumLocalFineNodes() * dofsPerNode);
135
136 *out << "Compute prolongatorGraph data" << std::endl;
137 if (geoData->getInterpolationOrder() == 0) {
138 ComputeGraphDataConstant(graph, geoData, dofsPerNode, numInterpolationPoints,
139 nnzOnRow, rowPtr, colIndex);
140 } else if (geoData->getInterpolationOrder() == 1) {
141 ComputeGraphDataLinear(graph, geoData, dofsPerNode, numInterpolationPoints,
142 nnzOnRow, rowPtr, colIndex);
143 }
144
145 // Compute graph's rowMap, colMap and domainMap
146 RCP<Map> rowMap = MapFactory::Build(graph.GetDomainMap(), dofsPerNode);
147 RCP<Map> colMap, domainMap;
148 *out << "Compute domain and column maps of the CrsGraph" << std::endl;
149 if (coupled) {
150 *out << "Extract data for ghosted nodes" << std::endl;
151 Array<LO> ghostedCoarseNodeCoarseLIDs;
152 Array<int> ghostedCoarseNodeCoarsePIDs;
153 Array<GO> ghostedCoarseNodeCoarseGIDs;
154 geoData->getGhostedNodesData(graph.GetDomainMap(), ghostedCoarseNodeCoarseLIDs,
155 ghostedCoarseNodeCoarsePIDs, ghostedCoarseNodeCoarseGIDs);
156
157 // In this case we specify the global number of nodes on the coarse mesh
158 // as well as the GIDs needed on rank.
159 colMap = MapFactory::Build(graph.GetDomainMap()->lib(),
160 geoData->getNumGlobalCoarseNodes(),
161 ghostedCoarseNodeCoarseGIDs(),
162 graph.GetDomainMap()->getIndexBase(),
163 graph.GetDomainMap()->getComm());
164
165 LO coarseNodeIdx = 0;
166 Array<GO> coarseNodeCoarseGIDs, coarseNodeFineGIDs;
167 geoData->getCoarseNodesData(graph.GetDomainMap(), coarseNodeCoarseGIDs, coarseNodeFineGIDs);
168 for (LO nodeIdx = 0; nodeIdx < ghostedCoarseNodeCoarseGIDs.size(); ++nodeIdx) {
169 if (ghostedCoarseNodeCoarsePIDs[nodeIdx] == colMap->getComm()->getRank()) {
170 coarseNodeCoarseGIDs[coarseNodeIdx] = ghostedCoarseNodeCoarseGIDs[nodeIdx];
171 ++coarseNodeIdx;
172 }
173 }
174 domainMap = MapFactory::Build(graph.GetDomainMap()->lib(),
175 geoData->getNumGlobalCoarseNodes(),
176 coarseNodeCoarseGIDs(),
177 graph.GetDomainMap()->getIndexBase(),
178 graph.GetDomainMap()->getComm());
179 coarseCoordinatesMap = MapFactory::Build(graph.GetDomainMap()->lib(),
180 geoData->getNumGlobalCoarseNodes(),
181 coarseNodeCoarseGIDs(),
182 graph.GetDomainMap()->getIndexBase(),
183 graph.GetDomainMap()->getComm());
184 coarseCoordinatesFineMap = MapFactory::Build(graph.GetDomainMap()->lib(),
185 geoData->getNumGlobalCoarseNodes(),
186 coarseNodeFineGIDs(),
187 graph.GetDomainMap()->getIndexBase(),
188 graph.GetDomainMap()->getComm());
189 } else {
190 // In this case the map will compute the global number of nodes on the coarse mesh
191 // and it will assign GIDs to the local coarse nodes.
192 colMap = MapFactory::Build(graph.GetDomainMap()->lib(),
193 Teuchos::OrdinalTraits<GO>::invalid(),
194 geoData->getNumLocalCoarseNodes() * dofsPerNode,
195 graph.GetDomainMap()->getIndexBase(),
196 graph.GetDomainMap()->getComm());
197 domainMap = colMap;
198
199 Array<GO> coarseNodeCoarseGIDs(geoData->getNumLocalCoarseNodes());
200 Array<GO> coarseNodeFineGIDs(geoData->getNumLocalCoarseNodes());
201 geoData->getCoarseNodesData(graph.GetDomainMap(), coarseNodeCoarseGIDs, coarseNodeFineGIDs);
202 coarseCoordinatesMap = MapFactory::Build(graph.GetDomainMap()->lib(),
203 Teuchos::OrdinalTraits<GO>::invalid(),
204 geoData->getNumLocalCoarseNodes(),
205 graph.GetDomainMap()->getIndexBase(),
206 graph.GetDomainMap()->getComm());
207 coarseCoordinatesFineMap = MapFactory::Build(graph.GetDomainMap()->lib(),
208 Teuchos::OrdinalTraits<GO>::invalid(),
209 coarseNodeFineGIDs(),
210 graph.GetDomainMap()->getIndexBase(),
211 graph.GetDomainMap()->getComm());
212 }
213
214 *out << "Call constructor of CrsGraph" << std::endl;
215 myGraph = CrsGraphFactory::Build(rowMap,
216 colMap,
217 nnzOnRow);
218
219 *out << "Fill CrsGraph" << std::endl;
220 LO rowIdx = 0;
221 for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
222 for (LO dof = 0; dof < dofsPerNode; ++dof) {
223 rowIdx = nodeIdx * dofsPerNode + dof;
224 myGraph->insertLocalIndices(rowIdx, colIndex(rowPtr[rowIdx], nnzOnRow[rowIdx]));
225 }
226 }
227
228 *out << "Call fillComplete on CrsGraph" << std::endl;
229 myGraph->fillComplete(domainMap, rowMap);
230 *out << "Prolongator CrsGraph computed" << std::endl;
231
232} // BuildGraph()
233
234template <class LocalOrdinal, class GlobalOrdinal, class Node>
236 ComputeGraphDataConstant(const LWGraph& graph, RCP<IndexManager>& geoData,
237 const LO dofsPerNode, const int /* numInterpolationPoints */,
238 ArrayRCP<size_t>& nnzOnRow, Array<size_t>& rowPtr,
239 Array<LO>& colIndex) const {
240 RCP<Teuchos::FancyOStream> out;
241 if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
242 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
243 out->setShowAllFrontMatter(false).setShowProcRank(true);
244 } else {
245 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
246 }
247
248 Array<LO> ghostedCoarseNodeCoarseLIDs;
249 Array<int> ghostedCoarseNodeCoarsePIDs;
250 Array<GO> ghostedCoarseNodeCoarseGIDs;
251 geoData->getGhostedNodesData(graph.GetDomainMap(), ghostedCoarseNodeCoarseLIDs,
252 ghostedCoarseNodeCoarsePIDs, ghostedCoarseNodeCoarseGIDs);
253
254 LO ghostedCoarseNodeCoarseLID, rem, rate;
255 Array<LO> ghostedIdx(3), coarseIdx(3);
256 for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
257 // Compute coarse ID associated with fine LID
258 geoData->getFineNodeGhostedTuple(nodeIdx, ghostedIdx[0], ghostedIdx[1], ghostedIdx[2]);
259
260 for (int dim = 0; dim < 3; ++dim) {
261 if (geoData->isSingleCoarsePoint() && (geoData->getLocalFineNodesInDir(dim) - 1 < geoData->getCoarseningRate(dim))) {
262 coarseIdx[dim] = 0;
263 } else {
264 coarseIdx[dim] = ghostedIdx[dim] / geoData->getCoarseningRate(dim);
265 rem = ghostedIdx[dim] % geoData->getCoarseningRate(dim);
266 if (ghostedIdx[dim] - geoData->getOffset(dim) < geoData->getLocalFineNodesInDir(dim) - geoData->getCoarseningEndRate(dim)) {
267 rate = geoData->getCoarseningRate(dim);
268 } else {
269 rate = geoData->getCoarseningEndRate(dim);
270 }
271 if (rem > (rate / 2)) {
272 ++coarseIdx[dim];
273 }
274 if ((geoData->getStartGhostedCoarseNode(dim) * geoData->getCoarseningRate(dim) > geoData->getStartIndex(dim)) && geoData->isAggregationCoupled()) {
275 --coarseIdx[dim];
276 }
277 }
278 }
279
280 geoData->getCoarseNodeGhostedLID(coarseIdx[0], coarseIdx[1], coarseIdx[2],
281 ghostedCoarseNodeCoarseLID);
282
283 for (LO dof = 0; dof < dofsPerNode; ++dof) {
284 nnzOnRow[nodeIdx * dofsPerNode + dof] = 1;
285 rowPtr[nodeIdx * dofsPerNode + dof + 1] = rowPtr[nodeIdx * dofsPerNode + dof] + 1;
286 colIndex[rowPtr[nodeIdx * dofsPerNode + dof]] =
287 ghostedCoarseNodeCoarseLIDs[ghostedCoarseNodeCoarseLID] * dofsPerNode + dof;
288 }
289 } // Loop over fine points
290
291} // ComputeGraphDataConstant()
292
293template <class LocalOrdinal, class GlobalOrdinal, class Node>
295 ComputeGraphDataLinear(const LWGraph& /* graph */, RCP<IndexManager>& geoData,
296 const LO dofsPerNode, const int numInterpolationPoints,
297 ArrayRCP<size_t>& nnzOnRow, Array<size_t>& rowPtr,
298 Array<LO>& colIndex) const {
299 RCP<Teuchos::FancyOStream> out;
300 if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
301 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
302 out->setShowAllFrontMatter(false).setShowProcRank(true);
303 } else {
304 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
305 }
306
307 const bool coupled = geoData->isAggregationCoupled();
308 const int numDimensions = geoData->getNumDimensions();
309 Array<LO> ghostedIdx(3, 0);
310 Array<LO> coarseIdx(3, 0);
311 Array<LO> ijkRem(3, 0);
312 const LO coarsePointOffset[8][3] = {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}};
313
314 for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
315 // Compute coarse ID associated with fine LID
316 geoData->getFineNodeGhostedTuple(nodeIdx, ghostedIdx[0], ghostedIdx[1], ghostedIdx[2]);
317 for (int dim = 0; dim < numDimensions; dim++) {
318 coarseIdx[dim] = ghostedIdx[dim] / geoData->getCoarseningRate(dim);
319 ijkRem[dim] = ghostedIdx[dim] % geoData->getCoarseningRate(dim);
320 if (coupled) {
321 if (geoData->getStartGhostedCoarseNode(dim) * geoData->getCoarseningRate(dim) > geoData->getStartIndex(dim)) {
322 --coarseIdx[dim];
323 }
324 } else {
325 if (ghostedIdx[dim] == geoData->getLocalFineNodesInDir(dim) - 1) {
326 coarseIdx[dim] = geoData->getLocalCoarseNodesInDir(dim) - 1;
327 }
328 }
329 }
330
331 // Fill Graph
332 // Check if Fine node lies on Coarse Node
333 bool allCoarse = true;
334 Array<bool> isCoarse(numDimensions);
335 for (int dim = 0; dim < numDimensions; ++dim) {
336 isCoarse[dim] = false;
337 if (ijkRem[dim] == 0)
338 isCoarse[dim] = true;
339
340 if (coupled) {
341 if (ghostedIdx[dim] - geoData->getOffset(dim) == geoData->getLocalFineNodesInDir(dim) - 1 &&
342 geoData->getMeshEdge(dim * 2 + 1))
343 isCoarse[dim] = true;
344 } else {
345 if (ghostedIdx[dim] - geoData->getOffset(dim) == geoData->getLocalFineNodesInDir(dim) - 1)
346 isCoarse[dim] = true;
347 }
348
349 if (!isCoarse[dim])
350 allCoarse = false;
351 }
352
353 LO rowIdx = 0, colIdx = 0;
354 if (allCoarse) {
355 for (LO dof = 0; dof < dofsPerNode; ++dof) {
356 rowIdx = nodeIdx * dofsPerNode + dof;
357 nnzOnRow[rowIdx] = 1;
358 rowPtr[rowIdx + 1] = rowPtr[rowIdx] + 1;
359
360 // Fine node lies on Coarse node, easy case, we only need the LID of the coarse node.
361 geoData->getCoarseNodeGhostedLID(coarseIdx[0], coarseIdx[1], coarseIdx[2], colIdx);
362 colIndex[rowPtr[rowIdx]] = colIdx * dofsPerNode + dof;
363 }
364 } else {
365 // Harder case, we need the LIDs of all the coarse nodes contributing to the interpolation
366 for (int dim = 0; dim < numDimensions; ++dim) {
367 if (coarseIdx[dim] == geoData->getGhostedNodesInDir(dim) - 1)
368 --coarseIdx[dim];
369 }
370
371 for (LO dof = 0; dof < dofsPerNode; ++dof) {
372 // at the current node.
373 rowIdx = nodeIdx * dofsPerNode + dof;
374 nnzOnRow[rowIdx] = Teuchos::as<size_t>(numInterpolationPoints);
375 rowPtr[rowIdx + 1] = rowPtr[rowIdx] + Teuchos::as<LO>(numInterpolationPoints);
376 // Compute Coarse Node LID
377 for (LO interpIdx = 0; interpIdx < numInterpolationPoints; ++interpIdx) {
378 geoData->getCoarseNodeGhostedLID(coarseIdx[0] + coarsePointOffset[interpIdx][0],
379 coarseIdx[1] + coarsePointOffset[interpIdx][1],
380 coarseIdx[2] + coarsePointOffset[interpIdx][2],
381 colIdx);
382 colIndex[rowPtr[rowIdx] + interpIdx] = colIdx * dofsPerNode + dof;
383 } // Loop over numInterpolationPoints
384 } // Loop over dofsPerNode
385 }
386 } // Loop over fine points
387} // ComputeGraphDataLinear()
388
389template <class LocalOrdinal, class GlobalOrdinal, class Node>
391 BuildAggregates(const Teuchos::ParameterList& /* params */, const LWGraph_kokkos& graph,
392 Aggregates& aggregates,
394 LO& numNonAggregatedNodes) const {
395 Monitor m(*this, "BuildAggregates");
396
397 RCP<Teuchos::FancyOStream> out;
398 if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
399 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
400 out->setShowAllFrontMatter(false).setShowProcRank(true);
401 } else {
402 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
403 }
404
405 RCP<IndexManager_kokkos> geoData = aggregates.GetIndexManagerKokkos();
406 const LO numLocalFineNodes = geoData->getNumLocalFineNodes();
407 const LO numCoarseNodes = geoData->getNumCoarseNodes();
408 LOVectorView vertex2AggId = aggregates.GetVertex2AggId()->getLocalViewDevice(Tpetra::Access::ReadWrite);
409 LOVectorView procWinner = aggregates.GetProcWinner()->getLocalViewDevice(Tpetra::Access::ReadWrite);
410
411 *out << "Loop over fine nodes and assign them to an aggregate and a rank" << std::endl;
412 LO numAggregatedNodes;
413 fillAggregatesFunctor fillAggregates(geoData,
414 graph.GetComm()->getRank(),
415 aggStat,
416 vertex2AggId,
417 procWinner);
418 Kokkos::parallel_reduce("StructuredAggregation: fill aggregates data",
419 Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes),
420 fillAggregates,
421 numAggregatedNodes);
422
423 *out << "numCoarseNodes= " << numCoarseNodes
424 << ", numAggregatedNodes= " << numAggregatedNodes << std::endl;
425 numNonAggregatedNodes = numNonAggregatedNodes - numAggregatedNodes;
426
427} // BuildAggregates()
428
429template <class LocalOrdinal, class GlobalOrdinal, class Node>
431 BuildGraph(const LWGraph_kokkos& graph, RCP<IndexManager_kokkos>& geoData, const LO dofsPerNode,
432 RCP<CrsGraph>& myGraph) const {
433 Monitor m(*this, "BuildGraphP");
434
435 RCP<Teuchos::FancyOStream> out;
436 if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
437 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
438 out->setShowAllFrontMatter(false).setShowProcRank(true);
439 } else {
440 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
441 }
442
443 // Compute the number of coarse points needed to interpolate quantities to a fine point
444 int numInterpolationPoints = 0;
445 if (geoData->getInterpolationOrder() == 0) {
446 numInterpolationPoints = 1;
447 } else if (geoData->getInterpolationOrder() == 1) {
448 // Compute 2^numDimensions using bit logic to avoid round-off errors from std::pow()
449 numInterpolationPoints = 1 << geoData->getNumDimensions();
450 }
451 *out << "numInterpolationPoints=" << numInterpolationPoints << std::endl;
452
453 const LO numLocalFineNodes = geoData->getNumLocalFineNodes();
454 const LO numCoarseNodes = geoData->getNumCoarseNodes();
455 const LO numNnzEntries = dofsPerNode * (numCoarseNodes + numInterpolationPoints * (numLocalFineNodes - numCoarseNodes));
456
457 non_const_row_map_type rowPtr("Prolongator graph, rowPtr", dofsPerNode * (numLocalFineNodes + 1));
458 entries_type colIndex("Prolongator graph, colIndices", numNnzEntries);
459
460 *out << "Compute prolongatorGraph data" << std::endl;
461 if (geoData->getInterpolationOrder() == 0) {
462 computeGraphDataConstantFunctor computeGraphData(geoData,
463 numCoarseNodes,
464 dofsPerNode,
465 geoData->getCoarseningRates(),
466 geoData->getCoarseningEndRates(),
467 geoData->getLocalFineNodesPerDir(),
468 rowPtr,
469 colIndex);
470 Kokkos::parallel_for("Structured Aggregation: compute loca graph data",
471 Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes),
472 computeGraphData);
473 } else if (geoData->getInterpolationOrder() == 1) {
474 // Note, lbv 2018-11-08: in the piece-wise linear case I am computing the rowPtr
475 // using a parallel scan, it might be possible to do something faster than that
476 // by including this calculation in computeGraphDataLinearFunctor but at the moment
477 // all the ideas I have include a bunch of if statements which I would like to avoid.
478 computeGraphRowPtrFunctor computeGraphRowPtr(geoData,
479 dofsPerNode,
480 numInterpolationPoints,
481 numLocalFineNodes,
482 geoData->getCoarseningRates(),
483 geoData->getLocalFineNodesPerDir(),
484 rowPtr);
485 Kokkos::parallel_scan("Structured Aggregation: compute rowPtr for prolongator graph",
486 Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes + 1),
487 computeGraphRowPtr);
488
489 computeGraphDataLinearFunctor computeGraphData(geoData,
490 geoData->getNumDimensions(),
491 numCoarseNodes,
492 dofsPerNode,
493 numInterpolationPoints,
494 geoData->getCoarseningRates(),
495 geoData->getCoarseningEndRates(),
496 geoData->getLocalFineNodesPerDir(),
497 geoData->getCoarseNodesPerDir(),
498 rowPtr,
499 colIndex);
500 Kokkos::parallel_for("Structured Aggregation: compute loca graph data",
501 Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes),
502 computeGraphData);
503 }
504
505 local_graph_type myLocalGraph(colIndex, rowPtr);
506
507 // Compute graph's colMap and domainMap
508 RCP<Map> colMap, domainMap;
509 *out << "Compute domain and column maps of the CrsGraph" << std::endl;
510 colMap = MapFactory::Build(graph.GetDomainMap()->lib(),
511 Teuchos::OrdinalTraits<GO>::invalid(),
512 numCoarseNodes,
513 graph.GetDomainMap()->getIndexBase(),
514 graph.GetDomainMap()->getComm());
515 domainMap = colMap;
516
517 myGraph = CrsGraphFactory::Build(myLocalGraph, graph.GetDomainMap(), colMap,
518 colMap, graph.GetDomainMap());
519
520} // BuildGraph()
521
522template <class LocalOrdinal, class GlobalOrdinal, class Node>
524 fillAggregatesFunctor::fillAggregatesFunctor(RCP<IndexManager_kokkos> geoData,
525 const int myRank,
526 Kokkos::View<unsigned*, device_type> aggStat,
527 LOVectorView vertex2AggID,
528 LOVectorView procWinner)
529 : geoData_(*geoData)
530 , myRank_(myRank)
531 , aggStat_(aggStat)
532 , vertex2AggID_(vertex2AggID)
533 , procWinner_(procWinner) {}
534
535template <class LocalOrdinal, class GlobalOrdinal, class Node>
537 fillAggregatesFunctor::operator()(const LO nodeIdx, LO& lNumAggregatedNodes) const {
538 // Compute coarse ID associated with fine LID
539 LO rem, rate;
540 LO coarseNodeCoarseLID;
541 LO nodeFineTuple[3], coarseIdx[3];
542 auto coarseRate = geoData_.getCoarseningRates();
543 auto endRate = geoData_.getCoarseningEndRates();
544 auto lFineNodesPerDir = geoData_.getLocalFineNodesPerDir();
545 // Compute coarse ID associated with fine LID
546 geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
547
548 for (int dim = 0; dim < 3; ++dim) {
549 coarseIdx[dim] = nodeFineTuple[dim] / coarseRate(dim);
550 rem = nodeFineTuple[dim] % coarseRate(dim);
551 rate = (nodeFineTuple[dim] < lFineNodesPerDir(dim) - endRate(dim)) ? coarseRate(dim) : endRate(dim);
552 if (rem > (rate / 2)) {
553 ++coarseIdx[dim];
554 }
555 }
556
557 geoData_.getCoarseTuple2CoarseLID(coarseIdx[0], coarseIdx[1], coarseIdx[2],
558 coarseNodeCoarseLID);
559
560 vertex2AggID_(nodeIdx, 0) = coarseNodeCoarseLID;
561 procWinner_(nodeIdx, 0) = myRank_;
562 aggStat_(nodeIdx) = AGGREGATED;
563 ++lNumAggregatedNodes;
564
565} // fillAggregatesFunctor::operator()
566
567template <class LocalOrdinal, class GlobalOrdinal, class Node>
570 computeGraphDataConstantFunctor(RCP<IndexManager_kokkos> geoData,
571 const LO NumGhostedNodes,
572 const LO dofsPerNode,
573 constIntTupleView coarseRate,
574 constIntTupleView endRate,
575 constLOTupleView lFineNodesPerDir,
577 entries_type colIndex)
578 : geoData_(*geoData)
579 , numGhostedNodes_(NumGhostedNodes)
580 , dofsPerNode_(dofsPerNode)
581 , coarseRate_(coarseRate)
582 , endRate_(endRate)
583 , lFineNodesPerDir_(lFineNodesPerDir)
584 , rowPtr_(rowPtr)
585 , colIndex_(colIndex) {
586} // computeGraphDataConstantFunctor()
587
588template <class LocalOrdinal, class GlobalOrdinal, class Node>
590 computeGraphDataConstantFunctor::operator()(const LO nodeIdx) const {
591 LO nodeFineTuple[3] = {0, 0, 0};
592 LO nodeCoarseTuple[3] = {0, 0, 0};
593
594 // Compute ghosted tuple associated with fine LID
595 geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
596
597 // Compute coarse tuple associated with fine point
598 // then overwrite it with tuple associated with aggregate
599 LO rem, rate, coarseNodeCoarseLID;
600 for (int dim = 0; dim < 3; ++dim) {
601 nodeCoarseTuple[dim] = nodeFineTuple[dim] / coarseRate_(dim);
602 rem = nodeFineTuple[dim] % coarseRate_(dim);
603 if (nodeFineTuple[dim] < (lFineNodesPerDir_(dim) - endRate_(dim))) {
604 rate = coarseRate_(dim);
605 } else {
606 rate = endRate_(dim);
607 }
608 if (rem > (rate / 2)) {
609 ++nodeCoarseTuple[dim];
610 }
611 }
612
613 // get LID associted with aggregate
614 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2],
615 coarseNodeCoarseLID);
616
617 // store data into CrsGraph taking care of multiple dofs case
618 for (LO dof = 0; dof < dofsPerNode_; ++dof) {
619 rowPtr_(nodeIdx * dofsPerNode_ + dof + 1) = nodeIdx * dofsPerNode_ + dof + 1;
620 colIndex_(nodeIdx * dofsPerNode_ + dof) = coarseNodeCoarseLID * dofsPerNode_ + dof;
621 }
622
623} // computeGraphDataConstantFunctor::operator()
624
625template <class LocalOrdinal, class GlobalOrdinal, class Node>
627 computeGraphRowPtrFunctor::computeGraphRowPtrFunctor(RCP<IndexManager_kokkos> geoData,
628 const LO dofsPerNode,
629 const int numInterpolationPoints,
630 const LO numLocalRows,
631 constIntTupleView coarseRate,
632 constLOTupleView lFineNodesPerDir,
634 : geoData_(*geoData)
635 , dofsPerNode_(dofsPerNode)
636 , numInterpolationPoints_(numInterpolationPoints)
637 , numLocalRows_(numLocalRows)
638 , coarseRate_(coarseRate)
639 , lFineNodesPerDir_(lFineNodesPerDir)
640 , rowPtr_(rowPtr) {}
641
642template <class LocalOrdinal, class GlobalOrdinal, class Node>
644 computeGraphRowPtrFunctor::operator()(const LO rowIdx, GO& update, const bool final) const {
645 if (final) {
646 // Kokkos uses a multipass algorithm to implement scan.
647 // Only update the array on the final pass. Updating the
648 // array before changing 'update' means that we do an
649 // exclusive scan. Update the array after for an inclusive
650 // scan.
651 rowPtr_(rowIdx) = update;
652 }
653 if (rowIdx < numLocalRows_) {
654 LO nodeIdx = rowIdx / dofsPerNode_;
655 bool allCoarse = true;
656 LO nodeFineTuple[3] = {0, 0, 0};
657 geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
658 for (int dim = 0; dim < 3; ++dim) {
659 const LO rem = nodeFineTuple[dim] % coarseRate_(dim);
660
661 // Check if Fine node lies on Coarse Node
662 allCoarse = (allCoarse && ((rem == 0) || (nodeFineTuple[dim] == lFineNodesPerDir_(dim) - 1)));
663 }
664 update += (allCoarse ? 1 : numInterpolationPoints_);
665 }
666} // computeGraphRowPtrFunctor::operator()
667
668template <class LocalOrdinal, class GlobalOrdinal, class Node>
671 const int numDimensions,
672 const LO numGhostedNodes,
673 const LO dofsPerNode,
674 const int numInterpolationPoints,
675 constIntTupleView coarseRate,
676 constIntTupleView endRate,
677 constLOTupleView lFineNodesPerDir,
678 constLOTupleView ghostedNodesPerDir,
680 entries_type colIndex)
681 : geoData_(*geoData)
682 , numDimensions_(numDimensions)
683 , numGhostedNodes_(numGhostedNodes)
684 , dofsPerNode_(dofsPerNode)
685 , numInterpolationPoints_(numInterpolationPoints)
686 , coarseRate_(coarseRate)
687 , endRate_(endRate)
688 , lFineNodesPerDir_(lFineNodesPerDir)
689 , ghostedNodesPerDir_(ghostedNodesPerDir)
690 , rowPtr_(rowPtr)
691 , colIndex_(colIndex) {
692} // computeGraphDataLinearFunctor()
693
694template <class LocalOrdinal, class GlobalOrdinal, class Node>
696 computeGraphDataLinearFunctor::operator()(const LO nodeIdx) const {
697 LO nodeFineTuple[3] = {0, 0, 0};
698 LO nodeCoarseTuple[3] = {0, 0, 0};
699
700 // Compute coarse ID associated with fine LID
701 geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
702
703 LO coarseNodeCoarseLID;
704 bool allCoarse = false;
705 for (int dim = 0; dim < 3; ++dim) {
706 nodeCoarseTuple[dim] = nodeFineTuple[dim] / coarseRate_(dim);
707 }
708 if (rowPtr_(nodeIdx + 1) == rowPtr_(nodeIdx) + 1) {
709 allCoarse = true;
710 }
711
712 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2],
713 coarseNodeCoarseLID);
714
715 if (allCoarse) {
716 // Fine node lies on Coarse node, easy case, we only need the LID of the coarse node.
717 for (LO dof = 0; dof < dofsPerNode_; ++dof) {
718 colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof)) = coarseNodeCoarseLID * dofsPerNode_ + dof;
719 }
720 } else {
721 for (int dim = 0; dim < numDimensions_; ++dim) {
722 if (nodeCoarseTuple[dim] == ghostedNodesPerDir_(dim) - 1) {
723 --nodeCoarseTuple[dim];
724 }
725 }
726 // Compute Coarse Node LID
727 // Note lbv 10-06-2018: it is likely benefitial to remove the two if statments and somehow
728 // find out the number of dimensions before calling the opertor() of the functor.
729 for (LO dof = 0; dof < dofsPerNode_; ++dof) {
730 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 0));
731 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1], nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 1));
732 if (numDimensions_ > 1) {
733 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1] + 1, nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 2));
734 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1] + 1, nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 3));
735 if (numDimensions_ > 2) {
736 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 4));
737 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1], nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 5));
738 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1] + 1, nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 6));
739 geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1] + 1, nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 7));
740 }
741 }
742 }
743 }
744} // computeGraphDataLinearFunctor::operator()
745
746} // namespace MueLu
747
748#endif /* MUELU_AGGREGATIONSTRUCTUREDALGORITHM_DEF_HPP_ */
Container class for aggregation information.
RCP< IndexManager_kokkos > & GetIndexManagerKokkos()
Get the index manager used by structured aggregation algorithms. This has to be done by the aggregati...
RCP< IndexManager > & GetIndexManager()
Get the index manager used by various aggregation algorithms. This has to be done by the aggregation ...
const RCP< LOMultiVector > & GetVertex2AggId() const
Returns constant vector that maps local node IDs to local aggregates IDs.
const RCP< LOVector > & GetProcWinner() const
Returns constant vector that maps local node IDs to owning processor IDs.
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
Kokkos::View< unsigned *, typename LWGraphType::device_type > AggStatType
decltype(std::declval< LOVector >().getLocalViewDevice(Tpetra::Access::ReadWrite)) LOVectorView
void ComputeGraphDataConstant(const LWGraph &graph, RCP< IndexManager > &geoData, const LO dofsPerNode, const int numInterpolationPoints, ArrayRCP< size_t > &nnzOnRow, Array< size_t > &rowPtr, Array< LO > &colIndex) const
void BuildGraph(const LWGraph_kokkos &graph, RCP< IndexManager_kokkos > &geoData, const LO dofsPerNode, RCP< CrsGraph > &myGraph) const
Build a CrsGraph instead of aggregates.
void ComputeGraphDataLinear(const LWGraph &graph, RCP< IndexManager > &geoData, const LO dofsPerNode, const int numInterpolationPoints, ArrayRCP< size_t > &nnzOnRow, Array< size_t > &rowPtr, Array< LO > &colIndex) const
typename Kokkos::View< const int[3], device_type > constIntTupleView
typename LWGraph_kokkos::local_graph_type local_graph_type
typename Kokkos::View< const LO[3], device_type > constLOTupleView
void BuildAggregatesNonKokkos(const Teuchos::ParameterList &params, const LWGraph &graph, Aggregates &aggregates, typename AggregationAlgorithmBase< LocalOrdinal, GlobalOrdinal, Node >::AggStatHostType &aggStat, LO &numNonAggregatedNodes) const
Local aggregation.
typename local_graph_type::row_map_type::non_const_type non_const_row_map_type
void BuildAggregates(const Teuchos::ParameterList &params, const LWGraph_kokkos &graph, Aggregates &aggregates, typename AggregationAlgorithmBase< LocalOrdinal, GlobalOrdinal, Node >::AggStatType &aggStat, LO &numNonAggregatedNodes) const
Build aggregates object.
void BuildGraphOnHost(const LWGraph &graph, RCP< IndexManager > &geoData, const LO dofsPerNode, RCP< CrsGraph > &myGraph, RCP< const Map > &coarseCoordinatesFineMap, RCP< const Map > &coarseCoordinatesMap) const
Local aggregation.
const RCP< const Map > GetDomainMap() const
const RCP< const Teuchos::Comm< int > > GetComm() const
Lightweight MueLu representation of a compressed row storage graph.
Lightweight MueLu representation of a compressed row storage graph.
Timer to be used in non-factories.
Namespace for MueLu classes and methods.
computeGraphDataConstantFunctor(RCP< IndexManager_kokkos > geoData, const LO numGhostedNodes, const LO dofsPerNode, constIntTupleView coarseRate, constIntTupleView endRate, constLOTupleView lFineNodesPerDir, non_const_row_map_type rowPtr, entries_type colIndex)
computeGraphDataLinearFunctor(RCP< IndexManager_kokkos > geoData, const int numDimensions, const LO numGhostedNodes, const LO dofsPerNode, const int numInterpolationPoints, constIntTupleView coarseRate, constIntTupleView endRate, constLOTupleView lFineNodesPerDir, constLOTupleView ghostedNodesPerDir, non_const_row_map_type rowPtr, entries_type colIndex)
computeGraphRowPtrFunctor(RCP< IndexManager_kokkos > geoData, const LO dofsPerNode, const int numInterpolationPoints, const LO numLocalRows, constIntTupleView coarseRate, constLOTupleView lFineNodesPerDir, non_const_row_map_type rowPtr)
KOKKOS_INLINE_FUNCTION void operator()(const LO rowIdx, GO &update, const bool final) const
KOKKOS_INLINE_FUNCTION void operator()(const LO nodeIdx, LO &lNumAggregatedNodes) const
fillAggregatesFunctor(RCP< IndexManager_kokkos > geoData, const int myRank, Kokkos::View< unsigned *, device_type > aggStat, LOVectorView vertex2AggID, LOVectorView procWinner)