yade-users team mailing list archive
-
yade-users team
-
Mailing list archive
-
Message #14366
Re: [Question #556258]: yade install problem
Question #556258 on Yade changed:
https://answers.launchpad.net/yade/+question/556258
Tanvir Hossain posted a new comment:
Hi Jan, here is the script.
#New version, amelioration wrt 20150715 :
#- IMPORTANT Modify the length of the vector evaluated from ndimz to ndimz. Works with Yade6 and is not adapted to the other cases
#- Add a limiter to avoid negative tau transmitted to the fluid (unphysical and source of numerical instabilities
#- Add a new configuration for the turbulentFluctuation function. Correspond to a new formulation of the C++ HydroForceEngine. Possibility to use a new turbulent fluctuation model where each particle fluctuation lifetime depends on its wall-normal position.
#- Add an option for fluidProfile imposed case.
#- Register the averaged velocity of the part1 and 2 in twoSize mode (Yade6)
#If activated, adapt the script to the associated computer path
Cluster = 0
philippeComputer = 0
julienComputer = 0
lamiaComputer = 0
raphaelComputer = 0
#Import libraries
from yade import pack, plot
import math
import random as rand
import numpy as np
np.set_printoptions(threshold=numpy.nan)
import yade.timing
import pylab as pyl
from matplotlib import pyplot as pyp
import matplotlib.gridspec as gridspec
#Register the path for later use (tests + save)
scriptPath = os.path.abspath(os.path.dirname(sys.argv[-1]))
##
## Main parameters of the simulation
##
diameterPart = 6e-3 #Diameter of the particles, in meter
densPart = 2500 #density of the particles, in kg/m3
waterDepth = 7. #Water depth in diameter
ndimz = 525 #Number of cells in the height
from nsmp1d_yade3D525Phi061 import *
lengthCell = 15 #Streamwise length of the periodic cell
widthCell = 15 #Spanwise length of the periodic cell
Nlayer = 10. #nb of layer of particle, in diameter
fluidHeight = (Nlayer+waterDepth)*diameterPart #Height of the flow from
the bottom of the sample
quasi2D = 0
twoSize = 0
#If twoSize option activated, overwrite the previous input #tanvir
if twoSize:
Nlayer1 = 10 #nb of layer of particle type 1
Nlayer2 = 1 #nb of layer of particle type 2
diameterPart1 = 6e-3 #Diameter of the particles type 1, in meter
diameterPart2 = 4e-3 #Diameter of the particles type 2, in meter
fluidHeight = Nlayer1*diameterPart1 + Nlayer2*diameterPart2 + 7*diameterPart1 #free surface position
diameterPart = diameterPart1 #Size 1 taken as reference
#Fluid library importation and precisions
phiPartMax = 0.61 #Value of the maximum volume fraction used for the thresholding
##
## Option of the simulation
##
#Imposed fluid profile? If yes, require to add a file fluid.py in the folder with inside the value of vxFluid vector + turbStress vector if you want to add turbulent fluctuations also.
imposedFluidPro = 0
#Temporary imposed profile: impose a fluid profile for 50 seconds (considered as equilibrium) and switch to the fluid resolution
initImposedFluidPro = 0
#Activation and choice of the fluid turbulent fluid velocity fluctuation. Cannot choose both. If none, will not apply fluct.
turbModel1 = 1
turbModel2 = 0
#Stress averaging: if activated, compute and save the stress tensor depth profile at each execution of measure()
stressSave = 0
pythonStressCalculation = 0 #use the python function instead of C++
#Option to put lateral walls, to break the biperiodicity and study the influence of walls.
lateralWalls = 0
#Option for time averaging of the DEM data before fluid resolution
timeAveraging = 0 #1 activated, 0 not activated
nbAv = 5. #number of averaging between the fluid resolution
#Averaging parameter : if activated, evaluate the average using python function partConcVelocity() instead of the C++ one
pythonAverage = 0
#debug stress mode, record all the quantities necessary to study the momentum balance in detail.
debugStress = 0
#Video
video = 1 #1, make a movie
if video:
snapshotEngine = 0 #To make the movie later using mencoder (require the qt.viewer open, obtain what you see)
paraview = 1 #To make the movie later using paraview (do not require the qt.viewer open, faster)
fps = 1. #frame per second #tanvir
##
## Secondary parameters of the simulation (less changed)
##
#Particles parameters
restitCoef = 0.5 #Restitution coefficient of the particles
partFrictAngle = atan(0.4) #friction angle of the particles, in radian
slope = 0.1 #Angle of the slope in radian #tanvir
# Fluid parameters
expoRZ = 3.1 # Richardson Zaki exponent for the hindrance function of the drag
dpdx = 0.0 #pressure gradient along streamwise direction
densFluid = 1000. #Density of the fluid
kinematicViscoFluid = 1e-6 #kinematic viscosity of the fluid
# Fluid simulation parameters (RANS), see fluidResolution function
dsig = np.zeros(ndimz)
dz = fluidHeight/(1.0*(ndimz-1))
sig=pyl.linspace(0e0,1e0,ndimz)
for i in range(ndimz-1): # calcul du pas d'espace
dsig[i] = sig[i+1] - sig[i]
#In order to fasten the script, some correspondance are supposed. Should be respected otherwise it does not work well
dtFluid = 1e-5 #Time step for the fluid resolution
fluidResolPeriod = 1e-2 #1/fluidResolPeriod = frequency of the calculation of the fluid profile
measurePeriod = (1e-1)*5 # We perform measurement every measurePeriod seconds #tanvir
savePeriod = 1e1 # We save the simulation (to be able to reload) every savePeriod seconds.
#Quasi 2D option
if quasi2D ==1:
print '\nQuasi 2D option activated\n'
lateralWalls = 1
widthCell = 6.5/6.
phiPartMax = 0.51
print 'phiPartMax = 0.51\n'
#
## Tests on the script
#
#Width check and Value of the fluid library and size of the system
if widthCell<2 and phiPartMax>0.6:
if widthCell<=1:
print 'Impossible to run simulation with width exactly equal to the diameter particle size !\n'
exit()
else:
print '\nCareful !! Uncoherence between the 2D character and the value of phiPartMax !! \n'
#Value of ndimz and dz
if ndimz != int(round(30*fluidHeight/diameterPart)):
print('\n!!Problem dz = d/{0} !!\nUse ndimz = {1} instead to have dz = d/30 (and change accordingly the fluid library import)\n'.format(diameterPart/fluidHeight*ndimz,int(round(30*fluidHeight/diameterPart))))
# if quasi2D!=1:
# exit()
#Option compatibility
if measurePeriod<fluidResolPeriod:
print '\nNot possible to have measurePeriod<fluidResolPeriod in the present configuration, modify the script to make measurement inside measure() instead of fluidResolution() !\n'
exit()
turbModel = 0
if turbModel1 ==1 or turbModel2==1:
turbModel = 1
if turbModel1 ==1 and turbModel2==1:
print "It is not possible to have the two fluctuations model in the same time ! \n Modify turbModel1 or turbModel2"
exit()
#Reloading simulation
reloadingSimulation = 0
if os.path.exists(scriptPath +'/paramSave.py'):
reloadingSimulation = 0#1 Out for now, useless, it is not working
##
## Initialization of the parameters
##
# Averaging/Save
vxPart = np.zeros(ndimz) # streamwise particle velocity depth profile
vyPart = np.zeros(ndimz) # spanmwise particle velocity depth profile
vzPart = np.zeros(ndimz) # normal particle velocity depth profile
qsMean = 0 #Mean bead flux
dragTerm = np.zeros(ndimz) # drag term transmitted to the fluid vector
averageDrag = np.zeros(ndimz) # drag field vector
stressProfile = getStressProfile(1.0,ndimz,dz,0.0,np.zeros(ndimz),np.zeros(ndimz),np.zeros(ndimz)) #Matrix full of zero
positionPartX = np.zeros(len(O.bodies)) #Defined global in order to use
positionPartZ = np.zeros(len(O.bodies)) #Defined global in order to use
velocityPartX = np.zeros(len(O.bodies)) # the saving function
velocityPartZ = np.zeros(len(O.bodies)) # the saving function
if twoSize:
phiPart1 = np.zeros(ndimz) # Concentration vector
vxPart1 = np.zeros(ndimz) # streamwise particle velocity depth profile
vyPart1 = np.zeros(ndimz) # spanwise particle velocity depth profile
vzPart1 = np.zeros(ndimz) # wall-normal particle velocity depth profile
phiPart2 = np.zeros(ndimz) # Concentration vector
vxPart2 = np.zeros(ndimz) # streamwise particle velocity depth profile
vyPart2 = np.zeros(ndimz) # spanwise particle velocity depth profile
vzPart2 = np.zeros(ndimz) # wall-normal particle velocity depth profile
#Initialization of the variables necessary for timeAveraging option
if timeAveraging:
n_dt = 1.
vxPart_dt = np.zeros(ndimz)
phiPart_dt = np.zeros(ndimz)
averageDrag_dt = np.zeros(ndimz)
if twoSize:
phiPart1_dt = np.zeros(ndimz)
averageDrag1_dt = np.zeros(ndimz)
vxPart1_dt = np.zeros(ndimz)
vyPart1_dt = np.zeros(ndimz)
vzPart1_dt = np.zeros(ndimz)
phiPart2_dt = np.zeros(ndimz)
averageDrag2_dt = np.zeros(ndimz)
vxPart2_dt = np.zeros(ndimz)
vyPart2_dt = np.zeros(ndimz)
vzPart2_dt = np.zeros(ndimz)
#Parameter initialized only if it is the initial simulation, otherwise they are charged
if reloadingSimulation !=1:
#Parameters which should be loaded and not initiallized if we recover the simulation
phiPart = np.zeros(ndimz) # Concentration vector
turbulentViscosity = np.zeros(ndimz) # Turbulent viscocity
waterDepth = 0.0 #Water depth : height of the "clear" water
vxFluid = np.zeros(ndimz) # Fluid velocity at time step n
turbStress = np.zeros(ndimz) #Turbulent stress vector
fileNumber = 0 #counter to save the files
###########################
## PARAMETERS DECLARATION##
###########################
#Geometrical configuration, define useful quantities
height = 5*fluidHeight #heigth of the periodic cell, bigger than the real height to take into account jumps
length = lengthCell*diameterPart #length of the stream
width = widthCell*diameterPart #width of the stream
gravityVector = Vector3(9.81*sin(slope),0.0,-9.81*cos(slope))
gravityVectorApplied = Vector3(0.0,0.0,-9.81*cos(slope))
groundPosition = height/4.0
VLayer = dz*length*width #Volume of a layer
partVolume = pi/6.*pow(diameterPart,3)
if twoSize:
partVolume1 = partVolume
partVolume2 = pi/6.*pow(diameterPart2,3)
#Particles contact law parameters
maxPressure = (densPart-densFluid)*phiPartMax*Nlayer*diameterPart*abs(gravityVector[2]) #Estimated max particle pressure ("hydrostatic")
normalStiffness = maxPressure*diameterPart*1e4 #Evaluate the minimal normal stiffness to be in the rigid particle limit (cf Roux and Combe 2002)
youngMod = normalStiffness/diameterPart #Young modulus of the particles from the stiffness wanted. Need that in order to use the restitution coefficient definition + more practical when polydisperse sample.
poissonRatio = 0.5 #poisson's ratio of the particles. Classical values, not much influence (see ref in Da Cruz et al 2005)
if twoSize:
youngMod1 = normalStiffness/diameterPart1
youngMod2 = normalStiffness/diameterPart2
O.materials.append(ViscElMat(en=restitCoef, et=0., young=youngMod1, poisson=poissonRatio, density=densPart, frictionAngle=partFrictAngle, label='Mat1'))
O.materials.append(ViscElMat(en=restitCoef, et=0., young=youngMod2, poisson=poissonRatio, density=densPart, frictionAngle=partFrictAngle, label='Mat2'))
#Material
O.materials.append(ViscElMat(en=restitCoef, et=0., young=youngMod, poisson=poissonRatio, density=densPart, frictionAngle=partFrictAngle, label='Mat'))
# if it is the initial simulation create the framework and the simulation loop, otherwise load it
if reloadingSimulation !=1:
##########################################
## FRAMEWORK CREATION (sphere, wall,...)##
##########################################
#Definition of the semi-periodic cell
O.periodic = True
O.cell.setBox(length,width,height)
#To be compatible with lateral walls
leftLimitY = 0.0
rightLimitY = width
centerLimitY = width/2.0
#If lateralWalls, add the walls and increase the cell size to avoid particle touching the walls to appear on the other side
if lateralWalls:
#Warn the user
print '\nlateralWalls option activated: mono-periodic boundary condition only !\n'
#Increase the cell size
O.cell.setBox(length,width+2*diameterPart,height)
#Modify accordingly the position of the center of the cell and the wall right and left position
leftLimitY = diameterPart
rightLimitY = width+diameterPart
centerLimitY = diameterPart + width/2.0
#Define the wall and add to the simulation
sidePlaneL = box(center= (length/2.0,leftLimitY,height/2.0),extents=(2000,0,height*10),fixed=True,wire = True,color = (1,0,0), material = 'Mat')
sidePlaneR = box(center= (length/2.0,rightLimitY,height/2.0),extents=(2000,0,height*10.0),fixed=True,wire=True, material = 'Mat',color = (0,0,1))
O.bodies.append([sidePlaneR,sidePlaneL])
if quasi2D == 1:
# Regular arrangement of spheres sticked at the bottom with random height
a = range(0,int(length/(diameterPart))) #The length is divided in diameter of particle
for b in a: #loop creating a set of sphere sticked at the bottom with a (uniform) random altitude comprised between 0.5 (diameter/12) and 5.5mm (11diameter/12) with steps of 0.5mm. The repartition is made around groundPosition. Exactly the same set up as the one from the experiment.
n = rand.randrange(0,12,1)/12.0*diameterPart #Define a number between 0 and 11/12 diameter with steps of 1/12 diameter (0.5mm in the experiment)
O.bodies.append(sphere((b*diameterPart,centerLimitY,groundPosition - 11*diameterPart/12.0/2.0 + n),diameterPart/2.,color=(0,0,0),fixed = True,material = 'Mat'))
else:
#Execute the file containing the database which is a 2D list containing the positions and radius of the particles composing the random fixed bed. Each position x,y (integer) contain a list of particle with position and radius at this place
if Cluster==1:
pathFixedBot = '/home/maurin/'
elif philippeComputer==1:
pathFixedBot = '/home/philippe/fixedBot/'
elif tanvir==1:
pathFixedBot = '/home/tanvir/output/'
elif julienComputer==1:
pathFixedBot = '/home/julien/Yade/scriptsRaphael/'
elif lamiaComputer==1:
pathFixedBot = '/home/lamia/periodicStream/'
elif raphaelComputer:
pathFixedBot = '/home/raphael/these/scripts/twoWayCoupling/'
else:
print '\nNo precised computer used ! Cannot resolve the fixed bottom file path accordingly ! Precise the computer used at line 12\n'
exit()
if diameterPart==6e-3:
if lengthCell>= 10:
execfile(pathFixedBot+'fixedBotDataLongMONO.py')
else:
execfile(pathFixedBot+'fixedBotDataShort.py')
print '\n Use the short database for random fixed bottom generation ! \n Be careful, polydisperse bottom !\n'
elif diameterPart==3e-3:
execfile(pathFixedBot+'fixedBotDataMONOd3.py')
elif diameterPart==12e-3:
execfile(pathFixedBot+'fixedBotDataMONOd12.py')
else:
print '\nno fixed bottom of the right size !! quit the simulation ! \n'
exit()
xMax = len(fixedBottomData) # Maximum size of the data base along x axis
yMax = len(fixedBottomData[0]) # Maximum size of the data base along y axis
x = rand.randrange(0,xMax,1) # Generate a uniform random number between 0 and the size of the data base along x (in diameterPart)
y = rand.randrange(0,yMax,1) # Generate a uniform random number between 0 and the size of the data base along y (in diameterPart)
#Starting from the random x and y position, loop over the length and width of the require fixed bed increasing x and y position (in diameterPart). Create then a sphere starting from 0 for x and y.
for i in range(0,lengthCell):
for j in range(0,int(widthCell)):
for k in fixedBottomData[(i+x)%xMax][(j+y)%yMax]:
O.bodies.append(sphere(center = ((i+k[0]/diameterPart-int(k[0]/diameterPart))*diameterPart,(j+k[1]/diameterPart-int(k[1]/diameterPart))*diameterPart+leftLimitY,groundPosition+k[2]),radius = k[3],material = 'Mat',fixed = True,color = (0,0,0)))
# Ground reference and Wall on the side
lowPlane = box(center= (length/2.0,centerLimitY,groundPosition),extents=(200,200,0),fixed=True,wire=False,color = (0.,1.,0.),material = 'Mat') #Build a plane to have a reference for the eyes
WaterSurface = box(center= (length/2.0,centerLimitY,groundPosition+fluidHeight),extents=(2000,width/2.0,0),fixed=True,wire=False,color = (0,0,1),material = 'Mat',mask = 0) #Build a plane to have a reference for the eyes of the position of the water surface. No interaction with the sphere
O.bodies.append([lowPlane,WaterSurface]) #add to simulation
#Count the initial number of particles (for later check)
initNumber = len(O.bodies)
#Create a loose cloud of particle inside the cell
partCloud = pack.SpherePack()
if twoSize:
diameterPart = diameterPart1
partVolume = partVolume1
Nlayer = Nlayer1
#Define the number of particle from the density of particle per unit length
if quasi2D==1:#to keep the correspondance with previous work where I putter NbPart = Nl*L/d
partNumber = int(Nlayer*lengthCell)
else:
partNumber = int(Nlayer*phiPartMax*diameterPart*length*width/partVolume) #Volume of beads
#Define the deposition height considering that the packing realised by make cloud is 0.2
depositionHeight = Nlayer*phiPartMax/0.2*diameterPart #Consider that the packing realised by make cloud is 0.2
#Create a cloud of partNumber particles
partCloud.makeCloud(minCorner=(0,leftLimitY,groundPosition+diameterPart+1e-4),maxCorner=(length,rightLimitY,groundPosition+depositionHeight),rRelFuzz=0., rMean=diameterPart/2.0, num = partNumber)
#Send this packing to simulation with material Mat
partCloud.toSimulation(material='Mat')
partNumber += initNumber
#Same for a second size of particles
if twoSize:
partCloud2 = pack.SpherePack()
if quasi2D==1:#to keep the correspondance with previous work where I putter NbPart = Nl*L/d
partNumber2 = int(Nlayer2*lengthCell*diameterPart1/diameterPart2)
else:
partNumber2 = int(Nlayer2*phiPartMax*diameterPart2*length*width/partVolume2) #Volume of beads
#Define the deposition height considering that the packing realised by make cloud is 0.2
depositionHeight2 =Nlayer2*diameterPart2*phiPartMax/0.2
partCloud2.makeCloud(minCorner=(0,leftLimitY,groundPosition+depositionHeight),maxCorner=(length,rightLimitY,groundPosition+depositionHeight+depositionHeight2),rRelFuzz=0., rMean=diameterPart2/2.0, num = partNumber2)
partCloud2.toSimulation(material='Mat2',color = (0,0,1)) #send this packing to simulation with material Mat2
#Increment the counters for check and deposition time input
depositionHeight+=depositionHeight2
partNumber+=partNumber2
#Evaluate the deposition time considering the free-fall time of the highest particle to the ground (overestimation)
depoTime = sqrt(depositionHeight*2/abs(gravityVector[2]))
#Check
if len(O.bodies)<partNumber:
print '\nProblem : too low number of beads in the sample compared with what was asked !\n'
exit()
# Collect the ids of the spheres which are dynamic and to which we should add the hydroforce
dv =1e-2 #Scale of the velocity imposed to the particle, no influence if not extreme case en = 1
idApplyForce = []
for b in O.bodies:
if isinstance(b.shape,Sphere) and b.dynamic:
if widthCell<2: #For the quasi 2D case, need to push slightly the spheres randomly in order to break the 2D configuration
deltaV = - dv + rand.uniform(0,2*dv)
b.state.vel[1]+=deltaV
idApplyForce+=[b.id]
#########################
#### SIMULATION LOOP#####
#########################
O.engines = [
# Reset the forces
ForceResetter(),
# Detect the potential contacts
InsertionSortCollider([Bo1_Sphere_Aabb(), Bo1_Wall_Aabb(),Bo1_Facet_Aabb(),Bo1_Box_Aabb()],label='contactDetection',allowBiggerThanPeriod = True),
# Calculate the different interactions
InteractionLoop(
[Ig2_Sphere_Sphere_ScGeom(), Ig2_Box_Sphere_ScGeom()],
[Ip2_ViscElMat_ViscElMat_ViscElPhys()],
[Law2_ScGeom_ViscElPhys_Basic()]
,label = 'interactionLoop'),
#Apply an hydrodynamic force to the particles
HydroForceEngine(densFluid = densFluid,viscoDyn = kinematicViscoFluid*densFluid,zRef = groundPosition,gravity = gravityVectorApplied,deltaZ = dz,expoRZ = expoRZ,lift = False,nCell = ndimz,vCell = length*width*dz ,vxFluid = vxFluid,phiPart = phiPart,vxPart = vxPart,ids = idApplyForce, label = 'addFluidForce', dead = True),
#Time averaging of the DEM data for fluid resolution
PyRunner(command = 'timeAveragingDEMdata()', virtPeriod = fluidResolPeriod/nbAv, label = 'timeAve', dead = True),
#Calculate the fluid profile using the routine
PyRunner(command = 'fluidResolution(fluidResolPeriod)', virtPeriod = fluidResolPeriod, label = 'fluidResol', dead = True),
#Calculate the turbulent fluctuations from a DRW random walk model
PyRunner(command = 'turbulentFluctuation()', virtPeriod = 0.1, label = 'turbFluct', dead = True),
#Measurement, output files
PyRunner(command = 'measure()', virtPeriod = measurePeriod, label = 'measurement', dead = True),
# Check if the packing is stabilized, if yes activate the hydro force on the grains and the slope.
PyRunner(command='gravityDeposition(depoTime)',virtPeriod = 0.01,label = 'packing'),
#GlobalStiffnessTimeStepper, determine the time step
GlobalStiffnessTimeStepper(defaultDt = 1e-4, viscEl = True,timestepSafetyCoefficient = 0.7, label = 'GSTS'),
# Integrate the equation and calculate the new position/velocities...
NewtonIntegrator(damping=0.2, gravity=gravityVector, label='newton')
]
#save the initial configuration to be able to recharge the simulation starting configuration easily
O.saveTmp()
#run
O.run()
#Add engines to make a video
if video:
if snapshotEngine:
print '\n video snapshot activated : takes snapshot of the qt.view as you see it\n'
O.pause()
O.engines += [SnapshotEngine(virtPeriod=1.0/fps,fileBase=scriptPath+'/figure/',label='snapshooter')]
elif paraview:
print '\n video paraview activated : register vtk file for later use of paraview (video...)\n'
O.engines += [VTKRecorder(virtPeriod=1/fps,recorders=['spheres','colors'],fileName=scriptPath+'/Paraview/p1-')]
else:
print '\nBe careful the video is not activated : need to specify snapshotEngine or paraview value.\n'
O.pause()
#Add a pyRunner to re-activate the fluctuations at 50s
if initImposedFluidPro:
O.engines += [PyRunner(command='activateFluidResol()',virtPeriod = 10,label = 'actFlResol')]
# else, it is a reloading of simulation, we load the necessary parameters and the simulation
else :
execfile(scriptPath +'/paramSave.py') #Execute the file containing the parameter registered previously
O.load(scriptPath + '/save.xml') #load the simulation where it stopped
print '\n RELOAD THE PREVIOUS SIMULATION\n'
if imposedFluidPro==1 or initImposedFluidPro==1:
execfile('fluid.py') #Import the fluid profile (+turbStress if necessary)
###################################################################################################################################
################################################### FUNCTION DEFINITION #########################################################
###################################################################################################################################
###### ######
### LET THE TIME FOR THE GRAVITY DEPOSITION AND ACTIVATE THE FLUID AT THE END ###
###### ######
def gravityDeposition(lim):
#At the very start, unbalanced force can be low as there is only few contacts, but it does not mean the packing is stable
#The rest will be run only if O.time>lim = estimation of the deposition time
if O.time<lim : return
else :
newton.damping = 0.0
packing.dead = True # Remove the present engine for the following
addFluidForce.dead = False # Activate the fluid force
fluidResol.dead = False # Activate the fluid profile resolution
# O.timingEnabled = True # Activate a function to check the time taken by the different function
# If option activated, Activate the turbulent fluctuation calculation
if turbModel==1:
turbFluct.dead = False
# If option activated, activate the function to perform cumulated time averaging on DEM for fluidResol
if timeAveraging:
timeAve.dead = False
#If twoSize C++ option activated, express the size of the two particles in the engine for later averaging
if twoSize and pythonAverage!=1:
addFluidForce.radiusPart1 = diameterPart1/2.
addFluidForce.radiusPart2 = diameterPart2/2.
addFluidForce.twoSize = True
if imposedFluidPro==1 or initImposedFluidPro==1:
fluidResol.dead = True #Force no fluid resolution
addFluidForce.vxFluid = vxFluid #pass the fluid velocity vector to add drag force value
addFluidForce.simplifiedReynoldStresses = turbStress #and reynolds stress tensor for fluctuations
else:
#Initialization of the fluid resolution
fluidResolution(fluidResolPeriod)
measurement.dead = False # Activate the Measurement
return
###############
#########################################
############# ###################
# Activate the fluid resolution. Used only when initImposedFluidPro option activated ###
############# ###################
def activateFluidResol():
global initImposedFluidPro
if O.time>50:
fluidResol.dead = False #Activate the fluid resolution
initImposedFluidPro = 0 #Put the option to zero, to avoid confusion in the script
actFlResol.dead = True #Kill the engine
#######################################################
###################################################################################################
############## Function to time-average the DEM data transmitted to fluid resolution ###########
###################################################################################################
def timeAveragingDEMdata():
global phiPart_dt
global vxPart_dt
global averageDrag_dt
global phiPart1_dt
global averageDrag1_dt
global vxPart1_dt
global vyPart1_dt
global vzPart1_dt
global phiPart2_dt
global averageDrag2_dt
global vxPart2_dt
global vyPart2_dt
global vzPart2_dt
global n_dt
#Re-initialized at each new averaging step
if n_dt==0:
vxPart_dt = np.zeros(ndimz)
phiPart_dt = np.zeros(ndimz)
averageDrag_dt = np.zeros(ndimz)
if twoSize:
phiPart1_dt = np.zeros(ndimz)
averageDrag1_dt = np.zeros(ndimz)
vxPart1_dt = np.zeros(ndimz)
vyPart1_dt = np.zeros(ndimz)
vzPart1_dt = np.zeros(ndimz)
phiPart2_dt = np.zeros(ndimz)
averageDrag2_dt = np.zeros(ndimz)
vxPart2_dt = np.zeros(ndimz)
vyPart2_dt = np.zeros(ndimz)
vzPart2_dt = np.zeros(ndimz)
#Evaluate the average vx,vy,vz,phi,drag profiles and store it in addFluidForce
addFluidForce.averageProfile()
#Store the values in
phiPart_dt += np.array(addFluidForce.phiPart)
vxPart_dt += np.array(addFluidForce.vxPart)
averageDrag_dt += np.array(addFluidForce.averageDrag)
if twoSize:
phiPart1_dt += np.array(addFluidForce.phiPart1)
averageDrag1_dt += np.array(addFluidForce.averageDrag1)
vxPart1_dt += np.array(addFluidForce.vxPart1)
vyPart1_dt += np.array(addFluidForce.vyPart1)
vzPart1_dt += np.array(addFluidForce.vzPart1)
phiPart2_dt += np.array(addFluidForce.phiPart2)
averageDrag2_dt += np.array(addFluidForce.averageDrag2)
vxPart2_dt += np.array(addFluidForce.vxPart2)
vyPart2_dt += np.array(addFluidForce.vyPart2)
vzPart2_dt += np.array(addFluidForce.vzPart2)
n_dt+=1.
###############
#########################################
################ #########################
########## EVALUATE THE TURBULENT FLUCTUATION ASSOCIATED TO EACH PARTICLE##########
################# #########################
# Argument: ndimz, turbulentViscosity, vxFluid, phiPart,
# Modification : turbFluct.virtPeriod, addFluidForce.bedElevation, addFluidForce.simplifiedReynoldStresses, addFluidForce.velFluct
addFluidForce.simplifiedReynoldStresses = np.zeros(ndimz)
addFluidForce.bedElevation = 0.
addFluidForce.turbulentFluctuation()
addFluidForce.fluctTime = np.zeros(len(O.bodies))
def turbulentFluctuation():
global waterDepth
global turbStress
#For stability requirement at the initialization stage
if O.time<depoTime+0.5:
print 'No turbulent fluctuation in the initialization process for stability reasons!'
turbFluct.virtPeriod = 0.5
else:
# Evaluate nBed, the position of the bed which is assumed to be located around the first maximum of concentration when considering decreasing z.
nBed = 0.
bedElevation = 0.
for n in range(1,ndimz):
# if there is a peak and its value is superior to 0.5, we consider it to be the position of the bed
if phiPart[ndimz - n] < phiPart[ndimz - n-1] and phiPart[ndimz - n] > 0.5 :
nBed = ndimz - n
waterDepth = (ndimz-1 - nBed)*dz
bedElevation = fluidHeight - waterDepth #Evaluate the bed elevation for the following
break
#(Re)Define the bed elevation over which fluid turbulent fluctuations will be applied.
addFluidForce.bedElevation = bedElevation
#First turbulent fluctuation model: a unique constant lifetime for the turbulent fluctuation, flucTimeScale
if turbModel1:
vMeanAboveBed = sum(vxFluid[nBed:])/(ndimz-nBed) # fluid elocity scale in the water depth
flucTimeScale = waterDepth/vMeanAboveBed # time scale of the fluctuation w_d/v, eddy turn over time
# New evaluation of the random fluid velocity fluctuation for each particle.
addFluidForce.turbulentFluctuation()
turbFluct.virtPeriod = flucTimeScale #Actualize when will be calculated the next fluctuations.
elif turbModel2:
# New evaluation of the random fluid velocity fluctuation for each particle.
addFluidForce.turbulentFluctuationBIS()
turbFluct.virtPeriod = min(addFluidForce.fluctTime)#Actualize when will be calculated the next fluct.
addFluidForce.dtFluct = min(addFluidForce.fluctTime)#Actualize the time step of the function
if O.time<depoTime+1: #To avoid important virtPeriod at the start, impose it for 1s. Fasten the transient.
turbFluct.virtPeriod = 0.1
if turbModel2: addFluidForce.dtFluct=0.1
###############
#########################################
###### ######
### CALL THE FLUID PROFILE RESOLUTION ROUTINE###
###### ######
#Arguments : ndimz, vxFluid, vxPart, dragTerm, densFluid, fluidHeight, sig, dsig, diameterPart, phiPartFluid, kinematicViscoFluid, densPart, dpdx, slope, tfin,d tFluid
#Modify : vxFluid, addFluidForce.vxFluid
testFluidResol = 0 # Test variable for the fluid resolution
def fluidResolution(tfin):
global phiPart
global vxPart
global vyPart
global vzPart
global vxFluid
global averageDrag
global turbulentViscosity
global testFluidResol
global dragTerm
global taufsi
global n_dt
global turbStress
if twoSize:
global averageDrag1
global phiPart1
global vxPart1
global vyPart1
global vzPart1
global averageDrag2
global phiPart2
global vxPart2
global vyPart2
global vzPart2
#Two different way of evaluating the average profiles: phiPart, vxPart, averageDrag, (+ same for 1 and 2 with twoSize)
#From python
if pythonAverage==1 or debugStress==1:
averageProfile()
#Or from C++
elif timeAveraging:#with multiple time averaging made previously in timeAveragingDEMdata
#Normalize the time averaged data
vxPart = vxPart_dt/n_dt
phiPart = phiPart_dt/n_dt
averageDrag = averageDrag_dt/n_dt
if twoSize:
phiPart1 = phiPart1_dt/n_dt
averageDrag1 = averageDrag1_dt/n_dt
vxPart1 = vxPart1_dt/n_dt
vyPart1 = vyPart1_dt/n_dt
vzPart1 = vzPart1_dt/n_dt
phiPart2 = phiPart2_dt/n_dt
averageDrag2 = averageDrag2_dt/n_dt
vxPart2 = vxPart2_dt/n_dt
vyPart2 = vyPart2_dt/n_dt
vzPart2 = vzPart2_dt/n_dt
#And report the other one (for usual measurement)
vyPart = np.array(addFluidForce.vyPart)
vzPart = np.array(addFluidForce.vzPart)
n_dt = 0
else:#with simple time averaging
if raphaelComputer!=1:
#Evaluate the average vx,vy,vz,phi,drag profiles and store it in addFluidForce
addFluidForce.averageProfile()
else:#On old ubuntu/Yade version, needs to do it differently:
#At next time step, Evaluate the average vx,vy,vz,phi,drag profiles and store it in addFluidForce
if testFluidResol == 0:
addFluidForce.activateAverage = True #Activate the average for next time step
fluidResol.iterPeriod = 1 #For it to be re-executed at next time step
testFluidResol = 1
return
## Import the necessary average variables for the fluid resolution from addFluidForce : phiPart,vxPart, averageDrag
vxPart = np.array(addFluidForce.vxPart)
vyPart = np.array(addFluidForce.vyPart)
vzPart = np.array(addFluidForce.vzPart)
phiPart = np.array(addFluidForce.phiPart)
averageDrag = np.array(addFluidForce.averageDrag)
#Back to the usual resolution period for next step
fluidResol.iterPeriod = -1 #For it not to be re-executed next time
fluidResol.virtPeriod = fluidResolPeriod #Back to the normal period
testFluidResol = 0 #Re-initialize the test
#If two particle size in the simulation, store complementary necessary average
if twoSize:
vCell = dz*width*length
#C++ function evaluating the depth profiles of solid volume fraction and solid velocities
phiPart1=np.array(addFluidForce.phiPart1)
phiPart2=np.array(addFluidForce.phiPart2)
averageDrag1=np.array(addFluidForce.averageDrag1)
averageDrag2=np.array(addFluidForce.averageDrag2)
vxPart1=np.array(addFluidForce.vxPart1)
vxPart2=np.array(addFluidForce.vxPart2)
vyPart1=np.array(addFluidForce.vyPart1)
vyPart2=np.array(addFluidForce.vyPart2)
vzPart1=np.array(addFluidForce.vzPart1)
vzPart2=np.array(addFluidForce.vzPart2)
#
## Prepare the variables for the fluid resolution
#
# Threshold the solid vol. fraction in the bed to remove the oscillations due to layering and avoid turbulence in the bed
phiPartFluid = np.zeros(ndimz)
for n in range(1,ndimz+1):
# If the concentration inside the bed reach the maximum concentration (imposed in the fluid solver). Then all the values of concentration under this one are going to be thresholded at phiPartMax, in order to damp the turbulence inside the bed.
if phiPart[ndimz - n] > phiPartMax:
for i in range(n,ndimz+1):
phiPartFluid[ndimz - i] = phiPartMax
break
#Otherwise we report the normal value.
phiPartFluid[ndimz - n] = phiPart[ndimz - n]
#Density of particle per unit volume N/Vcell:
nPart = phiPart[:ndimz]/partVolume
#Calculate the momentum transfer from the drag force interaction : N<fd>/Vcell
dragTerm = nPart*averageDrag[:ndimz]
if twoSize: #if two size, sum the two contributions n1<f1> + n2 <f2>, formulation necessary to keep energy conservation.
dragTerm = phiPart1[:ndimz]/partVolume1*averageDrag1[:ndimz] + phiPart2[:ndimz]/partVolume2*averageDrag2[:ndimz]
#Create Taufsi/rhof = dragTerm/(rhof(vf-vxp)) to transmit to the fluid code
taufsi = np.zeros(ndimz)
for i in range(1,ndimz):
urel = max(abs(vxFluid[i] - vxPart[i]),1e-5) #Limit the value to avoid division by 0
#Limit the max value of taufsi to the fluid resolution limit, i.e. 1/(10dt) and required positive (charact. time)
taufsi[i] = max(0,min(dragTerm[i]/urel/densFluid, pow(10*dtFluid,-1)))
#
## Call the routine for fluid resolution
#
[vxFluid_np,turbulentViscosity] = nsmp1d_yade(fluidHeight,sig,dsig,diameterPart,vxFluid,1e0-phiPartFluid[0:ndimz],densFluid,kinematicViscoFluid,vxPart[0:ndimz],phiPartFluid[0:ndimz],densPart,dpdx,slope,tfin,dtFluid,taufsi)
#Debugstress option
if debugStress==1:
global taufsiBIS
taufsiBIS = np.zeros(ndimz)
for i in range(1,ndimz):
urel = max(abs(vxFluid[i] - vxPart[i]),1e-5)
taufsiBIS[i] = min(dragTermBIS[i]/urel/densFluid, pow(10*dtFluid,-1))
global vxFluid_before
vxFluid_before = vxFluid
vxFluid = vxFluid_np
path = scriptPath + '/'+ str(fileNumber)+'_debug.py'
globalParam = ['vxPart','vxPartBIS','phiPart','phiPartBIS','vxFluid','vxFluid_before', 'averageDrag','averageDragBIS','dragTerm','dragTermBIS','taufsi','taufsiBIS']
Save(path, globalParam)
#update
vxFluid = vxFluid_np
#Modify the velocity in the HydroForceEngine which apply the force
addFluidForce.vxFluid = vxFluid
#Evaluate the turbulent shear stress for the turbulent fluctuations model and Shields number evaluation
turbStress = np.zeros(ndimz)
n = 0
for nu_t in turbulentViscosity[:-2]: # Turbulent viscosity is global, calculated in fluidResolution
turbStress[n] = nu_t*(vxFluid[n+1]-vxFluid[n])/dz #tau/rho
n+=1
addFluidForce.simplifiedReynoldStresses = turbStress #Actualize the Reynolds stress tensor (/rho)value
###############
#########################################
####### ########
### OUTPUT ###
####### ########
#Function which register the different quantities asked for post processing
#Arguments : len(O.bodies), O.bodies, scriptPath, fileNumber, measurePeriod, savePeriod, qsMean, phiPart, vxPart, vxFluid, turbulentViscosity, dragTerm, waterDepth
#Modify : fileNumber, 'paramSave.py', 'save.xml'
def measure():
global fileNumber
global qsMean
global stressProfile
global vxPart
global vyPart
global vzPart
global phiPart
global averageDrag
global phiPart1
global phiPart2
global averageDrag1
global averageDrag2
global vxPart1
global vxPart2
global vyPart1
global vyPart2
global vzPart1
global vzPart2
if imposedFluidPro==1 or initImposedFluidPro==1:#Then you should evaluate the average (as not done in fluidResolution)
if pythonAverage==1 or debugStress==1:
averageProfile()
#Or from C++
else:
#Evaluate the average vx,vy,vz,phi,drag profiles and store it in addFluidForce
addFluidForce.averageProfile()
#Replace it in the global python variables
vxPart = np.array(addFluidForce.vxPart)
vyPart = np.array(addFluidForce.vyPart)
vzPart = np.array(addFluidForce.vzPart)
phiPart = np.array(addFluidForce.phiPart)
averageDrag = np.array(addFluidForce.averageDrag)
#If two particle size in the simulation, store complementary necessary average
if twoSize:
vCell = dz*width*length
#C++ function evaluating the depth profiles of solid volume fraction and solid velocities
phiPart1=np.array(addFluidForce.phiPart1)
phiPart2=np.array(addFluidForce.phiPart2)
averageDrag1=np.array(addFluidForce.averageDrag1)
averageDrag2=np.array(addFluidForce.averageDrag2)
vxPart1=np.array(addFluidForce.vxPart1)
vxPart2=np.array(addFluidForce.vxPart2)
vyPart1=np.array(addFluidForce.vyPart1)
vyPart2=np.array(addFluidForce.vyPart2)
vzPart1=np.array(addFluidForce.vzPart1)
vzPart2=np.array(addFluidForce.vzPart2)
# Save all the following variables/split in two file for faster post processing
if stressSave == 1:
if pythonStressCalculation:
stressProfile = stressFieldCalculation(ndimz,dz*width*length,vxPart,dz)
else:
stressProfile = getStressProfile(dz*width*length,ndimz,dz,groundPosition,vxPart,vyPart,vzPart)
for n in range(0,ndimz):
stressProfile[0][n] = np.array(stressProfile[0][n]).reshape(1,9)[0]
stressProfile[1][n] = np.array(stressProfile[1][n]).reshape(1,9)[0]
globalParam = ['stressProfile']
path = scriptPath + '/'+ str(fileNumber)+'_stress.py'
Save(path, globalParam)
#if necessary output file with the positions and velocities of the particles
if 0:
global positionPartX
global positionPartZ
global velocityPartX
global velocityPartZ
positionPartX = np.zeros(len(O.bodies)) #Defined global in order to use
positionPartZ = np.zeros(len(O.bodies)) #Defined global in order to use
velocityPartX = np.zeros(len(O.bodies)) # the saving function
velocityPartZ = np.zeros(len(O.bodies)) # the saving function
for b in O.bodies:
if isinstance(b.shape,Sphere): # If it is a sphere
positionPartX[b.id] = b.state.pos[0]
positionPartZ[b.id] = b.state.pos[2]
velocityPartX[b.id] = b.state.vel[0]
velocityPartZ[b.id] = b.state.vel[2]
path = scriptPath + '/'+ str(fileNumber)+'_2.py'
globalParam = ['positionPartX', 'positionPartZ','velocityPartX', 'velocityPartZ']
Save(path, globalParam)
#Evaluate the dimensionless sediment rate to save
qsMean = sum(phiPart*vxPart)*dz/sqrt((densPart/densFluid - 1)*abs(gravityVector[2])*pow(diameterPart,3))
path = scriptPath + '/'+ str(fileNumber)+'.py'
globalParam = ['qsMean','phiPart','vxPart','vyPart','vzPart','vxFluid','turbulentViscosity','dragTerm','turbStress']
if twoSize:
globalParam =['qsMean','phiPart','vxPart','vyPart','vzPart','vxFluid','turbulentViscosity','dragTerm','turbStress', 'phiPart1','vxPart1','vyPart1','vzPart1','phiPart2','vxPart2','vyPart2','vzPart2']
Save(path, globalParam)
fileNumber +=1
#PHF if twoSize!=1 and O.time>=150:
# if O.time>=150:
# print '\n End of the simulation, simulated 150s as required !\n '
# O.pause()
# O.exitNoBacktrace()
#For reload, save sometimes the variables necessary to reload. (does not work anymore...)
if (fileNumber*measurePeriod)%savePeriod == 0:
#Save the simulation of yade the global python parameter in order to be able to recover the simulation
O.save(scriptPath + '/'+'save.xml')
# Save the global parameters which shouldn't be initialized to zero at the reloading.
globalParam = ['phiPart','fileNumber','vxFluid','turbulentViscosity','waterDepth','turbStress']
Save(scriptPath + '/'+'paramSave.py', globalParam)
##
# Evaluation and printing of the Shields number or qsMean.
if imposedFluidPro==1 or initImposedFluidPro==1:
print 'qsMean', qsMean
else:
if twoSize:
#Consider the average diameter in the layer in motion (which is the one to consider for Shields number)
dummy = np.where(phiPart[:ndimz]<0.8*phiPartMax)
phi1Sum = sum(phiPart1[dummy])
phi2Sum = sum(phiPart2[dummy])
#Volume weighted average diameter: N1Vp1 d1 + N2Vp2 d2/(N1Vp1 + N2Vp2) (*VCell/VCell)
diameterMix = (diameterPart1*phi1Sum + diameterPart2*phi2Sum)/(phi1Sum + phi2Sum)
else:
#Only one size in the simulation...
diameterMix = diameterPart
shieldsNumber = densFluid*max(turbStress)/((densPart-densFluid)*diameterMix*abs(gravityVector[2]))
print 'Shields number', shieldsNumber
###############
#########################################
########## ##########
### EVALUATE THE MEAN VOLUME FRACTION, DRAG AND STREAMWISE VELOCITY OF THE PARTICLES IN FUNCTION OF THE DEPTH###
########## ##########
#Arguments : ndimz, dz, length, Vlayer, groundPosition, radius, phiPart
#Modify : phiPart, vxPart, averageDrag
def averageProfile():
global phiPart
global averageDrag
global vxPart
global vyPart
global vzPart
global qsMean
global phiPart1
global averageDrag1
global phiPart2
global averageDrag2
#Initialization of the concentration and the streamwise velocity. (two times the water height in order to take into account the particles which are also above the fluid in the concentration and velocity profile
phiPart_loc = np.zeros(ndimz) #Mean particle concentration in function of depth
vxPart_loc = np.zeros(ndimz) #Mean particle velocity in function of depth
vyPart_loc = np.zeros(ndimz) #Mean particle velocity in function of depth
vzPart_loc = np.zeros(ndimz) #Mean particle velocity in function of depth
averageDrag_loc = np.zeros(ndimz) #Mean drag
phiPart1_loc = np.zeros(ndimz)
averageDrag1_loc = np.zeros(ndimz)
phiPart2_loc = np.zeros(ndimz)
averageDrag2_loc = np.zeros(ndimz)
if debugStress==1:
global vxPartBIS
global phiPartBIS
global averageDragBIS
global dragTermBIS
averageDragBIS_loc = np.zeros(ndimz)
phiPartBIS_loc = np.zeros(ndimz)
vxPartBIS_loc = np.zeros(ndimz)
dragTermBIS_loc = np.zeros(ndimz)
#Import the vector of velocity fluctuation associated to each particle in C++ code
VxFluct = addFluidForce.vFluctX
VzFluct = addFluidForce.vFluctZ
shiftPosition = 1.2*diameterPart #To shift the position
in order to avoid to have negative position (not compatible with the
volume calculation used later)
## Loop over the file to determine the concentration and the mean velocity
for b in O.bodies:
if isinstance(b.shape,Sphere): # If it is a sphere
z = b.state.pos[2]-groundPosition # Altitude of the particle redefined with the position of the bottom wall as the
radius = b.shape.radius
Np = int(z/dz) #Layer corresponding to the position of the center of the particle
#Evaluate the drag force undergone by the particle (Dallavalle formulation + Richardson Zaki correction)
uRel = Vector3(0.0,.0,0.0)
if Np<ndimz and Np>=0 : uRel = Vector3(vxFluid[Np]+VxFluct[b.id],0.0,VzFluct[b.id]) - b.state.vel
fDrag = 0.5*pi*pow(radius,2)*densFluid*(0.44*uRel.norm()+24.4*kinematicViscoFluid/(2*radius))*pow(1-phiPart[Np],-expoRZ)*uRel
if debugStress==1:
dragTermBIS_loc[Np]+=fDrag[0]
phiPartBIS_loc[Np]+=1.0
vxPartBIS_loc[Np]+=b.state.vel[0]
#Shift the position to avoid z<0 which induces some problems in the volume calculation. This is done here in order not to change the value of the drag. Evaluate all the parameters after this shift. (Np in particular is reevaluated
z+=shiftPosition
Np = int(z/dz) #new evaluation of Np after the shift. DO NOT REMOVE, IMPORTANT
minZ = int((z-radius)/dz) #Lowest layer occupied by the particle
maxZ = int((z+radius)/dz) #Highest layer occupied by the particle
deltaCenter = z - Np*dz #length between the real center of the particle and the position of the layer in which it is considered to be (Np).
#loop from the bottom to the top layer inside which the particle is contained
numLayer = minZ
while numLayer <= maxZ:
if numLayer>=0 and numLayer<ndimz:
zInf = (numLayer-Np-1)*dz + deltaCenter
zSup = (numLayer-Np)*dz + deltaCenter
if numLayer==minZ: zInf = -radius
if numLayer==maxZ: zSup = radius
#evaluate the volume of the part of the particle contained in the layer considered (the formula results from the analytical resolution of the integral of a layer of sphere in cylindrical coordinate)
V = math.pi*radius*radius*(zSup-zInf +(pow(zInf,3)-pow(zSup,3))/(3*radius*radius))
#Add the quantities to the (not normalized for now) mean particle velocity and concentration
phiPart_loc[numLayer]+=V
vxPart_loc[numLayer]+=V*b.state.vel[0]
vyPart_loc[numLayer]+=V*b.state.vel[1]
vzPart_loc[numLayer]+=V*b.state.vel[2]
averageDrag_loc[numLayer]+=V*fDrag[0]
if twoSize:
if radius==diameterPart1/2.0:
phiPart1_loc[numLayer]+=V
averageDrag1_loc[numLayer]+=V*fDrag[0]
elif radius==diameterPart2/2.0:
phiPart2_loc[numLayer]+=V
averageDrag2_loc[numLayer]+=V*fDrag[0]
#Increment for the next loop
numLayer+=1
#Normalize the weighted velocity/different mean quantities of each layer by the total particle volume in this layer
n = 0
for i in phiPart_loc:
if i: #if non zero, to avoid division by zero
vxPart_loc[n]/=i
vyPart_loc[n]/=i
vzPart_loc[n]/=i
averageDrag_loc[n]/=i
if twoSize:
if phiPart1_loc[n]:
averageDrag1_loc[n]/=phiPart1_loc[n]
if phiPart2_loc[n]:
averageDrag2_loc[n]/=phiPart2_loc[n]
n += 1
#Normalization of the concentration
phiPart_loc/=VLayer
phiPart1_loc/=VLayer
phiPart2_loc/=VLayer
if debugStress==1:
#Normalization
n = 0
for i in phiPartBIS_loc:#Loop over the number of part contained in each layer
#Normalize the average drag and particle velocity
if i:
averageDragBIS_loc[n] = dragTermBIS_loc[n]/i
vxPartBIS_loc[n]/=i
n+=1
phiPartBIS_loc*=(partVolume/VLayer)
dragTermBIS_loc/=VLayer
#Report the value in global variables
vxPartBIS = vxPartBIS_loc
phiPartBIS = phiPartBIS_loc
averageDragBIS = averageDragBIS_loc
dragTermBIS = dragTermBIS_loc
#Resize the vector to remove the effect of the shift previously introduced
phiPart_loc = Resize(phiPart_loc,int(shiftPosition/dz))
vxPart_loc = Resize(vxPart_loc,int(shiftPosition/dz))
vyPart_loc = Resize(vyPart_loc,int(shiftPosition/dz))
vzPart_loc = Resize(vzPart_loc,int(shiftPosition/dz))
averageDrag_loc = Resize(averageDrag_loc,int(shiftPosition/dz))
phiPart1_loc = Resize(phiPart1_loc,int(shiftPosition/dz))
averageDrag1_loc = Resize(averageDrag1_loc,int(shiftPosition/dz))
phiPart2_loc = Resize(phiPart2_loc,int(shiftPosition/dz))
averageDrag2_loc = Resize(averageDrag2_loc,int(shiftPosition/dz))
#Impose variables at the bottom to be consistent with the fluid formulation
averageDrag_loc[0] = 0.0
vxPart_loc[0] = 0.0
###Actualize the global variables
phiPart = phiPart_loc
vxPart = vxPart_loc
vyPart = vyPart_loc
vzPart = vzPart_loc
averageDrag = averageDrag_loc
phiPart1 = phiPart1_loc
averageDrag1 = averageDrag1_loc
phiPart2 = phiPart2_loc
averageDrag2 = averageDrag2_loc
#And the one associated to the fluid force application
addFluidForce.phiPart = phiPart_loc
return
###############
#########################################
###### ######
## Function to resize the vector removing the n first case##
###### ######
def Resize(a,n):
import numpy as np
l = len(a)
b = np.zeros(l)
k = 0
for i in range(n,l):
b[k] = a[i]
k+=1
return b
###############
#########################################
###### ######
### Save global variables ###
###### ######
#Function to save global variables in a python file which can be re-executed for later
def Save(filePathName, globalVariables):
f = open(filePathName,'w')
f.write('from numpy import *\n')
for i in globalVariables:
f.write(i + ' = '+repr(globals()[i]) + '\n')
f.close()
###############
#########################################
###### ######
### python Stress field calculation ###
###### ######
def stressFieldCalculation(ndimz,vCell,vxPart,dz):
#Initialization
granularTemp_loc = np.zeros(ndimz)
N_loc = np.zeros(ndimz)
stressTensorField_loc = []
kineticStressTensorField_loc = []
for i in range(0,ndimz):
stressTensorField_loc += [Matrix3(0,0,0,0,0,0,0,0,0)]
kineticStressTensorField_loc += [Matrix3(0,0,0,0,0,0,0,0,0)]
###
## Dynamical stress tensor part
###
for b in O.bodies:
Np = int((b.state.pos[2] - groundPosition)/dz)
if Np>=0 and Np<ndimz:
vFluct = b.state.vel - Vector3(vxPart[Np],vyPart[Np],vzPart[Np])
stressTensorField_loc[Np]+= -1/vCell*b.state.mass*vFluct.outer(vFluct)
kineticStressTensorField_loc[Np]+= -1/vCell*b.state.mass*vFluct.outer(vFluct)
granularTemp_loc[Np] += 1/3.0*(pow(vFluct[0],2) + pow(vFluct[1],2) + pow(vFluct[2],2))
N_loc[Np]+=1.0
###
## Love-Weber stress tensor part (contact
###
for Int in O.interactions:
if O.bodies[Int.id1].dynamic or O.bodies[Int.id2].dynamic:
Np1 = int((O.bodies[Int.id1].state.pos[2] - groundPosition)/dz)
Np2 = int((O.bodies[Int.id2].state.pos[2] - groundPosition)/dz)
#Vector joining the two particles (from id2 to id1)
x12 = O.bodies[Int.id1].state.pos - O.bodies[Int.id2].state.pos
#Contact vector of the two particles (defined as applied by id1 on id2)
fContact = Int.phys.normalForce + Int.phys.shearForce
#Remove the artificial effect of the periodic BC if one particle goes to the other side
x12 -= O.cell.hSize*Int.cellDist
#No reason to have one upon another, so check and define the min and max correpondingly
if Np2==Np1: #If the contact vector is entirely inside the layer, add it directly.
if Np1>=0 and Np1<ndimz:
stressTensorField_loc[Np1]+= 1/vCell*fContact.outer(x12) #outer product of contact force and branch vector
else:
if Np1>Np2: #Particle 1 above 2 (z component)
minZ = Np2
minPosZ = O.bodies[Int.id2].state.pos[2] - groundPosition
maxZ = Np1
maxPosZ = O.bodies[Int.id1].state.pos[2] - groundPosition
elif Np2>Np1: #Particle 2 above 1 (z component)
minZ = Np1
minPosZ = O.bodies[Int.id1].state.pos[2] - groundPosition
maxZ = Np2
maxPosZ = O.bodies[Int.id2].state.pos[2] - groundPosition
#Loop over the layers containing the vector connecting the two particles
numLayer = minZ
while numLayer<=maxZ:
if numLayer>=0 and numLayer<ndimz:
deltaZ = dz
if numLayer==minZ:
deltaZ = dz - (minPosZ - minZ*dz)
elif numLayer==maxZ:
deltaZ = maxPosZ - maxZ*dz
branchVectCell=deltaZ/abs(x12[2])*Vector3(x12[0],x12[1],x12[2])
#Add to stress tensor of the considered layer the part considered
stressTensorField_loc[numLayer]+= 1/vCell*fContact.outer(branchVectCell) #outer product
#Increment the layer
numLayer+=1
#Normalization
for n in range(0,len(N_loc)):
if N_loc[n]>0:
granularTemp_loc[n]/=N_loc[n]
return
[stressTensorField_loc,kineticStressTensorField_loc,granularTemp_loc]
###############
#########################################
###DEBUG/COMPARISON WITH getStress
#To obtain exactly the same as getStress, you need to shift groundPosition -> groundPosition - diameterPart + to remove the condition on the dynamics of the particles, to avoid the non contribution of the bottom wall and particles.
#This function might be also useful, it is reproducing exactly getStress in python
def getStressBIS(vCell):
stressTensorField = Matrix3(0,0,0,0,0,0,0,0,0)
for Int in O.interactions:
x12 = O.bodies[Int.id1].state.pos - O.bodies[Int.id2].state.pos
x12 -= O.cell.hSize*Int.cellDist
fContact = Int.phys.normalForce + Int.phys.shearForce
stressTensorField+= fContact.outer(x12) #outer product of contact force a
return stressTensorField/vCell
###############
#########################################
--
You received this question notification because your team yade-users is
an answer contact for Yade.