Skip to content

Commit d695b78

Browse files
committed
Fix NEST native Tsodyks synapse handling (issue NeuralEnsemble#810)
- Replace string-based 'tsodyks' model name check with isinstance(TsodyksMarkramSynapse) in _connect() and _convergent_connect(), so tau_psc is only auto-copied from the post-synaptic neuron for the PyNN standard model, not for native_synapse_type. - Fix broken tau_psc read in _connect(), which was reading from non-existent connections; now reads directly from the post-synaptic population's node_collection. - Fix self.post -> projection.post in NESTConnectorMixin.synapse_parameters(), which caused AttributeError for inhibitory projections using the native connect path. - Add three regression tests covering native tsodyks_synapse (both _convergent_connect and _connect paths) and native tsodyks2_synapse.
1 parent 01ac5a4 commit d695b78

3 files changed

Lines changed: 80 additions & 8 deletions

File tree

pyNN/nest/connectors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def synapse_parameters(self, projection):
116116
if (
117117
name == "weight"
118118
and projection.receptor_type == 'inhibitory'
119-
and self.post.conductance_based
119+
and projection.post.conductance_based
120120
):
121121
# NEST wants negative values for inhibitory weights,
122122
# even if these are conductances

pyNN/nest/projections.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from ..space import Space
1717
from ..parameters import simplify
1818
from . import simulator
19-
from .standardmodels.synapses import StaticSynapse
19+
from .standardmodels.synapses import StaticSynapse, TsodyksMarkramSynapse
2020
from .conversion import make_sli_compatible
2121

2222
logger = logging.getLogger("PyNN")
@@ -123,16 +123,16 @@ def _connect(self, rule_params, syn_params):
123123
Create connections by calling nest. Connect on the presynaptic and postsynaptic population
124124
with the parameters provided by params.
125125
"""
126-
if 'tsodyks' in self.nest_synapse_model:
126+
if isinstance(self.synapse_type, TsodyksMarkramSynapse):
127127
translations = self.post.local_cells[0].celltype.translations
128128
if self.receptor_type == 'inhibitory':
129129
param_name = translations['tau_syn_I']['translated_name']
130130
elif self.receptor_type == 'excitatory':
131131
param_name = translations['tau_syn_E']['translated_name']
132132
else:
133133
raise NotImplementedError()
134-
syn_params.update(
135-
{'tau_psc': nest.GetStatus([self.nest_connections[0, 1]], param_name)})
134+
tau_psc = nest.GetStatus(self.post.node_collection, param_name)
135+
syn_params.update({'tau_psc': tau_psc[0] if len(set(tau_psc)) == 1 else list(tau_psc)})
136136

137137
syn_params.update({'synapse_label': self.nest_synapse_label})
138138
nest.Connect(self.pre.node_collection,
@@ -258,9 +258,10 @@ def _convergent_connect(self, presynaptic_indices, postsynaptic_index,
258258
syn_dict.update({'weight': weights, 'delay': delays})
259259

260260
if postsynaptic_cell.celltype.standard_receptor_type:
261-
# For Tsodyks-Markram synapses models we set the "tau_psc" parameter to match
262-
# the relevant "tau_syn" parameter from the post-synaptic neuron.
263-
if 'tsodyks' in self.nest_synapse_model:
261+
# For the standard TsodyksMarkramSynapse, copy "tau_psc" from the
262+
# post-synaptic neuron's tau_syn so they stay consistent. For
263+
# native_synapse_type, the user-supplied tau_psc is left untouched.
264+
if isinstance(self.synapse_type, TsodyksMarkramSynapse):
264265
translations = postsynaptic_cell.celltype.translations
265266
if self.receptor_type == 'inhibitory':
266267
param_name = translations['tau_syn_I']['translated_name']

test/system/test_nest.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,77 @@ def test_tsodyks_markram_synapse():
191191
assert_array_equal(tau_psc, np.arange(0.2, 0.7, 0.1))
192192

193193

194+
def test_native_tsodyks_synapse_convergent_connect():
195+
"""native_synapse_type tsodyks_synapse via _convergent_connect preserves user tau_psc (issue #810)."""
196+
if not have_nest:
197+
pytest.skip("nest not available")
198+
import nest
199+
sim = pyNN.nest
200+
sim.setup()
201+
spike_source = sim.Population(1, sim.SpikeSourceArray(spike_times=np.arange(10, 100, 10)))
202+
neurons = sim.Population(5, sim.IF_cond_exp(e_rev_I=-75, tau_syn_I=np.arange(0.2, 0.7, 0.1)))
203+
synapse_type = sim.native_synapse_type('tsodyks_synapse')(
204+
U=0.04, tau_rec=100.0, tau_fac=1000.0, weight=10.0, delay=0.5, tau_psc=5.0)
205+
connector = sim.AllToAllConnector()
206+
prj = sim.Projection(spike_source, neurons, connector,
207+
receptor_type='inhibitory',
208+
synapse_type=synapse_type)
209+
connections = nest.GetConnections(
210+
nest.NodeCollection(list(prj._sources)),
211+
synapse_model=prj.nest_synapse_model)
212+
tau_psc = np.array(nest.GetStatus(connections, 'tau_psc'))
213+
assert_array_equal(tau_psc, [5.0] * 5)
214+
sim.end()
215+
216+
217+
def test_native_tsodyks_synapse_native_connect():
218+
"""native_synapse_type tsodyks_synapse via _connect (NativeRNG) preserves user tau_psc (issue #810)."""
219+
if not have_nest:
220+
pytest.skip("nest not available")
221+
import nest
222+
sim = pyNN.nest
223+
sim.setup()
224+
spike_source = sim.Population(1, sim.SpikeSourceArray(spike_times=np.arange(10, 100, 10)))
225+
neurons = sim.Population(5, sim.IF_cond_exp(e_rev_I=-75, tau_syn_I=3.0))
226+
synapse_type = sim.native_synapse_type('tsodyks_synapse')(
227+
U=0.04, tau_rec=100.0, tau_fac=1000.0, weight=10.0, delay=0.5, tau_psc=5.0)
228+
rng = sim.NativeRNG(seed=1234)
229+
connector = sim.FixedProbabilityConnector(p_connect=1.0, rng=rng)
230+
prj = sim.Projection(spike_source, neurons, connector,
231+
receptor_type='inhibitory',
232+
synapse_type=synapse_type)
233+
connections = nest.GetConnections(
234+
nest.NodeCollection(list(prj._sources)),
235+
synapse_model=prj.nest_synapse_model)
236+
tau_psc = np.array(nest.GetStatus(connections, 'tau_psc'))
237+
assert_array_equal(tau_psc, [5.0] * 5)
238+
sim.end()
239+
240+
241+
def test_native_tsodyks2_synapse():
242+
"""native_synapse_type tsodyks2_synapse creates projection without error (issue #810)."""
243+
if not have_nest:
244+
pytest.skip("nest not available")
245+
import nest
246+
sim = pyNN.nest
247+
sim.setup()
248+
spike_source = sim.Population(1, sim.SpikeSourceArray(spike_times=np.arange(10, 100, 10)))
249+
neurons = sim.Population(5, sim.IF_cond_exp())
250+
synapse_type = sim.native_synapse_type('tsodyks2_synapse')(
251+
U=0.04, tau_rec=100.0, tau_fac=1000.0, weight=10.0, delay=0.5)
252+
connector = sim.AllToAllConnector()
253+
prj = sim.Projection(spike_source, neurons, connector,
254+
receptor_type='excitatory',
255+
synapse_type=synapse_type)
256+
connections = nest.GetConnections(
257+
nest.NodeCollection(list(prj._sources)),
258+
synapse_model=prj.nest_synapse_model)
259+
assert len(connections) == 5
260+
U_vals = np.array(nest.GetStatus(connections, 'U'))
261+
assert_array_equal(U_vals, [0.04] * 5)
262+
sim.end()
263+
264+
194265
def test_native_electrode_types():
195266
""" Test of NativeElectrodeType class. (See issue #506)"""
196267
if not have_nest:

0 commit comments

Comments
 (0)