182 typedef Teuchos::ScalarTraits<SC> STS;
183 typedef typename STS::magnitudeType real_type;
184 typedef Xpetra::MultiVector<real_type,LO,GO,NO> RealValuedMultiVector;
185 typedef Xpetra::MultiVectorFactory<real_type,LO,GO,NO> RealValuedMultiVectorFactory;
193 bool doExperimentalWrap = pL.get<
bool>(
"lightweight wrap");
196 std::string algo = pL.get<std::string>(
"aggregation: drop scheme");
197 const bool aggregationMayCreateDirichlet = pL.get<
bool>(
"aggregation: dropping may create Dirichlet");
199 RCP<RealValuedMultiVector> Coords;
202 bool use_block_algorithm=
false;
203 LO interleaved_blocksize = as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize"));
204 bool useSignedClassicalRS =
false;
205 bool useSignedClassicalSA =
false;
206 bool generateColoringGraph =
false;
210 typename STS::magnitudeType rowSumTol = as<typename STS::magnitudeType>(pL.get<
double>(
"aggregation: row sum drop tol"));
213 RCP<LocalOrdinalVector> ghostedBlockNumber;
214 ArrayRCP<const LO> g_block_id;
216 if(algo ==
"distance laplacian" ) {
221 else if(algo ==
"signed classical sa") {
222 useSignedClassicalSA =
true;
226 else if(algo ==
"signed classical" || algo ==
"block diagonal colored signed classical" || algo ==
"block diagonal signed classical") {
227 useSignedClassicalRS =
true;
231 RCP<const Import> importer = realA->getCrsGraph()->getImporter();
232 if(!importer.is_null()) {
234 ghostedBlockNumber= Xpetra::VectorFactory<LO,LO,GO,NO>::Build(importer->getTargetMap());
235 ghostedBlockNumber->doImport(*BlockNumber, *importer, Xpetra::INSERT);
238 ghostedBlockNumber = BlockNumber;
240 g_block_id = ghostedBlockNumber->getData(0);
242 if(algo ==
"block diagonal colored signed classical")
243 generateColoringGraph=
true;
248 else if(algo ==
"block diagonal") {
253 else if (algo ==
"block diagonal classical" || algo ==
"block diagonal distance laplacian") {
255 use_block_algorithm =
true;
257 if(algo ==
"block diagonal distance laplacian") {
260 if (OldCoords->getLocalLength() != realA->getLocalNumRows()) {
261 LO dim = (LO) OldCoords->getNumVectors();
262 Coords = RealValuedMultiVectorFactory::Build(realA->getRowMap(),dim);
263 for(LO k=0; k<dim; k++){
264 ArrayRCP<const real_type> old_vec = OldCoords->getData(k);
265 ArrayRCP<real_type> new_vec = Coords->getDataNonConst(k);
266 for(LO i=0; i <(LO)OldCoords->getLocalLength(); i++) {
268 for(LO j=0; j<interleaved_blocksize; j++)
269 new_vec[new_base + j] = old_vec[i];
276 algo =
"distance laplacian";
278 else if(algo ==
"block diagonal classical") {
290 Array<double> dlap_weights = pL.get<Array<double> >(
"aggregation: distance laplacian directional weights");
291 enum {NO_WEIGHTS=0, SINGLE_WEIGHTS, BLOCK_WEIGHTS};
292 int use_dlap_weights = NO_WEIGHTS;
293 if(algo ==
"distance laplacian") {
294 LO dim = (LO) Coords->getNumVectors();
296 bool non_unity =
false;
297 for (LO i=0; !non_unity && i<(LO)dlap_weights.size(); i++) {
298 if(dlap_weights[i] != 1.0) {
303 LO blocksize = use_block_algorithm ? as<LO>(pL.get<
int>(
"aggregation: block diagonal: interleaved blocksize")) : 1;
304 if((LO)dlap_weights.size() == dim)
305 use_dlap_weights = SINGLE_WEIGHTS;
306 else if((LO)dlap_weights.size() == blocksize * dim)
307 use_dlap_weights = BLOCK_WEIGHTS;
310 "length of 'aggregation: distance laplacian directional weights' must equal the coordinate dimension OR the coordinate dimension times the blocksize");
328 if (doExperimentalWrap) {
329 TEUCHOS_TEST_FOR_EXCEPTION(
predrop_ != null && algo !=
"classical",
Exceptions::RuntimeError,
"Dropping function must not be provided for \"" << algo <<
"\" algorithm");
330 TEUCHOS_TEST_FOR_EXCEPTION(algo !=
"classical" && algo !=
"distance laplacian" && algo !=
"signed classical",
Exceptions::RuntimeError,
"\"algorithm\" must be one of (classical|distance laplacian|signed classical)");
334 if (pL.get<
bool>(
"aggregation: use ml scaling of drop tol"))
335 threshold = pL.get<
double>(
"aggregation: drop tol") / pow(2.0,currentLevel.
GetLevelID());
337 threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
340 std::string distanceLaplacianAlgoStr = pL.get<std::string>(
"aggregation: distance laplacian algo");
341 std::string classicalAlgoStr = pL.get<std::string>(
"aggregation: classical algo");
342 real_type realThreshold = STS::magnitude(threshold);
346#ifdef HAVE_MUELU_DEBUG
347 int distanceLaplacianCutVerbose = 0;
349#ifdef DJS_READ_ENV_VARIABLES
350 if (getenv(
"MUELU_DROP_TOLERANCE_MODE")) {
351 distanceLaplacianAlgoStr = std::string(getenv(
"MUELU_DROP_TOLERANCE_MODE"));
354 if (getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD")) {
355 auto tmp = atoi(getenv(
"MUELU_DROP_TOLERANCE_THRESHOLD"));
356 realThreshold = 1e-4*tmp;
359# ifdef HAVE_MUELU_DEBUG
360 if (getenv(
"MUELU_DROP_TOLERANCE_VERBOSE")) {
361 distanceLaplacianCutVerbose = atoi(getenv(
"MUELU_DROP_TOLERANCE_VERBOSE"));
367 enum decisionAlgoType {defaultAlgo, unscaled_cut, scaled_cut, scaled_cut_symmetric};
369 decisionAlgoType distanceLaplacianAlgo = defaultAlgo;
370 decisionAlgoType classicalAlgo = defaultAlgo;
371 if (algo ==
"distance laplacian") {
372 if (distanceLaplacianAlgoStr ==
"default")
373 distanceLaplacianAlgo = defaultAlgo;
374 else if (distanceLaplacianAlgoStr ==
"unscaled cut")
375 distanceLaplacianAlgo = unscaled_cut;
376 else if (distanceLaplacianAlgoStr ==
"scaled cut")
377 distanceLaplacianAlgo = scaled_cut;
378 else if (distanceLaplacianAlgoStr ==
"scaled cut symmetric")
379 distanceLaplacianAlgo = scaled_cut_symmetric;
381 TEUCHOS_TEST_FOR_EXCEPTION(
true,
Exceptions::RuntimeError,
"\"aggregation: distance laplacian algo\" must be one of (default|unscaled cut|scaled cut), not \"" << distanceLaplacianAlgoStr <<
"\"");
382 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" distance laplacian algorithm = \"" << distanceLaplacianAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize()<< std::endl;
383 }
else if (algo ==
"classical") {
384 if (classicalAlgoStr ==
"default")
385 classicalAlgo = defaultAlgo;
386 else if (classicalAlgoStr ==
"unscaled cut")
387 classicalAlgo = unscaled_cut;
388 else if (classicalAlgoStr ==
"scaled cut")
389 classicalAlgo = scaled_cut;
391 TEUCHOS_TEST_FOR_EXCEPTION(
true,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" must be one of (default|unscaled cut|scaled cut), not \"" << classicalAlgoStr <<
"\"");
392 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\" classical algorithm = \"" << classicalAlgoStr <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
395 GetOStream(
Runtime0) <<
"algorithm = \"" << algo <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
396 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
398 const typename STS::magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.get<
double>(
"aggregation: Dirichlet threshold")));
402 TEUCHOS_TEST_FOR_EXCEPTION(useSignedClassicalRS && classicalAlgo != defaultAlgo,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" != default is not supported for scalled classical aggregation");
403 TEUCHOS_TEST_FOR_EXCEPTION(useSignedClassicalSA && classicalAlgo != defaultAlgo,
Exceptions::RuntimeError,
"\"aggregation: classical algo\" != default is not supported for scalled classical sa aggregation");
405 GO numDropped = 0, numTotal = 0;
406 std::string graphType =
"unamalgamated";
425 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0,
Exceptions::RuntimeError,
"A->GetFixedBlockSize() needs to be a multiple of A->GetStorageBlockSize()");
426 const LO BlockSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
430 if (algo ==
"classical") {
437 RCP<PreDropFunctionConstVal> predropConstVal = rcp_dynamic_cast<PreDropFunctionConstVal>(
predrop_);
439 "MueLu::CoalesceFactory::Build: cast to PreDropFunctionConstVal failed.");
441 SC newt = predropConstVal->GetThreshold();
442 if (newt != threshold) {
443 GetOStream(
Warnings0) <<
"switching threshold parameter from " << threshold <<
" (list) to " << newt <<
" (user function" << std::endl;
450 if ( BlockSize==1 && threshold == STS::zero() && !useSignedClassicalRS && !useSignedClassicalSA && A->hasCrsGraph()) {
452 RCP<GraphBase> graph = rcp(
new Graph(A->getCrsGraph(),
"graph of A"));
458 graph->SetBoundaryNodeMap(boundaryNodes);
459 numTotal = A->getLocalNumEntries();
462 GO numLocalBoundaryNodes = 0;
463 GO numGlobalBoundaryNodes = 0;
464 for (LO i = 0; i < boundaryNodes.size(); ++i)
465 if (boundaryNodes[i])
466 numLocalBoundaryNodes++;
467 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
468 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
472 Set(currentLevel,
"DofsPerNode", 1);
473 Set(currentLevel,
"Graph", graph);
475 }
else if ( (BlockSize == 1 && threshold != STS::zero()) ||
476 (BlockSize == 1 && threshold == STS::zero() && !A->hasCrsGraph()) ||
477 (BlockSize == 1 && useSignedClassicalRS) ||
478 (BlockSize == 1 && useSignedClassicalSA) ) {
484 ArrayRCP<LO> rows (A->getLocalNumRows()+1);
485 ArrayRCP<LO> columns(A->getLocalNumEntries());
487 using MT =
typename STS::magnitudeType;
488 RCP<Vector> ghostedDiag;
489 ArrayRCP<const SC> ghostedDiagVals;
490 ArrayRCP<const MT> negMaxOffDiagonal;
492 if(useSignedClassicalRS) {
493 if(ghostedBlockNumber.is_null()) {
506 ghostedDiagVals = ghostedDiag->getData(0);
509 if (rowSumTol > 0.) {
510 if(ghostedBlockNumber.is_null()) {
523 for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
524 size_t nnz = A->getNumEntriesInLocalRow(row);
525 bool rowIsDirichlet = boundaryNodes[row];
526 ArrayView<const LO> indices;
527 ArrayView<const SC> vals;
528 A->getLocalRowView(row, indices, vals);
530 if(classicalAlgo == defaultAlgo) {
537 if(useSignedClassicalRS) {
539 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
540 LO col = indices[colID];
541 MT max_neg_aik = realThreshold * STS::real(negMaxOffDiagonal[row]);
542 MT neg_aij = - STS::real(vals[colID]);
547 if ((!rowIsDirichlet && (g_block_id.is_null() || g_block_id[row] == g_block_id[col]) && neg_aij > max_neg_aik) || row == col) {
548 columns[realnnz++] = col;
553 rows[row+1] = realnnz;
555 else if(useSignedClassicalSA) {
557 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
558 LO col = indices[colID];
560 bool is_nonpositive = STS::real(vals[colID]) <= 0;
561 MT aiiajj = STS::magnitude(threshold*threshold * ghostedDiagVals[col]*ghostedDiagVals[row]);
562 MT aij = is_nonpositive ? STS::magnitude(vals[colID]*vals[colID]) : (-STS::magnitude(vals[colID]*vals[colID]));
568 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
569 columns[realnnz++] = col;
574 rows[row+1] = realnnz;
578 for (LO colID = 0; colID < Teuchos::as<LO>(nnz); colID++) {
579 LO col = indices[colID];
580 MT aiiajj = STS::magnitude(threshold*threshold * ghostedDiagVals[col]*ghostedDiagVals[row]);
581 MT aij = STS::magnitude(vals[colID]*vals[colID]);
583 if ((!rowIsDirichlet && aij > aiiajj) || row == col) {
584 columns[realnnz++] = col;
589 rows[row+1] = realnnz;
596 std::vector<DropTol> drop_vec;
597 drop_vec.reserve(nnz);
598 const real_type zero = Teuchos::ScalarTraits<real_type>::zero();
599 const real_type one = Teuchos::ScalarTraits<real_type>::one();
604 for (LO colID = 0; colID < (LO)nnz; colID++) {
605 LO col = indices[colID];
607 drop_vec.emplace_back( zero, one, colID,
false);
612 if(boundaryNodes[colID])
continue;
613 typename STS::magnitudeType aiiajj = STS::magnitude(threshold*threshold * ghostedDiagVals[col]*ghostedDiagVals[row]);
614 typename STS::magnitudeType aij = STS::magnitude(vals[colID]*vals[colID]);
615 drop_vec.emplace_back(aij, aiiajj, colID,
false);
618 const size_t n = drop_vec.size();
620 if (classicalAlgo == unscaled_cut) {
621 std::sort( drop_vec.begin(), drop_vec.end()
622 , [](DropTol
const& a, DropTol
const& b) {
623 return a.val > b.val;
627 for (
size_t i=1; i<n; ++i) {
629 auto const& x = drop_vec[i-1];
630 auto const& y = drop_vec[i];
633 if (a > realThreshold*b) {
635#ifdef HAVE_MUELU_DEBUG
636 if (distanceLaplacianCutVerbose) {
637 std::cout <<
"DJS: KEEP, N, ROW: " << i+1 <<
", " << n <<
", " << row << std::endl;
642 drop_vec[i].drop = drop;
644 }
else if (classicalAlgo == scaled_cut) {
645 std::sort( drop_vec.begin(), drop_vec.end()
646 , [](DropTol
const& a, DropTol
const& b) {
647 return a.val/a.diag > b.val/b.diag;
652 for (
size_t i=1; i<n; ++i) {
654 auto const& x = drop_vec[i-1];
655 auto const& y = drop_vec[i];
656 auto a = x.val/x.diag;
657 auto b = y.val/y.diag;
658 if (a > realThreshold*b) {
661#ifdef HAVE_MUELU_DEBUG
662 if (distanceLaplacianCutVerbose) {
663 std::cout <<
"DJS: KEEP, N, ROW: " << i+1 <<
", " << n <<
", " << row << std::endl;
670 drop_vec[i].drop = drop;
674 std::sort( drop_vec.begin(), drop_vec.end()
675 , [](DropTol
const& a, DropTol
const& b) {
676 return a.col < b.col;
680 for (LO idxID =0; idxID<(LO)drop_vec.size(); idxID++) {
681 LO col = indices[drop_vec[idxID].col];
684 columns[realnnz++] = col;
689 if (!drop_vec[idxID].drop) {
690 columns[realnnz++] = col;
697 rows[row+1] = realnnz;
702 columns.resize(realnnz);
703 numTotal = A->getLocalNumEntries();
705 if (aggregationMayCreateDirichlet) {
707 for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); ++row) {
708 if (rows[row+1]- rows[row] <= 1)
709 boundaryNodes[row] =
true;
713 RCP<GraphBase> graph = rcp(
new LWGraph(rows, columns, A->getRowMap(), A->getColMap(),
"thresholded graph of A"));
714 graph->SetBoundaryNodeMap(boundaryNodes);
716 GO numLocalBoundaryNodes = 0;
717 GO numGlobalBoundaryNodes = 0;
718 for (LO i = 0; i < boundaryNodes.size(); ++i)
719 if (boundaryNodes[i])
720 numLocalBoundaryNodes++;
721 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
722 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
725 Set(currentLevel,
"Graph", graph);
726 Set(currentLevel,
"DofsPerNode", 1);
729 if(generateColoringGraph) {
730 RCP<GraphBase> colorGraph;
731 RCP<const Import> importer = A->getCrsGraph()->getImporter();
733 Set(currentLevel,
"Coloring Graph",colorGraph);
737 Xpetra::IO<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Write(
"m_regular_graph."+std::to_string(currentLevel.
GetLevelID()), *rcp_dynamic_cast<LWGraph>(graph)->GetCrsGraph());
738 Xpetra::IO<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Write(
"m_color_graph."+std::to_string(currentLevel.
GetLevelID()), *rcp_dynamic_cast<LWGraph>(colorGraph)->GetCrsGraph());
754 }
else if (BlockSize > 1 && threshold == STS::zero()) {
756 const RCP<const Map> rowMap = A->getRowMap();
757 const RCP<const Map> colMap = A->getColMap();
759 graphType =
"amalgamated";
765 RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
766 RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
767 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
768 Array<LO> colTranslation = *(amalInfo->getColTranslation());
771 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
774 ArrayRCP<LO> rows = ArrayRCP<LO>(numRows+1);
775 ArrayRCP<LO> columns = ArrayRCP<LO>(A->getLocalNumEntries());
777 const ArrayRCP<bool> amalgBoundaryNodes(numRows,
false);
783 ArrayRCP<bool > pointBoundaryNodes;
790 LO blkSize = A->GetFixedBlockSize();
792 LO blkPartSize = A->GetFixedBlockSize();
793 if (A->IsView(
"stridedMaps") ==
true) {
794 Teuchos::RCP<const Map> myMap = A->getRowMap(
"stridedMaps");
795 Teuchos::RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
797 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
798 blkId = strMap->getStridedBlockId();
800 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
806 Array<LO> indicesExtra;
807 for (LO row = 0; row < numRows; row++) {
808 ArrayView<const LO> indices;
809 indicesExtra.resize(0);
817 bool isBoundary =
false;
818 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
819 for (LO j = 0; j < blkPartSize; j++) {
820 if (pointBoundaryNodes[row*blkPartSize+j]) {
827 for (LO j = 0; j < blkPartSize; j++) {
828 if (!pointBoundaryNodes[row*blkPartSize+j]) {
838 MergeRows(*A, row, indicesExtra, colTranslation);
840 indicesExtra.push_back(row);
841 indices = indicesExtra;
842 numTotal += indices.size();
846 LO nnz = indices.size(), rownnz = 0;
847 for (LO colID = 0; colID < nnz; colID++) {
848 LO col = indices[colID];
849 columns[realnnz++] = col;
860 amalgBoundaryNodes[row] =
true;
862 rows[row+1] = realnnz;
864 columns.resize(realnnz);
866 RCP<GraphBase> graph = rcp(
new LWGraph(rows, columns, uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
867 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
870 GO numLocalBoundaryNodes = 0;
871 GO numGlobalBoundaryNodes = 0;
873 for (LO i = 0; i < amalgBoundaryNodes.size(); ++i)
874 if (amalgBoundaryNodes[i])
875 numLocalBoundaryNodes++;
877 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
878 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
880 <<
" agglomerated Dirichlet nodes" << std::endl;
883 Set(currentLevel,
"Graph", graph);
884 Set(currentLevel,
"DofsPerNode", blkSize);
886 }
else if (BlockSize > 1 && threshold != STS::zero()) {
888 const RCP<const Map> rowMap = A->getRowMap();
889 const RCP<const Map> colMap = A->getColMap();
890 graphType =
"amalgamated";
896 RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
897 RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
898 Array<LO> rowTranslation = *(amalInfo->getRowTranslation());
899 Array<LO> colTranslation = *(amalInfo->getColTranslation());
902 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
905 ArrayRCP<LO> rows = ArrayRCP<LO>(numRows+1);
906 ArrayRCP<LO> columns = ArrayRCP<LO>(A->getLocalNumEntries());
908 const ArrayRCP<bool> amalgBoundaryNodes(numRows,
false);
914 ArrayRCP<bool > pointBoundaryNodes;
921 LO blkSize = A->GetFixedBlockSize();
923 LO blkPartSize = A->GetFixedBlockSize();
924 if (A->IsView(
"stridedMaps") ==
true) {
925 Teuchos::RCP<const Map> myMap = A->getRowMap(
"stridedMaps");
926 Teuchos::RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
928 blkSize = Teuchos::as<const LO>(strMap->getFixedBlockSize());
929 blkId = strMap->getStridedBlockId();
931 blkPartSize = Teuchos::as<LO>(strMap->getStridingData()[blkId]);
936 const ArrayRCP<const SC> ghostedDiagVals = ghostedDiag->getData(0);
941 Array<LO> indicesExtra;
942 for (LO row = 0; row < numRows; row++) {
943 ArrayView<const LO> indices;
944 indicesExtra.resize(0);
952 bool isBoundary =
false;
953 if (pL.get<
bool>(
"aggregation: greedy Dirichlet") ==
true) {
954 for (LO j = 0; j < blkPartSize; j++) {
955 if (pointBoundaryNodes[row*blkPartSize+j]) {
962 for (LO j = 0; j < blkPartSize; j++) {
963 if (!pointBoundaryNodes[row*blkPartSize+j]) {
975 indicesExtra.push_back(row);
976 indices = indicesExtra;
977 numTotal += indices.size();
981 LO nnz = indices.size(), rownnz = 0;
982 for (LO colID = 0; colID < nnz; colID++) {
983 LO col = indices[colID];
984 columns[realnnz++] = col;
995 amalgBoundaryNodes[row] =
true;
997 rows[row+1] = realnnz;
999 columns.resize(realnnz);
1001 RCP<GraphBase> graph = rcp(
new LWGraph(rows, columns, uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1002 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1005 GO numLocalBoundaryNodes = 0;
1006 GO numGlobalBoundaryNodes = 0;
1008 for (LO i = 0; i < amalgBoundaryNodes.size(); ++i)
1009 if (amalgBoundaryNodes[i])
1010 numLocalBoundaryNodes++;
1012 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
1013 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1015 <<
" agglomerated Dirichlet nodes" << std::endl;
1018 Set(currentLevel,
"Graph", graph);
1019 Set(currentLevel,
"DofsPerNode", blkSize);
1022 }
else if (algo ==
"distance laplacian") {
1023 LO blkSize = A->GetFixedBlockSize();
1024 GO indexBase = A->getRowMap()->getIndexBase();
1035 ArrayRCP<bool > pointBoundaryNodes;
1040 if ( (blkSize == 1) && (threshold == STS::zero()) ) {
1042 RCP<GraphBase> graph = rcp(
new Graph(A->getCrsGraph(),
"graph of A"));
1043 graph->SetBoundaryNodeMap(pointBoundaryNodes);
1044 graphType=
"unamalgamated";
1045 numTotal = A->getLocalNumEntries();
1048 GO numLocalBoundaryNodes = 0;
1049 GO numGlobalBoundaryNodes = 0;
1050 for (LO i = 0; i < pointBoundaryNodes.size(); ++i)
1051 if (pointBoundaryNodes[i])
1052 numLocalBoundaryNodes++;
1053 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
1054 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1055 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1058 Set(currentLevel,
"DofsPerNode", blkSize);
1059 Set(currentLevel,
"Graph", graph);
1074 TEUCHOS_TEST_FOR_EXCEPTION(A->getRowMap()->getLocalNumElements()/blkSize != Coords->getLocalLength(),
Exceptions::Incompatible,
1075 "Coordinate vector length (" << Coords->getLocalLength() <<
") is incompatible with number of rows in A (" << A->getRowMap()->getLocalNumElements() <<
") by modulo block size ("<< blkSize <<
").");
1077 const RCP<const Map> colMap = A->getColMap();
1078 RCP<const Map> uniqueMap, nonUniqueMap;
1079 Array<LO> colTranslation;
1081 uniqueMap = A->getRowMap();
1082 nonUniqueMap = A->getColMap();
1083 graphType=
"unamalgamated";
1086 uniqueMap = Coords->getMap();
1088 "Different index bases for matrix and coordinates");
1092 graphType =
"amalgamated";
1094 LO numRows = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
1096 RCP<RealValuedMultiVector> ghostedCoords;
1097 RCP<Vector> ghostedLaplDiag;
1098 Teuchos::ArrayRCP<SC> ghostedLaplDiagData;
1099 if (threshold != STS::zero()) {
1101 RCP<const Import> importer;
1104 if (blkSize == 1 && realA->getCrsGraph()->getImporter() != Teuchos::null) {
1106 importer = realA->getCrsGraph()->getImporter();
1109 importer = ImportFactory::Build(uniqueMap, nonUniqueMap);
1112 ghostedCoords = Xpetra::MultiVectorFactory<real_type,LO,GO,NO>::Build(nonUniqueMap, Coords->getNumVectors());
1115 ghostedCoords->doImport(*Coords, *importer, Xpetra::INSERT);
1119 RCP<Vector> localLaplDiag = VectorFactory::Build(uniqueMap);
1120 Array<LO> indicesExtra;
1121 Teuchos::Array<Teuchos::ArrayRCP<const real_type>> coordData;
1122 if (threshold != STS::zero()) {
1123 const size_t numVectors = ghostedCoords->getNumVectors();
1124 coordData.reserve(numVectors);
1125 for (
size_t j = 0; j < numVectors; j++) {
1126 Teuchos::ArrayRCP<const real_type> tmpData=ghostedCoords->getData(j);
1127 coordData.push_back(tmpData);
1132 ArrayRCP<SC> localLaplDiagData = localLaplDiag->getDataNonConst(0);
1133 for (LO row = 0; row < numRows; row++) {
1134 ArrayView<const LO> indices;
1137 ArrayView<const SC> vals;
1138 A->getLocalRowView(row, indices, vals);
1142 indicesExtra.resize(0);
1143 MergeRows(*A, row, indicesExtra, colTranslation);
1144 indices = indicesExtra;
1147 LO nnz = indices.size();
1148 bool haveAddedToDiag =
false;
1149 for (LO colID = 0; colID < nnz; colID++) {
1150 const LO col = indices[colID];
1153 if(use_dlap_weights == SINGLE_WEIGHTS) {
1159 else if(use_dlap_weights == BLOCK_WEIGHTS) {
1160 int block_id = row % interleaved_blocksize;
1161 int block_start = block_id * interleaved_blocksize;
1168 haveAddedToDiag =
true;
1173 if (!haveAddedToDiag)
1174 localLaplDiagData[row] = STS::rmax();
1179 ghostedLaplDiag = VectorFactory::Build(nonUniqueMap);
1180 ghostedLaplDiag->doImport(*localLaplDiag, *importer, Xpetra::INSERT);
1181 ghostedLaplDiagData = ghostedLaplDiag->getDataNonConst(0);
1185 GetOStream(
Runtime0) <<
"Skipping distance laplacian construction due to 0 threshold" << std::endl;
1191 ArrayRCP<LO> rows = ArrayRCP<LO>(numRows+1);
1192 ArrayRCP<LO> columns = ArrayRCP<LO>(A->getLocalNumEntries());
1194#ifdef HAVE_MUELU_DEBUG
1196 for(LO i=0; i<(LO)columns.size(); i++) columns[i]=-666;
1200 ArrayRCP<LO> rows_stop;
1201 bool use_stop_array = threshold != STS::zero() && distanceLaplacianAlgo == scaled_cut_symmetric;
1203 rows_stop.resize(numRows);
1205 const ArrayRCP<bool> amalgBoundaryNodes(numRows,
false);
1210 Array<LO> indicesExtra;
1213 Teuchos::Array<Teuchos::ArrayRCP<const real_type>> coordData;
1214 if (threshold != STS::zero()) {
1215 const size_t numVectors = ghostedCoords->getNumVectors();
1216 coordData.reserve(numVectors);
1217 for (
size_t j = 0; j < numVectors; j++) {
1218 Teuchos::ArrayRCP<const real_type> tmpData=ghostedCoords->getData(j);
1219 coordData.push_back(tmpData);
1223 ArrayView<const SC> vals;
1224 for (LO row = 0; row < numRows; row++) {
1225 ArrayView<const LO> indices;
1226 indicesExtra.resize(0);
1227 bool isBoundary =
false;
1231 A->getLocalRowView(row, indices, vals);
1232 isBoundary = pointBoundaryNodes[row];
1235 for (LO j = 0; j < blkSize; j++) {
1236 if (!pointBoundaryNodes[row*blkSize+j]) {
1244 MergeRows(*A, row, indicesExtra, colTranslation);
1246 indicesExtra.push_back(row);
1247 indices = indicesExtra;
1249 numTotal += indices.size();
1251 LO nnz = indices.size(), rownnz = 0;
1253 if(use_stop_array) {
1254 rows[row+1] = rows[row]+nnz;
1255 realnnz = rows[row];
1258 if (threshold != STS::zero()) {
1260 if (distanceLaplacianAlgo == defaultAlgo) {
1262 for (LO colID = 0; colID < nnz; colID++) {
1264 LO col = indices[colID];
1267 columns[realnnz++] = col;
1273 if(isBoundary)
continue;
1276 if(use_dlap_weights == SINGLE_WEIGHTS) {
1279 else if(use_dlap_weights == BLOCK_WEIGHTS) {
1280 int block_id = row % interleaved_blocksize;
1281 int block_start = block_id * interleaved_blocksize;
1287 real_type aiiajj = STS::magnitude(realThreshold*realThreshold * ghostedLaplDiagData[row]*ghostedLaplDiagData[col]);
1288 real_type aij = STS::magnitude(laplVal*laplVal);
1291 columns[realnnz++] = col;
1300 std::vector<DropTol> drop_vec;
1301 drop_vec.reserve(nnz);
1302 const real_type zero = Teuchos::ScalarTraits<real_type>::zero();
1303 const real_type one = Teuchos::ScalarTraits<real_type>::one();
1306 for (LO colID = 0; colID < nnz; colID++) {
1308 LO col = indices[colID];
1311 drop_vec.emplace_back( zero, one, colID,
false);
1315 if(isBoundary)
continue;
1318 if(use_dlap_weights == SINGLE_WEIGHTS) {
1321 else if(use_dlap_weights == BLOCK_WEIGHTS) {
1322 int block_id = row % interleaved_blocksize;
1323 int block_start = block_id * interleaved_blocksize;
1330 real_type aiiajj = STS::magnitude(ghostedLaplDiagData[row]*ghostedLaplDiagData[col]);
1331 real_type aij = STS::magnitude(laplVal*laplVal);
1333 drop_vec.emplace_back(aij, aiiajj, colID,
false);
1336 const size_t n = drop_vec.size();
1338 if (distanceLaplacianAlgo == unscaled_cut) {
1340 std::sort( drop_vec.begin(), drop_vec.end()
1341 , [](DropTol
const& a, DropTol
const& b) {
1342 return a.val > b.val;
1347 for (
size_t i=1; i<n; ++i) {
1349 auto const& x = drop_vec[i-1];
1350 auto const& y = drop_vec[i];
1353 if (a > realThreshold*b) {
1355#ifdef HAVE_MUELU_DEBUG
1356 if (distanceLaplacianCutVerbose) {
1357 std::cout <<
"DJS: KEEP, N, ROW: " << i+1 <<
", " << n <<
", " << row << std::endl;
1362 drop_vec[i].drop = drop;
1365 else if (distanceLaplacianAlgo == scaled_cut || distanceLaplacianAlgo == scaled_cut_symmetric) {
1367 std::sort( drop_vec.begin(), drop_vec.end()
1368 , [](DropTol
const& a, DropTol
const& b) {
1369 return a.val/a.diag > b.val/b.diag;
1374 for (
size_t i=1; i<n; ++i) {
1376 auto const& x = drop_vec[i-1];
1377 auto const& y = drop_vec[i];
1378 auto a = x.val/x.diag;
1379 auto b = y.val/y.diag;
1380 if (a > realThreshold*b) {
1382#ifdef HAVE_MUELU_DEBUG
1383 if (distanceLaplacianCutVerbose) {
1384 std::cout <<
"DJS: KEEP, N, ROW: " << i+1 <<
", " << n <<
", " << row << std::endl;
1389 drop_vec[i].drop = drop;
1393 std::sort( drop_vec.begin(), drop_vec.end()
1394 , [](DropTol
const& a, DropTol
const& b) {
1395 return a.col < b.col;
1399 for (LO idxID =0; idxID<(LO)drop_vec.size(); idxID++) {
1400 LO col = indices[drop_vec[idxID].col];
1405 columns[realnnz++] = col;
1411 if (!drop_vec[idxID].drop) {
1412 columns[realnnz++] = col;
1423 for (LO colID = 0; colID < nnz; colID++) {
1424 LO col = indices[colID];
1425 columns[realnnz++] = col;
1437 amalgBoundaryNodes[row] =
true;
1441 rows_stop[row] = rownnz + rows[row];
1443 rows[row+1] = realnnz;
1448 if (use_stop_array) {
1451 for (LO row = 0; row < numRows; row++) {
1452 for (LO colidx = rows[row]; colidx < rows_stop[row]; colidx++) {
1453 LO col = columns[colidx];
1454 if(col >= numRows)
continue;
1457 for(LO t_col = rows[col] ; !found && t_col < rows_stop[col]; t_col++) {
1458 if (columns[t_col] == row)
1463 if(!found && !pointBoundaryNodes[col] && rows_stop[col] < rows[col+1]) {
1464 LO new_idx = rows_stop[col];
1466 columns[new_idx] = row;
1475 for (LO row = 0; row < numRows; row++) {
1476 LO old_start = current_start;
1477 for (LO col = rows[row]; col < rows_stop[row]; col++) {
1478 if(current_start != col) {
1479 columns[current_start] = columns[col];
1483 rows[row] = old_start;
1485 rows[numRows] = realnnz = current_start;
1489 columns.resize(realnnz);
1491 RCP<GraphBase> graph;
1494 graph = rcp(
new LWGraph(rows, columns, uniqueMap, nonUniqueMap,
"amalgamated graph of A"));
1495 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1499 GO numLocalBoundaryNodes = 0;
1500 GO numGlobalBoundaryNodes = 0;
1502 for (LO i = 0; i < amalgBoundaryNodes.size(); ++i)
1503 if (amalgBoundaryNodes[i])
1504 numLocalBoundaryNodes++;
1506 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
1507 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1509 <<
" using threshold " << dirichletThreshold << std::endl;
1512 Set(currentLevel,
"Graph", graph);
1513 Set(currentLevel,
"DofsPerNode", blkSize);
1518 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
1519 GO numGlobalTotal, numGlobalDropped;
1522 GetOStream(
Statistics1) <<
"Number of dropped entries in " << graphType <<
" matrix graph: " << numGlobalDropped <<
"/" << numGlobalTotal;
1523 if (numGlobalTotal != 0)
1524 GetOStream(
Statistics1) <<
" (" << 100*Teuchos::as<double>(numGlobalDropped)/Teuchos::as<double>(numGlobalTotal) <<
"%)";
1531 SC threshold = as<SC>(pL.get<
double>(
"aggregation: drop tol"));
1533 GetOStream(
Runtime0) <<
"algorithm = \"" <<
"failsafe" <<
"\": threshold = " << threshold <<
", blocksize = " << A->GetFixedBlockSize() << std::endl;
1534 Set<bool>(currentLevel,
"Filtering", (threshold != STS::zero()));
1536 RCP<const Map> rowMap = A->getRowMap();
1537 RCP<const Map> colMap = A->getColMap();
1540 GO indexBase = rowMap->getIndexBase();
1544 if(A->IsView(
"stridedMaps") &&
1545 Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap(
"stridedMaps")) != Teuchos::null) {
1546 Xpetra::viewLabel_t oldView = A->SwitchToView(
"stridedMaps");
1547 RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap());
1548 TEUCHOS_TEST_FOR_EXCEPTION(strMap == Teuchos::null,
Exceptions::BadCast,
"MueLu::CoalesceFactory::Build: cast to strided row map failed.");
1549 blockdim = strMap->getFixedBlockSize();
1550 offset = strMap->getOffset();
1551 oldView = A->SwitchToView(oldView);
1552 GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build():" <<
" found blockdim=" << blockdim <<
" from strided maps. offset=" << offset << std::endl;
1553 }
else GetOStream(
Statistics1) <<
"CoalesceDropFactory::Build(): no striding information available. Use blockdim=1 with offset=0" << std::endl;
1557 RCP<const Map> nodeMap = amalInfo->getNodeRowMap();
1558 GetOStream(
Statistics1) <<
"CoalesceDropFactory: nodeMap " << nodeMap->getLocalNumElements() <<
"/" << nodeMap->getGlobalNumElements() <<
" elements" << std::endl;
1561 RCP<CrsGraph> crsGraph = CrsGraphFactory::Build(nodeMap, A->getLocalMaxNumRowEntries()*blockdim);
1563 LO numRows = A->getRowMap()->getLocalNumElements();
1564 LO numNodes = nodeMap->getLocalNumElements();
1565 const ArrayRCP<bool> amalgBoundaryNodes(numNodes,
false);
1566 const ArrayRCP<int> numberDirichletRowsPerNode(numNodes, 0);
1567 bool bIsDiagonalEntry =
false;
1572 for(LO row=0; row<numRows; row++) {
1574 GO grid = rowMap->getGlobalElement(row);
1577 bIsDiagonalEntry =
false;
1582 size_t nnz = A->getNumEntriesInLocalRow(row);
1583 Teuchos::ArrayView<const LO> indices;
1584 Teuchos::ArrayView<const SC> vals;
1585 A->getLocalRowView(row, indices, vals);
1587 RCP<std::vector<GO> > cnodeIds = Teuchos::rcp(
new std::vector<GO>);
1589 for(LO col=0; col<Teuchos::as<LO>(nnz); col++) {
1590 GO gcid = colMap->getGlobalElement(indices[col]);
1592 if(vals[col]!=STS::zero()) {
1594 cnodeIds->push_back(cnodeId);
1596 if (grid == gcid) bIsDiagonalEntry =
true;
1600 if(realnnz == 1 && bIsDiagonalEntry ==
true) {
1601 LO lNodeId = nodeMap->getLocalElement(nodeId);
1602 numberDirichletRowsPerNode[lNodeId] += 1;
1603 if (numberDirichletRowsPerNode[lNodeId] == blockdim)
1604 amalgBoundaryNodes[lNodeId] =
true;
1607 Teuchos::ArrayRCP<GO> arr_cnodeIds = Teuchos::arcp( cnodeIds );
1609 if(arr_cnodeIds.size() > 0 )
1610 crsGraph->insertGlobalIndices(nodeId, arr_cnodeIds());
1613 crsGraph->fillComplete(nodeMap,nodeMap);
1616 RCP<GraphBase> graph = rcp(
new Graph(crsGraph,
"amalgamated graph of A"));
1619 graph->SetBoundaryNodeMap(amalgBoundaryNodes);
1622 GO numLocalBoundaryNodes = 0;
1623 GO numGlobalBoundaryNodes = 0;
1624 for (LO i = 0; i < amalgBoundaryNodes.size(); ++i)
1625 if (amalgBoundaryNodes[i])
1626 numLocalBoundaryNodes++;
1627 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
1628 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
1629 GetOStream(
Statistics1) <<
"Detected " << numGlobalBoundaryNodes <<
" Dirichlet nodes" << std::endl;
1634 Set(currentLevel,
"DofsPerNode", blockdim);
1635 Set(currentLevel,
"Graph", graph);