def _create_sim(self, integrator=None, inhom_mmpr=False, delays=False, run_sim=True): mpr = MontbrioPazoRoxin() conn = Connectivity.from_file() if inhom_mmpr: dispersion = 1 + np.random.randn(conn.weights.shape[0])*0.1 mpr = MontbrioPazoRoxin(eta=mpr.eta*dispersion) conn.speed = np.r_[3.0 if delays else np.inf] if integrator is None: dt = 0.01 integrator = EulerDeterministic(dt=dt) else: dt = integrator.dt sim = Simulator(connectivity=conn, model=mpr, integrator=integrator, monitors=[Raw()], simulation_length=0.1) # 10 steps sim.configure() if not delays: self.assertTrue((conn.idelays == 0).all()) buf = sim.history.buffer[...,0] # kernel has history in reverse order except 1st element 🤕 rbuf = np.concatenate((buf[0:1], buf[1:][::-1]), axis=0) state = np.transpose(rbuf, (1, 0, 2)).astype('f') self.assertEqual(state.shape[0], 2) self.assertEqual(state.shape[2], conn.weights.shape[0]) if isinstance(sim.integrator, IntegratorStochastic): sim.integrator.noise.reset_random_stream() if run_sim: (t,y), = sim.run() return sim, state, t, y else: return sim
def test_shape(self): # try to avoid introspector picking up this model Gen2D = copy.deepcopy(models.Generic2dOscillator) class CouplingShapeTestModel(Gen2D): def __init__(self, test_case=None, n_node=None, **kwds): super(CouplingShapeTestModel, self).__init__(**kwds) self.cvar = numpy.r_[0, 1] self.n_node = n_node self.test_case = test_case def dfun(self, state, coupling, local_coupling): if self.test_case is not None: self.test_case.assert_equal((2, self.n_node, 1), coupling.shape) return state conn = connectivity.Connectivity.from_file() surf = cortex.Cortex.from_file() surf.region_mapping_data.connectivity = conn sim = Simulator(model=CouplingShapeTestModel(self, surf.vertices.shape[0]), connectivity=conn, surface=surf) sim.configure() for _ in sim(simulation_length=sim.integrator.dt * 2): pass
def _prep_sim(self, coupling) -> Simulator: "Prepare simulator for testing a coupling function." con = Connectivity.from_file() con.weights[:] = 1.0 # con = Connectivity( # region_labels=np.array(['']), # weights=con.weights[:5][:,:5], # tract_lengths=con.tract_lengths[:5][:,:5], # speed=np.array([10.0]), # centres=np.array([0.0])) sim = Simulator(connectivity=con, model=LinearModel(gamma=np.r_[0.0]), coupling=coupling, integrator=Identity(dt=1.0), monitors=[Raw()], simulation_length=0.5) sim.configure() return sim
class TestsExactPropagation(BaseTestCase): def build_simulator(self, n=4): self.conn = numpy.zeros((n, n)) # , numpy.int32) for i in range(self.conn.shape[0] - 1): self.conn[i, i + 1] = 1 self.dist = numpy.r_[:n * n].reshape((n, n)) self.dist = numpy.array(self.dist, dtype=float) self.sim = Simulator( conduction_speed=1.0, coupling=IdCoupling(), surface=None, stimulus=None, integrator=Identity(dt=1.0), initial_conditions=numpy.ones((n * n, 1, n, 1)), simulation_length=10.0, connectivity=Connectivity(region_labels=numpy.array(['']), weights=self.conn, tract_lengths=self.dist, speed=numpy.array([1.0]), centres=numpy.array([0.0])), model=Sum(), monitors=(Raw(), ), ) self.sim.configure() def test_propagation(self): n = 4 self.build_simulator(n=n) # x = numpy.zeros((n, )) xs = [] for (t, raw), in self.sim(simulation_length=10): xs.append(raw.flat[:].copy()) xs = numpy.array(xs) xs_ = numpy.array([[2., 2., 2., 1.], [3., 3., 3., 1.], [5., 4., 4., 1.], [8., 5., 5., 1.], [12., 6., 6., 1.], [17., 7., 7., 1.], [23., 8., 8., 1.], [30., 10., 9., 1.], [38., 13., 10., 1.], [48., 17., 11., 1.]]) assert numpy.allclose(xs, xs_)
def main_example(tvb_sim_model, connectivity_zip=CONFIGURED.DEFAULT_CONNECTIVITY_ZIP, dt=0.1, noise_strength=0.001, simulation_length=100.0, config=CONFIGURED): plotter = Plotter(config) # --------------------------------------1. Load TVB connectivity---------------------------------------------------- connectivity = Connectivity.from_file(connectivity_zip) connectivity.configure() plotter.plot_tvb_connectivity(connectivity) # ----------------------2. Define a TVB simulator (model, integrator, monitors...)---------------------------------- # Create a TVB simulator and set all desired inputs # (connectivity, model, surface, stimuli etc) # We choose all defaults in this example simulator = Simulator() simulator.integrator = HeunStochastic(dt=dt) simulator.integrator.noise.nsig = np.array(ensure_list(noise_strength)) simulator.model = tvb_sim_model simulator.connectivity = connectivity mon_raw = Raw(period=simulator.integrator.dt) simulator.monitors = (mon_raw, ) # -----------------------------------3. Simulate and gather results------------------------------------------------- # Configure the simulator with the TVB-NEST interface... # simulator.configure(tvb_nest_interface=tvb_nest_model) simulator.configure() # ...and simulate! t_start = time.time() results = simulator.run(simulation_length=simulation_length) print("\nSimulated in %f secs!" % (time.time() - t_start)) # -------------------------------------------6. Plot results-------------------------------------------------------- plot_results(results, simulator, None, "State Variables", simulator.model.variables_of_interest, plotter) return connectivity, results
class SimulatorAdapter(ABCAsynchronous): """ Interface between the Simulator and the Framework. """ _ui_name = "Simulation Core" algorithm = None available_models = get_traited_subclasses(Model) available_monitors = get_traited_subclasses(Monitor) available_integrators = get_traited_subclasses(Integrator) available_couplings = get_traited_subclasses(Coupling) # This is a list with the monitors that actually return multi dimensions for the state variable dimension. # We exclude from this for example EEG, MEG or Bold which return HAVE_STATE_VARIABLES = ["GlobalAverage", "SpatialAverage", "Raw", "SubSample", "TemporalAverage"] def __init__(self): super(SimulatorAdapter, self).__init__() self.log.debug("%s: Initialized..." % str(self)) def get_input_tree2(self): sim = Simulator() sim.trait.bound = self.INTERFACE_ATTRIBUTES_ONLY result = sim.interface_experimental return result def get_input_tree(self): """ Return a list of lists describing the interface to the simulator. This is used by the GUI to generate the menus and fields necessary for defining a simulation. """ sim = Simulator() sim.trait.bound = self.INTERFACE_ATTRIBUTES_ONLY result = sim.interface[self.INTERFACE_ATTRIBUTES] # We should add as hidden the Simulator State attribute. result.append({self.KEY_NAME: 'simulation_state', self.KEY_TYPE: 'tvb.datatypes.simulation_state.SimulationState', self.KEY_LABEL: "Continuation of", self.KEY_REQUIRED: False, self.KEY_UI_HIDE: True}) return result def get_output(self): """ :returns: list of classes for possible results of the Simulator. """ return [time_series.TimeSeries] def configure(self, model, model_parameters, integrator, integrator_parameters, connectivity, monitors, monitors_parameters=None, surface=None, surface_parameters=None, stimulus=None, coupling=None, coupling_parameters=None, initial_conditions=None, conduction_speed=None, simulation_length=0, simulation_state=None): """ Make preparations for the adapter launch. """ self.log.debug("available_couplings: %s..." % str(self.available_couplings)) self.log.debug("coupling: %s..." % str(coupling)) self.log.debug("coupling_parameters: %s..." % str(coupling_parameters)) self.log.debug("%s: Initializing Model..." % str(self)) noise_framework.build_noise(model_parameters) model_instance = self.available_models[str(model)](**model_parameters) self._validate_model_parameters(model_instance, connectivity, surface) self.log.debug("%s: Initializing Integration scheme..." % str(self)) noise_framework.build_noise(integrator_parameters) integr = self.available_integrators[integrator](**integrator_parameters) self.log.debug("%s: Instantiating Monitors..." % str(self)) monitors_list = [] for monitor_name in monitors: if (monitors_parameters is not None) and (str(monitor_name) in monitors_parameters): current_monitor_parameters = monitors_parameters[str(monitor_name)] HRFKernelEquation.build_equation_from_dict('hrf_kernel', current_monitor_parameters, True) monitors_list.append(self.available_monitors[str(monitor_name)](**current_monitor_parameters)) else: ### We have monitors without any UI settable parameter. monitors_list.append(self.available_monitors[str(monitor_name)]()) if len(monitors) < 1: raise LaunchException("Can not launch operation without monitors selected !!!") self.log.debug("%s: Initializing Coupling..." % str(self)) coupling_inst = self.available_couplings[str(coupling)](**coupling_parameters) self.log.debug("Initializing Cortex...") if self._is_surface_simulation(surface, surface_parameters): cortex_entity = Cortex(use_storage=False).populate_cortex(surface, surface_parameters) if cortex_entity.region_mapping_data.connectivity.number_of_regions != connectivity.number_of_regions: raise LaunchException("Incompatible RegionMapping -- Connectivity !!") if cortex_entity.region_mapping_data.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException("Incompatible RegionMapping -- Surface !!") select_loc_conn = cortex_entity.local_connectivity if select_loc_conn is not None and select_loc_conn.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException("Incompatible LocalConnectivity -- Surface !!") else: cortex_entity = None self.log.debug("%s: Instantiating requested simulator..." % str(self)) if conduction_speed not in (0.0, None): connectivity.speed = numpy.array([conduction_speed]) else: raise LaunchException("conduction speed cannot be 0 or missing") self.algorithm = Simulator(connectivity=connectivity, coupling=coupling_inst, surface=cortex_entity, stimulus=stimulus, model=model_instance, integrator=integr, monitors=monitors_list, initial_conditions=initial_conditions, conduction_speed=conduction_speed) self.simulation_length = simulation_length self.log.debug("%s: Initializing storage..." % str(self)) try: self.algorithm.preconfigure() except ValueError as err: raise LaunchException("Failed to configure simulator due to invalid Input Values. It could be because " "of an incompatibility between different version of TVB code.", err) def get_required_memory_size(self, **kwargs): """ Return the required memory to run this algorithm. """ return self.algorithm.memory_requirement() def get_required_disk_size(self, **kwargs): """ Return the required disk size this algorithm estimates it will take. (in kB) """ return self.algorithm.storage_requirement(self.simulation_length) / 2 ** 10 def get_execution_time_approximation(self, **kwargs): """ Method should approximate based on input arguments, the time it will take for the operation to finish (in seconds). """ # This is just a brute approx so cluster nodes won't kill operation before # it's finished. This should be done with a higher grade of sensitivity # Magic number connecting simulation length to simulation computation time # This number should as big as possible, as long as it is still realistic, to magic_number = 6.57e-06 # seconds approx_number_of_nodes = 500 approx_nvar = 15 approx_modes = 15 simulation_length = int(float(kwargs['simulation_length'])) approx_integrator_dt = float(kwargs['integrator_parameters']['dt']) if approx_integrator_dt == 0.0: approx_integrator_dt = 1.0 if 'surface' in kwargs and kwargs['surface'] is not None and kwargs['surface'] != '': approx_number_of_nodes *= approx_number_of_nodes estimation = magic_number * approx_number_of_nodes * approx_nvar * approx_modes * simulation_length \ / approx_integrator_dt return max(int(estimation), 1) def _try_find_mapping(self, mapping_class, connectivity_gid): """ Try to find a DataType instance of class "mapping_class", linked to the given Connectivity. Entities in the current project will have priority. :param mapping_class: DT class, with field "_connectivity" on it :param connectivity_gid: GUID :return: None or instance of "mapping_class" """ dts_list = dao.get_generic_entity(mapping_class, connectivity_gid, '_connectivity') if len(dts_list) < 1: return None for dt in dts_list: dt_operation = dao.get_operation_by_id(dt.fk_from_operation) if dt_operation.fk_launched_in == self.current_project_id: return dt return dts_list[0] def launch(self, model, model_parameters, integrator, integrator_parameters, connectivity, monitors, monitors_parameters=None, surface=None, surface_parameters=None, stimulus=None, coupling=None, coupling_parameters=None, initial_conditions=None, conduction_speed=None, simulation_length=0, simulation_state=None): """ Called from the GUI to launch a simulation. *: string class name of chosen model, etc... *_parameters: dictionary of parameters for chosen model, etc... connectivity: tvb.datatypes.connectivity.Connectivity object. surface: tvb.datatypes.surfaces.CorticalSurface: or None. stimulus: tvb.datatypes.patters.* object """ result_datatypes = dict() start_time = self.algorithm.current_step * self.algorithm.integrator.dt self.algorithm.configure(full_configure=False) if simulation_state is not None: simulation_state.fill_into(self.algorithm) region_map = self._try_find_mapping(region_mapping.RegionMapping, connectivity.gid) region_volume_map = self._try_find_mapping(region_mapping.RegionVolumeMapping, connectivity.gid) for monitor in self.algorithm.monitors: m_name = monitor.__class__.__name__ ts = monitor.create_time_series(self.storage_path, connectivity, surface, region_map, region_volume_map) self.log.debug("Monitor %s created the TS %s" % (m_name, ts)) # Now check if the monitor will return results for each state variable, in which case store # the labels for these state variables. # todo move these into monitors as well # and replace check if ts.user_tag_1 with something better (e.g. pre_ex & post) state_variable_dimension_name = ts.labels_ordering[1] if ts.user_tag_1: ts.labels_dimensions[state_variable_dimension_name] = ts.user_tag_1.split(';') elif m_name in self.HAVE_STATE_VARIABLES: selected_vois = [self.algorithm.model.variables_of_interest[idx] for idx in monitor.voi] ts.labels_dimensions[state_variable_dimension_name] = selected_vois ts.start_time = start_time result_datatypes[m_name] = ts #### Create Simulator State entity and persist it in DB. H5 file will be empty now. if not self._is_group_launch(): simulation_state = SimulationState(storage_path=self.storage_path) self._capture_operation_results([simulation_state]) ### Run simulation self.log.debug("%s: Starting simulation..." % str(self)) for result in self.algorithm(simulation_length=simulation_length): for j, monitor in enumerate(monitors): if result[j] is not None: result_datatypes[monitor].write_time_slice([result[j][0]]) result_datatypes[monitor].write_data_slice([result[j][1]]) self.log.debug("%s: Completed simulation, starting to store simulation state " % str(self)) ### Populate H5 file for simulator state. This step could also be done while running sim, in background. if not self._is_group_launch(): simulation_state.populate_from(self.algorithm) self._capture_operation_results([simulation_state]) self.log.debug("%s: Simulation state persisted, returning results " % str(self)) final_results = [] for result in result_datatypes.values(): result.close_file() final_results.append(result) self.log.info("%s: Adapter simulation finished!!" % str(self)) return final_results def _validate_model_parameters(self, model_instance, connectivity, surface): """ Checks if the size of the model parameters is set correctly. """ ui_configurable_params = model_instance.ui_configurable_parameters for param in ui_configurable_params: param_value = eval('model_instance.' + param) if isinstance(param_value, numpy.ndarray): if len(param_value) == 1 or connectivity is None: continue if surface is not None: if (len(param_value) != surface.number_of_vertices and len(param_value) != connectivity.number_of_regions): msg = str(surface.number_of_vertices) + ' or ' + str(connectivity.number_of_regions) msg = self._get_exception_message(param, msg, len(param_value)) self.log.error(msg) raise LaunchException(msg) elif len(param_value) != connectivity.number_of_regions: msg = self._get_exception_message(param, connectivity.number_of_regions, len(param_value)) self.log.error(msg) raise LaunchException(msg) @staticmethod def _get_exception_message(param_name, expected_size, actual_size): """ Creates the message that will be displayed to the user when the size of a model parameter is incorrect. """ msg = "The length of the parameter '" + param_name + "' is not correct." msg += " It is expected to be an array of length " + str(expected_size) + "." msg += " It is an array of length " + str(actual_size) + "." return msg @staticmethod def _is_surface_simulation(surface, surface_parameters): """ Is this a surface simulation? """ return surface is not None and surface_parameters is not None
class SimulatorAdapter(ABCAsynchronous): """ Interface between the Simulator and the Framework. """ _ui_name = "Simulation Core" algorithm = None available_models = get_traited_subclasses(Model) available_monitors = get_traited_subclasses(Monitor) available_integrators = get_traited_subclasses(Integrator) available_couplings = get_traited_subclasses(Coupling) # This is a list with the monitors that actually return multi dimensions for the state variable dimension. # We exclude from this for example EEG, MEG or Bold which return HAVE_STATE_VARIABLES = [ "GlobalAverage", "SpatialAverage", "Raw", "SubSample", "TemporalAverage" ] def __init__(self): super(SimulatorAdapter, self).__init__() self.log.debug("%s: Initialized..." % str(self)) def get_input_tree2(self): sim = Simulator() sim.trait.bound = self.INTERFACE_ATTRIBUTES_ONLY result = sim.interface_experimental return result def get_input_tree(self): """ Return a list of lists describing the interface to the simulator. This is used by the GUI to generate the menus and fields necessary for defining a simulation. """ sim = Simulator() sim.trait.bound = self.INTERFACE_ATTRIBUTES_ONLY result = sim.interface[self.INTERFACE_ATTRIBUTES] # We should add as hidden the Simulator State attribute. result.append({ self.KEY_NAME: 'simulation_state', self.KEY_TYPE: 'tvb.datatypes.simulation_state.SimulationState', self.KEY_LABEL: "Continuation of", self.KEY_REQUIRED: False, self.KEY_UI_HIDE: True }) return result def get_output(self): """ :returns: list of classes for possible results of the Simulator. """ return [time_series.TimeSeries] def configure(self, model, model_parameters, integrator, integrator_parameters, connectivity, monitors, monitors_parameters=None, surface=None, surface_parameters=None, stimulus=None, coupling=None, coupling_parameters=None, initial_conditions=None, conduction_speed=None, simulation_length=0, simulation_state=None): """ Make preparations for the adapter launch. """ self.log.debug("available_couplings: %s..." % str(self.available_couplings)) self.log.debug("coupling: %s..." % str(coupling)) self.log.debug("coupling_parameters: %s..." % str(coupling_parameters)) self.log.debug("%s: Initializing Model..." % str(self)) noise_framework.build_noise(model_parameters) model_instance = self.available_models[str(model)](**model_parameters) self._validate_model_parameters(model_instance, connectivity, surface) self.log.debug("%s: Initializing Integration scheme..." % str(self)) noise_framework.build_noise(integrator_parameters) integr = self.available_integrators[integrator]( **integrator_parameters) self.log.debug("%s: Instantiating Monitors..." % str(self)) monitors_list = [] for monitor_name in monitors: if (monitors_parameters is not None) and (str(monitor_name) in monitors_parameters): current_monitor_parameters = monitors_parameters[str( monitor_name)] HRFKernelEquation.build_equation_from_dict( 'hrf_kernel', current_monitor_parameters, True) monitors_list.append( self.available_monitors[str(monitor_name)]( **current_monitor_parameters)) else: ### We have monitors without any UI settable parameter. monitors_list.append( self.available_monitors[str(monitor_name)]()) if len(monitors) < 1: raise LaunchException( "Can not launch operation without monitors selected !!!") self.log.debug("%s: Initializing Coupling..." % str(self)) coupling_inst = self.available_couplings[str(coupling)]( **coupling_parameters) self.log.debug("Initializing Cortex...") if self._is_surface_simulation(surface, surface_parameters): cortex_entity = Cortex(use_storage=False).populate_cortex( surface, surface_parameters) if cortex_entity.region_mapping_data.connectivity.number_of_regions != connectivity.number_of_regions: raise LaunchException( "Incompatible RegionMapping -- Connectivity !!") if cortex_entity.region_mapping_data.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException( "Incompatible RegionMapping -- Surface !!") select_loc_conn = cortex_entity.local_connectivity if select_loc_conn is not None and select_loc_conn.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException( "Incompatible LocalConnectivity -- Surface !!") else: cortex_entity = None self.log.debug("%s: Instantiating requested simulator..." % str(self)) if conduction_speed not in (0.0, None): connectivity.speed = numpy.array([conduction_speed]) else: raise LaunchException("conduction speed cannot be 0 or missing") self.algorithm = Simulator(connectivity=connectivity, coupling=coupling_inst, surface=cortex_entity, stimulus=stimulus, model=model_instance, integrator=integr, monitors=monitors_list, initial_conditions=initial_conditions, conduction_speed=conduction_speed) self.simulation_length = simulation_length self.log.debug("%s: Initializing storage..." % str(self)) try: self.algorithm.preconfigure() except ValueError as err: raise LaunchException( "Failed to configure simulator due to invalid Input Values. It could be because " "of an incompatibility between different version of TVB code.", err) def get_required_memory_size(self, **kwargs): """ Return the required memory to run this algorithm. """ return self.algorithm.memory_requirement() def get_required_disk_size(self, **kwargs): """ Return the required disk size this algorithm estimates it will take. (in kB) """ return self.algorithm.storage_requirement( self.simulation_length) / 2**10 def get_execution_time_approximation(self, **kwargs): """ Method should approximate based on input arguments, the time it will take for the operation to finish (in seconds). """ # This is just a brute approx so cluster nodes won't kill operation before # it's finished. This should be done with a higher grade of sensitivity # Magic number connecting simulation length to simulation computation time # This number should as big as possible, as long as it is still realistic, to magic_number = 6.57e-06 # seconds approx_number_of_nodes = 500 approx_nvar = 15 approx_modes = 15 simulation_length = int(float(kwargs['simulation_length'])) approx_integrator_dt = float(kwargs['integrator_parameters']['dt']) if approx_integrator_dt == 0.0: approx_integrator_dt = 1.0 if 'surface' in kwargs and kwargs[ 'surface'] is not None and kwargs['surface'] != '': approx_number_of_nodes *= approx_number_of_nodes estimation = magic_number * approx_number_of_nodes * approx_nvar * approx_modes * simulation_length \ / approx_integrator_dt return max(int(estimation), 1) def _try_find_mapping(self, mapping_class, connectivity_gid): """ Try to find a DataType instance of class "mapping_class", linked to the given Connectivity. Entities in the current project will have priority. :param mapping_class: DT class, with field "_connectivity" on it :param connectivity_gid: GUID :return: None or instance of "mapping_class" """ dts_list = dao.get_generic_entity(mapping_class, connectivity_gid, '_connectivity') if len(dts_list) < 1: return None for dt in dts_list: dt_operation = dao.get_operation_by_id(dt.fk_from_operation) if dt_operation.fk_launched_in == self.current_project_id: return dt return dts_list[0] def launch(self, model, model_parameters, integrator, integrator_parameters, connectivity, monitors, monitors_parameters=None, surface=None, surface_parameters=None, stimulus=None, coupling=None, coupling_parameters=None, initial_conditions=None, conduction_speed=None, simulation_length=0, simulation_state=None): """ Called from the GUI to launch a simulation. *: string class name of chosen model, etc... *_parameters: dictionary of parameters for chosen model, etc... connectivity: tvb.datatypes.connectivity.Connectivity object. surface: tvb.datatypes.surfaces.CorticalSurface: or None. stimulus: tvb.datatypes.patters.* object """ result_datatypes = dict() start_time = self.algorithm.current_step * self.algorithm.integrator.dt self.algorithm.configure(full_configure=False) if simulation_state is not None: simulation_state.fill_into(self.algorithm) region_map = self._try_find_mapping(region_mapping.RegionMapping, connectivity.gid) region_volume_map = self._try_find_mapping( region_mapping.RegionVolumeMapping, connectivity.gid) for monitor in self.algorithm.monitors: m_name = monitor.__class__.__name__ ts = monitor.create_time_series(self.storage_path, connectivity, surface, region_map, region_volume_map) self.log.debug("Monitor %s created the TS %s" % (m_name, ts)) # Now check if the monitor will return results for each state variable, in which case store # the labels for these state variables. # todo move these into monitors as well # and replace check if ts.user_tag_1 with something better (e.g. pre_ex & post) state_variable_dimension_name = ts.labels_ordering[1] if ts.user_tag_1: ts.labels_dimensions[ state_variable_dimension_name] = ts.user_tag_1.split(';') elif m_name in self.HAVE_STATE_VARIABLES: selected_vois = [ self.algorithm.model.variables_of_interest[idx] for idx in monitor.voi ] ts.labels_dimensions[ state_variable_dimension_name] = selected_vois ts.start_time = start_time result_datatypes[m_name] = ts #### Create Simulator State entity and persist it in DB. H5 file will be empty now. if not self._is_group_launch(): simulation_state = SimulationState(storage_path=self.storage_path) self._capture_operation_results([simulation_state]) ### Run simulation self.log.debug("%s: Starting simulation..." % str(self)) for result in self.algorithm(simulation_length=simulation_length): for j, monitor in enumerate(monitors): if result[j] is not None: result_datatypes[monitor].write_time_slice([result[j][0]]) result_datatypes[monitor].write_data_slice([result[j][1]]) self.log.debug( "%s: Completed simulation, starting to store simulation state " % str(self)) ### Populate H5 file for simulator state. This step could also be done while running sim, in background. if not self._is_group_launch(): simulation_state.populate_from(self.algorithm) self._capture_operation_results([simulation_state]) self.log.debug("%s: Simulation state persisted, returning results " % str(self)) final_results = [] for result in result_datatypes.values(): result.close_file() final_results.append(result) self.log.info("%s: Adapter simulation finished!!" % str(self)) return final_results def _validate_model_parameters(self, model_instance, connectivity, surface): """ Checks if the size of the model parameters is set correctly. """ ui_configurable_params = model_instance.ui_configurable_parameters for param in ui_configurable_params: param_value = eval('model_instance.' + param) if isinstance(param_value, numpy.ndarray): if len(param_value) == 1 or connectivity is None: continue if surface is not None: if (len(param_value) != surface.number_of_vertices and len(param_value) != connectivity.number_of_regions): msg = str(surface.number_of_vertices) + ' or ' + str( connectivity.number_of_regions) msg = self._get_exception_message( param, msg, len(param_value)) self.log.error(msg) raise LaunchException(msg) elif len(param_value) != connectivity.number_of_regions: msg = self._get_exception_message( param, connectivity.number_of_regions, len(param_value)) self.log.error(msg) raise LaunchException(msg) @staticmethod def _get_exception_message(param_name, expected_size, actual_size): """ Creates the message that will be displayed to the user when the size of a model parameter is incorrect. """ msg = "The length of the parameter '" + param_name + "' is not correct." msg += " It is expected to be an array of length " + str( expected_size) + "." msg += " It is an array of length " + str(actual_size) + "." return msg @staticmethod def _is_surface_simulation(surface, surface_parameters): """ Is this a surface simulation? """ return surface is not None and surface_parameters is not None
class SimulatorAdapter(ABCAsynchronous): """ Interface between the Simulator and the Framework. """ _ui_name = "Simulation Core" algorithm = None available_models = get_traited_subclasses(Model) available_monitors = get_traited_subclasses(Monitor) available_integrators = get_traited_subclasses(Integrator) available_couplings = get_traited_subclasses(Coupling) ### Info: This are the possible results returned with this adapter from different Monitors. ### When a list appears(surface & region), we actually return only one based on param surface being None or not. # MONITOR_RESULTS = {"Raw": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface], # "SubSample": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface], # "SpatialAverage": time_series.TimeSeries, # "GlobalAverage": time_series.TimeSeries, # "TemporalAverage": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface], # "EEG": time_series.TimeSeriesEEG, # "SphericalEEG": time_series.TimeSeriesEEG, # "SphericalMEG": time_series.TimeSeriesMEG, # "Bold": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface]} RESULTS_MAP = {time_series.TimeSeriesEEG: ["SphericalEEG", "EEG"], time_series.TimeSeriesMEG: ["SphericalMEG"], # Add here also "MEG" monitor reference time_series.TimeSeries: ["GlobalAverage", "SpatialAverage"], time_series.TimeSeriesSEEG: ["SEEG"]} # time_series.TimeSeriesVolume: ["Bold"], #SK: For a number of reasons, it's probably best to avoid returning TimeSeriesVolume , # from a simulation directly, instead just stick with the source, i.e. Region and Surface, # then later we can add a voxelisation "analyser" to produce TimeSeriesVolume on which Volume # based analysers and visualisers (which don't exist yet) can operate. # This is a list with the monitors that actually return multi dimensions for the state variable dimension. # We exclude from this for example EEG, MEG or Bold which return HAVE_STATE_VARIABLES = ["GlobalAverage", "SpatialAverage", "Raw", "SubSample", "TemporalAverage"] def __init__(self): super(SimulatorAdapter, self).__init__() self.log.debug("%s: Initialized..." % str(self)) def get_input_tree(self): """ Return a list of lists describing the interface to the simulator. This is used by the GUI to generate the menus and fields necessary for defining a simulation. """ sim = Simulator() sim.trait.bound = self.INTERFACE_ATTRIBUTES_ONLY result = sim.interface[self.INTERFACE_ATTRIBUTES] # We should add as hidden the Simulator State attribute. result.append({self.KEY_NAME: 'simulation_state', self.KEY_TYPE: SimulationState, self.KEY_LABEL: "Continuation of", self.KEY_REQUIRED: False, self.KEY_UI_HIDE: True}) return result def get_output(self): """ :returns: list of classes for possible results of the Simulator. """ return [time_series.TimeSeries] def configure(self, model, model_parameters, integrator, integrator_parameters, connectivity, monitors, monitors_parameters=None, surface=None, surface_parameters=None, stimulus=None, coupling=None, coupling_parameters=None, initial_conditions=None, conduction_speed=None, simulation_length=0, simulation_state=None): """ Make preparations for the adapter launch. """ self.log.debug("available_couplings: %s..." % str(self.available_couplings)) self.log.debug("coupling: %s..." % str(coupling)) self.log.debug("coupling_parameters: %s..." % str(coupling_parameters)) self.log.debug("%s: Initializing Model..." % str(self)) noise_framework.build_noise(model_parameters) model_instance = self.available_models[str(model)](**model_parameters) self._validate_model_parameters(model_instance, connectivity, surface) self.log.debug("%s: Initializing Integration scheme..." % str(self)) noise_framework.build_noise(integrator_parameters) integr = self.available_integrators[integrator](**integrator_parameters) self.log.debug("%s: Instantiating Monitors..." % str(self)) monitors_list = [] for monitor_name in monitors: if (monitors_parameters is not None) and (str(monitor_name) in monitors_parameters): current_monitor_parameters = monitors_parameters[str(monitor_name)] HRFKernelEquation.build_equation_from_dict('hrf_kernel', current_monitor_parameters, True) monitors_list.append(self.available_monitors[str(monitor_name)](**current_monitor_parameters)) else: ### We have monitors without any UI settable parameter. monitors_list.append(self.available_monitors[str(monitor_name)]()) if len(monitors) < 1: raise LaunchException("Can not launch operation without monitors selected !!!") self.log.debug("%s: Initializing Coupling..." % str(self)) coupling_inst = self.available_couplings[str(coupling)](**coupling_parameters) self.log.debug("Initializing Cortex...") if self._is_surface_simulation(surface, surface_parameters): cortex_entity = Cortex(use_storage=False).populate_cortex(surface, surface_parameters) if cortex_entity.region_mapping_data.connectivity.number_of_regions != connectivity.number_of_regions: raise LaunchException("Incompatible RegionMapping -- Connectivity !!") if cortex_entity.region_mapping_data.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException("Incompatible RegionMapping -- Surface !!") select_loc_conn = cortex_entity.local_connectivity if select_loc_conn is not None and select_loc_conn.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException("Incompatible LocalConnectivity -- Surface !!") else: cortex_entity = None self.log.debug("%s: Instantiating requested simulator..." % str(self)) connectivity.configure() self.algorithm = Simulator(connectivity=connectivity, coupling=coupling_inst, surface=cortex_entity, stimulus=stimulus, model=model_instance, integrator=integr, monitors=monitors_list, initial_conditions=initial_conditions, conduction_speed=conduction_speed) self.simulation_length = simulation_length self.log.debug("%s: Initializing storage..." % str(self)) try: self.algorithm.configure() if simulation_state is not None: simulation_state.fill_into(self.algorithm) except ValueError, err: raise LaunchException("Failed to configure simulator due to invalid Input Values. It could be because " "of an incompatibility between different version of TVB code.", err)
class SimulatorAdapter(ABCAsynchronous): """ Interface between the Simulator and the Framework. """ _ui_name = "Simulation Core" algorithm = None available_models = get_traited_subclasses(Model) available_monitors = get_traited_subclasses(Monitor) available_integrators = get_traited_subclasses(Integrator) available_couplings = get_traited_subclasses(Coupling) available_noise = get_traited_subclasses(Noise) ### Info: This are the possible results returned with this adapter from different Monitors. ### When a list appears(surface & region), we actually return only one based on param surface being None or not. # MONITOR_RESULTS = {"Raw": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface], # "SubSample": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface], # "SpatialAverage": time_series.TimeSeries, # "GlobalAverage": time_series.TimeSeries, # "TemporalAverage": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface], # "EEG": time_series.TimeSeriesEEG, # "SphericalEEG": time_series.TimeSeriesEEG, # "SphericalMEG": time_series.TimeSeriesMEG, # "Bold": [time_series.TimeSeriesRegion, time_series.TimeSeriesSurface]} RESULTS_MAP = {time_series.TimeSeriesEEG: ["SphericalEEG", "EEG"], time_series.TimeSeriesMEG: ["SphericalMEG"], # Add here also "MEG" monitor reference time_series.TimeSeries: ["GlobalAverage", "SpatialAverage"]} # time_series.TimeSeriesVolume: ["Bold"], #SK: For a number of reasons, it's probably best to avoid returning TimeSeriesVolume , # from a simulation directly, instead just stick with the source, i.e. Region and Surface, # then later we can add a voxelisation "analyser" to produce TimeSeriesVolume on which Volume # based analysers and visualisers (which don't exist yet) can operate. # This is a list with the monitors that actually return multi dimensions for the state variable dimension. # We exclude from this for example EEG, MEG or Bold which return HAVE_STATE_VARIABLES = ["GlobalAverage", "SpatialAverage", "Raw", "SubSample", "TemporalAverage"] def __init__(self): super(SimulatorAdapter, self).__init__() self.log.debug("%s: Initialized..." % str(self)) def get_input_tree(self): """ Return a list of lists describing the interface to the simulator. This is used by the GUI to generate the menus and fields necessary for defining a simulation. """ sim = Simulator() sim.trait.bound = self.INTERFACE_ATTRIBUTES_ONLY result = sim.interface[self.INTERFACE_ATTRIBUTES] # We should add as hidden the Simulator State attribute. result.append({'name': 'simulation_state', 'type': SimulationState, 'required': False, 'ui_hidden': True}) return result def get_output(self): """ :returns: list of classes for possible results of the Simulator. """ return [time_series.TimeSeries] def configure(self, model, model_parameters, integrator, integrator_parameters, connectivity, monitors, monitors_parameters=None, surface=None, surface_parameters=None, stimulus=None, coupling=None, coupling_parameters=None, initial_conditions=None, conduction_speed=None, simulation_length=0, simulation_state=None): """ Make preparations for the adapter launch. """ self.log.debug("available_couplings: %s..." % str(self.available_couplings)) self.log.debug("coupling: %s..." % str(coupling)) self.log.debug("coupling_parameters: %s..." % str(coupling_parameters)) self.log.debug("%s: Initializing Model..." % str(self)) noise_framework.build_noise(model_parameters) model_instance = self.available_models[str(model)](**model_parameters) self._validate_model_parameters(model_instance, connectivity, surface) self.log.debug("%s: Initializing Integration scheme..." % str(self)) noise_framework.build_noise(integrator_parameters) integr = self.available_integrators[integrator](**integrator_parameters) self.log.debug("%s: Instantiating Monitors..." % str(self)) monitors_list = [] for monitor_name in monitors: if (monitors_parameters is not None) and (str(monitor_name) in monitors_parameters): monitors_list.append(self.available_monitors[str(monitor_name) ](**monitors_parameters[str(monitor_name)])) else: ### We have monitors without any UI settable parameter. monitors_list.append(self.available_monitors[str(monitor_name)]()) if len(monitors) < 1: raise LaunchException("Can not launch operation without monitors selected !!!") self.log.debug("%s: Initializing Coupling..." % str(self)) coupling_inst = self.available_couplings[str(coupling)](**coupling_parameters) self.log.debug("Initializing Cortex...") if surface is not None and surface_parameters is not None: cortex_entity = Cortex(use_storage=False).populate_cortex(surface, surface_parameters) if cortex_entity.region_mapping_data.connectivity.number_of_regions != connectivity.number_of_regions: raise LaunchException("Incompatible RegionMapping -- Connectivity !!") if cortex_entity.region_mapping_data.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException("Incompatible RegionMapping -- Surface !!") select_loc_conn = cortex_entity.local_connectivity if select_loc_conn is not None and select_loc_conn.surface.number_of_vertices != surface.number_of_vertices: raise LaunchException("Incompatible LocalConnectivity -- Surface !!") else: cortex_entity = None self.log.debug("%s: Instantiating requested simulator..." % str(self)) connectivity.configure() self.algorithm = Simulator(connectivity=connectivity, coupling=coupling_inst, surface=cortex_entity, stimulus=stimulus, model=model_instance, integrator=integr, monitors=monitors_list, initial_conditions=initial_conditions, conduction_speed=conduction_speed) self.simulation_length = simulation_length self.log.debug("%s: Initializing storage..." % str(self)) try: self.algorithm.configure() if simulation_state is not None: simulation_state.fill_into(self.algorithm) except ValueError, err: raise LaunchException("Failed to configure simulator due to invalid Input Values. It could be because " "of an incompatibility between different version of TVB code.", err)
def generate_region_demo_data(file_path=os.path.join(os.getcwd(), "demo_data_region_16s_2048Hz.npy")): """ Generate 16 seconds of 2048Hz data at the region level, stochastic integration. ``Run time``: approximately 4 minutes (workstation circa 2010) ``Memory requirement``: < 1GB ``Storage requirement``: ~ 19MB .. moduleauthor:: Stuart A. Knock <*****@*****.**> """ ##----------------------------------------------------------------------------## ##- Perform the simulation -## ##----------------------------------------------------------------------------## LOG.info("Configuring...") # Initialise a Model, Coupling, and Connectivity. pars = {'a': np.array([1.05]), 'b': np.array([-1]), 'c': np.array([0.0]), 'd': np.array([0.1]), 'e': np.array([0.0]), 'f': np.array([1 / 3.]), 'g': np.array([1.0]), 'alpha': np.array([1.0]), 'beta': np.array([0.2]), 'tau': np.array([1.25]), 'gamma': np.array([-1.0])} oscillator = Generic2dOscillator(**pars) white_matter = Connectivity.from_file() white_matter.speed = np.array([4.0]) white_matter_coupling = Linear(a=np.array([0.033])) # Initialise an Integrator hiss = Additive(nsig=np.array([2 ** -10, ])) heunint = HeunStochastic(dt=0.06103515625, noise=hiss) # Initialise a Monitor with period in physical time what_to_watch = TemporalAverage(period=0.48828125) # 2048Hz => period=1000.0/2048.0 # Initialise a Simulator -- Model, Connectivity, Integrator, and Monitors. sim = Simulator(model=oscillator, connectivity=white_matter, coupling=white_matter_coupling, integrator=heunint, monitors=[what_to_watch]) sim.configure() # Perform the simulation tavg_data = [] tavg_time = [] LOG.info("Starting simulation...") for tavg in sim(simulation_length=16000): if tavg is not None: tavg_time.append(tavg[0][0]) # TODO:The first [0] is a hack for single monitor tavg_data.append(tavg[0][1]) # TODO:The first [0] is a hack for single monitor LOG.info("Finished simulation.") ##----------------------------------------------------------------------------## ##- Save the data to a file -## ##----------------------------------------------------------------------------## # Make the list a numpy.array. LOG.info("Converting result to array...") TAVG = np.array(tavg_data) # Save it LOG.info("Saving array to %s..." % file_path) np.save(file_path, TAVG) LOG.info("Done.")