Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cijk_partition_zoltan_3d.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stokhos Package
4 //
5 // Copyright 2009 NTESS and the Stokhos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Stokhos_Epetra.hpp"
13 #include "Teuchos_toString.hpp"
14 
15 #include <fstream>
16 #include <iostream>
17 
18 extern "C" {
19 #include "zoltan.h"
20 }
21 
22 // Growth policies
23 const int num_growth_types = 2;
26 const char *growth_type_names[] = { "slow", "moderate" };
27 
28 // Product Basis types
30 const int num_prod_basis_types = 4;
33 const char *prod_basis_type_names[] = {
34  "complete", "tensor", "total", "smolyak" };
35 
36 // Ordering types
38 const int num_ordering_types = 2;
41 const char *ordering_type_names[] = {
42  "total", "lexicographic" };
43 
44 // Partitioning types
46 const int num_partitioning_types = 2;
48  RCB, HG_FLAT_J };
49 const char *partitioning_type_names[] = {
50  "rcb", "hg_flat_j" };
51 
52 using Teuchos::rcp;
53 using Teuchos::RCP;
55 using Teuchos::Array;
56 using Teuchos::toString;
57 
58 struct TensorData {
62 };
63 
64 // Functions implementing hypergraph for 3-D decomposition
65 // For this hypergraph model
66 // * the nnz vertices are the Cijk non-zeros
67 // * the 3*n hyperedges are the i, j, and k values
68 // each Cijk non-zero belongs to 3 hyperedges: i, j, and k
69 namespace HG_3D {
70 
71  // Return number of vertices
72  int get_number_of_vertices(void *data, int *ierr) {
73  TensorData *td = static_cast<TensorData*>(data);
74  *ierr = ZOLTAN_OK;
75 
76  return td->Cijk->num_entries();
77  }
78 
79  // Compute IDs and weights of each vertex
80  void get_vertex_list(void *data, int sizeGID, int sizeLID,
81  ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
82  int wgt_dim, float *obj_wgts, int *ierr) {
83  TensorData *td = static_cast<TensorData*>(data);
84  *ierr = ZOLTAN_OK;
85 
86  int nnz = td->Cijk->num_entries();
87  for (int i=0; i<nnz; ++i) {
88  globalID[i] = i;
89  localID[i] = i;
90  }
91 
92  // Do not set weights so Zoltan assumes equally weighted vertices
93  }
94 
95  // Compute number of hyperedges and pins
96  void get_hypergraph_size(void *data, int *num_lists, int *num_pins,
97  int *format, int *ierr) {
98  TensorData *td = static_cast<TensorData*>(data);
99  *ierr = ZOLTAN_OK;
100 
101  //int n = td->basis->size();
102  int nnz = td->Cijk->num_entries();
103 
104  // Number of vertices
105  *num_lists = nnz;
106 
107  // Number of pins. Each nonzero belongs creates 1 pin in 3 hyperedges
108  // thus there are 3*nnz pins
109  *num_pins = 3*nnz;
110 
111  // hypergraph will be stored in compressed-vertex format
112  *format = ZOLTAN_COMPRESSED_VERTEX;
113  }
114 
115  // Compute hypergraph
116  void get_hypergraph(void *data, int sizeGID, int num_vtx, int num_pins,
117  int format, ZOLTAN_ID_PTR vtxGID, int *edgePtr,
118  ZOLTAN_ID_PTR edgeGID, int *ierr) {
119  TensorData *td = static_cast<TensorData*>(data);
120  *ierr = ZOLTAN_OK;
121 
122  int n = td->basis->size();
123 
124  TEUCHOS_ASSERT(sizeGID == 1);
125  TEUCHOS_ASSERT(num_vtx == td->Cijk->num_entries());
126  TEUCHOS_ASSERT(num_pins == 3*(td->Cijk->num_entries()));
127 
128  // Compute pins in each hyperedge stored in compressed-vertex format.
129  // For each vertex we store the GIDs of the 3 edges that it connects to.
130  // Edges are ordered as follows:
131  // [0,n) -- i edges
132  // [n,2*n) -- j edges
133  // [2*n,3*n) -- k edges
134  int vtx_idx = 0;
135  int pin_idx = 0;
138  for (TensorData::Cijk_type::k_iterator k_it=k_begin; k_it!=k_end;
139  ++k_it) {
140  int k = index(k_it);
141  TensorData::Cijk_type::kj_iterator j_begin = td->Cijk->j_begin(k_it);
142  TensorData::Cijk_type::kj_iterator j_end = td->Cijk->j_end(k_it);
143  for (TensorData::Cijk_type::kj_iterator j_it = j_begin; j_it != j_end;
144  ++j_it) {
145  int j = index(j_it);
146  TensorData::Cijk_type::kji_iterator i_begin = td->Cijk->i_begin(j_it);
148  for (TensorData::Cijk_type::kji_iterator i_it = i_begin; i_it != i_end;
149  ++i_it) {
150  int i = index(i_it);
151  vtxGID[vtx_idx] = vtx_idx;
152  edgePtr[vtx_idx++] = pin_idx;
153  edgeGID[pin_idx++] = i;
154  edgeGID[pin_idx++] = n + j;
155  edgeGID[pin_idx++] = 2*n + k;
156  }
157  }
158  }
159  }
160 }
161 
162 
163 int main(int argc, char **argv)
164 {
165  try {
166 
167  // Initialize Zoltan
168  float version;
169  int rc = Zoltan_Initialize(argc,argv,&version);
170  TEUCHOS_ASSERT(rc == 0);
171 
172  // Setup command line options
174  CLP.setDocString(
175  "This example generates the sparsity pattern for the block stochastic Galerkin matrix.\n");
176  int d = 5;
177  CLP.setOption("dimension", &d, "Stochastic dimension");
178  int p = 3;
179  CLP.setOption("order", &p, "Polynomial order");
180  double drop = 1.0e-12;
181  CLP.setOption("drop", &drop, "Drop tolerance");
182  bool symmetric = true;
183  CLP.setOption("symmetric", "asymmetric", &symmetric, "Use basis polynomials with symmetric PDF");
185  CLP.setOption("growth", &growth_type,
187  "Growth type");
188  ProductBasisType prod_basis_type = TOTAL;
189  CLP.setOption("product_basis", &prod_basis_type,
192  "Product basis type");
193  OrderingType ordering_type = LEXICOGRAPHIC_ORDERING;
194  CLP.setOption("ordering", &ordering_type,
197  "Product basis ordering");
198  PartitioningType partitioning_type = RCB;
199  CLP.setOption("partitioning", &partitioning_type,
202  "Partitioning Method");
203  double imbalance_tol = 1.2;
204  CLP.setOption("imbalance", &imbalance_tol, "Imbalance tolerance");
205  bool full = true;
206  CLP.setOption("full", "linear", &full, "Use full or linear expansion");
207  int tile_size = 32;
208  CLP.setOption("tile_size", &tile_size, "Tile size");
209  bool save_3tensor = false;
210  CLP.setOption("save_3tensor", "no-save_3tensor", &save_3tensor,
211  "Save full 3tensor to file");
212  std::string file_3tensor = "Cijk.dat";
213  CLP.setOption("filename_3tensor", &file_3tensor,
214  "Filename to store full 3-tensor");
215 
216  // Parse arguments
217  CLP.parse( argc, argv );
218 
219  // Basis
221  const double alpha = 1.0;
222  const double beta = symmetric ? 1.0 : 2.0 ;
223  for (int i=0; i<d; i++) {
224  bases[i] = rcp(new Stokhos::JacobiBasis<int,double>(
225  p, alpha, beta, true, growth_type));
226  }
230  if (prod_basis_type == COMPLETE)
231  basis =
233  bases, drop));
234  else if (prod_basis_type == TENSOR) {
235  if (ordering_type == TOTAL_ORDERING)
236  basis =
238  bases, drop));
239  else if (ordering_type == LEXICOGRAPHIC_ORDERING)
240  basis =
242  bases, drop));
243  }
244  else if (prod_basis_type == TOTAL) {
245  if (ordering_type == TOTAL_ORDERING)
246  basis =
248  bases, drop));
249  else if (ordering_type == LEXICOGRAPHIC_ORDERING)
250  basis =
252  bases, drop));
253  }
254  else if (prod_basis_type == SMOLYAK) {
255  Stokhos::TotalOrderIndexSet<int> index_set(d, p);
256  if (ordering_type == TOTAL_ORDERING)
257  basis =
259  bases, index_set, drop));
260  else if (ordering_type == LEXICOGRAPHIC_ORDERING)
261  basis =
263  bases, index_set, drop));
264  }
265 
266  // Triple product tensor
268  RCP<Cijk_type> Cijk;
269  if (full)
270  Cijk = basis->computeTripleProductTensor();
271  else
272  Cijk = basis->computeLinearTripleProductTensor();
273 
274  int basis_size = basis->size();
275  std::cout << "basis size = " << basis_size
276  << " num nonzero Cijk entries = " << Cijk->num_entries()
277  << std::endl;
278 
279  // File for saving sparse Cijk tensor and parts
280  std::ofstream cijk_file;
281  if (save_3tensor) {
282  cijk_file.open(file_3tensor.c_str());
283  cijk_file.precision(14);
284  cijk_file.setf(std::ios::scientific);
285  cijk_file << "i, j, k, part" << std::endl;
286  }
287 
288  // Create zoltan
289  Zoltan_Struct *zz = Zoltan_Create(MPI_COMM_WORLD);
290 
291  // Setup Zoltan parameters
292  Zoltan_Set_Param(zz, "DEBUG_LEVEL", "2");
293 
294  // partitioning method
295  Zoltan_Set_Param(zz, "LB_METHOD", "HYPERGRAPH");
296  Zoltan_Set_Param(zz, "HYPERGRAPH_PACKAGE", "PHG"); // version of method
297  Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");// global IDs are integers
298  Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");// local IDs are integers
299  //Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL"); // export AND import lists
300  Zoltan_Set_Param(zz, "RETURN_LISTS", "PARTS");
301  Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0"); // use Zoltan default vertex weights
302  Zoltan_Set_Param(zz, "EDGE_WEIGHT_DIM", "0");// use Zoltan default hyperedge weights
303  int num_parts = basis_size / tile_size;
304  Zoltan_Set_Param(zz, "NUM_GLOBAL_PARTS", toString(num_parts).c_str());
305  Zoltan_Set_Param(zz, "NUM_LOCAL_PARTS", toString(num_parts).c_str());
306  Zoltan_Set_Param(zz, "IMBALANCE_TOL", toString(imbalance_tol).c_str());
307 
308  // Set query functions
309  TensorData td; td.basis = basis; td.Cijk = Cijk;
310  Zoltan_Set_Num_Obj_Fn(zz, HG_3D::get_number_of_vertices, &td);
311  Zoltan_Set_Obj_List_Fn(zz, HG_3D::get_vertex_list, &td);
312  Zoltan_Set_HG_Size_CS_Fn(zz, HG_3D::get_hypergraph_size, &td);
313  Zoltan_Set_HG_CS_Fn(zz, HG_3D::get_hypergraph, &td);
314 
315  // Partition
316  int changes, numGidEntries, numLidEntries, numImport, numExport;
317  ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
318  int *importProcs, *importToPart, *exportProcs, *exportToPart;
319  rc =
320  Zoltan_LB_Partition(
321  zz, // input (all remaining fields are output)
322  &changes, // 1 if partitioning was changed, 0 otherwise
323  &numGidEntries, // Number of integers used for a global ID
324  &numLidEntries, // Number of integers used for a local ID
325  &numImport, // Number of vertices to be sent to me
326  &importGlobalGids, // Global IDs of vertices to be sent to me
327  &importLocalGids, // Local IDs of vertices to be sent to me
328  &importProcs, // Process rank for source of each incoming vertex
329  &importToPart, // New partition for each incoming vertex
330  &numExport, // Number of vertices I must send to other processes*/
331  &exportGlobalGids, // Global IDs of the vertices I must send
332  &exportLocalGids, // Local IDs of the vertices I must send
333  &exportProcs, // Process to which I send each of the vertices
334  &exportToPart); // Partition to which each vertex will belong
335  TEUCHOS_ASSERT(rc == 0);
336 
337  std::cout << "num parts requested = " << num_parts
338  << " changes= " << changes
339  << " num import = " << numImport
340  << " num export = " << numExport << std::endl;
341 
342  // Build list of rows that belong to each part based on diagonal
343  Array< Array<int> > part_map(num_parts);
344  int idx = 0;
345  int num_diag = 0;
346  Cijk_type::k_iterator k_begin = Cijk->k_begin();
347  Cijk_type::k_iterator k_end = Cijk->k_end();
348  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
349  int k = index(k_it);
350  Cijk_type::kj_iterator j_begin = Cijk->j_begin(k_it);
351  Cijk_type::kj_iterator j_end = Cijk->j_end(k_it);
352  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
353  int j = index(j_it);
354  Cijk_type::kji_iterator i_begin = Cijk->i_begin(j_it);
355  Cijk_type::kji_iterator i_end = Cijk->i_end(j_it);
356  for (Cijk_type::kji_iterator i_it = i_begin; i_it != i_end; ++i_it) {
357  int i = index(i_it);
358  if (i == j && j == k) {
359  part_map[ exportToPart[idx] ].push_back(i);
360  ++num_diag;
361  }
362  idx++;
363  }
364  }
365  }
366 
367  std::cout << "basis_size = " << basis_size << " num_diag = " << num_diag
368  << std::endl;
369 
370  // Build permuation array mapping reoredered to original
371  Array<int> perm_new_to_old;
372  for (int part=0; part<num_parts; ++part) {
373  int num_row = part_map[part].size();
374  for (int i=0; i<num_row; ++i)
375  perm_new_to_old.push_back(part_map[part][i]);
376  }
377  TEUCHOS_ASSERT(perm_new_to_old.size() == basis_size);
378 
379  // Build permuation array mapping original to reordered
380  Array<int> perm_old_to_new(basis_size);
381  for (int i=0; i<basis_size; ++i)
382  perm_old_to_new[ perm_new_to_old[i] ] = i;
383 
384  if (save_3tensor) {
385  idx = 0;
386  Cijk_type::k_iterator k_begin = Cijk->k_begin();
387  Cijk_type::k_iterator k_end = Cijk->k_end();
388  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
389  int k = index(k_it);
390  Cijk_type::kj_iterator j_begin = Cijk->j_begin(k_it);
391  Cijk_type::kj_iterator j_end = Cijk->j_end(k_it);
392  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
393  int j = index(j_it);
394  Cijk_type::kji_iterator i_begin = Cijk->i_begin(j_it);
395  Cijk_type::kji_iterator i_end = Cijk->i_end(j_it);
396  for (Cijk_type::kji_iterator i_it = i_begin; i_it != i_end; ++i_it) {
397  int i = index(i_it);
398  cijk_file << perm_old_to_new[i] << ", "
399  << perm_old_to_new[j] << ", "
400  << perm_old_to_new[k] << ", "
401  << exportToPart[idx++] << std::endl;
402  // cijk_file << i << ", "
403  // << j << ", "
404  // << k << ", "
405  // << exportToPart[idx++] << std::endl;
406  }
407  }
408  }
409  cijk_file.close();
410  }
411 
412  // Clean-up
413  Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
414  &importProcs, &importToPart);
415  Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
416  &exportProcs, &exportToPart);
417  Zoltan_Destroy(&zz);
418 
419  //Teuchos::TimeMonitor::summarize(std::cout);
420 
421  }
422  catch (std::exception& e) {
423  std::cout << e.what() << std::endl;
424  }
425 
426  return 0;
427 }
const ProductBasisType prod_basis_type_values[]
void get_hypergraph_size(void *data, int *num_lists, int *num_pins, int *format, int *ierr)
PartitioningType
k_iterator k_begin() const
Iterator pointing to first k entry.
SparseArrayIterator< index_iterator, value_iterator >::value_type index(const SparseArrayIterator< index_iterator, value_iterator > &it)
Multivariate orthogonal polynomial basis generated from a total order tensor product of univariate po...
kj_iterator j_begin(const k_iterator &k) const
Iterator pointing to first j entry for given k.
const int num_prod_basis_types
int get_number_of_vertices(void *data, int *ierr)
GrowthPolicy
Enumerated type for determining Smolyak growth policies.
const char * growth_type_names[]
const OrderingType ordering_type_values[]
const char * partitioning_type_names[]
const char * toString(const EReductionType reductType)
void get_vertex_list(void *data, int sizeGID, int sizeLID, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID, int wgt_dim, float *obj_wgts, int *ierr)
const int num_ordering_types
A comparison functor implementing a strict weak ordering based total-order ordering, recursive on the dimension.
kj_iterator j_end(const k_iterator &k) const
Iterator pointing to last j entry for given k.
Bi-directional iterator for traversing a sparse array.
RCP< const Stokhos::ProductBasis< int, double > > basis
OrderingType
void get_hypergraph(void *data, int sizeGID, int num_vtx, int num_pins, int format, ZOLTAN_ID_PTR vtxGID, int *edgePtr, ZOLTAN_ID_PTR edgeGID, int *ierr)
ProductBasisType
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setOption(const char option_true[], const char option_false[], bool *option_val, const char documentation[]=NULL)
const int num_growth_types
std::string toString(const HashSet< Key > &h)
Jacobi polynomial basis.
EParseCommandLineReturn parse(int argc, char *argv[], std::ostream *errout=&std::cerr) const
const int num_partitioning_types
const Stokhos::GrowthPolicy growth_type_values[]
Multivariate orthogonal polynomial basis generated from a Smolyak sparse grid.
k_iterator k_end() const
Iterator pointing to last k entry.
Multivariate orthogonal polynomial basis generated from a tensor product of univariate polynomials...
Stokhos::Sparse3Tensor< int, double > Cijk_type
int main(int argc, char **argv)
void push_back(const value_type &x)
An isotropic total order index set.
void setDocString(const char doc_string[])
size_type size() const
A comparison functor implementing a strict weak ordering based lexographic ordering.
Stokhos::Sparse3Tensor< int, double > Cijk_type
#define TEUCHOS_ASSERT(assertion_test)
RCP< const Stokhos::Sparse3Tensor< int, double > > Cijk
kji_iterator i_begin(const kj_iterator &j) const
Iterator pointing to first i entry for given j and k.
const char * ordering_type_names[]
kji_iterator i_end(const kj_iterator &j) const
Iterator pointing to last i entry for given j and k.
int n
const char * prod_basis_type_names[]
virtual ordinal_type size() const =0
Return total size of basis.
ordinal_type num_entries() const
Return number of non-zero entries.
const PartitioningType partitioning_type_values[]