From 3b4db8aed0cf77020e0182908daf1de958a3315a Mon Sep 17 00:00:00 2001
From: Pietro Incardona <incardon@mpi-cbg.de>
Date: Sat, 17 Jun 2017 12:46:39 +0200
Subject: [PATCH] Adding CG for Vortrx in Cell

---
 example/Numerics/Vortex_in_cell/CG.hpp        | 173 ++++++++++++++++++
 .../Vortex_in_cell/main_vic_petsc.cpp         |  77 +++++++-
 src/Grid/grid_dist_id.hpp                     |  19 ++
 3 files changed, 268 insertions(+), 1 deletion(-)
 create mode 100644 example/Numerics/Vortex_in_cell/CG.hpp

diff --git a/example/Numerics/Vortex_in_cell/CG.hpp b/example/Numerics/Vortex_in_cell/CG.hpp
new file mode 100644
index 000000000..98eedd529
--- /dev/null
+++ b/example/Numerics/Vortex_in_cell/CG.hpp
@@ -0,0 +1,173 @@
+/*
+ * CG.hpp
+ *
+ *  Created on: Jun 16, 2017
+ *      Author: i-bird
+ */
+
+#ifndef EXAMPLE_NUMERICS_VORTEX_IN_CELL_CG_HPP_
+#define EXAMPLE_NUMERICS_VORTEX_IN_CELL_CG_HPP_
+
+typedef grid_dist_id<3,float,aggregate<float>> grid_type_scal;
+
+float norm(grid_type_scal & scl)
+{
+	double nrm = 0.0;
+
+	Vcluster & v_cl = create_vcluster();
+
+	auto it = scl.getDomainIterator();
+
+	while (it.isNext())
+	{
+		auto p = it.get();
+
+		nrm += scl.template getProp<0>(p)*scl.template getProp<0>(p);
+
+		++it;
+	}
+
+	v_cl.sum(nrm);
+	v_cl.execute();
+
+	return nrm;
+}
+
+void copy(grid_type_scal & src, grid_type_scal & dst)
+{
+	auto it = src.getDomainIterator();
+
+	while (it.isNext())
+	{
+		auto key = it.get();
+
+		dst.getProp<0>(key) = src.getProp<0>(key);
+
+		++it;
+	}
+}
+
+
+void x_plus_alpha_p(grid_type_scal & x, grid_type_scal & p, float alpha)
+{
+	auto it = x.getDomainIterator();
+
+	while (it.isNext())
+	{
+		auto key = it.get();
+
+		x.getProp<0>(key) = x.getProp<0>(key) + alpha * p.getProp<0>(key);
+
+		++it;
+	}
+}
+
+void x_plus_alpha_p(grid_type_scal & xn, grid_type_scal & x, grid_type_scal & p, float alpha)
+{
+	auto it = x.getDomainIterator();
+
+	while (it.isNext())
+	{
+		auto key = it.get();
+
+		xn.getProp<0>(key) = x.getProp<0>(key) + alpha * p.getProp<0>(key);
+
+		++it;
+	}
+}
+
+float alpha(void (* A)(grid_type_scal & in, grid_type_scal & out),
+		   grid_type_scal & r,
+		   grid_type_scal & p,
+		   grid_type_scal & Ap)
+{
+	auto it = r.getDomainIterator();
+	double scal_r = 0.0;
+	double scal_pAp = 0.0;
+
+	A(p,Ap);
+
+	while (it.isNext())
+	{
+		auto key = it.get();
+
+		scal_r += r.template getProp<0>(key)*r.template getProp<0>(key);
+		scal_pAp += p.template getProp<0>(key)*Ap.template getProp<0>(key);
+
+
+		++it;
+	}
+
+	Vcluster & v_cl = create_vcluster();
+	v_cl.sum(scal_r);
+	v_cl.sum(scal_pAp);
+	v_cl.execute();
+
+	return scal_r / scal_pAp;
+}
+
+float beta(grid_type_scal & r,
+		   grid_type_scal & rn)
+{
+	auto it = r.getDomainIterator();
+	double scal_r = 0.0;
+	double scal_rn = 0.0;
+
+	while (it.isNext())
+	{
+		auto key = it.get();
+
+		scal_r += r.template getProp<0>(key)*r.template getProp<0>(key);
+		scal_rn += rn.template getProp<0>(key)*rn.template getProp<0>(key);
+
+		++it;
+	}
+
+	Vcluster & v_cl = create_vcluster();
+	v_cl.sum(scal_r);
+	v_cl.sum(scal_rn);
+	v_cl.execute();
+
+	return scal_rn / scal_r;
+}
+
+void CG(void (* A)(grid_type_scal & in, grid_type_scal & out), grid_type_scal & x, grid_type_scal & b)
+{
+	grid_type_scal tmp(b.getDecomposition(),b.getGridInfo().getSize(),b.getDecomposition().getGhost());
+	grid_type_scal r(b.getDecomposition(),b.getGridInfo().getSize(),b.getDecomposition().getGhost());
+	grid_type_scal rn(b.getDecomposition(),b.getGridInfo().getSize(),b.getDecomposition().getGhost());
+	grid_type_scal p(b.getDecomposition(),b.getGridInfo().getSize(),b.getDecomposition().getGhost());
+	grid_type_scal Ap(b.getDecomposition(),b.getGridInfo().getSize(),b.getDecomposition().getGhost());
+
+
+	// r_0 = b - Ax
+	copy(b,r);
+	A(x,Ap);
+	x_plus_alpha_p(r,Ap,-1);
+
+	// r0 = p0
+	copy(r,p);
+
+	for (size_t i = 0 ; i < 400 ; i++)
+	{
+		float alpha_c = alpha(A,r,p,Ap);
+
+		x_plus_alpha_p(x,p,alpha_c);
+		x_plus_alpha_p(rn,r,Ap,-alpha_c);
+
+		float r_norm = norm(rn);
+
+		std::cout << "It: " << i << "  " << r_norm << std::endl;
+
+		if (r_norm < 0.1)
+			return;
+
+		float beta_c = beta(r,rn);
+		x_plus_alpha_p(p,rn,p,beta_c);
+		copy(rn,r);
+	}
+}
+
+
+
+#endif /* EXAMPLE_NUMERICS_VORTEX_IN_CELL_CG_HPP_ */
diff --git a/example/Numerics/Vortex_in_cell/main_vic_petsc.cpp b/example/Numerics/Vortex_in_cell/main_vic_petsc.cpp
index 495ab6cf4..0179103a0 100644
--- a/example/Numerics/Vortex_in_cell/main_vic_petsc.cpp
+++ b/example/Numerics/Vortex_in_cell/main_vic_petsc.cpp
@@ -115,6 +115,8 @@ typedef grid_dist_id<3,float,aggregate<float[3]>> grid_type;
 // The type of the particles
 typedef vector_dist<3,float,aggregate<float[3],float[3],float[3],float[3],float[3]>> particles_type;
 
+#include "CG.hpp"
+
 // radius of the torus
 float ringr1 = 5.0/4.0;
 // radius of the core of the torus
@@ -300,6 +302,29 @@ const bool poisson_nn_helm::boundary[] = {PERIODIC,PERIODIC,PERIODIC};
 
 //! \cond [poisson_syseq] \endcond
 
+void OpA(grid_type_scal & in, grid_type_scal & out)
+{
+	float fac1 = 0.25f/(in.spacing(0)*in.spacing(0));
+	float fac2 = 0.25f/(in.spacing(1)*in.spacing(1));
+	float fac3 = 0.25f/(in.spacing(2)*in.spacing(2));
+
+	in.ghost_get<0>();
+
+	auto it = in.getDomainIterator();
+
+
+	while (it.isNext())
+	{
+		auto p = it.get();
+
+		out.template getProp<0>(p) = fac1*(in.template get<0>(p.move(x,2))+in.template get<0>(p.move(x,-2)))+
+                fac2*(in.template get<0>(p.move(y,2))+in.template get<0>(p.move(y,-2)))+
+				  fac3*(in.template get<0>(p.move(z,2))+in.template get<0>(p.move(z,-2)))-
+				  2.0f*(fac1+fac2+fac3)*in.template get<0>(p);
+
+		++it;
+	}
+}
 
 /*! \page Vortex_in_cell_petsc Vortex in Cell 3D
  *
@@ -499,6 +524,26 @@ void helmotz_hodge_projection(grid_type & gr, const Box<3,float> & domain)
 	// Give to the solver A and b, return x, the solution
 	auto x_ = solver.solve(fd.getA(),fd.getB());
 
+	//////////////// CG Call //////////////////////////
+
+	// Here we create a distributed grid to store the result of the helmotz projection
+	grid_dist_id<3,float,aggregate<float>> sol(gr.getDecomposition(),gr.getGridInfo().getSize(),g);
+
+	auto zit = sol.getDomainIterator();
+
+	while (zit.isNext())
+	{
+		auto p = zit.get();
+
+		sol.template getProp<0>(p) = 0.0;
+
+		++zit;
+	}
+
+	CG(OpA,sol,psi);
+
+	///////////////////////////////////////////////////
+
 	// copy the solution x to the grid psi
 	fd.template copy<phi>(x_,psi);
 
@@ -697,8 +742,9 @@ void comp_vel(Box<3,float> & domain, grid_type & g_vort,grid_type & g_vel, petsc
 		petsc_solver<double> solver;
 
 		solver.setSolver(KSPCG);
-		solver.setAbsTol(0.001);
+		solver.setAbsTol(0.1);
 		solver.setMaxIter(500);
+		solver.log_monitor();
 
 		// Get the sparse matrix that represent the left-hand-side
 		// of the equation
@@ -712,6 +758,26 @@ void comp_vel(Box<3,float> & domain, grid_type & g_vort,grid_type & g_vel, petsc
 		// time step
 		solver.solve(A,phi_s[i],b);
 
+		//////////////// CG Call //////////////////////////
+
+		// Here we create a distributed grid to store the result of the helmotz projection
+		grid_dist_id<3,float,aggregate<float>> sol(gr_ps.getDecomposition(),gr_ps.getGridInfo().getSize(),g);
+
+		auto zit = sol.getDomainIterator();
+
+		while (zit.isNext())
+		{
+			auto p = zit.get();
+
+			sol.template getProp<0>(p) = 0.0;
+
+			++zit;
+		}
+
+		CG(OpA,sol,gr_ps);
+
+		///////////////////////////////////////////////////
+
 		// Calculate the residual
 
 		solError serr;
@@ -724,6 +790,13 @@ void comp_vel(Box<3,float> & domain, grid_type & g_vort,grid_type & g_vel, petsc
 		// copy the solution to grid
 		fd.template copy<phi>(phi_s[i],gr_ps);
 
+		/////////////// DEBUG ///////////////
+
+		gr_ps.write("Solution_petsc_" + std::to_string(i));
+		sol.write("Solution_my_" + std::to_string(i));
+
+		/////////////////////////////////////
+
 		//! \cond [solve_poisson_comp] \endcond
 
 		//! \cond [copy_to_phi_v] \endcond
@@ -743,6 +816,8 @@ void comp_vel(Box<3,float> & domain, grid_type & g_vort,grid_type & g_vel, petsc
 		//! \cond [copy_to_phi_v] \endcond
 	}
 
+	exit(0);
+
 	//! \cond [curl_phi_v] \endcond
 
 	phi_v.ghost_get<phi>();
diff --git a/src/Grid/grid_dist_id.hpp b/src/Grid/grid_dist_id.hpp
index 461a3bb1c..10bbdecef 100644
--- a/src/Grid/grid_dist_id.hpp
+++ b/src/Grid/grid_dist_id.hpp
@@ -959,6 +959,25 @@ public:
 		return total;
 	}
 
+	/*! \brief Get the size of local domain grids
+	 *
+	 * \return The size of the local domain
+	 *
+	 */
+	size_t getLocalDomainWithGhostSize() const
+	{
+#ifdef SE_CLASS2
+		check_valid(this,8);
+#endif
+		size_t total = 0;
+
+		for (size_t i = 0 ; i < gdb_ext.size() ; i++)
+		{
+			total += gdb_ext.get(i).GDbox.getVolumeKey();
+		}
+
+		return total;
+	}
 
 
 	/*! \brief It return the informations about the local grids
-- 
GitLab