lowering
adapters.smallscale.lowering
Backend-neutral network lowering for small-scale simulators.
The functions here turn a TVB-O Network (nodes with size, edges with a connectivity rule, Dynamics/Coupling/Event biology) into the two structures every point-neuron backend needs:
- populations — nodes grouped by their
Dynamics, each a block ofNode.sizecells, with a stable base index per node so edges can address individual cells; and - connections — the explicit cell-to-cell :class:
ConnectionRecordset that aconnectivityrule (all_to_all/one_to_one) lowers to, with self-connections filtered and per-connectionweight/delayextracted.
Everything here is independent of how a backend emits a synapse — that (LEMS XML, Brian2 Synapses, …) stays in the backend adapter. The backend injects its own role vocabulary (which Dynamics are cells vs current sources vs event sources) so the same lowering serves NeuroML, Brian2 and the rest unchanged.
Classes
| Name | Description |
|---|---|
| ConnectionRecord | One lowered cell-to-cell connection — the contract every backend consumes. |
ConnectionRecord
adapters.smallscale.lowering.ConnectionRecord()One lowered cell-to-cell connection — the contract every backend consumes.
Produced by connectivity-rule expansion; a plain dict at runtime so templates and adapters can index it directly. The neutral core is from_pop/from_idx → to_pop/to_idx through synapse with an optional per-connection weight/delay. from_rule records whether the connection came from a lowered connectivity rule (vs a single explicit edge). Backends may attach their own keys (e.g. conn_class for LEMS projection classification) without changing this core.
Functions
| Name | Description |
|---|---|
| assign_cell_population | Assign a cell population id and per-node base indices, filling the maps. |
| classify_node_role | Classify a node group as a cell, current-input, or event-source. |
| connectivity_pairs | Expand a population-level connectivity rule into (src_idx, tgt_idx) pairs. |
| expand_edge_connections | Yield (from_idx, to_idx, from_rule) for one synapse edge. |
| expand_input_targets | Local target cell indices an input edge fans out to. |
| group_nodes_by_dynamics | Group nodes by their Dynamics name, preserving first-encounter order. |
| merge_params | Merge parameter dicts with later dicts overriding earlier ones. |
| node_dynamics_name | The Dynamics name a node runs. |
| safe_id | Make a string safe for XML id attribute. |
| unique_component_id | A component id derived from name that no other component already holds. |
assign_cell_population
adapters.smallscale.lowering.assign_cell_population(
dyn_name,
group_nodes,
node_pop_map,
node_size_map,
)Assign a cell population id and per-node base indices, filling the maps.
Each node contributes Node.size cells laid out contiguously; the running base index lets an edge address an individual cell within the population. Mutates node_pop_map (node_id -> (pop_id, base)) and node_size_map (node_id -> size) in place, and returns (pop_id, node_ids, size).
classify_node_role
adapters.smallscale.lowering.classify_node_role(dyn_name, dyn_lib_obj, vocab)Classify a node group as a cell, current-input, or event-source.
The biological type is read from Dynamics.iri (neuroml:<type>); a Dynamics without such an iri is a plain cell named by itself. vocab is the backend’s role vocabulary — a mapping with current_input and event_source keys to sets of type names — so the same lowering serves any backend by swapping the sets.
Returns (role, nml_type) with role one of "cell", "current_input", "event_source".
connectivity_pairs
adapters.smallscale.lowering.connectivity_pairs(rule, src_size, tgt_size)Expand a population-level connectivity rule into (src_idx, tgt_idx) pairs.
Given the ConnectivityRule (or its string value) and the source/target population sizes, yields the local cell-index pairs a projection (or per-cell input list) enumerates. This is the “allToAll lowering”: the user declares one population-to-population Edge and the adapter generates the i x j connection set, so no O(N**2) explicit edges ever appear in the input.
Self-connection filtering (the diagonal of a self-projection) is applied by the caller on the resolved global cell indices, so this helper simply yields the raw pattern.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| rule | Connectivity pattern (all_to_all or one_to_one). |
required | |
| src_size | Number of cells in the source population. | required | |
| tgt_size | Number of cells in the target population. | required |
Yields
| Name | Type | Description |
|---|---|---|
(src_idx, tgt_idx) local cell indices. |
expand_edge_connections
adapters.smallscale.lowering.expand_edge_connections(
edge,
*,
src_pop,
src_base,
tgt_pop,
tgt_base,
src_size,
tgt_size,
)Yield (from_idx, to_idx, from_rule) for one synapse edge.
An Edge with a connectivity rule is a population-to-population projection: expand it into the individual cell-to-cell connections here, skipping the diagonal of a self-projection when allow_self_connections is False. Without a rule the Edge is a single explicit cell-to-cell connection. from_rule marks whether the connection came from a lowered rule.
expand_input_targets
adapters.smallscale.lowering.expand_input_targets(tgt_base, tgt_size, rule)Local target cell indices an input edge fans out to.
A connectivity rule attaches an independent copy of the input component to every target cell (rule expansion over a size-1 “source”); without a rule the input hits the node’s base cell only.
group_nodes_by_dynamics
adapters.smallscale.lowering.group_nodes_by_dynamics(nodes, default_dyn_name)Group nodes by their Dynamics name, preserving first-encounter order.
merge_params
adapters.smallscale.lowering.merge_params(*param_dicts)Merge parameter dicts with later dicts overriding earlier ones.
The canonical order is dynamics-library → node/edge → per-connection, i.e. the same precedence as the {**dyn, **node, **edge} spreads the backends build by hand. Keys are taken verbatim; values are not copied.
node_dynamics_name
adapters.smallscale.lowering.node_dynamics_name(node, default_dyn_name)The Dynamics name a node runs.
Node.dynamics is a name-reference slot, so it may arrive as a bare name or as a resolved Dynamics; a node that declares none falls back to default_dyn_name — the experiment’s top-level dynamics. One rule, shared by every backend, so they cannot disagree about which model a node runs.
safe_id
adapters.smallscale.lowering.safe_id(s)Make a string safe for XML id attribute.
unique_component_id
adapters.smallscale.lowering.unique_component_id(name, taken, kind='component')A component id derived from name that no other component already holds.
Components are named after their Dynamics, so two differently parameterised uses of one Dynamics would collide and the second would be dropped.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| name | the Dynamics name to derive the id from. | required | |
| taken | ids already assigned; the returned id is added to it. | required | |
| kind | what is being named, for the disambiguation warning. | 'component' |
Returns
| Name | Type | Description |
|---|---|---|
safe_id(name), or that with a numeric suffix when it is taken. |