1/*
2 * ie_ghost.hpp
3 *
4 * Created on: Aug 8, 2015
5 * Author: i-bird
6 */
7
8#ifndef SRC_DECOMPOSITION_GHOST_DEC_IE_GHOST_HPP_
9#define SRC_DECOMPOSITION_GHOST_DEC_IE_GHOST_HPP_
10
11#include "Space/Shape/Box.hpp"
12#include "Space/Ghost.hpp"
13#include "Space/SpaceBox.hpp"
14#include "common.hpp"
15#include "VTKWriter/VTKWriter.hpp"
16#include "nn_processor.hpp"
17
18/*! \brief structure that store and compute the internal and external local ghost box
19 *
20 * \tparam dim is the dimensionality of the physical domain we are going to decompose.
21 * \tparam T type of the space we decompose, Real, Integer, Complex ...
22 *
23 * \see CartDecomposition
24 *
25 */
26template<unsigned int dim, typename T, template <typename> class layout_base, typename Memory>
27class ie_loc_ghost
28{
29 //! It contain the calculated local ghost boxes
30 openfpm::vector<lBox_dom<dim,T>> loc_ghost_box;
31
32 //! temporal added sub-domains
33 openfpm::vector<Box_loc_sub<dim,T>> sub_domains_tmp;
34
35 /*! \brief Create the external local ghost boxes
36 *
37 * \param ghost part
38 * \param sub_domains list of local sub-domains
39 * \param sub_domains_prc list of sub-domains from the neighborhood processors
40 *
41 */
42 void create_loc_ghost_ebox(Ghost<dim,T> & ghost,
43 openfpm::vector<SpaceBox<dim,T>,Memory,layout_base> & sub_domains,
44 openfpm::vector<Box_loc_sub<dim,T>> & sub_domains_prc)
45 {
46 comb<dim> zero;
47 zero.zero();
48
49 loc_ghost_box.resize(sub_domains.size());
50
51 // For each sub-domain
52 for (size_t i = 0 ; i < sub_domains.size() ; i++)
53 {
54 SpaceBox<dim,T> sub_with_ghost = sub_domains.get(i);
55
56 // enlarge the sub-domain with the ghost
57 sub_with_ghost.enlarge(ghost);
58
59 // intersect with the other local sub-domains
60 for (size_t j = 0 ; j < sub_domains_prc.size() ; j++)
61 {
62 size_t rj = sub_domains_prc.get(j).sub;
63
64 if (rj == i && sub_domains_prc.get(j).cmb == zero)
65 continue;
66
67 ::Box<dim,T> bi;
68
69 bool intersect = sub_with_ghost.Intersect(sub_domains_prc.get(j).bx,bi);
70
71 if (intersect == true)
72 {
73 Box_sub_k<dim,T> b;
74 b.sub = rj;
75 b.bx = bi;
76 b.cmb = sub_domains_prc.get(j).cmb;
77
78 // local external ghost box
79 loc_ghost_box.get(i).ebx.add(b);
80
81 // search this box in the internal box of the sub-domain j
82 for (size_t k = 0; k < loc_ghost_box.get(rj).ibx.size() ; k++)
83 {
84 if (loc_ghost_box.get(rj).ibx.get(k).sub == i && loc_ghost_box.get(rj).ibx.get(k).cmb == sub_domains_prc.get(j).cmb.operator-())
85 {
86 loc_ghost_box.get(rj).ibx.get(k).k = loc_ghost_box.get(i).ebx.size()-1;
87 loc_ghost_box.get(i).ebx.last().k = k;
88 break;
89 }
90 }
91 }
92 }
93 }
94 }
95
96 /*! \brief Create the internal local ghost boxes
97 *
98 * \param ghost part
99 * \param sub_domains local sub-domains
100 * \param sub_domains_prc list of sub-domains from the neighborhood processors
101 *
102 */
103 void create_loc_ghost_ibox(Ghost<dim,T> & ghost,
104 openfpm::vector<SpaceBox<dim,T>,Memory,layout_base> & sub_domains,
105 openfpm::vector<Box_loc_sub<dim,T>> & sub_domains_prc)
106 {
107 comb<dim> zero;
108 zero.zero();
109
110 loc_ghost_box.resize(sub_domains.size());
111
112 // For each sub-domain
113 for (size_t i = 0 ; i < sub_domains.size() ; i++)
114 {
115 // intersect with the others local sub-domains
116 for (size_t j = 0 ; j < sub_domains_prc.size() ; j++)
117 {
118 SpaceBox<dim,T> sub_with_ghost = sub_domains_prc.get(j).bx;
119 size_t rj = sub_domains_prc.get(j).sub;
120
121 // Avoid to intersect the box with itself
122 if (rj == i && sub_domains_prc.get(j).cmb == zero)
123 continue;
124
125 // enlarge the sub-domain with the ghost
126 sub_with_ghost.enlarge(ghost);
127
128 ::Box<dim,T> bi;
129
130 bool intersect = sub_with_ghost.Intersect(::SpaceBox<dim,T>(sub_domains.get(i)),bi);
131
132 if (intersect == true)
133 {
134 Box_sub_k<dim,T> b;
135 b.sub = rj;
136 b.bx = bi;
137 b.k = -1;
138 b.cmb = sub_domains_prc.get(j).cmb;
139
140 loc_ghost_box.get(i).ibx.add(b);
141 }
142 }
143 }
144 }
145
146 /*! \brief In case of periodic boundary conditions we replicate the sub-domains at the border
147 *
148 * \param sub_domains list of sub-domains
149 * \param domain Domain box
150 * \param ghost part
151 * \param bc boundary conditions
152 *
153 */
154 void applyBC(openfpm::vector<Box_loc_sub<dim,T>> & sub_domains, const Box<dim,T> & domain, const Ghost<dim,T> & ghost, const size_t (&bc)[dim])
155 {
156 HyperCube<dim> hyp;
157
158 // first we create boxes at the border of the domain used to detect the sub-domain
159 // that must be adjusted, each of this boxes define a shift in case of periodic boundary condition
160 for (long int i = dim-1 ; i >= 0 ; i--)
161 {
162 std::vector<comb<dim>> cmbs = hyp.getCombinations_R_bc(i,bc);
163
164 for (size_t j = 0 ; j < cmbs.size() ; j++)
165 {
166 if (nn_prcs<dim,T,layout_base,Memory>::check_valid(cmbs[j],bc) == false)
167 continue;
168
169 Box<dim,T> bp;
170 Point<dim,T> shift;
171
172 for (size_t k = 0 ; k < dim ; k++)
173 {
174 switch (cmbs[j][k])
175 {
176 case 1:
177 bp.setLow(k,domain.getHigh(k)+ghost.getLow(k));
178 bp.setHigh(k,domain.getHigh(k));
179 shift.get(k) = -domain.getHigh(k)+domain.getLow(k);
180 break;
181 case 0:
182 bp.setLow(k,domain.getLow(k));
183 bp.setHigh(k,domain.getHigh(k));
184 shift.get(k) = 0;
185 break;
186 case -1:
187 bp.setLow(k,domain.getLow(k));
188 bp.setHigh(k,ghost.getHigh(k));
189 shift.get(k) = domain.getHigh(k)-domain.getLow(k);
190 break;
191 }
192 }
193
194 // Detect all the sub-domain involved, shift them and add to the list
195 // Detection is performed intersecting the sub-domains with the ghost
196 // parts near the domain borders
197 for (size_t k = 0 ; k < sub_domains.size() ; k++)
198 {
199 Box<dim,T> sub = sub_domains.get(k).bx;
200 Box<dim,T> b_int;
201
202 if (sub.Intersect(bp,b_int) == true)
203 {
204 sub += shift;
205 add_subdomain(Box_loc_sub<dim,T>(sub,k,cmbs[j]));
206 }
207 }
208 }
209 }
210
211 flush(sub_domains);
212 }
213
214
215
216 /*! \brief add sub-domains to a temporal list
217 *
218 * \param bx Box to add
219 *
220 */
221 inline void add_subdomain(const Box_loc_sub<dim,T> & bx)
222 {
223 sub_domains_tmp.add(bx);
224 }
225
226 /*! \brief Flush the temporal added sub-domain to the sub-domain list
227 *
228 * \param sub_domains to add (In general they come from mirroring periodic
229 * boundary conditions)
230 *
231 */
232 void flush(openfpm::vector<Box_loc_sub<dim,T>> & sub_domains)
233 {
234 for (size_t i = 0 ; i < sub_domains_tmp.size() ; i++)
235 {
236 sub_domains.add(sub_domains_tmp.get(i));
237 }
238
239 sub_domains_tmp.clear();
240 }
241
242public:
243
244 /*! \brief Create external and internal local ghosts
245 *
246 * \param sub_domains list of local sub-domains
247 * \param domain simulation domain
248 * \param ghost boundary
249 * \param bc Boundary conditions
250 *
251 */
252 void create(openfpm::vector<SpaceBox<dim,T>,Memory,layout_base> & sub_domains, Box<dim,T> & domain , Ghost<dim,T> & ghost , const size_t (&bc)[dim] )
253 {
254 // It will store local sub-domains + borders
255 openfpm::vector<Box_loc_sub<dim,T>> sub_domains_prc;
256
257 comb<dim> zero;
258 zero.zero();
259
260 // Copy sub_domains into sub_domains_prc
261 for (size_t i = 0 ; i < sub_domains.size() ; i++)
262 {
263 Box_loc_sub<dim,T> bls(SpaceBox<dim,T>(sub_domains.get(i)),i,zero);
264 sub_domains_prc.add(bls);
265 sub_domains_prc.last().sub = i;
266 }
267
268 applyBC(sub_domains_prc,domain,ghost,bc);
269
270 create_loc_ghost_ibox(ghost,sub_domains,sub_domains_prc);
271 create_loc_ghost_ebox(ghost,sub_domains,sub_domains_prc);
272 }
273
274 //! Default constructor
275 ie_loc_ghost() {};
276
277 //! Constructor from another ie_loc_ghost
278 ie_loc_ghost(const ie_loc_ghost<dim,T,layout_base,Memory> & ilg)
279 {
280 this->operator=(ilg);
281 };
282
283 //! Constructor from temporal ie_loc_ghost
284 ie_loc_ghost(ie_loc_ghost<dim,T,layout_base,Memory> && ilg)
285 {
286 this->operator=(ilg);
287 }
288
289 /*! \brief copy the ie_loc_ghost
290 *
291 * \param ilg object to copy
292 *
293 * \return itself
294 *
295 */
296 ie_loc_ghost<dim,T,layout_base,Memory> & operator=(const ie_loc_ghost<dim,T,layout_base,Memory> & ilg)
297 {
298 loc_ghost_box = ilg.loc_ghost_box;
299 return *this;
300 }
301
302 /*! \brief copy the ie_loc_ghost
303 *
304 * \param ilg object to copy
305 *
306 * \return itself
307 *
308 */
309 ie_loc_ghost<dim,T,layout_base,Memory> & operator=(ie_loc_ghost<dim,T,layout_base,Memory> && ilg)
310 {
311 loc_ghost_box.swap(ilg.loc_ghost_box);
312 return *this;
313 }
314
315 /*! \brief copy the ie_loc_ghost
316 *
317 * \param ilg object to copy
318 *
319 * \return itself
320 *
321 */
322 template<template <typename> class layout_base2, typename Memory2>
323 ie_loc_ghost<dim,T,layout_base,Memory> & operator=(const ie_loc_ghost<dim,T,layout_base2,Memory2> & ilg)
324 {
325 loc_ghost_box = ilg.private_get_loc_ghost_box();
326 return *this;
327 }
328
329 /*! \brief copy the ie_loc_ghost
330 *
331 * \param ilg object to copy
332 *
333 * \return itself
334 *
335 */
336 template<template <typename> class layout_base2, typename Memory2>
337 ie_loc_ghost<dim,T,layout_base,Memory> & operator=(ie_loc_ghost<dim,T,layout_base2,Memory2> && ilg)
338 {
339 loc_ghost_box.swap(ilg.private_get_loc_ghost_box());
340 return *this;
341 }
342
343 /*! \brief Get the internal loc_ghost_box
344 *
345 * \return the internal loc_ghost_box
346 *
347 */
348 inline openfpm::vector<lBox_dom<dim,T>> & private_get_loc_ghost_box()
349 {
350 return loc_ghost_box;
351 }
352
353 /*! \brief Get the number of local sub-domains
354 *
355 * \return the number of local sub-domains
356 *
357 *
358 */
359 inline size_t getNLocalSub()
360 {
361 return loc_ghost_box.size();
362 }
363
364 /*! \brief Get the number of external local ghost box for each sub-domain
365 *
366 * \param id sub-domain id
367 *
368 * \return the number of external ghost box
369 *
370 */
371 inline size_t getLocalNEGhost(size_t id)
372 {
373 return loc_ghost_box.get(id).ebx.size();
374 }
375
376 /*! \brief Get the number of internal local ghost box for each sub-domain
377 *
378 * \param id sub-domain id
379 *
380 * \return the number of internal ghost box
381 *
382 */
383 inline size_t getLocalNIGhost(size_t id)
384 {
385 return loc_ghost_box.get(id).ibx.size();
386 }
387
388 /*! \brief For the sub-domain i intersected with a surrounding sub-domain enlarged. Produce a internal ghost box from
389 * the prospecive of i and an associated external ghost box from the prospective of j.
390 * In order to retrieve the information about the external ghost box we have to use getLocalEGhostBox(x,k).
391 * where k is the value returned by getLocalIGhostE(i,j) and x is the value returned by
392 * getLocalIGhostSub(i,j)
393 *
394 * \param i
395 * \param j
396 *
397 * \return k
398 *
399 */
400 inline size_t getLocalIGhostE(size_t i, size_t j)
401 {
402 return loc_ghost_box.get(i).ibx.get(j).k;
403 }
404
405 /*! \brief Get the j internal local ghost box for the i sub-domain
406 *
407 * \note For the sub-domain i intersected with the sub-domain j enlarged, the associated
408 * external ghost box is located in getLocalIGhostBox(j,k) with
409 * getLocalIGhostSub(j,k) == i
410 *
411 * To get k use getLocalIGhostE
412 *
413 * \see getLocalIGhostE
414 *
415 * \param i sub-domain
416 * \param j box
417 * \return the box
418 *
419 */
420 inline const ::Box<dim,T> & getLocalIGhostBox(size_t i, size_t j) const
421 {
422 return loc_ghost_box.get(i).ibx.get(j).bx;
423 }
424
425 /*! \brief Get the j internal local ghost box boundary position for the i sub-domain of the local processor
426 *
427 * \note For the sub-domain i intersected with the sub-domain j enlarged, the associated
428 * external ghost box is located in getLocalIGhostBox(j,k) with
429 * getLocalIGhostSub(j,k) == i
430 *
431 * To get k use getLocalIGhostE
432 *
433 * \see getLocalIGhostE
434 *
435 * Some of the intersection boxes has special position, because they are at the boundary, this function
436 * return their position at the border
437 *
438 \verbatim
439
440 [1,1]
441 +---------+------------------------+---------+
442 | (1,-1) | | (1,1) |
443 | | | (1,0) --> 7 | | |
444 | v | | v |
445 | 6 | | 8 |
446 +--------------------------------------------+
447 | | | |
448 | | | |
449 | | | |
450 | (-1,0) | | (1,0) |
451 | | | | | |
452 | v | (0,0) --> 4 | v |
453 | 3 | | 5 |
454 | | | |
455 | | | |
456 | | | |
457 | | | |
458 | | | |
459 | | | |
460 +--------------------------------------------+
461 | (-1,-1) | | (-1,1) |
462 | | | (-1,0) --> 1 | | |
463 | v | | v |
464 | 0 | | 2 |
465 +---------+------------------------+---------+
466
467
468 \endverbatim
469 *
470 * \param i sub-domain
471 * \param j box
472 * \return the box
473 *
474 */
475 inline const comb<dim> & getLocalIGhostPos(size_t i, size_t j) const
476 {
477 return loc_ghost_box.get(i).ibx.get(j).cmb;
478 }
479
480 /*! \brief Get the j external local ghost box for the local processor
481 *
482 * \param i sub-domain
483 * \param j box
484 * \return the box
485 *
486 */
487 inline const ::Box<dim,T> & getLocalEGhostBox(size_t i, size_t j) const
488 {
489 return loc_ghost_box.get(i).ebx.get(j).bx;
490 }
491
492 /*! \brief Get the j external local ghost box for the local processor
493 *
494 * \param i sub-domain
495 * \param j box
496 * \return the box
497 *
498 */
499 inline const comb<dim> & getLocalEGhostPos(size_t i, size_t j) const
500 {
501 return loc_ghost_box.get(i).ebx.get(j).cmb;
502 }
503
504 /*! \brief Considering that sub-domains has N internal local ghost box identified
505 * with the 0 <= k < N that come from the intersection of 2 sub-domains i and j
506 * where j is enlarged, given the sub-domain i and the id k of the internal box,
507 * it return the id j of the other sub-domain that produced the intersection
508 *
509 * \param i sub-domain
510 * \param k id
511 * \return j
512 *
513 */
514 inline size_t getLocalIGhostSub(size_t i, size_t k) const
515 {
516 return loc_ghost_box.get(i).ibx.get(k).sub;
517 }
518
519 /*! \brief Considering that sub-domains has N external local ghost box identified
520 * with the 0 <= k < N that come from the intersection of 2 sub-domains i and j
521 * where i is enlarged, given the sub-domain i and the id k of the external box,
522 * it return the id of the other sub-domain j that produced the intersection
523 *
524 * \param i sub-domain
525 * \param k id
526 * \return j
527 *
528 */
529 inline size_t getLocalEGhostSub(size_t i, size_t k) const
530 {
531 return loc_ghost_box.get(i).ebx.get(k).sub;
532 }
533
534 /*! \brief Write the decomposition as VTK file
535 *
536 * The function generate several files
537 *
538 * 5) local_internal_ghost_X.vtk internal local ghost boxes for the local processor (X)
539 * 6) local_external_ghost_X.vtk external local ghost boxes for the local processor (X)
540 *
541 * where X is the local processor rank
542 *
543 * \param output directory where to write the files
544 * \param p_id id of the local processor
545 *
546 * \return true if the file is written correctly
547 *
548 */
549 bool write(std::string output, size_t p_id) const
550 {
551 // Copy the Box_sub_k into a vector of boxes
552 openfpm::vector<openfpm::vector<Box<dim,T>>> vv5;
553
554 for (size_t p = 0 ; p < loc_ghost_box.size() ; p++)
555 {
556 vv5.add();
557 for (size_t i = 0 ; i < loc_ghost_box.get(p).ibx.size() ; i++)
558 vv5.last().add(loc_ghost_box.get(p).ibx.get(i).bx);
559 }
560
561 //! local_internal_ghost_X.vtk internal local ghost boxes for the local processor (X)
562 VTKWriter<openfpm::vector<Box<dim,T>>,VECTOR_BOX> vtk_box5;
563 for (size_t p = 0 ; p < vv5.size() ; p++)
564 {
565 vtk_box5.add(vv5.get(p));
566 }
567 vtk_box5.write(output + std::string("local_internal_ghost_") + std::to_string(p_id) + std::string(".vtk"));
568
569 // Copy the Box_sub_k into a vector of boxes
570 openfpm::vector<openfpm::vector<Box<dim,T>>> vv6;
571
572 for (size_t p = 0 ; p < loc_ghost_box.size() ; p++)
573 {
574 vv6.add();
575 for (size_t i = 0 ; i < loc_ghost_box.get(p).ebx.size() ; i++)
576 vv6.last().add(loc_ghost_box.get(p).ebx.get(i).bx);
577 }
578
579 //! local_external_ghost_X.vtk external local ghost boxes for the local processor (X)
580 VTKWriter<openfpm::vector<Box<dim,T>>,VECTOR_BOX> vtk_box6;
581 for (size_t p = 0 ; p < vv6.size() ; p++)
582 {
583 vtk_box6.add(vv6.get(p));
584 }
585 vtk_box6.write(output + std::string("local_external_ghost_") + std::to_string(p_id) + std::string(".vtk"));
586
587 return true;
588 }
589
590 /*! \brief function to check the consistency of the information of the decomposition
591 *
592 * \param n_sub Number of sub_domain
593 *
594 * \return false if is inconsistent
595 *
596 */
597 bool check_consistency(size_t n_sub)
598 {
599 //! for each sub-domain
600 for (size_t i = 0 ; i < loc_ghost_box.size() ; i++)
601 {
602 for (size_t j = 0 ; j < loc_ghost_box.get(i).ibx.size() ; j++)
603 {
604 if (loc_ghost_box.get(i).ibx.get(j).k == -1)
605 {
606 std::cout << __FILE__ << ":" << __LINE__ << " Error: inconsistent decomposition no ibx link" << "\n";
607 return false;
608 }
609
610 size_t k = loc_ghost_box.get(i).ibx.get(j).k;
611 size_t sub = loc_ghost_box.get(i).ibx.get(j).sub;
612
613 if (loc_ghost_box.get(sub).ebx.get(k).k != (long int)j)
614 {
615 std::cout << __FILE__ << ":" << __LINE__ << " Error: inconsistent link between an external ghost box and an internal ghost box" << "\n";
616 return false;
617 }
618 }
619 }
620
621 return true;
622 }
623
624 /*! \brief Check if the ie_loc_ghosts contain the same information
625 *
626 * \param ilg Element to check
627 *
628 * \return true if they match
629 *
630 */
631 bool is_equal(ie_loc_ghost<dim,T,layout_base,Memory> & ilg)
632 {
633 if (ilg.loc_ghost_box.size() != loc_ghost_box.size())
634 return false;
635
636 // Explore all the subdomains
637 for (size_t i = 0 ; i < loc_ghost_box.size() ; i++)
638 {
639 if (getLocalNIGhost(i) != ilg.getLocalNIGhost(i))
640 return false;
641
642 if (getLocalNEGhost(i) != ilg.getLocalNEGhost(i))
643 return false;
644
645 for (size_t j = 0 ; j < getLocalNIGhost(i) ; j++)
646 {
647 if (getLocalIGhostE(i,j) != ilg.getLocalIGhostE(i,j))
648 return false;
649 if (getLocalIGhostBox(i,j) != ilg.getLocalIGhostBox(i,j))
650 return false;
651 if (getLocalIGhostSub(i,j) != ilg.getLocalIGhostSub(i,j))
652 return false;
653 }
654 for (size_t j = 0 ; j < getLocalNEGhost(i) ; j++)
655 {
656 if (getLocalEGhostBox(i,j) != ilg.getLocalEGhostBox(i,j))
657 return false;
658 if (getLocalEGhostSub(i,j) != ilg.getLocalEGhostSub(i,j))
659 return false;
660 }
661
662 }
663
664 return true;
665 }
666
667
668
669 /*! \brief Check if the ie_loc_ghosts contain the same information
670 * with the exception of the ghost part
671 *
672 * \param ilg Element to check
673 *
674 * \return true if the two objects are equal with the exception of the
675 * ghost part
676 *
677 */
678 bool is_equal_ng(ie_loc_ghost<dim,T,layout_base,Memory> & ilg)
679 {
680 return true;
681 }
682
683 /*! \brief Reset the ie_loc_ghost
684 *
685 */
686 void reset()
687 {
688 loc_ghost_box.clear();
689 sub_domains_tmp.clear();
690 }
691};
692
693
694#endif /* SRC_DECOMPOSITION_GHOST_DEC_IE_GHOST_HPP_ */
695