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 // ***********************************************************************
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_STRUCTUREDAGGREGATIONFACTORY_DEF_HPP_
47 #define MUELU_STRUCTUREDAGGREGATIONFACTORY_DEF_HPP_
48 
49 #include <Xpetra_Map.hpp>
50 #include <Xpetra_CrsGraph.hpp>
51 
52 #include "MueLu_AggregationStructuredAlgorithm.hpp"
53 #include "MueLu_Level.hpp"
54 #include "MueLu_LWGraph.hpp"
55 #include "MueLu_Aggregates.hpp"
56 #include "MueLu_MasterList.hpp"
57 #include "MueLu_Monitor.hpp"
58 #include "MueLu_UncoupledIndexManager.hpp"
59 #include "MueLu_LocalLexicographicIndexManager.hpp"
60 #include "MueLu_GlobalLexicographicIndexManager.hpp"
61 
63 
64 namespace MueLu {
65 
66 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
69  : bDefinitionPhase_(true) {}
70 
71 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
74  RCP<ParameterList> validParamList = rcp(new ParameterList());
75 
76 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
77  SET_VALID_ENTRY("aggregation: preserve Dirichlet points");
78  SET_VALID_ENTRY("aggregation: allow user-specified singletons");
79  SET_VALID_ENTRY("aggregation: error on nodes with no on-rank neighbors");
80  SET_VALID_ENTRY("aggregation: phase3 avoid singletons");
81 
82  // general variables needed in StructuredAggregationFactory
83  SET_VALID_ENTRY("aggregation: mesh layout");
84  SET_VALID_ENTRY("aggregation: mode");
85  SET_VALID_ENTRY("aggregation: output type");
86  SET_VALID_ENTRY("aggregation: coarsening rate");
87  SET_VALID_ENTRY("aggregation: coarsening order");
88 #undef SET_VALID_ENTRY
89  validParamList->set<RCP<const FactoryBase> >("Graph", Teuchos::null,
90  "Graph of the matrix after amalgamation but without dropping.");
91  validParamList->set<RCP<const FactoryBase> >("numDimensions", Teuchos::null,
92  "Number of spatial dimension provided by CoordinatesTransferFactory.");
93  validParamList->set<RCP<const FactoryBase> >("gNodesPerDim", Teuchos::null,
94  "Global number of nodes per spatial dimension provided by CoordinatesTransferFactory.");
95  validParamList->set<RCP<const FactoryBase> >("lNodesPerDim", Teuchos::null,
96  "Local number of nodes per spatial dimension provided by CoordinatesTransferFactory.");
97  validParamList->set<RCP<const FactoryBase> >("DofsPerNode", Teuchos::null,
98  "Generating factory for variable \'DofsPerNode\', usually the same as the \'Graph\' factory");
99  validParamList->set<const bool>("aggregation: single coarse point", false,
100  "Allows the aggreagtion process to reduce spacial dimensions to a single layer");
101 
102  return validParamList;
103 } // GetValidParameterList()
104 
105 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
107  DeclareInput(Level& currentLevel) const {
108  Input(currentLevel, "Graph");
109  Input(currentLevel, "DofsPerNode");
110 
111  ParameterList pL = GetParameterList();
112  std::string coupling = pL.get<std::string>("aggregation: mode");
113  const bool coupled = (coupling == "coupled" ? true : false);
114  if (coupled) {
115  // Request the global number of nodes per dimensions
116  if (currentLevel.GetLevelID() == 0) {
117  if (currentLevel.IsAvailable("gNodesPerDim", NoFactory::get())) {
118  currentLevel.DeclareInput("gNodesPerDim", NoFactory::get(), this);
119  } else {
120  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("gNodesPerDim", NoFactory::get()),
122  "gNodesPerDim was not provided by the user on level0!");
123  }
124  } else {
125  Input(currentLevel, "gNodesPerDim");
126  }
127  }
128 
129  // Request the local number of nodes per dimensions
130  if (currentLevel.GetLevelID() == 0) {
131  if (currentLevel.IsAvailable("numDimensions", NoFactory::get())) {
132  currentLevel.DeclareInput("numDimensions", NoFactory::get(), this);
133  } else {
134  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("numDimensions", NoFactory::get()),
136  "numDimensions was not provided by the user on level0!");
137  }
138  if (currentLevel.IsAvailable("lNodesPerDim", NoFactory::get())) {
139  currentLevel.DeclareInput("lNodesPerDim", NoFactory::get(), this);
140  } else {
141  TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.IsAvailable("lNodesPerDim", NoFactory::get()),
143  "lNodesPerDim was not provided by the user on level0!");
144  }
145  } else {
146  Input(currentLevel, "numDimensions");
147  Input(currentLevel, "lNodesPerDim");
148  }
149 } // DeclareInput()
150 
151 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
153  Build(Level& currentLevel) const {
154  FactoryMonitor m(*this, "Build", currentLevel);
155 
157  if (const char* dbg = std::getenv("MUELU_STRUCTUREDAGGREGATION_DEBUG")) {
158  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
159  out->setShowAllFrontMatter(false).setShowProcRank(true);
160  } else {
161  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
162  }
163 
164  *out << "Entering structured aggregation" << std::endl;
165 
166  ParameterList pL = GetParameterList();
167  bDefinitionPhase_ = false; // definition phase is finished, now all aggregation algorithm information is fixed
168 
169  // General problem informations are gathered from data stored in the problem matix.
170  RCP<const LWGraph> graph = Get<RCP<LWGraph> >(currentLevel, "Graph");
171  RCP<const Map> fineMap = graph->GetDomainMap();
172  const int myRank = fineMap->getComm()->getRank();
173  const int numRanks = fineMap->getComm()->getSize();
174  const GO minGlobalIndex = fineMap->getMinGlobalIndex();
175  const LO dofsPerNode = Get<LO>(currentLevel, "DofsPerNode");
176 
177  // Since we want to operate on nodes and not dof, we need to modify the rowMap in order to
178  // obtain a nodeMap.
179  const int interpolationOrder = pL.get<int>("aggregation: coarsening order");
180  std::string meshLayout = pL.get<std::string>("aggregation: mesh layout");
181  std::string coupling = pL.get<std::string>("aggregation: mode");
182  const bool coupled = (coupling == "coupled" ? true : false);
183  std::string outputType = pL.get<std::string>("aggregation: output type");
184  const bool outputAggregates = (outputType == "Aggregates" ? true : false);
185  const bool singleCoarsePoint = pL.get<bool>("aggregation: single coarse point");
186  int numDimensions;
187  Array<GO> gFineNodesPerDir(3);
188  Array<LO> lFineNodesPerDir(3);
189  if (currentLevel.GetLevelID() == 0) {
190  // On level 0, data is provided by applications and has no associated factory.
191  numDimensions = currentLevel.Get<int>("numDimensions", NoFactory::get());
192  lFineNodesPerDir = currentLevel.Get<Array<LO> >("lNodesPerDim", NoFactory::get());
193  if (coupled) {
194  gFineNodesPerDir = currentLevel.Get<Array<GO> >("gNodesPerDim", NoFactory::get());
195  }
196  } else {
197  // On level > 0, data is provided directly by generating factories.
198  numDimensions = Get<int>(currentLevel, "numDimensions");
199  lFineNodesPerDir = Get<Array<LO> >(currentLevel, "lNodesPerDim");
200  if (coupled) {
201  gFineNodesPerDir = Get<Array<GO> >(currentLevel, "gNodesPerDim");
202  }
203  }
204 
205  // First make sure that input parameters are set logically based on dimension
206  for (int dim = 0; dim < 3; ++dim) {
207  if (dim >= numDimensions) {
208  gFineNodesPerDir[dim] = 1;
209  lFineNodesPerDir[dim] = 1;
210  }
211  }
212 
213  // Get the coarsening rate
214  std::string coarseningRate = pL.get<std::string>("aggregation: coarsening rate");
215  Teuchos::Array<LO> coarseRate;
216  try {
217  coarseRate = Teuchos::fromStringToArray<LO>(coarseningRate);
218  } catch (const Teuchos::InvalidArrayStringRepresentation& e) {
219  GetOStream(Errors, -1) << " *** \"aggregation: coarsening rate\" must be a string convertible into an array! *** "
220  << std::endl;
221  throw e;
222  }
223  TEUCHOS_TEST_FOR_EXCEPTION((coarseRate.size() > 1) && (coarseRate.size() < numDimensions),
225  "\"aggregation: coarsening rate\" must have at least as many"
226  " components as the number of spatial dimensions in the problem.");
227 
228  // Now that we have extracted info from the level, create the IndexManager
229  RCP<IndexManager> geoData;
230  if (!coupled) {
231  geoData = rcp(new MueLu::UncoupledIndexManager<LO, GO, NO>(fineMap->getComm(),
232  coupled,
233  numDimensions,
234  interpolationOrder,
235  myRank,
236  numRanks,
237  gFineNodesPerDir,
238  lFineNodesPerDir,
239  coarseRate,
240  singleCoarsePoint));
241  } else if (meshLayout == "Local Lexicographic") {
242  Array<GO> meshData;
243  if (currentLevel.GetLevelID() == 0) {
244  // On level 0, data is provided by applications and has no associated factory.
245  meshData = currentLevel.Get<Array<GO> >("aggregation: mesh data", NoFactory::get());
247  "The meshData array is empty, somehow the input for structured"
248  " aggregation are not captured correctly.");
249  } else {
250  // On level > 0, data is provided directly by generating factories.
251  meshData = Get<Array<GO> >(currentLevel, "aggregation: mesh data");
252  }
253  // Note, LBV Feb 5th 2018:
254  // I think that it might make sense to pass ghostInterface rather than interpolationOrder.
255  // For that I need to make sure that ghostInterface can be computed with minimal mesh
256  // knowledge outside of the IndexManager...
257  geoData = rcp(new MueLu::LocalLexicographicIndexManager<LO, GO, NO>(fineMap->getComm(),
258  coupled,
259  numDimensions,
260  interpolationOrder,
261  myRank,
262  numRanks,
263  gFineNodesPerDir,
264  lFineNodesPerDir,
265  coarseRate,
266  meshData));
267  } else if (meshLayout == "Global Lexicographic") {
268  // Note, LBV Feb 5th 2018:
269  // I think that it might make sense to pass ghostInterface rather than interpolationOrder.
270  // For that I need to make sure that ghostInterface can be computed with minimal mesh
271  // knowledge outside of the IndexManager...
272  geoData = rcp(new MueLu::GlobalLexicographicIndexManager<LO, GO, NO>(fineMap->getComm(),
273  coupled,
274  numDimensions,
275  interpolationOrder,
276  gFineNodesPerDir,
277  lFineNodesPerDir,
278  coarseRate,
279  minGlobalIndex));
280  }
281 
282  *out << "The index manager has now been built" << std::endl;
283  *out << "graph num nodes: " << fineMap->getLocalNumElements()
284  << ", structured aggregation num nodes: " << geoData->getNumLocalFineNodes() << std::endl;
285  TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getLocalNumElements() != static_cast<size_t>(geoData->getNumLocalFineNodes()),
287  "The local number of elements in the graph's map is not equal to "
288  "the number of nodes given by: lNodesPerDim!");
289  if (coupled) {
290  TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getGlobalNumElements() != static_cast<size_t>(geoData->getNumGlobalFineNodes()),
292  "The global number of elements in the graph's map is not equal to "
293  "the number of nodes given by: gNodesPerDim!");
294  }
295 
296  *out << "Compute coarse mesh data" << std::endl;
297  std::vector<std::vector<GO> > coarseMeshData = geoData->getCoarseMeshData();
298 
299  // Now we are ready for the big loop over the fine node that will assign each
300  // node on the fine grid to an aggregate and a processor.
301  RCP<const FactoryBase> graphFact = GetFactory("Graph");
302  RCP<const Map> coarseCoordinatesFineMap, coarseCoordinatesMap;
304  myStructuredAlgorithm = rcp(new AggregationStructuredAlgorithm(graphFact));
305 
306  if (interpolationOrder == 0 && outputAggregates) {
307  // Create aggregates for prolongation
308  *out << "Compute Aggregates" << std::endl;
309  RCP<Aggregates> aggregates = rcp(new Aggregates(graph->GetDomainMap()));
310  aggregates->setObjectLabel("ST");
311  aggregates->SetIndexManager(geoData);
312  aggregates->AggregatesCrossProcessors(coupled);
313  aggregates->SetNumAggregates(geoData->getNumLocalCoarseNodes());
315  AggStatHostType aggStat(Kokkos::ViewAllocateWithoutInitializing("aggregation status"), geoData->getNumLocalFineNodes());
316  Kokkos::deep_copy(aggStat, READY);
317  LO numNonAggregatedNodes = geoData->getNumLocalFineNodes();
318 
319  myStructuredAlgorithm->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStat,
320  numNonAggregatedNodes);
321 
323  "MueLu::StructuredAggregationFactory::Build: Leftover nodes found! Error!");
324  aggregates->ComputeAggregateSizes(true /*forceRecompute*/);
325  GetOStream(Statistics1) << aggregates->description() << std::endl;
326  Set(currentLevel, "Aggregates", aggregates);
327 
328  } else {
329  // Create the graph of the prolongator
330  *out << "Compute CrsGraph" << std::endl;
331  RCP<CrsGraph> myGraph;
332  myStructuredAlgorithm->BuildGraphOnHost(*graph, geoData, dofsPerNode, myGraph,
333  coarseCoordinatesFineMap, coarseCoordinatesMap);
334  Set(currentLevel, "prolongatorGraph", myGraph);
335  }
336 
337  if (coupled) {
338  Set(currentLevel, "gCoarseNodesPerDim", geoData->getGlobalCoarseNodesPerDir());
339  }
340  Set(currentLevel, "lCoarseNodesPerDim", geoData->getLocalCoarseNodesPerDir());
341  Set(currentLevel, "coarseCoordinatesFineMap", coarseCoordinatesFineMap);
342  Set(currentLevel, "coarseCoordinatesMap", coarseCoordinatesMap);
343  Set(currentLevel, "structuredInterpolationOrder", interpolationOrder);
344  Set(currentLevel, "numDimensions", numDimensions);
345 
346 } // Build()
347 } // namespace MueLu
348 
349 #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
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.
LocalOrdinal LO
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:99
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:76
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.