Source code for tvb.simulator.models.larter_breakspear

# -*- coding: utf-8 -*-
#
#
# TheVirtualBrain-Scientific Package. This package holds all simulators, and
# analysers necessary to run brain-simulations. You can use it stand alone or
# in conjunction with TheVirtualBrain-Framework Package. See content of the
# documentation-folder for more details. See also http://www.thevirtualbrain.org
#
# (c) 2012-2024, Baycrest Centre for Geriatric Care ("Baycrest") and others
#
# This program is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this
# program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#   CITATION:
# When using The Virtual Brain for scientific publications, please cite it as explained here:
# https://www.thevirtualbrain.org/tvb/zwei/neuroscience-publications
#
#

"""
Larter-Breakspear model based on the Morris-Lecar equations.

"""

import numpy
from .base import Model
from tvb.basic.neotraits.api import NArray, Final, List, Range


[docs] class LarterBreakspear(Model): r""" A modified Morris-Lecar model that includes a third equation which simulates the effect of a population of inhibitory interneurons synapsing on the pyramidal cells. .. [Larteretal_1999] Larter et.al. *A coupled ordinary differential equation lattice model for the simulation of epileptic seizures.* Chaos. 9(3): 795, 1999. .. [Breaksetal_2003_a] Breakspear, M.; Terry, J. R. & Friston, K. J. *Modulation of excitatory synaptic coupling facilitates synchronization and complex dynamics in an onlinear model of neuronal dynamics*. Neurocomputing 52–54 (2003).151–158 .. [Breaksetal_2003_b] M. J. Breakspear et.al. *Modulation of excitatory synaptic coupling facilitates synchronization and complex dynamics in a biophysical model of neuronal dynamics.* Network: Computation in Neural Systems 14: 703-732, 2003. .. [Honeyetal_2007] Honey, C.; Kötter, R.; Breakspear, M. & Sporns, O. * Network structure of cerebral cortex shapes functional connectivity on multiple time scales*. (2007) PNAS, 104, 10240 .. [Honeyetal_2009] Honey, C. J.; Sporns, O.; Cammoun, L.; Gigandet, X.; Thiran, J. P.; Meuli, R. & Hagmann, P. *Predicting human resting-state functional connectivity from structural connectivity.* (2009), PNAS, 106, 2035-2040 .. [Alstottetal_2009] Alstott, J.; Breakspear, M.; Hagmann, P.; Cammoun, L. & Sporns, O. *Modeling the impact of lesions in the human brain*. (2009)), PLoS Comput Biol, 5, e1000408 Equations and default parameters are taken from [Breaksetal_2003_b]_. All equations and parameters are non-dimensional and normalized. For values of d_v < 0.55, the dynamics of a single column settles onto a solitary fixed point attractor. Parameters used for simulations in [Breaksetal_2003_a]_ Table 1. Page 153. Two nodes were coupled. C=0.1 +---------------------------+ | Table 1 | +--------------+------------+ |Parameter | Value | +==============+============+ | I | 0.3 | +--------------+------------+ | a_ee | 0.4 | +--------------+------------+ | a_ei | 0.1 | +--------------+------------+ | a_ie | 1.0 | +--------------+------------+ | a_ne | 1.0 | +--------------+------------+ | a_ni | 0.4 | +--------------+------------+ | r_NMDA | 0.2 | +--------------+------------+ | delta | 0.001 | +--------------+------------+ | Breakspear et al. 2003 | +---------------------------+ +---------------------------+ | Table 2 | +--------------+------------+ |Parameter | Value | +==============+============+ | gK | 2.0 | +--------------+------------+ | gL | 0.5 | +--------------+------------+ | gNa | 6.7 | +--------------+------------+ | gCa | 1.0 | +--------------+------------+ | a_ne | 1.0 | +--------------+------------+ | a_ni | 0.4 | +--------------+------------+ | a_ee | 0.36 | +--------------+------------+ | a_ei | 2.0 | +--------------+------------+ | a_ie | 2.0 | +--------------+------------+ | VK | -0.7 | +--------------+------------+ | VL | -0.5 | +--------------+------------+ | VNa | 0.53 | +--------------+------------+ | VCa | 1.0 | +--------------+------------+ | phi | 0.7 | +--------------+------------+ | b | 0.1 | +--------------+------------+ | I | 0.3 | +--------------+------------+ | r_NMDA | 0.25 | +--------------+------------+ | C | 0.1 | +--------------+------------+ | TCa | -0.01 | +--------------+------------+ | d_Ca | 0.15 | +--------------+------------+ | TK | 0.0 | +--------------+------------+ | d_K | 0.3 | +--------------+------------+ | VT | 0.0 | +--------------+------------+ | ZT | 0.0 | +--------------+------------+ | TNa | 0.3 | +--------------+------------+ | d_Na | 0.15 | +--------------+------------+ | d_V | 0.65 | +--------------+------------+ | d_Z | d_V | +--------------+------------+ | QV_max | 1.0 | +--------------+------------+ | QZ_max | 1.0 | +--------------+------------+ | Alstott et al. 2009 | +---------------------------+ NOTES about parameters :math:`\delta_V` : for :math:`\delta_V` < 0.55, in an uncoupled network, the system exhibits fixed point dynamics; for 0.55 < :math:`\delta_V` < 0.59, limit cycle attractors; and for :math:`\delta_V` > 0.59 chaotic attractors (eg, d_V=0.6,aee=0.5,aie=0.5, gNa=0, Iext=0.165) :math:`\delta_Z` this parameter might be spatialized: ones(N,1).*0.65 + modn*(rand(N,1)-0.5); :math:`C` The long-range coupling :math:`\delta_C` is ‘weak’ in the sense that the model is well behaved for parameter values for which C < a_ee and C << a_ie. .. figure :: img/LarterBreakspear_01_mode_0_pplane.svg :alt: Larter-Breaskpear phase plane (V, W) The (:math:`V`, :math:`W`) phase-plane for the Larter-Breakspear model. Dynamic equations: .. math:: \dot{V}_k & = - (g_{Ca} + (1 - C) \, r_{NMDA} \, a_{ee} \, Q_V + C \, r_{NMDA} \, a_{ee} \, \langle Q_V\rangle^{k}) \, m_{Ca} \, (V - VCa) \\ & \,\,- g_K \, W \, (V - VK) - g_L \, (V - VL) \\ & \,\,- (g_{Na} \, m_{Na} + (1 - C) \, a_{ee} \, Q_V + C \, a_{ee} \, \langle Q_V\rangle^{k}) \,(V - VNa) \\ & \,\,- a_{ie} \, Z \, Q_Z + a_{ne} \, I \\ & \\ \dot{W}_k & = \phi \, \dfrac{m_K - W}{\tau_{K}} \\ & \nonumber\\ \dot{Z}_k &= b (a_{ni}\, I + a_{ei}\,V\,Q_V) \\ Q_{V} &= Q_{V_{max}} \, (1 + \tanh\left(\dfrac{V_{k} - VT}{\delta_{V}}\right)) \\ Q_{Z} &= Q_{Z_{max}} \, (1 + \tanh\left(\dfrac{Z_{k} - ZT}{\delta_{Z}}\right)) See Equations (7), (3), (6) and (2) respectively in [Breaksetal_2003_a]_. Pag: 705-706 """ # Define traited attributes for this model, these represent possible kwargs. gCa = NArray( label=":math:`g_{Ca}`", default=numpy.array([1.1]), domain=Range(lo=0.9, hi=1.5, step=0.1), doc="""Conductance of population of Ca++ channels.""") gK = NArray( label=":math:`g_{K}`", default=numpy.array([2.0]), domain=Range(lo=1.95, hi= 2.05, step=0.025), doc="""Conductance of population of K channels.""") gL = NArray( label=":math:`g_{L}`", default=numpy.array([0.5]), domain=Range(lo=0.45 , hi=0.55, step=0.05), doc="""Conductance of population of leak channels.""") phi = NArray( label=r":math:`\phi`", default=numpy.array([0.7]), domain=Range(lo=0.3, hi=0.9, step=0.1), doc="""Temperature scaling factor.""") gNa = NArray( label=":math:`g_{Na}`", default=numpy.array([6.7]), domain=Range(lo=0.0, hi=10.0, step=0.1), doc="""Conductance of population of Na channels.""") TK = NArray( label=":math:`T_{K}`", default=numpy.array([0.0]), domain=Range(lo=0.0, hi=0.0001, step=0.00001), doc="""Threshold value for K channels.""") TCa = NArray( label=":math:`T_{Ca}`", default=numpy.array([-0.01]), domain=Range(lo=-0.02, hi=-0.01, step=0.0025), doc="Threshold value for Ca channels.") TNa = NArray( label=":math:`T_{Na}`", default=numpy.array([0.3]), domain=Range(lo=0.25, hi= 0.3, step=0.025), doc="Threshold value for Na channels.") VCa = NArray( label=":math:`V_{Ca}`", default=numpy.array([1.0]), domain=Range(lo=0.9, hi=1.1, step=0.05), doc="""Ca Nernst potential.""") VK = NArray( label=":math:`V_{K}`", default=numpy.array([-0.7]), domain=Range(lo=-0.8, hi=1., step=0.1), doc="""K Nernst potential.""") VL = NArray( label=":math:`V_{L}`", default=numpy.array([-0.5]), domain=Range(lo=-0.7, hi=-0.4, step=0.1), doc="""Nernst potential leak channels.""") VNa = NArray( label=":math:`V_{Na}`", default=numpy.array([0.53]), domain=Range(lo=0.51, hi=0.55, step=0.01), doc="""Na Nernst potential.""") d_K = NArray( label=r":math:`\delta_{K}`", default=numpy.array([0.3]), domain=Range(lo=0.1, hi=0.4, step=0.1), doc="""Variance of K channel threshold.""") tau_K = NArray( label=r":math:`\tau_{K}`", default=numpy.array([1.0]), domain=Range(lo=1.0, hi=10.0, step=1.0), doc="""Time constant for K relaxation time (ms)""") d_Na = NArray( label=r":math:`\delta_{Na}`", default=numpy.array([0.15]), domain=Range(lo=0.1, hi=0.2, step=0.05), doc="Variance of Na channel threshold.") d_Ca = NArray( label=r":math:`\delta_{Ca}`", default=numpy.array([0.15]), domain=Range(lo=0.1, hi=0.2, step=0.05), doc="Variance of Ca channel threshold.") aei = NArray( label=":math:`a_{ei}`", default=numpy.array([2.0]), domain=Range(lo=0.1, hi=2.0, step=0.1), doc="""Excitatory-to-inhibitory synaptic strength.""") aie = NArray( label=":math:`a_{ie}`", default=numpy.array([2.0]), domain=Range(lo=0.5, hi=2.0, step=0.1), doc="""Inhibitory-to-excitatory synaptic strength.""") b = NArray( label=":math:`b`", default=numpy.array([0.1]), domain=Range(lo=0.0001, hi=1.0, step=0.0001), doc="""Time constant scaling factor. The original value is 0.1""") C = NArray( label=":math:`C`", default=numpy.array([0.1]), domain=Range(lo=0.0, hi=1.0, step=0.01), doc="""Strength of excitatory coupling. Balance between internal and local (and global) coupling strength. C > 0 introduces interdependences between consecutive columns/nodes. C=1 corresponds to maximum coupling between node and no self-coupling. This strenght should be set to sensible values when a whole network is connected. """) ane = NArray( label=":math:`a_{ne}`", default=numpy.array([1.0]), domain=Range(lo=0.4, hi=1.0, step=0.05), doc="""Non-specific-to-excitatory synaptic strength.""") ani = NArray( label=":math:`a_{ni}`", default=numpy.array([0.4]), domain=Range(lo=0.3, hi=0.5, step=0.05), doc="""Non-specific-to-inhibitory synaptic strength.""") aee = NArray( label=":math:`a_{ee}`", default=numpy.array([0.4]), domain=Range(lo=0.0, hi=0.6, step=0.05), doc="""Excitatory-to-excitatory synaptic strength.""") Iext = NArray( label=":math:`I_{ext}`", default=numpy.array([0.3]), domain=Range(lo=0.165, hi=0.3, step=0.005), doc="""Subcortical input strength. It represents a non-specific excitation or thalamic inputs.""") rNMDA = NArray( label=":math:`r_{NMDA}`", default=numpy.array([0.25]), domain=Range(lo=0.2, hi=0.3, step=0.05), doc="""Ratio of NMDA to AMPA receptors.""") VT = NArray( label=":math:`V_{T}`", default=numpy.array([0.0]), domain=Range(lo=0.0, hi=0.7, step=0.01), doc="""Threshold potential (mean) for excitatory neurons. In [Breaksetal_2003_b]_ this value is 0.""") d_V = NArray( label=r":math:`\delta_{V}`", default=numpy.array([0.65]), domain=Range(lo=0.49, hi=0.7, step=0.01), doc="""Variance of the excitatory threshold. It is one of the main parameters explored in [Breaksetal_2003_b]_.""") ZT = NArray( label=":math:`Z_{T}`", default=numpy.array([0.0]), domain=Range(lo=0.0, hi=0.1, step=0.005), doc="""Threshold potential (mean) for inihibtory neurons.""") d_Z = NArray( label=r":math:`\delta_{Z}`", default=numpy.array([0.7]), domain=Range(lo=0.001, hi=0.75, step=0.05), doc="""Variance of the inhibitory threshold.""") # NOTE: the values were not in the article. QV_max = NArray( label=":math:`QV_{max}`", default=numpy.array([1.0]), domain=Range(lo=0.1, hi=1., step=0.001), doc="""Maximal firing rate for excitatory populations (kHz)""") QZ_max = NArray( label=":math:`QZ_{max}`", default=numpy.array([1.0]), domain=Range(lo=0.1, hi=1., step=0.001), doc="""Maximal firing rate for excitatory populations (kHz)""") t_scale = NArray( label=":math:`t_{scale}`", default=numpy.array([1.0]), domain=Range(lo=0.1, hi=1., step=0.001), doc="""Time scale factor""") variables_of_interest = List( of=str, label="Variables watched by Monitors", choices=("V", "W", "Z"), default=("V",), doc="""This represents the default state-variables of this Model to be monitored. It can be overridden for each Monitor if desired.""") # Informational attribute, used for phase-plane and initial() state_variable_range = Final( label="State Variable ranges [lo, hi]", default={ "V": numpy.array([-1.5, 1.5]), "W": numpy.array([-1.5, 1.5]), "Z": numpy.array([-1.5, 1.5])}, doc="""The values for each state-variable should be set to encompass the expected dynamic range of that state-variable for the current parameters, it is used as a mechanism for bounding random inital conditions when the simulation isn't started from an explicit history, it is also provides the default range of phase-plane plots.""") state_variables = tuple('V W Z'.split()) _state_variables = ("V", "W", "Z") _nvar = 3 cvar = numpy.array([0], dtype=numpy.int32)
[docs] def dfun(self, state_variables, coupling, local_coupling=0.0): r""" Dynamic equations: .. math:: \dot{V}_k & = - (g_{Ca} + (1 - C) \, r_{NMDA} \, a_{ee} \, Q_V + C \, r_{NMDA} \, a_{ee} \, \langle Q_V\rangle^{k}) \, m_{Ca} \, (V - VCa) \\ & \,\,- g_K \, W \, (V - VK) - g_L \, (V - VL) \\ & \,\,- (g_{Na} \, m_{Na} + (1 - C) \, a_{ee} \, Q_V + C \, a_{ee} \, \langle Q_V\rangle^{k}) \,(V - VNa) \\ & \,\,- a_{ie} \, Z \, Q_Z + a_{ne} \, I \\ & \\ \dot{W}_k & = \phi \, \dfrac{m_K - W}{\tau_{K}} \\ & \nonumber\\ \dot{Z}_k &= b (a_{ni}\, I + a_{ei}\,V\,Q_V) \\ Q_{V} &= Q_{V_{max}} \, (1 + \tanh\left(\dfrac{V_{k} - VT}{\delta_{V}}\right)) \\ Q_{Z} &= Q_{Z_{max}} \, (1 + \tanh\left(\dfrac{Z_{k} - ZT}{\delta_{Z}}\right)) """ V, W, Z = state_variables derivative = numpy.empty_like(state_variables) c_0 = coupling[0, :] # relationship between membrane voltage and channel conductance m_Ca = 0.5 * (1 + numpy.tanh((V - self.TCa) / self.d_Ca)) m_Na = 0.5 * (1 + numpy.tanh((V - self.TNa) / self.d_Na)) m_K = 0.5 * (1 + numpy.tanh((V - self.TK ) / self.d_K)) # voltage to firing rate QV = 0.5 * self.QV_max * (1 + numpy.tanh((V - self.VT) / self.d_V)) QZ = 0.5 * self.QZ_max * (1 + numpy.tanh((Z - self.ZT) / self.d_Z)) lc_0 = local_coupling * QV derivative[0] = self.t_scale * (- (self.gCa + (1.0 - self.C) * (self.rNMDA * self.aee) * (QV + lc_0)+ self.C * self.rNMDA * self.aee * c_0) * m_Ca * (V - self.VCa) - self.gK * W * (V - self.VK) - self.gL * (V - self.VL) - (self.gNa * m_Na + (1.0 - self.C) * self.aee * (QV + lc_0) + self.C * self.aee * c_0) * (V - self.VNa) - self.aie * Z * QZ + self.ane * self.Iext) derivative[1] = self.t_scale * self.phi * (m_K - W) / self.tau_K derivative[2] = self.t_scale * self.b * (self.ani * self.Iext + self.aei * V * QV) return derivative