yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #11422
[Branch ~yade-pkg/yade/git-trunk] Rev 3418: -big change, inherit from FlowEngine.
------------------------------------------------------------
revno: 3418
committer: Chao Yuan <chaoyuan2012@xxxxxxxxx>
timestamp: Fri 2014-05-09 16:29:16 +0200
message:
-big change, inherit from FlowEngine.
added:
pkg/pfv/UnsaturatedEngine.cpp
--
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
=== added file 'pkg/pfv/UnsaturatedEngine.cpp'
--- pkg/pfv/UnsaturatedEngine.cpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/UnsaturatedEngine.cpp 2014-05-09 14:29:16 +0000
@@ -0,0 +1,1065 @@
+/*************************************************************************
+* Copyright (C) 2012 by Chao Yuan <chao.yuan@xxxxxxxxxxxxxxx> *
+* Copyright (C) 2012 by Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> *
+* *
+* This program is free software; it is licensed under the terms of the *
+* GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+#ifdef FLOW_ENGINE
+
+//keep this #ifdef for commited versions unless you really have stable version that should be compiled by default
+//it will save compilation time for everyone else
+//when you want it compiled, you can pass -DDFNFLOW to cmake, or just uncomment the following line
+#define UNSATURATED_FLOW
+#ifdef UNSATURATED_FLOW
+#define TEMPLATE_FLOW_NAME UnsaturatedEngineT
+#include <yade/pkg/pfv/FlowEngine.hpp>
+
+/// We can add data to the Info types by inheritance
+class UnsatCellInfo : public FlowCellInfo {
+ public:
+ bool isWaterReservoir;
+ bool isAirReservoir;
+ Real capillaryCellVolume;//abs(cell.volume) - abs(cell.solid.volume)
+ std::vector<double> poreRadius;//pore throat radius for drainage
+ double solidLine [4][4];//the length of intersecting line between sphere and facet. [i][j] is for sphere facet "i" and sphere facetVertices[i][j]. Last component for 1/sumLines in the facet.
+ double trapCapP;//for calculating the pressure of trapped phase, cell.pressureTrapped = pressureAir - trapCapP.
+ int windowsID;//a temp cell info for experiment comparison
+ UnsatCellInfo (void)
+ {
+ poreRadius.resize(4, 0);
+ isWaterReservoir = false; isAirReservoir = false; capillaryCellVolume = 0;
+ for (int k=0; k<4;k++) for (int l=0; l<3;l++) solidLine[k][l]=0;
+ trapCapP = 0;
+ windowsID = 0;
+ }
+};
+
+class UnsatVertexInfo : public FlowVertexInfo {
+// add later;
+public:
+// UnsatVertexInfo (void)
+};
+
+typedef TemplateFlowEngine<UnsatCellInfo,UnsatVertexInfo> UnsaturatedEngineT;
+REGISTER_SERIALIZABLE(UnsaturatedEngineT);
+YADE_PLUGIN((UnsaturatedEngineT));
+
+class UnsaturatedEngine : public UnsaturatedEngineT
+{
+ protected:
+ void testFunction();
+
+
+ public :
+ void initializeCellIndex();
+ void updatePoreRadius();
+ void updateVolumeCapillaryCell();
+ double computeEffPoreRadius(CellHandle cell, int j);
+ double computeEffPoreRadiusFine(CellHandle cell, int j);
+ double bisection(CellHandle cell, int j, double a, double b);
+ double computeDeltaForce(CellHandle cell,int j, double rCap);
+ void computeSolidLine();
+ void computeFacetPoreForcesWithCache(bool onlyCache=false);
+
+ void invade();
+ Real getMinEntryValue();
+ Real getSaturation();
+
+ void invadeSingleCell1(CellHandle cell, double pressure);
+ void invade1();
+ void checkTrap(double pressure);//check trapped phase, define trapCapP.
+ Real getMinEntryValue1();
+ void updatePressure();
+ void updatePressureReservoir();
+ void initReservoirBound();
+ void initWaterReservoirBound();
+ void updateWaterReservoir();
+ void waterReservoirRecursion(CellHandle cell);
+ void initAirReservoirBound();
+ void updateAirReservoir();
+ void airReservoirRecursion(CellHandle cell);
+ Real getSaturation1();
+
+ void invadeSingleCell2(CellHandle cell, double pressure);
+ void invade2();
+ void updatePressure2();
+ Real getMinEntryValue2();
+ Real getSaturation2();
+
+ //record and test functions
+ void checkCellsConnection();
+ void checkEntryCapillaryPressure();
+ void checkLatticeNodeY(double y);
+ void checkReservoirInfo(int boundN);
+ void checkBoundingCellsInfo();
+ void saveVtk(const char* folder) {bool initT=solver->noCache; solver->noCache=false; solver->saveVtk(folder); solver->noCache=initT;}
+ //temp functions
+ void initializeCellWindowsID();
+ Real getWindowsSaturation(int windowsID);
+ Real getWindowsSaturation1(int i);
+ Real getWindowsSaturation2(int i);
+ double getRadiusMin(CellHandle cell, int j);
+ void debugTemp();
+
+ virtual ~UnsaturatedEngine();
+
+ virtual void action();
+
+ YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(UnsaturatedEngine,UnsaturatedEngineT,"Preliminary version engine of a drainage model for unsaturated soils. Note:Air reservoir is on the top; water reservoir is on the bottom.",
+ ((bool, isPhaseTrapped, true,,"Activate invade mode. If True, the wetting phase can be trapped, activate invade mode 1; if false, the wetting phase cann't be trapped, activate invade mode 2."))
+ ((double,gasPressure,0,,"Invasion pressure"))
+ ((double,surfaceTension,0.0728,,"Water Surface Tension in contact with air at 20 Degrees Celsius is: 0.0728(N/m)"))
+
+ ((bool, computeForceActivated, true,,"Activate capillary force computation. WARNING: turning off means capillary force is not computed at all, but the drainage can still work."))
+ ((bool, invadeBoundary, false,,"Invade from boundaries."))
+ ((int, windowsNo, 10,, "Number of genrated windows/(zoomed samples)."))
+ ,,,
+
+ .def("saveVtk",&UnsaturatedEngine::saveVtk,(python::arg("folder")="./VTK"),"Save pressure field in vtk format. Specify a folder name for output.")
+ .def("testFunction",&UnsaturatedEngine::testFunction,"The playground for Chao's experiments.")
+ .def("getSaturation",&UnsaturatedEngine::getSaturation,"get saturation.")
+ .def("getWindowsSaturation",&UnsaturatedEngine::getWindowsSaturation,(python::arg("windowsID")), "get saturation of windowsID")
+ .def("getMinEntryValue",&UnsaturatedEngine::getMinEntryValue,"get the minimum air entry pressure for the next invade step.")
+ .def("checkCellsConnection",&UnsaturatedEngine::checkCellsConnection,"Check cell connections.")
+ .def("checkEntryCapillaryPressure",&UnsaturatedEngine::checkEntryCapillaryPressure,"Check entry capillary pressure between neighbor cells.")
+ .def("checkLatticeNodeY",&UnsaturatedEngine::checkLatticeNodeY,(python::arg("y")),"Check the slice of lattice nodes for yNormal(y). 0: out of sphere; 1: inside of sphere.")
+ .def("checkReservoirInfo",&UnsaturatedEngine::checkReservoirInfo,(python::arg("boundN")),"Check reservoir cells(N=2,3) statement and export to 'waterReservoirBoundInfo.txt' and 'airReservoirBoundInfo.txt'.")
+ .def("checkBoundingCellsInfo",&UnsaturatedEngine::checkBoundingCellsInfo,"Check boundary cells (without reservoirs) statement and export to 'boundInfo.txt'.")
+ .def("debugTemp",&UnsaturatedEngine::debugTemp,"debug temp file.(temporary)")
+ .def("initializeCellWindowsID",&UnsaturatedEngine::initializeCellWindowsID,"Initialize cell windows index. A temp function for comparison with experiments, will delete soon")
+ .def("invade",&UnsaturatedEngine::invade,"Run the drainage invasion.")
+ .def("computeForce",&UnsaturatedEngine::computeFacetPoreForcesWithCache,"Compute capillary force. ")
+ )
+ DECLARE_LOGGER;
+};
+
+REGISTER_SERIALIZABLE(UnsaturatedEngine);
+YADE_PLUGIN((UnsaturatedEngine));
+
+UnsaturatedEngine::~UnsaturatedEngine(){}
+
+void UnsaturatedEngine::testFunction()
+{
+ cout<<"This is UnsaturatedEngine test program"<<endl;
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if (tri.number_of_vertices()==0) {
+ cout<< "triangulation is empty: building a new one" << endl;
+ scene = Omega::instance().getScene().get();//here define the pointer to Yade's scene
+ setPositionsBuffer(true);//copy sphere positions in a buffer...
+ buildTriangulation(pZero,*solver);//create a triangulation and initialize pressure in the elements, everything will be contained in "solver"
+ initializeCellIndex();//initialize cell index
+ updatePoreRadius();//save all pore radii before invade
+ updateVolumeCapillaryCell();//save capillary volume of all cells, for fast calculating saturation
+ computeSolidLine();//save cell->info().solidLine[j][y]
+ }
+ solver->noCache = true;
+}
+
+void UnsaturatedEngine::action()
+{/*
+ if ( !isActivated ) return;
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if ( (tri.number_of_vertices()==0) || (updateTriangulation) ) {
+ cout<< "triangulation is empty: building a new one" << endl;
+ scene = Omega::instance().getScene().get();//here define the pointer to Yade's scene
+ setPositionsBuffer(true);//copy sphere positions in a buffer...
+ buildTriangulation(pZero,solver);//create a triangulation and initialize pressure in the elements, everything will be contained in "solver"
+ initializeCellIndex();//initialize cell index
+ updatePoreRadius();//save all pore radii before invade
+ updateVolumeCapillaryCell();//save capillary volume of all cells, for calculating saturation
+ computeSolidLine();//save cell->info().solidLine[j][y]
+ solver->noCache = true;
+ }
+ ///compute invade
+ if (pressureForce) {
+ invade();
+ }
+
+ ///compute force
+ if(computeForceActivated){
+ computeFacetPoreForcesWithCache(solver);
+ Vector3r force;
+ FiniteVerticesIterator vertices_end = solver->T[solver->currentTes].Triangulation().finite_vertices_end();
+ for ( FiniteVerticesIterator V_it = solver->T[solver->currentTes].Triangulation().finite_vertices_begin(); V_it != vertices_end; V_it++ ) {
+ force = pressureForce ? Vector3r ( V_it->info().forces[0],V_it->info().forces[1],V_it->info().forces[2] ): Vector3r(0,0,0);
+ scene->forces.addForce ( V_it->info().id(), force);
+ }
+}*/
+}
+
+void UnsaturatedEngine::initializeCellIndex()
+{
+ 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++;
+ }
+}
+
+void UnsaturatedEngine::updatePoreRadius()
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ CellHandle neighbourCell;
+ for (FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ for (int j=0; j<4; j++) {
+ neighbourCell = cell->neighbor(j);
+ if (!tri.is_infinite(neighbourCell)) {
+ cell->info().poreRadius[j]=computeEffPoreRadius(cell, j);
+ neighbourCell->info().poreRadius[tri.mirror_index(cell, j)]= cell->info().poreRadius[j];
+ }
+ }
+ }
+}
+
+void UnsaturatedEngine::updateVolumeCapillaryCell()
+{
+ initializeVolumes(*solver);
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ CellHandle neighbourCell;
+ for (FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ cell->info().capillaryCellVolume = abs( cell->info().volume() ) - solver->volumeSolidPore(cell);
+ }
+}
+
+void UnsaturatedEngine::invade()
+{
+ if (isPhaseTrapped) invade1();
+ else invade2();
+}
+
+Real UnsaturatedEngine::getMinEntryValue()
+{
+ if (isPhaseTrapped) return getMinEntryValue1();
+ else return getMinEntryValue2();
+}
+
+Real UnsaturatedEngine::getSaturation()
+{
+ if (isPhaseTrapped) return getSaturation1();
+ else return getSaturation2();
+}
+
+///invade mode 1. update phase reservoir before invasion. Consider no viscous effects, and invade gradually.
+void UnsaturatedEngine::invadeSingleCell1(CellHandle cell, double pressure)
+{
+ if (invadeBoundary==true) {
+ for (int facet = 0; facet < 4; facet ++) {
+ if (solver->T[solver->currentTes].Triangulation().is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;
+ if (cell->neighbor(facet)->info().isWaterReservoir == true) {
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ if (pressure > nCellP) {
+ CellHandle nCell = cell->neighbor(facet);
+ nCell->info().p() = pressure;
+ nCell->info().isAirReservoir=true;
+ nCell->info().isWaterReservoir=false;
+ invadeSingleCell1(nCell, pressure);}}}}
+ else {
+ for (int facet = 0; facet < 4; facet ++) {
+ if (solver->T[solver->currentTes].Triangulation().is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;//FIXME:defensive
+ if (cell->neighbor(facet)->info().isFictious) continue;
+ if (cell->neighbor(facet)->info().isWaterReservoir == true) {
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ if (pressure > nCellP) {
+ CellHandle nCell = cell->neighbor(facet);
+ nCell->info().p() = pressure;
+ nCell->info().isAirReservoir=true;
+ nCell->info().isWaterReservoir=false;
+ invadeSingleCell1(nCell, pressure);}}}}
+}
+
+void UnsaturatedEngine::invade1()
+{
+ updatePressureReservoir();
+ 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().isAirReservoir == true)
+ invadeSingleCell1(cell,cell->info().p());
+ }
+ checkTrap(bndCondValue[3]);
+ FiniteCellsIterator ncellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator ncell = tri.finite_cells_begin(); ncell != ncellEnd; ncell++ ) {
+ if( (ncell->info().isWaterReservoir) || (ncell->info().isAirReservoir) ) continue;
+ ncell->info().p() = bndCondValue[3] - ncell->info().trapCapP;
+ }
+ initReservoirBound();
+}
+
+//check trapped phase, define trapCapP.
+void UnsaturatedEngine::checkTrap(double pressure)
+{
+ 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().isWaterReservoir) || (cell->info().isAirReservoir) ) continue;
+ if(cell->info().trapCapP!=0) continue;
+ cell->info().trapCapP=pressure;
+ }
+}
+
+Real UnsaturatedEngine::getMinEntryValue1()
+{
+ updatePressureReservoir();
+ Real nextEntry = 1e50;
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if (invadeBoundary==true) {
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (cell->info().isAirReservoir == true) {
+ for (int facet=0; facet<4; facet ++) {
+ if (tri.is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;
+ if ( cell->neighbor(facet)->info().isWaterReservoir == true ) {
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ nextEntry = min(nextEntry,nCellP);}}}}}
+ else {
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (cell->info().isAirReservoir == true) {
+ for (int facet=0; facet<4; facet ++) {
+ if (tri.is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;//FIXME:defensive
+ if (cell->neighbor(facet)->info().isFictious) continue;
+ if ( cell->neighbor(facet)->info().isWaterReservoir == true ) {
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ nextEntry = min(nextEntry,nCellP);}}}}}
+ if (nextEntry==1e50) {
+ cout << "End drainage !" << endl;
+ return nextEntry=0;}
+ else return nextEntry;
+}
+
+void UnsaturatedEngine::updatePressure()
+{
+ boundaryConditions(*solver);
+ solver->pressureChanged=true;
+ solver->reApplyBoundaryConditions();
+ 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().isWaterReservoir==true) cell->info().p()=bndCondValue[2];
+ if (cell->info().isAirReservoir==true) cell->info().p()=bndCondValue[3];
+ }
+}
+
+//update pressure and reservoir attr
+void UnsaturatedEngine::updatePressureReservoir()
+{
+ updatePressure();//NOTE:updatePressure must be run before update reservoirs.
+ updateAirReservoir();
+ updateWaterReservoir();
+}
+
+//NOTE:keep boundingCells[2],boundingCells[3] always being reservoirs.
+void UnsaturatedEngine::initReservoirBound()
+{
+ initWaterReservoirBound();
+ initAirReservoirBound();
+}
+
+//boundingCells[2] is water reservoir.
+void UnsaturatedEngine::initWaterReservoirBound()
+{
+ if (solver->boundingCells[2].size()==0) {
+ cerr<<"ERROR! set bndCondIsPressure[2] true. boundingCells.size=0!";
+ }
+ else {
+ vector<CellHandle>::iterator it = solver->boundingCells[2].begin();
+ for ( it ; it != solver->boundingCells[2].end(); it++) {
+ if ((*it)->info().index == 0) continue;
+ (*it)->info().isWaterReservoir = true;
+ }
+ }
+}
+void UnsaturatedEngine::updateWaterReservoir()
+{
+ 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().isWaterReservoir = false;
+ }
+ initWaterReservoirBound();
+ vector<CellHandle>::iterator it = solver->boundingCells[2].begin();
+ for ( it ; it != solver->boundingCells[2].end(); it++) {
+ if ((*it)->info().index == 0) continue;
+ waterReservoirRecursion(*it);
+ }
+}
+void UnsaturatedEngine::waterReservoirRecursion(CellHandle cell)
+{
+ for (int facet = 0; facet < 4; facet ++) {
+ if (solver->T[solver->currentTes].Triangulation().is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().p() != bndCondValue[2]) continue;
+ if (cell->neighbor(facet)->info().isWaterReservoir==true) continue;
+ CellHandle nCell = cell->neighbor(facet);
+ nCell->info().isWaterReservoir = true;
+ waterReservoirRecursion(nCell);
+ }
+}
+//boundingCells[3] is air reservoir
+void UnsaturatedEngine::initAirReservoirBound()
+{
+ if (solver->boundingCells[3].size()==0) {
+ cerr<<"ERROR! set bndCondIsPressure[3] true. boundingCells.size=0!";
+ }
+ else {
+ vector<CellHandle>::iterator it = solver->boundingCells[3].begin();
+ for ( it ; it != solver->boundingCells[3].end(); it++) {
+ if((*it)->info().index == 0) continue;
+ (*it)->info().isAirReservoir = true;
+ }
+ }
+}
+
+void UnsaturatedEngine::updateAirReservoir()
+{
+ 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().isAirReservoir = false;
+ }
+ initAirReservoirBound();
+ vector<CellHandle>::iterator it = solver->boundingCells[3].begin();
+ for ( it ; it != solver->boundingCells[3].end(); it++) {
+ if ((*it)->info().index == 0) continue;
+ airReservoirRecursion(*it);
+ }
+}
+
+void UnsaturatedEngine::airReservoirRecursion(CellHandle cell)
+{
+ for (int facet = 0; facet < 4; facet ++) {
+ if (solver->T[solver->currentTes].Triangulation().is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().p() != bndCondValue[3]) continue;
+ if (cell->neighbor(facet)->info().isAirReservoir == true) continue;
+ CellHandle nCell = cell->neighbor(facet);
+ nCell->info().isAirReservoir = true;
+ airReservoirRecursion(nCell);
+ }
+}
+
+Real UnsaturatedEngine::getSaturation1()
+{
+ updatePressureReservoir();
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ Real capillaryVolume = 0.0; //total capillary volume
+ Real airVolume = 0.0; //air volume
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+
+ if (invadeBoundary==true) {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;//NOTE:reservoirs cells should not be included in saturation
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().isAirReservoir==true) {
+ airVolume = airVolume + cell->info().capillaryCellVolume;}}}
+ else {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;
+ if (cell->info().isFictious) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().isAirReservoir==true) {
+ airVolume = airVolume + cell->info().capillaryCellVolume;}}}
+ Real saturation = 1 - airVolume/capillaryVolume;
+ return saturation;
+}
+
+///invade mode 2. Consider no trapped phase.
+void UnsaturatedEngine::invadeSingleCell2(CellHandle cell, double pressure)
+{
+ if (invadeBoundary==true) {
+ for (int facet = 0; facet < 4; facet ++) {
+ if (solver->T[solver->currentTes].Triangulation().is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;
+ if (cell->neighbor(facet)->info().p()!=0) continue;
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ if (pressure > nCellP) {
+ CellHandle nCell = cell->neighbor(facet);
+ nCell->info().p() = pressure;
+ invadeSingleCell2(nCell, pressure);}}}
+ else {
+ for (int facet = 0; facet < 4; facet ++) {
+ if (solver->T[solver->currentTes].Triangulation().is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;//FIXME:defensive
+ if (cell->neighbor(facet)->info().isFictious) continue;
+ if (cell->neighbor(facet)->info().p()!=0) continue;
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ if (pressure > nCellP) {
+ CellHandle nCell = cell->neighbor(facet);
+ nCell->info().p() = pressure;
+ invadeSingleCell2(nCell, pressure);}}}
+}
+
+void UnsaturatedEngine::invade2()
+{
+ updatePressure2();
+ 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().p()!=0) {
+ invadeSingleCell2(cell, cell->info().p());
+ }
+ }
+}
+
+void UnsaturatedEngine::updatePressure2()
+{
+ boundaryConditions(*solver);
+ solver->pressureChanged=true;
+ solver->reApplyBoundaryConditions();
+ 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().p()!=0) cell->info().p()=bndCondValue[3];
+ }
+}
+
+Real UnsaturatedEngine::getMinEntryValue2()
+{
+ Real nextEntry = 1e50;
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+
+ if (invadeBoundary==true) {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (cell->info().p()!=0) {
+ for (int facet=0; facet<4; facet ++) {
+ if (tri.is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;
+ if (cell->neighbor(facet)->info().p()==0) {
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ nextEntry = min(nextEntry,nCellP);}}}}}
+ else {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (cell->info().p()!=0) {
+ for (int facet=0; facet<4; facet ++) {
+ if (tri.is_infinite(cell->neighbor(facet))) continue;
+ if (cell->neighbor(facet)->info().Pcondition) continue;
+ if (cell->neighbor(facet)->info().isFictious) continue;//FIXME:defensive
+ if (cell->neighbor(facet)->info().p()==0) {
+ double nCellP = surfaceTension/cell->info().poreRadius[facet];
+ nextEntry = min(nextEntry,nCellP);}}}}}
+ if (nextEntry==1e50) {
+ cout << "End drainage !" << endl;
+ return nextEntry=0;
+ }
+ else {
+ return nextEntry;
+ }
+}
+
+Real UnsaturatedEngine::getSaturation2()
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ Real capillaryVolume = 0.0;
+ Real waterVolume = 0.0;
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+
+ if (invadeBoundary==true) {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().p()==0) {
+ waterVolume = waterVolume + cell->info().capillaryCellVolume;}}}
+ else {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;
+ if (cell->info().isFictious) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().p()==0) {
+ waterVolume = waterVolume + cell->info().capillaryCellVolume;}}}
+ Real saturation = waterVolume/capillaryVolume;
+ return saturation;
+}
+
+double UnsaturatedEngine::computeEffPoreRadius(CellHandle cell, int j)
+{
+ double rInscribe = abs(solver->computeEffectiveRadius(cell, j));
+ CellHandle cellh = CellHandle(cell);
+ int facetNFictious = solver->detectFacetFictiousVertices (cellh,j);
+ switch (facetNFictious) {
+ case (0) : { return computeEffPoreRadiusFine(cell,j); }; break;
+ case (1) : { return rInscribe; }; break;
+ case (2) : { return rInscribe; }; break;
+ }
+}
+//seperate rmin=getMinPoreRadius(cell,j) later;
+double UnsaturatedEngine::computeEffPoreRadiusFine(CellHandle cell, int j)
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if (tri.is_infinite(cell->neighbor(j))) return 0;
+
+ Vector3r posA = makeVector3r(cell->vertex(facetVertices[j][0])->point().point());
+ Vector3r posB = makeVector3r(cell->vertex(facetVertices[j][1])->point().point());
+ Vector3r posC = makeVector3r(cell->vertex(facetVertices[j][2])->point().point());
+ double rA = sqrt(cell->vertex(facetVertices[j][0])->point().weight());
+ double rB = sqrt(cell->vertex(facetVertices[j][1])->point().weight());
+ double rC = sqrt(cell->vertex(facetVertices[j][2])->point().weight());
+ double AB = (posA-posB).norm();
+ double AC = (posA-posC).norm();
+ double BC = (posB-posC).norm();
+ double A = acos(((posB-posA).dot(posC-posA))/((posB-posA).norm()*(posC-posA).norm()));
+ double B = acos(((posA-posB).dot(posC-posB))/((posA-posB).norm()*(posC-posB).norm()));
+ double C = acos(((posA-posC).dot(posB-posC))/((posA-posC).norm()*(posB-posC).norm()));
+ double rAB = 0.5*(AB-rA-rB); if (rAB<0) { rAB=0; }
+ double rBC = 0.5*(BC-rB-rC); if (rBC<0) { rBC=0; }
+ double rAC = 0.5*(AC-rA-rC); if (rAC<0) { rAC=0; }
+
+ double rmin = max(rAB,max(rBC,rAC)); if (rmin==0) { rmin= 1.0e-10; }
+ double rmax = abs(solver->computeEffectiveRadius(cell, j));//rmin>rmax ?
+ if(rmin>rmax) { cerr<<"WARNING! rmin>rmax. rmin="<<rmin<<" ,rmax="<<rmax<<endl; }
+
+ double deltaForceRMin = computeDeltaForce(cell,j,rmin);
+ double deltaForceRMax = computeDeltaForce(cell,j,rmax);
+ if(deltaForceRMax<0) {
+ double effPoreRadius = rmax;
+ cerr<<"deltaForceRMax Negative. cellID: "<<cell->info().index<<". posA="<<posA<<"; posB="<<posB<<"; posC="<< posC<<"; rA="<< rA<<"; rB="<< rB<<"; rC="<<rC<<endl;
+ return effPoreRadius;}
+ else if(deltaForceRMin<0) {
+ double effPoreRadius = bisection(cell,j,rmin,rmax);// cerr<<"1";//we suppose most cases should be this.
+ return effPoreRadius;}
+ else if( (deltaForceRMin>0) && (deltaForceRMin<deltaForceRMax) ) {
+ double effPoreRadius = rmin;// cerr<<"2";
+ return effPoreRadius;}
+ else if(deltaForceRMin>deltaForceRMax) {
+ double effPoreRadius = rmax;
+ cerr<<"WARNING! deltaForceRMin>deltaForceRMax. cellID: "<<cell->info().index<<"; deltaForceRMin="<<deltaForceRMin<<"; deltaForceRMax="<<deltaForceRMax<<". posA="<<posA<<"; posB="<<posB<<"; posC="<< posC<<"; rA="<< rA<<"; rB="<< rB<<"; rC="<<rC<<endl;
+ return effPoreRadius;}
+}
+
+double UnsaturatedEngine::bisection(CellHandle cell, int j, double a, double b)
+{
+ double m = 0.5*(a+b);
+ if (abs(b-a)>abs((solver->computeEffectiveRadius(cell, j)*1.0e-6))) {
+ if ( computeDeltaForce(cell,j,m) * computeDeltaForce(cell,j,a) < 0 ) {
+ b = m;
+ return bisection(cell,j,a,b);}
+ else {
+ a = m;
+ return bisection(cell,j,a,b);}}
+ else return m;
+}
+
+double UnsaturatedEngine::computeDeltaForce(CellHandle cell,int j, double rCap)
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if (tri.is_infinite(cell->neighbor(j))) return 0;
+
+ Vector3r posA = makeVector3r(cell->vertex(facetVertices[j][0])->point().point());
+ Vector3r posB = makeVector3r(cell->vertex(facetVertices[j][1])->point().point());
+ Vector3r posC = makeVector3r(cell->vertex(facetVertices[j][2])->point().point());
+ double rA = sqrt(cell->vertex(facetVertices[j][0])->point().weight());
+ double rB = sqrt(cell->vertex(facetVertices[j][1])->point().weight());
+ double rC = sqrt(cell->vertex(facetVertices[j][2])->point().weight());
+ double AB = (posA-posB).norm();
+ double AC = (posA-posC).norm();
+ double BC = (posB-posC).norm();
+ double A = acos(((posB-posA).dot(posC-posA))/((posB-posA).norm()*(posC-posA).norm()));
+ double B = acos(((posA-posB).dot(posC-posB))/((posA-posB).norm()*(posC-posB).norm()));
+ double C = acos(((posA-posC).dot(posB-posC))/((posA-posC).norm()*(posB-posC).norm()));
+ double rAB = 0.5*(AB-rA-rB); if (rAB<0) { rAB=0; }
+ double rBC = 0.5*(BC-rB-rC); if (rBC<0) { rBC=0; }
+ double rAC = 0.5*(AC-rA-rC); if (rAC<0) { rAC=0; }
+
+ //In triangulation ArB,rCap is the radius of sphere r;
+ double _AB = (pow((rA+rCap),2)+pow(AB,2)-pow((rB+rCap),2))/(2*(rA+rCap)*AB); if(_AB>1.0) {_AB=1.0;} if(_AB<-1.0) {_AB=-1.0;}
+ double alphaAB = acos(_AB);
+ double _BA = (pow((rB+rCap),2)+pow(AB,2)-pow((rA+rCap),2))/(2*(rB+rCap)*AB); if(_BA>1.0) {_BA=1.0;} if(_BA<-1.0) {_BA=-1.0;}
+ double alphaBA = acos(_BA);
+ double _ArB = (pow((rA+rCap),2)+pow((rB+rCap),2)-pow(AB,2))/(2*(rA+rCap)*(rB+rCap)); if(_ArB>1.0) {_ArB=1.0;} if(_ArB<-1.0) {_ArB=-1.0;}
+ double alphaArB = acos(_ArB);
+
+ double lengthLiquidAB = alphaArB*rCap;
+ double AreaArB = 0.5*(rA+rCap)*(rB+rCap)*sin(alphaArB);
+ double areaLiquidAB = AreaArB-0.5*alphaAB*pow(rA,2)-0.5*alphaBA*pow(rB,2)-0.5*alphaArB*pow(rCap,2);
+
+ double _AC = (pow((rA+rCap),2)+pow(AC,2)-pow((rC+rCap),2))/(2*(rA+rCap)*AC); if(_AC>1.0) {_AC=1.0;} if(_AC<-1.0) {_AC=-1.0;}
+ double alphaAC = acos(_AC);
+ double _CA = (pow((rC+rCap),2)+pow(AC,2)-pow((rA+rCap),2))/(2*(rC+rCap)*AC); if(_CA>1.0) {_CA=1.0;} if(_CA<-1.0) {_CA=-1.0;}
+ double alphaCA = acos(_CA);
+ double _ArC = (pow((rA+rCap),2)+pow((rC+rCap),2)-pow(AC,2))/(2*(rA+rCap)*(rC+rCap)); if(_ArC>1.0) {_ArC=1.0;} if(_ArC<-1.0) {_ArC=-1.0;}
+ double alphaArC = acos(_ArC);
+
+ double lengthLiquidAC = alphaArC*rCap;
+ double AreaArC = 0.5*(rA+rCap)*(rC+rCap)*sin(alphaArC);
+ double areaLiquidAC = AreaArC-0.5*alphaAC*pow(rA,2)-0.5*alphaCA*pow(rC,2)-0.5*alphaArC*pow(rCap,2);
+
+ double _BC = (pow((rB+rCap),2)+pow(BC,2)-pow((rC+rCap),2))/(2*(rB+rCap)*BC); if(_BC>1.0) {_BC=1.0;} if(_BC<-1.0) {_BC=-1.0;}
+ double alphaBC = acos(_BC);
+ double _CB = (pow((rC+rCap),2)+pow(BC,2)-pow((rB+rCap),2))/(2*(rC+rCap)*BC); if(_CB>1.0) {_CB=1.0;} if(_CB<-1.0) {_CB=-1.0;}
+ double alphaCB = acos(_CB);
+ double _BrC = (pow((rB+rCap),2)+pow((rC+rCap),2)-pow(BC,2))/(2*(rB+rCap)*(rC+rCap)); if(_BrC>1.0) {_BrC=1.0;} if(_BrC<-1.0) {_BrC=-1.0;}
+ double alphaBrC = acos(_BrC);
+
+ double lengthLiquidBC = alphaBrC*rCap;
+ double AreaBrC = 0.5*(rB+rCap)*(rC+rCap)*sin(alphaBrC);
+ double areaLiquidBC = AreaBrC-0.5*alphaBC*pow(rB,2)-0.5*alphaCB*pow(rC,2)-0.5*alphaBrC*pow(rCap,2);
+
+ double areaCap = sqrt(cell->info().facetSurfaces[j].squared_length()) * cell->info().facetFluidSurfacesRatio[j];
+ double areaPore = areaCap - areaLiquidAB - areaLiquidAC - areaLiquidBC;
+
+ //FIXME:rethink here,areaPore Negative, Flat facets, do nothing ?
+ if(areaPore<0) {cerr<<"ERROR! areaPore Negative. cellID: "<<cell->info().index<<". posA="<<posA<<"; posB="<<posB<<"; posC="<< posC<<"; rA="<< rA<<"; rB="<< rB<<"; rC="<<rC<<endl;}
+ double perimeterPore = lengthLiquidAB + lengthLiquidAC + lengthLiquidBC + (A - alphaAB - alphaAC)*rA + (B - alphaBA - alphaBC)*rB + (C - alphaCA - alphaCB)*rC;
+ if(perimeterPore<0) {cerr<<"ERROR! perimeterPore Negative. cellID: "<<cell->info().index<<". posA="<<posA<<"; posB="<<posB<<"; posC="<< posC<<"; rA="<< rA<<"; rB="<< rB<<"; rC="<<rC<<endl;}
+
+ double deltaForce = perimeterPore - areaPore/rCap;//deltaForce=surfaceTension*(perimeterPore - areaPore/rCap)
+ return deltaForce;
+}
+
+void UnsaturatedEngine::checkCellsConnection()
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ ofstream file;
+ file.open("cellsConnection.txt");
+ file << "cell" << " " << "neighborCells" << endl;
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ file << cell->info().index << " " <<cell->neighbor(0)->info().index << " " << cell->neighbor(1)->info().index << " " << cell->neighbor(2)->info().index << " " << cell->neighbor(3)->info().index << endl;
+ }
+ file.close();
+}
+
+void UnsaturatedEngine::checkEntryCapillaryPressure()
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ ofstream file;
+ file.open("entryCapillaryPressure.txt");
+ file << "#List of Connections \n";
+ file << "cell" << " " << "neighborCell" << " " << "entryCapillaryPressure" << endl;
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ file << cell->info().index << " " <<cell->neighbor(0)->info().index << " " << surfaceTension/cell->info().poreRadius[0] << endl;
+ file << cell->info().index << " " <<cell->neighbor(1)->info().index << " " << surfaceTension/cell->info().poreRadius[1] << endl;
+ file << cell->info().index << " " <<cell->neighbor(2)->info().index << " " << surfaceTension/cell->info().poreRadius[2] << endl;
+ file << cell->info().index << " " <<cell->neighbor(3)->info().index << " " << surfaceTension/cell->info().poreRadius[3] << endl;
+ }
+ file.close();
+}
+
+void UnsaturatedEngine::checkLatticeNodeY(double y)
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if((y<solver->yMin)||(y>solver->yMax)) {
+ cerr<<"y is out of range! "<<"pleas set y between "<<solver->yMin<<" and "<<solver->yMax<<endl;}
+ else {
+ int N=100;// the default Node number for each slice is 100X100
+ ofstream file;
+ std::ostringstream fileNameStream(".txt");
+ fileNameStream << "LatticeNodeY_"<< y;
+ std::string fileName = fileNameStream.str();
+ file.open(fileName.c_str());
+// file << "#Slice Of LatticeNodes: 0: out of sphere; 1: inside of sphere \n";
+ Real deltaX = (solver->xMax-solver->xMin)/N;
+ Real deltaZ = (solver->zMax-solver->zMin)/N;
+ for (int j=0; j<N+1; j++) {
+ for (int k=0; k<N+1; k++) {
+ double x=solver->xMin+j*deltaX;
+ double z=solver->zMin+k*deltaZ;
+ int M=0;
+ Vector3r LatticeNode = Vector3r(x,y,z);
+ for (FiniteVerticesIterator V_it = tri.finite_vertices_begin(); V_it != tri.finite_vertices_end(); V_it++) {
+ if(V_it->info().isFictious) continue;
+ Vector3r SphereCenter = makeVector3r(V_it->point().point());
+ if ((LatticeNode-SphereCenter).squaredNorm() < V_it->point().weight()) {
+ M=1;
+ break;}}
+ file << M;}
+ file << "\n";}
+ file.close();}
+}
+
+void UnsaturatedEngine::checkBoundingCellsInfo()
+{
+ ofstream file;
+ file.open("boundInfo.txt");
+ file << "#Checking the boundingCells statement";
+ file << "CellID" << " CellPressure" << " isAirReservoir" << " isWaterReservoir" <<endl;
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().index==0) continue;
+ if ((cell->info().isFictious==true)&&(cell->info().Pcondition==false)) {
+ file << cell->info().index <<" "<<cell->info().p()<<" "<<cell->info().isAirReservoir<<" "<<cell->info().isWaterReservoir<<endl;
+ }
+ }
+}
+
+void UnsaturatedEngine::checkReservoirInfo(int boundN)
+{
+ if(solver->boundingCells[boundN].size()==0) {
+ cerr << "please set corresponding bndCondIsPressure[bound] to be true ."<< endl;
+ }
+ else {
+ if (boundN==2) {
+ ofstream file;
+ file.open("waterReservoirBoundInfo.txt");
+ file << "#Checking the water reservoir cells statement";
+ file << "CellID" << " CellPressure" << " isAirReservoir" << " isWaterReservoir" <<endl;
+ vector<CellHandle>::iterator it = solver->boundingCells[boundN].begin();
+ for ( it ; it != solver->boundingCells[boundN].end(); it++) {
+ if ((*it)->info().index == 0) continue;
+ file << (*it)->info().index <<" "<<(*it)->info().p()<<" "<<(*it)->info().isAirReservoir<<" "<<(*it)->info().isWaterReservoir<<endl;
+ }
+ file.close();
+ }
+ else if (boundN==3) {
+ ofstream file;
+ file.open("airReservoirBoundInfo.txt");
+ file << "#Checking the air reservoir cells statement";
+ file << "CellID"<<" CellPressure"<<" isAirReservoir"<<" isWaterReservoir"<<endl;
+ vector<CellHandle>::iterator it = solver->boundingCells[boundN].begin();
+ for ( it ; it != solver->boundingCells[boundN].end(); it++) {
+ if ((*it)->info().index == 0) continue;
+ file << (*it)->info().index <<" "<<(*it)->info().p()<<" "<<(*it)->info().isAirReservoir<<" "<<(*it)->info().isWaterReservoir<<endl;
+ }
+ file.close();
+ }
+ else {
+ cerr<<"This is not a reservoir boundary. Please set boundN to be 2(waterReservoirBound) or 3(airReservoirBound)."<<endl;
+ }
+ }
+}
+
+//----temp function for Vahid Joekar-Niasar's data----
+double UnsaturatedEngine::getRadiusMin(CellHandle cell, int j)
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ if (tri.is_infinite(cell->neighbor(j))) return 0;
+
+ Vector3r posA = makeVector3r(cell->vertex(facetVertices[j][0])->point().point());
+ Vector3r posB = makeVector3r(cell->vertex(facetVertices[j][1])->point().point());
+ Vector3r posC = makeVector3r(cell->vertex(facetVertices[j][2])->point().point());
+ double rA = sqrt(cell->vertex(facetVertices[j][0])->point().weight());
+ double rB = sqrt(cell->vertex(facetVertices[j][1])->point().weight());
+ double rC = sqrt(cell->vertex(facetVertices[j][2])->point().weight());
+ double AB = (posA-posB).norm();
+ double AC = (posA-posC).norm();
+ double BC = (posB-posC).norm();
+ double A = acos(((posB-posA).dot(posC-posA))/((posB-posA).norm()*(posC-posA).norm()));
+ double B = acos(((posA-posB).dot(posC-posB))/((posA-posB).norm()*(posC-posB).norm()));
+ double C = acos(((posA-posC).dot(posB-posC))/((posA-posC).norm()*(posB-posC).norm()));
+ double rAB = 0.5*(AB-rA-rB); if (rAB<0) { rAB=0; }
+ double rBC = 0.5*(BC-rB-rC); if (rBC<0) { rBC=0; }
+ double rAC = 0.5*(AC-rA-rC); if (rAC<0) { rAC=0; }
+
+ double rmin = max(rAB,max(rBC,rAC)); if (rmin==0) { rmin= 1.0e-10; }
+ return rmin;
+}
+
+void UnsaturatedEngine::debugTemp()
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ ofstream file;
+ file.open("bugTemp.txt");
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ file << cell->info().index << " " <<cell->info().poreRadius[0]<<" "<<getRadiusMin(cell,0)<<" "<<abs(solver->computeEffectiveRadius(cell, 0))<<endl;
+ file << cell->info().index << " " <<cell->info().poreRadius[1]<<" "<<getRadiusMin(cell,1)<<" "<<abs(solver->computeEffectiveRadius(cell, 1))<<endl;
+ file << cell->info().index << " " <<cell->info().poreRadius[2]<<" "<<getRadiusMin(cell,2)<<" "<<abs(solver->computeEffectiveRadius(cell, 2))<<endl;
+ file << cell->info().index << " " <<cell->info().poreRadius[3]<<" "<<getRadiusMin(cell,3)<<" "<<abs(solver->computeEffectiveRadius(cell, 3))<<endl;
+ }
+ file.close();
+}//----------end temp function for Vahid Joekar-Niasar's data (clear later)---------------------
+
+//----------temp functions for comparison with experiment-----------------------
+void UnsaturatedEngine::initializeCellWindowsID()
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ for (int i=1; i<(windowsNo+1); i++) {
+ if ( (cell->info()[1]>(solver->yMin+(i-1)*(solver->yMax-solver->yMin)/windowsNo) ) && (cell->info()[1] < (solver->yMin+i*(solver->yMax-solver->yMin)/windowsNo)) )
+ {cell->info().windowsID=i; break;}
+ }
+ }
+}
+
+Real UnsaturatedEngine::getWindowsSaturation(int windowsID)
+{
+ 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().windowsID==0) {cerr<<"Please initialize windowsID"<<endl;break;}
+ }
+ if (isPhaseTrapped) {
+ return getWindowsSaturation1(windowsID);
+ }
+ else {
+ return getWindowsSaturation2(windowsID);
+ }
+}
+Real UnsaturatedEngine::getWindowsSaturation1(int i)
+{
+ updatePressureReservoir();
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ Real capillaryVolume = 0.0; //total capillary volume
+ Real airVolume = 0.0; //air volume
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+
+ if (invadeBoundary==true) {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;//NOTE:reservoirs cells should not be included in saturation
+ if (cell->info().windowsID != i) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().isAirReservoir==true) {
+ airVolume = airVolume + cell->info().capillaryCellVolume;}}}
+ else {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;
+ if (cell->info().isFictious) continue;
+ if (cell->info().windowsID != i) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().isAirReservoir==true) {
+ airVolume = airVolume + cell->info().capillaryCellVolume;}}}
+ Real saturation = 1 - airVolume/capillaryVolume;
+ return saturation;
+}
+Real UnsaturatedEngine::getWindowsSaturation2(int i)
+{
+ RTriangulation& tri = solver->T[solver->currentTes].Triangulation();
+ Real capillaryVolume = 0.0;
+ Real waterVolume = 0.0;
+ FiniteCellsIterator cellEnd = tri.finite_cells_end();
+ if (invadeBoundary==true) {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;
+ if (cell->info().windowsID != i) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().p()==0) {
+ waterVolume = waterVolume + cell->info().capillaryCellVolume;}}}
+ else {
+ for ( FiniteCellsIterator cell = tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
+ if (tri.is_infinite(cell)) continue;
+ if (cell->info().Pcondition) continue;
+ if (cell->info().isFictious) continue;
+ if (cell->info().windowsID != i) continue;
+ capillaryVolume = capillaryVolume + cell->info().capillaryCellVolume;
+ if (cell->info().p()==0) {
+ waterVolume = waterVolume + cell->info().capillaryCellVolume;}}}
+ Real saturation = waterVolume/capillaryVolume;
+ return saturation;
+}//----------end temp functions for comparison with experiment-------------------
+
+///compute forces
+void UnsaturatedEngine::computeSolidLine()
+{
+ RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ for(int j=0; j<4; j++) {
+ solver->lineSolidPore(cell, j);
+ }
+ }
+}
+
+void UnsaturatedEngine::computeFacetPoreForcesWithCache(bool onlyCache)
+{
+ RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ CVector nullVect(0,0,0);
+ //reset forces
+ if (!onlyCache) for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) v->info().forces=nullVect;
+
+ #ifdef parallel_forces
+ if (solver->noCache) {
+ solver->perVertexUnitForce.clear(); solver->perVertexPressure.clear();
+// vector<const CVector*> exf; exf.reserve(20);
+// vector<const Real*> exp; exp.reserve(20);
+ solver->perVertexUnitForce.resize(Tri.number_of_vertices());
+ solver->perVertexPressure.resize(Tri.number_of_vertices());}
+ #endif
+
+ CellHandle neighbourCell;
+ VertexHandle mirrorVertex;
+ CVector tempVect;
+ //FIXME : Ema, be carefull with this (noCache), it needs to be turned true after retriangulation
+ if (solver->noCache) {for (FlowSolver::VCellIterator cellIt=solver->T[currentTes].cellHandles.begin(); cellIt!=solver->T[currentTes].cellHandles.end(); cellIt++){
+// if (noCache) for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ CellHandle& cell = *cellIt;
+ //reset cache
+ for (int k=0;k<4;k++) cell->info().unitForceVectors[k]=nullVect;
+ for (int j=0; j<4; j++) if (!Tri.is_infinite(cell->neighbor(j))) {
+ neighbourCell = cell->neighbor(j);
+ const CVector& Surfk = cell->info().facetSurfaces[j];
+ //FIXME : later compute that fluidSurf only once in hydraulicRadius, for now keep full surface not modified in cell->info for comparison with other forces schemes
+ //The ratio void surface / facet surface
+ Real area = sqrt(Surfk.squared_length()); if (area<=0) cerr <<"AREA <= 0!!"<<endl;
+ CVector facetNormal = Surfk/area;
+ const std::vector<CVector>& crossSections = cell->info().facetSphereCrossSections;
+ CVector fluidSurfk = cell->info().facetSurfaces[j]*cell->info().facetFluidSurfacesRatio[j];
+ /// handle fictious vertex since we can get the projected surface easily here
+ if (cell->vertex(j)->info().isFictious) {
+ Real projSurf=abs(Surfk[solver->boundary(cell->vertex(j)->info().id()).coordinate]);
+ tempVect=-projSurf*solver->boundary(cell->vertex(j)->info().id()).normal;
+ cell->vertex(j)->info().forces = cell->vertex(j)->info().forces+tempVect*cell->info().p();
+ //define the cached value for later use with cache*p
+ cell->info().unitForceVectors[j]=cell->info().unitForceVectors[j]+ tempVect;
+ }
+ /// Apply weighted forces f_k=sqRad_k/sumSqRad*f
+ CVector Facet_Unit_Force = -fluidSurfk*cell->info().solidLine[j][3];
+ CVector Facet_Force = cell->info().p()*Facet_Unit_Force;
+
+ for (int y=0; y<3;y++) {
+ cell->vertex(facetVertices[j][y])->info().forces = cell->vertex(facetVertices[j][y])->info().forces + Facet_Force*cell->info().solidLine[j][y];
+ //add to cached value
+ cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]+Facet_Unit_Force*cell->info().solidLine[j][y];
+ //uncomment to get total force / comment to get only pore tension forces
+ if (!cell->vertex(facetVertices[j][y])->info().isFictious) {
+ cell->vertex(facetVertices[j][y])->info().forces = cell->vertex(facetVertices[j][y])->info().forces -facetNormal*cell->info().p()*crossSections[j][y];
+ //add to cached value
+ cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]-facetNormal*crossSections[j][y];
+ }
+ }
+ #ifdef parallel_forces
+ solver->perVertexUnitForce[cell->vertex(j)->info().id()].push_back(&(cell->info().unitForceVectors[j]));
+ solver->perVertexPressure[cell->vertex(j)->info().id()].push_back(&(cell->info().p()));
+ #endif
+ }
+ }
+ solver->noCache=false;//cache should always be defined after execution of this function
+ if (onlyCache) return;
+ } else {//use cached values when triangulation doesn't change
+ #ifndef parallel_forces
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ for (int yy=0;yy<4;yy++) cell->vertex(yy)->info().forces = cell->vertex(yy)->info().forces + cell->info().unitForceVectors[yy]*cell->info().p();}
+
+ #else
+ #pragma omp parallel for num_threads(ompThreads)
+ for (int vn=0; vn<= solver->T[currentTes].maxId; vn++) {
+ VertexHandle& v = solver->T[currentTes].vertexHandles[vn];
+// for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v){
+ const int& id = v->info().id();
+ CVector tf (0,0,0);
+ int k=0;
+ for (vector<const Real*>::iterator c = solver->perVertexPressure[id].begin(); c != solver->perVertexPressure[id].end(); c++)
+ tf = tf + (*(solver->perVertexUnitForce[id][k++]))*(**c);
+ v->info().forces = tf;
+ }
+ #endif
+ }
+ if (solver->debugOut) {
+ CVector TotalForce = nullVect;
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
+ if (!v->info().isFictious) TotalForce = TotalForce + v->info().forces;
+ else if (solver->boundary(v->info().id()).flowCondition==1) TotalForce = TotalForce + v->info().forces; }
+ cout << "TotalForce = "<< TotalForce << endl;}
+}
+
+#endif //UNSATURATED_FLOW
+#endif //FLOW_ENGINE
\ No newline at end of file