MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
24 namespace MueLu {
25 
26 template <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 
37 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
39  Input(currentLevel, "A");
40  Input(currentLevel, "number of partitions");
41  Input(currentLevel, "Coordinates");
42 }
43 
44 template <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 
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.
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 
167 template <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 
186 template <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 
230 template <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 
243 template <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 
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 
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
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Print more statistics.
LocalOrdinal LO
T * get() const
static int GetProblemDimension(void *data, int *ierr)
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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)
Exception throws to report incompatible objects (like maps).
MueLu::DefaultNode Node
T * getRawPtr() const
void Build(Level &level) const
Build an object with this factory.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
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)
void DeclareInput(Level &level) const
Specifies the data that this class needs, and the factories that generate that data.
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
Exception throws to report errors in the internal logical of the program.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
iterator end() const
iterator begin() const
std::string toString(const T &t)
static int GetLocalNumberOfRows(void *data, int *ierr)