def concatenate(self, time_series_list, dim, **kwargs): time_series_list = ensure_list(time_series_list) n_ts = len(time_series_list) if n_ts > 0: out_time_series, select_fun = self.select(time_series_list[0], **kwargs) if n_ts > 1: for id, time_series in enumerate(time_series_list[1:]): if np.float32(out_time_series.sample_period) != np.float32(time_series.sample_period): raise_value_error("Timeseries concatenation failed!\n" "Timeseries %d have a different time step (%s) \n " "than the concatenated ones (%s)!" % (id, str(np.float32(time_series.sample_period)), str(np.float32(out_time_series.sample_period)))) else: time_series = self.select(time_series, select_fun)[0] try: out_time_series.set_data(np.concatenate([out_time_series.data, time_series.data], axis=dim)) if len(out_time_series.labels_dimensions[out_time_series.labels_ordering[dim]]) > 0: dim_label = out_time_series.labels_ordering[dim] out_time_series.labels_dimensions[dim_label] = \ np.array(ensure_list(out_time_series.labels_dimensions[dim_label]) + ensure_list(time_series.labels_dimensions[dim_label])) except: raise_value_error("Timeseries concatenation failed!\n" "Timeseries %d have a shape (%s) and the concatenated ones (%s)!" % (id, str(out_time_series.shape), str(time_series.shape))) return out_time_series else: return out_time_series else: raise_value_error("Cannot concatenate empty list of TimeSeries!")
def connect_nest_nodes(self): n_nodes = len(self.nest_nodes_ids) # For every different type of connections between distinct NEST nodes' populations for i_conn, conn in enumerate(ensure_list(self.node_connections)): conn_spec = self.default_synapse['params'] conn_spec.update(conn['params']) model = conn.get("model", self.default_synapse["model"]) weight = conn.get("weight", 1.0) delay = conn.get("delay", 0.0) # Define functions for the exact synthesis of source and target populations pop_src = lambda node: \ flatten_tuple([node[pop] for pop in ensure_list(conn['src_population'])]) pop_trg = lambda node: \ flatten_tuple([node[pop] for pop in ensure_list(conn['trg_population'])]) # ...and form the connection for every distinct pair of NEST nodes # TODO! Confirm that no self connections are allowed here! for i_n1 in range(n_nodes - 1): for i_n2 in range(1, n_nodes): if self.tvb_weights[i_n1, i_n2] > 0: self._connect_two_populations_between_nodes( pop_src(self.nodes[i_n1]), pop_trg(self.nodes[i_n2]), i_n1, i_n2, conn_spec, model, weight, delay) if self.tvb_weights[i_n2, i_n1] > 0: self._connect_two_populations_between_nodes( pop_src(self.nodes[i_n2]), pop_trg(self.nodes[i_n1]), i_n2, i_n1, conn_spec, model, weight, delay)
def __init__(self, tvb_simulator, nest_network, nest_nodes_ids, nest_to_tvb_interfaces=None, tvb_to_nest_interfaces=None, config=CONFIGURED): self.config = config if isinstance(nest_network, NESTNetwork): self.nest_network = nest_network else: raise ValueError("Input nest_network is not a NESTNetwork object!\n%s" % str(nest_network)) if isinstance(tvb_simulator, Simulator): self.connectivity = tvb_simulator.connectivity self.integrator = tvb_simulator.integrator self.tvb_model = tvb_simulator.model self.tvb_nodes_ids = list(range(self.connectivity.weights.shape[0])) try: self.nest_nodes_ids = ensure_list(nest_nodes_ids) for i_n in self.nest_nodes_ids: self.tvb_nodes_ids.remove(i_n) except: raise ValueError("Failed to compute tvb_nodes_ids from nest_nodes_ids %s " "and TVB connectivity of size %s!" % (str(self.nest_nodes_ids, self.connectivity.weights.shape[0]))) if tvb_simulator.stimulus is not None: if np.sum(tvb_simulator.stimulus[:, self.nest_nodes_ids]): raise ValueError("TVB-NEST interface does not implement TVB stimulus application to NEST nodes!\n" "The user has to configure such stimulus as part of the NEST model, " "via appropriate NEST input devices!") else: raise ValueError("Input simulator_tvb is not a Simulator object!\n%s" % str(tvb_simulator)) if nest_to_tvb_interfaces is not None: self.nest_to_tvb_interfaces = ensure_list(nest_to_tvb_interfaces) if tvb_to_nest_interfaces is not None: self.tvb_to_nest_interfaces = ensure_list(tvb_to_nest_interfaces)
def connect_nest_nodes(self): # Define a function for the exact synthesis of source and target populations population = lambda node, populations: \ flatten_tuple([node[pop] for pop in ensure_list(populations)]) # For every different type of connections between distinct NEST nodes' populations for i_conn, conn in enumerate(ensure_list(self.nodes_connections)): model = property_to_fun(conn["model"]) weight = property_to_fun(conn["weight"]) delay = property_to_fun(conn["delay"]) receptor_type = property_to_fun(conn["receptor_type"]) conn_spec = property_to_fun(conn['conn_spec']) # ...and form the connection for every distinct pair of NEST nodes for source_index in conn["source_nodes"]: i_source_node = np.where( self.nest_nodes_ids == source_index)[0][0] for target_index in conn["target_nodes"]: if source_index != target_index: # TODO! Confirm that no self connections are allowed here! i_target_node = np.where( self.nest_nodes_ids == target_index)[0][0] if self.tvb_weights[source_index, target_index] > 0: self._connect_two_populations_between_nodes( population(self.nodes[i_source_node], conn["source"]), population(self.nodes[i_target_node], conn["target"]), i_source_node, i_target_node, conn_spec(source_index, target_index), model(source_index, target_index), weight(source_index, target_index), delay(source_index, target_index), receptor_type(source_index, target_index))
def normalize_signals(signals, normalization=None, axis=None, percent=None): # Following pylab demean: def matrix_subtract_along_axis(x, y, axis=0): "Return x minus y, where y corresponds to some statistic of x along the specified axis" if axis == 0 or axis is None or x.ndim <= 1: return x - y ind = [slice(None)] * x.ndim ind[axis] = np.newaxis return x - y[ind] def matrix_divide_along_axis(x, y, axis=0): "Return x divided by y, where y corresponds to some statistic of x along the specified axis" if axis == 0 or axis is None or x.ndim <= 1: return x / y ind = [slice(None)] * x.ndim ind[axis] = np.newaxis return x / y[ind] for norm, ax, prcnd in zip(ensure_list(normalization), cycle(ensure_list(axis)), cycle(ensure_list(percent))): if isinstance(norm, string_types): if isequal_string(norm, "zscore"): signals = zscore(signals, axis=ax) # / 3.0 elif isequal_string(norm, "baseline-std"): signals = normalize_signals(["baseline", "std"], axis=axis) elif norm.find("baseline") == 0 and norm.find("amplitude") >= 0: signals = normalize_signals(signals, ["baseline", norm.split("-")[1]], axis=axis, percent=percent) elif isequal_string(norm, "minmax"): signals = normalize_signals(signals, ["min", "max"], axis=axis) elif isequal_string(norm, "mean"): signals = demean(signals, axis=ax) elif isequal_string(norm, "baseline"): if prcnd is None: prcnd = 1 signals = matrix_subtract_along_axis(signals, np.percentile(signals, prcnd, axis=ax), axis=ax) elif isequal_string(norm, "min"): signals = matrix_subtract_along_axis(signals, np.min(signals, axis=ax), axis=ax) elif isequal_string(norm, "max"): signals = matrix_divide_along_axis(signals, np.max(signals, axis=ax), axis=ax) elif isequal_string(norm, "std"): signals = matrix_divide_along_axis(signals, signals.std(axis=ax), axis=ax) elif norm.find("amplitude") >= 0: if prcnd is None: prcnd = [1, 99] amplitude = np.percentile(signals, prcnd[1], axis=ax) - np.percentile(signals, prcnd[0], axis=ax) this_ax = ax if isequal_string(norm.split("amplitude")[0], "max"): amplitude = amplitude.max() this_ax = None elif isequal_string(norm.split("amplitude")[0], "mean"): amplitude = amplitude.mean() this_ax = None signals = matrix_divide_along_axis(signals, amplitude, axis=this_ax) else: raise_value_error("Ignoring signals' normalization " + normalization + ",\nwhich is not one of the currently available " + str(NORMALIZATION_METHODS) + "!") return signals
def current_data(self, variables=None, neurons=None, exclude_neurons=[], name=None, dims_names=["Variable", "Neuron"]): # This method will return current time data if name is None: name = self.model coords = OrderedDict() variables = self._determine_variables(variables) events = self.events times = events["times"] coords[dims_names[0]] = variables if len(times) > 0: # Get only the last time stamp events: output_inds = events["times"] == events["times"][-1] # Optionally filter sender neurons senders = events["senders"] if neurons is not None: output_inds = np.logical_and( output_inds, [sender in flatten_list(neurons) for sender in senders]) else: neurons = ensure_list(self.neurons) if len(exclude_neurons) > 0: output_inds = np.logical_and(output_inds, [ sender not in flatten_list(exclude_neurons) for sender in senders ]) coords[dims_names[1]] = neurons data = np.empty((len(variables), len(neurons))) for i_var, var in enumerate(variables): data[i_var] = events[var][output_inds] else: # The multimeter is still empty, so return zeros if neurons is None: neurons = ensure_list(self.neurons) else: neurons = flatten_list(neurons) for neuron in flatten_list(exclude_neurons): try: neurons.remove(neuron) except: pass n_neurons = len(neurons) coords[dims_names[1]] = neurons data = np.empty((len(variables), len(neurons))) for i_var in range(len(variables)): data[i_var] = np.zeros((n_neurons, )) return xr.DataArray(data, coords=coords, dims=list(coords.keys()), name=name)
def filter_events(self, events, variables=None, neurons=None, times=None, exclude_neurons=[], exclude_times=[]): # This method will select/exclude part of the measured events, depending on user inputs if variables is None: variables = events.keys() output_events = OrderedDict() if events is None: events = self.events events_times = np.array(events["times"]) senders = np.array(events["senders"]) inds = np.ones((self.n_events, )) if len(inds) > 0: if times is not None: if senders is not None: inds = np.logical_and(inds, [ time in flatten_list(times) and time not in flatten_list(exclude_times) and sender in flatten_list(neurons) and sender not in flatten_list(exclude_neurons) for time, sender in zip(events_times, senders) ]) else: inds = np.logical_and(inds, [ time in flatten_list(times) and time not in flatten_list(exclude_times) and sender not in flatten_list(exclude_neurons) for time, sender in zip(events_times, senders) ]) else: if neurons is not None: inds = np.logical_and(inds, [ time not in flatten_list(exclude_times) and sender in flatten_list(neurons) and sender not in flatten_list(exclude_neurons) for time, sender in zip(events_times, senders) ]) else: inds = np.logical_and(inds, [ time not in flatten_list(exclude_times) and sender not in flatten_list(exclude_neurons) for time, sender in zip(events_times, senders) ]) for var in ensure_list(variables): output_events[var] = events[var][inds] else: for var in ensure_list(variables): output_events[var] = np.array([]) return output_events
def __setitem__(self, keys, values): if isinstance(keys, slice): keys = (np.array(list(self._dict.keys()))[keys]).tolist() for key, val in zip(ensure_list(keys), ensure_list(values)): try: if is_integer(key): list(self._dict.values())[key] = val else: # assuming key string self._dict[key] = val except: LOG.warning("key %s not found in IndexedOrderedDict %s!\n" "Skipping item setting with value %s!" % (str(key), str(self._dict), str(val)))
def set_values(self, values, nodes=None): if nodes is None or len(nodes) == 0: nodes = self._dict.keys() nodes = ensure_list(nodes) values = ensure_list(values) n_vals = len(values) n_nodes = len(nodes) if n_vals not in [1, n_nodes]: raise ValueError("Values' number %d is neither equal to 1 " "nor equal to nodes' number %d!" % (n_vals, n_nodes)) for node, value in zip(ensure_list(nodes), cycle(ensure_list(values))): self.nest_instance.SetStatus(self._dict[node], {self.parameter: self.sign * value})
def _compile_select_fun(self, **kwargs): select_fun = [] for dim, lbl in enumerate(["times", "variables", "labels", "samples"]): index = ensure_list(kwargs.pop(lbl, [])) if len(index) > 0: select_fun.append(lambda ts: getattr(ts, "get_subset")(index, dim)) return select_fun
def _compile_select_funs(self, labels_ordering, **kwargs): select_funs = [] for dim, lbl in enumerate(labels_ordering): indices_labels_slices = ensure_list(kwargs.pop(lbl, [])) if len(indices_labels_slices) > 0: select_funs.append(lambda ts: getattr(ts, "slice_data_across_dimension")(indices_labels_slices, dim)) return select_funs
def __getitem__(self, keys): output = [] if isinstance(keys, slice): try: output = (np.array(list(self._dict.values()))[keys]).tolist() except: LOG.warning("keys %s not found in IndexedOrderedDict %s!\n" "Returning None!" % (str(keys), str(self._dict))) else: output = [] for key in ensure_list(keys): try: if is_integer(key): output.append(list(self._dict.values())[key]) else: # assuming key string output.append(self._dict[key]) except: LOG.warning("key %s not found in IndexedOrderedDict %s!\n" "Returning None!" % (str(key), str(self._dict))) n_outputs = len(output) if n_outputs == 0: return None elif n_outputs == 1: return output[0] else: return output
def get_subset(self, list_of_indices_or_labels, dim, **kwargs): assert dim in [0, 1, 2, 3] list_of_indices_or_labels = ensure_list(list_of_indices_or_labels) if numpy.all([ is_integer(ind_or_lbl) for ind_or_lbl in list_of_indices_or_labels ]): return self.get_subset_by_index(list_of_indices_or_labels, dim, **kwargs) else: if dim == 0: if not numpy.all([ is_numeric(ind_or_lbl) for ind_or_lbl in list_of_indices_or_labels ]): raise_value_error( "Input consists neither of integer indices nor of points in time (floats)!: %s" % list_of_indices_or_labels) time_indices = [ self._get_index_for_time(time) for time in list_of_indices_or_labels ] return self.get_subset_by_index(time_indices, 0, **kwargs) else: if not numpy.all([ isinstance(ind_or_lbl, string_types) for ind_or_lbl in list_of_indices_or_labels ]): raise_value_error( "Input consists neither of integer indices nor of label strings!: %s" % list_of_indices_or_labels) return self.get_subset_by_label(list_of_indices_or_labels, dim, **kwargs)
def read_sensors_and_projection(self, filename, root_folder, s_type, atlas=""): def get_sensors_name(sensors_file, name): if len(sensors_file) > 1: gain_file = sensors_file[1] else: gain_file = "" return name + gain_file.replace(".txt", "").replace(name, "") filename = ensure_list(filename) path = os.path.join(root_folder, filename[0]) if os.path.isfile(path): sensors = \ SensorTypesToClassesDict.get(s_type, Sensors).from_file(path) sensors.configure() if len(filename) > 1: projection = self.read_projection( os.path.join(root_folder, atlas, filename[1]), s_type) else: projection = None sensors.name = get_sensors_name(filename, sensors._ui_name) sensors.configure() return sensors, projection else: self.logger.warning("\nNo Sensor file found at path %s!" % str(path)) return None
def compile_modules(modules, recompile=False, config=CONFIGURED, logger=LOG): # ...unless we need to first compile it: from pynestml.frontend.pynestml_frontend import install_nest if not os.path.exists(config.MODULES_BLDS_DIR): logger.info("Creating MODULES_BLDS_DIR: %s" % config.MODULES_BLDS_DIR) os.makedirs(config.MODULES_BLDS_DIR) for module in ensure_list(modules): logger.info("Compiling %s..." % module) module_bld_dir = os.path.join(config.MODULES_BLDS_DIR, module) logger.info("from in build_interfaces directory %s..." % module_bld_dir) if not os.path.exists(module_bld_dir) or recompile: source_path = os.path.join(config.MODULES_DIR, module) logger.info("copying sources from %s\ninto %s..." % (source_path, module_bld_dir)) shutil.copytree(source_path, module_bld_dir) logger.info("Running compilation...") install_nest(module_bld_dir, config.NEST_PATH) if os.path.isfile(os.path.join(config.MODULES_BLDS_DIR, module + "module.so")) and \ os.path.isfile(os.path.join(config.MODULES_BLDS_DIR, "lib" + module + "module.so")): logger.info("DONE compiling %s!" % module) else: logger.warn( "Something seems to have gone wrong with compiling %s!" % module)
def get_subset_by_label(self, list_of_labels, dim, **kwargs): assert dim in [0, 1, 2, 3] list_of_labels = ensure_list(list_of_labels) dim_label = self.labels_ordering[dim] list_of_indices = labels_to_indices(self.labels_dimensions[dim_label], list_of_labels, dim_label, self.logger) return self.get_subset_by_index(list_of_indices, dim, **kwargs)
def update_dimension_names(self, dim_names, dim_indices=None): dim_names = ensure_list(dim_names) if dim_indices is None: dim_indices = list(range(len(dim_names))) else: dim_indices = ensure_list(dim_indices) labels_ordering = list(self.labels_ordering) for dim_name, dim_index in zip(dim_names, dim_indices): labels_ordering[dim_index] = dim_name try: old_dim_name = self.labels_ordering[dim_index] dim_labels = list(self.labels_dimensions[old_dim_name]) del self.labels_dimensions[old_dim_name] self.labels_dimensions[dim_name] = dim_labels except: pass self.labels_ordering = labels_ordering
def _determine_variables(self, variables=None): if variables is not None: variables = ensure_list(variables) for variable in variables: assert variable in self.record_from else: variables = self.record_from return variables
def GetStatus(self, attrs, nodes=None, return_values=False): if nodes is None or len(nodes) == 0: nodes = self._dict.keys() vals = OrderedDict({}) for attr in ensure_list(attrs): this_attr = [] for node in ensure_list(nodes): this_attr.append(getattr(self._dict[node], attr)) vals.update({attr: this_attr}) if return_values: vals = vals.values() if len(vals) == 1: return vals[0] else: return vals else: return vals
def set(self, values): values = ensure_list(values) n_vals = len(values) if n_vals not in [1, self.n_nodes]: raise ValueError("Values' number %d is neither equal to 1 " "nor equal to nodes' number %d!" % (n_vals, self.n_nodes)) for node, value in zip(self.nodes, cycle(values)): self.nest_instance.SetStatus(self[node], {self.parameter: value})
def _check_indices(self, indices, dimension): dim_index = self.get_dimension_index(dimension) for index in ensure_list(indices): if index < 0 or index > self.data.shape[dim_index]: self.logger.error( "Some of the given indices are out of %s range: [0, %s]", (self.get_dimension_name(dim_index), self.data.shape[dim_index])) raise IndexError
def _assert_connection_populations(self, connection): # This method will make sure that there source and target user inputs for every population connection # and that every source/target population is already among the populations to be generated. for pop in ["source", "target"]: pops_labels = connection.get(pop, None) if pops_labels is None: raise_value_error("No %s population in connection!:\n%s" % (pop, str(connection))) for pop_lbl in ensure_list(pops_labels): assert pop_lbl in self.populations_labels return pops_labels
def _index_or_label_or_slice(self, inputs): inputs = ensure_list(inputs) if numpy.all([is_integer(inp) for inp in inputs]): return "index" elif numpy.all([isinstance(inp, string_types) for inp in inputs]): return "label" elif numpy.all([isinstance(inp, slice) for inp in inputs]): return "slice" else: raise ValueError( "input %s is not of type integer, string or slice!" % str(inputs))
def sensor_label_to_index(self, labels): indexes = [] for label in ensure_list(labels): indexes.append( np.where([ np.array(lbl) == np.array(label) for lbl in self._tvb.labels ])[0][0]) if isinstance(labels, (list, tuple)) or len(indexes) > 1: return indexes else: return indexes[0]
def labels_to_indices(labels, target_labels, variables_name, logger): indices = [] target_labels = numpy.unique(ensure_list(target_labels)) if len(target_labels) > 0: try: indices = labels_to_inds(labels, target_labels) except IndexError: logger.error( "Failed to access indices of %s: %s.\nExisting %s: %s" % (variables_name, target_labels, variables_name, labels)) raise return indices
def _configure_populations(self): # Every population must have his own model name, # scale of spiking neurons' number, and model specific parameters for key in ['models', 'scales', 'params']: attr = 'populations_' + key setattr(self, attr, ensure_list(getattr(self, attr))) val = ensure_list(getattr(self, attr)) n_temp = len(val) if n_temp != self.number_of_populations: if n_temp == 1: setattr(self, attr, val * self.number_of_populations) else: raise ValueError( "populations_%s has neither length 1 " "nor equal to the number %d of populations_names %s,\n" "but %d" % (attr, self.number_of_populations, self.populations_names, n_temp)) self.populations_sizes = [ int(np.round(scale * self.populations_order)) for scale in self.populations_scales ]
def _connect_two_populations(self, pop_src, pop_trg, conn_spec, syn_spec): # Prepare the parameters of connectivity: conn_spec, n_cons = self._prepare_populations_connection_params( pop_src, pop_trg, conn_spec, syn_spec) # Scale the synaptic weight with respect to the total number of connections between the two populations: syn_spec["weight"] = self._synaptic_weight_scaling( syn_spec["weight"], n_cons) # We might create the same connection multiple times with different synaptic receptors... receptors = ensure_list(syn_spec["receptor_type"]) for receptor in receptors: syn_spec["receptor_type"] = receptor self.connect_two_populations(pop_src, pop_trg, conn_spec, syn_spec)
def concatenate(self, time_series_list, dim, **kwargs): time_series_list = ensure_list(time_series_list) n_ts = len(time_series_list) if n_ts > 0: out_time_series, select_funs = self.select(time_series_list[0], **kwargs) if n_ts > 1: dim_label = out_time_series.get_dimension_name(dim) for id, time_series in enumerate(time_series_list[1:]): if np.float32(out_time_series.sample_period) != np.float32(time_series.sample_period): raise ValueError("Timeseries concatenation failed!\n" "Timeseries %d have a different time step %s \n " "than the concatenated ones %s!" % (id, str(np.float32(time_series.sample_period)), str(np.float32(out_time_series.sample_period)))) else: time_series = self.select(time_series, select_funs)[0] labels_dimensions = dict(out_time_series.labels_dimensions) out_labels = out_time_series.get_dimension_labels(dim) if out_labels is not None and len(out_labels) == out_time_series.shape[dim]: time_series_labels = time_series.get_dimension_labels(dim) if time_series_labels is not None and len(time_series_labels) == time_series.shape[dim]: labels_dimensions[dim_label] =\ np.array(ensure_list(out_labels) + ensure_list(time_series_labels)) else: del labels_dimensions[dim_label] warning("Dimension labels for dimensions %s cannot be concatenated! " "Deleting them!" % dim_label) try: out_data = np.concatenate([out_time_series.data, time_series.data], axis=dim) except: raise_value_error("Timeseries concatenation failed!\n" "Timeseries %d have a shape %s and the concatenated ones %s!" % (id, str(out_time_series.shape), str(time_series.shape))) out_time_series = out_time_series.duplicate(data=out_data, labels_dimensions=labels_dimensions) return out_time_series else: return out_time_series else: raise ValueError("Cannot concatenate empty list of TimeSeries!")
def get_devices_by_model(self, model, nodes=None): devices = pd.Series() if nodes is None: get_device = lambda device, nodes: device else: nodes = ensure_list(nodes) get_device = lambda device, nodes: device[nodes] for i_pop, (pop_label, pop_device) in enumerate(self.output_devices.iteritems()): if pop_device.model == model: devices[pop_label] = get_device(pop_device, nodes) return devices
def _confirm_compile_install_nest_models(self, models, modules=[]): nest_models = self.nest_instance.Models() models = ensure_list(models) modules = ensure_list(modules) if len(modules) == 0: for model in models: modules.append("%smodule" % model) # Assuming default naming for modules as modelmodule for model, module in zip(models, cycle(modules)): if model not in nest_models: try: # Try to install it... self.logger.info("Trying to install module %s..." % module) self.nest_instance.Install(module) except: self.logger.info("FAILED! We need to first compile it!") # ...unless we need to first compile it: compile_modules(model, recompile=False, config=self.config) # and now install it... self.logger.info("Installing now module %s..." % module) self.nest_instance.Install(module) self.logger.info("DONE installing module %s!" % module) nest_models = self.nest_instance.Models()