openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
SF_partitioning.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
27 #ifndef _SF_PARTITIONING_H
28 #define _SF_PARTITIONING_H
29 
30 #define KDPART_MPI
31 #include "kdpart.hpp"
32 #include "SF_container.h"
33 #include "SF_vector.h"
34 
35 namespace SF {
36 
43 template<class T, class S>
45 {
46 public:
47  virtual void operator()(const meshdata<T, S> & mesh, vector<T> & part) = 0;
48 };
49 
50 #ifdef WITH_PARMETIS
51 
52 #include "parmetis.h"
53 
57 template<class T, class S>
58 class parmetis_partitioner : public abstract_partitioner<T, S>
59 {
60 private:
61  // this are the options configurable by the user
62  float _unbalance;
63  short _ncommon;
64 
65 public:
67  parmetis_partitioner() : _unbalance(1.01f), _ncommon(2)
68  {}
70  parmetis_partitioner(float ub, short nc) : _unbalance(ub), _ncommon(nc)
71  {}
72 
80  inline void operator()(const meshdata<T, S> & mesh, vector<T> & part)
81  {
82  MPI_Comm comm = mesh.comm;
83 
84  int rank, size;
85  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
86 
87  part.resize(mesh.l_numelem);
88  // special treatment of sequential case since parmetis is rather slow
89  if(size == 1) {
90  part.zero();
91  return;
92  }
93 
94  // communicate the distribution of the elements
95  vector<idx_t> elemdist_cnt(size), elemdist_dsp(size+1);
96  idx_t numelem = mesh.l_numelem; // we need a type conversion to int
97  MPI_Allgather(&numelem, sizeof(idx_t), MPI_BYTE, elemdist_cnt.data(), sizeof(idx_t), MPI_BYTE, comm);
98  dsp_from_cnt(elemdist_cnt, elemdist_dsp);
99 
100  int nparts = size; // number of partitions
101  int ncommonnod = _ncommon; // number of common nodes defining the neighbourhood between 2 elems
102  int ncon = 1; // number of constraints to satisfy (we always use 1)
103  int wgtflag = 0; // number of weights for graph edges (unused, thus 0)
104  idx_t* elemwgt = NULL;
105  int numflag = 0; // indexing is 0 based
106 
107  vector<real_t> tpwgts(nparts*ncon); // weights for nodes
108  for(size_t i=0; i<tpwgts.size(); i++) tpwgts[i] = (float)1. / (float)(nparts*ncon);
109 
110  vector<real_t> ubvec(ncon);
111  for (int i = 0; i < ncon; i++ ) ubvec[i] = _unbalance;
112 
113  vector<int> opt(4, 0); // options are unused
114 
115  // we need to convert the mesh to idx_t
116  vector<idx_t> eptr(mesh.dsp.size()), eind(mesh.con.size());
117  vec_assign(eptr.data(), mesh.dsp.data(), eptr.size());
118 
119  const vector<T> & rnod = mesh.get_numbering(NBR_REF);
120  for(size_t i=0; i<mesh.con.size(); i++) eind[i] = rnod[mesh.con[i]];
121 
122  vector<idx_t> pm_part(mesh.l_numelem);
123 
124  int n_edgecut;
125  ParMETIS_V3_PartMeshKway(elemdist_dsp.data(),
126  eptr.data(),
127  eind.data(),
128  elemwgt,
129  &wgtflag,
130  &numflag,
131  &ncon,
132  &ncommonnod,
133  &nparts,
134  tpwgts.data(),
135  ubvec.data(),
136  opt.data(),
137  &n_edgecut,
138  pm_part.data(),
139  &comm);
140 
141  vec_assign(part.data(), pm_part.data(), part.size());
142 
143  }
144 };
145 
146 #endif
147 
148 template<class T, class S>
150 {
151  public:
152  void operator() (const meshdata<T,S> & mesh, vector<T> & part_vec)
153  {
154  int size; MPI_Comm_size(mesh.comm, &size);
155 
156  part_vec.resize(mesh.l_numelem);
157  // special treatment of sequential case
158  if(size == 1) {
159  part_vec.zero();
160  return;
161  }
162 
163  std::vector<S> ctr(mesh.l_numelem*3);
164  for(size_t i=0; i<mesh.l_numelem; i++) {
165  kdpart::vec3<S> avrg;
166  T dsp = mesh.dsp[i];
167  T elemsize = mesh.dsp[i+1] - dsp;
168 
169  for(T j=0; j<elemsize; j++) {
170  T v = mesh.con[dsp+j];
171  avrg.x += mesh.xyz[v*3+0];
172  avrg.y += mesh.xyz[v*3+1];
173  avrg.z += mesh.xyz[v*3+2];
174  }
175  avrg.x /= S(elemsize);
176  avrg.y /= S(elemsize);
177  avrg.z /= S(elemsize);
178 
179  ctr[i*3+0] = avrg.x;
180  ctr[i*3+1] = avrg.y;
181  ctr[i*3+2] = avrg.z;
182  }
183 
184  std::vector<T> part;
186  partitioner(mesh.comm, ctr, size, part);
187 
188  part_vec.assign(part.begin(), part.end());
189  }
190 };
191 
192 }
193 
194 #endif
Definition: dense_mat.hpp:34
The mesh storage class. It contains both element and vertex data.
Definition: SF_container.h:383
The vector class and related algorithms.
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:452
void zero()
Definition: SF_vector.h:248
MPI_Comm comm
the parallel mesh is defined on a MPI world
Definition: SF_container.h:392
vector< T > dsp
connectivity starting index of each element
Definition: SF_container.h:404
minimalistic internal point struct
Definition: kdpart.hpp:44
kdtree based partitioning classes.
The nodal numbering of the reference mesh (the one stored on HD).
Definition: SF_container.h:189
Basic containers.
vector< S > xyz
node cooridnates
Definition: SF_container.h:415
T * data()
Pointer to the vector&#39;s start.
Definition: SF_vector.h:91
vector< T > con
Definition: SF_container.h:400
size_t size() const
The current size of the vector.
Definition: SF_vector.h:104
virtual void operator()(const meshdata< T, S > &mesh, vector< T > &part)=0
A vector storing arbitrary data.
Definition: SF_vector.h:42
size_t l_numelem
local number of elements
Definition: SF_container.h:387
Abstract base class for a mesh partitioner.
void assign(InputIterator s, InputIterator e)
Assign a memory range.
Definition: SF_vector.h:161
void vec_assign(S *lhs, const V *rhs, size_t size)
Assign the values in rhs to lhs. The data-type of rhs is cast to the type of lhs. ...
Definition: SF_vector.h:371
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:209
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
Definition: SF_vector.h:310