Skip to content

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.

Code style: black

🚀 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:

python HGD/main.py json/hopper.json5

📋 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:**
sudo apt-get update
sudo apt-get install python3 python3-pip g++ cmake libomp-dev
**macOS:**
brew install python cmake libomp
**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

  1. Clone or download this repository:

    git clone https://github.com/benjym/HGD.git
    cd HGD
    

  2. Install HGD and dependencies:

    pip install -e .
    

This command installs all required Python packages and compiles the C++ extension modules.

  1. Verify installation:

    python -c "import HGD; print('HGD installed successfully!')"
    

  2. (Optional) Set up pre-commit hooks for development:

    pre-commit install
    

🎯 Running Simulations

Run a simulation using a JSON5 configuration file:

python HGD/main.py json/<config_file>.json5

Example:

python HGD/main.py json/hopper.json5

The simulation parameters are stored in the JSON5 file. Default parameters are available in json/defaults.json5.

📚 Documentation & Resources

💡 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,
}