MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_ReitzingerPFactory_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_REITZINGERPFACTORY_DEF_HPP
11 #define MUELU_REITZINGERPFACTORY_DEF_HPP
12 
13 #include <Xpetra_MapFactory.hpp>
14 #include <Xpetra_Map.hpp>
15 #include <Xpetra_CrsMatrix.hpp>
16 #include <Xpetra_Matrix.hpp>
17 #include <Xpetra_MatrixMatrix.hpp>
18 #include <Xpetra_MultiVector.hpp>
19 #include <Xpetra_MultiVectorFactory.hpp>
20 #include <Xpetra_VectorFactory.hpp>
21 #include <Xpetra_Import.hpp>
22 #include <Xpetra_ImportUtils.hpp>
23 #include <Xpetra_ImportFactory.hpp>
24 #include <Xpetra_CrsMatrixWrap.hpp>
25 #include <Xpetra_StridedMap.hpp>
26 #include <Xpetra_StridedMapFactory.hpp>
27 #include <Xpetra_IO.hpp>
28 
30 
31 #include "MueLu_MasterList.hpp"
32 #include "MueLu_Monitor.hpp"
33 #include "MueLu_Utilities.hpp"
34 
35 namespace MueLu {
36 
37 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
39  RCP<ParameterList> validParamList = rcp(new ParameterList());
40 
41 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
42  SET_VALID_ENTRY("repartition: enable");
43  SET_VALID_ENTRY("repartition: use subcommunicators");
44  SET_VALID_ENTRY("tentative: calculate qr");
45  SET_VALID_ENTRY("tentative: constant column sums");
46 #undef SET_VALID_ENTRY
47 
48  validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
49  validParamList->set<RCP<const FactoryBase> >("D0", Teuchos::null, "Generating factory of the matrix D0");
50  validParamList->set<RCP<const FactoryBase> >("NodeAggMatrix", Teuchos::null, "Generating factory of the matrix NodeAggMatrix");
51  validParamList->set<RCP<const FactoryBase> >("Pnodal", Teuchos::null, "Generating factory of the matrix P");
52  validParamList->set<RCP<const FactoryBase> >("NodeImporter", Teuchos::null, "Generating factory of the matrix NodeImporter");
53 
54  // Make sure we don't recursively validate options for the matrixmatrix kernels
55  ParameterList norecurse;
56  norecurse.disableRecursiveValidation();
57  validParamList->set<ParameterList>("matrixmatrix: kernel params", norecurse, "MatrixMatrix kernel parameters");
58 
59  return validParamList;
60 }
61 
62 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
64  Input(fineLevel, "A");
65  Input(fineLevel, "D0");
66  Input(fineLevel, "NodeAggMatrix");
67  Input(coarseLevel, "NodeAggMatrix");
68  Input(coarseLevel, "Pnodal");
69  // Input(coarseLevel, "NodeImporter");
70 }
71 
72 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
74  return BuildP(fineLevel, coarseLevel);
75 }
76 
77 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
79  FactoryMonitor m(*this, "Build", coarseLevel);
80  using Teuchos::arcp_const_cast;
81  using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
83  Teuchos::FancyOStream& out0 = GetBlackHole();
84  const ParameterList& pL = GetParameterList();
85 
86  bool update_communicators = pL.get<bool>("repartition: enable") && pL.get<bool>("repartition: use subcommunicators");
87 
88  // If these are set correctly we assume that the nodal P contains only ones
89  bool nodal_p_is_all_ones = !pL.get<bool>("tentative: constant column sums") && !pL.get<bool>("tentative: calculate qr");
90 
91  RCP<Matrix> EdgeMatrix = Get<RCP<Matrix> >(fineLevel, "A");
92  RCP<Matrix> D0 = Get<RCP<Matrix> >(fineLevel, "D0");
93  RCP<Matrix> NodeMatrix = Get<RCP<Matrix> >(fineLevel, "NodeAggMatrix");
94  RCP<Matrix> Pn = Get<RCP<Matrix> >(coarseLevel, "Pnodal");
95 
96  const GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
97  const LO LO_INVALID = Teuchos::OrdinalTraits<LO>::invalid();
98 
99  // This needs to be an Operator because if NodeMatrix gets repartitioned away, we get an Operator on the level
100  RCP<Operator> CoarseNodeMatrix = Get<RCP<Operator> >(coarseLevel, "NodeAggMatrix");
101  int MyPID = EdgeMatrix.is_null() ? -1 : EdgeMatrix->getRowMap()->getComm()->getRank();
102 
103  // Matrix matrix params
104  RCP<ParameterList> mm_params = rcp(new ParameterList);
105  ;
106  if (pL.isSublist("matrixmatrix: kernel params"))
107  mm_params->sublist("matrixmatrix: kernel params") = pL.sublist("matrixmatrix: kernel params");
108 
109  // Normalize P
110  if (!nodal_p_is_all_ones) {
111  // The parameters told us the nodal P isn't all ones, so we make a copy that is.
112  GetOStream(Runtime0) << "ReitzingerPFactory::BuildP(): Assuming Pn is not normalized" << std::endl;
113  RCP<Matrix> Pn_old = Pn;
114 
115  Pn = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(Pn->getCrsGraph());
116  Pn->setAllToScalar(Teuchos::ScalarTraits<SC>::one());
117  Pn->fillComplete(Pn->getDomainMap(), Pn->getRangeMap());
118  } else {
119  // The parameters claim P is all ones.
120  GetOStream(Runtime0) << "ReitzingerPFactory::BuildP(): Assuming Pn is normalized" << std::endl;
121  }
122 
123  // TODO: We need to make sure Pn isn't normalized. Right now this has to be done explicitly by the user
124 
125  // TODO: We need to look through and see which of these really need importers and which ones don't
126 
127  /* Generate the D0 * Pn matrix and its transpose */
128  RCP<Matrix> D0_Pn, PnT_D0T, D0_Pn_nonghosted;
129  Teuchos::Array<int> D0_Pn_col_pids;
130  {
131  RCP<Matrix> dummy;
132  SubFactoryMonitor m2(*this, "Generate D0*Pn", coarseLevel);
133  D0_Pn = XMM::Multiply(*D0, false, *Pn, false, dummy, out0, true, true, "D0*Pn", mm_params);
134 
135  // We don't want this guy getting accidently used later
136  if (!mm_params.is_null()) mm_params->remove("importer", false);
137 
138  // Save this so we don't need to do the multiplication again later
139  D0_Pn_nonghosted = D0_Pn;
140 
141  // Get owning PID information on columns for tie-breaking
142  if (!D0_Pn->getCrsGraph()->getImporter().is_null()) {
143  Xpetra::ImportUtils<LO, GO, NO> utils;
144  utils.getPids(*D0_Pn->getCrsGraph()->getImporter(), D0_Pn_col_pids, false);
145  } else {
146  D0_Pn_col_pids.resize(D0_Pn->getCrsGraph()->getColMap()->getLocalNumElements(), MyPID);
147  }
148  }
149 
150  {
151  // Get the transpose
152  SubFactoryMonitor m2(*this, "Transpose D0*Pn", coarseLevel);
153  PnT_D0T = Utilities::Transpose(*D0_Pn, true);
154  }
155 
156  // We really need a ghosted version of D0_Pn here.
157  // The reason is that if there's only one fine edge between two coarse nodes, somebody is going
158  // to own the associated coarse edge. The sum/sign rule doesn't guarantee the fine owner is the coarse owner.
159  // So you can wind up with a situation that only guy who *can* register the coarse edge isn't the sum/sign
160  // owner. Adding more ghosting fixes that.
161  if (!PnT_D0T->getCrsGraph()->getImporter().is_null()) {
162  RCP<const Import> Importer = PnT_D0T->getCrsGraph()->getImporter();
163  RCP<const CrsMatrix> D0_Pn_crs = rcp_dynamic_cast<const CrsMatrixWrap>(D0_Pn)->getCrsMatrix();
164  RCP<Matrix> D0_Pn_new = rcp(new CrsMatrixWrap(CrsMatrixFactory::Build(D0_Pn_crs, *Importer, D0_Pn->getDomainMap(), Importer->getTargetMap())));
165  D0_Pn = D0_Pn_new;
166  // Get owning PID information on columns for tie-breaking
167  if (!D0_Pn->getCrsGraph()->getImporter().is_null()) {
168  Xpetra::ImportUtils<LO, GO, NO> utils;
169  utils.getPids(*D0_Pn->getCrsGraph()->getImporter(), D0_Pn_col_pids, false);
170  } else {
171  D0_Pn_col_pids.resize(D0_Pn->getCrsGraph()->getColMap()->getLocalNumElements(), MyPID);
172  }
173  }
174 
175  // FIXME: This is using deprecated interfaces
176  ArrayView<const LO> colind_E, colind_N;
177  ArrayView<const SC> values_E, values_N;
178 
179  size_t Ne = EdgeMatrix->getLocalNumRows();
180 
181  // Notinal upper bound on local number of coarse edges
182  size_t max_edges = PnT_D0T->getLocalNumEntries();
183  ArrayRCP<size_t> D0_rowptr(Ne + 1);
184  ArrayRCP<LO> D0_colind(max_edges);
185  ArrayRCP<SC> D0_values(max_edges);
186  D0_rowptr[0] = 0;
187 
188  LO current = 0;
189  LO Nnc = PnT_D0T->getRowMap()->getLocalNumElements();
190 
191  // Get the node maps for D0_coarse
192  RCP<const Map> ownedCoarseNodeMap = Pn->getDomainMap();
193  RCP<const Map> ownedPlusSharedCoarseNodeMap = D0_Pn->getCrsGraph()->getColMap();
194 
195  for (LO i = 0; i < (LO)Nnc; i++) {
196  LO local_column_i = ownedPlusSharedCoarseNodeMap->getLocalElement(PnT_D0T->getRowMap()->getGlobalElement(i));
197 
198  // FIXME: We don't really want an std::map here. This is just a first cut implementation
199  using value_type = bool;
200  std::map<LO, value_type> ce_map;
201 
202  // FIXME: This is using deprecated interfaces
203  PnT_D0T->getLocalRowView(i, colind_E, values_E);
204 
205  for (LO j = 0; j < (LO)colind_E.size(); j++) {
206  // NOTE: Edges between procs will be via handled via the a version
207  // of ML's odd/even rule
208  // For this to function correctly, we make two assumptions:
209  // (a) The processor that owns a fine edge owns at least one of the attached nodes.
210  // (b) Aggregation is uncoupled.
211 
212  // TODO: Add some debug code to check the assumptions
213 
214  // Check to see if we own this edge and continue if we don't
215  GO edge_gid = PnT_D0T->getColMap()->getGlobalElement(colind_E[j]);
216  LO j_row = D0_Pn->getRowMap()->getLocalElement(edge_gid);
217  int pid0, pid1;
218  D0_Pn->getLocalRowView(j_row, colind_N, values_N);
219 
220  // Skip incomplete rows
221  if (colind_N.size() != 2) continue;
222 
223  pid0 = D0_Pn_col_pids[colind_N[0]];
224  pid1 = D0_Pn_col_pids[colind_N[1]];
225  // 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]));
226 
227  // Check to see who owns these nodes
228  // If the sum of owning procs is odd, the lower ranked proc gets it
229 
230  bool zero_matches = pid0 == MyPID;
231  bool one_matches = pid1 == MyPID;
232  bool keep_shared_edge = false, own_both_nodes = false;
233  if (zero_matches && one_matches) {
234  own_both_nodes = true;
235  } else {
236  bool sum_is_even = (pid0 + pid1) % 2 == 0;
237  bool i_am_smaller = MyPID == std::min(pid0, pid1);
238  if (sum_is_even && i_am_smaller) keep_shared_edge = true;
239  if (!sum_is_even && !i_am_smaller) keep_shared_edge = true;
240  }
241  // 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);
242  if (!keep_shared_edge && !own_both_nodes) continue;
243 
244  // We're doing this in GID space, but only because it allows us to explain
245  // the edge orientation as "always goes from lower GID to higher GID". This could
246  // be done entirely in LIDs, but then the ordering is a little more confusing.
247  // This could be done in local indices later if we need the extra performance.
248  for (LO k = 0; k < (LO)colind_N.size(); k++) {
249  LO my_colind = colind_N[k];
250  if (my_colind != LO_INVALID && ((keep_shared_edge && my_colind != local_column_i) || (own_both_nodes && my_colind > local_column_i))) {
251  ce_map.emplace(std::make_pair(my_colind, true));
252  }
253  } // end for k < colind_N.size()
254  } // end for j < colind_E.size()
255 
256  // std::map is sorted, so we'll just iterate through this
257  for (auto iter = ce_map.begin(); iter != ce_map.end(); iter++) {
258  LO col = iter->first;
259  if (col == local_column_i) {
260  continue;
261  }
262 
263  // Exponential memory reallocation, if needed
264  if (current + 1 >= Teuchos::as<LocalOrdinal>(max_edges)) {
265  max_edges *= 2;
266  D0_colind.resize(max_edges);
267  D0_values.resize(max_edges);
268  }
269  if (current / 2 + 1 >= D0_rowptr.size()) {
270  D0_rowptr.resize(2 * D0_rowptr.size() + 1);
271  }
272 
273  // NOTE: "i" here might not be a valid local column id, so we read it from the map
274  D0_colind[current] = local_column_i;
275  D0_values[current] = -1;
276  current++;
277  D0_colind[current] = col;
278  D0_values[current] = 1;
279  current++;
280  D0_rowptr[current / 2] = current;
281  }
282 
283  } // end for i < Nn
284 
285  LO num_coarse_edges = current / 2;
286  D0_rowptr.resize(num_coarse_edges + 1);
287  D0_colind.resize(current);
288  D0_values.resize(current);
289 
290  // Handle empty ranks gracefully
291  if (num_coarse_edges == 0) {
292  D0_rowptr[0] = 0;
293  }
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  // Create the coarse D0
300  RCP<CrsMatrix> D0_coarse;
301  {
302  SubFactoryMonitor m2(*this, "Build D0", coarseLevel);
303  // FIXME: We can be smarter with memory here
304  // TODO: Is there a smarter way to get this importer?
305  D0_coarse = CrsMatrixFactory::Build(ownedCoarseEdgeMap, ownedPlusSharedCoarseNodeMap, 0);
306  TEUCHOS_TEST_FOR_EXCEPTION(D0_coarse.is_null(), Exceptions::RuntimeError, "MueLu::ReitzingerPFactory: CrsMatrixFatory failed.");
307 
308  // FIXME: Deprecated code
309  ArrayRCP<size_t> ia;
310  ArrayRCP<LO> ja;
311  ArrayRCP<SC> val;
312  D0_coarse->allocateAllValues(current, ia, ja, val);
313  std::copy(D0_rowptr.begin(), D0_rowptr.end(), ia.begin());
314  std::copy(D0_colind.begin(), D0_colind.end(), ja.begin());
315  std::copy(D0_values.begin(), D0_values.end(), val.begin());
316  D0_coarse->setAllValues(ia, ja, val);
317 
318 #if 0
319  {
320  char fname[80];
321  int fine_level_id = fineLevel.GetLevelID();
322  printf("[%d] Level %d D0: ia.size() = %d ja.size() = %d\n",MyPID,fine_level_id,(int)ia.size(),(int)ja.size());
323  printf("[%d] Level %d D0: ia :",MyPID,fine_level_id);
324  for(int i=0; i<(int)ia.size(); i++)
325  printf("%d ",(int)ia[i]);
326  printf("\n[%d] Level %d D0: global ja :",MyPID,fine_level_id);
327  for(int i=0; i<(int)ja.size(); i++)
328  printf("%d ",(int)ownedPlusSharedCoarseNodeMap->getGlobalElement(ja[i]));
329  printf("\n[%d] Level %d D0: local ja :",MyPID,fine_level_id);
330  for(int i=0; i<(int)ja.size(); i++)
331  printf("%d ",(int)ja[i]);
332  printf("\n");
333 
334  sprintf(fname,"D0_global_ja_%d_%d.dat",MyPID,fine_level_id);
335  FILE * f = fopen(fname,"w");
336  for(int i=0; i<(int)ja.size(); i++)
337  fprintf(f,"%d ",(int)ownedPlusSharedCoarseNodeMap->getGlobalElement(ja[i]));
338  fclose(f);
339 
340  sprintf(fname,"D0_local_ja_%d_%d.dat",MyPID,fine_level_id);
341  f = fopen(fname,"w");
342  for(int i=0; i<(int)ja.size(); i++)
343  fprintf(f,"%d ",(int)ja[i]);
344  fclose(f);
345 
346  }
347 #endif
348  D0_coarse->expertStaticFillComplete(ownedCoarseNodeMap, ownedCoarseEdgeMap);
349  }
350  RCP<Matrix> D0_coarse_m = rcp(new CrsMatrixWrap(D0_coarse));
351  RCP<Teuchos::FancyOStream> fout = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
352 
353  // Create the Pe matrix, but with the extra entries. From ML's notes:
354  /* The general idea is that the matrix */
355  /* T_h P_n T_H^* */
356  /* is almost Pe. If we make sure that P_n contains 1's and -1's, the*/
357  /* matrix triple product will yield a matrix with +/- 1 and +/- 2's.*/
358  /* If we remove all the 1's and divide the 2's by 2. we arrive at Pe*/
359  RCP<Matrix> Pe;
360  {
361  SubFactoryMonitor m2(*this, "Generate Pe (pre-fix)", coarseLevel);
362 #if 0
363  {
364  // If you're concerned about processor / rank mismatches, this debugging code might help
365  int rank = D0->getRowMap()->getComm()->getRank();
366  int fine_level = fineLevel.GetLevelID();
367  printf("[%d] Level %d Checkpoint #2 Pn = %d/%d/%d/%d D0c = %d/%d/%d/%d D0 = %d/%d/%d/%d\n",rank,fine_level,
368  Pn->getRangeMap()->getComm()->getSize(),
369  Pn->getRowMap()->getComm()->getSize(),
370  Pn->getColMap()->getComm()->getSize(),
371  Pn->getDomainMap()->getComm()->getSize(),
372  D0_coarse_m->getRangeMap()->getComm()->getSize(),
373  D0_coarse_m->getRowMap()->getComm()->getSize(),
374  D0_coarse_m->getColMap()->getComm()->getSize(),
375  D0_coarse_m->getDomainMap()->getComm()->getSize(),
376  D0->getRangeMap()->getComm()->getSize(),
377  D0->getRowMap()->getComm()->getSize(),
378  D0->getColMap()->getComm()->getSize(),
379  D0->getDomainMap()->getComm()->getSize());
380  fflush(stdout);
381  D0->getRowMap()->getComm()->barrier();
382  }
383 #endif
384  RCP<Matrix> dummy;
385  RCP<Matrix> Pn_D0cT = XMM::Multiply(*Pn, false, *D0_coarse_m, true, dummy, out0, true, true, "Pn*D0c'", mm_params);
386 
387  // We don't want this guy getting accidently used later
388  if (!mm_params.is_null()) mm_params->remove("importer", false);
389 
390  Pe = XMM::Multiply(*D0, false, *Pn_D0cT, false, dummy, out0, true, true, "D0*(Pn*D0c')", mm_params);
391 
392  // TODO: Something like this *might* work. But this specifically, doesn't
393  // Pe = XMM::Multiply(*D0_Pn_nonghosted,false,*D0_coarse_m,true,dummy,out0,true,true,"(D0*Pn)*D0c'",mm_params);
394  }
395 
396  /* Weed out the +/- entries, shrinking the matrix as we go */
397  {
398  SubFactoryMonitor m2(*this, "Generate Pe (post-fix)", coarseLevel);
399  Pe->resumeFill();
401  MT two = 2 * Teuchos::ScalarTraits<MT>::one();
403  SC neg_one = -one;
404 
405  RCP<const CrsMatrix> Pe_crs = rcp_dynamic_cast<const CrsMatrixWrap>(Pe)->getCrsMatrix();
406  TEUCHOS_TEST_FOR_EXCEPTION(Pe_crs.is_null(), Exceptions::RuntimeError, "MueLu::ReitzingerPFactory: Pe is not a crs matrix.");
407  ArrayRCP<const size_t> rowptr_const;
408  ArrayRCP<const LO> colind_const;
409  ArrayRCP<const SC> values_const;
410  Pe_crs->getAllValues(rowptr_const, colind_const, values_const);
411  ArrayRCP<size_t> rowptr = arcp_const_cast<size_t>(rowptr_const);
412  ArrayRCP<LO> colind = arcp_const_cast<LO>(colind_const);
413  ArrayRCP<SC> values = arcp_const_cast<SC>(values_const);
414  LO ct = 0;
415  LO lower = rowptr[0];
416  for (LO i = 0; i < (LO)Ne; i++) {
417  for (size_t j = lower; j < rowptr[i + 1]; j++) {
418  if (values[j] == one || values[j] == neg_one || values[j] == zero) {
419  // drop this guy
420  } else {
421  colind[ct] = colind[j];
422  values[ct] = values[j] / two;
423  ct++;
424  }
425  }
426  lower = rowptr[i + 1];
427  rowptr[i + 1] = ct;
428  }
429  rowptr[Ne] = ct;
430  colind.resize(ct);
431  values.resize(ct);
432  rcp_const_cast<CrsMatrix>(Pe_crs)->setAllValues(rowptr, colind, values);
433 
434  Pe->fillComplete(Pe->getDomainMap(), Pe->getRangeMap());
435  }
436 
437  /* Check commuting property */
438  CheckCommutingProperty(*Pe, *D0_coarse_m, *D0, *Pn);
439 
440  /* If we're repartitioning here, we need to cut down the communicators */
441  // NOTE: We need to do this *after* checking the commuting property, since
442  // that's going to need to fineLevel's communicators, not the repartitioned ones
443  if (update_communicators) {
444  // NOTE: We can only do D0 here. We have to do Ke_coarse=(Re Ke_fine Pe) in RebalanceAcFactory
446  if (!CoarseNodeMatrix.is_null()) newComm = CoarseNodeMatrix->getDomainMap()->getComm();
447  RCP<const Map> newMap = Xpetra::MapFactory<LO, GO, NO>::copyMapWithNewComm(D0_coarse_m->getRowMap(), newComm);
448  D0_coarse_m->removeEmptyProcessesInPlace(newMap);
449 
450  // The "in place" still leaves a dummy matrix here. That needs to go
451  if (newMap.is_null()) D0_coarse_m = Teuchos::null;
452 
453  Set(coarseLevel, "InPlaceMap", newMap);
454  }
455 
456  /* Set output on the level */
457  Set(coarseLevel, "P", Pe);
458  Set(coarseLevel, "Ptent", Pe);
459 
460  Set(coarseLevel, "D0", D0_coarse_m);
461 
462  /* This needs to be kept for the smoothers */
463  coarseLevel.Set("D0", D0_coarse_m, NoFactory::get());
464  coarseLevel.AddKeepFlag("D0", NoFactory::get(), MueLu::Final);
465  coarseLevel.RemoveKeepFlag("D0", NoFactory::get(), MueLu::UserData);
466 
467 #if 0
468  {
469  int numProcs = Pe->getRowMap()->getComm()->getSize();
470  char fname[80];
471 
472  sprintf(fname,"Pe_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*Pe);
473  sprintf(fname,"Pn_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*Pn);
474  sprintf(fname,"D0c_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*D0_coarse_m);
475  sprintf(fname,"D0f_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*D0);
476  }
477 #endif
478 
479 } // end Build
480 
481 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
483  CheckCommutingProperty(const Matrix& Pe, const Matrix& D0_c, const Matrix& D0_f, const Matrix& Pn) const {
484  if (IsPrint(Statistics0)) {
486  using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
489 
490  RCP<Matrix> dummy;
491  Teuchos::FancyOStream& out0 = GetBlackHole();
492  RCP<Matrix> left = XMM::Multiply(Pe, false, D0_c, false, dummy, out0);
493  RCP<Matrix> right = XMM::Multiply(D0_f, false, Pn, false, dummy, out0);
494 
495  // We need a non-FC matrix for the add, sadly
496  RCP<CrsMatrix> sum_c = CrsMatrixFactory::Build(left->getRowMap(), left->getLocalMaxNumRowEntries() + right->getLocalMaxNumRowEntries());
497  RCP<Matrix> summation = rcp(new CrsMatrixWrap(sum_c));
498  XMM::TwoMatrixAdd(*left, false, one, *summation, zero);
499  XMM::TwoMatrixAdd(*right, false, -one, *summation, one);
500 
501  MT norm = summation->getFrobeniusNorm();
502  GetOStream(Statistics0) << "CheckCommutingProperty: ||Pe D0_c - D0_f Pn || = " << norm << std::endl;
503  }
504 
505 } // end CheckCommutingProperty
506 
507 } // namespace MueLu
508 
509 #define MUELU_REITZINGERPFACTORY_SHORT
510 #endif // MUELU_REITZINGERPFACTORY_DEF_HPP
#define SET_VALID_ENTRY(name)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
GlobalOrdinal GO
T & get(const std::string &name, T def_value)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static void Write(const std::string &fileName, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &M)
size_type size() const
User data are always kept. This flag is set automatically when Level::Set(&quot;data&quot;, data) is used...
LocalOrdinal LO
One-liner description of what is happening.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
size_type size() const
static const NoFactory * get()
void resize(const size_type n, const T &val=T())
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
Print statistics that do not involve significant additional computation.
bool remove(std::string const &name, bool throwIfNotExists=true)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
static Teuchos::RCP< Map< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, const Teuchos::RCP< const Teuchos::Comm< int >> &comm, LocalGlobal lg=Xpetra::GloballyDistributed)
bool isSublist(const std::string &name) const
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
Keep data only for this run. Used to keep data useful for Hierarchy::Iterate(). Data will be deleted ...
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)
void resize(size_type new_size, const value_type &x=value_type())
void CheckCommutingProperty(const Matrix &Pe, const Matrix &D0_c, const Matrix &D0_f, const Matrix &Pn) const
Utility method.
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
TransListIter iter
Scalar SC
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
static RCP< Matrix > Build(const RCP< const Map > &rowMap, size_t maxNumEntriesPerRow, Xpetra::ProfileType pftype=Xpetra::DynamicProfile)
Exception throws to report errors in the internal logical of the program.
iterator end() const
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
iterator begin() const
bool is_null() const