Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
rcbPerformance.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
16 #include <Zoltan2_TestHelpers.hpp>
20 
21 #include <Teuchos_CommandLineProcessor.hpp>
22 
23 #include <vector>
24 
25 using std::vector;
26 using std::bad_alloc;
27 using Teuchos::RCP;
28 using Teuchos::rcp;
29 using Teuchos::Comm;
30 using Teuchos::ArrayView;
31 using Teuchos::ArrayRCP;
32 using Teuchos::CommandLineProcessor;
33 
34 typedef Tpetra::MultiVector<zscalar_t, zlno_t, zgno_t, znode_t> tMVector_t;
35 typedef Tpetra::Map<zlno_t, zgno_t, znode_t> tMap_t;
36 
42 };
43 
44 ArrayRCP<zscalar_t> makeWeights(
45  const RCP<const Teuchos::Comm<int> > & comm,
46  zlno_t len, weightTypes how, zscalar_t scale, int rank)
47 {
48  zscalar_t *wgts = new zscalar_t [len];
49  if (!wgts)
50  throw bad_alloc();
51 
52  ArrayRCP<zscalar_t> weights(wgts, 0, len, true);
53 
54  if (how == upDown){
55  zscalar_t val = scale + rank%2;
56  for (zlno_t i=0; i < len; i++)
57  wgts[i] = val;
58  }
59  else if (how == roundRobin){
60  for (int i=0; i < 10; i++){
61  zscalar_t val = (i + 10)*scale;
62  for (zlno_t j=i; j < len; j += 10)
63  weights[j] = val;
64  }
65  }
66  else if (how == increasing){
67  zscalar_t val = scale + rank;
68  for (zlno_t i=0; i < len; i++)
69  wgts[i] = val;
70  }
71 
72  return weights;
73 }
74 
79 const RCP<tMVector_t> getMeshCoordinates(
80  const RCP<const Teuchos::Comm<int> > & comm,
81  zgno_t numGlobalCoords)
82 {
83  int rank = comm->getRank();
84  int nprocs = comm->getSize();
85 
86  double k = log(numGlobalCoords) / 3;
87  double xdimf = exp(k) + 0.5;
88  ssize_t xdim = static_cast<ssize_t>(floor(xdimf));
89  ssize_t ydim = xdim;
90  ssize_t zdim = numGlobalCoords / (xdim*ydim);
91  ssize_t num=xdim*ydim*zdim;
92  ssize_t diff = numGlobalCoords - num;
93  ssize_t newdiff = 0;
94 
95  while (diff > 0){
96  if (zdim > xdim && zdim > ydim){
97  zdim++;
98  newdiff = diff - (xdim*ydim);
99  if (newdiff < 0)
100  if (diff < -newdiff)
101  zdim--;
102  }
103  else if (ydim > xdim && ydim > zdim){
104  ydim++;
105  newdiff = diff - (xdim*zdim);
106  if (newdiff < 0)
107  if (diff < -newdiff)
108  ydim--;
109  }
110  else{
111  xdim++;
112  newdiff = diff - (ydim*zdim);
113  if (newdiff < 0)
114  if (diff < -newdiff)
115  xdim--;
116  }
117 
118  diff = newdiff;
119  }
120 
121  num=xdim*ydim*zdim;
122  diff = numGlobalCoords - num;
123  if (diff < 0)
124  diff /= -numGlobalCoords;
125  else
126  diff /= numGlobalCoords;
127 
128  if (rank == 0){
129  if (diff > .01)
130  std::cout << "Warning: Difference " << diff*100 << " percent" << std::endl;
131  std::cout << "Mesh size: " << xdim << "x" << ydim << "x" <<
132  zdim << ", " << num << " vertices." << std::endl;
133  }
134 
135  // Divide coordinates.
136 
137  ssize_t numLocalCoords = num / nprocs;
138  ssize_t leftOver = num % nprocs;
139  ssize_t gid0 = 0;
140 
141  if (rank <= leftOver)
142  gid0 = zgno_t(rank) * (numLocalCoords+1);
143  else
144  gid0 = (leftOver * (numLocalCoords+1)) +
145  ((zgno_t(rank) - leftOver) * numLocalCoords);
146 
147  if (rank < leftOver)
148  numLocalCoords++;
149 
150  ssize_t gid1 = gid0 + numLocalCoords;
151 
152  zgno_t *ids = new zgno_t [numLocalCoords];
153  if (!ids)
154  throw bad_alloc();
155  ArrayRCP<zgno_t> idArray(ids, 0, numLocalCoords, true);
156 
157  for (ssize_t i=gid0; i < gid1; i++)
158  *ids++ = zgno_t(i);
159 
160  RCP<const tMap_t> idMap = rcp(
161  new tMap_t(num, idArray.view(0, numLocalCoords), 0, comm));
162 
163  // Create a Tpetra::MultiVector of coordinates.
164 
165  zscalar_t *x = new zscalar_t [numLocalCoords*3];
166  if (!x)
167  throw bad_alloc();
168  ArrayRCP<zscalar_t> coordArray(x, 0, numLocalCoords*3, true);
169 
170  zscalar_t *y = x + numLocalCoords;
171  zscalar_t *z = y + numLocalCoords;
172 
173  zgno_t xStart = 0;
174  zgno_t yStart = 0;
175  zgno_t xyPlane = xdim*ydim;
176  zgno_t zStart = gid0 / xyPlane;
177  zgno_t rem = gid0 % xyPlane;
178  if (rem > 0){
179  yStart = rem / xdim;
180  xStart = rem % xdim;
181  }
182 
183  zlno_t next = 0;
184  for (zscalar_t zval=zStart; next < numLocalCoords && zval < zdim; zval++){
185  for (zscalar_t yval=yStart; next < numLocalCoords && yval < ydim; yval++){
186  for (zscalar_t xval=xStart; next < numLocalCoords && xval < xdim; xval++){
187  x[next] = xval;
188  y[next] = yval;
189  z[next] = zval;
190  next++;
191  }
192  xStart = 0;
193  }
194  yStart = 0;
195  }
196 
197  ArrayView<const zscalar_t> xArray(x, numLocalCoords);
198  ArrayView<const zscalar_t> yArray(y, numLocalCoords);
199  ArrayView<const zscalar_t> zArray(z, numLocalCoords);
200  ArrayRCP<ArrayView<const zscalar_t> > coordinates =
201  arcp(new ArrayView<const zscalar_t> [3], 0, 3);
202  coordinates[0] = xArray;
203  coordinates[1] = yArray;
204  coordinates[2] = zArray;
205 
206  ArrayRCP<const ArrayView<const zscalar_t> > constCoords =
207  coordinates.getConst();
208 
209  RCP<tMVector_t> meshCoords = rcp(new tMVector_t(
210  idMap, constCoords.view(0,3), 3));
211 
212  return meshCoords;
213 }
214 
215 
216 int main(int narg, char *arg[])
217 {
218  // MEMORY_CHECK(true, "Before initializing MPI");
219 
220  Tpetra::ScopeGuard tscope(&narg, &arg);
221  Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
222 
223  int rank = comm->getRank();
224  int nprocs = comm->getSize();
225 
226  MEMORY_CHECK(rank==0, "After initializing MPI");
227 
228  if (rank==0)
229  std::cout << "Number of processes: " << nprocs << std::endl;
230 
231  // Default values
232  double numGlobalCoords = 1000;
233  int numTestCuts = 1;
234  int nWeights = 0;
235  string timingType("no_timers");
236  string debugLevel("basic_status");
237  string memoryOn("memoryOn");
238  string memoryOff("memoryOff");
239  string memoryProcs("0");
240  bool doMemory=false;
241  int numGlobalParts = nprocs;
242 
243  CommandLineProcessor commandLine(false, true);
244  commandLine.setOption("size", &numGlobalCoords,
245  "Approximate number of global coordinates.");
246  commandLine.setOption("testCuts", &numTestCuts,
247  "Number of test cuts to make when looking for bisector.");
248  commandLine.setOption("numParts", &numGlobalParts,
249  "Number of parts (default is one per proc).");
250  commandLine.setOption("nWeights", &nWeights,
251  "Number of weights per coordinate, zero implies uniform weights.");
252 
253  string balanceCount("balance_object_count");
254  string balanceWeight("balance_object_weight");
255  string mcnorm1("multicriteria_minimize_total_weight");
256  string mcnorm2("multicriteria_balance_total_maximum");
257  string mcnorm3("multicriteria_minimize_maximum_weight");
258 
259  string objective(balanceWeight); // default
260 
261  string doc(balanceCount); doc.append(": ignore weights\n");
262 
263  doc.append(balanceWeight); doc.append(": balance on first weight\n");
264 
265  doc.append(mcnorm1);
266  doc.append(": given multiple weights, balance their total.\n");
267 
268  doc.append(mcnorm3);
269  doc.append(": given multiple weights, balance the maximum for each coordinate.\n");
270 
271  doc.append(mcnorm2);
272  doc.append(": given multiple weights, balance the L2 norm of the weights.\n");
273 
274  commandLine.setOption("objective", &objective, doc.c_str());
275 
276  commandLine.setOption("timers", &timingType,
277  "no_timers, micro_timers, macro_timers, both_timers, test_timers");
278 
279  commandLine.setOption("debug", &debugLevel,
280  "no_status, basic_status, detailed_status, verbose_detailed_status");
281 
282  commandLine.setOption(memoryOn.c_str(), memoryOff.c_str(), &doMemory,
283  "do memory profiling");
284 
285  commandLine.setOption("memoryProcs", &memoryProcs,
286  "list of processes that output memory usage");
287 
288  CommandLineProcessor::EParseCommandLineReturn rc =
289  commandLine.parse(narg, arg);
290 
291  if (rc != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL){
292  if (rc == Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED){
293  if (rank==0)
294  std::cout << "PASS" << std::endl;
295  return 1;
296  }
297  else{
298  if (rank==0)
299  std::cout << "FAIL" << std::endl;
300  return 0;
301  }
302  }
303 
304  //MEMORY_CHECK(doMemory && rank==0, "After processing parameters");
305 
306  zgno_t globalSize = static_cast<zgno_t>(numGlobalCoords);
307 
308  RCP<tMVector_t> coordinates = getMeshCoordinates(comm, globalSize);
309  size_t numLocalCoords = coordinates->getLocalLength();
310 
311 #if 0
312  comm->barrier();
313  for (int p=0; p < nprocs; p++){
314  if (p==rank){
315  std::cout << "Rank " << rank << ", " << numLocalCoords << "coords" << std::endl;
316  const zscalar_t *x = coordinates->getData(0).getRawPtr();
317  const zscalar_t *y = coordinates->getData(1).getRawPtr();
318  const zscalar_t *z = coordinates->getData(2).getRawPtr();
319  for (zlno_t i=0; i < numLocalCoords; i++)
320  std::cout << " " << x[i] << " " << y[i] << " " << z[i] << std::endl;
321  }
322  std::cout.flush();
323  comm->barrier();
324  }
325 #endif
326 
327  Array<ArrayRCP<zscalar_t> > weights(nWeights);
328 
329  if (nWeights > 0){
330  int wt = 0;
331  zscalar_t scale = 1.0;
332  for (int i=0; i < nWeights; i++){
333  weights[i] =
334  makeWeights(comm, numLocalCoords, weightTypes(wt++), scale, rank);
335  if (wt == numWeightTypes){
336  wt = 0;
337  scale++;
338  }
339  }
340  }
341 
342  MEMORY_CHECK(doMemory && rank==0, "After creating input");
343 
344  // Create an input adapter.
345  const RCP<const tMap_t> &coordmap = coordinates->getMap();
346  ArrayView<const zgno_t> ids = coordmap->getLocalElementList();
347  const zgno_t *globalIds = ids.getRawPtr();
348 
349  size_t localCount = coordinates->getLocalLength();
350  typedef Zoltan2::BasicVectorAdapter<tMVector_t> inputAdapter_t;
351  RCP<inputAdapter_t> ia;
352 
353  if (nWeights == 0){
354  ia = rcp(new inputAdapter_t (localCount, globalIds,
355  coordinates->getData(0).getRawPtr(), coordinates->getData(1).getRawPtr(),
356  coordinates->getData(2).getRawPtr(), 1,1,1));
357  }
358  else{
359  vector<const zscalar_t *> values(3);
360  for (int i=0; i < 3; i++)
361  values[i] = coordinates->getData(i).getRawPtr();
362  vector<int> valueStrides(0); // implies stride is one
363  vector<const zscalar_t *> weightPtrs(nWeights);
364  for (int i=0; i < nWeights; i++)
365  weightPtrs[i] = weights[i].getRawPtr();
366  vector<int> weightStrides(0); // implies stride is one
367 
368  ia = rcp(new inputAdapter_t (localCount, globalIds,
369  values, valueStrides, weightPtrs, weightStrides));
370  }
371 
372  MEMORY_CHECK(doMemory && rank==0, "After creating input adapter");
373 
374  // Parameters
375 
376  Teuchos::ParameterList params;
377 
378  if (timingType != "no_timers"){
379  params.set("timer_output_stream" , "std::cout");
380  params.set("timer_type" , timingType);
381  }
382 
383  if (doMemory){
384  params.set("memory_output_stream" , "std::cout");
385  params.set("memory_procs" , memoryProcs);
386  }
387 
388  params.set("debug_output_stream" , "std::cerr");
389  params.set("debug_procs" , "0");
390 
391  if (debugLevel != "basic_status"){
392  params.set("debug_level" , debugLevel);
393  }
394 
395  params.set("algorithm", "rcb");
396  params.set("partitioning_objective", objective);
397  double tolerance = 1.1;
398  params.set("imbalance_tolerance", tolerance );
399 
400  if (numGlobalParts != nprocs)
401  params.set("num_global_parts" , numGlobalParts);
402 
403  if (rank==0){
404  std::cout << "Number of parts: " << numGlobalParts << std::endl;
405  }
406 
407  // Create a problem, solve it, and display the quality.
408 
409  Zoltan2::PartitioningProblem<inputAdapter_t> problem(&(*ia), &params);
410 
411  problem.solve();
412 
413  comm->barrier();
414 
415  problem.printTimers();
416 
417  comm->barrier();
418 
419  if (rank == 0){
420  std::cout << "PASS" << std::endl;
421  }
422 
423  return 0;
424 }
425 
const RCP< tMVector_t > getMeshCoordinates(const RCP< const Teuchos::Comm< int > > &comm, zgno_t numGlobalCoords)
Create a mesh of approximately the desired size.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
int main(int narg, char **arg)
Definition: coloring1.cpp:164
Defines the PartitioningSolution class.
common code used by tests
ArrayRCP< zscalar_t > makeWeights(const RCP< const Teuchos::Comm< int > > &comm, zlno_t len, weightTypes how, zscalar_t scale, int rank)
static RCP< tMVector_t > coordinates
BasicVectorAdapter represents a vector (plus optional weights) supplied by the user as pointers to st...
void printTimers() const
Return the communicator passed to the problem.
Tpetra::Map::local_ordinal_type zlno_t
Tpetra::Map< zlno_t, zgno_t, znode_t > tMap_t
PartitioningProblem sets up partitioning problems for the user.
Defines the PartitioningProblem class.
float zscalar_t
Defines the BasicVectorAdapter class.
Tpetra::MultiVector< zscalar_t, zlno_t, zgno_t, znode_t > tMVector_t
Tpetra::Map::global_ordinal_type zgno_t
void solve(bool updateInputData=true)
Direct the problem to create a solution.
#define MEMORY_CHECK(iPrint, msg)