brain-zero / space /brain.toml
rfick's picture
Squash history: one commit holding the current files
6bc44d6
Raw History Blame Contribute Delete
10.5 kB
# The brain Space: what is pinned. Every number the app shows comes from pipeline.py and sources/brain.py on this
# configuration. DISCO_CONFIG=brain.toml selects it (the entry app.py, tools/deploy.py --config, tools/live.py --config).
source = "brain" # space/sources/brain.py
# The asset: the multi-tissue CSD of the subject's scan (WM FOD, WM/GM/CSF fractions, mask), its parcellation
# (labels, regions.json, stop mask) and a mean b = 0, made once offline (disco-space#8 steps 2-4). A public Hub
# dataset at a revision, downloaded into the Hub cache when the container starts; `local = "/dir"` (or
# DISCO_BRAIN_ASSET in the environment) reads a directory instead.
[asset]
hub = "SubstrateCommons/masivar-brain"
revision = "7556d3900adfe73f2b78b34fffb74902354775e9" # MASiVar sub-cIs1 ses-s1Ax1, dmipy-fit 11294e9 (mask eroded 3, tournier13) csd_msmt_torch, 2026-10-01 (revision 3)
[describe]
title = "Brain replay: MASiVar"
subject = "MASiVar sub-cIs1 (OpenNeuro ds003416, Cai et al. MRM 2021, CC0)"
heading = """A real brain as a compositional replay phantom: the multi-tissue CSD of one scan (its white-matter FOD field and \
WM / GM / CSF fractions) composed with replay packs, one Monte-Carlo walk per tissue. Choose an acquisition, the tissue and the \
scanner; the Space replays every brain voxel from the packs' responses, adds noise, estimates the tissue responses from the \
replayed data, fits multi-tissue CSD, tracks from the white matter and scores the 84-region connectome against the connectome of \
the input FOD tracked the same way. The progress bar names each stage."""
scan_preset = "the scan's own protocol"
# The pulse timing the scan's own protocol plays when the asset's manifest states none (MASiVar's sidecars carry no
# EchoTime, delta or Delta): the BATMAN capstone's square pulses, which the 100 ms packs play; the page says it is assumed.
[scan]
delta = 0.025
Delta = 0.055
TE = 0.100
# The timing classes a shell plays (square pulses; delta / Delta / TE in seconds, kind = "pgste" a stimulated echo
# storing for TM = Delta - delta, whose TE = 2 t_store + TM includes the storage). A pack is its walk in windows
# (RPK.md 4.3; 125 ms for the menu's windowed packs); a class reads the windows its acquisition reaches
# (Brain.windows_reached: the classes up to TE 100 ms window 0), and a class beyond a pack's walk or its declared windows is refused by name. The scan's own class
# (`scan`) comes from the asset's manifest.
[shapes."d12-D24"]
label = "clinical δ 12 / Δ 24 ms, TE 60 ms"
delta = 0.012
Delta = 0.024
TE = 0.060
[shapes."d17-D30"]
label = "research δ 17 / Δ 30 ms, TE 70 ms"
delta = 0.017
Delta = 0.030
TE = 0.070
[shapes."d25-D55"]
label = "long δ 25 / Δ 55 ms, TE 100 ms (the BATMAN capstone's)"
delta = 0.025
Delta = 0.055
TE = 0.100
[shapes."ste-d12-TM36"]
label = "stimulated echo δ 12 / TM 36 ms (Δ 48 ms), TE 70 ms"
delta = 0.012
Delta = 0.048
TE = 0.070
kind = "pgste"
# The classes only a walk longer than 100 ms plays (two windows of the 1 s pack); a 100 ms pack refuses them by name.
[shapes."ste-d12-TM150"]
label = "long stimulated echo δ 12 / TM 150 ms (Δ 162 ms), TE 184 ms: a walk beyond 100 ms (two windows)"
delta = 0.012
Delta = 0.162
TE = 0.184
kind = "pgste"
[shapes."long-TE-d30-D120"]
label = "long-TE δ 30 / Δ 120 ms, TE 160 ms: a walk beyond 100 ms (two windows)"
delta = 0.030
Delta = 0.120
TE = 0.160
# Presets besides the scan's own protocol (which comes from the asset). b in s/mm^2.
[presets."clinical b1000 x 30"]
n_b0 = 1
shells = [{ shape = "d12-D24", b = 1000, n_dirs = 30 }]
[presets."research 3-shell x 90"]
n_b0 = 3
shells = [
{ shape = "d17-D30", b = 1000, n_dirs = 90 },
{ shape = "d17-D30", b = 2000, n_dirs = 90 },
{ shape = "d17-D30", b = 3000, n_dirs = 90 },
]
# The tissue and the scanner: the field presets (T), the default field, whether a run starts with the tiers on, and
# the values the "M0 of GM" knob offers B. The tissue's numbers come from dmipy-sim's biophysical constants by key.
[physics]
fields = [0.064, 1.5, 3.0, 7.0, 11.7]
default_field = 3.0
default_on = true
m0_gm_knob = [0.7, 1.0]
# The scanner menu after "ideal": catalogue machines whose every catalogued term the brain applies, the head centre at
# isocentre (docs/scanner.md). Each voxel is binned into an encoding class by what the machine delivers there, to
# `tolerance` of b (dmipy_sim.phantom.bore.encoding_classes), and every class's played acquisition is expanded by the
# packs. `refused` are the machines kept off the menu, each shown under it with the reason (Brain.refused_machines):
# the Swoop, whose own gradient makes the head thousands of encoding classes (docs/scanner.md).
[scanners]
machines = [
{ label = "Siemens Prisma 3 T", key = "siemens_magnetom_prisma_3T" },
{ label = "Siemens Terra 7 T", key = "siemens_magnetom_terra_7T" },
]
refused = [
{ label = "Hyperfine Swoop 64 mT", key = "hyperfine_swoop_64mT" },
]
tolerance = 0.01
# The pack menu per tissue (the first is the default): a label and a pack URI (hf:// or a local path, as
# dmipy_sim.phantom.PackSubstrate resolves it). A Hub pack declaring several windows loads the windows a run reaches
# (Brain.pack); a local path or a one-window pack loads whole. SubstrateCommons family records feed this later (disco-space#8, decision 5).
[packs]
wm = [
{ label = "CACTUS single bundle, 1 s walk in 125 ms windows (1280 Hz)", uri = "hf://SubstrateCommons/cactus-axons/packs/single_bundle_1s_c3_seg125ms.rpk" },
{ label = "canonical cylinder, 2 µm, 100 ms", uri = "hf://SubstrateCommons/canonical-pores/packs/cylinder/d02.00um.rpk" },
]
gm = [
{ label = "grey-matter spheres, 250 ms in 125 ms windows (240 Hz)", uri = "hf://SubstrateCommons/grey-matter-spheres/packs/packed_spheres_leaky_250ms_c2_seg125ms.rpk" },
{ label = "grey-matter spheres, 100 ms", uri = "hf://SubstrateCommons/grey-matter-spheres/packs/gm_spheres_100ms.rpk" },
]
# The compute backend: the brain's replay contraction is torch on the device; the CSD solver and the tracker follow
# this backend. DISCO_BACKEND overrides.
[compute]
backend = "torch"
resident = false
# The reconstruction: msmt (three-tissue responses from the data + multi-shell multi-tissue CSD, dmipy-fit#39) or
# tournier07 (single-fibre response + single-tissue CSD). DISCO_RECONSTRUCTION overrides.
[reconstruction]
method = "msmt"
[tracking]
density = 2 # seeds per WM voxel = density^3
step_mm = 1.25
max_angle = 45.0
# The GPU reservation model (Brain.estimated_seconds): a run = fixed + per_meas x n + track[d] (A's tracking), plus
# track[d] for the truth (the input FOD tracked the same way, shared by B), per_meas_ladder x n for the ladder, B = a
# run without the worker's start, track[d] per extra key; times margin. Refit from tools/measure_brain.py on an L40S
# with the BATMAN fixture (90,205 voxels, 36,605 WM seeds per density^3; README-brain-zero.md has the table), each
# device stage x 1.5 for the pool (DiSCo's CSD and tracking ran 1.1-1.3x slower on the pool than on an L40S), the
# worker's start and a multi-GB payload's handoff 12 s. The single-tissue reconstruction's cost is in per_meas
# (8.0 s at 495 measurements); refit when dmipy-fit#39's multi-tissue path runs. Seconds.
[budget]
worker = 12.0 # the worker's start and the payload's handoff
fixed = 16.0 # worker + noise, the round trip, the scoring and the explorer's maps (L40S 2.5 s x 1.5)
per_meas = 0.03 # the contraction and the reconstruction per measurement (L40S 8.9 s at 495 x 1.5 / 495)
ladder_per_meas = 0.002 # the ladder's rungs of contraction (L40S 0.5 s at 495 x 1.5 / 495)
margin = 1.3
# The packs' pose responses the GPU worker computes when the page has them not cached (Brain.responses), JAX on
# the CPU: fixed + per_meas x n per entry, bounding every measurement on a CPU host (8 threads; the pool's worker has
# 192 CPUs, taken as x 1.0) over the scan (113), clinical (31) and two 4 x 128 + 10 custom protocols (522; TE 100 ms
# alone and four mixed classes), fields 0.064-12 T. cold: a field band not compiled in this process (the scan at
# 11.7 T 16.6 s, at 11.7 T with chi x 1.1 29.4 s, 4 x 128 at TE 100 ms and 12 T 49.9 s); warm: a compiled band at
# another tissue or field direction (2.3 / 6.8 / 14.7 s at 31 / 113 / 522); no_field: the field tier off, nothing
# compiles (0.7 / 1.7 / 3.3 s). An entry is priced fixed + per_meas x n_meas + per_save x saves, where saves is the
# number of the WM pack's saves the entry's acquisition spans, k (n_t - 1) + 1 for the k windows of n_t saves it
# reaches (Brain.windows_needed, Brain.saves_spanned; a one-window pack's n_t): per_save is seconds per save spanned,
# priced independent of the measurement count: the slope of prepare's seconds over the saves at one protocol, the 485
# measurements of MASiVar's (the measurements' share stays in per_meas). Measured on a CPU host (4 threads,
# tools/measure_brain.py --saves): prepare on the 100 ms legacy pack (1,002 saves) and the 1 s Swoop pack's prefixes
# of 100 / 204 ms (ReplayPack.prefix per shard: 1,303 / 2,656 saves), three runs, the third adding the 85 ms prefix
# (1,107 saves) and playing the d17-D30 class instead of the scan's. With the field
# tier off the slope is 0.0008-0.0016 s per save; the field states' slopes (-0.0015 to +0.0062) are within the
# shared box's noise, and their save-dependent work is the same expansion, so the three take the largest no_field
# slope. fixed and per_meas were fit on the 1,002-save pack, so its saves are priced twice: 1.6 s of margin.
response_cold = { fixed = 22.0, per_meas = 0.07, per_save = 0.0016 }
response_warm = { fixed = 2.5, per_meas = 0.04, per_save = 0.0016 }
response_no_field = { fixed = 0.5, per_meas = 0.012, per_save = 0.0016 }
# On a machine every encoding class's rows play their own amplitude, so its shells no longer share the expansion's
# bodies: a class of the scan's 485 measurements on the 100 ms CACTUS pack at 3 T with every tier took 25 s against
# 4.5 s for the commanded protocol (a CPU host, 8 threads, the Prisma at 6 cm, its slew), so an entry's rows count
# once per class times this (Brain.responses).
response_per_class = 5.6
[budget.track] # one tracking of the WM at density d, the run's or the truth's (L40S steady x 1.5)
1 = 1.5 # 36,605 seeds: 0.7 s
2 = 3.5 # 292,840 seeds: 1.9-2.1 s
4 = 35.0 # 2,342,720 seeds: 13.6-23.2 s