Flow123d  release_2.2.0-914-gf1a3a4f
partitioning.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file partitioning.cc
15  * @brief
16  */
17 
18 #include "mesh/partitioning.hh"
19 #include "la/sparse_graph.hh"
20 #include "la/distribution.hh"
21 #include "mesh/mesh.h"
22 
23 #include "petscao.h"
24 
25 
26 namespace IT = Input::Type;
28  return IT::Selection("GraphType",
29  "Different algorithms to make the sparse graph with weighted edges\n"
30  "from the multidimensional mesh. Main difference is dealing with \n"
31  "neighborings of elements of different dimension.")
32  .add_value(any_neighboring, "any_neighboring", "Add edge for any pair of neighboring elements.")
33  .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.")
34  .add_value(same_dimension_neighboring, "same_dimension_neghboring", "Add edge for any pair of neighboring elements of same dimension (bad for matrix multiply).")
35  .close();
36 }
37 
39  return IT::Selection("PartTool", "Select the partitioning tool to use.")
40  .add_value(PETSc, "PETSc", "Use PETSc interface to various partitioning tools.")
41  .add_value(METIS, "METIS", "Use direct interface to Metis.")
42  .close();
43 }
44 
46  static IT::Record input_type = IT::Record("Partition","Setting for various types of mesh partitioning." )
47  .declare_key("tool", Partitioning::get_tool_sel(), IT::Default("\"METIS\""), "Software package used for partitioning. See corresponding selection.")
48  .declare_key("graph_type", Partitioning::get_graph_type_sel(), IT::Default("\"any_neighboring\""), "Algorithm for generating graph and its weights from a multidimensional mesh.")
49  .allow_auto_conversion("graph_type") // mainly in order to allow Default value for the whole record Partition
50  .close();
51  input_type.finish();
52 
53  return input_type;
54 }
55 
56 
58 : mesh_(mesh), in_(in), graph_(NULL), loc_part_(NULL), init_el_ds_(NULL)
59 {
61 }
62 
63 
64 
66  if (loc_part_) delete [] loc_part_;
67  loc_part_ = NULL;
68  if (init_el_ds_) delete init_el_ds_;
69  init_el_ds_ = NULL;
70  if (graph_) delete graph_;
71  graph_ = NULL;
72 }
73 
75  OLD_ASSERT(init_el_ds_, "NULL initial distribution.");
76  return init_el_ds_;
77 }
78 
79 
80 
82  OLD_ASSERT(loc_part_, "NULL local partitioning.");
83  return loc_part_;
84 }
85 
86 
87 
89 
90  Distribution edistr = graph_->get_distr();
91 
92  Edge *edg;
93  int li, e_idx;
94  unsigned int i_neigh;
95  int i_s, n_s;
96 
97  // Add nigbouring edges only for "any_*" graph types
98  bool neigh_on = ( in_.val<PartitionGraphType>("graph_type") != same_dimension_neighboring );
99 
100  FOR_ELEMENTS( mesh_, ele) {
101  // skip non-local elements
102  if (!edistr.is_local(ele.index()))
103  continue;
104 
105  // for all connected elements
106  FOR_ELEMENT_SIDES( ele, si ) {
107  edg = ele->side(si)->edge();
108 
109  FOR_EDGE_SIDES( edg, li ) {
110  OLD_ASSERT(edg->side(li)->valid(),"NULL side of edge.");
111  e_idx = ELEMENT_FULL_ITER(mesh_, edg->side(li)->element()).index();
112 
113  // for elements of connected elements, excluding element itself
114  if (e_idx != ele.index()) {
115  graph_->set_edge(ele.index(), e_idx);
116  }
117  }
118  }
119 
120  // include connections from lower dim. edge
121  // to the higher dimension
122  if (neigh_on) {
123  for (i_neigh = 0; i_neigh < ele->n_neighs_vb; i_neigh++) {
124  n_s = ele->neigh_vb[i_neigh]->edge()->n_sides;
125  for (i_s = 0; i_s < n_s; i_s++) {
126  e_idx=ELEMENT_FULL_ITER(mesh_, ele->neigh_vb[i_neigh]->edge()->side(i_s)->element()).index();
127  graph_->set_edge(ele.index(), e_idx);
128  graph_->set_edge(e_idx, ele.index());
129  }
130  }
131  }
132  }
133  graph_->finalize();
134 }
135 
136 
137 
139 
140 
141  // prepare dual graph
142  switch ( in_.val<PartitionTool>("tool")) {
143  case PETSc:
144  init_el_ds_ = new Distribution(DistributionBlock(), mesh_->n_elements(), mesh_->get_comm() ); // initial distr.
146 
147  break;
148  case METIS:
149  init_el_ds_ = new Distribution(DistributionLocalized(), mesh_->n_elements(), mesh_->get_comm() ); // initial distr.
150  graph_ = new SparseGraphMETIS(*init_el_ds_);
151  break;
152  }
153  int mesh_size = mesh_->n_elements();
154  int num_of_procs = init_el_ds_->np();
155  if (mesh_size < num_of_procs) { // check if decomposing is possible
156  THROW( ExcDecomposeMesh() << EI_NElems( mesh_size ) << EI_NProcs( num_of_procs ) );
157  }
158 
160 
161  // compute partitioning
162  loc_part_ = new IdxInt[init_el_ds_->lsize()];
164  delete graph_; graph_ = NULL;
165 }
166 
167 
168 
169 
170 /**
171  * Old UGLY, PETSC dependent method for getting new numbering after partitioning.
172  *
173  * n_ids - given maximal ID used in id_4_old
174  * id_4_old - given array of size init_el_ds_.size() - assign ID to an old index
175  *
176  * new_ds - new distribution of elements according to current distributed partitioning loc_part_
177  * id_4_loc - IDs for local elements in new distribution, has size new_ds->lsize()
178  * new_4_id - for given ID, the new index, -1 for unknown IDs
179  *
180  */
181 void Partitioning::id_maps(int n_ids, IdxInt *id_4_old,
182  const Distribution &old_ds, IdxInt *loc_part,
183  Distribution * &new_ds, IdxInt * &id_4_loc, IdxInt * &new_4_id) {
184 
185  IS part, new_numbering;
186  unsigned int size = old_ds.size(); // whole size of distr. array
187  int new_counts[old_ds.np()];
188  AO new_old_ao;
189  int *old_4_new;
190  int i_loc;
191 
192  // make distribution and numbering
193  ISCreateGeneral(PETSC_COMM_WORLD, old_ds.lsize(), loc_part, PETSC_COPY_VALUES, &part); // global IS part.
194  ISPartitioningCount(part, old_ds.np(), new_counts); // new size of each proc
195 
196  new_ds = new Distribution((unsigned int *) new_counts, PETSC_COMM_WORLD); // new distribution
197  ISPartitioningToNumbering(part, &new_numbering); // new numbering
198 
199  old_4_new = new int [size];
200  id_4_loc = new IdxInt [ new_ds->lsize() ];
201  new_4_id = new IdxInt [ n_ids + 1 ];
202 
203  // create whole new->old mapping on each proc
204  AOCreateBasicIS(new_numbering, PETSC_NULL, &new_old_ao); // app ordering= new; petsc ordering = old
205  for (unsigned int i = 0; i < size; i++)
206  old_4_new[i] = i;
207  AOApplicationToPetsc(new_old_ao, size, old_4_new);
208  AODestroy(&(new_old_ao));
209 
210  // compute id_4_loc
211  i_loc = 0;
212 
213  for (unsigned int i_new = new_ds->begin(); i_new < new_ds->end(); i_new++) {
214  id_4_loc[i_loc++] = id_4_old[old_4_new[i_new]];
215  }
216  // compute row_4_id
217  for (i_loc = 0; i_loc <= n_ids; i_loc++)
218  new_4_id[i_loc] = -1; // ensure that all ids are initialized
219  for (unsigned int i_new = 0; i_new < size; i_new++)
220  new_4_id[id_4_old[old_4_new[i_new]]] = i_new;
221 
222  delete [] old_4_new;
223 }
224 
225 
226 void Partitioning::id_maps(int n_ids, IdxInt *id_4_old, Distribution * &new_ds, IdxInt * &id_4_loc, IdxInt * &new_4_id) {
227  Partitioning::id_maps(n_ids, id_4_old, *init_el_ds_, loc_part_, new_ds, id_4_loc, new_4_id);
228 }
229 
230 
231 
232 shared_ptr< vector<int> > Partitioning::subdomain_id_field_data() {
233  OLD_ASSERT(loc_part_, "Partition is not yet computed.\n");
234  if (!seq_part_) {
235  unsigned int seq_size=(init_el_ds_->myp() == 0) ? init_el_ds_->size() : 1;
236  //seq_part_.resize(seq_size);
237  seq_part_ = make_shared< vector<int> >(seq_size);
238  std::vector<int> &vec = *( seq_part_.get() );
239 
241  &vec[0],
242  (int *)(init_el_ds_->get_lsizes_array()),
243  (int *)(init_el_ds_->get_starts_array()),
244  MPI_INT, 0,init_el_ds_->get_comm() );
245 
246  }
247  return seq_part_;
248 
249 }
unsigned int size() const
get global size
int IdxInt
Define integers that are indices into large arrays (elements, nodes, dofs etc.)
Definition: mesh.h:85
Mesh * mesh_
The input mesh.
~Partitioning()
Destructor.
Definition: partitioning.cc:65
shared_ptr< vector< int > > subdomain_id_field_data()
void make_element_connection_graph()
Definition: partitioning.cc:88
#define FOR_EDGE_SIDES(i, j)
Definition: edges.h:41
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:480
static const Input::Type::Record & get_input_type()
Definition: partitioning.cc:45
Add edge for any pair of neighboring elements.
shared_ptr< vector< int > > seq_part_
Sequential partitioning for output.
#define ELEMENT_FULL_ITER(_mesh_, i)
Definition: mesh.h:488
Definition: mesh.h:99
#define MPI_Gatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm)
Definition: mpi.h:549
#define FOR_ELEMENT_SIDES(i, j)
Definition: elements.h:157
Definition: edges.h:26
bool valid() const
Definition: side_impl.hh:86
Edge * edge() const
Definition: side_impl.hh:65
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
const unsigned int * get_lsizes_array()
get local sizes array
#define OLD_ASSERT(...)
Definition: global_defs.h:131
virtual Record & allow_auto_conversion(const string &from_key)
Allows shorter input of the Record providing only value of the from_key given as the parameter...
Definition: type_record.cc:132
unsigned int n_elements() const
Definition: mesh.h:156
bool is_local(unsigned int idx) const
identify local index
Use PETSc interface to various partitioing tools.
Definition: partitioning.hh:96
static const Input::Type::Selection & get_tool_sel()
Definition: partitioning.cc:38
IdxInt * loc_part_
Partition numbers for local elements in original distribution of elements given be init_el_ds_...
Input::Record in_
Input Record accessor.
const unsigned int * get_starts_array() const
get local starts array
MPI_Comm get_comm() const
Definition: mesh.h:201
void finalize()
Make sparse graph structures: rows, adj.
Definition: sparse_graph.cc:98
virtual void partition(int *loc_part)=0
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
Use direct interface to Metis.
Definition: partitioning.hh:97
Selection & add_value(const int value, const std::string &key, const std::string &description="", TypeBase::attribute_map attributes=TypeBase::attribute_map())
Adds one new value with name given by key to the Selection.
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:490
unsigned int np() const
get num of processors
Distribution get_distr()
void id_maps(int n_ids, IdxInt *id_4_old, Distribution *&new_ds, IdxInt *&id_4_loc, IdxInt *&new_4_id)
Distribution * init_el_ds_
Original distribution of elements. Depends on type of partitioner.
unsigned int myp() const
get my processor
Support classes for parallel programing.
FinishStatus finish(FinishStatus finish_type=FinishStatus::regular_) override
Finish declaration of the Record type.
Definition: type_record.cc:242
const Selection & close() const
Close the Selection, no more values can be added.
ElementFullIter element() const
Definition: side_impl.hh:52
#define MPI_INT
Definition: mpi.h:160
MPI_Comm get_comm() const
Returns communicator.
Same as before and assign higher weight to cuts of lower dimension in order to make them stick to one...
Distributed sparse graphs, partitioning.
const Distribution * get_init_distr() const
Definition: partitioning.cc:74
void make_partition()
const IdxInt * get_loc_part() const
Definition: partitioning.cc:81
Record type proxy class.
Definition: type_record.hh:182
SparseGraph * graph_
Graph used to partitioning the mesh.
static const Input::Type::Selection & get_graph_type_sel()
Input specification objects.
Definition: partitioning.cc:27
Add edge for any pair of neighboring elements of same dimension (bad for matrix multiply) ...
Partitioning(Mesh *mesh, Input::Record in)
Definition: partitioning.cc:57
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
SideIter side(const unsigned int i) const
Definition: edges.h:31
Template for classes storing finite set of named values.
void set_edge(const int a, const int b, int weight=1)
Definition: sparse_graph.cc:66
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:260
unsigned int lsize(int proc) const
get local size