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
31namespace MueLu {
32
33template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
35 defaultZoltan2Params = rcp(new ParameterList());
36 defaultZoltan2Params->set("algorithm", "multijagged");
37 defaultZoltan2Params->set("partitioning_approach", "partition");
38
39 // Improve scaling for communication bound algorithms by premigrating
40 // coordinates to a subset of processors.
41 // For more information, see Github issue #1538
42 defaultZoltan2Params->set("mj_premigration_option", 1);
43}
44
45template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
47 RCP<ParameterList> validParamList = rcp(new ParameterList());
48
49 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
50 validParamList->set<RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
51 validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
52 validParamList->set<RCP<const ParameterList> >("ParameterList", Teuchos::null, "Zoltan2 parameters");
53 validParamList->set<RCP<const FactoryBase> >("repartition: heuristic target rows per process", Teuchos::null, "Factory for number of rows per process to use with MultiJagged");
54
55 return validParamList;
56}
57
58template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
60 Input(currentLevel, "A");
61 Input(currentLevel, "number of partitions");
62 const ParameterList& pL = GetParameterList();
63 // We do this dance, because we don't want "ParameterList" to be marked as used.
64 // Is there a better way?
65 Teuchos::ParameterEntry entry = pL.getEntry("ParameterList");
66 RCP<const Teuchos::ParameterList> providedList = Teuchos::any_cast<RCP<const Teuchos::ParameterList> >(entry.getAny(false));
67 if (providedList != Teuchos::null && providedList->isType<std::string>("algorithm")) {
68 const std::string algo = providedList->get<std::string>("algorithm");
69 if (algo == "multijagged") {
70 Input(currentLevel, "Coordinates");
71 Input(currentLevel, "repartition: heuristic target rows per process");
72 } else if (algo == "rcb") {
73 Input(currentLevel, "Coordinates");
74 }
75 } else {
76 Input(currentLevel, "repartition: heuristic target rows per process");
77 Input(currentLevel, "Coordinates");
78 }
79}
80
81template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
83 FactoryMonitor m(*this, "Build", level);
84
85 typedef typename Teuchos::ScalarTraits<SC>::coordinateType real_type;
86 typedef typename Xpetra::MultiVector<real_type, LO, GO, NO> RealValuedMultiVector;
87
88 RCP<Matrix> A = Get<RCP<Matrix> >(level, "A");
89 RCP<const Map> rowMap = A->getRowMap();
90 LO blkSize = A->GetFixedBlockSize();
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<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
96 Set(level, "Partition", decomposition);
97 return;
98 } /* else if (numParts == -1) {
99 // No repartitioning
100 RCP<Xpetra::Vector<GO,LO,GO,NO> > decomposition = Teuchos::null; //Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
101 //decomposition->putScalar(Teuchos::as<Scalar>(rowMap->getComm()->getRank()));
102 Set(level, "Partition", decomposition);
103 return;
104 }*/
105
106 const ParameterList& pL = GetParameterList();
107
108 RCP<const ParameterList> providedList = pL.get<RCP<const ParameterList> >("ParameterList");
109 ParameterList Zoltan2Params;
110 if (providedList != Teuchos::null)
111 Zoltan2Params = *providedList;
112
113 // Merge defalt Zoltan2 parameters with user provided
114 // If default and user parameters contain the same parameter name, user one is always preferred
115 for (ParameterList::ConstIterator param = defaultZoltan2Params->begin(); param != defaultZoltan2Params->end(); param++) {
116 const std::string& pName = defaultZoltan2Params->name(param);
117 if (!Zoltan2Params.isParameter(pName))
118 Zoltan2Params.setEntry(pName, defaultZoltan2Params->getEntry(pName));
119 }
120 Zoltan2Params.set("num_global_parts", Teuchos::as<int>(numParts));
121
122 GetOStream(Runtime0) << "Zoltan2 parameters:\n----------\n"
123 << Zoltan2Params << "----------" << std::endl;
124
125 const std::string& algo = Zoltan2Params.get<std::string>("algorithm");
126
127 if (algo == "multijagged" || algo == "rcb") {
128 RCP<RealValuedMultiVector> coords = Get<RCP<RealValuedMultiVector> >(level, "Coordinates");
129 RCP<const Map> map = coords->getMap();
130 GO numElements = map->getLocalNumElements();
131
132 // Check that the number of local coordinates is consistent with the #rows in A
133 TEUCHOS_TEST_FOR_EXCEPTION(rowMap->getLocalNumElements() / blkSize != coords->getLocalLength(), Exceptions::Incompatible,
134 "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.");
135#ifdef HAVE_MUELU_DEBUG
136 GO indexBase = rowMap->getIndexBase();
137 GetOStream(Runtime0) << "Checking consistence of row and coordinates maps" << std::endl;
138 // Make sure that logical blocks in row map coincide with logical nodes in coordinates map
139 ArrayView<const GO> rowElements = rowMap->getLocalElementList();
140 ArrayView<const GO> coordsElements = map->getLocalElementList();
141 for (LO i = 0; i < Teuchos::as<LO>(numElements); i++)
142 TEUCHOS_TEST_FOR_EXCEPTION((coordsElements[i] - indexBase) * blkSize + indexBase != rowElements[i * blkSize],
143 Exceptions::RuntimeError, "i = " << i << ", coords GID = " << coordsElements[i] << ", row GID = " << rowElements[i * blkSize] << ", blkSize = " << blkSize << std::endl);
144#endif
145
146 typedef Zoltan2::XpetraMultiVectorAdapter<RealValuedMultiVector> InputAdapterType;
147 typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
148
149 Array<real_type> weightsPerRow(numElements);
150 for (LO i = 0; i < numElements; i++) {
151 weightsPerRow[i] = 0.0;
152
153 for (LO j = 0; j < blkSize; j++) {
154 weightsPerRow[i] += A->getNumEntriesInLocalRow(i * blkSize + j);
155 }
156 }
157
158 // MultiJagged: Grab the target rows per process from the Heuristic to use unless the Zoltan2 list says otherwise
159 if (algo == "multijagged" && !Zoltan2Params.isParameter("mj_premigration_coordinate_count")) {
160 LO heuristicTargetRowsPerProcess = Get<LO>(level, "repartition: heuristic target rows per process");
161 Zoltan2Params.set("mj_premigration_coordinate_count", heuristicTargetRowsPerProcess);
162 }
163 const bool writeZoltan2DebuggingFiles = Zoltan2Params.get("mj_debug", false);
164 Zoltan2Params.remove("mj_debug");
165
166 std::vector<int> strides;
167 std::vector<const real_type*> weights(1, weightsPerRow.getRawPtr());
168
169 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
170 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
171
172 InputAdapterType adapter(coords, weights, strides);
173 RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
174
175 {
176 SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
177 if (writeZoltan2DebuggingFiles)
178 adapter.generateFiles(("mj_debug.lvl_" + std::to_string(level.GetLevelID())).c_str(), *(rowMap->getComm()));
179 problem->solve();
180 }
181
182 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false);
183 ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
184
185 const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
186
187 for (GO i = 0; i < numElements; i++) {
188 int partNum = parts[i];
189
190 for (LO j = 0; j < blkSize; j++)
191 decompEntries[i * blkSize + j] = partNum;
192 }
193
194 Set(level, "Partition", decomposition);
195
196 } else {
197 GO numElements = rowMap->getLocalNumElements();
198
199 typedef Zoltan2::XpetraCrsGraphAdapter<CrsGraph> InputAdapterType;
200 typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
201
202 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
203 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
204
205 InputAdapterType adapter(A->getCrsGraph());
206 RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
207
208 {
209 SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
210 problem->solve();
211 }
212
213 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false);
214 ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
215
216 const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
217
218 // For blkSize > 1, ignore solution for every row but the first ones in a block.
219 for (GO i = 0; i < numElements / blkSize; i++) {
220 int partNum = parts[i * blkSize];
221
222 for (LO j = 0; j < blkSize; j++)
223 decompEntries[i * blkSize + j] = partNum;
224 }
225
226 Set(level, "Partition", decomposition);
227 }
228}
229
230} // namespace MueLu
231
232#endif // if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
233
234#endif // MUELU_ZOLTAN2INTERFACE_DEF_HPP
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.
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.