Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ path = "examples/example_template/main.rs"
name = "cone_hopper"
path = "examples/cone_hopper/main.rs"

[[example]]
name = "bench_rotating_drum"
path = "examples/bench_rotating_drum/main.rs"

[profile.release]
opt-level = 3
lto = "fat"
Expand Down
79 changes: 79 additions & 0 deletions examples/bench_rotating_drum/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Rotating Drum Angle of Repose Benchmark

## Physics

This benchmark validates the **dynamic angle of repose** in a 2D rotating drum
against expected trends from DEM literature. In the rolling regime (Froude
number Fr = omega^2 * R / g << 1), granular material in a rotating drum forms a
flat free surface tilted at the **dynamic angle of repose**. This angle
depends primarily on the inter-particle friction coefficient.

## Setup

- **Geometry**: 2D (quasi-3D) drum of radius R = 50 mm, modeled as a 48-sided
polygon of plane walls (to capture tangential friction at the drum wall).
Periodic in y to enforce a single-layer quasi-2D configuration.
- **Particles**: 200 monodisperse spheres, radius = 2 mm, density = 2500 kg/m^3
(glass-like), Young's modulus = 5 MPa (softened for fast simulation).
- **Rotation**: Instead of rotating the drum, gravity is rotated at omega = 1.5
rad/s (Fr = 0.011). This is physically equivalent for Fr << 1 where
centrifugal/Coriolis effects are negligible.
- **Fill fraction**: ~40% of the drum cross-section.

## Measurement

After an 80,000-step settling phase and one full rotation of transient, the
free surface angle is measured every 500 steps by:

1. Rotating particle positions into a gravity-aligned frame
2. Binning particles by horizontal position
3. Finding the highest particle in each bin (free surface)
4. Fitting a line through the surface points using least squares
5. Computing the angle from the slope

## Validation

The benchmark runs 4 simulations with friction coefficients mu = 0.2, 0.3, 0.5, 0.7.

**Expected results** (from Li & Cleary 2015, Zhou et al. 2002, Wensrich & Katterfeld 2012):
- The angle of repose should fall within 15-45 degrees for typical DEM parameters
- The angle should **increase monotonically** with friction coefficient
- Typical values: mu=0.3 -> ~24 deg, mu=0.5 -> ~30 deg, mu=0.7 -> ~35 deg

## How to Run

```bash
# Single run with default friction (mu=0.5):
cargo run --release --example bench_rotating_drum --no-default-features \
-- examples/bench_rotating_drum/config.toml

# Full validation (4 friction values, ~15 min total):
cd examples/bench_rotating_drum
python validate.py

# Generate plots:
python plot.py
```

## Output Files

- `output/surface_angle.txt` — Time series of measured surface angle (step, time, angle_deg)
- `results.txt` — Summary: friction vs mean angle (generated by validate.py)
- `angle_vs_friction.png` — Angle of repose vs friction coefficient plot
- `angle_time_series.png` — Time series of surface angle for each friction value

## Assumptions and Simplifications

- **2D (quasi-3D)**: Thin slab periodic in y; single particle layer
- **Monodisperse**: All particles have the same radius
- **Soft particles**: E = 5 MPa (much softer than real glass) for reasonable timestep
- **Rotating gravity**: Equivalent to rotating drum for Fr << 1
- **Polygon drum**: 48-sided polygon approximates a smooth cylinder
- **Restitution = 0.5**: High damping for fast energy dissipation during settling
- **Rolling friction = 0.1**: Small but nonzero for realistic packing

## References

- Li, T., & Cleary, P. W. (2015). *Granular Matter*, 17, 367-382.
- Zhou, Y. C., et al. (2002). *Chemical Engineering Science*, 57, 3621-3638.
- Wensrich, C. M., & Katterfeld, A. (2012). *Granular Matter*, 14, 467-482.
85 changes: 85 additions & 0 deletions examples/bench_rotating_drum/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# ============================================================================
# Rotating Drum Angle of Repose Benchmark
# ============================================================================
#
# 2D (quasi-3D) rotating drum with monodisperse particles.
# The drum wall is a ring of frozen particles rotated kinematically.
# Full Hertz-Mindlin contact (with tangential friction) between wall and mobile
# particles drives the cascading flow.
#
# Froude number: Fr = omega^2 * R / g = 1.5^2 * 0.05 / 9.81 = 0.011
# This is well within the rolling regime (Fr < 0.1).

# ── Domain ────────────────────────────────────────────────────────────────────
[domain]
x_low = -0.01
x_high = 0.11 # drum fits in [0, 0.10]
y_low = 0.0
y_high = 0.005 # thin slab (~1.25 particle diameters)
z_low = -0.01
z_high = 0.11
periodic_x = false
periodic_y = true # quasi-2D: periodic in y
periodic_z = false

# ── Neighbor list ─────────────────────────────────────────────────────────────
[neighbor]
skin_fraction = 1.5
bin_size = 0.005 # ~1.25 particle diameters (m)
every = 10
check = true

# ── DEM materials ─────────────────────────────────────────────────────────────
[dem]
contact_model = "hertz"

# Type 0: mobile particles
[[dem.materials]]
name = "particles"
youngs_mod = 5.0e6 # Pa — soft particles for fast simulation
poisson_ratio = 0.3
restitution = 0.5 # moderate damping for fast settling
friction = 0.5 # sliding friction coefficient
rolling_friction = 0.1

# Type 1: wall particles (same properties; friction between wall & mobile
# particles is the mixed value from the material table)
[[dem.materials]]
name = "wall"
youngs_mod = 5.0e6
poisson_ratio = 0.3
restitution = 0.5
friction = 0.5
rolling_friction = 0.1

# ── Particle insertion ────────────────────────────────────────────────────────
# Insert mobile particles in a cylinder region inside the drum.
# Wall particles are created programmatically by WallParticlePlugin.
[[particles.insert]]
material = "particles"
count = 200 # ~40% fill of drum cross-section
radius = 0.002 # 2 mm radius (4 mm diameter)
density = 2500.0 # kg/m³ (glass-like)
velocity = 0.0
region = { type = "cylinder", center = [0.05, 0.05], radius = 0.042, axis = "y", lo = 0.0, hi = 0.005 }

# ── Gravity ───────────────────────────────────────────────────────────────────
[gravity]
gx = 0.0
gy = 0.0
gz = -9.81 # m/s²

# ── Run settings ──────────────────────────────────────────────────────────────
[run]
steps = 300000 # total steps (15.0 s at dt=5e-5)
thermo = 5000
dt = 5.0e-5 # s
dump_interval = 10000

# ── Dump output ───────────────────────────────────────────────────────────────
[dump]
format = "text"

# ── Output directory ──────────────────────────────────────────────────────────
[output]
directory = "examples/bench_rotating_drum/output"
Loading
Loading