Biophysical Models

The Allen Cell Types Database contains biophysical models that characterize the firing behavior of neurons measured in slices through current injection by a somatic whole-cell patch clamp electrode. These models contain a set of 10 active conductances placed at the soma and use the reconstructed 3D morphologies of the modeled neurons. The biophysical modeling technical white paper contains details on the specific construction of these models and the optimization of the model parameters to match the experimentally-recorded firing behaviors.

The biophysical models are run with the NEURON simulation environment. The Allen SDK package contains libraries that assist in downloading and setting up the models available on the Allen Institute web site for users to run using NEURON. The examples and scripts provided run on Linux using the bash shell.

Prerequisites

You must have NEURON with the Python interpreter enabled and the Allen SDK installed.

The Allen Institute perisomatic biophysical models were generated using NEURON version v7.4.rel-1370. Instructions for compiling NEURON with the Python interpreter are available from the NEURON team under the heading Installation with Python as an alternative interpreter. The Allen SDK is compatible with Python version 2.7.9, included in the Anaconda 2.1.0 distribution.

Instructions for optional Docker installation are also available.

Note

Building and installing NEURON with the Python wrapper enabled is not always easy. This page targets users that have a background in NEURON usage and installation.

Downloading Biophysical Models

There are two ways to download files necessary to run a biophysical model. The first way is to visit http://celltypes.brain-map.org and find cells that have biophysical models available for download. The electrophysiology details page for a cell has a neuronal model download link. Specifically:

  1. Click ‘More Options+’
  2. Check ‘Models -> Biophysical - perisomatic’ or ‘Biophysical - all active’
  3. Use the Filters, Cell Location and Cell Feature Filters to narrow your results.
  4. Click on a Cell Summary to view the Mouse Experiment Electrophysiology.
  5. Click the “download data” link to download the NWB stimulus and response file.
  6. Click “show model response” and select ‘Biophysical - perisomatic’ or ‘Biophysical - all active’.
  7. Scroll down and click the ‘Biophysical - perisomatic’ or ‘Biophysical - all active’ “download model” link.

This may be also be done programmatically. The neuronal model id can be found to the left of the corresponding ‘Biophysical - perisomatic’ or ‘Biophysical - all active’ “download model” link.

from allensdk.api.queries.biophysical_api import \
    BiophysicalApi

bp = BiophysicalApi()
bp.cache_stimulus = True # change to False to not download the large stimulus NWB file
neuronal_model_id = 472451419    # get this from the web site as above
bp.cache_data(neuronal_model_id, working_directory='neuronal_model')


More help can be found in the online help for the Allen Cell Types Database web application.

Directory Structure

The structure of the directory created looks like this. It includes stimulus files, model parameters, morphology, cellular mechanisms and application configuration.

neuronal_model
|-- manifest.json
|-- 472451419_fit.json
|-- Nr5a1-Cre_Ai14_IVSCC_-169248.04.02.01.nwb
|-- Nr5a1-Cre_Ai14_IVSCC_-169248.04.02.01_403165543_m.swc
|-- modfiles
|   |--CaDynamics.mod
|   |--Ca_HVA.mod
|   |--Ca_LVA.mod
|   |--Ih.mod
|   `--...etc.
|
|--x86_64
`---work

Running the Simulation (Linux shell prompt)

All of the sweeps available from the web site are included in manifest.json and will be run by default. This can take some time.

cd neuronal_model
nrnivmodl ./modfiles   # compile the model (only needs to be done once)
python -m allensdk.model.biophysical.runner manifest.json

Selecting a Specific Sweep

The sweeps are listed in manifest.json. You can remove all of the sweep numbers that you do not want run.

Simulation Main Loop

The top level script is in the run() method of the allensdk.model.biophysical.runner module. The implementation of the method is discussed here step-by-step:

First configure NEURON based on the configuration file, which was read in from the command line at the very bottom of the script.

run():

# configure NEURON -- this will infer model type (perisomatic vs. all-active)
utils = Utils.create_utils(description)
h = utils.h

The next step is to get the path of the morphology file and pass it to NEURON.

# configure model
manifest = description.manifest
morphology_path = description.manifest.get_path('MORPHOLOGY')
utils.generate_morphology(morphology_path.encode('ascii', 'ignore'))
utils.load_cell_parameters()

Then read the stimulus and recording configuration and configure NEURON

# configure stimulus and recording
stimulus_path = description.manifest.get_path('stimulus_path')
nwb_out_path = manifest.get_path("output")
output = NwbDataSet(nwb_out_path)
run_params = description.data['runs'][0]
sweeps = run_params['sweeps']
junction_potential = description.data['fitting'][0]['junction_potential']
mV = 1.0e-3

Loop through the stimulus sweeps and write the output.

# run sweeps
for sweep in sweeps:
    utils.setup_iclamp(stimulus_path, sweep=sweep)
    vec = utils.record_values()

    h.finitialize()
    h.run()

    # write to an NWB File
    output_data = (numpy.array(vec['v']) - junction_potential) * mV
    output.set_sweep(sweep, None, output_data)

Customization

Much of the code in the perisomatic simulation is not core Allen SDK code. The runner.py script largely reads the configuration file and calls into methods in the Utils class. Utils is a subclass of the HocUtils class, which provides access to objects in the NEURON package. The various methods called by the runner.script are implemented here, including: generate_morphology(), load_cell_parameters(), setup_iclamp(), read_stimulus() and record_values().

Utils:

from allensdk.model.biophys_sim.neuron.hoc_utils import HocUtils

.....

class Utils(HocUtils):
.....

    def __init__(self, description):
        super(Utils, self).__init__(description)
....

To create a biophysical model using your own software or data, simply model your directory structure on one of the downloaded simulations or one of the examples below. Add your own runner.py and utils.py module to the simulation directory.

Compile the .mod files using NEURON’s nrnivmodl command (Linux shell):

nrnivmodl modfiles

Then call your runner script directly, passing in the manifest file to your script:

python runner.py manifest.json

The output from your simulation and any intermediate files will go in the work directory.

Examples

A minimal example (simple_example.tgz) and a multicell example (multicell_example.tgz) are available to download as a starting point for your own projects.

Each example provides its own utils.py file along with a main script (Linux shell) and supporting configuration files.

simple_example.tgz:

tar xvzf simple_example.tgz
cd simple
nrnivmodl modfiles
python simple.py

multicell_example.tgz:

tar xvzf multicell_example.tgz
cd multicell
nrnivmodl modfiles
python multi.py
python multicell_diff.py

Exporting Output to Text Format or Image

This is an example of using the AllenSDK to save a response voltage to other formats.

from allensdk.core.dat_utilities import \
    DatUtilities
from allensdk.core.nwb_data_set import \
    NwbDataSet
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

nwb_file = '313862020.nwb'
sweep_number = 52
dat_file = '313862020_%d.dat' % (sweep_number)

nwb = NwbDataSet(nwb_file)
sweep = nwb.get_sweep(sweep_number)

# read v and t as numpy arrays
v = sweep['response']
dt = 1.0e3 / sweep['sampling_rate']
num_samples = len(v)
t = np.arange(num_samples) * dt

# save as text file
data = np.transpose(np.vstack((t, v)))
with open (dat_file, "w") as f:
    np.savetxt(f, data)

# save image using matplotlib
fig, ax = plt.subplots(nrows=1, ncols=1)
ax.plot(t, v)
ax.set_title("Sweep %s" % (sweep_number))
fig.savefig('out.png')

Model Description Files

Basic Structure

A model description file is simply a JSON object with several sections at the top level and an array of JSON objects within each section.

 {
    "cell_section": [
        {
          "name": "cell 1",
          "shape": "pyramidal"
          "position": [ 0.1, 0.2, 0.3 ]
        },
        {
          "name": "cell 2",
          "shape": "glial",
          "position": [ 0.1, 0.2, 0.3 ]
        }
    ],
    "extra": [
       { "what": "wood",
         "who": "woodchuck"
       }
    ]
}

Even if a section contains no objects or only one object the array brackets must be present.

Objects Within Sections

While no restrictions are enforced on what kinds of objects are stored in a section, some rules of thumb make the file easier to work with.

  1. All objects within a section are the same structure. Common operations on a section are to display it as a table, iterate over it, load from or write to a spreadsheet or csv file. These operations are all easier if the section is fairly homogeneous.
  2. Objects are not deeply nested. While some shallow nesting is often useful, deep nesting such as a tree structure is not recommended. It makes interoperability with other tools and data formats more difficult.
  3. Arrays are allowed, though they should not be deeply nested either.
  4. Object member values should be literals. Do not use pickled classes, for example.

Comment Lines

The JSON specification does not allow comments. However, the Allen SDK library applies a preprocessing stage to remove C++-style comments, so they can be used in description files.

Multi-line comments should be surrounded by /* */ and single-line comments start with //. Commented description files will not be recognized by strict json parsers unless the comments are stripped.

commented.json:

{
   /*
    *  multi-line comment
    */
   "section1": [
       {
          "name": "simon"  // single line comment
       }]
   }

Split Description Files by Section

A model description can be split into multiple files by putting some sections in one file and other sections into another file. This can be useful if you want to put a topology of cells and connections in one file and experimental conditions and stimulus in another file. The resulting structure in memory will behave the same way as if the files were not split. This allows a small experiment to be described in a single file and large experiments to be more modular.

cells.json:

{
   "cell_section": [
       {
         "name": "cell 1",
         "shape": "pyramidal"
         "position": [ 0.1, 0.2, 0.3 ]
       },
       {
         "name": "cell 2",
         "shape": "glial",
         "position": [ 0.1, 0.2, 0.3 ]
       }
   ]
}

extras.json:

{
    "extra": [
       {
         "what": "wood",
         "who": "woodchuck"
       }
    ]
}

Split Sections Between Description Files

If two description files containing the same sections are combined, the resulting description will contain objects from both files. This feature allows sub-networks to be described in separate files. The sub-networks can then be composed into a larger network with an additional description of the interconnections.

network1.json:

/* A self-contained sub-network */
{
    "cells": [
        { "name": "cell1" },
        { "name": "cell2" }
    ],
    /* intra-network connections /*
    "connections": [
        { "source": "cell1", "target" : "cell2" }
    ]
}

network2.json:

/* Another self-contained sub-network */
{
    "cells": [
        { "name": "cell3" },
        { "name": "cell4" }
    ],
    "connections": [
        { "source": "cell3", "target" : "cell4" }
    ]
}

interconnect.json:

{
    // the additional connections needed to
    // connect the network1 and network2
    // into a ring topology.
    "connections": [
       { "source": "cell2", "target": "cell3" },
       { "source": "cell4", "target": "cell1" }
    ]
}

Resource Manifest

JSON has many advantages. It is widely supported, readable and easy to parse and edit. As data sets get larger or specialized those advantages diminish. Large or complex models and experiments generally need more than a single model description file to completely describe an experiment. A manifest file is a way to describe all of the resources needed within the Allen SDK description format itself.

The manifest section is named “manifest” by default, though it is configurable. The objects in the manifest section each specify a directory, file, or file pattern. Files and directories may be organized in a parent-child relationship.

A Simple Manifest

This is a simple manifest file that specifies the BASEDIR directory using ”.”, meaning the current directory:

{
    "manifest": [
        {   "key": "BASEDIR",
            "type": "dir",
            "spec": "."
        }
    ] }
}

Parent Child Relationships

Adding the optional “parent_key” member to a manifest object creates a parent-child relation. In this case WORKDIR will be found in ”./work”:

{
    "manifest": [
        {   "key": "BASEDIR",
            "type": "dir",
            "spec": "."
        },
        {   "key": "WORKDIR",
            "type": "dir",
            "spec": "/work",
            "parent_key": "BASEDIR"
        }
    ] }
}

File Spec Patterns

Files can be specified using the type “file” instead of “dir”. If a sequence of many files is needed, the spec may contain patterns to indicate where the sequence number (%d) or string (%s) will be interpolated:

{
    "manifest": [
        {   "key": "BASEDIR",
            "type": "dir",
            "spec": "."
        },
        {
            "key": "voltage_out_cell_path",
            "type": "file",
            "spec": "v_out-cell-%d.dat",
            "parent_key": "BASEDIR"
        }
    ] }
}

Split Manifest Files

Manifest files can be split like any description file. This allows the specification of a general directory structure in a shared file and specific files in a separate configuration (i.e. stimulus and working directory)

Extensions

To date, manifest description files have not been used to reference URLs that provide model data, but it is a planned future use case.

Further Reading