MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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>
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 
31 namespace MueLu {
32 
33 template <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 
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 
102 template <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 
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(),
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(),
204  geoData->getNumLocalCoarseNodes(),
205  graph.GetDomainMap()->getIndexBase(),
206  graph.GetDomainMap()->getComm());
207  coarseCoordinatesFineMap = MapFactory::Build(graph.GetDomainMap()->lib(),
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 
234 template <class LocalOrdinal, class GlobalOrdinal, class Node>
237  const LO dofsPerNode, const int /* numInterpolationPoints */,
238  ArrayRCP<size_t>& nnzOnRow, Array<size_t>& rowPtr,
239  Array<LO>& colIndex) const {
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 
293 template <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 {
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 
389 template <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 
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()->getDeviceLocalView(Xpetra::Access::ReadWrite);
409  LOVectorView procWinner = aggregates.GetProcWinner()->getDeviceLocalView(Xpetra::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 
429 template <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 
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(),
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 
522 template <class LocalOrdinal, class GlobalOrdinal, class Node>
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 
535 template <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 
567 template <class LocalOrdinal, class GlobalOrdinal, class Node>
571  const LO NumGhostedNodes,
572  const LO dofsPerNode,
573  constIntTupleView coarseRate,
574  constIntTupleView endRate,
575  constLOTupleView lFineNodesPerDir,
576  non_const_row_map_type rowPtr,
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 
588 template <class LocalOrdinal, class GlobalOrdinal, class Node>
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 
625 template <class LocalOrdinal, class GlobalOrdinal, class Node>
628  const LO dofsPerNode,
629  const int numInterpolationPoints,
630  const LO numLocalRows,
631  constIntTupleView coarseRate,
632  constLOTupleView lFineNodesPerDir,
633  non_const_row_map_type rowPtr)
634  : geoData_(*geoData)
635  , dofsPerNode_(dofsPerNode)
636  , numInterpolationPoints_(numInterpolationPoints)
637  , numLocalRows_(numLocalRows)
638  , coarseRate_(coarseRate)
639  , lFineNodesPerDir_(lFineNodesPerDir)
640  , rowPtr_(rowPtr) {}
641 
642 template <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 
668 template <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,
679  non_const_row_map_type rowPtr,
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 
694 template <class LocalOrdinal, class GlobalOrdinal, class Node>
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_ */
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
GO getStartIndex(int const dim) const
LO getLocalCoarseNodesInDir(const int dim) const
virtual void getFineNodeGhostedTuple(const LO myLID, LO &i, LO &j, LO &k) const =0
bool getMeshEdge(const int dir) const
Lightweight MueLu representation of a compressed row storage graph.
const RCP< LOVector > & GetProcWinner() const
Returns constant vector that maps local node IDs to owning processor IDs.
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
Container class for aggregation information.
RCP< IndexManager > & GetIndexManager()
Get the index manager used by various aggregation algorithms. This has to be done by the aggregation ...
LO getGhostedNodesInDir(const int dim) const
fillAggregatesFunctor(RCP< IndexManager_kokkos > geoData, const int myRank, Kokkos::View< unsigned *, device_type > aggStat, LOVectorView vertex2AggID, LOVectorView procWinner)
basic_FancyOStream & setShowProcRank(const bool showProcRank)
GlobalOrdinal GO
KOKKOS_INLINE_FUNCTION intTupleView getCoarseningEndRates() const
KOKKOS_INLINE_FUNCTION intTupleView getCoarseningRates() const
decltype(std::declval< LOVector >().getDeviceLocalView(Xpetra::Access::ReadWrite)) LOVectorView
GO getStartGhostedCoarseNode(int const dim) const
int getCoarseningRate(const int dim) const
typename Kokkos::View< const LO[3], device_type > constLOTupleView
LocalOrdinal LO
virtual void getGhostedNodesData(const RCP< const Map > fineMap, Array< LO > &ghostedNodeCoarseLIDs, Array< int > &ghostedNodeCoarsePIDs, Array< GO > &ghostedNodeCoarseGIDs) const =0
computeGraphRowPtrFunctor(RCP< IndexManager_kokkos > geoData, const LO dofsPerNode, const int numInterpolationPoints, const LO numLocalRows, constIntTupleView coarseRate, constLOTupleView lFineNodesPerDir, non_const_row_map_type rowPtr)
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)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
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.
virtual void getCoarseNodeGhostedLID(const LO i, const LO j, const LO k, LO &myLID) const =0
virtual void getCoarseNodesData(const RCP< const Map > fineCoordinatesMap, Array< GO > &coarseNodeCoarseGIDs, Array< GO > &coarseNodeFineGIDs) const =0
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.
typename local_graph_type::row_map_type::non_const_type non_const_row_map_type
basic_FancyOStream & setShowAllFrontMatter(const bool showAllFrontMatter)
const RCP< LOMultiVector > & GetVertex2AggId() const
Returns constant vector that maps local node IDs to local aggregates IDs.
KOKKOS_INLINE_FUNCTION void operator()(const LO rowIdx, GO &update, const bool final) const
typename LWGraph_kokkos::local_graph_type local_graph_type
LO getLocalFineNodesInDir(const int dim) const
KOKKOS_INLINE_FUNCTION void operator()(const LO nodeIdx, LO &lNumAggregatedNodes) const
void BuildAggregatesNonKokkos(const Teuchos::ParameterList &params, const LWGraph &graph, Aggregates &aggregates, typename AggregationAlgorithmBase< LocalOrdinal, GlobalOrdinal, Node >::AggStatHostType &aggStat, LO &numNonAggregatedNodes) const
Local aggregation.
LO getOffset(int const dim) const
Timer to be used in non-factories.
size_type size() const
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)
int getCoarseningEndRate(const int dim) const
const RCP< const Map > GetDomainMap() const
Lightweight MueLu representation of a compressed row storage graph.
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
KOKKOS_INLINE_FUNCTION LOTupleView getCoarseNodesPerDir() const
KOKKOS_INLINE_FUNCTION LOTupleView getLocalFineNodesPerDir() const
void BuildGraph(const LWGraph_kokkos &graph, RCP< IndexManager_kokkos > &geoData, const LO dofsPerNode, RCP< CrsGraph > &myGraph) const
Build a CrsGraph instead of aggregates.
const RCP< const Teuchos::Comm< int > > GetComm() const
typename Kokkos::View< const int[3], device_type > constIntTupleView
Kokkos::View< unsigned *, typename LWGraphType::device_type > AggStatType
RCP< IndexManager_kokkos > & GetIndexManagerKokkos()
Get the index manager used by structured aggregation algorithms. This has to be done by the aggregati...