Example #1
0
    def _configure_history(self, initial_conditions):
        """
        Set initial conditions for the simulation using either the provided
        initial_conditions or, if none are provided, the model's initial()
        method. This method is called durin the Simulator's __init__().

        Any initial_conditions that are provided as an argument are expected
        to have dimensions 1, 2, and 3 with shapse corresponding to the number
        of state_variables, nodes and modes, respectively. If the provided
        inital_conditions are shorter in time (dim=0) than the required history
        the model's initial() method is called to make up the difference.

        """
        rng = numpy.random
        if hasattr(self.integrator, 'noise'):
            rng = self.integrator.noise.random_stream
        # Default initial conditions
        if initial_conditions is None:
            n_time, n_svar, n_node, n_mode = self.good_history_shape
            LOG.info(
                'Preparing initial history of shape %r using model.initial()',
                self.good_history_shape)
            if self.surface is not None:
                n_node = self.number_of_nodes
            history = self.model.initial(self.integrator.dt,
                                         (n_time, n_svar, n_node, n_mode), rng)
        # ICs provided
        else:
            # history should be [timepoints, state_variables, nodes, modes]
            LOG.info('Using provided initial history of shape %r',
                     initial_conditions.shape)
            n_time, n_svar, n_node, n_mode = ic_shape = initial_conditions.shape
            nr = self.connectivity.number_of_regions
            if self.surface is not None and n_node == nr:
                initial_conditions = initial_conditions[:, :, self._regmap]
                return self._configure_history(initial_conditions)
            elif ic_shape[1:] != self.good_history_shape[1:]:
                raise_value_error(
                    "Incorrect history sample shape %s, expected %s" %
                    ic_shape[1:], self.good_history_shape[1:])
            else:
                if ic_shape[0] >= self.horizon:
                    LOG.debug("Using last %d time-steps for history.",
                              self.horizon)
                    history = initial_conditions[
                        -self.horizon:, :, :, :].copy()
                else:
                    LOG.debug('Padding initial conditions with model.initial')
                    history = self.model.initial(self.integrator.dt,
                                                 self.good_history_shape, rng)
                    shift = self.current_step % self.horizon
                    history = numpy.roll(history, -shift, axis=0)
                    history[:ic_shape[0], :, :, :] = initial_conditions
                    history = numpy.roll(history, shift, axis=0)
                self.current_step += ic_shape[0] - 1
        # Make sure that history values are bounded,
        # and any possible non-state variables are initialized
        # based on state variable ones (but with no coupling yet...)
        self._update_and_bound_history(numpy.swapaxes(history, 0, 1))
        LOG.info('Final initial history shape is %r', history.shape)
        # create initial state from history
        self.current_state = history[self.current_step % self.horizon].copy()
        LOG.debug('initial state has shape %r' % (self.current_state.shape, ))
        if self.surface is not None and history.shape[
                2] > self.connectivity.number_of_regions:
            n_reg = self.connectivity.number_of_regions
            (nt, ns, _, nm), ax = history.shape, (2, 0, 1, 3)
            region_history = numpy.zeros((nt, ns, n_reg, nm))
            numpy_add_at(region_history.transpose(ax), self._regmap,
                         history.transpose(ax))
            region_history /= numpy.bincount(self._regmap).reshape((-1, 1))
            history = region_history
        # create history query implementation
        self.history = SparseHistory(self.connectivity.weights,
                                     self.connectivity.idelays,
                                     self.model.cvar,
                                     self.model.number_of_modes)
        # initialize its buffer
        self.history.initialize(history)
Example #2
0
    def config_for_sim(self, simulator):
        "Configure projection matrix monitor for given simulation."

        super(Projection, self).config_for_sim(simulator)
        self._sim = simulator
        if hasattr(self, 'sensors'):
            self.sensors.configure()

        # handle region vs simulation, analytic vs numerical proj, cortical vs subcortical.
        # setup convenient locals
        surf = simulator.surface
        conn = simulator.connectivity
        using_cortical_surface = surf is not None
        if using_cortical_surface:
            non_cortical_indices, = numpy.where(
                numpy.bincount(surf.region_mapping) == 1)
            self.rmap = surf.region_mapping
        else:
            # assume all cortical if no info
            if conn.cortical.size == 0:
                conn.cortical = numpy.array([True] * conn.weights.shape[0])
            non_cortical_indices, = numpy.where(~conn.cortical)
            if self.region_mapping is None:
                raise Exception(
                    "Please specify a region mapping on the EEG/MEG/iEEG monitor when "
                    "performing a region simulation.")
            else:
                self.rmap = self.region_mapping

            LOG.debug(
                'Projection used in region sim has %d non-cortical regions',
                non_cortical_indices.size)

        have_subcortical = len(non_cortical_indices) > 0

        # determine source space
        if using_cortical_surface:
            sources = {'loc': surf.vertices, 'ori': surf.vertex_normals}
        else:
            sources = {
                'loc': conn.centres[conn.cortical],
                'ori': conn.orientations[conn.cortical]
            }

        # compute analytic if not provided
        if self.projection is None:
            print("projection is None")
            LOG.debug(
                'Precomputed projection not unavailable using analytic approximation.'
            )
            self.gain = self.analytic(**sources)
        else:
            self.gain = self.projection.projection_data

        # reduce to region lead field if region sim
        if not using_cortical_surface and self.gain.shape[
                1] == self.rmap.mapping.size:
            gain = numpy.zeros((self.gain.shape[0], conn.number_of_regions))
            numpy_add_at(gain.T, self.rmap.mapping, self.gain.T)
            LOG.debug('Region mapping gain shape %s to %s', self.gain.shape,
                      gain.shape)
            self.gain = gain

        # append analytic sub-cortical to lead field
        if have_subcortical:
            # need matrix of shape (proj.shape[0], len(sc_ind))
            src = conn.centres[non_cortical_indices], conn.orientations[
                non_cortical_indices]
            self.gain = numpy.hstack((self.gain, self.analytic(*src)))
            LOG.debug('Added subcortical analytic gain, for final shape %s',
                      self.gain.shape)

        if self.sensors.usable is not None and not self.sensors.usable.all():
            mask_unusable = ~self.sensors.usable
            self.gain[mask_unusable] = 0.0
            LOG.debug('Zeroed gain coefficients for %d unusable sensors',
                      mask_unusable.sum())

        # unconditionally zero NaN elements; framework not prepared for NaNs.
        nan_mask = numpy.isfinite(self.gain).all(axis=1)
        self.gain[~nan_mask] = 0.0
        LOG.debug('Zeroed %d NaN gain coefficients', nan_mask.sum())

        # attrs used for recording
        self._state = numpy.zeros((self.gain.shape[0], len(self.voi)))
        self._period_in_steps = int(self.period / self.dt)
        LOG.debug('State shape %s, period in steps %s', self._state.shape,
                  self._period_in_steps)

        LOG.info('Projection configured gain shape %s', self.gain.shape)
Example #3
0
    def __call__(self, simulation_length=None, random_state=None):
        """
        When a Simulator is called it returns an iterator.

        kwargs:

        ``simulation_length``:
           total time of simulation

        ``random_state``: 
           a state for the NumPy random number generator, saved from a previous 
           call to permit consistent continuation of a simulation.

        """

        self.calls += 1
        self.simulation_length = simulation_length or self.simulation_length

        # Estimate run time and storage requirements, with logging.
        self._guesstimate_runtime()
        self._calculate_storage_requirement()

        if random_state is not None:
            if isinstance(self.integrator,
                          integrators_module.IntegratorStochastic):
                self.integrator.noise.random_stream.set_state(random_state)
                msg = "random_state supplied with seed %s"
                LOG.info(msg,
                         self.integrator.noise.random_stream.get_state()[1][0])
            else:
                LOG.warn(
                    "random_state supplied for non-stochastic integration")

        # number of steps to perform integrqtion
        int_steps = int(simulation_length / self.integrator.dt)
        msg = 'sim length %f ms requires %d steps'
        LOG.info(msg, simulation_length, int_steps)

        # locals for cleaner code.
        ncvar = len(self.model.cvar)
        number_of_regions = self.connectivity.number_of_regions

        # Exact dtypes and alignment are required by c speedups. Once we have history objects these will be encapsulated
        # cvar index array broadcastable to nodes, cvars, nodes
        cvar = numpy.array(self.model.cvar[numpy.newaxis, :, numpy.newaxis],
                           dtype=numpy.intc)
        LOG.debug("%s: cvar is: %s" % (str(self), str(cvar)))

        # idelays array broadcastable to nodes, cvars, nodes
        idelays = numpy.array(self.connectivity.idelays[:, numpy.newaxis, :],
                              dtype=numpy.intc,
                              order='c')
        LOG.debug("%s: idelays shape is: %s" % (str(self), str(idelays.shape)))

        # weights array broadcastable to nodes, cva, nodes, modes
        weights = self.connectivity.weights[:, numpy.newaxis, :, numpy.newaxis]
        LOG.debug("%s: weights shape is: %s" % (str(self), str(weights.shape)))

        # node_ids broadcastable to nodes, cvars, nodes
        node_ids = numpy.array(
            numpy.arange(number_of_regions)[numpy.newaxis, numpy.newaxis, :],
            dtype=numpy.intc)
        LOG.debug("%s: node_ids shape is: %s" %
                  (str(self), str(node_ids.shape)))

        if self.surface is None:
            local_coupling = 0.0
        else:
            (nt, ns, _, nm), ax = self.history.shape, (2, 0, 1, 3)
            region_history = numpy.zeros((nt, ns, number_of_regions, nm))
            numpy_add_at(region_history.transpose(ax), self._regmap,
                         self.history.transpose(ax))
            region_history /= numpy.bincount(self._regmap).reshape((-1, 1))
            if self.surface.coupling_strength.size == 1:
                local_coupling = (self.surface.coupling_strength[0] *
                                  self.surface.local_connectivity.matrix)
            elif self.surface.coupling_strength.size == self.surface.number_of_vertices:
                ind = numpy.arange(self.number_of_nodes, dtype=int)
                vec_cs = numpy.zeros((self.number_of_nodes, ))
                vec_cs[:self.surface.
                       number_of_vertices] = self.surface.coupling_strength
                sp_cs = sparse.csc_matrix(
                    (vec_cs, (ind, ind)),
                    shape=(self.number_of_nodes, self.number_of_nodes))
                local_coupling = sp_cs * self.surface.local_connectivity.matrix

        if self.stimulus is None:
            stimulus = 0.0
        else:
            self.stimulus.configure_time(
                numpy.r_[:simulation_length:self.integrator.dt].reshape(
                    (1, -1)))
            stimulus = numpy.zeros((self.model.nvar, self.number_of_nodes, 1))
            LOG.debug("stimulus shape is: %s", stimulus.shape)

        # initial state, history[timepoint[0], state_variables, nodes, modes]
        state = self.history[self.current_step % self.horizon, :]
        LOG.debug("state shape is: %s", state.shape)

        delayed_state = numpy.zeros(
            (number_of_regions, ncvar, number_of_regions,
             self.model.number_of_modes))

        # integration loop
        for step in xrange(self.current_step + 1,
                           self.current_step + int_steps + 1):

            # compute afferent coupling
            time_indices = (step - 1 - idelays) % self.horizon
            if self.surface is None:
                get_state(self.history,
                          time_indices,
                          cvar,
                          node_ids,
                          out=delayed_state)
                node_coupling = self.coupling(weights, state[self.model.cvar],
                                              delayed_state)
            else:
                get_state(region_history,
                          time_indices,
                          cvar,
                          node_ids,
                          out=delayed_state)
                region_coupling = self.coupling(
                    weights, region_history[(step - 1) % self.horizon,
                                            self.model.cvar], delayed_state)
                node_coupling = region_coupling[:, self._regmap].transpose(
                    (1, 0, 2))

            # stimulus pattern at this time point
            if self.stimulus is not None:
                stim_step = step - (self.current_step + 1
                                    )  # TODO stim_step != current step ??
                stimulus[self.model.cvar, :, :] = self.stimulus(
                    stim_step).reshape((1, -1, 1))

            # apply integration scheme
            state = self.integrator.scheme(state, self.model.dfun,
                                           node_coupling, local_coupling,
                                           stimulus)

            # update full history & region history if applicable
            self.history[step % self.horizon, :] = state
            if self.surface is not None:
                region_state = numpy.zeros(
                    (number_of_regions, state.shape[0], state.shape[2]))
                numpy_add_at(region_state, self._regmap,
                             state.transpose((1, 0, 2)))
                region_state /= numpy.bincount(self._regmap).reshape(
                    (-1, 1, 1))
                region_history[step %
                               self.horizon, :] = region_state.transpose(
                                   (1, 0, 2))

            # record monitor output & forward to caller
            output = [monitor.record(step, state) for monitor in self.monitors]
            if any(outputi is not None for outputi in output):
                yield output

        # This -1 is here for not repeating the point on resume
        self.current_step = self.current_step + int_steps - 1