From 6bcf7186666a48b6519a45263815e843e24adc6b Mon Sep 17 00:00:00 2001
From: Pietro Incardona <incardon@mpi-cbg.de>
Date: Mon, 19 Sep 2016 01:47:30 +0200
Subject: [PATCH] Complex properties with serialization completed

---
 example/Vector/4_complex_prop/Makefile |  10 +-
 example/Vector/4_complex_prop/main.cpp | 122 ++++++++++++++++++++-----
 openfpm_data                           |   2 +-
 openfpm_pdata.doc                      |   2 +-
 src/Vector/vector_dist_comm.hpp        | 122 ++++++++++++++++---------
 src/Vector/vector_dist_unit_test.hpp   |   1 +
 6 files changed, 186 insertions(+), 73 deletions(-)

diff --git a/example/Vector/4_complex_prop/Makefile b/example/Vector/4_complex_prop/Makefile
index 646357e95..93fc158bd 100644
--- a/example/Vector/4_complex_prop/Makefile
+++ b/example/Vector/4_complex_prop/Makefile
@@ -5,17 +5,21 @@ CC=mpic++
 LDIR =
 
 OBJ = main.o
+OBJ_SER = main_ser.o
 
 %.o: %.cpp
 	$(CC) -O3 -c --std=c++11 -o $@ $< $(INCLUDE_PATH)
 
-vect: $(OBJ)
+vect_cp: $(OBJ)
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS)
 
-all: vect
+vect_ser: $(OBJ_SER)
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS)
+
+all: vect_cp vect_ser
 
 run: all
-	source $$HOME/openfpm_vars; mpirun -np 2 ./vect
+	source $$HOME/openfpm_vars && mpirun -np 2 ./vect_cp && mpirun -np 2 ./vect_ser
 
 .PHONY: clean all run
 
diff --git a/example/Vector/4_complex_prop/main.cpp b/example/Vector/4_complex_prop/main.cpp
index 915f2868e..028b2b33f 100644
--- a/example/Vector/4_complex_prop/main.cpp
+++ b/example/Vector/4_complex_prop/main.cpp
@@ -1,12 +1,19 @@
+/*! \page Vector_4_cp Vector 4 complex properties and serialization
+ *
+ * \subpage Vector_4_complex_prop
+ * \subpage Vector_4_complex_prop_ser
+ *
+ */
+
 /*!
  *
- * \page Vector_4_complex_prop Vector 4 complex property
+ * \page Vector_4_complex_prop Vector 4 complex properties
  *
  *
  * [TOC]
  *
  *
- * # Vector 4 complex property # {#vector_example_cp}
+ * # Vector 4 complex properties # {#vector_example_cp}
  *
  *
  * This example show how we can use complex properties in a vector
@@ -19,7 +26,7 @@ int main(int argc, char* argv[])
 {
 	/*!
 	 *
-	 * \page Vector_4_complex_prop Vector 4 complex property
+	 * \page Vector_4_complex_prop Vector 4 complex properties
 	 *
 	 *
 	 * ## Initialization and vector creation ##
@@ -29,13 +36,36 @@ int main(int argc, char* argv[])
 	 *
 	 * \snippet Vector/4_complex_prop/main.cpp vect create
 	 *
-	 * In This this particular case every particle carry a scalar,
+	 * In this this particular case every particle carry a scalar,
 	 * a vector in form of float[3], a Point, a list
-	 * in form of vector of float and a list of custom structures
+	 * in form of vector of float and a list of custom structures, and a vector of vector.
+	 * In general particles can have properties of arbitrary complexity.
+	 *
+	 * \warning For arbitrary complexity mean that we can use any openfpm data structure with and arbitrary nested complexity.
+	 *          For example a openfpm::vector<aggregate<grid_cpu<openfpm::vector<aggregate<double,double[3]>>>,openfpm::vector<float>> is valid
+	 * \verbatim
+
+	       particle
+	          *
+	        vector
+	         / \
+	        /   \
+	     grid    vector<float>
+	      /\
+	     /  \
+	double  double[3]
+
+	 * \endverbatim
+	 *
+	 * Our custom data-structure A is defined below. Note that this data-structure
+	 * does not have pointers
 	 *
 	 * \snippet Vector/4_complex_prop/main.cpp struct A
 	 *
 	 *
+	 * \warning custom data structure are allowed only if they does not have pointer.
+	 *          In case they have pointer we have to define how to serialize our data-structure
+	 *
 	 */
 
     // initialize the library
@@ -82,20 +112,24 @@ int main(int argc, char* argv[])
 	// A listA
 	constexpr int listA = 4;
 
+	// A list of list
+	constexpr int listlist = 5;
+
 	//! \cond [vect create] \endcond
 
 	vector_dist<2,float, aggregate<float,
 	                               float[3],
 								   Point<3,double>,
 								   openfpm::vector<float>,
-	                               openfpm::vector<A>>>
+	                               openfpm::vector<A>,
+								   openfpm::vector<openfpm::vector<float>>> >
 	vd(4096,domain,bc,g);
 
 	//! \cond [vect create] \endcond
 
 	/*!
 	 *
-	 * \page Vector_4_complex_prop Vector 4 complex property
+	 * \page Vector_4_complex_prop Vector 4 complex properties
 	 *
 	 *
 	 * ## Assign values to properties ##
@@ -135,7 +169,7 @@ int main(int argc, char* argv[])
 		vd.getProp<point>(p).get(1) = 1.0;
 		vd.getProp<point>(p).get(2) = 1.0;
 
-		size_t n_cp = (float)10 * rand()/RAND_MAX;
+		size_t n_cp = (float)10.0 * rand()/RAND_MAX;
 
 		vd.getProp<listA>(p).resize(n_cp);
 
@@ -146,10 +180,17 @@ int main(int argc, char* argv[])
 			vd.getProp<list>(p).add(i + 30);
 
 			vd.getProp<listA>(p).get(i) = A(i+10.0,i+20.0);
-			vd.getProp<listA>(p).get(i) = A(i+30.0,i+40.0);
-			vd.getProp<listA>(p).get(i) = A(i+50.0,i+60.0);
 		}
 
+		vd.getProp<listlist>(p).resize(2);
+		vd.getProp<listlist>(p).get(0).resize(2);
+		vd.getProp<listlist>(p).get(1).resize(2);
+
+		vd.getProp<listlist>(p).get(0).get(0) = 1.0;
+		vd.getProp<listlist>(p).get(0).get(1) = 2.0;
+		vd.getProp<listlist>(p).get(1).get(0) = 3.0;
+		vd.getProp<listlist>(p).get(1).get(1) = 4.0;
+
 		// next particle
 		++it;
 	}
@@ -158,19 +199,15 @@ int main(int argc, char* argv[])
 
 	/*!
 	 *
-	 * \page Vector_4_complex_prop Vector 4 complex property
+	 * \page Vector_4_complex_prop Vector 4 complex properties
 	 *
 	 *
 	 * ## Mapping and ghost_get ##
 	 *
-	 * Particles are redistributed across processors but only the scalar,vector and the point
-	 * are communicated (properties 0,1,2). A lot of time complex properties can be recomputed and
-	 * communicate them is not a good idea. The same concept also apply for ghost_get
-	 *
-	 * \note OpenFPM <= 0.5.0 cannot communicate complex properties like a vector or other structure
-	 *                        that are not POD object
-	 *
-	 * \note OpenFPM > 0.5.0 Does not have such limitation
+	 * Particles are redistributed across processors all properties are communicated but instead of
+	 * using map we use map_list that we can use to select properties.
+	 * A lot of time complex properties can be recomputed and communicate them is not a good idea.
+	 * The same concept also apply for ghost_get. In general we choose which properties to communicate
 	 *
 	 *
 	 * \snippet Vector/4_complex_prop/main.cpp vect map ghost
@@ -181,16 +218,16 @@ int main(int argc, char* argv[])
 
 	// Particles are redistribued across the processors but only the scalar,vector, and point properties
 	// are transfert
-	vd.map_list<scalar,vector,point>();
+	vd.map_list<scalar,vector,point,list,listA,listlist>();
 	
 	// Synchronize the ghost
-	vd.ghost_get<scalar,vector,point>();
+	vd.ghost_get<scalar,vector,point,listA,listlist>();
 
 	//! \cond [vect map ghost] \endcond
 
 	/*!
 	 *
-	 * \page Vector_4_complex_prop Vector 4 complex property
+	 * \page Vector_4_complex_prop Vector 4 complex properties
 	 *
 	 *
 	 * ## Output and VTK visualization ##
@@ -209,7 +246,44 @@ int main(int argc, char* argv[])
 	//! \cond [vtk] \endcond
 
 	/*!
-	 * \page Vector_4_complex_prop Vector 4 complex property
+	 *
+	 * \page Vector_4_complex_prop Vector 4 complex properties
+	 *
+	 * ## Print 4 particles in the ghost area ##
+	 *
+	 * Here we print that the first 4 particles to show that the list of A and the list of list are filled
+	 * and the ghosts contain the correct information
+	 *
+	 * \snippet Vector/4_complex_prop/main.cpp print ghost info
+	 *
+	 */
+
+	//! \cond [print ghost info] \endcond
+
+	size_t fg = vd.size_local();
+
+	Vcluster & v_cl = create_vcluster();
+	if (v_cl.getProcessUnitID() == 0)
+	{
+		for ( ; fg < vd.size_local()+4 ; fg++)
+		{
+			std::cout << "List of A" << std::endl;
+			for (size_t i = 0 ; i < vd.getProp<listA>(fg).size() ; i++)
+				std::cout << "Element: " << i << "   p1=" << vd.getProp<listA>(fg).get(i).p1 << "   p2=" << vd.getProp<listA>(fg).get(i).p2 << std::endl;
+
+			std::cout << "List of list" << std::endl;
+			for (size_t i = 0 ; i < vd.getProp<listlist>(fg).size() ; i++)
+			{
+				for (size_t j = 0 ; j < vd.getProp<listlist>(fg).get(i).size() ; j++)
+					std::cout << "Element: " << i << "  " << j << "   " << vd.getProp<listlist>(fg).get(i).get(j) << std::endl;
+			}
+		}
+	}
+
+	//! \cond [print ghost info] \endcond
+
+	/*!
+	 * \page Vector_4_complex_prop Vector 4 complex properties
 	 *
 	 * ## Finalize ## {#finalize}
 	 *
@@ -226,7 +300,7 @@ int main(int argc, char* argv[])
 	//! \cond [finalize] \endcond
 
 	/*!
-	 * \page Vector_4_complex_prop Vector 4 complex property
+	 * \page Vector_4_complex_prop Vector 4 complex properties
 	 *
 	 * # Full code # {#code}
 	 *
diff --git a/openfpm_data b/openfpm_data
index dbfc39c70..f378ee11c 160000
--- a/openfpm_data
+++ b/openfpm_data
@@ -1 +1 @@
-Subproject commit dbfc39c70904fa40ac52d71e784cd6f54283f578
+Subproject commit f378ee11c3aa2be8d0fde9fe5308d86d1d705aa7
diff --git a/openfpm_pdata.doc b/openfpm_pdata.doc
index b16dc1c02..94101cdb7 100644
--- a/openfpm_pdata.doc
+++ b/openfpm_pdata.doc
@@ -38,7 +38,7 @@ PROJECT_NAME           = "OpenFPM_pdata"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.5.0
+PROJECT_NUMBER         = 0.5.1
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/src/Vector/vector_dist_comm.hpp b/src/Vector/vector_dist_comm.hpp
index 9f45b1c49..a22e80561 100644
--- a/src/Vector/vector_dist_comm.hpp
+++ b/src/Vector/vector_dist_comm.hpp
@@ -84,6 +84,67 @@ class vector_dist_comm
 	//! replicated ghost particles that are local
 	size_t lg_m;
 
+	//! process the particle with properties
+	struct proc_without_prp
+	{
+		template<typename T1, typename T2> inline static void proc(size_t lbl, size_t cnt, size_t id, T1 & v_prp, T2 & m_prp)
+		{
+			m_prp.get(lbl).set(cnt, v_prp.get(id));
+		}
+	};
+
+	template<typename prp_object, int ... prp>
+	struct proc_with_prp
+	{
+		template<typename T1, typename T2> inline static void proc(size_t lbl, size_t cnt, size_t id, T1 & v_prp, T2 & m_prp)
+		{
+			// source object type
+			typedef encapc<1, prop, typename openfpm::vector<prop>::layout_type> encap_src;
+			// destination object type
+			typedef encapc<1, prp_object, typename openfpm::vector<prp_object>::layout_type> encap_dst;
+
+			// Copy only the selected properties
+			object_si_d<encap_src, encap_dst, OBJ_ENCAP, prp...>(v_prp.get(id), m_prp.get(lbl).get(cnt));
+		}
+	};
+
+	//! It process one particle
+	template<typename proc_class, typename T1, typename T2, typename T3, typename T4> inline void process_map_particle(size_t i, long int & end, long int & id_end, T1 & m_pos, T2 & m_prp, T3 & v_pos, T4 & v_prp, openfpm::vector<size_t> & cnt)
+	{
+		long int prc_id = m_opart.template get<2>(i);
+		size_t id = m_opart.template get<0>(i);
+
+		if (prc_id >= 0)
+		{
+			size_t lbl = p_map_req.get(prc_id);
+
+			m_pos.get(lbl).set(cnt.get(lbl), v_pos.get(id));
+			proc_class::proc(lbl,cnt.get(lbl),id,v_prp,m_prp);
+
+			cnt.get(lbl)++;
+
+			// swap the particle
+			long int id_valid = get_end_valid(end,id_end);
+
+			if (id_valid > 0 && (long int)id < id_valid)
+			{
+				v_pos.set(id,v_pos.get(id_valid));
+				v_prp.set(id,v_prp.get(id_valid));
+			}
+		}
+		else
+		{
+			// swap the particle
+			long int id_valid = get_end_valid(end,id_end);
+
+			if (id_valid > 0 && (long int)id < id_valid)
+			{
+				v_pos.set(id,v_pos.get(id_valid));
+				v_prp.set(id,v_prp.get(id_valid));
+			}
+		}
+	}
+
 	/*! \brief Return a valid particle starting from end and tracing back
 	 *
 	 * \param end actual opart particle pointer
@@ -492,21 +553,7 @@ class vector_dist_comm
 		// Run through all the particles and fill the sending buffer
 		for (size_t i = 0; i < m_opart.size(); i++)
 		{
-			size_t lbl = p_map_req.get(m_opart.template get<2>(i));
-			size_t id = m_opart.template get<0>(i);
-
-			m_pos.get(lbl).set(cnt.get(lbl), v_pos.get(id));
-			m_prp.get(lbl).set(cnt.get(lbl), v_prp.get(id));
-			cnt.get(lbl)++;
-
-			// swap the particle
-			long int id_valid = get_end_valid(end,id_end);
-
-			if (id_valid > 0 && (long int)id < id_valid)
-			{
-				v_pos.set(id,v_pos.get(id_valid));
-				v_prp.set(id,v_prp.get(id_valid));
-			}
+			process_map_particle<proc_without_prp>(i,end,id_end,m_pos,m_prp,v_pos,v_prp,cnt);
 		}
 
 		v_pos.resize(v_pos.size() - m_opart.size());
@@ -523,17 +570,18 @@ class vector_dist_comm
 	 * \param pb send buffer
 	 *
 	 */
-	template<typename prp_object,int ... prp> void fill_send_map_buf_list(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & prc_r, openfpm::vector<size_t> & prc_sz_r, openfpm::vector<openfpm::vector<Point<dim,St>>> & m_pos, openfpm::vector<openfpm::vector<prp_object>> & m_prp)
+	template<typename prp_object,int ... prp> void fill_send_map_buf_list(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & prc_sz_r, openfpm::vector<openfpm::vector<Point<dim,St>>> & m_pos, openfpm::vector<openfpm::vector<prp_object>> & m_prp)
 	{
-		m_prp.resize(v_cl.getProcessingUnits());
-		m_pos.resize(v_cl.getProcessingUnits());
-		openfpm::vector<size_t> cnt(v_cl.getProcessingUnits());
+		m_prp.resize(prc_sz_r.size());
+		m_pos.resize(prc_sz_r.size());
+		openfpm::vector<size_t> cnt(prc_sz_r.size());
 
-		for (size_t i = 0; i < prc_r.size(); i++)
+		for (size_t i = 0; i < prc_sz_r.size(); i++)
 		{
 			// set the size and allocate, using mem warant that pos and prp is contiguous
 			m_pos.get(i).resize(prc_sz_r.get(i));
 			m_prp.get(i).resize(prc_sz_r.get(i));
+			cnt.get(i) = 0;
 		}
 
 		// end vector point
@@ -545,31 +593,11 @@ class vector_dist_comm
 		// Run through all the particles and fill the sending buffer
 		for (size_t i = 0; i < m_opart.size(); i++)
 		{
-			size_t lbl = m_opart.template get<2>(i);
-			size_t id = m_opart.template get<0>(i);
-
-			m_pos.get(lbl).set(cnt.get(lbl), v_pos.get(id));
-
-			// source object type
-			typedef encapc<1, prop, typename openfpm::vector<prop>::layout_type> encap_src;
-			// destination object type
-			typedef encapc<1, prp_object, typename openfpm::vector<prp_object>::layout_type> encap_dst;
-
-			// Copy only the selected properties
-			object_si_d<encap_src, encap_dst, OBJ_ENCAP, prp...>(v_prp.get(id), m_prp.get(lbl).get(cnt.get(lbl)));
-
-			cnt.get(lbl)++;
-
-			// swap the particle
-			long int id_valid = get_end_valid(end,id_end);
-
-			if (id_valid > 0 && (long int)id < id_valid)
-			{
-				v_pos.set(id,v_pos.get(id_valid));
-				v_prp.set(id,v_prp.get(id_valid));
-			}
+			process_map_particle<proc_with_prp<prp_object,prp...>>(i,end,id_end,m_pos,m_prp,v_pos,v_prp,cnt);
 		}
 
+		v_pos.resize(v_pos.size() - m_opart.size());
+		v_prp.resize(v_prp.size() - m_opart.size());
 	}
 
 	/*! \brief Label particles for mappings
@@ -616,6 +644,12 @@ class vector_dist_comm
 					lbl_p.last().template get<0>() = key;
 					lbl_p.last().template get<2>() = p_id;
 				}
+				else
+				{
+					lbl_p.add();
+					lbl_p.last().template get<0>() = key;
+					lbl_p.last().template get<2>() = p_id;
+				}
 			}
 
 			// Add processors and add size
@@ -930,7 +964,7 @@ public:
 		//! properties vector
 		openfpm::vector<openfpm::vector<prp_object>> m_prp;
 
-		fill_send_map_buf_list<prp_object,prp...>(v_pos,v_prp,prc_r, prc_sz_r, m_pos, m_prp);
+		fill_send_map_buf_list<prp_object,prp...>(v_pos,v_prp,prc_sz_r, m_pos, m_prp);
 
 		v_cl.SSendRecv(m_pos,v_pos,prc_r,prc_recv_map,recv_sz_map);
 		v_cl.SSendRecvP<openfpm::vector<prp_object>,decltype(v_prp),prp...>(m_prp,v_prp,prc_r,prc_recv_map,recv_sz_map);
diff --git a/src/Vector/vector_dist_unit_test.hpp b/src/Vector/vector_dist_unit_test.hpp
index 413bf7aac..a4ef53344 100644
--- a/src/Vector/vector_dist_unit_test.hpp
+++ b/src/Vector/vector_dist_unit_test.hpp
@@ -1773,6 +1773,7 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put )
 
 #include "vector_dist_cell_list_tests.hpp"
 #include "vector_dist_NN_tests.hpp"
+#include "vector_dist_complex_prp_unit_test.hpp"
 
 BOOST_AUTO_TEST_SUITE_END()
 
-- 
GitLab