MueLu  Version of the Day
MueLu_ZoltanInterface_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_ZOLTANINTERFACE_DEF_HPP
47 #define MUELU_ZOLTANINTERFACE_DEF_HPP
48 
50 #if defined(HAVE_MUELU_ZOLTAN) && defined(HAVE_MPI)
51 
52 #include <Teuchos_Utils.hpp>
53 #include <Teuchos_DefaultMpiComm.hpp> //TODO: fwd decl.
54 #include <Teuchos_OpaqueWrapper.hpp> //TODO: fwd decl.
55 
56 #include "MueLu_Level.hpp"
57 #include "MueLu_Exceptions.hpp"
58 #include "MueLu_Monitor.hpp"
59 #include "MueLu_Utilities.hpp"
60 
61 namespace MueLu {
62 
63  template <class LocalOrdinal, class GlobalOrdinal, class Node>
65  RCP<ParameterList> validParamList = rcp(new ParameterList());
66 
67  validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
68  validParamList->set< RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
69 
70  return validParamList;
71  }
72 
73 
74  template <class LocalOrdinal, class GlobalOrdinal, class Node>
76  Input(currentLevel, "A");
77  Input(currentLevel, "Coordinates");
78  }
79 
80  template <class LocalOrdinal, class GlobalOrdinal, class Node>
82  FactoryMonitor m(*this, "Build", level);
83 
84  RCP<Matrix> A = Get< RCP<Matrix> > (level, "A");
85  RCP<const Map> rowMap = A->getRowMap();
86 
87  RCP<MultiVector> Coords = Get< RCP<MultiVector> >(level, "Coordinates");
88  size_t dim = Coords->getNumVectors();
89 
90  GO numParts = level.Get<GO>("number of partitions");
91 
92  if (numParts == 1) {
93  // Running on one processor, so decomposition is the trivial one, all zeros.
94  RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
95  Set(level, "Partition", decomposition);
96  return;
97  }
98 
99  float zoltanVersion_;
100  Zoltan_Initialize(0, NULL, &zoltanVersion_);
101 
102  RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
103  RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
104 
105  RCP<Zoltan> zoltanObj_ = rcp(new Zoltan((*zoltanComm)())); //extract the underlying MPI_Comm handle and create a Zoltan object
106  if (zoltanObj_ == Teuchos::null)
107  throw Exceptions::RuntimeError("MueLu::Zoltan : Unable to create Zoltan data structure");
108 
109  // Tell Zoltan what kind of local/global IDs we will use.
110  // In our case, each GID is two ints and there are no local ids.
111  // One can skip this step if the IDs are just single ints.
112  int rv;
113  if ((rv = zoltanObj_->Set_Param("num_gid_entries", "1")) != ZOLTAN_OK)
114  throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'num_gid_entries' returned error code " + Teuchos::toString(rv));
115  if ((rv = zoltanObj_->Set_Param("num_lid_entries", "0") ) != ZOLTAN_OK)
116  throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'num_lid_entries' returned error code " + Teuchos::toString(rv));
117  if ((rv = zoltanObj_->Set_Param("obj_weight_dim", "1") ) != ZOLTAN_OK)
118  throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'obj_weight_dim' returned error code " + Teuchos::toString(rv));
119 
120  if (GetVerbLevel() & Statistics1) zoltanObj_->Set_Param("debug_level", "1");
121  else zoltanObj_->Set_Param("debug_level", "0");
122 
123  zoltanObj_->Set_Param("num_global_partitions", toString(numParts));
124 
125  zoltanObj_->Set_Num_Obj_Fn(GetLocalNumberOfRows, (void *) &*A);
126  zoltanObj_->Set_Obj_List_Fn(GetLocalNumberOfNonzeros, (void *) &*A);
127  zoltanObj_->Set_Num_Geom_Fn(GetProblemDimension, (void *) &dim);
128  zoltanObj_->Set_Geom_Multi_Fn(GetProblemGeometry, (void *) Coords.get());
129 
130  // Data pointers that Zoltan requires.
131  ZOLTAN_ID_PTR import_gids = NULL; // Global nums of objs to be imported
132  ZOLTAN_ID_PTR import_lids = NULL; // Local indices to objs to be imported
133  int *import_procs = NULL; // Proc IDs of procs owning objs to be imported.
134  int *import_to_part = NULL; // Partition #s to which imported objs should be assigned.
135  ZOLTAN_ID_PTR export_gids = NULL; // Global nums of objs to be exported
136  ZOLTAN_ID_PTR export_lids = NULL; // local indices to objs to be exported
137  int *export_procs = NULL; // Proc IDs of destination procs for objs to be exported.
138  int *export_to_part = NULL; // Partition #s for objs to be exported.
139  int num_imported; // Number of objs to be imported.
140  int num_exported; // Number of objs to be exported.
141  int newDecomp; // Flag indicating whether the decomposition has changed
142  int num_gid_entries; // Number of array entries in a global ID.
143  int num_lid_entries;
144 
145  {
146  SubFactoryMonitor m1(*this, "Zoltan RCB", level);
147  rv = zoltanObj_->LB_Partition(newDecomp, num_gid_entries, num_lid_entries,
148  num_imported, import_gids, import_lids, import_procs, import_to_part,
149  num_exported, export_gids, export_lids, export_procs, export_to_part);
150  if (rv == ZOLTAN_FATAL)
151  throw Exceptions::RuntimeError("Zoltan::LB_Partition() returned error code");
152  }
153 
154  // TODO check that A's row map is 1-1. Zoltan requires this.
155 
156  RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition;
157  if (newDecomp) {
158  decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false); // Don't initialize, will be overwritten
159  ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
160 
161  int mypid = rowMap->getComm()->getRank();
162  for (typename ArrayRCP<GO>::iterator i = decompEntries.begin(); i != decompEntries.end(); ++i)
163  *i = mypid;
164 
165  LO blockSize = A->GetFixedBlockSize();
166  for (int i = 0; i < num_exported; ++i) {
167  // We have assigned Zoltan gids to first row GID in the block
168  // NOTE: Zoltan GIDs are different from GIDs in the Coordinates vector
169  LO localEl = rowMap->getLocalElement(export_gids[i]);
170  int partNum = export_to_part[i];
171  for (LO j = 0; j < blockSize; ++j)
172  decompEntries[localEl + j] = partNum;
173  }
174  }
175 
176  Set(level, "Partition", decomposition);
177 
178  zoltanObj_->LB_Free_Part(&import_gids, &import_lids, &import_procs, &import_to_part);
179  zoltanObj_->LB_Free_Part(&export_gids, &export_lids, &export_procs, &export_to_part);
180 
181  } //Build()
182 
183  //-------------------------------------------------------------------------------------------------------------
184  // GetLocalNumberOfRows
185  //-------------------------------------------------------------------------------------------------------------
186 
187  template <class LocalOrdinal, class GlobalOrdinal, class Node>
189  if (data == NULL) {
190  *ierr = ZOLTAN_FATAL;
191  return -1;
192  }
193  Matrix *A = (Matrix*) data;
194  *ierr = ZOLTAN_OK;
195 
196  LO blockSize = A->GetFixedBlockSize();
197  TEUCHOS_TEST_FOR_EXCEPTION(blockSize == 0, Exceptions::RuntimeError, "MueLu::Zoltan : Matrix has block size 0.");
198 
199  return A->getRowMap()->getNodeNumElements() / blockSize;
200  } //GetLocalNumberOfRows()
201 
202  //-------------------------------------------------------------------------------------------------------------
203  // GetLocalNumberOfNonzeros
204  //-------------------------------------------------------------------------------------------------------------
205 
206  template <class LocalOrdinal, class GlobalOrdinal, class Node>
208  GetLocalNumberOfNonzeros(void *data, int NumGidEntries, int NumLidEntries, ZOLTAN_ID_PTR gids,
209  ZOLTAN_ID_PTR lids, int wgtDim, float *weights, int *ierr) {
210  if (data == NULL || NumGidEntries < 1) {
211  *ierr = ZOLTAN_FATAL;
212  return;
213  } else {
214  *ierr = ZOLTAN_OK;
215  }
216 
217  Matrix *A = (Matrix*) data;
218  RCP<const Map> map = A->getRowMap();
219 
220  LO blockSize = A->GetFixedBlockSize();
221  TEUCHOS_TEST_FOR_EXCEPTION(blockSize == 0, Exceptions::RuntimeError, "MueLu::Zoltan : Matrix has block size 0.");
222 
223  size_t numElements = map->getNodeNumElements();
224  ArrayView<const GO> mapGIDs = map->getNodeElementList();
225 
226  if (blockSize == 1) {
227  for (size_t i = 0; i < numElements; i++) {
228  gids[i] = as<ZOLTAN_ID_TYPE>(mapGIDs[i]);
229  weights[i] = A->getNumEntriesInLocalRow(i);
230  }
231 
232  } else {
233  LO numBlockElements = numElements / blockSize;
234 
235  for (LO i = 0; i < numBlockElements; i++) {
236  // Assign zoltan GID to the first row GID in the block
237  // NOTE: Zoltan GIDs are different from GIDs in the Coordinates vector
238  gids[i] = as<ZOLTAN_ID_TYPE>(mapGIDs[i*blockSize]);
239  weights[i] = 0.0;
240  for (LO j = 0; j < blockSize; j++)
241  weights[i] += A->getNumEntriesInLocalRow(i*blockSize+j);
242  }
243  }
244 
245  }
246 
247  //-------------------------------------------------------------------------------------------------------------
248  // GetProblemDimension
249  //-------------------------------------------------------------------------------------------------------------
250 
251  template <class LocalOrdinal, class GlobalOrdinal, class Node>
253  GetProblemDimension(void *data, int *ierr)
254  {
255  int dim = *((int*)data);
256  *ierr = ZOLTAN_OK;
257 
258  return dim;
259  } //GetProblemDimension
260 
261  //-------------------------------------------------------------------------------------------------------------
262  // GetProblemGeometry
263  //-------------------------------------------------------------------------------------------------------------
264 
265  template <class LocalOrdinal, class GlobalOrdinal, class Node>
267  GetProblemGeometry(void *data, int numGIDEntries, int numLIDEntries, int numObjectIDs,
268  ZOLTAN_ID_PTR gids, ZOLTAN_ID_PTR lids, int dim, double *coordinates, int *ierr)
269  {
270  if (data == NULL) {
271  *ierr = ZOLTAN_FATAL;
272  return;
273  }
274 
275  MultiVector *Coords = (MultiVector*) data;
276 
277  if (dim != Teuchos::as<int>(Coords->getNumVectors())) {
278  //FIXME I'm assuming dim should be 1, 2, or 3 coming in?!
279  *ierr = ZOLTAN_FATAL;
280  return;
281  }
282 
283  TEUCHOS_TEST_FOR_EXCEPTION(numObjectIDs != Teuchos::as<int>(Coords->getLocalLength()), Exceptions::Incompatible, "Length of coordinates must be the same as the number of objects");
284 
285  ArrayRCP<ArrayRCP<const SC> > CoordsData(dim);
286  for (int j = 0; j < dim; ++j)
287  CoordsData[j] = Coords->getData(j);
288 
289  size_t numElements = Coords->getLocalLength();
290  for (size_t i = 0; i < numElements; ++i)
291  for (int j = 0; j < dim; ++j)
292  coordinates[i*dim+j] = (double) CoordsData[j][i];
293 
294  *ierr = ZOLTAN_OK;
295 
296  } //GetProblemGeometry
297 
298 } //namespace MueLu
299 
300 #endif //if defined(HAVE_MUELU_ZOLTAN) && defined(HAVE_MPI)
301 
302 #endif // MUELU_ZOLTANINTERFACE_DEF_HPP
static int GetProblemDimension(void *data, int *ierr)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
static int GetLocalNumberOfRows(void *data, int *ierr)
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)
Timer to be used in factories. Similar to Monitor but with additional timers.
Print more statistics.
Namespace for MueLu classes and methods.
Exception throws to report incompatible objects (like maps).
static void GetLocalNumberOfNonzeros(void *data, int NumGidEntries, int NumLidEntries, ZOLTAN_ID_PTR gids, ZOLTAN_ID_PTR lids, int wgtDim, float *weights, int *ierr)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
void Build(Level &level) const
Build an object with this factory.
Exception throws to report errors in the internal logical of the program.
void DeclareInput(Level &level) 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.