MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_Zoltan2Interface_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_ZOLTAN2INTERFACE_DEF_HPP
11#define MUELU_ZOLTAN2INTERFACE_DEF_HPP
12
13#include <sstream>
14#include <set>
15
17#if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
18
19#include <Zoltan2_XpetraMultiVectorAdapter.hpp>
20#include <Zoltan2_XpetraCrsGraphAdapter.hpp>
21#include <Zoltan2_PartitioningProblem.hpp>
22
23#include <Teuchos_Utils.hpp>
24#include <Teuchos_DefaultMpiComm.hpp>
25#include <Teuchos_OpaqueWrapper.hpp>
26
27#include "MueLu_Level.hpp"
28#include "MueLu_Exceptions.hpp"
29#include "MueLu_Monitor.hpp"
30#include "MueLu_Behavior.hpp"
31
32namespace MueLu {
33
34template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
36 defaultZoltan2Params = rcp(new ParameterList());
37 defaultZoltan2Params->set("algorithm", "multijagged");
38 defaultZoltan2Params->set("partitioning_approach", "partition");
39
40 // Improve scaling for communication bound algorithms by premigrating
41 // coordinates to a subset of processors.
42 // For more information, see Github issue #1538
43 defaultZoltan2Params->set("mj_premigration_option", 1);
44}
45
46template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
48 RCP<ParameterList> validParamList = rcp(new ParameterList());
49
50 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
51 validParamList->set<RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
52 validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
53 validParamList->set<RCP<const ParameterList> >("ParameterList", Teuchos::null, "Zoltan2 parameters");
54 validParamList->set<RCP<const FactoryBase> >("repartition: heuristic target rows per process", Teuchos::null, "Factory for number of rows per process to use with MultiJagged");
55
56 return validParamList;
57}
58
59template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
61 Input(currentLevel, "A");
62 Input(currentLevel, "number of partitions");
63 const ParameterList& pL = GetParameterList();
64 // We do this dance, because we don't want "ParameterList" to be marked as used.
65 // Is there a better way?
66 Teuchos::ParameterEntry entry = pL.getEntry("ParameterList");
67 RCP<const Teuchos::ParameterList> providedList = Teuchos::any_cast<RCP<const Teuchos::ParameterList> >(entry.getAny(false));
68 if (providedList != Teuchos::null && providedList->isType<std::string>("algorithm")) {
69 const std::string algo = providedList->get<std::string>("algorithm");
70 if (algo == "multijagged") {
71 Input(currentLevel, "Coordinates");
72 Input(currentLevel, "repartition: heuristic target rows per process");
73 } else if (algo == "rcb") {
74 Input(currentLevel, "Coordinates");
75 }
76 } else {
77 Input(currentLevel, "repartition: heuristic target rows per process");
78 Input(currentLevel, "Coordinates");
79 }
80}
81
82template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
84 FactoryMonitor m(*this, "Build", level);
85
86 typedef typename Teuchos::ScalarTraits<SC>::coordinateType real_type;
87 typedef typename Xpetra::MultiVector<real_type, LO, GO, NO> RealValuedMultiVector;
89
90 RCP<Matrix> A = Get<RCP<Matrix> >(level, "A");
91
92 int numParts = Get<int>(level, "number of partitions");
93 if (numParts == 1 || numParts == -1) {
94 // Single processor, decomposition is trivial: all zeros
95 RCP<const Map> rowMap = A->getRowMap();
96 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
97 Set(level, "Partition", decomposition);
98 return;
99 } /* else if (numParts == -1) {
100 // No repartitioning
101 RCP<Xpetra::Vector<GO,LO,GO,NO> > decomposition = Teuchos::null; //Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
102 //decomposition->putScalar(Teuchos::as<Scalar>(rowMap->getComm()->getRank()));
103 Set(level, "Partition", decomposition);
104 return;
105 }*/
106
107 const ParameterList& pL = GetParameterList();
108
109 RCP<const ParameterList> providedList = pL.get<RCP<const ParameterList> >("ParameterList");
110 ParameterList Zoltan2Params;
111 if (providedList != Teuchos::null)
112 Zoltan2Params = *providedList;
113
114 // Merge defalt Zoltan2 parameters with user provided
115 // If default and user parameters contain the same parameter name, user one is always preferred
116 for (ParameterList::ConstIterator param = defaultZoltan2Params->begin(); param != defaultZoltan2Params->end(); param++) {
117 const std::string& pName = defaultZoltan2Params->name(param);
118 if (!Zoltan2Params.isParameter(pName))
119 Zoltan2Params.setEntry(pName, defaultZoltan2Params->getEntry(pName));
120 }
121 Zoltan2Params.set("num_global_parts", Teuchos::as<int>(numParts));
122
123 const std::string& algo = Zoltan2Params.get<std::string>("algorithm");
124
125 if (algo == "multijagged" && !Zoltan2Params.isParameter("mj_premigration_coordinate_count")) {
126 LO heuristicTargetRowsPerProcess = Get<LO>(level, "repartition: heuristic target rows per process");
127 Zoltan2Params.set("mj_premigration_coordinate_count", heuristicTargetRowsPerProcess);
128 }
129
130 GetOStream(Runtime0) << "Zoltan2 parameters:\n----------\n"
131 << Zoltan2Params << "----------" << std::endl;
132
133 RCP<RealValuedMultiVector> coords;
134
135 if (algo == "multijagged" || algo == "rcb")
136 coords = Get<RCP<RealValuedMultiVector> >(level, "Coordinates");
137
138 const std::string debuggingFile = "mj_debug.lvl_" + std::to_string(level.GetLevelID());
139 RCP<typename Util::GOVector> decomposition;
140 {
141 SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
142 decomposition = Util::ComputeDecomposition(numParts, A, coords, Zoltan2Params, debuggingFile);
143 }
144
145 Set(level, "Partition", decomposition);
146}
147
148template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
149RCP<typename Zoltan2Utilities<Scalar, LocalOrdinal, GlobalOrdinal, Node>::GOVector>
150Zoltan2Utilities<Scalar, LocalOrdinal, GlobalOrdinal, Node>::ComputeDecomposition(int numPartitions, RCP<Matrix>& A, RCP<RealValuedMultiVector> coords, Teuchos::ParameterList& Zoltan2Params, std::string debuggingFile) {
151 Zoltan2Params.set("num_global_parts", numPartitions);
152
153 RCP<const Map> rowMap = A->getRowMap();
154 LO blkSize = A->GetFixedBlockSize();
155
156 const std::string& algo = Zoltan2Params.get<std::string>("algorithm");
157
158 if (algo == "multijagged" || algo == "rcb") {
159 TEUCHOS_ASSERT(coords);
160 RCP<const Map> map = coords->getMap();
161 GO numElements = map->getLocalNumElements();
162
163 // Check that the number of local coordinates is consistent with the #rows in A
164 TEUCHOS_TEST_FOR_EXCEPTION(rowMap->getLocalNumElements() / blkSize != coords->getLocalLength(), Exceptions::Incompatible,
165 "Coordinate vector length (" + toString(coords->getLocalLength()) << " is incompatible with number of block rows in A (" + toString(rowMap->getLocalNumElements() / blkSize) + "The vector length should be the same as the number of mesh points.");
166 if (Behavior::debug()) {
167 GO indexBase = rowMap->getIndexBase();
168 // Make sure that logical blocks in row map coincide with logical nodes in coordinates map
169 ArrayView<const GO> rowElements = rowMap->getLocalElementList();
170 ArrayView<const GO> coordsElements = map->getLocalElementList();
171 for (LO i = 0; i < Teuchos::as<LO>(numElements); i++)
172 TEUCHOS_TEST_FOR_EXCEPTION((coordsElements[i] - indexBase) * blkSize + indexBase != rowElements[i * blkSize],
173 Exceptions::RuntimeError, "i = " << i << ", coords GID = " << coordsElements[i] << ", row GID = " << rowElements[i * blkSize] << ", blkSize = " << blkSize << std::endl);
174 }
175
176 typedef Zoltan2::XpetraMultiVectorAdapter<RealValuedMultiVector> InputAdapterType;
177 typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
178
179 Array<real_type> weightsPerRow(numElements);
180 for (LO i = 0; i < numElements; i++) {
181 weightsPerRow[i] = 0.0;
182
183 for (LO j = 0; j < blkSize; j++) {
184 weightsPerRow[i] += A->getNumEntriesInLocalRow(i * blkSize + j);
185 }
186 }
187
188 const bool writeZoltan2DebuggingFiles = Zoltan2Params.get("mj_debug", false);
189 Zoltan2Params.remove("mj_debug");
190
191 std::vector<int> strides;
192 std::vector<const real_type*> weights(1, weightsPerRow.getRawPtr());
193
194 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
195 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
196
197 InputAdapterType adapter(coords, weights, strides);
198 RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
199
200 {
201 if (writeZoltan2DebuggingFiles)
202 adapter.generateFiles(debuggingFile.c_str(), *(rowMap->getComm()));
203 problem->solve();
204 }
205
206 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false);
207 ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
208
209 const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
210
211 for (GO i = 0; i < numElements; i++) {
212 int partNum = parts[i];
213
214 for (LO j = 0; j < blkSize; j++)
215 decompEntries[i * blkSize + j] = partNum;
216 }
217
218 return decomposition;
219 }
220
221 GO numElements = rowMap->getLocalNumElements();
222
223 typedef Zoltan2::XpetraCrsGraphAdapter<CrsGraph> InputAdapterType;
224 typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
225
226 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
227 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
228
229 InputAdapterType adapter(A->getCrsGraph());
230 RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
231
232 problem->solve();
233
234 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false);
235 ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
236
237 const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
238
239 // For blkSize > 1, ignore solution for every row but the first ones in a block.
240 for (GO i = 0; i < numElements / blkSize; i++) {
241 int partNum = parts[i * blkSize];
242
243 for (LO j = 0; j < blkSize; j++)
244 decompEntries[i * blkSize + j] = partNum;
245 }
246
247 return decomposition;
248}
249
250} // namespace MueLu
251
252#endif // if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
253
254#endif // MUELU_ZOLTAN2INTERFACE_DEF_HPP
static bool debug()
Whether MueLu is in debug mode.
Exception throws to report incompatible objects (like maps).
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
Class that holds all level-specific information.
int GetLevelID() const
Return level number.
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
void DeclareInput(Level &currentLevel) const
Specifies the data that this class needs, and the factories that generate that data.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void Build(Level &currentLevel) const
Build an object with this factory.
Namespace for MueLu classes and methods.
@ Runtime0
One-liner description of what is happening.
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
static RCP< GOVector > ComputeDecomposition(int numPartitions, RCP< Matrix > &A, RCP< RealValuedMultiVector > coords, Teuchos::ParameterList &Zoltan2Params, std::string debuggingFile="")