Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
TaskMappingTest.cpp
Go to the documentation of this file.
1 
5 
6 #include <string>
7 
8 #include <Teuchos_RCP.hpp>
9 #include <Teuchos_Array.hpp>
10 #include <Teuchos_ParameterList.hpp>
11 #include "Teuchos_XMLParameterListHelpers.hpp"
12 
13 #include "Tpetra_MultiVector.hpp"
14 #include <Tpetra_CrsGraph.hpp>
15 #include <Tpetra_Map.hpp>
16 
19 
20 typedef Tpetra::CrsGraph<zlno_t, zgno_t, znode_t> tcrsGraph_t;
21 typedef Tpetra::MultiVector<zscalar_t, zlno_t, zgno_t, znode_t> tMVector_t;
23 
24 
25 int main(int narg, char *arg[]){
26 
27  Tpetra::ScopeGuard tscope(&narg, &arg);
28  Teuchos::RCP<const Teuchos::Comm<int> > tcomm = Tpetra::getDefaultComm();
29 
31 
32  int nx = 2, ny = 2, nz = 2;
33  for ( int i = 1 ; i < narg ; ++i ) {
34  if ( 0 == strcasecmp( arg[i] , "NX" ) ) {
35  nx = atoi( arg[++i] );
36  }
37  else if ( 0 == strcasecmp( arg[i] , "NY" ) ) {
38  ny = atoi( arg[++i] );
39  }
40  else if ( 0 == strcasecmp( arg[i] , "NZ" ) ) {
41  nz = atoi( arg[++i] );
42  }
43  else{
44  std::cerr << "Unrecognized command line argument #" << i << ": " << arg[i] << std::endl ;
45  return 1;
46  }
47  }
48 
49 
50  try{
51 
52 
53  int rank = tcomm->getRank();
54  part_t numProcs = tcomm->getSize();
55 
56  int coordDim = 3;
57  zgno_t numGlobalTasks = nx*ny*nz;
58 
59  zgno_t myTasks = numGlobalTasks / numProcs;
60  zgno_t taskLeftOver = numGlobalTasks % numProcs;
61  if (rank < taskLeftOver ) ++myTasks;
62 
63  zgno_t myTaskBegin = (numGlobalTasks / numProcs) * rank;
64  myTaskBegin += (taskLeftOver < rank ? taskLeftOver : rank);
65  zgno_t myTaskEnd = myTaskBegin + myTasks;
66 
67  zscalar_t **partCenters = NULL;
68  partCenters = new zscalar_t * [coordDim];
69  for(int i = 0; i < coordDim; ++i){
70  partCenters[i] = new zscalar_t[myTasks];
71  }
72 
73 
74  zgno_t *task_gnos = new zgno_t [myTasks];
75  zlno_t *task_communication_xadj_ = new zlno_t [myTasks+1];
76  zgno_t *task_communication_adj_ = new zgno_t [myTasks * 6];
77 
78  zlno_t prevNCount = 0;
79  task_communication_xadj_[0] = 0;
80  for (zlno_t i = myTaskBegin; i < myTaskEnd; ++i) {
81  task_gnos[i - myTaskBegin] = i;
82 
83  zlno_t x = i % nx;
84  zlno_t y = (i / (nx)) % ny;
85  zlno_t z = (i / (nx)) / ny;
86  partCenters[0][i - myTaskBegin] = x;
87  partCenters[1][i - myTaskBegin] = y;
88  partCenters[2][i - myTaskBegin] = z;
89 
90 
91 
92  if (x > 0){
93  task_communication_adj_[prevNCount++] = i - 1;
94  }
95  if (x < nx - 1){
96  task_communication_adj_[prevNCount++] = i + 1;
97  }
98  if (y > 0){
99  task_communication_adj_[prevNCount++] = i - nx;
100  }
101  if (y < ny - 1){
102  task_communication_adj_[prevNCount++] = i + nx;
103  }
104  if (z > 0){
105  task_communication_adj_[prevNCount++] = i - nx * ny;
106  }
107  if (z < nz - 1){
108  task_communication_adj_[prevNCount++] = i + nx * ny;
109  }
110  task_communication_xadj_[i+1 - myTaskBegin] = prevNCount;
111  }
112  using namespace Teuchos;
113  RCP<my_adapter_t> ia;
114  typedef Tpetra::Map<>::node_type mytest_znode_t;
115  typedef Tpetra::Map<zlno_t, zgno_t, mytest_znode_t> map_t;
116  RCP<const map_t> map = rcp (new map_t (numGlobalTasks, myTasks, 0, tcomm));
117 
118  RCP<tcrsGraph_t> TpetraCrsGraph(new tcrsGraph_t (map, 0));
119 
120 
121  for (zlno_t lclRow = 0; lclRow < myTasks; ++lclRow) {
122  const zgno_t gblRow = map->getGlobalElement (lclRow);
123  zgno_t begin = task_communication_xadj_[lclRow];
124  zgno_t end = task_communication_xadj_[lclRow + 1];
125  const ArrayView< const zgno_t > indices(task_communication_adj_+begin, end-begin);
126  TpetraCrsGraph->insertGlobalIndices(gblRow, indices);
127  }
128  TpetraCrsGraph->fillComplete ();
129  RCP<const tcrsGraph_t> const_data = rcp_const_cast<const tcrsGraph_t>(TpetraCrsGraph);
130 
131  ia = RCP<my_adapter_t> (new my_adapter_t(const_data));
132 
133  const int coord_dim = 3;
134  Teuchos::Array<Teuchos::ArrayView<const zscalar_t> > coordView(coord_dim);
135 
136  if(myTasks > 0){
137  Teuchos::ArrayView<const zscalar_t> a(partCenters[0], myTasks);
138  coordView[0] = a;
139  Teuchos::ArrayView<const zscalar_t> b(partCenters[1], myTasks);
140  coordView[1] = b;
141  Teuchos::ArrayView<const zscalar_t> c(partCenters[2], myTasks);
142  coordView[2] = c;
143  }
144  else {
145  Teuchos::ArrayView<const zscalar_t> a;
146  coordView[0] = a;
147  coordView[1] = a;
148  coordView[2] = a;
149  }
150  RCP<tMVector_t> coords(new tMVector_t(map, coordView.view(0, coord_dim), coord_dim));//= set multivector;
151  RCP<const tMVector_t> const_coords = rcp_const_cast<const tMVector_t>(coords);
152  RCP <Zoltan2::XpetraMultiVectorAdapter<tMVector_t> > adapter (new Zoltan2::XpetraMultiVectorAdapter<tMVector_t>(const_coords));
153  ia->setCoordinateInput(adapter.getRawPtr());
154 
155 
156  //return ia;
157 
158 
159 
160 
161  //create input adapter
162  //RCP<my_adapter_t> ia = create_problem(tcomm, nx, ny, nz);
163 
164  //create partitioning problem
165  typedef Zoltan2::PartitioningProblem<my_adapter_t> xcrsGraph_problem_t; // xpetra_graph problem type
167  ParameterList zoltan2_parameters;
168  zoltan2_parameters.set("compute_metrics", true); // bool parameter
169  zoltan2_parameters.set("imbalance_tolerance", 1.0);
170  zoltan2_parameters.set("num_global_parts", tcomm->getSize());
171  zoltan2_parameters.set("algorithm", "multijagged");
172  zoltan2_parameters.set("mj_keep_part_boxes", false); // bool parameter
173  zoltan2_parameters.set("mj_recursion_depth", 3);
174  RCP<xcrsGraph_problem_t> partition_problem;
175  partition_problem = RCP<xcrsGraph_problem_t> (new xcrsGraph_problem_t(ia.getRawPtr(),&zoltan2_parameters,tcomm));
176 
177  //solve the partitioning problem.
178  partition_problem->solve();
179  tcomm->barrier();
180  RCP<const Zoltan2::Environment> env = partition_problem->getEnvironment();
181 
182  RCP<quality_t>metricObject =
183  rcp(new quality_t(ia.getRawPtr(), &zoltan2_parameters, tcomm,
184  &partition_problem->getSolution()));
185 
186  if (tcomm->getRank() == 0){
187  metricObject->printMetrics(std::cout);
188  }
189  partition_problem->printTimers();
190 
191  part_t *proc_to_task_xadj_ = NULL;
192  part_t *proc_to_task_adj_ = NULL;
193 
194  //create the zoltan2 machine representation object
196 
197  //create the mapper and map the partitioning solution.
199  tcomm,
200  Teuchos::rcpFromRef(mach),
201  ia,
202  rcpFromRef(partition_problem->getSolution()),
203  env);
204 
205  //get the results and print
206  ctm.getProcTask(proc_to_task_xadj_, proc_to_task_adj_);
207  //part_t numProcs = tcomm->getSize();
208  if (tcomm->getRank() == 0){
209  for (part_t i = 0; i < numProcs; ++i){
210  std::cout << "\nProc i:" << i << " ";
211  for (part_t j = proc_to_task_xadj_[i]; j < proc_to_task_xadj_[i+1]; ++j){
212  std::cout << " " << proc_to_task_adj_[j];
213  }
214  }
215  std::cout << std::endl;
216  }
217 
218  //below is to calculate the result hops. this uses the global graph
219  //also this is used for debug, as the hops are also calculated in mapper.
220  {
221 
222  zlno_t prevNCount_tmp = 0;
223  zgno_t *task_communication_adj_tmp = new zgno_t [numGlobalTasks * 6];
224  zlno_t *task_communication_xadj_tmp = new zlno_t [numGlobalTasks+1];
225  task_communication_xadj_tmp[0] = 0;
226  for (zlno_t i = 0; i < numGlobalTasks; ++i) {
227  zlno_t x = i % nx;
228  zlno_t y = (i / (nx)) % ny;
229  zlno_t z = (i / (nx)) / ny;
230 
231  if (x > 0){
232  task_communication_adj_tmp[prevNCount_tmp++] = i - 1;
233  }
234  if (x < nx - 1){
235  task_communication_adj_tmp[prevNCount_tmp++] = i + 1;
236  }
237  if (y > 0){
238  task_communication_adj_tmp[prevNCount_tmp++] = i - nx;
239  }
240  if (y < ny - 1){
241  task_communication_adj_tmp[prevNCount_tmp++] = i + nx;
242  }
243  if (z > 0){
244  task_communication_adj_tmp[prevNCount_tmp++] = i - nx * ny;
245  }
246  if (z < nz - 1){
247  task_communication_adj_tmp[prevNCount_tmp++] = i + nx * ny;
248  }
249  task_communication_xadj_tmp[i+1] = prevNCount_tmp;
250  }
251 
252  int mach_coord_dim = mach.getMachineDim();
253  std::vector <int> mach_extent(mach_coord_dim);
254  mach.getMachineExtent(&(mach_extent[0]));
255 
256  std::vector <part_t> all_parts(numGlobalTasks), copy(numGlobalTasks, 0);
257 
258  const part_t *parts = partition_problem->getSolution().getPartListView();
259 
260  //typedef Tpetra::Map<>::node_type mytest_znode_t;
261  //typedef Tpetra::Map<zlno_t, zgno_t, mytest_znode_t> map_t;
262  //RCP<const map_t> map = rcp (new map_t (numGlobalTasks, myTasks, 0, tcomm));
263  for (part_t i = 0; i < myTasks; ++i){
264  zgno_t g = map->getGlobalElement(i);
265  copy[g] = parts[i];
266  }
267 
268  reduceAll<int, part_t>(
269  *tcomm,
270  Teuchos::REDUCE_SUM,
271  numGlobalTasks,
272  &(copy[0]),
273  &(all_parts[0])
274  );
275 
276  zscalar_t **proc_coords;
277  mach.getAllMachineCoordinatesView(proc_coords);
278  part_t hops=0;
279  part_t hops2 = 0;
280  int *machine_extent = new int [mach_coord_dim];
281  bool *machine_extent_wrap_around = new bool[mach_coord_dim];
282 
283  mach.getMachineExtent(machine_extent);
284  mach.getMachineExtentWrapArounds(machine_extent_wrap_around);
285 
286  for (zlno_t i = 0; i < numGlobalTasks; ++i){
287  zlno_t b = task_communication_xadj_tmp[i];
288  zlno_t e = task_communication_xadj_tmp[i+1];
289 
290  part_t procId1 = ctm.getAssignedProcForTask(all_parts[i]);
291 
292  for (zlno_t j = b; j < e; ++j){
293  zgno_t n = task_communication_adj_tmp[j];
294  part_t procId2 = ctm.getAssignedProcForTask(all_parts[n]);
295 
296  zscalar_t distance2 = 0;
297  mach.getHopCount(procId1, procId2, distance2);
298  hops2 += distance2;
299  for (int k = 0 ; k < mach_coord_dim ; ++k){
300  part_t distance = ZOLTAN2_ABS(proc_coords[k][procId1] - proc_coords[k][procId2]);
301  if (machine_extent_wrap_around[k]){
302  if (machine_extent[k] - distance < distance){
303  distance = machine_extent[k] - distance;
304  }
305  }
306  hops += distance;
307  }
308  }
309  }
310  delete [] machine_extent_wrap_around;
311  delete [] machine_extent;
312 
313  if (tcomm->getRank() == 0)
314  std::cout << "HOPS:" << hops << " HOPS2:" << hops2 << std::endl;
315 
316  delete [] task_communication_xadj_tmp;
317  delete [] task_communication_adj_tmp;
318  }
319  /*
320  part_t *machineDimensions = NULL;
321  //machineDimensions = hopper;
322  Zoltan2::coordinateTaskMapperInterface<part_t, zscalar_t, zscalar_t>(
323  tcomm,
324  procDim,
325  numProcs,
326  procCoordinates,
327 
328  coordDim,
329  numGlobalTasks,
330  partCenters,
331 
332  task_communication_xadj_,
333  task_communication_adj_,
334  NULL,
335 
336  proc_to_task_xadj_,
337  proc_to_task_adj_,
338 
339  partArraysize,
340  partArray,
341  machineDimensions
342  );
343  */
344 
345  if (tcomm->getRank() == 0){
346  std::cout << "PASS" << std::endl;
347  }
348 
349 
350  for (int i = 0; i < coordDim; i++) delete [] partCenters[i];
351  delete [] partCenters;
352 
353  }
354  catch(std::string &s){
355  std::cerr << s << std::endl;
356  }
357 
358  catch(char * s){
359  std::cerr << s << std::endl;
360  }
361 }
362 
Zoltan2::XpetraCrsGraphAdapter< tcrsGraph_t, tMVector_t > my_adapter_t
bool getHopCount(int rank1, int rank2, pcoord_t &hops) const
int main(int narg, char *arg[])
double zscalar_t
Provides access for Zoltan2 to Xpetra::CrsGraph data.
int zlno_t
common code used by tests
Tpetra::Map::node_type mytest_znode_t
part_t getAssignedProcForTask(part_t taskId)
getAssignedProcForTask function, returns the assigned processor id for the given task ...
Defines the XpetraMultiVectorAdapter.
Defines XpetraCrsGraphAdapter class.
SparseMatrixAdapter_t::part_t part_t
int getMachineDim() const
returns the dimension (number of coords per node) in the machine
bool getAllMachineCoordinatesView(pcoord_t **&allCoords) const
getProcDim function set the coordinates of all ranks allCoords[i][j], i=0,...,getMachineDim(), j=0,...,getNumRanks(), is the i-th dimensional coordinate for rank j. return true if coordinates are available for all ranks
void getProcTask(part_t *&proc_to_task_xadj_, part_t *&proc_to_task_adj_)
#define ZOLTAN2_ABS(x)
Tpetra::CrsGraph< zlno_t, zgno_t, znode_t > tcrsGraph_t
Definition: GraphModel.cpp:83
bool getMachineExtentWrapArounds(bool *wrap_around) const
if the machine has a wrap-around tourus link in each dimension. return true if the information is ava...
InputTraits< User >::part_t part_t
An adapter for Xpetra::MultiVector.
MachineRepresentation Class Base class for representing machine coordinates, networks, etc.
int zgno_t
PartitioningProblem sets up partitioning problems for the user.
Tpetra::MultiVector< double, int, int > tMVector_t
Defines the PartitioningProblem class.
A class that computes and returns quality metrics.
bool getMachineExtent(int *nxyz) const
sets the number of unique coordinates in each machine dimension return true if coordinates are availa...