93 RCP<Teuchos::FancyOStream> out;
94 if (
const char* dbg = std::getenv(
"MUELU_GEOMETRICINTERPOLATIONPFACTORY_DEBUG")) {
95 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
96 out->setShowAllFrontMatter(
false).setShowProcRank(
true);
98 out = Teuchos::getFancyOStream(rcp(
new Teuchos::oblackholestream()));
101 *out <<
"Starting GeometricInterpolationPFactory::BuildP." << std::endl;
104 const ParameterList& pL = GetParameterList();
106 const bool buildCoarseCoordinates = pL.get<
bool>(
"interp: build coarse coordinates");
107 const int interpolationOrder = Get<int>(fineLevel,
"structuredInterpolationOrder");
108 const int numDimensions = Get<int>(fineLevel,
"numDimensions");
111 RCP<Matrix> A = Get<RCP<Matrix> >(fineLevel,
"A");
112 RCP<const CrsGraph> prolongatorGraph = Get<RCP<CrsGraph> >(fineLevel,
"prolongatorGraph");
113 RCP<realvaluedmultivector_type> fineCoordinates, coarseCoordinates;
118 if (buildCoarseCoordinates || (interpolationOrder == 1)) {
120 RCP<const Map> coarseCoordsFineMap = Get<RCP<const Map> >(fineLevel,
"coarseCoordinatesFineMap");
121 RCP<const Map> coarseCoordsMap = Get<RCP<const Map> >(fineLevel,
"coarseCoordinatesMap");
123 fineCoordinates = Get<RCP<realvaluedmultivector_type> >(fineLevel,
"Coordinates");
124 coarseCoordinates = Xpetra::MultiVectorFactory<real_type, LO, GO, Node>::Build(coarseCoordsFineMap,
125 fineCoordinates->getNumVectors());
126 RCP<const Import> coordsImporter = ImportFactory::Build(fineCoordinates->getMap(),
127 coarseCoordsFineMap);
128 coarseCoordinates->doImport(*fineCoordinates, *coordsImporter, Xpetra::INSERT);
129 coarseCoordinates->replaceMap(coarseCoordsMap);
131 Set(coarseLevel,
"Coordinates", coarseCoordinates);
133 if (pL.get<
bool>(
"keep coarse coords")) {
134 coarseLevel.
Set<RCP<realvaluedmultivector_type> >(
"Coordinates2", coarseCoordinates,
NoFactory::get());
138 *out <<
"Fine and coarse coordinates have been loaded from the fine level and set on the coarse level." << std::endl;
140 if (interpolationOrder == 0) {
143 BuildConstantP(P, prolongatorGraph, A);
144 }
else if (interpolationOrder == 1) {
147 RCP<const Map> prolongatorColMap = prolongatorGraph->getColMap();
149 const size_t dofsPerNode =
static_cast<size_t>(A->GetFixedBlockSize());
150 const size_t numColIndices = prolongatorColMap->getLocalNumElements();
151 TEUCHOS_TEST_FOR_EXCEPTION((numColIndices % dofsPerNode) != 0,
153 "Something went wrong, the number of columns in the prolongator is not a multiple of dofsPerNode!");
154 const size_t numGhostCoords = numColIndices / dofsPerNode;
155 const GO indexBase = prolongatorColMap->getIndexBase();
156 const GO coordIndexBase = fineCoordinates->getMap()->getIndexBase();
158 ArrayView<const GO> prolongatorColIndices = prolongatorColMap->getLocalElementList();
159 Array<GO> ghostCoordIndices(numGhostCoords);
160 for (
size_t ghostCoordIdx = 0; ghostCoordIdx < numGhostCoords; ++ghostCoordIdx) {
161 ghostCoordIndices[ghostCoordIdx] = (prolongatorColIndices[ghostCoordIdx * dofsPerNode] - indexBase) / dofsPerNode + coordIndexBase;
163 RCP<Map> ghostCoordMap = MapFactory::Build(fineCoordinates->getMap()->lib(),
164 prolongatorColMap->getGlobalNumElements() / dofsPerNode,
167 fineCoordinates->getMap()->getComm());
169 RCP<realvaluedmultivector_type> ghostCoordinates = Xpetra::MultiVectorFactory<real_type, LO, GO, NO>::Build(ghostCoordMap,
170 fineCoordinates->getNumVectors());
171 RCP<const Import> ghostImporter = ImportFactory::Build(coarseCoordinates->getMap(),
173 ghostCoordinates->doImport(*coarseCoordinates, *ghostImporter, Xpetra::INSERT);
175 BuildLinearP(coarseLevel, A, prolongatorGraph, fineCoordinates,
179 *out <<
"The prolongator matrix has been built." << std::endl;
184 RCP<MultiVector> fineNullspace = Get<RCP<MultiVector> >(fineLevel,
"Nullspace");
185 RCP<MultiVector> coarseNullspace = MultiVectorFactory::Build(P->getDomainMap(),
186 fineNullspace->getNumVectors());
188 using helpers = Xpetra::Helpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
189 if (helpers::isTpetraBlockCrs(A)) {
192 Ptrans->apply(*fineNullspace, *coarseNullspace, Teuchos::NO_TRANS, Teuchos::ScalarTraits<SC>::one(),
193 Teuchos::ScalarTraits<SC>::zero());
195 P->apply(*fineNullspace, *coarseNullspace, Teuchos::TRANS, Teuchos::ScalarTraits<SC>::one(),
196 Teuchos::ScalarTraits<SC>::zero());
199 Set(coarseLevel,
"Nullspace", coarseNullspace);
202 *out <<
"The coarse nullspace is constructed and set on the coarse level." << std::endl;
204 Set(coarseLevel,
"P", P);
206 *out <<
"GeometricInterpolationPFactory::BuildP has completed." << std::endl;
212 BuildConstantP(RCP<Matrix>& P, RCP<const CrsGraph>& prolongatorGraph, RCP<Matrix>& A)
const {
214 RCP<Teuchos::FancyOStream> out;
215 if (
const char* dbg = std::getenv(
"MUELU_GEOMETRICINTERPOLATIONPFACTORY_DEBUG")) {
216 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
217 out->setShowAllFrontMatter(
false).setShowProcRank(
true);
219 out = Teuchos::getFancyOStream(rcp(
new Teuchos::oblackholestream()));
222 *out <<
"BuildConstantP" << std::endl;
224 std::vector<size_t> strideInfo(1);
225 strideInfo[0] = A->GetFixedBlockSize();
226 RCP<const StridedMap> stridedDomainMap =
227 StridedMapFactory::Build(prolongatorGraph->getDomainMap(), strideInfo);
229 *out <<
"Call prolongator constructor" << std::endl;
231 using helpers = Xpetra::Helpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
232 if (helpers::isTpetraBlockCrs(A)) {
233 SC one = Teuchos::ScalarTraits<SC>::one();
234 SC zero = Teuchos::ScalarTraits<SC>::zero();
235 LO NSDim = A->GetStorageBlockSize();
238 RCP<const Map> BlockMap = prolongatorGraph->getDomainMap();
239 Teuchos::ArrayView<const GO> block_dofs = BlockMap->getLocalElementList();
240 Teuchos::Array<GO> point_dofs(block_dofs.size() * NSDim);
241 for (LO i = 0, ct = 0; i < block_dofs.size(); i++) {
242 for (LO j = 0; j < NSDim; j++) {
243 point_dofs[ct] = block_dofs[i] * NSDim + j;
248 RCP<const Map> PointMap = MapFactory::Build(BlockMap->lib(),
249 BlockMap->getGlobalNumElements() * NSDim,
251 BlockMap->getIndexBase(),
252 BlockMap->getComm());
253 strideInfo[0] = A->GetFixedBlockSize();
254 RCP<const StridedMap> stridedPointMap = StridedMapFactory::Build(PointMap, strideInfo);
256 RCP<Xpetra::CrsMatrix<SC, LO, GO, NO> > P_xpetra = Xpetra::CrsMatrixFactory<SC, LO, GO, NO>::BuildBlock(prolongatorGraph, PointMap, A->getRangeMap(), NSDim);
257 RCP<Xpetra::TpetraBlockCrsMatrix<SC, LO, GO, NO> > P_tpetra = rcp_dynamic_cast<Xpetra::TpetraBlockCrsMatrix<SC, LO, GO, NO> >(P_xpetra);
258 if (P_tpetra.is_null())
throw std::runtime_error(
"BuildConstantP Matrix factory did not return a Tpetra::BlockCrsMatrix");
259 RCP<CrsMatrixWrap> P_wrap = rcp(
new CrsMatrixWrap(P_xpetra));
262 Teuchos::Array<LO> temp(1);
263 Teuchos::ArrayView<const LO> indices;
264 Teuchos::Array<Scalar> block(NSDim * NSDim, zero);
265 for (LO i = 0; i < NSDim; i++)
266 block[i * NSDim + i] = one;
267 for (LO i = 0; i < (int)prolongatorGraph->getLocalNumRows(); i++) {
268 prolongatorGraph->getLocalRowView(i, indices);
269 for (LO j = 0; j < (LO)indices.size(); j++) {
270 temp[0] = indices[j];
271 P_tpetra->replaceLocalValues(i, temp(), block());
276 if (A->IsView(
"stridedMaps") ==
true) {
277 P->CreateView(
"stridedMaps", A->getRowMap(
"stridedMaps"), stridedPointMap);
281 RCP<ParameterList> dummyList = rcp(
new ParameterList());
282 P = rcp(
new CrsMatrixWrap(prolongatorGraph, dummyList));
283 RCP<CrsMatrix> PCrs = toCrsMatrix(P);
284 PCrs->setAllToScalar(1.0);
285 PCrs->fillComplete();
288 if (A->IsView(
"stridedMaps") ==
true)
289 P->CreateView(
"stridedMaps", A->getRowMap(
"stridedMaps"), stridedDomainMap);
297 RCP<Matrix>& A, RCP<const CrsGraph>& prolongatorGraph,
298 RCP<realvaluedmultivector_type>& fineCoordinates,
299 RCP<realvaluedmultivector_type>& ghostCoordinates,
301 RCP<Matrix>& P)
const {
303 RCP<Teuchos::FancyOStream> out;
304 if (
const char* dbg = std::getenv(
"MUELU_GEOMETRICINTERPOLATIONPFACTORY_DEBUG")) {
305 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
306 out->setShowAllFrontMatter(
false).setShowProcRank(
true);
308 out = Teuchos::getFancyOStream(rcp(
new Teuchos::oblackholestream()));
312 const int numInterpolationPoints = 1 << numDimensions;
313 const int dofsPerNode = A->GetFixedBlockSize() / A->GetStorageBlockSize();
316 RCP<ParameterList> dummyList = rcp(
new ParameterList());
317 P = rcp(
new CrsMatrixWrap(prolongatorGraph, dummyList));
318 RCP<CrsMatrix> PCrs = toCrsMatrix(P);
322 *out <<
"Entering BuildLinearP" << std::endl;
326 const LO numFineNodes = fineCoordinates->getLocalLength();
327 const LO numGhostNodes = ghostCoordinates->getLocalLength();
328 Array<ArrayRCP<const real_type> > fineCoords(3);
329 Array<ArrayRCP<const real_type> > ghostCoords(3);
330 const real_type realZero = Teuchos::as<real_type>(0.0);
331 ArrayRCP<real_type> fineZero(numFineNodes, realZero);
332 ArrayRCP<real_type> ghostZero(numGhostNodes, realZero);
333 for (
int dim = 0; dim < 3; ++dim) {
334 if (dim < numDimensions) {
335 fineCoords[dim] = fineCoordinates->getData(dim);
336 ghostCoords[dim] = ghostCoordinates->getData(dim);
338 fineCoords[dim] = fineZero;
339 ghostCoords[dim] = ghostZero;
343 *out <<
"Coordinates extracted from the multivectors!" << std::endl;
346 LO interpolationNodeIdx = 0, rowIdx = 0;
347 ArrayView<const LO> colIndices;
349 Array<Array<real_type> > coords(numInterpolationPoints + 1);
350 Array<real_type> stencil(numInterpolationPoints);
351 for (LO nodeIdx = 0; nodeIdx < numFineNodes; ++nodeIdx) {
352 if (PCrs->getNumEntriesInLocalRow(nodeIdx * dofsPerNode) == 1) {
355 for (LO dof = 0; dof < dofsPerNode; ++dof) {
356 rowIdx = nodeIdx * dofsPerNode + dof;
357 prolongatorGraph->getLocalRowView(rowIdx, colIndices);
358 PCrs->replaceLocalValues(rowIdx, colIndices, values());
364 for (
int dim = 0; dim < 3; ++dim) {
365 coords[0][dim] = fineCoords[dim][nodeIdx];
367 prolongatorGraph->getLocalRowView(nodeIdx * dofsPerNode, colIndices);
368 for (
int interpolationIdx = 0; interpolationIdx < numInterpolationPoints; ++interpolationIdx) {
369 coords[interpolationIdx + 1].resize(3);
370 interpolationNodeIdx = colIndices[interpolationIdx] / dofsPerNode;
371 for (
int dim = 0; dim < 3; ++dim) {
372 coords[interpolationIdx + 1][dim] = ghostCoords[dim][interpolationNodeIdx];
375 RCP<Teuchos::TimeMonitor> tm = rcp(
new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(
"Compute Linear Interpolation")));
376 ComputeLinearInterpolationStencil(numDimensions, numInterpolationPoints, coords, stencil);
378 values.resize(numInterpolationPoints);
379 for (LO valueIdx = 0; valueIdx < numInterpolationPoints; ++valueIdx) {
380 values[valueIdx] = Teuchos::as<SC>(stencil[valueIdx]);
384 for (LO dof = 0; dof < dofsPerNode; ++dof) {
385 rowIdx = nodeIdx * dofsPerNode + dof;
386 prolongatorGraph->getLocalRowView(rowIdx, colIndices);
387 PCrs->replaceLocalValues(rowIdx, colIndices, values());
393 *out <<
"The calculation of the interpolation stencils has completed." << std::endl;
395 PCrs->fillComplete();
398 *out <<
"All values in P have been set and fillComplete has been performed." << std::endl;
407 *out <<
"Entering remove small entries" << std::endl;
410 ArrayRCP<const size_t> rowptrOrig;
411 ArrayRCP<const LO> colindOrig;
412 ArrayRCP<const Scalar> valuesOrig;
413 PCrs->getAllValues(rowptrOrig, colindOrig, valuesOrig);
415 const size_t numRows =
static_cast<size_t>(rowptrOrig.size() - 1);
416 ArrayRCP<size_t> rowPtr(numRows + 1);
417 ArrayRCP<size_t> nnzOnRows(numRows);
419 size_t countRemovedEntries = 0;
420 for (
size_t rowIdx = 0; rowIdx < numRows; ++rowIdx) {
421 for (
size_t entryIdx = rowptrOrig[rowIdx]; entryIdx < rowptrOrig[rowIdx + 1]; ++entryIdx) {
422 if (Teuchos::ScalarTraits<Scalar>::magnitude(valuesOrig[entryIdx]) < 1e-6) {
423 ++countRemovedEntries;
426 rowPtr[rowIdx + 1] = rowptrOrig[rowIdx + 1] - countRemovedEntries;
427 nnzOnRows[rowIdx] = rowPtr[rowIdx + 1] - rowPtr[rowIdx];
429 GetOStream(
Statistics1) <<
"interp: number of small entries removed= " << countRemovedEntries <<
" / " << rowptrOrig[numRows] << std::endl;
431 size_t countKeptEntries = 0;
432 ArrayRCP<LO> colInd(rowPtr[numRows]);
433 ArrayRCP<SC> values(rowPtr[numRows]);
434 for (
size_t entryIdx = 0; entryIdx < rowptrOrig[numRows]; ++entryIdx) {
435 if (Teuchos::ScalarTraits<Scalar>::magnitude(valuesOrig[entryIdx]) > 1e-6) {
436 colInd[countKeptEntries] = colindOrig[entryIdx];
437 values[countKeptEntries] = valuesOrig[entryIdx];
442 P = rcp(
new CrsMatrixWrap(prolongatorGraph->getRowMap(),
443 prolongatorGraph->getColMap(),
445 RCP<CrsMatrix> PCrsSqueezed = toCrsMatrix(P);
446 PCrsSqueezed->resumeFill();
447 PCrsSqueezed->setAllValues(rowPtr, colInd, values);
448 PCrsSqueezed->expertStaticFillComplete(prolongatorGraph->getDomainMap(),
449 prolongatorGraph->getRangeMap());
452 std::vector<size_t> strideInfo(1);
453 strideInfo[0] = dofsPerNode;
454 RCP<const StridedMap> stridedDomainMap =
455 StridedMapFactory::Build(prolongatorGraph->getDomainMap(), strideInfo);
457 *out <<
"The strided maps of P have been computed" << std::endl;
460 if (A->IsView(
"stridedMaps") ==
true) {
461 P->CreateView(
"stridedMaps", A->getRowMap(
"stridedMaps"), stridedDomainMap);
469 const Array<Array<real_type> > coord,
470 Array<real_type>& stencil)
const {
486 Teuchos::SerialDenseMatrix<LO, real_type> Jacobian(numDimensions, numDimensions);
487 Teuchos::SerialDenseVector<LO, real_type> residual(numDimensions);
488 Teuchos::SerialDenseVector<LO, real_type> solutionDirection(numDimensions);
489 Teuchos::SerialDenseVector<LO, real_type> paramCoords(numDimensions);
490 Teuchos::SerialDenseSolver<LO, real_type> problem;
491 int iter = 0, max_iter = 5;
492 real_type functions[4][8], norm_ref = 1.0, norm2 = 1.0, tol = 1.0e-5;
493 paramCoords.size(numDimensions);
495 while ((iter < max_iter) && (norm2 > tol * norm_ref)) {
498 solutionDirection.size(numDimensions);
499 residual.size(numDimensions);
503 GetInterpolationFunctions(numDimensions, paramCoords, functions);
504 for (LO i = 0; i < numDimensions; ++i) {
505 residual(i) = coord[0][i];
506 for (LO k = 0; k < numInterpolationPoints; ++k) {
507 residual(i) -= functions[0][k] * coord[k + 1][i];
510 norm_ref += residual(i) * residual(i);
511 if (i == numDimensions - 1) {
512 norm_ref = std::sqrt(norm_ref);
516 for (LO j = 0; j < numDimensions; ++j) {
517 for (LO k = 0; k < numInterpolationPoints; ++k) {
518 Jacobian(i, j) += functions[j + 1][k] * coord[k + 1][i];
524 problem.setMatrix(Teuchos::rcp(&Jacobian,
false));
525 problem.setVectors(Teuchos::rcp(&solutionDirection,
false), Teuchos::rcp(&residual,
false));
526 if (problem.shouldEquilibrate()) {
527 problem.factorWithEquilibration(
true);
531 for (LO i = 0; i < numDimensions; ++i) {
532 paramCoords(i) = paramCoords(i) + solutionDirection(i);
536 GetInterpolationFunctions(numDimensions, paramCoords, functions);
537 for (LO i = 0; i < numDimensions; ++i) {
539 for (LO k = 0; k < numInterpolationPoints; ++k) {
540 tmp -= functions[0][k] * coord[k + 1][i];
545 norm2 = std::sqrt(norm2);
549 for (LO i = 0; i < numInterpolationPoints; ++i) {
550 stencil[i] = functions[0][i];
558 const Teuchos::SerialDenseVector<LO, real_type> parametricCoordinates,
560 real_type xi = 0.0, eta = 0.0, zeta = 0.0, denominator = 0.0;
561 if (numDimensions == 1) {
562 xi = parametricCoordinates[0];
564 }
else if (numDimensions == 2) {
565 xi = parametricCoordinates[0];
566 eta = parametricCoordinates[1];
568 }
else if (numDimensions == 3) {
569 xi = parametricCoordinates[0];
570 eta = parametricCoordinates[1];
571 zeta = parametricCoordinates[2];
575 functions[0][0] = (1.0 - xi) * (1.0 - eta) * (1.0 - zeta) / denominator;
576 functions[0][1] = (1.0 + xi) * (1.0 - eta) * (1.0 - zeta) / denominator;
577 functions[0][2] = (1.0 - xi) * (1.0 + eta) * (1.0 - zeta) / denominator;
578 functions[0][3] = (1.0 + xi) * (1.0 + eta) * (1.0 - zeta) / denominator;
579 functions[0][4] = (1.0 - xi) * (1.0 - eta) * (1.0 + zeta) / denominator;
580 functions[0][5] = (1.0 + xi) * (1.0 - eta) * (1.0 + zeta) / denominator;
581 functions[0][6] = (1.0 - xi) * (1.0 + eta) * (1.0 + zeta) / denominator;
582 functions[0][7] = (1.0 + xi) * (1.0 + eta) * (1.0 + zeta) / denominator;
584 functions[1][0] = -(1.0 - eta) * (1.0 - zeta) / denominator;
585 functions[1][1] = (1.0 - eta) * (1.0 - zeta) / denominator;
586 functions[1][2] = -(1.0 + eta) * (1.0 - zeta) / denominator;
587 functions[1][3] = (1.0 + eta) * (1.0 - zeta) / denominator;
588 functions[1][4] = -(1.0 - eta) * (1.0 + zeta) / denominator;
589 functions[1][5] = (1.0 - eta) * (1.0 + zeta) / denominator;
590 functions[1][6] = -(1.0 + eta) * (1.0 + zeta) / denominator;
591 functions[1][7] = (1.0 + eta) * (1.0 + zeta) / denominator;
593 functions[2][0] = -(1.0 - xi) * (1.0 - zeta) / denominator;
594 functions[2][1] = -(1.0 + xi) * (1.0 - zeta) / denominator;
595 functions[2][2] = (1.0 - xi) * (1.0 - zeta) / denominator;
596 functions[2][3] = (1.0 + xi) * (1.0 - zeta) / denominator;
597 functions[2][4] = -(1.0 - xi) * (1.0 + zeta) / denominator;
598 functions[2][5] = -(1.0 + xi) * (1.0 + zeta) / denominator;
599 functions[2][6] = (1.0 - xi) * (1.0 + zeta) / denominator;
600 functions[2][7] = (1.0 + xi) * (1.0 + zeta) / denominator;
602 functions[3][0] = -(1.0 - xi) * (1.0 - eta) / denominator;
603 functions[3][1] = -(1.0 + xi) * (1.0 - eta) / denominator;
604 functions[3][2] = -(1.0 - xi) * (1.0 + eta) / denominator;
605 functions[3][3] = -(1.0 + xi) * (1.0 + eta) / denominator;
606 functions[3][4] = (1.0 - xi) * (1.0 - eta) / denominator;
607 functions[3][5] = (1.0 + xi) * (1.0 - eta) / denominator;
608 functions[3][6] = (1.0 - xi) * (1.0 + eta) / denominator;
609 functions[3][7] = (1.0 + xi) * (1.0 + eta) / denominator;