Plotting somatodendritic attenuation for biophysical models

Hello everyone,

I am using a configuration I found for a biophysical neuron model in the mouse V1 area, namely:

"N": 2350,
            "node_type_id": 471129934,
            "model_type": "biophysical",
            "model_template": "ctdb:Biophys1.hoc",
            "dynamics_params": "471129934_fit.json",
            "morphology": "Rbp4-Cre_KL100_Ai14-180747.06.01.01_495335491_m.swc",
            "model_processing": "aibs_perisomatic",
            "rotation_angle_zaxis": -2.527764895

I am trying to plot the somatodendritic attenuation for a current injection at the soma at steady state. For example, if I apply a -10 pA current injection at the soma for 1000ms, I would like to be able to see the membrane potential depending on what distance from the soma I’m looking at, for example at 100 micrometers, 250 micrometers and 600 micrometers from the soma on the dendritic tree. I am new to this and I would appreciate any help or guidance into how this could be done using the Brain Modelling Toolkit (BMTK). Currently my code doesn’t implement this because I tried to find information about distance-dependent recordings, but wasn’t able to. Thank you in advance!

Currently, my code looks like this:

from bmtk.builder.networks import NetworkBuilder
from bmtk.utils.sim_setup import build_env_bionet
from bmtk.simulator import bionet
import h5py

# Build the network
net = NetworkBuilder('mcortex')
net.add_nodes(
    cell_name='e4',
    potential='exc',
    model_type='biophysical',
    model_template='ctdb:Biophys1.hoc',
    model_processing='aibs_perisomatic',
    dynamics_params='471129934_fit.json',
    morphology='Rbp4-Cre_KL100_Ai14-180747.06.01.01_495335491_m.swc',
    rotation_angle_zaxis= -2.527764895
)

net.build()
net.save_nodes(output_dir='sim_ch01/network')

for node in net.nodes():
    print(node)

# Set up the simulation environment
build_env_bionet(
    base_dir='sim_ch01',       # Where to save the scripts and config files 
    config_file='config.json', # Where main config will be saved.
    network_dir='network',     # Location of directory containing network files
    tstop=2000.0, dt=0.1,      # Run a simulation for 2000 ms at 0.1 ms intervals
    report_vars=['v', 'cai'],  # Tells simulator we want to record membrane potential and calcium traces
    current_clamp={            # Creates a step current from 500.0 ms to 1500.0 ms  
        'amp': 0.520,
        'delay': 300.0,
        'duration': 1000.0
    },
    include_examples=True,    # Copies components files for tutorial examples
    compile_mechanisms=True   # Will try to compile NEURON mechanisms
)

from bmtk.builder.networks import NetworkBuilder
from bmtk.utils.sim_setup import build_env_bionet
from bmtk.simulator import bionet
import h5py
# Run the simulation
conf = bionet.Config.from_json('sim_ch01/config.json')
conf.build_env()
net = bionet.BioNetwork.from_config(conf)
sim = bionet.BioSimulator.from_config(conf, network=net)
sim.run()

# Inspect the spike file
spike_file = 'sim_ch01/output/spikes.h5' 

with h5py.File(spike_file, 'r') as f:
    print("Groups in the spike file:", list(f.keys()))
    if 'spikes' in f:
        print("Populations in the spike file:", list(f['spikes'].keys()))

# Check if the spike file is generated and not empty
from bmtk.analyzer.spike_trains import _find_spikes

try:
    pop, spike_trains = _find_spikes(config_file='sim_ch01/config.json')
    print(f"Population: {pop}")
    print(f"Spike Trains: {spike_trains}")
    df = spike_trains.to_dataframe()
except IndexError as e:
    print(f"IndexError: {e} - Check if the spike file contains the expected population.")
except Exception as e:
    print(f"Unexpected error: {e}")

from bmtk.analyzer.compartment import plot_traces
import matplotlib.pyplot as plt

try:
    v_plots = plot_traces(config_file='sim_ch01/config.json', node_ids=[0], report_name='v_report')
except Exception as e:
    print(f"Error plotting traces: {e}")

The simulation_config.json file has the following parameters:

{
  "manifest": {
    "$BASE_DIR": "${configdir}",
    "$OUTPUT_DIR": "$BASE_DIR/output"
  },
  "target_simulator": "NEURON",
  "run": {
    "tstart": 0.0,
    "tstop": 2000.0,
    "dt": 0.1,
    "dL": 20.0,
    "spike_threshold": -15.0,
    "nsteps_block": 5000
  },
  "conditions": {
    "celsius": 34.0,
    "v_init": -80.0
  },
  "inputs": {
    "current_clamp": {
      "input_type": "current_clamp",
      "module": "IClamp",
      "node_set": "all",
      "gids": "all",
      "amp": -0.1,
      "delay": 500.0,
      "duration": 1000.0
    }
  },
  "output": {
    "log_file": "log.txt",
    "output_dir": "$OUTPUT_DIR",
    "spikes_file": "spikes.h5"
  },
  "reports": {
    "v_report": {
      "variable_name": "v",
      "cells": "all",
      "module": "membrane_report",
      "sections": "all"
    },
    "cai_report": {
      "variable_name": "cai",
      "cells": "all",
      "module": "membrane_report",
      "sections": "soma"
    }
  },
  "node_sets_file": "$BASE_DIR/node_sets.json"
}

Many thanks.

Best wishes,
Rares

Hi @rad216

BMTK current_clamp module allows the option of specifying options section_name and section_index to specify where the clamp is placed. If you know the NEURON section_id number for a given cell model you can specify it particularly. However the latest version of bmtk also allows to you to have a ranged value. For example if you want to place a clamp that is between 900 and 1100 microns (arc-lenght) distance on an apical or basal dendrite branch away from the soma, you can add the following to the options

   "section_name": ["apic", "dend"],
   "section_index": [900, 1100]

Then when you run the simulation bmtk will try to find all apical (apic) or basal (dend) segments that are between 900 to 1100 um away and randomly select one to place the clamp on.

One caveat is that not all cell morphologies will be able to meet the criteria which can cause the simulation to fail. So you may want to use the node_set option to select which cells will recieve inputs. For example to add current-clamps ~1000 um arc-distance length from the soma on all the biophysical detailed Rbp4 cells try the following:

  "inputs": {
    "current_clamp": {
      "input_type": "current_clamp",
      "module": "IClamp",
      "node_set": {
           "model_type": "biophysical",
           "morphology": "Rbp4-Cre_KL100_Ai14-180747.06.01.01_495335491_m.swc"
       },
      "amp": -0.1,
      "delay": 500.0,
      "duration": 1000.0,
      "section_name": ["apic", "dend"],
      "section_index": [900, 1100]
    }
  },

You may need to checkout the latest version of bmtk?

Hi @kael ,

Thanks a lot for your response!

That’s very helpful indeed and I managed to implement some of it (the range still doesn’t work for me as it says the section_index parameter must be an integer, but that’s not a problem right now).

What I am really interested in is to place the clam on the soma (like I’m doing currently) and then record the voltage on the dendritic tree at a certain distance from the soma, for example at 400um, where I identified that the apical dendrite with index 24 is at this distance:

  "reports": {
    "v_report": {
      "variable_name": "v",
      "cells": "all",
      "module": "membrane_report",
      "sections": ["apic"],
      "section_index": [24],
      "loc": [0.5]
    },

However, running the script and trying to plot the v_report using the above expression results in a plot which has about 40 traces, instead of just one trace which corresponds to the segment I want to record from. Somehow it doesn’t seem to take the ‘section_index’ and ‘loc’ arguments into account the way I intend it to, perhaps there is a different way to specify these arguments in the ‘reports’ section?

Thank you very much for your time!

Best wishes,
Rares