← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-pkg/yade/git-trunk] Rev 3465: Merge branch 'master' of github.com:yade/trunk

 

Merge authors:
  T Sweijen <thomasje100@xxxxxxxxxxx>
------------------------------------------------------------
revno: 3465 [merge]
committer: Chao Yuan <chaoyuan2012@xxxxxxxxx>
timestamp: Mon 2014-10-13 14:21:20 +0200
message:
  Merge branch 'master' of github.com:yade/trunk
  
  Conflicts:
  	pkg/pfv/TwoPhaseFlowEngine.cpp
  	pkg/pfv/TwoPhaseFlowEngine.hpp
modified:
  pkg/pfv/TwoPhaseFlowEngine.cpp
  pkg/pfv/TwoPhaseFlowEngine.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 'pkg/pfv/TwoPhaseFlowEngine.cpp'
--- pkg/pfv/TwoPhaseFlowEngine.cpp	2014-10-13 12:12:57 +0000
+++ pkg/pfv/TwoPhaseFlowEngine.cpp	2014-10-13 12:21:20 +0000
@@ -19,6 +19,7 @@
 #include "TwoPhaseFlowEngine.hpp"
 
 YADE_PLUGIN((TwoPhaseFlowEngineT));
+
 YADE_PLUGIN((TwoPhaseFlowEngine));
 
 void TwoPhaseFlowEngine::fancyFunction(Real what) {std::cerr<<"yes, I'm a new function"<<std::endl;}
@@ -43,5 +44,207 @@
     }
 }
 
+void TwoPhaseFlowEngine:: computePoreSatAtInterface(CellHandle cell)
+{
+    //This function calculates the new saturation of pore at the interface between wetting/nonwetting 
+    //filled pores. It substracts the outgoing flux from the water volume  
+    double qout = 0.0, Vw = 0.0;
+    
+    for(unsigned int ngb = 0; ngb < 4; ngb++)
+    {
+      //find out/influx of water
+      if(cell->neighbor(ngb)->info().isWRes){
+	qout= qout + std::abs(cell->info().kNorm() [ngb])*(cell->neighbor ( ngb )->info().p()-cell->info().p());    
+      }
+    }
+   
+    Vw = cell->info().saturation * cell->info().poreBodyVolume - (qout * scene->dt);  
+    cell->info().saturation = Vw / cell->info().poreBodyVolume;
+   
+   
+   // The following constrains check the value of saturation
+    if(std::abs(cell->info().saturation) < 1e-6){cell->info().saturation = 0.0;} // To prevent dt going to 0
+    if(cell->info().saturation < 0.0){
+      cout << endl << "dt was too large!, negative saturation in cell "<< cell->info().id;
+      cell->info().saturation = 0.0;    
+      }
+    if(cell->info().saturation > 1.0){
+      cout << endl <<"dt was too large!,saturation larger than 1 in cell " << cell->info().id;
+      cell->info().saturation = 1.0;}
+}
+
+void TwoPhaseFlowEngine:: computePoreCapillaryPressure(CellHandle cell)
+{
+  //This formula relates the pore-saturation to the capillary-pressure, and the water-pressure
+  //based on Joekar-Niasar, for cubic pores. NOTE: Needs to be changed into a proper set of equations 
+
+  double Re = 0.0, Pc = 0.0, Pg = 0.0;  
+  
+  for(unsigned int i = 0; i<4;i++)
+  {
+    Re = max(Re,cell->info().poreThroatRadius[i]);
+  }
+  Pc = surfaceTension / (Re * (1.0-exp(-6.83 * cell->info().saturation)));
+  Pg = std::max(bndCondValue[2],bndCondValue[3]);
+  cell->info().p() = Pg - Pc; 
+}
+
+void TwoPhaseFlowEngine::computePoreThroatRadius()
+{
+  //Calculate the porethroat radii of the inscribed sphere in each pore-body. 
+  RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+  FiniteCellsIterator cellEnd = tri.finite_cells_end();
+  for (FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++) {
+    for(unsigned int i = 0; i<4;i++){
+    cell->info().poreThroatRadius[i] = solver->computeEffectiveRadius(cell,i);
+    }
+  }
+}
+
+void TwoPhaseFlowEngine::computePoreBodyRadius()
+{
+  
+    // This routine finds the radius of the inscribed sphere within each pore-body
+    // Following Mackay et al., 1972. 
+      double d01 = 0.0, d02 = 0.0, d03 = 0.0, d12 = 0.0, d13 = 0.0, d23 = 0.0, Rin = 0.0, r0 = 0.0, r1 = 0.0, r2 =0.0, r3 = 0.0;
+      bool check = false;
+      unsigned int i = 0;
+      double dR=0.0, tempR = 0.0;
+      bool initialSign = false; //False = negative, true is positive
+      bool first = true;
+      
+      Eigen::MatrixXd M(6,6);
+      
+      FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles){
+	//Distance between multiple particles, can be done more efficient
+	d01 = d02 = d03 = d12 = d13 = d23 = r0 = r1 = r2= r3 = 0.0;
+	
+	d01 = pow((cell->vertex(0)->point().x()-cell->vertex(1)->point().x()),2)+
+	pow((cell->vertex(0)->point().y()-cell->vertex(1)->point().y()),2)+
+	pow((cell->vertex(0)->point().z()-cell->vertex(1)->point().z()),2);
+	
+	d02 = pow((cell->vertex(0)->point().x()-cell->vertex(2)->point().x()),2)+
+	pow((cell->vertex(0)->point().y()-cell->vertex(2)->point().y()),2)+
+	pow((cell->vertex(0)->point().z()-cell->vertex(2)->point().z()),2);
+	
+	d03 = pow((cell->vertex(0)->point().x()-cell->vertex(3)->point().x()),2)+
+	pow((cell->vertex(0)->point().y()-cell->vertex(3)->point().y()),2)+
+	pow((cell->vertex(0)->point().z()-cell->vertex(3)->point().z()),2);
+	
+	d12 =pow((cell->vertex(1)->point().x()-cell->vertex(2)->point().x()),2)+
+	pow((cell->vertex(1)->point().y()-cell->vertex(2)->point().y()),2)+
+	pow((cell->vertex(1)->point().z()-cell->vertex(2)->point().z()),2);
+	
+	d13 = pow((cell->vertex(1)->point().x()-cell->vertex(3)->point().x()),2)+
+	pow((cell->vertex(1)->point().y()-cell->vertex(3)->point().y()),2)+
+	pow((cell->vertex(1)->point().z()-cell->vertex(3)->point().z()),2);
+	
+	d23 = pow((cell->vertex(2)->point().x()-cell->vertex(3)->point().x()),2)+
+	pow((cell->vertex(2)->point().y()-cell->vertex(3)->point().y()),2)+
+	pow((cell->vertex(2)->point().z()-cell->vertex(3)->point().z()),2);
+	
+	//Radii of the particles
+	r0 = sqrt(cell -> vertex(0) -> point().weight());
+	r1 = sqrt(cell -> vertex(1) -> point().weight());
+	r2 = sqrt(cell -> vertex(2) -> point().weight());
+	r3 = sqrt(cell -> vertex(3) -> point().weight());	
+	
+	//Fill coefficient matrix
+	M(0,0) = 0.0;
+	M(1,0) = d01;
+	M(2,0) = d02;
+	M(3,0) = d03;
+	M(4,0) = pow((r0+Rin),2);
+	M(5,0) = 1.0;
+	
+	M(0,1) = d01;
+	M(1,1) = 0.0;
+	M(2,1) = d12;
+	M(3,1) = d13;
+	M(4,1) = pow((r1+Rin),2);
+	M(5,1) = 1.0;
+	
+	M(0,2) = d02; 
+	M(1,2) = d12;
+	M(2,2) = 0.0;
+	M(3,2) = d23;
+	M(4,2) = pow((r2+Rin),2);
+	M(5,2) = 1.0;
+	
+	M(0,3) = d03;
+	M(1,3) = d13;
+	M(2,3) = d23;
+	M(3,3) = 0.0;
+	M(4,3) = pow((r3+Rin),2);
+	M(5,3) = 1.0;
+	
+	M(0,4) = pow((r0+Rin),2);
+	M(1,4) = pow((r1+Rin),2);
+	M(2,4) = pow((r2+Rin),2);
+	M(3,4) = pow((r3+Rin),2);
+	M(4,4) = 0.0;
+	M(5,4) = 1.0;
+	
+	M(0,5) = 1.0;
+	M(1,5) = 1.0;
+	M(2,5) = 1.0;
+	M(3,5) = 1.0;
+	M(4,5) = 1.0;
+	M(5,5) = 0.0;
+	
+	i = 0;
+	check = false;
+	dR = Rin = 0.0 + (min(r0,min(r1,min(r2,r3))) / 50.0); //Estimate an initial dR
+	first = true;
+	//Iterate untill check = true, such that an accurate answer as been found
+	while (check == false){
+	  i = i + 1;
+	  tempR = Rin;
+	  Rin = Rin + dR;
+	
+	  M(4,0) = pow((r0+Rin),2);
+	  M(4,1) = pow((r1+Rin),2);
+	  M(4,2) = pow((r2+Rin),2);
+	  M(4,3) = pow((r3+Rin),2);
+	  M(0,4) = pow((r0+Rin),2);
+	  M(1,4) = pow((r1+Rin),2);
+	  M(2,4) = pow((r2+Rin),2);
+	  M(3,4) = pow((r3+Rin),2);
+	
+	
+	  if (first){
+	    first = false;
+	    if(M.determinant() < 0.0){initialSign = false;} //Initial D is negative
+	    if(M.determinant() > 0.0){initialSign = true;} // Initial D is positive
+	  }
+	
+	  if(std::abs(M.determinant()) < 1E-30){check = true;}	
+	
+	  if((initialSign==true) && (check ==false)){
+	    if(M.determinant() < 0.0){
+	      Rin = Rin -dR;
+	      dR = dR / 2.0; 
+	    }	  
+	  }
+	
+	  if((initialSign==false) && (check ==false)){
+	    if(M.determinant() > 0.0){
+	      Rin = Rin -dR;
+	      dR = dR / 2.0;  
+	    }	  
+	  }
+	
+	  cout << endl << i << " "<<Rin << " "<< dR << " "<< M.determinant();
+	  if(i > 4000){
+	    cout << endl << "error, finding solution takes too long cell:" << cell->info().id;
+	    check = true;
+	  }
+	  if ( std::abs(tempR - Rin)/Rin < 0.001){check = true;}
+	
+      }
+    cell -> info().poreBodyRadius = Rin;
+   }
+}
+
 #endif //TwoPhaseFLOW
  

=== modified file 'pkg/pfv/TwoPhaseFlowEngine.hpp'
--- pkg/pfv/TwoPhaseFlowEngine.hpp	2014-10-13 12:12:57 +0000
+++ pkg/pfv/TwoPhaseFlowEngine.hpp	2014-10-13 12:21:20 +0000
@@ -25,9 +25,10 @@
 	bool isNWRes;
 	bool isTrapW;
 	bool isTrapNW;
-	double saturation;//the saturation of single pore (will be used in imbibition)
+	double saturation;//the saturation of single pore (will be used in quasi-static imbibition and dynamic flow)
 	bool isImbibition;//Flag for marking pore unit which contains NW-W interface (used by Thomas)
 	double trapCapP;//for calculating the pressure of trapped pore, cell->info().p() = pressureNW- trapCapP. OR cell->info().p() = pressureW + trapCapP
+	bool hasInterface; //Indicated whether a NW-W interface is present within the pore body
 	std::vector<double> poreThroatRadius;
 	double poreBodyRadius;
 	double poreBodyVolume;
@@ -38,7 +39,7 @@
 	{
 		isWRes = true; isNWRes = false; isTrapW = false; isTrapNW = false;
 		saturation = 1.0;
-		isImbibition = false;
+		hasInterface = false;
 		trapCapP = 0;
 		poreThroatRadius.resize(4, 0);
 		poreBodyRadius = 0;
@@ -70,6 +71,10 @@
 	void fancyFunction(Real what);
 	void initializeCellIndex();
 	void computePoreBodyVolume();	
+	void computePoreBodyRadius();
+	void computePoreThroatRadius();
+	void computePoreSatAtInterface(CellHandle cell);
+	void computePoreCapillaryPressure(CellHandle cell);
 
 	YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(TwoPhaseFlowEngine,TwoPhaseFlowEngineT,"documentation here",
 	((double,surfaceTension,0.0728,,"Water Surface Tension in contact with air at 20 Degrees Celsius is: 0.0728(N/m)"))