HOPPER
§5 · Method

Method

What the silo is, how the four measurements are made, which numbers are identifiable and which are not, and where the colour on this page came from. Every figure on this site is produced by code in this repository from a stated seed or a stated block.

§5.1

The silo

Soft-sphere discrete element, after Cundall & Strack (1979). Grains carry a linear spring-dashpot normal contact and a tangential spring with history, capped by Coulomb friction:

F_n = k_n·δ − γ_n·v_n        no cohesion, no tension
F_t = −k_t·ξ − γ_t·v_t,  |F_t| ≤ μ·F_n

ξ is the accumulated tangential displacement of that contact — a spring with history, not a drag. The distinction is the whole model: a viscous tangential force lets go the instant sliding stops, so a bed built on one flows like a liquid and can never arch. Static friction is what holds an arch up, and static friction is a spring.

Grains in the silo on the front page
440
Grains in the packing measurement
516
Radius spread
±10%, to stop the bed crystallising
Normal stiffness k_n
2000
Friction μ, grain and wall
0.5
Timestep
5 × 10⁻⁴ — a hundredth of a contact
Packing fraction reached
0.852, overlaps 0.46% of a diameter
Corrected for overlap
0.844
Coordination number
3.48

The grains are deliberately unequal. Identical discs in two dimensions crystallise into a triangular lattice within seconds of settling, and a crystal is a different material — it discharges in bursts along its own lattice planes. A soft-sphere packing fraction is also quoted with its overlaps, because without them it is a number you can push past the geometric limit by softening the springs.

§5.2

Run it yourself

The same solver, with the orifice on a slider. Everything below is computed in your tab from the width you choose — including whether it arches, which you can make happen by taking the gate under 4.5 grain widths and waiting.

Grains through
0
Rate
Under a tenth of exit speed
State
flowing

Friction is on the slider because it is what makes an arch possible at all. Take it to zero and the bed becomes a liquid: it will not arch at any width, and its rate starts caring about how full it is.

colour is speed
slow → fast
§5.3

The exponent this experiment cannot measure

Beverloo's law says the rate goes as (D − k·d)^β, with β = 3/2 in two dimensions. Two free parameters, nine precisely measured rates. Fit them, and you get a confident wrong answer.

Discharge rate against orifice widthtwo models, nine rates
061218244.55.87.08.39.5orifice width D, in grain diametersgrains out per √(d/g)both curves are drawn
β held at 3/2, k fittedβ fitted, k = 0
Both curves are drawn, and they lie on each other. One says the exponent is three halves with an empty rim of 1.828 grain diameters; the other says it is 2.059 with no rim at all. Nine rates measured over 2.1-fold in orifice width cannot separate them, and no amount of extra precision in the rates would — the difference between the models is smaller than the range of the experiment can resolve. C2

Letting both float and taking the best R² returns β = 2.059 ± 0.038 with k pinned at zero: an exponent wrong by a third, quoted to four figures, with a standard error that says it is certain. Nothing is wrong with the fit. The residual cannot see the error, because the data do not contain the answer.

Every pair that describes the same nine ratesR² printed above each point
1.311.631.940.000.250.500.751.001.251.501.752.002.252.50k — the empty rim assumed, in grain diametersβ0.99760.99760.99750.99730.99700.99670.99620.99550.99460.99330.9916β = 3/2, what the theory says
β slides from 2.06 to 1.24 as k is walked from 0 to 2.5, for a total R² spread of 0.00608. Over a 2.1-fold range of orifice widths, a power law and a shifted power law are the same curve. C2

So the law is not fitted here. It is decomposed, and each factor is measured on its own: rate = φ · w_eff · v.

Exit speed against orifice widthlog–log, nothing fitted alongside it
2.63.03.43.84.256789orifice width D (log)exit speed (log)slope 0.555 ± 0.024dashed: exactly one half
Grains leaving a wider hole leave FASTER — exponent 0.555 ± 0.024, against a theoretical one half. That is the non-obvious half of Beverloo, and it is the half that needs no fitting at all. Packing in the aperture stays between 0.654 and 0.679 across the whole range, so it is not doing any of the work. C2

What is left is the flowing width, and it comes out linear in the orifice with an empty rim of 2.02 grain diameters — a Beverloo k a laboratory would recognise. The exponent is then a consequence of two measurements rather than a knob. The site publishes the ridge instead of the exponent, because the ridge is what the experiment actually determined.

§5.4

Confidence classes

A structural design code does not print a load and leave you to guess where it came from. Every figure on this site carries one of these, and the build fails if one is published without.

C1

Measured

Read from a public Base node by a script in this repository, at a stated block, with no API key and no proxy in the path. Re-runnable by anyone; it will not return the same numbers, because the chain has moved.

C2

Computed

Produced by the discrete element model in js/granular.js from a stated seed. Deterministic: the same seed returns the same figure on any machine, and the build recomputes it rather than trusting the last answer.

C3

Assumed

A parameter chosen, or a value taken from published work rather than reproduced here. Everything in this class is a place the site could be wrong without any of its own checks noticing.

Symbols

SymbolUnitMeaning
dgrain diameter. Every length on this site is in these.
Ddorifice width — the gate.
Wdbin width.
hdhead: the height of material above the orifice.
φpacking fraction: how much of a volume is grain rather than gap.
kdthe empty rim at the orifice that grain centres do not enter.
βthe exponent in Beverloo's law. Three halves in two dimensions.
γthe exponent of discharge rate on head. Exactly ½ for a liquid.
μfriction coefficient, grain on grain and grain on wall.
ggravity. Set to 1, so time is in units of √(d/g).
W(D)grains/√(d/g)discharge rate.
§5.5

Every check the build runs

These are imported from tools/verify-model.mjs and tools/palette.mjs rather than transcribed, so this page cannot name a check that does not exist. Any failure fails the build.

  • PASS exit speed goes as a square root of the aperture, not linearlyexponent 0.555 ± 0.024 against D, R² 0.9876; theory brackets 0.50–0.73
  • PASS packing in the aperture does not depend on the apertureφ from 0.654 to 0.679 across a 2.1× range of D
  • PASS the flowing width is linear in the orifice (R² ≥ 0.99)w_eff = 1.199·D − 2.42, R² 0.9977 ⇒ an empty rim of 2.02 d
  • PASS Beverloo with β held at 3/2 fits the nine rates (R² ≥ 0.99)k = 1.828 d, R² = 0.9964, residual 0.38 grains per √(d/g)
  • PASS a plain power law with no offset fits them just as wellβ = 2.059 ± 0.038, R² = 0.9976
  • PASS the exponent is NOT identifiable from these ratesβ spans 1.24–2.06 for a total R² spread of 0.00608 over a 2.1× range of D
  • PASS the empty rim is one a laboratory would recognise (0.5 – 3 d)2.02 d from the decomposition, 1.828 d from the held fit
  • PASS head exponent is far below a liquid's ½ — every bin with head leftγ = 0.171 ± 0.035 over 14 bins, head ×7.9; Torricelli is exactly 0.5
  • PASS head exponent is far below a liquid's ½ — after the first 2 binsγ = 0.135 ± 0.036 over 12 bins, head ×6.9; Torricelli is exactly 0.5
  • PASS the answer does not depend on where the start-up is cutγ = 0.171 with the first bins, 0.135 without
  • PASS the head range measured is at least fourfoldhead 51.3 → 6.5 d, a factor of 7.9
  • PASS clogging vanishes at or below D/d = 5first orifice with no arch in 12 runs: D/d = 4.5
  • PASS clogging probability falls with orifice width2.5:67% 3:58% 3.5:33% 4:33% 4.5:0% 5:0% 6:0%
  • PASS a fifth or more of the bed is standing still at half drained32.2% of what remains has never moved; peak 68.8%
  • PASS the floor stops feeling extra weight — Janssen saturationover the tested range the weight grew ×14.8 and the load on the floor grew ×6.2
  • PASS an exponential saturation describes it (R² ≥ 0.97)λ = 23.7 d, p∞ = 219.0, R² = 0.9943
  • PASS the implied stress ratio K is a plausible one (0.2 – 1.2)K = 0.42 from λ = W/(2μK)
  • PASS at the deepest fill the walls carry most of the weight59% of the weight never reaches the floor
  • PASS packing is granular once its overlaps are taken off (0.78 – 0.86)φ 0.8518, mean overlap 0.46% of d → 0.8439; coordination 3.48
§5.6

Where the colour came from

The palette is the thesis in another medium. Grind a solid finer and it gets lighter and less saturated. Nothing was added and nothing was removed: the absorption per unit path is a property of the material and does not change. What changes is how far light travels between scattering events.

The model is Kubelka–Munk, the standard two-flux treatment of an opaque diffusing layer: R∞ = 1 + K/S − √((K/S)² + 2K/S), with the scattering coefficient going as one over the grain size. So grain diameter is the one parameter that moves a pigment along its own ramp — the same material, divided more finely, looks like more.

d = 8L 0.57 · C 0.137
#638517
d = 4L 0.65 · C 0.144
#7B9E2D
d = 2L 0.73 · C 0.141
#94B548
d = 1L 0.79 · C 0.131
#AAC865
d = 0.5L 0.84 · C 0.113
#BED782
d = 0.25L 0.88 · C 0.093
#CEE29D

Hue comes from the absorber, not from that one parameter: a one-parameter family is a line, and a line is not a palette. The ground is a two-band absorber — the shape that makes vegetation green. The accents are a broad blue band (dry grain), its complement (aeration air) and an absorption edge (rust, and the thing that stops). Every lightness that has to clear a contrast target is solved for that target rather than nudged until it looked right.

  • PASS ȳ peaks at 555 nm (photopic maximum)554.3 nm
  • PASS x̄ peaks at 600 nm ± 6599.8 nm
  • PASS z̄ peaks at 446 nm ± 8448.3 nm
  • PASS a flat 50% reflector has no huechroma 0.00000
  • PASS K/S → 0 gives R∞ → 10.999965
  • PASS K/S → ∞ gives R∞ → 00.00e+0
  • PASS sward: finer grind is lighter, monotonically0.881 > 0.840 > 0.788 > 0.725 > 0.651 > 0.570
  • PASS husk: finer grind is lighter, monotonically0.879 > 0.842 > 0.797 > 0.744 > 0.684 > 0.615
  • PASS oxide: finer grind is lighter, monotonically0.734 > 0.662 > 0.585 > 0.508 > 0.434 > 0.365
  • PASS vent: finer grind is lighter, monotonically0.746 > 0.672 > 0.590 > 0.506 > 0.425 > 0.352
  • PASS flint: finer grind is lighter, monotonically0.833 > 0.774 > 0.702 > 0.618 > 0.527 > 0.439
  • PASS sward: chroma falls as it is ground finer0.1368 at d=8 → 0.0927 at d=0.25
  • PASS the four coloured absorbers are ≥ 35° apart in huesward 123° / husk 68° / oxide 24° / vent 265°
  • PASS hex round-trips to within 1% in L0.7444 → 0.7430
  • PASS body ink on --deep ≥ 7:115.41:1
  • PASS body ink on --ground2 ≥ 7:114.22:1
  • PASS body ink on --ground ≥ 7:112.88:1
  • PASS body ink on --plate ≥ 7:111.18:1
  • PASS body ink on --plate2 ≥ 7:19.52:1
  • PASS faintest ink on --plate2 ≥ 4.5:14.90:1
  • PASS --ink reached its solved target of 11.2:111.20:1
  • PASS --ink2 reached its solved target of 9.5:19.52:1
  • PASS --ink3 reached its solved target of 7:16.99:1
  • PASS --faint reached its solved target of 4.9:14.90:1
  • PASS every sibling ground differs by ≥0.05 in L or ≥40° in hueclosest call is ANNEAL — ΔL 0.093, Δh 71° (too neutral to count)
  • PASS the ground is green (OKLCh hue 105–145)126.7°
  • PASS the ground sits at L 0.255 ± 0.010.2546
  • PASS --husk on --plate2 ≥ 4.5:1 as text4.618:1
  • PASS --vent on --plate2 ≥ 4.5:1 as text4.606:1
  • PASS --oxide on --plate2 ≥ 4.5:1 as text4.631:1
  • PASS --deep on --husk-mark ≥ 7:18.423:1
  • PASS --deep on --vent-mark ≥ 7:18.399:1
  • PASS --deep on --oxide-mark ≥ 7:18.323:1
  • PASS surface steps are between 0.030 and 0.055 in L0.038 0.037 0.043 0.043
  • PASS the published grind ramp is monotone in L0.570 < 0.651 < 0.725 < 0.788 < 0.840 < 0.881