OpenFPM_pdata  1.1.0
Project that contain the implementation of distributed structures
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Friends Pages
SpaceDistribution.hpp
1 /*
2  * SpaceDistribution.hpp
3  *
4  * Created on: Dec 3, 2016
5  * Author: i-bird
6  */
7 
8 #ifndef SRC_DECOMPOSITION_DISTRIBUTION_SPACEDISTRIBUTION_HPP_
9 #define SRC_DECOMPOSITION_DISTRIBUTION_SPACEDISTRIBUTION_HPP_
10 
11 #include "util/mathutil.hpp"
12 #include "NN/CellList/CellDecomposer.hpp"
13 #include "Grid/grid_key_dx_iterator_hilbert.hpp"
14 
23 template<unsigned int dim, typename T>
25 {
28 
31 
34 
37 
38 
39 public:
40 
46  :v_cl(v_cl)
47  {
48  }
49 
56  :v_cl(pm.v_cl)
57  {
58  this->operator=(pm);
59  }
60 
67  :v_cl(pm.v_cl)
68  {
69  this->operator=(pm);
70  }
71 
78  {
79  size_t bc[dim];
80 
81  for (size_t i = 0 ; i < dim ; i++)
82  bc[i] = NON_PERIODIC;
83 
84  // Set grid and domain
85  gr = grid;
86  domain = dom;
87 
88  // Create a cartesian grid graph
90  gp = g_factory_part.template construct<NO_EDGE, nm_v::id, T, dim - 1, 0>(gr.getSize(), domain, bc);
91 
92  // Init to 0.0 axis z (to fix in graphFactory)
93  if (dim < 3)
94  {
95  for (size_t i = 0; i < gp.getNVertex(); i++)
96  gp.vertex(i).template get<nm_v::x>()[2] = 0.0;
97  }
98  for (size_t i = 0; i < gp.getNVertex(); i++)
99  gp.vertex(i).template get<nm_v::global_id>() = i;
100 
101  }
102 
107  {
108  return gp;
109  }
110 
114  void decompose()
115  {
116  // Get the number of processing units
117  size_t Np = v_cl.getProcessingUnits();
118 
119  // Calculate the best number of sub-domains for each
120  // processor
121  size_t N_tot = gr.size();
122  size_t N_best_each = N_tot / Np;
123  size_t N_rest = N_tot % Np;
124 
125  openfpm::vector<size_t> accu(Np);
126  accu.get(0) = N_best_each + ((0 < N_rest)?1:0);
127  for (size_t i = 1 ; i < Np ; i++)
128  accu.get(i) = accu.get(i-1) + N_best_each + ((i < N_rest)?1:0);
129 
130  // Get the maximum along dimensions and take the smallest n number
131  // such that 2^n < m. n it will be order of the hilbert curve
132 
133  size_t max = 0;
134 
135  for (size_t i = 0; i < dim ; i++)
136  {
137  if (max < gr.size(i))
138  max = gr.size(i);
139  }
140 
141  // Get the order of the hilbert-curve
142  size_t order = openfpm::math::log2_64(max);
143  if (1ul << order < max)
144  order += 1;
145 
146  size_t n = 1 << order;
147 
148  // Create the CellDecomoser
149 
150  CellDecomposer_sm<dim,T> cd_sm;
151  cd_sm.setDimensions(domain, gr.getSize(), 0);
152 
153  // create the hilbert curve
154 
155  //hilbert curve iterator
157 
158  T spacing[dim];
159 
160  // Calculate the hilbert curve spacing
161  for (size_t i = 0 ; i < dim ; i++)
162  spacing[i] = (domain.getHigh(i) - domain.getLow(i)) / n;
163 
164  // Small grid to detect already assigned sub-sub-domains
166  g.setMemory();
167 
168  // Reset the grid to -1
170  while (it.isNext())
171  {
172  auto key = it.get();
173 
174  g.template get<0>(key) = -1;
175 
176  ++it;
177  }
178 
179  // Go along the hilbert-curve and divide the space
180 
181  size_t proc_d = 0;
182  size_t ele_d = 0;
183  while (h_it.isNext())
184  {
185  auto key = h_it.get();
186 
187  // Point p
188  Point<dim,T> p;
189 
190  for (size_t i = 0 ; i < dim ; i++)
191  p.get(i) = key.get(i) * spacing[i] + spacing[i] / 2;
192 
193  grid_key_dx<dim> sp = cd_sm.getCellGrid(p);
194 
195  if (g.template get<0>(sp) == -1)
196  {
197  g.template get<0>(sp) = proc_d;
198  ele_d++;
199 
200  if (ele_d >= accu.get(proc_d))
201  proc_d++;
202  }
203 
204  ++h_it;
205  }
206 
207  // Fill from the grid to the graph
208 
209  // Reset the grid to -1
211  while (it2.isNext())
212  {
213  auto key = it2.get();
214 
215  gp.template vertex_p<nm_v::proc_id>(gr.LinId(key)) = g.template get<0>(key);
216 
217  ++it2;
218  }
219 
220  return;
221  }
222 
228  void refine()
229  {
230  std::cout << __FILE__ << ":" << __LINE__ << " You are trying to dynamicaly balance a fixed decomposition, this operation has no effect" << std::endl;
231  }
232 
237  float getUnbalance()
238  {
239  return gr.size() % v_cl.getProcessingUnits();
240  }
241 
248  void getSubSubDomainPosition(size_t id, T (&pos)[dim])
249  {
250 #ifdef SE_CLASS1
251  if (id >= gp.getNVertex())
252  std::cerr << __FILE__ << ":" << __LINE__ << "Such vertex doesn't exist (id = " << id << ", " << "total size = " << gp.getNVertex() << ")\n";
253 #endif
254 
255  // Copy the geometrical informations inside the pos vector
256  pos[0] = gp.vertex(id).template get<nm_v::x>()[0];
257  pos[1] = gp.vertex(id).template get<nm_v::x>()[1];
258  if (dim == 3)
259  pos[2] = gp.vertex(id).template get<nm_v::x>()[2];
260  }
261 
268  inline void setComputationCost(size_t id, size_t weight)
269  {
270  std::cout << __FILE__ << ":" << __LINE__ << " You are trying to set the computation cost on a fixed decomposition, this operation has no effect" << std::endl;
271  }
272 
278  {
279  return false;
280  }
281 
290  {
291  return 1.0;
292  }
293 
299  {
300  // Get the number of processing units
301  size_t Np = v_cl.getProcessingUnits();
302 
303  // Calculate the best number of sub-domains for each
304  // processor
305  size_t N_tot = gr.size();
306  size_t N_best_each = N_tot / Np;
307  size_t N_rest = N_tot % Np;
308 
309  if (v_cl.getProcessUnitID() < N_rest)
310  N_best_each += 1;
311 
312  return N_best_each;
313  }
314 
320  void setMigrationCost(size_t id, size_t migration)
321  {
322  }
323 
330  void setCommunicationCost(size_t v_id, size_t e, size_t communication)
331  {
332  }
333 
340  {
341  return gp.getNVertex();
342  }
343 
348  size_t getNSubSubDomainNeighbors(size_t id)
349  {
350  return gp.getNChilds(id);
351  }
352 
358  void write(const std::string & file)
359  {
360  VTKWriter<Graph_CSR<nm_v, nm_e>, VTK_GRAPH> gv2(gp);
361  gv2.write(std::to_string(v_cl.getProcessUnitID()) + "_" + file + ".vtk");
362  }
363 
364  const SpaceDistribution<dim,T> & operator=(const SpaceDistribution<dim,T> & dist)
365  {
366  gr = dist.gr;
367  domain = dist.domain;
368  gp = dist.gp;
369 
370  return *this;
371  }
372 
373  const SpaceDistribution<dim,T> & operator=(SpaceDistribution<dim,T> && dist)
374  {
375  v_cl = dist.v_cl;
376  gr = dist.gr;
377  domain = dist.domain;
378  gp.swap(dist.gp);
379 
380  return *this;
381  }
382 
390  size_t get_ndec()
391  {
392  return 0;
393  }
394 };
395 
396 
397 #endif /* SRC_DECOMPOSITION_DISTRIBUTION_SPACEDISTRIBUTION_HPP_ */
bool weightsAreUsed()
Checks if weights are used on the vertices.
mem_id LinId(const grid_key_dx< N > &gk, const char sum_id[N]) const
Linearization of the grid_key_dx with a specified shift.
Definition: grid_sm.hpp:337
SpaceDistribution(const ParMetisDistribution< dim, T > &pm)
Vcluster & v_cl
Vcluster.
void setComputationCost(size_t id, size_t weight)
Function that set the weight of the vertex.
SpaceDistribution(Vcluster &v_cl)
grid_key_dx is the key to access any element in the grid
Definition: grid_key.hpp:18
size_t getProcessUnitID()
Get the process unit id.
size_t size() const
Return the size of the grid.
Definition: grid_sm.hpp:572
Class that distribute sub-sub-domains across processors using an hilbert curve to divide the space...
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:22
void write(const std::string &file)
Print the current distribution and save it to VTK file.
Implementation of VCluster class.
Definition: VCluster.hpp:36
This class construct a cartesian graph.
void setMigrationCost(size_t id, size_t migration)
Set migration cost of the vertex id.
Class that distribute sub-sub-domains across processors using ParMetis Library.
size_t getSubSubDomainComputationCost(size_t id)
function that get the weight of the vertex
Graph_CSR< nm_v, nm_e > gp
Global sub-sub-domain graph.
const size_t(& getSize() const)[N]
Return the size of the grid as an array.
Definition: grid_sm.hpp:677
Box< dim, T > domain
rectangular domain to decompose
const grid_key_dx< dim > & get() const
Get the actual key.
SpaceDistribution(SpaceDistribution< dim, T > &&pm)
size_t getNSubSubDomains()
Returns total number of sub-sub-domains in the distribution graph.
size_t getProcessorLoad()
Compute the processor load counting the total weights of its vertices.
void setCommunicationCost(size_t v_id, size_t e, size_t communication)
Set communication cost of the edge id.
const T & get(size_t i) const
Get coordinate.
Definition: Point.hpp:142
bool isNext()
Check if there is the next element.
void getSubSubDomainPosition(size_t id, T(&pos)[dim])
function that return the position of the vertex in the space
This class represent an N-dimensional box.
Definition: Box.hpp:56
void refine()
Refine current decomposition.
This class is a trick to indicate the compiler a specific specialization pattern. ...
Definition: memory_c.hpp:201
auto vertex(size_t id) -> decltype(v.get(id))
Function to access the vertex.
Definition: map_graph.hpp:600
void createCartGraph(grid_sm< dim, void > &grid, Box< dim, T > dom)
Create the Cartesian graph.
size_t getNVertex() const
Return the number of the vertex.
Definition: map_graph.hpp:1029
static const unsigned int id
id property id in boost::fusion::vector
void swap(Graph_CSR< V, E > &g)
swap the memory of g with this graph
Definition: map_graph.hpp:960
grid_sm< dim, void > gr
Structure that store the cartesian grid information.
size_t get_ndec()
It return the decomposition id.
const grid_key_dx< dim > & get()
Get the actual key.
size_t getNChilds(size_t c) const
Return the number of childs of a vertex.
Definition: map_graph.hpp:752
void decompose()
Create the decomposition.
float getUnbalance()
Compute the unbalance of the processor compared to the optimal balance.
size_t getProcessingUnits()
Get the total number of processors.
bool isNext()
Check if there is the next element.
Graph_CSR< nm_v, nm_e > & getGraph()
Get the current graph (main)
size_t getNSubSubDomainNeighbors(size_t id)
Returns total number of neighbors of the sub-sub-domain id.