From e8cb410eba653c121428df63a440da58920d5f27 Mon Sep 17 00:00:00 2001
From: Pietro Incardona <incardon@mpi-cbg.de>
Date: Mon, 3 Jul 2017 00:30:38 +0200
Subject: [PATCH] Last

---
 src/interpolation/interpolation_bck.hpp | 629 ++++++++++++++++++++++++
 1 file changed, 629 insertions(+)
 create mode 100644 src/interpolation/interpolation_bck.hpp

diff --git a/src/interpolation/interpolation_bck.hpp b/src/interpolation/interpolation_bck.hpp
new file mode 100644
index 00000000..d96a9576
--- /dev/null
+++ b/src/interpolation/interpolation_bck.hpp
@@ -0,0 +1,629 @@
+/*
+ * mp4_interpolation.hpp
+ *
+ *  Created on: May 4, 2017
+ *      Author: i-bird
+ */
+
+#ifndef OPENFPM_NUMERICS_SRC_INTERPOLATION_INTERPOLATION_HPP_
+#define OPENFPM_NUMERICS_SRC_INTERPOLATION_INTERPOLATION_HPP_
+
+#include "NN/CellList/MemFast.hpp"
+#include "NN/CellList/CellList.hpp"
+
+#define INTERPOLATION_ERROR_OBJECT std::runtime_error("Runtime interpolation error");
+
+constexpr int inte_m2p = 0;
+constexpr int inte_p2m = 1;
+
+template<unsigned int n_ele, typename T>
+struct agg_arr
+{
+	T ele[n_ele];
+};
+
+/*! \brief multiply the src  by coeff for several types T
+ *
+ * \tparam type T
+ *
+ */
+template<typename T>
+struct mul_inte
+{
+	/*! \brief multiply the src  by coeff for several types T
+	 *
+	 * \param result the result of the multiplication
+	 * \param coeff coefficent to use for of the multiplication
+	 * \param src source
+	 *
+	 */
+	inline static void value(T & result, const T & coeff, const T & src)
+	{
+		result += coeff * src;
+	}
+};
+
+/*! \brief multiply the src  by coeff for several types T
+ *
+ * \tparam type T
+ *
+ */
+template<typename T, unsigned int N1>
+struct mul_inte<T[N1]>
+{
+	/*! \brief multiply the src  by coeff for several types T
+	 *
+	 * \param result the result of the multiplication
+	 * \param coeff coefficent to use for of the multiplication
+	 * \param src source
+	 *
+	 */
+	inline static void value(T (& result)[N1], const T & coeff, const T (& src)[N1])
+	{
+		for (size_t i = 0 ; i < N1 ; i++)
+			result[i] += coeff * src[i];
+	}
+};
+
+/*! \brief multiply the src  by coeff for several types T
+ *
+ * \tparam type T
+ *
+ */
+template<typename T, unsigned int N1, unsigned int N2>
+struct mul_inte<T[N1][N2]>
+{
+	/*! \brief multiply the src  by coeff for several types T
+	 *
+	 * \param result the result of the multiplication
+	 * \param coeff coefficent to use for of the multiplication
+	 * \param src source
+	 *
+	 */
+	inline static void value(T (& result)[N1][N2], const T & coeff, const T (& src)[N1][N2])
+	{
+		for (size_t i = 0 ; i < N1 ; i++)
+			for (size_t j = 0 ; j < N2 ; j++)
+				result[i][j] += coeff * src[i][j];
+	}
+};
+
+/*! \brief Class that select the operation to do differently if we are doing Mesh to particle (m2p) or particle to mesh (p2m)
+ *
+ * \tparam prp_g property of the grid to interpolate
+ * \tparam prp_v property of the vector to interpolate
+ * \param M2P or P2M
+ *
+ */
+template<unsigned int np, unsigned int prp_g, unsigned int prp_v,unsigned int m2p_or_p2m>
+struct inte_template
+{
+	/*! \brief Evaluate the interpolation
+	 *
+	 * \tparam np number of kernel points in one direction
+	 * \tparam grid type of grid
+	 * \tparam vector type of vector
+	 * \tparam iterator type of the iterator
+	 *
+	 * \param gd grid for interpolation
+	 * \param vd vector for interpolation
+	 * \param k_dist grid key grid point for interpolation
+	 * \param key_p particle for interpolation
+	 * \param a_int interpolation coefficients pre-calculated
+	 * \param key indicate which pre-calculated coefficient we have to use
+	 *
+	 */
+	template<typename grid, typename vector, typename iterator> inline static void value(grid & gd,
+			                                                          vector & vd,
+																	  const grid_dist_lin_dx & k_dist,
+																	  iterator & key_p,
+																	  typename vector::stype (& a_int)[openfpm::math::pow(vector::dims,np)],
+																	  const size_t & key)
+	{
+		mul_inte<typename std::remove_reference<decltype(gd.template get<prp_g>(k_dist))>::type>::value(gd.template get<prp_g>(k_dist),a_int[key],vd.template getProp<prp_v>(key_p));
+	}
+};
+
+/*! \brief Class that select the operation to do differently if we are doing Mesh to particle (m2p) or particle to mesh (p2m)
+ *
+ * \tparam prp_g property of the grid to interpolate
+ * \tparam prp_v property of the vector to interpolate
+ * \param M2P or P2M
+ *
+ */
+template<unsigned int np, unsigned int prp_g, unsigned int prp_v>
+struct inte_template<np,prp_g,prp_v,inte_m2p>
+{
+	/*! \brief Evaluate the interpolation
+	 *
+	 * \tparam grid type of grid
+	 * \tparam vector type of vector
+	 * \tparam iterator type of the iterator
+	 * \tparam key_type type of the key
+	 *
+	 * \param gd grid for interpolation
+	 * \param vd vector for interpolation
+	 * \param k_dist grid key grid point for interpolation
+	 * \param key_p particle for interpolation
+	 * \param a_int interpolation coefficients pre-calculated
+	 * \param key indicate which pre-calculated coefficient we have to use
+	 *
+	 */
+	template<typename grid, typename vector, typename iterator> inline static void value(grid & gd,
+			                                                          vector & vd,
+																	  const grid_dist_lin_dx & k_dist,
+																	  iterator & key_p,
+																	  typename vector::stype (& a_int)[openfpm::math::pow(vector::dims,np)],
+																	  const size_t & key)
+	{
+		mul_inte<typename std::remove_reference<decltype(gd.template get<prp_g>(k_dist))>::type>::value(vd.template getProp<prp_v>(key_p),a_int[key],gd.template get<prp_g>(k_dist));
+	}
+};
+
+/*! \brief Calculate aint
+ *
+ *
+ */
+template<unsigned int dims, typename vector, unsigned int np>
+struct calculate_aint
+{
+	static inline void value(size_t (& sz)[vector::dims],
+			                 typename vector::stype a_int[openfpm::math::pow(vector::dims,np)],
+							 typename vector::stype (& a)[vector::dims][np])
+	{
+		grid_sm<vector::dims,void> gs(sz);
+		grid_key_dx_iterator<vector::dims> kit(gs);
+
+		size_t s = 0;
+		while (kit.isNext())
+		{
+			auto key = kit.get();
+
+			a_int[s] = 1;
+
+			for (size_t i = 0 ; i < vector::dims ; i++)
+				a_int[s] *= a[i][key.get(i)];
+
+			s++;
+			++kit;
+		}
+	}
+};
+
+/*! \brief Calculate aint 2D
+ *
+ *
+ */
+template<typename vector, unsigned int np>
+struct calculate_aint<2,vector,np>
+{
+	static inline void value(size_t (& sz)[vector::dims],
+			                 typename vector::stype a_int[openfpm::math::pow(vector::dims,np)],
+							 typename vector::stype (& a)[vector::dims][np])
+	{
+		size_t s = 0;
+		for (size_t i = 0 ; i < np ; i++)
+		{
+			for (size_t j = 0 ; j < np ; j++)
+			{
+				a_int[s] = a[0][j]*a[1][i];
+
+				s++;
+			}
+		}
+	}
+};
+
+/*! \brief Calculate aint
+ *
+ *
+ */
+template<typename vector, unsigned int np>
+struct calculate_aint<3,vector,np>
+{
+	static inline void value(size_t (& sz)[vector::dims],
+			                 typename vector::stype a_int[openfpm::math::pow(vector::dims,np)],
+							 typename vector::stype (& a)[vector::dims][np])
+	{
+		size_t s = 0;
+		for (size_t i = 0 ; i < np ; i++)
+		{
+			for (size_t j = 0 ; j < np ; j++)
+			{
+				for (size_t k = 0 ; k < np ; k++)
+				{
+					a_int[s] = a[0][k]*a[1][j]*a[2][i];
+
+					s++;
+				}
+			}
+		}
+	}
+};
+
+/*! \brief return the sub-domain where this particle must be interpolated
+ *
+ * \param p particle position
+ *
+ * \return the sub-domain id
+ *
+ */
+template<typename vector, typename grid>
+inline size_t getSub(Point<vector::dims,typename vector::stype> & p,
+		             const CellList<vector::dims,typename vector::stype,Mem_fast<vector::dims,typename vector::stype>,shift<vector::dims,typename vector::stype>> & geo_cell,
+					 grid & gd)
+{
+	size_t cell = geo_cell.getCell(p);
+
+	for (size_t i = 0 ; i < geo_cell.getNelements(cell) ; i++)
+	{
+		size_t ns = geo_cell.get(cell,i);
+
+		if (gd.getDecomposition().getSubDomain(ns).isInside(p))
+			return ns;
+	}
+
+#ifdef SE_CLASS1
+	std::cerr << __FILE__ << ":" << __LINE__ << " Error: " << std::endl;
+	ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT)
+#endif
+
+	return (size_t)-1;
+}
+
+template<typename vector,typename kernel>
+struct inte_calc_impl
+{
+	//! Type of the calculations
+	typedef typename vector::stype arr_type;
+
+	template<unsigned int prp_g, unsigned int prp_v, unsigned int m2p_or_p2m, typename iterator, typename grid>
+																	 static inline void inte_calc(iterator & it,
+																	 vector & vd,
+																	 const Box<vector::dims,typename vector::stype> & domain,
+																	 int (& ip)[vector::dims][kernel::np],
+																	 grid & gd,
+																	 const typename vector::stype (& dx)[vector::dims],
+																	 typename vector::stype (& xp)[vector::dims],
+																	 typename vector::stype (& a_int)[openfpm::math::pow(vector::dims,kernel::np)],
+																	 typename vector::stype (& a)[vector::dims][kernel::np],
+																	 typename vector::stype (& x)[vector::dims][kernel::np],
+																	 size_t (& sz)[vector::dims],
+																	 const CellList<vector::dims,typename vector::stype,Mem_fast<vector::dims,typename vector::stype>,shift<vector::dims,typename vector::stype>> & geo_cell,
+																	 openfpm::vector<agg_arr<openfpm::math::pow(vector::dims,kernel::np),typename vector::stype>> & offsets)
+	{
+		auto key_p = it.get();
+
+		Point<vector::dims,typename vector::stype> p = vd.getPos(key_p);
+
+		// On which sub-domain we interpolate the particle
+		size_t sub = getSub<vector>(p,geo_cell,gd);
+
+		typename vector::stype x0[vector::dims];
+
+		// calculate the position of the particle in the grid
+		// coordinated
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			x0[i] = (p.get(i)-domain.getLow(i))*dx[i];
+
+		// convert into integer
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			ip[i][0] = (int)x0[i];
+
+		// convert the global grid position into local grid position
+		grid_key_dx<vector::dims> base;
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			base.set_d(i,ip[i][0] - gd.getLocalGridsInfo().get(sub).origin.get(i) - (long int)kernel::np/2 + 1);
+
+		// convenient grid of points
+
+		for (size_t j = 0 ; j < kernel::np-1 ; j++)
+		{
+			for (size_t i = 0 ; i < vector::dims ; i++)
+				ip[i][j+1] = (int)ip[i][j]+1;
+		}
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			xp[i] = x0[i] - ip[i][0];
+
+		for (long int j = 0 ; j < kernel::np ; j++)
+		{
+			for (size_t i = 0 ; i < vector::dims ; i++)
+				x[i][j] = - xp[i] + typename vector::stype((long int)j - (long int)kernel::np/2 + 1);
+		}
+
+		for (size_t j = 0 ; j < kernel::np ; j++)
+		{
+			for (size_t i = 0 ; i < vector::dims ; i++)
+				a[i][j] = kernel::value(x[i][j],j);
+		}
+
+		calculate_aint<vector::dims,vector,kernel::np>::value(sz,a_int,a);
+
+		grid_dist_lin_dx k_dist_lin;
+		k_dist_lin.setSub(sub);
+
+		size_t k = 0;
+		auto & gs_info = gd.get_loc_grid(sub).getGrid();
+
+		size_t lin_base = gs_info.LinId(base);
+
+		#pragma omp simd
+		for (size_t i = 0 ; i < openfpm::math::pow(vector::dims,kernel::np) ; i++)
+		{
+			size_t lin = offsets.get(sub).ele[k] + lin_base;
+			k_dist_lin.getKeyRef() = lin;
+
+			inte_template<kernel::np,prp_g,prp_v,m2p_or_p2m>::value(gd,vd,k_dist_lin,key_p,a_int,k);
+
+			k++;
+		}
+	}
+};
+
+/*! \brief Main class for interpolation Particle to mest p2m and Mesh to particle m2p
+ *
+ * This function is the main class to interpolate from particle to mesh and mesh to particle
+ *
+ * \tparam vector type of vector for interpolation
+ * \tparam grid type of grid for interpolation
+ * \tparam interpolation kernel
+ *
+ */
+template<typename vector,typename grid, typename kernel>
+class interpolate
+{
+	//! Cell list used to convert particles position to sub-domain
+	CellList<vector::dims,typename vector::stype,Mem_fast<vector::dims,typename vector::stype>,shift<vector::dims,typename vector::stype>> geo_cell;
+
+	/*! Structure to order boxes by volume
+	 *
+	 *
+	 *
+	 */
+	struct Box_vol
+	{
+		//! Box
+		Box<vector::dims,size_t> bv;
+
+		//! Calculated volume
+		size_t vol;
+
+		/*! \brief operator to reorder
+		 *
+		 * \param bv box to compare with
+		 *
+		 * \return true if bv has volume bigger volume
+		 *
+		 */
+		bool operator<(const Box_vol & bv)
+		{
+			return vol < bv.vol;
+		}
+	};
+
+	//! particles
+	vector & vd;
+
+	//! grid
+	grid & gd;
+
+	//! Type of the calculations
+	typedef typename vector::stype arr_type;
+
+	/*! \brief It calculate the interpolation stencil offsets
+	 *
+	 * \param array where to store offsets
+	 * \param sz kernel stencil points in each direction
+	 *
+	 */
+	void calculate_the_offsets(openfpm::vector<agg_arr<openfpm::math::pow(vector::dims,kernel::np),typename vector::stype>> & offsets, size_t (& sz)[vector::dims])
+	{
+		offsets.resize(gd.getN_loc_grid());
+
+		for (size_t i = 0 ; i < offsets.size() ; i++)
+		{
+			auto & loc_grid = gd.get_loc_grid(i);
+			const grid_sm<vector::dims,void> & gs = loc_grid.getGrid();
+
+			grid_sm<vector::dims,void> gs2(sz);
+			grid_key_dx_iterator<vector::dims> kit2(gs2);
+
+			size_t k = 0;
+
+			while (kit2.isNext())
+			{
+				auto key = kit2.get();
+
+				long int lin = gs.LinId(key);
+
+				offsets.get(i).ele[k] = lin;
+
+				++k;
+				++kit2;
+			}
+		}
+	}
+
+public:
+
+	/*! \brief construct an interpolation object between a grid and a vector
+	 *
+	 * When possible and easy to do we suggest to retain the object
+	 *
+	 * \param vd interpolation vector
+	 * \param gd interpolation grid
+	 *
+	 */
+	interpolate(vector & vd, grid & gd)
+	:vd(vd),gd(gd)
+	{
+		// get the processor bounding box in grid units
+		Box<vector::dims,typename vector::stype> bb = gd.getDecomposition().getProcessorBounds();
+		Box<vector::dims,typename vector::stype> bunit = gd.getDecomposition().getCellDecomposer().getCellBox();
+
+		size_t div[vector::dims];
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			div[i] = (bb.getHigh(i) - bb.getLow(i)) / bunit.getHigh(i);
+
+		geo_cell.Initialize(bb,div);
+
+		// Now draw the domain into the cell list
+
+		auto & dec = gd.getDecomposition();
+
+		for (size_t i = 0 ; i < dec.getNSubDomain() ; i++)
+		{
+			const Box<vector::dims,typename vector::stype> & bx = dec.getSubDomain(i);
+
+			// get the cells this box span
+			const grid_key_dx<vector::dims> p1 = geo_cell.getCellGrid(bx.getP1());
+			const grid_key_dx<vector::dims> p2 = geo_cell.getCellGrid(bx.getP2());
+
+			// Get the grid and the sub-iterator
+			auto & gi = geo_cell.getGrid();
+			grid_key_dx_iterator_sub<vector::dims> g_sub(gi,p1,p2);
+
+			// add the box-id to the cell list
+			while (g_sub.isNext())
+			{
+				auto key = g_sub.get();
+				geo_cell.addCell(gi.LinId(key),i);
+				++g_sub;
+			}
+		}
+	};
+
+	/*! \brief Interpolate particles to mesh
+	 *
+	 * Most of the time the particle set and the mesh are the same
+	 * as the one used in the constructor. They also can be different
+	 * as soon as they have the same decomposition
+	 *
+	 * \param gd grid or mesh
+	 * \param vd particle set
+	 *
+	 */
+	template<unsigned int prp_v, unsigned int prp_g> void p2m(vector & vd, grid & gd)
+	{
+#ifdef SE_CLASS1
+
+		if (!vd.getDecomposition().is_equal_ng(gd.getDecomposition()) )
+		{
+			std::cerr << __FILE__ << ":" << __LINE__ << " Error: the distribution of the vector of particles" <<
+					" and the grid is different. In order to interpolate the two data structure must have the" <<
+					" same decomposition" << std::endl;
+
+			ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT)
+		}
+
+#endif
+
+		Box<vector::dims,typename vector::stype> domain = vd.getDecomposition().getDomain();
+
+		// grid spacing
+		typename vector::stype dx[vector::dims];
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			dx[i] = 1.0/gd.spacing(i);
+
+		size_t sz[vector::dims];
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			sz[i] = kernel::np;
+
+		// Precalculate the offset for each sub-sub-domain
+		openfpm::vector<agg_arr<openfpm::math::pow(vector::dims,kernel::np),typename vector::stype>> offsets;
+
+		calculate_the_offsets(offsets,sz);
+
+		// point position
+		typename vector::stype xp[vector::dims];
+
+		int ip[vector::dims][kernel::np];
+		typename vector::stype x[vector::dims][kernel::np];
+		typename vector::stype a[vector::dims][kernel::np];
+
+//		grid_cpu<vector::dims,aggregate<typename vector::stype>> a_int(sz);
+//		a_int.setMemory();
+		typename vector::stype a_int[openfpm::math::pow(vector::dims,kernel::np)];
+
+		auto it = vd.getDomainIterator();
+
+		while (it.isNext() == true)
+		{
+			inte_calc_impl<vector,kernel>::template inte_calc<prp_g,prp_v,inte_p2m>(it,vd,domain,ip,gd,dx,xp,a_int,a,x,sz,geo_cell,offsets);
+
+			++it;
+		}
+	}
+
+	/*! \brief Interpolate mesh to particle
+	 *
+	 * Most of the time the particle set and the mesh are the same
+	 * as the one used in the constructor. They also can be different
+	 * as soon as they have the same decomposition
+	 *
+	 * \param gd grid or mesh
+	 * \param vd particle set
+	 *
+	 */
+	template<unsigned int prp_g, unsigned int prp_v> void m2p(grid & gd, vector & vd)
+	{
+#ifdef SE_CLASS1
+
+		if (!vd.getDecomposition().is_equal_ng(gd.getDecomposition()) )
+		{
+			std::cerr << __FILE__ << ":" << __LINE__ << " Error: the distribution of the vector of particles" <<
+					" and the grid is different. In order to interpolate the two data structure must have the" <<
+					" same decomposition" << std::endl;
+
+			ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT)
+		}
+
+#endif
+
+		Box<vector::dims,typename vector::stype> domain = vd.getDecomposition().getDomain();
+
+		// grid spacing
+		typename vector::stype dx[vector::dims];
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			dx[i] = 1.0/gd.spacing(i);
+
+		// point position
+		typename vector::stype xp[vector::dims];
+
+		int ip[vector::dims][kernel::np];
+		typename vector::stype x[vector::dims][kernel::np];
+		typename vector::stype a[vector::dims][kernel::np];
+
+		size_t sz[vector::dims];
+
+		for (size_t i = 0 ; i < vector::dims ; i++)
+			sz[i] = kernel::np;
+
+		// Precalculate the offset for each sub-sub-domain
+		openfpm::vector<agg_arr<openfpm::math::pow(vector::dims,kernel::np),typename vector::stype>> offsets;
+
+		calculate_the_offsets(offsets,sz);
+
+		//		grid_cpu<vector::dims,aggregate<typename vector::stype>> a_int(sz);
+		//		a_int.setMemory();
+		typename vector::stype a_int[openfpm::math::pow(vector::dims,kernel::np)];
+
+		auto it = vd.getDomainIterator();
+
+		while (it.isNext() == true)
+		{
+			inte_calc_impl<vector,kernel>::template inte_calc<prp_g,prp_v,inte_m2p>(it,vd,domain,ip,gd,dx,xp,a_int,a,x,sz,geo_cell,offsets);
+
+			++it;
+		}
+	}
+
+};
+
+#endif /* OPENFPM_NUMERICS_SRC_INTERPOLATION_INTERPOLATION_HPP_ */
-- 
GitLab