MueLu Version of the Day
Loading...
Searching...
No Matches
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
28namespace MueLu {
29
30template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
34
35template <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
69template <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
115template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
117 Build(Level& currentLevel) const {
118 FactoryMonitor m(*this, "Build", currentLevel);
119
120 RCP<Teuchos::FancyOStream> out;
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());
210 TEUCHOS_TEST_FOR_EXCEPTION(meshData.empty() == true, Exceptions::RuntimeError,
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;
267 RCP<MueLu::AggregationStructuredAlgorithm<LocalOrdinal, GlobalOrdinal, Node> >
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
286 TEUCHOS_TEST_FOR_EXCEPTION(numNonAggregatedNodes, Exceptions::RuntimeError,
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_ */
#define SET_VALID_ENTRY(name)
Container class for aggregation information.
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
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.
Class that holds all level-specific information.
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.
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()
void Build(Level &currentLevel) const
Build aggregates.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
Namespace for MueLu classes and methods.
@ Statistics1
Print more statistics.