From 9c543ef65e4a091acb6f96023ef8d1d697ef20da Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Mon, 14 Oct 2024 14:04:20 +0200 Subject: [PATCH] NONLINEAR requires `sympy --analytic`. (#1512) --- src/language/nmodl.yaml | 6 +++--- src/main.cpp | 2 ++ test/usecases/CMakeLists.txt | 1 + test/usecases/nonlinear/nonlin.mod | 21 +++++++++++++++++++++ test/usecases/nonlinear/test_nonlin.py | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 test/usecases/nonlinear/nonlin.mod create mode 100644 test/usecases/nonlinear/test_nonlin.py diff --git a/src/language/nmodl.yaml b/src/language/nmodl.yaml index 0f76b01a3..de598cec3 100644 --- a/src/language/nmodl.yaml +++ b/src/language/nmodl.yaml @@ -1140,15 +1140,15 @@ type: Expression - NonLinEquation: - brief: "TODO" + brief: "One equation in a system of equations that collectively make a NONLINEAR block." nmodl: "~ " members: - lhs: - brief: "TODO" + brief: "Left-hand-side of the equation." type: Expression suffix: {value: " = "} - rhs: - brief: "TODO" + brief: "Right-hand-side of the equation." type: Expression - LinEquation: diff --git a/src/main.cpp b/src/main.cpp index 436ec2c4e..ba9de4a19 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -516,6 +516,8 @@ int run_nmodl(int argc, const char* argv[]) { enable_sympy(solver_exists(*ast, "derivimplicit"), "'SOLVE ... METHOD derivimplicit'"); enable_sympy(node_exists(*ast, ast::AstNodeType::LINEAR_BLOCK), "'LINEAR' block"); + enable_sympy(node_exists(*ast, ast::AstNodeType::NON_LINEAR_BLOCK), + "'NONLINEAR' block"); enable_sympy(solver_exists(*ast, "sparse"), "'SOLVE ... METHOD sparse'"); } diff --git a/test/usecases/CMakeLists.txt b/test/usecases/CMakeLists.txt index 764b907cf..22a806a1c 100644 --- a/test/usecases/CMakeLists.txt +++ b/test/usecases/CMakeLists.txt @@ -18,6 +18,7 @@ set(NMODL_USECASE_DIRS net_receive net_send neuron_variables + nonlinear nonspecific_current parameter point_process diff --git a/test/usecases/nonlinear/nonlin.mod b/test/usecases/nonlinear/nonlin.mod new file mode 100644 index 000000000..ec0bed30f --- /dev/null +++ b/test/usecases/nonlinear/nonlin.mod @@ -0,0 +1,21 @@ +NEURON { + SUFFIX nonlin +} + +STATE { x } + +FUNCTION solve() { + : Iterative solvers need a starting guess. + x = 1.0 + SOLVE eq + + solve = x +} + +NONLINEAR eq { + ~ x*x = 4.0 +} + +FUNCTION residual(x) { + residual = x - 2.0 +} diff --git a/test/usecases/nonlinear/test_nonlin.py b/test/usecases/nonlinear/test_nonlin.py new file mode 100644 index 000000000..eef75edbd --- /dev/null +++ b/test/usecases/nonlinear/test_nonlin.py @@ -0,0 +1,15 @@ +from neuron import h, gui + + +def test_nonlin(): + s = h.Section() + s.insert("nonlin") + inst = s(0.5).nonlin + + x = inst.solve() + error = inst.residual(x) + assert abs(error) < 1e-9, f"{x = }, {error = }" + + +if __name__ == "__main__": + test_nonlin()