User Guide
solve_block.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <catch2/catch_test_macros.hpp>
9 
10 #include "ast/program.hpp"
11 #include "parser/nmodl_driver.hpp"
18 
19 using namespace nmodl;
20 using namespace visitor;
21 using namespace test;
22 using namespace test_utils;
23 
25 
26 
27 //=============================================================================
28 // SolveBlock visitor tests
29 //=============================================================================
30 
31 std::string run_solve_block_visitor(const std::string& text) {
33  const auto& ast = driver.parse_string(text);
34  SymtabVisitor().visit_program(*ast);
35  NeuronSolveVisitor().visit_program(*ast);
36  SolveBlockVisitor().visit_program(*ast);
37  std::stringstream stream;
38  NmodlPrintVisitor(stream).visit_program(*ast);
39 
40  // check that, after visitor rearrangement, parents are still up-to-date
41  CheckParentVisitor().check_ast(*ast);
42 
43  return stream.str();
44 }
45 
46 TEST_CASE("Solve ODEs using legacy NeuronSolveVisitor", "[visitor][solver]") {
47  SECTION("SolveBlock add NrnState block") {
48  GIVEN("Breakpoint block with single solve block in breakpoint") {
49  std::string nmodl_text = R"(
50  BREAKPOINT {
51  SOLVE states METHOD cnexp
52  }
53 
54  DERIVATIVE states {
55  m' = (mInf-m)/mTau
56  }
57  )";
58 
59  std::string output_nmodl = R"(
60  BREAKPOINT {
61  SOLVE states METHOD cnexp
62  }
63 
64  DERIVATIVE states {
65  m = m+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-m)
66  }
67 
68  NRN_STATE SOLVE states METHOD cnexp{
69  m = m+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-m)
70  }
71 
72  )";
73 
74  THEN("Single NrnState block gets added") {
75  auto result = run_solve_block_visitor(nmodl_text);
76  REQUIRE(reindent_text(output_nmodl) == reindent_text(result));
77  }
78  }
79 
80  GIVEN("Breakpoint block with two solve block in breakpoint") {
81  std::string nmodl_text = R"(
82  BREAKPOINT {
83  SOLVE state1 METHOD cnexp
84  SOLVE state2 METHOD cnexp
85  }
86 
87  DERIVATIVE state1 {
88  m' = (mInf-m)/mTau
89  }
90 
91  DERIVATIVE state2 {
92  h' = (mInf-h)/mTau
93  }
94  )";
95 
96  std::string output_nmodl = R"(
97  BREAKPOINT {
98  SOLVE state1 METHOD cnexp
99  SOLVE state2 METHOD cnexp
100  }
101 
102  DERIVATIVE state1 {
103  m = m+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-m)
104  }
105 
106  DERIVATIVE state2 {
107  h = h+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-h)
108  }
109 
110  NRN_STATE SOLVE state1 METHOD cnexp{
111  m = m+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-m)
112  }
113  SOLVE state2 METHOD cnexp{
114  h = h+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-h)
115  }
116 
117  )";
118 
119  THEN("NrnState blok combining multiple solve nodes added") {
120  auto result = run_solve_block_visitor(nmodl_text);
121  REQUIRE(reindent_text(output_nmodl) == reindent_text(result));
122  }
123  }
124  }
125 }
126 
127 TEST_CASE("Throw errors on invalid methods", "[visitor][solver]") {
128  SECTION("PROCEDURE cannot be SOLVEd with derivimplicit METHOD") {
129  GIVEN("Breakpoint block with a PROCEDURE being solved using the derivimplcit METHOD") {
130  std::string nmodl_text = R"(
131  NEURON {
132  SUFFIX example
133  }
134 
135  BREAKPOINT {
136  SOLVE myfunc METHOD derivimplicit
137  }
138 
139  PROCEDURE myfunc() {}
140 )";
141  THEN("A runtime error should be thrown") {
142  REQUIRE_THROWS_AS(run_solve_block_visitor(nmodl_text), std::runtime_error);
143  }
144  }
145  }
146 }
test_utils.hpp
nmodl::parser::NmodlDriver
Class that binds all pieces together for parsing nmodl file.
Definition: nmodl_driver.hpp:67
solve_block_visitor.hpp
Replace solve block statements with actual solution node in the AST.
nmodl::test_utils::reindent_text
std::string reindent_text(const std::string &text, int indent_level)
Reindent nmodl text for text-to-text comparison.
Definition: test_utils.cpp:53
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
TEST_CASE
TEST_CASE("Solve ODEs using legacy NeuronSolveVisitor", "[visitor][solver]")
Definition: solve_block.cpp:46
program.hpp
Auto generated AST classes declaration.
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
nmodl::parser::UnitDriver::parse_string
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
Definition: unit_driver.cpp:40
neuron_solve_visitor.hpp
Visitor that solves ODEs using old solvers of NEURON
checkparent_visitor.hpp
Visitor for checking parents of ast nodes
nmodl_driver.hpp
run_solve_block_visitor
std::string run_solve_block_visitor(const std::string &text)
Definition: solve_block.cpp:31
symtab_visitor.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
nmodl_visitor.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.