yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #12394
[Branch ~yade-pkg/yade/git-trunk] Rev 3726: Updates towards merging of both capillarity codes
------------------------------------------------------------
revno: 3726
committer: thomassweijen <thomassweijen@xxxxxxx>
timestamp: Thu 2015-09-24 09:25:27 +0200
message:
Updates towards merging of both capillarity codes
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 2015-06-30 14:20:30 +0000
+++ pkg/pfv/TwoPhaseFlowEngine.cpp 2015-09-24 07:25:27 +0000
@@ -16,19 +16,38 @@
#include "TwoPhaseFlowEngine.hpp"
#ifdef TWOPHASEFLOW
-
YADE_PLUGIN((TwoPhaseFlowEngineT));
YADE_PLUGIN((TwoPhaseFlowEngine));
-void TwoPhaseFlowEngine::initializeCellIndex()
+void TwoPhaseFlowEngine::initialization()
{
- int k=0;
- RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
- FiniteCellsIterator cellEnd = tri.finite_cells_end();
- for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
- cell->info().index=k++;}
+ scene = Omega::instance().getScene().get();//here define the pointer to Yade's scene
+ setPositionsBuffer(true);//copy sphere positions in a buffer...
+ buildTriangulation(0.0,*solver);//create a triangulation and initialize pressure in the elements (connecting with W-reservoir), everything will be contained in "solver"
+// initializeCellIndex();//initialize cell index
+// if(isInvadeBoundary) {computePoreThroatRadius();}
+// else {computePoreThroatRadiusTrickyMethod1();}//save pore throat radius before drainage. Thomas, here you can also revert this to computePoreThroatCircleRadius().
+
+ // Determine the entry-pressure
+ if(entryPressureMethod == 1 && isInvadeBoundary){computePoreThroatRadiusMethod1();} //MS-P method
+ else if(entryPressureMethod == 1 && isInvadeBoundary == false){computePoreThroatRadiusTrickyMethod1();} //MS-P method
+ else if(entryPressureMethod == 2){computePoreThroatRadiusMethod2();} //Inscribed circle}
+ else if(entryPressureMethod == 3){computePoreThroatRadiusMethod3();} //Area equivalent circle}
+ else if(entryPressureMethod > 3){cout << endl << "ERROR - Method for determining the entry pressure does not exist";}
+
+ computePoreBodyRadius();//save pore body radius before imbibition
+ computePoreBodyVolume();//save capillary volume of all cells, for fast calculating saturation
+ computeSolidLine();//save cell->info().solidLine[j][y]
+ initializeReservoirs();//initial pressure, reservoir flags and local pore saturation
+ solver->noCache = true;
}
+
+
+
+
+
+
void TwoPhaseFlowEngine::computePoreBodyVolume()
{
initializeVolumes(*solver);
@@ -39,68 +58,9 @@
}
}
-double TwoPhaseFlowEngine:: computePoreSatAtInterface(int ID)
-{
- //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
- RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
- FiniteCellsIterator cellEnd = tri.finite_cells_end();
- for (FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++) {
- if(cell->info().id == ID){
-
- double qout = 0.0, Vw = 0.0, dt = 0.0;
-
- for(unsigned int ngb = 0; ngb < 4; ngb++)
- {
- //find out/influx of water
- if((cell->neighbor(ngb)->info().isWRes) && (cell->neighbor(ngb)->info().isFictious == 0)){
- qout= qout + std::abs(cell->info().kNorm() [ngb])*(cell->info().p()-cell->neighbor ( ngb )->info().p());
- }
- }
-
- Vw = (cell->info().saturation * cell->info().poreBodyVolume) - (qout * scene->dt);
-
- //Functionality to calculate the smallest time step
- if((1e-16 < Vw) && (Vw < 1e16)){
- if((1e-16 < qout) && (qout < 1e16)){
- dt = (Vw / qout);
- if(dt!=0.0){dtDynTPF = std::min(dt,dtDynTPF);}
- }
- }
- 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;}
- return cell->info().saturation;
- }
-}
-}
-
-
-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::computePoreThroatCircleRadius()
+
+
+void TwoPhaseFlowEngine::computePoreThroatRadiusMethod2()
{
//Calculate the porethroat radii of the inscribed sphere in each pore-body.
RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
@@ -112,6 +72,20 @@
}
}
+void TwoPhaseFlowEngine::computePoreThroatRadiusMethod3()
+{
+ //Calculate the porethroat radii of the surface equal circle of a throat
+ 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->computeEquivalentRadius(cell,i);
+ }
+ }
+}
+
+
+
void TwoPhaseFlowEngine::computePoreBodyRadius()
{
@@ -256,7 +230,7 @@
}
}
-void TwoPhaseFlowEngine::computePoreThroatRadius()
+void TwoPhaseFlowEngine::computePoreThroatRadiusMethod1()
{
RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
FiniteCellsIterator cellEnd = tri.finite_cells_end();
@@ -437,9 +411,9 @@
}
vtkfile.end_data();
}
-void TwoPhaseFlowEngine::computePoreThroatRadiusTricky()
+void TwoPhaseFlowEngine::computePoreThroatRadiusTrickyMethod1()
{
- computePoreThroatRadius();
+ computePoreThroatRadiusMethod1();
RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
FiniteCellsIterator cellEnd = tri.finite_cells_end();
CellHandle neighbourCell;
@@ -453,20 +427,7 @@
}
}
-void TwoPhaseFlowEngine::initialization()
-{
- scene = Omega::instance().getScene().get();//here define the pointer to Yade's scene
- setPositionsBuffer(true);//copy sphere positions in a buffer...
- buildTriangulation(0.0,*solver);//create a triangulation and initialize pressure in the elements (connecting with W-reservoir), everything will be contained in "solver"
-// initializeCellIndex();//initialize cell index
- if(isInvadeBoundary) {computePoreThroatRadius();}
- else {computePoreThroatRadiusTricky();}//save pore throat radius before drainage. Thomas, here you can also revert this to computePoreThroatCircleRadius().
- computePoreBodyRadius();//save pore body radius before imbibition
- computePoreBodyVolume();//save capillary volume of all cells, for fast calculating saturation
- computeSolidLine();//save cell->info().solidLine[j][y]
- initializeReservoirs();//initial pressure, reservoir flags and local pore saturation
- solver->noCache = true;
-}
+
void TwoPhaseFlowEngine::computeSolidLine()
{
@@ -526,5 +487,172 @@
}
+void TwoPhaseFlowEngine::savePoreNetwork()
+{
+ std::ofstream filePoreBodyRadius;
+ std::cout << "Opening File: " << "PoreBodyRadius" << std::endl;
+ filePoreBodyRadius.open("PoreBodyRadius.txt", std::ios::trunc);
+ if(!filePoreBodyRadius.is_open()){
+ std::cerr<< "Error opening file [" << "PoreBodyRadius" << ']' << std::endl;
+ return;
+ }
+
+ std::ofstream filePoreBoundary;
+ std::cout << "Opening File: " << "PoreBoundary" << std::endl;
+ filePoreBoundary.open("PoreBoundary.txt" , std::ios::trunc);
+ if(!filePoreBoundary.is_open()){
+ std::cerr<< "Error opening file [" << "PoreBoundary" << ']' << std::endl;
+ return;
+ }
+
+ std::ofstream filePoreBodyVolume;
+ std::cout << "Opening File: " << "PoreBodyVolume" << std::endl;
+ filePoreBodyVolume.open("PoreBodyVolume.txt", std::ios::trunc);
+ if(!filePoreBodyVolume.is_open()){
+ std::cerr<< "Error opening file [" << "PoreBodyVolume" << ']' << std::endl;
+ return;
+ }
+ std::ofstream fileLocation;
+ std::cout << "Opening File: " << "Location" << std::endl;
+ fileLocation.open("Location.txt", std::ios::trunc);
+ if(!fileLocation.is_open()){
+ std::cerr<< "Error opening file [" << "fileLocation" << ']' << std::endl;
+ return;
+ }
+
+ std::ofstream fileNeighbor;
+ std::cout << "Opening File: " << "fileNeighbor" << std::endl;
+ fileNeighbor.open("neighbor.txt", std::ios::trunc);
+ if(!filePoreBoundary.is_open()){
+ std::cerr<< "Error opening file [" << "fileNeighbor" << ']' << std::endl;
+ return;
+ }
+
+ std::ofstream fileThroatRadius;
+ std::cout << "Opening File: " << "fileThroatRadius" << std::endl;
+ fileThroatRadius.open("throatRadius.txt", std::ios::trunc);
+ if(!filePoreBoundary.is_open()){
+ std::cerr<< "Error opening file [" << "fileThroatRadius" << ']' << std::endl;
+ return;
+ }
+ std::ofstream fileThroats;
+ std::cout << "Opening File: " << "fileThroats" << std::endl;
+ fileThroats.open("Throats.txt", std::ios::trunc);
+ if(!filePoreBoundary.is_open()){
+ std::cerr<< "Error opening file [" << "fileThroats" << ']' << std::endl;
+ return;
+ }
+
+
+ cout << solver->T[solver->currentTes].cellHandles.size();
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for (FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ if(cell->info().isGhost == false && cell->info().id < solver->T[solver->currentTes].cellHandles.size()){
+ filePoreBodyRadius << cell->info().poreBodyRadius << '\n';
+ filePoreBodyVolume << cell->info().poreBodyRadius << '\n';
+ CVector center ( 0,0,0 );
+ for ( int k=0;k<4;k++ ){ center= center + 0.25* (cell->vertex(k)->point()-CGAL::ORIGIN);}
+
+ fileLocation << center<< '\n';
+ for (unsigned int i=0;i<4;i++){
+ if(cell->neighbor(i)->info().isGhost == false && cell->neighbor(i)->info().id < solver->T[solver->currentTes].cellHandles.size() && (cell->info().id < cell->neighbor(i)->info().id)){
+ fileNeighbor << cell->neighbor(i)->info().id << '\n';
+ fileThroatRadius << cell->info().poreThroatRadius[i] << '\n';
+ fileThroats << cell->info().id << " " << cell->neighbor(i)->info().id << '\n';
+ }
+ }
+
+ }
+
+ if(cell->info().isFictious == 1 && cell->info().isGhost == false && cell->info().id < solver->T[solver->currentTes].cellHandles.size()){
+ //add boundary condition
+ if(cell->info().isFictious == 1 &&(cell->vertex(0)->info().id() == 3 || cell->vertex(1)->info().id() == 3 || cell->vertex(2)->info().id() == 3 || cell->vertex(3)->info().id() == 3)){
+ filePoreBoundary << "3" << '\n';
+ }
+ else if(cell->info().isFictious == 1 &&(cell->vertex(0)->info().id() == 2 || cell->vertex(1)->info().id() == 2 || cell->vertex(2)->info().id() == 2 || cell->vertex(3)->info().id() == 2)){
+ filePoreBoundary << "2" << '\n';
+ }
+ else{filePoreBoundary << "2" << '\n';}
+ }
+ if(cell->info().isFictious == 0 && cell->info().isGhost == false && cell->info().id < solver->T[solver->currentTes].cellHandles.size()){
+ filePoreBoundary << "0" << '\n';
+ }
+}
+
+
+ filePoreBodyRadius.close();
+ filePoreBoundary.close();
+ filePoreBodyVolume.close();
+ fileLocation.close();
+ fileNeighbor.close();
+ fileThroatRadius.close();
+
+
+}
+
+
+double TwoPhaseFlowEngine:: computePoreSatAtInterface(int ID)
+{
+// //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
+// RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+// FiniteCellsIterator cellEnd = tri.finite_cells_end();
+// for (FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++) {
+// if(cell->info().id == ID){
+//
+// double qout = 0.0, Vw = 0.0, dt = 0.0;
+//
+// for(unsigned int ngb = 0; ngb < 4; ngb++)
+// {
+// //find out/influx of water
+// if((cell->neighbor(ngb)->info().isWRes) && (cell->neighbor(ngb)->info().isFictious == 0)){
+// qout= qout + std::abs(cell->info().kNorm() [ngb])*(cell->info().p()-cell->neighbor ( ngb )->info().p());
+// }
+// }
+//
+// Vw = (cell->info().saturation * cell->info().poreBodyVolume) - (qout * scene->dt);
+//
+// //Functionality to calculate the smallest time step
+// if((1e-16 < Vw) && (Vw < 1e16)){
+// if((1e-16 < qout) && (qout < 1e16)){
+// dt = (Vw / qout);
+// if(dt!=0.0){dtDynTPF = std::min(dt,dtDynTPF);}
+// }
+// }
+// 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;}
+// return cell->info().saturation;
+// }
+// }
+ return 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; */
+}
+
#endif //TwoPhaseFLOW
=== modified file 'pkg/pfv/TwoPhaseFlowEngine.hpp'
--- pkg/pfv/TwoPhaseFlowEngine.hpp 2015-06-30 14:20:30 +0000
+++ pkg/pfv/TwoPhaseFlowEngine.hpp 2015-09-24 07:25:27 +0000
@@ -13,9 +13,8 @@
//keep this #ifdef as long as you don't really want to realize a final version publicly, it will save compilation time for everyone else
//when you want it compiled, you can pass -DTWOPHASEFLOW to cmake, or just uncomment the following line
-// #define TWOPHASEFLOW
+//#define TWOPHASEFLOW
#ifdef TWOPHASEFLOW
-
#include "FlowEngine_TwoPhaseFlowEngineT.hpp"
/// We can add data to the Info types by inheritance
@@ -68,15 +67,14 @@
//If a new function is specific to the derived engine, put it here, else go to the base TemplateFlowEngine
//if it is useful for everyone
- void initializeCellIndex();
void computePoreBodyVolume();
- void computePoreBodyRadius();
- void computePoreThroatCircleRadius();
+ void computePoreBodyRadius();
+// void computePoreThroatCircleRadius();
double computePoreSatAtInterface(int ID);
void computePoreCapillaryPressure(CellHandle cell);
void savePhaseVtk(const char* folder);
- void computePoreThroatRadius();
- void computePoreThroatRadiusTricky();//set the radius of pore throat between side pores negative.
+// void computePoreThroatRadius();
+// void computePoreThroatRadiusTricky();//set the radius of pore throat between side pores negative.
double computeEffPoreThroatRadius(CellHandle cell, int j);
double computeEffPoreThroatRadiusFine(CellHandle cell, int j);
@@ -87,6 +85,13 @@
void computeSolidLine();
void initializeReservoirs();
+ void computePoreThroatRadiusMethod1();
+ void computePoreThroatRadiusTrickyMethod1();//set the radius of pore throat between side pores negative.
+ void computePoreThroatRadiusMethod2();
+ void computePoreThroatRadiusMethod3();
+ void savePoreNetwork();
+
+
boost::python::list cellporeThroatRadius(unsigned int id){ // Temporary function to allow for simulations in Python, can be easily accessed in c++
boost::python::list ids;
@@ -127,6 +132,8 @@
((bool, isInvadeBoundary, true,,"Invasion side boundary condition. If True, pores of side boundary can be invaded; if False, the pore throats connecting side boundary are closed, those pores are excluded in saturation calculation."))
((bool, drainageFirst, true,,"If true, activate drainage first (initial saturated), then imbibition; if false, activate imbibition first (initial unsaturated), then drainage."))
((double,dtDynTPF,0.0,,"Parameter which stores the smallest time step, based on the residence time"))
+ ((int,entryPressureMethod,1,,"integer to define the method used to determine the pore throat radii and the according entry pressures. 1)radius of entry pore throat based on MS-P method; 2) radius of the inscribed circle; 3) radius of the circle with equivalent surface area of the pore throat."))
+ ((double,partiallySaturatedPores,false,,"Include partially saturated pores or not?"))
,/*TwoPhaseFlowEngineT()*/,
,
@@ -148,6 +155,8 @@
.def("getCellInSphereRadius",&TwoPhaseFlowEngine::cellInSphereRadius,"get the radius of the inscribed sphere in a pore unit")
.def("getCellVoidVolume",&TwoPhaseFlowEngine::cellVoidVolume,"get the volume of pore space in each pore unit")
.def("setCellHasInterface",&TwoPhaseFlowEngine::setCellHasInterface,"change wheter a cell has a NW-W interface")
+ .def("savePoreNetwork",&TwoPhaseFlowEngine::savePoreNetwork,"Extract the pore network of the granular material")
+
)
DECLARE_LOGGER;
};