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