46 #ifndef MUELU_COALESCEDROPFACTORY_DEF_HPP
47 #define MUELU_COALESCEDROPFACTORY_DEF_HPP
53 #include <Xpetra_MapFactory.hpp>
54 #include <Xpetra_Map.hpp>
56 #include <Xpetra_MultiVectorFactory.hpp>
58 #include <Xpetra_StridedMap.hpp>
66 #include "MueLu_AmalgamationFactory.hpp"
67 #include "MueLu_AmalgamationInfo.hpp"
69 #include "MueLu_LWGraph.hpp"
72 #include "MueLu_LWGraph.hpp"
75 #include "MueLu_PreDropFunctionConstVal.hpp"
76 #include "MueLu_Utilities.hpp"
78 #ifdef HAVE_XPETRA_TPETRA
79 #include "Tpetra_CrsGraphTransposer.hpp"
93 template <
class real_type,
class LO>
102 DropTol(real_type val_, real_type diag_,
LO col_,
bool drop_)
118 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
122 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
130 SET_VALID_ENTRY(
"aggregation: distance laplacian directional weights");
135 validParamList->
getEntry(
"aggregation: drop scheme").
setValidator(
rcp(
new Teuchos::StringValidator(Teuchos::tuple<std::string>(
"signed classical sa",
"classical",
"distance laplacian",
"signed classical",
"block diagonal",
"block diagonal classical",
"block diagonal distance laplacian",
"block diagonal signed classical",
"block diagonal colored signed classical"))));
140 #undef SET_VALID_ENTRY
141 validParamList->
set<
bool>(
"lightweight wrap",
true,
"Experimental option for lightweight graph access");
144 validParamList->
set<
RCP<const FactoryBase>>(
"UnAmalgamationInfo", Teuchos::null,
"Generating factory for UnAmalgamationInfo");
148 return validParamList;
151 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
153 : predrop_(Teuchos::null) {}
155 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
157 Input(currentLevel,
"A");
158 Input(currentLevel,
"UnAmalgamationInfo");
161 if (pL.
get<
bool>(
"lightweight wrap") ==
true) {
162 std::string algo = pL.
get<std::string>(
"aggregation: drop scheme");
163 if (algo ==
"distance laplacian" || algo ==
"block diagonal distance laplacian") {
164 Input(currentLevel,
"Coordinates");
166 if (algo ==
"signed classical sa")
168 else if (algo.find(
"block diagonal") != std::string::npos || algo.find(
"signed classical") != std::string::npos) {
169 Input(currentLevel,
"BlockNumber");
174 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
179 typedef typename STS::magnitudeType real_type;
183 if (predrop_ != Teuchos::null)
184 GetOStream(
Parameters0) << predrop_->description();
186 RCP<Matrix> realA = Get<RCP<Matrix>>(currentLevel,
"A");
189 bool doExperimentalWrap = pL.get<
bool>(
"lightweight wrap");
191 GetOStream(
Parameters0) <<
"lightweight wrap = " << doExperimentalWrap << std::endl;
192 std::string algo = pL.get<std::string>(
"aggregation: drop scheme");
193 const bool aggregationMayCreateDirichlet = pL.get<
bool>(
"aggregation: dropping may create Dirichlet");
198 bool use_block_algorithm =
false;
199 LO interleaved_blocksize = as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize"));
200 bool useSignedClassicalRS =
false;
201 bool useSignedClassicalSA =
false;
202 bool generateColoringGraph =
false;
206 typename STS::magnitudeType rowSumTol = as<typename STS::magnitudeType>(pL.get<
double>(
"aggregation: row sum drop tol"));
211 if (algo ==
"distance laplacian") {
213 Coords = Get<RCP<RealValuedMultiVector>>(currentLevel,
"Coordinates");
215 }
else if (algo ==
"signed classical sa") {
216 useSignedClassicalSA =
true;
219 }
else if (algo ==
"signed classical" || algo ==
"block diagonal colored signed classical" || algo ==
"block diagonal signed classical") {
220 useSignedClassicalRS =
true;
225 if (!importer.is_null()) {
228 ghostedBlockNumber->doImport(*BlockNumber, *importer,
Xpetra::INSERT);
230 ghostedBlockNumber = BlockNumber;
232 g_block_id = ghostedBlockNumber->getData(0);
234 if (algo ==
"block diagonal colored signed classical")
235 generateColoringGraph =
true;
239 }
else if (algo ==
"block diagonal") {
241 BlockDiagonalize(currentLevel, realA,
false);
243 }
else if (algo ==
"block diagonal classical" || algo ==
"block diagonal distance laplacian") {
245 use_block_algorithm =
true;
246 RCP<Matrix> filteredMatrix = BlockDiagonalize(currentLevel, realA,
true);
247 if (algo ==
"block diagonal distance laplacian") {
250 if (OldCoords->getLocalLength() != realA->getLocalNumRows()) {
251 LO dim = (
LO)OldCoords->getNumVectors();
252 Coords = RealValuedMultiVectorFactory::Build(realA->getRowMap(), dim);
253 for (
LO k = 0; k < dim; k++) {
256 for (
LO i = 0; i < (
LO)OldCoords->getLocalLength(); i++) {
257 LO new_base = i * dim;
258 for (
LO j = 0; j < interleaved_blocksize; j++)
259 new_vec[new_base + j] = old_vec[i];
265 algo =
"distance laplacian";
266 }
else if (algo ==
"block diagonal classical") {
278 enum { NO_WEIGHTS = 0,
281 int use_dlap_weights = NO_WEIGHTS;
282 if (algo ==
"distance laplacian") {
283 LO dim = (
LO)Coords->getNumVectors();
285 bool non_unity =
false;
286 for (
LO i = 0; !non_unity && i < (
LO)dlap_weights.
size(); i++) {
287 if (dlap_weights[i] != 1.0) {
292 LO blocksize = use_block_algorithm ? as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize")) : 1;
293 if ((
LO)dlap_weights.
size() == dim)
294 use_dlap_weights = SINGLE_WEIGHTS;
295 else if ((
LO)dlap_weights.
size() == blocksize * dim)
296 use_dlap_weights = BLOCK_WEIGHTS;
299 "length of 'aggregation: distance laplacian directional weights' must equal the coordinate dimension OR the coordinate dimension times the blocksize");
302 GetOStream(
Statistics1) <<
"Using distance laplacian weights: " << dlap_weights << std::endl;
317 if (doExperimentalWrap) {
323 if (pL.get<
bool>(
"aggregation: use ml scaling of drop tol"))
324 threshold = pL.get<
double>(
"aggregation: drop tol") / pow(2.0, currentLevel.GetLevelID());
326 threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
328 std::string distanceLaplacianAlgoStr = pL.get<std::string>(
"aggregation: distance laplacian algo");
329 std::string classicalAlgoStr = pL.get<std::string>(
"aggregation: classical algo");
330 real_type realThreshold = STS::magnitude(threshold);
334 #ifdef HAVE_MUELU_DEBUG
335 int distanceLaplacianCutVerbose = 0;
337 #ifdef DJS_READ_ENV_VARIABLES
338 if (getenv(
"MUELU_DROP_TOLERANCE_MODE")) {
339 distanceLaplacianAlgoStr = std::string(getenv(
"MUELU_DROP_TOLERANCE_MODE"));
342 if (getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD")) {
343 auto tmp = atoi(getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD"));
344 realThreshold = 1e-4 * tmp;
347 #ifdef HAVE_MUELU_DEBUG
348 if (getenv(
"MUELU_DROP_TOLERANCE_VERBOSE")) {
349 distanceLaplacianCutVerbose = atoi(getenv(
"MUELU_DROP_TOLERANCE_VERBOSE"));
355 enum decisionAlgoType { defaultAlgo,
358 scaled_cut_symmetric };
360 decisionAlgoType distanceLaplacianAlgo = defaultAlgo;
361 decisionAlgoType classicalAlgo = defaultAlgo;
362 if (algo ==
"distance laplacian") {
363 if (distanceLaplacianAlgoStr ==
"default")
364 distanceLaplacianAlgo = defaultAlgo;
365 else if (distanceLaplacianAlgoStr ==
"unscaled cut")
366 distanceLaplacianAlgo = unscaled_cut;
367 else if (distanceLaplacianAlgoStr ==
"scaled cut")
368 distanceLaplacianAlgo = scaled_cut;
369 else if (distanceLaplacianAlgoStr ==
"scaled cut symmetric")
370 distanceLaplacianAlgo = scaled_cut_symmetric;
373 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" distance laplacian algorithm = \"" << distanceLaplacianAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
374 }
else if (algo ==
"classical") {
375 if (classicalAlgoStr ==
"default")
376 classicalAlgo = defaultAlgo;
377 else if (classicalAlgoStr ==
"unscaled cut")
378 classicalAlgo = unscaled_cut;
379 else if (classicalAlgoStr ==
"scaled cut")
380 classicalAlgo = scaled_cut;
383 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" classical algorithm = \"" << classicalAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
386 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
387 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
389 const typename STS::magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.get<
double>(
"aggregation: Dirichlet threshold")));
395 GO numDropped = 0, numTotal = 0;
396 std::string graphType =
"unamalgamated";
415 const LO BlockSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
418 if (algo ==
"classical") {
419 if (predrop_ == null) {
424 if (predrop_ != null) {
427 "MueLu::CoalesceFactory::Build: cast to PreDropFunctionConstVal failed.");
430 if (newt != threshold) {
431 GetOStream(
Warnings0) <<
"switching threshold parameter from " << threshold <<
" (list) to " << newt <<
" (user function" << std::endl;
438 if (BlockSize == 1 && threshold == STS::zero() && !useSignedClassicalRS && !useSignedClassicalSA && A->hasCrsGraph()) {
447 numTotal = A->getLocalNumEntries();
450 GO numLocalBoundaryNodes = 0;
451 GO numGlobalBoundaryNodes = 0;
452 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
453 if (boundaryNodes[i])
454 numLocalBoundaryNodes++;
456 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
457 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
460 Set(currentLevel,
"DofsPerNode", 1);
461 Set(currentLevel,
"Graph", graph);
463 }
else if ((BlockSize == 1 && threshold != STS::zero()) ||
464 (BlockSize == 1 && threshold == STS::zero() && !A->hasCrsGraph()) ||
465 (BlockSize == 1 && useSignedClassicalRS) ||
466 (BlockSize == 1 && useSignedClassicalSA)) {
472 typename LWGraph::row_type::non_const_type
rows(
"rows", A->getLocalNumRows() + 1);
473 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
475 using MT =
typename STS::magnitudeType;
480 if (useSignedClassicalRS) {
481 if (ghostedBlockNumber.
is_null()) {
484 GetOStream(
Statistics1) <<
"Calculated max point off-diagonal" << std::endl;
488 GetOStream(
Statistics1) <<
"Calculating max block off-diagonal" << std::endl;
492 ghostedDiagVals = ghostedDiag->getData(0);
495 if (rowSumTol > 0.) {
496 if (ghostedBlockNumber.
is_null()) {
498 GetOStream(
Statistics1) <<
"Applying point row sum criterion." << std::endl;
502 GetOStream(
Statistics1) <<
"Applying block row sum criterion." << std::endl;
509 for (
LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
510 size_t nnz = A->getNumEntriesInLocalRow(row);
511 bool rowIsDirichlet = boundaryNodes[row];
514 A->getLocalRowView(row, indices, vals);
516 if (classicalAlgo == defaultAlgo) {
523 if (useSignedClassicalRS) {
525 for (
LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
526 LO col = indices[colID];
527 MT max_neg_aik = realThreshold * STS::real(negMaxOffDiagonal[row]);
528 MT neg_aij = -STS::real(vals[colID]);
533 if ((!rowIsDirichlet && (g_block_id.
is_null() || g_block_id[row] == g_block_id[col]) && neg_aij > max_neg_aik) || row == col) {
534 columns[realnnz++] = col;
539 rows(row + 1) = realnnz;
540 }
else if (useSignedClassicalSA) {
542 for (
LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
543 LO col = indices[colID];
545 bool is_nonpositive = STS::real(vals[colID]) <= 0;
546 MT aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
547 MT aij = is_nonpositive ? STS::magnitude(vals[colID] * vals[colID]) : (-STS::magnitude(vals[colID] * vals[colID]));
553 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
554 columns(realnnz++) = col;
559 rows[row + 1] = realnnz;
562 for (
LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
563 LO col = indices[colID];
564 MT aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
565 MT aij = STS::magnitude(vals[colID] * vals[colID]);
567 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
568 columns(realnnz++) = col;
573 rows(row + 1) = realnnz;
579 std::vector<DropTol> drop_vec;
580 drop_vec.reserve(nnz);
587 for (
LO colID = 0; colID < (
LO)nnz; colID++) {
588 LO col = indices[colID];
590 drop_vec.emplace_back(zero, one, colID,
false);
595 if (boundaryNodes[colID])
continue;
596 typename STS::magnitudeType aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[col] * ghostedDiagVals[row]);
597 typename STS::magnitudeType aij = STS::magnitude(vals[colID] * vals[colID]);
598 drop_vec.emplace_back(aij, aiiajj, colID,
false);
601 const size_t n = drop_vec.size();
603 if (classicalAlgo == unscaled_cut) {
604 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
605 return a.val > b.val;
609 for (
size_t i = 1; i < n; ++i) {
611 auto const& x = drop_vec[i - 1];
612 auto const& y = drop_vec[i];
615 if (a > realThreshold * b) {
617 #ifdef HAVE_MUELU_DEBUG
618 if (distanceLaplacianCutVerbose) {
619 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
624 drop_vec[i].drop = drop;
626 }
else if (classicalAlgo == scaled_cut) {
627 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
628 return a.val / a.diag > b.val / b.diag;
633 for (
size_t i = 1; i < n; ++i) {
635 auto const& x = drop_vec[i - 1];
636 auto const& y = drop_vec[i];
637 auto a = x.val / x.diag;
638 auto b = y.val / y.diag;
639 if (a > realThreshold * b) {
642 #ifdef HAVE_MUELU_DEBUG
643 if (distanceLaplacianCutVerbose) {
644 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
650 drop_vec[i].drop = drop;
654 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
655 return a.col < b.col;
658 for (
LO idxID = 0; idxID < (
LO)drop_vec.size(); idxID++) {
659 LO col = indices[drop_vec[idxID].col];
662 columns[realnnz++] = col;
667 if (!drop_vec[idxID].drop) {
668 columns[realnnz++] = col;
675 rows[row + 1] = realnnz;
679 numTotal = A->getLocalNumEntries();
681 if (aggregationMayCreateDirichlet) {
683 for (
LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
685 boundaryNodes[row] =
true;
689 RCP<LWGraph> graph =
rcp(
new LWGraph(
rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), A->getRowMap(), A->getColMap(),
"thresholded graph of A"));
692 GO numLocalBoundaryNodes = 0;
693 GO numGlobalBoundaryNodes = 0;
694 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
695 if (boundaryNodes(i))
696 numLocalBoundaryNodes++;
698 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
699 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
701 Set(currentLevel,
"Graph", graph);
702 Set(currentLevel,
"DofsPerNode", 1);
705 if (generateColoringGraph) {
708 BlockDiagonalizeGraph(graph, ghostedBlockNumber, colorGraph, importer);
709 Set(currentLevel,
"Coloring Graph", colorGraph);
729 }
else if (BlockSize > 1 && threshold == STS::zero()) {
734 graphType =
"amalgamated";
742 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
743 Array<LO> colTranslation = *(amalInfo->getColTranslation());
746 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
749 typename LWGraph::row_type::non_const_type
rows(
"rows", numRows + 1);
750 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
753 Kokkos::deep_copy(amalgBoundaryNodes,
false);
765 LO blkSize = A->GetFixedBlockSize();
767 LO blkPartSize = A->GetFixedBlockSize();
768 if (A->IsView(
"stridedMaps") ==
true) {
772 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
773 blkId = strMap->getStridedBlockId();
775 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
782 for (
LO row = 0; row < numRows; row++) {
792 bool isBoundary =
false;
793 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
794 for (
LO j = 0; j < blkPartSize; j++) {
795 if (pointBoundaryNodes[row * blkPartSize + j]) {
802 for (
LO j = 0; j < blkPartSize; j++) {
803 if (!pointBoundaryNodes[row * blkPartSize + j]) {
813 MergeRows(*A, row, indicesExtra, colTranslation);
816 indices = indicesExtra;
817 numTotal += indices.
size();
821 LO nnz = indices.
size(), rownnz = 0;
822 for (
LO colID = 0; colID < nnz; colID++) {
823 LO col = indices[colID];
824 columns(realnnz++) = col;
835 amalgBoundaryNodes[row] =
true;
837 rows(row + 1) = realnnz;
840 RCP<LWGraph> graph =
rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
844 GO numLocalBoundaryNodes = 0;
845 GO numGlobalBoundaryNodes = 0;
847 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
848 if (amalgBoundaryNodes(i))
849 numLocalBoundaryNodes++;
852 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
853 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes
854 <<
" agglomerated Dirichlet nodes" << std::endl;
857 Set(currentLevel,
"Graph", graph);
858 Set(currentLevel,
"DofsPerNode", blkSize);
860 }
else if (BlockSize > 1 && threshold != STS::zero()) {
864 graphType =
"amalgamated";
872 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
873 Array<LO> colTranslation = *(amalInfo->getColTranslation());
876 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
879 typename LWGraph::row_type::non_const_type
rows(
"rows", numRows + 1);
880 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
883 Kokkos::deep_copy(amalgBoundaryNodes,
false);
894 LO blkSize = A->GetFixedBlockSize();
896 LO blkPartSize = A->GetFixedBlockSize();
897 if (A->IsView(
"stridedMaps") ==
true) {
901 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
902 blkId = strMap->getStridedBlockId();
904 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
915 for (
LO row = 0; row < numRows; row++) {
925 bool isBoundary =
false;
926 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
927 for (
LO j = 0; j < blkPartSize; j++) {
928 if (pointBoundaryNodes[row * blkPartSize + j]) {
935 for (
LO j = 0; j < blkPartSize; j++) {
936 if (!pointBoundaryNodes[row * blkPartSize + j]) {
946 MergeRowsWithDropping(*A, row, ghostedDiagVals, threshold, indicesExtra, colTranslation);
949 indices = indicesExtra;
950 numTotal += indices.
size();
954 LO nnz = indices.
size(), rownnz = 0;
955 for (
LO colID = 0; colID < nnz; colID++) {
956 LO col = indices[colID];
957 columns[realnnz++] = col;
968 amalgBoundaryNodes[row] =
true;
970 rows[row + 1] = realnnz;
974 RCP<LWGraph> graph =
rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
978 GO numLocalBoundaryNodes = 0;
979 GO numGlobalBoundaryNodes = 0;
981 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
982 if (amalgBoundaryNodes(i))
983 numLocalBoundaryNodes++;
986 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
987 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes
988 <<
" agglomerated Dirichlet nodes" << std::endl;
991 Set(currentLevel,
"Graph", graph);
992 Set(currentLevel,
"DofsPerNode", blkSize);
995 }
else if (algo ==
"distance laplacian") {
996 LO blkSize = A->GetFixedBlockSize();
997 GO indexBase = A->getRowMap()->getIndexBase();
1012 if ((blkSize == 1) && (threshold == STS::zero())) {
1016 graphType =
"unamalgamated";
1017 numTotal = A->getLocalNumEntries();
1020 GO numLocalBoundaryNodes = 0;
1021 GO numGlobalBoundaryNodes = 0;
1022 for (
size_t i = 0; i < pointBoundaryNodes.size(); ++i)
1023 if (pointBoundaryNodes(i))
1024 numLocalBoundaryNodes++;
1026 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1027 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1030 Set(currentLevel,
"DofsPerNode", blkSize);
1031 Set(currentLevel,
"Graph", graph);
1047 "Coordinate vector length (" << Coords->getLocalLength() <<
") is incompatible with number of rows in A (" << A->getRowMap()->getLocalNumElements() <<
") by modulo block size (" << blkSize <<
").");
1053 uniqueMap = A->getRowMap();
1054 nonUniqueMap = A->getColMap();
1055 graphType =
"unamalgamated";
1058 uniqueMap = Coords->getMap();
1060 "Different index bases for matrix and coordinates");
1064 graphType =
"amalgamated";
1066 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
1071 if (threshold != STS::zero()) {
1076 if (blkSize == 1 && realA->getCrsGraph()->getImporter() != Teuchos::null) {
1077 GetOStream(
Warnings1) <<
"Using existing importer from matrix graph" << std::endl;
1078 importer = realA->getCrsGraph()->getImporter();
1080 GetOStream(
Warnings0) <<
"Constructing new importer instance" << std::endl;
1081 importer = ImportFactory::Build(uniqueMap, nonUniqueMap);
1091 RCP<Vector> localLaplDiag = VectorFactory::Build(uniqueMap);
1094 if (threshold != STS::zero()) {
1095 const size_t numVectors = ghostedCoords->getNumVectors();
1096 coordData.
reserve(numVectors);
1097 for (
size_t j = 0; j < numVectors; j++) {
1104 ArrayRCP<SC> localLaplDiagData = localLaplDiag->getDataNonConst(0);
1105 for (
LO row = 0; row < numRows; row++) {
1110 A->getLocalRowView(row, indices, vals);
1115 MergeRows(*A, row, indicesExtra, colTranslation);
1116 indices = indicesExtra;
1120 bool haveAddedToDiag =
false;
1121 for (
LO colID = 0; colID < nnz; colID++) {
1122 const LO col = indices[colID];
1125 if (use_dlap_weights == SINGLE_WEIGHTS) {
1130 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1131 int block_id = row % interleaved_blocksize;
1132 int block_start = block_id * interleaved_blocksize;
1138 haveAddedToDiag =
true;
1143 if (!haveAddedToDiag)
1144 localLaplDiagData[row] = STS::rmax();
1149 ghostedLaplDiag = VectorFactory::Build(nonUniqueMap);
1150 ghostedLaplDiag->doImport(*localLaplDiag, *importer,
Xpetra::INSERT);
1151 ghostedLaplDiagData = ghostedLaplDiag->getDataNonConst(0);
1155 GetOStream(
Runtime0) <<
"Skipping distance laplacian construction due to 0 threshold" << std::endl;
1161 typename LWGraph::row_type::non_const_type
rows(
"rows", numRows + 1);
1162 typename LWGraph::entries_type::non_const_type columns(
"columns", A->getLocalNumEntries());
1164 #ifdef HAVE_MUELU_DEBUG
1166 for (
LO i = 0; i < (
LO)columns.size(); i++) columns[i] = -666;
1171 bool use_stop_array = threshold != STS::zero() && distanceLaplacianAlgo == scaled_cut_symmetric;
1174 rows_stop.
resize(numRows);
1177 Kokkos::deep_copy(amalgBoundaryNodes,
false);
1186 if (threshold != STS::zero()) {
1187 const size_t numVectors = ghostedCoords->getNumVectors();
1188 coordData.
reserve(numVectors);
1189 for (
size_t j = 0; j < numVectors; j++) {
1196 for (
LO row = 0; row < numRows; row++) {
1199 bool isBoundary =
false;
1203 A->getLocalRowView(row, indices, vals);
1204 isBoundary = pointBoundaryNodes[row];
1207 for (
LO j = 0; j < blkSize; j++) {
1208 if (!pointBoundaryNodes[row * blkSize + j]) {
1216 MergeRows(*A, row, indicesExtra, colTranslation);
1219 indices = indicesExtra;
1221 numTotal += indices.
size();
1223 LO nnz = indices.
size(), rownnz = 0;
1225 if (use_stop_array) {
1227 realnnz =
rows(row);
1230 if (threshold != STS::zero()) {
1232 if (distanceLaplacianAlgo == defaultAlgo) {
1234 for (
LO colID = 0; colID < nnz; colID++) {
1235 LO col = indices[colID];
1238 columns(realnnz++) = col;
1244 if (isBoundary)
continue;
1247 if (use_dlap_weights == SINGLE_WEIGHTS) {
1249 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1250 int block_id = row % interleaved_blocksize;
1251 int block_start = block_id * interleaved_blocksize;
1256 real_type aiiajj = STS::magnitude(realThreshold * realThreshold * ghostedLaplDiagData[row] * ghostedLaplDiagData[col]);
1257 real_type aij = STS::magnitude(laplVal * laplVal);
1260 columns(realnnz++) = col;
1269 std::vector<DropTol> drop_vec;
1270 drop_vec.reserve(nnz);
1275 for (
LO colID = 0; colID < nnz; colID++) {
1276 LO col = indices[colID];
1279 drop_vec.emplace_back(zero, one, colID,
false);
1283 if (isBoundary)
continue;
1286 if (use_dlap_weights == SINGLE_WEIGHTS) {
1288 }
else if (use_dlap_weights == BLOCK_WEIGHTS) {
1289 int block_id = row % interleaved_blocksize;
1290 int block_start = block_id * interleaved_blocksize;
1296 real_type aiiajj = STS::magnitude(ghostedLaplDiagData[row] * ghostedLaplDiagData[col]);
1297 real_type aij = STS::magnitude(laplVal * laplVal);
1299 drop_vec.emplace_back(aij, aiiajj, colID,
false);
1302 const size_t n = drop_vec.size();
1304 if (distanceLaplacianAlgo == unscaled_cut) {
1305 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1306 return a.val > b.val;
1310 for (
size_t i = 1; i < n; ++i) {
1312 auto const& x = drop_vec[i - 1];
1313 auto const& y = drop_vec[i];
1316 if (a > realThreshold * b) {
1318 #ifdef HAVE_MUELU_DEBUG
1319 if (distanceLaplacianCutVerbose) {
1320 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
1325 drop_vec[i].drop = drop;
1327 }
else if (distanceLaplacianAlgo == scaled_cut || distanceLaplacianAlgo == scaled_cut_symmetric) {
1328 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1329 return a.val / a.diag > b.val / b.diag;
1333 for (
size_t i = 1; i < n; ++i) {
1335 auto const& x = drop_vec[i - 1];
1336 auto const& y = drop_vec[i];
1337 auto a = x.val / x.diag;
1338 auto b = y.val / y.diag;
1339 if (a > realThreshold * b) {
1341 #ifdef HAVE_MUELU_DEBUG
1342 if (distanceLaplacianCutVerbose) {
1343 std::cout <<
"DJS: KEEP, N, ROW: " << i + 1 <<
", " << n <<
", " << row << std::endl;
1348 drop_vec[i].drop = drop;
1352 std::sort(drop_vec.begin(), drop_vec.end(), [](DropTol
const& a, DropTol
const& b) {
1353 return a.col < b.col;
1356 for (
LO idxID = 0; idxID < (
LO)drop_vec.size(); idxID++) {
1357 LO col = indices[drop_vec[idxID].col];
1361 columns(realnnz++) = col;
1367 if (!drop_vec[idxID].drop) {
1368 columns(realnnz++) = col;
1379 for (
LO colID = 0; colID < nnz; colID++) {
1380 LO col = indices[colID];
1381 columns(realnnz++) = col;
1393 amalgBoundaryNodes[row] =
true;
1397 rows_stop[row] = rownnz + rows[row];
1399 rows[row + 1] = realnnz;
1404 if (use_stop_array) {
1407 for (
LO row = 0; row < numRows; row++) {
1408 for (
LO colidx = rows[row]; colidx < rows_stop[row]; colidx++) {
1409 LO col = columns[colidx];
1410 if (col >= numRows)
continue;
1413 for (
LO t_col =
rows(col); !found && t_col < rows_stop[col]; t_col++) {
1414 if (columns[t_col] == row)
1419 if (!found && !pointBoundaryNodes[col] && Teuchos::as<typename LWGraph::row_type::value_type>(rows_stop[col]) < rows[col + 1]) {
1420 LO new_idx = rows_stop[col];
1422 columns[new_idx] = row;
1430 LO current_start = 0;
1431 for (
LO row = 0; row < numRows; row++) {
1432 LO old_start = current_start;
1433 for (
LO col =
rows(row); col < rows_stop[row]; col++) {
1434 if (current_start != col) {
1435 columns(current_start) = columns(col);
1439 rows[row] = old_start;
1441 rows(numRows) = realnnz = current_start;
1447 graph =
rcp(
new LWGraph(rows, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1452 GO numLocalBoundaryNodes = 0;
1453 GO numGlobalBoundaryNodes = 0;
1455 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1456 if (amalgBoundaryNodes(i))
1457 numLocalBoundaryNodes++;
1460 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1461 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" agglomerated Dirichlet nodes"
1462 <<
" using threshold " << dirichletThreshold << std::endl;
1465 Set(currentLevel,
"Graph", graph);
1466 Set(currentLevel,
"DofsPerNode", blkSize);
1470 if ((GetVerbLevel() &
Statistics1) && !(A->GetFixedBlockSize() > 1 && threshold != STS::zero())) {
1472 GO numGlobalTotal, numGlobalDropped;
1475 GetOStream(
Statistics1) <<
"Number of dropped entries in " << graphType <<
" matrix graph: " << numGlobalDropped <<
"/" << numGlobalTotal;
1476 if (numGlobalTotal != 0)
1477 GetOStream(
Statistics1) <<
" (" << 100 * Teuchos::as<double>(numGlobalDropped) / Teuchos::as<double>(numGlobalTotal) <<
"%)";
1484 SC threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
1486 GetOStream(
Runtime0) <<
"algorithm = \""
1488 <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
1489 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
1495 GO indexBase = rowMap->getIndexBase();
1499 if (A->IsView(
"stridedMaps") &&
1500 Teuchos::rcp_dynamic_cast<
const StridedMap>(A->getRowMap(
"stridedMaps")) != Teuchos::null) {
1504 blockdim = strMap->getFixedBlockSize();
1505 offset = strMap->getOffset();
1506 oldView = A->SwitchToView(oldView);
1507 GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build():"
1508 <<
" found blockdim=" << blockdim <<
" from strided maps. offset=" << offset << std::endl;
1510 GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build(): no striding information available. Use blockdim=1 with offset=0" << std::endl;
1515 GetOStream(
Statistics1) <<
"CoalesceDropFactory: nodeMap " << nodeMap->getLocalNumElements() <<
"/" << nodeMap->getGlobalNumElements() <<
" elements" << std::endl;
1518 RCP<CrsGraph> crsGraph = CrsGraphFactory::Build(nodeMap, A->getLocalMaxNumRowEntries() * blockdim);
1520 LO numRows = A->getRowMap()->getLocalNumElements();
1521 LO numNodes = nodeMap->getLocalNumElements();
1523 Kokkos::deep_copy(amalgBoundaryNodes,
false);
1524 const ArrayRCP<int> numberDirichletRowsPerNode(numNodes, 0);
1525 bool bIsDiagonalEntry =
false;
1530 for (
LO row = 0; row < numRows; row++) {
1532 GO grid = rowMap->getGlobalElement(row);
1535 bIsDiagonalEntry =
false;
1540 size_t nnz = A->getNumEntriesInLocalRow(row);
1543 A->getLocalRowView(row, indices, vals);
1547 for (
LO col = 0; col < Teuchos::as<LO>(nnz); col++) {
1548 GO gcid = colMap->getGlobalElement(indices[col]);
1550 if (vals[col] != STS::zero()) {
1552 cnodeIds->push_back(cnodeId);
1554 if (grid == gcid) bIsDiagonalEntry =
true;
1558 if (realnnz == 1 && bIsDiagonalEntry ==
true) {
1559 LO lNodeId = nodeMap->getLocalElement(nodeId);
1560 numberDirichletRowsPerNode[lNodeId] += 1;
1561 if (numberDirichletRowsPerNode[lNodeId] == blockdim)
1562 amalgBoundaryNodes[lNodeId] =
true;
1567 if (arr_cnodeIds.
size() > 0)
1568 crsGraph->insertGlobalIndices(nodeId, arr_cnodeIds());
1571 crsGraph->fillComplete(nodeMap, nodeMap);
1580 GO numLocalBoundaryNodes = 0;
1581 GO numGlobalBoundaryNodes = 0;
1582 for (
size_t i = 0; i < amalgBoundaryNodes.size(); ++i)
1583 if (amalgBoundaryNodes(i))
1584 numLocalBoundaryNodes++;
1586 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1587 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1592 Set(currentLevel,
"DofsPerNode", blockdim);
1593 Set(currentLevel,
"Graph", graph);
1599 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1604 LO blkSize = A.GetFixedBlockSize();
1605 if (A.IsView(
"stridedMaps") ==
true) {
1609 if (strMap->getStridedBlockId() > -1)
1610 blkSize = Teuchos::as<LO>(strMap->getStridingData()[strMap->getStridedBlockId()]);
1614 size_t nnz = 0, pos = 0;
1615 for (
LO j = 0; j < blkSize; j++)
1616 nnz += A.getNumEntriesInLocalRow(row * blkSize + j);
1628 for (
LO j = 0; j < blkSize; j++) {
1629 A.getLocalRowView(row * blkSize + j, inds, vals);
1630 size_type numIndices = inds.
size();
1632 if (numIndices == 0)
1636 cols[pos++] = translation[inds[0]];
1637 for (size_type k = 1; k < numIndices; k++) {
1638 LO nodeID = translation[inds[k]];
1642 if (nodeID != cols[pos - 1])
1643 cols[pos++] = nodeID;
1650 std::sort(cols.
begin(), cols.
end());
1652 for (
size_t j = 1; j < nnz; j++)
1653 if (cols[j] != cols[pos])
1654 cols[++pos] = cols[j];
1658 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1664 LO blkSize = A.GetFixedBlockSize();
1665 if (A.IsView(
"stridedMaps") ==
true) {
1669 if (strMap->getStridedBlockId() > -1)
1670 blkSize = Teuchos::as<LO>(strMap->getStridingData()[strMap->getStridedBlockId()]);
1674 size_t nnz = 0, pos = 0;
1675 for (
LO j = 0; j < blkSize; j++)
1676 nnz += A.getNumEntriesInLocalRow(row * blkSize + j);
1688 for (
LO j = 0; j < blkSize; j++) {
1689 A.getLocalRowView(row * blkSize + j, inds, vals);
1690 size_type numIndices = inds.
size();
1692 if (numIndices == 0)
1697 for (size_type k = 0; k < numIndices; k++) {
1699 LO nodeID = translation[inds[k]];
1702 typename STS::magnitudeType aiiajj = STS::magnitude(threshold * threshold * ghostedDiagVals[dofID] * ghostedDiagVals[row * blkSize + j]);
1703 typename STS::magnitudeType aij = STS::magnitude(vals[k] * vals[k]);
1706 if (aij > aiiajj || (row * blkSize + j == dofID)) {
1712 if (nodeID != prevNodeID) {
1713 cols[pos++] = nodeID;
1714 prevNodeID = nodeID;
1723 std::sort(cols.
begin(), cols.
end());
1725 for (
size_t j = 1; j < nnz; j++)
1726 if (cols[j] != cols[pos])
1727 cols[++pos] = cols[j];
1733 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1738 const typename STS::magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.
get<
double>(
"aggregation: Dirichlet threshold")));
1739 const typename STS::magnitudeType rowSumTol = as<typename STS::magnitudeType>(pL.
get<
double>(
"aggregation: row sum drop tol"));
1743 GetOStream(
Statistics1) <<
"Using BlockDiagonal Graph before dropping (with provided blocking)" << std::endl;
1750 ghostedBlockNumber->doImport(*BlockNumber, *importer,
Xpetra::INSERT);
1752 ghostedBlockNumber = BlockNumber;
1760 typename CrsMatrix::local_matrix_type::row_map_type::HostMirror::non_const_type rows_mat;
1761 typename LWGraph::row_type::non_const_type rows_graph;
1762 typename LWGraph::entries_type::non_const_type columns;
1763 typename CrsMatrix::local_matrix_type::values_type::HostMirror::non_const_type values;
1766 if (generate_matrix) {
1767 crs_matrix_wrap =
rcp(
new CrsMatrixWrap(A->getRowMap(), A->getColMap(), 0));
1768 rows_mat =
typename CrsMatrix::local_matrix_type::row_map_type::HostMirror::non_const_type(
"rows_mat", A->getLocalNumRows() + 1);
1770 rows_graph =
typename LWGraph::row_type::non_const_type(
"rows_graph", A->getLocalNumRows() + 1);
1772 columns =
typename LWGraph::entries_type::non_const_type(
"columns", A->getLocalNumEntries());
1773 values =
typename CrsMatrix::local_matrix_type::values_type::HostMirror::non_const_type(
"values", A->getLocalNumEntries());
1776 GO numDropped = 0, numTotal = 0;
1777 for (
LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
1778 LO row_block = row_block_number[row];
1779 size_t nnz = A->getNumEntriesInLocalRow(row);
1782 A->getLocalRowView(row, indices, vals);
1785 for (
LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
1786 LO col = indices[colID];
1787 LO col_block = col_block_number[col];
1789 if (row_block == col_block) {
1790 if (generate_matrix) values[realnnz] = vals[colID];
1791 columns[realnnz++] = col;
1796 if (generate_matrix)
1797 rows_mat[row + 1] = realnnz;
1799 rows_graph[row + 1] = realnnz;
1806 numTotal = A->getLocalNumEntries();
1809 GO numLocalBoundaryNodes = 0;
1810 GO numGlobalBoundaryNodes = 0;
1811 for (
size_t i = 0; i < boundaryNodes.size(); ++i)
1812 if (boundaryNodes(i))
1813 numLocalBoundaryNodes++;
1815 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1816 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1818 GO numGlobalTotal, numGlobalDropped;
1821 GetOStream(
Statistics1) <<
"Number of dropped entries in block-diagonalized matrix graph: " << numGlobalDropped <<
"/" << numGlobalTotal;
1822 if (numGlobalTotal != 0)
1823 GetOStream(
Statistics1) <<
" (" << 100 * Teuchos::as<double>(numGlobalDropped) / Teuchos::as<double>(numGlobalTotal) <<
"%)";
1827 Set(currentLevel,
"Filtering",
true);
1829 if (generate_matrix) {
1834 typename CrsMatrix::local_matrix_type::row_map_type>::value) {
1835 crs_matrix_wrap->getCrsMatrix()->setAllValues(rows_mat, columns, values);
1837 auto rows_mat2 =
typename CrsMatrix::local_matrix_type::row_map_type::non_const_type(
"rows_mat2", rows_mat.extent(0));
1838 Kokkos::deep_copy(rows_mat2, rows_mat);
1839 auto columns2 =
typename CrsMatrix::local_graph_type::entries_type::non_const_type(
"columns2", columns.extent(0));
1840 Kokkos::deep_copy(columns2, columns);
1841 auto values2 =
typename CrsMatrix::local_matrix_type::values_type::non_const_type(
"values2", values.extent(0));
1842 Kokkos::deep_copy(values2, values);
1843 crs_matrix_wrap->getCrsMatrix()->setAllValues(rows_mat2, columns2, values2);
1845 crs_matrix_wrap->getCrsMatrix()->expertStaticFillComplete(A->getColMap(), A->getRowMap());
1847 RCP<LWGraph> graph =
rcp(
new LWGraph(rows_graph, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), A->getRowMap(), A->getColMap(),
"block-diagonalized graph of A"));
1849 Set(currentLevel,
"Graph", graph);
1852 Set(currentLevel,
"DofsPerNode", 1);
1853 return crs_matrix_wrap;
1856 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1861 const bool localizeColoringGraph = pL.get<
bool>(
"aggregation: coloring: localize color graph");
1863 GetOStream(
Statistics1) <<
"Using BlockDiagonal Graph after Dropping (with provided blocking)";
1864 if (localizeColoringGraph)
1865 GetOStream(
Statistics1) <<
", with localization" << std::endl;
1867 GetOStream(
Statistics1) <<
", without localization" << std::endl;
1875 typename LWGraph::row_type::non_const_type rows_graph(
"rows_graph", inputGraph->
GetNodeNumVertices() + 1);
1876 typename LWGraph::entries_type::non_const_type columns(
"columns", inputGraph->
GetNodeNumEdges());
1879 GO numDropped = 0, numTotal = 0;
1880 const LO numRows = Teuchos::as<LO>(inputGraph->
GetDomainMap()->getLocalNumElements());
1881 if (localizeColoringGraph) {
1882 for (
LO row = 0; row < numRows; ++row) {
1883 LO row_block = row_block_number[row];
1887 for (
LO colID = 0; colID < Teuchos::as<LO>(indices.length); colID++) {
1888 LO col = indices(colID);
1889 LO col_block = col_block_number[col];
1891 if ((row_block == col_block) && (col < numRows)) {
1892 columns(realnnz++) = col;
1897 rows_graph(row + 1) = realnnz;
1904 boundaryNodesVector->getDataNonConst(0)[i] = boundaryNodes[i];
1907 boundaryColumnVector->doImport(*boundaryNodesVector, *importer,
Xpetra::INSERT);
1908 auto boundaryColumn = boundaryColumnVector->getData(0);
1910 for (
LO row = 0; row < numRows; ++row) {
1911 LO row_block = row_block_number[row];
1915 for (
LO colID = 0; colID < Teuchos::as<LO>(indices.length); colID++) {
1916 LO col = indices(colID);
1917 LO col_block = col_block_number[col];
1919 if ((row_block == col_block) && ((row == col) || (boundaryColumn[col] == 0))) {
1920 columns(realnnz++) = col;
1925 rows_graph(row + 1) = realnnz;
1933 GO numGlobalTotal, numGlobalDropped;
1936 GetOStream(
Statistics1) <<
"Number of dropped entries in block-diagonalized matrix graph: " << numGlobalDropped <<
"/" << numGlobalTotal;
1937 if (numGlobalTotal != 0)
1938 GetOStream(
Statistics1) <<
" (" << 100 * Teuchos::as<double>(numGlobalDropped) / Teuchos::as<double>(numGlobalTotal) <<
"%)";
1942 if (localizeColoringGraph) {
1943 outputGraph =
rcp(
new LWGraph(rows_graph, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), inputGraph->
GetDomainMap(), inputGraph->
GetImportMap(),
"block-diagonalized graph of A"));
1947 #ifdef HAVE_XPETRA_TPETRA
1948 auto outputGraph2 =
rcp(
new LWGraph(rows_graph, Kokkos::subview(columns, Kokkos::make_pair(0, realnnz)), inputGraph->
GetDomainMap(), inputGraph->
GetImportMap(),
"block-diagonalized graph of A"));
1950 auto tpGraph =
Xpetra::toTpetra(rcp_const_cast<const CrsGraph>(outputGraph2->GetCrsGraph()));
1952 auto tpGraphSym = sym->symmetrize();
1953 auto lclGraphSym = tpGraphSym->getLocalGraphHost();
1954 auto colIndsSym = lclGraphSym.entries;
1956 auto rowsSym = tpGraphSym->getLocalRowPtrsHost();
1957 typename LWGraph::row_type::non_const_type rows_graphSym(
"rows_graphSym", rowsSym.size());
1958 for (
size_t row = 0; row < rowsSym.size(); row++)
1959 rows_graphSym(row) = rowsSym(row);
1968 #endif // MUELU_COALESCEDROPFACTORY_DEF_HPP
Important warning messages (one line)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
typename local_graph_type::row_map_type row_type
Exception indicating invalid cast attempted.
void reserve(size_type n)
void BlockDiagonalizeGraph(const RCP< LWGraph > &inputGraph, const RCP< LocalOrdinalVector > &ghostedBlockNumber, RCP< LWGraph > &outputGraph, RCP< const Import > &importer) const
#define MueLu_sumAll(rcpComm, in, out)
static void ApplyRowSumCriterionHost(const Matrix &A, const typename Teuchos::ScalarTraits< Scalar >::magnitudeType rowSumTol, Kokkos::View< bool *, Kokkos::HostSpace > &dirichletRows)
KOKKOS_INLINE_FUNCTION void SetBoundaryNodeMap(const boundary_nodes_type bndry)
Set boolean array indicating which rows correspond to Dirichlet boundaries.
static Teuchos::RCP< MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Build(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node >> &map, size_t NumVectors, bool zeroOut=true)
void setValidator(RCP< const ParameterEntryValidator > const &validator)
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
static void ApplyRowSumCriterion(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude rowSumTol, Teuchos::ArrayRCP< bool > &dirichletRows)
Apply Rowsum Criterion.
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static void Write(const std::string &fileName, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &M)
DropTol & operator=(DropTol const &)=default
Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > BlockDiagonalize(Level ¤tLevel, const RCP< Matrix > &A, bool generate_matrix) const
One-liner description of what is happening.
KOKKOS_INLINE_FUNCTION size_type GetNodeNumVertices() const
Return number of graph vertices.
KOKKOS_INLINE_FUNCTION size_type GetNodeNumEdges() const
Return number of graph edges.
KOKKOS_INLINE_FUNCTION const boundary_nodes_type GetBoundaryNodeMap() const
Returns map with global ids of boundary nodes.
Exception throws to report incompatible objects (like maps).
static Teuchos::ArrayRCP< Magnitude > GetMatrixMaxMinusOffDiagonal(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A)
Return vector containing: max_{i=k}(-a_ik), for each for i in the matrix.
static const GlobalOrdinal DOFGid2NodeId(GlobalOrdinal gid, LocalOrdinal blockSize, const GlobalOrdinal offset, const GlobalOrdinal indexBase)
Translate global (row/column) id to global amalgamation block id.
Scalar GetThreshold() const
Return threshold value.
void resize(const size_type n, const T &val=T())
CoalesceDropFactory()
Constructor.
Kokkos::View< bool *, memory_space > boundary_nodes_type
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
static Teuchos::ArrayRCP< const bool > DetectDirichletRows(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude &tol=Teuchos::ScalarTraits< Magnitude >::zero(), bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
#define SET_VALID_ENTRY(name)
static void AmalgamateMap(const Map &sourceMap, const Matrix &A, RCP< const Map > &amalgamatedMap, Array< LO > &translation)
Method to create merged map for systems of PDEs.
static RCP< Vector > GetMatrixOverlappedDiagonal(const Matrix &A)
Extract Overlapped Matrix Diagonal.
void resize(size_type new_size, const value_type &x=value_type())
void Build(Level ¤tLevel) const
Build an object with this factory.
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
void DeclareInput(Level ¤tLevel) const
Input.
KOKKOS_INLINE_FUNCTION neighbor_vertices_type getNeighborVertices(LO i) const
Return the list of vertices adjacent to the vertex 'v'.
const RCP< const Map > GetImportMap() const
Return overlapping import map (nodes).
RCP< const Tpetra::CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > toTpetra(const RCP< const CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > &graph)
void push_back(const value_type &x)
void MergeRows(const Matrix &A, const LO row, Array< LO > &cols, const Array< LO > &translation) const
Method to merge rows of matrix for systems of PDEs.
RCP< const CrsGraph< int, GlobalOrdinal, Node > > toXpetra(const Epetra_CrsGraph &g)
const RCP< const Map > GetDomainMap() const
Lightweight MueLu representation of a compressed row storage graph.
DropTol(real_type val_, real_type diag_, LO col_, bool drop_)
Exception throws to report errors in the internal logical of the program.
#define TEUCHOS_ASSERT(assertion_test)
static Kokkos::View< bool *, typename Kokkos::HostSpace > DetectDirichletRows_kokkos_host(const Matrix &A, const Magnitude &tol=Teuchos::ScalarTraits< typename Teuchos::ScalarTraits< SC >::magnitudeType >::zero(), const bool count_twos_as_dirichlet=false)
static Teuchos::ScalarTraits< Scalar >::magnitudeType Distance2(const Teuchos::Array< Teuchos::ArrayRCP< const Scalar >> &v, LocalOrdinal i0, LocalOrdinal i1)
Squared distance between two rows in a multivector.
ParameterEntry & getEntry(const std::string &name)
void MergeRowsWithDropping(const Matrix &A, const LO row, const ArrayRCP< const SC > &ghostedDiagVals, SC threshold, Array< LO > &cols, const Array< LO > &translation) const