Source code for brainpy._src.dyn.ions.calcium

# -*- coding: utf-8 -*-

from typing import Union, Callable, Optional

import brainpy.math as bm
from brainpy._src.context import share
from brainpy._src.dyn.base import IonChaDyn
from brainpy._src.initialize import OneInit, Initializer, parameter, variable
from brainpy._src.integrators.ode.generic import odeint
from brainpy.types import Shape, ArrayType
from .base import Ion

__all__ = [
  'Calcium',
  'CalciumFixed',
  'CalciumDetailed',
  'CalciumFirstOrder',
]


[docs] class Calcium(Ion): """Base class for modeling Calcium ion.""" pass
[docs] class CalciumFixed(Calcium): """Fixed Calcium dynamics. This calcium model has no dynamics. It holds fixed reversal potential :math:`E` and concentration :math:`C`. """ def __init__( self, size: Shape, keep_size: bool = False, E: Union[float, ArrayType, Initializer, Callable] = 120., C: Union[float, ArrayType, Initializer, Callable] = 2.4e-4, method: str = 'exp_auto', name: Optional[str] = None, mode: Optional[bm.Mode] = None, **channels ): super().__init__(size, keep_size=keep_size, method=method, name=name, mode=mode, **channels) self.E = parameter(E, self.varshape, allow_none=False) self.C = parameter(C, self.varshape, allow_none=False) def reset_state(self, V, C_Ca=None, E_Ca=None, batch_size=None): C_Ca = self.C if C_Ca is None else C_Ca E_Ca = self.E if E_Ca is None else E_Ca for node in self.nodes(level=1, include_self=False).unique().subset(IonChaDyn).values(): node.reset_state(V, C_Ca, E_Ca, batch_size=batch_size)
class CalciumDyna(Calcium): """Calcium ion flow with dynamics. Parameters ---------- size: int, tuple of int The ion size. keep_size: bool Keep the geometry size. C0: float, ArrayType, Initializer, Callable The Calcium concentration outside of membrane. T: float, ArrayType, Initializer, Callable The temperature. C_initializer: Initializer, Callable, ArrayType The initializer for Calcium concentration. method: str The numerical method. name: str The ion name. """ R = 8.31441 # gas constant, J*mol-1*K-1 F = 96.489 # the Faraday constant def __init__( self, size: Shape, keep_size: bool = False, C0: Union[float, ArrayType, Initializer, Callable] = 2., T: Union[float, ArrayType, Initializer, Callable] = 36., C_initializer: Union[Initializer, Callable, ArrayType] = OneInit(2.4e-4), method: str = 'exp_auto', name: Optional[str] = None, mode: Optional[bm.Mode] = None, **channels ): super().__init__(size, keep_size=keep_size, method=method, name=name, mode=mode, **channels) # parameters self.C0 = parameter(C0, self.varshape, allow_none=False) self.T = parameter(T, self.varshape, allow_none=False) # temperature self._C_initializer = C_initializer self._constant = self.R / (2 * self.F) * (273.15 + self.T) # variables self.C = variable(C_initializer, self.mode, self.varshape) # Calcium concentration self.E = bm.Variable(self._reversal_potential(self.C), batch_axis=0 if isinstance(self.mode, bm.BatchingMode) else None) # Reversal potential # function self.integral = odeint(self.derivative, method=method) def derivative(self, C, t, V): raise NotImplementedError def reset_state(self, V, C_Ca=None, E_Ca=None, batch_size=None): self.C.value = variable(self._C_initializer, batch_size, self.varshape) if (C_Ca is None) else C_Ca self.E.value = self._reversal_potential(self.C) for node in self.nodes(level=1, include_self=False).unique().subset(IonChaDyn).values(): node.reset(V, self.C, self.E, batch_size=batch_size) def update(self, V): for node in self.nodes(level=1, include_self=False).unique().subset(IonChaDyn).values(): node.update(V, self.C.value, self.E.value) self.C.value = self.integral(self.C.value, share['t'], V, share['dt']) self.E.value = self._reversal_potential(self.C.value) def _reversal_potential(self, C): return self._constant * bm.log(self.C0 / C)
[docs] class CalciumDetailed(CalciumDyna): r"""Dynamical Calcium model proposed. **1. The dynamics of intracellular** :math:`Ca^{2+}` The dynamics of intracellular :math:`Ca^{2+}` were determined by two contributions [1]_ : *(i) Influx of* :math:`Ca^{2+}` *due to Calcium currents* :math:`Ca^{2+}` ions enter through :math:`Ca^{2+}` channels and diffuse into the interior of the cell. Only the :math:`Ca^{2+}` concentration in a thin shell beneath the membrane was modeled. The influx of :math:`Ca^{2+}` into such a thin shell followed: .. math:: [Ca]_{i}=-\frac{k}{2 F d} I_{Ca} where :math:`F=96489\, \mathrm{C\, mol^{-1}}` is the Faraday constant, :math:`d=1\, \mathrm{\mu m}` is the depth of the shell beneath the membrane, the unit conversion constant is :math:`k=0.1` for :math:`I_T` in :math:`\mathrm{\mu A/cm^{2}}` and :math:`[Ca]_{i}` in millimolar, and :math:`I_{Ca}` is the summation of all :math:`Ca^{2+}` currents. *(ii) Efflux of* :math:`Ca^{2+}` *due to an active pump* In a thin shell beneath the membrane, :math:`Ca^{2+}` retrieval usually consists of a combination of several processes, such as binding to :math:`Ca^{2+}` buffers, calcium efflux due to :math:`Ca^{2+}` ATPase pump activity and diffusion to neighboring shells. Only the :math:`Ca^{2+}` pump was modeled here. We adopted the following kinetic scheme: .. math:: Ca _{i}^{2+}+ P \overset{c_1}{\underset{c_2}{\rightleftharpoons}} CaP \xrightarrow{c_3} P+ Ca _{0}^{2+} where P represents the :math:`Ca^{2+}` pump, CaP is an intermediate state, :math:`Ca _{ o }^{2+}` is the extracellular :math:`Ca^{2+}` concentration, and :math:`c_{1}, c_{2}` and :math:`c_{3}` are rate constants. :math:`Ca^{2+}` ions have a high affinity for the pump :math:`P`, whereas extrusion of :math:`Ca^{2+}` follows a slower process (Blaustein, 1988 ). Therefore, :math:`c_{3}` is low compared to :math:`c_{1}` and :math:`c_{2}` and the Michaelis-Menten approximation can be used for describing the kinetics of the pump. According to such a scheme, the kinetic equation for the :math:`Ca^{2+}` pump is: .. math:: \frac{[Ca^{2+}]_{i}}{dt}=-\frac{K_{T}[Ca]_{i}}{[Ca]_{i}+K_{d}} where :math:`K_{T}=10^{-4}\, \mathrm{mM\, ms^{-1}}` is the product of :math:`c_{3}` with the total concentration of :math:`P` and :math:`K_{d}=c_{2} / c_{1}=10^{-4}\, \mathrm{mM}` is the dissociation constant, which can be interpreted here as the value of :math:`[Ca]_{i}` at which the pump is half activated (if :math:`[Ca]_{i} \ll K_{d}` then the efflux is negligible). **2.A simple first-order model** While, in (Bazhenov, et al., 1998) [2]_, the :math:`Ca^{2+}` dynamics is described by a simple first-order model, .. math:: \frac{d\left[Ca^{2+}\right]_{i}}{d t}=-\frac{I_{Ca}}{z F d}+\frac{\left[Ca^{2+}\right]_{rest}-\left[C a^{2+}\right]_{i}}{\tau_{Ca}} where :math:`I_{Ca}` is the summation of all :math:`Ca ^{2+}` currents, :math:`d` is the thickness of the perimembrane "shell" in which calcium is able to affect membrane properties :math:`(1.\, \mathrm{\mu M})`, :math:`z=2` is the valence of the :math:`Ca ^{2+}` ion, :math:`F` is the Faraday constant, and :math:`\tau_{C a}` is the :math:`Ca ^{2+}` removal rate. The resting :math:`Ca ^{2+}` concentration was set to be :math:`\left[ Ca ^{2+}\right]_{\text {rest}}=.05\, \mathrm{\mu M}` . **3. The reversal potential** The reversal potential of calcium :math:`Ca ^{2+}` is calculated according to the Nernst equation: .. math:: E = k'{RT \over 2F} log{[Ca^{2+}]_0 \over [Ca^{2+}]_i} where :math:`R=8.31441 \, \mathrm{J} /(\mathrm{mol}^{\circ} \mathrm{K})`, :math:`T=309.15^{\circ} \mathrm{K}`, :math:`F=96,489 \mathrm{C} / \mathrm{mol}`, and :math:`\left[\mathrm{Ca}^{2+}\right]_{0}=2 \mathrm{mM}`. Parameters ---------- d : float The thickness of the peri-membrane "shell". F : float The Faraday constant. (:math:`C*mmol^{-1}`) tau : float The time constant of the :math:`Ca ^{2+}` removal rate. (ms) C_rest : float The resting :math:`Ca ^{2+}` concentration. C0 : float The :math:`Ca ^{2+}` concentration outside of the membrane. R : float The gas constant. (:math:` J*mol^{-1}*K^{-1}`) References ---------- .. [1] Destexhe, Alain, Agnessa Babloyantz, and Terrence J. Sejnowski. "Ionic mechanisms for intrinsic slow oscillations in thalamic relay neurons." Biophysical journal 65, no. 4 (1993): 1538-1552. .. [2] Bazhenov, Maxim, Igor Timofeev, Mircea Steriade, and Terrence J. Sejnowski. "Cellular and network models for intrathalamic augmenting responses during 10-Hz stimulation." Journal of neurophysiology 79, no. 5 (1998): 2730-2748. """ def __init__( self, size: Shape, keep_size: bool = False, T: Union[float, ArrayType, Initializer, Callable] = 36., d: Union[float, ArrayType, Initializer, Callable] = 1., C_rest: Union[float, ArrayType, Initializer, Callable] = 2.4e-4, tau: Union[float, ArrayType, Initializer, Callable] = 5., C0: Union[float, ArrayType, Initializer, Callable] = 2., C_initializer: Union[Initializer, Callable, ArrayType] = OneInit(2.4e-4), method: str = 'exp_auto', name: Optional[str] = None, mode: Optional[bm.Mode] = None, **channels ): super().__init__(size, keep_size=keep_size, method=method, name=name, T=T, C0=C0, C_initializer=C_initializer, mode=mode, **channels) # parameters self.d = parameter(d, self.varshape, allow_none=False) self.tau = parameter(tau, self.varshape, allow_none=False) self.C_rest = parameter(C_rest, self.varshape, allow_none=False) def derivative(self, C, t, V): ICa = self.current(V, C, self.E, external=True) drive = bm.maximum(- ICa / (2 * self.F * self.d), 0.) return drive + (self.C_rest - C) / self.tau
[docs] class CalciumFirstOrder(CalciumDyna): r"""The first-order calcium concentration model. .. math:: Ca' = -\alpha I_{Ca} + -\beta Ca """ def __init__( self, size: Shape, keep_size: bool = False, T: Union[float, ArrayType, Initializer, Callable] = 36., alpha: Union[float, ArrayType, Initializer, Callable] = 0.13, beta: Union[float, ArrayType, Initializer, Callable] = 0.075, C0: Union[float, ArrayType, Initializer, Callable] = 2., C_initializer: Union[Initializer, Callable, ArrayType] = OneInit(2.4e-4), method: str = 'exp_auto', name: Optional[str] = None, mode: Optional[bm.Mode] = None, **channels ): super().__init__(size, keep_size=keep_size, method=method, name=name, T=T, C0=C0, C_initializer=C_initializer, mode=mode, **channels) # parameters self.alpha = parameter(alpha, self.varshape, allow_none=False) self.beta = parameter(beta, self.varshape, allow_none=False) def derivative(self, C, t, V): ICa = self.current(V, C, self.E, external=True) drive = bm.maximum(- self.alpha * ICa, 0.) return drive - self.beta * C