Flow123d  release_3.0.0-1212-g8801db3
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/side_impl.hh"
22 #include "mesh/long_idx.hh"
23 #include "mesh/mesh.h"
24 #include "mesh/accessors.hh"
25 #include "mesh/range_wrapper.hh"
26 #include "mesh/neighbours.h"
27 
28 #include "petscao.h"
29 
30 
31 namespace IT = Input::Type;
33  return IT::Selection("GraphType",
34  "Different algorithms to make the sparse graph with weighted edges\n"
35  "from the multidimensional mesh. Main difference is dealing with \n"
36  "neighboring of elements of different dimension.")
37  .add_value(any_neighboring, "any_neighboring", "Add an edge for any pair of neighboring elements.")
38  .add_value(any_weight_lower_dim_cuts, "any_weight_lower_dim_cuts", "Same as before and assign higher weight to cuts of lower dimension in order to make them stick to one face.")
39  .add_value(same_dimension_neighboring, "same_dimension_neighboring", "Add an edge for any pair of neighboring elements of the same dimension (bad for matrix multiply).")
40  .close();
41 }
42 
44  return IT::Selection("PartTool", "Select the partitioning tool to use.")
45  .add_value(PETSc, "PETSc", "Use PETSc interface to various partitioning tools.")
46  .add_value(METIS, "METIS", "Use direct interface to Metis.")
47  .close();
48 }
49 
51  static IT::Record input_type = IT::Record("Partition","Setting for various types of mesh partitioning." )
52  .declare_key("tool", Partitioning::get_tool_sel(), IT::Default("\"METIS\""), "Software package used for partitioning. See corresponding selection.")
53  .declare_key("graph_type", Partitioning::get_graph_type_sel(), IT::Default("\"any_neighboring\""), "Algorithm for generating graph and its weights from a multidimensional mesh.")
54  .allow_auto_conversion("graph_type") // mainly in order to allow Default value for the whole record Partition
55  .close();
56  input_type.finish();
57 
58  return input_type;
59 }
60 
61 
63 : mesh_(mesh), in_(in), graph_(NULL), loc_part_(NULL), init_el_ds_(NULL)
64 {
66 }
67 
68 
69 
71  if (loc_part_) delete [] loc_part_;
72  loc_part_ = NULL;
73  if (init_el_ds_) delete init_el_ds_;
74  init_el_ds_ = NULL;
75  if (graph_) delete graph_;
76  graph_ = NULL;
77 }
78 
80  OLD_ASSERT(init_el_ds_, "NULL initial distribution.");
81  return init_el_ds_;
82 }
83 
84 
85 
87  OLD_ASSERT(loc_part_, "NULL local partitioning.");
88  return loc_part_;
89 }
90 
91 
92 
94 
95  Distribution edistr = graph_->get_distr();
96 
97  const Edge *edg;
98  int e_idx;
99  unsigned int i_neigh;
100  int i_s, n_s;
101 
102  // Add nigbouring edges only for "any_*" graph types
103  bool neigh_on = ( in_.val<PartitionGraphType>("graph_type") != same_dimension_neighboring );
104 
105  for (auto ele : mesh_->elements_range()) {
106  // skip non-local elements
107  if ( !edistr.is_local( ele.idx() ) )
108  continue;
109 
110  // for all connected elements
111  for (unsigned int si=0; si<ele->n_sides(); si++) {
112  edg = ele.side(si)->edge();
113 
114  for (unsigned int li=0; li<edg->n_sides; li++) {
115  ASSERT(edg->side(li)->valid()).error("NULL side of edge.");
116  e_idx = edg->side(li)->element().idx();
117 
118  // for elements of connected elements, excluding element itself
119  if ( e_idx != ele.idx() ) {
120  graph_->set_edge( ele.idx(), e_idx );
121  }
122  }
123  }
124 
125  // include connections from lower dim. edge
126  // to the higher dimension
127  if (neigh_on) {
128  for (i_neigh = 0; i_neigh < ele->n_neighs_vb(); i_neigh++) {
129  n_s = ele->neigh_vb[i_neigh]->edge()->n_sides;
130  for (i_s = 0; i_s < n_s; i_s++) {
131  e_idx = ele->neigh_vb[i_neigh]->edge()->side(i_s)->element().idx();
132  graph_->set_edge( ele.idx(), e_idx );
133  graph_->set_edge( e_idx, ele.idx() );
134  }
135  }
136  }
137  }
138  graph_->finalize();
139 }
140 
141 
142 
144 
145 
146  // prepare dual graph
147  switch ( in_.val<PartitionTool>("tool")) {
148  case PETSc:
149  init_el_ds_ = new Distribution(DistributionBlock(), mesh_->n_elements(), mesh_->get_comm() ); // initial distr.
151 
152  break;
153  case METIS:
154  init_el_ds_ = new Distribution(DistributionLocalized(), mesh_->n_elements(), mesh_->get_comm() ); // initial distr.
155  graph_ = new SparseGraphMETIS(*init_el_ds_);
156  break;
157  }
158  int mesh_size = mesh_->n_elements();
159  int num_of_procs = init_el_ds_->np();
160  if (mesh_size < num_of_procs) { // check if decomposing is possible
161  THROW( ExcDecomposeMesh() << EI_NElems( mesh_size ) << EI_NProcs( num_of_procs ) );
162  }
163 
165 
166  // compute partitioning
169  delete graph_; graph_ = NULL;
170 }
171 
172 
173 
174 
175 /**
176  * Old UGLY, PETSC dependent method for getting new numbering after partitioning.
177  *
178  * n_ids - given maximal ID used in id_4_old
179  * id_4_old - given array of size init_el_ds_.size() - assign ID to an old index
180  *
181  * new_ds - new distribution of elements according to current distributed partitioning loc_part_
182  * id_4_loc - IDs for local elements in new distribution, has size new_ds->lsize()
183  * new_4_id - for given ID, the new index, -1 for unknown IDs
184  *
185  */
186 void Partitioning::id_maps(int n_ids, LongIdx *id_4_old,
187  const Distribution &old_ds, LongIdx *loc_part,
188  Distribution * &new_ds, LongIdx * &id_4_loc, LongIdx * &new_4_id) {
189 
190  IS part, new_numbering;
191  unsigned int size = old_ds.size(); // whole size of distr. array
192  int new_counts[old_ds.np()];
193  AO new_old_ao;
194  int *old_4_new;
195  int i_loc;
196 
197  // make distribution and numbering
198  ISCreateGeneral(PETSC_COMM_WORLD, old_ds.lsize(), loc_part, PETSC_COPY_VALUES, &part); // global IS part.
199  ISPartitioningCount(part, old_ds.np(), new_counts); // new size of each proc
200 
201  new_ds = new Distribution((unsigned int *) new_counts, PETSC_COMM_WORLD); // new distribution
202  ISPartitioningToNumbering(part, &new_numbering); // new numbering
203  ISDestroy(&part);
204 
205  old_4_new = new int [size];
206  id_4_loc = new LongIdx [ new_ds->lsize() ];
207  new_4_id = new LongIdx [ n_ids + 1 ];
208 
209  // create whole new->old mapping on each proc
210  AOCreateBasicIS(new_numbering, PETSC_NULL, &new_old_ao); // app ordering= new; petsc ordering = old
211  ISDestroy(&new_numbering);
212  for (unsigned int i = 0; i < size; i++)
213  old_4_new[i] = i;
214  AOApplicationToPetsc(new_old_ao, size, old_4_new);
215  AODestroy(&(new_old_ao));
216 
217  // compute id_4_loc
218  i_loc = 0;
219 
220  for (unsigned int i_new = new_ds->begin(); i_new < new_ds->end(); i_new++) {
221  id_4_loc[i_loc++] = id_4_old[old_4_new[i_new]];
222  }
223  // compute row_4_id
224  for (i_loc = 0; i_loc <= n_ids; i_loc++)
225  new_4_id[i_loc] = -1; // ensure that all ids are initialized
226  for (unsigned int i_new = 0; i_new < size; i_new++)
227  new_4_id[id_4_old[old_4_new[i_new]]] = i_new;
228 
229 
230  delete [] old_4_new;
231 }
232 
233 
234 void Partitioning::id_maps(int n_ids, LongIdx *id_4_old, Distribution * &new_ds, LongIdx * &id_4_loc, LongIdx * &new_4_id) {
235  Partitioning::id_maps(n_ids, id_4_old, *init_el_ds_, loc_part_, new_ds, id_4_loc, new_4_id);
236 }
237 
238 
239 
240 shared_ptr< vector<int> > Partitioning::subdomain_id_field_data() {
241  ASSERT(loc_part_).error("Partition is not yet computed.\n");
242  if (!seq_part_) {
243  unsigned int seq_size=mesh_->get_el_ds()->lsize();
244  seq_part_ = make_shared< vector<int> >(seq_size, mesh_->get_el_ds()->myp());
245  }
246 
247  return seq_part_;
248 
249 }
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
const Edge * edge() const
Definition: side_impl.hh:66
unsigned int size() const
get global size
Mesh * mesh_
The input mesh.
~Partitioning()
Destructor.
Definition: partitioning.cc:70
shared_ptr< vector< int > > subdomain_id_field_data()
void make_element_connection_graph()
Definition: partitioning.cc:93
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
static const Input::Type::Record & get_input_type()
Definition: partitioning.cc:50
Add edge for any pair of neighboring elements.
shared_ptr< vector< int > > seq_part_
Sequential partitioning for output.
Definition: mesh.h:76
int n_sides
Definition: edges.h:36
Definition: edges.h:26
bool valid() const
Definition: side_impl.hh:92
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
ElementAccessor< 3 > element() const
Definition: side_impl.hh:53
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
LongIdx * loc_part_
Partition numbers for local elements in original distribution of elements given be init_el_ds_...
#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:133
bool is_local(unsigned int idx) const
identify local index
Use PETSc interface to various partitioing tools.
static const Input::Type::Selection & get_tool_sel()
Definition: partitioning.cc:43
Input::Record in_
Input Record accessor.
MPI_Comm get_comm() const
Definition: mesh.h:185
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.
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:503
virtual Range< ElementAccessor< 3 > > elements_range() const
Returns range of bulk elements.
Definition: mesh.cc:1041
unsigned int np() const
get num of processors
Distribution get_distr()
Distribution * get_el_ds() const
Definition: mesh.h:164
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.
void id_maps(int n_ids, LongIdx *id_4_old, Distribution *&new_ds, LongIdx *&id_4_loc, LongIdx *&new_4_id)
FinishStatus finish(FinishStatus finish_type=FinishStatus::regular_) override
Finish declaration of the Record type.
Definition: type_record.cc:243
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:346
const Selection & close() const
Close the Selection, no more values can be added.
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:79
void make_partition()
const LongIdx * get_loc_part() const
Definition: partitioning.cc:86
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:32
Add edge for any pair of neighboring elements of same dimension (bad for matrix multiply) ...
Partitioning(Mesh *mesh, Input::Record in)
Definition: partitioning.cc:62
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
Definition: accessors.hh:111
#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.
Implementation of range helper class.
void set_edge(const int a, const int b, int weight=1)
Definition: sparse_graph.cc:66
unsigned int lsize(int proc) const
get local size