Heterarchical Granular Dynamics (HGD)
Disclaimer: This code is under development and is likely to have significant breaking changes in the near future. Many features are incomplete or redundant. Please contact the development team if you would like a tour.
A Python package for simulating the motion of granular materials as a result of the motion of voids. HGD models non-inertial problems and segregation particularly well for several systems.
🚀 Quick Start
New to HGD? Follow our comprehensive Getting Started Guide for step-by-step installation and your first simulation.
Already installed? Try running an example:
📋 Prerequisites
Before installing HGD, ensure you have:
- Python 3.9 or newer (Python 3.11+ recommended)
- C++ compiler (g++, Clang, or MSVC)
- CMake 3.15+
- OpenMP (for parallel execution)
📦 Quick install commands for dependencies
**Ubuntu/Debian:** **macOS:** **Windows:** - Install Python from [python.org](https://www.python.org/downloads/) - Install Visual Studio with C++ support - Install CMake from [cmake.org](https://cmake.org/download/)🔧 Installation
-
Clone or download this repository:
-
Install HGD and dependencies:
This command installs all required Python packages and compiles the C++ extension modules.
-
Verify installation:
-
(Optional) Set up pre-commit hooks for development:
🎯 Running Simulations
Run a simulation using a JSON5 configuration file:
Example:
The simulation parameters are stored in the JSON5 file. Default parameters are available in json/defaults.json5.
📚 Documentation & Resources
- Getting Started Guide - Complete installation and first simulation walkthrough
- Examples Guide - Detailed description of all example scenarios
- Troubleshooting - Solutions to common problems
- API Documentation - Comprehensive code reference
- Default Parameters - All configurable parameters with defaults
💡 Example Simulations
HGD includes several example configurations. Start with the quickest one:
# Quick validation (10 seconds)
python HGD/main.py json/minimal_test.json5
# Simple examples
python HGD/main.py json/collapse.json5 # ~1 minute
python HGD/main.py json/hopper.json5 # ~2 minutes
| Example | Description | Runtime |
|---|---|---|
minimal_test.json5 |
Installation verification | ~10 sec |
hopper.json5 |
Material flowing through a hopper | ~2 min |
collapse.json5 |
Column collapse under gravity | ~1 min |
footing.json5 |
Load bearing capacity test | ~3 min |
temperature.json5 |
Thermal effects in flow | ~5 min |
See the Examples Guide for complete descriptions and usage instructions.
🔍 Viewing Results
After running a simulation, results are saved in the output/ directory:
output/
└── <simulation_name>/
├── <parameter_set>/
│ ├── nu_*.png # Density snapshots
│ ├── s_*.png # Particle size snapshots
│ ├── nu.mp4 # Density video
│ └── s.mp4 # Particle size video
└── ...
🛠️ Configuration
Simulations are configured using JSON5 files. Key parameters include:
{
// Grid resolution
nx: 50, // Horizontal cells
ny: 50, // Vertical cells
nm: 20, // Internal states
// Physical properties
H: 1.0, // System height (m)
repose_angle: 30, // Friction angle (degrees)
s_m: 0.001, // Min particle size (m)
gsd_mode: 'bi', // Grain size distribution
// Simulation
t_f: 5.0, // Final time (s)
save_inc: 1, // Save frequency
plot: ['nu', 's'], // Variables to plot
}
See json/defaults.json5 for all available parameters.
❓ Troubleshooting
Installation fails? Check the Troubleshooting Guide for solutions to common issues: - C++ compiler not found - CMake errors - OpenMP missing - Memory errors - And more...
Need help? See the Support section below.
Documentation
You can read the docs here.
Support
You can contact the development team here.
Authors
Usage
The code is run by calling python void_migration/main.py <json5 file>. The parameters for the simulation are stored in the json5 file.
The default parameters, contained in defaults.json5 are as follows:
{
// resolution
nx : 10, // number of cells horizontally
ny : 10, // number of cells vertically
nm : 10, // number of cells in internal direction
P_stab : 0.5, // maximum probability to allow for stability
// geometry
H : 1, // physical height of the system (m)
theta : 0, // angle of gravity (0 is vertical, degrees)
g : 9.81, // gravitational acceleration (m/s^2)
boundaries : [], // "central_outlet", "multiple_outlets", "slope", "mara" or "pour"
masks: [], // list of masks to be used in the simulation
internal_geometry : false, // true if internal geometry is present, currently defined only for a single case
cyclic_BC : false, // true if cyclic BCs are used horizontally
cyclic_BC_y_angle : 0, // angle of the cyclic BCs (degrees)
refill : false, // should the particles come back in the top if they leave the bottom
outlet_rate : 1.0, // proportion of each timestep that the outlet is open
outlet_nu : 0, // solid fraction of the particles in the outlet
wall_motion : false, // should the walls move
// void migration model parameters
diag : 0,
lagrangian : false,
close_voids : false, // should the voids be closed after some time
max_diff_swap_length : 1, // maximum length of a diffusion swap
slope_stability_model : 'gradient', // 'stress' or 'gradient'
time_average : true, // should the chi, u and v fields be time averaged with exponential averaging
// material properties
repose_angle : 30, // (degrees)
gsd_mode : 'bi', // 'mono', 'bi' or 'poly'
large_concentration: 0.5, // concentration of large particles for bidisperse case
s_m : 0.0005, // minimum particle size (m)
nu_cs : 0.5, // critical state solid volume fraction
alpha : 4, // diffusivity parameter
seg_exponent : 1.0, // exponent used in segmentation probability
void_creation_param : 0.52, // void creation parameter - default taken from fitting linear lines to Fig 5c/d from https://www.annualreviews.org/docserver/fulltext/fl/40/1/annurev.fluid.40.111406.102142.pdf and taking ratio of slopes
cohesion : 0.0, // cohesion between particles (Pa)
// initial condition
fill_ratio : 0.25, // ratio of the domain that is filled with particles
nu_fill : 0.5, // solid fraction of the particles in the initial condition
IC_mode : "column", // where should the initial particles be, "column", "random", "top", "full" or "empty"
// temperature
calculate_temperature : false, // should the temperature be calculated
T_init : 20, // initial temperature (C)
// stress
calculate_stress : false, // should the stress be calculated
stress_mode : 'active', // 'isotropic', 'active', 'passive', 'K_0', 'anisotropic' or 'harr'
solid_density : 2700, // density of the solid particles (kg/m^3/m)
wall_friction_angle : 30, // friction coefficient between the walls and the particles
// gas
gas_density:1.225,
gas_viscosity:1.8e-5,
// saving
folderName : "output/", // name of the folder to save the data in
save_inc : 1, // how often to save the state of the system (timesteps)
t_f : 5, // final time to end the simulation (s)
plot : ['nu', 's', 'combined_plot'], // which variables to plot. Should at least include the ones to make videos.
videos : ['nu','s'], // which variables to save videos of.
save : [], // which variables to save. By default none.
mask_s_bar : false, // should the images of s_bar be masked to hide areas of low density
plot_colorbar : false, // should the colorbar be plotted
// density pressure model
nu_cs_mode : 'constant', // 'dynamic' or 'constant'
lambda_nu : 10, // rate of change of nu_cs
nu_1 : 0.5, // value of nu_cs at (or below) 1 kPa
point_load : false,
pad_width : 0.05, // width of the pad (m)
// parallel code
max_workers : 5, // max number of workers to run simultaneously. Default value is actually set void_migration.py
motion_model : 'd2q4_cpp', // 'd2q4_slow', 'd2q4_array' or 'd2q9_slow'
advection_model : 'freefall', // 'average_size', 'freefall' or 'stress'
inertia : false, // should the inertia term be included
// cycles
cycles : [], // list of dicts that define any cycles
inlet : 0, // amount of material added this cycle
outlet : 0, // amount of material removed this cycle
cycle_forever : false, // should the cycles be repeated indefinitely
charge_rate : 1, // rate of charge zone filling (kg/s)
sigma_charge : 0.1, // relative width of charge zone
// stopping
stop_event : null, // this is None in Python, but null in JavaScript
stop_after : 100, // number of timesteps to run with nothing happening before stopping
stopped_times : 0, // number of times the system has stopped
// diagnostics
show_optimal_resolution : false, // should the optimal resolution be shown on the screen at runtime
gui : null, // this is None in Python, but null in JavaScript
queue: null,
queue2: null,
}