From 27da9d79ece044cf991e7a049f66ab4690c17031 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 8 Oct 2025 14:03:57 +0200 Subject: [PATCH 1/5] Add NEURON 9 compatibility to mod files --- pyNN/neuron/nmodl/gif.mod | 9 +++++++-- pyNN/neuron/nmodl/netstim2.mod | 7 ++++++- pyNN/neuron/nmodl/quantal_stp.mod | 9 +++++++-- pyNN/neuron/nmodl/stochastic_synapse.mod | 11 ++++++++--- pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod | 11 ++++++++--- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/pyNN/neuron/nmodl/gif.mod b/pyNN/neuron/nmodl/gif.mod index 7829fcd34..b14599b5d 100644 --- a/pyNN/neuron/nmodl/gif.mod +++ b/pyNN/neuron/nmodl/gif.mod @@ -55,8 +55,13 @@ VERBATIM #include #include +#ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); void* nrn_random_arg(int argpos); +#define RANDCAST +#else +#define RANDCAST (Rand*) +#endif ENDVERBATIM ASSIGNED { @@ -199,7 +204,7 @@ VERBATIM : each instance. However, the corresponding hoc Random : distribution MUST be set to Random.negexp(1) */ - value = nrn_random_pick(_p_rng); + value = nrn_random_pick(RANDCAST _p_rng); //printf("random stream for this simulation = %lf\n",value); return value; }else{ @@ -208,7 +213,7 @@ ENDVERBATIM : independent of nhost or which host this instance is on : is desired, since each instance on this cpu draws from : the same stream - value = scop_random(1) + value = scop_random() VERBATIM } ENDVERBATIM diff --git a/pyNN/neuron/nmodl/netstim2.mod b/pyNN/neuron/nmodl/netstim2.mod index c612422ef..eb60a82ca 100755 --- a/pyNN/neuron/nmodl/netstim2.mod +++ b/pyNN/neuron/nmodl/netstim2.mod @@ -72,8 +72,13 @@ FUNCTION invl(mean (ms)) (ms) { } } VERBATIM +#ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); void* nrn_random_arg(int argpos); +#define RANDCAST +#else +#define RANDCAST (Rand*) +#endif ENDVERBATIM FUNCTION erand() { @@ -84,7 +89,7 @@ VERBATIM : each instance. However, the corresponding hoc Random : distribution MUST be set to Random.negexp(1) */ - _lerand = nrn_random_pick(_p_donotuse); + _lerand = nrn_random_pick(RANDCAST _p_donotuse); }else{ /* only can be used in main thread */ if (_nt != nrn_threads) { diff --git a/pyNN/neuron/nmodl/quantal_stp.mod b/pyNN/neuron/nmodl/quantal_stp.mod index 6d9765016..f7ed37c9e 100644 --- a/pyNN/neuron/nmodl/quantal_stp.mod +++ b/pyNN/neuron/nmodl/quantal_stp.mod @@ -82,8 +82,13 @@ NET_RECEIVE(w, available, t_last (ms)) { } VERBATIM +#ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); void* nrn_random_arg(int argpos); +#define RANDCAST +#else +#define RANDCAST (Rand*) +#endif ENDVERBATIM PROCEDURE setRNG() { @@ -110,12 +115,12 @@ VERBATIM : each instance. However, the corresponding hoc Random : distribution MUST be set to Random.negexp(1) */ - value = nrn_random_pick(_p_rng); + value = nrn_random_pick(RANDCAST _p_rng); //printf("random stream for this simulation = %lf\n",value); return value; } else { ENDVERBATIM - value = scop_random(1) + value = scop_random() VERBATIM } ENDVERBATIM diff --git a/pyNN/neuron/nmodl/stochastic_synapse.mod b/pyNN/neuron/nmodl/stochastic_synapse.mod index 87da7bada..8b12cdd1f 100644 --- a/pyNN/neuron/nmodl/stochastic_synapse.mod +++ b/pyNN/neuron/nmodl/stochastic_synapse.mod @@ -21,8 +21,13 @@ VERBATIM #include #include +#ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); -void* nrn_random_arg(int argpos); +Rand* nrn_random_arg(int argpos); +#define RANDCAST +#else +#define RANDCAST (Rand*) +#endif ENDVERBATIM @@ -63,12 +68,12 @@ VERBATIM : each instance. However, the corresponding hoc Random : distribution MUST be set to Random.negexp(1) */ - value = nrn_random_pick(_p_rng); + value = nrn_random_pick(RANDCAST _p_rng); //printf("random stream for this simulation = %lf\n",value); return value; } else { ENDVERBATIM - value = scop_random(1) + value = scop_random() VERBATIM } ENDVERBATIM diff --git a/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod b/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod index 519e578ca..646b86847 100644 --- a/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod +++ b/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod @@ -85,8 +85,13 @@ NET_RECEIVE(w, p_surv, t_surv) { } VERBATIM +#ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); -void* nrn_random_arg(int argpos); +Rand* nrn_random_arg(int argpos); +#define RANDCAST +#else +#define RANDCAST (Rand*) +#endif ENDVERBATIM PROCEDURE setRNG() { @@ -113,12 +118,12 @@ VERBATIM : each instance. However, the corresponding hoc Random : distribution MUST be set to Random.negexp(1) */ - value = nrn_random_pick(_p_rng); + value = nrn_random_pick(RANDCAST _p_rng); //printf("random stream for this simulation = %lf\n",value); return value; } else { ENDVERBATIM - value = scop_random(1) + value = scop_random() VERBATIM } ENDVERBATIM From 766233794eef65f79de52b368d780becd393c224 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 8 Oct 2025 15:09:06 +0200 Subject: [PATCH 2/5] Fix mechanism loading --- pyNN/neuron/simulator.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pyNN/neuron/simulator.py b/pyNN/neuron/simulator.py index f95c33391..d57c8971e 100644 --- a/pyNN/neuron/simulator.py +++ b/pyNN/neuron/simulator.py @@ -92,11 +92,13 @@ def load_mechanisms(path): else: arch_list = [platform.machine(), 'i686', 'x86_64', 'powerpc', 'umac'] for arch in arch_list: - lib_path = os.path.join(path, arch, '.libs', 'libnrnmech.so') - if os.path.exists(lib_path): - h.nrn_load_dll(lib_path) - nrn_dll_loaded.append(path) - return + path_list = ['.so', '.dylib'] + for p in path_list: + lib_path = os.path.join(path, arch, f'libnrnmech{p}') + if os.path.exists(lib_path): + h.nrn_load_dll(lib_path) + nrn_dll_loaded.append(path) + return raise IOError( f"NEURON mechanisms not found in {path}. " "You may need to run 'nrnivmodl' in this directory.") From 842abf5cf1aa734ae491643b0156e0f8ce6898f8 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 14 Oct 2025 10:51:26 +0200 Subject: [PATCH 3/5] Partially revert --- pyNN/neuron/nmodl/stochastic_synapse.mod | 2 +- pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyNN/neuron/nmodl/stochastic_synapse.mod b/pyNN/neuron/nmodl/stochastic_synapse.mod index 8b12cdd1f..8a8906c19 100644 --- a/pyNN/neuron/nmodl/stochastic_synapse.mod +++ b/pyNN/neuron/nmodl/stochastic_synapse.mod @@ -23,7 +23,7 @@ VERBATIM #ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); -Rand* nrn_random_arg(int argpos); +void* nrn_random_arg(int argpos); #define RANDCAST #else #define RANDCAST (Rand*) diff --git a/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod b/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod index 646b86847..5e2fc104e 100644 --- a/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod +++ b/pyNN/neuron/nmodl/stochastic_tsodyksmarkram.mod @@ -87,7 +87,7 @@ NET_RECEIVE(w, p_surv, t_surv) { VERBATIM #ifndef NRN_VERSION_GTEQ_8_2_0 double nrn_random_pick(void* r); -Rand* nrn_random_arg(int argpos); +void* nrn_random_arg(int argpos); #define RANDCAST #else #define RANDCAST (Rand*) From 3e884891d96a45c284b887786a0f7bccf0ab5d3e Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 14 Oct 2025 16:51:49 +0200 Subject: [PATCH 4/5] Add THREADSAFE to mod file Fixes the segfault --- pyNN/neuron/nmodl/tsodyksmarkram.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/pyNN/neuron/nmodl/tsodyksmarkram.mod b/pyNN/neuron/nmodl/tsodyksmarkram.mod index c4580fe3e..569e014aa 100644 --- a/pyNN/neuron/nmodl/tsodyksmarkram.mod +++ b/pyNN/neuron/nmodl/tsodyksmarkram.mod @@ -5,6 +5,7 @@ Andrew Davison, UNIC, CNRS, 2013 ENDCOMMENT NEURON { + THREADSAFE POINT_PROCESS TsodyksMarkramWA RANGE tau_rec, tau_facil, U, u0, tau_syn POINTER wsyn From 08f75aeb8bf958269603eeb525c60b24279302a8 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 16 Oct 2025 09:51:42 +0200 Subject: [PATCH 5/5] Use `load_mechanisms` from NEURON itself --- pyNN/neuron/simulator.py | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/pyNN/neuron/simulator.py b/pyNN/neuron/simulator.py index d57c8971e..09c5d10e2 100644 --- a/pyNN/neuron/simulator.py +++ b/pyNN/neuron/simulator.py @@ -26,6 +26,7 @@ import warnings import numpy as np +import neuron from neuron import h, nrn_dll_loaded from .. import common @@ -76,32 +77,11 @@ def load_mechanisms(path): which the directory 'i686' (or 'x86_64' or 'powerpc' depending on your platform) was created. """ - import platform - - if path in nrn_dll_loaded: - logger.warning("Mechanisms already loaded from path: %s" % path) - return - # in case NEURON is assuming a different architecture to Python, - # we try multiple possibilities - if platform.system() == 'Windows': - lib_path = os.path.join(path, 'nrnmech.dll') - if os.path.exists(lib_path): - h.nrn_load_dll(lib_path) - nrn_dll_loaded.append(path) - return - else: - arch_list = [platform.machine(), 'i686', 'x86_64', 'powerpc', 'umac'] - for arch in arch_list: - path_list = ['.so', '.dylib'] - for p in path_list: - lib_path = os.path.join(path, arch, f'libnrnmech{p}') - if os.path.exists(lib_path): - h.nrn_load_dll(lib_path) - nrn_dll_loaded.append(path) - return - raise IOError( - f"NEURON mechanisms not found in {path}. " - "You may need to run 'nrnivmodl' in this directory.") + result = neuron.load_mechanisms(path) + if not result: + raise IOError( + f"NEURON mechanisms not found in {path}. " + "You may need to run 'nrnivmodl' in this directory.") def is_point_process(obj):