146 typedef Teuchos::ScalarTraits<SC> STS;
147 typedef typename STS::magnitudeType real_type;
148 typedef Xpetra::MultiVector<real_type, LO, GO, NO> RealValuedMultiVector;
149 typedef Xpetra::MultiVectorFactory<real_type, LO, GO, NO> RealValuedMultiVectorFactory;
151 if (predrop_ != Teuchos::null)
152 GetOStream(
Parameters0) << predrop_->description();
154 RCP<Matrix> realA = Get<RCP<Matrix>>(currentLevel,
"A");
155 RCP<AmalgamationInfo> amalInfo = Get<RCP<AmalgamationInfo>>(currentLevel,
"UnAmalgamationInfo");
156 const ParameterList& pL = GetParameterList();
157 bool doExperimentalWrap = pL.get<
bool>(
"lightweight wrap");
159 GetOStream(
Parameters0) <<
"lightweight wrap = " << doExperimentalWrap << std::endl;
160 std::string algo = pL.get<std::string>(
"aggregation: drop scheme");
161 const bool aggregationMayCreateDirichlet = pL.get<
bool>(
"aggregation: dropping may create Dirichlet");
163 RCP<RealValuedMultiVector> Coords;
166 bool use_block_algorithm =
false;
167 LO interleaved_blocksize = as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize"));
168 bool useSignedClassicalRS =
false;
169 bool useSignedClassicalSA =
false;
170 bool generateColoringGraph =
false;
174 typename STS::magnitudeType rowSumTol = as<typename STS::magnitudeType>(pL.get<
double>(
"aggregation: row sum drop tol"));
176 RCP<LocalOrdinalVector> ghostedBlockNumber;
178 if (algo ==
"distance laplacian") {
180 Coords = Get<RCP<RealValuedMultiVector>>(currentLevel,
"Coordinates");
182 }
else if (algo ==
"signed classical sa") {
183 useSignedClassicalSA =
true;
186 }
else if (algo ==
"signed classical" || algo ==
"block diagonal colored signed classical" || algo ==
"block diagonal signed classical") {
187 useSignedClassicalRS =
true;
189 RCP<LocalOrdinalVector> BlockNumber = Get<RCP<LocalOrdinalVector>>(currentLevel,
"BlockNumber");
191 RCP<const Import> importer = realA->getCrsGraph()->getImporter();
192 if (!importer.is_null()) {
194 ghostedBlockNumber = Xpetra::VectorFactory<LO, LO, GO, NO>::Build(importer->getTargetMap());
195 ghostedBlockNumber->doImport(*BlockNumber, *importer, Xpetra::INSERT);
197 ghostedBlockNumber = BlockNumber;
200 if (algo ==
"block diagonal colored signed classical")
201 generateColoringGraph =
true;
205 }
else if (algo ==
"block diagonal") {
207 BlockDiagonalize(currentLevel, realA,
false);
209 }
else if (algo ==
"block diagonal classical" || algo ==
"block diagonal distance laplacian") {
211 use_block_algorithm =
true;
212 RCP<Matrix> filteredMatrix = BlockDiagonalize(currentLevel, realA,
true);
213 if (algo ==
"block diagonal distance laplacian") {
215 RCP<RealValuedMultiVector> OldCoords = Get<RCP<RealValuedMultiVector>>(currentLevel,
"Coordinates");
216 if (OldCoords->getLocalLength() != realA->getLocalNumRows()) {
217 LO dim = (LO)OldCoords->getNumVectors();
218 Coords = RealValuedMultiVectorFactory::Build(realA->getRowMap(), dim);
219 for (LO k = 0; k < dim; k++) {
220 ArrayRCP<const real_type> old_vec = OldCoords->getData(k);
221 ArrayRCP<real_type> new_vec = Coords->getDataNonConst(k);
222 for (LO i = 0; i < (LO)OldCoords->getLocalLength(); i++) {
223 LO new_base = i * dim;
224 for (LO j = 0; j < interleaved_blocksize; j++)
225 new_vec[new_base + j] = old_vec[i];
231 algo =
"distance laplacian";
232 }
else if (algo ==
"block diagonal classical") {
243 Array<double> dlap_weights = pL.get<Array<double>>(
"aggregation: distance laplacian directional weights");
244 enum { NO_WEIGHTS = 0,
247 int use_dlap_weights = NO_WEIGHTS;
248 if (algo ==
"distance laplacian") {
249 LO dim = (LO)Coords->getNumVectors();
251 bool non_unity =
false;
252 for (LO i = 0; !non_unity && i < (LO)dlap_weights.size(); i++) {
253 if (dlap_weights[i] != 1.0) {
258 LO blocksize = use_block_algorithm ? as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize")) : 1;
259 if ((LO)dlap_weights.size() == dim)
260 use_dlap_weights = SINGLE_WEIGHTS;
261 else if ((LO)dlap_weights.size() == blocksize * dim)
262 use_dlap_weights = BLOCK_WEIGHTS;
265 "length of 'aggregation: distance laplacian directional weights' must equal the coordinate dimension OR the coordinate dimension times the blocksize");
268 GetOStream(
Statistics1) <<
"Using distance laplacian weights: " << dlap_weights << std::endl;
283 if (doExperimentalWrap) {
284 TEUCHOS_TEST_FOR_EXCEPTION(predrop_ != null && algo !=
"classical",
Exceptions::RuntimeError,
"Dropping function must not be provided for \"" << algo <<
"\" algorithm");
285 TEUCHOS_TEST_FOR_EXCEPTION(algo !=
"classical" && algo !=
"distance laplacian" && algo !=
"signed classical",
Exceptions::RuntimeError,
"\"algorithm\" must be one of (classical|distance laplacian|signed classical)");
289 if (pL.get<
bool>(
"aggregation: use ml scaling of drop tol"))
290 threshold = pL.get<
double>(
"aggregation: drop tol") / pow(2.0, currentLevel.
GetLevelID());
292 threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
294 std::string distanceLaplacianAlgoStr = pL.get<std::string>(
"aggregation: distance laplacian algo");
295 std::string classicalAlgoStr = pL.get<std::string>(
"aggregation: classical algo");
296 real_type realThreshold = STS::magnitude(threshold);
300#ifdef HAVE_MUELU_DEBUG
301 int distanceLaplacianCutVerbose = 0;
303#ifdef DJS_READ_ENV_VARIABLES
304 if (getenv(
"MUELU_DROP_TOLERANCE_MODE")) {
305 distanceLaplacianAlgoStr = std::string(getenv(
"MUELU_DROP_TOLERANCE_MODE"));
308 if (getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD")) {
309 auto tmp = atoi(getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD"));
310 realThreshold = 1e-4 * tmp;
313#ifdef HAVE_MUELU_DEBUG
314 if (getenv(
"MUELU_DROP_TOLERANCE_VERBOSE")) {
315 distanceLaplacianCutVerbose = atoi(getenv(
"MUELU_DROP_TOLERANCE_VERBOSE"));
323 if (algo ==
"distance laplacian") {
324 if (distanceLaplacianAlgoStr ==
"default")
326 else if (distanceLaplacianAlgoStr ==
"unscaled cut")
328 else if (distanceLaplacianAlgoStr ==
"scaled cut")
330 else if (distanceLaplacianAlgoStr ==
"scaled cut symmetric")
333 TEUCHOS_TEST_FOR_EXCEPTION(
true,
Exceptions::RuntimeError,
"\"aggregation: distance laplacian algo\" must be one of (default|unscaled cut|scaled cut), not \"" << distanceLaplacianAlgoStr <<
"\"");
334 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" distance laplacian algorithm = \"" << distanceLaplacianAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
335 }
else if (algo ==
"classical") {
336 if (classicalAlgoStr ==
"default")
338 else if (classicalAlgoStr ==
"unscaled cut")
340 else if (classicalAlgoStr ==
"scaled cut")
343 TEUCHOS_TEST_FOR_EXCEPTION(
true,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" must be one of (default|unscaled cut|scaled cut), not \"" << classicalAlgoStr <<
"\"");
344 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" classical algorithm = \"" << classicalAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
347 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
349 if (((algo ==
"classical") && (classicalAlgoStr.find(
"scaled") != std::string::npos)) || ((algo ==
"distance laplacian") && (distanceLaplacianAlgoStr.find(
"scaled") != std::string::npos)))
350 TEUCHOS_TEST_FOR_EXCEPTION(realThreshold > 1.0,
Exceptions::RuntimeError,
"For cut-drop algorithms, \"aggregation: drop tol\" = " << threshold <<
", needs to be <= 1.0");
352 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
354 const typename STS::magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.get<
double>(
"aggregation: Dirichlet threshold")));
357 TEUCHOS_TEST_FOR_EXCEPTION(useSignedClassicalRS && classicalAlgo !=
defaultAlgo,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" != default is not supported for scalled classical aggregation");
358 TEUCHOS_TEST_FOR_EXCEPTION(useSignedClassicalSA && classicalAlgo !=
defaultAlgo,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" != default is not supported for scalled classical sa aggregation");
360 GO numDropped = 0, numTotal = 0;
361 std::string graphType =
"unamalgamated";
379 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0,
Exceptions::RuntimeError,
"A->GetFixedBlockSize() needs to be a multiple of A->GetStorageBlockSize()");
380 const LO BlockSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
383 if (algo ==
"classical") {
384 if (predrop_ == null) {
389 if (predrop_ != null) {
390 RCP<PreDropFunctionConstVal> predropConstVal = rcp_dynamic_cast<PreDropFunctionConstVal>(predrop_);
392 "MueLu::CoalesceFactory::Build: cast to PreDropFunctionConstVal failed.");
394 SC newt = predropConstVal->GetThreshold();
395 if (newt != threshold) {
396 GetOStream(
Warnings0) <<
"switching threshold parameter from " << threshold <<
" (list) to " << newt <<
" (user function" << std::endl;
403 if (BlockSize == 1 && threshold == STS::zero() && !useSignedClassicalRS && !useSignedClassicalSA && A->hasCrsGraph()) {
405 RCP<LWGraph> graph = rcp(
new LWGraph(A->getCrsGraph(),
"graph of A"));
411 graph->SetBoundaryNodeMap(boundaryNodes);
412 numTotal = A->getLocalNumEntries();
415 GO numLocalBoundaryNodes = 0;
416 GO numGlobalBoundaryNodes = 0;
417 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
418 if (boundaryNodes[i])
419 numLocalBoundaryNodes++;
420 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
421 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
422 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
425 Set(currentLevel,
"DofsPerNode", 1);
426 Set(currentLevel,
"Graph", graph);
428 }
else if ((BlockSize == 1 && threshold != STS::zero()) ||
429 (BlockSize == 1 && threshold == STS::zero() && !A->hasCrsGraph()) ||
430 (BlockSize == 1 && useSignedClassicalRS) ||
431 (BlockSize == 1 && useSignedClassicalSA)) {
437 typename LWGraph::row_type::non_const_type
rows(
"rows", A->getLocalNumRows() + 1);
438 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
440 using MT =
typename STS::magnitudeType;
441 RCP<Vector> ghostedDiag;
442 ArrayRCP<const SC> ghostedDiagVals;
443 ArrayRCP<const SC> negMaxOffDiagonal;
445 if (useSignedClassicalRS) {
446 if (ghostedBlockNumber.is_null()) {
448 negMaxOffDiagonal = negMaxOffDiagonalVec->getData(0);
450 GetOStream(
Statistics1) <<
"Calculated max point off-diagonal" << std::endl;
453 negMaxOffDiagonal = negMaxOffDiagonalVec->getData(0);
455 GetOStream(
Statistics1) <<
"Calculating max block off-diagonal" << std::endl;
460 ghostedDiagVals = ghostedDiag->getData(0);
464 if (rowSumTol > 0.) {
465 if (ghostedBlockNumber.is_null()) {
467 GetOStream(
Statistics1) <<
"Applying point row sum criterion." << std::endl;
471 GetOStream(
Statistics1) <<
"Applying block row sum criterion." << std::endl;
476 ArrayRCP<const LO> g_block_id;
477 if (!ghostedBlockNumber.is_null())
478 g_block_id = ghostedBlockNumber->getData(0);
484 for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
485 size_t nnz = A->getNumEntriesInLocalRow(row);
486 bool rowIsDirichlet = boundaryNodes[row];
487 ArrayView<const LO> indices;
488 ArrayView<const SC> vals;
489 A->getLocalRowView(row, indices, vals);
497 if (useSignedClassicalRS) {
499 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
500 LO col = indices[colID];
501 MT max_neg_aik = realThreshold * STS::real(negMaxOffDiagonal[row]);
502 MT neg_aij = -STS::real(vals[colID]);
507 if ((!rowIsDirichlet && (g_block_id.is_null() || g_block_id[row] == g_block_id[col]) && neg_aij > max_neg_aik) || row == col) {
508 columns[realnnz++] = col;
513 rows(row + 1) = realnnz;
514 }
else if (useSignedClassicalSA) {
516 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
517 LO col = indices[colID];
519 bool is_nonpositive = STS::real(vals[colID]) <= 0;
520 MT aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
521 MT aij = is_nonpositive ? STS::magnitude(vals[colID] * vals[colID]) : (-STS::magnitude(vals[colID] * vals[colID]));
527 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
528 columns(realnnz++) = col;
533 rows[row + 1] = realnnz;
536 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
537 LO col = indices[colID];
538 MT aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
539 MT aij = STS::magnitude(vals[colID] * vals[colID]);
541 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
542 columns(realnnz++) = col;
547 rows(row + 1) = realnnz;
553 using ExecSpace =
typename Node::execution_space;
554 using TeamPol = Kokkos::TeamPolicy<ExecSpace>;
555 using TeamMem =
typename TeamPol::member_type;
556 using ATS = KokkosKernels::ArithTraits<Scalar>;
557 using impl_scalar_type =
typename ATS::val_type;
558 using implATS = KokkosKernels::ArithTraits<impl_scalar_type>;
561 auto ghostedDiagValsView = Kokkos::subview(ghostedDiag->getLocalViewDevice(Tpetra::Access::ReadOnly), Kokkos::ALL(), 0);
562 auto thresholdKokkos =
static_cast<impl_scalar_type
>(threshold);
563 auto realThresholdKokkos = implATS::magnitude(thresholdKokkos);
564 auto columnsDevice = Kokkos::create_mirror_view(ExecSpace(), columns);
566 auto A_device = A->getLocalMatrixDevice();
567 RCP<LWGraph> graph = rcp(
new LWGraph(A->getCrsGraph(),
"graph of A"));
568 RCP<const Import> importer = A->getCrsGraph()->getImporter();
569 RCP<LocalOrdinalVector> boundaryNodesVector = Xpetra::VectorFactory<LO, LO, GO, NO>::Build(graph->GetDomainMap());
570 RCP<LocalOrdinalVector> boundaryColumnVector;
571 for (
size_t i = 0; i < graph->GetNodeNumVertices(); i++) {
572 boundaryNodesVector->getDataNonConst(0)[i] = boundaryNodes[i];
574 if (!importer.is_null()) {
575 boundaryColumnVector = Xpetra::VectorFactory<LO, LO, GO, NO>::Build(graph->GetImportMap());
576 boundaryColumnVector->doImport(*boundaryNodesVector, *importer, Xpetra::INSERT);
578 boundaryColumnVector = boundaryNodesVector;
580 auto boundaryColumn = boundaryColumnVector->getLocalViewDevice(Tpetra::Access::ReadOnly);
581 auto boundary = Kokkos::subview(boundaryColumn, Kokkos::ALL(), 0);
583 Kokkos::View<LO*, ExecSpace> rownnzView(
"rownnzView", A_device.numRows());
584 auto drop_views = Kokkos::View<bool*, ExecSpace>(
"drop_views", A_device.nnz());
585 auto index_views = Kokkos::View<size_t*, ExecSpace>(
"index_views", A_device.nnz());
587 Kokkos::parallel_reduce(
588 "classical_cut", TeamPol(A_device.numRows(), Kokkos::AUTO), KOKKOS_LAMBDA(
const TeamMem& teamMember, LO& globalnnz, GO& totalDropped) {
589 LO row = teamMember.league_rank();
590 auto rowView = A_device.rowConst(row);
591 size_t nnz = rowView.length;
593 auto drop_view = Kokkos::subview(drop_views, Kokkos::make_pair(A_device.graph.row_map(row), A_device.graph.row_map(row + 1)));
594 auto index_view = Kokkos::subview(index_views, Kokkos::make_pair(A_device.graph.row_map(row), A_device.graph.row_map(row + 1)));
597 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember, (LO)nnz), [&](
const LO colID) {
598 index_view(colID) = colID;
599 LO col = rowView.colidx(colID);
602 if (row == col || boundary(col)) {
603 drop_view(colID) =
true;
605 drop_view(colID) =
false;
609 size_t dropStart = nnz;
612 Kokkos::Experimental::sort_team(teamMember, index_view, [=](
size_t& x,
size_t& y) ->
bool {
613 if (drop_view(x) || drop_view(y)) {
614 return drop_view(x) < drop_view(y);
616 auto x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
617 auto y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
618 return x_aij > y_aij;
623 Kokkos::parallel_reduce(
624 Kokkos::TeamThreadRange(teamMember, 1, nnz), [=](
size_t i,
size_t& min) {
625 auto const& x = index_view(i - 1);
626 auto const& y = index_view(i);
627 typename implATS::magnitudeType x_aij = 0;
628 typename implATS::magnitudeType y_aij = 0;
630 x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
633 y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
636 if (realThresholdKokkos * realThresholdKokkos * x_aij > y_aij) {
642 Kokkos::Min<size_t>(dropStart));
645 Kokkos::Experimental::sort_team(teamMember, index_view, [=](
size_t& x,
size_t& y) ->
bool {
646 if (drop_view(x) || drop_view(y)) {
647 return drop_view(x) < drop_view(y);
649 auto x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
650 auto y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
651 auto x_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(x)) * ghostedDiagValsView(row));
652 auto y_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(y)) * ghostedDiagValsView(row));
653 return (x_aij / x_aiiajj) > (y_aij / y_aiiajj);
658 Kokkos::parallel_reduce(
659 Kokkos::TeamThreadRange(teamMember, 1, nnz), [=](
size_t i,
size_t& min) {
660 auto const& x = index_view(i - 1);
661 auto const& y = index_view(i);
662 typename implATS::magnitudeType x_val = 0;
663 typename implATS::magnitudeType y_val = 0;
665 typename implATS::magnitudeType x_aij = implATS::magnitude(rowView.value(x) * rowView.value(x));
666 typename implATS::magnitudeType x_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(x)) * ghostedDiagValsView(row));
667 x_val = x_aij / x_aiiajj;
670 typename implATS::magnitudeType y_aij = implATS::magnitude(rowView.value(y) * rowView.value(y));
671 typename implATS::magnitudeType y_aiiajj = implATS::magnitude(ghostedDiagValsView(rowView.colidx(y)) * ghostedDiagValsView(row));
672 y_val = y_aij / y_aiiajj;
675 if (realThresholdKokkos * realThresholdKokkos * x_val > y_val) {
681 Kokkos::Min<size_t>(dropStart));
685 if (dropStart < nnz) {
686 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember, dropStart, nnz), [=](
size_t i) {
687 drop_view(index_view(i)) =
true;
693 Kokkos::parallel_reduce(
694 Kokkos::TeamThreadRange(teamMember, nnz), [=](
const size_t idxID, LO& keep, GO& drop) {
695 LO col = rowView.colidx(idxID);
697 if (row == col || !drop_view(idxID)) {
698 columnsDevice(A_device.graph.row_map(row) + idxID) = col;
701 columnsDevice(A_device.graph.row_map(row) + idxID) = -1;
707 Kokkos::single(Kokkos::PerTeam(teamMember), [&]() {
709 totalDropped += rowDropped;
710 rownnzView(row) = rownnz;
713 realnnz, numDropped);
716 Kokkos::Experimental::remove(ExecSpace(), columnsDevice, -1);
717 Kokkos::deep_copy(columns, columnsDevice);
720 auto rowsDevice = Kokkos::create_mirror_view(ExecSpace(),
rows);
721 Kokkos::parallel_scan(
722 Kokkos::RangePolicy<ExecSpace>(0, A_device.numRows()), KOKKOS_LAMBDA(
const int i, LO& partial_sum,
bool is_final) {
723 partial_sum += rownnzView(i);
724 if (is_final) rowsDevice(i + 1) = partial_sum;
726 Kokkos::deep_copy(
rows, rowsDevice);
729 numTotal = A->getLocalNumEntries();
731 if (aggregationMayCreateDirichlet) {
733 for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
735 boundaryNodes[row] =
true;
739 RCP<LWGraph> graph = rcp(
new LWGraph(
rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), A->getRowMap(), A->getColMap(),
"thresholded graph of A"));
740 graph->SetBoundaryNodeMap(boundaryNodes);
742 GO numLocalBoundaryNodes = 0;
743 GO numGlobalBoundaryNodes = 0;
744 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
745 if (boundaryNodes(i))
746 numLocalBoundaryNodes++;
747 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
748 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
749 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
751 Set(currentLevel,
"Graph", graph);
752 Set(currentLevel,
"DofsPerNode", 1);
755 if (generateColoringGraph) {
756 RCP<LWGraph> colorGraph;
757 RCP<const Import> importer = A->getCrsGraph()->getImporter();
758 BlockDiagonalizeGraph(graph, ghostedBlockNumber, colorGraph, importer);
759 Set(currentLevel,
"Coloring Graph", colorGraph);
763 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(
"m_regular_graph." + std::to_string(currentLevel.
GetLevelID()), *rcp_dynamic_cast<LWGraph>(graph)->GetCrsGraph());
764 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(
"m_color_graph." + std::to_string(currentLevel.
GetLevelID()), *rcp_dynamic_cast<LWGraph>(colorGraph)->GetCrsGraph());
779 }
else if (BlockSize > 1 && threshold == STS::zero()) {
781 const RCP<const Map> rowMap = A->getRowMap();
782 const RCP<const Map> colMap = A->getColMap();
784 graphType =
"amalgamated";
790 RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
791 RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
792 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
793 Array<LO> colTranslation = *(amalInfo->getColTranslation());
796 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
799 typename LWGraph::row_type::non_const_type
rows(
"rows", numRows + 1);
800 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
803 Kokkos::deep_copy(amalgBoundaryNodes,
false);
809 ArrayRCP<bool> pointBoundaryNodes;
815 LO blkSize = A->GetFixedBlockSize();
817 LO blkPartSize = A->GetFixedBlockSize();
818 if (A->IsView(
"stridedMaps") ==
true) {
819 Teuchos::RCP<const Map> myMap = A->getRowMap(
"stridedMaps");
820 Teuchos::RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
822 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
823 blkId = strMap->getStridedBlockId();
825 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
831 Array<LO> indicesExtra;
832 for (LO row = 0; row < numRows; row++) {
833 ArrayView<const LO> indices;
834 indicesExtra.resize(0);
842 bool isBoundary =
false;
843 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
844 for (LO j = 0; j < blkPartSize; j++) {
845 if (pointBoundaryNodes[row * blkPartSize + j]) {
852 for (LO j = 0; j < blkPartSize; j++) {
853 if (!pointBoundaryNodes[row * blkPartSize + j]) {
863 MergeRows(*A, row, indicesExtra, colTranslation);
865 indicesExtra.push_back(row);
866 indices = indicesExtra;
867 numTotal += indices.size();
871 LO nnz = indices.size(), rownnz = 0;
872 for (LO colID = 0; colID < nnz; colID++) {
873 LO col = indices[colID];
874 columns(realnnz++) = col;
885 amalgBoundaryNodes[row] =
true;
887 rows(row + 1) = realnnz;
890 RCP<LWGraph> graph = rcp(
new LWGraph(
rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
891 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
894 GO numLocalBoundaryNodes = 0;
895 GO numGlobalBoundaryNodes = 0;
897 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
898 if (amalgBoundaryNodes(i))
899 numLocalBoundaryNodes++;
901 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
902 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
903 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes
904 <<
" agglomerated Dirichlet nodes" << std::endl;
907 Set(currentLevel,
"Graph", graph);
908 Set(currentLevel,
"DofsPerNode", blkSize);
910 }
else if (BlockSize > 1 && threshold != STS::zero()) {
912 const RCP<const Map> rowMap = A->getRowMap();
913 const RCP<const Map> colMap = A->getColMap();
914 graphType =
"amalgamated";
920 RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
921 RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
922 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
923 Array<LO> colTranslation = *(amalInfo->getColTranslation());
926 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
929 typename LWGraph::row_type::non_const_type
rows(
"rows", numRows + 1);
930 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
933 Kokkos::deep_copy(amalgBoundaryNodes,
false);
944 LO blkSize = A->GetFixedBlockSize();
946 LO blkPartSize = A->GetFixedBlockSize();
947 if (A->IsView(
"stridedMaps") ==
true) {
948 Teuchos::RCP<const Map> myMap = A->getRowMap(
"stridedMaps");
949 Teuchos::RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
951 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
952 blkId = strMap->getStridedBlockId();
954 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
959 const ArrayRCP<const SC> ghostedDiagVals = ghostedDiag->getData(0);
964 Array<LO> indicesExtra;
965 for (LO row = 0; row < numRows; row++) {
966 ArrayView<const LO> indices;
967 indicesExtra.resize(0);
975 bool isBoundary =
false;
976 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
977 for (LO j = 0; j < blkPartSize; j++) {
978 if (pointBoundaryNodes[row * blkPartSize + j]) {
985 for (LO j = 0; j < blkPartSize; j++) {
986 if (!pointBoundaryNodes[row * blkPartSize + j]) {
996 MergeRowsWithDropping(*A, row, ghostedDiagVals, threshold, indicesExtra, colTranslation);
998 indicesExtra.push_back(row);
999 indices = indicesExtra;
1000 numTotal += indices.size();
1004 LO nnz = indices.size(), rownnz = 0;
1005 for (LO colID = 0; colID < nnz; colID++) {
1006 LO col = indices[colID];
1007 columns[realnnz++] = col;
1018 amalgBoundaryNodes[row] =
true;
1020 rows[row + 1] = realnnz;
1024 RCP<LWGraph> graph = rcp(
new LWGraph(
rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1025 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1028 GO numLocalBoundaryNodes = 0;
1029 GO numGlobalBoundaryNodes = 0;
1031 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1032 if (amalgBoundaryNodes(i))
1033 numLocalBoundaryNodes++;
1035 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1036 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1037 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes
1038 <<
" agglomerated Dirichlet nodes" << std::endl;
1041 Set(currentLevel,
"Graph", graph);
1042 Set(currentLevel,
"DofsPerNode", blkSize);
1045 }
else if (algo ==
"distance laplacian") {
1046 LO blkSize = A->GetFixedBlockSize();
1047 GO indexBase = A->getRowMap()->getIndexBase();
1062 if ((blkSize == 1) && (threshold == STS::zero())) {
1064 RCP<LWGraph> graph = rcp(
new LWGraph(A->getCrsGraph(),
"graph of A"));
1065 graph->SetBoundaryNodeMap(pointBoundaryNodes);
1066 graphType =
"unamalgamated";
1067 numTotal = A->getLocalNumEntries();
1070 GO numLocalBoundaryNodes = 0;
1071 GO numGlobalBoundaryNodes = 0;
1072 for (
size_t i = 0; i < pointBoundaryNodes.size(); ++i)
1073 if (pointBoundaryNodes(i))
1074 numLocalBoundaryNodes++;
1075 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1076 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1077 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1080 Set(currentLevel,
"DofsPerNode", blkSize);
1081 Set(currentLevel,
"Graph", graph);
1096 TEUCHOS_TEST_FOR_EXCEPTION(A->getRowMap()->getLocalNumElements() / blkSize != Coords->getLocalLength(),
Exceptions::Incompatible,
1097 "Coordinate vector length (" << Coords->getLocalLength() <<
") is incompatible with number of rows in A (" << A->getRowMap()->getLocalNumElements() <<
") by modulo block size (" << blkSize <<
").");
1099 const RCP<const Map> colMap = A->getColMap();
1100 RCP<const Map> uniqueMap, nonUniqueMap;
1101 Array<LO> colTranslation;
1103 uniqueMap = A->getRowMap();
1104 nonUniqueMap = A->getColMap();
1105 graphType =
"unamalgamated";
1108 uniqueMap = Coords->getMap();
1110 "Different index bases for matrix and coordinates");
1114 graphType =
"amalgamated";
1116 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
1118 RCP<RealValuedMultiVector> ghostedCoords;
1119 RCP<Vector> ghostedLaplDiag;
1120 Teuchos::ArrayRCP<SC> ghostedLaplDiagData;
1121 if (threshold != STS::zero()) {
1123 RCP<const Import> importer;
1126 if (blkSize == 1 && realA->getCrsGraph()->getImporter() != Teuchos::null) {
1127 GetOStream(
Warnings1) <<
"Using existing importer from matrix graph" << std::endl;
1128 importer = realA->getCrsGraph()->getImporter();
1130 GetOStream(
Warnings0) <<
"Constructing new importer instance" << std::endl;
1131 importer = ImportFactory::Build(uniqueMap, nonUniqueMap);
1134 ghostedCoords = Xpetra::MultiVectorFactory<real_type, LO, GO, NO>::Build(nonUniqueMap, Coords->getNumVectors());
1137 ghostedCoords->doImport(*Coords, *importer, Xpetra::INSERT);
1141 RCP<Vector> localLaplDiag = VectorFactory::Build(uniqueMap);
1142 Array<LO> indicesExtra;
1143 Teuchos::Array<Teuchos::ArrayRCP<const real_type>> coordData;
1144 if (threshold != STS::zero()) {
1145 const size_t numVectors = ghostedCoords->getNumVectors();
1146 coordData.reserve(numVectors);
1147 for (
size_t j = 0; j < numVectors; j++) {
1148 Teuchos::ArrayRCP<const real_type> tmpData = ghostedCoords->getData(j);
1149 coordData.push_back(tmpData);
1154 ArrayRCP<SC> localLaplDiagData = localLaplDiag->getDataNonConst(0);
1155 for (LO row = 0; row < numRows; row++) {
1156 ArrayView<const LO> indices;
1159 ArrayView<const SC> vals;
1160 A->getLocalRowView(row, indices, vals);
1164 indicesExtra.resize(0);
1165 MergeRows(*A, row, indicesExtra, colTranslation);
1166 indices = indicesExtra;
1169 LO nnz = indices.size();
1170 bool haveAddedToDiag =
false;
1171 for (LO colID = 0; colID < nnz; colID++) {
1172 const LO col = indices[colID];
1175 if (use_dlap_weights == SINGLE_WEIGHTS) {
1180 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1181 int block_id = row % interleaved_blocksize;
1182 int block_start = block_id * interleaved_blocksize;
1188 haveAddedToDiag =
true;
1193 if (!haveAddedToDiag)
1194 localLaplDiagData[row] = STS::squareroot(STS::rmax());
1199 ghostedLaplDiag = VectorFactory::Build(nonUniqueMap);
1200 ghostedLaplDiag->doImport(*localLaplDiag, *importer, Xpetra::INSERT);
1201 ghostedLaplDiagData = ghostedLaplDiag->getDataNonConst(0);
1205 GetOStream(
Runtime0) <<
"Skipping distance laplacian construction due to 0 threshold" << std::endl;
1211 typename LWGraph::row_type::non_const_type
rows(
"rows", numRows + 1);
1212 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
1214#ifdef HAVE_MUELU_DEBUG
1216 for (LO i = 0; i < (LO)columns.size(); i++) columns[i] = -666;
1220 ArrayRCP<LO> rows_stop;
1221 bool use_stop_array = threshold != STS::zero() && distanceLaplacianAlgo ==
scaled_cut_symmetric;
1224 rows_stop.resize(numRows);
1227 Kokkos::deep_copy(amalgBoundaryNodes,
false);
1232 Array<LO> indicesExtra;
1235 Teuchos::Array<Teuchos::ArrayRCP<const real_type>> coordData;
1236 if (threshold != STS::zero()) {
1237 const size_t numVectors = ghostedCoords->getNumVectors();
1238 coordData.reserve(numVectors);
1239 for (
size_t j = 0; j < numVectors; j++) {
1240 Teuchos::ArrayRCP<const real_type> tmpData = ghostedCoords->getData(j);
1241 coordData.push_back(tmpData);
1245 ArrayView<const SC> vals;
1246 for (LO row = 0; row < numRows; row++) {
1247 ArrayView<const LO> indices;
1248 indicesExtra.resize(0);
1249 bool isBoundary =
false;
1253 A->getLocalRowView(row, indices, vals);
1254 isBoundary = pointBoundaryNodes[row];
1258 for (LO j = 0; j < blkSize; j++) {
1259 if (!pointBoundaryNodes[row * blkSize + j]) {
1267 MergeRows(*A, row, indicesExtra, colTranslation);
1269 indicesExtra.push_back(row);
1270 indices = indicesExtra;
1272 numTotal += indices.size();
1274 LO nnz = indices.size(), rownnz = 0;
1276 if (use_stop_array) {
1278 realnnz =
rows(row);
1281 if (threshold != STS::zero()) {
1285 for (LO colID = 0; colID < nnz; colID++) {
1286 LO col = indices[colID];
1289 columns(realnnz++) = col;
1295 if (isBoundary)
continue;
1298 if (use_dlap_weights == SINGLE_WEIGHTS) {
1300 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1301 int block_id = row % interleaved_blocksize;
1302 int block_start = block_id * interleaved_blocksize;
1307 real_type aiiajj = STS::magnitude(realThreshold * realThreshold * ghostedLaplDiagData[row] * ghostedLaplDiagData[col]);
1308 real_type aij = STS::magnitude(laplVal * laplVal);
1311 columns(realnnz++) = col;
1320 std::vector<DropTol> drop_vec;
1321 drop_vec.reserve(nnz);
1322 const real_type zero = Teuchos::ScalarTraits<real_type>::zero();
1323 const real_type one = Teuchos::ScalarTraits<real_type>::one();
1326 for (LO colID = 0; colID < nnz; colID++) {
1327 LO col = indices[colID];
1330 drop_vec.emplace_back(zero, one, colID,
false);
1334 if (isBoundary)
continue;
1337 if (use_dlap_weights == SINGLE_WEIGHTS) {
1339 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1340 int block_id = row % interleaved_blocksize;
1341 int block_start = block_id * interleaved_blocksize;
1347 real_type aiiajj = STS::magnitude(ghostedLaplDiagData[row] * ghostedLaplDiagData[col]);
1348 real_type aij = STS::magnitude(laplVal * laplVal);
1350 drop_vec.emplace_back(aij, aiiajj, colID,
false);
1353 const size_t n = drop_vec.size();
1356 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1357 return a.val > b.val;
1361 for (
size_t i = 1; i < n; ++i) {
1363 auto const& x = drop_vec[i - 1];
1364 auto const& y = drop_vec[i];
1367 if (realThreshold * realThreshold * a > b) {
1369#ifdef HAVE_MUELU_DEBUG
1370 if (distanceLaplacianCutVerbose) {
1371 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
1376 drop_vec[i].drop = drop;
1379 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1380 return a.val / a.diag > b.val / b.diag;
1384 for (
size_t i = 1; i < n; ++i) {
1386 auto const& x = drop_vec[i - 1];
1387 auto const& y = drop_vec[i];
1388 auto a = x.val / x.diag;
1389 auto b = y.val / y.diag;
1390 if (realThreshold * realThreshold * a > b) {
1392#ifdef HAVE_MUELU_DEBUG
1393 if (distanceLaplacianCutVerbose) {
1394 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
1399 drop_vec[i].drop = drop;
1403 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1404 return a.col < b.col;
1407 for (LO idxID = 0; idxID < (LO)drop_vec.size(); idxID++) {
1408 LO col = indices[drop_vec[idxID].col];
1412 columns(realnnz++) = col;
1418 if (!drop_vec[idxID].drop) {
1419 columns(realnnz++) = col;
1430 for (LO colID = 0; colID < nnz; colID++) {
1431 LO col = indices[colID];
1432 columns(realnnz++) = col;
1444 amalgBoundaryNodes[row] =
true;
1448 rows_stop[row] = rownnz +
rows[row];
1450 rows[row + 1] = realnnz;
1455 if (use_stop_array) {
1458 for (LO row = 0; row < numRows; row++) {
1459 for (LO colidx =
rows[row]; colidx < rows_stop[row]; colidx++) {
1460 LO col = columns[colidx];
1461 if (col >= numRows)
continue;
1464 for (LO t_col =
rows(col); !found && t_col < rows_stop[col]; t_col++) {
1465 if (columns[t_col] == row)
1470 if (!found && !pointBoundaryNodes[col] && Teuchos::as<typename LWGraph::row_type::value_type>(rows_stop[col]) <
rows[col + 1]) {
1471 LO new_idx = rows_stop[col];
1473 columns[new_idx] = row;
1481 LO current_start = 0;
1482 for (LO row = 0; row < numRows; row++) {
1483 LO old_start = current_start;
1484 for (LO col =
rows(row); col < rows_stop[row]; col++) {
1485 if (current_start != col) {
1486 columns(current_start) = columns(col);
1490 rows[row] = old_start;
1492 rows(numRows) = realnnz = current_start;
1498 graph = rcp(
new LWGraph(
rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1499 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1503 GO numLocalBoundaryNodes = 0;
1504 GO numGlobalBoundaryNodes = 0;
1506 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1507 if (amalgBoundaryNodes(i))
1508 numLocalBoundaryNodes++;
1510 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1511 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1512 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" agglomerated Dirichlet nodes"
1513 <<
" using threshold " << dirichletThreshold << std::endl;
1516 Set(currentLevel,
"Graph", graph);
1517 Set(currentLevel,
"DofsPerNode", blkSize);
1522 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1523 GO numGlobalTotal, numGlobalDropped;
1526 GetOStream(
Statistics1) <<
"Number of dropped entries in " << graphType <<
" matrix graph: " << numGlobalDropped <<
"/" << numGlobalTotal;
1527 if (numGlobalTotal != 0)
1528 GetOStream(
Statistics1) <<
" (" << 100 * Teuchos::as<double>(numGlobalDropped) / Teuchos::as<double>(numGlobalTotal) <<
"%)";
1535 SC threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
1537 GetOStream(
Runtime0) <<
"algorithm = \""
1539 <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
1540 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
1542 RCP<const Map> rowMap = A->getRowMap();
1543 RCP<const Map> colMap = A->getColMap();
1546 GO indexBase = rowMap->getIndexBase();
1550 if (A->IsView(
"stridedMaps") &&
1551 Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap(
"stridedMaps")) != Teuchos::null) {
1552 Xpetra::viewLabel_t oldView = A->SwitchToView(
"stridedMaps");
1553 RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap());
1554 TEUCHOS_TEST_FOR_EXCEPTION(strMap == Teuchos::null,
Exceptions::BadCast,
"MueLu::CoalesceFactory::Build: cast to strided row map failed.");
1555 blockdim = strMap->getFixedBlockSize();
1556 offset = strMap->getOffset();
1557 oldView = A->SwitchToView(oldView);
1558 GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build():"
1559 <<
" found blockdim=" << blockdim <<
" from strided maps. offset=" << offset << std::endl;
1561 GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build(): no striding information available. Use blockdim=1 with offset=0" << std::endl;
1565 RCP<const Map> nodeMap = amalInfo->getNodeRowMap();
1566 GetOStream(
Statistics1) <<
"CoalesceDropFactory: nodeMap " << nodeMap->getLocalNumElements() <<
"/" << nodeMap->getGlobalNumElements() <<
" elements" << std::endl;
1569 RCP<CrsGraph> crsGraph = CrsGraphFactory::Build(nodeMap, A->getLocalMaxNumRowEntries() * blockdim);
1571 LO numRows = A->getRowMap()->getLocalNumElements();
1572 LO numNodes = nodeMap->getLocalNumElements();
1574 Kokkos::deep_copy(amalgBoundaryNodes,
false);
1575 const ArrayRCP<int> numberDirichletRowsPerNode(numNodes, 0);
1576 bool bIsDiagonalEntry =
false;
1581 for (LO row = 0; row < numRows; row++) {
1583 GO grid = rowMap->getGlobalElement(row);
1586 bIsDiagonalEntry =
false;
1591 size_t nnz = A->getNumEntriesInLocalRow(row);
1592 Teuchos::ArrayView<const LO> indices;
1593 Teuchos::ArrayView<const SC> vals;
1594 A->getLocalRowView(row, indices, vals);
1596 RCP<std::vector<GO>> cnodeIds = Teuchos::rcp(
new std::vector<GO>);
1598 for (LO col = 0; col < Teuchos::as<LO>(nnz); col++) {
1599 GO gcid = colMap->getGlobalElement(indices[col]);
1601 if (vals[col] != STS::zero()) {
1603 cnodeIds->push_back(cnodeId);
1605 if (grid == gcid) bIsDiagonalEntry =
true;
1609 if (realnnz == 1 && bIsDiagonalEntry ==
true) {
1610 LO lNodeId = nodeMap->getLocalElement(nodeId);
1611 numberDirichletRowsPerNode[lNodeId] += 1;
1612 if (numberDirichletRowsPerNode[lNodeId] == blockdim)
1613 amalgBoundaryNodes[lNodeId] =
true;
1616 Teuchos::ArrayRCP<GO> arr_cnodeIds = Teuchos::arcp(cnodeIds);
1618 if (arr_cnodeIds.size() > 0)
1619 crsGraph->insertGlobalIndices(nodeId, arr_cnodeIds());
1622 crsGraph->fillComplete(nodeMap, nodeMap);
1625 RCP<LWGraph> graph = rcp(
new LWGraph(crsGraph,
"amalgamated graph of A"));
1628 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1631 GO numLocalBoundaryNodes = 0;
1632 GO numGlobalBoundaryNodes = 0;
1633 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1634 if (amalgBoundaryNodes(i))
1635 numLocalBoundaryNodes++;
1636 RCP<const Teuchos::Comm<int>> comm = A->getRowMap()->getComm();
1637 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1638 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1643 Set(currentLevel,
"DofsPerNode", blockdim);
1644 Set(currentLevel,
"Graph", graph);