267 RCP<Matrix>& Ac, RCP<Matrix> P,
268 const Teuchos::Array<LocalOrdinal>& lCoarseNodesPerDim,
270 using local_graph_type =
typename CrsGraph::local_graph_type;
271 using row_map_type =
typename local_graph_type::row_map_type::non_const_type;
272 using entries_type =
typename local_graph_type::entries_type::non_const_type;
273 using device_type =
typename Node::device_type;
274 using execution_space =
typename device_type::execution_space;
275 using range_policy = Kokkos::RangePolicy<execution_space, Kokkos::IndexType<size_t>>;
278 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
279 <<
"): number of dimensions must be between one and three.");
281 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
282 <<
"): insufficient local coarse-grid dimensions.");
284 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
285 <<
"): dofsPerNode must be positive.");
287 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
288 <<
"): coarse-grid stencil is empty; it must define at least one relative node position (dx, dy, dz).");
289 constexpr size_t maxSupportedStencilSize = 27;
290 constexpr size_t maxSupportedDofsPerNode = 3;
292 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
293 <<
"): a radius-one stencil may contain at most 27 entries.");
295 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
296 <<
"): at most three DOFs per node are supported.");
298 Kokkos::Array<GO, 3> localNodes{};
299 for (
int dim = 0; dim < 3; ++dim)
300 localNodes[dim] = Teuchos::as<GO>(1);
302 localNodes[dim] = Teuchos::as<GO>(lCoarseNodesPerDim[dim]);
304 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
305 <<
"): local coarse dimensions must be positive.");
308 Kokkos::Array<StencilOffset, maxSupportedStencilSize> stencilOffsets{};
309 Kokkos::Array<GO, maxSupportedStencilSize> localStencilNodeOffsets{};
310 for (
size_t stencil = 0; stencil < graphSpec.
stencilOffsets.size(); ++stencil) {
312 TEUCHOS_TEST_FOR_EXCEPTION(offset.
x < -1 || offset.
x > 1 ||
313 offset.
y < -1 || offset.
y > 1 ||
314 offset.
z < -1 || offset.
z > 1,
316 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
317 <<
"): only radius-one stencil offsets are currently supported.");
318 TEUCHOS_TEST_FOR_EXCEPTION((graphSpec.
numDimensions < 2 && offset.
y != 0) ||
321 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
322 <<
"): stencil contains an offset in an inactive dimension.");
323 stencilOffsets[stencil] = offset;
324 localStencilNodeOffsets[stencil] =
325 static_cast<GO
>(offset.
x) +
static_cast<GO
>(offset.
y) * localNodes[0] +
326 static_cast<GO
>(offset.
z) * localNodes[0] * localNodes[1];
329 RCP<ParameterList> paramList = rcp(
new ParameterList);
330 paramList->set(
"No Nonlocal Changes",
true);
331 paramList->set(
"Optimize Storage",
true);
332 paramList->set(
"compute global constants",
true);
335 auto rowMap = P->getDomainMap();
336 const size_t localNumRows = rowMap->getLocalNumElements();
338 const GO dofsPerNodeGO = Teuchos::as<GO>(dofsPerNode);
339 const size_t rowsPerNode = Teuchos::as<size_t>(dofsPerNode);
340 const GO localNumNodesGO = localNodes[0] * localNodes[1] * localNodes[2];
341 const size_t localNumNodes = Teuchos::as<size_t>(localNumNodesGO);
342 const GO expectedLocalRows = localNumNodesGO * dofsPerNodeGO;
344 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
345 <<
"): local coarse dimensions with " << graphSpec.
dofsPerNode
346 <<
" dofs per node do not match local coarse row count "
347 << localNumRows <<
".");
349 "StructuredRAPFactory::GetStructuredGraph requires the Tpetra backend.");
351 const GO numGlobalRows = Teuchos::as<GO>(rowMap->getGlobalNumElements());
353 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
354 <<
"): global coarse row count is not divisible by dofsPerNode.");
355 const GO numGlobalNodes = numGlobalRows / dofsPerNodeGO;
356 const GO globalMinGid = rowMap->getMinAllGlobalIndex();
357 const GO globalMaxGid = rowMap->getMaxAllGlobalIndex();
359 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
360 <<
"): coarse row-map GIDs must form a contiguous range.");
362 RCP<const Teuchos::Comm<int>> comm = rowMap->getComm();
363 const int myRank = comm->getRank();
364 const int numRanks = comm->getSize();
365 const GO localMinGid = rowMap->getMinGlobalIndex();
367 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
368 <<
"): local row range does not begin at a nodal boundary.");
369 const GO firstLocalNode = (localMinGid - globalMinGid) / dofsPerNodeGO;
371 Teuchos::Array<GO> localRankData(4);
372 localRankData[0] = firstLocalNode;
373 localRankData[1] = localNodes[0];
374 localRankData[2] = localNodes[1];
375 localRankData[3] = localNodes[2];
376 Teuchos::Array<GO> rankData(4 * numRanks);
379 Teuchos::gatherAll(*comm, 4, localRankData.getRawPtr(), 4 * numRanks, rankData.getRawPtr());
383 Kokkos::Array<int, 3> procGrid{};
384 for (
int dim = 0; dim < 3; ++dim)
387 procGrid[0] = numRanks;
389 while ((procGrid[0] + 1) * (procGrid[0] + 1) <= numRanks)
391 procGrid[1] = numRanks / procGrid[0];
392 while (procGrid[0] * procGrid[1] != numRanks)
393 procGrid[1] = numRanks / (--procGrid[0]);
395 int cubeRootNumRanks = 1;
396 while ((cubeRootNumRanks + 1) * (cubeRootNumRanks + 1) * (cubeRootNumRanks + 1) <= numRanks)
398 procGrid[0] = cubeRootNumRanks;
399 procGrid[1] = cubeRootNumRanks;
400 procGrid[2] = cubeRootNumRanks;
402 if (procGrid[0] * procGrid[1] * procGrid[2] != numRanks) {
407 int procTemp = numRanks;
409 const int galeriFactorSearchLimit = 50;
410 int factors[galeriFactorSearchLimit] = {};
411 for (
int factor = 2; factor < galeriFactorSearchLimit; ++factor) {
412 while (procTemp % factor == 0) {
417 procGrid[0] = procTemp;
418 for (
int factor = galeriFactorSearchLimit - 1; factor > 0; --factor) {
419 while (factors[factor] != 0) {
420 if (procGrid[0] <= procGrid[1] && procGrid[0] <= procGrid[2])
421 procGrid[0] *= factor;
422 else if (procGrid[1] <= procGrid[0] && procGrid[1] <= procGrid[2])
423 procGrid[1] *= factor;
425 procGrid[2] *= factor;
432 const int procXY = procGrid[0] * procGrid[1];
433 TEUCHOS_TEST_FOR_EXCEPTION(procGrid[0] <= 0 || procGrid[1] <= 0 || procGrid[2] <= 0 ||
434 procXY * procGrid[2] != numRanks,
436 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
437 <<
"): invalid inferred processor grid "
438 << procGrid[0] <<
"x" << procGrid[1] <<
"x" << procGrid[2]
439 <<
" for " << numRanks <<
" ranks.");
441 const int myProcX = myRank % procGrid[0];
442 const int myProcY = (myRank % procXY) / procGrid[0];
443 const int myProcZ = myRank / procXY;
445 Kokkos::Array<GO, 3> globalNodes{};
446 for (
int dim = 0; dim < 3; ++dim)
447 globalNodes[dim] = Teuchos::as<GO>(0);
448 for (
int px = 0; px < procGrid[0]; ++px)
449 globalNodes[0] += rankData[4 * px + 1];
450 for (
int py = 0; py < procGrid[1]; ++py)
451 globalNodes[1] += rankData[4 * (py * procGrid[0]) + 2];
452 for (
int pz = 0; pz < procGrid[2]; ++pz)
453 globalNodes[2] += rankData[4 * (pz * procXY) + 3];
454 TEUCHOS_TEST_FOR_EXCEPTION(globalNodes[0] * globalNodes[1] * globalNodes[2] != numGlobalNodes,
456 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
457 <<
"): processor-grid coarse dimensions do not match coarse node count.");
459 execution_space executionSpace;
460 Kokkos::View<GO*, device_type> rankDataDevice(
461 Kokkos::ViewAllocateWithoutInitializing(
"StructuredRAP: rank metadata"), rankData.size());
462 auto rankDataHost = Kokkos::create_mirror_view(rankDataDevice);
463 for (
int entry = 0; entry < rankData.size(); ++entry)
464 rankDataHost(entry) = rankData[entry];
465 Kokkos::deep_copy(executionSpace, rankDataDevice, rankDataHost);
469 const auto rowLocalMap = rowMap->getLocalMap();
473 size_t invalidLocalRows = 0;
474 Kokkos::parallel_reduce(
475 "StructuredRAP: validate local rows", range_policy(executionSpace, 0, localNumRows),
476 KOKKOS_LAMBDA(
const size_t rowLid,
size_t& invalid) {
477 const GO rowGid = rowLocalMap.getGlobalElement(
static_cast<LO
>(rowLid));
478 const GO expectedRowGid = localMinGid +
static_cast<GO
>(rowLid);
479 if (rowGid != expectedRowGid)
484 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
485 <<
"): coarse row-map GIDs are not locally contiguous and ordered.");
490 constexpr size_t maxNeighborRegions = 26;
491 Kokkos::Array<int, maxNeighborRegions> remoteRegionRanks{};
492 Kokkos::Array<StencilOffset, maxNeighborRegions> remoteRegionDirections{};
493 Kokkos::Array<GO, maxNeighborRegions> remoteRegionFirstNodes{};
494 Kokkos::Array<GO, maxNeighborRegions> remoteRegionNx{};
495 Kokkos::Array<GO, maxNeighborRegions> remoteRegionNy{};
496 Kokkos::Array<GO, maxNeighborRegions> remoteRegionNz{};
497 Kokkos::Array<size_t, maxNeighborRegions + 1> remoteRegionOffsets{};
498 size_t numRemoteRegions = 0;
504 for (
int procDz = minProcZ; procDz <= maxProcZ; ++procDz) {
505 for (
int procDy = minProcY; procDy <= maxProcY; ++procDy) {
506 for (
int procDx = -1; procDx <= 1; ++procDx) {
507 if (procDx == 0 && procDy == 0 && procDz == 0)
510 bool stencilReachesRegion =
false;
511 for (
size_t stencil = 0; stencil < stencilSize; ++stencil) {
513 const bool reachesX = procDx == 0 || offset.
x == procDx;
514 const bool reachesY = procDy == 0 || offset.
y == procDy;
515 const bool reachesZ = procDz == 0 || offset.
z == procDz;
516 if (reachesX && reachesY && reachesZ) {
517 stencilReachesRegion =
true;
521 if (!stencilReachesRegion)
524 const int neighborProcX = myProcX + procDx;
525 const int neighborProcY = myProcY + procDy;
526 const int neighborProcZ = myProcZ + procDz;
527 if (neighborProcX < 0 || neighborProcX >= procGrid[0] ||
528 neighborProcY < 0 || neighborProcY >= procGrid[1] ||
529 neighborProcZ < 0 || neighborProcZ >= procGrid[2])
532 const int neighborRank = neighborProcZ * procXY + neighborProcY * procGrid[0] + neighborProcX;
533 const GO neighborNx = rankData[4 * neighborRank + 1];
534 const GO neighborNy = rankData[4 * neighborRank + 2];
535 const GO neighborNz = rankData[4 * neighborRank + 3];
536 const size_t regionNodes = Teuchos::as<size_t>((procDx == 0 ? neighborNx : 1) *
537 (procDy == 0 ? neighborNy : 1) *
538 (procDz == 0 ? neighborNz : 1));
540 remoteRegionRanks[numRemoteRegions] = neighborRank;
541 remoteRegionDirections[numRemoteRegions] =
StencilOffset{procDx, procDy, procDz};
542 remoteRegionFirstNodes[numRemoteRegions] = rankData[4 * neighborRank];
543 remoteRegionNx[numRemoteRegions] = neighborNx;
544 remoteRegionNy[numRemoteRegions] = neighborNy;
545 remoteRegionNz[numRemoteRegions] = neighborNz;
546 remoteRegionOffsets[numRemoteRegions + 1] =
547 remoteRegionOffsets[numRemoteRegions] + regionNodes * rowsPerNode;
552 const size_t numRemoteColumns = remoteRegionOffsets[numRemoteRegions];
554 Kokkos::View<GO*, device_type> colMapGids(
555 Kokkos::ViewAllocateWithoutInitializing(
"StructuredRAP: column map GIDs"),
556 localNumRows + numRemoteColumns);
557 const auto localRowGidsDevice = rowMap->getMyGlobalIndicesDevice();
558 Kokkos::parallel_for(
559 "StructuredRAP: fill column map", range_policy(executionSpace, 0, localNumRows + numRemoteColumns),
560 KOKKOS_LAMBDA(
const size_t entry) {
561 if (entry < localNumRows) {
562 colMapGids(entry) = localRowGidsDevice(entry);
566 const size_t remoteEntry = entry - localNumRows;
568 while (remoteEntry >= remoteRegionOffsets[region + 1])
571 const StencilOffset direction = remoteRegionDirections[region];
572 const GO neighborNx = remoteRegionNx[region];
573 const GO neighborNy = remoteRegionNy[region];
574 const GO neighborNz = remoteRegionNz[region];
575 size_t regionEntry = remoteEntry - remoteRegionOffsets[region];
576 const GO dof =
static_cast<GO
>(regionEntry % rowsPerNode);
577 size_t regionNode = regionEntry / rowsPerNode;
579 GO neighborX = direction.
x < 0 ? neighborNx - 1 : 0;
580 GO neighborY = direction.
y < 0 ? neighborNy - 1 : 0;
581 GO neighborZ = direction.
z < 0 ? neighborNz - 1 : 0;
582 if (direction.
x == 0) {
583 neighborX =
static_cast<GO
>(regionNode %
static_cast<size_t>(neighborNx));
584 regionNode /=
static_cast<size_t>(neighborNx);
586 if (direction.
y == 0) {
587 neighborY =
static_cast<GO
>(regionNode %
static_cast<size_t>(neighborNy));
588 regionNode /=
static_cast<size_t>(neighborNy);
590 if (direction.
z == 0)
591 neighborZ =
static_cast<GO
>(regionNode);
593 const GO neighborNode = remoteRegionFirstNodes[region] +
594 neighborZ * neighborNx * neighborNy + neighborY * neighborNx + neighborX;
595 colMapGids(entry) = globalMinGid + neighborNode * dofsPerNodeGO + dof;
597 executionSpace.fence(
"StructuredRAP: column map GIDs ready");
599 typename Map::global_indices_array_device_type constColMapGids = colMapGids;
601 RCP<const Map> colMap;
603 colMap = MapFactory::Build(
604 rowMap->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),
605 constColMapGids, rowMap->getIndexBase(), comm);
612 rowptr = row_map_type(
613 Kokkos::ViewAllocateWithoutInitializing(
"StructuredRAP: graph row pointers"), localNumRows + 1);
614 Kokkos::parallel_scan(
615 "StructuredRAP: compute graph row pointers", range_policy(executionSpace, 0, localNumNodes + 1),
616 KOKKOS_LAMBDA(
const size_t localNodeIndex,
size_t& update,
const bool final) {
617 if (localNodeIndex == localNumNodes) {
619 rowptr(localNumRows) = update;
623 const GO localNode =
static_cast<GO
>(localNodeIndex);
624 GO x = 0, y = 0, z = 0;
626 const bool isInterior =
627 x > 0 && x + 1 < localNodes[0] &&
628 (numDimensions < 2 || (y > 0 && y + 1 < localNodes[1])) &&
629 (numDimensions < 3 || (z > 0 && z + 1 < localNodes[2]));
630 size_t rowLength = isInterior ? stencilSize * rowsPerNode : 0;
632 for (
size_t stencil = 0; stencil < stencilSize; ++stencil) {
633 int neighborRank = myRank;
636 x, y, z, stencilOffsets[stencil], localNodes, procGrid, rankDataDevice,
637 myProcX, myProcY, myProcZ, neighborRank, neighborNode))
638 rowLength += rowsPerNode;
643 const size_t firstRow = localNodeIndex * rowsPerNode;
644 for (
size_t rowDof = 0; rowDof < rowsPerNode; ++rowDof)
645 rowptr(firstRow + rowDof) = update + rowDof * rowLength;
647 update += rowLength * rowsPerNode;
654 colind = entries_type(
655 Kokkos::ViewAllocateWithoutInitializing(
"StructuredRAP: graph column indices"), localNnz);
658 const LO invalidLocalOrdinal = Teuchos::OrdinalTraits<LO>::invalid();
659 Kokkos::View<int, device_type> invalidColumn;
661 invalidColumn = Kokkos::View<int, device_type>(
"StructuredRAP: invalid column");
662 Kokkos::deep_copy(executionSpace, invalidColumn, 0);
667 Kokkos::parallel_for(
668 "StructuredRAP: fill graph column indices", range_policy(executionSpace, 0, localNumNodes),
669 KOKKOS_LAMBDA(
const size_t localNodeIndex) {
670 const GO localNode =
static_cast<GO
>(localNodeIndex);
671 GO x = 0, y = 0, z = 0;
673 size_t columnOffset = 0;
674 const bool isInterior =
675 x > 0 && x + 1 < localNodes[0] &&
676 (numDimensions < 2 || (y > 0 && y + 1 < localNodes[1])) &&
677 (numDimensions < 3 || (z > 0 && z + 1 < localNodes[2]));
680 const size_t firstRow = localNodeIndex * rowsPerNode;
681 for (
size_t stencil = 0; stencil < stencilSize; ++stencil) {
682 const GO neighborLocalNode = localNode + localStencilNodeOffsets[stencil];
683 for (
size_t colDof = 0; colDof < rowsPerNode; ++colDof) {
684 const LO colLid =
static_cast<LO
>(
685 neighborLocalNode * dofsPerNodeGO +
static_cast<GO
>(colDof));
686 for (
size_t rowDof = 0; rowDof < rowsPerNode; ++rowDof)
687 colind(rowptr(firstRow + rowDof) + columnOffset) = colLid;
694 Kokkos::Array<LO, maxSupportedStencilSize * maxSupportedDofsPerNode> nodeColumns;
695 for (
size_t stencil = 0; stencil < stencilSize; ++stencil) {
696 int neighborRank = myRank;
699 x, y, z, stencilOffsets[stencil], localNodes, procGrid, rankDataDevice,
700 myProcX, myProcY, myProcZ, neighborRank, neighborNode))
703 for (
size_t colDof = 0; colDof < rowsPerNode; ++colDof) {
704 const GO colGid = globalMinGid + neighborNode * dofsPerNodeGO +
static_cast<GO
>(colDof);
705 LO colLid = invalidLocalOrdinal;
706 if (neighborRank == myRank) {
707 colLid =
static_cast<LO
>(colGid - localMinGid);
710 while (region < numRemoteRegions && remoteRegionRanks[region] != neighborRank)
712 if (region < numRemoteRegions) {
713 const GO neighborNx = remoteRegionNx[region];
714 const GO neighborNy = remoteRegionNy[region];
715 const GO localNeighborNode = neighborNode - remoteRegionFirstNodes[region];
716 const GO neighborX = localNeighborNode % neighborNx;
717 const GO neighborY = (localNeighborNode / neighborNx) % neighborNy;
718 const GO neighborZ = localNeighborNode / (neighborNx * neighborNy);
719 const StencilOffset direction = remoteRegionDirections[region];
720 size_t regionNode = 0;
722 if (direction.
x == 0) {
723 regionNode +=
static_cast<size_t>(neighborX) * stride;
724 stride *=
static_cast<size_t>(neighborNx);
726 if (direction.
y == 0) {
727 regionNode +=
static_cast<size_t>(neighborY) * stride;
728 stride *=
static_cast<size_t>(neighborNy);
730 if (direction.
z == 0)
731 regionNode +=
static_cast<size_t>(neighborZ) * stride;
732 colLid =
static_cast<LO
>(localNumRows + remoteRegionOffsets[region] +
733 regionNode * rowsPerNode + colDof);
737 if (debug && colLid == invalidLocalOrdinal)
738 Kokkos::atomic_exchange(&invalidColumn(), 1);
740 nodeColumns[columnOffset++] = colLid;
744 for (
size_t entry = 1; entry < columnOffset; ++entry) {
745 const LO value = nodeColumns[entry];
746 size_t insertion = entry;
747 while (insertion > 0 && value < nodeColumns[insertion - 1]) {
748 nodeColumns[insertion] = nodeColumns[insertion - 1];
751 nodeColumns[insertion] = value;
754 const size_t firstRow = localNodeIndex * rowsPerNode;
755 for (
size_t rowDof = 0; rowDof < rowsPerNode; ++rowDof) {
756 const size_t rowStart = rowptr(firstRow + rowDof);
757 for (
size_t entry = 0; entry < columnOffset; ++entry)
758 colind(rowStart + entry) = nodeColumns[entry];
761 executionSpace.fence(
"StructuredRAP: graph column indices ready");
765 int invalidColumnHost = 0;
766 Kokkos::deep_copy(executionSpace, invalidColumnHost, invalidColumn);
768 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
769 <<
"): a generated column GID was not found in the coarse column map.");
771 size_t unsortedRows = 0;
772 Kokkos::parallel_reduce(
773 "StructuredRAP: validate sorted graph rows", range_policy(executionSpace, 0, localNumRows),
774 KOKKOS_LAMBDA(
const size_t row,
size_t& invalid) {
775 for (
size_t entry = rowptr(row) + 1; entry < rowptr(row + 1); ++entry) {
776 if (colind(entry) < colind(entry - 1)) {
784 "StructuredRAPFactory::GetStructuredGraph(" << graphSpec.
description
785 <<
"): generated graph rows are not sorted.");
788 local_graph_type localGraph(colind, rowptr);
791 graph = CrsGraphFactory::Build(
792 localGraph, rowMap, colMap, rowMap, rowMap, paramList);
795 using values_type =
typename Matrix::local_matrix_type::values_type;
797 Kokkos::ViewAllocateWithoutInitializing(
"StructuredRAP: matrix values"), localNnz);
798 Ac = MatrixFactory::Build(graph, values, paramList);
804 const bool doTranspose =
true;
805 const bool doFillComplete =
true;
806 const bool doOptimizeStorage =
true;
807 const Teuchos::ParameterList& pL = GetParameterList();
808 const bool prebuildCoarseGraph = pL.get<
bool>(
"rap: prebuild coarse graph");
809 const bool useRAPDelegate = !prebuildCoarseGraph;
811 TEUCHOS_TEST_FOR_EXCEPTION(
813 "StructuredRAPFactory requires \"transpose: use implicit\" = true because "
814 "the prebuilt coarse graph assumes the Galerkin product P^T A P.");
819 "MueLu::RAPFactory::Build(): CallDeclareInput has not been called before Build!");
821 if (useRAPDelegate) {
822 if (coarseLevel.
IsAvailable(
"RAP reuse data",
this)) {
823 RCP<ParameterList> RAPparams = coarseLevel.
Get<RCP<ParameterList>>(
"RAP reuse data",
this);
824 coarseLevel.
Set(
"RAP reuse data", RAPparams, rapFactoryDelegate_.get());
829 rapFactoryDelegate_->Build(fineLevel, coarseLevel);
831 Ac = coarseLevel.
Get<RCP<Matrix>>(
"A", rapFactoryDelegate_.get());
832 Set(coarseLevel,
"A", Ac);
834 if (coarseLevel.
IsAvailable(
"RAP reuse data", rapFactoryDelegate_.get())) {
835 RCP<ParameterList> RAPparams = coarseLevel.
Get<RCP<ParameterList>>(
"RAP reuse data", rapFactoryDelegate_.get());
836 Set(coarseLevel,
"RAP reuse data", RAPparams);
845 std::ostringstream levelstr;
849 TEUCHOS_TEST_FOR_EXCEPTION(
851 "StructuredRAPFactory requires \"rap: triple product\" = true.");
853 RCP<Matrix> A = Get<RCP<Matrix>>(fineLevel,
"A");
854 RCP<Matrix> P = Get<RCP<Matrix>>(coarseLevel,
"P");
859 Set(coarseLevel,
"A", Ac);
864 RCP<ParameterList> RAPparams = rcp(
new ParameterList);
865 if (pL.isSublist(
"matrixmatrix: kernel params"))
866 RAPparams->sublist(
"matrixmatrix: kernel params") = pL.sublist(
"matrixmatrix: kernel params");
868 if (coarseLevel.IsAvailable(
"RAP reuse data",
this)) {
869 GetOStream(
static_cast<MsgType>(
Runtime0 |
Test)) <<
"Reusing previous RAP data" << std::endl;
871 RAPparams = coarseLevel.Get<RCP<ParameterList>>(
"RAP reuse data",
this);
874 "StructuredRAPFactory::Build(): \"RAP reuse data\" does not contain the expected graph.");
875 Ac = RAPparams->get<RCP<Matrix>>(
"graph");
877 "StructuredRAPFactory::Build(): \"RAP reuse data\" graph is null.");
881 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<SC>::one());
885 }
else if (prebuildCoarseGraph) {
887 std::string matrixType = pL.get<std::string>(
"rap: matrix type");
888 if (matrixType.empty())
889 matrixType = Get<std::string>(fineLevel,
"matrixType");
890 Teuchos::Array<LocalOrdinal> lCoarseNodesPerDim =
891 Get<Teuchos::Array<LocalOrdinal>>(fineLevel,
"lCoarseNodesPerDim");
892 const int interpolationOrder = Get<int>(fineLevel,
"structuredInterpolationOrder");
893 const StructuredGraphSpec graphSpec = GetStructuredGraphSpec(matrixType, interpolationOrder);
896 <<
" nodal entries." << std::endl;
897 GetStructuredGraph(Ac, P, lCoarseNodesPerDim, graphSpec);
901 RAPparams->set(
"compute global constants: temporaries", RAPparams->get(
"compute global constants: temporaries",
false));
902 RAPparams->set(
"compute global constants",
true);
905 Ac = MatrixFactory::Build(P->getDomainMap(), Teuchos::as<LocalOrdinal>(0));
909 Xpetra::TripleMatrixMultiply<SC, LO, GO, NO>::
910 MultiplyRAP(*P, doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
911 doOptimizeStorage, labelstr + std::string(
"MueLu::P^T*A*P-implicit-") + levelstr.str(),
914 GetOStream(
Statistics1) <<
"StructuredRAP: Ac nnz (prebuild coarse graph = "
915 << (prebuildCoarseGraph ?
"true" :
"false")
916 <<
"): local = " << Ac->getLocalNumEntries()
917 <<
", global = " << Ac->getGlobalNumEntries() << std::endl;
919 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double>>(
"rap: relative diagonal floor")();
920 if (relativeFloor.size() > 0) {
921 Xpetra::MatrixUtils<SC, LO, GO, NO>::RelativeDiagonalBoost(Ac, relativeFloor, GetOStream(
Statistics2));
924 bool repairZeroDiagonals = pL.get<
bool>(
"RepairMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
925 bool checkAc = pL.get<
bool>(
"CheckMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
926 if (checkAc || repairZeroDiagonals) {
927 using magnitudeType =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
928 magnitudeType threshold;
929 if (pL.isType<magnitudeType>(
"rap: fix zero diagonals threshold"))
930 threshold = pL.get<magnitudeType>(
"rap: fix zero diagonals threshold");
932 threshold = Teuchos::as<magnitudeType>(pL.get<
double>(
"rap: fix zero diagonals threshold"));
933 Scalar replacement = Teuchos::as<Scalar>(pL.get<
double>(
"rap: fix zero diagonals replacement"));
934 Xpetra::MatrixUtils<SC, LO, GO, NO>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, GetOStream(
Warnings1), threshold, replacement);
938 RCP<ParameterList> params = rcp(
new ParameterList());
939 params->set(
"printLoadBalancingInfo",
true);
940 params->set(
"printCommInfo",
true);
946 std::ostringstream oss;
947 oss <<
"A_" << coarseLevel.GetLevelID();
948 Ac->setObjectLabel(oss.str());
950 Set(coarseLevel,
"A", Ac);
952 RAPparams->set(
"graph", Ac);
953 Set(coarseLevel,
"RAP reuse data", RAPparams);
958 MatrixUtils::checkLocalRowMapMatchesColMap(*Ac);
960 if (transferFacts_.begin() != transferFacts_.end()) {
964 for (std::vector<RCP<const FactoryBase>>::const_iterator it = transferFacts_.begin(); it != transferFacts_.end(); ++it) {
965 RCP<const FactoryBase> fac = *it;
966 GetOStream(
Runtime0) <<
"RAPFactory: call transfer factory: " << fac->description() << std::endl;
967 fac->CallBuild(coarseLevel);