← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 3028: - TWrapper: python binding for local deformations

 

------------------------------------------------------------
revno: 3028
committer: Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
branch nick: trunk
timestamp: Tue 2012-02-14 17:58:21 +0100
message:
  - TWrapper: python binding for local deformations
  - Flow: fixes in the periodic BCs
  - Flow: improvements in BCs handling and imposed fluxes, toward per-step update of the RHS + code cleaning
  - Periodic flow: support for optimized solvers (not in trunk) by introducing cells indexes
  - Periodic flow: optimization of periodicity by precomputed Hsize[k]*gradP products
  - SpherePack: more code documentation in makeCloud
modified:
  lib/triangulation/FlowBoundingSphere.cpp
  lib/triangulation/FlowBoundingSphere.hpp
  lib/triangulation/FlowBoundingSphere.ipp
  lib/triangulation/Network.hpp
  lib/triangulation/PeriodicFlow.cpp
  lib/triangulation/PeriodicFlow.hpp
  lib/triangulation/Tesselation.ipp
  lib/triangulation/TriaxialState.h
  lib/triangulation/def_types.h
  pkg/dem/FlowEngine.cpp
  pkg/dem/FlowEngine.hpp
  pkg/dem/SpherePack.cpp
  pkg/dem/TesselationWrapper.cpp
  pkg/dem/TesselationWrapper.hpp


--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription
=== modified file 'lib/triangulation/FlowBoundingSphere.cpp'
--- lib/triangulation/FlowBoundingSphere.cpp	2012-01-24 17:14:09 +0000
+++ lib/triangulation/FlowBoundingSphere.cpp	2012-02-14 16:58:21 +0000
@@ -11,13 +11,15 @@
 namespace CGT {
 Vecteur PeriodicCellInfo::gradP;
 Vecteur PeriodicCellInfo::hSize[3];
+Vecteur PeriodicCellInfo::deltaP;
 }
 
+
 //Forcing instanciation of the template to avoid linkage problems 
 typedef CGT::FlowBoundingSphere<FlowTesselation> FlowBoundingSphere;
 FlowBoundingSphere ex;
 #ifdef LINSOLV
-typedef CGT::FlowBoundingSphereLinSolv<FlowTesselation> FlowBoundingSphereLinSolv;
+typedef CGT::FlowBoundingSphereLinSolv<FlowBoundingSphere> FlowBoundingSphereLinSolv;
 FlowBoundingSphereLinSolv exls;
 #endif
 

=== modified file 'lib/triangulation/FlowBoundingSphere.hpp'
--- lib/triangulation/FlowBoundingSphere.hpp	2012-02-01 14:42:03 +0000
+++ lib/triangulation/FlowBoundingSphere.hpp	2012-02-14 16:58:21 +0000
@@ -29,7 +29,7 @@
 		DECLARE_TESSELATION_TYPES(Network<Tesselation>)
 		
 		//painfull, but we need that for templates inheritance...
-		using _N::T; using _N::x_min; using _N::x_max; using _N::y_min; using _N::y_max; using _N::z_min; using _N::z_max; using _N::Rmoy; using _N::SectionArea; using _N::Height; using _N::Vtotale; using _N::currentTes; using _N::DEBUG_OUT; using _N::nOfSpheres; using _N::x_min_id; using _N::x_max_id; using _N::y_min_id; using _N::y_max_id; using _N::z_min_id; using _N::z_max_id; using _N::boundsIds; using _N::Corner_min; using _N::Corner_max;  using _N::Vsolid_tot; using _N::Vtotalissimo; using _N::Vporale; using _N::Ssolid_tot; using _N::V_porale_porosity; using _N::V_totale_porosity; using _N::boundaries; using _N::id_offset; using _N::vtk_infinite_vertices; using _N::vtk_infinite_cells; using _N::num_particles; using _N::fictious_vertex;
+		using _N::T; using _N::x_min; using _N::x_max; using _N::y_min; using _N::y_max; using _N::z_min; using _N::z_max; using _N::Rmoy; using _N::SectionArea; using _N::Height; using _N::Vtotale; using _N::currentTes; using _N::DEBUG_OUT; using _N::nOfSpheres; using _N::x_min_id; using _N::x_max_id; using _N::y_min_id; using _N::y_max_id; using _N::z_min_id; using _N::z_max_id; using _N::boundsIds; using _N::Corner_min; using _N::Corner_max;  using _N::Vsolid_tot; using _N::Vtotalissimo; using _N::Vporale; using _N::Ssolid_tot; using _N::V_porale_porosity; using _N::V_totale_porosity; using _N::boundaries; using _N::id_offset; using _N::vtk_infinite_vertices; using _N::vtk_infinite_cells; using _N::num_particles; using _N::fictious_vertex; using _N::boundingCells;
 		//same for functions
 		using _N::Define_fictious_cells; using _N::AddBoundingPlanes; using _N::boundary;
 		
@@ -87,6 +87,7 @@
 		void SpheresFileCreator ();
 		void DisplayStatistics();
 		void Initialize_pressures ( double P_zero );
+		void reApplyBoundaryConditions ();
 		/// Define forces using the same averaging volumes as for permeability
 		void ComputeTetrahedralForces();
 		/// Define forces spliting drag and buoyancy terms

=== modified file 'lib/triangulation/FlowBoundingSphere.ipp'
--- lib/triangulation/FlowBoundingSphere.ipp	2012-01-25 10:02:04 +0000
+++ lib/triangulation/FlowBoundingSphere.ipp	2012-02-14 16:58:21 +0000
@@ -981,16 +981,21 @@
 
         for (int bound=0; bound<6;bound++) {
                 int& id = *boundsIds[bound];
+		boundingCells[bound].clear();
+		if (id<0) continue;
                 Boundary& bi = boundary(id);
                 if (!bi.flowCondition) {
                         Vector_Cell tmp_cells;
                         tmp_cells.resize(10000);
                         VCell_iterator cells_it = tmp_cells.begin();
                         VCell_iterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[id],cells_it);
-                        for (VCell_iterator it = tmp_cells.begin(); it != cells_end; it++)
-			{(*it)->info().p() = bi.value;(*it)->info().Pcondition=true;}
+                        for (VCell_iterator it = tmp_cells.begin(); it != cells_end; it++){
+				(*it)->info().p() = bi.value;(*it)->info().Pcondition=true;
+				boundingCells[bound].push_back(*it);
+			}
                 }
         }
+        IPCells.clear();
         for (unsigned int n=0; n<imposedP.size();n++) {
 		Cell_handle cell=Tri.locate(imposedP[n].first);
 		IPCells.push_back(cell);
@@ -1003,6 +1008,31 @@
 		cell->info().p()=imposedP[n].second;
 		cell->info().Pcondition=true;}
 }
+
+template <class Tesselation> 
+void FlowBoundingSphere<Tesselation>::reApplyBoundaryConditions()
+{
+        RTriangulation& Tri = T[currentTes].Triangulation();
+        Finite_cells_iterator cell_end = Tri.finite_cells_end();
+
+        for (int bound=0; bound<6;bound++) {
+                int& id = *boundsIds[bound];
+		if (id<0) continue;
+                Boundary& bi = boundary(id);
+                if (!bi.flowCondition) {
+                        for (VCell_iterator it = boundingCells[bound].begin(); it != boundingCells[bound].end(); it++){
+				(*it)->info().p() = bi.value;(*it)->info().Pcondition=true;
+			}
+                }
+        }
+        for (unsigned int n=0; n<imposedP.size();n++) {
+		IPCells[n]->info().p()=imposedP[n].second;
+		IPCells[n]->info().Pcondition=true;}
+}
+
+
+
+
 template <class Tesselation> 
 void FlowBoundingSphere<Tesselation>::GaussSeidel()
 {

=== modified file 'lib/triangulation/Network.hpp'
--- lib/triangulation/Network.hpp	2012-01-20 17:31:56 +0000
+++ lib/triangulation/Network.hpp	2012-02-14 16:58:21 +0000
@@ -44,6 +44,7 @@
 		int nOfSpheres;
 		int x_min_id, x_max_id, y_min_id, y_max_id, z_min_id, z_max_id;
 		int* boundsIds [6];
+		vector<Cell_handle> boundingCells [6];
 		Point Corner_min;
 		Point Corner_max;
 		Real Vsolid_tot, Vtotalissimo, Vporale, Ssolid_tot, V_porale_porosity, V_totale_porosity;

=== modified file 'lib/triangulation/PeriodicFlow.cpp'
--- lib/triangulation/PeriodicFlow.cpp	2012-02-01 14:42:03 +0000
+++ lib/triangulation/PeriodicFlow.cpp	2012-02-14 16:58:21 +0000
@@ -83,6 +83,10 @@
 			}
 	}
 	//use cached values
+	//First define products that will be used below for all cells:
+	Real pDeltas [3];
+	for (unsigned int k=0; k<3;k++) pDeltas[k]=PeriodicCellInfo::hSize[k]*PeriodicCellInfo::gradP;
+	//Then compute the forces
 	for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++){
 		if (cell->info().isGhost) continue;
 		for (int yy=0;yy<4;yy++) {
@@ -91,7 +95,7 @@
 // 			cerr <<"p="<<cell->info().p()<<" shifted="<<cell->info().shiftedP()<<endl;
 			//the pressure translated to a ghost cell adjacent to the non-ghost vertex
 			//FIXME: the hsize[k]*gradP products could be computed only once for all cells and facets
-			if (vhi.isGhost) unshiftedP -= (PeriodicCellInfo::hSize[0]*PeriodicCellInfo::gradP)*vhi.period[0] + (PeriodicCellInfo::hSize[1]*PeriodicCellInfo::gradP)*vhi.period[1] +(PeriodicCellInfo::hSize[2]*PeriodicCellInfo::gradP)*vhi.period[2];
+			if (vhi.isGhost) unshiftedP -= pDeltas[0]*vhi.period[0] + pDeltas[1]*vhi.period[1] +pDeltas[2]*vhi.period[2];
 			vhi.forces = vhi.forces + cell->info().unitForceVectors[yy]*unshiftedP;
 // 			cerr <<"unshifted="<<unshiftedP<<endl;
 		}
@@ -348,10 +352,17 @@
 				{(*it)->info().setP(bi.value);(*it)->info().Pcondition=true;}
 		}
         }
+        IPCells.clear();
         for (unsigned int n=0; n<imposedP.size();n++) {
 		Cell_handle cell=Tri.locate(imposedP[n].first);
+		
+		//check redundancy
+		for (unsigned int kk=0;kk<IPCells.size();kk++){
+			if (cell==IPCells[kk]) cerr<<"Two imposed pressures fall in the same cell."<<endl;
+			else if  (cell->info().Pcondition) cerr<<"Imposed pressure fall in a boundary condition."<<endl;}
 // 		cerr<<"cell found : "<<cell->vertex(0)->point()<<" "<<cell->vertex(1)->point()<<" "<<cell->vertex(2)->point()<<" "<<cell->vertex(3)->point()<<endl;
 // 		assert(cell);
+		IPCells.push_back(cell);
 		cell->info().setP(imposedP[n].second);
 		cell->info().Pcondition=true;}
 }
@@ -406,7 +417,7 @@
         dp_moy = sum_dp/cell2;
 	j++;
 	if (j%100==0) cerr <<"j="<<j<<" p_moy="<<p_moy<<" dp="<< dp_moy<<" p_max="<<p_max<<" dp_max="<<dp_max<<endl;
-	if (j>=40000) cerr<<"GS not converged after 40k iterations, break"<<endl;
+	if (j>=40000) cerr<<"\r GS not converged after 40k iterations, break";
 
     } while ((dp_max/p_max) > tolerance && j<40000 /*&& ( dp_max > tolerance )*//* &&*/ /*( j<50 )*/);
 
@@ -476,9 +487,9 @@
         int num_cells = 0;
         double facet_flow_rate = 0;
 	double volume_facet_translation = 0;
-	Real tVel=0; Real tVol=0;
         Finite_cells_iterator cell_end = Tri.finite_cells_end();
         for ( Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++ ) {
+		if (cell->info().isGhost) continue;
 		cell->info().av_vel() =CGAL::NULL_VECTOR;
                 num_cells++;
                 for ( int i=0; i<4; i++ ) {
@@ -490,12 +501,10 @@
 //                         Vecteur facetNormal = Surfk/area;
                         Vecteur branch = cell->vertex ( facetVertices[i][0] )->point() - cell->info();
                         pos_av_facet = (Point) cell->info() + ( branch*Surfk ) *Surfk;
-// 		pos_av_facet=CGAL::ORIGIN + ((cell->vertex(facetVertices[i][0])->point() - CGAL::ORIGIN) + (cell->vertex(facetVertices[i][1])->point() - CGAL::ORIGIN) + (cell->vertex(facetVertices[i][2])->point() - CGAL::ORIGIN))*0.3333333333;
 			facet_flow_rate = (cell->info().k_norm())[i] * (cell->info().shiftedP() - cell->neighbor (i)->info().shiftedP());
-                        cell->info().av_vel() = cell->info().av_vel() + (facet_flow_rate) * ( pos_av_facet-CGAL::ORIGIN );
+			cell->info().av_vel() = cell->info().av_vel() + (facet_flow_rate) * ( pos_av_facet-CGAL::ORIGIN );
 		  }}
- 		if (cell->info().volume()){ tVel+=cell->info().av_vel()[1]; tVol+=cell->info().volume();}
-		cell->info().av_vel() = cell->info().av_vel() /cell->info().volume();
+		cell->info().av_vel() = cell->info().av_vel() /abs(cell->info().volume());
 	}
 }
 
@@ -504,7 +513,7 @@
 
 #endif //FLOW_ENGINE
 
-/*
+
 #ifdef LINSOLV
-#include "FlowBoundingSphereLinSolv.cpp"
-#endif*/
+#include "PeriodicFlowLinSolv.ipp"
+#endif

=== modified file 'lib/triangulation/PeriodicFlow.hpp'
--- lib/triangulation/PeriodicFlow.hpp	2012-01-24 17:14:09 +0000
+++ lib/triangulation/PeriodicFlow.hpp	2012-02-14 16:58:21 +0000
@@ -14,7 +14,6 @@
 // #include "Vue3D.h" //FIXME implicit dependencies will look for this class (out of tree) even ifndef XVIEW
 // #endif
 
-// using namespace std;
 
 namespace CGT{
 
@@ -41,9 +40,9 @@
 	};
 }
 
-// #ifdef LINSOLV
-// #include "FlowBoundingSphereLinSolv.hpp"
-// #endif
+#ifdef LINSOLV
+#include "PeriodicFlowLinSolv.hpp"
+#endif
 
 
 #endif //FLOW_ENGINE

=== modified file 'lib/triangulation/Tesselation.ipp'
--- lib/triangulation/Tesselation.ipp	2012-01-24 17:14:09 +0000
+++ lib/triangulation/Tesselation.ipp	2012-02-14 16:58:21 +0000
@@ -402,49 +402,50 @@
 	}
 	cell0=cell2++;
 	Cell_circulator cell1=cell2++;
-	//std::cout << "edge : " << ed_it->first->vertex ( ed_it->second )->info().id() << "-" << ed_it->first->vertex ( ed_it->third )->info().id() << std::endl;
+// 	std::cout << "edge : " << ed_it->first->vertex ( ed_it->second )->info().id() << "-" << ed_it->first->vertex ( ed_it->third )->info().id() << std::endl;
 	bool isFictious1 = ( ed_it->first )->vertex ( ed_it->second )->info().isFictious;
 	bool isFictious2 = ( ed_it->first )->vertex ( ed_it->third )->info().isFictious;
+// 	cout<<"fictious "<<isFictious1<<" "<<isFictious2<<endl;
 	Real r;
 
-	//cout << "cell0 : " <<  cell0->vertex(0)->info().id() << " "
-	//   <<  cell0->vertex(1)->info().id() << " "
-	//   <<  cell0->vertex(2)->info().id() << " "
-	//   <<  cell0->vertex(3)->info().id() << "(center : " << (Point) cell0->info() << ")" <<   endl;
+// 	cout << "cell0 : " <<  cell0->vertex(0)->info().id() << " "
+// 	  <<  cell0->vertex(1)->info().id() << " "
+// 	  <<  cell0->vertex(2)->info().id() << " "
+// 	  <<  cell0->vertex(3)->info().id() << "(center : " << (Point) cell0->info() << ")" <<   endl;
 
 	while ( cell2!=cell0 )
 	{
 		if ( !Tri->is_infinite ( cell1 )  && !Tri->is_infinite ( cell2 ) )
 		{
-			// cout << "cell1 : " <<  cell1->vertex(0)->info().id() << " "
-			//   <<  cell1->vertex(1)->info().id() << " "
-			//   <<  cell1->vertex(2)->info().id() << " "
-			//   <<  cell1->vertex(3)->info().id() << "(center : " << (Point) cell1->info() << ")" << endl;
-			// cout << "cell2 : " <<  cell2->vertex(0)->info().id() << " "
-			//   <<  cell2->vertex(1)->info().id() << " "
-			//   <<  cell2->vertex(2)->info().id() << " "
-			//   <<  cell2->vertex(3)->info().id() << "(center : " << (Point) cell2->info() << ")" << endl;
+// 			cout << "cell1 : " <<  cell1->vertex(0)->info().id() << " "
+// 			  <<  cell1->vertex(1)->info().id() << " "
+// 			  <<  cell1->vertex(2)->info().id() << " "
+// 			  <<  cell1->vertex(3)->info().id() << "(center : " << (Point) cell1->info() << ")" << endl;
+// 			cout << "cell2 : " <<  cell2->vertex(0)->info().id() << " "
+// 			  <<  cell2->vertex(1)->info().id() << " "
+// 			  <<  cell2->vertex(2)->info().id() << " "
+// 			  <<  cell2->vertex(3)->info().id() << "(center : " << (Point) cell2->info() << ")" << endl;
 
-			//std::cout << "assign tetra : (" << ed_it->first->vertex ( ed_it->second )->point() << "),(" << cell0->info() << "),(" << cell1->info() << "),(" <<cell2->info() << ")" << std::endl;
+// 			std::cout << "assign tetra : (" << ed_it->first->vertex ( ed_it->second )->point() << "),(" << cell0->info() << "),(" << cell1->info() << "),(" <<cell2->info() << ")" << std::endl;
 			if ( !isFictious1 )
 			{
 				r = std::abs ( ( Tetraedre ( ed_it->first->vertex ( ed_it->second )->point(), cell0->info(), cell1->info(), cell2->info() ) ).volume() );
-				//std::cout << "assigned1=" << r << " on " << ed_it->first->vertex ( ed_it->second )->info().id() << std::endl;
+// 				std::cout << "assigned1=" << r << " on " << ed_it->first->vertex ( ed_it->second )->info().id() << std::endl;
 				( ed_it->first )->vertex ( ed_it->second )->info().v() += r;
 				TotalFiniteVoronoiVolume+=r;
 			}
-			//std::cout << "assign tetra : (" << ed_it->first->vertex ( ed_it->third )->point() << "),(" << cell0->info() << "),(" << cell1->info() << "),(" <<cell2->info() << ")" << std::endl;
+// 			std::cout << "assign tetra : (" << ed_it->first->vertex ( ed_it->third )->point() << "),(" << cell0->info() << "),(" << cell1->info() << "),(" <<cell2->info() << ")" << std::endl;
 			if ( !isFictious2 )
 			{
 				r = std::abs ( ( Tetraedre ( ed_it->first->vertex ( ed_it->third )->point(), cell0->info(),  cell1->info(), cell2->info() ) ).volume() );
-				//std::cout << "assigned2=" << r << " on " << ed_it->first->vertex ( ed_it->third )->info().id() << std::endl;
+// 				std::cout << "assigned2=" << r << " on " << ed_it->first->vertex ( ed_it->third )->info().id() << std::endl;
 				ed_it->first->vertex ( ed_it->third )->info().v() +=r;
 				TotalFiniteVoronoiVolume+=r;
 			}
 		}
 		++cell1; ++cell2;
 	}
-	//std::cout << "fin AssignPartialVolume" << std::endl;
+// 	std::cout << "fin AssignPartialVolume,total " << TotalFiniteVoronoiVolume<< std::endl;
 }
 
 template<class TT>

=== modified file 'lib/triangulation/TriaxialState.h'
--- lib/triangulation/TriaxialState.h	2012-01-20 17:31:56 +0000
+++ lib/triangulation/TriaxialState.h	2012-02-14 16:58:21 +0000
@@ -25,8 +25,6 @@
 namespace CGT {
 using namespace std;
 
-
-
 class TriaxialState
 {
 public:

=== modified file 'lib/triangulation/def_types.h'
--- lib/triangulation/def_types.h	2012-01-24 17:14:09 +0000
+++ lib/triangulation/def_types.h	2012-02-14 16:58:21 +0000
@@ -71,6 +71,7 @@
 	inline Real& f (void) {return s;}
 	inline Real& v (void) {return vol;}
 	inline const unsigned int& id (void) const {return i;}
+	SimpleVertexInfo (void) {isFictious=false; s=0; i=0;}
 };
 
 
@@ -163,20 +164,24 @@
 	static Vecteur gradP;
 	int period[3];
 	static Vecteur hSize[3];
+	static Vecteur deltaP;
 	int ghost;
 	Real* _pression;
 	bool isGhost;
 	PeriodicCellInfo (void)
 	{
 		_pression=&pression;
+		period[0]=period[1]=period[2]=0;
+		isGhost=false;
 	}
 	~PeriodicCellInfo (void) {}
 	PeriodicCellInfo& operator= (const Point &p) { Point::operator= (p); return *this; }
 	PeriodicCellInfo& operator= (const float &scalar) { s=scalar; return *this; }
 	
-	inline const double shiftedP (void) {return isGhost? (*_pression)+(hSize[0]*gradP)*period[0] + (hSize[1]*gradP)*period[1] +(hSize[2]*gradP)*period[2] :(*_pression) ;}
+	inline const double shiftedP (void) const {return isGhost? (*_pression)+pShift() :(*_pression) ;}
+	inline const double pShift (void) const {return deltaP[0]*period[0] + deltaP[1]*period[1] +deltaP[2]*period[2];}
 // 	inline const double p (void) {return shiftedP();}
-	inline double setP (Real p) {pression=p;}
+	inline void setP (const Real& p) {pression=p;}
 };
 
 class PeriodicVertexInfo : public FlowVertexInfo {

=== modified file 'pkg/dem/FlowEngine.cpp'
--- pkg/dem/FlowEngine.cpp	2012-01-26 08:46:25 +0000
+++ pkg/dem/FlowEngine.cpp	2012-02-14 16:58:21 +0000
@@ -15,7 +15,6 @@
 #include<yade/pkg/common/Sphere.hpp>
 #include<yade/pkg/common/Wall.hpp>
 #include<yade/pkg/common/Box.hpp>
-
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -138,16 +137,16 @@
 template<class Solver>
 void FlowEngine::imposeFlux(Vector3r pos, Real flux,Solver& flow)
 {
-	RTriangulation& Tri = flow->T[flow->currentTes].Triangulation();
+	typename Solver::RTriangulation& Tri = flow.T[flow.currentTes].Triangulation();
 	double flux_base=0.f;
 	double perm_base=0.f;
-	Cell_handle cell = Tri.locate(CGT::Point(pos[0],pos[1],pos[2]));
+	typename Solver::Cell_handle cell = Tri.locate(CGT::Point(pos[0],pos[1],pos[2]));
 	for (int ngb=0;ngb<4;ngb++) {
 		if (!cell->neighbor(ngb)->info().Pcondition) {
 		  flux_base += cell->info().k_norm()[ngb]*(cell->neighbor(ngb)->info().p());
 		  perm_base += cell->info().k_norm()[ngb];}}
 	
-	flow->imposedP.push_back( pair<CGT::Point,Real>(CGT::Point(pos[0],pos[1],pos[2]),(flux_base-flux)/perm_base));
+	flow.imposedP.push_back( pair<CGT::Point,Real>(CGT::Point(pos[0],pos[1],pos[2]),(flux_base-flux)/perm_base));
 	//force immediate update of boundary conditions
 	Update_Triangulation=true;
 }
@@ -587,17 +586,25 @@
 
 void PeriodicFlowEngine:: action()
 {
+	if (!isActivated) return;
 	CGT::PeriodicCellInfo::gradP = makeCgVect(gradP);
 	CGT::PeriodicCellInfo::hSize[0] = makeCgVect(scene->cell->hSize.col(0));
 	CGT::PeriodicCellInfo::hSize[1] = makeCgVect(scene->cell->hSize.col(1));
 	CGT::PeriodicCellInfo::hSize[2] = makeCgVect(scene->cell->hSize.col(2));
-	if (!isActivated) return;
+	CGT::PeriodicCellInfo::deltaP=CGT::Vecteur(
+		CGT::PeriodicCellInfo::hSize[0]*CGT::PeriodicCellInfo::gradP,
+		CGT::PeriodicCellInfo::hSize[1]*CGT::PeriodicCellInfo::gradP,
+		CGT::PeriodicCellInfo::hSize[2]*CGT::PeriodicCellInfo::gradP);
+/*
+	CGT::PeriodicCellInfo::hSize[2]
+	(hSize[0]*gradP)*period[0] + (hSize[1]*gradP)*period[1] +(hSize[2]*gradP)*period[2]*/
+
 // 	timingDeltas->start();
 
-	if (first) Build_Triangulation(P_zero);
+	if (first) {Build_Triangulation(P_zero); Update_Triangulation = false;}
 // 	timingDeltas->checkpoint("Triangulating");
 	UpdateVolumes ( );
-	if (!first) {
+// 	if (!first) {
 // 		eps_vol_max=0.f;//huh? in that case Eps_Vol_Cumulative will always be zero
 		Eps_Vol_Cumulative += eps_vol_max;
 		if ((Eps_Vol_Cumulative > EpsVolPercent_RTRG || retriangulationLastIter>1000) && retriangulationLastIter>10) {
@@ -628,7 +635,7 @@
 		}
 		///End Compute flow and forces
 // 		timingDeltas->checkpoint("Applying Forces");
-	}
+// 	}
 // 	if ( scene->iter % PermuteInterval == 0 )
 // 	{ Update_Triangulation = true; }
 
@@ -687,10 +694,6 @@
 // 		cerr <<"number of vtx"<< solver->T[solver -> currentTes].Triangulation().number_of_vertices()<<endl;
 	}
     }
-	// Define the ghost cells
-	Finite_cells_iterator cellend=solver->T[solver->currentTes].Triangulation().finite_cells_end();
-	for (Finite_cells_iterator cell=solver -> T[solver -> currentTes].Triangulation().finite_cells_begin(); cell!=cellend; cell++)
-		locateCell(cell);
 	solver -> viscousShearForces.resize(solver -> T[solver -> currentTes].max_id+1);
 }
 
@@ -750,21 +753,46 @@
     }
 }
 
-void PeriodicFlowEngine::locateCell(Cell_handle baseCell)
+void PeriodicFlowEngine::locateCell(Cell_handle baseCell, unsigned int& index)
 {
+    PeriFlowTesselation::Cell_Info& base_info = baseCell->info();
+    if (base_info.index>0 || base_info.isGhost) return;
     RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+    Tesselation& Tes = solver->T[solver->currentTes];
     Vector3r center(0,0,0);
     Vector3i period;
     for (int k=0;k<4;k++) center+= 0.25*makeVector3r(baseCell->vertex(k)->point());
     Vector3r wdCenter= scene->cell->wrapPt(center,period);
     if (period[0]!=0 || period[1]!=0 || period[2]!=0) {
-        baseCell->info().isGhost=true;
-        Cell_handle ch= Tri.locate(CGT::Point(wdCenter[0],wdCenter[1],wdCenter[2]));
-        baseCell->info().period[0]=period[0];
-        baseCell->info().period[1]=period[1];
-        baseCell->info().period[2]=period[2];
-        baseCell->info()._pression=&(ch->info().p());
-    } else baseCell->info().isGhost=false;
+        if (baseCell->info().index>0) {
+            cout<<"indexed cell is found ghost!"<<base_info.index <<endl;
+            base_info.isGhost=false;
+            return;
+        }
+//         Cell_handle ch= Tri.locate(CGT::Point(wdCenter[0],wdCenter[1],wdCenter[2]),Tes.vertexHandles[baseCell->vertex(0)->info().id()]);//T[currentTes].vertexHandles[id]
+	Cell_handle ch= Tri.locate(CGT::Point(wdCenter[0],wdCenter[1],wdCenter[2]));//T[currentTes].vertexHandles[id]
+	base_info.period[0]=period[0];
+        base_info.period[1]=period[1];
+        base_info.period[2]=period[2];
+	//call recursively, since the returned cell could be also a ghost (especially if baseCell is a non-periodic type from the external contour
+        locateCell(ch,index);
+	if (ch==baseCell) cerr<<"WTF!!"<<endl;
+	
+	base_info.isGhost=true;
+        //index is 1-based, if it is zero it is not initialized, we define it here
+//         if (!ch->info().Pcondition && ch->info().index==0)  {
+//             ch->info().index=++index;
+//             ch->info().isGhost=false;
+//         }
+        //we make the ghost point to the real cell
+	base_info._pression=&(ch->info().p());
+        base_info.index=ch->info().index;
+	base_info.Pcondition=ch->info().Pcondition;
+    } else {
+        base_info.isGhost=false;
+        //index is 1-based, if it is zero it is not initialized, we define it here
+        if (!base_info.Pcondition && base_info.index==0) base_info.index=++index;
+    }
 }
 
 Vector3r PeriodicFlowEngine::MeanVelocity()
@@ -776,8 +804,8 @@
 	for ( Finite_cells_iterator cell = solver->T[solver->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ) {
 		if (cell->info().isGhost) continue;
 		for (int i=0;i<3;i++)
-			MeanVel[i]=MeanVel[i]+((cell->info().av_vel())[i] * cell->info().volume());
-		volume+=cell->info().volume();
+			MeanVel[i]=MeanVel[i]+((cell->info().av_vel())[i] * abs(cell->info().volume()));
+		volume+=abs(cell->info().volume());
 	}
 	return (MeanVel/volume);
 }
@@ -814,7 +842,7 @@
 //             totVol1+=newVol;
 //             break;
 //         case ( 0 ) :
-            newVol = Volume_cell ( cell );
+//             newVol = Volume_cell ( cell );
 //             totVol0+=newVol;
 //             break;
 //         default:
@@ -824,7 +852,7 @@
         newVol = Volume_cell ( cell );
         totVol+=newVol;
         dVol=cell->info().volumeSign * (newVol - cell->info().volume());
-        totDVol+=dVol;
+	totDVol+=dVol;
         eps_vol_max = max(eps_vol_max, abs(dVol/newVol));
         cell->info().dv() = dVol * invDeltaT;
         cell->info().volume() = newVol;
@@ -885,7 +913,6 @@
 	solver->T[solver->currentTes].Compute();
 
 // 	solver->Define_fictious_cells();
-	solver->DisplayStatistics ();
 
 	solver->meanK_LIMIT = meanK_correction;
 	solver->meanK_STAT = meanK_opt;
@@ -899,9 +926,22 @@
 	for ( Finite_cells_iterator cell = solver->T[solver->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ){cell->info().dv() = 0; cell->info().p() = 0;}
 	
 	BoundaryConditions(solver);
+
+	
 	solver->Initialize_pressures(P_zero);
 	
-	if (!first && useSolver==0) solver->Interpolate (solver->T[!solver->currentTes], solver->T[solver->currentTes]);
+	// Define the ghost cells and add indexes to the cells inside the period (the ones that will contain the pressure unknowns)
+	//This must be done after boundary conditions and before initialize pressure, else the indexes are not good (not accounting imposedP):
+	Finite_cells_iterator cellend=solver->T[solver->currentTes].Triangulation().finite_cells_end();
+	unsigned int index=0;
+	for (Finite_cells_iterator cell=solver -> T[solver -> currentTes].Triangulation().finite_cells_begin(); cell!=cellend; cell++)
+		locateCell(cell,index);
+	
+	solver->DisplayStatistics ();
+	
+	//FIXME: check interpolate() for the periodic case, at least use the mean pressure from previous step. 
+// 	if (!first && useSolver==0) solver->Interpolate (solver->T[!solver->currentTes], solver->T[solver->currentTes]);
+	
 	if (WaveAction) solver->ApplySinusoidalPressure(solver->T[solver->currentTes].Triangulation(), Sinus_Amplitude, Sinus_Average, 30);
 	
 	Initialize_volumes();

=== modified file 'pkg/dem/FlowEngine.hpp'
--- pkg/dem/FlowEngine.hpp	2012-01-26 08:46:25 +0000
+++ pkg/dem/FlowEngine.hpp	2012-02-14 16:58:21 +0000
@@ -16,7 +16,7 @@
 class Flow;
 class TesselationWrapper;
 #ifdef LINSOLV
-#define _FlowSolver CGT::FlowBoundingSphereLinSolv<FlowTesselation>
+#define _FlowSolver CGT::FlowBoundingSphereLinSolv<CGT::FlowBoundingSphere<FlowTesselation> >
 #else
 #define _FlowSolver CGT::FlowBoundingSphere<FlowTesselation>
 #endif
@@ -95,7 +95,7 @@
 		
 		//Instanciation of templates for python binding
 		Vector3r 	_fluidShearForce(unsigned int id_sph) {return fluidShearForce(id_sph,solver);}
-		void 		_imposeFlux(Vector3r pos, Real flux) {return imposeFlux(pos,flux,solver);}
+		void 		_imposeFlux(Vector3r pos, Real flux) {return imposeFlux(pos,flux,*solver);}
 		unsigned int 	_imposePressure(Vector3r pos, Real p) {return imposePressure(pos,p,solver);}	
 		void 		_setImposedPressure(unsigned int cond, Real p) {setImposedPressure(cond,p,solver);}
 		void 		_clearImposedPressure() {clearImposedPressure(solver);}
@@ -211,21 +211,17 @@
 
 REGISTER_SERIALIZABLE(FlowEngine);
 
-// #ifdef LINSOLV
-// #define _PeriFlowSolver CGT::FlowBoundingSphereLinSolv<FlowTesselation>
-// #else
-// #define _PeriFlowSolver CGT::FlowBoundingSphere<PeriodicFlowTesselation>
-// #endif
+#ifdef LINSOLV
+#define _PeriFlowSolver CGT::PeriodicFlowLinSolv
+#else
+#define _PeriFlowSolver CGT::PeriodicFlow
+#endif
 
 class PeriodicFlowEngine : public FlowEngine
 {
-	private:
-// 		shared_ptr<FlowSolver> flow;
-// 		int retriangulationLastIter;
-		
 	public :
 		public :
-		typedef CGT::PeriodicFlow						FlowSolver;
+		typedef _PeriFlowSolver							FlowSolver;
 		typedef PeriFlowTesselation						Tesselation;
 		typedef FlowSolver::RTriangulation					RTriangulation;
 		typedef FlowSolver::Finite_vertices_iterator                    	Finite_vertices_iterator;
@@ -243,7 +239,7 @@
 		void UpdateVolumes ();
 		Real Volume_cell (Cell_handle cell);
 		void ApplyViscousForces();
-		void locateCell(Cell_handle baseCell);
+		void locateCell(Cell_handle baseCell, unsigned int& index);
 		Vector3r MeanVelocity();
 		
 		virtual ~PeriodicFlowEngine();
@@ -252,7 +248,7 @@
 		
 		//Instanciation of templates for python binding
 		Vector3r 	_fluidShearForce(unsigned int id_sph) {return fluidShearForce(id_sph,solver);}
-// 		void 		_imposeFlux(Vector3r pos, Real flux) {return imposeFlux(pos,flux,solver);}
+		void 		_imposeFlux(Vector3r pos, Real flux) {return imposeFlux(pos,flux,*solver);}
 		unsigned int 	_imposePressure(Vector3r pos, Real p) {return imposePressure(pos,p,this->solver);}	
 // 		void 		_setImposedPressure(unsigned int cond, Real p) {setImposedPressure(cond,p,solver);}
 // 		void 		_clearImposedPressure() {clearImposedPressure(solver);}

=== modified file 'pkg/dem/SpherePack.cpp'
--- pkg/dem/SpherePack.cpp	2012-02-01 18:06:57 +0000
+++ pkg/dem/SpherePack.cpp	2012-02-14 16:58:21 +0000
@@ -115,6 +115,7 @@
 			if (!area) throw invalid_argument("The box defined has null volume AND null surface. Define at least maxCorner of the box, or hSize if periodic.");
 			rMean=pow(area*(1-porosity)/(Mathr::PI*(1+rRelFuzz*rRelFuzz)*num),0.5);}
 	}
+	// transform sizes and cummulated fractions values in something convenient for the generation process
 	if(psdSizes.size()>0){
 		err=(mode>=0); mode=RDIST_PSD;
 		if(psdSizes.size()!=psdCumm.size()) throw invalid_argument(("SpherePack.makeCloud: psdSizes and psdCumm must have same dimensions ("+lexical_cast<string>(psdSizes.size())+"!="+lexical_cast<string>(psdCumm.size())).c_str());
@@ -137,8 +138,6 @@
 			appliedPsdScaling=1;
 			if(distributeMass) {
 				if (psdCumm2[psdSizes.size()-1]<num) appliedPsdScaling=pow(psdCumm2[psdSizes.size()-1]/num,1./3.);
-				//Normalize psdCumm2 so it's between 0 and 1
-// 				for(size_t i=1; i<psdSizes.size(); i++) psdCumm2[i]/=psdCumm2[psdSizes.size()-1];
 			} else {
 				double totVol=0;
 				for(size_t i=1; i<psdSizes.size(); i++) totVol+= 4/3*Mathr::PI*(psdCumm[i]-psdCumm[i-1])*num*
@@ -158,13 +157,13 @@
 	Real r=0;
 	for(int i=0; (i<num) || (num<0); i++) {
 		Real norm, rand;
-		//Determine radius of the next sphere we will attempt to place in space. If (num>0), generate radii the deterministic way, in decreasing order, else radii are stochastic since we don't know what the final number will be
+		//Determine radius of the next sphere that will be placed in space. If (num>0), generate radii the deterministic way, in decreasing order, else radii are stochastic since we don't know what the final number will be
 		if (num>0) rand = ((Real)num-(Real)i+0.5)/((Real)num+1.);
 		else rand = rnd();
 		int t;
 		switch(mode){
 			case RDIST_RMEAN:
-				//FIXME : r is never defined, it will be zero at first iteration, but it will have values in the next ones. Some magic?
+			//FIXME : r is never defined, it will be zero at first iteration, but it will have values in the next ones. Some magic?
 			case RDIST_NUM:
 				if(distributeMass) r=pow3Interp(rand,rMean*(1-rRelFuzz),rMean*(1+rRelFuzz));
 				else r=rMean*(2*(rand-.5)*rRelFuzz+1); // uniform distribution in rMean*(1±rRelFuzz)
@@ -205,6 +204,7 @@
 		if (t==maxTry) {
 			if(num>0) {
 				if (mode!=RDIST_RMEAN) {
+					//if rMean is not imposed, then we call makeCloud recursively, scaling the PSD down until the target num is obtained
 					Real nextPoro = porosity+(1-porosity)/10.;
 					LOG_WARN("Exceeded "<<maxTry<<" tries to insert non-overlapping sphere to packing. Only "<<i<<" spheres was added, although you requested "<<num<<". Trying again with porosity "<<nextPoro<<". The size distribution is being scaled down");
 					pack.clear();

=== modified file 'pkg/dem/TesselationWrapper.cpp'
--- pkg/dem/TesselationWrapper.cpp	2012-01-23 14:43:54 +0000
+++ pkg/dem/TesselationWrapper.cpp	2012-02-14 16:58:21 +0000
@@ -158,7 +158,7 @@
 // 	clock.top("Triangulation");
 }
 
-double TesselationWrapper::Volume(unsigned int id) {return ((unsigned int) Tes->Max_id() > id) ? Tes->Volume(id) : -1;}
+double TesselationWrapper::Volume(unsigned int id) {return ((unsigned int) Tes->Max_id() >= id) ? Tes->Volume(id) : -1;}
 
 bool TesselationWrapper::insert(double x, double y, double z, double rad, unsigned int id)
 {
@@ -205,6 +205,7 @@
 
 void TesselationWrapper::ComputeVolumes(void)
 {
+	if (!bounded) AddBoundingPlanes();
 	ComputeTesselation();
 	Tes->ComputeVolumes();
 }

=== modified file 'pkg/dem/TesselationWrapper.hpp'
--- pkg/dem/TesselationWrapper.hpp	2012-01-20 17:31:56 +0000
+++ pkg/dem/TesselationWrapper.hpp	2012-02-14 16:58:21 +0000
@@ -77,8 +77,13 @@
 	///Compute Voronoi vertices + volumes of all cells
 	///use ComputeTesselation to force update, e.g. after spheres positions have been updated
   	void	ComputeVolumes	(void);
+	void	computeDeformations (void) {mma.analyser->ComputeParticlesDeformation();}
 	///Get volume of the sphere inserted with indentifier "id""
 	double	Volume	(unsigned int id);
+	double	deformation (unsigned int id,unsigned int i,unsigned int j) {
+		if (!mma.analyser->ParticleDeformation.size()) {LOG_ERROR("Compute deformations first"); return 0;}
+		if (mma.analyser->ParticleDeformation.size()<id) {LOG_ERROR("id out of bounds"); return 0;}
+		return mma.analyser->ParticleDeformation[id](i,j);}
 
 	/// number of facets in the tesselation (finite branches of the triangulation)
 	unsigned int NumberOfFacets(bool initIters=false);
@@ -121,13 +126,15 @@
 	.def("triangulate",&TesselationWrapper::insertSceneSpheres,(python::arg("reset")=true),"triangulate spheres of the packing")
  	.def("setState",&TesselationWrapper::setState,(python::arg("state")=0),"Make the current state of the simulation the initial (0) or final (1) configuration for the definition of displacement increments, use only state=0 if you just want to get  volmumes and porosity.")
  	.def("loadState",&TesselationWrapper::loadState,(python::arg("stateNumber")=0),"Load a file with positions to define state 0 or 1.")
- 	.def("saveState",&TesselationWrapper::saveState,(python::arg("outputFile")="state",python::arg("bz2")=true),"Save a file with positions, can be later reloaded in order to define state 0 or 1.")
+ 	.def("saveState",&TesselationWrapper::saveState,(python::arg("outputFile")="state",python::arg("state")=0,python::arg("bz2")=true),"Save a file with positions, can be later reloaded in order to define state 0 or 1.")
  	.def("volume",&TesselationWrapper::Volume,(python::arg("id")=0),"Returns the volume of Voronoi's cell of a sphere.")
  	.def("defToVtk",&TesselationWrapper::defToVtk,(python::arg("outputFile")="def.vtk"),"Write local deformations in vtk format from states 0 and 1.")
- 	.def("defToVtkFromStates",&TesselationWrapper::defToVtkFromStates,(python::arg("input1")="state1",python::arg("input2")="state2",python::arg("outputFile")="def.vtk",python::arg("bz2")=false),"Write local deformations in vtk format from state files (since the file format is very special, consider using defToVtkFromPositions instead).")
- 	.def("defToVtkFromPositions",&TesselationWrapper::defToVtkFromPositions,(python::arg("input1")="pos1",python::arg("input2")="pos2",python::arg("outputFile")="def.vtk",python::arg("bz2")=false),"Write local deformations in vtk format from state files (since the file format is very special, consider using defToVtkFromPositions instead).")
+ 	.def("defToVtkFromStates",&TesselationWrapper::defToVtkFromStates,(python::arg("input1")="state1",python::arg("input2")="state2",python::arg("outputFile")="def.vtk",python::arg("bz2")=false),"Write local deformations in vtk format from state files (since the file format is very special, consider using defToVtkFromPositions if the input files were not generated by TesselationWrapper).")
+ 	.def("defToVtkFromPositions",&TesselationWrapper::defToVtkFromPositions,(python::arg("input1")="pos1",python::arg("input2")="pos2",python::arg("outputFile")="def.vtk",python::arg("bz2")=false),"Write local deformations in vtk format from positions files (one sphere per line, with x,y,z,rad separated by spaces).")
  	.def("computeVolumes",&TesselationWrapper::ComputeVolumes,"Compute volumes of all Voronoi's cells.")
 	.def("getVolPoroDef",&TesselationWrapper::getVolPoroDef,(python::arg("deformation")=false),"Return a table with per-sphere computed quantities. Include deformations on the increment defined by states 0 and 1 if deformation=True (make sure to define states 0 and 1 consistently).")
+	.def("ComputeDeformations",&TesselationWrapper::computeDeformations,"Compute per-particle deformation. Get it with :yref:`TesselationWrapper.deformation`(id,i,j).")
+	.def("deformation",&TesselationWrapper::deformation,(python::arg("id"),python::arg("i"),python::arg("j")),"Get particle deformation")
 	);
 	DECLARE_LOGGER;
 };