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.
AggregationStructuredAlgorithm(const RCP< const FactoryBase > &=Teuchos::null)
Constructor.
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.