Zoltan2
Loading...
Searching...
No Matches
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
20
21#include <Teuchos_CommandLineProcessor.hpp>
22
23#include <vector>
24
25using std::vector;
26using std::bad_alloc;
27using Teuchos::RCP;
28using Teuchos::rcp;
29using Teuchos::Comm;
30using Teuchos::ArrayView;
31using Teuchos::ArrayRCP;
32using Teuchos::CommandLineProcessor;
33
34typedef Tpetra::MultiVector<zscalar_t, zlno_t, zgno_t, znode_t> tMVector_t;
35typedef Tpetra::Map<zlno_t, zgno_t, znode_t> tMap_t;
36
43
44ArrayRCP<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
79const 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
216int 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
Defines the BasicVectorAdapter class.
Defines the PartitioningProblem class.
Defines the PartitioningSolution class.
common code used by tests
float zscalar_t
#define MEMORY_CHECK(iPrint, msg)
Tpetra::Map ::local_ordinal_type zlno_t
Tpetra::Map ::global_ordinal_type zgno_t
int main()
BasicVectorAdapter represents a vector (plus optional weights) supplied by the user as pointers to st...
PartitioningProblem sets up partitioning problems for the user.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
void printTimers() const
Return the communicator passed to the problem.
Tpetra::MultiVector< zscalar_t, zlno_t, zgno_t, znode_t > tMVector_t
static RCP< tMVector_t > coordinates
static ArrayRCP< ArrayRCP< zscalar_t > > weights
ArrayRCP< zscalar_t > makeWeights(const RCP< const Teuchos::Comm< int > > &comm, zlno_t len, weightTypes how, zscalar_t scale, int rank)
weightTypes
@ increasing
@ roundRobin
@ upDown
@ numWeightTypes
const RCP< tMVector_t > getMeshCoordinates(const RCP< const Teuchos::Comm< int > > &comm, zgno_t numGlobalCoords)
Create a mesh of approximately the desired size.
Tpetra::Map< zlno_t, zgno_t, znode_t > tMap_t