OpenFPM_pdata  1.1.0
Project that contain the implementation of distributed structures
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Friends Pages
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 
38 template <unsigned int dim, typename Graph>
40 {
43 
44 private:
45 
53  void expand_one_wf(openfpm::vector<wavefront<dim>> & v_w, std::vector<comb<dim>> & w_comb , size_t d)
54  {
55  for (size_t j = 0 ; j < dim ; j++)
56  {
57  v_w.template get<wavefront<dim>::stop>(d)[j] = v_w.template get<wavefront<dim>::stop>(d)[j] + w_comb[d].c[j];
58  v_w.template get<wavefront<dim>::start>(d)[j] = v_w.template get<wavefront<dim>::start>(d)[j] + w_comb[d].c[j];
59  }
60  }
61 
62 
71  void adjust_others_wf(openfpm::vector<wavefront<dim>> & v_w, HyperCube<dim> & hyp, std::vector<comb<dim>> & w_comb, size_t d)
72  {
73  // expand the intersection of the wavefronts
74 
75  std::vector<comb<dim>> q_comb = SubHyperCube<dim,dim-1>::getCombinations_R(w_comb[d],dim-2);
76 
77  // Eliminate the w_comb[d] direction
78 
79  for (size_t k = 0 ; k < q_comb.size() ; k++)
80  {
81  for (size_t j = 0 ; j < dim ; j++)
82  {
83  if (w_comb[d].c[j] != 0)
84  {
85  q_comb[k].c[j] = 0;
86  }
87  }
88  }
89 
90  // for all the combinations
91  for (size_t j = 0 ; j < q_comb.size() ; j++)
92  {
93  size_t id = hyp.LinId(q_comb[j]);
94 
95  // get the combination of the direction d
96  bool is_pos = hyp.isPositive(d);
97 
98  // is positive, modify the stop point or the starting point
99 
100  for (size_t s = 0 ; s < dim ; s++)
101  {
102  if (is_pos == true)
103  {v_w.template get<wavefront<dim>::stop>(id)[s] = v_w.template get<wavefront<dim>::stop>(id)[s] + w_comb[d].c[s];}
104  else
105  {v_w.template get<wavefront<dim>::start>(id)[s] = v_w.template get<wavefront<dim>::start>(id)[s] + w_comb[d].c[s];}
106  }
107  }
108  }
109 
118  template<unsigned int prp> void write_wavefront(Graph & graph,openfpm::vector<wavefront<dim>> & v_w)
119  {
120  // fill the wall domain with 0
121 
122  fill_domain<prp>(graph,gh.getBox(),0);
123 
124  // fill the wavefront
125 
126  for (int i = 0 ; i < v_w.size() ; i++)
127  {
128  Box<dim,size_t> box = wavefront<dim>::getBox(v_w.get(i));
129 
130  fill_domain<prp>(graph,box,1);
131  }
132  }
133 
144  template<unsigned int p_sub> void fill_domain(Graph & graph,const Box<dim,size_t> & box, long int ids)
145  {
146  // Create a subgrid iterator
148 
149  // iterate through all grid points
150 
151  while (g_sub.isNext())
152  {
153  // get the actual key
154  const grid_key_dx<dim> & gk = g_sub.get();
155 
156  // get the vertex and set the sub id
157 
158  graph.vertex(gh.LinId(gk)).template get<p_sub>() = ids;
159 
160  // next subdomain
161  ++g_sub;
162  }
163  }
164 
178  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])
179  {
180  // create a new queue
181  openfpm::vector<size_t> domains_new;
182 
183  // push in the new queue, the old domains of the queue that are not assigned element
184 
185  for (size_t j = 0 ; j < domains.size() ; j++)
186  {
187  long int gs = graph.vertex(domains.get(j)).template get<p_sub>();
188  if (gs < 0)
189  {
190  // not assigned push it
191 
192  domains_new.add(domains.get(j));
193  }
194  }
195 
196  // Create an Hyper-cube
197  HyperCube<dim> hyp;
198 
199  for (size_t d = 0 ; d < v_w.size() ; d++)
200  {
201  expand_one_wf(v_w,w_comb,d);
202  adjust_others_wf(v_w,hyp,w_comb,d);
203  }
204 
205  // for each expanded wavefront create a sub-grid iterator and add the sub-domain
206 
207  for (size_t d = 0 ; d < v_w.size() ; d++)
208  {
209  // Create a sub-grid iterator
211 
212  // iterate through all grid points
213 
214  while (g_sub.isNext())
215  {
216  // get the actual key
217  const grid_key_dx<dim> & gk = g_sub.get();
218 
219  // get the vertex and if does not have a sub-id and is assigned ...
220  long int pid = graph.vertex(gh.LinId(gk)).template get<p_sub>();
221 
222  // Get the processor id of the sub-sub-domain
223  long int pp_id = graph.vertex(gh.LinId(gk)).template get<p_id>();
224 
225  // if the sub-sub-domain is not assigned
226  if (pid < 0)
227  {
228  // ... and we are not processing the full graph
229  if (pr_id != -1)
230  {
231  // ... and the processor id of the sub-sub-domain match the part we are processing, add to the queue
232 
233  if ( pr_id == pp_id)
234  domains_new.add(gh.LinId(gk));
235  }
236  else
237  domains_new.add(gh.LinId(gk));
238  }
239 
240  ++g_sub;
241  }
242  }
243 
244  // copy the new queue to the old one (it not copied, C++11 move semantic)
245  domains.swap(domains_new);
246  }
247 
263  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)
264  {
265  // We assume that Graph is the rapresentation of a cartesian graph
266  // this mean that the direction d is at the child d
267 
268  // Get the number of wavefronts
269  size_t n_wf = w_comb.size();
270 
271  // Create an Hyper-cube
272  HyperCube<dim> hyp;
273 
274  // direction of expansion
275 
276  size_t domain_id = graph.vertex(start_p).template get<p_id>();
277  bool can_expand = true;
278 
279  // while is possible to expand
280 
281  while (can_expand)
282  {
283  // reset can expand
284  can_expand = false;
285 
286  // for each direction of expansion expand the wavefront
287 
288  for (size_t d = 0 ; d < n_wf ; d++)
289  {
290  // number of processed sub-domain
291  size_t n_proc_sub = 0;
292 
293  // flag to indicate if the wavefront can expand
294  bool w_can_expand = true;
295 
296  // Create an iterator of the expanded wavefront
297  grid_key_dx<dim> start = grid_key_dx<dim>(v_w.template get<wavefront<dim>::start>(d)) + w_comb[d];
298  grid_key_dx<dim> stop = grid_key_dx<dim>(v_w.template get<wavefront<dim>::stop>(d)) + w_comb[d];
300 
301  // for each sub-domain in the expanded wavefront
302  while (it.isNext())
303  {
304  // get the wavefront sub-domain id
305  size_t sub_w_e = gh.LinId(it.get());
306 
307  // we get the processor id of the neighborhood sub-domain on direction d
308  // (expanded wavefront)
309  size_t exp_p = graph.vertex(sub_w_e).template get<p_id>();
310 
311  // Check if already assigned
312  long int ass = graph.vertex(sub_w_e).template get<p_sub>();
313 
314  // we check if it is the same processor id and is not assigned
315  w_can_expand &= ((exp_p == domain_id) & (ass < 0));
316 
317  // next domain
318  ++it;
319 
320  // increase the number of processed sub-domain
321  n_proc_sub++;
322  }
323 
324  // if we did not processed sub-domain, we cannot expand
325  w_can_expand &= (n_proc_sub != 0);
326 
327  // if you can expand one wavefront we did not reach the end
328  can_expand |= w_can_expand;
329 
330  // if we can expand the wavefront expand it
331  if (w_can_expand == true)
332  {
333  // expand the wavefront
334  for (size_t j = 0 ; j < dim ; j++)
335  {
336  v_w.template get<wavefront<dim>::stop>(d)[j] = v_w.template get<wavefront<dim>::stop>(d)[j] + w_comb[d].c[j];
337  v_w.template get<wavefront<dim>::start>(d)[j] = v_w.template get<wavefront<dim>::start>(d)[j] + w_comb[d].c[j];
338  }
339 
340  // expand the intersection of the wavefronts
341 
342  if (dim >= 2)
343  {
344  std::vector<comb<dim>> q_comb = SubHyperCube<dim,dim-1>::getCombinations_R(w_comb[d],dim-2);
345 
346  // Eliminate the w_comb[d] direction
347 
348  for (size_t k = 0 ; k < q_comb.size() ; k++)
349  {
350  for (size_t j = 0 ; j < dim ; j++)
351  {
352  if (w_comb[d].c[j] != 0)
353  {
354  q_comb[k].c[j] = 0;
355  }
356  }
357  }
358 
359  // for all the combinations
360  for (size_t j = 0 ; j < q_comb.size() ; j++)
361  {
362  size_t id = hyp.LinId(q_comb[j]);
363 
364  // get the combination of the direction d
365 
366  bool is_pos = hyp.isPositive(d);
367 
368  // is positive, modify the stop point or the starting point
369 
370  for (size_t s = 0 ; s < dim ; s++)
371  {
372  if (is_pos == true)
373  {v_w.template get<wavefront<dim>::stop>(id)[s] = v_w.template get<wavefront<dim>::stop>(id)[s] + w_comb[d].c[s];}
374  else
375  {v_w.template get<wavefront<dim>::start>(id)[s] = v_w.template get<wavefront<dim>::start>(id)[s] + w_comb[d].c[s];}
376  }
377  }
378  }
379  }
380  }
381  }
382 
383  // get back the hyper-cube produced
384 
385  for (size_t i = 0 ; i < dim ; i++)
386  {
387  // get the index of the wavefront direction
388  size_t p_f = hyp.positiveFace(i);
389  size_t n_f = hyp.negativeFace(i);
390 
391  // set the box
392  box.setHigh(i,v_w.template get<wavefront<dim>::stop>(p_f)[i]);
393  box.setLow(i,v_w.template get<wavefront<dim>::start>(n_f)[i]);
394  }
395  }
396 
404  {
405  // Wavefront to initialize
406 
407  for (size_t i = 0 ; i < v_w.size() ; i++)
408  {
409  for (size_t j = 0 ; j < dim ; j++)
410  {
411  v_w.template get<wavefront<dim>::start>(i)[j] = start_p.get(j);
412  v_w.template get<wavefront<dim>::stop>(i)[j] = start_p.get(j);
413  }
414  }
415  }
416 
431  template<unsigned int p_id, unsigned int p_sub> grid_key_dx<dim> search_seed(Graph & graph, long int id)
432  {
433  // if no processor is selected return the first point
434  if (id < -1)
435  {
437  key.zero();
438 
439  return key;
440  }
441 
442  // Create a grid iterator
444 
445  // iterate through all grid points
446 
447  while (g_sub.isNext())
448  {
449  // get the actual key
450  const grid_key_dx<dim> & gk = g_sub.get();
451 
452  // if the subdomain has the id we are searching stop
453  if ((long int)graph.vertex(gh.LinId(gk)).template get<p_id>() == id && graph.vertex(gh.LinId(gk)).template get<p_sub>() == -1)
454  {
455  return gk;
456  }
457 
458  ++g_sub;
459  }
460 
461  // If not found return an invalid key
463  key.invalid();
464 
465  return key;
466  }
467 
468 
492  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)
493  {
494  // queue
496 
497  // box list 2
498  openfpm::vector< openfpm::vector<size_t> > box_nn_processor2;
499 
500  // Create an hyper-cube
501  HyperCube<dim> hyp;
502 
503  // Get the wavefront combinations
504  std::vector<comb<dim>> w_comb = hyp.getCombinations_R(dim-1);
505 
506  // wavefronts
507  openfpm::vector<wavefront<dim>> v_w(w_comb.size());
508 
509  // fill the sub decomposition with negative number
510 
511  if (init_sub_id == true)
512  fill_domain<p_sub>(graph,gh.getBox(),-1);
513 
514  // push the first domain
515  v_q.add(gh.LinId(start_p));
516 
517  while (v_q.size() != 0)
518  {
519  // Box
520  Box<dim,size_t> box;
521 
522  // Get the grid_key position from the linearized id
523  start_p = gh.InvLinId(v_q.get(0));
524 
525  // Initialize the wavefronts from the domain start_p
526  InitializeWavefront(start_p,v_w);
527 
528  // Create the biggest box containing the domain
529  expand_from_point<p_sub,p_id>(v_q.get(0),graph,box,v_w,w_comb);
530 
531  // Add the created box to the list of boxes
532  lb.add(box);
533 
534  // fill the domain
535  fill_domain<p_sub>(graph,box,sub_id);
536 
537  // add the surrounding sub-domain to the queue
538  add_to_queue<p_sub,p_id>(v_q,v_w,graph,w_comb,pr_id,bc);
539 
540  // increment the sub_id
541  sub_id++;
542  }
543 
544  return sub_id;
545  }
546 
561  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)
562  {
563  std::unordered_map<size_t,size_t> map;
564 
565  for (size_t i = 0 ; i < subs.size() ; i++)
566  {
567  map.clear();
568  Box<dim,size_t> sub = subs.get(i);
569  sub.enlarge(ghe);
570 
571  grid_skin_iterator_bc<dim> gsi(gh,subs.get(i),sub,bc);
572 
573  while (gsi.isNext())
574  {
575  auto key = gsi.get();
576 
577  size_t pp_id = graph.vertex(gh.LinId(key)).template get<p_id>();
578  if (pr_id != (long int)pp_id)
579  map[pp_id] = pp_id;
580 
581  ++gsi;
582  }
583 
584  // Add the keys to box_nn_processors
585 
586  box_nn_processor.add();
587  for ( auto it = map.begin(); it != map.end(); ++it )
588  {
589  box_nn_processor.last().add(it->first);
590  }
591  }
592  }
593 
594 public:
595 
603  dec_optimizer(Graph & g, const size_t (& sz)[dim])
604  :gh(sz)
605  {
606  // The graph g is suppose to represent a cartesian grid
607  // No check is performed on g
608  }
609 
625  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])
626  {
627  // temporal vector
629 
630  // temporal vector
631  openfpm::vector< openfpm::vector<size_t> > box_nn_processor;
632 
633  // optimize
634  optimize<p_sub,p_id>(start_p,graph,-1,tmp, box_nn_processor,ghe,bc);
635  }
636 
653  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])
654  {
655  grid_key_dx<dim> key_seed;
656  key_seed.zero();
657 
658  // if processor is -1 call optimize with -1 to do on all processors and exit
659  if (pr_id == -1)
660  {
661  optimize<p_sub,p_id>(key_seed,graph,pr_id,lb,box_nn_processor,ghe,bc);
662 
663  // Construct box box_nn_processor from the constructed domain
664  construct_box_nn_processor<p_id>(graph,box_nn_processor,lb,ghe,bc,pr_id);
665 
666  return;
667  }
668 
669  size_t sub_id = 0;
670 
671  // fill the sub decomposition with negative number
672  fill_domain<p_sub>(graph,gh.getBox(),-1);
673 
674  key_seed = search_seed<p_id,p_sub>(graph,pr_id);
675 
676  while (key_seed.isValid())
677  {
678  // optimize
679  sub_id = optimize<p_sub,p_id>(key_seed,graph,pr_id,lb,box_nn_processor,ghe,bc,false,sub_id);
680 
681  // new seed
682  key_seed = search_seed<p_id,p_sub>(graph,pr_id);
683  }
684 
685  // Construct box box_nn_processor from the constructed domain
686  construct_box_nn_processor<p_id>(graph,box_nn_processor,lb,ghe,bc,pr_id);
687  }
688 };
689 
690 #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.
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
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.
static std::vector< comb< dim > > getCombinations_R(size_t d)
Definition: HyperCube.hpp:100
grid_key_dx is the key to access any element in the grid
Definition: grid_key.hpp:18
Position of the element of dimension d in the hyper-cube of dimension dim.
Definition: comb.hpp:34
grid_key_dx< dim > getKP2() const
Get the point p12 as grid_key_dx.
Definition: Box.hpp:592
void invalid()
Set to invalid the key.
Definition: grid_key.hpp:134
const Box< N, size_t > & getBox() const
Return the box enclosing the grid.
Definition: grid_sm.hpp:197
static int positiveFace(int d)
return the combination of the positive face on direction d
Definition: HyperCube.hpp:460
void setHigh(int i, T val)
set the high interval of the box
Definition: Box.hpp:467
size_t size()
Stub size.
Definition: map_vector.hpp:70
grid_sm< dim, void > gh
Contain information about the grid size.
bool isNext()
Check if there is the next element.
grid_key_dx< N > InvLinId(mem_id id) const
Construct.
Definition: grid_sm.hpp:503
grid_key_dx< dim > getKP1() const
Get the point p1 as grid_key_dx.
Definition: Box.hpp:579
static bool isPositive(size_t d)
isPositive return if the combination d is a positive or a negative
Definition: HyperCube.hpp:448
static size_t LinId(comb< dim > &c)
Linearize the combination.
Definition: HyperCube.hpp:367
mem_id get(size_t i) const
Get the i index.
Definition: grid_key.hpp:394
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
The same as grid_key_dx_iterator_sub_p but with periodic boundary.
void enlarge(const Box< dim, T > &gh)
Enlarge the box with ghost margin.
Definition: Box.hpp:700
void zero()
Set to zero the key.
Definition: grid_key.hpp:116
const grid_key_dx< dim > & get() const
Get the actual key.
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.
void setLow(int i, T val)
set the low interval of the box
Definition: Box.hpp:456
bool isNext()
Check if there is the next element.
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:56
Box< dim, size_t > & getBox()
Get the box enclosing this Box.
Definition: Box.hpp:546
grid_key_dx< dim > get() const
Return the actual grid key iterator.
This class is a trick to indicate the compiler a specific specialization pattern. ...
Definition: memory_c.hpp:201
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:77
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:506
static int negativeFace(int d)
Return the combination of the negative face on direction d.
Definition: HyperCube.hpp:472
This class calculate elements of the hyper-cube.
Definition: HyperCube.hpp:57
const grid_key_dx< dim > get() const
Return the actual grid key iterator.
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:61
bool isNext()
Check if there is the next element.
this class represent a wavefront of dimension dim