Run your first NEURON simulation

Note

This guide uses notions on the BSB reconstructions that are explained in Getting Started guide.

In this tutorial, we present how to configure a NEURON simulation for a multi-compartment neuron network.

Pre-requirements

NEURON is one of the supported simulators of the BSB. As for the other simulator, its adapter code is stored in a separate repository: bsb-neuron

So, you would need to install it with pip:

pip install bsb-neuron[parallel]

We will also need some model files for NEURON which you can obtain and link to bsb like so:

pip install dbbs-catalogue

Create a data folder in your project folder and save inside:

  • A custom stellate cell morphology here as StellateCell.swc.

  • The Stellate model available here as Stellate.py.

BSB reconstruction for this tutorial

For this example, we will build a network consisting of a single layer of stellate_cells connected through axon-dendrite overlap, using the strategy VoxelIntersection.

The network configuration should be as follows:

{
  "name": "DBBS test stellate rand circuit v4.0",
  "storage": {
    "engine": "hdf5",
    "root": "my_network.hdf5"
  },
  "network": {
    "x": 100.0,
    "y": 200.0,
    "z": 300.0,
    "chunk_size": [100, 100, 100]
  },
  "partitions": {
    "stellate_layer": {
      "thickness": 300.0
    }
  },
  "regions": {
    "example_cortex": {
      "type": "stack",
      "children": ["stellate_layer"]
    }
  },
  "morphologies": [
    {
      "file": "data/StellateCell.swc",
      "parser":{
        "tags": {
            "16": ["dendrites", "proximal_dendrites"],
            "17": ["dendrites", "distal_dendrites"],
            "18": ["axon", "axon_initial_segment"]
            }      
        }
    }
  ],
  "cell_types": {
    "stellate_cell": {
      "spatial": {
        "radius": 4.0,
        "density": 0.000005,
        "morphologies": [
          {
            "names": ["StellateCell"]
          }
        ]
      }
    }
  },
  "placement": {
    "stellate_placement": {
      "strategy": "bsb.placement.RandomPlacement",
      "partitions": ["stellate_layer"],
      "cell_types": ["stellate_cell"]
    }
  },
  "connectivity": {
    "stellate_to_stellate": {
      "strategy": "bsb.connectivity.VoxelIntersection",
      "presynaptic": {
        "cell_types": ["stellate_cell"],
        "morphology_labels" : ["axon"]
      },
      "postsynaptic": {
        "cell_types": ["stellate_cell"],
        "morphology_labels" : ["dendrites"]
      },
      "affinity": 0.5
    }
  },
name: DBBS test stellate rand circuit v4.0
storage:
  engine: hdf5
  root: my_network.hdf5
network:
  x: 100
  y: 200
  z: 300
  chunk_size:
    - 100
    - 100
    - 100
partitions:
  stellate_layer:
    thickness: 300
regions:
  example_cortex:
    type: stack
    children:
      - stellate_layer
morphologies:
  - file: data/StellateCell.swc
    parser:
      tags:
        '16':
          - dendrites
          - proximal_dendrites
        '17':
          - dendrites
          - distal_dendrites
        '18':
          - axon
          - axon_initial_segment
cell_types:
  stellate_cell:
    spatial:
      radius: 4
      density: 0.000005
      morphologies:
        - names:
            - StellateCell
placement:
  stellate_placement:
    strategy: bsb.placement.RandomPlacement
    partitions:
      - stellate_layer
    cell_types:
      - stellate_cell
connectivity:
  stellate_to_stellate:
    strategy: bsb.connectivity.VoxelIntersection
    presynaptic:
      cell_types:
        - stellate_cell
      morphology_labels:
        - axon
    postsynaptic:
      cell_types:
        - stellate_cell
      morphology_labels:
        - dendrites
    affinity: 0.5
import pathlib

import bsb.options
from bsb import Configuration, Scaffold

bsb.options.verbosity = 3
config = Configuration.default(storage={"engine": "hdf5", "root": "my_network.hdf5"})

config.network.x = 100.0
config.network.y = 200.0
config.network.z = 300.0
config.network.chunk_size = [100, 100, 100]

config.partitions.add("stellate_layer", thickness=300)

config.regions.add(
    "brain_region",
    type="stack",
    children=["stellate_layer"],
)

config.morphologies = [
    dict(
        file="data/StellateCell.swc",
        parser={
            "tags": {
                "16": ["dendrites", "proximal_dendrites"],
                "17": ["dendrites", "distal_dendrites"],
                "18": ["axon", "axon_initial_segment"],
            }
        },
    )
]

config.cell_types.add(
    "stellate_cell",
    spatial=dict(
        radius=4,
        density=5e-6,
        morphologies=[{"names": ["StellateCell"]}],
    ),
)

config.placement.add(
    "stellate_placement",
    strategy="bsb.placement.RandomPlacement",
    cell_types=["stellate_cell"],
    partitions=["stellate_layer"],
)

config.connectivity.add(
    "stellate_to_stellate",
    strategy="bsb.connectivity.VoxelIntersection",
    presynaptic=dict(cell_types=["stellate_cell"], morphology_labels=["axon"]),
    postsynaptic=dict(cell_types=["stellate_cell"], morphology_labels=["dendrites"]),
    affinity=0.5,
)

Copy the configuration in you favorite format and put it in the project folder as neuron-simulation.[YOUR EXTENSION]

At this stage, your project folder should contain these files:

.
├── data
│ ├── StellateCell.swc
│ └── Stellate.py
├── pyproject.toml
└── neuron-simulation.yaml # or .json or .py

Then, the configuration should be compiled:

bsb compile --verbosity 3 neuron-simulation.json
# or
bsb compile --verbosity 3 neuron-simulation.yaml
# or
python neuron-simulation.py

Now we have to configure the simulation block.

Configuration of the simulation

We want here to see the postsynaptic response of our cells upon receiving an excitatory input. Each cell will receive one spike on their dendrites and we will check its effect on the postsynaptic current.

Let’s start by configuring the global simulation parameters: first of all, define a simulator; in our example, we are setting it to use NEURON. Then you need to define the resolution (the time step of the simulation in milliseconds), the duration (the total length of the simulation in milliseconds) and the temperature (celsius unit).

  "simulations": {
    "neuronsim": {
      "simulator": "neuron",
      "duration": 100,
      "resolution": 0.025,
      "temperature": 32,
simulations:
  neuronsim:
    simulator: neuron
    duration: 100
    resolution: 0.025
    temperature: 32
config.simulations.add(
    "neuronsim",
    simulator="neuron",
    duration=100,
    resolution=0.025,
    temperature=32,
    cell_models={},
    connection_models={},
    devices={},
)

Cell Models

For each cell type population in your network, you must assign a NEURON model to define the cell’s behavior.

In short, these models encapsulate all the specifications for ion channels and synapses covering all compartments of the neuron. Discussing NEURON model characteristics is beyond the scope of this guide; therefore, we will leverage the data/Stellate.py NEURON model provided before. Please review its contents.

Within the model file, you will find a model definition called definitionStellate, which includes all the customized parameters. This is the object you will refer to in your configuration. Note also that the parameters for the ion channel mechanisms are in the attribute cable_types.

      "cell_models": {
        "stellate_cell": {
          "model": "data.Stellate.definitionStellate",
          "parameters": []
        }    
      },
    cell_models:
      stellate_cell:
        model: data.Stellate.definitionStellate
        parameters: []
config.simulations["neuronsim"].cell_models = dict(
    stellate_cell=dict(model="data.Stellate.definitionStellate", parameters=[])
)

Connection Models

For each connection type of your network, you also need to provide a NEURON model describing its synapses’ dynamics. Similar to the cell_models block, for each connection_model you should use a key that corresponds to a ConnectivitySet created during reconstruction (as explained in the previous section). In this example, to the stellate_to_stellate connection is assigned a reference to one of the synapse_types, defined in the Stellate.py model file: GABA.

      "connection_models": {
        "stellate_to_stellate": 
        {
          "synapses": [{"synapse": "GABA", "weight": 0.001, "delay": 1}]
        }
      },
    connection_models:
      stellate_to_stellate:
        synapses:
          - synapse: GABA
            weight: 0.001
            delay: 1
config.simulations["neuronsim"].connection_models = dict(
    stellate_to_stellate=dict(
        synapses=[
            {
                "synapse": "GABA",
                "weight": 0.001,
                "delay": 1,
            }
        ]
    )
)

To each synapse is assigned a weight of 0.001 and a delay (ms) of 1.

Devices

In the devices block, include all interfaces you wish to use for interacting with the network. These devices correspond typically to stimulators and measurement instruments.

Use the device key to select the type of device. We also introduce here the targetting concept for the devices: This configuration node allows you to filter elements of your neuron circuit to which you want to link your devices (see the targetting section on this page for more details).

      "devices": {
        "spike_generator": {
          "device": "spike_generator",
          "start": 9,
          "number": 1,
          "weight": 0.01,
          "delay": 1,
          "targetting": {
            "strategy": "by_id",
            "ids": {"stellate_cell": [0]}
          },
          "locations": {
            "strategy": "branch",
            "labels": ["dendrites"]
          },
          "synapses" : ["AMPA", "NMDA"]
        },
        "vrecorder": {
          "device": "voltage_recorder",
          "targetting": {
            "strategy": "sphere",
            "radius" : 100,
            "origin" : [50, 100, 150],
            "cell_models" : ["stellate_cell"]
          }
        },
        "synapses_rec":{
          "device": "synapse_recorder",
          "synapse_types": ["AMPA", "NMDA", "GABA"],
          "targetting": {
            "strategy": "sphere",
            "radius" : 100,
            "origin" : [50, 100, 150],
            "cell_models" : ["stellate_cell"]
          },
          "locations":{
            "strategy": "branch",
            "labels": ["dendrites"]
          }
        }
      }
    devices:
      spike_generator:
        device: spike_generator
        start: 9
        number: 1
        weight: 0.01
        delay: 1
        targetting:
          strategy: by_id
          ids:
            stellate_cell:
              - 0
        locations:
          strategy: branch
          labels:
            - dendrites
        synapses:
          - AMPA
          - NMDA
      vrecorder:
        device: voltage_recorder
        targetting:
          strategy: sphere
          radius: 100
          origin:
            - 50
            - 100
            - 150
          cell_models:
            - stellate_cell
      synapses_rec:
        device: synapse_recorder
        synapse_types:
          - AMPA
          - NMDA
          - GABA
        targetting:
          strategy: sphere
          radius: 100
          origin:
            - 50
            - 100
            - 150
          cell_models:
            - stellate_cell
        locations:
          strategy: branch
          labels:
            - dendrites
config.simulations["neuronsim"].devices = dict(
    spike_generator=dict(
        device="spike_generator",
        start=9,
        number=1,
        weight=0.01,
        delay=1,
        targetting={"strategy": "by_id", "ids": {"stellate_cell": [0]}},
        locations={"strategy": "branch", "labels": ["dendrites"]},
        synapses=["AMPA", "NMDA"],
    ),
    vrecorder=dict(
        device="voltage_recorder",
        targetting={
            "strategy": "sphere",
            "radius": 100,
            "origin": [50, 100, 150],
            "cell_models": ["stellate_cell"],
        },
    ),
    synapses_rec=dict(
        device="synapse_recorder",
        synapse_types=["AMPA", "NMDA", "GABA"],
        targetting={
            "strategy": "sphere",
            "radius": 100,
            "origin": [50, 100, 150],
            "cell_models": ["stellate_cell"],
        },
        locations={"strategy": "branch", "labels": ["dendrites"]},
    ),
)

scaffold = Scaffold(config)

In this example, a spike_generator is used to produce 1 spike (attribute number) at 9 ms and send it to the cell with ID 0 (using the targetting) after 1 ms of delay and a weight of 0.01. The stimulus targets the AMPA and NMDA (excitatory) synapses located on the dendrites of the cell.

The membrane potential is recorded using a voltage_recorder, which collects the signal from within a 100 µm radius sphere at the center of the circuit. Hence, not all cells might be recorded.

Synapse activity is monitored with a synapse_recorder for all the synaptic types on the cell’s dendrites, within the same spherical region. Here too, not all synapses might be recorded.

Final configuration file

{
  "name": "DBBS test stellate rand circuit v4.0",
  "storage": {
    "engine": "hdf5",
    "root": "my_network.hdf5"
  },
  "network": {
    "x": 100.0,
    "y": 200.0,
    "z": 300.0,
    "chunk_size": [100, 100, 100]
  },
  "partitions": {
    "stellate_layer": {
      "thickness": 300.0
    }
  },
  "regions": {
    "example_cortex": {
      "type": "stack",
      "children": ["stellate_layer"]
    }
  },
  "morphologies": [
    {
      "file": "data/StellateCell.swc",
      "parser":{
        "tags": {
            "16": ["dendrites", "proximal_dendrites"],
            "17": ["dendrites", "distal_dendrites"],
            "18": ["axon", "axon_initial_segment"]
            }      
        }
    }
  ],
  "cell_types": {
    "stellate_cell": {
      "spatial": {
        "radius": 4.0,
        "density": 0.000005,
        "morphologies": [
          {
            "names": ["StellateCell"]
          }
        ]
      }
    }
  },
  "placement": {
    "stellate_placement": {
      "strategy": "bsb.placement.RandomPlacement",
      "partitions": ["stellate_layer"],
      "cell_types": ["stellate_cell"]
    }
  },
  "connectivity": {
    "stellate_to_stellate": {
      "strategy": "bsb.connectivity.VoxelIntersection",
      "presynaptic": {
        "cell_types": ["stellate_cell"],
        "morphology_labels" : ["axon"]
      },
      "postsynaptic": {
        "cell_types": ["stellate_cell"],
        "morphology_labels" : ["dendrites"]
      },
      "affinity": 0.5
    }
  },
  "simulations": {
    "neuronsim": {
      "simulator": "neuron",
      "duration": 100,
      "resolution": 0.025,
      "temperature": 32,
      "cell_models": {
        "stellate_cell": {
          "model": "data.Stellate.definitionStellate",
          "parameters": []
        }    
      },
      "connection_models": {
        "stellate_to_stellate": 
        {
          "synapses": [{"synapse": "GABA", "weight": 0.001, "delay": 1}]
        }
      },
      "devices": {
        "spike_generator": {
          "device": "spike_generator",
          "start": 9,
          "number": 1,
          "weight": 0.01,
          "delay": 1,
          "targetting": {
            "strategy": "by_id",
            "ids": {"stellate_cell": [0]}
          },
          "locations": {
            "strategy": "branch",
            "labels": ["dendrites"]
          },
          "synapses" : ["AMPA", "NMDA"]
        },
        "vrecorder": {
          "device": "voltage_recorder",
          "targetting": {
            "strategy": "sphere",
            "radius" : 100,
            "origin" : [50, 100, 150],
            "cell_models" : ["stellate_cell"]
          }
        },
        "synapses_rec":{
          "device": "synapse_recorder",
          "synapse_types": ["AMPA", "NMDA", "GABA"],
          "targetting": {
            "strategy": "sphere",
            "radius" : 100,
            "origin" : [50, 100, 150],
            "cell_models" : ["stellate_cell"]
          },
          "locations":{
            "strategy": "branch",
            "labels": ["dendrites"]
          }
        }
      }
    }
  }
}
name: DBBS test stellate rand circuit v4.0
storage:
  engine: hdf5
  root: my_network.hdf5
network:
  x: 100
  y: 200
  z: 300
  chunk_size:
    - 100
    - 100
    - 100
partitions:
  stellate_layer:
    thickness: 300
regions:
  example_cortex:
    type: stack
    children:
      - stellate_layer
morphologies:
  - file: data/StellateCell.swc
    parser:
      tags:
        '16':
          - dendrites
          - proximal_dendrites
        '17':
          - dendrites
          - distal_dendrites
        '18':
          - axon
          - axon_initial_segment
cell_types:
  stellate_cell:
    spatial:
      radius: 4
      density: 0.000005
      morphologies:
        - names:
            - StellateCell
placement:
  stellate_placement:
    strategy: bsb.placement.RandomPlacement
    partitions:
      - stellate_layer
    cell_types:
      - stellate_cell
connectivity:
  stellate_to_stellate:
    strategy: bsb.connectivity.VoxelIntersection
    presynaptic:
      cell_types:
        - stellate_cell
      morphology_labels:
        - axon
    postsynaptic:
      cell_types:
        - stellate_cell
      morphology_labels:
        - dendrites
    affinity: 0.5
simulations:
  neuronsim:
    simulator: neuron
    duration: 100
    resolution: 0.025
    temperature: 32
    cell_models:
      stellate_cell:
        model: data.Stellate.definitionStellate
        parameters: []
    connection_models:
      stellate_to_stellate:
        synapses:
          - synapse: GABA
            weight: 0.001
            delay: 1
    devices:
      spike_generator:
        device: spike_generator
        start: 9
        number: 1
        weight: 0.01
        delay: 1
        targetting:
          strategy: by_id
          ids:
            stellate_cell:
              - 0
        locations:
          strategy: branch
          labels:
            - dendrites
        synapses:
          - AMPA
          - NMDA
      vrecorder:
        device: voltage_recorder
        targetting:
          strategy: sphere
          radius: 100
          origin:
            - 50
            - 100
            - 150
          cell_models:
            - stellate_cell
      synapses_rec:
        device: synapse_recorder
        synapse_types:
          - AMPA
          - NMDA
          - GABA
        targetting:
          strategy: sphere
          radius: 100
          origin:
            - 50
            - 100
            - 150
          cell_models:
            - stellate_cell
        locations:
          strategy: branch
          labels:
            - dendrites
import bsb.options
from bsb import Configuration, Scaffold

bsb.options.verbosity = 3
config = Configuration.default(storage={"engine": "hdf5", "root": "my_network.hdf5"})

config.network.x = 100.0
config.network.y = 200.0
config.network.z = 300.0
config.network.chunk_size = [100, 100, 100]

config.partitions.add("stellate_layer", thickness=300)

config.regions.add(
    "brain_region",
    type="stack",
    children=["stellate_layer"],
)

config.morphologies = [
    dict(
        file="data/StellateCell.swc",
        parser={
            "tags": {
                "16": ["dendrites", "proximal_dendrites"],
                "17": ["dendrites", "distal_dendrites"],
                "18": ["axon", "axon_initial_segment"],
            }
        },
    )
]

config.cell_types.add(
    "stellate_cell",
    spatial=dict(
        radius=4,
        density=5e-6,
        morphologies=[{"names": ["StellateCell"]}],
    ),
)

config.placement.add(
    "stellate_placement",
    strategy="bsb.placement.RandomPlacement",
    cell_types=["stellate_cell"],
    partitions=["stellate_layer"],
)

config.connectivity.add(
    "stellate_to_stellate",
    strategy="bsb.connectivity.VoxelIntersection",
    presynaptic=dict(cell_types=["stellate_cell"], morphology_labels=["axon"]),
    postsynaptic=dict(cell_types=["stellate_cell"], morphology_labels=["dendrites"]),
    affinity=0.5,
)

config.simulations.add(
    "neuronsim",
    simulator="neuron",
    duration=100,
    resolution=0.025,
    temperature=32,
    cell_models={},
    connection_models={},
    devices={},
)

config.simulations["neuronsim"].cell_models = dict(
    stellate_cell=dict(model="data.Stellate.definitionStellate", parameters=[])
)

config.simulations["neuronsim"].connection_models = dict(
    stellate_to_stellate=dict(
        synapses=[
            {
                "synapse": "GABA",
                "weight": 0.001,
                "delay": 1,
            }
        ]
    )
)

config.simulations["neuronsim"].devices = dict(
    spike_generator=dict(
        device="spike_generator",
        start=9,
        number=1,
        weight=0.01,
        delay=1,
        targetting={"strategy": "by_id", "ids": {"stellate_cell": [0]}},
        locations={"strategy": "branch", "labels": ["dendrites"]},
        synapses=["AMPA", "NMDA"],
    ),
    vrecorder=dict(
        device="voltage_recorder",
        targetting={
            "strategy": "sphere",
            "radius": 100,
            "origin": [50, 100, 150],
            "cell_models": ["stellate_cell"],
        },
    ),
    synapses_rec=dict(
        device="synapse_recorder",
        synapse_types=["AMPA", "NMDA", "GABA"],
        targetting={
            "strategy": "sphere",
            "radius": 100,
            "origin": [50, 100, 150],
            "cell_models": ["stellate_cell"],
        },
        locations={"strategy": "branch", "labels": ["dendrites"]},
    ),
)

scaffold = Scaffold(config)
scaffold.compile(clear=True)

# create the simulation results folder

Running the Simulation

Simulations are separated from the reconstruction pipeline (see the top level guide), which means you do not need to recompile your network to add a simulation to your stored Configuration. In this example, we only modified the Configuration in the simulations block but this updates were not been saved in the network file. So, you need to update your file, using either the reconfigure command or the store_active_config method.

bsb reconfigure my_network.hdf5 neuron-simulation.json
# or
bsb reconfigure my_network.hdf5 neuron-simulation.yaml
storage = scaffold.storage
storage.store_active_config(config)

You can now run your simulation:

bsb simulate my_network.hdf5 neuronsim -o simulation-results
import pathlib
from bsb import from_storage

scaffold = from_storage("my_network.hdf5")
# create the simulation results folder
root = pathlib.Path("simulation-results")
root.mkdir()
# run the simulation and save the results
result = scaffold.run_simulation("neuronsim")
result.write(root / "neuronsimulation.nio", "ow")

The results of the simulation will be stored in the "simulation-results" folder.

Note

If you run the simulation with the command line interface, the name of the output nio file is randomized by BSB.

For more detailed information about simulation modules, please refer to the simulation section.

Congratulations, you simulated your first BSB reconstructed network with NEURON!

Next steps:

Analyze your Results

How to extract your data.

Analyze multi-compartment neuron results
Make custom components

Learn how to write your own components to e.g. place or connect cells.

Create your own components
Learn about Components

Explore more about the main components.

BSB components
Examples

Explore more advanced examples

Examples