From 1ead3a4c474cde193824cffa6f24bda0924f5aca Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 27 Feb 2024 13:22:39 +0100 Subject: [PATCH 01/33] Move nmodl Python bindings to `python/nmodl` Fixes #462 --- pyproject.toml | 1 - {nmodl => python/nmodl}/__init__.py | 0 {nmodl => python/nmodl}/_binwrapper.py | 0 {nmodl => python/nmodl}/ast.py | 0 {nmodl => python/nmodl}/dsl.py | 0 {nmodl => python/nmodl}/ext/example/exp2syn.mod | 0 {nmodl => python/nmodl}/ext/example/expsyn.mod | 0 {nmodl => python/nmodl}/ext/example/hh.mod | 0 {nmodl => python/nmodl}/ext/example/passive.mod | 0 {nmodl => python/nmodl}/ext/viz/css/tree.css | 0 {nmodl => python/nmodl}/ext/viz/index.html | 0 {nmodl => python/nmodl}/ext/viz/js/d3.min.js | 0 {nmodl => python/nmodl}/ext/viz/js/tree.js | 0 {nmodl => python/nmodl}/ode.py | 0 {nmodl => python/nmodl}/symtab.py | 0 {nmodl => python/nmodl}/visitor.py | 0 src/pybind/CMakeLists.txt | 2 +- 17 files changed, 1 insertion(+), 2 deletions(-) rename {nmodl => python/nmodl}/__init__.py (100%) rename {nmodl => python/nmodl}/_binwrapper.py (100%) rename {nmodl => python/nmodl}/ast.py (100%) rename {nmodl => python/nmodl}/dsl.py (100%) rename {nmodl => python/nmodl}/ext/example/exp2syn.mod (100%) rename {nmodl => python/nmodl}/ext/example/expsyn.mod (100%) rename {nmodl => python/nmodl}/ext/example/hh.mod (100%) rename {nmodl => python/nmodl}/ext/example/passive.mod (100%) rename {nmodl => python/nmodl}/ext/viz/css/tree.css (100%) rename {nmodl => python/nmodl}/ext/viz/index.html (100%) rename {nmodl => python/nmodl}/ext/viz/js/d3.min.js (100%) rename {nmodl => python/nmodl}/ext/viz/js/tree.js (100%) rename {nmodl => python/nmodl}/ode.py (100%) rename {nmodl => python/nmodl}/symtab.py (100%) rename {nmodl => python/nmodl}/visitor.py (100%) diff --git a/pyproject.toml b/pyproject.toml index 8e067eef5d..478809f776 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ build-backend = "scikit_build_core.build" [tool.scikit-build] metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" -wheel.packages = ["nmodl"] logging.level = "DEBUG" [tool.scikit-build.cmake] diff --git a/nmodl/__init__.py b/python/nmodl/__init__.py similarity index 100% rename from nmodl/__init__.py rename to python/nmodl/__init__.py diff --git a/nmodl/_binwrapper.py b/python/nmodl/_binwrapper.py similarity index 100% rename from nmodl/_binwrapper.py rename to python/nmodl/_binwrapper.py diff --git a/nmodl/ast.py b/python/nmodl/ast.py similarity index 100% rename from nmodl/ast.py rename to python/nmodl/ast.py diff --git a/nmodl/dsl.py b/python/nmodl/dsl.py similarity index 100% rename from nmodl/dsl.py rename to python/nmodl/dsl.py diff --git a/nmodl/ext/example/exp2syn.mod b/python/nmodl/ext/example/exp2syn.mod similarity index 100% rename from nmodl/ext/example/exp2syn.mod rename to python/nmodl/ext/example/exp2syn.mod diff --git a/nmodl/ext/example/expsyn.mod b/python/nmodl/ext/example/expsyn.mod similarity index 100% rename from nmodl/ext/example/expsyn.mod rename to python/nmodl/ext/example/expsyn.mod diff --git a/nmodl/ext/example/hh.mod b/python/nmodl/ext/example/hh.mod similarity index 100% rename from nmodl/ext/example/hh.mod rename to python/nmodl/ext/example/hh.mod diff --git a/nmodl/ext/example/passive.mod b/python/nmodl/ext/example/passive.mod similarity index 100% rename from nmodl/ext/example/passive.mod rename to python/nmodl/ext/example/passive.mod diff --git a/nmodl/ext/viz/css/tree.css b/python/nmodl/ext/viz/css/tree.css similarity index 100% rename from nmodl/ext/viz/css/tree.css rename to python/nmodl/ext/viz/css/tree.css diff --git a/nmodl/ext/viz/index.html b/python/nmodl/ext/viz/index.html similarity index 100% rename from nmodl/ext/viz/index.html rename to python/nmodl/ext/viz/index.html diff --git a/nmodl/ext/viz/js/d3.min.js b/python/nmodl/ext/viz/js/d3.min.js similarity index 100% rename from nmodl/ext/viz/js/d3.min.js rename to python/nmodl/ext/viz/js/d3.min.js diff --git a/nmodl/ext/viz/js/tree.js b/python/nmodl/ext/viz/js/tree.js similarity index 100% rename from nmodl/ext/viz/js/tree.js rename to python/nmodl/ext/viz/js/tree.js diff --git a/nmodl/ode.py b/python/nmodl/ode.py similarity index 100% rename from nmodl/ode.py rename to python/nmodl/ode.py diff --git a/nmodl/symtab.py b/python/nmodl/symtab.py similarity index 100% rename from nmodl/symtab.py rename to python/nmodl/symtab.py diff --git a/nmodl/visitor.py b/python/nmodl/visitor.py similarity index 100% rename from nmodl/visitor.py rename to python/nmodl/visitor.py diff --git a/src/pybind/CMakeLists.txt b/src/pybind/CMakeLists.txt index 9600515e11..d1376ba2e1 100644 --- a/src/pybind/CMakeLists.txt +++ b/src/pybind/CMakeLists.txt @@ -77,7 +77,7 @@ foreach(file IN LISTS NMODL_PYTHON_FILES) cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/nmodl/${file} OUTPUT ${CMAKE_BINARY_DIR}/lib/nmodl/${file}) endforeach() -file(COPY ${NMODL_PROJECT_SOURCE_DIR}/nmodl/ext DESTINATION ${CMAKE_BINARY_DIR}/lib/nmodl/) +file(COPY ${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/ext DESTINATION ${CMAKE_BINARY_DIR}/lib/nmodl/) # ============================================================================= # Install python binding components From 4dd0cde740744e6a4f10878dd59d1cfc45b0c902 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 27 Feb 2024 13:41:57 +0100 Subject: [PATCH 02/33] Minor fixes for testing --- packaging/test_wheel.bash | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packaging/test_wheel.bash b/packaging/test_wheel.bash index 6706037976..ac99d7bdf9 100755 --- a/packaging/test_wheel.bash +++ b/packaging/test_wheel.bash @@ -23,16 +23,14 @@ test_wheel () { # sample mod file for nrnivmodl check TEST_DIR="$(mktemp -d)" OUTPUT_DIR="$(mktemp -d)" - cp "${this_dir}/../nmodl/ext/example/"*.mod "$TEST_DIR/" + cp "${this_dir}/../python/nmodl/ext/example/"*.mod "$TEST_DIR/" cp "${this_dir}/../test/integration/mod/cabpump.mod" "${this_dir}/../test/integration/mod/var_init.inc" "$TEST_DIR/" - cd "${this_dir}" for mod in "${TEST_DIR}/"*.mod do nmodl -o "${OUTPUT_DIR}" "${mod}" sympy --analytic $python_exe -c "import nmodl; driver = nmodl.NmodlDriver(); driver.parse_file('${mod}')" done $python_exe -m pytest -vvv "${this_dir}/../test/" - cd - } echo "== Testing $python_wheel using $python_exe ($python_ver) ==" From a75d65653b83aad6a985a791c2dd815e34785fab Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 27 Feb 2024 15:00:46 +0100 Subject: [PATCH 03/33] Fix wheel.packages No idea why this doesn't work in the CI yet I can build the wheels just fine locally... --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 478809f776..0d057c2f46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ build-backend = "scikit_build_core.build" [tool.scikit-build] metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" +wheel.packages = ["python/nmodl"] logging.level = "DEBUG" [tool.scikit-build.cmake] From 3a8640e564c4fa6e8dcb5bc77738bd68e5f2255e Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 27 Feb 2024 15:13:24 +0100 Subject: [PATCH 04/33] Copy also files from build dir --- src/pybind/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pybind/CMakeLists.txt b/src/pybind/CMakeLists.txt index d1376ba2e1..82304c1ae5 100644 --- a/src/pybind/CMakeLists.txt +++ b/src/pybind/CMakeLists.txt @@ -70,8 +70,8 @@ endif() # ============================================================================= file( GLOB NMODL_PYTHON_FILES - RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/nmodl/" - CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/nmodl/*.py") + RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/" + CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/*.py") foreach(file IN LISTS NMODL_PYTHON_FILES) cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/nmodl/${file} OUTPUT From 6453a1ead465271ec2af5f1a9fb6a58cb7a1f50d Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 27 Feb 2024 16:32:05 +0100 Subject: [PATCH 05/33] Revert "Copy also files from build dir" This reverts commit 3a8640e564c4fa6e8dcb5bc77738bd68e5f2255e. --- src/pybind/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pybind/CMakeLists.txt b/src/pybind/CMakeLists.txt index 82304c1ae5..d1376ba2e1 100644 --- a/src/pybind/CMakeLists.txt +++ b/src/pybind/CMakeLists.txt @@ -70,8 +70,8 @@ endif() # ============================================================================= file( GLOB NMODL_PYTHON_FILES - RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/" - CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/*.py") + RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/nmodl/" + CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/nmodl/*.py") foreach(file IN LISTS NMODL_PYTHON_FILES) cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/nmodl/${file} OUTPUT From 8eb4c84985071dd88814e1747a17c5788b65169e Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 27 Feb 2024 16:56:22 +0100 Subject: [PATCH 06/33] Fix for cmake build --- src/language/code_generator.cmake | 2 +- src/pybind/CMakeLists.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/language/code_generator.cmake b/src/language/code_generator.cmake index 0c6ccae181..a3dea0767f 100644 --- a/src/language/code_generator.cmake +++ b/src/language/code_generator.cmake @@ -34,9 +34,9 @@ set(CODE_GENERATOR_JINJA_FILES set(CODE_GENERATOR_PY_FILES ${PROJECT_SOURCE_DIR}/src/language/argument.py ${PROJECT_SOURCE_DIR}/src/language/code_generator.py + ${PROJECT_SOURCE_DIR}/src/language/language_parser.py ${PROJECT_SOURCE_DIR}/src/language/node_info.py ${PROJECT_SOURCE_DIR}/src/language/nodes.py - ${PROJECT_SOURCE_DIR}/src/language/language_parser.py ${PROJECT_SOURCE_DIR}/src/language/utils.py ) diff --git a/src/pybind/CMakeLists.txt b/src/pybind/CMakeLists.txt index d1376ba2e1..0d7516874b 100644 --- a/src/pybind/CMakeLists.txt +++ b/src/pybind/CMakeLists.txt @@ -70,11 +70,11 @@ endif() # ============================================================================= file( GLOB NMODL_PYTHON_FILES - RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/nmodl/" - CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/nmodl/*.py") + RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/" + CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/*.py") foreach(file IN LISTS NMODL_PYTHON_FILES) - cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/nmodl/${file} OUTPUT + cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/${file} OUTPUT ${CMAKE_BINARY_DIR}/lib/nmodl/${file}) endforeach() file(COPY ${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/ext DESTINATION ${CMAKE_BINARY_DIR}/lib/nmodl/) From dfde76a8fddc12b06ca6c54dd42101aeb9052f24 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 28 Feb 2024 11:44:11 +0100 Subject: [PATCH 07/33] Update docs --- CONTRIBUTING.rst | 5 ++--- INSTALL.rst | 45 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index c7ad6e594b..4ea7c5da9f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -201,9 +201,8 @@ the Python API: 1. setup a sandbox environment with either *virtualenv*, *pyenv*, or *pipenv*. For instance with *virtualenv*: ``python -m venv .venv && source .venv/bin/activate`` -2. build the Python package with the command: ``python setup.py build`` -3. install *pytest* Python package: ``pip install pytest`` -4. execute the unit-tests: ``pytest`` +2. build the Python wheel with the command: ``python -m pip wheel . --no-deps`` +3. execute the unit-tests for the wheel: ``bash packaging/test_wheel.bash $(command -v python) WHEEL``, where ``WHEEL`` is the path to the wheel generated in the previous step. Memory Leaks and clang-tidy ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/INSTALL.rst b/INSTALL.rst index 72fff92bde..a37b0474de 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -45,12 +45,13 @@ of all dependencies we recommend using `homebrew `__: brew install flex bison cmake python3 -The necessary Python packages can then easily be added using the pip3 -command. +All of the Python dependencies (build, run, and development) can be installed +using: .. code:: sh - pip3 install --user -r requirements.txt + pip3 install --user pip-tools + pip3 install --user -r <(pip-compile --all-build-deps --all-extras --no-strip-extras 2>&1) Make sure to have latest flex/bison in $PATH : @@ -74,11 +75,13 @@ installed along with the system toolchain: apt-get install flex bison gcc python3 python3-pip -The Python dependencies are installed using: +All of the Python dependencies (build, run, and development) can be installed +using: .. code:: sh - pip3 install --user -r requirements.txt + pip3 install --user pip-tools + pip3 install --user -r <(pip-compile --all-build-deps --all-extras --no-strip-extras 2>&1) Build Project ------------- @@ -139,6 +142,19 @@ This should build the NMODL framework and install it into your pip user ``site-packages`` folder such that it becomes available as a Python module. +Building a wheel +~~~~~~~~~~~~~~~~ + +You can also build a wheel you can test and install in another environment using: + +.. code:: sh + + pip3 wheel . --no-deps [-C OPTION1=VALUE1 -C OPTION2=VALUE2...] [--wheel-dir DIRECTORY] + +where the various ``OPTION`` values describe the build options (for a list of +all available options, please consult the `reference `_). +Notably, due to a bug in CMake, on MacOS one should pass ``-C build-dir=DIRECTORY`` to the above. + When building without linking against libpython ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -210,6 +226,16 @@ example in your Python 3 interpeter as follows: SUFFIX hh } +You can also run all of the Python tests for a given wheel using: + +.. code:: sh + + bash packaging/test_wheel.bash PYTHON_EXECUTABLE WHEEL + +where ``PYTHON_EXECUTABLE`` should be replaced by the path to the Python +executable, and ``WHEEL`` should be replaced by the path to the wheel you wish +to test. + NMODL is now setup correctly! Generating Documentation @@ -219,9 +245,12 @@ In order to build the documentation you must have additionally ``pandoc`` installed. Use your system’s package manager to do this (e.g. ``sudo apt-get install pandoc``). -You can build the entire documentation simply by using sphinx from -``setup.py``: +You can build the entire documentation simply by using the ``generate_docs.sh`` +script: .. code:: sh - python3 setup.py build_ext --inplace docs + bash docs/generate_docs.sh + +The documentation will then be available in the ``public`` subdirectory. Note +that the Python package must be installed beforehand using ``pip install .``. From 25eb4a055fee4ba7a2e77a621b36834f9d028312 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 28 Feb 2024 11:53:27 +0100 Subject: [PATCH 08/33] Improve usecases 'func_proc{,_pnt}'. (#1182) Check that if there's multiple instances of the mechanisms the functions and procedures use the values for the correct instance. --- test/usecases/func_proc/func_proc.mod | 4 ++-- test/usecases/func_proc/simulate.py | 18 ++++++++++---- test/usecases/func_proc_pnt/func_proc_pnt.mod | 4 ++-- test/usecases/func_proc_pnt/simulate.py | 24 ++++++++++++++----- test/usecases/references | 2 +- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/test/usecases/func_proc/func_proc.mod b/test/usecases/func_proc/func_proc.mod index b8ad6b46ce..c11f662ebd 100644 --- a/test/usecases/func_proc/func_proc.mod +++ b/test/usecases/func_proc/func_proc.mod @@ -15,8 +15,8 @@ PROCEDURE set_x_a(a) { x = a } -FUNCTION get_a_42(a) { - get_a_42 = a + 42 +FUNCTION x_plus_a(a) { + x_plus_a = x + a } PROCEDURE set_a_x() { diff --git a/test/usecases/func_proc/simulate.py b/test/usecases/func_proc/simulate.py index 261ec54076..ca1ffc73b2 100644 --- a/test/usecases/func_proc/simulate.py +++ b/test/usecases/func_proc/simulate.py @@ -1,15 +1,23 @@ from neuron import h +nseg = 5 s = h.Section() +s.nseg = nseg s.insert("test_func_proc") -s(0.5).test_func_proc.set_x_42() +coords = [(0.5 + k) * 1.0 / nseg for k in range(nseg)] +values = [ 0.1 + k for k in range(nseg)] -assert s(0.5).test_func_proc.x == 42 +for x in coords: + s(x).test_func_proc.set_x_42() + assert s(x).test_func_proc.x == 42 -s(0.5).test_func_proc.set_x_a(13.7) +for x, value in zip(coords, values): + s(x).test_func_proc.set_x_a(value) -assert s(0.5).test_func_proc.x == 13.7 +for x, value in zip(coords, values): + assert s(x).test_func_proc.x == value -assert s(0.5).test_func_proc.get_a_42(42) == 84 +for x, value in zip(coords, values): + assert s(x).test_func_proc.x_plus_a(100.0) == 100.0 + value diff --git a/test/usecases/func_proc_pnt/func_proc_pnt.mod b/test/usecases/func_proc_pnt/func_proc_pnt.mod index b97ccd03a0..c39f846fb1 100644 --- a/test/usecases/func_proc_pnt/func_proc_pnt.mod +++ b/test/usecases/func_proc_pnt/func_proc_pnt.mod @@ -15,6 +15,6 @@ PROCEDURE set_x_a(a) { x = a } -FUNCTION get_a_42(a) { - get_a_42 = a + 42 +FUNCTION x_plus_a(a) { + x_plus_a = x + a } diff --git a/test/usecases/func_proc_pnt/simulate.py b/test/usecases/func_proc_pnt/simulate.py index 41c22b4601..20d6760062 100644 --- a/test/usecases/func_proc_pnt/simulate.py +++ b/test/usecases/func_proc_pnt/simulate.py @@ -1,15 +1,27 @@ from neuron import h +nseg = 5 s = h.Section() +s.nseg = nseg -pnt_proc = h.test_func_proc_pnt(s(0.5)) +point_processes = [] +for k in range(nseg): + x = (0.5 + k) * 1.0 / nseg + point_processes.append(h.test_func_proc_pnt(s(x))) -pnt_proc.set_x_42() +for k in range(nseg): + point_processes[k].set_x_42() -assert pnt_proc.x == 42 +for k in range(nseg): + assert point_processes[k].x == 42 -pnt_proc.set_x_a(13.7) +for k in range(nseg): + value = 0.1 + k + point_processes[k].set_x_a(value) -assert pnt_proc.x == 13.7 +for k in range(nseg): + value = 0.1 + k + assert point_processes[k].x == value + assert point_processes[k].x_plus_a(1000.0) == 1000.0 + value -assert pnt_proc.get_a_42(42) == 84 +print([point_processes[k].x for k in range(nseg)]) diff --git a/test/usecases/references b/test/usecases/references index 86ea3be285..25e2d91dea 160000 --- a/test/usecases/references +++ b/test/usecases/references @@ -1 +1 @@ -Subproject commit 86ea3be28505f69fe6073498fc995c61f493326d +Subproject commit 25e2d91deabe4115ada0edb91b99e27416c3ff7c From e8abe2ad857aedf40423ad0671de59407b9bd889 Mon Sep 17 00:00:00 2001 From: JCGoran Date: Wed, 28 Feb 2024 13:07:49 +0100 Subject: [PATCH 09/33] Update docs/generate_docs.sh Co-authored-by: Luc Grosheintz --- docs/generate_docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 41a4783e22..01f1e57f99 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -4,7 +4,7 @@ # note that the NMODL Python wheel must be installed # for the script to work properly -set -xe +set -xeu # the abs dir where this script is located (so we can call it from wherever) script_dir="$(realpath "$(dirname "$0")")" From fbf9de61d02b252a1c8da54ef3c7e98175920cdf Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 28 Feb 2024 14:53:49 +0100 Subject: [PATCH 10/33] Pass inst when passing id. (#1184) For functions that are meant to be called "in a loop", i.e. function which accept `id`, we also pass `inst`. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 6 +++--- test/usecases/references | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 6f06aada85..c3ed7567d1 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -211,8 +211,6 @@ void CodegenNeuronCppVisitor::print_function_or_procedure(const ast::Block& node printer->add_text(" "); printer->push_block(); - printer->fmt_line("auto inst = make_instance_{}(*_ml);", info.mod_suffix); - // function requires return variable declaration if (node.is_function_block()) { auto type = default_float_data_type(); @@ -328,6 +326,7 @@ void CodegenNeuronCppVisitor::print_hoc_py_wrapper_function_body( _nt = nrn_threads; )CODE"); } + printer->fmt_line("auto inst = make_instance_{}(_ml_real);", info.mod_suffix); if (info.function_uses_table(block_name)) { printer->fmt_line("_check_{}({})", block_name, internal_method_arguments()); } @@ -376,13 +375,14 @@ void CodegenNeuronCppVisitor::print_hoc_py_wrapper_function_definitions() { std::string CodegenNeuronCppVisitor::internal_method_arguments() { - return "_ml, id, _ppvar, _thread, _nt"; + return "_ml, inst, id, _ppvar, _thread, _nt"; } CodegenNeuronCppVisitor::ParamVector CodegenNeuronCppVisitor::internal_method_parameters() { ParamVector params; params.emplace_back("", "_nrn_mechanism_cache_range*", "", "_ml"); + params.emplace_back("", fmt::format("{}&", instance_struct()), "", "inst"); params.emplace_back("", "size_t", "", "id"); params.emplace_back("", "Datum*", "", "_ppvar"); params.emplace_back("", "Datum*", "", "_thread"); diff --git a/test/usecases/references b/test/usecases/references index 25e2d91dea..e508c4bb21 160000 --- a/test/usecases/references +++ b/test/usecases/references @@ -1 +1 @@ -Subproject commit 25e2d91deabe4115ada0edb91b99e27416c3ff7c +Subproject commit e508c4bb21af8ee5f962ad33b0c101d21f8cd8df From 31a9bc260fd658e74c80401de868f5e90a968be0 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 29 Feb 2024 09:19:09 +0100 Subject: [PATCH 11/33] Document cable equations. (#1175) Starts write up of the underlying equations as needed in NMODL. --- docs/contents/cable_equations.rst | 97 ++++++ docs/images/cable-eqn_circuit.svg | 544 ++++++++++++++++++++++++++++++ docs/images/cable-eqn_nodes.svg | 385 +++++++++++++++++++++ docs/index.rst | 1 + 4 files changed, 1027 insertions(+) create mode 100644 docs/contents/cable_equations.rst create mode 100644 docs/images/cable-eqn_circuit.svg create mode 100644 docs/images/cable-eqn_nodes.svg diff --git a/docs/contents/cable_equations.rst b/docs/contents/cable_equations.rst new file mode 100644 index 0000000000..2b192e6100 --- /dev/null +++ b/docs/contents/cable_equations.rst @@ -0,0 +1,97 @@ +Cable Equation +============== + +.. note:: + + NEURON has a sophisticated system for allowing users to describe the + geometry of neurons. Here we'll try to derive the equations in a manner that + hides those details whenever they're not relevant to NMODL. Please consult + its geometry related documentation or one of its publications, e.g. `The + NEURON Simulation Environment`_. + +.. _The NEURON Simulation Environment: https://doi.org/10.1162/neco.1997.9.6.1179 + +In order to derive the `cable equations` we model a neuron as an electrical +circuit. We first pick points along the neuron at which we model the voltage. +We'll call them nodes and connect the nodes to form a graph. At every branch +point we place a node, see Figure 1. + +.. figure:: ../images/cable-eqn_nodes.svg + + Figure 1: Illustration of the placement of node along a neurite. + +Two adjacent nodes are connected by a resistor. The interesting behaviour comes +from a difference in ion concentrations across the membrane. This difference is +upheld by three processes: a) the membrane which is largely impermeable to +ions, effectively creating a barrier for ions; b) (voltage-gated) ion channels +that conditionally allow ions to quickly cross the membrane; and c) ion pumps +which continuously pump ions across the membrane to restore a resting state. + +The fact that the membrane is (mostly) impermeable to ions means that it +behaves like a dielectric material and can therefore be modeled by a capacitor. +The ion pumps and channels we simply model by a current :math:`I`. + +This model gives rise to the circuit shown in Figure 2. + +.. figure:: ../images/cable-eqn_circuit.svg + + Figure 2: Illustration of the circuit near one node. The total trans-membrane + current is :math:`I_M`, the current due to the dielectric property of the + membrane is :math:`I_C`, and all mechanism specific currents are represented + by :math:`I`. + +We can start writing down equations. Let's recall the formula for a capacitor +and Ohm's Law: + +.. math:: + + I = C \frac{dV}{dt}, \qquad + \Delta V = R I + +Using Kirchoff's Law we can write down two equations for the trans-membrane +current: + +.. math:: + + I_M &= I_C + I(V_1) \\ + I_{0,1} &= I_{1, 2} + I_M + +which leads to + +.. math:: + + I_C + I = I_{0,1} - I_{1, 2} \\ + I_C + I_{1,2} - I_{0, 1} = -I + +which can be rewritten in terms of the voltage as follows: + +.. math:: + + C \frac{dV_1}{dt} + R_{1,2}^{-1} (V_{2} - V{1}) - R_{0,1}^{-1} (V_{1} - V_{0}) = - I(V_1) + +This can be discretized by implicit Euler: + +.. math:: + + C \frac{V_1^{n+1} - V_1^{n}}{\Delta t} + R_{1,2}^{-1} \left(V_{2}^{n+1} - V_{1}^{n+1}\right) - R_{0,1}^{-1} \left(V_{1}^{n+1} - V_{0}^{n+1}\right) = - I(V_1^{n+1}) + +We collect terms as follows: + +.. math:: + + R_{0,1}^{-1} V_{0}^{n+1} + + \left(\frac{C}{\Delta t} + R_{0,1}^{-1} - R_{1,2}^{-1}\right) V_1^{n+1} + + R_{1,2}^{-1} V_{2}^{n+1} + = \frac{C}{\Delta t} V_1^{n} - I(V_1^{n+1}) + +The unpleasant term is :math:`I(V_1^{n+1})` since it makes the system non-linear. +Therefore, it's linearized as follows: + +.. math:: + + I(V_1^{n+1}) + &\approx I_1^{n} + \left(V^{n+1} - V^{n}\right) \frac{dI_1}{dV_1} \\ + &=: I_1^{n} + \left(V^{n+1} - V^{n}\right) g_i^{n} + +where :math:`g_i^{n}` is the mechanism dependent (differential) conductance. + diff --git a/docs/images/cable-eqn_circuit.svg b/docs/images/cable-eqn_circuit.svg new file mode 100644 index 0000000000..83415be5d9 --- /dev/null +++ b/docs/images/cable-eqn_circuit.svg @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/cable-eqn_nodes.svg b/docs/images/cable-eqn_nodes.svg new file mode 100644 index 0000000000..2736930961 --- /dev/null +++ b/docs/images/cable-eqn_nodes.svg @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + V1 + V0 + V2 + V3 + V4 + V5 + V6 + V7 + V8 + V9 + V10 + V11 + V12 + V13 + + diff --git a/docs/index.rst b/docs/index.rst index 33a6f992c6..b9c49d4586 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,6 +22,7 @@ About NMODL contents/currents contents/ions contents/pointers + contents/cable_equations .. toctree:: :maxdepth: 3 From ee517e4b282dc54cf6cbd5a2b9d65dd616a7ba89 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 29 Feb 2024 11:08:15 +0100 Subject: [PATCH 12/33] Implement NONSPECIFIC_CURRENT. (#1185) This commits adds a test for NONSPECIFIC_CURRENT and implements the codegen for NEURON required to pass the test. It does not set the conductances. --- src/codegen/codegen_cpp_visitor.hpp | 7 + src/codegen/codegen_neuron_cpp_visitor.cpp | 289 ++++++++++++++---- src/codegen/codegen_neuron_cpp_visitor.hpp | 14 + test/usecases/CMakeLists.txt | 3 +- .../usecases/nonspecific_current/leonhard.mod | 16 + test/usecases/nonspecific_current/simulate.py | 29 ++ test/usecases/references | 2 +- 7 files changed, 305 insertions(+), 55 deletions(-) create mode 100644 test/usecases/nonspecific_current/leonhard.mod create mode 100644 test/usecases/nonspecific_current/simulate.py diff --git a/src/codegen/codegen_cpp_visitor.hpp b/src/codegen/codegen_cpp_visitor.hpp index 671af52e84..19883cc2e7 100644 --- a/src/codegen/codegen_cpp_visitor.hpp +++ b/src/codegen/codegen_cpp_visitor.hpp @@ -371,6 +371,13 @@ class CodegenCppVisitor: public visitor::ConstAstVisitor { return fmt::format("{}_Instance", info.mod_suffix); } + /** + * Name of structure that wraps node variables + */ + std::string node_data_struct() const { + return fmt::format("{}_NodeData", info.mod_suffix); + } + /** * Name of structure that wraps global variables diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index c3ed7567d1..64ba56dbae 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -919,50 +919,6 @@ void CodegenNeuronCppVisitor::print_global_variables_for_hoc() { } } -void CodegenNeuronCppVisitor::print_make_instance() const { - printer->add_newline(2); - printer->fmt_push_block("static {} make_instance_{}(_nrn_mechanism_cache_range& _ml)", - instance_struct(), - info.mod_suffix); - printer->fmt_push_block("return {}", instance_struct()); - - std::vector make_instance_args; - - const auto codegen_float_variables_size = codegen_float_variables.size(); - for (int i = 0; i < codegen_float_variables_size; ++i) { - const auto& float_var = codegen_float_variables[i]; - if (float_var->is_array()) { - make_instance_args.push_back( - fmt::format("_ml.template data_array_ptr<{}, {}>()", i, float_var->get_length())); - } else { - make_instance_args.push_back(fmt::format("_ml.template fpfield_ptr<{}>()", i)); - } - } - - const auto codegen_int_variables_size = codegen_int_variables.size(); - for (size_t i = 0; i < codegen_int_variables_size; ++i) { - const auto& var = codegen_int_variables[i]; - auto name = var.symbol->get_name(); - auto const variable = [&var, i]() -> std::string { - if (var.is_index || var.is_integer) { - return ""; - } else if (var.is_vdata) { - return ""; - } else { - return fmt::format("_ml.template dptr_field_ptr<{}>()", i); - } - }(); - if (variable != "") { - make_instance_args.push_back(variable); - } - } - - printer->add_multi_line(fmt::format("{}", fmt::join(make_instance_args, ",\n"))); - - printer->pop_block(";"); - printer->pop_block(); -} - void CodegenNeuronCppVisitor::print_mechanism_register() { /// TODO: Write this according to NEURON printer->add_newline(2); @@ -1136,6 +1092,83 @@ void CodegenNeuronCppVisitor::print_mechanism_range_var_structure(bool print_ini printer->pop_block(";"); } +void CodegenNeuronCppVisitor::print_make_instance() const { + printer->add_newline(2); + printer->fmt_push_block("static {} make_instance_{}(_nrn_mechanism_cache_range& _ml)", + instance_struct(), + info.mod_suffix); + printer->fmt_push_block("return {}", instance_struct()); + + std::vector make_instance_args; + + const auto codegen_float_variables_size = codegen_float_variables.size(); + for (int i = 0; i < codegen_float_variables_size; ++i) { + const auto& float_var = codegen_float_variables[i]; + if (float_var->is_array()) { + make_instance_args.push_back( + fmt::format("_ml.template data_array_ptr<{}, {}>()", i, float_var->get_length())); + } else { + make_instance_args.push_back(fmt::format("_ml.template fpfield_ptr<{}>()", i)); + } + } + + const auto codegen_int_variables_size = codegen_int_variables.size(); + for (size_t i = 0; i < codegen_int_variables_size; ++i) { + const auto& var = codegen_int_variables[i]; + auto name = var.symbol->get_name(); + auto const variable = [&var, i]() -> std::string { + if (var.is_index || var.is_integer) { + return ""; + } else if (var.is_vdata) { + return ""; + } else { + return fmt::format("_ml.template dptr_field_ptr<{}>()", i); + } + }(); + if (variable != "") { + make_instance_args.push_back(variable); + } + } + + printer->add_multi_line(fmt::format("{}", fmt::join(make_instance_args, ",\n"))); + + printer->pop_block(";"); + printer->pop_block(); +} + +void CodegenNeuronCppVisitor::print_node_data_structure(bool print_initializers) { + auto const value_initialize = print_initializers ? "{}" : ""; + printer->add_newline(2); + printer->fmt_push_block("struct {} ", node_data_struct()); + + // Pointers to node variables + printer->add_line("int const * nodeindices;"); + printer->add_line("double const * node_voltages;"); + printer->add_line("double * node_rhs;"); + printer->add_line("int nodecount;"); + + printer->pop_block(";"); +} + +void CodegenNeuronCppVisitor::print_make_node_data() const { + printer->add_newline(2); + printer->fmt_push_block("static {} make_node_data_{}(NrnThread& _nt, Memb_list& _ml_arg)", + node_data_struct(), + info.mod_suffix); + + std::vector make_node_data_args; + make_node_data_args.push_back("_ml_arg.nodeindices"); + make_node_data_args.push_back("_nt.node_voltage_storage()"); + make_node_data_args.push_back("_nt.node_rhs_storage()"); + make_node_data_args.push_back("_ml_arg.nodecount"); + + printer->fmt_push_block("return {}", node_data_struct()); + printer->add_multi_line(fmt::format("{}", fmt::join(make_node_data_args, ",\n"))); + + printer->pop_block(";"); + printer->pop_block(); +} + void CodegenNeuronCppVisitor::print_initial_block(const InitialBlock* node) { // read ion statements @@ -1169,6 +1202,8 @@ void CodegenNeuronCppVisitor::print_global_function_common_code(BlockType type, printer->add_line("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};"); printer->fmt_line("auto inst = make_instance_{}(_lmr);", info.mod_suffix); + printer->fmt_line("auto node_data = make_node_data_{}(*_nt, *_ml_arg);", info.mod_suffix); + printer->add_line("auto nodecount = _ml_arg->nodecount;"); } @@ -1353,28 +1388,152 @@ void CodegenNeuronCppVisitor::print_nrn_state() { /* Print nrn_cur related routines */ /****************************************************************************************/ +std::string CodegenNeuronCppVisitor::nrn_current_arguments() { + if (ion_variable_struct_required()) { + throw std::runtime_error("Not implemented."); + } + return "id, inst, node_data, v"; +} + + +CodegenNeuronCppVisitor::ParamVector CodegenNeuronCppVisitor::nrn_current_parameters() { + if (ion_variable_struct_required()) { + throw std::runtime_error("Not implemented."); + } + + ParamVector params; + params.emplace_back("", "size_t", "", "id"); + params.emplace_back("", fmt::format("{}&", instance_struct()), "", "inst"); + params.emplace_back("", fmt::format("{}&", node_data_struct()), "", "node_data"); + params.emplace_back("", "double", "", "v"); + return params; +} + /// TODO: Edit for NEURON void CodegenNeuronCppVisitor::print_nrn_current(const BreakpointBlock& node) { - return; + const auto& args = nrn_current_parameters(); + const auto& block = node.get_statement_block(); + printer->add_newline(2); + // print_device_method_annotation(); + printer->fmt_push_block("inline double nrn_current_{}({})", + info.mod_suffix, + get_parameter_str(args)); + printer->add_line("double current = 0.0;"); + print_statement_block(*block, false, false); + for (auto& current: info.currents) { + const auto& name = get_variable_name(current); + printer->fmt_line("current += {};", name); + } + printer->add_line("return current;"); + printer->pop_block(); } /// TODO: Edit for NEURON void CodegenNeuronCppVisitor::print_nrn_cur_conductance_kernel(const BreakpointBlock& node) { - return; + const auto& block = node.get_statement_block(); + print_statement_block(*block, false, false); + if (!info.currents.empty()) { + std::string sum; + for (const auto& current: info.currents) { + auto var = breakpoint_current(current); + sum += get_variable_name(var); + if (¤t != &info.currents.back()) { + sum += "+"; + } + } + printer->fmt_line("double rhs = {};", sum); + } + + std::string sum; + for (const auto& conductance: info.conductances) { + auto var = breakpoint_current(conductance.variable); + sum += get_variable_name(var); + if (&conductance != &info.conductances.back()) { + sum += "+"; + } + } + printer->fmt_line("double g = {};", sum); + + for (const auto& conductance: info.conductances) { + if (!conductance.ion.empty()) { + const auto& lhs = std::string(naming::ION_VARNAME_PREFIX) + "di" + conductance.ion + + "dv"; + const auto& rhs = get_variable_name(conductance.variable); + const ShadowUseStatement statement{lhs, "+=", rhs}; + const auto& text = process_shadow_update_statement(statement, BlockType::Equation); + printer->add_line(text); + } + } } /// TODO: Edit for NEURON void CodegenNeuronCppVisitor::print_nrn_cur_non_conductance_kernel() { - return; + printer->fmt_line("double I1 = nrn_current_{}({}+0.001);", + info.mod_suffix, + nrn_current_arguments()); + for (auto& ion: info.ions) { + for (auto& var: ion.writes) { + if (ion.is_ionic_current(var)) { + const auto& name = get_variable_name(var); + printer->fmt_line("double di{} = {};", ion.name, name); + } + } + } + printer->fmt_line("double I0 = nrn_current_{}({});", info.mod_suffix, nrn_current_arguments()); + printer->add_line("double rhs = I0;"); + + printer->add_line("double g = (I1-I0)/0.001;"); + for (auto& ion: info.ions) { + for (auto& var: ion.writes) { + if (ion.is_ionic_current(var)) { + const auto& lhs = std::string(naming::ION_VARNAME_PREFIX) + "di" + ion.name + "dv"; + auto rhs = fmt::format("(di{}-{})/0.001", ion.name, get_variable_name(var)); + if (info.point_process) { + auto area = get_variable_name(naming::NODE_AREA_VARIABLE); + rhs += fmt::format("*1.e2/{}", area); + } + const ShadowUseStatement statement{lhs, "+=", rhs}; + const auto& text = process_shadow_update_statement(statement, BlockType::Equation); + printer->add_line(text); + } + } + } } /// TODO: Edit for NEURON void CodegenNeuronCppVisitor::print_nrn_cur_kernel(const BreakpointBlock& node) { - return; + printer->add_line("int node_id = node_data.nodeindices[id];"); + printer->add_line("double v = node_data.node_voltages[node_id];"); + + const auto& read_statements = ion_read_statements(BlockType::Equation); + for (auto& statement: read_statements) { + printer->add_line(statement); + } + + if (info.conductances.empty()) { + print_nrn_cur_non_conductance_kernel(); + } else { + print_nrn_cur_conductance_kernel(node); + } + + const auto& write_statements = ion_write_statements(BlockType::Equation); + for (auto& statement: write_statements) { + auto text = process_shadow_update_statement(statement, BlockType::Equation); + printer->add_line(text); + } + + if (info.point_process) { + const auto& area = get_variable_name(naming::NODE_AREA_VARIABLE); + printer->fmt_line("double mfactor = 1.e2/{};", area); + printer->add_line("g = g*mfactor;"); + printer->add_line("rhs = rhs*mfactor;"); + } + + // print_g_unused(); } @@ -1390,14 +1549,36 @@ void CodegenNeuronCppVisitor::print_nrn_cur() { return; } + if (info.conductances.empty()) { + print_nrn_current(*info.breakpoint_node); + } + printer->add_newline(2); + printer->add_line("/** update current */"); + print_global_function_common_code(BlockType::Equation); + // print_channel_iteration_block_parallel_hint(BlockType::Equation, info.breakpoint_node); + printer->push_block("for (int id = 0; id < nodecount; id++)"); + print_nrn_cur_kernel(*info.breakpoint_node); + // print_nrn_cur_matrix_shadow_update(); + // if (!nrn_cur_reduction_loop_required()) { + // print_fast_imem_calculation(); + // } - printer->fmt_line( - "void {}(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, Memb_list* _ml_arg, " - "int _type) {{}}", - method_name(naming::NRN_CUR_METHOD)); - /// TODO: Fill in + printer->add_line("node_data.node_rhs[node_id] -= rhs;"); + + + printer->pop_block(); + + // if (nrn_cur_reduction_loop_required()) { + // printer->push_block("for (int id = 0; id < nodecount; id++)"); + // print_nrn_cur_matrix_shadow_reduction(); + // printer->pop_block(); + // print_fast_imem_calculation(); + // } + + // print_kernel_data_present_annotation_block_end(); + printer->pop_block(); } @@ -1482,7 +1663,9 @@ void CodegenNeuronCppVisitor::print_namespace_end() { void CodegenNeuronCppVisitor::print_data_structures(bool print_initializers) { print_mechanism_global_var_structure(print_initializers); print_mechanism_range_var_structure(print_initializers); + print_node_data_structure(print_initializers); print_make_instance(); + print_make_node_data(); } diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index 0d30fa2111..b680431a7b 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -492,6 +492,8 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { /* Print nrn_cur related routines */ /****************************************************************************************/ + std::string nrn_current_arguments(); + ParamVector nrn_current_parameters(); /** * Print the \c nrn_current kernel @@ -598,6 +600,10 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { */ void print_make_instance() const; + /** Print `make_*_node_data`. + */ + void print_make_node_data() const; + /** * Set v_unused (voltage) for NRN_PRCELLSTATE feature */ @@ -655,6 +661,14 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { * be included in the struct declaration. */ void print_mechanism_range_var_structure(bool print_initializers) override; + + /** + * Print the structure that wraps all node variables required for the NMODL. + * + * \param print_initializers Whether or not default values for variables + * be included in the struct declaration. + */ + void print_node_data_structure(bool print_initializers); }; diff --git a/test/usecases/CMakeLists.txt b/test/usecases/CMakeLists.txt index 3f555d9db2..cd204c1153 100644 --- a/test/usecases/CMakeLists.txt +++ b/test/usecases/CMakeLists.txt @@ -5,7 +5,8 @@ set(NMODL_USECASE_DIRS point_process parameter func_proc - func_proc_pnt) + func_proc_pnt + nonspecific_current) file(GLOB NMODL_GOLDEN_REFERENCES "${CMAKE_CURRENT_SOURCE_DIR}/references/*") if(NMODL_GOLDEN_REFERENCES STREQUAL "") diff --git a/test/usecases/nonspecific_current/leonhard.mod b/test/usecases/nonspecific_current/leonhard.mod new file mode 100644 index 0000000000..bec601666b --- /dev/null +++ b/test/usecases/nonspecific_current/leonhard.mod @@ -0,0 +1,16 @@ +UNITS { + (mA) = (milliamp) +} + +NEURON { + SUFFIX leonhard + NONSPECIFIC_CURRENT il +} + +ASSIGNED { + il (mA/cm2) +} + +BREAKPOINT { + il = 0.005 * (v - 1.5) +} diff --git a/test/usecases/nonspecific_current/simulate.py b/test/usecases/nonspecific_current/simulate.py new file mode 100644 index 0000000000..ffa4048322 --- /dev/null +++ b/test/usecases/nonspecific_current/simulate.py @@ -0,0 +1,29 @@ +import numpy as np + +from neuron import h, gui +from neuron.units import ms + +nseg = 1 + +s = h.Section() +s.insert("leonhard") +s.nseg = nseg + +v_hoc = h.Vector().record(s(0.5)._ref_v) +t_hoc = h.Vector().record(h._ref_t) + +h.stdinit() +h.tstop = 5.0 * ms +h.run() + +v = np.array(v_hoc.as_numpy()) +t = np.array(t_hoc.as_numpy()) + +erev = 1.5 +rate = 0.005 / 1e-3 +v0 = -65.0 +v_exact = erev + (v0 - erev)*np.exp(-rate*t) +rel_err = np.abs(v - v_exact) / np.max(np.abs(v_exact)) + +assert np.all(rel_err < 1e-1), f"rel_err = {rel_err}" +print("leonhard: success") diff --git a/test/usecases/references b/test/usecases/references index e508c4bb21..9893f6e7dd 160000 --- a/test/usecases/references +++ b/test/usecases/references @@ -1 +1 @@ -Subproject commit e508c4bb21af8ee5f962ad33b0c101d21f8cd8df +Subproject commit 9893f6e7dd0466ba339281c1b412809e50136f63 From b1afcd0923d6c10f86f86dbbb841a8df289fa0cb Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 28 Feb 2024 17:03:15 +0100 Subject: [PATCH 13/33] Fix doxygen issues when building docs --- docs/generate_docs.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 01f1e57f99..376e318428 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -6,8 +6,13 @@ set -xeu +# in order to create the docs, we first need to build NMODL +build_dir="$(mktemp -d)" +wheel_dir="$(mktemp -d)" +pip wheel . --no-deps --wheel-dir "$(cd "${wheel_dir}"; pwd -P)" -C build-dir="$(cd "${build_dir}"; pwd -P)" + # the abs dir where this script is located (so we can call it from wherever) -script_dir="$(realpath "$(dirname "$0")")" +script_dir="$(cd "$(dirname "$0")"; pwd -P)" cd "${script_dir}" doxygen Doxyfile From f44ffbbdbc21ca61555e1740ca46cb745ae0a080 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 11:29:47 +0100 Subject: [PATCH 14/33] Allow setting a custom build directory for docs --- docs/generate_docs.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 376e318428..51c2c93500 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -7,7 +7,11 @@ set -xeu # in order to create the docs, we first need to build NMODL -build_dir="$(mktemp -d)" +build_dir="${1:-"$(mktemp -d)"}" +if ! [ -d "${build_dir}" ] +then + mkdir -p "${build_dir}" +fi wheel_dir="$(mktemp -d)" pip wheel . --no-deps --wheel-dir "$(cd "${wheel_dir}"; pwd -P)" -C build-dir="$(cd "${build_dir}"; pwd -P)" From bc6d6924c32036f510ddbb6ee69aec3f6a0fd7ab Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 11:35:20 +0100 Subject: [PATCH 15/33] Minor updates to docs --- INSTALL.rst | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/INSTALL.rst b/INSTALL.rst index a37b0474de..7ebbc2dd00 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -127,8 +127,8 @@ to cmake as: -DBISON_EXECUTABLE=/usr/local/opt/bison/bin/bison \ -DCMAKE_INSTALL_PREFIX=$HOME/nmodl -Using Python setuptools -~~~~~~~~~~~~~~~~~~~~~~~ +Using the Python build system +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you are mainly interested in the NMODL Framework parsing and analysis tools and wish to use them from Python, we recommend building and @@ -253,4 +253,15 @@ script: bash docs/generate_docs.sh The documentation will then be available in the ``public`` subdirectory. Note -that the Python package must be installed beforehand using ``pip install .``. +that the above script actually builds NMODL using the Python build system in a +temporary directory; if you wish to make a persistent build directory (to +reduce the build time for instance), you can do so by specifying a custom build +directory: + +.. code:: sh + + bash docs/generate_docs.sh DIRECTORY + +where ``DIRECTORY`` is the directory where you wish to store the output of the +build (if the directory does not exist, the script will attempt to create one +for you). From 3bb39d207212a7ba5159883de74395ff1cb16777 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 29 Feb 2024 13:03:28 +0100 Subject: [PATCH 16/33] Document `nmodl blame`. (#1189) --- CONTRIBUTING.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index c7ad6e594b..e61710636a 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -152,6 +152,15 @@ pull the changes from the main (upstream) repository: Development Conventions ------------------------ +New Lines +~~~~~~~~~ + +When generating/printing code it's important to use ``add_newline`` to +start a new line of code. When printing a string containing multiple lines, +i.e. one that contains a ``"\n"`` one must use ``add_multi_line``. + +It's important that NMODL knows the line number it's currently on. + Formatting ~~~~~~~~~~ @@ -226,3 +235,27 @@ have ``CMake >= 3.15`` and use following cmake option: :: cmake .. -DENABLE_CLANG_TIDY=ON + +Blaming NMODL +~~~~~~~~~~~~~ + +While developing NMODL one may want to know which line of code in NMODL +produced a particular line of code in the generated file, e.g. when faced with +a compiler error such as + +.. code-block:: + + hodhux.cpp:105:26: error: ‘coreneuron’ has not been declared + 105 | double* celsius{&coreneuron::celsius}; + | ^~~~~~~~~~ + +One can find the line by doing: + +.. code-block:: + + $ nmodl hodhux.mod ... blame --line 105 + +which will print a backtrace every time NMODL writes to line 105. While this is +useful for finding the line responsible for printing, i.e. convert AST to C++, +that line it doesn't immediately explain why the AST ended up that way. +Currently, we don't have a tool for the latter. From a689939f545422327ce5b714608abd217534e189 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 13:54:48 +0100 Subject: [PATCH 17/33] Fix docs building again (and maybe for all) --- INSTALL.rst | 8 +++++++- docs/generate_docs.sh | 28 +++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/INSTALL.rst b/INSTALL.rst index 7ebbc2dd00..75de7affbe 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -264,4 +264,10 @@ directory: where ``DIRECTORY`` is the directory where you wish to store the output of the build (if the directory does not exist, the script will attempt to create one -for you). +for you). You can also specify the path to the Python executable, as well as +whether or not to use a virtual env (anything other than the string ``false`` is +considered to be ``true``): + +.. code:: sh + + bash docs/generate_docs.sh DIRECTORY PYTHON_EXECUTABLE false diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 51c2c93500..9bf103ac38 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -1,19 +1,32 @@ #!/usr/bin/env bash # script for generating documentation for NMODL -# note that the NMODL Python wheel must be installed -# for the script to work properly set -xeu -# in order to create the docs, we first need to build NMODL +# in order to create the docs, we first need to build NMODL in some dir build_dir="${1:-"$(mktemp -d)"}" if ! [ -d "${build_dir}" ] then mkdir -p "${build_dir}" fi -wheel_dir="$(mktemp -d)" -pip wheel . --no-deps --wheel-dir "$(cd "${wheel_dir}"; pwd -P)" -C build-dir="$(cd "${build_dir}"; pwd -P)" + +# the Python executable to use (default: whatever `python3` is) +python_exe="${2:-"$(command -v python3)"}" + +# should we use a separate venv? +use_venv="${3:-}" + +if [ "${use_venv}" != "false" ] +then + venv_name="$(mktemp -d)" + $(command -v python3) -m venv "${venv_name}" + . "${venv_name}/bin/activate" + python_exe="$(command -v python)" +else + python_exe="$(command -v python3)" +fi +${python_exe} -m pip install ".[docs]" -C build-dir="$(cd "${build_dir}"; pwd -P)" # the abs dir where this script is located (so we can call it from wherever) script_dir="$(cd "$(dirname "$0")"; pwd -P)" @@ -22,3 +35,8 @@ cd "${script_dir}" doxygen Doxyfile sphinx-build . "${script_dir}/../public" cd - + +if [ "${use_venv}" != "false" ] +then + deactivate +fi From 7c5be89ee9f140a27baf5ff3fbc61e42c377d240 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 14:31:23 +0100 Subject: [PATCH 18/33] Fix docs CI to match changes --- .github/workflows/nmodl-doc.yml | 17 +++++++---------- docs/generate_docs.sh | 1 + 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/nmodl-doc.yml b/.github/workflows/nmodl-doc.yml index 7e7d2f1bf1..33df5fe48b 100644 --- a/.github/workflows/nmodl-doc.yml +++ b/.github/workflows/nmodl-doc.yml @@ -61,27 +61,24 @@ jobs: pip3 install -U pip setuptools 'pip-tools>=7.4.0' pip3 install --user -r <(pip-compile --all-build-deps --all-extras --no-strip-extras 2>&1) - # This step will set up an SSH connection on tmate.io for live debugging. - # To trigger it, simply add 'live-debug-docs' to your last pushed commit message. - - name: live debug session on failure - if: failure() && contains(github.event.head_commit.message, 'live-debug-docs') - uses: mxschmitt/action-tmate@v3 - - name: Documentation id: documentation working-directory: ${{runner.workspace}}/nmodl run: | echo "------- Build Documentation -------"; - # build wheel and install it - pip wheel . --wheel-dir wheelhouse/ -C build-dir=_build --no-deps - pip install wheelhouse/*.whl - bash docs/generate_docs.sh + bash docs/generate_docs.sh _build $(command -v python${PYTHON_VERSION}) touch public/.nojekyll echo "" > public/index.html; echo "status=done" >> $GITHUB_OUTPUT env: CCACHE_DIR: ${{runner.workspace}}/ccache + # This step will set up an SSH connection on tmate.io for live debugging. + # To trigger it, simply add 'live-debug-docs' to your last pushed commit message. + - name: live debug session on failure + if: failure() && contains(github.event.head_commit.message, 'live-debug-docs') + uses: mxschmitt/action-tmate@v3 + - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@v4 if: steps.documentation.outputs.status == 'done' && startsWith(github.ref, 'refs/heads/master') diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 9bf103ac38..e904367e33 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -23,6 +23,7 @@ then $(command -v python3) -m venv "${venv_name}" . "${venv_name}/bin/activate" python_exe="$(command -v python)" + ${python_exe} -m pip install -U pip else python_exe="$(command -v python3)" fi From f2fbb2ec568ab588c7d99c7e343a5ec62ffddda8 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 15:03:08 +0100 Subject: [PATCH 19/33] Fix no effect statement in docs gen --- docs/generate_docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index e904367e33..283722c8b2 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -20,7 +20,7 @@ use_venv="${3:-}" if [ "${use_venv}" != "false" ] then venv_name="$(mktemp -d)" - $(command -v python3) -m venv "${venv_name}" + ${python_exe} -m venv "${venv_name}" . "${venv_name}/bin/activate" python_exe="$(command -v python)" ${python_exe} -m pip install -U pip From 9373afbd8a304cd0efb764e3542ca6083a20d6d5 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 15:43:31 +0100 Subject: [PATCH 20/33] Fix `change_name.py` script --- packaging/change_name.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packaging/change_name.py b/packaging/change_name.py index f3c453dc56..f54846c14a 100755 --- a/packaging/change_name.py +++ b/packaging/change_name.py @@ -2,10 +2,6 @@ """ Barebones utility for changing the name of the package in `pyproject.toml`. -Usage ------ -[SCRIPT] [PYPROJECT_FILE] [NAME] - Notes ----- Should only be used by the CI @@ -19,7 +15,9 @@ def main(): - parser = ArgumentParser() + parser = ArgumentParser( + description="Script for changing the name of a project in a pyproject.toml file", + ) parser.add_argument("pyproject_file", help="The path to the pyproject.toml file") parser.add_argument("name", help="The new name of the project") args = parser.parse_args() From 23bee8915ab62f137ebb7f09659216434550d16c Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 29 Feb 2024 15:43:43 +0100 Subject: [PATCH 21/33] Leave in the `nmodl.hpp` header --- src/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 614ed9f673..7a81895ff3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,6 +49,4 @@ endif() # Install executable # ============================================================================= install(TARGETS nmodl DESTINATION ${NMODL_INSTALL_DIR_SUFFIX}bin) -if(NOT NMODL_BUILD_WHEEL) - install(FILES nmodl.hpp DESTINATION ${NMODL_INSTALL_DIR_SUFFIX}include) -endif() +install(FILES nmodl.hpp DESTINATION ${NMODL_INSTALL_DIR_SUFFIX}include) From 1ef357f16462d0867401c3903bbedd27287651fa Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 09:29:50 +0100 Subject: [PATCH 22/33] Refactor generation of docs --- docs/generate_docs.sh | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 283722c8b2..335ec96518 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -2,21 +2,28 @@ # script for generating documentation for NMODL -set -xeu +set -eu -# in order to create the docs, we first need to build NMODL in some dir -build_dir="${1:-"$(mktemp -d)"}" -if ! [ -d "${build_dir}" ] +if [ $# -lt 2 ] then - mkdir -p "${build_dir}" + echo "Usage: $(basename "$0") output_dir python_exe [use_virtual_env]" + exit 1 fi -# the Python executable to use (default: whatever `python3` is) -python_exe="${2:-"$(command -v python3)"}" - -# should we use a separate venv? +# the dir where we put the temporary build and the docs +output_dir="$1" +# path to the Python executable +python_exe="$2" use_venv="${3:-}" +if ! [ -d "${output_dir}" ] +then + mkdir -p "${output_dir}" +fi + +echo "== Building documentation files in: ${output_dir}/_docs ==" +echo "== Temporary project build directory is: ${output_dir}/_build ==" + if [ "${use_venv}" != "false" ] then venv_name="$(mktemp -d)" @@ -24,18 +31,16 @@ then . "${venv_name}/bin/activate" python_exe="$(command -v python)" ${python_exe} -m pip install -U pip -else - python_exe="$(command -v python3)" fi -${python_exe} -m pip install ".[docs]" -C build-dir="$(cd "${build_dir}"; pwd -P)" +${python_exe} -m pip install ".[docs]" -C build-dir="${output_dir}/_build" # the abs dir where this script is located (so we can call it from wherever) script_dir="$(cd "$(dirname "$0")"; pwd -P)" cd "${script_dir}" doxygen Doxyfile -sphinx-build . "${script_dir}/../public" cd - +sphinx-build docs/ "${output_dir}/_docs" if [ "${use_venv}" != "false" ] then From 23354035f6a05f61d2dbbc23ab63fcc90584e97d Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 09:32:52 +0100 Subject: [PATCH 23/33] Update docs CI --- .github/workflows/nmodl-doc.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nmodl-doc.yml b/.github/workflows/nmodl-doc.yml index 33df5fe48b..41c5bd13a9 100644 --- a/.github/workflows/nmodl-doc.yml +++ b/.github/workflows/nmodl-doc.yml @@ -66,9 +66,9 @@ jobs: working-directory: ${{runner.workspace}}/nmodl run: | echo "------- Build Documentation -------"; - bash docs/generate_docs.sh _build $(command -v python${PYTHON_VERSION}) - touch public/.nojekyll - echo "" > public/index.html; + bash docs/generate_docs.sh public $(command -v python${PYTHON_VERSION}) false + touch public/_docs/.nojekyll + echo "" > public/_docs/index.html echo "status=done" >> $GITHUB_OUTPUT env: CCACHE_DIR: ${{runner.workspace}}/ccache @@ -84,5 +84,5 @@ jobs: if: steps.documentation.outputs.status == 'done' && startsWith(github.ref, 'refs/heads/master') with: branch: gh-pages # The branch the action should deploy to. - folder: ${{runner.workspace}}/nmodl/public + folder: ${{runner.workspace}}/nmodl/public/_docs clean: false # Automatically remove deleted files from the deploy branch From 5931038d208c1fe097b2048bef40af9ad180fc0a Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 09:35:53 +0100 Subject: [PATCH 24/33] Put back the version --- nmodl/__init__.py | 8 +------- src/pybind/pynmodl.cpp | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/nmodl/__init__.py b/nmodl/__init__.py index 781d12faa4..c494b042cf 100644 --- a/nmodl/__init__.py +++ b/nmodl/__init__.py @@ -35,13 +35,7 @@ try: # Try importing but catch exception in case bindings are not available - from ._nmodl import NmodlDriver, to_json, to_nmodl # noqa - - try: - __version__ = version("nmodl") - except PackageNotFoundError: - # package is not installed - pass + from ._nmodl import NmodlDriver, to_json, to_nmodl, __version__ # noqa __all__ = ["NmodlDriver", "to_json", "to_nmodl"] except ImportError: diff --git a/src/pybind/pynmodl.cpp b/src/pybind/pynmodl.cpp index b4a8b80a0e..bb58f3fc77 100644 --- a/src/pybind/pynmodl.cpp +++ b/src/pybind/pynmodl.cpp @@ -138,6 +138,7 @@ void init_symtab_module(py::module& m); PYBIND11_MODULE(_nmodl, m_nmodl) { m_nmodl.doc() = "NMODL : Source-to-Source Code Generation Framework"; + m_nmodl.attr("__version__") = nmodl::Version::NMODL_VERSION; py::class_ _{m_nmodl, "nmodl::parser::NmodlDriver"}; py::class_ nmodl_driver( From 859ee448e654475aba7acc75cd2fb3c9d012ce39 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 09:41:29 +0100 Subject: [PATCH 25/33] Update INSTALL.rst --- INSTALL.rst | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/INSTALL.rst b/INSTALL.rst index 75de7affbe..708491b2df 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -250,24 +250,11 @@ script: .. code:: sh - bash docs/generate_docs.sh - -The documentation will then be available in the ``public`` subdirectory. Note -that the above script actually builds NMODL using the Python build system in a -temporary directory; if you wish to make a persistent build directory (to -reduce the build time for instance), you can do so by specifying a custom build -directory: - -.. code:: sh - - bash docs/generate_docs.sh DIRECTORY - -where ``DIRECTORY`` is the directory where you wish to store the output of the -build (if the directory does not exist, the script will attempt to create one -for you). You can also specify the path to the Python executable, as well as -whether or not to use a virtual env (anything other than the string ``false`` is -considered to be ``true``): - -.. code:: sh - - bash docs/generate_docs.sh DIRECTORY PYTHON_EXECUTABLE false + bash docs/generate_docs.sh DIRECTORY PYTHON_EXECUTABLE [use_virtual_env] + +where ``DIRECTORY`` is where you want to put the output files. The HTML +documentation will then be available in ``DIRECTORY/_docs``, and the temporary +build will be stored in ``DIRECTORY/_build``. You can also specify that you do +not want to use a virtual environment by optionally passing ``false`` as the +third argument above (if not specified, the script first creates a temporary +env). From 8ad9f0fc2ffcd59a6523f3d6bfa1b4adb27fda58 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 09:51:57 +0100 Subject: [PATCH 26/33] Save valuable time and keystrokes by not using underscores --- .github/workflows/nmodl-doc.yml | 6 +++--- INSTALL.rst | 4 ++-- docs/generate_docs.sh | 11 +++++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/nmodl-doc.yml b/.github/workflows/nmodl-doc.yml index 41c5bd13a9..cbeefba372 100644 --- a/.github/workflows/nmodl-doc.yml +++ b/.github/workflows/nmodl-doc.yml @@ -67,8 +67,8 @@ jobs: run: | echo "------- Build Documentation -------"; bash docs/generate_docs.sh public $(command -v python${PYTHON_VERSION}) false - touch public/_docs/.nojekyll - echo "" > public/_docs/index.html + touch public/docs/.nojekyll + echo "" > public/docs/index.html echo "status=done" >> $GITHUB_OUTPUT env: CCACHE_DIR: ${{runner.workspace}}/ccache @@ -84,5 +84,5 @@ jobs: if: steps.documentation.outputs.status == 'done' && startsWith(github.ref, 'refs/heads/master') with: branch: gh-pages # The branch the action should deploy to. - folder: ${{runner.workspace}}/nmodl/public/_docs + folder: ${{runner.workspace}}/nmodl/public/docs clean: false # Automatically remove deleted files from the deploy branch diff --git a/INSTALL.rst b/INSTALL.rst index 708491b2df..c0a6f2c118 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -253,8 +253,8 @@ script: bash docs/generate_docs.sh DIRECTORY PYTHON_EXECUTABLE [use_virtual_env] where ``DIRECTORY`` is where you want to put the output files. The HTML -documentation will then be available in ``DIRECTORY/_docs``, and the temporary -build will be stored in ``DIRECTORY/_build``. You can also specify that you do +documentation will then be available in ``DIRECTORY/docs``, and the temporary +build will be stored in ``DIRECTORY/build``. You can also specify that you do not want to use a virtual environment by optionally passing ``false`` as the third argument above (if not specified, the script first creates a temporary env). diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 335ec96518..807f585f81 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -21,8 +21,11 @@ then mkdir -p "${output_dir}" fi -echo "== Building documentation files in: ${output_dir}/_docs ==" -echo "== Temporary project build directory is: ${output_dir}/_build ==" +build_dir="build" +docs_dir="docs" + +echo "== Building documentation files in: ${output_dir}/${docs_dir} ==" +echo "== Temporary project build directory is: ${output_dir}/${build_dir} ==" if [ "${use_venv}" != "false" ] then @@ -32,7 +35,7 @@ then python_exe="$(command -v python)" ${python_exe} -m pip install -U pip fi -${python_exe} -m pip install ".[docs]" -C build-dir="${output_dir}/_build" +${python_exe} -m pip install ".[docs]" -C build-dir="${output_dir}/${build_dir}" # the abs dir where this script is located (so we can call it from wherever) script_dir="$(cd "$(dirname "$0")"; pwd -P)" @@ -40,7 +43,7 @@ script_dir="$(cd "$(dirname "$0")"; pwd -P)" cd "${script_dir}" doxygen Doxyfile cd - -sphinx-build docs/ "${output_dir}/_docs" +sphinx-build docs/ "${output_dir}/${docs_dir}" if [ "${use_venv}" != "false" ] then From 2cc77338d972f94f9b6e0007b24770461e7b8dd9 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 10:35:20 +0100 Subject: [PATCH 27/33] Remove comment --- packaging/change_name.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packaging/change_name.py b/packaging/change_name.py index f54846c14a..478eb30c35 100755 --- a/packaging/change_name.py +++ b/packaging/change_name.py @@ -1,10 +1,6 @@ #!/usr/bin/env python3 """ Barebones utility for changing the name of the package in `pyproject.toml`. - -Notes ------ -Should only be used by the CI """ import re from argparse import ArgumentParser From e07a6d22af0740fd6492110896386ce221db3b8d Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 11:41:53 +0100 Subject: [PATCH 28/33] Update docgen --- docs/generate_docs.sh | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh index 807f585f81..c0a756d326 100755 --- a/docs/generate_docs.sh +++ b/docs/generate_docs.sh @@ -4,17 +4,16 @@ set -eu -if [ $# -lt 2 ] +if [ $# -lt 1 ] then - echo "Usage: $(basename "$0") output_dir python_exe [use_virtual_env]" + echo "Usage: $(basename "$0") output_dir [python_exe]" exit 1 fi # the dir where we put the temporary build and the docs output_dir="$1" # path to the Python executable -python_exe="$2" -use_venv="${3:-}" +python_exe="${2:-"$(command -v python3)"}" if ! [ -d "${output_dir}" ] then @@ -27,14 +26,11 @@ docs_dir="docs" echo "== Building documentation files in: ${output_dir}/${docs_dir} ==" echo "== Temporary project build directory is: ${output_dir}/${build_dir} ==" -if [ "${use_venv}" != "false" ] -then - venv_name="$(mktemp -d)" - ${python_exe} -m venv "${venv_name}" - . "${venv_name}/bin/activate" - python_exe="$(command -v python)" - ${python_exe} -m pip install -U pip -fi +venv_name="${output_dir}/env" +${python_exe} -m venv "${venv_name}" +. "${venv_name}/bin/activate" +python_exe="$(command -v python)" +${python_exe} -m pip install -U pip ${python_exe} -m pip install ".[docs]" -C build-dir="${output_dir}/${build_dir}" # the abs dir where this script is located (so we can call it from wherever) @@ -45,7 +41,4 @@ doxygen Doxyfile cd - sphinx-build docs/ "${output_dir}/${docs_dir}" -if [ "${use_venv}" != "false" ] -then - deactivate -fi +deactivate From d93760e6ca73b923dd63bb1ab2bf67a09268c210 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 11:46:31 +0100 Subject: [PATCH 29/33] Update dosc --- INSTALL.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/INSTALL.rst b/INSTALL.rst index c0a6f2c118..3d3ce529db 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -250,11 +250,9 @@ script: .. code:: sh - bash docs/generate_docs.sh DIRECTORY PYTHON_EXECUTABLE [use_virtual_env] + bash docs/generate_docs.sh DIRECTORY [PYTHON_EXECUTABLE] where ``DIRECTORY`` is where you want to put the output files. The HTML documentation will then be available in ``DIRECTORY/docs``, and the temporary -build will be stored in ``DIRECTORY/build``. You can also specify that you do -not want to use a virtual environment by optionally passing ``false`` as the -third argument above (if not specified, the script first creates a temporary -env). +build will be stored in ``DIRECTORY/build``. You can also specify the path to +the Python executable if it is not picked up automatically. From c21722caa6976ef2c0f5f873932635deac37b857 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 11:49:03 +0100 Subject: [PATCH 30/33] Update CI --- .github/workflows/nmodl-doc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nmodl-doc.yml b/.github/workflows/nmodl-doc.yml index cbeefba372..8053257d36 100644 --- a/.github/workflows/nmodl-doc.yml +++ b/.github/workflows/nmodl-doc.yml @@ -66,7 +66,7 @@ jobs: working-directory: ${{runner.workspace}}/nmodl run: | echo "------- Build Documentation -------"; - bash docs/generate_docs.sh public $(command -v python${PYTHON_VERSION}) false + bash docs/generate_docs.sh public $(command -v python${PYTHON_VERSION}) touch public/docs/.nojekyll echo "" > public/docs/index.html echo "status=done" >> $GITHUB_OUTPUT From 85a4906f3458f29843ba57381a946aa4fccefdb1 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Fri, 1 Mar 2024 13:38:36 +0100 Subject: [PATCH 31/33] Don't install fmt and backward. (#1193) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0053fd90db..4b628c4d3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ endif() cpp_cc_git_submodule(eigen) # We could have fmt incoming from NEURON if(NOT TARGET fmt) - cpp_cc_git_submodule(fmt BUILD PACKAGE fmt REQUIRED) + cpp_cc_git_submodule(fmt BUILD EXCLUDE_FROM_ALL PACKAGE fmt REQUIRED) endif() # If we're building from the submodule, make sure we pass -fPIC so that we can link the code into a # shared library later. @@ -133,7 +133,7 @@ endif() cpp_cc_git_submodule(spdlog BUILD PACKAGE spdlog REQUIRED) if(NMODL_ENABLE_BACKWARD) - cpp_cc_git_submodule(backward BUILD PACKAGE backward REQUIRED) + cpp_cc_git_submodule(backward BUILD EXCLUDE_FROM_ALL PACKAGE backward REQUIRED) endif() # ============================================================================= From 713e32e3e2924119054957bad2da794275f9edf3 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 14:59:42 +0100 Subject: [PATCH 32/33] Remove useless flags --- CMakeLists.txt | 1 - src/solver/CMakeLists.txt | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f5ed91357..0e5988eb79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,6 @@ option(NMODL_BUILD_WHEEL "Flag to signal we are building a wheel" OFF) if(NMODL_BUILD_WHEEL) set(LINK_AGAINST_PYTHON OFF) set(NMODL_ENABLE_TESTS OFF) - set(FMT_INSTALL OFF) endif() # ============================================================================= diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 1ffa266dee..78c44c5d0d 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -9,14 +9,10 @@ cpp_cc_build_time_copy(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/crout/crout.hpp" OUTPU "${CMAKE_BINARY_DIR}/include/crout/crout.hpp") # Eigen -if(NOT NMODL_BUILD_WHEEL) - file(COPY ${NMODL_PROJECT_SOURCE_DIR}/ext/eigen/Eigen DESTINATION ${CMAKE_BINARY_DIR}/include/) -endif() +file(COPY ${NMODL_PROJECT_SOURCE_DIR}/ext/eigen/Eigen DESTINATION ${CMAKE_BINARY_DIR}/include/) # ============================================================================= # Install solver headers and eigen from include # ============================================================================= -if(NOT NMODL_BUILD_WHEEL) - install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION ${NMODL_INSTALL_DIR_SUFFIX}include) -endif() +install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION ${NMODL_INSTALL_DIR_SUFFIX}include) From 5c67ac771c58d0b9cea59aba79160b330ac71c9a Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 1 Mar 2024 15:00:05 +0100 Subject: [PATCH 33/33] Remove useless CI job --- .github/workflows/nmodl-doc.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/nmodl-doc.yml b/.github/workflows/nmodl-doc.yml index 8053257d36..da1c062b35 100644 --- a/.github/workflows/nmodl-doc.yml +++ b/.github/workflows/nmodl-doc.yml @@ -55,12 +55,6 @@ jobs: with: fetch-depth: 0 - - name: Install Python3 dependencies - working-directory: ${{runner.workspace}}/nmodl - run: | - pip3 install -U pip setuptools 'pip-tools>=7.4.0' - pip3 install --user -r <(pip-compile --all-build-deps --all-extras --no-strip-extras 2>&1) - - name: Documentation id: documentation working-directory: ${{runner.workspace}}/nmodl