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 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_AGGREGATIONSTRUCTUREDALGORITHM_DEF_HPP_
47 #define MUELU_AGGREGATIONSTRUCTUREDALGORITHM_DEF_HPP_
48 
49 #include <Teuchos_Comm.hpp>
50 #include <Teuchos_CommHelpers.hpp>
51 
52 #include <Xpetra_MapFactory.hpp>
53 #include <Xpetra_Map.hpp>
55 #include <Xpetra_CrsGraph.hpp>
56 
58 
59 #include "MueLu_LWGraph.hpp"
60 #include "MueLu_LWGraph_kokkos.hpp"
61 #include "MueLu_Aggregates.hpp"
62 #include "MueLu_IndexManager.hpp"
63 #include "MueLu_Exceptions.hpp"
64 #include "MueLu_Monitor.hpp"
65 #include "MueLu_IndexManager_kokkos.hpp"
66 
67 namespace MueLu {
68 
69 template <class LocalOrdinal, class GlobalOrdinal, class Node>
71  BuildAggregatesNonKokkos(const Teuchos::ParameterList& /* params */, const LWGraph& graph,
72  Aggregates& aggregates,
74  LO& numNonAggregatedNodes) const {
75  Monitor m(*this, "BuildAggregates");
76 
78  if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
79  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
80  out->setShowAllFrontMatter(false).setShowProcRank(true);
81  } else {
82  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
83  }
84 
85  RCP<IndexManager> geoData = aggregates.GetIndexManager();
86  const bool coupled = geoData->isAggregationCoupled();
87  const bool singleCoarsePoint = geoData->isSingleCoarsePoint();
88  ArrayRCP<LO> vertex2AggId = aggregates.GetVertex2AggId()->getDataNonConst(0);
89  ArrayRCP<LO> procWinner = aggregates.GetProcWinner()->getDataNonConst(0);
90  Array<LO> ghostedCoarseNodeCoarseLIDs;
91  Array<int> ghostedCoarseNodeCoarsePIDs;
92  Array<GO> ghostedCoarseNodeCoarseGIDs;
93 
94  *out << "Extract data for ghosted nodes" << std::endl;
95  geoData->getGhostedNodesData(graph.GetDomainMap(), ghostedCoarseNodeCoarseLIDs,
96  ghostedCoarseNodeCoarsePIDs, ghostedCoarseNodeCoarseGIDs);
97 
98  LO rem, rate;
99  Array<LO> ghostedIdx(3), coarseIdx(3);
100  LO ghostedCoarseNodeCoarseLID, aggId;
101  *out << "Loop over fine nodes and assign them to an aggregate and a rank" << std::endl;
102  for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
103  // Compute coarse ID associated with fine LID
104  geoData->getFineNodeGhostedTuple(nodeIdx, ghostedIdx[0], ghostedIdx[1], ghostedIdx[2]);
105 
106  for (int dim = 0; dim < 3; ++dim) {
107  if (singleCoarsePoint && (geoData->getLocalFineNodesInDir(dim) - 1 < geoData->getCoarseningRate(dim))) {
108  coarseIdx[dim] = 0;
109  } else {
110  coarseIdx[dim] = ghostedIdx[dim] / geoData->getCoarseningRate(dim);
111  rem = ghostedIdx[dim] % geoData->getCoarseningRate(dim);
112  if (ghostedIdx[dim] - geoData->getOffset(dim) < geoData->getLocalFineNodesInDir(dim) - geoData->getCoarseningEndRate(dim)) {
113  rate = geoData->getCoarseningRate(dim);
114  } else {
115  rate = geoData->getCoarseningEndRate(dim);
116  }
117  if (rem > (rate / 2)) {
118  ++coarseIdx[dim];
119  }
120  if (coupled && (geoData->getStartGhostedCoarseNode(dim) * geoData->getCoarseningRate(dim) > geoData->getStartIndex(dim))) {
121  --coarseIdx[dim];
122  }
123  }
124  }
125 
126  geoData->getCoarseNodeGhostedLID(coarseIdx[0], coarseIdx[1], coarseIdx[2],
127  ghostedCoarseNodeCoarseLID);
128 
129  aggId = ghostedCoarseNodeCoarseLIDs[ghostedCoarseNodeCoarseLID];
130  vertex2AggId[nodeIdx] = aggId;
131  procWinner[nodeIdx] = ghostedCoarseNodeCoarsePIDs[ghostedCoarseNodeCoarseLID];
132  aggStat[nodeIdx] = AGGREGATED;
133  --numNonAggregatedNodes;
134 
135  } // Loop over fine points
136 } // BuildAggregates()
137 
138 template <class LocalOrdinal, class GlobalOrdinal, class Node>
140  BuildGraphOnHost(const LWGraph& graph, RCP<IndexManager>& geoData, const LO dofsPerNode,
141  RCP<CrsGraph>& myGraph, RCP<const Map>& coarseCoordinatesFineMap,
142  RCP<const Map>& coarseCoordinatesMap) const {
143  Monitor m(*this, "BuildGraphP");
144 
146  if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
147  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
148  out->setShowAllFrontMatter(false).setShowProcRank(true);
149  } else {
150  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
151  }
152 
153  const bool coupled = geoData->isAggregationCoupled();
154 
155  // Compute the number of coarse points needed to interpolate quantities to a fine point
156  int numInterpolationPoints = 0;
157  if (geoData->getInterpolationOrder() == 0) {
158  numInterpolationPoints = 1;
159  } else if (geoData->getInterpolationOrder() == 1) {
160  // Compute 2^numDimensions using bit logic to avoid round-off errors
161  numInterpolationPoints = 1 << geoData->getNumDimensions();
162  }
163  *out << "numInterpolationPoints=" << numInterpolationPoints << std::endl;
164 
165  Array<LO> colIndex((geoData->getNumLocalCoarseNodes() + numInterpolationPoints *
166  (geoData->getNumLocalFineNodes() - geoData->getNumLocalCoarseNodes())) *
167  dofsPerNode);
168  Array<size_t> rowPtr(geoData->getNumLocalFineNodes() * dofsPerNode + 1);
169  rowPtr[0] = 0;
170  ArrayRCP<size_t> nnzOnRow(geoData->getNumLocalFineNodes() * dofsPerNode);
171 
172  *out << "Compute prolongatorGraph data" << std::endl;
173  if (geoData->getInterpolationOrder() == 0) {
174  ComputeGraphDataConstant(graph, geoData, dofsPerNode, numInterpolationPoints,
175  nnzOnRow, rowPtr, colIndex);
176  } else if (geoData->getInterpolationOrder() == 1) {
177  ComputeGraphDataLinear(graph, geoData, dofsPerNode, numInterpolationPoints,
178  nnzOnRow, rowPtr, colIndex);
179  }
180 
181  // Compute graph's rowMap, colMap and domainMap
182  RCP<Map> rowMap = MapFactory::Build(graph.GetDomainMap(), dofsPerNode);
183  RCP<Map> colMap, domainMap;
184  *out << "Compute domain and column maps of the CrsGraph" << std::endl;
185  if (coupled) {
186  *out << "Extract data for ghosted nodes" << std::endl;
187  Array<LO> ghostedCoarseNodeCoarseLIDs;
188  Array<int> ghostedCoarseNodeCoarsePIDs;
189  Array<GO> ghostedCoarseNodeCoarseGIDs;
190  geoData->getGhostedNodesData(graph.GetDomainMap(), ghostedCoarseNodeCoarseLIDs,
191  ghostedCoarseNodeCoarsePIDs, ghostedCoarseNodeCoarseGIDs);
192 
193  // In this case we specify the global number of nodes on the coarse mesh
194  // as well as the GIDs needed on rank.
195  colMap = MapFactory::Build(graph.GetDomainMap()->lib(),
196  geoData->getNumGlobalCoarseNodes(),
197  ghostedCoarseNodeCoarseGIDs(),
198  graph.GetDomainMap()->getIndexBase(),
199  graph.GetDomainMap()->getComm());
200 
201  LO coarseNodeIdx = 0;
202  Array<GO> coarseNodeCoarseGIDs, coarseNodeFineGIDs;
203  geoData->getCoarseNodesData(graph.GetDomainMap(), coarseNodeCoarseGIDs, coarseNodeFineGIDs);
204  for (LO nodeIdx = 0; nodeIdx < ghostedCoarseNodeCoarseGIDs.size(); ++nodeIdx) {
205  if (ghostedCoarseNodeCoarsePIDs[nodeIdx] == colMap->getComm()->getRank()) {
206  coarseNodeCoarseGIDs[coarseNodeIdx] = ghostedCoarseNodeCoarseGIDs[nodeIdx];
207  ++coarseNodeIdx;
208  }
209  }
210  domainMap = MapFactory::Build(graph.GetDomainMap()->lib(),
211  geoData->getNumGlobalCoarseNodes(),
212  coarseNodeCoarseGIDs(),
213  graph.GetDomainMap()->getIndexBase(),
214  graph.GetDomainMap()->getComm());
215  coarseCoordinatesMap = MapFactory::Build(graph.GetDomainMap()->lib(),
216  geoData->getNumGlobalCoarseNodes(),
217  coarseNodeCoarseGIDs(),
218  graph.GetDomainMap()->getIndexBase(),
219  graph.GetDomainMap()->getComm());
220  coarseCoordinatesFineMap = MapFactory::Build(graph.GetDomainMap()->lib(),
221  geoData->getNumGlobalCoarseNodes(),
222  coarseNodeFineGIDs(),
223  graph.GetDomainMap()->getIndexBase(),
224  graph.GetDomainMap()->getComm());
225  } else {
226  // In this case the map will compute the global number of nodes on the coarse mesh
227  // and it will assign GIDs to the local coarse nodes.
228  colMap = MapFactory::Build(graph.GetDomainMap()->lib(),
230  geoData->getNumLocalCoarseNodes() * dofsPerNode,
231  graph.GetDomainMap()->getIndexBase(),
232  graph.GetDomainMap()->getComm());
233  domainMap = colMap;
234 
235  Array<GO> coarseNodeCoarseGIDs(geoData->getNumLocalCoarseNodes());
236  Array<GO> coarseNodeFineGIDs(geoData->getNumLocalCoarseNodes());
237  geoData->getCoarseNodesData(graph.GetDomainMap(), coarseNodeCoarseGIDs, coarseNodeFineGIDs);
238  coarseCoordinatesMap = MapFactory::Build(graph.GetDomainMap()->lib(),
240  geoData->getNumLocalCoarseNodes(),
241  graph.GetDomainMap()->getIndexBase(),
242  graph.GetDomainMap()->getComm());
243  coarseCoordinatesFineMap = MapFactory::Build(graph.GetDomainMap()->lib(),
245  coarseNodeFineGIDs(),
246  graph.GetDomainMap()->getIndexBase(),
247  graph.GetDomainMap()->getComm());
248  }
249 
250  *out << "Call constructor of CrsGraph" << std::endl;
251  myGraph = CrsGraphFactory::Build(rowMap,
252  colMap,
253  nnzOnRow);
254 
255  *out << "Fill CrsGraph" << std::endl;
256  LO rowIdx = 0;
257  for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
258  for (LO dof = 0; dof < dofsPerNode; ++dof) {
259  rowIdx = nodeIdx * dofsPerNode + dof;
260  myGraph->insertLocalIndices(rowIdx, colIndex(rowPtr[rowIdx], nnzOnRow[rowIdx]));
261  }
262  }
263 
264  *out << "Call fillComplete on CrsGraph" << std::endl;
265  myGraph->fillComplete(domainMap, rowMap);
266  *out << "Prolongator CrsGraph computed" << std::endl;
267 
268 } // BuildGraph()
269 
270 template <class LocalOrdinal, class GlobalOrdinal, class Node>
273  const LO dofsPerNode, const int /* numInterpolationPoints */,
274  ArrayRCP<size_t>& nnzOnRow, Array<size_t>& rowPtr,
275  Array<LO>& colIndex) const {
277  if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
278  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
279  out->setShowAllFrontMatter(false).setShowProcRank(true);
280  } else {
281  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
282  }
283 
284  Array<LO> ghostedCoarseNodeCoarseLIDs;
285  Array<int> ghostedCoarseNodeCoarsePIDs;
286  Array<GO> ghostedCoarseNodeCoarseGIDs;
287  geoData->getGhostedNodesData(graph.GetDomainMap(), ghostedCoarseNodeCoarseLIDs,
288  ghostedCoarseNodeCoarsePIDs, ghostedCoarseNodeCoarseGIDs);
289 
290  LO ghostedCoarseNodeCoarseLID, rem, rate;
291  Array<LO> ghostedIdx(3), coarseIdx(3);
292  for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
293  // Compute coarse ID associated with fine LID
294  geoData->getFineNodeGhostedTuple(nodeIdx, ghostedIdx[0], ghostedIdx[1], ghostedIdx[2]);
295 
296  for (int dim = 0; dim < 3; ++dim) {
297  if (geoData->isSingleCoarsePoint() && (geoData->getLocalFineNodesInDir(dim) - 1 < geoData->getCoarseningRate(dim))) {
298  coarseIdx[dim] = 0;
299  } else {
300  coarseIdx[dim] = ghostedIdx[dim] / geoData->getCoarseningRate(dim);
301  rem = ghostedIdx[dim] % geoData->getCoarseningRate(dim);
302  if (ghostedIdx[dim] - geoData->getOffset(dim) < geoData->getLocalFineNodesInDir(dim) - geoData->getCoarseningEndRate(dim)) {
303  rate = geoData->getCoarseningRate(dim);
304  } else {
305  rate = geoData->getCoarseningEndRate(dim);
306  }
307  if (rem > (rate / 2)) {
308  ++coarseIdx[dim];
309  }
310  if ((geoData->getStartGhostedCoarseNode(dim) * geoData->getCoarseningRate(dim) > geoData->getStartIndex(dim)) && geoData->isAggregationCoupled()) {
311  --coarseIdx[dim];
312  }
313  }
314  }
315 
316  geoData->getCoarseNodeGhostedLID(coarseIdx[0], coarseIdx[1], coarseIdx[2],
317  ghostedCoarseNodeCoarseLID);
318 
319  for (LO dof = 0; dof < dofsPerNode; ++dof) {
320  nnzOnRow[nodeIdx * dofsPerNode + dof] = 1;
321  rowPtr[nodeIdx * dofsPerNode + dof + 1] = rowPtr[nodeIdx * dofsPerNode + dof] + 1;
322  colIndex[rowPtr[nodeIdx * dofsPerNode + dof]] =
323  ghostedCoarseNodeCoarseLIDs[ghostedCoarseNodeCoarseLID] * dofsPerNode + dof;
324  }
325  } // Loop over fine points
326 
327 } // ComputeGraphDataConstant()
328 
329 template <class LocalOrdinal, class GlobalOrdinal, class Node>
331  ComputeGraphDataLinear(const LWGraph& /* graph */, RCP<IndexManager>& geoData,
332  const LO dofsPerNode, const int numInterpolationPoints,
333  ArrayRCP<size_t>& nnzOnRow, Array<size_t>& rowPtr,
334  Array<LO>& colIndex) const {
336  if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
337  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
338  out->setShowAllFrontMatter(false).setShowProcRank(true);
339  } else {
340  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
341  }
342 
343  const bool coupled = geoData->isAggregationCoupled();
344  const int numDimensions = geoData->getNumDimensions();
345  Array<LO> ghostedIdx(3, 0);
346  Array<LO> coarseIdx(3, 0);
347  Array<LO> ijkRem(3, 0);
348  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}};
349 
350  for (LO nodeIdx = 0; nodeIdx < geoData->getNumLocalFineNodes(); ++nodeIdx) {
351  // Compute coarse ID associated with fine LID
352  geoData->getFineNodeGhostedTuple(nodeIdx, ghostedIdx[0], ghostedIdx[1], ghostedIdx[2]);
353  for (int dim = 0; dim < numDimensions; dim++) {
354  coarseIdx[dim] = ghostedIdx[dim] / geoData->getCoarseningRate(dim);
355  ijkRem[dim] = ghostedIdx[dim] % geoData->getCoarseningRate(dim);
356  if (coupled) {
357  if (geoData->getStartGhostedCoarseNode(dim) * geoData->getCoarseningRate(dim) > geoData->getStartIndex(dim)) {
358  --coarseIdx[dim];
359  }
360  } else {
361  if (ghostedIdx[dim] == geoData->getLocalFineNodesInDir(dim) - 1) {
362  coarseIdx[dim] = geoData->getLocalCoarseNodesInDir(dim) - 1;
363  }
364  }
365  }
366 
367  // Fill Graph
368  // Check if Fine node lies on Coarse Node
369  bool allCoarse = true;
370  Array<bool> isCoarse(numDimensions);
371  for (int dim = 0; dim < numDimensions; ++dim) {
372  isCoarse[dim] = false;
373  if (ijkRem[dim] == 0)
374  isCoarse[dim] = true;
375 
376  if (coupled) {
377  if (ghostedIdx[dim] - geoData->getOffset(dim) == geoData->getLocalFineNodesInDir(dim) - 1 &&
378  geoData->getMeshEdge(dim * 2 + 1))
379  isCoarse[dim] = true;
380  } else {
381  if (ghostedIdx[dim] - geoData->getOffset(dim) == geoData->getLocalFineNodesInDir(dim) - 1)
382  isCoarse[dim] = true;
383  }
384 
385  if (!isCoarse[dim])
386  allCoarse = false;
387  }
388 
389  LO rowIdx = 0, colIdx = 0;
390  if (allCoarse) {
391  for (LO dof = 0; dof < dofsPerNode; ++dof) {
392  rowIdx = nodeIdx * dofsPerNode + dof;
393  nnzOnRow[rowIdx] = 1;
394  rowPtr[rowIdx + 1] = rowPtr[rowIdx] + 1;
395 
396  // Fine node lies on Coarse node, easy case, we only need the LID of the coarse node.
397  geoData->getCoarseNodeGhostedLID(coarseIdx[0], coarseIdx[1], coarseIdx[2], colIdx);
398  colIndex[rowPtr[rowIdx]] = colIdx * dofsPerNode + dof;
399  }
400  } else {
401  // Harder case, we need the LIDs of all the coarse nodes contributing to the interpolation
402  for (int dim = 0; dim < numDimensions; ++dim) {
403  if (coarseIdx[dim] == geoData->getGhostedNodesInDir(dim) - 1)
404  --coarseIdx[dim];
405  }
406 
407  for (LO dof = 0; dof < dofsPerNode; ++dof) {
408  // at the current node.
409  rowIdx = nodeIdx * dofsPerNode + dof;
410  nnzOnRow[rowIdx] = Teuchos::as<size_t>(numInterpolationPoints);
411  rowPtr[rowIdx + 1] = rowPtr[rowIdx] + Teuchos::as<LO>(numInterpolationPoints);
412  // Compute Coarse Node LID
413  for (LO interpIdx = 0; interpIdx < numInterpolationPoints; ++interpIdx) {
414  geoData->getCoarseNodeGhostedLID(coarseIdx[0] + coarsePointOffset[interpIdx][0],
415  coarseIdx[1] + coarsePointOffset[interpIdx][1],
416  coarseIdx[2] + coarsePointOffset[interpIdx][2],
417  colIdx);
418  colIndex[rowPtr[rowIdx] + interpIdx] = colIdx * dofsPerNode + dof;
419  } // Loop over numInterpolationPoints
420  } // Loop over dofsPerNode
421  }
422  } // Loop over fine points
423 } // ComputeGraphDataLinear()
424 
425 template <class LocalOrdinal, class GlobalOrdinal, class Node>
427  BuildAggregates(const Teuchos::ParameterList& /* params */, const LWGraph_kokkos& graph,
428  Aggregates& aggregates,
430  LO& numNonAggregatedNodes) const {
431  Monitor m(*this, "BuildAggregates");
432 
434  if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
435  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
436  out->setShowAllFrontMatter(false).setShowProcRank(true);
437  } else {
438  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
439  }
440 
441  RCP<IndexManager_kokkos> geoData = aggregates.GetIndexManagerKokkos();
442  const LO numLocalFineNodes = geoData->getNumLocalFineNodes();
443  const LO numCoarseNodes = geoData->getNumCoarseNodes();
444  LOVectorView vertex2AggId = aggregates.GetVertex2AggId()->getDeviceLocalView(Xpetra::Access::ReadWrite);
445  LOVectorView procWinner = aggregates.GetProcWinner()->getDeviceLocalView(Xpetra::Access::ReadWrite);
446 
447  *out << "Loop over fine nodes and assign them to an aggregate and a rank" << std::endl;
448  LO numAggregatedNodes;
449  fillAggregatesFunctor fillAggregates(geoData,
450  graph.GetComm()->getRank(),
451  aggStat,
452  vertex2AggId,
453  procWinner);
454  Kokkos::parallel_reduce("StructuredAggregation: fill aggregates data",
455  Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes),
456  fillAggregates,
457  numAggregatedNodes);
458 
459  *out << "numCoarseNodes= " << numCoarseNodes
460  << ", numAggregatedNodes= " << numAggregatedNodes << std::endl;
461  numNonAggregatedNodes = numNonAggregatedNodes - numAggregatedNodes;
462 
463 } // BuildAggregates()
464 
465 template <class LocalOrdinal, class GlobalOrdinal, class Node>
467  BuildGraph(const LWGraph_kokkos& graph, RCP<IndexManager_kokkos>& geoData, const LO dofsPerNode,
468  RCP<CrsGraph>& myGraph) const {
469  Monitor m(*this, "BuildGraphP");
470 
472  if (const char* dbg = std::getenv("MUELU_STRUCTUREDALGORITHM_DEBUG")) {
473  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
474  out->setShowAllFrontMatter(false).setShowProcRank(true);
475  } else {
476  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
477  }
478 
479  // Compute the number of coarse points needed to interpolate quantities to a fine point
480  int numInterpolationPoints = 0;
481  if (geoData->getInterpolationOrder() == 0) {
482  numInterpolationPoints = 1;
483  } else if (geoData->getInterpolationOrder() == 1) {
484  // Compute 2^numDimensions using bit logic to avoid round-off errors from std::pow()
485  numInterpolationPoints = 1 << geoData->getNumDimensions();
486  }
487  *out << "numInterpolationPoints=" << numInterpolationPoints << std::endl;
488 
489  const LO numLocalFineNodes = geoData->getNumLocalFineNodes();
490  const LO numCoarseNodes = geoData->getNumCoarseNodes();
491  const LO numNnzEntries = dofsPerNode * (numCoarseNodes + numInterpolationPoints * (numLocalFineNodes - numCoarseNodes));
492 
493  non_const_row_map_type rowPtr("Prolongator graph, rowPtr", dofsPerNode * (numLocalFineNodes + 1));
494  entries_type colIndex("Prolongator graph, colIndices", numNnzEntries);
495 
496  *out << "Compute prolongatorGraph data" << std::endl;
497  if (geoData->getInterpolationOrder() == 0) {
498  computeGraphDataConstantFunctor computeGraphData(geoData,
499  numCoarseNodes,
500  dofsPerNode,
501  geoData->getCoarseningRates(),
502  geoData->getCoarseningEndRates(),
503  geoData->getLocalFineNodesPerDir(),
504  rowPtr,
505  colIndex);
506  Kokkos::parallel_for("Structured Aggregation: compute loca graph data",
507  Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes),
508  computeGraphData);
509  } else if (geoData->getInterpolationOrder() == 1) {
510  // Note, lbv 2018-11-08: in the piece-wise linear case I am computing the rowPtr
511  // using a parallel scan, it might be possible to do something faster than that
512  // by including this calculation in computeGraphDataLinearFunctor but at the moment
513  // all the ideas I have include a bunch of if statements which I would like to avoid.
514  computeGraphRowPtrFunctor computeGraphRowPtr(geoData,
515  dofsPerNode,
516  numInterpolationPoints,
517  numLocalFineNodes,
518  geoData->getCoarseningRates(),
519  geoData->getLocalFineNodesPerDir(),
520  rowPtr);
521  Kokkos::parallel_scan("Structured Aggregation: compute rowPtr for prolongator graph",
522  Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes + 1),
523  computeGraphRowPtr);
524 
525  computeGraphDataLinearFunctor computeGraphData(geoData,
526  geoData->getNumDimensions(),
527  numCoarseNodes,
528  dofsPerNode,
529  numInterpolationPoints,
530  geoData->getCoarseningRates(),
531  geoData->getCoarseningEndRates(),
532  geoData->getLocalFineNodesPerDir(),
533  geoData->getCoarseNodesPerDir(),
534  rowPtr,
535  colIndex);
536  Kokkos::parallel_for("Structured Aggregation: compute loca graph data",
537  Kokkos::RangePolicy<execution_space>(0, numLocalFineNodes),
538  computeGraphData);
539  }
540 
541  local_graph_type myLocalGraph(colIndex, rowPtr);
542 
543  // Compute graph's colMap and domainMap
544  RCP<Map> colMap, domainMap;
545  *out << "Compute domain and column maps of the CrsGraph" << std::endl;
546  colMap = MapFactory::Build(graph.GetDomainMap()->lib(),
548  numCoarseNodes,
549  graph.GetDomainMap()->getIndexBase(),
550  graph.GetDomainMap()->getComm());
551  domainMap = colMap;
552 
553  myGraph = CrsGraphFactory::Build(myLocalGraph, graph.GetDomainMap(), colMap,
554  colMap, graph.GetDomainMap());
555 
556 } // BuildGraph()
557 
558 template <class LocalOrdinal, class GlobalOrdinal, class Node>
561  const int myRank,
562  Kokkos::View<unsigned*, device_type> aggStat,
563  LOVectorView vertex2AggID,
564  LOVectorView procWinner)
565  : geoData_(*geoData)
566  , myRank_(myRank)
567  , aggStat_(aggStat)
568  , vertex2AggID_(vertex2AggID)
569  , procWinner_(procWinner) {}
570 
571 template <class LocalOrdinal, class GlobalOrdinal, class Node>
573  fillAggregatesFunctor::operator()(const LO nodeIdx, LO& lNumAggregatedNodes) const {
574  // Compute coarse ID associated with fine LID
575  LO rem, rate;
576  LO coarseNodeCoarseLID;
577  LO nodeFineTuple[3], coarseIdx[3];
578  auto coarseRate = geoData_.getCoarseningRates();
579  auto endRate = geoData_.getCoarseningEndRates();
580  auto lFineNodesPerDir = geoData_.getLocalFineNodesPerDir();
581  // Compute coarse ID associated with fine LID
582  geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
583 
584  for (int dim = 0; dim < 3; ++dim) {
585  coarseIdx[dim] = nodeFineTuple[dim] / coarseRate(dim);
586  rem = nodeFineTuple[dim] % coarseRate(dim);
587  rate = (nodeFineTuple[dim] < lFineNodesPerDir(dim) - endRate(dim)) ? coarseRate(dim) : endRate(dim);
588  if (rem > (rate / 2)) {
589  ++coarseIdx[dim];
590  }
591  }
592 
593  geoData_.getCoarseTuple2CoarseLID(coarseIdx[0], coarseIdx[1], coarseIdx[2],
594  coarseNodeCoarseLID);
595 
596  vertex2AggID_(nodeIdx, 0) = coarseNodeCoarseLID;
597  procWinner_(nodeIdx, 0) = myRank_;
598  aggStat_(nodeIdx) = AGGREGATED;
599  ++lNumAggregatedNodes;
600 
601 } // fillAggregatesFunctor::operator()
602 
603 template <class LocalOrdinal, class GlobalOrdinal, class Node>
607  const LO NumGhostedNodes,
608  const LO dofsPerNode,
609  constIntTupleView coarseRate,
610  constIntTupleView endRate,
611  constLOTupleView lFineNodesPerDir,
612  non_const_row_map_type rowPtr,
613  entries_type colIndex)
614  : geoData_(*geoData)
615  , numGhostedNodes_(NumGhostedNodes)
616  , dofsPerNode_(dofsPerNode)
617  , coarseRate_(coarseRate)
618  , endRate_(endRate)
619  , lFineNodesPerDir_(lFineNodesPerDir)
620  , rowPtr_(rowPtr)
621  , colIndex_(colIndex) {
622 } // computeGraphDataConstantFunctor()
623 
624 template <class LocalOrdinal, class GlobalOrdinal, class Node>
627  LO nodeFineTuple[3] = {0, 0, 0};
628  LO nodeCoarseTuple[3] = {0, 0, 0};
629 
630  // Compute ghosted tuple associated with fine LID
631  geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
632 
633  // Compute coarse tuple associated with fine point
634  // then overwrite it with tuple associated with aggregate
635  LO rem, rate, coarseNodeCoarseLID;
636  for (int dim = 0; dim < 3; ++dim) {
637  nodeCoarseTuple[dim] = nodeFineTuple[dim] / coarseRate_(dim);
638  rem = nodeFineTuple[dim] % coarseRate_(dim);
639  if (nodeFineTuple[dim] < (lFineNodesPerDir_(dim) - endRate_(dim))) {
640  rate = coarseRate_(dim);
641  } else {
642  rate = endRate_(dim);
643  }
644  if (rem > (rate / 2)) {
645  ++nodeCoarseTuple[dim];
646  }
647  }
648 
649  // get LID associted with aggregate
650  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2],
651  coarseNodeCoarseLID);
652 
653  // store data into CrsGraph taking care of multiple dofs case
654  for (LO dof = 0; dof < dofsPerNode_; ++dof) {
655  rowPtr_(nodeIdx * dofsPerNode_ + dof + 1) = nodeIdx * dofsPerNode_ + dof + 1;
656  colIndex_(nodeIdx * dofsPerNode_ + dof) = coarseNodeCoarseLID * dofsPerNode_ + dof;
657  }
658 
659 } // computeGraphDataConstantFunctor::operator()
660 
661 template <class LocalOrdinal, class GlobalOrdinal, class Node>
664  const LO dofsPerNode,
665  const int numInterpolationPoints,
666  const LO numLocalRows,
667  constIntTupleView coarseRate,
668  constLOTupleView lFineNodesPerDir,
669  non_const_row_map_type rowPtr)
670  : geoData_(*geoData)
671  , dofsPerNode_(dofsPerNode)
672  , numInterpolationPoints_(numInterpolationPoints)
673  , numLocalRows_(numLocalRows)
674  , coarseRate_(coarseRate)
675  , lFineNodesPerDir_(lFineNodesPerDir)
676  , rowPtr_(rowPtr) {}
677 
678 template <class LocalOrdinal, class GlobalOrdinal, class Node>
680  computeGraphRowPtrFunctor::operator()(const LO rowIdx, GO& update, const bool final) const {
681  if (final) {
682  // Kokkos uses a multipass algorithm to implement scan.
683  // Only update the array on the final pass. Updating the
684  // array before changing 'update' means that we do an
685  // exclusive scan. Update the array after for an inclusive
686  // scan.
687  rowPtr_(rowIdx) = update;
688  }
689  if (rowIdx < numLocalRows_) {
690  LO nodeIdx = rowIdx / dofsPerNode_;
691  bool allCoarse = true;
692  LO nodeFineTuple[3] = {0, 0, 0};
693  geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
694  for (int dim = 0; dim < 3; ++dim) {
695  const LO rem = nodeFineTuple[dim] % coarseRate_(dim);
696 
697  // Check if Fine node lies on Coarse Node
698  allCoarse = (allCoarse && ((rem == 0) || (nodeFineTuple[dim] == lFineNodesPerDir_(dim) - 1)));
699  }
700  update += (allCoarse ? 1 : numInterpolationPoints_);
701  }
702 } // computeGraphRowPtrFunctor::operator()
703 
704 template <class LocalOrdinal, class GlobalOrdinal, class Node>
707  const int numDimensions,
708  const LO numGhostedNodes,
709  const LO dofsPerNode,
710  const int numInterpolationPoints,
711  constIntTupleView coarseRate,
712  constIntTupleView endRate,
713  constLOTupleView lFineNodesPerDir,
714  constLOTupleView ghostedNodesPerDir,
715  non_const_row_map_type rowPtr,
716  entries_type colIndex)
717  : geoData_(*geoData)
718  , numDimensions_(numDimensions)
719  , numGhostedNodes_(numGhostedNodes)
720  , dofsPerNode_(dofsPerNode)
721  , numInterpolationPoints_(numInterpolationPoints)
722  , coarseRate_(coarseRate)
723  , endRate_(endRate)
724  , lFineNodesPerDir_(lFineNodesPerDir)
725  , ghostedNodesPerDir_(ghostedNodesPerDir)
726  , rowPtr_(rowPtr)
727  , colIndex_(colIndex) {
728 } // computeGraphDataLinearFunctor()
729 
730 template <class LocalOrdinal, class GlobalOrdinal, class Node>
733  LO nodeFineTuple[3] = {0, 0, 0};
734  LO nodeCoarseTuple[3] = {0, 0, 0};
735 
736  // Compute coarse ID associated with fine LID
737  geoData_.getFineLID2FineTuple(nodeIdx, nodeFineTuple);
738 
739  LO coarseNodeCoarseLID;
740  bool allCoarse = false;
741  for (int dim = 0; dim < 3; ++dim) {
742  nodeCoarseTuple[dim] = nodeFineTuple[dim] / coarseRate_(dim);
743  }
744  if (rowPtr_(nodeIdx + 1) == rowPtr_(nodeIdx) + 1) {
745  allCoarse = true;
746  }
747 
748  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2],
749  coarseNodeCoarseLID);
750 
751  if (allCoarse) {
752  // Fine node lies on Coarse node, easy case, we only need the LID of the coarse node.
753  for (LO dof = 0; dof < dofsPerNode_; ++dof) {
754  colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof)) = coarseNodeCoarseLID * dofsPerNode_ + dof;
755  }
756  } else {
757  for (int dim = 0; dim < numDimensions_; ++dim) {
758  if (nodeCoarseTuple[dim] == ghostedNodesPerDir_(dim) - 1) {
759  --nodeCoarseTuple[dim];
760  }
761  }
762  // Compute Coarse Node LID
763  // Note lbv 10-06-2018: it is likely benefitial to remove the two if statments and somehow
764  // find out the number of dimensions before calling the opertor() of the functor.
765  for (LO dof = 0; dof < dofsPerNode_; ++dof) {
766  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 0));
767  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1], nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 1));
768  if (numDimensions_ > 1) {
769  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1] + 1, nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 2));
770  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1] + 1, nodeCoarseTuple[2], colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 3));
771  if (numDimensions_ > 2) {
772  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1], nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 4));
773  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1], nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 5));
774  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0], nodeCoarseTuple[1] + 1, nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 6));
775  geoData_.getCoarseTuple2CoarseLID(nodeCoarseTuple[0] + 1, nodeCoarseTuple[1] + 1, nodeCoarseTuple[2] + 1, colIndex_(rowPtr_(nodeIdx * dofsPerNode_ + dof) + 7));
776  }
777  }
778  }
779  }
780 } // computeGraphDataLinearFunctor::operator()
781 
782 } // namespace MueLu
783 
784 #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...