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);
279 P->CreateView(
"stridedMaps", P->getRangeMap(), PointMap);
283 RCP<ParameterList> dummyList = rcp(
new ParameterList());
284 P = rcp(
new CrsMatrixWrap(prolongatorGraph, dummyList));
285 RCP<CrsMatrix> PCrs = toCrsMatrix(P);
286 PCrs->setAllToScalar(1.0);
287 PCrs->fillComplete();
290 if (A->IsView(
"stridedMaps") ==
true)
291 P->CreateView(
"stridedMaps", A->getRowMap(
"stridedMaps"), stridedDomainMap);
293 P->CreateView(
"stridedMaps", P->getRangeMap(), stridedDomainMap);
301 RCP<Matrix>& A, RCP<const CrsGraph>& prolongatorGraph,
302 RCP<realvaluedmultivector_type>& fineCoordinates,
303 RCP<realvaluedmultivector_type>& ghostCoordinates,
305 RCP<Matrix>& P)
const {
307 RCP<Teuchos::FancyOStream> out;
308 if (
const char* dbg = std::getenv(
"MUELU_GEOMETRICINTERPOLATIONPFACTORY_DEBUG")) {
309 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
310 out->setShowAllFrontMatter(
false).setShowProcRank(
true);
312 out = Teuchos::getFancyOStream(rcp(
new Teuchos::oblackholestream()));
316 const int numInterpolationPoints = 1 << numDimensions;
317 const int dofsPerNode = A->GetFixedBlockSize() / A->GetStorageBlockSize();
320 RCP<ParameterList> dummyList = rcp(
new ParameterList());
321 P = rcp(
new CrsMatrixWrap(prolongatorGraph, dummyList));
322 RCP<CrsMatrix> PCrs = toCrsMatrix(P);
326 *out <<
"Entering BuildLinearP" << std::endl;
330 const LO numFineNodes = fineCoordinates->getLocalLength();
331 const LO numGhostNodes = ghostCoordinates->getLocalLength();
332 Array<ArrayRCP<const real_type> > fineCoords(3);
333 Array<ArrayRCP<const real_type> > ghostCoords(3);
334 const real_type realZero = Teuchos::as<real_type>(0.0);
335 ArrayRCP<real_type> fineZero(numFineNodes, realZero);
336 ArrayRCP<real_type> ghostZero(numGhostNodes, realZero);
337 for (
int dim = 0; dim < 3; ++dim) {
338 if (dim < numDimensions) {
339 fineCoords[dim] = fineCoordinates->getData(dim);
340 ghostCoords[dim] = ghostCoordinates->getData(dim);
342 fineCoords[dim] = fineZero;
343 ghostCoords[dim] = ghostZero;
347 *out <<
"Coordinates extracted from the multivectors!" << std::endl;
350 LO interpolationNodeIdx = 0, rowIdx = 0;
351 ArrayView<const LO> colIndices;
353 Array<Array<real_type> > coords(numInterpolationPoints + 1);
354 Array<real_type> stencil(numInterpolationPoints);
355 for (LO nodeIdx = 0; nodeIdx < numFineNodes; ++nodeIdx) {
356 if (PCrs->getNumEntriesInLocalRow(nodeIdx * dofsPerNode) == 1) {
359 for (LO dof = 0; dof < dofsPerNode; ++dof) {
360 rowIdx = nodeIdx * dofsPerNode + dof;
361 prolongatorGraph->getLocalRowView(rowIdx, colIndices);
362 PCrs->replaceLocalValues(rowIdx, colIndices, values());
368 for (
int dim = 0; dim < 3; ++dim) {
369 coords[0][dim] = fineCoords[dim][nodeIdx];
371 prolongatorGraph->getLocalRowView(nodeIdx * dofsPerNode, colIndices);
372 for (
int interpolationIdx = 0; interpolationIdx < numInterpolationPoints; ++interpolationIdx) {
373 coords[interpolationIdx + 1].resize(3);
374 interpolationNodeIdx = colIndices[interpolationIdx] / dofsPerNode;
375 for (
int dim = 0; dim < 3; ++dim) {
376 coords[interpolationIdx + 1][dim] = ghostCoords[dim][interpolationNodeIdx];
379 RCP<Teuchos::TimeMonitor> tm = rcp(
new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(
"Compute Linear Interpolation")));
380 ComputeLinearInterpolationStencil(numDimensions, numInterpolationPoints, coords, stencil);
382 values.resize(numInterpolationPoints);
383 for (LO valueIdx = 0; valueIdx < numInterpolationPoints; ++valueIdx) {
384 values[valueIdx] = Teuchos::as<SC>(stencil[valueIdx]);
388 for (LO dof = 0; dof < dofsPerNode; ++dof) {
389 rowIdx = nodeIdx * dofsPerNode + dof;
390 prolongatorGraph->getLocalRowView(rowIdx, colIndices);
391 PCrs->replaceLocalValues(rowIdx, colIndices, values());
397 *out <<
"The calculation of the interpolation stencils has completed." << std::endl;
399 PCrs->fillComplete();
402 *out <<
"All values in P have been set and fillComplete has been performed." << std::endl;
411 *out <<
"Entering remove small entries" << std::endl;
414 ArrayRCP<const size_t> rowptrOrig;
415 ArrayRCP<const LO> colindOrig;
416 ArrayRCP<const Scalar> valuesOrig;
417 PCrs->getAllValues(rowptrOrig, colindOrig, valuesOrig);
419 const size_t numRows =
static_cast<size_t>(rowptrOrig.size() - 1);
420 ArrayRCP<size_t> rowPtr(numRows + 1);
421 ArrayRCP<size_t> nnzOnRows(numRows);
423 size_t countRemovedEntries = 0;
424 for (
size_t rowIdx = 0; rowIdx < numRows; ++rowIdx) {
425 for (
size_t entryIdx = rowptrOrig[rowIdx]; entryIdx < rowptrOrig[rowIdx + 1]; ++entryIdx) {
426 if (Teuchos::ScalarTraits<Scalar>::magnitude(valuesOrig[entryIdx]) < 1e-6) {
427 ++countRemovedEntries;
430 rowPtr[rowIdx + 1] = rowptrOrig[rowIdx + 1] - countRemovedEntries;
431 nnzOnRows[rowIdx] = rowPtr[rowIdx + 1] - rowPtr[rowIdx];
433 GetOStream(
Statistics1) <<
"interp: number of small entries removed= " << countRemovedEntries <<
" / " << rowptrOrig[numRows] << std::endl;
435 size_t countKeptEntries = 0;
436 ArrayRCP<LO> colInd(rowPtr[numRows]);
437 ArrayRCP<SC> values(rowPtr[numRows]);
438 for (
size_t entryIdx = 0; entryIdx < rowptrOrig[numRows]; ++entryIdx) {
439 if (Teuchos::ScalarTraits<Scalar>::magnitude(valuesOrig[entryIdx]) > 1e-6) {
440 colInd[countKeptEntries] = colindOrig[entryIdx];
441 values[countKeptEntries] = valuesOrig[entryIdx];
446 P = rcp(
new CrsMatrixWrap(prolongatorGraph->getRowMap(),
447 prolongatorGraph->getColMap(),
449 RCP<CrsMatrix> PCrsSqueezed = toCrsMatrix(P);
450 PCrsSqueezed->resumeFill();
451 PCrsSqueezed->setAllValues(rowPtr, colInd, values);
452 PCrsSqueezed->expertStaticFillComplete(prolongatorGraph->getDomainMap(),
453 prolongatorGraph->getRangeMap());
456 std::vector<size_t> strideInfo(1);
457 strideInfo[0] = dofsPerNode;
458 RCP<const StridedMap> stridedDomainMap =
459 StridedMapFactory::Build(prolongatorGraph->getDomainMap(), strideInfo);
461 *out <<
"The strided maps of P have been computed" << std::endl;
464 if (A->IsView(
"stridedMaps") ==
true) {
465 P->CreateView(
"stridedMaps", A->getRowMap(
"stridedMaps"), stridedDomainMap);
467 P->CreateView(
"stridedMaps", P->getRangeMap(), stridedDomainMap);
475 const Array<Array<real_type> > coord,
476 Array<real_type>& stencil)
const {
492 Teuchos::SerialDenseMatrix<LO, real_type> Jacobian(numDimensions, numDimensions);
493 Teuchos::SerialDenseVector<LO, real_type> residual(numDimensions);
494 Teuchos::SerialDenseVector<LO, real_type> solutionDirection(numDimensions);
495 Teuchos::SerialDenseVector<LO, real_type> paramCoords(numDimensions);
496 Teuchos::SerialDenseSolver<LO, real_type> problem;
497 int iter = 0, max_iter = 5;
498 real_type functions[4][8], norm_ref = 1.0, norm2 = 1.0, tol = 1.0e-5;
499 paramCoords.size(numDimensions);
501 while ((iter < max_iter) && (norm2 > tol * norm_ref)) {
504 solutionDirection.size(numDimensions);
505 residual.size(numDimensions);
509 GetInterpolationFunctions(numDimensions, paramCoords, functions);
510 for (LO i = 0; i < numDimensions; ++i) {
511 residual(i) = coord[0][i];
512 for (LO k = 0; k < numInterpolationPoints; ++k) {
513 residual(i) -= functions[0][k] * coord[k + 1][i];
516 norm_ref += residual(i) * residual(i);
517 if (i == numDimensions - 1) {
518 norm_ref = std::sqrt(norm_ref);
522 for (LO j = 0; j < numDimensions; ++j) {
523 for (LO k = 0; k < numInterpolationPoints; ++k) {
524 Jacobian(i, j) += functions[j + 1][k] * coord[k + 1][i];
530 problem.setMatrix(Teuchos::rcp(&Jacobian,
false));
531 problem.setVectors(Teuchos::rcp(&solutionDirection,
false), Teuchos::rcp(&residual,
false));
532 if (problem.shouldEquilibrate()) {
533 problem.factorWithEquilibration(
true);
537 for (LO i = 0; i < numDimensions; ++i) {
538 paramCoords(i) = paramCoords(i) + solutionDirection(i);
542 GetInterpolationFunctions(numDimensions, paramCoords, functions);
543 for (LO i = 0; i < numDimensions; ++i) {
545 for (LO k = 0; k < numInterpolationPoints; ++k) {
546 tmp -= functions[0][k] * coord[k + 1][i];
551 norm2 = std::sqrt(norm2);
555 for (LO i = 0; i < numInterpolationPoints; ++i) {
556 stencil[i] = functions[0][i];
564 const Teuchos::SerialDenseVector<LO, real_type> parametricCoordinates,
566 real_type xi = 0.0, eta = 0.0, zeta = 0.0, denominator = 0.0;
567 if (numDimensions == 1) {
568 xi = parametricCoordinates[0];
570 }
else if (numDimensions == 2) {
571 xi = parametricCoordinates[0];
572 eta = parametricCoordinates[1];
574 }
else if (numDimensions == 3) {
575 xi = parametricCoordinates[0];
576 eta = parametricCoordinates[1];
577 zeta = parametricCoordinates[2];
581 functions[0][0] = (1.0 - xi) * (1.0 - eta) * (1.0 - zeta) / denominator;
582 functions[0][1] = (1.0 + xi) * (1.0 - eta) * (1.0 - zeta) / denominator;
583 functions[0][2] = (1.0 - xi) * (1.0 + eta) * (1.0 - zeta) / denominator;
584 functions[0][3] = (1.0 + xi) * (1.0 + eta) * (1.0 - zeta) / denominator;
585 functions[0][4] = (1.0 - xi) * (1.0 - eta) * (1.0 + zeta) / denominator;
586 functions[0][5] = (1.0 + xi) * (1.0 - eta) * (1.0 + zeta) / denominator;
587 functions[0][6] = (1.0 - xi) * (1.0 + eta) * (1.0 + zeta) / denominator;
588 functions[0][7] = (1.0 + xi) * (1.0 + eta) * (1.0 + zeta) / denominator;
590 functions[1][0] = -(1.0 - eta) * (1.0 - zeta) / denominator;
591 functions[1][1] = (1.0 - eta) * (1.0 - zeta) / denominator;
592 functions[1][2] = -(1.0 + eta) * (1.0 - zeta) / denominator;
593 functions[1][3] = (1.0 + eta) * (1.0 - zeta) / denominator;
594 functions[1][4] = -(1.0 - eta) * (1.0 + zeta) / denominator;
595 functions[1][5] = (1.0 - eta) * (1.0 + zeta) / denominator;
596 functions[1][6] = -(1.0 + eta) * (1.0 + zeta) / denominator;
597 functions[1][7] = (1.0 + eta) * (1.0 + zeta) / denominator;
599 functions[2][0] = -(1.0 - xi) * (1.0 - zeta) / denominator;
600 functions[2][1] = -(1.0 + xi) * (1.0 - zeta) / denominator;
601 functions[2][2] = (1.0 - xi) * (1.0 - zeta) / denominator;
602 functions[2][3] = (1.0 + xi) * (1.0 - zeta) / denominator;
603 functions[2][4] = -(1.0 - xi) * (1.0 + zeta) / denominator;
604 functions[2][5] = -(1.0 + xi) * (1.0 + zeta) / denominator;
605 functions[2][6] = (1.0 - xi) * (1.0 + zeta) / denominator;
606 functions[2][7] = (1.0 + xi) * (1.0 + zeta) / denominator;
608 functions[3][0] = -(1.0 - xi) * (1.0 - eta) / denominator;
609 functions[3][1] = -(1.0 + xi) * (1.0 - eta) / denominator;
610 functions[3][2] = -(1.0 - xi) * (1.0 + eta) / denominator;
611 functions[3][3] = -(1.0 + xi) * (1.0 + eta) / denominator;
612 functions[3][4] = (1.0 - xi) * (1.0 - eta) / denominator;
613 functions[3][5] = (1.0 + xi) * (1.0 - eta) / denominator;
614 functions[3][6] = (1.0 - xi) * (1.0 + eta) / denominator;
615 functions[3][7] = (1.0 + xi) * (1.0 + eta) / denominator;