Skip to content

Commit 5f4d474

Browse files
committed
add supHopf model
1 parent 0b2a2c5 commit 5f4d474

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

tvb/simulator/models/oscillator.py

+107
Original file line numberDiff line numberDiff line change
@@ -530,3 +530,110 @@ def dfun(self, state_variables, coupling, local_coupling=0.0,
530530

531531
# all this pi makeh me have great hungary, can has sum NaN?
532532
return self.derivative
533+
534+
535+
class supHopf(ModelNumbaDfun):
536+
r"""
537+
The supHopf model describes the normal form of a supercritical Hopf bifurcation in Cartesian coordinates.
538+
This normal form has a supercritical bifurcation at a=0 with a the bifurcation parameter in
539+
the model. So for a < 0, the local dynamics has a stable fixed point, and for a > 0, the local dynamics enters
540+
in a stable limit cycle.
541+
542+
See:
543+
544+
.. [Deco_2017a] Deco, G., Kringelbach, M.L., Jirsa, V.K., Ritter, P.
545+
*The dynamics of resting fluctuations in the brain: metastability and its dynamical
546+
cortical core* Sci Reports, 2017, 7: 3095.
547+
548+
The equations of the supHopf population model read:
549+
550+
.. math::
551+
\dot{x}_{i} &= (a_{i} - x_{i}^{2} - y_{i}^{2})x_{i} - omega{i}y_{i} \\
552+
\dot{y}_{i} &= (a_{i} - x_{i}^{2} - y_{i}^{2})y_{i} + omega{i}x_{i}
553+
554+
"""
555+
556+
_ui_name = "supHopf"
557+
ui_configurable_parameters = ['a', 'omega']
558+
559+
#supHopf's parameters.
560+
a = arrays.FloatArray(
561+
label=r":math:`a`",
562+
default=numpy.array([-0.5]),
563+
range=basic.Range(lo=-10.0, hi=10.0, step=0.01),
564+
doc="""Local bifurcation parameter.""",
565+
order=1)
566+
567+
omega = arrays.FloatArray(
568+
label=r":math:`\omega`",
569+
default=numpy.array([1.]),
570+
range=basic.Range(lo=0.05, hi=630.0, step=0.01),
571+
doc="""Angular frequency.""",
572+
order=2)
573+
574+
# Initialization.
575+
state_variable_range = basic.Dict(
576+
label="State Variable ranges [lo, hi]",
577+
default={"x": numpy.array([-5.0, 5.0]),
578+
"y": numpy.array([-5.0, 5.0])},
579+
doc="""The values for each state-variable should be set to encompass
580+
the expected dynamic range of that state-variable for the current
581+
parameters, it is used as a mechanism for bounding random initial
582+
conditions when the simulation isn't started from an explicit
583+
history, it is also provides the default range of phase-plane plots.""",
584+
order=3)
585+
586+
variables_of_interest = basic.Enumerate(
587+
label="Variables watched by Monitors",
588+
options=["x", "y"],
589+
default=["x"],
590+
select_multiple=True,
591+
doc="Quantities of supHopf available to monitor.",
592+
order=4)
593+
594+
state_variables = ["x", "y"]
595+
596+
_nvar = 2 # number of state-variables
597+
cvar = numpy.array([0, 1], dtype=numpy.int32) # coupling variables
598+
599+
def _numpy_dfun(self, state_variables, coupling, local_coupling=0.0,
600+
array=numpy.array, where=numpy.where, concat=numpy.concatenate):
601+
r"""
602+
Computes the derivatives of the state-variables of supHopf
603+
with respect to time.
604+
"""
605+
606+
y = state_variables
607+
ydot = numpy.empty_like(state_variables)
608+
609+
# long-range coupling
610+
c_0 = coupling[0]
611+
c_1 = coupling[1]
612+
613+
# short-range (local) coupling
614+
lc_0 = local_coupling * y[0]
615+
616+
#supHopf's equations in Cartesian coordinates:
617+
ydot[0] = (self.a - y[0]**2 - y[1]**2) * y[0] - self.omega * y[1] + c_0
618+
ydot[1] = (self.a - y[0]**2 - y[1]**2) * y[1] + self.omega * y[0] + c_1
619+
620+
return ydot
621+
622+
def dfun(self, x, c, local_coupling=0.0):
623+
x_ = x.reshape(x.shape[:-1]).T
624+
c_ = c.reshape(c.shape[:-1]).T
625+
lc_0 = local_coupling * x[0, :, 0]
626+
deriv = _numba_dfun(x_, c_, self.a, self.omega, lc_0)
627+
return deriv.T[..., numpy.newaxis]
628+
629+
@guvectorize([(float64[:],) * 6], '(n),(m)' + ',()' * 3 + '->(n)', nopython=True)
630+
def _numba_dfun(y, c, a, omega, lc_0, ydot):
631+
"Gufunc for supHopf model equations."
632+
633+
#long-range coupling
634+
c_0 = c[0]
635+
c_1 = c[1]
636+
637+
#supHopf equations
638+
ydot[0] = (a[0] - y[0]**2 - y[1]**2) * y[0] - omega[0] * y[1] + c_0
639+
ydot[1] = (a[0] - y[0]**2 - y[1]**2) * y[1] + omega[0] * y[0] + c_1

0 commit comments

Comments
 (0)