87 const Teuchos::ParameterList& pL = GetParameterList();
90 bool remapPartitions = pL.get<
bool>(
"repartition: remap parts");
93 RCP<Matrix> A = Get<RCP<Matrix> >(currentLevel,
"A");
94 if (A == Teuchos::null) {
95 Set<RCP<const Import> >(currentLevel,
"Importer", Teuchos::null);
98 RCP<const Map> rowMap = A->getRowMap();
99 GO indexBase = rowMap->getIndexBase();
100 Xpetra::UnderlyingLib lib = rowMap->lib();
102 RCP<const Teuchos::Comm<int> > origComm = rowMap->getComm();
103 RCP<const Teuchos::Comm<int> > comm = origComm;
105 int numProcs = comm->getSize();
107 RCP<const Teuchos::MpiComm<int> > tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
108 TEUCHOS_TEST_FOR_EXCEPTION(tmpic == Teuchos::null,
Exceptions::RuntimeError,
"Cannot cast base Teuchos::Comm to Teuchos::MpiComm object.");
109 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm();
112 int numPartitions = Get<int>(currentLevel,
"number of partitions");
117 RCP<GOVector> decomposition = Get<RCP<GOVector> >(currentLevel,
"Partition");
120 if (remapPartitions ==
true && Teuchos::rcp_dynamic_cast<const CloneRepartitionInterface>(GetFactory(
"Partition")) != Teuchos::null) {
124 remapPartitions =
false;
128 if (numPartitions == 1) {
133 GetOStream(
Runtime0) <<
"Only one partition: Skip call to the repartitioner." << std::endl;
134 }
else if (numPartitions == -1) {
136 GetOStream(
Runtime0) <<
"No repartitioning necessary: partitions were left unchanged by the repartitioner" << std::endl;
137 Set<RCP<const Import> >(currentLevel,
"Importer", Teuchos::null);
142 const int nodeRepartLevel = pL.get<
int>(
"repartition: node repartition level");
143 if (currentLevel.
GetLevelID() == nodeRepartLevel) {
148 remapPartitions =
false;
188 if (remapPartitions) {
191 bool acceptPartition = pL.get<
bool>(
"repartition: remap accept partition");
192 bool allSubdomainsAcceptPartitions;
193 int localNumAcceptPartition = acceptPartition;
194 int globalNumAcceptPartition;
195 MueLu_sumAll(comm, localNumAcceptPartition, globalNumAcceptPartition);
196 GetOStream(
Statistics2) <<
"Number of ranks that accept partitions: " << globalNumAcceptPartition << std::endl;
197 if (globalNumAcceptPartition < numPartitions) {
198 GetOStream(
Warnings0) <<
"Not enough ranks are willing to accept a partition, allowing partitions on all ranks." << std::endl;
199 acceptPartition =
true;
200 allSubdomainsAcceptPartitions =
true;
201 }
else if (numPartitions > numProcs) {
203 allSubdomainsAcceptPartitions =
true;
205 allSubdomainsAcceptPartitions =
false;
208 DeterminePartitionPlacement(*A, *decomposition, numPartitions, acceptPartition, allSubdomainsAcceptPartitions);
219#ifdef HAVE_MUELU_DEBUG
220 int myRank = comm->getRank();
221 ArrayRCP<const GO> decompEntries;
222 if (decomposition->getLocalLength() > 0)
223 decompEntries = decomposition->getData(0);
226 int incorrectRank = -1;
227 for (
int i = 0; i < decompEntries.size(); i++)
228 if (decompEntries[i] >= numProcs || decompEntries[i] < 0) {
229 incorrectRank = myRank;
233 int incorrectGlobalRank = -1;
235 TEUCHOS_TEST_FOR_EXCEPTION(incorrectGlobalRank > -1,
Exceptions::RuntimeError,
"pid " + Teuchos::toString(incorrectGlobalRank) +
" encountered a partition number is that out-of-range");
243 std::tie(myGIDs, numLocalKept) = Util::ConstructGIDs(decomposition);
246 GO numGlobalKept, numGlobalRows = A->getGlobalNumRows();
248 GetOStream(
Statistics2) <<
"Unmoved rows: " << numGlobalKept <<
" / " << numGlobalRows <<
" (" << 100 * Teuchos::as<double>(numGlobalKept) / numGlobalRows <<
"%)" << std::endl;
256 newRowMap = MapFactory ::Build(lib, rowMap->getGlobalNumElements(), myGIDs(), indexBase, origComm);
259 RCP<const Import> rowMapImporter;
261 RCP<const BlockedMap> blockedRowMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
266 if (blockedRowMap.is_null())
267 rowMapImporter = ImportFactory::Build(rowMap, newRowMap);
269 rowMapImporter = ImportFactory::Build(blockedRowMap->getMap(), newRowMap);
274 if (!blockedRowMap.is_null()) {
280 size_t numBlocks = blockedRowMap->getNumMaps();
281 std::vector<RCP<const Import> > subImports(numBlocks);
283 for (
size_t i = 0; i < numBlocks; i++) {
284 RCP<const Map> source = blockedRowMap->getMap(i);
285 RCP<const Map> target = blockedTargetMap->getMap(i);
286 subImports[i] = ImportFactory::Build(source, target);
288 Set(currentLevel,
"SubImporters", subImports);
291 Set(currentLevel,
"Importer", rowMapImporter);
294 bool save_importer = pL.get<
bool>(
"repartition: save importer");
303 if (!rowMapImporter.is_null() && IsPrint(
Statistics2)) {
308 if (pL.get<
bool>(
"repartition: print partition distribution") && IsPrint(
Statistics2)) {
310 GetOStream(
Statistics2) <<
"Partition distribution over cores (ownership is indicated by '+')" << std::endl;
312 char amActive = (myGIDs.size() ? 1 : 0);
313 std::vector<char> areActive(numProcs, 0);
314 MPI_Gather(&amActive, 1, MPI_CHAR, &areActive[0], 1, MPI_CHAR, 0, *rawMpiComm);
316 int rowWidth = std::min(Teuchos::as<int>(ceil(sqrt(numProcs))), 100);
317 for (
int proc = 0; proc < numProcs; proc += rowWidth) {
318 for (
int j = 0; j < rowWidth; j++)
319 if (proc + j < numProcs)
320 GetOStream(
Statistics2) << (areActive[proc + j] ?
"+" :
".");
324 GetOStream(
Statistics2) <<
" " << proc <<
":" << std::min(proc + rowWidth, numProcs) - 1 << std::endl;
343 DeterminePartitionPlacement(
const Matrix& A, GOVector& decomposition, GO numPartitions,
bool willAcceptPartition,
bool allSubdomainsAcceptPartitions)
const {
344 RCP<const Map> rowMap = A.getRowMap();
346 RCP<const Teuchos::Comm<int> > comm = rowMap->getComm()->duplicate();
347 int numProcs = comm->getSize();
349 RCP<const Teuchos::MpiComm<int> > tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
350 TEUCHOS_TEST_FOR_EXCEPTION(tmpic == Teuchos::null,
Exceptions::RuntimeError,
"Cannot cast base Teuchos::Comm to Teuchos::MpiComm object.");
351 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm();
353 const Teuchos::ParameterList& pL = GetParameterList();
359 const int maxLocal = pL.get<
int>(
"repartition: remap num values");
360 const int dataSize = 2 * maxLocal;
362 ArrayRCP<GO> decompEntries;
363 if (decomposition.getLocalLength() > 0)
364 decompEntries = decomposition.getDataNonConst(0);
376 std::map<GO, GO> lEdges;
377 if (willAcceptPartition)
378 for (LO i = 0; i < decompEntries.size(); i++)
379 lEdges[decompEntries[i]] += A.getNumEntriesInLocalRow(i);
383 std::multimap<GO, GO> revlEdges;
384 for (
typename std::map<GO, GO>::const_iterator it = lEdges.begin(); it != lEdges.end(); it++)
385 revlEdges.insert(std::make_pair(it->second, it->first));
390 Array<GO> lData(dataSize, -1), gData(numProcs * dataSize);
392 for (
typename std::multimap<GO, GO>::reverse_iterator rit = revlEdges.rbegin(); rit != revlEdges.rend() && numEdges < maxLocal; rit++) {
393 lData[2 * numEdges + 0] = rit->second;
394 lData[2 * numEdges + 1] = rit->first;
400 MPI_Datatype MpiType = Teuchos::Details::MpiTypeTraits<GO>::getType();
401 MPI_Allgather(
static_cast<void*
>(lData.getRawPtr()), dataSize, MpiType,
static_cast<void*
>(gData.getRawPtr()), dataSize, MpiType, *rawMpiComm);
406 Teuchos::Array<Triplet<int, int> > gEdges(numProcs * maxLocal);
407 Teuchos::Array<bool> procWillAcceptPartition(numProcs, allSubdomainsAcceptPartitions);
409 for (LO i = 0; i < gData.size(); i += 2) {
410 int procNo = i / dataSize;
411 GO part = gData[i + 0];
412 GO weight = gData[i + 1];
414 gEdges[k].i = procNo;
416 gEdges[k].v = weight;
417 procWillAcceptPartition[procNo] =
true;
425 std::sort(gEdges.begin(), gEdges.end(), compareTriplets<int, int>);
428 std::map<int, int> match;
429 Teuchos::Array<char> matchedRanks(numProcs, 0), matchedParts(numPartitions, 0);
431 for (
typename Teuchos::Array<
Triplet<int, int> >::const_iterator it = gEdges.begin(); it != gEdges.end(); it++) {
434 if (matchedRanks[rank] == 0 && matchedParts[part] == 0) {
435 matchedRanks[rank] = 1;
436 matchedParts[part] = 1;
441 GetOStream(
Statistics1) <<
"Number of unassigned partitions before cleanup stage: " << (numPartitions - numMatched) <<
" / " << numPartitions << std::endl;
448 if (numPartitions - numMatched > 0) {
449 Teuchos::Array<char> partitionCounts(numPartitions, 0);
450 for (
typename std::map<int, int>::const_iterator it = match.begin(); it != match.end(); it++)
451 partitionCounts[it->first] += 1;
452 for (
int part = 0, matcher = 0; part < numPartitions; part++) {
453 if (partitionCounts[part] == 0) {
455 while (matchedRanks[matcher] || !procWillAcceptPartition[matcher])
458 match[part] = matcher++;
464 TEUCHOS_TEST_FOR_EXCEPTION(numMatched != numPartitions,
Exceptions::RuntimeError,
"MueLu::RepartitionFactory::DeterminePartitionPlacement: Only " << numMatched <<
" partitions out of " << numPartitions <<
" got assigned to ranks.");
467 for (LO i = 0; i < decompEntries.size(); i++)
468 decompEntries[i] = match[decompEntries[i]];