MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_HybridAggregationFactory_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_HYBRIDAGGREGATIONFACTORY_DEF_HPP_
47 #define MUELU_HYBRIDAGGREGATIONFACTORY_DEF_HPP_
48 
49 #include <Xpetra_Matrix.hpp>
50 #include <Xpetra_Map.hpp>
51 #include <Xpetra_Vector.hpp>
52 #include <Xpetra_MultiVectorFactory.hpp>
53 #include <Xpetra_VectorFactory.hpp>
54 
56 
57 // Uncoupled Agg
58 #include "MueLu_InterfaceAggregationAlgorithm.hpp"
59 #include "MueLu_OnePtAggregationAlgorithm.hpp"
60 #include "MueLu_PreserveDirichletAggregationAlgorithm.hpp"
61 
62 #include "MueLu_AggregationPhase1Algorithm.hpp"
63 #include "MueLu_AggregationPhase2aAlgorithm.hpp"
64 #include "MueLu_AggregationPhase2bAlgorithm.hpp"
65 #include "MueLu_AggregationPhase3Algorithm.hpp"
66 
67 // Structured Agg
68 #include "MueLu_AggregationStructuredAlgorithm.hpp"
69 #include "MueLu_UncoupledIndexManager.hpp"
70 //#include "MueLu_LocalLexicographicIndexManager.hpp"
71 //#include "MueLu_GlobalLexicographicIndexManager.hpp"
72 
73 // Shared
74 #include "MueLu_Level.hpp"
75 #include "MueLu_LWGraph.hpp"
76 #include "MueLu_Aggregates.hpp"
77 #include "MueLu_MasterList.hpp"
78 #include "MueLu_Monitor.hpp"
79 
80 namespace MueLu {
81 
82 template <class LocalOrdinal, class GlobalOrdinal, class Node>
85  : bDefinitionPhase_(true) {}
86 
87 template <class LocalOrdinal, class GlobalOrdinal, class Node>
90  RCP<ParameterList> validParamList = rcp(new ParameterList());
91 
92 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
93  // From UncoupledAggregationFactory
94  SET_VALID_ENTRY("aggregation: max agg size");
95  SET_VALID_ENTRY("aggregation: min agg size");
96  SET_VALID_ENTRY("aggregation: max selected neighbors");
97  SET_VALID_ENTRY("aggregation: ordering");
98  validParamList->getEntry("aggregation: ordering").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("natural", "graph", "random"))));
99  SET_VALID_ENTRY("aggregation: enable phase 1");
100  SET_VALID_ENTRY("aggregation: enable phase 2a");
101  SET_VALID_ENTRY("aggregation: enable phase 2b");
102  SET_VALID_ENTRY("aggregation: enable phase 3");
103  SET_VALID_ENTRY("aggregation: preserve Dirichlet points");
104  SET_VALID_ENTRY("aggregation: allow user-specified singletons");
105  SET_VALID_ENTRY("aggregation: error on nodes with no on-rank neighbors");
106  SET_VALID_ENTRY("aggregation: match ML phase2a");
107  SET_VALID_ENTRY("aggregation: phase2a agg factor");
108  SET_VALID_ENTRY("aggregation: phase3 avoid singletons");
109 
110  // From StructuredAggregationFactory
111  SET_VALID_ENTRY("aggregation: coarsening rate");
112  SET_VALID_ENTRY("aggregation: coarsening order");
113  SET_VALID_ENTRY("aggregation: number of spatial dimensions");
114 
115  // From HybridAggregationFactory
116  SET_VALID_ENTRY("aggregation: use interface aggregation");
117 #undef SET_VALID_ENTRY
118 
119  /* From UncoupledAggregation */
120  // general variables needed in AggregationFactory
121  validParamList->set<RCP<const FactoryBase> >("Graph", null, "Generating factory of the graph");
122  validParamList->set<RCP<const FactoryBase> >("DofsPerNode", null, "Generating factory for variable \'DofsPerNode\', usually the same as for \'Graph\'");
123  // special variables necessary for OnePtAggregationAlgorithm
124  validParamList->set<std::string>("OnePt aggregate map name", "",
125  "Name of input map for single node aggregates. (default='')");
126  validParamList->set<std::string>("OnePt aggregate map factory", "",
127  "Generating factory of (DOF) map for single node aggregates.");
128 
129  // InterfaceAggregation parameters
130  validParamList->set<std::string>("Interface aggregate map name", "",
131  "Name of input map for interface aggregates. (default='')");
132  validParamList->set<std::string>("Interface aggregate map factory", "",
133  "Generating factory of (DOF) map for interface aggregates.");
134  validParamList->set<RCP<const FactoryBase> >("interfacesDimensions", Teuchos::null,
135  "Describes the dimensions of all the interfaces on this rank.");
136  validParamList->set<RCP<const FactoryBase> >("nodeOnInterface", Teuchos::null,
137  "List the LIDs of the nodes on any interface.");
138 
139  /* From StructuredAggregation */
140  // general variables needed in AggregationFactory
141  validParamList->set<RCP<const FactoryBase> >("numDimensions", Teuchos::null,
142  "Number of spatial dimension provided by CoordinatesTransferFactory.");
143  validParamList->set<RCP<const FactoryBase> >("lNodesPerDim", Teuchos::null,
144  "Number of nodes per spatial dimmension provided by CoordinatesTransferFactory.");
145 
146  // Hybrid Aggregation Params
147  validParamList->set<RCP<const FactoryBase> >("aggregationRegionType", Teuchos::null,
148  "Type of aggregation to use on the region (\"structured\" or \"uncoupled\")");
149 
150  return validParamList;
151 }
152 
153 template <class LocalOrdinal, class GlobalOrdinal, class Node>
155  DeclareInput(Level& currentLevel) const {
156  Input(currentLevel, "Graph");
157 
158  ParameterList pL = GetParameterList();
159 
160  /* StructuredAggregation */
161 
162  // Request the local number of nodes per dimensions
163  if (currentLevel.GetLevelID() == 0) {
164  if (currentLevel.IsAvailable("aggregationRegionType", NoFactory::get())) {
165  currentLevel.DeclareInput("aggregationRegionType", NoFactory::get(), this);
166  } else {
167  TEUCHOS_TEST_FOR_EXCEPTION(!currentLevel.IsAvailable("aggregationRegionType", NoFactory::get()),
169  "Aggregation region type was not provided by the user!");
170  }
171  if (currentLevel.IsAvailable("numDimensions", NoFactory::get())) {
172  currentLevel.DeclareInput("numDimensions", NoFactory::get(), this);
173  } else {
174  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("numDimensions", NoFactory::get()),
176  "numDimensions was not provided by the user on level0!");
177  }
178  if (currentLevel.IsAvailable("lNodesPerDim", NoFactory::get())) {
179  currentLevel.DeclareInput("lNodesPerDim", NoFactory::get(), this);
180  } else {
181  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("lNodesPerDim", NoFactory::get()),
183  "lNodesPerDim was not provided by the user on level0!");
184  }
185  } else {
186  Input(currentLevel, "aggregationRegionType");
187  Input(currentLevel, "numDimensions");
188  Input(currentLevel, "lNodesPerDim");
189  }
190 
191  /* UncoupledAggregation */
192  Input(currentLevel, "DofsPerNode");
193 
194  // request special data necessary for InterfaceAggregation
195  if (pL.get<bool>("aggregation: use interface aggregation") == true) {
196  if (currentLevel.GetLevelID() == 0) {
197  if (currentLevel.IsAvailable("interfacesDimensions", NoFactory::get())) {
198  currentLevel.DeclareInput("interfacesDimensions", NoFactory::get(), this);
199  } else {
200  TEUCHOS_TEST_FOR_EXCEPTION(!currentLevel.IsAvailable("interfacesDimensions", NoFactory::get()),
202  "interfacesDimensions was not provided by the user on level0!");
203  }
204  if (currentLevel.IsAvailable("nodeOnInterface", NoFactory::get())) {
205  currentLevel.DeclareInput("nodeOnInterface", NoFactory::get(), this);
206  } else {
207  TEUCHOS_TEST_FOR_EXCEPTION(!currentLevel.IsAvailable("nodeOnInterface", NoFactory::get()),
209  "nodeOnInterface was not provided by the user on level0!");
210  }
211  } else {
212  Input(currentLevel, "interfacesDimensions");
213  Input(currentLevel, "nodeOnInterface");
214  }
215  }
216 
217  // request special data necessary for OnePtAggregationAlgorithm
218  std::string mapOnePtName = pL.get<std::string>("OnePt aggregate map name");
219  if (mapOnePtName.length() > 0) {
220  std::string mapOnePtFactName = pL.get<std::string>("OnePt aggregate map factory");
221  if (mapOnePtFactName == "" || mapOnePtFactName == "NoFactory") {
222  currentLevel.DeclareInput(mapOnePtName, NoFactory::get());
223  } else {
224  RCP<const FactoryBase> mapOnePtFact = GetFactory(mapOnePtFactName);
225  currentLevel.DeclareInput(mapOnePtName, mapOnePtFact.get());
226  }
227  }
228 } // DeclareInput()
229 
230 template <class LocalOrdinal, class GlobalOrdinal, class Node>
232  Build(Level& currentLevel) const {
233  FactoryMonitor m(*this, "Build", currentLevel);
234 
236  if (const char* dbg = std::getenv("MUELU_HYBRIDAGGREGATION_DEBUG")) {
237  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
238  out->setShowAllFrontMatter(false).setShowProcRank(true);
239  } else {
240  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
241  }
242 
243  *out << "Entering hybrid aggregation" << std::endl;
244 
245  ParameterList pL = GetParameterList();
246  bDefinitionPhase_ = false; // definition phase is finished, now all aggregation algorithm information is fixed
247 
248  if (pL.get<int>("aggregation: max agg size") == -1)
249  pL.set("aggregation: max agg size", INT_MAX);
250 
251  // define aggregation algorithms
252  RCP<const FactoryBase> graphFact = GetFactory("Graph");
253 
254  // General problem informations are gathered from data stored in the problem matix.
255  RCP<const LWGraph> graph = Get<RCP<LWGraph> >(currentLevel, "Graph");
256  RCP<const Map> fineMap = graph->GetDomainMap();
257  const int myRank = fineMap->getComm()->getRank();
258  const int numRanks = fineMap->getComm()->getSize();
259 
260  out->setProcRankAndSize(graph->GetImportMap()->getComm()->getRank(),
261  graph->GetImportMap()->getComm()->getSize());
262 
263  // Build aggregates
264  RCP<Aggregates> aggregates = rcp(new Aggregates(*graph));
265  aggregates->setObjectLabel("HB");
266 
267  // construct aggStat information
268  const LO numRows = graph->GetNodeNumVertices();
270  AggStatHostType aggStat(Kokkos::ViewAllocateWithoutInitializing("aggregation status"), numRows);
271  Kokkos::deep_copy(aggStat, READY);
272 
273  // Get aggregation type for region
274  std::string regionType;
275  if (currentLevel.GetLevelID() == 0) {
276  // On level 0, data is provided by applications and has no associated factory.
277  regionType = currentLevel.Get<std::string>("aggregationRegionType", NoFactory::get());
278  } else {
279  // On level > 0, data is provided directly by generating factories.
280  regionType = Get<std::string>(currentLevel, "aggregationRegionType");
281  }
282 
283  int numDimensions = 0;
284  if (currentLevel.GetLevelID() == 0) {
285  // On level 0, data is provided by applications and has no associated factory.
286  numDimensions = currentLevel.Get<int>("numDimensions", NoFactory::get());
287  } else {
288  // On level > 0, data is provided directly by generating factories.
289  numDimensions = Get<int>(currentLevel, "numDimensions");
290  }
291 
292  // Get the coarsening rate (potentially used for both structured and uncoupled aggregation if interface)
293  std::string coarseningRate = pL.get<std::string>("aggregation: coarsening rate");
294  Teuchos::Array<LO> coarseRate;
295  try {
296  coarseRate = Teuchos::fromStringToArray<LO>(coarseningRate);
297  } catch (const Teuchos::InvalidArrayStringRepresentation& e) {
298  GetOStream(Errors, -1) << " *** \"aggregation: coarsening rate\" must be a string convertible into an array! *** "
299  << std::endl;
300  throw e;
301  }
302  TEUCHOS_TEST_FOR_EXCEPTION((coarseRate.size() > 1) && (coarseRate.size() < numDimensions),
304  "\"aggregation: coarsening rate\" must have at least as many"
305  " components as the number of spatial dimensions in the problem.");
306 
307  algos_.clear();
308  LO numNonAggregatedNodes = numRows;
309  if (regionType == "structured") {
310  // Add AggregationStructuredAlgorithm
311  algos_.push_back(rcp(new AggregationStructuredAlgorithm(graphFact)));
312 
313  // Since we want to operate on nodes and not dof, we need to modify the rowMap in order to
314  // obtain a nodeMap.
315  const int interpolationOrder = pL.get<int>("aggregation: coarsening order");
316  Array<LO> lFineNodesPerDir(3);
317  if (currentLevel.GetLevelID() == 0) {
318  // On level 0, data is provided by applications and has no associated factory.
319  lFineNodesPerDir = currentLevel.Get<Array<LO> >("lNodesPerDim", NoFactory::get());
320  } else {
321  // On level > 0, data is provided directly by generating factories.
322  lFineNodesPerDir = Get<Array<LO> >(currentLevel, "lNodesPerDim");
323  }
324 
325  // Set lFineNodesPerDir to 1 for directions beyond numDimensions
326  for (int dim = numDimensions; dim < 3; ++dim) {
327  lFineNodesPerDir[dim] = 1;
328  }
329 
330  // Now that we have extracted info from the level, create the IndexManager
332  geoData = rcp(new MueLu::UncoupledIndexManager<LO, GO, NO>(fineMap->getComm(),
333  false,
334  numDimensions,
335  interpolationOrder,
336  myRank,
337  numRanks,
338  Array<GO>(3, -1),
339  lFineNodesPerDir,
340  coarseRate, false));
341 
342  TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getLocalNumElements() != static_cast<size_t>(geoData->getNumLocalFineNodes()),
344  "The local number of elements in the graph's map is not equal to "
345  "the number of nodes given by: lNodesPerDim!");
346 
347  aggregates->SetIndexManager(geoData);
348  aggregates->SetNumAggregates(geoData->getNumLocalCoarseNodes());
349 
350  Set(currentLevel, "lCoarseNodesPerDim", geoData->getLocalCoarseNodesPerDir());
351 
352  } // end structured aggregation setup
353 
354  if (regionType == "uncoupled") {
355  // Add unstructred aggregation phases
356  algos_.push_back(rcp(new PreserveDirichletAggregationAlgorithm(graphFact)));
357  if (pL.get<bool>("aggregation: use interface aggregation") == true) algos_.push_back(rcp(new InterfaceAggregationAlgorithm(graphFact)));
358  if (pL.get<bool>("aggregation: allow user-specified singletons") == true) algos_.push_back(rcp(new OnePtAggregationAlgorithm(graphFact)));
359  if (pL.get<bool>("aggregation: enable phase 1") == true) algos_.push_back(rcp(new AggregationPhase1Algorithm(graphFact)));
360  if (pL.get<bool>("aggregation: enable phase 2a") == true) algos_.push_back(rcp(new AggregationPhase2aAlgorithm(graphFact)));
361  if (pL.get<bool>("aggregation: enable phase 2b") == true) algos_.push_back(rcp(new AggregationPhase2bAlgorithm(graphFact)));
362  if (pL.get<bool>("aggregation: enable phase 3") == true) algos_.push_back(rcp(new AggregationPhase3Algorithm(graphFact)));
363 
364  *out << " Build interface aggregates" << std::endl;
365  // interface
366  if (pL.get<bool>("aggregation: use interface aggregation") == true) {
367  BuildInterfaceAggregates(currentLevel, aggregates, aggStat, numNonAggregatedNodes,
368  coarseRate);
369  }
370 
371  *out << "Treat Dirichlet BC" << std::endl;
372  // Dirichlet boundary
373  auto dirichletBoundaryMap = graph->GetBoundaryNodeMap();
374  for (LO i = 0; i < numRows; i++)
375  if (dirichletBoundaryMap[i] == true)
376  aggStat[i] = BOUNDARY;
377 
378  // OnePt aggregation
379  std::string mapOnePtName = pL.get<std::string>("OnePt aggregate map name");
380  RCP<Map> OnePtMap = Teuchos::null;
381  if (mapOnePtName.length()) {
382  std::string mapOnePtFactName = pL.get<std::string>("OnePt aggregate map factory");
383  if (mapOnePtFactName == "" || mapOnePtFactName == "NoFactory") {
384  OnePtMap = currentLevel.Get<RCP<Map> >(mapOnePtName, NoFactory::get());
385  } else {
386  RCP<const FactoryBase> mapOnePtFact = GetFactory(mapOnePtFactName);
387  OnePtMap = currentLevel.Get<RCP<Map> >(mapOnePtName, mapOnePtFact.get());
388  }
389  }
390 
391  LO nDofsPerNode = Get<LO>(currentLevel, "DofsPerNode");
392  GO indexBase = graph->GetDomainMap()->getIndexBase();
393  if (OnePtMap != Teuchos::null) {
394  for (LO i = 0; i < numRows; i++) {
395  // reconstruct global row id (FIXME only works for contiguous maps)
396  GO grid = (graph->GetDomainMap()->getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
397  for (LO kr = 0; kr < nDofsPerNode; kr++)
398  if (OnePtMap->isNodeGlobalElement(grid + kr))
399  aggStat[i] = ONEPT;
400  }
401  }
402 
403  // Create a fake lCoarseNodesPerDir for CoordinatesTranferFactory
404  Array<LO> lCoarseNodesPerDir(3, -1);
405  Set(currentLevel, "lCoarseNodesPerDim", lCoarseNodesPerDir);
406  } // end uncoupled aggregation setup
407 
408  aggregates->AggregatesCrossProcessors(false); // No coupled aggregation
409 
410  *out << "Run all the algorithms on the local rank" << std::endl;
411  for (size_t a = 0; a < algos_.size(); a++) {
412  std::string phase = algos_[a]->description();
413  SubFactoryMonitor sfm(*this, "Algo \"" + phase + "\"", currentLevel);
414  *out << regionType << " | Executing phase " << a << std::endl;
415 
416  int oldRank = algos_[a]->SetProcRankVerbose(this->GetProcRankVerbose());
417  algos_[a]->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStat, numNonAggregatedNodes);
418  algos_[a]->SetProcRankVerbose(oldRank);
419  *out << regionType << " | Done Executing phase " << a << std::endl;
420  }
421 
422  *out << "Compute statistics on aggregates" << std::endl;
423  aggregates->ComputeAggregateSizes(true /*forceRecompute*/);
424 
425  Set(currentLevel, "Aggregates", aggregates);
426  Set(currentLevel, "numDimensions", numDimensions);
427  Set(currentLevel, "aggregationRegionTypeCoarse", regionType);
428 
429  GetOStream(Statistics1) << aggregates->description() << std::endl;
430  *out << "HybridAggregation done!" << std::endl;
431 }
432 
433 template <class LocalOrdinal, class GlobalOrdinal, class Node>
437  Array<LO> coarseRate) const {
438  FactoryMonitor m(*this, "BuildInterfaceAggregates", currentLevel);
439 
441  if (const char* dbg = std::getenv("MUELU_HYBRIDAGGREGATION_DEBUG")) {
442  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
443  out->setShowAllFrontMatter(false).setShowProcRank(true);
444  } else {
445  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
446  }
447 
448  // Extract and format input data for algo
449  if (coarseRate.size() == 1) {
450  coarseRate.resize(3, coarseRate[0]);
451  }
452  ArrayRCP<LO> vertex2AggId = aggregates->GetVertex2AggId()->getDataNonConst(0);
453  ArrayRCP<LO> procWinner = aggregates->GetProcWinner()->getDataNonConst(0);
454  Array<LO> interfacesDimensions = Get<Array<LO> >(currentLevel, "interfacesDimensions");
455  Array<LO> nodesOnInterfaces = Get<Array<LO> >(currentLevel, "nodeOnInterface");
456  const int numInterfaces = interfacesDimensions.size() / 3;
457  const int myRank = aggregates->GetMap()->getComm()->getRank();
458 
459  // Create coarse level container to gather data on the fly
460  Array<LO> coarseInterfacesDimensions(interfacesDimensions.size());
461  Array<LO> nodesOnCoarseInterfaces;
462  { // Scoping the temporary variables...
463  LO endRate, totalNumCoarseNodes = 0, numCoarseNodes;
464  for (int interfaceIdx = 0; interfaceIdx < numInterfaces; ++interfaceIdx) {
465  numCoarseNodes = 1;
466  for (int dim = 0; dim < 3; ++dim) {
467  endRate = (interfacesDimensions[3 * interfaceIdx + dim] - 1) % coarseRate[dim];
468  if (interfacesDimensions[3 * interfaceIdx + dim] == 1) {
469  coarseInterfacesDimensions[3 * interfaceIdx + dim] = 1;
470  } else {
471  coarseInterfacesDimensions[3 * interfaceIdx + dim] = (interfacesDimensions[3 * interfaceIdx + dim] - 1) / coarseRate[dim] + 2;
472  if (endRate == 0) {
473  coarseInterfacesDimensions[3 * interfaceIdx + dim]--;
474  }
475  }
476  numCoarseNodes *= coarseInterfacesDimensions[3 * interfaceIdx + dim];
477  }
478  totalNumCoarseNodes += numCoarseNodes;
479  }
480  nodesOnCoarseInterfaces.resize(totalNumCoarseNodes, -1);
481  }
482 
483  Array<LO> endRate(3);
484  LO interfaceOffset = 0, aggregateCount = 0, coarseNodeCount = 0;
485  for (int interfaceIdx = 0; interfaceIdx < numInterfaces; ++interfaceIdx) {
486  ArrayView<LO> fineNodesPerDim = interfacesDimensions(3 * interfaceIdx, 3);
487  ArrayView<LO> coarseNodesPerDim = coarseInterfacesDimensions(3 * interfaceIdx, 3);
488  LO numInterfaceNodes = 1, numCoarseNodes = 1;
489  for (int dim = 0; dim < 3; ++dim) {
490  numInterfaceNodes *= fineNodesPerDim[dim];
491  numCoarseNodes *= coarseNodesPerDim[dim];
492  endRate[dim] = (fineNodesPerDim[dim] - 1) % coarseRate[dim];
493  }
494  ArrayView<LO> interfaceNodes = nodesOnInterfaces(interfaceOffset, numInterfaceNodes);
495 
496  interfaceOffset += numInterfaceNodes;
497 
498  LO rem, rate, fineNodeIdx;
499  Array<LO> nodeIJK(3), coarseIJK(3), rootIJK(3);
500  // First find treat coarse nodes as they generate the aggregate IDs
501  // and they might be repeated on multiple interfaces (think corners and edges).
502  for (LO coarseNodeIdx = 0; coarseNodeIdx < numCoarseNodes; ++coarseNodeIdx) {
503  coarseIJK[2] = coarseNodeIdx / (coarseNodesPerDim[0] * coarseNodesPerDim[1]);
504  rem = coarseNodeIdx % (coarseNodesPerDim[0] * coarseNodesPerDim[1]);
505  coarseIJK[1] = rem / coarseNodesPerDim[0];
506  coarseIJK[0] = rem % coarseNodesPerDim[0];
507 
508  for (LO dim = 0; dim < 3; ++dim) {
509  if (coarseIJK[dim] == coarseNodesPerDim[dim] - 1) {
510  nodeIJK[dim] = fineNodesPerDim[dim] - 1;
511  } else {
512  nodeIJK[dim] = coarseIJK[dim] * coarseRate[dim];
513  }
514  }
515  fineNodeIdx = (nodeIJK[2] * fineNodesPerDim[1] + nodeIJK[1]) * fineNodesPerDim[0] + nodeIJK[0];
516 
517  if (aggStat[interfaceNodes[fineNodeIdx]] == READY) {
518  vertex2AggId[interfaceNodes[fineNodeIdx]] = aggregateCount;
519  procWinner[interfaceNodes[fineNodeIdx]] = myRank;
520  aggStat[interfaceNodes[fineNodeIdx]] = AGGREGATED;
521  ++aggregateCount;
522  --numNonAggregatedNodes;
523  }
524  nodesOnCoarseInterfaces[coarseNodeCount] = vertex2AggId[interfaceNodes[fineNodeIdx]];
525  ++coarseNodeCount;
526  }
527 
528  // Now loop over all the node on the interface
529  // skip the coarse nodes as they are already aggregated
530  // and find the appropriate aggregate ID for the fine nodes.
531  for (LO nodeIdx = 0; nodeIdx < numInterfaceNodes; ++nodeIdx) {
532  // If the node is already aggregated skip it!
533  if (aggStat[interfaceNodes[nodeIdx]] == AGGREGATED) {
534  continue;
535  }
536 
537  nodeIJK[2] = nodeIdx / (fineNodesPerDim[0] * fineNodesPerDim[1]);
538  rem = nodeIdx % (fineNodesPerDim[0] * fineNodesPerDim[1]);
539  nodeIJK[1] = rem / fineNodesPerDim[0];
540  nodeIJK[0] = rem % fineNodesPerDim[0];
541 
542  for (int dim = 0; dim < 3; ++dim) {
543  coarseIJK[dim] = nodeIJK[dim] / coarseRate[dim];
544  rem = nodeIJK[dim] % coarseRate[dim];
545  if (nodeIJK[dim] < fineNodesPerDim[dim] - endRate[dim]) {
546  rate = coarseRate[dim];
547  } else {
548  rate = endRate[dim];
549  }
550  if (rem > (rate / 2)) {
551  ++coarseIJK[dim];
552  }
553  }
554 
555  for (LO dim = 0; dim < 3; ++dim) {
556  if (coarseIJK[dim] == coarseNodesPerDim[dim] - 1) {
557  nodeIJK[dim] = fineNodesPerDim[dim] - 1;
558  } else {
559  nodeIJK[dim] = coarseIJK[dim] * coarseRate[dim];
560  }
561  }
562  fineNodeIdx = (nodeIJK[2] * fineNodesPerDim[1] + nodeIJK[1]) * fineNodesPerDim[0] + nodeIJK[0];
563 
564  vertex2AggId[interfaceNodes[nodeIdx]] = vertex2AggId[interfaceNodes[fineNodeIdx]];
565  procWinner[interfaceNodes[nodeIdx]] = myRank;
566  aggStat[interfaceNodes[nodeIdx]] = AGGREGATED;
567  --numNonAggregatedNodes;
568  } // Loop over interface nodes
569  } // Loop over the interfaces
570 
571  // Update aggregates information before subsequent aggregation algorithms
572  aggregates->SetNumAggregates(aggregateCount);
573 
574  // Set coarse data for next level
575  Set(currentLevel, "coarseInterfacesDimensions", coarseInterfacesDimensions);
576  Set(currentLevel, "nodeOnCoarseInterface", nodesOnCoarseInterfaces);
577 
578 } // BuildInterfaceAggregates()
579 
580 } // namespace MueLu
581 
582 #endif /* MUELU_HYBRIDAGGREGATIONFACTORY_DEF_HPP */
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
basic_FancyOStream & setProcRankAndSize(const int procRank, const int numProcs)
Algorithm for coarsening a graph with uncoupled aggregation. keep special marked nodes as singleton n...
const RCP< LOVector > & GetProcWinner() const
Returns constant vector that maps local node IDs to owning processor IDs.
Container class for aggregation information.
void setValidator(RCP< const ParameterEntryValidator > const &validator)
basic_FancyOStream & setShowProcRank(const bool showProcRank)
GlobalOrdinal GO
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Algorithm for coarsening a graph with structured aggregation.
Print more statistics.
void BuildInterfaceAggregates(Level &currentLevel, RCP< Aggregates > aggregates, typename AggregationAlgorithmBase< LocalOrdinal, GlobalOrdinal, Node >::AggStatHostType &aggStat, LO &numNonAggregatedNodes, Array< LO > coarseRate) const
Specifically build aggregates along interfaces.
const RCP< const Map > GetMap() const
returns (overlapping) map of aggregate/node distribution
LocalOrdinal LO
T * get() const
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
KOKKOS_INLINE_FUNCTION size_type GetNodeNumVertices() const
Return number of graph vertices.
KOKKOS_INLINE_FUNCTION const boundary_nodes_type GetBoundaryNodeMap() const
Returns map with global ids of boundary nodes.
void SetIndexManager(RCP< IndexManager > &geoData)
Set the index manager used by various aggregation algorithms. This has to be done by the aggregation ...
static const NoFactory * get()
Algorithm for coarsening a graph with uncoupled aggregation. creates aggregates along an interface us...
Builds one-to-one aggregates for all Dirichlet boundary nodes. For some applications this might be ne...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
virtual void setObjectLabel(const std::string &objectLabel)
basic_FancyOStream & setShowAllFrontMatter(const bool showAllFrontMatter)
const RCP< LOMultiVector > & GetVertex2AggId() const
Returns constant vector that maps local node IDs to local aggregates IDs.
void resize(size_type new_size, const value_type &x=value_type())
const RCP< const Map > GetImportMap() const
Return overlapping import map (nodes).
void Build(Level &currentLevel) const
Build aggregates.
Among unaggregated points, see if we can make a reasonable size aggregate out of it.IdeaAmong unaggregated points, see if we can make a reasonable size aggregate out of it. We do this by looking at neighbors and seeing how many are unaggregated and on my processor. Loosely, base the number of new aggregates created on the percentage of unaggregated nodes.
size_type size() const
Add leftovers to existing aggregatesIdeaIn phase 2b non-aggregated nodes are added to existing aggreg...
void DeclareInput(Level &currentLevel) const
Input.
const RCP< const Map > GetDomainMap() const
KOKKOS_INLINE_FUNCTION void AggregatesCrossProcessors(const bool &flag)
Record whether aggregates include DOFs from other processes.
Algorithm for coarsening a graph with uncoupled aggregation.
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
Exception throws to report errors in the internal logical of the program.
Handle leftover nodes. Try to avoid singleton nodesIdeaIn phase 3 we try to stick unaggregated nodes ...
#define SET_VALID_ENTRY(name)
ParameterEntry & getEntry(const std::string &name)
std::string description() const
Return a simple one-line description of this object.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
aggregates_sizes_type::const_type ComputeAggregateSizes(bool forceRecompute=false) const
Compute sizes of aggregates.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need&#39;s value has been saved.
void SetNumAggregates(LO nAggregates)
Set number of local aggregates on current processor.