yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #11421
[Branch ~yade-pkg/yade/git-trunk] Rev 3417: Merge github.com:yade/trunk into chaoUnsat
Merge authors:
Alexander Eulitz [Eugen] (kubeu)
Anton Gladky (gladky-anton)
Anton Gladky (gladky-anton)
Bruno Chareyre (bruno-chareyre)
Bruno Chareyre (bruno-chareyre)...
------------------------------------------------------------
revno: 3417 [merge]
committer: Chao Yuan <chaoyuan2012@xxxxxxxxx>
timestamp: Fri 2014-05-09 16:24:08 +0200
message:
Merge github.com:yade/trunk into chaoUnsat
Conflicts:
lib/triangulation/FlowBoundingSphere.cpp
lib/triangulation/FlowBoundingSphere.ipp
lib/triangulation/Network.hpp
lib/triangulation/RegularTriangulation.h
lib/triangulation/Tesselation.h
lib/triangulation/def_types.h
pkg/dem/FlowEngine.cpp
removed:
lib/triangulation/PeriodicFlow.cpp
lib/triangulation/def_types.h
pkg/dem/FlowEngine.cpp
pkg/dem/FlowEngine.hpp
added:
examples/FluidCouplingLBM/
examples/FluidCouplingLBM/Buoyancy_Gradient.m
examples/FluidCouplingLBM/buoyancy.py
examples/FluidCouplingLBM/yadeLBMvisu.m
examples/ViscElMatchMaker.py
examples/capillary/
examples/capillary/capillar.py
examples/capillary/liquidmigration/
examples/capillary/liquidmigration/showcase.py
examples/sph/
examples/sph/README
examples/sph/box.geo
examples/sph/box.mesh
examples/sph/cpt/
examples/sph/cpt/a
examples/sph/sph_box.py
examples/sph/testKernelFunc.py
examples/sph/toystar.py
examples/sph/watercolumn.py
pkg/common/SPHEngine.cpp
pkg/common/SPHEngine.hpp
pkg/dem/ViscoelasticCapillarPM.hpp
pkg/lbm/
pkg/lbm/HydrodynamicsLawLBM.cpp
pkg/lbm/HydrodynamicsLawLBM.hpp
pkg/lbm/LBMbody.cpp
pkg/lbm/LBMbody.hpp
pkg/lbm/LBMlink.cpp
pkg/lbm/LBMlink.hpp
pkg/lbm/LBMnode.cpp
pkg/lbm/LBMnode.hpp
pkg/pfv/
pkg/pfv/DFNFlow.cpp
pkg/pfv/DummyFlowEngine.cpp
pkg/pfv/FlowEngine.cpp
pkg/pfv/FlowEngine.hpp
pkg/pfv/FlowEngine.ipp
pkg/pfv/PeriodicFlowEngine.cpp
pkg/pfv/SoluteFlowEngine.cpp
modified:
.gitignore
CMakeLists.txt
cMake/FindOpenBlas.cmake
core/Body.cpp
core/Body.hpp
core/Bound.hpp
core/Cell.hpp
core/Clump.cpp
core/Clump.hpp
core/InteractionContainer.hpp
core/Scene.cpp
core/Scene.hpp
core/State.hpp
doc/references.bib
doc/sphinx/installation.rst
doc/sphinx/references.bib
doc/sphinx/user.rst
doc/yade-articles.bib
doc/yade-conferences.bib
examples/FluidCouplingPFV/oedometer.py
examples/PIDController.py
examples/ResetRandomPosition.py
examples/baraban/BicyclePedalEngine.py
examples/baraban/baraban.py
examples/bulldozer/bulldozerVTK.py
examples/clumps/clump-hopper-viscoelastic.py
examples/clumps/clump-inbox-viscoelastic.py
examples/clumps/clump-viscoelastic.py
examples/jointedCohesiveFrictionalPM/gravityBis.py
examples/jointedCohesiveFrictionalPM/identifBis.py
examples/ring2d/ringSimpleViscoelastic.py
examples/rotationalResistance.py
examples/tesselationwrapper/tesselationWrapper.py
examples/test/facet-sphere-ViscElBasic-peri.py
examples/test/facet-sphere-ViscElBasic.py
examples/test/performance/checkPerf.py
examples/test/periodic-simple-shear.py
examples/test/sphere-sphere-ViscElBasic-peri.py
examples/test/vtk-exporter/vtkExporter.py
gui/qt4/GLViewer.cpp
gui/qt4/GLViewer.hpp
gui/qt4/GLViewerMouse.cpp
lib/base/Logging.hpp
lib/base/openmp-accu.hpp
lib/serialization/Serializable.hpp
lib/triangulation/FlowBoundingSphere.hpp
lib/triangulation/FlowBoundingSphere.ipp
lib/triangulation/FlowBoundingSphereLinSolv.hpp
lib/triangulation/FlowBoundingSphereLinSolv.ipp
lib/triangulation/KinematicLocalisationAnalyser.cpp
lib/triangulation/KinematicLocalisationAnalyser.hpp
lib/triangulation/Network.hpp
lib/triangulation/Network.ipp
lib/triangulation/PeriodicFlow.hpp
lib/triangulation/PeriodicFlowLinSolv.hpp
lib/triangulation/PeriodicFlowLinSolv.ipp
lib/triangulation/RegularTriangulation.h
lib/triangulation/Tenseur3.cpp
lib/triangulation/Tenseur3.h
lib/triangulation/Tesselation.h
lib/triangulation/Tesselation.ipp
lib/triangulation/TriaxialState.cpp
lib/triangulation/TriaxialState.h
pkg/common/CylScGeom6D.hpp
pkg/common/Cylinder.cpp
pkg/common/Cylinder.hpp
pkg/common/Dispatching.cpp
pkg/common/Dispatching.hpp
pkg/common/Gl1_NormPhys.hpp
pkg/common/InsertionSortCollider.cpp
pkg/common/InsertionSortCollider.hpp
pkg/common/InteractionLoop.cpp
pkg/common/KinematicEngines.cpp
pkg/common/KinematicEngines.hpp
pkg/common/OpenGLRenderer.cpp
pkg/common/PersistentTriangulationCollider.cpp
pkg/dem/ConcretePM.hpp
pkg/dem/JointedCohesiveFrictionalPM.cpp
pkg/dem/JointedCohesiveFrictionalPM.hpp
pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.cpp
pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.hpp
pkg/dem/MicroMacroAnalyser.cpp
pkg/dem/MicroMacroAnalyser.hpp
pkg/dem/NewtonIntegrator.cpp
pkg/dem/Shop.hpp
pkg/dem/Shop_02.cpp
pkg/dem/TesselationWrapper.cpp
pkg/dem/TesselationWrapper.hpp
pkg/dem/TriaxialStressController.hpp
pkg/dem/UniaxialStrainer.cpp
pkg/dem/UniaxialStrainer.hpp
pkg/dem/VTKRecorder.cpp
pkg/dem/VTKRecorder.hpp
pkg/dem/ViscoelasticCapillarPM.cpp
pkg/dem/ViscoelasticPM.cpp
pkg/dem/ViscoelasticPM.hpp
py/_polyhedra_utils.cpp
py/_utils.cpp
py/config.py.in
py/export.py
py/wrapper/yadeWrapper.cpp
scripts/checks-and-tests/checks/checkGravity.py
scripts/checks-and-tests/checks/checkViscElEng.py
scripts/checks-and-tests/checks/checkWeight.py
--
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 '.gitignore'
--- .gitignore 2013-10-15 16:14:46 +0000
+++ .gitignore 2014-04-01 13:18:38 +0000
@@ -29,4 +29,4 @@
.kdev4/
*.kdev4
*.pyc
-
+*~
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-02-18 12:02:35 +0000
+++ CMakeLists.txt 2014-05-08 07:11:18 +0000
@@ -14,6 +14,9 @@
# ENABLE_GL2PS: enable GL2PS-option (ON by default)
# ENABLE_LINSOLV: enable LINSOLV-option (ON by default)
# ENABLE_PFVFLOW: enable PFVFLOW-option, FlowEngine (ON by default)
+# ENABLE_SPH: enable SPH-option, Smoothed Particle Hydrodynamics (OFF by default, experimental)
+# ENABLE_LBMFLOW: enable LBMFLOW-option, LBM_ENGINE (OFF by default)
+# ENABLE_LIQMIGRATION: enable LIQMIGRATION-option, see [Mani2013] for details (OFF by default)
# runtimePREFIX: used for packaging, when install directory is not the same is runtime directory (/usr/local by default)
# CHUNKSIZE: set >1, if you want several sources to be compiled at once. Increases compilation speed and RAM-consumption during it (1 by default).
@@ -84,7 +87,7 @@
#===========================================================
# Add possibility to use local boost installation (e.g. -DLocalBoost=1.46.1)
-FIND_PACKAGE(Boost ${LocalBoost} COMPONENTS python thread date_time filesystem iostreams regex serialization system REQUIRED)
+FIND_PACKAGE(Boost ${LocalBoost} COMPONENTS python thread filesystem iostreams regex serialization system REQUIRED)
INCLUDE_DIRECTORIES (${Boost_INCLUDE_DIRS})
# for checking purpose
MESSAGE("-- Boost_VERSION: " ${Boost_VERSION})
@@ -116,6 +119,9 @@
OPTION(ENABLE_GL2PS "Enable GL2PS" ${DEFAULT})
OPTION(ENABLE_LINSOLV "Enable direct solver for the flow engines (experimental)" ${DEFAULT})
OPTION(ENABLE_PFVFLOW "Enable flow engine (experimental)" ${DEFAULT})
+OPTION(ENABLE_SPH "Enable SPH" OFF)
+OPTION(ENABLE_LBMFLOW "Enable LBM engine (very experimental)" OFF)
+OPTION(ENABLE_LIQMIGRATION "Enable liquid control (very experimental), see [Mani2013] for details" OFF)
#===========================================================
# Use Eigen3 by default
@@ -286,6 +292,20 @@
SET(DISABLED_FEATS "${DISABLED_FEATS} LinSolv")
ENDIF(ENABLE_LINSOLV)
#===============================================
+IF(ENABLE_SPH)
+ ADD_DEFINITIONS("-DYADE_SPH")
+ SET(CONFIGURED_FEATS "${CONFIGURED_FEATS} SPH")
+ELSE(ENABLE_SPH)
+ SET(DISABLED_FEATS "${DISABLED_FEATS} SPH")
+ENDIF(ENABLE_SPH)
+#===============================================
+IF(ENABLE_LIQMIGRATION)
+ ADD_DEFINITIONS("-DYADE_LIQMIGRATION")
+ SET(CONFIGURED_FEATS "${CONFIGURED_FEATS} LIQMIGRATION")
+ELSE(ENABLE_LIQMIGRATION)
+ SET(DISABLED_FEATS "${DISABLED_FEATS} LIQMIGRATION")
+ENDIF(ENABLE_LIQMIGRATION)
+#===============================================
IF(ENABLE_GL2PS)
FIND_PACKAGE(GL2PS)
IF(GL2PS_FOUND)
@@ -308,6 +328,15 @@
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
#===========================================================
+IF(ENABLE_LBMFLOW)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLBM_ENGINE")
+ SET(CONFIGURED_FEATS "${CONFIGURED_FEATS} LBMFLOW")
+ MESSAGE("LBMFLOW is still experimental, building and running LBM engine are at your own risk!")
+ELSE(ENABLE_LBMFLOW)
+ SET(DISABLED_FEATS "${DISABLED_FEATS} LBMFLOW")
+ENDIF(ENABLE_LBMFLOW)
+
+#===========================================================
IF (NOT INSTALL_PREFIX)
SET(CMAKE_INSTALL_PREFIX "/usr/local")
@@ -395,14 +424,15 @@
#===========================================================
ADD_LIBRARY(boot SHARED ${CMAKE_CURRENT_SOURCE_DIR}/core/main/pyboot.cpp)
-SET_TARGET_PROPERTIES(boot PROPERTIES PREFIX "")
-TARGET_LINK_LIBRARIES(yade ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${LINKLIBS} ${LOKI_LIBRARY} -lrt)
+SET_TARGET_PROPERTIES(boot PROPERTIES PREFIX "" LINK_FLAGS "-Wl,--as-needed" )
+TARGET_LINK_LIBRARIES(yade ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${LINKLIBS} -lrt)
TARGET_LINK_LIBRARIES(boot yade)
IF(ENABLE_VTK)
IF(${VTK_MAJOR_VERSION} EQUAL 6)
TARGET_LINK_LIBRARIES(yade ${VTK_LIBRARIES})
ADD_DEFINITIONS("-DYADE_VTK6")
+ MESSAGE(STATUS "VTK version 6 is found")
ELSE(${VTK_MAJOR_VERSION} EQUAL 6)
TARGET_LINK_LIBRARIES(yade vtkHybrid)
ENDIF(${VTK_MAJOR_VERSION} EQUAL 6)
=== modified file 'cMake/FindOpenBlas.cmake'
--- cMake/FindOpenBlas.cmake 2013-06-26 18:15:55 +0000
+++ cMake/FindOpenBlas.cmake 2014-02-28 09:40:54 +0000
@@ -1,10 +1,10 @@
# - Find OpenBlas library
#
# This module defines
-# OPENBLAS_LIBRARY, libraries to link against to use GL2PS.
-# OPENBLAS_FOUND, If false, do not try to use GL2PS.
+# OPENBLAS_LIBRARY, libraries to link against to use Openblas.
+# OPENBLAS_FOUND, If false, do not try to use Openblas.
-FIND_LIBRARY(OPENBLAS_LIBRARY NAMES openblas PATHS /usr/lib/openblas-base )
+FIND_LIBRARY(OPENBLAS_LIBRARY NAMES openblas blas PATHS /usr/lib/openblas-base )
# handle the QUIETLY and REQUIRED arguments and set LOKI_FOUND to TRUE if
# all listed variables are TRUE
=== modified file 'core/Body.cpp'
--- core/Body.cpp 2013-02-19 07:07:27 +0000
+++ core/Body.cpp 2014-04-09 14:03:16 +0000
@@ -21,3 +21,13 @@
return ret;
}
+// return list of interactions of this particle
+unsigned int Body::coordNumber(){
+ unsigned int intrSize = 0;
+ for(Body::MapId2IntrT::iterator it=this->intrs.begin(),end=this->intrs.end(); it!=end; ++it) { //Iterate over all bodie's interactions
+ if(!(*it).second->isReal()) continue;
+ intrSize++;
+ }
+ return intrSize;
+}
+
=== modified file 'core/Body.hpp'
--- core/Body.hpp 2012-09-21 19:03:18 +0000
+++ core/Body.hpp 2014-05-08 05:57:04 +0000
@@ -56,7 +56,7 @@
void setBounded(bool d){ if(d) flags|=FLAG_BOUNDED; else flags&=~(FLAG_BOUNDED); }
bool isAspherical() const {return flags & FLAG_ASPHERICAL; }
void setAspherical(bool d){ if(d) flags|=FLAG_ASPHERICAL; else flags&=~(FLAG_ASPHERICAL); }
-
+
/*! Hook for clump to update position of members when user-forced reposition and redraw (through GUI) occurs.
* This is useful only in cases when engines that do that in every iteration are not active - i.e. when the simulation is paused.
* (otherwise, GLViewer would depend on Clump and therefore Clump would have to go to core...) */
@@ -65,6 +65,7 @@
python::list py_intrs();
Body::id_t getId() const {return id;};
+ unsigned int coordNumber(); // Number of neighboring particles
int getGroupMask() {return groupMask; };
bool maskOk(int mask){return (mask==0 || (groupMask&mask));}
@@ -87,6 +88,16 @@
((long,chain,-1,,"Id of chain to which the body belongs."))
((long,iterBorn,-1,,"Step number at which the body was added to simulation."))
((Real,timeBorn,-1,,"Time at which the body was added to simulation."))
+#ifdef YADE_SPH
+ ((Real,rho, -1.0,, "Current density (only for SPH-model)")) // [Mueller2003], (12)
+ ((Real,rho0,-1.0,, "Rest density (only for SPH-model)")) // [Mueller2003], (12)
+ ((Real,press,0.0,, "Pressure (only for SPH-model)")) // [Mueller2003], (12)
+ ((Real,Cs,0.0,, "Color field (only for SPH-model)")) // [Mueller2003], (15)
+#endif
+#ifdef YADE_LIQMIGRATION
+ ((Real,Vf, -1.0,, "Individual amount of liquid"))
+ ((Real,Vmin,-1.0,, "Minimal amount of liquid"))
+#endif
,
/* ctor */,
/* py */
@@ -103,6 +114,11 @@
.add_property("timeBorn",&Body::timeBorn,"Returns time at which the body was added to simulation.")
.def_readwrite("chain",&Body::chain,"Returns Id of chain to which the body belongs.")
.def("intrs",&Body::py_intrs,"Return all interactions in which this body participates.")
+#ifdef YADE_SPH
+ .add_property("rho", &Body::rho, "Returns the current density (only for SPH-model).")
+ .add_property("rho0", &Body::rho0,"Returns the rest density (only for SPH-model).")
+ .add_property("press",&Body::press,"Returns the pressure (only for SPH-model).")
+#endif
);
};
REGISTER_SERIALIZABLE(Body);
=== modified file 'core/Bound.hpp'
--- core/Bound.hpp 2012-01-23 14:43:54 +0000
+++ core/Bound.hpp 2014-04-28 11:49:53 +0000
@@ -28,7 +28,7 @@
((Real,sweepLength,0, Attr::readonly,"The length used to increase the bounding boxe size, can be adjusted on the basis of previous displacement if :yref:`BoundDispatcher::targetInterv`>0. |yupdate|"))
((Vector3r,color,Vector3r(1,1,1),,"Color for rendering this object"))
((Vector3r,min,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Lower corner of box containing this bound (and the :yref:`Body` as well)"))
- ((Vector3r,max,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Lower corner of box containing this bound (and the :yref:`Body` as well)"))
+ ((Vector3r,max,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Upper corner of box containing this bound (and the :yref:`Body` as well)"))
,
/*deprec*/,
/* init */,
=== modified file 'core/Cell.hpp'
--- core/Cell.hpp 2013-09-11 10:54:47 +0000
+++ core/Cell.hpp 2014-03-24 12:23:56 +0000
@@ -170,7 +170,7 @@
.add_property("refSize",&Cell::getRefSize,&Cell::setRefSize,"Reference size of the cell (lengths of initial cell vectors, i.e. column norms of :yref:`hSize<Cell.hSize>`).\n\n.. note::\n\t Modifying this value is deprecated, use :yref:`setBox<Cell.setBox>` instead.")
// useful properties
.add_property("trsf",&Cell::getTrsf,&Cell::setTrsf,"Current transformation matrix of the cell, obtained from time integration of :yref:`Cell.velGrad`.")
- .add_property("velGrad",&Cell::getVelGrad,&Cell::setVelGrad,"Velocity gradient of the transformation; used in :yref:`NewtonIntegrator`. Values of :yref:`velGrad<Cell.velGrad>` accumulate in :yref:`trsf<Cell.trsf>` at every step.\n\n NOTE: changing velGrad at the beginning of a simulation loop would lead to inacurate integration for one step, as it should normaly be changed after the contact laws (but before Newton). To avoid this problem, assignment is deferred automatically. The target value typed in terminal is actually stored in :yref:`Cell.nextVelGrad` and will be applied right in time by Newton integrator.")
+ .add_property("velGrad",&Cell::getVelGrad,&Cell::setVelGrad,"Velocity gradient of the transformation; used in :yref:`NewtonIntegrator`. Values of :yref:`velGrad<Cell.velGrad>` accumulate in :yref:`trsf<Cell.trsf>` at every step.\n\n NOTE: changing velGrad at the beginning of a simulation loop would lead to inacurate integration for one step, as it should normaly be changed after the contact laws (but before Newton). To avoid this problem, assignment is deferred automatically. The target value typed in terminal is actually stored in :yref:`Cell.nextVelGrad` and will be applied right in time by Newton integrator. \n\n.. note::\n\t Assigning individual components of velGrad is not possible (it will not return any error but it will have no effect). Instead, you can assign to :yref:`Cell.nextVelGrad`, as in O.cell.nextVelGrad[1,2]=1.")
.def_readonly("size",&Cell::getSize_copy,"Current size of the cell, i.e. lengths of the 3 cell lateral vectors contained in :yref:`Cell.hSize` columns. Updated automatically at every step.")
.add_property("volume",&Cell::getVolume,"Current volume of the cell.")
// functions
=== modified file 'core/Clump.cpp'
--- core/Clump.cpp 2013-10-04 11:41:10 +0000
+++ core/Clump.cpp 2014-03-15 15:30:36 +0000
@@ -32,9 +32,9 @@
assert(member->isClumpMember());
member->clumpId=clumpBody->id;
clump->members[memberId]=Se3r();// meaningful values will be put in by Clump::updateProperties
- LOG_DEBUG("Added body #"<<memberId->id<<" to clump #"<<clumpBody->id);
+ //LOG_DEBUG("Added body #"<<memberId->id<<" to clump #"<<clumpBody->id);
}
- LOG_DEBUG("Clump #"<<subClump->id<<" will be erased.");// see addToClump() in yadeWrapper.cpp
+ //LOG_DEBUG("Clump #"<<subClump->id<<" will be erased.");// see addToClump() in yadeWrapper.cpp
}
else{ // subBody must be a standalone!
clump->members[subId]=Se3r();// meaningful values will be put in by Clump::updateProperties
@@ -82,7 +82,7 @@
*/
-void Clump::updateProperties(const shared_ptr<Body>& clumpBody, unsigned int discretization, bool integrateInertia){
+void Clump::updateProperties(const shared_ptr<Body>& clumpBody, unsigned int discretization){
LOG_DEBUG("Updating clump #"<<clumpBody->id<<" parameters");
const shared_ptr<State> state(clumpBody->state);
const shared_ptr<Clump> clump(YADE_PTR_CAST<Clump>(clumpBody->shape));
@@ -110,7 +110,7 @@
bool intersecting = false;
shared_ptr<Sphere> sph (new Sphere);
int Sph_Index = sph->getClassIndexStatic(); // get sphere index for checking if bodies are spheres
- if (integrateInertia){
+ if (discretization>0){
FOREACH(MemberMap::value_type& mm, clump->members){
const shared_ptr<Body> subBody1=Body::byId(mm.first);
FOREACH(MemberMap::value_type& mm, clump->members){
@@ -120,9 +120,10 @@
const Sphere* sphere1 = YADE_CAST<Sphere*> (subBody1->shape.get());
const Sphere* sphere2 = YADE_CAST<Sphere*> (subBody2->shape.get());
Real un = (sphere1->radius+sphere2->radius) - dist.norm();
- if (un > -0.001*min(sphere1->radius,sphere2->radius)) {intersecting = true; break;}
+ if (un > 0.001*min(sphere1->radius,sphere2->radius)) {intersecting = true; break;}
}
}
+ if (intersecting) break;
}
}
/* quantities suffixed by
@@ -153,9 +154,11 @@
}
//get volume and inertia tensor using regular cubic cell array inside bounding box of the clump:
Real dx = rMin/discretization; //edge length of cell
- Real aabbMax = max(max(aabb.max().x()-aabb.min().x(),aabb.max().y()-aabb.min().y()),aabb.max().z()-aabb.min().z());
- if (aabbMax/dx > 150) dx = aabbMax/150;//limit dx
+ //Real aabbMax = max(max(aabb.max().x()-aabb.min().x(),aabb.max().y()-aabb.min().y()),aabb.max().z()-aabb.min().z());
+ //if (aabbMax/dx > 150) dx = aabbMax/150;//limit dx: leads to bug, when long chain of clump members is created (https://bugs.launchpad.net/yade/+bug/1273172)
Real dv = pow(dx,3); //volume of cell
+ long nCells=(aabb.sizes()/dx).prod();
+ if(nCells>1e7) LOG_WARN("Clump::updateProperties: Cell array has "<<nCells<<" cells. Integrate inertia may take a while ...");
Vector3r x; //position vector (center) of cell
for(x.x()=aabb.min().x()+dx/2.; x.x()<aabb.max().x(); x.x()+=dx){
for(x.y()=aabb.min().y()+dx/2.; x.y()<aabb.max().y(); x.y()+=dx){
@@ -169,7 +172,7 @@
M += dv;
Sg += dv*x;
//inertia I = sum_i( mass_i*dist^2 + I_s) ) //steiners theorem
- Ig += dv*( x.dot(x)*Matrix3r::Identity()-x*x.transpose()/*dist^2*/+Matrix3r(Vector3r::Constant(dv*pow(dx,2)/6.).asDiagonal())/*I_s/m = d^2: along princial axes of dv; perhaps negligible?*/);
+ Ig += dv*( x.dot(x)*Matrix3r::Identity()-x*x.transpose())/*dist^2*/+Matrix3r(Vector3r::Constant(dv*pow(dx,2)/6.).asDiagonal())/*I_s/m = d^2: along princial axes of dv; perhaps negligible?*/;
break;
}
}
@@ -180,7 +183,7 @@
}
if(!intersecting){
FOREACH(MemberMap::value_type& mm, clump->members){
- // I.first is Body::id_t, I.second is Se3r of that body
+ // mm.first is Body::id_t, mm.second is Se3r of that body
const shared_ptr<Body> subBody=Body::byId(mm.first);
dens = subBody->material->density;
if (subBody->shape->getClassIndex() == Sph_Index){//clump member should be a sphere
=== modified file 'core/Clump.hpp'
--- core/Clump.hpp 2013-10-04 11:41:10 +0000
+++ core/Clump.hpp 2014-02-27 08:27:24 +0000
@@ -61,7 +61,7 @@
static void add(const shared_ptr<Body>& clump, const shared_ptr<Body>& subBody);
static void del(const shared_ptr<Body>& clump, const shared_ptr<Body>& subBody);
//! Recalculate physical properties of Clump.
- static void updateProperties(const shared_ptr<Body>& clump, unsigned int discretization, bool integrateInertia);
+ static void updateProperties(const shared_ptr<Body>& clump, unsigned int discretization);
//! Calculate positions and orientations of members based on relative Se3; newton pointer (if non-NULL) calls NewtonIntegrator::saveMaximaVelocity
// done as template to avoid cross-dependency between clump and newton (not necessary if all plugins are linked together)
template<class IntegratorT>
=== modified file 'core/InteractionContainer.hpp'
--- core/InteractionContainer.hpp 2014-02-03 11:21:42 +0000
+++ core/InteractionContainer.hpp 2014-02-22 04:56:33 +0000
@@ -37,10 +37,6 @@
Future (?):
-* The shared_ptr<Interaction> might be duplicated in body id2 as well. That would allow to retrieve
- in a straigthforward manner all interactions with given body id, for instance. Performance implications
- are not clear.
-
* the linear vector might be removed; in favor of linear traversal of bodies by their subdomains,
then traversing the map in each body. If the previous point would come to realization, half of the
interactions would have to be skipped explicitly in such a case.
@@ -112,14 +108,31 @@
*/
template<class T> size_t conditionalyEraseNonReal(const T& t, Scene* rb){
// beware iterators here, since erase is invalidating them. We need to iterate carefully, and keep in mind that erasing one interaction is moving the last one to the current position.
+ // For the parallel flavor we build the list to be erased in parallel, then it is erased sequentially. Still significant speedup since checking bounds is the most expensive part.
+ #ifndef YADE_OPENMP
size_t initSize=currSize;
for (size_t linPos=0; linPos<currSize;){
const shared_ptr<Interaction>& i=linIntrs[linPos];
if(!i->isReal() && t.shouldBeErased(i->getId1(),i->getId2(),rb)) erase(i->getId1(),i->getId2(),linPos);
else linPos++;}
return initSize-currSize;
+ #else
+ unsigned nThreads= omp_get_max_threads();
+ assert(nThreads>0);
+ std::vector<std::vector<Vector3i > >toErase;
+ toErase.resize(nThreads,std::vector<Vector3i >());
+ for (unsigned kk=0; kk<nThreads; kk++) toErase[kk].reserve(1000);//A smarter value than 1000?
+ size_t initSize=currSize;
+ #pragma omp parallel for schedule(guided,100) num_threads(nThreads)
+ for (size_t linPos=0; linPos<currSize;linPos++){
+ const shared_ptr<Interaction>& i=linIntrs[linPos];
+ if(!i->isReal() && t.shouldBeErased(i->getId1(),i->getId2(),rb)) toErase[omp_get_thread_num()].push_back(Vector3i(i->getId1(),i->getId2(),linPos)) ;
+ }
+ for (unsigned int kk=0; kk<nThreads; kk++) for (size_t ii(0), jj(toErase[kk].size()); ii<jj;ii++) erase(toErase[kk][ii][0],toErase[kk][ii][1],toErase[kk][ii][2]);
+ return initSize-currSize;
+ #endif
}
-
+
// we must call Scene's ctor (and from Scene::postLoad), since we depend on the existing BodyContainer at that point.
void postLoad__calledFromScene(const shared_ptr<BodyContainer>&);
void preLoad(InteractionContainer&);
=== modified file 'core/Scene.cpp'
--- core/Scene.cpp 2013-08-23 15:21:20 +0000
+++ core/Scene.cpp 2014-05-08 05:57:04 +0000
@@ -203,5 +203,6 @@
}
}
bound->min=mn;
- bound->max=mx;
+ bound->max=mx;
}
+
=== modified file 'core/Scene.hpp'
--- core/Scene.hpp 2013-10-02 12:47:38 +0000
+++ core/Scene.hpp 2014-05-08 05:57:04 +0000
@@ -23,13 +23,23 @@
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif
-
+#ifdef YADE_OPENMP
+ #include<omp.h>
+#endif
class Bound;
#ifdef YADE_OPENGL
class OpenGLRenderer;
#endif
+#ifdef YADE_LIQMIGRATION
+struct intReal {
+ public:
+ id_t id;
+ Real Vol;
+};
+#endif
+
class Scene: public Serializable{
public:
//! Adds material to Scene::materials. It also sets id of the material accordingly and returns it.
@@ -60,6 +70,11 @@
shared_ptr<Engine> engineByName(const string& s);
+ #ifdef YADE_LIQMIGRATION
+ OpenMPVector<Interaction* > addIntrs; //Array of added interactions, needed for liquid migration.
+ OpenMPVector<intReal > delIntrs; //Array of deleted interactions, needed for liquid migration.
+ #endif
+
#ifdef YADE_OPENGL
shared_ptr<OpenGLRenderer> renderer;
#endif
=== modified file 'core/State.hpp'
--- core/State.hpp 2013-02-26 10:56:01 +0000
+++ core/State.hpp 2014-03-27 14:52:07 +0000
@@ -73,7 +73,7 @@
.add_property("pos",&State::pos_get,&State::pos_set,"Current position.")
.add_property("ori",&State::ori_get,&State::ori_set,"Current orientation.")
.def("displ",&State::displ,"Displacement from :yref:`reference position<State.refPos>` (:yref:`pos<State.pos>` - :yref:`refPos<State.refPos>`)")
- .def("rot",&State::rot,"Rotation from :yref:`reference orientation<State.refPos>` (as rotation vector)")
+ .def("rot",&State::rot,"Rotation from :yref:`reference orientation<State.refOri>` (as rotation vector)")
);
REGISTER_INDEX_COUNTER(State);
DECLARE_LOGGER;
=== modified file 'doc/references.bib'
--- doc/references.bib 2014-01-29 16:26:55 +0000
+++ doc/references.bib 2014-05-08 05:57:04 +0000
@@ -631,6 +631,17 @@
author = "Diego Mas Ivars and Matthew E. Pierce and Caroline Darcel and Juan Reyes-Montes and David O. Potyondy and R. Paul Young and Peter A. Cundall"
}
+@article{Potyondy2004,
+title = "A bonded-particle model for rock ",
+journal = "International Journal of Rock Mechanics and Mining Sciences ",
+volume = "41",
+number = "8",
+pages = "1329 - 1364",
+year = "2004",
+doi = "10.1016/j.ijrmms.2004.09.011",
+author = "D.O. Potyondy and P.A. Cundall"
+}
+
@book{Radjai2011,
title={Discrete-Element Modeling of Granular Materials},
author={Radjai, F. and Dubois, F.},
@@ -659,7 +670,7 @@
@article{Lambert2008,
title={Comparison between two capillary forces models},
- author={Lambert, Pierre and Chau, Alexandre and Delchambre, Alain and R{\'e}gnier, St{\'e}phane},
+ author={Lambert, Pierre and Chau, Alexandre and Delchambre, Alain and Régnier, Stéphane},
journal={Langmuir},
volume={24},
number={7},
@@ -667,3 +678,50 @@
year={2008},
publisher={ACS Publications}
}
+
+@inproceedings{Mueller2003,
+ author = {M\"{u}ller, Matthias and Charypar, David and Gross, Markus},
+ title = {Particle-based Fluid Simulation for Interactive Applications},
+ booktitle = {Proceedings of the 2003 ACM SIGGRAPH/Eurographics Symposium on Computer Animation},
+ series = {SCA '03},
+ year = {2003},
+ isbn = {1-58113-659-5},
+ location = {San Diego, California},
+ pages = {154--159},
+ numpages = {6},
+ url = {http://dl.acm.org/citation.cfm?id=846276.846298},
+ acmid = {846298},
+ publisher = {Eurographics Association},
+ address = {Aire-la-Ville, Switzerland, Switzerland},
+}
+
+@article {Soulie2006,
+ author = {Soulié, F. and Cherblanc, F. and El Youssoufi, M.S. and Saix, C.},
+ title = {Influence of liquid bridges on the mechanical behaviour of polydisperse granular materials},
+ journal = {International Journal for Numerical and Analytical Methods in Geomechanics},
+ volume = {30},
+ number = {3},
+ publisher = {John Wiley & Sons, Ltd.},
+ issn = {1096-9853},
+ url = {http://dx.doi.org/10.1002/nag.476},
+ doi = {10.1002/nag.476},
+ pages = {213--228},
+ keywords = {liquid bridge, polydisperse, cohesion, capillary force, humid granular media, DEM simulation},
+ year = {2006},
+}
+
+@article{Mani2013,
+ year={2013},
+ issn={1434-5021},
+ journal={Granular Matter},
+ volume={15},
+ number={4},
+ doi={10.1007/s10035-012-0387-3},
+ title={Liquid migration in sheared unsaturated granular media},
+ url={http://dx.doi.org/10.1007/s10035-012-0387-3},
+ publisher={Springer Berlin Heidelberg},
+ keywords={Wet granular matter; Contact dynamics simulations; Liquid bridge; Cohesion; Liquid migration},
+ author={Mani, Roman and Kadau, Dirk and Herrmann, HansJ.},
+ pages={447-454},
+ language={English}
+}
=== modified file 'doc/sphinx/installation.rst'
--- doc/sphinx/installation.rst 2014-02-03 16:11:58 +0000
+++ doc/sphinx/installation.rst 2014-04-26 12:37:18 +0000
@@ -22,12 +22,15 @@
sudo bash -c 'echo "deb http://www.yade-dem.org/packages/ precise/" >> /etc/apt/sources.list'
wget -O - http://www.yade-dem.org/packages/yadedev_pub.gpg | sudo apt-key add -
+ sudo apt-get update
sudo apt-get install yadedaily
-If you have another distribution, not Ubuntu Precise, be sure to use the
+If you have another distribution, not Ubuntu Precise (Version 12.04), be sure to use the
correct name in the first line (for instance, jessie, trusty or wheezy).
After that you can normally start Yade using "yadedaily" or "yadedaily-batch" command.
+yadedaily on older distributions can have some disabled features due to older library
+versions, shipped with particular distribution.
Git-repository for packaging stuff is available on `GitHub <https://github.com/yade/yadedaily/>`_.
Each branch corresponds to one distribution e.g. precise, jessie etc.
@@ -124,8 +127,10 @@
Most of the list above is very likely already packaged for your distribution. In case you are confronted
with some errors concerning not available packages (e.g. Package libmetis-dev is not available) it may be necessary
to add yade external ppa from https://launchpad.net/~yade-users/+archive/external::
+
sudo add-apt-repository ppa:yade-users/external
sudo apt-get update
+
The following commands have to be executed in command line of corresponding
distributions. Just copy&paste to the terminal. To perform commands you
should have root privileges
@@ -142,7 +147,7 @@
libgts-dev python-pygraphviz libvtk5-dev python-scientific libeigen3-dev \
python-xlib python-qt4 pyqt4-dev-tools gtk2-engines-pixbuf python-argparse \
libqglviewer-dev python-imaging libjs-jquery python-sphinx python-git python-bibtex \
- libxmu-dev libxi-dev libcgal-dev help2man libbz2-dev zlib1g-dev \
+ libxmu-dev libxi-dev libcgal-dev help2man libbz2-dev zlib1g-dev
Some of packages (for example, cmake, eigen3) are mandatory, some of them
@@ -152,37 +157,42 @@
Additional packages, which can become mandatory later::
- sudo apt-get install python-gts python-minieigen \
+ sudo apt-get install python-gts python-minieigen
-For effective usage of direct solvers in the fluid coupling, the following libraries are recommended, together with eigen>=3.1: blas, lapack, suitesparse, and metis.
-All four of them are available in many different versions. Different combinations are possible and not all of them will work. The following was found to be effective on ubuntu 12.04 and debian wheezy.
-(openblas provides its own version of lapack, and suitesparse-metis will trigger the installation of parmetis)::
+For effective usage of direct solvers in the PFV-type fluid coupling, the following libraries are recommended, together with eigen>=3.1: blas, lapack, suitesparse, and metis.
+All four of them are available in many different versions. Different combinations are possible and not all of them will work. The following was found to be effective on recent deb-based systems. On ubuntu 12.04, better compile openblas with USE_OPENMP=1, else yade will run on a single core::
- sudo apt-get install libopenblas-dev libsuitesparse-metis-dev \
+ sudo apt-get install libopenblas-dev libsuitesparse-metis-dev
Some packages listed here are relatively new and they can be absent
in your distribution (for example, libmetis-dev or python-gts). They can be
installed from our `external PPA <https://launchpad.net/~yade-users/+archive/external/>`_
or just ignored. In this case some features can be disabled.
-If you are using other distribuition, than Debian or its derivatives, you should
+If you are using other distribution, than Debian or its derivatives, you should
install the softwares listed above. Their names can differ from the
names of Debian-packages.
-
-
-
-
Compilation
^^^^^^^^^^^
You should create a separate build-place-folder, where Yade will be configured
-and where the source code will be compiled. Then inside this build-directory you
-should start cmake to configure the compilation process::
+and where the source code will be compiled. Here is an example for a folderstructure:
+
+ myYade/ ## base directory
+ trunk/ ## folder for sourcecode in which you use github
+ build/ ## folder in which sources will be compiled; build-directory; use cmake here
+ install/ ## installfolder
+
+Then inside this build-directory you should start cmake to configure the compilation process::
cmake -DINSTALL_PREFIX=/path/to/installfolder /path/to/sources
+For the folder structure given above call the following command in folder "build":
+
+ cmake -DINSTALL_PREFIX=../install ../trunk
+
Additional options can be configured in the same line with the following
syntax::
@@ -228,7 +238,11 @@
and split the compilation on many cores. For example, on 4-core machines
it would be reasonable to set the parameter ``-j4``. Note, the Yade requires
approximately 2GB/core for compilation, otherwise the swap-file will be used
-and a compilation time dramatically increases.
+and a compilation time dramatically increases. After compilation finished successfully
+the new built can be started by navigating to /path/to/installfolder/bin and calling yade via (based on version yade-2014-02-20.git-a7048f4)::
+
+ cd /path/to/installfolder/bin
+ ./yade-2014-02-20.git-a7048f4
For building the documentation you should at first execute the command "make install"
and then "make doc" to build it. The generated files will be stored in your current
=== modified file 'doc/sphinx/references.bib'
--- doc/sphinx/references.bib 2013-10-04 12:35:58 +0000
+++ doc/sphinx/references.bib 2014-04-15 13:55:10 +0000
@@ -116,6 +116,16 @@
publisher = {American Physical Society}
}
+@article{Potyondy2004,
+title = "A bonded-particle model for rock ",
+journal = "International Journal of Rock Mechanics and Mining Sciences ",
+volume = "41",
+number = "8",
+pages = "1329 - 1364",
+year = "2004",
+doi = "10.1016/j.ijrmms.2004.09.011",
+author = "D.O. Potyondy and P.A. Cundall"
+}
@article{Jung1997,
author={Derek Jung and Kamal K. Gupta},
=== modified file 'doc/sphinx/user.rst'
--- doc/sphinx/user.rst 2013-12-20 14:12:32 +0000
+++ doc/sphinx/user.rst 2014-05-06 15:32:52 +0000
@@ -1379,8 +1379,8 @@
# …
O.saveGnuplot(O.tags['id']+'/'+'graph1')
-Controlling parallel compuation
--------------------------------
+Controlling parallel computation
+--------------------------------
Default total number of available cores is determined from ``/proc/cpuinfo`` (provided by Linux kernel); in addition, if ``OMP_NUM_THREADS`` environment variable is set, minimum of these two is taken. The ``-j``/``--jobs`` option can be used to override this number.
@@ -1391,7 +1391,7 @@
If number of cores for a job exceeds total number of cores, warning is issued and only the total number of cores is used instead.
Merging gnuplot from individual jobs
--------------------------------------
+------------------------------------
Frequently, it is desirable to obtain single figure for all jobs in the batch, for comparison purposes. Somewhat heiristic way for this functionality is provided by the batch system. ``yade-batch`` must be run with the ``--gnuplot`` option, specifying some file name that will be used for the merged figure::
@@ -1528,7 +1528,7 @@
Micro-stress and micro-strain
=============================
-It is sometimes useful to visualize a DEM simulation through equivalent strain fields or stress fields. This is possible with :yref:`TesselationWrapper`. This class handles the triangulation of spheres in a scene, build tesselation on request, and give access to computed quantities: volume, porosity and local deformation for each sphere. The definition of microstrain and microstress is at the scale of particle-centered subdomains shown below, as explained in [Catalano2013a]_ .
+It is sometimes useful to visualize a DEM simulation through equivalent strain fields or stress fields. This is possible with :yref:`TesselationWrapper`. This class handles the triangulation of spheres in a scene, build tesselation on request, and give access to computed quantities: volume, porosity and local deformation for each sphere. The definition of microstrain and microstress is at the scale of particle-centered subdomains shown below, as explained in [Catalano2014a]_ .
.. figure:: fig/micro-domains.*
@@ -1557,7 +1557,7 @@
Micro-stress
------------
-Stress fields can be generated by combining the volume returned by TesselationWrapper to per-particle stress given by :yref:`bodyStressTensors<yade._utils.bodyStressTensors>`. Since the stress $\sigma$ from bodyStressTensor implies a division by the volume $V_b$ of the solid particle, one has to re-normalize it in order to obtain the micro-stress as defined in [Catalano2013a]_ (equation 39 therein), i.e. $\overline{\sigma}^k = \sigma^k \times V_b^k / V_{\sigma}^k$ where $V_{\sigma}^k$ is the volume assigned to particle $k$ in the tesselation. For instance:
+Stress fields can be generated by combining the volume returned by TesselationWrapper to per-particle stress given by :yref:`bodyStressTensors<yade._utils.bodyStressTensors>`. Since the stress $\sigma$ from bodyStressTensor implies a division by the volume $V_b$ of the solid particle, one has to re-normalize it in order to obtain the micro-stress as defined in [Catalano2014a]_ (equation 39 therein), i.e. $\overline{\sigma}^k = \sigma^k \times V_b^k / V_{\sigma}^k$ where $V_{\sigma}^k$ is the volume assigned to particle $k$ in the tesselation. For instance:
.. code-block:: python
=== modified file 'doc/yade-articles.bib'
--- doc/yade-articles.bib 2014-01-06 09:35:37 +0000
+++ doc/yade-articles.bib 2014-04-02 15:19:41 +0000
@@ -20,14 +20,17 @@
author = {Boon,C.W. and Houlsby, G.T. and Utili, S.}
}
-@Article{Catalano2013a,
+@Article{Catalano2014a,
title = {Pore-scale modeling of fluid-particles interaction and emerging poromechanical effects},
author = {Catalano, E. and Chareyre, B. and Barthélémy, E.},
journal = {International Journal for Numerical and Analytical Methods in Geomechanics},
- year = {2013},
+ year = {2014},
+ volume = {38},
+ number = {1},
+ pages = {51--71},
doi = {10.1002/nag.2198},
- note = {in press, arxiv version available},
- url = {http://arxiv.org/pdf/1304.4895.pdf}
+ note = {http://arxiv.org/pdf/1304.4895.pdf},
+ url = {http://dx.doi.org/10.1002/nag.2198}
}
@article{Chareyre2012a,
@@ -363,7 +366,7 @@
author = {Puckett, J.G. and Lechenault, F. and Daniels, K.E.},
journal = {Physical Review E},
volume = {83},
- issue = {4},
+ number = {4},
pages = {041301},
year = {2011},
doi = {10.1103/PhysRevE.83.041301},
@@ -592,7 +595,7 @@
author = {Hilton, J. E. and Tordesillas, A.},
journal = {Phys. Rev. E},
volume = {88},
- issue = {6},
+ number = {6},
pages = {062203},
numpages = {8},
year = {2013},
=== modified file 'doc/yade-conferences.bib'
--- doc/yade-conferences.bib 2014-01-13 17:49:25 +0000
+++ doc/yade-conferences.bib 2014-04-02 15:19:41 +0000
@@ -521,7 +521,7 @@
url = {https://www.yade-dem.org/publi/APC000193.pdf}
}
-@InProceedings{ Hilton2013,
+@InProceedings{ Hilton2013b,
author = {J. E. Hilton and P. W. Cleary and A. Tordesillas},
title = {Unitary stick-slip motion in granular beds},
publisher = {AIP},
=== added directory 'examples/FluidCouplingLBM'
=== added file 'examples/FluidCouplingLBM/Buoyancy_Gradient.m'
--- examples/FluidCouplingLBM/Buoyancy_Gradient.m 1970-01-01 00:00:00 +0000
+++ examples/FluidCouplingLBM/Buoyancy_Gradient.m 2014-04-16 15:49:09 +0000
@@ -0,0 +1,138 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Authors: Luc Sibille luc.sibille@xxxxxxxxxxxxxxx
+% Franck Lomine franck.lomine@xxxxxxxxxxxxxx
+%
+% Script to interpret the DEM-LBM buoyancy simulation performed with the script buoyancy.py
+% This script was written for the OZ ALERT school in Grenoble 2011
+% Script updated in 2014
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+clear all
+close all
+
+radFactor = 0.6;
+rhoSolid = 3000;
+gravity = 0.1;
+
+%----- reading of LBM.log file
+logfile='LBM.log';
+fid = fopen(logfile);
+tline = fgetl(fid);
+fscanf(fid,'%s %s %s',[3,1]);
+fscanf(fid,'%s',[1,1]); Lx0=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Ly0=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); depth=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); thickness=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); NbBodies=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); dP=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Nu=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); rhoFluid=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); dx=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Nx=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Ny=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Nz=fscanf(fid,'%f',[1,1]);
+tline = fgetl(fid);
+tline = fgetl(fid);
+fscanf(fid,'%s',[1,1]); tau=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); omega=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); IterMax=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); SaveMode=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); IterSave=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); SaveGridRatio=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); IntervalLBM=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); LBMConvergenceCriterion=fscanf(fid,'%f',[1,1]);
+tline = fgetl(fid);
+tline = fgetl(fid);
+fscanf(fid,'%s %s',[2,1]); LBMdt=fscanf(fid,'%f',[1,1]);
+fclose(fid);
+%-------------------------------
+
+
+C=dx/LBMdt;
+Cs2=C^2/3;
+
+
+path1 = './lbm-nodes/'
+path2 = './dem-bodies/'
+
+fiVx=dir([path1 'Vx_*']);
+fiRho=dir([path1 'Rho_*']);
+fiBodies=dir([path2 'spheres_*']);
+
+nb_file =length(fiVx)
+
+
+
+
+for i=1:nb_file
+
+
+ vxfile=[path1 fiVx(i).name]
+ ux = importdata(vxfile);
+ ux=ux';
+
+ Vdarcy(i) = mean( ux(1,:) );
+
+
+ rhofile=[path1 fiRho(i).name];
+ rho = importdata(rhofile);
+ rho=rho';
+
+ DP(i) = Cs2*(rho(1,90)-rho(end,90));
+
+
+ fid2 = fopen([path2 fiBodies(i).name],'r');
+ [donnees2] = fscanf(fid2,'%d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f',[17,inf]);
+
+ id=donnees2(1,:);
+ x=donnees2(2,:);
+ y=donnees2(3,:);
+ r=donnees2(5,:);
+
+ fclose(fid2);
+ clear donnees2
+
+ xmin(i)=min(x);
+ xmax(i)=max(x);
+
+ if i==1 %computation of Terzaghi critical hydraulic gradient
+
+ Stotal = 0.005*(max(x+r)-min(x-r));
+ Ssolid = sum( pi*(r/radFactor).^2 );
+
+ Swater = Stotal-Ssolid;
+
+ Wwater = rhoFluid*gravity*Swater;
+ Wsolid = rhoSolid*gravity*Ssolid;
+ %Wsolid = rhoSolid*gravity*sum( pi*(r/radFactor).^2 );
+
+ Wtotal = Wwater+Wsolid;
+
+ HgradCrit = Wtotal/Stotal/(rhoFluid*gravity);
+ end
+
+end
+
+L = xmax(1)-xmin(1);
+Hgrad = DP/(rhoFluid*gravity*L);
+
+figure(1)
+hold on
+%plot(DP,Vdarcy)
+plot(Hgrad,Vdarcy,'b')
+plot([HgradCrit HgradCrit], [0 max(Vdarcy)],'r')
+xlabel('Hydraulic gradient')
+ylabel('Darcy velocity')
+legend('Darcy velocity','Terzaghi critical gradient')
+
+figure(2)
+hold on
+% plot(DP,xmin,'b')
+% plot(DP,xmax,'r')
+plot(Hgrad,xmin,'b')
+plot(Hgrad,xmax,'g')
+plot([HgradCrit HgradCrit], [0 max(xmax)],'r')
+xlabel('Hydraulic gradient')
+ylabel('Max and min particle positions')
+legend('Top particle position','Bottom particle position','Terzaghi critical gradient')
+
=== added file 'examples/FluidCouplingLBM/buoyancy.py'
--- examples/FluidCouplingLBM/buoyancy.py 1970-01-01 00:00:00 +0000
+++ examples/FluidCouplingLBM/buoyancy.py 2014-04-16 15:49:09 +0000
@@ -0,0 +1,195 @@
+##############################################################################################################################
+#Authors: Luc Sibille luc.sibille@xxxxxxxxxxxxxxx
+# Franck Lomine franck.lomine@xxxxxxxxxxxxxx
+#
+# Script to simulate buoyancy in a granular assembly with the DEM-LBM coupling.
+# This script was written for a practical work in the OZ ALERT school in Grenoble 2011.
+# Script updated in 2014
+##############################################################################################################################
+
+
+from yade import pack,timing,utils
+
+
+rMean = 0.00035 #mean radius (m) of solid particles
+
+Gravity=-0.1 #gravity (m.s-2) that will be applied to solid particles
+
+#definition of the simulation domain (position of walls), the domain is a 3D domain but particles will be generated on a unique plane at z=0, be carefull that wall normal to z directions do not touch particles.
+lowerCornerW = (0.00001,0.00001,-0.002)
+upperCornerW = (0.00701,0.00501,0.002)
+
+#definitions of the domain for particles: positions in z direction is set to 0 to force a 2D granular assembly
+lowerCornerS = (0.00001,0.00001,0)
+upperCornerS = (0.00701,0.00501,0)
+
+
+nbSpheres = 70 #this not the real number of particles but number of times where we try to insert a new particle, the real number of particles can be much lower!
+
+
+
+## Build of the engine vector
+O.engines=[
+
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb(),Bo1_Box_Aabb()]),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom(),Ig2_Box_Sphere_ScGeom()],
+ [Ip2_FrictMat_FrictMat_FrictPhys()],
+ [Law2_ScGeom_FrictPhys_CundallStrack()]
+ ),
+
+
+ HydrodynamicsLawLBM( EngineIsActivated=False,
+ WallYm_id=0,
+ WallYp_id=1,
+ WallXm_id=2,
+ WallXp_id=3,
+ WallZp_id=5,
+ WallZm_id=4,
+ useWallYm=1,
+ useWallYp=1,
+ YmBCType=2,
+ YpBCType=2,
+
+ useWallXm=0,
+ useWallXp=0,
+ XmBCType=1,
+ XpBCType=1,
+ LBMSavedData='spheres,velXY,rho,nodeBD',
+ tau=1.1,
+ dP=(0,0,0),
+ IterSave=200,
+ IterPrint=100,
+ RadFactor=0.6, # The radius of particles seen by the LBM engine is reduced here by a factor RadFactor=0.6 to allow flow between particles in this 2D case.
+ Nx=250,
+ Rho=1000,
+ Nu=1.0e-6,
+ periodicity='',
+ bc='',
+ VbCutOff=0.0,
+ applyForcesAndTorques=True,
+ label="Elbm"
+ ),
+
+
+ NewtonIntegrator(damping=0.2,gravity=(Gravity,0.,0.),label="ENewton"),
+]
+
+
+
+###############################################################################################################
+# Creation of 6 walls at the limit of the simulation domain
+
+# defintiion of the material for walls
+O.materials.append(FrictMat(young=50e6,poisson=.5,frictionAngle=0.0,density=3000,label='walls'))
+
+## create walls around the packing
+wallOversizeFactor=1.001
+thickness=0.00001;
+#bottom box
+center= ((lowerCornerW[0]+upperCornerW[0])/2,lowerCornerW[1]-thickness/2.0,(lowerCornerW[2]+upperCornerW[2])/2)
+halfSize= (wallOversizeFactor*fabs(lowerCornerW[0]-upperCornerW[0])/2+thickness,thickness/2.0,wallOversizeFactor*fabs(lowerCornerW[2]-upperCornerW[2])/2+thickness)
+b1=utils.box(center=[center[0],center[1],center[2]],extents=[halfSize[0],halfSize[1],halfSize[2]],color=[0,1,0],fixed=True,wire=True,material='walls')
+O.bodies.append(b1)
+#--
+#Top box
+center=((lowerCornerW[0]+upperCornerW[0])/2,upperCornerW[1]+thickness/2.0,(lowerCornerW[2]+upperCornerW[2])/2)
+halfSize =(wallOversizeFactor*fabs(lowerCornerW[0]-upperCornerW[0])/2+thickness,thickness/2.0,wallOversizeFactor*fabs(lowerCornerW[2]-upperCornerW[2])/2+thickness)
+b2=utils.box(center=[center[0],center[1],center[2]],extents=[halfSize[0],halfSize[1],halfSize[2]],color=[0,1,0],fixed=True,wire=True,material='walls')
+O.bodies.append(b2)
+#--
+center=(lowerCornerW[0]-thickness/2.0,(lowerCornerW[1]+upperCornerW[1])/2,(lowerCornerW[2]+upperCornerW[2])/2)
+halfSize=(thickness/2.0,wallOversizeFactor*fabs(lowerCornerW[1]-upperCornerW[1])/2+thickness,wallOversizeFactor*fabs(lowerCornerW[2]-upperCornerW[2])/2+thickness)
+b3=utils.box(center=[center[0],center[1],center[2]],extents=[halfSize[0],halfSize[1],halfSize[2]],color=[0,1,0],fixed=True,wire=True,material='walls')
+O.bodies.append(b3)
+#--
+center=(upperCornerW[0]+thickness/2.0,(lowerCornerW[1]+upperCornerW[1])/2,(lowerCornerW[2]+upperCornerW[2])/2)
+halfSize=(thickness/2.0,wallOversizeFactor*fabs(lowerCornerW[1]-upperCornerW[1])/2+thickness,wallOversizeFactor*fabs(lowerCornerW[2]-upperCornerW[2])/2+thickness)
+b4=utils.box(center=[center[0],center[1],center[2]],extents=[halfSize[0],halfSize[1],halfSize[2]],color=[0,1,0],fixed=True,wire=True,material='walls')
+O.bodies.append(b4)
+#--
+center=((lowerCornerW[0]+upperCornerW[0])/2,(lowerCornerW[1]+upperCornerW[1])/2,lowerCornerW[2]-thickness/2.0)
+halfSize=(wallOversizeFactor*fabs(lowerCornerW[0]-upperCornerW[0])/2+thickness,wallOversizeFactor*fabs(lowerCornerW[1]-upperCornerW[1])/2+thickness,thickness/2.0)
+b5=utils.box(center=[center[0],center[1],center[2]],extents=[halfSize[0],halfSize[1],halfSize[2]],color=[0,1,0],fixed=True,wire=True,material='walls')
+O.bodies.append(b5)
+#--
+center=((lowerCornerW[0]+upperCornerW[0])/2,(lowerCornerW[1]+upperCornerW[1])/2,upperCornerW[2]+thickness/2.0)
+halfSize=(wallOversizeFactor*fabs(lowerCornerW[0]-upperCornerW[0])/2+thickness,wallOversizeFactor*fabs(lowerCornerW[1]-upperCornerW[1])/2+thickness,thickness/2.0);
+b6=utils.box(center=[center[0],center[1],center[2]],extents=[halfSize[0],halfSize[1],halfSize[2]],color=[0,1,0],fixed=True,wire=True,material='walls')
+O.bodies.append(b6)
+
+
+###############################################################################################################
+# Creation of the assembly of particles
+
+# defintiion of the material for particles
+O.materials.append(FrictMat(young=50e6,poisson=.5,frictionAngle=35*3.1415926535/180,density=3000,label='spheres'))
+## use a SpherePack object to generate a random loose particles packing
+sp=pack.SpherePack()
+sp.makeCloud(lowerCornerS,upperCornerS,-1,0.33,nbSpheres,False, 0.5,seed=1) #"seed" make the "random" generation always the same
+sp.toSimulation(material='spheres')
+
+
+# loop over bodies to change their 3D inertia into 2D inertia (by default in YADE particles are 3D spheres, here we want to cylinder with a length=1).
+for s in O.bodies:
+ if isinstance(s.shape,Box): continue
+
+ r=s.shape.radius
+ oldm=s.state.mass
+ oldI=s.state.inertia
+
+ m=oldm*3./4./r
+ s.state.mass=m
+
+ s.state.inertia[0] = 15./16./r*oldI[0] #inertia with respect to x and y axes are not used and the computation here is wrong
+ s.state.inertia[1] = 15./16./r*oldI[1] #inertia with respect to x and y axes are not used and the computation here is wrong
+ s.state.inertia[2] = 15./16./r*oldI[2] #only inertia with respect to z axis is usefull
+
+
+
+O.dt=0.00005 #use a fix value of time step, it is better to not use a time stepper computing a new step at each iteration since DEM time step is eventually fixed by the LBM engine.
+
+yade.qt.View() #to see what is happening
+
+print"___________________"
+print"PHASE 1"
+print "Settlement of particle under gravity only, fluid flow is not activated at the present time... please wait"
+print"___________________"
+
+O.run(60000,1) #settlement of particle under gravity only, no action of the fluid flow.
+
+
+
+#definition of a runnable python function to increase progressively the fluid pressure gradient.
+def IncrDP():
+ currentDP=Elbm.dP
+ Elbm.dP=(currentDP[0]+1.0/10000.0,0,0)
+ #O.engines[6].dP=currentDP+1.0/100.0
+ if not(O.iter%100):
+ print "dP=", Elbm.dP[0]
+
+O.engines=O.engines+[PyRunner(iterPeriod=1,command='IncrDP()')]
+
+#Necessary to initiate correctly the LBM engine
+O.resetTime()
+
+#Activation of the LBM engine
+Elbm.EngineIsActivated=True
+
+#Cundall damping for solid particles removed (the fluid viscosity should be enough to damp the solid particles ... in general, not always...)
+ENewton.damping=0.0
+
+# Now you just need to run the simulation as long as you want to ... note that if you wait to long the pressure gradient will become very large inducing great fluid velocities, and the fluid simulation may become crazy!! Look at the Mach number (M) printed in the console, it should not be too high...
+
+print"___________________"
+print"PHASE 2"
+print "Fluid flow has been activated now with a gradual increase of the pressure gradient."
+print "Run the simulation, until the pressure gradient is strong enough to compensate the gravity forces, then particles will mouve to the right."
+print"..."
+print"..."
+print "Velocity and pressure field of the fluid can be plotted with the matlab script yadeLBMvisu.m"
+print "Terzaghi critical hydraulic gradient can be compared with the one deduced from the simulation with the matlab script Buoyancy_Gradient.m"
+print"___________________"
+
+
=== added file 'examples/FluidCouplingLBM/yadeLBMvisu.m'
--- examples/FluidCouplingLBM/yadeLBMvisu.m 1970-01-01 00:00:00 +0000
+++ examples/FluidCouplingLBM/yadeLBMvisu.m 2014-04-16 15:49:09 +0000
@@ -0,0 +1,151 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Authors: Luc Sibille luc.sibille@xxxxxxxxxxxxxxx
+% Franck Lomine franck.lomine@xxxxxxxxxxxxxx
+%
+% Script to visualize the fluid flow simulated with LBM written for a practical work in the OZ ALERT school in Grenoble 2011.
+% Script updated in 2014
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+clear all
+close all
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% The only thing you have to do is choose below the iteration number for
+%%%% which you want to plot the fluid flow. This iteration number should
+%%%% correspond to one the saving iteration appearing in the same of the
+%%%% files saved in ./dem-bodies or ./lbm-nodes
+
+IterNumber=600;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+vxfile=sprintf('lbm-nodes/Vx_%.10d',IterNumber);
+vyfile=sprintf('lbm-nodes/Vy_%.10d',IterNumber);
+ux = importdata(vxfile);
+uy = importdata(vyfile);
+%ux=ux';
+%uy=uy';
+u = sqrt(ux.*ux+uy.*uy);
+
+
+rhofile=sprintf('lbm-nodes/Rho_%.10d',IterNumber);
+rho = importdata(rhofile);
+
+
+nodebdfile=sprintf('lbm-nodes/NodeBoundary_%.10d',IterNumber);
+nodeBD = importdata(nodebdfile);
+nodeBD=nodeBD';
+
+
+spherefile=sprintf('dem-bodies/spheres_%.10d',IterNumber);
+
+tmpMat = importdata(spherefile);
+Sid=tmpMat(:,1);
+Sx=tmpMat(:,2);
+Sy=tmpMat(:,3);
+Sz=tmpMat(:,4);
+Sr=tmpMat(:,5);
+clear tmpMat
+
+
+
+%----- reading of LBM.log file
+logfile='LBM.log';
+fid = fopen(logfile);
+tline = fgetl(fid);
+fscanf(fid,'%s %s %s',[3,1]);
+fscanf(fid,'%s',[1,1]); Lx0=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Ly0=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); depth=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); thickness=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); NbBodies=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); dP=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Nu=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Rho=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); dx=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Nx=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Ny=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); Nz=fscanf(fid,'%f',[1,1]);
+tline = fgetl(fid);
+tline = fgetl(fid);
+fscanf(fid,'%s',[1,1]); tau=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); omega=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); IterMax=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); SaveMode=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); IterSave=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); SaveGridRatio=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); IntervalLBM=fscanf(fid,'%f',[1,1]);
+fscanf(fid,'%s',[1,1]); LBMConvergenceCriterion=fscanf(fid,'%f',[1,1]);
+tline = fgetl(fid);
+tline = fgetl(fid);
+fscanf(fid,'%s %s',[2,1]); LBMdt=fscanf(fid,'%f',[1,1]);
+fclose(fid);
+%-------------------------------
+
+
+fig1=figure(1)
+set(gcf, 'color', 'white');
+clf
+nodeBD=flipdim(nodeBD',1);
+imagesc(nodeBD);
+title('Obstacle Boundaries');
+axis equal;
+
+axis off
+
+
+%---------------------------------------
+% VELOCITIES (colormap)
+%--------------------------------------
+fig2=figure(2)
+set(gcf, 'color', 'white');
+%set(gca,'ZDir','reverse')
+clf;
+hold on
+
+imagesc(u);
+title('Velocity colormap');
+
+umax_current=max(max(u));
+if(umax_current==0.) umax_current=umax_current+1.e-9;end;
+caxis([0. umax_current]);
+colorbar('location','southoutside');
+
+theta = -pi:2*pi/40:pi;
+for aa=1:length(Sx)
+
+ fill(ceil(Sx(aa)/dx)+Sr(aa)/dx*cos(theta),ceil(Sy(aa)/dx)+Sr(aa)/dx*sin(theta),[1 1 1]);
+end
+
+hold off;
+axis equal;
+axis off;
+
+
+
+fig3=figure(3)
+rhomax_current=max(max(rho));
+rhomin_current=min(min(rho));
+set(gcf, 'color', 'white');
+%set(gca,'ZDir','reverse')
+clf;
+hold on
+
+%rho=flipdim(rho,1)
+imagesc(rho);
+title('Rho');
+if(rhomax_current==rhomin_current) rhomax_current=rhomax_current+1.e-9;end;
+caxis([rhomin_current rhomax_current]);
+colorbar;
+
+theta = -pi:2*pi/40:pi;
+for aa=1:length(Sx)
+
+ %fill(ceil(Sx(aa)/dx)+Sr(aa)/dx*cos(theta),ceil(Sy(aa)/dx)+Sr(aa)/dx*sin(theta),[1 1 1]);
+ fill((Sx(aa)/dx)+1+ceil(Sr(aa)/dx)*cos(theta),(Sy(aa)/dx)+1+ceil(Sr(aa)/dx)*sin(theta),[1 1 1]);
+end
+
+hold off;
+axis equal;
+axis off;
=== modified file 'examples/FluidCouplingPFV/oedometer.py'
--- examples/FluidCouplingPFV/oedometer.py 2013-07-29 17:36:38 +0000
+++ examples/FluidCouplingPFV/oedometer.py 2014-04-01 13:18:38 +0000
@@ -10,7 +10,7 @@
## Example script for using the DEM-PFV coupling introduced with E. Catalano, as reported in:
## * [Chareyre2012a] Chareyre, B., Cortis, A., Catalano, E., Barthélemy, E. (2012), Pore-scale modeling of viscous flow and induced forces in dense sphere packings. Transport in Porous Media (92), pages 473-493. DOI 10.1007/s11242-011-9915-6
## http://dx.doi.org/10.1007/s11242-011-9915-6
-## * [Catalano2013a] Catalano, E., Chareyre, B., Barthélémy, E. (2013), Pore-scale modeling of fluid-particles interaction and emerging poromechanical effects. International Journal for Numerical and Analytical Methods in Geomechanics. DOI 10.1002/nag.2198
+## * [Catalano2014a] Catalano, E., Chareyre, B., Barthélémy, E. (2013), Pore-scale modeling of fluid-particles interaction and emerging poromechanical effects. International Journal for Numerical and Analytical Methods in Geomechanics. DOI 10.1002/nag.2198
## http://arxiv.org/pdf/1304.4895.pdf
## Also used in:
## * Tong et al.2012 (http://dx.doi.org/10.2516/ogst/2012032)
=== modified file 'examples/PIDController.py'
--- examples/PIDController.py 2013-07-05 09:11:44 +0000
+++ examples/PIDController.py 2014-04-02 15:33:41 +0000
@@ -7,8 +7,7 @@
fr = 0.0;rho=2000
tc = 0.001; en = 0.3; et = 0.3; o.dt = 0.02*tc
-param = getViscoelasticFromSpheresInteraction(tc,en,et)
-mat1 = O.materials.append(ViscElMat(frictionAngle=fr, density=rho,**param))
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr, density=rho,tc=tc,en=en,et=et))
spheresID = O.bodies.append(pack.regularHexa(pack.inCylinder((0,0,-2.0),(0,0,2.0),2.0),radius=0.2,gap=0.1,color=(0,1,0),material=mat1))
@@ -33,7 +32,7 @@
PyRunner(command='addPlotData()',iterPeriod=1000, label='graph'),
PyRunner(command='switchTranslationEngine()',iterPeriod=45000, nDo = 2, label='switchEng'),
]
-
+O.step()
from yade import qt
qt.View()
r=qt.Renderer()
=== modified file 'examples/ResetRandomPosition.py'
--- examples/ResetRandomPosition.py 2013-03-28 10:53:06 +0000
+++ examples/ResetRandomPosition.py 2014-04-02 15:33:41 +0000
@@ -13,12 +13,10 @@
es=0.3 # tangential restitution coefficient
frictionAngle=radians(35)#
density=2700
-kw=getViscoelasticFromSpheresInteraction(tc,en,es)
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
# facets material
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
# default spheres material
-dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params))
+dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
O.dt=.2*tc # time step
=== added file 'examples/ViscElMatchMaker.py'
--- examples/ViscElMatchMaker.py 1970-01-01 00:00:00 +0000
+++ examples/ViscElMatchMaker.py 2014-04-02 15:33:41 +0000
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# This example shows, how matchmaker can be used to
+# set the parameters of ViscoElastic model.
+
+from yade import utils, plot
+o = Omega()
+fr = 0.5;rho=2000
+tc = 0.001; en = 0.5; et = 0.5; o.dt = 0.002*tc
+
+
+r1 = 0.002381
+r2 = 0.002381
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,tc=tc,en=en,et=et,density=rho))
+mat2 = O.materials.append(ViscElMat(frictionAngle=fr,tc=tc,en=en,et=et,density=rho))
+mat3 = O.materials.append(ViscElMat(frictionAngle=fr,tc=tc,en=en,et=et,density=rho))
+
+
+id11 = O.bodies.append(sphere(center=[0,0,0],radius=r1,material=mat1,fixed=True,color=[0,0,1]))
+id12 = O.bodies.append(sphere(center=[0,0,(r1+r2+0.005*r2)],radius=r2,material=mat2,fixed=False,color=[0,0,1]))
+
+id21 = O.bodies.append(sphere(center=[3*r1,0,0],radius=r1,material=mat1,fixed=True,color=[0,1,0]))
+id22 = O.bodies.append(sphere(center=[3*r1,0,(r1+r2+0.005*r2)],radius=r2,material=mat3,fixed=False,color=[0,1,0]))
+
+id31 = O.bodies.append(sphere(center=[6*r1,0,0],radius=r1,material=mat2,fixed=True,color=[1,0,0]))
+id32 = O.bodies.append(sphere(center=[6*r1,0,(r1+r2+0.005*r2)],radius=r2,material=mat3,fixed=False,color=[1,0,0]))
+
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb()],verletDist=(r1+r2)*5.0),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom()],
+ [Ip2_ViscElMat_ViscElMat_ViscElPhys(
+ en=MatchMaker(matches=((mat1,mat2,.9),(mat1,mat3,.5),(mat2,mat3,.1))), # Set parameters
+ et=MatchMaker(matches=((mat1,mat2,.9),(mat1,mat3,.5),(mat2,mat3,.1)))
+ )],
+ [Law2_ScGeom_ViscElPhys_Basic()],
+ ),
+ NewtonIntegrator(damping=0,gravity=[0,0,-9.81]),
+ PyRunner(command='addPlotData()',iterPeriod=100),
+]
+
+vel=-0.50
+O.bodies[id12].state.vel=[0,0,vel]
+O.bodies[id22].state.vel=[0,0,vel]
+O.bodies[id32].state.vel=[0,0,vel]
+
+def addPlotData():
+ s1 = (O.bodies[id12].state.pos[2]-O.bodies[id11].state.pos[2])-(r1+r2)
+ s2 = (O.bodies[id22].state.pos[2]-O.bodies[id11].state.pos[2])-(r1+r2)
+ s3 = (O.bodies[id32].state.pos[2]-O.bodies[id11].state.pos[2])-(r1+r2)
+ plot.addData(mat1mat2=s1,mat1mat3=s2,mat2mat3=s3,it=O.iter)
+
+
+
+plot.plots={'it':('mat1mat2','mat1mat3','mat2mat3')}; plot.plot()
+
+O.step()
+from yade import qt
+qt.View()
+
+#O.run(100000, True)
+#plot.saveGnuplot('sim-data_')
=== modified file 'examples/baraban/BicyclePedalEngine.py'
--- examples/baraban/BicyclePedalEngine.py 2013-11-11 16:22:15 +0000
+++ examples/baraban/BicyclePedalEngine.py 2014-04-02 15:33:41 +0000
@@ -10,9 +10,8 @@
es = 0.3
## Import wall's geometry
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
-sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es)) # **params sets kn, cn, ks, cs
+sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
from yade import ymport
fctIds=O.bodies.append(ymport.stl('baraban.stl',color=(1,0,0),material=facetMat))
## Spheres
=== modified file 'examples/baraban/baraban.py'
--- examples/baraban/baraban.py 2013-03-28 10:55:47 +0000
+++ examples/baraban/baraban.py 2014-04-02 15:33:41 +0000
@@ -10,9 +10,8 @@
es = 0.3
## Import wall's geometry
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
-sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
+sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
from yade import ymport
fctIds=O.bodies.append(ymport.stl('baraban.stl',color=(1,0,0),material=facetMat))
## Spheres
=== modified file 'examples/bulldozer/bulldozerVTK.py'
--- examples/bulldozer/bulldozerVTK.py 2013-03-28 10:58:04 +0000
+++ examples/bulldozer/bulldozerVTK.py 2014-04-02 15:33:41 +0000
@@ -27,9 +27,8 @@
es = 0.3
## Materials
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
-sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
+sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
### Creating the Buldozer Knife
### from facets, using GTS
=== added directory 'examples/capillary'
=== added file 'examples/capillary/capillar.py'
--- examples/capillary/capillar.py 1970-01-01 00:00:00 +0000
+++ examples/capillary/capillar.py 2014-04-02 15:33:41 +0000
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# The simulation of different capillary bridge models.
+# Parameters are set like in experiments of [Willett2000]
+
+from yade import utils, plot
+o = Omega()
+fr = 0.5;rho=2000
+tc = 0.001; en = 0.7; et = 0.7; o.dt = 0.0002*tc
+
+
+r = 0.002381
+
+Gamma = 20.6*1e-3
+Theta = 0
+VB = 74.2*1e-12
+
+
+CapillarType1 = "Willett_numeric"
+CapillarType2 = "Willett_analytic"
+CapillarType3 = "Rabinovich"
+CapillarType4 = "Lambert"
+CapillarType5 = "Weigert"
+CapillarType6 = "Soulie"
+
+
+mat1 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType1,tc=tc,en=en,et=et))
+mat2 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType2,tc=tc,en=en,et=et))
+mat3 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType3,tc=tc,en=en,et=et))
+mat4 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType4,tc=tc,en=en,et=et))
+mat5 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType5,tc=tc,en=en,et=et))
+mat6 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType6,tc=tc,en=en,et=et))
+
+
+id1 = O.bodies.append(sphere(center=[0,0,0],radius=r,material=mat1,fixed=True))
+id2 = O.bodies.append(sphere(center=[0,0,2*r],radius=r,material=mat1,fixed=True))
+
+id3 = O.bodies.append(sphere(center=[3.0*r,0,0],radius=r,material=mat2,fixed=True))
+id4 = O.bodies.append(sphere(center=[3.0*r,0,2*r],radius=r,material=mat2,fixed=True))
+
+id5 = O.bodies.append(sphere(center=[6.0*r,0,0],radius=r,material=mat3,fixed=True))
+id6 = O.bodies.append(sphere(center=[6.0*r,0,2*r],radius=r,material=mat3,fixed=True))
+
+id7 = O.bodies.append(sphere(center=[9.0*r,0,0],radius=r,material=mat4,fixed=True))
+id8 = O.bodies.append(sphere(center=[9.0*r,0,2*r],radius=r,material=mat4,fixed=True))
+
+id9 = O.bodies.append(sphere(center=[12.0*r,0,0],radius=r,material=mat5,fixed=True))
+id10= O.bodies.append(sphere(center=[12.0*r,0,2*r],radius=r,material=mat5,fixed=True))
+
+id11= O.bodies.append(sphere(center=[15.0*r,0,0],radius=r,material=mat6,fixed=True))
+id12= O.bodies.append(sphere(center=[15.0*r,0,2*r],radius=r,material=mat6,fixed=True))
+
+
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb()]),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom()],
+ [Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys()],
+ [Law2_ScGeom_ViscElCapPhys_Basic()],
+ ),
+ NewtonIntegrator(damping=0,gravity=[0,0,0]),
+ PyRunner(command='addPlotData()',iterPeriod=100),
+]
+
+vel = 0.01
+O.bodies[id2].state.vel=[0,0,vel]
+O.bodies[id4].state.vel=[0,0,vel]
+O.bodies[id6].state.vel=[0,0,vel]
+O.bodies[id8].state.vel=[0,0,vel]
+O.bodies[id10].state.vel=[0,0,vel]
+O.bodies[id12].state.vel=[0,0,vel]
+
+def addPlotData():
+ f1=O.forces.f(id2)
+ f2=O.forces.f(id4)
+ f3=O.forces.f(id6)
+ f4=O.forces.f(id8)
+ f5=O.forces.f(id10)
+ f6=O.forces.f(id12)
+
+ s1 = (O.bodies[id2].state.pos[2]-O.bodies[id1].state.pos[2])-2*r
+ sc=s1
+
+ plot.addData(Willett_numeric=-f1[2], Willett_analytic=-f2[2], Rabinovich=-f3[2], Lambert=-f4[2], Weigert=-f5[2], Soulie=-f6[2], sc=sc)
+
+
+
+plot.plots={'sc':('Willett_numeric','Willett_analytic','Rabinovich','Lambert','Weigert','Soulie')}; plot.plot()
+
+O.step()
+from yade import qt
+qt.View()
+
+O.run(250000, True)
+#plot.saveGnuplot('sim-data_'+CapillarType1)
=== added directory 'examples/capillary/liquidmigration'
=== added file 'examples/capillary/liquidmigration/showcase.py'
--- examples/capillary/liquidmigration/showcase.py 1970-01-01 00:00:00 +0000
+++ examples/capillary/liquidmigration/showcase.py 2014-05-08 05:57:04 +0000
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# The script implements the show case in this article [Mani2013]
+from yade import utils, plot
+o = Omega()
+fr = 0.5;rho=2000
+tc = 0.001; en = 0.7; et = 0.7;
+o.dt = 1.0
+
+
+r1 = 1.0
+r2 = 1.0
+Gamma = 20.6*1e-3
+Theta = 0
+VB3 = 74.2*1e-12
+
+
+CapillarType = "Lambert"
+
+mat1 = O.materials.append(ViscElCapMat(frictionAngle=fr,density=rho,Vb=VB3,gamma=Gamma,theta=Theta,Capillar=True,CapillarType=CapillarType,tc=tc,en=en,et=et))
+
+d = 0.9999
+
+id1 = O.bodies.append(sphere(center=[0,0,0], radius=r2,material=mat1,fixed=True, color=[0,1,0]))
+id2 = O.bodies.append(sphere(center=[0,(r1+r2)*d,0], radius=r2,material=mat1,fixed=True, color=[0,1,0]))
+id3 = O.bodies.append(sphere(center=[(r1+r2)*d,(r1+r2)*d,0], radius=r2,material=mat1,fixed=True, color=[0,1,0]))
+id4 = O.bodies.append(sphere(center=[(r1+r2)*d,(r1+r2)*d*2,0], radius=r2,material=mat1,fixed=True, color=[0,1,0]))
+id5 = O.bodies.append(sphere(center=[(r1+r2)*d*2,(r1+r2)*d,0], radius=r2,material=mat1,fixed=True, color=[0,1,0]))
+
+
+Vf = 0.5e-1
+Vfmin = 0.1e-1
+
+O.bodies[id1].Vf = Vf
+O.bodies[id1].Vmin = Vfmin
+
+O.bodies[id2].Vf = Vf
+O.bodies[id2].Vmin = Vfmin
+
+O.bodies[id3].Vf = Vf
+O.bodies[id3].Vmin = Vfmin
+
+O.bodies[id4].Vf = Vf
+O.bodies[id4].Vmin = Vfmin
+
+O.bodies[id5].Vf = Vf
+O.bodies[id5].Vmin = Vfmin
+
+vel = 0.0
+O.bodies[id1].state.vel=[0,0,vel]
+O.bodies[id2].state.vel=[0,0,-vel]
+O.bodies[id3].state.vel=[vel,0,0]
+O.bodies[id4].state.vel=[-vel,0,0]
+
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb()],verletDist=(r1+r2)*5.0),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom()],
+ [Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys()],
+ [Law2_ScGeom_ViscElCapPhys_Basic()],
+ ),
+ LiqControl(),
+ NewtonIntegrator(damping=0,gravity=[0,0,0]),
+ PyRunner(command='showData()',iterPeriod=1),
+]
+
+
+def showData():
+ print "Step %d"%O.iter
+ print "idB=%d, Vf=%s, Vmin=%s;"%(id1, O.bodies[id1].Vf, O.bodies[id1].Vmin)
+ print "idB=%d, Vf=%s, Vmin=%s;"%(id2, O.bodies[id2].Vf, O.bodies[id2].Vmin)
+ print "idB=%d, Vf=%s, Vmin=%s;"%(id3, O.bodies[id3].Vf, O.bodies[id3].Vmin)
+ print "idB=%d, Vf=%s, Vmin=%s;"%(id4, O.bodies[id4].Vf, O.bodies[id4].Vmin)
+ print "idB=%d, Vf=%s, Vmin=%s;"%(id5, O.bodies[id5].Vf, O.bodies[id5].Vmin)
+
+ try:
+ print "Interaction[1, 2].Vb=%s"%(O.interactions[id1,id2].phys.Vb)
+ except:
+ pass
+
+ try:
+ print "Interaction[2, 3].Vb=%s"%(O.interactions[id2,id3].phys.Vb)
+ except:
+ pass
+
+ try:
+ print "Interaction[3, 4].Vb=%s"%(O.interactions[id3,id4].phys.Vb)
+ except:
+ pass
+
+ try:
+ print "Interaction[3, 5].Vb=%s"%(O.interactions[id3,id5].phys.Vb)
+ except:
+ pass
+ print
+
+
+showData()
+
+O.run(1, True)
+
+for i in range(5):
+ O.bodies[i].Vf = 0
+ O.bodies[i].Vmin = 0
+
+O.interactions[id1,id2].phys.Vb = 1.0
+O.interactions[id1,id2].phys.Vmax = 5.0
+O.interactions[id2,id3].phys.Vb = 1.0
+O.interactions[id2,id3].phys.Vmax = 5.0
+O.interactions[id3,id4].phys.Vb = 1.0
+O.interactions[id3,id4].phys.Vmax = 5.0
+O.interactions[id3,id5].phys.Vb = 1.0
+O.interactions[id3,id5].phys.Vmax = 5.0
+
+O.run(1, True)
+
+
+vel = 1.0
+O.bodies[id3].state.vel=[vel,0,0]
+O.bodies[id4].state.vel=[vel,0,0]
+O.bodies[id5].state.vel=[vel,0,0]
+
+from yade import qt
+qt.View()
=== modified file 'examples/clumps/clump-hopper-viscoelastic.py'
--- examples/clumps/clump-hopper-viscoelastic.py 2013-03-28 11:01:40 +0000
+++ examples/clumps/clump-hopper-viscoelastic.py 2014-04-02 15:33:41 +0000
@@ -11,10 +11,9 @@
frictionAngle=radians(35)#
density=2700
# facets material
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
# default spheres material
-dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle, **params))
+dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
O.dt=.05*tc # time step
=== modified file 'examples/clumps/clump-inbox-viscoelastic.py'
--- examples/clumps/clump-inbox-viscoelastic.py 2013-03-28 11:01:40 +0000
+++ examples/clumps/clump-inbox-viscoelastic.py 2014-04-02 15:33:41 +0000
@@ -11,10 +11,9 @@
frictionAngle=radians(35)#
density=2700
# facets material
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
# default spheres material
-dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params))
+dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
O.dt=.05*tc # time step
=== modified file 'examples/clumps/clump-viscoelastic.py'
--- examples/clumps/clump-viscoelastic.py 2013-03-28 11:01:40 +0000
+++ examples/clumps/clump-viscoelastic.py 2014-04-02 15:33:41 +0000
@@ -12,10 +12,9 @@
frictionAngle=radians(35)#
density=2700
# facets material
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
# default spheres material
-dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params))
+dfltSpheresMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
O.dt=.01*tc # time step
=== modified file 'examples/jointedCohesiveFrictionalPM/gravityBis.py'
--- examples/jointedCohesiveFrictionalPM/gravityBis.py 2013-11-04 14:30:22 +0000
+++ examples/jointedCohesiveFrictionalPM/gravityBis.py 2014-05-05 12:42:06 +0000
@@ -18,7 +18,7 @@
poros=0.13
rMeanSpheres = dimModele * pow(3.0/4.0*(1-poros)/(pi*nSpheres),1.0/3.0)
print ''
-print 'Creating a cubic sample of spheres (may take some time)'
+print 'Creating a cubic sample of spheres (may take some time and cause warnings)'
print ''
sp = pack.randomDensePack(pred,radius=rMeanSpheres,rRelFuzz=0.3,memoizeDb='/tmp/gts-triax-packings.sqlite',returnSpherePack=True)
sp.toSimulation(color=(0.9,0.8,0.6),wire=False,material=mat)
@@ -99,20 +99,20 @@
#### dataCollector
from yade import plot
-plot.plots={'iterations':('v',)}
-#plot.plots={'x':('z',)}
+plot.plots={'iterations':'v','x':'z'}
+
def dataCollector():
R=O.bodies[refPoint]
plot.addData(v=R.state.vel[2],z=R.state.pos[2],x=R.state.pos[0],iterations=O.iter,t=O.realtime)
#### joint strength degradation
-stableIter=2000
+stableIter=1000
stableVel=0.001
degrade=True
def jointStrengthDegradation():
global degrade
if degrade and O.iter>=stableIter and abs(O.bodies[refPoint].state.vel[2])<stableVel :
- print '!joint cohesion total degradation!', ' | iteration=', O.iter
+ print 'Equilibrium reached \nJoint cohesion canceled now !', ' | iteration=', O.iter
degrade=False
for i in O.interactions:
if i.phys.isOnJoint :
@@ -121,9 +121,7 @@
i.phys.FnMax=0.
i.phys.FsMax=0.
-O.step()
-
print 'Seeking after an initial equilibrium state'
print ''
O.run(10000)
-plot.plot()# note the straight line (during sliding step, before free fall) despite the discretization of joint plane with spheres
+plot.plot()# note the straight trajectory (z(x) plot)during sliding step (before free fall) despite the discretization of joint plane with spheres
=== modified file 'examples/jointedCohesiveFrictionalPM/identifBis.py'
--- examples/jointedCohesiveFrictionalPM/identifBis.py 2013-11-04 14:20:24 +0000
+++ examples/jointedCohesiveFrictionalPM/identifBis.py 2014-05-05 12:42:06 +0000
@@ -5,27 +5,19 @@
# The sample (spheres + facets) has to exist already, with their JCFpmMat
-############################ engines definition
-interactionRadius=1.;
+### engines definition, according to our only goal that is to detect spheres concerned by joint surfaces
+
O.engines=[
-
- ForceResetter(),
- InsertionSortCollider([Bo1_Sphere_Aabb(aabbEnlargeFactor=interactionRadius,label='is2aabb'),Bo1_Facet_Aabb()]),
+ InsertionSortCollider([Bo1_Sphere_Aabb(),Bo1_Facet_Aabb()],verletDist=0), #verletDist=0 to avoid introducing NewtonIntegrator in engines list
InteractionLoop(
- [Ig2_Sphere_Sphere_ScGeom(interactionDetectionFactor=interactionRadius,label='ss2d3dg'),Ig2_Facet_Sphere_ScGeom()],
+ [Ig2_Sphere_Sphere_ScGeom(),Ig2_Facet_Sphere_ScGeom()],
[Ip2_JCFpmMat_JCFpmMat_JCFpmPhys(cohesiveTresholdIteration=1,label='interactionPhys')],
[Law2_ScGeom_JCFpmPhys_JointedCohesiveFrictionalPM(smoothJoint=True,label='interactionLaw')]
- ),
- NewtonIntegrator(damping=1)
-
+ )
]
-############################ timestep + opening yade windows
-O.dt=0.001*utils.PWaveTimeStep()
+O.dt=1 # whatever value is ok
-# from yade import qt
-# v=qt.Controller()
-# v=qt.View()
############################ Identification spheres on joint
#### color set for particles on joint
@@ -35,9 +27,10 @@
jointcolor4=(1,1,1)
jointcolor5=(0,0,0)
+
+O.step(); # one step to know interactions
+
#### first step-> find spheres on facet
-O.step();
-
for i in O.interactions:
##if not i.isReal : continue
### Rk: facet are only stored in id1
@@ -125,36 +118,17 @@
elif facetSphereDir.dot(jointNormalRef)<0:
O.bodies[othSph].state.jointNormal1=-jointNormalRef
-#### for visualization:
-#bj=0
-#vert=(0.,1.,0.)
-#hor=(0.,1.,1.)
-#for o in O.bodies:
- #if o.state.onJoint==True : # or o.shape.name=='Facet':
- ##if o.shape.name=='Facet':
- ##o.shape.wire=True
- ##o.state.pos+=(0,50,0)
- ##bj+=1
- #if o.state.jointNormal1.dot(hor)>0 :
- ##o.state.pos+=(0,50,0)
- #o.shape.color=jointcolor1
- #elif o.state.jointNormal1.dot(hor)<0 :
- ##o.state.pos+=(0,55,0)
- #o.shape.color=jointcolor2
- #if o.mat.type>2 :
- #bj+=1
- #o.shape.color=jointcolor5
- ##print o.state.jointNormal.dot(vert)
-
-
-##### to delete facets (should be OK to start the simulation after that!
+
+
+##### to delete facets
for b in O.bodies:
if isinstance(b.shape,Facet):
O.bodies.erase(b.id)
O.resetTime()
O.interactions.clear()
-print '\n IdentificationSpheresOnJoint executed ! Spheres onJoint (and so on...) detected, facets deleted\n\n'
+
+print '\nIdentificationSpheresOnJoint executed ! Spheres onJoint (and so on...) detected, facets deleted, simulation may go on.\n\n'
=== modified file 'examples/ring2d/ringSimpleViscoelastic.py'
--- examples/ring2d/ringSimpleViscoelastic.py 2013-03-28 11:06:34 +0000
+++ examples/ring2d/ringSimpleViscoelastic.py 2014-04-02 15:33:41 +0000
@@ -15,9 +15,8 @@
es = 0.3
## Import wall's geometry
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
-sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
+sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
walls = O.bodies.append(ymport.stl('ring.stl',material=facetMat))
=== modified file 'examples/rotationalResistance.py'
--- examples/rotationalResistance.py 2013-06-06 09:27:41 +0000
+++ examples/rotationalResistance.py 2014-04-02 15:33:41 +0000
@@ -7,10 +7,8 @@
r = 0.002
-param = getViscoelasticFromSpheresInteraction(tc,en,et)
-
-mat1 = O.materials.append(ViscElMat(frictionAngle=fr,mR = 0.05, mRtype = 1, density=rho,**param))
-mat2 = O.materials.append(ViscElMat(frictionAngle=fr,mR = 0.05, mRtype = 2, density=rho,**param))
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,mR = 0.05, mRtype = 1, density=rho,tc=tc,en=en,et=et))
+mat2 = O.materials.append(ViscElMat(frictionAngle=fr,mR = 0.05, mRtype = 2, density=rho,tc=tc,en=en,et=et))
oriBody = Quaternion(Vector3(1,0,0),(pi/28))
=== added directory 'examples/sph'
=== added file 'examples/sph/README'
--- examples/sph/README 1970-01-01 00:00:00 +0000
+++ examples/sph/README 2014-04-09 14:03:21 +0000
@@ -0,0 +1,5 @@
+This directory contains some scripits, which are
+using SPH method. This is highly experimental for
+the moment.
+
+<2014-04-09 Wed>
=== added file 'examples/sph/box.geo'
--- examples/sph/box.geo 1970-01-01 00:00:00 +0000
+++ examples/sph/box.geo 2014-04-09 14:03:16 +0000
@@ -0,0 +1,27 @@
+acc = 300.0;
+hW = 2000.0;
+thickW = 50.0;
+
+Point(1) = {0, 300, 0, acc};
+Point(2) = {0, -hW, 0, acc};
+Point(3) = {1000.0, -hW, 0, acc};
+Point(4) = {2000.0, -hW, 0, acc};
+Point(5) = {2300, -hW+300, 0, acc};
+Point(6) = {2300, -hW, 0, acc};
+Point(7) = {3700, -hW, 0, acc};
+Point(8) = {4000, -hW+300, 0, acc};
+Point(9) = {4000, 300, 0, acc};
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 5};
+Line(5) = {5, 6};
+Line(6) = {6, 7};
+Line(7) = {7, 8};
+Line(8) = {8, 9};
+Line(9) = {9, 1};
+Line Loop(10) = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+Plane Surface(11) = {10};
+Extrude {0, 0, thickW} {
+ Surface{11};
+}
=== added file 'examples/sph/box.mesh'
--- examples/sph/box.mesh 1970-01-01 00:00:00 +0000
+++ examples/sph/box.mesh 2014-04-09 14:03:16 +0000
@@ -0,0 +1,1273 @@
+ MeshVersionFormatted 2
+ Dimension
+ 3
+ Vertices
+ 388
+ 0 300 0 1
+ 0 -2000 0 2
+ 1000 -2000 0 3
+ 2000 -2000 0 4
+ 2300 -1700 0 5
+ 2300 -2000 0 6
+ 3700 -2000 0 7
+ 4000 -1700 0 8
+ 4000 300 0 9
+ 0 300 50 10
+ 0 -2000 50 11
+ 1000 -2000 50 15
+ 2000 -2000 50 19
+ 2300 -1700 50 23
+ 2300 -2000 50 27
+ 3700 -2000 50 31
+ 4000 -1700 50 35
+ 4000 300 50 39
+ 0 12.500000000903 0 1
+ 0 -274.99999999796 0 1
+ 0 -562.49999999681 0 1
+ 0 -849.99999999633 0 1
+ 0 -1137.4999999966 0 1
+ 0 -1424.9999999969 0 1
+ 0 -1712.4999999971 0 1
+ 249.99999999967 -2000 0 2
+ 499.99999999976 -2000 0 2
+ 749.99999999991 -2000 0 2
+ 1250 -2000 0 3
+ 1500 -2000 0 3
+ 1750 -2000 0 3
+ 2150.0000000009 -1849.9999999991 0 4
+ 2580 -2000 0 6
+ 2860 -2000 0 6
+ 3140 -2000 0 6
+ 3420 -2000 0 6
+ 3850 -1850 0 7
+ 4000 -1414.2857142857 0 8
+ 4000 -1128.5714285715 0 8
+ 4000 -842.8571428572 0 8
+ 4000 -557.1428571428 0 8
+ 4000 -271.42857142853 0 8
+ 4000 14.285714285733 0 8
+ 3714.2857142857 300 0 9
+ 3428.5714285715 300 0 9
+ 3142.8571428572 300 0 9
+ 2857.1428571429 300 0 9
+ 2571.4285714287 300 0 9
+ 2285.7142857144 300 0 9
+ 2000.0000000001 300 0 9
+ 1714.2857142856 300 0 9
+ 1428.5714285713 300 0 9
+ 1142.8571428571 300 0 9
+ 857.1428571428 300 0 9
+ 571.42857142853 300 0 9
+ 285.71428571427 300 0 9
+ 0 12.500000000903 50 13
+ 0 -274.99999999796 50 13
+ 0 -562.49999999681 50 13
+ 0 -849.99999999633 50 13
+ 0 -1137.4999999966 50 13
+ 0 -1424.9999999969 50 13
+ 0 -1712.4999999971 50 13
+ 249.99999999967 -2000 50 14
+ 499.99999999976 -2000 50 14
+ 749.99999999991 -2000 50 14
+ 1250 -2000 50 15
+ 1500 -2000 50 15
+ 1750 -2000 50 15
+ 2150.0000000009 -1849.9999999991 50 16
+ 2580 -2000 50 18
+ 2860 -2000 50 18
+ 3140 -2000 50 18
+ 3420 -2000 50 18
+ 3850 -1850 50 19
+ 4000 -1414.2857142857 50 20
+ 4000 -1128.5714285715 50 20
+ 4000 -842.8571428572 50 20
+ 4000 -557.1428571428 50 20
+ 4000 -271.42857142853 50 20
+ 4000 14.285714285733 50 20
+ 3714.2857142857 300 50 21
+ 3428.5714285715 300 50 21
+ 3142.8571428572 300 50 21
+ 2857.1428571429 300 50 21
+ 2571.4285714287 300 50 21
+ 2285.7142857144 300 50 21
+ 2000.0000000001 300 50 21
+ 1714.2857142856 300 50 21
+ 1428.5714285713 300 50 21
+ 1142.8571428571 300 50 21
+ 857.1428571428 300 50 21
+ 571.42857142853 300 50 21
+ 285.71428571427 300 50 21
+ 1529.4446589135 -846.19882489058 0 11
+ 2948.8647910372 -797.27139693469 0 11
+ 768.85477021509 -1191.4331778603 0 11
+ 2225.3179510661 -995.96925999185 0 11
+ 882.98506830098 -423.62886416129 0 11
+ 2357.4759469348 -385.72537641386 0 11
+ 3334.1697178436 -1295.4261086936 0 11
+ 1753.5944220141 -1401.251792038 0 11
+ 2785.9051377217 -1352.6096802644 0 11
+ 3340.5444050499 -333.78170779744 0 11
+ 1781.7192577219 -312.00179782218 0 11
+ 1239.0164902535 -1479.6066037279 0 11
+ 3406.8595304718 -826.55892132953 0 11
+ 498.05326042224 -798.11345014194 0 11
+ 2877.3940074457 -158.86269305865 0 11
+ 1312.9094429575 -188.08933892446 0 11
+ 421.26022679498 -1568.3121263798 0 11
+ 479.3644383792 -179.9473566853 0 11
+ 1079.615368893 -851.4864133385 0 11
+ 2094.5747160518 -1373.0348484798 0 11
+ 1914.3929728395 -699.98358083334 0 11
+ 885.37357867263 -1614.8958107276 0 11
+ 2512.5374604002 -723.15889087768 0 11
+ 3033.6727876963 -1618.0590145742 0 11
+ 3535.4401799374 -1637.6777328536 0 11
+ 2120.8436812794 -73.272527652081 0 11
+ 1870.1705689431 -1065.5436320433 0 11
+ 1470.6887651328 -1197.6555917815 0 11
+ 3101.6438544384 -1176.8301328472 0 11
+ 2640.5965260745 -1681.7980989853 0 11
+ 376.50369589741 -1138.3073016349 0 11
+ 934.26001492933 -130.97450694126 0 11
+ 2446.7543465715 -1314.9110827347 0 11
+ 1519.1695021153 -1704.2615789078 0 11
+ 1321.38510647 -490.93211495581 0 11
+ 1856.8766695228 -1713.8800482108 0 11
+ 3629.2731642966 -119.36920619177 0 11
+ 3579.263470053 -1141.5591856709 0 11
+ 2705.0374641419 -1026.2932625922 0 11
+ 3603.2172344318 -594.03118802079 0 11
+ 3110.049443106 -478.9767977651 0 11
+ 2571.4746621187 -46.609234895912 0 11
+ 1135.8000096194 -1171.5142581261 0 11
+ 3187.7055426079 -56.57788934156 0 11
+ 2713.4240465413 -521.10101130376 0 11
+ 1609.7287827223 -27.757030646951 0 11
+ 2218.2808542131 -611.73080288984 0 11
+ 339.77434389417 -501.56273219575 0 11
+ 1628.4095443371 -583.8378231765 0 11
+ 1127.7531780478 -1736.4024554212 0 11
+ 783.45663487986 -911.36971711706 0 11
+ 632.05380854947 -1754.5359385757 0 11
+ 3708.2839439231 -1405.4255247641 0 11
+ 2454.7868603542 -1539.9042746893 0 11
+ 2091.9665388526 -311.17123097013 0 11
+ 2082.1217200227 -1635.0000625566 0 11
+ 3273.4354982145 -1742.8740271813 0 11
+ 3706.0339596851 -848.60652082524 0 11
+ 722.36683469073 42.963518414442 0 11
+ 262.94130347572 -1733.5288300386 0 11
+ 3778.058225824 -1628.058225824 0 11
+ 622.80394092887 -467.13330345548 0 11
+ 1004.3260710173 -1346.6259737243 0 11
+ 3129.5375392764 -925.21562551409 0 11
+ 1920.0539321953 81.716682003892 0 11
+ 264.10502811154 33.186453018978 0 11
+ 3335.9949786522 -564.15567518578 0 11
+ 2971.1394624533 -1381.1740234635 0 11
+ 1351.8207521926 -1026.0372727017 0 11
+ 215.1945587744 -921.44343644 0 11
+ 3777.9039666689 -389.01253121797 0 11
+ 696.60118099605 -1445.3382867397 0 11
+ 728.35605944582 -231.74410256578 0 11
+ 3319.3115215333 -1073.9684694836 0 11
+ 1530.8304268418 -320.52362110518 0 11
+ 1285.7142857142 76.103882369648 0 11
+ 2474.4274814706 -1015.6649119318 0 11
+ 2951.0287882931 71.331937890859 0 11
+ 1520.501381672 -1425.3304293798 0 11
+ 253.6973135114 -1374.8468483467 0 11
+ 1110.952305133 -319.40091038483 0 11
+ 1350.6011578823 -1811.1729631562 0 11
+ 2338.1660764839 65.729833865481 0 11
+ 2858.5107349988 -1760.0160943389 0 11
+ 1627.2275441016 -1039.7316169914 0 11
+ 3665.7543823172 -1786.4216673679 0 11
+ 1923.8707999441 -1275.6821326923 0 11
+ 1085.6123252695 -587.51500034014 0 11
+ 3438.4243515027 68.682495248415 0 11
+ 605.58286398704 -1059.6338500857 0 11
+ 2609.508999673 -311.68836401073 0 11
+ 245.98314002489 -259.25014738251 0 11
+ 2058.4956784593 -885.34925903342 0 11
+ 1764.0325246399 -866.84558719798 0 11
+ 3110.001253574 -276.20095824932 0 11
+ 2265.1599402191 -1488.4548701852 0 11
+ 2468.3827255104 -1797.189068538 0 11
+ 1682.7777746686 -1801.9522820407 0 11
+ 874.99999999995 -1825.0191987092 0 11
+ 2826.2893615091 -1545.2191605369 0 11
+ 2072.1121891632 -1138.5574595677 0 11
+ 798.90642055128 -666.5740256143 0 11
+ 3363.9794589634 -1515.8092628208 0 11
+ 2310.0022045934 -817.77285230863 0 11
+ 956.7723965576 -1038.1425165412 0 11
+ 203.80770423961 -694.60096326135 0 11
+ 1332.7146260126 -731.0012415672 0 11
+ 2736.2963545966 -809.01301810765 0 11
+ 1912.917229461 -1489.1145205076 0 11
+ 2848.8056048724 -1187.6725098473 0 11
+ 1910.311811976 -490.06137012571 0 11
+ 2755.2480385675 99.259138194832 0 11
+ 3137.71838514 -698.10133794125 0 11
+ 3769.8773198013 73.021229696858 0 11
+ 2504.8730852043 -516.86975916373 0 11
+ 1707.6394965756 -1589.2984418475 0 11
+ 1967.7996779093 -1839.7760221533 0 11
+ 2322.1948729117 -158.21196510554 0 11
+ 520.41667523366 -1296.3119318412 0 11
+ 2648.8039626677 -1229.9564880484 0 11
+ 1694.342246968 -1234.1991991544 0 11
+ 2142.5260679531 138.52442710411 0 11
+ 3504.2273541441 -1399.1795629606 0 11
+ 1015.165916226 86.098665248372 0 11
+ 3835.4108901534 -138.50067297114 0 11
+ 476.63184692998 107.35456591656 0 11
+ 3046.5330873028 -1818.6891070206 0 11
+ 3816.8158456071 -1224.5822677841 0 11
+ 2911.6976013938 -987.04932430719 0 11
+ 1288.2093595642 -1287.1762444129 0 11
+ 2633.2953778388 -1455.0724689842 0 11
+ 2909.6711019268 -606.11308583545 0 11
+ 3503.5967245883 -1828.5311691038 0 11
+ 3819.95043295 -657.02581520156 0 11
+ 443.03408776235 -1816.8508568957 0 11
+ 1922.7072374645 -140.38078415628 0 11
+ 2263.0577707571 -1221.0987388152 0 11
+ 165.61538782086 -1558.4628703367 0 11
+ 3820.422655069 -1037.2353091418 0 11
+ 3441.4789343952 -149.50414065605 0 11
+ 1068.5780858665 -1557.7249410525 0 11
+ 3169.8062650757 -1459.8592624457 0 11
+ 124.99999999984 -1856.2499999986 0 11
+ 1144.2671355981 -77.68362293098 0 11
+ 3530.4249014986 -366.64277666758 0 11
+ 2888.3414753778 -392.15715170384 0 11
+ 1352.7439897812 -1626.7393704996 0 11
+ 1529.4446589135 -846.19882489058 50 58
+ 2948.8647910372 -797.27139693469 50 58
+ 768.85477021509 -1191.4331778603 50 58
+ 2225.3179510661 -995.96925999185 50 58
+ 882.98506830098 -423.62886416129 50 58
+ 2357.4759469348 -385.72537641386 50 58
+ 3334.1697178436 -1295.4261086936 50 58
+ 1753.5944220141 -1401.251792038 50 58
+ 2785.9051377217 -1352.6096802644 50 58
+ 3340.5444050499 -333.78170779744 50 58
+ 1781.7192577219 -312.00179782218 50 58
+ 1239.0164902535 -1479.6066037279 50 58
+ 3406.8595304718 -826.55892132953 50 58
+ 498.05326042224 -798.11345014194 50 58
+ 2877.3940074457 -158.86269305865 50 58
+ 1312.9094429575 -188.08933892446 50 58
+ 421.26022679498 -1568.3121263798 50 58
+ 479.3644383792 -179.9473566853 50 58
+ 1079.615368893 -851.4864133385 50 58
+ 2094.5747160518 -1373.0348484798 50 58
+ 1914.3929728395 -699.98358083334 50 58
+ 885.37357867263 -1614.8958107276 50 58
+ 2512.5374604002 -723.15889087768 50 58
+ 3033.6727876963 -1618.0590145742 50 58
+ 3535.4401799374 -1637.6777328536 50 58
+ 2120.8436812794 -73.272527652081 50 58
+ 1870.1705689431 -1065.5436320433 50 58
+ 1470.6887651328 -1197.6555917815 50 58
+ 3101.6438544384 -1176.8301328472 50 58
+ 2640.5965260745 -1681.7980989853 50 58
+ 376.50369589741 -1138.3073016349 50 58
+ 934.26001492933 -130.97450694126 50 58
+ 2446.7543465715 -1314.9110827347 50 58
+ 1519.1695021153 -1704.2615789078 50 58
+ 1321.38510647 -490.93211495581 50 58
+ 1856.8766695228 -1713.8800482108 50 58
+ 3629.2731642966 -119.36920619177 50 58
+ 3579.263470053 -1141.5591856709 50 58
+ 2705.0374641419 -1026.2932625922 50 58
+ 3603.2172344318 -594.03118802079 50 58
+ 3110.049443106 -478.9767977651 50 58
+ 2571.4746621187 -46.609234895912 50 58
+ 1135.8000096194 -1171.5142581261 50 58
+ 3187.7055426079 -56.57788934156 50 58
+ 2713.4240465413 -521.10101130376 50 58
+ 1609.7287827223 -27.757030646951 50 58
+ 2218.2808542131 -611.73080288984 50 58
+ 339.77434389417 -501.56273219575 50 58
+ 1628.4095443371 -583.8378231765 50 58
+ 1127.7531780478 -1736.4024554212 50 58
+ 783.45663487986 -911.36971711706 50 58
+ 632.05380854947 -1754.5359385757 50 58
+ 3708.2839439231 -1405.4255247641 50 58
+ 2454.7868603542 -1539.9042746893 50 58
+ 2091.9665388526 -311.17123097013 50 58
+ 2082.1217200227 -1635.0000625566 50 58
+ 3273.4354982145 -1742.8740271813 50 58
+ 3706.0339596851 -848.60652082524 50 58
+ 722.36683469073 42.963518414442 50 58
+ 262.94130347572 -1733.5288300386 50 58
+ 3778.058225824 -1628.058225824 50 58
+ 622.80394092887 -467.13330345548 50 58
+ 1004.3260710173 -1346.6259737243 50 58
+ 3129.5375392764 -925.21562551409 50 58
+ 1920.0539321953 81.716682003892 50 58
+ 264.10502811154 33.186453018978 50 58
+ 3335.9949786522 -564.15567518578 50 58
+ 2971.1394624533 -1381.1740234635 50 58
+ 1351.8207521926 -1026.0372727017 50 58
+ 215.1945587744 -921.44343644 50 58
+ 3777.9039666689 -389.01253121797 50 58
+ 696.60118099605 -1445.3382867397 50 58
+ 728.35605944582 -231.74410256578 50 58
+ 3319.3115215333 -1073.9684694836 50 58
+ 1530.8304268418 -320.52362110518 50 58
+ 1285.7142857142 76.103882369648 50 58
+ 2474.4274814706 -1015.6649119318 50 58
+ 2951.0287882931 71.331937890859 50 58
+ 1520.501381672 -1425.3304293798 50 58
+ 253.6973135114 -1374.8468483467 50 58
+ 1110.952305133 -319.40091038483 50 58
+ 1350.6011578823 -1811.1729631562 50 58
+ 2338.1660764839 65.729833865481 50 58
+ 2858.5107349988 -1760.0160943389 50 58
+ 1627.2275441016 -1039.7316169914 50 58
+ 3665.7543823172 -1786.4216673679 50 58
+ 1923.8707999441 -1275.6821326923 50 58
+ 1085.6123252695 -587.51500034014 50 58
+ 3438.4243515027 68.682495248415 50 58
+ 605.58286398704 -1059.6338500857 50 58
+ 2609.508999673 -311.68836401073 50 58
+ 245.98314002489 -259.25014738251 50 58
+ 2058.4956784593 -885.34925903342 50 58
+ 1764.0325246399 -866.84558719798 50 58
+ 3110.001253574 -276.20095824932 50 58
+ 2265.1599402191 -1488.4548701852 50 58
+ 2468.3827255104 -1797.189068538 50 58
+ 1682.7777746686 -1801.9522820407 50 58
+ 874.99999999995 -1825.0191987092 50 58
+ 2826.2893615091 -1545.2191605369 50 58
+ 2072.1121891632 -1138.5574595677 50 58
+ 798.90642055128 -666.5740256143 50 58
+ 3363.9794589634 -1515.8092628208 50 58
+ 2310.0022045934 -817.77285230863 50 58
+ 956.7723965576 -1038.1425165412 50 58
+ 203.80770423961 -694.60096326135 50 58
+ 1332.7146260126 -731.0012415672 50 58
+ 2736.2963545966 -809.01301810765 50 58
+ 1912.917229461 -1489.1145205076 50 58
+ 2848.8056048724 -1187.6725098473 50 58
+ 1910.311811976 -490.06137012571 50 58
+ 2755.2480385675 99.259138194832 50 58
+ 3137.71838514 -698.10133794125 50 58
+ 3769.8773198013 73.021229696858 50 58
+ 2504.8730852043 -516.86975916373 50 58
+ 1707.6394965756 -1589.2984418475 50 58
+ 1967.7996779093 -1839.7760221533 50 58
+ 2322.1948729117 -158.21196510554 50 58
+ 520.41667523366 -1296.3119318412 50 58
+ 2648.8039626677 -1229.9564880484 50 58
+ 1694.342246968 -1234.1991991544 50 58
+ 2142.5260679531 138.52442710411 50 58
+ 3504.2273541441 -1399.1795629606 50 58
+ 1015.165916226 86.098665248372 50 58
+ 3835.4108901534 -138.50067297114 50 58
+ 476.63184692998 107.35456591656 50 58
+ 3046.5330873028 -1818.6891070206 50 58
+ 3816.8158456071 -1224.5822677841 50 58
+ 2911.6976013938 -987.04932430719 50 58
+ 1288.2093595642 -1287.1762444129 50 58
+ 2633.2953778388 -1455.0724689842 50 58
+ 2909.6711019268 -606.11308583545 50 58
+ 3503.5967245883 -1828.5311691038 50 58
+ 3819.95043295 -657.02581520156 50 58
+ 443.03408776235 -1816.8508568957 50 58
+ 1922.7072374645 -140.38078415628 50 58
+ 2263.0577707571 -1221.0987388152 50 58
+ 165.61538782086 -1558.4628703367 50 58
+ 3820.422655069 -1037.2353091418 50 58
+ 3441.4789343952 -149.50414065605 50 58
+ 1068.5780858665 -1557.7249410525 50 58
+ 3169.8062650757 -1459.8592624457 50 58
+ 124.99999999984 -1856.2499999986 50 58
+ 1144.2671355981 -77.68362293098 50 58
+ 3530.4249014986 -366.64277666758 50 58
+ 2888.3414753778 -392.15715170384 50 58
+ 1352.7439897812 -1626.7393704996 50 58
+ Edges
+ 103
+ 1 19 1
+ 19 20 1
+ 20 21 1
+ 21 22 1
+ 22 23 1
+ 23 24 1
+ 24 25 1
+ 25 2 1
+ 2 26 2
+ 26 27 2
+ 27 28 2
+ 28 3 2
+ 3 29 3
+ 29 30 3
+ 30 31 3
+ 31 4 3
+ 4 32 4
+ 32 5 4
+ 5 6 5
+ 6 33 6
+ 33 34 6
+ 34 35 6
+ 35 36 6
+ 36 7 6
+ 7 37 7
+ 37 8 7
+ 8 38 8
+ 38 39 8
+ 39 40 8
+ 40 41 8
+ 41 42 8
+ 42 43 8
+ 43 9 8
+ 9 44 9
+ 44 45 9
+ 45 46 9
+ 46 47 9
+ 47 48 9
+ 48 49 9
+ 49 50 9
+ 50 51 9
+ 51 52 9
+ 52 53 9
+ 53 54 9
+ 54 55 9
+ 55 56 9
+ 56 1 9
+ 10 57 13
+ 57 58 13
+ 58 59 13
+ 59 60 13
+ 60 61 13
+ 61 62 13
+ 62 63 13
+ 63 11 13
+ 11 64 14
+ 64 65 14
+ 65 66 14
+ 66 12 14
+ 12 67 15
+ 67 68 15
+ 68 69 15
+ 69 13 15
+ 13 70 16
+ 70 14 16
+ 14 15 17
+ 15 71 18
+ 71 72 18
+ 72 73 18
+ 73 74 18
+ 74 16 18
+ 16 75 19
+ 75 17 19
+ 17 76 20
+ 76 77 20
+ 77 78 20
+ 78 79 20
+ 79 80 20
+ 80 81 20
+ 81 18 20
+ 18 82 21
+ 82 83 21
+ 83 84 21
+ 84 85 21
+ 85 86 21
+ 86 87 21
+ 87 88 21
+ 88 89 21
+ 89 90 21
+ 90 91 21
+ 91 92 21
+ 92 93 21
+ 93 94 21
+ 94 10 21
+ 1 10 23
+ 2 11 24
+ 3 12 28
+ 4 13 32
+ 5 14 36
+ 6 15 40
+ 7 16 44
+ 8 17 48
+ 9 18 52
+ Triangles
+ 772
+ 162 236 123 11
+ 123 236 101 11
+ 33 178 124 11
+ 99 175 126 11
+ 23 125 164 11
+ 110 129 169 11
+ 44 183 208 11
+ 23 174 125 11
+ 115 143 188 11
+ 1 160 56 11
+ 1 19 160 11
+ 184 108 125 11
+ 127 171 231 11
+ 107 134 161 11
+ 21 142 186 11
+ 112 142 156 11
+ 115 187 141 11
+ 148 127 190 11
+ 125 108 164 11
+ 101 217 132 11
+ 99 126 167 11
+ 141 187 198 11
+ 5 191 148 11
+ 95 143 201 11
+ 51 52 140 11
+ 131 208 183 11
+ 30 192 128 11
+ 171 98 231 11
+ 107 132 152 11
+ 101 132 168 11
+ 30 128 176 11
+ 20 21 186 11
+ 127 231 190 11
+ 107 168 132 11
+ 52 170 140 11
+ 44 45 183 11
+ 129 201 143 11
+ 95 188 143 11
+ 211 130 31 11
+ 101 168 123 11
+ 46 138 183 11
+ 100 149 141 11
+ 33 124 191 11
+ 107 152 134 11
+ 112 156 167 11
+ 117 202 139 11
+ 137 199 157 11
+ 110 175 129 11
+ 33 34 178 11
+ 129 143 169 11
+ 41 165 228 11
+ 130 192 31 11
+ 199 97 157 11
+ 109 206 136 11
+ 116 166 146 11
+ 110 140 170 11
+ 115 141 205 11
+ 8 38 155 11
+ 134 228 165 11
+ 48 177 136 11
+ 115 205 143 11
+ 111 146 166 11
+ 105 230 140 11
+ 139 202 226 11
+ 45 46 183 11
+ 19 186 160 11
+ 107 207 158 11
+ 122 173 215 11
+ 124 148 191 11
+ 117 209 141 11
+ 127 225 214 11
+ 127 148 225 11
+ 19 20 186 11
+ 7 180 227 11
+ 161 207 107 11
+ 5 150 32 11
+ 46 172 138 11
+ 41 42 165 11
+ 134 239 161 11
+ 104 135 161 11
+ 100 141 209 11
+ 122 179 163 11
+ 117 139 209 11
+ 141 149 205 11
+ 3 29 144 11
+ 109 136 185 11
+ 51 140 159 11
+ 108 156 142 11
+ 105 140 169 11
+ 95 163 179 11
+ 113 196 145 11
+ 4 211 31 11
+ 102 215 173 11
+ 104 138 189 11
+ 113 137 163 11
+ 108 142 200 11
+ 100 212 149 11
+ 132 217 147 11
+ 104 189 135 11
+ 110 169 140 11
+ 109 189 138 11
+ 109 172 206 11
+ 109 138 172 11
+ 22 23 164 11
+ 127 214 171 11
+ 5 6 191 11
+ 234 138 104 11
+ 23 24 174 11
+ 117 141 198 11
+ 113 182 196 11
+ 32 150 211 11
+ 140 230 159 11
+ 48 136 206 11
+ 54 153 218 11
+ 126 175 238 11
+ 38 147 155 11
+ 236 151 197 11
+ 98 198 187 11
+ 100 185 212 11
+ 136 212 185 11
+ 54 55 153 11
+ 27 28 146 11
+ 48 49 177 11
+ 97 184 213 11
+ 105 143 205 11
+ 116 157 166 11
+ 113 199 137 11
+ 7 227 36 11
+ 97 166 157 11
+ 118 151 236 11
+ 126 218 153 11
+ 108 145 196 11
+ 112 186 142 11
+ 99 167 156 11
+ 21 200 142 11
+ 133 171 214 11
+ 116 193 144 11
+ 106 224 157 11
+ 104 161 239 11
+ 123 168 158 11
+ 97 213 166 11
+ 137 157 224 11
+ 3 144 193 11
+ 119 155 147 11
+ 120 149 212 11
+ 105 169 143 11
+ 8 155 37 11
+ 108 196 156 11
+ 46 47 172 11
+ 131 234 239 11
+ 108 184 145 11
+ 35 36 151 11
+ 131 239 165 11
+ 50 51 159 11
+ 114 190 231 11
+ 122 163 224 11
+ 116 144 235 11
+ 29 176 144 11
+ 106 173 224 11
+ 108 200 164 11
+ 137 224 163 11
+ 111 229 146 11
+ 130 211 150 11
+ 111 232 154 11
+ 113 201 182 11
+ 106 144 241 11
+ 96 226 202 11
+ 28 193 146 11
+ 103 214 225 11
+ 133 202 171 11
+ 30 31 192 11
+ 106 241 173 11
+ 122 215 179 11
+ 130 203 210 11
+ 116 146 193 11
+ 121 195 187 11
+ 106 235 144 11
+ 29 30 176 11
+ 111 154 229 11
+ 117 171 202 11
+ 130 150 203 11
+ 5 148 190 11
+ 126 153 167 11
+ 97 145 184 11
+ 112 167 153 11
+ 111 174 232 11
+ 103 162 204 11
+ 129 182 201 11
+ 26 229 154 11
+ 97 199 145 11
+ 113 145 199 11
+ 9 208 43 11
+ 9 44 208 11
+ 119 147 217 11
+ 52 53 170 11
+ 37 155 180 11
+ 26 27 229 11
+ 5 190 150 11
+ 107 158 168 11
+ 6 33 191 11
+ 112 160 186 11
+ 123 204 162 11
+ 112 153 220 11
+ 114 203 150 11
+ 109 185 240 11
+ 98 187 195 11
+ 105 149 230 11
+ 96 223 158 11
+ 123 158 223 11
+ 38 222 147 11
+ 120 230 149 11
+ 7 37 180 11
+ 119 197 151 11
+ 113 163 201 11
+ 139 240 185 11
+ 120 216 159 11
+ 2 237 25 11
+ 112 220 160 11
+ 110 238 175 11
+ 103 194 162 11
+ 27 146 229 11
+ 53 218 170 11
+ 105 205 149 11
+ 122 224 173 11
+ 50 159 216 11
+ 102 210 203 11
+ 114 150 190 11
+ 119 151 227 11
+ 121 187 188 11
+ 34 35 221 11
+ 102 173 210 11
+ 119 180 155 11
+ 133 223 202 11
+ 21 22 200 11
+ 118 221 151 11
+ 144 176 241 11
+ 132 147 222 11
+ 128 210 173 11
+ 55 56 220 11
+ 170 218 238 11
+ 109 240 189 11
+ 129 175 182 11
+ 115 188 187 11
+ 121 181 195 11
+ 38 39 222 11
+ 99 156 196 11
+ 125 213 184 11
+ 56 160 220 11
+ 35 151 221 11
+ 3 193 28 11
+ 99 196 182 11
+ 40 228 152 11
+ 139 185 209 11
+ 99 182 175 11
+ 40 152 233 11
+ 26 154 237 11
+ 100 209 185 11
+ 118 162 194 11
+ 136 177 212 11
+ 22 164 200 11
+ 47 48 206 11
+ 132 233 152 11
+ 128 173 241 11
+ 124 225 148 11
+ 124 178 194 11
+ 134 152 228 11
+ 111 213 174 11
+ 40 41 228 11
+ 39 40 233 11
+ 36 227 151 11
+ 135 207 161 11
+ 95 179 188 11
+ 114 181 203 11
+ 135 189 240 11
+ 125 174 213 11
+ 96 202 223 11
+ 138 234 183 11
+ 96 158 207 11
+ 34 221 178 11
+ 98 195 231 11
+ 55 220 153 11
+ 116 235 157 11
+ 24 25 232 11
+ 121 188 179 11
+ 49 50 216 11
+ 42 43 219 11
+ 4 32 211 11
+ 53 54 218 11
+ 98 171 198 11
+ 95 201 163 11
+ 106 157 235 11
+ 120 159 230 11
+ 114 195 181 11
+ 25 154 232 11
+ 117 198 171 11
+ 25 237 154 11
+ 118 194 178 11
+ 124 194 225 11
+ 2 26 237 11
+ 47 206 172 11
+ 130 210 192 11
+ 131 165 219 11
+ 103 225 194 11
+ 111 166 213 11
+ 42 219 165 11
+ 102 203 181 11
+ 104 239 234 11
+ 134 165 239 11
+ 128 192 210 11
+ 118 236 162 11
+ 120 212 177 11
+ 133 204 223 11
+ 103 204 214 11
+ 110 170 238 11
+ 120 177 216 11
+ 121 179 215 11
+ 133 214 204 11
+ 102 181 215 11
+ 118 178 221 11
+ 49 216 177 11
+ 24 232 174 11
+ 126 238 218 11
+ 121 215 181 11
+ 128 241 176 11
+ 96 207 226 11
+ 131 183 234 11
+ 119 217 197 11
+ 101 197 217 11
+ 135 226 207 11
+ 114 231 195 11
+ 101 236 197 11
+ 131 219 208 11
+ 119 227 180 11
+ 43 208 219 11
+ 123 223 204 11
+ 132 222 233 11
+ 139 226 240 11
+ 135 240 226 11
+ 39 233 222 11
+ 19 20 57 25
+ 57 20 58 25
+ 60 23 61 25
+ 60 22 23 25
+ 61 24 62 25
+ 61 23 24 25
+ 10 19 57 25
+ 10 1 19 25
+ 20 59 58 25
+ 20 21 59 25
+ 59 22 60 25
+ 59 21 22 25
+ 25 62 24 25
+ 25 63 62 25
+ 11 25 2 25
+ 11 63 25 25
+ 11 2 64 29
+ 2 26 64 29
+ 26 65 64 29
+ 27 65 26 29
+ 65 28 66 29
+ 65 27 28 29
+ 66 3 12 29
+ 66 28 3 29
+ 12 3 67 33
+ 3 29 67 33
+ 68 30 69 33
+ 30 31 69 33
+ 69 31 13 33
+ 31 4 13 33
+ 67 30 68 33
+ 67 29 30 33
+ 13 32 70 37
+ 13 4 32 37
+ 32 14 70 37
+ 32 5 14 37
+ 14 5 15 41
+ 5 6 15 41
+ 6 71 15 45
+ 6 33 71 45
+ 33 34 71 45
+ 71 34 72 45
+ 34 73 72 45
+ 34 35 73 45
+ 36 73 35 45
+ 74 73 36 45
+ 16 36 7 45
+ 16 74 36 45
+ 7 37 16 49
+ 16 37 75 49
+ 75 37 17 49
+ 37 8 17 49
+ 17 38 76 53
+ 17 8 38 53
+ 38 39 76 53
+ 76 39 77 53
+ 81 43 18 53
+ 43 9 18 53
+ 77 40 78 53
+ 77 39 40 53
+ 40 79 78 53
+ 41 79 40 53
+ 79 42 80 53
+ 79 41 42 53
+ 80 43 81 53
+ 42 43 80 53
+ 18 9 82 57
+ 9 44 82 57
+ 44 45 82 57
+ 82 45 83 57
+ 83 45 84 57
+ 45 46 84 57
+ 46 47 84 57
+ 84 47 85 57
+ 49 50 88 57
+ 49 88 87 57
+ 51 90 89 57
+ 51 52 90 57
+ 54 55 92 57
+ 92 55 93 57
+ 93 56 94 57
+ 93 55 56 57
+ 48 85 47 57
+ 86 85 48 57
+ 49 86 48 57
+ 87 86 49 57
+ 89 50 51 57
+ 89 88 50 57
+ 52 91 90 57
+ 52 53 91 57
+ 91 54 92 57
+ 91 53 54 57
+ 94 1 10 57
+ 94 56 1 57
+ 309 383 270 58
+ 270 383 248 58
+ 71 325 271 58
+ 246 322 273 58
+ 61 272 311 58
+ 257 276 316 58
+ 82 330 355 58
+ 61 321 272 58
+ 262 290 335 58
+ 10 307 94 58
+ 10 57 307 58
+ 331 255 272 58
+ 274 318 378 58
+ 254 281 308 58
+ 59 289 333 58
+ 259 289 303 58
+ 262 334 288 58
+ 295 274 337 58
+ 272 255 311 58
+ 248 364 279 58
+ 246 273 314 58
+ 288 334 345 58
+ 14 338 295 58
+ 242 290 348 58
+ 89 90 287 58
+ 278 355 330 58
+ 68 339 275 58
+ 318 245 378 58
+ 254 279 299 58
+ 248 279 315 58
+ 68 275 323 58
+ 58 59 333 58
+ 274 378 337 58
+ 254 315 279 58
+ 90 317 287 58
+ 82 83 330 58
+ 276 348 290 58
+ 242 335 290 58
+ 358 277 69 58
+ 248 315 270 58
+ 84 285 330 58
+ 247 296 288 58
+ 71 271 338 58
+ 254 299 281 58
+ 259 303 314 58
+ 264 349 286 58
+ 284 346 304 58
+ 257 322 276 58
+ 71 72 325 58
+ 276 290 316 58
+ 79 312 375 58
+ 277 339 69 58
+ 346 244 304 58
+ 256 353 283 58
+ 263 313 293 58
+ 257 287 317 58
+ 262 288 352 58
+ 17 76 302 58
+ 281 375 312 58
+ 86 324 283 58
+ 262 352 290 58
+ 258 293 313 58
+ 252 377 287 58
+ 286 349 373 58
+ 83 84 330 58
+ 57 333 307 58
+ 254 354 305 58
+ 269 320 362 58
+ 271 295 338 58
+ 264 356 288 58
+ 274 372 361 58
+ 274 295 372 58
+ 57 58 333 58
+ 16 327 374 58
+ 308 354 254 58
+ 14 297 70 58
+ 84 319 285 58
+ 79 80 312 58
+ 281 386 308 58
+ 251 282 308 58
+ 247 288 356 58
+ 269 326 310 58
+ 264 286 356 58
+ 288 296 352 58
+ 12 67 291 58
+ 256 283 332 58
+ 89 287 306 58
+ 255 303 289 58
+ 252 287 316 58
+ 242 310 326 58
+ 260 343 292 58
+ 13 358 69 58
+ 249 362 320 58
+ 251 285 336 58
+ 260 284 310 58
+ 255 289 347 58
+ 247 359 296 58
+ 279 364 294 58
+ 251 336 282 58
+ 257 316 287 58
+ 256 336 285 58
+ 256 319 353 58
+ 256 285 319 58
+ 60 61 311 58
+ 274 361 318 58
+ 14 15 338 58
+ 381 285 251 58
+ 61 62 321 58
+ 264 288 345 58
+ 260 329 343 58
+ 70 297 358 58
+ 287 377 306 58
+ 86 283 353 58
+ 92 300 365 58
+ 273 322 385 58
+ 76 294 302 58
+ 383 298 344 58
+ 245 345 334 58
+ 247 332 359 58
+ 283 359 332 58
+ 92 93 300 58
+ 65 66 293 58
+ 86 87 324 58
+ 244 331 360 58
+ 252 290 352 58
+ 263 304 313 58
+ 260 346 284 58
+ 16 374 74 58
+ 244 313 304 58
+ 265 298 383 58
+ 273 365 300 58
+ 255 292 343 58
+ 259 333 289 58
+ 246 314 303 58
+ 59 347 289 58
+ 280 318 361 58
+ 263 340 291 58
+ 253 371 304 58
+ 251 308 386 58
+ 270 315 305 58
+ 244 360 313 58
+ 284 304 371 58
+ 12 291 340 58
+ 266 302 294 58
+ 267 296 359 58
+ 252 316 290 58
+ 17 302 75 58
+ 255 343 303 58
+ 84 85 319 58
+ 278 381 386 58
+ 255 331 292 58
+ 73 74 298 58
+ 278 386 312 58
+ 88 89 306 58
+ 261 337 378 58
+ 269 310 371 58
+ 263 291 382 58
+ 67 323 291 58
+ 253 320 371 58
+ 255 347 311 58
+ 284 371 310 58
+ 258 376 293 58
+ 277 358 297 58
+ 258 379 301 58
+ 260 348 329 58
+ 253 291 388 58
+ 243 373 349 58
+ 66 340 293 58
+ 250 361 372 58
+ 280 349 318 58
+ 68 69 339 58
+ 253 388 320 58
+ 269 362 326 58
+ 277 350 357 58
+ 263 293 340 58
+ 268 342 334 58
+ 253 382 291 58
+ 67 68 323 58
+ 258 301 376 58
+ 264 318 349 58
+ 277 297 350 58
+ 14 295 337 58
+ 273 300 314 58
+ 244 292 331 58
+ 259 314 300 58
+ 258 321 379 58
+ 250 309 351 58
+ 276 329 348 58
+ 64 376 301 58
+ 244 346 292 58
+ 260 292 346 58
+ 18 355 81 58
+ 18 82 355 58
+ 266 294 364 58
+ 90 91 317 58
+ 75 302 327 58
+ 64 65 376 58
+ 14 337 297 58
+ 254 305 315 58
+ 15 71 338 58
+ 259 307 333 58
+ 270 351 309 58
+ 259 300 367 58
+ 261 350 297 58
+ 256 332 387 58
+ 245 334 342 58
+ 252 296 377 58
+ 243 370 305 58
+ 270 305 370 58
+ 76 369 294 58
+ 267 377 296 58
+ 16 75 327 58
+ 266 344 298 58
+ 260 310 348 58
+ 286 387 332 58
+ 267 363 306 58
+ 11 384 63 58
+ 259 367 307 58
+ 257 385 322 58
+ 250 341 309 58
+ 65 293 376 58
+ 91 365 317 58
+ 252 352 296 58
+ 269 371 320 58
+ 88 306 363 58
+ 249 357 350 58
+ 261 297 337 58
+ 266 298 374 58
+ 268 334 335 58
+ 72 73 368 58
+ 249 320 357 58
+ 266 327 302 58
+ 280 370 349 58
+ 59 60 347 58
+ 265 368 298 58
+ 291 323 388 58
+ 279 294 369 58
+ 275 357 320 58
+ 93 94 367 58
+ 317 365 385 58
+ 256 387 336 58
+ 276 322 329 58
+ 262 335 334 58
+ 268 328 342 58
+ 76 77 369 58
+ 246 303 343 58
+ 272 360 331 58
+ 94 307 367 58
+ 73 298 368 58
+ 12 340 66 58
+ 246 343 329 58
+ 78 375 299 58
+ 286 332 356 58
+ 246 329 322 58
+ 78 299 380 58
+ 64 301 384 58
+ 247 356 332 58
+ 265 309 341 58
+ 283 324 359 58
+ 60 311 347 58
+ 85 86 353 58
+ 279 380 299 58
+ 275 320 388 58
+ 271 372 295 58
+ 271 325 341 58
+ 281 299 375 58
+ 258 360 321 58
+ 78 79 375 58
+ 77 78 380 58
+ 74 374 298 58
+ 282 354 308 58
+ 242 326 335 58
+ 261 328 350 58
+ 282 336 387 58
+ 272 321 360 58
+ 243 349 370 58
+ 285 381 330 58
+ 243 305 354 58
+ 72 368 325 58
+ 245 342 378 58
+ 93 367 300 58
+ 263 382 304 58
+ 62 63 379 58
+ 268 335 326 58
+ 87 88 363 58
+ 80 81 366 58
+ 13 70 358 58
+ 91 92 365 58
+ 245 318 345 58
+ 242 348 310 58
+ 253 304 382 58
+ 267 306 377 58
+ 261 342 328 58
+ 63 301 379 58
+ 264 345 318 58
+ 63 384 301 58
+ 265 341 325 58
+ 271 341 372 58
+ 11 64 384 58
+ 85 353 319 58
+ 277 357 339 58
+ 278 312 366 58
+ 250 372 341 58
+ 258 313 360 58
+ 80 366 312 58
+ 249 350 328 58
+ 251 386 381 58
+ 281 312 386 58
+ 275 339 357 58
+ 265 383 309 58
+ 267 359 324 58
+ 280 351 370 58
+ 250 351 361 58
+ 257 317 385 58
+ 267 324 363 58
+ 268 326 362 58
+ 280 361 351 58
+ 249 328 362 58
+ 265 325 368 58
+ 87 363 324 58
+ 62 379 321 58
+ 273 385 365 58
+ 268 362 328 58
+ 275 388 323 58
+ 243 354 373 58
+ 278 330 381 58
+ 266 364 344 58
+ 248 344 364 58
+ 282 373 354 58
+ 261 378 342 58
+ 248 383 344 58
+ 278 366 355 58
+ 266 374 327 58
+ 81 355 366 58
+ 270 370 351 58
+ 279 369 380 58
+ 286 373 387 58
+ 282 387 373 58
+ 77 380 369 58
+ End
=== added directory 'examples/sph/cpt'
=== added file 'examples/sph/cpt/a'
=== added file 'examples/sph/sph_box.py'
--- examples/sph/sph_box.py 1970-01-01 00:00:00 +0000
+++ examples/sph/sph_box.py 2014-04-09 09:11:49 +0000
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# This script demonstrates SPH-engine in Yade
+# !!! Very experimental at the moment!!!
+
+from yade import utils, plot, qt
+o = Omega()
+
+# Physical parameters
+fr = 0.5;
+rho=1000.0
+
+k = 1.0
+mu = 0.001
+tc = 0.0001; en = 0.7; et = 0.7;
+Rad = 10.0e-3
+o.dt = 0.00025
+
+# Add material
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et))
+
+# Add spheres
+d = 0.18
+idSpheres = O.bodies.append(
+ pack.regularHexa(
+ pack.inAlignedBox(
+ (-d,-d,-d), # lower angle
+ (d,d,d)), # upper angle
+ radius=Rad,gap=0.2*Rad, material=mat1,color=(0,1,1)))
+
+
+id1 = O.bodies.append(geom.facetBox((Vector3(0.0,0,0.0)),
+ (Vector3(0.2, 0.2, 0.2)),
+ material=mat1, mask=1, color=(1,0,0), wire=True))
+
+# Add engines
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb(label='is2aabb'),Bo1_Facet_Aabb(label='is3aabb')]),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom(label='ss2sc'),Ig2_Facet_Sphere_ScGeom()],
+ [Ip2_ViscElMat_ViscElMat_ViscElPhys()],
+ [Law2_ScGeom_ViscElPhys_Basic()],
+ ),
+ NewtonIntegrator(damping=0.0,gravity=[0,0,-9.81]),
+ SPHEngine(mask=1, k=k, rho0 = rho),
+]
+
+
+O.step()
+qt.View()
=== added file 'examples/sph/testKernelFunc.py'
--- examples/sph/testKernelFunc.py 1970-01-01 00:00:00 +0000
+++ examples/sph/testKernelFunc.py 2014-04-09 14:03:21 +0000
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# This example allows to test different kernel functions
+from yade import utils, plot, qt
+o = Omega()
+
+# Physical parameters
+fr = 0.5;
+rho=1000.0
+
+k = 1.0
+mu = 100.0
+tc = 0.0001; en = 0.7; et = 0.7;
+vel = 0.05
+Rad = 15.0e-3
+o.dt = 0.0001
+
+shift = 1.0
+# Add material
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et, KernFunctionPressure = 1, KernFunctionVisco = 1))
+mat2 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et, KernFunctionPressure = 1, KernFunctionVisco = 2))
+mat3 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et, KernFunctionPressure = 1, KernFunctionVisco = 3))
+mat4 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et, KernFunctionPressure = 1, KernFunctionVisco = 4))
+mat5 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et, KernFunctionPressure = 1, KernFunctionVisco = 5))
+
+# Add spheres
+#inert = True
+inert = True
+id11 = O.bodies.append(sphere(center=[0,0,0],radius=Rad, material=mat1, mask = 1, fixed=True))
+id12 = O.bodies.append(sphere(center=[0,0,(Rad*2.0*shift)],radius=Rad, material=mat1, mask = 1, fixed=inert))
+
+id21 = O.bodies.append(sphere(center=[3.0*Rad,0,0],radius=Rad, material=mat2, mask = 1, fixed=True))
+id22 = O.bodies.append(sphere(center=[3.0*Rad,0,(Rad*2.0*shift)],radius=Rad, material=mat2, mask = 1, fixed=inert))
+
+id31 = O.bodies.append(sphere(center=[6.0*Rad,0,0],radius=Rad, material=mat3, mask = 1, fixed=True))
+id32 = O.bodies.append(sphere(center=[6.0*Rad,0,(Rad*2.0*shift)],radius=Rad, material=mat3, mask = 1, fixed=inert))
+
+id41 = O.bodies.append(sphere(center=[9.0*Rad,0,0],radius=Rad, material=mat4, mask = 1, fixed=True))
+id42 = O.bodies.append(sphere(center=[9.0*Rad,0,(Rad*2.0*shift)],radius=Rad, material=mat4, mask = 1, fixed=inert))
+
+id51 = O.bodies.append(sphere(center=[12.0*Rad,0,0],radius=Rad, material=mat5, mask = 1, fixed=True))
+id52 = O.bodies.append(sphere(center=[12.0*Rad,0,(Rad*2.0*shift)],radius=Rad, material=mat5, mask = 1, fixed=inert))
+
+vel = 0.1
+O.bodies[id12].state.vel=Vector3(0,0,-vel)
+O.bodies[id22].state.vel=Vector3(0,0,-vel)
+O.bodies[id32].state.vel=Vector3(0,0,-vel)
+O.bodies[id42].state.vel=Vector3(0,0,-vel)
+O.bodies[id52].state.vel=Vector3(0,0,-vel)
+
+# Add engines
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb(label='is2aabb')]),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom(label='ss2sc')],
+ [Ip2_ViscElMat_ViscElMat_ViscElPhys()],
+ [Law2_ScGeom_ViscElPhys_Basic()],
+ ),
+ NewtonIntegrator(damping=0,gravity=[0,0,-9.81]),
+ SPHEngine(mask=1, k=k, rho0 = rho, KernFunctionDensity=1),
+ PyRunner(command='addPlotData()',iterPeriod=1,dead=False),
+]
+
+print "Time\tX\tRho\tP\tFpr "
+
+# Function to add data to plot
+def addPlotData():
+ #print "%.2f\t%.5f\t%.5f\t%.5f\t%.5f" % (O.time+O.dt, O.bodies[id2].state.pos[2], O.bodies[id2].rho, O.bodies[id2].press, O.forces.f(id2)[2])
+ s1 = (O.bodies[id12].state.pos[2]-O.bodies[id11].state.pos[2])-(Rad*2.0)
+ s2 = (O.bodies[id22].state.pos[2]-O.bodies[id21].state.pos[2])-(Rad*2.0)
+ s3 = (O.bodies[id32].state.pos[2]-O.bodies[id31].state.pos[2])-(Rad*2.0)
+ s4 = (O.bodies[id42].state.pos[2]-O.bodies[id41].state.pos[2])-(Rad*2.0)
+ s5 = (O.bodies[id52].state.pos[2]-O.bodies[id51].state.pos[2])-(Rad*2.0)
+
+ f1 = O.forces.f(id12)[2]
+ f2 = O.forces.f(id22)[2]
+ f3 = O.forces.f(id32)[2]
+ f4 = O.forces.f(id42)[2]
+ f5 = O.forces.f(id52)[2]
+
+ plot.addData(sc=O.iter, s1 = s1, s2 = s2, s3 = s3, s4 = s4, s5 = s5,
+ fc=O.iter, f1 = f1, f2 = f2, f3 = f3, f4 = f4, f5 = f5)
+
+plot.plots={'sc':('s1', 's2', 's3', 's4', 's5'), 'fc':('f1', 'f2', 'f3', 'f4', 'f5')}; plot.plot()
+
+O.run(1, True)
+
+qt.View()
+O.run(1500)
=== added file 'examples/sph/toystar.py'
--- examples/sph/toystar.py 1970-01-01 00:00:00 +0000
+++ examples/sph/toystar.py 2014-04-10 06:21:57 +0000
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# This script demonstrates SPH-engine in Yade
+# !!! Very experimental at the moment!!!
+
+from yade import utils, plot, qt
+o = Omega()
+
+# Physical parameters
+fr = 0.5;
+rho=1000.0
+
+k = 1.0
+mu = 0.01
+tc = 0.0001; en = 0.7; et = 0.7;
+Rad = 10.0e-3
+o.dt = 0.00001
+
+# Add material
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et))
+
+# Add spheres
+d = 0.8
+idSpheres = O.bodies.append(
+ pack.regularHexa(
+ pack.inSphere(
+ (0,0,0), d),
+ radius=Rad,gap=10.5*Rad, material=mat1, mask=1, color=(0,1,1)))
+
+idCentralBody = O.bodies.append(sphere(center=[0,0,0],radius=0.1*Rad, mask = 2, color = [1,0,0], fixed=True))
+
+
+# Add engines
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb(label='is2aabb'),Bo1_Facet_Aabb(label='is3aabb')]),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom(label='ss2sc'),Ig2_Facet_Sphere_ScGeom()],
+ [Ip2_ViscElMat_ViscElMat_ViscElPhys()],
+ [Law2_ScGeom_ViscElPhys_Basic()],
+ ),
+ CentralGravityEngine(accel=50.0, label='gr', centralBody=idCentralBody),
+ NewtonIntegrator(damping=0.1),
+ SPHEngine(mask=1, k=k, rho0 = rho),
+ VTKRecorder(iterPeriod=1000, mask=1, fileName='./cpt/spheres-', recorders=['spheres','velocity','colors','intr','ids','mask','materialId','stress']),
+]
+
+
+O.step()
+qt.View()
=== added file 'examples/sph/watercolumn.py'
--- examples/sph/watercolumn.py 1970-01-01 00:00:00 +0000
+++ examples/sph/watercolumn.py 2014-04-09 14:03:16 +0000
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+from yade import utils, plot, qt, ymport
+o = Omega()
+
+# Physical parameters
+fr = 0.0;
+rho=1000.0
+
+k = 5.0
+mu = 0.001
+tc = 0.0001; en = 0.7; et = 0.7;
+vel = 0.05
+Rad = 15.0e-3
+o.dt = 0.0002
+
+
+scaleF = 0.001
+
+# Add material
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho, SPHmode=True,mu=mu,tc=tc, en=en, et=et))
+id1 = O.bodies.append(ymport.gmsh("box.mesh", scale=scaleF, material=mat1, color=(1,0,0), mask = 1, wire=True))
+
+d = 15.0*scaleF
+
+print d
+idSpheres = O.bodies.append(
+ pack.regularHexa(
+ pack.inAlignedBox(
+ (0, -2000.0*scaleF, 0.0),
+ (1000*scaleF, 200*scaleF, 50.0*scaleF)),
+ radius=d,gap=0.01*d, material=mat1, mask=1, color=(0,1,1)))
+
+
+print len(idSpheres)
+
+# Add engines
+o.engines = [
+ ForceResetter(),
+ InsertionSortCollider([Bo1_Sphere_Aabb(label='is2aabb'),Bo1_Facet_Aabb(label='is3aabb')]),
+ InteractionLoop(
+ [Ig2_Sphere_Sphere_ScGeom(label='ss2sc'),Ig2_Facet_Sphere_ScGeom()],
+ [Ip2_ViscElMat_ViscElMat_ViscElPhys()],
+ [Law2_ScGeom_ViscElPhys_Basic()],
+ ),
+ NewtonIntegrator(damping=0.05,gravity=[0,-9.81,0]),
+ SPHEngine(mask=1, k=k, rho0 = rho),
+ VTKRecorder(iterPeriod=100,fileName='./cpt/spheres-', recorders=['spheres','velocity','colors','intr','ids','mask','materialId','stress']),
+ VTKRecorder(iterPeriod=100,fileName='./cpt/facet-', recorders=['facets'],label='VTK_box2'),
+ PyRunner(command='addPlotData()',iterPeriod=50,dead=False),
+]
+
+def addPlotData():
+ plot.addData(t=O.time, Ekin=utils.kineticEnergy())
+
+plot.plots={'t':('Ekin')}; plot.plot()
+
+O.run(1, True)
+
+qt.View()
+#O.run(10000, True)
+#plot.saveGnuplot('sim-data_0.05')
=== modified file 'examples/tesselationwrapper/tesselationWrapper.py'
--- examples/tesselationwrapper/tesselationWrapper.py 2013-08-19 17:51:24 +0000
+++ examples/tesselationwrapper/tesselationWrapper.py 2014-04-01 13:18:38 +0000
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#2012 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
"""Example usage of a TesselationWrapper object for getting microscale quantities."""
-# See Catalano2013a for the definition of micro-strain
+# See Catalano2014a for the definition of micro-strain
# (http://dx.doi.org/10.1002/nag.2198 or free-access at arxiv http://arxiv.org/pdf/1304.4895.pdf)
tt=TriaxialTest()
=== modified file 'examples/test/facet-sphere-ViscElBasic-peri.py'
--- examples/test/facet-sphere-ViscElBasic-peri.py 2013-03-28 11:13:12 +0000
+++ examples/test/facet-sphere-ViscElBasic-peri.py 2014-04-02 15:33:41 +0000
@@ -11,12 +11,11 @@
es=0.3 # tangential restitution coefficient
density=2700
frictionAngle=radians(35)#
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params))
-sphereMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
+sphereMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
#floor
-n=5.
+n=5
s=1./n
for i in range(0,n):
for j in range(0,n):
=== modified file 'examples/test/facet-sphere-ViscElBasic.py'
--- examples/test/facet-sphere-ViscElBasic.py 2013-03-28 11:13:12 +0000
+++ examples/test/facet-sphere-ViscElBasic.py 2014-04-02 15:33:41 +0000
@@ -11,9 +11,8 @@
es = 0.3
## Import wall's geometry
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,**params))
-sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,**params))
+facetMat=O.materials.append(ViscElMat(frictionAngle=frictionAngle,tc=tc,en=en,et=es))
+sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
facetId=O.bodies.append(facet( [ (-1,0,0), (1,1,0), (1,-1,0)], material=facetMat,color=(1,0,0)))
=== modified file 'examples/test/performance/checkPerf.py'
--- examples/test/performance/checkPerf.py 2013-03-28 11:16:16 +0000
+++ examples/test/performance/checkPerf.py 2014-04-02 15:33:41 +0000
@@ -44,8 +44,7 @@
frictionAngle=radians(35)
density=2300
- params=getViscoelasticFromSpheresInteraction(tc,en,es)
- defMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
+ defMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
O.dt=.1*tc # time step
rad=0.5 # particle radius
=== modified file 'examples/test/periodic-simple-shear.py'
--- examples/test/periodic-simple-shear.py 2014-01-23 18:08:34 +0000
+++ examples/test/periodic-simple-shear.py 2014-04-03 13:30:10 +0000
@@ -29,29 +29,29 @@
def triaxDone():
global phase
if phase==0:
- print 'Here we are: stress',triax['stress'],'strain',triax['strain'],'stiffness',triax['stiff']
+ print 'Here we are: stress',triax.stress,'strain',triax.strain,'stiffness',triax.stiff
print 'Now shearing.'
- O.cell.velGrad[1,2]=6.0
+ O.cell.velGrad=Matrix3(0,6,0, 0,0,0, 0,0,0)
triax.stressMask=7
- triax['goal']=[-1e4,-1e4,-1e4]
+ triax.goal=[-1e4,-1e4,-1e4]
phase+=1
- elif phase==1:
- print 'Here we are: stress',triax['stress'],'strain',triax['strain'],'stiffness',triax['stiff']
- #print 'Done, pausing now.'
- #O.pause()
+ O.pause()
+ #elif phase==1:
+ #print 'Here we are: stress',triax.stress,'strain',triax.strain,'stiffness',triax.stiff
+ #phase+=1
+ ##print 'Done, pausing now.'
+ ##O.pause()
O.dt=PWaveTimeStep()
-O.run(7000);
-qt.View()
-#r=qt.Renderer()
-#r.bgColor=1,1,1
-O.wait()
-
-O.cell.velGrad[1,2]=0
-O.cell.velGrad[2,1]=-6
-O.run(5000);
-O.wait()
-
-O.cell.velGrad[1,2]=6
-O.cell.velGrad[2,1]=0
-O.run(5000);
+#O.run(7000);
+#qt.View()
+##r=qt.Renderer()
+##r.bgColor=1,1,1
+#O.wait()
+#O.saveTmp()
+#O.cell.velGrad=Matrix3(0,0,0, -6,0,0, 0,0,0)
+#O.run(5000);
+#O.wait()
+
+#O.cell.velGrad=Matrix3(0,6,0, 0,0,0, 0,0,0)
+#O.run(5000);
=== modified file 'examples/test/sphere-sphere-ViscElBasic-peri.py'
--- examples/test/sphere-sphere-ViscElBasic-peri.py 2013-03-28 11:13:12 +0000
+++ examples/test/sphere-sphere-ViscElBasic-peri.py 2014-04-02 15:33:41 +0000
@@ -11,8 +11,7 @@
es=1 # tangential restitution coefficient
density=2700
frictionAngle=radians(35)#
-params=getViscoelasticFromSpheresInteraction(tc,en,es)
-sphereMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params))
+sphereMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
# Spheres
=== modified file 'examples/test/vtk-exporter/vtkExporter.py'
--- examples/test/vtk-exporter/vtkExporter.py 2014-01-28 13:33:10 +0000
+++ examples/test/vtk-exporter/vtkExporter.py 2014-04-10 17:41:16 +0000
@@ -1,32 +1,33 @@
from yade import export,polyhedra_utils
+
mat = PolyhedraMat()
-O.bodies.append([
- sphere((0,0,0),1),
- sphere((0,3,0),1),
- sphere((0,2,4),2),
- sphere((0,5,2),1.5),
- facet([Vector3(0,-3,-1),Vector3(0,-2,5),Vector3(5,4,0)]),
- facet([Vector3(0,-3,-1),Vector3(0,-2,5),Vector3(-5,4,0)]),
+O.bodies.append((
polyhedra_utils.polyhedra(mat,(1,2,3),0),
polyhedra_utils.polyhedralBall(2,20,mat,(-2,-2,4)),
-])
+))
O.bodies[-1].state.pos = (-2,-2,-2)
O.bodies[-1].state.ori = Quaternion((1,1,2),1)
O.bodies[-2].state.pos = (-2,-2,3)
O.bodies[-2].state.ori = Quaternion((1,2,0),1)
-createInteraction(0,1)
-createInteraction(0,2)
-createInteraction(0,3)
-createInteraction(1,2)
-createInteraction(1,3)
-createInteraction(2,3)
-
O.step()
-vtkExporter = export.VTKExporter('vtkExporterTesting')
+O.bodies.append((
+ sphere((0,0,0),1),
+ sphere((0,3,0),1),
+ sphere((0,2,4),2),
+ sphere((0,5,2),1.5),
+ facet([Vector3(0,-3,-1),Vector3(0,-2,5),Vector3(5,4,0)]),
+ facet([Vector3(0,-3,-1),Vector3(0,-2,5),Vector3(-5,4,0)]),
+))
+
+for i,j in ((0,1),(0,2),(0,3),(1,2),(1,3),(2,3)):
+ createInteraction(i+2,j+2)
+
+vtkExporter = export.VTKExporter('/tmp/vtkExporterTesting')
vtkExporter.exportSpheres(what=[('dist','b.state.pos.norm()')])
vtkExporter.exportFacets(what=[('pos','b.state.pos')])
vtkExporter.exportInteractions(what=[('kn','i.phys.kn')])
+vtkExporter.exportContactPoints(what=[('nn','i.geom.normal')])
vtkExporter.exportPolyhedra(what=[('n','b.id')])
=== modified file 'gui/qt4/GLViewer.cpp'
--- gui/qt4/GLViewer.cpp 2014-02-16 14:03:41 +0000
+++ gui/qt4/GLViewer.cpp 2014-05-06 14:24:07 +0000
@@ -25,8 +25,6 @@
#include<boost/algorithm/string/case_conv.hpp>
#include<yade/lib/serialization/ObjectIO.hpp>
#include<yade/lib/pyutil/gil.hpp>
-
-
#include<QtGui/qevent.h>
using namespace boost;
@@ -76,10 +74,9 @@
if(manipulatedFrame()==0) setManipulatedFrame(new qglviewer::ManipulatedFrame());
xyPlaneConstraint=shared_ptr<qglviewer::LocalConstraint>(new qglviewer::LocalConstraint());
- //xyPlaneConstraint->setTranslationConstraint(qglviewer::AxisPlaneConstraint::AXIS,qglviewer::Vec(0,0,1));
- //xyPlaneConstraint->setRotationConstraint(qglviewer::AxisPlaneConstraint::FORBIDDEN,qglviewer::Vec(0,0,1));
manipulatedFrame()->setConstraint(NULL);
+ setKeyDescription(Qt::Key_Return,"Run simulation.");
setKeyDescription(Qt::Key_A,"Toggle visibility of global axes.");
setKeyDescription(Qt::Key_C,"Set scene center so that all bodies are visible; if a body is selected, center around this body.");
setKeyDescription(Qt::Key_C & Qt::AltModifier,"Set scene center to median body position (same as space)");
@@ -97,12 +94,6 @@
setKeyDescription(Qt::Key_P,"Set wider field of view");
setKeyDescription(Qt::Key_R,"Revolve around scene center");
setKeyDescription(Qt::Key_V,"Save PDF of the current view to /tmp/yade-snapshot-0001.pdf (whichever number is available first). (Must be compiled with the gl2ps feature.)");
-#if 0
- setKeyDescription(Qt::Key_Plus, "Cut plane increase");
- setKeyDescription(Qt::Key_Minus, "Cut plane decrease");
- setKeyDescription(Qt::Key_Slash, "Cut plane step decrease");
- setKeyDescription(Qt::Key_Asterisk,"Cut plane step increase");
-#endif
setPathKey(-Qt::Key_F1);
setPathKey(-Qt::Key_F2);
setKeyDescription(Qt::Key_Escape,"Manipulate scene (default)");
@@ -122,9 +113,6 @@
setKeyDescription(Qt::Key_Space,"Center scene (same as Alt-C); clip plane: activate/deactivate");
centerScene();
-
- //connect(&GLGlobals::redrawTimer,SIGNAL(timeout()),this,SLOT(updateGL()));
-
}
bool GLViewer::isManipulating(){
@@ -273,6 +261,11 @@
}
}
else if(e->key()==Qt::Key_Period) gridSubdivide = !gridSubdivide;
+ else if(e->key()==Qt::Key_Return){
+ if (Omega::instance().isRunning()) Omega::instance().pause();
+ else Omega::instance().run();
+ LOG_INFO("Running...");
+ }
#ifdef YADE_GL2PS
else if(e->key()==Qt::Key_V){
for(int i=0; ;i++){
=== modified file 'gui/qt4/GLViewer.hpp'
--- gui/qt4/GLViewer.hpp 2014-02-16 14:03:41 +0000
+++ gui/qt4/GLViewer.hpp 2014-03-08 21:19:02 +0000
@@ -10,6 +10,7 @@
#endif
#include<QGLViewer/qglviewer.h>
+#include<QGLViewer/manipulatedFrame.h>
#include<QGLViewer/constraint.h>
#include<set>
=== modified file 'gui/qt4/GLViewerMouse.cpp'
--- gui/qt4/GLViewerMouse.cpp 2014-01-06 13:57:32 +0000
+++ gui/qt4/GLViewerMouse.cpp 2014-05-06 16:53:02 +0000
@@ -25,7 +25,7 @@
#include<boost/algorithm/string/case_conv.hpp>
#include<yade/lib/serialization/ObjectIO.hpp>
#include<yade/lib/pyutil/gil.hpp>
-
+#include<QGLViewer/manipulatedCameraFrame.h>
#include<QtGui/qevent.h>
@@ -36,15 +36,14 @@
#endif
void GLViewer::mouseMovesCamera(){
- camera()->frame()->setWheelSensitivity(-1.0f);
-
setWheelBinding(Qt::ShiftModifier , FRAME, ZOOM);
setWheelBinding(Qt::NoModifier, CAMERA, ZOOM);
#if QGLVIEWER_VERSION>=0x020500
setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, SELECT);
- setMouseBinding(Qt::ShiftModifier, Qt::LeftButton | Qt::RightButton, FRAME, ZOOM);
+ setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, FRAME, ZOOM);
+ setMouseBinding(Qt::ShiftModifier, Qt::RightButton, FRAME, ZOOM);
setMouseBinding(Qt::ShiftModifier, Qt::MidButton, FRAME, TRANSLATE);
setMouseBinding(Qt::ShiftModifier, Qt::RightButton, FRAME, ROTATE);
@@ -54,7 +53,6 @@
setMouseBinding(Qt::NoModifier, Qt::RightButton, CAMERA, TRANSLATE);
#else
setMouseBinding(Qt::SHIFT + Qt::LeftButton, SELECT);
-
setMouseBinding(Qt::SHIFT + Qt::LeftButton + Qt::RightButton, FRAME, ZOOM);
setMouseBinding(Qt::SHIFT + Qt::MidButton, FRAME, TRANSLATE);
setMouseBinding(Qt::SHIFT + Qt::RightButton, FRAME, ROTATE);
@@ -63,6 +61,7 @@
setMouseBinding(Qt::MidButton, CAMERA, ZOOM);
setMouseBinding(Qt::LeftButton, CAMERA, ROTATE);
setMouseBinding(Qt::RightButton, CAMERA, TRANSLATE);
+ camera()->frame()->setWheelSensitivity(-1.0f);
#endif
};
@@ -102,7 +101,6 @@
#endif
switch (event->button()){
case Qt::LeftButton: manipulatedFrame()->alignWithFrame(NULL,true); LOG_DEBUG("Aligning cutting plane"); break;
- // case Qt::RightButton: projectOnLine(camera->position(), camera->viewDirection()); break;
default: break; // avoid warning
}
}
@@ -113,8 +111,6 @@
if(manipulatedClipPlane<0){ QGLViewer::wheelEvent(event); return; }
assert(manipulatedClipPlane<renderer->numClipPlanes);
float distStep=1e-3*sceneRadius();
- //const float wheelSensitivityCoef = 8E-4f;
- //Vec trans(0.0, 0.0, -event->delta()*wheelSensitivity()*wheelSensitivityCoef*(camera->position()-position()).norm());
float dist=event->delta()*manipulatedFrame()->wheelSensitivity()*distStep;
Vector3r normal=renderer->clipPlaneSe3[manipulatedClipPlane].orientation*Vector3r(0,0,1);
qglviewer::Vec newPos=manipulatedFrame()->position()+qglviewer::Vec(normal[0],normal[1],normal[2])*dist;
=== modified file 'lib/base/Logging.hpp'
--- lib/base/Logging.hpp 2012-04-13 16:27:00 +0000
+++ lib/base/Logging.hpp 2014-02-28 11:14:59 +0000
@@ -16,9 +16,18 @@
# define _POOR_MANS_LOG(level,msg) {std::cerr<<level " "<<_LOG_HEAD<<msg<<std::endl;}
# define _LOG_HEAD __FILE__ ":"<<__LINE__<<" "<<__FUNCTION__<<": "
-# define LOG_TRACE(msg) // _POOR_MANS_LOG("TRACE",msg)
-# define LOG_DEBUG(msg) // _POOR_MANS_LOG("DEBUG",msg)
-# define LOG_INFO(msg) // _POOR_MANS_LOG("INFO ",msg)
+
+#ifdef YADE_DEBUG
+ # define LOG_TRACE(msg) _POOR_MANS_LOG("TRACE",msg)
+ # define LOG_INFO(msg) _POOR_MANS_LOG("INFO ",msg)
+ # define LOG_DEBUG(msg) _POOR_MANS_LOG("DEBUG",msg)
+#else
+ # define LOG_TRACE(msg) // _POOR_MANS_LOG("TRACE",msg)
+ # define LOG_INFO(msg) // _POOR_MANS_LOG("INFO ",msg)
+ # define LOG_DEBUG(msg) // _POOR_MANS_LOG("DEBUG",msg)
+#endif
+
+
# define LOG_WARN(msg) _POOR_MANS_LOG("WARN ",msg)
# define LOG_ERROR(msg) _POOR_MANS_LOG("ERROR",msg)
# define LOG_FATAL(msg) _POOR_MANS_LOG("FATAL",msg)
=== modified file 'lib/base/openmp-accu.hpp'
--- lib/base/openmp-accu.hpp 2013-03-28 19:18:22 +0000
+++ lib/base/openmp-accu.hpp 2014-05-08 08:11:40 +0000
@@ -2,20 +2,20 @@
#pragma once
// for ZeroInitializer template
-#include<yade/lib/base/Math.hpp>
+#include <yade/lib/base/Math.hpp>
-#include<boost/serialization/split_free.hpp>
-#include<boost/lexical_cast.hpp>
-#include<string>
-#include<vector>
-#include<cstdlib>
-#include<unistd.h>
-#include<stdexcept>
-#include<iostream>
+#include <boost/serialization/split_free.hpp>
+#include <boost/lexical_cast.hpp>
+#include <string>
+#include <vector>
+#include <cstdlib>
+#include <unistd.h>
+#include <stdexcept>
+#include <iostream>
#ifdef YADE_OPENMP
-#include"omp.h"
+#include "omp.h"
// O(1) access container which stores data in contiguous chunks of memory
// each chunk belonging to one thread
@@ -101,6 +101,7 @@
~OpenMPAccumulator() { free((void*)data); }
// lock-free addition
void operator+=(const T& val){ *((T*)(data+omp_get_thread_num()*eSize))+=val; }
+ void operator-=(const T& val){ *((T*)(data+omp_get_thread_num()*eSize))-=val; }
// return summary value; must not be used concurrently
operator T() const { return get(); }
// reset to zeroValue; must NOT be used concurrently
@@ -112,6 +113,57 @@
// only useful for debugging
std::vector<T> getPerThreadData() const { std::vector<T> ret; for(int i=0; i<nThreads; i++) ret.push_back(*(T*)(data+i*eSize)); return ret; }
};
+
+/* OpenMP implementation of std::vector.
+ * Very minimal functionality, which is required by Yade
+ */
+template<typename T>
+class OpenMPVector{
+ std::vector<std::vector<T> > vals;
+ size_t sizeV;
+ public:
+ OpenMPVector() {sizeV = omp_get_max_threads(); vals.resize(sizeV);};
+ void push_back (const T& val) {vals[omp_get_thread_num()].push_back(val);};
+ size_t size() const {
+ size_t sumSize = 0;
+ for (size_t i=0; i<sizeV; i++) {
+ sumSize += vals[i].size();
+ }
+ return sumSize;
+ }
+
+ size_t size(size_t t) const {
+ if (t >= sizeV) {
+ std::cerr<< ("Index is out of range.")<<std::endl; exit (EXIT_FAILURE);
+ } else {
+ return vals[t].size();
+ }
+ }
+
+ size_t sizeT() {
+ return sizeV;
+ }
+
+ T operator[](size_t ix) const {
+ if (ix >= size()) {
+ std::cerr<< ("Index is out of range.")<<std::endl; exit (EXIT_FAILURE);
+ } else {
+ size_t t = 0;
+ while (ix >= vals[t].size()) {
+ ix-=vals[t].size();
+ t+=1;
+ }
+ return vals[t][ix];
+ }
+ }
+
+ void clear() {
+ for (size_t i=0; i<sizeV; i++) {
+ vals[i].clear();
+ }
+ }
+
+};
#else
template<typename T>
class OpenMPArrayAccumulator{
@@ -136,6 +188,7 @@
T data;
public:
void operator+=(const T& val){ data+=val; }
+ void operator-=(const T& val){ data-=val; }
operator T() const { return get(); }
void reset(){ data=ZeroInitializer<T>(); }
T get() const { return data; }
@@ -143,6 +196,8 @@
// debugging only
std::vector<T> getPerThreadData() const { std::vector<T> ret; ret.push_back(data); return ret; }
};
+
+template <typename T> using OpenMPVector=std::vector <T>;
#endif
// boost serialization
=== modified file 'lib/serialization/Serializable.hpp'
--- lib/serialization/Serializable.hpp 2011-02-27 13:54:43 +0000
+++ lib/serialization/Serializable.hpp 2014-04-01 13:18:38 +0000
@@ -212,8 +212,14 @@
boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable> _classObj(#thisClass,docString "\n\n" BOOST_PP_SEQ_FOR_EACH(_STATATTR_MAKE_DOC,thisClass,attrs) ); _classObj.def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<thisClass>)); \
BOOST_PP_SEQ_FOR_EACH(_STATATTR_PY,thisClass,attrs); \
}
-
-
+
+#define _YADE_CLASS_PYCLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,pyClassName,baseClass,docString,attrs,deprec,extras) \
+ _REGISTER_ATTRIBUTES_DEPREC(thisClass,baseClass,attrs,deprec) \
+ REGISTER_CLASS_AND_BASE(pyClassName,baseClass) \
+ /* accessors for deprecated attributes, with warnings */ BOOST_PP_SEQ_FOR_EACH(_ACCESS_DEPREC,thisClass,deprec) \
+ /* python class registration */ virtual void pyRegisterClass(python::object _scope) { checkPyClassRegistersItself(#pyClassName); boost::python::scope thisScope(_scope); YADE_SET_DOCSTRING_OPTS; boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable> _classObj(#pyClassName,docString); _classObj.def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<thisClass>)); BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEF,thisClass,attrs); (void) _classObj BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEPREC_DEF,thisClass,deprec); (void) _classObj extras ; }
+
+
/********************** USER MACROS START HERE ********************/
// attrs is (type,name,init-value,docstring)
@@ -229,6 +235,12 @@
thisClass() BOOST_PP_IF(BOOST_PP_SEQ_SIZE(inits attrDecls),:,) BOOST_PP_SEQ_FOR_EACH_I(_ATTR_MAKE_INITIALIZER,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(inits attrDecls)), inits BOOST_PP_SEQ_FOR_EACH(_ATTR_MAKE_INIT_TUPLE,~,attrDecls)) { ctor ; } /* ctor, with initialization of defaults */ \
_YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,BOOST_PP_SEQ_FOR_EACH(_ATTRS_EMBED_INI_TYP_IN_DOC,~,attrDecls),deprec,extras)
+// this one lets you give different class names in c++ and python, necessary for compatibility with c++ templates (else all instaces would have the same class name (ex. in FlowEngine.hpp)
+#define YADE_CLASS_PYCLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(thisClass,pyClassName,baseClass,docString,attrDecls,deprec,inits,ctor,extras) \
+ public: BOOST_PP_SEQ_FOR_EACH(_ATTR_DECL,~,attrDecls) /* attribute declarations */ \
+ thisClass() BOOST_PP_IF(BOOST_PP_SEQ_SIZE(inits attrDecls),:,) BOOST_PP_SEQ_FOR_EACH_I(_ATTR_MAKE_INITIALIZER,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(inits attrDecls)), inits BOOST_PP_SEQ_FOR_EACH(_ATTR_MAKE_INIT_TUPLE,~,attrDecls)) { ctor ; } /* ctor, with initialization of defaults */ \
+ _YADE_CLASS_PYCLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,pyClassName,baseClass,docString,BOOST_PP_SEQ_FOR_EACH(_ATTRS_EMBED_INI_TYP_IN_DOC,~,attrDecls),deprec,extras)
+
// see https://bugs.launchpad.net/yade/+bug/666876
// we have to change things at a few other places as well
#if BOOST_VERSION>=104200
=== modified file 'lib/triangulation/FlowBoundingSphere.hpp'
--- lib/triangulation/FlowBoundingSphere.hpp 2014-02-17 18:00:12 +0000
+++ lib/triangulation/FlowBoundingSphere.hpp 2014-04-24 21:37:44 +0000
@@ -29,19 +29,18 @@
DECLARE_TESSELATION_TYPES(Network<Tesselation>)
//painfull, but we need that for templates inheritance...
- using _N::T; using _N::x_min; using _N::x_max; using _N::y_min; using _N::y_max; using _N::z_min; using _N::z_max; using _N::Rmoy; using _N::SectionArea; using _N::Height; using _N::Vtotale; using _N::currentTes; using _N::DEBUG_OUT; using _N::nOfSpheres; using _N::x_min_id; using _N::x_max_id; using _N::y_min_id; using _N::y_max_id; using _N::z_min_id; using _N::z_max_id; using _N::boundsIds; using _N::Corner_min; using _N::Corner_max; using _N::Vsolid_tot; using _N::Vtotalissimo; using _N::Vporale; using _N::Ssolid_tot; using _N::V_porale_porosity; using _N::V_totale_porosity; using _N::boundaries; using _N::id_offset; using _N::vtk_infinite_vertices; using _N::vtk_infinite_cells; using _N::num_particles; using _N::boundingCells; using _N::facetVertices; using _N::facetNFictious;
+ using _N::T; using _N::xMin; using _N::xMax; using _N::yMin; using _N::yMax; using _N::zMin; using _N::zMax; using _N::Rmoy; using _N::sectionArea; using _N::Height; using _N::vTotal; using _N::currentTes; using _N::debugOut; using _N::nOfSpheres; using _N::xMinId; using _N::xMaxId; using _N::yMinId; using _N::yMaxId; using _N::zMinId; using _N::zMaxId; using _N::boundsIds; using _N::cornerMin; using _N::cornerMax; using _N::VSolidTot; using _N::Vtotalissimo; using _N::vPoral; using _N::sSolidTot; using _N::vPoralPorosity; using _N::vTotalPorosity; using _N::boundaries; using _N::idOffset; using _N::vtkInfiniteVertices; using _N::vtkInfiniteCells; using _N::num_particles; using _N::boundingCells; using _N::facetVertices; using _N::facetNFictious;
//same for functions
- using _N::Define_fictious_cells; using _N::AddBoundingPlanes; using _N::boundary;
+ using _N::defineFictiousCells; using _N::addBoundingPlanes; using _N::boundary;
virtual ~FlowBoundingSphere();
FlowBoundingSphere();
- bool SLIP_ON_LATERALS;
-// bool areaR2Permeability;
- double TOLERANCE;
- double RELAX;
+ bool slipBoundary;
+ double tolerance;
+ double relax;
double ks; //Hydraulic Conductivity
- bool clampKValues, meanKStat, distance_correction;
+ bool clampKValues, meanKStat, distanceCorrection;
bool OUTPUT_BOUDARIES_RADII;
bool noCache;//flag for checking if cached values cell->unitForceVectors have been defined
bool computedOnce;//flag for checking if current triangulation has been computed at least once
@@ -50,36 +49,39 @@
//Handling imposed pressures/fluxes on elements in the form of {point,value} pairs, IPCells contains the cell handles corresponding to point
vector<pair<Point,Real> > imposedP;
- vector<Cell_handle> IPCells;
+ vector<CellHandle> IPCells;
vector<pair<Point,Real> > imposedF;
- vector<Cell_handle> IFCells;
+ vector<CellHandle> IFCells;
+ //Pointers to vectors used for user defined boundary pressure
+ vector<Real> *pxpos, *ppval;
void initNewTri () {noCache=true; /*isLinearSystemSet=false; areCellsOrdered=false;*/}//set flags after retriangulation
- bool permeability_map;
+ bool permeabilityMap;
bool computeAllCells;//exececute computeHydraulicRadius for all facets and all spheres (double cpu time but needed for now in order to define crossSections correctly)
- double K_opt_factor;
+ double KOptFactor;
double minKdivKmean;
double maxKdivKmean;
int Iterations;
- bool RAVERAGE;
+ bool rAverage;
int walls_id[6];
-// #define parallel_forces
+ #define parallel_forces
#ifdef parallel_forces
int ompThreads;
- vector< vector<const Vecteur*> > perVertexUnitForce;
+ vector< vector<const CVector*> > perVertexUnitForce;
vector< vector<const Real*> > perVertexPressure;
#endif
- vector <Finite_edges_iterator> Edge_list;
- vector <double> Edge_Surfaces;
- vector <pair<int,int> > Edge_ids;
+ vector <double> edgeSurfaces;
+ vector <pair<const VertexInfo*,const VertexInfo*> > edgeIds;
vector <Real> edgeNormalLubF;
- vector <Vector3r> viscousShearForces;
- vector <Vector3r> viscousShearTorques;
- vector <Vector3r> normLubForce;
- vector <Matrix3r> viscousBodyStress;
- vector <Matrix3r> lubBodyStress;
+ vector <Vector3r> shearLubricationForces;
+ vector <Vector3r> shearLubricationTorques;
+ vector <Vector3r> pumpLubricationTorques;
+ vector <Vector3r> twistLubricationTorques;
+ vector <Vector3r> normalLubricationForce;
+ vector <Matrix3r> shearLubricationBodyStress;
+ vector <Matrix3r> normalLubricationBodyStress;
vector <Vector3r> deltaNormVel;
vector <Vector3r> deltaShearVel;
vector <Vector3r> normalV;
@@ -89,87 +91,84 @@
vector <Matrix3r> normalStressInteraction;
void Localize();
- void Compute_Permeability();
- virtual void GaussSeidel (Real dt=0);
- virtual void ResetNetwork();
-
- void Fictious_cells ( );
-
- double k_factor; //permeability moltiplicator
+ void computePermeability();
+ virtual void gaussSeidel (Real dt=0);
+ virtual void resetNetwork();
+
+
+ double kFactor; //permeability moltiplicator
std::string key; //to give to consolidation files a name with iteration number
- std::vector<double> Pressures; //for automatic write maximum pressures during consolidation
- bool tess_based_force; //allow the force computation method to be chosen from FlowEngine
+// std::vector<double> pressures; //for automatic write maximum pressures during consolidation
+ bool tessBasedForce; //allow the force computation method to be chosen from FlowEngine
Real minPermLength; //min branch length for Poiseuille
- double P_SUP, P_INF, P_INS, VISCOSITY;
+ double viscosity;
double fluidBulkModulus;
- Tesselation& Compute_Action ( );
- Tesselation& Compute_Action ( int argc, char *argv[ ], char *envp[ ] );
- Tesselation& LoadPositions(int argc, char *argv[ ], char *envp[ ]);
- void SpheresFileCreator ();
- void DisplayStatistics();
- void Initialize_pressures ( double P_zero );
+ void displayStatistics();
+ void initializePressure ( double pZero );
bool reApplyBoundaryConditions ();
- /// Define forces using the same averaging volumes as for permeability
- void ComputeTetrahedralForces();
- /// Define forces spliting drag and buoyancy terms
- void ComputeFacetForcesWithCache(bool onlyCache=false);
+ void computeFacetForcesWithCache(bool onlyCache=false);
void saveVtk (const char* folder);
#ifdef XVIEW
- void Dessine_Triangulation ( Vue3D &Vue, RTriangulation &T );
- void Dessine_Short_Tesselation ( Vue3D &Vue, Tesselation &Tes );
+ void dessineTriangulation ( Vue3D &Vue, RTriangulation &T );
+ void dessineShortTesselation ( Vue3D &Vue, Tesselation &Tes );
#endif
- double Permeameter ( double P_Inf, double P_Sup, double Section, double DeltaY, const char *file );
- double Sample_Permeability( double& x_Min,double& x_Max ,double& y_Min,double& y_Max,double& z_Min,double& z_Max);
- double Compute_HydraulicRadius (Cell_handle cell, int j );
+ double permeameter ( double PInf, double PSup, double Section, double DeltaY, const char *file );
+ double samplePermeability( double& xMin,double& xMax ,double& yMin,double& yMax,double& zMin,double& zMax);
+ double computeHydraulicRadius (CellHandle cell, int j );
Real checkSphereFacetOverlap(const Sphere& v0, const Sphere& v1, const Sphere& v2);
- double dotProduct ( Vecteur x, Vecteur y );
- double Compute_EffectiveRadius(Cell_handle cell, int j);
- double Compute_EquivalentRadius(Cell_handle cell, int j);
+ double dotProduct ( CVector x, CVector y );
+ double computeEffectiveRadius(CellHandle cell, int j);
+ double computeEquivalentRadius(CellHandle cell, int j);
//return the list of constriction values
vector<double> getConstrictions();
vector<Constriction> getConstrictionsFull();
- void GenerateVoxelFile ( );
+ void generateVoxelFile ( );
void computeEdgesSurfaces();
Vector3r computeViscousShearForce(const Vector3r& deltaV, const int& edge_id, const Real& Rh);
Real computeNormalLubricationForce(const Real& deltaNormV, const Real& dist, const int& edge_id, const Real& eps, const Real& stiffness, const Real& dt, const Real& meanRad);
Vector3r computeShearLubricationForce(const Vector3r& deltaShearV, const Real& dist, const int& edge_id, const Real& eps, const Real& centerDist, const Real& meanRad);
-
- RTriangulation& Build_Triangulation ( Real x, Real y, Real z, Real radius, unsigned const id );
+ Vector3r computePumpTorque(const Vector3r& deltaShearAngV, const Real& dist, const int& edge_id, const Real& eps, const Real& meanRad );
+ Vector3r computeTwistTorque(const Vector3r& deltaNormAngV, const Real& dist, const int& edge_id, const Real& eps, const Real& meanRad );
+
+
+
+ RTriangulation& buildTriangulation ( Real x, Real y, Real z, Real radius, unsigned const id );
bool isInsideSphere ( double& x, double& y, double& z );
- void SliceField (const char *filename);
- void ComsolField();
+ void sliceField (const char *filename);
+ void comsolField();
- void Interpolate ( Tesselation& Tes, Tesselation& NewTes );
- virtual void Average_Relative_Cell_Velocity();
- void Average_Fluid_Velocity();
- void ApplySinusoidalPressure(RTriangulation& Tri, double Amplitude, double Average_Pressure, double load_intervals);
+ void interpolate ( Tesselation& Tes, Tesselation& NewTes );
+ virtual void averageRelativeCellVelocity();
+ void averageFluidVelocity();
+ void applySinusoidalPressure(RTriangulation& Tri, double amplitude, double averagePressure, double loadIntervals);
+ void applyUserDefinedPressure(RTriangulation& Tri, vector<Real>& xpos, vector<Real>& pval);
bool isOnSolid (double X, double Y, double Z);
double getPorePressure (double X, double Y, double Z);
- void measurePressureProfile(double Wall_up_y, double Wall_down_y);
+ void measurePressureProfile(double WallUpy, double WallDowny);
double averageSlicePressure(double Y);
double averagePressure();
double getCell (double X,double Y,double Z);
double boundaryFlux(unsigned int boundaryId);
- vector<Real> Average_Fluid_Velocity_On_Sphere(unsigned int Id_sph);
+ vector<Real> averageFluidVelocityOnSphere(unsigned int Id_sph);
//Solver?
- int useSolver;//(0 : GaussSeidel, 1 : TAUCS, 2 : PARDISO, 3:CHOLMOD)
+ int useSolver;//(0 : GaussSeidel, 1:CHOLMOD)
};
} //namespace CGT
-
+#include <yade/lib/triangulation/FlowBoundingSphere.ipp>
#ifdef LINSOLV
#include "yade/lib/triangulation/FlowBoundingSphereLinSolv.hpp"
#endif
/// _____ Template Implementation ____
-#include "yade/lib/triangulation/FlowBoundingSphere.ipp"
+// #include "yade/lib/triangulation/FlowBoundingSphereLinSolv.ipp"
#endif //FLOW_ENGINE
=== modified file 'lib/triangulation/FlowBoundingSphere.ipp'
--- lib/triangulation/FlowBoundingSphere.ipp 2014-02-28 15:52:38 +0000
+++ lib/triangulation/FlowBoundingSphere.ipp 2014-04-24 21:37:44 +0000
@@ -7,11 +7,6 @@
* GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/
#ifdef FLOW_ENGINE
-// #include "def_types.h"
-// #include "def_flow_types.h"
-// #include "CGAL/constructions/constructions_on_weighted_points_cartesian_3.h"
-// #include <CGAL/Width_3.h>
-
// #define XVIEW
#include "FlowBoundingSphere.hpp"//include after #define XVIEW
@@ -23,7 +18,6 @@
#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
-// #include "Network.hpp"
#include <omp.h>
@@ -31,10 +25,6 @@
// #include "Vue3D.h" //FIXME implicit dependencies will look for this class (out of tree) even ifndef XVIEW
#endif
-#define FAST
-#define TESS_BASED_FORCES
-#define FACET_BASED_FORCES 1
-
#ifdef YADE_OPENMP
// #define GS_OPEN_MP //It should never be defined if Yade is not using openmp
#endif
@@ -65,254 +55,70 @@
template <class Tesselation>
FlowBoundingSphere<Tesselation>::FlowBoundingSphere()
{
- x_min = 1000.0, x_max = -10000.0, y_min = 1000.0, y_max = -10000.0, z_min = 1000.0, z_max = -10000.0;
+ xMin = 1000.0, xMax = -10000.0, yMin = 1000.0, yMax = -10000.0, zMin = 1000.0, zMax = -10000.0;
currentTes = 0;
nOfSpheres = 0;
- SectionArea = 0, Height=0, Vtotale=0;
- vtk_infinite_vertices=0, vtk_infinite_cells=0;
- VISCOSITY = 1;
+ sectionArea = 0, Height=0, vTotal=0;
+ vtkInfiniteVertices=0, vtkInfiniteCells=0;
+ viscosity = 1;
fluidBulkModulus = 0;
- tess_based_force = true;
+ tessBasedForce = true;
for (int i=0;i<6;i++) boundsIds[i] = 0;
minPermLength=-1;
- SLIP_ON_LATERALS = false;//no-slip/symmetry conditions on lateral boundaries
- TOLERANCE = 1e-07;
- RELAX = 1.9;
+ slipBoundary = false;//no-slip/symmetry conditions on lateral boundaries
+ tolerance = 1e-07;
+ relax = 1.9;
ks=0;
- distance_correction = true;
+ distanceCorrection = true;
clampKValues = true;
- meanKStat = true; K_opt_factor=0;
+ meanKStat = true; KOptFactor=0;
noCache=true;
pressureChanged=false;
- computeAllCells=true;//might be turned false IF the code is reorganized (we can make a separate function to compute unitForceVectors outside Compute_Permeability) AND it really matters for CPU time
- DEBUG_OUT = true;
- RAVERAGE = false; /** use the average between the effective radius (inscribed sphere in facet) and the equivalent (circle surface = facet fluid surface) **/
+ computeAllCells=true;//might be turned false IF the code is reorganized (we can make a separate function to compute unitForceVectors outside compute_Permeability) AND it really matters for CPU time
+ debugOut = true;
+ rAverage = false; /** use the average between the effective radius (inscribed sphere in facet) and the equivalent (circle surface = facet fluid surface) **/
OUTPUT_BOUDARIES_RADII = false;
- RAVERAGE = false; /** if true use the average between the effective radius (inscribed sphere in facet) and the equivalent (circle surface = facet fluid surface) **/
+ rAverage = false; /** if true use the average between the effective radius (inscribed sphere in facet) and the equivalent (circle surface = facet fluid surface) **/
// areaR2Permeability=true;
- permeability_map = false;
+ permeabilityMap = false;
computedOnce=false;
minKdivKmean=0.0001;
maxKdivKmean=100.;
- #ifdef parallel_forces
ompThreads=1;
- #endif
errorCode=0;
-}
-
-template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::ResetNetwork() {T[0].Clear();noCache=true;}
-
-template <class Tesselation>
-Tesselation& FlowBoundingSphere<Tesselation>::Compute_Action()
-{
- return Compute_Action(0,NULL,NULL);
-}
-template <class Tesselation>
-Tesselation& FlowBoundingSphere<Tesselation>::Compute_Action(int argc, char *argv[ ], char *envp[ ])
-{
- double factor = 1.001;
- VectorR X, Y, Z, R;
- Real_timer clock;
- clock.start();
- clock.top("start");
- Tesselation& Tes = T[0];
- RTriangulation& Tri = Tes.Triangulation();
-
- /** READING SPHERES POSITIONS FROM A TEXT FILE CONTAINING COORDINATES **/
- double x, y, z, r;
- ifstream loadFile(argc==1 ? "cube" : argv[1]); // cree l'objet loadFile de la classe ifstream qui va permettre de lire importFilename
- while (!loadFile.eof()) {
- loadFile >> x >> y >> z >> r;
- X.push_back(x);
- Y.push_back(y);
- Z.push_back(z);
- R.push_back(factor*r);
- nOfSpheres++;
- Rmoy += r;
- x_min = min(x_min,x-r);
- x_max = max(x_max,x+r);
- y_min = min(y_min,y-r);
- y_max = max(y_max,y+r);
- z_min = min(z_min,z-r);
- z_max = max(z_max,z+r);
- }
- Rmoy /= nOfSpheres;
- minPermLength = Rmoy*minLength;
- if (DEBUG_OUT) cout << "Rmoy = " << Rmoy << endl;
- if (DEBUG_OUT) cout << "x_min = " << x_min << " x_max = " << x_max << " y_min = " << y_min << " y_max = " << y_max << " y_max = " << z_min << " x_min = " << z_max << endl;
-
- Vertex_handle Vh;
- Cell_handle neighbour_cell, cell, location;
-
- int V = X.size();
- if (DEBUG_OUT) cout << "V =" << V << "nOfSpheres = " << nOfSpheres << endl;
- if (DEBUG_OUT) cout << Tes.Max_id() << endl;
- clock.top("loading spheres");
-
-
- vector<Sphere> vs; RTriangulation testT;
- for (int i=0; i<V; i++) {
- vs.push_back(Sphere(Point(X[i],Y[i],Z[i]), R[i]));
- }
- clock.top("make a spheres vector");
- testT.insert(vs.begin(),vs.end());
- clock.top("test speed");
-
- AddBoundingPlanes();
- for (int i=0; i<V; i++) {
- int id = Tes.Max_id() +1;
- Vh = Tes.insert(X[i],Y[i],Z[i],R[i],id); /** EMPILEMENT QUELCONQUE **/
-#ifdef XVIEW
- Vue1.SetSpheresColor(0.8,0.6,0.6,1);
- Vue1.Dessine_Sphere(X[i],Y[i],Z[i], R[i], 15);
-#endif
- }
- Height = y_max-y_min;
- SectionArea = (x_max-x_min) * (z_max-z_min);
- Vtotale = (x_max-x_min) * (y_max-y_min) * (z_max-z_min);
- clock.top("Triangulation");
-
- Tes.Compute();
- clock.top("tesselation");
-
- boundary(y_min_id).flowCondition=0;
- boundary(y_max_id).flowCondition=0;
- boundary(y_min_id).value=0;
- boundary(y_max_id).value=1;
- Define_fictious_cells();
- clock.top("BoundaryConditions");
-
- /** INITIALIZATION OF VOLUMES AND PRESSURES **/
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- cell->info().volume() = ( std::abs ( ( CGT::Tetraedre ( cell->vertex(0)->point(),cell->vertex(1)->point(),cell->vertex(2)->point(),cell->vertex(3)->point()).volume() ) ) );
- cell->info().dv() = 0;
- }
-
- clock.top("initializing delta_volumes");
-
- /** PERMEABILITY **/
- /** START PERMEABILITY CALCULATION**/
- k_factor = 1;
- Compute_Permeability();
- clock.top("Compute_Permeability");
- /** END PERMEABILITY CALCULATION**/
-
- if(DEBUG_OUT) cerr << "TOTAL VOID VOLUME: " << Vporale <<endl;
- if(DEBUG_OUT) cerr << "Porosity = " << V_porale_porosity / V_totale_porosity << endl;
-
- /** STATISTICS **/
- DisplayStatistics();
- clock.top("DisplayStatistics");
- /** START GAUSS SEIDEL */
- // Boundary_Conditions ( Tri );
- double P_zero = abs((boundary(y_min_id).value-boundary(y_max_id).value)/2);
- Initialize_pressures( P_zero );
- clock.top("Initialize_pressures");
- GaussSeidel();
- clock.top("GaussSeidel");
- /** END GAUSS SEIDEL */
- const char* file ="Permeability";
- ks = Permeameter(boundary(y_min_id).value, boundary(y_max_id).value, SectionArea, Height, file);
- clock.top("Permeameter");
-
- ComputeFacetForcesWithCache();
- clock.top("Compute_Forces");
-
- ///*** VUE 3D ***///
-
-#ifdef XVIEW
- Vue1.SetCouleurSegments(0.1,0,1);
- Dessine_Short_Tesselation(Vue1, Tes);
- Vue1.Affiche();
-#endif
- if (SLIP_ON_LATERALS && DEBUG_OUT) cout << "SLIP CONDITION IS ACTIVATED" << endl;
- else if (DEBUG_OUT) cout << "NOSLIP CONDITION IS ACTIVATED" << endl;
-// }
- return Tes;
-}
-
-template <class Tesselation>
-Tesselation& FlowBoundingSphere<Tesselation>::LoadPositions(int argc, char *argv[ ], char *envp[ ])
-{
- double factor = 1.001;
- VectorR X, Y, Z, R;
- Tesselation& Tes = T[0];
-// RTriangulation& Tri = Tes.Triangulation();
- /** READING SPHERES POSITIONS FROM A TEXT FILE CONTAINING COORDINATES **/
- double x, y, z, r;
- ifstream loadFile(argc==1 ? "cube" : argv[1]); // cree l'objet loadFile de la classe ifstream qui va permettre de lire importFilename
- while (!loadFile.eof()) {
- loadFile >> x >> y >> z >> r;
- X.push_back(x);
- Y.push_back(y);
- Z.push_back(z);
- R.push_back(factor*r);
- nOfSpheres++;
- Rmoy += r;
- x_min = min(x_min,x-r);
- x_max = max(x_max,x+r);
- y_min = min(y_min,y-r);
- y_max = max(y_max,y+r);
- z_min = min(z_min,z-r);
- z_max = max(z_max,z+r);
- }
- Rmoy /= nOfSpheres;
- minPermLength = Rmoy*minLength;
- Vertex_handle Vh;
- Cell_handle neighbour_cell, cell, location;
-
- int V = X.size();
- if (DEBUG_OUT) cout << "V =" << V << "nOfSpheres = " << nOfSpheres << endl;
- if (DEBUG_OUT) cout << Tes.Max_id() << endl;
-
- AddBoundingPlanes();
- for (int i=0; i<V; i++) {
- int id = Tes.Max_id() +1;
- Vh = Tes.insert(X[i],Y[i],Z[i],R[i],id); /** EMPILEMENT QUELCONQUE **/
-#ifdef XVIEW
- Vue1.SetSpheresColor(0.8,0.6,0.6,1);
- Vue1.Dessine_Sphere(X[i],Y[i],Z[i], R[i], 15);
-#endif
- }
- Height = y_max-y_min;
- SectionArea = (x_max-x_min) * (z_max-z_min);
- Vtotale = (x_max-x_min) * (y_max-y_min) * (z_max-z_min);
-
- Tes.Compute();
- Define_fictious_cells();
-
- return Tes;
-}
+ pxpos=ppval=NULL;
+}
+
+template <class Tesselation>
+void FlowBoundingSphere<Tesselation>::resetNetwork() {T[currentTes].Clear();noCache=true;}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Average_Relative_Cell_Velocity()
+void FlowBoundingSphere<Tesselation>::averageRelativeCellVelocity()
{
RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- Point pos_av_facet;
- int num_cells = 0;
- double facet_flow_rate = 0;
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for ( Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++ ) {
+ Point posAvFacet;
+ int numCells = 0;
+ double facetFlowRate = 0;
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++ ) {
if (cell->info().isGhost) continue;
- cell->info().av_vel() =CGAL::NULL_VECTOR;
- num_cells++;
- Real tot_flow_rate = 0;//used to acount for influxes in elements where pressure is imposed
+ cell->info().averageVelocity() =CGAL::NULL_VECTOR;
+ numCells++;
+ Real totFlowRate = 0;//used to acount for influxes in elements where pressure is imposed
for ( int i=0; i<4; i++ ) if (!Tri.is_infinite(cell->neighbor(i))){
- Vecteur Surfk = cell->info()-cell->neighbor(i)->info();
+ CVector Surfk = cell->info()-cell->neighbor(i)->info();
Real area = sqrt ( Surfk.squared_length() );
Surfk = Surfk/area;
- Vecteur branch = cell->vertex ( facetVertices[i][0] )->point() - cell->info();
- pos_av_facet = (Point) cell->info() + ( branch*Surfk ) *Surfk;
- facet_flow_rate = (cell->info().k_norm())[i] * (cell->info().shiftedP() - cell->neighbor (i)->info().shiftedP());
- tot_flow_rate += facet_flow_rate;
- cell->info().av_vel() = cell->info().av_vel() + (facet_flow_rate) * ( pos_av_facet-CGAL::ORIGIN );
+ CVector branch = cell->vertex ( facetVertices[i][0] )->point() - cell->info();
+ posAvFacet = (Point) cell->info() + ( branch*Surfk ) *Surfk;
+ facetFlowRate = (cell->info().kNorm())[i] * (cell->info().shiftedP() - cell->neighbor (i)->info().shiftedP());
+ totFlowRate += facetFlowRate;
+ cell->info().averageVelocity() = cell->info().averageVelocity() + (facetFlowRate) * ( posAvFacet-CGAL::ORIGIN );
}
//This is the influx term
- if (cell->info().Pcondition) cell->info().av_vel() = cell->info().av_vel() - (tot_flow_rate)*((Point) cell->info()-CGAL::ORIGIN );
+ if (cell->info().Pcondition) cell->info().averageVelocity() = cell->info().averageVelocity() - (totFlowRate)*((Point) cell->info()-CGAL::ORIGIN );
//now divide by volume
- cell->info().av_vel() = cell->info().av_vel() /abs(cell->info().volume());
+ cell->info().averageVelocity() = cell->info().averageVelocity() /abs(cell->info().volume());
}
}
@@ -322,8 +128,8 @@
bool FlowBoundingSphere<Tesselation>::isOnSolid (double X, double Y, double Z)
{
RTriangulation& Tri = T[currentTes].Triangulation();
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ FiniteCellsIterator cellEnd = Tri.finiteCellsEnd();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
for (int i=0; i<4; i++){
double radius = sqrt(cell->vertex(i)->point().weight());
if (X < (cell->vertex(i)->point().x()+radius) && X > (cell->vertex(i)->point().x()-radius)){
@@ -333,74 +139,72 @@
return false;
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Average_Fluid_Velocity()
+void FlowBoundingSphere<Tesselation>::averageFluidVelocity()
{
- Average_Relative_Cell_Velocity();
+ averageRelativeCellVelocity();
RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- int num_vertex = 0;
- Finite_vertices_iterator vertices_end = Tri.finite_vertices_end();
- for (Finite_vertices_iterator V_it = Tri.finite_vertices_begin(); V_it != vertices_end; V_it++) {
- num_vertex++;}
-
- vector<Real> Volumes;
- vector<CGT::Vecteur> VelocityVolumes;
- VelocityVolumes.resize(num_vertex);
- Volumes.resize(num_vertex);
-
- for (Finite_vertices_iterator V_it = Tri.finite_vertices_begin(); V_it != vertices_end; V_it++) {
- VelocityVolumes[V_it->info().id()]=CGAL::NULL_VECTOR;
- Volumes[V_it->info().id()]=0.f;}
-
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for ( Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++ )
+ int numVertex = 0;
+ FiniteVerticesIterator verticesEnd = Tri.finite_vertices_end();
+ for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != verticesEnd; vIt++) {
+ numVertex++;}
+
+ vector<Real> volumes;
+ vector<CGT::CVector> velocityVolumes;
+ velocityVolumes.resize(numVertex);
+ volumes.resize(numVertex);
+
+ for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != verticesEnd; vIt++) {
+ velocityVolumes[vIt->info().id()]=CGAL::NULL_VECTOR;
+ volumes[vIt->info().id()]=0.f;}
+
+ FiniteCellsIterator cellEnd = Tri.finiteCellsEnd();
+ for ( FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++ )
{
if (cell->info().fictious()==0){
for (int i=0;i<4;i++){
- VelocityVolumes[cell->vertex(i)->info().id()] = VelocityVolumes[cell->vertex(i)->info().id()] + cell->info().av_vel()*cell->info().volume();
- Volumes[cell->vertex(i)->info().id()] = Volumes[cell->vertex(i)->info().id()] + cell->info().volume();}
+ velocityVolumes[cell->vertex(i)->info().id()] = velocityVolumes[cell->vertex(i)->info().id()] + cell->info().averageVelocity()*cell->info().volume();
+ volumes[cell->vertex(i)->info().id()] = volumes[cell->vertex(i)->info().id()] + cell->info().volume();}
}}
std::ofstream fluid_vel ("Velocity", std::ios::out);
- double Rx = (x_max-x_min) /10;
- double Ry = (y_max-y_min) /12;
- double Rz = (z_max-z_min) /20;
- Cell_handle cellula;
+ double Rx = (xMax-xMin) /10;
+ double Ry = (yMax-yMin) /12;
+ double Rz = (zMax-zMin) /20;
+ CellHandle cellula;
- Vecteur Velocity = CGAL::NULL_VECTOR;
+ CVector velocity = CGAL::NULL_VECTOR;
int i=0;
- for(double X=x_min+Rx;X<x_max;X+=Rx){
- for (double Y=y_min+Ry;Y<y_max;Y+=Ry){
- Velocity = CGAL::NULL_VECTOR; i=0;
- for (double Z=z_min+Rz;Z<z_max;Z+=Rz){
+ for(double X=xMin+Rx;X<xMax;X+=Rx){
+ for (double Y=yMin+Ry;Y<yMax;Y+=Ry){
+ velocity = CGAL::NULL_VECTOR; i=0;
+ for (double Z=zMin+Rz;Z<zMax;Z+=Rz){
cellula = Tri.locate(Point(X,Y,Z));
- for (int y=0;y<4;y++) {if (!cellula->vertex(y)->info().isFictious) {Velocity = Velocity + (VelocityVolumes[cellula->vertex(y)->info().id()]/Volumes[cellula->vertex(y)->info().id()]);i++;}}
- }Velocity = Velocity/i;
- fluid_vel << X << " " << Y << " " << Velocity << endl;
+ for (int y=0;y<4;y++) {if (!cellula->vertex(y)->info().isFictious) {velocity = velocity + (velocityVolumes[cellula->vertex(y)->info().id()]/volumes[cellula->vertex(y)->info().id()]);i++;}}
+ }velocity = velocity/i;
+ fluid_vel << X << " " << Y << " " << velocity << endl;
}}
}
template <class Tesselation>
-vector<Real> FlowBoundingSphere<Tesselation>::Average_Fluid_Velocity_On_Sphere(unsigned int Id_sph)
+vector<Real> FlowBoundingSphere<Tesselation>::averageFluidVelocityOnSphere(unsigned int Id_sph)
{
- Average_Relative_Cell_Velocity();
- RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
-
- Real Volumes; CGT::Vecteur VelocityVolumes;
+ averageRelativeCellVelocity();
+ RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
+ Real volumes; CGT::CVector velocityVolumes;
vector<Real> result;
- result.resize(3);
-
- VelocityVolumes=CGAL::NULL_VECTOR;
- Volumes=0.f;
-
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for ( Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++ )
+ result.resize(3);
+ velocityVolumes=CGAL::NULL_VECTOR;
+ volumes=0.f;
+
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for ( FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++ )
{
if (cell->info().fictious()==0){
for (unsigned int i=0;i<4;i++){
if (cell->vertex(i)->info().id()==Id_sph){
- VelocityVolumes = VelocityVolumes + cell->info().av_vel()*cell->info().volume();
- Volumes = Volumes + cell->info().volume();}}}}
+ velocityVolumes = velocityVolumes + cell->info().averageVelocity()*cell->info().volume();
+ volumes = volumes + cell->info().volume();}}}}
- for (int i=0;i<3;i++) result[i] += VelocityVolumes[i]/Volumes;
+ for (int i=0;i<3;i++) result[i] += velocityVolumes[i]/volumes;
return result;
}
template <class Tesselation>
@@ -408,7 +212,7 @@
{
if (noCache && T[!currentTes].Max_id()<=0) return 0;//the engine never solved anything
RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- Cell_handle cell = Tri.locate(Point(X,Y,Z));
+ CellHandle cell = Tri.locate(Point(X,Y,Z));
return cell->info().p();
}
@@ -417,28 +221,27 @@
{
if (noCache) {cerr<<"Triangulation does not exist. Waht did you do?!"<<endl; return -1;}
RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- Cell_handle cell = Tri.locate(Point(X,Y,Z));
+ CellHandle cell = Tri.locate(Point(X,Y,Z));
return cell->info().id;
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::measurePressureProfile(double Wall_up_y, double Wall_down_y)
+void FlowBoundingSphere<Tesselation>::measurePressureProfile(double WallUpy, double WallDowny)
{
if (noCache && T[!currentTes].Max_id()<=0) return;//the engine never solved anything
RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- Cell_handle permeameter;
+ CellHandle permeameter;
std::ofstream capture ("Pressure_profile", std::ios::app);
int intervals = 5;
int captures = 6;
- double Rz = (z_max-z_min)/intervals;
- double Ry = (Wall_up_y-Wall_down_y)/captures;
-
- double X=(x_max+x_min)/2;
- double Y = Wall_down_y;
+ double Rz = (zMax-zMin)/intervals;
+ double Ry = (WallUpy-WallDowny)/captures;
+ double X=(xMax+xMin)/2;
+ double Y = WallDowny;
double pressure = 0.f;
int cell=0;
for (int i=0; i<captures; i++){
- for (double Z=min(z_min,z_max); Z<=max(z_min,z_max); Z+=abs(Rz)) {
+ for (double Z=min(zMin,zMax); Z<=max(zMin,zMax); Z+=abs(Rz)) {
permeameter = Tri.locate(Point(X, Y, Z));
pressure+=permeameter->info().p();
cell++;
@@ -453,11 +256,11 @@
RTriangulation& Tri = T[currentTes].Triangulation();
double P_ave = 0.f;
int n = 0;
- double Ry = (y_max-y_min)/30;
- double Rx = (x_max-x_min)/30;
- double Rz = (z_max-z_min)/30;
- for (double X=x_min; X<=x_max+Ry/10; X=X+Rx) {
- for (double Z=z_min; Z<=z_max+Ry/10; Z=Z+Rz) {
+ double Ry = (yMax-yMin)/30;
+ double Rx = (xMax-xMin)/30;
+ double Rz = (zMax-zMin)/30;
+ for (double X=xMin; X<=xMax+Ry/10; X=X+Rx) {
+ for (double Z=zMin; Z<=zMax+Ry/10; Z=Z+Rz) {
P_ave+=Tri.locate(Point(X, Y, Z))->info().p();
n++;
}
@@ -471,7 +274,7 @@
RTriangulation& Tri = T[currentTes].Triangulation();
double P = 0.f, Ppond=0.f, Vpond=0.f;
int n = 0;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); cell++) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); cell++) {
P+=cell->info().p();
n++;
Ppond+=cell->info().p()*cell->info().volume();
@@ -484,41 +287,37 @@
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::ComputeFacetForcesWithCache(bool onlyCache)
+void FlowBoundingSphere<Tesselation>::computeFacetForcesWithCache(bool onlyCache)
{
RTriangulation& Tri = T[currentTes].Triangulation();
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- Vecteur nullVect(0,0,0);
+ CVector nullVect(0,0,0);
//reset forces
- if (!onlyCache) for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) v->info().forces=nullVect;
+ if (!onlyCache) for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) v->info().forces=nullVect;
#ifdef parallel_forces
if (noCache) {
perVertexUnitForce.clear(); perVertexPressure.clear();
-// vector<const Vecteur*> exf; exf.reserve(20);
-// vector<const Real*> exp; exp.reserve(20);
- perVertexUnitForce.resize(T[currentTes].max_id+1);
- perVertexPressure.resize(T[currentTes].max_id+1);}
+ perVertexUnitForce.resize(T[currentTes].maxId+1);
+ perVertexPressure.resize(T[currentTes].maxId+1);}
#endif
- Cell_handle neighbour_cell;
- Vertex_handle mirror_vertex;
- Vecteur tempVect;
+ CellHandle neighbourCell;
+ VertexHandle mirrorVertex;
+ CVector tempVect;
//FIXME : Ema, be carefull with this (noCache), it needs to be turned true after retriangulation
- if (noCache) {for (VCell_iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
-// if (noCache) for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- Cell_handle& cell = *cell_it;
+ if (noCache) {for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ 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))) {
- neighbour_cell = cell->neighbor(j);
- const Vecteur& Surfk = cell->info().facetSurfaces[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;
- Vecteur facetNormal = Surfk/area;
- const std::vector<Vecteur>& crossSections = cell->info().facetSphereCrossSections;
- Vecteur fluidSurfk = cell->info().facetSurfaces[j]*cell->info().facetFluidSurfacesRatio[j];
+ 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[boundary(cell->vertex(j)->info().id()).coordinate]);
@@ -528,14 +327,13 @@
cell->info().unitForceVectors[j]=cell->info().unitForceVectors[j]+ tempVect;
}
/// Apply weighted forces f_k=sqRad_k/sumSqRad*f
- Vecteur Facet_Unit_Force = -fluidSurfk*cell->info().solidSurfaces[j][3];
- Vecteur Facet_Force = cell->info().p()*Facet_Unit_Force;
-
-
+ CVector facetUnitForce = -fluidSurfk*cell->info().solidSurfaces[j][3];
+ CVector facetForce = cell->info().p()*facetUnitForce;
+
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().solidSurfaces[j][y];
+ cell->vertex(facetVertices[j][y])->info().forces = cell->vertex(facetVertices[j][y])->info().forces + facetForce*cell->info().solidSurfaces[j][y];
//add to cached value
- cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]+Facet_Unit_Force*cell->info().solidSurfaces[j][y];
+ cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]+facetUnitForce*cell->info().solidSurfaces[j][y];
//uncomment to get total force / comment to get only viscous forces (Bruno)
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];
@@ -553,17 +351,16 @@
if (onlyCache) return;
} else {//use cached values
#ifndef parallel_forces
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ 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<= T[currentTes].max_id; vn++) {
+ for (int vn=0; vn<= T[currentTes].maxId; vn++) {
if (T[currentTes].vertexHandles[vn]==NULL) continue;
- Vertex_handle& v = T[currentTes].vertexHandles[vn];
-// for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v){
+ VertexHandle& v = T[currentTes].vertexHandles[vn];
const int& id = v->info().id();
- Vecteur tf (0,0,0);
+ CVector tf (0,0,0);
int k=0;
for (vector<const Real*>::iterator c = perVertexPressure[id].begin(); c != perVertexPressure[id].end(); c++)
tf = tf + (*(perVertexUnitForce[id][k++]))*(**c);
@@ -571,108 +368,83 @@
}
#endif
}
- if (DEBUG_OUT) {
- Vecteur TotalForce = nullVect;
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
- if (!v->info().isFictious) TotalForce = TotalForce + v->info().forces;
- else if (boundary(v->info().id()).flowCondition==1) TotalForce = TotalForce + v->info().forces; }
- cout << "TotalForce = "<< TotalForce << endl;}
-}
-template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::ComputeTetrahedralForces()
-{
- RTriangulation& Tri = T[currentTes].Triangulation();
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- Vecteur nullVect(0,0,0);
- bool ref = Tri.finite_cells_begin()->info().isvisited;
-
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
- v->info().forces=nullVect;
- }
-
- Cell_handle neighbour_cell;
- Vertex_handle mirror_vertex;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- for (int j=0; j<4; j++) if (!Tri.is_infinite(cell->neighbor(j)) && cell->neighbor(j)->info().isvisited==ref) {
- neighbour_cell = cell->neighbor(j);
- const Vecteur& Surfk = cell->info().facetSurfaces[j];
- /// handle fictious vertex since we can get the projected surface easily here
- if (cell->vertex(j)->info().isFictious) {
- Real projSurf=abs(Surfk[boundary(cell->vertex(j)->info().id()).coordinate]);
- cell->vertex(j)->info().forces = cell->vertex(j)->info().forces -projSurf*boundary(cell->vertex(j)->info().id()).normal*cell->info().p();
- }
- /// handle the opposite fictious vertex (remember each facet is seen only once)
- mirror_vertex = neighbour_cell->vertex(Tri.mirror_index(cell,j));
- Vertex_Info& info = neighbour_cell->vertex(Tri.mirror_index(cell,j))->info();
- if (info.isFictious) {
- Real projSurf=abs(Surfk[boundary(info.id()).coordinate]);
- info.forces = info.forces - projSurf*boundary(info.id()).normal*neighbour_cell->info().p();
- }
- /// Apply weighted forces f_k=sqRad_k/sumSqRad*f
- Vecteur Facet_Force = (neighbour_cell->info().p()-cell->info().p())*Surfk*cell->info().solidSurfaces[j][3];
- 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().solidSurfaces[j][y];
- }
- }
- cell->info().isvisited=!ref;
- }
-// if (DEBUG_OUT) cout << "tetrahedral scheme" <<endl;
-// Vecteur TotalForce = nullVect;
-// for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
-// if (!v->info().isFictious) {
-// TotalForce = TotalForce + v->info().forces;
-// } else {
-// if (boundary(v->info().id()).flowCondition==1) TotalForce = TotalForce + v->info().forces;
-// if (DEBUG_OUT) cout << "fictious_id = " << v->info().id() << " force = " << v->info().forces << endl;
-// }
-// }
-// if (DEBUG_OUT) cout << "TotalForce = "<< TotalForce << endl;
-}
-template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::ApplySinusoidalPressure(RTriangulation& Tri, double Amplitude, double Average_Pressure, double load_intervals)
-{
- double step = 1/load_intervals;
- Vector_Cell tmp_cells;
- tmp_cells.resize(10000);
- VCell_iterator cells_it = tmp_cells.begin();
+ if (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 (boundary(v->info().id()).flowCondition==1) totalForce = totalForce + v->info().forces; }
+ cout << "totalForce = "<< totalForce << endl;}
+}
+
+template <class Tesselation>
+void FlowBoundingSphere<Tesselation>::applySinusoidalPressure(RTriangulation& Tri, double amplitude, double averagePressure, double loadIntervals)
+{
+ double step = 1/loadIntervals;
+ VectorCell tmpCells;
+ tmpCells.resize(10000);
+ VCellIterator cellsIt = tmpCells.begin();
for (double alpha=0; alpha<1.001; alpha+=step)
{
- VCell_iterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[y_max_id],cells_it);
- for (VCell_iterator it = tmp_cells.begin(); it != cells_end; it++)
+ VCellIterator cellsEnd = Tri.incident_cells(T[currentTes].vertexHandles[yMaxId],cellsIt);
+ for (VCellIterator it = tmpCells.begin(); it != cellsEnd; it++)
{
if(!Tri.is_infinite(*it)){
Point& p1 = (*it)->info();
- Cell_handle& cell = *it;
- if (p1.x()<x_min) cell->info().p() = Average_Pressure+Amplitude;
- else if (p1.x()>x_max) cell->info().p() = Average_Pressure-Amplitude;
- else if (p1.x()>(x_min+alpha*(x_max-x_min)) && p1.x()<(x_min+(alpha+step)*(x_max-x_min))) cell->info().p() = Average_Pressure + (Amplitude)*(cos(alpha*M_PI));
- }
- }
- }
-}
-template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Interpolate(Tesselation& Tes, Tesselation& NewTes)
-{
- Cell_handle old_cell;
+ CellHandle& cell = *it;
+ if (p1.x()<xMin) cell->info().p() = averagePressure+amplitude;
+ else if (p1.x()>xMax) cell->info().p() = averagePressure-amplitude;
+ else if (p1.x()>(xMin+alpha*(xMax-xMin)) && p1.x()<(xMin+(alpha+step)*(xMax-xMin))) cell->info().p() = averagePressure + (amplitude)*(cos(alpha*M_PI));
+ }
+ }
+ }
+}
+
+template <class Tesselation>
+void FlowBoundingSphere<Tesselation>::applyUserDefinedPressure(RTriangulation& Tri, vector<Real>& xpos, vector<Real>& pval)
+{
+ if (!(xpos.size() && xpos.size()==pval.size())) {cerr << "Wrong definition of boundary pressure, check input" <<endl; return;}
+ pxpos=&xpos; ppval=&pval;
+ Real dx = xpos[1] - xpos[0]; Real xinit=xpos[0]; Real xlast=xpos.back();
+ VectorCell tmpCells; tmpCells.resize(10000);
+ VCellIterator cellsEnd = Tri.incident_cells(T[currentTes].vertexHandles[yMaxId],tmpCells.begin());
+ for (VCellIterator it = tmpCells.begin(); it != cellsEnd; it++)
+ {
+ if(Tri.is_infinite(*it)) continue;
+ Point& p1 = (*it)->info();
+ CellHandle& cell = *it;
+ if (p1.x()<xinit || p1.x()>xlast) cerr<<"udef pressure: cell out of range"<<endl;
+ else {
+ Real frac, intg;
+ frac=modf((p1.x()-xinit)/dx,&intg);
+ cell->info().p() = pval[intg]*(1-frac) + pval[intg+1]*frac;
+ }
+ }
+}
+
+template <class Tesselation>
+void FlowBoundingSphere<Tesselation>::interpolate(Tesselation& Tes, Tesselation& NewTes)
+{
+ CellHandle oldCell;
RTriangulation& Tri = Tes.Triangulation();
- for (typename Vector_Cell::iterator cell_it=NewTes.cellHandles.begin(); cell_it!=NewTes.cellHandles.end(); cell_it++){
- Cell_handle& new_cell = *cell_it;
- if (new_cell->info().Pcondition || new_cell->info().isGhost) continue;
- Vecteur center ( 0,0,0 );
- if (new_cell->info().fictious()==0) for ( int k=0;k<4;k++ ) center= center + 0.25* (Tes.vertex(new_cell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
+ for (typename VectorCell::iterator cellIt=NewTes.cellHandles.begin(); cellIt!=NewTes.cellHandles.end(); cellIt++){
+ CellHandle& newCell = *cellIt;
+ if (newCell->info().Pcondition || newCell->info().isGhost) continue;
+ CVector center ( 0,0,0 );
+ if (newCell->info().fictious()==0) for ( int k=0;k<4;k++ ) center= center + 0.25* (Tes.vertex(newCell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
else {
Real boundPos=0; int coord=0;
for ( int k=0;k<4;k++ ) {
- if (!new_cell->vertex (k)->info().isFictious) center= center+0.3333333333*(Tes.vertex(new_cell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
+ if (!newCell->vertex (k)->info().isFictious) center= center+0.3333333333*(Tes.vertex(newCell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
else {
- coord=boundary (new_cell->vertex(k)->info().id()).coordinate;
- boundPos=boundary (new_cell->vertex(k)->info().id()).p[coord];
+ coord=boundary (newCell->vertex(k)->info().id()).coordinate;
+ boundPos=boundary (newCell->vertex(k)->info().id()).p[coord];
}
}
- center=Vecteur(coord==0?boundPos:center[0],coord==1?boundPos:center[1],coord==2?boundPos:center[2]);
+ center=CVector(coord==0?boundPos:center[0],coord==1?boundPos:center[1],coord==2?boundPos:center[2]);
}
- old_cell = Tri.locate(Point(center[0],center[1],center[2]));
- new_cell->info().p() = old_cell->info().shiftedP();
+ oldCell = Tri.locate(Point(center[0],center[1],center[2]));
+ newCell->info().getInfo(oldCell->info());
+// newCell->info().p() = oldCell->info().shiftedP();
}
// Tes.Clear();//Don't reset to avoid segfault when getting pressure in scripts just after interpolation
}
@@ -696,35 +468,32 @@
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Compute_Permeability()
+void FlowBoundingSphere<Tesselation>::computePermeability()
{
- if (DEBUG_OUT) cout << "----Computing_Permeability------" << endl;
+ if (debugOut) cout << "----Computing_Permeability------" << endl;
RTriangulation& Tri = T[currentTes].Triangulation();
- Vsolid_tot = 0, Vtotalissimo = 0, Vporale = 0, Ssolid_tot = 0, V_totale_porosity=0, V_porale_porosity=0;
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
-
- Cell_handle neighbour_cell;
-
- double k=0, distance = 0, radius = 0, viscosity = VISCOSITY;
+ VSolidTot = 0, Vtotalissimo = 0, vPoral = 0, sSolidTot = 0, vTotalPorosity=0, vPoralPorosity=0;
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+
+ CellHandle neighbourCell;
+
+ double k=0, distance = 0, radius = 0;
int surfneg=0;
int NEG=0, POS=0, pass=0;
bool ref = Tri.finite_cells_begin()->info().isvisited;
-// Vecteur n;
Real meanK=0, STDEV=0, meanRadius=0, meanDistance=0;
Real infiniteK=1e10;
-// double volume_sub_pore = 0.f;
-
- for (VCell_iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
- Cell_handle& cell = *cell_it;
+ for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ CellHandle& cell = *cellIt;
Point& p1 = cell->info();
for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- Point& p2 = neighbour_cell->info();
- if (!Tri.is_infinite(neighbour_cell) && (neighbour_cell->info().isvisited==ref || computeAllCells)) {
- //Compute and store the area of sphere-facet intersections for later use
- Vertex_handle W [3];
+ neighbourCell = cell->neighbor(j);
+ Point& p2 = neighbourCell->info();
+ if (!Tri.is_infinite(neighbourCell) && (neighbourCell->info().isvisited==ref || computeAllCells)) {
+ //compute and store the area of sphere-facet intersections for later use
+ VertexHandle W [3];
for (int kk=0; kk<3; kk++) {
W[kk] = cell->vertex(facetVertices[j][kk]);
}
@@ -732,75 +501,55 @@
Sphere& v1 = W[1]->point();
Sphere& v2 = W[2]->point();
- cell->info().facetSphereCrossSections[j]=Vecteur(
+ cell->info().facetSphereCrossSections[j]=CVector(
W[0]->info().isFictious ? 0 : 0.5*v0.weight()*acos((v1-v0)*(v2-v0)/sqrt((v1-v0).squared_length()*(v2-v0).squared_length())),
W[1]->info().isFictious ? 0 : 0.5*v1.weight()*acos((v0-v1)*(v2-v1)/sqrt((v1-v0).squared_length()*(v2-v1).squared_length())),
W[2]->info().isFictious ? 0 : 0.5*v2.weight()*acos((v0-v2)*(v1-v2)/sqrt((v1-v2).squared_length()*(v2-v0).squared_length())));
pass+=1;
- Vecteur l = p1 - p2;
+ CVector l = p1 - p2;
distance = sqrt(l.squared_length());
-// n = l/distance;
- if (!RAVERAGE) radius = 2* Compute_HydraulicRadius(cell, j);
- else radius = (Compute_EffectiveRadius(cell, j)+Compute_EquivalentRadius(cell,j))*0.5;
+ if (!rAverage) radius = 2* computeHydraulicRadius(cell, j);
+ else radius = (computeEffectiveRadius(cell, j)+computeEquivalentRadius(cell,j))*0.5;
if (radius<0) NEG++;
else POS++;
if (radius==0) {
cout << "INS-INS PROBLEM!!!!!!!" << endl;
}
-// Real h,d;
Real fluidArea=0;
-// int test=0;
if (distance!=0) {
- if (minPermLength>0 && distance_correction) distance=max(minPermLength,distance);
- const Vecteur& Surfk = cell->info().facetSurfaces[j];
+ if (minPermLength>0 && distanceCorrection) distance=max(minPermLength,distance);
+ const CVector& Surfk = cell->info().facetSurfaces[j];
Real area = sqrt(Surfk.squared_length());
- const Vecteur& crossSections = cell->info().facetSphereCrossSections[j];
-// if (areaR2Permeability){
-// Real m1=sqrt((cross_product((v0-v1),v2-v1)).squared_length()/(v2-v1).squared_length());
- Real S0=0;
- S0=checkSphereFacetOverlap(v0,v1,v2);
- if (S0==0) S0=checkSphereFacetOverlap(v1,v2,v0);
- if (S0==0) S0=checkSphereFacetOverlap(v2,v0,v1);
- //take absolute value, since in rare cases the surface can be negative (overlaping spheres)
- fluidArea=abs(area-crossSections[0]-crossSections[1]-crossSections[2]+S0);
- cell->info().facetFluidSurfacesRatio[j]=fluidArea/area;
- k=(fluidArea * pow(radius,2)) / (8*viscosity*distance);
-// } else {
-// cout << "WARNING! if !areaR2Permeability, facetFluidSurfacesRatio will not be defined correctly. Don't use that."<<endl;
-// k = (M_PI * pow(radius,4)) / (8*viscosity*distance);}
-
+ const CVector& crossSections = cell->info().facetSphereCrossSections[j];
+ Real S0=0;
+ S0=checkSphereFacetOverlap(v0,v1,v2);
+ if (S0==0) S0=checkSphereFacetOverlap(v1,v2,v0);
+ if (S0==0) S0=checkSphereFacetOverlap(v2,v0,v1);
+ //take absolute value, since in rare cases the surface can be negative (overlaping spheres)
+ fluidArea=abs(area-crossSections[0]-crossSections[1]-crossSections[2]+S0);
+ cell->info().facetFluidSurfacesRatio[j]=fluidArea/area;
+ k=(fluidArea * pow(radius,2)) / (8*viscosity*distance);
meanDistance += distance;
meanRadius += radius;
- meanK += k*k_factor;
+ meanK += k*kFactor;
- if (k<0 && DEBUG_OUT) {surfneg+=1;
- cout<<"__ k<0 __"<<k<<" "<<" fluidArea "<<fluidArea<<" area "<<area<<" "<<crossSections[0]<<" "<<crossSections[1]<<" "<<crossSections[2] <<" "<<W[0]->info().id()<<" "<<W[1]->info().id()<<" "<<W[2]->info().id()<<" "<<p1<<" "<<p2<<" test "<<endl;}
-
+ if (k<0 && debugOut) {surfneg+=1;
+ cout<<"__ k<0 __"<<k<<" "<<" fluidArea "<<fluidArea<<" area "<<area<<" "<<crossSections[0]<<" "<<crossSections[1]<<" "<<crossSections[2] <<" "<<W[0]->info().id()<<" "<<W[1]->info().id()<<" "<<W[2]->info().id()<<" "<<p1<<" "<<p2<<" test "<<endl;}
} else {cout <<"infinite K1!"<<endl; k = infiniteK;}//Will be corrected in the next loop
- (cell->info().k_norm())[j]= k*k_factor;
-// (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]= k*k_factor;
- if (!neighbour_cell->info().isGhost) (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]= (cell->info().k_norm())[j];
-
-
-// if(permeability_map){
-// Cell_handle c = cell;
-// cell->info().s = cell->info().s + k*distance/fluidArea*this->Volume_Pore_VoronoiFraction (c,j);
-// volume_sub_pore += this->Volume_Pore_VoronoiFraction (c,j);}
-//
+ (cell->info().kNorm())[j]= k*kFactor;
+ if (!neighbourCell->info().isGhost) (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j];
}
}
cell->info().isvisited = !ref;
-// if(permeability_map){cell->info().s = cell->info().s/volume_sub_pore;
-// volume_sub_pore = 0.f;}
}
- if (DEBUG_OUT) cout<<"surfneg est "<<surfneg<<endl;
+ if (debugOut) cout<<"surfneg est "<<surfneg<<endl;
meanK /= pass;
meanRadius /= pass;
meanDistance /= pass;
- Real globalK=k_factor*meanDistance*Vporale/(Ssolid_tot*8.*viscosity);//An approximate value of macroscopic permeability, for clamping local values below
- if (DEBUG_OUT) {
+ Real globalK=kFactor*meanDistance*vPoral/(sSolidTot*8.*viscosity);//An approximate value of macroscopic permeability, for clamping local values below
+ if (debugOut) {
cout << "PassCompK = " << pass << endl;
cout << "meanK = " << meanK << endl;
cout << "globalK = " << globalK << endl;
@@ -812,20 +561,19 @@
ref = Tri.finite_cells_begin()->info().isvisited;
pass=0;
- if (clampKValues) for (VCell_iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
- Cell_handle& cell = *cell_it;
+ if (clampKValues) for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ CellHandle& cell = *cellIt;
for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) && neighbour_cell->info().isvisited==ref) {
+ neighbourCell = cell->neighbor(j);
+ if (!Tri.is_infinite(neighbourCell) && neighbourCell->info().isvisited==ref) {
pass++;
- (cell->info().k_norm())[j] = max(minKdivKmean*globalK ,min((cell->info().k_norm())[j], maxKdivKmean*globalK));
- (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]=(cell->info().k_norm())[j];
+ (cell->info().kNorm())[j] = max(minKdivKmean*globalK ,min((cell->info().kNorm())[j], maxKdivKmean*globalK));
+ (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]=(cell->info().kNorm())[j];
}
}
}
- if (DEBUG_OUT) cout << "PassKcorrect = " << pass << endl;
-
- if (DEBUG_OUT) cout << "POS = " << POS << " NEG = " << NEG << " pass = " << pass << endl;
+ if (debugOut) cout << "PassKcorrect = " << pass << endl;
+ if (debugOut) cout << "POS = " << POS << " NEG = " << NEG << " pass = " << pass << endl;
// A loop to compute the standard deviation of the local K distribution, and use it to include/exclude K values higher then (meanK +/- K_opt_factor*STDEV)
if (meanKStat)
@@ -833,53 +581,49 @@
std::ofstream k_opt_file("k_stdev.txt" ,std::ios::out);
ref = Tri.finite_cells_begin()->info().isvisited;
pass=0;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) && neighbour_cell->info().isvisited==ref) {
+ neighbourCell = cell->neighbor(j);
+ if (!Tri.is_infinite(neighbourCell) && neighbourCell->info().isvisited==ref) {
pass++;
- STDEV += pow(((cell->info().k_norm())[j]-meanK),2);
+ STDEV += pow(((cell->info().kNorm())[j]-meanK),2);
}
}cell->info().isvisited = !ref;
}
STDEV = sqrt(STDEV/pass);
- if (DEBUG_OUT) cout << "PassSTDEV = " << pass << endl;
- cout << "STATISTIC K" << endl;
- double k_min = 0, k_max = meanK + K_opt_factor*STDEV;
- cout << "Kmoy = " << meanK << " Standard Deviation = " << STDEV << endl;
- cout << "kmin = " << k_min << " kmax = " << k_max << endl;
+ if (debugOut) cout << "PassSTDEV = " << pass << endl << "STATISTIC K" << endl;
+ double k_min = 0, k_max = meanK + KOptFactor*STDEV;
+ cout << "Kmoy = " << meanK << " Standard Deviation = " << STDEV << endl<< "kmin = " << k_min << " kmax = " << k_max << endl;
ref = Tri.finite_cells_begin()->info().isvisited;
pass=0;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) && neighbour_cell->info().isvisited==ref) {
+ neighbourCell = cell->neighbor(j);
+ if (!Tri.is_infinite(neighbourCell) && neighbourCell->info().isvisited==ref) {
pass+=1;
- if ((cell->info().k_norm())[j]>k_max) {
- (cell->info().k_norm())[j]=k_max;
- (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]= (cell->info().k_norm())[j];
+ if ((cell->info().kNorm())[j]>k_max) {
+ (cell->info().kNorm())[j]=k_max;
+ (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j];
}
- k_opt_file << K_opt_factor << " " << (cell->info().k_norm())[j] << endl;
+ k_opt_file << KOptFactor << " " << (cell->info().kNorm())[j] << endl;
}
}cell->info().isvisited=!ref;
}
- if (DEBUG_OUT) cout << "PassKopt = " << pass << endl;
+ if (debugOut) cout << "PassKopt = " << pass << endl;
}
-
-
- if (DEBUG_OUT) {
- Finite_vertices_iterator vertices_end = Tri.finite_vertices_end();
+ if (debugOut) {
+ FiniteVerticesIterator verticesEnd = Tri.finite_vertices_end();
Real Vgrains = 0;
int grains=0;
- for (Finite_vertices_iterator V_it = Tri.finite_vertices_begin(); V_it != vertices_end; V_it++) {
- if (!V_it->info().isFictious && !V_it->info().isGhost) {
+ for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != verticesEnd; vIt++) {
+ if (!vIt->info().isFictious && !vIt->info().isGhost) {
grains +=1;
- Vgrains += 1.33333333 * M_PI * pow(V_it->point().weight(),1.5);}}
- cout<<grains<<"grains - " <<"Vtotale = " << Vtotale << " Vgrains = " << Vgrains << " Vporale1 = " << (Vtotale-Vgrains) << endl;
- cout << "Vtotalissimo = " << Vtotalissimo/2 << " Vsolid_tot = " << Vsolid_tot/2 << " Vporale2 = " << Vporale/2 << " Ssolid_tot = " << Ssolid_tot << endl<< endl;
- if (!RAVERAGE) cout << "------Hydraulic Radius is used for permeability computation------" << endl << endl;
+ Vgrains += 1.33333333 * M_PI * pow(vIt->point().weight(),1.5);}}
+ cout<<grains<<"grains - " <<"vTotal = " << vTotal << " Vgrains = " << Vgrains << " vPoral1 = " << (vTotal-Vgrains) << endl;
+ cout << "Vtotalissimo = " << Vtotalissimo/2 << " VSolidTot = " << VSolidTot/2 << " vPoral2 = " << vPoral/2 << " sSolidTot = " << sSolidTot << endl<< endl;
+ if (!rAverage) cout << "------Hydraulic Radius is used for permeability computation------" << endl << endl;
else cout << "------Average Radius is used for permeability computation------" << endl << endl;
- cout << "-----Computed_Permeability-----" << endl;}
+ cout << "-----computed_Permeability-----" << endl;}
}
template <class Tesselation>
@@ -887,12 +631,12 @@
{
RTriangulation& Tri = T[currentTes].Triangulation();
vector<double> constrictions;
- for (Finite_facets_iterator f_it=Tri.finite_facets_begin(); f_it != Tri.finite_facets_end();f_it++){
+ for (FiniteFacetsIterator f_it=Tri.finite_facets_begin(); f_it != Tri.finite_facets_end();f_it++){
//in the periodic case, we skip facets with lowest id out of the base period
- if ( ((f_it->first->info().index < f_it->first->neighbor(f_it->second)->info().index) && f_it->first->info().isGhost)
- || ((f_it->first->info().index > f_it->first->neighbor(f_it->second)->info().index) && f_it->first->neighbor(f_it->second)->info().isGhost)
+ if ( ((f_it->first->info().index <= f_it->first->neighbor(f_it->second)->info().index) && f_it->first->info().isGhost)
+ || ((f_it->first->info().index >= f_it->first->neighbor(f_it->second)->info().index) && f_it->first->neighbor(f_it->second)->info().isGhost)
|| f_it->first->info().index == 0 || f_it->first->neighbor(f_it->second)->info().index == 0) continue;
- constrictions.push_back(Compute_EffectiveRadius(f_it->first, f_it->second));
+ constrictions.push_back(computeEffectiveRadius(f_it->first, f_it->second));
}
return constrictions;
}
@@ -902,15 +646,15 @@
{
RTriangulation& Tri = T[currentTes].Triangulation();
vector<Constriction> constrictions;
- for (Finite_facets_iterator f_it=Tri.finite_facets_begin(); f_it != Tri.finite_facets_end();f_it++){
+ for (FiniteFacetsIterator f_it=Tri.finite_facets_begin(); f_it != Tri.finite_facets_end();f_it++){
//in the periodic case, we skip facets with lowest id out of the base period
- if ( ((f_it->first->info().index < f_it->first->neighbor(f_it->second)->info().index) && f_it->first->info().isGhost)
- || ((f_it->first->info().index > f_it->first->neighbor(f_it->second)->info().index) && f_it->first->neighbor(f_it->second)->info().isGhost)
+ if ( ((f_it->first->info().index <= f_it->first->neighbor(f_it->second)->info().index) && f_it->first->info().isGhost)
+ || ((f_it->first->info().index >= f_it->first->neighbor(f_it->second)->info().index) && f_it->first->neighbor(f_it->second)->info().isGhost)
|| f_it->first->info().index == 0 || f_it->first->neighbor(f_it->second)->info().index == 0) continue;
vector<double> rn;
- const Vecteur& normal = f_it->first->info().facetSurfaces[f_it->second];
+ const CVector& normal = f_it->first->info().facetSurfaces[f_it->second];
if (!normal[0] && !normal[1] && !normal[2]) continue;
- rn.push_back(Compute_EffectiveRadius(f_it->first, f_it->second));
+ rn.push_back(computeEffectiveRadius(f_it->first, f_it->second));
rn.push_back(normal[0]);
rn.push_back(normal[1]);
rn.push_back(normal[2]);
@@ -921,17 +665,16 @@
}
template <class Tesselation>
-double FlowBoundingSphere<Tesselation>::Compute_EffectiveRadius(Cell_handle cell, int j)
+double FlowBoundingSphere<Tesselation>::computeEffectiveRadius(CellHandle cell, int j)
{
RTriangulation& Tri = T[currentTes].Triangulation();
if (Tri.is_infinite(cell->neighbor(j))) return 0;
- Vecteur B = cell->vertex(facetVertices[j][1])->point().point()-cell->vertex(facetVertices[j][0])->point().point();
- Vecteur x = B/sqrt(B.squared_length());
- Vecteur C = cell->vertex(facetVertices[j][2])->point().point()-cell->vertex(facetVertices[j][0])->point().point();
- Vecteur z = CGAL::cross_product(x,C);
-// z = z/sqrt(z.squared_length());
- Vecteur y = CGAL::cross_product(x,z);
+ CVector B = cell->vertex(facetVertices[j][1])->point().point()-cell->vertex(facetVertices[j][0])->point().point();
+ CVector x = B/sqrt(B.squared_length());
+ CVector C = cell->vertex(facetVertices[j][2])->point().point()-cell->vertex(facetVertices[j][0])->point().point();
+ CVector z = CGAL::cross_product(x,C);
+ CVector y = CGAL::cross_product(x,z);
y = y/sqrt(y.squared_length());
double b1[2]; b1[0] = B*x; b1[1] = B*y;
@@ -961,34 +704,34 @@
}
template <class Tesselation>
-double FlowBoundingSphere<Tesselation>::Compute_EquivalentRadius(Cell_handle cell, int j)
+double FlowBoundingSphere<Tesselation>::computeEquivalentRadius(CellHandle cell, int j)
{
Real fluidSurf = sqrt(cell->info().facetSurfaces[j].squared_length())*cell->info().facetFluidSurfacesRatio[j];
return sqrt(fluidSurf/M_PI);
}
template <class Tesselation>
-double FlowBoundingSphere<Tesselation>::Compute_HydraulicRadius(Cell_handle cell, int j)
+double FlowBoundingSphere<Tesselation>::computeHydraulicRadius(CellHandle cell, int j)
{
RTriangulation& Tri = T[currentTes].Triangulation();
if (Tri.is_infinite(cell->neighbor(j))) return 0;
- double Vpore = this->Volume_Pore_VoronoiFraction(cell, j);
- double Ssolid = this->Surface_Solid_Pore(cell, j, SLIP_ON_LATERALS, /*reuse the same facet data*/ true);
+ double Vpore = this->volumePoreVoronoiFraction(cell, j);
+ double Ssolid = this->surfaceSolidPore(cell, j, slipBoundary, /*reuse the same facet data*/ true);
//handle symmetry (tested ok)
- if (SLIP_ON_LATERALS && facetNFictious>0) {
+ if (slipBoundary && facetNFictious>0) {
//! Include a multiplier so that permeability will be K/2 or K/4 in symmetry conditions
Real mult= facetNFictious==1 ? multSym1 : multSym2;
return Vpore/Ssolid*mult;}
return Vpore/Ssolid;
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Initialize_pressures( double P_zero )
+void FlowBoundingSphere<Tesselation>::initializePressure( double pZero )
{
RTriangulation& Tri = T[currentTes].Triangulation();
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++){
- cell->info().p() = P_zero; cell->info().dv()=0;}
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++){
+ cell->info().p() = pZero; cell->info().dv()=0;}
for (int bound=0; bound<6;bound++) {
int& id = *boundsIds[bound];
@@ -996,19 +739,21 @@
if (id<0) continue;
Boundary& bi = boundary(id);
if (!bi.flowCondition) {
- Vector_Cell tmp_cells;
- tmp_cells.resize(10000);
- VCell_iterator cells_it = tmp_cells.begin();
- VCell_iterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[id],cells_it);
- for (VCell_iterator it = tmp_cells.begin(); it != cells_end; it++){
+ VectorCell tmpCells;
+ tmpCells.resize(10000);
+ VCellIterator cells_it = tmpCells.begin();
+ VCellIterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[id],cells_it);
+ for (VCellIterator it = tmpCells.begin(); it != cells_end; it++){
(*it)->info().p() = bi.value;(*it)->info().Pcondition=true;
boundingCells[bound].push_back(*it);
}
}
}
+ if (ppval && pxpos) applyUserDefinedPressure(Tri,*pxpos,*ppval);
+
IPCells.clear();
for (unsigned int n=0; n<imposedP.size();n++) {
- Cell_handle cell=Tri.locate(imposedP[n].first);
+ CellHandle cell=Tri.locate(imposedP[n].first);
//check redundancy
for (unsigned int kk=0;kk<IPCells.size();kk++){
if (cell==IPCells[kk]) cerr<<"Two imposed pressures fall in the same cell."<<endl;
@@ -1020,7 +765,7 @@
IFCells.clear();
for (unsigned int n=0; n<imposedF.size();n++) {
- Cell_handle cell=Tri.locate(imposedF[n].first);
+ CellHandle cell=Tri.locate(imposedF[n].first);
//check redundancy
for (unsigned int kk=0;kk<IPCells.size();kk++){
if (cell==IPCells[kk]) cerr<<"Both flux and pressure are imposed in the same cell."<<endl;
@@ -1039,11 +784,12 @@
if (id<0) continue;
Boundary& bi = boundary(id);
if (!bi.flowCondition) {
- for (VCell_iterator it = boundingCells[bound].begin(); it != boundingCells[bound].end(); it++){
+ for (VCellIterator it = boundingCells[bound].begin(); it != boundingCells[bound].end(); it++){
(*it)->info().p() = bi.value; (*it)->info().Pcondition=true;
}
}
}
+ if (ppval && pxpos) applyUserDefinedPressure(T[currentTes].Triangulation(),*pxpos,*ppval);
for (unsigned int n=0; n<imposedP.size();n++) {
IPCells[n]->info().p()=imposedP[n].second;
IPCells[n]->info().Pcondition=true;}
@@ -1052,7 +798,7 @@
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::GaussSeidel(Real dt)
+void FlowBoundingSphere<Tesselation>::gaussSeidel(Real dt)
{
reApplyBoundaryConditions();
RTriangulation& Tri = T[currentTes].Triangulation();
@@ -1061,26 +807,24 @@
double compFlowFactor=0;
vector<Real> previousP;
previousP.resize(Tri.number_of_finite_cells());
- double tolerance = TOLERANCE;
- double relax = RELAX;
const int num_threads=1;
bool compressible= (fluidBulkModulus>0);
#ifdef GS_OPEN_MP
omp_set_num_threads(num_threads);
#endif
- if(DEBUG_OUT){ cout << "tolerance = " << tolerance << endl;
+ if(debugOut){ cout << "tolerance = " << tolerance << endl;
cout << "relax = " << relax << endl;}
vector<Real> t_sum_p, t_dp_max, t_sum_dp, t_p_max;
t_sum_dp.resize(num_threads);
t_dp_max.resize(num_threads);
t_p_max.resize(num_threads);
t_sum_p.resize(num_threads);
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
#ifdef GS_OPEN_MP
- vector<Finite_cells_iterator> cells_its;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) if ( !cell->info().Pcondition ) cells_its.push_back(cell);
- int num_cells=cells_its.size();
+ vector<FiniteCellsIterator> cells_its;
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) if ( !cell->info().Pcondition ) cells_its.push_back(cell);
+ int numCells=cells_its.size();
cout<<"cells_its.size() "<<cells_its.size();
#endif
// #pragma omp parallel shared(t_sum_dp, t_dp_max, sum_p, sum_dp,cells_its, j, Tri, relax)
@@ -1088,20 +832,20 @@
do {
int cell2=0; dp_max = 0;p_max = 0;p_moy=0;sum_p=0;sum_dp=0;
#ifdef GS_OPEN_MP
- cell2=num_cells;
+ cell2=numCells;
for (int ii=0;ii<num_threads;ii++) t_p_max[ii] =0;
for (int ii=0;ii<num_threads;ii++) t_dp_max[ii] =0;
for (int ii=0;ii<num_threads;ii++) t_sum_p[ii]=0;
for (int ii=0;ii<num_threads;ii++) t_sum_dp[ii]=0;
int kk=0;
- const int num_cells2 = num_cells;
+ const int numCells2 = numCells;
#pragma omp parallel for private(dp, m, n, kk) shared(tolerance, t_sum_dp, t_dp_max, sum_p, sum_dp,cells_its, j, Tri, relax) schedule(dynamic, 1000)
- for (kk=0; kk<num_cells2; kk++) {
- const Finite_cells_iterator& cell = cells_its[kk];
+ for (kk=0; kk<numCells2; kk++) {
+ const FiniteCellsIterator& cell = cells_its[kk];
{
#else
int bb=-1;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
bb++;
if ( !cell->info().Pcondition ) {
cell2++;
@@ -1113,29 +857,27 @@
/// COMPRESSIBLE:
if ( compressible ) {
compFlowFactor = fluidBulkModulus*dt*cell->info().invVoidVolume();
- m += compFlowFactor*(cell->info().k_norm())[j2] * cell->neighbor(j2)->info().p();
- if (j==0) n +=compFlowFactor*(cell->info().k_norm())[j2];
+ m += compFlowFactor*(cell->info().kNorm())[j2] * cell->neighbor(j2)->info().p();
+ if (j==0) n +=compFlowFactor*(cell->info().kNorm())[j2];
} else {
/// INCOMPRESSIBLE
- m += (cell->info().k_norm())[j2] * cell->neighbor(j2)->info().p();
- if ( isinf(m) && j<10 ) cout << "(cell->info().k_norm())[j2] = " << (cell->info().k_norm())[j2] << " cell->neighbor(j2)->info().p() = " << cell->neighbor(j2)->info().p() << endl;
- if (j==0) n += (cell->info().k_norm())[j2];
+ m += (cell->info().kNorm())[j2] * cell->neighbor(j2)->info().p();
+ if ( isinf(m) && j<10 ) cout << "(cell->info().kNorm())[j2] = " << (cell->info().kNorm())[j2] << " cell->neighbor(j2)->info().p() = " << cell->neighbor(j2)->info().p() << endl;
+ if (j==0) n += (cell->info().kNorm())[j2];
}
}
}
dp = cell->info().p();
if (n!=0 || j!=0) {
- if (j==0) { if (compressible) cell->info().inv_sum_k=1/(1+n); else cell->info().inv_sum_k=1/n; }
+ if (j==0) { if (compressible) cell->info().invSumK=1/(1+n); else cell->info().invSumK=1/n; }
if ( compressible ) {
/// COMPRESSIBLE cell->info().p() = ( (previousP - compFlowFactor*cell->info().dv()) + m ) / n ;
- cell->info().p() = ( ((previousP[bb] - ((fluidBulkModulus*dt*cell->info().invVoidVolume())*(cell->info().dv()))) + m) * cell->info().inv_sum_k - cell->info().p()) * relax + cell->info().p();
+ cell->info().p() = ( ((previousP[bb] - ((fluidBulkModulus*dt*cell->info().invVoidVolume())*(cell->info().dv()))) + m) * cell->info().invSumK - cell->info().p()) * relax + cell->info().p();
} else {
/// INCOMPRESSIBLE cell->info().p() = - ( cell->info().dv() - m ) / ( n ) = ( -cell.info().dv() + m ) / n ;
- cell->info().p() = (- (cell->info().dv() - m) * cell->info().inv_sum_k - cell->info().p()) * relax + cell->info().p();
+ cell->info().p() = (- (cell->info().dv() - m) * cell->info().invSumK - cell->info().p()) * relax + cell->info().p();
}
#ifdef GS_OPEN_MP
-// double r = sqrt(sqrt(sqrt(cell->info().p())/(1+sqrt(cell->info().p()))));
-// if (j % 100 == 0) cout<<"cell->info().p() "<<cell->info().p()<<" vs. "<< (- (cell->info().dv() - m) / (n) - cell->info().p())* relax<<endl;
#endif
}
dp -= cell->info().p();
@@ -1159,7 +901,6 @@
for (int ii=0;ii<num_threads;ii++) dp_max =max(dp_max, t_dp_max[ii]);
for (int ii=0;ii<num_threads;ii++) sum_p+=t_sum_p[ii];
for (int ii=0;ii<num_threads;ii++) sum_dp+=t_sum_dp[ii];
-// cerr<< p_max<< " "<<dp_max<<" "<<sum_p<<" "<<sum_dp<<endl;
#endif
p_moy = sum_p/cell2;
@@ -1174,9 +915,8 @@
#endif
}
- if (DEBUG_OUT) {cout << "pmax " << p_max << "; pmoy : " << p_moy << endl;
+ if (debugOut) {cout << "pmax " << p_max << "; pmoy : " << p_moy << endl;
cout << "iteration " << j <<"; erreur : " << dp_max/p_max << endl;}
-// iter << j << " " << dp_max/p_max << endl;
computedOnce=true;
}
@@ -1186,23 +926,24 @@
RTriangulation& Tri = T[currentTes].Triangulation();
double Q1=0;
- Vector_Cell tmp_cells;
- tmp_cells.resize(10000);
- VCell_iterator cells_it = tmp_cells.begin();
+ VectorCell tmpCells;
+ tmpCells.resize(10000);
+ VCellIterator cells_it = tmpCells.begin();
- VCell_iterator cell_up_end = Tri.incident_cells(T[currentTes].vertexHandles[boundaryId],cells_it);
- for (VCell_iterator it = tmp_cells.begin(); it != cell_up_end; it++)
+ VCellIterator cell_up_end = Tri.incident_cells(T[currentTes].vertexHandles[boundaryId],cells_it);
+ for (VCellIterator it = tmpCells.begin(); it != cell_up_end; it++)
{
- const Cell_handle& cell = *it;
+ const CellHandle& cell = *it;
if (cell->info().isGhost) continue;
+ Q1 -= cell->info().dv();
for (int j2=0; j2<4; j2++)
- Q1 += (cell->neighbor(j2)->info().k_norm())[Tri.mirror_index(cell, j2)]* (cell->neighbor(j2)->info().p()-cell->info().p());
+ Q1 += (cell->info().kNorm())[j2]* (cell->neighbor(j2)->info().shiftedP()-cell->info().shiftedP());
}
return Q1;
}
template <class Tesselation>
-double FlowBoundingSphere<Tesselation>::Permeameter(double P_Inf, double P_Sup, double Section, double DeltaY, const char *file)
+double FlowBoundingSphere<Tesselation>::permeameter(double PInf, double PSup, double Section, double DeltaY, const char *file)
{
RTriangulation& Tri = T[currentTes].Triangulation();
std::ofstream kFile(file, std::ios::out);
@@ -1210,34 +951,34 @@
int cellQ1=0, cellQ2=0;
double p_out_max=-10000000, p_out_min=10000000, p_in_max=-100000000, p_in_min=10000000,p_out_moy=0, p_in_moy=0;
- Vector_Cell tmp_cells;
- tmp_cells.resize(10000);
- VCell_iterator cells_it = tmp_cells.begin();
+ VectorCell tmpCells;
+ tmpCells.resize(10000);
+ VCellIterator cells_it = tmpCells.begin();
- VCell_iterator cell_up_end = Tri.incident_cells(T[currentTes].vertexHandles[y_max_id],cells_it);
- for (VCell_iterator it = tmp_cells.begin(); it != cell_up_end; it++)
+ VCellIterator cell_up_end = Tri.incident_cells(T[currentTes].vertexHandles[yMaxId],cells_it);
+ for (VCellIterator it = tmpCells.begin(); it != cell_up_end; it++)
{
- Cell_handle& cell = *it;
+ CellHandle& cell = *it;
for (int j2=0; j2<4; j2++) {
if (!cell->neighbor(j2)->info().Pcondition){
- Q1 = Q1 + (cell->neighbor(j2)->info().k_norm())[Tri.mirror_index(cell, j2)]* (cell->neighbor(j2)->info().p()-cell->info().p());
+ Q1 = Q1 + (cell->neighbor(j2)->info().kNorm())[Tri.mirror_index(cell, j2)]* (cell->neighbor(j2)->info().p()-cell->info().p());
cellQ1+=1;
p_out_max = max(cell->neighbor(j2)->info().p(), p_out_max);
p_out_min = min(cell->neighbor(j2)->info().p(), p_out_min);
p_out_moy += cell->neighbor(j2)->info().p();}
}}
- Vector_Cell tmp_cells2;
- tmp_cells2.resize(10000);
- VCell_iterator cells_it2 = tmp_cells2.begin();
+ VectorCell tmpCells2;
+ tmpCells2.resize(10000);
+ VCellIterator cells_it2 = tmpCells2.begin();
- VCell_iterator cell_down_end = Tri.incident_cells(T[currentTes].vertexHandles[y_min_id],cells_it2);
- for (VCell_iterator it = tmp_cells2.begin(); it != cell_down_end; it++)
+ VCellIterator cell_down_end = Tri.incident_cells(T[currentTes].vertexHandles[yMinId],cells_it2);
+ for (VCellIterator it = tmpCells2.begin(); it != cell_down_end; it++)
{
- Cell_handle& cell = *it;
+ CellHandle& cell = *it;
for (int j2=0; j2<4; j2++){
if (!cell->neighbor(j2)->info().Pcondition){
- Q2 = Q2 + (cell->neighbor(j2)->info().k_norm())[Tri.mirror_index(cell, j2)]* (cell->info().p()-cell->neighbor(j2)->info().p());
+ Q2 = Q2 + (cell->neighbor(j2)->info().kNorm())[Tri.mirror_index(cell, j2)]* (cell->info().p()-cell->neighbor(j2)->info().p());
cellQ2+=1;
p_in_max = max(cell->neighbor(j2)->info().p(), p_in_max);
p_in_min = min(cell->neighbor(j2)->info().p(), p_in_min);
@@ -1245,15 +986,15 @@
}}
double density = 1;
- double viscosity = VISCOSITY;
+ double viscosity = viscosity;
double gravity = 1;
double Vdarcy = Q1/Section;
- double DeltaP = abs(P_Inf-P_Sup);
+ double DeltaP = abs(PInf-PSup);
double DeltaH = DeltaP/ (density*gravity);
double k = viscosity*Vdarcy*DeltaY / DeltaP; /**m²**/
double Ks = k*(density*gravity)/viscosity; /**m/s**/
- if (DEBUG_OUT){
+ if (debugOut){
cout << "the maximum superior pressure is = " << p_out_max << " the min is = " << p_out_min << endl;
cout << "the maximum inferior pressure is = " << p_in_max << " the min is = " << p_in_min << endl;
cout << "superior average pressure is " << p_out_moy/cellQ1 << endl;
@@ -1267,7 +1008,7 @@
cout << "The permeability of the sample is = " << k << " m^2" <<endl;
cout << endl << "The hydraulic conductivity of the sample is = " << Ks << " m/s" << endl << endl;
}
- kFile << "y_max id = "<<y_max_id<< "y_min id = "<<y_min_id<<endl;
+ kFile << "yMax id = "<<yMaxId<< "yMin id = "<<yMinId<<endl;
kFile << "the maximum superior pressure is = " << p_out_max << " the min is = " << p_out_min << endl;
kFile << "the maximum inferior pressure is = " << p_in_max << " the min is = " << p_in_min << endl;
kFile << "superior average pressure is " << p_out_moy/cellQ2 << endl;
@@ -1283,15 +1024,15 @@
return k;
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::DisplayStatistics()
+void FlowBoundingSphere<Tesselation>::displayStatistics()
{
RTriangulation& Tri = T[currentTes].Triangulation();
int Zero =0, Inside=0, Fictious=0;
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
int zeros =0;
for (int j=0; j!=4; j++) {
- if ((cell->info().k_norm())[j]==0) {
+ if ((cell->info().kNorm())[j]==0) {
zeros+=1;
}
}
@@ -1305,14 +1046,14 @@
}
}
int fict=0, real=0;
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
if (v->info().isFictious) fict+=1;
else real+=1;
}
long Vertices = Tri.number_of_vertices();
long Cells = Tri.number_of_finite_cells();
long Facets = Tri.number_of_finite_facets();
- if(DEBUG_OUT) {cout << "zeros = " << Zero << endl;
+ if(debugOut) {cout << "zeros = " << Zero << endl;
cout << "There are " << Vertices << " vertices, dont " << fict << " fictious et " << real << " reeeeeel" << std::endl;
cout << "There are " << Cells << " cells " << std::endl;
cout << "There are " << Facets << " facets " << std::endl;
@@ -1332,23 +1073,23 @@
int firstReal=-1;
//count fictious vertices and cells
- vtk_infinite_vertices=vtk_infinite_cells=0;
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ vtkInfiniteVertices=vtkInfiniteCells=0;
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
bool isDrawable = cell->info().isReal() && cell->vertex(0)->info().isReal() && cell->vertex(1)->info().isReal() && cell->vertex(2)->info().isReal() && cell->vertex(3)->info().isReal();
- if (!isDrawable) vtk_infinite_cells+=1;
+ if (!isDrawable) vtkInfiniteCells+=1;
}
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
- if (!v->info().isReal()) vtk_infinite_vertices+=1;
- else if (firstReal==-1) firstReal=vtk_infinite_vertices;}
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
+ if (!v->info().isReal()) vtkInfiniteVertices+=1;
+ else if (firstReal==-1) firstReal=vtkInfiniteVertices;}
- basicVTKwritter vtkfile((unsigned int) Tri.number_of_vertices()-vtk_infinite_vertices, (unsigned int) Tri.number_of_finite_cells()-vtk_infinite_cells);
+ basicVTKwritter vtkfile((unsigned int) Tri.number_of_vertices()-vtkInfiniteVertices, (unsigned int) Tri.number_of_finite_cells()-vtkInfiniteCells);
vtkfile.open(filename,"test");
vtkfile.begin_vertices();
double x,y,z;
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
if (v->info().isReal()){
x = (double)(v->point().point()[0]);
y = (double)(v->point().point()[1]);
@@ -1358,58 +1099,58 @@
vtkfile.end_vertices();
vtkfile.begin_cells();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
bool isDrawable = cell->info().isReal() && cell->vertex(0)->info().isReal() && cell->vertex(1)->info().isReal() && cell->vertex(2)->info().isReal() && cell->vertex(3)->info().isReal();
if (isDrawable){vtkfile.write_cell(cell->vertex(0)->info().id()-firstReal, cell->vertex(1)->info().id()-firstReal, cell->vertex(2)->info().id()-firstReal, cell->vertex(3)->info().id()-firstReal);}
}
vtkfile.end_cells();
- if (permeability_map){
+ if (permeabilityMap){
vtkfile.begin_data("Permeability",CELL_DATA,SCALARS,FLOAT);
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
bool isDrawable = cell->info().isReal() && cell->vertex(0)->info().isReal() && cell->vertex(1)->info().isReal() && cell->vertex(2)->info().isReal() && cell->vertex(3)->info().isReal();
if (isDrawable){vtkfile.write_data(cell->info().s);}
}
vtkfile.end_data();}
else{
vtkfile.begin_data("Pressure",CELL_DATA,SCALARS,FLOAT);
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
bool isDrawable = cell->info().isReal() && cell->vertex(0)->info().isReal() && cell->vertex(1)->info().isReal() && cell->vertex(2)->info().isReal() && cell->vertex(3)->info().isReal();
if (isDrawable){vtkfile.write_data(cell->info().p());}
}
vtkfile.end_data();}
if (1){
- Average_Relative_Cell_Velocity();
+ averageRelativeCellVelocity();
vtkfile.begin_data("Velocity",CELL_DATA,VECTORS,FLOAT);
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != Tri.finite_cells_end(); ++cell) {
bool isDrawable = cell->info().isReal() && cell->vertex(0)->info().isReal() && cell->vertex(1)->info().isReal() && cell->vertex(2)->info().isReal() && cell->vertex(3)->info().isReal();
- if (isDrawable){vtkfile.write_data(cell->info().av_vel()[0],cell->info().av_vel()[1],cell->info().av_vel()[2]);}
+ if (isDrawable){vtkfile.write_data(cell->info().averageVelocity()[0],cell->info().averageVelocity()[1],cell->info().averageVelocity()[2]);}
}
vtkfile.end_data();}
}
#ifdef XVIEW
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Dessine_Triangulation(Vue3D &Vue, RTriangulation &T)
+void FlowBoundingSphere<Tesselation>::dessineTriangulation(Vue3D &Vue, RTriangulation &T)
{
double* Segments = NULL;
- long N_seg = New_liste_edges(T, &Segments);
+ long N_seg = newListeEdges(T, &Segments);
Vue.Dessine_Segment(Segments, N_seg);
- Delete_liste_edges(&Segments, N_seg);
+ deleteListeEdges(&Segments, N_seg);
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::Dessine_Short_Tesselation(Vue3D &Vue, Tesselation &Tes)
+void FlowBoundingSphere<Tesselation>::dessineShortTesselation(Vue3D &Vue, Tesselation &Tes)
{
- if (!Tes.Computed()) Tes.Compute();
+ if (!Tes.computed()) Tes.compute();
double* Segments = NULL;
- long N_seg = Tes.New_liste_short_edges(&Segments);
+ long N_seg = Tes.newListeShortEdges(&Segments);
Vue.Dessine_Segment(Segments, N_seg);
- Delete_liste_edges(&Segments, N_seg);
+ deleteListeEdges(&Segments, N_seg);
}
#endif
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::GenerateVoxelFile( )
+void FlowBoundingSphere<Tesselation>::generateVoxelFile( )
{
RTriangulation& Tri = T[currentTes].Triangulation();
double l = 1;
@@ -1424,9 +1165,9 @@
for (double x=0; x<=l; x+=eps) {
solid=false;
- for (Finite_vertices_iterator V_it = Tri.finite_vertices_begin(); V_it != Tri.finite_vertices_end(); V_it++) {
- double radius = sqrt(V_it->point().weight());
- if ((sqrt(pow((x- (V_it->point()[0])),2) +pow((y- (V_it->point()[1])),2) +pow((z- (V_it->point()[2])),2))) <= radius) solid=true;
+ for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != Tri.finite_vertices_end(); vIt++) {
+ double radius = sqrt(vIt->point().weight());
+ if ((sqrt(pow((x- (vIt->point()[0])),2) +pow((y- (vIt->point()[1])),2) +pow((z- (vIt->point()[2])),2))) <= radius) solid=true;
}
if (solid) voxelfile << 1;
else voxelfile << 0;
@@ -1437,192 +1178,142 @@
}
template <class Tesselation>
-double FlowBoundingSphere<Tesselation>::Sample_Permeability(double& x_Min,double& x_Max ,double& y_Min,double& y_Max,double& z_Min,double& z_Max/*, string key*/)
+double FlowBoundingSphere<Tesselation>::samplePermeability(double& xMin,double& xMax ,double& yMin,double& yMax,double& zMin,double& zMax/*, string key*/)
{
- double Section = (x_Max-x_Min) * (z_Max-z_Min);
- double DeltaY = y_Max-y_Min;
- boundary(y_min_id).flowCondition=0;
- boundary(y_max_id).flowCondition=0;
- boundary(y_min_id).value=0;
- boundary(y_max_id).value=1;
- double P_zero = abs((boundary(y_min_id).value-boundary(y_max_id).value)/2);
- Initialize_pressures( P_zero );
- GaussSeidel();
+ double Section = (xMax-xMin) * (zMax-zMin);
+ double DeltaY = yMax-yMin;
+ boundary(yMinId).flowCondition=0;
+ boundary(yMaxId).flowCondition=0;
+ boundary(yMinId).value=0;
+ boundary(yMaxId).value=1;
+ double pZero = abs((boundary(yMinId).value-boundary(yMaxId).value)/2);
+ initializePressure( pZero );
+ gaussSeidel();
const char *kk = "Permeability";
- return Permeameter(boundary(y_min_id).value, boundary(y_max_id).value, Section, DeltaY, kk);
+ return permeameter(boundary(yMinId).value, boundary(yMaxId).value, Section, DeltaY, kk);
}
template <class Tesselation>
bool FlowBoundingSphere<Tesselation>::isInsideSphere(double& x, double& y, double& z)
{
RTriangulation& Tri = T[currentTes].Triangulation();
- for (Finite_vertices_iterator V_it = Tri.finite_vertices_begin(); V_it != Tri.finite_vertices_end(); V_it++) {
- double radius = V_it->point().weight();
- if (pow((x- (V_it->point()[0])),2) +pow((y- (V_it->point()[1])),2) +pow((z- (V_it->point()[2])),2) <= radius) return true;
+ for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != Tri.finite_vertices_end(); vIt++) {
+ double radius = vIt->point().weight();
+ if (pow((x- (vIt->point()[0])),2) +pow((y- (vIt->point()[1])),2) +pow((z- (vIt->point()[2])),2) <= radius) return true;
}
return false;
}
template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::SliceField(const char *filename)
+void FlowBoundingSphere<Tesselation>::sliceField(const char *filename)
{
/** Pressure field along one cutting plane **/
RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- Cell_handle permeameter;
+ CellHandle permeameter;
std::ofstream consFile(filename,std::ios::out);
int intervals = 400;
- double Ry = (y_max-y_min) /intervals;
- double Rz = (z_max-z_min) /intervals;
-// cout<<Rx<<" "<<Ry<<" "<<Rz<<" "<<z_max<<" "<<z_min<<" "<<y_max<<" "<<y_min<<" "<<x_max<<" "<<x_min<<endl;
-
-// for (double X=min(x_min,x_max); X<=max(x_min,x_max); X=X+abs(Rx)) {
+ double Ry = (yMax-yMin) /intervals;
+ double Rz = (zMax-zMin) /intervals;
double X=0.5;
- for (double Y=min(y_max,y_min); Y<=max(y_max,y_min); Y=Y+abs(Ry)) {
- for (double Z=min(z_min,z_max); Z<=max(z_min,z_max); Z=Z+abs(Rz)) {
+ for (double Y=min(yMax,yMin); Y<=max(yMax,yMin); Y=Y+abs(Ry)) {
+ for (double Z=min(zMin,zMax); Z<=max(zMin,zMax); Z=Z+abs(Rz)) {
permeameter = Tri.locate(Point(X, Y, Z));
consFile << permeameter->info().p() <<" ";
-// if (!isInsideSphere(X,Y,Z)) {
-// permeameter = Tri.locate(Point(X, Y, Z));
-// consFile << permeameter->info().p() <<" ";
-// //cout <<"valeur trouvée";
-// } else consFile << "Nan ";
}
consFile << endl;}
consFile << endl;
-// }
consFile.close();
}
-template <class Tesselation>
-void FlowBoundingSphere<Tesselation>::ComsolField()
-{
- //Compute av. velocity first, because in the following permeabilities will be overwritten with "junk" (in fact velocities from comsol)
- Average_Relative_Cell_Velocity();
-
- RTriangulation& Tri = T[noCache?(!currentTes):currentTes].Triangulation();
- Cell_handle c;
- ifstream loadFile("vx_grid_03_07_ns.txt");
- ifstream loadFileY("vy_grid_03_07_ns.txt");
- ifstream loadFileZ("vz_grid_03_07_ns.txt");
- int Nx=100; int Ny=10; int Nz=100;
- std::ofstream consFile("velComp",std::ios::out);
-
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++){
- cell->info().dv()=0;
- cell->info().module_permeability[0]=cell->info().module_permeability[1]=cell->info().module_permeability[2]=0;
- }
-
- vector<Real> X, Y, Z;
- Real buffer;
- for (int xi=0;xi<Nx;xi++) {loadFile >> buffer; X.push_back(buffer); loadFileY >> buffer; loadFileZ >> buffer;}
- for (int yi=0;yi<Ny;yi++) {loadFile >> buffer; Y.push_back(buffer); loadFileY >> buffer; loadFileZ >> buffer;}
- for (int zi=0;zi<Nz;zi++) {loadFile >> buffer; Z.push_back(buffer); loadFileY >> buffer; loadFileZ >> buffer;}
-
- Real vx, vy, vz;
- Real meanCmsVel=0; int totCmsPoints = 0;
- for (int zi=0;zi<Nz;zi++)
- for (int yi=0;yi<Ny;yi++)
- for (int xi=0;xi<Nx;xi++) {
- loadFile >> vx; loadFileY >> vy; loadFileZ >> vz;
- if (!isInsideSphere(X[xi], Y[yi], Z[zi]) && vx!=0) {
- c = Tri.locate(Point(X[xi], Y[yi], Z[zi]));
- c->info().module_permeability[0]+=vx;
- c->info().module_permeability[1]+=vy;
- c->info().module_permeability[2]+=vz;
- c->info().dv()+=1;
- meanCmsVel+=vy; totCmsPoints++;}
- }
- int kk=0;
- Vecteur diff;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end && kk<10000; cell++){
- if (cell->info().fictious() || cell->info().dv()<60) continue;
- for (int k=0;k<3;k++) cell->info().module_permeability[k]/=cell->info().dv();
- cerr << cell->info().module_permeability[0]<<" "<< cell->info().module_permeability[1]<<" "<< cell->info().module_permeability[2]<<" "<<cell->info().dv()<<" "<< cell->info().av_vel()<<endl;
- Real m=sqrt(pow(cell->info().module_permeability[0],2)+pow(cell->info().module_permeability[1],2)+pow(cell->info().module_permeability[2],2));
- Vecteur comFlow (cell->info().module_permeability[0],cell->info().module_permeability[1],cell->info().module_permeability[2]);
- Real angle=asin(sqrt(cross_product(comFlow,cell->info().av_vel()).squared_length())/(sqrt(comFlow.squared_length())*sqrt(cell->info().av_vel().squared_length())));
- cerr<<"norms : "<<m<<" vs. "<<sqrt(cell->info().av_vel().squared_length())<<" angle "<<180*angle/3.1415<<endl;
- consFile<<m<<" "<<sqrt(cell->info().av_vel().squared_length())<<" "<<180*angle/3.1415<<endl;
- diff = diff + (comFlow - cell->info().av_vel());
- kk++;
- }
- cerr << "meanCmsVel "<<meanCmsVel/totCmsPoints<<" mean diff "<<diff/kk<<endl;
-}
+
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(Edge_ids[k].first,Edge_ids[k].second)].push_back(pair<int,Real> (max(Edge_ids[k].first,Edge_ids[k].second),edgeNormalLubF[k]));
-
- //Now we reset the containers and initialize them
- Edge_Surfaces.clear(); Edge_ids.clear(); edgeNormalLubF.clear();
- Finite_edges_iterator ed_it;
- for ( Finite_edges_iterator 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);
- Edge_Surfaces.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();
- Edge_ids.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>
Vector3r FlowBoundingSphere<Tesselation>::computeViscousShearForce(const Vector3r& deltaV, const int& edge_id, const Real& Rh)
{
- Vector3r tau = deltaV*VISCOSITY/Rh;
- return tau * Edge_Surfaces[edge_id];
+ Vector3r tau = deltaV*viscosity/Rh;
+ return tau * edgeSurfaces[edge_id];
}
template <class Tesselation>
Vector3r FlowBoundingSphere<Tesselation>::computeShearLubricationForce(const Vector3r& deltaShearV, const Real& dist, const int& edge_id, const Real& eps, const Real& centerDist, const Real& meanRad )
{
- Real d = max(dist,0.) + eps*meanRad;
- Vector3r viscLubF = 0.5 * Mathr::PI * VISCOSITY * (-2*meanRad + centerDist*log(centerDist/d)) * deltaShearV;
+ Real d = max(dist,0.) + 2.*eps*meanRad;
+ Vector3r viscLubF = 0.5 * Mathr::PI * viscosity * (-2*meanRad + centerDist*log(centerDist/d)) * deltaShearV;
return viscLubF;
}
template <class Tesselation>
+Vector3r FlowBoundingSphere<Tesselation>::computePumpTorque(const Vector3r& deltaShearAngV, const Real& dist, const int& edge_id, const Real& eps, const Real& meanRad )
+{
+ Real d = max(dist,0.) + 2.*eps*meanRad;
+ Vector3r viscPumpC = Mathr::PI * viscosity * pow(meanRad,3) *(3./20. * log(meanRad/d) + 63./500. * (d/meanRad) * log(meanRad/d)) * deltaShearAngV;
+ return viscPumpC;
+}
+
+template <class Tesselation>
+Vector3r FlowBoundingSphere<Tesselation>::computeTwistTorque(const Vector3r& deltaNormAngV, const Real& dist, const int& edge_id, const Real& eps, const Real& meanRad )
+{
+ Real d = max(dist,0.) + 2.*eps*meanRad;
+ Vector3r twistC = Mathr::PI * viscosity * pow(meanRad,2) * d * log(meanRad/d) * deltaNormAngV;
+ return twistC;
+}
+
+
+template <class Tesselation>
Real FlowBoundingSphere<Tesselation>::computeNormalLubricationForce(const Real& deltaNormV, const Real& dist, const int& edge_id, const Real& eps, const Real& stiffness, const Real& dt, const Real& meanRad)
{
//FIXME: here introduce elasticity
- Real d = max(dist,0.) + eps*meanRad;//account for grains roughness
+ Real d = max(dist,0.) + 2.*eps*meanRad;//account for grains roughness
if (stiffness>0) {
const Real k = stiffness*meanRad;
Real prevForce = edgeNormalLubF[edge_id];
-// Real prevForce = edgeNormalLubF[edge_id] ? edgeNormalLubF[edge_id] : (6*Mathr::PI*pow(meanRad,2)* VISCOSITY* deltaNormV)/d;
-// if (!edgeNormalLubF[edge_id]) for (int kk=0; kk<30; kk++) {
-// Real instantVisc = 6*Mathr::PI*pow(meanRad,2)*VISCOSITY/(d-prevForce/k);
-// prevForce = instantVisc*(deltaNormV + prevForce/(k*dt))/(1+instantVisc/(k*dt));
-// if ((kk==0 || kk==29) && deltaNormV!=0) cerr << "prevForce("<<kk<<") = "<< prevForce<<endl;
-// }
- Real instantVisc = 1.5*Mathr::PI*pow(meanRad,2)*VISCOSITY/(d-prevForce/k);
+ Real instantVisc = 1.5*Mathr::PI*pow(meanRad,2)*viscosity/(d-prevForce/k);
Real normLubF = instantVisc*(deltaNormV + prevForce/(k*dt))/(1+instantVisc/(k*dt));
edgeNormalLubF[edge_id]=normLubF;
return normLubF;
} else {
- Real normLubF = (1.5*Mathr::PI*pow(meanRad,2)* VISCOSITY* deltaNormV)/d;
+ Real normLubF = (1.5*Mathr::PI*pow(meanRad,2)* viscosity* deltaNormV)/d;
return normLubF;
}
}
=== modified file 'lib/triangulation/FlowBoundingSphereLinSolv.hpp'
--- lib/triangulation/FlowBoundingSphereLinSolv.hpp 2013-06-27 11:29:17 +0000
+++ lib/triangulation/FlowBoundingSphereLinSolv.hpp 2014-04-10 05:58:01 +0000
@@ -12,9 +12,9 @@
// #define TAUCS_LIB //comment this if TAUCS lib is not available, it will disable PARDISO lib as well
#ifdef EIGENSPARSE_LIB
- #include <eigen3/Eigen/Sparse>
- #include <eigen3/Eigen/SparseCore>
- #include <eigen3/Eigen/CholmodSupport>
+ #include <Eigen/Sparse>
+ #include <Eigen/SparseCore>
+ #include <Eigen/CholmodSupport>
#endif
#ifdef TAUCS_LIB
#define TAUCS_CORE_DOUBLE
@@ -34,7 +34,7 @@
namespace CGT {
-template<class FlowType>
+template<class _Tesselation, class FlowType=FlowBoundingSphere<_Tesselation> >
class FlowBoundingSphereLinSolv : public FlowType
{
public:
@@ -44,18 +44,19 @@
using FlowType::T;
using FlowType::currentTes;
using FlowType::boundary;
- using FlowType::y_min_id;
- using FlowType::y_max_id;
- using FlowType::DEBUG_OUT;
- using FlowType::TOLERANCE;
- using FlowType::RELAX;
+ using FlowType::yMinId;
+ using FlowType::yMaxId;
+ using FlowType::debugOut;
+ using FlowType::tolerance;
+ using FlowType::relax;
using FlowType::fluidBulkModulus;
using FlowType::reApplyBoundaryConditions;
using FlowType::pressureChanged;
using FlowType::computedOnce;
+ using FlowType::resetNetwork;
//! TAUCS DECs
- vector<Finite_cells_iterator> orderedCells;
+ vector<FiniteCellsIterator> orderedCells;
bool isLinearSystemSet;
bool isFullLinearSystemGSSet;
bool areCellsOrdered;//true when orderedCells is filled, turn it false after retriangulation
@@ -97,7 +98,7 @@
vector<int> T_jn;//(size+1);
vector<int> T_ia;//(size*5);
vector<double> T_f;//(size); // right-hand size vector object
- vector<Cell_handle> T_cells;//(size)
+ vector<CellHandle> T_cells;//(size)
int T_index;
vector<double> T_b;
@@ -143,35 +144,35 @@
FlowBoundingSphereLinSolv();
///Linear system solve
- virtual int SetLinearSystem(Real dt);
- void VectorizedGaussSeidel(Real dt);
- virtual int SetLinearSystemFullGS(Real dt);
+ virtual int setLinearSystem(Real dt);
+ void vectorizedGaussSeidel(Real dt);
+ virtual int setLinearSystemFullGS(Real dt);
- int TaucsSolveTest();
- int TaucsSolve(Real dt);
- int PardisoSolveTest();
- int PardisoSolve(Real dt);
+ int taucsSolveTest();
+ int taucsSolve(Real dt);
+ int pardisoSolveTest();
+ int pardisoSolve(Real dt);
int eigenSolve(Real dt);
- void CopyGsToCells();
- void CopyCellsToGs(Real dt);
+ void copyGsToCells();
+ void copyCellsToGs(Real dt);
- void CopyLinToCells();
- void CopyCellsToLin(Real dt);
- void swap_fwd (double* v, int i);
- void swap_fwd (int* v, int i);
- void sort_v(int k1, int k2, int* is, double* ds);
+ void copyLinToCells();
+ void copyCellsToLin(Real dt);
+ void swapFwd (double* v, int i);
+ void swapFwd (int* v, int i);
+ void sortV(int k1, int k2, int* is, double* ds);
- virtual void GaussSeidel (Real dt) {
+ virtual void gaussSeidel (Real dt) {
switch (useSolver) {
case 0:
- VectorizedGaussSeidel(dt);
+ vectorizedGaussSeidel(dt);
break;
case 1:
- TaucsSolve(dt);
+ taucsSolve(dt);
break;
case 2:
- PardisoSolve(dt);
+ pardisoSolve(dt);
break;
case 3:
eigenSolve(dt);
@@ -179,7 +180,7 @@
}
computedOnce=true;
}
- virtual void ResetNetwork();
+ virtual void resetNetwork();
};
} //namespace CGT
=== modified file 'lib/triangulation/FlowBoundingSphereLinSolv.ipp'
--- lib/triangulation/FlowBoundingSphereLinSolv.ipp 2013-11-26 15:37:26 +0000
+++ lib/triangulation/FlowBoundingSphereLinSolv.ipp 2014-03-21 18:47:45 +0000
@@ -9,8 +9,6 @@
// #define XVIEW
#include "FlowBoundingSphereLinSolv.hpp"//include after #define XVIEW
-// #include "def_types.h"
-// #include "def_flow_types.h"
#include "CGAL/constructions/constructions_on_weighted_points_cartesian_3.h"
#include <CGAL/Width_3.h>
#include <iostream>
@@ -62,15 +60,15 @@
#ifdef XVIEW
Vue3D Vue1;
#endif
-template<class FlowType>
-FlowBoundingSphereLinSolv<FlowType>::~FlowBoundingSphereLinSolv()
+template<class _Tesselation, class FlowType>
+FlowBoundingSphereLinSolv<_Tesselation,FlowType>::~FlowBoundingSphereLinSolv()
{
#ifdef TAUCS_LIB
if (Fccs) taucs_ccs_free(Fccs);
#endif
}
-template<class FlowType>
-FlowBoundingSphereLinSolv<FlowType>::FlowBoundingSphereLinSolv(): FlowType() {
+template<class _Tesselation, class FlowType>
+FlowBoundingSphereLinSolv<_Tesselation,FlowType>::FlowBoundingSphereLinSolv(): FlowType() {
useSolver=0;
isLinearSystemSet=0;
isFullLinearSystemGSSet=0;
@@ -92,10 +90,10 @@
}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::swap_fwd (double* v, int i) {double temp = v[i]; v[i]=v[i+1]; v[i+1]=temp;}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::swap_fwd (int* v, int i) {double temp = v[i]; v[i]=v[i+1]; v[i+1]=temp;}
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::swapFwd (double* v, int i) {double temp = v[i]; v[i]=v[i+1]; v[i+1]=temp;}
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::swapFwd (int* v, int i) {double temp = v[i]; v[i]=v[i+1]; v[i+1]=temp;}
//spatial sort traits to use with a pair of CGAL::sphere pointers and integer.
//template<class _Triangulation>
@@ -119,9 +117,9 @@
Less_z_3 less_z_3_object() const {return Less_z_3();}
};
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::ResetNetwork() {
- FlowType::ResetNetwork();
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::resetNetwork() {
+ FlowType::resetNetwork();
isLinearSystemSet=false;
isFullLinearSystemGSSet=false;
areCellsOrdered=false;
@@ -142,8 +140,8 @@
}
#endif
}
-template<class FlowType>
-int FlowBoundingSphereLinSolv<FlowType>::SetLinearSystem(Real dt)
+template<class _Tesselation, class FlowType>
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::setLinearSystem(Real dt)
{
RTriangulation& Tri = T[currentTes].Triangulation();
@@ -157,8 +155,8 @@
ncols=0;
///Ordered cells
orderedCells.clear();
- const Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ const FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
orderedCells.push_back(cell);
if (!cell->info().Pcondition) ++ncols;}
// //Segfault on 14.10, and useless overall since SuiteSparse has preconditionners (including metis)
@@ -187,12 +185,12 @@
T_nnz=0;}
for (int kk=0; kk<ncols;kk++) T_b[kk]=0;
///Ordered cells
- int index=0, nIndex=0; Cell_handle neighbour_cell;
+ int index=0, nIndex=0; CellHandle neighbourCell;
for (int i=0; i<n_cells; i++)
{
- Finite_cells_iterator& cell = orderedCells[i];
+ FiniteCellsIterator& cell = orderedCells[i];
///Non-ordered cells
-// for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+// for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
if (!cell->info().Pcondition) {
index=cell->info().index;
if (index==0) {
@@ -203,27 +201,27 @@
//Add diagonal term
is[T_nnz] = index;
js[T_nnz] = index;
- vs[T_nnz] = (cell->info().k_norm())[0]+ (cell->info().k_norm())[1]+ (cell->info().k_norm())[2]+ (cell->info().k_norm())[3];
+ vs[T_nnz] = (cell->info().kNorm())[0]+ (cell->info().kNorm())[1]+ (cell->info().kNorm())[2]+ (cell->info().kNorm())[3];
if (fluidBulkModulus>0) vs[T_nnz] += (1.f/(dt*fluidBulkModulus*cell->info().invVoidVolume()));
++T_nnz;
}
for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- nIndex=neighbour_cell->info().index;
- if (Tri.is_infinite(neighbour_cell)) continue;
- if (!isLinearSystemSet && !neighbour_cell->info().Pcondition) {
+ neighbourCell = cell->neighbor(j);
+ nIndex=neighbourCell->info().index;
+ if (Tri.is_infinite(neighbourCell)) continue;
+ if (!isLinearSystemSet && !neighbourCell->info().Pcondition) {
if (nIndex==0) {
- T_cells[++T_index]=neighbour_cell;
- neighbour_cell->info().index=nIndex=T_index;
+ T_cells[++T_index]=neighbourCell;
+ neighbourCell->info().index=nIndex=T_index;
} else if (index > nIndex) {
is[T_nnz] = index;
js[T_nnz] = nIndex;
- vs[T_nnz] = - (cell->info().k_norm())[j];
+ vs[T_nnz] = - (cell->info().kNorm())[j];
T_nnz++;
}
- } else if (neighbour_cell->info().Pcondition) {
+ } else if (neighbourCell->info().Pcondition) {
//ADD TO b, FIXME : use updated volume change
- T_b[index-1]+=cell->info().k_norm()[j]*neighbour_cell->info().p();
+ T_b[index-1]+=cell->info().kNorm()[j]*neighbourCell->info().p();
}
}
}
@@ -287,11 +285,11 @@
return ncols;
}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::CopyGsToCells() {for (int ii=1; ii<=ncols; ii++) T_cells[ii]->info().p()=gsP[ii];}
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::copyGsToCells() {for (int ii=1; ii<=ncols; ii++) T_cells[ii]->info().p()=gsP[ii];}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::CopyCellsToGs (Real dt)
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::copyCellsToGs (Real dt)
{
for (int ii=1; ii<=ncols; ii++){
gsP[ii]=T_cells[ii]->info().p();
@@ -300,11 +298,11 @@
}
}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::CopyLinToCells() {for (int ii=1; ii<=ncols; ii++) {T_cells[ii]->info().p()=T_x[ii-1];} }
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::copyLinToCells() {for (int ii=1; ii<=ncols; ii++) {T_cells[ii]->info().p()=T_x[ii-1];} }
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::CopyCellsToLin (Real dt)
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::copyCellsToLin (Real dt)
{
for (int ii=1; ii<=ncols; ii++) {
T_bv[ii-1]=T_b[ii-1]-T_cells[ii]->info().dv();
@@ -312,9 +310,9 @@
}
/// For Gauss Seidel, we need the full matrix
-template<class FlowType>
-// int FlowBoundingSphereLinSolv<FlowType>::SetLinearSystemFullGS()
-int FlowBoundingSphereLinSolv<FlowType>::SetLinearSystemFullGS(Real dt)
+template<class _Tesselation, class FlowType>
+// int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::SetLinearSystemFullGS()
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::setLinearSystemFullGS(Real dt)
{
//WARNING : boundary conditions (Pcondition, p values) must have been set for a correct definition
RTriangulation& Tri = T[currentTes].Triangulation();
@@ -324,18 +322,18 @@
T_index=0;
T_nnz=0;
ncols=0;
- const Finite_cells_iterator cell_end = Tri.finite_cells_end();
+ const FiniteCellsIterator cellEnd = Tri.finite_cells_end();
orderedCells.clear();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
orderedCells.push_back(cell);
if (!cell->info().Pcondition) ++ncols;
}
//FIXME: does it really help? test by commenting this "sorting" line
spatial_sort(orderedCells.begin(),orderedCells.end(), CellTraits_for_spatial_sort<RTriangulation>());
-// double P_zero=0;
-// if (y_min_id>=0 and y_max_id>y_min_id) P_zero = abs((boundary(y_min_id).value-boundary(y_max_id).value)/2);
+// double pZero=0;
+// if (yMinId>=0 and yMaxId>yMinId) pZero = abs((boundary(yMinId).value-boundary(yMaxId).value)/2);
gsP.resize(ncols+1);
// _gsP.resize(ncols+1);
gsB.resize(ncols+1);
@@ -348,7 +346,7 @@
fullAcolumns[k].resize(4);
fullAvalues[k].resize(5);
gsdV[k]=0;
-// gsP[k]=P_zero;
+// gsP[k]=pZero;
}
// _gsP[0]= &ZERO;
gsP[0]=0;
@@ -362,9 +360,9 @@
///Ordered cells
for (int i=0; i<n_cells; i++)
{
- Finite_cells_iterator& cell = orderedCells[i];
+ FiniteCellsIterator& cell = orderedCells[i];
///Non-ordered cells
-// for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+// for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
if (!cell->info().Pcondition) {
if (cell->info().index==0) {
T_cells[++T_index]=cell;
@@ -372,29 +370,29 @@
}
gsP[cell->info().index]=cell->info().pression;
//Add diagonal term
- double num = (cell->info().k_norm())[0]+ (cell->info().k_norm())[1]+ (cell->info().k_norm())[2]+ (cell->info().k_norm())[3];
+ double num = (cell->info().kNorm())[0]+ (cell->info().kNorm())[1]+ (cell->info().kNorm())[2]+ (cell->info().kNorm())[3];
if (fluidBulkModulus>0) num += (1.f/(dt*fluidBulkModulus*cell->info().invVoidVolume()));
fullAvalues[cell->info().index][4] = 1.f/num;
++T_nnz;
for (int j=0; j<4; j++) {
- Cell_handle neighbour_cell = cell->neighbor(j);
- if (Tri.is_infinite(neighbour_cell)) {
+ CellHandle neighbourCell = cell->neighbor(j);
+ if (Tri.is_infinite(neighbourCell)) {
fullAvalues[cell->info().index][j] = 0;
fullAcolumns[cell->info().index][j] = &gsP[0];
continue;}
- if (!neighbour_cell->info().Pcondition) {
- if (neighbour_cell->info().index==0) {
- T_cells[++T_index]=neighbour_cell;
- neighbour_cell->info().index=T_index;
+ if (!neighbourCell->info().Pcondition) {
+ if (neighbourCell->info().index==0) {
+ T_cells[++T_index]=neighbourCell;
+ neighbourCell->info().index=T_index;
}
++T_nnz;
- fullAvalues[cell->info().index][j] = (cell->info().k_norm())[j];
- fullAcolumns[cell->info().index][j] = &gsP[neighbour_cell->info().index];
+ fullAvalues[cell->info().index][j] = (cell->info().kNorm())[j];
+ fullAcolumns[cell->info().index][j] = &gsP[neighbourCell->info().index];
} else {
fullAvalues[cell->info().index][j] = 0;
fullAcolumns[cell->info().index][j] = &gsP[0];
- gsB[cell->info().index]+=cell->info().k_norm()[j]*neighbour_cell->info().p();
+ gsB[cell->info().index]+=cell->info().kNorm()[j]*neighbourCell->info().p();
}
}
}
@@ -404,30 +402,28 @@
///Ordered cells
for (int i=0; i<n_cells; i++)
{
- Finite_cells_iterator& cell = orderedCells[i];
+ FiniteCellsIterator& cell = orderedCells[i];
///Non-ordered cells
-// for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+// for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
if (!cell->info().Pcondition) for (int j=0; j<4; j++) {
- Cell_handle neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) && neighbour_cell->info().Pcondition)
- gsB[cell->info().index]+=cell->info().k_norm()[j]*neighbour_cell->info().p();
+ CellHandle neighbourCell = cell->neighbor(j);
+ if (!Tri.is_infinite(neighbourCell) && neighbourCell->info().Pcondition)
+ gsB[cell->info().index]+=cell->info().kNorm()[j]*neighbourCell->info().p();
}
}
isFullLinearSystemGSSet=true;
return ncols;
}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::VectorizedGaussSeidel(Real dt)
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::vectorizedGaussSeidel(Real dt)
{
// cout<<"VectorizedGaussSeidel"<<endl;
- if (!isFullLinearSystemGSSet || (isFullLinearSystemGSSet && reApplyBoundaryConditions())) SetLinearSystemFullGS(dt);
- CopyCellsToGs(dt);
+ if (!isFullLinearSystemGSSet || (isFullLinearSystemGSSet && reApplyBoundaryConditions())) setLinearSystemFullGS(dt);
+ copyCellsToGs(dt);
int j = 0;
double dp_max, p_max, sum_p, p_moy, dp_moy, sum_dp;
- double tolerance = TOLERANCE;
- double relax = RELAX;
#ifdef GS_OPEN_MP
const int num_threads=1;
@@ -490,35 +486,35 @@
if (j2==0) {
p_moy = sum_p/ncols;
dp_moy = sum_dp/ncols;
- if (DEBUG_OUT) cerr <<"GS : j="<<j<<" p_moy="<<p_moy<<" dp_moy="<<dp_moy<<endl;
+ if (debugOut) cerr <<"GS : j="<<j<<" p_moy="<<p_moy<<" dp_moy="<<dp_moy<<endl;
}
#ifdef GS_OPEN_MP
#pragma omp master
#endif
j++;
} while ((dp_max/p_max) > tolerance && j<20000 /*&& ( dp_max > tolerance )*//* &&*/ /*( j<50 )*/);
- CopyGsToCells();
+ copyGsToCells();
if (j>=20000) cerr<<"GS did not converge in 20k iterations (maybe because the reference pressure is 0?)"<<endl;
- if (DEBUG_OUT) cerr <<"GS iterations : "<<j-1<<endl;
+ if (debugOut) cerr <<"GS iterations : "<<j-1<<endl;
}
-template<class FlowType>
-void FlowBoundingSphereLinSolv<FlowType>::sort_v(int k1, int k2, int* is, double* ds){
+template<class _Tesselation, class FlowType>
+void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::sortV(int k1, int k2, int* is, double* ds){
for (int k=k1; k<k2; k++) {
int kk=k;
while (kk>=k1 && is[kk]>is[kk+1]) {
- swap_fwd(is,kk);
- swap_fwd(ds,kk);
+ swapFwd(is,kk);
+ swapFwd(ds,kk);
--kk;}
}
}
-template<class FlowType>
-int FlowBoundingSphereLinSolv<FlowType>::eigenSolve(Real dt)
+template<class _Tesselation, class FlowType>
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::eigenSolve(Real dt)
{
#ifdef EIGENSPARSE_LIB
- if (!isLinearSystemSet || (isLinearSystemSet && reApplyBoundaryConditions())) ncols = SetLinearSystem(dt);
- CopyCellsToLin(dt);
+ if (!isLinearSystemSet || (isLinearSystemSet && reApplyBoundaryConditions())) ncols = setLinearSystem(dt);
+ copyCellsToLin(dt);
//FIXME: we introduce new Eigen vectors, then we have to copy from/to c-arrays, can be optimized later
Eigen::VectorXd eb(ncols); Eigen::VectorXd ex(ncols);
for (int k=0; k<ncols; k++) eb[k]=T_bv[k];
@@ -537,7 +533,7 @@
openblas_set_num_threads(numSolveThreads);
ex = eSolver.solve(eb);
for (int k=0; k<ncols; k++) T_x[k]=ex[k];
- CopyLinToCells();
+ copyLinToCells();
#else
cerr<<"Flow engine not compiled with eigen, nothing computed if useSolver=3"<<endl;
#endif
@@ -545,19 +541,19 @@
}
-template<class FlowType>
-int FlowBoundingSphereLinSolv<FlowType>::TaucsSolve(Real dt)
+template<class _Tesselation, class FlowType>
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::taucsSolve(Real dt)
{
#ifdef TAUCS_LIB
- if (DEBUG_OUT) cerr <<endl<<"TAUCS solve"<<endl;
+ if (debugOut) cerr <<endl<<"TAUCS solve"<<endl;
double t = taucs_ctime();//timer
double t2 = taucs_ctime();//global timer
if (!isLinearSystemSet || (isLinearSystemSet && reApplyBoundaryConditions())) {
- ncols = SetLinearSystem(dt);
- if (DEBUG_OUT) cerr << "Assembling the matrix : " << taucs_ctime()-t << endl; t = taucs_ctime();}
+ ncols = setLinearSystem(dt);
+ if (debugOut) cerr << "Assembling the matrix : " << taucs_ctime()-t << endl; t = taucs_ctime();}
- CopyCellsToLin(dt);
- if (DEBUG_OUT) cerr << "Updating dv's (Yade->LinSolver) : " << taucs_ctime()-t << endl; t = taucs_ctime();
+ copyCellsToLin(dt);
+ if (debugOut) cerr << "Updating dv's (Yade->LinSolver) : " << taucs_ctime()-t << endl; t = taucs_ctime();
//taucs_logfile("stdout");//! VERY USEFULL!!!!!!!!!!! (disable to exclude output time from taucs_ctime() measurments)
taucs_double* x = &T_x[0];// the unknown vector to solve Ax=b
@@ -565,14 +561,14 @@
taucs_double* xod = &xodv[0];
if (Fccs==NULL) {
- if (DEBUG_OUT) cerr << "_entering taucs_" << endl;
+ if (debugOut) cerr << "_entering taucs_" << endl;
// 1) Reordering
taucs_ccs_order(T_A, &perm, &invperm, (char*)"metis");
- if (DEBUG_OUT) cerr << "_entering taucs_" << endl;
+ if (debugOut) cerr << "_entering taucs_" << endl;
taucs_ccs_matrix* Aod;
- if (DEBUG_OUT) cerr << "_entering taucs_" << endl;
+ if (debugOut) cerr << "_entering taucs_" << endl;
Aod = taucs_ccs_permute_symmetrically(T_A, perm, invperm);
- if (DEBUG_OUT) cerr << "Reordering : " << taucs_ctime()-t << endl; t = taucs_ctime();
+ if (debugOut) cerr << "Reordering : " << taucs_ctime()-t << endl; t = taucs_ctime();
// 2) Factoring
F = taucs_ccs_factor_llt_mf(Aod);
@@ -582,27 +578,27 @@
Fccs = taucs_supernodal_factor_to_ccs(F);
//... then delete F
taucs_supernodal_factor_free(F); F=NULL;
- if (DEBUG_OUT) cerr << "Factoring : " << taucs_ctime()-t << endl; t = taucs_ctime();
+ if (debugOut) cerr << "Factoring : " << taucs_ctime()-t << endl; t = taucs_ctime();
}
taucs_vec_permute(ncols, TAUCS_DOUBLE, &T_bv[0], bod, perm);
// 3) Back substitution and reodering the solution back
taucs_ccs_solve_llt(Fccs, xod, bod);//the ccs format (faster)
// taucs_supernodal_solve_llt(F, xod, bod);//the blackbox format (slower)
- if (DEBUG_OUT) cerr << "Solving : " << taucs_ctime()-t << endl; t = taucs_ctime();
+ if (debugOut) cerr << "Solving : " << taucs_ctime()-t << endl; t = taucs_ctime();
t = taucs_ctime();
taucs_vec_ipermute(ncols, TAUCS_DOUBLE, xod, x, perm);
// cerr << "Deordering : " << taucs_ctime()-t << endl; t = taucs_ctime();
// 4) Copy back to the triangulation
- CopyLinToCells();
+ copyLinToCells();
// cerr << "Updating P (LinSolver->Yade) : " << taucs_ctime()-t << endl;
- if (DEBUG_OUT) cerr << "Total TAUCS time ................ : " << taucs_ctime()-t2 << endl;
+ if (debugOut) cerr << "Total TAUCS time ................ : " << taucs_ctime()-t2 << endl;
#else
cerr<<"Flow engine not compiled with taucs, nothing computed if useSolver=1"<<endl;
#endif
return 0;
}
-template<class FlowType>
-int FlowBoundingSphereLinSolv<FlowType>::PardisoSolve(Real dt)
+template<class _Tesselation, class FlowType>
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::pardisoSolve(Real dt)
{
cerr <<endl<<"PardisoSolve solve"<<endl;
#ifndef PARDISO
@@ -610,29 +606,29 @@
#else
double iniT = taucs_ctime();
- if (DEBUG_OUT) cerr << "_entering pardiso_" << endl;
+ if (debugOut) cerr << "_entering pardiso_" << endl;
/* Matrix data. */
double t = taucs_ctime();//timer
bool wasLSystemSet= isLinearSystemSet;
if (!isLinearSystemSet || (isLinearSystemSet && reApplyBoundaryConditions())) {
- ncols = SetLinearSystem(dt);
- if (DEBUG_OUT) cerr << "Assembling the matrix : " << taucs_ctime()-t << endl; t = taucs_ctime();}
+ ncols = setLinearSystem(dt);
+ if (debugOut) cerr << "Assembling the matrix : " << taucs_ctime()-t << endl; t = taucs_ctime();}
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"s : set system"<<endl;
+ if (debugOut) cerr<<taucs_ctime()-t<<"s : set system"<<endl;
t=taucs_ctime();
ia = T_A->colptr;
ja = T_A->rowind;
a = T_A->values.d;
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"s : set system"<<endl;
- if (!wasLSystemSet) for (int k=0; k<ncols; k++) sort_v(ia[k],ia[k+1]-1,ja,a);
- if (DEBUG_OUT) cout<<taucs_ctime()-t<<"s for ordering CCS format"<<endl;
+ if (debugOut) cerr<<taucs_ctime()-t<<"s : set system"<<endl;
+ if (!wasLSystemSet) for (int k=0; k<ncols; k++) sortV(ia[k],ia[k+1]-1,ja,a);
+ if (debugOut) cout<<taucs_ctime()-t<<"s for ordering CCS format"<<endl;
t=taucs_ctime();
nnz = ia[ncols];
// int mtype = -2; /* Real symmetric matrix */
mtype = 2; /* Real symmetric positive def. matrix */
/* RHS and solution vectors. */
- CopyCellsToLin(dt);
+ copyCellsToLin(dt);
b = &T_bv[0];
// P_x.resize(n);
x = &T_x[0];// the unknown vector to solve Ax=b
@@ -652,9 +648,9 @@
num_procs=1;
cerr<<"Set environment OMP_NUM_THREADS to something. Pardiso needs it defined!"<<endl;
}
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"pardisoinit"<<endl;
+ if (debugOut) cerr<<taucs_ctime()-t<<"pardisoinit"<<endl;
F77_FUNC(pardisoinit)(pt, &mtype, &solver, iparm, dparm, &error);
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"pardisoinit'ed"<<endl;
+ if (debugOut) cerr<<taucs_ctime()-t<<"pardisoinit'ed"<<endl;
pardisoInitialized=true;
if (error != 0) {
if (error == -10) printf("No license file found \n");
@@ -669,7 +665,7 @@
/* .. Convert matrix from 0-based C-notation to Fortran 1-based */
/* notation. */
- if (DEBUG_OUT) cout<<taucs_ctime()-t<<"tuning"<<endl;
+ if (debugOut) cout<<taucs_ctime()-t<<"tuning"<<endl;
t=taucs_ctime();
for (i = 0; i < ncols+1; i++) {
ia[i] += 1;
@@ -677,7 +673,7 @@
for (i = 0; i < nnz; i++) {
ja[i] += 1;
}
- if (DEBUG_OUT) cout<<taucs_ctime()-t<<"s : Convert matrix from 0-based"<<endl;
+ if (debugOut) cout<<taucs_ctime()-t<<"s : Convert matrix from 0-based"<<endl;
t=taucs_ctime();
/* .. Reordering and Symbolic Factorization. This step also allocates */
/* all memory that is necessary for the factorization. */
@@ -689,7 +685,7 @@
printf("\nERROR during symbolic factorization: %d", error);
exit(1);
}
- if (DEBUG_OUT) cout<<taucs_ctime()-t<<"s : Reordering and Symbolic Factorization"<<endl;
+ if (debugOut) cout<<taucs_ctime()-t<<"s : Reordering and Symbolic Factorization"<<endl;
t=taucs_ctime();
/* .. Numerical factorization. */
@@ -702,7 +698,7 @@
printf("\nERROR during numerical factorization: %d", error);
exit(2);
}
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"s : Numerical factorization. "<<endl;
+ if (debugOut) cerr<<taucs_ctime()-t<<"s : Numerical factorization. "<<endl;
t=taucs_ctime();
}
/* .. Back substitution and iterative refinement. */
@@ -716,10 +712,10 @@
printf("\nERROR during solution: %d", error);
exit(3);
}
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"s : Back substitution and iterative refinement."<<endl;
+ if (debugOut) cerr<<taucs_ctime()-t<<"s : Back substitution and iterative refinement."<<endl;
t=taucs_ctime();
- CopyLinToCells();
- if (DEBUG_OUT) cerr<<taucs_ctime()-t<<"s : Copy back."<<endl;
+ copyLinToCells();
+ if (debugOut) cerr<<taucs_ctime()-t<<"s : Copy back."<<endl;
if (wasLSystemSet){
pTime1N++; pTime1+=(taucs_ctime()-iniT);
@@ -742,8 +738,8 @@
}
-template<class FlowType>
-int FlowBoundingSphereLinSolv<FlowType>::PardisoSolveTest()
+template<class _Tesselation, class FlowType>
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::pardisoSolveTest()
{
#ifndef PARDISO
return 0;
@@ -751,7 +747,7 @@
/* Matrix data. */
double t = taucs_ctime();//timer
bool wasLSystemSet= isLinearSystemSet;
- int n = SetLinearSystem();
+ int n = setLinearSystem();
// ncols=n;//for VectorizesGS
cout<<taucs_ctime()-t<<"s : set system"<<endl;
t=taucs_ctime();
@@ -759,7 +755,7 @@
int* ja = T_A->rowind;
double* a = T_A->values.d;
- if (!wasLSystemSet) for (int k=0; k<n; k++) sort_v(ia[k],ia[k+1]-1,ja,a);
+ if (!wasLSystemSet) for (int k=0; k<n; k++) sortV(ia[k],ia[k+1]-1,ja,a);
cout<<taucs_ctime()-t<<"s for ordering CCS format"<<endl;
t=taucs_ctime();
@@ -890,14 +886,14 @@
return 0;
#endif
}
-template<class FlowType>
-int FlowBoundingSphereLinSolv<FlowType>::TaucsSolveTest()
+template<class _Tesselation, class FlowType>
+int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::taucsSolveTest()
{
#ifdef TAUCS_LIB
cout <<endl<<"TAUCS solve test"<<endl;
double t = taucs_ctime();//timer
- ncols = SetLinearSystem();
+ ncols = setLinearSystem();
//taucs_logfile("stdout");//! VERY USEFULL!!!!!!!!!!! (disable to exclude output time from taucs_ctime() measurments)
@@ -972,8 +968,8 @@
// }
-// const Finite_cells_iterator cell_end = T[currentTes].Triangulation().finite_cells_end();
-// if (DEBUG_OUT) for (Finite_cells_iterator cell = T[currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++)
+// const FiniteCellsIterator cell_end = T[currentTes].Triangulation().finite_cells_end();
+// if (debugOut) for (FiniteCellsIterator cell = T[currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++)
// {
//
// if (cell->info().index>0) {
=== modified file 'lib/triangulation/KinematicLocalisationAnalyser.cpp'
--- lib/triangulation/KinematicLocalisationAnalyser.cpp 2012-03-12 19:57:25 +0000
+++ lib/triangulation/KinematicLocalisationAnalyser.cpp 2014-03-21 18:47:45 +0000
@@ -75,7 +75,7 @@
Delta_epsilon(2,2) = TS1->eps2 - TS0->eps2;
}
-const vector<Tenseur3>& KinematicLocalisationAnalyser::ComputeParticlesDeformation(const char* state_file1, const char* state_file0, bool usebz2)
+const vector<Tenseur3>& KinematicLocalisationAnalyser::computeParticlesDeformation(const char* state_file1, const char* state_file0, bool usebz2)
{
consecutive = false;
bz2 = usebz2;
@@ -85,7 +85,7 @@
Delta_epsilon(3,3) = TS1->eps3 - TS0->eps3;
Delta_epsilon(1,1) = TS1->eps1 - TS0->eps1;
Delta_epsilon(2,2) = TS1->eps2 - TS0->eps2;
- return ComputeParticlesDeformation();
+ return computeParticlesDeformation();
}
@@ -172,7 +172,7 @@
&& TS1->inside(T.segment(*ed_it).source())
&& TS1->inside(T.segment(*ed_it).target())) {
Segment s = T.segment(*ed_it);
- Vecteur v = s.to_vector();
+ CVector v = s.to_vector();
Real ny = abs(v.y()/sqrt(s.squared_length()));
if (Nymin < ny && ny <= Nymax) filteredList.push_back(ed_it);
@@ -193,7 +193,7 @@
bool KinematicLocalisationAnalyser::DefToFile(const char* output_file_name)
{
- ComputeParticlesDeformation();
+ computeParticlesDeformation();
Tesselation& Tes = TS1->tesselation();
RTriangulation& Tri = Tes.Triangulation();
basicVTKwritter vtk(n_real_vertices, n_real_cells);
@@ -272,7 +272,7 @@
for (Edge_iterator ed_it = T.edges_begin(); ed_it != ed_end; ++ed_it) {
if (!T.is_infinite(*ed_it)) {
Segment s = T.segment(*ed_it);
- Vecteur v = s.to_vector();
+ CVector v = s.to_vector();
Real xx = abs(v.z()/sqrt(s.squared_length()));
if (xx>0.95) edges.push_back(ed_it);
@@ -284,7 +284,7 @@
for (Edge_iterator ed_it = T.edges_begin(); ed_it != ed_end; ++ed_it) {
if (!T.is_infinite(*ed_it)) {
Segment s = T.segment(*ed_it);
- Vecteur v = s.to_vector();
+ CVector v = s.to_vector();
Real xx = abs(v.z()/sqrt(s.squared_length()));
if (xx<0.05) edges.push_back(ed_it);
@@ -296,7 +296,7 @@
for (Edge_iterator ed_it = T.edges_begin(); ed_it != ed_end; ++ed_it) {
if (!T.is_infinite(*ed_it)) {
Segment s = T.segment(*ed_it);
- Vecteur v = s.to_vector();
+ CVector v = s.to_vector();
Real xx = abs(v.z()/sqrt(s.squared_length()));
if (xx>0.65 && xx<0.75) edges.push_back(ed_it);
@@ -369,7 +369,7 @@
RTriangulation& T = state.tesselation().Triangulation();
Edge_iterator ed_end = T.edges_end();
Tenseur_sym3 Tens;
- Vecteur v;
+ CVector v;
Segment s;
for (Edge_iterator ed_it = T.edges_begin(); ed_it != ed_end; ++ed_it) {
if (!T.is_infinite(*ed_it)) {
@@ -397,7 +397,7 @@
state)
{
Tenseur_sym3 Tens;
- Vecteur v;
+ CVector v;
TriaxialState::ContactIterator cend = state.contacts_end();
for (TriaxialState::ContactIterator cit = state.contacts_begin();
@@ -438,7 +438,7 @@
vector<Real> Un_values;
Un_values.resize(edges.size());
Real UNmin(100000), UNmax(-100000);
- Vecteur branch, U;
+ CVector branch, U;
Real Un;
Vertex_handle Vh1, Vh2;
vector<Edge_iterator>::iterator ed_end = edges.end();
@@ -598,7 +598,7 @@
RTriangulation& T = (*TS1).tesselation().Triangulation();
Segment s;
- Vecteur v;
+ CVector v;
for (Edge_iterator ed_it = T.edges_begin(); ed_it != T.edges_end(); ed_it++) {
if (!T.is_infinite(*ed_it)) {
s = T.segment(*ed_it);
@@ -717,22 +717,22 @@
return output_file;
}
-Vecteur KinematicLocalisationAnalyser::Deplacement(Finite_cells_iterator cell, int facet)
+CVector KinematicLocalisationAnalyser::Deplacement(Finite_cells_iterator cell, int facet)
{
- Vecteur v(0.f, 0.f, 0.f);
+ CVector v(0.f, 0.f, 0.f);
int id;// ident. de la particule
- Vecteur fixedPoint = 0.5*((TS0->box.base-CGAL::ORIGIN)+(TS0->box.sommet-CGAL::ORIGIN));
+ CVector fixedPoint = 0.5*((TS0->box.base-CGAL::ORIGIN)+(TS0->box.sommet-CGAL::ORIGIN));
for (int i=0; i<4; i++) {
// char msg [256];
if (i!=facet) {
id = cell->vertex(i)->info().id();
- Vecteur meanFieldDisp =Vecteur(TS0->grain(id).sphere.point().x(), TS0->grain(id).sphere.point().y(), TS0->grain(id).sphere.point().z())-fixedPoint;
+ CVector meanFieldDisp =CVector(TS0->grain(id).sphere.point().x(), TS0->grain(id).sphere.point().y(), TS0->grain(id).sphere.point().z())-fixedPoint;
if (1){//fluctuations
- meanFieldDisp = Vecteur(
+ meanFieldDisp = CVector(
meanFieldDisp[0]*Delta_epsilon(0,0),
meanFieldDisp[1]*Delta_epsilon(1,1),
meanFieldDisp[2]*Delta_epsilon(2,2));
- } else meanFieldDisp=Vecteur(0,0,0);
+ } else meanFieldDisp=CVector(0,0,0);
if (consecutive) v = v + TS1->grain(id).translation-meanFieldDisp;
else v = v + (TS1->grain(id).sphere.point() - TS0->grain(id).sphere.point()-meanFieldDisp);
}
@@ -741,9 +741,9 @@
return v;
}
-void KinematicLocalisationAnalyser::Grad_u(Finite_cells_iterator cell, int facet, Vecteur &V, Tenseur3& T)
+void KinematicLocalisationAnalyser::Grad_u(Finite_cells_iterator cell, int facet, CVector &V, Tenseur3& T)
{
- Vecteur S = cross_product((cell->vertex(l_vertices[facet][1])->point())
+ CVector S = cross_product((cell->vertex(l_vertices[facet][1])->point())
- (cell->vertex(l_vertices[facet][0])->point()),
(cell->vertex(l_vertices[facet][2])->point()) -
(cell->vertex(l_vertices[facet][1])->point())) /2.f;
@@ -754,7 +754,7 @@
Tenseur3& T, bool vol_divide)// Calcule le gradient de d�p.
{
T.reset();
- Vecteur v;
+ CVector v;
for (int facet=0; facet<4; facet++) {
v = Deplacement(cell, facet);
Grad_u(cell, facet, v, T);
@@ -762,7 +762,7 @@
if (vol_divide) T/= Tesselation::Volume(cell);
}
-const vector<Tenseur3>& KinematicLocalisationAnalyser::ComputeParticlesDeformation(void)
+const vector<Tenseur3>& KinematicLocalisationAnalyser::computeParticlesDeformation(void)
{
Tesselation& Tes = TS1->tesselation();
RTriangulation& Tri = Tes.Triangulation();
@@ -777,8 +777,8 @@
Delta_epsilon(1,1) = TS1->eps1 - TS0->eps1;
Delta_epsilon(2,2) = TS1->eps2 - TS0->eps2;
- //Compute Voronoi tesselation (i.e. voronoi center of each cell)
- if (!Tes.Computed()) Tes.Compute();
+ //compute Voronoi tesselation (i.e. voronoi center of each cell)
+ if (!Tes.computed) Tes.compute();
if (ParticleDeformation.size() != (unsigned int)(Tes.Max_id() + 1)) {
ParticleDeformation.clear();
ParticleDeformation.resize(Tes.Max_id() + 1);
@@ -794,7 +794,7 @@
Finite_cells_iterator cell = Tri.finite_cells_begin();
Finite_cells_iterator cell0 = Tri.finite_cells_end();
- //Compute grad_u and volumes of all cells in the triangulation, and assign them to each of the vertices ( volume*grad_u is added here rather than grad_u, the weighted average is computed later )
+ //compute grad_u and volumes of all cells in the triangulation, and assign them to each of the vertices ( volume*grad_u is added here rather than grad_u, the weighted average is computed later )
//define the number of non-fictious cells, i.e. not in contact with a boundary
n_real_cells=0;
for (; cell != cell0; cell++) { // calcule la norme du d�viateur dans chaque cellule
@@ -839,7 +839,7 @@
return ParticleDeformation;
}
-Real KinematicLocalisationAnalyser::ComputeMacroPorosity(void)
+Real KinematicLocalisationAnalyser::computeMacroPorosity(void)
{
return (1-v_solid_total/(TS1->haut*TS1->larg*TS1->prof));
}
=== modified file 'lib/triangulation/KinematicLocalisationAnalyser.hpp'
--- lib/triangulation/KinematicLocalisationAnalyser.hpp 2012-01-20 17:31:56 +0000
+++ lib/triangulation/KinematicLocalisationAnalyser.hpp 2014-03-21 18:47:45 +0000
@@ -6,7 +6,7 @@
* GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/
-/*! \brief Computes statistics of micro-variables assuming axi-symetry.
+/*! \brief computes statistics of micro-variables assuming axi-symetry.
*/
@@ -53,7 +53,7 @@
bool DistribsToFile (const char* output_file_name);
- ///Write the averaged deformation on each grain in a file (vertices and cells lists included in the file), no need to call ComputeParticlesDeformation()
+ ///Write the averaged deformation on each grain in a file (vertices and cells lists included in the file), no need to call computeParticlesDeformation()
bool DefToFile (const char* output_file_name = "deformations");
bool DefToFile (const char* state_file1, const char* state_file0, const char* output_file_name="deformation.vtk", bool usebz2=false);
///Save/Load states using bz2 compression
@@ -78,18 +78,18 @@
void SetDisplacementIncrements (void);
///Add surface*displacement to T
- void Grad_u ( Finite_cells_iterator cell, int facet, Vecteur &V, Tenseur3& T );
- ///Compute grad_u in cell (by default, T= average grad_u in cell, if !vol_divide, T=grad_u*volume
+ void Grad_u ( Finite_cells_iterator cell, int facet, CVector &V, Tenseur3& T );
+ ///compute grad_u in cell (by default, T= average grad_u in cell, if !vol_divide, T=grad_u*volume
void Grad_u ( Finite_cells_iterator cell, Tenseur3& T, bool vol_divide=true );
- /// Compute grad_u for all particles, by summing grad_u of all adjaent cells using current states
- const vector<Tenseur3>& ComputeParticlesDeformation (void);
+ /// compute grad_u for all particles, by summing grad_u of all adjaent cells using current states
+ const vector<Tenseur3>& computeParticlesDeformation (void);
/// Do everything in one step by giving some final (file1) and initial (file0) positions
- const vector<Tenseur3>& ComputeParticlesDeformation(const char* state_file1, const char* state_file0, bool usebz2 = true);
- ///Compute porisity from cumulated spheres volumes and positions of boxes
- Real ComputeMacroPorosity (void );
+ const vector<Tenseur3>& computeParticlesDeformation(const char* state_file1, const char* state_file0, bool usebz2 = true);
+ ///compute porisity from cumulated spheres volumes and positions of boxes
+ Real computeMacroPorosity (void );
- Vecteur Deplacement ( Cell_handle cell ); //donne le d�placement d'un sommet de voronoi
- Vecteur Deplacement ( Finite_cells_iterator cell, int facet ); //mean displacement on a facet
+ CVector Deplacement ( Cell_handle cell ); //donne le d�placement d'un sommet de voronoi
+ CVector Deplacement ( Finite_cells_iterator cell, int facet ); //mean displacement on a facet
// Calcul du tenseur d'orientation des voisins
//Tenseur_sym3 Orientation_voisins (Tesselation& Tes);
=== modified file 'lib/triangulation/Network.hpp'
--- lib/triangulation/Network.hpp 2014-05-07 13:29:17 +0000
+++ lib/triangulation/Network.hpp 2014-05-09 14:24:08 +0000
@@ -26,7 +26,7 @@
struct Boundary
{
Point p;//position
- Vecteur normal;//orientation
+ CVector normal;//orientation
Vector3r velocity;//motion
int coordinate;//the axis perpendicular to the boundary
bool flowCondition;//flowCondition=0, pressure is imposed // flowCondition=1, flow is imposed
@@ -46,51 +46,49 @@
Tesselation T [2];
bool currentTes;
- double x_min, x_max, y_min, y_max, z_min, z_max, Rmoy, SectionArea, Height, Vtotale;
- bool DEBUG_OUT;
+ double xMin, xMax, yMin, yMax, zMin, zMax, Rmoy, sectionArea, Height, vTotal;
+ bool debugOut;
int nOfSpheres;
- int x_min_id, x_max_id, y_min_id, y_max_id, z_min_id, z_max_id;
+ int xMinId, xMaxId, yMinId, yMaxId, zMinId, zMaxId;
int* boundsIds [6];
- vector<Cell_handle> boundingCells [6];
- Point Corner_min;
- Point Corner_max;
- Real Vsolid_tot, Vtotalissimo, Vporale, Ssolid_tot, V_porale_porosity, V_totale_porosity;
+ vector<CellHandle> boundingCells [6];
+ Point cornerMin;
+ Point cornerMax;
+ Real VSolidTot, Vtotalissimo, vPoral, sSolidTot, vPoralPorosity, vTotalPorosity;
Boundary boundaries [6];
- Boundary& boundary (int b) {return boundaries[b-id_offset];}
- short id_offset;
- int vtk_infinite_vertices, vtk_infinite_cells, num_particles;
-
- void AddBoundingPlanes();
- void AddBoundingPlane (Vecteur Normal, int id_wall);
- void AddBoundingPlane (Real center[3], double thickness, Vecteur Normal, int id_wall );
-
- void Define_fictious_cells( );
- int detectFacetFictiousVertices (Cell_handle& cell, int& j);
- double volumeSolidPore (const Cell_handle& cell);
- double volume_single_fictious_pore(const Vertex_handle& SV1, const Vertex_handle& SV2, const Vertex_handle& SV3, const Point& PV1, const Point& PV2, Vecteur& facetSurface);
- double volume_double_fictious_pore(const Vertex_handle& SV1, const Vertex_handle& SV2, const Vertex_handle& SV3, const Point& PV1, const Point& PV2, Vecteur& facetSurface);
- double spherical_triangle_volume(const Sphere& ST1, const Point& PT1, const Point& PT2, const Point& PT3);
-
- double fast_spherical_triangle_area(const Sphere& STA1, const Point& STA2, const Point& STA3, const Point& PTA1);
- Real fast_solid_angle(const Point& STA1, const Point& PTA1, const Point& PTA2, const Point& PTA3);
- double volume_double_fictious_pore(Vertex_handle SV1, Vertex_handle SV2, Vertex_handle SV3, Point PV1);
- double volume_single_fictious_pore(Vertex_handle SV1, Vertex_handle SV2, Vertex_handle SV3, Point PV1);
- double Volume_Pore_VoronoiFraction ( Cell_handle& cell, int& j, bool reuseFacetData=false);
- double Surface_Solid_Pore( Cell_handle cell, int j, bool SLIP_ON_LATERALS, bool reuseFacetData=false);
- double spherical_triangle_area ( Sphere STA1, Sphere STA2, Sphere STA3, Point PTA1 );
-
- Vecteur surface_double_fictious_facet(Vertex_handle fSV1, Vertex_handle fSV2, Vertex_handle SV3);
- Vecteur surface_single_fictious_facet(Vertex_handle fSV1, Vertex_handle SV2, Vertex_handle SV3);
- double surface_solid_double_fictious_facet(Vertex_handle SV1, Vertex_handle SV2, Vertex_handle SV3);
- double surface_solid_facet(Sphere ST1, Sphere ST2, Sphere ST3);
-
- void Line_Solid_Pore( Cell_handle cell, int j);
- double Line_solid_facet(Sphere ST1, Sphere ST2, Sphere ST3);
+ Boundary& boundary (int b) {return boundaries[b-idOffset];}
+ short idOffset;
+ int vtkInfiniteVertices, vtkInfiniteCells, num_particles;
+
+ void addBoundingPlanes();
+ void addBoundingPlane (CVector Normal, int id_wall);
+ void addBoundingPlane (Real center[3], double thickness, CVector Normal, int id_wall );
+
+ void defineFictiousCells( );
+ int detectFacetFictiousVertices (CellHandle& cell, int& j);
+ double volumeSolidPore (const CellHandle& cell);
+ double volumeSingleFictiousPore(const VertexHandle& SV1, const VertexHandle& SV2, const VertexHandle& SV3, const Point& PV1, const Point& PV2, CVector& facetSurface);
+ double volumeDoubleFictiousPore(const VertexHandle& SV1, const VertexHandle& SV2, const VertexHandle& SV3, const Point& PV1, const Point& PV2, CVector& facetSurface);
+ double sphericalTriangleVolume(const Sphere& ST1, const Point& PT1, const Point& PT2, const Point& PT3);
+
+ double fastSphericalTriangleArea(const Sphere& STA1, const Point& STA2, const Point& STA3, const Point& PTA1);
+ Real fastSolidAngle(const Point& STA1, const Point& PTA1, const Point& PTA2, const Point& PTA3);
+ double volumeDoubleFictiousPore(VertexHandle SV1, VertexHandle SV2, VertexHandle SV3, Point PV1);
+ double volumeSingleFictiousPore(VertexHandle SV1, VertexHandle SV2, VertexHandle SV3, Point PV1);
+ double volumePoreVoronoiFraction ( CellHandle& cell, int& j, bool reuseFacetData=false);
+ double surfaceSolidPore( CellHandle cell, int j, bool slipBoundary, bool reuseFacetData=false);
+ double sphericalTriangleArea ( Sphere STA1, Sphere STA2, Sphere STA3, Point PTA1 );
+
+ CVector surfaceDoubleFictiousFacet(VertexHandle fSV1, VertexHandle fSV2, VertexHandle SV3);
+ CVector surfaceSingleFictiousFacet(VertexHandle fSV1, VertexHandle SV2, VertexHandle SV3);
+ double surfaceSolidDoubleFictiousFacet(VertexHandle SV1, VertexHandle SV2, VertexHandle SV3);
+ double surfaceSolidFacet(Sphere ST1, Sphere ST2, Sphere ST3);
+
+ void lineSolidPore(CellHandle cell, int j);
+ double lineSolidFacet(Sphere ST1, Sphere ST2, Sphere ST3);
int facetF1, facetF2, facetRe1, facetRe2, facetRe3;
- int F1, F2, Re1, Re2;
int facetNFictious;
- int real_vertex;
double FAR;
static const double ONE_THIRD;
static const int facetVertices [4][3];
@@ -102,6 +100,4 @@
#include "Network.ipp"
-
-
#endif //FLOW_ENGINE
=== modified file 'lib/triangulation/Network.ipp'
--- lib/triangulation/Network.ipp 2014-05-07 13:29:17 +0000
+++ lib/triangulation/Network.ipp 2014-05-09 14:24:08 +0000
@@ -32,46 +32,40 @@
Network<Tesselation>::Network(){
FAR = 50000;
facetF1=facetF2=facetRe1=facetRe2=facetRe3=0;
- F1=F2=Re1=Re2=0;
+// F1=F2=Re1=Re2=0;
}
template<class Tesselation>
-int Network<Tesselation>::detectFacetFictiousVertices (Cell_handle& cell, int& j)
+int Network<Tesselation>::detectFacetFictiousVertices (CellHandle& cell, int& j)
{
facetNFictious = 0;
- int real_vertex=0;
- Sphere v [3];
- Vertex_handle W [3];
-
- for (int kk=0; kk<3; kk++) {
- W[kk] = cell->vertex(facetVertices[j][kk]);
- v[kk] = cell->vertex(facetVertices[j][kk])->point();
- if (W[kk]->info().isFictious) {
- if (facetNFictious==0) {F1=facetVertices[j][kk];facetF1=kk;} else
- {F2 = facetVertices[j][kk];facetF2=kk;}
+ int nRealVtx=0;
+ for (int kk=0; kk<3; kk++) {
+ if (cell->vertex(facetVertices[j][kk])->info().isFictious) {
+ if (facetNFictious==0) facetF1=kk; else facetF2=kk;
facetNFictious +=1;
} else {
- if (real_vertex==0) {Re1=facetVertices[j][kk];facetRe1=kk;} else if (real_vertex==1)
- {Re2=facetVertices[j][kk];facetRe2=kk;} else if (real_vertex==2)
- {Re2=facetVertices[j][kk];facetRe3=kk;}
- real_vertex+=1;}}
+ if (nRealVtx==0) facetRe1=kk;
+ else if (nRealVtx==1) facetRe2=kk;
+ else if (nRealVtx==2) facetRe3=kk;
+ nRealVtx+=1;}}
return facetNFictious;
}
template<class Tesselation>
-double Network<Tesselation>::Volume_Pore_VoronoiFraction (Cell_handle& cell, int& j, bool reuseFacetData)
+double Network<Tesselation>::volumePoreVoronoiFraction (CellHandle& cell, int& j, bool reuseFacetData)
{
Point& p1 = cell->info();
Point& p2 = cell->neighbor(j)->info();
if (!reuseFacetData) facetNFictious = detectFacetFictiousVertices (cell,j);
Sphere v [3];
- Vertex_handle W [3];
+ VertexHandle W [3];
for (int kk=0; kk<3; kk++) {W[kk] = cell->vertex(facetVertices[j][kk]);v[kk] = cell->vertex(facetVertices[j][kk])->point();}
switch (facetNFictious) {
case (0) : {
- Vertex_handle& SV1 = W[0];
- Vertex_handle& SV2 = W[1];
- Vertex_handle& SV3 = W[2];
+ VertexHandle& SV1 = W[0];
+ VertexHandle& SV2 = W[1];
+ VertexHandle& SV3 = W[2];
cell->info().facetSurfaces[j]=0.5*CGAL::cross_product(SV1->point()-SV3->point(),SV2->point()-SV3->point());
if (cell->info().facetSurfaces[j][0]==0 && cell->info().facetSurfaces[j][1]==0 && cell->info().facetSurfaces[j][2]==0) cerr<<"NULL FACET SURF"<<endl;
@@ -81,37 +75,37 @@
double Vsolid1=0, Vsolid2=0;
for (int i=0;i<3;i++) {
- Vsolid1 += spherical_triangle_volume(v[permut3[i][0]],v[permut3[i][1]],p1,p2);
- Vsolid2 += spherical_triangle_volume(v[permut3[i][0]],v[permut3[i][2]],p1,p2);}
+ Vsolid1 += sphericalTriangleVolume(v[permut3[i][0]],v[permut3[i][1]],p1,p2);
+ Vsolid2 += sphericalTriangleVolume(v[permut3[i][0]],v[permut3[i][2]],p1,p2);}
- Vsolid_tot += Vsolid1 + Vsolid2;
- Vporale += Vtot - (Vsolid1 + Vsolid2);
+ VSolidTot += Vsolid1 + Vsolid2;
+ vPoral += Vtot - (Vsolid1 + Vsolid2);
bool border=false;
for (int i=0;i<4;i++){
if (cell->neighbor(i)->info().fictious()!=0) border=true;}
- if (!border) {V_porale_porosity += Vtot - (Vsolid1 + Vsolid2);
- V_totale_porosity += Vtot;}
+ if (!border) {vPoralPorosity += Vtot - (Vsolid1 + Vsolid2);
+ vTotalPorosity += Vtot;}
/**Vpore**/ return Vtot - (Vsolid1 + Vsolid2);
}; break;
- case (1) : {return volume_single_fictious_pore(cell->vertex(facetVertices[j][facetF1]), cell->vertex(facetVertices[j][facetRe1]), cell->vertex(facetVertices[j][facetRe2]), p1,p2, cell->info().facetSurfaces[j]);}; break;
- case (2) : {return volume_double_fictious_pore(cell->vertex(facetVertices[j][facetF1]), cell->vertex(facetVertices[j][facetF2]), cell->vertex(facetVertices[j][facetRe1]), p1,p2, cell->info().facetSurfaces[j]);}; break;
+ case (1) : {return volumeSingleFictiousPore(cell->vertex(facetVertices[j][facetF1]), cell->vertex(facetVertices[j][facetRe1]), cell->vertex(facetVertices[j][facetRe2]), p1,p2, cell->info().facetSurfaces[j]);}; break;
+ case (2) : {return volumeDoubleFictiousPore(cell->vertex(facetVertices[j][facetF1]), cell->vertex(facetVertices[j][facetF2]), cell->vertex(facetVertices[j][facetRe1]), p1,p2, cell->info().facetSurfaces[j]);}; break;
default : return 0;}
}
template<class Tesselation>
-double Network<Tesselation>::volumeSolidPore (const Cell_handle& cell)
+double Network<Tesselation>::volumeSolidPore (const CellHandle& cell)
{
double Vsolid=0;
for (int i=0;i<4;i++) {
- if ( !cell->vertex(permut4[i][0])->info().isFictious ) Vsolid += spherical_triangle_volume( cell->vertex(permut4[i][0])->point(), cell->vertex(permut4[i][1])->point(), cell->vertex(permut4[i][2])-> point(), cell->vertex(permut4[i][3])-> point());
+ if ( !cell->vertex(permut4[i][0])->info().isFictious ) Vsolid += sphericalTriangleVolume( cell->vertex(permut4[i][0])->point(), cell->vertex(permut4[i][1])->point(), cell->vertex(permut4[i][2])-> point(), cell->vertex(permut4[i][3])-> point());
}
return Vsolid;
}
template<class Tesselation>
-double Network<Tesselation>::volume_single_fictious_pore(const Vertex_handle& SV1, const Vertex_handle& SV2, const Vertex_handle& SV3, const Point& PV1, const Point& PV2, Vecteur& facetSurface)
+double Network<Tesselation>::volumeSingleFictiousPore(const VertexHandle& SV1, const VertexHandle& SV2, const VertexHandle& SV3, const Point& PV1, const Point& PV2, CVector& facetSurface)
{
double A [3], B[3];
@@ -125,7 +119,7 @@
Point AA(A[0],A[1],A[2]);
Point BB(B[0],B[1],B[2]);
- facetSurface = surface_single_fictious_facet(SV1,SV2,SV3);
+ facetSurface = surfaceSingleFictiousFacet(SV1,SV2,SV3);
if (facetSurface*(PV2-PV1) > 0) facetSurface = -1.0*facetSurface;
Real Vtot=ONE_THIRD*abs(facetSurface*(PV1-PV2));
Vtotalissimo += Vtot;
@@ -135,17 +129,17 @@
Sphere& SW2 = SV2->point();
Sphere& SW3 = SV3->point();
- Real Vsolid1 = spherical_triangle_volume(SW2, AA, PV1, PV2)+spherical_triangle_volume(SW2, SW3, PV1, PV2);
- Real Vsolid2 = spherical_triangle_volume(SW3, BB, PV1, PV2)+spherical_triangle_volume(SW3, SW2, PV1, PV2);
+ Real Vsolid1 = sphericalTriangleVolume(SW2, AA, PV1, PV2)+sphericalTriangleVolume(SW2, SW3, PV1, PV2);
+ Real Vsolid2 = sphericalTriangleVolume(SW3, BB, PV1, PV2)+sphericalTriangleVolume(SW3, SW2, PV1, PV2);
- Vsolid_tot += Vsolid1 + Vsolid2;
- Vporale += Vtot - (Vsolid1 + Vsolid2);
+ VSolidTot += Vsolid1 + Vsolid2;
+ vPoral += Vtot - (Vsolid1 + Vsolid2);
return (Vtot - (Vsolid1 + Vsolid2));
}
template<class Tesselation>
-double Network<Tesselation>::volume_double_fictious_pore(const Vertex_handle& SV1, const Vertex_handle& SV2, const Vertex_handle& SV3, const Point& PV1, const Point& PV2, Vecteur& facetSurface)
+double Network<Tesselation>::volumeDoubleFictiousPore(const VertexHandle& SV1, const VertexHandle& SV2, const VertexHandle& SV3, const Point& PV1, const Point& PV2, CVector& facetSurface)
{
double A [3], B[3];
@@ -163,44 +157,41 @@
Real Vtot = abs(facetSurface*(PV1-PV2))*ONE_THIRD;
Vtotalissimo += Vtot;
- Real Vsolid1 = spherical_triangle_volume(SV3->point(), AA, PV1, PV2);
- Real Vsolid2 = spherical_triangle_volume(SV3->point(), BB, PV1, PV2);
+ Real Vsolid1 = sphericalTriangleVolume(SV3->point(), AA, PV1, PV2);
+ Real Vsolid2 = sphericalTriangleVolume(SV3->point(), BB, PV1, PV2);
- Vporale += (Vtot - Vsolid1 - Vsolid2);
- Vsolid_tot += Vsolid1 + Vsolid2;
+ vPoral += (Vtot - Vsolid1 - Vsolid2);
+ VSolidTot += Vsolid1 + Vsolid2;
return (Vtot - Vsolid1 - Vsolid2);
}
template<class Tesselation>
-double Network<Tesselation>::spherical_triangle_volume(const Sphere& ST1, const Point& PT1, const Point& PT2, const Point& PT3)
+double Network<Tesselation>::sphericalTriangleVolume(const Sphere& ST1, const Point& PT1, const Point& PT2, const Point& PT3)
{
double rayon = sqrt(ST1.weight());
if (rayon == 0.0) return 0.0;
- return ((ONE_THIRD * rayon) * (fast_spherical_triangle_area(ST1, PT1, PT2, PT3))) ;
+ return ((ONE_THIRD * rayon) * (fastSphericalTriangleArea(ST1, PT1, PT2, PT3))) ;
}
template<class Tesselation>
-double Network<Tesselation>::fast_spherical_triangle_area(const Sphere& STA1, const Point& STA2, const Point& STA3, const Point& PTA1)
+double Network<Tesselation>::fastSphericalTriangleArea(const Sphere& STA1, const Point& STA2, const Point& STA3, const Point& PTA1)
{
using namespace CGAL;
-#ifndef FAST
- return spherical_triangle_area(STA1, STA2, STA3, PTA1);
-#endif
double rayon2 = STA1.weight();
if (rayon2 == 0.0) return 0.0;
- return rayon2 * fast_solid_angle(STA1,STA2,STA3,PTA1);
+ return rayon2 * fastSolidAngle(STA1,STA2,STA3,PTA1);
}
template<class Tesselation>
-double Network<Tesselation>::spherical_triangle_area ( Sphere STA1, Sphere STA2, Sphere STA3, Point PTA1 )
+double Network<Tesselation>::sphericalTriangleArea ( Sphere STA1, Sphere STA2, Sphere STA3, Point PTA1 )
{
double rayon = STA1.weight();
if ( rayon == 0.0 ) return 0.0;
- Vecteur v12 = STA2.point() - STA1.point();
- Vecteur v13 = STA3.point() - STA1.point();
- Vecteur v14 = PTA1 - STA1.point();
+ CVector v12 = STA2.point() - STA1.point();
+ CVector v13 = STA3.point() - STA1.point();
+ CVector v14 = PTA1 - STA1.point();
double norme12 = ( v12.squared_length() );
double norme13 = ( v13.squared_length() );
@@ -225,7 +216,7 @@
}
template<class Tesselation>
-Real Network<Tesselation>::fast_solid_angle(const Point& STA1, const Point& PTA1, const Point& PTA2, const Point& PTA3)
+Real Network<Tesselation>::fastSolidAngle(const Point& STA1, const Point& PTA1, const Point& PTA2, const Point& PTA3)
{
//! This function needs to be fast because it is used heavily. Avoid using vector operations which require constructing vectors (~50% of cpu time in the non-fast version), and compute angle using the 3x faster formula of Oosterom and StrackeeVan Oosterom, A; Strackee, J (1983). "The Solid Angle of a Plane Triangle". IEEE Trans. Biom. Eng. BME-30 (2): 125-126. (or check http://en.wikipedia.org/wiki/Solid_angle)
using namespace CGAL;
@@ -261,7 +252,7 @@
}
template<class Tesselation>
-double Network<Tesselation>::Surface_Solid_Pore(Cell_handle cell, int j, bool SLIP_ON_LATERALS, bool reuseFacetData)
+double Network<Tesselation>::surfaceSolidPore(CellHandle cell, int j, bool slipBoundary, bool reuseFacetData)
{
if (!reuseFacetData) facetNFictious=detectFacetFictiousVertices(cell,j);
Point& p1 = cell->info();
@@ -271,7 +262,7 @@
double Ssolid1= 0, Ssolid1n= 0, Ssolid2= 0, Ssolid2n= 0, Ssolid3= 0, Ssolid3n= 0;
Sphere v [3];
- Vertex_handle W [3];
+ VertexHandle W [3];
for (int kk=0; kk<3; kk++) {
W[kk] = cell->vertex(facetVertices[j][kk]);
@@ -279,46 +270,46 @@
switch (facetNFictious) {
case (0) : {
- Vertex_handle& SV1 = W[0];
- Vertex_handle& SV2 = W[1];
- Vertex_handle& SV3 = W[2];
+ VertexHandle& SV1 = W[0];
+ VertexHandle& SV2 = W[1];
+ VertexHandle& SV3 = W[2];
- Ssolid1 = fast_spherical_triangle_area(SV1->point(), SV2->point(), p1, p2);
- Ssolid1n = fast_spherical_triangle_area(SV1->point(), SV3->point(), p1, p2);
+ Ssolid1 = fastSphericalTriangleArea(SV1->point(), SV2->point(), p1, p2);
+ Ssolid1n = fastSphericalTriangleArea(SV1->point(), SV3->point(), p1, p2);
cell->info().solidSurfaces[j][0]=Ssolid1+Ssolid1n;
- Ssolid2 = fast_spherical_triangle_area(SV2->point(),SV1->point(),p1, p2);
- Ssolid2n = fast_spherical_triangle_area(SV2->point(),SV3->point(),p1, p2);
+ Ssolid2 = fastSphericalTriangleArea(SV2->point(),SV1->point(),p1, p2);
+ Ssolid2n = fastSphericalTriangleArea(SV2->point(),SV3->point(),p1, p2);
cell->info().solidSurfaces[j][1]=Ssolid2+Ssolid2n;
- Ssolid3 = fast_spherical_triangle_area(SV3->point(),SV2->point(),p1, p2);
- Ssolid3n = fast_spherical_triangle_area(SV3->point(),SV1->point(),p1, p2);
+ Ssolid3 = fastSphericalTriangleArea(SV3->point(),SV2->point(),p1, p2);
+ Ssolid3n = fastSphericalTriangleArea(SV3->point(),SV1->point(),p1, p2);
cell->info().solidSurfaces[j][2]=Ssolid3+Ssolid3n;
}; break;
case (1) : {
- Vertex_handle SV1 = cell->vertex(facetVertices[j][facetF1]);
- Vertex_handle SV2 = cell->vertex(facetVertices[j][facetRe1]);
- Vertex_handle SV3 = cell->vertex(facetVertices[j][facetRe2]);
+ VertexHandle SV1 = cell->vertex(facetVertices[j][facetF1]);
+ VertexHandle SV2 = cell->vertex(facetVertices[j][facetRe1]);
+ VertexHandle SV3 = cell->vertex(facetVertices[j][facetRe2]);
Boundary &bi1 = boundary(SV1->info().id());
Ssolid1 = 0;
- if (bi1.flowCondition && ! SLIP_ON_LATERALS) {
+ if (bi1.flowCondition && ! slipBoundary) {
Ssolid1 = abs(0.5*CGAL::cross_product(p1-p2, SV2->point()-SV3->point())[bi1.coordinate]);
cell->info().solidSurfaces[j][facetF1]=Ssolid1;
}
- Ssolid2 = fast_spherical_triangle_area(SV2->point(),SV1->point(),p1, p2);
- Ssolid2n = fast_spherical_triangle_area(SV2->point(),SV3->point(),p1, p2);
+ Ssolid2 = fastSphericalTriangleArea(SV2->point(),SV1->point(),p1, p2);
+ Ssolid2n = fastSphericalTriangleArea(SV2->point(),SV3->point(),p1, p2);
cell->info().solidSurfaces[j][facetRe1]=Ssolid2+Ssolid2n;
- Ssolid3 = fast_spherical_triangle_area(SV3->point(),SV2->point(),p1, p2);
- Ssolid3n = fast_spherical_triangle_area(SV3->point(),SV1->point(),p1, p2);
+ Ssolid3 = fastSphericalTriangleArea(SV3->point(),SV2->point(),p1, p2);
+ Ssolid3n = fastSphericalTriangleArea(SV3->point(),SV1->point(),p1, p2);
cell->info().solidSurfaces[j][facetRe2]=Ssolid3+Ssolid3n;
}; break;
case (2) : {
double A [3], B[3], C[3];
- Vertex_handle SV1 = cell->vertex(facetVertices[j][facetF1]);
- Vertex_handle SV2 = cell->vertex(facetVertices[j][facetF2]);
- Vertex_handle SV3 = cell->vertex(facetVertices[j][facetRe1]);
+ VertexHandle SV1 = cell->vertex(facetVertices[j][facetF1]);
+ VertexHandle SV2 = cell->vertex(facetVertices[j][facetF2]);
+ VertexHandle SV3 = cell->vertex(facetVertices[j][facetRe1]);
Boundary &bi1 = boundary(SV1->info().id());
Boundary &bi2 = boundary(SV2->info().id());
@@ -337,18 +328,18 @@
Sphere B1(BB, 0);
Sphere C1(CC, 0);
//FIXME : we are computing triangle area twice here, because its computed in volume_double_fictious already -> optimize
- Ssolid1 = fast_spherical_triangle_area(SV3->point(), AA, p1, p2);
- Ssolid1n = fast_spherical_triangle_area(SV3->point(), BB, p1, p2);
+ Ssolid1 = fastSphericalTriangleArea(SV3->point(), AA, p1, p2);
+ Ssolid1n = fastSphericalTriangleArea(SV3->point(), BB, p1, p2);
cell->info().solidSurfaces[j][facetRe1]=Ssolid1+Ssolid1n;
//area vector of triangle (p1,sphere,p2)
- Vecteur p1p2v1Surface = 0.5*CGAL::cross_product(p1-p2,SV3->point()-p2);
- if (bi1.flowCondition && ! SLIP_ON_LATERALS) {
+ CVector p1p2v1Surface = 0.5*CGAL::cross_product(p1-p2,SV3->point()-p2);
+ if (bi1.flowCondition && ! slipBoundary) {
//projection on boundary 1
Ssolid2 = abs(p1p2v1Surface[bi1.coordinate]);
cell->info().solidSurfaces[j][facetF1]=Ssolid2;
} else cell->info().solidSurfaces[j][facetF1]=0;
- if (bi2.flowCondition && ! SLIP_ON_LATERALS) {
+ if (bi2.flowCondition && ! slipBoundary) {
//projection on boundary 2
Ssolid3 = abs(p1p2v1Surface[bi2.coordinate]);
cell->info().solidSurfaces[j][facetF2]=Ssolid3;
@@ -361,14 +352,14 @@
if (Ssolid)
cell->info().solidSurfaces[j][3]=1.0/Ssolid;
else cell->info().solidSurfaces[j][3]=0;
- Ssolid_tot += Ssolid;
+ sSolidTot += Ssolid;
return Ssolid;
}
template<class Tesselation>
-Vecteur Network<Tesselation>::surface_double_fictious_facet(Vertex_handle fSV1, Vertex_handle fSV2, Vertex_handle SV3)
+CVector Network<Tesselation>::surfaceDoubleFictiousFacet(VertexHandle fSV1, VertexHandle fSV2, VertexHandle SV3)
{
//This function is correct only with axis-aligned boundaries
const Boundary &bi1 = boundary(fSV1->info().id());
@@ -377,22 +368,22 @@
double surf [3] = {1,1,1};
surf[bi1.coordinate]=0;
surf[bi2.coordinate]=0;
- return area*Vecteur(surf[0],surf[1],surf[2]);
+ return area*CVector(surf[0],surf[1],surf[2]);
}
template<class Tesselation>
-Vecteur Network<Tesselation>::surface_single_fictious_facet(Vertex_handle fSV1, Vertex_handle SV2, Vertex_handle SV3)
+CVector Network<Tesselation>::surfaceSingleFictiousFacet(VertexHandle fSV1, VertexHandle SV2, VertexHandle SV3)
{
//This function is correct only with axis-aligned boundaries
const Boundary &bi1 = boundary(fSV1->info().id());
// const Boundary &bi2 = boundary ( fSV2->info().id() );
- Vecteur mean_height = (bi1.p[bi1.coordinate]-0.5*(SV3->point()[bi1.coordinate]+SV2->point()[bi1.coordinate]))*bi1.normal;
+ CVector mean_height = (bi1.p[bi1.coordinate]-0.5*(SV3->point()[bi1.coordinate]+SV2->point()[bi1.coordinate]))*bi1.normal;
return CGAL::cross_product(mean_height,SV3->point()-SV2->point());
}
template<class Tesselation>
-double Network<Tesselation>::surface_solid_double_fictious_facet(Vertex_handle SV1, Vertex_handle SV2, Vertex_handle SV3)
+double Network<Tesselation>::surfaceSolidDoubleFictiousFacet(VertexHandle SV1, VertexHandle SV2, VertexHandle SV3)
{
double A [3], B [3];
@@ -413,20 +404,20 @@
}
total_surface = sqrt(board1 * board2);
- double solid_surface = surface_solid_facet(SV3->point(),SV2->point(),SV1->point());
+ double solid_surface = surfaceSolidFacet(SV3->point(),SV2->point(),SV1->point());
return total_surface - solid_surface;
}
template<class Tesselation>
-double Network<Tesselation>::surface_solid_facet(Sphere ST1, Sphere ST2, Sphere ST3)
+double Network<Tesselation>::surfaceSolidFacet(Sphere ST1, Sphere ST2, Sphere ST3)
{
double Area;
double squared_radius = ST1.weight();
- Vecteur v12 = ST2.point() - ST1.point();
- Vecteur v13 = ST3.point() - ST1.point();
+ CVector v12 = ST2.point() - ST1.point();
+ CVector v13 = ST3.point() - ST1.point();
double norme12 = v12.squared_length();
double norme13 = v13.squared_length();
@@ -439,114 +430,114 @@
}
template<class Tesselation>
-void Network<Tesselation>::AddBoundingPlanes()
+void Network<Tesselation>::addBoundingPlanes()
{
Tesselation& Tes = T[currentTes];
//FIXME: Id's order in boundsIds is done according to the enumerotation of boundaries from TXStressController.hpp, line 31. DON'T CHANGE IT!
- y_min_id = Tes.Max_id() + 2;
- boundsIds[0]=&y_min_id;
- y_max_id = Tes.Max_id() + 3;
- boundsIds[1]=&y_max_id;
- x_min_id = Tes.Max_id() + 0;
- boundsIds[2]=&x_min_id;
- x_max_id = Tes.Max_id() + 1;
- boundsIds[3]=&x_max_id;
- z_min_id = Tes.Max_id() + 5;
- boundsIds[4]=&z_max_id;
- z_max_id = Tes.Max_id() + 6;
- boundsIds[5]=&z_min_id;
-
- Corner_min = Point(x_min, y_min, z_min);
- Corner_max = Point(x_max, y_max, z_max);
-
- id_offset = Tes.Max_id() +1;//so that boundaries[vertex->id - offset] gives the ordered boundaries (also see function Boundary& boundary(int b))
-
- AddBoundingPlane (Vecteur(0,1,0) , y_min_id);
- AddBoundingPlane (Vecteur(0,-1,0) , y_max_id);
- AddBoundingPlane (Vecteur(-1,0,0) , x_max_id);
- AddBoundingPlane (Vecteur(1,0,0) , x_min_id);
- AddBoundingPlane (Vecteur(0,0,1) , z_min_id);
- AddBoundingPlane (Vecteur(0,0,-1) , z_max_id);
+ yMinId = Tes.Max_id() + 2;
+ boundsIds[0]=&yMinId;
+ yMaxId = Tes.Max_id() + 3;
+ boundsIds[1]=&yMaxId;
+ xMinId = Tes.Max_id() + 0;
+ boundsIds[2]=&xMinId;
+ xMaxId = Tes.Max_id() + 1;
+ boundsIds[3]=&xMaxId;
+ zMinId = Tes.Max_id() + 5;
+ boundsIds[4]=&zMaxId;
+ zMaxId = Tes.Max_id() + 6;
+ boundsIds[5]=&zMinId;
+
+ cornerMin = Point(xMin, yMin, zMin);
+ cornerMax = Point(xMax, yMax, zMax);
+
+ idOffset = Tes.Max_id() +1;//so that boundaries[vertex->id - offset] gives the ordered boundaries (also see function Boundary& boundary(int b))
+
+ addBoundingPlane (CVector(0,1,0) , yMinId);
+ addBoundingPlane (CVector(0,-1,0) , yMaxId);
+ addBoundingPlane (CVector(-1,0,0) , xMaxId);
+ addBoundingPlane (CVector(1,0,0) , xMinId);
+ addBoundingPlane (CVector(0,0,1) , zMinId);
+ addBoundingPlane (CVector(0,0,-1) , zMaxId);
-// AddBoundingPlanes(true);
+// addBoundingPlanes(true);
}
template<class Tesselation>
-void Network<Tesselation>::AddBoundingPlane (Vecteur Normal, int id_wall)
+void Network<Tesselation>::addBoundingPlane (CVector Normal, int id_wall)
{
// Tesselation& Tes = T[currentTes];
//FIXME: pre-condition: the normal is axis-aligned
int Coordinate = abs(Normal[0])*0 + abs(Normal[1])*1 + abs(Normal[2])*2;
double pivot = Normal[Coordinate]<0 ?
- Corner_max.x()*abs(Normal[0])+Corner_max.y()*abs(Normal[1])+Corner_max.z()*abs(Normal[2]) : Corner_min.x()*abs(Normal[0])+Corner_min.y()*abs(Normal[1])+Corner_min.z()*abs(Normal[2]);
+ cornerMax.x()*abs(Normal[0])+cornerMax.y()*abs(Normal[1])+cornerMax.z()*abs(Normal[2]) : cornerMin.x()*abs(Normal[0])+cornerMin.y()*abs(Normal[1])+cornerMin.z()*abs(Normal[2]);
- Real center [3] ={ 0.5*(Corner_min.x() +Corner_max.x())*(1-abs(Normal[0]))+pivot*abs(Normal[0]),
- 0.5*(Corner_max.y() +Corner_min.y())*(1-abs(Normal[1]))+pivot*abs(Normal[1]),
- 0.5*(Corner_max.z() +Corner_min.z())*(1-abs(Normal[2]))+pivot*abs(Normal[2])};
+ Real center [3] ={ 0.5*(cornerMin.x() +cornerMax.x())*(1-abs(Normal[0]))+pivot*abs(Normal[0]),
+ 0.5*(cornerMax.y() +cornerMin.y())*(1-abs(Normal[1]))+pivot*abs(Normal[1]),
+ 0.5*(cornerMax.z() +cornerMin.z())*(1-abs(Normal[2]))+pivot*abs(Normal[2])};
- AddBoundingPlane(center,0,Normal,id_wall);
+ addBoundingPlane(center,0,Normal,id_wall);
}
template<class Tesselation>
-void Network<Tesselation>::AddBoundingPlane (Real center[3], double thickness, Vecteur Normal, int id_wall )
+void Network<Tesselation>::addBoundingPlane (Real center[3], double thickness, CVector Normal, int id_wall )
{
Tesselation& Tes = T[currentTes];
int Coordinate = abs(Normal[0])*0 + abs(Normal[1])*1 + abs(Normal[2])*2;
- Tes.insert((center[0]+Normal[0]*thickness/2)*(1-abs(Normal[0])) + (center[0]+Normal[0]*thickness/2-Normal[0]*FAR*(Corner_max.y()-Corner_min.y()))*abs(Normal[0]),
- (center[1]+Normal[1]*thickness/2)*(1-abs(Normal[1])) + (center[1]+Normal[1]*thickness/2-Normal[1]*FAR*(Corner_max.y()-Corner_min.y()))*abs(Normal[1]),
- (center[2]+Normal[2]*thickness/2)*(1-abs(Normal[2])) + (center[2]+Normal[2]*thickness/2-Normal[2]*FAR*(Corner_max.y()-Corner_min.y()))*abs(Normal[2]),
- FAR*(Corner_max.y()-Corner_min.y()), id_wall, true);
+ Tes.insert((center[0]+Normal[0]*thickness/2)*(1-abs(Normal[0])) + (center[0]+Normal[0]*thickness/2-Normal[0]*FAR*(cornerMax.y()-cornerMin.y()))*abs(Normal[0]),
+ (center[1]+Normal[1]*thickness/2)*(1-abs(Normal[1])) + (center[1]+Normal[1]*thickness/2-Normal[1]*FAR*(cornerMax.y()-cornerMin.y()))*abs(Normal[1]),
+ (center[2]+Normal[2]*thickness/2)*(1-abs(Normal[2])) + (center[2]+Normal[2]*thickness/2-Normal[2]*FAR*(cornerMax.y()-cornerMin.y()))*abs(Normal[2]),
+ FAR*(cornerMax.y()-cornerMin.y()), id_wall, true);
Point P (center[0],center[1],center[2]);
- boundaries[id_wall-id_offset].p = P;
- boundaries[id_wall-id_offset].normal = Normal;
- boundaries[id_wall-id_offset].coordinate = Coordinate;
-
- boundaries[id_wall-id_offset].flowCondition = 1;
- boundaries[id_wall-id_offset].value = 0;
-
- if(DEBUG_OUT) cout << "A boundary -center/thick- has been created. ID = " << id_wall << " position = " << (center[0]+Normal[0]*thickness/2)*(1-abs(Normal[0])) + (center[0]+Normal[0]*thickness/2-Normal[0]*FAR*(Corner_max.y()-Corner_min.y()))*abs(Normal[0]) << " , " << (center[1]+Normal[1]*thickness/2)*(1-abs(Normal[1])) + (center[1]+Normal[1]*thickness/2-Normal[1]*FAR*(Corner_max.y()-Corner_min.y()))*abs(Normal[1]) << " , " << (center[2]+Normal[2]*thickness/2)*(1-abs(Normal[2])) + (center[2]+Normal[2]*thickness/2-Normal[2]*FAR*(Corner_max.y()-Corner_min.y()))*abs(Normal[2]) << ". Radius = " << FAR*(Corner_max.y()-Corner_min.y()) << endl;
+ boundaries[id_wall-idOffset].p = P;
+ boundaries[id_wall-idOffset].normal = Normal;
+ boundaries[id_wall-idOffset].coordinate = Coordinate;
+
+ boundaries[id_wall-idOffset].flowCondition = 1;
+ boundaries[id_wall-idOffset].value = 0;
+
+ if(debugOut) cout << "A boundary -center/thick- has been created. ID = " << id_wall << " position = " << (center[0]+Normal[0]*thickness/2)*(1-abs(Normal[0])) + (center[0]+Normal[0]*thickness/2-Normal[0]*FAR*(cornerMax.y()-cornerMin.y()))*abs(Normal[0]) << " , " << (center[1]+Normal[1]*thickness/2)*(1-abs(Normal[1])) + (center[1]+Normal[1]*thickness/2-Normal[1]*FAR*(cornerMax.y()-cornerMin.y()))*abs(Normal[1]) << " , " << (center[2]+Normal[2]*thickness/2)*(1-abs(Normal[2])) + (center[2]+Normal[2]*thickness/2-Normal[2]*FAR*(cornerMax.y()-cornerMin.y()))*abs(Normal[2]) << ". Radius = " << FAR*(cornerMax.y()-cornerMin.y()) << endl;
}
template<class Tesselation>
-void Network<Tesselation>::Define_fictious_cells()
+void Network<Tesselation>::defineFictiousCells()
{
RTriangulation& Tri = T[currentTes].Triangulation();
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
cell->info().fictious()=0;}
for (int bound=0; bound<6;bound++) {
int& id = *boundsIds[bound];
if (id<0) continue;
- Vector_Cell tmp_cells;
- tmp_cells.resize(10000);
- VCell_iterator cells_it = tmp_cells.begin();
- VCell_iterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[id],cells_it);
- for (VCell_iterator it = tmp_cells.begin(); it != cells_end; it++)
+ VectorCell tmpCells;
+ tmpCells.resize(10000);
+ VCellIterator cells_it = tmpCells.begin();
+ VCellIterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[id],cells_it);
+ for (VCellIterator it = tmpCells.begin(); it != cells_end; it++)
{
- Cell_handle& cell = *it;
+ CellHandle& cell = *it;
(cell->info().fictious())+=1;
cell->info().isFictious=true;
}
}
- if(DEBUG_OUT) cout << "Fictious cell defined" << endl;
+ if(debugOut) cout << "Fictious cell defined" << endl;
}
-// double Network::spherical_triangle_area ( Sphere STA1, Sphere STA2, Sphere STA3, Point PTA1 )
+// double Network::sphericalTriangleArea ( Sphere STA1, Sphere STA2, Sphere STA3, Point PTA1 )
// {
// double rayon = STA1.weight();
// if ( rayon == 0.0 ) return 0.0;
//
-// Vecteur v12 = STA2.point() - STA1.point();
-// Vecteur v13 = STA3.point() - STA1.point();
-// Vecteur v14 = PTA1 - STA1.point();
+// CVector v12 = STA2.point() - STA1.point();
+// CVector v13 = STA3.point() - STA1.point();
+// CVector v14 = PTA1 - STA1.point();
//
// double norme12 = ( v12.squared_length() );
// double norme13 = ( v13.squared_length() );
@@ -571,12 +562,12 @@
// }
template<class Tesselation>
-void Network<Tesselation>::Line_Solid_Pore(Cell_handle cell, int j)
+void Network<Tesselation>::lineSolidPore(CellHandle cell, int j)
{
facetNFictious=detectFacetFictiousVertices(cell,j);
double solidLine = 0; //total of solidLine[j][0], solidLine[j][1], solidLine[j][2].
Sphere v [3];
- Vertex_handle W [3];
+ VertexHandle W [3];
for (int kk=0; kk<3; kk++) {
W[kk] = cell->vertex(facetVertices[j][kk]);
@@ -584,21 +575,21 @@
switch (facetNFictious) {
case (0) : {
- Vertex_handle& SV1 = W[0];
- Vertex_handle& SV2 = W[1];
- Vertex_handle& SV3 = W[2];
+ VertexHandle& SV1 = W[0];
+ VertexHandle& SV2 = W[1];
+ VertexHandle& SV3 = W[2];
- cell->info().solidLine[j][0]=Line_solid_facet(SV1->point(), SV2->point(), SV3->point());
- cell->info().solidLine[j][1]=Line_solid_facet(SV2->point(), SV3->point(), SV1->point());
- cell->info().solidLine[j][2]=Line_solid_facet(SV3->point(), SV1->point(), SV2->point());
+ cell->info().solidLine[j][0]=lineSolidFacet(SV1->point(), SV2->point(), SV3->point());
+ cell->info().solidLine[j][1]=lineSolidFacet(SV2->point(), SV3->point(), SV1->point());
+ cell->info().solidLine[j][2]=lineSolidFacet(SV3->point(), SV1->point(), SV2->point());
}; break;
case (1) : {
- Vertex_handle SV1 = cell->vertex(facetVertices[j][facetRe1]);
- Vertex_handle SV2 = cell->vertex(facetVertices[j][facetRe2]);
- Vertex_handle SV3 = cell->vertex(facetVertices[j][facetF1]);
+ VertexHandle SV1 = cell->vertex(facetVertices[j][facetRe1]);
+ VertexHandle SV2 = cell->vertex(facetVertices[j][facetRe2]);
+ VertexHandle SV3 = cell->vertex(facetVertices[j][facetF1]);
- cell->info().solidLine[j][facetRe1]=Line_solid_facet(SV2->point(), SV3->point(), SV1->point());
- cell->info().solidLine[j][facetRe2]=Line_solid_facet(SV3->point(), SV1->point(), SV2->point());
+ cell->info().solidLine[j][facetRe1]=lineSolidFacet(SV2->point(), SV3->point(), SV1->point());
+ cell->info().solidLine[j][facetRe2]=lineSolidFacet(SV3->point(), SV1->point(), SV2->point());
Boundary &bi = boundary(SV3->info().id());
double A [3], B[3];
@@ -607,13 +598,13 @@
B[bi.coordinate]=bi.p[bi.coordinate];
Point AA(A[0],A[1],A[2]);
Point BB(B[0],B[1],B[2]);
- Vecteur AB= AA-BB;
+ CVector AB= AA-BB;
cell->info().solidLine[j][facetF1]=sqrt(AB.squared_length());
}; break;
case (2) : {
- Vertex_handle SV1 = cell->vertex(facetVertices[j][facetF1]);
- Vertex_handle SV2 = cell->vertex(facetVertices[j][facetF2]);
- Vertex_handle SV3 = cell->vertex(facetVertices[j][facetRe1]);
+ VertexHandle SV1 = cell->vertex(facetVertices[j][facetF1]);
+ VertexHandle SV2 = cell->vertex(facetVertices[j][facetF2]);
+ VertexHandle SV3 = cell->vertex(facetVertices[j][facetRe1]);
cell->info().solidLine[j][facetRe1]=0.5*M_PI*sqrt(SV3->point().weight());
@@ -627,26 +618,25 @@
}; break;
}
- double Lsolid = cell->info().solidLine[j][0] + cell->info().solidLine[j][1] + cell->info().solidLine[j][2];
- if (Lsolid)
- cell->info().solidLine[j][3]=1.0/Lsolid;
+ double lSolid = cell->info().solidLine[j][0] + cell->info().solidLine[j][1] + cell->info().solidLine[j][2];
+ if (lSolid)
+ cell->info().solidLine[j][3]=1.0/lSolid;
else cell->info().solidLine[j][3]=0;
}
-
template<class Tesselation>
-double Network<Tesselation>::Line_solid_facet(Sphere ST1, Sphere ST2, Sphere ST3)
+double Network<Tesselation>::lineSolidFacet(Sphere ST1, Sphere ST2, Sphere ST3)
{
- double Line;
- double squared_radius = ST1.weight();
- Vecteur v12 = ST2.point() - ST1.point();
- Vecteur v13 = ST3.point() - ST1.point();
+ double line;
+ double squaredRadius = ST1.weight();
+ CVector v12 = ST2.point() - ST1.point();
+ CVector v13 = ST3.point() - ST1.point();
double norme12 = v12.squared_length();
double norme13 = v13.squared_length();
double cosA = v12*v13 / (sqrt(norme13 * norme12));
- Line = acos(cosA) * sqrt(squared_radius);
- return Line;
+ line = acos(cosA) * sqrt(squaredRadius);
+ return line;
}
} //namespace CGT
=== removed file 'lib/triangulation/PeriodicFlow.cpp'
--- lib/triangulation/PeriodicFlow.cpp 2013-11-21 01:28:17 +0000
+++ lib/triangulation/PeriodicFlow.cpp 1970-01-01 00:00:00 +0000
@@ -1,650 +0,0 @@
-#ifdef FLOW_ENGINE
-
-#include"PeriodicFlow.hpp"
-
-#define FAST
-#define TESS_BASED_FORCES
-#define FACET_BASED_FORCES 1
-
-#ifdef YADE_OPENMP
-// #define GS_OPEN_MP //It should never be defined if Yade is not using openmp
-#endif
-
-
-namespace CGT {
-
-void PeriodicFlow::Interpolate(Tesselation& Tes, Tesselation& NewTes)
-{
- Cell_handle old_cell;
-// RTriangulation& NewTri = NewTes.Triangulation();
- RTriangulation& Tri = Tes.Triangulation();
-// Finite_cells_iterator cell_end = NewTri.finite_cells_end();
- for (Vector_Cell::iterator cell_it=NewTes.cellHandles.begin(); cell_it!=NewTes.cellHandles.end(); cell_it++){
- Cell_handle& new_cell = *cell_it;
-// for (Finite_cells_iterator new_cell = NewTri.finite_cells_begin(); new_cell != cell_end; new_cell++) {
- if (new_cell->info().Pcondition || new_cell->info().isGhost) continue;
- Vecteur center ( 0,0,0 );
- if (new_cell->info().fictious()==0) for ( int k=0;k<4;k++ ) center= center + 0.25* (Tes.vertex(new_cell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
- else {
- Real boundPos=0; int coord=0;
- for ( int k=0;k<4;k++ ) {
- if (!new_cell->vertex (k)->info().isFictious) center= center+0.3333333333*(Tes.vertex(new_cell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
- else {
- coord=boundary (new_cell->vertex(k)->info().id()).coordinate;
- boundPos=boundary (new_cell->vertex(k)->info().id()).p[coord];
- }
- }
- center=Vecteur(coord==0?boundPos:center[0],coord==1?boundPos:center[1],coord==2?boundPos:center[2]);
- }
- old_cell = Tri.locate(Point(center[0],center[1],center[2]));
- new_cell->info().p() = old_cell->info().shiftedP();
- }
-// Tes.Clear();//Don't reset to avoid segfault when getting pressure in scripts just after interpolation
-}
-
-
-
-void PeriodicFlow::ComputeFacetForcesWithCache(bool onlyCache)
-{
- RTriangulation& Tri = T[currentTes].Triangulation();
- Vecteur nullVect(0,0,0);
- static vector<Vecteur> oldForces;
- if (oldForces.size()<=Tri.number_of_vertices()) oldForces.resize(Tri.number_of_vertices()+1);
- //reset forces
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
- if (noCache) {oldForces[v->info().id()]=nullVect; v->info().forces=nullVect;}
- else {oldForces[v->info().id()]=v->info().forces; v->info().forces=nullVect;}
- }
-// #ifdef EIGENSPARSE_LIB
-// typedef Eigen::Triplet<double> ETriplet;
-// std::vector<ETriplet> tripletList;//The list of non-zero components in Eigen sparse matrix
-// std::vector<ETriplet> shiftsList;//The list of non-zero components in Eigen sparse matrix
-// std::vector<ETriplet> FRHSList;//The list of non-zero components in Eigen sparse matrix
-// unsigned int nPCells=0;
-// #endif
- Cell_handle neighbour_cell;
- Vertex_handle mirror_vertex;
- Vecteur tempVect;
-
- //FIXME : Ema, be carefull with this (noCache), it needs to be turned true after retriangulation
- if (noCache) {
- for (Vector_Cell::iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
- Cell_handle& cell = *cell_it;
- 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))) {
-// #ifdef EIGENSPARSE_LIB
-// if (!cell->info().Pcondition) ++nPCells;
-// #endif
- neighbour_cell = cell->neighbor(j);
- const Vecteur& 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());
- Vecteur facetNormal = Surfk/area;
- const std::vector<Vecteur>& crossSections = cell->info().facetSphereCrossSections;
- Vecteur 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[boundary(cell->vertex(j)->info().id()).coordinate]);
- tempVect=-projSurf*boundary(cell->vertex(j)->info().id()).normal;
- //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
- Vecteur Facet_Unit_Force = -fluidSurfk*cell->info().solidSurfaces[j][3];
- for (int y=0; y<3;y++) {
- //add to cached value
- cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]+Facet_Unit_Force*cell->info().solidSurfaces[j][y];
- //uncomment to get total force / comment to get only viscous forces (Bruno)
- if (!cell->vertex(facetVertices[j][y])->info().isFictious) {
- //add to cached value
- cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]-facetNormal*crossSections[j][y];
- }
- }
- }
-// #ifdef EIGENSPARSE_LIB //Problem:
-// for (int jj=0; jj<4; jj++) if (!Tri.is_infinite(cell->neighbor(jj))) {
-// for (unsigned int dim=0; dim<3; dim++) {
-// if (!cell->info().Pcondition) {
-// tripletList.push_back(ETriplet(
-// 3*cell->vertex(jj)->info().id()+dim,
-// cell->info().index-1,
-// cell->info().unitForceVectors[jj][dim]));
-//
-// if (cell->vertex(jj)->info().period[dim])
-// shiftsList.push_back(ETriplet(
-// 3*cell->vertex(jj)->info().id()+dim,
-// 0,
-// cell->vertex(jj)->info().period[dim]));
-// } else {
-// FRHSList.push_back(ETriplet(
-// 3*cell->vertex(jj)->info().id()+dim,
-// 0,
-// cell->info().unitForceVectors[jj][dim]*cell->info().p()));
-// }
-// }
-// }
-// #endif
- }
-
-// #ifdef EIGENSPARSE_LIB
-// cerr<<"set triplets"<<endl;
-// FIntegral.resize(Tri.number_of_vertices()*3,nPCells);
-// PshiftsInts.resize(Tri.number_of_vertices()*3,3);
-// FRHS.resize(Tri.number_of_vertices()*3,1);
-//
-// FIntegral.setFromTriplets(tripletList.begin(),tripletList.end());
-// PshiftsInts.setFromTriplets(shiftsList.begin(),shiftsList.end());
-// FRHS.setFromTriplets(FRHSList.begin(),FRHSList.end());
-//
-// Vector3r pDelts;
-// for (unsigned int k=0; k<3;k++) pDelts(k) = PeriodicCellInfo::hSize[k]*PeriodicCellInfo::gradP;
-// Eigen::MatrixXd p(nPCells,1);
-// for (Vector_Cell::iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++)
-// {
-// if (!(*cell_it)->info().Pcondition) p[(*cell_it)->info().index-1]=(*cell_it)->info().p();
-// }
-// forces.resize(Tri.number_of_vertices()*3);
-// cerr<<"compute and display forces"<<endl;
-// forces = FIntegral * p;
-// for (int jj=0;jj<30;jj++) cerr <<"force: "<<forces(3*jj)<<" "<<forces(3*jj+1)<<" "<<forces(3*jj+2)<<endl;
-// #endif
- noCache=false;//cache should always be defined after execution of this function
- if (onlyCache) return;
- }// end if(noCache)
-
- //use cached values
- //First define products that will be used below for all cells:
- Real pDeltas [3];
- for (unsigned int k=0; k<3;k++) pDeltas[k]=PeriodicCellInfo::hSize[k]*PeriodicCellInfo::gradP;
- //Then compute the forces
- for (Vector_Cell::iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
- const Cell_handle& cell = *cell_it;
- for (int yy=0;yy<4;yy++) {
- Vertex_Info& vhi = cell->vertex(yy)->info();
- Real unshiftedP = cell->info().p();
- //the pressure translated to a ghost cell adjacent to the non-ghost vertex
- unshiftedP -= pDeltas[0]*vhi.period[0] + pDeltas[1]*vhi.period[1] +pDeltas[2]*vhi.period[2];
- T[currentTes].vertexHandles[vhi.id()]->info().forces=T[currentTes].vertexHandles[vhi.id()]->info().forces + cell->info().unitForceVectors[yy]*unshiftedP;
- }
- }
- if (DEBUG_OUT) {
- Vecteur TotalForce = nullVect;
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); v++)
- {
- if (!v->info().isFictious /*&& !v->info().isGhost*/ ){
- TotalForce = TotalForce + v->info().forces;
-// cerr<< "real_id = " << v->info().id() << " force = "<< v->info().forces<< " ghost:"<< v->info().isGhost <<endl;
- }
-// cout << "real_id = " << v->info().id() << " force = " << v->info().forces << endl;
- else /*if (!v->info().isGhost)*/{
- if (boundary(v->info().id()).flowCondition==1) TotalForce = TotalForce + v->info().forces;
-// cout << "fictious_id = " << v->info().id() << " force = " << v->info().forces << " ghost:"<< v->info().isGhost<< endl;
- }
- }
- cout << "TotalForce = "<< TotalForce << endl;}
-}
-
-void PeriodicFlow::Compute_Permeability()
-{
- if (DEBUG_OUT) cout << "----Computing_Permeability (Periodic)------" << endl;
- RTriangulation& Tri = T[currentTes].Triangulation();
- Vsolid_tot = 0, Vtotalissimo = 0, Vporale = 0, Ssolid_tot = 0, V_totale_porosity=0, V_porale_porosity=0;
- Cell_handle neighbour_cell;
-
- double k=0, distance = 0, radius = 0, viscosity = VISCOSITY;
- int surfneg=0;
- int NEG=0, POS=0, pass=0;
-
-
-// Vecteur n;
-// std::ofstream oFile( "Radii",std::ios::out);
-// std::ofstream fFile( "Radii_Fictious",std::ios::out);
-// std::ofstream kFile ( "LocalPermeabilities" ,std::ios::app );
- Real meanK=0, STDEV=0, meanRadius=0, meanDistance=0;
- Real infiniteK=1e3;
-
- double volume_sub_pore = 0.f;
- Vector_Cell& cellHandles= T[currentTes].cellHandles;
- for (Vector_Cell::iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
- Cell_handle& cell = *cell_it;
- Point& p1 = cell->info();
- for (int j=0; j<4; j++){
- neighbour_cell = cell->neighbor(j);
- Point& p2 = neighbour_cell->info();
- if (!Tri.is_infinite(neighbour_cell) /*&& (neighbour_cell->info().isvisited==ref || computeAllCells)*/) {
- //Compute and store the area of sphere-facet intersections for later use
- Vertex_handle W [3];
- for (int kk=0; kk<3; kk++) {
- W[kk] = cell->vertex(facetVertices[j][kk]);
- }
- Sphere& v0 = W[0]->point();
- Sphere& v1 = W[1]->point();
- Sphere& v2 = W[2]->point();
-#ifdef USE_FAST_MATH
- //FIXME : code not compiling,, do the same as in "else"
- assert((W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())>=0 && (W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())<=1);
- for (int jj=0;jj<3;jj++)
- cell->info().facetSphereCrossSections[j][jj]=0.5*W[jj]->point().weight()*Wm3::FastInvCos1((W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point()));
-#else
- cell->info().facetSphereCrossSections[j]=Vecteur(
- W[0]->info().isFictious ? 0 : 0.5*v0.weight()*acos((v1-v0)*(v2-v0)/sqrt((v1-v0).squared_length()*(v2-v0).squared_length())),
- W[1]->info().isFictious ? 0 : 0.5*v1.weight()*acos((v0-v1)*(v2-v1)/sqrt((v1-v0).squared_length()*(v2-v1).squared_length())),
- W[2]->info().isFictious ? 0 : 0.5*v2.weight()*acos((v0-v2)*(v1-v2)/sqrt((v1-v2).squared_length()*(v2-v0).squared_length())));
-#endif
- pass+=1;
- Vecteur l = p1 - p2;
- distance = sqrt(l.squared_length());
- if (!RAVERAGE) radius = 2* Compute_HydraulicRadius(cell, j);
- else radius = (Compute_EffectiveRadius(cell, j)+Compute_EquivalentRadius(cell,j))*0.5;
- if (radius<0) NEG++;
- else POS++;
- if (radius==0) {
- cout << "INS-INS PROBLEM!!!!!!!" << endl;
- }
- Real fluidArea=0;
- int test=0;
- if (distance!=0) {
- if (minPermLength>0 && distance_correction) distance=max(minPermLength,distance);
- const Vecteur& Surfk = cell->info().facetSurfaces[j];
- Real area = sqrt(Surfk.squared_length());
- const Vecteur& crossSections = cell->info().facetSphereCrossSections[j];
-// if (areaR2Permeability){
-// Real m1=sqrt((cross_product((v0-v1),v2-v1)).squared_length()/(v2-v1).squared_length());
- Real S0=0;
- S0=checkSphereFacetOverlap(v0,v1,v2);
- if (S0==0) S0=checkSphereFacetOverlap(v1,v2,v0);
- if (S0==0) S0=checkSphereFacetOverlap(v2,v0,v1);
- //take absolute value, since in rare cases the surface can be negative (overlaping spheres)
- fluidArea=abs(area-crossSections[0]-crossSections[1]-crossSections[2]+S0);
- cell->info().facetFluidSurfacesRatio[j]=fluidArea/area;
- k=(fluidArea * pow(radius,2)) / (8*viscosity*distance);
-// } else {
-// cout << "WARNING! if !areaR2Permeability, facetFluidSurfacesRatio will not be defined correctly. Don't use that."<<endl;
-// k = (M_PI * pow(radius,4)) / (8*viscosity*distance);
-// }
- meanDistance += distance;
- meanRadius += radius;
- meanK += k*k_factor;
-
- if (k<0 && DEBUG_OUT) {surfneg+=1;
- cout<<"__ k<0 __"<<k<<" "<<" fluidArea "<<fluidArea<<" area "<<area<<" "<<crossSections[0]<<" "<<crossSections[1]<<" "<<crossSections[2] <<" "<<W[0]->info().id()<<" "<<W[1]->info().id()<<" "<<W[2]->info().id()<<" "<<p1<<" "<<p2<<" test "<<test<<endl;}
-
- } else {
- cout <<"infinite K2! surfaces will be missing (FIXME)"<<endl; k = infiniteK;
- }//Will be corrected in the next loop
- (cell->info().k_norm())[j]= k*k_factor;
- if (!neighbour_cell->info().isGhost) (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]= (cell->info().k_norm())[j];
- //The following block is correct but very usefull, since all values are clamped below with MIN and MAX, skip for now
-// else {//find the real neighbor connected to our cell through periodicity
-// Cell_handle true_neighbour_cell = cellHandles[neighbour_cell->info().baseIndex];
-// for (int ii=0;ii<4;ii++)
-// if (true_neighbour_cell->neighbor(ii)->info().index == cell->info().index){
-// (true_neighbour_cell->info().k_norm())[ii]=(cell->info().k_norm())[j]; break;
-// }
-// }
- if(permeability_map){
- Cell_handle c = cell;
- cell->info().s = cell->info().s + k*distance/fluidArea*Volume_Pore_VoronoiFraction (c,j);
- volume_sub_pore += Volume_Pore_VoronoiFraction (c,j);
- }
- }
- }
-// cell->info().isvisited = !ref;
- if(permeability_map){
- cell->info().s = cell->info().s/volume_sub_pore;
- volume_sub_pore = 0.f;
- }
-// }
-// else cell->info().isvisited = !ref;
- }
-
-
- if (DEBUG_OUT) cout<<"surfneg est "<<surfneg<<endl;
- meanK /= pass;
- meanRadius /= pass;
- meanDistance /= pass;
- Real globalK=k_factor*meanDistance*Vporale/(Ssolid_tot*8.*viscosity);//An approximate value of macroscopic permeability, for clamping local values below
- if (DEBUG_OUT) {
- cout << "PassCompK = " << pass << endl;
- cout << "meanK = " << meanK << endl;
- cout << "globalK = " << globalK << endl;
- cout << "maxKdivKmean*globalK = " << maxKdivKmean*globalK << endl;
- cout << "minKdivKmean*globalK = " << minKdivKmean*globalK << endl;
- cout << "meanTubesRadius = " << meanRadius << endl;
- cout << "meanDistance = " << meanDistance << endl;
- }
- pass=0;
- if (clampKValues) for (Vector_Cell::iterator cell_it=T[currentTes].cellHandles.begin(); cell_it!=T[currentTes].cellHandles.end(); cell_it++){
- Cell_handle& cell = *cell_it;
- for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) /*&& neighbour_cell->info().isvisited==ref*/) {
- pass++;
- (cell->info().k_norm())[j] = max(minKdivKmean*globalK, min((cell->info().k_norm())[j], maxKdivKmean*globalK));
-// (cell->info().k_norm())[j] = max(MINK_DIV_KMEAN*meanK ,min((cell->info().k_norm())[j], maxKdivKmean*meanK));
- (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]=(cell->info().k_norm())[j];
- if (!neighbour_cell->info().isGhost) (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]= (cell->info().k_norm())[j];
- else {//find the real neighbor connected to our cell through periodicity, as we want exactly the same permeability without rounding errors
- Cell_handle& true_neighbour_cell = cellHandles[neighbour_cell->info().baseIndex];
- for (int ii=0;ii<4;ii++)
- if (true_neighbour_cell->neighbor(ii)->info().index == cell->info().index){
- (true_neighbour_cell->info().k_norm())[ii]=(cell->info().k_norm())[j]; break;
- }
- }
-
-
-// cout<<(cell->info().k_norm())[j]<<endl;
-// kFile << (cell->info().k_norm())[j] << endl;
- }
- }
-// cell->info().isvisited = !ref;
- }
- if (DEBUG_OUT) cout << "PassKcorrect = " << pass << endl;
-
- if (DEBUG_OUT) cout << "POS = " << POS << " NEG = " << NEG << " pass = " << pass << endl;
-
-// A loop to compute the standard deviation of the local K distribution, and use it to include/exclude K values higher then (meanK +/- K_opt_factor*STDEV)
- if (meanKStat)
- {
- std::ofstream k_opt_file("k_stdev.txt" ,std::ios::out);
-// ref = Tri.finite_cells_begin()->info().isvisited;
- pass=0;
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) /*&& neighbour_cell->info().isvisited==ref*/) {
- pass++;
- STDEV += pow(((cell->info().k_norm())[j]-meanK),2);
- }
- }
-// cell->info().isvisited = !ref;
- }
- STDEV = sqrt(STDEV/pass);
- if (DEBUG_OUT) cout << "PassSTDEV = " << pass << endl;
- cout << "STATISTIC K" << endl;
- double k_min = 0, k_max = meanK + K_opt_factor*STDEV;
- cout << "Kmoy = " << meanK << " Standard Deviation = " << STDEV << endl;
- cout << "kmin = " << k_min << " kmax = " << k_max << endl;
-// ref = Tri.finite_cells_begin()->info().isvisited;
- pass=0;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (!Tri.is_infinite(neighbour_cell) /*&& neighbour_cell->info().isvisited==ref*/) {
- pass+=1;
- if ((cell->info().k_norm())[j]>k_max) {
- (cell->info().k_norm())[j]=k_max;
- (neighbour_cell->info().k_norm())[Tri.mirror_index(cell, j)]= (cell->info().k_norm())[j];
- }
- k_opt_file << K_opt_factor << " " << (cell->info().k_norm())[j] << endl;
- }
- }
-// cell->info().isvisited=!ref;
- }
- if (DEBUG_OUT) cout << "PassKopt = " << pass << endl;
- }
-
-
- if (DEBUG_OUT) {
- Finite_vertices_iterator vertices_end = Tri.finite_vertices_end();
- Real Vgrains = 0;
- int grains=0;
-
- for (Finite_vertices_iterator V_it = Tri.finite_vertices_begin(); V_it != vertices_end; V_it++) {
- if (!V_it->info().isFictious && !V_it->info().isGhost) {
- grains +=1;
- Vgrains += 1.33333333 * M_PI * pow(V_it->point().weight(),1.5);
- }
- }
- cout<<grains<<"grains - " <<"Vtotale = " << Vtotale << " Vgrains = " << Vgrains << " Vporale1 = " << (Vtotale-Vgrains) << endl;
- cout << "Vtotalissimo = " << Vtotalissimo/2 << " Vsolid_tot = " << Vsolid_tot/2 << " Vporale2 = " << Vporale/2 << " Ssolid_tot = " << Ssolid_tot << endl<< endl;
-
- if (!RAVERAGE) cout << "------Hydraulic Radius is used for permeability computation------" << endl << endl;
- else cout << "------Average Radius is used for permeability computation------" << endl << endl;
- cout << "-----Computed_Permeability Periodic-----" << endl;
- }
-// cout << "Negative Permeabilities = " << count_k_neg << endl;
-}
-
-// void PeriodicFlow::Initialize_pressures( double P_zero )
-// {
-// RTriangulation& Tri = T[currentTes].Triangulation();
-// Finite_cells_iterator cell_end = Tri.finite_cells_end();
-//
-// for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++){
-// cell->info().setP(P_zero); cell->info().dv()=0;}
-//
-// for (int bound=0; bound<6;bound++) {
-// int& id = *boundsIds[bound];
-// if (id<0) continue;
-// Boundary& bi = boundary(id);
-// if (!bi.flowCondition) {
-// Vector_Cell tmp_cells;
-// tmp_cells.resize(10000);
-// VCell_iterator cells_it = tmp_cells.begin();
-// VCell_iterator cells_end = Tri.incident_cells(T[currentTes].vertexHandles[id],cells_it);
-// for (VCell_iterator it = tmp_cells.begin(); it != cells_end; it++)
-// {(*it)->info().p() = bi.value;(*it)->info().Pcondition=true;
-// boundingCells[bound].push_back(*it);}
-// }
-// }
-// IPCells.clear();
-// for (unsigned int n=0; n<imposedP.size();n++) {
-// Cell_handle cell=Tri.locate(imposedP[n].first);
-//
-// //check redundancy
-// for (unsigned int kk=0;kk<IPCells.size();kk++){
-// if (cell==IPCells[kk]) cerr<<"Two imposed pressures fall in the same cell."<<endl;
-// else if (cell->info().Pcondition) cerr<<"Imposed pressure fall in a boundary condition."<<endl;}
-// // cerr<<"cell found : "<<cell->vertex(0)->point()<<" "<<cell->vertex(1)->point()<<" "<<cell->vertex(2)->point()<<" "<<cell->vertex(3)->point()<<endl;
-// // assert(cell);
-// IPCells.push_back(cell);
-// cell->info().p()=imposedP[n].second;
-// cell->info().Pcondition=true;}
-// pressureChanged=false;
-// }
-
-
-void PeriodicFlow::GaussSeidel(Real dt)
-{
- RTriangulation& Tri = T[currentTes].Triangulation();
- int j = 0;
- double m, n, dp_max, p_max, sum_p, dp, sum_dp;
- double compFlowFactor=0;
- vector<Real> previousP;
- previousP.resize(Tri.number_of_finite_cells());
- double tolerance = TOLERANCE;
- double relax = RELAX;
- const int num_threads=1;
- bool compressible= fluidBulkModulus>0;
-
- vector<Real> t_sum_p, t_dp_max, t_sum_dp, t_p_max;
- t_sum_dp.resize(num_threads);
- t_dp_max.resize(num_threads);
- t_p_max.resize(num_threads);
- t_sum_p.resize(num_threads);
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- do {
- int cell2=0;
- dp_max = 0;
- p_max = 0;
- sum_p=0;
- sum_dp=0;
- int bb=-1;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- bb++;
- if ( !cell->info().Pcondition && !cell->info().isGhost) {
- cell2++;
- if (compressible && j==0) previousP[bb]=cell->info().shiftedP();
- m=0, n=0;
- for (int j2=0; j2<4; j2++) {
- if (!Tri.is_infinite(cell->neighbor(j2))) {
- if ( compressible ) {
- compFlowFactor = fluidBulkModulus*dt*cell->info().invVoidVolume();
- m += compFlowFactor*(cell->info().k_norm())[j2]*cell->neighbor(j2)->info().shiftedP();
- if (j==0) n += compFlowFactor*(cell->info().k_norm())[j2];
- } else {
- m += (cell->info().k_norm())[j2]*cell->neighbor(j2)->info().shiftedP();
- if ( isinf(m) && j<10 ) cout << "(cell->info().k_norm())[j2] = " << (cell->info().k_norm())[j2] << " cell->neighbor(j2)->info().shiftedP() = " << cell->neighbor(j2)->info().shiftedP() << endl;
- if (j==0) n += (cell->info().k_norm())[j2];
- }
- }
- }
- dp = cell->info().p();
- if (n!=0 || j!=0) {
- if (j==0) { if (compressible) cell->info().inv_sum_k=1/(1+n); else cell->info().inv_sum_k=1/n; }
- if ( compressible ) {
- cell->info().setP( ( ((previousP[bb] - ((fluidBulkModulus*dt*cell->info().invVoidVolume())*(cell->info().dv()))) + m) * cell->info().inv_sum_k - cell->info().shiftedP()) * relax + cell->info().shiftedP());
- } else {
- cell->info().setP((-(cell->info().dv()-m)*cell->info().inv_sum_k-cell->info().p())*relax+cell->info().shiftedP());
- }
- }
- dp -= cell->info().p();
- dp_max = max(dp_max, std::abs(dp));
- p_max = max(p_max, std::abs(cell->info().shiftedP()));
- sum_p += cell->info().shiftedP();
- sum_dp += std::abs(dp);
- }
- }
- j++;
-
-// if (j%100==0) cerr <<"j="<<j<<" p_moy="<<p_moy<<" dp="<< dp_moy<<" p_max="<<p_max<<" dp_max="<<dp_max<<endl;
- if (j>=40000) cerr<<"\r GS not converged after 40k iterations, break";
-
- } while ((dp_max/p_max) > tolerance && j<40000 /*&& ( dp_max > tolerance )*//* &&*/ /*( j<50 )*/);
-
- int cel=0;
- double Pav=0;
- for (Finite_cells_iterator cell = Tri.finite_cells_begin();
- cell != cell_end;
- cell++) {
- cel++;
- Pav+=cell->info().shiftedP();
- }
- Pav/=cel;
-}
-
-void PeriodicFlow::DisplayStatistics()
-{
- RTriangulation& Tri = T[currentTes].Triangulation();
- int Zero =0, Inside=0, Fictious=0, ghostC=0,realC=0, ghostV=0, realV=0;
- Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
- int zeros =0;
- for (int j=0; j!=4; j++) {
- if ((cell->info().k_norm())[j]==0) {
- zeros+=1;
- }
- }
- if (zeros==4) {
- Zero+=1;
- }
- if (!cell->info().fictious()) {
- Inside+=1;
- }
- else {
- Fictious+=1;
- }
- if (cell->info().isGhost) ghostC+=1; else realC+=1;
- }
- int fict=0, real=0;
- for (Finite_vertices_iterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
- if (v->info().isFictious) fict+=1;
- else real+=1;
- if (v->info().isGhost) {ghostV+=1; /*cerr<<"ghost v "<< v->info().id() <<": period=("<<v->info().period[0]<<","<<v->info().period[1]<<","<<v->info().period[2]<<")"<<endl;*/} else realV+=1;
- }
- long Vertices = Tri.number_of_vertices();
- long Cells = Tri.number_of_finite_cells();
- long Facets = Tri.number_of_finite_facets();
- if(DEBUG_OUT) {
- cout << "zeros = " << Zero << endl;
- cout << "There are " << Vertices << " vertices, dont " << fict << " fictious et " << real << " reeeeeel" << std::endl;
- cout << "There are " << ghostV+realV << " vertices, dont " << ghostV << " ghost et " << realV << " reeeeeel" << std::endl;
- cout << "There are " << ghostC+realC << " cells, dont " << ghostC << " ghost et " << realC << " reeeeeel" << std::endl;
- cout << "There are " << Cells << " cells " << std::endl;
- cout << "There are " << Facets << " facets " << std::endl;
- cout << "There are " << Inside << " cells INSIDE." << endl;
- cout << "There are " << Fictious << " cells FICTIOUS." << endl;
- }
-
- vtk_infinite_vertices = fict;
- vtk_infinite_cells = Fictious;
- num_particles = real;
-}
-
-double PeriodicFlow::boundaryFlux(unsigned int boundaryId)
-{
- RTriangulation& Tri = T[currentTes].Triangulation();
- double Q1=0;
-
- Vector_Cell tmp_cells;
- tmp_cells.resize(10000);
- VCell_iterator cells_it = tmp_cells.begin();
-
- VCell_iterator cell_up_end = Tri.incident_cells(T[currentTes].vertexHandles[boundaryId],cells_it);
- for (VCell_iterator it = tmp_cells.begin(); it != cell_up_end; it++)
- {
- const Cell_handle& cell = *it;
- if (cell->info().isGhost) continue;
- Q1 -= cell->info().dv();
- for (int j2=0; j2<4; j2++)
- Q1 += (cell->info().k_norm())[j2]* (cell->neighbor(j2)->info().shiftedP()-cell->info().shiftedP());
- }
- return Q1;
-}
-
-void PeriodicFlow::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(Edge_ids[k].first,Edge_ids[k].second)].push_back(pair<int,Real> (max(Edge_ids[k].first,Edge_ids[k].second),edgeNormalLubF[k]));
-
- //Now we reset the containers and initialize them
-
- Edge_Surfaces.clear(); Edge_ids.clear(); edgeNormalLubF.clear();
- Finite_edges_iterator ed_it;
- for ( Finite_edges_iterator 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;
- if (((ed_it->first)->vertex(ed_it->second)->info().isGhost) && ((ed_it->first)->vertex(ed_it->third)->info().isGhost)) continue;
- if (((ed_it->first)->vertex(ed_it->second)->info().isGhost) && ((ed_it->first)->vertex(ed_it->third)->info().isFictious)) continue;
- if (((ed_it->first)->vertex(ed_it->second)->info().isFictious) && ((ed_it->first)->vertex(ed_it->third)->info().isGhost)) continue;
-
- unsigned int id1 = (ed_it->first)->vertex(ed_it->second)->info().id();
- unsigned int id2 = (ed_it->first)->vertex(ed_it->third)->info().id();
- double area = T[currentTes].ComputeVFacetArea(ed_it);
- Edge_Surfaces.push_back(area);
- Edge_ids.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);
-// edgeNormalLubF.push_back(0);
-
- }
-}
-
-} //namespace CGT
-
-#endif //FLOW_ENGINE
-
-
-#ifdef LINSOLV
-#include "PeriodicFlowLinSolv.ipp"
-#endif
=== modified file 'lib/triangulation/PeriodicFlow.hpp'
--- lib/triangulation/PeriodicFlow.hpp 2013-08-22 14:32:01 +0000
+++ lib/triangulation/PeriodicFlow.hpp 2014-04-17 15:10:23 +0000
@@ -16,17 +16,28 @@
namespace CGT{
- typedef CGT::FlowBoundingSphere<PeriFlowTesselation> PeriodicFlowBoundingSphere;
- class PeriodicFlow : public PeriodicFlowBoundingSphere
+// typedef CGT::FlowBoundingSphere<PeriFlowTesselation> PeriodicFlowBoundingSphere;
+ template<class _Tesselation>
+ class PeriodicFlow : public CGT::FlowBoundingSphere<_Tesselation>
{
public:
- void Interpolate(Tesselation& Tes, Tesselation& NewTes);
- void ComputeFacetForcesWithCache(bool onlyCache=false);
- void Compute_Permeability();
- void GaussSeidel(Real dt=0);
- void DisplayStatistics();
- void computeEdgesSurfaces();
- double boundaryFlux(unsigned int boundaryId);
+ typedef _Tesselation Tesselation;
+ typedef Network<Tesselation> _N;
+ DECLARE_TESSELATION_TYPES(Network<Tesselation>)
+ typedef CGT::FlowBoundingSphere<_Tesselation> BaseFlowSolver;
+
+ //painfull, but we need that for templates inheritance...
+ using _N::T; using _N::xMin; using _N::xMax; using _N::yMin; using _N::yMax; using _N::zMin; using _N::zMax; using _N::Rmoy; using _N::sectionArea; using _N::Height; using _N::vTotal; using _N::currentTes; using _N::debugOut; using _N::nOfSpheres; using _N::xMinId; using _N::xMaxId; using _N::yMinId; using _N::yMaxId; using _N::zMinId; using _N::zMaxId; using _N::boundsIds; using _N::cornerMin; using _N::cornerMax; using _N::VSolidTot; using _N::Vtotalissimo; using _N::vPoral; using _N::sSolidTot; using _N::vPoralPorosity; using _N::vTotalPorosity; using _N::boundaries; using _N::idOffset; using _N::vtkInfiniteVertices; using _N::vtkInfiniteCells; using _N::num_particles; using _N::boundingCells; using _N::facetVertices; using _N::facetNFictious;
+ using BaseFlowSolver::noCache; using BaseFlowSolver::rAverage; using BaseFlowSolver::distanceCorrection; using BaseFlowSolver::minPermLength; using BaseFlowSolver::checkSphereFacetOverlap; using BaseFlowSolver::viscosity; using BaseFlowSolver::kFactor; using BaseFlowSolver::permeabilityMap; using BaseFlowSolver::maxKdivKmean; using BaseFlowSolver::clampKValues; using BaseFlowSolver::KOptFactor; using BaseFlowSolver::meanKStat; using BaseFlowSolver::fluidBulkModulus; using BaseFlowSolver::relax; using BaseFlowSolver::tolerance; using BaseFlowSolver::minKdivKmean;
+
+ //same for functions
+ using _N::defineFictiousCells; using _N::addBoundingPlanes; using _N::boundary;
+
+ void interpolate(Tesselation& Tes, Tesselation& NewTes);
+ void computeFacetForcesWithCache(bool onlyCache=false);
+ void computePermeability();
+ void gaussSeidel(Real dt=0);
+ void displayStatistics();
#ifdef EIGENSPARSE_LIB
//Eigen's sparse matrix for forces computation
// Eigen::SparseMatrix<double> FIntegral;
@@ -35,7 +46,436 @@
// Eigen::VectorXd forces;
#endif
};
-}
+
+template<class _Tesselation>
+void PeriodicFlow<_Tesselation>::interpolate(Tesselation& Tes, Tesselation& NewTes)
+{
+ CellHandle oldCell;
+ RTriangulation& Tri = Tes.Triangulation();
+ for (VCellIterator cellIt=NewTes.cellHandles.begin(); cellIt!=NewTes.cellHandles.end(); cellIt++){
+ CellHandle& newCell = *cellIt;
+ if (newCell->info().Pcondition || newCell->info().isGhost) continue;
+ CVector center ( 0,0,0 );
+ if (newCell->info().fictious()==0) for ( int k=0;k<4;k++ ) center= center + 0.25* (Tes.vertex(newCell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
+ else {
+ Real boundPos=0; int coord=0;
+ for ( int k=0;k<4;k++ ) {
+ if (!newCell->vertex (k)->info().isFictious) center= center+0.3333333333*(Tes.vertex(newCell->vertex(k)->info().id())->point()-CGAL::ORIGIN);
+ else {
+ coord=boundary (newCell->vertex(k)->info().id()).coordinate;
+ boundPos=boundary (newCell->vertex(k)->info().id()).p[coord];
+ }
+ }
+ center=CVector(coord==0?boundPos:center[0],coord==1?boundPos:center[1],coord==2?boundPos:center[2]);
+ }
+ oldCell = Tri.locate(Point(center[0],center[1],center[2]));
+ //FIXME: should use getInfo
+ newCell->info().p() = oldCell->info().shiftedP();
+ }
+// Tes.Clear();//Don't reset to avoid segfault when getting pressure in scripts just after interpolation
+}
+
+
+template<class _Tesselation>
+void PeriodicFlow<_Tesselation>::computeFacetForcesWithCache(bool onlyCache)
+{
+ RTriangulation& Tri = T[currentTes].Triangulation();
+ CVector nullVect(0,0,0);
+ static vector<CVector> oldForces;
+ if (oldForces.size()<=Tri.number_of_vertices()) oldForces.resize(Tri.number_of_vertices()+1);
+ //reset forces
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
+ if (noCache) {oldForces[v->info().id()]=nullVect; v->info().forces=nullVect;}
+ else {oldForces[v->info().id()]=v->info().forces; v->info().forces=nullVect;}
+ }
+ CellHandle neighbourCell;
+ VertexHandle mirrorVertex;
+ CVector tempVect;
+
+ //FIXME : Ema, be carefull with this (noCache), it needs to be turned true after retriangulation
+ if (noCache) {
+ for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ CellHandle& cell = *cellIt;
+ 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))) {
+// #ifdef EIGENSPARSE_LIB
+// if (!cell->info().Pcondition) ++nPCells;
+// #endif
+ 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());
+ 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[boundary(cell->vertex(j)->info().id()).coordinate]);
+ tempVect=-projSurf*boundary(cell->vertex(j)->info().id()).normal;
+ //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 facetUnitForce = -fluidSurfk*cell->info().solidSurfaces[j][3];
+ for (int y=0; y<3;y++) {
+ //add to cached value
+ cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]+facetUnitForce*cell->info().solidSurfaces[j][y];
+ //uncomment to get total force / comment to get only viscous forces (Bruno)
+ if (!cell->vertex(facetVertices[j][y])->info().isFictious) {
+ //add to cached value
+ cell->info().unitForceVectors[facetVertices[j][y]]=cell->info().unitForceVectors[facetVertices[j][y]]-facetNormal*crossSections[j][y];
+ }
+ }
+ }
+ }
+
+ noCache=false;//cache should always be defined after execution of this function
+ if (onlyCache) return;
+ }// end if(noCache)
+
+ //use cached values
+ //First define products that will be used below for all cells:
+ Real pDeltas [3];
+ for (unsigned int k=0; k<3;k++) pDeltas[k]=CellInfo::hSize[k]*CellInfo::gradP;
+ //Then compute the forces
+ for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ const CellHandle& cell = *cellIt;
+ for (int yy=0;yy<4;yy++) {
+ VertexInfo& vhi = cell->vertex(yy)->info();
+ Real unshiftedP = cell->info().p();
+ //the pressure translated to a ghost cell adjacent to the non-ghost vertex
+ unshiftedP -= pDeltas[0]*vhi.period[0] + pDeltas[1]*vhi.period[1] +pDeltas[2]*vhi.period[2];
+ T[currentTes].vertexHandles[vhi.id()]->info().forces=T[currentTes].vertexHandles[vhi.id()]->info().forces + cell->info().unitForceVectors[yy]*unshiftedP;
+ }
+ }
+ if (debugOut) {
+ CVector totalForce = nullVect;
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); v++)
+ {
+ if (!v->info().isFictious /*&& !v->info().isGhost*/ ){
+ totalForce = totalForce + v->info().forces;}
+ else /*if (!v->info().isGhost)*/{
+ if (boundary(v->info().id()).flowCondition==1) totalForce = totalForce + v->info().forces;
+ }
+ }
+ cout << "totalForce = "<< totalForce << endl;}
+}
+
+template<class _Tesselation>
+void PeriodicFlow<_Tesselation>::computePermeability()
+{
+ if (debugOut) cout << "----Computing_Permeability (Periodic)------" << endl;
+ RTriangulation& Tri = T[currentTes].Triangulation();
+ VSolidTot = 0, Vtotalissimo = 0, vPoral = 0, sSolidTot = 0, vTotalPorosity=0, vPoralPorosity=0;
+ CellHandle neighbourCell;
+
+ double k=0, distance = 0, radius = 0;
+ int surfneg=0; int NEG=0, POS=0, pass=0;
+ Real meanK=0, STDEV=0, meanRadius=0, meanDistance=0;
+ Real infiniteK=1e3;
+ double volume_sub_pore = 0.f;
+ VectorCell& cellHandles= T[currentTes].cellHandles;
+ for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ CellHandle& cell = *cellIt;
+ Point& p1 = cell->info();
+ for (int j=0; j<4; j++){
+ neighbourCell = cell->neighbor(j);
+ Point& p2 = neighbourCell->info();
+ if (!Tri.is_infinite(neighbourCell) /*&& (neighbour_cell->info().isvisited==ref || computeAllCells)*/) {
+ //compute and store the area of sphere-facet intersections for later use
+ VertexHandle W [3];
+ for (int kk=0; kk<3; kk++) {
+ W[kk] = cell->vertex(facetVertices[j][kk]);
+ }
+ Sphere& v0 = W[0]->point();
+ Sphere& v1 = W[1]->point();
+ Sphere& v2 = W[2]->point();
+#ifdef USE_FAST_MATH
+ //FIXME : code not compiling,, do the same as in "else"
+ assert((W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())>=0 && (W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())<=1);
+ for (int jj=0;jj<3;jj++)
+ cell->info().facetSphereCrossSections[j][jj]=0.5*W[jj]->point().weight()*Wm3::FastInvCos1((W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point()));
+#else
+ cell->info().facetSphereCrossSections[j]=CVector(
+ W[0]->info().isFictious ? 0 : 0.5*v0.weight()*acos((v1-v0)*(v2-v0)/sqrt((v1-v0).squared_length()*(v2-v0).squared_length())),
+ W[1]->info().isFictious ? 0 : 0.5*v1.weight()*acos((v0-v1)*(v2-v1)/sqrt((v1-v0).squared_length()*(v2-v1).squared_length())),
+ W[2]->info().isFictious ? 0 : 0.5*v2.weight()*acos((v0-v2)*(v1-v2)/sqrt((v1-v2).squared_length()*(v2-v0).squared_length())));
+#endif
+ pass+=1;
+ CVector l = p1 - p2;
+ distance = sqrt(l.squared_length());
+ if (!rAverage) radius = 2* this->computeHydraulicRadius(cell, j);
+ else radius = (this->computeEffectiveRadius(cell, j)+this->computeEquivalentRadius(cell,j))*0.5;
+ if (radius<0) NEG++;
+ else POS++;
+ if (radius==0) {
+ cout << "INS-INS PROBLEM!!!!!!!" << endl;
+ }
+ Real fluidArea=0;
+ int test=0;
+ if (distance!=0) {
+ if (minPermLength>0 && distanceCorrection) distance=max(minPermLength,distance);
+ const CVector& Surfk = cell->info().facetSurfaces[j];
+ Real area = sqrt(Surfk.squared_length());
+ const CVector& crossSections = cell->info().facetSphereCrossSections[j];
+ Real S0=0;
+ S0=checkSphereFacetOverlap(v0,v1,v2);
+ if (S0==0) S0=checkSphereFacetOverlap(v1,v2,v0);
+ if (S0==0) S0=checkSphereFacetOverlap(v2,v0,v1);
+ //take absolute value, since in rare cases the surface can be negative (overlaping spheres)
+ fluidArea=abs(area-crossSections[0]-crossSections[1]-crossSections[2]+S0);
+ cell->info().facetFluidSurfacesRatio[j]=fluidArea/area;
+ k=(fluidArea * pow(radius,2)) / (8*viscosity*distance);
+ meanDistance += distance;
+ meanRadius += radius;
+ meanK += k*kFactor;
+
+ if (k<0 && debugOut) {surfneg+=1;
+ cout<<"__ k<0 __"<<k<<" "<<" fluidArea "<<fluidArea<<" area "<<area<<" "<<crossSections[0]<<" "<<crossSections[1]<<" "<<crossSections[2] <<" "<<W[0]->info().id()<<" "<<W[1]->info().id()<<" "<<W[2]->info().id()<<" "<<p1<<" "<<p2<<" test "<<test<<endl;}
+
+ } else cout <<"infinite K2! surfaces will be missing (FIXME)"<<endl; k = infiniteK;
+ //Will be corrected in the next loop
+ (cell->info().kNorm())[j]= k*kFactor;
+ if (!neighbourCell->info().isGhost) (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j];
+ //The following block is correct but not very usefull, since all values are clamped below with MIN and MAX, skip for now
+// else {//find the real neighbor connected to our cell through periodicity
+// CellHandle true_neighbour_cell = cellHandles[neighbour_cell->info().baseIndex];
+// for (int ii=0;ii<4;ii++)
+// if (true_neighbour_cell->neighbor(ii)->info().index == cell->info().index){
+// (true_neighbour_cell->info().kNorm())[ii]=(cell->info().kNorm())[j]; break;
+// }
+// }
+ if(permeabilityMap){
+ CellHandle c = cell;
+ cell->info().s = cell->info().s + k*distance/fluidArea*this->volumePoreVoronoiFraction (c,j);
+ volume_sub_pore += this->volumePoreVoronoiFraction (c,j);
+ }
+ }
+ }
+// cell->info().isvisited = !ref;
+ if(permeabilityMap){
+ cell->info().s = cell->info().s/volume_sub_pore;
+ volume_sub_pore = 0.f;
+ }
+// }
+ }
+
+
+ if (debugOut) cout<<"surfneg est "<<surfneg<<endl;
+ meanK /= pass;
+ meanRadius /= pass;
+ meanDistance /= pass;
+ Real globalK=kFactor*meanDistance*vPoral/(sSolidTot*8.*viscosity);//An approximate value of macroscopic permeability, for clamping local values below
+ if (debugOut) {
+ cout << "PassCompK = " << pass << endl;
+ cout << "meanK = " << meanK << endl;
+ cout << "globalK = " << globalK << endl;
+ cout << "maxKdivKmean*globalK = " << maxKdivKmean*globalK << endl;
+ cout << "minKdivKmean*globalK = " << minKdivKmean*globalK << endl;
+ cout << "meanTubesRadius = " << meanRadius << endl;
+ cout << "meanDistance = " << meanDistance << endl;
+ }
+ pass=0;
+ if (clampKValues) for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){
+ CellHandle& cell = *cellIt;
+ for (int j=0; j<4; j++) {
+ neighbourCell = cell->neighbor(j);
+ if (!Tri.is_infinite(neighbourCell) /*&& neighbour_cell->info().isvisited==ref*/) {
+ pass++;
+ (cell->info().kNorm())[j] = max(minKdivKmean*globalK, min((cell->info().kNorm())[j], maxKdivKmean*globalK));
+ (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]=(cell->info().kNorm())[j];
+ if (!neighbourCell->info().isGhost) (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j];
+ else {//find the real neighbor connected to our cell through periodicity, as we want exactly the same permeability without rounding errors
+ CellHandle& true_neighbourCell = cellHandles[neighbourCell->info().baseIndex];
+ for (int ii=0;ii<4;ii++)
+ if (true_neighbourCell->neighbor(ii)->info().index == cell->info().index){
+ (true_neighbourCell->info().kNorm())[ii]=(cell->info().kNorm())[j]; break;
+ }
+ }
+
+ }
+ }
+ }
+ if (debugOut) cout << "PassKcorrect = " << pass << endl;
+
+ if (debugOut) cout << "POS = " << POS << " NEG = " << NEG << " pass = " << pass << endl;
+
+// A loop to compute the standard deviation of the local K distribution, and use it to include/exclude K values higher then (meanK +/- K_opt_factor*STDEV)
+ if (meanKStat)
+ {
+ std::ofstream k_opt_file("k_stdev.txt" ,std::ios::out);
+ pass=0;
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ 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) /*&& neighbour_cell->info().isvisited==ref*/) {
+ pass++;
+ STDEV += pow(((cell->info().kNorm())[j]-meanK),2);
+ }
+ }
+ }
+ STDEV = sqrt(STDEV/pass);
+ if (debugOut) cout << "PassSTDEV = " << pass << endl;
+ cout << "STATISTIC K" << endl;
+ double k_min = 0, k_max = meanK + KOptFactor*STDEV;
+ cout << "Kmoy = " << meanK << " Standard Deviation = " << STDEV << endl;
+ cout << "kmin = " << k_min << " kmax = " << k_max << endl;
+ pass=0;
+ 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) /*&& neighbour_cell->info().isvisited==ref*/) {
+ pass+=1;
+ if ((cell->info().kNorm())[j]>k_max) {
+ (cell->info().kNorm())[j]=k_max;
+ (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j];
+ }
+ k_opt_file << KOptFactor << " " << (cell->info().kNorm())[j] << endl;
+ }
+ }
+ }
+ if (debugOut) cout << "PassKopt = " << pass << endl;
+ }
+ if (debugOut) {
+ FiniteVerticesIterator verticesEnd = Tri.finite_vertices_end();
+ Real Vgrains = 0;
+ int grains=0;
+
+ for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != verticesEnd; vIt++) {
+ if (!vIt->info().isFictious && !vIt->info().isGhost) {
+ grains +=1;
+ Vgrains += 1.33333333 * M_PI * pow(vIt->point().weight(),1.5);
+ }
+ }
+ cout<<grains<<"grains - " <<"vTotal = " << vTotal << " Vgrains = " << Vgrains << " vPoral1 = " << (vTotal-Vgrains) << endl;
+ cout << "Vtotalissimo = " << Vtotalissimo/2 << " VSolidTot = " << VSolidTot/2 << " vPoral2 = " << vPoral/2 << " sSolidTot = " << sSolidTot << endl<< endl;
+
+ if (!rAverage) cout << "------Hydraulic Radius is used for permeability computation------" << endl << endl;
+ else cout << "------Average Radius is used for permeability computation------" << endl << endl;
+ cout << "-----computed_Permeability Periodic-----" << endl;
+ }
+}
+
+
+
+
+template<class _Tesselation>
+void PeriodicFlow<_Tesselation>::gaussSeidel(Real dt)
+{
+ RTriangulation& Tri = T[currentTes].Triangulation();
+ int j = 0;
+ double m, n, dp_max, p_max, sum_p, dp, sum_dp;
+ double compFlowFactor=0;
+ vector<Real> previousP;
+ previousP.resize(Tri.number_of_finite_cells());
+ const int num_threads=1;
+ bool compressible= fluidBulkModulus>0;
+
+ vector<Real> t_sum_p, t_dp_max, t_sum_dp, t_p_max;
+ t_sum_dp.resize(num_threads);
+ t_dp_max.resize(num_threads);
+ t_p_max.resize(num_threads);
+ t_sum_p.resize(num_threads);
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ do {
+ int cell2=0;
+ dp_max = 0;
+ p_max = 0;
+ sum_p=0;
+ sum_dp=0;
+ int bb=-1;
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ bb++;
+ if ( !cell->info().Pcondition && !cell->info().isGhost) {
+ cell2++;
+ if (compressible && j==0) previousP[bb]=cell->info().shiftedP();
+ m=0, n=0;
+ for (int j2=0; j2<4; j2++) {
+ if (!Tri.is_infinite(cell->neighbor(j2))) {
+ if ( compressible ) {
+ compFlowFactor = fluidBulkModulus*dt*cell->info().invVoidVolume();
+ m += compFlowFactor*(cell->info().kNorm())[j2]*cell->neighbor(j2)->info().shiftedP();
+ if (j==0) n += compFlowFactor*(cell->info().kNorm())[j2];
+ } else {
+ m += (cell->info().kNorm())[j2]*cell->neighbor(j2)->info().shiftedP();
+ if ( isinf(m) && j<10 ) cout << "(cell->info().kNorm())[j2] = " << (cell->info().kNorm())[j2] << " cell->neighbor(j2)->info().shiftedP() = " << cell->neighbor(j2)->info().shiftedP() << endl;
+ if (j==0) n += (cell->info().kNorm())[j2];
+ }
+ }
+ }
+ dp = cell->info().p();
+ if (n!=0 || j!=0) {
+ if (j==0) { if (compressible) cell->info().invSumK=1/(1+n); else cell->info().invSumK=1/n; }
+ if ( compressible ) {
+ cell->info().setP( ( ((previousP[bb] - ((fluidBulkModulus*dt*cell->info().invVoidVolume())*(cell->info().dv()))) + m) * cell->info().invSumK - cell->info().shiftedP()) * relax + cell->info().shiftedP());
+ } else {
+ cell->info().setP((-(cell->info().dv()-m)*cell->info().invSumK-cell->info().p())*relax+cell->info().shiftedP());
+ }
+ }
+ dp -= cell->info().p();
+ dp_max = max(dp_max, std::abs(dp));
+ p_max = max(p_max, std::abs(cell->info().shiftedP()));
+ sum_p += cell->info().shiftedP();
+ sum_dp += std::abs(dp);
+ }
+ }
+ j++;
+
+ if (j>=40000) cerr<<"\r GS not converged after 40k iterations, break";
+
+ } while ((dp_max/p_max) > tolerance && j<40000 /*&& ( dp_max > tolerance )*//* &&*/ /*( j<50 )*/);
+
+ int cel=0;
+ double Pav=0;
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin();
+ cell != cellEnd;
+ cell++) {
+ cel++;
+ Pav+=cell->info().shiftedP();
+ }
+ Pav/=cel;
+}
+
+template<class _Tesselation>
+void PeriodicFlow<_Tesselation>::displayStatistics()
+{
+ RTriangulation& Tri = T[currentTes].Triangulation();
+ int Zero =0, Inside=0, Fictious=0, ghostC=0,realC=0, ghostV=0, realV=0;
+ FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
+ int zeros =0;
+ for (int j=0; j!=4; j++)
+ if ((cell->info().kNorm())[j]==0) zeros+=1;
+ if (zeros==4) Zero+=1;
+ if (!cell->info().fictious()) Inside+=1; else Fictious+=1;
+ if (cell->info().isGhost) ghostC+=1; else realC+=1;
+ }
+ int fict=0, real=0;
+ for (FiniteVerticesIterator v = Tri.finite_vertices_begin(); v != Tri.finite_vertices_end(); ++v) {
+ if (v->info().isFictious) fict+=1;
+ else real+=1;
+ }
+ long Vertices = Tri.number_of_vertices();
+ long Cells = Tri.number_of_finite_cells();
+ long Facets = Tri.number_of_finite_facets();
+ if(debugOut) {
+ cout << "zeros = " << Zero << endl;
+ cout << "There are " << Vertices << " vertices, dont " << fict << " fictious et " << real << " reeeeeel" << std::endl;
+ cout << "There are " << ghostV+realV << " vertices, dont " << ghostV << " ghost et " << realV << " reeeeeel" << std::endl;
+ cout << "There are " << ghostC+realC << " cells, dont " << ghostC << " ghost et " << realC << " reeeeeel" << std::endl;
+ cout << "There are " << Cells << " cells " << std::endl;
+ cout << "There are " << Facets << " facets " << std::endl;
+ cout << "There are " << Inside << " cells INSIDE." << endl;
+ cout << "There are " << Fictious << " cells FICTIOUS." << endl;
+ }
+ vtkInfiniteVertices = fict;
+ vtkInfiniteCells = Fictious;
+ num_particles = real;
+}
+
+} //END NAMESPACE
#ifdef LINSOLV
#include "PeriodicFlowLinSolv.hpp"
=== modified file 'lib/triangulation/PeriodicFlowLinSolv.hpp'
--- lib/triangulation/PeriodicFlowLinSolv.hpp 2013-08-22 14:32:01 +0000
+++ lib/triangulation/PeriodicFlowLinSolv.hpp 2014-03-21 18:47:45 +0000
@@ -15,22 +15,35 @@
namespace CGT {
-typedef FlowBoundingSphereLinSolv<PeriodicFlow> LinSolver;
-
-class PeriodicFlowLinSolv : public LinSolver
+template<class _Tesselation>
+class PeriodicFlowLinSolv : public FlowBoundingSphereLinSolv<_Tesselation,PeriodicFlow<_Tesselation> >
{
public:
- typedef PeriodicFlow FlowType;
+ typedef _Tesselation Tesselation;
+ typedef Network<Tesselation> _N;
+ DECLARE_TESSELATION_TYPES(Network<Tesselation>)
+ typedef FlowBoundingSphereLinSolv<_Tesselation,PeriodicFlow<_Tesselation> > BaseFlowSolver;
+ typedef typename BaseFlowSolver::ETriplet ETriplet;
+
+ ///painfull, but we need that for templates inheritance...
+ using _N::T; using _N::xMin; using _N::xMax; using _N::yMin; using _N::yMax; using _N::zMin; using _N::zMax; using _N::Rmoy; using _N::sectionArea; using _N::Height; using _N::vTotal; using _N::currentTes; using _N::debugOut; using _N::nOfSpheres; using _N::xMinId; using _N::xMaxId; using _N::yMinId; using _N::yMaxId; using _N::zMinId; using _N::zMaxId; using _N::boundsIds; using _N::cornerMin; using _N::cornerMax; using _N::VSolidTot; using _N::Vtotalissimo; using _N::vPoral; using _N::sSolidTot; using _N::vPoralPorosity; using _N::vTotalPorosity; using _N::boundaries; using _N::idOffset; using _N::vtkInfiniteVertices; using _N::vtkInfiniteCells; using _N::num_particles; using _N::boundingCells; using _N::facetVertices; using _N::facetNFictious;
+ //same for functions
+ using _N::defineFictiousCells; using _N::addBoundingPlanes; using _N::boundary;
+
+ using BaseFlowSolver::noCache; using BaseFlowSolver::rAverage; using BaseFlowSolver::distanceCorrection; using BaseFlowSolver::minPermLength; using BaseFlowSolver::checkSphereFacetOverlap; using BaseFlowSolver::viscosity; using BaseFlowSolver::kFactor; using BaseFlowSolver::permeabilityMap; using BaseFlowSolver::maxKdivKmean; using BaseFlowSolver::clampKValues; using BaseFlowSolver::KOptFactor; using BaseFlowSolver::meanKStat; using BaseFlowSolver::fluidBulkModulus; using BaseFlowSolver::relax; using BaseFlowSolver::tolerance; using BaseFlowSolver::minKdivKmean;
+ /// More members from LinSolv variant
+ using BaseFlowSolver::areCellsOrdered; using BaseFlowSolver::T_nnz; using BaseFlowSolver::ncols; using BaseFlowSolver::T_cells; using BaseFlowSolver::T_index; using BaseFlowSolver::orderedCells; using BaseFlowSolver::isLinearSystemSet; using BaseFlowSolver::T_x; using BaseFlowSolver::T_b; using BaseFlowSolver::T_bv; using BaseFlowSolver::bodv; using BaseFlowSolver::xodv; using BaseFlowSolver::errorCode; using BaseFlowSolver::useSolver; using BaseFlowSolver::tripletList; using BaseFlowSolver::A; using BaseFlowSolver::gsP; using BaseFlowSolver::gsB; using BaseFlowSolver::fullAcolumns; using BaseFlowSolver::fullAvalues; using BaseFlowSolver::isFullLinearSystemGSSet; using BaseFlowSolver::gsdV;
+
vector<int> indices;//redirection vector containing the rank of cell so that T_cells[indices[cell->info().index]]=cell
virtual ~PeriodicFlowLinSolv();
PeriodicFlowLinSolv();
///Linear system solve
- virtual int SetLinearSystem(Real dt=0);
- virtual int SetLinearSystemFullGS(Real dt=0);
+ virtual int setLinearSystem(Real dt=0);
+ virtual int setLinearSystemFullGS(Real dt=0);
};
} //namespace CGTF
-
+#include "PeriodicFlowLinSolv.ipp"
#endif //FLOW_ENGINE
=== modified file 'lib/triangulation/PeriodicFlowLinSolv.ipp'
--- lib/triangulation/PeriodicFlowLinSolv.ipp 2013-06-27 11:29:17 +0000
+++ lib/triangulation/PeriodicFlowLinSolv.ipp 2014-03-21 18:47:45 +0000
@@ -41,14 +41,15 @@
double *, int *, int *, int *, int *, int *,
int *, double *, double *, int *, double *);
#endif
-
-PeriodicFlowLinSolv::~PeriodicFlowLinSolv()
+template<class _Tesselation>
+PeriodicFlowLinSolv<_Tesselation>::~PeriodicFlowLinSolv()
{
}
-
-PeriodicFlowLinSolv::PeriodicFlowLinSolv(): LinSolver() {}
-
-int PeriodicFlowLinSolv::SetLinearSystem(Real dt)
+template<class _Tesselation>
+PeriodicFlowLinSolv<_Tesselation>::PeriodicFlowLinSolv(): BaseFlowSolver() {}
+
+template<class _Tesselation>
+int PeriodicFlowLinSolv<_Tesselation>::setLinearSystem(Real dt)
{
//WARNING : boundary conditions (Pcondition, p values) must have been set for a correct definition of
RTriangulation& Tri = T[currentTes].Triangulation();
@@ -64,11 +65,10 @@
unsigned int maxindex = 0;
//FIXME: this is way too large since many cells will be ghosts
T_cells.resize(Tri.number_of_finite_cells()+1);
-// indices.resize(Tri.number_of_finite_cells()+1);
///Ordered cells
orderedCells.clear();
- const Finite_cells_iterator cell_end = Tri.finite_cells_end();
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ const FiniteCellsIterator cellEnd = Tri.finite_cells_end();
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
if (cell->info().Pcondition || cell->info().isGhost) continue;
orderedCells.push_back(cell);
// T_cells[++ncols]=cell;
@@ -79,7 +79,6 @@
}
// spatial_sort(orderedCells.begin(),orderedCells.end(), CellTraits_for_spatial_sort());//FIXME: ordering will not work with the new "indices", which needs reordering to
T_cells.resize(ncols+1);
-// indices.resize(maxindex+1);
isLinearSystemSet=false;
areCellsOrdered=true;
}
@@ -93,128 +92,60 @@
T_bv.resize(ncols);
bodv.resize(ncols);
xodv.resize(ncols);
-// gsB.resize(ncols+1);
T_cells.resize(ncols+1);
T_nnz=0;}
for (int kk=0; kk<ncols;kk++) T_b[kk]=0;
///Ordered cells
- int nIndex=0; Cell_handle neighbour_cell;
+ int nIndex=0; CellHandle neighbourCell;
for (int i=0; i<ncols; i++)
{
- Finite_cells_iterator& cell = orderedCells[i];
+ FiniteCellsIterator& cell = orderedCells[i];
///Non-ordered cells
-// for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
-// if (!cell->info().Pcondition && !cell->info().isGhost)
{
const int& index=cell->info().index;
- const Cell_Info& cInfo = cell->info();
+ const CellInfo& cInfo = cell->info();
if (!isLinearSystemSet) {
//Add diagonal term
is[T_nnz] = index;
js[T_nnz] = index;
- vs[T_nnz] = (cInfo.k_norm())[0]+ (cInfo.k_norm())[1]+ (cInfo.k_norm())[2]+ (cInfo.k_norm())[3];
+ vs[T_nnz] = (cInfo.kNorm())[0]+ (cInfo.kNorm())[1]+ (cInfo.kNorm())[2]+ (cInfo.kNorm())[3];
if (vs[T_nnz]<0) cerr<<"!!!! WTF !!!"<<endl;
if (fluidBulkModulus>0) vs[T_nnz] += (1.f/(dt*fluidBulkModulus*cInfo.invVoidVolume()));
T_nnz++;
}
for (int j=0; j<4; j++) {
- neighbour_cell = cell->neighbor(j);
- if (Tri.is_infinite(neighbour_cell)) continue;
- Cell_Info& nInfo = neighbour_cell->info();
+ neighbourCell = cell->neighbor(j);
+ if (Tri.is_infinite(neighbourCell)) continue;
+ CellInfo& nInfo = neighbourCell->info();
nIndex=nInfo.index;
if (nIndex==index) {
cerr<<"ERROR: nIndex==index, the cell is neighbour to itself"<< index<<endl;
errorCode=3;}
- if (nInfo.Pcondition) T_b[index-1]+=cInfo.k_norm()[j]*nInfo.shiftedP();
+ if (nInfo.Pcondition) T_b[index-1]+=cInfo.kNorm()[j]*nInfo.shiftedP();
else {
if (!isLinearSystemSet && index>nIndex) {
is[T_nnz] = index;
js[T_nnz] = nIndex;
- vs[T_nnz] = - (cInfo.k_norm())[j];
+ vs[T_nnz] = - (cInfo.kNorm())[j];
if (vs[T_nnz]>0) cerr<<"!!!! WTF2 !!!"<<endl;
T_nnz++;}
- if (nInfo.isGhost) T_b[index-1]+=cInfo.k_norm()[j]*nInfo.pShift();
+ if (nInfo.isGhost) T_b[index-1]+=cInfo.kNorm()[j]*nInfo.pShift();
}
}
}
}
if (!isLinearSystemSet) {
- if (useSolver==1 || useSolver==2){
- #ifdef TAUCS_LIB
- clen.resize(ncols+1);
- T_jn.resize(ncols+1);
- T_A->colptr = &T_jn[0];
- T_ia.resize(T_nnz);
- T_A->rowind = &T_ia[0];
- T_A->flags = (TAUCS_DOUBLE | TAUCS_SYMMETRIC | TAUCS_LOWER);
- T_an.resize(T_nnz);
- T_A->values.d = &T_an[0];
- T_A->n = ncols;
- T_A->m = ncols;
- int i,j,k;
- for (j=0; j<ncols; j++) clen[j] = 0;
- for (k=0; k<T_nnz; k++) {
- i = is[k]-1; /* make it 1-based */
- j = js[k]-1; /* make it 1-based */
- (clen[j])++;
- }
- /* now compute column pointers */
- k = 0;
- for (j=0; j<ncols; j++) {
- int tmp;
- tmp = clen[j];
- clen[j] = (T_A->colptr[j]) = k;
- k += tmp;
- }
- clen[ncols] = (T_A->colptr[ncols]) = k;
-
- /* now read matrix into data structure */
- for (k=0; k<T_nnz; k++) {
- i = is[k] - 1; /* make it 1-based */
- j = js[k] - 1; /* make it 1-based */
- assert(i < ncols);
- assert(j < ncols);
- (T_A->taucs_values)[clen[j]] = vs[k];
- (T_A->rowind)[clen[j]] = i;
- clen[j] ++;
- }
- #else
- cerr<<"yade compiled without Taucs, FlowEngine.useSolver="<< useSolver <<" not supported"<<endl;
- #endif //TAUCS_LIB
- } else if (useSolver==3){
+ if (useSolver>0){
#ifdef EIGENSPARSE_LIB
-// //here the matrix can be exported in in MatrixMarket format for experiments
-// static int mn=0;
-// ofstream file; ofstream file2; ofstream file3;
-// stringstream ss,ss2,ss3;
-// ss<<"matrix"<<mn;
-// ss3<<"matrixf2"<<mn;
-// ss2<<"matrixf"<<mn++;
-// file.open(ss.str().c_str());
-// file2.open(ss2.str().c_str());
-// file3.open(ss3.str().c_str());
-// file <<"%%MatrixMarket matrix coordinate real symmetric"<<endl;
-// file2 <<"%%MatrixMarket matrix coordinate real symmetric"<<endl;
-// file3 <<"%%MatrixMarket matrix coordinate real symmetric"<<endl;
-// file <<ncols<<" "<<ncols<<" "<<T_nnz<<" -1"<<endl;
-// file2 <<ncols<<" "<<ncols<<" "<<T_nnz<<" -1"<<endl;
-// file3 <<ncols<<" "<<ncols<<" "<<T_nnz<<" -1"<<endl;
tripletList.clear(); tripletList.resize(T_nnz);
for(int k=0;k<T_nnz;k++) {
tripletList[k]=ETriplet(is[k]-1,js[k]-1,vs[k]);
-// file<<is[k]-1<<" "<<js[k]-1<<" "<<vs[k]<<endl;
-// if (is[k]==js[k]) file2<<is[k]-1<<" "<<js[k]-1<<" "<<1.0001*vs[k]<<endl;
-// else file2<<is[k]-1<<" "<<js[k]-1<<" "<<vs[k]<<endl;
-// if (is[k]==js[k]) file3<<is[k]-1<<" "<<js[k]-1<<" "<<1.00000001*vs[k]<<endl;
-// else file3<<is[k]-1<<" "<<js[k]-1<<" "<<vs[k]<<endl;
}
A.resize(ncols,ncols);
A.setFromTriplets(tripletList.begin(), tripletList.end());
-// file << A;
-// file.close();
#else
- cerr<<"yade compiled without CHOLMOD, FlowEngine.useSolver="<< useSolver <<" not supported"<<endl;
+ cerr<<"yade compiled without CHOLMOD, FlowEngine.useSolver="<< useSolver <<">0 not supported"<<endl;
#endif
}
isLinearSystemSet=true;
@@ -225,8 +156,8 @@
/// For Gauss Seidel, we need the full matrix
-
-int PeriodicFlowLinSolv::SetLinearSystemFullGS(Real dt)
+template<class _Tesselation>
+int PeriodicFlowLinSolv<_Tesselation>::setLinearSystemFullGS(Real dt)
{
//WARNING : boundary conditions (Pcondition, p values) must have been set for a correct definition
RTriangulation& Tri = T[currentTes].Triangulation();
@@ -237,10 +168,10 @@
T_index=0;//FIXME : no need to clear if we don't re-triangulate
T_nnz=0;
ncols=0;
- const Finite_cells_iterator cell_end = Tri.finite_cells_end();
+ const FiniteCellsIterator cellEnd = Tri.finite_cells_end();
orderedCells.clear();
T_cells.resize(n_cells+1);
- for (Finite_cells_iterator cell = Tri.finite_cells_begin(); cell != cell_end; cell++) {
+ for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
if (cell->info().Pcondition || cell->info().isGhost) continue;
++ncols;
T_cells[cell->info().index]=cell;
@@ -266,53 +197,51 @@
///Ordered cells
for (int i=1; i<=ncols; i++)
{
- Cell_handle& cell = T_cells[i];
+ CellHandle& cell = T_cells[i];
///Non-ordered cells
if (!cell->info().Pcondition && !cell->info().isGhost) {
//Add diagonal term
- fullAvalues[cell->info().index][4] = 1.f/((cell->info().k_norm())[0]+ (cell->info().k_norm())[1]+ (cell->info().k_norm())[2]+ (cell->info().k_norm())[3] + (fluidBulkModulus>0? 1.f/(dt*fluidBulkModulus*cell->info().invVoidVolume()):0));
+ fullAvalues[cell->info().index][4] = 1.f/((cell->info().kNorm())[0]+ (cell->info().kNorm())[1]+ (cell->info().kNorm())[2]+ (cell->info().kNorm())[3] + (fluidBulkModulus>0? 1.f/(dt*fluidBulkModulus*cell->info().invVoidVolume()):0));
//DUMP
-// cout<< cell->info().index<<" "<< cell->info().index<<" "<<fullAvalues[cell->info().index][4] <<endl;
T_nnz++;
for (int j=0; j<4; j++) {
- Cell_handle neighbour_cell = cell->neighbor(j);
- const Cell_Info& nInfo = neighbour_cell->info();
- Cell_Info& cInfo = cell->info();
- if (Tri.is_infinite(neighbour_cell)) {
+ CellHandle neighbourCell = cell->neighbor(j);
+ const CellInfo& nInfo = neighbourCell->info();
+ CellInfo& cInfo = cell->info();
+ if (Tri.is_infinite(neighbourCell)) {
fullAvalues[cInfo.index][j] = 0;
//We point to the pressure of the adjacent cell. If the cell is ghost, then it has the index of the real one, and then the pointer is correct
fullAcolumns[cInfo.index][j] = &gsP[0];
continue;}
if (!nInfo.Pcondition) {
++T_nnz;
- fullAvalues[cInfo.index][j] = (cInfo.k_norm())[j];
+ fullAvalues[cInfo.index][j] = (cInfo.kNorm())[j];
fullAcolumns[cInfo.index][j] = &gsP[nInfo.index];
//DUMP
-// cout<< cInfo.index<<" "<< nInfo.index<<" "<<fullAvalues[cInfo.index][j] <<endl;
//if the adjacent cell is ghost, we account for the pressure shift in the RHS
if (nInfo.isGhost){
- gsB[cInfo.index]+=cInfo.k_norm()[j]*nInfo.pShift();
+ gsB[cInfo.index]+=cInfo.kNorm()[j]*nInfo.pShift();
}
} else {
fullAvalues[cInfo.index][j] = 0;
fullAcolumns[cInfo.index][j] = &gsP[0];
- gsB[cInfo.index]+=cInfo.k_norm()[j]*nInfo.shiftedP();
+ gsB[cInfo.index]+=cInfo.kNorm()[j]*nInfo.shiftedP();
}
}
}
}
} else for (int i=1; i<=ncols; i++)
{
- Cell_handle& cell = T_cells[i];
+ CellHandle& cell = T_cells[i];
///Non-ordered cells
if (!cell->info().Pcondition && !cell->info().isGhost) {
for (int j=0; j<4; j++) {
- Cell_handle neighbour_cell = cell->neighbor(j);
- const Cell_Info& nInfo = neighbour_cell->info();
- Cell_Info& cInfo = cell->info();
+ CellHandle neighbourCell = cell->neighbor(j);
+ const CellInfo& nInfo = neighbourCell->info();
+ CellInfo& cInfo = cell->info();
if (!nInfo.Pcondition) {
- if (nInfo.isGhost) gsB[cInfo.index]+=cInfo.k_norm()[j]*nInfo.pShift();
- } else gsB[cInfo.index]+=cInfo.k_norm()[j]*nInfo.shiftedP();
+ if (nInfo.isGhost) gsB[cInfo.index]+=cInfo.kNorm()[j]*nInfo.pShift();
+ } else gsB[cInfo.index]+=cInfo.kNorm()[j]*nInfo.shiftedP();
}
}
}
=== modified file 'lib/triangulation/RegularTriangulation.h'
--- lib/triangulation/RegularTriangulation.h 2013-11-20 08:40:45 +0000
+++ lib/triangulation/RegularTriangulation.h 2014-03-21 18:47:45 +0000
@@ -5,14 +5,85 @@
* 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. *
*************************************************************************/
+
+//Define basic types from CGAL templates
#pragma once
-
-#include "def_types.h"
-#include <cassert>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Cartesian.h>
+#include <CGAL/Regular_triangulation_3.h>
+#include <CGAL/Regular_triangulation_euclidean_traits_3.h>
+#include <CGAL/Triangulation_vertex_base_with_info_3.h>
+#include <CGAL/Triangulation_cell_base_with_info_3.h>
+#include <CGAL/Delaunay_triangulation_3.h>
+#include <CGAL/circulator.h>
+#include <CGAL/number_utils.h>
+#include <boost/static_assert.hpp>
+
+//This include from yade let us use Eigen types
+#include <yade/lib/base/Math.hpp>
+
+const int facetVertices [4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
namespace CGT {
-
-
+//Robust kernel
+typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
+//A bit faster, but gives crash eventualy
+// typedef CGAL::Cartesian<double> K;
+
+typedef CGAL::Regular_triangulation_euclidean_traits_3<K> Traits;
+typedef K::Point_3 Point;
+typedef Traits::Vector_3 CVector;
+typedef Traits::Segment_3 Segment;
+#ifndef NO_REAL_CHECK
+/** compilation inside yade: check that Real in yade is the same as Real we will define; otherwise it might make things go wrong badly (perhaps) **/
+BOOST_STATIC_ASSERT(sizeof(Traits::RT)==sizeof(Real));
+#endif
+typedef Traits::RT Real; //Dans cartesian, RT = FT
+typedef Traits::Weighted_point Sphere;
+typedef Traits::Plane_3 Plane;
+typedef Traits::Triangle_3 Triangle;
+typedef Traits::Tetrahedron_3 Tetrahedron;
+
+class SimpleCellInfo : public Point {
+ public:
+ //"id": unique identifier of each cell, independant of other numberings used in the fluid types.
+ // Care to initialize it if you need it, there is no magic numbering to rely on
+ unsigned int id;
+ Real s;
+ bool isFictious;
+ SimpleCellInfo (void) {isFictious=false; s=0;}
+ SimpleCellInfo& setPoint(const Point &p) { Point::operator= (p); return *this; }
+ SimpleCellInfo& setScalar(const Real &scalar) { s=scalar; return *this; }
+ inline Real x (void) {return Point::x();}
+ inline Real y (void) {return Point::y();}
+ inline Real z (void) {return Point::z();}
+ inline Real& f (void) {return s;}
+ //virtual function that will be defined for all classes, allowing shared function (e.g. for display of periodic and non-periodic with the unique function saveVTK)
+ bool isReal (void) {return !isFictious;}
+};
+
+class SimpleVertexInfo : public CVector {
+protected:
+ Real s;
+ unsigned int i;
+ Real vol;
+public:
+ bool isFictious;
+ SimpleVertexInfo& setVector(const CVector &u) { CVector::operator= (u); return *this; }
+ SimpleVertexInfo& setFloat(const float &scalar) { s=scalar; return *this; }
+ SimpleVertexInfo& setId(const unsigned int &id) { i= id; return *this; }
+ inline Real ux (void) {return CVector::x();}
+ inline Real uy (void) {return CVector::y();}
+ inline Real uz (void) {return CVector::z();}
+ inline Real& f (void) {return s;}
+ inline Real& v (void) {return vol;}
+ inline const unsigned int& id (void) const {return i;}
+ SimpleVertexInfo (void) {isFictious=false; s=0; i=0; vol=-1;}
+ //virtual function that will be defined for all classes, allowing shared function (e.g. for display)
+ bool isReal (void) {return !isFictious;}
+};
+
+
template<class vertex_info, class cell_info>
class TriangulationTypes {
@@ -26,28 +97,24 @@
typedef CGAL::Triangulation_3<K> Triangulation;
typedef CGAL::Regular_triangulation_3<Traits, Tds> RTriangulation;
-typedef typename RTriangulation::Vertex_iterator Vertex_iterator;
-typedef typename RTriangulation::Vertex_handle Vertex_handle;
-typedef typename RTriangulation::Finite_vertices_iterator Finite_vertices_iterator;
-typedef typename RTriangulation::Cell_iterator Cell_iterator;
-typedef typename RTriangulation::Finite_cells_iterator Finite_cells_iterator;
-typedef typename RTriangulation::Cell_circulator Cell_circulator;
-typedef typename RTriangulation::Cell_handle Cell_handle;
+typedef typename RTriangulation::Vertex_iterator VertexIterator;
+typedef typename RTriangulation::Vertex_handle VertexHandle;
+typedef typename RTriangulation::Finite_vertices_iterator FiniteVerticesIterator;
+typedef typename RTriangulation::Cell_iterator CellIterator;
+typedef typename RTriangulation::Finite_cells_iterator FiniteCellsIterator;
+typedef typename RTriangulation::Cell_circulator CellCirculator;
+typedef typename RTriangulation::Cell_handle CellHandle;
typedef typename RTriangulation::Facet Facet;
-typedef typename RTriangulation::Facet_iterator Facet_iterator;
-typedef typename RTriangulation::Facet_circulator Facet_circulator;
-typedef typename RTriangulation::Finite_facets_iterator Finite_facets_iterator;
-typedef typename RTriangulation::Locate_type Locate_type;
+typedef typename RTriangulation::Facet_iterator FacetIterator;
+typedef typename RTriangulation::Facet_circulator FacetCirculator;
+typedef typename RTriangulation::Finite_facets_iterator FiniteFacetsIterator;
+typedef typename RTriangulation::Locate_type LocateType;
-typedef typename RTriangulation::Edge_iterator Edge_iterator;
-typedef typename RTriangulation::Finite_edges_iterator Finite_edges_iterator;
+typedef typename RTriangulation::Edge_iterator EdgeIterator;
+typedef typename RTriangulation::Finite_edges_iterator FiniteEdgesIterator;
};
-typedef CGAL::To_double<double> W_TO_DOUBLE; // foncteur Weight to Real
typedef TriangulationTypes<SimpleVertexInfo,SimpleCellInfo> SimpleTriangulationTypes;
-typedef TriangulationTypes<FlowVertexInfo,FlowCellInfo> FlowTriangulationTypes;
-typedef TriangulationTypes<PeriodicVertexInfo,PeriodicCellInfo> PeriFlowTriangulationTypes;
-typedef TriangulationTypes<UnsatVertexInfo,UnsatCellInfo> UnsatFlowTriangulationTypes;
} // namespace CGT
=== modified file 'lib/triangulation/Tenseur3.cpp'
--- lib/triangulation/Tenseur3.cpp 2012-01-20 17:31:56 +0000
+++ lib/triangulation/Tenseur3.cpp 2014-03-21 18:45:24 +0000
@@ -1,6 +1,6 @@
#include "Tenseur3.h"
-#include "def_types.h" //pour d�finition de la classe "Vecteur"
+#include "RegularTriangulation.h"
using namespace std;
namespace CGT {
@@ -14,16 +14,16 @@
return N;
}
-Vecteur operator* (Tens& tens, Vecteur& vect)
+CVector operator* (Tens& tens, CVector& vect)
{
- Vecteur result;
- result = Vecteur( tens(1,1)*vect.x()+ tens(1,2)*vect.y()+ tens(1,3)*vect.z(),
+ CVector result;
+ result = CVector( tens(1,1)*vect.x()+ tens(1,2)*vect.y()+ tens(1,3)*vect.z(),
tens(2,1)*vect.x()+ tens(2,2)*vect.y()+ tens(2,3)*vect.z(),
tens(3,1)*vect.x()+ tens(3,2)*vect.y()+ tens(3,3)*vect.z() );
return result;
}
-Vecteur& NormalizedVecteur (Vecteur& vect)
+CVector& NormalizedCVector (CVector& vect)
{
vect = vect*(1.0/sqrt(pow(vect.x(),2)+pow(vect.y(),2)+pow(vect.z(),2)));
return vect;
@@ -233,7 +233,7 @@
}
}
-void Tenseur_produit (Vecteur &v1, Vecteur &v2, Tenseur3 &result)
+void Tenseur_produit (CVector &v1, CVector &v2, Tenseur3 &result)
{
result(1,1) = v1.x()*v2.x();
result(1,2) = v1.x()*v2.y();
@@ -246,7 +246,7 @@
result(3,3) = v1.z()*v2.z();
}
-void Somme (Tenseur3 &result, Vecteur &v1, Vecteur &v2)
+void Somme (Tenseur3 &result, CVector &v1, CVector &v2)
{
result(1,1) += v1.x()*v2.x();
result(1,2) += v1.x()*v2.y();
=== modified file 'lib/triangulation/Tenseur3.h'
--- lib/triangulation/Tenseur3.h 2013-08-22 14:32:01 +0000
+++ lib/triangulation/Tenseur3.h 2014-03-21 18:45:24 +0000
@@ -1,8 +1,8 @@
#pragma once
-#include "def_types.h"
#include <iostream>
#include <fstream>
+#include "RegularTriangulation.h"
namespace CGT {
@@ -13,12 +13,12 @@
class Tenseur_sym3;
class Tenseur_anti3;
-Vecteur operator* ( Tens& tens, Vecteur& vect );
-Vecteur& NormalizedVecteur ( Vecteur& vect );
-
-
-void Tenseur_produit ( Vecteur &v1, Vecteur &v2, Tenseur3 &result );
-void Somme ( Tenseur3 &result, Vecteur &v1, Vecteur &v2 );
+CVector operator* ( Tens& tens, CVector& vect );
+CVector& NormalizedCVector ( CVector& vect );
+
+
+void Tenseur_produit ( CVector &v1, CVector &v2, Tenseur3 &result );
+void Somme ( Tenseur3 &result, CVector &v1, CVector &v2 );
std::ostream& operator<< ( std::ostream& os,const Tenseur3& T );
std::ostream& operator<< ( std::ostream& os,const Tenseur_sym3& T );
=== modified file 'lib/triangulation/Tesselation.h'
--- lib/triangulation/Tesselation.h 2013-07-26 14:55:13 +0000
+++ lib/triangulation/Tesselation.h 2014-03-21 18:47:45 +0000
@@ -1,5 +1,5 @@
/*************************************************************************
-* Copyright (C) 2006 by Bruno Chareyre *
+* Copyright (C) 2006 by Bruno Chareyre *
* bruno.chareyre@xxxxxxxxxxx *
* *
* This program is free software; it is licensed under the terms of the *
@@ -12,27 +12,27 @@
//Since template inheritance does not automatically give access to the members of the base class, this macro can be used to declare all members at once.
#define DECLARE_TESSELATION_TYPES(baseType)\
- typedef typename baseType::RTriangulation RTriangulation;\
- typedef typename baseType::Vertex_Info Vertex_Info;\
- typedef typename baseType::Cell_Info Cell_Info;\
- typedef typename baseType::Vertex_iterator Vertex_iterator;\
- typedef typename baseType::Vertex_handle Vertex_handle;\
- typedef typename baseType::Finite_vertices_iterator Finite_vertices_iterator;\
- typedef typename baseType::Cell_iterator Cell_iterator;\
- typedef typename baseType::Finite_cells_iterator Finite_cells_iterator;\
- typedef typename baseType::Cell_circulator Cell_circulator;\
- typedef typename baseType::Cell_handle Cell_handle;\
- typedef typename baseType::Facet Facet;\
- typedef typename baseType::Facet_iterator Facet_iterator;\
- typedef typename baseType::Facet_circulator Facet_circulator;\
- typedef typename baseType::Finite_facets_iterator Finite_facets_iterator;\
- typedef typename baseType::Locate_type Locate_type;\
- typedef typename baseType::Edge_iterator Edge_iterator;\
- typedef typename baseType::Finite_edges_iterator Finite_edges_iterator;\
- typedef typename baseType::Vector_Vertex Vector_Vertex;\
- typedef typename baseType::Vector_Cell Vector_Cell;\
- typedef typename baseType::List_Point List_Point;\
- typedef typename baseType::VCell_iterator VCell_iterator;
+ typedef typename baseType::RTriangulation RTriangulation;\
+ typedef typename baseType::VertexInfo VertexInfo;\
+ typedef typename baseType::CellInfo CellInfo;\
+ typedef typename baseType::VertexIterator VertexIterator;\
+ typedef typename baseType::VertexHandle VertexHandle;\
+ typedef typename baseType::FiniteVerticesIterator FiniteVerticesIterator;\
+ typedef typename baseType::CellIterator CellIterator;\
+ typedef typename baseType::FiniteCellsIterator FiniteCellsIterator;\
+ typedef typename baseType::CellCirculator CellCirculator;\
+ typedef typename baseType::CellHandle CellHandle;\
+ typedef typename baseType::Facet Facet;\
+ typedef typename baseType::FacetIterator FacetIterator;\
+ typedef typename baseType::FacetCirculator FacetCirculator;\
+ typedef typename baseType::FiniteFacetsIterator FiniteFacetsIterator;\
+ typedef typename baseType::LocateType LocateType;\
+ typedef typename baseType::EdgeIterator EdgeIterator;\
+ typedef typename baseType::FiniteEdgesIterator FiniteEdgesIterator;\
+ typedef typename baseType::VectorVertex VectorVertex;\
+ typedef typename baseType::VectorCell VectorCell;\
+ typedef typename baseType::ListPoint ListPoint;\
+ typedef typename baseType::VCellIterator VCellIterator;
// Classe Tesselation, contient les fonctions permettant de calculer la Tessalisation
// d'une RTriangulation et de stocker les centres dans chacune de ses cellules
@@ -43,90 +43,89 @@
{
public:
typedef typename TT::RTriangulation RTriangulation;
- typedef typename TT::Vertex_Info Vertex_Info;
- typedef typename TT::Cell_Info Cell_Info;
- typedef typename RTriangulation::Vertex_iterator Vertex_iterator;
- typedef typename RTriangulation::Vertex_handle Vertex_handle;
- typedef typename RTriangulation::Finite_vertices_iterator Finite_vertices_iterator;
- typedef typename RTriangulation::Cell_iterator Cell_iterator;
- typedef typename RTriangulation::Finite_cells_iterator Finite_cells_iterator;
- typedef typename RTriangulation::Cell_circulator Cell_circulator;
- typedef typename RTriangulation::Cell_handle Cell_handle;
+ typedef typename TT::Vertex_Info VertexInfo;
+ typedef typename TT::Cell_Info CellInfo;
+ typedef typename RTriangulation::Vertex_iterator VertexIterator;
+ typedef typename RTriangulation::Vertex_handle VertexHandle;
+ typedef typename RTriangulation::Finite_vertices_iterator FiniteVerticesIterator;
+ typedef typename RTriangulation::Cell_iterator CellIterator;
+ typedef typename RTriangulation::Finite_cells_iterator FiniteCellsIterator;
+ typedef typename RTriangulation::Cell_circulator CellCirculator;
+ typedef typename RTriangulation::Cell_handle CellHandle;
typedef typename RTriangulation::Facet Facet;
- typedef typename RTriangulation::Facet_iterator Facet_iterator;
- typedef typename RTriangulation::Facet_circulator Facet_circulator;
- typedef typename RTriangulation::Finite_facets_iterator Finite_facets_iterator;
- typedef typename RTriangulation::Locate_type Locate_type;
- typedef typename RTriangulation::Edge_iterator Edge_iterator;
- typedef typename RTriangulation::Finite_edges_iterator Finite_edges_iterator;
+ typedef typename RTriangulation::Facet_iterator FacetIterator;
+ typedef typename RTriangulation::Facet_circulator FacetCirculator;
+ typedef typename RTriangulation::Finite_facets_iterator FiniteFacetsIterator;
+ typedef typename RTriangulation::Locate_type LocateType;
+ typedef typename RTriangulation::Edge_iterator EdgeIterator;
+ typedef typename RTriangulation::Finite_edges_iterator FiniteEdgesIterator;
- typedef std::vector<Vertex_handle> Vector_Vertex;
- typedef std::vector<Cell_handle> Vector_Cell;
- typedef std::list<Point> List_Point;
- typedef typename Vector_Cell::iterator VCell_iterator;
- int max_id;
+ typedef std::vector<VertexHandle> VectorVertex;
+ typedef std::vector<CellHandle> VectorCell;
+ typedef std::list<Point> ListPoint;
+ typedef typename VectorCell::iterator VCellIterator;
+ int maxId;
protected:
RTriangulation* Tri;
RTriangulation* Tes; //=NULL or Tri depending on the constructor used.
- bool computed;
+
public:
Real TotalFiniteVoronoiVolume;
Real area;
Real TotalInternalVoronoiVolume;
Real TotalInternalVoronoiPorosity;
- Vector_Vertex vertexHandles;//This is a redirection vector to get vertex pointers by spheres id
- Vector_Cell cellHandles;//for speedup of global loops, iterating on this vector is faster than cellIterator++
- bool redirected;//is vertexHandles filled with current vertex pointers?
+ VectorVertex vertexHandles;//This is a redirection vector to get vertex pointers by spheres id
+ VectorCell cellHandles;//for speedup of global loops, iterating on this vector is faster than cellIterator++
+ bool redirected;//is vertexHandles filled with current vertex pointers?
+ bool computed;
-public:
- _Tesselation(void);
+ _Tesselation(void);
_Tesselation(RTriangulation &T);// : Tri(&T) { Calcule(); }
~_Tesselation(void);
///Insert a sphere
- Vertex_handle insert(Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious = false);
+ VertexHandle insert(Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious = false);
/// move a spheres
- Vertex_handle move (Real x, Real y, Real z, Real rad, unsigned int id);
+ VertexHandle move (Real x, Real y, Real z, Real rad, unsigned int id);
///Fill a vector with vertexHandles[i] = handle of vertex with id=i for fast access
bool redirect (void);
///Remove a sphere
bool remove (unsigned int id);
- int Max_id (void) {return max_id;}
+ int Max_id (void) {return maxId;}
- void Compute (); //Calcule le centres de Voronoi pour chaque cellule
+ void compute (); //Calcule le centres de Voronoi pour chaque cellule
void Invalidate () {computed=false;} //Set the tesselation as "not computed" (computed=false), this will launch //tesselation internaly when using functions like computeVolumes())
- // N.B : Compute() must be executed before the functions below are used
+ // N.B : compute() must be executed before the functions below are used
void Clear(void);
- static Point Dual (const Cell_handle &cell);
- static Plan Dual (Vertex_handle S1, Vertex_handle S2);
- static Segment Dual (Finite_facets_iterator &facet); //G�n�re le segment dual d'une facette finie
- static Real Volume (Finite_cells_iterator cell);
- inline void AssignPartialVolume (Finite_edges_iterator& ed_it);
-// inline void ComputeVFacetArea (Finite_edges_iterator& ed_it);
- double ComputeVFacetArea (Finite_edges_iterator ed_it);
+ static Point Dual (const CellHandle &cell);
+ static Plane Dual (VertexHandle S1, VertexHandle S2);
+ static Segment Dual (FiniteFacetsIterator &facet); //G�n�re le segment dual d'une facette finie
+ static Real Volume (FiniteCellsIterator cell);
+ inline void AssignPartialVolume (FiniteEdgesIterator& ed_it);
+ double computeVFacetArea (FiniteEdgesIterator ed_it);
void ResetVCellVolumes (void);
- void ComputeVolumes (void);//Compute volume each voronoi cell
- void ComputePorosity (void);//Compute volume and porosity of each voronoi cell
+ void computeVolumes (void);//compute volume each voronoi cell
+ void computePorosity (void);//compute volume and porosity of each voronoi cell
inline Real& Volume (unsigned int id) { return vertexHandles[id]->info().v(); }
- inline const Vertex_handle& vertex (unsigned int id) const { return vertexHandles[id]; }
+ inline const VertexHandle& vertex (unsigned int id) const { return vertexHandles[id]; }
- Finite_cells_iterator finite_cells_begin(void);// {return Tri->finite_cells_begin();}
- Finite_cells_iterator finite_cells_end(void);// {return Tri->finite_cells_end();}
- void Voisins (Vertex_handle v, Vector_Vertex& Output_vector);// {Tri->incident_vertices(v, back_inserter(Output_vector));}
+// FiniteCellsIterator finite_cells_begin(void);// {return Tri->finite_cells_begin();}
+// FiniteCellsIterator finiteCellsEnd(void);// {return Tri->finite_cells_end();}
+ void voisins (VertexHandle v, VectorVertex& Output_vector);// {Tri->incident_vertices(v, back_inserter(Output_vector));}
RTriangulation& Triangulation (void);// {return *Tri;}
- bool Computed (void) {return computed;}
-
- bool is_short ( Finite_facets_iterator f_it );
- inline bool is_internal ( Finite_facets_iterator &facet );//
-
- long New_liste_edges ( Real** Coordonnes ); //Genere la liste des segments de Voronoi
- long New_liste_short_edges ( Real** Coordonnes ); //Genere la version tronquee (partie interieure) du graph de Voronoi
- long New_liste_short_edges2 ( Real** Coordonnes );
- long New_liste_adjacent_edges ( Vertex_handle vertex0, Real** Coordonnes );
+// bool computed (void) {return computed;}
+
+ bool is_short ( FiniteFacetsIterator f_it );
+ inline bool is_internal ( FiniteFacetsIterator &facet );//
+
+ long newListeEdges ( Real** Coordonnes ); //Genere la liste des segments de Voronoi
+ long newListeShortEdges ( Real** Coordonnes ); //Genere la version tronquee (partie interieure) du graph de Voronoi
+ long newListeShortEdges2 ( Real** Coordonnes );
+ long New_liste_adjacent_edges ( VertexHandle vertex0, Real** Coordonnes );
};
@@ -138,11 +137,11 @@
DECLARE_TESSELATION_TYPES(Tesselation)
using Tesselation::Tri;
using Tesselation::vertexHandles;
- using Tesselation::max_id;
+ using Tesselation::maxId;
using Tesselation::redirected;
///Insert a sphere, which can be a duplicate one from the base period if duplicateOfId>=0
- Vertex_handle insert(Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious = false, int duplicateOfId=-1);
+ VertexHandle insert(Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious = false, int duplicateOfId=-1);
///Fill a vector with vertexHandles[i] = handle of vertex with id=i for fast access, contains only spheres from the base period
bool redirect (void);
};
@@ -153,7 +152,6 @@
//Explicit instanciation
typedef CGT::_Tesselation<CGT::SimpleTriangulationTypes> SimpleTesselation;
-typedef CGT::_Tesselation<CGT::FlowTriangulationTypes> FlowTesselation;
-typedef CGT::PeriodicTesselation<CGT::_Tesselation<CGT::PeriFlowTriangulationTypes> > PeriFlowTesselation;
-typedef CGT::_Tesselation<CGT::UnsatFlowTriangulationTypes> UnsatTesselation;
+
+
=== modified file 'lib/triangulation/Tesselation.ipp'
--- lib/triangulation/Tesselation.ipp 2012-07-09 12:19:23 +0000
+++ lib/triangulation/Tesselation.ipp 2014-03-21 18:47:45 +0000
@@ -16,11 +16,10 @@
template<class TT>
_Tesselation<TT>::_Tesselation ( void )
{
-// std::cout << "Tesselation(void)" << std::endl;
Tri = new RTriangulation;
Tes = Tri;
computed=false;
- max_id = -1;
+ maxId = -1;
TotalFiniteVoronoiVolume=0;
area=0;
TotalInternalVoronoiPorosity=0;
@@ -33,7 +32,7 @@
_Tesselation<TT>::_Tesselation ( RTriangulation &T ) : Tri ( &T ), Tes ( &T ), computed ( false )
{
std::cout << "Tesselation(RTriangulation &T)" << std::endl;
- Compute();
+ compute();
}
template<class TT>
@@ -48,34 +47,34 @@
redirected = false;
vertexHandles.clear();
vertexHandles.resize(MAX_ID+1,NULL);
- max_id=0;
+ maxId=0;
}
template<class TT>
-typename _Tesselation<TT>::Vertex_handle _Tesselation<TT>::insert ( Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious )
+typename _Tesselation<TT>::VertexHandle _Tesselation<TT>::insert ( Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious )
{
- Vertex_handle Vh;
+ VertexHandle Vh;
Vh = Tri->insert(Sphere(Point(x,y,z),pow(rad,2)));
if ( Vh!=NULL )
{
- Vh->info() = id;
+ Vh->info().setId(id);
Vh->info().isFictious = isFictious;
assert (vertexHandles.size()>id);
vertexHandles[id] = Vh;
- /*if ( !isFictious ) */max_id = std::max ( max_id, (int) id );
+ /*if ( !isFictious ) */maxId = std::max ( maxId, (int) id );
}
else cout << id << " : Vh==NULL!!"<< " id=" << id << " Point=" << Point ( x,y,z ) << " rad=" << rad << endl;
return Vh;
}
template<class TT>
-typename _Tesselation<TT>::Vertex_handle _Tesselation<TT>::move ( Real x, Real y, Real z, Real rad, unsigned int id )
+typename _Tesselation<TT>::VertexHandle _Tesselation<TT>::move ( Real x, Real y, Real z, Real rad, unsigned int id )
{
bool fictious = vertexHandles[id]->info().isFictious;
- Vertex_handle Vh;
+ VertexHandle Vh;
Vh = Tri->move_point ( vertexHandles[id], Sphere ( Point ( x,y,z ),pow ( rad,2 ) ) );
if ( Vh!=NULL )
{
vertexHandles[id] = Vh;
- Vh->info() = id;
+ Vh->info().setId(id);
Vh->info().isFictious = fictious;
}
else cerr << "Vh==NULL" << " id=" << id << " Point=" << Point ( x,y,z ) << " rad=" << rad << endl;
@@ -89,18 +88,15 @@
if ( !redirected )
{
//Set size of the redirection vector
- if ( (unsigned int)max_id+1 != vertexHandles.size() ) vertexHandles.resize ( max_id+1,NULL );
- //cout << "!redirected" << endl;
- max_id = 0;
- Finite_vertices_iterator vertices_end = Tri->finite_vertices_end ();
- for ( Finite_vertices_iterator V_it = Tri->finite_vertices_begin (); V_it != vertices_end; V_it++ )
+ if ( (unsigned int)maxId+1 != vertexHandles.size() ) vertexHandles.resize ( maxId+1,NULL );
+ maxId = 0;
+ FiniteVerticesIterator verticesEnd = Tri->finite_vertices_end ();
+ for ( FiniteVerticesIterator vIt = Tri->finite_vertices_begin (); vIt != verticesEnd; vIt++ )
{
- vertexHandles[V_it->info().id()]= V_it;
- max_id = max(max_id, (int) V_it->info().id());
- //if ( ! ( V_it->info().isFictious ) ) vertexHandles[V_it->info().id() ]= V_it;
- //std::cout<< "Cell " << V_it->info().id() << ": v=" << V_it->info().v() << std::endl;
+ vertexHandles[vIt->info().id()]= vIt;
+ maxId = max(maxId, (int) vIt->info().id());
}
- if ( (unsigned int)max_id+1 != vertexHandles.size() ) vertexHandles.resize ( max_id+1 );
+ if ( (unsigned int)maxId+1 != vertexHandles.size() ) vertexHandles.resize ( maxId+1 );
redirected = true;
} else return false;
return true;
@@ -115,15 +111,7 @@
}
template<class TT>
-typename _Tesselation<TT>::Finite_cells_iterator _Tesselation<TT>::finite_cells_begin ( void )
-{ return Tri->finite_cells_begin(); }
-
-template<class TT>
-typename _Tesselation<TT>::Finite_cells_iterator _Tesselation<TT>::finite_cells_end ( void )
-{ return Tri->finite_cells_end(); }
-
-template<class TT>
-void _Tesselation<TT>::Voisins ( Vertex_handle v, Vector_Vertex& Output_vector )
+void _Tesselation<TT>::voisins ( VertexHandle v, VectorVertex& Output_vector )
{ Tri->incident_vertices ( v, back_inserter ( Output_vector ) ); }
template<class TT>
@@ -131,14 +119,14 @@
{ return *Tri; }
template<class TT>
-Real _Tesselation<TT>::Volume ( Finite_cells_iterator cell )
+Real _Tesselation<TT>::Volume ( FiniteCellsIterator cell )
{
- return ( Tetraedre ( cell->vertex ( 0 )->point(), cell->vertex ( 1 )->point(),
+ return ( Tetrahedron ( cell->vertex ( 0 )->point(), cell->vertex ( 1 )->point(),
cell->vertex ( 2 )->point(), cell->vertex ( 3 )->point() ) ).volume();
}
template<class TT>
-Plan _Tesselation<TT>::Dual ( Vertex_handle S1, Vertex_handle S2 )
+Plane _Tesselation<TT>::Dual ( VertexHandle S1, VertexHandle S2 )
{
Segment seg ( S1->point(), S2->point() );
Real r = 0.5* ( 1.0 + ( ( S1->point() ).weight() * ( S1->point() ).weight() - ( S2->point() ).weight() * ( S2->point() ).weight() ) /seg.squared_length() );
@@ -146,17 +134,17 @@
}
template<class TT>
-Point _Tesselation<TT>::Dual ( const Cell_handle &cell )
+Point _Tesselation<TT>::Dual ( const CellHandle &cell )
{
return cell->info();
}
template<class TT>
-void _Tesselation<TT>::Compute ()
+void _Tesselation<TT>::compute ()
{
if (!redirected) redirect();
- Finite_cells_iterator cell_end = Tri->finite_cells_end();
- for ( Finite_cells_iterator cell = Tri->finite_cells_begin(); cell != cell_end; cell++ )
+ FiniteCellsIterator cellEnd = Tri->finite_cells_end();
+ for ( FiniteCellsIterator cell = Tri->finite_cells_begin(); cell != cellEnd; cell++ )
{
const Sphere& S0 = cell->vertex ( 0 )->point();
@@ -170,235 +158,46 @@
S2.point().x(), S2.point().y(), S2.point().z(), S2.weight(),
S3.point().x(), S3.point().y(), S3.point().z(), S3.weight(),
x, y, z );
- cell->info() =Point ( x,y,z );
+ cell->info().setPoint(Point(x,y,z));
}
computed = true;
}
-// long Tesselation::New_liste_adjacent_edges ( Vertex_handle vertex0, Real** Coordonnes )
-// {
-// Delete_liste_edges ( Coordonnes );
-// *Coordonnes = new Real [600];
-// long k = 0;
-// Finite_edges_iterator ed_it;
-//
-// for ( ed_it = Tri->finite_edges_begin(); ed_it != Tri->finite_edges_end(); ed_it++ )
-// {
-// if ( ed_it->first->vertex ( ed_it->second ) == vertex0 || ed_it->first->vertex ( ed_it->third ) == vertex0 )
-// {
-// Point p;
-// Facet_circulator facet0, facet;
-// facet0 = Tri->incident_facets ( *ed_it );
-// bool pass = false;
-// for ( facet = facet0; ! ( facet == facet0 && pass ) ; facet++ )
-// {
-// pass = true;
-// if ( !Tri->is_infinite ( ( *facet ).first ) && !Tri->is_infinite ( ( *facet ).first->neighbor ( ( *facet ).second ) ) )
-// {
-// // cout << "p.x() = " << p.x() << "p.y() = " << p.y() << "p.z() = " << p.z() << endl;
-// p = ( *facet ).first->info();
-// ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
-// p = ( *facet ).first->neighbor ( ( *facet ).second )->info();
-// ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
-// }
-// }
-// }
-// }
-//
-//
-// return k/6;
-// }
-
-/*
-long Tesselation::New_liste_short_edges2 ( Real** Coordonnes )
-{
- Delete_liste_edges ( Coordonnes );
- //long j = 6 * T.number_of_finite_edges();
-
- long Nff = Tri->number_of_finite_facets();
- *Coordonnes = new Real [6 * Nff];
-
- long k = 0;
- Point p, p2;
- Finite_facets_iterator f_it; //une facette = { cell, long }
- Cell_handle cell;
-// long id_facet ;
-// Locate_type lt;
-// int n, m;
- CGAL::Object result; //utilis� pour le retour du pr�dicat CGAL::intersection
-
- // const Edge & e : (e.first, e.second, e.third) == const Cell_handle& c, int i, int j
- //H2.top("initialisation de la liste de segments");
- for ( f_it = Tri->finite_facets_begin(); f_it != Tri->finite_facets_end(); f_it++ )
- {
- if ( is_short ( f_it ) )
- {
- p = f_it->first->info();
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
- Cell_handle cell = f_it->first->neighbor ( f_it->second );
-
- p = cell->info();
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
- }
- }
- return k/6;
-}*/
-/*
-bool Tesselation::is_short ( Finite_facets_iterator f_it )
-{
- Cell_handle cell1 = f_it->first;
- Cell_handle cell2 = cell1->neighbor ( f_it->second );
-// return ( !Tri->is_infinite(cell1->neighbor(1)) && !Tri->is_infinite(cell1->neighbor(2))
-// && !Tri->is_infinite(cell1->neighbor(3)) && !Tri->is_infinite(cell1->neighbor(0))
-// && !Tri->is_infinite(cell2->neighbor(1)) && !Tri->is_infinite(cell2->neighbor(2))
-// && !Tri->is_infinite(cell2->neighbor(3)) && !Tri->is_infinite(cell2->neighbor(0)) );
- return ( !Tri->is_infinite ( cell1 ) && !Tri->is_infinite ( cell2 ) );
-
-}*/
-/*
-long Tesselation::New_liste_short_edges ( Real** Coordonnes )
-{
- Delete_liste_edges ( Coordonnes );
- //long j = 6 * T.number_of_finite_edges();
-
- long Nff = Tri->number_of_finite_facets();
- *Coordonnes = new Real [6 * Nff];
-
- long k = 0;
- int n = 0;
- Point p, p2;
- Point v1, v2, v3;
- Finite_facets_iterator f_it; //une facette = { cell, long }
- Cell_handle cell, location;
- long id_facet ;
- CGAL::Object result; //utilis� pour le retour du pr�dicat CGAL::intersection
-
- // const Edge & e : (e.first, e.second, e.third) == const Cell_handle& c, int i, int j
- //H2.top("initialisation de la liste de segments");
- for ( f_it = Tri->finite_facets_begin(); f_it != Tri->finite_facets_end(); f_it++ )
- {
- id_facet = f_it->second; //indice de la facette dans la cellule
- cell = f_it->first->neighbor ( id_facet ); //Deuxi�me cellule adjacente
- if ( !Tri->is_infinite ( f_it->first ) && !Tri->is_infinite ( cell ) )
- {
- p = f_it->first->info();
- p2 = cell->info();
-
- location = Tri->locate ( p );
- if ( !Tri->is_infinite ( location ) )
- {
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
-
- location = Tri->locate ( p2 );
- if ( !Tri->is_infinite ( location ) ) { p = p2; }
- else
- {
- n = 0;
- v1 = f_it->first->vertex ( n == id_facet ? ++n : n )->point(); n++;
- v2 = f_it->first->vertex ( n == id_facet ? ++n : n )->point(); n++;
- v3 = f_it->first->vertex ( n == id_facet ? ++n : n )->point(); n++;
- Plan P1 ( v1, v2, v3 );
-
- result = CGAL::intersection ( P1, Droite ( p, p2 ) );
- if ( !CGAL::assign ( p, result ) ) std::cout << "pas de point d'intersection!!!!!!!!!" << std::endl;
- }
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
- }
- else
- {
- location = Tri->locate ( p2 );
- if ( !Tri->is_infinite ( location ) )
- {
- ( *Coordonnes ) [k++] = p2.x(); ( *Coordonnes ) [k++] = p2.y(); ( *Coordonnes ) [k++] = p2.z();
- n = 0;
- n = 0;
- v1 = f_it->first->vertex ( n == id_facet ? ++n : n )->point(); n++;
- v2 = f_it->first->vertex ( n == id_facet ? ++n : n )->point(); n++;
- v3 = f_it->first->vertex ( n == id_facet ? ++n : n )->point(); n++;
- Plan P1 ( v1, v2, v3 );
-
- result = CGAL::intersection ( P1, Droite ( p, p2 ) );
- if ( !CGAL::assign ( p, result ) ) std::cout << "pas de point d'intersection!!!!!!!!!" << std::endl;
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
- }
- }
- }
- }
- return k/6;
-}
-
-
-
-long Tesselation::New_liste_edges ( Real** Coordonnes )
-{
- Delete_liste_edges ( Coordonnes );
- //long j = 6 * T.number_of_finite_edges();
-
- long Nff = Tri->number_of_finite_facets();
- *Coordonnes = new Real [6 * Nff];
-
- long k = 0;
- Point p;
-
- // const Edge & e : (e.first, e.second, e.third) == const Cell_handle& c, int i, int j
- //H2.top("initialisation de la liste de segments");
- for ( Finite_facets_iterator f_it = Tri->finite_facets_begin(); f_it != Tri->finite_facets_end(); f_it++ )
- {
- if ( !Tri->is_infinite ( f_it->first ) )
- {
- p = f_it->first->info();
- //}
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
-
- Cell_handle cell = f_it->first->neighbor ( f_it->second );
- if ( !Tri->is_infinite ( cell ) )
- {
- p = cell->info();
- }
- ( *Coordonnes ) [k++] = p.x(); ( *Coordonnes ) [k++] = p.y(); ( *Coordonnes ) [k++] = p.z();
- }
- }
- return Nff;
-}*/
-
template<class TT>
-Segment _Tesselation<TT>::Dual ( Finite_facets_iterator &f_it )
+Segment _Tesselation<TT>::Dual ( FiniteFacetsIterator &f_it )
{
return Segment ( f_it->first->info(), ( f_it->first->neighbor ( f_it->second ) )->info() );
}
template<class TT>
-double _Tesselation<TT>::ComputeVFacetArea ( Finite_edges_iterator ed_it )
+double _Tesselation<TT>::computeVFacetArea ( FiniteEdgesIterator ed_it )
{
- Cell_circulator cell0 = Tri->incident_cells ( *ed_it );
- Cell_circulator cell2 = cell0;
+ CellCirculator cell0 = Tri->incident_cells ( *ed_it );
+ CellCirculator cell2 = cell0;
- if ( Tri->is_infinite ( cell2 ) )
- {
+ if ( Tri->is_infinite ( cell2 ) ){
++cell2;
while ( Tri->is_infinite ( cell2 ) && cell2!=cell0 ) ++cell2;
if ( cell2==cell0 ) return 0;
}
cell0=cell2++;
- Cell_circulator cell1=cell2++;
+ CellCirculator cell1=cell2++;
Real area = 0;
- while ( cell2!=cell0 )
- {
+ while ( cell2!=cell0 ){
area+= sqrt(std::abs (( Triangle ( cell0->info(), cell1->info(), cell2->info() ) ).squared_area())) ;
++cell1;
++cell2;
}
-
return area;
}
template<class TT>
-void _Tesselation<TT>::AssignPartialVolume ( Finite_edges_iterator& ed_it )
+void _Tesselation<TT>::AssignPartialVolume ( FiniteEdgesIterator& ed_it )
{
- //Edge_iterator ed_it
- Cell_circulator cell0=Tri->incident_cells ( *ed_it );
- Cell_circulator cell2=cell0;
+ //EdgeIterator ed_it
+ CellCirculator cell0=Tri->incident_cells ( *ed_it );
+ CellCirculator cell2=cell0;
if ( Tri->is_infinite ( cell2 ) )
{
++cell2;
@@ -406,116 +205,74 @@
if ( cell2==cell0 ) return;
}
cell0=cell2++;
- Cell_circulator cell1=cell2++;
-// std::cout << "edge : " << ed_it->first->vertex ( ed_it->second )->info().id() << "-" << ed_it->first->vertex ( ed_it->third )->info().id() << std::endl;
+ CellCirculator cell1=cell2++;
bool isFictious1 = ( ed_it->first )->vertex ( ed_it->second )->info().isFictious;
bool isFictious2 = ( ed_it->first )->vertex ( ed_it->third )->info().isFictious;
-// cout<<"fictious "<<isFictious1<<" "<<isFictious2<<endl;
Real r;
-
-// cout << "cell0 : " << cell0->vertex(0)->info().id() << " "
-// << cell0->vertex(1)->info().id() << " "
-// << cell0->vertex(2)->info().id() << " "
-// << cell0->vertex(3)->info().id() << "(center : " << (Point) cell0->info() << ")" << endl;
-
while ( cell2!=cell0 )
{
if ( !Tri->is_infinite ( cell1 ) && !Tri->is_infinite ( cell2 ) )
{
-// cout << "cell1 : " << cell1->vertex(0)->info().id() << " "
-// << cell1->vertex(1)->info().id() << " "
-// << cell1->vertex(2)->info().id() << " "
-// << cell1->vertex(3)->info().id() << "(center : " << (Point) cell1->info() << ")" << endl;
-// cout << "cell2 : " << cell2->vertex(0)->info().id() << " "
-// << cell2->vertex(1)->info().id() << " "
-// << cell2->vertex(2)->info().id() << " "
-// << cell2->vertex(3)->info().id() << "(center : " << (Point) cell2->info() << ")" << endl;
-
-// std::cout << "assign tetra : (" << ed_it->first->vertex ( ed_it->second )->point() << "),(" << cell0->info() << "),(" << cell1->info() << "),(" <<cell2->info() << ")" << std::endl;
if ( !isFictious1 )
{
- r = std::abs ( ( Tetraedre ( ed_it->first->vertex ( ed_it->second )->point(), cell0->info(), cell1->info(), cell2->info() ) ).volume() );
-// std::cout << "assigned1=" << r << " on " << ed_it->first->vertex ( ed_it->second )->info().id() << std::endl;
+ r = std::abs ( ( Tetrahedron ( ed_it->first->vertex ( ed_it->second )->point(), cell0->info(), cell1->info(), cell2->info() ) ).volume() );
( ed_it->first )->vertex ( ed_it->second )->info().v() += r;
TotalFiniteVoronoiVolume+=r;
}
-// std::cout << "assign tetra : (" << ed_it->first->vertex ( ed_it->third )->point() << "),(" << cell0->info() << "),(" << cell1->info() << "),(" <<cell2->info() << ")" << std::endl;
if ( !isFictious2 )
{
- r = std::abs ( ( Tetraedre ( ed_it->first->vertex ( ed_it->third )->point(), cell0->info(), cell1->info(), cell2->info() ) ).volume() );
-// std::cout << "assigned2=" << r << " on " << ed_it->first->vertex ( ed_it->third )->info().id() << std::endl;
+ r = std::abs ( ( Tetrahedron ( ed_it->first->vertex ( ed_it->third )->point(), cell0->info(), cell1->info(), cell2->info() ) ).volume() );
ed_it->first->vertex ( ed_it->third )->info().v() +=r;
TotalFiniteVoronoiVolume+=r;
}
}
++cell1; ++cell2;
}
-// std::cout << "fin AssignPartialVolume,total " << TotalFiniteVoronoiVolume<< std::endl;
}
template<class TT>
void _Tesselation<TT>::ResetVCellVolumes ( void )
{
- for ( Vertex_iterator V_it = Tri->vertices_begin (); V_it != Tri->vertices_end (); V_it++ )
- {
- V_it->info().v() =0;
- }
+ for ( VertexIterator vIt = Tri->vertices_begin (); vIt != Tri->vertices_end (); vIt++ ) vIt->info().v() =0;
TotalFiniteVoronoiVolume=0;
TotalInternalVoronoiPorosity=0;
}
template<class TT>
-void _Tesselation<TT>::ComputeVolumes ( void )
+void _Tesselation<TT>::computeVolumes ( void )
{
- if ( !computed ) Compute();
+ if ( !computed ) compute();
ResetVCellVolumes();
- for ( Finite_edges_iterator ed_it=Tri->finite_edges_begin(); ed_it!=Tri->finite_edges_end();ed_it++ )
+ for ( FiniteEdgesIterator ed_it=Tri->finite_edges_begin(); ed_it!=Tri->finite_edges_end();ed_it++ )
{
AssignPartialVolume ( ed_it );
}
- //Delete volume for spheres on the boarders of the packing
//FIXME: find a way to compute a volume correctly for spheres of the boarders.
-
-// Vector_Vertex boarder_vertices;
-// Voisins(Tri->infinite_vertex (), boarder_vertices);
-// unsigned int l = boarder_vertices.size();
-// for (unsigned int i=0; i<l; ++i) boarder_vertices[i]->info().v()=0;
-// cout << "TotalVolume : " << TotalFiniteVoronoiVolume << endl;
}
template<class TT>
-void _Tesselation<TT>::ComputePorosity ( void ) //WARNING : This function will erase real volumes of cells
+void _Tesselation<TT>::computePorosity ( void ) //WARNING : This function will erase real volumes of cells
{
- // and replace it with porosity
- ComputeVolumes();
- //Real rr=0;
- Finite_vertices_iterator vertices_end = Tri->finite_vertices_end ();
- for ( Finite_vertices_iterator V_it = Tri->finite_vertices_begin (); V_it != vertices_end; V_it++ )
+ computeVolumes();
+ FiniteVerticesIterator verticesEnd = Tri->finite_vertices_end ();
+ for ( FiniteVerticesIterator vIt = Tri->finite_vertices_begin (); vIt != verticesEnd; vIt++ )
{
- if ( V_it->info().v() && !V_it->info().isFictious )
+ if ( vIt->info().v() && !vIt->info().isFictious )
{
- Real r = 4.188790 * std::pow ( ( V_it->point().weight() ),1.5 );// 4/3*PI*R³ = 4.188...*R³
+ Real r = 4.188790 * std::pow ( ( vIt->point().weight() ),1.5 );// 4/3*PI*R³ = 4.188...*R³
TotalInternalVoronoiPorosity+=r;
- //rr+=V_it->info().v();
- TotalInternalVoronoiVolume += V_it->info().v();
- V_it->info().v() =
- ( V_it->info().v() - r )
- / V_it->info().v();
- //std::cout << "Cell " << V_it->info().id() << ": V_it->point().weight()=" << V_it->point().weight() << std::endl;
- std::cout << "Cell " << V_it->info().id() << ": v=" << V_it->info().v() << " radius=" << sqrt ( V_it->point().weight() ) << " volume sphere ="<< r << std::endl;
+ TotalInternalVoronoiVolume += vIt->info().v();
+ vIt->info().v() =
+ ( vIt->info().v() - r )
+ / vIt->info().v();
}
}
- std::cout << "total internal solid = " << TotalInternalVoronoiPorosity << std::endl;
- std::cout << "TotalFiniteVoronoiVolume = " << TotalFiniteVoronoiVolume << std::endl;
- std::cout << "TotalInternalVoronoiVolume = " << TotalInternalVoronoiVolume << std::endl;
-
TotalInternalVoronoiPorosity= ( TotalInternalVoronoiVolume-TotalInternalVoronoiPorosity ) /TotalInternalVoronoiVolume;
- std::cout << "TotalInternalVoronoiPorosity = " << TotalInternalVoronoiPorosity << std::endl;
}
template<class TT>
-bool _Tesselation<TT>::is_internal ( Finite_facets_iterator &facet )
+bool _Tesselation<TT>::is_internal ( FiniteFacetsIterator &facet )
{
return ( !Tri->is_infinite ( facet->first ) && !Tri->is_infinite ( facet->first->neighbor ( facet->second ) ) );
}
@@ -523,9 +280,9 @@
template<class Tesselation>
-typename Tesselation::Vertex_handle PeriodicTesselation<Tesselation>::insert(Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious, int duplicateOfId)
+typename Tesselation::VertexHandle PeriodicTesselation<Tesselation>::insert(Real x, Real y, Real z, Real rad, unsigned int id, bool isFictious, int duplicateOfId)
{
- Vertex_handle Vh;
+ VertexHandle Vh;
if (!Tri) cerr<<"!Tri!"<<endl;
Vh = Tri->insert(Sphere(Point(x,y,z),pow(rad,2)));
if ( Vh!=NULL )
@@ -535,7 +292,7 @@
if (duplicateOfId<0) {
assert (vertexHandles.size()>id);
vertexHandles[id] = Vh;
- max_id = std::max ( max_id, (int) id );
+ maxId = std::max ( maxId, (int) id );
Vh->info().isGhost=0;
} else Vh->info().isGhost=1;
}
@@ -549,19 +306,17 @@
if ( !redirected )
{
//Set size of the redirection vector
- if ( (unsigned int)max_id+1 != vertexHandles.size() ) vertexHandles.resize ( max_id+1,NULL );
+ if ( (unsigned int)maxId+1 != vertexHandles.size() ) vertexHandles.resize ( maxId+1,NULL );
cout << "!redirected" << endl;
- max_id = 0;
- Finite_vertices_iterator vertices_end = Tri->finite_vertices_end ();
- for ( Finite_vertices_iterator V_it = Tri->finite_vertices_begin (); V_it != vertices_end; V_it++ )
+ maxId = 0;
+ FiniteVerticesIterator verticesEnd = Tri->finite_vertices_end ();
+ for ( FiniteVerticesIterator vIt = Tri->finite_vertices_begin (); vIt != verticesEnd; vIt++ )
{
- if (V_it->info().isGhost) continue;
- vertexHandles[V_it->info().id()]= V_it;
- max_id = max(max_id, (int) V_it->info().id());
- //if ( ! ( V_it->info().isFictious ) ) vertexHandles[V_it->info().id() ]= V_it;
- //std::cout<< "Cell " << V_it->info().id() << ": v=" << V_it->info().v() << std::endl;
+ if (vIt->info().isGhost) continue;
+ vertexHandles[vIt->info().id()]= vIt;
+ maxId = max(maxId, (int) vIt->info().id());
}
- if ( (unsigned int)max_id+1 != vertexHandles.size() ) vertexHandles.resize ( max_id+1 );
+ if ( (unsigned int)maxId+1 != vertexHandles.size() ) vertexHandles.resize ( maxId+1 );
bool redirected = true;
} else return false;
return true;
=== modified file 'lib/triangulation/TriaxialState.cpp'
--- lib/triangulation/TriaxialState.cpp 2012-07-10 21:05:26 +0000
+++ lib/triangulation/TriaxialState.cpp 2014-03-21 18:45:24 +0000
@@ -144,7 +144,7 @@
z <= (box.sommet.z()-filter_distance*mean_radius) );
}
-bool TriaxialState::inside(Vecteur v)
+bool TriaxialState::inside(CVector v)
{
return TriaxialState::inside(v.x(), v.y(), v.z());
}
@@ -182,7 +182,7 @@
//Real tx, ty, tz;
Point pos(CGAL::ORIGIN);
mean_radius=0;
- Vecteur trans, rot;
+ CVector trans, rot;
Real rad; //coordonn�es/rayon
bool isSphere;
@@ -221,7 +221,7 @@
long id1, id2;
int stat;
- Vecteur c_pos, normal, old_fs, fs;
+ CVector c_pos, normal, old_fs, fs;
Real old_fn, fn, frictional_work;
Statefile >> Nc;
contacts.resize(Nc);
=== modified file 'lib/triangulation/TriaxialState.h'
--- lib/triangulation/TriaxialState.h 2013-08-22 14:32:01 +0000
+++ lib/triangulation/TriaxialState.h 2014-03-21 18:45:24 +0000
@@ -41,8 +41,8 @@
int id;
bool isSphere;
Sphere sphere;
- Vecteur translation;
- Vecteur rotation;
+ CVector translation;
+ CVector rotation;
VectorContact contacts;
Grain(void) {id=-1; isSphere=true;}
@@ -52,12 +52,12 @@
Grain* grain1;
Grain* grain2;
- Vecteur position;
- Vecteur normal;
+ CVector position;
+ CVector normal;
Real fn;
- Vecteur fs;
+ CVector fs;
Real old_fn;
- Vecteur old_fs;
+ CVector old_fs;
Real frictional_work;
bool visited;
Status status;
@@ -70,7 +70,7 @@
bool from_file(const char* filename, bool bz2=false);
bool to_file(const char* filename, bool bz2=false);
bool inside(Real x, Real y, Real z);
- bool inside(Vecteur v);
+ bool inside(CVector v);
bool inside(Point p);
static Real find_parameter (const char* parameter_name, const char* filename);
static Real find_parameter (const char* parameter_name, boost::iostreams::filtering_istream& file);
=== removed file 'lib/triangulation/def_types.h'
--- lib/triangulation/def_types.h 2014-04-04 17:12:06 +0000
+++ lib/triangulation/def_types.h 1970-01-01 00:00:00 +0000
@@ -1,256 +0,0 @@
-/*************************************************************************
-* Copyright (C) 2006 by Bruno Chareyre, bruno.chareyre@xxxxxxxxxxx *
-* Copyright (C) 2010 by Emanuele Catalano, emanuele.catalano@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. *
-*************************************************************************/
-
-#include <yade/lib/base/Math.hpp>
-
-//Define basic types from CGAL templates
-#pragma once
-
-#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Cartesian.h>
-#include <CGAL/Regular_triangulation_3.h>
-#include <CGAL/Regular_triangulation_euclidean_traits_3.h>
-#include <CGAL/Triangulation_vertex_base_with_info_3.h>
-#include <CGAL/Triangulation_cell_base_with_info_3.h>
-#include <CGAL/Delaunay_triangulation_3.h>
-#include <CGAL/circulator.h>
-#include <CGAL/number_utils.h>
-#include <boost/static_assert.hpp>
-
-namespace CGT {
-//Robust kernel
-typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
-//A bit faster, but gives crash eventualy
-// typedef CGAL::Cartesian<double> K;
-
-typedef CGAL::Regular_triangulation_euclidean_traits_3<K> Traits;
-typedef K::Point_3 Point;
-typedef Traits::Vector_3 Vecteur;
-typedef Traits::Segment_3 Segment;
-#ifndef NO_REAL_CHECK
-/** compilation inside yade: check that Real in yade is the same as Real we will define; otherwise it might make things go wrong badly (perhaps) **/
-BOOST_STATIC_ASSERT(sizeof(Traits::RT)==sizeof(Real));
-#endif
-typedef Traits::RT Real; //Dans cartesian, RT = FT
-typedef Traits::Weighted_point Sphere;
-typedef Traits::Line_3 Droite;
-typedef Traits::Plane_3 Plan;
-typedef Traits::Triangle_3 Triangle;
-typedef Traits::Tetrahedron_3 Tetraedre;
-
-class SimpleCellInfo : public Point {
- public:
- //"id": unique identifier of each cell, independant of other numberings used in the fluid types.
- // Care to initialize it, there is no magic numbering to rely on
- unsigned int id;
- Real s;
- bool isFictious;
- SimpleCellInfo (void) {isFictious=false; s=0;}
- SimpleCellInfo& operator= (const Point &p) { Point::operator= (p); return *this; }
- SimpleCellInfo& operator= (const float &scalar) { s=scalar; return *this; }
- inline Real x (void) {return Point::x();}
- inline Real y (void) {return Point::y();}
- inline Real z (void) {return Point::z();}
- inline Real& f (void) {return s;}
- //virtual function that will be defined for all classes, allowing shared function (e.g. for display of periodic and non-periodic with the unique function saveVTK)
- virtual bool isReal (void) {return !isFictious;}
-};
-
-class SimpleVertexInfo : public Vecteur {
-protected:
- Real s;
- unsigned int i;
- Real vol;
-public:
- bool isFictious;
- SimpleVertexInfo& operator= (const Vecteur &u) { Vecteur::operator= (u); return *this; }
- SimpleVertexInfo& operator= (const float &scalar) { s=scalar; return *this; }
- SimpleVertexInfo& operator= (const unsigned int &id) { i= id; return *this; }
- inline Real ux (void) {return Vecteur::x();}
- inline Real uy (void) {return Vecteur::y();}
- inline Real uz (void) {return Vecteur::z();}
- inline Real& f (void) {return s;}
- inline Real& v (void) {return vol;}
- inline const unsigned int& id (void) const {return i;}
- SimpleVertexInfo (void) {isFictious=false; s=0; i=0; vol=-1;}
- //virtual function that will be defined for all classes, allowing shared function (e.g. for display)
- virtual bool isReal (void) {return !isFictious;}
-};
-
-class FlowCellInfo : public SimpleCellInfo {
-
- public:
- //For vector storage of all cells
- unsigned int index;
- int volumeSign;
- bool Pcondition;
- Real invVoidV;
- Real t;
- int fict;
- Real VolumeVariation;
- double pression;
- //average relative (fluid - facet translation) velocity defined for a single cell as 1/Volume * SUM_ON_FACETS(x_average_facet*average_facet_flow_rate)
- Vecteur Average_Cell_Velocity;
- // Surface vectors of facets, pointing from outside toward inside the cell
- std::vector<Vecteur> facetSurfaces;
- //Ratio between fluid surface and facet surface
- std::vector<Real> facetFluidSurfacesRatio;
- // Reflects the geometrical property of the cell, so that the force by cell fluid on grain "i" is pressure*unitForceVectors[i]
- std::vector<Vecteur> unitForceVectors;
- // Store the area of triangle-sphere intersections for each facet (used in forces definition)
- std::vector<Vecteur> facetSphereCrossSections;
- std::vector<Vecteur> cell_force;
- std::vector<double> RayHydr;
-// std::vector<double> flow_rate;
- std::vector<double> module_permeability;
- // Partial surfaces of spheres in the double-tetrahedron linking two voronoi centers. [i][j] is for sphere facet "i" and sphere facetVertices[i][j]. Last component for 1/sum_surfaces in the facet.
- double solidSurfaces [4][4];
-
- FlowCellInfo (void)
- {
- module_permeability.resize(4, 0);
- cell_force.resize(4);
- facetSurfaces.resize(4);
- facetFluidSurfacesRatio.resize(4);
- facetSphereCrossSections.resize(4);
- unitForceVectors.resize(4);
- for (int k=0; k<4;k++) for (int l=0; l<3;l++) solidSurfaces[k][l]=0;
- RayHydr.resize(4, 0);
-// isInside = false;
- inv_sum_k=0;
- isFictious=false; Pcondition = false; isGhost = false;
-// isInferior = false; isSuperior = false; isLateral = false; isExternal=false;
- isvisited = false;
- index=0;
- volumeSign=0;
- s=0;
- VolumeVariation=0;
- pression=0;
- invVoidV=0;
- fict=0;
- isGhost=false;
- }
- bool isGhost;
- double inv_sum_k;
-// bool isInside;
-// bool isInferior;
-// bool isSuperior;
-// bool isLateral;
- bool isvisited;
-// bool isExternal;
-
- FlowCellInfo& operator= (const std::vector<double> &v) { for (int i=0; i<4;i++) module_permeability[i]= v[i]; return *this; }
- FlowCellInfo& operator= (const Point &p) { Point::operator= (p); return *this; }
- FlowCellInfo& operator= (const float &scalar) { s=scalar; return *this; }
-
- inline Real& volume (void) {return t;}
- inline const Real& invVoidVolume (void) const {return invVoidV;}
- inline Real& invVoidVolume (void) {return invVoidV;}
- inline Real& dv (void) {return VolumeVariation;}
- inline int& fictious (void) {return fict;}
- inline double& p (void) {return pression;}
- //For compatibility with the periodic case
- inline const double shiftedP (void) const {return pression;}
- inline const std::vector<double>& k_norm (void) const {return module_permeability;}
- inline std::vector<double>& k_norm (void) {return module_permeability;}
- inline std::vector< Vecteur >& facetSurf (void) {return facetSurfaces;}
- inline std::vector<Vecteur>& force (void) {return cell_force;}
- inline std::vector<double>& Rh (void) {return RayHydr;}
-
- inline Vecteur& av_vel (void) {return Average_Cell_Velocity;}
-};
-
-class FlowVertexInfo : public SimpleVertexInfo {
- Vecteur Grain_Velocity;
- Real volume_incident_cells;
-public:
- FlowVertexInfo& operator= (const Vecteur &u) { Vecteur::operator= (u); return *this; }
- FlowVertexInfo& operator= (const float &scalar) { s=scalar; return *this; }
- FlowVertexInfo& operator= (const unsigned int &id) { i= id; return *this; }
- Vecteur forces;
- bool isGhost;
- FlowVertexInfo (void) {isGhost=false;}
- inline Vecteur& force (void) {return forces;}
- inline Vecteur& vel (void) {return Grain_Velocity;}
- inline Real& vol_cells (void) {return volume_incident_cells;}
- inline const Vecteur ghostShift (void) {return CGAL::NULL_VECTOR;}
-};
-
-class PeriodicCellInfo : public FlowCellInfo
-{
- public:
- static Vecteur 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 Vecteur hSize[3];
- static Vecteur deltaP;
- int ghost;
- Real* _pression;
- PeriodicCellInfo (void){
- _pression=&pression;
- period[0]=period[1]=period[2]=0;
- baseIndex=-1;
- volumeSign=0;}
- ~PeriodicCellInfo (void) {}
- PeriodicCellInfo& operator= (const Point &p) { Point::operator= (p); return *this; }
- PeriodicCellInfo& operator= (const float &scalar) { s=scalar; return *this; }
-
- inline const double shiftedP (void) 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;}
- virtual bool isReal (void) {return !(isFictious || isGhost);}
-};
-
-class PeriodicVertexInfo : public FlowVertexInfo {
- public:
- PeriodicVertexInfo& operator= (const Vecteur &u) { Vecteur::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 Vecteur 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;}
- virtual bool isReal (void) {return !(isFictious || isGhost);}
-};
-
-class UnsatCellInfo : public FlowCellInfo {
- public:
- UnsatCellInfo& operator= (const Point &p) { Point::operator= (p); return *this; }
- bool isWaterReservoir;
- bool isAirReservoir;
- Real capillaryCellVolume;//for calculating saturation
- 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/sum_Lines in the facet.
- double trapCapP;//for calculating the pressure of trapped phase, cell.Pressure_trapped = Pressure_air - 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& operator= (const Vecteur &u) { Vecteur::operator= (u); return *this; }
- UnsatVertexInfo& operator= (const float &scalar) { s=scalar; return *this; }
- UnsatVertexInfo& operator= (const unsigned int &id) { i= id; return *this; }
- UnsatVertexInfo (void)
- {
-
- }
-};
-
-} // namespace CGT
\ No newline at end of file
=== modified file 'pkg/common/CylScGeom6D.hpp'
--- pkg/common/CylScGeom6D.hpp 2012-10-09 09:09:02 +0000
+++ pkg/common/CylScGeom6D.hpp 2014-05-06 15:32:52 +0000
@@ -1,3 +1,5 @@
+// 2011 © Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
+// 2012 © Kneib Francois <francois.kneib@xxxxxxxxx>
#pragma once
#include<yade/pkg/dem/ScGeom.hpp>
=== modified file 'pkg/common/Cylinder.cpp'
--- pkg/common/Cylinder.cpp 2014-02-03 11:21:42 +0000
+++ pkg/common/Cylinder.cpp 2014-05-06 15:32:52 +0000
@@ -1,3 +1,6 @@
+// 2011 © Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
+// 2012 © Kneib Francois <francois.kneib@xxxxxxxxx>
+
#include "Cylinder.hpp"
#include<yade/pkg/common/Sphere.hpp>
#ifdef YADE_OPENGL
=== modified file 'pkg/common/Cylinder.hpp'
--- pkg/common/Cylinder.hpp 2013-08-29 10:30:31 +0000
+++ pkg/common/Cylinder.hpp 2014-05-06 15:32:52 +0000
@@ -1,3 +1,6 @@
+// 2011 © Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
+// 2012 © Kneib Francois <francois.kneib@xxxxxxxxx>
+
#pragma once
#include<yade/pkg/common/Dispatching.hpp>
#include<yade/core/Shape.hpp>
=== modified file 'pkg/common/Dispatching.cpp'
--- pkg/common/Dispatching.cpp 2014-02-03 11:21:42 +0000
+++ pkg/common/Dispatching.cpp 2014-04-16 10:30:23 +0000
@@ -17,12 +17,21 @@
updateScenePtr();
shared_ptr<BodyContainer>& bodies = scene->bodies;
const long numBodies=(long)bodies->size();
- //#pragma omp parallel for
+ #pragma omp parallel for num_threads(ompThreads>0 ? min(ompThreads,omp_get_max_threads()) : omp_get_max_threads())
for(int id=0; id<numBodies; id++){
if(!bodies->exists(id)) continue; // don't delete this check - Janek
const shared_ptr<Body>& b=(*bodies)[id];
+ processBody(b);
+ }
+// With -j4, this update takes more time that the dispatching in itslef, and it is quite useless: commented out
+// scene->updateBound();
+}
+
+void BoundDispatcher::processBody(const shared_ptr<Body>& b)
+{
+// const shared_ptr<Body>& b=(*bodies)[id];
shared_ptr<Shape>& shape=b->shape;
- if(!shape || !b->isBounded()) continue;
+ if(!b->isBounded() || !shape) return;
if(b->bound) {
Real& sweepLength = b->bound->sweepLength;
if (targetInterv>=0) {
@@ -36,12 +45,12 @@
} else sweepLength=sweepDist;
}
#ifdef BV_FUNCTOR_CACHE
- if(!shape->boundFunctor){ shape->boundFunctor=this->getFunctor1D(shape); if(!shape->boundFunctor) continue; }
+ if(!shape->boundFunctor){ shape->boundFunctor=this->getFunctor1D(shape); if(!shape->boundFunctor) return; }
shape->boundFunctor->go(shape,b->bound,b->state->se3,b.get());
#else
operator()(shape,b->bound,b->state->se3,b.get());
#endif
- if(!b->bound) continue; // the functor did not create new bound
+ if(!b->bound) return; // the functor did not create new bound
b->bound->refPos=b->state->pos;
b->bound->lastUpdateIter=scene->iter;
const Real& sweepLength = b->bound->sweepLength;
@@ -51,8 +60,6 @@
aabb->max+=Vector3r(sweepLength,sweepLength,sweepLength);
}
}
- scene->updateBound();
-}
/********************************************************************
=== modified file 'pkg/common/Dispatching.hpp'
--- pkg/common/Dispatching.hpp 2012-01-23 14:43:54 +0000
+++ pkg/common/Dispatching.hpp 2014-02-22 04:56:33 +0000
@@ -81,6 +81,7 @@
public:
virtual void action();
virtual bool isActivated(){ return activated; }
+ void processBody(const shared_ptr<Body>&);
DECLARE_LOGGER;
YADE_DISPATCHER1D_FUNCTOR_DOC_ATTRS_CTOR_PY(BoundDispatcher,BoundFunctor,/*optional doc*/,
/*additional attrs*/
=== modified file 'pkg/common/Gl1_NormPhys.hpp'
--- pkg/common/Gl1_NormPhys.hpp 2012-09-21 19:03:18 +0000
+++ pkg/common/Gl1_NormPhys.hpp 2014-04-02 15:19:41 +0000
@@ -11,16 +11,17 @@
static GLUquadric* gluQuadric; // needed for gluCylinder, initialized by ::go if no initialized yet
public:
virtual void go(const shared_ptr<IPhys>&,const shared_ptr<Interaction>&,const shared_ptr<Body>&,const shared_ptr<Body>&,bool wireFrame);
- YADE_CLASS_BASE_DOC_STATICATTRS(Gl1_NormPhys,GlIPhysFunctor,"Renders :yref:`NormPhys` objects as cylinders of which diameter and color depends on :yref:`NormPhys::normForce` magnitude.",
- ((Real,maxFn,0,,"Value of :yref:`NormPhys.normalForce` corresponding to :yref:`maxDiameter<Gl1_NormPhys.maxDiameter>`. This value will be increased (but *not decreased* ) automatically."))
+ YADE_CLASS_BASE_DOC_STATICATTRS(Gl1_NormPhys,GlIPhysFunctor,"Renders :yref:`NormPhys` objects as cylinders of which diameter and color depends on :yref:`NormPhys.normalForce` magnitude.",
+ // changed doc maxDiameter -> maxRadius ((Real,maxFn,0,,"Value of :yref:`NormPhys.normalForce` corresponding to :yref:`maxDiameter<Gl1_NormPhys.maxDiameter>`. This value will be increased (but *not decreased* ) automatically."))
+ ((Real,maxFn,0,,"Value of :yref:`NormPhys.normalForce` corresponding to :yref:`maxRadius<Gl1_NormPhys.maxRadius>`. This value will be increased (but *not decreased* ) automatically."))
((int,signFilter,0,,"If non-zero, only display contacts with negative (-1) or positive (+1) normal forces; if zero, all contacts will be displayed."))
((Real,refRadius,std::numeric_limits<Real>::infinity(),,"Reference (minimum) particle radius; used only if :yref:`maxRadius<Gl1_NormPhys.maxRadius>` is negative. This value will be decreased (but *not increased* ) automatically. |yupdate|"))
((Real,maxRadius,-1,,"Cylinder radius corresponding to the maximum normal force. If negative, auto-updated :yref:`refRadius<Gl1_NormPhys.refRadius>` will be used instead."))
- ((int,slices,6,,"Number of sphere slices; (see `glutCylinder reference <http://www.opengl.org/sdk/docs/man/xhtml/gluCylinder.xml>`__)"))
- ((int,stacks,1,,"Number of sphere stacks; (see `glutCylinder reference <http://www.opengl.org/sdk/docs/man/xhtml/gluCylinder.xml>`__)"))
+ ((int,slices,6,,"Number of sphere slices; (see `glutCylinder reference <http://www.opengl.org/sdk/docs/man/xhtml/gluCylinder.xml>`_)")) // FIXME: the link does not exist
+ ((int,stacks,1,,"Number of sphere stacks; (see `glutCylinder reference <http://www.opengl.org/sdk/docs/man/xhtml/gluCylinder.xml>`_)"))
// strong/weak fabric attributes
- ((Real,maxWeakFn,NaN,,"Value that divides contacts by their normal force into the ``weak fabric'' and ``strong fabric''. This value is set as side-effect by :yref:`utils.fabricTensor`."))
- ((int,weakFilter,0,,"If non-zero, only display contacts belonging to the ``weak'' (-1) or ``strong'' (+1) fabric."))
+ ((Real,maxWeakFn,NaN,,"Value that divides contacts by their normal force into the 'weak fabric' and 'strong fabric'. This value is set as side-effect by :yref:`utils.fabricTensor`."))
+ ((int,weakFilter,0,,"If non-zero, only display contacts belonging to the 'weak' (-1) or 'strong' (+1) fabric."))
((Real,weakScale,1.,,"If :yref:`maxWeakFn<Gl1_NormPhys.maxWeakFn>` is set, scale radius of the weak fabric by this amount (usually smaller than 1). If zero, 1 pixel line is displayed. Colors are not affected by this value."))
);
RENDERS(NormPhys);
=== modified file 'pkg/common/InsertionSortCollider.cpp'
--- pkg/common/InsertionSortCollider.cpp 2014-02-02 20:49:51 +0000
+++ pkg/common/InsertionSortCollider.cpp 2014-05-06 15:32:52 +0000
@@ -1,4 +1,5 @@
// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+// 2013 © Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
#include"InsertionSortCollider.hpp"
#include<yade/core/Scene.hpp>
@@ -11,6 +12,9 @@
#include<algorithm>
#include<vector>
#include<boost/static_assert.hpp>
+#ifdef YADE_OPENMP
+ #include<omp.h>
+#endif
using namespace std;
@@ -53,6 +57,92 @@
}
}
+
+//Periodic version, only for non-periodic case at the moment (feel free to implement for the periodic case...)
+void InsertionSortCollider::insertionSortParallel(VecBounds& v, InteractionContainer* interactions, Scene*, bool doCollide){
+#ifdef YADE_OPENMP
+ assert(!periodic);
+ assert(v.size==(long)v.vec.size());
+ if (ompThreads<=1) return insertionSort(v,interactions, scene, doCollide);
+
+ Real chunksVerlet = 4*verletDist;//is 2* the theoretical requirement?
+ if (chunksVerlet<=0) {LOG_ERROR("Parallel insertion sort needs verletDist>0");}
+
+ ///chunks defines subsets of the bounds lists, we make sure they are not too small wrt. verlet dist.
+ std::vector<unsigned> chunks;
+ unsigned nChunks = ompThreads;
+ unsigned chunkSize = unsigned(v.size/nChunks)+1;
+ for(unsigned n=0; n<nChunks;n++) chunks.push_back(n*chunkSize); chunks.push_back(v.size);
+ while (nChunks>1){
+ bool changeChunks=false;
+ for(unsigned n=1; n<nChunks;n++) if (chunksVerlet>(v[chunks[n]].coord-v[chunks[n-1]].coord)) changeChunks=true;
+ if (!changeChunks) break;
+ nChunks--; chunkSize = unsigned(v.size/nChunks)+1; chunks.clear();
+ for(unsigned n=0; n<nChunks;n++) chunks.push_back(n*chunkSize); chunks.push_back(v.size);
+ }
+ static unsigned warnOnce=0;
+ if (nChunks<unsigned(ompThreads) && !warnOnce++) LOG_WARN("Parallel insertion: only "<<nChunks <<" thread(s) used. The number of bodies is probably too small for allowing more threads. The contact detection should succeed but not all available threads are used.");
+
+ ///Define per-thread containers bufferizing the actual insertion of new interactions, since inserting is not thread-safe
+ std::vector<std::vector<std::pair<Body::id_t,Body::id_t> > > newInteractions;
+ newInteractions.resize(ompThreads,std::vector<std::pair<Body::id_t,Body::id_t> >());
+ for (int kk=0; kk<ompThreads; kk++) newInteractions[kk].reserve(100);
+
+ /// First sort, independant in each chunk
+ #pragma omp parallel for schedule(dynamic,1) num_threads(ompThreads>0 ? min(ompThreads,omp_get_max_threads()) : omp_get_max_threads())
+ for (unsigned k=0; k<nChunks;k++) {
+ int threadNum = omp_get_thread_num();
+ for(long i=chunks[k]+1; i<chunks[k+1]; i++){
+ const Bounds viInit=v[i]; long j=i-1; const bool viInitBB=viInit.flags.hasBB;
+ const bool isMin=viInit.flags.isMin;
+ while(j>=chunks[k] && v[j]>viInit){
+ v[j+1]=v[j];
+ if(isMin && !v[j].flags.isMin && doCollide && viInitBB && v[j].flags.hasBB && (viInit.id!=v[j].id)) {
+ const Body::id_t& id1 = v[j].id; const Body::id_t& id2 = viInit.id;
+ if (spatialOverlap(id1,id2) && Collider::mayCollide(Body::byId(id1,scene).get(),Body::byId(id2,scene).get()) && !interactions->found(id1,id2))
+ newInteractions[threadNum].push_back(std::pair<Body::id_t,Body::id_t>(v[j].id,viInit.id));
+ }
+ j--;
+ }
+ v[j+1]=viInit;
+ }
+ }
+
+ ///In the second sort, the chunks are connected consistently.
+ ///If sorting requires to move a bound past half-chunk, the algorithm is not thread safe, if it happens we error out.
+ ///Better than computing with messed up interactions
+ #pragma omp parallel for schedule(dynamic,1) num_threads(ompThreads>0 ? min(ompThreads,omp_get_max_threads()) : omp_get_max_threads())
+ for (unsigned k=1; k<nChunks;k++) {
+
+ int threadNum = omp_get_thread_num();
+ long i=chunks[k];
+ for(; v[i]<v[i-1]; i++){
+ const Bounds viInit=v[i]; long j=i-1; /* cache hasBB; otherwise 1% overall performance hit */ const bool viInitBB=viInit.flags.hasBB;
+ const bool isMin=viInit.flags.isMin;
+
+ while(j>=chunks[k-1] && viInit<v[j]){
+ v[j+1]=v[j];
+ if(isMin && !v[j].flags.isMin && doCollide && viInitBB && v[j].flags.hasBB && (viInit.id!=v[j].id)) {
+ const Body::id_t& id1 = v[j].id; const Body::id_t& id2 = viInit.id;
+ //FIXME: do we need the check with found(id1,id2) here? It is checked again below...
+ if (spatialOverlap(id1,id2) && Collider::mayCollide(Body::byId(id1,scene).get(),Body::byId(id2,scene).get()) && !interactions->found(id1,id2))
+ newInteractions[threadNum].push_back(std::pair<Body::id_t,Body::id_t>(v[j].id,viInit.id));}
+ j--;
+ }
+ v[j+1]=viInit;
+ if (j<=long(chunks[k]-chunkSize*0.5)) LOG_ERROR("parallel sort not guaranteed to succeed; in chunk "<<k<<" of "<<nChunks<< ", bound descending past half-chunk. Consider turning ompThreads=1 for thread safety.");
+ }
+ if (i>=long(chunks[k]+chunkSize*0.5)) LOG_ERROR("parallel sort not guaranteed to succeed; in chunk "<<k+1<<" of "<<nChunks<< ", bound advancing past half-chunk. Consider turning ompThreads=1 for thread safety.")
+ }
+ /// Check again, just to be sure...
+ for (unsigned k=1; k<nChunks;k++) if (v[chunks[k]]<v[chunks[k]-1]) LOG_ERROR("parallel sort failed, consider turning ompThreads=1");
+
+ /// Now insert interactions sequentially
+ for (int n=0;n<ompThreads;n++) for (size_t k=0, kend=newInteractions[n].size();k<kend;k++) if (!interactions->found(newInteractions[n][k].first,newInteractions[n][k].second)) interactions->insert(shared_ptr<Interaction>(new Interaction(newInteractions[n][k].first,newInteractions[n][k].second)));
+#endif
+}
+
+
vector<Body::id_t> InsertionSortCollider::probeBoundingVolume(const Bound& bv){
if(periodic){ throw invalid_argument("InsertionSortCollider::probeBoundingVolume: handling periodic boundary not implemented."); }
vector<Body::id_t> ret;
@@ -101,7 +191,9 @@
long nBodies=(long)scene->bodies->size();
InteractionContainer* interactions=scene->interactions.get();
scene->interactions->iterColliderLastRun=-1;
-
+ #ifdef YADE_OPENMP
+ if (ompThreads<=0) ompThreads = omp_get_max_threads();
+ #endif
// periodicity changed, force reinit
if(scene->isPeriodic != periodic){
for(int i=0; i<3; i++) BB[i].vec.clear();
@@ -153,6 +245,11 @@
// if no spheres, disable stride
verletDist=isinf(minR) ? 0 : abs(verletDist)*minR;
}
+ // if interactions are dirty, force reinitialization
+ if(scene->interactions->dirty){
+ doInitSort=true;
+ scene->interactions->dirty=false;
+ }
// update bounds via boundDispatcher
boundDispatcher->scene=scene;
@@ -161,12 +258,8 @@
boundDispatcher->targetInterv=targetInterv;
boundDispatcher->updatingDispFactor=updatingDispFactor;
boundDispatcher->action();
+ ISC_CHECKPOINT("boundDispatcher");
- // if interactions are dirty, force reinitialization
- if(scene->interactions->dirty){
- doInitSort=true;
- scene->interactions->dirty=false;
- }
// STRIDE
if(verletDist>0){
@@ -176,67 +269,61 @@
if(!newton){ throw runtime_error("InsertionSortCollider.verletDist>0, but unable to locate NewtonIntegrator within O.engines."); }
}
}
- ISC_CHECKPOINT("init");
-
// STRIDE
// get us ready for strides, if they were deactivated
- if(!strideActive && verletDist>0 && newton->maxVelocitySq>=0){ // maxVelocitySq is a really computed value
- strideActive=true;
- }
+ if(!strideActive && verletDist>0 && newton->maxVelocitySq>=0) strideActive=true;
if(strideActive){
assert(verletDist>0);
assert(strideActive); assert(newton->maxVelocitySq>=0);
- newton->updatingDispFactor=updatingDispFactor;
- } else { /* !strideActive */
- boundDispatcher->sweepDist=0;
- }
+ newton->updatingDispFactor=updatingDispFactor;
+ } else boundDispatcher->sweepDist=0;
ISC_CHECKPOINT("bound");
- // copy bounds along given axis into our arrays
- for(long i=0; i<2*nBodies; i++){
- for(int j=0; j<3; j++){
+ // copy bounds along given axis into our arrays
+ #pragma omp parallel for schedule(guided) num_threads(ompThreads>0 ? min(ompThreads,omp_get_max_threads()) : omp_get_max_threads())
+ for(long i=0; i<2*nBodies; i++){
+// const long cacheIter = scene->iter;
+ for(int j=0; j<3; j++){
VecBounds& BBj=BB[j];
- const Body::id_t id=BBj[i].id;
+ Bounds& BBji = BBj[i];
+ const Body::id_t id=BBji.id;
const shared_ptr<Body>& b=Body::byId(id,scene);
if(b){
const shared_ptr<Bound>& bv=b->bound;
// coordinate is min/max if has bounding volume, otherwise both are the position. Add periodic shift so that we are inside the cell
// watch out for the parentheses around ?: within ?: (there was unwanted conversion of the Reals to bools!)
-
- BBj[i].coord=((BBj[i].flags.hasBB=((bool)bv)) ? (BBj[i].flags.isMin ? bv->min[j] : bv->max[j]) : (b->state->pos[j])) - (periodic ? BBj.cellDim*BBj[i].period : 0.);
-
+ BBji.coord=((BBji.flags.hasBB=((bool)bv)) ? (BBji.flags.isMin ? bv->min[j] : bv->max[j]) : (b->state->pos[j])) - (periodic ? BBj.cellDim*BBji.period : 0.);
+ // if initializing periodic, shift coords & record the period into BBj[i].period
+ if(doInitSort && periodic) BBji.coord=cellWrap(BBji.coord,0,BBj.cellDim,BBji.period);
+ // for each body, copy its minima and maxima, for quick checks of overlaps later
+ //bounds have been all updated when j==0, we can safely copy them here when j==1
+ if (BBji.flags.isMin && j==1 &&bv) {
+ memcpy(&minima[3*id],&bv->min,3*sizeof(Real)); memcpy(&maxima[3*id],&bv->max,3*sizeof(Real));
+ }
} else { BBj[i].flags.hasBB=false; /* for vanished body, keep the coordinate as-is, to minimize inversions. */ }
- // if initializing periodic, shift coords & record the period into BBj[i].period
- if(doInitSort && periodic) {
- BBj[i].coord=cellWrap(BBj[i].coord,0,BBj.cellDim,BBj[i].period);
- }
- }
+ }
}
- // for each body, copy its minima and maxima, for quick checks of overlaps later
- BOOST_STATIC_ASSERT(sizeof(Vector3r)==3*sizeof(Real));
- for(Body::id_t id=0; id<nBodies; id++){
- const shared_ptr<Body>& b=Body::byId(id,scene);
- if(b){
- const shared_ptr<Bound>& bv=b->bound;
- if(bv) { memcpy(&minima[3*id],&bv->min,3*sizeof(Real)); memcpy(&maxima[3*id],&bv->max,3*sizeof(Real)); } // ⇐ faster than 6 assignments
- else{ const Vector3r& pos=b->state->pos; memcpy(&minima[3*id],&pos,3*sizeof(Real)); memcpy(&maxima[3*id],&pos,3*sizeof(Real)); }
- } else { memset(&minima[3*id],0,3*sizeof(Real)); memset(&maxima[3*id],0,3*sizeof(Real)); }
- }
ISC_CHECKPOINT("copy");
- // process interactions that the constitutive law asked to be erased
-// interactions->erasePending(*this,scene);
+ // remove interactions which have disconnected bounds and are not real (will run parallel if YADE_OPENMP)
interactions->conditionalyEraseNonReal(*this,scene);
-
+
ISC_CHECKPOINT("erase");
// sort
// the regular case
if(!doInitSort && !sortThenCollide){
- /* each inversion in insertionSort calls handleBoundInversion, which in turns may add/remove interaction */
- if(!periodic) for(int i=0; i<3; i++) insertionSort(BB[i],interactions,scene);
+ /* each inversion in insertionSort calls may add interaction */
+ //1000 bodies is heuristic minimum above which parallel sort is called
+ if(!periodic) for(int i=0; i<3; i++) {
+ #ifdef YADE_OPENMP
+ if (ompThreads<=1 || nBodies<1000) insertionSort(BB[i],interactions,scene);
+ else insertionSortParallel(BB[i],interactions,scene);}
+ #else
+ insertionSort(BB[i],interactions,scene);}
+ #endif
else for(int i=0; i<3; i++) insertionSortPeri(BB[i],interactions,scene);
}
// create initial interactions (much slower)
@@ -244,6 +331,7 @@
if(doInitSort){
// the initial sort is in independent in 3 dimensions, may be run in parallel; it seems that there is no time gain running in parallel, though
// important to reset loInx for periodic simulation (!!)
+// #pragma omp parallel for schedule(dynamic,1) num_threads(min(ompThreads,3))
for(int i=0; i<3; i++) { BB[i].loIdx=0; std::sort(BB[i].vec.begin(),BB[i].vec.end()); }
numReinit++;
} else { // sortThenCollide
@@ -255,6 +343,12 @@
VecBounds& V=BB[sortAxis];
// go through potential aabb collisions, create interactions as necessary
if(!periodic){
+ #ifdef YADE_OPENMP
+ std::vector<std::vector<std::pair<Body::id_t,Body::id_t> > > newInts;
+ newInts.resize(ompThreads,std::vector<std::pair<Body::id_t,Body::id_t> >());
+ for (int kk=0; kk<ompThreads; kk++) newInts[kk].reserve(unsigned(10*nBodies/ompThreads));
+ #pragma omp parallel for schedule(guided,200) num_threads(ompThreads)
+ #endif
for(long i=0; i<2*nBodies; i++){
// start from the lower bound (i.e. skipping upper bounds)
// skip bodies without bbox, because they don't collide
@@ -265,11 +359,23 @@
const Body::id_t& jid=V[j].id;
// take 2 of the same condition (only handle collision [min_i..max_i]+min_j, not [min_i..max_i]+min_i (symmetric)
if(!(V[j].flags.isMin && V[j].flags.hasBB)) continue;
- /* abuse the same function here; since it does spatial overlap check first, it is OK to use it */
- handleBoundInversion(iid,jid,interactions,scene);
- assert(j<2*nBodies-1);
+ if (spatialOverlap(iid,jid) && Collider::mayCollide(Body::byId(iid,scene).get(),Body::byId(jid,scene).get()) ){
+ #ifdef YADE_OPENMP
+ unsigned int threadNum = omp_get_thread_num();
+ newInts[threadNum].push_back(std::pair<Body::id_t,Body::id_t>(iid,jid));
+ #else
+ if (!interactions->found(iid,jid))
+ interactions->insert(shared_ptr<Interaction>(new Interaction(iid,jid)));
+ #endif
+ }
}
}
+ //go through newly created candidates sequentially, duplicates coming from different threads may exist so we check existence with found()
+ #ifdef YADE_OPENMP
+ for (int n=0;n<ompThreads;n++) for (size_t k=0, kend=newInts[n].size();k<kend;k++)
+ if (!interactions->found(newInts[n][k].first,newInts[n][k].second))
+ interactions->insert(shared_ptr<Interaction>(new Interaction(newInts[n][k].first,newInts[n][k].second)));
+ #endif
} else { // periodic case: see comments above
for(long i=0; i<2*nBodies; i++){
if(!(V[i].flags.isMin && V[i].flags.hasBB)) continue;
@@ -354,8 +460,6 @@
// called by the insertion sort if 2 bodies swapped their bounds
void InsertionSortCollider::handleBoundInversionPeri(Body::id_t id1, Body::id_t id2, InteractionContainer* interactions, Scene*){
assert(periodic);
-
- ///fast
Vector3i periods;
bool overlap=spatialOverlapPeri(id1,id2,scene,periods);
if (overlap && Collider::mayCollide(Body::byId(id1,scene).get(),Body::byId(id2,scene).get()) && !interactions->found(id1,id2)){
@@ -363,45 +467,6 @@
newI->cellDist=periods;
interactions->insert(newI);
}
-
- ///Slow
- // do bboxes overlap in all 3 dimensions?
-// Vector3i periods;
-// bool overlap=spatialOverlapPeri(id1,id2,scene,periods);
-// // existing interaction?
-// const shared_ptr<Interaction>& I=interactions->find(id1,id2);
-// bool hasInter=(bool)I;
-// #ifdef PISC_DEBUG
-// if(watchIds(id1,id2)) LOG_DEBUG("Inversion #"<<id1<<"+#"<<id2<<", overlap=="<<overlap<<", hasInter=="<<hasInter);
-// #endif
-// // interaction doesn't exist and shouldn't, or it exists and should
-// if(likely(!overlap && !hasInter)) return;
-// if(overlap && hasInter){ return; }
-// // create interaction if not yet existing
-// if(overlap && !hasInter){ // second condition only for readability
-// #ifdef PISC_DEBUG
-// if(watchIds(id1,id2)) LOG_DEBUG("Attemtping collision of #"<<id1<<"+#"<<id2);
-// #endif
-// if(!Collider::mayCollide(Body::byId(id1,scene).get(),Body::byId(id2,scene).get())) return;
-// // LOG_TRACE("Creating new interaction #"<<id1<<"+#"<<id2);
-// shared_ptr<Interaction> newI=shared_ptr<Interaction>(new Interaction(id1,id2));
-// newI->cellDist=periods;
-// #ifdef PISC_DEBUG
-// if(watchIds(id1,id2)) LOG_DEBUG("Created intr #"<<id1<<"+#"<<id2<<", periods="<<periods);
-// #endif
-// interactions->insert(newI);
-// return;
-// }
-// if(!overlap && hasInter){
-// if(!I->isReal()) {
-// interactions->erase(id1,id2);
-// #ifdef PISC_DEBUG
-// if(watchIds(id1,id2)) LOG_DEBUG("Erased intr #"<<id1<<"+#"<<id2);
-// #endif
-// }
-// return;
-// }
-// assert(false); // unreachable
}
/* Performance hint
=== modified file 'pkg/common/InsertionSortCollider.hpp'
--- pkg/common/InsertionSortCollider.hpp 2014-02-20 16:49:26 +0000
+++ pkg/common/InsertionSortCollider.hpp 2014-05-06 15:32:52 +0000
@@ -1,5 +1,5 @@
// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
-
+// 2013 © Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
#pragma once
#include<yade/pkg/common/Collider.hpp>
#include<yade/core/Scene.hpp>
@@ -8,11 +8,6 @@
/*! Periodic collider notes.
-Use
-===
-* scripts/test/periodic-simple.py
-* In the future, triaxial compression working by growing/shrinking the cell should be implemented.
-
Architecture
============
Values from bounding boxes are added information about period in which they are.
@@ -50,7 +45,8 @@
Requirements
============
-* No body can have Aabb larger than about .499*cellSize. Exception is thrown if that is false.
+* By default, no body can have Aabb larger than about .499*cellSize. Exception is thrown if that is false.
+ Large bodies are accepted if allowBiggerThanPeriod (experimental)
* Constitutive law must not get body positions from Body::state directly.
If it does, it uses Interaction::cellDist to compute periodic position.
* No body can get further away than MAXINT periods. It will do horrible things if there is overflow. Not checked at the moment.
@@ -67,7 +63,7 @@
// #define this macro to enable timing within this engine
-//#define ISC_TIMING
+// #define ISC_TIMING
// #define to turn on some tracing information for the periodic part
// all code under this can be probably removed at some point, when the collider will have been tested thoroughly
@@ -157,6 +153,7 @@
http://en.wikipedia.org/wiki/Insertion_sort has the algorithm and other details
*/
void insertionSort(VecBounds& v,InteractionContainer*,Scene*,bool doCollide=true);
+ void insertionSortParallel(VecBounds& v,InteractionContainer*,Scene*,bool doCollide=true);
void handleBoundInversion(Body::id_t,Body::id_t,InteractionContainer*,Scene*);
// bool spatialOverlap(Body::id_t,Body::id_t) const;
@@ -194,7 +191,7 @@
YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(InsertionSortCollider,Collider,"\
Collider with O(n log(n)) complexity, using :yref:`Aabb` for bounds.\
\n\n\
- At the initial step, Bodies' bounds (along sortAxis) are first std::sort'ed along one axis (sortAxis), then collided. The initial sort has :math:`O(n^2)` complexity, see `Colliders' performance <https://yade-dem.org/index.php/Colliders_performace>`_ for some information (There are scripts in examples/collider-perf for measurements). \
+ At the initial step, Bodies' bounds (along :yref:`sortAxis<InsertionSortCollider.sortAxis>`) are first std::sort'ed along this (sortAxis) axis, then collided. The initial sort has :math:`O(n^2)` complexity, see `Colliders' performance <https://yade-dem.org/index.php/Colliders_performace>`_ for some information (There are scripts in examples/collider-perf for measurements). \
\n\n \
Insertion sort is used for sorting the bound list that is already pre-sorted from last iteration, where each inversion calls checkOverlap which then handles either overlap (by creating interaction if necessary) or its absence (by deleting interaction if it is only potential). \
\n\n \
=== modified file 'pkg/common/InteractionLoop.cpp'
--- pkg/common/InteractionLoop.cpp 2014-02-03 11:21:42 +0000
+++ pkg/common/InteractionLoop.cpp 2014-04-16 10:30:23 +0000
@@ -21,15 +21,6 @@
void InteractionLoop::action(){
-// if(eraseIntsInLoop && scene->interactions->conditionalyEraseNonReal(scene)>0 && !alreadyWarnedNoCollider){
-// LOG_WARN("Interactions pending erase found (erased), no collider being used?");
-// alreadyWarnedNoCollider=true;
-// }
- /*
- if(scene->interactions->dirty){
- throw std::logic_error("InteractionContainer::dirty is true; the collider should re-initialize in such case and clear the dirty flag.");
- }
- */
// update Scene* of the dispatchers
geomDispatcher->scene=physDispatcher->scene=lawDispatcher->scene=scene;
// ask dispatchers to update Scene* of their functors
@@ -60,11 +51,9 @@
// (only for some kinds of colliders; see comment for InteractionContainer::iterColliderLastRun)
bool removeUnseenIntrs=(scene->interactions->iterColliderLastRun>=0 && scene->interactions->iterColliderLastRun==scene->iter);
-
-
#ifdef YADE_OPENMP
const long size=scene->interactions->size();
- #pragma omp parallel for schedule(guided) num_threads(ompThreads>0 ? ompThreads : omp_get_max_threads())
+ #pragma omp parallel for schedule(guided) num_threads(ompThreads>0 ? min(ompThreads,omp_get_max_threads()) : omp_get_max_threads())
for(long i=0; i<size; i++){
const shared_ptr<Interaction>& I=(*scene->interactions)[i];
#else
@@ -154,15 +143,4 @@
if(callbackPtrs[i]!=NULL) (*(callbackPtrs[i]))(callbacks[i].get(),I.get());
}
}
-
- // process eraseAfterLoop
- #ifdef YADE_OPENMP
- FOREACH(list<idPair>& l, eraseAfterLoopIds){
- FOREACH(idPair p,l) scene->interactions->erase(p.first,p.second);
- l.clear();
- }
- #else
- FOREACH(idPair p, eraseAfterLoopIds) scene->interactions->erase(p.first,p.second);
- eraseAfterLoopIds.clear();
- #endif
}
=== modified file 'pkg/common/KinematicEngines.cpp'
--- pkg/common/KinematicEngines.cpp 2013-11-11 16:22:15 +0000
+++ pkg/common/KinematicEngines.cpp 2014-04-23 13:38:24 +0000
@@ -174,6 +174,7 @@
}
iterPrevStart = scene->iter;
+ current = tmpForce;
}
translationAxis = axis;
=== modified file 'pkg/common/KinematicEngines.hpp'
--- pkg/common/KinematicEngines.hpp 2013-11-11 16:22:15 +0000
+++ pkg/common/KinematicEngines.hpp 2014-04-23 13:38:24 +0000
@@ -99,6 +99,7 @@
((Real,maxVelocity,0.0,,"Velocity [m/s]"))
((Vector3r,axis,Vector3r::Zero(),,"Unit vector along which apply the velocity [-]"))
((Real,target,0.0,,"Target value for the controller [N]"))
+ ((Vector3r,current,Vector3r::Zero(),,"Current value for the controller [N]"))
((Real,kP,0.0,,"Proportional gain/coefficient for the PID-controller [-]"))
((Real,kI,0.0,,"Integral gain/coefficient for the PID-controller [-]"))
((Real,kD,0.0,,"Derivative gain/coefficient for the PID-controller [-]"))
=== modified file 'pkg/common/OpenGLRenderer.cpp'
--- pkg/common/OpenGLRenderer.cpp 2014-02-16 16:42:06 +0000
+++ pkg/common/OpenGLRenderer.cpp 2014-04-16 19:53:59 +0000
@@ -87,7 +87,7 @@
void OpenGLRenderer::setBodiesDispInfo(){
if(scene->bodies->size()!=bodyDisp.size()) {
bodyDisp.resize(scene->bodies->size());
- for (Body::id_t k=0; k<scene->bodies->size(); k++) bodyDisp[k].hidden=0;}
+ for (unsigned k=0; k<scene->bodies->size(); k++) bodyDisp[k].hidden=0;}
bool scaleRotations=(rotScale!=1.0);
bool scaleDisplacements=(dispScale!=Vector3r::Ones());
FOREACH(const shared_ptr<Body>& b, *scene->bodies){
=== modified file 'pkg/common/PersistentTriangulationCollider.cpp'
--- pkg/common/PersistentTriangulationCollider.cpp 2010-11-19 21:29:56 +0000
+++ pkg/common/PersistentTriangulationCollider.cpp 2014-03-21 18:45:24 +0000
@@ -60,7 +60,7 @@
const Sphere* s = YADE_CAST<Sphere*>(b->shape.get());
Tes->insert ( b->state->pos[0],b->state->pos[1],b->state->pos[2], s->radius, b->getId() );
}
- Tes->AddBoundingPlanes();
+ Tes->addBoundingPlanes();
isTriangulated = true;
triangulationIteration = true;
//}
=== added file 'pkg/common/SPHEngine.cpp'
--- pkg/common/SPHEngine.cpp 1970-01-01 00:00:00 +0000
+++ pkg/common/SPHEngine.cpp 2014-04-14 06:43:15 +0000
@@ -0,0 +1,398 @@
+#ifdef YADE_SPH
+#include"SPHEngine.hpp"
+#include<yade/core/Scene.hpp>
+#include<yade/pkg/dem/ViscoelasticPM.hpp>
+#include<yade/pkg/common/Sphere.hpp>
+
+#include<yade/core/State.hpp>
+#include<yade/core/Omega.hpp>
+
+void SPHEngine::action(){
+ {
+ YADE_PARALLEL_FOREACH_BODY_BEGIN(const shared_ptr<Body>& b, scene->bodies){
+ if(mask>0 && (b->groupMask & mask)==0) continue;
+ this->calculateSPHRho(b);
+ b->press=k*(b->rho - b->rho0);
+ } YADE_PARALLEL_FOREACH_BODY_END();
+ }
+ /*
+ {
+ YADE_PARALLEL_FOREACH_BODY_BEGIN(const shared_ptr<Body>& b, scene->bodies){
+ if(mask>0 && (b->groupMask & mask)==0) continue;
+ this->calculateSPHCs(b);
+ } YADE_PARALLEL_FOREACH_BODY_END();
+ }
+ */
+}
+
+void SPHEngine::calculateSPHRho(const shared_ptr<Body>& b) {
+ if (b->rho0<0) {
+ b->rho0 = rho0;
+ }
+ Real rho = 0;
+
+ // Pointer to kernel function
+ KernelFunction kernelFunctionCurDensity = returnKernelFunction (KernFunctionDensity, KernFunctionDensity, Norm);
+
+ // Calculate rho for every particle
+ for(Body::MapId2IntrT::iterator it=b->intrs.begin(),end=b->intrs.end(); it!=end; ++it) {
+ const shared_ptr<Body> b2 = Body::byId((*it).first,scene);
+ Sphere* s=dynamic_cast<Sphere*>(b->shape.get());
+ if(!s) continue;
+
+ if (((*it).second)->geom and ((*it).second)->phys) {
+ const ScGeom geom = *(YADE_PTR_CAST<ScGeom>(((*it).second)->geom));
+ const ViscElPhys phys=*(YADE_PTR_CAST<ViscElPhys>(((*it).second)->phys));
+
+ if((b2->groupMask & mask)==0) continue;
+
+ Real Mass = b2->state->mass;
+ if (Mass == 0) Mass = b->state->mass;
+
+ const Real SmoothDist = -geom.penetrationDepth + phys.h;
+
+ // [Mueller2003], (3)
+ rho += b2->state->mass*kernelFunctionCurDensity(SmoothDist, phys.h);
+ }
+ // [Mueller2003], (3), we need to consider the density of the current body (?)
+ rho += b->state->mass*kernelFunctionCurDensity(0.0, s->radius);
+ }
+ b->rho = rho;
+}
+
+void SPHEngine::calculateSPHCs(const shared_ptr<Body>& b) {
+ if (b->Cs<0) {
+ b->Cs = 0.0;
+ }
+ Real Cs = 0;
+
+ // Pointer to kernel function
+ KernelFunction kernelFunctionCurDensity = returnKernelFunction (KernFunctionDensity, KernFunctionDensity, Norm);
+
+ // Calculate Cs for every particle
+ for(Body::MapId2IntrT::iterator it=b->intrs.begin(),end=b->intrs.end(); it!=end; ++it) {
+ const shared_ptr<Body> b2 = Body::byId((*it).first,scene);
+ Sphere* s=dynamic_cast<Sphere*>(b->shape.get());
+ if(!s) continue;
+
+ if (((*it).second)->geom and ((*it).second)->phys) {
+ const ScGeom geom = *(YADE_PTR_CAST<ScGeom>(((*it).second)->geom));
+ const ViscElPhys phys=*(YADE_PTR_CAST<ViscElPhys>(((*it).second)->phys));
+
+ if((b2->groupMask & mask)==0) continue;
+
+ Real Mass = b2->state->mass;
+ if (Mass == 0) Mass = b->state->mass;
+
+ const Real SmoothDist = -geom.penetrationDepth + phys.h;
+
+ // [Mueller2003], (15)
+ Cs += b2->state->mass/b2->rho*kernelFunctionCurDensity(SmoothDist, phys.h);
+ }
+ }
+ b->Cs = Cs;
+}
+
+Real smoothkernelPoly6(const double & rr, const double & hh) {
+ if (rr<=hh) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 315/(64*M_PI*pow(h,9))*pow((h*h - r*r), 3);
+ return 315/(64*M_PI)*pow((h - r*r), 3);
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelPoly6Grad(const double & rr, const double & hh) {
+ if (rr<=hh) {
+ const Real h = 1; const Real r = rr/hh;
+ //return -315/(64*M_PI*pow(h,9))*(-6*r*pow((h*h-r*r), 2));
+ return -315/(64*M_PI)*(-6*r*pow((h-r*r), 2));
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelPoly6Lapl(const double & rr, const double & hh) {
+ if (rr<=hh) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 315/(64*M_PI*pow(h,9))*(-6*(h*h-r*r)*(h*h - 5*r*r));
+ return 315/(64*M_PI)*(-6*(h*h-r*r)*(h*h - 5*r*r));
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelSpiky(const double & rr, const double & hh) {
+ if (rr<=hh) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 15/(M_PI*pow(h,6))*(pow((h-r), 3)); // [Mueller2003], (21)
+ return 15/(M_PI)*(pow((h-r), 3)); // [Mueller2003], (21)
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelSpikyGrad(const double & rr, const double & hh) {
+ if (rr<=hh) {
+ const Real h = 1; const Real r = rr/hh;
+ //return -15/(M_PI*pow(h,6))*(-3*pow((h-r),2));
+ return -15/(M_PI)*(-3*pow((h-r),2));
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelSpikyLapl(const double & rr, const double & hh) {
+ if (rr<=hh) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 15/(M_PI*pow(h,6))*(6*(h-r));
+ return 15/(M_PI)*(6*(h-r));
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelVisco(const double & rr, const double & hh) {
+ if (rr<=hh and rr!=0 and hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 15/(2*M_PI*pow(h,3))*(-r*r*r/(2*h*h*h) + r*r/(h*h) + h/(2*r) -1); // [Mueller2003], (21)
+ return 15/(2*M_PI)*(-r*r*r/(2) + r*r + h/(2*r) -1); // [Mueller2003], (21)
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelViscoGrad(const double & rr, const double & hh) {
+ if (rr<=hh and rr!=0 and hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ //return -15/(2*M_PI*pow(h,3))*(-3*r*r/(2*h*h*h) + 2*r/(h*h) - h/(2*r*r));
+ return -15/(2*M_PI)*(-3*r*r/(2) + 2*r - h/(2*r*r));
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelViscoLapl(const double & rr, const double & hh) {
+ if (rr<=hh and rr!=0 and hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 45/(M_PI*pow(h,6))*(h - rrj); // [Mueller2003], (22+)
+ //return 15/(2*M_PI*pow(h,3))*(-3*r*r/(2*h*h*h) + 2*r/(h*h) - h/(2*r*r));
+ return 15/(2*M_PI)*(-3*r*r/(2) + 2*r - h/(2*r*r));
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelLucy(const double & rr, const double & hh) {
+ if (rr<=hh and rr!=0 and hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 5/(9*M_PI*pow(h,2))*(1+3*r/h)*pow((1-r/h),3);
+ return 5/(9*M_PI)*(1+3*r)*pow((1-r),3);
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelLucyGrad(const double & rr, const double & hh) {
+ if (rr<=hh and rr!=0 and hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ //return -5/(9*M_PI*pow(h,2))*(-12*r/(h*h))*pow((1-r/h),2);
+ return -5/(9*M_PI)*(-12*r)*pow((1-r),2);
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelLucyLapl(const double & rr, const double & hh) {
+ if (rr<=hh and rr!=0 and hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ //return 5/(9*M_PI*pow(h,2))*(-12/(h*h))*(1-r/h)*(1-3*r/h);
+ return 5/(9*M_PI)*(-12)*(1-r)*(1-3*r);
+ } else {
+ return 0;
+ }
+}
+
+Real smoothkernelMonaghan(const double & rr, const double & hh) {
+ Real ret = 0.0;
+ if (hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ if (rr/hh<0.5) {
+ //ret = 40/(7*M_PI*h*h)*(1 - 6*pow((r/h),2) + 6*pow((r/h),3));
+ ret = 40/(7*M_PI)*(1 - 6*pow((r),2) + 6*pow((r),3));
+ } else {
+ //ret = 80/(7*M_PI*h*h)*pow((1 - (r/h)), 3);
+ ret = 80/(7*M_PI)*pow((1 - (r)), 3);
+ }
+ }
+ return ret;
+}
+
+Real smoothkernelMonaghanGrad(const double & rr, const double & hh) {
+ Real ret = 0.0;
+ if (hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ if (rr/hh<0.5) {
+ //ret = -40/(7*M_PI*h*h)*( - 6*r/(h*h))*(2 - 3 * r/(h*h*h));
+ ret = -40/(7*M_PI)*( - 6*r)*(2 - 3 * r);
+ } else {
+ //ret = -80/(7*M_PI*h*h)*( -3/h)*pow((1 -r/h), 2);
+ ret = -80/(7*M_PI)*( -3/h)*pow((1 -r), 2);
+ }
+ }
+ return ret;
+}
+
+Real smoothkernelMonaghanLapl(const double & rr, const double & hh) {
+ Real ret = 0.0;
+ if (hh!=0) {
+ const Real h = 1; const Real r = rr/hh;
+ if (rr/hh<0.5) {
+ //ret = 40/(7*M_PI*h*h)*( - 12/(h*h))*(1 - 3 * r/(h*h*h*h*h));
+ ret = 40/(7*M_PI)*( - 12)*(1 - 3 * r);
+ } else {
+ //ret = 80/(7*M_PI*h*h)*( 6/(h*h))*(1 -r/h);
+ ret = 80/(7*M_PI)*( 6)*(1 -r);
+ }
+ }
+ return ret;
+}
+
+KernelFunction returnKernelFunction(const int a, const int b, const typeKernFunctions typeF) {
+ if (a != b) {
+ throw runtime_error("Kernel types should be equal!");
+ }
+ if (a==Poly6) {
+ if (typeF==Norm) {
+ return smoothkernelPoly6;
+ } else if (typeF==Grad) {
+ return smoothkernelPoly6Grad;
+ } else if (typeF==Lapl) {
+ return smoothkernelPoly6Lapl;
+ } else {
+ KERNELFUNCDESCR
+ }
+ } else if (a==Spiky) {
+ if (typeF==Norm) {
+ return smoothkernelSpiky;
+ } else if (typeF==Grad) {
+ return smoothkernelSpikyGrad;
+ } else if (typeF==Lapl) {
+ return smoothkernelSpikyLapl;
+ } else {
+ KERNELFUNCDESCR
+ }
+ } else if (a==Visco) {
+ if (typeF==Norm) {
+ return smoothkernelVisco;
+ } else if (typeF==Grad) {
+ return smoothkernelViscoGrad;
+ } else if (typeF==Lapl) {
+ return smoothkernelViscoLapl;
+ } else {
+ }
+ } else if (a==Lucy) {
+ if (typeF==Norm) {
+ return smoothkernelLucy;
+ } else if (typeF==Grad) {
+ return smoothkernelLucyGrad;
+ } else if (typeF==Lapl) {
+ return smoothkernelLucyLapl;
+ } else {
+ KERNELFUNCDESCR
+ }
+ } else if (a==Monaghan) {
+ if (typeF==Norm) {
+ return smoothkernelMonaghan;
+ } else if (typeF==Grad) {
+ return smoothkernelMonaghanGrad;
+ } else if (typeF==Lapl) {
+ return smoothkernelMonaghanLapl;
+ } else {
+ KERNELFUNCDESCR
+ }
+ } else {
+ KERNELFUNCDESCR
+ }
+}
+
+bool computeForceSPH(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I, Vector3r & force) {
+
+ const ScGeom& geom=*static_cast<ScGeom*>(_geom.get());
+ Scene* scene=Omega::instance().getScene().get();
+ ViscElPhys& phys=*static_cast<ViscElPhys*>(_phys.get());
+
+ const int id1 = I->getId1();
+ const int id2 = I->getId2();
+
+ const BodyContainer& bodies = *scene->bodies;
+
+ //////////////////////////////////////////////////////////////////
+ // Copy-paste
+
+ const State& de1 = *static_cast<State*>(bodies[id1]->state.get());
+ const State& de2 = *static_cast<State*>(bodies[id2]->state.get());
+
+ // Handle periodicity.
+ const Vector3r shift2 = scene->isPeriodic ? scene->cell->intrShiftPos(I->cellDist): Vector3r::Zero();
+ const Vector3r shiftVel = scene->isPeriodic ? scene->cell->intrShiftVel(I->cellDist): Vector3r::Zero();
+
+ const Vector3r c1x = (geom.contactPoint - de1.pos);
+ const Vector3r c2x = (geom.contactPoint - de2.pos - shift2);
+
+ const Vector3r relativeVelocity = (de1.vel+de1.angVel.cross(c1x)) - (de2.vel+de2.angVel.cross(c2x)) + shiftVel;
+ const Real normalVelocity = geom.normal.dot(relativeVelocity);
+ const Vector3r shearVelocity = relativeVelocity-normalVelocity*geom.normal;
+
+ // Copy-paste
+ //////////////////////////////////////////////////////////////////
+
+ if (phys.h<0) {
+ Sphere* s1=dynamic_cast<Sphere*>(bodies[id1]->shape.get());
+ Sphere* s2=dynamic_cast<Sphere*>(bodies[id2]->shape.get());
+ if (s1 and s2) {
+ phys.h = s1->radius + s2->radius;
+ } else if (s1 and not(s2)) {
+ phys.h = s1->radius;
+ } else {
+ phys.h = s2->radius;
+ }
+ }
+
+ Real Mass = bodies[id2]->state->mass;
+ if (Mass==0.0 and bodies[id1]->state->mass!= 0.0) {
+ Mass = bodies[id1]->state->mass;
+ }
+
+ Real Rho = bodies[id2]->rho;
+ if (Rho==0.0 and bodies[id1]->rho!=0.0) {
+ Rho = bodies[id1]->rho;
+ }
+
+ const Vector3r xixj = (-geom.penetrationDepth + phys.h)*geom.normal;
+
+ if (xixj.norm() < phys.h) {
+ Real fpressure = 0.0;
+ if (Rho!=0.0) {
+ // [Mueller2003], (10)
+ fpressure = -Mass *
+ (bodies[id1]->press + bodies[id2]->press)/(2.0*Rho) *
+ phys.kernelFunctionCurrentPressure(xixj.norm(), phys.h);
+ }
+
+ Vector3r fvisc = Vector3r::Zero();
+ if (Rho!=0.0) {
+ fvisc = phys.mu * Mass *
+ normalVelocity*geom.normal/Rho *
+ phys.kernelFunctionCurrentVisco(xixj.norm(), phys.h);
+ }
+ force = fpressure*geom.normal + fvisc;
+ return true;
+ } else {
+ return false;
+ }
+}
+YADE_PLUGIN((SPHEngine));
+#endif
+
=== added file 'pkg/common/SPHEngine.hpp'
--- pkg/common/SPHEngine.hpp 1970-01-01 00:00:00 +0000
+++ pkg/common/SPHEngine.hpp 2014-04-09 14:03:16 +0000
@@ -0,0 +1,46 @@
+#ifdef YADE_SPH
+#pragma once
+
+#include<yade/core/PartialEngine.hpp>
+#include<yade/pkg/dem/ScGeom.hpp>
+
+typedef Real (* KernelFunction)(const double & r, const double & h);
+
+enum KernFunctions {Poly6=1, Spiky=2, Visco=3, Lucy=4, Monaghan=5};
+#define KERNELFUNCDESCR throw runtime_error("Type of kernel function undefined! The following kernel functions are available: Poly6=1, Spiky=2, Visco=3, Lucy=4, Monaghan=5.");
+
+enum typeKernFunctions {Norm, Grad, Lapl};
+class SPHEngine: public PartialEngine{
+ public:
+ void calculateSPHRho(const shared_ptr<Body>& b);
+ void calculateSPHCs (const shared_ptr<Body>& b);
+ virtual void action();
+ YADE_CLASS_BASE_DOC_ATTRS(SPHEngine,PartialEngine,"Apply given torque (momentum) value at every subscribed particle, at every step. ",
+ ((int, mask,-1,, "Bitmask for SPH-particles."))
+ ((Real,k,-1,, "Gas constant for SPH-interactions (only for SPH-model). See Mueller [Mueller2003]_ .")) // [Mueller2003], (11)
+ ((Real,rho0,-1,, "Rest density. See Mueller [Mueller2003]_ .")) // [Mueller2003], (1)
+ ((int,KernFunctionDensity, Poly6,, "Kernel function for density calculation (by default - Poly6). The following kernel functions are available: Poly6=1, Spiky=2, Visco=3, Lucy=4, Monaghan=5."))
+ );
+};
+REGISTER_SERIALIZABLE(SPHEngine);
+Real smoothkernelPoly6(const double & r, const double & h); // [Mueller2003] (20)
+Real smoothkernelPoly6Grad(const double & r, const double & h);
+Real smoothkernelPoly6Lapl(const double & r, const double & h);
+Real smoothkernelSpiky(const double & r, const double & h); // [Mueller2003] (21)
+Real smoothkernelSpikyGrad(const double & r, const double & h);
+Real smoothkernelSpikyLapl(const double & r, const double & h);
+Real smoothkernelVisco(const double & r, const double & h); // [Mueller2003] (22)
+Real smoothkernelViscoGrad(const double & r, const double & h); // [Mueller2003] (22)
+Real smoothkernelViscoLapl(const double & r, const double & h);
+Real smoothkernelLucy(const double & r, const double & h);
+Real smoothkernelLucyGrad(const double & r, const double & h);
+Real smoothkernelLucyLapl(const double & r, const double & h);
+Real smoothkernelMonaghan(const double & r, const double & h);
+Real smoothkernelMonaghanGrad(const double & r, const double & h);
+Real smoothkernelMonaghanLapl(const double & r, const double & h);
+
+KernelFunction returnKernelFunction(const int a, const int b, const typeKernFunctions typeF);
+
+bool computeForceSPH(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I, Vector3r & force);
+#endif
+
=== modified file 'pkg/dem/ConcretePM.hpp'
--- pkg/dem/ConcretePM.hpp 2013-08-14 08:59:42 +0000
+++ pkg/dem/ConcretePM.hpp 2014-04-10 10:25:02 +0000
@@ -140,7 +140,8 @@
static long cummBetaIter, cummBetaCount;
/*! auxiliary variable for visualization, recalculated in Law2_ScGeom_CpmPhys_Cpm at every iteration */
// Fn and Fs are also stored as Vector3r normalForce, shearForce in NormShearPhys
- Real omega, Fn, sigmaN, epsN, relResidualStrength; Vector3r sigmaT, Fs;
+ Real omega, Fn, sigmaN, epsN, relResidualStrength, kappaD, epsNPl;
+ Vector3r sigmaT, Fs, epsTPl, epsT;
static Real solveBeta(const Real c, const Real N);
Real computeDmgOverstress(Real dt);
@@ -155,6 +156,7 @@
void setRelResidualStrength(Real r);
virtual ~CpmPhys();
+ #define _ZERO_VECTOR3R(v) v = Vector3r::Zero()
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(CpmPhys,NormShearPhys,"Representation of a single interaction of the Cpm type: storage for relevant parameters.\n\n Evolution of the contact is governed by :yref:`Law2_ScGeom_CpmPhys_Cpm`, that includes damage effects and chages of parameters inside CpmPhys. See :yref:`cpm-model<CpmMat>` for details.",
((Real,E,NaN,,"normal modulus (stiffness / crossSection) [Pa]"))
((Real,G,NaN,,"shear modulus [Pa]"))
@@ -173,25 +175,26 @@
((Real,plTau,-1,,"characteristic time for viscoplasticity (if non-positive, no rate-dependence for shear)"))
((Real,plRateExp,0,,"exponent in the rate-dependent viscoplasticity"))
((Real,isoPrestress,0,,"\"prestress\" of this link (used to simulate isotropic stress)"))
- ((Real,kappaD,0,,"Up to now maximum normal strain (semi-norm), non-decreasing in time."))
- ((Real,epsNPl,0,,"normal plastic strain (initially zero)"))
- ((Vector3r,epsTPl,Vector3r::Zero(),,"shear plastic strain (initially zero)"))
((bool,neverDamage,false,,"the damage evolution function will always return virgin state"))
((int,damLaw,1,,"Law for softening part of uniaxial tension. 0 for linear, 1 for exponential (default)"))
- ((Real,epsTrans,0,,"Transversal strain (perpendicular to the contact axis)"))
//((Real,epsPlSum,0,,"cummulative shear plastic strain measure (scalar) on this contact"))
((bool,isCohesive,false,,"if not cohesive, interaction is deleted when distance is greater than zero."))
- ((Vector3r,epsT,Vector3r::Zero(),,"Total shear strain (either computed from increments with :yref:`ScGeom`) |yupdate|"))
- ,
- createIndex(); epsT=Fs=Vector3r::Zero(); Fn=0; omega=0;
- ,
- .def_readonly("omega",&CpmPhys::omega,"Damage internal variable")
- .def_readonly("Fn",&CpmPhys::Fn,"Magnitude of normal force.")
- .def_readonly("Fs",&CpmPhys::Fs,"Magnitude of shear force")
- .def_readonly("epsN",&CpmPhys::epsN,"Current normal strain")
- .def_readonly("sigmaN",&CpmPhys::sigmaN,"Current normal stress")
- .def_readonly("sigmaT",&CpmPhys::sigmaT,"Current shear stress")
- .def_readonly("relResidualStrength",&CpmPhys::relResidualStrength,"Relative residual strength")
+ , // ctors
+ createIndex();
+ Fn = omega = kappaD = epsN = kappaD = epsNPl = 0;
+ _ZERO_VECTOR3R(epsT); _ZERO_VECTOR3R(Fs); _ZERO_VECTOR3R(epsTPl);
+ ,
+ .def_readonly("omega",&CpmPhys::omega,"Damage internal variable |yupdate|")
+ .def_readonly("Fn",&CpmPhys::Fn,"Magnitude of normal force |yupdate|")
+ .def_readonly("Fs",&CpmPhys::Fs,"Magnitude of shear force |yupdate|")
+ .def_readonly("epsN",&CpmPhys::epsN,"Current normal strain |yupdate|")
+ .def_readonly("epsT",&CpmPhys::epsT,"Current shear strain |yupdate|")
+ .def_readonly("sigmaN",&CpmPhys::sigmaN,"Current normal stress |yupdate|")
+ .def_readonly("sigmaT",&CpmPhys::sigmaT,"Current shear stress |yupdate|")
+ .def_readonly("kappaD",&CpmPhys::kappaD,"Up to now maximum normal strain (semi-norm), non-decreasing in time |yupdate|")
+ .def_readonly("epsNPl",&CpmPhys::epsNPl,"normal plastic strain (initially zero) |yupdate|")
+ .def_readonly("epsTPl",&CpmPhys::epsTPl,"shear plastic strain (initially zero) |yupdate|")
+ .def_readonly("relResidualStrength",&CpmPhys::relResidualStrength,"Relative residual strength |yupdate|")
.def_readonly("cummBetaIter",&CpmPhys::cummBetaIter,"Cummulative number of iterations inside CpmMat::solveBeta (for debugging).")
.def_readonly("cummBetaCount",&CpmPhys::cummBetaCount,"Cummulative number of calls of CpmMat::solveBeta (for debugging).")
.def("funcG",&CpmPhys::funcG,(py::arg("kappaD"),py::arg("epsCrackOnset"),py::arg("epsFracture"),py::arg("neverDamage")=false,py::arg("damLaw")=1),"Damage evolution law, evaluating the $\\omega$ parameter. $\\kappa_D$ is historically maximum strain, *epsCrackOnset* ($\\varepsilon_0$) = :yref:`CpmPhys.epsCrackOnset`, *epsFracture* = :yref:`CpmPhys.epsFracture`; if *neverDamage* is ``True``, the value returned will always be 0 (no damage). TODO")
@@ -201,6 +204,7 @@
.def("setDamage",&CpmPhys::setDamage,"TODO")
.def("setRelResidualStrength",&CpmPhys::setRelResidualStrength,"TODO")
);
+ #undef _ZERO_VECTOR3R
DECLARE_LOGGER;
REGISTER_CLASS_INDEX(CpmPhys,NormShearPhys);
};
@@ -311,7 +315,7 @@
((bool,epsT,false,,"Show shear strain "))
((bool,epsTAxes,false,,"Show axes of shear plane "))
((bool,normal,false,,"Show contact normal"))
- ((Real,colorStrainRatio,-1,,"If positive, set the interaction (wire) color based on $\\eps_N$ normalized by $\\eps_0$ × `colorStrainRatio` ($\\eps_0$ = :yref:`CpmPhys.epsCrackOnset` ). Otherwise, color based on the residual strength."))
+ ((Real,colorStrainRatio,-1,,"If positive, set the interaction (wire) color based on $\\eps_N$ normalized by $\\eps_0$ × :yref:`colorStrainRatio<CpmPhys.colorStrainRatio>` ($\\eps_0$ = :yref:`CpmPhys.epsCrackOnset` ). Otherwise, color based on the residual strength."))
((bool,epsNLabel,false,,"Numerically show normal strain"))
);
};
=== removed file 'pkg/dem/FlowEngine.cpp'
--- pkg/dem/FlowEngine.cpp 2014-02-17 18:00:12 +0000
+++ pkg/dem/FlowEngine.cpp 1970-01-01 00:00:00 +0000
@@ -1,1139 +0,0 @@
-/*************************************************************************
-* Copyright (C) 2009 by Emanuele Catalano <catalano@xxxxxxxxxxxxxxx> *
-* Copyright (C) 2009 by Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> *
-* Copyright (C) 2012 by Donia Marzougui <donia.marzougui@xxxxxxxxxxxxxxx>*
-* *
-* 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 YADE_CGAL
-
-#ifdef FLOW_ENGINE
-#include<yade/core/Scene.hpp>
-#include<yade/lib/base/Math.hpp>
-#include<yade/pkg/dem/TesselationWrapper.hpp>
-#include<yade/pkg/common/Sphere.hpp>
-#include<yade/pkg/common/Wall.hpp>
-#include<yade/pkg/common/Box.hpp>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <boost/thread.hpp>
-#include <boost/date_time.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-
-#ifdef LINSOLV
-#include <cholmod.h>
-#endif
-
-#include "FlowEngine.hpp"
-
-CREATE_LOGGER ( FlowEngine );
-CREATE_LOGGER ( PeriodicFlowEngine );
-
-CGT::Vecteur makeCgVect ( const Vector3r& yv ) {return CGT::Vecteur ( yv[0],yv[1],yv[2] );}
-CGT::Point makeCgPoint ( const Vector3r& yv ) {return CGT::Point ( yv[0],yv[1],yv[2] );}
-Vector3r makeVector3r ( const CGT::Point& yv ) {return Vector3r ( yv[0],yv[1],yv[2] );}
-Vector3r makeVector3r ( const CGT::Vecteur& yv ) {return Vector3r ( yv[0],yv[1],yv[2] );}
-
-
-FlowEngine::~FlowEngine()
-{
-}
-
-const int facetVertices [4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
-
-void FlowEngine::action()
-{
- if ( !isActivated ) return;
- timingDeltas->start();
- setPositionsBuffer(true);
- timingDeltas->checkpoint ( "Position buffer" );
- if (first) {
- if (multithread) setPositionsBuffer(false);
- Build_Triangulation(P_zero,solver);
- Initialize_volumes(solver);
- backgroundSolver=solver;
- backgroundCompleted=true;
- }
- #ifdef parallel_forces
- solver->ompThreads = ompThreads>0? ompThreads : omp_get_max_threads();
- #endif
-
- timingDeltas->checkpoint ( "Triangulating" );
- UpdateVolumes ( solver );
- timingDeltas->checkpoint ( "Update_Volumes" );
-
- Eps_Vol_Cumulative += eps_vol_max;
- retriangulationLastIter++;
- if (!updateTriangulation) updateTriangulation = // If not already set true by another function of by the user, check conditions
- (defTolerance>0 && Eps_Vol_Cumulative > defTolerance) || retriangulationLastIter>meshUpdateInterval;
-
- ///Compute flow and and forces here
- if (pressureForce){
- solver->GaussSeidel(scene->dt);
- timingDeltas->checkpoint ( "Gauss-Seidel (includes matrix construct and factorization in single-thread mode)" );
- solver->ComputeFacetForcesWithCache();}
- timingDeltas->checkpoint ( "Compute_Forces" );
- ///Application of vicscous forces
- scene->forces.sync();
- timingDeltas->checkpoint ( "forces.sync()" );
- ComputeViscousForces ( *solver );
- timingDeltas->checkpoint ( "viscous forces" );
- Vector3r force;
- Finite_vertices_iterator vertices_end = solver->T[solver->currentTes].Triangulation().finite_vertices_end();
- for ( Finite_vertices_iterator 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);
- if (shearLubrication || viscousShear){
- force = force + solver->viscousShearForces[V_it->info().id()];
- scene->forces.addTorque ( V_it->info().id(), solver->viscousShearTorques[V_it->info().id()]);
- }
- if (normalLubrication)
- force = force + solver-> normLubForce[V_it->info().id()];
- scene->forces.addForce ( V_it->info().id(), force);
- }
- ///End Compute flow and forces
- timingDeltas->checkpoint ( "Applying Forces" );
- int sleeping = 0;
- if (multithread && !first) {
- while (updateTriangulation && !backgroundCompleted) { /*cout<<"sleeping..."<<sleeping++<<endl;*/
- sleeping++;
- boost::this_thread::sleep(boost::posix_time::microseconds(1000));}
- if (Debug && sleeping) cerr<<"sleeping..."<<sleeping<<endl;
- if (updateTriangulation || (ellapsedIter>(0.5*meshUpdateInterval) && backgroundCompleted)) {
- if (Debug) cerr<<"switch flow solver"<<endl;
- if (useSolver==0) LOG_ERROR("background calculations not available for Gauss-Seidel");
- if (fluidBulkModulus>0) solver->Interpolate (solver->T[solver->currentTes], backgroundSolver->T[backgroundSolver->currentTes]);
- solver=backgroundSolver;
- backgroundSolver = shared_ptr<FlowSolver> (new FlowSolver);
- //Copy imposed pressures/flow from the old solver
- backgroundSolver->imposedP = vector<pair<CGT::Point,Real> >(solver->imposedP);
- backgroundSolver->imposedF = vector<pair<CGT::Point,Real> >(solver->imposedF);
- if (Debug) cerr<<"switched"<<endl;
- setPositionsBuffer(false);//set "parallel" buffer for background calculation
- backgroundCompleted=false;
- retriangulationLastIter=ellapsedIter;
- updateTriangulation=false;
- Eps_Vol_Cumulative=0;
- ellapsedIter=0;
- boost::thread workerThread(&FlowEngine::backgroundAction,this);
- workerThread.detach();
- if (Debug) cerr<<"backgrounded"<<endl;
- Initialize_volumes(solver);
- ComputeViscousForces(*solver);
- if (Debug) cerr<<"volumes initialized"<<endl;
- }
- else {
- if (Debug && !backgroundCompleted) cerr<<"still computing solver in the background, ellapsedIter="<<ellapsedIter<<endl;
- ellapsedIter++;
- }
- } else {
- if (updateTriangulation && !first) {
- Build_Triangulation (P_zero, solver);
- Initialize_volumes(solver);
- ComputeViscousForces(*solver);
- updateTriangulation = false;
- Eps_Vol_Cumulative=0;
- retriangulationLastIter=0;
- ReTrg++;}
- }
- first=false;
- timingDeltas->checkpoint ( "Triangulate + init volumes" );
-}
-
-void FlowEngine::backgroundAction()
-{
- if (useSolver<1) {LOG_ERROR("background calculations not available for Gauss-Seidel"); return;}
- Build_Triangulation ( P_zero,backgroundSolver );
- //FIXME: GS is computing too much, we need only matrix factorization in fact
- backgroundSolver->GaussSeidel(scene->dt);
- //FIXME(2): and here we need only cached variables, not forces
- backgroundSolver->ComputeFacetForcesWithCache(/*onlyCache?*/ true);
-// boost::this_thread::sleep(boost::posix_time::seconds(5));
- backgroundCompleted = true;
-}
-
-template<class Solver>
-
-void FlowEngine::BoundaryConditions ( Solver& flow )
-{
-
- for (int k=0;k<6;k++) {
- flow->boundary (wallIds[k]).flowCondition=!bndCondIsPressure[k];
- flow->boundary (wallIds[k]).value=bndCondValue[k];
- flow->boundary (wallIds[k]).velocity = boundaryVelocity[k];//FIXME: needs correct implementation, maybe update the cached pos/vel?
- }
-}
-
-template<class Solver>
-void FlowEngine::setImposedPressure ( unsigned int cond, Real p,Solver& flow )
-{
- if ( cond>=flow->imposedP.size() ) LOG_ERROR ( "Setting p with cond higher than imposedP size." );
- flow->imposedP[cond].second=p;
- //force immediate update of boundary conditions
- flow->pressureChanged=true;
-}
-
-template<class Solver>
-void FlowEngine::imposeFlux ( Vector3r pos, Real flux,Solver& flow ){
- flow.imposedF.push_back ( pair<CGT::Point,Real> ( CGT::Point ( pos[0],pos[1],pos[2] ), flux ) );
-}
-
-template<class Solver>
-void FlowEngine::clearImposedPressure ( Solver& flow ) { flow->imposedP.clear(); flow->IPCells.clear();}
-template<class Solver>
-void FlowEngine::clearImposedFlux ( Solver& flow ) { flow->imposedF.clear(); flow->IFCells.clear();}
-
-template<class Solver>
-Real FlowEngine::getCellFlux ( unsigned int cond, const shared_ptr<Solver>& flow )
-{
- if ( cond>=flow->imposedP.size() ) {LOG_ERROR ( "Getting flux with cond higher than imposedP size." ); return 0;}
- double flux=0;
- typename Solver::Cell_handle& cell= flow->IPCells[cond];
- for ( int ngb=0;ngb<4;ngb++ ) {
- /*if (!cell->neighbor(ngb)->info().Pcondition)*/
- flux+= cell->info().k_norm() [ngb]* ( cell->info().p()-cell->neighbor ( ngb )->info().p() );
- }
- return flux+cell->info().dv();
-}
-
-template<class Solver>
-void FlowEngine::initSolver ( Solver& flow )
-{
- flow->Vtotalissimo=0; flow->Vsolid_tot=0; flow->Vporale=0; flow->Ssolid_tot=0;
- flow->SLIP_ON_LATERALS=slip_boundary;
- flow->k_factor = permeabilityFactor;
- flow->DEBUG_OUT = Debug;
- flow->useSolver = useSolver;
- #ifdef EIGENSPARSE_LIB
- flow->numSolveThreads = numSolveThreads;
- flow->numFactorizeThreads = numFactorizeThreads;
- #endif
- flow->meanKStat = meanKStat;
- flow->VISCOSITY = viscosity;
- flow->TOLERANCE=Tolerance;
- flow->RELAX=Relax;
- flow->clampKValues = clampKValues;
- flow->maxKdivKmean = maxKdivKmean;
- flow->minKdivKmean = minKdivKmean;
- flow->meanKStat = meanKStat;
- flow->permeability_map = permeability_map;
- flow->fluidBulkModulus = fluidBulkModulus;
- flow->T[flow->currentTes].Clear();
- flow->T[flow->currentTes].max_id=-1;
- flow->x_min = 1000.0, flow->x_max = -10000.0, flow->y_min = 1000.0, flow->y_max = -10000.0, flow->z_min = 1000.0, flow->z_max = -10000.0;
-}
-
-#ifdef LINSOLV
-template<class Solver>
-void FlowEngine::setForceMetis ( Solver& flow, bool force )
-{
- if (force) {
- flow->eSolver.cholmod().nmethods=1;
- flow->eSolver.cholmod().method[0].ordering=CHOLMOD_METIS;
- } else cholmod_defaults(&(flow->eSolver.cholmod()));
-}
-
-template<class Solver>
-bool FlowEngine::getForceMetis ( Solver& flow ) {return (flow->eSolver.cholmod().nmethods==1);}
-#endif
-
-template<class Solver>
-void FlowEngine::Build_Triangulation ( Solver& flow )
-{
- Build_Triangulation ( 0.f,flow );
-}
-
-template<class Solver>
-void FlowEngine::Build_Triangulation ( double P_zero, Solver& flow )
-{
- flow->ResetNetwork();
- if (first) flow->currentTes=0;
- else {
- flow->currentTes=!flow->currentTes;
- if (Debug) cout << "--------RETRIANGULATION-----------" << endl;
- }
-
- initSolver(flow);
-
- AddBoundary ( flow );
- Triangulate ( flow );
- if ( Debug ) cout << endl << "Tesselating------" << endl << endl;
- flow->T[flow->currentTes].Compute();
-
- flow->Define_fictious_cells();
- // For faster loops on cells define this vector
- flow->T[flow->currentTes].cellHandles.clear();
- flow->T[flow->currentTes].cellHandles.reserve(flow->T[flow->currentTes].Triangulation().number_of_finite_cells());
- Finite_cells_iterator cell_end = flow->T[flow->currentTes].Triangulation().finite_cells_end();
- int k=0;
- for ( Finite_cells_iterator cell = flow->T[flow->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ){
- flow->T[flow->currentTes].cellHandles.push_back(cell);
- cell->info().id=k++;}//define unique numbering now, corresponds to position in cellHandles
- flow->DisplayStatistics ();
- flow->Compute_Permeability();
- porosity = flow->V_porale_porosity/flow->V_totale_porosity;
-
- BoundaryConditions ( flow );
- flow->Initialize_pressures ( P_zero );
-
- if ( !first && !multithread && (useSolver==0 || fluidBulkModulus>0)) flow->Interpolate ( flow->T[!flow->currentTes], flow->T[flow->currentTes] );
- if ( WaveAction ) flow->ApplySinusoidalPressure ( flow->T[flow->currentTes].Triangulation(), sineMagnitude, sineAverage, 30 );
- if (normalLubrication || shearLubrication || viscousShear) flow->computeEdgesSurfaces();
-}
-
-void FlowEngine::setPositionsBuffer(bool current)
-{
- vector<posData>& buffer = current? positionBufferCurrent : positionBufferParallel;
- buffer.clear();
- buffer.resize(scene->bodies->size());
- shared_ptr<Sphere> sph ( new Sphere );
- const int Sph_Index = sph->getClassIndexStatic();
- FOREACH ( const shared_ptr<Body>& b, *scene->bodies ) {
- if (!b || ignoredBody==b->getId()) continue;
- posData& dat = buffer[b->getId()];
- dat.id=b->getId();
- dat.pos=b->state->pos;
- dat.isSphere= (b->shape->getClassIndex() == Sph_Index);
- if (dat.isSphere) dat.radius = YADE_CAST<Sphere*>(b->shape.get())->radius;
- dat.exists=true;
- }
-}
-
-template<class Solver>
-void FlowEngine::AddBoundary ( Solver& flow )
-{
- vector<posData>& buffer = multithread ? positionBufferParallel : positionBufferCurrent;
- solver->x_min = Mathr::MAX_REAL, solver->x_max = -Mathr::MAX_REAL, solver->y_min = Mathr::MAX_REAL, solver->y_max = -Mathr::MAX_REAL, solver->z_min = Mathr::MAX_REAL, solver->z_max = -Mathr::MAX_REAL;
- FOREACH ( const posData& b, buffer ) {
- if ( !b.exists ) continue;
- if ( b.isSphere ) {
- const Real& rad = b.radius;
- const Real& x = b.pos[0];
- const Real& y = b.pos[1];
- const Real& z = b.pos[2];
- flow->x_min = min ( flow->x_min, x-rad );
- flow->x_max = max ( flow->x_max, x+rad );
- flow->y_min = min ( flow->y_min, y-rad );
- flow->y_max = max ( flow->y_max, y+rad );
- flow->z_min = min ( flow->z_min, z-rad );
- flow->z_max = max ( flow->z_max, z+rad );
- }
- }
- //FIXME id_offset must be set correctly, not the case here (always 0), then we need walls first or it will fail
- id_offset = flow->T[flow->currentTes].max_id+1;
- flow->id_offset = id_offset;
- flow->SectionArea = ( flow->x_max - flow->x_min ) * ( flow->z_max-flow->z_min );
- flow->Vtotale = ( flow->x_max-flow->x_min ) * ( flow->y_max-flow->y_min ) * ( flow->z_max-flow->z_min );
- flow->y_min_id=wallIds[ymin];
- flow->y_max_id=wallIds[ymax];
- flow->x_max_id=wallIds[xmax];
- flow->x_min_id=wallIds[xmin];
- flow->z_min_id=wallIds[zmin];
- flow->z_max_id=wallIds[zmax];
-
- //FIXME: Id's order in boundsIds is done according to the enumeration of boundaries from TXStressController.hpp, line 31. DON'T CHANGE IT!
- flow->boundsIds[0]= &flow->x_min_id;
- flow->boundsIds[1]= &flow->x_max_id;
- flow->boundsIds[2]= &flow->y_min_id;
- flow->boundsIds[3]= &flow->y_max_id;
- flow->boundsIds[4]= &flow->z_min_id;
- flow->boundsIds[5]= &flow->z_max_id;
-
- for (int k=0;k<6;k++) flow->boundary ( *flow->boundsIds[k] ).useMaxMin = boundaryUseMaxMin[k];
-
-// if ( flow->y_min_id>=0 ) flow->boundary ( flow->y_min_id ).useMaxMin = boundaryUseMaxMin[ymin];
-// if ( flow->y_max_id>=0 ) flow->boundary ( flow->y_max_id ).useMaxMin = boundaryUseMaxMin[ymax];
-// if ( flow->x_max_id>=0 ) flow->boundary ( flow->x_max_id ).useMaxMin = boundaryUseMaxMin[xmax];
-// if ( flow->x_min_id>=0 ) flow->boundary ( flow->x_min_id ).useMaxMin = boundaryUseMaxMin[xmin];
-// if ( flow->z_max_id>=0 ) flow->boundary ( flow->z_max_id ).useMaxMin = boundaryUseMaxMin[zmax];
-// if ( flow->z_min_id>=0 ) flow->boundary ( flow->z_min_id ).useMaxMin = boundaryUseMaxMin[zmin];
-
- flow->Corner_min = CGT::Point ( flow->x_min, flow->y_min, flow->z_min );
- flow->Corner_max = CGT::Point ( flow->x_max, flow->y_max, flow->z_max );
-
- //assign BCs types and values
- BoundaryConditions ( flow );
-
- double center[3];
- for ( int i=0; i<6; i++ ) {
- if ( *flow->boundsIds[i]<0 ) continue;
- CGT::Vecteur Normal ( normal[i].x(), normal[i].y(), normal[i].z() );
- if ( flow->boundary ( *flow->boundsIds[i] ).useMaxMin ) flow->AddBoundingPlane(Normal, *flow->boundsIds[i] );
- else {
- for ( int h=0;h<3;h++ ) center[h] = buffer[*flow->boundsIds[i]].pos[h];
-// cerr << "id="<<*flow->boundsIds[i] <<" center="<<center[0]<<","<<center[1]<<","<<center[2]<<endl;
- flow->AddBoundingPlane ( center, wall_thickness, Normal,*flow->boundsIds[i] );
- }
- }
-}
-
-template<class Solver>
-void FlowEngine::Triangulate ( Solver& flow )
-{
-///Using Tesselation wrapper (faster)
-// TesselationWrapper TW;
-// if (TW.Tes) delete TW.Tes;
-// TW.Tes = &(flow->T[flow->currentTes]);//point to the current Tes we have in Flowengine
-// TW.insertSceneSpheres();//TW is now really inserting in FlowEngine, using the faster insert(begin,end)
-// TW.Tes = NULL;//otherwise, Tes would be deleted by ~TesselationWrapper() at the end of the function.
-///Using one-by-one insertion
- vector<posData>& buffer = multithread ? positionBufferParallel : positionBufferCurrent;
- FOREACH ( const posData& b, buffer ) {
- if ( !b.exists ) continue;
- if ( b.isSphere ) {
- if (b.id==ignoredBody) continue;
- flow->T[flow->currentTes].insert ( b.pos[0], b.pos[1], b.pos[2], b.radius, b.id );}
- }
- flow->T[flow->currentTes].redirected=true;//By inserting one-by-one, we already redirected
- flow->viscousShearForces.resize ( flow->T[flow->currentTes].max_id+1 );
- flow->viscousShearTorques.resize ( flow->T[flow->currentTes].max_id+1 );
- flow->viscousBodyStress.resize ( flow->T[flow->currentTes].max_id+1 );
- flow->normLubForce.resize ( flow->T[flow->currentTes].max_id+1 );
- flow->lubBodyStress.resize ( flow->T[flow->currentTes].max_id+1 );
-}
-template<class Solver>
-void FlowEngine::Initialize_volumes ( Solver& flow )
-{
- typedef typename Solver::element_type Flow;
- typedef typename Flow::Finite_vertices_iterator Finite_vertices_iterator;
- typedef typename Solver::element_type Flow;
-
- Finite_vertices_iterator vertices_end = flow->T[flow->currentTes].Triangulation().finite_vertices_end();
- CGT::Vecteur Zero(0,0,0);
- for (Finite_vertices_iterator V_it = flow->T[flow->currentTes].Triangulation().finite_vertices_begin(); V_it!= vertices_end; V_it++) V_it->info().forces=Zero;
-
- FOREACH(Cell_handle& cell, flow->T[flow->currentTes].cellHandles)
- {
- switch ( cell->info().fictious() )
- {
- case ( 0 ) : cell->info().volume() = Volume_cell ( cell ); break;
- case ( 1 ) : cell->info().volume() = Volume_cell_single_fictious ( cell ); break;
- case ( 2 ) : cell->info().volume() = Volume_cell_double_fictious ( cell ); break;
- case ( 3 ) : cell->info().volume() = Volume_cell_triple_fictious ( cell ); break;
- default: break;
- }
- if (flow->fluidBulkModulus>0) { cell->info().invVoidVolume() = 1 / ( abs(cell->info().volume()) - flow->volumeSolidPore(cell) ); }
- }
- if (Debug) cout << "Volumes initialised." << endl;
-}
-
-void FlowEngine::Average_real_cell_velocity()
-{
- solver->Average_Relative_Cell_Velocity();
- Vector3r Vel ( 0,0,0 );
- //AVERAGE CELL VELOCITY
- Finite_cells_iterator cell_end = solver->T[solver->currentTes].Triangulation().finite_cells_end();
- for ( Finite_cells_iterator cell = solver->T[solver->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ) {
- for ( int g=0;g<4;g++ ) {
- if ( !cell->vertex ( g )->info().isFictious ) {
- const shared_ptr<Body>& sph = Body::byId ( cell->vertex ( g )->info().id(), scene );
- for ( int i=0;i<3;i++ ) Vel[i] = Vel[i] + sph->state->vel[i]/4;
- }
- }
- RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
- CGT::Point pos_av_facet;
- double volume_facet_translation = 0;
- CGT::Vecteur Vel_av ( Vel[0], Vel[1], Vel[2] );
- for ( int i=0; i<4; i++ ) {
- volume_facet_translation = 0;
- if ( !Tri.is_infinite ( cell->neighbor ( i ) ) ) {
- CGT::Vecteur Surfk = cell->info()-cell->neighbor ( i )->info();
- Real area = sqrt ( Surfk.squared_length() );
- Surfk = Surfk/area;
- CGT::Vecteur branch = cell->vertex ( facetVertices[i][0] )->point() - cell->info();
- pos_av_facet = ( CGT::Point ) cell->info() + ( branch*Surfk ) *Surfk;
- volume_facet_translation += Vel_av*cell->info().facetSurfaces[i];
- cell->info().av_vel() = cell->info().av_vel() - volume_facet_translation/cell->info().volume() * ( pos_av_facet-CGAL::ORIGIN );
- }
- }
- }
-}
-template<class Solver>
-void FlowEngine::UpdateVolumes ( Solver& flow )
-{
- if ( Debug ) cout << "Updating volumes.............." << endl;
- Real invDeltaT = 1/scene->dt;
- eps_vol_max=0;
- Real totVol=0; Real totDVol=0;
- #ifdef YADE_OPENMP
- const long size=flow->T[flow->currentTes].cellHandles.size();
- #pragma omp parallel for num_threads(ompThreads>0 ? ompThreads : 1)
- for(long i=0; i<size; i++){
- Cell_handle& cell = flow->T[flow->currentTes].cellHandles[i];
- #else
- FOREACH(Cell_handle& cell, flow->T[flow->currentTes].cellHandles){
- #endif
- double newVol, dVol;
- switch ( cell->info().fictious() ) {
- case ( 3 ) : newVol = Volume_cell_triple_fictious ( cell ); break;
- case ( 2 ) : newVol = Volume_cell_double_fictious ( cell ); break;
- case ( 1 ) : newVol = Volume_cell_single_fictious ( cell ); break;
- case ( 0 ) : newVol = Volume_cell (cell ); break;
- default: newVol = 0; break;}
- dVol=cell->info().volumeSign* ( newVol - cell->info().volume() );
- cell->info().dv() = dVol*invDeltaT;
- cell->info().volume() = newVol;
- if (defTolerance>0) { //if the criterion is not used, then we skip these updates a save a LOT of time when Nthreads > 1
- #pragma omp atomic
- totVol+=newVol;
- #pragma omp atomic
- totDVol+=abs(dVol);}
- }
- if (defTolerance>0) eps_vol_max = totDVol/totVol;
- for (unsigned int n=0; n<flow->imposedF.size();n++) {
- flow->IFCells[n]->info().dv()+=flow->imposedF[n].second;
- flow->IFCells[n]->info().Pcondition=false;}
- if ( Debug ) cout << "Updated volumes, total =" <<totVol<<", dVol="<<totDVol<<endl;
-}
-template<class Cellhandle>
-Real FlowEngine::Volume_cell_single_fictious ( Cellhandle cell )
-{
- Vector3r V[3];
- int b=0;
- int w=0;
- cell->info().volumeSign=1;
- Real Wall_coordinate=0;
-
- for ( int y=0;y<4;y++ ) {
- if ( ! ( cell->vertex ( y )->info().isFictious ) ) {
- V[w]=positionBufferCurrent[cell->vertex ( y )->info().id()].pos;
- w++;
- } else {
- b = cell->vertex ( y )->info().id();
- const shared_ptr<Body>& wll = Body::byId ( b , scene );
- if ( !solver->boundary ( b ).useMaxMin ) Wall_coordinate = wll->state->pos[solver->boundary ( b ).coordinate]+ ( solver->boundary ( b ).normal[solver->boundary ( b ).coordinate] ) *wall_thickness/2;
- else Wall_coordinate = solver->boundary ( b ).p[solver->boundary ( b ).coordinate];
- }
- }
- Real Volume = 0.5* ( ( V[0]-V[1] ).cross ( V[0]-V[2] ) ) [solver->boundary ( b ).coordinate] * ( 0.33333333333* ( V[0][solver->boundary ( b ).coordinate]+ V[1][solver->boundary ( b ).coordinate]+ V[2][solver->boundary ( b ).coordinate] ) - Wall_coordinate );
- return abs ( Volume );
-}
-template<class Cellhandle>
-Real FlowEngine::Volume_cell_double_fictious ( Cellhandle cell )
-{
- Vector3r A=Vector3r::Zero(), AS=Vector3r::Zero(),B=Vector3r::Zero(), BS=Vector3r::Zero();
-
- cell->info().volumeSign=1;
- int b[2];
- int coord[2];
- Real Wall_coordinate[2];
- int j=0;
- bool first_sph=true;
-
- for ( int g=0;g<4;g++ ) {
- if ( cell->vertex ( g )->info().isFictious ) {
- b[j] = cell->vertex ( g )->info().id();
- coord[j]=solver->boundary ( b[j] ).coordinate;
- if ( !solver->boundary ( b[j] ).useMaxMin ) Wall_coordinate[j] = positionBufferCurrent[b[j]].pos[coord[j]] + ( solver->boundary ( b[j] ).normal[coord[j]] ) *wall_thickness/2;
- else Wall_coordinate[j] = solver->boundary ( b[j] ).p[coord[j]];
- j++;
- } else if ( first_sph ) {
- A=AS=/*AT=*/ positionBufferCurrent[cell->vertex(g)->info().id()].pos;
- first_sph=false;
- } else {
- B=BS=/*BT=*/ positionBufferCurrent[cell->vertex(g)->info().id()].pos;;
- }
- }
- AS[coord[0]]=BS[coord[0]] = Wall_coordinate[0];
-
- //first pyramid with triangular base (A,B,BS)
- Real Vol1=0.5* ( ( A-BS ).cross ( B-BS ) ) [coord[1]]* ( 0.333333333* ( 2*B[coord[1]]+A[coord[1]] )-Wall_coordinate[1] );
- //second pyramid with triangular base (A,AS,BS)
- Real Vol2=0.5* ( ( AS-BS ).cross ( A-BS ) ) [coord[1]]* ( 0.333333333* ( B[coord[1]]+2*A[coord[1]] )-Wall_coordinate[1] );
- return abs ( Vol1+Vol2 );
-}
-template<class Cellhandle>
-Real FlowEngine::Volume_cell_triple_fictious ( Cellhandle cell )
-{
- Vector3r A;
-
- int b[3];
- int coord[3];
- Real Wall_coordinate[3];
- int j=0;
- cell->info().volumeSign=1;
-
- for ( int g=0;g<4;g++ ) {
- if ( cell->vertex ( g )->info().isFictious ) {
- b[j] = cell->vertex ( g )->info().id();
- coord[j]=solver->boundary ( b[j] ).coordinate;
- const shared_ptr<Body>& wll = Body::byId ( b[j] , scene );
- if ( !solver->boundary ( b[j] ).useMaxMin ) Wall_coordinate[j] = wll->state->pos[coord[j]] + ( solver->boundary ( b[j] ).normal[coord[j]] ) *wall_thickness/2;
- else Wall_coordinate[j] = solver->boundary ( b[j] ).p[coord[j]];
- j++;
- } else {
- const shared_ptr<Body>& sph = Body::byId ( cell->vertex ( g )->info().id(), scene );
- A= ( sph->state->pos );
- }
- }
- Real Volume = ( A[coord[0]]-Wall_coordinate[0] ) * ( A[coord[1]]-Wall_coordinate[1] ) * ( A[coord[2]]-Wall_coordinate[2] );
- return abs ( Volume );
-}
-template<class Cellhandle>
-Real FlowEngine::Volume_cell ( Cellhandle cell )
-{
- static const Real inv6 = 1/6.;
- const Vector3r& p0 = positionBufferCurrent[cell->vertex ( 0 )->info().id()].pos;
- const Vector3r& p1 = positionBufferCurrent[cell->vertex ( 1 )->info().id()].pos;
- const Vector3r& p2 = positionBufferCurrent[cell->vertex ( 2 )->info().id()].pos;
- const Vector3r& p3 = positionBufferCurrent[cell->vertex ( 3 )->info().id()].pos;
- Real volume = inv6 * ((p0-p1).cross(p0-p2)).dot(p0-p3);
- if ( ! ( cell->info().volumeSign ) ) cell->info().volumeSign= ( volume>0 ) ?1:-1;
- return volume;
-}
-template<class Solver>
-void FlowEngine::ComputeViscousForces ( Solver& flow )
-{
- if (normalLubrication || shearLubrication || viscousShear){
- if ( Debug ) cout << "Application of viscous forces" << endl;
- if ( Debug ) cout << "Number of edges = " << flow.Edge_ids.size() << endl;
- for ( unsigned int k=0; k<flow.viscousShearForces.size(); k++ ) flow.viscousShearForces[k]=Vector3r::Zero();
- for ( unsigned int k=0; k<flow.viscousShearTorques.size(); k++ ) flow.viscousShearTorques[k]=Vector3r::Zero();
- for ( unsigned int k=0; k<flow.viscousBodyStress.size(); k++) flow.viscousBodyStress[k]=Matrix3r::Zero();
- for ( unsigned int k=0; k<flow.normLubForce.size(); k++ ) flow.normLubForce[k]=Vector3r::Zero();
- for ( unsigned int k=0; k<flow.lubBodyStress.size(); k++) flow.lubBodyStress[k]=Matrix3r::Zero();
-
- typedef typename Solver::Tesselation Tesselation;
- const Tesselation& Tes = flow.T[flow.currentTes];
- flow.deltaShearVel.clear(); flow.normalV.clear(); flow.deltaNormVel.clear(); flow.surfaceDistance.clear(); flow.onlySpheresInteractions.clear(); flow.normalStressInteraction.clear(); flow.shearStressInteraction.clear();
-
-
- for ( int i=0; i< ( int ) flow.Edge_ids.size(); i++ ) {
- const int& id1 = flow.Edge_ids[i].first;
- const int& id2 = flow.Edge_ids[i].second;
-
- int hasFictious= Tes.vertex ( id1 )->info().isFictious + Tes.vertex ( id2 )->info().isFictious;
- if (hasFictious>0 or id1==id2) continue;
- const shared_ptr<Body>& sph1 = Body::byId ( id1, scene );
- const shared_ptr<Body>& sph2 = Body::byId ( id2, scene );
- Sphere* s1=YADE_CAST<Sphere*> ( sph1->shape.get() );
- Sphere* s2=YADE_CAST<Sphere*> ( sph2->shape.get() );
- const Real& r1 = s1->radius;
- const Real& r2 = s2->radius;
- Vector3r deltaV; Real deltaNormV; Vector3r deltaShearV;
- Vector3r O1O2_vect; Real O1O2; Vector3r normal; Real surfaceDist; Vector3r O1C_vect; Vector3r O2C_vect;Real meanRad ;Real Rh;
- Vector3r visc_f; Vector3r lub_f;
- //FIXME: if periodic and velGrad!=0, then deltaV should account for velGrad, not the case currently
- if ( !hasFictious ){
- O1O2_vect = sph2->state->pos + makeVector3r(Tes.vertex(id2)->info().ghostShift()) - sph1->state->pos - makeVector3r(Tes.vertex(id1)->info().ghostShift());
- O1O2 = O1O2_vect.norm();
- normal= (O1O2_vect/O1O2);
- surfaceDist = O1O2 - r2 - r1;
- O1C_vect = (O1O2/2. + (pow(r1,2) - pow(r2,2)) / (2.*O1O2))*normal;
- O2C_vect = -(O1O2_vect-O1C_vect);
- meanRad = (r2 + r1)/2.;
- Rh = (r1 < r2)? surfaceDist + 0.45 * r1 : surfaceDist + 0.45 * r2;
- deltaV = (sph2->state->vel + sph2->state->angVel.cross(-r2 * normal)) - (sph1->state->vel+ sph1->state->angVel.cross(r1 * normal));
-
- } else {
- if ( hasFictious==1 ) {//for the fictious sphere, use velocity of the boundary, not of the body
- bool v1fictious = Tes.vertex ( id1 )->info().isFictious;
- int bnd = v1fictious? id1 : id2;
- int coord = flow.boundary(bnd).coordinate;
- O1O2 = v1fictious ? abs((sph2->state->pos + makeVector3r(Tes.vertex(id2)->info().ghostShift()))[coord] - flow.boundary(bnd).p[coord]) : abs((sph1->state->pos + makeVector3r(Tes.vertex(id1)->info().ghostShift()))[coord] - flow.boundary(bnd).p[coord]);
- if(v1fictious)
- normal = makeVector3r(flow.boundary(id1).normal);
- else
- normal = -makeVector3r(flow.boundary(id2).normal);
- O1O2_vect = O1O2 * normal;
- meanRad = v1fictious ? r2:r1;
- surfaceDist = O1O2- meanRad;
- if (v1fictious){
- O1C_vect = Vector3r::Zero();
- O2C_vect = -O1O2_vect;}
- else{
- O1C_vect = O1O2_vect;
- O2C_vect = Vector3r::Zero();}
-
- Rh = surfaceDist + 0.45 * meanRad;
- Vector3r v1 = ( Tes.vertex ( id1 )->info().isFictious ) ? flow.boundary ( id1 ).velocity:sph1->state->vel + sph1->state->angVel.cross(r1 * normal);
- Vector3r v2 = ( Tes.vertex ( id2 )->info().isFictious ) ? flow.boundary ( id2 ).velocity:sph2->state->vel + sph2->state->angVel.cross(-r2 * (normal));
- deltaV = v2-v1;
- }
- }
- deltaShearV = deltaV - ( normal.dot ( deltaV ) ) *normal;
- flow.deltaShearVel.push_back(deltaShearV);
- flow.normalV.push_back(normal);
- flow.surfaceDistance.push_back(max(surfaceDist, 0.) + eps*meanRad);
-
- if (shearLubrication)
- visc_f = flow.computeShearLubricationForce(deltaShearV,surfaceDist,i,eps,O1O2,meanRad);
- else if (viscousShear)
- visc_f = flow.computeViscousShearForce ( deltaShearV, i , Rh);
-
- if (viscousShear || shearLubrication){
-
- flow.viscousShearForces[id1]+=visc_f;
- flow.viscousShearForces[id2]+=(-visc_f);
- flow.viscousShearTorques[id1]+=O1C_vect.cross(visc_f);
- flow.viscousShearTorques[id2]+=O2C_vect.cross(-visc_f);
-
-
- /// Compute the viscous shear stress on each particle
- if (viscousShearBodyStress){
- flow.viscousBodyStress[id1] += visc_f * O1C_vect.transpose()/ (4.0/3.0 *3.14* pow(r1,3));
- flow.viscousBodyStress[id2] += (-visc_f) * O2C_vect.transpose()/ (4.0/3.0 *3.14* pow(r2,3));
- flow.shearStressInteraction.push_back(visc_f * O1O2_vect.transpose()/(4.0/3.0 *3.14* pow(r1,3)));
- }
- }
-
- /// Compute the normal lubrication force applied on each particle
- if (normalLubrication){
- deltaNormV = normal.dot(deltaV);
- flow.deltaNormVel.push_back(deltaNormV * normal);
- lub_f = flow.computeNormalLubricationForce (deltaNormV, surfaceDist, i,eps,stiffness,scene->dt,meanRad)*normal;
- flow.normLubForce[id1]+=lub_f;
- flow.normLubForce[id2]+=(-lub_f);
-
- /// Compute the normal lubrication stress on each particle
- if (viscousNormalBodyStress){
- flow.lubBodyStress[id1] += lub_f * O1C_vect.transpose()/ (4.0/3.0 *3.14* pow(r1,3));
- flow.lubBodyStress[id2] += (-lub_f) *O2C_vect.transpose() / (4.0/3.0 *3.14* pow(r2,3));
- flow.normalStressInteraction.push_back(lub_f * O1O2_vect.transpose()/(4.0/3.0 *3.14* pow(r1,3)));
- }
- }
-
- if (create_file){
- std::ofstream velocity_file("result_velocity.txt",ios::app);
- velocity_file << i << "\t" << deltaNormV * normal[0] << "\t" << deltaNormV * normal[1] << "\t" << deltaNormV * normal[2] << "\t" << deltaShearV[0] << "\t" << deltaShearV[1] << "\t" << deltaShearV[2] << "\t" << normal[0] << "\t" << normal[1] << "\t" << normal[2] << "\t" << max(surfaceDist, 0.) + eps*meanRad << endl;
- velocity_file.close(); }
-
- if (display_force) cout<<"force tangentielle "<<visc_f<< " force normale "<< lub_f<<endl;
- if (!hasFictious)
- flow.onlySpheresInteractions.push_back(i);
-
- }
- }
-}
-
-YADE_PLUGIN ( ( FlowEngine ) );
-
-//______________________________________________________________
-
-//___________________ PERIODIC VERSION _________________________
-//______________________________________________________________
-
-PeriodicFlowEngine::~PeriodicFlowEngine(){}
-
-void PeriodicFlowEngine:: action()
-{
- if ( !isActivated ) return;
- timingDeltas->start();
- preparePShifts();
- setPositionsBuffer(true);
- if (first) {
- if (multithread) setPositionsBuffer(false);
- cachedCell= Cell(*(scene->cell));
- Build_Triangulation(P_zero,solver);
- if (solver->errorCode>0) {LOG_INFO("triangulation error, pausing"); Omega::instance().pause(); return;}
- Initialize_volumes(solver); backgroundSolver=solver; backgroundCompleted=true;}
-// if ( first ) {Build_Triangulation ( P_zero ); updateTriangulation = false; Initialize_volumes();}
-
- timingDeltas->checkpoint("Triangulating");
- UpdateVolumes (solver);
- Eps_Vol_Cumulative += eps_vol_max;
- retriangulationLastIter++;
- if (!updateTriangulation) updateTriangulation = // If not already set true by another function of by the user, check conditions
- (defTolerance>0 && Eps_Vol_Cumulative > defTolerance) || retriangulationLastIter>meshUpdateInterval;
-
- timingDeltas->checkpoint("Update_Volumes");
-
- ///Compute flow and and forces here
- if (pressureForce){
- solver->GaussSeidel(scene->dt);
- timingDeltas->checkpoint("Gauss-Seidel");
- solver->ComputeFacetForcesWithCache();}
- timingDeltas->checkpoint("Compute_Pressure_Forces");
-
- ///Compute vicscous forces
- scene->forces.sync();
- ComputeViscousForces(*solver);
- timingDeltas->checkpoint("Compute_Viscous_Forces");
- Vector3r force;
- const Tesselation& Tes = solver->T[solver->currentTes];
- for (int id=0; id<=Tes.max_id; id++){
- assert (Tes.vertexHandles[id] != NULL);
- const Tesselation::Vertex_Info& v_info = Tes.vertexHandles[id]->info();
- force =(pressureForce) ? Vector3r ( ( v_info.forces ) [0],v_info.forces[1],v_info.forces[2] ) : Vector3r(0,0,0);
- if (shearLubrication || viscousShear){
- force = force +solver->viscousShearForces[v_info.id()];
- scene->forces.addTorque ( v_info.id(), solver->viscousShearTorques[v_info.id()]);
- }
- if (normalLubrication)
- force = force + solver->normLubForce[v_info.id()];
- scene->forces.addForce ( v_info.id(), force);
- }
- ///End Compute flow and forces
- timingDeltas->checkpoint("Applying Forces");
- if (multithread && !first) {
- while (updateTriangulation && !backgroundCompleted) { /*cout<<"sleeping..."<<sleeping++<<endl;*/ boost::this_thread::sleep(boost::posix_time::microseconds(1000));}
- if (updateTriangulation || ellapsedIter>(0.5*meshUpdateInterval)) {
- if (useSolver==0) LOG_ERROR("background calculations not available for Gauss-Seidel");
- if (fluidBulkModulus>0) solver->Interpolate (solver->T[solver->currentTes], backgroundSolver->T[backgroundSolver->currentTes]);
- solver=backgroundSolver;
- backgroundSolver = shared_ptr<FlowSolver> (new FlowSolver);
- //Copy imposed pressures/flow from the old solver
- backgroundSolver->imposedP = vector<pair<CGT::Point,Real> >(solver->imposedP);
- backgroundSolver->imposedF = vector<pair<CGT::Point,Real> >(solver->imposedF);
- setPositionsBuffer(false);
- cachedCell= Cell(*(scene->cell));
- backgroundCompleted=false;
- retriangulationLastIter=ellapsedIter;
- ellapsedIter=0;
- Eps_Vol_Cumulative=0;
- boost::thread workerThread(&PeriodicFlowEngine::backgroundAction,this);
- workerThread.detach();
- Initialize_volumes(solver);
- ComputeViscousForces(*solver);
- }
- else if (Debug && !first) {
- if (Debug && !backgroundCompleted) cerr<<"still computing solver in the background"<<endl;
- ellapsedIter++;}
- } else {
- if (updateTriangulation && !first) {
- cachedCell= Cell(*(scene->cell));
- Build_Triangulation (P_zero, solver);
- Initialize_volumes(solver);
- ComputeViscousForces(*solver);
- updateTriangulation = false;
- Eps_Vol_Cumulative=0;
- retriangulationLastIter=0;
- ReTrg++;}
- }
- first=false;
- timingDeltas->checkpoint("Ending");
-}
-
-
-void PeriodicFlowEngine::backgroundAction()
-{
- if (useSolver<1) {LOG_ERROR("background calculations not available for Gauss-Seidel"); return;}
- Build_Triangulation (P_zero,backgroundSolver);
- //FIXME: GS is computing too much, we need only matrix factorization in fact
- backgroundSolver->GaussSeidel(scene->dt);
- backgroundSolver->ComputeFacetForcesWithCache(/*onlyCache?*/ true);
-// boost::this_thread::sleep(boost::posix_time::seconds(10));
- backgroundCompleted = true;
-}
-
-void PeriodicFlowEngine::Triangulate( shared_ptr<FlowSolver>& flow )
-{
- Tesselation& Tes = flow->T[flow->currentTes];
- vector<posData>& buffer = multithread ? positionBufferParallel : positionBufferCurrent;
- FOREACH ( const posData& b, buffer ) {
- if ( !b.exists || !b.isSphere || b.id==ignoredBody) continue;
- Vector3i period; Vector3r wpos;
- // FIXME: use "sheared" variant if the cell is sheared
- wpos=cachedCell.wrapPt ( b.pos,period );
- const Body::id_t& id = b.id;
- const Real& rad = b.radius;
- const Real& x = wpos[0];
- const Real& y = wpos[1];
- const Real& z = wpos[2];
- Vertex_handle vh0=Tes.insert ( x, y, z, rad, id );
-// Vertex_handle vh0=Tes.insert ( b.pos[0], b.pos[1], b.pos[2], b.radius, b.id );
- if (vh0==NULL) {
- flow->errorCode = 2;
- LOG_ERROR("Vh NULL in PeriodicFlowEngine::Triangulate(), check input data"); continue;}
- for ( int k=0;k<3;k++ ) vh0->info().period[k]=-period[k];
- const Vector3r cellSize ( cachedCell.getSize() );
- //FIXME: if hasShear, comment in
-// wpos=scene->cell->unshearPt ( wpos );
- // traverse all periodic cells around the body, to see if any of them touches
- Vector3r halfSize= ( rad+duplicateThreshold ) *Vector3r ( 1,1,1 );
- Vector3r pmin,pmax;
- Vector3i i;
- for ( i[0]=-1; i[0]<=1; i[0]++ )
- for ( i[1]=-1;i[1]<=1; i[1]++ )
- for ( i[2]=-1; i[2]<=1; i[2]++ ) {
- if ( i[0]!=0 || i[1]!=0 || i[2]!=0 ) { // middle; already rendered above
- Vector3r pos2=wpos+Vector3r ( cellSize[0]*i[0],cellSize[1]*i[1],cellSize[2]*i[2] ); // shift, but without shear!
- pmin=pos2-halfSize;
- pmax=pos2+halfSize;
- if ( (pmin[0]<=cellSize[0]) && (pmax[0]>=0) && (pmin[1]<=cellSize[1]) && (pmax[1]>=0) && (pmin[2]<=cellSize[2]) && (pmax[2]>=0) ) {
- //with shear:
- //Vector3r pt=scene->cell->shearPt ( pos2 );
- //without shear:
- const Vector3r& pt= pos2;
- Vertex_handle vh=Tes.insert ( pt[0],pt[1],pt[2],rad,id,false,id );
- for ( int k=0;k<3;k++ ) vh->info().period[k]=i[k]-period[k];}}
- }
- //re-assign the original vertex pointer since duplicates may have overwrite it
- Tes.vertexHandles[id]=vh0;
- }
- Tes.redirected=true;//By inserting one-by-one, we already redirected
- flow -> viscousShearForces.resize ( Tes.max_id+1 );
- flow -> viscousShearTorques.resize ( Tes.max_id+1 );
- flow -> viscousBodyStress.resize ( Tes.max_id+1 );
- flow -> normLubForce.resize ( Tes.max_id+1 );
- flow -> lubBodyStress.resize ( Tes.max_id+1 );
-}
-
-
-Real PeriodicFlowEngine::Volume_cell ( Cell_handle cell )
-{
- static const Real inv6 = 1/6.;
- const Vector3r p0 = positionBufferCurrent[cell->vertex(0)->info().id()].pos + makeVector3r(cell->vertex(0)->info().ghostShift());
- const Vector3r p1 = positionBufferCurrent[cell->vertex(1)->info().id()].pos + makeVector3r(cell->vertex(1)->info().ghostShift());
- const Vector3r p2 = positionBufferCurrent[cell->vertex(2)->info().id()].pos + makeVector3r(cell->vertex(2)->info().ghostShift());
- const Vector3r p3 = positionBufferCurrent[cell->vertex(3)->info().id()].pos + makeVector3r(cell->vertex(3)->info().ghostShift());
- Real volume = inv6*((p0-p1).cross(p0-p2)).dot(p0-p3);
- if ( ! ( cell->info().volumeSign ) ) cell->info().volumeSign= ( volume>0 ) ?1:-1;
- return volume;
-}
-
-Real PeriodicFlowEngine::Volume_cell_single_fictious ( Cell_handle cell )
-{
- Vector3r V[3];
- int b=0;
- int w=0;
- cell->info().volumeSign=1;
- Real Wall_coordinate=0;
-
- for ( int y=0;y<4;y++ ) {
- if ( ! ( cell->vertex ( y )->info().isFictious ) ) {
- const shared_ptr<Body>& sph = Body::byId ( cell->vertex ( y )->info().id(), scene );
- V[w]=sph->state->pos+ makeVector3r ( cell->vertex ( y )->info().ghostShift() );
- w++;
- } else {
- b = cell->vertex ( y )->info().id();
- const shared_ptr<Body>& wll = Body::byId ( b,scene );
- if ( !solver->boundary ( b ).useMaxMin ) Wall_coordinate = wll->state->pos[solver->boundary ( b ).coordinate]+ ( solver->boundary ( b ).normal[solver->boundary ( b ).coordinate] ) *wall_thickness/2;
- else Wall_coordinate = solver->boundary ( b ).p[solver->boundary ( b ).coordinate];
- }
- }
- Real Volume = 0.5* ( ( V[0]-V[1] ).cross ( V[0]-V[2] ) ) [solver->boundary ( b ).coordinate] * ( 0.33333333333* ( V[0][solver->boundary ( b ).coordinate]+ V[1][solver->boundary ( b ).coordinate]+ V[2][solver->boundary ( b ).coordinate] ) - Wall_coordinate );
- return abs ( Volume );
-}
-
-
-void PeriodicFlowEngine::locateCell ( Cell_handle baseCell, unsigned int& index, int& baseIndex, shared_ptr<FlowSolver>& flow, unsigned int count)
-{
- if (count>10) {
- LOG_ERROR("More than 10 attempts to locate a cell, duplicateThreshold may be too small, resulting in periodicity inconsistencies.");
- flow->errorCode=1; return;
- }
- PeriFlowTesselation::Cell_Info& base_info = baseCell->info();
- //already located, return FIXME: is inline working correctly? else move this test outside the function, just before the calls
- if ( base_info.index>0 || base_info.isGhost ) return;
- RTriangulation& Tri = flow->T[flow->currentTes].Triangulation();
- Vector3r center ( 0,0,0 );
- Vector3i period;
-
- if (baseCell->info().fictious()==0)
- for ( int k=0;k<4;k++ ) center+= 0.25*makeVector3r (baseCell->vertex(k)->point());
- else {
-
- Real boundPos=0; int coord=0;
- for ( int k=0;k<4;k++ ) {
- if ( !baseCell->vertex ( k )->info().isFictious ) center+= 0.3333333333*makeVector3r ( baseCell->vertex ( k )->point() );
- else {
- coord=flow->boundary ( baseCell->vertex ( k )->info().id() ).coordinate;
- boundPos=flow->boundary ( baseCell->vertex ( k )->info().id() ).p[coord];}
- }
- center[coord]=boundPos;
- }
- Vector3r wdCenter= cachedCell.wrapPt ( center,period );
- if ( period[0]!=0 || period[1]!=0 || period[2]!=0 ) {
- if ( baseCell->info().index>0 ) {
- cout<<"indexed cell is found ghost!"<<base_info.index <<endl;
- base_info.isGhost=false;
- return;
- }
- Cell_handle ch= Tri.locate ( CGT::Point ( wdCenter[0],wdCenter[1],wdCenter[2] )
-// ,/*hint*/ v0
- );
- base_info.period[0]=period[0];
- base_info.period[1]=period[1];
- base_info.period[2]=period[2];
- //call recursively, since the returned cell could be also a ghost (especially if baseCell is a non-periodic type from the external contour
- locateCell ( ch,index,baseIndex,flow,++count );
- if ( ch==baseCell ) cerr<<"WTF!!"<<endl;
- //check consistency
- bool checkC=false;
- for (int kk=0; kk<4;kk++) if ((!baseCell->vertex(kk)->info().isGhost) && ((!baseCell->vertex(kk)->info().isFictious))) checkC = true;
- if (checkC) {
- bool checkV=true;
- for (int kk=0; kk<4;kk++) {
- checkV=false;
- for (int jj=0; jj<4;jj++)
- if (baseCell->vertex(kk)->info().id() == ch->vertex(jj)->info().id()) checkV = true;
- if (!checkV) {cerr <<"periodicity is broken"<<endl;
- for (int jj=0; jj<4;jj++) cerr<<baseCell->vertex(jj)->info().id()<<" ";
- cerr<<" vs. ";
- for (int jj=0; jj<4;jj++) cerr<<ch->vertex(jj)->info().id()<<" ";
- cerr<<endl;}
- }
- } else {
-// bool checkV=true;
-// for (int kk=0; kk<4;kk++) {
-// checkV=false;
-// for (int jj=0; jj<4;jj++)
-// if (baseCell->vertex(kk)->info().id() == ch->vertex(jj)->info().id()) checkV = true;
-// if (!checkV) {cerr <<"periodicity is broken (that's ok probably)"<<endl;
-// for (int jj=0; jj<4;jj++) cerr<<baseCell->vertex(jj)->info().id()<<" ";
-// cerr<<" vs. ";
-// for (int jj=0; jj<4;jj++) cerr<<ch->vertex(jj)->info().id()<<" ";
-// cerr<<endl;}
-// }
- }
-
- base_info.isGhost=true;
- base_info._pression=& ( ch->info().p() );
- base_info.index=ch->info().index;
- base_info.baseIndex=ch->info().baseIndex;
- base_info.Pcondition=ch->info().Pcondition;
- } else {
- base_info.isGhost=false;
- //index is 1-based, if it is zero it is not initialized, we define it here
- if ( base_info.baseIndex<0 ){
- base_info.baseIndex=++baseIndex;
- if (!base_info.Pcondition) base_info.index=++index;}
- }
-}
-
-Vector3r PeriodicFlowEngine::meanVelocity()
-{
- solver->Average_Relative_Cell_Velocity();
- Vector3r meanVel ( 0,0,0 );
- Real volume=0;
- Finite_cells_iterator cell_end = solver->T[solver->currentTes].Triangulation().finite_cells_end();
- for ( Finite_cells_iterator cell = solver->T[solver->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ) {
- //We could also define velocity using cell's center
-// if ( !cell->info().isReal() ) continue;
- if ( cell->info().isGhost ) continue;
- for ( int i=0;i<3;i++ )
- meanVel[i]=meanVel[i]+ ( ( cell->info().av_vel() ) [i] * abs ( cell->info().volume() ) );
- volume+=abs ( cell->info().volume() );
- }
- return ( meanVel/volume );
-}
-
-void PeriodicFlowEngine::UpdateVolumes (shared_ptr<FlowSolver>& flow)
-{
- if ( Debug ) cout << "Updating volumes.............." << endl;
- Real invDeltaT = 1/scene->dt;
- double newVol, dVol;
- eps_vol_max=0;
- Real totVol=0;
- Real totDVol=0;
- Real totVol0=0;
- Real totVol1=0;
-
- FOREACH(Cell_handle& cell, flow->T[flow->currentTes].cellHandles){
- switch ( cell->info().fictious() ) {
- case ( 1 ) :
- newVol = Volume_cell_single_fictious ( cell );
- totVol1+=newVol;
- break;
- case ( 0 ) :
- newVol = Volume_cell ( cell );
- totVol0+=newVol;
- break;
- default:
- newVol = 0;
- break;
- }
- totVol+=newVol;
- dVol=cell->info().volumeSign * ( newVol - cell->info().volume() );
- totDVol+=dVol;
- eps_vol_max = max ( eps_vol_max, abs ( dVol/newVol ) );
- cell->info().dv() = dVol * invDeltaT;
- cell->info().volume() = newVol;
- }
- if ( Debug ) cout << "Updated volumes, total =" <<totVol<<", dVol="<<totDVol<<" "<< totVol0<<" "<< totVol1<<endl;
-}
-
-
-void PeriodicFlowEngine::Initialize_volumes (shared_ptr<FlowSolver>& flow)
-{
- Finite_vertices_iterator vertices_end = flow->T[flow->currentTes].Triangulation().finite_vertices_end();
- CGT::Vecteur Zero ( 0,0,0 );
- for ( Finite_vertices_iterator V_it = flow->T[flow->currentTes].Triangulation().finite_vertices_begin(); V_it!= vertices_end; V_it++ ) V_it->info().forces=Zero;
-
- FOREACH(Cell_handle& cell, flow->T[flow->currentTes].cellHandles){
- switch ( cell->info().fictious() )
- {
- case ( 0 ) : cell->info().volume() = Volume_cell ( cell ); break;
- case ( 1 ) : cell->info().volume() = Volume_cell_single_fictious ( cell ); break;
-// case ( 2 ) : cell->info().volume() = Volume_cell_double_fictious ( cell ); break;
-// case ( 3 ) : cell->info().volume() = Volume_cell_triple_fictious ( cell ); break;
- default: cell->info().volume() = 0; break;
- }
- //FIXME: the void volume is negative sometimes, hence crashing...
- if (flow->fluidBulkModulus>0) { cell->info().invVoidVolume() = 1. / (max(0.1*cell->info().volume(),abs(cell->info().volume()) - flow->volumeSolidPore(cell)) ); }
- }
- if ( Debug ) cout << "Volumes initialised." << endl;
-}
-
-void PeriodicFlowEngine::Build_Triangulation ( double P_zero, shared_ptr<FlowSolver>& flow)
-{
- flow->ResetNetwork();
- if (first) flow->currentTes=0;
- else {
- flow->currentTes=!flow->currentTes;
- if ( Debug ) cout << "--------RETRIANGULATION-----------" << endl;}
- initSolver(flow);
- AddBoundary ( flow );
- if ( Debug ) cout << endl << "Added boundaries------" << endl << endl;
- Triangulate (flow);
- if ( Debug ) cout << endl << "Tesselating------" << endl << endl;
- flow->T[flow->currentTes].Compute();
- flow->Define_fictious_cells();
-
- //FIXME: this is already done in addBoundary(?)
- BoundaryConditions ( flow );
- if ( Debug ) cout << endl << "BoundaryConditions------" << endl << endl;
- flow->Initialize_pressures ( P_zero );
- if ( Debug ) cout << endl << "Initialize_pressures------" << endl << endl;
- // Define the ghost cells and add indexes to the cells inside the period (the ones that will contain the pressure unknowns)
- //This must be done after boundary conditions and initialize pressure, else the indexes are not good (not accounting imposedP): FIXME
- unsigned int index=0;
- int baseIndex=-1;
- FlowSolver::Tesselation& Tes = flow->T[flow->currentTes];
- Tes.cellHandles.resize(Tes.Triangulation().number_of_finite_cells());
- const Finite_cells_iterator cellend=Tes.Triangulation().finite_cells_end();
- for ( Finite_cells_iterator cell=Tes.Triangulation().finite_cells_begin(); cell!=cellend; cell++ ){
-// if (cell->vertex(0)->info().isGhost && cell->vertex(1)->info().isGhost && cell->vertex(2)->info().isGhost && cell->vertex(3)->info().isGhost) { cell->info().isGhost=true; continue;} //crash, why?
- locateCell ( cell,index,baseIndex,flow );
- if (flow->errorCode>0) return;
- //Fill this vector than can be later used to speedup loops
- if (!cell->info().isGhost) Tes.cellHandles[cell->info().baseIndex]=cell;
- }
- Tes.cellHandles.resize(baseIndex+1);
-
- if ( Debug ) cout << endl << "locateCell------" << endl << endl;
- flow->Compute_Permeability ( );
- porosity = flow->V_porale_porosity/flow->V_totale_porosity;
- flow->TOLERANCE=Tolerance;flow->RELAX=Relax;
-
- flow->DisplayStatistics ();
- //FIXME: check interpolate() for the periodic case, at least use the mean pressure from previous step.
- if ( !first && !multithread && (useSolver==0 || fluidBulkModulus>0)) flow->Interpolate ( flow->T[!flow->currentTes], Tes );
-// if ( !first && (useSolver==0 || fluidBulkModulus>0)) flow->Interpolate ( flow->T[!flow->currentTes], flow->T[flow->currentTes] );
-
- if ( WaveAction ) flow->ApplySinusoidalPressure ( Tes.Triangulation(), sineMagnitude, sineAverage, 30 );
-
- if (normalLubrication || shearLubrication || viscousShear) flow->computeEdgesSurfaces();
- if ( Debug ) cout << endl << "end buildTri------" << endl << endl;
-}
-
-void PeriodicFlowEngine::preparePShifts()
-{
- CGT::PeriodicCellInfo::gradP = makeCgVect ( gradP );
- CGT::PeriodicCellInfo::hSize[0] = makeCgVect ( scene->cell->hSize.col ( 0 ) );
- CGT::PeriodicCellInfo::hSize[1] = makeCgVect ( scene->cell->hSize.col ( 1 ) );
- CGT::PeriodicCellInfo::hSize[2] = makeCgVect ( scene->cell->hSize.col ( 2 ) );
- CGT::PeriodicCellInfo::deltaP=CGT::Vecteur (
- CGT::PeriodicCellInfo::hSize[0]*CGT::PeriodicCellInfo::gradP,
- CGT::PeriodicCellInfo::hSize[1]*CGT::PeriodicCellInfo::gradP,
- CGT::PeriodicCellInfo::hSize[2]*CGT::PeriodicCellInfo::gradP );
-}
-
-
-YADE_PLUGIN((PeriodicFlowEngine));
-
-#endif //FLOW_ENGINE
-
-#endif /* YADE_CGAL */
-
=== removed file 'pkg/dem/FlowEngine.hpp'
--- pkg/dem/FlowEngine.hpp 2014-02-03 16:10:48 +0000
+++ pkg/dem/FlowEngine.hpp 1970-01-01 00:00:00 +0000
@@ -1,488 +0,0 @@
-/*************************************************************************
-* Copyright (C) 2009 by Emanuele Catalano <catalano@xxxxxxxxxxxxxxx> *
-* Copyright (C) 2009 by Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> *
-* Copyright (C) 2012 by Donia Marzougui <donia.marzougui@xxxxxxxxxxxxxxx>*
-* *
-* 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. *
-*************************************************************************/
-#pragma once
-#include<yade/core/PartialEngine.hpp>
-#include<yade/pkg/dem/TriaxialCompressionEngine.hpp>
-#include<yade/pkg/dem/TesselationWrapper.hpp>
-#include<yade/lib/triangulation/FlowBoundingSphere.hpp>
-#include<yade/lib/triangulation/PeriodicFlow.hpp>
-
-class Flow;
-class TesselationWrapper;
-#ifdef LINSOLV
-#define _FlowSolver CGT::FlowBoundingSphereLinSolv<CGT::FlowBoundingSphere<FlowTesselation> >
-#else
-#define _FlowSolver CGT::FlowBoundingSphere<FlowTesselation>
-#endif
-
-#define TPL template<class Solver>
-
-
-class FlowEngine : public PartialEngine
-{
- public :
- typedef _FlowSolver FlowSolver;
- typedef FlowTesselation Tesselation;
- typedef FlowSolver::RTriangulation RTriangulation;
- typedef FlowSolver::Finite_vertices_iterator Finite_vertices_iterator;
- typedef FlowSolver::Finite_cells_iterator Finite_cells_iterator;
- typedef FlowSolver::Cell_handle Cell_handle;
- typedef RTriangulation::Finite_edges_iterator Finite_edges_iterator;
- typedef FlowSolver::Vertex_handle Vertex_handle;
-
-
-
- protected:
- shared_ptr<FlowSolver> solver;
- shared_ptr<FlowSolver> backgroundSolver;
- volatile bool backgroundCompleted;
- Cell cachedCell;
- struct posData {Body::id_t id; Vector3r pos; Real radius; bool isSphere; bool exists; posData(){exists=0;}};
- vector<posData> positionBufferCurrent;//reflect last known positions before we start computations
- vector<posData> positionBufferParallel;//keep the positions from a given step for multithread factorization
- //copy positions in a buffer for faster and/or parallel access
- void setPositionsBuffer(bool current);
-
- public :
- int retriangulationLastIter;
- enum {wall_xmin, wall_xmax, wall_ymin, wall_ymax, wall_zmin, wall_zmax};
- Vector3r normal [6];
- bool currentTes;
- int id_offset;
- double Eps_Vol_Cumulative;
- int ReTrg;
- int ellapsedIter;
- TPL void initSolver (Solver& flow);
- #ifdef LINSOLV
- TPL void setForceMetis (Solver& flow, bool force);
- TPL bool getForceMetis (Solver& flow);
- #endif
- TPL void Triangulate (Solver& flow);
- TPL void AddBoundary (Solver& flow);
- TPL void Build_Triangulation (double P_zero, Solver& flow);
- TPL void Build_Triangulation (Solver& flow);
- TPL void UpdateVolumes (Solver& flow);
- TPL void Initialize_volumes (Solver& flow);
- TPL void BoundaryConditions(Solver& flow);
- TPL void updateBCs ( Solver& flow ) {
- if (flow->T[flow->currentTes].max_id>0) BoundaryConditions(flow);//avoids crash at iteration 0, when the packing is not bounded yet
- else LOG_ERROR("updateBCs not applied");
- flow->pressureChanged=true;}
-
- TPL void imposeFlux(Vector3r pos, Real flux,Solver& flow);
- TPL unsigned int imposePressure(Vector3r pos, Real p,Solver& flow);
- TPL void setImposedPressure(unsigned int cond, Real p,Solver& flow);
- TPL void clearImposedPressure(Solver& flow);
- TPL void clearImposedFlux(Solver& flow);
- TPL void ComputeViscousForces(Solver& flow);
- TPL Real getCellFlux(unsigned int cond, const shared_ptr<Solver>& flow);
- TPL Real getBoundaryFlux(unsigned int boundary,Solver& flow) {return flow->boundaryFlux(boundary);}
- TPL Vector3r fluidForce(unsigned int id_sph, Solver& flow) {
- const CGT::Vecteur& f=flow->T[flow->currentTes].vertex(id_sph)->info().forces; return Vector3r(f[0],f[1],f[2]);}
- TPL Vector3r shearLubForce(unsigned int id_sph, Solver& flow) {
- return (flow->viscousShearForces.size()>id_sph)?flow->viscousShearForces[id_sph]:Vector3r::Zero();}
- TPL Vector3r shearLubTorque(unsigned int id_sph, Solver& flow) {
- return (flow->viscousShearTorques.size()>id_sph)?flow->viscousShearTorques[id_sph]:Vector3r::Zero();}
- TPL Vector3r normalLubForce(unsigned int id_sph, Solver& flow) {
- return (flow->normLubForce.size()>id_sph)?flow->normLubForce[id_sph]:Vector3r::Zero();}
- TPL Matrix3r bodyShearLubStress(unsigned int id_sph, Solver& flow) {
- return (flow->viscousBodyStress.size()>id_sph)?flow->viscousBodyStress[id_sph]:Matrix3r::Zero();}
- TPL Matrix3r bodyNormalLubStress(unsigned int id_sph, Solver& flow) {
- return (flow->lubBodyStress.size()>id_sph)?flow->lubBodyStress[id_sph]:Matrix3r::Zero();}
- TPL Vector3r shearVelocity(unsigned int interaction, Solver& flow) {
- return (flow->deltaShearVel[interaction]);}
- TPL Vector3r normalVelocity(unsigned int interaction, Solver& flow) {
- return (flow->deltaNormVel[interaction]);}
- TPL Matrix3r normalStressInteraction(unsigned int interaction, Solver& flow) {
- return (flow->normalStressInteraction[interaction]);}
- TPL Matrix3r shearStressInteraction(unsigned int interaction, Solver& flow) {
- return (flow->shearStressInteraction[interaction]);}
- TPL Vector3r normalVect(unsigned int interaction, Solver& flow) {
- return (flow->normalV[interaction]);}
- TPL Real surfaceDistanceParticle(unsigned int interaction, Solver& flow) {
- return (flow->surfaceDistance[interaction]);}
- TPL Real edgeSize(Solver& flow) {
- return (flow->Edge_ids.size());}
- TPL Real OSI(Solver& flow) {
- return (flow->onlySpheresInteractions.size());}
- TPL int onlySpheresInteractions(unsigned int interaction, Solver& flow) {
- return (flow->onlySpheresInteractions[interaction]);}
- TPL python::list getConstrictions(bool all, Solver& flow) {
- vector<Real> csd=flow->getConstrictions(); python::list pycsd;
- for (unsigned int k=0;k<csd.size();k++) if ((all && csd[k]!=0) || csd[k]>0) pycsd.append(csd[k]); return pycsd;}
- TPL python::list getConstrictionsFull(bool all, Solver& flow) {
- vector<Constriction> csd=flow->getConstrictionsFull(); python::list pycsd;
- for (unsigned int k=0;k<csd.size();k++) if ((all && csd[k].second[0]!=0) || csd[k].second[0]>0) {
- python::list cons;
- cons.append(csd[k].first.first);
- cons.append(csd[k].first.second);
- cons.append(csd[k].second[0]);
- cons.append(csd[k].second[1]);
- cons.append(csd[k].second[2]);
- cons.append(csd[k].second[3]);
- pycsd.append(cons);}
- return pycsd;}
-
- template<class Cellhandle>
- Real Volume_cell_single_fictious (Cellhandle cell);
- template<class Cellhandle>
- Real Volume_cell_double_fictious (Cellhandle cell);
- template<class Cellhandle>
- Real Volume_cell_triple_fictious (Cellhandle cell);
- template<class Cellhandle>
- Real Volume_cell (Cellhandle cell);
- void Oedometer_Boundary_Conditions();
- void Average_real_cell_velocity();
- void saveVtk(const char* folder) {solver->saveVtk(folder);}
- vector<Real> avFlVelOnSph(unsigned int id_sph) {return solver->Average_Fluid_Velocity_On_Sphere(id_sph);}
-
-// void setBoundaryVel(Vector3r vel) {topBoundaryVelocity=vel; updateTriangulation=true;}
- void pressureProfile(double wallUpY, double wallDownY) {return solver->measurePressureProfile(wallUpY,wallDownY);}
- double getPorePressure(Vector3r pos){return solver->getPorePressure(pos[0], pos[1], pos[2]);}
- TPL int getCell(double posX, double posY, double posZ, Solver& flow){return flow->getCell(posX, posY, posZ);}
- TPL unsigned int nCells(Solver& flow){return flow->T[flow->currentTes].cellHandles.size();}
- TPL python::list getVertices(unsigned int id, Solver& flow){
- python::list ids;
- if (id>=flow->T[flow->currentTes].cellHandles.size()) {LOG_ERROR("id out of range, max value is "<<flow->T[flow->currentTes].cellHandles.size()); return ids;}
- for (unsigned int i=0;i<4;i++) ids.append(flow->T[flow->currentTes].cellHandles[id]->vertex(i)->info().id());
- return ids;
- }
- double averageSlicePressure(double posY){return solver->averageSlicePressure(posY);}
- double averagePressure(){return solver->averagePressure();}
- #ifdef LINSOLV
- TPL void exportMatrix(string filename,Solver& flow) {if (useSolver==3) flow->exportMatrix(filename.c_str());
- else cerr<<"available for Cholmod solver (useSolver==3)"<<endl;}
- TPL void exportTriplets(string filename,Solver& flow) {if (useSolver==3) flow->exportTriplets(filename.c_str());
- else cerr<<"available for Cholmod solver (useSolver==3)"<<endl;}
- #endif
-
- void emulateAction(){
- scene = Omega::instance().getScene().get();
- action();}
- //Instanciation of templates for python binding
- Vector3r _shearLubForce(unsigned int id_sph) {return shearLubForce(id_sph,solver);}
- Vector3r _shearLubTorque(unsigned int id_sph) {return shearLubTorque(id_sph,solver);}
- Vector3r _normalLubForce(unsigned int id_sph) {return normalLubForce(id_sph,solver);}
- Matrix3r _bodyShearLubStress(unsigned int id_sph) {return bodyShearLubStress(id_sph,solver);}
- Matrix3r _bodyNormalLubStress(unsigned int id_sph) {return bodyNormalLubStress(id_sph,solver);}
- Vector3r _fluidForce(unsigned int id_sph) {return fluidForce(id_sph,solver);}
- Vector3r _shearVelocity(unsigned int interaction) {return shearVelocity(interaction,solver);}
- Vector3r _normalVelocity(unsigned int interaction) {return normalVelocity(interaction,solver);}
- Matrix3r _normalStressInteraction(unsigned int interaction) {return normalStressInteraction(interaction,solver);}
- Matrix3r _shearStressInteraction(unsigned int interaction) {return shearStressInteraction(interaction,solver);}
- Vector3r _normalVect(unsigned int interaction) {return normalVect(interaction,solver);}
- Real _surfaceDistanceParticle(unsigned int interaction) {return surfaceDistanceParticle(interaction,solver);}
- int _onlySpheresInteractions(unsigned int interaction) {return onlySpheresInteractions(interaction,solver);}
- void _imposeFlux(Vector3r pos, Real flux) {return imposeFlux(pos,flux,*solver);}
- unsigned int _imposePressure(Vector3r pos, Real p) {return imposePressure(pos,p,solver);}
- void _setImposedPressure(unsigned int cond, Real p) {setImposedPressure(cond,p,solver);}
- void _clearImposedPressure() {clearImposedPressure(solver);}
- void _clearImposedFlux() {clearImposedFlux(solver);}
- void _updateBCs() {updateBCs(solver);}
- Real _getCellFlux(unsigned int cond) {return getCellFlux(cond,solver);}
- Real _getBoundaryFlux(unsigned int boundary) {return getBoundaryFlux(boundary,solver);}
- int _getCell(Vector3r pos) {return getCell(pos[0],pos[1],pos[2],solver);}
- unsigned int _nCells() {return nCells(solver);}
- python::list _getVertices(unsigned int id) {return getVertices(id,solver);}
- #ifdef LINSOLV
- void _exportMatrix(string filename) {exportMatrix(filename,solver);}
- void _exportTriplets(string filename) {exportTriplets(filename,solver);}
- void _setForceMetis (bool force) {setForceMetis(solver,force);}
- bool _getForceMetis () {return getForceMetis (solver);}
- void cholmodStats() {
- cerr << cholmod_print_common("PFV Cholmod factorization",&(solver->eSolver.cholmod()))<<endl;
- cerr << "cholmod method:" << solver->eSolver.cholmod().selected<<endl;
- cerr << "METIS called:"<<solver->eSolver.cholmod().called_nd<<endl;}
- bool metisUsed() {return bool(solver->eSolver.cholmod().called_nd);}
- #endif
- python::list _getConstrictions(bool all) {return getConstrictions(all,solver);}
- python::list _getConstrictionsFull(bool all) {return getConstrictionsFull(all,solver);}
-
- virtual ~FlowEngine();
-
- virtual void action();
- virtual void backgroundAction();
-
- YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(FlowEngine,PartialEngine,"An engine to solve flow problem in saturated granular media. Model description can be found in [Chareyre2012a]_ and [Catalano2013a]_. 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.",
- ((bool,isActivated,true,,"Activates Flow Engine"))
- ((bool,first,true,,"Controls the initialization/update phases"))
- ((double, fluidBulkModulus, 0.,,"Bulk modulus of fluid (inverse of compressibility) K=-dP*V/dV [Pa]. Flow is compressible if fluidBulkModulus > 0, else incompressible."))
- ((Real, dt, 0,,"timestep [s]"))
- ((bool,permeability_map,false,,"Enable/disable stocking of average permeability scalar in cell infos."))
- ((bool, slip_boundary, true,, "Controls friction condition on lateral walls"))
- ((bool,WaveAction, false,, "Allow sinusoidal pressure condition to simulate ocean waves"))
- ((double, sineMagnitude, 0,, "Pressure value (amplitude) when sinusoidal pressure is applied (p )"))
- ((double, sineAverage, 0,,"Pressure value (average) when sinusoidal pressure is applied"))
- ((bool, Debug, false,,"Activate debug messages"))
- ((double, wall_thickness,0.001,,"Walls thickness"))
- ((double,P_zero,0,,"The value used for initializing pore pressure. It is useless for incompressible fluid, but important for compressible model."))
- ((double,Tolerance,1e-06,,"Gauss-Seidel Tolerance"))
- ((double,Relax,1.9,,"Gauss-Seidel relaxation"))
- ((bool, updateTriangulation, 0,,"If true the medium is retriangulated. Can be switched on to force retriangulation after some events (else it will be true periodicaly based on :yref:`FlowEngine::defTolerance` and :yref:`FlowEngine::meshUpdateInterval`. Of course, it costs CPU time."))
- ((int,meshUpdateInterval,1000,,"Maximum number of timesteps between re-triangulation events. See also :yref:`FlowEngine::defTolerance`."))
- ((double, eps_vol_max, 0,(Attr::readonly),"Maximal absolute volumetric strain computed at each iteration. |yupdate|"))
- ((double, defTolerance,0.05,,"Cumulated deformation threshold for which retriangulation of pore space is performed. If negative, the triangulation update will occure with a fixed frequency on the basis of :yref:`FlowEngine::meshUpdateInterval`"))
- ((double, porosity, 0,(Attr::readonly),"Porosity computed at each retriangulation |yupdate|"))
- ((bool,meanKStat,false,,"report the local permeabilities' correction"))
- ((bool,clampKValues,true,,"If true, clamp local permeabilities in [minKdivKmean,maxKdivKmean]*globalK. This clamping can avoid singular values in the permeability matrix and may reduce numerical errors in the solve phase. It will also hide junk values if they exist, or bias all values in very heterogeneous problems. So, use this with care."))
- ((Real,minKdivKmean,0.0001,,"define the min K value (see :yref:`FlowEngine::clampKValues`)"))
- ((Real,maxKdivKmean,100,,"define the max K value (see :yref:`FlowEngine::clampKValues`)"))
- ((double,permeabilityFactor,1.0,,"permability multiplier"))
- ((double,viscosity,1.0,,"viscosity of the fluid"))
- ((double,stiffness, 10000,,"equivalent contact stiffness used in the lubrication model"))
- ((int, useSolver, 0,, "Solver to use 0=G-Seidel, 1=Taucs, 2-Pardiso, 3-CHOLMOD"))
- ((int, xmin,0,(Attr::readonly),"Index of the boundary $x_{min}$. This index is not equal the the id of the corresponding body in general, it may be used to access the corresponding attributes (e.g. flow.bndCondValue[flow.xmin], flow.wallId[flow.xmin],...)."))
- ((int, xmax,1,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
- ((int, ymin,2,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
- ((int, ymax,3,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
- ((int, zmin,4,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
- ((int, zmax,5,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
-
- ((vector<bool>, bndCondIsPressure, vector<bool>(6,false),,"defines the type of boundary condition for each side. True if pressure is imposed, False for no-flux. Indexes can be retrieved with :yref:`FlowEngine::xmin` and friends."))
- ((vector<double>, bndCondValue, vector<double>(6,0),,"Imposed value of a boundary condition. Only applies if the boundary condition is imposed pressure, else the imposed flux is always zero presently (may be generalized to non-zero imposed fluxes in the future)."))
- //FIXME: to be implemented:
- ((vector<Vector3r>, boundaryVelocity, vector<Vector3r>(6,Vector3r::Zero()),, "velocity on top boundary, only change it using :yref:`FlowEngine::setBoundaryVel`"))
- ((int, ignoredBody,-1,,"Id of a sphere to exclude from the triangulation.)"))
- ((vector<int>, wallIds,vector<int>(6),,"body ids of the boundaries (default values are ok only if aabbWalls are appended before spheres, i.e. numbered 0,...,5)"))
- ((vector<bool>, boundaryUseMaxMin, vector<bool>(6,true),,"If true (default value) bounding sphere is added as function of max/min sphere coord, if false as function of yade wall position"))
- ((bool, display_force, false,,"display the lubrication force applied on particles"))
- ((bool, create_file, false,,"create file of velocities"))
- ((bool, viscousShear, false,,"Compute viscous shear terms as developped by Donia Marzougui (FIXME: ref.)"))
- ((bool, shearLubrication, false,,"Compute shear lubrication force as developped by Brule (FIXME: ref.) "))
- ((double, eps, 0.00001,,"roughness defined as a fraction of particles size, giving the minimum distance between particles in the lubrication model."))
- ((bool, pressureForce, true,,"Compute the pressure field and associated fluid forces. WARNING: turning off means fluid flow is not computed at all."))
- ((bool, normalLubrication, false,,"Compute normal lubrication force as developped by Brule"))
- ((bool, viscousNormalBodyStress, false,,"Compute normal viscous stress applied on each body"))
- ((bool, viscousShearBodyStress, false,,"Compute shear viscous stress applied on each body"))
- ((bool, multithread, false,,"Build triangulation and factorize in the background (multi-thread mode)"))
- #ifdef EIGENSPARSE_LIB
- ((int, numSolveThreads, 1,,"number of openblas threads in the solve phase."))
- ((int, numFactorizeThreads, 1,,"number of openblas threads in the factorization phase"))
-// ((bool, forceMetis, 0,,"If true, METIS is used for matrix preconditioning, else Cholmod is free to choose the best method (which may be METIS to, depending on the matrix). See ``nmethods`` in Cholmod documentation"))
- #endif
- ,
- /*deprec*/
- ((meanK_opt,clampKValues,"the name changed"))
- ,,
- timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas);
- for (int i=0; i<6; ++i){normal[i]=Vector3r::Zero(); wallIds[i]=i;}
- normal[wall_ymin].y()=normal[wall_xmin].x()=normal[wall_zmin].z()=1;
- normal[wall_ymax].y()=normal[wall_xmax].x()=normal[wall_zmax].z()=-1;
- solver = shared_ptr<FlowSolver> (new FlowSolver);
- first=true;
- eps_vol_max=Eps_Vol_Cumulative=retriangulationLastIter=0;
- ReTrg=1;
- backgroundCompleted=true;
- ellapsedIter=0;
- ,
- .def("imposeFlux",&FlowEngine::_imposeFlux,(python::arg("pos"),python::arg("p")),"Impose incoming flux in boundary cell of location 'pos'.")
- .def("imposePressure",&FlowEngine::_imposePressure,(python::arg("pos"),python::arg("p")),"Impose pressure in cell of location 'pos'. The index of the condition is returned (for multiple imposed pressures at different points).")
- .def("setImposedPressure",&FlowEngine::_setImposedPressure,(python::arg("cond"),python::arg("p")),"Set pressure value at the point indexed 'cond'.")
- .def("clearImposedPressure",&FlowEngine::_clearImposedPressure,"Clear the list of points with pressure imposed.")
- .def("clearImposedFlux",&FlowEngine::_clearImposedFlux,"Clear the list of points with flux imposed.")
- .def("getCellFlux",&FlowEngine::_getCellFlux,(python::arg("cond")),"Get influx in cell associated to an imposed P (indexed using 'cond').")
- .def("getBoundaryFlux",&FlowEngine::_getBoundaryFlux,(python::arg("boundary")),"Get total flux through boundary defined by its body id.\n\n.. note:: The flux may be not zero even for no-flow condition. This artifact comes from cells which are incident to two or more boundaries (along the edges of the sample, typically). Such flux evaluation on impermeable boundary is just irrelevant, it does not imply that the boundary condition is not applied properly.")
- .def("getConstrictions",&FlowEngine::_getConstrictions,(python::arg("all")=true),"Get the list of constriction radii (inscribed circle) for all finite facets (if all==True) or all facets not incident to a virtual bounding sphere (if all==False). When all facets are returned, negative radii denote facet incident to one or more fictious spheres.")
- .def("getConstrictionsFull",&FlowEngine::_getConstrictionsFull,(python::arg("all")=true),"Get the list of constrictions (inscribed circle) for all finite facets (if all==True), or all facets not incident to a fictious bounding sphere (if all==False). When all facets are returned, negative radii denote facet incident to one or more fictious spheres. The constrictions are returned in the format {{cell1,cell2}{rad,nx,ny,nz}}")
- .def("saveVtk",&FlowEngine::saveVtk,(python::arg("folder")="./VTK"),"Save pressure field in vtk format. Specify a folder name for output.")
- .def("avFlVelOnSph",&FlowEngine::avFlVelOnSph,(python::arg("Id_sph")),"Compute a sphere-centered average fluid velocity")
- .def("fluidForce",&FlowEngine::_fluidForce,(python::arg("Id_sph")),"Return the fluid force on sphere Id_sph.")
- .def("shearLubForce",&FlowEngine::_shearLubForce,(python::arg("Id_sph")),"Return the shear lubrication force on sphere Id_sph.")
- .def("shearLubTorque",&FlowEngine::_shearLubTorque,(python::arg("Id_sph")),"Return the shear lubrication torque on sphere Id_sph.")
- .def("normalLubForce",&FlowEngine::_normalLubForce,(python::arg("Id_sph")),"Return the normal lubrication force on sphere Id_sph.")
- .def("bodyShearLubStress",&FlowEngine::_bodyShearLubStress,(python::arg("Id_sph")),"Return the shear lubrication stress on sphere Id_sph.")
- .def("bodyNormalLubStress",&FlowEngine::_bodyNormalLubStress,(python::arg("Id_sph")),"Return the normal lubrication stress on sphere Id_sph.")
- .def("shearVelocity",&FlowEngine::_shearVelocity,(python::arg("id_sph")),"Return the shear velocity of the interaction.")
- .def("normalVelocity",&FlowEngine::_normalVelocity,(python::arg("id_sph")),"Return the normal velocity of the interaction.")
- .def("normalVect",&FlowEngine::_normalVect,(python::arg("id_sph")),"Return the normal vector between particles.")
- .def("surfaceDistanceParticle",&FlowEngine::_surfaceDistanceParticle,(python::arg("interaction")),"Return the distance between particles.")
- .def("onlySpheresInteractions",&FlowEngine::_onlySpheresInteractions,(python::arg("interaction")),"Return the id of the interaction only between spheres.")
-
-
- .def("pressureProfile",&FlowEngine::pressureProfile,(python::arg("wallUpY"),python::arg("wallDownY")),"Measure pore pressure in 6 equally-spaced points along the height of the sample")
- .def("getPorePressure",&FlowEngine::getPorePressure,(python::arg("pos")),"Measure pore pressure in position pos[0],pos[1],pos[2]")
- .def("averageSlicePressure",&FlowEngine::averageSlicePressure,(python::arg("posY")),"Measure slice-averaged pore pressure at height posY")
- .def("averagePressure",&FlowEngine::averagePressure,"Measure averaged pore pressure in the entire volume")
- .def("updateBCs",&FlowEngine::_updateBCs,"tells the engine to update it's boundary conditions before running (especially useful when changing boundary pressure - should not be needed for point-wise imposed pressure)")
- .def("emulateAction",&FlowEngine::emulateAction,"get scene and run action (may be used to manipulate an engine outside the timestepping loop).")
- .def("getCell",&FlowEngine::_getCell,(python::arg("pos")),"get id of the cell containing (X,Y,Z).")
- .def("nCells",&FlowEngine::_nCells,"get the total number of finite cells in the triangulation.")
- .def("getVertices",&FlowEngine::_getVertices,(python::arg("id")),"get the vertices of a cell")
- #ifdef LINSOLV
- .def("exportMatrix",&FlowEngine::_exportMatrix,(python::arg("filename")="matrix"),"Export system matrix to a file with all entries (even zeros will displayed).")
- .def("exportTriplets",&FlowEngine::_exportTriplets,(python::arg("filename")="triplets"),"Export system matrix to a file with only non-zero entries.")
- .def("cholmodStats",&FlowEngine::cholmodStats,"get statistics of cholmod solver activity")
- .def("metisUsed",&FlowEngine::metisUsed,"check wether metis lib is effectively used")
- .add_property("forceMetis",&FlowEngine::_getForceMetis,&FlowEngine::_setForceMetis,"If true, METIS is used for matrix preconditioning, else Cholmod is free to choose the best method (which may be METIS to, depending on the matrix). See ``nmethods`` in Cholmod documentation")
- #endif
- )
- DECLARE_LOGGER;
-};
-
-
-template<class Solver>
-unsigned int FlowEngine::imposePressure(Vector3r pos, Real p,Solver& flow)
-{
- if (!flow) LOG_ERROR("no flow defined yet, run at least one iter");
- flow->imposedP.push_back( pair<CGT::Point,Real>(CGT::Point(pos[0],pos[1],pos[2]),p) );
- //force immediate update of boundary conditions
- updateTriangulation=true;
- return flow->imposedP.size()-1;
-}
-
-
-
-REGISTER_SERIALIZABLE(FlowEngine);
-
-#ifdef LINSOLV
-#define _PeriFlowSolver CGT::PeriodicFlowLinSolv
-#else
-#define _PeriFlowSolver CGT::PeriodicFlow
-#endif
-
-class PeriodicFlowEngine : public FlowEngine
-{
- public :
- public :
- typedef _PeriFlowSolver FlowSolver;
- typedef PeriFlowTesselation Tesselation;
- typedef FlowSolver::RTriangulation RTriangulation;
- typedef FlowSolver::Finite_vertices_iterator Finite_vertices_iterator;
- typedef FlowSolver::Finite_cells_iterator Finite_cells_iterator;
- typedef FlowSolver::Cell_handle Cell_handle;
- typedef RTriangulation::Finite_edges_iterator Finite_edges_iterator;
- typedef RTriangulation::Vertex_handle Vertex_handle;
-
- shared_ptr<FlowSolver> solver;
- shared_ptr<FlowSolver> backgroundSolver;
-
- void Triangulate (shared_ptr<FlowSolver>& flow);
-// void AddBoundary ();
- void Build_Triangulation (Real pzero, shared_ptr<FlowSolver>& flow);
- void Initialize_volumes (shared_ptr<FlowSolver>& flow);
- void UpdateVolumes (shared_ptr<FlowSolver>& flow);
- Real Volume_cell (Cell_handle cell);
-
- Real Volume_cell_single_fictious (Cell_handle cell);
- inline void locateCell(Cell_handle baseCell, unsigned int& index, int& baseIndex, shared_ptr<FlowSolver>& flow, unsigned int count=0);
- Vector3r meanVelocity();
-
- virtual ~PeriodicFlowEngine();
-
- virtual void action();
- void backgroundAction();
- //Cache precomputed values for pressure shifts, based on current hSize and pGrad
- void preparePShifts();
-
- //(re)instanciation of templates and others, for python binding
- void saveVtk(const char* folder) {solver->saveVtk(folder);}
- Vector3r _shearLubForce(unsigned int id_sph) {return shearLubForce(id_sph,solver);}
- Vector3r _shearLubTorque(unsigned int id_sph) {return shearLubTorque(id_sph,solver);}
- Vector3r _normalLubForce(unsigned int id_sph) {return normalLubForce(id_sph,solver);}
- Matrix3r _bodyShearLubStress(unsigned int id_sph) {return bodyShearLubStress(id_sph,solver);}
- Matrix3r _bodyNormalLubStress(unsigned int id_sph) {return bodyNormalLubStress(id_sph,solver);}
- Matrix3r _normalStressInteraction(unsigned int interaction) {return normalStressInteraction(interaction,solver);}
- Matrix3r _shearStressInteraction(unsigned int interaction) {return shearStressInteraction(interaction,solver);}
- Vector3r _shearVelocity(unsigned int id_sph) {return shearVelocity(id_sph,solver);}
- Vector3r _normalVelocity(unsigned int id_sph) {return normalVelocity(id_sph,solver);}
- Vector3r _normalVect(unsigned int id_sph) {return normalVect(id_sph,solver);}
- Real _surfaceDistanceParticle(unsigned int interaction) {return surfaceDistanceParticle(interaction,solver);}
- int _onlySpheresInteractions(unsigned int interaction) {return onlySpheresInteractions(interaction,solver);}
- Real _edgeSize() {return edgeSize(solver);}
- Real _OSI() {return OSI(solver);}
-
- Vector3r _fluidForce(unsigned int id_sph) {return fluidForce(id_sph, solver);}
- void _imposeFlux(Vector3r pos, Real flux) {return imposeFlux(pos,flux,*solver);}
- unsigned int _imposePressure(Vector3r pos, Real p) {return imposePressure(pos,p,this->solver);}
- Real _getBoundaryFlux(unsigned int boundary) {return getBoundaryFlux(boundary,solver);}
-
- void _updateBCs() {updateBCs(solver);}
- double getPorePressure(Vector3r pos){return solver->getPorePressure(pos[0], pos[1], pos[2]);}
- double averagePressure(){return solver->averagePressure();}
- void pressureProfile(double wallUpY, double wallDownY) {return solver->measurePressureProfile(wallUpY,wallDownY);}
-
- int _getCell(Vector3r pos) {return getCell(pos[0],pos[1],pos[2],solver);}
- #ifdef LINSOLV
- void _exportMatrix(string filename) {exportMatrix(filename,solver);}
- void _exportTriplets(string filename) {exportTriplets(filename,solver);}
- #endif
-
-// void _setImposedPressure(unsigned int cond, Real p) {setImposedPressure(cond,p,solver);}
-// void _clearImposedPressure() {clearImposedPressure(solver);}
- Real _getCellFlux(unsigned int cond) {return getCellFlux(cond,solver);}
- python::list _getConstrictions(bool all) {return getConstrictions(all,solver);}
- python::list _getConstrictionsFull(bool all) {return getConstrictionsFull(all,solver);}
-
- //commodities
- void compTessVolumes() {
- solver->T[solver->currentTes].Compute();
- 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.");}
- return (solver->T[solver->currentTes].Max_id() >= id) ? solver->T[solver->currentTes].Volume(id) : -1;}
-
- YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(PeriodicFlowEngine,FlowEngine,"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);
-// wallTopId=wallBottomId=wallFrontId=wallBackId=wallLeftId=wallRightId=-1;
- solver = shared_ptr<FlowSolver> (new FlowSolver);
- eps_vol_max=Eps_Vol_Cumulative=retriangulationLastIter=0;
- ReTrg=1;
- first=true;
- ,
- .def("meanVelocity",&PeriodicFlowEngine::meanVelocity,"measure the mean velocity in the period")
- .def("fluidForce",&PeriodicFlowEngine::_fluidForce,(python::arg("Id_sph")),"Return the fluid force on sphere Id_sph.")
- .def("shearLubForce",&PeriodicFlowEngine::_shearLubForce,(python::arg("Id_sph")),"Return the shear lubrication force on sphere Id_sph.")
- .def("shearLubTorque",&PeriodicFlowEngine::_shearLubTorque,(python::arg("Id_sph")),"Return the shear lubrication torque on sphere Id_sph.")
- .def("normalLubForce",&PeriodicFlowEngine::_normalLubForce,(python::arg("Id_sph")),"Return the normal lubrication force on sphere Id_sph.")
- .def("bodyShearLubStress",&PeriodicFlowEngine::_bodyShearLubStress,(python::arg("Id_sph")),"Return the shear lubrication stress on sphere Id_sph.")
- .def("bodyNormalLubStress",&PeriodicFlowEngine::_bodyNormalLubStress,(python::arg("Id_sph")),"Return the normal lubrication stress on sphere Id_sph.")
- .def("shearVelocity",&PeriodicFlowEngine::_shearVelocity,(python::arg("id_sph")),"Return the shear velocity of the interaction.")
- .def("normalStressInteraction",&PeriodicFlowEngine::_normalStressInteraction,(python::arg("id_sph")),"Return the shear velocity of the interaction.")
- .def("shearStressInteraction",&PeriodicFlowEngine::_shearStressInteraction,(python::arg("id_sph")),"Return the shear velocity of the interaction.")
- .def("normalVelocity",&PeriodicFlowEngine::_normalVelocity,(python::arg("id_sph")),"Return the normal velocity of the interaction.")
- .def("normalVect",&PeriodicFlowEngine::_normalVect,(python::arg("id_sph")),"Return the normal vector between particles.")
- .def("surfaceDistanceParticle",&PeriodicFlowEngine::_surfaceDistanceParticle,(python::arg("interaction")),"Return the distance between particles.")
- .def("onlySpheresInteractions",&PeriodicFlowEngine::_onlySpheresInteractions,(python::arg("interaction")),"Return the id of the interaction only between spheres.")
- .def("edgeSize",&PeriodicFlowEngine::_edgeSize,"Return the number of interactions.")
- .def("OSI",&PeriodicFlowEngine::_OSI,"Return the number of interactions only between spheres.")
-
-// .def("imposeFlux",&FlowEngine::_imposeFlux,(python::arg("pos"),python::arg("p")),"Impose incoming flux in boundary cell of location 'pos'.")
- .def("saveVtk",&PeriodicFlowEngine::saveVtk,(python::arg("folder")="./VTK"),"Save pressure field in vtk format. Specify a folder name for output.")
- .def("imposePressure",&PeriodicFlowEngine::_imposePressure,(python::arg("pos"),python::arg("p")),"Impose pressure in cell of location 'pos'. The index of the condition is returned (for multiple imposed pressures at different points).")
- .def("getBoundaryFlux",&PeriodicFlowEngine::_getBoundaryFlux,(python::arg("boundary")),"Get total flux through boundary defined by its body id.")
- .def("getPorePressure",&PeriodicFlowEngine::getPorePressure,(python::arg("pos")),"Measure pore pressure in position pos[0],pos[1],pos[2]")
- .def("averagePressure",&PeriodicFlowEngine::averagePressure,"Measure averaged pore pressure in the entire volume")
- .def("pressureProfile",&PeriodicFlowEngine::pressureProfile,(python::arg("wallUpY"),python::arg("wallDownY")),"Measure pore pressure in 6 equally-spaced points along the height of the sample")
-
- .def("updateBCs",&PeriodicFlowEngine::_updateBCs,"tells the engine to update it's boundary conditions before running (especially useful when changing boundary pressure - should not be needed for point-wise imposed pressure)")
-
- .def("getCell",&PeriodicFlowEngine::_getCell,python::arg("pos"),"get id of the cell containing 'pos'.")
- .def("getConstrictions",&PeriodicFlowEngine::_getConstrictions,(python::arg("all")=true),"Get the list of constriction radii (inscribed circle) for all finite facets (if all==True) or all facets not incident to a virtual bounding sphere (if all==False). When all facets are returned, negative radii denote facet incident to one or more fictious spheres.")
- .def("getConstrictionsFull",&PeriodicFlowEngine::_getConstrictionsFull,(python::arg("all")=true),"Get the list of constrictions (inscribed circle) for all finite facets (if all==True), or all facets not incident to a fictious bounding sphere (if all==False). When all facets are returned, negative radii denote facet incident to one or more fictious spheres. The constrictions are returned in the format {{cell1,cell2}{rad,nx,ny,nz}}")
- #ifdef LINSOLV
- .def("exportMatrix",&PeriodicFlowEngine::_exportMatrix,(python::arg("filename")="matrix"),"Export system matrix to a file with all entries (even zeros will displayed).")
- .def("exportTriplets",&PeriodicFlowEngine::_exportTriplets,(python::arg("filename")="triplets"),"Export system matrix to a file with only non-zero entries.")
- #endif
- .def("compTessVolumes",&PeriodicFlowEngine::compTessVolumes,"Like TesselationWrapper::computeVolumes()")
- .def("volume",&PeriodicFlowEngine::getVolume,(python::arg("id")=0),"Returns the volume of Voronoi's cell of a sphere.")
- )
- DECLARE_LOGGER;
-
-
-};
-
-REGISTER_SERIALIZABLE(PeriodicFlowEngine);
-
-
-// #endif
=== modified file 'pkg/dem/JointedCohesiveFrictionalPM.cpp'
--- pkg/dem/JointedCohesiveFrictionalPM.cpp 2014-01-29 11:27:31 +0000
+++ pkg/dem/JointedCohesiveFrictionalPM.cpp 2014-03-11 18:36:24 +0000
@@ -106,12 +106,15 @@
}
- /* Morh-Coulomb criterion */
+ /* Mohr-Coulomb criterion */
Real maxFs = phys->FsMax + Fn*phys->tanFrictionAngle;
Real scalarShearForce = shearForce.norm();
if (scalarShearForce > maxFs) {
- shearForce*=maxFs/scalarShearForce;
+ if (scalarShearForce != 0)
+ shearForce*=maxFs/scalarShearForce;
+ else
+ shearForce=Vector3r::Zero();
if ((smoothJoint) && (phys->isOnJoint)) {phys->dilation=phys->jointCumulativeSliding*phys->tanDilationAngle-D; phys->initD+=(jointSliding*phys->tanDilationAngle);}
// take into account shear cracking -> are those lines critical? -> TODO testing with and without
if ( phys->isCohesive ) {
@@ -202,12 +205,15 @@
// frictional properties
contactPhysics->kn = 2.*E1*R1*E2*R2/(E1*R1+E2*R2);
- contactPhysics->ks = 2.*E1*R1*v1*E2*R2*v2/(E1*R1*v1+E2*R2*v2);//alpha*contactPhysics->kn;
+ if ( (v1==0)&&(v2==0) )
+ contactPhysics->ks = 0;
+ else
+ contactPhysics->ks = 2.*E1*R1*v1*E2*R2*v2/(E1*R1*v1+E2*R2*v2);
contactPhysics->tanFrictionAngle = std::tan(std::min(f1,f2));
// cohesive properties
///to set if the contact is cohesive or not
- if ((scene->iter < cohesiveTresholdIteration) && (std::min(SigT1,SigT2)>0 || std::min(Coh1,Coh2)>0) && (yade1->type == yade2->type)){
+ if ( ((cohesiveTresholdIteration < 0) || (scene->iter < cohesiveTresholdIteration)) && (std::min(SigT1,SigT2)>0 || std::min(Coh1,Coh2)>0) && (yade1->type == yade2->type)){
contactPhysics->isCohesive=true;
st1->noIniLinks++;
st2->noIniLinks++;
@@ -267,7 +273,7 @@
contactPhysics->tanDilationAngle = std::tan(std::min(jdil1,jdil2));
///to set if the contact is cohesive or not
- if ((scene->iter < cohesiveTresholdIteration) && (std::min(jcoh1,jcoh2)>0 || std::min(jSigT1,jSigT2)/2.0>0)) {
+ if ( ((cohesiveTresholdIteration < 0) || (scene->iter < cohesiveTresholdIteration)) && (std::min(jcoh1,jcoh2)>0 || std::min(jSigT1,jSigT2)>0) ) {
contactPhysics->isCohesive=true;
st1->noIniLinks++;
st2->noIniLinks++;
=== modified file 'pkg/dem/JointedCohesiveFrictionalPM.hpp'
--- pkg/dem/JointedCohesiveFrictionalPM.hpp 2013-12-05 11:49:29 +0000
+++ pkg/dem/JointedCohesiveFrictionalPM.hpp 2014-03-14 08:46:30 +0000
@@ -86,7 +86,7 @@
DECLARE_LOGGER;
YADE_CLASS_BASE_DOC_ATTRS(Ip2_JCFpmMat_JCFpmMat_JCFpmPhys,IPhysFunctor,"Converts 2 :yref:`JCFpmMat` instances to one :yref:`JCFpmPhys` instance, with corresponding parameters.",
- ((int,cohesiveTresholdIteration,1,,"should new contacts be cohesive? They will before this iter, they won't afterward."))
+ ((int,cohesiveTresholdIteration,1,,"should new contacts be cohesive? If strictly negativ, they will in any case. If positiv, they will before this iter, they won't afterward."))
);
};
@@ -102,7 +102,7 @@
((string,Key,"",,"string specifying the name of saved file 'cracks___.txt', when :yref:`recordCracks<Law2_ScGeom_JCFpmPhys_JointedCohesiveFrictionalPM.recordCracks>` is true."))
((bool,cracksFileExist,false,,"if true (and if :yref:`recordCracks<Law2_ScGeom_JCFpmPhys_JointedCohesiveFrictionalPM.recordCracks>`), data are appended to an existing 'cracksKey' text file; otherwise its content is reset."))
((bool,smoothJoint,false,,"if true, interactions of particles belonging to joint surface (:yref:`JCFpmPhys.isOnJoint`) are handled according to a smooth contact logic [Ivars2011]_, [Scholtes2012]_."))
- ((bool,recordCracks,false,,"if true a text file cracksKey.txt (see :yref:`Key<Law2_ScGeom_JCFpmPhys_JointedCohesiveFrictionalPM.Key>`) will be created. It contains : apparition iteration, position, type (tensile or shear), cross section and contact normal."))
+ ((bool,recordCracks,false,,"if true, data about interactions that lose their cohesive feature are stored in a text file cracksKey.txt (see :yref:`Key<Law2_ScGeom_JCFpmPhys_JointedCohesiveFrictionalPM.Key>` and :yref:`cracksFileExist<Law2_ScGeom_JCFpmPhys_JointedCohesiveFrictionalPM.cracksFileExist>`). It contains 9 columns: the break iteration, the 3 coordinates of the contact point, the type (1 means shear break, while 0 corresponds to tensile break), the ''cross section'' (mean radius of the 2 spheres) and the 3 coordinates of the contact normal."))
);
DECLARE_LOGGER;
};
=== modified file 'pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.cpp'
--- pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.cpp 2013-05-30 20:17:45 +0000
+++ pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.cpp 2014-03-21 18:45:24 +0000
@@ -143,7 +143,7 @@
int* currentIndexes = hertzOn? mindlinContactPhysics->currentIndexes : cundallContactPhysics->currentIndexes;
//If P=0, we use null solution
MeniscusParameters
- solution(Pinterpol? capillary->Interpolate(R1,R2,Dinterpol, Pinterpol, currentIndexes) : MeniscusParameters());
+ solution(Pinterpol? capillary->interpolate(R1,R2,Dinterpol, Pinterpol, currentIndexes) : MeniscusParameters());
/// capillary adhesion force
Real Finterpol = solution.F;
Vector3r fCap = Finterpol*(2*Mathr::PI*(R2/alpha)*liquidTension)*currentContactGeometry->normal;
@@ -284,7 +284,7 @@
}
}
-MeniscusParameters capillarylaw::Interpolate(Real R1, Real R2, Real D, Real P, int* index)
+MeniscusParameters capillarylaw::interpolate(Real R1, Real R2, Real D, Real P, int* index)
{ //cerr << "interpolate" << endl;
if (R1 > R2) {
Real R3 = R1;
=== modified file 'pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.hpp'
--- pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.hpp 2013-05-30 20:17:45 +0000
+++ pkg/dem/Law2_ScGeom_CapillaryPhys_Capillarity.hpp 2014-04-16 09:32:47 +0000
@@ -93,7 +93,7 @@
void action();
void postLoad(Law2_ScGeom_CapillaryPhys_Capillarity&);
- YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(Law2_ScGeom_CapillaryPhys_Capillarity,GlobalEngine,"This law allows one to take into account capillary forces/effects between spheres coming from the presence of interparticular liquid bridges (menisci).\n\nThe control parameter is the capillary pressure (or suction) Uc = ugas - Uliquid. Liquid bridges properties (volume V, extent over interacting grains delta1 and delta2) are computed as a result of the defined capillary pressure and of the interacting geometry (spheres radii and interparticular distance).\n\nReferences: in english [Scholtes2009b]_; more detailed, but in french [Scholtes2009d]_.\n\nThe law needs ascii files M(r=i) with i=R1/R2 to work (see https://yade-dem.org/index.php/CapillaryTriaxialTest). These ASCII files contain a set of results from the resolution of the Laplace-Young equation for different configurations of the interacting geometry.\n\nIn order to allow capillary forces between distant spheres, it is necessary to enlarge the bounding boxes using :yref:`Bo1_Sphere_Aabb::aabbEnlargeFactor` and make the Ig2 define define distant interactions via :yref:`interactionDetectionFactor<Ig2_Sphere_Sphere_ScGeom::interactionDetectionFactor>`. It is also necessary to disable interactions removal by the constitutive law (:yref:`Law2<Law2_ScGeom_FrictPhys_CundallStrack::neverErase>=True`). The only combinations of laws supported are currently capillary law + :yref:`Law2_ScGeom_FrictPhys_CundallStrack` and capillary law + :yref:`Law2_ScGeom_MindlinPhys_Mindlin` (and the other variants of Hertz-Mindlin).\n\nSee CapillaryPhys-example.py for an example script.",
+ YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(Law2_ScGeom_CapillaryPhys_Capillarity,GlobalEngine,"This law allows one to take into account capillary forces/effects between spheres coming from the presence of interparticular liquid bridges (menisci).\n\nThe control parameter is the capillary pressure (or suction) Uc = ugas - Uliquid. Liquid bridges properties (volume V, extent over interacting grains delta1 and delta2) are computed as a result of the defined capillary pressure and of the interacting geometry (spheres radii and interparticular distance).\n\nReferences: in english [Scholtes2009b]_; more detailed, but in french [Scholtes2009d]_.\n\nThe law needs ascii files M(r=i) with i=R1/R2 to work (see https://yade-dem.org/wiki/CapillaryTriaxialTest). These ASCII files contain a set of results from the resolution of the Laplace-Young equation for different configurations of the interacting geometry.\n\nIn order to allow capillary forces between distant spheres, it is necessary to enlarge the bounding boxes using :yref:`Bo1_Sphere_Aabb::aabbEnlargeFactor` and make the Ig2 define define distant interactions via :yref:`interactionDetectionFactor<Ig2_Sphere_Sphere_ScGeom::interactionDetectionFactor>`. It is also necessary to disable interactions removal by the constitutive law (:yref:`Law2<Law2_ScGeom_FrictPhys_CundallStrack::neverErase>=True`). The only combinations of laws supported are currently capillary law + :yref:`Law2_ScGeom_FrictPhys_CundallStrack` and capillary law + :yref:`Law2_ScGeom_MindlinPhys_Mindlin` (and the other variants of Hertz-Mindlin).\n\nSee CapillaryPhys-example.py for an example script.",
((Real,capillaryPressure,0.,,"Value of the capillary pressure Uc defines as Uc=Ugas-Uliquid"))
((bool,fusionDetection,false,,"If true potential menisci overlaps are checked"))
((bool,binaryFusion,true,,"If true, capillary forces are set to zero as soon as, at least, 1 overlap (menisci fusion) is detected"))
@@ -137,7 +137,7 @@
public:
capillarylaw();
std::vector<Tableau> data_complete;
- MeniscusParameters Interpolate(Real R1, Real R2, Real D, Real P, int* index);
+ MeniscusParameters interpolate(Real R1, Real R2, Real D, Real P, int* index);
void fill (const char* filename);
};
=== modified file 'pkg/dem/MicroMacroAnalyser.cpp'
--- pkg/dem/MicroMacroAnalyser.cpp 2012-07-10 21:05:26 +0000
+++ pkg/dem/MicroMacroAnalyser.cpp 2014-03-21 18:47:45 +0000
@@ -58,7 +58,7 @@
} else if (scene->iter % interval == 0) {
setState(2, true, compIncrt);
if (compDeformation) {
- analyser->ComputeParticlesDeformation();
+ analyser->computeParticlesDeformation();
//for (int i=0; i<analyser->ParticleDeformation.size();i++) cerr<< analyser->ParticleDeformation[i]<<endl;
ostringstream oss;
oss<<"deformation"<<incrtNumber++<<".vtk";
@@ -130,7 +130,7 @@
// TS.grains[Idg].translation = trans;
AngleAxisr aa((*bi)->state->ori);
Vector3r rotVec=aa.axis()*aa.angle();
- TS.grains[Idg].rotation = CGT::Vecteur(rotVec[0],rotVec[1],rotVec[2]);
+ TS.grains[Idg].rotation = CGT::CVector(rotVec[0],rotVec[1],rotVec[2]);
TS.box.base = CGT::Point(min(TS.box.base.x(), pos.x()-rad),
min(TS.box.base.y(), pos.y()-rad),
min(TS.box.base.z(), pos.z()-rad));
@@ -173,12 +173,12 @@
c->grain2 = & (TS.grains[id2]);
grains[id1].contacts.push_back(c);
grains[id2].contacts.push_back(c);
- c->normal = CGT::Vecteur((YADE_CAST<ScGeom*> ((*ii)->geom.get()))->normal.x(),
+ c->normal = CGT::CVector((YADE_CAST<ScGeom*> ((*ii)->geom.get()))->normal.x(),
(YADE_CAST<ScGeom*> ((*ii)->geom.get()))->normal.y(),
(YADE_CAST<ScGeom*> ((*ii)->geom.get()))->normal.z());
// c->normal = ( grains[id2].sphere.point()-grains[id1].sphere.point() );
// c->normal = c->normal/sqrt ( pow ( c->normal.x(),2 ) +pow ( c->normal.y(),2 ) +pow ( c->normal.z(),2 ) );
- c->position = CGT::Vecteur((YADE_CAST<ScGeom*> ((*ii)->geom.get()))->contactPoint.x(),
+ c->position = CGT::CVector((YADE_CAST<ScGeom*> ((*ii)->geom.get()))->contactPoint.x(),
(YADE_CAST<ScGeom*> ((*ii)->geom.get()))->contactPoint.y(),
(YADE_CAST<ScGeom*> ((*ii)->geom.get()))->contactPoint.z());
// c->position = 0.5* ( ( grains[id1].sphere.point()-CGAL::ORIGIN ) +
@@ -187,7 +187,7 @@
// ( grains[id2].sphere.weight() *c->normal ) );
c->fn = YADE_CAST<FrictPhys*> (((*ii)->phys.get()))->normalForce.dot((YADE_CAST<ScGeom*> ((*ii)->geom.get()))->normal);
Vector3r fs = YADE_CAST<FrictPhys*> ((*ii)->phys.get())->shearForce;
- c->fs = CGT::Vecteur(fs.x(),fs.y(),fs.z());
+ c->fs = CGT::CVector(fs.x(),fs.y(),fs.z());
c->old_fn = c->fn;
c->old_fs = c->fs;
c->frictional_work = 0;
@@ -214,8 +214,8 @@
TS.haut = triaxialCompressionEngine->height;//find_parameter("haut=", Statefile);
TS.larg = triaxialCompressionEngine->width;//find_parameter("larg=", Statefile);
TS.prof = triaxialCompressionEngine->depth;//find_parameter("prof=", Statefile);
- TS.porom = 0/*analyser->ComputeMacroPorosity() crasher?*/;//find_parameter("porom=", Statefile);
- TS.ratio_f = triaxialCompressionEngine-> ComputeUnbalancedForce(scene); //find_parameter("ratio_f=", Statefile);
+ TS.porom = 0/*analyser->computeMacroPorosity() crasher?*/;//find_parameter("porom=", Statefile);
+ TS.ratio_f = triaxialCompressionEngine->ComputeUnbalancedForce(scene); //find_parameter("ratio_f=", Statefile);
} else TS.wszzh=TS.wsxxd=TS.wsyyfa=TS.eps3=TS.eps1=TS.eps2=TS.haut=TS.larg=TS.prof=TS.porom=TS.ratio_f=0;
if (filename!=NULL) TS.to_file(filename);
return TS;
@@ -223,7 +223,7 @@
// const vector<CGT::Tenseur3>& MicroMacroAnalyser::makeDeformationArray(const char* state_file1, const char* state_file0)
// {
-// return analyser->ComputeParticlesDeformation(state_file1, state_file0);
+// return analyser->computeParticlesDeformation(state_file1, state_file0);
// }
#endif /* YADE_CGAL */
=== modified file 'pkg/dem/MicroMacroAnalyser.hpp'
--- pkg/dem/MicroMacroAnalyser.hpp 2012-01-13 11:24:44 +0000
+++ pkg/dem/MicroMacroAnalyser.hpp 2014-03-21 18:47:45 +0000
@@ -15,7 +15,7 @@
#include <string>
#include <fstream>
-/*! \brief Compute fabric tensor, local porosity, local deformation, and other micromechanicaly defined quantities based on triangulation/tesselation of the packing.
+/*! \brief compute fabric tensor, local porosity, local deformation, and other micromechanicaly defined quantities based on triangulation/tesselation of the packing.
*/
@@ -45,7 +45,7 @@
void postLoad(MicroMacroAnalyser&);
- YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(MicroMacroAnalyser,GlobalEngine,"Compute fabric tensor, local porosity, local deformation, and other micromechanicaly defined quantities based on triangulation/tesselation of the packing.",
+ YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(MicroMacroAnalyser,GlobalEngine,"compute fabric tensor, local porosity, local deformation, and other micromechanicaly defined quantities based on triangulation/tesselation of the packing.",
((unsigned int,stateNumber,0,,"A number incremented and appended at the end of output files to reflect increment number."))
((unsigned int,incrtNumber,1,,""))
((std::string,outputFile,"MicroMacroAnalysis",,"Base name for increment analysis output file."))
=== modified file 'pkg/dem/NewtonIntegrator.cpp'
--- pkg/dem/NewtonIntegrator.cpp 2014-02-16 14:03:41 +0000
+++ pkg/dem/NewtonIntegrator.cpp 2014-04-08 19:11:03 +0000
@@ -108,7 +108,9 @@
if(warnNoForceReset && scene->forces.lastReset<scene->iter) LOG_WARN("O.forces last reset in step "<<scene->forces.lastReset<<", while the current step is "<<scene->iter<<". Did you forget to include ForceResetter in O.engines?");
const Real& dt=scene->dt;
//Take care of user's request to change velGrad. Safe to change it here after the interaction loop.
- if (scene->cell->velGradChanged) {scene->cell->velGrad=scene->cell->nextVelGrad; scene->cell->velGradChanged=0;}
+ if (scene->cell->velGradChanged || scene->cell->nextVelGrad!=Matrix3r::Zero()) {
+ scene->cell->velGrad=scene->cell->nextVelGrad;
+ scene->cell->velGradChanged=0; scene->cell->nextVelGrad=Matrix3r::Zero();}
homoDeform=scene->cell->homoDeform;
dVelGrad=scene->cell->velGrad-prevVelGrad;
// account for motion of the periodic boundary, if we remember its last position
@@ -229,10 +231,10 @@
void NewtonIntegrator::leapfrogSphericalRotate(State* state, const Body::id_t& id, const Real& dt )
{
- Vector3r axis = state->angVel;
- if (axis!=Vector3r::Zero()) {//If we have an angular velocity, we make a rotation
- Real angle=axis.norm(); axis/=angle;
- Quaternionr q(AngleAxisr(angle*dt,axis));
+ Real angle2=state->angVel.squaredNorm();
+ if (angle2!=0) {//If we have an angular velocity, we make a rotation
+ Real angle=sqrt(angle2);
+ Quaternionr q(AngleAxisr(angle*dt,state->angVel/angle));
state->ori = q*state->ori;
}
if(scene->forces.getMoveRotUsed() && scene->forces.getRot(id)!=Vector3r::Zero()) {
=== modified file 'pkg/dem/Shop.hpp'
--- pkg/dem/Shop.hpp 2013-10-30 23:25:56 +0000
+++ pkg/dem/Shop.hpp 2014-02-27 08:27:24 +0000
@@ -145,7 +145,7 @@
static void setContactFriction(Real angleRad);
//! Homothetic change of sizes of spheres and clumps
- static void growParticles(Real multiplier, bool updateMass, bool dynamicOnly, unsigned int discretization, bool integrateInertia);
+ static void growParticles(Real multiplier, bool updateMass, bool dynamicOnly, unsigned int discretization);
//! Change of size of a single sphere or a clump
static void growParticle(Body::id_t bodyID, Real multiplier, bool updateMass);
};
=== modified file 'pkg/dem/Shop_02.cpp'
--- pkg/dem/Shop_02.cpp 2013-10-30 23:25:56 +0000
+++ pkg/dem/Shop_02.cpp 2014-04-02 15:34:57 +0000
@@ -147,13 +147,7 @@
void Shop::getViscoelasticFromSpheresInteraction( Real tc, Real en, Real es, shared_ptr<ViscElMat> b)
{
- b->kn = 1/tc/tc * ( Mathr::PI*Mathr::PI + pow(log(en),2) );
- b->cn = -2.0 /tc * log(en);
- b->ks = 2.0/7.0 /tc/tc * ( Mathr::PI*Mathr::PI + pow(log(es),2) );
- b->cs = -2.0/7.0 /tc * log(es);
-
- if (abs(b->cn) <= Mathr::ZERO_TOLERANCE ) b->cn=0;
- if (abs(b->cs) <= Mathr::ZERO_TOLERANCE ) b->cs=0;
+ throw runtime_error("Setting parameters in ViscoElastic model is changed. You do not need to use getViscoelasticFromSpheresInteraction function any more, because this functino is deprecated. You need to set the parameters tc, en and es directly in material properties. Please, update your scripts. How to do it you can see in the following commit https://github.com/yade/trunk/commit/1987c2febdb8a6ce2d27f2dc1bb29df0dc5f686e");
}
/* This function is copied almost verbatim from scientific python, module Visualization, class ColorScale
@@ -477,7 +471,7 @@
}
}
-void Shop::growParticles(Real multiplier, bool updateMass, bool dynamicOnly, unsigned int discretization, bool integrateInertia)
+void Shop::growParticles(Real multiplier, bool updateMass, bool dynamicOnly, unsigned int discretization)
{
Scene* scene = Omega::instance().getScene().get();
FOREACH(const shared_ptr<Body>& b,*scene->bodies){
@@ -492,7 +486,7 @@
FOREACH(const shared_ptr<Body>& b,*scene->bodies){
if(b->isClump()){
Clump* clumpSt = YADE_CAST<Clump*>(b->shape.get());
- clumpSt->updateProperties(b, discretization, integrateInertia);
+ clumpSt->updateProperties(b, discretization);
}
}
FOREACH(const shared_ptr<Interaction>& ii, *scene->interactions){
=== modified file 'pkg/dem/TesselationWrapper.cpp'
--- pkg/dem/TesselationWrapper.cpp 2013-03-05 19:00:17 +0000
+++ pkg/dem/TesselationWrapper.cpp 2014-03-21 18:47:45 +0000
@@ -68,7 +68,7 @@
BodyContainer::iterator bi = biBegin;
Body::id_t Ng = 0;
- Body::id_t& MaxId=Tes.max_id;
+ Body::id_t& MaxId=Tes.maxId;
TW.mean_radius = 0;
shared_ptr<Sphere> sph (new Sphere);
@@ -109,9 +109,9 @@
if (v==RTriangulation::Vertex_handle())
hint=c;
else {
- v->info() = (const unsigned int) p->second;
+ v->info().setId((const unsigned int) p->second);
//Vh->info().isFictious = false;//false is the default
- Tes.max_id = std::max(Tes.max_id,(int) p->second);
+ Tes.maxId = std::max(Tes.maxId,(int) p->second);
Tes.vertexHandles[p->second]=v;
hint=v->cell();
++TW.n_spheres;
@@ -189,26 +189,26 @@
}
}
-void TesselationWrapper::ComputeTesselation(void)
+void TesselationWrapper::computeTesselation(void)
{
if (!rad_divided) {
mean_radius /= n_spheres;
rad_divided = true;
}
- Tes->Compute();
-}
-
-void TesselationWrapper::ComputeTesselation(double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz, double dt)
-{
- AddBoundingPlanes(pminx, pmaxx, pminy, pmaxy, pminz, pmaxz, dt);
- ComputeTesselation();
-}
-
-void TesselationWrapper::ComputeVolumes(void)
-{
- if (!bounded) AddBoundingPlanes();
- ComputeTesselation();
- Tes->ComputeVolumes();
+ Tes->compute();
+}
+
+void TesselationWrapper::computeTesselation(double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz, double dt)
+{
+ addBoundingPlanes(pminx, pmaxx, pminy, pmaxy, pminz, pmaxz, dt);
+ computeTesselation();
+}
+
+void TesselationWrapper::computeVolumes(void)
+{
+ if (!bounded) addBoundingPlanes();
+ computeTesselation();
+ Tes->computeVolumes();
}
unsigned int TesselationWrapper::NumberOfFacets(bool initIters)
{
@@ -232,7 +232,7 @@
return true;
}
-void TesselationWrapper::AddBoundingPlanes(double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz,double dt)
+void TesselationWrapper::addBoundingPlanes(double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz,double dt)
{
//Not sure this hack form JFJ works in all cases (?)
if (dt == 0) {
@@ -254,7 +254,7 @@
}
}
-void TesselationWrapper::AddBoundingPlanes(void)
+void TesselationWrapper::addBoundingPlanes(void)
{
if (!bounded) {
if (!rad_divided) {
@@ -349,7 +349,7 @@
delete Tes;
CGT::TriaxialState* ts;
if (deformation){//use the final state to compute volumes
- /*const vector<CGT::Tenseur3>& def =*/ mma.analyser->ComputeParticlesDeformation();
+ /*const vector<CGT::Tenseur3>& def =*/ mma.analyser->computeParticlesDeformation();
Tes = &mma.analyser->TS1->tesselation();
ts = mma.analyser->TS1;
}
@@ -357,8 +357,8 @@
ts = mma.analyser->TS0;}
RTriangulation& Tri = Tes->Triangulation();
Pmin=ts->box.base; Pmax=ts->box.sommet;
- //if (!scene->isPeriodic) AddBoundingPlanes();
- ComputeVolumes();
+ //if (!scene->isPeriodic) addBoundingPlanes();
+ computeVolumes();
int bodiesDim = Tes->Max_id() + 1; //=scene->bodies->size();
cerr<<"bodiesDim="<<bodiesDim<<endl;
int dim1[]={bodiesDim};
=== modified file 'pkg/dem/TesselationWrapper.hpp'
--- pkg/dem/TesselationWrapper.hpp 2013-10-31 00:03:24 +0000
+++ pkg/dem/TesselationWrapper.hpp 2014-04-01 13:18:38 +0000
@@ -37,11 +37,11 @@
class TesselationWrapper : public GlobalEngine{
public:
- typedef CGT::_Tesselation<CGT::SimpleTriangulationTypes> Tesselation;
+ typedef CGT::_Tesselation<CGT::SimpleTriangulationTypes> Tesselation;
typedef Tesselation::RTriangulation RTriangulation;
- typedef Tesselation::Vertex_Info Vertex_Info;
- typedef Tesselation::Cell_Info Cell_Info;
- typedef RTriangulation::Finite_edges_iterator Finite_edges_iterator;
+ typedef Tesselation::VertexInfo VertexInfo;
+ typedef Tesselation::CellInfo CellInfo;
+ typedef RTriangulation::Finite_edges_iterator FiniteEdgesIterator;
@@ -67,22 +67,22 @@
void clear2(void);
/// Add axis aligned bounding planes (modelised as spheres with (almost) infinite radius)
- void AddBoundingPlanes (void);
+ void addBoundingPlanes (void);
/// Force boudaries at positions not equal to precomputed ones
- void AddBoundingPlanes(double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz, double dt);
+ void addBoundingPlanes(double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz, double dt);
void RemoveBoundingPlanes (void);
- ///Compute voronoi centers then stop (don't compute anything else)
- void ComputeTesselation (void);
- void ComputeTesselation( double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz, double dt);
+ ///compute voronoi centers then stop (don't compute anything else)
+ void computeTesselation (void);
+ void computeTesselation( double pminx, double pmaxx, double pminy, double pmaxy, double pminz, double pmaxz, double dt);
- ///Compute Voronoi vertices + volumes of all cells
- ///use ComputeTesselation to force update, e.g. after spheres positions have been updated
- void ComputeVolumes (void);
- void computeDeformations (void) {mma.analyser->ComputeParticlesDeformation();}
+ ///compute Voronoi vertices + volumes of all cells
+ ///use computeTesselation to force update, e.g. after spheres positions have been updated
+ void computeVolumes (void);
+ void computeDeformations (void) {mma.analyser->computeParticlesDeformation();}
///Get volume of the sphere inserted with indentifier "id""
double Volume (unsigned int id);
double deformation (unsigned int id,unsigned int i,unsigned int j) {
- if (!mma.analyser->ParticleDeformation.size()) {LOG_ERROR("Compute deformations first"); return 0;}
+ if (!mma.analyser->ParticleDeformation.size()) {LOG_ERROR("compute deformations first"); return 0;}
if (mma.analyser->ParticleDeformation.size()<id) {LOG_ERROR("id out of bounds"); return 0;}
return mma.analyser->ParticleDeformation[id](i,j);}
@@ -108,12 +108,12 @@
public:
/// edge iterators are used for returning tesselation "facets", i.e. spheres with a common branch in the triangulation, convert CGAL::edge to int pair (b1->id, b2->id)
- Finite_edges_iterator facet_begin;
- Finite_edges_iterator facet_end;
- Finite_edges_iterator facet_it;
+ FiniteEdgesIterator facet_begin;
+ FiniteEdgesIterator facet_end;
+ FiniteEdgesIterator facet_it;
MicroMacroAnalyser mma;
- YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(TesselationWrapper,GlobalEngine,"Handle the triangulation of spheres in a scene, build tesselation on request, and give access to computed quantities (see also the `dedicated section in user manual <https://yade-dem.org/doc/user.html#micro-stress-and-micro-strain>`_). The calculation of microstrain is explained in [Catalano2013a]_ \n\nSee example usage in script example/tesselationWrapper/tesselationWrapper.py.\n\nBelow is an output of the :yref:`defToVtk<TesselationWrapper::defToVtk>` function visualized with paraview (in this case Yade's TesselationWrapper was used to process experimental data obtained on sand by Edward Ando at Grenoble University, 3SR lab.)\n\n.. figure:: fig/localstrain.*",
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(TesselationWrapper,GlobalEngine,"Handle the triangulation of spheres in a scene, build tesselation on request, and give access to computed quantities (see also the `dedicated section in user manual <https://yade-dem.org/doc/user.html#micro-stress-and-micro-strain>`_). The calculation of microstrain is explained in [Catalano2014a]_ \n\nSee example usage in script example/tesselationWrapper/tesselationWrapper.py.\n\nBelow is an output of the :yref:`defToVtk<TesselationWrapper::defToVtk>` function visualized with paraview (in this case Yade's TesselationWrapper was used to process experimental data obtained on sand by Edward Ando at Grenoble University, 3SR lab.)\n\n.. figure:: fig/localstrain.*",
((unsigned int,n_spheres,0,,"|ycomp|"))
,/*ctor*/
Tes = new Tesselation;
@@ -132,9 +132,9 @@
.def("defToVtk",&TesselationWrapper::defToVtk,(python::arg("outputFile")="def.vtk"),"Write local deformations in vtk format from states 0 and 1.")
.def("defToVtkFromStates",&TesselationWrapper::defToVtkFromStates,(python::arg("input1")="state1",python::arg("input2")="state2",python::arg("outputFile")="def.vtk",python::arg("bz2")=true),"Write local deformations in vtk format from state files (since the file format is very special, consider using defToVtkFromPositions if the input files were not generated by TesselationWrapper).")
.def("defToVtkFromPositions",&TesselationWrapper::defToVtkFromPositions,(python::arg("input1")="pos1",python::arg("input2")="pos2",python::arg("outputFile")="def.vtk",python::arg("bz2")=false),"Write local deformations in vtk format from positions files (one sphere per line, with x,y,z,rad separated by spaces).")
- .def("computeVolumes",&TesselationWrapper::ComputeVolumes,"Compute volumes of all Voronoi's cells.")
+ .def("computeVolumes",&TesselationWrapper::computeVolumes,"compute volumes of all Voronoi's cells.")
.def("getVolPoroDef",&TesselationWrapper::getVolPoroDef,(python::arg("deformation")=false),"Return a table with per-sphere computed quantities. Include deformations on the increment defined by states 0 and 1 if deformation=True (make sure to define states 0 and 1 consistently).")
- .def("ComputeDeformations",&TesselationWrapper::computeDeformations,"Compute per-particle deformation. Get it with :yref:`TesselationWrapper::deformation` (id,i,j).")
+ .def("computeDeformations",&TesselationWrapper::computeDeformations,"compute per-particle deformation. Get it with :yref:`TesselationWrapper::deformation` (id,i,j).")
.def("deformation",&TesselationWrapper::deformation,(python::arg("id"),python::arg("i"),python::arg("j")),"Get particle deformation")
);
DECLARE_LOGGER;
=== modified file 'pkg/dem/TriaxialStressController.hpp'
--- pkg/dem/TriaxialStressController.hpp 2013-07-16 09:57:52 +0000
+++ pkg/dem/TriaxialStressController.hpp 2014-03-24 12:23:56 +0000
@@ -99,9 +99,9 @@
((Real,height,0,Attr::readonly,"size of the box (1-axis) |yupdate|"))
((Real,width,0,Attr::readonly,"size of the box (0-axis) |yupdate|"))
((Real,depth,0,Attr::readonly,"size of the box (2-axis) |yupdate|"))
- ((Real,height0,0,Attr::readonly,"Reference size for strain definition. See :yref:`TriaxialStressController::height`"))
- ((Real,width0,0,Attr::readonly,"Reference size for strain definition. See :yref:`TriaxialStressController::width`"))
- ((Real,depth0,0,Attr::readonly,"Reference size for strain definition. See :yref:`TriaxialStressController::depth`"))
+ ((Real,height0,0,,"Reference size for strain definition. See :yref:`TriaxialStressController::height`"))
+ ((Real,width0,0,,"Reference size for strain definition. See :yref:`TriaxialStressController::width`"))
+ ((Real,depth0,0,,"Reference size for strain definition. See :yref:`TriaxialStressController::depth`"))
((Real,goal1,0,,"prescribed stress/strain rate on axis 1, as defined by :yref:`TriaxialStressController::stressMask` (see also :yref:`TriaxialStressController::isAxisymetric`)"))
((Real,goal2,0,,"prescribed stress/strain rate on axis 2, as defined by :yref:`TriaxialStressController::stressMask` (see also :yref:`TriaxialStressController::isAxisymetric`)"))
=== modified file 'pkg/dem/UniaxialStrainer.cpp'
--- pkg/dem/UniaxialStrainer.cpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/UniaxialStrainer.cpp 2014-04-02 07:44:58 +0000
@@ -109,13 +109,15 @@
if(asymmetry!=1){
for(size_t i=0; i<negIds.size(); i++){
negCoords[i]-=dAX;
- axisCoord(negIds[i])=negCoords[i]; // update current position
+ //axisCoord(negIds[i])=negCoords[i]; // this line that modifies state->pos is useless with curent velocity defined below, and use of NewtonIntegrator
+ axisVel(negIds[i]) = -dAX/scene->dt; // update current position
}
}
if(asymmetry!=-1){
for(size_t i=0; i<posIds.size(); i++){
posCoords[i]+=dAX;
- axisCoord(posIds[i])=posCoords[i];
+ //axisCoord(posIds[i])=posCoords[i]; // idem
+ axisVel(posIds[i]) = dAX/scene->dt;
}
}
=== modified file 'pkg/dem/UniaxialStrainer.hpp'
--- pkg/dem/UniaxialStrainer.hpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/UniaxialStrainer.hpp 2014-04-02 07:44:58 +0000
@@ -20,7 +20,8 @@
private:
bool needsInit;
void computeAxialForce();
- Real& axisCoord(Body::id_t id){ return Body::byId(id,scene)->state->pos[axis]; };
+ Real axisCoord(Body::id_t id){ return Body::byId(id,scene)->state->pos[axis]; };
+ Real& axisVel(Body::id_t id){ return Body::byId(id,scene)->state->vel[axis]; };
void init();
public:
virtual bool isActivated(){ return active; }
@@ -48,7 +49,7 @@
((Real,crossSectionArea,NaN,,"crossSection perpendicular to he strained axis; must be given explicitly [m²]"))
((Real,strain,0,,"Current strain value, elongation/originalLength |yupdate| [-]"))
((Real,avgStress,0,,"Current average stress |yupdate| [Pa]"))
- ((bool,blockDisplacements,false,,"Whether displacement of boundary bodies perpendicular to the strained axis are blocked of are free"))
+ ((bool,blockDisplacements,false,,"Whether displacement of boundary bodies perpendicular to the strained axis are blocked or are free"))
((bool,blockRotations,false,,"Whether rotations of boundary bodies are blocked."))
((bool,setSpeeds,false,,"should we set speeds at the beginning directly, instead of increasing strain rate progressively?"))
((int,stressUpdateInterval,10,,"How often to recompute stress on supports.")),
=== modified file 'pkg/dem/VTKRecorder.cpp'
--- pkg/dem/VTKRecorder.cpp 2013-11-04 14:55:45 +0000
+++ pkg/dem/VTKRecorder.cpp 2014-05-08 05:57:04 +0000
@@ -30,7 +30,9 @@
#include<yade/pkg/dem/WirePM.hpp>
#include<yade/pkg/dem/JointedCohesiveFrictionalPM.hpp>
#include<yade/pkg/dem/Shop.hpp>
-
+#ifdef YADE_LIQMIGRATION
+ #include<yade/pkg/dem/ViscoelasticCapillarPM.hpp>
+#endif
YADE_PLUGIN((VTKRecorder));
CREATE_LOGGER(VTKRecorder);
@@ -70,6 +72,7 @@
else if(rec=="jcfpm") recActive[REC_JCFPM]=true;
else if(rec=="cracks") recActive[REC_CRACKS]=true;
else if(rec=="pericell" && scene->isPeriodic) recActive[REC_PERICELL]=true;
+ else if(rec=="liquidcontrol") recActive[REC_LIQ]=true;
else LOG_ERROR("Unknown recorder named `"<<rec<<"' (supported are: all, spheres, velocity, facets, boxes, color, stress, cpm, wpm, intr, id, clumpId, materialId, jcfpm, cracks, pericell). Ignored.");
}
// cpm needs interactions
@@ -80,7 +83,10 @@
// wpm needs interactions
if(recActive[REC_WPM]) recActive[REC_INTR]=true;
-
+
+ // liquid control needs interactions
+ if(recActive[REC_LIQ]) recActive[REC_INTR]=true;
+
// spheres
vtkSmartPointer<vtkPoints> spheresPos = vtkSmartPointer<vtkPoints>::New();
@@ -97,7 +103,39 @@
vtkSmartPointer<vtkFloatArray> spheresId = vtkSmartPointer<vtkFloatArray>::New();
spheresId->SetNumberOfComponents(1);
spheresId->SetName("id");
-
+
+#ifdef YADE_SPH
+ vtkSmartPointer<vtkFloatArray> spheresCsSPH = vtkSmartPointer<vtkFloatArray>::New();
+ spheresCsSPH->SetNumberOfComponents(1);
+ spheresCsSPH->SetName("SPH_Cs");
+
+ vtkSmartPointer<vtkFloatArray> spheresRhoSPH = vtkSmartPointer<vtkFloatArray>::New();
+ spheresRhoSPH->SetNumberOfComponents(1);
+ spheresRhoSPH->SetName("SPH_Rho");
+
+ vtkSmartPointer<vtkFloatArray> spheresPressSPH = vtkSmartPointer<vtkFloatArray>::New();
+ spheresPressSPH->SetNumberOfComponents(1);
+ spheresPressSPH->SetName("SPH_Press");
+
+ vtkSmartPointer<vtkFloatArray> spheresCoordNumbSPH = vtkSmartPointer<vtkFloatArray>::New();
+ spheresCoordNumbSPH->SetNumberOfComponents(1);
+ spheresCoordNumbSPH->SetName("SPH_Neigh");
+#endif
+
+#ifdef YADE_LIQMIGRATION
+ vtkSmartPointer<vtkFloatArray> spheresLiqVol = vtkSmartPointer<vtkFloatArray>::New();
+ spheresLiqVol->SetNumberOfComponents(1);
+ spheresLiqVol->SetName("Liq_Vol");
+
+ vtkSmartPointer<vtkFloatArray> spheresLiqVolIter = vtkSmartPointer<vtkFloatArray>::New();
+ spheresLiqVolIter->SetNumberOfComponents(1);
+ spheresLiqVolIter->SetName("Liq_VolIter");
+
+ vtkSmartPointer<vtkFloatArray> spheresLiqVolTotal = vtkSmartPointer<vtkFloatArray>::New();
+ spheresLiqVolTotal->SetNumberOfComponents(1);
+ spheresLiqVolTotal->SetName("Liq_VolTotal");
+#endif
+
vtkSmartPointer<vtkFloatArray> spheresMask = vtkSmartPointer<vtkFloatArray>::New();
spheresMask->SetNumberOfComponents(1);
spheresMask->SetName("mask");
@@ -240,7 +278,16 @@
vtkSmartPointer<vtkFloatArray> crackNorm = vtkSmartPointer<vtkFloatArray>::New();
crackNorm->SetNumberOfComponents(3);
crackNorm->SetName("crackNorm");
-
+
+#ifdef YADE_LIQMIGRATION
+ vtkSmartPointer<vtkFloatArray> liqVol = vtkSmartPointer<vtkFloatArray>::New();
+ liqVol->SetNumberOfComponents(1);
+ liqVol->SetName("liqVol");
+
+ vtkSmartPointer<vtkFloatArray> liqVolNorm = vtkSmartPointer<vtkFloatArray>::New();
+ liqVolNorm->SetNumberOfComponents(1);
+ liqVolNorm->SetName("liqVolNorm");
+#endif
// the same for newly created cracks
// vtkSmartPointer<vtkPoints> crackPosNew = vtkSmartPointer<vtkPoints>::New();
// vtkSmartPointer<vtkCellArray> crackCellsNew = vtkSmartPointer<vtkCellArray>::New();
@@ -347,11 +394,16 @@
intrIsCohesive->InsertNextValue(jcfpmphys->isCohesive);
intrIsOnJoint->InsertNextValue(jcfpmphys->isOnJoint);
intrForceN->InsertNextValue(fn);
- }
-
- else {
+ } else {
intrForceN->InsertNextValue(fn);
}
+#ifdef YADE_LIQMIGRATION
+ if (recActive[REC_LIQ]) {
+ const ViscElCapPhys* capphys = YADE_CAST<ViscElCapPhys*>(I->phys.get());
+ liqVol->InsertNextValue(capphys->Vb);
+ liqVolNorm->InsertNextValue(capphys->Vb/capphys->Vmax);
+ }
+#endif
}
}
}
@@ -414,7 +466,18 @@
damage->InsertNextValue(YADE_PTR_CAST<JCFpmState>(b->state)->tensBreak + YADE_PTR_CAST<JCFpmState>(b->state)->shearBreak);
damageRel->InsertNextValue(YADE_PTR_CAST<JCFpmState>(b->state)->tensBreakRel + YADE_PTR_CAST<JCFpmState>(b->state)->shearBreakRel);
}
-
+#ifdef YADE_SPH
+ spheresCsSPH->InsertNextValue(b->Cs);
+ spheresRhoSPH->InsertNextValue(b->rho);
+ spheresPressSPH->InsertNextValue(b->press);
+ spheresCoordNumbSPH->InsertNextValue(b->coordNumber());
+#endif
+#ifdef YADE_LIQMIGRATION
+ spheresLiqVol->InsertNextValue(b->Vf);
+ const Real tmpVolIter = liqVolIterBody(b);
+ spheresLiqVolIter->InsertNextValue(tmpVolIter);
+ spheresLiqVolTotal->InsertNextValue(tmpVolIter + b->Vf);
+#endif
if (recActive[REC_MATERIALID]) spheresMaterialId->InsertNextValue(b->material->id);
continue;
}
@@ -550,6 +613,17 @@
spheresUg->GetPointData()->AddArray(spheresLinVelLen);
spheresUg->GetPointData()->AddArray(spheresAngVelLen);
}
+#ifdef YADE_SPH
+ spheresUg->GetPointData()->AddArray(spheresCsSPH);
+ spheresUg->GetPointData()->AddArray(spheresRhoSPH);
+ spheresUg->GetPointData()->AddArray(spheresPressSPH);
+ spheresUg->GetPointData()->AddArray(spheresCoordNumbSPH);
+#endif
+#ifdef YADE_LIQMIGRATION
+ spheresUg->GetPointData()->AddArray(spheresLiqVol);
+ spheresUg->GetPointData()->AddArray(spheresLiqVolIter);
+ spheresUg->GetPointData()->AddArray(spheresLiqVolTotal);
+#endif
if (recActive[REC_STRESS]){
spheresUg->GetPointData()->AddArray(spheresNormalStressVec);
spheresUg->GetPointData()->AddArray(spheresShearStressVec);
@@ -563,6 +637,7 @@
if (recActive[REC_JCFPM]) {
spheresUg->GetPointData()->AddArray(damage);
}
+
if (recActive[REC_MATERIALID]) spheresUg->GetPointData()->AddArray(spheresMaterialId);
#ifdef YADE_VTK_MULTIBLOCK
@@ -644,6 +719,12 @@
intrPd->SetLines(intrCells);
intrPd->GetCellData()->AddArray(intrForceN);
intrPd->GetCellData()->AddArray(intrAbsForceT);
+#ifdef YADE_LIQMIGRATION
+ if (recActive[REC_LIQ]) {
+ intrPd->GetCellData()->AddArray(liqVol);
+ intrPd->GetCellData()->AddArray(liqVolNorm);
+ }
+#endif
if (recActive[REC_JCFPM]) {
intrPd->GetCellData()->AddArray(intrIsCohesive);
intrPd->GetCellData()->AddArray(intrIsOnJoint);
=== modified file 'pkg/dem/VTKRecorder.hpp'
--- pkg/dem/VTKRecorder.hpp 2014-01-16 14:57:09 +0000
+++ pkg/dem/VTKRecorder.hpp 2014-05-08 05:57:04 +0000
@@ -11,7 +11,7 @@
class VTKRecorder: public PeriodicEngine {
public:
- enum {REC_SPHERES=0,REC_FACETS,REC_BOXES,REC_COLORS,REC_MASS,REC_CPM,REC_INTR,REC_VELOCITY,REC_ID,REC_CLUMPID,REC_SENTINEL,REC_MATERIALID,REC_STRESS,REC_MASK,REC_RPM,REC_JCFPM,REC_CRACKS,REC_WPM,REC_PERICELL};
+ enum {REC_SPHERES=0,REC_FACETS,REC_BOXES,REC_COLORS,REC_MASS,REC_CPM,REC_INTR,REC_VELOCITY,REC_ID,REC_CLUMPID,REC_SENTINEL,REC_MATERIALID,REC_STRESS,REC_MASK,REC_RPM,REC_JCFPM,REC_CRACKS,REC_WPM,REC_PERICELL,REC_LIQ};
virtual void action();
void addWallVTK (vtkSmartPointer<vtkQuad>& boxes, vtkSmartPointer<vtkPoints>& boxesPos, Vector3r& W1, Vector3r& W2, Vector3r& W3, Vector3r& W4);
YADE_CLASS_BASE_DOC_ATTRS_CTOR(VTKRecorder,PeriodicEngine,"Engine recording snapshots of simulation into series of \\*.vtu files, readable by VTK-based postprocessing programs such as Paraview. Both bodies (spheres and facets) and interactions can be recorded, with various vector/scalar quantities that are defined on them.\n\n:yref:`PeriodicEngine.initRun` is initialized to ``True`` automatically.",
=== modified file 'pkg/dem/ViscoelasticCapillarPM.cpp'
--- pkg/dem/ViscoelasticCapillarPM.cpp 2014-01-30 08:09:44 +0000
+++ pkg/dem/ViscoelasticCapillarPM.cpp 2014-05-08 05:57:04 +0000
@@ -1,147 +1,545 @@
-#include"ViscoelasticPM.hpp"
+#include"ViscoelasticCapillarPM.hpp"
#include<yade/core/State.hpp>
#include<yade/pkg/dem/ScGeom.hpp>
#include<yade/core/Omega.hpp>
#include<yade/core/Scene.hpp>
#include<yade/pkg/common/Sphere.hpp>
-Real Law2_ScGeom_ViscElPhys_Basic::calculateCapillarForce(const ScGeom& geom, ViscElPhys& phys) {
- Real fC = 0.0;
-
- /* Capillar
- * Some equations have constants, which can be calculated only once per contact.
- * No need to recalculate them at each step.
- * It needs to be fixed.
- *
- */
-
- if (phys.CapillarType == Weigert) {
- /* Capillar model from [Weigert1999]
- */
- Real R = phys.R;
- Real a = -geom.penetrationDepth;
- Real Ca = (1.0 + 6.0*a/(R*2.0)); // [Weigert1999], equation (16)
- Real Ct = (1.0 + 1.1*sin(phys.theta)); // [Weigert1999], equation (17)
-
- /*
- Real Eps = 0.36; // Porosity
- Real fi = phys.Vb/(2.0*M_PI/6.0*pow(R*2.0,3.)); // [Weigert1999], equation (13)
- Real S = M_PI*(1-Eps)/(pow(Eps, 2.0))*fi; // [Weigert1999], equation (14)
- Real beta = asin(pow(((S/0.36)*(pow(Eps, 2.0)/(1-Eps))*(1.0/Ca)*(1.0/Ct)), 1.0/4.0)); // [Weigert1999], equation (19)
- */
-
- Real beta = asin(pow(phys.Vb/(0.12*Ca*Ct*pow(2.0*R, 3.0)), 1.0/4.0)); // [Weigert1999], equation (15), against Vb
-
- Real r1 = (2.0*R*(1-cos(beta)) + a)/(2.0*cos(beta+phys.theta)); // [Weigert1999], equation (5)
- Real r2 = R*sin(beta) + r1*(sin(beta+phys.theta)-1); // [Weigert1999], equation (6)
- Real Pk = phys.gamma*(1/r1 - 1/r2); /* [Weigert1999], equation (22),
- * see also a sentence over the equation
- * "R1 was taken as positive and R2 was taken as negative"
- */
-
- //fC = M_PI*2.0*R*phys.gamma/(1+tan(0.5*beta)); // [Weigert1999], equation (23), [Fisher]
-
- fC = M_PI/4.0*pow((2.0*R),2.0)*pow(sin(beta),2.0)*Pk +
- phys.gamma*M_PI*2.0*R*sin(beta)*sin(beta+phys.theta); // [Weigert1999], equation (21)
-
- } else if (phys.CapillarType == Willett_numeric) {
-
- /* Capillar model from [Willett2000]
- */
-
- Real R = phys.R;
- Real s = -geom.penetrationDepth;
- Real Vb = phys.Vb;
-
- Real VbS = Vb/(R*R*R);
- Real Th1 = phys.theta;
- Real Th2 = phys.theta*phys.theta;
- Real Gamma = phys.gamma;
-
- /*
- * [Willett2000], equations in Anhang
- */
- Real f1 = (-0.44507 + 0.050832*Th1 - 1.1466*Th2) +
- (-0.1119 - 0.000411*Th1 - 0.1490*Th2) * log(VbS) +
- (-0.012101 - 0.0036456*Th1 - 0.01255*Th2) *log(VbS)*log(VbS) +
- (-0.0005 - 0.0003505*Th1 - 0.00029076*Th2) *log(VbS)*log(VbS)*log(VbS);
-
- Real f2 = (1.9222 - 0.57473*Th1 - 1.2918*Th2) +
- (-0.0668 - 0.1201*Th1 - 0.22574*Th2) * log(VbS) +
- (-0.0013375 - 0.0068988*Th1 - 0.01137*Th2) *log(VbS)*log(VbS);
-
- Real f3 = (1.268 - 0.01396*Th1 - 0.23566*Th2) +
- (0.198 + 0.092*Th1 - 0.06418*Th2) * log(VbS) +
- (0.02232 + 0.02238*Th1 - 0.009853*Th2) *log(VbS)*log(VbS) +
- (0.0008585 + 0.001318*Th1 - 0.00053*Th2) *log(VbS)*log(VbS)*log(VbS);
-
- Real f4 = (-0.010703 + 0.073776*Th1 - 0.34742*Th2) +
- (0.03345 + 0.04543*Th1 - 0.09056*Th2) * log(VbS) +
- (0.0018574 + 0.004456*Th1 - 0.006257*Th2) *log(VbS)*log(VbS);
-
- Real sPl = (s/2.0)/sqrt(Vb/R);
-
- Real lnFS = f1 - f2*exp(f3*log(sPl) + f4*log(sPl)*log(sPl));
- Real FS = exp(lnFS);
-
- fC = FS * 2.0 * M_PI* R * Gamma;
- } else if (phys.CapillarType == Willett_analytic) {
- /* Capillar model from Willet [Willett2000] (analytical solution), but
- * used also in the work of Herminghaus [Herminghaus2005]
- */
-
- Real R = phys.R;
- Real Gamma = phys.gamma;
- Real s = -geom.penetrationDepth;
- Real Vb = phys.Vb;
-
- /*
-
- Real sPl = s/sqrt(Vb/R); // [Herminghaus2005], equation (sentence between (7) and (8))
- fC = 2.0 * M_PI* R * Gamma * cos(phys.theta)/(1 + 1.05*sPl + 2.5 *sPl * sPl); // [Herminghaus2005], equation (7)
-
- */
-
- Real sPl = (s/2.0)/sqrt(Vb/R); // [Willett2000], equation (sentence after (11)), s - half-separation, so s*2.0
- Real f_star = cos(phys.theta)/(1 + 2.1*sPl + 10.0 * pow(sPl, 2.0)); // [Willett2000], equation (12)
- fC = f_star * (2*M_PI*R*Gamma); // [Willett2000], equation (13), against F
-
- } else if ((phys.CapillarType == Rabinovich) or (phys.CapillarType == Lambert)) {
- /*
- * Capillar model from Rabinovich [Rabinov2005]
- *
- * This formulation from Rabinovich has been later verified and corrected
- * by Lambert [Lambert2008]. So we can calculate both formulations
- *
- */
-
- Real R = phys.R;
- Real Gamma = phys.gamma;
- Real H = -geom.penetrationDepth;
- Real V = phys.Vb;
-
- Real dsp = 0.0;
- if (H!=0.0) {
- dsp = H/2.0*(-1.0 + sqrt(1.0 + 2.0*V/(M_PI*R*H*H))); // [Rabinov2005], equation (20)
- fC = -(2*M_PI*R*Gamma*cos(phys.theta))/(1+(H/(2*dsp))); // [Lambert2008], equation (65), taken from [Rabinov2005]
-
- if (phys.CapillarType == Rabinovich) {
- const Real alpha = sqrt(H/R*(-1+ sqrt(1 + 2.0*V/(M_PI*R*H*H)))); // [Rabinov2005], equation (A3)
- fC -= 2*M_PI*R*Gamma*sin(alpha)*sin(phys.theta + alpha); // [Rabinov2005], equation (19)
- }
- } else {
- fC = -(2*M_PI*R*Gamma*cos(phys.theta));
-
- if (phys.CapillarType == Rabinovich) {
- const Real alpha = 0.0;
- fC -= 2*M_PI*R*Gamma*sin(alpha)*sin(phys.theta + alpha); // [Rabinov2005], equation (19)
- }
+YADE_PLUGIN((ViscElCapMat)(ViscElCapPhys)(Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys)(Law2_ScGeom_ViscElCapPhys_Basic));
+
+/* ViscElCapMat */
+ViscElCapMat::~ViscElCapMat(){}
+
+/* ViscElCapPhys */
+ViscElCapPhys::~ViscElCapPhys(){}
+
+/* Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys */
+void Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys::go(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction) {
+ // no updates of an existing contact
+ if(interaction->phys) return;
+
+ shared_ptr<ViscElCapPhys> phys (new ViscElCapPhys());
+ Calculate_ViscElMat_ViscElMat_ViscElPhys(b1, b2, interaction, phys);
+
+ ViscElCapMat* mat1 = static_cast<ViscElCapMat*>(b1.get());
+ ViscElCapMat* mat2 = static_cast<ViscElCapMat*>(b2.get());
+
+ if (mat1->Capillar and mat2->Capillar) {
+ if (mat1->Vb == mat2->Vb) {
+ phys->Vb = mat1->Vb;
+ } else {
+ throw runtime_error("Vb should be equal for both particles!.");
+ }
+
+ if (mat1->gamma == mat2->gamma) {
+ phys->gamma = mat1->gamma;
+ } else {
+ throw runtime_error("Gamma should be equal for both particles!.");
+ }
+
+ if (mat1->theta == mat2->theta) {
+ phys->theta = (mat1->theta*M_PI/180.0);
+ } else {
+ throw runtime_error("Theta should be equal for both particles!.");
+ }
+
+ if (mat1->CapillarType == mat2->CapillarType and mat2->CapillarType != ""){
+
+ if (mat1->CapillarType == "Willett_numeric") {phys->CapillarType = Willett_numeric; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::Willett_numeric_f;}
+ else if (mat1->CapillarType == "Willett_analytic") {phys->CapillarType = Willett_analytic; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::Willett_analytic_f;}
+ else if (mat1->CapillarType == "Weigert") {phys->CapillarType = Weigert; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::Weigert_f;}
+ else if (mat1->CapillarType == "Rabinovich") {phys->CapillarType = Rabinovich; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::Rabinovich_f;}
+ else if (mat1->CapillarType == "Lambert") {phys->CapillarType = Lambert; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::Lambert_f;}
+ else if (mat1->CapillarType == "Soulie") {phys->CapillarType = Soulie; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::Soulie_f;}
+ else {phys->CapillarType = None_Capillar; phys->CapFunct = Law2_ScGeom_ViscElCapPhys_Basic::None_f;}
+ } else {
+ throw runtime_error("CapillarType should be equal for both particles!.");
+ }
+ phys->Capillar=true;
+ }
+
+ interaction->phys = phys;
+}
+
+/* Law2_ScGeom_ViscElCapPhys_Basic */
+void Law2_ScGeom_ViscElCapPhys_Basic::go(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I) {
+ Vector3r force = Vector3r::Zero();
+
+ const int id1 = I->getId1();
+ const int id2 = I->getId2();
+
+ const ScGeom& geom=*static_cast<ScGeom*>(_geom.get());
+ Scene* scene=Omega::instance().getScene().get();
+ ViscElCapPhys& phys=*static_cast<ViscElCapPhys*>(_phys.get());
+ const BodyContainer& bodies = *scene->bodies;
+
+ /*
+ * This part for implementation of the capillar model.
+ * All main equations are in calculateCapillarForce function.
+ * There is only the determination of critical distance between spheres,
+ * after that the liquid bridge will be broken.
+ */
+
+ if (not(phys.liqBridgeCreated) and phys.Capillar and geom.penetrationDepth>=0) {
+ phys.liqBridgeCreated = true;
+ phys.liqBridgeActive = false;
+ #ifdef YADE_LIQMIGRATION
+ scene->addIntrs.push_back(I);
+ #endif
+ Sphere* s1=dynamic_cast<Sphere*>(bodies[id1]->shape.get());
+ Sphere* s2=dynamic_cast<Sphere*>(bodies[id2]->shape.get());
+ if (s1 and s2) {
+ phys.R = 2 * s1->radius * s2->radius / (s1->radius + s2->radius);
+ } else if (s1 and not(s2)) {
+ phys.R = s1->radius;
+ } else {
+ phys.R = s2->radius;
+ }
+ }
+
+ phys.sCrit = this->critDist(phys.Vb, phys.R, phys.theta);
+
+ if (geom.penetrationDepth<0) {
+ if (phys.liqBridgeCreated and -geom.penetrationDepth<phys.sCrit and phys.Capillar) {
+ if (not(phys.liqBridgeActive)) {
+ phys.liqBridgeActive=true;
+ VLiqBridg += phys.Vb;
+ NLiqBridg += 1;
+ }
+ phys.normalForce = -phys.CapFunct(geom, phys)*geom.normal;
+ if (I->isActive) {
+ addForce (id1,-phys.normalForce,scene);
+ addForce (id2, phys.normalForce,scene);
+ };
+ return;
+ } else {
+ if (phys.liqBridgeActive) {
+ VLiqBridg -= phys.Vb;
+ NLiqBridg -= 1;
+ }
+ #ifdef YADE_LIQMIGRATION
+ const intReal B1={id1, phys.Vb/2.0};
+ const intReal B2={id2, phys.Vb/2.0};
+ scene->delIntrs.push_back(B1);
+ scene->delIntrs.push_back(B2);
+ #endif
+ scene->interactions->requestErase(I);
+ return;
+ };
+ };
+
+ if (phys.liqBridgeActive) {
+ phys.liqBridgeActive=false;
+ VLiqBridg -= phys.Vb;
+ NLiqBridg -= 1;
+ }
+
+ if (I->isActive) {
+
+ Vector3r torque1 = Vector3r::Zero();
+ Vector3r torque2 = Vector3r::Zero();
+
+ computeForceTorqueViscEl(_geom, _phys, I, force, torque1, torque2);
+
+ addForce (id1,-force,scene);
+ addForce (id2, force,scene);
+ addTorque(id1, torque1,scene);
+ addTorque(id2, torque2,scene);
+ }
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::critDist(const Real& Vb, const Real& R, const Real& Theta) {
+ const Real Vstar = Vb/(R*R*R);
+ const Real Sstar = (1+0.5*Theta)*(pow(Vstar,1/3.0) + 0.1*pow(Vstar,2.0/3.0)); // [Willett2000], equation (15), use the full-length e.g 2*Sc
+ const Real critDist = Sstar*R;
+ return critDist;
+}
+
+//=========================================================================================
+//======================Capillary bridge models============================================
+//=========================================================================================
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::Willett_numeric_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ /*
+ * Capillar model from [Willett2000]
+ */
+
+ const Real R = phys.R;
+ const Real s = -geom.penetrationDepth;
+ const Real Vb = phys.Vb;
+
+ const Real VbS = Vb/(R*R*R);
+ const Real Th1 = phys.theta;
+ const Real Th2 = phys.theta*phys.theta;
+ const Real Gamma = phys.gamma;
+
+ /*
+ * [Willett2000], equations in Attachment
+ */
+ const Real f1 = (-0.44507 + 0.050832*Th1 - 1.1466*Th2) +
+ (-0.1119 - 0.000411*Th1 - 0.1490*Th2) * log(VbS) +
+ (-0.012101 - 0.0036456*Th1 - 0.01255*Th2) *log(VbS)*log(VbS) +
+ (-0.0005 - 0.0003505*Th1 - 0.00029076*Th2) *log(VbS)*log(VbS)*log(VbS);
+
+ const Real f2 = (1.9222 - 0.57473*Th1 - 1.2918*Th2) +
+ (-0.0668 - 0.1201*Th1 - 0.22574*Th2) * log(VbS) +
+ (-0.0013375 - 0.0068988*Th1 - 0.01137*Th2) *log(VbS)*log(VbS);
+
+ const Real f3 = (1.268 - 0.01396*Th1 - 0.23566*Th2) +
+ (0.198 + 0.092*Th1 - 0.06418*Th2) * log(VbS) +
+ (0.02232 + 0.02238*Th1 - 0.009853*Th2) *log(VbS)*log(VbS) +
+ (0.0008585 + 0.001318*Th1 - 0.00053*Th2) *log(VbS)*log(VbS)*log(VbS);
+
+ const Real f4 = (-0.010703 + 0.073776*Th1 - 0.34742*Th2) +
+ (0.03345 + 0.04543*Th1 - 0.09056*Th2) * log(VbS) +
+ (0.0018574 + 0.004456*Th1 - 0.006257*Th2) *log(VbS)*log(VbS);
+
+ const Real sPl = (s/2.0)/sqrt(Vb/R);
+
+ const Real lnFS = f1 - f2*exp(f3*log(sPl) + f4*log(sPl)*log(sPl));
+ const Real FS = exp(lnFS);
+
+ const Real fC = FS * 2.0 * M_PI* R * Gamma;
+ return fC;
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::Willett_analytic_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ /*
+ * Capillar model from Willet [Willett2000] (analytical solution), but
+ * used also in the work of Herminghaus [Herminghaus2005]
+ */
+
+ const Real R = phys.R;
+ const Real Gamma = phys.gamma;
+ const Real s = -geom.penetrationDepth;
+ const Real Vb = phys.Vb;
+
+ /*
+ Real sPl = s/sqrt(Vb/R); // [Herminghaus2005], equation (sentence between (7) and (8))
+ fC = 2.0 * M_PI* R * Gamma * cos(phys.theta)/(1 + 1.05*sPl + 2.5 *sPl * sPl); // [Herminghaus2005], equation (7)
+ */
+
+ const Real sPl = (s/2.0)/sqrt(Vb/R); // [Willett2000], equation (sentence after (11)), s - half-separation, so s*2.0
+ const Real f_star = cos(phys.theta)/(1 + 2.1*sPl + 10.0 * pow(sPl, 2.0)); // [Willett2000], equation (12)
+ const Real fC = f_star * (2*M_PI*R*Gamma); // [Willett2000], equation (13), against F
+
+ return fC;
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::Weigert_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ /*
+ * Capillar model from [Weigert1999]
+ */
+ const Real R = phys.R;
+ const Real a = -geom.penetrationDepth;
+ const Real Ca = (1.0 + 6.0*a/(R*2.0)); // [Weigert1999], equation (16)
+ const Real Ct = (1.0 + 1.1*sin(phys.theta)); // [Weigert1999], equation (17)
+
+ /*
+ Real Eps = 0.36; // Porosity
+ Real fi = phys.Vb/(2.0*M_PI/6.0*pow(R*2.0,3.)); // [Weigert1999], equation (13)
+ Real S = M_PI*(1-Eps)/(pow(Eps, 2.0))*fi; // [Weigert1999], equation (14)
+ Real beta = asin(pow(((S/0.36)*(pow(Eps, 2.0)/(1-Eps))*(1.0/Ca)*(1.0/Ct)), 1.0/4.0)); // [Weigert1999], equation (19)
+ */
+
+ const Real beta = asin(pow(phys.Vb/(0.12*Ca*Ct*pow(2.0*R, 3.0)), 1.0/4.0)); // [Weigert1999], equation (15), against Vb
+
+ const Real r1 = (2.0*R*(1-cos(beta)) + a)/(2.0*cos(beta+phys.theta)); // [Weigert1999], equation (5)
+ const Real r2 = R*sin(beta) + r1*(sin(beta+phys.theta)-1); // [Weigert1999], equation (6)
+ const Real Pk = phys.gamma*(1/r1 - 1/r2); // [Weigert1999], equation (22),
+ // see also a sentence over the equation
+ // "R1 was taken as positive and R2 was taken as negative"
+
+ //fC = M_PI*2.0*R*phys.gamma/(1+tan(0.5*beta)); // [Weigert1999], equation (23), [Fisher]
+
+ const Real fC = M_PI/4.0*pow((2.0*R),2.0)*pow(sin(beta),2.0)*Pk +
+ phys.gamma*M_PI*2.0*R*sin(beta)*sin(beta+phys.theta); // [Weigert1999], equation (21)
+
+ return fC;
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::Rabinovich_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ /*
+ * Capillar model from Rabinovich [Rabinov2005]
+ *
+ * This formulation from Rabinovich has been later verified and corrected
+ * by Lambert [Lambert2008]. So we can calculate both formulations
+ *
+ */
+
+ const Real R = phys.R;
+ const Real Gamma = phys.gamma;
+ const Real H = -geom.penetrationDepth;
+ const Real V = phys.Vb;
+
+ Real fC = 0.0;
+ Real dsp = 0.0;
+
+ if (H!=0.0) {
+ dsp = H/2.0*(-1.0 + sqrt(1.0 + 2.0*V/(M_PI*R*H*H))); // [Rabinov2005], equation (20)
+ fC = -(2*M_PI*R*Gamma*cos(phys.theta))/(1+(H/(2*dsp))); // [Lambert2008], equation (65), taken from [Rabinov2005]
+ const Real alpha = sqrt(H/R*(-1+ sqrt(1 + 2.0*V/(M_PI*R*H*H)))); // [Rabinov2005], equation (A3)
+ fC -= 2*M_PI*R*Gamma*sin(alpha)*sin(phys.theta + alpha); // [Rabinov2005], equation (19)
+ } else {
+ fC = -(2*M_PI*R*Gamma*cos(phys.theta));
+ const Real alpha = 0.0;
+ fC -= 2*M_PI*R*Gamma*sin(alpha)*sin(phys.theta + alpha); // [Rabinov2005], equation (19)
+ }
+
+ fC *=-1;
+ return fC;
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::Lambert_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ /*
+ * Capillar model from Rabinovich [Rabinov2005]
+ *
+ * This formulation from Rabinovich has been later verified and corrected
+ * by Lambert [Lambert2008]. So we can calculate both formulations
+ *
+ */
+
+ const Real R = phys.R;
+ const Real Gamma = phys.gamma;
+ const Real H = -geom.penetrationDepth;
+ const Real V = phys.Vb;
+
+ Real fC = 0.0;
+ Real dsp = 0.0;
+
+ if (H!=0.0) {
+ dsp = H/2.0*(-1.0 + sqrt(1.0 + 2.0*V/(M_PI*R*H*H))); // [Rabinov2005], equation (20)
+ fC = -(2*M_PI*R*Gamma*cos(phys.theta))/(1+(H/(2*dsp))); // [Lambert2008], equation (65), taken from [Rabinov2005]
+ } else {
+ fC = -(2*M_PI*R*Gamma*cos(phys.theta));
+ }
+
+ fC *=-1;
+ return fC;
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::Soulie_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ /*
+ * Capillar model from Soulie [Soulie2006]
+ *
+ * !!! In this implementation the radiis of particles are taken equal
+ * to get the symmetric forces.
+ *
+ * Please, use this model only for testing purposes.
+ *
+ */
+
+ const Real R = phys.R;
+ const Real Gamma = phys.gamma;
+ const Real D = -geom.penetrationDepth;
+ const Real V = phys.Vb;
+ const Real Theta = phys.theta;
+
+ const Real a = -1.1*pow((V/(R*R*R)), -0.53);
+ const Real b = (-0.148*log(V/(R*R*R)) - 0.96)*Theta*Theta -0.0082*log(V/(R*R*R)) + 0.48;
+ const Real c = 0.0018*log(V/(R*R*R)) + 0.078;
+
+ const Real fC = Mathr::PI*Gamma*sqrt(R*R)*(c+exp(a*D/R+b));
+
+ return fC;
+}
+
+Real Law2_ScGeom_ViscElCapPhys_Basic::None_f(const ScGeom& geom, ViscElCapPhys& phys) {
+ return 0;
+}
+
+#ifdef YADE_LIQMIGRATION
+YADE_PLUGIN((LiqControl));
+void LiqControl::action(){
+ // This function implements liquid migration model, introduced here [Mani2013]
+ mapBodyInt bI;
+ mapBodyInt bodyNeedUpdate;
+
+ // Calculate, how much new contacts will be at each body
+ for (unsigned int i=0; i<scene->addIntrs.size(); i++) {
+ addBodyMapInt( bI, scene->addIntrs[i]->getId1() );
+ addBodyMapInt( bI, scene->addIntrs[i]->getId2() );
+ }
+
+ // Update volume water at each deleted interaction for each body
+ for (unsigned int i=0; i<scene->delIntrs.size(); i++) {
+ shared_ptr<Body> b = Body::byId(scene->delIntrs[i].id,scene);
+ b->Vf += scene->delIntrs[i].Vol;
+ addBodyMapInt(bodyNeedUpdate, scene->delIntrs[i].id);
+ liqVolRup += scene->delIntrs[i].Vol;
+ }
+ scene->delIntrs.clear();
+
+ // Update volume bridge at each new added interaction
+ mapBodyReal bodyUpdateLiquid;
+ for (unsigned int i=0; i<scene->addIntrs.size(); i++) {
+ shared_ptr<Body> b1 = Body::byId(scene->addIntrs[i]->getId1(),scene);
+ shared_ptr<Body> b2 = Body::byId(scene->addIntrs[i]->getId2(),scene);
+
+ const id_t id1 = b1->id;
+ const id_t id2 = b2->id;
+
+ ViscElCapPhys* Vb=dynamic_cast<ViscElCapPhys*>(scene->addIntrs[i]->phys.get());
+ const Real Vmax = vMax(b1, b2);
+ Vb->Vmax = Vmax;
+
+ Real Vf1 = 0.0;
+ Real Vf2 = 0.0;
+
+ if ((b1->Vmin)<b1->Vf) {
+ Vf1 = (b1->Vf - b1->Vmin)/bI[id1];
+ }
+
+ if ((b2->Vmin)<b2->Vf) {
+ Vf2 = (b2->Vf - b2->Vmin)/bI[id2];
+ }
+
+ Real Vrup = Vf1+Vf2;
+
+ if(mask!=0 && ((b1->groupMask & b2->groupMask & mask)==0)) {
+ Vf1 = 0;
+ Vf2 = 0;
+ Vrup = 0;
+ } else if (Vrup > Vmax) {
+ Vf1 *= Vmax/Vrup;
+ Vf2 *= Vmax/Vrup;
+ Vrup = Vf1 + Vf2;
+ }
+
+ liqVolShr += Vrup;
+ addBodyMapReal(bodyUpdateLiquid, id1, -Vf1);
+ addBodyMapReal(bodyUpdateLiquid, id2, -Vf2);
+
+ Vb->Vb = Vrup;
+ }
+
+ scene->addIntrs.clear();
+
+ // Update water volume in body
+ for (mapBodyReal::const_iterator it = bodyUpdateLiquid.begin(); it != bodyUpdateLiquid.end(); ++it) {
+ Body::byId(it->first)->Vf += it->second;
+ }
+
+ // Update contacts around body
+ for (mapBodyInt::const_iterator it = bodyNeedUpdate.begin(); it != bodyNeedUpdate.end(); ++it) {
+ updateLiquid(Body::byId(it->first));
+ }
+
+}
+
+void LiqControl::updateLiquid(shared_ptr<Body> b){
+ if (b->Vf<=b->Vmin) {
+ return;
+ } else {
+ // How much liquid can body share
+ const Real LiqCanBeShared = b->Vf - b->Vmin;
+
+ // Check how much liquid can accept contacts
+ Real LiqContactsAccept = 0.0;
+ unsigned int contactN = 0;
+ for(Body::MapId2IntrT::iterator it=b->intrs.begin(),end=b->intrs.end(); it!=end; ++it) {
+ if(!((*it).second) or !(((*it).second)->isReal())) continue;
+ ViscElCapPhys* physT=dynamic_cast<ViscElCapPhys*>(((*it).second)->phys.get());
+ if (physT->Vb<physT->Vmax) {
+ LiqContactsAccept+=physT->Vmax-physT->Vb;
+ contactN++;
+ }
+ }
+
+ if (contactN>0) {
+ //There are some contacts, which can be filled
+ Real FillLevel = 0.0;
+ if (LiqContactsAccept > LiqCanBeShared) { // Share all available liquid from body to contacts
+ const Real LiquidWillBeShared = b->Vf - b->Vmin;
+ b->Vf = b->Vmin;
+ FillLevel = LiquidWillBeShared/LiqContactsAccept;
+ } else { // Not all available liquid from body can be shared
+ b->Vf -= LiqContactsAccept;
+ FillLevel = 1.0;
+ }
+
+ for(Body::MapId2IntrT::iterator it=b->intrs.begin(),end=b->intrs.end(); it!=end; ++it) {
+ if(!((*it).second) or !(((*it).second)->isReal())) continue;
+ ViscElCapPhys* physT=dynamic_cast<ViscElCapPhys*>(((*it).second)->phys.get());
+ if (physT->Vb<physT->Vmax) {
+ liqVolShr += (physT->Vmax - physT->Vb)*FillLevel;
+ physT->Vb += (physT->Vmax - physT->Vb)*FillLevel;
}
-
- fC *=-1;
-
- } else {
- throw runtime_error("CapillarType is unknown, please, use only Willett_numeric, Willett_analytic, Weigert or Rabinovich");
}
- return fC;
-}
+ return;
+ } else {
+ return;
+ }
+ }
+}
+
+void LiqControl::addBodyMapInt( mapBodyInt & m, Body::id_t b ){
+ mapBodyInt::const_iterator got;
+ got = m.find (b);
+ if ( got == m.end() ) {
+ m.insert (mapBodyInt::value_type(b,1));
+ } else {
+ m[b] += 1;
+ }
+}
+
+void LiqControl::addBodyMapReal( mapBodyReal & m, Body::id_t b, Real addV ) {
+ mapBodyReal::const_iterator got;
+ got = m.find (b);
+ if ( got == m.end() ) {
+ m.insert (mapBodyReal::value_type(b, addV));
+ } else {
+ m[b] += addV;
+ }
+}
+
+Real LiqControl::vMax(shared_ptr<Body> const b1, shared_ptr<Body> const b2) {
+ Sphere* s1=dynamic_cast<Sphere*>(b1->shape.get());
+ Sphere* s2=dynamic_cast<Sphere*>(b2->shape.get());
+ Real minR = 0.0;
+ if (s1 and s2) {
+ minR = std::min (s1->radius, s2->radius);
+ } else if (s1 and not(s2)) {
+ minR = s1->radius;
+ } else {
+ minR = s2->radius;
+ }
+ return vMaxCoef*minR*minR*minR;
+}
+
+Real liqVolIterBody (shared_ptr<Body> b) {
+ Real LiqVol = 0.0;
+ for(Body::MapId2IntrT::iterator it=b->intrs.begin(),end=b->intrs.end(); it!=end; ++it) {
+ if(!((*it).second) or !(((*it).second)->isReal())) continue;
+ ViscElCapPhys* physT=dynamic_cast<ViscElCapPhys*>(((*it).second)->phys.get());
+ if (physT->Vb>0) {
+ LiqVol += physT->Vb/2.0;
+ }
+ }
+ return LiqVol;
+}
+
+Real LiqControl::liqVolBody (id_t id) const {
+ Scene* scene=Omega::instance().getScene().get();
+ const BodyContainer& bodies = *scene->bodies;
+ if (id >=0 and bodies[id]) {
+ if (bodies[id]->Vf > 0) {
+ return bodies[id]->Vf + liqVolIterBody(bodies[id]);
+ } else {
+ return liqVolIterBody(bodies[id]);
+ }
+ }
+ else return -1;
+}
+
+Real LiqControl::totalLiqVol(int mask=0) const{
+ Scene* scene=Omega::instance().getScene().get();
+ Real totalLiqVol = 0.0;
+ FOREACH(const shared_ptr<Body>& b, *scene->bodies){
+ if((mask>0 && (b->groupMask & mask)==0) or (!b)) continue;
+ totalLiqVol += liqVolIterBody(b);
+ if (b->Vf > 0) {totalLiqVol +=b->Vf;}
+ }
+ return totalLiqVol;
+}
+#endif
=== added file 'pkg/dem/ViscoelasticCapillarPM.hpp'
--- pkg/dem/ViscoelasticCapillarPM.hpp 1970-01-01 00:00:00 +0000
+++ pkg/dem/ViscoelasticCapillarPM.hpp 2014-05-08 05:57:04 +0000
@@ -0,0 +1,107 @@
+#include"ViscoelasticPM.hpp"
+#include <boost/unordered_map.hpp>
+
+class ViscElCapMat : public ViscElMat {
+ public:
+ virtual ~ViscElCapMat();
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR(ViscElCapMat,ViscElMat,"Material for extended viscoelastic model of contact with capillary parameters.",
+ ((bool,Capillar,false,,"True, if capillar forces need to be added."))
+ ((Real,Vb,NaN,,"Liquid bridge volume [m^3]"))
+ ((Real,gamma,NaN,,"Surface tension [N/m]"))
+ ((Real,theta,NaN,,"Contact angle [°]"))
+ ((std::string,CapillarType,"",,"Different types of capillar interaction: Willett_numeric, Willett_analytic [Willett2000]_ , Weigert [Weigert1999]_ , Rabinovich [Rabinov2005]_ , Lambert (simplified, corrected Rabinovich model) [Lambert2008]_ ")),
+ createIndex();
+ );
+ REGISTER_CLASS_INDEX(ViscElCapMat,ViscElMat);
+};
+REGISTER_SERIALIZABLE(ViscElCapMat);
+
+/// Interaction physics
+enum CapType {None_Capillar, Willett_numeric, Willett_analytic, Weigert, Rabinovich, Lambert, Soulie};
+class ViscElCapPhys : public ViscElPhys{
+ typedef Real (* CapillarFunction)(const ScGeom& geom, ViscElCapPhys& phys);
+ public:
+ virtual ~ViscElCapPhys();
+ Real R;
+ CapillarFunction CapFunct;
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR(ViscElCapPhys,ViscElPhys,"IPhys created from :yref:`ViscElCapMat`, for use with :yref:`Law2_ScGeom_ViscElCapPhys_Basic`.",
+ ((bool,Capillar,false,,"True, if capillar forces need to be added."))
+ ((bool,liqBridgeCreated,false,,"Whether liquid bridge was created, only after a normal contact of spheres"))
+ ((bool,liqBridgeActive,false,, "Whether liquid bridge is active at the moment"))
+ ((Real,sCrit,false,,"Critical bridge length [m]"))
+ ((Real,Vb,NaN,,"Liquid bridge volume [m^3]"))
+ ((Real,gamma,NaN,,"Surface tension [N/m]"))
+ ((Real,theta,NaN,,"Contact angle [rad]"))
+ ((CapType,CapillarType,None_Capillar,,"Different types of capillar interaction: Willett_numeric, Willett_analytic, Weigert, Rabinovich, Lambert, Soulie"))
+#ifdef YADE_LIQMIGRATION
+ ((Real,Vmax,-1,,"Maximal liquid bridge volume [m^3]"))
+#endif
+ ,
+ createIndex();
+ )
+ REGISTER_CLASS_INDEX(ViscElCapPhys,ViscElPhys);
+};
+REGISTER_SERIALIZABLE(ViscElCapPhys);
+
+/// Convert material to interaction physics.
+class Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys: public Ip2_ViscElMat_ViscElMat_ViscElPhys {
+ public :
+ virtual void go(const shared_ptr<Material>& b1,
+ const shared_ptr<Material>& b2,
+ const shared_ptr<Interaction>& interaction);
+ YADE_CLASS_BASE_DOC(Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys,Ip2_ViscElMat_ViscElMat_ViscElPhys,"Convert 2 instances of :yref:`ViscElCapMat` to :yref:`ViscElCapPhys` using the rule of consecutive connection.");
+ FUNCTOR2D(ViscElCapMat,ViscElCapMat);
+};
+REGISTER_SERIALIZABLE(Ip2_ViscElCapMat_ViscElCapMat_ViscElCapPhys);
+
+/// Constitutive law
+class Law2_ScGeom_ViscElCapPhys_Basic: public LawFunctor {
+ public :
+ virtual void go(shared_ptr<IGeom>&, shared_ptr<IPhys>&, Interaction*);
+ static Real Willett_numeric_f (const ScGeom& geom, ViscElCapPhys& phys);
+ static Real Willett_analytic_f (const ScGeom& geom, ViscElCapPhys& phys);
+ static Real Weigert_f (const ScGeom& geom, ViscElCapPhys& phys);
+ static Real Rabinovich_f (const ScGeom& geom, ViscElCapPhys& phys);
+ static Real Lambert_f (const ScGeom& geom, ViscElCapPhys& phys);
+ static Real Soulie_f (const ScGeom& geom, ViscElCapPhys& phys);
+ static Real None_f (const ScGeom& geom, ViscElCapPhys& phys);
+ Real critDist(const Real& Vb, const Real& R, const Real& Theta);
+ FUNCTOR2D(ScGeom,ViscElCapPhys);
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Law2_ScGeom_ViscElCapPhys_Basic,LawFunctor,"Extended version of Linear viscoelastic model with capillary parameters.",
+ ((OpenMPAccumulator<Real>,VLiqBridg,,Attr::noSave,"The total volume of liquid bridges"))
+ ((OpenMPAccumulator<int>, NLiqBridg,,Attr::noSave,"The total number of liquid bridges"))
+ ,/* ctor */
+ ,/* py */
+ ;
+ )
+ DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(Law2_ScGeom_ViscElCapPhys_Basic);
+
+#ifdef YADE_LIQMIGRATION
+typedef boost::unordered_map<Body::id_t, int> mapBodyInt;
+typedef boost::unordered_map<Body::id_t, Real> mapBodyReal;
+class LiqControl: public PartialEngine{
+ public:
+ virtual void action();
+ void addBodyMapInt( mapBodyInt & m, Body::id_t b );
+ void addBodyMapReal( mapBodyReal & m, Body::id_t b, Real addV );
+ Real vMax(shared_ptr<Body> b1, shared_ptr<Body> b2);
+ Real totalLiqVol(int mask) const;
+ Real liqVolBody(id_t id) const;
+ void updateLiquid(shared_ptr<Body> b);
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(LiqControl,PartialEngine,"This engine implements liquid migration model, introduced here [Mani2013]_ . ",
+ ((int,mask,0,, "Bitmask for liquid creation."))
+ ((Real,liqVolRup,0.,, "Liquid volume (integral value), which has been freed after rupture occured, [m^3]."))
+ ((Real,liqVolShr,0.,, "Liquid volume (integral value), which has been shared among of contacts, [m^3]."))
+ ((Real,vMaxCoef,0.03,, "Coefficient for vMax, [-]."))
+ ,/* ctor */
+ ,/* py */
+ .def("totalLiq",&LiqControl::totalLiqVol,(python::arg("mask")=0),"Return total volume of water in simulation.")
+ .def("liqBody",&LiqControl::liqVolBody,(python::arg("id")=-1),"Return total volume of water in body.")
+ );
+};
+
+Real liqVolIterBody (shared_ptr<Body> b);
+REGISTER_SERIALIZABLE(LiqControl);
+#endif
=== modified file 'pkg/dem/ViscoelasticPM.cpp'
--- pkg/dem/ViscoelasticPM.cpp 2014-02-07 18:20:02 +0000
+++ pkg/dem/ViscoelasticPM.cpp 2014-04-14 11:52:51 +0000
@@ -6,6 +6,10 @@
#include<yade/core/Scene.hpp>
#include<yade/pkg/common/Sphere.hpp>
+#ifdef YADE_SPH
+#include<yade/pkg/common/SPHEngine.hpp>
+#endif
+
YADE_PLUGIN((ViscElMat)(ViscElPhys)(Ip2_ViscElMat_ViscElMat_ViscElPhys)(Law2_ScGeom_ViscElPhys_Basic));
/* ViscElMat */
@@ -14,62 +18,219 @@
/* ViscElPhys */
ViscElPhys::~ViscElPhys(){}
-/* Contact parameter calculation function */
-Real Ip2_ViscElMat_ViscElMat_ViscElPhys::contactParameterCalculation(const Real& l1, const Real& l2, const bool& massMultiply){
- if (massMultiply) {
- // If one of paramaters > 0. we DO NOT return 0
- Real a = (l1?1/l1:0) + (l2?1/l2:0);
- if (a) return 1/a;
- else return 0;
- } else {
- // If one of paramaters > 0, we return 0
- return (l1>0 or l2>0)?l1*l2/(l1+l2):0;
- }
-}
-
/* Ip2_ViscElMat_ViscElMat_ViscElPhys */
void Ip2_ViscElMat_ViscElMat_ViscElPhys::go(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction) {
-
// no updates of an existing contact
if(interaction->phys) return;
+ shared_ptr<ViscElPhys> phys (new ViscElPhys());
+ Calculate_ViscElMat_ViscElMat_ViscElPhys(b1, b2, interaction, phys);
+ interaction->phys = phys;
+}
+
+/* Law2_ScGeom_ViscElPhys_Basic */
+void Law2_ScGeom_ViscElPhys_Basic::go(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I) {
+ Vector3r force = Vector3r::Zero();
+ Vector3r torque1 = Vector3r::Zero();
+ Vector3r torque2 = Vector3r::Zero();
+ if (computeForceTorqueViscEl(_geom, _phys, I, force, torque1, torque2) and (I->isActive)) {
+ const int id1 = I->getId1();
+ const int id2 = I->getId2();
+
+ addForce (id1,-force,scene);
+ addForce (id2, force,scene);
+ addTorque(id1, torque1,scene);
+ addTorque(id2, torque2,scene);
+ return;
+ } else {
+ scene->interactions->requestErase(I);
+ return;
+ }
+}
+
+bool computeForceTorqueViscEl(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I, Vector3r & force, Vector3r & torque1, Vector3r & torque2) {
+ ViscElPhys& phys=*static_cast<ViscElPhys*>(_phys.get());
+ const ScGeom& geom=*static_cast<ScGeom*>(_geom.get());
+ Scene* scene=Omega::instance().getScene().get();
+
+#ifdef YADE_SPH
+//=======================================================================================================
+ if (phys.SPHmode) {
+ if (computeForceSPH(_geom, _phys, I, force)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+//=======================================================================================================
+#endif
+
+ const int id1 = I->getId1();
+ const int id2 = I->getId2();
+
+ if (geom.penetrationDepth<0) {
+ return false;
+ } else {
+ const BodyContainer& bodies = *scene->bodies;
+
+ const State& de1 = *static_cast<State*>(bodies[id1]->state.get());
+ const State& de2 = *static_cast<State*>(bodies[id2]->state.get());
+
+ Vector3r& shearForce = phys.shearForce;
+ if (I->isFresh(scene)) shearForce=Vector3r(0,0,0);
+ const Real& dt = scene->dt;
+ shearForce = geom.rotate(shearForce);
+
+ // Handle periodicity.
+ const Vector3r shift2 = scene->isPeriodic ? scene->cell->intrShiftPos(I->cellDist): Vector3r::Zero();
+ const Vector3r shiftVel = scene->isPeriodic ? scene->cell->intrShiftVel(I->cellDist): Vector3r::Zero();
+
+ const Vector3r c1x = (geom.contactPoint - de1.pos);
+ const Vector3r c2x = (geom.contactPoint - de2.pos - shift2);
+
+ const Vector3r relativeVelocity = (de1.vel+de1.angVel.cross(c1x)) - (de2.vel+de2.angVel.cross(c2x)) + shiftVel;
+ const Real normalVelocity = geom.normal.dot(relativeVelocity);
+ const Vector3r shearVelocity = relativeVelocity-normalVelocity*geom.normal;
+
+ // As Chiara Modenese suggest, we store the elastic part
+ // and then add the viscous part if we pass the Mohr-Coulomb criterion.
+ // See http://www.mail-archive.com/yade-users@xxxxxxxxxxxxxxxxxxx/msg01391.html
+ shearForce += phys.ks*dt*shearVelocity; // the elastic shear force have a history, but
+ Vector3r shearForceVisc = Vector3r::Zero(); // the viscous shear damping haven't a history because it is a function of the instant velocity
+
+
+ // Prevent appearing of attraction forces due to a viscous component
+ // [Radjai2011], page 3, equation [1.7]
+ // [Schwager2007]
+ const Real normForceReal = phys.kn * geom.penetrationDepth + phys.cn * normalVelocity;
+ if (normForceReal < 0) {
+ phys.normalForce = Vector3r::Zero();
+ } else {
+ phys.normalForce = normForceReal * geom.normal;
+ }
+
+ Vector3r momentResistance = Vector3r::Zero();
+ if (phys.mR>0.0) {
+ const Vector3r relAngVel = de1.angVel - de2.angVel;
+ relAngVel.normalized();
+
+ if (phys.mRtype == 1) {
+ momentResistance = -phys.mR*phys.normalForce.norm()*relAngVel; // [Zhou1999536], equation (3)
+ } else if (phys.mRtype == 2) {
+ momentResistance = -phys.mR*(c1x.cross(de1.angVel) - c2x.cross(de2.angVel)).norm()*phys.normalForce.norm()*relAngVel; // [Zhou1999536], equation (4)
+ }
+ }
+
+ const Real maxFs = phys.normalForce.squaredNorm() * std::pow(phys.tangensOfFrictionAngle,2);
+ if( shearForce.squaredNorm() > maxFs )
+ {
+ // Then Mohr-Coulomb is violated (so, we slip),
+ // we have the max value of the shear force, so
+ // we consider only friction damping.
+ const Real ratio = sqrt(maxFs) / shearForce.norm();
+ shearForce *= ratio;
+ }
+ else
+ {
+ // Then no slip occurs we consider friction damping + viscous damping.
+ shearForceVisc = phys.cs*shearVelocity;
+ }
+ force = phys.normalForce + shearForce + shearForceVisc;
+ torque1 = -c1x.cross(force)+momentResistance;
+ torque2 = c2x.cross(force)-momentResistance;
+ return true;
+ }
+}
+
+void Ip2_ViscElMat_ViscElMat_ViscElPhys::Calculate_ViscElMat_ViscElMat_ViscElPhys(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction, shared_ptr<ViscElPhys> phys) {
ViscElMat* mat1 = static_cast<ViscElMat*>(b1.get());
ViscElMat* mat2 = static_cast<ViscElMat*>(b2.get());
Real mass1 = 1.0;
Real mass2 = 1.0;
- if (mat1->massMultiply and mat2->massMultiply) {
- mass1 = Body::byId(interaction->getId1())->state->mass;
- mass2 = Body::byId(interaction->getId2())->state->mass;
- if (mass1 == 0.0 and mass2 > 0.0) {
- mass1 = mass2;
- } else if (mass2 == 0.0 and mass1 > 0.0) {
- mass2 = mass1;
- }
+ if ((isfinite(mat1->kn) and not (isfinite(mat2->kn))) or
+ (isfinite(mat2->kn) and not (isfinite(mat1->kn))) or
+ (isfinite(mat1->ks) and not (isfinite(mat2->ks))) or
+ (isfinite(mat2->ks) and not (isfinite(mat1->ks))) or
+ (isfinite(mat1->cn) and not (isfinite(mat2->cn))) or
+ (isfinite(mat2->cn) and not (isfinite(mat1->cn))) or
+ (isfinite(mat1->cs) and not (isfinite(mat2->cs))) or
+ (isfinite(mat2->cs) and not (isfinite(mat1->cs))) or
+ (isfinite(mat1->tc) and not (isfinite(mat2->tc))) or
+ (isfinite(mat2->tc) and not (isfinite(mat1->tc))) or
+ (isfinite(mat1->en) and not (isfinite(mat2->en))) or
+ (isfinite(mat2->en) and not (isfinite(mat1->en))) or
+ (isfinite(mat1->et) and not (isfinite(mat2->et))) or
+ (isfinite(mat2->et) and not (isfinite(mat1->et)))) {
+ throw runtime_error("Both materials should have the same defined set of variables e.g. tc, ks etc.!");
+ }
+
+ mass1 = Body::byId(interaction->getId1())->state->mass;
+ mass2 = Body::byId(interaction->getId2())->state->mass;
+ if (mass1 == 0.0 and mass2 > 0.0) {
+ mass1 = mass2;
+ } else if (mass2 == 0.0 and mass1 > 0.0) {
+ mass2 = mass1;
}
+ const Real massR = 2*mass1*mass2/(mass1+mass2);
+
GenericSpheresContact* sphCont=YADE_CAST<GenericSpheresContact*>(interaction->geom.get());
Real R1=sphCont->refR1>0?sphCont->refR1:sphCont->refR2;
Real R2=sphCont->refR2>0?sphCont->refR2:sphCont->refR1;
- const Real kn1 = isnan(mat1->kn)?2*mat1->young*R1:mat1->kn*mass1;
- const Real cn1 = mat1->cn*mass1;
- const Real ks1 = isnan(mat1->ks)?kn1*mat1->poisson:mat1->ks*mass1;
- const Real cs1 = mat1->cs*mass1;
+ Real kn1 = 0.0; Real kn2 = 0.0;
+ Real cn1 = 0.0; Real cn2 = 0.0;
+ Real ks1 = 0.0; Real ks2 = 0.0;
+ Real cs1 = 0.0; Real cs2 = 0.0;
+
+ if (((isfinite(mat1->tc)) and (isfinite(mat1->en)) and (isfinite(mat1->et))) or ((tc) and (en) and (et))) {
+ //Set parameters according to [Pournin2001]
+
+ const Real Tc = (tc) ? (*tc)(mat1->id,mat2->id) : (mat1->tc+mat2->tc)/2.0;
+ const Real En = (en) ? (*en)(mat1->id,mat2->id) : (mat1->en+mat2->en)/2.0;
+ const Real Et = (et) ? (*et)(mat1->id,mat2->id) : (mat1->et+mat2->et)/2.0;
+
+ kn1 = kn2 = 1/Tc/Tc * ( Mathr::PI*Mathr::PI + pow(log(En),2) )*massR;
+ cn1 = cn2 = -2.0 /Tc * log(En)*massR;
+ ks1 = ks2 = 2.0/7.0 /Tc/Tc * ( Mathr::PI*Mathr::PI + pow(log(Et),2) )*massR;
+ cs1 = cs2 = -2.0/7.0 /Tc * log(Et)*massR;
+
+ if (abs(cn1) <= Mathr::ZERO_TOLERANCE ) cn1=0;
+ if (abs(cn2) <= Mathr::ZERO_TOLERANCE ) cn2=0;
+ if (abs(cs1) <= Mathr::ZERO_TOLERANCE ) cs1=0;
+ if (abs(cs2) <= Mathr::ZERO_TOLERANCE ) cs2=0;
+ } else if ((isfinite(mat1->kn)) and (isfinite(mat1->ks)) and (isfinite(mat1->cn)) and (isfinite(mat1->cs))) {
+ //Set parameters explicitly
+ kn1 = mat1->kn;
+ kn2 = mat2->kn;
+ ks1 = mat1->ks;
+ ks2 = mat2->ks;
+ cn1 = mat1->cn;
+ cn2 = mat2->cn;
+ cs1 = mat1->cs;
+ cs2 = mat2->cs;
+ } else {
+ //Set parameters on the base of young modulus
+ kn1 = 2*mat1->young*R1;
+ kn2 = 2*mat2->young*R2;
+ ks1 = kn1*mat1->poisson;
+ ks2 = kn2*mat2->poisson;
+ if ((isfinite(mat1->cn)) and (isfinite(mat1->cs))) {
+ cn1 = mat1->cn;
+ cn2 = mat2->cn;
+ cs1 = mat1->cs;
+ cs2 = mat2->cs;
+ }
+ }
const Real mR1 = mat1->mR; const Real mR2 = mat2->mR;
const int mRtype1 = mat1->mRtype; const int mRtype2 = mat2->mRtype;
- const Real kn2 = isnan(mat2->kn)?2*mat2->young*R2:mat2->kn*mass2;
- const Real cn2 = mat2->cn*mass2;
- const Real ks2 = isnan(mat2->ks)?kn2*mat2->poisson:mat2->ks*mass2;
- const Real cs2 = mat2->cs*mass2;
-
- ViscElPhys* phys = new ViscElPhys();
-
- phys->kn = contactParameterCalculation(kn1,kn2, mat1->massMultiply&&mat2->massMultiply);
- phys->ks = contactParameterCalculation(ks1,ks2, mat1->massMultiply&&mat2->massMultiply);
- phys->cn = contactParameterCalculation(cn1,cn2, mat1->massMultiply&&mat2->massMultiply);
- phys->cs = contactParameterCalculation(cs1,cs2, mat1->massMultiply&&mat2->massMultiply);
+
+ phys->kn = contactParameterCalculation(kn1,kn2);
+ phys->ks = contactParameterCalculation(ks1,ks2);
+ phys->cn = contactParameterCalculation(cn1,cn2);
+ phys->cs = contactParameterCalculation(cs1,cs2);
if ((mR1>0) or (mR2>0)) {
phys->mR = 2.0/( ((mR1>0)?1/mR1:0) + ((mR2>0)?1/mR2:0) );
@@ -85,163 +246,22 @@
} else {
phys->mRtype = mRtype1;
}
-
- if (mat1->Capillar and mat2->Capillar) {
- if (mat1->Vb == mat2->Vb) {
- phys->Vb = mat1->Vb;
- } else {
- throw runtime_error("Vb should be equal for both particles!.");
- }
-
- if (mat1->gamma == mat2->gamma) {
- phys->gamma = mat1->gamma;
- } else {
- throw runtime_error("Gamma should be equal for both particles!.");
- }
-
- if (mat1->theta == mat2->theta) {
- phys->theta = (mat1->theta*M_PI/180.0);
- } else {
- throw runtime_error("Theta should be equal for both particles!.");
- }
-
- if (mat1->CapillarType == mat2->CapillarType and mat2->CapillarType != ""){
-
- if (mat1->CapillarType == "Willett_numeric") phys->CapillarType = Willett_numeric;
- else if (mat1->CapillarType == "Willett_analytic") phys->CapillarType = Willett_analytic;
- else if (mat1->CapillarType == "Weigert") phys->CapillarType = Weigert;
- else if (mat1->CapillarType == "Rabinovich") phys->CapillarType = Rabinovich;
- else if (mat1->CapillarType == "Lambert") phys->CapillarType = Lambert;
- else phys->CapillarType = None_Capillar;
- } else {
- throw runtime_error("CapillarType should be equal for both particles!.");
- }
- phys->Capillar=true;
+#ifdef YADE_SPH
+ if (mat1->SPHmode and mat2->SPHmode) {
+ phys->SPHmode=true;
+ phys->mu=(mat1->mu+mat2->mu)/2.0;
}
- interaction->phys = shared_ptr<ViscElPhys>(phys);
+ phys->kernelFunctionCurrentPressure = returnKernelFunction (mat1->KernFunctionPressure, mat2->KernFunctionPressure, Grad);
+ phys->kernelFunctionCurrentVisco = returnKernelFunction (mat1->KernFunctionVisco, mat2->KernFunctionVisco, Lapl);
+#endif
}
-/* Law2_ScGeom_ViscElPhys_Basic */
-void Law2_ScGeom_ViscElPhys_Basic::go(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I){
-
- const ScGeom& geom=*static_cast<ScGeom*>(_geom.get());
- ViscElPhys& phys=*static_cast<ViscElPhys*>(_phys.get());
-
- const int id1 = I->getId1();
- const int id2 = I->getId2();
-
- if (geom.penetrationDepth<0) {
- if (phys.liqBridgeCreated and -geom.penetrationDepth<phys.sCrit and phys.Capillar) {
- phys.normalForce = -calculateCapillarForce(geom, phys)*geom.normal;
- if (I->isActive) {
- addForce (id1,-phys.normalForce,scene);
- addForce (id2, phys.normalForce,scene);
- };
- return;
- } else {
- scene->interactions->requestErase(I);
- return;
- };
- };
-
- const BodyContainer& bodies = *scene->bodies;
-
- const State& de1 = *static_cast<State*>(bodies[id1]->state.get());
- const State& de2 = *static_cast<State*>(bodies[id2]->state.get());
-
- /*
- * This part for implementation of the capillar model.
- * All main equations are in calculateCapillarForce function.
- * There is only the determination of critical distance between spheres,
- * after that the liquid bridge will be broken.
- */
-
- if (not(phys.liqBridgeCreated) and phys.Capillar) {
- phys.liqBridgeCreated = true;
- Sphere* s1=dynamic_cast<Sphere*>(bodies[id1]->shape.get());
- Sphere* s2=dynamic_cast<Sphere*>(bodies[id2]->shape.get());
- if (s1 and s2) {
- phys.R = 2 * s1->radius * s2->radius / (s1->radius + s2->radius);
- } else if (s1 and not(s2)) {
- phys.R = s1->radius;
- } else {
- phys.R = s2->radius;
- }
-
- const Real Vstar = phys.Vb/(phys.R*phys.R*phys.R);
- const Real Sstar = (1+0.5*phys.theta)*(pow(Vstar,1/3.0) + 0.1*pow(Vstar,2.0/3.0)); // [Willett2000], equation (15), use the full-length e.g 2*Sc
-
- phys.sCrit = Sstar*phys.R;
- }
-
- Vector3r& shearForce = phys.shearForce;
- if (I->isFresh(scene)) shearForce=Vector3r(0,0,0);
- const Real& dt = scene->dt;
- shearForce = geom.rotate(shearForce);
-
-
- // Handle periodicity.
- const Vector3r shift2 = scene->isPeriodic ? scene->cell->intrShiftPos(I->cellDist): Vector3r::Zero();
- const Vector3r shiftVel = scene->isPeriodic ? scene->cell->intrShiftVel(I->cellDist): Vector3r::Zero();
-
- const Vector3r c1x = (geom.contactPoint - de1.pos);
- const Vector3r c2x = (geom.contactPoint - de2.pos - shift2);
-
- const Vector3r relativeVelocity = (de1.vel+de1.angVel.cross(c1x)) - (de2.vel+de2.angVel.cross(c2x)) + shiftVel;
- const Real normalVelocity = geom.normal.dot(relativeVelocity);
- const Vector3r shearVelocity = relativeVelocity-normalVelocity*geom.normal;
-
- // As Chiara Modenese suggest, we store the elastic part
- // and then add the viscous part if we pass the Mohr-Coulomb criterion.
- // See http://www.mail-archive.com/yade-users@xxxxxxxxxxxxxxxxxxx/msg01391.html
- shearForce += phys.ks*dt*shearVelocity; // the elastic shear force have a history, but
- Vector3r shearForceVisc = Vector3r::Zero(); // the viscous shear damping haven't a history because it is a function of the instant velocity
-
-
- // Prevent appearing of attraction forces due to a viscous component
- // [Radjai2011], page 3, equation [1.7]
- // [Schwager2007]
- const Real normForceReal = phys.kn * geom.penetrationDepth + phys.cn * normalVelocity;
- if (normForceReal < 0) {
- phys.normalForce = Vector3r::Zero();
- } else {
- phys.normalForce = normForceReal * geom.normal;
- }
-
- Vector3r momentResistance = Vector3r::Zero();
- if (phys.mR>0.0) {
- const Vector3r relAngVel = de1.angVel - de2.angVel;
- relAngVel.normalized();
-
- if (phys.mRtype == 1) {
- momentResistance = -phys.mR*phys.normalForce.norm()*relAngVel; // [Zhou1999536], equation (3)
- } else if (phys.mRtype == 2) {
- momentResistance = -phys.mR*(c1x.cross(de1.angVel) - c2x.cross(de2.angVel)).norm()*phys.normalForce.norm()*relAngVel; // [Zhou1999536], equation (4)
- }
- }
-
- const Real maxFs = phys.normalForce.squaredNorm() * std::pow(phys.tangensOfFrictionAngle,2);
- if( shearForce.squaredNorm() > maxFs )
- {
- // Then Mohr-Coulomb is violated (so, we slip),
- // we have the max value of the shear force, so
- // we consider only friction damping.
- const Real ratio = sqrt(maxFs) / shearForce.norm();
- shearForce *= ratio;
- }
- else
- {
- // Then no slip occurs we consider friction damping + viscous damping.
- shearForceVisc = phys.cs*shearVelocity;
- }
-
- if (I->isActive) {
- const Vector3r f = phys.normalForce + shearForce + shearForceVisc;
- addForce (id1,-f,scene);
- addForce (id2, f,scene);
- addTorque(id1,-c1x.cross(f)+momentResistance,scene);
- addTorque(id2, c2x.cross(f)-momentResistance,scene);
- }
+/* Contact parameter calculation function */
+Real contactParameterCalculation(const Real& l1, const Real& l2){
+ // If one of paramaters > 0. we DO NOT return 0
+ Real a = (l1?1/l1:0) + (l2?1/l2:0);
+ if (a) return 1/a;
+ else return 0;
}
=== modified file 'pkg/dem/ViscoelasticPM.hpp'
--- pkg/dem/ViscoelasticPM.hpp 2014-01-30 08:09:44 +0000
+++ pkg/dem/ViscoelasticPM.hpp 2014-04-10 14:04:50 +0000
@@ -9,6 +9,12 @@
#include<yade/pkg/common/Dispatching.hpp>
#include<yade/pkg/dem/ScGeom.hpp>
#include<yade/pkg/dem/DemXDofGeom.hpp>
+#include<yade/pkg/common/MatchMaker.hpp>
+
+#ifdef YADE_SPH
+#include<yade/pkg/common/SPHEngine.hpp>
+#endif
+
/* Simple viscoelastic model */
@@ -18,18 +24,21 @@
public:
virtual ~ViscElMat();
YADE_CLASS_BASE_DOC_ATTRS_CTOR(ViscElMat,FrictMat,"Material for simple viscoelastic model of contact.\n\n.. note::\n\t ``Shop::getViscoelasticFromSpheresInteraction`` (and :yref:`yade.utils.getViscoelasticFromSpheresInteraction` in python) compute :yref:`kn<ViscElMat::kn>`, :yref:`cn<ViscElMat::cn>`, :yref:`ks<ViscElMat::ks>`, :yref:`cs<ViscElMat::cs>` from analytical solution of a pair spheres interaction problem.",
- ((Real,kn,NaN,,"Normal elastic stiffness"))
- ((Real,cn,NaN,,"Normal viscous constant"))
- ((Real,ks,NaN,,"Shear elastic stiffness"))
- ((Real,cs,NaN,,"Shear viscous constant"))
- ((bool,massMultiply,true,,"Stiffness and viscosity are multiplied by the reduced mass. If massMultiply=false, these parameter are set explicitly without mass multiplication"))
+ ((Real,tc,NaN,,"Contact time"))
+ ((Real,en,NaN,,"Restitution coefficient in normal direction"))
+ ((Real,et,NaN,,"Restitution coefficient in tangential direction"))
+ ((Real,kn,NaN,,"Normal elastic stiffness. Attention, this parameter cannot be set if tc, en or es is defined!"))
+ ((Real,cn,NaN,,"Normal viscous constant. Attention, this parameter cannot be set if tc, en or es is defined!"))
+ ((Real,ks,NaN,,"Shear elastic stiffness. Attention, this parameter cannot be set if tc, en or es is defined!"))
+ ((Real,cs,NaN,,"Shear viscous constant. Attention, this parameter cannot be set if tc, en or es is defined!"))
((Real,mR,0.0,,"Rolling resistance, see [Zhou1999536]_."))
- ((unsigned int,mRtype,1,,"Rolling resistance type, see [Zhou1999536]_. mRtype=1 - equation (3) in [Zhou1999536]_; mRtype=2 - equation (4) in [Zhou1999536]_."))
- ((bool,Capillar,false,,"True, if capillar forces need to be added."))
- ((Real,Vb,NaN,,"Liquid bridge volume [m^3]"))
- ((Real,gamma,NaN,,"Surface tension [N/m]"))
- ((Real,theta,NaN,,"Contact angle [°]"))
- ((std::string,CapillarType,"",,"Different types of capillar interaction: Willett_numeric, Willett_analytic [Willett2000]_ , Weigert [Weigert1999]_ , Rabinovich [Rabinov2005]_ , Lambert (simplified, corrected Rabinovich model) [Lambert2008]_ ")),
+#ifdef YADE_SPH
+ ((bool,SPHmode,false,,"True, if SPH-mode is enabled."))
+ ((Real,mu,-1,, "Viscosity. See Mueller [Mueller2003]_ .")) // [Mueller2003], (14)
+ ((int,KernFunctionPressure,Spiky,, "Kernel function for pressure calculation (by default - Spiky). The following kernel functions are available: Poly6=1, Spiky=2, Visco=3, Lucy=4, Monaghan=5."))
+ ((int,KernFunctionVisco, Visco,, "Kernel function for viscosity calculation (by default - Visco). The following kernel functions are available: Poly6=1, Spiky=2, Visco=3, Lucy=4, Monaghan=5."))
+#endif
+ ((unsigned int,mRtype,1,,"Rolling resistance type, see [Zhou1999536]_. mRtype=1 - equation (3) in [Zhou1999536]_; mRtype=2 - equation (4) in [Zhou1999536]_.")),
createIndex();
);
REGISTER_CLASS_INDEX(ViscElMat,FrictMat);
@@ -37,7 +46,6 @@
REGISTER_SERIALIZABLE(ViscElMat);
/// Interaction physics
-enum CapType {None_Capillar, Willett_numeric, Willett_analytic, Weigert, Rabinovich, Lambert};
class ViscElPhys : public FrictPhys{
public:
virtual ~ViscElPhys();
@@ -46,16 +54,18 @@
((Real,cn,NaN,,"Normal viscous constant"))
((Real,cs,NaN,,"Shear viscous constant"))
((Real,mR,0.0,,"Rolling resistance, see [Zhou1999536]_."))
- ((unsigned int,mRtype,1,,"Rolling resistance type, see [Zhou1999536]_. mRtype=1 - equation (3) in [Zhou1999536]_; mRtype=2 - equation (4) in [Zhou1999536]_"))
- ((bool,Capillar,false,,"True, if capillar forces need to be added."))
- ((bool,liqBridgeCreated,false,,"Whether liquid bridge was created, only after a normal contact of spheres"))
- ((Real,sCrit,false,,"Critical bridge length [m]"))
- ((Real,Vb,NaN,,"Liquid bridge volume [m^3]"))
- ((Real,gamma,NaN,,"Surface tension [N/m]"))
- ((Real,theta,NaN,,"Contact angle [rad]"))
- ((CapType,CapillarType,None_Capillar,,"Different types of capillar interaction: Willett_numeric, Willett_analytic, Weigert, Rabinovich, Lambert")),
+#ifdef YADE_SPH
+ ((bool,SPHmode,false,,"True, if SPH-mode is enabled."))
+ ((Real,h,-1,, "Core radius. See Mueller [Mueller2003]_ .")) // [Mueller2003], (1)
+ ((Real,mu,-1,, "Viscosity. See Mueller [Mueller2003]_ .")) // [Mueller2003], (14)
+#endif
+ ((unsigned int,mRtype,1,,"Rolling resistance type, see [Zhou1999536]_. mRtype=1 - equation (3) in [Zhou1999536]_; mRtype=2 - equation (4) in [Zhou1999536]_")),
createIndex();
)
+#ifdef YADE_SPH
+ KernelFunction kernelFunctionCurrentPressure;
+ KernelFunction kernelFunctionCurrentVisco;
+#endif
REGISTER_CLASS_INDEX(ViscElPhys,FrictPhys);
};
REGISTER_SERIALIZABLE(ViscElPhys);
@@ -67,11 +77,12 @@
virtual void go(const shared_ptr<Material>& b1,
const shared_ptr<Material>& b2,
const shared_ptr<Interaction>& interaction);
- private :
- Real contactParameterCalculation(const Real& l1,const Real& l2, const bool& massMultiply);
- YADE_CLASS_BASE_DOC(Ip2_ViscElMat_ViscElMat_ViscElPhys,IPhysFunctor,"Convert 2 instances of :yref:`ViscElMat` to :yref:`ViscElPhys` using the rule of consecutive connection.");
+ YADE_CLASS_BASE_DOC_ATTRS(Ip2_ViscElMat_ViscElMat_ViscElPhys,IPhysFunctor,"Convert 2 instances of :yref:`ViscElMat` to :yref:`ViscElPhys` using the rule of consecutive connection.",
+ ((shared_ptr<MatchMaker>,tc,,,"Instance of :yref:`MatchMaker` determining contact time"))
+ ((shared_ptr<MatchMaker>,en,,,"Instance of :yref:`MatchMaker` determining restitution coefficient in normal direction"))
+ ((shared_ptr<MatchMaker>,et,,,"Instance of :yref:`MatchMaker` determining restitution coefficient in tangential direction")));
+ virtual void Calculate_ViscElMat_ViscElMat_ViscElPhys(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction, shared_ptr<ViscElPhys> phys);
FUNCTOR2D(ViscElMat,ViscElMat);
-
};
REGISTER_SERIALIZABLE(Ip2_ViscElMat_ViscElMat_ViscElPhys);
@@ -80,11 +91,12 @@
class Law2_ScGeom_ViscElPhys_Basic: public LawFunctor {
public :
virtual void go(shared_ptr<IGeom>&, shared_ptr<IPhys>&, Interaction*);
- private:
- Real calculateCapillarForce(const ScGeom& geom, ViscElPhys& phys);
public :
FUNCTOR2D(ScGeom,ViscElPhys);
YADE_CLASS_BASE_DOC(Law2_ScGeom_ViscElPhys_Basic,LawFunctor,"Linear viscoelastic model operating on :yref:`ScGeom` and :yref:`ViscElPhys`. The model is mostly based on the paper for For details see Pournin [Pournin2001]_ .");
DECLARE_LOGGER;
};
REGISTER_SERIALIZABLE(Law2_ScGeom_ViscElPhys_Basic);
+
+Real contactParameterCalculation(const Real& l1,const Real& l2);
+bool computeForceTorqueViscEl(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I, Vector3r & force, Vector3r & torque1, Vector3r & torque2);
=== added directory 'pkg/lbm'
=== added file 'pkg/lbm/HydrodynamicsLawLBM.cpp'
--- pkg/lbm/HydrodynamicsLawLBM.cpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/HydrodynamicsLawLBM.cpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,1370 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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. *
+* *
+* Luc Scholtès luc.scholtes@xxxxxxxxxxxxxxxx *
+* and Luc Sibille luc.sibille@xxxxxxxxxxxxxxx also contributed to this *
+* code. *
+* *
+* Lominé F., Scholtès L., Sibille L., Poullain P. (2013) *
+* Modelling of fluid-solid interaction in granular media with coupled *
+* LB/DE methods: application to piping erosion. International Journal *
+* for Numerical and Analytical Methods in Geomechanics, 37(6):577-596 *
+* doi: 10.1002/nag.1109 *
+* *
+* Sibille L., Lominé F., Marot D. (2012) Investigation In Modelling *
+* Piping Erosion With a Coupled «Lattice Boltzmann – Discrete Element» *
+* Numerical Method. in Proc. 6th Int. Conference on Scour and Erosion *
+* (ICSE-6), pp. 93-100. *
+* *
+*************************************************************************/
+#ifdef LBM_ENGINE
+
+#include"HydrodynamicsLawLBM.hpp"
+#include<yade/core/Omega.hpp>
+#include<yade/core/Scene.hpp>
+#include<boost/filesystem/operations.hpp>
+#include<yade/pkg/common/Box.hpp>
+#include<yade/pkg/common/Sphere.hpp>
+#include<yade/pkg/dem/CohFrictPhys.hpp>
+
+
+namespace bfs=boost::filesystem;
+using namespace std;
+
+template<class Scalar> VECTOR3_TEMPLATE(Scalar) operator*(Scalar s, const VECTOR3_TEMPLATE(Scalar)& v) {return v*s;}
+inline Vector3i vect3rToVect3i(Vector3r vect){Vector3i newvect((int)vect[0],(int)vect[1],(int)vect[2]);return(newvect);}
+
+
+HydrodynamicsLawLBM::~HydrodynamicsLawLBM() {};
+
+bool HydrodynamicsLawLBM::isActivated(){
+ DEM_ITER=scene->iter;//+1;
+ if(EngineIsActivated){
+ if((DEM_ITER % DemIterLbmIterRatio==0)&&(DEM_ITER!=DemIterLbmIterRatio)) {
+ if(DEM_ITER==0){DEMdt0 = scene->dt;scene->dt=1.e-50;}
+ return(true);}
+ else{
+ if(applyForcesAndTorques) CalculateAndApplyForcesAndTorquesOnBodies(false,true);
+ return(false);
+ }
+ }else return(false);
+}
+
+void HydrodynamicsLawLBM::action()
+{
+ timingDeltas->start();
+ NB_BODIES= scene->bodies->size();
+ int I, J, step=0;
+ NbFluidNodes=0;
+ NbSolidNodes=0;
+ Real CurMinVelOfPtc=1000000.;
+ Real CurMaxVelOfPtc=-1000000.;
+ int ErrorCriterion=2;
+ /*------------------------------------------------------------------*/
+ /* AT FIRST ITERATION */
+ /*------------------------------------------------------------------*/
+ if(firstRun){
+ // createNewFiles(); //this line is move further to create files only when the recording configuration chosen by the operator is known
+ bool initVbCutOff=false;
+ if(VbCutOff==-1) initVbCutOff=true;
+ halfWallthickness=1000000.;
+ NB_WALLS=0;
+ //NB_DYNWALLS=0;
+ NB_DYNGRAINS=0;
+ LBMbody tmpbody;
+ FOREACH(const shared_ptr<Body>& b, *scene->bodies){
+ if(!b) continue; // deleted bodies
+ if (b->shape->getClassName()=="Box"){
+ Vector3r ext(YADE_PTR_CAST<Box> ( b->shape )->extents);
+ if (ext[0]<halfWallthickness) halfWallthickness=ext[0];
+ if (ext[1]<halfWallthickness) halfWallthickness=ext[1];
+ if (ext[2]<halfWallthickness) halfWallthickness=ext[2];
+ NB_WALLS++;
+ tmpbody.setAsBox();
+ tmpbody.saveProperties=false;
+ //if(b->isDynamic()) NB_DYNWALLS++;
+ }
+ if (b->shape->getClassName()=="Sphere"){
+ const shared_ptr<Sphere>& sph = YADE_PTR_CAST<Sphere> ( b->shape );
+ if(IdFirstSphere==-1) IdFirstSphere=b->getId();
+ tmpbody.setAsPtc();
+ Real r=sph->radius;
+ if(b->isDynamic()){
+ NB_DYNGRAINS++;
+ /*--- computation of the initial volume ---*/
+ if(!strcmp(model.c_str(), "d2q9" )) Vo += Mathr::PI*(r*r);
+ else Vo += 4./3.*Mathr::PI*(r*r*r);
+ if(initVbCutOff) VbCutOff=max(VbCutOff,b->state->vel.norm()+r*b->state->angVel.norm());
+ tmpbody.saveProperties=true;
+ }else{
+ if(b->state->pos[1]>0.) tmpbody.saveProperties=true;
+ else tmpbody.saveProperties=false;
+ }
+ /*--- computation of Rmean Rmax Rmin --*/
+ MaxBodyRadius=max(r,MaxBodyRadius);
+ MinBodyRadius=min(r,MinBodyRadius);
+ MeanBodyRadius+=r;
+ }
+
+ LBbodies.push_back(tmpbody);
+ }
+ Wallthickness=2.0*halfWallthickness;
+ NB_GRAINS=NB_BODIES-NB_WALLS;
+ //Luc: is it right to count the walls as dynamic bodies?
+ //Franck why not ? Enhancement (see next line is coming ;-))
+ NB_DYNBODIES=NB_WALLS+NB_DYNGRAINS;
+ //NB_DYNBODIES=NB_DYNWALLS+NB_DYNGRAINS;
+ MeanBodyRadius=MeanBodyRadius/NB_GRAINS;
+ InitialNumberOfDynamicParticles=NB_DYNGRAINS;
+
+ /*-------------------------------------------------------------------------*/
+ /* D2Q9 model configuration */
+ /*-------------------------------------------------------------------------*/
+ if(!strcmp(model.c_str(), "d2q9" )){
+ dim=2;
+ /*--------------------------------------*/
+ /* D2Q9 model: 6 2 5 */
+ /* 3 _\|/__1 */
+ /* /|\ */
+ /* 7 4 8 */
+ /*--------------------------------------*/
+ /*----------- D2Q9 constants ---------*/
+ w.push_back(4.0/9.0);
+ for(int aa=1;aa<=4;aa++) w.push_back(1.0/9.0);
+ for(int aa=5;aa<=8;aa++) w.push_back(1.0/36.0);
+
+ /*--------- node position vectors ----*/
+ eib.push_back(Vector3r( 0., 0., 0.)); //0
+ eib.push_back(Vector3r( 1., 0., 0.)); //1
+ eib.push_back(Vector3r( 0., 1., 0.)); //2
+ eib.push_back(Vector3r(-1., 0., 0.)); //3
+ eib.push_back(Vector3r( 0.,-1., 0.)); //4
+ eib.push_back(Vector3r( 1., 1., 0.)); //5
+ eib.push_back(Vector3r(-1., 1., 0.)); //6
+ eib.push_back(Vector3r(-1.,-1., 0.)); //7
+ eib.push_back(Vector3r( 1.,-1., 0.)); //8
+ NbDir=(int) eib.size();
+
+ /*-------------- opposite nodes --------*/
+ opp.push_back(0); opp.push_back(3); opp.push_back(4);
+ opp.push_back(1); opp.push_back(2); opp.push_back(7);
+ opp.push_back(8); opp.push_back(5); opp.push_back(6);
+ }else {cerr<<"This model is not implemented yet: "<<model<<endl;exit(-1);}
+
+
+ int res=0;
+ int ll=0;
+ bool CreateLbmDir = false; //Flag to create directories if required by the recording configuration
+ bool CreateDemDir = false; //Flag to create directories if required by the recording configuration
+ bool CreateCntctDir = false; //Flag to create directories if required by the recording configuration
+ /*-------------------------------------------------------------------------*/
+ /* Recording configuration */
+ /*-------------------------------------------------------------------------*/
+ ll=LBMSavedData.size();
+ res=LBMSavedData.find("Velocity"); if(res>=0&&res<ll) {SAVE_VELOCITY =true; SAVE_VELOCITYCOMP=true; CreateLbmDir=true;}
+ res=LBMSavedData.find("velocity"); if(res>=0&&res<ll) {SAVE_VELOCITY =true; SAVE_VELOCITYCOMP=true; CreateLbmDir=true;}
+ res=LBMSavedData.find("VelXY"); if(res>=0&&res<ll) {SAVE_VELOCITYCOMP=true; CreateLbmDir=true;}
+ res=LBMSavedData.find("velXY"); if(res>=0&&res<ll) {SAVE_VELOCITYCOMP=true; CreateLbmDir=true;}
+ res=LBMSavedData.find("Rho"); if(res>=0&&res<ll) {SAVE_RHO =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("rho"); if(res>=0&&res<ll) {SAVE_RHO =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("Forces"); if(res>=0&&res<ll) {SAVE_FORCES =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("forces"); if(res>=0&&res<ll) {SAVE_FORCES =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("Bodies"); if(res>=0&&res<ll) {SAVE_BODIES =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("bodies"); if(res>=0&&res<ll) {SAVE_BODIES =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("NodeBD"); if(res>=0&&res<ll) {SAVE_NODEBD =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("nodeBD"); if(res>=0&&res<ll) {SAVE_NODEBD =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("NewNode"); if(res>=0&&res<ll) {SAVE_NODEISNEW =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("newNode"); if(res>=0&&res<ll) {SAVE_NODEISNEW =true; CreateLbmDir=true;}
+ res=LBMSavedData.find("bz2"); if(res>=0&&res<ll) COMPRESS_DATA =true;
+ res=LBMSavedData.find("ObservedPtc"); if(res>=0&&res<ll) SAVE_OBSERVEDPTC =true;
+ res=LBMSavedData.find("observedptc"); if(res>=0&&res<ll) SAVE_OBSERVEDPTC =true;
+ res=LBMSavedData.find("observedPtc"); if(res>=0&&res<ll) SAVE_OBSERVEDPTC =true;
+ res=LBMSavedData.find("ObservedNode"); if(res>=0&&res<ll) SAVE_OBSERVEDNODE=true; // does not activate any recording in a a file currently
+ res=LBMSavedData.find("observednode"); if(res>=0&&res<ll) SAVE_OBSERVEDNODE=true;
+ res=LBMSavedData.find("observedNode"); if(res>=0&&res<ll) SAVE_OBSERVEDNODE=true;
+ res=LBMSavedData.find("contacts"); if(res>=0&&res<ll) {SAVE_CONTACTINFO =true; CreateCntctDir=true;} // SAVE_CONTACTINFO does not activate any (anymore) recording excepted the creation of a directory
+ res=LBMSavedData.find("Contacts"); if(res>=0&&res<ll) {SAVE_CONTACTINFO =true; CreateCntctDir=true;}
+ res=LBMSavedData.find("spheres"); if(res>=0&&res<ll) {SAVE_SPHERES =true; CreateDemDir=true;} // To save spheres_* file only if it is required by the operator
+ res=LBMSavedData.find("Spheres"); if(res>=0&&res<ll) {SAVE_SPHERES =true; CreateDemDir=true;} // To save spheres_* file only if it is required by the operator
+
+ // if(NB_DYNGRAINS==1) SAVE_OBSERVEDPTC =true; //Commented to avoid recording of observedPtc if not chosen by the operator
+ if ((ObservedPtc==-1)&&(NB_GRAINS>0)&&(SAVE_OBSERVEDPTC)) ObservedPtc=IdFirstSphere; //Condition If(SAVE_OBSERVEDPTC) is added to save observedPtc only if it is required by the operator
+ if ((SAVE_OBSERVEDPTC)&&((unsigned)ObservedPtc>=LBbodies.size())){cerr<<"Error: ObservedPtc>bodies.size()"<<endl;exit(-1);}
+ if ((SAVE_SPHERES)&&(NB_GRAINS<1)){cerr<<"Error: saving of sphere properties is switched on whereas NB_GRAINS<1"<<endl;exit(-1);}
+
+ createDirectories(CreateLbmDir,CreateDemDir,CreateCntctDir);
+ createNewFiles(); // Files are created now, since we know what the operator wants to record (ObservedPtc ... etc)
+
+
+ /*--------------------------------------------------------------*/
+ /* Periodicity configuration */
+ /*--------------------------------------------------------------*/
+ ll=periodicity.size();
+ res=periodicity.find("x"); if(res>=0&&res<ll) Xperiodicity=true;
+ res=periodicity.find("y"); if(res>=0&&res<ll) Yperiodicity=true;
+ res=periodicity.find("z"); if(res>=0&&res<ll) Zperiodicity=true;
+ cerr <<"Periodicity (XYZ): "<<Xperiodicity<<" "<<Yperiodicity<<" "<<Zperiodicity<<endl;
+
+
+
+ /*--------------------------------------------------------------*/
+ /* Lattice definition */
+ /*--------------------------------------------------------------*/
+ cerr << "---- Lattice setup -----" << endl;
+ State* sWallYm=Body::byId(WallYm_id,scene)->state.get();
+ State* sWallYp=Body::byId(WallYp_id,scene)->state.get();
+ State* sWallXm=Body::byId(WallXm_id,scene)->state.get();
+ State* sWallXp=Body::byId(WallXp_id,scene)->state.get();
+ State* sWallZp=Body::byId(WallZp_id,scene)->state.get();
+ State* sWallZm=Body::byId(WallZm_id,scene)->state.get();
+
+ height = sWallYp->se3.position.y() - sWallYm->se3.position.y();
+ width = sWallXp->se3.position.x() - sWallXm->se3.position.x();
+ depth = sWallZp->se3.position.z() - sWallZm->se3.position.z();
+
+
+ Lx0 = width-Wallthickness;
+ Ly0 = height-Wallthickness;
+ Lz0 = depth-Wallthickness;
+ Real Lx1 = width+Wallthickness;
+ Real Ly1 = height+Wallthickness;
+ Real Lz1 = depth+Wallthickness;
+ /*--------------------------------------------------------------*/
+ /* Computation of number of lattice nodes in each direction */
+ /*--------------------------------------------------------------*/
+ dx = Lx0 / (Real) (Nx-1);
+ invdx=1./dx;
+
+ //Number of nodes (after-correction)
+ Ny = ceil(invdx*Ly1)+1;
+ dx = Ly1 / (Real) (Ny-1);
+ invdx=1./dx;
+ dx2=dx*dx;
+ Nx = ceil(invdx*Lx1)+1;
+ Ny = ceil(invdx*Ly1)+1;
+ Nz=1;
+
+ cerr <<"LXYZ0= "<<Lx0<<" "<<Ly0<<" "<<Lz0<<endl;
+ cerr <<"LXYZ1= "<<Lx1<<" "<<Ly1<<" "<<Lz1<<endl;
+ cerr <<"Ny= "<<Ny<<" "<<" Nx*Ly0/Lx0="<<Nx*Ly0/Lx0<<endl;
+ cerr <<"Wallthickness= "<<Wallthickness<<" "<<" dx="<<dx<<endl;
+
+ /*-------------------------------------------------------*/
+ /* Verification of wall positionning in positive regions */
+ /*-------------------------------------------------------*/
+ if (sWallYm->se3.position.y()- halfWallthickness<0.){cerr <<"Wall position error: please avoid negatives region (Y)"<<endl;exit(-1);}
+ if (sWallXm->se3.position.x()- halfWallthickness<0.){cerr <<"Wall position error: please avoid negatives region (X)"<<endl;exit(-1);}
+ if ((dim==3)&&(sWallZm->se3.position.z()- halfWallthickness<0.)){cerr <<"Wall position error: please avoid negatives region (Z)"<<endl;exit(-1);}
+
+
+ /*--------------------------------------------------------------*/
+ /* Some tests about the validity of parameters */
+ /*--------------------------------------------------------------*/
+ if( (NB_DYNGRAINS==0)&&(use_ConvergenceCriterion)&&(ErrorCriterion==1)){
+ cerr <<"ERROR: can't use ErrorCriterion=1 when (NB_DYNGRAINS=0"<<endl;
+ exit(-1);}
+ if((ObservedNode!=-1)&&(ObservedNode>=Nx*Ny)){
+ cerr <<"Warning ObservedNode is >= Nx*Ny ... exit"<<endl;
+ exit(-1);}
+ if((SaveMode!=1)&&(SaveMode!=2)) {cerr <<"Warning unknown SaveMode."<<SaveMode<<endl; exit(-1);}
+ if((SaveMode==1)&&(IterSave<=0)) {cerr <<"Warning SaveMode==1 and IterSave<=0."<<endl; exit(-1);}
+ if((SaveMode==2)&&(TimeSave<=0)) {cerr <<"Warning SaveMode==2 and TimeSave<=0."<<endl; exit(-1);}
+ /*---------------------------------------------------------------*/
+ /*------------------ general node initialization ----------------*/
+ /*---------------------------------------------------------------*/
+ LBMnode aa;
+ for(int nidx=0; nidx<Nx*Ny; nidx++) {nodes.push_back(aa);}
+ bool j_update=false;
+ int j=0;
+ for (int nidx=0; nidx<Nx*Ny; nidx++){
+ int i=nidx-j*Nx;
+ if((nidx+1)%Nx==0) j_update=true;
+ int k=0;
+
+ nodes[nidx].SetCellIndexesAndPosition(i,j,k);
+ nodes[nidx].DispatchBoundaryConditions(Nx,Ny,Nz);
+ NbNodes++;
+ for (int dndx=0; dndx<NbDir; dndx++){
+ nodes[nidx].links_id.push_back(-1);
+ I=nodes[nidx].i+eib[dndx].x();
+ J=nodes[nidx].j+eib[dndx].y();
+ if(((I==i)&&(J==j)) || (I==-1) || (J==-1) || (I==Nx) || (J==Ny) ){
+ nodes[nidx].neighbour_id.push_back(-1);
+ }
+ else {nodes[nidx].neighbour_id.push_back(I+J*Nx);}
+ }
+ if(j_update) {j++;j_update=false;}
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ ///FIXME(flomine#1): periodicity should be implemented from links to facilitate the streaming step
+ ///FIXME(flomine#1): to be optimise and bug should be corrected (cf test version)
+ LBMlink bb;
+ int link_id=-1;
+ for (int nidx=0; nidx<Nx*Ny; nidx++){
+ int I=nodes[nidx].i;
+ int J=nodes[nidx].j;
+ for (int dndx=0; dndx<NbDir; dndx++){
+ if(dndx==0) continue;
+ bb.PointingOutside=false;
+ if((!strcmp(model.c_str(), "d2q9" )) && ((dndx==1)||(dndx==2)||(dndx==5)||(dndx==6))){
+ link_id++;bb.i=dndx;bb.nid1=nidx;
+ bb.nid2=nodes[nidx].neighbour_id[dndx];
+ if(bb.nid2==-1) bb.PointingOutside=true;
+ links.push_back(bb);
+ nodes[bb.nid1].links_id[dndx]=link_id;
+ if(bb.nid2!=-1) nodes[bb.nid2].links_id[opp[dndx]]=link_id;
+ }else if(!strcmp(model.c_str(), "d2q9" )){
+ if((I==0)&&(J!=0)&&((dndx==3)||(dndx==7))){
+ link_id++;bb.i=dndx; bb.nid1=nidx;
+ bb.nid2=nodes[nidx].neighbour_id[dndx];
+ bb.PointingOutside=true;
+ if(bb.nid2!=-1) {cerr<<"ERROR: bb.id2!=-1"<<endl;exit(-1);}
+ links.push_back(bb);
+ nodes[bb.nid1].links_id[dndx]=link_id;
+ if(bb.nid2!=-1) nodes[bb.nid2].links_id[opp[dndx]]=link_id;
+ } else if((J==0)&&(I!=0)&&((dndx==4)||(dndx==7)||(dndx==8))){
+ link_id++;bb.i=dndx; bb.nid1=nidx;
+ bb.nid2=nodes[nidx].neighbour_id[dndx];
+ bb.PointingOutside=true;
+ if(bb.nid2!=-1) {cerr<<"ERROR: bb.id2!=-1"<<endl;exit(-1);}
+ links.push_back(bb);
+ nodes[bb.nid1].links_id[dndx]=link_id;
+ if(bb.nid2!=-1) nodes[bb.nid2].links_id[opp[dndx]]=link_id;
+ } else if((I==0)&&(J==0)&&((dndx==3)||(dndx==4)||(dndx==7)||(dndx==8))){
+ link_id++;bb.i=dndx; bb.nid1=nidx;
+ bb.nid2=nodes[nidx].neighbour_id[dndx];
+ bb.PointingOutside=true;
+ if(bb.nid2!=-1) {cerr<<"ERROR: bb.id2!=-1"<<endl;exit(-1);}
+ links.push_back(bb);
+ nodes[bb.nid1].links_id[dndx]=link_id;
+ if(bb.nid2!=-1) nodes[bb.nid2].links_id[opp[dndx]]=link_id;
+ }
+ }else {cerr<<"ERROR: Unknow model type: "<<model<<endl;exit(-1);}
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ if((ConvergenceThreshold==-1)||(ConvergenceThreshold==0)) use_ConvergenceCriterion=false;
+ else {use_ConvergenceCriterion=true;ErrorCriterion=ConvergenceThreshold;}
+ /*------------------------------------------------------------------*/
+ /*------------------------ LBM PARAMETERS --------------------------*/
+ /*------------------------------------------------------------------*/
+ UMaxtheo = dP.norm()/(8.*Rho*Nu)*(height*height/width);
+ if(defaultLbmInitMode){
+ uMax = 0.1; c = UMaxtheo/uMax;
+ cs = c/sqrt(3.); dt = dx/c;
+ nu = dt/(dx*dx/Nu); tau = 3.*nu + 0.5;
+ }else{
+ nu = (1.0/3.0)*(tau - 0.5);
+ dt = nu*(dx*dx/Nu); c = dx/dt;
+ cs = c/sqrt(3.); uMax = UMaxtheo / c;
+ }
+ omega = 1.0/tau;
+ c2=c*c;
+ invdt=1./dt;
+ MaxBodyRadius=invdx*MaxBodyRadius;
+ MinBodyRadius=invdx*MinBodyRadius;
+ MeanBodyRadius=invdx*MeanBodyRadius;
+ outside_limit=1.5*width;
+ }//end if FirstRun
+
+ /*************************************************************************/
+ /* SOLID OBSTACLES SET-UP */
+ /*************************************************************************/
+ Real Rmin = 1000.;
+ int newFluidCells_couter=0;
+ int newObstacleCells_couter=0;
+
+ State* sWallYm=Body::byId(WallYm_id,scene)->state.get();
+ State* sWallYp=Body::byId(WallYp_id,scene)->state.get();
+ State* sWallXm=Body::byId(WallXm_id,scene)->state.get();
+ State* sWallXp=Body::byId(WallXp_id,scene)->state.get();
+ State* sWallZp=Body::byId(WallZp_id,scene)->state.get();
+ State* sWallZm=Body::byId(WallZm_id,scene)->state.get();
+
+ timingDeltas->checkpoint("Reinit:Nodes0");
+ #pragma omp parallel for
+ for (int nidx=0; nidx<Nx*Ny; nidx++){
+ /*------------------------------------------*/
+ /* Reinitialization: */
+ /*------------------------------------------*/
+ nodes[nidx].body_id=-1;
+ nodes[nidx].setAsFluid();
+ nodes[nidx].isObstacleBoundary=false;
+ nodes[nidx].isFluidBoundary=false;
+ nodes[nidx].isNewObstacle=false;
+ nodes[nidx].isNewFluid=false;
+
+ /*--- according to X+ ---*/
+ if (useWallXp&&(nodes[nidx].i>=invdx*(sWallXp->se3.position.x() - halfWallthickness))){
+ nodes[nidx].setAsObstacle();
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx].body_id=WallXp_id;
+ NbSolidNodes++;}
+ /*--- according to X- ---*/
+ else if (useWallXm&&(nodes[nidx].i<=invdx*(sWallXm->se3.position.x() + halfWallthickness))){
+ nodes[nidx].setAsObstacle();
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx].body_id=WallXm_id;
+ NbSolidNodes++;}
+ /*--- according to Y+ ---*/
+ else if (useWallYp&&(nodes[nidx].j>=invdx*(sWallYp->se3.position.y() - halfWallthickness))){
+ nodes[nidx].setAsObstacle();
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx].body_id=WallYp_id;
+ NbSolidNodes++;}
+ /*--- according to Y- ---*/
+ else if (useWallYm&&(nodes[nidx].j<=invdx*(sWallYm->se3.position.y() + halfWallthickness))){
+ nodes[nidx].setAsObstacle();
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx].body_id=WallYm_id;
+ NbSolidNodes++;}
+ /*--- according to Z+ ---*/
+ else if (useWallZp&&(nodes[nidx].k>=invdx*(sWallZp->se3.position.z() - halfWallthickness))){
+ nodes[nidx].setAsObstacle();
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx].body_id=WallZp_id;
+ NbSolidNodes++;}
+ /*--- according to Z- ---*/
+ else if (useWallZm&&(nodes[nidx].k<=invdx*(sWallZm->se3.position.z() + halfWallthickness))){
+ nodes[nidx].setAsObstacle();
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx].body_id=WallZm_id;
+ NbSolidNodes++;}
+
+ if(firstRun){nodes[nidx].wasObstacle=nodes[nidx].isObstacle;}
+ }
+
+ /*---------------------------------------------------------------*/
+ /*- Solid particle detection and recording of their properties --*/
+ /*---------------------------------------------------------------*/
+ NumberOfDynamicParticles=0;
+ if(removingCriterion!=0) IdOfNextErodedPtc.clear();
+ FOREACH(const shared_ptr<Body>& b, *scene->bodies){
+ if(!b) continue; // deleted bodies
+ State* state=b->state.get();
+ const int id=b->getId();
+ //if ((b->shape->getClassName()=="Sphere")&&(b->isDynamic())){ //ModLuc: removing of b->isDynamic() in order that non dynamic particle can be seen by the LBM
+ if (b->shape->getClassName()=="Sphere"){
+ const shared_ptr<Sphere>& sphere = YADE_PTR_CAST<Sphere> ( b->shape );
+
+ LBbodies[id].pos=invdx*state->pos;
+ LBbodies[id].vel=(state->vel)/c;
+ LBbodies[id].AVel= (state->angVel)*dt;
+ LBbodies[id].radius=invdx*RadFactor*(sphere->radius);
+
+ CurMinVelOfPtc=min(CurMinVelOfPtc,state->vel.norm());
+ CurMaxVelOfPtc=max(CurMaxVelOfPtc,state->vel.norm());
+
+ Vector3r posMax=LBbodies[id].pos+ Vector3r(LBbodies[id].radius,LBbodies[id].radius,LBbodies[id].radius);
+ Vector3r posMin=LBbodies[id].pos- Vector3r(LBbodies[id].radius,LBbodies[id].radius,LBbodies[id].radius);
+
+ Vector3r dist=Vector3r::Zero();
+ for(int ii=posMin[0]-1;ii<=posMax[0]+1;ii++)
+ for(int jj=posMin[1]-1;jj<=posMax[1]+1;jj++){
+ if((ii==-1)||(ii==Nx)||(jj==-1)||(jj==Ny)) continue;
+ if((ii<-1)||(ii>Nx)||(jj<-1)||(jj>Ny)) continue;
+ if (LBbodies[id].radius < Rmin) Rmin = LBbodies[id].radius;
+ int nidx=ii+jj*Nx;
+ dist=nodes[nidx].posb-LBbodies[id].pos;
+ if(dist.norm()<LBbodies[id].radius){
+ nodes[nidx].body_id = id;
+ nodes[nidx].setAsObstacle();
+ NbSolidNodes++;
+ NbParticleNodes++;}
+ if(firstRun){nodes[nidx].wasObstacle=nodes[nidx].isObstacle;}
+ }
+ /*-------------------------------------------------------------------*/
+ /* ///NOTE : this should be removed since it can be done with python */
+ ///Fck: pas en MODE 1
+ /*-------------------------------------------------------------------*/
+ //cerr <<"Check removing"<<endl;
+ //if(removingCriterion!=0){ //ModLuc adding of b->isDynamic() to remove only dynamic particles and not already removed particles changed into non dynamic
+ if((removingCriterion!=0)&&(b->isDynamic())){
+ switch(removingCriterion){
+ case 1:
+ /* criterion with respect to the particle postion in x direction */
+ if(LBbodies[id].pos.x()>(invdx*(sWallXp->se3.position.x())-1.05*MaxBodyRadius/RadFactor)){
+ IdOfNextErodedPtc.push_back(id);
+ }
+ break;
+ case 2:
+ /* criterion on particle velocity */
+ if((LBbodies[id].vel.norm()>VelocityThreshold)||(LBbodies[id].pos.x()>(invdx*(sWallXp->se3.position.x())-2.*LBbodies[id].radius))) {IdOfNextErodedPtc.push_back(id);}
+ break;
+ default:
+ exit(-1);
+ break;
+ }
+ }
+ //NumberOfDynamicParticles++; //ModLuc: to still count only dynamic particles and not all particles
+ if(b->isDynamic()) NumberOfDynamicParticles++;
+ }
+
+ LBbodies[id].force=Vector3r::Zero();
+ LBbodies[id].momentum=Vector3r::Zero();
+ }
+
+
+ /*------------------------------------------------------------------*/
+ /*------------------ detection of boundary nodes -------------------*/
+ /*------------------------------------------------------------------*/
+ #pragma omp parallel for
+ for (int nidx=0; nidx<Nx*Ny; nidx++)
+ if(nodes[nidx].isObstacle){
+ for(unsigned int n=0;n<nodes[nidx].neighbour_id.size();n++){
+ if(nodes[nidx].neighbour_id[n]!=-1){
+ int nidx2=nodes[nidx].neighbour_id[n];
+ if(nodes[nidx].isObstacle!=nodes[nidx2].isObstacle) {
+ nodes[nidx].isObstacleBoundary=true;
+ nodes[nidx2].isFluidBoundary=true;
+ int BodyId=nodes[nidx].body_id;
+ int lid=nodes[nidx].links_id[n];
+ links[lid].isBd=true;
+ links[lid].sid=nidx;
+ links[lid].fid=nidx2;
+ links[lid].idx_sigma_i=opp[n];
+ if(LBbodies[BodyId].isPtc()){
+ links[lid].DistMid= nodes[nidx].posb-0.5*eib[links[lid].idx_sigma_i]-LBbodies[BodyId].pos;
+ links[lid].VbMid=LBbodies[BodyId].vel+LBbodies[BodyId].AVel.cross(links[lid].DistMid);
+ if(links[lid].VbMid.norm()<VbCutOff) links[lid].VbMid=Vector3r::Zero();
+ }
+ if(LBbodies[BodyId].isBox()){
+ links[lid].DistMid= Vector3r::Zero();
+ links[lid].VbMid=Vector3r::Zero();
+ }
+ }
+ }
+ }
+ }
+ #pragma omp parallel for
+ for (int nidx=0; nidx<Nx*Ny; nidx++)
+ if((nodes[nidx].isObstacle)&&(!nodes[nidx].isObstacleBoundary)){
+ nodes[nidx].setAsFluid();
+ NbSolidNodes--;
+ if(firstRun) nodes[nidx].wasObstacle=nodes[nidx].isObstacle;
+ }
+
+ NbFluidNodes=NbNodes-NbSolidNodes;
+ /*----------------------------------------------------------------------*/
+
+ if(firstRun){
+
+ /*------------------------------------------------------------------*/
+ /*------------------------------- MODE -----------------------------*/
+ /*------------------------------------------------------------------*/
+ if((IterSubCyclingStart<=0) && (IterMax>1) ) MODE = 1;
+ if((IterSubCyclingStart<=0) && (IterMax==1) ) MODE = 2;
+ if(IterSubCyclingStart>0) MODE = 3;
+
+ /*------------------------------------------------------------------*/
+ /*---------------------------- SUBCYCLING --------------------------*/
+ /*------------------------------------------------------------------*/
+ if(MODE==3&&IterMax<IterSubCyclingStart){cerr <<"Exit because Itermax<IterSubCyclingStart"<<endl;exit(-1);}
+ if(DemIterLbmIterRatio==-1){
+ if(MODE==1) DemIterLbmIterRatio=1;
+ else DemIterLbmIterRatio=int(dt/DEMdt0);
+ newDEMdt=dt/DemIterLbmIterRatio;
+ }else{newDEMdt=dt/DemIterLbmIterRatio;}
+ scene->dt=newDEMdt;
+ if(SaveMode==2){
+ IterSave=TimeSave/(dt);
+ if(TimeSave<dt) {cerr <<"Warning SaveMode==2 and TimeSave<dt."<<endl; exit(-1);}
+ }
+ writelogfile();
+
+ /*------------------------------------------*/
+ /* Initialization of distribution functions */
+ /*------------------------------------------*/
+ for (int nidx=0; nidx<Nx*Ny; nidx++){
+ nodes[nidx].rhob=1.;
+ nodes[nidx].velb=Vector3r::Zero();
+ for (int didx=0; didx<NbDir; didx++){
+ cub = 3.0* eib[didx].dot(nodes[nidx].velb);
+ feqb = w[didx]*nodes[nidx].rhob*(1.0 + cub + 0.5*(cub*cub) - 1.5*((nodes[nidx].velb.x()*nodes[nidx].velb.x()) + (nodes[nidx].velb.y()*nodes[nidx].velb.y())));
+ nodes[nidx].f.push_back(feqb);
+ nodes[nidx].fpostcol.push_back(0.);
+ nodes[nidx].fprecol.push_back(0.);
+ }
+ }
+ firstRun = false;
+ }
+
+ /*----------------------------------------------------------------------*/
+ /* FOR ALL ITERATIONS */
+ /*----------------------------------------------------------------------*/
+ Real Error = 1.0;
+ DEMdt=scene->dt;
+ DEM_TIME=DEM_ITER*DEMdt;
+ for (iter=0; iter<IterMax; iter++){
+ step += 1;
+ LBM_ITER++;
+ LBM_TIME=LBM_ITER*dt;
+
+ /*------------------------------------------------------------------*/
+ /* REINITIALIZATION RELATIVE TO THE MODE 1 */
+ /*------------------------------------------------------------------*/
+ if(MODE==1){
+ FOREACH(const shared_ptr<Body>& b, *scene->bodies){
+ if(!b) continue;
+ const int id=b->getId();
+ LBbodies[id].force=Vector3r::Zero();
+ LBbodies[id].momentum=Vector3r::Zero();}
+ }
+
+ /*------------------------------------------------------------------*/
+ /* GENERAL REINITIALIZATION */
+ /*------------------------------------------------------------------*/
+ Vector3r WallBottomVel=Vector3r::Zero();//m s-1
+ FmoyCur=0.;
+ VmeanFluidC=0.; VmaxC=-1000000.; VminC=1000000.;
+ RhomaxC=-1000000.; RhominC=1000000.;RhoTot=0.;
+ /*------------------------------------------------------------------*/
+ /* Loop on nodes */
+ /*------------------------------------------------------------------*/
+ #pragma omp parallel for
+ for (int nidx=0; nidx<Nx*Ny; nidx++){
+ if(nodes[nidx].checkIsNewObstacle()) {newObstacleCells_couter++;}
+ else{if(nodes[nidx].checkIsNewFluid()) {newFluidCells_couter++;}}
+ if(nodes[nidx].applyBC){
+ Vector3r U=Vector3r::Zero();
+ Real density=0.;
+ /*----------- inlet ------------*/
+ if(nodes[nidx].applyXmBC){
+ if(XmBCType==1){
+ density=1.0 + dP.x()/(Rho*cs*cs);
+ U=Vector3r(1.0-((nodes[nidx].f[0]+nodes[nidx].f[2]+nodes[nidx].f[4]) + 2.0*(nodes[nidx].f[3]+nodes[nidx].f[6]+nodes[nidx].f[7]))/density,0.,0.);
+ }else if(XmBCType==2){
+ U=Vector3r::Zero();
+ density=(nodes[nidx].f[0]+nodes[nidx].f[2]+nodes[nidx].f[4]+2.*(nodes[nidx].f[3]+nodes[nidx].f[6]+nodes[nidx].f[7]))/(1.-U.x());
+ }
+ nodes[nidx].MixteBC(model,density,U,"Xm");
+ /*----------- outlet ------------*/
+ }else if( nodes[nidx].applyXpBC){
+ if(XpBCType==1){
+ density=1.0;
+ U=Vector3r(-1.0 + ((nodes[nidx].f[0]+nodes[nidx].f[2]+nodes[nidx].f[4]) + 2.0*(nodes[nidx].f[1]+nodes[nidx].f[5]+nodes[nidx].f[8]))/density,0.,0.);
+ }else if(XpBCType==2){
+ U=Vector3r::Zero();
+ density=(nodes[nidx].f[0]+nodes[nidx].f[2]+nodes[nidx].f[4]+2.*(nodes[nidx].f[1]+nodes[nidx].f[5]+nodes[nidx].f[8]))/(1.+U.x());
+ }
+ nodes[nidx].MixteBC(model,density,U,"Xp");
+ /*----------- top ------------*/
+ } else if( nodes[nidx].applyYpBC){
+ if(YpBCType==1){
+ density=1.0;
+ U=Vector3r(0.,-1.0 + ((nodes[nidx].f[0]+nodes[nidx].f[1]+nodes[nidx].f[3]) + 2.0*(nodes[nidx].f[2]+nodes[nidx].f[5]+nodes[nidx].f[6]))/density,0.);
+ }else if(YpBCType==2){
+ U=Vector3r::Zero();
+ density=(nodes[nidx].f[0]+nodes[nidx].f[1]+nodes[nidx].f[3]+2.*(nodes[nidx].f[2]+nodes[nidx].f[5]+nodes[nidx].f[6]))/(1.+U.y());
+ }
+ nodes[nidx].MixteBC(model,density,U,"Yp");
+ /*----------- bottom ------------*/
+ }else if( nodes[nidx].applyYmBC){
+ if(YmBCType==1){
+ density=1.0;
+ U=Vector3r(0.,1.0-((nodes[nidx].f[0]+nodes[nidx].f[1]+nodes[nidx].f[3]) + 2.0*(nodes[nidx].f[4]+nodes[nidx].f[7]+nodes[nidx].f[8]))/density,0.);
+ }else if(YmBCType==2){
+ U=Vector3r::Zero();
+ density=(nodes[nidx].f[0]+nodes[nidx].f[1]+nodes[nidx].f[3]+2.*(nodes[nidx].f[4]+nodes[nidx].f[7]+nodes[nidx].f[8]))/(1.-U.y());
+ }
+ nodes[nidx].MixteBC(model,density,U,"Ym");
+ /*----------- bottom-left ------------*/
+ }else if(nodes[nidx].applyYmXmBC){
+ if(XmYmZpBCType==1){
+ cerr <<"XmYmZpType=1 not implemented . Exit"<<endl;
+ exit(-1);
+ }else if(XmYmZpBCType==2){
+ U=Vector3r::Zero();
+ density=nodes[nidx+1].rhob;
+ }
+ nodes[nidx].MixteBC(model,density,U,"XmYmZp");
+ /*----------- top-left ------------*/
+ }else if(nodes[nidx].applyYpXmBC){
+ if(XmYpZpBCType==1){
+ cerr <<"XmYpZpBCType=1 not implemented . Exit"<<endl;
+ exit(-1);
+ }else if(XmYpZpBCType==2){
+ U=Vector3r::Zero();
+ density=nodes[nidx+1].rhob;
+ }
+ nodes[nidx].MixteBC(model,density,U,"XmYpZp");
+ /*----------- bottom-right ------------*/
+ }else if(nodes[nidx].applyYmXpBC){
+ if(XpYmZpBCType==1){
+ cerr <<"XpYmZpBCType=1 not implemented . Exit"<<endl;
+ exit(-1);
+ }else if(XpYmZpBCType==2){
+ U=Vector3r::Zero();
+ density=nodes[nidx-1].rhob;
+ }
+ nodes[nidx].MixteBC(model,density,U,"XpYmZp");
+ /*----------- top-right ------------*/
+ }else if(nodes[nidx].applyYpXpBC){
+ if(XpYpZpBCType==1){
+ cerr <<"XpYpZpBCType=1 not implemented . Exit"<<endl;
+ exit(-1);
+ }else if(XpYpZpBCType==2){
+ U=Vector3r::Zero();
+ density=nodes[nidx-1].rhob;
+ }
+ nodes[nidx].MixteBC(model,density,U,"XpYpZp");
+ }else{
+ cerr << "ERROR: node "<<nidx<<". Looking for a BC to apply ..."<<endl;
+ exit(-1);
+ }
+ }
+
+ nodes[nidx].rhob=0.;
+ nodes[nidx].velb=Vector3r::Zero();
+ nodes[nidx].IsolNb=0;
+ if(nodes[nidx].isFluidBoundary){nodes[nidx].IsolNb=8;}
+
+ for (int dndx=0; dndx<NbDir; dndx++){
+ nodes[nidx].fprecol[dndx] = nodes[nidx].f[dndx];
+ nodes[nidx].velb += eib[dndx]*nodes[nidx].f[dndx];
+ nodes[nidx].rhob += nodes[nidx].f[dndx];
+ if((nodes[nidx].isFluidBoundary)&&(nodes[nidx].neighbour_id[dndx]!=-1)){
+ int ns=nodes[nidx].neighbour_id[dndx];
+ if(!nodes[ns].isObstacle) nodes[nidx].IsolNb=nodes[nidx].IsolNb-1;
+ if(nodes[nidx].IsolNb<0) {cerr<<"isolNb<0"<<endl;exit(-1);}}
+
+ }
+ nodes[nidx].velb /= nodes[nidx].rhob;
+
+ Real temp0=1.5*((nodes[nidx].velb.x()*nodes[nidx].velb.x())+(nodes[nidx].velb.y()*nodes[nidx].velb.y()));
+ Real cub0 = 3.0* eib[0].dot(nodes[nidx].velb);
+ nodes[nidx].fpostcol[0]= nodes[nidx].f[0] - omega * (nodes[nidx].f[0]-(nodes[nidx].rhob* w[0]*( 1. + cub0 + 0.5*(cub0*cub0) - temp0)));
+
+
+ nodes[nidx].fpostcol[0] = nodes[nidx].fpostcol[0] + (nodes[nidx].rhob* w[0])/c2 * eib[0].dot(CstBodyForce);
+ nodes[nidx].f[0]=nodes[nidx].fpostcol[0];
+ RhoTot+=nodes[nidx].rhob;
+ if(nodes[nidx].body_id==-1)if(VmaxC<c*nodes[nidx].velb.norm()) VmaxC=c*nodes[nidx].velb.norm();
+ if(VminC>c*nodes[nidx].velb.norm()) VminC=c*nodes[nidx].velb.norm();
+ if(RhomaxC<Rho*nodes[nidx].rhob) RhomaxC=Rho*nodes[nidx].rhob;
+ if(RhominC>Rho*nodes[nidx].rhob) RhominC=Rho*nodes[nidx].rhob;
+ if(!nodes[nidx].isObstacle) VmeanFluidC+=c*nodes[nidx].velb.norm();
+ }
+
+ #pragma omp parallel for
+ for(unsigned int lid=0;lid<links.size();lid++){
+ int nidx1 = links[lid].nid1;
+ int nidx2 = links[lid].nid2;
+ int dndx1 = links[lid].i;
+ int dndx2 = opp[links[lid].i];
+
+ /*-------------------------------------------------- ---------------*/
+ /* equilibrium functions and collisions */
+ /*------------------------------------------------------------------*/
+ Real temp1=1.5*((nodes[nidx1].velb.x()*nodes[nidx1].velb.x())+(nodes[nidx1].velb.y()*nodes[nidx1].velb.y()));
+ Real cub1 = 3.0* eib[dndx1].dot(nodes[nidx1].velb);
+ nodes[nidx1].fpostcol[dndx1] = nodes[nidx1].fprecol[dndx1] - omega * (nodes[nidx1].fprecol[dndx1]-(nodes[nidx1].rhob* w[dndx1]*( 1. + cub1 + 0.5*(cub1*cub1) - temp1)));
+ nodes[nidx1].fpostcol[dndx1] = nodes[nidx1].fpostcol[dndx1] + (nodes[nidx1].rhob* w[dndx1])/c2 * eib[dndx1].dot(CstBodyForce);
+ if(!links[lid].PointingOutside){
+ Real temp2=1.5*((nodes[nidx2].velb.x()*nodes[nidx2].velb.x())+(nodes[nidx2].velb.y()*nodes[nidx2].velb.y()));
+ Real cub2 = 3.0* eib[dndx2].dot(nodes[nidx2].velb);
+ nodes[nidx2].fpostcol[dndx2] = nodes[nidx2].fprecol[dndx2] - omega * (nodes[nidx2].fprecol[dndx2]-(nodes[nidx2].rhob* w[dndx2]*( 1. + cub2 + 0.5*(cub2*cub2) - temp2)));
+ nodes[nidx2].fpostcol[dndx2] = nodes[nidx2].fpostcol[dndx2] + (nodes[nidx2].rhob* w[dndx2])/c2 * eib[dndx2].dot(CstBodyForce);
+ }
+
+ /*-------------------------------------------------- ---------------*/
+ /* Streaming */
+ /*------------------------------------------------------------------*/
+ if(links[lid].PointingOutside){
+ /// Periodicity is currently disabled until it is implemented through the link list.
+///FIXME
+ I=nodes[nidx1].i+eib[dndx1].x();
+ J=nodes[nidx1].j+eib[dndx1].y();
+ if(Xperiodicity){ if (I==Nx) {I=0;} else {if (I==-1) { I=Nx-1;}} }
+ if(Yperiodicity){ if (J==Ny) {J=0;} else {if (J==-1) { J=Ny-1;}} }
+ }else{
+ nodes[nidx1].f[dndx2]=nodes[nidx2].fpostcol[dndx2];
+ nodes[nidx2].f[dndx1]=nodes[nidx1].fpostcol[dndx1];
+ }
+
+ if(links[lid].isBd==false) continue;
+
+ int idx_sigma_i=links[lid].idx_sigma_i;
+ int sid= links[lid].sid;
+ int fid= links[lid].fid;
+ int BodyId=nodes[sid].body_id;
+
+
+ /*--- forces and momenta for this boundary link ---*/
+ links[lid].ct=3.0*w[idx_sigma_i]*nodes[sid].rhob*eib[links[lid].idx_sigma_i].dot(links[lid].VbMid);
+ Vector3r force_ij = eib[links[lid].idx_sigma_i] * (nodes[fid].fpostcol[idx_sigma_i] - links[lid].ct);
+ Vector3r lubforce_ij = Vector3r::Zero();
+ Vector3r totalforce_ij = force_ij+lubforce_ij;
+ Vector3r totalmomentum_ij = links[lid].DistMid.cross(totalforce_ij);
+
+ /* Sum over all boundary links of all boundary nodes */
+ LBbodies[BodyId].force=LBbodies[BodyId].force+totalforce_ij;
+ LBbodies[BodyId].momentum=LBbodies[BodyId].momentum+totalmomentum_ij;
+
+ /*------------------------------------------------------*/
+ /* Modified Bounce back rule */
+ if(nodes[fid].IsolNb>=5) {links[lid].VbMid=Vector3r::Zero();links[lid].ct=0.;}
+ nodes[fid].f[opp[idx_sigma_i]] = nodes[fid].fpostcol[idx_sigma_i] - 2.0*links[lid].ct;
+ nodes[sid].f[idx_sigma_i] = nodes[sid].fpostcol[opp[idx_sigma_i]]+ 2.0*links[lid].ct;
+ if( (MODE==2)||((MODE==3)&&(IterMax==1)) ) {links[lid].ReinitDynamicalProperties();}
+
+ }
+ VmeanFluidC=VmeanFluidC/NbFluidNodes;
+
+
+ /*---------------------------------------------*/
+ /* Stop criteria */
+ /*---------------------------------------------*/
+// if(use_ConvergenceCriterion){
+// switch(ErrorCriterion){
+// case 1:
+// /*--------------------------------------------------------*/
+// /* Criterion based on the mean force */
+// /*--------------------------------------------------------*/
+// if((LBM_ITER > 1000) & (LBM_ITER % 10 == 0)){
+// for (int s=NB_WALLS ; s<NB_BODIES; s++) {FmoyCur = FmoyCur + LBbodies[s].force.norm();}
+// FmoyCur = FmoyCur/(NB_DYNGRAINS);
+// if (FmoyCur!=0.){
+// Real ErrorA = abs(FmoyCur-FmoyPrev)/abs(FmoyCur);
+// Real ErrorB = abs(FmoyCur-FmoyPrevPrev)/abs(FmoyCur);
+// Error=max(ErrorA,ErrorB);
+// FmoyPrevPrev=FmoyPrev;
+// FmoyPrev=FmoyCur;
+// }
+// }
+// break;
+// case 2:
+// /*--------------------------------------------------------*/
+// /* Criterion based on the mean velocity */
+// /*--------------------------------------------------------*/
+// if((LBM_ITER > 100) & (LBM_ITER % 10 == 0)){
+// if (VmeanFluidC!=0.){
+// Real ErrorA = abs(VmeanFluidC-PrevVmeanFluidC)/abs(VmeanFluidC);
+// //Real ErrorB = abs(VmeanFluidC-PrevPrevVmeanFluidC)/abs(VmeanFluidC);
+// //Error=max(ErrorA,ErrorB);
+// Error= ErrorA;
+// PrevPrevVmeanFluidC=PrevVmeanFluidC;
+// PrevVmeanFluidC=VmeanFluidC;
+// }
+// }
+// break;
+// default:
+// cerr <<"Unknow ErrorCriterion value ! "<<endl;
+// exit(-1);
+// break;
+// }
+// }
+
+ if(LBM_ITER%IterPrint==0){
+ cerr.precision(6);
+ cerr <<"__________________________________________________________________________"<<endl;
+ cerr << "| Run in mode : "<<MODE<<endl;
+ cerr <<"| New Obstacle nodes: "<<newObstacleCells_couter<<" New Fluid nodes: "<<newFluidCells_couter<<endl;
+ cout <<"| height/width/depth (m) "<<height<<" / "<<width<<" / "<<depth<<endl;
+ cerr <<"|------------------------------------------------------------------------|"<<endl;
+ cerr <<"| \t\tDEM\t\t | \t\tLBM\t\t |"<<endl;
+ cerr <<"|------------------------------------------------------------------------|"<<endl;
+ cerr <<"| t (s)\t: "<<DEM_TIME<<"\t\t | t (s)\t\t: "<<LBM_TIME<<"\t\t "<<endl;
+ cerr <<"| Iter\t\t: "<<DEM_ITER<<"\t\t | Iter\t\t: "<<LBM_ITER<<"\t\t "<<endl;
+ cerr <<"| Nb dyn ptc\t: "<<NumberOfDynamicParticles<<"\t\t | M\t\t: "<<VmaxC/c<<"\t "<<endl;
+ cerr <<"| \t\t\t\t | "<<VminC<<"\t< <V(t)> (m/s)= "<<VmeanFluidC <<"\t< "<<VmaxC<<"\t "<<endl;
+ cerr <<"| \t\t\t\t | "<<RhominC<<"\t< rho(t) (m3/kg) <"<<RhomaxC<<"\t "<<endl;
+ cerr <<"| \t\t\t\t | RhoTot (adim) \t: "<<RhoTot<<"\t "<<endl;
+ if(ObservedPtc!=-1){
+ Vector3r tmp=2.*Rho*c2*dx*LBbodies[ObservedPtc].force; cerr <<"| \t\t\t\t\t | F (N) \t: "<<tmp<<"\t "<<endl;
+ tmp=LBbodies[ObservedPtc].pos*dx; cerr <<"| \t\t\t\t\t | pos (m) \t: "<<tmp<<"\t "<<endl;
+ tmp=LBbodies[ObservedPtc].vel*c; cerr <<"| \t\t\t\t\t | VPtc (m/s)\t: "<<tmp<<"\t \t\t\t\t "<<endl;
+ }
+ if(((MODE==2)||(MODE==3))&&(NB_DYNGRAINS>0)){
+ cerr <<"| VminPtcC (m/s)\t: "<<CurMinVelOfPtc<<"\t |\t\t\t\t "<<endl;
+ cerr <<"| VmaxPtcC (m/s)\t: "<<CurMaxVelOfPtc<<"\t |\t\t\t\t "<<endl;
+ }
+ if( ((MODE==1)&&firstRun) || (MODE==2) || (MODE==3)){
+ cerr <<"| \t\t\t\t\t | NbNodes\t: "<<NbNodes<<"\t "<<endl;
+ cerr <<"| \t\t\t\t\t | Fluid nodes\t: "<<NbFluidNodes<<"\t\t "<<endl;
+ cerr <<"| \t\t\t\t\t | Solid nodes\t: "<<NbSolidNodes<<"\t\t "<<endl;
+ }
+ if(ObservedNode!=-1){
+ cerr <<"| \t\t\t\t\t | Track node\t: "<<ObservedNode<<"\t\t "<<endl;
+ cerr <<"| \t\t\t\t\t | \t V(m/s)\t: "<<nodes[ObservedNode].velb.norm()<<"\t\t "<<endl;
+ cerr <<"| \t\t\t\t\t | \t rho\t: "<<Rho*nodes[ObservedNode].rhob<<"\t\t "<<endl;
+ }
+ if(use_ConvergenceCriterion){
+ cerr <<"| \t\t\t\t\t | Error\t: "<<Error<<"\t\t "<<endl;
+ cerr <<"| \t\t\t\t\t | with criterion "<<ErrorCriterion<<" \t\t "<<endl;
+ }
+ cerr <<"|------------------------------------------------------------------------|"<<endl;
+ }
+
+
+ /*-------------------------------------------------------------------------------*/
+ /*------------- RESULT RECORDING DURING COMPUTATION (MODE 1)--------------------*/
+ /*-------------------------------------------------------------------------------*/
+ if(((iter % (IterSave*DemIterLbmIterRatio) == 0)||(firstRun))&&MODE==1) {
+ if(((iter % (IterSave*SaveGridRatio*DemIterLbmIterRatio) == 0)||(firstRun))&&MODE==1) save(iter,dt);
+ saveStats(iter,dt);
+ if(SAVE_OBSERVEDPTC) {
+ CalculateAndApplyForcesAndTorquesOnBodies(true,false);
+ saveObservedPtc(iter,dt);
+ }
+ if(SAVE_OBSERVEDNODE) saveObservedNode(iter,dt);
+ }
+
+
+ if((IterSubCyclingStart>0)&&(iter+1>=IterSubCyclingStart)) {modeTransition();}
+ if ((Error < ConvergenceThreshold)&&(use_ConvergenceCriterion)) {
+ if(MODE==1) break;
+ if(MODE==3) modeTransition();
+ }
+ if((EndTime>0)&&(LBM_TIME>EndTime)) LbmEnd();
+ //if((InitialNumberOfDynamicParticles!=0)&&(NumberPtcEroded==InitialNumberOfDynamicParticles)) LbmEnd();
+}
+/*------------------- End of the LBM loop (iterations) --------------------*/
+
+
+if(MODE==1) {
+ cerr << "LBM ended after " << step << " iterations";
+ cerr <<" | LBM_ITER = "<< LBM_ITER<<" | Error = " << Error << endl;
+}
+
+/*--------------------------------------------------------------------------------*/
+/*-------------- APPLICATION OF HYDRODYNAMIC FORCES ON SPHERES -------------------*/
+/*--------------------------------------------------------------------------------*/
+if(applyForcesAndTorques) CalculateAndApplyForcesAndTorquesOnBodies(true,true);
+
+/*----------------------------------------------------------------------------*/
+/*----------------- SPHERES ARE MOVED OUTSIDE THE SIMULATION DOMAIN --------- */
+/*----------------------------------------------------------------------------*/
+//if(removingCriterion!=0){
+// for(unsigned int aa=0; aa<IdOfNextErodedPtc.size();aa++){
+// int IdRemoved=IdOfNextErodedPtc[aa];
+// LBbodies[IdRemoved].isEroded=true;
+// shared_ptr<Body> b=Body::byId(IdRemoved);
+// const shared_ptr<Sphere>& sphere = YADE_PTR_CAST<Sphere> ( b->shape );
+// Real r=sphere->radius;
+// outside_limit=outside_limit+1.1*r;
+// b->state->pos=Vector3r(outside_limit,0.,0.);
+// b->setDynamic(false);
+// NB_DYNGRAINS--;
+// NB_DYNBODIES--;
+// outside_limit=outside_limit+1.1*r;
+// cerr <<"Eroded Ptc: "<<IdRemoved<<endl;
+// NumberPtcEroded+=1;
+// if(!strcmp(model.c_str(), "d2q9" )) Vr += Mathr::PI*(r*r);
+// else Vr += 4./3.*Mathr::PI*(r*r*r);
+// }
+// if(IdOfNextErodedPtc.size()!=0) saveEroded(DEM_ITER,DEMdt);
+//}
+
+/*----------------------------------------------------------------------------*/
+/*------------- RESULT RECORDING AT THE END OF THE COMPUTATION ---------------*/
+/*----------------------------------------------------------------------------*/
+ if(((DEM_ITER % (IterSave*DemIterLbmIterRatio) == 0)||(firstRun))&&IterMax==1 ){
+ if(((DEM_ITER % (IterSave*SaveGridRatio*DemIterLbmIterRatio) == 0)||(firstRun))&&IterMax==1 ) save(DEM_ITER,DEMdt);
+ saveStats(DEM_ITER,DEMdt);
+ //saveEroded(DEM_ITER,DEMdt);
+ if(SAVE_OBSERVEDPTC) saveObservedPtc(DEM_ITER,DEMdt);
+ if(SAVE_OBSERVEDNODE) saveObservedNode(DEM_ITER,DEMdt);
+ }
+}
+
+void HydrodynamicsLawLBM::save(int iter_number, Real timestep)
+{
+
+ /*--------------------------------------------*/
+ /* Recording of properties of LBM nodes */
+ /*--------------------------------------------*/
+
+ bool saveLBMdata = false; // Flag to avoid to loop over all the lbm node if no lbm data are saved but only spheres data
+
+ std::stringstream Vfile_name;
+ std::stringstream Vxfile_name;
+ std::stringstream Vyfile_name;
+ std::ofstream Vfile;
+ std::ofstream Vxfile;
+ std::ofstream Vyfile;
+
+ std::stringstream FxLBMfile_name;
+ std::stringstream FyLBMfile_name;
+ std::stringstream MzLBMfile_name;
+ std::ofstream FxLBMfile;
+ std::ofstream FyLBMfile;
+ std::ofstream MzLBMfile;
+
+ std::stringstream Rhofile_name;
+ std::ofstream Rhofile;
+
+ std::stringstream Bodiesfile_name;
+ std::ofstream Bodiesfile;
+
+ std::stringstream NodeBoundaryfile_name;
+ std::ofstream NodeBoundaryfile;
+
+ std::stringstream NewNodefile_name;
+ std::ofstream NewNodefile;
+
+
+ /*--- VELOCITIES ---*/
+ if(SAVE_VELOCITY){
+ Vfile_name<<lbm_dir<<"/V"<<"_"; Vfile_name.width(10);
+ Vfile_name.fill('0'); Vfile_name<<iter_number;
+ Vfile.open(Vfile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+ if(SAVE_VELOCITYCOMP){
+ Vxfile_name<<lbm_dir<<"/Vx"<<"_";Vxfile_name.width(10);
+ Vyfile_name<<lbm_dir<<"/Vy"<<"_";Vyfile_name.width(10);
+
+ Vxfile_name.fill('0'); Vxfile_name<<iter_number;
+ Vyfile_name.fill('0'); Vyfile_name<<iter_number;
+
+ Vxfile.open(Vxfile_name.str().c_str());Vyfile.open(Vyfile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+ /*--- FORCES ---*/
+ if(SAVE_FORCES){
+ FxLBMfile_name<<lbm_dir<<"/Fx"<<"_";FxLBMfile_name.width(10);
+ FyLBMfile_name<<lbm_dir<<"/Fy"<<"_";FyLBMfile_name.width(10);
+ MzLBMfile_name<<lbm_dir<<"/Mz"<<"_";MzLBMfile_name.width(10);
+
+ FxLBMfile_name.fill('0'); FxLBMfile_name<<iter_number;
+ FyLBMfile_name.fill('0'); FyLBMfile_name<<iter_number;
+ MzLBMfile_name.fill('0'); MzLBMfile_name<<iter_number;
+
+ FxLBMfile.open(FxLBMfile_name.str().c_str());
+ FyLBMfile.open(FyLBMfile_name.str().c_str());
+ MzLBMfile.open(MzLBMfile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+ /*--- DENSITY ---*/
+ if(SAVE_RHO){
+ Rhofile_name<<lbm_dir<<"/Rho"<<"_";Rhofile_name.width(10);
+ Rhofile_name.fill('0'); Rhofile_name<<iter_number;
+ Rhofile.open(Rhofile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+ /*--- BODIES ---*/
+ if(SAVE_BODIES){
+ Bodiesfile_name<<lbm_dir<<"/Bodies"<<"_";Bodiesfile_name.width(10);
+ Bodiesfile_name.fill('0'); Bodiesfile_name<<iter_number;
+ Bodiesfile.open(Bodiesfile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+ /*--- BOUNDARY NODES ---*/
+ if(SAVE_NODEBD){
+ NodeBoundaryfile_name<<lbm_dir<<"/NodeBoundary"<<"_";
+ NodeBoundaryfile_name.width(10);
+ NodeBoundaryfile_name.fill('0'); NodeBoundaryfile_name<<iter_number;
+ NodeBoundaryfile.open(NodeBoundaryfile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+ /*--- NEW NODES ---*/
+ if(SAVE_NODEISNEW){
+ NewNodefile_name<<lbm_dir<<"/NewNode"<<"_";
+ NewNodefile_name.width(10);
+ NewNodefile_name.fill('0'); NewNodefile_name<<iter_number;
+ NewNodefile.open(NewNodefile_name.str().c_str());
+
+ saveLBMdata = true;
+ }
+
+
+
+ if(saveLBMdata){ //Condition to avoid to loop over all the lbm node if no lbm data are saved but only spheres data
+
+ cerr << "| Saving ("<<iter_number<<")"<<endl;
+
+ for (int nidx=0; nidx<Nx*Ny; nidx++){
+ if(SAVE_BODIES) Bodiesfile <<nodes[nidx].body_id<<" ";
+ if(SAVE_VELOCITY) Vfile<< c*nodes[nidx].velb.norm()<< " ";
+ if(SAVE_VELOCITYCOMP){Vxfile<< c*nodes[nidx].velb.x()<< " ";Vyfile<< c*nodes[nidx].velb.y()<< " ";}
+ if(SAVE_FORCES){
+ if(nodes[nidx].body_id>=0){
+ FxLBMfile<< 2.*Rho*c2*dx*(LBbodies[nodes[nidx].body_id].force.x()) << " ";
+ FyLBMfile<< 2.*Rho*c2*dx*(LBbodies[nodes[nidx].body_id].force.y()) << " ";
+ MzLBMfile<< 2.*Rho*c2*dx2*LBbodies[nodes[nidx].body_id].momentum.z() << " ";
+ }
+ else{FxLBMfile<< 0. << " ";FyLBMfile<< 0. << " ";MzLBMfile<< 0. << " ";}}
+ if(SAVE_RHO) Rhofile << Rho*nodes[nidx].rhob << " ";
+ if(SAVE_NODEBD) {
+ int tmp=0;
+ if(nodes[nidx].isObstacleBoundary) tmp=nodes[nidx].isObstacleBoundary;
+ if(nodes[nidx].isFluidBoundary) tmp= -1;
+ NodeBoundaryfile << tmp << " ";}
+ if(SAVE_NODEISNEW) {
+ int tmp=0;
+ if(nodes[nidx].isNewObstacle) tmp=nodes[nidx].isNewObstacle;
+ if(nodes[nidx].isNewFluid) tmp=-1;
+ NewNodefile << tmp << " ";}
+
+ if(nodes[nidx].i==Nx-1){
+ if(SAVE_BODIES) Bodiesfile<< endl;
+ if(SAVE_VELOCITY) Vfile<< endl;
+ if(SAVE_VELOCITYCOMP){Vxfile<< endl;Vyfile<< endl;}
+ if(SAVE_FORCES){FxLBMfile << endl;FyLBMfile << endl;MzLBMfile << endl;}
+ if(SAVE_RHO) Rhofile << endl;
+ if(SAVE_NODEBD) NodeBoundaryfile << endl;
+ if(SAVE_NODEISNEW) NewNodefile << endl;
+ }
+ }
+ }
+
+ std::stringstream cmd;
+ cmd<<"bzip2";
+ if(SAVE_BODIES) {Bodiesfile.close();cmd<<" "<<Bodiesfile_name.str().c_str();}
+ if(SAVE_VELOCITY) {Vfile.close();cmd<<" "<<Vfile_name.str().c_str();}
+ if(SAVE_VELOCITYCOMP) {Vxfile.close(); Vyfile.close();cmd<<" "<<Vxfile_name.str().c_str()<<" "<<Vyfile_name.str().c_str();}
+ if(SAVE_FORCES){
+ FxLBMfile.close();FyLBMfile.close();MzLBMfile.close();
+ cmd<<" "<<FxLBMfile_name.str().c_str()<<" "<<FyLBMfile_name.str().c_str()<<" "<<MzLBMfile_name.str().c_str();}
+ if(SAVE_RHO) {Rhofile.close();cmd<<" "<<Rhofile_name.str().c_str();}
+ if(SAVE_NODEBD) {NodeBoundaryfile.close();cmd<<" "<<NodeBoundaryfile_name.str().c_str();}
+ if(SAVE_NODEISNEW) {NewNodefile.close();cmd<<" "<<NewNodefile_name.str().c_str();}
+ //cmd<<"&";
+ if(COMPRESS_DATA) {if(std::system(cmd.str().c_str())) cerr<<"bzip error"<<endl;}
+
+
+ /*--------------------------------------------*/
+ /* Recording of properties of DEM objects */
+ /*--------------------------------------------*/
+ if(SAVE_SPHERES){ //condition to save spheres properties only if it is required by the operator, checking if NB_GRAINS > 0 is done earlier when recording configuration is done
+ spherefile_name.str("");
+ spherefile_name<<dem_dir<<"/spheres";
+ cerr <<" Write DEM data in "<<spherefile_name.str().c_str()<<endl;
+ spherefile_name<<"_";
+ spherefile_name.width(10);
+ spherefile_name.fill('0');
+ spherefile_name<<iter_number;
+ std::ofstream spherefile;
+ spherefile.open(spherefile_name.str().c_str());
+
+ for (unsigned int l=0;l<LBbodies.size();l++){
+ if(LBbodies[l].isPtc()){
+ if((!LBbodies[l].isEroded)&&(LBbodies[l].saveProperties)){
+ spherefile<<l<<" "; /* Id*/
+ spherefile<<dx*LBbodies[l].pos.x()<<" "<<dx*LBbodies[l].pos.y()<<" "<<dx*LBbodies[l].pos.z()<<" "; /* x, y, z*/
+ spherefile<<dx*LBbodies[l].radius<<" "; /* r*/
+ spherefile<<c*LBbodies[l].vel.x()<<" "<<c*LBbodies[l].vel.y()<<" "<<c*LBbodies[l].vel.z()<<" "; /* Vx, Vy, Vz*/
+ spherefile<<invdt*LBbodies[l].AVel.x()<<" "<<invdt*LBbodies[l].AVel.y()<<" "<<invdt*LBbodies[l].AVel.z()<<" "; /* Wx, Wy, Wz*/
+ spherefile<<LBbodies[l].Fh.x()<<" "<<LBbodies[l].Fh.y()<<" "<<LBbodies[l].Fh.z()<<" "; /* Fhx, Fhy, Fhz */
+ spherefile<<LBbodies[l].Mh.x()<<" "<<LBbodies[l].Mh.y()<<" "<<LBbodies[l].Mh.z()<<endl; /* Mhx, Mhy, Mhz */
+ }
+ }
+ }
+ spherefile.close();
+ }
+
+#ifdef LBM_VERBOSE
+cerr <<"END: HydrodynamicsLawLBM::save()"<<endl;
+#endif
+return;
+}
+
+void HydrodynamicsLawLBM::saveStats(int iter_number, Real timestep)
+{
+ #ifdef LBM_VERBOSE
+ cerr <<"START: HydrodynamicsLawLBM::saveStats()"<<endl;
+ #endif
+ cerr << "| Save stats ..."<<endl;
+ ofstream file(LBMmachFile.c_str(), ios::app);
+ file <<iter_number<<" "<<iter_number*timestep<<" "<<VmaxC<<" "<<VmaxC/c<<endl;
+ #ifdef LBM_VERBOSE
+ cerr <<"END: HydrodynamicsLawLBM::saveStats()"<<endl;
+ #endif
+ return;
+}
+//void HydrodynamicsLawLBM::saveEroded(int iter_number, Real timestep)
+//{
+//
+// cerr << "| Save Eroded Ptc ..."<<endl;
+// ofstream file(RemovedPtcFile.c_str(), ios::app);
+// file <<iter_number<<" "<<iter_number*timestep<<" "<<NumberPtcEroded<<" "<<Vr<<" "<<Vr/Vo<<" "<<FhTotale<<endl;
+//
+// return;
+//}
+void HydrodynamicsLawLBM::saveObservedPtc(int iter_number, Real timestep)
+{
+
+ cerr << "| Save Observed Ptc ..."<<endl;
+ ofstream file(ObservedPtcFile.c_str(), ios::app);
+ file <<iter_number<<" "<<iter_number*timestep<<" ";
+ file <<dx*LBbodies[ObservedPtc].pos.x()<<" "<<dx*LBbodies[ObservedPtc].pos.y()<<" "<<dx*LBbodies[ObservedPtc].pos.z()<<" ";
+ file <<dx*LBbodies[ObservedPtc].radius<<" ";
+ file <<c*LBbodies[ObservedPtc].vel.x()<<" "<<c*LBbodies[ObservedPtc].vel.y()<<" "<<c*LBbodies[ObservedPtc].vel.z()<<" ";
+ file <<invdt*LBbodies[ObservedPtc].AVel.x()<<" "<<invdt*LBbodies[ObservedPtc].AVel.y()<<" "<<invdt*LBbodies[ObservedPtc].AVel.z()<<" ";
+ file <<LBbodies[ObservedPtc].Fh.x()<<" "<<LBbodies[ObservedPtc].Fh.y()<<" "<<LBbodies[ObservedPtc].Fh.z()<<" ";
+ file <<LBbodies[ObservedPtc].Mh.x()<<" "<<LBbodies[ObservedPtc].Mh.y()<<" "<<LBbodies[ObservedPtc].Mh.z()<<endl;
+
+ return;
+}
+void HydrodynamicsLawLBM::saveObservedNode(int iter_number, Real timestep)
+{
+ return;
+}
+/*
+_________________________________________________________________________
+*/
+
+void HydrodynamicsLawLBM::createNewFiles()
+{
+
+ //spherefile_name<<dem_dir<<"/spheres"; //Useless here
+
+ ofstream file(LBMmachFile.c_str());
+ file <<"#iter_number\t time\t VmaxC\t VmaxC/c"<<endl;
+ file.close();
+
+ if(removingCriterion!=0){
+ ofstream file2(RemovedPtcFile.c_str());
+ file2 <<"#Iter time NumberPtcEroded Vr Vr/Vo FhTotale"<<endl;
+ file2.close();
+ }
+
+ if(SAVE_CONTACTINFO){
+ ofstream file3(LBMcontactsFile.c_str());
+ file3 <<"#Iter time NumberOfContact"<<endl;
+ file3.close();
+ }
+ //if(NB_GRAINS>0) {ofstream file3(spherefile_name.str().c_str());file3.close();} //For what this line is used for? It seems to work without
+
+ if(SAVE_OBSERVEDPTC){ //Condition to create observedPtc file only if the recording is required by the operator
+ ofstream file4(ObservedPtcFile.c_str());
+ file4 <<"#iter t x y z r Vx Vy Vz Wx Wy Wz Fx Fy Fz Mx My Mz"<<endl;
+ file4.close();
+ }
+
+ if(SAVE_OBSERVEDNODE){ //Condition to create observedNode file only if the recording is required by the operator
+ ofstream file5(ObservedNodeFile.c_str());file5.close();
+ }
+
+
+ return;
+}
+
+void HydrodynamicsLawLBM::createDirectories(bool dirLBM, bool dirDem, bool dirCntct)
+{
+
+ //bfs::create_directory(bfs::path(lbm_dir)); //ModLuc: to create only necessary directory
+ if(dirLBM) bfs::create_directory(bfs::path(lbm_dir));
+ //if(NB_GRAINS>0) bfs::create_directory(bfs::path(dem_dir)); //ModLuc: to create only necessary directory
+ if(dirDem) bfs::create_directory(bfs::path(dem_dir));
+ //if(SAVE_CONTACTINFO) bfs::create_directory(bfs::path(cntct_dir)); //ModLuc: to create only necessary directory
+ if(dirCntct) bfs::create_directory(bfs::path(cntct_dir));
+
+ return;
+}
+
+void HydrodynamicsLawLBM::writelogfile()
+{
+ ofstream file(LBMlogFile.c_str());
+ file <<"File format: 1"<<endl;
+ file <<"System parameters: "<<endl;
+ file <<"\t Lx0= "<<Lx0<<endl;
+ file <<"\t Ly0= "<<Ly0<<endl;
+ file <<"\t Lz0= "<<Lz0<<endl;
+ file <<"\t Wallthickness= "<<Wallthickness<<endl;
+ file <<"\t dP= "<<dP<<endl;
+ file <<"\t Nu= "<<Nu<<endl;
+ file <<"\t Rho= "<< Rho<<endl;
+ file <<"\t dx= "<< dx<<endl;
+ file <<"\t Nx= "<< Nx<<endl;
+ file <<"\t Ny= "<< Ny<<endl;
+ file <<"\t Nz= "<< Nz<<endl;
+ file <<"LBM parameters: "<<endl;
+ file <<"\t tau= "<<tau<<" omega= "<< omega <<endl;
+ file <<"\t IterMax= "<<IterMax<<endl;
+ file <<"\t SaveMode= "<<SaveMode<<endl;
+ file <<"\t IterSave= "<<IterSave<<endl;
+ file <<"\t SaveGridRatio= "<<SaveGridRatio<<endl;
+ file <<"\t DemIterLbmIterRatio= "<<DemIterLbmIterRatio<<endl;
+ file <<"\t ConvergenceThreshold= "<<ConvergenceThreshold<<endl;
+ file <<"\t Predicted Mach number (may be false)= "<<UMaxtheo/c<<endl;
+ file <<"\t LBM dt= "<<dt<<endl;
+ file <<"DEM parameters: "<<endl;
+ file <<"\t DEM dt= "<<DEMdt0<<endl;
+ file <<"\t DEM adjusted dt= "<<newDEMdt<<endl;
+ file <<"Particles: "<<endl;
+ file <<"\t InitialNumberOfDynamicParticles= "<<InitialNumberOfDynamicParticles<<endl;
+ file <<"\t NB_BODIES= "<<NB_BODIES<<" NB_GRAINS= "<<NB_GRAINS<<endl;
+ file <<"\t NB_DYNBODIES= "<<NB_DYNBODIES<<" NB_DYNGRAINS= "<<NB_DYNGRAINS<<endl;
+ file <<"\t Rmin / Rmax / Rmean = "<<dx*MinBodyRadius<<" / "<<dx*MaxBodyRadius<<" / "<<dx*MeanBodyRadius<<endl;
+ if(NB_GRAINS>0) file <<"\t NbNodePerPtc= "<<NbParticleNodes/NB_GRAINS<<endl;
+ else file <<"\t NbNodePerPtc= "<<-1<<endl;
+ file <<"\t Vo= "<<Vo<<endl;
+ file <<"Misc :"<<endl;
+ file <<"\t VbCutOff= "<<VbCutOff<<endl;
+ //file <<"\t CstBodyForceDensity= "<<CstBodyForceDensity<<endl;
+ file <<"Memory usage"<<endl;
+ file <<"\t Nodes= "<<nodes.size()<<endl;
+ file <<"\t links= "<<links.size()<<endl;
+
+ file.close();
+ return;
+}
+
+void HydrodynamicsLawLBM::modeTransition(){
+ cerr << "Mode transition "<<endl;
+ IterMax=1;
+ IterSubCyclingStart=-1;
+ LBM_ITER=1;
+ use_ConvergenceCriterion=false;
+ return;
+}
+
+void HydrodynamicsLawLBM::LbmEnd(){
+ if(MODE==1) IterMax=iter;
+ Omega::instance().stop();
+ Omega::instance().saveSimulation ("end.xml");
+}
+
+void HydrodynamicsLawLBM::CalculateAndApplyForcesAndTorquesOnBodies(bool mean,bool apply){
+ /*--------------------------------------------------------------------------------*/
+ /*---------------- APPLICATION OF HYDRODYNAMIC FORCES ON SPHERES -----------------*/
+ /*--------------------------------------------------------------------------------*/
+ if(mean) FhTotale=Vector3r::Zero();
+ FOREACH(const shared_ptr<Body>& b, *scene->bodies){
+ if(!b) continue;
+ const int id=b->getId();
+ //if ( ((b->isDynamic())&&(b->shape->getClassName()=="Sphere")) || (b->shape->getClassName()=="Box") ){ //ModLuc: remove the condition (b->isDynamic()) to be able to apply force and torque on non dynamic bodies, by this way hydrodynamic force and torque on bodies can be read through python even if bodies are non dynamic.
+ if ( (b->shape->getClassName()=="Sphere") || (b->shape->getClassName()=="Box") ){
+ if(mean){
+ LBbodies[id].fp=LBbodies[id].force;
+ LBbodies[id].force=0.5*(LBbodies[id].fp+LBbodies[id].fm);
+ LBbodies[id].fm=LBbodies[id].fp;
+ LBbodies[id].mp=LBbodies[id].momentum;
+ LBbodies[id].momentum=0.5*(LBbodies[id].mp+LBbodies[id].mm);
+ LBbodies[id].mm=LBbodies[id].mp;
+ LBbodies[id].Fh=2.*Rho*c2*dx*LBbodies[id].force;
+ LBbodies[id].Mh=2.*Rho*c2*dx2*LBbodies[id].momentum;
+ FhTotale=FhTotale+LBbodies[id].Fh;
+ }
+ if(apply){
+ scene->forces.addForce(id, LBbodies[id].Fh);
+ scene->forces.addTorque(id, LBbodies[id].Mh);
+ }
+ }
+ }
+ return;
+}
+YADE_PLUGIN((HydrodynamicsLawLBM));
+
+#endif //LBM_ENGINE
+
=== added file 'pkg/lbm/HydrodynamicsLawLBM.hpp'
--- pkg/lbm/HydrodynamicsLawLBM.hpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/HydrodynamicsLawLBM.hpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,302 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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. *
+* *
+* Luc Scholtès luc.scholtes@xxxxxxxxxxxxxxxx *
+* and Luc Sibille luc.sibille@xxxxxxxxxxxxxxx also contributed to this *
+* code. *
+* *
+* Lominé F., Scholtès L., Sibille L., Poullain P. (2013) *
+* Modelling of fluid-solid interaction in granular media with coupled *
+* LB/DE methods: application to piping erosion. International Journal *
+* for Numerical and Analytical Methods in Geomechanics, 37(6):577-596 *
+* doi: 10.1002/nag.1109 *
+* *
+* Sibille L., Lominé F., Marot D. (2012) Investigation In Modelling *
+* Piping Erosion With a Coupled «Lattice Boltzmann – Discrete Element» *
+* Numerical Method. in Proc. 6th Int. Conference on Scour and Erosion *
+* (ICSE-6), pp. 93-100. *
+* *
+*************************************************************************/
+#ifdef LBM_ENGINE
+
+#pragma once
+#include<yade/pkg/lbm/LBMnode.hpp>
+#include<yade/pkg/lbm/LBMlink.hpp>
+#include<yade/pkg/lbm/LBMbody.hpp>
+#include<yade/core/GlobalEngine.hpp>
+
+
+class HydrodynamicsLawLBM : public GlobalEngine
+{
+ private :
+ std::ofstream ofile;
+
+ public :
+ bool firstRun, /*! = 1 if it is the first iteration during 1 YADE simulation*/
+ use_ConvergenceCriterion, /*! use stop condition based on the convergence criterion*/
+ SAVE_VELOCITY, /*! Switch to save node velocities*/
+ SAVE_VELOCITYCOMP, /*! Switch to save node velocities in each directions*/
+ SAVE_RHO, /*! Switch to save node densities*/
+ SAVE_FORCES, /*! Switch to save node force and momentum on grid*/
+ SAVE_BODIES, /*! Switch to save particle nodes*/
+ SAVE_NODEBD, /*! Switch to save fluid or solid boundary nodes*/
+ SAVE_NODEISNEW, /*! Switch to save new fluid/solid nodes*/
+ SAVE_DEBUGFILES, /*! Switch to save some debug data*/
+ SAVE_OBSERVEDPTC, /*! Switch to save properties of the observed particle*/
+ SAVE_OBSERVEDNODE, /*! Switch to save properties of the observed node*/
+ SAVE_CONTACTINFO, /*! Switch to save contact properties*/
+ SAVE_SPHERES, /*! Switch to save spheres properties*/
+ COMPRESS_DATA, /*! Switch to enable file compression*/
+ Xperiodicity, /*! Switch to activate lattice periodicity in x direction*/
+ Yperiodicity, /*! Switch to activate lattice periodicity in y direction*/
+ Zperiodicity; /*! Switch to activate lattice periodicity in z direction*/
+
+ int NB_BODIES, /*! Number of bodies*/
+ NB_GRAINS, /*! number of grains*/
+ NB_DYNGRAINS, /*! number of dynamic grains*/
+ NB_DYNBODIES, /*! number of dynamic bodies*/
+ NB_WALLS, /*! Number of walls*/
+ DEM_ITER, /*! Number of iteration of the DEM loop*/
+ LBM_ITER, /*! Number of iteration of the LBM loop*/
+ MODE, /*! 1->only a LBM loop, 2->lbm subcycling, 3->lbm subcycling after lbm loop*/
+ dim, /*! dimension*/
+ NbDir, /*! number of directions of the lattice model*/
+ NbNodes, /*! Total number of nodes*/
+ NbFluidNodes, /*! Number of fluid nodes*/
+ NbSolidNodes, /*! Number of solid nodes*/
+ NbParticleNodes, /*! Number of particle nodes*/
+ NbContacts, /*! Number of Contact*/
+ InitialNumberOfDynamicParticles,/*! Initial number of dynamic particles*/
+ NumberOfDynamicParticles, /*! Number of dynamic particles*/
+ Ny, /*! Number of grid divisions in y direction */
+ Nz, /*! Number of grid divisions in z direction */
+ NumberPtcEroded, /*! The bumber of eroded/removed particles*/
+ iter, /*! LBM Iteration number in current DEM loop (=1 in mode=2)*/
+ IdFirstSphere; /*! Id of the first sphere*/
+
+ Real height, /*! System height */
+ width, /*! System width */
+ depth, /*! System depth */
+ halfWallthickness, /*! Half Wall thickness */
+ Wallthickness, /*! Wall thickness */
+ cub, /*! A temporary variable to calculate equilibrium distribution function */
+ c, /*! Lattice speed */
+ c2, /*! The squared lattice speed*/
+ dx, /*! The lattice size*/
+ invdx, /*! 1 / lattice size*/
+ dx2, /*! The squared lattice size*/
+ uMax, /// TODO: PLEASE EXPLAIN uMax
+ cs, /*! c/sqrt(3) */
+ dt, /*! LBM timestep */
+ invdt, /*! one over LBM timestep */
+ nu, /*! LBM kinematic viscosity */
+ feqb, /*! Equilibrium distribution function*/
+ omega, /*! 1/tau */
+ Lx0, /*! LBM grid size in x direction*/
+ Ly0, /*! LBM grid size in y direction*/
+ Lz0, /*! LBM grid size in z direction*/
+ outside_limit, /*! the x coordinate of a point outside the system*/
+ DEMdt, /*! timestep for the DEM iteration*/
+ DEMdt0, /*! original timestep for the DEM iteration*/
+ newDEMdt, /*! the new timestep for the DEM iteration*/
+ Vr, /*! Volume of the removed particles*/
+ Vo, /*! Initial volume of dynamic particles */
+ VmeanFluidC, /*! Current mean fluid velocity */
+ PrevVmeanFluidC, /*! Previous mean fluid velocity */
+ PrevPrevVmeanFluidC, /*! Previous previous mean fluid velocity */
+ VmaxC, /*! Maximum velocity during the current time step*/
+ VminC, /*! Minimum velocity during the current time step*/
+ RhomaxC, /*! Maximum density during the current time step*/
+ RhominC, /*! Minimum density during the current time step*/
+ LBM_TIME, /*! The time ellapsed in the LB method*/
+ DEM_TIME, /*! The time ellapsed in the DE method*/
+ RhoTot, /*! Cumulative density*/
+ FmoyCur, /*! Mean force at the current LB iteration*/
+ FmoyPrev, /*! Mean force at the previous LB iteration*/
+ FmoyPrevPrev, /*! Mean force at 2 previous LB iteration*/
+ UMaxtheo, /// TODO: PLEASE EXPLAIN UMaxtheo
+ MaxBodyRadius, /*! Max radius of spheres*/
+ MinBodyRadius, /*! Min radius of spheres*/
+ MeanBodyRadius; /*! Mean radius of spheres*/
+
+ std::string LBMlogFile, /*! Name of the logfile */
+ LBMmachFile, /*! Name of the stat file */
+ LBMcontactsFile, /*! Name of the contact file */
+ RemovedPtcFile, /*! Name of the file to store removed particle informations*/
+ ObservedPtcFile, /*! Name of the file to store observed particle informations*/
+ ObservedNodeFile, /*! Name of the file to store observed particle informations*/
+ lbm_dir, /*! Directory name to save LBM files */
+ dem_dir, /*! Directory name to save DEM files */
+ cntct_dir; /*! Directory name to save contact properties */
+
+ std::stringstream spherefile_name; /*! Name of the file where sphere data are saved*/
+
+ vector<int> IdOfNextErodedPtc, /*! List of particles which will be eroded*/
+ opp; /*! opposite nodes */
+
+ vector<Real> w; /*! Weighting factor */
+
+ vector <LBMnode> nodes; /*! the LBM nodes*/
+ vector <LBMlink> links; /*! the LBM links*/
+ vector <LBMbody> LBbodies; /*! the LBM bodies*/
+
+ vector <Vector3r> eib; /*! node velocity directions*/
+
+ Vector3r FhTotale; ///Total hydrodynamic force
+
+ virtual ~HydrodynamicsLawLBM ();
+ virtual bool isActivated();
+ virtual void action();
+ void save(int iter_number, Real timestep);
+ void saveStats(int iter_number, Real timestep);
+ void saveEroded(int iter_number, Real timestep);
+ void saveContacts(int iter_number, Real timestep);
+ void saveObservedNode(int iter_number, Real timestep);
+ void saveObservedPtc(int iter_number, Real timestep);
+ void createNewFiles();
+ //void createDirectories(); // ModLuc: to create directories only if necessary
+ void createDirectories(bool dirLBM, bool dirDem, bool dirCntct);
+ void writelogfile();
+ void modeTransition();
+ void LbmEnd();
+ void CalculateAndApplyForcesAndTorquesOnBodies(bool mean,bool apply);
+
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR(HydrodynamicsLawLBM,GlobalEngine,"Engine to simulate fluid flow (with the lattice Boltzmann method) with a coupling with the discrete element method.\n If you use this Engine, please cite and refer to F. Lominé et al. International Journal For Numerical and Analytical Method in Geomechanics, 2012, doi: 10.1002/nag.1109",
+
+ ((int,WallYm_id,0,,"Identifier of the Y- wall"))
+ ((bool,useWallYm,true,,"Set true if you want that the LBM see the wall in Ym"))
+ ((int,YmBCType,2,,"Boundary condition for the wall in Ym (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((Vector3r,YmBcVel,Vector3r::Zero(),,"(!!! not fully implemented !!) The velocity imposed at the boundary"))
+ ((Real,YmBcRho,-1,,"(!!! not fully implemented !!) The density imposed at the boundary"))
+ ((int,WallYp_id,1,,"Identifier of the Y+ wall"))
+ ((bool,useWallYp,true,,"Set true if you want that the LBM see the wall in Yp"))
+ ((int,YpBCType,2,,"Boundary condition for the wall in Yp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((Vector3r,YpBcVel,Vector3r::Zero(),,"(!!! not fully implemented !!) The velocity imposed at the boundary"))
+ ((Real,YpBcRho,-1,,"(!!! not fully implemented !!) The density imposed at the boundary"))
+ ((int,WallXm_id,2,,"Identifier of the X- wall"))
+ ((bool,useWallXm,false,,"Set true if you want that the LBM see the wall in Xm"))
+ ((int,XmBCType,1,,"Boundary condition for the wall in Xm (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((Vector3r,XmBcVel,Vector3r::Zero(),,"(!!! not fully implemented !!) The velocity imposed at the boundary"))
+ ((Real,XmBcRho,-1,,"(!!! not fully implemented !!) The density imposed at the boundary"))
+ ((int,WallXp_id,3,,"Identifier of the X+ wall"))
+ ((bool,useWallXp,false,,"Set true if you want that the LBM see the wall in Xp"))
+ ((int,XpBCType,1,,"Boundary condition for the wall in Xp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((Vector3r,XpBcVel,Vector3r::Zero(),,"(!!! not fully implemented !!) The velocity imposed at the boundary"))
+ ((Real,XpBcRho,-1,,"(!!! not fully implemented !!) The density imposed at the boundary"))
+ ((int,WallZp_id,5,,"Identifier of the Z+ wall"))
+ ((bool,useWallZp,false,,"Set true if you want that the LBM see the wall in Zp"))
+ ((int,ZpBCType,-1,,"Boundary condition for the wall in Zp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((Vector3r,ZpBcVel,Vector3r::Zero(),,"(!!! not fully implemented !!) The velocity imposed at the boundary"))
+ ((Real,zpBcRho,-1,,"(!!! not fully implemented !!) The density imposed at the boundary"))
+ ((int,WallZm_id,4,,"Identifier of the Z- wall"))
+ ((bool,useWallZm,false,,"Set true if you want that the LBM see the wall in Zm"))
+ ((int,ZmBCType,-1,,"Boundary condition for the wall in Zm (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((Vector3r,ZmBcVel,Vector3r::Zero(),,"(!!! not fully implemented !!) The velocity imposed at the boundary"))
+ ((Real,ZmBcRho,-1,,"(!!! not fully implemented !!) The density imposed at the boundary"))
+ ((int,XmYmZpBCType,2,,"Boundary condition for the corner node XmYmZp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XmYpZpBCType,2,,"Boundary condition for the corner node XmYpZp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XpYmZpBCType,2,,"Boundary condition for the corner node XpYmZp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XpYpZpBCType,2,,"Boundary condition for the corner node XpYpZp (-1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XmYmZmBCType,-1,,"Boundary condition for the corner node XmYmZm (not used with d2q9, -1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XmYpZmBCType,-1,,"Boundary condition for the corner node XmYpZm (not used with d2q9, -1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XpYmZmBCType,-1,,"Boundary condition for the corner node XpYmZm (not used with d2q9, -1: unused, 1: pressure condition, 2: velocity condition)."))
+ ((int,XpYpZmBCType,-1,,"Boundary condition for the corner node XpYpZm (not used with d2q9, -1: unused, 1: pressure condition, 2: velocity condition)."))
+
+ ((int,defaultLbmInitMode,0,,"Switch between the two initialisation methods"))
+ ((Vector3r,dP,Vector3r(0.,0.,0.),,"Pressure difference between input and output"))
+ ((Real,Rho,1000.,,"Fluid density"))
+ ((Real,Nu,0.000001,,"Fluid kinematic viscosity"))
+ ((Real,tau,0.6,,"Relaxation time"))
+ ((int,Nx,1000,,"The number of grid division in x direction"))
+ ((int,IterMax,1,,"This variable can be used to do several LBM iterations during one DEM iteration. "))
+ ((int,IterPrint,1,,"Print info on screen every IterPrint iterations"))
+ ((int,SaveMode,1,,"Save Mode (1-> default, 2-> in time (not yet implemented)"))
+ ((int,IterSave,100,,"Data are saved every IterSave LBM iteration (or see TimeSave)"))
+ ((Real,TimeSave,-1,,"Data are saved at constant time interval (or see IterSave)"))
+ ((int,SaveGridRatio,1,,"Grid data are saved every SaveGridRatio * IterSave LBM iteration (with SaveMode=1)"))
+ ((int,IterSubCyclingStart,-1,,"Iteration number when the subcycling process starts"))
+ ((int,DemIterLbmIterRatio,-1,,"Ratio between DEM and LBM iterations for subcycling"))
+ ((bool,EngineIsActivated,true,,"To activate (or not) the engine"))
+ ((bool,applyForcesAndTorques,true,,"Switch to apply forces and torques"))
+ ((int,ObservedNode,-1,,"The identifier of the node that will be observed (-1 means none)"))
+ ((int,ObservedPtc,-1,,"The identifier of the particle that will be observed (-1 means the first one)"))
+ ((Real,RadFactor,1.0,,"The radius of DEM particules seen by the LBM is the real radius of particules*RadFactor"))
+ ((Real,ConvergenceThreshold,0.000001,,""))
+ ((std::string,LBMSavedData," ",,"a list of data that will be saved. Can use velocity,velXY,forces,rho,bodies,nodeBD,newNode,observedptc,observednode,contacts,spheres,bz2"))
+ ((std::string,periodicity," ",,"periodicity"))
+ ((std::string,bc," ",,"Boundary condition"))
+ ((std::string,model,"d2q9",,"The LB model. Until now only d2q9 is implemented"))
+ ((int,removingCriterion ,0,,"Criterion to remove a sphere (1->based on particle position, 2->based on particle velocity"))
+ ((Real,VelocityThreshold,-1.,,"Velocity threshold when removingCriterion=2"))
+ ((Real,EndTime,-1,,"the time to stop the simulation"))
+ ((Vector3r,CstBodyForce,Vector3r::Zero(),,"A constant body force (=that does not vary in time or space, otherwise the implementation introduces errors)"))
+ ((Real,VbCutOff,-1,,"the minimum boundary velocity that is taken into account"))
+ ,
+ firstRun = true;
+ omega = 1.0/tau;
+ DEM_TIME = 0.;
+ LBM_TIME = 0.;
+ iter = 0;
+ use_ConvergenceCriterion = true;
+ MODE=0;
+ dim=0;
+ NbDir=0;
+ NbNodes=0;
+ NbFluidNodes=0;
+ NbSolidNodes=0;
+ NbParticleNodes=0;
+ NbContacts=0;
+ InitialNumberOfDynamicParticles=0;
+ NumberOfDynamicParticles=0;
+ NumberPtcEroded=0;
+ Vr=0.;
+ Vo=0.;
+ MaxBodyRadius=-1000000.;
+ MinBodyRadius=1000000.;
+ MeanBodyRadius=0.;
+ lbm_dir="lbm-nodes";
+ dem_dir="dem-bodies";
+ cntct_dir="contacts";
+ LBMlogFile ="LBM.log";
+ LBMmachFile ="LBM.mach";
+ LBMcontactsFile ="LBM.cntct";
+ RemovedPtcFile="eroded.dat";
+ ObservedPtcFile="observedPtc.dat";
+ ObservedNodeFile="observedNode.dat";
+ COMPRESS_DATA = false;
+ SAVE_VELOCITY = false;
+ SAVE_VELOCITYCOMP = false;
+ SAVE_RHO = false;
+ SAVE_FORCES = false;
+ SAVE_BODIES = false;
+ SAVE_NODEBD = false;
+ SAVE_NODEISNEW = false;
+ SAVE_DEBUGFILES = false;
+ SAVE_OBSERVEDPTC= false;
+ SAVE_OBSERVEDNODE=false;
+ SAVE_CONTACTINFO =false;
+ SAVE_SPHERES = false; //to save spheres_* files only if it is required by the operator
+ Xperiodicity = false;
+ Yperiodicity = false;
+ Zperiodicity = false;
+ Ny = 0;Nz = 0;
+ FmoyCur=0.;FmoyPrev=0.;
+ FmoyPrevPrev=0.;VmeanFluidC=0.;PrevVmeanFluidC=0.;PrevPrevVmeanFluidC=0.;
+ LBM_ITER=0;
+ DEM_ITER=0;
+ IdFirstSphere=-1;
+ timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas);
+
+ );
+ DECLARE_LOGGER;
+};
+
+
+REGISTER_SERIALIZABLE(HydrodynamicsLawLBM);
+
+#endif //LBM_ENGINE
+
=== added file 'pkg/lbm/LBMbody.cpp'
--- pkg/lbm/LBMbody.cpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/LBMbody.cpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,16 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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 LBM_ENGINE
+
+#include "LBMbody.hpp"
+
+YADE_PLUGIN((LBMbody));
+LBMbody::~LBMbody(){};
+
+#endif //LBM_ENGINE
=== added file 'pkg/lbm/LBMbody.hpp'
--- pkg/lbm/LBMbody.hpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/LBMbody.hpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,46 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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 LBM_ENGINE
+
+#pragma once
+#include<yade/lib/serialization/Serializable.hpp>
+#include<yade/lib/multimethods/Indexable.hpp>
+
+class LBMbody: public Serializable{
+ public:
+ virtual ~LBMbody();
+ //Real radius(){return ext[0];}
+ bool isBox(){if(type==1)return true; else return false;}
+ bool isPtc(){if(type==2)return true; else return false;}
+ void setAsPtc(){type=2;}
+ void setAsBox(){type=1;}
+
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR(LBMbody,Serializable,
+ "Body class for Lattice Boltzmann Method ",
+ ((Vector3r,force,Vector3r::Zero(),,"Hydrodynamic force, need to be reinitialized (LB unit)"))
+ ((Vector3r,fm,Vector3r::Zero(),,"Hydrodynamic force (LB unit) at t-0.5dt"))
+ ((Vector3r,fp,Vector3r::Zero(),,"Hydrodynamic force (LB unit) at t+0.5dt"))
+ ((Vector3r,momentum,Vector3r::Zero(),,"Hydrodynamic momentum,need to be reinitialized (LB unit)"))
+ ((Vector3r,mm,Vector3r::Zero(),,"Hydrodynamic momentum (LB unit) at t-0.5dt"))
+ ((Vector3r,mp,Vector3r::Zero(),,"Hydrodynamic momentum (LB unit) at t+0.5dt"))
+ ((Vector3r,pos,Vector3r::Zero(),,"Position of body"))
+ ((Vector3r,vel,Vector3r::Zero(),,"Velocity of body"))
+ ((Vector3r,AVel,Vector3r::Zero(),,"Angular velocity of body"))
+ ((Vector3r,Fh,Vector3r::Zero(),,"Hydrodynamical force on body"))
+ ((Vector3r,Mh,Vector3r::Zero(),,"Hydrodynamical momentum on body"))
+ ((Real,radius,-1000.,,"Radius of body (for sphere)"))
+ ((bool,isEroded,false,,"Hydrodynamical force on body"))
+ ((bool,saveProperties,false,,"To save properties of the body"))
+ ((short int,type,-1,," "))
+ ,
+ );
+};
+REGISTER_SERIALIZABLE(LBMbody);
+
+#endif //LBM_ENGINE
=== added file 'pkg/lbm/LBMlink.cpp'
--- pkg/lbm/LBMlink.cpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/LBMlink.cpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,17 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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 LBM_ENGINE
+
+#include "LBMlink.hpp"
+
+YADE_PLUGIN((LBMlink));
+LBMlink::~LBMlink(){};
+void LBMlink::ReinitDynamicalProperties(){sid=-1;fid=-1;idx_sigma_i=-1;isBd=false;VbMid=Vector3r::Zero();DistMid=Vector3r::Zero();ct=0.;return;}
+
+#endif //LBM_ENGINE
=== added file 'pkg/lbm/LBMlink.hpp'
--- pkg/lbm/LBMlink.hpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/LBMlink.hpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,37 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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 LBM_ENGINE
+
+#pragma once
+#include<yade/lib/serialization/Serializable.hpp>
+#include<yade/lib/multimethods/Indexable.hpp>
+
+class LBMlink: public Serializable{
+ public:
+ void ReinitDynamicalProperties();
+ virtual ~LBMlink();
+
+ YADE_CLASS_BASE_DOC_ATTRS_CTOR(LBMlink,Serializable,
+ "Link class for Lattice Boltzmann Method ",
+ ((int,sid,-1,,"Solid node identifier "))
+ ((int,fid,-1,,"Fluid node identifier "))
+ ((short int,i,-1,,"direction index of the link"))
+ ((int,nid1,-1,,"fixed node identifier"))
+ ((int,nid2,-1,,"fixed node identifier or -1 if node points outside"))
+ ((short int,idx_sigma_i,-1,,"sigma_i direction index (Fluid->Solid)"))
+ ((bool,isBd,false,,"True if it is a boundary link"))
+ ((bool,PointingOutside,false,,"True if it is a link pointing outside to the system (from a fluid or solid node)"))
+ ((Vector3r,VbMid,Vector3r::Zero(),,"Velocity of boundary at midpoint"))
+ ((Vector3r,DistMid,Vector3r::Zero(),,"Distance between middle of the link and mass center of body"))
+ ((Real,ct,0.,,"Coupling term in modified bounce back rule")),
+ );
+};
+REGISTER_SERIALIZABLE(LBMlink);
+
+#endif //LBM_ENGINE
=== added file 'pkg/lbm/LBMnode.cpp'
--- pkg/lbm/LBMnode.cpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/LBMnode.cpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,120 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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 LBM_ENGINE
+
+#include "LBMnode.hpp"
+
+YADE_PLUGIN((LBMnode));
+LBMnode::~LBMnode(){};
+
+void LBMnode::MixteBC(string lbmodel,Real density, Vector3r U, string where){
+ Real rhoVx=density*U.x();
+ Real rhoVy=density*U.y();
+ if(!strcmp(lbmodel.c_str(), "d2q9" )){
+ if(!strcmp(where.c_str(), "Xm" )){
+ f[1]=f[3]+(2./3.)*rhoVx;
+ f[5]=f[7]-0.5*(f[2]-f[4])+(1./6.)*rhoVx+ 0.5*rhoVy;
+ f[8]=f[6]+0.5*(f[2]-f[4])+(1./6.)*rhoVx- 0.5*rhoVy;
+ }
+ else if(!strcmp(where.c_str(), "Xp" )){
+ f[3]=f[1]-(2./3.)*rhoVx;
+ f[7]=f[5]+0.5*(f[2]-f[4])-(1./6.)*rhoVx - 0.5*rhoVy;
+ f[6]=f[8]-0.5*(f[2]-f[4])-(1./6.)*rhoVx + 0.5*rhoVy;
+ }
+ else if(!strcmp(where.c_str(), "Ym" )){
+ f[2]=f[4]+(2./3.)*rhoVy;
+ f[5]=f[7]-0.5*(f[1]-f[3])+0.5*rhoVx + (1./6.)*rhoVy;
+ f[6]=f[8]+0.5*(f[1]-f[3])-0.5*rhoVx + (1./6.)*rhoVy;
+ }
+ else if(!strcmp(where.c_str(), "Yp" )){
+ f[4]=f[2]-(2./3.)*rhoVy;
+ f[7]=f[5]+0.5*(f[1]-f[3])-0.5*rhoVx- (1./6.)*rhoVy;
+ f[8]=f[6]-0.5*(f[1]-f[3])+0.5*rhoVx -(1./6.)*rhoVy;
+ }
+ else if(!strcmp(where.c_str(), "XmYmZp" )){
+ f[1]=f[3]+(2./3.)*rhoVx;
+ f[2]=f[4]+(2./3.)*rhoVy;
+ f[5]=f[7] + (1./6.)*density*(U.x()+U.y());
+ f[6]=0.5*(density*(1.-U.x() -(2./3.)*U.y())-f[0]-2.*(f[3]+f[4]+f[7]));
+ f[8]=0.5*(density*(1.-(2./3.)*U.x() -U.y())-f[0]-2.*(f[3]+f[4]+f[7]));
+ }
+ else if(!strcmp(where.c_str(), "XmYpZp" )){
+ f[1]=f[3]+(2./3.)*rhoVx;
+ f[4]=f[2]-(2./3.)*rhoVy;
+ f[5]=0.5*(density*(1.-(2./3.)*U.x()+U.y())-f[0]-2.*(f[2]+f[3]+f[6]));
+ f[7]=0.5*(density*(1.-U.x()+(2./3.)*U.y())-f[0]-2.*(f[2]+f[3]+f[6]));
+ f[8]=f[6]+(1./6.)*density*(U.x()-U.y());
+ }
+ else if(!strcmp(where.c_str(), "XpYmZp" )){
+ f[2]=f[4]+(2./3.)*rhoVy;
+ f[3]=f[1]-(2./3.)*rhoVx;
+ f[5]=0.5*(density*(1.+U.x()-(2./3.)*U.y())-f[0]-2.*(f[1]+f[4]+f[8]));
+ f[6]=f[8]-(1./6.)*density*(U.x()-U.y());
+ f[7]=0.5*(density*(1.+(2./3.)*U.x()-U.y())-f[0]-2.*(f[1]+f[4]+f[8]));
+ }
+ else if(!strcmp(where.c_str(), "XpYpZp" )){
+ f[3]=f[1]-(2./3.)*rhoVx;
+ f[4]=f[2]-(2./3.)*rhoVy;
+ f[6]=0.5*(density*(1.+(2./3.)*U.x()+U.y())-f[0]-2.*(f[1]+f[2]+f[5]));
+ f[7]=f[5]-(1./6.)*density*(U.x()+U.y());
+ f[8]=0.5*(density*(1.+U.x()+(2./3.)*U.y())-f[0]-2.*(f[1]+f[2]+f[5]));
+ }
+ else {exit(-1);}
+ }else {exit(-1);}
+ return;
+}
+
+
+bool LBMnode::checkIsNewObstacle(){
+ if(isObstacle){
+ if(!wasObstacle) {isNewObstacle=true;wasObstacle=true;}
+ else {isNewObstacle=false;wasObstacle=true;}
+ return(isNewObstacle);
+ } else return(false);
+}
+
+bool LBMnode::checkIsNewFluid(){
+ if(!isObstacle){
+ if(wasObstacle) {isNewFluid=true;wasObstacle=false;}
+ else {isNewFluid=false;wasObstacle=false;}
+ return(isNewFluid);
+ } else return(false);
+}
+
+void LBMnode::DispatchBoundaryConditions(int SizeNx,int SizeNy,int SizeNz){
+ applyBC =false;
+ applyXmBC =false;
+ applyYmXmBC =false;
+ applyYpXmBC =false;
+ applyXpBC =false;
+ applyYmXpBC =false;
+ applyYpXpBC =false;
+ applyYpBC =false;
+ applyYmBC =false;
+ if((i==0)&&(j>0)&&(j<SizeNy-1)) {applyXmBC =true; applyBC=true;}
+ if((i==0)&&(j==0)) {applyYmXmBC =true; applyBC=true;}
+ if((i==0)&&(j==SizeNy-1)) {applyYpXmBC =true; applyBC=true;}
+ if((i==SizeNx-1)&&(j>0)&&(j<SizeNy-1)) {applyXpBC =true; applyBC=true;}
+ if((i==SizeNx-1)&&(j==0)) {applyYmXpBC =true; applyBC=true;}
+ if((i==SizeNx-1)&&(j==SizeNy-1)) {applyYpXpBC =true; applyBC=true;}
+ if((i>0)&&(i<SizeNx-1)&&(j==0)) {applyYmBC =true; applyBC=true;}
+ if((i>0)&&(i<SizeNx-1)&&(j==SizeNy-1)) {applyYpBC =true; applyBC=true;}
+return;
+}
+
+
+void LBMnode::SetCellIndexesAndPosition(int indI, int indJ, int indK){
+ i=indI;
+ j=indJ;
+ k=indK;
+ posb=Vector3r((Real) indI,(Real) indJ,(Real) indK);
+ return;
+}
+
+#endif //LBM_ENGINE
=== added file 'pkg/lbm/LBMnode.hpp'
--- pkg/lbm/LBMnode.hpp 1970-01-01 00:00:00 +0000
+++ pkg/lbm/LBMnode.hpp 2014-03-31 16:01:57 +0000
@@ -0,0 +1,67 @@
+/*************************************************************************
+* Copyright (C) 2009-2012 by Franck Lominé *
+* franck.lomine@xxxxxxxxxxxxxx *
+* *
+* 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 LBM_ENGINE
+
+#pragma once
+#include<yade/lib/serialization/Serializable.hpp>
+#include<yade/lib/multimethods/Indexable.hpp>
+
+class LBMnode: public Serializable{
+ public:
+ int
+ i, /*! node index in x direction */
+ j, /*! node index in y direction */
+ k, /*! node index in z direction */
+ body_id; /*! the node belongs to the body indexed with body_id*/
+
+ short int IsolNb; /*! number of boundary links of a fluid boundary nodes*/
+
+ bool
+ isObstacle, /*! the node belongs to an obstacle */
+ isObstacleBoundary, /*! the node is an obstacle boundary */
+ isFluidBoundary, /*! the node is a fluid boundary */
+ wasObstacle, /*! the node was an obstacle */
+ isNewObstacle, /*! the node is an new obstacle node */
+ isNewFluid, /*! the node is an new fluid node */
+ applyBC, /*! the node is subject to the one boundary condition */
+ applyXmBC, /*! the node is subject to the left boundary condition */
+ applyXpBC, /*! the node is subject to the right boundary condition */
+ applyYpBC, /*! the node is subject to the top boundary condition */
+ applyYmBC, /*! the node is subject to the bottom boundary condition */
+ applyZpBC, /*! the node is subject to the front boundary condition NOT USED NOW*/
+ applyZmBC, /*! the node is subject to the back boundary condition NOT USED NOW*/
+ applyYmXmBC, /*! the node is subject to the bottom-left boundary condition */
+ applyYpXmBC, /*! the node is subject to the top-left boundary condition */
+ applyYmXpBC, /*! the node is subject to the bottom-right boundary condition */
+ applyYpXpBC; /*! the node is subject to the top-right boundary condition */
+
+ Vector3r posb, /*! the node position */
+ velb; /*! the node velocity */
+
+ Real rhob; /*! the node density */ /*! the node density */
+ vector<int> neighbour_id; /*! list of adjacent nodes */
+ vector<int> links_id; /*! list of links */
+ vector<Real> f;
+ vector<Real> fprecol;
+ vector<Real> fpostcol;
+
+ void DispatchBoundaryConditions(int SizeNx,int SizeNy,int SizeNz);
+ bool checkIsNewFluid();
+ bool checkIsNewObstacle();
+ void MixteBC(string lbmodel,Real density, Vector3r U, string where);
+ void SetCellIndexesAndPosition(int indI, int indJ, int indK);
+ void setAsObstacle(){isObstacle=true;}
+ void setAsFluid(){isObstacle=false;}
+
+ virtual ~LBMnode();
+ YADE_CLASS_BASE_DOC(LBMnode,Serializable,"Node class for Lattice Boltzmann Method ");
+};
+REGISTER_SERIALIZABLE(LBMnode);
+
+#endif //LBM_ENGINE
=== added directory 'pkg/pfv'
=== added file 'pkg/pfv/DFNFlow.cpp'
--- pkg/pfv/DFNFlow.cpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/DFNFlow.cpp 2014-04-03 16:44:33 +0000
@@ -0,0 +1,85 @@
+
+/*************************************************************************
+* Copyright (C) 2014 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 DFNFLOW
+#ifdef DFNFLOW
+#define TEMPLATE_FLOW_NAME DFNFlowEngineT
+#include <yade/pkg/pfv/FlowEngine.hpp>
+
+class DFNCellInfo : public FlowCellInfo
+{
+ public:
+ Real anotherVariable;
+ void anotherFunction() {};
+};
+
+
+class DFNVertexInfo : public FlowVertexInfo {
+ public:
+ //same here if needed
+};
+
+typedef TemplateFlowEngine<DFNCellInfo,DFNVertexInfo> DFNFlowEngineT;
+REGISTER_SERIALIZABLE(DFNFlowEngineT);
+YADE_PLUGIN((DFNFlowEngineT));
+
+class DFNFlowEngine : public DFNFlowEngineT
+{
+ public :
+ void trickPermeability();
+ void trickPermeability (RTriangulation::Facet_circulator& facet,Real somethingBig);
+ void trickPermeability (RTriangulation::Finite_edges_iterator& edge,Real somethingBig);
+
+ YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(DFNFlowEngine,DFNFlowEngineT,"documentation here",
+ ((Real, myNewAttribute, 0,,"useless example"))
+ ,/*DFNFlowEngineT()*/,
+ ,
+ )
+ DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(DFNFlowEngine);
+YADE_PLUGIN((DFNFlowEngine));
+
+void DFNFlowEngine::trickPermeability (RTriangulation::Facet_circulator& facet, Real somethingBig)
+{
+ const RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+ const CellHandle& cell1 = facet->first;
+ const CellHandle& cell2 = facet->first->neighbor(facet->second);
+ if ( Tri.is_infinite(cell1) || Tri.is_infinite(cell2)) cerr<<"Infinite cell found in trickPermeability, should be handled somehow, maybe"<<endl;
+ cell1->info().kNorm()[facet->second] = somethingBig;
+ cell2->info().kNorm()[Tri.mirror_index(cell1, facet->second)] = somethingBig;
+}
+
+void DFNFlowEngine::trickPermeability(RTriangulation::Finite_edges_iterator& edge, Real somethingBig)
+{
+ const RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+ RTriangulation::Facet_circulator facet1 = Tri.incident_facets(*edge);
+ RTriangulation::Facet_circulator facet0=facet1++;
+ trickPermeability(facet0,somethingBig);
+ while ( facet1!=facet0 ) {trickPermeability(facet1,somethingBig); facet1++;}
+}
+
+
+void DFNFlowEngine::trickPermeability()
+{
+ Real somethingBig=10;//is that big??
+ const RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+ //We want to change permeability perpendicular to the 10th edge, let's say.
+ //in the end this function should have a loop on all edges I guess
+ FiniteEdgesIterator edge = Tri.finite_edges_begin();
+ for(int k=10; k>0;--k) edge++;
+ trickPermeability(edge,somethingBig);
+}
+
+
+#endif //DFNFLOW
+#endif //FLOWENGINE
\ No newline at end of file
=== added file 'pkg/pfv/DummyFlowEngine.cpp'
--- pkg/pfv/DummyFlowEngine.cpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/DummyFlowEngine.cpp 2014-04-03 16:45:33 +0000
@@ -0,0 +1,60 @@
+
+/*************************************************************************
+* Copyright (C) 2014 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. *
+*************************************************************************/
+
+// This is an example of how to derive a new FlowEngine with additional data and possibly completely new behaviour.
+// Every functions of the base engine can be overloaded, and new functions can be added
+
+//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 -DDFNFLOW to cmake, or just uncomment the following line
+// #define DUMMYFLOW
+#ifdef DUMMYFLOW
+#define TEMPLATE_FLOW_NAME DummyFlowEngineT
+#include <yade/pkg/pfv/FlowEngine.hpp>
+
+/// We can add data to the Info types by inheritance
+class DummyCellInfo : public FlowCellInfo
+{
+ public:
+ Real anotherVariable;
+ void anotherFunction() {};
+};
+
+class DummyVertexInfo : public FlowVertexInfo {
+ public:
+ //same here if needed
+};
+
+typedef TemplateFlowEngine<DummyCellInfo,DummyVertexInfo> TEMPLATE_FLOW_NAME;
+REGISTER_SERIALIZABLE(TEMPLATE_FLOW_NAME);
+YADE_PLUGIN((TEMPLATE_FLOW_NAME));
+
+class DummyFlowEngine : public TEMPLATE_FLOW_NAME
+{
+ public :
+ //We can overload every functions of the base engine to make it behave differently
+ //if we overload action() like this, this engine is doing nothing in a standard timestep, it can still have useful functions
+ virtual void action() {};
+
+ //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 fancyFunction(Real what); {cerr<<"yes, I'm a new function"<<end;}
+
+ YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(DummyFlowEngine,TEMPLATE_FLOW_NAME,"documentation here",
+ ((Real, myNewAttribute, 0,,"useless example"))
+ ,/*DummyFlowEngineT()*/,
+ ,
+ .def("fancyFunction",&DummyFlowEngine::fancyFunction,(python::arg("what")=0),"test function")
+ )
+ DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(DummyFlowEngine);
+YADE_PLUGIN((DummyFlowEngine));
+
+void DummyFlowEngine::fancyFunction(Real what) {cerr<<"yes, I'm a new function"<<end;}
+#undef TEMPLATE_FLOW_NAME DummyFlowEngineT //To be sure it will not conflict, maybe not needed
+#endif //DummyFLOW
\ No newline at end of file
=== added file 'pkg/pfv/FlowEngine.cpp'
--- pkg/pfv/FlowEngine.cpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/FlowEngine.cpp 2014-04-03 13:37:55 +0000
@@ -0,0 +1,40 @@
+/*************************************************************************
+* Copyright (C) 2009 by Emanuele Catalano <catalano@xxxxxxxxxxxxxxx> *
+* Copyright (C) 2009 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 YADE_CGAL
+#ifdef FLOW_ENGINE
+
+#define TEMPLATE_FLOW_NAME FlowEngineT
+#include "FlowEngine.hpp"
+
+// To register properly, we need to first instantiate an intermediate class, then inherit from it with correct class names in YADE_CLASS macro
+// The intermediate one would be seen with the name "TemplateFlowEngine" by python, thus it would not work when more than one class are derived, they would all
+// be named "TemplateFlowEngine" ...
+typedef TemplateFlowEngine<FlowCellInfo,FlowVertexInfo> FlowEngineT;
+REGISTER_SERIALIZABLE(FlowEngineT);
+
+class FlowEngine : public FlowEngineT
+{
+ public :
+ YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(FlowEngine,FlowEngineT,"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.",
+ ,,
+ ,
+ //nothing special to define here, we simply re-use FlowEngine methods
+ //.def("meanVelocity",&PeriodicFlowEngine::meanVelocity,"measure the mean velocity in the period")
+ )
+ DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(FlowEngine);
+
+YADE_PLUGIN((FlowEngineT));
+CREATE_LOGGER(FlowEngine );
+YADE_PLUGIN((FlowEngine));
+
+#endif //FLOW_ENGINE
+
+#endif /* YADE_CGAL */
+
=== added file 'pkg/pfv/FlowEngine.hpp'
--- pkg/pfv/FlowEngine.hpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/FlowEngine.hpp 2014-04-24 21:37:44 +0000
@@ -0,0 +1,438 @@
+/*************************************************************************
+* Copyright (C) 2009 by Emanuele Catalano <catalano@xxxxxxxxxxxxxxx> *
+* Copyright (C) 2009 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. *
+*************************************************************************/
+
+/*!
+
+FlowEngine is an interface between Yade and the fluid solvers defined in lib/triangulation and using the PFV scheme.
+There are also a few non-trivial functions defined here, such has building triangulation and computating elements volumes.
+The code strongly relies on CGAL library for building triangulations on the top of sphere packings.
+CGAL's trangulations introduce the data associated to each element of the triangulation through template parameters (Cell_info and Vertex_info).
+FlowEngine is thus defined via the template class TemplateFlowEngine(Cellinfo,VertexInfo), for easier addition of variables in various couplings.
+PeriodicFlowEngine is a variant for periodic boundary conditions.
+
+Which solver will be actually used internally to obtain pore pressure will depend partly on compile time flags (libcholmod available and #define LINSOLV),
+and on runtime settings (useSolver=0: Gauss-Seidel (iterative), useSolver=1: CHOLMOD if available (direct sparse cholesky)).
+
+The files defining lower level classes are in yade/lib. The code uses CGAL::Triangulation3 for managing the mesh and storing data. Eigen3::Sparse, suitesparse::cholmod, and metis are used for solving the linear systems with a direct method (Cholesky). An iterative method (Gauss-Seidel) is implemented directly in Yade and can be used as a fallback (see FlowEngine::useSolver).
+
+Most classes in lib/triangulation are templates, and are therefore completely defined in header files.
+A pseudo hpp/cpp split is reproduced for clarity, with hpp/ipp extensions (but again, in the end they are all include files).
+The files are
+- RegularTriangulation.h : declaration of info types embeded in the mesh (template parameters of CGAL::Triangulation3), and instanciation of RTriangulation classes
+- Tesselation.h/ipp : encapsulate RegularTriangulation and adds functions to manipulate the dual (Voronoi) graph of the triangulation
+- Network.hpp/ipp : specialized for PFV model (the two former are used independently by TesselationWrapper), a set of functions to determine volumes and surfaces of intersections between spheres and various subdomains. Contains two triangulations for smooth transitions while remeshing - e.g. interpolating values in the new mesh using the previous one.
+- FlowBoundingSphere.hpp/ipp and PeriodicFlow.hpp/ipp + LinSolv variants: implement the solver in itself (mesh, boundary conditions, solving, defining fluid-particles interactions)
+- FlowEngine.hpp/ipp/cpp (this file)
+
+Variants for periodic boundary conditions are also present.
+
+*/
+
+#pragma once
+#include<yade/core/PartialEngine.hpp>
+#include<yade/pkg/dem/TriaxialCompressionEngine.hpp>
+#include<yade/pkg/dem/TesselationWrapper.hpp>
+#include<yade/lib/triangulation/FlowBoundingSphere.hpp>
+#include<yade/lib/triangulation/PeriodicFlow.hpp>
+
+/// Frequently used:
+typedef CGT::CVector CVector;
+typedef CGT::Point Point;
+
+/// Converters for Eigen and CGAL vectors
+inline CVector makeCgVect ( const Vector3r& yv ) {return CVector ( yv[0],yv[1],yv[2] );}
+inline Point makeCgPoint ( const Vector3r& yv ) {return Point ( yv[0],yv[1],yv[2] );}
+inline Vector3r makeVector3r ( const Point& yv ) {return Vector3r ( yv[0],yv[1],yv[2] );}
+inline Vector3r makeVector3r ( const CVector& yv ) {return Vector3r ( yv[0],yv[1],yv[2] );}
+
+/// C++ templates and YADE_CLASS_... macro family are not very compatible, this #define is a hack to make it work
+/// TEMPLATE_FLOW_NAME will be the name of a serializable TemplateFlowEngine<...> instance, which can in turn be
+/// inherited from. The instance itself will be useless for actual simulations.
+#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=DEFAULTSOLVER >
+class TemplateFlowEngine : public PartialEngine
+{
+ public :
+ typedef solverT FlowSolver;
+ typedef FlowSolver Solver;//FIXME: useless alias, search/replace then remove
+ typedef typename FlowSolver::Tesselation Tesselation;
+ typedef typename FlowSolver::RTriangulation RTriangulation;
+ typedef typename FlowSolver::FiniteVerticesIterator FiniteVerticesIterator;
+ typedef typename FlowSolver::FiniteCellsIterator FiniteCellsIterator;
+ typedef typename FlowSolver::CellHandle CellHandle;
+ typedef typename FlowSolver::FiniteEdgesIterator FiniteEdgesIterator;
+ typedef typename FlowSolver::VertexHandle VertexHandle;
+ typedef typename RTriangulation::Triangulation_data_structure::Cell::Info CellInfo;
+ typedef typename RTriangulation::Triangulation_data_structure::Vertex::Info VertexInfo;
+
+ protected:
+ shared_ptr<FlowSolver> solver;
+ shared_ptr<FlowSolver> backgroundSolver;
+ volatile bool backgroundCompleted;
+ Cell cachedCell;
+ struct posData {Body::id_t id; Vector3r pos; Real radius; bool isSphere; bool exists; posData(){exists=0;}};
+ vector<posData> positionBufferCurrent;//reflect last known positions before we start computations
+ vector<posData> positionBufferParallel;//keep the positions from a given step for multithread factorization
+ //copy positions in a buffer for faster and/or parallel access
+ void setPositionsBuffer(bool current);
+ virtual void trickPermeability() {};
+
+ public :
+ int retriangulationLastIter;
+ enum {wall_xmin, wall_xmax, wall_ymin, wall_ymax, wall_zmin, wall_zmax};
+ Vector3r normal [6];
+ bool currentTes;
+ bool metisForced;
+ int idOffset;
+ double epsVolCumulative;
+ int ReTrg;
+ int ellapsedIter;
+ void initSolver (FlowSolver& flow);
+ #ifdef LINSOLV
+ void setForceMetis (bool force);
+ bool getForceMetis ();
+ #endif
+ void triangulate (Solver& flow);
+ void addBoundary (Solver& flow);
+ void buildTriangulation (double pZero, Solver& flow);
+ void buildTriangulation (Solver& flow);
+ void updateVolumes (Solver& flow);
+ void initializeVolumes (Solver& flow);
+ void boundaryConditions(Solver& flow);
+ void updateBCs ( Solver& flow ) {
+ if (flow.T[flow.currentTes].maxId>0) boundaryConditions(flow);//avoids crash at iteration 0, when the packing is not bounded yet
+ else LOG_ERROR("updateBCs not applied");
+ flow.pressureChanged=true;}
+
+ void imposeFlux(Vector3r pos, Real flux);
+ unsigned int imposePressure(Vector3r pos, Real p);
+ void setImposedPressure(unsigned int cond, Real p);
+ void clearImposedPressure();
+ void clearImposedFlux();
+ void computeViscousForces(Solver& flow);
+ Real getCellFlux(unsigned int cond);
+ Real getBoundaryFlux(unsigned int boundary) {return solver->boundaryFlux(boundary);}
+ Vector3r fluidForce(unsigned int idSph) {
+ const CGT::CVector& f=solver->T[solver->currentTes].vertex(idSph)->info().forces; return Vector3r(f[0],f[1],f[2]);}
+
+ Vector3r shearLubForce(unsigned int id_sph) {
+ return (solver->shearLubricationForces.size()>id_sph)?solver->shearLubricationForces[id_sph]:Vector3r::Zero();}
+ Vector3r shearLubTorque(unsigned int id_sph) {
+ return (solver->shearLubricationTorques.size()>id_sph)?solver->shearLubricationTorques[id_sph]:Vector3r::Zero();}
+ Vector3r pumpLubTorque(unsigned int id_sph) {
+ return (solver->pumpLubricationTorques.size()>id_sph)?solver->pumpLubricationTorques[id_sph]:Vector3r::Zero();}
+ Vector3r twistLubTorque(unsigned int id_sph) {
+ return (solver->twistLubricationTorques.size()>id_sph)?solver->twistLubricationTorques[id_sph]:Vector3r::Zero();}
+ Vector3r normalLubForce(unsigned int id_sph) {
+ return (solver->normalLubricationForce.size()>id_sph)?solver->normalLubricationForce[id_sph]:Vector3r::Zero();}
+ Matrix3r bodyShearLubStress(unsigned int id_sph) {
+ return (solver->shearLubricationBodyStress.size()>id_sph)?solver->shearLubricationBodyStress[id_sph]:Matrix3r::Zero();}
+ Matrix3r bodyNormalLubStress(unsigned int id_sph) {
+ return (solver->normalLubricationBodyStress.size()>id_sph)?solver->normalLubricationBodyStress[id_sph]:Matrix3r::Zero();}
+ Vector3r shearVelocity(unsigned int interaction) {
+ return (solver->deltaShearVel[interaction]);}
+ Vector3r normalVelocity(unsigned int interaction) {
+ return (solver->deltaNormVel[interaction]);}
+ Matrix3r normalStressInteraction(unsigned int interaction) {
+ return (solver->normalStressInteraction[interaction]);}
+ Matrix3r shearStressInteraction(unsigned int interaction) {
+ return (solver->shearStressInteraction[interaction]);}
+ Vector3r normalVect(unsigned int interaction) {
+ return (solver->normalV[interaction]);}
+ Real surfaceDistanceParticle(unsigned int interaction) {
+ return (solver->surfaceDistance[interaction]);}
+ Real edgeSize() {
+ return (solver->edgeIds.size());}
+ Real OSI() {
+ return (solver->onlySpheresInteractions.size());}
+ int onlySpheresInteractions(unsigned int interaction) {
+ return (solver->onlySpheresInteractions[interaction]);}
+ python::list getConstrictions(bool all) {
+ vector<Real> csd=solver->getConstrictions(); python::list pycsd;
+ for (unsigned int k=0;k<csd.size();k++) if ((all && csd[k]!=0) || csd[k]>0) pycsd.append(csd[k]); return pycsd;}
+ python::list getConstrictionsFull(bool all) {
+ vector<Constriction> csd=solver->getConstrictionsFull(); python::list pycsd;
+ for (unsigned int k=0;k<csd.size();k++) if ((all && csd[k].second[0]!=0) || csd[k].second[0]>0) {
+ python::list cons;
+ cons.append(csd[k].first.first);
+ cons.append(csd[k].first.second);
+ cons.append(csd[k].second[0]);
+ cons.append(csd[k].second[1]);
+ cons.append(csd[k].second[2]);
+ cons.append(csd[k].second[3]);
+ pycsd.append(cons);}
+ return pycsd;}
+
+ template<class Cellhandle>
+ Real volumeCellSingleFictious (Cellhandle cell);
+ template<class Cellhandle>
+ Real volumeCellDoubleFictious (Cellhandle cell);
+ template<class Cellhandle>
+ Real volumeCellTripleFictious (Cellhandle cell);
+ template<class Cellhandle>
+ Real volumeCell (Cellhandle cell);
+ void Oedometer_Boundary_Conditions();
+ void averageRealCellVelocity();
+ void saveVtk(const char* folder) {solver->saveVtk(folder);}
+ vector<Real> avFlVelOnSph(unsigned int idSph) {return solver->averageFluidVelocityOnSphere(idSph);}
+
+// void setBoundaryVel(Vector3r vel) {topBoundaryVelocity=vel; updateTriangulation=true;}
+ void pressureProfile(double wallUpY, double wallDownY) {return solver->measurePressureProfile(wallUpY,wallDownY);}
+ double getPorePressure(Vector3r pos){return solver->getPorePressure(pos[0], pos[1], pos[2]);}
+ int getCell(double posX, double posY, double posZ){return solver->getCell(posX, posY, posZ);}
+ unsigned int nCells(){return solver->T[solver->currentTes].cellHandles.size();}
+ python::list getVertices(unsigned int id){
+ python::list ids;
+ if (id>=solver->T[solver->currentTes].cellHandles.size()) {LOG_ERROR("id out of range, max value is "<<solver->T[solver->currentTes].cellHandles.size()); return ids;}
+ for (unsigned int i=0;i<4;i++) ids.append(solver->T[solver->currentTes].cellHandles[id]->vertex(i)->info().id());
+ return ids;
+ }
+ double averageSlicePressure(double posY){return solver->averageSlicePressure(posY);}
+ double averagePressure(){return solver->averagePressure();}
+
+ void emulateAction(){
+ scene = Omega::instance().getScene().get();
+ action();}
+ #ifdef LINSOLV
+ void exportMatrix(string filename) {if (useSolver==3) solver->exportMatrix(filename.c_str());
+ else cerr<<"available for Cholmod solver (useSolver==3)"<<endl;}
+ void exportTriplets(string filename) {if (useSolver==3) solver->exportTriplets(filename.c_str());
+ else cerr<<"available for Cholmod solver (useSolver==3)"<<endl;}
+ void cholmodStats() {
+ cerr << cholmod_print_common((char*)string("PFV Cholmod factorization").c_str(),&(solver->eSolver.cholmod()))<<endl;
+ cerr << "cholmod method:" << solver->eSolver.cholmod().selected<<endl;
+ cerr << "METIS called:"<<solver->eSolver.cholmod().called_nd<<endl;}
+ bool metisUsed() {return bool(solver->eSolver.cholmod().called_nd);}
+ #endif
+
+ virtual ~TemplateFlowEngine();
+ virtual void action();
+ virtual void backgroundAction();
+
+ //commodities
+ void compTessVolumes() {
+ solver->T[solver->currentTes].compute();
+ 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.");*/}
+ 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.",
+ ((bool,isActivated,true,,"Activates Flow Engine"))
+ ((bool,first,true,,"Controls the initialization/update phases"))
+ ((bool,doInterpolate,false,,"Force the interpolation of cell's info while remeshing. By default, interpolation would be done only for compressible fluids. It can be forced with this flag."))
+ ((double, fluidBulkModulus, 0.,,"Bulk modulus of fluid (inverse of compressibility) K=-dP*V/dV [Pa]. Flow is compressible if fluidBulkModulus > 0, else incompressible."))
+ ((Real, dt, 0,,"timestep [s]"))
+ ((bool,permeabilityMap,false,,"Enable/disable stocking of average permeability scalar in cell infos."))
+ ((bool, slipBoundary, true,, "Controls friction condition on lateral walls"))
+ ((bool,waveAction, false,, "Allow sinusoidal pressure condition to simulate ocean waves"))
+ ((double, sineMagnitude, 0,, "Pressure value (amplitude) when sinusoidal pressure is applied (p )"))
+ ((double, sineAverage, 0,,"Pressure value (average) when sinusoidal pressure is applied"))
+ ((bool, debug, false,,"Activate debug messages"))
+ ((double, wallThickness,0.001,,"Walls thickness"))
+ ((double,pZero,0,,"The value used for initializing pore pressure. It is useless for incompressible fluid, but important for compressible model."))
+ ((double,tolerance,1e-06,,"Gauss-Seidel tolerance"))
+ ((double,relax,1.9,,"Gauss-Seidel relaxation"))
+ ((bool, updateTriangulation, 0,,"If true the medium is retriangulated. Can be switched on to force retriangulation after some events (else it will be true periodicaly based on :yref:`FlowEngine::defTolerance` and :yref:`FlowEngine::meshUpdateInterval`. Of course, it costs CPU time."))
+ ((int,meshUpdateInterval,1000,,"Maximum number of timesteps between re-triangulation events. See also :yref:`FlowEngine::defTolerance`."))
+ ((double, epsVolMax, 0,(Attr::readonly),"Maximal absolute volumetric strain computed at each iteration. |yupdate|"))
+ ((double, defTolerance,0.05,,"Cumulated deformation threshold for which retriangulation of pore space is performed. If negative, the triangulation update will occure with a fixed frequency on the basis of :yref:`FlowEngine::meshUpdateInterval`"))
+ ((double, porosity, 0,(Attr::readonly),"Porosity computed at each retriangulation |yupdate|"))
+ ((bool,meanKStat,false,,"report the local permeabilities' correction"))
+ ((bool,clampKValues,true,,"If true, clamp local permeabilities in [minKdivKmean,maxKdivKmean]*globalK. This clamping can avoid singular values in the permeability matrix and may reduce numerical errors in the solve phase. It will also hide junk values if they exist, or bias all values in very heterogeneous problems. So, use this with care."))
+ ((Real,minKdivKmean,0.0001,,"define the min K value (see :yref:`FlowEngine::clampKValues`)"))
+ ((Real,maxKdivKmean,100,,"define the max K value (see :yref:`FlowEngine::clampKValues`)"))
+ ((double,permeabilityFactor,1.0,,"permability multiplier"))
+ ((double,viscosity,1.0,,"viscosity of the fluid"))
+ ((double,stiffness, 10000,,"equivalent contact stiffness used in the lubrication model"))
+ ((int, useSolver, 0,, "Solver to use 0=G-Seidel, 1=Taucs, 2-Pardiso, 3-CHOLMOD"))
+ ((int, xmin,0,(Attr::readonly),"Index of the boundary $x_{min}$. This index is not equal the the id of the corresponding body in general, it may be used to access the corresponding attributes (e.g. flow.bndCondValue[flow.xmin], flow.wallId[flow.xmin],...)."))
+ ((int, xmax,1,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
+ ((int, ymin,2,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
+ ((int, ymax,3,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
+ ((int, zmin,4,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
+ ((int, zmax,5,(Attr::readonly),"See :yref:`FlowEngine::xmin`."))
+
+ ((vector<bool>, bndCondIsPressure, vector<bool>(6,false),,"defines the type of boundary condition for each side. True if pressure is imposed, False for no-flux. Indexes can be retrieved with :yref:`FlowEngine::xmin` and friends."))
+ ((vector<double>, bndCondValue, vector<double>(6,0),,"Imposed value of a boundary condition. Only applies if the boundary condition is imposed pressure, else the imposed flux is always zero presently (may be generalized to non-zero imposed fluxes in the future)."))
+ //FIXME: to be implemented:
+ ((vector<Vector3r>, boundaryVelocity, vector<Vector3r>(6,Vector3r::Zero()),, "velocity on top boundary, only change it using :yref:`FlowEngine::setBoundaryVel`"))
+ ((int, ignoredBody,-1,,"Id of a sphere to exclude from the triangulation.)"))
+ ((vector<int>, wallIds,vector<int>(6),,"body ids of the boundaries (default values are ok only if aabbWalls are appended before spheres, i.e. numbered 0,...,5)"))
+ ((vector<bool>, boundaryUseMaxMin, vector<bool>(6,true),,"If true (default value) bounding sphere is added as function of max/min sphere coord, if false as function of yade wall position"))
+// ((bool, display_force, false,,"display the lubrication force applied on particles"))
+// ((bool, create_file, false,,"create file of velocities"))
+ ((bool, viscousShear, false,,"compute viscous shear terms as developped by Donia Marzougui (FIXME: ref.)"))
+ ((bool, shearLubrication, false,,"compute shear lubrication force as developped by Brule (FIXME: ref.) "))
+ ((bool, pumpTorque, false,,"Compute pump torque applied on particles "))
+ ((bool, twistTorque, false,,"Compute twist torque applied on particles "))
+ ((double, eps, 0.00001,,"roughness defined as a fraction of particles size, giving the minimum distance between particles in the lubrication model."))
+ ((bool, pressureForce, true,,"compute the pressure field and associated fluid forces. WARNING: turning off means fluid flow is not computed at all."))
+ ((bool, normalLubrication, false,,"compute normal lubrication force as developped by Brule"))
+ ((bool, viscousNormalBodyStress, false,,"compute normal viscous stress applied on each body"))
+ ((bool, viscousShearBodyStress, false,,"compute shear viscous stress applied on each body"))
+ ((bool, multithread, false,,"Build triangulation and factorize in the background (multi-thread mode)"))
+ #ifdef EIGENSPARSE_LIB
+ ((int, numSolveThreads, 1,,"number of openblas threads in the solve phase."))
+ ((int, numFactorizeThreads, 1,,"number of openblas threads in the factorization phase"))
+ #endif
+ ((vector<Real>, boundaryPressure,vector<Real>(),,"values defining pressure along x-axis for the top surface. See also :yref:`TEMPLATE_FLOW_NAME::boundaryXPos`"))
+ ((vector<Real>, boundaryXPos,vector<Real>(),,"values of the x-coordinate for which pressure is defined. See also :yref:`TEMPLATE_FLOW_NAME::boundaryPressure`"))
+ ,
+ /*deprec*/
+ ((meanK_opt,clampKValues,"the name changed"))
+ ,,
+ timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas);
+ for (int i=0; i<6; ++i){normal[i]=Vector3r::Zero(); wallIds[i]=i;}
+ normal[wall_ymin].y()=normal[wall_xmin].x()=normal[wall_zmin].z()=1;
+ normal[wall_ymax].y()=normal[wall_xmax].x()=normal[wall_zmax].z()=-1;
+ solver = shared_ptr<FlowSolver> (new FlowSolver);
+ first=true;
+ epsVolMax=epsVolCumulative=retriangulationLastIter=0;
+ ReTrg=1;
+ backgroundCompleted=true;
+ ellapsedIter=0;
+ metisForced=false;
+ ,
+ .def("imposeFlux",&TemplateFlowEngine::imposeFlux,(python::arg("pos"),python::arg("p")),"Impose incoming flux in boundary cell of location 'pos'.")
+ .def("imposePressure",&TemplateFlowEngine::imposePressure,(python::arg("pos"),python::arg("p")),"Impose pressure in cell of location 'pos'. The index of the condition is returned (for multiple imposed pressures at different points).")
+ .def("setImposedPressure",&TemplateFlowEngine::setImposedPressure,(python::arg("cond"),python::arg("p")),"Set pressure value at the point indexed 'cond'.")
+ .def("clearImposedPressure",&TemplateFlowEngine::clearImposedPressure,"Clear the list of points with pressure imposed.")
+ .def("clearImposedFlux",&TemplateFlowEngine::clearImposedFlux,"Clear the list of points with flux imposed.")
+ .def("getCellFlux",&TemplateFlowEngine::getCellFlux,(python::arg("cond")),"Get influx in cell associated to an imposed P (indexed using 'cond').")
+ .def("getBoundaryFlux",&TemplateFlowEngine::getBoundaryFlux,(python::arg("boundary")),"Get total flux through boundary defined by its body id.\n\n.. note:: The flux may be not zero even for no-flow condition. This artifact comes from cells which are incident to two or more boundaries (along the edges of the sample, typically). Such flux evaluation on impermeable boundary is just irrelevant, it does not imply that the boundary condition is not applied properly.")
+ .def("getConstrictions",&TemplateFlowEngine::getConstrictions,(python::arg("all")=true),"Get the list of constriction radii (inscribed circle) for all finite facets (if all==True) or all facets not incident to a virtual bounding sphere (if all==False). When all facets are returned, negative radii denote facet incident to one or more fictious spheres.")
+ .def("getConstrictionsFull",&TemplateFlowEngine::getConstrictionsFull,(python::arg("all")=true),"Get the list of constrictions (inscribed circle) for all finite facets (if all==True), or all facets not incident to a fictious bounding sphere (if all==False). When all facets are returned, negative radii denote facet incident to one or more fictious spheres. The constrictions are returned in the format {{cell1,cell2}{rad,nx,ny,nz}}")
+ .def("edgeSize",&TemplateFlowEngine::edgeSize,"Return the number of interactions.")
+ .def("OSI",&TemplateFlowEngine::OSI,"Return the number of interactions only between spheres.")
+
+ .def("saveVtk",&TemplateFlowEngine::saveVtk,(python::arg("folder")="./VTK"),"Save pressure field in vtk format. Specify a folder name for output.")
+ .def("avFlVelOnSph",&TemplateFlowEngine::avFlVelOnSph,(python::arg("idSph")),"compute a sphere-centered average fluid velocity")
+ .def("fluidForce",&TemplateFlowEngine::fluidForce,(python::arg("idSph")),"Return the fluid force on sphere idSph.")
+ .def("shearLubForce",&TemplateFlowEngine::shearLubForce,(python::arg("idSph")),"Return the shear lubrication force on sphere idSph.")
+ .def("shearLubTorque",&TemplateFlowEngine::shearLubTorque,(python::arg("idSph")),"Return the shear lubrication torque on sphere idSph.")
+ .def("normalLubForce",&TemplateFlowEngine::normalLubForce,(python::arg("idSph")),"Return the normal lubrication force on sphere idSph.")
+ .def("bodyShearLubStress",&TemplateFlowEngine::bodyShearLubStress,(python::arg("idSph")),"Return the shear lubrication stress on sphere idSph.")
+ .def("bodyNormalLubStress",&TemplateFlowEngine::bodyNormalLubStress,(python::arg("idSph")),"Return the normal lubrication stress on sphere idSph.")
+ .def("shearVelocity",&TemplateFlowEngine::shearVelocity,(python::arg("idSph")),"Return the shear velocity of the interaction.")
+ .def("normalVelocity",&TemplateFlowEngine::normalVelocity,(python::arg("idSph")),"Return the normal velocity of the interaction.")
+ .def("normalVect",&TemplateFlowEngine::normalVect,(python::arg("idSph")),"Return the normal vector between particles.")
+ .def("surfaceDistanceParticle",&TemplateFlowEngine::surfaceDistanceParticle,(python::arg("interaction")),"Return the distance between particles.")
+ .def("onlySpheresInteractions",&TemplateFlowEngine::onlySpheresInteractions,(python::arg("interaction")),"Return the id of the interaction only between spheres.")
+ .def("pressureProfile",&TemplateFlowEngine::pressureProfile,(python::arg("wallUpY"),python::arg("wallDownY")),"Measure pore pressure in 6 equally-spaced points along the height of the sample")
+ .def("getPorePressure",&TemplateFlowEngine::getPorePressure,(python::arg("pos")),"Measure pore pressure in position pos[0],pos[1],pos[2]")
+ .def("averageSlicePressure",&TemplateFlowEngine::averageSlicePressure,(python::arg("posY")),"Measure slice-averaged pore pressure at height posY")
+ .def("averagePressure",&TemplateFlowEngine::averagePressure,"Measure averaged pore pressure in the entire volume")
+ .def("updateBCs",&TemplateFlowEngine::updateBCs,"tells the engine to update it's boundary conditions before running (especially useful when changing boundary pressure - should not be needed for point-wise imposed pressure)")
+ .def("emulateAction",&TemplateFlowEngine::emulateAction,"get scene and run action (may be used to manipulate an engine outside the timestepping loop).")
+ .def("getCell",&TemplateFlowEngine::getCell,(python::arg("pos")),"get id of the cell containing (X,Y,Z).")
+ .def("nCells",&TemplateFlowEngine::nCells,"get the total number of finite cells in the triangulation.")
+ .def("getVertices",&TemplateFlowEngine::getVertices,(python::arg("id")),"get the vertices of a cell")
+ #ifdef LINSOLV
+ .def("exportMatrix",&TemplateFlowEngine::exportMatrix,(python::arg("filename")="matrix"),"Export system matrix to a file with all entries (even zeros will displayed).")
+ .def("exportTriplets",&TemplateFlowEngine::exportTriplets,(python::arg("filename")="triplets"),"Export system matrix to a file with only non-zero entries.")
+ .def("cholmodStats",&TemplateFlowEngine::cholmodStats,"get statistics of cholmod solver activity")
+ .def("metisUsed",&TemplateFlowEngine::metisUsed,"check wether metis lib is effectively used")
+ .add_property("forceMetis",&TemplateFlowEngine::getForceMetis,&TemplateFlowEngine::setForceMetis,"If true, METIS is used for matrix preconditioning, else Cholmod is free to choose the best method (which may be METIS to, depending on the matrix). See ``nmethods`` in Cholmod documentation")
+ #endif
+ .def("compTessVolumes",&TemplateFlowEngine::compTessVolumes,"Like TesselationWrapper::computeVolumes()")
+ .def("volume",&TemplateFlowEngine::getVolume,(python::arg("id")=0),"Returns the volume of Voronoi's cell of a sphere.")
+ )
+};
+// Definition of functions in a separate file for clarity
+#include<yade/pkg/pfv/FlowEngine.ipp>
+
+class FlowCellInfo : public CGT::SimpleCellInfo {
+ public:
+ //For vector storage of all cells
+ unsigned int index;
+ int volumeSign;
+ bool Pcondition;
+ Real invVoidV;
+ Real t;
+ int fict;
+ Real volumeVariation;
+ double pression;
+ //average relative (fluid - facet translation) velocity defined for a single cell as 1/Volume * SUM_ON_FACETS(x_average_facet*average_facet_flow_rate)
+ CVector averageCellVelocity;
+ // Surface vectors of facets, pointing from outside toward inside the cell
+ std::vector<CVector> facetSurfaces;
+ //Ratio between fluid surface and facet surface
+ std::vector<Real> facetFluidSurfacesRatio;
+ // Reflects the geometrical property of the cell, so that the force by cell fluid on grain "i" is pressure*unitForceVectors[i]
+ std::vector<CVector> unitForceVectors;
+ // Store the area of triangle-sphere intersections for each facet (used in forces definition)
+ std::vector<CVector> facetSphereCrossSections;
+ std::vector<CVector> cellForce;
+ std::vector<double> rayHydr;
+ std::vector<double> modulePermeability;
+ // Partial surfaces of spheres in the double-tetrahedron linking two voronoi centers. [i][j] is for sphere facet "i" and sphere facetVertices[i][j]. Last component for 1/sum_surfaces in the facet.doInterpolate
+ double solidSurfaces [4][4];
+
+ FlowCellInfo (void)
+ {
+ modulePermeability.resize(4, 0);
+ cellForce.resize(4,CGAL::NULL_VECTOR);
+ facetSurfaces.resize(4,CGAL::NULL_VECTOR);
+ facetFluidSurfacesRatio.resize(4,0);
+ facetSphereCrossSections.resize(4,CGAL::NULL_VECTOR);
+ unitForceVectors.resize(4,CGAL::NULL_VECTOR);
+ for (int k=0; k<4;k++) for (int l=0; l<3;l++) solidSurfaces[k][l]=0;
+ rayHydr.resize(4, 0);
+ invSumK=index=volumeSign=s=volumeVariation=pression=invVoidV=fict=0;
+ isFictious=false; Pcondition = false; isGhost = false;
+ isvisited = false;
+ isGhost=false;
+ }
+ bool isGhost;
+ double invSumK;
+ bool isvisited;
+
+ inline Real& volume (void) {return t;}
+ inline const Real& invVoidVolume (void) const {return invVoidV;}
+ inline Real& invVoidVolume (void) {return invVoidV;}
+ inline Real& dv (void) {return volumeVariation;}
+ inline int& fictious (void) {return fict;}
+ inline double& p (void) {return pression;}
+ inline const double shiftedP (void) const {return pression;} //For compatibility with the periodic case
+ inline const std::vector<double>& kNorm (void) const {return modulePermeability;}
+ inline std::vector<double>& kNorm (void) {return modulePermeability;}
+ inline std::vector< CVector >& facetSurf (void) {return facetSurfaces;}
+ inline std::vector<CVector>& force (void) {return cellForce;}
+ inline std::vector<double>& Rh (void) {return rayHydr;}
+ inline CVector& averageVelocity (void) {return averageCellVelocity;}
+ //used for transfering values between two triangulations, overload with more variables in derived classes (see e.g. SoluteFlow)
+ inline void getInfo(const FlowCellInfo& otherCellInfo) {p()=otherCellInfo.shiftedP();}
+};
+
+class FlowVertexInfo : public CGT::SimpleVertexInfo {
+ CVector grainVelocity;
+ Real volumeIncidentCells;
+public:
+ CVector forces;
+ bool isGhost;
+ FlowVertexInfo (void) {isGhost=false;}
+ inline CVector& force (void) {return forces;}
+ inline CVector& vel (void) {return grainVelocity;}
+ inline Real& volCells (void) {return volumeIncidentCells;}
+ inline const CVector ghostShift (void) const {return CGAL::NULL_VECTOR;}
+};
+
+
+
=== added file 'pkg/pfv/FlowEngine.ipp'
--- pkg/pfv/FlowEngine.ipp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/FlowEngine.ipp 2014-05-07 10:28:20 +0000
@@ -0,0 +1,735 @@
+/*************************************************************************
+* Copyright (C) 2009 by Emanuele Catalano <catalano@xxxxxxxxxxxxxxx> *
+* Copyright (C) 2009 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 YADE_CGAL
+
+#ifdef FLOW_ENGINE
+#include<yade/core/Scene.hpp>
+#include<yade/lib/base/Math.hpp>
+#include<yade/pkg/dem/TesselationWrapper.hpp>
+#include<yade/pkg/common/Sphere.hpp>
+#include<yade/pkg/common/Wall.hpp>
+#include<yade/pkg/common/Box.hpp>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <boost/thread.hpp>
+#include <boost/date_time.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#ifdef LINSOLV
+#include <cholmod.h>
+#endif
+
+#include "FlowEngine.hpp"
+
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::~TemplateFlowEngine() {}
+
+// YADE_PLUGIN((TFlowEng));
+
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+unsigned int TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::imposePressure(Vector3r pos, Real p)
+{
+// if (!flow) LOG_ERROR("no flow defined yet, run at least one iter");
+ solver->imposedP.push_back( pair<CGT::Point,Real>(CGT::Point(pos[0],pos[1],pos[2]),p) );
+ //force immediate update of boundary conditions
+ updateTriangulation=true;
+ return solver->imposedP.size()-1;
+}
+
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::action()
+{
+ if ( !isActivated ) return;
+ timingDeltas->start();
+ setPositionsBuffer(true);
+ timingDeltas->checkpoint ( "Position buffer" );
+ if (first) {
+ if (multithread) setPositionsBuffer(false);
+ buildTriangulation(pZero,*solver);
+ initializeVolumes(*solver);
+ backgroundSolver=solver;
+ backgroundCompleted=true;
+ }
+ solver->ompThreads = ompThreads>0? ompThreads : omp_get_max_threads();
+
+ timingDeltas->checkpoint ( "Triangulating" );
+ updateVolumes ( *solver );
+ timingDeltas->checkpoint ( "Update_Volumes" );
+
+ epsVolCumulative += epsVolMax;
+ retriangulationLastIter++;
+ if (!updateTriangulation) updateTriangulation = // If not already set true by another function of by the user, check conditions
+ (defTolerance>0 && epsVolCumulative > defTolerance) || retriangulationLastIter>meshUpdateInterval;
+
+ ///compute flow and and forces here
+ if (pressureForce){
+ solver->gaussSeidel(scene->dt);
+ timingDeltas->checkpoint ( "Gauss-Seidel (includes matrix construct and factorization in single-thread mode)" );
+ solver->computeFacetForcesWithCache();}
+ timingDeltas->checkpoint ( "compute_Forces" );
+ ///Application of vicscous forces
+ scene->forces.sync();
+ timingDeltas->checkpoint ( "forces.sync()" );
+ computeViscousForces ( *solver );
+ timingDeltas->checkpoint ( "viscous forces" );
+ Vector3r force;
+ Vector3r torque;
+ FiniteVerticesIterator verticesEnd = solver->T[solver->currentTes].Triangulation().finite_vertices_end();
+ for ( FiniteVerticesIterator vIt = solver->T[solver->currentTes].Triangulation().finite_vertices_begin(); vIt != verticesEnd; vIt++ ) {
+ force = pressureForce ? Vector3r ( vIt->info().forces[0],vIt->info().forces[1],vIt->info().forces[2] ): Vector3r(0,0,0);
+ torque = Vector3r(0,0,0);
+ if (shearLubrication || viscousShear){
+ force = force + solver->shearLubricationForces[vIt->info().id()];
+ torque = torque + solver->shearLubricationTorques[vIt->info().id()];
+ if (pumpTorque)
+ torque = torque + solver->pumpLubricationTorques[vIt->info().id()];
+ }
+ if (twistTorque)
+ torque = torque + solver->twistLubricationTorques[vIt->info().id()];
+ if (normalLubrication)
+ force = force + solver-> normalLubricationForce[vIt->info().id()];
+ scene->forces.addForce ( vIt->info().id(), force);
+ scene->forces.addTorque ( vIt->info().id(), torque);
+ }
+ ///End compute flow and forces
+ timingDeltas->checkpoint ( "Applying Forces" );
+ #ifdef LINSOLV
+ int sleeping = 0;
+ if (multithread && !first) {
+ while (updateTriangulation && !backgroundCompleted) { /*cout<<"sleeping..."<<sleeping++<<endl;*/
+ sleeping++;
+ boost::this_thread::sleep(boost::posix_time::microseconds(1000));}
+ if (debug && sleeping) cerr<<"sleeping..."<<sleeping<<endl;
+ if (updateTriangulation || (ellapsedIter>(0.5*meshUpdateInterval) && backgroundCompleted)) {
+ if (debug) cerr<<"switch flow solver"<<endl;
+ if (useSolver==0) LOG_ERROR("background calculations not available for Gauss-Seidel");
+ if (fluidBulkModulus>0 || doInterpolate) solver->interpolate (solver->T[solver->currentTes], backgroundSolver->T[backgroundSolver->currentTes]);
+ solver=backgroundSolver;
+ backgroundSolver = shared_ptr<FlowSolver> (new FlowSolver);
+ if (metisForced) {backgroundSolver->eSolver.cholmod().nmethods=1; backgroundSolver->eSolver.cholmod().method[0].ordering=CHOLMOD_METIS;}
+ //Copy imposed pressures/flow from the old solver
+ backgroundSolver->imposedP = vector<pair<CGT::Point,Real> >(solver->imposedP);
+ backgroundSolver->imposedF = vector<pair<CGT::Point,Real> >(solver->imposedF);
+ if (debug) cerr<<"switched"<<endl;
+ setPositionsBuffer(false);//set "parallel" buffer for background calculation
+ backgroundCompleted=false;
+ retriangulationLastIter=ellapsedIter;
+ updateTriangulation=false;
+ epsVolCumulative=0;
+ ellapsedIter=0;
+ boost::thread workerThread(&TemplateFlowEngine::backgroundAction,this);
+ workerThread.detach();
+ if (debug) cerr<<"backgrounded"<<endl;
+ initializeVolumes(*solver);
+ computeViscousForces(*solver);
+ if (debug) cerr<<"volumes initialized"<<endl;
+ }
+ else {
+ if (debug && !backgroundCompleted) cerr<<"still computing solver in the background, ellapsedIter="<<ellapsedIter<<endl;
+ ellapsedIter++;
+ }
+ } else
+ #endif
+ {
+ if (updateTriangulation && !first) {
+ buildTriangulation (pZero, *solver);
+ initializeVolumes(*solver);
+ computeViscousForces(*solver);
+ updateTriangulation = false;
+ epsVolCumulative=0;
+ retriangulationLastIter=0;
+ ReTrg++;}
+ }
+ first=false;
+ timingDeltas->checkpoint ( "triangulate + init volumes" );
+}
+
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::backgroundAction()
+{
+ if (useSolver<1) {LOG_ERROR("background calculations not available for Gauss-Seidel"); return;}
+ buildTriangulation ( pZero,*backgroundSolver );
+ //FIXME: GS is computing too much, we need only matrix factorization in fact
+ backgroundSolver->gaussSeidel(scene->dt);
+ //FIXME(2): and here we need only cached variables, not forces
+ backgroundSolver->computeFacetForcesWithCache(/*onlyCache?*/ true);
+// boost::this_thread::sleep(boost::posix_time::seconds(5));
+ backgroundCompleted = true;
+}
+
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::boundaryConditions ( Solver& flow )
+{
+ for (int k=0;k<6;k++) {
+ flow.boundary (wallIds[k]).flowCondition=!bndCondIsPressure[k];
+ flow.boundary (wallIds[k]).value=bndCondValue[k];
+ flow.boundary (wallIds[k]).velocity = boundaryVelocity[k];//FIXME: needs correct implementation, maybe update the cached pos/vel?
+ }
+}
+
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::setImposedPressure ( unsigned int cond, Real p)
+{
+ if ( cond>=solver->imposedP.size() ) LOG_ERROR ( "Setting p with cond higher than imposedP size." );
+ solver->imposedP[cond].second=p;
+ //force immediate update of boundary conditions
+ solver->pressureChanged=true;
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::imposeFlux ( Vector3r pos, Real flux){
+ solver->imposedF.push_back ( pair<CGT::Point,Real> ( CGT::Point ( pos[0],pos[1],pos[2] ), flux ) );
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::clearImposedPressure () { solver->imposedP.clear(); solver->IPCells.clear();}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::clearImposedFlux () { solver->imposedF.clear(); solver->IFCells.clear();}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+Real TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::getCellFlux ( unsigned int cond)
+{
+ if ( cond>=solver->imposedP.size() ) {LOG_ERROR ( "Getting flux with cond higher than imposedP size." ); return 0;}
+ double flux=0;
+ typename Solver::CellHandle& cell= solver->IPCells[cond];
+ for ( int ngb=0;ngb<4;ngb++ ) {
+ /*if (!cell->neighbor(ngb)->info().Pcondition)*/
+ flux+= cell->info().kNorm() [ngb]* ( cell->info().p()-cell->neighbor ( ngb )->info().p() );
+ }
+ return flux+cell->info().dv();
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::initSolver ( FlowSolver& flow )
+{
+ flow.Vtotalissimo=0; flow.VSolidTot=0; flow.vPoral=0; flow.sSolidTot=0;
+ flow.slipBoundary=slipBoundary;
+ flow.kFactor = permeabilityFactor;
+ flow.debugOut = debug;
+ flow.useSolver = useSolver;
+ #ifdef EIGENSPARSE_LIB
+ flow.numSolveThreads = numSolveThreads;
+ flow.numFactorizeThreads = numFactorizeThreads;
+ #endif
+ flow.meanKStat = meanKStat;
+ flow.viscosity = viscosity;
+ flow.tolerance=tolerance;
+ flow.relax=relax;
+ flow.clampKValues = clampKValues;
+ flow.maxKdivKmean = maxKdivKmean;
+ flow.minKdivKmean = minKdivKmean;
+ flow.meanKStat = meanKStat;
+ flow.permeabilityMap = permeabilityMap;
+ flow.fluidBulkModulus = fluidBulkModulus;
+// 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;
+}
+
+#ifdef LINSOLV
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::setForceMetis ( bool force )
+{
+ if (force) {
+ metisForced=true;
+ solver->eSolver.cholmod().nmethods=1;
+ solver->eSolver.cholmod().method[0].ordering=CHOLMOD_METIS;
+ } else {cholmod_defaults(&(solver->eSolver.cholmod())); metisForced=false;}
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+bool TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::getForceMetis () {return (solver->eSolver.cholmod().nmethods==1);}
+#endif
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::buildTriangulation ( Solver& flow )
+{
+ buildTriangulation ( 0.f,flow );
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::buildTriangulation ( double pZero, Solver& flow )
+{
+ if (first) flow.currentTes=0;
+ else {
+ flow.currentTes=!flow.currentTes;
+ if (debug) cout << "--------RETRIANGULATION-----------" << endl;
+ }
+ flow.resetNetwork();
+ initSolver(flow);
+
+ addBoundary ( flow );
+ triangulate ( flow );
+ if ( debug ) cout << endl << "Tesselating------" << endl << endl;
+ flow.T[flow.currentTes].compute();
+
+ flow.defineFictiousCells();
+ // For faster loops on cells define this vector
+ flow.T[flow.currentTes].cellHandles.clear();
+ flow.T[flow.currentTes].cellHandles.reserve(flow.T[flow.currentTes].Triangulation().number_of_finite_cells());
+ FiniteCellsIterator cell_end = flow.T[flow.currentTes].Triangulation().finite_cells_end();
+ int k=0;
+ for ( FiniteCellsIterator cell = flow.T[flow.currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ){
+ flow.T[flow.currentTes].cellHandles.push_back(cell);
+ cell->info().id=k++;}//define unique numbering now, corresponds to position in cellHandles
+ flow.displayStatistics ();
+ flow.computePermeability();
+ //This virtual function does nothing yet, derived class may overload it to make permeability different (see DFN engine)
+ trickPermeability();
+ porosity = flow.vPoralPorosity/flow.vTotalPorosity;
+
+ boundaryConditions ( flow );
+ flow.initializePressure ( pZero );
+
+ if ( !first && !multithread && (useSolver==0 || fluidBulkModulus>0 || doInterpolate)) flow.interpolate ( flow.T[!flow.currentTes], flow.T[flow.currentTes] );
+ if ( waveAction ) flow.applySinusoidalPressure ( flow.T[flow.currentTes].Triangulation(), sineMagnitude, sineAverage, 30 );
+ else if (boundaryPressure.size()!=0) flow.applyUserDefinedPressure ( flow.T[flow.currentTes].Triangulation(), boundaryXPos , boundaryPressure);
+ if (normalLubrication || shearLubrication || viscousShear) flow.computeEdgesSurfaces();
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::setPositionsBuffer(bool current)
+{
+ vector<posData>& buffer = current? positionBufferCurrent : positionBufferParallel;
+ buffer.clear();
+ buffer.resize(scene->bodies->size());
+ shared_ptr<Sphere> sph ( new Sphere );
+ const int Sph_Index = sph->getClassIndexStatic();
+ FOREACH ( const shared_ptr<Body>& b, *scene->bodies ) {
+ if (!b || ignoredBody==b->getId()) continue;
+ posData& dat = buffer[b->getId()];
+ dat.id=b->getId();
+ dat.pos=b->state->pos;
+ dat.isSphere= (b->shape->getClassIndex() == Sph_Index);
+ if (dat.isSphere) dat.radius = YADE_CAST<Sphere*>(b->shape.get())->radius;
+ dat.exists=true;
+ }
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::addBoundary ( Solver& flow )
+{
+ vector<posData>& buffer = multithread ? positionBufferParallel : positionBufferCurrent;
+ solver->xMin = Mathr::MAX_REAL, solver->xMax = -Mathr::MAX_REAL, solver->yMin = Mathr::MAX_REAL, solver->yMax = -Mathr::MAX_REAL, solver->zMin = Mathr::MAX_REAL, solver->zMax = -Mathr::MAX_REAL;
+ FOREACH ( const posData& b, buffer ) {
+ if ( !b.exists ) continue;
+ if ( b.isSphere ) {
+ const Real& rad = b.radius;
+ const Real& x = b.pos[0];
+ const Real& y = b.pos[1];
+ const Real& z = b.pos[2];
+ flow.xMin = min ( flow.xMin, x-rad );
+ flow.xMax = max ( flow.xMax, x+rad );
+ flow.yMin = min ( flow.yMin, y-rad );
+ flow.yMax = max ( flow.yMax, y+rad );
+ flow.zMin = min ( flow.zMin, z-rad );
+ flow.zMax = max ( flow.zMax, z+rad );
+ }
+ }
+ //FIXME idOffset must be set correctly, not the case here (always 0), then we need walls first or it will fail
+ idOffset = flow.T[flow.currentTes].maxId+1;
+ flow.idOffset = idOffset;
+ flow.sectionArea = ( flow.xMax - flow.xMin ) * ( flow.zMax-flow.zMin );
+ flow.vTotal = ( flow.xMax-flow.xMin ) * ( flow.yMax-flow.yMin ) * ( flow.zMax-flow.zMin );
+ flow.yMinId=wallIds[ymin];
+ flow.yMaxId=wallIds[ymax];
+ flow.xMaxId=wallIds[xmax];
+ flow.xMinId=wallIds[xmin];
+ flow.zMinId=wallIds[zmin];
+ flow.zMaxId=wallIds[zmax];
+
+ //FIXME: Id's order in boundsIds is done according to the enumeration of boundaries from TXStressController.hpp, line 31. DON'T CHANGE IT!
+ flow.boundsIds[0]= &flow.xMinId;
+ flow.boundsIds[1]= &flow.xMaxId;
+ flow.boundsIds[2]= &flow.yMinId;
+ flow.boundsIds[3]= &flow.yMaxId;
+ flow.boundsIds[4]= &flow.zMinId;
+ flow.boundsIds[5]= &flow.zMaxId;
+
+ for (int k=0;k<6;k++) flow.boundary ( *flow.boundsIds[k] ).useMaxMin = boundaryUseMaxMin[k];
+
+ flow.cornerMin = CGT::Point ( flow.xMin, flow.yMin, flow.zMin );
+ flow.cornerMax = CGT::Point ( flow.xMax, flow.yMax, flow.zMax );
+
+ //assign BCs types and values
+ boundaryConditions ( flow );
+
+ double center[3];
+ for ( int i=0; i<6; i++ ) {
+ if ( *flow.boundsIds[i]<0 ) continue;
+ CGT::CVector Normal ( normal[i].x(), normal[i].y(), normal[i].z() );
+ if ( flow.boundary ( *flow.boundsIds[i] ).useMaxMin ) flow.addBoundingPlane(Normal, *flow.boundsIds[i] );
+ else {
+ for ( int h=0;h<3;h++ ) center[h] = buffer[*flow.boundsIds[i]].pos[h];
+// cerr << "id="<<*flow.boundsIds[i] <<" center="<<center[0]<<","<<center[1]<<","<<center[2]<<endl;
+ flow.addBoundingPlane ( center, wallThickness, Normal,*flow.boundsIds[i] );
+ }
+ }
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::triangulate ( Solver& flow )
+{
+///Using Tesselation wrapper (faster)
+// TesselationWrapper TW;
+// if (TW.Tes) delete TW.Tes;
+// TW.Tes = &(flow.T[flow.currentTes]);//point to the current Tes we have in Flowengine
+// TW.insertSceneSpheres();//TW is now really inserting in TemplateFlowEngine, using the faster insert(begin,end)
+// TW.Tes = NULL;//otherwise, Tes would be deleted by ~TesselationWrapper() at the end of the function.
+///Using one-by-one insertion
+ vector<posData>& buffer = multithread ? positionBufferParallel : positionBufferCurrent;
+ FOREACH ( const posData& b, buffer ) {
+ if ( !b.exists ) continue;
+ if ( b.isSphere ) {
+ if (b.id==ignoredBody) continue;
+ flow.T[flow.currentTes].insert ( b.pos[0], b.pos[1], b.pos[2], b.radius, b.id );}
+ }
+ flow.T[flow.currentTes].redirected=true;//By inserting one-by-one, we already redirected
+ flow.shearLubricationForces.resize ( flow.T[flow.currentTes].maxId+1 );
+ flow.shearLubricationTorques.resize ( flow.T[flow.currentTes].maxId+1 );
+ flow.pumpLubricationTorques.resize ( flow.T[flow.currentTes].maxId+1 );
+ flow.twistLubricationTorques.resize ( flow.T[flow.currentTes].maxId+1 );
+ flow.shearLubricationBodyStress.resize ( flow.T[flow.currentTes].maxId+1 );
+ flow.normalLubricationForce.resize ( flow.T[flow.currentTes].maxId+1 );
+ flow.normalLubricationBodyStress.resize ( flow.T[flow.currentTes].maxId+1 );
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::initializeVolumes ( Solver& flow )
+{
+ typedef typename Solver::FiniteVerticesIterator FiniteVerticesIterator;
+
+ FiniteVerticesIterator vertices_end = flow.T[flow.currentTes].Triangulation().finite_vertices_end();
+ CGT::CVector Zero(0,0,0);
+ for (FiniteVerticesIterator V_it = flow.T[flow.currentTes].Triangulation().finite_vertices_begin(); V_it!= vertices_end; V_it++) V_it->info().forces=Zero;
+
+ FOREACH(CellHandle& cell, flow.T[flow.currentTes].cellHandles)
+ {
+ switch ( cell->info().fictious() )
+ {
+ case ( 0 ) : cell->info().volume() = volumeCell ( cell ); break;
+ case ( 1 ) : cell->info().volume() = volumeCellSingleFictious ( cell ); break;
+ case ( 2 ) : cell->info().volume() = volumeCellDoubleFictious ( cell ); break;
+ case ( 3 ) : cell->info().volume() = volumeCellTripleFictious ( cell ); break;
+ default: break;
+ }
+ if (flow.fluidBulkModulus>0) { cell->info().invVoidVolume() = 1 / ( abs(cell->info().volume()) - flow.volumeSolidPore(cell) ); }
+ }
+ if (debug) cout << "Volumes initialised." << endl;
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::averageRealCellVelocity()
+{
+ solver->averageRelativeCellVelocity();
+ Vector3r Vel ( 0,0,0 );
+ //AVERAGE CELL VELOCITY
+ FiniteCellsIterator cell_end = solver->T[solver->currentTes].Triangulation().finite_cells_end();
+ for ( FiniteCellsIterator cell = solver->T[solver->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ) {
+ for ( int g=0;g<4;g++ ) {
+ if ( !cell->vertex ( g )->info().isFictious ) {
+ const shared_ptr<Body>& sph = Body::byId ( cell->vertex ( g )->info().id(), scene );
+ for ( int i=0;i<3;i++ ) Vel[i] = Vel[i] + sph->state->vel[i]/4;
+ }
+ }
+ RTriangulation& Tri = solver->T[solver->currentTes].Triangulation();
+ CGT::Point pos_av_facet;
+ double volume_facet_translation = 0;
+ CGT::CVector Vel_av ( Vel[0], Vel[1], Vel[2] );
+ for ( int i=0; i<4; i++ ) {
+ volume_facet_translation = 0;
+ if ( !Tri.is_infinite ( cell->neighbor ( i ) ) ) {
+ CGT::CVector Surfk = cell->info()-cell->neighbor ( i )->info();
+ Real area = sqrt ( Surfk.squared_length() );
+ Surfk = Surfk/area;
+ CGT::CVector branch = cell->vertex ( facetVertices[i][0] )->point() - cell->info();
+ pos_av_facet = ( CGT::Point ) cell->info() + ( branch*Surfk ) *Surfk;
+ volume_facet_translation += Vel_av*cell->info().facetSurfaces[i];
+ cell->info().averageVelocity() = cell->info().averageVelocity() - volume_facet_translation/cell->info().volume() * ( pos_av_facet-CGAL::ORIGIN );
+ }
+ }
+ }
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::updateVolumes ( Solver& flow )
+{
+ if ( debug ) cout << "Updating volumes.............." << endl;
+ Real invDeltaT = 1/scene->dt;
+ epsVolMax=0;
+ Real totVol=0; Real totDVol=0;
+ #ifdef YADE_OPENMP
+ const long size=flow.T[flow.currentTes].cellHandles.size();
+ #pragma omp parallel for num_threads(ompThreads>0 ? ompThreads : 1)
+ for(long i=0; i<size; i++){
+ CellHandle& cell = flow.T[flow.currentTes].cellHandles[i];
+ #else
+ FOREACH(CellHandle& cell, flow.T[flow.currentTes].cellHandles){
+ #endif
+ double newVol, dVol;
+ switch ( cell->info().fictious() ) {
+ case ( 3 ) : newVol = volumeCellTripleFictious ( cell ); break;
+ case ( 2 ) : newVol = volumeCellDoubleFictious ( cell ); break;
+ case ( 1 ) : newVol = volumeCellSingleFictious ( cell ); break;
+ case ( 0 ) : newVol = volumeCell (cell ); break;
+ default: newVol = 0; break;}
+ dVol=cell->info().volumeSign* ( newVol - cell->info().volume() );
+ cell->info().dv() = dVol*invDeltaT;
+ cell->info().volume() = newVol;
+ if (defTolerance>0) { //if the criterion is not used, then we skip these updates a save a LOT of time when Nthreads > 1
+ #pragma omp atomic
+ totVol+=cell->info().volumeSign*newVol;
+ #pragma omp atomic
+ totDVol+=dVol;}
+ }
+ if (defTolerance>0) epsVolMax = totDVol/totVol;
+ for (unsigned int n=0; n<flow.imposedF.size();n++) {
+ flow.IFCells[n]->info().dv()+=flow.imposedF[n].second;
+ flow.IFCells[n]->info().Pcondition=false;}
+ if ( debug ) cout << "Updated volumes, total =" <<totVol<<", dVol="<<totDVol<<endl;
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+template<class Cellhandle>
+Real TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::volumeCellSingleFictious ( Cellhandle cell )
+{
+ Vector3r V[3];
+ int b=0;
+ int w=0;
+ cell->info().volumeSign=1;
+ Real Wall_coordinate=0;
+
+ for ( int y=0;y<4;y++ ) {
+ if ( ! ( cell->vertex ( y )->info().isFictious ) ) {
+ V[w]=positionBufferCurrent[cell->vertex ( y )->info().id()].pos;
+ w++;
+ } else {
+ b = cell->vertex ( y )->info().id();
+ const shared_ptr<Body>& wll = Body::byId ( b , scene );
+ if ( !solver->boundary ( b ).useMaxMin ) Wall_coordinate = wll->state->pos[solver->boundary ( b ).coordinate]+ ( solver->boundary ( b ).normal[solver->boundary ( b ).coordinate] ) *wallThickness/2.;
+ else Wall_coordinate = solver->boundary ( b ).p[solver->boundary ( b ).coordinate];
+ }
+ }
+ Real Volume = 0.5* ( ( V[0]-V[1] ).cross ( V[0]-V[2] ) ) [solver->boundary ( b ).coordinate] * ( 0.33333333333* ( V[0][solver->boundary ( b ).coordinate]+ V[1][solver->boundary ( b ).coordinate]+ V[2][solver->boundary ( b ).coordinate] ) - Wall_coordinate );
+ return abs ( Volume );
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+template<class Cellhandle>
+Real TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::volumeCellDoubleFictious ( Cellhandle cell )
+{
+ Vector3r A=Vector3r::Zero(), AS=Vector3r::Zero(),B=Vector3r::Zero(), BS=Vector3r::Zero();
+
+ cell->info().volumeSign=1;
+ int b[2];
+ int coord[2];
+ Real Wall_coordinate[2];
+ int j=0;
+ bool first_sph=true;
+
+ for ( int g=0;g<4;g++ ) {
+ if ( cell->vertex ( g )->info().isFictious ) {
+ b[j] = cell->vertex ( g )->info().id();
+ coord[j]=solver->boundary ( b[j] ).coordinate;
+ if ( !solver->boundary ( b[j] ).useMaxMin ) Wall_coordinate[j] = positionBufferCurrent[b[j]].pos[coord[j]] + ( solver->boundary ( b[j] ).normal[coord[j]] ) *wallThickness/2.;
+ else Wall_coordinate[j] = solver->boundary ( b[j] ).p[coord[j]];
+ j++;
+ } else if ( first_sph ) {
+ A=AS=/*AT=*/ positionBufferCurrent[cell->vertex(g)->info().id()].pos;
+ first_sph=false;
+ } else {
+ B=BS=/*BT=*/ positionBufferCurrent[cell->vertex(g)->info().id()].pos;;
+ }
+ }
+ AS[coord[0]]=BS[coord[0]] = Wall_coordinate[0];
+
+ //first pyramid with triangular base (A,B,BS)
+ Real Vol1=0.5* ( ( A-BS ).cross ( B-BS ) ) [coord[1]]* ( 0.333333333* ( 2*B[coord[1]]+A[coord[1]] )-Wall_coordinate[1] );
+ //second pyramid with triangular base (A,AS,BS)
+ Real Vol2=0.5* ( ( AS-BS ).cross ( A-BS ) ) [coord[1]]* ( 0.333333333* ( B[coord[1]]+2*A[coord[1]] )-Wall_coordinate[1] );
+ return abs ( Vol1+Vol2 );
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+template<class Cellhandle>
+Real TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::volumeCellTripleFictious ( Cellhandle cell )
+{
+ Vector3r A;
+
+ int b[3];
+ int coord[3];
+ Real Wall_coordinate[3];
+ int j=0;
+ cell->info().volumeSign=1;
+
+ for ( int g=0;g<4;g++ ) {
+ if ( cell->vertex ( g )->info().isFictious ) {
+ b[j] = cell->vertex ( g )->info().id();
+ coord[j]=solver->boundary ( b[j] ).coordinate;
+ const shared_ptr<Body>& wll = Body::byId ( b[j] , scene );
+ if ( !solver->boundary ( b[j] ).useMaxMin ) Wall_coordinate[j] = wll->state->pos[coord[j]] + ( solver->boundary ( b[j] ).normal[coord[j]] ) *wallThickness/2.;
+ else Wall_coordinate[j] = solver->boundary ( b[j] ).p[coord[j]];
+ j++;
+ } else {
+ const shared_ptr<Body>& sph = Body::byId ( cell->vertex ( g )->info().id(), scene );
+ A= ( sph->state->pos );
+ }
+ }
+ Real Volume = ( A[coord[0]]-Wall_coordinate[0] ) * ( A[coord[1]]-Wall_coordinate[1] ) * ( A[coord[2]]-Wall_coordinate[2] );
+ return abs ( Volume );
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+template<class Cellhandle>
+Real TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::volumeCell ( Cellhandle cell )
+{
+ static const Real inv6 = 1/6.;
+ const Vector3r& p0 = positionBufferCurrent[cell->vertex ( 0 )->info().id()].pos;
+ const Vector3r& p1 = positionBufferCurrent[cell->vertex ( 1 )->info().id()].pos;
+ const Vector3r& p2 = positionBufferCurrent[cell->vertex ( 2 )->info().id()].pos;
+ const Vector3r& p3 = positionBufferCurrent[cell->vertex ( 3 )->info().id()].pos;
+ Real volume = inv6 * ((p0-p1).cross(p0-p2)).dot(p0-p3);
+ if ( ! ( cell->info().volumeSign ) ) cell->info().volumeSign= ( volume>0 ) ?1:-1;
+ return volume;
+}
+template< class _CellInfo, class _VertexInfo, class _Tesselation, class solverT >
+void TemplateFlowEngine<_CellInfo,_VertexInfo,_Tesselation,solverT>::computeViscousForces ( Solver& flow )
+{
+ if (normalLubrication || shearLubrication || viscousShear){
+ if ( debug ) cout << "Application of viscous forces" << endl;
+ if ( debug ) cout << "Number of edges = " << flow.edgeIds.size() << endl;
+ for ( unsigned int k=0; k<flow.shearLubricationForces.size(); k++ ) flow.shearLubricationForces[k]=Vector3r::Zero();
+ for ( unsigned int k=0; k<flow.shearLubricationTorques.size(); k++ ) flow.shearLubricationTorques[k]=Vector3r::Zero();
+ for ( unsigned int k=0; k<flow.pumpLubricationTorques.size(); k++ ) flow.pumpLubricationTorques[k]=Vector3r::Zero();
+ for ( unsigned int k=0; k<flow.twistLubricationTorques.size(); k++ ) flow.twistLubricationTorques[k]=Vector3r::Zero();
+ for ( unsigned int k=0; k<flow.shearLubricationBodyStress.size(); k++) flow.shearLubricationBodyStress[k]=Matrix3r::Zero();
+ for ( unsigned int k=0; k<flow.normalLubricationForce.size(); k++ ) flow.normalLubricationForce[k]=Vector3r::Zero();
+ for ( unsigned int k=0; k<flow.normalLubricationBodyStress.size(); k++) flow.normalLubricationBodyStress[k]=Matrix3r::Zero();
+
+ typedef typename Solver::Tesselation Tesselation;
+ const Tesselation& Tes = flow.T[flow.currentTes];
+ flow.deltaShearVel.clear(); flow.normalV.clear(); flow.deltaNormVel.clear(); flow.surfaceDistance.clear(); flow.onlySpheresInteractions.clear(); flow.normalStressInteraction.clear(); flow.shearStressInteraction.clear();
+
+
+ for ( int i=0; i< ( int ) flow.edgeIds.size(); i++ ) {
+ 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;
+ const shared_ptr<Body>& sph1 = Body::byId ( id1, scene );
+ const shared_ptr<Body>& sph2 = Body::byId ( id2, scene );
+ Sphere* s1=YADE_CAST<Sphere*> ( sph1->shape.get() );
+ Sphere* s2=YADE_CAST<Sphere*> ( sph2->shape.get() );
+ const Real& r1 = s1->radius;
+ const Real& r2 = s2->radius;
+ Vector3r deltaV; Real deltaNormV; Vector3r deltaShearV;
+ Vector3r O1O2Vector; Real O1O2; Vector3r normal; Real surfaceDist; Vector3r O1CVector; Vector3r O2CVector;Real meanRad ;Real Rh; Vector3r deltaAngVel; Vector3r deltaShearAngVel;
+ 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(vi2.ghostShift()) - sph1->state->pos - makeVector3r(vi1.ghostShift());
+ O1O2 = O1O2Vector.norm();
+ normal= (O1O2Vector/O1O2);
+ surfaceDist = O1O2 - r2 - r1;
+ O1CVector = (O1O2/2. + (pow(r1,2) - pow(r2,2)) / (2.*O1O2))*normal;
+ O2CVector = -(O1O2Vector - O1CVector);
+ meanRad = (r2 + r1)/2.;
+ Rh = (r1 < r2)? surfaceDist + 0.45 * r1 : surfaceDist + 0.45 * r2;
+ deltaV = (sph2->state->vel + sph2->state->angVel.cross(-r2 * normal)) - (sph1->state->vel+ sph1->state->angVel.cross(r1 * normal));
+ angVel1 = sph1->state->angVel;
+ angVel2 = sph2->state->angVel;
+ deltaAngVel = sph2->state->angVel - sph1->state->angVel;
+
+ } else {
+ if ( hasFictious==1 ) {//for the fictious sphere, use velocity of the boundary, not of the body
+ bool v1fictious = Tes.vertex ( id1 )->info().isFictious;
+ int bnd = v1fictious? id1 : id2;
+ int coord = flow.boundary(bnd).coordinate;
+ O1O2 = v1fictious ? abs((sph2->state->pos + makeVector3r(Tes.vertex(id2)->info().ghostShift()))[coord] - flow.boundary(bnd).p[coord]) : abs((sph1->state->pos + makeVector3r(Tes.vertex(id1)->info().ghostShift()))[coord] - flow.boundary(bnd).p[coord]);
+ if(v1fictious)
+ normal = makeVector3r(flow.boundary(id1).normal);
+ else
+ normal = -makeVector3r(flow.boundary(id2).normal);
+ O1O2Vector = O1O2 * normal;
+ meanRad = v1fictious ? r2:r1;
+ surfaceDist = O1O2 - meanRad;
+ if (v1fictious){
+ O1CVector = Vector3r::Zero();
+ O2CVector = - O1O2Vector;}
+ else{
+ O1CVector = O1O2Vector;
+ O2CVector = Vector3r::Zero();}
+
+ Rh = surfaceDist + 0.45 * meanRad;
+ Vector3r v1 = ( Tes.vertex ( id1 )->info().isFictious ) ? flow.boundary ( id1 ).velocity:sph1->state->vel + sph1->state->angVel.cross(r1 * normal);
+ Vector3r v2 = ( Tes.vertex ( id2 )->info().isFictious ) ? flow.boundary ( id2 ).velocity:sph2->state->vel + sph2->state->angVel.cross(-r2 * (normal));
+ deltaV = v2-v1;
+ angVel1 = ( Tes.vertex ( id1 )->info().isFictious ) ? Vector3r::Zero() : sph1->state->angVel;
+ angVel2 = ( Tes.vertex ( id2 )->info().isFictious ) ? Vector3r::Zero() : sph2->state->angVel;
+ deltaAngVel = angVel2 - angVel1;
+ }
+ }
+ deltaShearV = deltaV - ( normal.dot ( deltaV ) ) *normal;
+ deltaShearAngVel = deltaAngVel - ( normal.dot ( deltaAngVel ) ) *normal;
+ flow.deltaShearVel.push_back(deltaShearV);
+ flow.normalV.push_back(normal);
+ flow.surfaceDistance.push_back(max(surfaceDist, 0.) + eps*meanRad);
+
+ /// Compute the shear Lubrication force and torque on each particle
+
+ if (shearLubrication)
+ shearLubF = flow.computeShearLubricationForce(deltaShearV,surfaceDist,i,eps,O1O2,meanRad);
+ else if (viscousShear)
+ shearLubF = flow.computeViscousShearForce ( deltaShearV, i , Rh);
+
+ if (viscousShear || shearLubrication){
+
+ flow.shearLubricationForces[id1]+=shearLubF;
+ flow.shearLubricationForces[id2]+=(-shearLubF);
+ flow.shearLubricationTorques[id1]+=O1CVector.cross(shearLubF);
+ flow.shearLubricationTorques[id2]+=O2CVector.cross(-shearLubF);
+
+ /// Compute the pump Lubrication torque on each particle
+
+ if (pumpTorque){
+ pumpT = flow.computePumpTorque(deltaShearAngVel, surfaceDist, i, eps, meanRad );
+ flow.pumpLubricationTorques[id1]+=(-pumpT);
+ flow.pumpLubricationTorques[id2]+=pumpT;}
+
+ /// Compute the twist Lubrication torque on each particle
+
+ if (twistTorque){
+ deltaAngNormVel = (normal.dot(deltaAngVel))*normal ;
+ twistT = flow.computeTwistTorque(deltaAngNormVel, surfaceDist, i, eps, meanRad );
+ flow.twistLubricationTorques[id1]+=(-twistT);
+ flow.twistLubricationTorques[id2]+=twistT;
+ }
+ }
+ /// Compute the viscous shear stress on each particle
+
+ if (viscousShearBodyStress){
+ flow.shearLubricationBodyStress[id1] += shearLubF * O1CVector.transpose()/ (4.0/3.0 *3.14* pow(r1,3));
+ flow.shearLubricationBodyStress[id2] += (-shearLubF) * O2CVector.transpose()/ (4.0/3.0 *3.14* pow(r2,3));
+ flow.shearStressInteraction.push_back(shearLubF * O1O2Vector.transpose()/(4.0/3.0 *3.14* pow(r1,3)));
+ }
+
+ /// Compute the normal lubrication force applied on each particle
+
+ if (normalLubrication){
+ deltaNormV = normal.dot(deltaV);
+ flow.deltaNormVel.push_back(deltaNormV * normal);
+ normaLubF = flow.computeNormalLubricationForce (deltaNormV, surfaceDist, i,eps,stiffness,scene->dt,meanRad)*normal;
+ flow.normalLubricationForce[id1]+=normaLubF;
+ flow.normalLubricationForce[id2]+=(-normaLubF);
+
+ /// Compute the normal lubrication stress on each particle
+
+ if (viscousNormalBodyStress){
+ flow.normalLubricationBodyStress[id1] += normaLubF * O1CVector.transpose()/ (4.0/3.0 *3.14* pow(r1,3));
+ flow.normalLubricationBodyStress[id2] += (-normaLubF) *O2CVector.transpose() / (4.0/3.0 *3.14* pow(r2,3));
+ flow.normalStressInteraction.push_back(normaLubF * O1O2Vector.transpose()/(4.0/3.0 *3.14* pow(r1,3)));
+ }
+ }
+
+ if (!hasFictious)
+ flow.onlySpheresInteractions.push_back(i);
+
+ }
+ }
+}
+
+#endif //FLOW_ENGINE
+
+#endif /* YADE_CGAL */
+
=== added file 'pkg/pfv/PeriodicFlowEngine.cpp'
--- pkg/pfv/PeriodicFlowEngine.cpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/PeriodicFlowEngine.cpp 2014-04-17 15:10:23 +0000
@@ -0,0 +1,550 @@
+/*************************************************************************
+* Copyright (C) 2009 by Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> *
+* Copyright (C) 2012 by Donia Marzougui <donia.marzougui@xxxxxxxxxxxxxxx>*
+* *
+* 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 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 <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();
+CVector PeriodicCellInfo::gradP=CVector();
+
+CREATE_LOGGER ( PeriodicFlowEngine );
+
+PeriodicFlowEngine::~PeriodicFlowEngine(){}
+
+void PeriodicFlowEngine:: action()
+{
+ if ( !isActivated ) return;
+ timingDeltas->start();
+ preparePShifts();
+ setPositionsBuffer(true);
+ if (first) {
+ if (multithread) setPositionsBuffer(false);
+ cachedCell= Cell(*(scene->cell));
+ buildTriangulation(pZero,*solver);
+ if (solver->errorCode>0) {LOG_INFO("triangulation error, pausing"); Omega::instance().pause(); return;}
+ initializeVolumes(*solver); backgroundSolver=solver; backgroundCompleted=true;}
+// if ( first ) {buildTriangulation ( pZero ); updateTriangulation = false; initializeVolumes();}
+
+ timingDeltas->checkpoint("Triangulating");
+ updateVolumes (*solver);
+ epsVolCumulative += epsVolMax;
+ retriangulationLastIter++;
+ if (!updateTriangulation) updateTriangulation = // If not already set true by another function of by the user, check conditions
+ (defTolerance>0 && epsVolCumulative > defTolerance) || retriangulationLastIter>meshUpdateInterval;
+
+ timingDeltas->checkpoint("Update_Volumes");
+
+ ///compute flow and and forces here
+ if (pressureForce){
+ solver->gaussSeidel(scene->dt);
+ timingDeltas->checkpoint("Gauss-Seidel");
+ solver->computeFacetForcesWithCache();}
+ timingDeltas->checkpoint("compute_Pressure_Forces");
+
+ ///compute vicscous forces
+ scene->forces.sync();
+ computeViscousForces(*solver);
+ timingDeltas->checkpoint("compute_Viscous_Forces");
+ Vector3r force;
+ Vector3r torque;
+ const Tesselation& Tes = solver->T[solver->currentTes];
+ for (int id=0; id<=Tes.maxId; id++){
+ assert (Tes.vertexHandles[id] != NULL);
+ const Tesselation::VertexInfo& v_info = Tes.vertexHandles[id]->info();
+ force =(pressureForce) ? Vector3r ( ( v_info.forces ) [0],v_info.forces[1],v_info.forces[2] ) : Vector3r(0,0,0);
+ torque = Vector3r(0,0,0);
+ if (shearLubrication || viscousShear){
+ force = force +solver->shearLubricationForces[v_info.id()];
+ torque = torque +solver->shearLubricationTorques[v_info.id()];
+ if (pumpTorque)
+ torque = torque +solver->pumpLubricationTorques[v_info.id()];
+ if (twistTorque)
+ torque = torque +solver->twistLubricationTorques[v_info.id()];
+ }
+
+ if (normalLubrication)
+ force = force + solver->normalLubricationForce[v_info.id()];
+ scene->forces.addForce ( v_info.id(), force);
+ scene->forces.addTorque ( v_info.id(), torque);
+ }
+ ///End Compute flow and forces
+ timingDeltas->checkpoint("Applying Forces");
+ if (multithread && !first) {
+ while (updateTriangulation && !backgroundCompleted) { /*cout<<"sleeping..."<<sleeping++<<endl;*/ boost::this_thread::sleep(boost::posix_time::microseconds(1000));}
+ if (updateTriangulation || ellapsedIter>(0.5*meshUpdateInterval)) {
+ if (useSolver==0) LOG_ERROR("background calculations not available for Gauss-Seidel");
+ if (fluidBulkModulus>0 || doInterpolate) solver->interpolate (solver->T[solver->currentTes], backgroundSolver->T[backgroundSolver->currentTes]);
+ solver=backgroundSolver;
+ backgroundSolver = shared_ptr<FlowSolver> (new FlowSolver);
+ //Copy imposed pressures/flow from the old solver
+ backgroundSolver->imposedP = vector<pair<CGT::Point,Real> >(solver->imposedP);
+ backgroundSolver->imposedF = vector<pair<CGT::Point,Real> >(solver->imposedF);
+ setPositionsBuffer(false);
+ cachedCell= Cell(*(scene->cell));
+ backgroundCompleted=false;
+ retriangulationLastIter=ellapsedIter;
+ ellapsedIter=0;
+ epsVolCumulative=0;
+ boost::thread workerThread(&PeriodicFlowEngine::backgroundAction,this);
+ workerThread.detach();
+ initializeVolumes(*solver);
+ computeViscousForces(*solver);
+ }
+ else if (debug && !first) {
+ if (debug && !backgroundCompleted) cerr<<"still computing solver in the background"<<endl;
+ ellapsedIter++;}
+ } else {
+ if (updateTriangulation && !first) {
+ cachedCell= Cell(*(scene->cell));
+ buildTriangulation (pZero, *solver);
+ initializeVolumes(*solver);
+ computeViscousForces(*solver);
+ updateTriangulation = false;
+ epsVolCumulative=0;
+ retriangulationLastIter=0;
+ ReTrg++;}
+ }
+ first=false;
+ timingDeltas->checkpoint("Ending");
+}
+
+
+// void PeriodicFlowEngine::backgroundAction()
+// {
+// if (useSolver<1) {LOG_ERROR("background calculations not available for Gauss-Seidel"); return;}
+// buildTriangulation (pZero,*backgroundSolver);
+// //FIXME: GS is computing too much, we need only matrix factorization in fact
+// backgroundSolver->gaussSeidel(scene->dt);
+// backgroundSolver->computeFacetForcesWithCache(/*onlyCache?*/ true);
+// // boost::this_thread::sleep(boost::posix_time::seconds(10));
+// backgroundCompleted = true;
+// }
+
+void PeriodicFlowEngine::triangulate( FlowSolver& flow )
+{
+ Tesselation& Tes = flow.T[flow.currentTes];
+ vector<posData>& buffer = multithread ? positionBufferParallel : positionBufferCurrent;
+ FOREACH ( const posData& b, buffer ) {
+ if ( !b.exists || !b.isSphere || b.id==ignoredBody) continue;
+ Vector3i period; Vector3r wpos;
+ // FIXME: use "sheared" variant if the cell is sheared
+ wpos=cachedCell.wrapPt ( b.pos,period );
+ const Body::id_t& id = b.id;
+ const Real& rad = b.radius;
+ const Real& x = wpos[0];
+ const Real& y = wpos[1];
+ const Real& z = wpos[2];
+ VertexHandle vh0=Tes.insert ( x, y, z, rad, id );
+// VertexHandle vh0=Tes.insert ( b.pos[0], b.pos[1], b.pos[2], b.radius, b.id );
+ if (vh0==NULL) {
+ flow.errorCode = 2;
+ LOG_ERROR("Vh NULL in PeriodicFlowEngine::triangulate(), check input data"); continue;}
+ for ( int k=0;k<3;k++ ) vh0->info().period[k]=-period[k];
+ const Vector3r cellSize ( cachedCell.getSize() );
+ //FIXME: if hasShear, comment in
+// wpos=scene->cell->unshearPt ( wpos );
+ // traverse all periodic cells around the body, to see if any of them touches
+ Vector3r halfSize= ( rad+duplicateThreshold ) *Vector3r ( 1,1,1 );
+ Vector3r pmin,pmax;
+ Vector3i i;
+ for ( i[0]=-1; i[0]<=1; i[0]++ )
+ for ( i[1]=-1;i[1]<=1; i[1]++ )
+ for ( i[2]=-1; i[2]<=1; i[2]++ ) {
+ if ( i[0]!=0 || i[1]!=0 || i[2]!=0 ) { // middle; already rendered above
+ Vector3r pos2=wpos+Vector3r ( cellSize[0]*i[0],cellSize[1]*i[1],cellSize[2]*i[2] ); // shift, but without shear!
+ pmin=pos2-halfSize;
+ pmax=pos2+halfSize;
+ if ( (pmin[0]<=cellSize[0]) && (pmax[0]>=0) && (pmin[1]<=cellSize[1]) && (pmax[1]>=0) && (pmin[2]<=cellSize[2]) && (pmax[2]>=0) ) {
+ //with shear:
+ //Vector3r pt=scene->cell->shearPt ( pos2 );
+ //without shear:
+ const Vector3r& pt= pos2;
+ VertexHandle vh=Tes.insert ( pt[0],pt[1],pt[2],rad,id,false,id );
+ for ( int k=0;k<3;k++ ) vh->info().period[k]=i[k]-period[k];}}
+ }
+ //re-assign the original vertex pointer since duplicates may have overwrite it
+ Tes.vertexHandles[id]=vh0;
+ }
+ Tes.redirected=true;//By inserting one-by-one, we already redirected
+ flow.shearLubricationForces.resize ( Tes.maxId+1 );
+ flow.shearLubricationTorques.resize ( Tes.maxId+1 );
+ flow.pumpLubricationTorques.resize ( Tes.maxId+1 );
+ flow.twistLubricationTorques.resize ( Tes.maxId+1 );
+ flow.shearLubricationBodyStress.resize ( Tes.maxId+1 );
+ flow.normalLubricationForce.resize ( Tes.maxId+1 );
+ flow.normalLubricationBodyStress.resize ( Tes.maxId+1 );
+}
+
+
+Real PeriodicFlowEngine::volumeCell ( CellHandle cell )
+{
+ static const Real inv6 = 1/6.;
+ const Vector3r p0 = positionBufferCurrent[cell->vertex(0)->info().id()].pos + makeVector3r(cell->vertex(0)->info().ghostShift());
+ const Vector3r p1 = positionBufferCurrent[cell->vertex(1)->info().id()].pos + makeVector3r(cell->vertex(1)->info().ghostShift());
+ const Vector3r p2 = positionBufferCurrent[cell->vertex(2)->info().id()].pos + makeVector3r(cell->vertex(2)->info().ghostShift());
+ const Vector3r p3 = positionBufferCurrent[cell->vertex(3)->info().id()].pos + makeVector3r(cell->vertex(3)->info().ghostShift());
+ Real volume = inv6*((p0-p1).cross(p0-p2)).dot(p0-p3);
+ if ( ! ( cell->info().volumeSign ) ) cell->info().volumeSign= ( volume>0 ) ?1:-1;
+ return volume;
+}
+
+Real PeriodicFlowEngine::volumeCellSingleFictious ( CellHandle cell )
+{
+ Vector3r V[3];
+ int b=0;
+ int w=0;
+ cell->info().volumeSign=1;
+ Real Wall_coordinate=0;
+
+ for ( int y=0;y<4;y++ ) {
+ if ( ! ( cell->vertex ( y )->info().isFictious ) ) {
+ const shared_ptr<Body>& sph = Body::byId ( cell->vertex ( y )->info().id(), scene );
+ V[w]=sph->state->pos+ makeVector3r ( cell->vertex ( y )->info().ghostShift() );
+ w++;
+ } else {
+ b = cell->vertex ( y )->info().id();
+ const shared_ptr<Body>& wll = Body::byId ( b,scene );
+ if ( !solver->boundary ( b ).useMaxMin ) Wall_coordinate = wll->state->pos[solver->boundary ( b ).coordinate]+ ( solver->boundary ( b ).normal[solver->boundary ( b ).coordinate] ) *wallThickness/2.;
+ else Wall_coordinate = solver->boundary ( b ).p[solver->boundary ( b ).coordinate];
+ }
+ }
+ Real Volume = 0.5* ( ( V[0]-V[1] ).cross ( V[0]-V[2] ) ) [solver->boundary ( b ).coordinate] * ( 0.33333333333* ( V[0][solver->boundary ( b ).coordinate]+ V[1][solver->boundary ( b ).coordinate]+ V[2][solver->boundary ( b ).coordinate] ) - Wall_coordinate );
+ return abs ( Volume );
+}
+
+
+void PeriodicFlowEngine::locateCell ( CellHandle baseCell, unsigned int& index, int& baseIndex, FlowSolver& flow, unsigned int count)
+{
+ if (count>10) {
+ LOG_ERROR("More than 10 attempts to locate a cell, duplicateThreshold may be too small, resulting in periodicity inconsistencies.");
+ flow.errorCode=1; return;
+ }
+ PeriFlowTesselation::CellInfo& baseInfo = baseCell->info();
+ //already located, return FIXME: is inline working correctly? else move this test outside the function, just before the calls
+ if ( baseInfo.index>0 || baseInfo.isGhost ) return;
+ RTriangulation& Tri = flow.T[flow.currentTes].Triangulation();
+ Vector3r center ( 0,0,0 );
+ Vector3i period;
+
+ if (baseCell->info().fictious()==0)
+ for ( int k=0;k<4;k++ ) center+= 0.25*makeVector3r (baseCell->vertex(k)->point());
+ else {
+
+ Real boundPos=0; int coord=0;
+ for ( int k=0;k<4;k++ ) {
+ if ( !baseCell->vertex ( k )->info().isFictious ) center+= 0.3333333333*makeVector3r ( baseCell->vertex ( k )->point() );
+ else {
+ coord=flow.boundary ( baseCell->vertex ( k )->info().id() ).coordinate;
+ boundPos=flow.boundary ( baseCell->vertex ( k )->info().id() ).p[coord];}
+ }
+ center[coord]=boundPos;
+ }
+ Vector3r wdCenter= cachedCell.wrapPt ( center,period );
+ if ( period[0]!=0 || period[1]!=0 || period[2]!=0 ) {
+ if ( baseCell->info().index>0 ) {
+ cout<<"indexed cell is found ghost!"<<baseInfo.index <<endl;
+ baseInfo.isGhost=false;
+ return;
+ }
+ CellHandle ch= Tri.locate ( CGT::Point ( wdCenter[0],wdCenter[1],wdCenter[2] )
+// ,/*hint*/ v0
+ );
+ baseInfo.period[0]=period[0];
+ baseInfo.period[1]=period[1];
+ baseInfo.period[2]=period[2];
+ //call recursively, since the returned cell could be also a ghost (especially if baseCell is a non-periodic type from the external contour
+ locateCell ( ch,index,baseIndex,flow,++count );
+ if ( ch==baseCell ) cerr<<"WTF!!"<<endl;
+ //check consistency
+ bool checkC=false;
+ for (int kk=0; kk<4;kk++) if ((!baseCell->vertex(kk)->info().isGhost) && ((!baseCell->vertex(kk)->info().isFictious))) checkC = true;
+ if (checkC) {
+ bool checkV=true;
+ for (int kk=0; kk<4;kk++) {
+ checkV=false;
+ for (int jj=0; jj<4;jj++)
+ if (baseCell->vertex(kk)->info().id() == ch->vertex(jj)->info().id()) checkV = true;
+ if (!checkV) {cerr <<"periodicity is broken"<<endl;
+ for (int jj=0; jj<4;jj++) cerr<<baseCell->vertex(jj)->info().id()<<" ";
+ cerr<<" vs. ";
+ for (int jj=0; jj<4;jj++) cerr<<ch->vertex(jj)->info().id()<<" ";
+ cerr<<endl;}
+ }
+ } else {
+// bool checkV=true;
+// for (int kk=0; kk<4;kk++) {
+// checkV=false;
+// for (int jj=0; jj<4;jj++)
+// if (baseCell->vertex(kk)->info().id() == ch->vertex(jj)->info().id()) checkV = true;
+// if (!checkV) {cerr <<"periodicity is broken (that's ok probably)"<<endl;
+// for (int jj=0; jj<4;jj++) cerr<<baseCell->vertex(jj)->info().id()<<" ";
+// cerr<<" vs. ";
+// for (int jj=0; jj<4;jj++) cerr<<ch->vertex(jj)->info().id()<<" ";
+// cerr<<endl;}
+// }
+ }
+
+ baseInfo.isGhost=true;
+ baseInfo._pression=& ( ch->info().p() );
+ baseInfo.index=ch->info().index;
+ baseInfo.baseIndex=ch->info().baseIndex;
+ baseInfo.Pcondition=ch->info().Pcondition;
+ } else {
+ baseInfo.isGhost=false;
+ //index is 1-based, if it is zero it is not initialized, we define it here
+ if ( baseInfo.baseIndex<0 ){
+ baseInfo.baseIndex=++baseIndex;
+ if (!baseInfo.Pcondition) baseInfo.index=++index;}
+ }
+}
+
+Vector3r PeriodicFlowEngine::meanVelocity()
+{
+ solver->averageRelativeCellVelocity();
+ Vector3r meanVel ( 0,0,0 );
+ Real volume=0;
+ FiniteCellsIterator cell_end = solver->T[solver->currentTes].Triangulation().finite_cells_end();
+ for ( FiniteCellsIterator cell = solver->T[solver->currentTes].Triangulation().finite_cells_begin(); cell != cell_end; cell++ ) {
+ //We could also define velocity using cell's center
+// if ( !cell->info().isReal() ) continue;
+ if ( cell->info().isGhost ) continue;
+ for ( int i=0;i<3;i++ )
+ meanVel[i]=meanVel[i]+ ( ( cell->info().averageVelocity() ) [i] * abs ( cell->info().volume() ) );
+ volume+=abs ( cell->info().volume() );
+ }
+ return ( meanVel/volume );
+}
+
+void PeriodicFlowEngine::updateVolumes (FlowSolver& flow)
+{
+ if ( debug ) cout << "Updating volumes.............." << endl;
+ Real invDeltaT = 1/scene->dt;
+ double newVol, dVol;
+ epsVolMax=0;
+ Real totVol=0;
+ Real totDVol=0;
+ Real totVol0=0;
+ Real totVol1=0;
+
+ FOREACH(CellHandle& cell, flow.T[flow.currentTes].cellHandles){
+ switch ( cell->info().fictious() ) {
+ case ( 1 ) :
+ newVol = volumeCellSingleFictious ( cell );
+ totVol1+=newVol;
+ break;
+ case ( 0 ) :
+ newVol = volumeCell ( cell );
+ totVol0+=newVol;
+ break;
+ default:
+ newVol = 0;
+ break;
+ }
+ totVol+=newVol;
+ dVol=cell->info().volumeSign * ( newVol - cell->info().volume() );
+ totDVol+=dVol;
+ epsVolMax = max ( epsVolMax, abs ( dVol/newVol ) );
+ cell->info().dv() = dVol * invDeltaT;
+ cell->info().volume() = newVol;
+ }
+ if ( debug ) cout << "Updated volumes, total =" <<totVol<<", dVol="<<totDVol<<" "<< totVol0<<" "<< totVol1<<endl;
+}
+
+
+void PeriodicFlowEngine::initializeVolumes (FlowSolver& flow)
+{
+ FiniteVerticesIterator vertices_end = flow.T[flow.currentTes].Triangulation().finite_vertices_end();
+ CGT::CVector Zero ( 0,0,0 );
+ for ( FiniteVerticesIterator V_it = flow.T[flow.currentTes].Triangulation().finite_vertices_begin(); V_it!= vertices_end; V_it++ ) V_it->info().forces=Zero;
+
+ FOREACH(CellHandle& cell, flow.T[flow.currentTes].cellHandles){
+ switch ( cell->info().fictious() )
+ {
+ case ( 0 ) : cell->info().volume() = volumeCell ( cell ); break;
+ case ( 1 ) : cell->info().volume() = volumeCellSingleFictious ( cell ); break;
+ default: cell->info().volume() = 0; break;
+ }
+ //FIXME: the void volume is negative sometimes, hence crashing...
+ if (flow.fluidBulkModulus>0) { cell->info().invVoidVolume() = 1. / (max(0.1*cell->info().volume(),abs(cell->info().volume()) - flow.volumeSolidPore(cell)) ); }
+ }
+ if ( debug ) cout << "Volumes initialised." << endl;
+}
+
+void PeriodicFlowEngine::buildTriangulation ( double pZero, FlowSolver& flow)
+{
+ 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;
+ triangulate (flow);
+ if ( debug ) cout << endl << "Tesselating------" << endl << endl;
+ flow.T[flow.currentTes].compute();
+ flow.defineFictiousCells();
+
+ //FIXME: this is already done in addBoundary(?)
+ boundaryConditions ( flow );
+ if ( debug ) cout << endl << "boundaryConditions------" << endl << endl;
+ flow.initializePressure ( pZero );
+ if ( debug ) cout << endl << "initializePressure------" << endl << endl;
+ // Define the ghost cells and add indexes to the cells inside the period (the ones that will contain the pressure unknowns)
+ //This must be done after boundary conditions and initialize pressure, else the indexes are not good (not accounting imposedP): FIXME
+ unsigned int index=0;
+ int baseIndex=-1;
+ FlowSolver::Tesselation& Tes = flow.T[flow.currentTes];
+ Tes.cellHandles.resize(Tes.Triangulation().number_of_finite_cells());
+ const FiniteCellsIterator cellend=Tes.Triangulation().finite_cells_end();
+ for ( FiniteCellsIterator cell=Tes.Triangulation().finite_cells_begin(); cell!=cellend; cell++ ){
+ locateCell ( cell,index,baseIndex,flow );
+ if (flow.errorCode>0) return;
+ //Fill this vector than can be later used to speedup loops
+ if (!cell->info().isGhost) Tes.cellHandles[cell->info().baseIndex]=cell;
+ }
+ Tes.cellHandles.resize(baseIndex+1);
+
+ if ( debug ) cout << endl << "locateCell------" << endl << endl;
+ flow.computePermeability ( );
+ porosity = flow.vPoralPorosity/flow.vTotalPorosity;
+ flow.tolerance=tolerance;flow.relax=relax;
+
+ flow.displayStatistics ();
+ //FIXME: check interpolate() for the periodic case, at least use the mean pressure from previous step.
+ if ( !first && !multithread && (useSolver==0 || fluidBulkModulus>0 || doInterpolate)) flow.interpolate ( flow.T[!flow.currentTes], Tes );
+// if ( !first && (useSolver==0 || fluidBulkModulus>0)) flow.interpolate ( flow.T[!flow.currentTes], flow.T[flow.currentTes] );
+
+ if ( waveAction ) flow.applySinusoidalPressure ( Tes.Triangulation(), sineMagnitude, sineAverage, 30 );
+
+ if (normalLubrication || shearLubrication || viscousShear) flow.computeEdgesSurfaces();
+ if ( debug ) cout << endl << "end buildTri------" << endl << endl;
+}
+
+void PeriodicFlowEngine::preparePShifts()
+{
+ CellInfo::gradP = makeCgVect ( gradP );
+ CellInfo::hSize[0] = makeCgVect ( scene->cell->hSize.col ( 0 ) );
+ CellInfo::hSize[1] = makeCgVect ( scene->cell->hSize.col ( 1 ) );
+ CellInfo::hSize[2] = makeCgVect ( scene->cell->hSize.col ( 2 ) );
+ CellInfo::deltaP=CGT::CVector (
+ CellInfo::hSize[0]*CellInfo::gradP,
+ CellInfo::hSize[1]*CellInfo::gradP,
+ CellInfo::hSize[2]*CellInfo::gradP );
+}
+
+
+YADE_PLUGIN((PeriodicFlowEngine));
+#endif //FLOW_ENGINE
+
+#endif /* YADE_CGAL */
\ No newline at end of file
=== added file 'pkg/pfv/SoluteFlowEngine.cpp'
--- pkg/pfv/SoluteFlowEngine.cpp 1970-01-01 00:00:00 +0000
+++ pkg/pfv/SoluteFlowEngine.cpp 2014-04-11 08:07:46 +0000
@@ -0,0 +1,197 @@
+/*************************************************************************
+* Copyright (C) 2013 by T. Sweijen (T.sweijen@xxxxx) *
+* *
+* 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 YADE_CGAL
+#ifdef FLOW_ENGINE
+
+// #define SOLUTE_FLOW
+#ifdef SOLUTE_FLOW
+
+#define TEMPLATE_FLOW_NAME SoluteFlowEngineT
+#include <yade/pkg/pfv/FlowEngine.hpp>
+
+#include <Eigen/Sparse>
+
+class SoluteCellInfo : public FlowCellInfo
+{
+ public:
+ Real solute_concentration;
+ SoluteCellInfo (void) : FlowCellInfo() {solute_concentration=0;}
+ inline Real& solute (void) {return solute_concentration;}
+ inline const Real& solute (void) const {return solute_concentration;}
+ inline void getInfo (const SoluteCellInfo& otherCellInfo) {FlowCellInfo::getInfo(otherCellInfo); solute()=otherCellInfo.solute();}
+};
+
+typedef TemplateFlowEngine<SoluteCellInfo,FlowVertexInfo> SoluteFlowEngineT;
+REGISTER_SERIALIZABLE(SoluteFlowEngineT);
+YADE_PLUGIN((SoluteFlowEngineT));
+
+class SoluteFlowEngine : public SoluteFlowEngineT
+{
+ public :
+ void initializeSoluteTransport();
+ void soluteTransport (double deltatime, double D);
+ double getConcentration(unsigned int id){return solver->T[solver->currentTes].cellHandles[id]->info().solute(); }
+ double insertConcentration(unsigned int id,double conc){
+ solver->T[solver->currentTes].cellHandles[id]->info().solute() = conc;
+ return conc;}
+ void soluteBC(unsigned int bc_id1, unsigned int bc_id2, double bc_concentration1, double bc_concentration2,unsigned int s);
+ double getConcentrationPlane (double Yobs,double Yr, int xyz);
+ ///Elaborate the description as you wish
+ YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(SoluteFlowEngine,SoluteFlowEngineT,"A variant of :yref:`FlowEngine` with solute transport).",
+ ///No additional variable yet, else input here
+// ((Vector3r, gradP, Vector3r::Zero(),,"Macroscopic pressure gradient"))
+ ,,,
+ .def("soluteTransport",&SoluteFlowEngine::soluteTransport,(python::arg("deltatime"),python::arg("D")),"Solute transport (advection and diffusion) engine for diffusion use a diffusion coefficient (D) other than 0.")
+ .def("getConcentration",&SoluteFlowEngine::getConcentration,(python::arg("id")),"get concentration of pore with ID")
+ .def("insertConcentration",&SoluteFlowEngine::insertConcentration,(python::arg("id"),python::arg("conc")),"Insert Concentration (ID, Concentration)")
+ .def("solute_BC",&SoluteFlowEngine::soluteBC,(python::arg("bc_id1"),python::arg("bc_id2"),python::arg("bc_concentration1"),python::arg("bc_concentration2"),python::arg("s")),"Enter X,Y,Z for concentration observation'.")
+ //I guess there is getConcentrationPlane missing here, but it is not on github
+ )
+};
+REGISTER_SERIALIZABLE(SoluteFlowEngine);
+
+
+// PeriodicFlowEngine::~PeriodicFlowEngine(){}
+
+void SoluteFlowEngine::initializeSoluteTransport ()
+{
+ //Prepare a list with concentrations in range of 0,nCells. Or resets the list of concentrations to 0
+// typedef typename Solver::element_type Flow;
+// typedef typename Flow::Finite_vertices_iterator Finite_vertices_iterator;
+// typedef typename Solver::element_type Flow;
+
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles)
+ {
+ cell->info().solute() = 0.0;
+ }
+}
+
+void SoluteFlowEngine::soluteTransport (double deltatime, double D)
+{
+ //soluteTransport is a function to solve transport of solutes for advection (+diffusion).
+ //Call this function with a pyRunner in the python script, implement a diffusion coefficient and a dt.
+ // Optimalization has to be done such that the coefficient matrix is not solved for each time step,only after triangulation.
+ // Extensive testing has to be done to check its ability to simulate a deforming porous media.
+ double coeff = 0.00;
+ double coeff1 = 0.00; //Coefficient for off-diagonal element
+ double coeff2 = 0.00; //Coefficient for diagonal element
+ double qin = 0.00; //Flux into the pore per pore throat
+ double Qout=0.0; //Total Flux out of the pore
+ int ncells = 0; //Number of cells
+ int ID = 0;
+ //double D = 0.0;
+ double invdistance = 0.0; //Fluid facet area divided by pore throat length for each pore throat
+ double invdistancelocal = 0.0; //Sum of invdistance
+ ncells=solver->T[solver->currentTes].cellHandles.size();
+
+ Eigen::SparseMatrix<double, Eigen::ColMajor> Aconc(ncells,ncells);
+ typedef Eigen::Triplet<double> ETriplet2;
+ std::vector<ETriplet2> tripletList2;
+ Eigen::SparseLU<Eigen::SparseMatrix<double,Eigen::ColMajor>,Eigen::COLAMDOrdering<int> > eSolver2;
+
+ // Prepare (copy) concentration vector
+ Eigen::VectorXd eb2(ncells); Eigen::VectorXd ex2(ncells);
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles){
+ eb2[cell->info().id]=cell->info().solute();
+ }
+
+ // Fill coefficient matrix
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles){
+ cell->info().invVoidVolume() = 1 / ( abs(cell->info().volume()) - abs(solver->volumeSolidPore(cell) ) );
+ invdistance=0.0;
+
+
+ unsigned int i=cell->info().id;
+ for (unsigned int ngb=0;ngb<4;ngb++){
+ CGT::Point& p2 = cell ->neighbor(ngb)->info();
+ CGT::Point& p1 = cell->info();
+ CGT::CVector l = p1-p2;
+ CGT::Real fluidSurf = sqrt(cell->info().facetSurfaces[ngb].squared_length())*cell->info().facetFluidSurfacesRatio[ngb];
+ invdistancelocal = (fluidSurf/sqrt(l.squared_length()));
+ invdistance+=(fluidSurf/sqrt(l.squared_length()));
+ coeff = deltatime*cell->info().invVoidVolume();
+ ID = cell->neighbor(ngb)->info().id;
+ qin=abs(cell->info().kNorm() [ngb])* ( cell->neighbor ( ngb )->info().p()-cell->info().p());
+ Qout=Qout+max(qin,0.0);
+ coeff1=-1*coeff*(abs(max(qin,0.0))-(D*invdistancelocal));
+ if (coeff1 != 0.0){
+ tripletList2.push_back(ETriplet2(i,ID,coeff1));
+ }
+
+ }
+ coeff2=1.0+(coeff*abs(Qout))+(coeff*D*invdistance);
+ tripletList2.push_back(ETriplet2(i,i,coeff2));
+ Qout=0.0;
+ }
+ //Solve Matrix
+ Aconc.setFromTriplets(tripletList2.begin(), tripletList2.end());
+ //if (eSolver2.signDeterminant() < 1){cerr << "determinant is negative!!!!!!! " << eSolver2.signDeterminant()<<endl;}
+ //eSolver2.setPivotThreshold(10e-8);
+ eSolver2.analyzePattern(Aconc);
+ eSolver2.factorize(Aconc);
+ eSolver2.compute(Aconc);
+ ex2 = eSolver2.solve(eb2);
+
+
+ double averageConc = 0.0;
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles){
+ averageConc+=cell->info().solute();}
+
+ //Copy data to concentration array
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles){
+ cell->info().solute()= ex2[cell->info().id];
+ }
+ tripletList2.clear();
+
+ }
+
+void SoluteFlowEngine::soluteBC(unsigned int bcid1, unsigned int bcid2, double bcconcentration1, double bcconcentration2, unsigned int s)
+{
+ //Boundary conditions according to soluteTransport.
+ //It simply assigns boundary concentrations to cells with a common vertices (e.g. infinite large sphere which makes up the boundary condition in flowEngine)
+ //s is a switch, if 0 only bc_id1 is used (advection only). If >0 than both bc_id1 and bc_id2 are used.
+ //NOTE (bruno): cell cirulators can be use to get all cells having bcid2 has a vertex more efficiently (see e.g. FlowBoundingSphere.ipp:721)
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles)
+ {
+ for (unsigned int ngb=0;ngb<4;ngb++){
+ if (cell->vertex(ngb)->info().id() == bcid1){cell->info().solute() = bcconcentration1;}
+ if (s > 0){if (cell->vertex(ngb)->info().id() == bcid2){cell->info().solute() = bcconcentration2;}}
+ }
+ }
+}
+
+double SoluteFlowEngine::getConcentrationPlane (double Yobs,double Yr, int xyz)
+{
+ //Get the concentration within a certain plane (Y_obs), whilst the cells are located in a small volume around this plane
+ //The concentration in cells are weighed for their distance to the observation point
+ //for a point on the x-axis (xyz=0), point on the y-axis (xyz=1), point on the z-axis (xyz=2)
+ double sumConcentration = 0.0;
+ double sumFraction=0.0;
+ double concentration=0.0;
+ //Find cells within designated volume
+
+ FOREACH(CellHandle& cell, solver->T[solver->currentTes].cellHandles)
+ {
+ CGT::Point& p1 = cell->info();
+ if (abs(p1[xyz]) < abs(abs(Yobs) + abs(Yr))){
+ if(abs(p1[xyz]) > abs(abs(Yobs) - abs(Yr))){
+ sumConcentration += cell->info().solute()*(1-(abs(p1[xyz])-abs(Yobs))/abs(Yr));
+ sumFraction += (1-(abs(p1[xyz])-abs(Yobs))/abs(Yr));
+ }
+ }
+ }
+ concentration = sumConcentration / sumFraction;
+ return concentration;
+}
+
+YADE_PLUGIN ( ( SoluteFlowEngine ) );
+
+#endif //SOLUTE_FLOW
+#endif //FLOW_ENGINE
+
+#endif /* YADE_CGAL */
=== modified file 'py/_polyhedra_utils.cpp'
--- py/_polyhedra_utils.cpp 2013-10-15 16:14:46 +0000
+++ py/_polyhedra_utils.cpp 2014-04-02 15:19:41 +0000
@@ -367,7 +367,7 @@
py::def("SieveCurve",SieveCurve,"save sieve curve coordinates into file");
py::def("SizeOfPolyhedra",SizeOfPolyhedra,"returns max, middle an min size in perpendicular directions");
py::def("SizeRatio",SizeRatio,"save sizes of polyhedra into file");
- py::def("convexHull",convexHull,"....");
+ py::def("convexHull",convexHull,"");
py::def("Split",Split,"split polyhedron perpendicularly to given direction direction");
}
=== modified file 'py/_utils.cpp'
--- py/_utils.cpp 2014-01-21 15:18:44 +0000
+++ py/_utils.cpp 2014-04-15 16:49:07 +0000
@@ -531,12 +531,12 @@
py::def("wireNone",wireNone,"Set :yref:`Shape::wire` on all bodies to False, rendering them as solids.");
py::def("wireNoSpheres",wireNoSpheres,"Set :yref:`Shape::wire` to True on non-spherical bodies (:yref:`Facets<Facet>`, :yref:`Walls<Wall>`).");
py::def("flipCell",&Shop::flipCell,(py::arg("flip")=Matrix3r(Matrix3r::Zero())),"Flip periodic cell so that angles between $R^3$ axes and transformed axes are as small as possible. This function relies on the fact that periodic cell defines by repetition or its corners regular grid of points in $R^3$; however, all cells generating identical grid are equivalent and can be flipped one over another. This necessiatates adjustment of :yref:`Interaction.cellDist` for interactions that cross boundary and didn't before (or vice versa), and re-initialization of collider. The *flip* argument can be used to specify desired flip: integers, each column for one axis; if zero matrix, best fit (minimizing the angles) is computed automatically.\n\nIn c++, this function is accessible as ``Shop::flipCell``.\n\n.. warning:: This function is currently broken and should not be used.");
- py::def("getViscoelasticFromSpheresInteraction",getViscoelasticFromSpheresInteraction,(py::arg("tc"),py::arg("en"),py::arg("es")),"Compute viscoelastic interaction parameters from analytical solution of a pair spheres collision problem:\n\n.. math:: k_n=\\frac{m}{t_c^2}\\left(\\pi^2+(\\ln e_n)^2\\right) \\\\ c_n=-\\frac{2m}{t_c}\\ln e_n \\\\ k_t=\\frac{2}{7}\\frac{m}{t_c^2}\\left(\\pi^2+(\\ln e_t)^2\\right) \\\\ c_t=-\\frac{2}{7}\\frac{m}{t_c}\\ln e_t \n\n\nwhere $k_n$, $c_n$ are normal elastic and viscous coefficients and $k_t$, $c_t$ shear elastic and viscous coefficients. For details see [Pournin2001]_.\n\n:param float m: sphere mass $m$\n:param float tc: collision time $t_c$\n:param float en: normal restitution coefficient $e_n$\n:param float es: tangential restitution coefficient $e_s$\n:return: dictionary with keys ``kn`` (the value of $k_n$), ``cn`` ($c_n$), ``kt`` ($k_t$), ``ct`` ($c_t$).");
+ py::def("getViscoelasticFromSpheresInteraction",getViscoelasticFromSpheresInteraction,(py::arg("tc"),py::arg("en"),py::arg("es")),"Attention! The function is deprecated! Compute viscoelastic interaction parameters from analytical solution of a pair spheres collision problem:\n\n.. math:: k_n=\\frac{m}{t_c^2}\\left(\\pi^2+(\\ln e_n)^2\\right) \\\\ c_n=-\\frac{2m}{t_c}\\ln e_n \\\\ k_t=\\frac{2}{7}\\frac{m}{t_c^2}\\left(\\pi^2+(\\ln e_t)^2\\right) \\\\ c_t=-\\frac{2}{7}\\frac{m}{t_c}\\ln e_t \n\n\nwhere $k_n$, $c_n$ are normal elastic and viscous coefficients and $k_t$, $c_t$ shear elastic and viscous coefficients. For details see [Pournin2001]_.\n\n:param float m: sphere mass $m$\n:param float tc: collision time $t_c$\n:param float en: normal restitution coefficient $e_n$\n:param float es: tangential restitution coefficient $e_s$\n:return: dictionary with keys ``kn`` (the value of $k_n$), ``cn`` ($c_n$), ``kt`` ($k_t$), ``ct`` ($c_t$).");
py::def("stressTensorOfPeriodicCell",Shop::getStress,(py::args("volume")=0),"Deprecated, use utils.getStress instead |ydeprecated|");
//py::def("stressTensorOfPeriodicCell",Shop__stressTensorOfPeriodicCell,(py::args("smallStrains")=false),"Compute overall (macroscopic) stress of periodic cell using equation published in [Kuhl2001]_:\n\n.. math:: \\vec{\\sigma}=\\frac{1}{V}\\sum_cl^c[\\vec{N}^cf_N^c+\\vec{T}^{cT}\\cdot\\vec{f}^c_T],\n\nwhere $V$ is volume of the cell, $l^c$ length of interaction $c$, $f^c_N$ normal force and $\\vec{f}^c_T$ shear force. Sumed are values over all interactions $c$. $\\vec{N}^c$ and $\\vec{T}^{cT}$ are projection tensors (see the original publication for more details):\n\n.. math:: \\vec{N}=\\vec{n}\\otimes\\vec{n}\\rightarrow N_{ij}=n_in_j\n\n.. math:: \\vec{T}^T=\\vec{I}_{sym}\\cdot\\vec{n}-\\vec{n}\\otimes\\vec{n}\\otimes\\vec{n}\\rightarrow T^T_{ijk}=\\frac{1}{2}(\\delta_{ik}\\delta_{jl}+\\delta_{il}\\delta_{jk})n_l-n_in_jn_k\n\n.. math:: \\vec{T}^T\\cdot\\vec{f}_T\\equiv T^T_{ijk}f_k=(\\delta_{ik}n_j/2+\\delta_{jk}n_i/2-n_in_jn_k)f_k=n_jf_i/2+n_if_j/2-n_in_jn_kf_k,\n\nwhere $n$ is unit vector oriented along the interaction (:yref:`normal<GenericSpheresContact::normal>`) and $\\delta$ is Kronecker's delta. As $\\vec{n}$ and $\\vec{f}_T$ are perpendicular (therfore $n_if_i=0$) we can write\n\n.. math:: \\sigma_{ij}=\\frac{1}{V}\\sum l[n_in_jf_N+n_jf^T_i/2+n_if^T_j/2]\n\n:param bool smallStrains: if false (large strains), real values of volume and interaction lengths are computed. If true, only :yref:`refLength<Dem3DofGeom::refLength>` of interactions and initial volume are computed (can save some time).\n\n:return: macroscopic stress tensor as Matrix3");
py::def("normalShearStressTensors",Shop__normalShearStressTensors,(py::args("compressionPositive")=false,py::args("splitNormalTensor")=false,py::args("thresholdForce")=NaN),"Compute overall stress tensor of the periodic cell decomposed in 2 parts, one contributed by normal forces, the other by shear forces. The formulation can be found in [Thornton2000]_, eq. (3):\n\n.. math:: \\tens{\\sigma}_{ij}=\\frac{2}{V}\\sum R N \\vec{n}_i \\vec{n}_j+\\frac{2}{V}\\sum R T \\vec{n}_i\\vec{t}_j\n\nwhere $V$ is the cell volume, $R$ is \"contact radius\" (in our implementation, current distance between particle centroids), $\\vec{n}$ is the normal vector, $\\vec{t}$ is a vector perpendicular to $\\vec{n}$, $N$ and $T$ are norms of normal and shear forces.\n\n:param bool splitNormalTensor: if true the function returns normal stress tensor split into two parts according to the two subnetworks of strong an weak forces.\n\n:param Real thresholdForce: threshold value according to which the normal stress tensor can be split (e.g. a zero value would make distinction between tensile and compressive forces).");
py::def("fabricTensor",Shop__fabricTensor,(py::args("splitTensor")=false,py::args("revertSign")=false,py::args("thresholdForce")=NaN),"Compute the fabric tensor of the periodic cell. The original paper can be found in [Satake1982]_.\n\n:param bool splitTensor: split the fabric tensor into two parts related to the strong and weak contact forces respectively.\n\n:param bool revertSign: it must be set to true if the contact law's convention takes compressive forces as positive.\n\n:param Real thresholdForce: if the fabric tensor is split into two parts, a threshold value can be specified otherwise the mean contact force is considered by default. It is worth to note that this value has a sign and the user needs to set it according to the convention adopted for the contact law. To note that this value could be set to zero if one wanted to make distinction between compressive and tensile forces.");
- py::def("bodyStressTensors",Shop__getStressLWForEachBody,"Compute and return a table with per-particle stress tensors. Each tensor represents the average stress in one particle, obtained from the contour integral of applied load as detailed below. This definition is considering each sphere as a continuum. It can be considered exact in the context of spheres at static equilibrium, interacting at contact points with negligible volume changes of the solid phase (this last assumption is not restricting possible deformations and volume changes at the packing scale).\n\nProof:\n\nFirst, we remark the identity: $\\sigma_{ij}=\\delta_{ik}\\sigma_{kj}=x_{i,k}\\sigma_{kj}=(x_{i}\\sigma_{kj})_{,k}-x_{i}\\sigma_{kj,k}$.\n\nAt equilibrium, the divergence of stress is null: $\\sigma_{kj,k}=\\vec{0}$. Consequently, after divergence theorem: $\\frac{1}{V}\\int_V \\sigma_{ij}dV = \\frac{1}{V}\\int_V (x_{i}\\sigma_{kj})_{,k}dV = \\frac{1}{V}\\int_{\\partial V}x_i\\sigma_{kj}n_kdS = \\frac{1}{V}\\sum_bx_i^bf_j^b$.\n\nThe last equality is implicitely based on the representation of external loads as Dirac distributions whose zeros are the so-called *contact points*: 0-sized surfaces on which the *contact forces* are applied, located at $x_i$ in the deformed configuration.\n\nA weighted average of per-body stresses will give the average stress inside the solid phase. There is a simple relation between the stress inside the solid phase and the stress in an equivalent continuum in the absence of fluid pressure. For porosity $n$, the relation reads: $\\sigma_{ij}^{equ.}=(1-n)\\sigma_{ij}^{solid}$.");
+ py::def("bodyStressTensors",Shop__getStressLWForEachBody,"Compute and return a table with per-particle stress tensors. Each tensor represents the average stress in one particle, obtained from the contour integral of applied load as detailed below. This definition is considering each sphere as a continuum. It can be considered exact in the context of spheres at static equilibrium, interacting at contact points with negligible volume changes of the solid phase (this last assumption is not restricting possible deformations and volume changes at the packing scale).\n\nProof: \n\nFirst, we remark the identity: $\\sigma_{ij}=\\delta_{ik}\\sigma_{kj}=x_{i,k}\\sigma_{kj}=(x_{i}\\sigma_{kj})_{,k}-x_{i}\\sigma_{kj,k}$.\n\nAt equilibrium, the divergence of stress is null: $\\sigma_{kj,k}=\\vec{0}$. Consequently, after divergence theorem: $\\frac{1}{V}\\int_V \\sigma_{ij}dV = \\frac{1}{V}\\int_V (x_{i}\\sigma_{kj})_{,k}dV = \\frac{1}{V}\\int_{\\partial V}x_i\\sigma_{kj}n_kdS = \\frac{1}{V}\\sum_bx_i^bf_j^b$.\n\nThe last equality is implicitely based on the representation of external loads as Dirac distributions whose zeros are the so-called *contact points*: 0-sized surfaces on which the *contact forces* are applied, located at $x_i$ in the deformed configuration.\n\nA weighted average of per-body stresses will give the average stress inside the solid phase. There is a simple relation between the stress inside the solid phase and the stress in an equivalent continuum in the absence of fluid pressure. For porosity $n$, the relation reads: $\\sigma_{ij}^{equ.}=(1-n)\\sigma_{ij}^{solid}$.\n\nThis last relation may not be very useful if porosity is not homogeneous. If it happens, one can define the equivalent bulk stress a the particles scale by assigning a volume to each particle. This volume can be obtained from :yref:`TesselationWrapper` (see e.g. [Catalano2014a]_)");
py::def("getStress",Shop::getStress,(py::args("volume")=0),"Compute and return Love-Weber stress tensor:\n\n $\\sigma_{ij}=\\frac{1}{V}\\sum_b f_i^b l_j^b$, where the sum is over all interactions, with $f$ the contact force and $l$ the branch vector (joining centers of the bodies). Stress is negativ for repulsive contact forces, i.e. compression. $V$ can be passed to the function. If it is not, it will be equal to one in non-periodic cases, or equal to the volume of the cell in periodic cases.");
py::def("getCapillaryStress",Shop::getCapillaryStress,(py::args("volume")=0),"Compute and return Love-Weber capillary stress tensor:\n\n $\\sigma^{cap}_{ij}=\\frac{1}{V}\\sum_b l_i^b f^{cap,b}_j$, where the sum is over all interactions, with $l$ the branch vector (joining centers of the bodies) and $f^{cap}$ is the capillary force. $V$ can be passed to the function. If it is not, it will be equal to one in non-periodic cases, or equal to the volume of the cell in periodic cases. Only the CapillaryPhys interaction type is supported presently.");
py::def("getBodyIdsContacts",Shop__getBodyIdsContacts,(py::args("bodyID")=0),"Get a list of body-ids, which contacts the given body.");
@@ -545,7 +545,7 @@
py::def("calm",Shop__calm,(py::arg("mask")=-1),"Set translational and rotational velocities of all bodies to zero.");
py::def("setNewVerticesOfFacet",setNewVerticesOfFacet,(py::arg("b"),py::arg("v1"),py::arg("v2"),py::arg("v3")),"Sets new vertices (in global coordinates) to given facet.");
py::def("setContactFriction",Shop::setContactFriction,py::arg("angleRad"),"Modify the friction angle (in radians) inside the material classes and existing contacts. The friction for non-dynamic bodies is not modified.");
- py::def("growParticles",Shop::growParticles,(py::args("multiplier"), py::args("updateMass")=true, py::args("dynamicOnly")=true, py::args("discretization")=15, py::args("integrateInertia")=true), "Change the size of spheres and sphere clumps by the multiplier. If updateMass=True, then the mass is updated. dynamicOnly=True is mandatory in many cases since in current implementation the function would crash on the non-spherical and non-dynamic bodies (e.g. facets, boxes, etc.). For clumps the masses and inertias are adapted automatically (for details of inertia tensor integration scheme see :yref:`clump()<BodyContainer.clump>`).");
+ py::def("growParticles",Shop::growParticles,(py::args("multiplier"), py::args("updateMass")=true, py::args("dynamicOnly")=true, py::args("discretization")=0), "Change the size of spheres and sphere clumps by the multiplier. If updateMass=True, then the mass is updated. dynamicOnly=True is mandatory in many cases since in current implementation the function would crash on the non-spherical and non-dynamic bodies (e.g. facets, boxes, etc.). For clumps the masses and inertias are adapted automatically when discretization>0 (for details of inertia tensor integration scheme see :yref:`clump()<BodyContainer.clump>`).");
py::def("growParticle",Shop::growParticle,(py::args("bodyID"),py::args("multiplier"), py::args("updateMass")=true), "Change the size of a single sphere (to be implemented: single clump). If updateMass=True, then the mass is updated.");
py::def("intrsOfEachBody",intrsOfEachBody,"returns list of lists of interactions of each body");
py::def("numIntrsOfEachBody",numIntrsOfEachBody,"returns list of number of interactions of each body");
=== modified file 'py/config.py.in'
--- py/config.py.in 2012-07-18 05:33:52 +0000
+++ py/config.py.in 2014-02-28 08:22:32 +0000
@@ -2,7 +2,7 @@
"""
Compile-time configuration for yade.
-Template file is processed by scons to create the actual configuration at build-time.
+Template file is processed by cmake to create the actual configuration at build-time.
"""
import os,datetime,os.path
prefix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX']
@@ -14,7 +14,7 @@
libDir=os.path.abspath(prefix+'/'+libPATH+'/yade${SUFFIX}')
confDir=os.environ['HOME']+'/.yade${SUFFIX}'
libstdcxx='${libstdcxx}'
-features='${features}'.split(',')
+features='${features}'.split(' ')
revision='${realVersion}'
version='${version}'
sourceRoot='${sourceRoot}'
=== modified file 'py/export.py'
--- py/export.py 2014-02-17 16:37:16 +0000
+++ py/export.py 2014-05-05 14:31:38 +0000
@@ -109,7 +109,7 @@
elif isinstance(val,(int,float)):
d.append(val)
else:
- print 'WARNING: export.text: wrong `what` parameter, output might be corrupted'
+ print "WARNING: export.text: wrong 'what' parameter, output might be corrupted"
return 0
data.append(d)
dataw = [' '.join('%e'%v for v in d) for d in data]
@@ -297,59 +297,87 @@
#VTKExporter===============================================================
class VTKExporter:
- """Class for exporting data to VTK Simple Legacy File (for example if, for some reason, you are not able to use VTKRecorder). Export of spheres, facets and interactions is supported.
-
+ """Class for exporting data to VTK Simple Legacy File (for example if, for some reason, you are not able to use VTKRecorder). Export of spheres, facets, interactions and polyhedra is supported.
+
USAGE:
create object vtkExporter = VTKExporter('baseFileName'),
add to engines PyRunner with command='vtkExporter.exportSomething(params)'
-
+ alternatively just use vtkExporter.exportSomething(...) at the end of the script for instance
+
Example: :ysrc:`examples/test/vtk-exporter/vtkExporter.py`, :ysrc:`examples/test/unv-read/unvReadVTKExport.py`.
-
+
:param string baseName: name of the exported files. The files would be named baseName-spheres-snapNb.vtk or baseName-facets-snapNb.vtk
- :param int=0 startSnap: the numbering of files will start form startSnap
+ :param int startSnap: the numbering of files will start form startSnap
"""
+ # TODO comments
def __init__(self,baseName,startSnap=0):
self.spheresSnapCount = startSnap
self.facetsSnapCount = startSnap
self.intrsSnapCount = startSnap
self.polyhedraSnapCount = startSnap
+ self.contactPointsSnapCount = startSnap
self.baseName = baseName
+ # auxiliary functions
+ def _warn(self,msg):
+ print "Warning (yade.export.VTKExporter): " + msg
+ def _error(self,msg):
+ print "ERROR (yade.export.VTKExporter): " + msg
+ def _getBodies(self,ids,type):
+ allIds = False
+ if isinstance(ids,str) and ids.lower()=='all':
+ ids=xrange(len(O.bodies))
+ allIds = True
+ bodies = []
+ for i in ids:
+ b = O.bodies[i]
+ if not b: continue
+ if not isinstance(b.shape,type):
+ if not allIds:
+ self._warn("body %d is not of type %s"%(i,type))
+ continue
+ bodies.append(b)
+ if not bodies:
+ self._warn("no bodies...")
+ return bodies
+ def _getInteractions(self,ids):
+ if isinstance(ids,str) and ids.lower()=='all':
+ ids = [(i.id1,i.id2) for i in O.interactions]
+ intrs = [(i,j) for i,j in ids]
+ if not intrs:
+ self._warn("no interactions ...")
+ return intrs
+
def exportSpheres(self,ids='all',what=[],comment="comment",numLabel=None,useRef=False):
"""exports spheres (positions and radius) and defined properties.
-
- :param ids: if "all", then export all spheres, otherwise only spheres from integer list
- :type ids: [int] | "all"
- :param what: what other than then position and radius export. parameter is list of couple (name,command). Name is string under which it is save to vtk, command is string to evaluate. Note that the bodies are labeled as b in this function. Scalar, vector and tensor variables are supported. For example, to export velocity (with name particleVelocity) and the distance form point (0,0,0) (named as dist) you should write: ... what=[('particleVelocity','b.state.vel'),('dist','b.state.pos.norm()', ...
- :type what: [tuple(2)]
+
+ :param [int]|"all" ids: if "all", then export all spheres, otherwise only spheres from integer list
+ :param [tuple(2)] what: what other than then position and radius export. parameter is list of couple (name,command). Name is string under which it is save to vtk, command is string to evaluate. Note that the bodies are labeled as b in this function. Scalar, vector and tensor variables are supported. For example, to export velocity (with name particleVelocity) and the distance form point (0,0,0) (named as dist) you should write: ... what=[('particleVelocity','b.state.vel'),('dist','b.state.pos.norm()', ...
:param string comment: comment to add to vtk file
:param int numLabel: number of file (e.g. time step), if unspecified, the last used value + 1 will be used
:param bool useRef: if False (default), use current position of the spheres for export, use reference position otherwise
"""
- allIds = False
- if ids=='all':
- ids=xrange(len(O.bodies))
- allIds = True
- bodies = []
- for i in ids:
- b = O.bodies[i]
- if not b: continue
- if b.shape.__class__.__name__!="Sphere":
- if not allIds: print "Warning: body %d is not Sphere"%(i)
- continue
- bodies.append(b)
- n = len(bodies)
+ # get list of bodies to export
+ bodies = self._getBodies(ids,Sphere)
+ if not bodies: return
+ nBodies = len(bodies)
+ # output file
fName = self.baseName+'-spheres-%04d'%(numLabel if numLabel else self.spheresSnapCount)+'.vtk'
outFile = open(fName, 'w')
- outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,n))
+ # head
+ outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,nBodies))
+ # write position of spheres
for b in bodies:
pos = b.state.refPos if useRef else b.state.pos if not O.periodic else O.cell.wrap(b.state.pos)
outFile.write("%g %g %g\n"%(pos[0],pos[1],pos[2]))
- outFile.write("\nPOINT_DATA %d\nSCALARS radius double 1\nLOOKUP_TABLE default\n"%(n))
+ # write radius
+ outFile.write("\nPOINT_DATA %d\nSCALARS radius double 1\nLOOKUP_TABLE default\n"%(nBodies))
for b in bodies:
outFile.write("%g\n"%(b.shape.radius))
- for name,command in what:
- test = eval(command)
+ # write additional data from 'what' param
+ for name,command in what: # for each name...
+ test = eval(command) # ... eval one example to see what type (float, Vector3, Matrix3) the result is ...
+ # ... and write appropriate header line and loop over all bodies and write appropriate vtk line(s)
if isinstance(test,Matrix3):
outFile.write("\nTENSORS %s double\n"%(name))
for b in bodies:
@@ -365,35 +393,29 @@
for b in bodies:
outFile.write("%g\n"%(eval(command)))
else:
- print 'WARNING: export.VTKExporter.exportSpheres: wrong `what` parameter, vtk output might be corrupted'
+ self._warn("exportSpheres: wrong 'what' parameter, vtk output might be corrupted'")
outFile.close()
self.spheresSnapCount += 1
def exportFacets(self,ids='all',what=[],comment="comment",numLabel=None):
"""
exports facets (positions) and defined properties. Facets are exported with multiplicated nodes
-
+
:param [int]|"all" ids: if "all", then export all facets, otherwise only facets from integer list
:param [tuple(2)] what: see exportSpheres
:param string comment: comment to add to vtk file
:param int numLabel: number of file (e.g. time step), if unspecified, the last used value + 1 will be used
"""
- allIds = False
- if ids=='all':
- ids=xrange(len(O.bodies))
- allIds = True
- bodies = []
- for i in ids:
- b = O.bodies[i]
- if not b: continue
- if b.shape.__class__.__name__!="Facet":
- if not allIds: print "Warning: body %d is not Facet"%(i)
- continue
- bodies.append(b)
- n = len(bodies)
+ # get list of bodies to export
+ bodies = self._getBodies(ids,Facet)
+ if not bodies: return
+ nBodies = len(bodies)
+ # output file
fName = self.baseName+'-facets-%04d'%(numLabel if numLabel else self.facetsSnapCount)+'.vtk'
outFile = open(fName, 'w')
- outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,3*n))
+ # head
+ outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,3*nBodies))
+ # write vertices
for b in bodies:
p = b.state.pos
o = b.state.ori
@@ -404,13 +426,16 @@
outFile.write("%g %g %g\n"%(pt1[0],pt1[1],pt1[2]))
outFile.write("%g %g %g\n"%(pt2[0],pt2[1],pt2[2]))
outFile.write("%g %g %g\n"%(pt3[0],pt3[1],pt3[2]))
- outFile.write("\nPOLYGONS %d %d\n"%(n,4*n))
+ # write facets
+ outFile.write("\nPOLYGONS %d %d\n"%(nBodies,4*nBodies))
i = 0
for b in bodies:
outFile.write("3 %d %d %d\n"%(i,i+1,i+2))
i += 3
+ # write additional data from 'what' param
if what:
- outFile.write("\nCELL_DATA %d"%(n))
+ outFile.write("\nCELL_DATA %d"%(nBodies))
+ # see exportSpheres for explanation of this code block
for name,command in what:
test = eval(command)
if isinstance(test,Matrix3):
@@ -424,7 +449,7 @@
v = eval(command)
outFile.write("%g %g %g\n"%(v[0],v[1],v[2]))
else:
- outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"(name))
+ outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"%(name))
for b in bodies:
outFile.write("%g\n"%(eval(command)))
outFile.close()
@@ -433,7 +458,7 @@
def exportFacetsAsMesh(self,ids='all',connectivityTable=None,what=[],comment="comment",numLabel=None):
"""
exports facets (positions) and defined properties. Facets are exported as mesh (not with multiplicated nodes). Therefore additional parameters connectivityTable is needed
-
+
:param [int]|"all" ids: if "all", then export all facets, otherwise only facets from integer list
:param [tuple(2)] what: see exportSpheres
:param string comment: comment to add to vtk file
@@ -441,26 +466,17 @@
:param [(float,float,float)|Vector3] nodes: list of coordinates of nodes
:param [(int,int,int)] connectivityTable: list of node ids of individual elements (facets)
"""
- allIds = False
- if ids=='all':
- ids=xrange(len(O.bodies))
- allIds = True
- bodies = []
- for i in ids:
- b = O.bodies[i]
- if not b: continue
- if b.shape.__class__.__name__!="Facet":
- if not allIds: print "Warning: body %d is not Facet"%(i)
- continue
- bodies.append(b)
- ids = xrange(len(bodies))
- n = len(bodies)
+ # get list of bodies to export
+ bodies = self._getBodies(ids,Facet)
+ if not bodies: return
+ nBodies = len(bodies)
if connectivityTable is None:
- print "ERROR: 'connectivityTable' not specified"
- return
- if n != len(connectivityTable):
- print "ERROR: length of 'connectivityTable' does not match length of 'ids', no export"
- return
+ self._error("'connectivityTable' not specified")
+ return
+ if nBodies != len(connectivityTable):
+ self._error("length of 'connectivityTable' does not match length of 'ids', no export")
+ return
+ # nodes
nodes = [Vector3.Zero for i in xrange(max(max(e) for e in connectivityTable)+1)]
for id,e in zip(ids,connectivityTable):
b = bodies[id]
@@ -473,17 +489,22 @@
nodes[e[0]] = pt1
nodes[e[1]] = pt2
nodes[e[2]] = pt3
+ # output file
fName = self.baseName+'-facets-%04d'%(numLabel if numLabel else self.facetsSnapCount)+'.vtk'
outFile = open(fName, 'w')
+ # head
outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,len(nodes)))
- gg = 0
- for n in nodes:
- outFile.write("%g %g %g\n"%(n[0],n[1],n[2]))
+ # write vertices
+ for node in nodes:
+ outFile.write("%g %g %g\n"%(node[0],node[1],node[2]))
+ # write facets
outFile.write("\nPOLYGONS %d %d\n"%(len(connectivityTable),4*len(connectivityTable)))
for e in connectivityTable:
outFile.write("3 %d %d %d\n"%e)
+ # write additional data from 'what' param
if what:
- outFile.write("\nCELL_DATA %d"%(n))
+ outFile.write("\nCELL_DATA %d"%(nBodies))
+ # see exportSpheres for explanation of this code block
for name,command in what:
test = eval(command)
if isinstance(test,Matrix3):
@@ -497,7 +518,7 @@
v = eval(command)
outFile.write("%g %g %g\n"%(v[0],v[1],v[2]))
else:
- outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"(name))
+ outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"%(name))
for b in bodies:
outFile.write("%g\n"%(eval(command)))
outFile.close()
@@ -505,59 +526,65 @@
def exportInteractions(self,ids='all',what=[],verticesWhat=[],comment="comment",numLabel=None):
"""exports interactions and defined properties.
-
- :param ids: if "all", then export all spheres, otherwise only spheres from integer list
- :type ids: [int] | "all"
- :param what: what to export. parameter is list of couple (name,command). Name is string under which it is save to vtk, command is string to evaluate. Note that the interactions are labeled as i in this function. Scalar, vector and tensor variables are supported. For example, to export stiffness difference from certain value (1e9) (named as dStiff) you should write: ... what=[('dStiff','i.phys.kn-1e9'), ...
- :type what: [tuple(2)]
+
+ :param [(int,int)]|"all" ids: if "all", then export all interactions, otherwise only interactions from (int,int) list
+ :param [tuple(2)] what: what to export. parameter is list of couple (name,command). Name is string under which it is save to vtk, command is string to evaluate. Note that the interactions are labeled as i in this function. Scalar, vector and tensor variables are supported. For example, to export stiffness difference from certain value (1e9) (named as dStiff) you should write: ... what=[('dStiff','i.phys.kn-1e9'), ...
+ :param [tuple(2|3)] verticesWhat: what to export on connected bodies. Bodies are labeled as 'b' (or 'b1' and 'b2' if you need treat both bodies differently)
:param string comment: comment to add to vtk file
:param int numLabel: number of file (e.g. time step), if unspecified, the last used value + 1 will be used
"""
- if ids=='all':
- ids = [(i.id1,i.id2) for i in O.interactions]
- intrs = [(2*j-1,2*j) for j in xrange(len(ids))]
- n = len(intrs)
+ # get list of interactions to export
+ intrs = self._getInteractions(ids)
+ if not intrs:
+ return
+ nIntrs = len(intrs)
+ # output file
fName = self.baseName+'-intrs-%04d'%(numLabel if numLabel else self.intrsSnapCount)+'.vtk'
outFile = open(fName, 'w')
- outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,2*n))
- for ii,jj in ids:
+ # head
+ outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,2*nIntrs))
+ # write coords of intrs bodies (also taking into account possible periodicity
+ for ii,jj in intrs:
i = O.interactions[ii,jj]
pos = O.bodies[ii].state.pos
outFile.write("%g %g %g\n"%(pos[0],pos[1],pos[2]))
pos = O.bodies[jj].state.pos + (O.cell.hSize*i.cellDist if O.periodic else Vector3.Zero)
outFile.write("%g %g %g\n"%(pos[0],pos[1],pos[2]))
- outFile.write("LINES %d %d\n"%(n,3*n))
+ # write interactions as lines
+ outFile.write("LINES %d %d\n"%(nIntrs,3*nIntrs))
for j,i in enumerate(intrs):
- outFile.write("2 %d %d\n"%(i[0]+1,i[1]+1))
- outFile.write("\nCELL_DATA %d\n"%(n))
- i = None
+ outFile.write("2 %d %d\n"%(2*j,2*j+1))
+ # write additional data from 'what' param
+ if what:
+ outFile.write("\nCELL_DATA %d\n"%(nIntrs))
for i in O.interactions:
if i.isReal: break
- if i:
- for name,command in what:
- test = eval(command)
- if isinstance(test,Matrix3):
- print 'WARNING: export.VTKExporter.exportInteractions: wrong `what` parameter, Matrix3 output not (yet?) supported'
- #outFile.write("\nTENSORS %s double\n"%(name))
- #for i in intrs:
- # t = eval(command)
- # outFile.write("%g %g %g\n%g %g %g\n%g %g %g\n\n"%(t[0,0],t[0,1],t[0,2],t[1,0],t[1,1],t[1,2],t[2,0],t[2,1],t[2,2]))
- elif isinstance(test,Vector3):
- print 'WARNING: export.VTKExporter.exportInteractions: wrong `what` parameter, Vector3 output not (yet?) supported'
- #outFile.write("\nVECTORS %s double\n"%(name))
- #for i in intrs:
- # v = eval(command)
- # outFile.write("%g %g %g\n"%(v[0],v[1],v[2]))
- elif isinstance(test,(int,float)):
- outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"%(name))
- for ii,jj in ids:
- i = O.interactions[ii,jj]
- outFile.write("%g\n"%(eval(command)))
- else:
- print 'WARNING: export.VTKExporter.exportInteractions: wrong `what` parameter, vtk output might be corrupted'
+ # see exportSpheres for explanation of this code block
+ for name,command in what:
+ test = eval(command)
+ if isinstance(test,Matrix3):
+ outFile.write("\nTENSORS %s double\n"%(name))
+ for ii,jj in intrs:
+ i = O.interactions[ii,jj]
+ t = eval(command)
+ outFile.write("%g %g %g\n%g %g %g\n%g %g %g\n\n"%(t[0,0],t[0,1],t[0,2],t[1,0],t[1,1],t[1,2],t[2,0],t[2,1],t[2,2]))
+ elif isinstance(test,Vector3):
+ outFile.write("\nVECTORS %s double\n"%(name))
+ for ii,jj in intrs:
+ v = eval(command)
+ outFile.write("%g %g %g\n"%(v[0],v[1],v[2]))
+ elif isinstance(test,(int,float)):
+ outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"%(name))
+ for ii,jj in intrs:
+ i = O.interactions[ii,jj]
+ outFile.write("%g\n"%(eval(command)))
+ else:
+ self._warn("exportInteractions: wrong 'what' parameter, vtk output might be corrupted")
+ # write additional data of bodies
if verticesWhat:
- outFile.write("\nPOINT_DATA %d\n"%(2*n))
+ outFile.write("\nPOINT_DATA %d\n"%(2*nIntrs))
b = b1 = b2 = O.bodies[0]
+ # see exportSpheres for explanation of this code block
for vWhat in verticesWhat:
lw = len(vWhat)
if lw == 2:
@@ -568,7 +595,7 @@
test = eval(command1)
if isinstance(test,Matrix3):
outFile.write("\nTENSORS %s double\n"%(name))
- for ii,jj in ids:
+ for ii,jj in intrs:
i = O.interactions[ii,jj]
b1 = O.bodies[ii]
b2 = O.bodies[jj]
@@ -583,7 +610,7 @@
outFile.write("%g %g %g\n%g %g %g\n%g %g %g\n\n"%(t2[0,0],t2[0,1],t2[0,2],t2[1,0],t2[1,1],t2[1,2],t2[2,0],t2[2,1],t2[2,2]))
elif isinstance(test,Vector3):
outFile.write("\nVECTORS %s double\n"%(name))
- for ii,jj in ids:
+ for ii,jj in intrs:
i = O.interactions[ii,jj]
b1 = O.bodies[ii]
b2 = O.bodies[jj]
@@ -598,7 +625,7 @@
outFile.write("%g %g %g\n"%(v2[0],v2[1],v2[2]))
elif isinstance(test,(int,float)):
outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"%(name))
- for ii,jj in ids:
+ for ii,jj in intrs:
i = O.interactions[ii,jj]
b1 = O.bodies[ii]
b2 = O.bodies[jj]
@@ -609,18 +636,88 @@
outFile.write("%g\n"%(eval(command1)))
outFile.write("%g\n"%(eval(command2)))
else:
- print 'WARNING: export.VTKExporter.exportInteractions: wrong `what` parameter, vtk output might be corrupted'
+ self._warn("exportInteractions: wrong 'what' parameter, vtk output might be corrupted")
outFile.close()
self.intrsSnapCount += 1
+ def exportContactPoints(self,ids='all',what=[],useRef={},comment="comment",numLabel=None):
+ """exports constact points and defined properties.
+
+ :param [(int,int)] ids: see exportInteractions
+ :param [tuple(2)] what: what to export. parameter is list of couple (name,command). Name is string under which it is save to vtk, command is string to evaluate. Note that the CPs are labeled as i in this function (sccording to their interaction). Scalar, vector and tensor variables are supported. For example, to export stiffness difference from certain value (1e9) (named as dStiff) you should write: ... what=[('dStiff','i.phys.kn-1e9'), ...
+ :param {Interaction:Vector3} useRef: if not specified, current position used. Otherwise use position from dict using interactions as keys. Interactions not in dict are not exported
+ :param string comment: comment to add to vtk file
+ :param int numLabel: number of file (e.g. time step), if unspecified, the last used value + 1 will be used
+ """
+ # get list of interactions to export
+ if useRef:
+ useRef = dict(((i.id1,i.id2),v) for i,v in useRef.iteritems())
+ intrs = useRef.keys()
+ else:
+ intrs = self._getInteractions(ids)
+ if not intrs:
+ return
+ nIntrs = len(intrs)
+ # output file
+ fName = self.baseName+'-cps-%04d'%(numLabel if numLabel else self.contactPointsSnapCount)+'.vtk'
+ outFile = open(fName, 'w')
+ # head
+ outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,nIntrs))
+ # write coords of contact points
+ for ii,jj in intrs:
+ if useRef:
+ pos = useRef[(ii,jj)]
+ else:
+ i = O.interactions[ii,jj]
+ pos = i.geom.contactPoint
+ outFile.write("%g %g %g\n"%(pos[0],pos[1],pos[2]))
+ # see exportSpheres for explanation of this code block
+ if what:
+ outFile.write("\nPOINT_DATA %d\n"%(nIntrs))
+ for i in O.interactions:
+ if i.isReal: break
+ for name,command in what:
+ test = eval(command)
+ if isinstance(test,Matrix3):
+ outFile.write("\nTENSORS %s double\n"%(name))
+ for ii,jj in intrs:
+ try:
+ i = O.interactions[ii,jj]
+ t = eval(command)
+ except IndexError:
+ t = Matrix3.Zero # TODO?
+ outFile.write("%g %g %g\n%g %g %g\n%g %g %g\n\n"%(t[0,0],t[0,1],t[0,2],t[1,0],t[1,1],t[1,2],t[2,0],t[2,1],t[2,2]))
+ elif isinstance(test,Vector3):
+ outFile.write("\nVECTORS %s double\n"%(name))
+ for ii,jj in intrs:
+ try:
+ i = O.interactions[ii,jj]
+ v = eval(command)
+ except IndexError:
+ v = Vector3.Zero # TODO?
+ outFile.write("%g %g %g\n"%(v[0],v[1],v[2]))
+ elif isinstance(test,(int,float)):
+ outFile.write("\nSCALARS %s double 1\nLOOKUP_TABLE default\n"%(name))
+ for ii,jj in intrs:
+ try:
+ i = O.interactions[ii,jj]
+ f = eval(command)
+ except IndexError:
+ f = 0. # TODO?
+ outFile.write("%g\n"%(f))
+ else:
+ self._warn("exportContacPoints: wrong 'what' parameter, vtk output might be corrupted'")
+ outFile.close()
+ self.contactPointsSnapCount += 1
+
def exportPeriodicCell(self,comment="comment",numLabel=None):
"""exports spheres (positions and radius) and defined properties.
-
+
:param string comment: comment to add to vtk file
:param int numLabel: number of file (e.g. time step), if unspecified, the last used value + 1 will be used
"""
if not O.periodic:
- print 'WARNING: export.VTKExporter.exportPeriodicCell: scene is not periodic, no export...'
+ self._warn("exportPeriodicCell: scene is not periodic, no export...")
return
hSize = O.cell.hSize
fName = self.baseName+'-periCell-%04d'%(numLabel if numLabel else self.intrsSnapCount)+'.vtk'
@@ -645,7 +742,7 @@
def exportPolyhedra(self,ids='all',what=[],comment="comment",numLabel=None):
"""Exports polyhedrons and defined properties.
-
+
:param ids: if "all", then export all polyhedrons, otherwise only polyhedrons from integer list
:type ids: [int] | "all"
:param what: what other than then position to export. parameter is list of couple (name,command). Name is string under which it is save to vtk, command is string to evaluate. Note that the bodies are labeled as b in this function. Scalar, vector and tensor variables are supported. For example, to export velocity (with name particleVelocity) and the distance form point (0,0,0) (named as dist) you should write: ... what=[('particleVelocity','b.state.vel'),('dist','b.state.pos.norm()', ...
@@ -654,20 +751,12 @@
:param int numLabel: number of file (e.g. time step), if unspecified, the last used value + 1 will be used
"""
# TODO useRef?
- allIds = False
- if ids=='all':
- ids=xrange(len(O.bodies))
- allIds = True
- bodies = []
- for i in ids:
- b = O.bodies[i]
- if not b: continue
- if b.shape.__class__.__name__!="Polyhedra":
- if not allIds: print "Warning: body %d is not Polyhedra"%(i)
- continue
- bodies.append(b)
- n = len(bodies)
+ # get list of bodies to export
+ bodies = self._getBodies(ids,Polyhedra) # TODO
+ if not bodies: return
+ # number of vertices
nVertices = sum(len(b.shape.v) for b in bodies)
+ # export polyherda as a set of triangle faces
bodyFaces = []
for b in bodies:
ff = []
@@ -675,16 +764,20 @@
for i in xrange(len(f)/3):
ff.append([f[3*i+j] for j in (0,1,2)])
bodyFaces.append(ff)
+ # output file
nFaces = sum(len(f) for f in bodyFaces)
fName = self.baseName+'-polyhedra-%04d'%(numLabel if numLabel else self.polyhedraSnapCount)+'.vtk'
outFile = open(fName, 'w')
+ # head
outFile.write("# vtk DataFile Version 3.0.\n%s\nASCII\n\nDATASET POLYDATA\nPOINTS %d double\n"%(comment,nVertices))
+ # write position of vertices
for b in bodies:
bPos = b.state.pos
bOri = b.state.ori
for v in b.shape.v:
pos = bPos + bOri*v
outFile.write("%g %g %g\n"%(pos[0],pos[1],pos[2]))
+ # write triangle faces
outFile.write("\nPOLYGONS %d %d\n"%(nFaces,4*nFaces))
j = 0
for i,b in enumerate(bodies):
@@ -693,8 +786,10 @@
t = tuple([j+ii for ii in face])
outFile.write("3 %d %d %d\n"%t)
j += len(b.shape.v)
+ # write additional data from 'what' param
if what:
outFile.write("\nCELL_DATA %d"%(nFaces))
+ # see exportSpheres for explanation of this code block
for name,command in what:
test = eval(command)
if isinstance(test,Matrix3):
@@ -716,7 +811,7 @@
for f in bodyFaces[i]:
outFile.write("%g\n"%e)
else:
- print 'WARNING: export.VTKExporter.exportPolyhedra: wrong `what` parameter, vtk output might be corrupted'
+ self._warn("exportPolyhedra: wrong 'what' parameter, vtk output might be corrupted")
outFile.close()
self.polyhedraSnapCount += 1
=== modified file 'py/wrapper/yadeWrapper.cpp'
--- py/wrapper/yadeWrapper.cpp 2013-10-04 13:41:43 +0000
+++ py/wrapper/yadeWrapper.cpp 2014-04-15 14:45:52 +0000
@@ -133,7 +133,7 @@
#endif
vector<Body::id_t> ret; FOREACH(shared_ptr<Body>& b, bb){ret.push_back(append(b));} return ret;
}
- Body::id_t clump(vector<Body::id_t> ids, unsigned int discretization, bool integrateInertia){
+ Body::id_t clump(vector<Body::id_t> ids, unsigned int discretization){
// create and add clump itself
Scene* scene(Omega::instance().getScene().get());
shared_ptr<Body> clumpBody=shared_ptr<Body>(new Body());
@@ -149,16 +149,16 @@
};
FOREACH(Body::id_t id, ids) Clump::add(clumpBody,Body::byId(id,scene));
- Clump::updateProperties(clumpBody, discretization, integrateInertia);
+ Clump::updateProperties(clumpBody, discretization);
return clumpBody->getId();
}
- python::tuple appendClump(vector<shared_ptr<Body> > bb, unsigned int discretization, bool integrateInertia){
+ python::tuple appendClump(vector<shared_ptr<Body> > bb, unsigned int discretization){
// append constituent particles
vector<Body::id_t> ids(appendList(bb));
// clump them together (the clump fcn) and return
- return python::make_tuple(clump(ids, discretization, integrateInertia),ids);
+ return python::make_tuple(clump(ids, discretization),ids);
}
- void addToClump(vector<Body::id_t> bids, Body::id_t cid, unsigned int discretization, bool integrateInertia){
+ void addToClump(vector<Body::id_t> bids, Body::id_t cid, unsigned int discretization){
Scene* scene(Omega::instance().getScene().get()); // get scene
shared_ptr<Body> clp = Body::byId(cid,scene); // get clump pointer
checkClump(clp);
@@ -179,10 +179,10 @@
}
else Clump::add(clp,bp);// bp must be a standalone!
}
- Clump::updateProperties(clp, discretization, integrateInertia);
+ Clump::updateProperties(clp, discretization);
FOREACH(Body::id_t bid, eraseList) proxee->erase(bid);//erase old clumps
}
- void releaseFromClump(Body::id_t bid, Body::id_t cid, unsigned int discretization, bool integrateInertia){
+ void releaseFromClump(Body::id_t bid, Body::id_t cid, unsigned int discretization){
Scene* scene(Omega::instance().getScene().get()); // get scene
shared_ptr<Body> bp = Body::byId(bid,scene); // get body pointer
shared_ptr<Body> clp = Body::byId(cid,scene); // get clump pointer
@@ -194,11 +194,11 @@
std::map<Body::id_t,Se3r>& members = clump->members;
if (members.size() == 2) {PyErr_Warn(PyExc_UserWarning,("Warning: Body "+lexical_cast<string>(bid)+" not released from clump "+lexical_cast<string>(cid)+", because number of clump members would get < 2!").c_str()); return;}
Clump::del(clp,bp);//release bid from cid
- Clump::updateProperties(clp, discretization, integrateInertia);
+ Clump::updateProperties(clp, discretization);
} else { PyErr_Warn(PyExc_UserWarning,("Warning: Body "+lexical_cast<string>(bid)+" must be a clump member of clump "+lexical_cast<string>(cid)+". Body was not released.").c_str()); return;}
} else { PyErr_Warn(PyExc_UserWarning,("Warning: Body "+lexical_cast<string>(bid)+" is not a clump member. Body was not released.").c_str()); return;}
}
- python::list replaceByClumps(python::list ctList, vector<Real> amounts, unsigned int discretization, bool integrateInertia){
+ python::list replaceByClumps(python::list ctList, vector<Real> amounts, unsigned int discretization){
python::list ret;
Real checkSum = 0.0;
FOREACH(Real amount, amounts) {
@@ -238,22 +238,45 @@
//extract attributes from python objects:
python::object ctTmp = ctList[ii];
- int numCM = python::extract<int>(ctTmp.attr("numCM"))();
+ int numCM = python::extract<int>(ctTmp.attr("numCM"))();// number of clump members
python::list relRadListTmp = python::extract<python::list>(ctTmp.attr("relRadii"))();
python::list relPosListTmp = python::extract<python::list>(ctTmp.attr("relPositions"))();
- //get relative radii and positions; calc. volumes; get balance point:
+ //get relative radii and positions; calculate volumes; get balance point: get axis aligned bounding box; get minimum radius;
vector<Real> relRadTmp(numCM), relVolTmp(numCM);
vector<Vector3r> relPosTmp(numCM);
Vector3r relPosTmpMean = Vector3r::Zero();
+ Real rMin=1./0.; AlignedBox3r aabb;
for (int jj = 0; jj < numCM; jj++) {
relRadTmp[jj] = python::extract<Real>(relRadListTmp[jj])();
relVolTmp[jj] = (4./3.)*Mathr::PI*pow(relRadTmp[jj],3.);
relPosTmp[jj] = python::extract<Vector3r>(relPosListTmp[jj])();
relPosTmpMean += relPosTmp[jj];
+ aabb.extend(relPosTmp[jj] + Vector3r::Constant(relRadTmp[jj]));
+ aabb.extend(relPosTmp[jj] - Vector3r::Constant(relRadTmp[jj]));
+ rMin=min(rMin,relRadTmp[jj]);
}
relPosTmpMean /= numCM;//balance point
-
+
+ //get volume of the clump template using regular cubic cell array inside axis aligned bounding box of the clump:
+ //(some parts are duplicated from intergration algorithm in Clump::updateProperties)
+ Real dx = rMin/5.; //edge length of cell
+ Real aabbMax = max(max(aabb.max().x()-aabb.min().x(),aabb.max().y()-aabb.min().y()),aabb.max().z()-aabb.min().z());
+ if (aabbMax/dx > 150) dx = aabbMax/150;//limit dx
+ Real dv = pow(dx,3); //volume of a single cell
+ Vector3r x; //position vector (center) of cell
+ Real relVolSumTmp = 0.0; //volume of clump template
+ for(x.x()=aabb.min().x()+dx/2.; x.x()<aabb.max().x(); x.x()+=dx){
+ for(x.y()=aabb.min().y()+dx/2.; x.y()<aabb.max().y(); x.y()+=dx){
+ for(x.z()=aabb.min().z()+dx/2.; x.z()<aabb.max().z(); x.z()+=dx){
+ for (int jj = 0; jj < numCM; jj++) {
+ if((x-relPosTmp[jj]).squaredNorm() < pow(relRadTmp[jj],2)){ relVolSumTmp += dv; break; }
+ }
+ }
+ }
+ }
+ /**
+ ### old method, not working for multiple overlaps:
//check for overlaps and correct volumes (-= volume of spherical caps):
Real distCMTmp, overlapTmp, hCapjj, hCapkk;
for (int jj = 0; jj < numCM; jj++) {
@@ -271,10 +294,9 @@
}
}
}
-
//get relative volume of the clump:
- Real relVolSumTmp = 0.0;
for (int jj = 0; jj < numCM; jj++) relVolSumTmp += relVolTmp[jj];
+ **/
//get pointer lists of spheres, that should be replaced:
int numReplaceTmp = round(num*amounts[ii]);
@@ -293,7 +315,17 @@
}
//adapt position- and radii-informations and replace spheres from bpListTmp by clumps:
+ #ifdef YADE_OPENMP
+ omp_lock_t locker;
+ omp_init_lock(&locker);//since bodies are created and deleted in following sections, it is neccessary to lock critical parts of the code (avoid seg fault)
+ #pragma omp parallel for schedule(dynamic) shared(locker)
+ for(int i=0; i<numReplaceTmp; i++) {
+ while (! omp_test_lock(&locker)) usleep(1);
+ const shared_ptr<Body>& b = bpListTmp[i];
+ LOG_DEBUG("replaceByClumps: Started processing body "<<bpListTmp[i]->id<<" in parallel ...");
+ #else
FOREACH (const shared_ptr<Body>& b, bpListTmp) {
+ #endif
//get sphere, that should be replaced:
const Sphere* sphere = YADE_CAST<Sphere*> (b->shape.get());
shared_ptr<Material> matTmp = b->material;
@@ -337,7 +369,11 @@
LOG_DEBUG("New body (sphere) "<<newSphere->id<<" added.");
idsTmp[jj] = newSphere->id;
}
- Body::id_t newClumpId = clump(idsTmp, discretization, integrateInertia);
+ //cout << "thread " << omp_get_thread_num() << " unsets locker" << endl;
+ #ifdef YADE_OPENMP
+ omp_unset_lock(&locker);//end of critical section
+ #endif
+ Body::id_t newClumpId = clump(idsTmp, discretization);
ret.append(python::make_tuple(newClumpId,idsTmp));
erase(b->id);
}
@@ -592,6 +628,8 @@
bool dynDtAvailable_get(){ return OMEGA.getScene()->timeStepperPresent(); }
long stopAtIter_get(){return OMEGA.getScene()->stopAtIter; }
void stopAtIter_set(long s){OMEGA.getScene()->stopAtIter=s; }
+ Real stopAtTime_get(){return OMEGA.getScene()->stopAtTime; }
+ void stopAtTime_set(long s){OMEGA.getScene()->stopAtTime=s; }
bool timingEnabled_get(){return TimingInfo::enabled;}
@@ -793,6 +831,7 @@
.add_property("subStep",&pyOmega::subStep,"Get the current subStep number (only meaningful if O.subStepping==True); -1 when outside the loop, otherwise either 0 (O.subStepping==False) or number of engine to be run (O.subStepping==True)")
.add_property("subStepping",&pyOmega::subStepping_get,&pyOmega::subStepping_set,"Get/set whether subStepping is active.")
.add_property("stopAtIter",&pyOmega::stopAtIter_get,&pyOmega::stopAtIter_set,"Get/set number of iteration after which the simulation will stop.")
+ .add_property("stopAtTime",&pyOmega::stopAtTime_get,&pyOmega::stopAtTime_set,"Get/set time after which the simulation will stop.")
.add_property("time",&pyOmega::time,"Return virtual (model world) time of the simulation.")
.add_property("realtime",&pyOmega::realTime,"Return clock (human world) time the simulation has been running.")
.add_property("speed",&pyOmega::speed,"Return current calculation speed [iter/sec].")
@@ -860,11 +899,11 @@
.def("__iter__",&pyBodyContainer::pyIter)
.def("append",&pyBodyContainer::append,"Append one Body instance, return its id.")
.def("append",&pyBodyContainer::appendList,"Append list of Body instance, return list of ids")
- .def("appendClumped",&pyBodyContainer::appendClump,(python::arg("discretization")=15,python::arg("integrateInertia")=true),"Append given list of bodies as a clump (rigid aggregate); returns a tuple of ``(clumpId,[memberId1,memberId2,...])``. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`).")
- .def("clump",&pyBodyContainer::clump,(python::arg("discretization")=15,python::arg("integrateInertia")=true),"Clump given bodies together (creating a rigid aggregate); returns ``clumpId``. Clump masses and inertia are adapted automatically (default with integrateInertia=True). If clump members are overlapping this is done by integration/summation over mass points using a regular grid of cells (number of grid cells in one direction is defined as $R_{min}/discretization$, where $R_{min}$ is minimum clump member radius). For non-overlapping members inertia of the clump is the sum of inertias from members. If integrateInertia=False sum of inertias from members is used (faster, but inaccurate).")
- .def("addToClump",&pyBodyContainer::addToClump,(python::arg("discretization")=15,python::arg("integrateInertia")=true),"Add body b (or a list of bodies) to an existing clump c. c must be clump and b may not be a clump member of c. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`).\n\nSee :ysrc:`examples/clumps/addToClump-example.py` for an example script.\n\n.. note:: If b is a clump itself, then all members will be added to c and b will be deleted. If b is a clump member of clump d, then all members from d will be added to c and d will be deleted. If you need to add just clump member b, :yref:`release<BodyContainer.releaseFromClump>` this member from d first.")
- .def("releaseFromClump",&pyBodyContainer::releaseFromClump,(python::arg("discretization")=15,python::arg("integrateInertia")=true),"Release body b from clump c. b must be a clump member of c. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`).\n\nSee :ysrc:`examples/clumps/releaseFromClump-example.py` for an example script.\n\n.. note:: If c contains only 2 members b will not be released and a warning will appear. In this case clump c should be :yref:`erased<BodyContainer.erase>`.")
- .def("replaceByClumps",&pyBodyContainer::replaceByClumps,(python::arg("discretization")=15,python::arg("integrateInertia")=true),"Replace spheres by clumps using a list of clump templates and a list of amounts; returns a list of tuples: ``[(clumpId1,[memberId1,memberId2,...]),(clumpId2,[memberId1,memberId2,...]),...]``. A new clump will have the same volume as the sphere, that was replaced. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`). \n\n\t *O.bodies.replaceByClumps( [utils.clumpTemplate([1,1],[.5,.5])] , [.9] ) #will replace 90 % of all standalone spheres by 'dyads'*\n\nSee :ysrc:`examples/clumps/replaceByClumps-example.py` for an example script.")
+ .def("appendClumped",&pyBodyContainer::appendClump,(python::arg("discretization")=0),"Append given list of bodies as a clump (rigid aggregate); returns a tuple of ``(clumpId,[memberId1,memberId2,...])``. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`).")
+ .def("clump",&pyBodyContainer::clump,(python::arg("discretization")=0),"Clump given bodies together (creating a rigid aggregate); returns ``clumpId``. Clump masses and inertia are adapted automatically when discretization>0. If clump members are overlapping this is done by integration/summation over mass points using a regular grid of cells (number of grid cells in one direction is defined as $R_{min}/discretization$, where $R_{min}$ is minimum clump member radius). For non-overlapping members inertia of the clump is the sum of inertias from members. If discretization<=0 sum of inertias from members is used (faster, but inaccurate).")
+ .def("addToClump",&pyBodyContainer::addToClump,(python::arg("discretization")=0),"Add body b (or a list of bodies) to an existing clump c. c must be clump and b may not be a clump member of c. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`).\n\nSee :ysrc:`examples/clumps/addToClump-example.py` for an example script.\n\n.. note:: If b is a clump itself, then all members will be added to c and b will be deleted. If b is a clump member of clump d, then all members from d will be added to c and d will be deleted. If you need to add just clump member b, :yref:`release<BodyContainer.releaseFromClump>` this member from d first.")
+ .def("releaseFromClump",&pyBodyContainer::releaseFromClump,(python::arg("discretization")=0),"Release body b from clump c. b must be a clump member of c. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`).\n\nSee :ysrc:`examples/clumps/releaseFromClump-example.py` for an example script.\n\n.. note:: If c contains only 2 members b will not be released and a warning will appear. In this case clump c should be :yref:`erased<BodyContainer.erase>`.")
+ .def("replaceByClumps",&pyBodyContainer::replaceByClumps,(python::arg("discretization")=0),"Replace spheres by clumps using a list of clump templates and a list of amounts; returns a list of tuples: ``[(clumpId1,[memberId1,memberId2,...]),(clumpId2,[memberId1,memberId2,...]),...]``. A new clump will have the same volume as the sphere, that was replaced. Clump masses and inertia are adapted automatically (for details see :yref:`clump()<BodyContainer.clump>`). \n\n\t *O.bodies.replaceByClumps( [utils.clumpTemplate([1,1],[.5,.5])] , [.9] ) #will replace 90 % of all standalone spheres by 'dyads'*\n\nSee :ysrc:`examples/clumps/replaceByClumps-example.py` for an example script.")
.def("getRoundness",&pyBodyContainer::getRoundness,(python::arg("excludeList")=python::list()),"Returns roundness coefficient RC = R2/R1. R1 is the theoretical radius of a sphere, with same volume as clump. R2 is the minimum radius of a sphere, that imbeds clump. If just spheres are present RC = 1. If clumps are present 0 < RC < 1. Bodies can be excluded from the calculation by giving a list of ids: *O.bodies.getRoundness([ids])*.\n\nSee :ysrc:`examples/clumps/replaceByClumps-example.py` for an example script.")
.def("clear", &pyBodyContainer::clear,"Remove all bodies (interactions not checked)")
.def("erase", &pyBodyContainer::erase,"Erase body with the given id; all interaction will be deleted by InteractionLoop in the next step.")
=== modified file 'scripts/checks-and-tests/checks/checkGravity.py'
--- scripts/checks-and-tests/checks/checkGravity.py 2013-08-29 10:30:31 +0000
+++ scripts/checks-and-tests/checks/checkGravity.py 2014-04-16 17:49:58 +0000
@@ -13,11 +13,10 @@
sphereRadius=0.05
tc = 0.001
en = 0.3
-es = 0.3
-
-
-params=utils.getViscoelasticFromSpheresInteraction(tc,en,es)
-sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,**params))
+et = 0.3
+
+
+sphereMat=O.materials.append(ViscElMat(density=Density,frictionAngle=frictionAngle,tc=tc,en=en,et=et))
v_down = -5.0
=== modified file 'scripts/checks-and-tests/checks/checkViscElEng.py'
--- scripts/checks-and-tests/checks/checkViscElEng.py 2013-12-04 15:43:55 +0000
+++ scripts/checks-and-tests/checks/checkViscElEng.py 2014-04-02 15:33:41 +0000
@@ -16,9 +16,7 @@
r2 = 0.002
-param = getViscoelasticFromSpheresInteraction(tc,en,et)
-
-mat1 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho,**param))
+mat1 = O.materials.append(ViscElMat(frictionAngle=fr,density=rho,tc=tc,en=en,et=et))
id1 = O.bodies.append(sphere(center=[0,0,0],radius=r1,material=mat1,fixed=True))
=== modified file 'scripts/checks-and-tests/checks/checkWeight.py'
--- scripts/checks-and-tests/checks/checkWeight.py 2014-01-20 08:45:23 +0000
+++ scripts/checks-and-tests/checks/checkWeight.py 2014-04-02 15:33:41 +0000
@@ -11,8 +11,7 @@
frictionAngle=radians(35)
density=2300
-params=utils.getViscoelasticFromSpheresInteraction(tc,en,es)
-defMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,**params)) # **params sets kn, cn, ks, cs
+defMat=O.materials.append(ViscElMat(density=density,frictionAngle=frictionAngle,tc=tc,en=en,et=es))
O.dt=.1*tc # time step