Resources¶
The HDF5 engine exposes four concrete Resource types, one per BSB
storage interface. Each lives at a fixed path inside the file and exposes the
operations the BSB asks for. This page describes what each resource stores and
the few quirks worth knowing.
PlacementSet¶
Path:
/placement/<cell_type_name>/Implements:
bsb.storage.interfaces.PlacementSetUses:
ChunkLoader(chunked positions, rotations, morphology indices, labels, plus anadditionalChunkedCollection).
A placement set is the per-cell-type record of where cells live. Its chunked layout (see Chunked storage) lets workers append disjoint chunks in parallel without contending on a single growing dataset.
Notable methods:
load_morphologiesreturns aMorphologySetkeyed on themorphology_loadersattribute the placement step wrote per chunk. It opens one handle which the nested_get_morphology_loaders(itself decorated) reuses automatically through the ambient-handle ContextVar. See Handles.append_dataacceptspositions,morphologies,rotations,additionalfor a chunk, callsrequire_chunkto materialise the chunk group on first write, then appends to each chunked property in turn. The per-chunkmorphology_loadersattribute is rewritten on every append by_append_morphologies.convert_to_localmaps a list of global cell ids into local-chunk indices for the loaded chunk filter. Use when the caller only has the flat-array indices but needs to write back to specific chunk groups.
ConnectivitySet¶
Path:
/connectivity/<tag>/Implements:
bsb.storage.interfaces.ConnectivitySet
A connectivity set is the per-tag record of synapses between one presynaptic and one postsynaptic cell type. Underneath, it stores per-source-chunk and per-destination-chunk groups so the BSB can answer “all connections out of chunk X” or “all connections into chunk Y” without reading the whole set.
Notable methods:
flat_iter_connectionsiterates over per-chunk connection blocks.connectwrites a new block of (src_locs, dst_locs) pairs into the appropriate chunk groups and updates the rootchunksJSON attribute’sinc/outcounters.
The ConnectivitySet.__init__ is decorated with
@handles_handles("r", handler=lambda args: args[1]) because at
construction time self._engine does not exist yet; the handler picks the
engine off the second positional argument instead.
MorphologyRepository¶
Path:
/morphologies/Implements:
bsb.storage.interfaces.MorphologyRepository
The morphology repository stores reusable morphology trees. Each morphology
gets a group at /morphologies/<name>/ containing a data dataset (one
row per point: [x, y, z, radius, label, *properties]) and a graph
dataset (one row per branch: [end_ptr, parent_branch_id]).
A single morphology_meta dataset at / holds the JSON-encoded metadata
for every morphology in the file. Reading it via get_all_meta is the
one cheap operation that lets the placement step decide which morphology to
load without touching any morphology group.
Notable methods:
preloadbuilds aStoredMorphologyfrom a name + meta dict. Passmeta=in to skip the meta lookup (the common path when iterating over many morphologies). Called from inside an open handle (an enclosing scope or decorated method) it reuses that handle automatically; see Handles.savewrites aMorphologyto disk and updates themorphology_metaattribute.
FileStore¶
Path:
/files/Implements:
bsb.storage.interfaces.FileStore
The file store holds arbitrary blobs by id (uuid4-by-default). Each blob is a
single dataset under /files/<id> with two attributes:
meta(JSON dict, includes at minimummtime)encoding(optional, e.g.utf-8if the blob originated as a string)
The file store is also where the active config lives: a special blob
flagged with meta["active_config"] = True, retrievable via
load_active_config. Only one blob carries that flag at a time;
store_active_config clears it on the previous holder before flagging
the new one.
Unlike the other resources, the file store does not use the
handles_handles decorator: every method opens its own handle in the
body via with self._engine._read(), self._engine._handle("r"). This is
intentional: the file store is mostly called as a one-shot from user code, not
from inside other engine paths, so threading would not pay off.
Batching reads and writes¶
Methods that loop over many morphologies, files, or chunks and dispatch to
nested resource calls benefit most from handle reuse. Nested decorated calls
inherit an open handle automatically (via the ambient-handle ContextVar), and a
caller that drives many top-level reads or writes can hold a single handle for
the whole batch with read_scope() /
write_scope() (or the engine-agnostic
storage.read_scope() / storage.write_scope()).
See Handles for the full discipline, including the
PromotedHandleWarning and
UnusedWriteScopeWarning the engine raises when a
scope is misused.