147 typedef Teuchos::ScalarTraits<SC> STS;
148 typedef typename STS::magnitudeType real_type;
149 typedef Xpetra::MultiVector<real_type, LO, GO, NO> RealValuedMultiVector;
150 typedef Xpetra::MultiVectorFactory<real_type, LO, GO, NO> RealValuedMultiVectorFactory;
158 bool doExperimentalWrap = pL.get<
bool>(
"lightweight wrap");
161 std::string algo = pL.get<std::string>(
"aggregation: drop scheme");
162 const bool aggregationMayCreateDirichlet = pL.get<
bool>(
"aggregation: dropping may create Dirichlet");
164 RCP<RealValuedMultiVector> Coords;
167 bool use_block_algorithm =
false;
168 LO interleaved_blocksize = as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize"));
169 bool useSignedClassicalRS =
false;
170 bool useSignedClassicalSA =
false;
171 bool generateColoringGraph =
false;
175 typename STS::magnitudeType rowSumTol = as<typename STS::magnitudeType>(pL.get<
double>(
"aggregation: row sum drop tol"));
177 RCP<LocalOrdinalVector> ghostedBlockNumber;
179 if (algo ==
"distance laplacian") {
183 }
else if (algo ==
"signed classical sa") {
184 useSignedClassicalSA =
true;
187 }
else if (algo ==
"signed classical" || algo ==
"block diagonal colored signed classical" || algo ==
"block diagonal signed classical") {
188 useSignedClassicalRS =
true;
192 RCP<const Import> importer = realA->getCrsGraph()->getImporter();
193 if (!importer.is_null()) {
195 ghostedBlockNumber = Xpetra::VectorFactory<LO, LO, GO, NO>::Build(importer->getTargetMap());
196 ghostedBlockNumber->doImport(*BlockNumber, *importer, Xpetra::INSERT);
198 ghostedBlockNumber = BlockNumber;
201 if (algo ==
"block diagonal colored signed classical")
202 generateColoringGraph =
true;
206 }
else if (algo ==
"block diagonal") {
210 }
else if (algo ==
"block diagonal classical" || algo ==
"block diagonal distance laplacian") {
212 use_block_algorithm =
true;
214 if (algo ==
"block diagonal distance laplacian") {
217 if (OldCoords->getLocalLength() != realA->getLocalNumRows()) {
218 LO dim = (LO)OldCoords->getNumVectors();
219 Coords = RealValuedMultiVectorFactory::Build(realA->getRowMap(), dim);
220 for (LO k = 0; k < dim; k++) {
221 ArrayRCP<const real_type> old_vec = OldCoords->getData(k);
222 ArrayRCP<real_type> new_vec = Coords->getDataNonConst(k);
223 for (LO i = 0; i < (LO)OldCoords->getLocalLength(); i++) {
224 LO new_base = i * dim;
225 for (LO j = 0; j < interleaved_blocksize; j++)
226 new_vec[new_base + j] = old_vec[i];
232 algo =
"distance laplacian";
233 }
else if (algo ==
"block diagonal classical") {
244 Array<double> dlap_weights = pL.get<Array<double>>(
"aggregation: distance laplacian directional weights");
245 enum { NO_WEIGHTS = 0,
248 int use_dlap_weights = NO_WEIGHTS;
249 if (algo ==
"distance laplacian") {
250 LO dim = (LO)Coords->getNumVectors();
252 bool non_unity =
false;
253 for (LO i = 0; !non_unity && i < (LO)dlap_weights.size(); i++) {
254 if (dlap_weights[i] != 1.0) {
259 LO blocksize = use_block_algorithm ? as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize")) : 1;
260 if ((LO)dlap_weights.size() == dim)
261 use_dlap_weights = SINGLE_WEIGHTS;
262 else if ((LO)dlap_weights.size() == blocksize * dim)
263 use_dlap_weights = BLOCK_WEIGHTS;
266 "length of 'aggregation: distance laplacian directional weights' must equal the coordinate dimension OR the coordinate dimension times the blocksize");
284 if (doExperimentalWrap) {
285 TEUCHOS_TEST_FOR_EXCEPTION(
predrop_ != null && algo !=
"classical",
Exceptions::RuntimeError,
"Dropping function must not be provided for \"" << algo <<
"\" algorithm");
286 TEUCHOS_TEST_FOR_EXCEPTION(algo !=
"classical" && algo !=
"distance laplacian" && algo !=
"signed classical",
Exceptions::RuntimeError,
"\"algorithm\" must be one of (classical|distance laplacian|signed classical)");
290 if (pL.get<
bool>(
"aggregation: use ml scaling of drop tol"))
291 threshold = pL.get<
double>(
"aggregation: drop tol") / pow(2.0, currentLevel.
GetLevelID());
293 threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
295 std::string distanceLaplacianAlgoStr = pL.get<std::string>(
"aggregation: distance laplacian algo");
296 std::string classicalAlgoStr = pL.get<std::string>(
"aggregation: classical algo");
297 real_type realThreshold = STS::magnitude(threshold);
301#ifdef HAVE_MUELU_DEBUG
302 int distanceLaplacianCutVerbose = 0;
304#ifdef DJS_READ_ENV_VARIABLES
305 if (getenv(
"MUELU_DROP_TOLERANCE_MODE")) {
306 distanceLaplacianAlgoStr = std::string(getenv(
"MUELU_DROP_TOLERANCE_MODE"));
309 if (getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD")) {
310 auto tmp = atoi(getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD"));
311 realThreshold = 1e-4 * tmp;
314#ifdef HAVE_MUELU_DEBUG
315 if (getenv(
"MUELU_DROP_TOLERANCE_VERBOSE")) {
316 distanceLaplacianCutVerbose = atoi(getenv(
"MUELU_DROP_TOLERANCE_VERBOSE"));
324 if (algo ==
"distance laplacian") {
325 if (distanceLaplacianAlgoStr ==
"default")
327 else if (distanceLaplacianAlgoStr ==
"unscaled cut")
329 else if (distanceLaplacianAlgoStr ==
"scaled cut")
331 else if (distanceLaplacianAlgoStr ==
"scaled cut symmetric")
334 TEUCHOS_TEST_FOR_EXCEPTION(
true,
Exceptions::RuntimeError,
"\"aggregation: distance laplacian algo\" must be one of (default|unscaled cut|scaled cut), not \"" << distanceLaplacianAlgoStr <<
"\"");
335 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" distance laplacian algorithm = \"" << distanceLaplacianAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
336 }
else if (algo ==
"classical") {
337 if (classicalAlgoStr ==
"default")
339 else if (classicalAlgoStr ==
"unscaled cut")
341 else if (classicalAlgoStr ==
"scaled cut")
344 TEUCHOS_TEST_FOR_EXCEPTION(
true,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" must be one of (default|unscaled cut|scaled cut), not \"" << classicalAlgoStr <<
"\"");
345 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" classical algorithm = \"" << classicalAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
348 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
350 if (((algo ==
"classical") && (classicalAlgoStr.find(
"scaled") != std::string::npos)) || ((algo ==
"distance laplacian") && (distanceLaplacianAlgoStr.find(
"scaled") != std::string::npos)))
351 TEUCHOS_TEST_FOR_EXCEPTION(realThreshold > 1.0,
Exceptions::RuntimeError,
"For cut-drop algorithms, \"aggregation: drop tol\" = " << threshold <<
", needs to be <= 1.0");
353 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
355 const typename STS::magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.get<
double>(
"aggregation: Dirichlet threshold")));
358 TEUCHOS_TEST_FOR_EXCEPTION(useSignedClassicalRS && classicalAlgo !=
defaultAlgo,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" != default is not supported for scalled classical aggregation");
359 TEUCHOS_TEST_FOR_EXCEPTION(useSignedClassicalSA && classicalAlgo !=
defaultAlgo,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" != default is not supported for scalled classical sa aggregation");
361 GO numDropped = 0, numTotal = 0;
362 std::string graphType =
"unamalgamated";
380 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0,
Exceptions::RuntimeError,
"A->GetFixedBlockSize() needs to be a multiple of A->GetStorageBlockSize()");
381 const LO BlockSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
384 if (algo ==
"classical") {
391 RCP<PreDropFunctionConstVal> predropConstVal = rcp_dynamic_cast<PreDropFunctionConstVal>(
predrop_);
393 "MueLu::CoalesceFactory::Build: cast to PreDropFunctionConstVal failed.");
395 SC newt = predropConstVal->GetThreshold();
396 if (newt != threshold) {
397 GetOStream(
Warnings0) <<
"switching threshold parameter from " << threshold <<
" (list) to " << newt <<
" (user function" << std::endl;
404 if (BlockSize == 1 && threshold == STS::zero() && !useSignedClassicalRS && !useSignedClassicalSA && A->hasCrsGraph()) {
406 RCP<LWGraph> graph = rcp(
new LWGraph(A->getCrsGraph(),
"graph of A"));
412 graph->SetBoundaryNodeMap(boundaryNodes);
413 numTotal = A->getLocalNumEntries();
416 GO numLocalBoundaryNodes = 0;
417 GO numGlobalBoundaryNodes = 0;
418 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
419 if (boundaryNodes[i])
420 numLocalBoundaryNodes++;
421 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
422 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
426 Set(currentLevel,
"DofsPerNode", 1);
427 Set(currentLevel,
"Graph", graph);
429 }
else if ((BlockSize == 1 && threshold != STS::zero()) ||
430 (BlockSize == 1 && threshold == STS::zero() && !A->hasCrsGraph()) ||
431 (BlockSize == 1 && useSignedClassicalRS) ||
432 (BlockSize == 1 && useSignedClassicalSA)) {
438 typename LWGraph::row_type::non_const_type rows(
"rows", A->getLocalNumRows() + 1);
439 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
441 using MT =
typename STS::magnitudeType;
442 RCP<Vector> ghostedDiag;
443 ArrayRCP<const SC> ghostedDiagVals;
444 ArrayRCP<const SC> negMaxOffDiagonal;
446 if (useSignedClassicalRS) {
447 if (ghostedBlockNumber.is_null()) {
449 negMaxOffDiagonal = negMaxOffDiagonalVec->getData(0);
454 negMaxOffDiagonal = negMaxOffDiagonalVec->getData(0);
461 ghostedDiagVals = ghostedDiag->getData(0);
465 if (rowSumTol > 0.) {
466 if (ghostedBlockNumber.is_null()) {
477 ArrayRCP<const LO> g_block_id;
478 if (!ghostedBlockNumber.is_null())
479 g_block_id = ghostedBlockNumber->getData(0);
485 for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
486 size_t nnz = A->getNumEntriesInLocalRow(row);
487 bool rowIsDirichlet = boundaryNodes[row];
488 ArrayView<const LO> indices;
489 ArrayView<const SC> vals;
490 A->getLocalRowView(row, indices, vals);
498 if (useSignedClassicalRS) {
500 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
501 LO col = indices[colID];
502 MT max_neg_aik = realThreshold * STS::real(negMaxOffDiagonal[row]);
503 MT neg_aij = -STS::real(vals[colID]);
508 if ((!rowIsDirichlet && (g_block_id.is_null() || g_block_id[row] == g_block_id[col]) && neg_aij > max_neg_aik) || row == col) {
509 columns[realnnz++] = col;
514 rows(row + 1) = realnnz;
515 }
else if (useSignedClassicalSA) {
517 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
518 LO col = indices[colID];
520 bool is_nonpositive = STS::real(vals[colID]) <= 0;
521 MT aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
522 MT aij = is_nonpositive ? STS::magnitude(vals[colID] * vals[colID]) : (-STS::magnitude(vals[colID] * vals[colID]));
528 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
529 columns(realnnz++) = col;
534 rows[row + 1] = realnnz;
537 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
538 LO col = indices[colID];
539 MT aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
540 MT aij = STS::magnitude(vals[colID] * vals[colID]);
542 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
543 columns(realnnz++) = col;
548 rows(row + 1) = realnnz;
554 using ExecSpace =
typename Node::execution_space;
555 using TeamPol = Kokkos::TeamPolicy<ExecSpace>;
556 using TeamMem =
typename TeamPol::member_type;
557#if KOKKOS_VERSION >= 40799
558 using ATS = KokkosKernels::ArithTraits<Scalar>;
560 using ATS = Kokkos::ArithTraits<Scalar>;
562 using impl_scalar_type =
typename ATS::val_type;
563#if KOKKOS_VERSION >= 40799
564 using implATS = KokkosKernels::ArithTraits<impl_scalar_type>;
566 using implATS = Kokkos::ArithTraits<impl_scalar_type>;
570 auto ghostedDiagValsView = Kokkos::subview(ghostedDiag->getLocalViewDevice(Tpetra::Access::ReadOnly), Kokkos::ALL(), 0);
571 auto thresholdKokkos =
static_cast<impl_scalar_type
>(threshold);
572 auto realThresholdKokkos = implATS::magnitude(thresholdKokkos);
573 auto columnsDevice = Kokkos::create_mirror_view(ExecSpace(), columns);
575 auto A_device = A->getLocalMatrixDevice();
576 RCP<LWGraph> graph = rcp(
new LWGraph(A->getCrsGraph(),
"graph of A"));
577 RCP<const Import> importer = A->getCrsGraph()->getImporter();
578 RCP<LocalOrdinalVector> boundaryNodesVector = Xpetra::VectorFactory<LO, LO, GO, NO>::Build(graph->GetDomainMap());
579 RCP<LocalOrdinalVector> boundaryColumnVector;
580 for (
size_t i = 0; i < graph->GetNodeNumVertices(); i++) {
581 boundaryNodesVector->getDataNonConst(0)[i] = boundaryNodes[i];
583 if (!importer.is_null()) {
584 boundaryColumnVector = Xpetra::VectorFactory<LO, LO, GO, NO>::Build(graph->GetImportMap());
585 boundaryColumnVector->doImport(*boundaryNodesVector, *importer, Xpetra::INSERT);
587 boundaryColumnVector = boundaryNodesVector;
589 auto boundaryColumn = boundaryColumnVector->getLocalViewDevice(Tpetra::Access::ReadOnly);
590 auto boundary = Kokkos::subview(boundaryColumn, Kokkos::ALL(), 0);
592 Kokkos::View<LO*, ExecSpace> rownnzView(
"rownnzView", A_device.numRows());
593 auto drop_views = Kokkos::View<bool*, ExecSpace>(
"drop_views", A_device.nnz());
594 auto index_views = Kokkos::View<size_t*, ExecSpace>(
"index_views", A_device.nnz());
596 Kokkos::parallel_reduce(
597 "classical_cut", TeamPol(A_device.numRows(), Kokkos::AUTO), KOKKOS_LAMBDA(
const TeamMem& teamMember, LO& globalnnz, GO& totalDropped) {
598 LO row = teamMember.league_rank();
599 auto rowView = A_device.rowConst(row);
600 size_t nnz = rowView.length;
602 auto drop_view = Kokkos::subview(drop_views, Kokkos::make_pair(A_device.graph.row_map(row), A_device.graph.row_map(row + 1)));
603 auto index_view = Kokkos::subview(index_views, Kokkos::make_pair(A_device.graph.row_map(row), A_device.graph.row_map(row + 1)));
606 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember, (LO)nnz), [&](
const LO colID) {
607 index_view(colID) = colID;
608 LO col = rowView.colidx(colID);
611 if (row == col || boundary(col)) {
612 drop_view(colID) =
true;
614 drop_view(colID) =
false;
618 size_t dropStart = nnz;
621 Kokkos::Experimental::sort_team(teamMember, index_view, [=](
size_t& x,
size_t& y) ->
bool {
622 if (drop_view(x) || drop_view(y)) {
623 return drop_view(x) < drop_view(y);
625 auto x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
626 auto y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
627 return x_aij > y_aij;
632 Kokkos::parallel_reduce(
633 Kokkos::TeamThreadRange(teamMember, 1, nnz), [=](
size_t i,
size_t& min) {
634 auto const& x = index_view(i - 1);
635 auto const& y = index_view(i);
636 typename implATS::magnitudeType x_aij = 0;
637 typename implATS::magnitudeType y_aij = 0;
639 x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
642 y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
645 if (realThresholdKokkos * realThresholdKokkos * x_aij > y_aij) {
651 Kokkos::Min<size_t>(dropStart));
654 Kokkos::Experimental::sort_team(teamMember, index_view, [=](
size_t& x,
size_t& y) ->
bool {
655 if (drop_view(x) || drop_view(y)) {
656 return drop_view(x) < drop_view(y);
658 auto x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
659 auto y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
660 auto x_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(x)) * ghostedDiagValsView(row));
661 auto y_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(y)) * ghostedDiagValsView(row));
662 return (x_aij / x_aiiajj) > (y_aij / y_aiiajj);
667 Kokkos::parallel_reduce(
668 Kokkos::TeamThreadRange(teamMember, 1, nnz), [=](
size_t i,
size_t& min) {
669 auto const& x = index_view(i - 1);
670 auto const& y = index_view(i);
671 typename implATS::magnitudeType x_val = 0;
672 typename implATS::magnitudeType y_val = 0;
674 typename implATS::magnitudeType x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
675 typename implATS::magnitudeType x_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(x)) * ghostedDiagValsView(row));
676 x_val = x_aij / x_aiiajj;
679 typename implATS::magnitudeType y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
680 typename implATS::magnitudeType y_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(y)) * ghostedDiagValsView(row));
681 y_val = y_aij / y_aiiajj;
684 if (realThresholdKokkos * realThresholdKokkos * x_val > y_val) {
690 Kokkos::Min<size_t>(dropStart));
694 if (dropStart < nnz) {
695 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember, dropStart, nnz), [=](
size_t i) {
696 drop_view(index_view(i)) =
true;
702 Kokkos::parallel_reduce(
703 Kokkos::TeamThreadRange(teamMember, nnz), [=](
const size_t idxID, LO& keep, GO& drop) {
704 LO col = rowView.colidx(idxID);
706 if (row == col || !drop_view(idxID)) {
707 columnsDevice(A_device.graph.row_map(row) + idxID) = col;
710 columnsDevice(A_device.graph.row_map(row) + idxID) = -1;
716 Kokkos::single(Kokkos::PerTeam(teamMember), [&]() {
718 totalDropped += rowDropped;
719 rownnzView(row) = rownnz;
722 realnnz, numDropped);
725 Kokkos::Experimental::remove(ExecSpace(), columnsDevice, -1);
726 Kokkos::deep_copy(columns, columnsDevice);
729 auto rowsDevice = Kokkos::create_mirror_view(ExecSpace(), rows);
730 Kokkos::parallel_scan(
731 Kokkos::RangePolicy<ExecSpace>(0, A_device.numRows()), KOKKOS_LAMBDA(
const int i, LO& partial_sum,
bool is_final) {
732 partial_sum += rownnzView(i);
733 if (is_final) rowsDevice(i + 1) = partial_sum;
735 Kokkos::deep_copy(rows, rowsDevice);
738 numTotal = A->getLocalNumEntries();
740 if (aggregationMayCreateDirichlet) {
742 for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
743 if (rows[row + 1] - rows[row] <= 1)
744 boundaryNodes[row] =
true;
748 RCP<LWGraph> graph = rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), A->getRowMap(), A->getColMap(),
"thresholded graph of A"));
749 graph->SetBoundaryNodeMap(boundaryNodes);
751 GO numLocalBoundaryNodes = 0;
752 GO numGlobalBoundaryNodes = 0;
753 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
754 if (boundaryNodes(i))
755 numLocalBoundaryNodes++;
756 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
757 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
760 Set(currentLevel,
"Graph", graph);
761 Set(currentLevel,
"DofsPerNode", 1);
764 if (generateColoringGraph) {
765 RCP<LWGraph> colorGraph;
766 RCP<const Import> importer = A->getCrsGraph()->getImporter();
768 Set(currentLevel,
"Coloring Graph", colorGraph);
772 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(
"m_regular_graph." + std::to_string(currentLevel.
GetLevelID()), *rcp_dynamic_cast<LWGraph>(graph)->GetCrsGraph());
773 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(
"m_color_graph." + std::to_string(currentLevel.
GetLevelID()), *rcp_dynamic_cast<LWGraph>(colorGraph)->GetCrsGraph());
788 }
else if (BlockSize > 1 && threshold == STS::zero()) {
790 const RCP<const Map> rowMap = A->getRowMap();
791 const RCP<const Map> colMap = A->getColMap();
793 graphType =
"amalgamated";
799 RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
800 RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
801 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
802 Array<LO> colTranslation = *(amalInfo->getColTranslation());
805 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
808 typename LWGraph::row_type::non_const_type rows(
"rows", numRows + 1);
809 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
812 Kokkos::deep_copy(amalgBoundaryNodes,
false);
818 ArrayRCP<bool> pointBoundaryNodes;
824 LO blkSize = A->GetFixedBlockSize();
826 LO blkPartSize = A->GetFixedBlockSize();
827 if (A->IsView(
"stridedMaps") ==
true) {
828 Teuchos::RCP<const Map> myMap = A->getRowMap(
"stridedMaps");
829 Teuchos::RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
831 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
832 blkId = strMap->getStridedBlockId();
834 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
840 Array<LO> indicesExtra;
841 for (LO row = 0; row < numRows; row++) {
842 ArrayView<const LO> indices;
843 indicesExtra.resize(0);
851 bool isBoundary =
false;
852 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
853 for (LO j = 0; j < blkPartSize; j++) {
854 if (pointBoundaryNodes[row * blkPartSize + j]) {
861 for (LO j = 0; j < blkPartSize; j++) {
862 if (!pointBoundaryNodes[row * blkPartSize + j]) {
872 MergeRows(*A, row, indicesExtra, colTranslation);
874 indicesExtra.push_back(row);
875 indices = indicesExtra;
876 numTotal += indices.size();
880 LO nnz = indices.size(), rownnz = 0;
881 for (LO colID = 0; colID < nnz; colID++) {
882 LO col = indices[colID];
883 columns(realnnz++) = col;
894 amalgBoundaryNodes[row] =
true;
896 rows(row + 1) = realnnz;
899 RCP<LWGraph> graph = rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
900 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
903 GO numLocalBoundaryNodes = 0;
904 GO numGlobalBoundaryNodes = 0;
906 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
907 if (amalgBoundaryNodes(i))
908 numLocalBoundaryNodes++;
910 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
911 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
913 <<
" agglomerated Dirichlet nodes" << std::endl;
916 Set(currentLevel,
"Graph", graph);
917 Set(currentLevel,
"DofsPerNode", blkSize);
919 }
else if (BlockSize > 1 && threshold != STS::zero()) {
921 const RCP<const Map> rowMap = A->getRowMap();
922 const RCP<const Map> colMap = A->getColMap();
923 graphType =
"amalgamated";
929 RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
930 RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
931 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
932 Array<LO> colTranslation = *(amalInfo->getColTranslation());
935 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
938 typename LWGraph::row_type::non_const_type rows(
"rows", numRows + 1);
939 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
942 Kokkos::deep_copy(amalgBoundaryNodes,
false);
953 LO blkSize = A->GetFixedBlockSize();
955 LO blkPartSize = A->GetFixedBlockSize();
956 if (A->IsView(
"stridedMaps") ==
true) {
957 Teuchos::RCP<const Map> myMap = A->getRowMap(
"stridedMaps");
958 Teuchos::RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
960 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
961 blkId = strMap->getStridedBlockId();
963 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
968 const ArrayRCP<const SC> ghostedDiagVals = ghostedDiag->getData(0);
973 Array<LO> indicesExtra;
974 for (LO row = 0; row < numRows; row++) {
975 ArrayView<const LO> indices;
976 indicesExtra.resize(0);
984 bool isBoundary =
false;
985 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
986 for (LO j = 0; j < blkPartSize; j++) {
987 if (pointBoundaryNodes[row * blkPartSize + j]) {
994 for (LO j = 0; j < blkPartSize; j++) {
995 if (!pointBoundaryNodes[row * blkPartSize + j]) {
1007 indicesExtra.push_back(row);
1008 indices = indicesExtra;
1009 numTotal += indices.size();
1013 LO nnz = indices.size(), rownnz = 0;
1014 for (LO colID = 0; colID < nnz; colID++) {
1015 LO col = indices[colID];
1016 columns[realnnz++] = col;
1027 amalgBoundaryNodes[row] =
true;
1029 rows[row + 1] = realnnz;
1033 RCP<LWGraph> graph = rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1034 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1037 GO numLocalBoundaryNodes = 0;
1038 GO numGlobalBoundaryNodes = 0;
1040 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1041 if (amalgBoundaryNodes(i))
1042 numLocalBoundaryNodes++;
1044 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1045 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1047 <<
" agglomerated Dirichlet nodes" << std::endl;
1050 Set(currentLevel,
"Graph", graph);
1051 Set(currentLevel,
"DofsPerNode", blkSize);
1054 }
else if (algo ==
"distance laplacian") {
1055 LO blkSize = A->GetFixedBlockSize();
1056 GO indexBase = A->getRowMap()->getIndexBase();
1071 if ((blkSize == 1) && (threshold == STS::zero())) {
1073 RCP<LWGraph> graph = rcp(
new LWGraph(A->getCrsGraph(),
"graph of A"));
1074 graph->SetBoundaryNodeMap(pointBoundaryNodes);
1075 graphType =
"unamalgamated";
1076 numTotal = A->getLocalNumEntries();
1079 GO numLocalBoundaryNodes = 0;
1080 GO numGlobalBoundaryNodes = 0;
1081 for (
size_t i = 0; i < pointBoundaryNodes.size(); ++i)
1082 if (pointBoundaryNodes(i))
1083 numLocalBoundaryNodes++;
1084 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1085 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1086 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1089 Set(currentLevel,
"DofsPerNode", blkSize);
1090 Set(currentLevel,
"Graph", graph);
1105 TEUCHOS_TEST_FOR_EXCEPTION(A->getRowMap()->getLocalNumElements() / blkSize != Coords->getLocalLength(),
Exceptions::Incompatible,
1106 "Coordinate vector length (" << Coords->getLocalLength() <<
") is incompatible with number of rows in A (" << A->getRowMap()->getLocalNumElements() <<
") by modulo block size (" << blkSize <<
").");
1108 const RCP<const Map> colMap = A->getColMap();
1109 RCP<const Map> uniqueMap, nonUniqueMap;
1110 Array<LO> colTranslation;
1112 uniqueMap = A->getRowMap();
1113 nonUniqueMap = A->getColMap();
1114 graphType =
"unamalgamated";
1117 uniqueMap = Coords->getMap();
1119 "Different index bases for matrix and coordinates");
1123 graphType =
"amalgamated";
1125 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
1127 RCP<RealValuedMultiVector> ghostedCoords;
1128 RCP<Vector> ghostedLaplDiag;
1129 Teuchos::ArrayRCP<SC> ghostedLaplDiagData;
1130 if (threshold != STS::zero()) {
1132 RCP<const Import> importer;
1135 if (blkSize == 1 && realA->getCrsGraph()->getImporter() != Teuchos::null) {
1137 importer = realA->getCrsGraph()->getImporter();
1140 importer = ImportFactory::Build(uniqueMap, nonUniqueMap);
1143 ghostedCoords = Xpetra::MultiVectorFactory<real_type, LO, GO, NO>::Build(nonUniqueMap, Coords->getNumVectors());
1146 ghostedCoords->doImport(*Coords, *importer, Xpetra::INSERT);
1150 RCP<Vector> localLaplDiag = VectorFactory::Build(uniqueMap);
1151 Array<LO> indicesExtra;
1152 Teuchos::Array<Teuchos::ArrayRCP<const real_type>> coordData;
1153 if (threshold != STS::zero()) {
1154 const size_t numVectors = ghostedCoords->getNumVectors();
1155 coordData.reserve(numVectors);
1156 for (
size_t j = 0; j < numVectors; j++) {
1157 Teuchos::ArrayRCP<const real_type> tmpData = ghostedCoords->getData(j);
1158 coordData.push_back(tmpData);
1163 ArrayRCP<SC> localLaplDiagData = localLaplDiag->getDataNonConst(0);
1164 for (LO row = 0; row < numRows; row++) {
1165 ArrayView<const LO> indices;
1168 ArrayView<const SC> vals;
1169 A->getLocalRowView(row, indices, vals);
1173 indicesExtra.resize(0);
1174 MergeRows(*A, row, indicesExtra, colTranslation);
1175 indices = indicesExtra;
1178 LO nnz = indices.size();
1179 bool haveAddedToDiag =
false;
1180 for (LO colID = 0; colID < nnz; colID++) {
1181 const LO col = indices[colID];
1184 if (use_dlap_weights == SINGLE_WEIGHTS) {
1189 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1190 int block_id = row % interleaved_blocksize;
1191 int block_start = block_id * interleaved_blocksize;
1197 haveAddedToDiag =
true;
1202 if (!haveAddedToDiag)
1203 localLaplDiagData[row] = STS::squareroot(STS::rmax());
1208 ghostedLaplDiag = VectorFactory::Build(nonUniqueMap);
1209 ghostedLaplDiag->doImport(*localLaplDiag, *importer, Xpetra::INSERT);
1210 ghostedLaplDiagData = ghostedLaplDiag->getDataNonConst(0);
1214 GetOStream(
Runtime0) <<
"Skipping distance laplacian construction due to 0 threshold" << std::endl;
1220 typename LWGraph::row_type::non_const_type rows(
"rows", numRows + 1);
1221 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
1223#ifdef HAVE_MUELU_DEBUG
1225 for (LO i = 0; i < (LO)columns.size(); i++) columns[i] = -666;
1229 ArrayRCP<LO> rows_stop;
1230 bool use_stop_array = threshold != STS::zero() && distanceLaplacianAlgo ==
scaled_cut_symmetric;
1233 rows_stop.resize(numRows);
1236 Kokkos::deep_copy(amalgBoundaryNodes,
false);
1241 Array<LO> indicesExtra;
1244 Teuchos::Array<Teuchos::ArrayRCP<const real_type>> coordData;
1245 if (threshold != STS::zero()) {
1246 const size_t numVectors = ghostedCoords->getNumVectors();
1247 coordData.reserve(numVectors);
1248 for (
size_t j = 0; j < numVectors; j++) {
1249 Teuchos::ArrayRCP<const real_type> tmpData = ghostedCoords->getData(j);
1250 coordData.push_back(tmpData);
1254 ArrayView<const SC> vals;
1255 for (LO row = 0; row < numRows; row++) {
1256 ArrayView<const LO> indices;
1257 indicesExtra.resize(0);
1258 bool isBoundary =
false;
1262 A->getLocalRowView(row, indices, vals);
1263 isBoundary = pointBoundaryNodes[row];
1267 for (LO j = 0; j < blkSize; j++) {
1268 if (!pointBoundaryNodes[row * blkSize + j]) {
1276 MergeRows(*A, row, indicesExtra, colTranslation);
1278 indicesExtra.push_back(row);
1279 indices = indicesExtra;
1281 numTotal += indices.size();
1283 LO nnz = indices.size(), rownnz = 0;
1285 if (use_stop_array) {
1286 rows(row + 1) = rows(row) + nnz;
1287 realnnz = rows(row);
1290 if (threshold != STS::zero()) {
1294 for (LO colID = 0; colID < nnz; colID++) {
1295 LO col = indices[colID];
1298 columns(realnnz++) = col;
1304 if (isBoundary)
continue;
1307 if (use_dlap_weights == SINGLE_WEIGHTS) {
1309 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1310 int block_id = row % interleaved_blocksize;
1311 int block_start = block_id * interleaved_blocksize;
1316 real_type aiiajj = STS::magnitude(realThreshold * realThreshold * ghostedLaplDiagData[row] * ghostedLaplDiagData[col]);
1317 real_type aij = STS::magnitude(laplVal * laplVal);
1320 columns(realnnz++) = col;
1329 std::vector<DropTol> drop_vec;
1330 drop_vec.reserve(nnz);
1331 const real_type zero = Teuchos::ScalarTraits<real_type>::zero();
1332 const real_type one = Teuchos::ScalarTraits<real_type>::one();
1335 for (LO colID = 0; colID < nnz; colID++) {
1336 LO col = indices[colID];
1339 drop_vec.emplace_back(zero, one, colID,
false);
1343 if (isBoundary)
continue;
1346 if (use_dlap_weights == SINGLE_WEIGHTS) {
1348 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1349 int block_id = row % interleaved_blocksize;
1350 int block_start = block_id * interleaved_blocksize;
1356 real_type aiiajj = STS::magnitude(ghostedLaplDiagData[row] * ghostedLaplDiagData[col]);
1357 real_type aij = STS::magnitude(laplVal * laplVal);
1359 drop_vec.emplace_back(aij, aiiajj, colID,
false);
1362 const size_t n = drop_vec.size();
1365 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1366 return a.val > b.val;
1370 for (
size_t i = 1; i < n; ++i) {
1372 auto const& x = drop_vec[i - 1];
1373 auto const& y = drop_vec[i];
1376 if (realThreshold * realThreshold * a > b) {
1378#ifdef HAVE_MUELU_DEBUG
1379 if (distanceLaplacianCutVerbose) {
1380 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
1385 drop_vec[i].drop = drop;
1388 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1389 return a.val / a.diag > b.val / b.diag;
1393 for (
size_t i = 1; i < n; ++i) {
1395 auto const& x = drop_vec[i - 1];
1396 auto const& y = drop_vec[i];
1397 auto a = x.val / x.diag;
1398 auto b = y.val / y.diag;
1399 if (realThreshold * realThreshold * a > b) {
1401#ifdef HAVE_MUELU_DEBUG
1402 if (distanceLaplacianCutVerbose) {
1403 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
1408 drop_vec[i].drop = drop;
1412 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1413 return a.col < b.col;
1416 for (LO idxID = 0; idxID < (LO)drop_vec.size(); idxID++) {
1417 LO col = indices[drop_vec[idxID].col];
1421 columns(realnnz++) = col;
1427 if (!drop_vec[idxID].drop) {
1428 columns(realnnz++) = col;
1439 for (LO colID = 0; colID < nnz; colID++) {
1440 LO col = indices[colID];
1441 columns(realnnz++) = col;
1453 amalgBoundaryNodes[row] =
true;
1457 rows_stop[row] = rownnz + rows[row];
1459 rows[row + 1] = realnnz;
1464 if (use_stop_array) {
1467 for (LO row = 0; row < numRows; row++) {
1468 for (LO colidx = rows[row]; colidx < rows_stop[row]; colidx++) {
1469 LO col = columns[colidx];
1470 if (col >= numRows)
continue;
1473 for (LO t_col = rows(col); !found && t_col < rows_stop[col]; t_col++) {
1474 if (columns[t_col] == row)
1479 if (!found && !pointBoundaryNodes[col] && Teuchos::as<typename LWGraph::row_type::value_type>(rows_stop[col]) < rows[col + 1]) {
1480 LO new_idx = rows_stop[col];
1482 columns[new_idx] = row;
1490 LO current_start = 0;
1491 for (LO row = 0; row < numRows; row++) {
1492 LO old_start = current_start;
1493 for (LO col = rows(row); col < rows_stop[row]; col++) {
1494 if (current_start != col) {
1495 columns(current_start) = columns(col);
1499 rows[row] = old_start;
1501 rows(numRows) = realnnz = current_start;
1507 graph = rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1508 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1512 GO numLocalBoundaryNodes = 0;
1513 GO numGlobalBoundaryNodes = 0;
1515 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1516 if (amalgBoundaryNodes(i))
1517 numLocalBoundaryNodes++;
1519 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1520 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1522 <<
" using threshold " << dirichletThreshold << std::endl;
1525 Set(currentLevel,
"Graph", graph);
1526 Set(currentLevel,
"DofsPerNode", blkSize);
1531 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1532 GO numGlobalTotal, numGlobalDropped;
1535 GetOStream(
Statistics1) <<
"Number of dropped entries in " << graphType <<
" matrix graph: " << numGlobalDropped <<
"/" << numGlobalTotal;
1536 if (numGlobalTotal != 0)
1537 GetOStream(
Statistics1) <<
" (" << 100 * Teuchos::as<double>(numGlobalDropped) / Teuchos::as<double>(numGlobalTotal) <<
"%)";
1544 SC threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
1548 <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
1549 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
1551 RCP<const Map> rowMap = A->getRowMap();
1552 RCP<const Map> colMap = A->getColMap();
1555 GO indexBase = rowMap->getIndexBase();
1559 if (A->IsView(
"stridedMaps") &&
1560 Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap(
"stridedMaps")) != Teuchos::null) {
1561 Xpetra::viewLabel_t oldView = A->SwitchToView(
"stridedMaps");
1562 RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap());
1563 TEUCHOS_TEST_FOR_EXCEPTION(strMap == Teuchos::null,
Exceptions::BadCast,
"MueLu::CoalesceFactory::Build: cast to strided row map failed.");
1564 blockdim = strMap->getFixedBlockSize();
1565 offset = strMap->getOffset();
1566 oldView = A->SwitchToView(oldView);
1568 <<
" found blockdim=" << blockdim <<
" from strided maps. offset=" << offset << std::endl;
1570 GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build(): no striding information available. Use blockdim=1 with offset=0" << std::endl;
1574 RCP<const Map> nodeMap = amalInfo->getNodeRowMap();
1575 GetOStream(
Statistics1) <<
"CoalesceDropFactory: nodeMap " << nodeMap->getLocalNumElements() <<
"/" << nodeMap->getGlobalNumElements() <<
" elements" << std::endl;
1578 RCP<CrsGraph> crsGraph = CrsGraphFactory::Build(nodeMap, A->getLocalMaxNumRowEntries() * blockdim);
1580 LO numRows = A->getRowMap()->getLocalNumElements();
1581 LO numNodes = nodeMap->getLocalNumElements();
1583 Kokkos::deep_copy(amalgBoundaryNodes,
false);
1584 const ArrayRCP<int> numberDirichletRowsPerNode(numNodes, 0);
1585 bool bIsDiagonalEntry =
false;
1590 for (LO row = 0; row < numRows; row++) {
1592 GO grid = rowMap->getGlobalElement(row);
1595 bIsDiagonalEntry =
false;
1600 size_t nnz = A->getNumEntriesInLocalRow(row);
1601 Teuchos::ArrayView<const LO> indices;
1602 Teuchos::ArrayView<const SC> vals;
1603 A->getLocalRowView(row, indices, vals);
1605 RCP<std::vector<GO>> cnodeIds = Teuchos::rcp(
new std::vector<GO>);
1607 for (LO col = 0; col < Teuchos::as<LO>(nnz); col++) {
1608 GO gcid = colMap->getGlobalElement(indices[col]);
1610 if (vals[col] != STS::zero()) {
1612 cnodeIds->push_back(cnodeId);
1614 if (grid == gcid) bIsDiagonalEntry =
true;
1618 if (realnnz == 1 && bIsDiagonalEntry ==
true) {
1619 LO lNodeId = nodeMap->getLocalElement(nodeId);
1620 numberDirichletRowsPerNode[lNodeId] += 1;
1621 if (numberDirichletRowsPerNode[lNodeId] == blockdim)
1622 amalgBoundaryNodes[lNodeId] =
true;
1625 Teuchos::ArrayRCP<GO> arr_cnodeIds = Teuchos::arcp(cnodeIds);
1627 if (arr_cnodeIds.size() > 0)
1628 crsGraph->insertGlobalIndices(nodeId, arr_cnodeIds());
1631 crsGraph->fillComplete(nodeMap, nodeMap);
1634 RCP<LWGraph> graph = rcp(
new LWGraph(crsGraph,
"amalgamated graph of A"));
1637 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1640 GO numLocalBoundaryNodes = 0;
1641 GO numGlobalBoundaryNodes = 0;
1642 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1643 if (amalgBoundaryNodes(i))
1644 numLocalBoundaryNodes++;
1645 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1646 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1647 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1652 Set(currentLevel,
"DofsPerNode", blockdim);
1653 Set(currentLevel,
"Graph", graph);