MueLu Version of the Day
MueLu_TentativePFactory_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_TENTATIVEPFACTORY_DEF_HPP
47#define MUELU_TENTATIVEPFACTORY_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_MultiVector.hpp>
54#include <Xpetra_MultiVectorFactory.hpp>
55#include <Xpetra_VectorFactory.hpp>
56#include <Xpetra_Import.hpp>
57#include <Xpetra_ImportFactory.hpp>
58#include <Xpetra_CrsMatrixWrap.hpp>
59#include <Xpetra_StridedMap.hpp>
60#include <Xpetra_StridedMapFactory.hpp>
61
63
64#include "MueLu_Aggregates.hpp"
65#include "MueLu_AmalgamationFactory.hpp"
66#include "MueLu_AmalgamationInfo.hpp"
67#include "MueLu_CoarseMapFactory.hpp"
68#include "MueLu_MasterList.hpp"
69#include "MueLu_Monitor.hpp"
70#include "MueLu_NullspaceFactory.hpp"
71#include "MueLu_PerfUtils.hpp"
72#include "MueLu_Utilities.hpp"
73
74namespace MueLu {
75
76 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
78 RCP<ParameterList> validParamList = rcp(new ParameterList());
79
80#define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
81 SET_VALID_ENTRY("tentative: calculate qr");
82 SET_VALID_ENTRY("tentative: build coarse coordinates");
83 SET_VALID_ENTRY("tentative: constant column sums");
84#undef SET_VALID_ENTRY
85 validParamList->set< std::string >("Nullspace name", "Nullspace", "Name for the input nullspace");
86
87 validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
88 validParamList->set< RCP<const FactoryBase> >("Aggregates", Teuchos::null, "Generating factory of the aggregates");
89 validParamList->set< RCP<const FactoryBase> >("Nullspace", Teuchos::null, "Generating factory of the nullspace");
90 validParamList->set< RCP<const FactoryBase> >("Scaled Nullspace", Teuchos::null, "Generating factory of the scaled nullspace");
91 validParamList->set< RCP<const FactoryBase> >("UnAmalgamationInfo", Teuchos::null, "Generating factory of UnAmalgamationInfo");
92 validParamList->set< RCP<const FactoryBase> >("CoarseMap", Teuchos::null, "Generating factory of the coarse map");
93 validParamList->set< RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Generating factory of the coordinates");
94 validParamList->set< RCP<const FactoryBase> >("Node Comm", Teuchos::null, "Generating factory of the node level communicator");
95
96 // Make sure we don't recursively validate options for the matrixmatrix kernels
97 ParameterList norecurse;
98 norecurse.disableRecursiveValidation();
99 validParamList->set<ParameterList> ("matrixmatrix: kernel params", norecurse, "MatrixMatrix kernel parameters");
100
101 return validParamList;
102 }
103
104 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
106
107 const ParameterList& pL = GetParameterList();
108 // NOTE: This guy can only either be 'Nullspace' or 'Scaled Nullspace' or else the validator above will cause issues
109 std::string nspName = "Nullspace";
110 if(pL.isParameter("Nullspace name")) nspName = pL.get<std::string>("Nullspace name");
111
112 Input(fineLevel, "A");
113 Input(fineLevel, "Aggregates");
114 Input(fineLevel, nspName);
115 Input(fineLevel, "UnAmalgamationInfo");
116 Input(fineLevel, "CoarseMap");
117 if( fineLevel.GetLevelID() == 0 &&
118 fineLevel.IsAvailable("Coordinates", NoFactory::get()) && // we have coordinates (provided by user app)
119 pL.get<bool>("tentative: build coarse coordinates") ) { // and we want coordinates on other levels
120 bTransferCoordinates_ = true; // then set the transfer coordinates flag to true
121 Input(fineLevel, "Coordinates");
122 } else if (bTransferCoordinates_) {
123 Input(fineLevel, "Coordinates");
124 }
125 }
126
127 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
129 return BuildP(fineLevel, coarseLevel);
130 }
131
132 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
134 FactoryMonitor m(*this, "Build", coarseLevel);
135 typedef typename Teuchos::ScalarTraits<Scalar>::coordinateType coordinate_type;
136 typedef Xpetra::MultiVector<coordinate_type,LO,GO,NO> RealValuedMultiVector;
137 typedef Xpetra::MultiVectorFactory<coordinate_type,LO,GO,NO> RealValuedMultiVectorFactory;
138
139 const ParameterList& pL = GetParameterList();
140 std::string nspName = "Nullspace";
141 if(pL.isParameter("Nullspace name")) nspName = pL.get<std::string>("Nullspace name");
142
143
144 RCP<Matrix> A = Get< RCP<Matrix> > (fineLevel, "A");
145 RCP<Aggregates> aggregates = Get< RCP<Aggregates> > (fineLevel, "Aggregates");
146 RCP<AmalgamationInfo> amalgInfo = Get< RCP<AmalgamationInfo> > (fineLevel, "UnAmalgamationInfo");
147 RCP<MultiVector> fineNullspace = Get< RCP<MultiVector> > (fineLevel, nspName);
148 RCP<const Map> coarseMap = Get< RCP<const Map> > (fineLevel, "CoarseMap");
149 RCP<RealValuedMultiVector> fineCoords;
150 if(bTransferCoordinates_) {
151 fineCoords = Get< RCP<RealValuedMultiVector> >(fineLevel, "Coordinates");
152 }
153
154 // FIXME: We should remove the NodeComm on levels past the threshold
155 if(fineLevel.IsAvailable("Node Comm")) {
156 RCP<const Teuchos::Comm<int> > nodeComm = Get<RCP<const Teuchos::Comm<int> > >(fineLevel,"Node Comm");
157 Set<RCP<const Teuchos::Comm<int> > >(coarseLevel, "Node Comm", nodeComm);
158 }
159
160 TEUCHOS_TEST_FOR_EXCEPTION(A->getRowMap()->getNodeNumElements() != fineNullspace->getMap()->getNodeNumElements(),
161 Exceptions::RuntimeError,"MueLu::TentativePFactory::MakeTentative: Size mismatch between A and Nullspace");
162
163 RCP<Matrix> Ptentative;
164 RCP<MultiVector> coarseNullspace;
165 RCP<RealValuedMultiVector> coarseCoords;
166
167 if(bTransferCoordinates_) {
168 //*** Create the coarse coordinates ***
169 // First create the coarse map and coarse multivector
170 ArrayView<const GO> elementAList = coarseMap->getNodeElementList();
171 LO blkSize = 1;
172 if (rcp_dynamic_cast<const StridedMap>(coarseMap) != Teuchos::null) {
173 blkSize = rcp_dynamic_cast<const StridedMap>(coarseMap)->getFixedBlockSize();
174 }
175 GO indexBase = coarseMap->getIndexBase();
176 LO numCoarseNodes = Teuchos::as<LO>(elementAList.size() / blkSize);
177 Array<GO> nodeList(numCoarseNodes);
178 const int numDimensions = fineCoords->getNumVectors();
179
180 for (LO i = 0; i < numCoarseNodes; i++) {
181 nodeList[i] = (elementAList[i*blkSize]-indexBase)/blkSize + indexBase;
182 }
183 RCP<const Map> coarseCoordsMap = MapFactory::Build(fineCoords->getMap()->lib(),
184 Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),
185 nodeList,
186 indexBase,
187 fineCoords->getMap()->getComm());
188 coarseCoords = RealValuedMultiVectorFactory::Build(coarseCoordsMap, numDimensions);
189
190 // Create overlapped fine coordinates to reduce global communication
191 RCP<RealValuedMultiVector> ghostedCoords;
192 if (aggregates->AggregatesCrossProcessors()) {
193 RCP<const Map> aggMap = aggregates->GetMap();
194 RCP<const Import> importer = ImportFactory::Build(fineCoords->getMap(), aggMap);
195
196 ghostedCoords = RealValuedMultiVectorFactory::Build(aggMap, numDimensions);
197 ghostedCoords->doImport(*fineCoords, *importer, Xpetra::INSERT);
198 } else {
199 ghostedCoords = fineCoords;
200 }
201
202 // Get some info about aggregates
203 int myPID = coarseCoordsMap->getComm()->getRank();
204 LO numAggs = aggregates->GetNumAggregates();
205 ArrayRCP<LO> aggSizes = aggregates->ComputeAggregateSizes();
206 const ArrayRCP<const LO> vertex2AggID = aggregates->GetVertex2AggId()->getData(0);
207 const ArrayRCP<const LO> procWinner = aggregates->GetProcWinner()->getData(0);
208
209 // Fill in coarse coordinates
210 for (int dim = 0; dim < numDimensions; ++dim) {
211 ArrayRCP<const coordinate_type> fineCoordsData = ghostedCoords->getData(dim);
212 ArrayRCP<coordinate_type> coarseCoordsData = coarseCoords->getDataNonConst(dim);
213
214 for (LO lnode = 0; lnode < Teuchos::as<LO>(vertex2AggID.size()); lnode++) {
215 if (procWinner[lnode] == myPID &&
216 lnode < fineCoordsData.size() &&
217 vertex2AggID[lnode] < coarseCoordsData.size() &&
218 Teuchos::ScalarTraits<coordinate_type>::isnaninf(fineCoordsData[lnode]) == false) {
219 coarseCoordsData[vertex2AggID[lnode]] += fineCoordsData[lnode];
220 }
221 }
222 for (LO agg = 0; agg < numAggs; agg++) {
223 coarseCoordsData[agg] /= aggSizes[agg];
224 }
225 }
226 }
227
228 if (!aggregates->AggregatesCrossProcessors())
229 BuildPuncoupled(A, aggregates, amalgInfo, fineNullspace, coarseMap, Ptentative, coarseNullspace,coarseLevel.GetLevelID());
230 else
231 BuildPcoupled (A, aggregates, amalgInfo, fineNullspace, coarseMap, Ptentative, coarseNullspace);
232
233 // If available, use striding information of fine level matrix A for range
234 // map and coarseMap as domain map; otherwise use plain range map of
235 // Ptent = plain range map of A for range map and coarseMap as domain map.
236 // NOTE:
237 // The latter is not really safe, since there is no striding information
238 // for the range map. This is not really a problem, since striding
239 // information is always available on the intermedium levels and the
240 // coarsest levels.
241 if (A->IsView("stridedMaps") == true)
242 Ptentative->CreateView("stridedMaps", A->getRowMap("stridedMaps"), coarseMap);
243 else
244 Ptentative->CreateView("stridedMaps", Ptentative->getRangeMap(), coarseMap);
245
246 if(bTransferCoordinates_) {
247 Set(coarseLevel, "Coordinates", coarseCoords);
248 }
249 Set(coarseLevel, "Nullspace", coarseNullspace);
250 Set(coarseLevel, "P", Ptentative);
251
252 if (IsPrint(Statistics2)) {
253 RCP<ParameterList> params = rcp(new ParameterList());
254 params->set("printLoadBalancingInfo", true);
255 GetOStream(Statistics2) << PerfUtils::PrintMatrixInfo(*Ptentative, "Ptent", params);
256 }
257 }
258
259 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
261 BuildPuncoupled(RCP<Matrix> A, RCP<Aggregates> aggregates, RCP<AmalgamationInfo> amalgInfo, RCP<MultiVector> fineNullspace,
262 RCP<const Map> coarseMap, RCP<Matrix>& Ptentative, RCP<MultiVector>& coarseNullspace, const int levelID) const {
263 RCP<const Map> rowMap = A->getRowMap();
264 RCP<const Map> colMap = A->getColMap();
265
266 const size_t numRows = rowMap->getNodeNumElements();
267
268 typedef Teuchos::ScalarTraits<SC> STS;
269 typedef typename STS::magnitudeType Magnitude;
270 const SC zero = STS::zero();
271 const SC one = STS::one();
272 const LO INVALID = Teuchos::OrdinalTraits<LO>::invalid();
273
274 const GO numAggs = aggregates->GetNumAggregates();
275 const size_t NSDim = fineNullspace->getNumVectors();
276 ArrayRCP<LO> aggSizes = aggregates->ComputeAggregateSizes();
277
278
279 // Sanity checking
280 const ParameterList& pL = GetParameterList();
281 const bool &doQRStep = pL.get<bool>("tentative: calculate qr");
282 const bool &constantColSums = pL.get<bool>("tentative: constant column sums");
283
284 TEUCHOS_TEST_FOR_EXCEPTION(doQRStep && constantColSums,Exceptions::RuntimeError,
285 "MueLu::TentativePFactory::MakeTentative: cannot use 'constant column sums' and 'calculate qr' at the same time");
286
287 // Aggregates map is based on the amalgamated column map
288 // We can skip global-to-local conversion if LIDs in row map are
289 // same as LIDs in column map
290 bool goodMap = MueLu::Utilities<SC,LO,GO,NO>::MapsAreNested(*rowMap, *colMap);
291
292 // Create a lookup table to determine the rows (fine DOFs) that belong to a given aggregate.
293 // aggStart is a pointer into aggToRowMapLO
294 // aggStart[i]..aggStart[i+1] are indices into aggToRowMapLO
295 // aggToRowMapLO[aggStart[i]]..aggToRowMapLO[aggStart[i+1]-1] are the DOFs in aggregate i
296 ArrayRCP<LO> aggStart;
297 ArrayRCP<LO> aggToRowMapLO;
298 ArrayRCP<GO> aggToRowMapGO;
299 if (goodMap) {
300 amalgInfo->UnamalgamateAggregatesLO(*aggregates, aggStart, aggToRowMapLO);
301 GetOStream(Runtime1) << "Column map is consistent with the row map, good." << std::endl;
302
303 } else {
304 amalgInfo->UnamalgamateAggregates(*aggregates, aggStart, aggToRowMapGO);
305 GetOStream(Warnings0) << "Column map is not consistent with the row map\n"
306 << "using GO->LO conversion with performance penalty" << std::endl;
307 }
308
309 coarseNullspace = MultiVectorFactory::Build(coarseMap, NSDim);
310
311 // Pull out the nullspace vectors so that we can have random access.
312 ArrayRCP<ArrayRCP<const SC> > fineNS (NSDim);
313 ArrayRCP<ArrayRCP<SC> > coarseNS(NSDim);
314 for (size_t i = 0; i < NSDim; i++) {
315 fineNS[i] = fineNullspace->getData(i);
316 if (coarseMap->getNodeNumElements() > 0)
317 coarseNS[i] = coarseNullspace->getDataNonConst(i);
318 }
319
320 size_t nnzEstimate = numRows * NSDim;
321
322 // Time to construct the matrix and fill in the values
323 Ptentative = rcp(new CrsMatrixWrap(rowMap, coarseMap, 0));
324 RCP<CrsMatrix> PtentCrs = rcp_dynamic_cast<CrsMatrixWrap>(Ptentative)->getCrsMatrix();
325
326 ArrayRCP<size_t> iaPtent;
327 ArrayRCP<LO> jaPtent;
328 ArrayRCP<SC> valPtent;
329
330 PtentCrs->allocateAllValues(nnzEstimate, iaPtent, jaPtent, valPtent);
331
332 ArrayView<size_t> ia = iaPtent();
333 ArrayView<LO> ja = jaPtent();
334 ArrayView<SC> val = valPtent();
335
336 ia[0] = 0;
337 for (size_t i = 1; i <= numRows; i++)
338 ia[i] = ia[i-1] + NSDim;
339
340 for (size_t j = 0; j < nnzEstimate; j++) {
341 ja [j] = INVALID;
342 val[j] = zero;
343 }
344
345
346 if (doQRStep) {
348 // Standard aggregate-wise QR //
350 for (GO agg = 0; agg < numAggs; agg++) {
351 LO aggSize = aggStart[agg+1] - aggStart[agg];
352
353 Xpetra::global_size_t offset = agg*NSDim;
354
355 // Extract the piece of the nullspace corresponding to the aggregate, and
356 // put it in the flat array, "localQR" (in column major format) for the
357 // QR routine.
358 Teuchos::SerialDenseMatrix<LO,SC> localQR(aggSize, NSDim);
359 if (goodMap) {
360 for (size_t j = 0; j < NSDim; j++)
361 for (LO k = 0; k < aggSize; k++)
362 localQR(k,j) = fineNS[j][aggToRowMapLO[aggStart[agg]+k]];
363 } else {
364 for (size_t j = 0; j < NSDim; j++)
365 for (LO k = 0; k < aggSize; k++)
366 localQR(k,j) = fineNS[j][rowMap->getLocalElement(aggToRowMapGO[aggStart[agg]+k])];
367 }
368
369 // Test for zero columns
370 for (size_t j = 0; j < NSDim; j++) {
371 bool bIsZeroNSColumn = true;
372
373 for (LO k = 0; k < aggSize; k++)
374 if (localQR(k,j) != zero)
375 bIsZeroNSColumn = false;
376
377 TEUCHOS_TEST_FOR_EXCEPTION(bIsZeroNSColumn == true, Exceptions::RuntimeError,
378 "MueLu::TentativePFactory::MakeTentative: fine level NS part has a zero column in NS column " << j);
379 }
380
381 // Calculate QR decomposition (standard)
382 // NOTE: Q is stored in localQR and R is stored in coarseNS
383 if (aggSize >= Teuchos::as<LO>(NSDim)) {
384
385 if (NSDim == 1) {
386 // Only one nullspace vector, calculate Q and R by hand
387 Magnitude norm = STS::magnitude(zero);
388 for (size_t k = 0; k < Teuchos::as<size_t>(aggSize); k++)
389 norm += STS::magnitude(localQR(k,0)*localQR(k,0));
390 norm = Teuchos::ScalarTraits<Magnitude>::squareroot(norm);
391
392 // R = norm
393 coarseNS[0][offset] = norm;
394
395 // Q = localQR(:,0)/norm
396 for (LO i = 0; i < aggSize; i++)
397 localQR(i,0) /= norm;
398
399 } else {
400 Teuchos::SerialQRDenseSolver<LO,SC> qrSolver;
401 qrSolver.setMatrix(Teuchos::rcp(&localQR, false));
402 qrSolver.factor();
403
404 // R = upper triangular part of localQR
405 for (size_t j = 0; j < NSDim; j++)
406 for (size_t k = 0; k <= j; k++)
407 coarseNS[j][offset+k] = localQR(k,j); //TODO is offset+k the correct local ID?!
408
409 // Calculate Q, the tentative prolongator.
410 // The Lapack GEQRF call only works for myAggsize >= NSDim
411 qrSolver.formQ();
412 Teuchos::RCP<Teuchos::SerialDenseMatrix<LO,SC> > qFactor = qrSolver.getQ();
413 for (size_t j = 0; j < NSDim; j++)
414 for (size_t i = 0; i < Teuchos::as<size_t>(aggSize); i++)
415 localQR(i,j) = (*qFactor)(i,j);
416 }
417
418 } else {
419 // Special handling for aggSize < NSDim (i.e. single node aggregates in structural mechanics)
420
421 // The local QR decomposition is not possible in the "overconstrained"
422 // case (i.e. number of columns in localQR > number of rows), which
423 // corresponds to #DOFs in Aggregate < NSDim. For usual problems this
424 // is only possible for single node aggregates in structural mechanics.
425 // (Similar problems may arise in discontinuous Galerkin problems...)
426 // We bypass the QR decomposition and use an identity block in the
427 // tentative prolongator for the single node aggregate and transfer the
428 // corresponding fine level null space information 1-to-1 to the coarse
429 // level null space part.
430
431 // NOTE: The resulting tentative prolongation operator has
432 // (aggSize*DofsPerNode-NSDim) zero columns leading to a singular
433 // coarse level operator A. To deal with that one has the following
434 // options:
435 // - Use the "RepairMainDiagonal" flag in the RAPFactory (default:
436 // false) to add some identity block to the diagonal of the zero rows
437 // in the coarse level operator A, such that standard level smoothers
438 // can be used again.
439 // - Use special (projection-based) level smoothers, which can deal
440 // with singular matrices (very application specific)
441 // - Adapt the code below to avoid zero columns. However, we do not
442 // support a variable number of DOFs per node in MueLu/Xpetra which
443 // makes the implementation really hard.
444
445 // R = extended (by adding identity rows) localQR
446 for (size_t j = 0; j < NSDim; j++)
447 for (size_t k = 0; k < NSDim; k++)
448 if (k < as<size_t>(aggSize))
449 coarseNS[j][offset+k] = localQR(k,j);
450 else
451 coarseNS[j][offset+k] = (k == j ? one : zero);
452
453 // Q = I (rectangular)
454 for (size_t i = 0; i < as<size_t>(aggSize); i++)
455 for (size_t j = 0; j < NSDim; j++)
456 localQR(i,j) = (j == i ? one : zero);
457 }
458
459
460 // Process each row in the local Q factor
461 // FIXME: What happens if maps are blocked?
462 for (LO j = 0; j < aggSize; j++) {
463 LO localRow = (goodMap ? aggToRowMapLO[aggStart[agg]+j] : rowMap->getLocalElement(aggToRowMapGO[aggStart[agg]+j]));
464
465 size_t rowStart = ia[localRow];
466 for (size_t k = 0, lnnz = 0; k < NSDim; k++) {
467 // Skip zeros (there may be plenty of them, i.e., NSDim > 1 or boundary conditions)
468 if (localQR(j,k) != zero) {
469 ja [rowStart+lnnz] = offset + k;
470 val[rowStart+lnnz] = localQR(j,k);
471 lnnz++;
472 }
473 }
474 }
475 }
476
477 } else {
478 GetOStream(Runtime1) << "TentativePFactory : bypassing local QR phase" << std::endl;
479 if (NSDim>1)
480 GetOStream(Warnings0) << "TentativePFactory : for nontrivial nullspace, this may degrade performance" << std::endl;
482 // "no-QR" option //
484 // Local Q factor is just the fine nullspace support over the current aggregate.
485 // Local R factor is the identity.
486 // TODO I have not implemented any special handling for aggregates that are too
487 // TODO small to locally support the nullspace, as is done in the standard QR
488 // TODO case above.
489 if (goodMap) {
490 for (GO agg = 0; agg < numAggs; agg++) {
491 const LO aggSize = aggStart[agg+1] - aggStart[agg];
492 Xpetra::global_size_t offset = agg*NSDim;
493
494 // Process each row in the local Q factor
495 // FIXME: What happens if maps are blocked?
496 for (LO j = 0; j < aggSize; j++) {
497
498 //TODO Here I do not check for a zero nullspace column on the aggregate.
499 // as is done in the standard QR case.
500
501 const LO localRow = aggToRowMapLO[aggStart[agg]+j];
502
503 const size_t rowStart = ia[localRow];
504
505 for (size_t k = 0, lnnz = 0; k < NSDim; k++) {
506 // Skip zeros (there may be plenty of them, i.e., NSDim > 1 or boundary conditions)
507 SC qr_jk = fineNS[k][aggToRowMapLO[aggStart[agg]+j]];
508 if(constantColSums) qr_jk = qr_jk / (double)aggSizes[agg];
509 if (qr_jk != zero) {
510 ja [rowStart+lnnz] = offset + k;
511 val[rowStart+lnnz] = qr_jk;
512 lnnz++;
513 }
514 }
515 }
516 for (size_t j = 0; j < NSDim; j++)
517 coarseNS[j][offset+j] = one;
518 } //for (GO agg = 0; agg < numAggs; agg++)
519
520 } else {
521 for (GO agg = 0; agg < numAggs; agg++) {
522 const LO aggSize = aggStart[agg+1] - aggStart[agg];
523 Xpetra::global_size_t offset = agg*NSDim;
524 for (LO j = 0; j < aggSize; j++) {
525
526 const LO localRow = rowMap->getLocalElement(aggToRowMapGO[aggStart[agg]+j]);
527
528 const size_t rowStart = ia[localRow];
529
530 for (size_t k = 0, lnnz = 0; k < NSDim; ++k) {
531 // Skip zeros (there may be plenty of them, i.e., NSDim > 1 or boundary conditions)
532 SC qr_jk = fineNS[k][rowMap->getLocalElement(aggToRowMapGO[aggStart[agg]+j])];
533 if(constantColSums) qr_jk = qr_jk / (double)aggSizes[agg];
534 if (qr_jk != zero) {
535 ja [rowStart+lnnz] = offset + k;
536 val[rowStart+lnnz] = qr_jk;
537 lnnz++;
538 }
539 }
540 }
541 for (size_t j = 0; j < NSDim; j++)
542 coarseNS[j][offset+j] = one;
543 } //for (GO agg = 0; agg < numAggs; agg++)
544
545 } //if (goodmap) else ...
546
547 } //if doQRStep ... else
548
549 // Compress storage (remove all INVALID, which happen when we skip zeros)
550 // We do that in-place
551 size_t ia_tmp = 0, nnz = 0;
552 for (size_t i = 0; i < numRows; i++) {
553 for (size_t j = ia_tmp; j < ia[i+1]; j++)
554 if (ja[j] != INVALID) {
555 ja [nnz] = ja [j];
556 val[nnz] = val[j];
557 nnz++;
558 }
559 ia_tmp = ia[i+1];
560 ia[i+1] = nnz;
561 }
562 if (rowMap->lib() == Xpetra::UseTpetra) {
563 // - Cannot resize for Epetra, as it checks for same pointers
564 // - Need to resize for Tpetra, as it check ().size() == ia[numRows]
565 // NOTE: these invalidate ja and val views
566 jaPtent .resize(nnz);
567 valPtent.resize(nnz);
568 }
569
570 GetOStream(Runtime1) << "TentativePFactory : aggregates do not cross process boundaries" << std::endl;
571
572 PtentCrs->setAllValues(iaPtent, jaPtent, valPtent);
573
574
575 // Managing labels & constants for ESFC
576 RCP<ParameterList> FCparams;
577 if(pL.isSublist("matrixmatrix: kernel params"))
578 FCparams=rcp(new ParameterList(pL.sublist("matrixmatrix: kernel params")));
579 else
580 FCparams= rcp(new ParameterList);
581 // By default, we don't need global constants for TentativeP
582 FCparams->set("compute global constants",FCparams->get("compute global constants",false));
583 std::string levelIDs = toString(levelID);
584 FCparams->set("Timer Label",std::string("MueLu::TentativeP-")+levelIDs);
585 RCP<const Export> dummy_e;
586 RCP<const Import> dummy_i;
587
588 PtentCrs->expertStaticFillComplete(coarseMap, A->getDomainMap(),dummy_i,dummy_e,FCparams);
589 }
590
591 template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
593 BuildPcoupled(RCP<Matrix> A, RCP<Aggregates> aggregates, RCP<AmalgamationInfo> amalgInfo, RCP<MultiVector> fineNullspace,
594 RCP<const Map> coarseMap, RCP<Matrix>& Ptentative, RCP<MultiVector>& coarseNullspace) const {
595 typedef Teuchos::ScalarTraits<SC> STS;
596 typedef typename STS::magnitudeType Magnitude;
597 const SC zero = STS::zero();
598 const SC one = STS::one();
599
600 // number of aggregates
601 GO numAggs = aggregates->GetNumAggregates();
602
603 // Create a lookup table to determine the rows (fine DOFs) that belong to a given aggregate.
604 // aggStart is a pointer into aggToRowMap
605 // aggStart[i]..aggStart[i+1] are indices into aggToRowMap
606 // aggToRowMap[aggStart[i]]..aggToRowMap[aggStart[i+1]-1] are the DOFs in aggregate i
607 ArrayRCP<LO> aggStart;
608 ArrayRCP< GO > aggToRowMap;
609 amalgInfo->UnamalgamateAggregates(*aggregates, aggStart, aggToRowMap);
610
611 // find size of the largest aggregate
612 LO maxAggSize=0;
613 for (GO i=0; i<numAggs; ++i) {
614 LO sizeOfThisAgg = aggStart[i+1] - aggStart[i];
615 if (sizeOfThisAgg > maxAggSize) maxAggSize = sizeOfThisAgg;
616 }
617
618 // dimension of fine level nullspace
619 const size_t NSDim = fineNullspace->getNumVectors();
620
621 // index base for coarse Dof map (usually 0)
622 GO indexBase=A->getRowMap()->getIndexBase();
623
624 const RCP<const Map> nonUniqueMap = amalgInfo->ComputeUnamalgamatedImportDofMap(*aggregates);
625 const RCP<const Map> uniqueMap = A->getDomainMap();
626 RCP<const Import> importer = ImportFactory::Build(uniqueMap, nonUniqueMap);
627 RCP<MultiVector> fineNullspaceWithOverlap = MultiVectorFactory::Build(nonUniqueMap,NSDim);
628 fineNullspaceWithOverlap->doImport(*fineNullspace,*importer,Xpetra::INSERT);
629
630 // Pull out the nullspace vectors so that we can have random access.
631 ArrayRCP< ArrayRCP<const SC> > fineNS(NSDim);
632 for (size_t i=0; i<NSDim; ++i)
633 fineNS[i] = fineNullspaceWithOverlap->getData(i);
634
635 //Allocate storage for the coarse nullspace.
636 coarseNullspace = MultiVectorFactory::Build(coarseMap, NSDim);
637
638 ArrayRCP< ArrayRCP<SC> > coarseNS(NSDim);
639 for (size_t i=0; i<NSDim; ++i)
640 if (coarseMap->getNodeNumElements() > 0) coarseNS[i] = coarseNullspace->getDataNonConst(i);
641
642 //This makes the rowmap of Ptent the same as that of A->
643 //This requires moving some parts of some local Q's to other processors
644 //because aggregates can span processors.
645 RCP<const Map > rowMapForPtent = A->getRowMap();
646 const Map& rowMapForPtentRef = *rowMapForPtent;
647
648 // Set up storage for the rows of the local Qs that belong to other processors.
649 // FIXME This is inefficient and could be done within the main loop below with std::vector's.
650 RCP<const Map> colMap = A->getColMap();
651
652 RCP<const Map > ghostQMap;
653 RCP<MultiVector> ghostQvalues;
654 Array<RCP<Xpetra::Vector<GO,LO,GO,Node> > > ghostQcolumns;
655 RCP<Xpetra::Vector<GO,LO,GO,Node> > ghostQrowNums;
656 ArrayRCP< ArrayRCP<SC> > ghostQvals;
657 ArrayRCP< ArrayRCP<GO> > ghostQcols;
658 ArrayRCP< GO > ghostQrows;
659
660 Array<GO> ghostGIDs;
661 for (LO j=0; j<numAggs; ++j) {
662 for (LO k=aggStart[j]; k<aggStart[j+1]; ++k) {
663 if (rowMapForPtentRef.isNodeGlobalElement(aggToRowMap[k]) == false) {
664 ghostGIDs.push_back(aggToRowMap[k]);
665 }
666 }
667 }
668 ghostQMap = MapFactory::Build(A->getRowMap()->lib(),
669 Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),
670 ghostGIDs,
671 indexBase, A->getRowMap()->getComm()); //JG:Xpetra::global_size_t>?
672 //Vector to hold bits of Q that go to other processors.
673 ghostQvalues = MultiVectorFactory::Build(ghostQMap,NSDim);
674 //Note that Epetra does not support MultiVectors templated on Scalar != double.
675 //So to work around this, we allocate an array of Vectors. This shouldn't be too
676 //expensive, as the number of Vectors is NSDim.
677 ghostQcolumns.resize(NSDim);
678 for (size_t i=0; i<NSDim; ++i)
679 ghostQcolumns[i] = Xpetra::VectorFactory<GO,LO,GO,Node>::Build(ghostQMap);
680 ghostQrowNums = Xpetra::VectorFactory<GO,LO,GO,Node>::Build(ghostQMap);
681 if (ghostQvalues->getLocalLength() > 0) {
682 ghostQvals.resize(NSDim);
683 ghostQcols.resize(NSDim);
684 for (size_t i=0; i<NSDim; ++i) {
685 ghostQvals[i] = ghostQvalues->getDataNonConst(i);
686 ghostQcols[i] = ghostQcolumns[i]->getDataNonConst(0);
687 }
688 ghostQrows = ghostQrowNums->getDataNonConst(0);
689 }
690
691 //importer to handle moving Q
692 importer = ImportFactory::Build(ghostQMap, A->getRowMap());
693
694 // Dense QR solver
695 Teuchos::SerialQRDenseSolver<LO,SC> qrSolver;
696
697 //Allocate temporary storage for the tentative prolongator.
698 Array<GO> globalColPtr(maxAggSize*NSDim,0);
699 Array<LO> localColPtr(maxAggSize*NSDim,0);
700 Array<SC> valPtr(maxAggSize*NSDim,0.);
701
702 //Create column map for Ptent, estimate local #nonzeros in Ptent, and create Ptent itself.
703 const Map& coarseMapRef = *coarseMap;
704
705 // For the 3-arrays constructor
706 ArrayRCP<size_t> ptent_rowptr;
707 ArrayRCP<LO> ptent_colind;
708 ArrayRCP<Scalar> ptent_values;
709
710 // Because ArrayRCPs are slow...
711 ArrayView<size_t> rowptr_v;
712 ArrayView<LO> colind_v;
713 ArrayView<Scalar> values_v;
714
715 // For temporary usage
716 Array<size_t> rowptr_temp;
717 Array<LO> colind_temp;
718 Array<Scalar> values_temp;
719
720 RCP<CrsMatrix> PtentCrs;
721
722 RCP<CrsMatrixWrap> PtentCrsWrap = rcp(new CrsMatrixWrap(rowMapForPtent, NSDim));
723 PtentCrs = PtentCrsWrap->getCrsMatrix();
724 Ptentative = PtentCrsWrap;
725
726 //*****************************************************************
727 //Loop over all aggregates and calculate local QR decompositions.
728 //*****************************************************************
729 GO qctr=0; //for indexing into Ptent data vectors
730 const Map& nonUniqueMapRef = *nonUniqueMap;
731
732 size_t total_nnz_count=0;
733
734 for (GO agg=0; agg<numAggs; ++agg)
735 {
736 LO myAggSize = aggStart[agg+1]-aggStart[agg];
737 // For each aggregate, extract the corresponding piece of the nullspace and put it in the flat array,
738 // "localQR" (in column major format) for the QR routine.
739 Teuchos::SerialDenseMatrix<LO,SC> localQR(myAggSize, NSDim);
740 for (size_t j=0; j<NSDim; ++j) {
741 bool bIsZeroNSColumn = true;
742 for (LO k=0; k<myAggSize; ++k)
743 {
744 // aggToRowMap[aggPtr[i]+k] is the kth DOF in the ith aggregate
745 // fineNS[j][n] is the nth entry in the jth NS vector
746 try{
747 SC nsVal = fineNS[j][ nonUniqueMapRef.getLocalElement(aggToRowMap[aggStart[agg]+k]) ]; // extract information from fine level NS
748 localQR(k,j) = nsVal;
749 if (nsVal != zero) bIsZeroNSColumn = false;
750 }
751 catch(...) {
752 GetOStream(Runtime1,-1) << "length of fine level nsp: " << fineNullspace->getGlobalLength() << std::endl;
753 GetOStream(Runtime1,-1) << "length of fine level nsp w overlap: " << fineNullspaceWithOverlap->getGlobalLength() << std::endl;
754 GetOStream(Runtime1,-1) << "(local?) aggId=" << agg << std::endl;
755 GetOStream(Runtime1,-1) << "aggSize=" << myAggSize << std::endl;
756 GetOStream(Runtime1,-1) << "agg DOF=" << k << std::endl;
757 GetOStream(Runtime1,-1) << "NS vector j=" << j << std::endl;
758 GetOStream(Runtime1,-1) << "j*myAggSize + k = " << j*myAggSize + k << std::endl;
759 GetOStream(Runtime1,-1) << "aggToRowMap["<<agg<<"][" << k << "] = " << aggToRowMap[aggStart[agg]+k] << std::endl;
760 GetOStream(Runtime1,-1) << "id aggToRowMap[agg][k]=" << aggToRowMap[aggStart[agg]+k] << " is global element in nonUniqueMap = " <<
761 nonUniqueMapRef.isNodeGlobalElement(aggToRowMap[aggStart[agg]+k]) << std::endl;
762 GetOStream(Runtime1,-1) << "colMap local id aggToRowMap[agg][k]=" << nonUniqueMapRef.getLocalElement(aggToRowMap[aggStart[agg]+k]) << std::endl;
763 GetOStream(Runtime1,-1) << "fineNS...=" << fineNS[j][ nonUniqueMapRef.getLocalElement(aggToRowMap[aggStart[agg]+k]) ] << std::endl;
764 GetOStream(Errors,-1) << "caught an error!" << std::endl;
765 }
766 } //for (LO k=0 ...
767 TEUCHOS_TEST_FOR_EXCEPTION(bIsZeroNSColumn == true, Exceptions::RuntimeError, "MueLu::TentativePFactory::MakeTentative: fine level NS part has a zero column. Error.");
768 } //for (LO j=0 ...
769
770 Xpetra::global_size_t offset=agg*NSDim;
771
772 if(myAggSize >= Teuchos::as<LocalOrdinal>(NSDim)) {
773 // calculate QR decomposition (standard)
774 // R is stored in localQR (size: myAggSize x NSDim)
775
776 // Householder multiplier
777 SC tau = localQR(0,0);
778
779 if (NSDim == 1) {
780 // Only one nullspace vector, so normalize by hand
781 Magnitude dtemp=0;
782 for (size_t k = 0; k < Teuchos::as<size_t>(myAggSize); ++k) {
783 Magnitude tmag = STS::magnitude(localQR(k,0));
784 dtemp += tmag*tmag;
785 }
786 dtemp = Teuchos::ScalarTraits<Magnitude>::squareroot(dtemp);
787 tau = localQR(0,0);
788 localQR(0,0) = dtemp;
789 } else {
790 qrSolver.setMatrix( Teuchos::rcp(&localQR, false) );
791 qrSolver.factor();
792 }
793
794 // Extract R, the coarse nullspace. This is stored in upper triangular part of localQR.
795 // Note: coarseNS[i][.] is the ith coarse nullspace vector, which may be counter to your intuition.
796 // This stores the (offset+k)th entry only if it is local according to the coarseMap.
797 for (size_t j=0; j<NSDim; ++j) {
798 for (size_t k=0; k<=j; ++k) {
799 try {
800 if (coarseMapRef.isNodeLocalElement(offset+k)) {
801 coarseNS[j][offset+k] = localQR(k, j); //TODO is offset+k the correct local ID?!
802 }
803 }
804 catch(...) {
805 GetOStream(Errors,-1) << "caught error in coarseNS insert, j="<<j<<", offset+k = "<<offset+k<<std::endl;
806 }
807 }
808 }
809
810 // Calculate Q, the tentative prolongator.
811 // The Lapack GEQRF call only works for myAggsize >= NSDim
812
813 if (NSDim == 1) {
814 // Only one nullspace vector, so calculate Q by hand
815 Magnitude dtemp = Teuchos::ScalarTraits<SC>::magnitude(localQR(0,0));
816 localQR(0,0) = tau;
817 dtemp = 1 / dtemp;
818 for (LocalOrdinal i=0; i<myAggSize; ++i) {
819 localQR(i,0) *= dtemp ;
820 }
821 } else {
822 qrSolver.formQ();
823 Teuchos::RCP<Teuchos::SerialDenseMatrix<LO,SC> > qFactor = qrSolver.getQ();
824 for (size_t j=0; j<NSDim; j++) {
825 for (size_t i = 0; i < Teuchos::as<size_t>(myAggSize); i++) {
826 localQR(i,j) = (*qFactor)(i,j);
827 }
828 }
829 }
830
831 // end default case (myAggSize >= NSDim)
832 } else { // special handling for myAggSize < NSDim (i.e. 1pt nodes)
833 // See comments for the uncoupled case
834
835 // R = extended (by adding identity rows) localQR
836 for (size_t j = 0; j < NSDim; j++)
837 for (size_t k = 0; k < NSDim; k++) {
838 TEUCHOS_TEST_FOR_EXCEPTION(!coarseMapRef.isNodeLocalElement(offset+k), Exceptions::RuntimeError,
839 "Caught error in coarseNS insert, j=" << j << ", offset+k = " << offset+k);
840
841 if (k < as<size_t>(myAggSize))
842 coarseNS[j][offset+k] = localQR(k,j);
843 else
844 coarseNS[j][offset+k] = (k == j ? one : zero);
845 }
846
847 // Q = I (rectangular)
848 for (size_t i = 0; i < as<size_t>(myAggSize); i++)
849 for (size_t j = 0; j < NSDim; j++)
850 localQR(i,j) = (j == i ? one : zero);
851 } // end else (special handling for 1pt aggregates)
852
853 //Process each row in the local Q factor. If the row is local to the current processor
854 //according to the rowmap, insert it into Ptentative. Otherwise, save it in ghostQ
855 //to be communicated later to the owning processor.
856 //FIXME -- what happens if maps are blocked?
857 for (GO j=0; j<myAggSize; ++j) {
858 //This loop checks whether row associated with current DOF is local, according to rowMapForPtent.
859 //If it is, the row is inserted. If not, the row number, columns, and values are saved in
860 //MultiVectors that will be sent to other processors.
861 GO globalRow = aggToRowMap[aggStart[agg]+j];
862
863 //TODO is the use of Xpetra::global_size_t below correct?
864 if (rowMapForPtentRef.isNodeGlobalElement(globalRow) == false ) {
865 ghostQrows[qctr] = globalRow;
866 for (size_t k=0; k<NSDim; ++k) {
867 ghostQcols[k][qctr] = coarseMapRef.getGlobalElement(agg*NSDim+k);
868 ghostQvals[k][qctr] = localQR(j,k);
869 }
870 ++qctr;
871 } else {
872 size_t nnz=0;
873 for (size_t k=0; k<NSDim; ++k) {
874 try{
875 if (localQR(j,k) != Teuchos::ScalarTraits<SC>::zero()) {
876 localColPtr[nnz] = agg * NSDim + k;
877 globalColPtr[nnz] = coarseMapRef.getGlobalElement(localColPtr[nnz]);
878 valPtr[nnz] = localQR(j,k);
879 ++total_nnz_count;
880 ++nnz;
881 }
882 }
883 catch(...) {
884 GetOStream(Errors,-1) << "caught error in colPtr/valPtr insert, current index="<<nnz<<std::endl;
885 }
886 } //for (size_t k=0; k<NSDim; ++k)
887
888 try{
889 Ptentative->insertGlobalValues(globalRow,globalColPtr.view(0,nnz),valPtr.view(0,nnz));
890 }
891 catch(...) {
892 GetOStream(Errors,-1) << "pid " << A->getRowMap()->getComm()->getRank()
893 << "caught error during Ptent row insertion, global row "
894 << globalRow << std::endl;
895 }
896 }
897 } //for (GO j=0; j<myAggSize; ++j)
898
899 } // for (LO agg=0; agg<numAggs; ++agg)
900
901
902 // ***********************************************************
903 // ************* end of aggregate-wise QR ********************
904 // ***********************************************************
905 GetOStream(Runtime1) << "TentativePFactory : aggregates may cross process boundaries" << std::endl;
906 // Import ghost parts of Q factors and insert into Ptentative.
907 // First import just the global row numbers.
908 RCP<Xpetra::Vector<GO,LO,GO,Node> > targetQrowNums = Xpetra::VectorFactory<GO,LO,GO,Node>::Build(rowMapForPtent);
909 targetQrowNums->putScalar(-1);
910 targetQrowNums->doImport(*ghostQrowNums,*importer,Xpetra::INSERT);
911 ArrayRCP< GO > targetQrows = targetQrowNums->getDataNonConst(0);
912
913 // Now create map based on just the row numbers imported.
914 Array<GO> gidsToImport;
915 gidsToImport.reserve(targetQrows.size());
916 for (typename ArrayRCP<GO>::iterator r=targetQrows.begin(); r!=targetQrows.end(); ++r) {
917 if (*r > -1) {
918 gidsToImport.push_back(*r);
919 }
920 }
921 RCP<const Map > reducedMap = MapFactory::Build( A->getRowMap()->lib(),
922 Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),
923 gidsToImport, indexBase, A->getRowMap()->getComm() );
924
925 // Import using the row numbers that this processor will receive.
926 importer = ImportFactory::Build(ghostQMap, reducedMap);
927
928 Array<RCP<Xpetra::Vector<GO,LO,GO,Node> > > targetQcolumns(NSDim);
929 for (size_t i=0; i<NSDim; ++i) {
930 targetQcolumns[i] = Xpetra::VectorFactory<GO,LO,GO,Node>::Build(reducedMap);
931 targetQcolumns[i]->doImport(*(ghostQcolumns[i]),*importer,Xpetra::INSERT);
932 }
933 RCP<MultiVector> targetQvalues = MultiVectorFactory::Build(reducedMap,NSDim);
934 targetQvalues->doImport(*ghostQvalues,*importer,Xpetra::INSERT);
935
936 ArrayRCP< ArrayRCP<SC> > targetQvals;
937 ArrayRCP<ArrayRCP<GO> > targetQcols;
938 if (targetQvalues->getLocalLength() > 0) {
939 targetQvals.resize(NSDim);
940 targetQcols.resize(NSDim);
941 for (size_t i=0; i<NSDim; ++i) {
942 targetQvals[i] = targetQvalues->getDataNonConst(i);
943 targetQcols[i] = targetQcolumns[i]->getDataNonConst(0);
944 }
945 }
946
947 valPtr = Array<SC>(NSDim,0.);
948 globalColPtr = Array<GO>(NSDim,0);
949 for (typename Array<GO>::iterator r=gidsToImport.begin(); r!=gidsToImport.end(); ++r) {
950 if (targetQvalues->getLocalLength() > 0) {
951 for (size_t j=0; j<NSDim; ++j) {
952 valPtr[j] = targetQvals[j][reducedMap->getLocalElement(*r)];
953 globalColPtr[j] = targetQcols[j][reducedMap->getLocalElement(*r)];
954 }
955 Ptentative->insertGlobalValues(*r, globalColPtr.view(0,NSDim), valPtr.view(0,NSDim));
956 } //if (targetQvalues->getLocalLength() > 0)
957 }
958
959 Ptentative->fillComplete(coarseMap, A->getDomainMap());
960 }
961
962
963
964} //namespace MueLu
965
966// TODO ReUse: If only P or Nullspace is missing, TentativePFactory can be smart and skip part of the computation.
967
968#define MUELU_TENTATIVEPFACTORY_SHORT
969#endif // MUELU_TENTATIVEPFACTORY_DEF_HPP
#define SET_VALID_ENTRY(name)
MueLu::DefaultLocalOrdinal LocalOrdinal
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
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
static const NoFactory * get()
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void BuildPuncoupled(RCP< Matrix > A, RCP< Aggregates > aggregates, RCP< AmalgamationInfo > amalgInfo, RCP< MultiVector > fineNullspace, RCP< const Map > coarseMap, RCP< Matrix > &Ptentative, RCP< MultiVector > &coarseNullspace, const int levelID) const
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
void BuildPcoupled(RCP< Matrix > A, RCP< Aggregates > aggregates, RCP< AmalgamationInfo > amalgInfo, RCP< MultiVector > fineNullspace, RCP< const Map > coarseMap, RCP< Matrix > &Ptentative, RCP< MultiVector > &coarseNullspace) const
static bool MapsAreNested(const Xpetra::Map< DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &rowMap, const Xpetra::Map< DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &colMap)
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line)
@ Statistics2
Print even more statistics.
@ Errors
Errors.
@ Runtime1
Description of what is happening (more verbose)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.