13 #include <fmt/format.h>
14 #include <pybind11/embed.h>
15 #include <pybind11/stl.h>
19 #include "pybind/ode_py.hpp"
25 namespace fs = std::filesystem;
27 using namespace py::literals;
30 namespace pybind_wrappers {
36 #ifdef NRN_ENABLE_COVERAGE
41 py::exec(fmt::format(R
"(
43 cov = coverage.Coverage(data_suffix='{}')
48 const auto& code_with_mapping = std::string(
"exec(compile(r'''" + ode_py + script +
"''', '" +
49 ode_py_path +
"', 'exec'))");
50 py::exec(code_with_mapping, locals);
52 py::exec(ode_py + script, locals);
55 #ifdef NRN_ENABLE_COVERAGE
56 const auto& path = fs::current_path() / fmt::format(
"coverage_{}.xml",
suffix);
57 py::exec(fmt::format(R
"(
60 # Check if we have any coverage data
62 if data.measured_files():
63 cov.xml_report(outfile='{}')
70 std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
72 const std::vector<std::string>& state_vars,
73 const std::set<std::string>& vars,
76 const std::string& tmp_unique_prefix,
77 const std::set<std::string>& function_calls) {
78 const auto locals = py::dict(
"eq_strings"_a = eq_system,
79 "state_vars"_a = state_vars,
81 "small_system"_a = small_system,
82 "do_cse"_a = elimination,
83 "function_calls"_a = function_calls,
84 "tmp_unique_prefix"_a = tmp_unique_prefix);
85 std::string script = R
"(
86 exception_message = ""
88 solutions, new_local_vars = solve_lin_system(eq_strings,
95 except Exception as e:
96 # if we fail, fail silently and return empty string
100 exception_message = traceback.format_exc()
104 auto solutions = locals[
"solutions"].cast<std::vector<std::string>>();
106 auto new_local_vars = locals[
"new_local_vars"].cast<std::vector<std::string>>();
108 auto exception_message = locals[
"exception_message"].cast<std::string>();
115 const std::vector<std::string>& eq_system,
116 const std::vector<std::string>& state_vars,
117 const std::set<std::string>& vars,
118 const std::set<std::string>& function_calls) {
119 const auto locals = py::dict(
"equation_strings"_a = eq_system,
120 "state_vars"_a = state_vars,
122 "function_calls"_a = function_calls);
123 std::string script = R
"(
124 exception_message = ""
126 solutions = solve_non_lin_system(equation_strings,
130 except Exception as e:
131 # if we fail, fail silently and return empty string
134 exception_message = traceback.format_exc()
139 auto solutions = locals[
"solutions"].cast<std::vector<std::string>>();
141 auto exception_message = locals[
"exception_message"].cast<std::string>();
148 const std::string& dt_var,
149 const std::set<std::string>& vars,
150 bool use_pade_approx,
151 const std::set<std::string>& function_calls,
152 const std::string& method) {
153 const auto locals = py::dict(
"equation_string"_a = node_as_nmodl,
156 "use_pade_approx"_a = use_pade_approx,
157 "function_calls"_a = function_calls);
163 std::string script = R
"(
164 exception_message = ""
166 solution = forwards_euler2c(equation_string, dt_var, vars, function_calls)
167 except Exception as e:
168 # if we fail, fail silently and return empty string
171 exception_message = traceback.format_exc()
179 std::string script = R
"(
180 exception_message = ""
182 solution = integrate2c(equation_string, dt_var, vars,
184 except Exception as e:
185 # if we fail, fail silently and return empty string
188 exception_message = traceback.format_exc()
196 auto solution = locals[
"solution"].cast<std::string>();
197 auto exception_message = locals[
"exception_message"].cast<std::string>();
204 const std::vector<std::string>& expressions,
205 const std::set<std::string>& used_names_in_block) {
206 auto locals = py::dict(
"expressions"_a = expressions,
"vars"_a = used_names_in_block);
207 std::string script = R
"(
208 exception_message = ""
210 rhs = expressions[-1].split("=", 1)[1]
211 solution = differentiate2c(rhs,
216 except Exception as e:
217 # if we fail, fail silently and return empty string
220 exception_message = traceback.format_exc()
225 auto solution = locals[
"solution"].cast<std::string>();
226 auto exception_message = locals[
"exception_message"].cast<std::string>();
232 const std::string& expression,
233 const std::pair<std::string, std::optional<int>>& variable,
234 const std::unordered_set<std::string>& indexed_vars) {
235 std::string statements;
237 for (
const auto&
var: indexed_vars) {
238 statements += fmt::format(
"_allvars.append(sp.IndexedBase('{}', shape=[1]))\n",
var);
240 auto [
name, property] = variable;
241 if (property.has_value()) {
242 name = fmt::format(
"sp.IndexedBase('{}', shape=[1])",
name);
243 statements += fmt::format(
"_allvars.append({})",
name);
247 auto locals = py::dict(
"expression"_a = expression);
253 exception_message = ""
255 solution = differentiate2c(expression,
259 except Exception as e:
260 # if we fail, fail silently and return empty string
262 exception_message = str(e)
265 property.has_value() ? fmt::format("{}[{}]",
name, property.value()) :
name);
269 auto solution = locals[
"solution"].cast<std::string>();
270 auto exception_message = locals[
"exception_message"].cast<std::string>();
276 pybind11::initialize_interpreter(
true);
280 pybind11::finalize_interpreter();
Common utility functions for file/dir manipulation.
std::string generate_random_string(const int len, UseNumbersInString use_numbers)
Generate random std::string of length len based on a uniform distribution.
double var(InputIterator begin, InputIterator end)
void move(Item *q1, Item *q2, Item *q3)
static constexpr char CNEXP_METHOD[]
cnexp method in nmodl
static constexpr char EULER_METHOD[]
euler method in nmodl
std::tuple< std::vector< std::string >, std::string > call_solve_nonlinear_system(const std::vector< std::string > &eq_system, const std::vector< std::string > &state_vars, const std::set< std::string > &vars, const std::set< std::string > &function_calls)
std::tuple< std::string, std::string > call_diff2c(const std::string &expression, const std::pair< std::string, std::optional< int >> &variable, const std::unordered_set< std::string > &indexed_vars)
Differentiates an expression with respect to a variable.
void initialize_interpreter_func()
void finalize_interpreter_func()
std::tuple< std::string, std::string > call_analytic_diff(const std::vector< std::string > &expressions, const std::set< std::string > &used_names_in_block)
static void run_python_script(const std::string &script, const py::dict &locals)
std::tuple< std::string, std::string > call_diffeq_solver(const std::string &node_as_nmodl, const std::string &dt_var, const std::set< std::string > &vars, bool use_pade_approx, const std::set< std::string > &function_calls, const std::string &method)
NMODL_EXPORT pybind_wrap_api nmodl_init_pybind_wrapper_api() noexcept
std::tuple< std::vector< std::string >, std::vector< std::string >, std::string > call_solve_linear_system(const std::vector< std::string > &eq_system, const std::vector< std::string > &state_vars, const std::set< std::string > &vars, bool small_system, bool elimination, const std::string &tmp_unique_prefix, const std::set< std::string > &function_calls)
encapsulates code generation backend implementations