← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-pkg/yade/git-trunk] Rev 3889: Bugfixes in PeriodicFlowEngine, as discussed with Donia

 

------------------------------------------------------------
revno: 3889
committer: Bruno Chareyre <bruno.chareyre@xxxxxxxxxxxxxxx>
timestamp: Mon 2014-04-07 11:33:19 +0200
message:
  Bugfixes in PeriodicFlowEngine, as discussed with Donia
modified:
  lib/triangulation/FlowBoundingSphere.hpp
  lib/triangulation/FlowBoundingSphere.ipp
  pkg/pfv/FlowEngine.hpp
  pkg/pfv/FlowEngine.ipp
  pkg/pfv/PeriodicFlowEngine.cpp
  pkg/pfv/PeriodicFlowEngine.hpp


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

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-pkg/yade/git-trunk/+edit-subscription
=== modified file 'lib/triangulation/FlowBoundingSphere.hpp'
--- lib/triangulation/FlowBoundingSphere.hpp	2014-03-21 18:47:45 +0000
+++ lib/triangulation/FlowBoundingSphere.hpp	2014-04-07 09:33:19 +0000
@@ -71,7 +71,7 @@
 		vector< vector<const Real*> > perVertexPressure;
 		#endif
 		vector <double> edgeSurfaces;
-		vector <pair<int,int> > edgeIds;
+		vector <pair<const VertexInfo*,const VertexInfo*> > edgeIds;
 		vector <Real> edgeNormalLubF;
 		vector <Vector3r> shearLubricationForces;
 		vector <Vector3r> shearLubricationTorques;

=== modified file 'lib/triangulation/FlowBoundingSphere.ipp'
--- lib/triangulation/FlowBoundingSphere.ipp	2014-04-03 13:07:09 +0000
+++ lib/triangulation/FlowBoundingSphere.ipp	2014-04-07 09:33:19 +0000
@@ -89,7 +89,7 @@
 }
 
 template <class Tesselation> 
-void FlowBoundingSphere<Tesselation>::resetNetwork() {T[0].Clear();noCache=true;}
+void FlowBoundingSphere<Tesselation>::resetNetwork() {T[currentTes].Clear();noCache=true;}
 
 template <class Tesselation>
 void FlowBoundingSphere<Tesselation>::averageRelativeCellVelocity()
@@ -1201,41 +1201,44 @@
 template <class Tesselation>
 void  FlowBoundingSphere<Tesselation>::computeEdgesSurfaces()
 {
-  RTriangulation& Tri = T[currentTes].Triangulation();
-
-  //first, copy interacting pairs and normal lub forces form prev. triangulation in a sorted structure for initializing the new lub. Forces
-  vector<vector<pair<unsigned int,Real> > > lubPairs;
-  lubPairs.resize(Tri.number_of_vertices()+1);
-  for (unsigned int k=0; k<edgeNormalLubF.size(); k++)
-	lubPairs[min(edgeIds[k].first,edgeIds[k].second)].push_back(pair<int,Real> (max(edgeIds[k].first,edgeIds[k].second),edgeNormalLubF[k]));
-
-  //Now we reset the containers and initialize them
-  edgeSurfaces.clear(); edgeIds.clear(); edgeNormalLubF.clear();
-  FiniteEdgesIterator ed_it;
-  for ( FiniteEdgesIterator ed_it = Tri.finite_edges_begin(); ed_it!=Tri.finite_edges_end();ed_it++ )
-  {
-    int hasFictious= (ed_it->first)->vertex(ed_it->second)->info().isFictious +  (ed_it->first)->vertex(ed_it->third)->info().isFictious;
-    if (hasFictious==2) continue;
-    double area = T[currentTes].computeVFacetArea(ed_it);
-    edgeSurfaces.push_back(area);
-    unsigned int id1 = (ed_it->first)->vertex(ed_it->second)->info().id();
-    unsigned int id2 = (ed_it->first)->vertex(ed_it->third)->info().id();
-    edgeIds.push_back(pair<int,int>(id1,id2));
-    
-    //For persistant edges, we must transfer the lub. force value from the older triangulation structure
-    if (id1>id2) swap(id1,id2);
-    unsigned int i=0;
-    //Look for the pair (id1,id2) in lubPairs
-    while (i<lubPairs[id1].size()) {
-		if (lubPairs[id1][i].first == id2) {
-			//it's found, we copy the lub force
-			edgeNormalLubF.push_back(lubPairs[id1][i].second);
-			break;}
-		++i;
-    }
-    // not found, we initialize with zero lub force
-    if (i==lubPairs[id1].size()) edgeNormalLubF.push_back(0);
-  }
+	RTriangulation& Tri = T[currentTes].Triangulation();
+	//first, copy interacting pairs and normal lub forces form prev. triangulation in a sorted structure for initializing the new lub. Forces
+	vector<vector<pair<unsigned int,Real> > > lubPairs;
+	lubPairs.resize(Tri.number_of_vertices()+1);
+	for (unsigned int k=0; k<edgeNormalLubF.size(); k++)
+		lubPairs[min(edgeIds[k].first->id(),edgeIds[k].second->id())].push_back(
+			pair<int,Real> (max(edgeIds[k].first->id(),edgeIds[k].second->id()),edgeNormalLubF[k]));
+
+	//Now we reset the containers and initialize them
+	edgeSurfaces.clear(); edgeIds.clear(); edgeNormalLubF.clear();
+	FiniteEdgesIterator ed_it;
+	for ( FiniteEdgesIterator ed_it = Tri.finite_edges_begin(); ed_it!=Tri.finite_edges_end();ed_it++ )
+	{
+		const VertexInfo& vi1=(ed_it->first)->vertex(ed_it->second)->info();
+		const VertexInfo& vi2=(ed_it->first)->vertex(ed_it->third)->info();
+	  
+		//We eliminate edges that would be periodic replications or involving two bounding objects, i.e. the min id must be non-ghost and non-fictious
+		if (vi1.id()<vi2.id()) {if (vi1.isFictious || vi2.isGhost) continue;}
+		else if (vi2.isFictious || vi2.isGhost) continue;
+		double area = T[currentTes].computeVFacetArea(ed_it);
+		edgeSurfaces.push_back(area);
+		unsigned int id1 = vi1.id();
+		unsigned int id2 = vi2.id();
+		edgeIds.push_back(pair<const VertexInfo*,const VertexInfo*>(&vi1,&vi2));
+		//For persistant edges, we must transfer the lub. force value from the older triangulation structure
+		if (id1>id2) swap(id1,id2);
+		unsigned int i=0;
+		//Look for the pair (id1,id2) in lubPairs
+		while (i<lubPairs[id1].size()) {
+			if (lubPairs[id1][i].first == id2) {
+				//it's found, we copy the lub force
+				edgeNormalLubF.push_back(lubPairs[id1][i].second);
+				break;}
+			++i;
+		}
+		// not found, we initialize with zero lub force
+    		if (i==lubPairs[id1].size()) edgeNormalLubF.push_back(0);
+	}
 }
 
 template <class Tesselation> 

=== modified file 'pkg/pfv/FlowEngine.hpp'
--- pkg/pfv/FlowEngine.hpp	2014-04-03 16:44:33 +0000
+++ pkg/pfv/FlowEngine.hpp	2014-04-07 09:33:19 +0000
@@ -56,16 +56,18 @@
 #ifndef TEMPLATE_FLOW_NAME
 #error You must define TEMPLATE_FLOW_NAME in your source file before including FlowEngine.hpp
 #endif
+
+#ifdef LINSOLV
+#define DEFAULTSOLVER CGT::FlowBoundingSphereLinSolv<_Tesselation>
+#else
+#define DEFAULTSOLVER CGT::FlowBoundingSphere<_Tesselation>
+#endif
 	
-template<class _CellInfo, class _VertexInfo, class _Tesselation=CGT::_Tesselation<CGT::TriangulationTypes<_VertexInfo,_CellInfo> >, class solverT=CGT::FlowBoundingSphere<_Tesselation> >
+template<class _CellInfo, class _VertexInfo, class _Tesselation=CGT::_Tesselation<CGT::TriangulationTypes<_VertexInfo,_CellInfo> >, class solverT=DEFAULTSOLVER >
 class TemplateFlowEngine : public PartialEngine
 {	
 	public :
-		#ifdef LINSOLV
-		typedef CGT::FlowBoundingSphereLinSolv<typename solverT::Tesselation,solverT>	FlowSolver;
-		#else
 		typedef solverT									FlowSolver;
-		#endif
 		typedef FlowSolver								Solver;//FIXME: useless alias, search/replace then remove
 		typedef typename FlowSolver::Tesselation					Tesselation;
 		typedef typename FlowSolver::RTriangulation					RTriangulation;
@@ -227,8 +229,8 @@
 			solver->T[solver->currentTes].computeVolumes();
 		}
 		Real getVolume (Body::id_t id) {
-			if (solver->T[solver->currentTes].Max_id() <= 0) {emulateAction(); LOG_WARN("Not triangulated yet, emulating action");}
-			if (solver->T[solver->currentTes].Volume(id) == -1) {compTessVolumes(); LOG_WARN("Computing all volumes now, as you did not request it explicitely.");}
+			if (solver->T[solver->currentTes].Max_id() <= 0) {emulateAction(); /*LOG_WARN("Not triangulated yet, emulating action");*/}
+			if (solver->T[solver->currentTes].Volume(id) == -1) {compTessVolumes();/* LOG_WARN("Computing all volumes now, as you did not request it explicitely.");*/}
 			return (solver->T[solver->currentTes].Max_id() >= id) ? solver->T[solver->currentTes].Volume(id) : -1;}
 
 		YADE_CLASS_PYCLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(TemplateFlowEngine,TEMPLATE_FLOW_NAME,PartialEngine,"An engine to solve flow problem in saturated granular media. Model description can be found in [Chareyre2012a]_ and [Catalano2014a]_. See the example script FluidCouplingPFV/oedometer.py. More documentation to come.\n\n.. note::Multi-threading seems to work fine for Cholesky decomposition, but it fails for the solve phase in which -j1 is the fastest, here we specify thread numbers independently using :yref:`FlowEngine::numFactorizeThreads` and :yref:`FlowEngine::numSolveThreads`. These multhreading settings are only impacting the behaviour of openblas library and are relatively independant of :yref:`FlowEngine::multithread`. However, the settings have to be globally consistent. For instance, :yref:`multithread<FlowEngine::multithread>` =True with  yref:`numFactorizeThreads<FlowEngine::numFactorizeThreads>` = yref:`numSolveThreads<FlowEngine::numSolveThreads>` = 4 implies that openblas will mobilize 8 processors at some point. If the system does not have so many procs. it will hurt performance.",
@@ -426,7 +428,7 @@
 	inline CVector& force (void) {return forces;}
 	inline CVector& vel (void) {return grainVelocity;}
 	inline Real& volCells (void) {return volumeIncidentCells;}
-	inline const CVector ghostShift (void) {return CGAL::NULL_VECTOR;}
+	inline const CVector ghostShift (void) const {return CGAL::NULL_VECTOR;}
 };
 
 

=== modified file 'pkg/pfv/FlowEngine.ipp'
--- pkg/pfv/FlowEngine.ipp	2014-04-03 13:37:55 +0000
+++ pkg/pfv/FlowEngine.ipp	2014-04-07 09:33:19 +0000
@@ -219,7 +219,7 @@
         flow.meanKStat = meanKStat;
         flow.permeabilityMap = permeabilityMap;
         flow.fluidBulkModulus = fluidBulkModulus;
-        flow.T[flow.currentTes].Clear();
+//         flow.T[flow.currentTes].Clear();
         flow.T[flow.currentTes].maxId=-1;
         flow.xMin = 1000.0, flow.xMax = -10000.0, flow.yMin = 1000.0, flow.yMax = -10000.0, flow.zMin = 1000.0, flow.zMax = -10000.0;
 }
@@ -245,13 +245,12 @@
 template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
 void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::buildTriangulation ( double pZero, Solver& flow )
 {
-        flow.resetNetwork();
-	if (first) flow.currentTes=0;
+ 	if (first) flow.currentTes=0;
         else {
                 flow.currentTes=!flow.currentTes;
                 if (debug) cout << "--------RETRIANGULATION-----------" << endl;
         }
-
+	flow.resetNetwork();
 	initSolver(flow);
 
         addBoundary ( flow );
@@ -597,8 +596,10 @@
 
 
 		for ( int i=0; i< ( int ) flow.edgeIds.size(); i++ ) {
-			const int& id1 = flow.edgeIds[i].first;
-			const int& id2 = flow.edgeIds[i].second;
+			const VertexInfo& vi1 = *flow.edgeIds[i].first;
+			const VertexInfo& vi2 = *flow.edgeIds[i].second;
+			const int& id1 = vi1.id();
+			const int& id2 = vi2.id();
 			
 			int hasFictious= Tes.vertex ( id1 )->info().isFictious +  Tes.vertex ( id2 )->info().isFictious;
 			if (hasFictious>0 or id1==id2) continue;
@@ -613,7 +614,7 @@
 			Vector3r shearLubF; Vector3r normaLubF; Vector3r pumpT; Vector3r deltaAngNormVel; Vector3r twistT; Vector3r angVel1; Vector3r angVel2; 
 		//FIXME: if periodic and velGrad!=0, then deltaV should account for velGrad, not the case currently
 			if ( !hasFictious ){
-				O1O2Vector = sph2->state->pos + makeVector3r(Tes.vertex(id2)->info().ghostShift()) - sph1->state->pos - makeVector3r(Tes.vertex(id1)->info().ghostShift());
+				O1O2Vector = sph2->state->pos + makeVector3r(vi2.ghostShift()) - sph1->state->pos - makeVector3r(vi1.ghostShift());
 				O1O2 = O1O2Vector.norm(); 
 				normal= (O1O2Vector/O1O2);
 				surfaceDist = O1O2 - r2 - r1;

=== modified file 'pkg/pfv/PeriodicFlowEngine.cpp'
--- pkg/pfv/PeriodicFlowEngine.cpp	2014-04-03 13:37:55 +0000
+++ pkg/pfv/PeriodicFlowEngine.cpp	2014-04-07 09:33:19 +0000
@@ -9,9 +9,109 @@
 #ifdef YADE_CGAL
 #ifdef FLOW_ENGINE
 
+/// The periodic variant of FlowEngine is defined here. It should become a template class for more flexibility.
+/// It is a bit more complicated as for FlowEngine, though, because we need template inheriting from template, which breaks YADE_CLASS_XXX logic_error
+/// See below the commented exemple, for a possible solution
+
 #define TEMPLATE_FLOW_NAME FlowEngine_PeriodicInfo
-#include "PeriodicFlowEngine.hpp"
-#undef TEMPLATE_FLOW_NAME
+#include <yade/pkg/pfv/FlowEngine.hpp>
+
+class PeriodicCellInfo : public FlowCellInfo
+{	
+	public:
+	static CVector gradP;
+	//for real cell, baseIndex is the rank of the cell in cellHandles. For ghost cells, it is the baseIndex of the corresponding real cell.
+	//Unlike ordinary index, baseIndex is also indexing cells with imposed pressures
+	int baseIndex;
+	int period[3];
+	static CVector hSize[3];
+	static CVector deltaP;
+	int ghost;
+	Real* _pression;
+	PeriodicCellInfo (void){
+		_pression=&pression;
+		period[0]=period[1]=period[2]=0;
+		baseIndex=-1;
+		volumeSign=0;}
+	~PeriodicCellInfo (void) {}
+
+	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 void setP (const Real& p) {pression=p;}
+	bool isReal (void) {return !(isFictious || isGhost);}
+};
+
+
+class PeriodicVertexInfo : public FlowVertexInfo {
+	public:
+	PeriodicVertexInfo& operator= (const CVector &u) { CVector::operator= (u); return *this; }
+	PeriodicVertexInfo& operator= (const float &scalar) { s=scalar; return *this; }
+	PeriodicVertexInfo& operator= (const unsigned int &id) { i= id; return *this; }
+	int period[3];
+	//FIXME: the name is misleading, even non-ghost can be out of the period and therefore they need to be shifted as well
+	inline const CVector ghostShift (void) const {
+		return period[0]*PeriodicCellInfo::hSize[0]+period[1]*PeriodicCellInfo::hSize[1]+period[2]*PeriodicCellInfo::hSize[2];}
+	PeriodicVertexInfo (void) {isFictious=false; s=0; i=0; period[0]=period[1]=period[2]=0; isGhost=false;}
+	bool isReal (void) {return !(isFictious || isGhost);}
+};
+
+typedef CGT::TriangulationTypes<PeriodicVertexInfo,PeriodicCellInfo>			PeriFlowTriangulationTypes;
+typedef CGT::PeriodicTesselation<CGT::_Tesselation<PeriFlowTriangulationTypes> >	PeriFlowTesselation;
+#ifdef LINSOLV
+#define _PeriFlowSolver CGT::PeriodicFlowLinSolv<PeriFlowTesselation>
+#else
+#define _PeriFlowSolver CGT::PeriodicFlow<PeriFlowTesselation>
+#endif
+
+typedef TemplateFlowEngine<	PeriodicCellInfo,
+				PeriodicVertexInfo,
+				CGT::PeriodicTesselation<CGT::_Tesselation<CGT::TriangulationTypes<PeriodicVertexInfo,PeriodicCellInfo> > >,
+				_PeriFlowSolver>
+				FlowEngine_PeriodicInfo;
+
+REGISTER_SERIALIZABLE(FlowEngine_PeriodicInfo);
+YADE_PLUGIN((FlowEngine_PeriodicInfo));
+
+
+class PeriodicFlowEngine : public FlowEngine_PeriodicInfo
+{
+	public :
+		void triangulate (FlowSolver& flow);
+		void buildTriangulation (Real pzero, FlowSolver& flow);
+		void initializeVolumes (FlowSolver&  flow);
+		void updateVolumes (FlowSolver&  flow);
+		Real volumeCell (CellHandle cell);
+
+		Real volumeCellSingleFictious (CellHandle cell);
+		inline void locateCell(CellHandle baseCell, unsigned int& index, int& baseIndex, FlowSolver& flow, unsigned int count=0);
+		Vector3r meanVelocity();
+
+		virtual ~PeriodicFlowEngine();
+
+		virtual void action();
+		//Cache precomputed values for pressure shifts, based on current hSize and pGrad
+		void preparePShifts();
+		
+		YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(PeriodicFlowEngine,FlowEngine_PeriodicInfo,"A variant of :yref:`FlowEngine` implementing periodic boundary conditions. The API is very similar.",
+		((Real,duplicateThreshold, 0.06,,"distance from cell borders that will triger periodic duplication in the triangulation |yupdate|"))
+		((Vector3r, gradP, Vector3r::Zero(),,"Macroscopic pressure gradient"))
+		,,
+		wallIds=vector<int>(6,-1);
+		solver = shared_ptr<FlowSolver> (new FlowSolver);
+		epsVolMax=epsVolCumulative=retriangulationLastIter=0;
+		ReTrg=1;
+		first=true;
+		,
+		//nothing special to define, we re-use FlowEngine methods
+		//.def("meanVelocity",&PeriodicFlowEngine::meanVelocity,"measure the mean velocity in the period")
+		)
+		DECLARE_LOGGER;
+
+
+};
+REGISTER_SERIALIZABLE(PeriodicFlowEngine);
+
 
 CVector PeriodicCellInfo::hSize[]={CVector(),CVector(),CVector()};
 CVector PeriodicCellInfo::deltaP=CVector();
@@ -382,11 +482,11 @@
 
 void PeriodicFlowEngine::buildTriangulation ( double pZero, FlowSolver& flow)
 {
-        flow.resetNetwork();
         if (first) flow.currentTes=0;
         else {
                 flow.currentTes=!flow.currentTes;
                 if ( debug ) cout << "--------RETRIANGULATION-----------" << endl;}
+	flow.resetNetwork();
         initSolver(flow);
         addBoundary ( flow );
         if ( debug ) cout << endl << "Added boundaries------" << endl << endl;
@@ -445,8 +545,6 @@
 
 
 YADE_PLUGIN((PeriodicFlowEngine));
-
-
 #endif //FLOW_ENGINE
 
 #endif /* YADE_CGAL */
\ No newline at end of file

=== modified file 'pkg/pfv/PeriodicFlowEngine.hpp'
--- pkg/pfv/PeriodicFlowEngine.hpp	2014-04-03 16:44:33 +0000
+++ pkg/pfv/PeriodicFlowEngine.hpp	2014-04-07 09:33:19 +0000
@@ -6,104 +6,3 @@
 *  GNU General Public License v2 or later. See file LICENSE for details. *
 *************************************************************************/
 
-/// The periodic variant of FlowEngine is defined here. It should become a template class for more flexibility.
-/// It is a bit more complicated as for FlowEngine, though, because we need template inheriting from template, which breaks YADE_CLASS_XXX logic_error
-/// See below the commented exemple, for a possible solution
-
-#include <yade/pkg/pfv/FlowEngine.hpp>
-
-class PeriodicCellInfo : public FlowCellInfo
-{	
-	public:
-	static CVector gradP;
-	//for real cell, baseIndex is the rank of the cell in cellHandles. For ghost cells, it is the baseIndex of the corresponding real cell.
-	//Unlike ordinary index, baseIndex is also indexing cells with imposed pressures
-	int baseIndex;
-	int period[3];
-	static CVector hSize[3];
-	static CVector deltaP;
-	int ghost;
-	Real* _pression;
-	PeriodicCellInfo (void){
-		_pression=&pression;
-		period[0]=period[1]=period[2]=0;
-		baseIndex=-1;
-		volumeSign=0;}
-	~PeriodicCellInfo (void) {}
-
-	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 void setP (const Real& p) {pression=p;}
-	bool isReal (void) {return !(isFictious || isGhost);}
-};
-
-
-class PeriodicVertexInfo : public FlowVertexInfo {
-	public:
-	PeriodicVertexInfo& operator= (const CVector &u) { CVector::operator= (u); return *this; }
-	PeriodicVertexInfo& operator= (const float &scalar) { s=scalar; return *this; }
-	PeriodicVertexInfo& operator= (const unsigned int &id) { i= id; return *this; }
-	int period[3];
-	//FIXME: the name is misleading, even non-ghost can be out of the period and therefore they need to be shifted as well
-	inline const CVector ghostShift (void) {
-		return period[0]*PeriodicCellInfo::hSize[0]+period[1]*PeriodicCellInfo::hSize[1]+period[2]*PeriodicCellInfo::hSize[2];}
-	PeriodicVertexInfo (void) {isFictious=false; s=0; i=0; period[0]=period[1]=period[2]=0; isGhost=false;}
-	bool isReal (void) {return !(isFictious || isGhost);}
-};
-
-typedef CGT::TriangulationTypes<PeriodicVertexInfo,PeriodicCellInfo>			PeriFlowTriangulationTypes;
-typedef CGT::PeriodicTesselation<CGT::_Tesselation<PeriFlowTriangulationTypes> >	PeriFlowTesselation;
-#ifdef LINSOLV
-#define _PeriFlowSolver CGT::PeriodicFlowLinSolv<PeriFlowTesselation>
-#else
-#define _PeriFlowSolver CGT::PeriodicFlow<PeriFlowTesselation>
-#endif
-
-typedef TemplateFlowEngine<	PeriodicCellInfo,
-				PeriodicVertexInfo,
-				CGT::PeriodicTesselation<CGT::_Tesselation<CGT::TriangulationTypes<PeriodicVertexInfo,PeriodicCellInfo> > >,
-				_PeriFlowSolver>
-				FlowEngine_PeriodicInfo;
-
-REGISTER_SERIALIZABLE(FlowEngine_PeriodicInfo);
-YADE_PLUGIN((FlowEngine_PeriodicInfo));
-
-
-class PeriodicFlowEngine : public FlowEngine_PeriodicInfo
-{
-	public :
-		void triangulate (FlowSolver& flow);
-		void buildTriangulation (Real pzero, FlowSolver& flow);
-		void initializeVolumes (FlowSolver&  flow);
-		void updateVolumes (FlowSolver&  flow);
-		Real volumeCell (CellHandle cell);
-
-		Real volumeCellSingleFictious (CellHandle cell);
-		inline void locateCell(CellHandle baseCell, unsigned int& index, int& baseIndex, FlowSolver& flow, unsigned int count=0);
-		Vector3r meanVelocity();
-
-		virtual ~PeriodicFlowEngine();
-
-		virtual void action();
-		//Cache precomputed values for pressure shifts, based on current hSize and pGrad
-		void preparePShifts();
-		
-		YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(PeriodicFlowEngine,FlowEngine_PeriodicInfo,"A variant of :yref:`FlowEngine` implementing periodic boundary conditions. The API is very similar.",
-		((Real,duplicateThreshold, 0.06,,"distance from cell borders that will triger periodic duplication in the triangulation |yupdate|"))
-		((Vector3r, gradP, Vector3r::Zero(),,"Macroscopic pressure gradient"))
-		,,
-		wallIds=vector<int>(6,-1);
-		solver = shared_ptr<FlowSolver> (new FlowSolver);
-		epsVolMax=epsVolCumulative=retriangulationLastIter=0;
-		ReTrg=1;
-		first=true;
-		,
-		//nothing special to define, we re-use FlowEngine methods
-		//.def("meanVelocity",&PeriodicFlowEngine::meanVelocity,"measure the mean velocity in the period")
-		)
-		DECLARE_LOGGER;
-
-
-};
-REGISTER_SERIALIZABLE(PeriodicFlowEngine);
\ No newline at end of file