MueLu  Version of the Day
MueLu_ReitzingerPFactory_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_REITZINGERPFACTORY_DEF_HPP
47 #define MUELU_REITZINGERPFACTORY_DEF_HPP
48 
49 #include <Xpetra_MapFactory.hpp>
50 #include <Xpetra_Map.hpp>
51 #include <Xpetra_CrsMatrix.hpp>
52 #include <Xpetra_Matrix.hpp>
53 #include <Xpetra_MatrixMatrix.hpp>
54 #include <Xpetra_MultiVector.hpp>
55 #include <Xpetra_MultiVectorFactory.hpp>
56 #include <Xpetra_VectorFactory.hpp>
57 #include <Xpetra_Import.hpp>
58 #include <Xpetra_ImportUtils.hpp>
59 #include <Xpetra_ImportFactory.hpp>
60 #include <Xpetra_CrsMatrixWrap.hpp>
61 #include <Xpetra_StridedMap.hpp>
62 #include <Xpetra_StridedMapFactory.hpp>
63 #include <Xpetra_IO.hpp>
64 
66 
67 #include "MueLu_Aggregates.hpp"
68 #include "MueLu_AmalgamationFactory.hpp"
69 #include "MueLu_AmalgamationInfo.hpp"
70 #include "MueLu_CoarseMapFactory.hpp"
71 #include "MueLu_MasterList.hpp"
72 #include "MueLu_Monitor.hpp"
73 #include "MueLu_NullspaceFactory.hpp"
74 #include "MueLu_PerfUtils.hpp"
75 #include "MueLu_Utilities.hpp"
76 
77 namespace MueLu {
78 
79  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
81  RCP<ParameterList> validParamList = rcp(new ParameterList());
82 
83 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
84 
85 
86 #undef SET_VALID_ENTRY
87 
88  validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
89  validParamList->set< RCP<const FactoryBase> >("D0", Teuchos::null, "Generating factory of the matrix D0");
90  validParamList->set< RCP<const FactoryBase> >("NodeMatrix", Teuchos::null, "Generating factory of the matrix NodeMatrix");
91  validParamList->set< RCP<const FactoryBase> >("Pnodal", Teuchos::null, "Generating factory of the matrix P");
92 
93  // Make sure we don't recursively validate options for the matrixmatrix kernels
94  ParameterList norecurse;
95  norecurse.disableRecursiveValidation();
96  validParamList->set<ParameterList> ("matrixmatrix: kernel params", norecurse, "MatrixMatrix kernel parameters");
97 
98  return validParamList;
99  }
100 
101  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
103  Input(fineLevel, "A");
104  Input(fineLevel, "D0");
105  Input(fineLevel, "NodeMatrix");
106  Input(coarseLevel, "Pnodal");
107 
108  }
109 
110  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
112  return BuildP(fineLevel, coarseLevel);
113  }
114 
115  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
117  FactoryMonitor m(*this, "Build", coarseLevel);
118  using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
119  using XMM = Xpetra::MatrixMatrix<SC,LO,GO,NO>;
120  Teuchos::FancyOStream& out0=GetBlackHole();
121  const ParameterList& pL = GetParameterList();
122 
123  RCP<Matrix> EdgeMatrix = Get< RCP<Matrix> > (fineLevel, "A");
124  RCP<Matrix> D0 = Get< RCP<Matrix> > (fineLevel, "D0");
125  RCP<Matrix> NodeMatrix = Get< RCP<Matrix> > (fineLevel, "NodeMatrix");
126  RCP<Matrix> Pn = Get< RCP<Matrix> > (coarseLevel, "Pnodal");
127  const GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
128  const LO LO_INVALID = Teuchos::OrdinalTraits<LO>::invalid();
129  int MyPID = D0->getRowMap()->getComm()->getRank();
130 
131  // Matrix matrix params
132  RCP<ParameterList> mm_params = rcp(new ParameterList);;
133  if(pL.isSublist("matrixmatrix: kernel params"))
134  mm_params->sublist("matrixmatrix: kernel params") = pL.sublist("matrixmatrix: kernel params");
135 
136 
137  // TODO: We need to make sure Pn isn't normalized. Right now this has to be done explicitly by the user
138 
139  // TODO: We need to look through and see which of these really need importers and which ones don't
140 
141  /* Generate the Pn * D0 matrix and its transpose */
142  RCP<Matrix> D0_Pn, PnT_D0T, D0_Pn_nonghosted;
143  Teuchos::Array<int> D0_Pn_col_pids;
144  {
145  RCP<Matrix> dummy;
146  SubFactoryMonitor m2(*this, "Generate D0*Pn", coarseLevel);
147  D0_Pn = XMM::Multiply(*D0,false,*Pn,false,dummy,out0,true,true,"D0*Pn",mm_params);
148 
149  // Save this so we don't need to do the multiplication again later
150  D0_Pn_nonghosted = D0_Pn;
151 
152  // Get owning PID information on columns for tie-breaking
153  if(!D0_Pn->getCrsGraph()->getImporter().is_null()) {
154  Xpetra::ImportUtils<LO,GO,NO> utils;
155  utils.getPids(*D0_Pn->getCrsGraph()->getImporter(),D0_Pn_col_pids,false);
156  }
157  else {
158  D0_Pn_col_pids.resize(D0_Pn->getCrsGraph()->getColMap()->getNodeNumElements(),MyPID);
159  }
160  }
161 
162 
163  {
164  // Get the transpose
165  SubFactoryMonitor m2(*this, "Transpose D0*Pn", coarseLevel);
166  PnT_D0T = Utilities::Transpose(*D0_Pn, true);
167  }
168 
169  // We really need a ghosted version of D0_Pn here.
170  // The reason is that if there's only one fine edge between two coarse nodes, somebody is going
171  // to own the associated coarse edge. The sum/sign rule doesn't guarantee the fine owner is the coarse owner.
172  // So you can wind up with a situation that only guy who *can* register the coarse edge isn't the sum/sign
173  // owner. Adding more ghosting fixes that.
174  if(!PnT_D0T->getCrsGraph()->getImporter().is_null()) {
175  RCP<const Import> Importer = PnT_D0T->getCrsGraph()->getImporter();
176  RCP<const CrsMatrix> D0_Pn_crs = rcp_dynamic_cast<const CrsMatrixWrap>(D0_Pn)->getCrsMatrix();
177  RCP<Matrix> D0_Pn_new = rcp(new CrsMatrixWrap(CrsMatrixFactory::Build(D0_Pn_crs,*Importer,D0_Pn->getDomainMap(),Importer->getTargetMap())));
178  D0_Pn = D0_Pn_new;
179  // Get owning PID information on columns for tie-breaking
180  if(!D0_Pn->getCrsGraph()->getImporter().is_null()) {
181  Xpetra::ImportUtils<LO,GO,NO> utils;
182  utils.getPids(*D0_Pn->getCrsGraph()->getImporter(),D0_Pn_col_pids,false);
183  }
184  else {
185  D0_Pn_col_pids.resize(D0_Pn->getCrsGraph()->getColMap()->getNodeNumElements(),MyPID);
186  }
187  }
188 
189 
190  // FIXME: This is using deprecated interfaces
191  ArrayView<const LO> colind_E, colind_N;
192  ArrayView<const SC> values_E, values_N;
193 
194  size_t Ne=EdgeMatrix->getNodeNumRows();
195  size_t Nn=NodeMatrix->getNodeNumRows();
196 
197  // Upper bound on local number of coarse edges
198  size_t max_edges = (NodeMatrix->getNodeNumEntries() + Nn +1) / 2;
199  ArrayRCP<size_t> D0_rowptr(Ne+1);
200  ArrayRCP<LO> D0_colind(max_edges);
201  ArrayRCP<SC> D0_values(max_edges);
202  D0_rowptr[0] = 0;
203 
204  LO current = 0;
205  LO Nnc = PnT_D0T->getRowMap()->getNodeNumElements();
206 
207  for(LO i=0; i<(LO)Nnc; i++) {
208  // GO global_i = PnT_D0T->getRowMap()->getGlobalElement(i);
209 
210  // FIXME: We don't really want an std::map here. This is just a first cut implementation
211  using value_type = bool;
212  std::map<LO, value_type> ce_map;
213 
214  // FIXME: This is using deprecated interfaces
215  PnT_D0T->getLocalRowView(i,colind_E,values_E);
216 
217  for(LO j=0; j<(LO)colind_E.size(); j++) {
218 
219  // NOTE: Edges between procs will be via handled via the a version
220  // of ML's odd/even rule
221  // For this to function correctly, we make two assumptions:
222  // (a) The processor that owns a fine edge owns at least one of the attached nodes.
223  // (b) Aggregation is uncoupled.
224 
225  // TODO: Add some debug code to check the assumptions
226 
227  // Check to see if we own this edge and continue if we don't
228  GO edge_gid = PnT_D0T->getColMap()->getGlobalElement(colind_E[j]);
229  LO j_row = D0_Pn->getRowMap()->getLocalElement(edge_gid);
230  int pid0, pid1;
231  D0_Pn->getLocalRowView(j_row,colind_N,values_N);
232 
233  // Skip incomplete rows
234  if(colind_N.size() != 2) continue;
235 
236  pid0 = D0_Pn_col_pids[colind_N[0]];
237  pid1 = D0_Pn_col_pids[colind_N[1]];
238  // printf("[%d] Row %d considering edge (%d)%d -> (%d)%d\n",MyPID,global_i,colind_N[0],D0_Pn->getColMap()->getGlobalElement(colind_N[0]),colind_N[1],D0_Pn->getColMap()->getGlobalElement(colind_N[1]));
239 
240  // Check to see who owns these nodes
241  // If the sum of owning procs is odd, the lower ranked proc gets it
242 
243  bool zero_matches = pid0 == MyPID;
244  bool one_matches = pid1 == MyPID;
245  bool keep_shared_edge = false, own_both_nodes = false;
246  if(zero_matches && one_matches) {own_both_nodes=true;}
247  else {
248  int sum_is_odd = (pid0 + pid1) % 2;
249  int i_am_smaller = MyPID == std::min(pid0,pid1);
250  if(sum_is_odd && i_am_smaller) keep_shared_edge=true;
251  if(!sum_is_odd && !i_am_smaller) keep_shared_edge=true;
252  }
253  // printf("[%d] - matches %d/%d keep_shared = %d own_both = %d\n",MyPID,(int)zero_matches,(int)one_matches,(int)keep_shared_edge,(int)own_both_nodes);
254  if(!keep_shared_edge && !own_both_nodes) continue;
255 
256 
257  // We're doing this in GID space, but only only because it allows us to explain
258  // the edge orientation as "always goes from lower GID to higher GID". This could
259  // be done entirely in local GIDs, but then the ordering is a little more confusing.
260  // This could be done in local indices later if we need the extra performance.
261  for(LO k=0; k<(LO)colind_N.size(); k++) {
262  LO my_colind = colind_N[k];
263  if(my_colind!=LO_INVALID && ((keep_shared_edge && my_colind != i) || (own_both_nodes && my_colind > i)) ) {
264  ce_map.emplace(std::make_pair(my_colind,true));
265  }
266  }//end for k < colind_N.size()
267  }// end for j < colind_E.size()
268 
269 
270  // std::map is sorted, so we'll just iterate through this
271  for(auto iter=ce_map.begin(); iter != ce_map.end(); iter++) {
272  LO col = iter->first;
273  // This shouldn't happen. But in case it did...
274  if(col == i) {
275  continue;
276  }
277 
278  // ASSUMPTION: "i" is a valid local column id
279  D0_colind[current] = i;
280  D0_values[current] = -1;
281  current++;
282  D0_colind[current] = col;
283  D0_values[current] = 1;
284  current++;
285  D0_rowptr[current / 2] = current;
286  }
287 
288  }// end for i < Nn
289 
290  LO num_coarse_edges = current / 2;
291  D0_rowptr.resize(num_coarse_edges+1);
292  D0_colind.resize(current);
293  D0_values.resize(current);
294 
295  // Count the total number of edges
296  // NOTE: Since we solve the ownership issue above, this should do what we want
297  RCP<const Map> ownedCoarseEdgeMap = Xpetra::MapFactory<LO,GO,NO>::Build(EdgeMatrix->getRowMap()->lib(), GO_INVALID, num_coarse_edges,EdgeMatrix->getRowMap()->getIndexBase(),EdgeMatrix->getRowMap()->getComm());
298 
299 
300  // NOTE: This only works because of the assumptions above
301  RCP<const Map> ownedCoarseNodeMap = Pn->getDomainMap();
302  RCP<const Map> ownedPlusSharedCoarseNodeMap = D0_Pn->getCrsGraph()->getColMap();
303 
304  // Create the coarse D0
305  RCP<CrsMatrix> D0_coarse;
306  {
307  SubFactoryMonitor m2(*this, "Build D0", coarseLevel);
308  // FIXME: We can be smarter with memory here
309  // TODO: Is there a smarter way to get this importer?
310  D0_coarse = CrsMatrixFactory::Build(ownedCoarseEdgeMap,ownedPlusSharedCoarseNodeMap,0);
311  TEUCHOS_TEST_FOR_EXCEPTION(D0_coarse.is_null(), Exceptions::RuntimeError, "MueLu::ReitzingerPFactory: CrsMatrixFatory failed.");
312 
313  // FIXME: Deprecated code
314  ArrayRCP<size_t> ia;
315  ArrayRCP<LO> ja;
316  ArrayRCP<SC> val;
317  D0_coarse->allocateAllValues(current, ia, ja, val);
318  std::copy(D0_rowptr.begin(),D0_rowptr.end(),ia.begin());
319  std::copy(D0_colind.begin(),D0_colind.end(),ja.begin());
320  std::copy(D0_values.begin(),D0_values.end(),val.begin());
321  D0_coarse->setAllValues(ia, ja, val);
322 
323 #if 0
324  {
325  char fname[80];
326  printf("[%d] D0: ia.size() = %d ja.size() = %d\n",MyPID,(int)ia.size(),(int)ja.size());
327  printf("[%d] D0: ia :",MyPID);
328  for(int i=0; i<(int)ia.size(); i++)
329  printf("%d ",(int)ia[i]);
330  printf("\n[%d] D0: global ja :",MyPID);
331  for(int i=0; i<(int)ja.size(); i++)
332  printf("%d ",(int)ownedPlusSharedCoarseNodeMap->getGlobalElement(ja[i]));
333  printf("\n[%d] D0: local ja :",MyPID);
334  for(int i=0; i<(int)ja.size(); i++)
335  printf("%d ",(int)ja[i]);
336  printf("\n");
337 
338  sprintf(fname,"D0_global_ja_%d_%d.dat",MyPID,fineLevel.GetLevelID());
339  FILE * f = fopen(fname,"w");
340  for(int i=0; i<(int)ja.size(); i++)
341  fprintf(f,"%d ",(int)ownedPlusSharedCoarseNodeMap->getGlobalElement(ja[i]));
342  fclose(f);
343 
344  sprintf(fname,"D0_local_ja_%d_%d.dat",MyPID,fineLevel.GetLevelID());
345  f = fopen(fname,"w");
346  for(int i=0; i<(int)ja.size(); i++)
347  fprintf(f,"%d ",(int)ja[i]);
348  fclose(f);
349 
350  }
351 #endif
352  fflush(stdout);
353 
354  D0_coarse->expertStaticFillComplete(ownedCoarseNodeMap,ownedCoarseEdgeMap);
355  }
356  RCP<Matrix> D0_coarse_m = rcp(new CrsMatrixWrap(D0_coarse));
357  RCP<Teuchos::FancyOStream> fout = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
358 
359 
360  // Create the Pe matrix, but with the extra entries. From ML's notes:
361  /* The general idea is that the matrix */
362  /* T_h P_n T_H^* */
363  /* is almost Pe. If we make sure that P_n contains 1's and -1's, the*/
364  /* matrix triple product will yield a matrix with +/- 1 and +/- 2's.*/
365  /* If we remove all the 1's and divide the 2's by 2. we arrive at Pe*/
366  RCP<Matrix> Pe;
367  {
368  SubFactoryMonitor m2(*this, "Generate Pe (pre-fix)", coarseLevel);
369  RCP<Matrix> dummy;
370 
371  RCP<Matrix> Pn_D0cT = XMM::Multiply(*Pn,false,*D0_coarse_m,true,dummy,out0,true,true,"Pn*D0c'",mm_params);
372  Pe = XMM::Multiply(*D0,false,*Pn_D0cT,false,dummy,out0,true,true,"D0*(Pn*D0c')",mm_params);
373 
374  // TODO: Something like this *might* work. But this specifically, doesn;'t
375  // Pe = XMM::Multiply(*D0_Pn_nonghosted,false,*D0_coarse_m,true,dummy,out0,true,true,"(D0*Pn)*D0c'",mm_params);
376  }
377 
378  /* Weed out the +/- entries */
379  {
380  SubFactoryMonitor m2(*this, "Generate Pe (post-fix)", coarseLevel);
381  Pe->resumeFill();
382  SC one = Teuchos::ScalarTraits<SC>::one();
383  MT two = 2*Teuchos::ScalarTraits<MT>::one();
384  SC zero = Teuchos::ScalarTraits<SC>::zero();
385  SC neg_one = - one;
386  // FIXME: Deprecated code
387  for(LO i=0; i<(LO) Ne; i++) {
388  ArrayView<const LO> columns;
389  ArrayView<const SC> values;
390  Pe->getLocalRowView(i,columns,values);
391  // FIXME: This won't work on fancy nodes
392  ArrayView<SC> values_nc = Teuchos::av_const_cast<SC>(values);
393  for (LO j=0; j<(LO)values.size(); j++)
394  if ((values_nc[j] == one || values_nc[j] == neg_one))
395  values_nc[j] = zero;
396  else
397  values_nc[j] /= two;
398  }//end for i < Ne
399  Pe->fillComplete(Pe->getDomainMap(),Pe->getRangeMap());
400  }
401 
402  /* Check commuting property */
403  CheckCommutingProperty(*Pe,*D0_coarse_m,*D0,*Pn);
404 
405  /* Set output on the level */
406  Set(coarseLevel,"P",Pe);
407  Set(coarseLevel,"Ptent",Pe);
408 
409  Set(coarseLevel,"D0",D0_coarse_m);
410  coarseLevel.Set("D0",D0_coarse_m,NoFactory::get());
411  coarseLevel.AddKeepFlag("D0",NoFactory::get(), MueLu::Final);
412  coarseLevel.RemoveKeepFlag("D0",NoFactory::get(), MueLu::UserData);
413 
414 #if 0
415  {
416  int numProcs = Pe->getRowMap()->getComm()->getSize();
417  char fname[80];
418 
419  sprintf(fname,"Pe_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*Pe);
420  sprintf(fname,"Pn_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*Pn);
421  sprintf(fname,"D0c_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*D0_coarse_m);
422  sprintf(fname,"D0f_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*D0);
423  }
424 #endif
425 
426  }// end Build
427 
428  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
430  CheckCommutingProperty(const Matrix & Pe, const Matrix & D0_c, const Matrix& D0_f, const Matrix & Pn) const {
431  if(IsPrint(Statistics0)) {
432  using XMM = Xpetra::MatrixMatrix<SC,LO,GO,NO>;
433  using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
434  SC one = Teuchos::ScalarTraits<SC>::one();
435  SC zero = Teuchos::ScalarTraits<SC>::zero();
436 
437  RCP<Matrix> dummy;
438  Teuchos::FancyOStream &out0=GetBlackHole();
439  RCP<Matrix> left = XMM::Multiply(Pe,false,D0_c,false,dummy,out0);
440  RCP<Matrix> right = XMM::Multiply(D0_f,false,Pn,false,dummy,out0);
441 
442  // We need a non-FC matrix for the add, sadly
443  RCP<CrsMatrix> sum_c = CrsMatrixFactory::Build(left->getRowMap(),left->getNodeMaxNumRowEntries()+right->getNodeMaxNumRowEntries());
444  RCP<Matrix> summation = rcp(new CrsMatrixWrap(sum_c));
445  XMM::TwoMatrixAdd(*left, false, one, *summation, zero);
446  XMM::TwoMatrixAdd(*right, false, -one, *summation, one);
447 
448  MT norm = summation->getFrobeniusNorm();
449  GetOStream(Statistics0) << "CheckCommutingProperty: ||Pe D0_c - D0_f Pn || = "<<norm<<std::endl;
450 
451  }
452 
453  }//end CheckCommutingProperty
454 
455 
456 
457 } //namespace MueLu
458 
459 
460 
461 #define MUELU_REITZINGERPFACTORY_SHORT
462 #endif // MUELU_REITZINGERPFACTORY_DEF_HPP
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.
Definition: MueLu_Level.hpp:99
void RemoveKeepFlag(const std::string &ename, const FactoryBase *factory, KeepType keep=MueLu::All)
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
void AddKeepFlag(const std::string &ename, const FactoryBase *factory=NoFactory::get(), KeepType keep=MueLu::Keep)
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
static const NoFactory * get()
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
void CheckCommutingProperty(const Matrix &Pe, const Matrix &D0_c, const Matrix &D0_f, const Matrix &Pn) const
Utility method.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Transpose(Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, bool optimizeTranspose=false, const std::string &label=std::string(), const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Namespace for MueLu classes and methods.
@ Final
Keep data only for this run. Used to keep data useful for Hierarchy::Iterate(). Data will be deleted ...
@ UserData
User data are always kept. This flag is set automatically when Level::Set("data", data) is used....
@ Statistics0
Print statistics that do not involve significant additional computation.