MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_StructuredAggregationFactory_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_STRUCTUREDAGGREGATIONFACTORY_DEF_HPP_
11 #define MUELU_STRUCTUREDAGGREGATIONFACTORY_DEF_HPP_
12 
13 #include <Xpetra_Map.hpp>
14 #include <Xpetra_CrsGraph.hpp>
15 
16 #include "MueLu_AggregationStructuredAlgorithm.hpp"
17 #include "MueLu_Level.hpp"
18 #include "MueLu_LWGraph.hpp"
19 #include "MueLu_Aggregates.hpp"
20 #include "MueLu_MasterList.hpp"
21 #include "MueLu_Monitor.hpp"
22 #include "MueLu_UncoupledIndexManager.hpp"
23 #include "MueLu_LocalLexicographicIndexManager.hpp"
24 #include "MueLu_GlobalLexicographicIndexManager.hpp"
25 
27 
28 namespace MueLu {
29 
30 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
33  : bDefinitionPhase_(true) {}
34 
35 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
38  RCP<ParameterList> validParamList = rcp(new ParameterList());
39 
40 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
41  SET_VALID_ENTRY("aggregation: preserve Dirichlet points");
42  SET_VALID_ENTRY("aggregation: allow user-specified singletons");
43  SET_VALID_ENTRY("aggregation: error on nodes with no on-rank neighbors");
44  SET_VALID_ENTRY("aggregation: phase3 avoid singletons");
45 
46  // general variables needed in StructuredAggregationFactory
47  SET_VALID_ENTRY("aggregation: mesh layout");
48  SET_VALID_ENTRY("aggregation: mode");
49  SET_VALID_ENTRY("aggregation: output type");
50  SET_VALID_ENTRY("aggregation: coarsening rate");
51  SET_VALID_ENTRY("aggregation: coarsening order");
52 #undef SET_VALID_ENTRY
53  validParamList->set<RCP<const FactoryBase> >("Graph", Teuchos::null,
54  "Graph of the matrix after amalgamation but without dropping.");
55  validParamList->set<RCP<const FactoryBase> >("numDimensions", Teuchos::null,
56  "Number of spatial dimension provided by CoordinatesTransferFactory.");
57  validParamList->set<RCP<const FactoryBase> >("gNodesPerDim", Teuchos::null,
58  "Global number of nodes per spatial dimension provided by CoordinatesTransferFactory.");
59  validParamList->set<RCP<const FactoryBase> >("lNodesPerDim", Teuchos::null,
60  "Local number of nodes per spatial dimension provided by CoordinatesTransferFactory.");
61  validParamList->set<RCP<const FactoryBase> >("DofsPerNode", Teuchos::null,
62  "Generating factory for variable \'DofsPerNode\', usually the same as the \'Graph\' factory");
63  validParamList->set<const bool>("aggregation: single coarse point", false,
64  "Allows the aggreagtion process to reduce spacial dimensions to a single layer");
65 
66  return validParamList;
67 } // GetValidParameterList()
68 
69 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
71  DeclareInput(Level& currentLevel) const {
72  Input(currentLevel, "Graph");
73  Input(currentLevel, "DofsPerNode");
74 
75  ParameterList pL = GetParameterList();
76  std::string coupling = pL.get<std::string>("aggregation: mode");
77  const bool coupled = (coupling == "coupled" ? true : false);
78  if (coupled) {
79  // Request the global number of nodes per dimensions
80  if (currentLevel.GetLevelID() == 0) {
81  if (currentLevel.IsAvailable("gNodesPerDim", NoFactory::get())) {
82  currentLevel.DeclareInput("gNodesPerDim", NoFactory::get(), this);
83  } else {
84  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("gNodesPerDim", NoFactory::get()),
86  "gNodesPerDim was not provided by the user on level0!");
87  }
88  } else {
89  Input(currentLevel, "gNodesPerDim");
90  }
91  }
92 
93  // Request the local number of nodes per dimensions
94  if (currentLevel.GetLevelID() == 0) {
95  if (currentLevel.IsAvailable("numDimensions", NoFactory::get())) {
96  currentLevel.DeclareInput("numDimensions", NoFactory::get(), this);
97  } else {
98  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("numDimensions", NoFactory::get()),
100  "numDimensions was not provided by the user on level0!");
101  }
102  if (currentLevel.IsAvailable("lNodesPerDim", NoFactory::get())) {
103  currentLevel.DeclareInput("lNodesPerDim", NoFactory::get(), this);
104  } else {
105  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("lNodesPerDim", NoFactory::get()),
107  "lNodesPerDim was not provided by the user on level0!");
108  }
109  } else {
110  Input(currentLevel, "numDimensions");
111  Input(currentLevel, "lNodesPerDim");
112  }
113 } // DeclareInput()
114 
115 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
117  Build(Level& currentLevel) const {
118  FactoryMonitor m(*this, "Build", currentLevel);
119 
121  if (const char* dbg = std::getenv("MUELU_STRUCTUREDAGGREGATION_DEBUG")) {
122  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
123  out->setShowAllFrontMatter(false).setShowProcRank(true);
124  } else {
125  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
126  }
127 
128  *out << "Entering structured aggregation" << std::endl;
129 
130  ParameterList pL = GetParameterList();
131  bDefinitionPhase_ = false; // definition phase is finished, now all aggregation algorithm information is fixed
132 
133  // General problem informations are gathered from data stored in the problem matix.
134  RCP<const LWGraph> graph = Get<RCP<LWGraph> >(currentLevel, "Graph");
135  RCP<const Map> fineMap = graph->GetDomainMap();
136  const int myRank = fineMap->getComm()->getRank();
137  const int numRanks = fineMap->getComm()->getSize();
138  const GO minGlobalIndex = fineMap->getMinGlobalIndex();
139  const LO dofsPerNode = Get<LO>(currentLevel, "DofsPerNode");
140 
141  // Since we want to operate on nodes and not dof, we need to modify the rowMap in order to
142  // obtain a nodeMap.
143  const int interpolationOrder = pL.get<int>("aggregation: coarsening order");
144  std::string meshLayout = pL.get<std::string>("aggregation: mesh layout");
145  std::string coupling = pL.get<std::string>("aggregation: mode");
146  const bool coupled = (coupling == "coupled" ? true : false);
147  std::string outputType = pL.get<std::string>("aggregation: output type");
148  const bool outputAggregates = (outputType == "Aggregates" ? true : false);
149  const bool singleCoarsePoint = pL.get<bool>("aggregation: single coarse point");
150  int numDimensions;
151  Array<GO> gFineNodesPerDir(3);
152  Array<LO> lFineNodesPerDir(3);
153  if (currentLevel.GetLevelID() == 0) {
154  // On level 0, data is provided by applications and has no associated factory.
155  numDimensions = currentLevel.Get<int>("numDimensions", NoFactory::get());
156  lFineNodesPerDir = currentLevel.Get<Array<LO> >("lNodesPerDim", NoFactory::get());
157  if (coupled) {
158  gFineNodesPerDir = currentLevel.Get<Array<GO> >("gNodesPerDim", NoFactory::get());
159  }
160  } else {
161  // On level > 0, data is provided directly by generating factories.
162  numDimensions = Get<int>(currentLevel, "numDimensions");
163  lFineNodesPerDir = Get<Array<LO> >(currentLevel, "lNodesPerDim");
164  if (coupled) {
165  gFineNodesPerDir = Get<Array<GO> >(currentLevel, "gNodesPerDim");
166  }
167  }
168 
169  // First make sure that input parameters are set logically based on dimension
170  for (int dim = 0; dim < 3; ++dim) {
171  if (dim >= numDimensions) {
172  gFineNodesPerDir[dim] = 1;
173  lFineNodesPerDir[dim] = 1;
174  }
175  }
176 
177  // Get the coarsening rate
178  std::string coarseningRate = pL.get<std::string>("aggregation: coarsening rate");
179  Teuchos::Array<LO> coarseRate;
180  try {
181  coarseRate = Teuchos::fromStringToArray<LO>(coarseningRate);
182  } catch (const Teuchos::InvalidArrayStringRepresentation& e) {
183  GetOStream(Errors, -1) << " *** \"aggregation: coarsening rate\" must be a string convertible into an array! *** "
184  << std::endl;
185  throw e;
186  }
187  TEUCHOS_TEST_FOR_EXCEPTION((coarseRate.size() > 1) && (coarseRate.size() < numDimensions),
189  "\"aggregation: coarsening rate\" must have at least as many"
190  " components as the number of spatial dimensions in the problem.");
191 
192  // Now that we have extracted info from the level, create the IndexManager
193  RCP<IndexManager> geoData;
194  if (!coupled) {
195  geoData = rcp(new MueLu::UncoupledIndexManager<LO, GO, NO>(fineMap->getComm(),
196  coupled,
197  numDimensions,
198  interpolationOrder,
199  myRank,
200  numRanks,
201  gFineNodesPerDir,
202  lFineNodesPerDir,
203  coarseRate,
204  singleCoarsePoint));
205  } else if (meshLayout == "Local Lexicographic") {
206  Array<GO> meshData;
207  if (currentLevel.GetLevelID() == 0) {
208  // On level 0, data is provided by applications and has no associated factory.
209  meshData = currentLevel.Get<Array<GO> >("aggregation: mesh data", NoFactory::get());
211  "The meshData array is empty, somehow the input for structured"
212  " aggregation are not captured correctly.");
213  } else {
214  // On level > 0, data is provided directly by generating factories.
215  meshData = Get<Array<GO> >(currentLevel, "aggregation: mesh data");
216  }
217  // Note, LBV Feb 5th 2018:
218  // I think that it might make sense to pass ghostInterface rather than interpolationOrder.
219  // For that I need to make sure that ghostInterface can be computed with minimal mesh
220  // knowledge outside of the IndexManager...
221  geoData = rcp(new MueLu::LocalLexicographicIndexManager<LO, GO, NO>(fineMap->getComm(),
222  coupled,
223  numDimensions,
224  interpolationOrder,
225  myRank,
226  numRanks,
227  gFineNodesPerDir,
228  lFineNodesPerDir,
229  coarseRate,
230  meshData));
231  } else if (meshLayout == "Global Lexicographic") {
232  // Note, LBV Feb 5th 2018:
233  // I think that it might make sense to pass ghostInterface rather than interpolationOrder.
234  // For that I need to make sure that ghostInterface can be computed with minimal mesh
235  // knowledge outside of the IndexManager...
236  geoData = rcp(new MueLu::GlobalLexicographicIndexManager<LO, GO, NO>(fineMap->getComm(),
237  coupled,
238  numDimensions,
239  interpolationOrder,
240  gFineNodesPerDir,
241  lFineNodesPerDir,
242  coarseRate,
243  minGlobalIndex));
244  }
245 
246  *out << "The index manager has now been built" << std::endl;
247  *out << "graph num nodes: " << fineMap->getLocalNumElements()
248  << ", structured aggregation num nodes: " << geoData->getNumLocalFineNodes() << std::endl;
249  TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getLocalNumElements() != static_cast<size_t>(geoData->getNumLocalFineNodes()),
251  "The local number of elements in the graph's map is not equal to "
252  "the number of nodes given by: lNodesPerDim!");
253  if (coupled) {
254  TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getGlobalNumElements() != static_cast<size_t>(geoData->getNumGlobalFineNodes()),
256  "The global number of elements in the graph's map is not equal to "
257  "the number of nodes given by: gNodesPerDim!");
258  }
259 
260  *out << "Compute coarse mesh data" << std::endl;
261  std::vector<std::vector<GO> > coarseMeshData = geoData->getCoarseMeshData();
262 
263  // Now we are ready for the big loop over the fine node that will assign each
264  // node on the fine grid to an aggregate and a processor.
265  RCP<const FactoryBase> graphFact = GetFactory("Graph");
266  RCP<const Map> coarseCoordinatesFineMap, coarseCoordinatesMap;
268  myStructuredAlgorithm = rcp(new AggregationStructuredAlgorithm(graphFact));
269 
270  if (interpolationOrder == 0 && outputAggregates) {
271  // Create aggregates for prolongation
272  *out << "Compute Aggregates" << std::endl;
273  RCP<Aggregates> aggregates = rcp(new Aggregates(graph->GetDomainMap()));
274  aggregates->setObjectLabel("ST");
275  aggregates->SetIndexManager(geoData);
276  aggregates->AggregatesCrossProcessors(coupled);
277  aggregates->SetNumAggregates(geoData->getNumLocalCoarseNodes());
279  AggStatHostType aggStat(Kokkos::ViewAllocateWithoutInitializing("aggregation status"), geoData->getNumLocalFineNodes());
280  Kokkos::deep_copy(aggStat, READY);
281  LO numNonAggregatedNodes = geoData->getNumLocalFineNodes();
282 
283  myStructuredAlgorithm->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStat,
284  numNonAggregatedNodes);
285 
287  "MueLu::StructuredAggregationFactory::Build: Leftover nodes found! Error!");
288  aggregates->ComputeAggregateSizes(true /*forceRecompute*/);
289  GetOStream(Statistics1) << aggregates->description() << std::endl;
290  Set(currentLevel, "Aggregates", aggregates);
291 
292  } else {
293  // Create the graph of the prolongator
294  *out << "Compute CrsGraph" << std::endl;
295  RCP<CrsGraph> myGraph;
296  myStructuredAlgorithm->BuildGraphOnHost(*graph, geoData, dofsPerNode, myGraph,
297  coarseCoordinatesFineMap, coarseCoordinatesMap);
298  Set(currentLevel, "prolongatorGraph", myGraph);
299  }
300 
301  if (coupled) {
302  Set(currentLevel, "gCoarseNodesPerDim", geoData->getGlobalCoarseNodesPerDir());
303  }
304  Set(currentLevel, "lCoarseNodesPerDim", geoData->getLocalCoarseNodesPerDir());
305  Set(currentLevel, "coarseCoordinatesFineMap", coarseCoordinatesFineMap);
306  Set(currentLevel, "coarseCoordinatesMap", coarseCoordinatesMap);
307  Set(currentLevel, "structuredInterpolationOrder", interpolationOrder);
308  Set(currentLevel, "numDimensions", numDimensions);
309 
310 } // Build()
311 } // namespace MueLu
312 
313 #endif /* MUELU_STRUCTUREDAGGREGATIONFACTORY_DEF_HPP_ */
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
Container class for aggregation information.
basic_FancyOStream & setShowProcRank(const bool showProcRank)
GlobalOrdinal GO
T & get(const std::string &name, T def_value)
bool empty() const
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.
LocalOrdinal LO
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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()
void DeclareInput(Level &currentLevel) const
Input.
Array< GO > getGlobalCoarseNodesPerDir() const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
virtual void setObjectLabel(const std::string &objectLabel)
basic_FancyOStream & setShowAllFrontMatter(const bool showAllFrontMatter)
virtual std::vector< std::vector< GO > > getCoarseMeshData() const =0
const RCP< const Map > GetDomainMap() const
KOKKOS_INLINE_FUNCTION void AggregatesCrossProcessors(const bool &flag)
Record whether aggregates include DOFs from other processes.
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:51
Exception throws to report errors in the internal logical of the program.
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()
void Build(Level &currentLevel) const
Build aggregates.
aggregates_sizes_type::const_type ComputeAggregateSizes(bool forceRecompute=false) const
Compute sizes of aggregates.
#define SET_VALID_ENTRY(name)
Array< LO > getLocalCoarseNodesPerDir() const
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.