Module dem_base
@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
File called during the DEM step.
Expand source code
# -*- encoding=utf-8 -*-
from yade import pack, utils, plot, export
import pickle
import numpy as np
# -----------------------------------------------------------------------------#
# Functions called once
# -----------------------------------------------------------------------------#
def create_materials():
'''
Create materials.
'''
O.materials.append(FrictMat(young=E, poisson=Poisson, frictionAngle=atan(0.5), density=density, label='frictMat'))
O.materials.append(FrictMat(young=E, poisson=Poisson, frictionAngle=0, density=density, label='frictlessMat'))
# -----------------------------------------------------------------------------#
def create_grains():
'''
Recreate level set from data extrapolated with phase field output.
'''
print("Creating level set")
for i_grain in range(len(L_sdf_i_map)):
# grid
spacing = L_x_L_i[i_grain][1]-L_x_L_i[i_grain][0]
grid = RegularGrid(
min=(min(L_x_L_i[i_grain]), min(L_y_L_i[i_grain]), -extrude_z*spacing/2),
nGP=(len(L_x_L_i[i_grain]), len(L_y_L_i[i_grain]), extrude_z),
spacing=spacing
)
# grid
O.bodies.append(
levelSetBody(grid=grid,
distField=L_sdf_i_map[i_grain].tolist(),
material=0)
)
O.bodies[-1].state.blockedDOFs = 'zXYZ'
O.bodies[-1].state.pos = L_rbm_to_apply[i_grain]
O.bodies[-1].state.refPos = L_rbm_to_apply[i_grain]
# -----------------------------------------------------------------------------#
def create_walls():
'''
Recreate walls.
'''
# -x
O.bodies.append(wall((L_pos_w[0], 0, 0), 0, material=1))
# +x
O.bodies.append(wall((L_pos_w[1], 0, 0), 0, material=1))
# -y
O.bodies.append(wall((0, L_pos_w[2], 0), 1, material=1))
# +y
O.bodies.append(wall((0, L_pos_w[3], 0), 1, material=1))
# -----------------------------------------------------------------------------#
def create_plots():
'''
Create plots during the DEM step.
'''
plot.plots = {'iteration': ('f_w_control'), 'iteration ': ('pos_w_control'), \
'pos_w_control': ('f_w_control'), 'iteration ': ('unbalForce')}
# -----------------------------------------------------------------------------#
def compute_dt():
'''
Compute the time step used in the DEM step.
'''
O.dt = 0.2*SpherePWaveTimeStep(radius=5*m_size, density=density, young=E)
# -----------------------------------------------------------------------------#
def create_engines():
'''
Create engines.
Overlap based on the distance
Ip2:
kn = given
ks = given
Law2:
Fn = kn.un
Fs = ks.us
'''
O.engines = [
VTKRecorder(recorders=["lsBodies"], fileName='./vtk/ite_PFDEM_'+str(i_DEMPF_ite)+'_', iterPeriod=0, multiblockLS=True, label='initial_export'),
ForceResetter(),
InsertionSortCollider([Bo1_LevelSet_Aabb(), Bo1_Wall_Aabb()], verletDist=0.00),
InteractionLoop(
[Ig2_LevelSet_LevelSet_ScGeom(), Ig2_Wall_LevelSet_ScGeom()],
[Ip2_FrictMat_FrictMat_FrictPhys(kn=MatchMaker(algo='val', val=kn), ks=MatchMaker(algo='val', val=ks))],
[Law2_ScGeom_FrictPhys_CundallStrack(sphericalBodies=False)]),
PyRunner(command='applied_force()',iterPeriod=1, label='apply_force'),
NewtonIntegrator(damping=0.1, label='newton', gravity=(0, 0, 0)),
PyRunner(command='add_data()',iterPeriod=1, label='data'),
PyRunner(command='check()',iterPeriod=1, label='checker')
]
if print_vtk:
O.engines = O.engines + [VTKRecorder(recorders=["lsBodies"], fileName='./vtk/yade/', iterPeriod=1000, multiblockLS=True, label='export')]
# -----------------------------------------------------------------------------#
# Functions called multiple times
# -----------------------------------------------------------------------------#
def applied_force():
'''
Apply a constant force on the control wall.
'''
v_plate_max = 1000*(1-0.6)/(O.dt*20000) # modify here
kp = v_plate_max/(force_applied_target*0.1)
Fy = O.forces.f(wall_control.id)[1]
if Fy == 0:
wall_control.state.vel = (0, -v_plate_max, 0)
else :
dF = Fy - force_applied_target
v_try_abs = kp*abs(dF)
# maximal speed is applied to top wall
if v_try_abs < v_plate_max :
wall_control.state.vel = (0, np.sign(dF)*v_try_abs, 0)
else :
wall_control.state.vel = (0, np.sign(dF)*v_plate_max, 0)
# -----------------------------------------------------------------------------#
def check():
'''
Try to detect a steady-state.
A maximum number of iteration is used.
'''
if O.iter < max(n_ite_max*0.01, n_steady_state_detection):
return
window = plot.data['unbalForce'][-n_steady_state_detection:]
if O.iter > n_ite_max or max(window) < steady_state_detection:
if print_all_dem:
plot.plot(noShow=True).savefig('plot/dem/'+str(i_DEMPF_ite)+'.png')
#plot.saveDataTxt('plot/dem/'+str(i_DEMPF_ite)+'.txt', vars=('iteration', 'unbalForce', 'pos_w_control', 'f_w_control'))
if print_dem:
plot.plot(noShow=True).savefig('plot/dem.png')
#plot.saveDataTxt('plot/dem.txt', vars=('iteration', 'unbalForce', 'pos_w_control', 'f_w_control'))
O.pause() # stop DEM simulation
# -----------------------------------------------------------------------------#
def add_data():
'''
Add data to plot :
- iteration
- unbalanced force (mean resultant forces / mean contact force)
- position of the control plate
- force applied on the control plate
'''
plot.addData(iteration=O.iter, unbalForce=round(unbalancedForce(),3),\
f_w_control=O.forces.f(wall_control.id)[1], pos_w_control=(wall_control.state.refPos[1]-wall_control.state.pos[1])/dim_ref)
# -----------------------------------------------------------------------------#
# Load data
# -----------------------------------------------------------------------------#
# other
density = 2000
# from main
with open('data/main_to_dem.data', 'rb') as handle:
dict_save = pickle.load(handle)
Poisson = dict_save['Poisson']
E = dict_save['E']
kn = dict_save['kn']
ks = dict_save['ks']
force_applied_target = dict_save['force_applied']
n_ite_max = dict_save['n_ite_max']
i_DEMPF_ite = dict_save['i_DEMPF_ite']
L_pos_w = dict_save['L_pos_w']
n_steady_state_detection = dict_save['n_steady_state_detection']
steady_state_detection = dict_save['steady_state_detection']
print_all_dem = dict_save['print_all_dem']
print_dem = dict_save['print_dem']
print_vtk = dict_save['print_vtk']
extrude_z = dict_save['extrude_z']
m_size = dict_save['m_size']
# from phase field interpolation
with open('data/level_set.data', 'rb') as handle:
dict_save = pickle.load(handle)
L_sdf_i_map = dict_save['L_sdf_i_map']
L_rbm_to_apply = dict_save['L_rbm_to_apply']
L_x_L_i = dict_save['L_x_L_i']
L_y_L_i = dict_save['L_y_L_i']
# -----------------------------------------------------------------------------#
# Plan simulation
# -----------------------------------------------------------------------------#
# materials
create_materials()
# create grains and walls
create_grains()
create_walls()
# define loading
wall_control = O.bodies[-1]
dim_ref = O.bodies[-1].state.refPos[1]-O.bodies[-2].state.refPos[1]
# Engines
create_engines()
# time step
compute_dt()
# plot
create_plots()
# -----------------------------------------------------------------------------#
# MAIN DEM
# -----------------------------------------------------------------------------#
O.run()
O.wait()
# -----------------------------------------------------------------------------#
# Output
# -----------------------------------------------------------------------------#
L_displacement = []
for i_grain in range(len(L_sdf_i_map)):
trans = np.array(O.bodies[i_grain].state.pos - O.bodies[i_grain].state.refPos)
rot_a = O.bodies[i_grain].state.ori.toAngleAxis()[0]
rot_v = O.bodies[i_grain].state.ori.toAngleAxis()[1]
L_displacement.append([trans[0], trans[1],\
rot_a, rot_v[0], rot_v[1], rot_v[2]])
L_contact = []
for i in O.interactions:
# work only on grain-grain contact
if isinstance(O.bodies[i.id1].shape, LevelSet) and isinstance(O.bodies[i.id2].shape, LevelSet):
if i.id1 < i.id2:
id_smaller = i.id1
id_larger = i.id2
else:
id_smaller = i.id2
id_larger = i.id1
L_contact.append([id_smaller, id_larger, i.geom.penetrationDepth, np.array([i.phys.normalForce[0], i.phys.normalForce[1], i.phys.normalForce[2]])])
# Save data
dict_save = {
'L_displacement': L_displacement,
'L_contact': L_contact,
'delta_y_sample': O.bodies[-1].state.pos[1]-O.bodies[-2].state.pos[1]
}
with open('data/dem_to_main.data', 'wb') as handle:
pickle.dump(dict_save, handle, protocol=pickle.HIGHEST_PROTOCOL)
Functions
def create_materials()
-
Create material.
Expand source code
def create_materials(): ''' Create materials. ''' O.materials.append(FrictMat(young=E, poisson=Poisson, frictionAngle=atan(0.5), density=density, label='frictMat')) O.materials.append(FrictMat(young=E, poisson=Poisson, frictionAngle=0, density=density, label='frictlessMat'))
def create_grains()
-
Recreate level set from data extrapolated with phase field output.
Expand source code
def create_grains(): ''' Recreate level set from data extrapolated with phase field output. ''' print("Creating level set") for i_grain in range(len(L_sdf_i_map)): # grid spacing = L_x_L_i[i_grain][1]-L_x_L_i[i_grain][0] grid = RegularGrid( min=(min(L_x_L_i[i_grain]), min(L_y_L_i[i_grain]), -extrude_z*spacing/2), nGP=(len(L_x_L_i[i_grain]), len(L_y_L_i[i_grain]), extrude_z), spacing=spacing ) # grid O.bodies.append( levelSetBody(grid=grid, distField=L_sdf_i_map[i_grain].tolist(), material=0) ) O.bodies[-1].state.blockedDOFs = 'zXYZ' O.bodies[-1].state.pos = L_rbm_to_apply[i_grain] O.bodies[-1].state.refPos = L_rbm_to_apply[i_grain]
def create_walls()
-
Recreate walls.
Expand source code
def create_walls(): ''' Recreate walls. ''' # -x O.bodies.append(wall((L_pos_w[0], 0, 0), 0, material=1)) # +x O.bodies.append(wall((L_pos_w[1], 0, 0), 0, material=1)) # -y O.bodies.append(wall((0, L_pos_w[2], 0), 1, material=1)) # +y O.bodies.append(wall((0, L_pos_w[3], 0), 1, material=1))
def create_plots()
-
Create plots during the DEM step.
Expand source code
def create_plots(): ''' Create plots during the DEM step. ''' plot.plots = {'iteration': ('f_w_control'), 'iteration ': ('pos_w_control'), \ 'pos_w_control': ('f_w_control'), 'iteration ': ('unbalForce')}
def compute_dt()
-
Compute the time step used in the DEM step.
Expand source code
def compute_dt(): ''' Compute the time step used in the DEM step. ''' O.dt = 0.2*SpherePWaveTimeStep(radius=5*m_size, density=density, young=E)
def create_engines()
-
Create engines.
Overlap based on the distance Ip2: kn = given ks = given Law2: Fn = kn.un Fs = ks.us
Expand source code
def create_engines(): ''' Create engines. Overlap based on the distance Ip2: kn = given ks = given Law2: Fn = kn.un Fs = ks.us ''' O.engines = [ VTKRecorder(recorders=["lsBodies"], fileName='./vtk/ite_PFDEM_'+str(i_DEMPF_ite)+'_', iterPeriod=0, multiblockLS=True, label='initial_export'), ForceResetter(), InsertionSortCollider([Bo1_LevelSet_Aabb(), Bo1_Wall_Aabb()], verletDist=0.00), InteractionLoop( [Ig2_LevelSet_LevelSet_ScGeom(), Ig2_Wall_LevelSet_ScGeom()], [Ip2_FrictMat_FrictMat_FrictPhys(kn=MatchMaker(algo='val', val=kn), ks=MatchMaker(algo='val', val=ks))], [Law2_ScGeom_FrictPhys_CundallStrack(sphericalBodies=False)]), PyRunner(command='applied_force()',iterPeriod=1, label='apply_force'), NewtonIntegrator(damping=0.1, label='newton', gravity=(0, 0, 0)), PyRunner(command='add_data()',iterPeriod=1, label='data'), PyRunner(command='check()',iterPeriod=1, label='checker') ] if print_vtk: O.engines = O.engines + [VTKRecorder(recorders=["lsBodies"], fileName='./vtk/yade/', iterPeriod=1000, multiblockLS=True, label='export')]
def applied_force()
-
Apply a constant force on the control wall.
Expand source code
def applied_force(): ''' Apply a constant force on the control wall. ''' v_plate_max = 1000*(1-0.6)/(O.dt*20000) # modify here kp = v_plate_max/(force_applied_target*0.1) Fy = O.forces.f(wall_control.id)[1] if Fy == 0: wall_control.state.vel = (0, -v_plate_max, 0) else : dF = Fy - force_applied_target v_try_abs = kp*abs(dF) # maximal speed is applied to top wall if v_try_abs < v_plate_max : wall_control.state.vel = (0, np.sign(dF)*v_try_abs, 0) else : wall_control.state.vel = (0, np.sign(dF)*v_plate_max, 0)
def check()
-
Try to detect a steady-state.
A maximum number of iteration is used.
Expand source code
def check(): ''' Try to detect a steady-state. A maximum number of iteration is used. ''' if O.iter < max(n_ite_max*0.01, n_steady_state_detection): return window = plot.data['unbalForce'][-n_steady_state_detection:] if O.iter > n_ite_max or max(window) < steady_state_detection: if print_all_dem: plot.plot(noShow=True).savefig('plot/dem/'+str(i_DEMPF_ite)+'.png') #plot.saveDataTxt('plot/dem/'+str(i_DEMPF_ite)+'.txt', vars=('iteration', 'unbalForce', 'pos_w_control', 'f_w_control')) if print_dem: plot.plot(noShow=True).savefig('plot/dem.png') #plot.saveDataTxt('plot/dem.txt', vars=('iteration', 'unbalForce', 'pos_w_control', 'f_w_control')) O.pause() # stop DEM simulation
def add_data()
-
Add data to plot
- iteration - unbalanced force (mean resultant forces / mean contact force) - position of the control plate - force applied on the control plate
Expand source code
def add_data(): ''' Add data to plot : - iteration - unbalanced force (mean resultant forces / mean contact force) - position of the control plate - force applied on the control plate ''' plot.addData(iteration=O.iter, unbalForce=round(unbalancedForce(),3),\ f_w_control=O.forces.f(wall_control.id)[1], pos_w_control=(wall_control.state.refPos[1]-wall_control.state.pos[1])/dim_ref)