예제 #1
0
    def __init__(self,
                 target,
                 target_var,
                 N,
                 rate,
                 weight,
                 when='synapses',
                 order=0):
        if target_var not in target.variables:
            raise KeyError('%s is not a variable of %s' %
                           (target_var, target.name))

        self._weight = weight
        self._target_var = target_var

        if isinstance(weight, str):
            weight = '(%s)' % weight
        else:
            weight_dims = get_dimensions(weight)
            target_dims = target.variables[target_var].dim
            # This will be checked automatically in the abstract code as well
            # but doing an explicit check here allows for a clearer error
            # message
            if not have_same_dimensions(weight_dims, target_dims):
                raise DimensionMismatchError(
                    ('The provided weight does not '
                     'have the same unit as the '
                     'target variable "%s"') % target_var, weight_dims,
                    target_dims)
            weight = repr(weight)
        self._N = N
        self._rate = rate
        binomial_sampling = BinomialFunction(N,
                                             rate * target.clock.dt,
                                             name='poissoninput_binomial*')

        code = '{targetvar} += {binomial}()*{weight}'.format(
            targetvar=target_var,
            binomial=binomial_sampling.name,
            weight=weight)
        self._stored_dt = target.dt_[:]  # make a copy
        # FIXME: we need an explicit reference here for on-the-fly subgroups
        # For example: PoissonInput(group[:N], ...)
        self._group = target
        CodeRunner.__init__(self,
                            group=target,
                            template='stateupdate',
                            code=code,
                            user_code='',
                            when=when,
                            order=order,
                            name='poissoninput*',
                            clock=target.clock)
        self.variables = Variables(self)
        self.variables._add_variable(binomial_sampling.name, binomial_sampling)
    def __init__(self,
                 source,
                 name='ratemonitor*',
                 codeobj_class=None,
                 dtype=np.float64):

        #: The group we are recording from
        self.source = source

        self.codeobj_class = codeobj_class
        CodeRunner.__init__(self,
                            group=self,
                            code='',
                            template='ratemonitor',
                            clock=source.clock,
                            when='end',
                            order=0,
                            name=name)

        self.add_dependency(source)

        self.variables = Variables(self)
        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))
        self.variables.add_constant('_source_start', start)
        self.variables.add_constant('_source_stop', stop)
        self.variables.add_reference('_spikespace', source)
        self.variables.add_dynamic_array('rate',
                                         size=0,
                                         dimensions=hertz.dim,
                                         read_only=True,
                                         dtype=dtype)
        self.variables.add_dynamic_array(
            't',
            size=0,
            dimensions=second.dim,
            read_only=True,
            dtype=self._clock.variables['t'].dtype)
        self.variables.add_reference('_num_source_neurons', source, 'N')
        self.variables.add_array('N',
                                 dtype=np.int32,
                                 size=1,
                                 scalar=True,
                                 read_only=True)
        self.variables.create_clock_variables(self._clock, prefix='_clock_')
        self._enable_group_attributes()
    def __init__(self, group, method, clock, order=0):
        # group is the neuron (a group of compartments)
        self.method_choice = method
        self.group = weakref.proxy(group)

        compartments = group.flat_morphology.n
        sections = group.flat_morphology.sections

        CodeRunner.__init__(self, group,
                            'spatialstateupdate',
                            code='''_gtot = gtot__private
                                    _I0 = I0__private''',
                            clock=clock,
                            when='groups',
                            order=order,
                            name=group.name + '_spatialstateupdater*',
                            check_units=False,
                            template_kwds={'number_sections': sections})

        self.variables = Variables(self, default_index='_section_idx')
        self.variables.add_reference('N', group)
        # One value per compartment
        self.variables.add_arange('_compartment_idx', size=compartments)
        self.variables.add_array('_invr', dimensions=siemens.dim,
                                 size=compartments, constant=True,
                                 index='_compartment_idx')
        # one value per section
        self.variables.add_arange('_section_idx', size=sections)
        self.variables.add_array('_P_parent', size=sections,
                                 constant=True)  # elements below diagonal
        self.variables.add_arrays(['_morph_idxchild', '_morph_parent_i',
                                   '_starts', '_ends'], size=sections,
                                  dtype=np.int32, constant=True)
        self.variables.add_arrays(['_invr0', '_invrn'], dimensions=siemens.dim,
                                  size=sections, constant=True)
        # one value per section + 1 value for the root
        self.variables.add_arange('_section_root_idx', size=sections+1)
        self.variables.add_array('_P_diag', size=sections+1,
                                 constant=True, index='_section_root_idx')
        self.variables.add_array('_B', size=sections+1,
                                 constant=True, index='_section_root_idx')
        self.variables.add_array('_morph_children_num',
                                 size=sections+1, dtype=np.int32,
                                 constant=True, index='_section_root_idx')
        # 2D matrices of size (sections + 1) x max children per section
        self.variables.add_arange('_morph_children_idx',
                                  size=len(group.flat_morphology.morph_children))
        self.variables.add_array('_P_children',
                                 size=len(group.flat_morphology.morph_children),
                                 index='_morph_children_idx',
                                 constant=True)  # elements above diagonal
        self.variables.add_array('_morph_children',
                                 size=len(group.flat_morphology.morph_children),
                                 dtype=np.int32, constant=True,
                                 index='_morph_children_idx')
        self._enable_group_attributes()

        self._morph_parent_i = group.flat_morphology.morph_parent_i
        self._morph_children_num = group.flat_morphology.morph_children_num
        self._morph_children = group.flat_morphology.morph_children
        self._morph_idxchild = group.flat_morphology.morph_idxchild
        self._starts = group.flat_morphology.starts
        self._ends = group.flat_morphology.ends
    def __init__(self, N, indices, times, dt=None, clock=None,
                 period=0*second, when='thresholds', order=0, sorted=False,
                 name='spikegeneratorgroup*', codeobj_class=None):

        Group.__init__(self, dt=dt, clock=clock, when=when, order=order, name=name)

        # We store the indices and times also directly in the Python object,
        # this way we can use them for checks in `before_run` even in standalone
        # TODO: Remove this when the checks in `before_run` have been moved to the template
        #: Array of spiking neuron indices.
        self._neuron_index = None
        #: Array of spiking neuron times.
        self._spike_time = None
        #: "Dirty flag" that will be set when spikes are changed after the
        #: `before_run` check
        self._spikes_changed = True

        # Let other objects know that we emit spikes events
        self.events = {'spike': None}

        self.codeobj_class = codeobj_class

        if N < 1 or int(N) != N:
            raise TypeError('N has to be an integer >=1.')
        N = int(N)
        self.start = 0
        self.stop = N

        self.variables = Variables(self)
        self.variables.create_clock_variables(self._clock)

        indices, times = self._check_args(indices, times, period, N, sorted,
                                          self._clock.dt)

        self.variables.add_constant('N', value=N)
        self.variables.add_array('period', dimensions=second.dim, size=1,
                                 constant=True, read_only=True, scalar=True,
                                 dtype=self._clock.variables['t'].dtype)
        self.variables.add_arange('i', N)
        self.variables.add_dynamic_array('spike_number',
                                         values=np.arange(len(indices)),
                                         size=len(indices),
                                         dtype=np.int32, read_only=True,
                                         constant=True, index='spike_number',
                                         unique=True)
        self.variables.add_dynamic_array('neuron_index', values=indices,
                                         size=len(indices),
                                         dtype=np.int32, index='spike_number',
                                         read_only=True, constant=True)
        self.variables.add_dynamic_array('spike_time', values=times, size=len(times),
                                         dimensions=second.dim, index='spike_number',
                                         read_only=True, constant=True,
                                         dtype=self._clock.variables['t'].dtype)
        self.variables.add_dynamic_array('_timebins', size=len(times),
                                         index='spike_number',
                                         read_only=True, constant=True,
                                         dtype=np.int32)
        self.variables.add_array('_period_bins', size=1, constant=True,
                                 read_only=True, scalar=True,
                                 dtype=np.int32)
        self.variables.add_array('_spikespace', size=N+1, dtype=np.int32)
        self.variables.add_array('_lastindex', size=1, values=0, dtype=np.int32,
                                 read_only=True, scalar=True)

        #: Remember the dt we used the last time when we checked the spike bins
        #: to not repeat the work for multiple runs with the same dt
        self._previous_dt = None

        CodeRunner.__init__(self, self,
                            code='',
                            template='spikegenerator',
                            clock=self._clock,
                            when=when,
                            order=order,
                            name=None)

        # Activate name attribute access
        self._enable_group_attributes()

        self.variables['period'].set_value(period)
    def __init__(self,
                 source,
                 variables,
                 record,
                 dt=None,
                 clock=None,
                 when='start',
                 order=0,
                 name='statemonitor*',
                 codeobj_class=None):
        self.source = source
        # Make the monitor use the explicitly defined namespace of its source
        # group (if it exists)
        self.namespace = getattr(source, 'namespace', None)
        self.codeobj_class = codeobj_class

        # run by default on source clock at the end
        if dt is None and clock is None:
            clock = source.clock

        # variables should always be a list of strings
        if variables is True:
            variables = source.equations.names
        elif isinstance(variables, str):
            variables = [variables]
        #: The variables to record
        self.record_variables = variables

        # record should always be an array of ints
        self.record_all = False
        if hasattr(record, '_indices'):
            # The ._indices method always returns absolute indices
            # If the source is already a subgroup of another group, we therefore
            # have to shift the indices to become relative to the subgroup
            record = record._indices() - getattr(source, '_offset', 0)
        if record is True:
            self.record_all = True
            try:
                record = np.arange(len(source), dtype=np.int32)
            except NotImplementedError:
                # In standalone mode, this is not possible for synaptic
                # variables because the number of synapses is not defined yet
                raise NotImplementedError(
                    ('Cannot determine the actual '
                     'indices to record for record=True. '
                     'This can occur for example in '
                     'standalone mode when trying to '
                     'record a synaptic variable. '
                     'Consider providing an explicit '
                     'array of indices for the record '
                     'argument.'))
        elif record is False:
            record = np.array([], dtype=np.int32)
        elif isinstance(record, numbers.Number):
            record = np.array([record], dtype=np.int32)
        else:
            record = np.asarray(record, dtype=np.int32)

        #: The array of recorded indices
        self.record = record
        self.n_indices = len(record)

        # Some dummy code so that code generation takes care of the indexing
        # and subexpressions
        code = ['_to_record_%s = _source_%s' % (v, v) for v in variables]
        code = '\n'.join(code)

        CodeRunner.__init__(self,
                            group=self,
                            template='statemonitor',
                            code=code,
                            name=name,
                            clock=clock,
                            dt=dt,
                            when=when,
                            order=order,
                            check_units=False)

        self.add_dependency(source)

        # Setup variables
        self.variables = Variables(self)

        self.variables.add_dynamic_array(
            't',
            size=0,
            dimensions=second.dim,
            constant=False,
            dtype=self._clock.variables['t'].dtype)
        self.variables.add_array('N',
                                 dtype=np.int32,
                                 size=1,
                                 scalar=True,
                                 read_only=True)
        self.variables.add_array('_indices',
                                 size=len(self.record),
                                 dtype=self.record.dtype,
                                 constant=True,
                                 read_only=True,
                                 values=self.record)
        self.variables.create_clock_variables(self._clock, prefix='_clock_')
        for varname in variables:
            var = source.variables[varname]
            if var.scalar and len(self.record) > 1:
                logger.warn(('Variable %s is a shared variable but it will be '
                             'recorded once for every target.' % varname),
                            once=True)
            index = source.variables.indices[varname]
            self.variables.add_reference('_source_%s' % varname,
                                         source,
                                         varname,
                                         index=index)
            if not index in ('_idx', '0') and index not in variables:
                self.variables.add_reference(index, source)
            self.variables.add_dynamic_array(varname,
                                             size=(0, len(self.record)),
                                             resize_along_first=True,
                                             dimensions=var.dim,
                                             dtype=var.dtype,
                                             constant=False,
                                             read_only=True)

        for varname in variables:
            var = self.source.variables[varname]
            self.variables.add_auxiliary_variable('_to_record_' + varname,
                                                  dimensions=var.dim,
                                                  dtype=var.dtype,
                                                  scalar=var.scalar)

        self.recorded_variables = dict([(varname, self.variables[varname])
                                        for varname in variables])
        recorded_names = [varname for varname in variables]

        self.needed_variables = recorded_names
        self.template_kwds = {'_recorded_variables': self.recorded_variables}
        self.written_readonly_vars = {
            self.variables[varname]
            for varname in self.record_variables
        }
        self._enable_group_attributes()
    def __init__(self,
                 source,
                 event,
                 variables=None,
                 record=True,
                 when=None,
                 order=None,
                 name='eventmonitor*',
                 codeobj_class=None):
        if not isinstance(source, SpikeSource):
            raise TypeError(
                ('%s can only monitor groups producing spikes '
                 '(such as NeuronGroup), but the given argument '
                 'is of type %s.') % (self.__class__.__name__, type(source)))
        #: The source we are recording from
        self.source = source
        #: Whether to record times and indices of events
        self.record = record
        #: The array of event counts (length = size of target group)
        self.count = None
        del self.count  # this is handled by the Variable mechanism

        if when is None:
            if order is not None:
                raise ValueError(
                    'Cannot specify order if when is not specified.')
            if hasattr(source, 'thresholder'):
                parent_obj = source.thresholder[event]
            else:
                parent_obj = source
            when = parent_obj.when
            order = parent_obj.order + 1
        elif order is None:
            order = 0

        #: The event that we are listening to
        self.event = event

        if variables is None:
            variables = {}
        elif isinstance(variables, str):
            variables = {variables}

        #: The additional variables that will be recorded
        self.record_variables = set(variables)

        for variable in variables:
            if variable not in source.variables:
                raise ValueError(("'%s' is not a variable of the recorded "
                                  "group" % variable))

        if self.record:
            self.record_variables |= {'i', 't'}

        # Some dummy code so that code generation takes care of the indexing
        # and subexpressions
        code = [
            '_to_record_%s = _source_%s' % (v, v)
            for v in self.record_variables
        ]
        code = '\n'.join(code)

        self.codeobj_class = codeobj_class

        # Since this now works for general events not only spikes, we have to
        # pass the information about which variable to use to the template,
        # it can not longer simply refer to "_spikespace"
        eventspace_name = '_{}space'.format(event)

        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))
        source_N = getattr(source, '_source_N', len(source))

        Nameable.__init__(self, name=name)

        self.variables = Variables(self)
        self.variables.add_reference(eventspace_name, source)

        for variable in self.record_variables:
            source_var = source.variables[variable]
            self.variables.add_reference('_source_%s' % variable, source,
                                         variable)
            self.variables.add_auxiliary_variable('_to_record_%s' % variable,
                                                  dimensions=source_var.dim,
                                                  dtype=source_var.dtype)
            self.variables.add_dynamic_array(variable,
                                             size=0,
                                             dimensions=source_var.dim,
                                             dtype=source_var.dtype,
                                             read_only=True)
        self.variables.add_arange('_source_idx', size=len(source))
        self.variables.add_array('count',
                                 size=len(source),
                                 dtype=np.int32,
                                 read_only=True,
                                 index='_source_idx')
        self.variables.add_constant('_source_start', start)
        self.variables.add_constant('_source_stop', stop)
        self.variables.add_constant('_source_N', source_N)
        self.variables.add_array('N',
                                 size=1,
                                 dtype=np.int32,
                                 read_only=True,
                                 scalar=True)

        record_variables = {
            varname: self.variables[varname]
            for varname in self.record_variables
        }
        template_kwds = {
            'eventspace_variable': source.variables[eventspace_name],
            'record_variables': record_variables,
            'record': self.record
        }
        needed_variables = {eventspace_name} | self.record_variables
        CodeRunner.__init__(
            self,
            group=self,
            code=code,
            template='spikemonitor',
            name=None,  # The name has already been initialized
            clock=source.clock,
            when=when,
            order=order,
            needed_variables=needed_variables,
            template_kwds=template_kwds)

        self.variables.create_clock_variables(self._clock, prefix='_clock_')
        self.add_dependency(source)
        self.written_readonly_vars = {
            self.variables[varname]
            for varname in self.record_variables
        }
        self._enable_group_attributes()