Download this testcase.
2D Sand Pile Formation¶
This example simulates the formation of a sand pile through deposition of a large number of polydisperse circular particles between two rigid walls. The particles settle under gravity and form a stable pile through frictional contact.
Keywords¶
DEM, Friction, Granular Pile, Generation
from migflow import scontact, time_integration
import numpy as np
import shutil, os, sys
for n_particles in [20_000]:
# Seed for the rng
np.random.seed(0)
# output directory
# ----------------
outputdir = (
f"output_2_no_inertia_{n_particles}" if len(sys.argv) < 2 else sys.argv[1]
)
shutil.rmtree(outputdir, ignore_errors=True)
os.makedirs(outputdir)
# Physical parameters of the particles
# ------------------------------------
rho = 2650 # [kg.m**-3]
friction_coefficient_particle_particle = 0.4
friction_coefficient_particle_wall = 1.4
L = 1e-3 # [m] reference length
dmin = 0.6 * L # [m]
dmax = 2 * dmin
# Domain size in 2d of the cut of the cylinder
domain_length = 5e1 * L # [m]
domain_height = 7e2 * L # [m]
# Problem definition
# ------------------
problem = scontact.ParticleProblem(2)
problem.set_fixed_contact_geometry(0)
problem.set_friction_coefficient(
friction_coefficient_particle_particle, "Sand", "Sand"
)
problem.set_friction_coefficient(friction_coefficient_particle_wall, "Sand", "Wall")
# Geometry = an immovable body
floor = problem.add_body(
(0, 0), 0, 0
) # [0, 0] = origin of the reference coordinates of the body
wall_left = problem.add_body((0, 0), 0, 0)
wall_right = problem.add_body((0, 0), 0, 0)
x_shift = domain_length
# problem.add_segment_to_body([ -20 * domain_length + x_shift, 0 ], [ 20 * domain_length + x_shift, 0 ], floor, "Wall", "Wall") #position = relative to the origin of the body
x_bounds = np.array([-domain_length * 20 + x_shift, domain_length * 20 + x_shift])
r_bnd = dmin / 2
x_p = np.arange(x_bounds[0], x_bounds[1], 1.2 * r_bnd * 2)
for xp in x_p:
problem.add_particle_to_body([xp, -r_bnd], r_bnd, floor, "Wall")
problem.add_segment_to_body(
[-domain_length / 2 + x_shift, 0],
[-domain_length / 2 + x_shift, domain_height],
wall_left,
"Wall",
"Wall",
)
problem.add_segment_to_body(
[domain_length / 2 + x_shift, 0],
[domain_length / 2 + x_shift, domain_height],
wall_right,
"Wall",
"Wall",
)
# Particle initialisation
# -----------------------
problem_particles = np.asarray([], int)
x0 = np.array([-domain_length / 2 + x_shift, 0.8 * domain_height])
x1 = np.array([-domain_length / 2 + x_shift, 0])
x2 = np.array([domain_length / 2 + x_shift, 0])
x3 = np.array([domain_length / 2 + x_shift, 0.8 * domain_height])
bnd = np.array([x0, x1, x2, x3])
ri = np.random.uniform(dmin / 2, dmax / 2, n_particles)
x, r = scontact.fastdeposit_2d(bnd, 1.1 * ri)
r /= 1.1
for xi, ri in zip(x, r):
mi = np.pi * ri**2 * rho # [kg] mass of the particle
inertia = (mi * ri**2) / 2 * 100_000
new_particle = problem.add_particle(
xi, ri, mi, "Sand", inverse_inertia=1 / inertia
)
problem_particles = np.append(problem_particles, new_particle)
# Simulation parameters
# ---------------------
dt = 1e-4
tEnd = 0.15#5.0
outf = int(1e-2 / dt)
iit = 0
t = 0
mg = np.pi * rho * problem.r() ** 2 * [0.0, -9.81] # [m.s^-2]
velocity_walls = 0.05
# problem.set_compute_contact_forces(1)
# problem.body_invert_inertia()[ : ] = 0
while t < tEnd:
print(
f"{iit=: 04d} -- t/tEnd: {t:.3f}/{tEnd: .3f} -- {t/tEnd*100:02.2f}% completed",
end="\r",
)
if iit % outf == 0:
problem.write_mig(outputdir, t)
if t > 0.0:
problem.body_velocity()[wall_right, 1] = velocity_walls
problem.body_velocity()[wall_left, 1] = velocity_walls
time_integration._advance_particles(problem, mg, dt, 5, 1e-4 * dmin / 2)
t += dt
iit += 1
Plot¶
python3 -m migflow.plot.migplot output_2_no_inertia_20000 --actors particles