henad-models 0.3.0

Example models for Henad, a parallel agent-based modelling engine.
Documentation
// Folds this tick's deposits into the field and decays it, one invocation per cell per layer.
//
// The CPU equivalent, `ScalarField::update`, scatters with `Combine::Max` into the next buffer,
// then decays it. This pass also resets each `accum` entry it reads, instead of clearing the
// whole buffer every tick.

#import henad::dispatch::linear_index

struct Params {
    n: u32,
    groups_x: u32,
    evaporation: f32,
    low: f32,
}

@group(0) @binding(0) var<storage, read_write> field: array<f32>;
// The step shader binds this as `atomic<u32>`. Only one invocation touches each entry here.
@group(0) @binding(1) var<storage, read_write> accum: array<u32>;
@group(0) @binding(2) var<uniform> params: Params;


@compute
@workgroup_size(256)
fn main(
    @builtin(local_invocation_id) lid: vec3<u32>,
    @builtin(workgroup_id) wid: vec3<u32>,
) {
    let i = linear_index(lid, wid, params.groups_x);
    if (i >= params.n) {
        return;
    }

    let deposited = bitcast<f32>(accum[i]);
    accum[i] = 0u;

    // Decay after the merge, so a fresh deposit is already one step old when read.
    var v = max(field[i], deposited) * params.evaporation;
    if (v < params.low) {
        // Without the floor a trail never disappears.
        v = 0.0;
    }
    field[i] = v;
}