diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 54de0c6157..ce0bb21bae 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -58,7 +58,7 @@ jobs: run: | python3 -m venv music-venv source music-venv/bin/activate - python3 -m pip install mpi4py "cython<3" 'numpy<2' setuptools + python3 -m pip install 'mpi4py<4' cython numpy setuptools sudo mkdir -p $MUSIC_INSTALL_DIR sudo chown -R $USER $MUSIC_INSTALL_DIR curl -L -o MUSIC.zip https://github.com/INCF/MUSIC/archive/refs/tags/${MUSIC_VERSION}.zip diff --git a/.github/workflows/neuron-ci.yml b/.github/workflows/neuron-ci.yml index a355ca18cf..e3ca977eb4 100644 --- a/.github/workflows/neuron-ci.yml +++ b/.github/workflows/neuron-ci.yml @@ -207,7 +207,7 @@ jobs: run: | python3 -m venv music-venv source music-venv/bin/activate - python3 -m pip install mpi4py "cython<3" 'numpy<2' setuptools + python3 -m pip install 'mpi4py<4' cython numpy setuptools sudo mkdir -p $MUSIC_INSTALL_DIR sudo chown -R $USER $MUSIC_INSTALL_DIR curl -L -o MUSIC.zip https://github.com/INCF/MUSIC/archive/refs/tags/${MUSIC_VERSION}.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index c5dee70d64..1b74dbc9a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -325,9 +325,6 @@ if(NRN_ENABLE_RX3D) message(SEND_ERROR "NRN_ENABLE_RX3D requires NRN_ENABLE_PYTHON feature.") else() find_package(Cython REQUIRED) - if(CYTHON_VERSION VERSION_GREATER_EQUAL 3) - message(FATAL_ERROR "Cython 3+ is not supported") - endif() endif() endif() if(MINGW) @@ -382,9 +379,6 @@ if(NRN_ENABLE_MUSIC) message(FATAL "MUSIC requires -DNRN_ENABLE_PYTHON=ON") endif() find_package(Cython REQUIRED) - if(CYTHON_VERSION VERSION_GREATER_EQUAL 3) - message(FATAL_ERROR "Cython 3+ is not supported") - endif() find_package(MUSIC REQUIRED) set(NRN_MUSIC 1) endif() diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b7dd958f4a..238988a536 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -148,8 +148,8 @@ stages: export PATH=/usr/local/opt/flex/bin:/usr/local/opt/bison/bin:$PATH export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) export NRN_BUILD_FOR_UPLOAD=1 - sudo mkdir /opt/nrnwheel - sudo tar -zxf $(readlineSF.secureFilePath) --directory /opt/nrnwheel/ + sudo mkdir -p /opt/nrnwheel/$(uname -m) + sudo tar -zxf $(readlineSF.secureFilePath) --directory /opt/nrnwheel/$(uname -m) packaging/python/build_wheels.bash osx $(python.version) coreneuron displayName: 'Build MacOS Wheel' diff --git a/ci/win_build_cmake.sh b/ci/win_build_cmake.sh index c3c84ad37e..ca610acea3 100755 --- a/ci/win_build_cmake.sh +++ b/ci/win_build_cmake.sh @@ -10,7 +10,7 @@ export MSYSTEM_PREFIX=/mingw64 export PATH=/mingw64/bin:$PATH # have compatible cython3 -python3 -m pip install "cython<3" +python3 -m pip install "cython" # if BUILD_SOURCESDIRECTORY not available, use te root of the repo if [ -z "$BUILD_SOURCESDIRECTORY" ]; then @@ -30,7 +30,7 @@ cd $BUILD_SOURCESDIRECTORY/build -DNRN_ENABLE_RX3D=ON \ -DNRN_RX3D_OPT_LEVEL=2 \ -DNRN_BINARY_DIST_BUILD=ON \ - -DPYTHON_EXECUTABLE=/c/Python38/python.exe \ + -DPYTHON_EXECUTABLE=/c/Python39/python.exe \ -DNRN_ENABLE_PYTHON_DYNAMIC=ON \ -DNRN_PYTHON_DYNAMIC='c:/Python38/python.exe;c:/Python39/python.exe;c:/Python310/python.exe;c:/Python311/python.exe;c:/Python312/python.exe' \ -DCMAKE_INSTALL_PREFIX='/c/nrn-install' \ diff --git a/ci/win_install_deps.cmd b/ci/win_install_deps.cmd index c75e977a10..b30c41c733 100644 --- a/ci/win_install_deps.cmd +++ b/ci/win_install_deps.cmd @@ -23,11 +23,11 @@ pwsh -command "(Get-Content C:\Python310\Lib\distutils\cygwinccompiler.py) -repl pwsh -command "(Get-Content C:\Python311\Lib\distutils\cygwinccompiler.py) -replace 'msvcr100', 'msvcrt' | Out-File C:\Python311\Lib\distutils\cygwinccompiler.py" :: install numpy -C:\Python38\python.exe -m pip install numpy==1.17.5 "cython < 3" || goto :error -C:\Python39\python.exe -m pip install numpy==1.19.3 "cython < 3" || goto :error -C:\Python310\python.exe -m pip install numpy==1.21.3 "cython < 3" || goto :error -C:\Python311\python.exe -m pip install numpy==1.23.5 "cython < 3" || goto :error -C:\Python312\python.exe -m pip install numpy==1.26.3 "cython < 3" || goto :error +C:\Python38\python.exe -m pip install numpy cython || goto :error +C:\Python39\python.exe -m pip install numpy cython || goto :error +C:\Python310\python.exe -m pip install numpy cython || goto :error +C:\Python311\python.exe -m pip install numpy cython || goto :error +C:\Python312\python.exe -m pip install numpy cython || goto :error :: setuptools 70.2 leads to an error C:\Python312\python.exe -m pip install setuptools==70.1.1 || goto :error diff --git a/ci/win_test_installer.cmd b/ci/win_test_installer.cmd index 85255af463..0bf68842ab 100644 --- a/ci/win_test_installer.cmd +++ b/ci/win_test_installer.cmd @@ -21,9 +21,24 @@ C:\Python38\python -c "import neuron; neuron.test(); quit()" || set "errorfound= C:\Python39\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" C:\Python310\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" C:\Python311\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" -:: install numpy dependency -python -m pip install "numpy<2" +C:\Python312\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" + +:: install oldest supported numpy +C:\Python38\python.exe -m pip install -r packaging/python/oldest_numpy_requirements.txt || goto :error +C:\Python39\python.exe -m pip install -r packaging/python/oldest_numpy_requirements.txt || goto :error +C:\Python310\python.exe -m pip install -r packaging/python/oldest_numpy_requirements.txt || goto :error +C:\Python311\python.exe -m pip install -r packaging/python/oldest_numpy_requirements.txt || goto :error +C:\Python312\python.exe -m pip install -r packaging/python/oldest_numpy_requirements.txt || goto :error + +:: test all pythons again +C:\Python38\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" +C:\Python39\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" +C:\Python310\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" +C:\Python311\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" +C:\Python312\python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" + :: run also using whatever is system python +python -m pip install numpy python --version python -c "import neuron; neuron.test(); quit()" || set "errorfound=y" diff --git a/cmake/ExternalProjectHelper.cmake b/cmake/ExternalProjectHelper.cmake index d1227d056c..c7f5f2299e 100644 --- a/cmake/ExternalProjectHelper.cmake +++ b/cmake/ExternalProjectHelper.cmake @@ -29,7 +29,11 @@ function(nrn_initialize_submodule path) list(APPEND UPDATE_OPTIONS --recursive) endif() if(opt_SHALLOW) - list(APPEND UPDATE_OPTIONS --depth 1) + # RHEL7-family distributions ship with an old git that does not support the --depth argument to + # git submodule update + if(GIT_VERSION_STRING VERSION_GREATER_EQUAL "1.8.4") + list(APPEND UPDATE_OPTIONS --depth 1) + endif() endif() if(NOT ${GIT_FOUND}) message( diff --git a/cmake/NeuronFileLists.cmake b/cmake/NeuronFileLists.cmake index ad70963033..9809bf8f88 100644 --- a/cmake/NeuronFileLists.cmake +++ b/cmake/NeuronFileLists.cmake @@ -17,6 +17,7 @@ set(HEADER_FILES_TO_INSTALL nrniv/neuronapi.h nrnmpi/nrnmpidec.h nrnoc/cabvars.h + nrnoc/cabcode.h nrnoc/md1redef.h nrnoc/md2redef.h nrnoc/membdef.h @@ -126,7 +127,6 @@ set(NRNOC_FILE_LIST ldifus.cpp membfunc.cpp memblist.cpp - nrnnemo.cpp nrntimeout.cpp nrnversion.cpp passive0.cpp diff --git a/cmake/coreneuron/MakefileBuildOptions.cmake b/cmake/coreneuron/MakefileBuildOptions.cmake index 1ab2de8e92..5f7119dddf 100644 --- a/cmake/coreneuron/MakefileBuildOptions.cmake +++ b/cmake/coreneuron/MakefileBuildOptions.cmake @@ -73,13 +73,19 @@ function(coreneuron_process_target target) if(target_imported) # In this case we can extract the full path to the library get_target_property(target_location ${target} LOCATION) - coreneuron_process_library_path(${target_location}) + if(target_location) + coreneuron_process_library_path(${target_location}) + endif() else() # This is probably another of our libraries, like -lcoreneuron-cuda. We might need to add -L # and an RPATH later. set_property(GLOBAL APPEND_STRING PROPERTY CORENRN_LIB_LINK_DEP_FLAGS " -l${target}") endif() endif() + get_target_property(target_flags ${target} INTERFACE_COMPILE_OPTIONS) + if(target_flags) + set_property(GLOBAL APPEND_STRING PROPERTY CORENRN_EXTRA_COMPILE_FLAGS " ${target_flags}") + endif() get_target_property(target_libraries ${target} LINK_LIBRARIES) if(target_libraries) foreach(child_target ${target_libraries}) diff --git a/docs/changelog.md b/docs/changelog.md index 0185999a9d..803c8cb372 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,21 @@ # NEURON 8.2 +## 8.2.6 +_Release Date_ : 24-07-2024 + +This release pins numpy to <2 and includes backports for several fixes. + +### Bug Fixes +- Informative error when cannot import hoc module +- ParallelContext: hoc_ac_ encodes global id of submitted process. +- Python 3.12 compatibility with Windows installer (#2963) +- Windows 11 fix for nrniv -python (#2946) +- Fix for dynamic ECS diffusion characteristics. +- python38 is back. For testing can use rx3doptlevel=0 bash bldnrnmacpkgcmake.sh +- Fix cvode.use_fast_imem(1) error with electrode time varying conductance. +- Apple M1 cmake failure in cloning subrepository. See #2326. +- Update iv + ## 8.2.4 _Release Date_ : 08-02-2024 diff --git a/docs/conda_environment.yml b/docs/conda_environment.yml index d13bdc8775..6abc60862b 100644 --- a/docs/conda_environment.yml +++ b/docs/conda_environment.yml @@ -9,7 +9,7 @@ dependencies: - cmake - xorg-libxcomposite - ffmpeg - - cython<3 + - cython - pandoc - mpich - pip diff --git a/docs/dev/setuptools/setuptools.md b/docs/dev/setuptools/setuptools.md index 56cc37f5e2..ae449e4f7e 100644 --- a/docs/dev/setuptools/setuptools.md +++ b/docs/dev/setuptools/setuptools.md @@ -15,20 +15,64 @@ We use [setup.py](../../../setup.py) in two operational modes : 1) **wheel building** - It boils down to + It boils down to setup.py build_ext bdist_wheel - + We configure the HOC extension along with a CMake configure, build all extensios and collect them for the wheel. This is called via [build_wheels.bash](../../../packaging/python/build_wheels.bash). 2) **CMake build** It boils down to - - setup.py build_ext build - We provide the cmake build folder, in this mode we do not run CMake configure, we build all extensions and make sure they are integrated into the CMake build and install. This is called via CMake in [src/nrnpython/CMakeLists.txt](../../../src/nrnpython/CMakeLists.txt) by passing **--cmake-build-dir** (the folder where we configured NEURON with CMake), along with other CMake options. + setup.py build_ext build + + We provide the cmake build folder, in this mode we do not run CMake configure, we build all extensions and make sure they are integrated into the CMake build and install. This is called via CMake in [src/nrnpython/CMakeLists.txt](../../../src/nrnpython/CMakeLists.txt) by passing **--cmake-build-dir** (the folder where we configured NEURON with CMake), along with other CMake options. ## **Activity Diagram** -![](images/setup-py.png) \ No newline at end of file +![](images/setup-py.png) + + +## Creating a Development Python Package + +`setup.py` can be lanched manually as well to create a dev build package, which can be tested +immediately. It supports several arguments to that the build can be tuned: + +``` + --disable-rx3d Disables Rx3d. Implies CMake -DNRN_ENABLE_RX3D=OFF + --disable-iv Disables IV. Implies CMake -DNRN_ENABLE_INTERVIEWS=OFF + --disable-mpi Disables MPI. Implies -DNRN_ENABLE_MPI=OFF and disabling of neuronmusic + --enable-music Enables neuronmusic + --enable-coreneuron Enables experimental CorenNeuron support + --rx3d-opt-level Sets the rx3d optimization level. Default: 0 (-O0) + --cmake-build-dir Declares one wants to use a specic NEURON build (with CMake), instead + of creating one behind the scenes. Only builds extensions and package. +``` + +A quick build for testing a change to a core component could therefore be: +``` +python setup.py build --disable-rx3d --disable-iv --disable-mpi +``` + +--- +**Mac Note** + +Since the introduction of Mac with Apple silicon, with an Official Python distribution, extension are simultaneously built for arm64 and x86_64. Besides not required for a dev build, it may fail +on older SDKs with `Unsupported architecture` errors. + +To skip that you may set the ARCHFLAGS environment var. Set it to "" (empty) for default architecture: `ARCHFLAGS='' python setup.py ...` + +--- + +### Testing + +Once built, the package may be imported and used normally. You might, however, need to set up +PYTHONPATH accordingly for the import to work: + +``` +export PYTHONPATH="/build/lib.macosx-10.9-x86_64-3.9/:$PYTHONPATH" + +# Run Neuron base tests +python -c "import neuron; neuron.test()" +``` diff --git a/docs/guide/hoc_chapter_11_old_reference.rst b/docs/guide/hoc_chapter_11_old_reference.rst index c09930d940..aeeb70bbf0 100644 --- a/docs/guide/hoc_chapter_11_old_reference.rst +++ b/docs/guide/hoc_chapter_11_old_reference.rst @@ -338,7 +338,7 @@ Names introduced by nrnoc .. code:: c++ - node_data disconnect batch_run batch_save + disconnect batch_run batch_save pt3dclear pt3dadd n3d x3d y3d z3d diam3d arc3d define_shape p3dconst spine3d setSpineArea getSpineArea area ri initnrn topology fadvance distance diff --git a/docs/hoc/compilationoptions.rst b/docs/hoc/compilationoptions.rst index fd40c2b306..e06db2fceb 100644 --- a/docs/hoc/compilationoptions.rst +++ b/docs/hoc/compilationoptions.rst @@ -3,8 +3,7 @@ Rarely Used Compilation Options The following definitions are found in nrnoc/SRC/options.h and add extra functionality which not everyone may need. The extras come at the cost -of larger memory requirements for node and section structures. METHOD3 is too large -and obscure to benefit most users. +of larger memory requirements for node and section structures. .. code-block:: none @@ -27,29 +26,3 @@ and obscure to benefit most users. * of spine. setSpineArea() tells how much * area/spine to add to the segment. */ #endif - - #define METHOD3 1 /* third order spatially correct method */ - /* testing only, not completely implemented */ - /* not working at this time */ - - #if METHOD3 - spatial_method(i) - no arg, returns current method - i=0 The standard NEURON method with zero area nodes at the ends - of sections. - i=1 conventional method with 1/2 area end nodes - i=2 modified second order method - i=3 third order correct spatial method - Note: i=1-3 don't work under all circumstances. They have been - insufficiently tested and the correctness must be established for - each simulation. - #endif - - #if NEMO - neuron2nemo("filename") Beginning of translator between John Millers - nemosys program and NEURON. Probably out of date. - nemo2neuron("filename") - #endif - - - diff --git a/docs/index.rst b/docs/index.rst index 7db6fdcc5e..f56c3fdcdd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -98,7 +98,7 @@ Installation pip3 install neuron - Alternatively, you can use the `PKG installer `_. + Alternatively, you can use the `PKG installer `_. For troubleshooting, see the `detailed installation instructions `_. @@ -115,7 +115,7 @@ Installation .. tab-item:: Windows - `Download the Windows Installer `_. + `Download the Windows Installer `_. You can also install the Linux wheel via the Windows Subsystem for Linux (WSL). See `instructions `_. diff --git a/docs/install/install_instructions.md b/docs/install/install_instructions.md index 209509b371..dcce802840 100644 --- a/docs/install/install_instructions.md +++ b/docs/install/install_instructions.md @@ -207,7 +207,7 @@ In order to build NEURON from source, the following packages must be available: The following packages are optional (see build options): - Python >=3.8 (for Python interface) -- Cython < 3 (for RXD) +- Cython (for RXD) - MPI (for parallel) - X11 (Linux) or XQuartz (MacOS) (for GUI) @@ -482,7 +482,7 @@ share/lib/python/neuron/rxd/geometry3d/surfaces.cpp:14605:41: error: no member n ``` often there's something related to NumPy nearby, e.g. `npy`. -The issue is that certain versions of NEURON (9.0 and earlier) are not +The issue is that certain versions of NEURON (below 9.0) are not compatible with `numpy>=2`. Check the numpy version, e.g., ``` python -c "import numpy; print(numpy.__version__)" diff --git a/docs/install/python_wheels.md b/docs/install/python_wheels.md index 7b6d6b1cf8..42387bfad8 100644 --- a/docs/install/python_wheels.md +++ b/docs/install/python_wheels.md @@ -264,24 +264,39 @@ $ git checkout 8.1a -b release/8.1a-aarch64 # manually updated `.circleci/config.yml` $ git diff -@@ -15,6 +15,10 @@ jobs: +@@ -14,6 +14,11 @@ jobs: + machine: image: ubuntu-2004:202101-01 + environment: -+ SETUPTOOLS_SCM_PRETEND_VERSION: 8.1a ++ SETUPTOOLS_SCM_PRETEND_VERSION: 8.2.6 + NEURON_NIGHTLY_TAG: "" + NRN_NIGHTLY_UPLOAD: false + NRN_RELEASE_UPLOAD: false -@@ -89,7 +95,7 @@ workflows: - - manylinux2014-aarch64: + resource_class: arm.medium + +@@ -54,6 +59,7 @@ jobs: + 39) pyenv_py_ver="3.9.1" ;; + 310) pyenv_py_ver="3.10.1" ;; + 311) pyenv_py_ver="3.11.0" ;; ++ 312) pyenv_py_ver="3.12.2" ;; + *) echo "Error: pyenv python version not specified!" && exit 1;; + esac + +@@ -95,7 +101,7 @@ workflows: + - /circleci\/.*/ matrix: parameters: - NRN_PYTHON_VERSION: ["311"] -+ NRN_PYTHON_VERSION: ["38", "39", "310", "311"] ++ NRN_PYTHON_VERSION: ["38", "39", "310", "311", "312"] + NRN_NIGHTLY_UPLOAD: ["false"] + + nightly: ``` The reason we are setting `SETUPTOOLS_SCM_PRETEND_VERSION` to a desired version `8.1a` because `setup.py` uses `git describe` and it will give different version name as we are now on a new branch! +`NEURON_WHEEL_VERSION` will also stop your wheels from getting extra numbers on the version ## Nightly wheels diff --git a/docs/python/compilationoptions.rst b/docs/python/compilationoptions.rst index fd40c2b306..e06db2fceb 100755 --- a/docs/python/compilationoptions.rst +++ b/docs/python/compilationoptions.rst @@ -3,8 +3,7 @@ Rarely Used Compilation Options The following definitions are found in nrnoc/SRC/options.h and add extra functionality which not everyone may need. The extras come at the cost -of larger memory requirements for node and section structures. METHOD3 is too large -and obscure to benefit most users. +of larger memory requirements for node and section structures. .. code-block:: none @@ -27,29 +26,3 @@ and obscure to benefit most users. * of spine. setSpineArea() tells how much * area/spine to add to the segment. */ #endif - - #define METHOD3 1 /* third order spatially correct method */ - /* testing only, not completely implemented */ - /* not working at this time */ - - #if METHOD3 - spatial_method(i) - no arg, returns current method - i=0 The standard NEURON method with zero area nodes at the ends - of sections. - i=1 conventional method with 1/2 area end nodes - i=2 modified second order method - i=3 third order correct spatial method - Note: i=1-3 don't work under all circumstances. They have been - insufficiently tested and the correctness must be established for - each simulation. - #endif - - #if NEMO - neuron2nemo("filename") Beginning of translator between John Millers - nemosys program and NEURON. Probably out of date. - nemo2neuron("filename") - #endif - - - diff --git a/nrn_requirements.txt b/nrn_requirements.txt index 8eaec90ee4..f049602b4e 100644 --- a/nrn_requirements.txt +++ b/nrn_requirements.txt @@ -1,15 +1,15 @@ wheel -setuptools setuptools_scm +setuptools<=70.3.0 scikit-build matplotlib # bokeh 3 seems to break docs notebooks bokeh<3 ipython -cython<3 +cython packaging pytest<=8.1.1 # potential bug from 8.2.0 due to parallelism? pytest-cov -mpi4py -numpy<2 +mpi4py<4 # MUSIC not compatible with MPI 4 +numpy find_libpython diff --git a/packaging/python/build_requirements.txt b/packaging/python/build_requirements.txt index c92f711148..71fe06794e 100644 --- a/packaging/python/build_requirements.txt +++ b/packaging/python/build_requirements.txt @@ -1,8 +1,3 @@ -cython<3 +cython packaging -numpy==1.17.5;python_version=='3.8' -numpy==1.19.3;python_version=='3.9' and platform_machine=='x86_64' -numpy==1.21.3;python_version=='3.9' and platform_machine=='arm64' -numpy==1.21.3;python_version=='3.10' -numpy==1.23.5;python_version=='3.11' -numpy==1.26.0;python_version=='3.12' +numpy diff --git a/packaging/python/build_static_readline_osx.bash b/packaging/python/build_static_readline_osx.bash index efe0bf09d5..26919f8958 100644 --- a/packaging/python/build_static_readline_osx.bash +++ b/packaging/python/build_static_readline_osx.bash @@ -1,57 +1,55 @@ #!/usr/bin/env bash -set -xe +set -eux # A script to build a static readline library for osx # # PREREQUESITES: # - curl -# - wget # - C/C++ compiler -# - /opt/nrnwheel folder created with access rights (this specific path is kept for consistency wrt `build_wheels.bash`) +# - /opt/nrnwheel/[ARCH] folder created with access rights (this specific path is kept for consistency wrt `build_wheels.bash`) -set -e - -if [[ `uname -s` != 'Darwin' ]]; then +if [[ "$(uname -s)" != 'Darwin' ]]; then echo "Error: this script is for macOS only. readline is already built statically in the linux Docker images" exit 1 fi -NRNWHEEL_DIR=/opt/nrnwheel +ARCH="$(uname -m)" + +NRNWHEEL_DIR="${1:-/opt/nrnwheel/${ARCH}}" if [[ ! -d "$NRNWHEEL_DIR" || ! -x "$NRNWHEEL_DIR" ]]; then - echo "Error: /opt/nrnwheel must exist and be accessible, i.e: sudo mkdir -p /opt/nrnwheel && sudo chown -R $USER /opt/nrnwheel" + echo "Error: ${NRNWHEEL_DIR} must exist and be accessible, i.e: sudo mkdir -p ${NRNWHEEL_DIR} && sudo chown -R ${USER} ${NRNWHEEL_DIR}" exit 1 fi # Set MACOSX_DEPLOYMENT_TARGET based on wheel arch. # For upcoming `universal2` wheels we will consider leveling everything to 11.0. -if [[ `uname -m` == 'arm64' ]]; then +if [[ "${ARCH}" == 'arm64' ]]; then export MACOSX_DEPLOYMENT_TARGET=11.0 # for arm64 we need 11.0 else export MACOSX_DEPLOYMENT_TARGET=10.9 # for x86_64 fi -(wget http://ftpmirror.gnu.org/ncurses/ncurses-6.4.tar.gz \ +(curl -L -o ncurses-6.4.tar.gz http://ftpmirror.gnu.org/ncurses/ncurses-6.4.tar.gz \ && tar -xvzf ncurses-6.4.tar.gz \ && cd ncurses-6.4 \ - && ./configure --prefix=/opt/nrnwheel/ncurses --without-shared CFLAGS="-fPIC" \ + && ./configure --prefix="${NRNWHEEL_DIR}/ncurses" --without-shared CFLAGS="-fPIC" \ && make -j install) (curl -L -o readline-7.0.tar.gz https://ftp.gnu.org/gnu/readline/readline-7.0.tar.gz \ && tar -xvzf readline-7.0.tar.gz \ && cd readline-7.0 \ - && ./configure --prefix=/opt/nrnwheel/readline --disable-shared CFLAGS="-fPIC" \ + && ./configure --prefix="${NRNWHEEL_DIR}/readline" --disable-shared CFLAGS="-fPIC" \ && make -j install) -(cd /opt/nrnwheel/readline/lib \ +(cd "${NRNWHEEL_DIR}/readline/lib" \ && ar -x libreadline.a \ && ar -x ../../ncurses/lib/libncurses.a \ && ar cq libreadline.a *.o \ && rm *.o) -RDL_MINOS=`otool -l /opt/nrnwheel/readline/lib/libreadline.a | grep -e "minos \|version " | uniq | awk '{print $2}'` +RDL_MINOS="$(otool -l "${NRNWHEEL_DIR}/readline/lib/libreadline.a" | grep -e "minos \|version " | uniq | awk '{print $2}')" if [ "$RDL_MINOS" != "$MACOSX_DEPLOYMENT_TARGET" ]; then - echo "Error: /opt/nrnwheel/readline/lib/libreadline.a doesn't match MACOSX_DEPLOYMENT_TARGET ($MACOSX_DEPLOYMENT_TARGET)" + echo "Error: ${NRNWHEEL_DIR}/readline/lib/libreadline.a doesn't match MACOSX_DEPLOYMENT_TARGET ($MACOSX_DEPLOYMENT_TARGET)" exit 1 fi - echo "Done." diff --git a/packaging/python/build_wheels.bash b/packaging/python/build_wheels.bash index 4da4f01f06..eeebf32f21 100755 --- a/packaging/python/build_wheels.bash +++ b/packaging/python/build_wheels.bash @@ -71,7 +71,7 @@ build_wheel_linux() { if [ "$2" == "coreneuron" ]; then setup_args="--enable-coreneuron" clone_nmodl_and_add_requirements - CMAKE_DEFS="${CMAKE_DEFS},LINK_AGAINST_PYTHON=OFF" + CMAKE_DEFS="${CMAKE_DEFS},LINK_AGAINST_PYTHON=OFF,CORENRN_ENABLE_OPENMP=ON" fi cat my_requirements.txt @@ -118,17 +118,17 @@ build_wheel_osx() { echo " - Installing build requirements" cp packaging/python/build_requirements.txt my_requirements.txt + CMAKE_DEFS="NRN_MPI_DYNAMIC=$3" + if [ "$USE_STATIC_READLINE" == "1" ]; then + CMAKE_DEFS="$CMAKE_DEFS,NRN_BINARY_DIST_BUILD=ON,NRN_WHEEL_STATIC_READLINE=ON" + fi + if [ "$2" == "coreneuron" ]; then setup_args="--enable-coreneuron" clone_nmodl_and_add_requirements CMAKE_DEFS="${CMAKE_DEFS},LINK_AGAINST_PYTHON=OFF" fi - CMAKE_DEFS="NRN_MPI_DYNAMIC=$3" - if [ "$USE_STATIC_READLINE" == "1" ]; then - CMAKE_DEFS="$CMAKE_DEFS,NRN_BINARY_DIST_BUILD=ON,NRN_WHEEL_STATIC_READLINE=ON" - fi - cat my_requirements.txt pip install -U delocate -r my_requirements.txt pip check @@ -160,7 +160,7 @@ build_wheel_osx() { fi fi - python setup.py build_ext --cmake-prefix="/opt/nrnwheel/ncurses;/opt/nrnwheel/readline;/usr/x11" --cmake-defs="$CMAKE_DEFS" $setup_args bdist_wheel + python setup.py build_ext --cmake-prefix="/opt/nrnwheel/$(uname -m)/ncurses;/opt/nrnwheel/$(uname -m)/readline;/usr/x11" --cmake-defs="$CMAKE_DEFS" $setup_args bdist_wheel echo " - Calling delocate-listdeps" delocate-listdeps dist/*.whl diff --git a/packaging/python/oldest_numpy_requirements.txt b/packaging/python/oldest_numpy_requirements.txt new file mode 100644 index 0000000000..4a77e64c2b --- /dev/null +++ b/packaging/python/oldest_numpy_requirements.txt @@ -0,0 +1,5 @@ +numpy==1.20.3;python_version=='3.9' and platform_machine!='arm64' +numpy==1.21.6;python_version=='3.9' and platform_machine=='arm64' +numpy==1.21.6;python_version=='3.10' +numpy==1.23.5;python_version=='3.11' +numpy==1.26.4;python_version=='3.12' diff --git a/packaging/python/test_requirements.txt b/packaging/python/test_requirements.txt new file mode 100644 index 0000000000..6dbabce060 --- /dev/null +++ b/packaging/python/test_requirements.txt @@ -0,0 +1,2 @@ +pytest +setuptools;python_version>='3.12' # From 3.12, no longer installed by default diff --git a/packaging/python/test_wheels.sh b/packaging/python/test_wheels.sh index 1234d57c2d..853d7cbd7e 100755 --- a/packaging/python/test_wheels.sh +++ b/packaging/python/test_wheels.sh @@ -237,6 +237,12 @@ test_wheel () { } +test_wheel_basic_python () { + echo "=========== BASIC PYTHON TESTS ===========" + $python_exe -c "import neuron; neuron.test(); neuron.test_rxd()" +} + + echo "== Testing $python_wheel using $python_exe ($python_ver) ==" @@ -257,10 +263,8 @@ fi $python_exe -m pip install --upgrade pip -# install numpy, pytest and neuron -# we install setuptools because since python 3.12 it is no more installed -# by default -$python_exe -m pip install "numpy<2" pytest setuptools +# install test requirements +$python_exe -m pip install -r packaging/python/test_requirements.txt $python_exe -m pip install $python_wheel $python_exe -m pip show neuron || $python_exe -m pip show neuron-nightly @@ -271,8 +275,14 @@ if echo $compile_options | grep "NRN_ENABLE_CORENEURON=ON" > /dev/null ; then has_coreneuron=true fi -# run tests -test_wheel "${python_exe}" +# run tests with latest NumPy +echo " == Running tests with latest NumPy == " +test_wheel + +# run basic python tests with oldest supported NumPy +echo " == Running basic python tests with oldest supported NumPy == " +$python_exe -m pip install -r packaging/python/oldest_numpy_requirements.txt +test_wheel_basic_python # cleanup if [[ "$use_venv" != "false" ]]; then diff --git a/setup.py b/setup.py index 96382a2e5e..e15b6e5ac0 100644 --- a/setup.py +++ b/setup.py @@ -354,7 +354,7 @@ def setup_package(): NRN_COLLECT_DIRS = ["bin", "lib", "include", "share"] docs_require = [] # sphinx, themes, etc - maybe_rxd_reqs = ["numpy<2", "Cython<3"] if Components.RX3D else [] + maybe_rxd_reqs = ["numpy", "Cython"] if Components.RX3D else [] maybe_docs = docs_require if "docs" in sys.argv else [] maybe_test_runner = ["pytest-runner"] if "test" in sys.argv else [] @@ -379,7 +379,6 @@ def setup_package(): list, library_dirs=[os.path.join(cmake_build_dir, "lib")], libraries=ext_common_libraries, - language="c++", ) logging.info("Extension common compile flags %s" % str(extension_common_params)) @@ -407,7 +406,6 @@ def setup_package(): ] + ( [ - "-DCORENRN_ENABLE_OPENMP=ON", # TODO: manylinux portability questions "-DNMODL_ENABLE_PYTHON_BINDINGS=ON", ] if Components.CORENRN @@ -436,6 +434,7 @@ def setup_package(): "neuronmusic", ["src/neuronmusic/neuronmusic.pyx"], include_dirs=["src/nrnpython", "src/nrnmusic"], + language="c++", **extension_common_params, ) ] @@ -510,10 +509,10 @@ def setup_package(): }, cmdclass=dict(build_ext=CMakeAugmentedBuilder, docs=Docs), install_requires=[ - "numpy>=1.9.3,<2", + "numpy>=1.9.3", "packaging", "find_libpython", - "setuptools", + "setuptools<=70.3.0", ] + ( [ diff --git a/share/lib/python/neuron/__init__.py b/share/lib/python/neuron/__init__.py index c48fdd56ef..36bca6d407 100644 --- a/share/lib/python/neuron/__init__.py +++ b/share/lib/python/neuron/__init__.py @@ -104,7 +104,7 @@ import warnings import weakref -embedded = True if "hoc" in sys.modules else False +embedded = "hoc" in sys.modules # First, check that the compiled extension (neuron.hoc) was built for this version of # Python. If not, fail early and helpfully. @@ -291,7 +291,6 @@ def test_rxd(exitOnError=True): # using the idiom self.basemethod = self.baseattr('methodname') # ------------------------------------------------------------------------------ -import sys, types from neuron.hclass3 import HocBaseObject, hclass # global list of paths already loaded by load_mechanisms @@ -341,8 +340,6 @@ def load_mechanisms(path, warn_if_already_loaded=True): return False -import os, sys - if "NRN_NMODL_PATH" in os.environ: nrn_nmodl_path = os.environ["NRN_NMODL_PATH"].split(":") print("Auto-loading mechanisms:") @@ -478,21 +475,6 @@ def quit(*args, **kwargs): return h.quit(*args, **kwargs) -def hoc_execute(hoc_commands, comment=None): - assert isinstance(hoc_commands, list) - if comment: - logging.debug(comment) - for cmd in hoc_commands: - logging.debug(cmd) - success = hoc.execute(cmd) - if not success: - raise HocError('Error produced by hoc command "%s"' % cmd) - - -def hoc_comment(comment): - logging.debug(comment) - - def psection(section): """ function psection(section): @@ -650,7 +632,6 @@ def nrn_dll_sym(name, type=None): """ # TODO: this won't work under Windows; will need to search through until # can find the right dll (should we cache the results of the search?) - import os if os.name == "nt": return nrn_dll_sym_nt(name, type) @@ -671,7 +652,6 @@ def nrn_dll_sym_nt(name, type): """ global nt_dlls import ctypes - import os if len(nt_dlls) == 0: b = "bin" @@ -708,8 +688,6 @@ def nrn_dll(printpath=False): """ import ctypes import glob - import os - import sys try: # extended? if there is a __file__, then use that diff --git a/share/lib/python/neuron/rxd/geometry3d/surfaces.pyx b/share/lib/python/neuron/rxd/geometry3d/surfaces.pyx index 141adf7899..bf3aac2eb1 100644 --- a/share/lib/python/neuron/rxd/geometry3d/surfaces.pyx +++ b/share/lib/python/neuron/rxd/geometry3d/surfaces.pyx @@ -1,13 +1,11 @@ import os import numpy -import graphicsPrimitives -import neuron -import numpy cimport numpy import itertools import bisect cimport cython +from neuron.rxd.geometry3d import graphicsPrimitives """ The surfaces module diff --git a/share/lib/python/neuron/rxd/rxd.py b/share/lib/python/neuron/rxd/rxd.py index 0ac5249684..3c0fd18a8e 100644 --- a/share/lib/python/neuron/rxd/rxd.py +++ b/share/lib/python/neuron/rxd/rxd.py @@ -61,7 +61,7 @@ setup_solver.argtypes = [ ndpointer(ctypes.c_double), ctypes.c_int, - numpy.ctypeslib.ndpointer(numpy.int_, flags="contiguous"), + numpy.ctypeslib.ndpointer(ctypes.c_long, flags="contiguous"), ctypes.c_int, ] @@ -630,8 +630,8 @@ def _matrix_to_rxd_sparse(m): return ( n, len(nonzero_i), - numpy.ascontiguousarray(nonzero_i, dtype=numpy.int_), - numpy.ascontiguousarray(nonzero_j, dtype=numpy.int_), + numpy.ascontiguousarray(nonzero_i, dtype=ctypes.c_long), + numpy.ascontiguousarray(nonzero_j, dtype=ctypes.c_long), nonzero_values, ) @@ -709,7 +709,7 @@ def _setup_matrices(): n = len(_node_get_states()) volumes = node._get_data()[0] - zero_volume_indices = (numpy.where(volumes == 0)[0]).astype(numpy.int_) + zero_volume_indices = (numpy.where(volumes == 0)[0]).astype(ctypes.c_long) if species._has_1d: # TODO: initialization is slow. track down why for sr in _species_get_all_species(): @@ -1896,7 +1896,7 @@ def _init(): _setup_matrices() # if species._has_1d and species._1d_submatrix_n(): # volumes = node._get_data()[0] - # zero_volume_indices = (numpy.where(volumes == 0)[0]).astype(numpy.int_) + # zero_volume_indices = (numpy.where(volumes == 0)[0]).astype(ctypes.c_long) # setup_solver(_node_get_states(), len(_node_get_states()), zero_volume_indices, len(zero_volume_indices), h._ref_t, h._ref_dt) clear_rates() _setup_memb_currents() diff --git a/share/lib/python/neuron/rxd/species.py b/share/lib/python/neuron/rxd/species.py index de8a3095b2..bd6e59f610 100644 --- a/share/lib/python/neuron/rxd/species.py +++ b/share/lib/python/neuron/rxd/species.py @@ -60,12 +60,12 @@ ctypes.c_int, ctypes.py_object, ctypes.c_long, - numpy.ctypeslib.ndpointer(dtype=int), - numpy.ctypeslib.ndpointer(dtype=int), + numpy.ctypeslib.ndpointer(dtype=ctypes.c_long), + numpy.ctypeslib.ndpointer(dtype=ctypes.c_long), ctypes.c_long, - numpy.ctypeslib.ndpointer(dtype=int), + numpy.ctypeslib.ndpointer(dtype=ctypes.c_long), ctypes.c_long, - numpy.ctypeslib.ndpointer(dtype=int), + numpy.ctypeslib.ndpointer(dtype=ctypes.c_long), ctypes.c_long, numpy.ctypeslib.ndpointer(dtype=float), ctypes.c_double, @@ -842,7 +842,7 @@ def line_defs(self, nodes, direction, nodes_length): # sort list for parallelization line_defs.sort(key=lambda x: x[1], reverse=True) - line_defs = numpy.asarray(line_defs, dtype=int) + line_defs = numpy.asarray(line_defs, dtype=ctypes.c_long) line_defs = line_defs.reshape(2 * len(line_defs)) return line_defs @@ -862,7 +862,7 @@ def ordered_nodes(self, p_line_defs, direction, neighbors): def create_neighbors_array(self, nodes, nodes_length): self._isalive() - my_array = numpy.zeros((nodes_length, 3), dtype=int) + my_array = numpy.zeros((nodes_length, 3), dtype=ctypes.c_long) for n in nodes: for i, ele in enumerate(n.neighbors[::2]): my_array[n._index, i] = ele if ele is not None else -1 diff --git a/src/coreneuron/CMakeLists.txt b/src/coreneuron/CMakeLists.txt index cf4fdf4903..1cf452d23c 100644 --- a/src/coreneuron/CMakeLists.txt +++ b/src/coreneuron/CMakeLists.txt @@ -29,7 +29,7 @@ include(${CODING_CONV_CMAKE}/build-time-copy.cmake) # ============================================================================= # Build options # ============================================================================= -option(CORENRN_ENABLE_OPENMP "Build the CORE NEURON with OpenMP implementation" ON) +option(CORENRN_ENABLE_OPENMP "Build the CORE NEURON with OpenMP implementation" OFF) option(CORENRN_ENABLE_OPENMP_OFFLOAD "Prefer OpenMP target offload to OpenACC" ON) option(CORENRN_ENABLE_TIMEOUT "Enable nrn_timeout implementation" ON) option(CORENRN_ENABLE_REPORTING "Enable use of libsonata for soma reports" OFF) @@ -197,11 +197,7 @@ if(NRN_ENABLE_MPI_DYNAMIC) endif() if(CORENRN_ENABLE_OPENMP) - find_package(OpenMP QUIET) - if(OPENMP_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} ${ADDITIONAL_THREADSAFE_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} ${ADDITIONAL_THREADSAFE_FLAGS}") - endif() + find_package(OpenMP REQUIRED) endif() list(APPEND CORENRN_COMPILE_DEFS LAYOUT=0) @@ -444,6 +440,14 @@ endif() # https://forums.developer.nvidia.com/t/cannot-dynamically-load-a-shared-library-containing-both-openacc-and-cuda-code/210972 add_library(coreneuron-core STATIC ${CORENEURON_CODE_FILES} ${CORENRN_MPI_OBJ}) add_dependencies(coreneuron-core coreneuron-copy-nrnivmodl-core-dependencies) +if(CORENRN_ENABLE_OPENMP) + # target_link_libraries(coreneuron-core PUBLIC OpenMP::OpenMP_CXX) + target_compile_options(coreneuron-core PUBLIC ${OpenMP_CXX_FLAGS}) + target_link_libraries(coreneuron-core PUBLIC ${OpenMP_CXX_LIB_NAMES}) + # The first line uses a generator expression to arrive at -fopenmp (or equivalent) - this will not + # work with our Makefile generation. Thus specify the flag manually. Enable the first line and + # remove the last two lines below once we get rid of the mechanism building Makefile. +endif() if(CORENRN_ENABLE_GPU) set(coreneuron_cuda_target coreneuron-cuda) add_library(coreneuron-cuda ${COMPILE_LIBRARY_TYPE} ${CORENEURON_CUDA_FILES}) diff --git a/src/neuron/model_data.hpp b/src/neuron/model_data.hpp index 9d71d80074..8909aa01cc 100644 --- a/src/neuron/model_data.hpp +++ b/src/neuron/model_data.hpp @@ -124,7 +124,7 @@ struct Model { private: container::Mechanism::storage& mechanism_data_impl(int type) const { - if (0 <= type && type >= m_mech_data.size()) { + if (type < 0 || type >= m_mech_data.size()) { throw std::runtime_error("mechanism_data(" + std::to_string(type) + "): type out of range"); } diff --git a/src/nmodl/noccout.cpp b/src/nmodl/noccout.cpp index 9eb07ab829..31c83e2e73 100644 --- a/src/nmodl/noccout.cpp +++ b/src/nmodl/noccout.cpp @@ -85,12 +85,12 @@ void c_out() { P("#undef PI\n"); P("#define nil 0\n"); P("#define _pval pval\n"); // due to some old models using _pval - P("// clang-format on\n"); + P("// clang-format off\n"); P("#include \"md1redef.h\"\n"); P("#include \"section_fwd.hpp\"\n"); P("#include \"nrniv_mf.h\"\n"); P("#include \"md2redef.h\"\n"); - P("// clang-format off\n"); + P("// clang-format on\n"); P("#include \"neuron/cache/mechanism_range.hpp\"\n"); P("#include \n"); diff --git a/src/nmodl/parse1.ypp b/src/nmodl/parse1.ypp index 443825a1ea..2d94253d41 100755 --- a/src/nmodl/parse1.ypp +++ b/src/nmodl/parse1.ypp @@ -172,14 +172,26 @@ model: MODEL line line: {$$ = inputline();} ; define1: DEFINE1 NAME INTEGER - /* all subsequent occurences of NAME will be replaced - by integer during parseing. See 'integer:' */ - { Symbol *sp = SYM($2); - if (sp->subtype) - diag(sp->name, " used before DEFINEed"); - sp->u.str = STR($3); - sp->type = DEFINEDVAR; - deltokens($1, $3);} + /* all subsequent occurences of NAME will be replaced + by integer during parseing. See 'integer:' */ + { + Symbol *sp = SYM($2); + if (sp->subtype) + diag(sp->name, " used before DEFINEed"); + sp->u.str = STR($3); + sp->type = DEFINEDVAR; + deltokens($1, $3); + } + | DEFINE1 NAME '-' INTEGER + { + Symbol *sp = SYM($2); + if (sp->subtype) + diag(sp->name, " used before DEFINEed"); + Sprintf(buf, "-%s", STR($4)); + sp->u.str = stralloc(buf, nullptr); + sp->type = DEFINEDVAR; + deltokens($1, $4); + } | DEFINE1 error {myerr("syntax: DEFINE name integer");} ; Name: NAME diff --git a/src/nrncvode/netcvode.cpp b/src/nrncvode/netcvode.cpp index 7a7154d178..b0ad67a1a0 100644 --- a/src/nrncvode/netcvode.cpp +++ b/src/nrncvode/netcvode.cpp @@ -3,13 +3,9 @@ // define to 0 if do not wish use_min_delay_ to ever be 1 #define USE_MIN_DELAY 1 -#include #include -#include -#include -#include +#include "cabcode.h" #include "classreg.h" -#include "nrnoc2iv.h" #include "parse.hpp" #include "cvodeobj.h" #include "hoclist.h" @@ -19,7 +15,6 @@ #include "nrnneosm.h" #include "datapath.h" #include "objcmd.h" -#include "shared/sundialsmath.h" #include "kssingle.h" #include "ocnotify.h" #include "utils/enumerate.h" @@ -44,6 +39,10 @@ #include "utils/formatting.hpp" #include +#include +#include +#include +#include #include #include @@ -56,8 +55,6 @@ typedef void (*ReceiveFunc)(Point_process*, double*, double); #define NVI_SUCCESS 0 #define PP2NT(pp) ((NrnThread*) ((pp)->_vnt)) #define PP2t(pp) (PP2NT(pp)->_t) -#define LOCK(m) /**/ -#define UNLOCK(m) /**/ // classical and when DiscreteEvent::deliver is already in the right thread // via a future thread instance of NrnNetItem with its own tqe. #define POINT_RECEIVE(type, tar, w, f) (*pnt_receive[type])(tar, w, f) @@ -67,8 +64,6 @@ typedef void (*ReceiveFunc)(Point_process*, double*, double); #include "membfunc.h" extern void single_event_run(); -extern void setup_topology(), v_setup_vectors(); -extern int nrn_errno_check(int); extern NetCvode* net_cvode_instance; extern cTemplate** nrn_pnt_template_; extern double t, dt; @@ -76,29 +71,18 @@ extern void nrn_cvfun(double t, double* y, double* ydot); extern void nrn_cleanup_presyn(PreSyn*); #define nt_dt nrn_threads->_dt #define nt_t nrn_threads->_t -extern void nrn_parent_info(Section*); -extern Object* nrn_sec2cell(Section*); -extern int nrn_sec2cell_equals(Section*, Object*); -extern ReceiveFunc* pnt_receive; -extern ReceiveFunc* pnt_receive_init; extern short* nrn_is_artificial_; // should be bool but not using that type in c extern short* nrn_artcell_qindex_; int nrn_use_selfqueue_; void nrn_pending_selfqueue(double tt, NrnThread*); static void all_pending_selfqueue(double tt); static void* pending_selfqueue(NrnThread*); -extern int hoc_araypt(Symbol*, int); -extern int hoc_stacktype(); -void nrn_use_daspk(int); extern int nrn_use_daspk_; int linmod_extra_eqn_count(); extern int nrn_modeltype(); -extern Symlist* hoc_built_in_symlist; -extern Symlist* hoc_top_level_symlist; extern TQueue* net_cvode_instance_event_queue(NrnThread*); extern hoc_Item* net_cvode_instance_psl(); extern std::vector* net_cvode_instance_prl(); -extern void nrn_update_ps2nt(); extern void nrn_use_busywait(int); void* nrn_interthread_enqueue(NrnThread*); extern void (*nrnthread_v_transfer_)(NrnThread*); diff --git a/src/nrncvode/occvode.cpp b/src/nrncvode/occvode.cpp index 889f9fbc69..67e24d1c87 100644 --- a/src/nrncvode/occvode.cpp +++ b/src/nrncvode/occvode.cpp @@ -1,5 +1,6 @@ #include <../../nrnconf.h> -#include +#include "hocdec.h" +#include "cabcode.h" #include "nrn_ansi.h" #include "nrndae_c.h" #include "nrniv_mf.h" @@ -12,16 +13,9 @@ #include "membfunc.h" #include "nonvintblock.h" -#include +#include +#include -extern void setup_topology(), v_setup_vectors(); -extern void recalc_diam(); -extern int nrn_errno_check(int); -// extern double t, dt; -#define nt_dt nrn_threads->_dt -#define nt_t nrn_threads->_t - -extern Symlist* hoc_built_in_symlist; #include "spmatrix.h" extern double* sp13mat; @@ -45,8 +39,6 @@ extern void (*nrn_multisplit_solve_)(); #endif static Symbol* vsym; // for absolute tolerance -#define SETUP 1 -#define USED 2 /* CVODE expects dy/dt = f(y) and solve (I - gamma*J)*x = b with approx to J=df/dy. diff --git a/src/nrniv/bbsavestate.cpp b/src/nrniv/bbsavestate.cpp index 903bd9eb0f..3274dc0011 100644 --- a/src/nrniv/bbsavestate.cpp +++ b/src/nrniv/bbsavestate.cpp @@ -168,6 +168,7 @@ callback to bbss_early when needed. */ #include "bbsavestate.h" +#include "cabcode.h" #include "classreg.h" #include "nrncvode.h" #include "nrnoc2iv.h" @@ -201,7 +202,6 @@ typedef void (*ReceiveFunc)(Point_process*, double*, double); #include "membfunc.h" extern int section_count; extern "C" void nrn_shape_update(); -extern Section* nrn_section_exists(char* name, int index, Object* cell); extern Section** secorder; extern ReceiveFunc* pnt_receive; extern NetCvode* net_cvode_instance; diff --git a/src/nrniv/impedanc.cpp b/src/nrniv/impedanc.cpp index 9b2d7a12d9..d9cbde709d 100644 --- a/src/nrniv/impedanc.cpp +++ b/src/nrniv/impedanc.cpp @@ -8,10 +8,7 @@ #include #include "nrnoc2iv.h" #include "classreg.h" -#include #include "membfunc.h" -extern void setup_topology(); -extern void recalc_diam(); typedef void (*Pfrv4)(int, Node**, double**, Datum**); diff --git a/src/nrniv/multisplit.cpp b/src/nrniv/multisplit.cpp index 3ca23e4dcc..f37e9ac2fe 100644 --- a/src/nrniv/multisplit.cpp +++ b/src/nrniv/multisplit.cpp @@ -1,36 +1,30 @@ #include <../../nrnconf.h> -#include -#include -#include #include -#include +#include "cabcode.h" #include "nrn_ansi.h" #include "nrndae_c.h" #include "nrniv_mf.h" #include #include #include -#include + +#include +#include +#include #include +#include +#include void nrnmpi_multisplit(Section*, double x, int sid, int backbone_style); int nrn_multisplit_active_; -extern void setup_topology(); extern void (*nrn_multisplit_setup_)(); extern void* nrn_multisplit_triang(NrnThread*); extern void* nrn_multisplit_reduce_solve(NrnThread*); extern void* nrn_multisplit_bksub(NrnThread*); extern double t; -void nrn_multisplit_ptr_update(); -void nrnmpi_multisplit_clear(); -void nrn_multisplit_nocap_v(); -void nrn_multisplit_nocap_v_part1(NrnThread*); -void nrn_multisplit_nocap_v_part2(NrnThread*); -void nrn_multisplit_nocap_v_part3(NrnThread*); -void nrn_multisplit_adjust_rhs(NrnThread*); extern void (*nrn_multisplit_solve_)(); static void multisplit_v_setup(); static void multisplit_solve(); diff --git a/src/nrniv/neuronapi.cpp b/src/nrniv/neuronapi.cpp index 3a286c87c0..a2a798ff4f 100644 --- a/src/nrniv/neuronapi.cpp +++ b/src/nrniv/neuronapi.cpp @@ -2,6 +2,7 @@ #include "../../nrnconf.h" #include "hocdec.h" +#include "cabcode.h" #include "nrniv_mf.h" #include "nrnmpi.h" #include "nrnmpiuse.h" @@ -42,8 +43,6 @@ extern "C" void nrnpy_set_pr_etal(int (*cbpr_stdoe)(int, char*), int (*cbpass)() int ivocmain_session(int, const char**, const char**, int start_session); void simpleconnectsection(); extern Object* hoc_newobj1(Symbol*, int); -extern void nrn_change_nseg(Section*, int); -extern Section* section_new(Symbol* sym); extern std::tuple nrn_mpi_setup(int argc, const char** argv); extern "C" { diff --git a/src/nrniv/nrnmenu.cpp b/src/nrniv/nrnmenu.cpp index 78ad7620c3..de66948849 100644 --- a/src/nrniv/nrnmenu.cpp +++ b/src/nrniv/nrnmenu.cpp @@ -1,13 +1,14 @@ #include <../../nrnconf.h> -#include -#include +#include +#include #if HAVE_IV #include "secbrows.h" #include "ivoc.h" #endif +#include "cabcode.h" #include "nrniv_mf.h" #include "nrnoc2iv.h" #include "nrnpy.h" @@ -15,20 +16,16 @@ #include "classreg.h" #include "gui-redirect.h" -typedef void (*ReceiveFunc)(Point_process*, double*, double); extern int hoc_return_type_code; // from nrnoc #include "membfunc.h" #include "parse.hpp" extern Symlist* hoc_built_in_symlist; extern Symbol** pointsym; -extern ReceiveFunc* pnt_receive; extern int nrn_has_net_event_cnt_; extern int* nrn_has_net_event_; extern short* nrn_is_artificial_; -extern int node_index(Section*, double); extern char* pnt_map; -extern void nrn_parent_info(Section*); // to nrnoc void nrnallsectionmenu(); @@ -1272,8 +1269,7 @@ const char* MechanismType::selected() { int MechanismType::internal_type() { return mti_->type_[selected_item()]; } -extern void mech_insert1(Section*, int); -extern void mech_uninsert1(Section*, Symbol*); + void MechanismType::insert(Section* sec) { if (!mti_->is_point_) { mech_insert1(sec, memb_func[mti_->type_[selected_item()]].sym->subtype); diff --git a/src/nrniv/spaceplt.cpp b/src/nrniv/spaceplt.cpp index ebaa05b1c7..e88aac8405 100644 --- a/src/nrniv/spaceplt.cpp +++ b/src/nrniv/spaceplt.cpp @@ -18,7 +18,6 @@ extern int nrn_multisplit_active_; extern int hoc_execerror_messages; -extern int node_index(Section*, double); extern int nrn_shape_changed_; extern int hoc_return_type_code; Object* (*nrnpy_rvp_rxd_to_callable)(Object*) = 0; diff --git a/src/nrnoc/cabcode.cpp b/src/nrnoc/cabcode.cpp index 50e7fe0c79..e829279659 100644 --- a/src/nrnoc/cabcode.cpp +++ b/src/nrnoc/cabcode.cpp @@ -3,13 +3,12 @@ /* /local/src/master/nrn/src/nrnoc/cabcode.cpp,v 1.37 1999/07/08 14:24:59 hines Exp */ #include -#include -#include -#include +#include +#include +#include #define HOC_L_LIST 1 #include "section.h" -#include "nrn_ansi.h" #include "nrniv_mf.h" #include "membfunc.h" #include "parse.hpp" @@ -447,12 +446,6 @@ double nrn_diameter(Node* nd) { return p->param(0); } -void nrn_chk_section(Symbol* s) { - if (s->type != SECTION) { - execerror("Not a SECTION name:", s->name); - } -} - Section* chk_access() { Section* sec = secstack[isecstack]; if (!sec || !sec->prop) { @@ -512,7 +505,7 @@ Section* nrn_noerr_access(void) /* return 0 if no accessed section */ /*sibling and child pointers do not ref sections to avoid mutual references */ /* the sibling list is ordered according to increasing distance from parent */ -void nrn_remove_sibling_list(Section* sec) { +static void nrn_remove_sibling_list(Section* sec) { Section* s; if (sec->parentsec) { if (sec->parentsec->child == sec) { @@ -538,7 +531,7 @@ static double ncp_abs(Section* sec) { return x; } -void nrn_add_sibling_list(Section* sec) { +static void nrn_add_sibling_list(Section* sec) { Section* s; double x; if (sec->parentsec) { @@ -578,7 +571,7 @@ static void reverse_sibling_list(Section* sec) { *pch = 0; } -void disconnect(void) { +void disconnect() { if (ifarg(1)) { hoc_execerror( "disconnect takes no positional arguments and disconnects the HOC currently accessed " @@ -712,7 +705,9 @@ static Section* Sec_access(void) /* section symbol at pc */ hoc_thisobject = 0; hoc_symlist = hoc_top_level_symlist; } - nrn_chk_section(s); + if (s->type != SECTION) { + execerror("Not a SECTION name:", s->name); + } itm = OPSECITM(s)[range_vec_indx(s)]; if (obsav) { hoc_objectdata = hoc_objectdata_restore(odsav); @@ -814,7 +809,7 @@ void* hoc_sec_internal_name2ptr(const char* s, int eflag) { return vp; } -void* hoc_pysec_name2ptr(const char* s, int eflag) { +void* hoc_pysec_name2ptr(const char* s, int /* eflag */) { /* syntax is _pysec. where is the name of a python nrn.Section from (*nrnpy_pysec_name_p_)(sec) @@ -835,14 +830,14 @@ below to keep the stack ok when it is popped at the end of the next statement. */ -void ob_sec_access_push(Item* qsec) { +void ob_sec_access_push(hoc_Item* qsec) { if (!qsec) { hoc_execerror("section in the object was deleted", (char*) 0); } nrn_pushsec(qsec->element.sec); } -void ob_sec_access(void) { +void ob_sec_access() { if (!section_object_seen) { hoc_nopop(); nrn_pushsec(secstack[isecstack]); @@ -1314,9 +1309,6 @@ neuron::container::data_handle nrn_rangepointer(Section* sec, Symbol* s, return dprop(s, indx, sec, i); } -/* return nullptr if failure instead of hoc_execerror - and return pointer to the 0 element if an array -*/ neuron::container::generic_data_handle nrnpy_rangepointer(Section* sec, Symbol* s, double d, @@ -1437,7 +1429,6 @@ int node_index(Section* sec, double x) /* returns nearest index to x */ return i; } -/* return -1 if x at connection end, nnode-1 if at other end */ int node_index_exact(Section* sec, double x) { if (x == 0.) { if (arc0at0(sec)) { @@ -1472,6 +1463,7 @@ double cable_prop_eval(Symbol* sym) { } return 0.; } + double* cable_prop_eval_pointer(Symbol* sym) { Section* sec; sec = nrn_sec_pop(); @@ -1522,6 +1514,7 @@ void nrn_change_nseg(Section* sec, int n) { } } } + void cable_prop_assign(Symbol* sym, double* pd, int op) { Section* sec; sec = nrn_sec_pop(); @@ -1562,12 +1555,10 @@ void cable_prop_assign(Symbol* sym, double* pd, int op) { } } -/* x of parent for this section */ double nrn_connection_position(Section* sec) { return sec->prop->dparam[1].get(); } -/* x=0,1 end connected to parent */ double nrn_section_orientation(Section* sec) { return sec->prop->dparam[3].get(); } @@ -1870,13 +1861,6 @@ int nrn_get_mechtype(const char* mechname) { return s->subtype; } -int nrn_instance_count(int mechtype) { - if (v_structure_change) { - v_setup_vectors(); - } - return memb_list[mechtype].nodecount; -} - #if EXTRACELLULAR /* want to handle vext(0), vext(1) correctly. No associated i_membrane though.*/ /* @@ -1995,7 +1979,6 @@ void forall_section(void) { Inst* savepc = pc; Item *qsec, *first, *last; - extern int hoc_returning; char buf[200]; char** s; int istk; @@ -2106,7 +2089,7 @@ void ismembrane(void) { /* return true if string is an inserted membrane in the hoc_retpushx((double) has_membrane(str, chk_access())); } -const char* secaccessname(void) { +static const char* secaccessname() { return secname(chk_access()); } @@ -2214,9 +2197,9 @@ void pop_section(void) { hoc_retpushx(1.); } -/* turn off section stack fixing (in case of return,continue,break in a section -statement) between exlicit user level push_section,etc and pop_section -*/ +/* turn off section stack fixing (in case of return,continue,break in a section statement) between + * exlicit user level push_section,etc and pop_section + */ void hoc_level_pushsec(Section* sec) { ++skip_secstack_check; diff --git a/src/nrnoc/cabcode.h b/src/nrnoc/cabcode.h new file mode 100644 index 0000000000..8e0dd2e37b --- /dev/null +++ b/src/nrnoc/cabcode.h @@ -0,0 +1,113 @@ +#pragma once + +#include "neuron/container/generic_data_handle.hpp" +#include "options.h" // for EXTRACELLULAR +#include "neuron/container/data_handle.hpp" + +struct Node; +struct Object; +struct Section; +struct Symbol; +struct Prop; +struct hoc_Item; + +double cable_prop_eval(Symbol* sym); + +// section on stack will be popped +double* cable_prop_eval_pointer(Symbol* sym); + +void oc_save_cabcode(int* a1, int* a2); +void oc_restore_cabcode(int* a1, int* a2); + +void nrn_initcode(); +void nrn_pushsec(Section*); +Object* nrn_sec2cell(Section* sec); +int nrn_sec2cell_equals(Section* sec, Object* obj); +void new_sections(Object* ob, Symbol* sym, hoc_Item** pitm, int size); +Section* section_new(Symbol* sym); + +#if USE_PYTHON +struct NPySecObj; +Section* nrnpy_newsection(NPySecObj*); +#endif + +int arc0at0(Section*); +double nrn_ra(Section*); +void cab_alloc(Prop*); +void morph_alloc(Prop* p); +double nrn_diameter(Node* nd); +double section_length(Section* sec); +Section* chk_access(); + +/// return 0 if no accessed section +Section* nrn_noerr_access(); + +void nrn_disconnect(Section* sec); +Section* nrn_sec_pop(); +void ob_sec_access_push(hoc_Item* qsec); +void mech_insert1(Section* sec, int type); +void mech_uninsert1(Section* sec, Symbol* s); +void nrn_rangeconst(Section*, Symbol*, neuron::container::data_handle value, int op); +Prop* nrn_mechanism(int type, Node* nd); + +/// returns prop given mech type, section, and inode error if mech not at this position +Prop* nrn_mechanism_check(int type, Section* sec, int inode); +Prop* hoc_getdata_range(int type); +int nrn_exists(Symbol* s, Node* node); +neuron::container::data_handle nrn_rangepointer(Section* sec, Symbol* s, double d); + +/// return nullptr if failure instead of hoc_execerror and return pointer to the 0 element if an +/// array +neuron::container::generic_data_handle nrnpy_rangepointer(Section*, Symbol*, double, int*, int); + +/// returns nearest index to x +int node_index(Section* sec, double x); + +/// return -1 if x at connection end, nnode-1 if at other end +int node_index_exact(Section* sec, double x); +void nrn_change_nseg(Section* sec, int n); +void cable_prop_assign(Symbol* sym, double* pd, int op); + +/* x of parent for this section */ +double nrn_connection_position(Section*); + +/* x=0,1 end connected to parent */ +double nrn_section_orientation(Section*); + +int nrn_at_beginning(Section* sec); +Section* nrn_trueparent(Section*); +void nrn_parent_info(Section* s); +void setup_topology(); + +/// name of section (for use in error messages) +const char* secname(Section* sec); + +char* hoc_section_pathname(Section* sec); +double nrn_arc_position(Section* sec, Node* node); +const char* sec_and_position(Section* sec, Node* nd); +int segment_limits(double*); + +/// like node_index but give proper node when x is 0 or 1 as well as in between +Node* node_exact(Section* sec, double x); +Node* node_ptr(Section* sec, double x, double* parea); + +/// returns location of property symbol +neuron::container::data_handle dprop(Symbol* s, int indx, Section* sec, short inode); + +/// returns location of property symbol, return nullptr instead of hoc_execerror +neuron::container::generic_data_handle nrnpy_dprop(Symbol* s, + int indx, + Section* sec, + short inode, + int* err); +int has_membrane(char* mechanism_name, Section* sec); + +/// turn off section stack fixing (in case of return, continue, break in a section statement) +/// between explicit user level push_section, etc and pop_section +void hoc_level_pushsec(Section* sec); + +Section* nrn_section_exists(char* name, int indx, Object* cell); + +#if EXTRACELLULAR +double* nrn_vext_pd(Symbol* s, int indx, Node* nd); +#endif diff --git a/src/nrnoc/cabvars.h b/src/nrnoc/cabvars.h index cb3aa81f07..73f26923ae 100644 --- a/src/nrnoc/cabvars.h +++ b/src/nrnoc/cabvars.h @@ -1,5 +1,7 @@ /* /local/src/master/nrn/src/nrnoc/cabvars.h,v 1.5 1999/02/05 18:09:50 hines Exp */ #pragma once +#include "cabcode.h" // to provide cab_alloc, morph_alloc for backward compatibility + #define XMECH 0 @@ -62,9 +64,6 @@ static const char* morph_mech[] = { 0, }; -extern void cab_alloc(Prop*); -extern void morph_alloc(Prop*); - #if 0 first two memb_func NULL_CUR, NULL_ALLOC, NULL_STATE, NULL_INITIALIZE, (Pfri)0, 0, /*Unused*/ diff --git a/src/nrnoc/eion.cpp b/src/nrnoc/eion.cpp index 7933fabe29..c591c541c5 100644 --- a/src/nrnoc/eion.cpp +++ b/src/nrnoc/eion.cpp @@ -1,7 +1,8 @@ #include <../../nrnconf.h> /* /local/src/master/nrn/src/nrnoc/eion.cpp,v 1.10 1998/02/26 16:42:50 hines Exp */ -#include +#include +#include "cabcode.h" #include "section.h" #include "neuron.h" #include "neuron/cache/mechanism_range.hpp" @@ -16,11 +17,6 @@ #undef hoc_retpushx -extern double chkarg(int, double low, double high); - -extern Section* nrn_noerr_access(); - -extern void hoc_register_prop_size(int, int, int); static constexpr auto nparm = 5; static constexpr auto ndparam = 1; diff --git a/src/nrnoc/neuron.h b/src/nrnoc/neuron.h index e42274b308..1fac159bb5 100755 --- a/src/nrnoc/neuron.h +++ b/src/nrnoc/neuron.h @@ -1,10 +1,6 @@ #include "options.h" -#if NEMO -extern int neuron2nemo(), nemo2neuron(); -#endif - -extern void node_data(), disconnect(); +extern void disconnect(); extern void batch_run(), batch_save(); extern void pt3dadd(), n3d(), x3d(), y3d(), z3d(), arc3d(), diam3d(); extern void pt3dclear(), pt3dinsert(), pt3dremove(), pt3dchange(); diff --git a/src/nrnoc/nrn_ansi.h b/src/nrnoc/nrn_ansi.h index c791b51b14..0aa1701ef0 100644 --- a/src/nrnoc/nrn_ansi.h +++ b/src/nrnoc/nrn_ansi.h @@ -1,10 +1,11 @@ #pragma once #include "hocdec.h" #include "membfunc.h" // nrn_bamech_t +#include "cabcode.h" #include "neuron/container/data_handle.hpp" #include "neuron/container/generic_data_handle.hpp" - #include + struct Extnode; struct hoc_Item; struct HocParmLimits; @@ -24,15 +25,11 @@ extern void hoc_register_dparam_semantics(int, int, const char*); extern void add_nrn_fornetcons(int, int); extern void hoc_register_tolerance(int, HocStateTolerance*, Symbol***); -extern void oc_save_cabcode(int* a1, int* a2); -extern void oc_restore_cabcode(int* a1, int* a2); - extern "C" void modl_reg(void); // nrnmech stuff extern void _nrn_free_fornetcon(void**); extern double nrn_call_mech_func(Symbol*, int narg, Prop*, int type); -extern Prop* nrn_mechanism(int type, Node*); // mod stuff extern void _nrn_free_watch(Datum*, int, int); @@ -52,23 +49,14 @@ extern void hoc_reg_ba(int, nrn_bamech_t, int); return static_cast(p); } -extern void nrn_pushsec(Section*); extern void nrn_popsec(void); -extern Section* chk_access(void); - -extern Node* node_exact(Section*, double); extern int state_discon_allowed_; extern int section_object_seen; extern int nrn_isecstack(void); extern void nrn_secstack(int); -extern void new_sections(Object* ob, Symbol* sym, hoc_Item** pitm, int size); -extern void cable_prop_assign(Symbol* sym, double* pd, int op); -extern void nrn_parent_info(Section* s); extern void nrn_relocate_old_points(Section* oldsec, Node* oldnode, Section* sec, Node* node); -extern int nrn_at_beginning(Section* sec); -extern void mech_insert1(Section*, int); extern void extcell_2d_alloc(Section* sec); extern int nrn_is_ion(int); extern void single_prop_free(Prop*); @@ -77,26 +65,10 @@ extern int can_change_morph(Section*); extern void nrn_area_ri(Section* sec); extern void nrn_diam_change(Section*); extern void sec_free(hoc_Item*); -extern int node_index(Section* sec, double x); extern void extcell_node_create(Node*); extern void extnode_free_elements(Extnode*); -extern const char* sec_and_position(Section* sec, Node* nd); extern void section_order(void); -extern Section* nrn_sec_pop(void); -extern Node* node_ptr(Section* sec, double x, double* parea); -extern double* nrn_vext_pd(Symbol* s, int indx, Node* nd); -neuron::container::generic_data_handle nrnpy_dprop(Symbol* s, - int indx, - Section* sec, - short inode, - int* err); -extern void nrn_disconnect(Section*); -extern void mech_uninsert1(Section* sec, Symbol* s); -extern Object* nrn_sec2cell(Section*); -extern int nrn_sec2cell_equals(Section*, Object*); neuron::container::data_handle dprop(Symbol* s, int indx, Section* sec, short inode); -extern void nrn_initcode(); -extern int segment_limits(double*); extern "C" void nrn_random_play(); extern void fixed_play_continuous(NrnThread*); extern void setup_tree_matrix(neuron::model_sorted_token const& sorted_token, NrnThread& nt); @@ -105,12 +77,10 @@ extern void second_order_cur(NrnThread*); void nrn_update_voltage(neuron::model_sorted_token const& sorted_token, NrnThread& nt); extern void nrn_fixed_step_lastpart(neuron::model_sorted_token const& sorted_token, NrnThread& nt); extern void hoc_register_dparam_size(int, int); -extern void setup_topology(void); extern int nrn_errno_check(int); void long_difus_solve(neuron::model_sorted_token const&, int method, NrnThread& nt); extern void nrn_fihexec(int); extern int special_pnt_call(Object*, Symbol*, int); -extern void ob_sec_access_push(hoc_Item*); extern void nrn_mk_prop_pools(int); extern void SectionList_reg(void); extern void SectionRef_reg(void); @@ -119,8 +89,6 @@ extern void hoc_symbol_tolerance(Symbol*, double); extern void node_destruct(Node**, int); extern void nrn_sec_ref(Section**, Section*); extern void hoc_level_pushsec(Section*); -extern double nrn_ra(Section*); -extern int node_index_exact(Section*, double); void nrn_ba(neuron::model_sorted_token const&, NrnThread&, int); extern void nrn_rhs_ext(NrnThread*); extern void nrn_setup_ext(NrnThread*); @@ -149,28 +117,15 @@ void nrn_rhs(neuron::model_sorted_token const&, NrnThread&); extern void v_setup_vectors(void); extern void section_ref(Section*); extern void section_unref(Section*); -extern const char* secname(Section*); extern const char* nrn_sec2pysecname(Section*); -void nrn_rangeconst(Section*, Symbol*, neuron::container::data_handle value, int op); -extern int nrn_exists(Symbol*, Node*); -neuron::container::data_handle nrn_rangepointer(Section*, Symbol*, double x); -neuron::container::generic_data_handle nrnpy_rangepointer(Section*, Symbol*, double, int*, int); -extern double* cable_prop_eval_pointer(Symbol*); // section on stack will be popped -extern char* hoc_section_pathname(Section*); -extern double nrn_arc_position(Section*, Node*); extern double node_dist(Section*, Node*); // distance of node to parent position -extern double nrn_section_orientation(Section*); -extern double nrn_connection_position(Section*); -extern Section* nrn_trueparent(Section*); extern double topol_distance(Section*, Node*, Section*, Node*, Section**, Node**); -extern int arc0at0(Section*); extern void nrn_clear_mark(void); extern short nrn_increment_mark(Section*); extern short nrn_value_mark(Section*); extern int is_point_process(Object*); extern int nrn_vartype(const Symbol*); // nrnocCONST, DEP, STATE extern void recalc_diam(void); -extern Prop* nrn_mechanism_check(int type, Section* sec, int inode); extern bool nrn_use_fast_imem; void nrn_fast_imem_alloc(); extern void nrn_calc_fast_imem(NrnThread*); diff --git a/src/nrnoc/nrnnemo.cpp b/src/nrnoc/nrnnemo.cpp deleted file mode 100644 index c0a2137bdb..0000000000 --- a/src/nrnoc/nrnnemo.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include <../../nrnconf.h> - -#include "section.h" - - -#define OBSOLETE 1 - -#if !OBSOLETE -#include "membfunc.h" -#include "hocassrt.h" - -/* basic loop taken from topology() in solve.cpp */ -static FILE *fin, *fmark, *fdat; -static int inode; -static dashes(), file_func(), dat_head(); -#define MAXMARKS 32 -static long* marksec; -static printline(); - -extern int section_count; -extern Section** secorder; -#endif - -void nemo2neuron(void) { - hoc_retpushx(1.0); -} - -void neuron2nemo(void) { -#if OBSOLETE - hoc_execerror("neuron2nemo:", "implementation is obsolete"); -#else - short i, isec, imark; - char name[50]; - - if (tree_changed) { - setup_topology(); - } - Sprintf(name, "in/%s", gargstr(1)); - if ((fin = fopen(name, "w")) == (FILE*) 0) { - hoc_execerror("Can't write to ", name); - } - Sprintf(name, "mark/%s", gargstr(1)); - if ((fmark = fopen(name, "w")) == (FILE*) 0) { - hoc_execerror("Can't write to ", name); - } - Sprintf(name, "dat/%s", gargstr(1)); - if ((fdat = fopen(name, "w")) == (FILE*) 0) { - hoc_execerror("Can't write to ", name); - } - dat_head(); - - /* set up the mark for every section */ - imark = 1; - marksec = (long*) ecalloc(section_count, sizeof(long)); - for (i = 1; i < section_count; i++) { - isec = i; - if (marksec[isec]) { - marksec[i] = marksec[isec]; - } else { - if (imark < MAXMARKS) { - marksec[i] = 1L << (imark++); - file_func(secorder[isec]); - } - } - } - Fprintf(fin, "/* created by NEURON */\n"); - inode = 0; - for (i = 0; i < rootnodecount; i++) { - printline(v_node[i]->child, 0, 0., (double) (i * 100)); - dashes(v_node[i]->child, 0., (double) (i * 100), 0., 1); - } - free((char*) marksec); - fclose(fin); - fclose(fmark); -#endif - hoc_retpushx(1.0); -} - -#if !OBSOLETE -static dashes(Section* sec, double x, double y, double theta, int leftend) { - Section* ch; - int i, nrall, irall; - double cos(), sin(), xx, yy, ttheta, dx; - - dx = section_length(sec) / ((double) sec->nnode - 1); - nrall = (int) sec->prop->dparam[4].val; - for (irall = 0; irall < nrall; irall++) { - xx = x; - yy = y; - ttheta = theta + (double) (nrall - 2 * irall - 1) / (double) nrall; - for (i = 0; i < sec->nnode - 1; i++) { - xx += dx * cos(ttheta); - yy += dx * sin(ttheta); - printline(sec, i, xx, yy); - } - for (i = sec->nnode - 1; i >= 0; i--) { - if ((ch = sec->pnode[i]->child) != (Section*) 0) { - if (i == sec->nnode - 1) { - dashes(ch, xx, yy, ttheta, 0); - } else { - dashes(ch, xx, yy, ttheta + .5, 0); - } - } - if (i < sec->nnode - 1) { - xx -= dx * cos(ttheta); - yy -= dx * sin(ttheta); - } - } - if (leftend) { - ttheta = 3.14159 - .5; - } - if ((ch = sec->sibling) != (Section*) 0) { - dashes(ch, x, y, ttheta + .5, 0); - } - } -} - -static double diamval(Node* nd) { - Prop* p; - - for (p = nd->prop; p; p = p->next) { - if (p->_type == MORPHOLOGY) { - break; - } - } - assert(p); - return p->param[0]; -} - -static void printline(Section* sec, int i, double x, double y) { - char type; - int nb; - Section* csec; - Node* nd; - double d; - - ++inode; - assert(sec->nnode > 1); - type = 'C'; - nd = sec->pnode[i]; - d = diamval(nd); - nb = 0; - for (csec = nd->child; csec; csec = csec->sibling) { - nb += (int) csec->prop->dparam[4].val; - } - if (i == sec->nnode - 2) { - ++i; - nd = sec->pnode[i]; - for (csec = nd->child; csec; csec = csec->sibling) { - nb += (int) csec->prop->dparam[4].val; - } - } - if (i < sec->nnode - 2) { - nb++; - } - if (nb > 2) { /*many branches*/ - type = 'B'; - x -= .001; - while (nb > 2) { - fwrite((char*) &marksec[sec->order], sizeof(long), 1, fmark); - Fprintf(fin, "%d\t%c\t%g\t%g\t0\t%g\n", inode++, type, (x += .001), y, d); - --nb; - } - } else if (nb == 2) { /*one branch*/ - type = 'B'; - } else if (nb == 0) { - type = 'T'; - } - fwrite((char*) &marksec[sec->order], sizeof(long), 1, fmark); - Fprintf(fin, "%d\t%c\t%g\t%g\t0\t%g\n", inode, type, x, y, d); -} - -/* modified from nemo.cpp */ -static void file_func(Section* sec) { - int active; - Node* nd; - Prop* p; - Symbol *s, *hoc_lookup(); - static int hhtype = 0; - - if (!hhtype) { - s = hoc_lookup("HH"); - hhtype = s->subtype; - } - nd = sec->pnode[0]; - - active = 0; - for (p = nd->prop; p; p = p->next) { - if (p->_type == hhtype) { - active = 1; - } - } - - assert(sec->prop->dparam[0].sym); - fprintf(fdat, "%s\n", sec->prop->dparam[0].sym->name); - fprintf(fdat, "^area %g\n", 1.); - fprintf(fdat, "^Rm %g\n", 1.); - fprintf(fdat, "^active %d\n", active); - fprintf(fdat, "^synapse %d\n", 0); - fprintf(fdat, "^Erev %g\n", 0.); - fprintf(fdat, "^gback %g\n", 0.); - fprintf(fdat, "^gsyn %g\n", 0.); - fprintf(fdat, "^tstart %g\n", 0.); - fprintf(fdat, "^twidth %g\n", 0.); -} - -static void dat_head(void) { - double Ra = 35.4; - - fprintf(fdat, "freq\n"); - fprintf(fdat, "%d %g %g\n", 4, 1., 1000.); - - fprintf(fdat, "tran\n"); - fprintf(fdat, "%g %g\n", .1, 10.); - - fprintf(fdat, "elec\n"); - fprintf(fdat, "%g %g %g\n", 1000., 1.e-6, Ra); - - fprintf(fdat, "syn\n"); - fprintf(fdat, "%g %g\n", 30., -15.); - - fprintf(fdat, "hh\n"); - fprintf(fdat, "%g %g %g %g %g %g\n", 1., 1., 1., 1., 1., 1.); - - fprintf(fdat, "batt\n"); - fprintf(fdat, "%g %g\n", 115., -12.); - - fprintf(fdat, "%10d\n", 9999); -} - -#endif diff --git a/src/nrnoc/section.h b/src/nrnoc/section.h index 0f496d1f46..04622aae75 100644 --- a/src/nrnoc/section.h +++ b/src/nrnoc/section.h @@ -23,6 +23,7 @@ d and rhs is calculated from the property list. */ #include "hoclist.h" +#include "cabcode.h" #include "membfunc.h" #include "neuron/container/mechanism_data.hpp" #include "neuron/container/node_data.hpp" @@ -446,7 +447,6 @@ extern hoc_List* section_list; /* Where the Sections live */ extern Section* sec_alloc(); /* Allocates a single section */ extern void node_alloc(Section*, short); /* Allocates node vectors in a section*/ -extern double section_length(Section*), nrn_diameter(Node*); extern Node* nrn_parent_node(Node*); extern Section* nrn_section_alloc(); extern void nrn_section_free(Section*); diff --git a/src/nrnoc/treeset.cpp b/src/nrnoc/treeset.cpp index ff8ca8283b..4ee251183a 100644 --- a/src/nrnoc/treeset.cpp +++ b/src/nrnoc/treeset.cpp @@ -1,6 +1,7 @@ #include <../../nrnconf.h> /* /local/src/master/nrn/src/nrnoc/treeset.cpp,v 1.39 1999/07/08 14:25:07 hines Exp */ +#include "cabcode.h" #include "cvodeobj.h" #include "membfunc.h" #include "multisplit.h" @@ -21,10 +22,10 @@ #include "utils/profile/profiler_interface.h" #include "multicore.h" -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -35,7 +36,6 @@ int nrn_shape_changed_; /* for notifying Shape class in nrniv */ double* nrn_mech_wtime_; extern double chkarg(int, double low, double high); -extern double nrn_ra(Section*); #if !defined(NRNMPI) || NRNMPI == 0 extern double nrnmpi_wtime(); #endif @@ -45,9 +45,7 @@ extern int* nrn_dparam_ptr_start_; extern int* nrn_dparam_ptr_end_; extern void nrn_define_shape(); -#if 1 || NRNMPI void (*nrn_multisplit_setup_)(); -#endif /* Do not use unless necessary (loops in tree structure) since overhead @@ -1782,107 +1780,6 @@ void v_setup_vectors(void) { } -#define NODE_DATA 0 -#if NODE_DATA -static FILE* fnd; - -#undef P -#undef Pn -#undef Pd -#undef Pg - -#define P fprintf(fnd, -#define Pn P "\n") -#define Pd(arg) P "%d\n", arg) -#define Pg(arg) P "%g\n", arg) - -void node_data_scaffolding(void) { - int i; - Pd(n_memb_func); - /* P "Mechanism names (first two are nullptr) beginning with memb_func[2]\n");*/ - for (i = 2; i < n_memb_func; ++i) { - P "%s", memb_func[i].sym->name); - Pn; - } -} - -void node_data_structure(void) { - int i, j; - nrn_thread_error("node_data_structure"); - Pd(v_node_count); - - Pd(nrn_global_ncell); - /* P "Indices of node parents\n");*/ - for (i = 0; i < v_node_count; ++i) { - Pd(v_parent[i]->v_node_index); - } - /* P "node lists for the membrane mechanisms\n");*/ - for (i = 2; i < n_memb_func; ++i) { - /* P "count, node list for mechanism %s\n", memb_func[i].sym->name);*/ - Pd(memb_list[i].nodecount); - for (j = 0; j < memb_list[i].nodecount; ++j) { - Pd(memb_list[i].nodelist[j]->v_node_index); - } - } -} - -void node_data_values(void) { - int i, j, k; - /* P "data for nodes then for all mechanisms in order of the above structure\n"); */ - for (i = 0; i < v_node_count; ++i) { - Pg(NODEV(v_node[i])); - Pg(NODEA(v_node[i])); - Pg(NODEB(v_node[i])); - Pg(NODEAREA(v_node[i])); - } - for (i = 2; i < n_memb_func; ++i) { - Prop* prop; - int cnt; - double* pd; - if (memb_list[i].nodecount) { - assert(!memb_func[i].hoc_mech); - prop = nrn_mechanism(i, memb_list[i].nodelist[0]); - cnt = prop->param_size; - Pd(cnt); - } - for (j = 0; j < memb_list[i].nodecount; ++j) { - pd = memb_list[i]._data[j]; - for (k = 0; k < cnt; ++k) { - Pg(pd[k]); - } - } - } -} - -void node_data(void) { - fnd = fopen(gargstr(1), "w"); - if (!fnd) { - hoc_execerror("node_data: can't open", gargstr(1)); - } - if (tree_changed) { - setup_topology(); - } - if (v_structure_change) { - v_setup_vectors(); - } - if (diam_changed) { - recalc_diam(); - } - node_data_scaffolding(); - node_data_structure(); - node_data_values(); - fclose(fnd); - hoc_retpushx(1.); -} - -#else -void node_data(void) { - Printf("recalc_diam=%d nrn_area_ri=%d\n", recalc_diam_count_, nrn_area_ri_count_); - hoc_retpushx(0.); -} - -#endif - void nrn_matrix_node_free() { NrnThread* nt; FOR_THREADS(nt) { diff --git a/src/nrnoc/vclmp.mod b/src/nrnoc/vclmp.mod index fa275e34fa..86614dacb1 100755 --- a/src/nrnoc/vclmp.mod +++ b/src/nrnoc/vclmp.mod @@ -157,9 +157,6 @@ PROCEDURE update() { e0 = e vo0 = vo vi0 = vi - VERBATIM - return 0; - ENDVERBATIM } COMMENT diff --git a/src/nrnpython/nrnpy_hoc.cpp b/src/nrnpython/nrnpy_hoc.cpp index cb10da5d47..4950c35c7b 100644 --- a/src/nrnpython/nrnpy_hoc.cpp +++ b/src/nrnpython/nrnpy_hoc.cpp @@ -1,3 +1,4 @@ +#include "cabcode.h" #include "ivocvect.h" #include "neuron/container/data_handle.hpp" #include "nrniv_mf.h" @@ -7,7 +8,6 @@ #include "nrnpy_utils.h" #include "nrnpython.h" #include "convert_cxx_exceptions.hpp" -#include #include "nrnwrap_dlfcn.h" #include "ocfile.h" @@ -15,12 +15,10 @@ #include "oclist.h" #include "shapeplt.h" -#include -#include // for PyMemberDef - #include #include #include +#include #include @@ -36,11 +34,9 @@ extern void (*nrnpy_restore_savestate)(int64_t, char*); extern void (*nrnpy_store_savestate)(char** save_data, uint64_t* save_data_size); extern void (*nrnpy_decref)(void* pyobj); extern void lvappendsec_and_ref(void* sl, Section* sec); -extern Section* nrn_noerr_access(); extern void hoc_pushs(Symbol*); extern double* hoc_evalpointer(); extern double cable_prop_eval(Symbol* sym); -extern void nrn_change_nseg(Section*, int); extern Symlist* hoc_top_level_symlist; extern Symlist* hoc_built_in_symlist; extern Inst* hoc_pc; diff --git a/src/nrnpython/nrnpy_nrn.cpp b/src/nrnpython/nrnpy_nrn.cpp index ea46a6247f..83d88cbf2c 100644 --- a/src/nrnpython/nrnpy_nrn.cpp +++ b/src/nrnpython/nrnpy_nrn.cpp @@ -1,9 +1,9 @@ #include "neuron/container/data_handle.hpp" #include "neuron/container/generic_data_handle.hpp" #include "nrn_ansi.h" +#include "cabcode.h" #include "nrnpython.h" #include -#include #include #include #include "nrniv_mf.h" @@ -11,6 +11,7 @@ #include "nrnpy.h" #include "nrnpy_utils.h" #include "convert_cxx_exceptions.hpp" + #ifndef M_PI #define M_PI (3.14159265358979323846) #endif @@ -19,7 +20,12 @@ #include #include +#include #include +#include +#include +#include +#include #include @@ -32,10 +38,7 @@ extern void nrn_pt3dchange2(Section* sec, int i, double x, double y, double z, d extern void nrn_pt3dstyle1(Section* sec, double x, double y, double z); extern void nrn_pt3dstyle0(Section* sec); -extern Symlist* hoc_built_in_symlist; -extern Section* nrn_noerr_access(); extern PyObject* nrn_ptr_richcmp(void* self_ptr, void* other_ptr, int op); -extern int has_membrane(char*, Section*); // used to be static in nrnpy_hoc.cpp extern int hocobj_pushargs(PyObject*, std::vector&); extern void hocobj_pushargs_free_strings(std::vector&); @@ -120,10 +123,7 @@ PyObject* pmech_types; // Python map for name to Mechanism PyObject* rangevars_; // Python map for name to Symbol extern PyTypeObject* hocobject_type; -extern Section* nrnpy_newsection(NPySecObj*); extern void simpleconnectsection(); -extern void nrn_change_nseg(Section*, int); -extern double section_length(Section*); extern short* nrn_is_artificial_; extern cTemplate** nrn_pnt_template_; extern PyObject* nrnpy_forall_safe(PyObject* self, PyObject* args); @@ -191,18 +191,13 @@ static Object* pysec_cell(Section* sec) { } static int NpySObj_contains(PyObject* s, PyObject* obj, const char* string) { - /* Checks is provided PyObject* s contains obj */ - PyObject* obj_seg; - int result; - if (!PyObject_HasAttrString(obj, string)) { + /* Checks is provided PyObject* s matches obj. */ + auto pyobj = nb::borrow(obj); // keep refcount+1 during use + if (!nb::hasattr(pyobj, string)) { return 0; } - Py_INCREF(obj); - obj_seg = PyObject_GetAttrString(obj, string); - Py_DECREF(obj); - result = PyObject_RichCompareBool(s, obj_seg, Py_EQ); - Py_XDECREF(obj_seg); - return (result); + auto obj_seg = pyobj.attr(string); + return nb::handle{s}.equal(obj_seg); } static int NPySecObj_contains(PyObject* sec, PyObject* obj) { @@ -321,6 +316,8 @@ static NPyMechObj* new_pymechobj() { // it as "null". So later `a = b` might segfault because copy constructor decrements the // refcount of `a`s nonsense memory. new (&m->prop_id_) neuron::container::non_owning_identifier_without_container; + m->pyseg_ = nullptr; + m->prop_ = nullptr; } return m; @@ -332,8 +329,8 @@ static NPyMechObj* new_pymechobj(NPySegObj* pyseg, Prop* p) { if (!m) { return NULL; } + Py_INCREF(pyseg); m->pyseg_ = pyseg; - Py_INCREF(m->pyseg_); m->prop_ = p; m->prop_id_ = p->id(); m->type_ = p->_type; @@ -446,8 +443,8 @@ static int NPyAllSegOfSecIter_init(NPyAllSegOfSecIter* self, PyObject* args, PyO return -1; } self->allseg_iter_ = 0; - self->pysec_ = pysec; Py_INCREF(pysec); + self->pysec_ = pysec; } return 0; } @@ -515,9 +512,9 @@ static PyObject* NPySegObj_new(PyTypeObject* type, PyObject* args, PyObject* /* self = (NPySegObj*) type->tp_alloc(type, 0); // printf("NPySegObj_new %p\n", self); if (self != NULL) { + Py_INCREF(pysec); self->pysec_ = pysec; self->x_ = x; - Py_INCREF(self->pysec_); } return (PyObject*) self; } @@ -537,8 +534,8 @@ static PyObject* NPyMechObj_new(PyTypeObject* type, PyObject* args, PyObject* /* // ((PyObject*)self)->ob_type->tp_name); if (self != NULL) { new (self) NPyMechObj; + Py_INCREF(pyseg); self->pyseg_ = pyseg; - Py_INCREF(self->pyseg_); } return (PyObject*) self; } @@ -704,7 +701,7 @@ static PyObject* NPySecObj_n3d_safe(NPySecObj* self) { static PyObject* NPySecObj_pt3dremove(NPySecObj* self, PyObject* args) { Section* sec = self->sec_; CHECK_SEC_INVALID(sec); - int i0, n; + int i0; if (!PyArg_ParseTuple(args, "i", &i0)) { return NULL; } @@ -1015,10 +1012,8 @@ static PyObject* nrnpy_set_psection_safe(PyObject* self, PyObject* args) { static PyObject* NPySecObj_psection(NPySecObj* self) { CHECK_SEC_INVALID(self->sec_); if (nrnpy_psection) { - PyObject* arglist = Py_BuildValue("(O)", self); - PyObject* result = PyObject_CallObject(nrnpy_psection, arglist); - Py_DECREF(arglist); - return result; + auto arglist = nb::steal(Py_BuildValue("(O)", self)); + return PyObject_CallObject(nrnpy_psection, arglist.ptr()); } Py_RETURN_NONE; } @@ -1128,14 +1123,13 @@ static PyObject* pysec_orientation_safe(NPySecObj* self) { } static bool lappendsec(PyObject* const sl, Section* const s) { - PyObject* item = (PyObject*) newpysechelp(s); - if (!item) { + auto item = nb::steal((PyObject*) newpysechelp(s)); + if (!item.is_valid()) { return false; } - if (PyList_Append(sl, item) != 0) { + if (PyList_Append(sl, item.ptr()) != 0) { return false; } - Py_XDECREF(item); return true; } @@ -1208,7 +1202,7 @@ static PyObject* pysec_wholetree_safe(NPySecObj* const self) { static PyObject* pysec2cell(NPySecObj* self) { PyObject* result; if (self->cell_weakref_) { - result = PyWeakref_GET_OBJECT(self->cell_weakref_); + result = PyWeakref_GetObject(self->cell_weakref_); Py_INCREF(result); } else if (auto* o = self->sec_->prop->dparam[6].get(); self->sec_->prop && o) { result = nrnpy_ho2po(o); @@ -1240,8 +1234,6 @@ static long pyseg_hash_safe(PyObject* self) { } static PyObject* pyseg_richcmp(NPySegObj* self, PyObject* other, int op) { - PyObject* pysec; - bool result = false; NPySegObj* seg = (NPySegObj*) self; void* self_ptr = (void*) node_exact(seg->pysec_->sec_, seg->x_); void* other_ptr = (void*) other; @@ -1258,8 +1250,6 @@ static PyObject* pyseg_richcmp_safe(NPySegObj* self, PyObject* other, int op) { static PyObject* pysec_richcmp(NPySecObj* self, PyObject* other, int op) { - PyObject* pysec; - bool result = false; void* self_ptr = (void*) (self->sec_); void* other_ptr = (void*) other; if (PyObject_TypeCheck(other, psection_type)) { @@ -1329,7 +1319,6 @@ static PyObject* NPyMechFunc_name_safe(NPyMechFunc* self) { static PyObject* NPyMechFunc_call(NPyMechFunc* self, PyObject* args) { CHECK_PROP_INVALID(self->pymech_->prop_id_); PyObject* result = NULL; - auto pyseg = self->pymech_->pyseg_; auto& f = self->f_->func; // patterning after fcall @@ -1370,12 +1359,8 @@ static PyObject* NPyMechObj_is_ion_safe(NPyMechObj* self) { static PyObject* NPyMechObj_segment(NPyMechObj* self) { CHECK_PROP_INVALID(self->prop_id_); - PyObject* result = NULL; - if (self->pyseg_) { - result = (PyObject*) (self->pyseg_); - Py_INCREF(result); - } - return result; + Py_XINCREF(self->pyseg_); + return (PyObject*) self->pyseg_; } static PyObject* NPyMechObj_segment_safe(NPyMechObj* self) { @@ -1383,13 +1368,12 @@ static PyObject* NPyMechObj_segment_safe(NPyMechObj* self) { } static PyObject* NPyMechFunc_mech(NPyMechFunc* self) { - PyObject* result = NULL; - if (self->pymech_) { - CHECK_PROP_INVALID(self->pymech_->prop_id_); - result = (PyObject*) (self->pymech_); - Py_INCREF(result); + auto* pymech = self->pymech_; + if (pymech) { + CHECK_PROP_INVALID(pymech->prop_id_); + Py_INCREF(pymech); } - return result; + return (PyObject*) pymech; } static PyObject* NPyMechFunc_mech_safe(NPyMechFunc* self) { @@ -1436,13 +1420,12 @@ static PyObject* NPyRangeVar_name_safe(NPyRangeVar* self) { } static PyObject* NPyRangeVar_mech(NPyRangeVar* self) { - CHECK_SEC_INVALID(self->pymech_->pyseg_->pysec_->sec_); - PyObject* result = NULL; - if (self->pymech_) { - result = (PyObject*) self->pymech_; - Py_INCREF(result); + auto* pymech = self->pymech_; + if (pymech) { + CHECK_SEC_INVALID(pymech->pyseg_->pysec_->sec_); + Py_INCREF(pymech); } - return result; + return (PyObject*) pymech; } static PyObject* NPyRangeVar_mech_safe(NPyRangeVar* self) { @@ -1485,12 +1468,12 @@ static PyObject* NPySecObj_connect(NPySecObj* self, PyObject* args) { PyErr_SetString(PyExc_ValueError, "child connection end must be 0 or 1"); return NULL; } - Py_INCREF(self); hoc_pushx(childend); hoc_pushx(parentx); nrn_pushsec(self->sec_); nrn_pushsec(parent->sec_); simpleconnectsection(); + Py_INCREF(self); return (PyObject*) self; } @@ -1501,29 +1484,27 @@ static PyObject* NPySecObj_connect_safe(NPySecObj* self, PyObject* args) { static PyObject* NPySecObj_insert(NPySecObj* self, PyObject* args) { CHECK_SEC_INVALID(self->sec_); char* tname; - PyObject *tpyobj, *tpyobj2; if (!PyArg_ParseTuple(args, "s", &tname)) { PyErr_Clear(); // if called with an object that has an insert method, use that + PyObject* tpyobj; if (PyArg_ParseTuple(args, "O", &tpyobj)) { - Py_INCREF(tpyobj); - Py_INCREF((PyObject*) self); - tpyobj2 = PyObject_CallMethod(tpyobj, "insert", "O", (PyObject*) self); - Py_DECREF(tpyobj); - if (tpyobj2 == NULL) { - Py_DECREF((PyObject*) self); + auto _tpyobj_tracker = nb::borrow(tpyobj); + // Returned object to be discarded + auto out_o = nb::steal(PyObject_CallMethod(tpyobj, "insert", "O", (PyObject*) self)); + if (!out_o.is_valid()) { PyErr_Clear(); PyErr_SetString( PyExc_TypeError, "insert argument must be either a string or an object with an insert method"); - return NULL; + return nullptr; } - Py_DECREF(tpyobj2); + Py_INCREF(self); return (PyObject*) self; } PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "insert takes a single positional argument"); - return NULL; + return nullptr; } PyObject* otype = PyDict_GetItemString(pmech_types, tname); if (!otype) { @@ -1625,8 +1606,8 @@ static PyObject* allseg(NPySecObj* self) { CHECK_SEC_INVALID(self->sec_); // printf("allseg\n"); NPyAllSegOfSecIter* ai = PyObject_New(NPyAllSegOfSecIter, pallseg_of_sec_iter_type); - ai->pysec_ = self; Py_INCREF(self); + ai->pysec_ = self; ai->allseg_iter_ = -1; return (PyObject*) ai; } @@ -1636,8 +1617,8 @@ static PyObject* allseg_safe(NPySecObj* self) { } static PyObject* allseg_of_sec_iter(NPyAllSegOfSecIter* self) { - Py_INCREF(self); self->allseg_iter_ = -1; + Py_INCREF(self); return (PyObject*) self; } @@ -1657,8 +1638,8 @@ static PyObject* allseg_of_sec_next(NPyAllSegOfSecIter* self) { // error return NULL; } - seg->pysec_ = self->pysec_; Py_INCREF(self->pysec_); + seg->pysec_ = self->pysec_; if (self->allseg_iter_ == -1) { seg->x_ = 0.; } else if (self->allseg_iter_ == n1) { @@ -1686,8 +1667,8 @@ static PyObject* seg_of_sec_next(NPySegOfSecIter* self) { // error return NULL; } - seg->pysec_ = self->pysec_; Py_INCREF(self->pysec_); + seg->pysec_ = self->pysec_; seg->x_ = (double(self->seg_iter_) + 0.5) / ((double) n1); ++self->seg_iter_; return (PyObject*) seg; @@ -1701,17 +1682,14 @@ static PyObject* seg_point_processes(NPySegObj* self) { Section* sec = self->pysec_->sec_; CHECK_SEC_INVALID(sec); Node* nd = node_exact(sec, self->x_); - PyObject* result = PyList_New(0); + nb::list result{}; for (Prop* p = nd->prop; p; p = p->next) { if (memb_func[p->_type].is_point) { auto* pp = p->dparam[1].get(); - PyObject* item = nrnpy_ho2po(pp->ob); - int err = PyList_Append(result, item); - assert(err == 0); - Py_XDECREF(item); + result.append(nb::steal(nrnpy_ho2po(pp->ob))); } } - return result; + return result.release().ptr(); } static PyObject* seg_point_processes_safe(NPySegObj* self) { @@ -1901,8 +1879,8 @@ static PyObject* mech_of_segment_iter_safe(NPySegObj* self) { } static Object* seg_from_sec_x(Section* sec, double x) { - PyObject* pyseg = (PyObject*) PyObject_New(NPySegObj, psegment_type); - NPySegObj* pseg = (NPySegObj*) pyseg; + auto pyseg = nb::steal((PyObject*) PyObject_New(NPySegObj, psegment_type)); + auto* pseg = (NPySegObj*) pyseg.ptr(); auto* pysec = static_cast(sec->prop->dparam[PROP_PY_INDEX].get()); if (pysec) { pseg->pysec_ = pysec; @@ -1916,9 +1894,7 @@ static Object* seg_from_sec_x(Section* sec, double x) { pseg->pysec_ = pysec; } pseg->x_ = x; - Object* ho = nrnpy_pyobject_in_obj(pyseg); - Py_DECREF(pyseg); - return ho; + return nrnpy_pyobject_in_obj(pyseg.ptr()); } static Object** pp_get_segment(void* vptr) { @@ -1957,8 +1933,8 @@ static NPyRangeVar* rvnew(Symbol* sym, NPySecObj* sec, double x) { } r->pymech_ = new_pymechobj(); r->pymech_->pyseg_ = PyObject_New(NPySegObj, psegment_type); - r->pymech_->pyseg_->pysec_ = sec; Py_INCREF(sec); + r->pymech_->pyseg_->pysec_ = sec; r->pymech_->pyseg_->x_ = 0.5; r->sym_ = sym; r->isptr_ = 0; @@ -1990,16 +1966,15 @@ static PyObject* section_getattro(NPySecObj* self, PyObject* pyname) { Section* sec = self->sec_; CHECK_SEC_INVALID(sec); PyObject* rv; - Py_INCREF(pyname); + auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use Py2NRNString name(pyname); char* n = name.c_str(); if (name.err()) { name.set_pyerr(PyExc_TypeError, "attribute name must be a string"); - Py_DECREF(pyname); - return NULL; + return nullptr; } // printf("section_getattr %s\n", n); - PyObject* result = 0; + PyObject* result = nullptr; if (strcmp(n, "L") == 0) { result = Py_BuildValue("d", section_length(sec)); } else if (strcmp(n, "Ra") == 0) { @@ -2016,7 +1991,7 @@ static PyObject* section_getattro(NPySecObj* self, PyObject* pyname) { auto const d = nrnpy_rangepointer(sec, sym, 0.5, &err, 0 /* idx */); if (d.is_invalid_handle()) { rv_noexist(sec, n, 0.5, err); - result = nullptr; + return nullptr; } else { if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) { nrn_area_ri(sec); @@ -2027,19 +2002,15 @@ static PyObject* section_getattro(NPySecObj* self, PyObject* pyname) { } else if (strcmp(n, "rallbranch") == 0) { result = Py_BuildValue("d", sec->prop->dparam[4].get()); } else if (strcmp(n, "__dict__") == 0) { - result = PyDict_New(); - int err = PyDict_SetItemString(result, "L", Py_None); - assert(err == 0); - err = PyDict_SetItemString(result, "Ra", Py_None); - assert(err == 0); - err = PyDict_SetItemString(result, "nseg", Py_None); - assert(err == 0); - err = PyDict_SetItemString(result, "rallbranch", Py_None); - assert(err == 0); + nb::dict out_dict{}; + out_dict["L"] = nb::none(); + out_dict["Ra"] = nb::none(); + out_dict["nseg"] = nb::none(); + out_dict["rallbranch"] = nb::none(); + result = out_dict.release().ptr(); } else { result = PyObject_GenericGetAttr((PyObject*) self, pyname); } - Py_DECREF(pyname); return result; } @@ -2055,12 +2026,11 @@ static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) } PyObject* rv; int err = 0; - Py_INCREF(pyname); + auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use Py2NRNString name(pyname); char* n = name.c_str(); if (name.err()) { name.set_pyerr(PyExc_TypeError, "attribute name must be a string"); - Py_DECREF(pyname); return -1; } // printf("section_setattro %s\n", n); @@ -2075,7 +2045,7 @@ static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) } } else { PyErr_SetString(PyExc_ValueError, "L must be > 0."); - err = -1; + return -1; } } else if (strcmp(n, "Ra") == 0) { double x; @@ -2085,7 +2055,7 @@ static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) sec->recalc_area_ = 1; } else { PyErr_SetString(PyExc_ValueError, "Ra must be > 0."); - err = -1; + return -1; } } else if (strcmp(n, "nseg") == 0) { int nseg; @@ -2093,7 +2063,7 @@ static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) nrn_change_nseg(sec, nseg); } else { PyErr_SetString(PyExc_ValueError, "nseg must be an integer in range 1 to 32767"); - err = -1; + return -1; } // printf("section_setattro err=%d nseg=%d nnode\n", err, nseg, // sec->nnode); @@ -2101,19 +2071,19 @@ static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) Symbol* sym = ((NPyRangeVar*) rv)->sym_; if (is_array(*sym)) { PyErr_SetString(PyExc_IndexError, "missing index"); - err = -1; + return -1; } else { int errp; auto d = nrnpy_rangepointer(sec, sym, 0.5, &errp, 0 /* idx */); if (d.is_invalid_handle()) { rv_noexist(sec, n, 0.5, errp); - err = -1; + return -1; } else if (!d.holds()) { PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer"); - err = -1; + return -1; } else if (!PyArg_Parse(value, "d", d.get())) { PyErr_SetString(PyExc_ValueError, "bad value"); - err = -1; + return -1; } else { // only need to do following if nseg > 1, VINDEX, or EXTRACELL nrn_rangeconst(sec, sym, neuron::container::data_handle(d), 0); @@ -2127,12 +2097,11 @@ static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) sec->recalc_area_ = 1; } else { PyErr_SetString(PyExc_ValueError, "rallbranch must be > 0"); - err = -1; + return -1; } } else { err = PyObject_GenericSetAttr((PyObject*) self, pyname, value); } - Py_DECREF(pyname); return err; } @@ -2174,8 +2143,8 @@ static PyObject* var_of_mech_iter(NPyMechObj* self) { if (!self->prop_) { return NULL; } + Py_INCREF(self); vmi->pymech_ = self; - Py_INCREF(vmi->pymech_); vmi->msym_ = memb_func[self->prop_->_type].sym; vmi->i_ = 0; return (PyObject*) vmi; @@ -2193,8 +2162,8 @@ static PyObject* var_of_mech_next(NPyVarOfMechIter* self) { Symbol* sym = self->msym_->u.ppsym[self->i_]; self->i_++; NPyRangeVar* r = (NPyRangeVar*) PyObject_New(NPyRangeVar, range_type); + Py_INCREF(self->pymech_); r->pymech_ = self->pymech_; - Py_INCREF(r->pymech_); r->sym_ = sym; r->isptr_ = 0; r->attr_from_sec_ = 0; @@ -2210,16 +2179,15 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { CHECK_SEC_INVALID(sec) Symbol* sym; - Py_INCREF(pyname); + auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use Py2NRNString name(pyname); char* n = name.c_str(); if (name.err()) { name.set_pyerr(PyExc_TypeError, "attribute name must be a string"); - Py_DECREF(pyname); - return NULL; + return nullptr; } // printf("segment_getattr %s\n", n); - PyObject* result = NULL; + PyObject* result = nullptr; PyObject* otype = NULL; PyObject* rv = NULL; if (strcmp(n, "v") == 0) { @@ -2232,7 +2200,7 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { Prop* p = nrn_mechanism(type, nd); if (!p) { rv_noexist(sec, n, self->x_, 1); - result = NULL; + return nullptr; } else { result = (PyObject*) new_pymechobj(self, p); } @@ -2247,8 +2215,8 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { } else if (is_array(*sym)) { NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type); r->pymech_ = new_pymechobj(); + Py_INCREF(self); r->pymech_->pyseg_ = self; - Py_INCREF(r->pymech_->pyseg_); r->sym_ = sym; r->isptr_ = 0; r->attr_from_sec_ = 0; @@ -2258,7 +2226,7 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { auto const d = nrnpy_rangepointer(sec, sym, self->x_, &err, 0 /* idx */); if (d.is_invalid_handle()) { rv_noexist(sec, n, self->x_, err); - result = NULL; + return nullptr; } else { if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) { nrn_area_ri(sec); @@ -2275,8 +2243,8 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { if (is_array(*sym)) { NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type); r->pymech_ = new_pymechobj(); - r->pymech_->pyseg_ = self; Py_INCREF(self); + r->pymech_->pyseg_ = self; r->sym_ = sym; r->isptr_ = 1; r->attr_from_sec_ = 0; @@ -2286,7 +2254,7 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { auto const d = nrnpy_rangepointer(sec, sym, self->x_, &err, 0 /* idx */); if (d.is_invalid_handle()) { rv_noexist(sec, n + 5, self->x_, err); - result = NULL; + return nullptr; } else { if (d.holds()) { result = nrn_hocobj_handle(neuron::container::data_handle(d)); @@ -2297,28 +2265,24 @@ static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) { } } else { rv_noexist(sec, n, self->x_, 2); - result = NULL; + return nullptr; } } else if (strcmp(n, "__dict__") == 0) { Node* nd = node_exact(sec, self->x_); - result = PyDict_New(); - int err = PyDict_SetItemString(result, "v", Py_None); - assert(err == 0); - PyDict_SetItemString(result, "diam", Py_None); - assert(err == 0); - PyDict_SetItemString(result, "cm", Py_None); - assert(err == 0); + nb::dict out_dict{}; + out_dict["v"] = nb::none(); + out_dict["diam"] = nb::none(); + out_dict["cm"] = nb::none(); for (Prop* p = nd->prop; p; p = p->next) { if (p->_type > CAP && !memb_func[p->_type].is_point) { char* pn = memb_func[p->_type].sym->name; - err = PyDict_SetItemString(result, pn, Py_None); - assert(err == 0); + out_dict[pn] = nb::none(); } } + result = out_dict.release().ptr(); } else { result = PyObject_GenericGetAttr((PyObject*) self, pyname); } - Py_DECREF(pyname); return result; } @@ -2357,17 +2321,15 @@ static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) PyObject* rv; Symbol* sym; int err = 0; - Py_INCREF(pyname); + auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use Py2NRNString name(pyname); char* n = name.c_str(); if (name.err()) { name.set_pyerr(PyExc_TypeError, "attribute name must be a string"); - Py_DECREF(pyname); return -1; } // printf("segment_setattro %s\n", n); if (strcmp(n, "x") == 0) { - int nseg; double x; if (PyArg_Parse(value, "d", &x) == 1 && x > 0. && x <= 1.) { if (x < 1e-9) { @@ -2379,7 +2341,7 @@ static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) } } else { PyErr_SetString(PyExc_ValueError, "x must be in range 0. to 1."); - err = -1; + return -1; } } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) { sym = ((NPyRangeVar*) rv)->sym_; @@ -2387,19 +2349,17 @@ static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) char s[200]; Sprintf(s, "%s needs an index for assignment", sym->name); PyErr_SetString(PyExc_IndexError, s); - err = -1; + return -1; } else { int errp; auto d = nrnpy_rangepointer(sec, sym, self->x_, &errp, 0 /* idx */); if (d.is_invalid_handle()) { rv_noexist(sec, n, self->x_, errp); - Py_DECREF(pyname); return -1; } if (d.holds()) { if (!PyArg_Parse(value, "d", d.get())) { PyErr_SetString(PyExc_ValueError, "bad value"); - Py_DECREF(pyname); return -1; } else if (sym->u.rng.type == MORPHOLOGY) { diam_changed = 1; @@ -2411,7 +2371,6 @@ static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) } } else { PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer"); - Py_DECREF(pyname); return -1; } } @@ -2429,7 +2388,6 @@ static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) } else { err = PyObject_GenericSetAttr((PyObject*) self, pyname, value); } - Py_DECREF(pyname); return err; } @@ -2512,13 +2470,12 @@ static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) { Section* sec = self->pyseg_->pysec_->sec_; CHECK_SEC_INVALID(sec) CHECK_PROP_INVALID(self->prop_id_); - Py_INCREF(pyname); + auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use Py2NRNString name(pyname); char* n = name.c_str(); if (!n) { name.set_pyerr(PyExc_TypeError, "attribute name must be a string"); - Py_DECREF(pyname); - return NULL; + return nullptr; } // printf("mech_getattro %s\n", n); PyObject* result = NULL; @@ -2538,8 +2495,8 @@ static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) { // printf("mech_getattro sym %s\n", sym->name); if (is_array(*sym)) { NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type); - r->pymech_ = self; Py_INCREF(self); + r->pymech_ = self; r->sym_ = sym; r->isptr_ = isptr; r->attr_from_sec_ = 0; @@ -2559,21 +2516,20 @@ static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) { Object* ob = nrn_nmodlrandom_wrap(self->prop_, sym); result = nrnpy_ho2po(ob); } else if (strcmp(n, "__dict__") == 0) { - result = PyDict_New(); + nb::dict out_dict{}; int cnt = mechsym->s_varn; for (int i = 0; i < cnt; ++i) { Symbol* s = mechsym->u.ppsym[i]; if (!striptrail(buf, bufsz, s->name, mname)) { strcpy(buf, s->name); } - int err = PyDict_SetItemString(result, buf, Py_None); - assert(err == 0); + out_dict[buf] = nb::none(); } // FUNCTION and PROCEDURE for (auto& it: nrn_mech2funcs_map[self->prop_->_type]) { - int err = PyDict_SetItemString(result, it.first.c_str(), Py_None); - assert(err == 0); + out_dict[it.first.c_str()] = nb::none(); } + result = out_dict.release().ptr(); } else { bool found_func{false}; if (self->prop_) { @@ -2582,8 +2538,8 @@ static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) { found_func = true; auto& f = funcs[n]; NPyMechFunc* pymf = PyObject_New(NPyMechFunc, pmechfunc_generic_type); - pymf->pymech_ = self; Py_INCREF(self); + pymf->pymech_ = self; pymf->f_ = f; result = (PyObject*) pymf; } @@ -2592,7 +2548,6 @@ static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) { result = PyObject_GenericGetAttr((PyObject*) self, pyname); } } - Py_DECREF(pyname); delete[] buf; return result; } @@ -2609,12 +2564,11 @@ static int mech_setattro(NPyMechObj* self, PyObject* pyname, PyObject* value) { } int err = 0; - Py_INCREF(pyname); + auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use Py2NRNString name(pyname); char* n = name.c_str(); if (name.err()) { name.set_pyerr(PyExc_TypeError, "attribute name must be a string"); - Py_DECREF(pyname); return -1; } // printf("mech_setattro %s\n", n); @@ -2638,19 +2592,18 @@ static int mech_setattro(NPyMechObj* self, PyObject* pyname, PyObject* value) { auto pd = get_rangevar(self, sym, 0); if (pd.is_invalid_handle()) { rv_noexist(sec, sym->name, self->pyseg_->x_, 2); - err = -1; + return -1; } else if (!pd.holds()) { PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer"); - err = -1; + return -1; } else if (!PyArg_Parse(value, "d", pd.get())) { PyErr_SetString(PyExc_ValueError, "must be a double"); - err = -1; + return -1; } } } else { err = PyObject_GenericSetAttr((PyObject*) self, pyname, value); } - Py_DECREF(pyname); return err; } @@ -2682,10 +2635,8 @@ static PyObject* NPySecObj_call(NPySecObj* self, PyObject* args) { CHECK_SEC_INVALID(self->sec_); double x = 0.5; PyArg_ParseTuple(args, "|d", &x); - PyObject* segargs = Py_BuildValue("(O,d)", self, x); - PyObject* seg = NPySegObj_new(psegment_type, segargs, 0); - Py_DECREF(segargs); - return seg; + auto segargs = nb::steal(Py_BuildValue("(O,d)", self, x)); + return NPySegObj_new(psegment_type, segargs.ptr(), nullptr); } static PyObject* NPySecObj_call_safe(NPySecObj* self, PyObject* args) { @@ -2963,23 +2914,9 @@ static PyMethodDef NPySegObj_methods[] = { {"volume", (PyCFunction) seg_volume_safe, METH_NOARGS, "Segment volume (um3)"}, {NULL}}; -// I'm guessing Python should change their typedef to get rid of the -// four "deprecated conversion from string constant to 'char*'" warnings. -// Could avoid by casting each to (char*) but probably better to keep the -// warnings. For now we get rid of the warnings by copying the string to -// char array. -static char* cpstr(const char* s) { - char* s2 = new char[strlen(s) + 1]; - strcpy(s2, s); - return s2; -} static PyMemberDef NPySegObj_members[] = { - {cpstr("x"), - T_DOUBLE, - offsetof(NPySegObj, x_), - 0, - cpstr("location in the section (segment containing x)")}, - {cpstr("sec"), T_OBJECT_EX, offsetof(NPySegObj, pysec_), 0, cpstr("Section")}, + {"x", T_DOUBLE, offsetof(NPySegObj, x_), 0, "location in the section (segment containing x)"}, + {"sec", T_OBJECT_EX, offsetof(NPySegObj, pysec_), 0, "Section"}, {NULL}}; static PyMethodDef NPyMechObj_methods[] = { @@ -3053,7 +2990,6 @@ static void rangevars_add(Symbol* sym) { } PyObject* nrnpy_nrn(void) { - int i; PyObject* m; int err = 0; diff --git a/src/nrnpython/nrnpy_p2h.cpp b/src/nrnpython/nrnpy_p2h.cpp index 0d765bb6a5..931fa0a453 100644 --- a/src/nrnpython/nrnpy_p2h.cpp +++ b/src/nrnpython/nrnpy_p2h.cpp @@ -1,6 +1,7 @@ #include <../../nrnconf.h> #include + #include #include #include @@ -11,12 +12,14 @@ #include "oc_ansi.h" #include "parse.hpp" -static void nrnpy_decref_defer(PyObject*); + +#include +namespace nb = nanobind; + static char* nrnpyerr_str(); static PyObject* nrnpy_pyCallObject(PyObject*, PyObject*); static PyObject* main_module; static PyObject* main_namespace; -static hoc_List* dlist; struct Py2Nrn final { ~Py2Nrn() { @@ -249,15 +252,12 @@ static void py2n_component(Object* ob, Symbol* sym, int nindex, int isfunc) { PyObject* pn = PyNumber_Float(result); hoc_pushx(PyFloat_AsDouble(pn)); Py_XDECREF(pn); - Py_XDECREF(result); } else if (is_python_string(result)) { char** ts = hoc_temp_charptr(); Py2NRNString str(result, true); *ts = str.c_str(); hoc_pop_defer(); hoc_pushstr(ts); - // how can we defer the result unref til the string is popped - nrnpy_decref_defer(result); } else { // PyObject_Print(result, stdout, 0); on = nrnpy_po2ho(result); @@ -266,8 +266,8 @@ static void py2n_component(Object* ob, Symbol* sym, int nindex, int isfunc) { if (on) { on->refcount--; } - Py_XDECREF(result); } + Py_XDECREF(result); Py_XDECREF(head); Py_DECREF(tail); } @@ -329,17 +329,6 @@ static void hpoasgn(Object* o, int type) { } } -static void nrnpy_decref_defer(PyObject* po) { - if (po) { -#if 0 - PyObject* ps = PyObject_Str(po); - printf("defer %s\n", PyString_AsString(ps)); - Py_DECREF(ps); -#endif - hoc_l_lappendvoid(dlist, (void*) po); - } -} - static PyObject* hoccommand_exec_help1(PyObject* po) { PyObject* r; // PyObject_Print(po, stdout, 0); @@ -607,43 +596,35 @@ static int guigetstr(Object* ho, char** cpp) { return 1; } -static PyObject* loads; -static PyObject* dumps; +static nb::callable loads; +static nb::callable dumps; static void setpickle() { if (dumps) { return; } - PyObject* pickle = PyImport_ImportModule("pickle"); - if (pickle) { - Py_INCREF(pickle); - dumps = PyObject_GetAttrString(pickle, "dumps"); - loads = PyObject_GetAttrString(pickle, "loads"); - if (dumps) { - Py_INCREF(dumps); - Py_INCREF(loads); - } - } + nb::module_ pickle = nb::module_::import_("pickle"); + dumps = pickle.attr("dumps"); + loads = pickle.attr("loads"); if (!dumps || !loads) { hoc_execerror("Neither Python cPickle nor pickle are available", 0); } + // We intentionally leak these, because if we don't + // we observe SEGFAULTS during application shutdown. + // Likely because "~nb::callable" runs after the Python + // library cleaned up. + dumps.inc_ref(); + loads.inc_ref(); } // note that *size includes the null terminating character if it exists static std::vector pickle(PyObject* p) { - PyObject* arg = PyTuple_Pack(1, p); - PyObject* r = nrnpy_pyCallObject(dumps, arg); - Py_XDECREF(arg); + auto r = nb::borrow(dumps(nb::borrow(p))); if (!r && PyErr_Occurred()) { PyErr_Print(); } assert(r); - assert(PyBytes_Check(r)); - std::size_t size = PyBytes_Size(r); - char* buf = PyBytes_AsString(r); - std::vector ret(buf, buf + size); - Py_XDECREF(r); - return ret; + return std::vector(r.c_str(), r.c_str() + r.size()); } static std::vector po2pickle(Object* ho) { @@ -656,25 +637,18 @@ static std::vector po2pickle(Object* ho) { } } -static PyObject* unpickle(const char* s, std::size_t len) { - PyObject* ps = PyBytes_FromStringAndSize(s, len); - PyObject* arg = PyTuple_Pack(1, ps); - PyObject* po = nrnpy_pyCallObject(loads, arg); - assert(po); - Py_XDECREF(arg); - Py_XDECREF(ps); - return po; +static nb::object unpickle(const char* s, std::size_t len) { + return loads(nb::bytes(s, len)); } -static PyObject* unpickle(const std::vector& s) { +static nb::object unpickle(const std::vector& s) { return unpickle(s.data(), s.size()); } static Object* pickle2po(const std::vector& s) { setpickle(); - PyObject* po = unpickle(s); - Object* ho = nrnpy_pyobject_in_obj(po); - Py_XDECREF(po); + nb::object po = unpickle(s); + Object* ho = nrnpy_pyobject_in_obj(po.ptr()); return ho; } @@ -743,33 +717,22 @@ std::vector call_picklef(const std::vector& fname, int narg) { // fname is a pickled callable, narg is the number of args on the // hoc stack with types double, char*, hoc Vector, and PythonObject // callable return must be pickleable. - PyObject* args = 0; - PyObject* result = 0; - PyObject* callable; - setpickle(); - PyObject* ps = PyBytes_FromStringAndSize(fname.data(), fname.size()); - args = PyTuple_Pack(1, ps); - callable = nrnpy_pyCallObject(loads, args); + nb::bytes ps(fname.data(), fname.size()); + + auto callable = nb::borrow(loads(ps)); assert(callable); - Py_XDECREF(args); - Py_XDECREF(ps); - args = PyTuple_New(narg); + nb::list args{}; for (int i = 0; i < narg; ++i) { - PyObject* arg = nrnpy_hoc_pop("call_picklef"); - if (PyTuple_SetItem(args, narg - 1 - i, arg)) { - assert(0); - } - // Py_XDECREF(arg); + nb::object arg = nb::steal(nrnpy_hoc_pop("call_picklef")); + args.append(arg); } - result = nrnpy_pyCallObject(callable, args); - Py_DECREF(callable); - Py_DECREF(args); + nb::object result = callable(*args); if (!result) { char* mes = nrnpyerr_str(); if (mes) { - Fprintf(stderr, "%s\n", mes); + std::cerr << mes << std::endl; free(mes); hoc_execerror("PyObject method call failed:", NULL); } @@ -777,9 +740,7 @@ std::vector call_picklef(const std::vector& fname, int narg) { PyErr_Print(); } } - auto rs = pickle(result); - Py_XDECREF(result); - return rs; + return pickle(result.ptr()); } #include "nrnmpi.h" @@ -801,7 +762,8 @@ static PyObject* char2pylist(char* buf, int np, int* cnt, int* displ) { Py_INCREF(Py_None); // 'Fatal Python error: deallocating None' eventually PyList_SetItem(plist, i, Py_None); } else { - PyObject* p = unpickle(buf + displ[i], cnt[i]); + nb::object po = unpickle(buf + displ[i], cnt[i]); + PyObject* p = po.release().ptr(); PyList_SetItem(plist, i, p); } } @@ -874,7 +836,8 @@ static PyObject* py_broadcast(PyObject* psrc, int root) { nrnmpi_char_broadcast(buf.data(), cnt, root); PyObject* pdest = psrc; if (root != nrnmpi_myid) { - pdest = unpickle(buf); + nb::object po = unpickle(buf); + pdest = po.release().ptr(); } else { Py_INCREF(pdest); } @@ -1082,7 +1045,8 @@ static Object* py_alltoall_type(int size, int type) { delete[] sdispl; if (rcnt[0]) { - pdest = unpickle(r); + nb::object po = unpickle(r); + pdest = po.release().ptr(); } else { pdest = Py_None; Py_INCREF(pdest); @@ -1149,5 +1113,4 @@ extern "C" NRN_EXPORT void nrnpython_reg_real(neuron::python::impl_ptrs* ptrs) { nrnpython_reg_real_nrnpython_cpp(ptrs); // call a function in nrnpy_hoc.cpp to register the functions defined there nrnpython_reg_real_nrnpy_hoc_cpp(ptrs); - dlist = hoc_l_newlist(); } diff --git a/src/oc/code.cpp b/src/oc/code.cpp index 817d4ba656..d297dcceaa 100644 --- a/src/oc/code.cpp +++ b/src/oc/code.cpp @@ -2,8 +2,9 @@ /* /local/src/master/nrn/src/oc/code.cpp,v 1.37 1999/07/03 14:20:21 hines Exp */ #include "backtrace_utils.h" -#include +#include "bbslsrv2.h" #include "hoc.h" +#include "cabcode.h" #include "code.h" #include "hocstr.h" #include "parse.hpp" @@ -12,9 +13,6 @@ #include "oc_ansi.h" #include "hocparse.h" #include "equation.h" -#include -#include -#include #include #include "nrnfilewrap.h" #include "utils/enumerate.h" @@ -23,6 +21,10 @@ #include "options.h" #include "section.h" +#include +#include +#include +#include #include #include #include @@ -1828,7 +1830,6 @@ void eval(void) /* evaluate variable on stack */ Object* obsav = 0; Symlist* slsav; double d = 0.0; - extern double cable_prop_eval(Symbol*); Symbol* sym; sym = hoc_spop(); if (sym->cpublic == 2) { @@ -1877,14 +1878,6 @@ void eval(void) /* evaluate variable on stack */ case USERFLOAT: d = (sym->u.pvalfloat)[araypt(sym, SYMBOL)]; break; -#if NEMO - case NEMONODE: - hoc_eval_nemonode(sym, hoc_xpop(), &d); - break; - case NEMOAREA: - hoc_eval_nemoarea(sym, hoc_xpop(), &d); - break; -#endif /*NEMO*/ default: d = (OPVAL(sym))[araypt(sym, OBJECTVAR)]; break; @@ -1951,10 +1944,6 @@ void hoc_evalpointer() { break; case USERINT: case USERFLOAT: -#if NEMO - case NEMONODE: - case NEMOAREA: -#endif /*NEMO*/ execerror("can use pointer only to doubles", sym->name); break; default: @@ -2244,14 +2233,6 @@ void hoc_assign() { } (sym->u.pvalfloat)[ind] = (float) d2; break; -#if NEMO - case NEMONODE: - hoc_asgn_nemonode(sym, hoc_xpop(), &d2, op); - break; - case NEMOAREA: - hoc_asgn_nemoarea(sym, hoc_xpop(), &d2, op); - break; -#endif /*NEMO*/ default: ind = araypt(sym, OBJECTVAR); if (op) { diff --git a/src/oc/code.h b/src/oc/code.h index e9906db78f..eab311bae1 100644 --- a/src/oc/code.h +++ b/src/oc/code.h @@ -27,7 +27,7 @@ extern void hoc_arayinstal(void); /* OOP */ extern void hoc_objectvar(void), hoc_object_component(void), hoc_object_eval(void); extern void hoc_object_asgn(void), hoc_objvardecl(void), hoc_cmp_otype(void), hoc_newobj(void); -extern void hoc_asgn_obj_to_str(void), hoc_known_type(void), hoc_push_string(void); +extern void hoc_asgn_obj_to_str(void), hoc_known_type(void); extern void hoc_objectarg(void), hoc_ob_pointer(void), hoc_constobject(void); extern void hoc_push_current_object(void), hoc_newobj_arg(void); extern void hoc_autoobject(void), hocobjret(void), hoc_newobj_ret(void); diff --git a/src/oc/fileio.cpp b/src/oc/fileio.cpp index 455d0220a1..8b59284e79 100644 --- a/src/oc/fileio.cpp +++ b/src/oc/fileio.cpp @@ -91,14 +91,16 @@ void wopen(void) /* open file for writing */ else fname = ""; d = 1.; - if (fout != stdout) - ERRCHK(IGNORE(fclose(fout));) + if (fout != stdout) { + IGNORE(fclose(fout)); + } fout = stdout; - if (fname[0] != 0) - ERRCHK(if ((fout = fopen(expand_env_var(fname), "w")) == (FILE*) 0) { + if (fname[0] != 0) { + if ((fout = fopen(expand_env_var(fname), "w")) == nullptr) { d = 0.; fout = stdout; - }) + } + } errno = 0; ret(); pushx(d); diff --git a/src/oc/hoc_oop.cpp b/src/oc/hoc_oop.cpp index 4f2ee252b3..6184dc87ce 100644 --- a/src/oc/hoc_oop.cpp +++ b/src/oc/hoc_oop.cpp @@ -1,15 +1,17 @@ #include <../../nrnconf.h> +#include +#include #include "utils/formatting.hpp" -#include -#include -#include + +#include "classreg.h" #include "hocstr.h" #include "parse.hpp" #include "hocparse.h" #include "code.h" +#include "cabcode.h" #include "hocassrt.h" #include "hoclist.h" #include "nrn_ansi.h" @@ -1367,7 +1369,6 @@ void hoc_object_eval(void) { } hoc_pushx(*(nrn_rangepointer(sec, sym, x))); } else if (d_sym->type == VAR && d_sym->subtype == USERPROPERTY) { - extern double cable_prop_eval(Symbol*); hoc_pushx(cable_prop_eval(hoc_spop())); } } diff --git a/src/oc/hocdec.h b/src/oc/hocdec.h index d1a95eb200..a8f5b31826 100644 --- a/src/oc/hocdec.h +++ b/src/oc/hocdec.h @@ -83,11 +83,7 @@ typedef char* Upoint; #define USERINT 1 /* For subtype */ #define USERDOUBLE 2 #define USERPROPERTY 3 /* for newcable non-range variables */ -#define USERFLOAT 4 /* John Miller's NEMO uses floats */ -#if NEMO -#define NEMONODE 5 /* looks syntactically like vector */ -#define NEMOAREA 6 /* looks like vector */ -#endif +#define USERFLOAT 4 #define SYMBOL 7 /* for stack type */ #define OBJECTTMP 8 /* temporary object on stack */ #define STKOBJ_UNREF 9 /* already unreffed temporary object on stack */ @@ -280,8 +276,6 @@ int ilint; #endif using neuron::Sprintf; -#define ERRCHK(c1) c1 - // No longer used because of clang format difficulty // #define IFGUI if (hoc_usegui) { // #define ENDGUI } diff --git a/src/oc/mk_hocusr_h.py b/src/oc/mk_hocusr_h.py index 596634c51a..56f60ff688 100644 --- a/src/oc/mk_hocusr_h.py +++ b/src/oc/mk_hocusr_h.py @@ -49,11 +49,11 @@ def process(type, names): # the pgcc 18.4 compiler prepends with a multiline typedef and several # extern void lines that need to be skipped. Our first relevant line -# contains spatial_method or neuron2nemo or node_data +# contains disconnect skip = 1 for line in text.splitlines(): - if "spatial_method" in line or "neuron2nemo" in line or "node_data" in line: + if "disconnect" in line: skip = 0 names = line.replace(",", " ").replace(";", " ").split() if not skip and len(names) > 2: diff --git a/test/rxd/conftest.py b/test/rxd/conftest.py index 1fbe8ee0cc..2a98c9d3f9 100644 --- a/test/rxd/conftest.py +++ b/test/rxd/conftest.py @@ -1,5 +1,6 @@ import os.path as osp import numpy +import ctypes import pytest import gc @@ -81,7 +82,7 @@ def neuron_nosave_instance(neuron_import): rxd.rxd.rxd_include_node_flux1D(0, None, None, None) rxd.species._has_1d = False rxd.species._has_3d = False - rxd.rxd._zero_volume_indices = numpy.ndarray(0, dtype=numpy.int_) + rxd.rxd._zero_volume_indices = numpy.ndarray(0, dtype=ctypes.c_long) rxd.set_solve_type(dimension=1)