def createNeurone(name, component_info, rng, parameters):
    """
    Returns daetoolsComponent object based on the supplied daetoolsComponentInfo object.
    There are some special cases which are handled individually such as:
     
     * SpikeSourcePoisson
    
    :param name: string
    :param component_info: AL Component object
    :param rng: numpy.random.RandomState object
    :param parameters: python dictionary 'name' : value
    
    :rtype: daetoolsComponent object
    :raises: RuntimeError 
    """
    neurone = None
    """
    ACHTUNG, ACHTUNG!!
    We should handle components' with names that mean something. How can we know that 
    the spike_source_poisson component should be treated differently by a simulator?
    The same stands for other types of components.
    """
    if component_info.name == 'spike_source_poisson':
        if 'rate' in parameters:
            # Create daetools quantity and scale it to 'Hz'
            rate = pyUnits.quantity(parameters['rate'][0], parameters['rate'][1]).scaleTo(pyUnits.Hz)
            #print('spike_source_poisson.rate = %s' % rate)
        else:
            raise RuntimeError('The SpikeSourcePoisson component: must have [rate] parameter')
        
        if 'duration' in parameters:
            # Create daetools quantity and scale it to 's'
            duration = pyUnits.quantity(parameters['duration'][0], parameters['duration'][1]).scaleTo(pyUnits.s)
            #print('spike_source_poisson.duration = %s' % duration)
        else:
            raise RuntimeError('The SpikeSourcePoisson component: must have [duration] parameter')
        
        if 't0' in parameters:
            # Create daetools quantity and scale it to 's'
            t0 = pyUnits.quantity(parameters['t0'][0], parameters['t0'][1]).scaleTo(pyUnits.s)
            #print('spike_source_poisson.t0 = %s' % t0)
        else:
            t0 = 0.0

        # Should be rate [Hz] * duration [s]
        lambda_ = rate.value * duration.value

        spiketimes = createPoissonSpikeTimes(rate, duration, t0, rng, lambda_, rng)
        neurone    = daetoolsSpikeSource(spiketimes, name, None, '')
    
    else:
        neurone = daetoolsComponent(component_info, fixObjectName(name), None, '')
        neurone.Nitems = 1
        neurone.initialize()
    
    spike_event_port = neurone.getOutletEventPort()
    neurone.on_spike_out_action = daetoolsOnSpikeOutAction(neurone, spike_event_port)
    neurone.ON_EVENT(spike_event_port, userDefinedActions = [neurone.on_spike_out_action])
    
    return neurone
    def createConnections(self, cgi, source_population, target_population,
                          psr_weight_units, connrule_weight_units, connrule_delay_units):
        """
        Iterates over ConnectionGeneratorInterface object and creates connections.
        It connects source->target neurones and (optionally) sets weights and delays
        
        :param cgi: ConnectionGenerator interface object
        
        :rtype: None
        :raises: RuntimeError
        """
        count = 0
        for connection in cgi:
            size = len(connection)
            if(size < 2):
                raise RuntimeError('Not enough data in the explicit lists of connections')
            
            source_index = int(connection[0])
            target_index = int(connection[1])
            weight       = 0.0
            delay        = 0.0
            parameters   = []

            # Weight and delay values are in units specified by the user in the UL component
            # Weight will be scaled to the units in the PSR component, while delay to seconds
            if cgi.arity == 1:
                weight = pyUnits.quantity(float(connection[2]), connrule_weight_units)

            elif cgi.arity >= 2:
                weight = pyUnits.quantity(float(connection[2]), connrule_weight_units)
                delay  = pyUnits.quantity(float(connection[3]), connrule_delay_units)
            
            source_neurone = source_population.getNeurone(source_index)
            target_neurone = target_population.getNeurone(target_index)
            synapse        = self.getSynapse(target_index)

            # Scale the delay to seconds
            delay_in_seconds = delay.scaleTo(pyUnits.s).value
            #print('delay_in_seconds = %f' % delay_in_seconds)

            if delay_in_seconds < self.minimal_delay:
                self.minimal_delay = delay_in_seconds
            
            # Add the new item to the list of connected synapse event ports and connection delays.
            # Here we cannot add an event port directly since it does not exist yet.
            # Therefore, we add the synapse object and the index of the event port.
            source_neurone.target_synapses.append( (synapse, synapse.Nitems, delay_in_seconds, target_neurone) )
            synapse.Nitems += 1
            
            # Weights cannot be set right now. Thus, we put them into an array.
            # Also, the units must be scaled to those specified in the PSR component
            synapse.synapse_weights.append( weight.scaleTo(psr_weight_units) )
            count += 1
        
        print('{0}: created {1} connections'.format(self.name, count))
def createNeurone(name, component_info, rng, parameters):
    """
    Returns daetoolsComponent object based on the supplied daetoolsComponentInfo object.
    There are some special cases which are handled individually such as:
     
     * SpikeSourcePoisson
    
    :param name: string
    :param component_info: AL Component object
    :param rng: numpy.random.RandomState object
    :param parameters: python dictionary 'name' : value
    
    :rtype: daetoolsComponent object
    :raises: RuntimeError 
    """
    neurone = None
    """
    ACHTUNG, ACHTUNG!!
    We should handle components' with names that mean something. How can we know that 
    the spike_source_poisson component should be treated differently by a simulator?
    The same stands for other types of components.
    """
    if component_info.name == 'spike_source_poisson':
        if 'rate' in parameters:
            # Create daetools quantity and scale it to 'Hz'
            rate = pyUnits.quantity(parameters['rate'][0],
                                    parameters['rate'][1]).scaleTo(pyUnits.Hz)
            #print('spike_source_poisson.rate = %s' % rate)
        else:
            raise RuntimeError(
                'The SpikeSourcePoisson component: must have [rate] parameter')

        if 'duration' in parameters:
            # Create daetools quantity and scale it to 's'
            duration = pyUnits.quantity(parameters['duration'][0],
                                        parameters['duration'][1]).scaleTo(
                                            pyUnits.s)
            #print('spike_source_poisson.duration = %s' % duration)
        else:
            raise RuntimeError(
                'The SpikeSourcePoisson component: must have [duration] parameter'
            )

        if 't0' in parameters:
            # Create daetools quantity and scale it to 's'
            t0 = pyUnits.quantity(parameters['t0'][0],
                                  parameters['t0'][1]).scaleTo(pyUnits.s)
            #print('spike_source_poisson.t0 = %s' % t0)
        else:
            t0 = 0.0

        # Should be rate [Hz] * duration [s]
        lambda_ = rate.value * duration.value

        spiketimes = createPoissonSpikeTimes(rate, duration, t0, rng, lambda_,
                                             rng)
        neurone = daetoolsSpikeSource(spiketimes, name, None, '')

    else:
        neurone = daetoolsComponent(component_info, fixObjectName(name), None,
                                    '')
        neurone.Nitems = 1
        neurone.initialize()

    spike_event_port = neurone.getOutletEventPort()
    neurone.on_spike_out_action = daetoolsOnSpikeOutAction(
        neurone, spike_event_port)
    neurone.ON_EVENT(spike_event_port,
                     userDefinedActions=[neurone.on_spike_out_action])

    return neurone
    def createConnections(self, cgi, source_population, target_population,
                          psr_weight_units, connrule_weight_units,
                          connrule_delay_units):
        """
        Iterates over ConnectionGeneratorInterface object and creates connections.
        It connects source->target neurones and (optionally) sets weights and delays
        
        :param cgi: ConnectionGenerator interface object
        
        :rtype: None
        :raises: RuntimeError
        """
        count = 0
        for connection in cgi:
            size = len(connection)
            if (size < 2):
                raise RuntimeError(
                    'Not enough data in the explicit lists of connections')

            source_index = int(connection[0])
            target_index = int(connection[1])
            weight = 0.0
            delay = 0.0
            parameters = []

            # Weight and delay values are in units specified by the user in the UL component
            # Weight will be scaled to the units in the PSR component, while delay to seconds
            if cgi.arity == 1:
                weight = pyUnits.quantity(float(connection[2]),
                                          connrule_weight_units)

            elif cgi.arity >= 2:
                weight = pyUnits.quantity(float(connection[2]),
                                          connrule_weight_units)
                delay = pyUnits.quantity(float(connection[3]),
                                         connrule_delay_units)

            source_neurone = source_population.getNeurone(source_index)
            target_neurone = target_population.getNeurone(target_index)
            synapse = self.getSynapse(target_index)

            # Scale the delay to seconds
            delay_in_seconds = delay.scaleTo(pyUnits.s).value
            #print('delay_in_seconds = %f' % delay_in_seconds)

            if delay_in_seconds < self.minimal_delay:
                self.minimal_delay = delay_in_seconds

            # Add the new item to the list of connected synapse event ports and connection delays.
            # Here we cannot add an event port directly since it does not exist yet.
            # Therefore, we add the synapse object and the index of the event port.
            source_neurone.target_synapses.append(
                (synapse, synapse.Nitems, delay_in_seconds, target_neurone))
            synapse.Nitems += 1

            # Weights cannot be set right now. Thus, we put them into an array.
            # Also, the units must be scaled to those specified in the PSR component
            synapse.synapse_weights.append(weight.scaleTo(psr_weight_units))
            count += 1

        print('{0}: created {1} connections'.format(self.name, count))