class TestBoundsModel(Model): # Used for phase-plane axis ranges and to bound random initial() conditions. state_variable_boundaries = Final( label="State Variable boundaries [lo, hi]", default={"x1": numpy.array([0.0, 1.0]), "x2": numpy.array([None, 1.0]), "x3": numpy.array([0.0, None]), "x4": numpy.array([-numpy.inf, numpy.inf]) }, 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 = List( of=str, label="Variables watched by Monitors", choices=('x1', 'x2', 'x3', 'x4', 'x5'), default=('x1', 'x2', 'x3', 'x4', 'x5'), doc="""default state variables to be monitored""") state_variables = ['x1', 'x2', 'x3', 'x4', 'x5'] state_variable_range = Final( default={ "x1": numpy.array([-1.0, 2.0]), "x2": numpy.array([-1.0, 2.0]), "x3": numpy.array([-1.0, 2.0]), "x4": numpy.array([-1.0, 2.0]), "x5": numpy.array([-1.0, 2.0]) }) _nvar = 5 cvar = numpy.array([0], dtype=numpy.int32) def dfun(self, state, node_coupling, local_coupling=0.0): return 0.0 * state
class KuramotoT(ModelNumbaDfun): omega = NArray(label=":math:`omega`", default=numpy.array([60.0 * 2.0 * 3.1415927 / 1e3]), doc="""""") state_variable_range = Final(label="State Variable ranges [lo, hi]", default={"V": numpy.array([0.0, 0.0])}, doc="""state variables""") state_variable_boundaries = Final( label="State Variable boundaries [lo, hi]", default={"V": numpy.array([-2, 1])}, ) variables_of_interest = List( of=str, label="Variables or quantities available to Monitors", choices=('V', ), default=('V', ), doc="Variables to monitor") state_variables = ['V'] _nvar = 1 cvar = numpy.array([ 0, ], dtype=numpy.int32) def dfun(self, vw, c, local_coupling=0.0): vw_ = vw.reshape(vw.shape[:-1]).T c_ = c.reshape(c.shape[:-1]).T deriv = _numba_dfun_KuramotoT(vw_, c_, self.omega, local_coupling) return deriv.T[..., numpy.newaxis]
class Linear(Model): gamma = NArray( label=r":math:`\gamma`", default=numpy.array([-10.0]), domain=Range(lo=-100.0, hi=0.0, step=1.0), doc="The damping coefficient specifies how quickly the node's activity relaxes, must be larger" " than the node's in-degree in order to remain stable.") state_variable_range = Final( label="State Variable ranges [lo, hi]", default={"x": numpy.array([-1, 1])}, doc="Range used for state variable initialization and visualization.") variables_of_interest = List( of=str, label="Variables watched by Monitors", choices=("x",), default=("x",), ) coupling_terms = Final( label="Coupling terms", # how to unpack coupling array default=["c"] ) state_variable_dfuns = Final( label="Drift functions", default={ "x": "gamma * x + c", } ) parameter_names = List( of=str, label="List of parameters for this model", default=tuple('gamma'.split())) state_variables = ('x',) _nvar = 1 cvar = numpy.array([0], dtype=numpy.int32) def dfun(self, state, coupling, local_coupling=0.0): """ .. math:: x = a{\gamma} + b """ x, = state c, = coupling dx = self.gamma * x + c + local_coupling * x return numpy.array([dx])
class Linear(Model): gamma = NArray( label=r":math:`\gamma`", default=numpy.array([-10.0]), domain=Range(lo=-100.0, hi=0.0, step=1.0), doc= "The damping coefficient specifies how quickly the node's activity relaxes, must be larger" " than the node's in-degree in order to remain stable.") state_variable_range = Final( label="State Variable ranges [lo, hi]", default={"x": numpy.array([-1, 1])}, doc="Range used for state variable initialization and visualization.") variables_of_interest = List( of=str, label="Variables watched by Monitors", choices=("x", ), default=("x", ), ) state_variables = ('x', ) _nvar = 1 cvar = numpy.array([0], dtype=numpy.int32) def dfun(self, state, coupling, local_coupling=0.0): x, = state c, = coupling dx = self.gamma * x + c + local_coupling * x return numpy.array([dx])
class FaceSurface(Surface): """Face surface.""" surface_type = Final(FACE) @classmethod def from_file(cls, source_file="face_8614.zip"): return super(FaceSurface, cls).from_file(source_file)
class EEGCap(Surface): """EEG cap surface.""" surface_type = Final(EEG_CAP) @classmethod def from_file(cls, source_file="scalp_1082.zip"): return super(EEGCap, cls).from_file(source_file)
class SkullSkin(Surface): """Outer-skull - scalp interface surface.""" surface_type = Final(OUTER_SKULL) @classmethod def from_file(cls, source_file="outer_skull_4096.zip"): return super(SkullSkin, cls).from_file(source_file)
class BrainSkull(Surface): """Brain - inner skull interface surface.""" surface_type = Final(INNER_SKULL) @classmethod def from_file(cls, source_file="inner_skull_4096.zip"): return super(BrainSkull, cls).from_file(source_file)
class SkinAir(Surface): """Skin - air interface surface.""" surface_type = Final(OUTER_SKIN) @classmethod def from_file(cls, source_file="outer_skin_4096.zip"): return super(SkinAir, cls).from_file(source_file)
class SensorsMEG(Sensors): """ These are actually just SQUIDS. Axial or planar gradiometers are achieved by calculating lead fields for two sets of sensors and then subtracting... :: position orientation | | / \ / \\ / \ / \\ file columns: labels, x, y, z, dx, dy, dz """ sensors_type = Final(field_type=str, default=SensorTypesEnum.TYPE_MEG.value) orientations = NArray( label="Sensor orientations", doc="An array representing the orientation of the MEG SQUIDs") has_orientation = Attr(field_type=bool, default=True) @classmethod def from_file(cls, source_file="meg_151.txt.bz2"): result = super(SensorsMEG, cls).from_file(source_file) source_full_path = try_get_absolute_path("tvb_data.sensors", source_file) reader = FileReader(source_full_path) result.orientations = reader.read_array(use_cols=(4, 5, 6)) return result
class DoubleGaussian(FiniteSupportEquation): """ A Mexican-hat function approximated by the difference of Gaussians functions. """ _ui_name = "Mexican-hat" equation = Final( label="Double Gaussian Equation", default= "(amp_1 * exp(-((var-midpoint_1)**2 / (2.0 * sigma_1**2)))) - (amp_2 * exp(-((var-midpoint_2)**2 / (2.0 * sigma_2**2))))", # locked=True, doc=""":math:`amp_1 \\exp\\left(-\\left((x-midpoint_1)^2 / \\left(2.0 \\sigma_1^2\\right)\\right)\\right) - amp_2 \\exp\\left(-\\left((x-midpoint_2)^2 / \\left(2.0 \\sigma_2^2\\right)\\right)\\right)`""") parameters = Attr(field_type=dict, label="Double Gaussian Parameters", default=lambda: { "amp_1": 0.5, "sigma_1": 20.0, "midpoint_1": 0.0, "amp_2": 1.0, "sigma_2": 10.0, "midpoint_2": 0.0 })
class PulseTrain(TemporalApplicableEquation): """ A pulse train , offset with respect to the time axis. **Parameters**: * :math:`\\tau` : pulse width or pulse duration * :math:`T` : pulse repetition period * onset : time of the first pulse * amp : amplitude of the pulse """ equation = Final( label="Pulse Train", default="where((var>onset)&(((var-onset) % T) < tau), amp, 0)", doc= """:math:`\\left\\{{\\begin{array}{rl}amp,&{\\text{if }} (var-onset) \\mod T < \\tau \\and var > onset\\\\0,&{\\text{otherwise }}\\end{array}}\\right.`""" ) # onset is in milliseconds # T and tau are in milliseconds as well parameters = Attr(field_type=dict, default=lambda: { "T": 42.0, "tau": 13.0, "amp": 1.0, "onset": 30.0 }, label="Pulse Train Parameters")
class BrainSkull(Surface): """Brain - inner skull interface surface.""" surface_type = Final(field_type=str, default=SurfaceTypesEnum.BRAIN_SKULL_SURFACE.value) @classmethod def from_file(cls, source_file="inner_skull_4096.zip"): return super(BrainSkull, cls).from_file(source_file)
class FaceSurface(Surface): """Face surface.""" surface_type = Final(field_type=str, default=SurfaceTypesEnum.FACE_SURFACE.value) @classmethod def from_file(cls, source_file="face_8614.zip"): return super(FaceSurface, cls).from_file(source_file)
class EEGCap(Surface): """EEG cap surface.""" surface_type = Final(field_type=str, default=SurfaceTypesEnum.EEG_CAP_SURFACE.value) @classmethod def from_file(cls, source_file="scalp_1082.zip"): return super(EEGCap, cls).from_file(source_file)
class SkullSkin(Surface): """Outer-skull - scalp interface surface.""" surface_type = Final(field_type=str, default=SurfaceTypesEnum.SKULL_SKIN_SURFACE.value) @classmethod def from_file(cls, source_file="outer_skull_4096.zip"): return super(SkullSkin, cls).from_file(source_file)
class SkinAir(Surface): """Skin - air interface surface.""" surface_type = Final(field_type=str, default=SurfaceTypesEnum.SKIN_AIR_SURFACE.value) @classmethod def from_file(cls, source_file="outer_skin_4096.zip"): return super(SkinAir, cls).from_file(source_file)
class DoubleExponential(HRFKernelEquation): """ A difference of two exponential functions to define a kernel for the bold monitor. **Parameters** : * :math:`\\tau_1`: Time constant of the second exponential function [s] * :math:`\\tau_2`: Time constant of the first exponential function [s]. * :math:`f_1` : Frequency of the first sine function [Hz]. * :math:`f_2` : Frequency of the second sine function [Hz]. * :math:`amp_1`: Amplitude of the first exponential function. * :math:`amp_2`: Amplitude of the second exponential function. * :math:`a` : Amplitude factor after normalization. **Reference**: .. [P_2000] Alex Polonsky, Randolph Blake, Jochen Braun and David J. Heeger (2000). Neuronal activity in human primary visual cortex correlates with perception during binocular rivalry. Nature Neuroscience 3: 1153-1159 """ _ui_name = "HRF kernel: Difference of Exponentials" equation = Final( label="Double Exponential Equation", default= "((amp_1 * exp(-var/tau_1) * sin(2.*pi*f_1*var)) - (amp_2 * exp(-var/ tau_2) * sin(2.*pi*f_2*var)))", doc=""":math:`h(var) = amp_1\\exp(\\frac{-var}{\tau_1}) \\sin(2\\cdot\\pi f_1 \\cdot var) - amp_2\\cdot \\exp(-\\frac{var} {\\tau_2})*\\sin(2\\pi f_2 var)`.""") parameters = Attr(field_type=dict, label="Double Exponential Parameters", default=lambda: { "tau_1": 7.22, "f_1": 0.03, "amp_1": 0.1, "tau_2": 7.4, "f_2": 0.12, "amp_2": 0.1, "a": 0.1, "pi": numpy.pi }) def evaluate(self, var): """ Generate a discrete representation of the equation for the space represented by ``var``. """ _pattern = RefBase.evaluate(self.equation, global_dict=self.parameters) _pattern /= max(_pattern) _pattern *= self.parameters["a"] return _pattern
class PulseTrain(TemporalApplicableEquation): """ A pulse train , offset with respect to the time axis. **Parameters**: * :math:`\\tau` : pulse width or pulse duration * :math:`T` : pulse repetition period * :math:`f` : pulse repetition frequency (1/T) * duty cycle : :math:``\\frac{\\tau}{T}`` (for a square wave: 0.5) * onset time : """ equation = Final(label="Pulse Train", default="where((var % T) < tau, amp, 0)", doc=""":math:`\\frac{\\tau}{T} +\\sum_{n=1}^{\\infty}\\frac{2}{n\\pi} \\sin\\left(\\frac{\\pi\\,n\\tau}{T}\\right) \\cos\\left(\\frac{2\\pi\\,n}{T} var\\right)`. The starting time is halfway through the first pulse. The phase can be offset t with t - tau/2""") # onset is in milliseconds # T and tau are in milliseconds as well parameters = Attr(field_type=dict, default=lambda: { "T": 42.0, "tau": 13.0, "amp": 1.0, "onset": 30.0 }, label="Pulse Train Parameters") def evaluate(self, var): """ Generate a discrete representation of the equation for the space represented by ``var``. The argument ``var`` can represent a distance, or effective distance, for each node in a simulation. Or a time, or in principle any arbitrary `` space ``. ``var`` can be a single number, a numpy.ndarray or a ?scipy.sparse_matrix? TODO: think this last one is true, need to check as we need it for LocalConnectivity... """ # rolling in the deep ... onset = self.parameters["onset"] off = var < onset var = numpy.roll(var, off.sum() + 1) var[..., off] = 0.0 _pattern = RefBase.evaluate(self.equation, global_dict=self.parameters) _pattern[..., off] = 0.0 return _pattern
class TestTrait(HasTraits): """ Test class with traited attributes""" test_array = NArray(label="State Variables range [[lo],[hi]]", default=numpy.array([[-3.0, -6.0], [3.0, 6.0]]), dtype="float") test_dict = Final(label="State Variable ranges [lo, hi].", default={ "V": -3.0, "W": -6.0 })
class Cosine(TemporalApplicableEquation): """ A Cosine equation. """ equation = Final(label="Cosine Equation", default="amp * cos(6.283185307179586 * frequency * var)", doc=""":math:`amp \\cos(2.0 \\pi frequency x)` """) parameters = Attr(field_type=dict, label="Cosine Parameters", default=lambda: { "amp": 1.0, "frequency": 0.01 }) #kHz #"pi": numpy.pi,
class SensorsEEG(Sensors): """ EEG sensor locations are represented as unit vectors, these need to be combined with a head(outer-skin) surface to obtain actual sensor locations :: position | / \\ / \\ file columns: labels, x, y, z """ sensors_type = Final(field_type=str, default=SensorTypesEnum.TYPE_EEG.value) has_orientation = Attr(bool, default=False)
class Linear(TemporalApplicableEquation): """ A linear equation. """ equation = Final( label="Linear Equation", default="a * var + b", # locked=True, doc=""":math:`result = a * x + b`""") parameters = Attr(field_type=dict, label="Linear Parameters", default=lambda: { "a": 1.0, "b": 0.0 })
class FirstOrderVolterra(HRFKernelEquation): """ Integral form of the first Volterra kernel of the three used in the Ballon Windekessel model for computing the Bold signal. This function describes a damped Oscillator. **Parameters** : * :math:`\\tau_s`: Dimensionless? exponential decay parameter. * :math:`\\tau_f`: Dimensionless? oscillatory parameter. * :math:`k_1` : First Volterra kernel coefficient. * :math:`V_0` : Resting blood volume fraction. **References** : .. [F_2000] Friston, K., Mechelli, A., Turner, R., and Price, C., *Nonlinear Responses in fMRI: The Balloon Model, Volterra Kernels, and Other Hemodynamics*, NeuroImage, 12, 466 - 477, 2000. """ _ui_name = "HRF kernel: Volterra Kernel" equation = Final( label="First Order Volterra Kernel", default= "1/3. * exp(-0.5*(var / tau_s)) * (sin(sqrt(1./tau_f - 1./(4.*tau_s**2)) * var)) / (sqrt(1./tau_f - 1./(4.*tau_s**2)))", doc=""":math:`G(t - t^{\\prime}) = e^{\\frac{1}{2} \\left(\\frac{t - t^{\\prime}}{\\tau_s} \\right)} \\frac{\\sin\\left((t - t^{\\prime}) \\sqrt{\\frac{1}{\\tau_f} - \\frac{1}{4 \\tau_s^2}}\\right)} {\\sqrt{\\frac{1}{\\tau_f} - \\frac{1}{4 \\tau_s^2}}} \\; \\; \\; \\; \\; \\; for \\; \\; \\; t \\geq t^{\\prime} = 0 \\; \\; \\; \\; \\; \\; for \\; \\; \\; t < t^{\\prime}`.""" ) parameters = Attr(field_type=dict, label="Mixture of Gammas Parameters", default=lambda: { "tau_s": 0.8, "tau_f": 0.4, "k_1": 5.6, "V_0": 0.02 })
class ProjectionSurfaceSEEG(ProjectionMatrix): """ Specific projection, from a CorticalSurface to SEEG sensors. """ projection_type = Final(field_type=str, default=ProjectionsTypeEnum.SEEG.value) sensors = Attr(field_type=sensors.SensorsInternal) @classmethod def from_file(cls, source_file='projection_seeg_588_surface_16k.npy', matlab_data_name=None, is_brainstorm=False): return ProjectionMatrix.from_file.__func__(cls, source_file, matlab_data_name, is_brainstorm)
class Alpha(TemporalApplicableEquation): """ An Alpha function belonging to the Exponential function family. """ equation = Final( label="Alpha Equation", default= "where((var-onset) > 0, (alpha * beta) / (beta - alpha) * (exp(-alpha * (var-onset)) - exp(-beta * (var-onset))), 0.0 * var)", doc=""":math:`(\\alpha * \\beta) / (\\beta - \\alpha) * (\\exp(-\\alpha * (x-onset)) - \\exp(-\\beta * (x-onset)))` for :math:`(x-onset) > 0`""" ) parameters = Attr(field_type=dict, label="Alpha Parameters", default=lambda: { "onset": 0.5, "alpha": 13.0, "beta": 42.0 })
class GeneralizedSigmoid(TemporalApplicableEquation): """ A General Sigmoid equation. """ equation = Final( label="Generalized Sigmoid Equation", default= "low + (high - low) / (1.0 + exp(-1.8137993642342178 * (var-midpoint)/sigma))", doc=""":math:`low + (high - low) / (1.0 + \\exp(-\\pi/\\sqrt(3.0) (x-midpoint)/\\sigma))`""") parameters = Attr(field_type=dict, label="Sigmoid Parameters", default=lambda: { "low": 0.0, "high": 1.0, "midpoint": 1.0, "sigma": 0.3 }) #,
class TestUpdateVariablesModel(Model): variables_of_interest = List( of=str, label="Variables watched by Monitors", choices=('x1', 'x2', 'x3', 'x4', 'x5'), default=('x1', 'x2', 'x3', 'x4', 'x5'), doc="""default state variables to be monitored""") state_variables = ['x1', 'x2', 'x3', 'x4', 'x5'] non_integrated_variables = ['x4', 'x5'] state_variable_range = Final( default={ "x1": numpy.array([-1.0, 2.0]), "x2": numpy.array([-1.0, 2.0]), "x3": numpy.array([-1.0, 2.0]), "x4": numpy.array([-1.0, 2.0]), "x5": numpy.array([-1.0, 2.0]) }) _nvar = 5 cvar = numpy.array([0], dtype=numpy.int32) def dfun(self, integrated_variables, node_coupling, local_coupling=0.0): return 0.0 * integrated_variables def update_state_variables_before_integration(self, state, coupling, local_coupling=0.0, stimulus=0.0): new_state = numpy.copy(state) new_state[3] = state[3] + state[0] new_state[4] = state[4] + state[1] + state[2] return state def update_state_variables_after_integration(self, state): new_state = numpy.copy(state) new_state[3] = state[3] - state[0] new_state[4] = state[4] - state[1] - state[2] return state
class Sigmoid(SpatialApplicableEquation, FiniteSupportEquation): """ A Sigmoid equation. offset: parameter to extend the behaviour of this function when spatializing model parameters. """ equation = Final( label="Sigmoid Equation", default= "(amp / (1.0 + exp(-1.8137993642342178 * (radius-var)/sigma))) + offset", doc=""":math:`(amp / (1.0 + \\exp(-\\pi/\\sqrt(3.0) (radius-x)/\\sigma))) + offset`""") parameters = Attr(field_type=dict, label="Sigmoid Parameters", default=lambda: { "amp": 1.0, "radius": 5.0, "sigma": 1.0, "offset": 0.0 }) #"pi": numpy.pi,
class Gaussian(SpatialApplicableEquation, FiniteSupportEquation): """ A Gaussian equation. offset: parameter to extend the behaviour of this function when spatializing model parameters. """ equation = Final( label="Gaussian Equation", default="(amp * exp(-((var-midpoint)**2 / (2.0 * sigma**2))))+offset", # locked=True, doc=""":math:`(amp \\exp\\left(-\\left(\\left(x-midpoint\\right)^2 / \\left(2.0 \\sigma^2\\right)\\right)\\right)) + offset`""") parameters = Attr(field_type=dict, label="Gaussian Parameters", default=lambda: { "amp": 1.0, "sigma": 1.0, "midpoint": 0.0, "offset": 0.0 })