def _assert_ticbase_change_raises_and_reset(self, after_call): """Assert that changing tic-base raises a NESTError, and reset the kernel""" with self.assertRaises(nest.kernel.NESTError, msg=f'after calling "{after_call}"'): # For co-dependent properties, we use `set()` instead of kernel attributes nest.set(resolution=0.5, tics_per_ms=1500.0) nest.ResetKernel()
def test_multiple_synapse_deletion_one_to_one(self): for syn_model in nest.Models('synapses'): if syn_model not in self.exclude_synapse_model: nest.ResetKernel() nest.CopyModel('static_synapse', 'my_static_synapse') nest.SetDefaults(syn_model, {'delay': 0.5}) syn_dict = { 'synapse_model': syn_model, 'pre_synaptic_element': 'SE1', 'post_synaptic_element': 'SE2' } # For co-dependent properties, we use `set()` instead of kernel attributes nest.set(min_delay=0.1, max_delay=1.0) nest.structural_plasticity_synapses = {'syn1': syn_dict} neurons = nest.Create( 'iaf_psc_alpha', 10, { 'synaptic_elements': { 'SE1': { 'z': 0.0, 'growth_rate': 0.0 }, 'SE2': { 'z': 0.0, 'growth_rate': 0.0 } } }) nest.Connect(neurons, neurons, "all_to_all", syn_dict) # Test if the connected synaptic elements before the simulation # are correct status = nest.GetStatus(neurons, 'synaptic_elements') for st_neuron in status: self.assertEqual(10, st_neuron['SE1']['z_connected']) self.assertEqual(10, st_neuron['SE2']['z_connected']) src_neurons = neurons[:5] tgt_neurons = neurons[5:] conns = nest.GetConnections(src_neurons, tgt_neurons, syn_model) assert conns conndictionary = {'rule': 'one_to_one'} syndictionary = {'synapse_model': syn_model} nest.Disconnect(src_neurons, tgt_neurons, conndictionary, syndictionary) status = nest.GetStatus(neurons, 'synaptic_elements') for st_neuron in status[0:5]: self.assertEqual(9, st_neuron['SE1']['z_connected']) self.assertEqual(10, st_neuron['SE2']['z_connected']) for st_neuron in status[5:10]: self.assertEqual(10, st_neuron['SE1']['z_connected']) self.assertEqual(9, st_neuron['SE2']['z_connected'])
def test_models(self): """Time objects in models correctly updated""" # Generate a dictionary of reference values for each model. reference = {} for model in nest.Models(): if model in self.ignored_models: continue try: reference[model] = nest.GetDefaults(model) except nest.kernel.NESTError: # If we can't get the defaults, we ignore the model. pass # Change the tic-base. nest.set(resolution=0.5, tics_per_ms=1500.0) # At this point, Time objects in models should have been updated to # account for the new tic-base. Values in model defaults should therefore # be equal (within a tolerance) to the reference values. failing_models = [] for model in reference.keys(): model_reference = reference[model] model_defaults = nest.GetDefaults(model) # Remove entries where the item contains more than one value, as this causes issues when comparing. array_keys = [ key for key, value in model_defaults.items() if isinstance(value, (list, tuple, dict, np.ndarray)) ] for key in array_keys: del model_defaults[key] del model_reference[key] keydiff = [] for key, value in model_defaults.items(): # value may not be a number, so we test for equality first. # If it's not equal to the reference value, we assume it is a number. if value != model_reference[key] and abs( value - model_reference[key]) > self.eps: print(value - model_reference[key]) keydiff.append([key, model_reference[key], value]) # If any keys have values different from the reference, the model fails. if len(keydiff) > 0: print(model, keydiff) failing_models.append(model) # No models should fail for the test to pass. self.assertEqual([], failing_models)
def test_register_synapses(self): for syn_model in nest.synapse_models: if syn_model not in self.exclude_synapse_model: nest.ResetKernel() nest.SetDefaults(syn_model, {'delay': 0.5}) syn_dict = { 'synapse_model': syn_model, 'pre_synaptic_element': 'SE1', 'post_synaptic_element': 'SE2' } # For co-dependent properties, we use `set()` instead of kernel attributes nest.set(min_delay=0.1, max_delay=1.0) nest.structural_plasticity_synapses = {'syn1': syn_dict} kernel_status = nest.structural_plasticity_synapses assert 'syn1' in kernel_status assert kernel_status['syn1'] == extract_dict_a_from_b(kernel_status['syn1'], syn_dict)
def test_set(self): """ Test the `nest` module's `.set` function, `KernelAttribute` assignment and errors on unknown attribute assignment. """ # Setting the value of unknown attributes should error. Prevents user errors. with self.assertRaises(AttributeError, msg="arbitrary attribute assignment passed"): nest.absolutelyUnknownThingOnNestModule = 5 # Don't allow non-KA to be replaced on the module. with self.assertRaises(AttributeError, msg="known attribute assignment passed"): nest.get = 5 nest.set(total_num_virtual_procs=2) self.assertEqual(2, nest.total_num_virtual_procs, 'set failed') nest.total_num_virtual_procs = 3 self.assertEqual(3, nest.total_num_virtual_procs, 'kernelattribute set failed')
def run_protocol(self, pre_post_shift): """ Create network and simulate for each delta value. Returns a dict with the synaptic weight at end of simulation for plain and precise parrots, one weight per delta value. All values for the plain parrot case should be identical, and the values for the precise parrot case should converge to that value for delta -> 0. All delta values must fulfill multiplicity * delta < resolution / 2 so that in the plain case off-grid spike times are rounded up to the end of the step and thus belong to the same step as the corresponding precise spikes. :param pre_post_shift: Delay between pre- and postsynaptic trains :returns: {'parrot': [<weights>], 'parrot_ps': [<weights>]} """ multiplicity = 2**3 resolution = 2.**-4 tics_per_ms = 1. / resolution * multiplicity * 4 deltas = [resolution / multiplicity / 2**m for m in range(2, 10)] delay = 1. # k spikes will be emitted at these two times pre_spike_times_base = [100., 200.] nest.set_verbosity("M_WARNING") post_weights = {'parrot': [], 'parrot_ps': []} for delta in deltas: assert multiplicity * delta < resolution / 2., "Test inconsistent." nest.ResetKernel() # For co-dependent properties, we use `set()` instead of kernel attributes nest.set(resolution=resolution, tics_per_ms=tics_per_ms) pre_times = sorted(t_base - k * delta for t_base in pre_spike_times_base for k in range(multiplicity)) post_times = [pre_time + pre_post_shift for pre_time in pre_times] # create spike_generators with these times pre_sg = nest.Create("spike_generator", params={ "spike_times": pre_times, 'allow_offgrid_times': True }) post_sg = nest.Create("spike_generator", params={ "spike_times": post_times, 'allow_offgrid_times': True }) pre_sg_ps = nest.Create("spike_generator", params={ "spike_times": pre_times, 'precise_times': True }) post_sg_ps = nest.Create("spike_generator", params={ "spike_times": post_times, 'precise_times': True }) # create parrot neurons and connect spike_generators pre_parrot = nest.Create("parrot_neuron") post_parrot = nest.Create("parrot_neuron") pre_parrot_ps = nest.Create("parrot_neuron_ps") post_parrot_ps = nest.Create("parrot_neuron_ps") nest.Connect(pre_sg, pre_parrot, syn_spec={"delay": delay}) nest.Connect(post_sg, post_parrot, syn_spec={"delay": delay}) nest.Connect(pre_sg_ps, pre_parrot_ps, syn_spec={"delay": delay}) nest.Connect(post_sg_ps, post_parrot_ps, syn_spec={"delay": delay}) # create spike recorder --- debugging only spikes = nest.Create("spike_recorder") nest.Connect( pre_parrot + post_parrot + pre_parrot_ps + post_parrot_ps, spikes) # connect both parrot neurons with a stdp synapse onto port 1 # thereby spikes transmitted through the stdp connection are # not repeated postsynaptically. nest.Connect(pre_parrot, post_parrot, syn_spec={ 'synapse_model': 'stdp_synapse', 'receptor_type': 1 }) nest.Connect(pre_parrot_ps, post_parrot_ps, syn_spec={ 'synapse_model': 'stdp_synapse', 'receptor_type': 1 }) # get STDP synapse and weight before protocol syn = nest.GetConnections(source=pre_parrot, synapse_model="stdp_synapse") w_pre = syn.get('weight') syn_ps = nest.GetConnections(source=pre_parrot_ps, synapse_model="stdp_synapse") w_pre_ps = syn_ps.get('weight') sim_time = max(pre_times + post_times) + 5 * delay nest.Simulate(sim_time) # get weight post protocol w_post = syn.get('weight') w_post_ps = syn_ps.get('weight') assert w_post != w_pre, "Plain parrot weight did not change." assert w_post_ps != w_pre_ps, "Precise parrot \ weight did not change." post_weights['parrot'].append(w_post) post_weights['parrot_ps'].append(w_post_ps) if DEBUG_PLOTS: fig, ax = plt.subplots(nrows=2) fig.suptitle("Final obtained weights") ax[0].plot(post_weights["parrot"], marker="o", label="parrot") ax[0].plot(post_weights["parrot_ps"], marker="o", label="parrot_ps") ax[0].set_ylabel("final weight") ax[0].set_xticklabels([]) ax[1].semilogy(np.abs( np.array(post_weights["parrot"]) - np.array(post_weights["parrot_ps"])), marker="o", label="error") ax[1].set_xticks([i for i in range(len(deltas))]) ax[1].set_xticklabels(["{0:.1E}".format(d) for d in deltas]) ax[1].set_xlabel("timestep [ms]") for _ax in ax: _ax.grid(True) _ax.legend() plt.savefig("/tmp/test_stdp_multiplicity.png") plt.close(fig) print(post_weights) return post_weights
def test_models(self): """Time objects in models correctly updated""" # These parameters are automatically adjusted upon changes to # the tic base or the resolution so they should explicitly not # be the same after a change of those. We therefore exclude # them from the checks below. ignored_params = { "correlation_detector": ["delta_tau"], "correlomatrix_detector": ["delta_tau"], "correlospinmatrix_detector": ["delta_tau"], "noise_generator": ["dt"], } # Generate a dictionary of reference values for each model. reference = {} for model in nest.node_models + nest.synapse_models: if model in self.ignored_models: continue try: reference[model] = nest.GetDefaults(model) except nest.kernel.NESTError: # If we can't get the defaults, we ignore the model. pass # Change the tic-base. nest.set(resolution=0.5, tics_per_ms=1500.0) # At this point, Time objects in models should have been updated to # account for the new tic-base. Values in model defaults should therefore # be equal (within a tolerance) to the reference values. failing_models = [] for model in reference.keys(): model_reference = reference[model] model_defaults = nest.GetDefaults(model) # Remove entries where the item contains more than one value, as this causes issues when comparing. array_keys = [ key for key, value in model_defaults.items() if isinstance(value, (list, tuple, dict, np.ndarray)) ] for key in array_keys: del model_defaults[key] del model_reference[key] keydiff = [] for key, value in model_defaults.items(): if model in ignored_params and key in ignored_params[model]: continue # value may not be a number, so we test for equality first. # If it's not equal to the reference value, we assume it is a number. if value != model_reference[key] and abs( value - model_reference[key]) > self.eps: print(value - model_reference[key]) keydiff.append([key, model_reference[key], value]) # If any keys have values different from the reference, the model fails. if len(keydiff) > 0: print(model, keydiff) failing_models.append(model) # No models should fail for the test to pass. self.assertEqual([], failing_models)