MueLu  Version of the Day
MueLu_UncoupledAggregationFactory_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_UNCOUPLEDAGGREGATIONFACTORY_DEF_HPP_
47 #define MUELU_UNCOUPLEDAGGREGATIONFACTORY_DEF_HPP_
48 
49 #include <climits>
50 
51 #include <Xpetra_Map.hpp>
52 #include <Xpetra_Vector.hpp>
53 #include <Xpetra_MultiVectorFactory.hpp>
54 #include <Xpetra_VectorFactory.hpp>
55 
57 
58 #include "MueLu_OnePtAggregationAlgorithm.hpp"
59 #include "MueLu_PreserveDirichletAggregationAlgorithm.hpp"
60 #include "MueLu_IsolatedNodeAggregationAlgorithm.hpp"
61 
62 #include "MueLu_AggregationPhase1Algorithm.hpp"
63 #include "MueLu_AggregationPhase2aAlgorithm.hpp"
64 #include "MueLu_AggregationPhase2bAlgorithm.hpp"
65 #include "MueLu_AggregationPhase3Algorithm.hpp"
66 
67 #include "MueLu_Level.hpp"
68 #include "MueLu_GraphBase.hpp"
69 #include "MueLu_Aggregates.hpp"
70 #include "MueLu_MasterList.hpp"
71 #include "MueLu_Monitor.hpp"
72 #include "MueLu_AmalgamationInfo.hpp"
73 #include "MueLu_Utilities.hpp"
74 
75 namespace MueLu {
76 
77  template <class LocalOrdinal, class GlobalOrdinal, class Node>
79  : bDefinitionPhase_(true)
80  { }
81 
82  template <class LocalOrdinal, class GlobalOrdinal, class Node>
84  RCP<ParameterList> validParamList = rcp(new ParameterList());
85 
86  // Aggregation parameters (used in aggregation algorithms)
87  // TODO introduce local member function for each aggregation algorithm such that each aggregation algorithm can define its own parameters
88 
89  typedef Teuchos::StringToIntegralParameterEntryValidator<int> validatorType;
90 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
91  SET_VALID_ENTRY("aggregation: max agg size");
92  SET_VALID_ENTRY("aggregation: min agg size");
93  SET_VALID_ENTRY("aggregation: max selected neighbors");
94  SET_VALID_ENTRY("aggregation: ordering");
95  validParamList->getEntry("aggregation: ordering").setValidator(
96  rcp(new validatorType(Teuchos::tuple<std::string>("natural", "graph", "random"), "aggregation: ordering")));
97  SET_VALID_ENTRY("aggregation: enable phase 1");
98  SET_VALID_ENTRY("aggregation: enable phase 2a");
99  SET_VALID_ENTRY("aggregation: enable phase 2b");
100  SET_VALID_ENTRY("aggregation: enable phase 3");
101  SET_VALID_ENTRY("aggregation: preserve Dirichlet points");
102  SET_VALID_ENTRY("aggregation: allow user-specified singletons");
103  SET_VALID_ENTRY("aggregation: error on nodes with no on-rank neighbors");
104 #undef SET_VALID_ENTRY
105 
106  // general variables needed in AggregationFactory
107  validParamList->set< RCP<const FactoryBase> >("Graph", null, "Generating factory of the graph");
108  validParamList->set< RCP<const FactoryBase> >("DofsPerNode", null, "Generating factory for variable \'DofsPerNode\', usually the same as for \'Graph\'");
109 
110  // special variables necessary for OnePtAggregationAlgorithm
111  validParamList->set< std::string > ("OnePt aggregate map name", "", "Name of input map for single node aggregates. (default='')");
112  validParamList->set< std::string > ("OnePt aggregate map factory", "", "Generating factory of (DOF) map for single node aggregates.");
113  //validParamList->set< RCP<const FactoryBase> >("OnePt aggregate map factory", NoFactory::getRCP(), "Generating factory of (DOF) map for single node aggregates.");
114 
115  return validParamList;
116  }
117 
118  template <class LocalOrdinal, class GlobalOrdinal, class Node>
120  Input(currentLevel, "Graph");
121  Input(currentLevel, "DofsPerNode");
122 
123  const ParameterList& pL = GetParameterList();
124 
125  // request special data necessary for OnePtAggregationAlgorithm
126  std::string mapOnePtName = pL.get<std::string>("OnePt aggregate map name");
127  if (mapOnePtName.length() > 0) {
128  std::string mapOnePtFactName = pL.get<std::string>("OnePt aggregate map factory");
129  if (mapOnePtFactName == "" || mapOnePtFactName == "NoFactory") {
130  currentLevel.DeclareInput(mapOnePtName, NoFactory::get());
131  } else {
132  RCP<const FactoryBase> mapOnePtFact = GetFactory(mapOnePtFactName);
133  currentLevel.DeclareInput(mapOnePtName, mapOnePtFact.get());
134  }
135  }
136  }
137 
138  template <class LocalOrdinal, class GlobalOrdinal, class Node>
140  FactoryMonitor m(*this, "Build", currentLevel);
141 
142  ParameterList pL = GetParameterList();
143  bDefinitionPhase_ = false; // definition phase is finished, now all aggregation algorithm information is fixed
144 
145  if (pL.get<int>("aggregation: max agg size") == -1)
146  pL.set("aggregation: max agg size", INT_MAX);
147 
148  // define aggregation algorithms
149  RCP<const FactoryBase> graphFact = GetFactory("Graph");
150 
151  // TODO Can we keep different aggregation algorithms over more Build calls?
152  algos_.clear();
153  algos_.push_back(rcp(new PreserveDirichletAggregationAlgorithm(graphFact)));
154  if (pL.get<bool>("aggregation: allow user-specified singletons") == true) algos_.push_back(rcp(new OnePtAggregationAlgorithm (graphFact)));
155  if (pL.get<bool>("aggregation: enable phase 1" ) == true) algos_.push_back(rcp(new AggregationPhase1Algorithm (graphFact)));
156  if (pL.get<bool>("aggregation: enable phase 2a") == true) algos_.push_back(rcp(new AggregationPhase2aAlgorithm (graphFact)));
157  if (pL.get<bool>("aggregation: enable phase 2b") == true) algos_.push_back(rcp(new AggregationPhase2bAlgorithm (graphFact)));
158  if (pL.get<bool>("aggregation: enable phase 3" ) == true) algos_.push_back(rcp(new AggregationPhase3Algorithm (graphFact)));
159 
160  // TODO: remove old aggregation mode
161  //if (pL.get<bool>("UseOnePtAggregationAlgorithm") == true) algos_.push_back(rcp(new OnePtAggregationAlgorithm (graphFact)));
162  //if (pL.get<bool>("UseUncoupledAggregationAlgorithm") == true) algos_.push_back(rcp(new AggregationPhase1Algorithm (graphFact)));
163  //if (pL.get<bool>("UseMaxLinkAggregationAlgorithm") == true) algos_.push_back(rcp(new MaxLinkAggregationAlgorithm (graphFact)));
164  //if (pL.get<bool>("UseEmergencyAggregationAlgorithm") == true) algos_.push_back(rcp(new EmergencyAggregationAlgorithm (graphFact)));
165 
166  std::string mapOnePtName = pL.get<std::string>("OnePt aggregate map name");
167  RCP<Map> OnePtMap = Teuchos::null;
168  if (mapOnePtName.length()) {
169  std::string mapOnePtFactName = pL.get<std::string>("OnePt aggregate map factory");
170  if (mapOnePtFactName == "" || mapOnePtFactName == "NoFactory") {
171  OnePtMap = currentLevel.Get<RCP<Map> >(mapOnePtName, NoFactory::get());
172  } else {
173  RCP<const FactoryBase> mapOnePtFact = GetFactory(mapOnePtFactName);
174  OnePtMap = currentLevel.Get<RCP<Map> >(mapOnePtName, mapOnePtFact.get());
175  }
176  }
177 
178  RCP<const GraphBase> graph = Get< RCP<GraphBase> >(currentLevel, "Graph");
179 
180  // Build
181  RCP<Aggregates> aggregates = rcp(new Aggregates(*graph));
182  aggregates->setObjectLabel("UC");
183 
184  const LO numRows = graph->GetNodeNumVertices();
185 
186  // construct aggStat information
187  std::vector<unsigned> aggStat(numRows, READY);
188 
189  ArrayRCP<const bool> dirichletBoundaryMap = graph->GetBoundaryNodeMap();
190  if (dirichletBoundaryMap != Teuchos::null)
191  for (LO i = 0; i < numRows; i++)
192  if (dirichletBoundaryMap[i] == true)
193  aggStat[i] = BOUNDARY;
194 
195  LO nDofsPerNode = Get<LO>(currentLevel, "DofsPerNode");
196  GO indexBase = graph->GetDomainMap()->getIndexBase();
197  if (OnePtMap != Teuchos::null) {
198  for (LO i = 0; i < numRows; i++) {
199  // reconstruct global row id (FIXME only works for contiguous maps)
200  GO grid = (graph->GetDomainMap()->getGlobalElement(i)-indexBase) * nDofsPerNode + indexBase;
201 
202  for (LO kr = 0; kr < nDofsPerNode; kr++)
203  if (OnePtMap->isNodeGlobalElement(grid + kr))
204  aggStat[i] = ONEPT;
205  }
206  }
207 
208 
209  const RCP<const Teuchos::Comm<int> > comm = graph->GetComm();
210  GO numGlobalRows = 0;
211  if (IsPrint(Statistics1))
212  MueLu_sumAll(comm, as<GO>(numRows), numGlobalRows);
213 
214  LO numNonAggregatedNodes = numRows;
215  GO numGlobalAggregatedPrev = 0, numGlobalAggsPrev = 0;
216  for (size_t a = 0; a < algos_.size(); a++) {
217  std::string phase = algos_[a]->description();
218  SubFactoryMonitor sfm(*this, "Algo \"" + phase + "\"", currentLevel);
219 
220  int oldRank = algos_[a]->SetProcRankVerbose(this->GetProcRankVerbose());
221  algos_[a]->BuildAggregates(pL, *graph, *aggregates, aggStat, numNonAggregatedNodes);
222  algos_[a]->SetProcRankVerbose(oldRank);
223 
224  if (IsPrint(Statistics1)) {
225  GO numLocalAggregated = numRows - numNonAggregatedNodes, numGlobalAggregated = 0;
226  GO numLocalAggs = aggregates->GetNumAggregates(), numGlobalAggs = 0;
227  MueLu_sumAll(comm, numLocalAggregated, numGlobalAggregated);
228  MueLu_sumAll(comm, numLocalAggs, numGlobalAggs);
229 
230  double aggPercent = 100*as<double>(numGlobalAggregated)/as<double>(numGlobalRows);
231  if (aggPercent > 99.99 && aggPercent < 100.00) {
232  // Due to round off (for instance, for 140465733/140466897), we could
233  // get 100.00% display even if there are some remaining nodes. This
234  // is bad from the users point of view. It is much better to change
235  // it to display 99.99%.
236  aggPercent = 99.99;
237  }
238  GetOStream(Statistics1) << " aggregated : " << (numGlobalAggregated - numGlobalAggregatedPrev) << " (phase), " << std::fixed
239  << std::setprecision(2) << numGlobalAggregated << "/" << numGlobalRows << " [" << aggPercent << "%] (total)\n"
240  << " remaining : " << numGlobalRows - numGlobalAggregated << "\n"
241  << " aggregates : " << numGlobalAggs-numGlobalAggsPrev << " (phase), " << numGlobalAggs << " (total)" << std::endl;
242  numGlobalAggregatedPrev = numGlobalAggregated;
243  numGlobalAggsPrev = numGlobalAggs;
244  }
245  }
246 
247  TEUCHOS_TEST_FOR_EXCEPTION(numNonAggregatedNodes, Exceptions::RuntimeError, "MueLu::UncoupledAggregationFactory::Build: Leftover nodes found! Error!");
248 
249  aggregates->AggregatesCrossProcessors(false);
250 
251  Set(currentLevel, "Aggregates", aggregates);
252 
253  GetOStream(Statistics1) << aggregates->description() << std::endl;
254  }
255 
256 } //namespace MueLu
257 
258 
259 #endif /* MUELU_UNCOUPLEDAGGREGATIONFACTORY_DEF_HPP_ */
std::vector< RCP< MueLu::AggregationAlgorithmBase< LocalOrdinal, GlobalOrdinal, Node > > > algos_
Append a new aggregation algorithm to list of aggregation algorithms.
Algorithm for coarsening a graph with uncoupled aggregation. keep special marked nodes as singleton n...
#define MueLu_sumAll(rcpComm, in, out)
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access). Usage: Level->Get< RCP<Matrix> >("A", factory) if factory == NULL => use default factory.
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
Container class for aggregation information.
Timer to be used in factories. Similar to Monitor but with additional timers.
Print more statistics.
void DeclareInput(Level &currentLevel) const
Input.
Namespace for MueLu classes and methods.
void Build(Level &currentLevel) const
Build aggregates.
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
static const NoFactory * get()
Builds one-to-one aggregates for all Dirichlet boundary nodes. For some applications this might be ne...
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
int GetProcRankVerbose() const
Get proc rank used for printing. Do not use this information for any other purpose.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
virtual const Teuchos::ParameterList & GetParameterList() const
#define SET_VALID_ENTRY(name)
Among unaggregated points, see if we can make a reasonable size aggregate out of it.IdeaAmong unaggregated points, see if we can make a reasonable size aggregate out of it. We do this by looking at neighbors and seeing how many are unaggregated and on my processor. Loosely, base the number of new aggregates created on the percentage of unaggregated nodes.
Add leftovers to existing aggregatesIdeaIn phase 2b non-aggregated nodes are added to existing aggreg...
void Input(Level &level, const std::string &varName) const
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory()
Algorithm for coarsening a graph with uncoupled aggregation.
Exception throws to report errors in the internal logical of the program.
Handle leftover nodes. Try to avoid singleton nodesIdeaIn phase 3 we try to stick unaggregated nodes ...
void Set(Level &level, const std::string &varName, const T &data) const
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()