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
98 if (GetVerbLevel() & Statistics1)
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.
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.
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.