Skip to content

Commit 36cb645

Browse files
authored
DEM improvements (#756)
* fixes * fixing * fix and add tests * fix tests * fix test * revert change * fix tests * improve docs * update news * update * add new example * cleanup * format * Update NEWS.md * review changes * format * format * remove static arrays from dep * review comments * update * remove test_util.jl * review comments * fix style of example * remove again * remove again * update * set 0.3 * fix pertub
1 parent 74ac372 commit 36cb645

14 files changed

Lines changed: 599 additions & 125 deletions

File tree

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ used in the Julia ecosystem. Notable changes will be documented in this file for
2020

2121
### Features
2222

23+
- **Explicit Contact Models:** Added explicit contact models, `LinearContactModel` and `HertzContactModel`, to the DEM solver. (#756)
24+
2325
- **Particle Shifting Technique (PST) for Closed Systems:** Integrated the
2426
Particle Shifting Technique to enhance particle distribution, reduce clumping
2527
and prevent void regions due to tensile instability in closed system simulations. (#735)
@@ -88,6 +90,7 @@ used in the Julia ecosystem. Notable changes will be documented in this file for
8890
- Add particle packing for 2D (.asc) and 3D (.stl) geometries (#529)
8991

9092
### Compatibility Changes
93+
9194
- Dropped support for Julia 1.9
9295

9396
## Version 0.2.4

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "TrixiParticles"
22
uuid = "66699cd8-9c01-4e9d-a059-b96c86d16b3a"
33
authors = ["erik.faulhaber <44124897+efaulhaber@users.noreply.github.com>"]
4-
version = "0.3-dev"
4+
version = "0.3"
55

66
[deps]
77
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

docs/src/systems/dem.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# [Discrete Element Method](@id dem)
2+
23
The Discrete Element Method (DEM) is a computational technique widely used in physics, engineering,
34
and applied mathematics for simulating the mechanical behavior of granular materials, such as powders,
45
sand, soil, or rock, as well as other discontinua. Unlike continuum mechanics that treats materials as
@@ -7,13 +8,23 @@ detailed insights into the micro-mechanical behavior of materials, making it par
78
in fields such as geomechanics, material science, and mechanical engineering.
89

910
## Fundamental Principles
11+
1012
The core idea behind DEM is the discretization of a material system into a finite set of distinct,
1113
interacting mass elements (particles). These elements (particles) can vary in shape, size, and properties, and
1214
they interact with each other and possibly with their boundaries through contact forces and potential fields.
1315
The motion and behavior of each mass element are governed by Newton's laws of motion, accounting for the forces
1416
and moments acting upon them.
1517

18+
## API
19+
1620
```@autodocs
1721
Modules = [TrixiParticles]
1822
Pages = [joinpath("schemes", "solid", "discrete_element_method", "system.jl")]
1923
```
24+
25+
### Contact Models
26+
27+
```@autodocs
28+
Modules = [TrixiParticles]
29+
Pages = [joinpath("schemes", "solid", "discrete_element_method", "contact_models.jl")]
30+
```
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using TrixiParticles
2+
using OrdinaryDiffEq
3+
4+
# Physical parameters
5+
gravity = -9.81
6+
acceleration = (0.0, 0.0, gravity)
7+
8+
# ==========================================================================================
9+
# ==== Collapsing Sand Pile Simulation
10+
11+
# Resolution
12+
particle_spacing = 0.1
13+
14+
# Initial sand column dimensions and placement
15+
pile_size = (0.5, 0.5, 1.0)
16+
pile_min_z = particle_spacing * 0.1
17+
pile_center_z = pile_min_z + pile_size[3] / 2
18+
pile_center = (0.0, 0.0, pile_center_z)
19+
sand_density = 1600.0
20+
21+
# Container dimensions
22+
container_width = 10
23+
container_depth = 10
24+
container_height = 1.5
25+
26+
n_boundary_layers = 1
27+
boundary_thickness = n_boundary_layers * particle_spacing
28+
29+
# Sand column particles
30+
n_particles_pile = round.(Int, pile_size ./ particle_spacing)
31+
32+
min_coords_pile = (pile_center[1] - pile_size[1] / 2,
33+
pile_center[2] - pile_size[2] / 2,
34+
pile_min_z)
35+
sand_particles = RectangularShape(particle_spacing, n_particles_pile, min_coords_pile;
36+
density=sand_density, coordinates_perturbation=0.1)
37+
38+
# Boundary particles (floor and walls)
39+
min_boundary = (-container_width / 2, -container_depth / 2, 0.0)
40+
boundary_density = sand_density
41+
42+
floor_width = container_width + 2 * boundary_thickness
43+
floor_depth = container_depth + 2 * boundary_thickness
44+
n_particles_floor_x = round(Int, floor_width / particle_spacing)
45+
n_particles_floor_y = round(Int, floor_depth / particle_spacing)
46+
n_particles_floor_z = n_boundary_layers
47+
48+
min_coords_floor = (min_boundary[1] - boundary_thickness,
49+
min_boundary[2] - boundary_thickness,
50+
min_boundary[3] - boundary_thickness)
51+
floor_particles = RectangularShape(particle_spacing,
52+
(n_particles_floor_x, n_particles_floor_y,
53+
n_particles_floor_z),
54+
min_coords_floor; density=boundary_density, tlsph=true)
55+
boundary_particles = floor_particles
56+
57+
# ==========================================================================================
58+
# ==== Systems
59+
contact_model = LinearContactModel(1e6)
60+
damping_coefficient = 0.00001
61+
62+
sand_system = DEMSystem(sand_particles, contact_model;
63+
damping_coefficient=damping_coefficient,
64+
acceleration=acceleration, radius=0.4 * particle_spacing)
65+
66+
boundary_stiffness = 1.0e5
67+
boundary_system = BoundaryDEMSystem(boundary_particles, boundary_stiffness)
68+
69+
# ==========================================================================================
70+
# ==== Simulation
71+
semi = Semidiscretization(sand_system, boundary_system)
72+
tspan = (0.0, 2.0)
73+
ode = semidiscretize(semi, tspan)
74+
75+
info_callback = InfoCallback(interval=2000)
76+
saving_callback = SolutionSavingCallback(dt=0.02, prefix="")
77+
callbacks = CallbackSet(info_callback, saving_callback)
78+
79+
# Use a Runge-Kutta method with automatic (error based) time step size control
80+
sol = solve(ode, RDPK3SpFSAL49(),
81+
abstol=1e-5, # Default abstol is 1e-6 (may need to be tuned to prevent boundary penetration)
82+
reltol=1e-4, # Default reltol is 1e-3 (may need to be tuned to prevent boundary penetration)
83+
dtmax=1e-3, # Limit stepsize to prevent crashing
84+
dt=1e-7, # Initial step size
85+
save_everystep=false, callback=callbacks);

examples/dem/rectangular_tank_2d.jl

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ using OrdinaryDiffEq
44
gravity = -9.81
55

66
# ==========================================================================================
7-
# ==== Falling rocks
7+
# ==== Falling Rocks Simulation Setup
8+
#
9+
# This example sets up a simulation of falling rocks within a rectangular tank.
10+
# The tank is generated using a helper function (RectangularTank) which creates
11+
# a "fluid" region (containing the rock particles) and a "boundary" region (representing walls).
12+
# ==========================================================================================
813

914
particle_spacing = 0.1
1015

@@ -15,29 +20,48 @@ rock_density = 3000.0
1520
tank_width = 2.0
1621
tank_height = 4.0
1722

23+
# Create a rectangular tank. The tank has a "fluid" region for the rock particles
24+
# and a "boundary" region for the container walls.
1825
tank = RectangularTank(particle_spacing, (rock_width, rock_height),
1926
(tank_width, tank_height), rock_density,
2027
n_layers=2)
2128

2229
# ==========================================================================================
2330
# ==== Systems
31+
#
32+
# We adjust the rock positions upward to allow them to fall under gravity.
33+
# Next, we create a contact model and use it to build the rock (DEM) system.
34+
# ==========================================================================================
2435

25-
# Move the rocks up to let them fall
36+
# Move the rock particles up to let them fall
2637
tank.fluid.coordinates[2, :] .+= 0.5
27-
rock_system = DEMSystem(tank.fluid, 2 * 10e5, 10e9, 0.3, acceleration=(0.0, gravity))
38+
# small perturbation
39+
tank.fluid.coordinates .+= 0.01 .* (2 .* rand(size(tank.fluid.coordinates)) .- 1)
40+
41+
# Create a contact model.
42+
# Option 1: Hertzian contact model (uses elastic modulus and Poisson's ratio)
43+
contact_model = HertzContactModel(10e9, 0.3)
44+
# Option 2 (alternative): Linear contact model (constant normal stiffness)
45+
# contact_model = LinearContactModel(2 * 10e5)
46+
47+
# Construct the rock system using the new DEMSystem signature.
48+
rock_system = DEMSystem(tank.fluid, contact_model; damping_coefficient=0.0001,
49+
acceleration=(0.0, gravity), radius=0.4 * particle_spacing)
50+
51+
# Construct the boundary system for the tank walls.
2852
boundary_system = BoundaryDEMSystem(tank.boundary, 10e7)
2953

3054
# ==========================================================================================
3155
# ==== Simulation
56+
# ==========================================================================================
3257

3358
semi = Semidiscretization(rock_system, boundary_system)
3459

35-
tspan = (0.0, 5.0)
60+
tspan = (0.0, 4.0)
3661
ode = semidiscretize(semi, tspan)
3762

3863
info_callback = InfoCallback(interval=5000)
3964
saving_callback = SolutionSavingCallback(dt=0.02)
40-
4165
callbacks = CallbackSet(info_callback, saving_callback)
4266

4367
# Use a Runge-Kutta method with automatic (error based) time step size control

src/TrixiParticles.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export DensityDiffusion, DensityDiffusionMolteniColagrossi, DensityDiffusionFerr
7979
export BoundaryModelMonaghanKajtar, BoundaryModelDummyParticles, AdamiPressureExtrapolation,
8080
PressureMirroring, PressureZeroing, BoundaryModelLastiwka, BoundaryModelTafuni,
8181
BernoulliPressureExtrapolation
82+
export HertzContactModel, LinearContactModel
8283
export BoundaryMovement
8384
export examples_dir, validation_dir
8485
export trixi2vtk, vtk2trixi

src/io/write_vtk.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,15 @@ function write2vtk!(vtk, v, u, t, system; write_meta_data=true)
257257
return vtk
258258
end
259259

260+
function write2vtk!(vtk, v, u, t, system::DEMSystem; write_meta_data=true)
261+
vtk["velocity"] = view(v, 1:ndims(system), :)
262+
vtk["mass"] = [hydrodynamic_mass(system, particle)
263+
for particle in active_particles(system)]
264+
vtk["radius"] = [particle_radius(system, particle)
265+
for particle in active_particles(system)]
266+
return vtk
267+
end
268+
260269
function write2vtk!(vtk, v, u, t, system::FluidSystem; write_meta_data=true)
261270
vtk["velocity"] = [current_velocity(v, system, particle)
262271
for particle in active_particles(system)]

src/schemes/boundary/system.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ function Base.show(io::IO, system::BoundaryDEMSystem)
121121
@nospecialize system # reduce precompilation time
122122

123123
print(io, "BoundaryDEMSystem{", ndims(system), "}(")
124-
print(io, system.boundary_model)
125124
print(io, ") with ", nparticles(system), " particles")
126125
end
127126

@@ -267,6 +266,10 @@ end
267266
return system.coordinates
268267
end
269268

269+
@inline function current_velocity(v, system::BoundaryDEMSystem, particle)
270+
return zero(SVector{ndims(system), eltype(system)})
271+
end
272+
270273
@inline function current_velocity(v, system::BoundarySPHSystem, particle)
271274
return current_velocity(v, system, system.movement, particle)
272275
end

0 commit comments

Comments
 (0)