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