Esempio n. 1
0
    def connect(self,
                sender,
                send_port_name,
                receive_port_name,
                delay=0.0 * un.ms,
                properties=None):
        """
        Connects a port of the cell to a matching port on the 'other' cell

        Parameters
        ----------
        sender : pype9.simulator.neuron.cells.Cell
            The sending cell to connect the from
        send_port_name : str
            Name of the port in the sending cell to connect to
        receive_port_name : str
            Name of the receive port in the current cell to connect from
        delay : nineml.Quantity (time)
            The delay of the connection
        properties : list(nineml.Property)
            The connection properties of the event port
        """
        send_port = sender.component_class.send_port(send_port_name)
        receive_port = self.component_class.receive_port(receive_port_name)
        delay = float(delay.in_units(un.ms))
        if properties is None:
            properties = []
        if send_port.communicates != receive_port.communicates:
            raise Pype9UsageError(
                "Cannot connect {} send port, '{}', to {} receive port, '{}'".
                format(send_port.communicates, send_port_name,
                       receive_port.communicates, receive_port_name))
        if receive_port.communicates == 'event':
            if len(list(self.component_class.event_receive_ports)) > 1:
                raise Pype9Unsupported9MLException(
                    "Multiple event receive ports ('{}') are not currently "
                    "supported".format("', '".join([
                        p.name
                        for p in self.component_class.event_receive_ports
                    ])))
            netcon = h.NetCon(sender._hoc, self._hoc, sec=self._sec)
            if delay:
                netcon.delay = delay
            self._check_connection_properties(receive_port_name, properties)
            if len(properties) > 1:
                raise Pype9Unsupported9MLException(
                    "Cannot handle more than one connection property per port")
            elif properties:
                netcon.weight[0] = self.unit_handler.scale_value(
                    properties[0].quantity)
            self._input_auxs.append(netcon)
        elif receive_port.communicates == 'analog':
            raise Pype9UsageError(
                "Cannot individually 'connect' analog ports. Simulate the "
                "sending cell in a separate simulation then play the analog "
                "signal in the port")
        else:
            raise Pype9UsageError(
                "Unrecognised port communication '{}'".format(
                    receive_port.communicates))
Esempio n. 2
0
 def _prepare(self, **kwargs):
     "Reset the simulation and prepare it for creating new cells/networks"
     if self._min_delay is None:
         if self.num_threads() == 1:
             min_delay = self.device_delay
         else:
             raise Pype9UsageError(
                 "Min delay needs to be set for NEST simulator if using "
                 "more than one thread")
     else:
         min_delay = self._min_delay
     if self._max_delay is None:
         if self.num_threads() == 1:
             max_delay = self.DEFAULT_MAX_DELAY
         else:
             raise Pype9UsageError(
                 "Max delay needs to be set for NEST simulator if using "
                 "more than one thread")
     else:
         max_delay = self._max_delay
     pyNN_setup(timestep=float(self.dt.in_units(un.ms)),
                min_delay=float(min_delay.in_units(un.ms)),
                max_delay=float(max_delay.in_units(un.ms)),
                grng_seed=self.global_seed,
                rng_seeds=self.all_dynamics_seeds,
                **kwargs)
Esempio n. 3
0
def parse_units(unit_str):
    # TODO: Should donate this function to the nineml.units module
    try:
        unit_expr = sympy.sympify(unit_str)
    except:
        raise Pype9UsageError(
            "Unit expression '{}' is not a valid expression".format(unit_str))
    try:
        return _parse_subexpr(unit_expr)
    except Pype9UnitStrError:
        raise Pype9UsageError(
            "Unit expression '{}' contains operators other than "
            "multiplication and division".format(unit_str))
Esempio n. 4
0
 def register_cell(self, cell):
     if cell.code_generator != self.code_generator:
         raise Pype9UsageError(
             "Equivlent code generators must be provided to both the "
             "CellMetaClass and Simulation objects ({} and {})".format(
                 cell.code_generator, self.code_generator))
     self._registered_cells.append(cell)
Esempio n. 5
0
 def register_array(self, array):
     cell_code_gen = array.celltype.model.code_generator
     if cell_code_gen != self.code_generator:
         raise Pype9UsageError(
             "Equivlent code generators must be provided to both the "
             "Network and Simulation objects ({} and {})".format(
                 cell_code_gen, self.code_generator))
     self._registered_arrays.append(array)
Esempio n. 6
0
 def _check_units(self, varname, val, dimension, allow_none=False):
     if not (val is None and allow_none):
         try:
             assert val.units.dimension == dimension
         except (AssertionError, AttributeError):
             raise Pype9UsageError(
                 "Provided value to {} ({}) is not a valid '{}' "
                 "quantity".format(varname, val, dimension.name))
Esempio n. 7
0
    def play(self, port_name, signal, properties=[]):
        """
        Injects current into the segment

        Parameters
        ----------
        port_name : str
            The name of the receive port to play the signal into
        signal : neo.AnalogSignal (current) | neo.SpikeTrain
            Signal to play into the port
        properties : list(nineml.Property)
            The connection properties of the event port
        """
        ext_is = self.build_component_class.annotations.get(
            (BUILD_TRANS, PYPE9_NS), EXTERNAL_CURRENTS).split(',')
        port = self.component_class.port(port_name)
        if isinstance(port, EventPort):
            if len(list(self.component_class.event_receive_ports)) > 1:
                raise Pype9Unsupported9MLException(
                    "Multiple event receive ports ('{}') are not currently "
                    "supported".format("', '".join([
                        p.name
                        for p in self.component_class.event_receive_ports
                    ])))
            if signal.t_start < 1.0:
                raise Pype9UsageError(
                    "Signal must start at or after 1 ms to handle delay in "
                    "neuron ({})".format(signal.t_start))
            times = numpy.asarray(signal.times.rescale(pq.ms)) - 1.0
            vstim = h.VecStim()
            vstim_times = h.Vector(times)
            vstim.play(vstim_times)
            vstim_con = h.NetCon(vstim, self._hoc, sec=self._sec)
            self._check_connection_properties(port_name, properties)
            if len(properties) > 1:
                raise NotImplementedError(
                    "Cannot handle more than one connection property per port")
            elif properties:
                vstim_con.weight[0] = self.unit_handler.scale_value(
                    properties[0].quantity)
            self._inputs['vstim'] = vstim
            self._input_auxs.extend((vstim_times, vstim_con))
        else:
            if port_name not in ext_is:
                raise Pype9Unsupported9MLException(
                    "Can only play into external current ports ('{}'), not "
                    "'{}' port.".format("', '".join(ext_is), port_name))
            iclamp = h.IClamp(0.5, sec=self._sec)
            iclamp.delay = 0.0
            iclamp.dur = 1e12
            iclamp.amp = 0.0
            iclamp_amps = h.Vector(pq.Quantity(signal, 'nA'))
            iclamp_times = h.Vector(signal.times.rescale(pq.ms))
            iclamp_amps.play(iclamp._ref_amp, iclamp_times)
            self._inputs['iclamp'] = iclamp
            self._input_auxs.extend((iclamp_amps, iclamp_times))
Esempio n. 8
0
 def activate(self):
     if self.__class__._active is not None:
         raise Pype9UsageError(
             "Cannot enter context of multiple {} simulations at the same "
             "time".format(self.__class__.name))
     self._set_seeds()
     self._running = False
     self._prepare()
     self._registered_cells = []
     self._registered_arrays = []
     self.__class__._active = self
Esempio n. 9
0
 def _get(self, varname):
     varname = self._escaped_name(varname)
     try:
         return getattr(self._hoc, varname)
     except AttributeError:
         try:
             return getattr(self._sec, varname)
         except AttributeError:
             raise Pype9UsageError(
                 "'{}' doesn't have an attribute '{}'".format(
                     self.name, varname))
Esempio n. 10
0
 def __init__(self,
              dt,
              t_start=0.0 * un.s,
              seed=None,
              properties_seed=None,
              min_delay=1 * un.ms,
              max_delay=10 * un.ms,
              code_generator=None,
              build_base_dir=None,
              **options):
     self._check_units('dt', dt, un.time)
     self._check_units('t_start', dt, un.time)
     self._check_units('min_delay', dt, un.time, allow_none=True)
     self._check_units('max_delay', dt, un.time, allow_none=True)
     self._dt = dt
     self._t_start = t_start
     self._t = t_start
     self._min_delay = min_delay if min_delay > dt else dt
     self._max_delay = max_delay if max_delay > dt else dt
     self._options = options
     self._registered_cells = None
     self._registered_arrays = None
     if seed is not None and (seed < 0 or seed > self.max_seed):
         raise Pype9UsageError(
             "Provided seed {} is out of range, must be between (0 and {})".
             format(seed, self.max_seed))
     self._base_seed = seed
     if properties_seed is not None and (properties_seed < 0 or
                                         properties_seed > self.max_seed):
         raise Pype9UsageError(
             "Provided structure seed {} is out of range, must be between "
             "(0 and {})".format(seed, self.max_seed))
     self._base_properties_seed = properties_seed
     if code_generator is None:
         code_generator = self.CodeGenerator(base_dir=build_base_dir)
     elif build_base_dir is not None:
         raise Pype9UsageError(
             "Cannot provide both code generator and 'build_base_dir' "
             "options to Simulation __init__")
     self._code_generator = code_generator
Esempio n. 11
0
 def _trim_analog_signal(self, signal, t_start, interval):
     sim_start = self.unit_handler.to_pq_quantity(self._t_start)
     offset = (t_start - sim_start)
     if offset > 0.0 * pq.s:
         offset_index = offset / interval
         if round(offset_index) != offset_index:
             raise Pype9UsageError(
                 "Difference between recording start time ({}) needs to"
                 "and simulation start time ({}) must be an integer "
                 "multiple of the sampling interval ({})".format(
                     t_start, sim_start, interval))
         signal = signal[int(offset_index):]
     return signal
Esempio n. 12
0
def _parse_subexpr(expr):
    """parse_units helper function"""
    try:
        return standard_units[str(expr)]
    except KeyError:
        if isinstance(expr, sympy.Symbol):
            raise Pype9UsageError("Unrecognised unit '{}'".format(expr))
        elif isinstance(expr, (sympy.Mul, sympy.Pow)):
            op = operator.mul if isinstance(expr, sympy.Mul) else operator.pow
            return reduce(op, (_parse_subexpr(a) for a in expr.args))
        elif isinstance(expr, sympy.Integer):
            return int(expr)
        else:
            raise Pype9UnitStrError
Esempio n. 13
0
 def set_regime(self, regime):
     if regime not in self.component_class.regime_names:
         raise Pype9UsageError(
             "'{}' is not a name of a regime in '{} cells "
             "(regimes are '{}')".format(
                 regime, self.name,
                 "', '".join(self.component_class.regime_names)))
     try:
         # If regime is an integer (as it will be when passed from PyNN)
         index = int(regime)
     except ValueError:
         # If the regime is the regime name
         index = self.regime_index(regime)
     super(Cell, self).__setattr__('_regime_index', index)
     self._set_regime()
Esempio n. 14
0
def run(argv):
    import neo
    from pype9.exceptions import Pype9UsageError
    args = argparser().parse_args(argv)
    if args.hide:
        import matplotlib  # @IgnorePep8
        matplotlib.use('Agg')  # Set to use Agg so DISPLAY is not required
    from pype9.plot import plot  # @IgnorePep8

    segments = neo.PickleIO(args.filename).read()
    if len(segments) > 1:
        raise Pype9UsageError(
            "Expected only a single recording segment in file '{}', found {}."
            .format(args.filename, len(segments)))

    seg = segments[0]
    plot(seg, dims=args.dims, show=not args.hide, resolution=args.resolution,
         save=args.save)
Esempio n. 15
0
    def _get_port_details(self, port_name):
        """
        Return the communication type of the corresponding port and its fully
        qualified name in the cell-synapse namespace (e.g. the 'spike_output'
        port in the cell namespace will be 'spike_output__cell')

        Parameters
        ----------
        port_name : str
            Name of the port or state variable

        Returns
        -------
        communicates : str
            Either 'event' or 'analog' depending on the type of port port_name
            corresponds to
        record_name : str
            Name of the port fully qualified in the joint cell-synapse
            namespace
        """
        # TODO: Need to add a check that the port was recorded
        component_class = self.celltype.model.component_class
        port = None
        for name in (port_name, port_name + '__cell'):
            try:
                port = component_class.send_port(name)
            except NineMLNameError:
                try:
                    port = component_class.state_variable(name)
                except NineMLNameError:
                    pass
        if port is None:
            raise Pype9UsageError(
                "Unknown port or state-variable '{}' for '{}' "
                "component array (available '{}').".format(
                    port_name, self.name, "', '".join(chain(
                        component_class.send_port_names,
                        component_class.sub_component(
                            'cell').send_port_names))))
        if isinstance(port, StateVariable):
            communicates = 'analog'
        else:
            communicates = port.communicates
        return communicates, port.name
Esempio n. 16
0
    def play(self, port_name, signal, properties=[]):
        """
        Injects current into the segment

        Parameters
        ----------
        port_name : str
            The name of the receive port to play the signal into
        signal : neo.AnalogSignal (current) | neo.SpikeTrain
            Signal to play into the port
        properties : list(nineml.Property)
            The connection properties of the event port
        """
        port = self.component_class.receive_port(port_name)
        if port.nineml_type in ('EventReceivePort',
                                'EventReceivePortExposure'):
            # Shift the signal times to account for the minimum delay and
            # match the NEURON implementation
            spike_times = (numpy.asarray(signal.rescale(pq.ms)) -
                           self.device_delay_ms)
            if any(spike_times <= 0.0):
                raise Pype9UsageError(
                    "Some spike times are less than device delay and so "
                    "can't be played into cell ({})".format(
                        ', '.join(spike_times < self.device_delay_ms)))
            self._inputs[port_name] = nest.Create(
                'spike_generator', 1, {'spike_times': list(spike_times)})
            syn_spec = {
                'receptor_type': self._receive_ports[port_name],
                'delay': self.device_delay_ms
            }
            self._check_connection_properties(port_name, properties)
            if len(properties) > 1:
                raise NotImplementedError(
                    "Cannot handle more than one connection property per port")
            elif properties:
                syn_spec['weight'] = self.unit_handler.scale_value(
                    properties[0].quantity)
            nest.Connect(self._inputs[port_name],
                         self._cell,
                         syn_spec=syn_spec)
        elif port.nineml_type in ('AnalogReceivePort', 'AnalogReducePort',
                                  'AnalogReceivePortExposure',
                                  'AnalogReducePortExposure'):
            # Signals are played into NEST cells include a delay (set to be the
            # minimum), which is is subtracted from the start of the signal so
            # that the effect of the signal aligns with other simulators
            t_start = (float(signal.t_start.rescale(pq.ms)) -
                       self.device_delay_ms)
            if t_start <= 0.0:
                raise Pype9UsageError(
                    "Start time of signal played into port '{}' ({}) must "
                    "be greater than device delay ({})".format(
                        port_name, signal.t_start, self.device_delay))
            step_current_params = {
                'amplitude_values':
                list(numpy.ravel(pq.Quantity(signal, 'pA'))),
                'amplitude_times':
                list(
                    numpy.ravel(numpy.asarray(signal.times.rescale(pq.ms))) -
                    self.device_delay_ms),
                'start':
                t_start,
                'stop':
                float(signal.t_stop.rescale(pq.ms))
            }
            self._inputs[port_name] = nest.Create('step_current_generator', 1,
                                                  step_current_params)
            nest.Connect(self._inputs[port_name],
                         self._cell,
                         syn_spec={
                             "receptor_type": self._receive_ports[port_name],
                             'delay': self.device_delay_ms
                         })
        else:
            raise Pype9UsageError(
                "Unrecognised port type '{}' to play signal into".format(port))
Esempio n. 17
0
    def get_v_threshold(self, dynamics_properties, port_name):
        """
        Returns the voltage threshold at which an event is emitted from the
        given event port

        Parameters
        ----------
        component_class : nineml.Dynamics
            The component class of the cell to find the v-threshold for
        port_name : str
            Name of the event send port to threshold
        """
        comp_class = (
            dynamics_properties.component_class._dynamics.substitute_aliases())
        transitions = OuputEventTransitionsFinder(
            comp_class, comp_class.event_send_port(port_name)).transitions
        assert transitions
        try:
            triggers = set(t.trigger for t in transitions)
        except AttributeError:
            raise Pype9UsageError(
                "Cannot get threshold for event port '{}' in {} as it is "
                "emitted from at least OnEvent transition ({})".format(
                    port_name, comp_class,
                    ', '.join(str(t) for t in transitions)))
        if len(triggers) > 1:
            raise Pype9UsageError(
                "Cannot get threshold for event port '{}' in {} as it is the "
                "condition from at least OnEvent transition ({})".format(
                    port_name, comp_class, ', '.join(transitions)))
        expr = next(iter(triggers)).rhs
        v = sympy.Symbol(
            self.component_class.annotations.get((BUILD_TRANS, PYPE9_NS),
                                                 MEMBRANE_VOLTAGE))
        if v not in expr.free_symbols:
            raise Pype9UsageError(
                "Trigger expression for '{}' port in {} is not an expression "
                "of membrane voltage '{}'".format(port_name, comp_class, v))
        solution = None
        if isinstance(expr, (sympy.StrictGreaterThan, sympy.StrictLessThan)):
            # Get the equation for the transition between true and false
            equality = sympy.Eq(*expr.args)
            solutions = sympy.solvers.solve(equality, v)
            if len(solutions) == 1:
                solution = solutions[0]
        if solution is None:
            raise Pype9UsageError(
                "Cannot solve threshold equation for trigger expression '{}' "
                "for '{}' (to find condition where spikes are emitted from "
                "'{}' event send port) in {} as it is not a simple inequality".
                format(expr, v, port_name, comp_class))
        values = {}
        for sym in solution.free_symbols:
            sym_str = str(sym)
            try:
                prop = dynamics_properties.property(sym_str)
            except NineMLNameError:
                try:
                    prop = comp_class.constant(sym_str)
                except NineMLNameError:
                    raise Pype9UsageError(
                        "Cannot calculated fixed value for voltage threshold "
                        "as it contains reference to {}".format(
                            comp_class.element(sym_str)))
            values[sym] = self.unit_handler.scale_value(prop.quantity)
        threshold = solution.subs(values)
        return float(threshold)
Esempio n. 18
0
 def __init__(self, *args, **kwargs):
     self._in_array = kwargs.pop('_in_array', False)
     # Flag to determine whether the cell has been initialized or not
     # (it makes a difference to how the state of the cell is updated,
     # either saved until the 'initialze' method is called or directly
     # set to the state)
     sim = self.Simulation.active()
     self._t_start = sim.t_start
     self._t_stop = None
     if self.in_array:
         for k, v in kwargs.items():
             self._set(k, v)  # Values should be in the right units.
         self._regime_index = None
     else:
         # These position arguments are a little more complex to retrieve
         # due to Python 2's restriction of **kwargs only following
         # *args.
         # Get prototype argument
         if len(args) >= 1:
             prototype = args[0]
             if 'prototype_' in kwargs:
                 raise Pype9UsageError(
                     "Cannot provide prototype as (1st) argument ({}) and "
                     "keyword arg ({})".format(prototype,
                                               kwargs['prototype_']))
         else:
             prototype = kwargs.pop('prototype_', self.component_class)
         # Get regime argument
         if len(args) >= 2:
             regime = args[1]
             if 'regime_' in kwargs:
                 raise Pype9UsageError(
                     "Cannot provide regime as (2nd) argument ({}) and "
                     "keyword arg ({})".format(regime, kwargs['regime_']))
         else:
             try:
                 regime = kwargs.pop('regime_')
             except KeyError:
                 regime = None
         if regime is None:
             if self.component_class.num_regimes == 1:
                 regime = next(self.component_class.regime_names)
             else:
                 raise Pype9UsageError(
                     "Need to specify initial regime using 'regime_' "
                     "keyword arg for component class with multiple "
                     "regimes ('{}')".format(
                         self.component_class.regime_names))
         if len(args) > 2:
             raise Pype9UsageError(
                 "Only two non-keyword arguments ('prototype_' and "
                 "'regime_' permitted in Cell __init__ (provided: {})"
                 .format(', '.join(args)))
         self.set_regime(regime)
         properties = []
         initial_values = []
         for name, qty in kwargs.items():
             if isinstance(qty, pq.Quantity):
                 qty = self.unit_handler.from_pq_quantity(qty)
             if name in self.component_class.state_variable_names:
                 initial_values.append(nineml.Initial(name, qty))
             else:
                 properties.append(nineml.Property(name, qty))
         self._nineml = nineml.DynamicsProperties(
             name=self.name + '_properties',
             definition=prototype,
             properties=properties, initial_values=initial_values,
             check_initial_values=True)
         # Set up references from parameter names to internal variables and
         # set parameters
         for p in chain(self.properties, self.initial_values):
             qty = p.quantity
             if qty.value.nineml_type != 'SingleValue':
                 raise Pype9UsageError(
                     "Only SingleValue quantities can be used to initiate "
                     "individual cell classes ({})".format(p))
             self._set(p.name, float(self.unit_handler.scale_value(qty)))
         sim.register_cell(self)
Esempio n. 19
0
 def write(self, file, **kwargs):  # @ReservedAssignment
     if self.in_array:
         raise Pype9UsageError(
             "Can only write cell properties when they are not in an "
             "array")
     self._nineml.write(file, **kwargs)
Esempio n. 20
0
def run(argv):
    """
    Runs the simulation script from the provided arguments
    """
    import nineml
    from pype9.exceptions import Pype9UsageError
    import neo.io

    args = argparser().parse_args(argv)

    time = args.time * un.ms
    timestep = args.timestep * un.ms

    if args.simulator == 'neuron':
        from pype9.simulate.neuron import Network, CellMetaClass, Simulation  # @UnusedImport @IgnorePep8
    elif args.simulator == 'nest':
        from pype9.simulate.nest import Network, CellMetaClass, Simulation  # @Reimport @IgnorePep8
    else:
        assert False

    if not args.record:
        raise Pype9UsageError(
            "No recorders set, please specify at least one with the '--record'"
            " option")

    min_delay = (float(args.min_delay[0]) * parse_units(args.min_delay[1])
                 if args.min_delay is not None else 1.0 * un.ms)

    device_delay = (float(args.device_delay[0]) *
                    parse_units(args.device_delay[1])
                    if args.device_delay is not None else None)

    # Parse record specs
    record_specs = []
    for rec in args.record:
        if len(rec) == 4:
            rec_t_start = pq.Quantity(float(rec[2]), rec[3])
        elif len(rec) == 2:
            rec_t_start = None
        else:
            raise Pype9UsageError(
                "Record options can be passed either have 2 or 4 (provided {})"
                ": PORT/STATE-VARIABLE FILENAME [T_START T_START_UNITS]")
        record_specs.append(RecordSpec(rec[0], rec[1], rec_t_start))

    # Check for clashing record paths
    record_paths = [r.fname for r in record_specs]
    for pth in record_paths:
        if record_paths.count(pth) > 1:
            raise Pype9UsageError(
                "Duplicate record paths '{}' given to separate '--record' "
                "options".format(pth))

    # For convenience
    model = args.model

    if isinstance(model, nineml.Network) and not model.num_projections:
        raise Pype9UsageError(
            "Provided network model '{}' (may have been implicitly created "
            "from complete document) does not contain any projections".format(
                model))

    if isinstance(model, nineml.Network):
        with Simulation(dt=timestep,
                        seed=args.seed,
                        properties_seed=args.properties_seed,
                        device_delay=device_delay,
                        **model.delay_limits()) as sim:
            # Construct the network
            logger.info("Constructing network")
            network = Network(model,
                              build_mode=args.build_mode,
                              build_base_dir=args.build_dir)
            logger.info("Finished constructing the '{}' network".format(
                model.name))
            for rspec in record_specs:
                pop_name, port_name = rspec.port.split('.')
                network.component_array(pop_name).record(port_name)
            logger.info("Running the simulation")
            sim.run(time)
        logger.info("Writing recorded data to file")
        for rspec in record_specs:
            pop_name, port_name = rspec.port.split('.')
            pop = network.component_array(pop_name)
            neo.PickleIO(rspec.fname).write(
                pop.recording(port_name, t_start=rspec.t_start))
    else:
        assert isinstance(model, (nineml.DynamicsProperties, nineml.Dynamics))
        # Override properties passed as options
        if args.prop:
            props_dict = dict((parm, float(val) * parse_units(unts))
                              for parm, val, unts in args.prop)
            props = nineml.DynamicsProperties(model.name + '_props', model,
                                              props_dict)
            component_class = model
        elif isinstance(model, nineml.DynamicsProperties):
            props = model
            component_class = model.component_class
        else:
            raise Pype9UsageError(
                "Specified model {} is not a dynamics properties object and "
                "no properties supplied to simulate command via --prop option".
                format(model))
        # Get the initial state
        init_state = dict((sv, float(val) * parse_units(units))
                          for sv, val, units in args.init_value)
        # Get the init_regime
        init_regime = args.init_regime
        if init_regime is None:
            if component_class.num_regimes == 1:
                # If there is only one regime it doesn't need to be specified
                init_regime = next(component_class.regimes).name
            else:
                raise Pype9UsageError(
                    "Need to specify initial regime as dynamics has more than "
                    "one '{}'".format("', '".join(
                        r.name for r in component_class.regimes)))
        # FIXME: A bit of a hack until better detection of input currents is
        #        implemented in neuron code gen.
        external_currents = []
        for port_name, _ in args.play:
            if component_class.port(port_name).dimension == un.current:
                external_currents.append(port_name)
        # Build cell class
        Cell = CellMetaClass(component_class,
                             build_mode=args.build_mode,
                             external_currents=external_currents,
                             build_version=args.build_version,
                             build_base_dir=args.build_dir)
        record_regime = False
        with Simulation(dt=timestep,
                        seed=args.seed,
                        min_delay=min_delay,
                        device_delay=device_delay,
                        build_base_dir=args.build_dir) as sim:
            # Create cell
            cell = Cell(props, regime_=init_regime, **init_state)
            # Play inputs
            for port_name, fname in args.play:
                port = component_class.receive_port(port_name)
                seg = neo.io.PickleIO(filename=fname).read()[0]
                if port.communicates == 'event':
                    signal = seg.spiketrains[0]
                else:
                    signal = seg.analogsignals[0]
                logger.info("Playing signal (t_start: {}, t_stop: {}, dt: {}) "
                            "into port '{}".format(signal.t_start,
                                                   signal.t_stop,
                                                   signal.sampling_period,
                                                   port_name))
                # Input is an event train or analog signal
                cell.play(port_name, signal)
            # Set up recorders
            for rspec in record_specs:
                if (component_class.num_regimes > 1 and component_class.port(
                        rspec.port).communicates == 'analog'):
                    record_regime = True
                cell.record(rspec.port, t_start=rspec.t_start)
            if record_regime:
                cell.record_regime()
            # Run simulation
            sim.run(time)
        # Collect data into Neo Segments
        fnames = set(r.fname for r in record_specs)
        data_segs = {}
        for fname in fnames:
            data_segs[fname] = neo.Segment(
                description="Simulation of '{}' cell".format(model.name))
        for rspec in record_specs:
            data = cell.recording(rspec.port, t_start=rspec.t_start)
            if isinstance(data, neo.AnalogSignal):
                data_segs[rspec.fname].analogsignals.append(data)
            else:
                data_segs[rspec.fname].spiketrains.append(data)
            if record_regime:
                data_segs[rspec.fname].epochs.append(cell.regime_epochs())
        # Write data to file
        for fname, data_seg in data_segs.items():
            neo.io.PickleIO(fname).write(data_seg)
    logger.info("Finished simulation of '{}' for {}".format(model.name, time))
Esempio n. 21
0
 def properties_rng(self):
     if self._properties_rng is None:
         raise Pype9UsageError(
             "Can only access rng inside simulation context")
     return self._properties_rng
Esempio n. 22
0
    def connect(self,
                sender,
                send_port_name,
                receive_port_name,
                delay=None,
                properties=None):
        """
        Connects a port of the cell to a matching port on the 'other' cell

        Parameters
        ----------
        sender : pype9.simulator.nest.cells.Cell
            The sending cell to connect the from
        send_port_name : str
            Name of the port in the sending cell to connect to
        receive_port_name : str
            Name of the receive port in the current cell to connect from
        delay : nineml.Quantity (time)
            The delay of the connection
        properties : list(nineml.Property)
            The connection properties of the event port
        """
        if delay is None:
            delay = self.device_delay
        if properties is None:
            properties = []
        delay = float(delay.in_units(un.ms))
        send_port = sender.component_class.send_port(send_port_name)
        receive_port = self.component_class.receive_port(receive_port_name)
        if send_port.communicates != receive_port.communicates:
            raise Pype9UsageError(
                "Cannot connect {} send port, '{}', to {} receive port, '{}'".
                format(send_port.communicates, send_port_name,
                       receive_port.communicates, receive_port_name))
        if receive_port.communicates == 'event':
            if self.component_class.num_event_send_ports > 1:
                raise Pype9Unsupported9MLException(
                    "Cannot currently differentiate between multiple event "
                    "send ports in NEST implementation ('{}')".format(
                        "', '".join(
                            self.component_class.event_send_port_names)))
            syn_spec = {
                'receptor_type': self._receive_ports[receive_port_name],
                'delay': delay
            }
            if len(properties) > 1:
                raise Pype9Unsupported9MLException(
                    "Cannot handle more than one connection property per port")
            elif properties:
                self._check_connection_properties(receive_port_name,
                                                  properties)
                syn_spec['weight'] = self.unit_handler.scale_value(
                    properties[0].quantity)
            nest.Connect(sender._cell, self._cell, syn_spec=syn_spec)
        elif receive_port.communicates == 'analog':
            raise Pype9UsageError(
                "Cannot individually 'connect' analog ports. Simulate the "
                "sending cell in a separate simulation then play the analog "
                "signal in the port")
        else:
            raise Pype9UsageError(
                "Unrecognised port communication '{}'".format(
                    receive_port.communicates))