# 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