Zoltan2
Loading...
Searching...
No Matches
mj_backwardcompat.cpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// Zoltan2: A package of combinatorial algorithms for scientific computing
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 Karen Devine (kddevin@sandia.gov)
39// Erik Boman (egboman@sandia.gov)
40// Siva Rajamanickam (srajama@sandia.gov)
41//
42// ***********************************************************************
43//
44// @HEADER
45
54#include <Tpetra_Map.hpp>
55#include <vector>
56#include <cstdlib>
57
59// Simple adapter with contiguous coordinates
60template <typename User>
62{
63public:
67 typedef typename node_t::device_type device_t;
68
70 const size_t nids_,
71 const gno_t *gids_,
72 const int dim_,
73 const scalar_t *coords_,
74 const scalar_t *weights_ = NULL)
75 : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
76 { }
77
78 size_t getLocalNumIDs() const { return nids; }
79
80 void getIDsView(const gno_t *&ids) const { ids = gids; }
81
82 int getNumWeightsPerID() const { return (weights != NULL); }
83
84 void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
85 { wgt = weights; stride = 1; }
86
87 int getNumEntriesPerID() const { return dim; }
88
89 void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
90 {
91 coo = &(coords[idx*nids]);
92 stride = 1;
93 }
94
95private:
96 const size_t nids;
97 const gno_t *gids;
98 const int dim;
99 const scalar_t *coords;
100 const scalar_t *weights;
101};
102
104// Simple adapter with strided coordinates
105template <typename User>
107{
108public:
111
113 const size_t nids_,
114 const gno_t *gids_,
115 const int dim_,
116 const scalar_t *coords_,
117 const scalar_t *weights_ = NULL)
118 : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
119 { }
120
121 size_t getLocalNumIDs() const { return nids; }
122
123 void getIDsView(const gno_t *&ids) const { ids = gids; }
124
125 int getNumWeightsPerID() const { return (weights != NULL); }
126
127 void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
128 { wgt = weights; stride = 1; }
129
130 int getNumEntriesPerID() const { return dim; }
131
132 void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
133 {
134 coo = &(coords[idx]);
135 stride = dim;
136 }
137
138private:
139 const size_t nids;
140 const gno_t *gids;
141 const int dim;
142 const scalar_t *coords;
143 const scalar_t *weights;
144};
145
147// Same adapter as above but now we supply the Kokkos calls, not the original
148// calls. This is to verify that backwards and forward compatibility are all
149// working properly.
150template <typename User>
152{
153public:
156 typedef Tpetra::Map<>::node_type node_t;
157 typedef typename node_t::device_type device_t;
158
160 const size_t nids_,
161 const gno_t *gids_,
162 const int dim_,
163 const scalar_t *coords_,
164 const scalar_t *weights_ = NULL)
165 : nids(nids_), dim(dim_)
166 {
167 // create kokkos_gids in default memory space
168 {
169 typedef Kokkos::DualView<gno_t *, device_t> view_ids_t;
170 kokkos_gids = view_ids_t(
171 Kokkos::ViewAllocateWithoutInitializing("gids"), nids);
172
173 auto host_gids = kokkos_gids.h_view;
174 for(size_t n = 0; n < nids; ++n) {
175 host_gids(n) = gids_[n];
176 }
177
178 kokkos_gids.template modify<typename view_ids_t::host_mirror_space>();
179 kokkos_gids.sync_host();
180 kokkos_gids.template sync<device_t>();
181 }
182
183 // create kokkos_weights in default memory space
184 if(weights_ != NULL)
185 {
186 typedef Kokkos::DualView<scalar_t **, device_t> view_weights_t;
187 kokkos_weights = view_weights_t(
188 Kokkos::ViewAllocateWithoutInitializing("weights"), nids, 0);
189 auto host_kokkos_weights = kokkos_weights.h_view;
190 for(size_t n = 0; n < nids; ++n) {
191 host_kokkos_weights(n,0) = weights_[n];
192 }
193
194 kokkos_weights.template modify<typename view_weights_t::host_mirror_space>();
195 kokkos_weights.sync_host();
196 kokkos_weights.template sync<device_t>();
197 }
198
199 // create kokkos_coords in default memory space
200 {
201 typedef Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft, device_t> kokkos_coords_t;
202 kokkos_coords = kokkos_coords_t(
203 Kokkos::ViewAllocateWithoutInitializing("coords"), nids, dim);
204 auto host_kokkos_coords = kokkos_coords.h_view;
205
206 for(size_t n = 0; n < nids; ++n) {
207 for(int idx = 0; idx < dim; ++idx) {
208 host_kokkos_coords(n,idx) = coords_[n+idx*nids];
209 }
210 }
211
212 kokkos_coords.template modify<typename kokkos_coords_t::host_mirror_space>();
213 kokkos_coords.sync_host();
214 kokkos_coords.template sync<device_t>();
215 }
216 }
217
218 size_t getLocalNumIDs() const { return nids; }
219
220 void getIDsView(const gno_t *&ids) const override {
221 auto kokkosIds = kokkos_gids.view_host();
222 ids = kokkosIds.data();
223 }
224
225 virtual void getIDsKokkosView(Kokkos::View<const gno_t *, device_t> &ids) const {
226 ids = kokkos_gids.template view<device_t>();
227 }
228
229 int getNumWeightsPerID() const { return (kokkos_weights.h_view.size() != 0); }
230
231 void getWeightsView(const scalar_t *&wgt, int &stride,
232 int idx = 0) const override
233 {
234 auto h_wgts_2d = kokkos_weights.view_host();
235
236 wgt = Kokkos::subview(h_wgts_2d, Kokkos::ALL, idx).data();
237 stride = 1;
238 }
239
240 virtual void getWeightsKokkosView(Kokkos::View<scalar_t **, device_t> & wgt) const {
241 wgt = kokkos_weights.template view<device_t>();
242 }
243
244 int getNumEntriesPerID() const { return dim; }
245
246 void getEntriesView(const scalar_t *&elements,
247 int &stride, int idx = 0) const override {
248 elements = kokkos_coords.view_host().data();
249 stride = 1;
250 }
251
252 virtual void getEntriesKokkosView(Kokkos::View<scalar_t **,
253 Kokkos::LayoutLeft, device_t> & coo) const {
254 coo = kokkos_coords.template view<device_t>();
255 }
256
257private:
258 const size_t nids;
259 Kokkos::DualView<gno_t *, device_t> kokkos_gids;
260 const int dim;
261 Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft, device_t> kokkos_coords;
262 Kokkos::DualView<scalar_t **, device_t> kokkos_weights;
263};
264
266int run_test_strided_versus_contig(const std::string & algorithm) {
267
268 int nFail = 0;
269
270 const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
271
272 int rank = comm->getRank();
273 int nprocs = comm->getSize();
274
275 typedef Tpetra::Map<> Map_t;
276 typedef Map_t::local_ordinal_type localId_t;
277 typedef Map_t::global_ordinal_type globalId_t;
278 typedef double scalar_t;
279
281 typedef OldSchoolVectorAdapterStrided<myTypes> stridedAdapter_t;
282 typedef OldSchoolVectorAdapterContig<myTypes> contigAdapter_t;
283 typedef KokkosVectorAdapter<myTypes> kokkosAdapter_t;
285
287 // Create input data.
288
289 size_t localCount = 40;
290 int dim = 3; // no higher since we are testing rcb as a control which supports dim <= 3
291
292 // Create coordinates strided
293 scalar_t *cStrided = new scalar_t [dim * localCount];
294 size_t cnt = 0;
295 for (size_t i = 0; i < localCount; i++)
296 for (int d = 0; d < dim; d++)
297 cStrided[cnt++] = d*1000 + rank*100 + i;
298
299 // Create same coords, stored contiguously
300 scalar_t *cContig = new scalar_t [dim * localCount];
301 cnt = 0;
302 for (int d = 0; d < dim; d++)
303 for (size_t i = 0; i < localCount; i++)
304 cContig[cnt++] = d*1000 + rank*100 + i;
305
306 // Create global ids for the coordinates.
307 globalId_t *globalIds = new globalId_t [localCount];
308 globalId_t offset = rank * localCount;
309 for (size_t i=0; i < localCount; i++) globalIds[i] = offset++;
310
312 // Create parameters for an MJ problem
313
314 Teuchos::ParameterList params("test params");
315 params.set("debug_level", "basic_status");
316 params.set("error_check_level", "debug_mode_assertions");
317
318 params.set("algorithm", algorithm); // test runs multijagged and rcb
319 params.set("num_global_parts", nprocs+1);
320
322 // Test one: No weights
323
324 // Partition using strided coords
325 stridedAdapter_t *ia1 =
326 new stridedAdapter_t(localCount,globalIds,dim,cStrided);
327
330
331 problem1->solve();
332
333 quality_t *metricObject1 = new quality_t(ia1, &params, comm,
334 &problem1->getSolution());
335 if (rank == 0){
336
337 metricObject1->printMetrics(std::cout);
338
339 double imb = metricObject1->getObjectCountImbalance();
340 if (imb <= 1.03) // Should get perfect balance
341 std::cout << "no weights -- balance satisfied: " << imb << std::endl;
342 else {
343 std::cout << "no weights -- balance failure: " << imb << std::endl;
344 nFail++;
345 }
346 std::cout << std::endl;
347 }
348
349 // Partition using contiguous coords
350 contigAdapter_t *ia2 = new contigAdapter_t(localCount,globalIds,dim,cContig);
351
354
355 problem2->solve();
356
357 // Partition using contiguous coords to generate kokkos adapter
358 kokkosAdapter_t *ia3 = new kokkosAdapter_t(localCount,globalIds,dim,cContig);
359
362
363 problem3->solve();
364
365 // compare strided vs contiguous vs kokkos
366 size_t ndiff = 0;
367 for (size_t i = 0; i < localCount; i++) {
368 if((problem1->getSolution().getPartListView()[i] !=
369 problem2->getSolution().getPartListView()[i]) ||
370 (problem2->getSolution().getPartListView()[i] !=
371 problem3->getSolution().getPartListView()[i]))
372 {
373 std::cout << rank << " Error: differing parts for index " << i
374 << problem1->getSolution().getPartListView()[i] << " "
375 << problem2->getSolution().getPartListView()[i] << " "
376 << problem3->getSolution().getPartListView()[i] << std::endl;
377
378 ndiff++;
379 }
380 }
381 if (ndiff > 0) nFail++;
382 else if (rank == 0) std::cout << "no weights -- comparisons OK " << std::endl;
383
384 delete metricObject1;
385 delete problem1;
386 delete problem2;
387 delete problem3;
388 delete ia1;
389 delete ia2;
390 delete ia3;
391
393 // Test two: weighted
394 // Create a Zoltan2 input adapter that includes weights.
395
396 scalar_t *weights = new scalar_t [localCount];
397 for (size_t i=0; i < localCount; i++) weights[i] = 1 + scalar_t(rank);
398
399 // Test with strided coords
400 ia1 = new stridedAdapter_t(localCount, globalIds, dim, cStrided, weights);
401
402 problem1 = new Zoltan2::PartitioningProblem<stridedAdapter_t>(ia1, &params);
403
404 problem1->solve();
405
406 metricObject1 = new quality_t(ia1, &params, comm, &problem1->getSolution());
407
408 if (rank == 0){
409
410 metricObject1->printMetrics(std::cout);
411
412 double imb = metricObject1->getWeightImbalance(0);
413 if (imb <= 1.03)
414 std::cout << "weighted -- balance satisfied " << imb << std::endl;
415 else {
416 std::cout << "weighted -- balance failed " << imb << std::endl;
417 nFail++;
418 }
419 std::cout << std::endl;
420 }
421
422 // Partition using contiguous coords
423 ia2 = new contigAdapter_t(localCount, globalIds, dim, cContig, weights);
424
425 problem2 = new Zoltan2::PartitioningProblem<contigAdapter_t>(ia2, &params);
426
427 problem2->solve();
428
429 // compare strided vs contiguous
430 ndiff = 0;
431 for (size_t i = 0; i < localCount; i++) {
432 if (problem1->getSolution().getPartListView()[i] !=
433 problem2->getSolution().getPartListView()[i]) {
434 std::cout << rank << " Error: differing parts for index " << i
435 << problem1->getSolution().getPartListView()[i] << " "
436 << problem2->getSolution().getPartListView()[i] << std::endl;
437
438 ndiff++;
439 }
440 }
441 if (ndiff > 0) nFail++;
442 else if (rank == 0) std::cout << "weighted -- comparisons OK " << std::endl;
443
444 delete metricObject1;
445 delete problem1;
446 delete problem2;
447 delete ia1;
448 delete ia2;
449
450 // Test with strided coords
451 if (weights) delete [] weights;
452 if (cStrided) delete [] cStrided;
453 if (cContig) delete [] cContig;
454 if (globalIds) delete [] globalIds;
455
456 // check result
457
458 int gnFail;
459 Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, 1, &nFail, &gnFail);
460 return gnFail;
461}
462
463
464int main(int narg, char *arg[])
465{
466 Tpetra::ScopeGuard scope(&narg, &arg);
467 const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
468
469 int err = 0;
470
471 // err += run_test_strided_versus_contig("multijagged");
472 err += run_test_strided_versus_contig("rcb");
473
474 if (comm->getRank() == 0) {
475 if (err == 0) std::cout << "PASS" << std::endl;
476 else std::cout << "FAIL: " << err << " tests failed" << std::endl;
477 }
478
479 return 0;
480}
481
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
Definition: mapRemotes.cpp:18
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