Dendrify basics

In this tutorial, we are going to cover the following topics:

  • Getting to know Dendrify’s basic object types and their functions

  • How to generate model equations

  • How to set model parameters

Imports


import brian2 as b
import dendrify as d
from brian2.units import *
from dendrify import Soma, Dendrite, PointNeuronModel

b.prefs.codegen.target = 'numpy' # faster for simple models and short simulations

Generating model equations

Important:
In this first part of the tutorial we are going to focus only on how to create single compartments and how to update their equations. In the second part, we will describe how to provide model parameters.

Creating compartments


# Setting a compartment's name is the barely minimum you need to create it
soma = Soma('soma')
dend = Dendrite('dend')

A compartment’s name is important to differentiate between compartments of the same multicompartmental model.


# Soma and Dendrite objects share many functions since they both inherit from
# the same class
print(isinstance(soma, d.Compartment))
print(isinstance(dend, d.Compartment))
True
True

Accessing equations


print(soma.equations)
dV_soma/dt = (gL_soma * (EL_soma-V_soma) + I_soma) / C_soma  :volt
I_soma = I_ext_soma  :amp
I_ext_soma  :amp
Explanation:
line 1: Equations describing how the membrane voltage changes over time
line 2: I_soma is a variable that sums all sources of input current into a compartment
line 3: I_ext_soma is a helper variable for injecting external input current

print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend  :amp
I_ext_dend  :amp

Synaptic currents


# The usage of tags helps differentiate between same type of synapses that reach
# a single compartment (also see below).
dend.synapse('AMPA', tag='A')

print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
  • s_AMPA_x_dend -> the state variable for this channel (0 -> closed).

  • w_AMPA_x_dend -> the weight variable. Useful for plasticity (1 by default).


dend.synapse('AMPA', tag='B')
print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_AMPA_B_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_AMPA_B_dend = g_AMPA_B_dend * (E_AMPA-V_dend) * s_AMPA_B_dend * w_AMPA_B_dend  :amp
ds_AMPA_B_dend/dt = -s_AMPA_B_dend / t_AMPA_decay_B_dend  :1

dend.synapse('NMDA', tag='C')
print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_NMDA_C_dend + I_AMPA_B_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_AMPA_B_dend = g_AMPA_B_dend * (E_AMPA-V_dend) * s_AMPA_B_dend * w_AMPA_B_dend  :amp
ds_AMPA_B_dend/dt = -s_AMPA_B_dend / t_AMPA_decay_B_dend  :1
I_NMDA_C_dend = g_NMDA_C_dend * (E_NMDA-V_dend) * s_NMDA_C_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_C_dend  :amp
ds_NMDA_C_dend/dt = -s_NMDA_C_dend/t_NMDA_decay_C_dend  :1

Random noise


dend.noise()  # adds equations for Gaussian white noise
print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_noise_dend + I_NMDA_C_dend + I_AMPA_B_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_AMPA_B_dend = g_AMPA_B_dend * (E_AMPA-V_dend) * s_AMPA_B_dend * w_AMPA_B_dend  :amp
ds_AMPA_B_dend/dt = -s_AMPA_B_dend / t_AMPA_decay_B_dend  :1
I_NMDA_C_dend = g_NMDA_C_dend * (E_NMDA-V_dend) * s_NMDA_C_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_C_dend  :amp
ds_NMDA_C_dend/dt = -s_NMDA_C_dend/t_NMDA_decay_C_dend  :1
dI_noise_dend/dt = (mean_noise_dend-I_noise_dend) / tau_noise_dend + sigma_noise_dend * (sqrt(2/(tau_noise_dend*dt)) * randn()) :amp

NOTE: You can find more info about how random noise is impemented inBrian’s documentation.

Dendritic spikes


dend.dspikes('Na')
print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_rise_Na_dend + I_fall_Na_dend + I_noise_dend + I_NMDA_C_dend + I_AMPA_B_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_AMPA_B_dend = g_AMPA_B_dend * (E_AMPA-V_dend) * s_AMPA_B_dend * w_AMPA_B_dend  :amp
ds_AMPA_B_dend/dt = -s_AMPA_B_dend / t_AMPA_decay_B_dend  :1
I_NMDA_C_dend = g_NMDA_C_dend * (E_NMDA-V_dend) * s_NMDA_C_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_C_dend  :amp
ds_NMDA_C_dend/dt = -s_NMDA_C_dend/t_NMDA_decay_C_dend  :1
dI_noise_dend/dt = (mean_noise_dend-I_noise_dend) / tau_noise_dend + sigma_noise_dend * (sqrt(2/(tau_noise_dend*dt)) * randn()) :amp
I_rise_Na_dend = g_rise_Na_dend * (E_rise_Na-V_dend)  :amp
I_fall_Na_dend = g_fall_Na_dend * (E_fall_Na-V_dend)  :amp
g_rise_Na_dend = g_rise_max_Na_dend * int(t_in_timesteps <= spiketime_Na_dend + duration_rise_Na_dend) * gate_Na_dend :siemens
g_fall_Na_dend = g_fall_max_Na_dend * int(t_in_timesteps <= spiketime_Na_dend + offset_fall_Na_dend + duration_fall_Na_dend) * int(t_in_timesteps >= spiketime_Na_dend + offset_fall_Na_dend) *  gate_Na_dend :siemens
spiketime_Na_dend  :1
gate_Na_dend  :1

NOTE: You can find more info about how dendritic spiking is impementedhere.

Connecting compartments


dend.connect(soma)

NOTE: Ιgnore any errors that might be generated from the above command for now. They will make sense in a while.


print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_soma_dend  + I_rise_Na_dend + I_fall_Na_dend + I_noise_dend + I_NMDA_C_dend + I_AMPA_B_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_AMPA_B_dend = g_AMPA_B_dend * (E_AMPA-V_dend) * s_AMPA_B_dend * w_AMPA_B_dend  :amp
ds_AMPA_B_dend/dt = -s_AMPA_B_dend / t_AMPA_decay_B_dend  :1
I_NMDA_C_dend = g_NMDA_C_dend * (E_NMDA-V_dend) * s_NMDA_C_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_C_dend  :amp
ds_NMDA_C_dend/dt = -s_NMDA_C_dend/t_NMDA_decay_C_dend  :1
dI_noise_dend/dt = (mean_noise_dend-I_noise_dend) / tau_noise_dend + sigma_noise_dend * (sqrt(2/(tau_noise_dend*dt)) * randn()) :amp
I_rise_Na_dend = g_rise_Na_dend * (E_rise_Na-V_dend)  :amp
I_fall_Na_dend = g_fall_Na_dend * (E_fall_Na-V_dend)  :amp
g_rise_Na_dend = g_rise_max_Na_dend * int(t_in_timesteps <= spiketime_Na_dend + duration_rise_Na_dend) * gate_Na_dend :siemens
g_fall_Na_dend = g_fall_max_Na_dend * int(t_in_timesteps <= spiketime_Na_dend + offset_fall_Na_dend + duration_fall_Na_dend) * int(t_in_timesteps >= spiketime_Na_dend + offset_fall_Na_dend) *  gate_Na_dend :siemens
spiketime_Na_dend  :1
gate_Na_dend  :1
I_soma_dend = (V_soma-V_dend) * g_soma_dend  :amp

print(soma.equations)
dV_soma/dt = (gL_soma * (EL_soma-V_soma) + I_soma) / C_soma  :volt
I_soma = I_ext_soma + I_dend_soma   :amp
I_ext_soma  :amp
I_dend_soma = (V_dend-V_soma) * g_dend_soma  :amp

User-defined equations

Equations are Python strings, thus you can adapt them with standard string formatting practices.


type(dend.equations)

str

custom_model = "dcns/dt = -cns/tau_cns  :1"
eqs = f"{dend.equations}\n{custom_model}"
print(eqs)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_soma_dend  + I_rise_Na_dend + I_fall_Na_dend + I_noise_dend + I_NMDA_C_dend + I_AMPA_B_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_AMPA_B_dend = g_AMPA_B_dend * (E_AMPA-V_dend) * s_AMPA_B_dend * w_AMPA_B_dend  :amp
ds_AMPA_B_dend/dt = -s_AMPA_B_dend / t_AMPA_decay_B_dend  :1
I_NMDA_C_dend = g_NMDA_C_dend * (E_NMDA-V_dend) * s_NMDA_C_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_C_dend  :amp
ds_NMDA_C_dend/dt = -s_NMDA_C_dend/t_NMDA_decay_C_dend  :1
dI_noise_dend/dt = (mean_noise_dend-I_noise_dend) / tau_noise_dend + sigma_noise_dend * (sqrt(2/(tau_noise_dend*dt)) * randn()) :amp
I_rise_Na_dend = g_rise_Na_dend * (E_rise_Na-V_dend)  :amp
I_fall_Na_dend = g_fall_Na_dend * (E_fall_Na-V_dend)  :amp
g_rise_Na_dend = g_rise_max_Na_dend * int(t_in_timesteps <= spiketime_Na_dend + duration_rise_Na_dend) * gate_Na_dend :siemens
g_fall_Na_dend = g_fall_max_Na_dend * int(t_in_timesteps <= spiketime_Na_dend + offset_fall_Na_dend + duration_fall_Na_dend) * int(t_in_timesteps >= spiketime_Na_dend + offset_fall_Na_dend) *  gate_Na_dend :siemens
spiketime_Na_dend  :1
gate_Na_dend  :1
I_soma_dend = (V_soma-V_dend) * g_soma_dend  :amp
dcns/dt = -cns/tau_cns  :1
Important:
Although it is possible to add custom model equations, it can be quite tricky for non-experienced Brian2/Dendrify users. If this is a feature that you need to implement and you are not sure how, please check one of the availablesupport options.

Setting model parameters

In this second part of the tutorial we are going to explore how to access, generate or update all model parameters.

Accessing model properties


dend.parameters
ERROR [dendrify.ephysproperties:351]
Could not calculate the g_couple for 'dend' and 'soma'.
Please make sure that [length, diameter, r_axial] are
available for both compartments.

WARNING [dendrify.ephysproperties:196]
Missing parameters [length | diameter] for 'dend'.
Could not calculate the area of 'dend', returned None.

WARNING [dendrify.ephysproperties:225]
Could not calculate the [capacitance] of 'dend', returned None.

WARNING [dendrify.ephysproperties:196]
Missing parameters [length | diameter] for 'dend'.
Could not calculate the area of 'dend', returned None.

WARNING [dendrify.ephysproperties:254]
Could not calculate the [g_leakage] of 'dend', returned None.

ERROR [dendrify.ephysproperties:279]
Could not resolve [EL_dend] for 'dend'.

ERROR [dendrify.ephysproperties:279]
Could not resolve [C_dend] for 'dend'.

ERROR [dendrify.ephysproperties:279]
Could not resolve [gL_dend] for 'dend'.


{'w_AMPA_A_dend': 1.0,
 'w_AMPA_B_dend': 1.0,
 'w_NMDA_C_dend': 1.0,
 'tau_noise_dend': 20. * msecond,
 'sigma_noise_dend': 1. * pamp,
 'mean_noise_dend': 0. * amp,
 'g_soma_dend': None,
 'Vth_Na_dend': None,
 'g_rise_max_Na_dend': None,
 'g_fall_max_Na_dend': None,
 'E_rise_Na': None,
 'E_fall_Na': None,
 'duration_rise_Na_dend': None,
 'duration_fall_Na_dend': None,
 'offset_fall_Na_dend': None,
 'refractory_Na_dend': None,
 'E_AMPA': 0. * volt,
 'E_NMDA': 0. * volt,
 'E_GABA': -80. * mvolt,
 'E_Na': 70. * mvolt,
 'E_K': -89. * mvolt,
 'E_Ca': 136. * mvolt,
 'Mg_con': 1.0,
 'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'Gamma_NMDA': 0}

Dendrify is designed to fail loudly!!! Errors and warnings are raised if you try to access parameters that do not exist, or if something important is missing.

Default parameters

NOTE: Dendrify has a built-in library of default simulation parameters that can be views or adjusted using default_params() and update_default_params() respectively.


d.default_params()

{'E_AMPA': 0. * volt,
 'E_NMDA': 0. * volt,
 'E_GABA': -80. * mvolt,
 'E_Na': 70. * mvolt,
 'E_K': -89. * mvolt,
 'E_Ca': 136. * mvolt,
 'Mg_con': 1.0,
 'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'Gamma_NMDA': 0}

d.update_default_params({"E_Ca":2024})
d.default_params()

{'E_AMPA': 0. * volt,
 'E_NMDA': 0. * volt,
 'E_GABA': -80. * mvolt,
 'E_Na': 70. * mvolt,
 'E_K': -89. * mvolt,
 'E_Ca': 2024,
 'Mg_con': 1.0,
 'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'Gamma_NMDA': 0}

Ephys parameters

In Dendrify, each compartment is treated as an open cylinder. Although an RC circuit does not have physical dimensions, length and diameter are needed to estimate a compartment’s theoretical surface area.


soma = Soma('soma', length=20*um, diameter=20*um,
            cm=1*uF/(cm**2), gl=40*uS/(cm**2),
            r_axial=150*ohm*cm, v_rest=-70*mV)

dend = Dendrite('dend', length=20*um, diameter=20*um,
                cm=1*uF/(cm**2), gl=40*uS/(cm**2),
                r_axial=150*ohm*cm, v_rest=-70*mV)

print(soma) # no more errors :)

OBJECT
------
<class 'dendrify.compartment.Soma'>


EQUATIONS
---------
dV_soma/dt = (gL_soma * (EL_soma-V_soma) + I_soma) / C_soma  :volt
I_soma = I_ext_soma  :amp
I_ext_soma  :amp


PARAMETERS
----------
{'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'C_soma': 12.56637061 * pfarad,
 'EL_soma': -70. * mvolt,
 'E_AMPA': 0. * volt,
 'E_Ca': 2024,
 'E_GABA': -80. * mvolt,
 'E_K': -89. * mvolt,
 'E_NMDA': 0. * volt,
 'E_Na': 70. * mvolt,
 'Gamma_NMDA': 0,
 'Mg_con': 1.0,
 'gL_soma': 0.50265482 * nsiemens}


USER PARAMETERS
---------------
{'_dimensionless': False,
 'cm': 0.01 * metre ** -4 * kilogram ** -1 * second ** 4 * amp ** 2,
 'cm_abs': None,
 'diameter': 20. * umetre,
 'gl': 0.4 * metre ** -4 * kilogram ** -1 * second ** 3 * amp ** 2,
 'gl_abs': None,
 'length': 20. * umetre,
 'name': 'soma',
 'r_axial': 1.5 * metre ** 3 * kilogram * second ** -3 * amp ** -2,
 'scale_factor': 1.0,
 'spine_factor': 1.0,
 'v_rest': -70. * mvolt}

# The surface area of an equivalent open cylinder
soma.area

$1256.637061435917\,\mathrm{um^2}$

# Absolute capacitance (specific capacitance [cm] multiplied by area)
soma.capacitance

$12.566370614359167\,\mathrm{p}\mathrm{F}$

# Absolute leakage conductance (specific leakage conductance [gl] multiplied by area)
soma.g_leakage

$0.5026548245743667\,\mathrm{n}\mathrm{S}$

Synaptic parameters


dend.synapse('AMPA', 'A', g=1*nS, t_decay=5*ms)
print(dend)

OBJECT
------
<class 'dendrify.compartment.Dendrite'>


EQUATIONS
---------
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1


PARAMETERS
----------
{'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'C_dend': 12.56637061 * pfarad,
 'EL_dend': -70. * mvolt,
 'E_AMPA': 0. * volt,
 'E_Ca': 2024,
 'E_GABA': -80. * mvolt,
 'E_K': -89. * mvolt,
 'E_NMDA': 0. * volt,
 'E_Na': 70. * mvolt,
 'Gamma_NMDA': 0,
 'Mg_con': 1.0,
 'gL_dend': 0.50265482 * nsiemens,
 'g_AMPA_A_dend': 1. * nsiemens,
 't_AMPA_decay_A_dend': 5. * msecond,
 'w_AMPA_A_dend': 1.0}


EVENTS
------
[]


EVENT CONDITIONS
----------------
{}


USER PARAMETERS
---------------
{'cm': 0.01 * metre ** -4 * kilogram ** -1 * second ** 4 * amp ** 2,
 'diameter': 20. * umetre,
 'gl': 0.4 * metre ** -4 * kilogram ** -1 * second ** 3 * amp ** 2,
 'length': 20. * umetre,
 'name': 'dend',
 'r_axial': 1.5 * metre ** 3 * kilogram * second ** -3 * amp ** -2,
 'scale_factor': 1.0,
 'spine_factor': 1.0,
 'v_rest': -70. * mvolt}

# NMDA synapse with instant activation and exponential decay:
dend.synapse('NMDA', 'A', g=1*nS, t_decay=60*ms)

# NMDA synapse as a sum of two exponentials with rise and decay kinetics:
dend.synapse('NMDA', 'B', g=1*nS, t_decay=60*ms, t_rise=5*ms)

print(dend)

OBJECT
------
<class 'dendrify.compartment.Dendrite'>


EQUATIONS
---------
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_NMDA_B_dend + I_NMDA_A_dend + I_AMPA_A_dend  :amp
I_ext_dend  :amp
I_AMPA_A_dend = g_AMPA_A_dend * (E_AMPA-V_dend) * s_AMPA_A_dend * w_AMPA_A_dend  :amp
ds_AMPA_A_dend/dt = -s_AMPA_A_dend / t_AMPA_decay_A_dend  :1
I_NMDA_A_dend = g_NMDA_A_dend * (E_NMDA-V_dend) * s_NMDA_A_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_A_dend  :amp
ds_NMDA_A_dend/dt = -s_NMDA_A_dend/t_NMDA_decay_A_dend  :1
I_NMDA_B_dend = g_NMDA_B_dend * (E_NMDA-V_dend) * x_NMDA_B_dend / (1 + Mg_con * exp(-Alpha_NMDA*(V_dend/mV+Gamma_NMDA)) / Beta_NMDA) * w_NMDA_B_dend  :amp
dx_NMDA_B_dend/dt = (-x_NMDA_B_dend/t_NMDA_decay_B_dend) + s_NMDA_B_dend/ms  :1
ds_NMDA_B_dend/dt = -s_NMDA_B_dend / t_NMDA_rise_B_dend  :1


PARAMETERS
----------
{'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'C_dend': 12.56637061 * pfarad,
 'EL_dend': -70. * mvolt,
 'E_AMPA': 0. * volt,
 'E_Ca': 2024,
 'E_GABA': -80. * mvolt,
 'E_K': -89. * mvolt,
 'E_NMDA': 0. * volt,
 'E_Na': 70. * mvolt,
 'Gamma_NMDA': 0,
 'Mg_con': 1.0,
 'gL_dend': 0.50265482 * nsiemens,
 'g_AMPA_A_dend': 1. * nsiemens,
 'g_NMDA_A_dend': 1. * nsiemens,
 'g_NMDA_B_dend': 1. * nsiemens,
 't_AMPA_decay_A_dend': 5. * msecond,
 't_NMDA_decay_A_dend': 60. * msecond,
 't_NMDA_decay_B_dend': 60. * msecond,
 't_NMDA_rise_B_dend': 5. * msecond,
 'w_AMPA_A_dend': 1.0,
 'w_NMDA_A_dend': 1.0,
 'w_NMDA_B_dend': 1.0}


EVENTS
------
[]


EVENT CONDITIONS
----------------
{}


USER PARAMETERS
---------------
{'cm': 0.01 * metre ** -4 * kilogram ** -1 * second ** 4 * amp ** 2,
 'diameter': 20. * umetre,
 'gl': 0.4 * metre ** -4 * kilogram ** -1 * second ** 3 * amp ** 2,
 'length': 20. * umetre,
 'name': 'dend',
 'r_axial': 1.5 * metre ** 3 * kilogram * second ** -3 * amp ** -2,
 'scale_factor': 1.0,
 'spine_factor': 1.0,
 'v_rest': -70. * mvolt}

Random noise parameters


dend.noise(mean=0*pA, sigma=10*pA, tau=1*ms)

dSpike parameters

We will explore this topic in detail in another tutorial. For now, you can view some of the availableexamples that implement dendritic spiking.

Coupling parameters


# Automatic approach
soma.connect(dend, g=10*nS)

print(soma)

OBJECT
------
<class 'dendrify.compartment.Soma'>


EQUATIONS
---------
dV_soma/dt = (gL_soma * (EL_soma-V_soma) + I_soma) / C_soma  :volt
I_soma = I_ext_soma + I_dend_soma   :amp
I_ext_soma  :amp
I_dend_soma = (V_dend-V_soma) * g_dend_soma  :amp


PARAMETERS
----------
{'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'C_soma': 12.56637061 * pfarad,
 'EL_soma': -70. * mvolt,
 'E_AMPA': 0. * volt,
 'E_Ca': 2024,
 'E_GABA': -80. * mvolt,
 'E_K': -89. * mvolt,
 'E_NMDA': 0. * volt,
 'E_Na': 70. * mvolt,
 'Gamma_NMDA': 0,
 'Mg_con': 1.0,
 'gL_soma': 0.50265482 * nsiemens,
 'g_dend_soma': 10. * nsiemens}


USER PARAMETERS
---------------
{'_dimensionless': False,
 'cm': 0.01 * metre ** -4 * kilogram ** -1 * second ** 4 * amp ** 2,
 'cm_abs': None,
 'diameter': 20. * umetre,
 'gl': 0.4 * metre ** -4 * kilogram ** -1 * second ** 3 * amp ** 2,
 'gl_abs': None,
 'length': 20. * umetre,
 'name': 'soma',
 'r_axial': 1.5 * metre ** 3 * kilogram * second ** -3 * amp ** -2,
 'scale_factor': 1.0,
 'spine_factor': 1.0,
 'v_rest': -70. * mvolt}

Dimensionless compartments

If you know the model’s desired capacitance and leakage conductance you can pass them dirrectly as a parameters when creating a compartment.


soma = Soma('soma', cm_abs=200*pF, gl_abs=20*nS, v_rest=-70*mV)
dend = Dendrite('dend', cm_abs=200*pF, gl_abs=20*nS, v_rest=-70*mV)

Since these compartments have no dimensions, the automatic connection approach will not work, since it calculates the resistance between two adjucent half-cylinders.


soma.connect(dend)
---------------------------------------------------------------------------
DimensionlessCompartmentError             Traceback (most recent call last)
Cell In[31], line 1
----> 1 soma.connect(dend)

File ~/.conda/envs/brian/lib/python3.13/site-packages/dendrify/compartment.py:186, in Compartment.connect(self, other, g)
    183     raise ValueError(
    184         "Cannot connect compartments with the same name.\n")
    185 if (self.dimensionless or other.dimensionless) and isinstance(g, str):
--> 186     raise DimensionlessCompartmentError(
    187         ("Cannot automatically calculate the coupling \nconductance of "
    188          "dimensionless compartments. To resolve this error, perform\n"
    189          "one of the following:\n\n"
    190          f"1. Provide [length, diameter, r_axial] for both '{self.name}'"
    191          f" and '{other.name}'.\n\n"
    192          f"2. Turn both compartment into dimensionless by providing only"
    193          " values for \n   [cm_abs, gl_abs] and then connect them using "
    194          "an exact coupling conductance."
    195          )
    196     )
    198 # Current from Comp2 -> Comp1
    199 forward_current = 'I_{1}_{0} = (V_{1}-V_{0}) * g_{1}_{0}  :amp'.format(
    200     self.name, other.name)

DimensionlessCompartmentError: Cannot automatically calculate the coupling
conductance of dimensionless compartments. To resolve this error, perform
one of the following:

1. Provide [length, diameter, r_axial] for both 'soma' and 'dend'.

2. Turn both compartment into dimensionless by providing only values for
   [cm_abs, gl_abs] and then connect them using an exact coupling conductance.

However, you can still connect them by explicitly specifying the coupling conductance as shown bellow.IMPORTANT: This trick also works for compartments that have dimensions as well.


soma.connect(dend, g=10*nS)

print(soma)

OBJECT
------
<class 'dendrify.compartment.Soma'>


EQUATIONS
---------
dV_soma/dt = (gL_soma * (EL_soma-V_soma) + I_soma) / C_soma  :volt
I_soma = I_ext_soma + I_dend_soma   :amp
I_ext_soma  :amp
I_dend_soma = (V_dend-V_soma) * g_dend_soma  :amp


PARAMETERS
----------
{'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'C_soma': 200. * pfarad,
 'EL_soma': -70. * mvolt,
 'E_AMPA': 0. * volt,
 'E_Ca': 2024,
 'E_GABA': -80. * mvolt,
 'E_K': -89. * mvolt,
 'E_NMDA': 0. * volt,
 'E_Na': 70. * mvolt,
 'Gamma_NMDA': 0,
 'Mg_con': 1.0,
 'gL_soma': 20. * nsiemens,
 'g_dend_soma': 10. * nsiemens}


USER PARAMETERS
---------------
{'_dimensionless': True,
 'cm': None,
 'cm_abs': 200. * pfarad,
 'diameter': None,
 'gl': None,
 'gl_abs': 20. * nsiemens,
 'length': None,
 'name': 'soma',
 'r_axial': None,
 'scale_factor': None,
 'spine_factor': None,
 'v_rest': -70. * mvolt}

Creating point neurons

Dendrify also supports point (single-compartment) neuron models that share most of the functionalities of compartment objects (Soma/Dendrite). Note that here, there is no need to specify a compartment’s name.


model = PointNeuronModel(model='leakyIF', v_rest=-60*mV,
                         cm_abs=200*pF, gl_abs=10*nS)
model.noise(mean=10*pA, sigma=100*pA, tau=20*ms)
model.synapse('AMPA', tag='x', g=2*nS, t_decay=2*ms)

print(model)

OBJECT
------
<class 'dendrify.neuronmodel.PointNeuronModel'>


EQUATIONS
---------
dV/dt = (gL * (EL-V) + I) / C  :volt
I = I_ext + I_AMPA_x + I_noise  :amp
I_ext  :amp
dI_noise/dt = (mean_noise-I_noise) / tau_noise + sigma_noise * (sqrt(2/(tau_noise*dt)) * randn()) :amp
I_AMPA_x = g_AMPA_x * (E_AMPA-V) * s_AMPA_x * w_AMPA_x  :amp
ds_AMPA_x/dt = -s_AMPA_x / t_AMPA_decay_x  :1


PARAMETERS
----------
{'Alpha_NMDA': 0.062,
 'Beta_NMDA': 3.57,
 'C': 200. * pfarad,
 'EL': -60. * mvolt,
 'E_AMPA': 0. * volt,
 'E_Ca': 2024,
 'E_GABA': -80. * mvolt,
 'E_K': -89. * mvolt,
 'E_NMDA': 0. * volt,
 'E_Na': 70. * mvolt,
 'Gamma_NMDA': 0,
 'Mg_con': 1.0,
 'gL': 10. * nsiemens,
 'g_AMPA_x': 2. * nsiemens,
 'mean_noise': 10. * pamp,
 'sigma_noise': 100. * pamp,
 't_AMPA_decay_x': 2. * msecond,
 'tau_noise': 20. * msecond,
 'w_AMPA_x': 1.0}


USER PARAMETERS
---------------
{'_dimensionless': True,
 'cm': None,
 'cm_abs': 200. * pfarad,
 'diameter': None,
 'gl': None,
 'gl_abs': 10. * nsiemens,
 'length': None,
 'name': None,
 'r_axial': None,
 'scale_factor': None,
 'spine_factor': None,
 'v_rest': -60. * mvolt}

Congratulations on completing the first Dendrify tutorial!! By now, you might have built some basic intuition on how to create compartmental models with Dendrify. To see how to do more interesting things and actually run simulations, please checkTutorial 2.