-
Pietro Incardona authoredPietro Incardona authored
ie_ghost.hpp 39.48 KiB
/*
* ie_ghost.hpp
*
* Created on: Aug 8, 2015
* Author: i-bird
*/
#ifndef SRC_DECOMPOSITION_IE_GHOST_HPP_
#define SRC_DECOMPOSITION_IE_GHOST_HPP_
#include "common.hpp"
#include "nn_processor.hpp"
#include "Decomposition/shift_vect_converter.hpp"
#include "Decomposition/cuda/ie_ghost_gpu.cuh"
//! Processor id and box id
struct proc_box_id
{
size_t proc_id;
size_t box_id;
size_t shift_id;
//! operator to reorder
bool operator<(const proc_box_id & pbi) const
{
if (proc_id < pbi.proc_id)
{return true;}
else if (proc_id == pbi.proc_id)
{
return shift_id < pbi.shift_id;
}
return false;
}
};
/*! \brief structure that store and compute the internal and external local ghost box
*
* \tparam dim is the dimensionality of the physical domain we are going to decompose.
* \tparam T type of the space we decompose, Real, Integer, Complex ...
*
* \see CartDecomposition
*
*/
template<unsigned int dim, typename T, typename Memory, template<typename> class layout_base >
class ie_ghost
{
//! for each sub-domain (first vector), contain the list (nested vector) of the neighborhood processors
//! and for each processor contain the boxes calculated from the intersection
//! of the sub-domains + ghost with the near-by processor sub-domain () and the other way around
//! \see calculateGhostBoxes
openfpm::vector< openfpm::vector< Box_proc<dim,T> > > box_nn_processor_int;
//! It store the same information of box_nn_processor_int organized by processor id
openfpm::vector< Box_dom<dim,T> > proc_int_box;
//! External ghost boxes for this processor
openfpm::vector<p_box<dim,T> > vb_ext;
//! Internal ghost boxes for this processor domain
openfpm::vector<aggregate<unsigned int,unsigned int,unsigned int>,Memory,typename layout_base<aggregate<unsigned int,unsigned int,unsigned int>>::type,layout_base> vb_int;
//! Internal ghost boxes for this processor domain
openfpm::vector<Box<dim,T>,Memory,typename layout_base<Box<dim,T>>::type,layout_base> vb_int_box;
//! Cell-list that store the geometrical information of the internal ghost boxes
CellList<dim,T,Mem_fast<Memory,int>,shift<dim,T>> geo_cell;
typedef openfpm::vector<Box<dim,T>,Memory,typename layout_base<Box<dim,T>>::type,layout_base> proc_boxes;
//! shift vectors
openfpm::vector<Point<dim,T>,Memory,typename layout_base<Point<dim,T>>::type,layout_base> shifts;
//! Temporal buffers to return temporal information for ghost_processorID
openfpm::vector<std::pair<size_t,size_t>> ids_p;
//! Temporal buffers to return temporal information
openfpm::vector<size_t> ids;
//! shift converter
shift_vect_converter<dim,T,Memory,layout_base> sc_convert;
//! host to device transfer
bool host_dev_transfer = false;
/*! \brief Given a local sub-domain i, it give the id of such sub-domain in the sent list
* for the processor p_id
*
* Processor 5 send its sub-domains to processor 6 and will receive the list from 6
*
* This function search if a local sub-domain has been sent to a processor p_id, if
* found it return at witch position is in the list of the sent sub-domains
*
* \param nn_p structure that store the processor graph as near processor
* \param p_id near processor rank
* \param i sub-domain
*
* \return Given a local sub-domain i, it give the id of such sub-domain in the sent list
* for the processor p_id
*
*/
inline size_t link_ebx_ibx(const nn_prcs<dim,T,layout_base,Memory> & nn_p, size_t p_id, size_t i)
{
// Search for the correct id
size_t k = 0;
size_t p_idp = nn_p.ProctoID(p_id);
for (k = 0 ; k < nn_p.getSentSubdomains(p_idp).size() ; k++)
{
if (nn_p.getSentSubdomains(p_idp).get(k) == i)
break;
}
if (k == nn_p.getSentSubdomains(p_idp).size())
std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " sub-domain not found\n";
return k;
}
/*! \brief This is the external and internal ghost box link formula
*
* This formula is pretty important and require an extensive explanation
*
* \verbatim
+------------+
| |
| +---+---------+
| Processor 5| | |
| | E | Proc 6 |
| Sub 0 | 0 | |
| | _ | Sub 9 |
| | 9 | |
| | | |
| +---+---------+
| |
+------------+
* \endverbatim
*
* E0_6 is an external ghost box from the prospective of processor 5 and an internal
* ghost boxes from the prospective of processor 6. So for every external
* ghost box that processor 5 compute, exist an internal ghost box in processor 6
*
* Here we link this information with an unique id, for processor 5 and 6.
* Consider Processor 5 sending to processor 6
* its sub-domains, including the one in figure with id 0 in the list, and
* receive from processor 6 the sub-domain in figure as id 9. Consider also
* we have 16 processor. E0_9 come from the intersection of the expanded sub-domain
* 0 with 9 (Careful the id is related to the send and receive position in the list)
* and the intersection is in the sector 0
*
*
* The id of the external box (for processor 5) is calculated as
*
* ((k * N_b + b) * v_cl.getProcessingUnits() + p_id) * openfpm::math::pow(3,dim) + c.lin()
*
* The parameter assume a different meaning if they the formula is used for calculating
* external/internal ghost boxes id
*
* \param k expanded sub-domain sent/received to/from p_id ( 0 )
* \param b sub-domain received/sent from/to p_id ( 9 )
* \param p_id processor id ( 6 )
* \param c sector where the sub-domain b live
* \param N_b number of sub-domain received/sent from/to p_id
* \param v_cl Vcluster
* \param ei indicate if the formula is used to calculate external (true) or internal (false) ids
*
* \return id of the external/internal ghost
*
* \note To an explanation about the sectors see getShiftVectors
*
*/
inline size_t ebx_ibx_form(size_t k, size_t b, size_t p_id, const comb<dim> & c ,size_t N_b, Vcluster<> & v_cl, const bool ei)
{
comb<dim> cext = c;
if (ei == true)
cext.sign_flip();
return ((k * N_b + b) * v_cl.getProcessingUnits() + p_id) * openfpm::math::pow(3,dim) + cext.lin();
}
protected:
/*! \brief Here we generare the shift vectors
*
* \param domain box that describe the domain
*
*/
void generateShiftVectors(const Box<dim,T> & domain, size_t (& bc)[dim])
{
sc_convert.generateShiftVectors(domain,bc,shifts);
}
/*! \brief Initialize the geo cell list structure
*
* The geo cell list structure exist to speed up the labelling the points if they fall on some
* internal ghost
*
* \param domain where the cell list is defined
* \param div number of division of the cell list
*
*/
void Initialize_geo_cell(const Box<dim,T> & domain, const size_t (&div)[dim])
{
// Initialize the geo_cell structure
geo_cell.Initialize(domain,div,1);
}
/*! \brief Deallocate structures that identify a point to which internal ghost is located
*
*/
void free_geo_cell()
{
geo_cell.destroy();
}
/*! \brief Create the box_nn_processor_int (bx part) structure
*
* For each sub-domain of the local processor it store the intersection between the enlarged
* sub-domain of the calling processor with the adjacent processors sub-domains (External ghost box)
*
* \param v_cl Virtual cluster
* \param ghost margins
* \param sub_domains vector of local sub-domains
* \param box_nn_processor it will store for each sub-domain the near processors
* \param nn_p contain the sub-domains of the near processors
*
* \note Are the G8_0 G9_0 G9_1 G5_0 boxes in calculateGhostBoxes
* \see calculateGhostBoxes
*
*/
void create_box_nn_processor_ext(Vcluster<> & v_cl,
Ghost<dim,T> & ghost,
openfpm::vector<SpaceBox<dim,T>,Memory,typename layout_base<SpaceBox<dim, T>>::type,layout_base> & sub_domains,
const openfpm::vector<openfpm::vector<long unsigned int> > & box_nn_processor,
const nn_prcs<dim,T,layout_base,Memory> & nn_p)
{
box_nn_processor_int.resize(sub_domains.size());
proc_int_box.resize(nn_p.getNNProcessors());
// For each sub-domain
for (size_t i = 0 ; i < sub_domains.size() ; i++)
{
SpaceBox<dim,T> sub_with_ghost = sub_domains.get(i);
// enlarge the sub-domain with the ghost
sub_with_ghost.enlarge(ghost);
// resize based on the number of near processors
box_nn_processor_int.get(i).resize(box_nn_processor.get(i).size());
// For each processor near to this sub-domain
for (size_t j = 0 ; j < box_nn_processor.get(i).size() ; j++)
{
// near processor
size_t p_id = box_nn_processor.get(i).get(j);
// used later
Box_dom<dim,T> & proc_int_box_g = proc_int_box.get(nn_p.ProctoID(p_id));
// Number of received sub-domains
size_t n_r_sub = nn_p.getNRealSubdomains(p_id);
// get the set of sub-domains, sector position, and real sub-domain id of the near processor p_id
const openfpm::vector< ::Box<dim,T> > & nn_processor_subdomains_g = nn_p.getNearSubdomains(p_id);
const openfpm::vector< comb<dim> > & nnpsg_pos = nn_p.getNearSubdomainsPos(p_id);
const openfpm::vector< size_t > & r_sub = nn_p.getNearSubdomainsRealId(p_id);
// used later
openfpm::vector< ::Box<dim,T> > & box_nn_processor_int_gg = box_nn_processor_int.get(i).get(j).bx;
// for each near processor sub-domain intersect with the enlarged local sub-domain and store it
for (size_t b = 0 ; b < nn_processor_subdomains_g.size() ; b++)
{
::Box<dim,T> bi;
::Box<dim,T> sub_bb(nn_processor_subdomains_g.get(b));
bool intersect = sub_with_ghost.Intersect(sub_bb,bi);
if (intersect == true)
{
struct p_box<dim,T> pb;
pb.box = bi;
pb.proc = p_id;
pb.lc_proc = nn_p.ProctoID(p_id);
pb.shift_id = (size_t)-1;
//
// Updating
//
// vb_ext
// box_nn_processor_int
// proc_int_box
//
// They all store the same information but organized in different ways
// read the description of each for more information
//
vb_ext.add(pb);
box_nn_processor_int_gg.add(bi);
proc_int_box_g.ebx.add();
proc_int_box_g.ebx.last().bx = bi;
proc_int_box_g.ebx.last().sub = i;
proc_int_box_g.ebx.last().cmb = nnpsg_pos.get(b);
// Search where the sub-domain i is in the sent list for processor p_id
size_t k = link_ebx_ibx(nn_p,p_id,i);
proc_int_box_g.ebx.last().id = ebx_ibx_form(k,r_sub.get(b),p_id,nnpsg_pos.get(b),n_r_sub,v_cl,true);
}
}
}
}
}
/*! \brief Create the box_nn_processor_int (nbx part) structure, the geo_cell list and proc_int_box
*
* This structure store for each sub-domain of this processors the boxes that come from the intersection
* of the near processors sub-domains enlarged by the ghost size (Internal ghost box). These boxes
* fill a geometrical cell list. The proc_int_box store the same information ordered by near processors
*
* \param v_cl Virtual cluster
* \param ghost margins
* \param sub_domains
* \param box_nn_processor sub-domains of the near processors
* \param nn_p structure that store the near processor sub-domains
*
* \note Are the B8_0 B9_0 B9_1 B5_0 boxes in calculateGhostBoxes
* \see calculateGhostBoxes
*
*/
void create_box_nn_processor_int(Vcluster<> & v_cl,
Ghost<dim,T> & ghost,
openfpm::vector<SpaceBox<dim,T>,Memory,typename layout_base<SpaceBox<dim, T>>::type,layout_base> & sub_domains,
const openfpm::vector<openfpm::vector<long unsigned int> > & box_nn_processor,
const nn_prcs<dim,T,layout_base,Memory> & nn_p)
{
box_nn_processor_int.resize(sub_domains.size());
proc_int_box.resize(nn_p.getNNProcessors());
// For each sub-domain
for (size_t i = 0 ; i < sub_domains.size() ; i++)
{
// For each processor contiguous to this sub-domain
for (size_t j = 0 ; j < box_nn_processor.get(i).size() ; j++)
{
// Near processor
size_t p_id = box_nn_processor.get(i).get(j);
// get the set of sub-domains of the near processor p_id
const openfpm::vector< ::Box<dim,T> > & nn_p_box = nn_p.getNearSubdomains(p_id);
// get the sector position for each sub-domain in the list
const openfpm::vector< comb<dim> > nn_p_box_pos = nn_p.getNearSubdomainsPos(p_id);
// get the real sub-domain id for each sub-domain
const openfpm::vector<size_t> r_sub = nn_p.getNearSubdomainsRealId(p_id);
// get the local processor id
size_t lc_proc = nn_p.getNearProcessor(p_id);
// For each near processor sub-domains enlarge and intersect with the local sub-domain and store the result
for (size_t k = 0 ; k < nn_p_box.size() ; k++)
{
// enlarge the near-processor sub-domain
::Box<dim,T> n_sub = nn_p_box.get(k);
// local sub-domain
::SpaceBox<dim,T> l_sub = sub_domains.get(i);
// Create a margin of ghost size around the near processor sub-domain
n_sub.enlarge(ghost);
// Intersect with the local sub-domain
Box<dim,T> b_int;
bool intersect = n_sub.Intersect(l_sub,b_int);
// store if it intersect
if (intersect == true)
{
vb_int.add();
size_t last = vb_int.size() - 1;
// the box fill with the processor id
vb_int.template get<proc_>(last) = p_id;
// fill the local processor id
vb_int.template get<lc_proc_>(last) = lc_proc;
// fill the shift id
vb_int.template get<shift_id_>(last) = convertShift(nn_p_box_pos.get(k));
//
// Updating
//
// vb_int
// box_nn_processor_int
// proc_int_box
//
// They all store the same information but organized in different ways
// read the description of each for more information
//
// add the box to the near processor sub-domain intersections
openfpm::vector< ::Box<dim,T> > & p_box_int = box_nn_processor_int.get(i).get(j).nbx;
p_box_int.add(b_int);
vb_int_box.add(b_int);
// store the box in proc_int_box storing from which sub-domain they come from
Box_sub<dim,T> sb;
sb.bx = b_int;
sb.sub = i;
sb.r_sub = r_sub.get(k);
sb.cmb = nn_p_box_pos.get(k);
size_t p_idp = nn_p.ProctoID(p_id);
// Search where the sub-domain i is in the sent list for processor p_id
size_t s = link_ebx_ibx(nn_p,p_id,i);
// calculate the id of the internal box
sb.id = ebx_ibx_form(r_sub.get(k),s,v_cl.getProcessUnitID(),nn_p_box_pos.get(k),nn_p.getSentSubdomains(p_idp).size(),v_cl,false);
Box_dom<dim,T> & pr_box_int = proc_int_box.get(nn_p.ProctoID(p_id));
pr_box_int.ibx.add(sb);
// update the geo_cell list
// get the cells this box span
const grid_key_dx<dim> p1 = geo_cell.getCellGrid_me(b_int.getP1());
const grid_key_dx<dim> p2 = geo_cell.getCellGrid_pe(b_int.getP2());
// Get the grid and the sub-iterator
auto & gi = geo_cell.getGrid();
grid_key_dx_iterator_sub<dim> g_sub(gi,p1,p2);
// add the box-id to the cell list
while (g_sub.isNext())
{
auto key = g_sub.get();
size_t cell = gi.LinId(key);
geo_cell.addCell(cell,vb_int.size()-1);
++g_sub;
}
}
}
}
}
reorder_geo_cell();
}
/*! \brief in this function we reorder the list in each cells by processor id
*
* suppose in one cell we have 7 boxes each box contain the processor id
*
* 1,5,9,5,1,1,6
*
* after reorder we have the following sequence
*
* 1,1,1,5,5,6,9
*
* This simplify the procedure to get a unique list of processor ids
* indicating on which processor a particle must be replicated as ghost
*
*/
void reorder_geo_cell()
{
openfpm::vector<proc_box_id> tmp_sort;
size_t div[dim];
for (size_t i = 0 ; i < dim ; i++) {div[i] = geo_cell.getDiv()[i];}
grid_sm<dim,void> gs(div);
grid_key_dx_iterator<dim> it(gs);
while (it.isNext())
{
size_t cell = gs.LinId(it.get());
size_t sz = geo_cell.getNelements(cell);
tmp_sort.resize(sz);
for (size_t i = 0 ; i < sz ; i++)
{
tmp_sort.get(i).box_id = geo_cell.get(cell,i);
tmp_sort.get(i).proc_id = vb_int.template get<proc_>(tmp_sort.get(i).box_id);
tmp_sort.get(i).shift_id = vb_int.template get<shift_id_>(tmp_sort.get(i).box_id);
}
tmp_sort.sort();
// now we set again the cell in an ordered way
for (size_t i = 0 ; i < sz ; i++)
{geo_cell.get(cell,i) = tmp_sort.get(i).box_id;}
++it;
}
}
public:
//! Default constructor
ie_ghost() {};
//! Copy constructor
ie_ghost(const ie_ghost<dim,T,Memory,layout_base> & ie)
{
this->operator=(ie);
}
//! Copy constructor
ie_ghost(ie_ghost<dim,T,Memory,layout_base> && ie)
{
this->operator=(ie);
}
//! Copy operator
inline ie_ghost<dim,T,Memory,layout_base> & operator=(ie_ghost<dim,T,Memory,layout_base> && ie)
{
box_nn_processor_int.swap(ie.box_nn_processor_int);
proc_int_box.swap(ie.proc_int_box);
vb_ext.swap(ie.vb_ext);
vb_int.swap(ie.vb_int);
vb_int_box.swap(ie.vb_int_box);
geo_cell.swap(ie.geo_cell);
shifts.swap(ie.shifts);
ids_p.swap(ie.ids_p);
ids.swap(ie.ids);
return *this;
}
//! Copy operator
inline ie_ghost<dim,T,Memory,layout_base> & operator=(const ie_ghost<dim,T,Memory,layout_base> & ie)
{
box_nn_processor_int = ie.box_nn_processor_int;
proc_int_box = ie.proc_int_box;
vb_ext = ie.vb_ext;
vb_int = ie.vb_int;
vb_int_box = ie.vb_int_box;
geo_cell = ie.geo_cell;
shifts = ie.shifts;
ids_p = ie.ids_p;
ids = ie.ids;
return *this;
}
/*! \brief duplicate this structure changing layout and Memory
*
* \return a structure with Memory type and layout changed
*
*/
template<typename Memory2, template <typename> class layout_base2>
inline ie_ghost<dim,T,Memory2,layout_base2> duplicate()
{
ie_ghost<dim,T,Memory2,layout_base2> tmp;
tmp.private_get_box_nn_processor_int() = box_nn_processor_int;
tmp.private_get_proc_int_box() = proc_int_box;
tmp.private_get_vb_ext() = vb_ext;
tmp.private_get_vb_int() = vb_int;
tmp.private_get_vb_int_box() = vb_int_box;
tmp.private_geo_cell() = geo_cell;
tmp.private_get_shifts() = shifts;
tmp.private_get_ids_p() = ids_p;
tmp.private_get_ids() = ids;
return tmp;
}
/*! It return the shift vector
*
* Consider a domain with some ghost, at the border of the domain the
* ghost must be treated in a special way, depending on the periodicity
* of the boundary
*
\verbatim
[1,1]
+---------+------------------------+---------+
| (1,-1) | | (1,1) |
| | | (1,0) --> 7 | | |
| v | | v |
| 6 | | 8 |
+--------------------------------------------+
| | | |
| | | |
| | | |
| (-1,0) | | (1,0) |
| | | | | |
| v | (0,0) --> 4 | v |
| 3 | | 5 |
| | | |
B | | | A |
* | | | * |
| | | |
| | | |
| | | |
+--------------------------------------------+
| (-1,-1) | | (-1,1) |
| | | (-1,0) --> 1 | | |
| v | | v |
| 0 | | 2 |
+---------+------------------------+---------+
\endverbatim
*
*
* if a particle is bound in (1,0) linearized to 5, before communicate this particle (A in figure)
* must be shifted on -1.0 on x (B in figure)
*
* This function return the set of shift vectors that determine such shift, for example
* in the example above the shift at position 5 will be (0,-1.0)
*
* \return the shift vectors
*
*/
const openfpm::vector<Point<dim,T>,Memory,typename layout_base<Point<dim,T>>::type,layout_base> & getShiftVectors()
{
if (host_dev_transfer == false)
{
shifts.template hostToDevice<0>();
}
return shifts;
}
/*! It return the converted shift vector
*
* In high dimensions the number of shifts vectors explode exponentially, so we are
* expecting that some of the boundary is non periodic to reduce the numbers of shift
* vectors
*
* \return the shift vectors
*
*/
size_t convertShift(const comb<dim> & cmb)
{
return sc_convert.linId(cmb);
}
/*! \brief Get the number of Internal ghost boxes for one processor
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \return the number of internal ghost
*
*/
inline size_t getProcessorNIGhost(size_t id) const
{
return proc_int_box.get(id).ibx.size();
}
/*! \brief Get the number of External ghost boxes for one processor id
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \return the number of external ghost
*
*/
inline size_t getProcessorNEGhost(size_t id) const
{
return proc_int_box.get(id).ebx.size();
}
/*! \brief Get the j Internal ghost box for one processor
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one internal ghost box)
* \return the box
*
*/
inline const ::Box<dim,T> & getProcessorIGhostBox(size_t id, size_t j) const
{
return proc_int_box.get(id).ibx.get(j).bx;
}
/*! \brief Get the j External ghost box
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one external ghost box)
* \return the box
*
*/
inline const ::Box<dim,T> & getProcessorEGhostBox(size_t id, size_t j) const
{
return proc_int_box.get(id).ebx.get(j).bx;
}
/*! \brief Get the j External ghost box sector
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one external ghost box)
* \return the sector
*
*/
inline const comb<dim> & getProcessorEGhostPos(size_t id, size_t j) const
{
return proc_int_box.get(id).ebx.get(j).cmb;
}
/*! \brief Get the ghost box sector of the external ghost box linked with the j internal ghost box
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one internal ghost box)
* \return the sector
*
*/
inline const comb<dim> & getProcessorIGhostPos(size_t id, size_t j) const
{
return proc_int_box.get(id).ibx.get(j).cmb;
}
/*! \brief Get the j Internal ghost box id
*
* Every internal ghost box has a linked external ghost box, because they overlap
* and they must contain the same information (Think on a ghost_get). So if exist
* an internal ghost box with id x, exist also an external ghost box with id x
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one internal ghost box)
* \return the box id
*
*/
inline size_t getProcessorIGhostId(size_t id, size_t j) const
{
return proc_int_box.get(id).ibx.get(j).id;
}
/*! \brief Get the j External ghost box id
*
* Every external ghost box has a linked internal ghost box, because they overlap
* and they must contain the same information (Think on a ghost_get). So if exist
* an internal ghost box with id x, exist also an external ghost box with id x
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one external ghost box)
* \return the box
*
*/
inline size_t getProcessorEGhostId(size_t id, size_t j) const
{
return proc_int_box.get(id).ebx.get(j).id;
}
/*! \brief Get the sub-domain send-id at witch belong the internal ghost box
*
* The internal ghost box is create from the intersection a local sub-domain
* and an extended sub-domain communicated from another processor. This function
* return the id of the sub-domain in the receiving list
*
* \param id adjacent processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one internal ghost box)
* \return sub-domain at which belong the internal ghost box
*
*/
inline size_t getProcessorIGhostSSub(size_t id, size_t j) const
{
return proc_int_box.get(id).ibx.get(j).r_sub;
}
/*! \brief Get the local sub-domain at witch belong the internal ghost box
*
* \param id adjacent processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one internal ghost box)
* \return sub-domain at which belong the internal ghost box
*
*/
inline size_t getProcessorIGhostSub(size_t id, size_t j) const
{
return proc_int_box.get(id).ibx.get(j).sub;
}
/*! \brief Get the local sub-domain at witch belong the external ghost box
*
* \param id near processor list id (the id go from 0 to getNNProcessor())
* \param j box (each near processor can produce more than one external ghost box)
* \return sub-domain at which belong the external ghost box
*
*/
inline size_t getProcessorEGhostSub(size_t id, size_t j) const
{
return proc_int_box.get(id).ebx.get(j).sub;
}
/*! \brief Return the total number of the calculated internal ghost boxes
*
* \return the number of internal ghost boxes
*
*/
inline size_t getNIGhostBox() const
{
return vb_int.size();
}
/*! \brief Given the internal ghost box id, it return the internal ghost box
*
* \param b_id internal ghost box id
*
* \return the internal ghost box
*
*/
inline ::Box<dim,T> getIGhostBox(size_t b_id) const
{
return vb_int_box.get(b_id);
}
/*! \brief Given the internal ghost box id, it return the near processor at witch belong
* or the near processor that produced this internal ghost box
*
* \param b_id internal ghost box id
*
* \return the processor id of the ghost box
*
*/
inline size_t getIGhostBoxProcessor(size_t b_id) const
{
return vb_int.template get<proc_>(b_id);
}
/*! \brief Get the number of the calculated external ghost boxes
*
* \return the number of external ghost boxes
*
*/
inline size_t getNEGhostBox() const
{
return vb_ext.size();
}
/*! \brief Given the external ghost box id, it return the external ghost box
*
* \param b_id external ghost box id
*
* \return the external ghost box
*
*/
inline ::Box<dim,T> getEGhostBox(size_t b_id) const
{
return vb_ext.get(b_id).box;
}
/*! \brief Given the external ghost box id, it return the near processor at witch belong
* or the near processor that produced this external ghost box
*
* \param b_id external ghost box id
*
* \return the processor id of the external ghost box
*
*/
inline size_t getEGhostBoxProcessor(size_t b_id) const
{
return vb_ext.get(b_id).proc;
}
/*! /brief Given a point it return the set of boxes in which the point fall
*
* \param p Point to check
*
* \return An iterator with the id's of the internal boxes in which the point fall
*
*/
auto getInternalIDBoxes(Point<dim,T> & p) -> decltype(geo_cell.getCellIterator(geo_cell.getCell(p)))
{
return geo_cell.getCellIterator(geo_cell.getCell(p));
}
/*! \brief if the point fall into the ghost of some near processor it return the processors id's in which
* it fall
*
* \param p Point
* \return iterator of the processors id's
*
*/
inline auto labelPoint(Point<dim,T> & p) -> decltype(geo_cell.getCellIterator(geo_cell.getCell(p)))
{
return geo_cell.getCellIterator(geo_cell.getCell(p));
}
/*! \brief Get the number of processor a particle must sent
*
* \param p position of the particle
*
*/
template<typename output_type> inline void ghost_processor_ID(const Point<dim,T> & p, output_type & output, unsigned int base, unsigned int pi)
{
ID_operation<output_type> op(output);
ghost_processorID_general_impl(p,base,pi,geo_cell,vb_int_box,vb_int,op);
}
/*! \brief Get the number of processor a particle must sent
*
* \param p position of the particle
*
*/
inline unsigned int ghost_processorID_N(const Point<dim,T> & p)
{
return ghost_processorID_N_impl(p,geo_cell,vb_int_box,vb_int);
}
/*! \brief Given a position it return if the position belong to any neighborhood processor ghost
* (Internal ghost)
*
* if the particle come from an internal ghost from the periodicity of the domain, position must be shifted
* this function return the id of the shift vector
*
* \see getShiftVector
*
* \tparam id type of id to get box_id processor_id lc_processor_id shift_id
*
* \param p Particle position
* \param opt intersection boxes of the same processor can overlap, so in general the function
* can produce more entry with the same processor, the UNIQUE option eliminate double entries
* (UNIQUE) is for particle data (MULTIPLE) is for grid data [default MULTIPLE]
* \return return the processor ids (not the rank, the id in the near processor list)
*
*/
template <typename id1, typename id2> inline const openfpm::vector<std::pair<size_t,size_t>> ghost_processorID_pair(Point<dim,T> & p, const int opt = MULTIPLE)
{
ids_p.clear();
// Check with geo-cell if a particle is inside one Cell containing boxes
auto cell_it = geo_cell.getCellIterator(geo_cell.getCell(p));
// For each element in the cell, check if the point is inside the box
// if it is, store the processor id
while (cell_it.isNext())
{
size_t bid = cell_it.get();
if (Box<dim,T>(vb_int_box.get(bid)).isInsideNP(p) == true)
{
ids_p.add(std::pair<size_t,size_t>(id1::id(vb_int.get(bid),bid),id2::id(vb_int.get(bid),bid)));
}
++cell_it;
}
// Make the id unique
if (opt == UNIQUE)
{
ids_p.sort();
ids_p.unique();
}
return ids_p;
}
/*! \brief Given a position it return if the position belong to any neighborhood processor ghost
* (Internal ghost)
*
* if the particle come from an internal ghost from the periodicity of the domain, position must be shifted
* this function return the id of the shift vector
*
* \see getShiftVector
*
* \tparam id type of id to get box_id processor_id lc_processor_id shift_id
* \param p Particle position
* \param opt intersection boxes of the same processor can overlap, so in general the function
* can produce more entry with the same processor, the UNIQUE option eliminate double entries
* (UNIQUE) is for particle data (MULTIPLE) is for grid data [default MULTIPLE]
*
* \return the processor ids
*
*/
template <typename id> inline const openfpm::vector<size_t> ghost_processorID(const Point<dim,T> & p, const int opt = MULTIPLE)
{
ids.clear();
// Check with geo-cell if a particle is inside one Cell containing boxes
auto cell_it = geo_cell.getCellIterator(geo_cell.getCell(p));
// For each element in the cell, check if the point is inside the box
// if it is, store the processor id
while (cell_it.isNext())
{
size_t bid = cell_it.get();
if (Box<dim,T>(vb_int_box.get(bid)).isInsideNP(p) == true)
{
ids.add(id::id(vb_int.get(bid),bid));
}
++cell_it;
}
// Make the id unique
if (opt == UNIQUE)
{
ids_p.sort();
ids_p.unique();
}
return ids;
}
/*! \brief Given a position it return if the position belong to any neighborhood processor ghost
* (Internal ghost)
*
* \tparam id1 first index type to get box_id processor_id lc_processor_id
* \tparam id2 second index type to get box_id processor_id lc_processor_id
*
* \param p Particle position
* \param opt indicate if the entries in the vector must be unique
*
* \return a vector of pair containing the requested information
*
*/
template<typename id1, typename id2, typename Mem> inline const openfpm::vector<std::pair<size_t,size_t>> & ghost_processorID_pair(const encapc<1,Point<dim,T>,Mem> & p, const int opt = MULTIPLE)
{
ids_p.clear();
// Check with geo-cell if a particle is inside one Cell containing boxes
auto cell_it = geo_cell.getCellIterator(geo_cell.getCell(p));
// For each element in the cell, check if the point is inside the box
// if it is, store the processor id
while (cell_it.isNext())
{
size_t bid = cell_it.get();
if (Box<dim,T>(vb_int_box.get(bid)).isInsideNP(p) == true)
{
ids_p.add(std::pair<size_t,size_t>(id1::id(vb_int.get(bid),bid),id2::id(vb_int.get(bid),bid)));
}
++cell_it;
}
// Make the id unique
if (opt == UNIQUE)
{
ids_p.sort();
ids_p.unique();
}
return ids_p;
}
/*! \brief Given a position it return if the position belong to any neighborhood processor ghost
* (Internal ghost)
*
* \tparam id type of if to get box_id processor_id lc_processor_id
*
* \param p Particle position
* \param opt it indicate if the entry in the vector must be unique or not
*
* \return the processor ids
*
*/
template<typename id, typename Mem> inline const openfpm::vector<size_t> & ghost_processorID(const encapc<1,Point<dim,T>,Mem> & p, const int opt = MULTIPLE)
{
ids.clear();
// Check with geo-cell if a particle is inside one Cell containing boxes
auto cell_it = geo_cell.getCellIterator(geo_cell.getCell(p));
// For each element in the cell, check if the point is inside the box
// if it is, store the processor id
while (cell_it.isNext())
{
size_t bid = cell_it.get();
if (vb_int.get(bid).box.isInsideNP(p) == true)
{
ids.add(id::id(vb_int.get(bid),bid));
}
++cell_it;
}
// Make the id unique
if (opt == UNIQUE)
{
ids_p.sort();
ids_p.unique();
}
return ids;
}
/*! \brief write the information about the ghost in vtk format
*
* 1) internal_ghost_X.vtk Internal ghost boxes for the local processor (X)
* 2) external_ghost_X.vtk External ghost boxes for the local processor (X)
*
* \param output directory
* \param p_id processor rank
*
*
* \return true if the write succeed
*
*/
bool write(std::string output, size_t p_id) const
{
//! internal_ghost_X.vtk Internal ghost boxes for the local processor (X)
VTKWriter<openfpm::vector<::Box<dim,T>>,VECTOR_BOX> vtk_box3;
for (size_t p = 0 ; p < box_nn_processor_int.size() ; p++)
{
for (size_t s = 0 ; s < box_nn_processor_int.get(p).size() ; s++)
{
vtk_box3.add(box_nn_processor_int.get(p).get(s).nbx);
}
}
vtk_box3.write(output + std::string("internal_ghost_") + std::to_string(p_id) + std::string(".vtk"));
//! external_ghost_X.vtk External ghost boxes for the local processor (X)
VTKWriter<openfpm::vector<::Box<dim,T>>,VECTOR_BOX> vtk_box4;
for (size_t p = 0 ; p < box_nn_processor_int.size() ; p++)
{
for (size_t s = 0 ; s < box_nn_processor_int.get(p).size() ; s++)
{
vtk_box4.add(box_nn_processor_int.get(p).get(s).bx);
}
}
vtk_box4.write(output + std::string("external_ghost_") + std::to_string(p_id) + std::string(".vtk"));
return true;
}
/*! \brief Check if the ie_ghosts contain the same information
*
* \param ig Element to check
*
* \return true if they are equal
*
*/
bool is_equal(ie_ghost<dim,T,Memory,layout_base> & ig)
{
if (getNEGhostBox() != ig.getNEGhostBox())
return false;
if (getNIGhostBox() != ig.getNIGhostBox())
return false;
for (size_t i = 0 ; i < getNIGhostBox() ; i++)
{
if (getIGhostBox(i) != ig.getIGhostBox(i))
return false;
if (getIGhostBoxProcessor(i) != ig.getIGhostBoxProcessor(i))
return false;
}
for (size_t i = 0 ; i < proc_int_box.size() ; i++)
{
if (getProcessorNIGhost(i) != ig.getProcessorNIGhost(i))
return false;
for (size_t j = 0 ; j < getProcessorNIGhost(i) ; j++)
{
if (getProcessorIGhostBox(i,j) != ig.getProcessorIGhostBox(i,j))
return false;
if (getProcessorIGhostId(i,j) != ig.getProcessorIGhostId(i,j))
return false;
if (getProcessorIGhostSub(i,j) != ig.getProcessorIGhostSub(i,j))
return false;
}
}
for (size_t i = 0 ; i < getNEGhostBox() ; i++)
{
if (getEGhostBox(i) != ig.getEGhostBox(i))
return false;
if (getEGhostBoxProcessor(i) != ig.getEGhostBoxProcessor(i))
return false;
}
for (size_t i = 0 ; i < proc_int_box.size() ; i++)
{
if (getProcessorNEGhost(i) != ig.getProcessorNEGhost(i))
return false;
for (size_t j = 0 ; j < getProcessorNEGhost(i) ; j++)
{
if (getProcessorEGhostBox(i,j) != ig.getProcessorEGhostBox(i,j))
return false;
if (getProcessorEGhostId(i,j) != ig.getProcessorEGhostId(i,j))
return false;
if (getProcessorEGhostSub(i,j) != ig.getProcessorEGhostSub(i,j))
return false;
}
}
return true;
}
/*! \brief Check if the ie_loc_ghosts contain the same information with the exception of the ghost part
* It is anyway required that the ghost come from the same sub-domains decomposition
*
* \param ig Element to check
*
* \return true if they are equal
*
*/
bool is_equal_ng(ie_ghost<dim,T,Memory,layout_base> & ig)
{
return true;
}
/*! \brief Reset the nn_prcs structure
*
*/
void reset()
{
box_nn_processor_int.clear();
proc_int_box.clear();
vb_ext.clear();
vb_int.clear();
vb_int_box.clear();
geo_cell.clear();
shifts.clear();
ids_p.clear();
ids.clear();
}
/*! \brief Return the internal data structure box_nn_processor_int
*
* \return box_nn_processor_int
*
*/
inline openfpm::vector< openfpm::vector< Box_proc<dim,T> > > & private_get_box_nn_processor_int()
{
return box_nn_processor_int;
}
/*! \brief Return the internal data structure proc_int_box
*
* \return proc_int_box
*
*/
inline openfpm::vector< Box_dom<dim,T> > & private_get_proc_int_box()
{
return proc_int_box;
}
/*! \brief Return the internal data structure vb_ext
*
* \return vb_ext
*
*/
inline openfpm::vector<p_box<dim,T> > & private_get_vb_ext()
{
return vb_ext;
}
/*! \brief Return the internal data structure vb_int
*
* \return vb_int
*
*/
inline openfpm::vector<aggregate<unsigned int,unsigned int,unsigned int>,Memory,typename layout_base<aggregate<unsigned int,unsigned int,unsigned int>>::type,layout_base> &
private_get_vb_int()
{
return vb_int;
}
/*! \brief Return the internal data structure vb_int_box
*
* \return vb_int_box
*
*/
inline openfpm::vector<Box<dim,T>,Memory,typename layout_base<Box<dim,T>>::type,layout_base> &
private_get_vb_int_box()
{
return vb_int_box;
}
/*! \brief Return the internal data structure proc_int_box
*
* \return proc_int_box
*
*/
inline CellList<dim,T,Mem_fast<Memory,int>,shift<dim,T>> &
private_geo_cell()
{
return geo_cell;
}
/*! \brief Return the internal data structure shifts
*
* \return shifts
*
*/
inline openfpm::vector<Point<dim,T>,Memory,typename layout_base<Point<dim,T>>::type,layout_base> &
private_get_shifts()
{
return shifts;
}
/*! \brief Return the internal data structure ids_p
*
* \return ids_p
*
*/
inline openfpm::vector<std::pair<size_t,size_t>> &
private_get_ids_p()
{
return ids_p;
}
/*! \brief Return the internal data structure ids_p
*
* \return ids_p
*
*/
inline openfpm::vector<size_t> &
private_get_ids()
{
return ids;
}
/*! \brief toKernel() Convert this data-structure into a kernel usable data-structure
*
* \return
*
*/
ie_ghost_gpu<dim,T,Memory,layout_base> toKernel()
{
if (host_dev_transfer == false)
{
geo_cell.hostToDevice();
vb_int_box.template hostToDevice<0,1>();
vb_int.template hostToDevice<0,1,2>();
shifts.template hostToDevice<0>();
host_dev_transfer = true;
}
ie_ghost_gpu<dim,T,Memory,layout_base> igg(geo_cell.toKernel(),
vb_int_box.toKernel(),
vb_int.toKernel());
return igg;
}
/*! \brief Notify that the next toKernel() data-structures must be re-offloaded
*
*
*/
void reset_host_dev_transfer()
{
host_dev_transfer = false;
}
};
#endif /* SRC_DECOMPOSITION_IE_GHOST_HPP_ */