Flow123d
partitioning.cc
Go to the documentation of this file.
1 /*
2  * partitioning.cc
3  *
4  * Created on: May 3, 2013
5  * Author: jb
6  */
7 
8 #include "mesh/partitioning.hh"
9 #include "mesh/mesh.h"
10 #include "la/sparse_graph.hh"
11 #include "la/distribution.hh"
12 
13 #include "petscao.h"
14 
15 
16 namespace IT = Input::Type;
18  =IT::Selection("GraphType",
19  "Different algorithms to make the sparse graph with weighted edges\n"
20  "from the multidimensional mesh. Main difference is dealing with \n"
21  "neighborings of elements of different dimension.")
22  .add_value(any_neighboring, "any_neighboring", "Add edge for any pair of neighboring elements.")
23  .add_value(any_weight_lower_dim_cuts, "any_wight_lower_dim_cuts", "Same as before and assign higher weight to cuts of lower dimension in order to make them stick to one face.")
24  .add_value(same_dimension_neighboring, "same_dimension_neghboring", "Add edge for any pair of neighboring elements of same dimension (bad for matrix multiply).")
25  .close();
26 
28  =IT::Selection("PartTool", "Select the partitioning tool to use.")
29  .add_value(PETSc, "PETSc", "Use PETSc interface to various partitioning tools.")
30  .add_value(METIS, "METIS", "Use direct interface to Metis.")
31  .close();
32 
34  = IT::Record("Partition","Setting for various types of mesh partitioning." )
35  .declare_key("tool", Partitioning::tool_sel, IT::Default("METIS"), "Software package used for partitioning. See corresponding selection.")
36  .declare_key("graph_type", Partitioning::graph_type_sel, IT::Default("any_neighboring"), "Algorithm for generating graph and its weights from a multidimensional mesh.")
37  .allow_auto_conversion("graph_type") // mainly in order to allow Default value for the whole record Partition
38  .close();
39 
40 
42 : mesh_(mesh), in_(in), graph_(NULL), loc_part_(NULL), init_el_ds_(NULL)
43 {
45 }
46 
47 
48 
50  if (loc_part_) delete [] loc_part_;
51  loc_part_ = NULL;
52  if (init_el_ds_) delete init_el_ds_;
53  init_el_ds_ = NULL;
54  if (graph_) delete graph_;
55  graph_ = NULL;
56 }
57 
59  ASSERT(init_el_ds_, "NULL initial distribution.");
60  return init_el_ds_;
61 }
62 
63 
64 
65 const int * Partitioning::get_loc_part() const {
66  ASSERT(loc_part_, "NULL local partitioning.");
67  return loc_part_;
68 }
69 
70 
71 
73 
74  Distribution edistr = graph_->get_distr();
75 
76  Edge *edg;
77  int li, e_idx, i_neigh;
78  int i_s, n_s;
79  F_ENTRY;
80 
81  // Add nigbouring edges only for "any_*" graph types
82  bool neigh_on = ( in_.val<PartitionGraphType>("graph_type") != same_dimension_neighboring );
83 
84  FOR_ELEMENTS( mesh_, ele) {
85  //xprintf(Msg,"Element id %d , its index %d.\n",ele.id(), i_ele);
86 
87  // skip non-local elements
88  if (!edistr.is_local(ele.index()))
89  continue;
90 
91  // for all connected elements
92  FOR_ELEMENT_SIDES( ele, si ) {
93  edg = ele->side(si)->edge();
94 
95  FOR_EDGE_SIDES( edg, li ) {
96  ASSERT(edg->side(li)->valid(),"NULL side of edge.");
97  e_idx = ELEMENT_FULL_ITER(mesh_, edg->side(li)->element()).index();
98 
99  // for elements of connected elements, excluding element itself
100  if (e_idx != ele.index()) {
101  graph_->set_edge(ele.index(), e_idx);
102  }
103  }
104  }
105 
106  // include connections from lower dim. edge
107  // to the higher dimension
108  if (neigh_on) {
109  for (i_neigh = 0; i_neigh < ele->n_neighs_vb; i_neigh++) {
110  n_s = ele->neigh_vb[i_neigh]->edge()->n_sides;
111  for (i_s = 0; i_s < n_s; i_s++) {
112  e_idx=ELEMENT_FULL_ITER(mesh_, ele->neigh_vb[i_neigh]->edge()->side(i_s)->element()).index();
113  graph_->set_edge(ele.index(), e_idx);
114  graph_->set_edge(e_idx, ele.index());
115  }
116  }
117  }
118  }
119  graph_->finalize();
120 }
121 
122 
123 
125  // prepare dual graph
126  switch ( in_.val<PartitionTool>("tool")) {
127  case PETSc:
128  init_el_ds_ = new Distribution(DistributionBlock(), mesh_->n_elements(), mesh_->get_comm() ); // initial distr.
130 
131  break;
132  case METIS:
133  init_el_ds_ = new Distribution(DistributionLocalized(), mesh_->n_elements(), mesh_->get_comm() ); // initial distr.
134  graph_ = new SparseGraphMETIS(*init_el_ds_);
135  break;
136  }
138 
139  // compute partitioning
140  loc_part_ = new int[init_el_ds_->lsize()];
142  delete graph_; graph_ = NULL;
143 }
144 
145 
146 
147 
148 /**
149  * Old UGLY, PETSC dependent method for getting new numbering after partitioning.
150  *
151  * n_ids - given maximal ID used in id_4_old
152  * id_4_old - given array of size init_el_ds_.size() - assign ID to an old index
153  *
154  * new_ds - new distribution of elements according to current distributed partitioning loc_part_
155  * id_4_loc - IDs for local elements in new distribution, has size new_ds->lsize()
156  * new_4_id - for given ID, the new index, -1 for unknown IDs
157  *
158  */
159 void Partitioning::id_maps(int n_ids, int *id_4_old,
160  const Distribution &old_ds, int *loc_part,
161  Distribution * &new_ds, int * &id_4_loc, int * &new_4_id) {
162 
163  IS part, new_numbering;
164  unsigned int size = old_ds.size(); // whole size of distr. array
165  int new_counts[old_ds.np()];
166  AO new_old_ao;
167  int *old_4_new;
168  int i_loc;
169  F_ENTRY;
170  // make distribution and numbering
171  //DBGPRINT_INT("Local partitioning",old_ds->lsize,loc_part_);
172 
173  ISCreateGeneral(PETSC_COMM_WORLD, old_ds.lsize(), loc_part, PETSC_COPY_VALUES, &part); // global IS part.
174  ISPartitioningCount(part, old_ds.np(), new_counts); // new size of each proc
175 
176  new_ds = new Distribution((unsigned int *) new_counts, PETSC_COMM_WORLD); // new distribution
177  ISPartitioningToNumbering(part, &new_numbering); // new numbering
178 
179  //xprintf(Msg,"Func: %d\n",petscstack->currentsize);
180  // xprintf(Msg,"Func: %s\n",petscstack->function[petscstack->currentsize]);
181  //xprintf(Msg,"Func: %s\n",petscstack->function[petscstack->currentsize-1]);
182 
183  old_4_new = (int *) xmalloc(size * sizeof(int));
184  id_4_loc = (int *) xmalloc(new_ds->lsize() * sizeof(int));
185  new_4_id = (int *) xmalloc((n_ids + 1) * sizeof(int));
186 
187  // create whole new->old mapping on each proc
188  //DBGMSG("Creating global new->old mapping ...\n");
189  AOCreateBasicIS(new_numbering, PETSC_NULL, &new_old_ao); // app ordering= new; petsc ordering = old
190  for (unsigned int i = 0; i < size; i++)
191  old_4_new[i] = i;
192  AOApplicationToPetsc(new_old_ao, size, old_4_new);
193  AODestroy(&(new_old_ao));
194 
195  // compute id_4_loc
196  //DBGMSG("Creating loc.number -> id mapping ...\n");
197  i_loc = 0;
198  //DBGPRINT_INT("id_4_old",old_ds.lsize(),id_4_old);
199  //DBGPRINT_INT("old_4_new",new_ds->lsize(),old_4_new)
200 
201  for (unsigned int i_new = new_ds->begin(); i_new < new_ds->end(); i_new++) {
202  //printf("i_new: %d old: %d id: %d i_loc: %d \n",i_new,old_4_new[i_new],i_loc);
203  id_4_loc[i_loc++] = id_4_old[old_4_new[i_new]];
204  }
205  // compute row_4_id
206  //DBGMSG("Creating id -> stiffness mtx. row mapping ...\n");
207  for (i_loc = 0; i_loc <= n_ids; i_loc++)
208  new_4_id[i_loc] = -1; // ensure that all ids are initialized
209  for (unsigned int i_new = 0; i_new < size; i_new++)
210  new_4_id[id_4_old[old_4_new[i_new]]] = i_new;
211  xfree(old_4_new);
212 }
213 
214 
215 void Partitioning::id_maps(int n_ids, int *id_4_old, Distribution * &new_ds, int * &id_4_loc, int * &new_4_id) {
216  Partitioning::id_maps(n_ids, id_4_old, *init_el_ds_, loc_part_, new_ds, id_4_loc, new_4_id);
217 }
218 
219 
220 
222  ASSERT(loc_part_, "Partition is not yet computed.\n");
223  if (seq_part_.size() == 0) {
224  // cout << "[" << myp() << "]" << seqDBGMSG("make distr part\n");
225  if (init_el_ds_->myp() == 0)
226  seq_part_.resize(init_el_ds_->size());
227  else
228  seq_part_.resize(1);
229  //for(unsigned int i = 0; i<init_el_ds_.lsize();i++) seq_part_[init_el_ds_->begin()+i]=loc
230  // communicate send sizes
231 
232 
234  &seq_part_[0],
235  (int *)(init_el_ds_->get_lsizes_array()),
236  (int *)(init_el_ds_->get_starts_array()),
237  MPI_INT, 0,init_el_ds_->get_comm() );
238 
239  }
240  //ASSERT_EQUAL(seq_part_.size(), init_el_ds_->size());
241  return seq_part_;
242 
243 }