From c39f57a2a4a30d82fb5c4813568460a52cc70603 Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Wed, 22 Feb 2023 20:29:57 +0100 Subject: [PATCH 01/21] Change default dtype from float to int for structural plasticity update interval --- pynest/nest/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pynest/nest/__init__.py b/pynest/nest/__init__.py index 47aca7862d..1d4cf345ac 100644 --- a/pynest/nest/__init__.py +++ b/pynest/nest/__init__.py @@ -312,7 +312,7 @@ def __dir__(self): + " manager will make changes in the structure of the network (" + " creation and deletion of plastic synapses)" ), - default=10000.0, + default=10000, ) growth_curves = KernelAttribute( "list[str]", @@ -490,6 +490,7 @@ class ModuleClass(types.ModuleType): users install missing optional modules :type optional_hint: str """ + def lazy_loader(self): cls = type(self) delattr(cls, module_name) From 951f6c234130f8ab2f91de46fc3f3d669539accd Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 23 Feb 2023 13:03:00 +0100 Subject: [PATCH 02/21] Default value should given as integer in docs --- nestkernel/kernel_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestkernel/kernel_manager.h b/nestkernel/kernel_manager.h index dcfdf7b7ea..85e78812a2 100644 --- a/nestkernel/kernel_manager.h +++ b/nestkernel/kernel_manager.h @@ -146,7 +146,7 @@ element. structural_plasticity_update_interval integertype - Defines the time interval in ms at which the structural plasticity manager will make changes in the structure of the network (creation - and deletion of plastic synapses), defaults to 10000.0. + and deletion of plastic synapses), defaults to 10000. synapse_models arraytype - The list of the available synapse models (read only). Waveform relaxation method (wfr) From 4647e367d81ae73c8145f251158739e594152a01 Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 23 Feb 2023 13:54:04 +0100 Subject: [PATCH 03/21] State correct attribute in Exception message --- nestkernel/simulation_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestkernel/simulation_manager.cpp b/nestkernel/simulation_manager.cpp index 41a2c7217f..2fa7d90071 100644 --- a/nestkernel/simulation_manager.cpp +++ b/nestkernel/simulation_manager.cpp @@ -265,7 +265,7 @@ nest::SimulationManager::set_status( const DictionaryDatum& d ) } else { - throw KernelException( "Change of tics_per_step requires simultaneous specification of resolution." ); + throw KernelException( "Change of tics_per_ms requires simultaneous specification of resolution." ); } } From 7f22b29b07714ea3e576d567d58a9e90135b05c3 Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 23 Feb 2023 14:12:26 +0100 Subject: [PATCH 04/21] Change ms_per_tic and tics_per_step to read-only --- pynest/nest/__init__.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pynest/nest/__init__.py b/pynest/nest/__init__.py index 1d4cf345ac..129fd8d33a 100644 --- a/pynest/nest/__init__.py +++ b/pynest/nest/__init__.py @@ -152,13 +152,28 @@ def __dir__(self): "float", "The minimum delay in the network", default=0.1 ) ms_per_tic = KernelAttribute( - "float", "The number of milliseconds per tic", default=0.001 + "float", + ( + "The number of milliseconds per tic. Calculated by " + "ms_per_tic = 1 / tics_per_ms" + ), + readonly=True, ) tics_per_ms = KernelAttribute( - "float", "The number of tics per millisecond", default=1000.0 + "float", + ( + "The number of tics per millisecond. Change of tics_per_ms " + "requires simultaneous specification of resolution" + ), + default=1000.0 ) tics_per_step = KernelAttribute( - "int", "The number of tics per simulation time step", default=100 + "int", + ( + "The number of tics per simulation time step. Calculated by " + + "tics_per_step = resolution * tics_per_ms" + ), + readonly=True ) T_max = KernelAttribute( "float", "The largest representable time value", readonly=True From 5dd2d2411652b85967921a06c57248823f29ff12 Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 23 Feb 2023 14:33:52 +0100 Subject: [PATCH 05/21] Remember to concatenate strings --- pynest/nest/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pynest/nest/__init__.py b/pynest/nest/__init__.py index 129fd8d33a..caac006664 100644 --- a/pynest/nest/__init__.py +++ b/pynest/nest/__init__.py @@ -155,7 +155,7 @@ def __dir__(self): "float", ( "The number of milliseconds per tic. Calculated by " - "ms_per_tic = 1 / tics_per_ms" + + "ms_per_tic = 1 / tics_per_ms" ), readonly=True, ) @@ -163,7 +163,7 @@ def __dir__(self): "float", ( "The number of tics per millisecond. Change of tics_per_ms " - "requires simultaneous specification of resolution" + + "requires simultaneous specification of resolution" ), default=1000.0 ) From 01c0520a1909d2b283e69b079ff055723023b95e Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 23 Feb 2023 14:47:41 +0100 Subject: [PATCH 06/21] Update ms_per_tic and tics_per_step docs in kernel_manager --- nestkernel/kernel_manager.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nestkernel/kernel_manager.h b/nestkernel/kernel_manager.h index 85e78812a2..f1f42cd07f 100644 --- a/nestkernel/kernel_manager.h +++ b/nestkernel/kernel_manager.h @@ -60,11 +60,13 @@ s; read only). min_update_time doubletype - Shortest wall-clock time measured so far for a full update step (in s; read only). - ms_per_tic doubletype - The number of milliseconds per tic, defaults to 0.001. + ms_per_tic doubletype - The number of milliseconds per tic, calculated by. + ms_per_tic = 1 / tics_per_ms (read_only). resolution doubletype - The resolution of the simulation (in ms), defaults to 0.1. time doubletype - The current simulation time (in ms). tics_per_ms doubletype - The number of tics per millisecond, defaults to 1000.0. - tics_per_step integertype - The number of tics per simulation time step, defaults to 100. + tics_per_step integertype - The number of tics per simulation time step, calculated by. + tics_per_step = resolution * tics_per_ms (read_only). to_do integertype - The number of steps yet to be simulated (read only). T_max doubletype - The largest representable time value (in ms; read only). T_min doubletype - The smallest representable time value (in ms; read only). From 93c57380234a8fa60adf4e056d8b522b49be0378 Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Fri, 24 Feb 2023 13:31:58 +0100 Subject: [PATCH 07/21] Fix typo --- nestkernel/kernel_manager.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nestkernel/kernel_manager.h b/nestkernel/kernel_manager.h index f1f42cd07f..a1c2fe2671 100644 --- a/nestkernel/kernel_manager.h +++ b/nestkernel/kernel_manager.h @@ -60,12 +60,12 @@ s; read only). min_update_time doubletype - Shortest wall-clock time measured so far for a full update step (in s; read only). - ms_per_tic doubletype - The number of milliseconds per tic, calculated by. + ms_per_tic doubletype - The number of milliseconds per tic, calculated by ms_per_tic = 1 / tics_per_ms (read_only). resolution doubletype - The resolution of the simulation (in ms), defaults to 0.1. time doubletype - The current simulation time (in ms). tics_per_ms doubletype - The number of tics per millisecond, defaults to 1000.0. - tics_per_step integertype - The number of tics per simulation time step, calculated by. + tics_per_step integertype - The number of tics per simulation time step, calculated by tics_per_step = resolution * tics_per_ms (read_only). to_do integertype - The number of steps yet to be simulated (read only). T_max doubletype - The largest representable time value (in ms; read only). From 63563ed93a259fe861ebed69961a52f300b1b85d Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Thu, 23 Mar 2023 22:51:36 +0100 Subject: [PATCH 08/21] Convert multimeter test from SLI to Python implementation --- testsuite/pytests/test_multimeter.py | 78 +++++++++++++++ testsuite/unittests/test_multimeter.sli | 127 ------------------------ 2 files changed, 78 insertions(+), 127 deletions(-) create mode 100644 testsuite/pytests/test_multimeter.py delete mode 100644 testsuite/unittests/test_multimeter.sli diff --git a/testsuite/pytests/test_multimeter.py b/testsuite/pytests/test_multimeter.py new file mode 100644 index 0000000000..8a4e5f8a46 --- /dev/null +++ b/testsuite/pytests/test_multimeter.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# +# test_multimeter.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# NEST is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with NEST. If not, see . + +import pytest +import nest + + +@pytest.fixture +def _set_resolution(): + """ + Set resolution to power of two to avoid rounding issues. + """ + + nest.ResetKernel() + nest.resolution = 2**-3 + + +# Obtain all models with non-empty recordables list +models = [model for model in nest.node_models + if ('recordables' in (dflts := nest.GetDefaults(model)) + and dflts['recordables'])] + +@pytest.mark.parametrize('model', models) +def test_recordables_are_recorded(_set_resolution, model): + """ + Test that recordables are recorded. + + For each model with recordables, set up minimal simulation + recording from all recordables and test that data is provided. + I also checks that the recording interval can be set. + + @note This test does not check if the data is meaningful. + """ + + recording_interval = 2 + simtime = 10 + num_data_expected = simtime / recording_interval - 1 + + nrn = nest.Create(model) + recordables = nrn.recordables + mm = nest.Create('multimeter', {'interval': recording_interval, + 'record_from': recordables}) + nest.Connect(mm, nrn) + nest.Simulate(simtime) + + result = mm.events + + for r in recordables + ('times', 'senders'): + assert r in result + assert len(result[r]) == num_data_expected + + +def test_multimeter_freeze(): + """ + Ensure that frozen parameter can be set to False but not True on multimeter. + """ + + nest.Create('multimeter', params={'frozen': False}) + with pytest.raises(Exception): + nest.Create('multimeter', params={'frozen': True}) diff --git a/testsuite/unittests/test_multimeter.sli b/testsuite/unittests/test_multimeter.sli deleted file mode 100644 index 14db5dc193..0000000000 --- a/testsuite/unittests/test_multimeter.sli +++ /dev/null @@ -1,127 +0,0 @@ -/* - * test_multimeter.sli - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * NEST is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NEST. If not, see . - * - */ - -/** @BeginDocumentation -Name: testsuite::test_multimeter - Minimal test for correct multimeter setup - -Synopsis: (test_multimeter) run -> NEST exits if test fails - -Description: - This test provides a minimal check for correct multimeter setup. - - For each model with a "recordables" property, it creates an instance, - connects a multimeter to them requestin all properties, simulates briefly - and checks that the correct number of data items is collected for each - recordable. - - This test mainly ensures that init_buffers_() initializes the data logger. - If a developer has forgotten to add recordables to get_status(), this test - will ignore the pertaining neuron. - -Author: Hans Ekkehard Plesser, 2010-05-05 - */ - -(unittest) run -/unittest using - -% use power-of-two resolution to avoid roundof problems -/res -3 dexp def - -% simulation time -/simtime 100. def - -% recording interval --- different from default to check setting works -/recint 2. def - -% number of data points expected -/n_data simtime recint div cvi 1 sub def - -{ - GetKernelStatus /node_models get - { - /model Set - - % some logging information to make failure localization easier - (Testing model: ) model cvs join == - - ResetKernel - << /resolution res >> SetKernelStatus - - % get recordables, if none, return true - model GetDefaults dup - /recordables known - { - % set up for simulation and simulate - /recordables get /recs Set - /n model Create def - - % if the model is a compartmental model, - % we need to add at least a root compartment - model GetDefaults dup - /compartments known - { - n - << - /compartments << /parent_idx -1 >> - >> SetStatus - } - if - - /mm /multimeter << /interval recint /record_from recs >> Create def - mm n Connect - simtime Simulate - - % check results - /result mm /events get def - true - recs % for each recordable, see if we have correct number of data points - { - result exch get cva - length n_data eq - and - } - Fold - } - { ; true } - ifelse - } - Map - - % see if all entries are true - true exch { and } Fold - -} -assert_or_die - -% make sure multimeter cannot be frozen -{ - ResetKernel - /multimeter Create << /frozen true >> SetStatus -} fail_or_die - -% but this should pass -{ - ResetKernel - /multimeter Create << /frozen false >> SetStatus -} pass_or_die - -endusing From d06cbf78e24b41a57b4ac51069b8d1c05f5aa5ee Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Sat, 25 Mar 2023 22:00:04 +0100 Subject: [PATCH 09/21] Fix PEP8 --- testsuite/pytests/test_multimeter.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testsuite/pytests/test_multimeter.py b/testsuite/pytests/test_multimeter.py index 8a4e5f8a46..b28aa63941 100644 --- a/testsuite/pytests/test_multimeter.py +++ b/testsuite/pytests/test_multimeter.py @@ -28,7 +28,7 @@ def _set_resolution(): """ Set resolution to power of two to avoid rounding issues. """ - + nest.ResetKernel() nest.resolution = 2**-3 @@ -38,6 +38,7 @@ def _set_resolution(): if ('recordables' in (dflts := nest.GetDefaults(model)) and dflts['recordables'])] + @pytest.mark.parametrize('model', models) def test_recordables_are_recorded(_set_resolution, model): """ @@ -53,7 +54,7 @@ def test_recordables_are_recorded(_set_resolution, model): recording_interval = 2 simtime = 10 num_data_expected = simtime / recording_interval - 1 - + nrn = nest.Create(model) recordables = nrn.recordables mm = nest.Create('multimeter', {'interval': recording_interval, @@ -67,7 +68,7 @@ def test_recordables_are_recorded(_set_resolution, model): assert r in result assert len(result[r]) == num_data_expected - + def test_multimeter_freeze(): """ Ensure that frozen parameter can be set to False but not True on multimeter. From a6f95913e834a1574586e37a1d9fbed08d72f41a Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Sat, 25 Mar 2023 22:06:48 +0100 Subject: [PATCH 10/21] Pip install pycodestyle>=2.9 in build matrix to ensure assignment operator is supported --- .github/workflows/nestbuildmatrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nestbuildmatrix.yml b/.github/workflows/nestbuildmatrix.yml index 5620149441..de5479295d 100644 --- a/.github/workflows/nestbuildmatrix.yml +++ b/.github/workflows/nestbuildmatrix.yml @@ -70,7 +70,7 @@ jobs: # --force-reinstall required to ensure executable is linked from bin dir in PATH python -m pip install --force-reinstall clang-format==13.0 python -c "import setuptools; print('package location:', setuptools.__file__)" - python -m pip install --force-reinstall --upgrade scipy 'junitparser>=2' numpy pytest pytest-timeout pytest-xdist mpi4py cython matplotlib terminaltables pandoc pandas + python -m pip install --force-reinstall --upgrade scipy 'junitparser>=2' numpy pytest pytest-timeout pytest-xdist mpi4py cython matplotlib terminaltables pandoc pandas 'pycodestyle>=2.9' python -c "import pytest; print('package location:', pytest.__file__)" pip list From f904705d882ced5c68a89228927d0d8b2d425766 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Sat, 25 Mar 2023 22:10:41 +0100 Subject: [PATCH 11/21] Make models list a generator --- testsuite/pytests/test_multimeter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testsuite/pytests/test_multimeter.py b/testsuite/pytests/test_multimeter.py index b28aa63941..578449c5f9 100644 --- a/testsuite/pytests/test_multimeter.py +++ b/testsuite/pytests/test_multimeter.py @@ -34,9 +34,9 @@ def _set_resolution(): # Obtain all models with non-empty recordables list -models = [model for model in nest.node_models +models = (model for model in nest.node_models if ('recordables' in (dflts := nest.GetDefaults(model)) - and dflts['recordables'])] + and dflts['recordables'])) @pytest.mark.parametrize('model', models) From 3e47aa046162cecb316de3ec7f8db13e7dd07264 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 27 Mar 2023 08:51:28 +0200 Subject: [PATCH 12/21] Simplified syntax --- testsuite/pytests/test_multimeter.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testsuite/pytests/test_multimeter.py b/testsuite/pytests/test_multimeter.py index 578449c5f9..2e8d75089f 100644 --- a/testsuite/pytests/test_multimeter.py +++ b/testsuite/pytests/test_multimeter.py @@ -34,9 +34,7 @@ def _set_resolution(): # Obtain all models with non-empty recordables list -models = (model for model in nest.node_models - if ('recordables' in (dflts := nest.GetDefaults(model)) - and dflts['recordables'])) +models = (model for model in nest.node_models if nest.GetDefaults(model).get('recordables')) @pytest.mark.parametrize('model', models) From 5e2ef54dbb7b2dfdf6714a7879446273cab8c7d6 Mon Sep 17 00:00:00 2001 From: Jochen Martin Eppler Date: Fri, 7 Apr 2023 16:28:29 +0200 Subject: [PATCH 13/21] Remove NESTServerClient from nest-simulator repository --- doc/htmldoc/connect_nest/nest_server.rst | 74 +++++++++---------- examples/NESTServerClient/NESTServerClient.py | 68 ----------------- examples/NESTServerClient/__init__.py | 23 ------ .../examples/NESTClient_example.py | 64 ---------------- .../examples/NESTClient_script.py | 41 ---------- .../NESTServerClient/examples/__init__.py | 23 ------ examples/NESTServerClient/setup.py | 35 --------- 7 files changed, 36 insertions(+), 292 deletions(-) delete mode 100644 examples/NESTServerClient/NESTServerClient.py delete mode 100644 examples/NESTServerClient/__init__.py delete mode 100644 examples/NESTServerClient/examples/NESTClient_example.py delete mode 100644 examples/NESTServerClient/examples/NESTClient_script.py delete mode 100644 examples/NESTServerClient/examples/__init__.py delete mode 100644 examples/NESTServerClient/setup.py diff --git a/doc/htmldoc/connect_nest/nest_server.rst b/doc/htmldoc/connect_nest/nest_server.rst index e943ee4912..e728e61187 100644 --- a/doc/htmldoc/connect_nest/nest_server.rst +++ b/doc/htmldoc/connect_nest/nest_server.rst @@ -45,13 +45,12 @@ you a better idea of what NEST Server is good for, here are some of its main use cases. One scenario in which NEST Server comes in handy, is if you want to -work on your laptop, but run your NEST simulations on a -machine with higher performance or more memory, for instance, a big -workstation or computer cluster at your lab. For this, you would -deploy NEST Server on the remote machine, and use the provided -:ref:`NEST Server Client ` locally or write your -own client using one of the recipes provided in the :ref:`section on -advanced applications `. +work on your laptop, but run your NEST simulations on a machine with +higher performance or more memory, for instance, a big workstation or +computer cluster at your lab. For this, you would deploy NEST Server +on the remote machine, and use the :ref:`NEST Client ` +locally or write your own client using one of the recipes provided in +the :ref:`section on advanced applications `. `NEST Desktop `_, the web-based graphical user interface for NEST, uses NEST Server as its simulation @@ -148,21 +147,21 @@ completely the same as one coming from the serial version of the NEST Server. The only difference may be that information pertaining to process-local data structures is being replaced by generic values. -.. _nest_server_client: +.. _nest_client: -The NEST Server Client ----------------------- +The NEST Client +--------------- -The easiest way to interact with the NEST Server is the `NEST Server -Client` provided in ``examples/NESTServerClient`` in the source -distribution of NEST. It can be used either by directly starting -a Python session in that directory or installing it by running ``python3 -setup.py install`` therein. NEST itself does not have to be installed -in order to use the NEST Server Client. +The easiest way to interact with the NEST Server is the `NEST Client` +provided in `_. It can be used +either by directly starting a Python session in a clone of that +repository, or by installing it by running ``python3 setup.py +install`` therein. NEST itself does not have to be installed in order +to use the NEST Client. -Using a dynamic function mapping mechanism, the NEST Server Client -supports the same functions as PyNEST does. However, instead of -directly executing calls in NEST, it forwards them together with their +Using a dynamic function mapping mechanism, the NEST Client supports +the same functions as PyNEST does. However, instead of directly +executing calls in NEST, it forwards them together with their arguments to the NEST Server, which in turn executes them. To you as a user, everything looks much like a typical simulation code for NEST Simulator. @@ -172,17 +171,16 @@ Basic usage To give you an idea of the usage, the following table shows a comparison of a typical simulation once for PyNEST and once using the -NEST Server Client. +NEST Client. .. list-table:: * - **PyNEST directly** - - **via NEST Server Client** + - **via NEST Client** * - .. code-block:: Python import nest - # Reset the kernel nest.ResetKernel() @@ -205,8 +203,8 @@ NEST Server Client. - .. code-block:: Python - from NESTServerClient import NESTServerClient - nsc = NESTServerClient() + from nest_client import NESTClient + nsc = NESTClient() # Reset the kernel nsc.ResetKernel() @@ -231,7 +229,7 @@ NEST Server Client. Run scripts ~~~~~~~~~~~ -The NEST Server Client is able to send complete simulation scripts to +The NEST Client is able to send complete simulation scripts to the NEST Server using the functions ``exec_script`` and ``from_file``. The following listing shows a Python snippet using the NEST Server Client to execute a simple script on the Server using the @@ -239,8 +237,8 @@ Client to execute a simple script on the Server using the .. code-block:: Python - from NESTServerClient import NESTServerClient - nsc = NESTServerClient() + from nest_client import NESTClient + nsc = NESTClient() script = "print('Hello world!')" response = nsc.exec_script(script) @@ -254,12 +252,12 @@ Client to execute a simple script on the Server using the In a more realistic scenario, you probably already have your simulation script stored in a file. Such scripts can be sent to the NEST Server for execution using the ``from_file`` function provided by -the NEST Server Client. +the NEST Client. .. code-block:: Python - from NESTServerClient import NESTServerClient - nsc = NESTServerClient() + from nest_client import NESTClient + nsc = NESTClient() response = nsc.from_file('simulation_script.py', return_vars='n_events') n_events = response['data'] @@ -274,24 +272,24 @@ the NEST Server Client. on :ref:`security and modules ` below. -NEST Server Client API -~~~~~~~~~~~~~~~~~~~~~~ +NEST Client API +~~~~~~~~~~~~~~~ -.. py:class:: NESTServerClient +.. py:class:: NESTClient The client object to interact with the NEST Server -.. py:method:: NESTServerClient.(*args, **kwargs) +.. py:method:: NESTClient.(*args, **kwargs) Execute a PyNEST function `` on the NEST Server; the arguments `args` and `kwargs` will be forwarded to the function -.. py:method:: NESTServerClient.exec_script(source, return_vars=None) +.. py:method:: NESTClient.exec_script(source, return_vars=None) Execute a Python script on the NEST Server; the script has to be given as a string in the `source` argument -.. py:method:: NESTServerClient.from_file(filename, return_vars=None) +.. py:method:: NESTClient.from_file(filename, return_vars=None) Execute a Python script on the NEST Server; the argument `filename` is the name of the file in which the script is stored @@ -429,8 +427,8 @@ After this, NumPy can be used from within scripts in the regular way: .. code-block:: Python - from NESTServerClient import NESTServerClient - nsc = NESTServerClient() + from nest_client import NESTClient + nsc = NESTClient() response = nsc.exec_script("a = numpy.arange(10)", 'a') print(response['data'][::2]) # [0, 2, 4, 6, 8] diff --git a/examples/NESTServerClient/NESTServerClient.py b/examples/NESTServerClient/NESTServerClient.py deleted file mode 100644 index 4085f654ab..0000000000 --- a/examples/NESTServerClient/NESTServerClient.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -# -# NESTServerClient.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - -import requests -from werkzeug.exceptions import BadRequest - - -__all__ = [ - 'NESTServerClient', -] - - -def encode(response): - if response.ok: - return response.json() - elif response.status_code == 400: - raise BadRequest(response.text) - - -class NESTServerClient: - - def __init__(self, host='localhost', port=52425): - self.url = 'http://{}:{}/'.format(host, port) - self.headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} - - def __getattr__(self, call): - def method(*args, **kwargs): - kwargs.update({'args': args}) - response = requests.post(self.url + 'api/' + call, json=kwargs, headers=self.headers) - return encode(response) - return method - - def exec_script(self, source, return_vars=None): - params = { - 'source': source, - 'return': return_vars, - } - response = requests.post(self.url + 'exec', json=params, headers=self.headers) - return encode(response) - - def from_file(self, filename, return_vars=None): - with open(filename, 'r') as f: - lines = f.readlines() - script = ''.join(lines) - print('Execute script code of {}'.format(filename)) - print('Return variables: {}'.format(return_vars)) - print(20 * '-') - print(script) - print(20 * '-') - return self.exec_script(script, return_vars) diff --git a/examples/NESTServerClient/__init__.py b/examples/NESTServerClient/__init__.py deleted file mode 100644 index 1a2f534c46..0000000000 --- a/examples/NESTServerClient/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -# -# __init__.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - - -from .NESTServerClient import * diff --git a/examples/NESTServerClient/examples/NESTClient_example.py b/examples/NESTServerClient/examples/NESTClient_example.py deleted file mode 100644 index a8b709e0af..0000000000 --- a/examples/NESTServerClient/examples/NESTClient_example.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -# -# NESTClient_example.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - -from NESTServerClient import NESTServerClient - -print('Running client examples using NEST via NEST Server') - -# Load NEST Server client -nestsc = NESTServerClient() - -# -# Use NEST Server API -# -print('\n') -print('Execute script code with NEST Server API') -print('-' * 20) - -# Reset kernel -nestsc.ResetKernel() - -# Create nodes -pg = nestsc.Create("poisson_generator", params={"rate": 6500.}) -neurons = nestsc.Create("iaf_psc_alpha", 100) -sr = nestsc.Create("spike_recorder") - -# Connect nodes -nestsc.Connect(pg, neurons, syn_spec={'weight': 10.}) -nestsc.Connect(neurons[::10], sr) - -# Simulate -nestsc.Simulate(1000.0) - -# Get events -n_events = nestsc.GetStatus(sr, 'n_events')[0] -print('Number of events:', n_events) - - -# -# Use NEST Server exec -# -print('\n') -print('Execute script code from file') -print('-' * 20) - -n_events = nestsc.from_file('NESTClient_script.py', 'n_events')['data'] -print('Number of events:', n_events) diff --git a/examples/NESTServerClient/examples/NESTClient_script.py b/examples/NESTServerClient/examples/NESTClient_script.py deleted file mode 100644 index f5c72146e6..0000000000 --- a/examples/NESTServerClient/examples/NESTClient_script.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# NESTClient_script.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - -import nest - - -# Reset kernel -nest.ResetKernel() - -# Create nodes -pg = nest.Create("poisson_generator", params={"rate": 6500.}) -neurons = nest.Create("iaf_psc_alpha", 100) -sr = nest.Create("spike_recorder") - -# Connect nodes -nest.Connect(pg, neurons, syn_spec={"weight": 10.}) -nest.Connect(neurons[::10], sr) - -# Simulate -nest.Simulate(1000.) - -# Get events -n_events = sr.get("n_events") diff --git a/examples/NESTServerClient/examples/__init__.py b/examples/NESTServerClient/examples/__init__.py deleted file mode 100644 index 1a2f534c46..0000000000 --- a/examples/NESTServerClient/examples/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -# -# __init__.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - - -from .NESTServerClient import * diff --git a/examples/NESTServerClient/setup.py b/examples/NESTServerClient/setup.py deleted file mode 100644 index 8cbe11c62a..0000000000 --- a/examples/NESTServerClient/setup.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# -# setup.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# NEST is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with NEST. If not, see . - -# NESTServerClient --- A Client for NEST Server - -from distutils.core import setup - -setup(name='NESTServerClient', - version='0.1', - description=('NESTServerClient sends JSON requests to NEST Server.'), - author='Sebastian Spreizer', - author_email='spreizer@web.de', - url='https://www.nest-simulator.org', - license='GNU Public License v2 or later', - packages=['NESTServerClient', 'NESTServerClient.examples'], - package_dir={'NESTServerClient': ''} - ) From 535dce56129da858db9ce7af1696ff73421e7c9d Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 10 Apr 2023 14:18:22 +0200 Subject: [PATCH 14/21] Revise spatial tests to pytest style; avoids numercial issues due to precise float comparions --- .../test_SynapseCollection_distance.py | 203 +++++++++--------- .../pytests/test_spatial/test_plotting.py | 153 +++++++------ 2 files changed, 171 insertions(+), 185 deletions(-) diff --git a/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py b/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py index 186e87c857..793497700a 100644 --- a/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py +++ b/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py @@ -23,159 +23,152 @@ Tests distance between sources and targets of SynapseCollection """ -import unittest +import pytest import math import nest -class SynapseCollectionDistance(unittest.TestCase): +@pytest.fixture(autouse=True) +def _reset_kernel(): + nest.ResetKernel() - def setUp(self): - nest.ResetKernel() - def calculate_distance(self, conns, s_nodes, t_nodes): - """Calculate a reference distance between source and target nodes""" +def _calculate_distance(conns, s_nodes, t_nodes): + """Calculate a reference distance between source and target nodes""" - s_pos = nest.GetPosition(s_nodes) - t_pos = nest.GetPosition(t_nodes) + s_pos = nest.GetPosition(s_nodes) + t_pos = nest.GetPosition(t_nodes) - src = conns.source - trgt = conns.target + src = conns.source + trgt = conns.target - in_3d = len(s_pos[0]) == 3 + in_3d = len(s_pos[0]) == 3 - ref_distance = [] - for s, t in zip(src, trgt): - x_ref = t_pos[t_nodes.index(t)][0] - s_pos[s_nodes.index(s)][0] - y_ref = t_pos[t_nodes.index(t)][1] - s_pos[s_nodes.index(s)][1] - z_ref = 0.0 - if in_3d: - z_ref = t_pos[t_nodes.index(t)][2] - s_pos[s_nodes.index(s)][2] + ref_distance = [] + for s, t in zip(src, trgt): + x_ref = t_pos[t_nodes.index(t)][0] - s_pos[s_nodes.index(s)][0] + y_ref = t_pos[t_nodes.index(t)][1] - s_pos[s_nodes.index(s)][1] + z_ref = 0.0 + if in_3d: + z_ref = t_pos[t_nodes.index(t)][2] - s_pos[s_nodes.index(s)][2] - ref_dist = math.sqrt(x_ref * x_ref + y_ref * y_ref + z_ref * z_ref) - ref_distance.append(ref_dist) + ref_dist = math.sqrt(x_ref * x_ref + y_ref * y_ref + z_ref * z_ref) + ref_distance.append(ref_dist) - return tuple(ref_distance) + return tuple(ref_distance) - def test_SynapseCollection_distance_simple(self): - """Test distance on SynapseCollection where source and target are equal""" - s_nodes = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid(shape=[3, 3])) +def test_SynapseCollection_distance_simple(): + """Test distance on SynapseCollection where source and target are equal""" - nest.Connect(s_nodes, s_nodes, {'rule': 'one_to_one'}) - conns = nest.GetConnections() - dist = conns.distance + s_nodes = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid(shape=[3, 3])) - self.assertTrue(all([dd == 0. for dd in dist])) + nest.Connect(s_nodes, s_nodes, {'rule': 'one_to_one'}) + conns = nest.GetConnections() + dist = conns.distance - def test_SynapseCollection_distance(self): - """Test SynapseCollection distance function for grid positions""" + assert all(d == 0 for d in dist) - s_nodes = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid(shape=[3, 1])) - t_nodes = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid(shape=[1, 3])) - nest.Connect(s_nodes, t_nodes) - conns = nest.GetConnections() - dist = conns.distance +def test_SynapseCollection_distance(): + """Test SynapseCollection distance function for grid positions""" - ref_distance = self.calculate_distance(conns, s_nodes, t_nodes) + s_nodes = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid(shape=[3, 1])) + t_nodes = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid(shape=[1, 3])) - self.assertEqual(ref_distance, dist) + nest.Connect(s_nodes, t_nodes) + conns = nest.GetConnections() + dist = conns.distance - def test_SynapseCollection_distance_free(self): - """Test SynapseCollection distance function for positions placed freely in space""" + ref_distance = _calculate_distance(conns, s_nodes, t_nodes) - positions = nest.spatial.free(nest.random.uniform(), num_dimensions=2) - s_nodes = nest.Create('iaf_psc_alpha', n=5, positions=positions) - t_nodes = nest.Create('iaf_psc_alpha', n=7, positions=positions) + assert dist == pytest.approx(ref_distance) - nest.Connect(s_nodes, t_nodes, {'rule': 'pairwise_bernoulli', 'p': 0.7}) - conns = nest.GetConnections() - dist = conns.distance - ref_distance = self.calculate_distance(conns, s_nodes, t_nodes) +def test_SynapseCollection_distance_free(): + """Test SynapseCollection distance function for positions placed freely in space""" - self.assertEqual(ref_distance, dist) + positions = nest.spatial.free(nest.random.uniform(), num_dimensions=2) + s_nodes = nest.Create('iaf_psc_alpha', n=5, positions=positions) + t_nodes = nest.Create('iaf_psc_alpha', n=7, positions=positions) - def test_SynapseCollection_distance_3D(self): - """Test SynapseCollection distance function for spatial nodes in 3D""" + nest.Connect(s_nodes, t_nodes, {'rule': 'pairwise_bernoulli', 'p': 0.7}) + conns = nest.GetConnections() + dist = conns.distance - positions = nest.spatial.free(nest.random.uniform(), num_dimensions=3) - s_nodes = nest.Create('iaf_psc_alpha', n=8, positions=positions) - t_nodes = nest.Create('iaf_psc_alpha', n=11, positions=positions) + ref_distance = _calculate_distance(conns, s_nodes, t_nodes) - nest.Connect(s_nodes, t_nodes) - conns = nest.GetConnections() - dist = conns.distance + assert dist == pytest.approx(ref_distance) - ref_distance = self.calculate_distance(conns, s_nodes, t_nodes) - self.assertEqual(ref_distance, dist) +def test_SynapseCollection_distance_3D(): + """Test SynapseCollection distance function for spatial nodes in 3D""" - def test_SynapseCollection_distance_non_spatial(self): - """Test SynapseCollection distance function on non-spatial nodes""" + positions = nest.spatial.free(nest.random.uniform(), num_dimensions=3) + s_nodes = nest.Create('iaf_psc_alpha', n=8, positions=positions) + t_nodes = nest.Create('iaf_psc_alpha', n=11, positions=positions) - s_nodes = nest.Create('iaf_psc_alpha', 3) - t_nodes = nest.Create('iaf_psc_alpha', 2) + nest.Connect(s_nodes, t_nodes) + conns = nest.GetConnections() + dist = conns.distance - nest.Connect(s_nodes, t_nodes) - conns = nest.GetConnections() - dist = conns.distance + ref_distance = _calculate_distance(conns, s_nodes, t_nodes) - dist_is_nan = [math.isnan(d) for d in dist] + assert dist == pytest.approx(ref_distance) - self.assertTrue(dist_is_nan) - def test_SynapseCollection_distance_mixed(self): - """Test SynapseCollection distance function on non-spatial and spatial nodes""" +def test_SynapseCollection_distance_non_spatial(): + """Test SynapseCollection distance function on non-spatial nodes""" - num_snodes_nonspatial = 3 - num_tnodes_nonspatial = 2 - num_conns_nonsparial = num_snodes_nonspatial * num_tnodes_nonspatial - s_nodes_nonspatial = nest.Create('iaf_psc_alpha', num_snodes_nonspatial) - t_nodes_nonspatial = nest.Create('iaf_psc_alpha', num_tnodes_nonspatial) + s_nodes = nest.Create('iaf_psc_alpha', 3) + t_nodes = nest.Create('iaf_psc_alpha', 2) - positions = nest.spatial.free(nest.random.uniform(), num_dimensions=2) - s_nodes_spatial = nest.Create('iaf_psc_alpha', n=6, positions=positions) - t_nodes_spatial = nest.Create('iaf_psc_alpha', n=7, positions=positions) + nest.Connect(s_nodes, t_nodes) + conns = nest.GetConnections() + dist = conns.distance - nest.Connect(s_nodes_nonspatial, t_nodes_nonspatial) - nest.Connect(s_nodes_spatial, t_nodes_spatial) - conns = nest.GetConnections() - dist = conns.distance + assert all(math.isnan(d) for d in dist) - # Check part that is spatial - ref_distance = self.calculate_distance(conns[num_conns_nonsparial:], s_nodes_spatial, t_nodes_spatial) - self.assertEqual(ref_distance, dist[num_conns_nonsparial:]) - # Check part that is non-spatial - dist_is_nan = [math.isnan(d) for d in dist[:num_conns_nonsparial]] - self.assertTrue(dist_is_nan) +def test_SynapseCollection_distance_mixed(): + """Test SynapseCollection distance function on non-spatial and spatial nodes""" - def test_SynapseCollection_distance_spatial_nonspatial_connected(self): - """Test SynapseCollection distance function on non-spatial and spatial nodes that are connected""" + num_snodes_nonspatial = 3 + num_tnodes_nonspatial = 2 + num_conns_nonspatial = num_snodes_nonspatial * num_tnodes_nonspatial + s_nodes_nonspatial = nest.Create('iaf_psc_alpha', num_snodes_nonspatial) + t_nodes_nonspatial = nest.Create('iaf_psc_alpha', num_tnodes_nonspatial) - num_snodes = 5 - num_tnodes = 11 - s_nodes_nonspatial = nest.Create('iaf_psc_alpha', num_snodes) + positions = nest.spatial.free(nest.random.uniform(), num_dimensions=2) + s_nodes_spatial = nest.Create('iaf_psc_alpha', n=6, positions=positions) + t_nodes_spatial = nest.Create('iaf_psc_alpha', n=7, positions=positions) - positions = nest.spatial.free(nest.random.uniform(), num_dimensions=2) - t_nodes_spatial = nest.Create('iaf_psc_alpha', n=num_tnodes, positions=positions) + nest.Connect(s_nodes_nonspatial, t_nodes_nonspatial) + nest.Connect(s_nodes_spatial, t_nodes_spatial) + conns = nest.GetConnections() + dist = conns.distance - nest.Connect(s_nodes_nonspatial, t_nodes_spatial) - conns = nest.GetConnections() - dist = conns.distance + # Check part that is spatial + ref_distance = _calculate_distance(conns[num_conns_nonspatial:], s_nodes_spatial, t_nodes_spatial) + assert dist[num_conns_nonspatial:] == pytest.approx(ref_distance) - # All should be nan - dist_is_nan = [math.isnan(d) for d in dist] - self.assertTrue(dist_is_nan) + # Check part that is non-spatial + assert all(math.isnan(d) for d in dist[:num_conns_nonspatial]) -def suite(): - suite = unittest.makeSuite(SynapseCollectionDistance, 'test') - return suite +def test_SynapseCollection_distance_spatial_nonspatial_connected(): + """Test SynapseCollection distance function on non-spatial and spatial nodes that are connected""" + num_snodes = 5 + num_tnodes = 11 + s_nodes_nonspatial = nest.Create('iaf_psc_alpha', num_snodes) -if __name__ == "__main__": - runner = unittest.TextTestRunner(verbosity=2) - runner.run(suite()) + positions = nest.spatial.free(nest.random.uniform(), num_dimensions=2) + t_nodes_spatial = nest.Create('iaf_psc_alpha', n=num_tnodes, positions=positions) + + nest.Connect(s_nodes_nonspatial, t_nodes_spatial) + conns = nest.GetConnections() + dist = conns.distance + + # All should be nan + assert all(math.isnan(d) for d in dist) diff --git a/testsuite/pytests/test_spatial/test_plotting.py b/testsuite/pytests/test_spatial/test_plotting.py index 5c8616edfa..f63f4c84c2 100644 --- a/testsuite/pytests/test_spatial/test_plotting.py +++ b/testsuite/pytests/test_spatial/test_plotting.py @@ -23,161 +23,154 @@ Tests for basic spatial plotting functions. """ -import unittest +import pytest import nest import numpy as np try: + import matplotlib + matplotlib.use('Agg') # backend without window import matplotlib.pyplot as plt - tmp_fig = plt.figure() # make sure we can open a window; DISPLAY may not be set + tmp_fig = plt.figure() # make sure we can open a figure plt.close(tmp_fig) PLOTTING_POSSIBLE = True except ImportError: PLOTTING_POSSIBLE = False -@unittest.skipIf(not PLOTTING_POSSIBLE, - 'Plotting impossible because matplotlib or display missing') -class PlottingTestCase(unittest.TestCase): +# skip all test if plotting impossible +pytestmark = pytest.mark.skipif(not PLOTTING_POSSIBLE, + reason='Plotting impossible because matplotlib or display missing') + + +class TestLayerPlot: + + @pytest.fixture(autouse=True) + def _prep(self): + nest.ResetKernel() + self.layer = nest.Create('iaf_psc_alpha', + positions=nest.spatial.grid(shape=[3, 3], + extent=[2., 2.], + edge_wrap=True)) + def test_PlotLayer(self): """Test plotting layer.""" - nest.ResetKernel() - layer = nest.Create('iaf_psc_alpha', - positions=nest.spatial.grid(shape=[3, 3], - extent=[2., 2.], - edge_wrap=True)) - nest.PlotLayer(layer) - plotted_datapoints = plt.gca().collections[-1].get_offsets().data - reference_datapoints = nest.GetPosition(layer) - self.assertTrue(np.allclose(plotted_datapoints, reference_datapoints)) + nest.PlotLayer(self.layer) + + plotted_datapoints = np.array(plt.gca().collections[-1].get_offsets().data) + reference_datapoints = np.array(nest.GetPosition(self.layer)) + assert plotted_datapoints == pytest.approx(reference_datapoints) def test_PlotTargets(self): """Test plotting targets.""" + delta = 0.05 mask = {'rectangular': {'lower_left': [-delta, -2/3 - delta], 'upper_right': [2/3 + delta, delta]}} - cdict = {'rule': 'pairwise_bernoulli', 'p': 1., - 'mask': mask} + cdict = {'rule': 'pairwise_bernoulli', 'p': 1., 'mask': mask} sdict = {'synapse_model': 'stdp_synapse'} - nest.ResetKernel() - layer = nest.Create('iaf_psc_alpha', - positions=nest.spatial.grid(shape=[3, 3], - extent=[2., 2.], - edge_wrap=True)) # connect layer -> layer - nest.Connect(layer, layer, cdict, sdict) + nest.Connect(self.layer, self.layer, cdict, sdict) - ctr = nest.FindCenterElement(layer) - fig = nest.PlotTargets(ctr, layer) + ctr = nest.FindCenterElement(self.layer) + fig = nest.PlotTargets(ctr, self.layer) fig.gca().set_title('Plain call') plotted_datapoints = plt.gca().collections[0].get_offsets().data eps = 0.01 - pos = np.array(nest.GetPosition(layer)) + pos = np.array(nest.GetPosition(self.layer)) pos_xmask = pos[np.where(pos[:, 0] > -eps)] reference_datapoints = pos_xmask[np.where(pos_xmask[:, 1] < eps)][::-1] - self.assertTrue(np.array_equal(np.sort(plotted_datapoints, axis=0), np.sort(reference_datapoints, axis=0))) + assert np.sort(plotted_datapoints, axis=0) == pytest.approx(np.sort(reference_datapoints, axis=0)) - fig = nest.PlotTargets(ctr, layer, mask=mask) + fig = nest.PlotTargets(ctr, self.layer, mask=mask) ax = fig.gca() ax.set_title('Call with mask') - self.assertGreaterEqual(len(ax.patches), 1) + assert len(ax.patches) >= 1 def test_PlotSources(self): """Test plotting sources""" + delta = 0.05 mask = {'rectangular': {'lower_left': [-delta, -2/3 - delta], 'upper_right': [2/3 + delta, delta]}} - cdict = {'rule': 'pairwise_bernoulli', 'p': 1., - 'mask': mask} + cdict = {'rule': 'pairwise_bernoulli', 'p': 1., 'mask': mask} sdict = {'synapse_model': 'stdp_synapse'} - nest.ResetKernel() - layer = nest.Create('iaf_psc_alpha', - positions=nest.spatial.grid(shape=[3, 3], - extent=[2., 2.], - edge_wrap=True)) # connect layer -> layer - nest.Connect(layer, layer, cdict, sdict) + nest.Connect(self.layer, self.layer, cdict, sdict) - ctr = nest.FindCenterElement(layer) - fig = nest.PlotSources(layer, ctr) + ctr = nest.FindCenterElement(self.layer) + fig = nest.PlotSources(self.layer, ctr) fig.gca().set_title('Plain call') plotted_datapoints = plt.gca().collections[0].get_offsets().data eps = 0.01 - pos = np.array(nest.GetPosition(layer)) + pos = np.array(nest.GetPosition(self.layer)) pos_xmask = pos[np.where(pos[:, 0] < eps)] reference_datapoints = pos_xmask[np.where(pos_xmask[:, 1] > - eps)][::-1] - self.assertTrue(np.array_equal(np.sort(plotted_datapoints, axis=0), np.sort(reference_datapoints, axis=0))) + assert np.sort(plotted_datapoints, axis=0) == pytest.approx(np.sort(reference_datapoints, axis=0)) - fig = nest.PlotSources(layer, ctr, mask=mask) + fig = nest.PlotSources(self.layer, ctr, mask=mask) ax = fig.gca() ax.set_title('Call with mask') - self.assertGreaterEqual(len(ax.patches), 1) + assert len(ax.patches) >= 1 - def test_plot_probability_kernel(self): - """Plot parameter probability""" + +class TestKernelProbabilityPlot: + + @pytest.fixture(autouse=True) + def _prep(self): nest.ResetKernel() - plot_shape = [10, 10] - plot_edges = [-0.5, 0.5, -0.5, 0.5] + self.plot_shape = [10, 10] + self.plot_edges = [-0.5, 0.5, -0.5, 0.5] + self.layer = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid([10, 10], edge_wrap=False)) + self.source = self.layer[25] - def probability_calculation(distance): - return 1 - 1.5*distance + @staticmethod + def _probability_calculation(distance): + return 1 - 1.5 * distance + + def test_plot_probability_kernel(self): + """Plot parameter probability""" - layer = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid([10, 10], edge_wrap=False)) - source = layer[25] - source_pos = np.array(nest.GetPosition(source)) - source_x, source_y = source_pos + source_x, source_y = nest.GetPosition(self.source) # Calculate reference values - ref_probability = np.zeros(plot_shape[::-1]) - for i, x in enumerate(np.linspace(plot_edges[0], plot_edges[1], plot_shape[0])): - positions = np.array([[x, y] for y in np.linspace(plot_edges[2], plot_edges[3], plot_shape[1])]) + ref_probability = np.zeros(self.plot_shape[::-1]) + for i, x in enumerate(np.linspace(self.plot_edges[0], self.plot_edges[1], self.plot_shape[0])): + positions = np.array([[x, y] + for y in np.linspace(self.plot_edges[2], self.plot_edges[3], self.plot_shape[1])]) ref_distances = np.sqrt((positions[:, 0] - source_x)**2 + (positions[:, 1] - source_y)**2) - values = probability_calculation(ref_distances) + values = self._probability_calculation(ref_distances) ref_probability[:, i] = np.maximum(np.minimum(np.array(values), 1.0), 0.0) # Create the parameter - parameter = probability_calculation(nest.spatial.distance) + parameter = self._probability_calculation(nest.spatial.distance) fig, ax = plt.subplots() - nest.PlotProbabilityParameter(source, parameter, ax=ax, shape=plot_shape, edges=plot_edges) + nest.PlotProbabilityParameter(self.source, parameter, ax=ax, shape=self.plot_shape, edges=self.plot_edges) - self.assertEqual(len(ax.images), 1) + assert len(ax.images) >= 1 img = ax.images[0] img_data = img.get_array().data - self.assertTrue(np.array_equal(img_data, ref_probability)) + assert img_data == pytest.approx(ref_probability) def test_plot_probability_kernel_with_mask(self): """Plot parameter probability with mask""" - nest.ResetKernel() - plot_shape = [10, 10] - plot_edges = [-0.5, 0.5, -0.5, 0.5] - layer = nest.Create('iaf_psc_alpha', positions=nest.spatial.grid([10, 10], edge_wrap=False)) - parameter = 1 - 1.5*nest.spatial.distance + parameter = self._probability_calculation(1 - 1.5 * nest.spatial.distance) - source = layer[25] masks = [{'circular': {'radius': 0.4}}, {'doughnut': {'inner_radius': 0.2, 'outer_radius': 0.45}}, {'rectangular': {'lower_left': [-.3, -.3], 'upper_right': [0.3, 0.3]}}, {'elliptical': {'major_axis': 0.8, 'minor_axis': 0.4}}] fig, axs = plt.subplots(2, 2) - for mask, ax in zip(masks, axs.flatten()): - nest.PlotProbabilityParameter(source, parameter, mask=mask, ax=ax, shape=plot_shape, edges=plot_edges) - self.assertEqual(len(ax.images), 1) - self.assertGreaterEqual(len(ax.patches), 1) - -def suite(): - suite = unittest.makeSuite(PlottingTestCase, 'test') - return suite - - -if __name__ == "__main__": - runner = unittest.TextTestRunner(verbosity=2) - runner.run(suite()) + for mask, ax in zip(masks, axs.flatten()): + nest.PlotProbabilityParameter(self.source, parameter, mask=mask, ax=ax, + shape=self.plot_shape, edges=self.plot_edges) - plt.show() + assert len(ax.images) >= 1 + assert len(ax.patches) >= 1 From 9bb6a24a4e797b3b3e60d30eedacbb2726648a51 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 10 Apr 2023 22:42:01 +0200 Subject: [PATCH 15/21] Skip tests requiring multiple threads --- testsuite/pytests/test_connect_all_to_all.py | 4 ++++ testsuite/pytests/test_connect_array_fixed_outdegree.py | 4 ++++ testsuite/pytests/test_connect_fixed_indegree.py | 5 +++++ testsuite/pytests/test_connect_fixed_total_number.py | 5 +++++ testsuite/pytests/test_connect_one_to_one.py | 5 +++++ testsuite/pytests/test_connect_pairwise_bernoulli.py | 5 +++++ .../pytests/test_connect_symmetric_pairwise_bernoulli.py | 5 +++++ 7 files changed, 33 insertions(+) diff --git a/testsuite/pytests/test_connect_all_to_all.py b/testsuite/pytests/test_connect_all_to_all.py index e920d13c43..8f5d44f095 100644 --- a/testsuite/pytests/test_connect_all_to_all.py +++ b/testsuite/pytests/test_connect_all_to_all.py @@ -27,6 +27,10 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') @nest.ll_api.check_stack class TestAllToAll(connect_test_base.ConnectTestBase): diff --git a/testsuite/pytests/test_connect_array_fixed_outdegree.py b/testsuite/pytests/test_connect_array_fixed_outdegree.py index b715cbb374..5ceff991f8 100644 --- a/testsuite/pytests/test_connect_array_fixed_outdegree.py +++ b/testsuite/pytests/test_connect_array_fixed_outdegree.py @@ -29,6 +29,10 @@ import numpy +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') @nest.ll_api.check_stack class ConnectArrayFixedOutdegreeTestCase(unittest.TestCase): """Tests of connections with fixed outdegree and parameter arrays""" diff --git a/testsuite/pytests/test_connect_fixed_indegree.py b/testsuite/pytests/test_connect_fixed_indegree.py index 8bd36da876..aac38096f3 100644 --- a/testsuite/pytests/test_connect_fixed_indegree.py +++ b/testsuite/pytests/test_connect_fixed_indegree.py @@ -27,6 +27,11 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@nest.ll_api.check_stack class TestFixedInDegree(connect_test_base.ConnectTestBase): # specify connection pattern and specific params diff --git a/testsuite/pytests/test_connect_fixed_total_number.py b/testsuite/pytests/test_connect_fixed_total_number.py index ef7fdc2300..64a9e7a72c 100644 --- a/testsuite/pytests/test_connect_fixed_total_number.py +++ b/testsuite/pytests/test_connect_fixed_total_number.py @@ -26,6 +26,11 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@nest.ll_api.check_stack class TestFixedTotalNumber(connect_test_base.ConnectTestBase): # specify connection pattern and specific params diff --git a/testsuite/pytests/test_connect_one_to_one.py b/testsuite/pytests/test_connect_one_to_one.py index 3abaeeeb3b..002c050452 100644 --- a/testsuite/pytests/test_connect_one_to_one.py +++ b/testsuite/pytests/test_connect_one_to_one.py @@ -25,6 +25,11 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@nest.ll_api.check_stack class TestOneToOne(connect_test_base.ConnectTestBase): # specify connection pattern diff --git a/testsuite/pytests/test_connect_pairwise_bernoulli.py b/testsuite/pytests/test_connect_pairwise_bernoulli.py index 40656bd170..1334af74a8 100644 --- a/testsuite/pytests/test_connect_pairwise_bernoulli.py +++ b/testsuite/pytests/test_connect_pairwise_bernoulli.py @@ -27,6 +27,11 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@nest.ll_api.check_stack class TestPairwiseBernoulli(connect_test_base.ConnectTestBase): # specify connection pattern and specific params diff --git a/testsuite/pytests/test_connect_symmetric_pairwise_bernoulli.py b/testsuite/pytests/test_connect_symmetric_pairwise_bernoulli.py index 4757598069..d07653cb98 100644 --- a/testsuite/pytests/test_connect_symmetric_pairwise_bernoulli.py +++ b/testsuite/pytests/test_connect_symmetric_pairwise_bernoulli.py @@ -28,6 +28,11 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@nest.ll_api.check_stack class TestSymmetricPairwiseBernoulli(connect_test_base.ConnectTestBase): # sizes of source-, target-population and connection probability for From 3ea37ed286fd641b7827f9ea233b07961f318356 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 10 Apr 2023 23:46:23 +0200 Subject: [PATCH 16/21] Make it an error to set multiple threads if NEST was compiled without thread support; skip tests depending on threading. --- nestkernel/vp_manager.cpp | 4 +--- testsuite/mpitests/test_get_nodes.sli | 2 ++ testsuite/mpitests/test_sinusoidal_poisson_generator_5.sli | 2 ++ testsuite/mpitests/test_sinusoidal_poisson_generator_6.sli | 2 ++ .../mpitests/topo_mpi_test_pairwise_bernoulli_on_source.sli | 2 ++ .../mpitests/topo_mpi_test_pairwise_bernoulli_on_target.sli | 2 ++ testsuite/pytests/mpi/2/test_connect_arrays_mpi.py | 2 ++ testsuite/pytests/mpi/4/test_consistent_local_vps.py | 5 +++++ testsuite/pytests/test_connect_arrays.py | 1 + testsuite/pytests/test_connect_fixed_outdegree.py | 5 +++++ testsuite/pytests/test_recording_backend_ascii.py | 3 +++ testsuite/pytests/test_recording_backend_memory.py | 3 +++ testsuite/pytests/test_weight_recorder.py | 2 ++ testsuite/regressiontests/issue-1640.sli | 2 ++ testsuite/regressiontests/ticket-643.sli | 2 ++ testsuite/regressiontests/ticket-881.sli | 2 ++ testsuite/unittests/test_GetConnections.sli | 2 ++ testsuite/unittests/test_sinusoidal_gamma_generator.sli | 2 ++ testsuite/unittests/test_sinusoidal_poisson_generator.sli | 2 ++ 19 files changed, 44 insertions(+), 3 deletions(-) diff --git a/nestkernel/vp_manager.cpp b/nestkernel/vp_manager.cpp index aaaaaa0ef4..3b31b373f1 100644 --- a/nestkernel/vp_manager.cpp +++ b/nestkernel/vp_manager.cpp @@ -95,9 +95,7 @@ nest::VPManager::set_status( const DictionaryDatum& d ) if ( force_singlethreading_ and n_threads > 1 ) { - std::string msg = "Multithreading requested, but unavailable. Using a single thread."; - LOG( M_WARNING, "VPManager::set_status", msg ); - n_threads = 1; + throw BadProperty( "This installation of NEST was built without support for multiple threads." ); } // We only want to act if new values differ from the old diff --git a/testsuite/mpitests/test_get_nodes.sli b/testsuite/mpitests/test_get_nodes.sli index d0b3312f21..ab5f6c7870 100644 --- a/testsuite/mpitests/test_get_nodes.sli +++ b/testsuite/mpitests/test_get_nodes.sli @@ -32,6 +32,8 @@ Description: Author: August 2019, Stine B. Vennemo */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/mpitests/test_sinusoidal_poisson_generator_5.sli b/testsuite/mpitests/test_sinusoidal_poisson_generator_5.sli index 977dcc093e..a0986ad423 100644 --- a/testsuite/mpitests/test_sinusoidal_poisson_generator_5.sli +++ b/testsuite/mpitests/test_sinusoidal_poisson_generator_5.sli @@ -35,6 +35,8 @@ Author: December 2012, May 2013, Plesser, based on test_poisson_generator.sli See also: test_sinusoidal_poisson_generator_{1,2,3,4,6}, test_sinusoidal_poisson_generator_nostat */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/mpitests/test_sinusoidal_poisson_generator_6.sli b/testsuite/mpitests/test_sinusoidal_poisson_generator_6.sli index d9d3ec9342..9e10b99794 100644 --- a/testsuite/mpitests/test_sinusoidal_poisson_generator_6.sli +++ b/testsuite/mpitests/test_sinusoidal_poisson_generator_6.sli @@ -35,6 +35,8 @@ Author: December 2012, May 2013, Plesser, based on test_poisson_generator.sli See also: test_sinusoidal_poisson_generator_{1,2,3,4,5}, test_sinusoidal_poisson_generator_nostat */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_source.sli b/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_source.sli index 645caac749..ebfdb39874 100644 --- a/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_source.sli +++ b/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_source.sli @@ -20,6 +20,8 @@ * */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_target.sli b/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_target.sli index 5837467845..2b73dfffbc 100644 --- a/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_target.sli +++ b/testsuite/mpitests/topo_mpi_test_pairwise_bernoulli_on_target.sli @@ -20,6 +20,8 @@ * */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py b/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py index c5f1e1ae20..4e331773f3 100644 --- a/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py +++ b/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py @@ -32,8 +32,10 @@ HAVE_MPI4PY = False HAVE_MPI = nest.ll_api.sli_func("statusdict/have_mpi ::") +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') @unittest.skipIf(not HAVE_MPI4PY, 'mpi4py is not available') class TestConnectArraysMPICase(unittest.TestCase): """ diff --git a/testsuite/pytests/mpi/4/test_consistent_local_vps.py b/testsuite/pytests/mpi/4/test_consistent_local_vps.py index 5b2e2c3a0e..69cb426522 100644 --- a/testsuite/pytests/mpi/4/test_consistent_local_vps.py +++ b/testsuite/pytests/mpi/4/test_consistent_local_vps.py @@ -19,9 +19,14 @@ # You should have received a copy of the GNU General Public License # along with NEST. If not, see . +import unittest import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') def test_consistent_local_vps(): """ Test local_vps field of kernel status. diff --git a/testsuite/pytests/test_connect_arrays.py b/testsuite/pytests/test_connect_arrays.py index 3c2465729c..74da9bb901 100644 --- a/testsuite/pytests/test_connect_arrays.py +++ b/testsuite/pytests/test_connect_arrays.py @@ -124,6 +124,7 @@ def test_connect_arrays_different_weights_delays(self): np.testing.assert_array_almost_equal(conns.weight, weights) np.testing.assert_array_almost_equal(conns.delay, delays) + @unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') def test_connect_arrays_threaded(self): """Connecting NumPy arrays, threaded""" nest.local_num_threads = 2 diff --git a/testsuite/pytests/test_connect_fixed_outdegree.py b/testsuite/pytests/test_connect_fixed_outdegree.py index b5197925bd..834057510c 100644 --- a/testsuite/pytests/test_connect_fixed_outdegree.py +++ b/testsuite/pytests/test_connect_fixed_outdegree.py @@ -26,6 +26,11 @@ import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@nest.ll_api.check_stack class TestFixedOutDegree(connect_test_base.ConnectTestBase): # specify connection pattern and specific params diff --git a/testsuite/pytests/test_recording_backend_ascii.py b/testsuite/pytests/test_recording_backend_ascii.py index 5a12186f1b..516ddb16a4 100644 --- a/testsuite/pytests/test_recording_backend_ascii.py +++ b/testsuite/pytests/test_recording_backend_ascii.py @@ -23,7 +23,10 @@ import unittest import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') class TestRecordingBackendASCII(unittest.TestCase): def testAAAOverwriteFiles(self): diff --git a/testsuite/pytests/test_recording_backend_memory.py b/testsuite/pytests/test_recording_backend_memory.py index c404a89c8a..2d6efef3b0 100644 --- a/testsuite/pytests/test_recording_backend_memory.py +++ b/testsuite/pytests/test_recording_backend_memory.py @@ -22,7 +22,10 @@ import unittest import nest +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") + +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') class TestRecordingBackendMemory(unittest.TestCase): def testEventsDict(self): diff --git a/testsuite/pytests/test_weight_recorder.py b/testsuite/pytests/test_weight_recorder.py index 957198dada..6152a7c091 100644 --- a/testsuite/pytests/test_weight_recorder.py +++ b/testsuite/pytests/test_weight_recorder.py @@ -28,8 +28,10 @@ import numpy as np HAVE_GSL = nest.ll_api.sli_func("statusdict/have_gsl ::") +HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') @nest.ll_api.check_stack class WeightRecorderTestCase(unittest.TestCase): """Tests for the Weight Recorder""" diff --git a/testsuite/regressiontests/issue-1640.sli b/testsuite/regressiontests/issue-1640.sli index 1c23c08df6..a2347d9f0e 100644 --- a/testsuite/regressiontests/issue-1640.sli +++ b/testsuite/regressiontests/issue-1640.sli @@ -34,6 +34,8 @@ Author: Håkon Mørk FirstVersion: August 2020 */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/regressiontests/ticket-643.sli b/testsuite/regressiontests/ticket-643.sli index e225bca137..88cdacbc1c 100644 --- a/testsuite/regressiontests/ticket-643.sli +++ b/testsuite/regressiontests/ticket-643.sli @@ -33,6 +33,8 @@ */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/regressiontests/ticket-881.sli b/testsuite/regressiontests/ticket-881.sli index ca31b6f3fb..7f2578dc52 100644 --- a/testsuite/regressiontests/ticket-881.sli +++ b/testsuite/regressiontests/ticket-881.sli @@ -34,6 +34,8 @@ Author: Hans Ekkehard Plesser */ +skip_if_not_threaded + (unittest) run /unittest using diff --git a/testsuite/unittests/test_GetConnections.sli b/testsuite/unittests/test_GetConnections.sli index e4014f5652..5220a3a579 100644 --- a/testsuite/unittests/test_GetConnections.sli +++ b/testsuite/unittests/test_GetConnections.sli @@ -222,6 +222,8 @@ % eighth test: check static synapses on four threads +skip_if_not_threaded + { << >> begin ResetKernel diff --git a/testsuite/unittests/test_sinusoidal_gamma_generator.sli b/testsuite/unittests/test_sinusoidal_gamma_generator.sli index 8df58fcd73..2b246134f4 100644 --- a/testsuite/unittests/test_sinusoidal_gamma_generator.sli +++ b/testsuite/unittests/test_sinusoidal_gamma_generator.sli @@ -206,6 +206,8 @@ M_ERROR setverbosity } assert_or_die (passed 4b) == +skip_if_not_threaded + % test 4c: two threads, one spike train for all targets { false 2 4 test4_function diff --git a/testsuite/unittests/test_sinusoidal_poisson_generator.sli b/testsuite/unittests/test_sinusoidal_poisson_generator.sli index 2708685308..54458f7e62 100644 --- a/testsuite/unittests/test_sinusoidal_poisson_generator.sli +++ b/testsuite/unittests/test_sinusoidal_poisson_generator.sli @@ -201,6 +201,8 @@ M_ERROR setverbosity } assert_or_die (passed 4b) == +skip_if_not_threaded + % test 4c: two threads, one spike train for all targets { false 2 4 test4_function From ef9d3883ae68289fc637acd4d177195feef7f011 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Tue, 11 Apr 2023 15:47:45 +0200 Subject: [PATCH 17/21] Correct rST annotations Co-authored-by: Nicolai Haug <39106781+nicolossus@users.noreply.github.com> --- testsuite/pytests/test_multimeter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testsuite/pytests/test_multimeter.py b/testsuite/pytests/test_multimeter.py index 2e8d75089f..307b2d24c6 100644 --- a/testsuite/pytests/test_multimeter.py +++ b/testsuite/pytests/test_multimeter.py @@ -46,7 +46,8 @@ def test_recordables_are_recorded(_set_resolution, model): recording from all recordables and test that data is provided. I also checks that the recording interval can be set. - @note This test does not check if the data is meaningful. + .. note:: + This test does not check if the data is meaningful. """ recording_interval = 2 From 110e9ee2c8a0993451c5811ecc7a35b286ed3e8a Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Tue, 11 Apr 2023 16:20:37 +0200 Subject: [PATCH 18/21] Refactored distance calculation in test. Co-authored-by: med-ayssar --- .../test_SynapseCollection_distance.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py b/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py index 793497700a..6aa67aeb8e 100644 --- a/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py +++ b/testsuite/pytests/test_spatial/test_SynapseCollection_distance.py @@ -25,6 +25,7 @@ import pytest import math +import numpy as np import nest @@ -42,20 +43,12 @@ def _calculate_distance(conns, s_nodes, t_nodes): src = conns.source trgt = conns.target - in_3d = len(s_pos[0]) == 3 + dim = len(s_pos[0]) - ref_distance = [] - for s, t in zip(src, trgt): - x_ref = t_pos[t_nodes.index(t)][0] - s_pos[s_nodes.index(s)][0] - y_ref = t_pos[t_nodes.index(t)][1] - s_pos[s_nodes.index(s)][1] - z_ref = 0.0 - if in_3d: - z_ref = t_pos[t_nodes.index(t)][2] - s_pos[s_nodes.index(s)][2] + ref_distance = [np.linalg.norm(np.array(t_pos[t_nodes.index(t)]) - np.array(s_pos[s_nodes.index(s)]), ord=2) + for s, t in zip(conns.source, conns.target)] - ref_dist = math.sqrt(x_ref * x_ref + y_ref * y_ref + z_ref * z_ref) - ref_distance.append(ref_dist) - - return tuple(ref_distance) + return ref_distance def test_SynapseCollection_distance_simple(): From 957c0e8541434dca46bba8ed317ddee46620cbb9 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Tue, 11 Apr 2023 20:52:37 +0200 Subject: [PATCH 19/21] Fix formatting issues --- nestkernel/vp_manager.cpp | 2 +- testsuite/pytests/mpi/2/test_connect_arrays_mpi.py | 2 +- testsuite/pytests/mpi/4/test_consistent_local_vps.py | 2 +- testsuite/pytests/test_recording_backend_ascii.py | 2 +- testsuite/pytests/test_recording_backend_memory.py | 2 +- testsuite/pytests/test_weight_recorder.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nestkernel/vp_manager.cpp b/nestkernel/vp_manager.cpp index 3b31b373f1..812eb54913 100644 --- a/nestkernel/vp_manager.cpp +++ b/nestkernel/vp_manager.cpp @@ -95,7 +95,7 @@ nest::VPManager::set_status( const DictionaryDatum& d ) if ( force_singlethreading_ and n_threads > 1 ) { - throw BadProperty( "This installation of NEST was built without support for multiple threads." ); + throw BadProperty( "This installation of NEST was built without support for multiple threads." ); } // We only want to act if new values differ from the old diff --git a/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py b/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py index 4e331773f3..7c7e665be3 100644 --- a/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py +++ b/testsuite/pytests/mpi/2/test_connect_arrays_mpi.py @@ -35,7 +35,7 @@ HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") -@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') @unittest.skipIf(not HAVE_MPI4PY, 'mpi4py is not available') class TestConnectArraysMPICase(unittest.TestCase): """ diff --git a/testsuite/pytests/mpi/4/test_consistent_local_vps.py b/testsuite/pytests/mpi/4/test_consistent_local_vps.py index 69cb426522..17c04ca45d 100644 --- a/testsuite/pytests/mpi/4/test_consistent_local_vps.py +++ b/testsuite/pytests/mpi/4/test_consistent_local_vps.py @@ -26,7 +26,7 @@ HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") -@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') def test_consistent_local_vps(): """ Test local_vps field of kernel status. diff --git a/testsuite/pytests/test_recording_backend_ascii.py b/testsuite/pytests/test_recording_backend_ascii.py index 516ddb16a4..5e96834463 100644 --- a/testsuite/pytests/test_recording_backend_ascii.py +++ b/testsuite/pytests/test_recording_backend_ascii.py @@ -26,7 +26,7 @@ HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") -@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') class TestRecordingBackendASCII(unittest.TestCase): def testAAAOverwriteFiles(self): diff --git a/testsuite/pytests/test_recording_backend_memory.py b/testsuite/pytests/test_recording_backend_memory.py index 2d6efef3b0..b0cef6f6c4 100644 --- a/testsuite/pytests/test_recording_backend_memory.py +++ b/testsuite/pytests/test_recording_backend_memory.py @@ -25,7 +25,7 @@ HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") -@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') class TestRecordingBackendMemory(unittest.TestCase): def testEventsDict(self): diff --git a/testsuite/pytests/test_weight_recorder.py b/testsuite/pytests/test_weight_recorder.py index 6152a7c091..c903434a3f 100644 --- a/testsuite/pytests/test_weight_recorder.py +++ b/testsuite/pytests/test_weight_recorder.py @@ -31,7 +31,7 @@ HAVE_OPENMP = nest.ll_api.sli_func("is_threaded") -@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') +@unittest.skipIf(not HAVE_OPENMP, 'NEST was compiled without multi-threading') @nest.ll_api.check_stack class WeightRecorderTestCase(unittest.TestCase): """Tests for the Weight Recorder""" From e37368d4c2605d10603dd82115c268b403a4b809 Mon Sep 17 00:00:00 2001 From: Jochen Martin Eppler Date: Wed, 12 Apr 2023 22:09:51 +0200 Subject: [PATCH 20/21] Update doc/htmldoc/connect_nest/nest_server.rst Co-authored-by: Sebastian Spreizer --- doc/htmldoc/connect_nest/nest_server.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/htmldoc/connect_nest/nest_server.rst b/doc/htmldoc/connect_nest/nest_server.rst index e728e61187..edc5bbfad0 100644 --- a/doc/htmldoc/connect_nest/nest_server.rst +++ b/doc/htmldoc/connect_nest/nest_server.rst @@ -428,7 +428,7 @@ After this, NumPy can be used from within scripts in the regular way: .. code-block:: Python from nest_client import NESTClient - nsc = NESTClient() + nest = NESTClient() response = nsc.exec_script("a = numpy.arange(10)", 'a') print(response['data'][::2]) # [0, 2, 4, 6, 8] From ab81f2a3a20cc5713f0769eb349e861a85808151 Mon Sep 17 00:00:00 2001 From: Jochen Martin Eppler Date: Wed, 12 Apr 2023 22:10:17 +0200 Subject: [PATCH 21/21] Update doc/htmldoc/connect_nest/nest_server.rst Co-authored-by: Pooja Babu <75320801+pnbabu@users.noreply.github.com> --- doc/htmldoc/connect_nest/nest_server.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/htmldoc/connect_nest/nest_server.rst b/doc/htmldoc/connect_nest/nest_server.rst index edc5bbfad0..d1d95c362b 100644 --- a/doc/htmldoc/connect_nest/nest_server.rst +++ b/doc/htmldoc/connect_nest/nest_server.rst @@ -153,7 +153,7 @@ The NEST Client --------------- The easiest way to interact with the NEST Server is the `NEST Client` -provided in `_. It can be used +provided in ``_. It can be used either by directly starting a Python session in a clone of that repository, or by installing it by running ``python3 setup.py install`` therein. NEST itself does not have to be installed in order