コード例 #1
0
class Sum(Model):
    nvar = 1
    _nvar = 1
    state_variable_range = {'x': [0, 100]}
    variables_of_interest = basic.Enumerate(default=['x'], options=['x'])
    cvar = numpy.array([0])

    def dfun(self, X, coupling, local_coupling=0):
        return X + coupling + local_coupling
コード例 #2
0
class EpileptorDP2D(Model):

    r"""
    The Epileptor 2D is a composite neural mass model of two dimensions which
    has been crafted to model the phenomenology of epileptic seizures in a
    reduced form. This model is used for Linear Stability Analysis
    (see [Proixetal_2014]_).
    ->x0 parameters are shifted for the bifurcation
      to be at x0=1, where x0>1 is the supercritical region.
    ->there is a choice for linear or sigmoidal z dynamics (see [Proixetal_2014]_)
    ->some parameters change their names to be more similar to the equations.

    Equations and default parameters are taken from [Jirsaetal_2014]_.

          +------------------------------------------------------+
          |                         Table 1                      |
          +----------------------+-------------------------------+
          |        Parameter     |           Value               |
          +======================+===============================+
          |         I_ext1      |              3.1              |
          +----------------------+-------------------------------+
          |         tau0         |           2857.0              |
          +----------------------+-------------------------------+
          |         x_0          |              0.0              |
          +----------------------+-------------------------------+
          |         slope        |              0.0              |
          +----------------------+-------------------------------+
          |             Integration parameter                    |
          +----------------------+-------------------------------+
          |           dt         |              0.1              |
          +----------------------+-------------------------------+
          |  simulation_length   |              4000             |
          +----------------------+-------------------------------+
          |                    Noise                             |
          +----------------------+-------------------------------+
          |         nsig         | [0., 0., 0., 1e-3, 1e-3, 0.]  |
          +----------------------+-------------------------------+
          |       Jirsa et al. 2014, Proix et al. 2014           |
          +------------------------------------------------------+


    .. figure :: img/Epileptor_01_mode_0_pplane.svg
        :alt: Epileptor phase plane

    .. [Jirsaetal_2014] Jirsa, V. K.; Stacey, W. C.; Quilichini, P. P.;
        Ivanov, A. I.; Bernard, C. *On the nature of seizure dynamics.* Brain,
        2014.

    .. [Proixetal_2014] Proix, T., Bartolomei, F., Chauvel, P., Bernard, C.,
                       & Jirsa, V. K. (2014).
                       Permitau1ivity Coupling across Brain Regions Determines
                       Seizure Recruitment in Partial Epilepsy.
                       Journal of Neuroscience, 34(45), 15009–15021.
                       htau1p://doi.org/10.1523/JNEUROSCI.1570-14.2014

    .. automethod:: EpileptorDP.__init__

    Variables of interest to be used by monitors: -y[0] + y[3]

        .. math::
            \dot{x_{1}} &=& yc - f_{1}(x_{1},z) - z + I_{ext1} \\
            \dot{z} &=&
            \begin{cases}
            (f_z(x_{1}) - z-0.1 z^{7})/tau0 & \text{if } x<5/3 \\
            (f_z(x_{1}) - z)/tau0           & \text{if } x \geq 5/3
            \end{cases} \\

    where:
        .. math::
            f_{1}(x_{1},z) =
            \begin{cases}
            a ( x_{1} -5/3 )^{3} - b ( x_{1} -5/3 )^2 & \text{if } x_{1} <5/3\\
            ( 5*( x_{1} -5/3 ) - 0.6(z-4)^2 -slope) ( x_{1} - 5/3 ) &\text{if }x_{1} \geq 5/3
            \end{cases}

   and:
        .. math::
            f_z(x_{1})  =
            \begin{cases}
            4 * (x_{1} - r_{x0}*x0 + x0_{cr}) & \text{linear} \\
            \frac{3}{1+e^{-10*(x_{1}-7/6)}} - r_{x0}*x0 + x0_{cr} & \text{sigmoidal} \\
            \end{cases}

    """

    _ui_name = "EpileptorDP2D"
    ui_configurable_parameters = ["Iext1", "tau0", "x0", "slope"]

    zmode = arrays.FloatArray(
        label="zmode",
        default=numpy.array("lin"),
        doc="zmode = numpy.array(""lin"") for linear and numpy.array(""sig"") for sigmoidal z dynamics",
        order=-1)

#    a = arrays.FloatArray(
#        label="a",
#        default=numpy.array([1]),
#        doc="Coefficient of the cubic term in the first state variable",
#        order=-1)

#    b = arrays.FloatArray(
#        label="b",
#        default=numpy.array([3]),
#        doc="Coefficient of the squared term in the first state variabel",
#        order=-1)

    yc = arrays.FloatArray(
        label="yc",
        default=numpy.array([1]),
        doc="Additive coefficient for the second state variable",
        order=-1)

#    d = arrays.FloatArray(
#        label="d",
#        default=numpy.array([5]),
#        doc="Coefficient of the squared term in the second state variable",
#        order=-1)

    tau0 = arrays.FloatArray(
        label="tau0",
        range=basic.Range(lo=100.0, hi=5000, step=10),
        default=numpy.array([2857.0]),
        doc="Temporal scaling in the z state variable",
        order=4)

#    s = arrays.FloatArray(
#        label="s",
#        default=numpy.array([4]),
#        doc="Linear coefficient in the third state variable",
#        order=-1)

    x0 = arrays.FloatArray(
        label="x0",
        range=basic.Range(lo=-0.5, hi=1.5, step=0.1),
        default=numpy.array([0.0]),
        doc="Excitability parameter",
        order=3)

    x0cr = arrays.FloatArray(
        label="x0cr",
        range=basic.Range(lo=-1.0, hi=1.0, step=0.1),
        default=numpy.array([2.46018518518519]),
        doc="Critical excitability parameter",
        order=-1)

    r = arrays.FloatArray(
        label="r",
        range=basic.Range(lo=0.0, hi=1.0, step=0.1),
        default=numpy.array([43.0/108.0]),
        doc="Excitability parameter scaling",
        order=-1)

    Iext1 = arrays.FloatArray(
        label="Iext1",
        range=basic.Range(lo=1.5, hi=5.0, step=0.1),
        default=numpy.array([3.1]),
        doc="External input current to the first population",
        order=1)

    slope = arrays.FloatArray(
        label="slope",
        range=basic.Range(lo=-16.0, hi=6.0, step=0.1),
        default=numpy.array([0.]),
        doc="Linear coefficient in the first state variable",
        order=5)

    Kvf = arrays.FloatArray(
        label="K_vf",
        default=numpy.array([0.0]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc="Coupling scaling on a very fast time scale.",
        order=6)

    K = arrays.FloatArray(
        label="K",
        default=numpy.array([0.0]),
        range=basic.Range(lo=-4.0, hi=4.0, step=0.1),
        doc="Permittivity coupling, that is from the fast time scale toward the slow time scale",
        order=8)

    tau1 = arrays.FloatArray(
        label="tau1",
        default=numpy.array([0.25]),
        range=basic.Range(lo=0.001, hi=10.0, step=0.001),
        doc="Time scaling of the whole system",
        order=9)

    state_variable_range = basic.Dict(
        label="State variable ranges [lo, hi]",
        default={"y0": numpy.array([-2., 2.]),
                 "y1": numpy.array([-2.0, 5.0])},
        doc="n/a",
        order=16
        )

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["y0", "y1"],
        default=["y0", "y1"],
        select_multiple=True,
        doc="""default state variables to be monitored""",
        order=-1)

    state_variables = ["y0", "y1"]

    _nvar = 2
    cvar = numpy.array([0, 1], dtype=numpy.int32)

    def dfun(self, state_variables, coupling, local_coupling=0.0,
             array=numpy.array, where=numpy.where, concat=numpy.concatenate):
        r"""
        Computes the derivatives of the state variables of the Epileptor
        with respect to time.

        Implementation note: we expect this version of the Epileptor to be used
        in a vectorized manner. Concretely, y has a shape of (2, n) where n is
        the number of nodes in the network. An consequence is that
        the original use of if/else is translated by calculated both the true
        and false forms and mixing them using a boolean mask.

        Variables of interest to be used by monitors: -y[0] + y[3]

            .. math::
            \dot{y_{0}} &=& yc - f_{1}(y_{0}, y_{1}) - y_{2} + I_{ext1} \\
            \dot{y_{1}} &=&
            \begin{cases}
            (f_z(y_{0}) - y_{1}-0.1 y_{1}^{7})/tau0 & \text{if } y_{0}<5/3 \\
            (f_z(y_{0}) - y_{1})/tau0           & \text{if } y_{0} \geq 5/3
            \end{cases} \\

        where:
            .. math::
                f_{1}(y_{0}, y_{3}) =
                \begin{cases}
                a ( y_{0} -5/3 )^{3} - b ( y_{0} -5/3 )^2 & \text{if } y_{0} <5/3\\
                ( 5*( y_{0} -5/3 ) - 0.6(y_{1}-4)^2 -slope) ( y_{0} - 5/3 ) &\text{if }y_{0} \geq 5/3
                \end{cases}
        and:

            .. math::
                f_z(y_{0})  =
                \begin{cases}
                4 * (y_{0} - r*x0 + x0_{cr}) & \text{linear} \\
                \frac{3}{1+e^{-10*(y_{0}-7/6)}} - r*x0 + x0_{cr} & \text{sigmoidal} \\
                \end{cases}


        """

        y = state_variables
        ydot = numpy.empty_like(state_variables)

        Iext1 = self.Iext1 + local_coupling * y[0]
        c_pop1 = coupling[0, :]

        # population 1
        if_ydot0 = y[0] ** 2 + 2.0 * y[0] #self.a=1.0, self.b=-2.0
        else_ydot0 = 5 * y[0] - 0.6 * (y[1] - 4.0) ** 2 - self.slope
        ydot[0] = self.tau1 * (self.yc - y[1] + Iext1 + self.Kvf * c_pop1 - where(y[0] < 0.0, if_ydot0, else_ydot0) * y[0])

        # energy
        if_ydot1 = - 0.1 * y[1] ** 7
        else_ydot1 = 0

        if self.zmode == 'lin':
            fz = 4 * (y[0] - self.r * self.x0 + self.x0cr) + where(y[1] < 0.0, if_ydot1, else_ydot1) #self.x0

        elif self.zmode == 'sig':
            fz = 3.0 / (1.0 + numpy.exp(-10*(y[0] + 0.5))) - self.r * self.x0 + self.x0cr

        else:
            raise ValueError('zmode has to be either ""lin"" or ""sig"" for linear and sigmoidal fz(), respectively')

        ydot[1] = self.tau1*(fz - y[1] + self.K * c_pop1)/self.tau0

        return ydot
コード例 #3
0
class EpileptorDPrealistic(Model):
    r"""
    The Epileptor is a composite neural mass model of six dimensions which
    has been crafted to model the phenomenology of epileptic seizures.
    (see [Jirsaetal_2014]_).
    ->x0 parameters are shifted for the bifurcation
      to be at x0=1, where x0>1 is the supercritical region.
    ->there is a choice for linear or sigmoidal z dynamics (see [Proixetal_2014]_).

    Equations and default parameters are taken from [Jirsaetal_2014]_.

    The realistic Epileptor allows for state variables I_{ext1}, I_{ext2}, x0, slope and K
    to fluctuate as linear dynamical equations, driven by the corresponding
    parameter values. It could be combined with multiplicative and/or pink noise.

          +------------------------------------------------------+
          |                         Table 1                      |
          +----------------------+-------------------------------+
          |        Parameter     |           Value               |
          +======================+===============================+
          |         I_ext1      |              3.1              |
          +----------------------+-------------------------------+
          |         I_ext2      |              0.45             |
          +----------------------+-------------------------------+
          |         tau0         |           2857.0              |
          +----------------------+-------------------------------+
          |         x_0          |              0.0              |
          +----------------------+-------------------------------+
          |         slope        |              0.0              |
          +----------------------+-------------------------------+
          |             Integration parameter                    |
          +----------------------+-------------------------------+
          |           dt         |              0.1              |
          +----------------------+-------------------------------+
          |  simulation_length   |              4000             |
          +----------------------+-------------------------------+
          |                    Noise                             |
          +----------------------+-------------------------------+
          |         nsig         | [0., 0., 0., 1e-3, 1e-3, 0.]  |
          +----------------------+-------------------------------+
          |       Jirsa et al. 2014, Proix et al. 2014           |
          +------------------------------------------------------+


    .. figure :: img/Epileptor_01_mode_0_pplane.svg
        :alt: Epileptor phase plane

    .. [Jirsaetal_2014] Jirsa, V. K.; Stacey, W. C.; Quilichini, P. P.;
        Ivanov, A. I.; Bernard, C. *On the nature of seizure dynamics.* Brain,
        2014.

    .. [Proixetal_2014] Proix, T., Bartolomei, F., Chauvel, P., Bernard, C.,
                       & Jirsa, V. K. (2014).
                       Permitau1ivity Coupling across Brain Regions Determines
                       Seizure Recruitment in Partial Epilepsy.
                       Journal of Neuroscience, 34(45), 15009–15021.
                       htau1p://doi.org/10.1523/JNEUROSCI.1570-14.2014

    .. automethod:: EpileptorDP.__init__

    Variables of interest to be used by monitors: -y[0] + y[3]

        .. math::
            \dot{x_{1}} &=& y_{1} - f_{1}(x_{1}, x_{2}) - z + I_{ext1} \\
            \dot{y_{1}} &=& yc - d x_{1}^{2} - y{1} \\
            \dot{z} &=&
            \begin{cases}
            (f_z(x_{1}) - z-0.1 z^{7})/tau0 & \text{if } x<0 \\
            (f_z(x_{1}) - z)/tau0           & \text{if } x \geq 0
            \end{cases} \\
            \dot{x_{2}} &=& -y_{2} + x_{2} - x_{2}^{3} + I_{ext2} + 0.002 g - 0.3 (z-3.5) \\
            \dot{y_{2}} &=& 1 / \tau2 (-y_{2} + f_{2}(x_{2}))\\
            \dot{g} &=& -0.01 (g - 0.1 x_{1} )

    where:
        .. math::
            f_{1}(x_{1}, x_{2}) =
            \begin{cases}
            a x_{1}^{3} - b x_{1}^2 & \text{if } x_{1} <0\\
            (x_{2} - 0.6(z-4)^2 -slope) x_{1} &\text{if }x_{1} \geq 0
            \end{cases}

        .. math::
            f_z(x_{1})  =
            \begin{cases}
            4 * (x_{1} - x0) & \text{linear} \\
            \frac{3}{1+e^{-10*(x_{1}+0.5)}} - x0 & \text{sigmoidal} \\
            \end{cases}
    and:

        .. math::
            f_{2}(x_{2}) =
            \begin{cases}
            0 & \text{if } x_{2} <-0.25\\
            s*(x_{2} + 0.25) & \text{if } x_{2} \geq -0.25
            \end{cases}
    """

    _ui_name = "EpileptorDPrealistic"
    ui_configurable_parameters = ["Iext1", "Iext2", "tau0", "x0", "slope"]

    zmode = arrays.FloatArray(
        label="zmode",
        default=numpy.array("lin"),
        doc="zmode = np.array(""lin"") for linear and numpy.array(""sig"") for sigmoidal z dynamics",
        order=-1)
        
    pmode = arrays.FloatArray(
        label="pmode",
        default=numpy.array("const"),
        doc="pmode = numpy.array(""g""), numpy.array(""z""), numpy.array(""z*g"") or numpy.array(""const"") parameters following the g, z, z*g dynamics or staying constamt, respectively",
        order=-1)   

#    a = arrays.FloatArray(
#        label="a",
#        default=numpy.array([1]),
#        doc="Coefficient of the cubic term in the first state variable",
#        order=-1)

#    b = arrays.FloatArray(
#        label="b",
#        default=numpy.array([3]),
#        doc="Coefficient of the squared term in the first state variabel",
#        order=-1)

    yc = arrays.FloatArray(
        label="yc",
        default=numpy.array([1]),
        doc="Additive coefficient for the second state variable",
        order=-1)

#    d = arrays.FloatArray(
#        label="d",
#        default=numpy.array([5]),
#        doc="Coefficient of the squared term in the second state variable",
#        order=-1)

    tau0 = arrays.FloatArray(
        label="r",
        range=basic.Range(lo=100.0, hi=5000, step=10),
        default=numpy.array([10000.0]),
        doc="Temporal scaling in the third state variable",
        order=4)

#    s = arrays.FloatArray(
#        label="s",
#        default=numpy.array([4]),
#        doc="Linear coefficient in the third state variable",
#        order=-1)

    x0 = arrays.FloatArray(
        label="x0",
        range=basic.Range(lo=-0.5, hi=1.5, step=0.1),
        default=numpy.array([0.0]),
        doc="Excitability parameter",
        order=3)

    Iext1 = arrays.FloatArray(
        label="Iext1",
        range=basic.Range(lo=1.5, hi=5.0, step=0.1),
        default=numpy.array([3.1]),
        doc="External input current to the first population",
        order=1)

    slope = arrays.FloatArray(
        label="slope",
        range=basic.Range(lo=-16.0, hi=6.0, step=0.1),
        default=numpy.array([0.]),
        doc="Linear coefficient in the first state variable",
        order=5)

    Iext2 = arrays.FloatArray(
        label="Iext2",
        range=basic.Range(lo=0.0, hi=1.0, step=0.05),
        default=numpy.array([0.45]),
        doc="External input current to the second population",
        order=2)

    tau2 = arrays.FloatArray(
        label="tau2",
        default=numpy.array([10]),
        doc="Temporal scaling coefficient in fifth state variable",
        order=-1)

    Kvf = arrays.FloatArray(
        label="K_vf",
        default=numpy.array([0.0]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc="Coupling scaling on a very fast time scale.",
        order=6)

    Kf = arrays.FloatArray(
        label="K_f",
        default=numpy.array([0.0]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc="Correspond to the coupling scaling on a fast time scale.",
        order=7)

    K = arrays.FloatArray(
        label="K",
        default=numpy.array([0.0]),
        range=basic.Range(lo=-4.0, hi=4.0, step=0.1),
        doc="Permitau1ivity coupling, that is from the fast time scale toward the slow time scale",
        order=8)

    tau1 = arrays.FloatArray(
        label="tau1",
        default=numpy.array([0.25]),
        range=basic.Range(lo=0.001, hi=10.0, step=0.001),
        doc="Time scaling of the whole system",
        order=9)

    state_variable_range = basic.Dict(
        label="State variable ranges [lo, hi]",
        default={"y0": numpy.array([-2., 2.]), #x1
                 "y1": numpy.array([-20., 2.]), #y1
                 "y2": numpy.array([2.0, 20.0]), #z
                 "y3": numpy.array([-2., 0.]), #x2
                 "y4": numpy.array([0., 2.]), #y2
                 "y5": numpy.array([-1., 1.]), #g
                 "y6": numpy.array([-2, 2]), #x0
                 "y7": numpy.array([-20., 6.]), #slope
                 "y8": numpy.array([1.5, 5.]), #Iext1
                 "y9": numpy.array([0., 1.]), #Iext2
                 "y10": numpy.array([-50., 50.])},#K
        doc="n/a",
        order=16
        )

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["y0", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8", "y9", "y10", "y3 - y0"],
        default=["y3 - y0", "y2"],
        select_multiple=True,
        doc="""default state variables to be monitored""",
        order=-1)

    state_variables = ["y0", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8", "y9", "y10"]

    _nvar = 11
    cvar = numpy.array([0, 3], dtype=numpy.int32)

    @staticmethod
    def fun_slope_Iext2(z, g, pmode, slope, Iext2):

        from tvb_epilepsy.base.utils import linear_scaling

        if (pmode == numpy.array(['g','z','z*g'])).any():

            if pmode == 'g':
                xp = 1.0/ (1.0 + numpy.exp(1) ** (-10 * (g + 0.0)))
                xp1 = 0#-0.175
                xp2 = 1#0.025

            elif pmode == 'z':
                xp = 1.0 / (1.0 + numpy.exp(1) ** (-10 * (z - 3.00)))
                xp1 = 0
                xp2 = 1

            elif pmode == 'z*g':
                xp = z * g
                xp1 = -0.7
                xp2 = 0.1
            slope_eq = linear_scaling(xp, xp1, xp2, 1.0, slope)
            #slope_eq = self.slope
            Iext2_eq = linear_scaling(xp, xp1, xp2, 0.0, Iext2)

        else:
            slope_eq = slope
            Iext2_eq = Iext2

        return slope_eq, Iext2_eq
        
    def dfun(self, state_variables, coupling, local_coupling=0.0,
             array=numpy.array, where=numpy.where, concat=numpy.concatenate):
        r"""
        Computes the derivatives of the state variables of the Epileptor
        with respect to time.

        Implementation note: we expect this version of the Epileptor to be used
        in a vectorized manner. Concretely, y has a shape of (6, n) where n is
        the number of nodes in the network. An consequence is that
        the original use of if/else is translated by calculated both the true
        and false forms and mixing them using a boolean mask.

        Variables of interest to be used by monitors: -y[0] + y[3]

            .. math::
            \dot{y_{0}} &=& y_{1} - f_{1}(y_{0}, y_{3}) - y_{2} + I_{ext1} \\
            \dot{y_{1}} &=& yc - d (y_{0} -5/3)^{2} - y{1} \\
            \dot{y_{2}} &=&
            \begin{cases}
            (f_z(y_{0}) - y_{2}-0.1 y_{2}^{7})/tau0 & \text{if } y_{0}<5/3 \\
            (f_z(y_{0}) - y_{2})/tau0           & \text{if } y_{0} \geq 5/3
            \end{cases} \\
            \dot{y_{3}} &=& -y_{4} + y_{3} - y_{3}^{3} + I_{ext2} + 0.002 y_{5} - 0.3 (y_{2}-3.5) \\
            \dot{y_{4}} &=& 1 / \tau2 (-y_{4} + f_{2}(y_{3}))\\
            \dot{y_{5}} &=& -0.01 (y_{5} - 0.1 ( y_{0} -5/3 ) )

        where:
            .. math::
                f_{1}(y_{0}, y_{3}) =
                \begin{cases}
                a ( y_{0} -5/3 )^{3} - b ( y_{0} -5/3 )^2 & \text{if } y_{0} <5/3\\
                ( y_{3} - 0.6(y_{2}-4)^2 -slope ) ( y_{0} - 5/3 ) &\text{if }y_{0} \geq 5/3
                \end{cases}

            .. math::
                f_z(y_{0})  =
                \begin{cases}
                4 * (y_{0} - x0) & \text{linear} \\
                \frac{3}{1+e^{-10*(y_{0}-7/6)}} - x0 & \text{sigmoidal} \\
                \end{cases}
        and:

            .. math::
                f_{2}(y_{3}) =
                \begin{cases}
                0 & \text{if } y_{3} <-0.25\\
                s*(y_{3} + 0.25) & \text{if } y_{3} \geq -0.25
                \end{cases}

        """

        y = state_variables
        ydot = numpy.empty_like(state_variables)


        #To use later:
        x0=y[6]
        slope = y[7]
        Iext1 = y[8]
        Iext2 = y[9]
        K = y[10]

        Iext1 = self.Iext1 + local_coupling * y[0]
        c_pop1 = coupling[0, :]
        c_pop2 = coupling[1, :]

        # population 1
        if_ydot0 = -y[0]**2 + 3.0*y[0] #self.a=1.0, self.b=3.0
        else_ydot0 = slope - y[3] + 0.6*(y[2]-4.0)**2
        ydot[0] = self.tau1 * (y[1] - y[2] + Iext1 + self.Kvf * c_pop1 + where(y[0] < 0.0, if_ydot0, else_ydot0) * y[0])
        ydot[1] = self.tau1 * (self.yc - 5.0 * y[0] ** 2 - y[1]) #self.d=5

        # energy
        if_ydot2 = - 0.1*y[2]**7
        else_ydot2 = 0

        if self.zmode == 'lin':
            fz = 4*(y[0] - x0) + where(y[2] < 0., if_ydot2, else_ydot2)

        elif self.zmode == 'sig':
            fz = 3.0 / (1.0 + numpy.exp(-10 * (y[0] + 0.5))) - x0

        else:
            raise ValueError("zmode has to be either ""lin"" or ""sig"" for linear and sigmoidal fz(), respectively")
        ydot[2] = self.tau1 * ((fz - y[2] + K * c_pop1) / self.tau0)

        # population 2
        ydot[3] = self.tau1 * (-y[4] + y[3] - y[3] ** 3 + Iext2 + 2*y[5] - 0.3 * (y[2] - 3.5) + self.Kf * c_pop2)
        if_ydot4 = 0
        else_ydot4 = 6.0 * (y[3] + 0.25) #self.s = 6.0
        ydot[4] = self.tau1 * ((-y[4] + where(y[3] < -0.25, if_ydot4, else_ydot4)) / self.tau2)

        # filter
        ydot[5] = self.tau1 * (-0.01 * (y[5] - 0.1 * y[0]))

        slope_eq, Iext2_eq = self.fun_slope_Iext2(y[2], y[5], self.pmode, self.slope, self.Iext2)
        
        # x0
        ydot[6] = self.tau1 * (-y[6] + self.x0)
        # slope
        ydot[7] = 10 * self.tau1 * (-y[7] + slope_eq) #5*
        # Iext1
        ydot[8] = self.tau1 * (-y[8] + self.Iext1) / self.tau0
        # Iext2
        ydot[9] = 5 * self.tau1*(-y[9] + Iext2_eq)
        # K
        ydot[10] = self.tau1*(-y[10] + self.K) / self.tau0

        return ydot


    def jacobian(self, state_variables, coupling, local_coupling=0.0,
                 array=numpy.array, where=numpy.where, concat=numpy.concatenate):

        return None
コード例 #4
0
class EpileptorDP(Model):
    r"""
    The Epileptor is a composite neural mass model of six dimensions which
    has been crafted to model the phenomenology of epileptic seizures.
    (see [Jirsaetal_2014]_). 
    ->x0 parameters are shifted for the bifurcation
      to be at x0=1, where x0>1 is the supercritical region.
    ->there is a choice for linear or sigmoidal z dynamics (see [Proixetal_2014]_)
    ->some parameters change their names to be more similar to the equations.

    Equations and default parameters are taken from [Jirsaetal_2014]_.

          +------------------------------------------------------+
          |                         Table 1                      |
          +----------------------+-------------------------------+
          |        Parameter     |           Value               |
          +======================+===============================+
          |         I_ext1      |              3.1              |
          +----------------------+-------------------------------+
          |         I_ext2      |              0.45             |
          +----------------------+-------------------------------+
          |         tau0         |           2857.0              |
          +----------------------+-------------------------------+
          |         x_0          |              0.0              |
          +----------------------+-------------------------------+
          |         slope        |              0.0              |
          +----------------------+-------------------------------+
          |             Integration parameter                    |
          +----------------------+-------------------------------+
          |           dt         |              0.1              |
          +----------------------+-------------------------------+
          |  simulation_length   |              4000             |
          +----------------------+-------------------------------+
          |                    Noise                             |
          +----------------------+-------------------------------+
          |         nsig         | [0., 0., 0., 1e-3, 1e-3, 0.]  |
          +----------------------+-------------------------------+
          |       Jirsa et al. 2014, Proix et al. 2014           |
          +------------------------------------------------------+


    .. figure :: img/Epileptor_01_mode_0_pplane.svg
        :alt: Epileptor phase plane

    .. [Jirsaetal_2014] Jirsa, V. K.; Stacey, W. C.; Quilichini, P. P.;
        Ivanov, A. I.; Bernard, C. *On the nature of seizure dynamics.* Brain,
        2014.

    .. [Proixetal_2014] Proix, T., Bartolomei, F., Chauvel, P., Bernard, C.,
                       & Jirsa, V. K. (2014).
                       Permitivity Coupling across Brain Regions Determines
                       Seizure Recruitment in Partial Epilepsy.
                       Journal of Neuroscience, 34(45), 15009–15021.
                       htau1p://doi.org/10.1523/JNEUROSCI.1570-14.2014

    .. automethod:: EpileptorDP.__init__

    Variables of interest to be used by monitors: -y[0] + y[3]

        .. math::
            \dot{x_{1}} &=& y_{1} - f_{1}(x_{1}, x_{2}) - z + I_{ext1} \\
            \dot{y_{1}} &=& yc - d x_{1}^{2} - y{1} \\
            \dot{z} &=&
            \begin{cases}
            (f_z(x_{1}) - z-0.1 z^{7})/tau0 & \text{if } x<0 \\
            (f_z(x_{1}) - z)/tau0           & \text{if } x \geq 0
            \end{cases} \\
            \dot{x_{2}} &=& -y_{2} + x_{2} - x_{2}^{3} + I_{ext2} + 0.002 g - 0.3 (z-3.5) \\
            \dot{y_{2}} &=& 1 / \tau2 (-y_{2} + f_{2}(x_{2}))\\
            \dot{g} &=& -0.01 (g - 0.1 x_{1} )

    where:
        .. math::
            f_{1}(x_{1}, x_{2}) =
            \begin{cases}
            a x_{1}^{3} - b x_{1}^2 & \text{if } x_{1} <0\\
            ( x_{2} - 0.6(z-4)^2 -slope ) x_{1}  &\text{if }x_{1} \geq 0
            \end{cases}

        .. math::
            f_z(x_{1})  =
            \begin{cases}
            4 * (x_{1} - x0) & \text{linear} \\
            \frac{3}{1+e^{-10*(x_{1}+0.5)}} - x0  & \text{sigmoidal} \\
            \end{cases}
    and:

        .. math::
            f_{2}(x_{2}) =
            \begin{cases}
            0 & \text{if } x_{2} <-0.25\\
            s*(x_{2} + 0.25) & \text{if } x_{2} \geq -0.25
            \end{cases}
    """

    _ui_name = "EpileptorDP"
    ui_configurable_parameters = ["Iext1", "Iext2", "tau0", "x0", "slope"]

    zmode = arrays.FloatArray(
        label="zmode",
        default=numpy.array("lin"),
        doc="zmode = numpy.array(""lin"") for linear and numpy.array(""sig"") for sigmoidal z dynamics",
        order=-1)

#    a = arrays.FloatArray(
#        label="a",
#        default=numpy.array([1]),
#        doc="Coefficient of the cubic term in the first state variable",
#        order=-1)

#    b = arrays.FloatArray(
#        label="b",
#        default=numpy.array([3]),
#        doc="Coefficient of the squared term in the first state variabel",
#        order=-1)

    yc = arrays.FloatArray(
        label="yc",
        default=numpy.array([1]),
        doc="Additive coefficient for the second state variable",
        order=-1)

#    d = arrays.FloatArray(
#        label="d",
#        default=numpy.array([5]),
#        doc="Coefficient of the squared term in the second state variable",
#        order=-1)

    tau0 = arrays.FloatArray(
        label="r",
        range=basic.Range(lo=100.0, hi=5000, step=10),
        default=numpy.array([2857.0]),
        doc="Temporal scaling in the third state variable",
        order=4)

#    s = arrays.FloatArray(
#        label="s",
#        default=numpy.array([4]),
#        doc="Linear coefficient in the third state variable",
#        order=-1)

    x0 = arrays.FloatArray(
        label="x0",
        range=basic.Range(lo=-0.5, hi=1.5, step=0.1),
        default=numpy.array([0.0]),
        doc="Excitability parameter",
        order=3)

    Iext1 = arrays.FloatArray(
        label="Iext1",
        range=basic.Range(lo=1.5, hi=5.0, step=0.1),
        default=numpy.array([3.1]),
        doc="External input current to the first population",
        order=1)

    slope = arrays.FloatArray(
        label="slope",
        range=basic.Range(lo=-16.0, hi=6.0, step=0.1),
        default=numpy.array([0.]),
        doc="Linear coefficient in the first state variable",
        order=5)

    Iext2 = arrays.FloatArray(
        label="Iext2",
        range=basic.Range(lo=0.0, hi=1.0, step=0.05),
        default=numpy.array([0.45]),
        doc="External input current to the second population",
        order=2)

    tau2 = arrays.FloatArray(
        label="tau2",
        default=numpy.array([10]),
        doc="Temporal scaling coefficient in fifth state variable",
        order=-1)

    Kvf = arrays.FloatArray(
        label="K_vf",
        default=numpy.array([0.0]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc="Coupling scaling on a very fast time scale.",
        order=6)

    Kf = arrays.FloatArray(
        label="K_f",
        default=numpy.array([0.0]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc="Correspond to the coupling scaling on a fast time scale.",
        order=7)

    K = arrays.FloatArray(
        label="K",
        default=numpy.array([0.0]),
        range=basic.Range(lo=-4.0, hi=4.0, step=0.1),
        doc="Permitau1ivity coupling, that is from the fast time scale toward the slow time scale",
        order=8)

    tau1 = arrays.FloatArray(
        label="tau1",
        default=numpy.array([0.25]),
        range=basic.Range(lo=0.001, hi=10.0, step=0.001),
        doc="Time scaling of the whole system",
        order=9)

    state_variable_range = basic.Dict(
        label="State variable ranges [lo, hi]",
        default={"y0": numpy.array([-2., 2.]),
                 "y1": numpy.array([-20., 2.]),
                 "y2": numpy.array([2.0, 20.0]),
                 "y3": numpy.array([-2., 0.]),
                 "y4": numpy.array([0., 2.]),
                 "y5": numpy.array([-1., 1.])},
        doc="n/a",
        order=16
        )

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["y0", "y1", "y2", "y3", "y4", "y5", "y3 - y0"],
        default=["y3 - y0", "y2"],
        select_multiple=True,
        doc="""default state variables to be monitored""",
        order=-1)

    state_variables = ["y0", "y1", "y2", "y3", "y4", "y5"]

    _nvar = 6
    cvar = numpy.array([0, 3], dtype=numpy.int32)


    def dfun(self, state_variables, coupling, local_coupling=0.0,
             array=numpy.array, where=numpy.where, concat=numpy.concatenate):
        r"""
        Computes the derivatives of the state variables of the Epileptor
        with respect to time.

        Implementation note: we expect this version of the Epileptor to be used
        in a vectorized manner. Concretely, y has a shape of (6, n) where n is
        the number of nodes in the network. An consequence is that
        the original use of if/else is translated by calculated both the true
        and false forms and mixing them using a boolean mask.

        Variables of interest to be used by monitors: -y[0] + y[3]

            .. math::
            \dot{y_{0}} &=& y_{1} - f_{1}(y_{0}, y_{3}) - y_{2} + I_{ext1} \\
            \dot{y_{1}} &=& yc - d y_{0}^{2} - y{1} \\
            \dot{y_{2}} &=&
            \begin{cases}
            (f_z(y_{0}) - y_{2}-0.1 y_{2}^{7})/tau0 & \text{if } y_{0}<0 \\
            (f_z(y_{0}) - y_{2})/tau0           & \text{if } y_{0} \geq 0
            \end{cases} \\
            \dot{y_{3}} &=& -y_{4} + y_{3} - y_{3}^{3} + I_{ext2} + 0.002 y_{5} - 0.3 (y_{2}-3.5) \\
            \dot{y_{4}} &=& 1 / \tau2 (-y_{4} + f_{2}(y_{3}))\\
            \dot{y_{5}} &=& -0.01 (y_{5} - 0.1 y_{0} )

        where:
            .. math::
                f_{1}(y_{0}, y_{3}) =
                \begin{cases}
                a y_{0}^{3} - by_{0}^2 & \text{if } y_{0} <0\\
                (y_{3} - 0.6(y_{2}-4)^2 slope)y_{0} &\text{if }y_{0} \geq 0
                \end{cases}

            .. math::
                f_z(y_{0})  =
                \begin{cases}
                4 * (y_{0} - x0) & \text{linear} \\
                \frac{3}{1+e^{-10*(y_{0}+0.5)}} - x0 & \text{sigmoidal} \\
                \end{cases}
        and:

            .. math::
                f_{2}(y_{3}) =
                \begin{cases}
                0 & \text{if } y_{3} <-0.25\\
                s*(y_{3} + 0.25) & \text{if } y_{3} \geq -0.25
                \end{cases}

        """

        y = state_variables
        ydot = numpy.empty_like(state_variables)

        Iext1 = self.Iext1 + local_coupling * y[0]
        c_pop1 = coupling[0, :]
        c_pop2 = coupling[1, :]

        #TVB Epileptor in commented lines below

        # population 1
        #if_ydot0 = - self.a * y[0] ** 2 + self.b * y[0]
        if_ydot0 = -y[0]**2 + 3.0*y[0] #self.a=1.0, self.b=3.0
        #else_ydot0 = self.slope - y[3] + 0.6 * (y[2] - 4.0) ** 2
        else_ydot0 = self.slope - y[3] + 0.6 * (y[2]-4.0) ** 2
        # ydot[0] = self.tt * (y[1] - y[2] + Iext + self.Kvf * c_pop1 + where(y[0] < 0., if_ydot0, else_ydot0) * y[0])
        ydot[0] = self.tau1 * (y[1] - y[2] + Iext1 + self.Kvf * c_pop1 + where(y[0] < 0.0, if_ydot0, else_ydot0) * y[0])
        # ydot[1] = self.tt * (self.c - self.d * y[0] ** 2 - y[1])
        ydot[1] = self.tau1 * (self.yc - 5.0 * y[0] ** 2 - y[1]) #self.d=5

        # energy
        #if_ydot2 = - 0.1 * y[2] ** 7
        if_ydot2 = - 0.1 * y[2] ** 7
        #else_ydot2 = 0
        else_ydot2 = 0

        if self.zmode == 'lin':
            # self.r * (4 * (y[0] - self.x0) - y[2]      + where(y[2] < 0., if_ydot2, else_ydot2)
            fz = 4*(y[0] - self.x0) + where(y[2] < 0., if_ydot2, else_ydot2)

        elif self.zmode == 'sig':
            fz = 3.0 / (1.0 + numpy.exp(-10 * (y[0] + 0.5))) - self.x0

        else:
            raise ValueError("zmode has to be either ""lin"" or ""sig"" for linear and sigmoidal fz(), " +
                             "respectively")

        # ydot[2] = self.tt * (        ...+ self.Ks * c_pop1))
        ydot[2] = self.tau1 * ((fz - y[2] + self.K * c_pop1) / self.tau0)

        # population 2
        # ydot[3] = self.tt * (-y[4] + y[3] - y[3] ** 3 + self.Iext2 + 2 * y[5] - 0.3 * (y[2] - 3.5) + self.Kf * c_pop2)
        ydot[3] = self.tau1 * (-y[4] + y[3] - y[3] ** 3 + self.Iext2 + 2 * y[5] - 0.3 * (y[2] - 3.5) + self.Kf * c_pop2)
        # if_ydot4 = 0
        if_ydot4 = 0
        # else_ydot4 = self.aa * (y[3] + 0.25)
        else_ydot4 = 6.0 * (y[3] + 0.25) #self.s = 6.0
        # ydot[4] = self.tt * ((-y[4] + where(y[3] < -0.25, if_ydot4, else_ydot4)) / self.tau)
        ydot[4] = self.tau1 * ((-y[4] + where(y[3] < -0.25, if_ydot4, else_ydot4)) / self.tau2)

        # filter
        #ydot[5] = self.tt * (-0.01 * (y[5] - 0.1 * y[0]))
        ydot[5] = self.tau1*(-0.01 * (y[5] - 0.1 * y[0]))

        return ydot

    def jacobian(self, state_variables, coupling, local_coupling=0.0,
                 array=numpy.array, where=numpy.where, concat=numpy.concatenate):

        return None
コード例 #5
0
class WongWang(models.Model):
    """
    .. [WW_2006] Kong-Fatt Wong and Xiao-Jing Wang,  *A Recurrent Network 
                Mechanism of Time Integration in Perceptual Decisions*. 
                Journal of Neuroscience 26(4), 1314-1328, 2006.

    .. [WW_2006_SI] Supplementary Information
                
    .. [WW_2007] Kong-Fatt Wong, Alexander C. Huk2, Michael N. Shadlen,
                Xiao-Jing Wang, *Neural circuit dynamics underlying accumulation
                of time-varying evidence during perceptual decision making*.
                Front. Comput. Neurosci., 2007.

    A reduced model by Wong and Wang: A reduced two-variable neural model 
    that offers a simple yet biophysically plausible framework for studying 
    perceptual decision making in general.

    S is the NMDA gating variable. Since its decay time is much longer that those
    corresponding to AMPAand GABA gating variables, it is assumed that is 
    :math:`S_{NMDA}` that dominates the time evolution of the system.

    The model (:math:`Sl`, :math:`Sr`) phase-plane, including a representation 
    of the vector field as well as its nullclines, using default parameters, 
    can be seen below:

    Notation and parameter selection follows _Materials and methods_ from [WW_2007].

    To reproduce the phase plane in Figure 5B, page 1320:
        Jll = Jrr = 0.3725
        Jlr = Jrl = 0.1137
        J_ext = 1.1e-3
        I_o = 0.3297
        mu_o = 30
        c = 6.4 

    To reproduce C & D vary c parameter respectively.

    .. automethod:: __init__

    """
    _ui_name = "Wong-Wang (2D)"

    #Define traited attributes for this model, these represent possible kwargs.
    a = arrays.FloatArray(
        label=":math:`a`",
        default=numpy.array([
            270.,
        ]),
        range=basic.Range(lo=0.0, hi=1000.0),
        doc="""[Hz/nA] Parameter chosen to fit numerical solutions.""")

    b = arrays.FloatArray(
        label=":math:`b`",
        default=numpy.array([
            108,
        ]),
        range=basic.Range(lo=0.0, hi=1.0),
        doc="""[Hz]. Parameter chosen to fit numerical solutions.""")

    d = arrays.FloatArray(
        label=":math:`d`",
        default=numpy.array([
            0.154,
        ]),
        range=basic.Range(lo=0.0, hi=200.0),
        doc="""[s]. Parameter chosen to fit numerical solutions.""")

    gamma = arrays.FloatArray(label=r":math:`\gamma`",
                              default=numpy.array([
                                  0.641,
                              ]),
                              range=basic.Range(lo=0.0, hi=1.0),
                              doc="""Kinetic parameter""")

    tau_s = arrays.FloatArray(
        label=r":math:`\tau_S`",
        default=numpy.array([
            60.,
        ]),
        range=basic.Range(lo=50.0, hi=150.0),
        doc="""[ms] Kinetic parameter. NMDA decay time constant.""")

    tau_noise = arrays.FloatArray(label=r":math:`\tau_{noise}`",
                                  default=numpy.array([
                                      2.,
                                  ]),
                                  range=basic.Range(lo=1.0, hi=10.0),
                                  doc="""[ms] Noise decay time constant.""",
                                  order=-1)

    Jll = arrays.FloatArray(label=":math:`J_{ll}`",
                            default=numpy.array([
                                0.3725,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    Jrr = arrays.FloatArray(label=":math:`J_{rr}`",
                            default=numpy.array([
                                0.3725,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    Jlr = arrays.FloatArray(label=":math:`J_{lr}`",
                            default=numpy.array([
                                0.1137,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    Jrl = arrays.FloatArray(label=":math:`J_{rl}`",
                            default=numpy.array([
                                0.1137,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    J_N = arrays.FloatArray(label=":math:`J_{N}`",
                            default=numpy.array([
                                0.1137,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""External synaptic coupling""")

    J_ext = arrays.FloatArray(label=":math:`J_{ext}`",
                              default=numpy.array([
                                  1.1e-3,
                              ]),
                              range=basic.Range(lo=0.0, hi=0.01),
                              doc="""[nA/Hz] Synaptic coupling""")

    I_o = arrays.FloatArray(label=":math:`I_{o}`",
                            default=numpy.array([
                                0.3297,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Effective external input""")

    sigma_noise = arrays.FloatArray(
        label=r":math:`\sigma_{noise}`",
        default=numpy.array([
            0.009,
        ]),
        range=basic.Range(lo=0.0, hi=1.0),
        doc="""Noise amplitude. Take this value into account for stochatic
        integration schemes.""")

    mu_o = arrays.FloatArray(label=r":math:`\mu_{0}`",
                             default=numpy.array([
                                 30,
                             ]),
                             range=basic.Range(lo=0.0, hi=50.0),
                             doc="""[Hz] Stimulus amplitude""")

    c = arrays.FloatArray(
        label=":math:`c`",
        default=numpy.array([
            51.0,
        ]),
        range=basic.Range(lo=0.0, hi=100.0),
        doc="""[%].  Percentage coherence or motion strength. This parameter
        comes from experiments in MT cells.""")

    f = arrays.FloatArray(
        label=":math:`f`",
        default=numpy.array([
            1.,
        ]),  #0.45
        range=basic.Range(lo=0.0, hi=100.0),
        doc=""" Gain of MT firing rates""")

    state_variable_range = basic.Dict(label="State variable ranges [lo, hi]",
                                      default={
                                          "Sl": numpy.array([0., 1.]),
                                          "Sr": numpy.array([0., 1.])
                                      },
                                      doc="n/a",
                                      order=-1)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["Sl", "Sr"],
        default=["Sl"],
        select_multiple=True,
        doc="""default state variables to be monitored""",
        order=10)

    state_variables = ['Sl', 'Sr']

    def __init__(self, **kwargs):
        """
        .. May need to put kwargs back if we can't get them from trait...

        """

        super(WongWang, self).__init__(**kwargs)

        self._nvar = 2
        self.cvar = numpy.array([0], dtype=numpy.int32)

        #derived parameters
        self.I_mot_l = None
        self.I_mot_r = None

        LOG.debug('%s: inited.' % repr(self))

    def configure(self):
        """  """
        super(WongWang, self).configure()
        self.update_derived_parameters()

    def dfun(self, state_variables, coupling, local_coupling=0.0):
        r"""
        The notation of those dynamic equations follows [WW_2007].
        Derivatives of s are multiplied by 0.001 constant to match ms time scale.
        """
        # add global coupling?
        sl = state_variables[0, :]
        sr = state_variables[1, :]

        c_0 = coupling[0, :]
        lc_0_l = local_coupling * sl
        lc_0_r = local_coupling * sr

        I_l = self.Jll * sl - self.Jlr * sr + self.I_mot_l + self.I_o + self.J_N * c_0 + self.J_N * lc_0_l
        I_r = self.Jrr * sr - self.Jrl * sl + self.I_mot_r + self.I_o + self.J_N * c_0 + self.J_N * lc_0_r

        r = lambda I_i: (self.a * I_i - self.b) * 1. / (1 - numpy.exp(
            -self.d * (self.a * I_i - self.b)))

        ds1 = -sl * 1. / self.tau_s + (
            1 - sl) * self.gamma * r(I_l) * 0.001  # to ms
        ds2 = -sr * 1. / self.tau_s + (
            1 - sr) * self.gamma * r(I_r) * 0.001  # to ms

        derivative = numpy.array([ds1, ds2])
        return derivative

    def update_derived_parameters(self):
        """
        Derived parameters
        """
        # Additional parameter g_stim introduced that controls I_mot strength
        self.I_mot_l = self.J_ext * self.mu_o * (1 +
                                                 self.f * self.c * 1. / 100)
        self.I_mot_r = self.J_ext * self.mu_o * (1 -
                                                 self.f * self.c * 1. / 100)
        if len(self.I_mot_l) > 1:
            self.I_mot_l = numpy.expand_dims(self.I_mot_l, -1)
            self.I_mot_r = numpy.expand_dims(self.I_mot_r, -1)
コード例 #6
0
class FFT(core.Type):
    """
    A class for calculating the FFT of a TimeSeries object of TVB and returning
    a FourierSpectrum object. A segment length and windowing function can be
    optionally specified. By default the time series is segmented into 1 second
    blocks and no windowing function is applied.
    """

    time_series = time_series.TimeSeries(
        label="Time Series",
        required=True,
        doc="""The TimeSeries to which the FFT is to be applied.""",
        order=1)

    segment_length = basic.Float(
        label="Segment(window) length (ms)",
        default=1000.0,
        required=False,
        doc="""The TimeSeries can be segmented into equally sized blocks
            (overlapping if necessary). The segment length determines the
            frequency resolution of the resulting power spectra -- longer
            windows produce finer frequency resolution.""",
        order=2)

    window_function = basic.Enumerate(
        label="Windowing function",
        options=SUPPORTED_WINDOWING_FUNCTIONS,
        default=None,
        required=False,
        select_multiple=False,
        doc="""Windowing functions can be applied before the FFT is performed.
             Default is None, possibilities are: 'hamming'; 'bartlett';
            'blackman'; and 'hanning'. See, numpy.<function_name>.""",
        order=3)
    
    
    def evaluate(self):
        """
        Calculate the FFT of time_series broken into segments of length
        segment_length and filtered by window_function.
        """
        cls_attr_name = self.__class__.__name__ + ".time_series"
        self.time_series.trait["data"].log_debug(owner=cls_attr_name)
        
        tpts = self.time_series.data.shape[0]
        time_series_length = tpts * self.time_series.sample_period
        
        #Segment time-series, overlapping if necessary
        nseg = int(numpy.ceil(time_series_length / self.segment_length))
        if nseg > 1:
            seg_tpts = numpy.ceil(self.segment_length / self.time_series.sample_period)
            overlap = (seg_tpts * nseg - tpts) / (nseg - 1.0)
            starts = [max(seg * (seg_tpts - overlap), 0) for seg in range(nseg)]
            segments = [self.time_series.data[start:start + seg_tpts]
                        for start in starts]
            segments = [segment[:, :, :, numpy.newaxis] for segment in segments]
            time_series = numpy.concatenate(segments, axis=4)
        else:
            self.segment_length = time_series_length
            time_series = self.time_series.data[:, :, :, numpy.newaxis]
            seg_tpts = time_series.shape[0]
        
        LOG.debug("Segment length being used is: %s" % self.segment_length)
        
        #Base-line correct the segmented time-series  
        time_series = sp_signal.detrend(time_series, axis=0)
        util.log_debug_array(LOG, time_series, "time_series")
        
        #Apply windowing function
        if self.window_function is not None and self.window_function != [None]:
            if self.window_function not in SUPPORTED_WINDOWING_FUNCTIONS:
                LOG.error("Windowing function is: %s" % self.window_function)
                LOG.error("Must be in: %s" % str(SUPPORTED_WINDOWING_FUNCTIONS))
            else:
                window_function = eval("".join(("numpy.", self.window_function[0])))
                window_mask = numpy.reshape(window_function(seg_tpts),
                                            (seg_tpts, 1, 1, 1, 1))
                time_series = time_series * window_mask

        #Calculate the FFT
        result = numpy.fft.fft(time_series, axis=0)
        nfreq = result.shape[0] / 2
        result = result[1:nfreq + 1, :]
        util.log_debug_array(LOG, result, "result")

        spectra = spectral.FourierSpectrum(source=self.time_series,
                                           segment_length=self.segment_length,
                                           array_data=result,
                                           use_storage=False)

        return spectra
    
    
    def result_shape(self, input_shape, segment_length, sample_period):
        """Returns the shape of the main result (complex array) of the FFT."""
        freq_len = (segment_length / sample_period) / 2.0
        freq_len = int(min((input_shape[0], freq_len)))
        nseg = max((1, int(numpy.ceil(input_shape[0] * sample_period / segment_length))))
        result_shape = (freq_len, input_shape[1], input_shape[2], input_shape[3], nseg)
        return result_shape
    
    
    def result_size(self, input_shape, segment_length, sample_period):
        """
        Returns the storage size in Bytes of the main result (complex array) of 
        the FFT.
        """
        result_size = numpy.prod(self.result_shape(input_shape, segment_length,
                                                   sample_period)) * 2.0 * 8.0  # complex*Bytes
        return result_size


    def extended_result_size(self, input_shape, segment_length, sample_period):
        """
        Returns the storage size in Bytes of the extended result of the FFT. 
        That is, it includes storage of the evaluated FourierSpectrum attributes
        such as power, phase, amplitude, etc.
        """
        result_shape = self.result_shape(input_shape, segment_length, sample_period)
        result_size = self.result_size(input_shape, segment_length, sample_period)
        extend_size = result_size           # Main array
        extend_size += 0.5 * result_size    # Amplitude
        extend_size += 0.5 * result_size    # Phase
        extend_size += 0.5 * result_size    # Power
        extend_size += 0.5 * result_size / result_shape[4]  # Average power
        extend_size += 0.5 * result_size / result_shape[4]  # Normalised Average power
        extend_size += result_shape[0] * 8.0    # Frequency
        return extend_size
コード例 #7
0
class Larter(models.Model):
    """
    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] 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.
    
    Equations are taken from [Larteretal_1999]_. Parameter values are taken from
    Table I, page 799.
    
    Regarding the choice of coupling: the three biophysically reasonable
    mechanisms (diffusive; delay line axonal/ synaptic or glial; and
    extracellular current flow) are dependent of K++. This is reflected in the
    potassium equilibrium potential (:math:`V_{K}`). Thus, this variable is
    chosen as the coupling element between nodes.
    
        .. figure :: img/Larter_01_mode_0_pplane.svg
            :alt: Larter phase plane (V, W)
            
            The (:math:`V`, :math:`W`) phase-plane for the Larter model.
    
    .. #Currently there seems to be a clash betwen traits and autodoc, autodoc
    .. #can't find the methods of the class, the class specific names below get
    .. #us around this...
    .. automethod:: Larter.__init__
    .. automethod:: Larter.dfun
    
    """

    _ui_name = "Larter"
    ui_configurable_parameters = [
        'gCa', 'gK', 'gL', 'phi', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7',
        'VK', 'VL', 'tau_K', 'a_exc', 'a_inh', 'b', 'c', 'Iext'
    ]

    #Define traited attributes for this model, these represent possible kwargs.
    gCa = arrays.FloatArray(
        label=":math:`g_{Ca}`",
        default=numpy.array([1.1]),
        range=basic.Range(lo=0.9, hi=1.5, step=0.01),
        doc="""Conductance of population of Ca++ channels""",
        order=1)

    gK = arrays.FloatArray(label=":math:`g_K`",
                           default=numpy.array([2.0]),
                           range=basic.Range(lo=1.5, hi=2.5, step=0.01),
                           doc="""Conductance of population of K channels""",
                           order=2)

    gL = arrays.FloatArray(
        label=":math:`g_L`",
        default=numpy.array([0.5]),
        range=basic.Range(lo=0.25, hi=0.75, step=0.01),
        doc="""Conductance of population of leak channels""",
        order=3)

    phi = arrays.FloatArray(label=":math:`\\phi`",
                            default=numpy.array([0.7]),
                            range=basic.Range(lo=0.35, hi=1.05, step=0.01),
                            doc="""Temperature scaling factor""",
                            order=4)

    V1 = arrays.FloatArray(label=":math:`V_1`",
                           default=numpy.array([-0.01]),
                           range=basic.Range(lo=-0.1, hi=0.1, step=0.01),
                           doc="""Threshold value for :math:`M_{\\infty}`""",
                           order=5)

    V2 = arrays.FloatArray(
        label=":math:`V_2`",
        default=numpy.array([0.15]),
        range=basic.Range(lo=0.01, hi=1.0, step=0.01),
        doc="""Steepness parameter for :math:`M_{\\infty}`""",
        order=6)

    V3 = arrays.FloatArray(label=":math:`V_3`",
                           default=numpy.array([0.0]),
                           range=basic.Range(lo=0.0, hi=1.0, step=0.01),
                           doc="""Threshold value for :math:`W_{\\infty}`""",
                           order=7)

    V4 = arrays.FloatArray(
        label=":math:`V_4`",
        default=numpy.array([0.3]),
        range=basic.Range(lo=0.01, hi=1.0, step=0.01),
        doc="""Steepness parameter for :math:`W_{\\infty}`""",
        order=8)

    V5 = arrays.FloatArray(label=":math:`V_5`",
                           default=numpy.array([0.0]),
                           range=basic.Range(lo=0.0, hi=1.0, step=0.01),
                           doc="""Threshold value for :math:`a_{exc}`""",
                           order=9)

    V6 = arrays.FloatArray(
        label=":math:`V_6`",
        default=numpy.array([0.6]),
        range=basic.Range(lo=0.01, hi=1.0, step=0.01),
        doc="""Steepness parameter for a_exc and :math:`a_{inh}`""",
        order=10)

    V7 = arrays.FloatArray(label=":math:`V_7`",
                           default=numpy.array([0.0]),
                           range=basic.Range(lo=0.0, hi=1.0, step=0.01),
                           doc="""Threshold value for :math:`a_{inh}`""",
                           order=11)

    VK = arrays.FloatArray(label=":math:`V_K`",
                           default=numpy.array([-0.7]),
                           range=basic.Range(lo=-0.8, hi=1.0, step=0.01),
                           doc="""K Nernst potential""",
                           order=12)

    VL = arrays.FloatArray(label=":math:`V_L`",
                           default=numpy.array([-0.5]),
                           range=basic.Range(lo=-0.75, hi=-0.25, step=0.01),
                           doc="""Nernst potential leak channels""",
                           order=13)

    tau_K = arrays.FloatArray(label=":math:`\\tau_K`",
                              default=numpy.array([1.0]),
                              range=basic.Range(lo=0.5, hi=1.5, step=0.01),
                              doc="""Time constant for K relaxation time""",
                              order=14)

    a_exc = arrays.FloatArray(label=":math:`a_{exc}`",
                              default=numpy.array([1.0]),
                              range=basic.Range(lo=0.7, hi=1.3, step=0.01),
                              doc="""strength of excitatory synapse""",
                              order=15)

    a_inh = arrays.FloatArray(label=":math:`a_{ie}`",
                              default=numpy.array([1.0]),
                              range=basic.Range(lo=0.7, hi=1.3, step=0.01),
                              doc="""strength of inhibitory synapse""",
                              order=16)

    b = arrays.FloatArray(label=":math:`b`",
                          default=numpy.array([0.1]),
                          range=basic.Range(lo=0.05, hi=0.15, step=0.01),
                          doc="""Time constant scaling factor""",
                          order=17)

    c = arrays.FloatArray(label=":math:`c`",
                          default=numpy.array([0.165]),
                          range=basic.Range(lo=0.0, hi=0.2, step=0.01),
                          doc="""strength of feedforward inhibition""",
                          order=18)

    Iext = arrays.FloatArray(
        label=":math:`I_{ext}`",
        default=numpy.array([0.3]),
        range=basic.Range(lo=0.15, hi=0.45, step=0.01),
        doc="""Subcortical input strength. It represents a non-specific
       excitation of both the excitatory and inhibitory populations.""",
        order=19)

    #Used for phase-plane axis ranges and to bound random initial() conditions.
    state_variable_range = basic.Dict(
        label="State Variable ranges [lo, hi]",
        default={
            "V": numpy.array([-0.3, 0.1]),
            "W": numpy.array([0.0, 0.6]),
            "Z": numpy.array([-0.02, 0.08])
        },
        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.""",
        order=20)

    # variables_of_interest = arrays.IntegerArray(
    #     label = "Variables watched by Monitors",
    #     range = basic.Range(lo = 0, hi = 3, step=1),
    #     default = numpy.array([0, 2], dtype=numpy.int32),
    #     doc = """This represents the default state-variables of this Model to be
    #     monitored. It can be overridden for each Monitor if desired. The
    #     corresponding state-variable indices for this model are :math:`V = 0`,
    #     :math:`W = 1`, and :math:`Z = 2`.""",
    #     order = 21)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["V", "W", "Z"],
        default=["V", "W", "Z"],
        select_multiple=True,
        doc="""This represents the default state-variables of this Model to be
        monitored. It can be overridden for each Monitor if desired. The 
        corresponding state-variable indices for this model are :math:`V = 0`,
        :math:`W = 1`, and :math:`Z = 2`.""",
        order=21)

    def __init__(self, **kwargs):
        """
        Initialize the Larter model's traited attributes, any provided as
        keywords will overide their traited default.
        
        """
        LOG.info('%s: initing...' % str(self))
        super(Larter, self).__init__(**kwargs)

        #self._state_variables = ["V", "W", "Z"]
        self._nvar = 3

        self.cvar = numpy.array([0], dtype=numpy.int32)

        LOG.debug('%s: inited.' % repr(self))

    def dfun(self, state_variables, coupling, local_coupling=0.0):
        """
        .. math::
             \\dot{V} &= - g_L \\, (V - V_L) - g_K\\, Z \\, (V - V_K) -
                 g_{Ca} \\, m_{\\infty} \\, (V - 1) + I - \\alpha_{inh}\\,Z  \\\\
             \\dot{W} &= \\frac{\\phi \\, (w_{\\infty} - W)}{\\tau_w} \\\\
             \\dot{Z}(t) &= b ( c \\, I_{ext} + \\alpha_{exc} \\,V ) \\\\
             m_{\\infty} &= 0.5 \\, \\left(1 + \\tanh\\left(\\frac{V - V_1}{V_2}\\right)\\right) \\\\
             w_{\\infty} &= 0.5 \\, \\left(1 + \\tanh\\left(\\frac{V - V_3}{V_4}\\right)\\right)\\\\
             tau_{w} &= \\left[ \\cosh\\left(\\frac{V - V_3}{2 \\,V_4}\\right) \\right]^{-1} \\\\
             \\alpha_{exc} &= a_{exc} \\,\\left(1 + \\tanh\\left(\\frac{V - V_5}{V_6}\\right)\\right)\\\\
             \\alpha_{inh} &= a_{inh} \\,\\left(1 + \\tanh\\left(\\frac{V - V_7}{V_6}\\right)\\right)
             
        See Eqs (1)-(8) in [Larteretal_1999]_
        """
        ##--------------------- As in Larter 1999 ----------------------------##
        V = state_variables[0, :]
        W = state_variables[1, :]
        Z = state_variables[2, :]

        c_0 = coupling[0, :]

        M_inf = 0.5 * (1 + numpy.tanh((V - self.V1) / self.V2))
        W_inf = 0.5 * (1 + numpy.tanh((V - self.V3) / self.V4))
        tau_Winv = numpy.cosh((V - self.V3) / (2 * self.V4))
        alpha_exc = self.a_exc * (1 + numpy.tanh((V - self.V5) / self.V6))
        alpha_inh = self.a_inh * (1 + numpy.tanh((V - self.V7) / self.V6))

        #import pdb; pdb.set_trace()
        dV = (local_coupling * V - alpha_inh * Z - self.gL * (V - self.VL) -
              self.gCa * M_inf * (V - 1) - self.gK * W * (V - self.VK + c_0) +
              self.Iext)

        dW = self.phi * tau_Winv * (W_inf - W)

        dZ = self.b * ((self.c * self.Iext) + (alpha_exc * V))

        derivative = numpy.array([dV, dW, dZ])

        return derivative
コード例 #8
0
class SpatialAverage(Monitor):
    """
    Monitors the averaged value for the models variable of interest over sets of
    nodes -- defined by spatial_mask. This is primarily intended for use with
    surface simulations, with a default behaviour, when no spatial_mask is
    specified, of using surface.region_mapping in order to reduce a surface
    simulation back to a single average timeseries for each region in the
    associated Connectivity. However, any vector of length nodes containing
    integers, from a set contiguous from zero, specifying the new grouping to
    which each node belongs should work.

    Additionally, this monitor temporally sub-samples the simulation every `istep` 
    integration steps.

    """
    _ui_name = "Spatial average with temporal sub-sample"

    spatial_mask = arrays.IntegerArray( #TODO: Check it's a vector of length Nodes (like region mapping for surface)
        label = "An index mask of nodes into areas",
        doc = """A vector of length==nodes that assigns an index to each node
            specifying the "region" to which it belongs. The default usage is
            for mapping a surface based simulation back to the regions used in 
            its `Long-range Connectivity.`""")
    
    default_mask = basic.Enumerate(
                              label = "Default Mask",
                              options = ["cortical", "hemispheres"],
                              default = ["hemispheres"],
                              doc = r"""Fallback in case spatial mask is none and no surface provided 
                              to use either connectivity hemispheres or cortical attributes.""",
                              order = -1)

    def config_for_sim(self, simulator):

        # initialize base attributes
        super(SpatialAverage, self).config_for_sim(simulator)
        self.is_default_special_mask = False

        # setup given spatial mask or default to region mapping
        if self.spatial_mask.size == 0:
            self.is_default_special_mask = True
            if not (simulator.surface is None):
                self.spatial_mask = simulator.surface.region_mapping
            else:
                conn = simulator.connectivity
                if self.default_mask[0] == 'cortical':
                    if conn is not None and conn.cortical is not None and conn.cortical.size > 0:
                        ## Use as spatial-mask cortical/non cortical areas
                        self.spatial_mask = [int(c) for c in conn.cortical]
                    else:
                        msg = "Must fill Spatial Mask parameter for non-surface simulations when using SpatioTemporal monitor!"
                        raise Exception(msg)
                if self.default_mask[0] == 'hemispheres':
                    if conn is not None and conn.hemispheres is not None and conn.hemispheres.size > 0:
                        ## Use as spatial-mask left/right hemisphere
                        self.spatial_mask = [int(h) for h in conn.hemispheres]
                    else:
                        msg = "Must fill Spatial Mask parameter for non-surface simulations when using SpatioTemporal monitor!"
                        raise Exception(msg)

        number_of_nodes = simulator.number_of_nodes
        if self.spatial_mask.size != number_of_nodes:
            msg = "spatial_mask must be a vector of length number_of_nodes."
            raise Exception(msg)

        areas = numpy.unique(self.spatial_mask)
        number_of_areas = len(areas)
        if not numpy.all(areas == numpy.arange(number_of_areas)):
            msg = ("Areas in the spatial_mask must be specified as a "
                    "contiguous set of indices starting from zero.")
            raise Exception(msg)

        util.log_debug_array(LOG, self.spatial_mask, "spatial_mask", owner=self.__class__.__name__)
        spatial_sum = numpy.zeros((number_of_nodes, number_of_areas))
        spatial_sum[numpy.arange(number_of_nodes), self.spatial_mask] = 1
        spatial_sum = spatial_sum.T
        util.log_debug_array(LOG, spatial_sum, "spatial_sum")
        nodes_per_area = numpy.sum(spatial_sum, axis=1)[:, numpy.newaxis]
        self.spatial_mean = spatial_sum / nodes_per_area
        util.log_debug_array(LOG, self.spatial_mean, "spatial_mean", owner=self.__class__.__name__)


    def sample(self, step, state):
        if step % self.istep == 0:
            time = step * self.dt
            monitored_state = numpy.dot(self.spatial_mean, state[self.voi, :])
            return [time, monitored_state.transpose((1, 0, 2))]

    def create_time_series(self, storage_path, connectivity=None, surface=None,
                           region_map=None, region_volume_map=None):
        if self.is_default_special_mask:
            return TimeSeriesRegion(storage_path=storage_path,
                                    sample_period=self.period,
                                    region_mapping=region_map,
                                    region_mapping_volume=region_volume_map,
                                    title='Regions ' + self.__class__.__name__,
                                    connectivity=connectivity,
                                    **self._transform_user_tags())
        else:
            # mask does not correspond to the number of regions
            # let the parent create a plain TimeSeries
            return super(SpatialAverage, self).create_time_series(storage_path)
コード例 #9
0
ファイル: epileptor.py プロジェクト: maedoc/tvb-library
class HMJEpileptor(models.Model):
    """
    The Epileptor is a composite neural mass model of six dimensions which 
    has be crafted to model the phenomenology of epileptic seizures.

    This model, its motivation and derivation are currently in preparation
    for publication (Jirsa et al, 2013)

    .. automethod:: HMJEpileptor.__init__
    .. automethod:: HMJEpileptor.dfun
    """

    _ui_name = "Epileptor"
    ui_configurable_parameters = ["Iext", "Iext2", "r", "x0"]

    a = arrays.FloatArray(
        label="a",
        default=numpy.array([1]),
        doc="n/a",
        order=-1)

    b = arrays.FloatArray(
        label="b",
        default=numpy.array([3]),
        doc="n/a",
        order=-1)

    c = arrays.FloatArray(
        label="c",
        default=numpy.array([1]),
        doc="n/a",
        order=-1)

    d = arrays.FloatArray(
        label="d",
        default=numpy.array([5]),
        doc="n/a",
        order=-1)

    r = arrays.FloatArray(
        label="r",
        range=basic.Range(lo=0.0, hi=0.001, step=0.00005),
        default=numpy.array([0.00035]),
        doc="n/a",
        order=4)

    s = arrays.FloatArray(
        label="s",
        default=numpy.array([4]),
        doc="n/a",
        order=-1)

    x0 = arrays.FloatArray(
        label="x0",
        range=basic.Range(lo=-3.0, hi=0.0, step=0.1),
        default=numpy.array([-1.6]),
        doc="n/a",
        order=3)

    Iext = arrays.FloatArray(
        label="Iext",
        range=basic.Range(lo=1.5, hi=5.0, step=0.1),
        default=numpy.array([3.1]),
        doc="n/a",
        order=1)

    omega2 = arrays.FloatArray(
        label="omega2",
        default=numpy.array([0.1]),
        doc="n/a",
        order=-1)

    slope = arrays.FloatArray(
        label="slope",
        default=numpy.array([0.]),
        doc="n/a",
        order=-1)

    Iext2 = arrays.FloatArray(
        label="Iext2",
        range=basic.Range(lo=0.0, hi=1.0, step=0.05),
        default=numpy.array([0.45]),
        doc="n/a",
        order=2)

    tau = arrays.FloatArray(
        label="tau",
        default=numpy.array([10]),
        doc="n/a",
        order=-1)

    aa = arrays.FloatArray(
        label="aa",
        default=numpy.array([6]),
        doc="n/a",
        order=-1)
        
    Kpop1 = arrays.FloatArray(
        label="K_11",
        default=numpy.array([0.5]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc='''Test parameter. Correspond to the coupling scaling. Move outside to be
        consistent with the general TVB implementation.''',
        order=-1)
        
    Kpop2 = arrays.FloatArray(
        label="K_22",
        default=numpy.array([0.2]),
        range=basic.Range(lo=0.0, hi=1.0, step=0.5),
        doc='''Test parameter. Correspond to the coupling scaling. Move outside to be
        consistent with the general TVB implementation.''',
        order=-1)

    state_variable_range = basic.Dict(
        label="State variable ranges [lo, hi]",
        default = {"y0": numpy.array([0., 1e-10]),
                   "y1": numpy.array([-5., 0.]),
                   "y2": numpy.array([3., 4.]),
                   "y3": numpy.array([0., 1e-10]),
                   "y4": numpy.array([0., 1e-10]),
                   "y5": numpy.array([0., 1e-2]) },
        doc = "n/a",
        order=-1
        )

    variables_of_interest = basic.Enumerate(
                              label = "Variables watched by Monitors",
                              options = ["y0", "y1", "y2", "y3", "y4", "y5"],
                              default = ["y0", "y3"],
                              select_multiple = True,
                              doc = """default state variables to be monitored""",
                              order = 10)

#    variables_of_interest = arrays.IntegerArray(
#        label="Variables watched by Monitors",
#        range=basic.Range(lo=0.0, hi=6.0, step=1.0),
#        default=numpy.array([0], dtype=numpy.int32),
#        doc="default state variables to be monitored",
#        order=10)


    def __init__(self, **kwargs):
        """
        """

        LOG.info("%s: init'ing..." % (str(self),))

        super(HMJEpileptor, self).__init__(**kwargs)

        #self._state_variables = ["y%d" % i for i in range(6)]
        #self._state_variables = ["y%d" % i for i in range(6)]
        self._nvar = 6
        self.cvar = numpy.array([0,3], dtype=numpy.int32)


        LOG.debug("%s: init'ed." % (repr(self),))

    def dfun(self, state_variables, coupling, local_coupling=0.0,
             array=numpy.array, where=numpy.where, concat=numpy.concatenate):
        """
        Computes the derivatives of the state variables of the Epileptor 
        with respect to time. 

        Implementation note: we expect this version of the Epileptor to be used
        in a vectorized manner. Concretely, y has a shape of (6, n) where n is 
        the number of nodes in the network. An consequence is that
        the original use of if/else is translated by calculated both the true and
        false forms and mixing them using a boolean mask.

        Variables of interest to be used by monitors: -y[0] + y[3]

        """

        """
        First population with high frequency burst and baseline jump - mechanisms
        is similar to a Hindmarsh-Rose scenario with two régimes connected by a
        slow trajectory (here y(3)).
        """

        y = state_variables
        n = y.shape[1]
        Iext = self.Iext + coupling[0, :] + local_coupling
        c_pop1 = coupling[0, :]
        c_pop2 = coupling[1, :]

        # if y(1)<0.
        #     ydot1 = y(2)-a*y(1)^3 + b*y(1)^2-y(3)+iext; 
        #     ydot2 = c-d*y(1)^2-y(2); 
        #     ydot3 =  r*(s*(y(1)-x0)  - y(3));   % energy consumption = 1 - available energy

        if_y1_lt_0 = concat([ (y[1] - self.a*y[0]**3 + self.b*y[0]**2 - y[2] + Iext).reshape((1, n, 1)),
                              (self.c - self.d*y[0]**2 - y[1]).reshape((1, n, 1)),
                              (self.r*(self.s*(y[0] - self.x0) - y[2] - self.Kpop1 * (c_pop1 - y[0]) )).reshape((1, n, 1)) ])

         # else
        # %    ydot1 = y(2) + (slope - y(4) -1.0*(y(3)-4))*y(1) - y(3)+iext; % this is just an
        # %    alternative representation, which worked well
        #     ydot1 = y(2) + (slope - y(4) + 0.6*(y(3)-4)^2)*y(1) -y(3)+iext; 
        # %   here the high energy burst is being generated through variation of the slope: 
        # %               1. via y(4) within the epileptic spike complex;         
        # %               2. via the expression with y(3), which causes more
        # %               oscillations at the beginning of the seizure (effect of the
        # %               energy available)
        #     ydot2 = c-d*y(1)^2-y(2);  
        #     ydot3 =   r*(s*(y(1)-x0)  - y(3));
        # end

        else_pop1 = concat([ (y[1] + (self.slope - y[3] + 0.6*(y[2]-4.0)**2)*y[0] - y[2] + Iext).reshape((1, n, 1)),
                         (self.c - self.d*y[0]**2 - y[1]).reshape((1, n, 1)),
                         (self.r*(self.s*(y[0] - self.x0) - y[2] - self.Kpop1 * (c_pop1 - y[0]))).reshape((1, n, 1)) ])

        pop1 = where(y[0] < 0., if_y1_lt_0, else_pop1)

        # % istim= 0*block(t,150,1);
        # 
        # % this is the second population that generates the big spike-wave complex
        # % preictally and within the seizure via a morris-lecar-jirsa (mlj) structure
        # 
        # if y(4)<-0.25
        #     ydot4 = -y(5)+ y(4)-y(4)^3 + iext2 + 2*y(6)-0.3*(y(3)-3.5) ; % these last two terms
        #     % put the population dynamics into the critical regime. in particular,
        #     % y(6) turns the oscillator on and off, whereas the y(3) term helps it to become precritical (critical fluctuations). 
        #     ydot5 = -y(5)/tau ;

        if_ = concat([ (-y[4] + y[3] - y[3]**3 + self.Iext2 + 2*y[5] - 0.3*(y[2] - 3.5) + self.Kpop2 * (c_pop2 - y[3])).reshape((1, n, 1)), (-y[4]/self.tau).reshape((1, n, 1)) ])
        # else
        #     ydot4 = -y(5)+ y(4)-y(4)^3 + iext2+ 2*y(6)-0.3*(y(3)-3.5); 
        #     ydot5 = (-y(5) + aa*(y(4)+0.25))/tau;   % here is the mlj structure
        # end

        else_pop2 = concat([ (-y[4] + y[3] - y[3]**3 + self.Iext2 + 2*y[5] - 0.3*(y[2] - 3.5) + self.Kpop2 * (c_pop2 - y[3])).reshape((1, n, 1)), ((-y[4] + self.aa*(y[3] + 0.25))/self.tau).reshape((1, n, 1)) ])


        pop2 = where(y[3] < -0.25, if_, else_pop2)

        # 
        #  ydot6 = -0.01*(y(6)-0.1*y(1)) ;

        energy = array([ -0.01*(y[5] - 0.1*y[0])])
        
        # 
        # ydot = [ydot1;ydot2;ydot3;ydot4;ydot5;ydot6];

        return concat((pop1, pop2, energy))
コード例 #10
0
class WongWang(models.Model):
    """
    .. [WW_2006] Kong-Fatt Wong and Xiao-Jing Wang,  *A Recurrent Network 
                Mechanism of Time Integration in Perceptual Decisions*. 
                Journal of Neuroscience 26(4), 1314-1328, 2006.

    .. [WW_2006_SI] Supplementary Information

    A reduced model by Wong and Wang: A reduced two-variable neural model 
    that offers a simple yet biophysically plausible framework for studying 
    perceptual decision making in general.

    S is the NMDA gating variable. Since its decay time is much longer that those
    corresponding to AMPAand GABA gating variables, it is assumed that is 
    :math:`S_{NMDA}` that dominates the time evolution of the system.

    The model (:math:`S1`, :math:`S2`) phase-plane, including a representation 
    of the vector field as well as its nullclines, using default parameters, 
    can be seen below:

    .. figure :: img/WongWang_01_mode_0_pplane.svg
    .. _phase-plane-WongWang:
        :alt: Phase plane of the reduced model by Wong and Wang (S1, S2)

    To reproduce the phase plane in Figure 4A, page 1319 (five steady states):
        J11 = 0.54
        J22 = 0.18
        J12 = 0.08
        J21 = 0.58
        J_ext = 0.0
        I_o = 0.34
        sigma_noise = 0.02
        mu_o = 0.00
        c = 100.0

    To reproduce the phase plane in Figure 4B, page 1319 (saddle-type point):
        b = 0.108
        d = 121.0
        gamma = 0.11
        tau_s = 100.
        J11 = 0.78
        J22 = 0.59
        J12 = 0.72
        J21 = 0.67
        J_ext = 0.52
        I_o = 0.3255
        sigma_noise = 0.02
        mu_o = 0.35
        c = 0.0

    .. automethod:: __init__

    """
    _ui_name = "Wong-Wang (Original)"

    #Define traited attributes for this model, these represent possible kwargs.
    a = arrays.FloatArray(
        label=":math:`a`",
        default=numpy.array([
            0.270,
        ]),
        range=basic.Range(lo=0.0, hi=1.0),
        doc=""" (mVnC)^{-1}. Parameter chosen to fit numerical solutions.""")

    b = arrays.FloatArray(
        label=":math:`b`",
        default=numpy.array([
            0.108,
        ]),
        range=basic.Range(lo=0.0, hi=1.0),
        doc="""[kHz]. Parameter chosen to fit numerical solutions.""")

    d = arrays.FloatArray(
        label=":math:`d`",
        default=numpy.array([
            154.0,
        ]),
        range=basic.Range(lo=0.0, hi=200.0),
        doc="""[ms]. Parameter chosen to fit numerical solutions.""")

    gamma = arrays.FloatArray(
        label=r":math:`\gamma`",
        default=numpy.array([
            0.0641,
        ]),
        range=basic.Range(lo=0.0, hi=1.0),
        doc="""Kinetic parameter divided by 1000 to set the time scale in ms"""
    )

    tau_s = arrays.FloatArray(
        label=r":math:`\tau_S`",
        default=numpy.array([
            100.,
        ]),
        range=basic.Range(lo=50.0, hi=150.0),
        doc="""Kinetic parameter. NMDA decay time constant.""")

    tau_ampa = arrays.FloatArray(
        label=r":math:`\tau_{ampa}`",
        default=numpy.array([
            2.,
        ]),
        range=basic.Range(lo=1.0, hi=10.0),
        doc="""Kinetic parameter. AMPA decay time constant.""",
        order=-1)

    J11 = arrays.FloatArray(label=":math:`J_{11}`",
                            default=numpy.array([
                                0.2609,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    J22 = arrays.FloatArray(label=":math:`J_{22}`",
                            default=numpy.array([
                                0.2609,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    J12 = arrays.FloatArray(label=":math:`J_{12}`",
                            default=numpy.array([
                                0.0497,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    J21 = arrays.FloatArray(label=":math:`J_{21}`",
                            default=numpy.array([
                                0.0497,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Synaptic coupling""")

    J_ext = arrays.FloatArray(label=":math:`J_{ext}`",
                              default=numpy.array([
                                  0.52,
                              ]),
                              range=basic.Range(lo=0.0, hi=1.0),
                              doc="""Synaptic coupling""")

    I_o = arrays.FloatArray(label=":math:`I_{o}`",
                            default=numpy.array([
                                0.3255,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0),
                            doc="""Effective external input""")

    sigma_noise = arrays.FloatArray(
        label=r":math:`\sigma_{noise}`",
        default=numpy.array([
            0.02,
        ]),
        range=basic.Range(lo=0.0, hi=1.0),
        doc="""Noise amplitude. Take this value into account for stochatic
        integration schemes.""")

    mu_o = arrays.FloatArray(label=r":math:`\mu_{0}`",
                             default=numpy.array([
                                 0.03,
                             ]),
                             range=basic.Range(lo=0.0, hi=1.0),
                             doc="""Stimulus amplitude""")

    c = arrays.FloatArray(
        label=":math:`c`",
        default=numpy.array([
            51.0,
        ]),
        range=basic.Range(lo=0.0, hi=100.0),
        doc="""[%].  Percentage coherence or motion strength. This parameter
        comes from experiments in MT cells.""")

    state_variable_range = basic.Dict(label="State variable ranges [lo, hi]",
                                      default={
                                          "S1": numpy.array([0.0, 0.3]),
                                          "S2": numpy.array([0.0, 0.3])
                                      },
                                      doc="n/a",
                                      order=-1)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["S1", "S2"],
        default=["S1"],
        select_multiple=True,
        doc="""default state variables to be monitored""",
        order=10)

    def __init__(self, **kwargs):
        """
        .. May need to put kwargs back if we can't get them from trait...

        """

        #LOG.info('%s: initing...' % str(self))

        super(WongWang, self).__init__(**kwargs)

        #self._state_variables = ["S1", "S2"]
        self._nvar = 2
        self.cvar = numpy.array([0], dtype=numpy.int32)

        #derived parameters
        self.I_1 = None
        self.I_2 = None

        LOG.debug('%s: inited.' % repr(self))

    def configure(self):
        """  """
        super(WongWang, self).configure()
        self.update_derived_parameters()

    def dfun(self, state_variables, coupling, local_coupling=0.0):
        r"""
        These dynamic equations, taken from [WW_2006]_, ...

        ..math::

            \frac{dS_{i}}{dt} &= - \frac{S_{i}}{\tau_{S}} + (1 - S_{i})\gamma H_{i} \\
            H_{i} &= \frac{a x_{i} - b}{1- \exp[-d (a x_{i} - b)]} \\
            x_{1} &= J11  S_{1} - J_{12}S_{2} + I_{0} + I_{1} \\
            x_{2} &= J22  S_{2} - J_{21}S_{1} + I_{0} + I_{2} \\
            I_{i} &= J_{ext} \mu_{0} \left( 1 \pm \frac{c}{100}\right)

        where :math:`i=` 1, 2 labels the selective population.

        """
        # add global coupling?
        s1 = state_variables[0, :]
        s2 = state_variables[1, :]

        c_0 = coupling[0]

        x1 = self.J11 * s1 - self.J12 * s2 + self.I_o + self.I_1
        x2 = self.J21 * s2 - self.J22 * s1 + self.I_o + self.I_2

        H1 = (self.a * x1 - self.b) / (1 - numpy.exp(-self.d * (self.a * x1 - \
                                                                self.b)))
        H2 = (self.a * x2 - self.b) / (1 - numpy.exp(-self.d * (self.a * x2 - \
                                                                self.b)))

        ds1 = -(s1 / self.tau_s) + (1 - s1) * H1 * self.gamma
        ds2 = -(s2 / self.tau_s) + (1 - s2) * H2 * self.gamma

        derivative = numpy.array([ds1, ds2])

        return derivative

    def update_derived_parameters(self):
        """
        Derived parameters
        """

        self.I_1 = self.J_ext * self.mu_o * (1 + self.c / 100)
        self.I_2 = self.J_ext * self.mu_o * (1 - self.c / 100)
コード例 #11
0
class BalloonModel(core.Type):
    """

    A class for calculating the simulated BOLD signal given a TimeSeries
    object of TVB and returning another TimeSeries object.

    The haemodynamic model parameters based on constants for a 1.5 T scanner.
        
    """

    #NOTE: a potential problem when the input is a TimeSeriesSurface.
    #TODO: add an spatial averaging for TimeSeriesSurface.

    time_series = time_series.TimeSeries(
        label="Time Series",
        required=True,
        doc="""The timeseries that represents the input neural activity""",
        order=1)
    # it also sets the bold sampling period.
    dt = basic.Float(
        label=":math:`dt`",
        default=0.002,
        required=True,
        doc="""The integration time step size for the balloon model (s).
        If none is provided, by default, the TimeSeries sample period is used.""",
        order=2)

    integrator = integrators_module.Integrator(
        label="Integration scheme",
        default=integrators_module.HeunDeterministic,
        required=True,
        order=-1,
        doc=""" A tvb.simulator.Integrator object which is
        an integration scheme with supporting attributes such as 
        integration step size and noise specification for stochastic 
        methods. It is used to compute the time courses of the balloon model state 
        variables.""")

    bold_model = basic.Enumerate(
        label="Select BOLD model equations",
        options=["linear", "nonlinear"],
        default=["nonlinear"],
        select_multiple=False,
        doc="""Select the set of equations for the BOLD model.""",
        order=4)

    RBM = basic.Bool(
        label="Revised BOLD Model",
        default=True,
        required=True,
        doc="""Select classical vs revised BOLD model (CBM or RBM).
        Coefficients  k1, k2 and k3 will be derived accordingly.""",
        order=5)

    neural_input_transformation = basic.Enumerate(
        label="Neural input transformation",
        options=["none", "abs_diff", "sum"],
        default=["none"],
        select_multiple=False,
        doc=
        """ This represents the operation to perform on the state-variable(s) of
        the model used to generate the input TimeSeries. ``none`` takes the
        first state-variable as neural input; `` abs_diff`` is the absolute
        value of the derivative (first order difference) of the first state variable; 
        ``sum``: sum all the state-variables of the input TimeSeries.""",
        order=3)

    tau_s = basic.Float(
        label=r":math:`\tau_s`",
        default=0.65,
        required=True,
        doc="""Balloon model parameter. Time of signal decay (s)""",
        order=-1)

    tau_f = basic.Float(
        label=r":math:`\tau_f`",
        default=0.41,
        required=True,
        doc=""" Balloon model parameter. Time of flow-dependent elimination or
        feedback regulation (s). The average  time blood take to traverse the
        venous compartment. It is the  ratio of resting blood volume (V0) to
        resting blood flow (F0).""",
        order=-1)

    tau_o = basic.Float(label=r":math:`\tau_o`",
                        default=0.98,
                        required=True,
                        doc="""
        Balloon model parameter. Haemodynamic transit time (s). The average
        time blood take to traverse the venous compartment. It is the  ratio
        of resting blood volume (V0) to resting blood flow (F0).""",
                        order=-1)

    alpha = basic.Float(
        label=r":math:`\tau_f`",
        default=0.32,
        required=True,
        doc=
        """Balloon model parameter. Stiffness parameter. Grubb's exponent.""",
        order=-1)

    TE = basic.Float(label=":math:`TE`",
                     default=0.04,
                     required=True,
                     doc="""BOLD parameter. Echo Time""",
                     order=-1)

    V0 = basic.Float(label=":math:`V_0`",
                     default=4.0,
                     required=True,
                     doc="""BOLD parameter. Resting blood volume fraction.""",
                     order=-1)

    E0 = basic.Float(
        label=":math:`E_0`",
        default=0.4,
        required=True,
        doc="""BOLD parameter. Resting oxygen extraction fraction.""",
        order=-1)

    epsilon = arrays.FloatArray(
        label=":math:`\epsilon`",
        default=numpy.array([0.5]),
        range=basic.Range(lo=0.5, hi=2.0, step=0.25),
        required=True,
        doc=
        """ BOLD parameter. Ratio of intra- and extravascular signals. In principle  this
        parameter could be derived from empirical data and spatialized.""",
        order=-1)

    nu_0 = basic.Float(
        label=r":math:`\nu_0`",
        default=40.3,
        required=True,
        doc=
        """BOLD parameter. Frequency offset at the outer surface of magnetized vessels (Hz).""",
        order=-1)

    r_0 = basic.Float(
        label=":math:`r_0`",
        default=25.,
        required=True,
        doc=
        """ BOLD parameter. Slope r0 of intravascular relaxation rate (Hz). Only used for
        ``revised`` coefficients. """,
        order=-1)

    def evaluate(self):
        """
        Calculate simulated BOLD signal
        """
        cls_attr_name = self.__class__.__name__ + ".time_series"
        self.time_series.trait["data"].log_debug(owner=cls_attr_name)

        #NOTE: Just using the first state variable, although in the Bold monitor
        #      input is the sum over the state-variables. Only time-series
        #      from basic monitors should be used as inputs.

        neural_activity, t_int = self.input_transformation(
            self.time_series, self.neural_input_transformation)
        input_shape = neural_activity.shape
        result_shape = self.result_shape(input_shape)
        LOG.debug("Result shape will be: %s" % str(result_shape))

        if self.dt is None:
            self.dt = self.time_series.sample_period / 1000.  # (s) integration time step
            msg = "Integration time step size for the balloon model is %s seconds" % str(
                self.dt)
            LOG.debug(msg)

        #NOTE: Avoid upsampling ...
        if self.dt < (self.time_series.sample_period / 1000.):
            msg = "Integration time step shouldn't be smaller than the sampling period of the input signal."
            LOG.error(msg)

        balloon_nvar = 4

        #NOTE: hard coded initial conditions
        state = numpy.zeros((input_shape[0], balloon_nvar, input_shape[2],
                             input_shape[3]))  # s
        state[0, 1, :] = 1.  # f
        state[0, 2, :] = 1.  # v
        state[0, 3, :] = 1.  # q

        # BOLD model coefficients
        k = self.compute_derived_parameters()
        k1, k2, k3 = k[0], k[1], k[2]

        # prepare integrator
        self.integrator.dt = self.dt
        self.integrator.configure()
        LOG.debug("Integration time step size will be: %s seconds" %
                  str(self.integrator.dt))

        scheme = self.integrator.scheme

        # NOTE: the following variables are not used in this integration but
        # required due to the way integrators scheme has been defined.

        local_coupling = 0.0
        stimulus = 0.0

        # Do some checks:
        if numpy.isnan(neural_activity).any():
            LOG.warning("NaNs detected in the neural activity!!")

        # normalise the time-series.
        neural_activity = neural_activity - neural_activity.mean(
            axis=0)[numpy.newaxis, :]

        # solve equations
        for step in range(1, t_int.shape[0]):
            state[step, :] = scheme(state[step - 1, :], self.balloon_dfun,
                                    neural_activity[step, :], local_coupling,
                                    stimulus)
            if numpy.isnan(state[step, :]).any():
                LOG.warning("NaNs detected...")

        # NOTE: just for the sake of clarity, define the variables used in the BOLD model
        s = state[:, 0, :]
        f = state[:, 1, :]
        v = state[:, 2, :]
        q = state[:, 3, :]

        #import pdb; pdb.set_trace()

        # BOLD models
        if self.bold_model == "nonlinear":
            """
            Non-linear BOLD model equations.
            Page 391. Eq. (13) top in [Stephan2007]_
            """
            y_bold = numpy.array(self.V0 * (k1 * (1. - q) + k2 *
                                            (1. - q / v) + k3 * (1. - v)))
            y_b = y_bold[:, numpy.newaxis, :, :]
            LOG.debug("Max value: %s" % str(y_b.max()))

        else:
            """
            Linear BOLD model equations.
            Page 391. Eq. (13) bottom in [Stephan2007]_ 
            """
            y_bold = numpy.array(self.V0 * ((k1 + k2) * (1. - q) + (k3 - k2) *
                                            (1. - v)))
            y_b = y_bold[:, numpy.newaxis, :, :]

        sample_period = 1. / self.dt

        bold_signal = time_series.TimeSeriesRegion(data=y_b,
                                                   time=t_int,
                                                   sample_period=sample_period,
                                                   sample_period_unit='s',
                                                   use_storage=False)

        return bold_signal

    def compute_derived_parameters(self):
        """
        Compute derived parameters :math:`k_1`, :math:`k_2` and :math:`k_3`.
        """

        if not self.RBM:
            """
            Classical BOLD Model Coefficients [Obata2004]_
            Page 389 in [Stephan2007]_, Eq. (3)
            """
            k1 = 7. * self.E0
            k2 = 2. * self.E0
            k3 = 1. - self.epsilon
        else:
            """
            Revised BOLD Model Coefficients.
            Generalized BOLD signal model.
            Page 400 in [Stephan2007]_, Eq. (12)
            """
            k1 = 4.3 * self.nu_0 * self.E0 * self.TE
            k2 = self.epsilon * self.r_0 * self.E0 * self.TE
            k3 = 1 - self.epsilon

        return numpy.array([k1, k2, k3])

    def input_transformation(self, time_series, mode):
        """
        Perform an operation on the input time-series.
        """

        LOG.debug("Computing: %s on the input time series" % str(mode))

        if mode == "none":
            ts = time_series.data[:, 0, :, :]
            ts = ts[:, numpy.newaxis, :, :]
            t_int = time_series.time / 1000.  # (s)

        elif mode == "abs_diff":
            ts = abs(numpy.diff(time_series.data, axis=0))
            t_int = (time_series.time[1:] -
                     time_series.time[0:-1]) / 1000.  # (s)

        elif mode == "sum":
            ts = numpy.sum(time_series.data, axis=1)
            ts = ts[:, numpy.newaxis, :, :]
            t_int = time_series.time / 1000.  # (s)

        else:
            LOG.error("Bad operation/transformation mode, must be one of:")
            LOG.error("('abs_diff', 'sum', 'none')")
            raise Exception("Bad transformation mode")

        return ts, t_int

    def balloon_dfun(self, state_variables, neural_input, local_coupling=0.0):
        r"""
        The Balloon model equations. See Eqs. (4-10) in [Stephan2007]_
        .. math::
                \frac{ds}{dt} &= x - \kappa\,s - \gamma \,(f-1) \\
                \frac{df}{dt} &= s \\
                \frac{dv}{dt} &= \frac{1}{\tau_o} \, (f - v^{1/\alpha})\\
                \frac{dq}{dt} &= \frac{1}{\tau_o}(f \, \frac{1-(1-E_0)^{1/\alpha}}{E_0} - v^{&/\alpha} \frac{q}{v})\\
                \kappa &= \frac{1}{\tau_s}\\
                \gamma &= \frac{1}{\tau_f}
        """

        s = state_variables[0, :]
        f = state_variables[1, :]
        v = state_variables[2, :]
        q = state_variables[3, :]

        x = neural_input[0, :]

        ds = x - (1. / self.tau_s) * s - (1. / self.tau_f) * (f - 1)
        df = s
        dv = (1. / self.tau_o) * (f - v**(1. / self.alpha))
        dq = (1. / self.tau_o) * ((f * (1. -
                                        (1. - self.E0)**(1. / f)) / self.E0) -
                                  (v**(1. / self.alpha)) * (q / v))

        return numpy.array([ds, df, dv, dq])

    def result_shape(self, input_shape):
        """Returns the shape of the main result of fmri balloon ..."""
        result_shape = (input_shape[0], input_shape[1], input_shape[2],
                        input_shape[3])
        return result_shape

    def result_size(self, input_shape):
        """
        Returns the storage size in Bytes of the main result of .
        """
        result_size = numpy.sum(map(
            numpy.prod, self.result_shape(input_shape))) * 8.0  # Bytes
        return result_size

    def extended_result_size(self, input_shape):
        """
        Returns the storage size in Bytes of the extended result of the ....
        That is, it includes storage of the evaluated ... attributes
        such as ..., etc.
        """
        extend_size = self.result_size(
            input_shape)  # Currently no derived attributes.
        return extend_size
コード例 #12
0
class ReducedWongWangExcInh(ModelNumbaDfun):
    """
    """
    # Define traited attributes for this model, these represent possible kwargs.
    a_e = arrays.FloatArray(
        label=":math:`a_e`",
        default=numpy.array([
            310.0,
        ]),
        range=basic.Range(lo=0.0, hi=500.0, step=1.0),
        doc="[n/C]. Excitatory population input gain parameter.")

    b_e = arrays.FloatArray(
        label=":math:`b_e`",
        default=numpy.array([
            125.0,
        ]),
        range=basic.Range(lo=0.0, hi=200.0, step=1.0),
        doc="[Hz]. Excitatory population input shift parameter.")

    d_e = arrays.FloatArray(
        label=":math:`d_e`",
        default=numpy.array([
            0.160,
        ]),
        range=basic.Range(lo=0.0, hi=0.2, step=0.001),
        doc="""[s]. Excitatory population input scaling parameter.""")

    gamma_e = arrays.FloatArray(
        label=r":math:`\gamma_e`",
        default=numpy.array([
            0.641 / 1000,
        ]),
        range=basic.Range(lo=0.0, hi=1.0 / 1000, step=0.001 / 1000),
        doc=
        """Excitatory population kinetic parameter, the factor 1000 is for expressing everything in ms."""
    )

    tau_e = arrays.FloatArray(
        label=r":math:`\tau_e`",
        default=numpy.array([
            100.0,
        ]),
        range=basic.Range(lo=50.0, hi=150.0, step=1.0),
        doc="""[ms]. Excitatory population NMDA decay time constant.""")

    w_p = arrays.FloatArray(
        label=r":math:`w_p`",
        default=numpy.array([
            1.4,
        ]),
        range=basic.Range(lo=0.0, hi=2.0, step=0.01),
        doc=
        """Excitatory population synaptic weight of the recurrence self-excitation."""
    )

    J_N = arrays.FloatArray(label=r":math:`J_{N}`",
                            default=numpy.array([
                                0.15,
                            ]),
                            range=basic.Range(lo=0.001, hi=0.5, step=0.001),
                            doc="""[nA] Excitatory NMDA synaptic coupling.""")

    W_e = arrays.FloatArray(
        label=r":math:`W_e`",
        default=numpy.array([
            1.0,
        ]),
        range=basic.Range(lo=0.0, hi=2.0, step=0.01),
        doc="""Excitatory population external input scaling weight.""")

    a_i = arrays.FloatArray(
        label=":math:`a_i`",
        default=numpy.array([
            615.0,
        ]),
        range=basic.Range(lo=0.0, hi=1000.0, step=1.0),
        doc="[n/C]. Inhibitory population input gain parameter.")

    b_i = arrays.FloatArray(
        label=":math:`b_i`",
        default=numpy.array([
            177.0,
        ]),
        range=basic.Range(lo=0.0, hi=200.0, step=1.0),
        doc="[Hz]. Inhibitory population input shift parameter.")

    d_i = arrays.FloatArray(
        label=":math:`d_i`",
        default=numpy.array([
            0.087,
        ]),
        range=basic.Range(lo=0.0, hi=0.2, step=0.001),
        doc="""[s]. Inhibitory population input scaling parameter.""")

    gamma_i = arrays.FloatArray(
        label=r":math:`\gamma_i`",
        default=numpy.array([
            1.0 / 1000,
        ]),
        range=basic.Range(lo=0.0, hi=2.0 / 1000, step=0.01 / 1000),
        doc=
        """Inhibitory population kinetic parameter, the factor 1000 is for expressing everything in ms."""
    )

    tau_i = arrays.FloatArray(
        label=r":math:`\tau_i`",
        default=numpy.array([
            10.0,
        ]),
        range=basic.Range(lo=50.0, hi=150.0, step=1.0),
        doc="""[ms]. Inhibitory population GABA decay time constant.""")

    J = arrays.FloatArray(
        label=r":math:`J`",
        default=numpy.array([
            1.0,
        ]),
        range=basic.Range(lo=0.001, hi=2.0, step=0.001),
        doc=
        """[nA] Local feedback inhibitory synaptic coupling. By default, in the no-FIC (feedback inhibitory control) case. Otherwise, it is adjusted independently by the algorithm described as in Deco_2014."""
    )

    W_i = arrays.FloatArray(
        label=r":math:`W_i`",
        default=numpy.array([
            0.7,
        ]),
        range=basic.Range(lo=0.0, hi=1.0, step=0.01),
        doc="""Inhibitory population external input scaling weight.""")

    I_o = arrays.FloatArray(label=":math:`I_{o}`",
                            default=numpy.array([
                                0.382,
                            ]),
                            range=basic.Range(lo=0.0, hi=1.0, step=0.001),
                            doc="""[nA]. Effective external input.""")

    G = arrays.FloatArray(label=":math:`G`",
                          default=numpy.array([
                              1.0,
                          ]),
                          range=basic.Range(lo=0.0, hi=10.0, step=0.01),
                          doc="""Global coupling scaling.""")

    lamda = arrays.FloatArray(
        label=":math:`\lambda`",
        default=numpy.array([
            0.0,
        ]),
        range=basic.Range(lo=0.0, hi=1.0, step=0.01),
        doc=
        """Inhibitory global coupling scaling. By default, in the no-FFI (feedforward inhibition) case. Otherwise, it is set to 1."""
    )

    I_ext = arrays.FloatArray(
        label=":math:`I_{ext}`",
        default=numpy.array([
            0.0,
        ]),
        range=basic.Range(lo=0.0, hi=1.0, step=0.01),
        doc=
        """External stimulation input for simulating task-evoked activity. By default, in resting-state activity. Otherwise, it is set to 0.02."""
    )

    state_variable_range = basic.Dict(
        label="State-variable ranges [lo, hi]",
        default={
            "S_e": numpy.array([0.0, 1.0]),
            "S_i": numpy.array([0.0, 1.0])
        },
        doc="Population mean synaptic gating variables.")

    # Used for phase-plane axis ranges and to bound random initial() conditions.
    #state_variable_boundaries = basic.Enumerate(
    #label="State-variable boundaries [lo, hi]",
    #default={"S_e": numpy.array([0.0, 1.0]), "S_i": numpy.array([0.0, 1.0])},
    #doc="""The values for each state-variable should be set to encompass the boundaries of the dynamic range of that state-variable. Set None for one-sided boundaries.""")

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=['S_e', 'S_i'],
        default=['S_e', 'S_i'],
        select_multiple=True,
        doc="Default state-variables to be monitored.")

    state_variables = ['S_e', 'S_i']
    _nvar = 2
    cvar = numpy.array([0], dtype=numpy.int32)

    def configure(self):
        """  """
        super(ReducedWongWangExcInh, self).configure()
        self.update_derived_parameters()

    def _numpy_dfun(self, state_variables, coupling, local_coupling=0.0):
        """
            Computes the derivatives of the state-variables of the ReducedWongWangExcInh model with respect to time.
        """
        S = state_variables[:, :]

        c_0 = coupling[0, :]
        lc_0 = local_coupling * S[0]  # if applicable

        coupling = self.G * self.J_N * (c_0 + lc_0)

        I_e = self.W_e * self.I_o + self.w_p * self.J_N * S[0] - self.J * S[
            1] + coupling + self.I_ext
        r_e = (self.a_e * I_e -
               self.b_e) / (1 - numpy.exp(-self.d_e *
                                          (self.a_e * I_e - self.b_e)))
        dS_e = -(S[0] / self.tau_e) + (1 - S[0]) * self.gamma_e * r_e

        I_i = self.W_i * self.I_o + self.J_N * S[0] - S[
            1] + self.lamda * coupling
        r_i = (self.a_i * I_i -
               self.b_i) / (1 - numpy.exp(-self.d_i *
                                          (self.a_i * I_i - self.b_i)))
        dS_i = -(S[1] / self.tau_i) + self.gamma_i * r_i

        derivative = numpy.array([dS_e, dS_i])
        return derivative

    def dfun(self, x, c, local_coupling=0.0, **kwargs):
        """The dfun using numba for speed."""
        x_ = x.reshape(x.shape[:-1]).T
        c_ = c.reshape(c.shape[:-1]).T + local_coupling * x[0]
        deriv = _numba_dfun(x_, c_, self.a_e, self.b_e, self.d_e, self.gamma_e,
                            self.tau_e, self.w_p, self.W_e, self.J_N, self.a_i,
                            self.b_i, self.d_i, self.gamma_i, self.tau_i,
                            self.W_i, self.J, self.G, self.lamda, self.I_o,
                            self.I_ext)
        return deriv.T[..., numpy.newaxis]
コード例 #13
0
ファイル: brunel_wang.py プロジェクト: maedoc/tvb-library
class BrunelWang(models.Model):
    """
    .. [DJ_2012] Deco G and Jirsa V. *Ongoing Cortical
        Activity at Rest: Criticality, Multistability, and Ghost Attractors*.
        Journal of Neuroscience 32, 3366-3375, 2012.

    .. [BW_2001] Brunel N and Wang X-J. *Effects of neuromodulation in a cortical
       network model of object working memory dominated by recurrent inhibition*.
       Journal of Computational Neuroscience 11, 63–85, 2001.

    Each node consists of one excitatory (E) and one inhibitory (I) pool.

    At a global level, it uses Hagmann's 2008 connectome 66 areas(hagmann_struct.csv)
    with a global scaling weight (W) of 1.65.


    """

    _ui_name = "Deco-Jirsa (Mean-Field Brunel-Wang)"
    ui_configurable_parameters = ['tau', 'calpha', 'cbeta', 'cgamma', 'tauNMDArise',
                                  'tauNMDAdecay', 'tauAMPA', 'tauGABA',
                                  'VE', 'VI', 'VL', 'Vthr', 'Vreset', 'gNMDA_e',
                                  'gNMDA_i', 'gGABA_e', 'gGABA_i', 'gAMPArec_e',
                                  'gAMPArec_i', 'gAMPAext_e', 'gAMPAext_i',
                                  'gm_e', 'gm_i', 'Cm_e', 'Cm_i', 'taum_e',
                                  'taum_i', 'taurp_e', 'taurp_i', 'Cext', 'C',
                                  'nuext', 'wplus', 'wminus', 'W']

    #Define traited attributes for this model, these represent possible kwargs.
    tau = arrays.FloatArray(
        label = ":math:`\\tau`",
        default = numpy.array([1.25,]),
        range = basic.Range(lo = 0.01, hi = 5.0, step = 0.01),
        doc = """A time-scale separation between the fast, :math:`V`, and slow,
        :math:`W`, state-variables of the model.""",
        order = 1)

    calpha = arrays.FloatArray(
        label = ":math:`c_{\\alpha}`",
        default = numpy.array([0.5,]),
        range = basic.Range(lo = 0.4, hi = 0.5, step = 0.05),
        doc = """NMDA saturation parameter (kHz)""",
        order = 2)

    cbeta = arrays.FloatArray(
        label = ":math:`c_{\\beta}`",
        default = numpy.array([0.062,]),
        range = basic.Range(lo = 0.06, hi = 0.062, step = 0.002),
        doc = """Inverse MG2+ blockade potential(mV-1)""",
        order = 3)

    cgamma = arrays.FloatArray(
        label = ":math:`c_{\\gamma}`",
        default = numpy.array([0.2801120448,]),
        range = basic.Range(lo = 0.2801120440, hi = 0.2801120448, step = 0.0000000001),
        doc = """Strength of Mg2+ blockade""",
        order = -1)

    tauNMDArise = arrays.FloatArray(
        label = ":math:`\\tau_{NMDA_{rise}}`",
        default = numpy.array([2.0,]),
        range = basic.Range(lo = 0.0, hi = 2.0, step = 0.5),
        doc="""NMDA time constant (rise) (ms)""",
        order = 4)

    tauNMDAdecay = arrays.FloatArray(
        label = ":math:`\\tau_{NMDA_{decay}}`",
        default = numpy.array([100.,]),
        range = basic.Range(lo = 50.0, hi = 100.0, step = 10.0),
        doc = """NMDA time constant (decay) (ms)""",
        order = 5)

    tauAMPA = arrays.FloatArray(
        label = ":math:`\\tau_{AMPA}`",
        default = numpy.array([2.0,]),
        range = basic.Range(lo = 1.0, hi = 2.0, step = 1.0),
        doc = """AMPA time constant (decay) (ms)""",
        order = 6)

    tauGABA = arrays.FloatArray(
        label = ":math:`\\tau_{GABA}`",
        default = numpy.array([10.0,]),
        range = basic.Range(lo = 5.0, hi = 15.0, step = 1.0),
        doc = """GABA time constant (decay) (ms)""",
        order = 7)

    VE = arrays.FloatArray(
        label = ":math:`V_E`",
        default = numpy.array([0.0,]),
        range = basic.Range(lo = 0.0, hi = 10.0, step = 2.0),
        doc = """Extracellular potential (mV)""",
        order = 8)

    VI = arrays.FloatArray(
        label = ":math:`V_I`",
        default = numpy.array([-70.0,]),
        range = basic.Range(lo = -70.0, hi = -50.0, step = 5.0),
        doc = """.""",
        order = -1)

    VL = arrays.FloatArray(
        label = ":math:`V_L`",
        default = numpy.array([-70.0,]),
        range = basic.Range(lo = -70.0, hi = -50.0, step = 5.0),
        doc = """Resting potential (mV)""",
        order = -1)

    Vthr = arrays.FloatArray(
        label = ":math:`V_{thr}`",
        default = numpy.array([-50.0,]),
        range = basic.Range(lo = -50.0, hi = -30.0, step = 5.0),
        doc = """Threshold potential (mV)""",
        order = -1)

    Vreset = arrays.FloatArray(
        label = ":math:`V_{reset}`",
        default = numpy.array([-55.0,]),
        range = basic.Range(lo = -70.0, hi = -30.0, step = 5.0),
        doc = """Reset potential (mV)""",
        order = 9)

    gNMDA_e = arrays.FloatArray(
        label = ":math:`g_{NMDA_{e}}`",
        default = numpy.array([0.327,]),
        range = basic.Range(lo = 0.320, hi = 0.350, step = 0.0035),
        doc = """NMDA conductance on post-synaptic excitatory (nS)""",
        order = -1)

    gNMDA_i = arrays.FloatArray(
        label = ":math:`g_{NMDA_{i}}`",
        default = numpy.array([0.258,]),
        range = basic.Range(lo = 0.250, hi = 0.270, step = 0.002),
        doc = """NMDA conductance on post-synaptic inhibitory (nS)""",
        order = -1)

    gGABA_e = arrays.FloatArray(
        label = ":math:`g_{GABA_{e}}`",
        default = numpy.array([1.25 * 3.5, ]),
        range = basic.Range(lo = 1.25, hi = 4.375, step = 0.005),
        doc = """GABA conductance on excitatory post-synaptic (nS)""",
        order = 10)

    gGABA_i = arrays.FloatArray(
        label = ":math:`g_{GABA_{i}}`",
        default = numpy.array([0.973 * 3.5, ]),
        range = basic.Range(lo = 0.9730, hi = 3.4055, step = 0.0005),
        doc = """GABA conductance on inhibitory post-synaptic (nS)""",
        order = 11)

    gAMPArec_e = arrays.FloatArray(
        label = ":math:`g_{AMPA_{rec_e}}`",
        default = numpy.array([0.104,]),
        range = basic.Range(lo = 0.1, hi = 0.11, step = 0.001),
        doc = """AMPA(recurrent) cond on post-synaptic (nS)""",
        order = -1)

    gAMPArec_i = arrays.FloatArray(
        label = ":math:`g_{AMPA_{rec_i}}`",
        default = numpy.array([0.081,]),
        range = basic.Range(lo = 0.081, hi = 0.1, step = 0.001),
        doc = """AMPA(recurrent) cond on post-synaptic (nS)""",
        order = -1)

    gAMPAext_e = arrays.FloatArray(
        label = ":math:`g_{AMPA_{ext_e}}`",
        default = numpy.array([2.08 * 1.2,]),
        range = basic.Range(lo = 2.08, hi = 2.496, step = 0.004),
        doc = """AMPA(external) cond on post-synaptic (nS)""",
        order = 12)

    gAMPAext_i = arrays.FloatArray(
        label = ":math:`g_{AMPA_{ext_i}}`",
        default = numpy.array([1.62 * 1.2,]),
        range = basic.Range(lo = 1.62, hi = 1.944, step = 0.004),
        doc = """AMPA(external) cond on post-synaptic (nS)""",
        order = 13)

    gm_e = arrays.FloatArray(
        label = ":math:`gm_e`",
        default = numpy.array([25.0,]),
        range = basic.Range(lo = 20.0, hi = 25.0, step = 1.0),
        doc = """Excitatory membrane conductance (nS)""",
        order = 13)

    gm_i = arrays.FloatArray(
        label = ":math:`gm_i`",
        default = numpy.array([20.,]),
        range = basic.Range(lo = 15.0, hi = 21.0, step = 1.0),
        doc = """Inhibitory membrane conductance (nS)""",
        order = 14)

    Cm_e = arrays.FloatArray(
        label = ":math:`Cm_e`",
        default = numpy.array([500.,]),
        range = basic.Range(lo = 200.0, hi = 600.0, step = 50.0),
        doc = """Excitatory membrane capacitance (mF)""",
        order = 15)

    Cm_i = arrays.FloatArray(
        label = ":math:`Cm_i`",
        default = numpy.array([200.,]),
        range = basic.Range(lo = 150.0, hi = 250.0, step = 50.0),
        doc = """Inhibitory membrane capacitance (mF)""",
        order = 16)

    taum_e = arrays.FloatArray(
        label = ":math:`\\tau_{m_{e}}`",
        default = numpy.array([20.,]),
        range = basic.Range(lo = 10.0, hi = 25.0, step = 5.0),
        doc = """Excitatory membrane leak time (ms)""",
        order = 17)

    taum_i = arrays.FloatArray(
        label = ":math:`\\tau_{m_{i}}`",
        default = numpy.array([10.0,]),
        range = basic.Range(lo = 5.0, hi = 15.0, step = 5.),
        doc = """Inhibitory Membrane leak time (ms)""",
        order = 18)

    taurp_e = arrays.FloatArray(
        label = ":math:`\\tau_{rp_{e}}`",
        default = numpy.array([2.0,]),
        range = basic.Range(lo = 0.0, hi = 4.0, step = 1.),
        doc = """Excitatory absolute refractory period (ms)""",
        order = 19)

    taurp_i = arrays.FloatArray(
        label = ":math:`\\tau_{rp_{i}}`",
        default = numpy.array([1.0,]),
        range = basic.Range(lo = 0.0, hi = 2.0, step = 0.5),
        doc= """Inhibitory absolute refractory period (ms)""",
        order = 20)

    Cext = arrays.IntegerArray(
        label = ":math:`C_{ext}`",
        default = numpy.array([800,]),
        range = basic.Range(lo = 500, hi = 1200, step = 100),
        doc = """Number of external (excitatory) connections""",
        order = -1)

    C = arrays.IntegerArray(
        label = ":math:`C`",
        default = numpy.array([200,]),
        range = basic.Range(lo = 100, hi = 500, step = 100),
        doc = "Number of neurons for each node",
        order = -1)

    nuext = arrays.FloatArray(
        label = ":math:`\\nu_{ext}`",
        default = numpy.array([0.003,]),
        range = basic.Range(lo = 0.002, hi = 0.01, step = 0.001),
        doc = """External firing rate (kHz)""",
        order = -1)

    wplus = arrays.FloatArray(
        label = ":math:`w_{+}`",
        default = numpy.array([1.5,]),
        range = basic.Range(lo = 0.5, hi = 3., step = 0.05),
        doc = """Synaptic coupling strength [w+] (dimensionless)""",
        order = -1)

    wminus = arrays.FloatArray(
        label = ":math:`w_{-}`",
        default = numpy.array([1.,]),
        range = basic.Range(lo = 0.2, hi = 2., step = 0.05),
        doc = """Synaptic coupling strength [w-] (dimensionless)""",
        order = -1)


    NMAX = arrays.IntegerArray(
        label = ":math:`N_{MAX}`",
        default = numpy.array([8, ], dtype=numpy.int32),
        range = basic.Range(lo = 2, hi = 8, step=1),
        doc = """This is a magic number as given in the original code.
        It is used to compute the phi and psi -- computationally expensive --
        functions""",
        order = -1)

    pool_nodes = arrays.FloatArray(
        label = ":math:`p_{nodes}`",
        default = numpy.array([74.0, ]),
        range = basic.Range(lo = 1.0, hi = 74.0, step = 1.0),
        doc = """Scale coupling weight sby the number of nodes in the network""",
        order = 23)

    a = arrays.FloatArray(
        label = ":math:`a`",
        default = numpy.array([0.80823563, ]),
        range = basic.Range(lo = 0.80, hi = 0.88, step = 0.01),
        doc = """.""",
        order = -1)

    b = arrays.FloatArray(
        label = ":math:`b`",
        default = numpy.array([67.06177975, ]),
        range =  basic.Range(lo = 66.0, hi = 69.0, step = 0.5 ),
        doc = """.""",
        order = -1)

    ve = arrays.FloatArray(
        label = ":math:`ve`",
        default = numpy.array([- 52.5, ]),
        range = basic.Range(lo = -50.0, hi = -45.0, step = 0.2),
        doc = """.""",
        order = -1)

    vi = arrays.FloatArray(
        label = ":math:`vi`",
        default = numpy.array([- 52.5,]),
        range = basic.Range(lo = -50.0, hi = -45.0, step = 0.2 ),
        doc = """.""",
        order = -1)

    W = arrays.FloatArray(
        label = ":math:`W`",
        default = numpy.array([1.65,]),
        range = basic.Range(lo = 1.4, hi = 1.9, step = 0.05),
        doc = """Global scaling weight [W] (dimensionless)""",
        order = -1)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["E", "I"],
        default=["E"],
        select_multiple=True,
        doc="""This represents the default state-variables of this Model to be
                                    monitored. It can be overridden for each Monitor if desired. The
                                    corresponding state-variable indices for this model are :math:`E = 0`
                                    and :math:`I = 1`.""",
        order=21)

        #Informational attribute, used for phase-plane and initial()
    state_variable_range = basic.Dict(
        label = "State Variable ranges [lo, hi]",
        default = {"E": numpy.array([0.001, 0.01]),
                   "I": numpy.array([0.001, 0.01])},
        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 initial
            conditions when the simulation isn't started from an explicit
            history, it is also provides the default range of phase-plane plots.
            The corresponding state-variable units for this model are kHz.""",
        order = 22)


    # psi_table = lookup_tables.PsiTable(required=True,
    #                                    default=lookup_tables.PsiTable(),
    #                                    label="Psi Table",
    #                                    doc="""Psi Table (description).""")
    #
    # nerf_table = lookup_tables.NerfTable(required=True,
    #                                      default=lookup_tables.NerfTable(),
    #                                      label="Nerf Table",
    #                                      doc="""Nerf Table (description).""")


    def __init__(self, **kwargs):
        """
        May need to put kwargs back if we can't get them from trait...

        """

        LOG.info("%s: initing..." % str(self))

        super(BrunelWang, self).__init__(**kwargs)

        #self._state_variables = ["E", "I"]
        self._nvar = 2

        self.cvar = numpy.array([0, 1], dtype=numpy.int32)

        #Derived parameters
        self.crho1_e  = None
        self.crho1_i  = None
        self.crho2_e  = None
        self.crho2_i  = None
        self.csigma_e = None
        self.csigma_i = None
        self.tauNMDA  = None

        self.Text_e   = None
        self.Text_i   = None
        self.TAMPA_e  = None
        self.TAMPA_i  = None
        self.T_ei     = None
        self.T_ii     = None

        self.pool_fractions = None


        #NOTE: We could speed up this model simplifying some the phi and psi functions
        #above. However it was decided that functions should be the same as
        # in the original paper.

        # integral
        #self.vector_nerf = lambda z: numpy.exp(z**2) * (scipy.special.erf(z) + 1)
        #integral = lambda x : numpy.float64(quad(self.vector_nerf, float('-Inf') , x, full_output = True)[0])
        #self.vint = numpy.vectorize(integral)

        LOG.debug('%s: inited.' % repr(self))



    def configure(self):
        """  """
        super(BrunelWang, self).configure()
        self.update_derived_parameters()

        self.psi_table = lookup_tables.PsiTable(load_default=True, use_storage=False)
        self.nerf_table = lookup_tables.NerfTable(load_default=True, use_storage=False)
        # configure look up tables
        self.psi_table.configure()
        self.nerf_table.configure()

        #self.optimize()

    def optimize(self, fnname='optdfun'):
        """
        Optimization routine when we have too many self.parameters
        within dfun
        """

        decl = "def %s(state_variables, coupling, local_coupling=0.0):\n" % (fnname,)

        NoneType = type(None)
        for k in dir(self):
            attr = getattr(self, k)
            if not k[0] == '_' and type(attr) in (numpy.ndarray, NoneType):
                decl += '        %s = %r\n' % (k, attr)

        decl += '\n'.join(inspect.getsource(self.dfun).split('\n')[1:]).replace("self.", "")
        dikt = {'vint': self.vint, 'array': numpy.array, 'int32': numpy.int32, 'numpy': numpy}
        #print decl
        exec decl in dikt
        self.dfun = dikt[fnname]

    def dfun(self, state_variables, coupling, local_coupling=0.0):
        """
        .. math::
             \tau_e*\\dot{\nu_e}(t) &= -\nu_e(t) + \\phi_e \\\\
             \tau_i*\\dot{\nu_i}(t) &= -\nu_i(t) + \\phi_i \\\\
             ve &= - (V_thr - V_reset) \\, \nu_e \\, \tau_e + \\mu_e \\\\
             vi &= - (V_thr - V_reset) \\, \nu_i \\, \tau_i + \\mu_i \\\\

             \tau_X &= \\frac{C_m_X}{g_m_x  \\, S_X} \\\\
             S_X &= 1 + Text \\, \nu_ext + T_ampa \\, \nu_X + (rho_1 + rho_2)
                     \\, \\psi(\nu_X) + T_XI \\, \\nu_I \\\\
             \\mu_X &= \\frac{(Text \\, \\nu_X + T_AMPA \\, \\nu_X + \\rho_1 \\,
                        \\psi(\nu_X)) \\, (V_E - V_L)}{S_X} +
                        \\frac{\\rho_2 \\, \\psi(\nu_X) \\,(\\bar{V_X} - V_L) +
                        T_xI \\, \\nu_I \\, (V_I - V_L)}{S_X} \\\\
            sigma_X^2 &= \\frac{g_AMPA_ext^2(\\bar{V_X} - V_X)^2 \\, C_ext \\, nu_ext
                        \\tau_AMPA^2 \\, \\tau_X}{g_m_X^2 * \\tau_m_X^2} \\\\
            \\rho_1 &= {g_NMDA * C}{g_m_X * J} \\\\
            \\rho_2 &= \\beta \\frac{g_NMDA * C (\\bar{V_X} - V_E)(J - 1)}
                        {g_m_X * J^2} \\\\
            J_X &= 1 + \\gamma \\,\exp(-\\beta*\\bar{V_X}) \\\\
            \\phi(\mu_X, \\sigma_X) &= (\\tau_rp_X + \\tau_X \\, \\int
                                         \exp(u^2) * (\\erf(u) + 1))^-1

        The NMDA gating variable
        .. math::
            \\psi(\\nu)
        has been approximated by the exponential function:
        .. math::
            \\psi(\\nu) &= a * (1 - \exp(-b * \\nu)) \\\\
            a &= 0.80823563 \\\\
            b &= 67.06177975

        The post-synaptic rate as described by the :math:`\\phi` function
        constitutes a non-linear input-output relationship between the firing
        rate of the post-synaptic neuron and the average firing rates
        :math:`\\nu_{E}` and :math:`\\nu_{I}` of the pre-synaptic excitatory and
        inhibitory neural populations. This input-output function is
        conceptually equivalent to the simple threshold-linear or sigmoid
        input-output functions routinely used in firing-rate models. What it is
        gained from using the integral form is a firing-rate model that captures
        many of the underlying biophysics of the real spiking neurons.[BW_2001]_

        """

        E = state_variables[0, :]
        I = state_variables[1, :]
        #A = state_variables[2, :]

        # where and how to add local coupling

        c_0 = coupling[0, :]
        c_2 = coupling[1, :]

        # AMPA synapses (E --> E, and E --> I)
        vn_e = c_0
        vn_i = E * self.wminus * self.pool_fractions

        # NMDA synapses (E --> E, and E --> I)
        vN_e = c_2
        vN_i = E * self.wminus * self.pool_fractions

        # GABA (A) synapses (I --> E, and I --> I)
        vni_e = self.wminus * I  # I --> E
        vni_i = self.wminus * I  # I --> I

        J_e = 1 + self.cgamma * numpy.exp(-self.cbeta * self.ve)
        J_i = 1 + self.cgamma * numpy.exp(-self.cbeta * self.vi)

        rho1_e = self.crho1_e / J_e
        rho1_i = self.crho1_i / J_i
        rho2_e = self.crho2_e * (self.ve - self.VE) * (J_e - 1) / J_e ** 2
        rho2_i = self.crho2_i * (self.vi - self.VI) * (J_i - 1) / J_i ** 2

        vS_e = 1 + self.Text_e * self.nuext + self.TAMPA_e * vn_e + \
               (rho1_e + rho2_e) * vN_e + self.T_ei * vni_e
        vS_i = 1 + self.Text_i * self.nuext + self.TAMPA_i * vn_i + \
               (rho1_i + rho2_i) * vN_i + self.T_ii * vni_i

        vtau_e = self.Cm_e / (self.gm_e * vS_e)
        vtau_i = self.Cm_i / (self.gm_i * vS_i)

        vmu_e = (rho2_e * vN_e * self.ve + self.T_ei * vni_e * self.VI + \
                 self.VL) / vS_e

        vmu_i = (rho2_i * vN_i * self.vi + self.T_ii * vni_i * self.VI + \
                 self.VL) / vS_i

        vsigma_e = numpy.sqrt((self.ve - self.VE) ** 2 * vtau_e * \
                              self.csigma_e * self.nuext)
        vsigma_i = numpy.sqrt((self.vi - self.VE) ** 2 * vtau_i * \
                              self.csigma_i * self.nuext)

        #tauAMPA_over_vtau_e
        k_e = self.tauAMPA / vtau_e
        k_i = self.tauAMPA / vtau_i


        #integration limits
        alpha_e = (self.Vthr - vmu_e) / vsigma_e * (1.0 + 0.5 * k_e) + \
                  1.03 * numpy.sqrt(k_e) - 0.5 * k_e
        alpha_e = numpy.where(alpha_e > 19, 19, alpha_e)
        alpha_i = (self.Vthr - vmu_i) / vsigma_i * (1.0 + 0.5 * k_i) + \
                  1.03 * numpy.sqrt(k_i) - 0.5 * k_i
        alpha_i = numpy.where(alpha_i > 19, 19, alpha_i)

        beta_e = (self.Vreset - vmu_e) / vsigma_e
        beta_e = numpy.where(beta_e > 19, 19, beta_e)

        beta_i = (self.Vreset - vmu_i) / vsigma_i
        beta_i = numpy.where(beta_i > 19, 19, beta_i)

        v_ae = self.nerf_table.search_value(alpha_e)
        v_ai = self.nerf_table.search_value(alpha_i)
        v_be = self.nerf_table.search_value(beta_e)
        v_bi = self.nerf_table.search_value(beta_e)

        v_integral_e = v_ae - v_be
        v_integral_i = v_ai - v_bi

        Phi_e = 1 / (self.taurp_e + vtau_e * numpy.sqrt(numpy.pi) * v_integral_e)
        Phi_i = 1 / (self.taurp_i + vtau_i * numpy.sqrt(numpy.pi) * v_integral_i)

        self.ve = - (self.Vthr - self.Vreset) * E * vtau_e + vmu_e
        self.vi = - (self.Vthr - self.Vreset) * I * vtau_i + vmu_i

        dE = (-E + Phi_e) / vtau_e
        dI = (-I + Phi_i) / vtau_i

        derivative = numpy.array([dE, dI])
        return derivative

    def update_derived_parameters(self):
        """
        Derived parameters

        """

        self.pool_fractions = 1. / (self.pool_nodes * 2)

        self.tauNMDA = self.calpha * self.tauNMDArise * self.tauNMDAdecay
        self.Text_e = (self.gAMPAext_e * self.Cext * self.tauAMPA) / self.gm_e
        self.Text_i = (self.gAMPAext_i * self.Cext * self.tauAMPA) / self.gm_i
        self.TAMPA_e = (self.gAMPArec_e * self.C * self.tauAMPA) / self.gm_e
        self.TAMPA_i = (self.gAMPArec_i * self.C * self.tauAMPA) / self.gm_i
        self.T_ei = (self.gGABA_e * self.C * self.tauGABA) / self.gm_e
        self.T_ii = (self.gGABA_i * self.C * self.tauGABA) / self.gm_i

        self.crho1_e = (self.gNMDA_e * self.C) / self.gm_e
        self.crho1_i = (self.gNMDA_i * self.C) / self.gm_i
        self.crho2_e = self.cbeta * self.crho1_e
        self.crho2_i = self.cbeta * self.crho1_i

        self.csigma_e = (self.gAMPAext_e ** 2 * self.Cext * self.tauAMPA ** 2) / \
                        (self.gm_e * self.taum_e) ** 2
        self.csigma_i = (self.gAMPAext_i ** 2 * self.Cext * self.tauAMPA ** 2) / \
                        (self.gm_i * self.taum_i) ** 2
コード例 #14
0
class LarterBreakspear(models.Model):
    """
    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.
    
    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.

    +---------------------------+
    |          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 |
    +---------------------------+



    +---------------------------+
    |          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   |  # note, this parameter might be spatialized: ones(N,1).*0.65 + modn*(rand(N,1)-0.5);
    | QV_max       |      1.0   |
    | QZ_max       |      1.0   |
    +---------------------------+
    |   Alstott et al. 2009     |
    +---------------------------+


    NOTES about parameters

    d_V
    For d_V < 0.55, uncoupled network, the system exhibits fixed point dynamics; 
    for 55 < lb.d_V < 0.59, limit cycle atractors; 
    and for d_V > 0.59 chaotic attractors (eg, d_V=0.6,aee=0.5,aie=0.5, 
                                               gNa=0, Iext=0.165)

    C
    The long-range coupling 'C' is ‘weak’ in the sense that 
    they investigated 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.
    
    .. automethod:: __init__
    
    """
    
    _ui_name = "Larter-Breakspear"
    ui_configurable_parameters = ['gCa', 'gK', 'gL', 'phi', 'gNa', 'TK', 'TCa',
                                  'TNa', 'VCa', 'VK', 'VL', 'VNa', 'd_K', 'tau_K',
                                  'd_Na', 'd_Ca', 'aei', 'aie', 'b', 'C', 'ane',
                                  'ani', 'aee', 'Iext', 'rNMDA', 'VT', 'd_V', 'ZT',
                                  'd_Z', 'beta', 'QV_max', 'QZ_max']
    
    #Define traited attributes for this model, these represent possible kwargs.
    gCa = arrays.FloatArray(
        label = ":math:`g_{Ca}`",
        default = numpy.array([1.1]),
        range = basic.Range(lo = 0.9, hi = 1.5, step = 0.1),
        doc = """Conductance of population of Ca++ channels.""")
    
    gK = arrays.FloatArray(
        label = ":math:`g_{K}`",
        default = numpy.array([2.0]),
        range = basic.Range(lo = 1.95, hi= 2.05, step = 0.025),
        doc = """Conductance of population of K channels.""")
    
    gL = arrays.FloatArray(
        label = ":math:`g_{L}`",
        default = numpy.array([0.5]),
        range = basic.Range(lo = 0.45 , hi = 0.55, step = 0.05),
        doc = """Conductance of population of leak channels.""")
    
    phi = arrays.FloatArray(
        label = ":math:`\\phi`",
        default = numpy.array([0.7]),
        range = basic.Range(lo = 0.3, hi = 0.9, step = 0.1),
        doc = """Temperature scaling factor.""")
    
    gNa = arrays.FloatArray(
        label = ":math:`g_{Na}`",
        default = numpy.array([6.7]),
        range = basic.Range(lo = 0.0, hi = 10.0, step = 0.1),
        doc = """Conductance of population of Na channels.""")
    
    TK = arrays.FloatArray(
        label = ":math:`T_{K}`",
        default = numpy.array([0.0]),
        range = basic.Range(lo = 0.0, hi = 0.0001, step = 0.00001),
        doc = """Threshold value for K channels.""")
    
    TCa = arrays.FloatArray(
        label = ":math:`T_{Ca}`",
        default = numpy.array([-0.01]),
        range = basic.Range(lo = -0.02, hi=-0.01, step = 0.0025),
        doc = "Threshold value for Ca channels.")
    
    TNa = arrays.FloatArray(
        label = ":math:`T_{Na}`",
        default = numpy.array([0.3]),
        range = basic.Range(lo = 0.25, hi= 0.3, step = 0.025),
        doc = "Threshold value for Na channels.")
    
    VCa = arrays.FloatArray(
        label = ":math:`V_{Ca}`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = 0.9, hi = 1.1, step = 0.05),
        doc = """Ca Nernst potential.""")
    
    VK = arrays.FloatArray(
        label = ":math:`V_{K}`",
        default = numpy.array([-0.7]),
        range = basic.Range(lo = -0.8, hi = 1., step = 0.1),
        doc = """K Nernst potential.""")
    
    VL = arrays.FloatArray(
        label = ":math:`V_{L}`",
        default = numpy.array([-0.5]),
        range = basic.Range(lo = -0.7, hi = -0.4, step = 0.1),
        doc = """Nernst potential leak channels.""")
    
    VNa = arrays.FloatArray(
        label = ":math:`V_{Na}`",
        default = numpy.array([0.53]),
        range = basic.Range(lo = 0.51, hi = 0.55, step = 0.01),
        doc = """Na Nernst potential.""")
    
    d_K = arrays.FloatArray(
        label = ":math:`\\delta_{K}`",
        default = numpy.array([0.3]),
        range = basic.Range(lo = 0.1, hi = 0.4, step = 0.1),
        doc = """Variance of K channel threshold.""")
    
    tau_K = arrays.FloatArray(
        label = ":math:`\\tau_{K}`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = 0.01, hi = 0.0, step = 0.1),
        doc = """Time constant for K relaxation time (ms)""")
    
    d_Na = arrays.FloatArray(
        label = ":math:`\\delta_{Na}`",
        default = numpy.array([0.15]),
        range = basic.Range(lo = 0.1, hi = 0.2, step = 0.05),
        doc = "Variance of Na channel threshold.")
    
    d_Ca = arrays.FloatArray(
        label = ":math:`\\delta_{Ca}`",
        default = numpy.array([0.15]),
        range = basic.Range(lo = 0.1, hi = 0.2, step = 0.05),
        doc = "Variance of Ca channel threshold.")
    
    aei = arrays.FloatArray(
        label = ":math:`a_{ei}`",
        default = numpy.array([2.0]),
        range = basic.Range(lo = 0.1, hi = 2.0, step = 0.1),
        doc = """Excitatory-to-inhibitory synaptic strength.""")
    
    aie = arrays.FloatArray(
        label = ":math:`a_{ie}`",
        default = numpy.array([2.0]),
        range = basic.Range(lo = 0.5, hi = 2.0, step = 0.1),
        doc = """Inhibitory-to-excitatory synaptic strength.""")
    
    b = arrays.FloatArray(
        label = ":math:`b`",
        default = numpy.array([0.1]),
        range = basic.Range(lo = 0.0001, hi = 1.0, step = 0.0001),
        doc = """Time constant scaling factor. The original value is 0.1""")
    
    C = arrays.FloatArray(
        label = ":math:`c`",    
        default = numpy.array([0.0]),
        range = basic.Range(lo = 0.0, hi = 0.2, step = 0.05),
        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.
        This strenght should be set to sensible values when a whole network is connected. """)
    
    ane = arrays.FloatArray(
        label = ":math:`a_{ne}`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = 0.4, hi = 1.0, step = 0.05),
        doc = """Non-specific-to-excitatory synaptic strength.""")
    
    ani = arrays.FloatArray(
        label = ":math:`a_{ni}`",
        default = numpy.array([0.4]),
        range = basic.Range(lo = 0.3, hi = 0.5, step = 0.05),
        doc = """Non-specific-to-inhibitory synaptic strength.""")
    
    aee = arrays.FloatArray(
        label = ":math:`a_{ee}`",
        default = numpy.array([0.4]),
        range = basic.Range(lo = 0.4, hi = 0.6, step = 0.05),
        doc = """Excitatory-to-excitatory synaptic strength.""")
    
    Iext = arrays.FloatArray(
       label = ":math:`I_{ext}`",
       default = numpy.array([0.3]),
       range = basic.Range(lo = 0.165, hi = 0.3, step = 0.005),
       doc = """Subcortical input strength. It represents a non-specific
       excitation or thalamic inputs.""")
    
    rNMDA = arrays.FloatArray(
        label = ":math:`r_{NMDA}`",
        default = numpy.array([0.25]),
        range = basic.Range(lo = 0.2, hi = 0.3, step = 0.05),
        doc = """Ratio of NMDA to AMPA receptors.""")
    
    VT = arrays.FloatArray(
        label = ":math:`V_{T}`",
        default = numpy.array([0.0]),
        range = basic.Range(lo = 0.0, hi = 0.7, step = 0.01),
        doc = """Threshold potential (mean) for excitatory neurons. 
        In [Breaksetal_2003_b]_ this values is 0.""")
    
    d_V = arrays.FloatArray(
        label = ":math:`\\delta_{V}`",
        default = numpy.array([0.65]),
        range = basic.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 = arrays.FloatArray(
        label = ":math:`Z_{T}`",
        default = numpy.array([0.0]),
        range = basic.Range(lo = 0.0, hi = 0.1, step = 0.005),
        doc = """Threshold potential (mean) for inihibtory neurons.""")
    
    d_Z = arrays.FloatArray(
        label = ":math:`\\delta_{Z}`",
        default = numpy.array([0.7]),
        range = basic.Range(lo = 0.001, hi = 0.75, step = 0.05),
        doc = """Variance of the inhibitory threshold.""")
    
    
    # NOTE: the values were not in the article. 
    #I took these ones from DESTEXHE 2001
    QV_max = arrays.FloatArray(
        label = ":math:`Q_{max}`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = 0.1, hi = 1., step = 0.001),
        doc = """Maximal firing rate for excitatory populations (kHz)""")

    QZ_max = arrays.FloatArray(
        label = ":math:`Q_{max}`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = 0.1, hi = 1., step = 0.001),
        doc = """Maximal firing rate for excitatory populations (kHz)""")


    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["V", "W", "Z"],
        default=["V"],
        select_multiple=True,
        doc="""This represents the default state-variables of this Model to be
        monitored. It can be overridden for each Monitor if desired.""",
        order=10)
    
    #Informational attribute, used for phase-plane and initial()
    state_variable_range = basic.Dict(
        label = "State Variable ranges [lo, hi]",
        default = {"V": numpy.array([-1.5, 1.5]),
                   "W": numpy.array([-1.0, 1.0]),
                   "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.""")
    
    
    def __init__(self, **kwargs):
        """
        .. May need to put kwargs back if we can't get them from trait...
        
        """
        
        LOG.info('%s: initing...' % str(self))
        
        super(LarterBreakspear, self).__init__(**kwargs)
        
        self._state_variables = ["V", "W", "Z"]
        
        self._nvar = 3
        self.cvar = numpy.array([0], dtype=numpy.int32)
        
        LOG.debug('%s: inited.' % repr(self))
    
    
    def dfun(self, state_variables, coupling, local_coupling=0.0):
        """
        .. math::
             \\dot{V} &= - (g_{Ca} + (1 - C) \\, r_{NMDA} \\, a_{ee} Q_V^i +
            C \\, r_{NMDA} \\, a_{ee} \\langle Q_V \\rangle) \\, m_{Ca} \\,(V - V_{Ca})
            - g_K\\, W\\, (V - V_K) - g_L\\, (V - V_L)
            - (g_{Na} m_{Na} + (1 - C) \\, a_{ee} Q_V^i + 
            C \\, a_{ee} \\langle Q_V \\rangle) \\, (V - V_{Na})
            - a_{ie}\\, Z \\, Q_Z^i + a_{ne} \\, I_{\\delta}
            
            \\dot{W} &= \\frac{\\phi \\, (m_K - W)}{\\tau_K} \\\\
            \\dot{Z} &= b \\, (a_{ni} \\, I_{\\delta} + a_{ei} \\, V \\, Q_V)\\\\
            
            m_{ion}(X) &= 0.5 \\, (1 + tanh(\\frac{V-T_{ion}}{\\delta_{ion}})
            
        See Equations (7), (3), (6) and (2) respectively in [Breaksetal_2003]_.
        Pag: 705-706

        NOTE: Equation (8) has an error the sign before the term :math:`a_{ie}\\, Z \\, Q_Z^i`
        should be a minus (-) and not a plus (+).
        
        """
        V = state_variables[0, :]
        W = state_variables[1, :]
        Z = state_variables[2, :]

        c_0   = coupling[0, :]    
        lc_0  = local_coupling
        
        # 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))
        
        dV = (- (self.gCa + (1.0 - self.C) * self.rNMDA * self.aee * QV + 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 + self.C * self.aee * c_0) * (V - self.VNa) - self.aei * Z * QZ + self.ane * self.Iext)

        dW = (self.phi * (m_K - W) / self.tau_K)
        
        dZ = (self.b * (self.ani * self.Iext + self.aei * V * QV))
        
        derivative = numpy.array([dV, dW, dZ])
        
        return derivative
コード例 #15
0
class JansenRitDavid(models.Model):
    """
    The Jansen and Rit models as studied by David et al., 2005
    #TODO: finish this model

    """

    _ui_name = "Jansen-Rit (David et al., 2005)"

    #Define traited attributes for this model, these represent possible kwargs.
    He = arrays.FloatArray(
        label=":math:`He`",
        default=numpy.array([3.25]),
        range=basic.Range(lo=2.6, hi=9.75, step=0.05),
        doc=
        """Maximum amplitude of EPSP [mV]. Also called average synaptic gain.""",
        order=1)

    Hi = arrays.FloatArray(
        label=":math:`B`",
        default=numpy.array([29.3]),
        range=basic.Range(lo=17.6, hi=110.0, step=0.2),
        doc=
        """Maximum amplitude of IPSP [mV]. Also called average synaptic gain.""",
        order=2)

    tau_e = arrays.FloatArray(label=":math:`a`",
                              default=numpy.array([0.1]),
                              range=basic.Range(lo=0.05, hi=0.15, step=0.01),
                              doc="""time constant""",
                              order=3)

    tau_i = arrays.FloatArray(label=":math:`b`",
                              default=numpy.array([0.15]),
                              range=basic.Range(lo=0.025, hi=0.075,
                                                step=0.005),
                              doc="""time constant""",
                              order=4)

    eo = arrays.FloatArray(
        label=":math:`v_0`",
        default=numpy.array([0.0025]),
        range=basic.Range(lo=3.12, hi=6.0, step=0.02),
        doc="""Firing threshold (PSP) for which a 50% firing rate is achieved.
        In other words, it is the value of the average membrane potential
        corresponding to the inflection point of the sigmoid [mV].""",
        order=5)

    r = arrays.FloatArray(
        label=":math:`r`",
        default=numpy.array([0.56]),
        range=basic.Range(lo=0.28, hi=0.84, step=0.01),
        doc="""Steepness of the sigmoidal transformation [mV^-1].""",
        order=7)

    gamma_1 = arrays.FloatArray(
        label=r":math:`\alpha_1`",
        default=numpy.array([50.0]),
        range=basic.Range(lo=0.5, hi=1.5, step=0.1),
        doc="""Average probability of synaptic contacts in the feedback
        excitatory loop.""",
        order=9)

    gamma_2 = arrays.FloatArray(
        label=r":math:`\alpha_2`",
        default=numpy.array([40.]),
        range=basic.Range(lo=0.4, hi=1.2, step=0.1),
        doc="""Average probability of synaptic contacts in the feedback
        excitatory loop.""",
        order=10)

    gamma_3 = arrays.FloatArray(
        label=r":math:`\alpha_3`",
        default=numpy.array([12.]),
        range=basic.Range(lo=0.125, hi=0.375, step=0.005),
        doc="""Average probability of synaptic contacts in the feedback
        excitatory loop.""",
        order=11)

    gamma_4 = arrays.FloatArray(
        label=r":math:`\alpha_4`",
        default=numpy.array([12.]),
        range=basic.Range(lo=0.125, hi=0.375, step=0.005),
        doc="""Average probability of synaptic contacts in the slow feedback
        inhibitory loop.""",
        order=12)

    #Used for phase-plane axis ranges and to bound random initial() conditions.
    state_variable_range = basic.Dict(
        label="State Variable ranges [lo, hi]",
        default={
            "x0": numpy.array([-1.0, 1.0]),
            "x1": numpy.array([-1.0, 1.0]),
            "x2": numpy.array([-5.0, 5.0]),
            "x3": numpy.array([-6.0, 6.0]),
            "x4": numpy.array([-2.0, 2.0]),
            "x5": numpy.array([-5.0, 5.0]),
            "x6": numpy.array([-5.0, 5.0]),
            "x7": numpy.array([-5.0, 5.0])
        },
        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.""",
        order=16)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"],
        default=["x0", "x1", "x2", "x3"],
        select_multiple=True,
        doc="""This represents the default state-variables of this Model to be
                                    monitored. It can be overridden for each Monitor if desired. The 
                                    corresponding state-variable indices for this model are :math:`y0 = 0`,
                                    :math:`y1 = 1`, :math:`y2 = 2`, :math:`y3 = 3`, :math:`y4 = 4`, and
                                    :math:`y5 = 5`""",
        order=17)

    def __init__(self, **kwargs):
        """
        Initialise parameters for the Jansen Rit column, [JR_1995]_.

        """
        LOG.info("%s: initing..." % str(self))
        super(JansenRitDavid, self).__init__(**kwargs)

        #self._state_variables = ["y0", "y1", "y2", "y3", "y4", "y5"]
        self._nvar = 8

        self.cvar = numpy.array([1, 2], dtype=numpy.int32)

        LOG.debug('%s: inited.' % repr(self))

    def dfun(self, state_variables, coupling, local_coupling=0.0):
        r"""
        The dynamic equations were taken from:

        TODO: add equations and finish the model ...
            

        """

        magic_exp_number = 709
        AF = 0.1
        AB = 0.2
        AL = 0.05
        x0 = state_variables[0, :]
        x1 = state_variables[1, :]
        x2 = state_variables[2, :]
        x3 = state_variables[3, :]
        x4 = state_variables[4, :]
        x5 = state_variables[5, :]
        x6 = state_variables[6, :]
        x7 = state_variables[7, :]

        y = x1 - x2
        #delayed activity x1 - x2
        c_12 = coupling[0, :] - coupling[1, :]
        c_12_f = AF * ((2 * self.eo) /
                       (1 + numpy.exp(self.r * c_12)) - self.eo)
        c_12_b = AB * ((2 * self.eo) /
                       (1 + numpy.exp(self.r * c_12)) - self.eo)
        c_12_l = AL * ((2 * self.eo) /
                       (1 + numpy.exp(self.r * c_12)) - self.eo)

        lc_f = (local_coupling * y) * AF
        lc_l = (local_coupling * y) * AL
        lc_b = (local_coupling * y) * AB

        S_y = (2 * self.eo) / (1 + numpy.exp(self.r * y)) - self.eo
        S_x0 = (2 * self.eo) / (1 + numpy.exp(self.r * x0)) - self.eo
        S_x6 = (2 * self.eo) / (1 + numpy.exp(self.r * x6)) - self.eo

        # NOTE: for local couplings
        # 0:3 pyramidal cells
        # 1:4 excitatory interneurons
        # 2:5 inhibitory interneurons
        # 3:7

        dx0 = x3
        dx3 = self.He / self.tau_e * (c_12_f + c_12_l + self.gamma_1 * S_y) - (
            2 * x3) / self.tau_e - (x0 / self.tau_e**2)
        dx1 = x4
        dx4 = self.He / self.tau_e * (
            c_12_b + c_12_l + self.gamma_2 * S_x0) - (2 * x4) / self.tau_e - (
                x1 / self.tau_e**2)
        dx2 = x5
        dx5 = self.Hi / self.tau_i * (self.gamma_4 * S_x6) - (
            2 * x5) / self.tau_i - (x2 / self.tau_i**2)
        dx6 = x7
        dx7 = self.He / self.tau_e * (c_12_b + c_12_l + self.gamma_3 * S_y) - (
            2 * x7) / self.tau_e - (x6 / self.tau_e**2)

        derivative = numpy.array([dx0, dx1, dx2, dx3, dx4, dx5, dx6, dx7])

        return derivative
コード例 #16
0
class EpileptorDPrealistic(Model):
    r"""
    The Epileptor is a composite neural mass model of six dimensions which
    has been crafted to model the phenomenology of epileptic seizures.
    (see [Jirsaetal_2014]_).
    ->x0_values parameters are shifted for the bifurcation
      to be at x0_values=1, where x0_values>1 is the supercritical region.
    ->there is a choice for linear or sigmoidal z dynamics (see [Proixetal_2014]_).

    Equations and default parameters are taken from [Jirsaetal_2014]_.

    The realistic Epileptor allows for state variables I_{ext1}, I_{ext2}, x0_values, slope and K
    to fluctuate as linear dynamical equations, driven by the corresponding
    parameter values. It could be combined with multiplicative and/or pink noise.

          +------------------------------------------------------+
          |                         Table 1                      |
          +----------------------+-------------------------------+
          |        Parameter     |           Value               |
          +======================+===============================+
          |         I_ext1      |              3.1              |
          +----------------------+-------------------------------+
          |         I_ext2      |              0.45             |
          +----------------------+-------------------------------+
          |         tau0         |           2857.0              |
          +----------------------+-------------------------------+
          |         x_0          |              0.0              |
          +----------------------+-------------------------------+
          |         slope        |              0.0              |
          +----------------------+-------------------------------+
          |             Integration parameter                    |
          +----------------------+-------------------------------+
          |           dt         |              0.1              |
          +----------------------+-------------------------------+
          |  simulation_length   |              4000             |
          +----------------------+-------------------------------+
          |                    Noise                             |
          +----------------------+-------------------------------+
          |         nsig         | [0., 0., 0., 1e-3, 1e-3, 0.]  |
          +----------------------+-------------------------------+
          |       Jirsa et al. 2014, Proix et al. 2014           |
          +------------------------------------------------------+


    .. figure :: img/Epileptor_01_mode_0_pplane.svg
        :alt: Epileptor phase plane

    .. [Jirsaetal_2014] Jirsa, V. K.; Stacey, W. C.; Quilichini, P. P.;
        Ivanov, A. I.; Bernard, C. *On the nature of seizure dynamics.* Brain,
        2014.

    .. [Proixetal_2014] Proix, T., Bartolomei, F., Chauvel, P., Bernard, C.,
                       & Jirsa, V. K. (2014).
                       Permitau1ivity Coupling across Brain Regions Determines
                       Seizure Recruitment in Partial Epilepsy.
                       Journal of Neuroscience, 34(45), 15009–15021.
                       htau1p://doi.org/10.1523/JNEUROSCI.1570-14.2014

    .. automethod:: EpileptorDP.__init__

    Variables of interest to be used by monitors: -y[0] + y[3]

        .. math::
            \dot{x_{1}} &=& y_{1} - f_{1}(x_{1}, x_{2}) - z + I_{ext1} \\
            \dot{y_{1}} &=& yc - d x_{1}^{2} - y{1} \\
            \dot{z} &=&
            \begin{cases}
            (f_z(x_{1}) - z-0.1 z^{7})/tau0 & \text{if } x<0 \\
            (f_z(x_{1}) - z)/tau0           & \text{if } x \geq 0
            \end{cases} \\
            \dot{x_{2}} &=& -y_{2} + x_{2} - x_{2}^{3} + I_{ext2} + 0.002 g - 0.3 (z-3.5) \\
            \dot{y_{2}} &=& 1 / \tau2 (-y_{2} + f_{2}(x_{2}))\\
            \dot{g} &=& -0.01 (g - 0.1 x_{1} )

    where:
        .. math::
            f_{1}(x_{1}, x_{2}) =
            \begin{cases}
            a x_{1}^{3} - b x_{1}^2 & \text{if } x_{1} <0\\
            (x_{2} - 0.6(z-4)^2 -slope) x_{1} &\text{if }x_{1} \geq 0
            \end{cases}

        .. math::
            f_z(x_{1})  =
            \begin{cases}
            4 * (x_{1} - x0_values) & \text{linear} \\
            \frac{3}{1+e^{-10*(x_{1}+0.5)}} - x0_values & \text{sigmoidal} \\
            \end{cases}
    and:

        .. math::
            f_{2}(x_{2}) =
            \begin{cases}
            0 & \text{if } x_{2} <-0.25\\
            s*(x_{2} + 0.25) & \text{if } x_{2} \geq -0.25
            \end{cases}
    """

    _ui_name = "EpileptorDPrealistic"
    ui_configurable_parameters = [
        "Iext1", "Iext2", "tau0", "x0_values", "slope"
    ]

    pmode = arrays.FloatArray(
        label="pmode",
        default=numpy.array([PMODE_DEF]),
        doc=
        "pmode = numpy.array([0]), numpy.array([1]), numpy.array([2]), numpy.array([3) or  "
        +
        "parameters staying constant or following the z,g, z*g dynamics, respectively",
        order=-1)

    zmode = arrays.FloatArray(
        label="zmode",
        default=numpy.array([ZMODE_DEF]),
        doc=
        "zmode = numpy.array([0]) for linear and numpy.array([1]) for sigmoidal z dynamics",
        order=-1)

    a = arrays.FloatArray(
        label="a",
        default=numpy.array([A_DEF]),
        doc="Coefficient of the cubic term in the first state variable",
        order=-1)

    b = arrays.FloatArray(
        label="b",
        default=numpy.array([B_DEF]),
        doc="Coefficient of the squared term in the first state variabel",
        order=-1)

    yc = arrays.FloatArray(
        label="yc",
        default=numpy.array([YC_DEF]),
        doc="Additive coefficient for the second state variable",
        order=-1)

    d = arrays.FloatArray(
        label="d",
        default=numpy.array([D_DEF]),
        doc="Coefficient of the squared term in the second state variable",
        order=-1)

    s = arrays.FloatArray(label="s",
                          default=numpy.array([S_DEF]),
                          doc="Linear coefficient in the third state variable",
                          order=-1)

    x0 = arrays.FloatArray(label="x0",
                           range=basic.Range(lo=-4.0, hi=1, step=0.1),
                           default=numpy.array([X0_DEF]),
                           doc="Excitability parameter",
                           order=3)

    Iext1 = arrays.FloatArray(
        label="Iext1",
        range=basic.Range(lo=1.5, hi=5.0, step=0.1),
        default=numpy.array([I_EXT1_DEF]),
        doc="External input current to the first population",
        order=1)

    slope = arrays.FloatArray(
        label="slope",
        range=basic.Range(lo=-16.0, hi=6.0, step=0.1),
        default=numpy.array([SLOPE_DEF]),
        doc="Linear coefficient in the first state variable",
        order=5)

    gamma = arrays.FloatArray(
        label="gamma",
        range=basic.Range(lo=0.01, hi=0.2, step=0.01),
        default=numpy.array([GAMMA_DEF]),
        doc="Linear coefficient in the sixth state variable",
        order=5)

    Iext2 = arrays.FloatArray(
        label="Iext2",
        range=basic.Range(lo=0.0, hi=1.0, step=0.05),
        default=numpy.array([I_EXT2_DEF]),
        doc="External input current to the second population",
        order=2)

    Kvf = arrays.FloatArray(label="K_vf",
                            default=numpy.array([0.0]),
                            range=basic.Range(lo=0.0, hi=4.0, step=0.5),
                            doc="Coupling scaling on a very fast time scale.",
                            order=6)

    Kf = arrays.FloatArray(
        label="K_f",
        default=numpy.array([0.0]),
        range=basic.Range(lo=0.0, hi=4.0, step=0.5),
        doc="Correspond to the coupling scaling on a fast time scale.",
        order=7)

    K = arrays.FloatArray(
        label="K",
        default=numpy.array([-K_DEF]),
        range=basic.Range(lo=-4.0, hi=4.0, step=0.1),
        doc=
        "Permitau1ivity coupling, that is from the fast time scale toward the slow time scale",
        order=8)

    tau1 = arrays.FloatArray(label="tau1",
                             default=numpy.array([TAU1_DEF]),
                             range=basic.Range(lo=0.1, hi=2.0, step=0.1),
                             doc="Time scaling of the whole system",
                             order=9)

    tau0 = arrays.FloatArray(
        label="r",
        range=basic.Range(lo=3.0, hi=30000, step=100),
        default=numpy.array([TAU0_DEF]),
        doc="Temporal scaling in the third state variable",
        order=4)

    tau2 = arrays.FloatArray(
        label="tau2",
        default=numpy.array([TAU2_DEF]),
        doc="Temporal scaling coefficient in fifth state variable",
        order=-1)

    state_variable_range = basic.Dict(
        label="State variable ranges [lo, hi]",
        default={
            "x1": numpy.array([-2., 1.]),
            "y1": numpy.array([-20., 2.]),
            "z": numpy.array([2.0, 5.0]),
            "x2": numpy.array([-2., 0.]),
            "y2": numpy.array([0., 2.]),
            "g": numpy.array([-1., 1.]),
            "x0_t": numpy.array([-2., 2.]),
            "slope_t": numpy.array([-20., 6.]),
            "Iext1_t": numpy.array([1.5, 5.]),
            "Iext2_t": numpy.array([0., 1.]),
            "K_t": numpy.array([-50., 50.])
        },
        doc="Typical bounds on state variables in the Epileptor model.",
        order=16)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=[
            'x1', 'y1', 'z', 'x2', 'y2', 'g', 'x0_t', 'slope_t', 'Iext1_t',
            'Iext2_t', 'K_t'
        ],
        default=[
            'x1', 'y1', 'z', 'x2', 'y2', 'g', 'x0_t', 'slope_t', 'Iext1_t',
            'Iext2_t', 'K_t'
        ],
        select_multiple=True,
        doc="Quantities of the Epileptor available to monitor.",
        order=-1)

    state_variables = [
        'x1', 'y1', 'z', 'x2', 'y2', 'g', 'x0_t', 'slope_t', 'Iext1_t',
        'Iext2_t', 'K_t'
    ]

    _nvar = 11
    cvar = numpy.array([0, 3], dtype=numpy.int32)

    @staticmethod
    def fun_slope_Iext2(z, g, pmode, slope, Iext2):

        from tvb_fit.base.computations.analyzers_utils import interval_scaling

        iz = numpy.ones(z.shape)
        pmode = numpy.array(pmode) * iz
        slope = numpy.array(slope) * iz
        Iext2 = numpy.array(Iext2) * iz
        slope_eq = numpy.array(slope) * iz
        Iext2_eq = numpy.array(Iext2) * iz

        for iv in range(z.size):

            if pmode[iv] > 0:

                if pmode[iv] == 1:
                    xp = 1.0 / (1.0 + numpy.exp(1)**(-10 * (z[iv] - 3.00)))
                    xp1 = 0
                    xp2 = 1

                elif pmode[iv] == 2:
                    xp = 1.0 / (1.0 + numpy.exp(1)**(-10 * (g[iv] + 0.0)))
                    xp1 = 0  # -0.175
                    xp2 = 1  # 0.025

                elif pmode[iv] == 3:
                    xp = z[iv] * g[iv]
                    xp1 = -0.7
                    xp2 = 0.1
                #                           targ min,max  orig      min,max
                slope_eq[iv] = interval_scaling(xp, 1.0, slope[iv], xp1, xp2)
                # slope_eq = slope * numpy.ones(z.shape)
                Iext2_eq[iv] = interval_scaling(xp, 0.0, Iext2[iv], xp1, xp2)

        return slope_eq, Iext2_eq

    def dfun(self,
             state_variables,
             coupling,
             local_coupling=0.0,
             array=numpy.array,
             where=numpy.where,
             concat=numpy.concatenate):
        r"""
        Computes the derivatives of the state variables of the Epileptor
        with respect to time.

        Implementation note: we expect this version of the Epileptor to be used
        in a vectorized manner. Concretely, y has a shape of (6, n) where n is
        the number of nodes in the network. An consequence is that
        the original use of if/else is translated by calculated both the true
        and false forms and mixing them using a boolean mask.

        Variables of interest to be used by monitors: -y[0] + y[3]

            .. math::
            \dot{y_{0}} &=& y_{1} - f_{1}(y_{0}, y_{3}) - y_{2} + I_{ext1} \\
            \dot{y_{1}} &=& yc - d (y_{0} -5/3)^{2} - y{1} \\
            \dot{y_{2}} &=&
            \begin{cases}
            (f_z(y_{0}) - y_{2}-0.1 y_{2}^{7})/tau0 & \text{if } y_{0}<5/3 \\
            (f_z(y_{0}) - y_{2})/tau0           & \text{if } y_{0} \geq 5/3
            \end{cases} \\
            \dot{y_{3}} &=& -y_{4} + y_{3} - y_{3}^{3} + I_{ext2} + 0.002 y_{5} - 0.3 (y_{2}-3.5) \\
            \dot{y_{4}} &=& 1 / \tau2 (-y_{4} + f_{2}(y_{3}))\\
            \dot{y_{5}} &=& -0.01 (y_{5} - 0.1 ( y_{0} -5/3 ) )

        where:
            .. math::
                f_{1}(y_{0}, y_{3}) =
                \begin{cases}
                a ( y_{0} -5/3 )^{3} - b ( y_{0} -5/3 )^2 & \text{if } y_{0} <5/3\\
                ( y_{3} - 0.6(y_{2}-4)^2 -slope ) ( y_{0} - 5/3 ) &\text{if }y_{0} \geq 5/3
                \end{cases}

            .. math::
                f_z(y_{0})  =
                \begin{cases}
                4 * (y_{0} - x0_values) & \text{linear} \\
                \frac{3}{1+e^{-10*(y_{0}-7/6)}} - x0_values & \text{sigmoidal} \\
                \end{cases}
        and:

            .. math::
                f_{2}(y_{3}) =
                \begin{cases}
                0 & \text{if } y_{3} <-0.25\\
                s*(y_{3} + 0.25) & \text{if } y_{3} \geq -0.25
                \end{cases}

        """

        y = state_variables
        ydot = numpy.empty_like(state_variables)

        # To use later:
        x0 = y[6]
        slope = y[7]
        Iext1 = y[8]
        Iext2 = y[9]
        K = y[10]

        Iext1_local_coupling = Iext1 + local_coupling * y[0]
        c_pop1 = coupling[0, :]
        c_pop2 = coupling[1, :]

        # population 1
        if_ydot0 = -self.a * y[0]**2 + self.b * y[0]  # self.a=1.0, self.b=3.0
        else_ydot0 = slope - y[3] + 0.6 * (y[2] - 4.0)**2
        ydot[0] = self.tau1 * (y[1] - y[2] + Iext1_local_coupling +
                               self.Kvf * c_pop1 +
                               where(y[0] < 0.0, if_ydot0, else_ydot0) * y[0])
        ydot[1] = self.tau1 * (self.yc - self.d * y[0]**2 - y[1])  # self.d=5

        # energy
        if_ydot2 = -0.1 * y[2]**7
        else_ydot2 = 0

        fz = where(self.zmode, 3.0 / (1.0 + numpy.exp(-10 * (y[0] + 0.5))) - x0, 4 * (y[0] - x0)) + \
             where(y[2] < 0., if_ydot2, else_ydot2)

        ydot[2] = self.tau1 * ((fz - y[2] + K * c_pop1) / self.tau0)

        # population 2
        ydot[3] = self.tau1 * (-y[4] + y[3] - y[3]**3 + Iext2 + 2 * y[5] -
                               0.3 * (y[2] - 3.5) + self.Kf * c_pop2)
        if_ydot4 = 0
        else_ydot4 = self.s * (y[3] + 0.25)  # self.s = 6.0
        ydot[4] = self.tau1 * (
            (-y[4] + where(y[3] < -0.25, if_ydot4, else_ydot4)) / self.tau2)

        # filter
        ydot[5] = self.tau1 * (-0.01 * (y[5] - self.gamma * y[0]))

        feedback = numpy.any(self.pmode > 0)
        slope_eq, Iext2_eq = self.fun_slope_Iext2(y[2], y[5], self.pmode,
                                                  self.slope, self.Iext2)
        tau0_feedback = numpy.where(feedback, 1.0, self.tau0 / 100)

        # x0_values
        ydot[6] = 1000 * self.tau1 * (-y[6] + self.x0) / self.tau0
        # slope
        ydot[7] = 10 * self.tau1 * (-y[7] + slope_eq) / tau0_feedback  #
        # Iext1
        ydot[8] = 1000 * self.tau1 * (-y[8] + self.Iext1) / self.tau0
        # Iext2
        ydot[9] = 10 * self.tau1 * (-y[9] + Iext2_eq) / tau0_feedback  #
        # K
        ydot[10] = 1000 * self.tau1 * (-y[10] + self.K) / self.tau0

        return ydot

    def jacobian(self,
                 state_variables,
                 coupling,
                 local_coupling=0.0,
                 array=numpy.array,
                 where=numpy.where,
                 concat=numpy.concatenate):
        raise_not_implemented_error("Jacobian calculation of model " +
                                    self._ui_name + " is not implemented yet!")
コード例 #17
0
class Generic2dOscillator(models.Model):
    """
    The Generic2dOscillator model is a generic dynamic system with two
    state variables. The dynamic equations of this model are composed
    of two ordinary differential equations comprising two nullclines.
    The first nullcline is a cubic function as it is found in most
    neuron and population models; the  second nullcline is arbitrarily
    configurable as a polynomial function up to second order. The
    manipulation of the latter nullcline's parameters allows to
    generate a wide range of different behaviors.  
    See:
        
        .. [FH_1961] FitzHugh, R., *Impulses and physiological states in 
            theoretical models of nerve membrane*, Biophysical Journal 1: 445, 1961. 
    
        .. [Nagumo_1962] Nagumo et.al, *An Active Pulse Transmission Line 
            Simulating Nerve Axon*, Proceedings of the IRE 50: 2061, 1962.
        
        .. [SJ_2011] Stefanescu, R., Jirsa, V.K. *Reduced representations of 
            heterogeneous mixed neural networks with synaptic coupling*.  
            Physical Review E, 83, 2011. 

        .. [SJ_2010]    Jirsa VK, Stefanescu R.  *Neural population modes 
            capture biologically realistic large-scale network dynamics*. 
            Bulletin of Mathematical Biology, 2010.    

        .. [SJ_2008_a] Stefanescu, R., Jirsa, V.K. *A low dimensional 
            description of globally coupled heterogeneous neural 
            networks of excitatory and inhibitory neurons*. PLoS 
            Computational Biology, 4(11), 2008).

    The model's (:math:`V`, :math:`W`) time series and phase-plane 
    its nullclines can be seen in the figure below. 

    The model with its default parameters exhibits FitzHugh-Nagumo like dynamics.

     ---------------------------
    |  EXCITABLE CONFIGURATION  |
     ---------------------------
    |Parameter     |  Value     |
    -----------------------------
    | a            |     -2.0   |
    | b            |    -10.0   |
    | c            |      0.0   |
    | d            |      0.1   |
    | I            |      0.0   |
    -----------------------------
    |* limit cylce if a = 2.0   |
    -----------------------------
    
     ---------------------------
    |   BISTABLE CONFIGURATION  |
     ---------------------------
    |Parameter     |  Value     |
    -----------------------------
    | a            |      1.0   |
    | b            |      0.0   |
    | c            |     -5.0   |
    | d            |      0.1   |
    | I            |      0.0   |
    -----------------------------
    |* monostable regime:       |
    |* fixed point if Iext=-2.0 |
    |* limit cycle if Iext=-1.0 |
    -----------------------------
    
     ---------------------------
    |  EXCITABLE CONFIGURATION  | (similar to Morris-Lecar)
     ---------------------------
    |Parameter     |  Value     |
    -----------------------------
    | a            |      0.5   |
    | b            |      0.6   |
    | c            |     -4.0   |
    | d            |      0.1   |
    | I            |      0.0   |
    -----------------------------
    |* excitable regime if b=0.6|
    |* oscillatory if b=0.4     |
    -----------------------------
    
    
     ---------------------------
    |  SanzLeonetAl  2013       | 
     ---------------------------
    |Parameter     |  Value     |
    -----------------------------
    | a            |    - 0.5   |
    | b            |    -15.0   |
    | c            |      0.0   |
    | d            |      0.02  |
    | I            |      0.0   |
    -----------------------------
    |* excitable regime if      |
    |* intrinsic frequency is   |
    |  approx 10 Hz             |
    -----------------------------

    .. figure :: img/Generic2dOscillator_01_mode_0_pplane.svg
    .. _phase-plane-Generic2D:
        :alt: Phase plane of the generic 2D population model with (V, W)

        The (:math:`V`, :math:`W`) phase-plane for the generic 2D population 
        model for default parameters. The dynamical system has an equilibrium 
        point.
    """

    _ui_name = "Generic 2d Oscillator"
    ui_configurable_parameters = ['tau', 'a', 'b', 'c', 'd', 'I']

    #Define traited attributes for this model, these represent possible kwargs.
    tau = arrays.FloatArray(
        label = r":math:`\tau`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = 0.00001, hi = 5.0, step = 0.01),
        doc = """A time-scale hierarchy can be introduced for the state 
        variables :math:`V` and :math:`W`. Default parameter is 1, which means
        no time-scale hierarchy.""",
        order = 1)

    I = arrays.FloatArray(
        label = ":math:`I_{ext}`",
        default = numpy.array([0.0]),
        range = basic.Range(lo = -2.0, hi = 2.0, step = 0.01),
        doc = """Baseline shift of the cubic nullcline""",
        order = 2)

    a = arrays.FloatArray(
        label = ":math:`a`",
        default = numpy.array([-2.0]),
        range = basic.Range(lo = -5.0, hi = 5.0, step = 0.01),
        doc = """Vertical shift of the configurable nullcline""",
        order = 3)

    b = arrays.FloatArray(
        label = ":math:`b`",
        default = numpy.array([-10.0]),
        range = basic.Range(lo = -20.0, hi = 15.0, step = 0.01),
        doc = """Linear slope of the configurable nullcline""",
        order = 4)

    c = arrays.FloatArray(
        label = ":math:`c`",
        default = numpy.array([0.0]),
        range = basic.Range(lo = -10.0, hi = 10.0, step = 0.01),
        doc = """Parabolic term of the configurable nullcline""",
        order = 5)
        
    d = arrays.FloatArray(
        label = ":math:`d`",
        default = numpy.array([0.1]),
        range = basic.Range(lo = 0.0001, hi = 1.0, step = 0.0001),
        doc = """Temporal scale factor.""",
        order = -1)
        
    e = arrays.FloatArray(
        label = ":math:`e`",
        default = numpy.array([3.0]),
        range = basic.Range(lo = -5.0, hi = 5.0, step = 0.0001),
        doc = """Coefficient of the quadratic term of the cubic nullcline.""",
        order = -1)
        
    f = arrays.FloatArray(
        label = ":math:`f`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = -5.0, hi = 5.0, step = 0.0001),
        doc = """Coefficient of the cubic term of the cubic nullcline.""",
        order = -1)
        
    alpha = arrays.FloatArray(
        label = ":math:`\alpha`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = -5.0, hi = 5.0, step = 0.0001),
        doc = """Constant parameter to scale the rate of feedback from the 
            slow variable to the fast variable.""",
        order = -1)
        
    beta = arrays.FloatArray(
        label = ":math:`\beta`",
        default = numpy.array([1.0]),
        range = basic.Range(lo = -5.0, hi = 5.0, step = 0.0001),
        doc = """Constant parameter to scale the rate of feedback from the 
            slow variable to itself""",
        order = -1)

    #Informational attribute, used for phase-plane and initial()
    state_variable_range = basic.Dict(
        label = "State Variable ranges [lo, hi]",
        default = {"V": numpy.array([-2.0, 4.0]),
                   "W": numpy.array([-6.0, 6.0])},
        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 initial 
            conditions when the simulation isn't started from an explicit
            history, it is also provides the default range of phase-plane plots.""",
        order = 6)

    
    variables_of_interest = basic.Enumerate(
        label = "Variables watched by Monitors",
        options = ["V", "W"],
        default = ["V",],
        select_multiple = True,
        doc = """This represents the default state-variables of this 
            Model to be monitored. It can be overridden for each 
            Monitor if desired. The corresponding state-variable 
            indices for this model are :math:`V = 0`and :math:`W = 1`.""",
        order = 7)
    

    def __init__(self, **kwargs):
        """
        Intialise Model
        """

        LOG.info("%s: initing..." % str(self))

        super(Generic2dOscillator, self).__init__(**kwargs)

        self._nvar = 2 
        # long range coupling variables
        self.cvar = numpy.array([0], dtype=numpy.int32)

        LOG.debug("%s: inited." % repr(self))


    def dfun(self, state_variables, coupling, local_coupling=0.0,
             ev=numexpr.evaluate):
        r"""
        The two state variables :math:`V` and :math:`W` are typically considered 
        to represent a function of the neuron's membrane potential, such as the 
        firing rate or dendritic currents, and a recovery variable, respectively. 
        If there is a time scale hierarchy, then typically :math:`V` is faster 
        than :math:`W` corresponding to a value of :math:`\tau` greater than 1.

        The equations of the generic 2D population model read

        .. math::
            \dot{V} &= \tau (\alpha W - V^3 +3 V^2 + I) \\
            \dot{W} &= (a\, + b\, V + c\, V^2 - \, beta W) / \tau

        where external currents :math:`I` provide the entry point for local, 
        long-range connectivity and stimulation.

        """

        V = state_variables[0, :]
        W = state_variables[1, :]

        #[State_variables, nodes]
        c_0 = coupling[0, :]
        
        tau = self.tau
        I = self.I
        a = self.a
        b = self.b
        c = self.c
        d = self.d
        e = self.e
        f = self.f
        beta  = self.beta
        alpha = self.alpha

        lc_0 = local_coupling*V
        
        ## numexpr       
        dV = ev('d * tau * (alpha * W - f * V**3 + e * V**2 + I + c_0 + lc_0)')
        dW = ev('d * (a + b * V + c * V**2 - beta * W) / tau')

        self.derivative = numpy.array([dV, dW])
        
        return self.derivative
コード例 #18
0
class LileySteynRoss(models.Model):
    """
    Liley lumped model as presented in Steyn-Ross et al 1999.

    This  model is to be use for modelling cortical dynamics in which "inputs"
    to neuronal assemblies are treated as random Gaussian fluctuations about a
    mean value. Anesthetic agent effects are modelled as as a modulation of the
    inhibitory neurotransmitter rate constant.

    The main state variable is h_e, the average excitatory soma potential,
    coherent fluctuations of which are believed to be the source of scalp-measured
    electroencephalogram ͑EEG͒ signals.

    Parameters are taken from Table 1 [Steyn-Ross_1999]_


    State variables:

    h_e: exc population mean soma potential [mV]
    h_i: exc population mean soma potential [mV]

    I_ee: total 'exc' current input to 'exc' synapses [mV]
    I_ie: total 'inh' current input to 'exc' synapses [mV]
    I_ei: total 'exc' current input to 'inh' synapses [mV]
    I_ii: total 'inh' current input to 'inh' synapses [mV]

    :math:`\Psi_{jk}`:  weighting factors for the I_jk inputs [dimensionless]

    :math:`phi_e`: long-range (cortico-cortical) spike input to exc population
    :math:`phi_i`: long-range (cortico-cortical) spike input to inh population [ms-1]

    EPSP: exc post-synaptic potential [mV]
    IPSP: inh post-synaptic potential [mV]

    Mean axonal conduction speed: 7 mm/ms

    S_e(h_e): sigmoid function mapping soma potential to firing rate [ms]-1
    S_i(h_i): sigmoid function mapping soma potential to firing rate [ms]-1



    The models (:math:`h_e`, :math:h_i`) phase-plane, including a representation of
    the vector field as well as its nullclines, using default parameters, can be
    seen below:

        .. _phase-plane-LSR:
        .. figure :: img/LileySteynRoss_01_mode_0_pplane.svg
            :alt: LileySteynRoss phase plane (E, I)

            The (:math:`h_e`, :math:`hi`) phase-plane for the LileySteynRoss model.


    References
    ----------

    .. [Steyn-Ross et al 1999] Theoretical electroencephalogram stationary spectrum for a 
       white-noise-driven cortex: Evidence for a general anesthetic-induced phase transition.

    .. [Liley et al 2013] The mesoscopic modelin of burst supression during anesthesia.


    """

    _ui_name = "Liley-SteynRoss model"
    #ui_configurable_parameters = []

    #Define traited attributes for this model, these represent possible kwargs.

    tau_e = arrays.FloatArray(
        label=r":math:`\tau_e`",
        default=numpy.array([40.0]),
        range=basic.Range(lo=5.0, hi=50.0, step=1.00),
        doc="""Excitatory population, membrane time-constant [ms]""",
        order=1)

    tau_i = arrays.FloatArray(
        label=r":math:`\tau_i`",
        default=numpy.array([40.0]),
        range=basic.Range(lo=5.0, hi=50.0, step=1.0),
        doc="""Inhibitory population, membrane time-constant [ms]""",
        order=2)

    h_e_rest = arrays.FloatArray(
        label=r":math:`h_e^{rest}`",
        default=numpy.array([-70.0]),
        range=basic.Range(lo=-90.0, hi=-50.0, step=10.00),
        doc="""Excitatory population, cell resting potential [mV]""",
        order=3)

    h_i_rest = arrays.FloatArray(
        label=r":math:`h_i^{rest}`",
        default=numpy.array([-70.0]),
        range=basic.Range(lo=-90.0, hi=-50.0, step=10.0),
        doc="""Inhibitory population, cell resting potential [mV]""",
        order=4)

    h_e_rev = arrays.FloatArray(
        label=r":math:`h_e^{rev}`",
        default=numpy.array([45.0]),
        range=basic.Range(lo=0.0, hi=50.0, step=5.00),
        doc="""Excitatory population, cell reversal potential [mV]""",
        order=42)

    h_i_rev = arrays.FloatArray(
        label=r":math:`h_i^{rev}`",
        default=numpy.array([-90.0]),
        range=basic.Range(lo=-90.0, hi=-50.0, step=10.0),
        doc="""Inhibitory population, cell reversal potential [mV]""",
        order=43)

    p_ee = arrays.FloatArray(
        label=":math:`p_{ee}`",
        default=numpy.array([1.1]),
        range=basic.Range(lo=1.0, hi=1.8, step=0.1),
        doc=
        """Exogenous (subcortical) spike input to exc population [ms]-1 [kHz]. 
               This could be replaced by a noise term""",
        order=5)

    p_ie = arrays.FloatArray(
        label=":math:`p_{ie}`",
        default=numpy.array([1.6]),
        range=basic.Range(lo=1.0, hi=1.8, step=0.1),
        doc=
        """Exogenous (subcortical) spike input to exc population [ms]-1 [kHz]. 
               This could be replaced by a noise term""",
        order=6)

    p_ei = arrays.FloatArray(
        label=":math:`p_{ei}`",
        default=numpy.array([1.6]),
        range=basic.Range(lo=1.0, hi=1.8, step=0.1),
        doc=
        """Exogenous (subcortical) spike input to inh population [ms]-1 [kHz]. 
               This could be replaced by a noise term""",
        order=7)

    p_ii = arrays.FloatArray(
        label=":math:`p_{ii}`",
        default=numpy.array([1.1]),
        range=basic.Range(lo=1.0, hi=1.8, step=0.1),
        doc=
        """Exogenous (subcortical) spike input to inh population [ms]-1 [kHz]. 
               This could be replaced by a noise term""",
        order=8)

    A_ee = arrays.FloatArray(
        label=r":math:`\alpha_{ee}`",
        default=numpy.array([0.04]),
        range=basic.Range(lo=0.02, hi=0.06, step=0.01),
        doc=
        """Characteristic cortico-cortical inverse length scale [mm]-1. Original: 0.4 cm-1""",
        order=9)

    A_ei = arrays.FloatArray(
        label=r":math:`\alpha_{ei}`",
        default=numpy.array([0.065]),
        range=basic.Range(lo=0.02, hi=0.08, step=0.01),
        doc=
        """Characteristic cortico-cortical inverse length scale [mm]-1. Original: 0.4 cm-1""",
        order=10)

    gamma_e = arrays.FloatArray(
        label=r":math:`\gamma_e`",
        default=numpy.array([0.3]),
        range=basic.Range(lo=0.1, hi=0.4, step=0.01),
        doc="""Neurotransmitter rate constant"for EPSP [ms]-1""",
        order=11)

    gamma_i = arrays.FloatArray(
        label=r":math:`\gamma_i`",
        default=numpy.array([0.065]),
        range=basic.Range(lo=0.005, hi=0.1, step=0.005),
        doc="""Neurotransmitter rate constant"for IPSP [ms]-1""",
        order=12)

    G_e = arrays.FloatArray(label=":math:`G_e`",
                            default=numpy.array([0.18]),
                            range=basic.Range(lo=0.1, hi=0.5, step=0.01),
                            doc="""peak ampplitude of EPSP [mV]""",
                            order=13)

    G_i = arrays.FloatArray(label=":math:`G_i`",
                            default=numpy.array([0.37]),
                            range=basic.Range(lo=0.1, hi=0.5, step=0.01),
                            doc="""peak ampplitude of IPSP [mV]""",
                            order=14)

    N_b_ee = arrays.FloatArray(
        label=":math:`N_{ee}^{\beta}`",
        default=numpy.array([3034.0]),
        range=basic.Range(lo=3000., hi=3050., step=10.0),
        doc="""Total number of local exc to exc synaptic connections.""",
        order=15)

    N_b_ei = arrays.FloatArray(
        label=r":math:`N_{ei}^{\beta}`",
        default=numpy.array([3034.0]),
        range=basic.Range(lo=3000., hi=3050., step=10.0),
        doc="""Total number of local exc to inh synaptic connections.""",
        order=16)

    N_b_ie = arrays.FloatArray(
        label=r":math:`N_{ie}^{\beta}`",
        default=numpy.array([536.0]),
        range=basic.Range(lo=500., hi=550., step=1.0),
        doc="""Total number of local inh to exc synaptic connections.""",
        order=17)

    N_b_ii = arrays.FloatArray(
        label=r":math:`N_{ii}^{\beta}`",
        default=numpy.array([536.0]),
        range=basic.Range(lo=500., hi=550., step=1.0),
        doc="""Total number of local inh to inh synaptic connections.""",
        order=18)

    N_a_ee = arrays.FloatArray(
        label=r":math:`N_{ee}^{\alpha}`",
        default=numpy.array([4000.0]),
        range=basic.Range(lo=3000., hi=5000., step=10.0),
        doc=
        """Total number of synaptic connections from distant exc populations""",
        order=19)

    N_a_ei = arrays.FloatArray(
        label=r":math:`N_{ei}^{\alpha}`",
        default=numpy.array([2000.0]),
        range=basic.Range(lo=1000., hi=3000., step=1.0),
        doc=
        """Total number of synaptic connections from distant exc populations""",
        order=20)

    theta_e = arrays.FloatArray(
        label=r":math:`\theta_e`",
        default=numpy.array([-60.0]),
        range=basic.Range(lo=-90.0, hi=-40.0, step=5.0),
        doc="""inflection point voltage for sigmoid function [mV]""",
        order=21)

    theta_i = arrays.FloatArray(
        label=r":math:`\theta_i`",
        default=numpy.array([-60.0]),
        range=basic.Range(lo=-90.0, hi=-40.0, step=5.0),
        doc="""inflection point voltage for sigmoid function [mV]""",
        order=22)

    g_e = arrays.FloatArray(
        label=":math:`g_e`",
        default=numpy.array([0.28]),
        range=basic.Range(lo=0.0, hi=2.0, step=0.01),
        doc="""Sigmoid slope at inflection point exc population [mV]-1""",
        order=23)

    g_i = arrays.FloatArray(
        label=":math:`g_i`",
        default=numpy.array([0.14]),
        range=basic.Range(lo=0.0, hi=2.0, step=0.01),
        doc="""Sigmoid slope at inflection point inh population [mV]-1""",
        order=24)

    lambd = arrays.FloatArray(label=":math:`\lambda`",
                              default=numpy.array([1.0]),
                              range=basic.Range(lo=0.0, hi=2.0, step=0.01),
                              doc="""Anesthetic effects""",
                              order=24)

    #Used for phase-plane axis ranges and to bound random initial() conditions.
    state_variable_range = basic.Dict(
        label="State Variable ranges [lo, hi]",
        default={
            "he": numpy.array([-90.0, 70.0]),
            "hi": numpy.array([-90.0, 70.0])
        },
        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.""",
        order=25)

    variables_of_interest = basic.Enumerate(
        label="Variables watched by Monitors",
        options=["he", "hi"],
        default=["he"],
        select_multiple=True,
        doc="""This represents the default state-variables of this Model to be
                                    monitored. It can be overridden for each Monitor if desired. The 
                                    corresponding state-variable indices for this model are :math:`E = 0`
                                    and :math:`I = 1`.""",
        order=26)

    def __init__(self, **kwargs):
        """
        Initialize the Liley Steyn-Ross model's traited attributes, any provided as
        keywords will overide their traited default.

        """
        LOG.info('%s: initing...' % str(self))
        super(LileySteynRoss, self).__init__(**kwargs)
        #self._state_variables = ["E", "I"]
        self._nvar = 2
        self.cvar = numpy.array([0, 1], dtype=numpy.int32)
        LOG.debug('%s: inited.' % repr(self))

    def dfun(self, state_variables, coupling, local_coupling=0.0):
        r"""

        TODO:  include equations here and see how to add the local connectivity or the 
        the laplacian oeprator. This model is the one used in Bojak 2011.

        """

        he = state_variables[0, :]
        hi = state_variables[1, :]

        # long-range coupling - phi_e -> he / phi_e -> h_i
        c_0 = coupling[0, :]

        # short-range (local) coupling - local coupling functions should be different for exc and inh
        #lc_0 = local_coupling * he
        #lc_1 = local_coupling * hi

        #
        psi_ee = (self.h_e_rev - he) / abs(
            self.h_e_rev - self.h_e_rest)  # usually > 0
        psi_ei = (self.h_e_rev - hi) / abs(
            self.h_e_rev - self.h_i_rest)  # usually > 0
        psi_ie = (self.h_i_rev - he) / abs(
            self.h_i_rev - self.h_e_rest)  # usually < 0
        psi_ii = (self.h_i_rev - hi) / abs(
            self.h_i_rev - self.h_i_rest)  # usually < 0

        S_e = 1.0 / (1.0 + numpy.exp(-self.g_e * (he + c_0 - self.theta_e)))
        S_i = 1.0 / (1.0 + numpy.exp(-self.g_i * (hi + c_0 - self.theta_i)))

        F1 = ((self.h_e_rest - he) + psi_ee * ((self.N_a_ee + self.N_b_ee) * S_e  + self.p_ee) * (self.G_e/self.gamma_e) +\
                                  self.lambd * psi_ie * (self.N_b_ie * S_i + self.p_ie) * (self.G_i/self.gamma_i)) / self.tau_e

        F2 = ((self.h_i_rest - hi) + psi_ei * ((self.N_a_ei + self.N_b_ei) * S_e  + self.p_ei) * (self.G_e/self.gamma_e) +\
                                  self.lambd * psi_ii * (self.N_b_ii * S_i + self.p_ii) * (self.G_i/self.gamma_i)) / self.tau_i

        dhe = F1
        dhi = F2

        derivative = numpy.array([dhe, dhi])

        return derivative