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 before_run(self, run_namespace): if self._group.dt_ != self._stored_dt: raise NotImplementedError('The dt used for simulating %s changed ' 'after the PoissonInput source was ' 'created.' % self.group.name) CodeRunner.before_run(self, run_namespace=run_namespace)
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()