OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
dec_optimizer.hpp
1 #ifndef DEC_OPTIMIZER_HPP
2 #define DEC_OPTIMIZER_HPP
3 
4 #include "Grid/iterators/grid_key_dx_iterator_sub.hpp"
5 #include "Grid/iterators/grid_skin_iterator.hpp"
6 
17 template <unsigned int dim>
18 class wavefront : public Box<dim,size_t>
19 {
20 public:
21 
23  static const int start = 0;
24 
26  static const int stop = 1;
27 };
28 
30 
31 template<unsigned int dim>
33 {
34  enum
35  {
36  value = 1
37  };
38 };
39 
49 template <unsigned int dim, typename Graph>
51 {
54 
55 private:
56 
64  void expand_one_wf(openfpm::vector<wavefront<dim>> & v_w, std::vector<comb<dim>> & w_comb , size_t d)
65  {
66  for (size_t j = 0 ; j < dim ; j++)
67  {
68  v_w.template get<wavefront<dim>::stop>(d)[j] = v_w.template get<wavefront<dim>::stop>(d)[j] + w_comb[d].c[j];
69  v_w.template get<wavefront<dim>::start>(d)[j] = v_w.template get<wavefront<dim>::start>(d)[j] + w_comb[d].c[j];
70  }
71  }
72 
73 
82  void adjust_others_wf(openfpm::vector<wavefront<dim>> & v_w, HyperCube<dim> & hyp, std::vector<comb<dim>> & w_comb, size_t d)
83  {
84  // expand the intersection of the wavefronts
85 
86  std::vector<comb<dim>> q_comb = SubHyperCube<dim,dim-1>::getCombinations_R(w_comb[d],dim-2);
87 
88  // Eliminate the w_comb[d] direction
89 
90  for (size_t k = 0 ; k < q_comb.size() ; k++)
91  {
92  for (size_t j = 0 ; j < dim ; j++)
93  {
94  if (w_comb[d].c[j] != 0)
95  {
96  q_comb[k].c[j] = 0;
97  }
98  }
99  }
100 
101  // for all the combinations
102  for (size_t j = 0 ; j < q_comb.size() ; j++)
103  {
104  size_t id = hyp.LinId(q_comb[j]);
105 
106  // get the combination of the direction d
107  bool is_pos = hyp.isPositive(d);
108 
109  // is positive, modify the stop point or the starting point
110 
111  for (size_t s = 0 ; s < dim ; s++)
112  {
113  if (is_pos == true)
114  {v_w.template get<wavefront<dim>::stop>(id)[s] = v_w.template get<wavefront<dim>::stop>(id)[s] + w_comb[d].c[s];}
115  else
116  {v_w.template get<wavefront<dim>::start>(id)[s] = v_w.template get<wavefront<dim>::start>(id)[s] + w_comb[d].c[s];}
117  }
118  }
119  }
120 
129  template<unsigned int prp> void write_wavefront(Graph & graph,openfpm::vector<wavefront<dim>> & v_w)
130  {
131  // fill the wall domain with 0
132 
133  fill_domain<prp>(graph,gh.getBox(),0);
134 
135  // fill the wavefront
136 
137  for (int i = 0 ; i < v_w.size() ; i++)
138  {
139  Box<dim,size_t> box = wavefront<dim>::getBox(v_w.get(i));
140 
141  fill_domain<prp>(graph,box,1);
142  }
143  }
144 
155  template<unsigned int p_sub> void fill_domain(Graph & graph,const Box<dim,size_t> & box, long int ids)
156  {
157  // Create a subgrid iterator
159 
160  // iterate through all grid points
161 
162  while (g_sub.isNext())
163  {
164  // get the actual key
165  const grid_key_dx<dim> & gk = g_sub.get();
166 
167  // get the vertex and set the sub id
168 
169  graph.vertex(gh.LinId(gk)).template get<p_sub>() = ids;
170 
171  // next subdomain
172  ++g_sub;
173  }
174  }
175 
189  template<unsigned int p_sub, unsigned int p_id> void add_to_queue(openfpm::vector<size_t> & domains, openfpm::vector<wavefront<dim>> & v_w, Graph & graph, std::vector<comb<dim>> & w_comb, long int pr_id, const size_t(& bc)[dim])
190  {
191  // create a new queue
192  openfpm::vector<size_t> domains_new;
193 
194  // push in the new queue, the old domains of the queue that are not assigned element
195 
196  for (size_t j = 0 ; j < domains.size() ; j++)
197  {
198  long int gs = graph.vertex(domains.get(j)).template get<p_sub>();
199  if (gs < 0)
200  {
201  // not assigned push it
202 
203  domains_new.add(domains.get(j));
204  }
205  }
206 
207  // Create an Hyper-cube
208  HyperCube<dim> hyp;
209 
210  for (size_t d = 0 ; d < v_w.size() ; d++)
211  {
212  expand_one_wf(v_w,w_comb,d);
213  adjust_others_wf(v_w,hyp,w_comb,d);
214  }
215 
216  // for each expanded wavefront create a sub-grid iterator and add the sub-domain
217 
218  for (size_t d = 0 ; d < v_w.size() ; d++)
219  {
220  // Create a sub-grid iterator
222 
223  // iterate through all grid points
224 
225  while (g_sub.isNext())
226  {
227  // get the actual key
228  const grid_key_dx<dim> & gk = g_sub.get();
229 
230  // get the vertex and if does not have a sub-id and is assigned ...
231  long int pid = graph.vertex(gh.LinId(gk)).template get<p_sub>();
232 
233  // Get the processor id of the sub-sub-domain
234  long int pp_id = graph.vertex(gh.LinId(gk)).template get<p_id>();
235 
236  // if the sub-sub-domain is not assigned
237  if (pid < 0)
238  {
239  // ... and we are not processing the full graph
240  if (pr_id != -1)
241  {
242  // ... and the processor id of the sub-sub-domain match the part we are processing, add to the queue
243 
244  if ( pr_id == pp_id)
245  domains_new.add(gh.LinId(gk));
246  }
247  else
248  domains_new.add(gh.LinId(gk));
249  }
250 
251  ++g_sub;
252  }
253  }
254 
255  // copy the new queue to the old one (it not copied, C++11 move semantic)
256  domains.swap(domains_new);
257  }
258 
274  template <unsigned int p_sub, unsigned int p_id> void expand_from_point(size_t start_p, Graph & graph, Box<dim,size_t> & box, openfpm::vector<wavefront<dim>> & v_w , std::vector<comb<dim>> & w_comb)
275  {
276  // We assume that Graph is the rapresentation of a cartesian graph
277  // this mean that the direction d is at the child d
278 
279  // Get the number of wavefronts
280  size_t n_wf = w_comb.size();
281 
282  // Create an Hyper-cube
283  HyperCube<dim> hyp;
284 
285  // direction of expansion
286 
287  size_t domain_id = graph.vertex(start_p).template get<p_id>();
288  bool can_expand = true;
289 
290  // while is possible to expand
291 
292  while (can_expand)
293  {
294  // reset can expand
295  can_expand = false;
296 
297  // for each direction of expansion expand the wavefront
298 
299  for (size_t d = 0 ; d < n_wf ; d++)
300  {
301  // number of processed sub-domain
302  size_t n_proc_sub = 0;
303 
304  // flag to indicate if the wavefront can expand
305  bool w_can_expand = true;
306 
307  // Create an iterator of the expanded wavefront
308  grid_key_dx<dim> start = grid_key_dx<dim>(v_w.template get<wavefront<dim>::start>(d)) + w_comb[d];
309  grid_key_dx<dim> stop = grid_key_dx<dim>(v_w.template get<wavefront<dim>::stop>(d)) + w_comb[d];
311 
312  // for each sub-domain in the expanded wavefront
313  while (it.isNext())
314  {
315  // get the wavefront sub-domain id
316  size_t sub_w_e = gh.LinId(it.get());
317 
318  // we get the processor id of the neighborhood sub-domain on direction d
319  // (expanded wavefront)
320  size_t exp_p = graph.vertex(sub_w_e).template get<p_id>();
321 
322  // Check if already assigned
323  long int ass = graph.vertex(sub_w_e).template get<p_sub>();
324 
325  // we check if it is the same processor id and is not assigned
326  w_can_expand &= ((exp_p == domain_id) & (ass < 0));
327 
328  // next domain
329  ++it;
330 
331  // increase the number of processed sub-domain
332  n_proc_sub++;
333  }
334 
335  // if we did not processed sub-domain, we cannot expand
336  w_can_expand &= (n_proc_sub != 0);
337 
338  // if you can expand one wavefront we did not reach the end
339  can_expand |= w_can_expand;
340 
341  // if we can expand the wavefront expand it
342  if (w_can_expand == true)
343  {
344  // expand the wavefront
345  for (size_t j = 0 ; j < dim ; j++)
346  {
347  v_w.template get<wavefront<dim>::stop>(d)[j] = v_w.template get<wavefront<dim>::stop>(d)[j] + w_comb[d].c[j];
348  v_w.template get<wavefront<dim>::start>(d)[j] = v_w.template get<wavefront<dim>::start>(d)[j] + w_comb[d].c[j];
349  }
350 
351  // expand the intersection of the wavefronts
352 
353  if (dim >= 2)
354  {
355  std::vector<comb<dim>> q_comb = SubHyperCube<dim,dim-1>::getCombinations_R(w_comb[d],dim-2);
356 
357  // Eliminate the w_comb[d] direction
358 
359  for (size_t k = 0 ; k < q_comb.size() ; k++)
360  {
361  for (size_t j = 0 ; j < dim ; j++)
362  {
363  if (w_comb[d].c[j] != 0)
364  {
365  q_comb[k].c[j] = 0;
366  }
367  }
368  }
369 
370  // for all the combinations
371  for (size_t j = 0 ; j < q_comb.size() ; j++)
372  {
373  size_t id = hyp.LinId(q_comb[j]);
374 
375  // get the combination of the direction d
376 
377  bool is_pos = hyp.isPositive(d);
378 
379  // is positive, modify the stop point or the starting point
380 
381  for (size_t s = 0 ; s < dim ; s++)
382  {
383  if (is_pos == true)
384  {v_w.template get<wavefront<dim>::stop>(id)[s] = v_w.template get<wavefront<dim>::stop>(id)[s] + w_comb[d].c[s];}
385  else
386  {v_w.template get<wavefront<dim>::start>(id)[s] = v_w.template get<wavefront<dim>::start>(id)[s] + w_comb[d].c[s];}
387  }
388  }
389  }
390  }
391  }
392  }
393 
394  // get back the hyper-cube produced
395 
396  for (size_t i = 0 ; i < dim ; i++)
397  {
398  // get the index of the wavefront direction
399  size_t p_f = hyp.positiveFace(i);
400  size_t n_f = hyp.negativeFace(i);
401 
402  // set the box
403  box.setHigh(i,v_w.template get<wavefront<dim>::stop>(p_f)[i]);
404  box.setLow(i,v_w.template get<wavefront<dim>::start>(n_f)[i]);
405  }
406  }
407 
415  {
416  // Wavefront to initialize
417 
418  for (size_t i = 0 ; i < v_w.size() ; i++)
419  {
420  for (size_t j = 0 ; j < dim ; j++)
421  {
422  v_w.template get<wavefront<dim>::start>(i)[j] = start_p.get(j);
423  v_w.template get<wavefront<dim>::stop>(i)[j] = start_p.get(j);
424  }
425  }
426  }
427 
442  template<unsigned int p_id, unsigned int p_sub> grid_key_dx<dim> search_seed(Graph & graph, long int id)
443  {
444  // if no processor is selected return the first point
445  if (id < -1)
446  {
447  grid_key_dx<dim> key;
448  key.zero();
449 
450  return key;
451  }
452 
453  // Create a grid iterator
455 
456  // iterate through all grid points
457 
458  while (g_sub.isNext())
459  {
460  // get the actual key
461  const grid_key_dx<dim> & gk = g_sub.get();
462 
463  // if the subdomain has the id we are searching stop
464  if ((long int)graph.vertex(gh.LinId(gk)).template get<p_id>() == id && graph.vertex(gh.LinId(gk)).template get<p_sub>() == -1)
465  {
466  return gk;
467  }
468 
469  ++g_sub;
470  }
471 
472  // If not found return an invalid key
473  grid_key_dx<dim> key;
474  key.invalid();
475 
476  return key;
477  }
478 
479 
503  template <unsigned int p_sub, unsigned int p_id> size_t optimize(grid_key_dx<dim> & start_p, Graph & graph, long int pr_id, openfpm::vector<Box<dim,size_t>> & lb, openfpm::vector< openfpm::vector<size_t> > & box_nn_processor , const Ghost<dim,long int> & ghe ,const size_t (& bc)[dim], bool init_sub_id = true, size_t sub_id = 0)
504  {
505  // queue
507 
508  // box list 2
509  openfpm::vector< openfpm::vector<size_t> > box_nn_processor2;
510 
511  // Create an hyper-cube
512  HyperCube<dim> hyp;
513 
514  // Get the wavefront combinations
515  std::vector<comb<dim>> w_comb = hyp.getCombinations_R(dim-1);
516 
517  // wavefronts
518  openfpm::vector<wavefront<dim>> v_w(w_comb.size());
519 
520  // fill the sub decomposition with negative number
521 
522  if (init_sub_id == true)
523  fill_domain<p_sub>(graph,gh.getBox(),-1);
524 
525  // push the first domain
526  v_q.add(gh.LinId(start_p));
527 
528  while (v_q.size() != 0)
529  {
530  // Box
531  Box<dim,size_t> box;
532 
533  // Get the grid_key position from the linearized id
534  start_p = gh.InvLinId(v_q.get(0));
535 
536  // Initialize the wavefronts from the domain start_p
537  InitializeWavefront(start_p,v_w);
538 
539  // Create the biggest box containing the domain
540  expand_from_point<p_sub,p_id>(v_q.get(0),graph,box,v_w,w_comb);
541 
542  // Add the created box to the list of boxes
543  lb.add(box);
544 
545  // fill the domain
546  fill_domain<p_sub>(graph,box,sub_id);
547 
548  // add the surrounding sub-domain to the queue
549  add_to_queue<p_sub,p_id>(v_q,v_w,graph,w_comb,pr_id,bc);
550 
551  // increment the sub_id
552  sub_id++;
553  }
554 
555  return sub_id;
556  }
557 
572  template<unsigned int p_id> void construct_box_nn_processor(Graph & graph, openfpm::vector< openfpm::vector<size_t> > & box_nn_processor, const openfpm::vector<Box<dim,size_t>> & subs, const Ghost<dim,long int> & ghe, const size_t (& bc)[dim], long int pr_id)
573  {
574  std::unordered_map<size_t,size_t> map;
575 
576  for (size_t i = 0 ; i < subs.size() ; i++)
577  {
578  map.clear();
579  Box<dim,size_t> sub = subs.get(i);
580  sub.enlarge(ghe);
581 
582  grid_skin_iterator_bc<dim> gsi(gh,subs.get(i),sub,bc);
583 
584  while (gsi.isNext())
585  {
586  auto key = gsi.get();
587 
588  size_t pp_id = graph.vertex(gh.LinId(key)).template get<p_id>();
589  if (pr_id != (long int)pp_id)
590  map[pp_id] = pp_id;
591 
592  ++gsi;
593  }
594 
595  // Add the keys to box_nn_processors
596 
597  box_nn_processor.add();
598  for ( auto it = map.begin(); it != map.end(); ++it )
599  {
600  box_nn_processor.last().add(it->first);
601  }
602  }
603  }
604 
605 public:
606 
614  dec_optimizer(Graph & g, const size_t (& sz)[dim])
615  :gh(sz)
616  {
617  // The graph g is suppose to represent a cartesian grid
618  // No check is performed on g
619  }
620 
636  template <unsigned int p_sub, unsigned int p_id> void optimize(grid_key_dx<dim> & start_p, Graph & graph, const Ghost<dim,long int> & ghe , const size_t (& bc)[dim])
637  {
638  // temporal vector
640 
641  // temporal vector
642  openfpm::vector< openfpm::vector<size_t> > box_nn_processor;
643 
644  // optimize
645  optimize<p_sub,p_id>(start_p,graph,-1,tmp, box_nn_processor,ghe,bc);
646  }
647 
664  template <unsigned int p_sub, unsigned int p_id> void optimize(Graph & graph, long int pr_id, openfpm::vector<Box<dim,size_t>> & lb, openfpm::vector< openfpm::vector<size_t> > & box_nn_processor, const Ghost<dim,long int> & ghe, const size_t (& bc)[dim])
665  {
666  grid_key_dx<dim> key_seed;
667  key_seed.zero();
668 
669  // if processor is -1 call optimize with -1 to do on all processors and exit
670  if (pr_id == -1)
671  {
672  optimize<p_sub,p_id>(key_seed,graph,pr_id,lb,box_nn_processor,ghe,bc);
673 
674  // Construct box box_nn_processor from the constructed domain
675  construct_box_nn_processor<p_id>(graph,box_nn_processor,lb,ghe,bc,pr_id);
676 
677  return;
678  }
679 
680  size_t sub_id = 0;
681 
682  // fill the sub decomposition with negative number
683  fill_domain<p_sub>(graph,gh.getBox(),-1);
684 
685  key_seed = search_seed<p_id,p_sub>(graph,pr_id);
686 
687  while (key_seed.isValid())
688  {
689  // optimize
690  sub_id = optimize<p_sub,p_id>(key_seed,graph,pr_id,lb,box_nn_processor,ghe,bc,false,sub_id);
691 
692  // new seed
693  key_seed = search_seed<p_id,p_sub>(graph,pr_id);
694  }
695 
696  // Construct box box_nn_processor from the constructed domain
697  construct_box_nn_processor<p_id>(graph,box_nn_processor,lb,ghe,bc,pr_id);
698  }
699 };
700 
701 #endif
grid_key_dx< dim > search_seed(Graph &graph, long int id)
Get the first seed.
void optimize(grid_key_dx< dim > &start_p, Graph &graph, const Ghost< dim, long int > &ghe, const size_t(&bc)[dim])
optimize the graph
dec_optimizer(Graph &g, const size_t(&sz)[dim])
Constructor.
void construct_box_nn_processor(Graph &graph, openfpm::vector< openfpm::vector< size_t > > &box_nn_processor, const openfpm::vector< Box< dim, size_t >> &subs, const Ghost< dim, long int > &ghe, const size_t(&bc)[dim], long int pr_id)
Construct the sub-domain processor list.
void add_to_queue(openfpm::vector< size_t > &domains, openfpm::vector< wavefront< dim >> &v_w, Graph &graph, std::vector< comb< dim >> &w_comb, long int pr_id, const size_t(&bc)[dim])
Add the boundary domain of id p_id to the queue.
bool isNext()
Check if there is the next element.
__device__ __host__ grid_key_dx< N > InvLinId(mem_id id) const
Construct.
Definition: grid_sm.hpp:589
static std::vector< comb< dim > > getCombinations_R(size_t d)
Definition: HyperCube.hpp:100
Position of the element of dimension d in the hyper-cube of dimension dim.
Definition: comb.hpp:34
check if T::type and T.data has the same type
Definition: common.hpp:189
static int positiveFace(int d)
return the combination of the positive face on direction d
Definition: HyperCube.hpp:463
__device__ __host__ index_type get(index_type i) const
Get the i index.
Definition: grid_key.hpp:503
grid_sm< dim, void > gh
Contain information about the grid size.
size_t size()
Stub size.
Definition: map_vector.hpp:211
static bool isPositive(size_t d)
isPositive return if the combination d is a positive or a negative
Definition: HyperCube.hpp:451
static size_t LinId(comb< dim > &c)
Linearize the combination.
Definition: HyperCube.hpp:367
__device__ __host__ void setHigh(int i, T val)
set the high interval of the box
Definition: Box.hpp:544
mem_id LinId(const grid_key_dx< N, ids_type > &gk, const char sum_id[N]) const
Linearization of the grid_key_dx with a specified shift.
Definition: grid_sm.hpp:434
grid_key_dx< dim > getKP2() const
Get the point p12 as grid_key_dx.
Definition: Box.hpp:669
void expand_one_wf(openfpm::vector< wavefront< dim >> &v_w, std::vector< comb< dim >> &w_comb, size_t d)
Expand one wavefront.
static const int start
start point is the property with id 0 (first property)
size_t optimize(grid_key_dx< dim > &start_p, Graph &graph, long int pr_id, openfpm::vector< Box< dim, size_t >> &lb, openfpm::vector< openfpm::vector< size_t > > &box_nn_processor, const Ghost< dim, long int > &ghe, const size_t(&bc)[dim], bool init_sub_id=true, size_t sub_id=0)
optimize the graph
const grid_key_dx< dim > & get() const
Get the actual key.
The same as grid_key_dx_iterator_sub_p but with periodic boundary.
grid_key_dx< dim > get() const
Return the actual grid key iterator.
__device__ __host__ void setLow(int i, T val)
set the low interval of the box
Definition: Box.hpp:533
void enlarge(const Box< dim, T > &gh)
Enlarge the box with ghost margin.
Definition: Box.hpp:823
void expand_from_point(size_t start_p, Graph &graph, Box< dim, size_t > &box, openfpm::vector< wavefront< dim >> &v_w, std::vector< comb< dim >> &w_comb)
Find the biggest hyper-cube.
void fill_domain(Graph &graph, const Box< dim, size_t > &box, long int ids)
Fill the domain.
const grid_key_dx< dim > get() const
Return the actual grid key iterator.
void write_wavefront(Graph &graph, openfpm::vector< wavefront< dim >> &v_w)
Fill the wavefront position.
This class represent an N-dimensional box.
Definition: Box.hpp:60
Box< dim, size_t > & getBox()
Get the box enclosing this Box.
Definition: Box.hpp:623
void invalid()
Set to invalid the key.
Definition: grid_key.hpp:188
grid_key_dx< dim > get() const
Get the actual key.
static const int stop
stop point is the property with id 1 (second property)
This class take a graph representing the space decomposition and produce a simplified version.
Declaration grid_key_dx_iterator_sub.
Definition: grid_sm.hpp:156
void zero()
Set to zero the key.
Definition: grid_key.hpp:170
void adjust_others_wf(openfpm::vector< wavefront< dim >> &v_w, HyperCube< dim > &hyp, std::vector< comb< dim >> &w_comb, size_t d)
Adjust the other wavefronts.
static std::vector< comb< dim > > getCombinations_R(comb< dim > c, int d)
Definition: HyperCube.hpp:509
static int negativeFace(int d)
Return the combination of the negative face on direction d.
Definition: HyperCube.hpp:475
grid_key_dx< dim > getKP1() const
Get the point p1 as grid_key_dx.
Definition: Box.hpp:656
This class calculate elements of the hyper-cube.
Definition: HyperCube.hpp:57
Box< N, size_t > getBox() const
Return the box enclosing the grid.
Definition: grid_sm.hpp:294
bool isNext()
Check if there is the next element.
void InitializeWavefront(grid_key_dx< dim > &start_p, openfpm::vector< wavefront< dim >> &v_w)
Initialize the wavefronts.
void optimize(Graph &graph, long int pr_id, openfpm::vector< Box< dim, size_t >> &lb, openfpm::vector< openfpm::vector< size_t > > &box_nn_processor, const Ghost< dim, long int > &ghe, const size_t(&bc)[dim])
optimize the graph
Implementation of 1-D std::vector like structure.
Definition: map_vector.hpp:202
bool isNext()
Check if there is the next element.
this class represent a wavefront of dimension dim