77 using XMM = Xpetra::MatrixMatrix<SC, LO, GO, NO>;
78 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_type;
79 using rowptr_type =
typename local_matrix_type::row_map_type::non_const_type;
80 using colidx_type =
typename local_matrix_type::index_type::non_const_type;
81 using values_type =
typename local_matrix_type::values_type::non_const_type;
83 using impl_scalar_type =
typename Matrix::impl_scalar_type;
84 using ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
85 using mag_type =
typename KokkosKernels::ArithTraits<impl_scalar_type>::magnitudeType;
86 using magATS = KokkosKernels::ArithTraits<mag_type>;
88 using execution_space =
typename Node::execution_space;
89 using memory_space =
typename Node::memory_space;
91 const auto one_Scalar = Teuchos::ScalarTraits<Scalar>::one();
92 const auto one_impl_scalar = ATS::one();
93 const auto zero_impl_scalar = ATS::zero();
94 const auto zero_LO = KokkosKernels::ArithTraits<LocalOrdinal>::zero();
95 const auto one_LO = KokkosKernels::ArithTraits<LocalOrdinal>::one();
96 const auto one_mag = magATS::one();
97 const auto eps_mag = magATS::epsilon();
98 const auto INVALID_GO = Teuchos::OrdinalTraits<GlobalOrdinal>::invalid();
129 Teuchos::FancyOStream& out0 = GetBlackHole();
130 const ParameterList& pL = GetParameterList();
132 bool update_communicators = pL.get<
bool>(
"repartition: enable") && pL.get<
bool>(
"repartition: use subcommunicators");
134 RCP<Matrix> D0 = Get<RCP<Matrix> >(fineLevel,
"D0");
135 RCP<Matrix> Pn = Get<RCP<Matrix> >(coarseLevel,
"Pnodal");
138 RCP<Operator> CoarseNodeMatrix = Get<RCP<Operator> >(coarseLevel,
"NodeAggMatrix");
141 RCP<ParameterList> mm_params = rcp(
new ParameterList);
142 if (pL.isSublist(
"matrixmatrix: kernel params"))
143 mm_params->sublist(
"matrixmatrix: kernel params") = pL.sublist(
"matrixmatrix: kernel params");
148 auto vec_ones = VectorFactory::Build(Pn->getDomainMap(),
false);
149 vec_ones->putScalar(one_Scalar);
150 auto vec_rowsums = VectorFactory::Build(Pn->getRangeMap(),
false);
151 Pn->apply(*vec_ones, *vec_rowsums, Teuchos::NO_TRANS);
153 auto lclPn = Pn->getLocalMatrixDevice();
154 auto lclRowSums = vec_rowsums->getLocalViewDevice(Tpetra::Access::ReadOnly);
156 bool all_entries_ok =
true;
157 Kokkos::parallel_reduce(
158 Kokkos::RangePolicy<execution_space>(0, lclPn.numRows()), KOKKOS_LAMBDA(
const LocalOrdinal rlid,
bool& entries_ok) {
160 entries_ok = entries_ok && (ATS::magnitude(lclRowSums(rlid, 0) - one_impl_scalar) < eps_mag);
163 auto row = lclPn.rowConst(rlid);
165 entries_ok = entries_ok && (ATS::magnitude(row.value(k)-one_impl_scalar) < eps_mag);
167 } }, Kokkos::LAnd<bool>(all_entries_ok));
169 TEUCHOS_TEST_FOR_EXCEPTION(!all_entries_ok, std::runtime_error,
"The prolongator needs to be piecewise constant and all entries need to be 1.");
177 auto isDirichletFineEdge = Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(D0->getRowMap(),
false);
178 auto numFineEdges = isDirichletFineEdge->getMap()->getLocalNumElements();
182 D0_Pn = XMM::Multiply(*D0,
false, *Pn,
false, dummy, GetOStream(
Runtime0),
true,
true);
183 RCP<Matrix> Z = XMM::Multiply(*D0_Pn,
true, *D0_Pn,
false, dummy, GetOStream(
Runtime0),
true,
true);
185 auto rowMap = Z->getRowMap();
186 auto colMap = Z->getColMap();
187 auto lclRowMap = rowMap->getLocalMap();
188 auto lclColMap = colMap->getLocalMap();
189 auto lclZ = Z->getLocalMatrixDevice();
190 auto numLocalRows = lclZ.numRows();
196 auto importer = Z->getCrsGraph()->getImporter();
198 Teuchos::Array<int> Z_col_pids;
199 Kokkos::View<int*, memory_space> Z_col_pids_d;
200 if (!importer.is_null()) {
202 utils.
getPids(*importer, Z_col_pids,
false);
203 Kokkos::View<int*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged> > Z_col_pids_h(Z_col_pids.data(), Z_col_pids.size());
204 Z_col_pids_d = Kokkos::View<int*, memory_space>(
"Z_col_pids_d", Z_col_pids.size());
205 Kokkos::deep_copy(Z_col_pids_d, Z_col_pids_h);
208 int myProcId = rowMap->getComm()->getRank();
211 auto tie_break = KOKKOS_LAMBDA(
int proc0,
int proc1) {
212 if ((proc0 + proc1) % 2 == 1) {
213 return Kokkos::min(proc0, proc1);
215 return Kokkos::max(proc0, proc1);
222 if (clid < numLocalRows) {
225 return (rlid < clid);
228 int otherProcId = Z_col_pids_d(clid);
229 int owner = tie_break(myProcId, otherProcId);
230 return (owner == myProcId);
235 Kokkos::parallel_reduce(
237 auto row = lclZ.rowConst(rlid);
240 auto clid = row.colidx(k);
241 if (add_edge(rlid, clid))
245 numCoarseRegularEdges);
250 using LOMatrix = Tpetra::CrsMatrix<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>;
251 RCP<LOMatrix> D0_LocalOrdinal;
259 using lo_local_matrix_type =
typename LOMatrix::local_matrix_device_type;
261 auto lclGraph = D0->getCrsGraph()->getLocalGraphDevice();
262 Kokkos::View<LocalOrdinal*, memory_space> values(Kokkos::ViewAllocateWithoutInitializing(
"values_LocalOrdinal"), D0->getLocalNumEntries());
264 auto values_scalar = D0->getLocalMatrixDevice().values;
265 Kokkos::parallel_for(
266 "MueLu::ReitzingerPFactory::convert", Kokkos::RangePolicy<execution_space>(0, values.extent(0)), KOKKOS_LAMBDA(
const size_t i) {
267 if (values_scalar(i) == one_impl_scalar)
269 else if (values_scalar(i) == -one_impl_scalar)
271 else if (values_scalar(i) == zero_impl_scalar)
274 Kokkos::abort(
"D0 contains bad values");
277 lo_local_matrix_type lclMatrix(
"D0_LocalOrdinal", D0->getLocalMatrixDevice().numCols(), values, lclGraph);
279 D0_LocalOrdinal = rcp(
new LOMatrix(lclMatrix, toTpetra(D0->getRowMap()), toTpetra(D0->getColMap()), toTpetra(D0->getDomainMap()), toTpetra(D0->getRangeMap())));
282 auto oneVec = Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(D0->getDomainMap(),
false);
283 oneVec->putScalar(KokkosKernels::ArithTraits<LocalOrdinal>::one());
284 D0_LocalOrdinal->apply(*toTpetra(oneVec), *toTpetra(isDirichletFineEdge), Teuchos::NO_TRANS);
286 auto lcl_isDirichletFineEdge = isDirichletFineEdge->getLocalViewDevice(Tpetra::Access::ReadWrite);
287 auto lcl_D0_Pn = D0_Pn->getLocalMatrixDevice();
288 Kokkos::parallel_for(
289 Kokkos::RangePolicy<execution_space>(0, lcl_isDirichletFineEdge.extent(0)), KOKKOS_LAMBDA(
const LocalOrdinal i) {
290 if (ATS::magnitude(ATS::magnitude(lcl_isDirichletFineEdge(i, 0)) - one_mag) > eps_mag) {
292 lcl_isDirichletFineEdge(i, 0) = zero_LO;
295 lcl_isDirichletFineEdge(i, 0) = one_LO;
302 auto numberConnectedFineDirichletEdgesToCoarseNode = Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(D0_Pn->getDomainMap(),
false);
304 auto abs_D0_Pn = LOMatrix(toTpetra(D0_Pn->getCrsGraph()));
305 abs_D0_Pn.fillComplete(toTpetra(D0_Pn->getDomainMap()), toTpetra(D0_Pn->getRangeMap()));
306 abs_D0_Pn.setAllToScalar(KokkosKernels::ArithTraits<LocalOrdinal>::one());
307 abs_D0_Pn.apply(*toTpetra(isDirichletFineEdge), *toTpetra(numberConnectedFineDirichletEdgesToCoarseNode), Teuchos::TRANS);
312 auto lcl_numberConnectedFineDirichletEdgesToCoarseNode = numberConnectedFineDirichletEdgesToCoarseNode->getLocalViewDevice(Tpetra::Access::ReadOnly);
314 Kokkos::parallel_reduce(
315 Kokkos::RangePolicy<execution_space>(0, lcl_numberConnectedFineDirichletEdgesToCoarseNode.extent(0)),
317 if (ATS::magnitude(lcl_numberConnectedFineDirichletEdgesToCoarseNode(i, 0)) > eps_mag) {
321 numCoarseDirichletEdges);
327 MueLu_sumAll(rowMap->getComm(), numCoarseRegularEdges, numGlobalRegularEdges);
328 MueLu_sumAll(rowMap->getComm(), numCoarseDirichletEdges, numGlobalDirichletEdges);
329 GetOStream(
Statistics0) <<
"regular edges: " << numGlobalRegularEdges <<
", Dirichlet edges: " << numGlobalDirichletEdges << std::endl;
332 numCoarseEdges = numCoarseRegularEdges + numCoarseDirichletEdges;
333 rowptr_type rowptr(Kokkos::ViewAllocateWithoutInitializing(
"rowptr D0H"), numCoarseEdges + 1);
335 LocalOrdinal nnz = 2 * numCoarseRegularEdges + numCoarseDirichletEdges;
336 colidx_type colidx(Kokkos::ViewAllocateWithoutInitializing(
"colidx D0H"), nnz);
337 values_type values(Kokkos::ViewAllocateWithoutInitializing(
"values D0H"), nnz);
340 Kokkos::parallel_scan(
341 Kokkos::RangePolicy<execution_space>(0, numLocalRows),
343 auto row = lclZ.rowConst(rlid);
347 auto clid = row.colidx(k);
348 if (add_edge(rlid, clid))
358 auto rgid = lclRowMap.getGlobalElement(rlid);
359 auto rclid = lclColMap.getLocalElement(rgid);
363 auto clid = row.colidx(k);
364 if (add_edge(rlid, clid)) {
365 auto cgid = lclColMap.getGlobalElement(clid);
367 colidx(2 * ne) = rclid;
368 colidx(2 * ne + 1) = clid;
370 values(2 * ne) = -one_impl_scalar;
371 values(2 * ne + 1) = one_impl_scalar;
373 values(2 * ne) = one_impl_scalar;
374 values(2 * ne + 1) = -one_impl_scalar;
386 auto lcl_numberConnectedFineDirichletEdgesToCoarseNode = numberConnectedFineDirichletEdgesToCoarseNode->getLocalViewDevice(Tpetra::Access::ReadOnly);
387 Kokkos::parallel_scan(
388 Kokkos::RangePolicy<execution_space>(0, lcl_numberConnectedFineDirichletEdgesToCoarseNode.extent(0)),
390 if (ATS::magnitude(lcl_numberConnectedFineDirichletEdgesToCoarseNode(agg_lid, 0)) > eps_mag) {
396 colidx(2 * numCoarseRegularEdges + ne) = agg_lid;
397 values(2 * numCoarseRegularEdges + ne) = one_impl_scalar;
399 rowptr(numCoarseRegularEdges + ne) = 2 * numCoarseRegularEdges + ne;
405 auto D0H_rowmap = MapFactory::Build(rowMap->lib(), INVALID_GO, numCoarseEdges, 0, rowMap->getComm());
406 auto lclD0H = local_matrix_type(
"D0H", numCoarseEdges, colMap->getLocalNumElements(), nnz, values, rowptr, colidx);
409 D0H = MatrixFactory::Build(lclD0H, D0H_rowmap, colMap, Z->getDomainMap(), D0H_rowmap);
412 const bool needToBuildPe = (coarseLevel.
IsRequested(
"P",
this) ||
423 RCP<Matrix> D0_Pn_D0HT;
429 int rank = D0->getRowMap()->getComm()->getRank();
431 printf(
"[%d] Level %d Checkpoint #2 Pn = %d/%d/%d/%d D0c = %d/%d/%d/%d D0 = %d/%d/%d/%d\n",rank,fine_level,
432 Pn->getRangeMap()->getComm()->getSize(),
433 Pn->getRowMap()->getComm()->getSize(),
434 Pn->getColMap()->getComm()->getSize(),
435 Pn->getDomainMap()->getComm()->getSize(),
436 D0H->getRangeMap()->getComm()->getSize(),
437 D0H->getRowMap()->getComm()->getSize(),
438 D0H->getColMap()->getComm()->getSize(),
439 D0H->getDomainMap()->getComm()->getSize(),
440 D0->getRangeMap()->getComm()->getSize(),
441 D0->getRowMap()->getComm()->getSize(),
442 D0->getColMap()->getComm()->getSize(),
443 D0->getDomainMap()->getComm()->getSize());
445 D0->getRowMap()->getComm()->barrier();
449 RCP<Matrix> Pn_D0cT = XMM::Multiply(*Pn,
false, *D0H,
true, dummy, out0,
true,
true,
"Pn*D0c'", mm_params);
452 if (!mm_params.is_null()) mm_params->remove(
"importer",
false);
454 D0_Pn_D0HT = XMM::Multiply(*D0,
false, *Pn_D0cT,
false, dummy, out0,
true,
true,
"D0*(Pn*D0c')", mm_params);
461 auto lcl_D0_Pn = D0_Pn->getLocalMatrixDevice();
462 auto lcl_D0_Pn_D0HT = D0_Pn_D0HT->getLocalMatrixDevice();
463 auto lcl_isDirichletFineEdge = isDirichletFineEdge->getLocalViewDevice(Tpetra::Access::ReadOnly);
465 auto lcl_colmap_D0_Pn_D0HT = D0_Pn_D0HT->getColMap()->getLocalMap();
467 const auto half = one_impl_scalar / (one_impl_scalar + one_impl_scalar);
470 rowptr_type Pe_rowptr(
"Pe_rowptr", numFineEdges + 2);
473 Kokkos::parallel_for(
474 "Pe_count_entries", Kokkos::RangePolicy<execution_space>(0, numFineEdges), KOKKOS_LAMBDA(
const LocalOrdinal fineEdge) {
475 if (lcl_isDirichletFineEdge(fineEdge, 0) != one_LO) {
477 auto row = lcl_D0_Pn_D0HT.rowConst(fineEdge);
478 for (
int k = 0; k < row.length; ++k) {
479 auto val = row.value(k);
481 if (!((ATS::magnitude(val - one_impl_scalar) < eps_mag) || (ATS::magnitude(val + one_impl_scalar) < eps_mag) || (ATS::magnitude(val) < eps_mag))) {
483 ++Pe_rowptr(fineEdge + 2);
488 ++Pe_rowptr(fineEdge + 2);
494 Kokkos::parallel_scan(
495 "Pe_prefix_sum", Kokkos::RangePolicy<execution_space>(0, numFineEdges + 2), KOKKOS_LAMBDA(
const LocalOrdinal rlid,
LocalOrdinal& nnz,
const bool update) {
496 nnz += Pe_rowptr(rlid);
498 Pe_rowptr(rlid) = nnz;
504 colidx_type Pe_colidx(
"Pe_colidx", Pe_nnz);
505 values_type Pe_values(
"Pe_values", Pe_nnz);
508 RCP<GOVector> map_coarseNodes_colMap_D0_Pn_to_coarseEdges;
510 auto map_coarseEdges_rowMap_D0H_to_coarseEdges = Xpetra::VectorFactory<GlobalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(D0H->getRowMap());
512 auto lcl_map_coarseEdges_rowMap_D0H_to_coarseEdges = map_coarseEdges_rowMap_D0H_to_coarseEdges->getLocalViewDevice(Tpetra::Access::OverwriteAll);
513 auto lclMap = D0H->getRowMap()->getLocalMap();
514 Kokkos::parallel_for(
515 Kokkos::RangePolicy<execution_space>(numCoarseRegularEdges, numCoarseEdges), KOKKOS_LAMBDA(
const LocalOrdinal coarseEdge) {
516 lcl_map_coarseEdges_rowMap_D0H_to_coarseEdges(coarseEdge, 0) = lclMap.getGlobalElement(coarseEdge);
519 auto map_coarseNodes_domainMap_D0_Pn_to_coarseEdges = Xpetra::VectorFactory<GlobalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(D0H->getDomainMap());
527 using GOMatrix = Tpetra::CrsMatrix<GlobalOrdinal, LocalOrdinal, GlobalOrdinal, Node>;
528 using go_local_matrix_type =
typename GOMatrix::local_matrix_device_type;
530 auto lclGraph = D0H->getCrsGraph()->getLocalGraphDevice();
531 typename go_local_matrix_type::values_type::non_const_type ones(
"ones_GlobalOrdinal", D0H->getLocalNumEntries());
532 const auto one_GO = KokkosKernels::ArithTraits<typename go_local_matrix_type::values_type::value_type>::one();
533 Kokkos::deep_copy(ones, one_GO);
535 go_local_matrix_type lclMatrix(
"D0H_GlobalOrdinal", D0H->getLocalMatrixDevice().numCols(), ones, lclGraph);
537 auto D0H_GlobalOrdinal = GOMatrix(lclMatrix, toTpetra(D0H->getRowMap()), toTpetra(D0H->getColMap()), toTpetra(D0H->getDomainMap()), toTpetra(D0H->getRangeMap()));
538 D0H_GlobalOrdinal.apply(*toTpetra(map_coarseEdges_rowMap_D0H_to_coarseEdges), *toTpetra(map_coarseNodes_domainMap_D0_Pn_to_coarseEdges), Teuchos::TRANS);
541 auto importer = D0_Pn->getCrsGraph()->getImporter();
542 if (!importer.is_null()) {
543 map_coarseNodes_colMap_D0_Pn_to_coarseEdges = Xpetra::VectorFactory<GlobalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(D0_Pn->getColMap());
544 map_coarseNodes_colMap_D0_Pn_to_coarseEdges->doImport(*map_coarseNodes_domainMap_D0_Pn_to_coarseEdges, *importer, Xpetra::INSERT);
546 map_coarseNodes_colMap_D0_Pn_to_coarseEdges = map_coarseNodes_domainMap_D0_Pn_to_coarseEdges;
550 auto lcl_map_coarseNodes_colMap_D0_Pn_to_coarseEdges = map_coarseNodes_colMap_D0_Pn_to_coarseEdges->getLocalViewDevice(Tpetra::Access::ReadOnly);
553 Kokkos::parallel_for(
554 "Pe_fill", Kokkos::RangePolicy<execution_space>(0, numFineEdges), KOKKOS_LAMBDA(
const LocalOrdinal fineEdge_lid) {
555 if (lcl_isDirichletFineEdge(fineEdge_lid, 0) != one_LO) {
557 auto row = lcl_D0_Pn_D0HT.rowConst(fineEdge_lid);
558 for (
int k = 0; k < row.length; ++k) {
559 auto val = row.value(k);
560 if (!((ATS::magnitude(val - one_impl_scalar) < eps_mag) || (ATS::magnitude(val + one_impl_scalar) < eps_mag) || (ATS::magnitude(val) < eps_mag))) {
561 auto clid = row.colidx(k);
563 auto offset = Pe_rowptr(fineEdge_lid + 1);
564 Pe_colidx(offset) = clid;
565 Pe_values(offset) = val * half;
566 ++Pe_rowptr(fineEdge_lid + 1);
572 for (
auto offset_D0_Pn = lcl_D0_Pn.graph.row_map(fineEdge_lid); offset_D0_Pn < lcl_D0_Pn.graph.row_map(fineEdge_lid + 1); ++offset_D0_Pn) {
573 LocalOrdinal coarseNode_lid_D0_Pn = lcl_D0_Pn.graph.entries(offset_D0_Pn);
574 impl_scalar_type val_D0_Pn = lcl_D0_Pn.values(offset_D0_Pn);
575 if (ATS::magnitude(val_D0_Pn) > eps_mag) {
576 GlobalOrdinal coarseEdge_gid = lcl_map_coarseNodes_colMap_D0_Pn_to_coarseEdges(coarseNode_lid_D0_Pn, 0);
578 auto coarseEdge_lid_D0_Pn_D0HT = lcl_colmap_D0_Pn_D0HT.getLocalElement(coarseEdge_gid);
581 const auto val_D0H = one_impl_scalar;
584 auto offset_Pe = Pe_rowptr(fineEdge_lid + 1);
585 Pe_colidx(offset_Pe) = coarseEdge_lid_D0_Pn_D0HT;
586 Pe_values(offset_Pe) = val_D0_Pn / val_D0H;
587 ++Pe_rowptr(fineEdge_lid + 1);
594 auto lclPe = local_matrix_type(
"Pe", numFineEdges, D0_Pn_D0HT->getColMap()->getLocalNumElements(), Pe_nnz, Pe_values, Kokkos::subview(Pe_rowptr, Kokkos::make_pair((
decltype(numFineEdges))0, numFineEdges + 1)), Pe_colidx);
597 Pe = MatrixFactory::Build(lclPe, D0->getRowMap(), D0_Pn_D0HT->getColMap(), D0H->getRangeMap(), D0->getRangeMap());
602 CheckCommutingProperty(*Pe, *D0H, *D0, *Pn);
609 if (update_communicators) {
611 RCP<const Teuchos::Comm<int> > newComm;
612 if (!CoarseNodeMatrix.is_null()) newComm = CoarseNodeMatrix->getDomainMap()->getComm();
613 RCP<const Map> newMap = MapFactory::copyMapWithNewComm(D0H->getRowMap(), newComm);
614 D0H->removeEmptyProcessesInPlace(newMap);
617 if (newMap.is_null()) D0H = Teuchos::null;
619 Set(coarseLevel,
"InPlaceMap", newMap);
624 Set(coarseLevel,
"P", Pe);
626 Set(coarseLevel,
"Ptent", Pe);
628 Set(coarseLevel,
"D0", D0H);
637 int numProcs = Pe->getRowMap()->getComm()->getSize();
640 sprintf(fname,
"Pe_%d_%d.mat", numProcs, fineLevel.
GetLevelID());
641 Xpetra::IO<SC, LO, GO, NO>::Write(fname, *Pe);
642 sprintf(fname,
"Pn_%d_%d.mat", numProcs, fineLevel.
GetLevelID());
643 Xpetra::IO<SC, LO, GO, NO>::Write(fname, *Pn);
644 if (!D0H.is_null()) {
645 sprintf(fname,
"D0c_%d_%d.mat", numProcs, fineLevel.
GetLevelID());
646 Xpetra::IO<SC, LO, GO, NO>::Write(fname, *D0H);
648 sprintf(fname,
"D0f_%d_%d.mat", numProcs, fineLevel.
GetLevelID());
649 Xpetra::IO<SC, LO, GO, NO>::Write(fname, *D0);