Spaces:
Running on Zero
Running on Zero
File size: 10,630 Bytes
6bc44d6 b11d6eb 6bc44d6 b11d6eb 6bc44d6 b11d6eb 6bc44d6 b11d6eb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | # 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_replay.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_replay.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
# the host'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
# The noise a run starts with: the SNR at M0 every preset starts at.
[noise]
snr = 30
|