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 // ***********************************************************************
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_MasterList.hpp"
68 #include "MueLu_Monitor.hpp"
69 #include "MueLu_Utilities.hpp"
70 
71 namespace MueLu {
72 
73 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
75  RCP<ParameterList> validParamList = rcp(new ParameterList());
76 
77 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
78  SET_VALID_ENTRY("repartition: enable");
79  SET_VALID_ENTRY("repartition: use subcommunicators");
80  SET_VALID_ENTRY("tentative: calculate qr");
81  SET_VALID_ENTRY("tentative: constant column sums");
82 #undef SET_VALID_ENTRY
83 
84  validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
85  validParamList->set<RCP<const FactoryBase> >("D0", Teuchos::null, "Generating factory of the matrix D0");
86  validParamList->set<RCP<const FactoryBase> >("NodeAggMatrix", Teuchos::null, "Generating factory of the matrix NodeAggMatrix");
87  validParamList->set<RCP<const FactoryBase> >("Pnodal", Teuchos::null, "Generating factory of the matrix P");
88  validParamList->set<RCP<const FactoryBase> >("NodeImporter", Teuchos::null, "Generating factory of the matrix NodeImporter");
89 
90  // Make sure we don't recursively validate options for the matrixmatrix kernels
91  ParameterList norecurse;
92  norecurse.disableRecursiveValidation();
93  validParamList->set<ParameterList>("matrixmatrix: kernel params", norecurse, "MatrixMatrix kernel parameters");
94 
95  return validParamList;
96 }
97 
98 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
100  Input(fineLevel, "A");
101  Input(fineLevel, "D0");
102  Input(fineLevel, "NodeAggMatrix");
103  Input(coarseLevel, "NodeAggMatrix");
104  Input(coarseLevel, "Pnodal");
105  // Input(coarseLevel, "NodeImporter");
106 }
107 
108 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
110  return BuildP(fineLevel, coarseLevel);
111 }
112 
113 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
115  FactoryMonitor m(*this, "Build", coarseLevel);
116  using Teuchos::arcp_const_cast;
117  using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
119  Teuchos::FancyOStream& out0 = GetBlackHole();
120  const ParameterList& pL = GetParameterList();
121 
122  bool update_communicators = pL.get<bool>("repartition: enable") && pL.get<bool>("repartition: use subcommunicators");
123 
124  // If these are set correctly we assume that the nodal P contains only ones
125  bool nodal_p_is_all_ones = !pL.get<bool>("tentative: constant column sums") && !pL.get<bool>("tentative: calculate qr");
126 
127  RCP<Matrix> EdgeMatrix = Get<RCP<Matrix> >(fineLevel, "A");
128  RCP<Matrix> D0 = Get<RCP<Matrix> >(fineLevel, "D0");
129  RCP<Matrix> NodeMatrix = Get<RCP<Matrix> >(fineLevel, "NodeAggMatrix");
130  RCP<Matrix> Pn = Get<RCP<Matrix> >(coarseLevel, "Pnodal");
131 
132  const GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
133  const LO LO_INVALID = Teuchos::OrdinalTraits<LO>::invalid();
134 
135  // This needs to be an Operator because if NodeMatrix gets repartitioned away, we get an Operator on the level
136  RCP<Operator> CoarseNodeMatrix = Get<RCP<Operator> >(coarseLevel, "NodeAggMatrix");
137  int MyPID = EdgeMatrix.is_null() ? -1 : EdgeMatrix->getRowMap()->getComm()->getRank();
138 
139  // Matrix matrix params
140  RCP<ParameterList> mm_params = rcp(new ParameterList);
141  ;
142  if (pL.isSublist("matrixmatrix: kernel params"))
143  mm_params->sublist("matrixmatrix: kernel params") = pL.sublist("matrixmatrix: kernel params");
144 
145  // Normalize P
146  if (!nodal_p_is_all_ones) {
147  // The parameters told us the nodal P isn't all ones, so we make a copy that is.
148  GetOStream(Runtime0) << "ReitzingerPFactory::BuildP(): Assuming Pn is not normalized" << std::endl;
149  RCP<Matrix> Pn_old = Pn;
150 
151  Pn = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(Pn->getCrsGraph());
152  Pn->setAllToScalar(Teuchos::ScalarTraits<SC>::one());
153  Pn->fillComplete(Pn->getDomainMap(), Pn->getRangeMap());
154  } else {
155  // The parameters claim P is all ones.
156  GetOStream(Runtime0) << "ReitzingerPFactory::BuildP(): Assuming Pn is normalized" << std::endl;
157  }
158 
159  // TODO: We need to make sure Pn isn't normalized. Right now this has to be done explicitly by the user
160 
161  // TODO: We need to look through and see which of these really need importers and which ones don't
162 
163  /* Generate the D0 * Pn matrix and its transpose */
164  RCP<Matrix> D0_Pn, PnT_D0T, D0_Pn_nonghosted;
165  Teuchos::Array<int> D0_Pn_col_pids;
166  {
167  RCP<Matrix> dummy;
168  SubFactoryMonitor m2(*this, "Generate D0*Pn", coarseLevel);
169  D0_Pn = XMM::Multiply(*D0, false, *Pn, false, dummy, out0, true, true, "D0*Pn", mm_params);
170 
171  // We don't want this guy getting accidently used later
172  if (!mm_params.is_null()) mm_params->remove("importer", false);
173 
174  // Save this so we don't need to do the multiplication again later
175  D0_Pn_nonghosted = D0_Pn;
176 
177  // Get owning PID information on columns for tie-breaking
178  if (!D0_Pn->getCrsGraph()->getImporter().is_null()) {
179  Xpetra::ImportUtils<LO, GO, NO> utils;
180  utils.getPids(*D0_Pn->getCrsGraph()->getImporter(), D0_Pn_col_pids, false);
181  } else {
182  D0_Pn_col_pids.resize(D0_Pn->getCrsGraph()->getColMap()->getLocalNumElements(), MyPID);
183  }
184  }
185 
186  {
187  // Get the transpose
188  SubFactoryMonitor m2(*this, "Transpose D0*Pn", coarseLevel);
189  PnT_D0T = Utilities::Transpose(*D0_Pn, true);
190  }
191 
192  // We really need a ghosted version of D0_Pn here.
193  // The reason is that if there's only one fine edge between two coarse nodes, somebody is going
194  // to own the associated coarse edge. The sum/sign rule doesn't guarantee the fine owner is the coarse owner.
195  // So you can wind up with a situation that only guy who *can* register the coarse edge isn't the sum/sign
196  // owner. Adding more ghosting fixes that.
197  if (!PnT_D0T->getCrsGraph()->getImporter().is_null()) {
198  RCP<const Import> Importer = PnT_D0T->getCrsGraph()->getImporter();
199  RCP<const CrsMatrix> D0_Pn_crs = rcp_dynamic_cast<const CrsMatrixWrap>(D0_Pn)->getCrsMatrix();
200  RCP<Matrix> D0_Pn_new = rcp(new CrsMatrixWrap(CrsMatrixFactory::Build(D0_Pn_crs, *Importer, D0_Pn->getDomainMap(), Importer->getTargetMap())));
201  D0_Pn = D0_Pn_new;
202  // Get owning PID information on columns for tie-breaking
203  if (!D0_Pn->getCrsGraph()->getImporter().is_null()) {
204  Xpetra::ImportUtils<LO, GO, NO> utils;
205  utils.getPids(*D0_Pn->getCrsGraph()->getImporter(), D0_Pn_col_pids, false);
206  } else {
207  D0_Pn_col_pids.resize(D0_Pn->getCrsGraph()->getColMap()->getLocalNumElements(), MyPID);
208  }
209  }
210 
211  // FIXME: This is using deprecated interfaces
212  ArrayView<const LO> colind_E, colind_N;
213  ArrayView<const SC> values_E, values_N;
214 
215  size_t Ne = EdgeMatrix->getLocalNumRows();
216  size_t Nn = NodeMatrix->getLocalNumRows();
217 
218  // Upper bound on local number of coarse edges
219  size_t max_edges = (NodeMatrix->getLocalNumEntries() + Nn + 1) / 2;
220  ArrayRCP<size_t> D0_rowptr(Ne + 1);
221  ArrayRCP<LO> D0_colind(max_edges);
222  ArrayRCP<SC> D0_values(max_edges);
223  D0_rowptr[0] = 0;
224 
225  LO current = 0;
226  LO Nnc = PnT_D0T->getRowMap()->getLocalNumElements();
227 
228  // Get the node maps for D0_coarse
229  RCP<const Map> ownedCoarseNodeMap = Pn->getDomainMap();
230  RCP<const Map> ownedPlusSharedCoarseNodeMap = D0_Pn->getCrsGraph()->getColMap();
231 
232  for (LO i = 0; i < (LO)Nnc; i++) {
233  LO local_column_i = ownedPlusSharedCoarseNodeMap->getLocalElement(PnT_D0T->getRowMap()->getGlobalElement(i));
234 
235  // FIXME: We don't really want an std::map here. This is just a first cut implementation
236  using value_type = bool;
237  std::map<LO, value_type> ce_map;
238 
239  // FIXME: This is using deprecated interfaces
240  PnT_D0T->getLocalRowView(i, colind_E, values_E);
241 
242  for (LO j = 0; j < (LO)colind_E.size(); j++) {
243  // NOTE: Edges between procs will be via handled via the a version
244  // of ML's odd/even rule
245  // For this to function correctly, we make two assumptions:
246  // (a) The processor that owns a fine edge owns at least one of the attached nodes.
247  // (b) Aggregation is uncoupled.
248 
249  // TODO: Add some debug code to check the assumptions
250 
251  // Check to see if we own this edge and continue if we don't
252  GO edge_gid = PnT_D0T->getColMap()->getGlobalElement(colind_E[j]);
253  LO j_row = D0_Pn->getRowMap()->getLocalElement(edge_gid);
254  int pid0, pid1;
255  D0_Pn->getLocalRowView(j_row, colind_N, values_N);
256 
257  // Skip incomplete rows
258  if (colind_N.size() != 2) continue;
259 
260  pid0 = D0_Pn_col_pids[colind_N[0]];
261  pid1 = D0_Pn_col_pids[colind_N[1]];
262  // 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]));
263 
264  // Check to see who owns these nodes
265  // If the sum of owning procs is odd, the lower ranked proc gets it
266 
267  bool zero_matches = pid0 == MyPID;
268  bool one_matches = pid1 == MyPID;
269  bool keep_shared_edge = false, own_both_nodes = false;
270  if (zero_matches && one_matches) {
271  own_both_nodes = true;
272  } else {
273  bool sum_is_even = (pid0 + pid1) % 2 == 0;
274  bool i_am_smaller = MyPID == std::min(pid0, pid1);
275  if (sum_is_even && i_am_smaller) keep_shared_edge = true;
276  if (!sum_is_even && !i_am_smaller) keep_shared_edge = true;
277  }
278  // 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);
279  if (!keep_shared_edge && !own_both_nodes) continue;
280 
281  // We're doing this in GID space, but only because it allows us to explain
282  // the edge orientation as "always goes from lower GID to higher GID". This could
283  // be done entirely in LIDs, but then the ordering is a little more confusing.
284  // This could be done in local indices later if we need the extra performance.
285  for (LO k = 0; k < (LO)colind_N.size(); k++) {
286  LO my_colind = colind_N[k];
287  if (my_colind != LO_INVALID && ((keep_shared_edge && my_colind != local_column_i) || (own_both_nodes && my_colind > local_column_i))) {
288  ce_map.emplace(std::make_pair(my_colind, true));
289  }
290  } // end for k < colind_N.size()
291  } // end for j < colind_E.size()
292 
293  // std::map is sorted, so we'll just iterate through this
294  for (auto iter = ce_map.begin(); iter != ce_map.end(); iter++) {
295  LO col = iter->first;
296  if (col == local_column_i) {
297  continue;
298  }
299 
300  // NOTE: "i" here might not be a valid local column id, so we read it from the map
301  D0_colind[current] = local_column_i;
302  D0_values[current] = -1;
303  current++;
304  D0_colind[current] = col;
305  D0_values[current] = 1;
306  current++;
307  D0_rowptr[current / 2] = current;
308  }
309 
310  } // end for i < Nn
311 
312  LO num_coarse_edges = current / 2;
313  D0_rowptr.resize(num_coarse_edges + 1);
314  D0_colind.resize(current);
315  D0_values.resize(current);
316 
317  // Count the total number of edges
318  // NOTE: Since we solve the ownership issue above, this should do what we want
319  RCP<const Map> ownedCoarseEdgeMap = Xpetra::MapFactory<LO, GO, NO>::Build(EdgeMatrix->getRowMap()->lib(), GO_INVALID, num_coarse_edges, EdgeMatrix->getRowMap()->getIndexBase(), EdgeMatrix->getRowMap()->getComm());
320 
321  // Create the coarse D0
322  RCP<CrsMatrix> D0_coarse;
323  {
324  SubFactoryMonitor m2(*this, "Build D0", coarseLevel);
325  // FIXME: We can be smarter with memory here
326  // TODO: Is there a smarter way to get this importer?
327  D0_coarse = CrsMatrixFactory::Build(ownedCoarseEdgeMap, ownedPlusSharedCoarseNodeMap, 0);
328  TEUCHOS_TEST_FOR_EXCEPTION(D0_coarse.is_null(), Exceptions::RuntimeError, "MueLu::ReitzingerPFactory: CrsMatrixFatory failed.");
329 
330  // FIXME: Deprecated code
331  ArrayRCP<size_t> ia;
332  ArrayRCP<LO> ja;
333  ArrayRCP<SC> val;
334  D0_coarse->allocateAllValues(current, ia, ja, val);
335  std::copy(D0_rowptr.begin(), D0_rowptr.end(), ia.begin());
336  std::copy(D0_colind.begin(), D0_colind.end(), ja.begin());
337  std::copy(D0_values.begin(), D0_values.end(), val.begin());
338  D0_coarse->setAllValues(ia, ja, val);
339 
340 #if 0
341  {
342  char fname[80];
343  printf("[%d] D0: ia.size() = %d ja.size() = %d\n",MyPID,(int)ia.size(),(int)ja.size());
344  printf("[%d] D0: ia :",MyPID);
345  for(int i=0; i<(int)ia.size(); i++)
346  printf("%d ",(int)ia[i]);
347  printf("\n[%d] D0: global ja :",MyPID);
348  for(int i=0; i<(int)ja.size(); i++)
349  printf("%d ",(int)ownedPlusSharedCoarseNodeMap->getGlobalElement(ja[i]));
350  printf("\n[%d] D0: local ja :",MyPID);
351  for(int i=0; i<(int)ja.size(); i++)
352  printf("%d ",(int)ja[i]);
353  printf("\n");
354 
355  sprintf(fname,"D0_global_ja_%d_%d.dat",MyPID,fineLevel.GetLevelID());
356  FILE * f = fopen(fname,"w");
357  for(int i=0; i<(int)ja.size(); i++)
358  fprintf(f,"%d ",(int)ownedPlusSharedCoarseNodeMap->getGlobalElement(ja[i]));
359  fclose(f);
360 
361  sprintf(fname,"D0_local_ja_%d_%d.dat",MyPID,fineLevel.GetLevelID());
362  f = fopen(fname,"w");
363  for(int i=0; i<(int)ja.size(); i++)
364  fprintf(f,"%d ",(int)ja[i]);
365  fclose(f);
366 
367  }
368 #endif
369  D0_coarse->expertStaticFillComplete(ownedCoarseNodeMap, ownedCoarseEdgeMap);
370  }
371  RCP<Matrix> D0_coarse_m = rcp(new CrsMatrixWrap(D0_coarse));
372  RCP<Teuchos::FancyOStream> fout = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
373 
374  // Create the Pe matrix, but with the extra entries. From ML's notes:
375  /* The general idea is that the matrix */
376  /* T_h P_n T_H^* */
377  /* is almost Pe. If we make sure that P_n contains 1's and -1's, the*/
378  /* matrix triple product will yield a matrix with +/- 1 and +/- 2's.*/
379  /* If we remove all the 1's and divide the 2's by 2. we arrive at Pe*/
380  RCP<Matrix> Pe;
381  {
382  SubFactoryMonitor m2(*this, "Generate Pe (pre-fix)", coarseLevel);
383 
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  coarseLevel.Set("D0", D0_coarse_m, NoFactory::get());
462  coarseLevel.AddKeepFlag("D0", NoFactory::get(), MueLu::Final);
463  coarseLevel.RemoveKeepFlag("D0", NoFactory::get(), MueLu::UserData);
464 
465 #if 0
466  {
467  int numProcs = Pe->getRowMap()->getComm()->getSize();
468  char fname[80];
469 
470  sprintf(fname,"Pe_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*Pe);
471  sprintf(fname,"Pn_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*Pn);
472  sprintf(fname,"D0c_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*D0_coarse_m);
473  sprintf(fname,"D0f_%d_%d.mat",numProcs,fineLevel.GetLevelID()); Xpetra::IO<SC,LO,GO,NO>::Write(fname,*D0);
474  }
475 #endif
476 
477 } // end Build
478 
479 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
481  CheckCommutingProperty(const Matrix& Pe, const Matrix& D0_c, const Matrix& D0_f, const Matrix& Pn) const {
482  if (IsPrint(Statistics0)) {
484  using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
487 
488  RCP<Matrix> dummy;
489  Teuchos::FancyOStream& out0 = GetBlackHole();
490  RCP<Matrix> left = XMM::Multiply(Pe, false, D0_c, false, dummy, out0);
491  RCP<Matrix> right = XMM::Multiply(D0_f, false, Pn, false, dummy, out0);
492 
493  // We need a non-FC matrix for the add, sadly
494  RCP<CrsMatrix> sum_c = CrsMatrixFactory::Build(left->getRowMap(), left->getLocalMaxNumRowEntries() + right->getLocalMaxNumRowEntries());
495  RCP<Matrix> summation = rcp(new CrsMatrixWrap(sum_c));
496  XMM::TwoMatrixAdd(*left, false, one, *summation, zero);
497  XMM::TwoMatrixAdd(*right, false, -one, *summation, one);
498 
499  MT norm = summation->getFrobeniusNorm();
500  GetOStream(Statistics0) << "CheckCommutingProperty: ||Pe D0_c - D0_f Pn || = " << norm << std::endl;
501  }
502 
503 } // end CheckCommutingProperty
504 
505 } // namespace MueLu
506 
507 #define MUELU_REITZINGERPFACTORY_SHORT
508 #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)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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.
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:99
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