Skip to content
Snippets Groups Projects
grid_dist_util.hpp 15.82 KiB
/*
 * grid_dist_util.hpp
 *
 *  Created on: Jan 28, 2016
 *      Author: i-bird
 */

#ifndef SRC_GRID_GRID_DIST_UTIL_HPP_
#define SRC_GRID_GRID_DIST_UTIL_HPP_

#include "NN/CellList/CellDecomposer.hpp"
#include "Decomposition/common.hpp"

/*! \brief get cellDecomposer parameters
 *
 * \tparam dim dimensionality
 *
 * \param c_g get the parameters of the cell decomposer
 * \param g_sz global grid parameters
 *
 */
template<unsigned int dim> void getCellDecomposerPar(size_t (& c_g)[dim], const size_t (& g_sz)[dim], const size_t (& bc)[dim])
{
	for (size_t i = 0 ; i < dim ; i++)
	{
		if (bc[i] == NON_PERIODIC)
			c_g[i] = (g_sz[i]-1 > 0)?(g_sz[i]-1):1;
		else
			c_g[i] = g_sz[i];
	}
}


/*! \brief Create NON_PERIODIC data structure
 *
 * \tparam dim Dimensionality
 *
 * \return structure that define the non periodicity of the grid
 *
 */
template<unsigned int dim> periodicity<dim> create_non_periodic()
{
	periodicity<dim> p;

	for(size_t i = 0 ; i < dim ; i++)
		p.bc[i] = NON_PERIODIC;

	return p;
}

template<unsigned int dim>
size_t get_gdb_ext(const openfpm::vector<GBoxes<dim>> & gdb_ext, size_t start , size_t stop, size_t k)
{
	for (size_t i = start ; i < stop ; i++)
	{
		if (gdb_ext.get(i).k == k)
		{return i;}
	}

	// not found
	return (size_t)-1;
}

/*! \brief Add a box to gdb_ext
 *
 * \param on which gdb_ext array add the box
 * \param k from which definition box it come from
 *        This parameter make sense only when the grid is not defined everywhere
 * \param grid of the sub-domain
 * \param grid of the sub-domain inclusive of ghost
 *
 */
template<unsigned int dim>
void add_to_gdb_ext(openfpm::vector<GBoxes<dim>> & gdb_ext, size_t k, Box<dim,long int> & sp_t, Box<dim,long int> & sp_tg)
{
	// Add gdb_ext
	gdb_ext.add();

	//! Save the origin of the sub-domain of the local grid
	gdb_ext.last().origin = sp_tg.getP1();

	// save information about the local grid: domain box seen inside the domain + ghost box (see GDBoxes for a visual meaning)
	// and where the GDBox start, or the origin of the local grid (+ghost) in global coordinate
	gdb_ext.last().Dbox = sp_t;
	gdb_ext.last().Dbox -= sp_tg.getP1();

	gdb_ext.last().GDbox = sp_tg;
	gdb_ext.last().GDbox -= sp_tg.getP1();

	gdb_ext.last().k = k;
}

/*! \brief Create the gdb_ext
 *
 * It is a fundamental function, because it create the structure that store the information of the local grids. In
 * particular from the continuous decomposed domain it calculate the grid that each sub-domain store
 *
 * \param gdb_ext output Vector of Boxes that define the local grids extension
 * \param dec Decomposition
 * \param cd_sm CellDecomposer the size of cell is equal to the distance between grid points
 *
 */
template<int dim, typename Decomposition>
inline void create_gdb_ext(openfpm::vector<GBoxes<Decomposition::dims>> & gdb_ext,
						   openfpm::vector<size_t> & gdb_ext_markers,
		                   Decomposition & dec,
						   CellDecomposer_sm<Decomposition::dims,typename Decomposition::stype,shift<dim,typename Decomposition::stype>> & cd_sm,
						   openfpm::vector<Box<Decomposition::dims,long int>> & bx_create,
						   const Ghost<Decomposition::dims,long int> & exp,
						   bool use_bx_def)
{
	gdb_ext.clear();
	gdb_ext_markers.clear();

	// Get the number of local grid needed
	size_t n_grid = dec.getNSubDomain();

	// Allocate the grids
	for (size_t i = 0 ; i < n_grid ; i++)
	{
		gdb_ext_markers.add(gdb_ext.size());

		// Get the local sub-domain (Grid conversion must be done with the domain P1 equivalent to 0.0)
		// consider that the sub-domain with point P1 equivalent to the domain P1 is a (0,0,0) in grid unit
		SpaceBox<Decomposition::dims, typename Decomposition::stype> sp = dec.getSubDomain(i);
		SpaceBox<Decomposition::dims, typename Decomposition::stype> sp_g = dec.getSubDomainWithGhost(i);

		// Because of round off we expand for safety the ghost area
		// std::nextafter return the next bigger or smaller representable floating
		// point number
		for (size_t i = 0 ; i < Decomposition::dims ; i++)
		{
			sp_g.setLow(i,std::nextafter(sp_g.getLow(i),sp_g.getLow(i) - 1.0));
			sp_g.setHigh(i,std::nextafter(sp_g.getHigh(i),sp_g.getHigh(i) + 1.0));
		}

		// Convert from SpaceBox<dim,St> to SpaceBox<dim,long int>
		SpaceBox<Decomposition::dims,long int> sp_t = cd_sm.convertDomainSpaceIntoGridUnits(sp,dec.periodicity());
		SpaceBox<Decomposition::dims,long int> sp_tg = cd_sm.convertDomainSpaceIntoGridUnits(sp_g,dec.periodicity());
		for (size_t i = 0 ; i < Decomposition::dims ; i++)
		{
			if (sp_t.getLow(i) < sp_tg.getLow(i))
			{sp_tg.setLow(i,sp_t.getLow(i));}
			if (sp_t.getHigh(i) > sp_tg.getHigh(i))
			{sp_tg.setHigh(i,sp_t.getHigh(i));}
		}

		if (use_bx_def == true)
		{
			// intersect the sub-domain with all the boxes

			for (size_t k = 0 ; k < bx_create.size() ; k++)
			{
				Box<Decomposition::dims, long int> inte;

				if (sp_t.Intersect(bx_create.get(k),inte) == true)
				{
					// Ok we have a sub-domain now we have to create the ghost part.
					// The ghost part is created converting the bx_def into a continuous
					// box expanding this box by the ghost and intersecting this box
					// with the sub-domain. This is one way to get a ghost area consistent
					// with the construction of the external and internal ghost boxes,
					// always calculated in continuous from the decomposition.
					//

					Box<Decomposition::dims,typename Decomposition::stype> output;
					Box<Decomposition::dims,typename Decomposition::stype> bx_wg = cd_sm.convertCellUnitsIntoDomainSpaceMiddle(bx_create.get(k));
					bx_wg.enlarge(dec.getGhost());
					bx_wg.Intersect(sp_g,output);

					SpaceBox<Decomposition::dims,long int> sp_t2 = inte;
					SpaceBox<Decomposition::dims,long int> sp_tg2 =  cd_sm.convertDomainSpaceIntoGridUnits(output,dec.periodicity());

					add_to_gdb_ext(gdb_ext,k,sp_t2,sp_tg2);
				}
			}
		}
		else
		{
			add_to_gdb_ext(gdb_ext,0,sp_t,sp_tg);
		}
	}

	gdb_ext_markers.add(gdb_ext.size());
}

/*! \brief Create the gdb_ext
 *
 * \param gdb_ext Vector of Boxes that define the local grids extension
 * \param gdb_ext_markers filled with sub-domain markers
 *                see gdb_ext_markers in grid_dist_id for an explanation
 * \param dec Decomposition
 * \param sz Global grid grid size
 * \param domain Domain where the grid is defined
 * \param spacing Define the spacing of the grid
 * \param bc boundary conditions
 *
 */
template<int dim, typename Decomposition>
inline void create_gdb_ext(openfpm::vector<GBoxes<dim>> & gdb_ext,
		                   Decomposition & dec,
						   const size_t (& sz)[dim],
						   const Box<Decomposition::dims,typename Decomposition::stype> & domain,
						   typename Decomposition::stype (& spacing)[dim])
{
	// Create the cell decomposer
	CellDecomposer_sm<Decomposition::dims,typename Decomposition::stype, shift<Decomposition::dims,typename Decomposition::stype>> cd_sm;

	size_t cdp[dim];

	// Get the parameters to create a Cell-decomposer
	getCellDecomposerPar<Decomposition::dims>(cdp,sz,dec.periodicity());

	// Careful cd_sm require the number of cell
	cd_sm.setDimensions(domain,cdp,0);

	// create an empty vector of boxes
	openfpm::vector<Box<Decomposition::dims,long int>> empty;
	Ghost<Decomposition::dims,long int> zero(0);

	//! We are not interested on the markers
	openfpm::vector<size_t> unused;
	create_gdb_ext<dim,Decomposition>(gdb_ext,unused,dec,cd_sm,empty,zero,false);

	// fill the spacing
	for (size_t i = 0 ; i < dim ; i++)
	{spacing[i] = cd_sm.getCellBox().getP2()[i];}
}

/*! \brief It store the information about the external ghost box
 *
 *
 */
template <unsigned int dim> struct e_box_id
{
	//! Box defining the external ghost box in global coordinates
	::Box<dim,long int> g_e_box;

	//! Box defining the external ghost box in local coordinates for gdb_ext
	::Box<dim,long int> l_e_box;

	//! Box defining the external box in local coordinates for received box
	::Box<dim,long int> lr_e_box;

	//! Sector position of the external ghost
	comb<dim> cmb;

	//! Id
	size_t g_id;

	//! sub_id in which sub-domain this box live
	size_t sub;
};

/*! \brief flip box just convert and internal ghost box into an external ghost box and the other way around
 *
 * \param box to convert
 * \param cmb sector position of the box
 *
 * \return the converted box
 *
 */
template<unsigned int dim, typename T, typename idT>
Box<dim,long int> flip_box(const Box<dim,idT> & box, const comb<dim> & cmb, const grid_sm<dim,T> & ginfo)
{
	Box<dim,long int> flp;

	for (size_t i = 0 ; i < dim; i++)
	{
		if (cmb[i] == 0)
		{
			flp.setLow(i,box.getLow(i));
			flp.setHigh(i,box.getHigh(i));
		}
		else if (cmb[i] == 1)
		{
			flp.setLow(i,box.getLow(i) + ginfo.size(i));
			flp.setHigh(i,box.getHigh(i) + ginfo.size(i));
		}
		else if (cmb[i] == -1)
		{
			flp.setLow(i,box.getLow(i) - ginfo.size(i));
			flp.setHigh(i,box.getHigh(i) - ginfo.size(i));
		}
	}

	return flp;
}

/*! \brief convert to sub-domain id
 *
 * In case the grid is not defined everywhere the ids returned by getProcessorIGhostSub
 * or any function that return a sub-domain id does not match the ids in gdb_ext. This
 * function convert it to the correct one
 *
 * \param k sub-domain id to convert
 * \param def_id id of the box that define the real allocated grid
 * \param gdb_ext_markers markers for sub-domain id gdb_ext
 *
 */
template<unsigned int dim>
inline size_t convert_to_gdb_ext(size_t sub_id,
		                         size_t def_id,
								 openfpm::vector<GBoxes<dim>> & gdb_ext,
								 openfpm::vector<size_t> & gdb_ext_markers)
{
	size_t start = gdb_ext_markers.get(sub_id);
	size_t stop = gdb_ext_markers.get(sub_id+1);
	return get_gdb_ext(gdb_ext,start,stop,def_id);
}

/*! \brief It store the information about the local external ghost box
 *
 *
 */
template <unsigned int dim> struct e_lbox_id
{
	//! Box defining the external ghost box in local coordinates
	::Box<dim,long int> ebox;

	//! Has this external ghost box initialized
	bool initialized = false;

	//! sub-domain id of the non-extended sub-domain
	size_t sub;

	//! to which gdb_ext this external ghost box is linked with
	//! (in case of grid defined everywhere these two number match)
	size_t sub_gdb_ext;

	//! external ghost box linked to this internal ghost box
	size_t k;

	//! Sector position of the local external ghost box
	comb<dim> cmb;
};


/*! \brief Add a local external ghost box
 *
 * \param le_sub sub-domain id
 * \param s id of the external ghost box
 * \param j id of the domain not expanded
 * \param k id of the grid (gdb_ext) this external ghost box is linked with
 * \param bid where to add the local external ghost box
 * \param box the box to add
 * \param cmb quadrant in which the external ghost box live
 *
 */
template<unsigned int dim> inline void add_loc_eg_box(size_t le_sub,
											   size_t se,
											   size_t j,
											   size_t k,
		                                       openfpm::vector<e_lbox_id<dim>> & bid,
		                                       const Box<dim,long int> & ebox,
											   comb<dim> & cmb)
{
	bid.add();

	bid.last().ebox = ebox;

	bid.last().sub = se;
	bid.last().sub_gdb_ext = k;

	bid.last().cmb = cmb;
	bid.last().k = j;
	bid.last().initialized = true;
}

/*! Add an entry of for an external ghost box
 *
 * \param k sub-domain id to which this external ghost box is linked
 * \param cmb quadrant where the received linked internal ghost box live
 * \param output external ghost box
 * \param g_id global id of the external ghost box, in general this id is communicated
 *             by the processor that has the linked internal ghost-box
 * \param origin domain where this external ghost box is linked
 * \param p1 origin of the received internal ghost box
 *
 */
template<unsigned int dim> inline void add_eg_box(size_t k,
		                                   const comb<dim> & cmb,
										   const Box<dim,long int> & output,
										   size_t g_id,
										   const Point<dim,long int> & origin,
										   const Point<dim,long int> & p1,
										   openfpm::vector<e_box_id<dim>> & bid)
{
	// link

	size_t sub_id = k;

	e_box_id<dim> bid_t;
	bid_t.sub = sub_id;
	bid_t.cmb = cmb;
	bid_t.cmb.sign_flip();
	::Box<dim,long int> ib = output;
	bid_t.g_e_box = ib;
	bid_t.g_id = g_id;

	// Translate in local coordinate for gdb_ext
	Box<dim,long int> tb = ib;
	tb -= origin;
	bid_t.l_e_box = tb;

	// Translate in local coordinates for the received box
	Box<dim,long int> tbr = ib;
	bid_t.lr_e_box = tbr;

	bid.add(bid_t);
}

/*! \brief Result of the itersection of a box with an array of boxes
 *
 *
 */
template<unsigned int dim>
struct result_box
{
	//! id of the box in the array that produced an non-empty intersection
	size_t id;

	//! valid result of the itersection
	Box<dim,long int> bx;
};

/*! \brief Intersect a box with an array of boxes
 *
 * \param bx_def array of boxes
 * \param bx box to intersect with
 * \param use_bx_def in case of false the box bx is added to the result array
 *        and nothing is performed
 * \param result results of the intersections
 *
 */
template<unsigned int dim>
void bx_intersect(openfpm::vector<Box<dim,long int>> & bx_def,
		          bool use_bx_def,
				  Box<dim,long int> & bx,
				  openfpm::vector_std<result_box<dim>> & result)
{
	result.clear();

	if (use_bx_def == false)
	{
		result_box<dim> tmp;
		tmp.bx = bx;
		tmp.id = 0;

		result.add(tmp);
		return;
	}

	for (size_t i = 0 ; i < bx_def.size() ; i++)
	{
		result_box<dim> inte;
		if (bx.Intersect(bx_def.get(i),inte.bx))
		{
			inte.id = i;
			result.add(inte);
		}
	}
}

/*! \brief it store a box, its unique id and the sub-domain from where it come from
 *
 */
template<unsigned int dim> struct i_box_id
{
	//! Box
	::Box<dim,long int> box;

	//! id
	size_t g_id;

	//! r_sub id of the sub-domain in the sent list
	size_t r_sub;

	//! Sector where it live the linked external ghost box
	comb<dim> cmb;



	//! sub
	size_t sub;
};

/*! \brief set of internal ghost box to send
 *
 *
 */
template<unsigned int dim>
struct ibox_send
{
	//! global id
	size_t gid;

	//! internal ghost box
	Box<dim,long int> ibox;
};



/*! \brief it store an internal ghost box, the linked external ghost box and the sub-domain from where
 *  it come from as internal ghost box
 *
 */
template<unsigned int dim> struct i_lbox_id
{
	//! Box
	::Box<dim,long int> box;

	//! sub-domain id (of the extended sub-domain).
	//! sub and sub_gdb_ext match if use_bx_def is not used in the
	//! distributed grid
	size_t sub;

	//! to which gdb_ext this internal ghost box is linked with
	size_t sub_gdb_ext;

	//! external ghost box linked to this internal ghost box
	openfpm::vector<size_t> k;

	//! combination
	comb<dim> cmb;
};


/*! \brief For each external ghost id, it contain a set of sub-domain at which this
 *         external box is linked
 *
 *
 */
template<unsigned int dim>
struct e_box_multi
{
	//! set sub-domain at which with external ghost is linked
	//! The eb_list are id for the eb_box list
	openfpm::vector<size_t> eb_list;

	//! This is the id in eb_list that contain an external ghost box
	//! able to store the full received box
	size_t full_match;

	//! It store the id of linked eg_box (eg_box.get(e_id) is valid, this mean that e_id store processor id information)
	//! \see ProctoID function
	size_t e_id;
};


/*! \brief Per-processor Internal ghost box
 *
 */
template <unsigned int dim> struct ip_box_grid
{
	// ghost in grid units
	openfpm::vector<i_box_id<dim>> bid;

	//! processor id
	size_t prc;
};

/*! \brief local Internal ghost box
 *
 */
template <unsigned int dim> struct i_lbox_grid
{
	// ghost in grid units
	openfpm::vector<i_lbox_id<dim>> bid;
};

/*! \brief Per-processor external ghost box
 *
 */
template <unsigned int dim>struct ep_box_grid
{
	// ghost in grid units
	openfpm::vector<e_box_id<dim>> bid;

	//! processor id
	size_t prc;

	//! total number of received points
	size_t recv_pnt;

	//! Number of received boxes
	size_t n_r_box;
};

/*! \brief Per-processor external ghost box
 *
 */
template <unsigned int dim> struct e_lbox_grid
{
	// ghost in grid units
	openfpm::vector<e_lbox_id<dim>> bid;
};


#endif /* SRC_GRID_GRID_DIST_UTIL_HPP_ */