Skip to content
Snippets Groups Projects
gargabe.hpp 27.59 KiB
/*
 * gargabe.hpp
 *
 *  Created on: Jan 13, 2015
 *      Author: i-bird
 */

#ifdef GARGABE_HPP_
#define GARGABE_HPP_



	template <unsigned int j, unsigned int i, typename Graph> void optimize(size_t start_p, Graph & graph)
	{
		// We assume that Graph is the rapresentation of a cartesian graph
		// this mean that the direction d is at the child d

		// Create an Hyper-cube

		HyperCube<dim> hyp;

		// Get the number of wavefronts

		size_t n_wf = hyp.getNumberOfElements_R(0);

		// Get the number of intersecting wavefront



		// Get the number of sub-dimensional common wavefront
		// basically are a list of all the subdomain common to two or more

		// Create n_wf wavefront queue

		openfpm::vector<wavefront> v_w;
		v.reserve(n_wf);

		// direction of expansion

		size_t domain_id = 0;
		int exp_dir = 0;
		bool can_expand = true;

		// while is possible to expand

		while (can_expand)
		{
			// for each direction of expansion expand the wavefront

			for (int d = 0 ; d < n_wf ; d++)
			{
				// get the wavefront at direction d

				openfpm::vector<size_t> & wf_d = v_w.get<wavefront::domains>(d);

				// flag to indicate if the wavefront can expand

				bool w_can_expand = true;

				// for each subdomain

				for (size_t sub = 0 ; sub < wf_d.size() ; sub++)
				{
					// check if the adjacent domain in direction d exist
					// and is of the same id

					// get the starting subdomain
					size_t sub_w = wf_d.get<0>(sub);

					// we get the processor id of the neighborhood sub-domain on direction d
					size_t exp_p = graph.getChild(sub_w,d).get<j>();

					// we check if it is the same processor id
					if (exp_p != domain_id)
					{
						w_can_expand = false;
					}
				}

				// if we can expand the wavefront expand it
				if (w_can_expand == true)
				{
					// for each subdomain
					for (size_t sub = 0 ; sub < wf_d.size() ; sub++)
					{
						// update the position of the wavefront
						wf_d.get<0>(sub) = wf_d.get<0>(sub) + gh.stride(d);
					}

					// here we add sub-domains to all the other queues
					// get the face of the hyper-cube

					SubHyperCube<dim,dim-1> sub_hyp = hyp.getSubHyperCube(d);

					std::vector<comb<dim>> q_comb = sub_hyp.getCombinations_R(dim-2);
				}
			}
		}

		// For each point in the Hyper-cube check if we can move the wave front


	}

#ifndef PARALLEL_DECOMPOSITION
//		CreateSubspaces();
#endif

#ifndef USE_METIS_GP

		// Here we do not use METIS
		// Distribute the divided domains

		// Get the number of processing units
		size_t Np = v_cl.getProcessingUnits();

		// Get the ID of this processing unit
		// and push the subspace is taking this
		// processing unit

		for (size_t p_id = v_cl.getProcessUnitID(); p_id < Np ; p_id += Np)
			id_sub.push_back(p_id);
#else


#endif



<<<<<<< HEAD
		/////////////// DEBUG /////////////////////

		// get the decomposition
		auto & dec = g_dist.getDecomposition();

		Vcluster & v_cl = *global_v_cluster;

		// check the consistency of the decomposition
		val = dec.check_consistency();
		BOOST_REQUIRE_EQUAL(val,true);

		// for each local volume
		// Get the number of local grid needed
		size_t n_grid = dec.getNLocalHyperCube();

		size_t vol = 0;

		openfpm::vector<Box<2,size_t>> v_b;

		// Allocate the grids
		for (size_t i = 0 ; i < n_grid ; i++)
		{
			// Get the local hyper-cube
			SpaceBox<2,float> sub = dec.getLocalHyperCube(i);

			Box<2,size_t> g_box = g_dist.getCellDecomposer().convertDomainSpaceIntoGridUnits(sub);
			v_b.add(g_box);

			vol += g_box.getVolumeKey();
		}

		v_cl.reduce(vol);
		v_cl.execute();

		BOOST_REQUIRE_EQUAL(vol,k*k);

		/////////////////////////////////////


		// 3D test

	//	g_dist.write("");

	/*	auto g_it = g_dist.getIteratorBulk();

		auto g_it_halo = g_dist.getHalo();

		// Let try to solve the poisson equation d2(u) = f with f = 1 and computation
		// comunication overlap (100 Jacobi iteration)

		for (int i = 0 ; i < 100 ; i++)
		{
			g_dist.ghost_get();

			// Compute the bulk

			jacobi_iteration(g_it);

			g_dist.ghost_sync();

			// Compute the halo

			jacobi_iteration(g_it_halo);
		}*/


		BOOST_AUTO_TEST_CASE( grid_dist_id_poisson_test_use)
		{
			// grid size
		/*	size_t sz[2] = {1024,1024};

			// Distributed grid with id decomposition

			grid_dist_id<2, scalar<float>, CartDecomposition<2,size_t>> g_dist(sz);

			// Create the grid on memory

			g_dist.Create();*/

		/*	auto g_it = g_dist.getIteratorBulk();

			auto g_it_halo = g_dist.getHalo();

			// Let try to solve the poisson equation d2(u) = f with f = 1 and computation
			// comunication overlap (100 Jacobi iteration)

			for (int i = 0 ; i < 100 ; i++)
			{
				g_dist.ghost_get();

				// Compute the bulk

				jacobi_iteration(g_it);

				g_dist.ghost_sync();

				// Compute the halo

				jacobi_iteration(g_it_halo);
			}*/
		}

		template<typename iterator> void jacobi_iteration(iterator g_it, grid_dist_id<2, float, scalar<float>, CartDecomposition<2,float>> & g_dist)
		{
			// scalar
			typedef scalar<float> S;

			// iterator

			while(g_it.isNext())
			{
				// Jacobi update

				auto pos = g_it.get();

				g_dist.template get<S::ele>(pos) = (g_dist.template get<S::ele>(pos.move(0,1)) +
			                             g_dist.template get<S::ele>(pos.move(0,-1)) +
			                             g_dist.template get<S::ele>(pos.move(1,1)) +
			                             g_dist.template get<S::ele>(pos.move(1,-1)) / 4.0);

				++g_it;
			}
		}

=======

		/*
		 * CartDecomposition.cpp
		 *
		 *  Created on: Aug 15, 2014
		 *      Author: Pietro Incardona
		 */

		#include "CartDecomposition.hpp"



		/*! \brief The the bulk part of the data set, or the data that does not depend
		 *  from the ghosts layers
		 *
		 * The the bulk part of the data set, or the data that does not depend from the
		 *  ghosts layers
		 *
		 */

		/*template<typename T> T CartDecomposition<T>::getBulk(T data)
		{
			// for each element in data

			for (size_t i = 0; i < data.size() ; i++)
			{
				if (localSpace.isInside())
			}

		}

		template<typename T> T CartDecomposition<T>::getInternal()
		{

		}*/

		/*! \brief Check if is border or bulk
		 *
		 * \param neighboorhood define the neighboorhood of all the points
		 * \return true if border, false if bulk
		 *
		 */

		bool borderOrBulk(neighborhood & nb)
		{
			device::grid<1,size_t> nbr = nb.next();

			// check the neighborhood

			// get neighborhood iterator

			grid_key_dx_iterator<dim> iterator_nbr = nbr.getIterator();

			while (iterator_nbr.hasNext())
			{
				grid_key_dx key_nbr = iterator_nbr.next();

				// check if the neighboorhood is internal

				if(subspace.isBound(data.template get<Point::x>(key_nbr)) == false)
				{
					// it is border

					return true;

					ret.bord.push_back(key);
					break;
				}
			}

			return false;
		}

		/*! \brief This function divide the data set into bulk, border, external and internal part
		 *
		 * \tparam dim dimensionality of the structure storing your data
		 *         (example if they are in 3D grid, has to be 3)
		 * \tparam T type of object we are dividing
		 * \tparam device type of layout selected
		 * \param data 1-dimensional grid of point
		 * \param nb define the neighborhood of all the points
		 * \return a structure with the set of objects divided
		 *
		 */

		template<unsigned int dim, typename T, template<typename> class layout, typename Memory, template<unsigned int, typename> class Domain, template<typename, typename, typename> class data_s>
		dataDiv<T> CartDecomposition<dim,T,layout>::divide(device::grid<1,Point<dim,T>> & data, neighborhood & nb)
		{
			//! allocate the 3 subset

			dataDiv<T> ret;

			ret.bord = new boost::shared_ptr<T>(new T());
			ret.inte = new boost::shared_ptr<T>(new T());
			ret.ext = new boost::shared_ptr<T>(new T());

			//! get grid iterator

			grid_key_dx_iterator<dim> iterator = data.getIterator();

			//! we iterate trough all the set of objects

			while (iterator.hasNext())
			{
				grid_key_dx<dim> key = iterator.next();

				//! Check if the object is inside the subspace

				if (subspace.isBound(data.template get<Point<3,T>::x>(key)))
				{
					//! Check if the neighborhood is inside the subspace

					if (borderOrBulk(nb) == true)
					{
						// It is border

						ret.bord.push_back(key);
					}
					else
					{
						// It is bulk

						ret.bulk.push_back(key);
					}
				}
				else
				{
					//! it is external

					ret.ext.push_back(key);
				}
			}
		}


>>>>>>> Jenkin script for taurus


/*! \brief Allocate a set of objects
 *
 * \tparam obj
 * \param n number of object
 *
 * \return an object representing an array of objects
 *
 */
/*	template <typename obj> Vcluster_object_array<obj> allocate(size_t n)
{
	// Vcluster object array
	Vcluster_object_array<obj> vo;

	// resize the array
	vo.resize(n);

	// Create the object on memory and return a Vcluster_object_array
	return vo;
}*/


/*template<typename T>
class Vcluster_object_array : public VObject
{
	std::vector<T> objects;

public:*/

	/*! \brief Constructor of object array
	 *
	 */
/*	Vcluster_object_array()
	{

	}*/

	/*! \brief Return the size of the objects array
	 *
	 * \return the size of the array
	 *
	 */
/*	size_t size() const
	{
		return objects.size();
	}*/

	/*! \brief Return the element i
	 *
	 * \return a reference to the object i
	 *
	 */

/*	T & get(unsigned int i)
	{
		return objects[i];
	}*/

	/*! \brief Return the element i
	 *
	 * \return a reference to the object i
	 *
	 */
/*	const T & get(unsigned int i) const
	{
		return objects[i];
	}*/

	/*! \brief Check if this Object is an array
	 *
	 * \return true, it is an array
	 *
	 */
/*	bool isArray()
	{
		return true;
	}*/

	/*! \brief Destroy the object
	 *
	 */
/*	virtual void destroy()
	{
		// Destroy the objects
		objects.clear();
	}*/

	/*! \brief Get the size of the memory needed to pack the object
	 *
	 * \return the size of the message to pack the object
	 *
	 */
/*	size_t packObjectSize()
	{
		size_t message = 0;

		// Destroy each objects
		for (size_t i = 0 ; i < objects.size() ; i++)
		{
			message += objects[i].packObjectSize();
		}

		return message;
	}*/


	/*! \brief Get the size of the memory needed to pack the object
	 *
	 * \param Memory where to write the packed object
	 *
	 * \return the size of the message to pack the object
	 *
	 */
/*	size_t packObject(void * mem)
	{
		// Pointer is zero
		size_t ptr = 0;
		unsigned char * m = (unsigned char *)mem;

		// pack each object
		for (size_t i = 0 ; i < objects.size() ; i++)
		{
			ptr += objects[i].packObject(&m[ptr]);
		}

#ifdef DEBUG
		if (ptr != packObjectSize())
		{
			std::cerr << "Error " << __FILE__ << " " << __LINE__ << " the pack object size does not match the message" << "\n";
		}
#endif

		return ptr;
	}*/

	/*! \brief Calculate the size to pack an object in the array
	 *
	 * \param array object index
	 *
	 */
/*	size_t packObjectInArraySize(size_t i)
	{
		return objects[i].packObjectSize();
	}*/

	/*! \brief pack the object in the array (the message produced can be used to move one)
	 * object from one processor to another
	 *
	 * \param i index of the object to pack
	 * \param p Memory of the packed object message
	 *
	 */
/*	size_t packObjectInArray(size_t i, void * p)
	{
		return objects[i].packObject(p);
	}*/

	/*! \brief Destroy an object from the array
	 *
	 * \param i object to destroy
	 *
	 */
/*	void destroy(size_t i)
	{
		objects.erase(objects.begin() + i);
	}*/

	/*! \brief Return the object j in the array
	 *
	 * \param j element j
	 *
	 */
/*	T & operator[](size_t j)
	{
		return objects[j];
	}*/

	/*! \brief Return the object j in the array
	 *
	 * \param j element j
	 *
	 */
/*	const T & operator[](size_t j) const
	{
		return objects[j];
	}*/

	/*! \brief Resize the array
	 *
	 * \param size
	 *
	 */
/*	void resize(size_t n)
	{
		objects.resize(n);
	}
};*/

/*! \brief VObject
 *
 * Any object produced by the Virtual cluster (MUST) inherit this class
 *
 */

/*class VObject
{
public:

	// Check if this Object is an array
	virtual bool isArray() = 0;

	// destroy the object
	virtual void destroy() = 0;

	// get the size of the memory needed to pack the object
	virtual size_t packObjectSize() = 0;

	// pack the object
	virtual size_t packObject(void *) = 0;

	// get the size of the memory needed to pack the object in the array
	virtual size_t packObjectInArraySize(size_t i) = 0;

	// pack the object in the array (the message produced can be used to move one)
	// object from one processor to another
	virtual size_t packObjectInArray(size_t i, void * p) = 0;

	// destroy an element from the array
	virtual void destroy(size_t n) = 0;
};*/








/*! \brief Impose an operator
 *
 * This function impose an operator on a particular grid region to produce the system
 *
 * Ax = b
 *
 * ## Stokes equation, lid driven cavity with one splipping wall
 *
 * \param op Operator to impose (A term)
 * \param num right hand side of the term (b term)
 * \param id Equation id in the system that we are imposing
 * \param it_d iterator that define where you want to impose
 *
 */
template<typename T> void impose(const T & op , typename Sys_eqs::stype num ,long int id ,grid_dist_iterator_sub<Sys_eqs::dims,typename g_map_type::d_grid> it_d, bool skip_first = false)
{
	//////////////////////// DEBUG /////////////////

	SparseMatrix<double,int> Al;
	Al.load("debug_matrix_single_processor");

	// Construct the map 3 processors 1 processors

	std::unordered_map<size_t,size_t> map_row;

	auto it2 = g_map.getDomainGhostIterator();
	auto ginfo = g_map.getGridInfoVoid();

	while (it2.isNext())
	{
		auto key = it2.get();
		auto key_g = g_map.getGKey(key);
		key_g += pd.getKP1();

		// To linearize must be positive
		bool is_negative = false;
		for (size_t i = 0 ; i < Sys_eqs::dims ; i++)
		{
			if (key_g.get(i) < 0)
				is_negative = true;
		}

		if (is_negative == true)
		{
			++it2;
			continue;
		}

		// Carefull g map is extended, so the original (0,0) is shifted in g_map by

		if (g_map.template get<0>(key) == 7)
		{
			int debug = 0;
			debug++;
		}

		map_row[g_map.template get<0>(key)] = ginfo.LinId(key_g);

		++it2;
	}

	////////////////////////////////////////////////

	Vcluster & v_cl = *global_v_cluster;

	openfpm::vector<triplet> & trpl = A.getMatrixTriplets();

	auto it = it_d;
	grid_sm<Sys_eqs::dims,void> gs = g_map.getGridInfoVoid();

	std::unordered_map<long int,float> cols;

	// resize b if needed
	b.resize(Sys_eqs::nvar * g_map.size());

	bool is_first = skip_first;

	// iterate all the grid points
	while (it.isNext())
	{
		if (is_first == true && v_cl.getProcessUnitID() == 0)
		{
			++it;
			is_first = false;
			continue;
		}
		else
			is_first = false;

		// get the position
		auto key = it.get();

		// Calculate the non-zero colums
		T::value(g_map,key,gs,spacing,cols,1.0);

		//////////// DEBUG //////////////////

		auto g_calc_pos = g_map.getGKey(key);
		g_calc_pos += pd.getKP1();

		/////////////////////////////////////

		// create the triplet

		for ( auto it = cols.begin(); it != cols.end(); ++it )
		{
			trpl.add();
			trpl.last().row() = g_map.template get<0>(key)*Sys_eqs::nvar + id;
			trpl.last().col() = it->first;
			trpl.last().value() = it->second;

			///////////// DEBUG ///////////////////////

			auto ginfo = g_map.getGridInfoVoid();

			size_t r = (trpl.last().row() / Sys_eqs::nvar);
			size_t r_rest = (trpl.last().row() % Sys_eqs::nvar);
			size_t c = (trpl.last().col() / Sys_eqs::nvar);
			size_t c_rest = (trpl.last().col() % Sys_eqs::nvar);
			double val = trpl.last().value();

			// Transform

			size_t rf = map_row[r] * 3 + r_rest;
			size_t cf = map_row[c] * 3 + c_rest;

			auto position_row = ginfo.InvLinId(rf / 3);
			auto position_col = ginfo.InvLinId(cf / 3);

			double valf = Al.getValue(rf,cf);

			if (val != valf)
			{
				int debug = 0;
				debug++;
			}

			///////////////////////////////////////////
//				std::cout << "(" << trpl.last().row() << "," << trpl.last().col() << "," << trpl.last().value() << ")" << "\n";
		}

		b(g_map.template get<0>(key)*Sys_eqs::nvar + id) = num;

		cols.clear();
//			std::cout << "\n";

		// if SE_CLASS1 is defined check the position
#ifdef SE_CLASS1
//			T::position(key,gs,s_pos);
#endif

		++row;
		++row_b;
		++it;
	}
}

typename Sys_eqs::SparseMatrix_type A;

/*! \brief produce the Matrix
 *
 *  \return the Sparse matrix produced
 *
 */
typename Sys_eqs::SparseMatrix_type & getA()
{
#ifdef SE_CLASS1
	consistency();
#endif
	A.resize(g_map.size()*Sys_eqs::nvar,g_map.size()*Sys_eqs::nvar);

	///////////////// DEBUG SAVE //////////////////

//		A.save("debug_matrix_single_processor");

	////////////////////////////////////////////////

	return A;

}


typename Sys_eqs::SparseMatrix_type A;

/*! \brief produce the Matrix
 *
 *  \return the Sparse matrix produced
 *
 */
typename Sys_eqs::SparseMatrix_type & getA()
{
#ifdef SE_CLASS1
	consistency();
#endif
	A.resize(g_map.size()*Sys_eqs::nvar,g_map.size()*Sys_eqs::nvar);

	///////////////// DEBUG SAVE //////////////////

//		A.save("debug_matrix_single_processor");

	////////////////////////////////////////////////

	return A;

}


/*! \brief produce the B vector
 *
 *  \return the vector produced
 *
 */
typename Sys_eqs::Vector_type & getB()
{
#ifdef SE_CLASS1
	consistency();
#endif

	// size of the matrix
//		B.resize(g_map.size()*Sys_eqs::nvar);

	// copy the vector
//		for (size_t i = 0; i < row_b; i++)
//			B.insert(i,b.get(i));

	return b;
}
};




/*! \brief Given an external ghost box, I have an internal ghost box with the same id this function link them
 *
 *
 */
void link_ebox_with_ibox()
{
/*
#ifdef SE_CLASS1

	// No box must be unlinked
	for (size_t i = 0 ; i < proc_int_box.size() ; i++)
	{
		for (size_t j = 0 ; j < proc_int_box.get(i).ibx.size() ; j++)
			proc_int_box.get(i).ibx.get(j).link = -1;

		for (size_t j = 0 ; j < proc_int_box.get(i).ebx.size() ; j++)
			proc_int_box.get(i).ebx.get(j).link= -1;
	}
#endif

	// Get the number of near processors
	for (size_t i = 0 ; i < proc_int_box.size() ; i++)
	{
		std::unordered_map<size_t,std::pair<size_t,size_t>> from_id_to_ibox;
		std::unordered_map<size_t,std::pair<size_t,size_t>> from_id_to_ebox;

		for (size_t j = 0 ; j < getProcessorNIGhost(i) ; j++)
		{
			std::pair<size_t,size_t> & ele = from_id_to_ibox[getProcessorIGhostId(i,j)];
			ele.first = i;
			ele.second = j;
		}

		for (size_t j = 0 ; j < getProcessorNEGhost(i) ; j++)
		{
			std::pair<size_t,size_t> & ele = from_id_to_ebox[getProcessorEGhostId(i,j)];

			ele.first = i;
			ele.second = j;
		}

		// iterate across all the ibox

		for ( auto it = from_id_to_ibox.begin(); it != from_id_to_ibox.end(); ++it )
		{
			auto ite = from_id_to_ebox.find(it->first);

			if(ite == from_id_to_ebox.end())
				std::cerr << __FILE__ << ":" << __LINE__ << " error exist an internal ghost box that does not have an external ghost box" << std::endl;

			if (ite->first != it->first)
				std::cerr << __FILE__ << ":" << __LINE__ << " error exist an internal ghost box with inconsistent information about its origin" << std::endl;

			proc_int_box.get(i).ibx.get(it->second.second).link = ite->second.second;
			proc_int_box.get(i).ebx.get(ite->second.second).link = it->second.second;
		}
	}

#ifdef SE_CLASS1

	// No box must be unlinked
	for (size_t i = 0 ; i < proc_int_box.size() ; i++)
	{
		for (size_t j = 0 ; j < proc_int_box.get(i).ibx.size() ; j++)
		{
			if (proc_int_box.get(i).ibx.get(j).link == -1)
				std::cerr << __FILE__ << ":" << __LINE__ << " error detected unlinked internal ghost box" << std::endl;
		}

		for (size_t j = 0 ; j < proc_int_box.get(i).ebx.size() ; j++)
		{
			if (proc_int_box.get(i).ibx.get(j).link == -1)
				std::cerr << __FILE__ << ":" << __LINE__ << " error detected unlinked external ghost box" << std::endl;
		}
	}
#endif*/


	/*		for (size_t i = 0 ; i < this->getNNProcessors() ; i++)
			{
				for (size_t j = 0 ; j < this->getProcessorNIGhost(i) ; j++)
				{
					size_t id_i = this->getProcessorIGhostId(i,j);
					long int link = this->getProcessorIGhostLink(i,j);

					if (link == -1)
						return false;

					size_t id_e = this->getProcessorEGhostId(i,link);

					if (id_i != id_e)
						return false;
				}
			}*/
}





/////////////////////////////// Fixing  IG BOX not clear if it is really needed /////////////////

/*! \brief Fix the destination box based on the source box
 *
 * in case of periodic grids external ghost box and internal ghost box can miss-match
 * in size if the external ghost box is outside the domain, or more practically
 * if internal and external ghost boxes are linked by periodicity.
 * The two boxes has been calculated in two different way and round-off problem can happen
 * In this call we fix such problem maching the received ghost box to the external ghost box
 *
 * \param bs source box
 * \param dom_i domain from where the source box has been created
 * \param bd destination box
 * \param cmb sector of the destination box
 *
 */
inline bool fix_box_ig(Box<dim,size_t> & bs, Box<dim,long int> & dom_i, const Box<dim,size_t> & bd, comb<dim> & cmb)
{
	// Each dimension must match
	for (size_t k = 0 ; k < dim ; k++)
	{
		size_t iw = bs.getHigh(k) - bs.getLow(k);
		size_t ew = bd.getHigh(k) - bd.getLow(k);

		if (iw != ew)
		{
			std::cout << "Fixing internal external" << std::endl;

			Box<dim,size_t> & bst = bs;

			if (cmb.c[k] == -1)
				bst.setHigh(k,bd.getHigh(k) - (iw - ew));
			else if (cmb.c[k] == 1)
				bst.setLow(k,bs.getLow(k) + (iw - ew));
			else
				return false;

			// points in direction k of the domain
			long int dom_ext = dom_i.getHigh(k) - dom_i.getLow(k);
			// points in direction k of the internal ghost box
			long int ext_ibox = bst.getHigh(k) - bst.getLow(k);

			// internal ghost box cannot be bigger than the domain
			// notify the failure in fixing
			if (dom_ext < ext_ibox)
				return false;

			bs = bst;
		}
	}

	return true;
}

/////////////// GHOST LOCAL FIX


bool ret = fix_box_ig(bx_src,gdb_ext.get(i).Dbox,bx_dst,loc_eg_box.get(sub_id_dst).bid.get(k).cmb);

if (ret == false)
	std::cerr << "ERROR FAIL TO FIX " << std::endl;


/////////////////////


/*! \brief Fix the internal and external ghost box to be consistent
 *
 * in case of periodic grids external ghost box and internal ghost box can miss-match
 * in size if the external ghost box is outside the domain, or more practically
 * if internal and external ghost boxes are linked by periodicity.
 * The two boxes has been calculated in two different way and round-off problem can happen
 * In this call we fix such problem maching each processor communicate its calculate external
 * ghost boxes out of the boundary of the domain the receiving processor fix the size of the
 * connected internal ghost box
 *
 */
inline void fix_ie_g_box()
{
	if (init_fix_ie_g_box == true)	return;

	comb<dim> zero;
	zero.zero();

	// Here we collect all the external ghost box in the sector different from 0 that this processor has
	openfpm::vector<size_t> prc;
	openfpm::vector<size_t> prc_recv;
	openfpm::vector<size_t> sz_recv;
	openfpm::vector<openfpm::vector<Box_fix<dim>>> box_ext_send(dec.getNNProcessors());
	openfpm::vector<openfpm::vector<Box_fix<dim>>> box_ext_recv;

	// It contain the map g_id as key, and the pair, processor id, box-id
	std::unordered_map<long int,std::pair<long int,long int>> iglist;

	// Here we create list of all the internal ghost box linked with an external ghost box
	// by periodicity
	for(size_t i = 0 ; i < dec.getNNProcessors() ; i++)
	{
		for (size_t j = 0 ; j < ig_box.get(i).bid.size() ; j++)
		{
			if (ig_box.get(i).bid.get(j).cmb != zero)
			{
				auto & ele = iglist[ig_box.get(i).bid.get(j).g_id];
				ele.first = i;
				ele.second = j;
			}
		}
	}

	for(size_t i = 0 ; i < dec.getNNProcessors() ; i++)
	{
		for (size_t j = 0 ; j < eg_box.get(i).bid.size() ; j++)
		{
			if (eg_box.get(i).bid.get(j).cmb != zero)
			{
				box_ext_send.get(i).add();
				box_ext_send.get(i).last().bx = eg_box.get(i).bid.get(j).l_e_box;
				box_ext_send.get(i).last().g_id = eg_box.get(i).bid.get(j).g_id;
			}
		}
		prc.add(dec.IDtoProc(i));
	}

	v_cl.SSendRecv(box_ext_send,box_ext_recv,prc,prc_recv,sz_recv);

	// Received the external boxes we do fixation for each processor
	for (size_t i = 0 ; i < box_ext_recv.size() ; i++)
	{
		// For each received external ghost box
		for (size_t j = 0 ; j < box_ext_recv.get(i).size() ; j++)
		{
			// ig box linked
			size_t proc_id = dec.ProctoID(prc_recv.get(i));

			auto it = g_id_to_internal_ghost_box.get(proc_id).find(box_ext_recv.get(i).get(j).g_id);

#ifdef SE_CLASS1

			if (it == g_id_to_internal_ghost_box.get(proc_id).end())
			{
				std::cerr << __FILE__ << ":" << __LINE__ << " warning unlinked external ghost box" << std::endl;
				continue;
			}

#endif

			size_t link = it->second;

			Box<dim,size_t> & box_i = ig_box.get(proc_id).bid.get(link).box;

			// local Sub-domain from where this internal ghost box is calculated
			Box<dim,long int> & box_sub_i = gdb_ext.get(ig_box.get(proc_id).bid.get(link).sub).Dbox;

			comb<dim> cmb = ig_box.get(proc_id).bid.get(link).cmb;
			// the fixing can fail
			// if it fail put the ig_box into a list
			// The fix can fail (for example) if the external ghost box require 7 point on x
			// but the domain has 6 point, in this case we cannot correct the internal ghost box
			bool ret = fix_box_ig(box_i,box_sub_i,box_ext_recv.get(i).get(j).bx,cmb);

			if (ret == false)
				std::cerr << __FILE__ << ":" << __LINE__ << " and inconsistency between internal and external ghost boxes has been detected. The fix is not possible please change your ghost size (by a small amount) on the order of 10^-5 if you use float 10^-14 if you use double"  << std::endl;

			// Invalidate the ig_box in the list
			auto & ele = iglist[box_ext_recv.get(i).get(j).g_id];
			ele.first = -1;
			ele.second = -1;
		}
	}

	// Here we check if all the internal ghost box has been explored
	// if one internal ghost box has not been explored, it been that, there is not
	// corresponding external ghost box on the other side. so we invalidate

	for ( auto it = iglist.begin(); it != iglist.end(); ++it )
	{
		// If has not been explored invalidate, there is not external ghost
		if (it->second.first != -1)
		{
			size_t a = it->second.first;
			size_t b = it->second.second;
			ig_box.get(a).bid.get(b).box.invalidate();
		}
	}
}


//////////////////////////////////////////////////////////////

// Fix the exteenal and internal ghost boxes in ghost get
fix_ie_g_box();

//////////////////////


/*		Point<dim,long int> p;
		p.get(0) = 0;
		p.get(1) = 81;
		p.get(2) = 79;
		if (ib.isInside(p))
		{
			int debug = 0;
			debug++;
		}

		for (size_t i = 0 ; i < dim ; i++)
		{
			if (sub_domain.getLow(i) == ib_dom.getLow(i) &&
				(sub_domain_other.getHigh(i) == sub_domain.getLow(i) || cmb.c[i] == 1))
			{
				if (g.getHigh(i) != INVALID_GHOST && (ib.getHigh(i) - ib.getLow(i) + 1) > g.getHigh(i))
				{
					ib.setHigh(i,ib.getLow(i) + g.getHigh(i) - 1);
				}
			}

			if (sub_domain.getHigh(i) == ib_dom.getHigh(i) &&
				(sub_domain_other.getLow(i) == sub_domain.getHigh(i) || cmb.c[i] == 1))
			{
				if (g.getLow(i) != -INVALID_GHOST && (ib.getHigh(i) - ib.getLow(i) + 1) > abs(g.getLow(i)))
				{
					ib.setLow(i, g.getHigh(i) - g.getLow(i) + 1);
				}
			}
		}

		// This is a special case because a domain intersect itself by
		// periodicity
		if (sub_domain == sub_domain_other)
		{
			for (size_t i = 0 ; i < dim ; i++)
			{
				if (sub_domain.getLow(i) == ib_dom.getLow(i) &&
					sub_domain.getLow(i) == domain.getLow(i) &&
					sub_domain_other.getHigh(i) == domain.getHigh(i) &&
					cmb.c[i] == 1)
				{
					if (g.getHigh(i) != INVALID_GHOST && (ib.getHigh(i) - ib.getLow(i) + 1) > g.getHigh(i))
					{
						ib.setHigh(i,ib.getLow(i) + g.getHigh(i) - 1);
					}
				}

				if (sub_domain.getHigh(i) == ib_dom.getHigh(i) &&
					sub_domain.getHigh(i) == domain.getHigh(i) &&
					sub_domain_other.getLow(i) == sub_domain.getHigh(i) &&
					cmb.c[i] == -1)
				{
					if (g.getLow(i) != -INVALID_GHOST && (ib.getHigh(i) - ib.getLow(i) + 1) > abs(g.getLow(i)))
					{
						ib.setLow(i, g.getHigh(i) - g.getLow(i) + 1);
					}
				}
			}
		}*/

//////////////////////////

#endif /* GARGABE_HPP_ */