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#

In this first part of the tutorial we are going to focus on how to create single compartments and how to equip them with desired mechanisms.

Creating compartments#


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

# 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

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.
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='A')
print(dend.equations)
dV_dend/dt = (gL_dend * (EL_dend-V_dend) + I_dend) / C_dend  :volt
I_dend = I_ext_dend + I_NMDA_A_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_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

Random noise#


dend.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_A_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_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
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_A_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_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
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

Connecting compartments#


dend.connect(soma)

NOTE: Ιgnore the above errors 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_A_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_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
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_A_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_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
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

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:336]
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:180]
Missing parameters [length | diameter] for 'dend'.
Could not calculate the area of 'dend', returned None.

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

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

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

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

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

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


{'w_AMPA_A_dend': 1.0,
 'w_AMPA_B_dend': 1.0,
 'w_NMDA_A_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":2023})
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': 2023,
 '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': 2023,
 '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': 2023,
 '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': 2023,
 '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 another tutorial…

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': 2023,
 '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 ~/anaconda3/envs/dendrify/lib/python3.11/site-packages/dendrify/compartment.py:169, in Compartment.connect(self, other, g)
    166     raise ValueError(
    167         "Cannot connect compartments with the same name.\n")
    168 if (self.dimensionless or other.dimensionless) and type(g) == str:
--> 169     raise DimensionlessCompartmentError(
    170         ("Cannot automatically calculate the coupling \nconductance of "
    171          "dimensionless compartments. To resolve this error, perform\n"
    172          "one of the following:\n\n"
    173          f"1. Provide [length, diameter, r_axial] for both '{self.name}'"
    174          f" and '{other.name}'.\n\n"
    175          f"2. Turn both compartment into dimensionless by providing only"
    176          " values for \n   [cm_abs, gl_abs] and then connect them using "
    177          "an exact coupling conductance."
    178          )
    179     )
    181 # Current from Comp2 -> Comp1
    182 I_forward = 'I_{1}_{0} = (V_{1}-V_{0}) * g_{1}_{0}  :amp'.format(
    183     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': 2023,
 '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). Notice 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': 2023,
 '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}