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¶
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
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
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
# 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¶
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.