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.
void Input(Level &level, const std::string &varName) const
T Get(Level &level, const std::string &varName) const
void Set(Level &level, const std::string &varName, const T &data) const
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory().
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()
virtual const Teuchos::ParameterList & GetParameterList() const
void Build(Level &currentLevel) const
Build aggregates.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
Namespace for MueLu classes and methods.
@ Statistics1
Print more statistics.