Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .github/workflows/full-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Install Linux system dependencies
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get install libltdl-dev libgsl0-dev python3-all-dev openmpi-bin libopenmpi-dev
sudo apt-get install libltdl-dev libgsl0-dev python3-all-dev openmpi-bin libopenmpi-dev libboost-dev
- name: Install basic Python dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -50,15 +50,19 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')
run: |
python -m pip install "cython<3.1.0"
wget https://github.com/nest/nest-simulator/archive/refs/tags/v3.9.tar.gz -O nest-simulator-3.9.tar.gz
tar xzf nest-simulator-3.9.tar.gz
cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local -Dwith-mpi=ON ./nest-simulator-3.9
wget https://github.com/nest/nest-simulator/archive/refs/tags/v3.10_rc2.tar.gz -O nest-simulator-3.10.tar.gz
tar xzf nest-simulator-3.10.tar.gz
cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local -Dwith-mpi=ON ./nest-simulator-3.10_rc2
make
make install
- name: Install Arbor
if: startsWith(matrix.os, 'ubuntu')
run: |
python -m pip install arbor==0.9.0 libNeuroML morphio
- name: Install NESTML
if: startsWith(matrix.os, 'ubuntu')
run: |
python -m pip install https://github.com/nest/nestml/archive/refs/tags/v8.3.0-rc2.tar.gz
- name: Install PyNN itself
run: |
python -m pip install -e ".[test,nestml]"
Expand Down
5 changes: 2 additions & 3 deletions examples/nestml/stdp_synapse.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ model stdp_synapse:
post_trace real = 0.

parameters:
d ms = 1 ms # Synaptic transmission delay
lambda real = 0.01 # (dimensionless) learning rate for causal updates
alpha real = 1 # relative learning rate for acausal firing
tau_tr_pre ms = 20 ms # time constant of presynaptic trace
Expand All @@ -83,7 +82,7 @@ model stdp_synapse:
post_spikes <- spike

output:
spike(weight real, delay ms)
spike

onReceive(post_spikes):
post_trace += 1
Expand All @@ -102,7 +101,7 @@ model stdp_synapse:
w = max(Wmin, w_)

# deliver spike to postsynaptic partner
emit_spike(w, d)
emit_spike(w)

update:
integrate_odes()
9 changes: 4 additions & 5 deletions examples/nestml/tsodyks_synapse.nestml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
model tsodyks_synapse_nestml:
parameters:
w real = 1 # Synaptic weight
d ms = 1 ms # Dendritic delay (required by PyNESTML; NEST applies transmission delay at connection level)
tau_psc ms = 3 ms # Time constant of postsynaptic current
tau_fac ms = 0 ms # Time constant for facilitation (0 = no facilitation)
tau_rec ms = 800 ms # Time constant for recovery from depression
Expand All @@ -10,20 +9,20 @@ model tsodyks_synapse_nestml:
state:
x real = 1 # Fraction of synaptic resources available
y real = 0 # Fraction of resources in use
u real = 0.5 # Running value of utilisation
u real = U # Running value of utilisation
t_last_update ms = 0 ms

input:
pre_spikes <- spike

output:
spike(weight real, delay ms)
spike

onReceive(pre_spikes):
dt ms = t - t_last_update
t_last_update = t

Puu real = tau_fac == 0 ms ? 0 : exp(-dt / tau_fac)
Puu real = tau_fac == 0 ? 0 : exp(-dt / tau_fac)
Pyy real = exp(-dt / tau_psc)
Pzz real = exp(-dt / tau_rec)
Pxy real = ((Pzz - 1) * tau_rec - (Pyy - 1) * tau_psc) / (tau_psc - tau_rec)
Expand All @@ -39,4 +38,4 @@ model tsodyks_synapse_nestml:
x -= delta_y_tsp
y += delta_y_tsp

emit_spike(delta_y_tsp * w, d)
emit_spike(delta_y_tsp * w)
7 changes: 2 additions & 5 deletions pyNN/nest/cells.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_defaults(model_name):
for name, value in defaults.items():
if name in variables:
default_initial_values[name] = value
elif name not in ignore:
elif name not in ignore and not name.startswith('__'):
if isinstance(value, valid_types):
default_params[name] = conversion.make_pynn_compatible(value)
else:
Expand All @@ -53,10 +53,7 @@ def get_receptor_types(model_name):


def get_recordables(model_name):
try:
return [name for name in nest.GetDefaults(model_name, "recordables")]
except nest.NESTError:
return []
return list(nest.GetDefaults(model_name).get("recordables", []))


def native_cell_type(model_name):
Expand Down
11 changes: 10 additions & 1 deletion pyNN/nest/extensions/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,23 @@ add_custom_target( dist
)


# On macOS, loadable modules need -undefined dynamic_lookup so that NEST
# kernel symbols (provided by nestkernel_api.so at Python import time) are
# resolved at dlopen time rather than requiring a libnest.so at link time.
if ( APPLE )
set( MACOS_LINK_FLAGS "-undefined dynamic_lookup" )
else ()
set( MACOS_LINK_FLAGS "" )
endif ()

# Create a module for loading at runtime
# with the `Install` command.
add_library( ${MODULE_NAME}_module MODULE ${MODULE_SOURCES} )
target_link_libraries(${MODULE_NAME}_module ${USER_LINK_LIBRARIES})
set_target_properties( ${MODULE_NAME}_module
PROPERTIES
COMPILE_FLAGS "${NEST_CXXFLAGS} -DLTX_MODULE"
LINK_FLAGS "${NEST_LIBS}"
LINK_FLAGS "${NEST_LIBS} ${MACOS_LINK_FLAGS}"
PREFIX ""
OUTPUT_NAME ${MODULE_NAME} )
install( TARGETS ${MODULE_NAME}_module
Expand Down
19 changes: 10 additions & 9 deletions pyNN/nest/extensions/simple_stochastic_synapse.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

// Includes from nestkernel:
#include "connection.h"
#include "dictionary.h"
#include "kernel_manager.h"


Expand Down Expand Up @@ -156,15 +157,15 @@ class simple_stochastic_synapse : public nest::Connection< targetidentifierT >
// data member holding the weight.

//! Store connection status information in dictionary
void get_status( DictionaryDatum& d ) const;
void get_status( Dictionary& d ) const;

/**
* Set connection status.
*
* @param d Dictionary with new parameter values
* @param cm ConnectorModel is passed along to validate new delay values
*/
void set_status( const DictionaryDatum& d, nest::ConnectorModel& cm );
void set_status( const Dictionary& d, nest::ConnectorModel& cm );

//! Allows efficient initialization on construction
void
Expand Down Expand Up @@ -203,23 +204,23 @@ simple_stochastic_synapse< targetidentifierT >::send( nest::Event& e,
template < typename targetidentifierT >
void
simple_stochastic_synapse< targetidentifierT >::get_status(
DictionaryDatum& d ) const
Dictionary& d ) const
{
ConnectionBase::get_status( d );
def< double >( d, nest::names::weight, weight_ );
def< double >( d, nest::names::p, p_ );
def< long >( d, nest::names::size_of, sizeof( *this ) );
d[ nest::names::weight ] = weight_;
d[ nest::names::p ] = p_;
d[ nest::names::size_of ] = static_cast< long >( sizeof( *this ) );
}

template < typename targetidentifierT >
void
simple_stochastic_synapse< targetidentifierT >::set_status(
const DictionaryDatum& d,
const Dictionary& d,
nest::ConnectorModel& cm )
{
ConnectionBase::set_status( d, cm );
updateValue< double >( d, nest::names::weight, weight_ );
updateValue< double >( d, nest::names::p, p_ );
d.update_value( nest::names::weight, weight_ );
d.update_value( nest::names::p, p_ );
}

} // namespace
Expand Down
5 changes: 3 additions & 2 deletions pyNN/nest/extensions/stochastic_stp_synapse.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

// Includes from nestkernel:
#include "connection.h"
#include "dictionary.h"

/* BeginUserDocs: synapse, short-term plasticity

Expand Down Expand Up @@ -93,13 +94,13 @@ class stochastic_stp_synapse : public nest::Connection< targetidentifierT >
/**
* Get all properties of this connection and put them into a dictionary.
*/
void get_status( DictionaryDatum& d ) const;
void get_status( Dictionary& d ) const;

/**
* Set default properties of this connection from the values given in
* dictionary.
*/
void set_status( const DictionaryDatum& d, nest::ConnectorModel& cm );
void set_status( const Dictionary& d, nest::ConnectorModel& cm );

/**
* Send an event to the receiver of this connection.
Expand Down
29 changes: 14 additions & 15 deletions pyNN/nest/extensions/stochastic_stp_synapse_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
#include "connector_model.h"
#include "nest_names.h"

// Includes from sli:
#include "dictutils.h"
// Includes from nestkernel:
#include "dictionary.h"

namespace pynn
{
Expand Down Expand Up @@ -55,30 +55,29 @@ stochastic_stp_synapse< targetidentifierT >::stochastic_stp_synapse(
template < typename targetidentifierT >
void
stochastic_stp_synapse< targetidentifierT >::get_status(
DictionaryDatum& d ) const
Dictionary& d ) const
{
ConnectionBase::get_status( d );
def< double >( d, nest::names::weight, weight_ );
def< double >( d, nest::names::dU, U_ );
def< double >( d, nest::names::u, u_ );
def< double >( d, nest::names::tau_rec, tau_rec_ );
def< double >( d, nest::names::tau_fac, tau_fac_ );
d[ nest::names::weight ] = weight_;
d[ nest::names::dU ] = U_;
d[ nest::names::u ] = u_;
d[ nest::names::tau_rec ] = tau_rec_;
d[ nest::names::tau_fac ] = tau_fac_;
}


template < typename targetidentifierT >
void
stochastic_stp_synapse< targetidentifierT >::set_status(
const DictionaryDatum& d,
const Dictionary& d,
nest::ConnectorModel& cm )
{
ConnectionBase::set_status( d, cm );
updateValue< double >( d, nest::names::weight, weight_ );

updateValue< double >( d, nest::names::dU, U_ );
updateValue< double >( d, nest::names::u, u_ );
updateValue< double >( d, nest::names::tau_rec, tau_rec_ );
updateValue< double >( d, nest::names::tau_fac, tau_fac_ );
d.update_value( nest::names::weight, weight_ );
d.update_value( nest::names::dU, U_ );
d.update_value( nest::names::u, u_ );
d.update_value( nest::names::tau_rec, tau_rec_ );
d.update_value( nest::names::tau_fac, tau_fac_ );
}

} // of namespace pynn
Expand Down
20 changes: 19 additions & 1 deletion pyNN/nest/nestml.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def nestml_synapse_type(
nestml_description,
postsynaptic_neuron_nestml_description=None,
weight_variable="w",
delay_variable="d"
delay_variable=None
):
"""
Register a NESTML synapse description and return a synapse type class.
Expand Down Expand Up @@ -270,6 +270,24 @@ def _compile_and_resolve():
codegen_opts=codegen_opts,
)
nest.Install(module_name)
except nest.NESTErrors.DynamicModuleManagementError as e:
missing_delay = [
entry["name"] for entry in _pending
if entry["type"] == "synapse" and entry["delay_variable"] is None
]
hint = ""
if missing_delay:
hint = (
f"Synapse model(s) {missing_delay} have no delay_variable set. "
"If your NESTML model uses an explicit delay variable, "
"pass delay_variable='<name>' to nestml_synapse_type() "
"to match the delay parameter in your model."
)
raise RuntimeError(
f"Failed to install NESTML module '{module_name}'. "
"NESTML model compilation failed silently. "
f"{hint}"
) from e
finally:
for tmpdir in tmpdirs:
shutil.rmtree(tmpdir, ignore_errors=True)
Expand Down
2 changes: 1 addition & 1 deletion pyNN/nest/populations.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def _set_initial_value_array(self, variable, value):
simulator.state.set_status(self.node_collection[self._mask_local],
variable, local_values)
except nest.NESTError as e:
if "Unused dictionary items" in e.args[0]:
if "Unused dictionary items" in e.args[0] or "Unaccessed" in e.args[0]:
logger.warning("NEST does not allow setting an initial value for %s" % variable)
# should perhaps check whether value-to-be-set is the same as current value,
# and raise an Exception if not, rather than just emit a warning.
Expand Down
26 changes: 22 additions & 4 deletions pyNN/nest/projections.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,10 @@ def _convergent_connect(self, presynaptic_indices, postsynaptic_index,
weights = np.array([weights])
if delays is not None and not np.isscalar(delays):
delays = np.array([delays])
if weights is not None or delays is not None:
syn_dict.update({'weight': weights, 'delay': delays})
if weights is not None:
syn_dict['weight'] = weights
if delays is not None:
syn_dict['delay'] = delays

if postsynaptic_cell.celltype.standard_receptor_type:
# For the standard TsodyksMarkramSynapse, copy "tau_psc" from the
Expand Down Expand Up @@ -463,7 +465,10 @@ def _get_attributes_as_list(self, names):
else:
nest_names.append(name)
values = nest.GetStatus(self.nest_connections, nest_names)
values = np.array(values) # ought to preserve int type for source, target
if isinstance(values, dict): # NEST 3.10_rc1
values = np.array([values[key] for key in nest_names]).T
else:
values = np.array(values) # ought to preserve int type for source, target
if 'weight' in names:
# other attributes could also have scale factors - need to use translation mechanisms
scale_factors = np.ones(len(names))
Expand Down Expand Up @@ -492,7 +497,20 @@ def _get_attributes_as_arrays(self, names, multiple_synapses='sum'):
value_arr = np.nan * np.ones((self.pre.size, self.post.size))
connection_attributes = nest.GetStatus(self.nest_connections,
('source', 'target', attribute_name))
for conn in connection_attributes:
# GetStatus return format varies by NEST version:
# dict {key: [values]} — seen in some NEST 3.x builds
# list of dicts — NEST 3.10rc1
# list of tuples — older NEST
if isinstance(connection_attributes, dict):
conn_iter = zip(connection_attributes['source'],
connection_attributes['target'],
connection_attributes[attribute_name])
elif connection_attributes and isinstance(connection_attributes[0], dict):
conn_iter = ((c['source'], c['target'], c[attribute_name])
for c in connection_attributes)
else:
conn_iter = connection_attributes
for conn in conn_iter:
# (offset is always 0,0 for connections created with connect())
src, tgt, value = conn
addr = self.pre.id_to_index(src), self.post.id_to_index(tgt)
Expand Down
13 changes: 10 additions & 3 deletions pyNN/nest/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ def _set_spike_precision(self, precision):
spike_precision = property(fget=_get_spike_precision, fset=_set_spike_precision)

def _set_verbosity(self, verbosity):
nest.set_verbosity('M_{}'.format(verbosity.upper()))
try:
nest.set_verbosity('M_{}'.format(verbosity.upper()))
except AttributeError:
vb_level = getattr(nest.VerbosityLevel, verbosity.upper())
nest.verbosity = vb_level
verbosity = property(fset=_set_verbosity)

def set_status(self, nodes, params, val=None):
Expand Down Expand Up @@ -308,8 +312,11 @@ def clear(self):
self.current_sources = []
self.recording_devices = []
self.recorders = set()
# clear the sli stack, if this is not done --> memory leak cause the stack increases
nest.ll_api.sr('clear')
try:
# clear the sli stack, if this is not done --> memory leak cause the stack increases
nest.ll_api.sr('clear')
except AttributeError: # NEST 3.10+
pass
# reset the simulation kernel
nest.ResetKernel()
# but this reverts some of the PyNN settings, so we have to repeat them (see NEST #716)
Expand Down
Loading