MueLu Version of the Day
Loading...
Searching...
No Matches
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
60namespace MueLu {
61
62 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
64 RCP<ParameterList> validParamList = rcp(new ParameterList());
65
66 validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
67 validParamList->set< RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
68 validParamList->set< RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
69
70 return validParamList;
71 }
72
73
74 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
76 Input(currentLevel, "A");
77 Input(currentLevel, "number of partitions");
78 Input(currentLevel, "Coordinates");
79 }
80
81 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
83 FactoryMonitor m(*this, "Build", level);
84
85 RCP<Matrix> A = Get< RCP<Matrix> > (level, "A");
86 RCP<BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A);
87 RCP<const Map> rowMap;
88 if(bA != Teuchos::null) {
89 // Extracting the full the row map here...
90 RCP<const Map> bArowMap = bA->getRowMap();
91 RCP<const BlockedMap> bRowMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(bArowMap);
92 rowMap = bRowMap->getFullMap();
93 } else {
94 rowMap = A->getRowMap();
95 }
96
97 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LocalOrdinal, GlobalOrdinal, Node> double_multivector_type;
98 RCP<double_multivector_type> Coords = Get< RCP<double_multivector_type> >(level, "Coordinates");
99 size_t dim = Coords->getNumVectors();
100 int numParts = Get<int>(level, "number of partitions");
101
102 if (numParts == 1 || numParts == -1) {
103 // Running on one processor, so decomposition is the trivial one, all zeros.
104 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
105 Set(level, "Partition", decomposition);
106 return;
107 } else if (numParts == -1) {
108 // No repartitioning
109 RCP<Xpetra::Vector<GO,LO,GO,NO> > decomposition = Teuchos::null;
110 Set(level, "Partition", decomposition);
111 return;
112 }
113
114 float zoltanVersion_;
115 Zoltan_Initialize(0, NULL, &zoltanVersion_);
116
117 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
118 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
119
120 RCP<Zoltan> zoltanObj_ = rcp(new Zoltan((*zoltanComm)())); //extract the underlying MPI_Comm handle and create a Zoltan object
121 if (zoltanObj_ == Teuchos::null)
122 throw Exceptions::RuntimeError("MueLu::Zoltan : Unable to create Zoltan data structure");
123
124 // Tell Zoltan what kind of local/global IDs we will use.
125 // In our case, each GID is two ints and there are no local ids.
126 // One can skip this step if the IDs are just single ints.
127 int rv;
128 if ((rv = zoltanObj_->Set_Param("num_gid_entries", "1")) != ZOLTAN_OK)
129 throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'num_gid_entries' returned error code " + Teuchos::toString(rv));
130 if ((rv = zoltanObj_->Set_Param("num_lid_entries", "0") ) != ZOLTAN_OK)
131 throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'num_lid_entries' returned error code " + Teuchos::toString(rv));
132 if ((rv = zoltanObj_->Set_Param("obj_weight_dim", "1") ) != ZOLTAN_OK)
133 throw Exceptions::RuntimeError("MueLu::Zoltan::Setup : setting parameter 'obj_weight_dim' returned error code " + Teuchos::toString(rv));
134
135 if (GetVerbLevel() & Statistics1) zoltanObj_->Set_Param("debug_level", "1");
136 else zoltanObj_->Set_Param("debug_level", "0");
137
138 zoltanObj_->Set_Param("num_global_partitions", toString(numParts));
139
140 zoltanObj_->Set_Num_Obj_Fn(GetLocalNumberOfRows, (void *) A.getRawPtr());
141 zoltanObj_->Set_Obj_List_Fn(GetLocalNumberOfNonzeros, (void *) A.getRawPtr());
142 zoltanObj_->Set_Num_Geom_Fn(GetProblemDimension, (void *) &dim);
143 zoltanObj_->Set_Geom_Multi_Fn(GetProblemGeometry, (void *) Coords.get());
144
145 // Data pointers that Zoltan requires.
146 ZOLTAN_ID_PTR import_gids = NULL; // Global nums of objs to be imported
147 ZOLTAN_ID_PTR import_lids = NULL; // Local indices to objs to be imported
148 int *import_procs = NULL; // Proc IDs of procs owning objs to be imported.
149 int *import_to_part = NULL; // Partition #s to which imported objs should be assigned.
150 ZOLTAN_ID_PTR export_gids = NULL; // Global nums of objs to be exported
151 ZOLTAN_ID_PTR export_lids = NULL; // local indices to objs to be exported
152 int *export_procs = NULL; // Proc IDs of destination procs for objs to be exported.
153 int *export_to_part = NULL; // Partition #s for objs to be exported.
154 int num_imported; // Number of objs to be imported.
155 int num_exported; // Number of objs to be exported.
156 int newDecomp; // Flag indicating whether the decomposition has changed
157 int num_gid_entries; // Number of array entries in a global ID.
158 int num_lid_entries;
159
160 {
161 SubFactoryMonitor m1(*this, "Zoltan RCB", level);
162 rv = zoltanObj_->LB_Partition(newDecomp, num_gid_entries, num_lid_entries,
163 num_imported, import_gids, import_lids, import_procs, import_to_part,
164 num_exported, export_gids, export_lids, export_procs, export_to_part);
165 if (rv == ZOLTAN_FATAL)
166 throw Exceptions::RuntimeError("Zoltan::LB_Partition() returned error code");
167 }
168
169 // TODO check that A's row map is 1-1. Zoltan requires this.
170
171 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition;
172 if (newDecomp) {
173 decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, false); // Don't initialize, will be overwritten
174 ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
175
176 int mypid = rowMap->getComm()->getRank();
177 for (typename ArrayRCP<GO>::iterator i = decompEntries.begin(); i != decompEntries.end(); ++i)
178 *i = mypid;
179
180 LO blockSize = A->GetFixedBlockSize();
181 for (int i = 0; i < num_exported; ++i) {
182 // We have assigned Zoltan gids to first row GID in the block
183 // NOTE: Zoltan GIDs are different from GIDs in the Coordinates vector
184 LO localEl = rowMap->getLocalElement(export_gids[i]);
185 int partNum = export_to_part[i];
186 for (LO j = 0; j < blockSize; ++j)
187 decompEntries[localEl + j] = partNum;
188 }
189 }
190
191 Set(level, "Partition", decomposition);
192
193 zoltanObj_->LB_Free_Part(&import_gids, &import_lids, &import_procs, &import_to_part);
194 zoltanObj_->LB_Free_Part(&export_gids, &export_lids, &export_procs, &export_to_part);
195
196 } //Build()
197
198 //-------------------------------------------------------------------------------------------------------------
199 // GetLocalNumberOfRows
200 //-------------------------------------------------------------------------------------------------------------
201
202 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
204 if (data == NULL) {
205 *ierr = ZOLTAN_FATAL;
206 return -1;
207 }
208 Matrix *A = (Matrix*) data;
209 *ierr = ZOLTAN_OK;
210
211 LO blockSize = A->GetFixedBlockSize();
212 TEUCHOS_TEST_FOR_EXCEPTION(blockSize == 0, Exceptions::RuntimeError, "MueLu::Zoltan : Matrix has block size 0.");
213
214 return A->getRowMap()->getLocalNumElements() / blockSize;
215 } //GetLocalNumberOfRows()
216
217 //-------------------------------------------------------------------------------------------------------------
218 // GetLocalNumberOfNonzeros
219 //-------------------------------------------------------------------------------------------------------------
220
221 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
223 GetLocalNumberOfNonzeros(void *data, int NumGidEntries, int /* NumLidEntries */, ZOLTAN_ID_PTR gids,
224 ZOLTAN_ID_PTR /* lids */, int /* wgtDim */, float *weights, int *ierr) {
225 if (data == NULL || NumGidEntries < 1) {
226 *ierr = ZOLTAN_FATAL;
227 return;
228 } else {
229 *ierr = ZOLTAN_OK;
230 }
231
232 Matrix *A = (Matrix*) data;
233 RCP<const Map> map = A->getRowMap();
234
235 LO blockSize = A->GetFixedBlockSize();
236 TEUCHOS_TEST_FOR_EXCEPTION(blockSize == 0, Exceptions::RuntimeError, "MueLu::Zoltan : Matrix has block size 0.");
237
238 size_t numElements = map->getLocalNumElements();
239 ArrayView<const GO> mapGIDs = map->getLocalElementList();
240
241 if (blockSize == 1) {
242 for (size_t i = 0; i < numElements; i++) {
243 gids[i] = as<ZOLTAN_ID_TYPE>(mapGIDs[i]);
244 weights[i] = A->getNumEntriesInLocalRow(i);
245 }
246
247 } else {
248 LO numBlockElements = numElements / blockSize;
249
250 for (LO i = 0; i < numBlockElements; i++) {
251 // Assign zoltan GID to the first row GID in the block
252 // NOTE: Zoltan GIDs are different from GIDs in the Coordinates vector
253 gids[i] = as<ZOLTAN_ID_TYPE>(mapGIDs[i*blockSize]);
254 weights[i] = 0.0;
255 for (LO j = 0; j < blockSize; j++)
256 weights[i] += A->getNumEntriesInLocalRow(i*blockSize+j);
257 }
258 }
259
260 }
261
262 //-------------------------------------------------------------------------------------------------------------
263 // GetProblemDimension
264 //-------------------------------------------------------------------------------------------------------------
265
266 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
268 GetProblemDimension(void *data, int *ierr)
269 {
270 int dim = *((int*)data);
271 *ierr = ZOLTAN_OK;
272
273 return dim;
274 } //GetProblemDimension
275
276 //-------------------------------------------------------------------------------------------------------------
277 // GetProblemGeometry
278 //-------------------------------------------------------------------------------------------------------------
279
280 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
282 GetProblemGeometry(void *data, int /* numGIDEntries */, int /* numLIDEntries */, int numObjectIDs,
283 ZOLTAN_ID_PTR /* gids */, ZOLTAN_ID_PTR /* lids */, int dim, double *coordinates, int *ierr)
284 {
285 if (data == NULL) {
286 *ierr = ZOLTAN_FATAL;
287 return;
288 }
289
290 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::coordinateType, LocalOrdinal, GlobalOrdinal, Node> double_multivector_type;
291 double_multivector_type *Coords = (double_multivector_type*) data;
292
293 if (dim != Teuchos::as<int>(Coords->getNumVectors())) {
294 //FIXME I'm assuming dim should be 1, 2, or 3 coming in?!
295 *ierr = ZOLTAN_FATAL;
296 return;
297 }
298
299 TEUCHOS_TEST_FOR_EXCEPTION(numObjectIDs != Teuchos::as<int>(Coords->getLocalLength()), Exceptions::Incompatible, "Length of coordinates must be the same as the number of objects");
300
301 ArrayRCP<ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType> > CoordsData(dim);
302 for (int j = 0; j < dim; ++j)
303 CoordsData[j] = Coords->getData(j);
304
305 size_t numElements = Coords->getLocalLength();
306 for (size_t i = 0; i < numElements; ++i)
307 for (int j = 0; j < dim; ++j)
308 coordinates[i*dim+j] = (double) CoordsData[j][i];
309
310 *ierr = ZOLTAN_OK;
311
312 } //GetProblemGeometry
313
314} //namespace MueLu
315
316#endif //if defined(HAVE_MUELU_ZOLTAN) && defined(HAVE_MPI)
317
318#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.
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
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.