User Guide
diffeq_context.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 <iostream>
9 
10 #include "lexer/diffeq_lexer.hpp"
11 #include "utils/string_utils.hpp"
12 
13 
14 namespace nmodl {
15 namespace parser {
16 namespace diffeq {
17 
18 Term::Term(const std::string& expr, const std::string& state)
19  : expr(expr)
20  , b(expr) {
21  if (expr == state) {
22  deriv = "1.0";
23  a = "1.0";
24  b = "0.0";
25  }
26 }
27 
28 
29 void Term::print() const {
30  std::cout << "Term [expr, deriv, a, b] : " << expr << ", " << deriv << ", " << a << ", " << b
31  << '\n';
32 }
33 
34 
35 void DiffEqContext::print() const {
36  std::cout << "-----------------DiffEq Context----------------" << std::endl;
37  std::cout << "deriv_invalid = " << deriv_invalid << std::endl;
38  std::cout << "eqn_invalid = " << eqn_invalid << std::endl;
39  std::cout << "expr = " << solution.expr << std::endl;
40  std::cout << "deriv = " << solution.deriv << std::endl;
41  std::cout << "a = " << solution.a << std::endl;
42  std::cout << "b = " << solution.b << std::endl;
43  std::cout << "-----------------------------------------------" << std::endl;
44 }
45 
46 
47 std::string DiffEqContext::cvode_deriv() const {
48  std::string result;
49  if (!deriv_invalid) {
50  result = solution.deriv;
51  }
52  return result;
53 }
54 
55 
56 std::string DiffEqContext::cvode_eqnrhs() const {
57  std::string result;
58  if (!eqn_invalid) {
59  result = solution.b;
60  }
61  return result;
62 }
63 
64 
65 /**
66  * When non-cnexp method is used, for solving non-linear equations we need original
67  * expression but with replacing every state variable with (state+0.001). In order
68  * to do this we scan original expression and build new by replacing only state variable.
69  */
71  std::string expression;
72 
73  /// build lexer instance
74  std::istringstream in(rhs);
75  DiffeqLexer scanner(&in);
76 
77  /// scan entire expression
78  while (true) {
79  auto sym = scanner.next_token();
80  auto token_type = sym.type_get();
81  if (token_type == DiffeqParser::by_type(DiffeqParser::token::END).type_get()) {
82  break;
83  }
84  /// extract value of the token and check if it is a token
85  auto value = sym.value.as<std::string>();
86  if (value == state) {
87  expression += "(" + value + "+0.001)";
88  } else {
89  expression += value;
90  }
91  }
92  return expression;
93 }
94 
95 
96 /**
97  * Return solution for non-cnexp method and when equation is linear
98  */
100  auto result = "D" + state + " = " + "D" + state + "/(1.0-dt*(" + solution.deriv + "))";
101  return result;
102 }
103 
104 
105 /**
106  * Return solution for non-cnexp method and when equation is non-linear.
107  */
109  std::string expr = get_expr_for_nonlinear();
110  std::string sol = "D" + state + " = " + "D" + state + "/(1.0-dt*(";
111  sol += "((" + expr + ")-(" + solution.expr + "))/0.001))";
112  return sol;
113 }
114 
115 
116 /**
117  * Return solution for cnexp method
118  */
120  auto a = cvode_deriv();
121  auto b = cvode_eqnrhs();
122  /**
123  * a is zero typically when rhs doesn't have state variable
124  * in this case we have to remove "last" term "/(0.0)" from b
125  * and then return : state = state - dt*(b)
126  */
127  std::string result;
128  if (a == "0.0") {
129  std::string suffix = "/(0.0)";
130  b = b.substr(0, b.size() - suffix.size());
131  result = state + " = " + state + "-dt*(" + b + ")";
132  } else {
133  result = state + " = " + state + "+(1.0-exp(dt*(" + a + ")))*(" + b + "-" + state + ")";
134  }
135  return result;
136 }
137 
138 
139 /**
140  * Return solution for euler method
141  */
143  return "D" + state + " = " + rhs;
144 }
145 
146 
147 /**
148  * Return solution for non-cnexp method
149  */
151  std::string result;
152  if (!deriv_invalid) {
153  result = get_cvode_linear_diffeq();
154  } else if (deriv_invalid && eqn_invalid) {
155  result = get_cvode_nonlinear_diffeq();
156  } else {
157  throw std::runtime_error("Error in differential equation solver with non-cnexp");
158  }
159  return result;
160 }
161 
162 
163 /**
164  * Return the solution for differential equation based on method used.
165  *
166  * \todo Currently we have tested cnexp, euler and derivimplicit methods with
167  * all equations from BBP models. Need to test this against various other mod
168  * files, especially kinetic schemes, reaction-diffusion etc.
169  */
170 std::string DiffEqContext::get_solution(bool& cnexp_possible) {
171  std::string solution;
172  if (method == "euler") {
173  cnexp_possible = false;
175  } else if (method == "cnexp" && !(deriv_invalid && eqn_invalid)) {
176  cnexp_possible = true;
178  } else {
179  cnexp_possible = false;
181  }
182  return solution;
183 }
184 
185 } // namespace diffeq
186 } // namespace parser
187 } // namespace nmodl
nmodl::parser::diffeq::DiffEqContext::get_euler_derivate
std::string get_euler_derivate() const
return only the derivate for euler method
Definition: diffeq_context.cpp:142
nmodl::parser::diffeq::DiffEqContext::solution
Term solution
"final" solution of the equation
Definition: diffeq_context.hpp:100
nmodl::parser::diffeq::Term::expr
std::string expr
expression being solved
Definition: diffeq_context.hpp:28
nmodl::parser::DiffeqLexer
Represent Lexer/Scanner class for differential equation parsing.
Definition: diffeq_lexer.hpp:47
nmodl::parser::diffeq::DiffEqContext::get_cnexp_solution
std::string get_cnexp_solution() const
return solution for cnexp method
Definition: diffeq_context.cpp:119
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
string_utils.hpp
Implement string manipulation functions.
nmodl::parser::diffeq::DiffEqContext::deriv_invalid
bool deriv_invalid
if derivative of the equation is invalid
Definition: diffeq_context.hpp:103
diffeq_lexer.hpp
nmodl::parser::diffeq::Term::deriv
std::string deriv
derivative of the expression
Definition: diffeq_context.hpp:31
nmodl::parser::diffeq::DiffEqContext::get_cvode_linear_diffeq
std::string get_cvode_linear_diffeq() const
for non-cnexp methods : return the solution based on if equation is linear or not
Definition: diffeq_context.cpp:99
nmodl::parser::diffeq::DiffEqContext::rhs
std::string rhs
rhs of equation
Definition: diffeq_context.hpp:79
nmodl::parser::diffeq::DiffEqContext::get_expr_for_nonlinear
std::string get_expr_for_nonlinear() const
return expression with Dstate added
Definition: diffeq_context.cpp:70
nmodl::parser::diffeq::DiffEqContext::method
std::string method
name of the solve method
Definition: diffeq_context.hpp:73
nmodl::parser::diffeq::DiffEqContext::cvode_eqnrhs
std::string cvode_eqnrhs() const
Definition: diffeq_context.cpp:56
nmodl::parser::diffeq::Term::b
std::string b
Definition: diffeq_context.hpp:35
nmodl::parser::DiffeqLexer::next_token
virtual DiffeqParser::symbol_type next_token()
Function for lexer to scan token (replacement for yylex())
nmodl::parser::diffeq::DiffEqContext::get_solution
std::string get_solution(bool &cnexp_possible)
return solution of the differential equation
Definition: diffeq_context.cpp:170
nmodl::parser::diffeq::Term::print
void print() const
Definition: diffeq_context.cpp:29
nmodl::parser::diffeq::DiffEqContext::cvode_deriv
std::string cvode_deriv() const
Definition: diffeq_context.cpp:47
nmodl::parser::diffeq::Term::a
std::string a
Definition: diffeq_context.hpp:34
nmodl::parser::diffeq::DiffEqContext::eqn_invalid
bool eqn_invalid
if equation itself is invalid
Definition: diffeq_context.hpp:106
nmodl::parser::diffeq::DiffEqContext::get_cvode_nonlinear_diffeq
std::string get_cvode_nonlinear_diffeq() const
Return solution for non-cnexp method and when equation is non-linear.
Definition: diffeq_context.cpp:108
nmodl::parser::diffeq::DiffEqContext::print
void print() const
print the context (for debugging)
Definition: diffeq_context.cpp:35
nmodl::parser::diffeq::DiffEqContext::state
std::string state
name of the state variable
Definition: diffeq_context.hpp:76
nmodl::parser::diffeq::Term::Term
Term()=default
nmodl::token_type
TokenType token_type(const std::string &name)
Return token type for given token name.
Definition: token_mapping.cpp:284
nmodl::parser::diffeq::DiffEqContext::get_non_cnexp_solution
std::string get_non_cnexp_solution() const
return solution for non-cnexp method
Definition: diffeq_context.cpp:150