Dendrify basics¶
In this first part of the tutorial series, we’ll focus on creating single compartments and updating their equations. In the second part, we’ll dive into how to add model parameters. Specifically, in this section, we’ll 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
Note
It is highly recommended to have a solid understanding of how Brian 2 works before starting with Dendrify. You can explore Brian’s tutorials here.
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¶
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 crucial for distinguishing between compartments within 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
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 use of tags helps distinguish between synapses of the same type that target
# a single compartment (see below for more details).
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
💡 You can find more information about how random noise is impemented in Brian’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
💡 You can find more information about how dendritic spiking is impemented here.
Connecting compartments¶
dend.connect(soma)
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 represented as Python strings, so you can modify them using standard string formatting techniques.
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
🚨 Starting with Dendrify v2.2.0, users can fully customize model equations. This feature, however, is intended for advanced users who are highly familiar with how Brian 2 works. You can learn more about this advanced feature in the relevant tutorial. It is recommended to explore this feature only after completing the Brian 2 and Dendrify tutorials and gaining a solid understanding of writing your own model equations.
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¶
Dendrify has a built-in library of default simulation parameters that can be viewd 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¶
Dendrify treats every compartment 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
# Absolute capacitance (specific capacitance [cm] multiplied by area)
soma.capacitance
# Absolute leakage conductance (specific leakage conductance [gl] multiplied by area)
soma.g_leakage
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¶
To learn how to modify dSpike parameters, check out the available examples showing dendritic spiking. Additionally, to understand what each parameter means and how it contributes to the dSpike shape, you can explore the dSpike Playground.
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 directly as 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 won’t work, as it calculates the resistance between two adjacent half-cylinders.
soma.connect(dend)
---------------------------------------------------------------------------
DimensionlessCompartmentError Traceback (most recent call last)
Cell In[30], line 1
----> 1 soma.connect(dend)
File ~/anaconda3/envs/brian2/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, which share most of the functionalities of compartment objects (Soma/Dendrite). Note that in this case, there’s 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 should have gained a basic understanding of how to create compartmental models with Dendrify. To learn how to do more exciting things and run simulations, check out Tutorial 2.