83 const Teuchos::ParameterList& pL = GetParameterList();
86 bool remapPartitions = pL.get<
bool>(
"repartition: remap parts");
89 RCP<Matrix> A = Get<RCP<Matrix> >(currentLevel,
"A");
90 if (A == Teuchos::null) {
91 Set<RCP<const Import> >(currentLevel,
"Importer", Teuchos::null);
94 RCP<const Map> rowMap = A->getRowMap();
95 GO indexBase = rowMap->getIndexBase();
96 Xpetra::UnderlyingLib lib = rowMap->lib();
98 RCP<const Teuchos::Comm<int> > origComm = rowMap->getComm();
99 RCP<const Teuchos::Comm<int> > comm = origComm;
101 int myRank = comm->getRank();
102 int numProcs = comm->getSize();
104 RCP<const Teuchos::MpiComm<int> > tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
105 TEUCHOS_TEST_FOR_EXCEPTION(tmpic == Teuchos::null,
Exceptions::RuntimeError,
"Cannot cast base Teuchos::Comm to Teuchos::MpiComm object.");
106 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm();
109 int numPartitions = Get<int>(currentLevel,
"number of partitions");
114 RCP<GOVector> decomposition = Get<RCP<GOVector> >(currentLevel,
"Partition");
117 if (remapPartitions ==
true && Teuchos::rcp_dynamic_cast<const CloneRepartitionInterface>(GetFactory(
"Partition")) != Teuchos::null) {
121 remapPartitions =
false;
125 if (numPartitions == 1) {
130 GetOStream(
Runtime0) <<
"Only one partition: Skip call to the repartitioner." << std::endl;
131 }
else if (numPartitions == -1) {
133 GetOStream(
Runtime0) <<
"No repartitioning necessary: partitions were left unchanged by the repartitioner" << std::endl;
134 Set<RCP<const Import> >(currentLevel,
"Importer", Teuchos::null);
139 const int nodeRepartLevel = pL.get<
int>(
"repartition: node repartition level");
140 if (currentLevel.
GetLevelID() == nodeRepartLevel) {
145 remapPartitions =
false;
185 if (remapPartitions) {
188 bool acceptPartition = pL.get<
bool>(
"repartition: remap accept partition");
189 bool allSubdomainsAcceptPartitions;
190 int localNumAcceptPartition = acceptPartition;
191 int globalNumAcceptPartition;
192 MueLu_sumAll(comm, localNumAcceptPartition, globalNumAcceptPartition);
193 GetOStream(
Statistics2) <<
"Number of ranks that accept partitions: " << globalNumAcceptPartition << std::endl;
194 if (globalNumAcceptPartition < numPartitions) {
195 GetOStream(
Warnings0) <<
"Not enough ranks are willing to accept a partition, allowing partitions on all ranks." << std::endl;
196 acceptPartition =
true;
197 allSubdomainsAcceptPartitions =
true;
198 }
else if (numPartitions > numProcs) {
200 allSubdomainsAcceptPartitions =
true;
202 allSubdomainsAcceptPartitions =
false;
205 DeterminePartitionPlacement(*A, *decomposition, numPartitions, acceptPartition, allSubdomainsAcceptPartitions);
216 ArrayRCP<const GO> decompEntries;
217 if (decomposition->getLocalLength() > 0)
218 decompEntries = decomposition->getData(0);
220#ifdef HAVE_MUELU_DEBUG
222 int incorrectRank = -1;
223 for (
int i = 0; i < decompEntries.size(); i++)
224 if (decompEntries[i] >= numProcs || decompEntries[i] < 0) {
225 incorrectRank = myRank;
229 int incorrectGlobalRank = -1;
231 TEUCHOS_TEST_FOR_EXCEPTION(incorrectGlobalRank > -1,
Exceptions::RuntimeError,
"pid " + Teuchos::toString(incorrectGlobalRank) +
" encountered a partition number is that out-of-range");
235 myGIDs.reserve(decomposition->getLocalLength());
240 typedef std::map<GO, Array<GO> > map_type;
242 for (LO i = 0; i < decompEntries.size(); i++) {
243 GO
id = decompEntries[i];
244 GO GID = rowMap->getGlobalElement(i);
247 myGIDs.push_back(GID);
249 sendMap[id].push_back(GID);
251 decompEntries = Teuchos::null;
254 GO numLocalKept = myGIDs.size(), numGlobalKept, numGlobalRows = A->getGlobalNumRows();
256 GetOStream(
Statistics2) <<
"Unmoved rows: " << numGlobalKept <<
" / " << numGlobalRows <<
" (" << 100 * Teuchos::as<double>(numGlobalKept) / numGlobalRows <<
"%)" << std::endl;
259 int numSend = sendMap.size(), numRecv;
262 Array<GO> myParts(numSend), myPart(1);
265 for (
typename map_type::const_iterator it = sendMap.begin(); it != sendMap.end(); it++)
266 myParts[cnt++] = it->first;
272 GO partsIndexBase = 0;
273 RCP<Map> partsIHave = MapFactory ::Build(lib, Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), myParts(), partsIndexBase, comm);
274 RCP<Map> partsIOwn = MapFactory ::Build(lib, numProcs, myPart(), partsIndexBase, comm);
275 RCP<Export> partsExport = ExportFactory::Build(partsIHave, partsIOwn);
277 RCP<GOVector> partsISend = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(partsIHave);
278 RCP<GOVector> numPartsIRecv = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(partsIOwn);
280 ArrayRCP<GO> partsISendData = partsISend->getDataNonConst(0);
281 for (
int i = 0; i < numSend; i++)
282 partsISendData[i] = 1;
284 (numPartsIRecv->getDataNonConst(0))[0] = 0;
286 numPartsIRecv->doExport(*partsISend, *partsExport, Xpetra::ADD);
287 numRecv = (numPartsIRecv->getData(0))[0];
291 MPI_Datatype MpiType = Teuchos::Details::MpiTypeTraits<GO>::getType();
295 Array<MPI_Request> sendReqs(numSend);
297 for (
typename map_type::iterator it = sendMap.begin(); it != sendMap.end(); it++)
298 MPI_Isend(
static_cast<void*
>(it->second.getRawPtr()), it->second.size(), MpiType, Teuchos::as<GO>(it->first), msgTag, *rawMpiComm, &sendReqs[cnt++]);
301 size_t totalGIDs = myGIDs.size();
302 for (
int i = 0; i < numRecv; i++) {
304 MPI_Probe(MPI_ANY_SOURCE, msgTag, *rawMpiComm, &status);
307 int fromRank = status.MPI_SOURCE, count;
308 MPI_Get_count(&status, MpiType, &count);
310 recvMap[fromRank].resize(count);
311 MPI_Recv(
static_cast<void*
>(recvMap[fromRank].getRawPtr()), count, MpiType, fromRank, msgTag, *rawMpiComm, &status);
318 Array<MPI_Status> sendStatuses(numSend);
319 MPI_Waitall(numSend, sendReqs.getRawPtr(), sendStatuses.getRawPtr());
323 myGIDs.reserve(totalGIDs);
324 for (
typename map_type::const_iterator it = recvMap.begin(); it != recvMap.end(); it++) {
325 int offset = myGIDs.size(), len = it->second.size();
327 myGIDs.resize(offset + len);
328 memcpy(myGIDs.getRawPtr() + offset, it->second.getRawPtr(), len *
sizeof(GO));
333 std::sort(myGIDs.begin(), myGIDs.end());
339 newRowMap = MapFactory ::Build(lib, rowMap->getGlobalNumElements(), myGIDs(), indexBase, origComm);
342 RCP<const Import> rowMapImporter;
344 RCP<const BlockedMap> blockedRowMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
349 if (blockedRowMap.is_null())
350 rowMapImporter = ImportFactory::Build(rowMap, newRowMap);
352 rowMapImporter = ImportFactory::Build(blockedRowMap->getMap(), newRowMap);
357 if (!blockedRowMap.is_null()) {
363 size_t numBlocks = blockedRowMap->getNumMaps();
364 std::vector<RCP<const Import> > subImports(numBlocks);
366 for (
size_t i = 0; i < numBlocks; i++) {
367 RCP<const Map> source = blockedRowMap->getMap(i);
368 RCP<const Map> target = blockedTargetMap->getMap(i);
369 subImports[i] = ImportFactory::Build(source, target);
371 Set(currentLevel,
"SubImporters", subImports);
374 Set(currentLevel,
"Importer", rowMapImporter);
377 bool save_importer = pL.get<
bool>(
"repartition: save importer");
386 if (!rowMapImporter.is_null() && IsPrint(
Statistics2)) {
391 if (pL.get<
bool>(
"repartition: print partition distribution") && IsPrint(
Statistics2)) {
393 GetOStream(
Statistics2) <<
"Partition distribution over cores (ownership is indicated by '+')" << std::endl;
395 char amActive = (myGIDs.size() ? 1 : 0);
396 std::vector<char> areActive(numProcs, 0);
397 MPI_Gather(&amActive, 1, MPI_CHAR, &areActive[0], 1, MPI_CHAR, 0, *rawMpiComm);
399 int rowWidth = std::min(Teuchos::as<int>(ceil(sqrt(numProcs))), 100);
400 for (
int proc = 0; proc < numProcs; proc += rowWidth) {
401 for (
int j = 0; j < rowWidth; j++)
402 if (proc + j < numProcs)
403 GetOStream(
Statistics2) << (areActive[proc + j] ?
"+" :
".");
407 GetOStream(
Statistics2) <<
" " << proc <<
":" << std::min(proc + rowWidth, numProcs) - 1 << std::endl;
426 DeterminePartitionPlacement(
const Matrix& A, GOVector& decomposition, GO numPartitions,
bool willAcceptPartition,
bool allSubdomainsAcceptPartitions)
const {
427 RCP<const Map> rowMap = A.getRowMap();
429 RCP<const Teuchos::Comm<int> > comm = rowMap->getComm()->duplicate();
430 int numProcs = comm->getSize();
432 RCP<const Teuchos::MpiComm<int> > tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
433 TEUCHOS_TEST_FOR_EXCEPTION(tmpic == Teuchos::null,
Exceptions::RuntimeError,
"Cannot cast base Teuchos::Comm to Teuchos::MpiComm object.");
434 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm();
436 const Teuchos::ParameterList& pL = GetParameterList();
442 const int maxLocal = pL.get<
int>(
"repartition: remap num values");
443 const int dataSize = 2 * maxLocal;
445 ArrayRCP<GO> decompEntries;
446 if (decomposition.getLocalLength() > 0)
447 decompEntries = decomposition.getDataNonConst(0);
459 std::map<GO, GO> lEdges;
460 if (willAcceptPartition)
461 for (LO i = 0; i < decompEntries.size(); i++)
462 lEdges[decompEntries[i]] += A.getNumEntriesInLocalRow(i);
466 std::multimap<GO, GO> revlEdges;
467 for (
typename std::map<GO, GO>::const_iterator it = lEdges.begin(); it != lEdges.end(); it++)
468 revlEdges.insert(std::make_pair(it->second, it->first));
473 Array<GO> lData(dataSize, -1), gData(numProcs * dataSize);
475 for (
typename std::multimap<GO, GO>::reverse_iterator rit = revlEdges.rbegin(); rit != revlEdges.rend() && numEdges < maxLocal; rit++) {
476 lData[2 * numEdges + 0] = rit->second;
477 lData[2 * numEdges + 1] = rit->first;
483 MPI_Datatype MpiType = Teuchos::Details::MpiTypeTraits<GO>::getType();
484 MPI_Allgather(
static_cast<void*
>(lData.getRawPtr()), dataSize, MpiType,
static_cast<void*
>(gData.getRawPtr()), dataSize, MpiType, *rawMpiComm);
489 Teuchos::Array<Triplet<int, int> > gEdges(numProcs * maxLocal);
490 Teuchos::Array<bool> procWillAcceptPartition(numProcs, allSubdomainsAcceptPartitions);
492 for (LO i = 0; i < gData.size(); i += 2) {
493 int procNo = i / dataSize;
494 GO part = gData[i + 0];
495 GO weight = gData[i + 1];
497 gEdges[k].i = procNo;
499 gEdges[k].v = weight;
500 procWillAcceptPartition[procNo] =
true;
508 std::sort(gEdges.begin(), gEdges.end(), compareTriplets<int, int>);
511 std::map<int, int> match;
512 Teuchos::Array<char> matchedRanks(numProcs, 0), matchedParts(numPartitions, 0);
514 for (
typename Teuchos::Array<
Triplet<int, int> >::const_iterator it = gEdges.begin(); it != gEdges.end(); it++) {
517 if (matchedRanks[rank] == 0 && matchedParts[part] == 0) {
518 matchedRanks[rank] = 1;
519 matchedParts[part] = 1;
524 GetOStream(
Statistics1) <<
"Number of unassigned partitions before cleanup stage: " << (numPartitions - numMatched) <<
" / " << numPartitions << std::endl;
531 if (numPartitions - numMatched > 0) {
532 Teuchos::Array<char> partitionCounts(numPartitions, 0);
533 for (
typename std::map<int, int>::const_iterator it = match.begin(); it != match.end(); it++)
534 partitionCounts[it->first] += 1;
535 for (
int part = 0, matcher = 0; part < numPartitions; part++) {
536 if (partitionCounts[part] == 0) {
538 while (matchedRanks[matcher] || !procWillAcceptPartition[matcher])
541 match[part] = matcher++;
547 TEUCHOS_TEST_FOR_EXCEPTION(numMatched != numPartitions,
Exceptions::RuntimeError,
"MueLu::RepartitionFactory::DeterminePartitionPlacement: Only " << numMatched <<
" partitions out of " << numPartitions <<
" got assigned to ranks.");
550 for (LO i = 0; i < decompEntries.size(); i++)
551 decompEntries[i] = match[decompEntries[i]];