Zoltan2
Loading...
Searching...
No Matches
mj_backwardcompat.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
18#include <Tpetra_Map.hpp>
19#include <vector>
20#include <cstdlib>
21
23// Simple adapter with contiguous coordinates
24template <typename User>
26{
27public:
31 typedef typename node_t::device_type device_t;
32
34 const size_t nids_,
35 const gno_t *gids_,
36 const int dim_,
37 const scalar_t *coords_,
38 const scalar_t *weights_ = NULL)
39 : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
40 { }
41
42 size_t getLocalNumIDs() const { return nids; }
43
44 void getIDsView(const gno_t *&ids) const { ids = gids; }
45
46 int getNumWeightsPerID() const { return (weights != NULL); }
47
48 void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
49 { wgt = weights; stride = 1; }
50
51 int getNumEntriesPerID() const { return dim; }
52
53 void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
54 {
55 coo = &(coords[idx*nids]);
56 stride = 1;
57 }
58
59private:
60 const size_t nids;
61 const gno_t *gids;
62 const int dim;
63 const scalar_t *coords;
64 const scalar_t *weights;
65};
66
68// Simple adapter with strided coordinates
69template <typename User>
71{
72public:
75
77 const size_t nids_,
78 const gno_t *gids_,
79 const int dim_,
80 const scalar_t *coords_,
81 const scalar_t *weights_ = NULL)
82 : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
83 { }
84
85 size_t getLocalNumIDs() const { return nids; }
86
87 void getIDsView(const gno_t *&ids) const { ids = gids; }
88
89 int getNumWeightsPerID() const { return (weights != NULL); }
90
91 void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
92 { wgt = weights; stride = 1; }
93
94 int getNumEntriesPerID() const { return dim; }
95
96 void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
97 {
98 coo = &(coords[idx]);
99 stride = dim;
100 }
101
102private:
103 const size_t nids;
104 const gno_t *gids;
105 const int dim;
106 const scalar_t *coords;
107 const scalar_t *weights;
108};
109
111// Same adapter as above but now we supply the Kokkos calls, not the original
112// calls. This is to verify that backwards and forward compatibility are all
113// working properly.
114template <typename User>
116{
117public:
120 typedef Tpetra::Map<>::node_type node_t;
121 typedef typename node_t::device_type device_t;
122
124 const size_t nids_,
125 const gno_t *gids_,
126 const int dim_,
127 const scalar_t *coords_,
128 const scalar_t *weights_ = NULL)
129 : nids(nids_), dim(dim_)
130 {
131 // create kokkos_gids in default memory space
132 {
133 typedef Kokkos::DualView<gno_t *, device_t> view_ids_t;
134 kokkos_gids = view_ids_t(
135 Kokkos::ViewAllocateWithoutInitializing("gids"), nids);
136
137 auto host_gids = kokkos_gids.view_host();
138 for(size_t n = 0; n < nids; ++n) {
139 host_gids(n) = gids_[n];
140 }
141
142 kokkos_gids.template modify<typename view_ids_t::host_mirror_space>();
143 kokkos_gids.sync_host();
144 kokkos_gids.template sync<device_t>();
145 }
146
147 // create kokkos_weights in default memory space
148 if(weights_ != NULL)
149 {
150 typedef Kokkos::DualView<scalar_t **, device_t> view_weights_t;
151 kokkos_weights = view_weights_t(
152 Kokkos::ViewAllocateWithoutInitializing("weights"), nids, 0);
153 auto host_kokkos_weights = kokkos_weights.view_host();
154 for(size_t n = 0; n < nids; ++n) {
155 host_kokkos_weights(n,0) = weights_[n];
156 }
157
158 kokkos_weights.template modify<typename view_weights_t::host_mirror_space>();
159 kokkos_weights.sync_host();
160 kokkos_weights.template sync<device_t>();
161 }
162
163 // create kokkos_coords in default memory space
164 {
165 typedef Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft, device_t> kokkos_coords_t;
166 kokkos_coords = kokkos_coords_t(
167 Kokkos::ViewAllocateWithoutInitializing("coords"), nids, dim);
168 auto host_kokkos_coords = kokkos_coords.view_host();
169
170 for(size_t n = 0; n < nids; ++n) {
171 for(int idx = 0; idx < dim; ++idx) {
172 host_kokkos_coords(n,idx) = coords_[n+idx*nids];
173 }
174 }
175
176 kokkos_coords.template modify<typename kokkos_coords_t::host_mirror_space>();
177 kokkos_coords.sync_host();
178 kokkos_coords.template sync<device_t>();
179 }
180 }
181
182 size_t getLocalNumIDs() const { return nids; }
183
184 void getIDsView(const gno_t *&ids) const override {
185 auto kokkosIds = kokkos_gids.view_host();
186 ids = kokkosIds.data();
187 }
188
189 virtual void getIDsKokkosView(Kokkos::View<const gno_t *, device_t> &ids) const {
190 ids = kokkos_gids.template view<device_t>();
191 }
192
193 int getNumWeightsPerID() const { return (kokkos_weights.view_host().size() != 0); }
194
195 void getWeightsView(const scalar_t *&wgt, int &stride,
196 int idx = 0) const override
197 {
198 auto h_wgts_2d = kokkos_weights.view_host();
199
200 wgt = Kokkos::subview(h_wgts_2d, Kokkos::ALL, idx).data();
201 stride = 1;
202 }
203
204 virtual void getWeightsKokkosView(Kokkos::View<scalar_t **, device_t> & wgt) const {
205 wgt = kokkos_weights.template view<device_t>();
206 }
207
208 int getNumEntriesPerID() const { return dim; }
209
210 void getEntriesView(const scalar_t *&elements,
211 int &stride, int idx = 0) const override {
212 elements = kokkos_coords.view_host().data();
213 stride = 1;
214 }
215
216 virtual void getEntriesKokkosView(Kokkos::View<scalar_t **,
217 Kokkos::LayoutLeft, device_t> & coo) const {
218 coo = kokkos_coords.template view<device_t>();
219 }
220
221private:
222 const size_t nids;
223 Kokkos::DualView<gno_t *, device_t> kokkos_gids;
224 const int dim;
225 Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft, device_t> kokkos_coords;
226 Kokkos::DualView<scalar_t **, device_t> kokkos_weights;
227};
228
230int run_test_strided_versus_contig(const std::string & algorithm) {
231
232 int nFail = 0;
233
234 const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
235
236 int rank = comm->getRank();
237 int nprocs = comm->getSize();
238
239 typedef Tpetra::Map<> Map_t;
240 typedef Map_t::local_ordinal_type localId_t;
241 typedef Map_t::global_ordinal_type globalId_t;
242 typedef double scalar_t;
243
245 typedef OldSchoolVectorAdapterStrided<myTypes> stridedAdapter_t;
246 typedef OldSchoolVectorAdapterContig<myTypes> contigAdapter_t;
247 typedef KokkosVectorAdapter<myTypes> kokkosAdapter_t;
249
251 // Create input data.
252
253 size_t localCount = 40;
254 int dim = 3; // no higher since we are testing rcb as a control which supports dim <= 3
255
256 // Create coordinates strided
257 scalar_t *cStrided = new scalar_t [dim * localCount];
258 size_t cnt = 0;
259 for (size_t i = 0; i < localCount; i++)
260 for (int d = 0; d < dim; d++)
261 cStrided[cnt++] = d*1000 + rank*100 + i;
262
263 // Create same coords, stored contiguously
264 scalar_t *cContig = new scalar_t [dim * localCount];
265 cnt = 0;
266 for (int d = 0; d < dim; d++)
267 for (size_t i = 0; i < localCount; i++)
268 cContig[cnt++] = d*1000 + rank*100 + i;
269
270 // Create global ids for the coordinates.
271 globalId_t *globalIds = new globalId_t [localCount];
272 globalId_t offset = rank * localCount;
273 for (size_t i=0; i < localCount; i++) globalIds[i] = offset++;
274
276 // Create parameters for an MJ problem
277
278 Teuchos::ParameterList params("test params");
279 params.set("debug_level", "basic_status");
280 params.set("error_check_level", "debug_mode_assertions");
281
282 params.set("algorithm", algorithm); // test runs multijagged and rcb
283 params.set("num_global_parts", nprocs+1);
284
286 // Test one: No weights
287
288 // Partition using strided coords
289 stridedAdapter_t *ia1 =
290 new stridedAdapter_t(localCount,globalIds,dim,cStrided);
291
294
295 problem1->solve();
296
297 quality_t *metricObject1 = new quality_t(ia1, &params, comm,
298 &problem1->getSolution());
299 if (rank == 0){
300
301 metricObject1->printMetrics(std::cout);
302
303 double imb = metricObject1->getObjectCountImbalance();
304 if (imb <= 1.03) // Should get perfect balance
305 std::cout << "no weights -- balance satisfied: " << imb << std::endl;
306 else {
307 std::cout << "no weights -- balance failure: " << imb << std::endl;
308 nFail++;
309 }
310 std::cout << std::endl;
311 }
312
313 // Partition using contiguous coords
314 contigAdapter_t *ia2 = new contigAdapter_t(localCount,globalIds,dim,cContig);
315
318
319 problem2->solve();
320
321 // Partition using contiguous coords to generate kokkos adapter
322 kokkosAdapter_t *ia3 = new kokkosAdapter_t(localCount,globalIds,dim,cContig);
323
326
327 problem3->solve();
328
329 // compare strided vs contiguous vs kokkos
330 size_t ndiff = 0;
331 for (size_t i = 0; i < localCount; i++) {
332 if((problem1->getSolution().getPartListView()[i] !=
333 problem2->getSolution().getPartListView()[i]) ||
334 (problem2->getSolution().getPartListView()[i] !=
335 problem3->getSolution().getPartListView()[i]))
336 {
337 std::cout << rank << " Error: differing parts for index " << i
338 << problem1->getSolution().getPartListView()[i] << " "
339 << problem2->getSolution().getPartListView()[i] << " "
340 << problem3->getSolution().getPartListView()[i] << std::endl;
341
342 ndiff++;
343 }
344 }
345 if (ndiff > 0) nFail++;
346 else if (rank == 0) std::cout << "no weights -- comparisons OK " << std::endl;
347
348 delete metricObject1;
349 delete problem1;
350 delete problem2;
351 delete problem3;
352 delete ia1;
353 delete ia2;
354 delete ia3;
355
357 // Test two: weighted
358 // Create a Zoltan2 input adapter that includes weights.
359
360 scalar_t *weights = new scalar_t [localCount];
361 for (size_t i=0; i < localCount; i++) weights[i] = 1 + scalar_t(rank);
362
363 // Test with strided coords
364 ia1 = new stridedAdapter_t(localCount, globalIds, dim, cStrided, weights);
365
366 problem1 = new Zoltan2::PartitioningProblem<stridedAdapter_t>(ia1, &params);
367
368 problem1->solve();
369
370 metricObject1 = new quality_t(ia1, &params, comm, &problem1->getSolution());
371
372 if (rank == 0){
373
374 metricObject1->printMetrics(std::cout);
375
376 double imb = metricObject1->getWeightImbalance(0);
377 if (imb <= 1.03)
378 std::cout << "weighted -- balance satisfied " << imb << std::endl;
379 else {
380 std::cout << "weighted -- balance failed " << imb << std::endl;
381 nFail++;
382 }
383 std::cout << std::endl;
384 }
385
386 // Partition using contiguous coords
387 ia2 = new contigAdapter_t(localCount, globalIds, dim, cContig, weights);
388
389 problem2 = new Zoltan2::PartitioningProblem<contigAdapter_t>(ia2, &params);
390
391 problem2->solve();
392
393 // compare strided vs contiguous
394 ndiff = 0;
395 for (size_t i = 0; i < localCount; i++) {
396 if (problem1->getSolution().getPartListView()[i] !=
397 problem2->getSolution().getPartListView()[i]) {
398 std::cout << rank << " Error: differing parts for index " << i
399 << problem1->getSolution().getPartListView()[i] << " "
400 << problem2->getSolution().getPartListView()[i] << std::endl;
401
402 ndiff++;
403 }
404 }
405 if (ndiff > 0) nFail++;
406 else if (rank == 0) std::cout << "weighted -- comparisons OK " << std::endl;
407
408 delete metricObject1;
409 delete problem1;
410 delete problem2;
411 delete ia1;
412 delete ia2;
413
414 // Test with strided coords
415 if (weights) delete [] weights;
416 if (cStrided) delete [] cStrided;
417 if (cContig) delete [] cContig;
418 if (globalIds) delete [] globalIds;
419
420 // check result
421
422 int gnFail;
423 Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, 1, &nFail, &gnFail);
424 return gnFail;
425}
426
427
428int main(int narg, char *arg[])
429{
430 Tpetra::ScopeGuard scope(&narg, &arg);
431 const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
432
433 int err = 0;
434
435 // err += run_test_strided_versus_contig("multijagged");
436 err += run_test_strided_versus_contig("rcb");
437
438 if (comm->getRank() == 0) {
439 if (err == 0) std::cout << "PASS" << std::endl;
440 else std::cout << "FAIL: " << err << " tests failed" << std::endl;
441 }
442
443 return 0;
444}
445
Traits for application input objects.
Defines the PartitioningProblem class.
Defines the PartitioningSolution class.
Defines the VectorAdapter interface.
int main()
int getNumEntriesPerID() const
Return the number of vectors.
virtual void getEntriesKokkosView(Kokkos::View< scalar_t **, Kokkos::LayoutLeft, device_t > &coo) const
void getIDsView(const gno_t *&ids) const override
virtual void getWeightsKokkosView(Kokkos::View< scalar_t **, device_t > &wgt) const
node_t::device_type device_t
Tpetra::Map ::node_type node_t
void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const override
size_t getLocalNumIDs() const
Returns the number of objects on this process.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater....
KokkosVectorAdapter(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
virtual void getIDsKokkosView(Kokkos::View< const gno_t *, device_t > &ids) const
Zoltan2::InputTraits< User >::gno_t gno_t
Zoltan2::InputTraits< User >::scalar_t scalar_t
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const override
Zoltan2::InputTraits< User >::scalar_t scalar_t
int getNumEntriesPerID() const
Return the number of vectors.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater....
OldSchoolVectorAdapterContig(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
void getIDsView(const gno_t *&ids) const
size_t getLocalNumIDs() const
Returns the number of objects on this process.
Zoltan2::InputTraits< User >::gno_t gno_t
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const
Zoltan2::InputTraits< User >::node_t node_t
void getEntriesView(const scalar_t *&coo, int &stride, int idx=0) const
Zoltan2::InputTraits< User >::scalar_t scalar_t
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater....
size_t getLocalNumIDs() const
Returns the number of objects on this process.
int getNumEntriesPerID() const
Return the number of vectors.
void getIDsView(const gno_t *&ids) const
void getEntriesView(const scalar_t *&coo, int &stride, int idx=0) const
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const
OldSchoolVectorAdapterStrided(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
Zoltan2::InputTraits< User >::gno_t gno_t
A simple class that can be the User template argument for an InputAdapter.
A class that computes and returns quality metrics.
void printMetrics(std::ostream &os) const
Print all metrics.
scalar_t getWeightImbalance(int weightIndex) const
Return the imbalance for the requested weight.
scalar_t getObjectCountImbalance() const
Return the object count imbalance.
PartitioningProblem sets up partitioning problems for the user.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
VectorAdapter defines the interface for vector input.
map_t::global_ordinal_type gno_t
int run_test_strided_versus_contig(const std::string &algorithm)
static ArrayRCP< ArrayRCP< zscalar_t > > weights
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
default_node_t node_t
The Kokkos node type. This is only meaningful for users of Tpetra objects.
default_scalar_t scalar_t
The data type for weights and coordinates.
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t