Commit 10c89c90 authored by Raphael Maurin's avatar Raphael Maurin
Browse files

HydroForceEngine: new fluctuation model for the example script + small correction

Add new simple discrete random walk fluctuation model, to be used with the new example script fluidizedBed.py
Change the condition for applying the fluid force from p>0 to p>=0, which is more appropriate
parent a105b9fc
......@@ -85,7 +85,7 @@ void LinearDragEngine::action(){
void HydroForceEngine::action(){
/* Application of hydrodynamical forces */
if (activateAverage==true) averageProfile(); //Calculate the average solid profiles
FOREACH(Body::id_t id, ids){
Body* b=Body::byId(id,scene).get();
if (!b) continue;
......@@ -94,7 +94,7 @@ void HydroForceEngine::action(){
if (sphere){
Vector3r posSphere = b->state->pos;//position vector of the sphere
int p = floor((posSphere[2]-zRef)/deltaZ); //cell number in which the particle is
if ((p<nCell)&&(p>0)) {
if ((p<nCell)&&(p>=0)) {
Vector3r liftForce = Vector3r::Zero();
Vector3r dragForce = Vector3r::Zero();
Vector3r vRel = Vector3r(vxFluid[p]+vFluctX[id],vFluctY[id],vFluctZ[id]) - b->state->vel;//fluid-particle relative velocity
......@@ -152,7 +152,6 @@ void HydroForceEngine::averageProfile(){
shared_ptr<Sphere> s=YADE_PTR_DYN_CAST<Sphere>(b->shape); if(!s) continue;
const Real zPos = b->state->pos[2]-zRef;
int Np = floor(zPos/deltaZ); //Define the layer number with 0 corresponding to zRef. Let the z position wrt to zero, that way all z altitude are positive. (otherwise problem with volPart evaluation)
if ((b->state->blockedDOFs==State::DOF_ALL)&&(zPos > s->radius)) continue;// to remove contribution from the fixed particles on the sidewalls.
// Relative fluid/particle velocity using also the associated fluid vel. fluct.
......@@ -396,6 +395,62 @@ void HydroForceEngine::turbulentFluctuationBIS(){
}
}
/* Velocity fluctuation determination. To execute at a given period*/
/* Should be initialized before running HydroForceEngine */
void HydroForceEngine::turbulentFluctuationFluidizedBed(){
/* check size */
size_t size=vFluctX.size();
if(size<scene->bodies->size()){
size=scene->bodies->size();
vFluctX.resize(size);
vFluctY.resize(size);
vFluctZ.resize(size);
}
/* reset stored values to zero */
memset(& vFluctX[0],0,size);
memset(& vFluctY[0],0,size);
memset(& vFluctZ[0],0,size);
/* Create a random number generator rnd() with a gaussian distribution of mean 0 and stdev 1.0 */
/* see http://www.boost.org/doc/libs/1_55_0/doc/html/boost_random/reference.html and the chapter 7 of Numerical Recipes in C, second edition (1992) for more details */
static boost::minstd_rand0 randGen((int)TimingInfo::getNow(true));
static boost::normal_distribution<Real> dist(0.0, 1.0);
static boost::variate_generator<boost::minstd_rand0&,boost::normal_distribution<Real> > rnd(randGen,dist);
double rand1 = 0.0;
double rand2 = 0.0;
double rand3 = 0.0;
/* Attribute a fluid velocity fluctuation to each body above the bed elevation */
FOREACH(Body::id_t id, ids){
Body* b=Body::byId(id,scene).get();
if (!b) continue;
if (!(scene->bodies->exists(id))) continue;
const Sphere* sphere = dynamic_cast<Sphere*>(b->shape.get());
if (sphere){
Vector3r posSphere = b->state->pos;//position vector of the sphere
int p = floor((posSphere[2]-zRef)/deltaZ); //cell number in which the particle is
// If the particle is inside the water and above the bed elevation, so inside the turbulent flow, evaluate a turbulent fluid velocity fluctuation which will be used to apply the drag.
// The fluctuation magnitude is linked to the value of the Reynolds stress tensor at the given position, a kind of local friction velocity ustar
if ((p<nCell)&&(posSphere[2]-zRef>0.)) { // Remove the particles outside of the flow
Real uStar2 = simplifiedReynoldStresses[p];
if (uStar2>0.0){
Real uStar = sqrt(uStar2);
rand1 = rnd();
rand2 = rnd();
rand3 = rnd();
vFluctZ[id] = rand1*uStar;
vFluctY[id] = rand2*uStar;
vFluctX[id] = rand3*uStar;
}
}
else{
vFluctZ[id] = 0.0;
vFluctY[id] = 0.0;
vFluctX[id] = 0.0;
}
}
}
}
......@@ -75,6 +75,7 @@ class HydroForceEngine: public PartialEngine{
void averageProfile();
void turbulentFluctuation();
void turbulentFluctuationBIS();
void turbulentFluctuationFluidizedBed();
public:
virtual void action();
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(HydroForceEngine,PartialEngine,"Apply drag and lift due to a fluid flow vector (1D) to each sphere + the buoyant weight.\n The applied drag force reads\n\n $F_{d}=\\frac{1}{2} C_d A\\rho^f|\\vec{v_f - v}| \\vec{v_f - v}$ \n\n where $\\rho$ is the medium density (:yref:`densFluid<HydroForceEngine.densFluid>`), $v$ is particle's velocity, $v_f$ is the velocity of the fluid at the particle center(:yref:`vxFluid<HydroForceEngine.vxFluid>`), $A$ is particle projected area (disc), $C_d$ is the drag coefficient. The formulation of the drag coefficient depends on the local particle reynolds number and the solid volume fraction. The formulation of the drag is [Dallavalle1948]_ [RevilBaudard2013]_ with a correction of Richardson-Zaki [Richardson1954]_ to take into account the hindrance effect. This law is classical in sediment transport. It is possible to activate a fluctuation of the drag force for each particle which account for the turbulent fluctuation of the fluid velocity (:yref:`velFluct<HydroForceEngine.velFluct>`). The model implemented for the turbulent velocity fluctuation is a simple discrete random walk which takes as input the Reynolds stress tensor $R^f_{xz}$ as a function of the depth, and allows to recover the main property of the fluctuations by imposing $<u_x'u_z'> (z) = <R^f_{xz}>(z)/\\rho^f$. It requires as input $<R^f_{xz}>(z)/\\rho^f$ called :yref:`simplifiedReynoldStresses<HydroForceEngine.simplifiedReynoldStresses>` in the code. \n The formulation of the lift is taken from [Wiberg1985]_ and is such that : \n\n $F_{L}=\\frac{1}{2} C_L A\\rho^f((v_f - v)^2_{top} - (v_f - v)^2_{bottom})$ \n\n Where the subscript top and bottom means evaluated at the top (respectively the bottom) of the sphere considered. This formulation of the lift account for the difference of pressure at the top and the bottom of the particle inside a turbulent shear flow. As this formulation is controversial when approaching the threshold of motion [Schmeeckle2007]_ it is possible to desactivate it with the variable :yref:`lift<HydroForceEngine.lift>`.\n The buoyancy is taken into account through the buoyant weight : \n\n $F_{buoyancy}= - \\rho^f V^p g$ \n\n, where g is the gravity vector along the vertical, and $V^p$ is the volume of the particle. This engine also evaluate the average particle velocity, solid volume fraction and drag force depth profiles, through the function averageProfile. This is done as the solid volume fraction depth profile is required for the drag calculation, and as the three are required for the independent fluid resolution.",
......@@ -122,6 +123,7 @@ class HydroForceEngine: public PartialEngine{
.def("averageProfile",&HydroForceEngine::averageProfile,"Compute and store the particle velocity (:yref:`vxPart<HydroForceEngine.vxPart>`, :yref:`vyPart<HydroForceEngine.vyPart>`, :yref:`vzPart<HydroForceEngine.vzPart>`) and solid volume fraction (:yref:`phiPart<HydroForceEngine.phiPart>`) depth profile. For each defined cell z, the k component of the average particle velocity reads: \n\n $<v_k>^z= \\sum_p V^p v_k^p/\\sum_p V^p$,\n\n where the sum is made over the particles contained in the cell, $v_k^p$ is the k component of the velocity associated to particle p, and $V^p$ is the part of the volume of the particle p contained inside the cell. This definition allows to smooth the averaging, and is equivalent to taking into account the center of the particles only when there is a lot of particles in each cell. As for the solid volume fraction, it is evaluated in the same way: for each defined cell z, it reads: \n\n $<\\phi>^z= \\frac{1}{V_{cell}}\\sum_p V^p$, where $V_{cell}$ is the volume of the cell considered, and $V^p$ is the volume of particle p contained in cell z.\n This function gives depth profiles of average velocity and solid volume fraction, returning the average quantities in each cell of height dz, from the reference horizontal plane at elevation :yref:`zRef<HydroForceEngine.zRef>` (input parameter) until the plane of elevation :yref:`zRef<HydroForceEngine.zRef>` plus :yref:`nCell<HydroForceEngine.nCell>` times :yref:`deltaZ<HydroForceEngine.deltaZ>` (input parameters). When the option :yref:`twoSize<HydroForceEngine.twoSize>` is set to True, evaluate in addition the average drag (:yref:`averageDrag1<HydroForceEngine.averageDrag1>` and :yref:`averageDrag2<HydroForceEngine.averageDrag2>`) and solid volume fraction (:yref:`phiPart1<HydroForceEngine.phiPart1>` and :yref:`phiPart2<HydroForceEngine.phiPart2>`) depth profiles considering only the particles of radius respectively :yref:`radiusPart1<HydroForceEngine.radiusPart1>` and :yref:`radiusPart2<HydroForceEngine.radiusPart2>` in the averaging.")
.def("turbulentFluctuation",&HydroForceEngine::turbulentFluctuation,"Apply turbulent fluctuation to the problem.")
.def("turbulentFluctuationBIS",&HydroForceEngine::turbulentFluctuationBIS,"Apply turbulent fluctuation to the problem with an alternative formulation.")
.def("turbulentFluctuationFluidizedBed",&HydroForceEngine::turbulentFluctuationFluidizedBed,"Apply turbulent fluctuation to the problem with another alternative formulation.")
);
};
REGISTER_SERIALIZABLE(HydroForceEngine);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment