MueLu Version of the Day
Loading...
Searching...
No Matches
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_ImportFactory.hpp>
23#include <Xpetra_CrsMatrixWrap.hpp>
24#include <Xpetra_StridedMap.hpp>
25#include <Xpetra_StridedMapFactory.hpp>
26#include <Xpetra_IO.hpp>
27
29
30#include "MueLu_MasterList.hpp"
31#include "MueLu_Monitor.hpp"
32#include "MueLu_Utilities.hpp"
33#include "MueLu_ImportUtils.hpp"
34
35namespace MueLu {
36
37template <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
62template <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
72template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
74 return BuildP(fineLevel, coarseLevel);
75}
76
77template <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;
82 using XMM = Xpetra::MatrixMatrix<SC, LO, GO, NO>;
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()) {
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()) {
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();
400 SC one = Teuchos::ScalarTraits<SC>::one();
401 MT two = 2 * Teuchos::ScalarTraits<MT>::one();
402 SC zero = Teuchos::ScalarTraits<SC>::zero();
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
445 RCP<const Teuchos::Comm<int> > newComm;
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
481template <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)) {
485 using XMM = Xpetra::MatrixMatrix<SC, LO, GO, NO>;
486 using MT = typename Teuchos::ScalarTraits<SC>::magnitudeType;
487 SC one = Teuchos::ScalarTraits<SC>::one();
488 SC zero = Teuchos::ScalarTraits<SC>::zero();
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)
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.
MueLu utility class for Import-related routines.
void getPids(const Xpetra::Import< LocalOrdinal, GlobalOrdinal, Node > &Importer, Teuchos::Array< int > &pids, bool use_minus_one_for_local)
Like getPidGidPairs, but just gets the PIDs, ordered by the column Map.
Class that holds all level-specific information.
void RemoveKeepFlag(const std::string &ename, const FactoryBase *factory, KeepType keep=MueLu::All)
int GetLevelID() const
Return level number.
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....
@ Runtime0
One-liner description of what is happening.
@ Statistics0
Print statistics that do not involve significant additional computation.