MueLu Version of the Day
Loading...
Searching...
No Matches
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_GraphBase.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
64namespace MueLu {
65
66 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
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
156 RCP<Teuchos::FancyOStream> out;
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 GraphBase> graph = Get< RCP<GraphBase> >(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
206 // First make sure that input parameters are set logically based on dimension
207 for(int dim = 0; dim < 3; ++dim) {
208 if(dim >= numDimensions) {
209 gFineNodesPerDir[dim] = 1;
210 lFineNodesPerDir[dim] = 1;
211 }
212 }
213
214 // Get the coarsening rate
215 std::string coarseningRate = pL.get<std::string>("aggregation: coarsening rate");
216 Teuchos::Array<LO> coarseRate;
217 try {
218 coarseRate = Teuchos::fromStringToArray<LO>(coarseningRate);
219 } catch(const Teuchos::InvalidArrayStringRepresentation& e) {
220 GetOStream(Errors,-1) << " *** \"aggregation: coarsening rate\" must be a string convertible into an array! *** "
221 << std::endl;
222 throw e;
223 }
224 TEUCHOS_TEST_FOR_EXCEPTION((coarseRate.size() > 1) && (coarseRate.size() < numDimensions),
226 "\"aggregation: coarsening rate\" must have at least as many"
227 " components as the number of spatial dimensions in the problem.");
228
229 // Now that we have extracted info from the level, create the IndexManager
230 RCP<IndexManager > geoData;
231 if(!coupled) {
232 geoData = rcp(new MueLu::UncoupledIndexManager<LO,GO,NO>(fineMap->getComm(),
233 coupled,
234 numDimensions,
235 interpolationOrder,
236 myRank,
237 numRanks,
238 gFineNodesPerDir,
239 lFineNodesPerDir,
240 coarseRate,
241 singleCoarsePoint));
242 } else if(meshLayout == "Local Lexicographic") {
243 Array<GO> meshData;
244 if(currentLevel.GetLevelID() == 0) {
245 // On level 0, data is provided by applications and has no associated factory.
246 meshData = currentLevel.Get<Array<GO> >("aggregation: mesh data", NoFactory::get());
247 TEUCHOS_TEST_FOR_EXCEPTION(meshData.empty() == true, Exceptions::RuntimeError,
248 "The meshData array is empty, somehow the input for structured"
249 " aggregation are not captured correctly.");
250 } else {
251 // On level > 0, data is provided directly by generating factories.
252 meshData = Get<Array<GO> >(currentLevel, "aggregation: mesh data");
253 }
254 // Note, LBV Feb 5th 2018:
255 // I think that it might make sense to pass ghostInterface rather than interpolationOrder.
256 // For that I need to make sure that ghostInterface can be computed with minimal mesh
257 // knowledge outside of the IndexManager...
258 geoData = rcp(new MueLu::LocalLexicographicIndexManager<LO,GO,NO>(fineMap->getComm(),
259 coupled,
260 numDimensions,
261 interpolationOrder,
262 myRank,
263 numRanks,
264 gFineNodesPerDir,
265 lFineNodesPerDir,
266 coarseRate,
267 meshData));
268 } else if(meshLayout == "Global Lexicographic") {
269 // Note, LBV Feb 5th 2018:
270 // I think that it might make sense to pass ghostInterface rather than interpolationOrder.
271 // For that I need to make sure that ghostInterface can be computed with minimal mesh
272 // knowledge outside of the IndexManager...
273 geoData = rcp(new MueLu::GlobalLexicographicIndexManager<LO,GO,NO>(fineMap->getComm(),
274 coupled,
275 numDimensions,
276 interpolationOrder,
277 gFineNodesPerDir,
278 lFineNodesPerDir,
279 coarseRate,
280 minGlobalIndex));
281 }
282
283
284 *out << "The index manager has now been built" << std::endl;
285 *out << "graph num nodes: " << fineMap->getLocalNumElements()
286 << ", structured aggregation num nodes: " << geoData->getNumLocalFineNodes() << std::endl;
287 TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getLocalNumElements()
288 != static_cast<size_t>(geoData->getNumLocalFineNodes()),
290 "The local number of elements in the graph's map is not equal to "
291 "the number of nodes given by: lNodesPerDim!");
292 if(coupled) {
293 TEUCHOS_TEST_FOR_EXCEPTION(fineMap->getGlobalNumElements()
294 != static_cast<size_t>(geoData->getNumGlobalFineNodes()),
296 "The global number of elements in the graph's map is not equal to "
297 "the number of nodes given by: gNodesPerDim!");
298 }
299
300 *out << "Compute coarse mesh data" << std::endl;
301 std::vector<std::vector<GO> > coarseMeshData = geoData->getCoarseMeshData();
302
303 // Now we are ready for the big loop over the fine node that will assign each
304 // node on the fine grid to an aggregate and a processor.
305 RCP<const FactoryBase> graphFact = GetFactory("Graph");
306 RCP<const Map> coarseCoordinatesFineMap, coarseCoordinatesMap;
307 RCP<MueLu::AggregationStructuredAlgorithm<LocalOrdinal, GlobalOrdinal, Node> >
308 myStructuredAlgorithm = rcp(new AggregationStructuredAlgorithm(graphFact));
309
310 if(interpolationOrder == 0 && outputAggregates){
311 // Create aggregates for prolongation
312 *out << "Compute Aggregates" << std::endl;
313 RCP<Aggregates> aggregates = rcp(new Aggregates(graph->GetDomainMap()));
314 aggregates->setObjectLabel("ST");
315 aggregates->SetIndexManager(geoData);
316 aggregates->AggregatesCrossProcessors(coupled);
317 aggregates->SetNumAggregates(geoData->getNumLocalCoarseNodes());
318 std::vector<unsigned> aggStat(geoData->getNumLocalFineNodes(), READY);
319 LO numNonAggregatedNodes = geoData->getNumLocalFineNodes();
320
321 myStructuredAlgorithm->BuildAggregates(pL, *graph, *aggregates, aggStat,
322 numNonAggregatedNodes);
323
324 TEUCHOS_TEST_FOR_EXCEPTION(numNonAggregatedNodes, Exceptions::RuntimeError,
325 "MueLu::StructuredAggregationFactory::Build: Leftover nodes found! Error!");
326 aggregates->ComputeAggregateSizes(true/*forceRecompute*/);
327 GetOStream(Statistics1) << aggregates->description() << std::endl;
328 Set(currentLevel, "Aggregates", aggregates);
329
330 } else {
331 // Create the graph of the prolongator
332 *out << "Compute CrsGraph" << std::endl;
333 RCP<CrsGraph> myGraph;
334 myStructuredAlgorithm->BuildGraph(*graph, geoData, dofsPerNode, myGraph,
335 coarseCoordinatesFineMap, coarseCoordinatesMap);
336 Set(currentLevel, "prolongatorGraph", myGraph);
337 }
338
339 if(coupled) {
340 Set(currentLevel, "gCoarseNodesPerDim", geoData->getGlobalCoarseNodesPerDir());
341 }
342 Set(currentLevel, "lCoarseNodesPerDim", geoData->getLocalCoarseNodesPerDir());
343 Set(currentLevel, "coarseCoordinatesFineMap", coarseCoordinatesFineMap);
344 Set(currentLevel, "coarseCoordinatesMap", coarseCoordinatesMap);
345 Set(currentLevel, "structuredInterpolationOrder", interpolationOrder);
346 Set(currentLevel, "numDimensions", numDimensions);
347
348 } // Build()
349} //namespace MueLu
350
351
352#endif /* MUELU_STRUCTUREDAGGREGATIONFACTORY_DEF_HPP_ */
#define SET_VALID_ENTRY(name)
Container class for aggregation information.
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.
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().
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.