MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_ZoltanInterface_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_ZOLTANINTERFACE_DEF_HPP
11#define MUELU_ZOLTANINTERFACE_DEF_HPP
12
14#if defined(HAVE_MUELU_ZOLTAN) && defined(HAVE_MPI)
15
16#include <Teuchos_Utils.hpp>
17#include <Teuchos_DefaultMpiComm.hpp> //TODO: fwd decl.
18#include <Teuchos_OpaqueWrapper.hpp> //TODO: fwd decl.
19
20#include "MueLu_Level.hpp"
21#include "MueLu_Exceptions.hpp"
22#include "MueLu_Monitor.hpp"
23
24namespace MueLu {
25
26template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
28 RCP<ParameterList> validParamList = rcp(new ParameterList());
29
30 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
31 validParamList->set<RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
32 validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
33
34 return validParamList;
35}
36
37template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
39 Input(currentLevel, "A");
40 Input(currentLevel, "number of partitions");
41 Input(currentLevel, "Coordinates");
42}
43
44template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
46 FactoryMonitor m(*this, "Build", level);
47
48 RCP<Matrix> A = Get<RCP<Matrix> >(level, "A");
49 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A);
50 RCP<const Map> rowMap;
51 if (bA != Teuchos::null) {
52 // Extracting the full the row map here...
53 RCP<const Map> bArowMap = bA->getRowMap();
54 RCP<const BlockedMap> bRowMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(bArowMap);
55 rowMap = bRowMap->getFullMap();
56 } else {
57 rowMap = A->getRowMap();
58 }
59
60 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LocalOrdinal, GlobalOrdinal, Node> double_multivector_type;
61 RCP<double_multivector_type> Coords = Get<RCP<double_multivector_type> >(level, "Coordinates");
62 size_t dim = Coords->getNumVectors();
63 int numParts = Get<int>(level, "number of partitions");
64
65 if (numParts == 1 || numParts == -1) {
66 // Running on one processor, so decomposition is the trivial one, all zeros.
67 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
68 Set(level, "Partition", decomposition);
69 return;
70 } else if (numParts == -1) {
71 // No repartitioning
72 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Teuchos::null;
73 Set(level, "Partition", decomposition);
74 return;
75 }
76
77 float zoltanVersion_;
78 Zoltan_Initialize(0, NULL, &zoltanVersion_);
79
80 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
81 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
82
83 RCP<Zoltan> zoltanObj_ = rcp(new Zoltan((*zoltanComm)())); // extract the underlying MPI_Comm handle and create a Zoltan object
84 if (zoltanObj_ == Teuchos::null)
85 throw Exceptions::RuntimeError("MueLu::Zoltan : Unable to create Zoltan data structure");
86
87 // Tell Zoltan what kind of local/global IDs we will use.
88 // In our case, each GID is two ints and there are no local ids.
89 // One can skip this step if the IDs are just single ints.
90 int rv;
91 if ((rv = zoltanObj_->Set_Param("num_gid_entries", "1")) != ZOLTAN_OK)
92 throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'num_gid_entries' returned error code " + Teuchos::toString(rv));
93 if ((rv = zoltanObj_->Set_Param("num_lid_entries", "0")) != ZOLTAN_OK)
94 throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'num_lid_entries' returned error code " + Teuchos::toString(rv));
95 if ((rv = zoltanObj_->Set_Param("obj_weight_dim", "1")) != ZOLTAN_OK)
96 throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'obj_weight_dim' returned error code " + Teuchos::toString(rv));
97
99 zoltanObj_->Set_Param("debug_level", "1");
100 else
101 zoltanObj_->Set_Param("debug_level", "0");
102
103 zoltanObj_->Set_Param("num_global_partitions", toString(numParts));
104
105 zoltanObj_->Set_Num_Obj_Fn(GetLocalNumberOfRows, (void *)A.getRawPtr());
106 zoltanObj_->Set_Obj_List_Fn(GetLocalNumberOfNonzeros, (void *)A.getRawPtr());
107 zoltanObj_->Set_Num_Geom_Fn(GetProblemDimension, (void *)&dim);
108 zoltanObj_->Set_Geom_Multi_Fn(GetProblemGeometry, (void *)Coords.get());
109
110 // Data pointers that Zoltan requires.
111 ZOLTAN_ID_PTR import_gids = NULL; // Global nums of objs to be imported
112 ZOLTAN_ID_PTR import_lids = NULL; // Local indices to objs to be imported
113 int *import_procs = NULL; // Proc IDs of procs owning objs to be imported.
114 int *import_to_part = NULL; // Partition #s to which imported objs should be assigned.
115 ZOLTAN_ID_PTR export_gids = NULL; // Global nums of objs to be exported
116 ZOLTAN_ID_PTR export_lids = NULL; // local indices to objs to be exported
117 int *export_procs = NULL; // Proc IDs of destination procs for objs to be exported.
118 int *export_to_part = NULL; // Partition #s for objs to be exported.
119 int num_imported; // Number of objs to be imported.
120 int num_exported; // Number of objs to be exported.
121 int newDecomp; // Flag indicating whether the decomposition has changed
122 int num_gid_entries; // Number of array entries in a global ID.
123 int num_lid_entries;
124
125 {
126 SubFactoryMonitor m1(*this, "Zoltan RCB", level);
127 rv = zoltanObj_->LB_Partition(newDecomp, num_gid_entries, num_lid_entries,
128 num_imported, import_gids, import_lids, import_procs, import_to_part,
129 num_exported, export_gids, export_lids, export_procs, export_to_part);
130 if (rv == ZOLTAN_FATAL)
131 throw Exceptions::RuntimeError("Zoltan::LB_Partition() returned error code");
132 }
133
134 // TODO check that A's row map is 1-1. Zoltan requires this.
135
136 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition;
137 if (newDecomp) {
138 decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false); // Don't initialize, will be overwritten
139 ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
140
141 int mypid = rowMap->getComm()->getRank();
142 for (typename ArrayRCP<GO>::iterator i = decompEntries.begin(); i != decompEntries.end(); ++i)
143 *i = mypid;
144
145 LO blockSize = A->GetFixedBlockSize();
146 for (int i = 0; i < num_exported; ++i) {
147 // We have assigned Zoltan gids to first row GID in the block
148 // NOTE: Zoltan GIDs are different from GIDs in the Coordinates vector
149 LO localEl = rowMap->getLocalElement(export_gids[i]);
150 int partNum = export_to_part[i];
151 for (LO j = 0; j < blockSize; ++j)
152 decompEntries[localEl + j] = partNum;
153 }
154 }
155
156 Set(level, "Partition", decomposition);
157
158 zoltanObj_->LB_Free_Part(&import_gids, &import_lids, &import_procs, &import_to_part);
159 zoltanObj_->LB_Free_Part(&export_gids, &export_lids, &export_procs, &export_to_part);
160
161} // Build()
162
163//-------------------------------------------------------------------------------------------------------------
164// GetLocalNumberOfRows
165//-------------------------------------------------------------------------------------------------------------
166
167template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
169 if (data == NULL) {
170 *ierr = ZOLTAN_FATAL;
171 return -1;
172 }
173 Matrix *A = (Matrix *)data;
174 *ierr = ZOLTAN_OK;
175
176 LO blockSize = A->GetFixedBlockSize();
177 TEUCHOS_TEST_FOR_EXCEPTION(blockSize == 0, Exceptions::RuntimeError, "MueLu::Zoltan : Matrix has block size 0.");
178
179 return A->getRowMap()->getLocalNumElements() / blockSize;
180} // GetLocalNumberOfRows()
181
182//-------------------------------------------------------------------------------------------------------------
183// GetLocalNumberOfNonzeros
184//-------------------------------------------------------------------------------------------------------------
185
186template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
188 GetLocalNumberOfNonzeros(void *data, int NumGidEntries, int /* NumLidEntries */, ZOLTAN_ID_PTR gids,
189 ZOLTAN_ID_PTR /* lids */, int /* wgtDim */, float *weights, int *ierr) {
190 if (data == NULL || NumGidEntries < 1) {
191 *ierr = ZOLTAN_FATAL;
192 return;
193 } else {
194 *ierr = ZOLTAN_OK;
195 }
196
197 Matrix *A = (Matrix *)data;
198 RCP<const Map> map = A->getRowMap();
199
200 LO blockSize = A->GetFixedBlockSize();
201 TEUCHOS_TEST_FOR_EXCEPTION(blockSize == 0, Exceptions::RuntimeError, "MueLu::Zoltan : Matrix has block size 0.");
202
203 size_t numElements = map->getLocalNumElements();
204 ArrayView<const GO> mapGIDs = map->getLocalElementList();
205
206 if (blockSize == 1) {
207 for (size_t i = 0; i < numElements; i++) {
208 gids[i] = as<ZOLTAN_ID_TYPE>(mapGIDs[i]);
209 weights[i] = A->getNumEntriesInLocalRow(i);
210 }
211
212 } else {
213 LO numBlockElements = numElements / blockSize;
214
215 for (LO i = 0; i < numBlockElements; i++) {
216 // Assign zoltan GID to the first row GID in the block
217 // NOTE: Zoltan GIDs are different from GIDs in the Coordinates vector
218 gids[i] = as<ZOLTAN_ID_TYPE>(mapGIDs[i * blockSize]);
219 weights[i] = 0.0;
220 for (LO j = 0; j < blockSize; j++)
221 weights[i] += A->getNumEntriesInLocalRow(i * blockSize + j);
222 }
223 }
224}
225
226//-------------------------------------------------------------------------------------------------------------
227// GetProblemDimension
228//-------------------------------------------------------------------------------------------------------------
229
230template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
232 GetProblemDimension(void *data, int *ierr) {
233 int dim = *((int *)data);
234 *ierr = ZOLTAN_OK;
235
236 return dim;
237} // GetProblemDimension
238
239//-------------------------------------------------------------------------------------------------------------
240// GetProblemGeometry
241//-------------------------------------------------------------------------------------------------------------
242
243template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
245 GetProblemGeometry(void *data, int /* numGIDEntries */, int /* numLIDEntries */, int numObjectIDs,
246 ZOLTAN_ID_PTR /* gids */, ZOLTAN_ID_PTR /* lids */, int dim, double *coordinates, int *ierr) {
247 if (data == NULL) {
248 *ierr = ZOLTAN_FATAL;
249 return;
250 }
251
252 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::coordinateType, LocalOrdinal, GlobalOrdinal, Node> double_multivector_type;
253 double_multivector_type *Coords = (double_multivector_type *)data;
254
255 if (dim != Teuchos::as<int>(Coords->getNumVectors())) {
256 // FIXME I'm assuming dim should be 1, 2, or 3 coming in?!
257 *ierr = ZOLTAN_FATAL;
258 return;
259 }
260
261 TEUCHOS_TEST_FOR_EXCEPTION(numObjectIDs != Teuchos::as<int>(Coords->getLocalLength()), Exceptions::Incompatible, "Length of coordinates must be the same as the number of objects");
262
263 ArrayRCP<ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType> > CoordsData(dim);
264 for (int j = 0; j < dim; ++j)
265 CoordsData[j] = Coords->getData(j);
266
267 size_t numElements = Coords->getLocalLength();
268 for (size_t i = 0; i < numElements; ++i)
269 for (int j = 0; j < dim; ++j)
270 coordinates[i * dim + j] = (double)CoordsData[j][i];
271
272 *ierr = ZOLTAN_OK;
273
274} // GetProblemGeometry
275
276} // namespace MueLu
277
278#endif // if defined(HAVE_MUELU_ZOLTAN) && defined(HAVE_MPI)
279
280#endif // MUELU_ZOLTANINTERFACE_DEF_HPP
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultGlobalOrdinal GlobalOrdinal
MueLu::DefaultNode Node
Exception throws to report incompatible objects (like maps).
Exception throws to report errors in the internal logical of the program.
void Input(Level &level, const std::string &varName) const
T Get(Level &level, const std::string &varName) const
void Set(Level &level, const std::string &varName, const T &data) const
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.
VerbLevel GetVerbLevel() const
Get the verbosity level.
static void GetLocalNumberOfNonzeros(void *data, int NumGidEntries, int NumLidEntries, ZOLTAN_ID_PTR gids, ZOLTAN_ID_PTR lids, int wgtDim, float *weights, int *ierr)
static int GetLocalNumberOfRows(void *data, int *ierr)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void Build(Level &level) const
Build an object with this factory.
void DeclareInput(Level &level) const
Specifies the data that this class needs, and the factories that generate that data.
static void GetProblemGeometry(void *data, int numGIDEntries, int numLIDEntries, int numObjectIDs, ZOLTAN_ID_PTR gids, ZOLTAN_ID_PTR lids, int dim, double *coordinates, int *ierr)
static int GetProblemDimension(void *data, int *ierr)
Namespace for MueLu classes and methods.
@ Statistics1
Print more statistics.
std::string toString(const T &what)
Little helper function to convert non-string types to strings.