27 using visitor::DefUseAnalyzeVisitor;
29 using visitor::RenameVisitor;
30 using visitor::SymtabVisitor;
40 return optimize_ion_variable_copies() && info.ion_has_write_variable();
44 std::vector<std::string> variables;
45 for (
const auto& param: params) {
46 variables.push_back(std::get<3>(param));
48 return fmt::format(
"{}", fmt::join(variables,
", "));
53 std::vector<std::string> variables;
54 for (
const auto& param: params) {
55 variables.push_back(fmt::format(
"{}{} {}{}",
61 return fmt::format(
"{}", fmt::join(variables,
", "));
67 auto parameters = node->get_parameters();
68 return std::any_of(parameters.begin(),
70 [&name](
const decltype(*parameters.begin()) arg) {
71 return arg->get_node_name() == name;
77 return "update_table_" + method_name(block_name);
100 if (expression->is_solve_block()) {
103 if (expression->is_initial_block()) {
112 if (net_receive_required() && !info.artificial_cell) {
113 if (info.net_event_used || info.net_send_used || info.is_watch_used()) {
122 return info.point_process && !info.artificial_cell && info.net_receive_node !=
nullptr;
127 if (info.artificial_cell) {
130 return info.nrn_state_block !=
nullptr || breakpoint_exist();
135 return info.breakpoint_node !=
nullptr && !info.currents.empty();
140 return info.net_receive_node !=
nullptr;
145 return info.breakpoint_node !=
nullptr;
150 return net_receive_exist();
165 const auto&
function = program_symtab->lookup(name);
166 auto properties = NmodlType::function_block | NmodlType::procedure_block;
167 return function &&
function->has_any_property(properties);
171 auto it = std::find_if(info.function_tables.begin(),
172 info.function_tables.end(),
173 [name](
const auto& node) { return node->get_node_name() == name; });
174 return it != info.function_tables.end();
179 for (
const auto& var: codegen_float_variables) {
180 n_floats += var->get_length();
188 const auto count_semantics = [](
int sum,
const IndexSemantics& sem) {
return sum += sem.size; };
189 return std::accumulate(info.semantics.begin(), info.semantics.end(), 0, count_semantics);
233 if (expression->is_statement_block()
234 || expression->is_eigen_newton_solver_block()
235 || expression->is_eigen_linear_solver_block()
236 || expression->is_solution_expression()
237 || expression->is_for_netcon()) {
253 if (optimize_ion_variable_copies()) {
254 return ion_read_statements_optimized(type);
256 std::vector<std::string> statements;
257 for (
const auto& ion: info.ions) {
258 auto name = ion.name;
259 for (
const auto& var: ion.reads) {
260 auto const iter = std::find(ion.implicit_reads.begin(), ion.implicit_reads.end(), var);
261 if (iter != ion.implicit_reads.end()) {
264 auto variable_names = read_ion_variable_name(var);
265 auto first = get_variable_name(variable_names.first);
266 auto second = get_variable_name(variable_names.second);
267 statements.push_back(fmt::format(
"{} = {};", first, second));
269 for (
const auto& var: ion.writes) {
270 if (ion.is_ionic_conc(var)) {
271 auto variables = read_ion_variable_name(var);
272 auto first = get_variable_name(variables.first);
273 auto second = get_variable_name(variables.second);
274 statements.push_back(fmt::format(
"{} = {};", first, second));
283 std::vector<std::string> statements;
284 for (
const auto& ion: info.ions) {
285 for (
const auto& var: ion.writes) {
286 if (ion.is_ionic_conc(var)) {
287 auto variables = read_ion_variable_name(var);
288 auto first =
"ionvar." + variables.first;
289 const auto& second = get_variable_name(variables.second);
290 statements.push_back(fmt::format(
"{} = {};", first, second));
299 std::vector<ShadowUseStatement> statements;
300 for (
const auto& ion: info.ions) {
301 std::string concentration;
302 for (
const auto& var: ion.writes) {
303 auto variable_names = write_ion_variable_name(var);
304 if (ion.is_ionic_current(var)) {
306 auto current = breakpoint_current(var);
307 auto lhs = variable_names.first;
309 auto rhs = get_variable_name(current);
310 if (info.point_process) {
312 rhs += fmt::format(
"*(1.e2/{})", area);
317 if (!ion.is_rev_potential(var)) {
320 auto lhs = variable_names.first;
322 auto rhs = get_variable_name(variable_names.second);
328 append_conc_write_statements(statements, ion, concentration);
343 if (statement.
op.empty() && statement.
rhs.empty()) {
344 auto text = statement.
lhs +
";";
349 auto lhs = get_variable_name(statement.
lhs);
350 auto text = fmt::format(
"{} {} {};", lhs, statement.
op, statement.
rhs);
364 auto breakpoint = info.breakpoint_node;
365 if (breakpoint ==
nullptr) {
368 auto symtab = breakpoint->get_statement_block()->get_symbol_table();
369 auto variables = symtab->get_variables_with_properties(NmodlType::local_var);
370 for (
const auto& var: variables) {
371 auto renamed_name = var->get_name();
372 auto original_name = var->get_original_name();
373 if (current == original_name) {
374 current = renamed_name;
402 std::vector<std::shared_ptr<const ast::Ast>> nodes;
410 printer->add_line(
"#pragma omp simd");
411 printer->add_line(
"#pragma ivdep");
421 std::string result(name);
422 if (ion_variable_struct_required()) {
423 if (info.is_ion_read_variable(name)) {
426 if (info.is_ion_write_variable(name)) {
427 result =
"ionvar." + name;
429 if (info.is_current(name)) {
430 result =
"ionvar." + name;
438 const std::string& name) {
444 const std::string& name) {
460 time_t current_time{};
462 std::string data_time_str{std::ctime(¤t_time)};
465 printer->add_line(
"/*********************************************************");
466 printer->add_line(
"Model Name : ", info.mod_suffix);
467 printer->add_line(
"Filename : ", info.mod_file,
".mod");
468 printer->add_line(
"NMODL Version : ", nmodl_version());
469 printer->fmt_line(
"Vectorized : {}", info.vectorize);
470 printer->fmt_line(
"Threadsafe : {}", info.thread_safe);
472 printer->add_line(
"Simulator : ", simulator_name());
473 printer->add_line(
"Backend : ", backend_name());
474 printer->add_line(
"NMODL Compiler : ", version);
475 printer->add_line(
"*********************************************************/");
480 for (
const auto& f: info.function_tables) {
481 printer->fmt_line(
"void* _ptable_{}{{}};", f->get_node_name());
482 codegen_global_variables.push_back(make_symbol(
"_ptable_" + f->get_node_name()));
490 printer->fmt_line(
"static_assert(std::is_trivially_copy_constructible_v<{}>);",
492 printer->fmt_line(
"static_assert(std::is_trivially_move_constructible_v<{}>);",
494 printer->fmt_line(
"static_assert(std::is_trivially_copy_assignable_v<{}>);", global_struct());
495 printer->fmt_line(
"static_assert(std::is_trivially_move_assignable_v<{}>);", global_struct());
496 printer->fmt_line(
"static_assert(std::is_trivially_destructible_v<{}>);", global_struct());
501 printer->fmt_line(
"static {} {};", global_struct(), global_struct_instance());
510 auto get_renamed_random_function =
511 [&](
const std::string& name) -> std::pair<std::string, bool> {
515 return {name,
false};
517 auto [function_name, is_random_function] = get_renamed_random_function(name);
519 if (defined_method(name)) {
520 function_name = method_name(name);
524 print_nrn_pointing(node);
528 if (is_net_send(name)) {
529 print_net_send_call(node);
533 if (is_net_move(name)) {
534 print_net_move_call(node);
538 if (is_net_event(name)) {
539 print_net_event_call(node);
543 if (is_function_table_call(name)) {
544 print_function_table_call(node);
549 printer->add_text(function_name,
'(');
551 if (defined_method(name)) {
552 auto internal_args = internal_method_arguments();
553 printer->add_text(internal_args);
554 if (!arguments.empty() && !internal_args.empty()) {
555 printer->add_text(
", ");
559 print_vector_elements(arguments,
", ");
560 printer->add_text(
')');
564 printer->add_text(
"nrn_pointing(&");
566 printer->add_text(
")");
570 print_function_procedure_helper(node);
578 std::string return_var;
579 if (info.function_uses_table(name)) {
580 return_var =
"ret_f_" + name;
582 return_var =
"ret_" + name;
590 print_function_procedure_helper(node);
597 auto [params, table_params] = function_table_parameters(node);
598 printer->fmt_push_block(
"double {}({})", method_name(name), get_parameter_str(params));
599 printer->fmt_line(
"double _arg[{}];", p.size());
600 for (
size_t i = 0; i < p.size(); ++i) {
601 printer->fmt_line(
"_arg[{}] = {};", i, p[i]->get_node_name());
603 printer->fmt_line(
"return hoc_func_table({}, {}, _arg);",
604 get_variable_name(std::string(
"_ptable_" + name),
true),
606 printer->pop_block();
608 printer->fmt_push_block(
"double table_{}({})",
610 get_parameter_str(table_params));
611 printer->fmt_line(
"hoc_spec_table(&{}, {});",
612 get_variable_name(std::string(
"_ptable_" + name)),
614 printer->add_line(
"return 0.;");
615 printer->pop_block();
620 printer->add_line(
"#ifndef NRN_PRCELLSTATE");
621 printer->add_line(
"#define NRN_PRCELLSTATE 0");
622 printer->add_line(
"#endif");
627 auto variable_printer = [&](
const std::vector<SymbolType>& variables) {
628 for (
const auto& v: variables) {
629 auto name = v->get_name();
630 if (!info.point_process) {
631 name +=
"_" + info.mod_suffix;
634 name += fmt::format(
"[{}]", v->get_length());
636 printer->add_line(add_escape_quote(name),
",");
640 printer->add_newline(2);
641 printer->add_line(
"/** channel information */");
642 printer->fmt_line(
"static const char *{}[] = {{", get_channel_info_var_name());
643 printer->increase_indent();
644 printer->add_line(add_escape_quote(nmodl_version()),
",");
645 printer->add_line(add_escape_quote(info.mod_suffix),
",");
646 variable_printer(info.range_parameter_vars);
647 printer->add_line(
"0,");
648 variable_printer(info.range_assigned_vars);
649 printer->add_line(
"0,");
650 variable_printer(info.range_state_vars);
651 printer->add_line(
"0,");
652 variable_printer(info.pointer_variables);
653 printer->add_line(
"0");
654 printer->decrease_indent();
655 printer->add_line(
"};");
659 printer->fmt_line(
"using namespace {};", namespace_name());
663 printer->add_newline(2);
664 printer->fmt_push_block(
"namespace {}", namespace_name());
669 printer->pop_block();
674 if (info.top_verbatim_blocks.empty()) {
677 print_namespace_stop();
679 printer->add_newline(2);
680 print_using_namespace();
682 printing_top_verbatim_blocks =
true;
684 for (
const auto& block: info.top_verbatim_blocks) {
685 printer->add_newline(2);
686 block->accept(*
this);
689 printing_top_verbatim_blocks =
false;
691 print_namespace_start();
704 printer->push_block();
708 for (
const auto& statement: statements) {
709 if (statement_to_skip(*statement)) {
713 if (!statement->is_verbatim() && !statement->is_mutex_lock() &&
714 !statement->is_mutex_unlock() && !statement->is_protect_statement()) {
715 printer->add_indent();
717 statement->accept(*
this);
718 if (need_semicolon(*statement)) {
719 printer->add_text(
';');
721 if (!statement->is_mutex_lock() && !statement->is_mutex_unlock()) {
722 printer->add_newline();
727 printer->pop_block_nl(0);
745 auto model_symbol_table = std::make_shared<symtab::ModelSymbolTable>();
753 auto is_functor_const =
true;
755 for (
const auto& variable: variables) {
756 const auto& chain = v.
analyze(complete_block, variable->get_node_name());
757 is_functor_const = !(chain.eval() == DUState::D || chain.eval() == DUState::LD ||
758 chain.eval() == DUState::CD);
759 if (!is_functor_const) {
764 return is_functor_const;
769 for (
const auto& functor_name: info.functor_names) {
770 printer->add_newline(2);
771 print_functor_definition(*functor_name.first);
778 auto float_type = default_float_data_type();
781 const auto functor_name = info.functor_names[&node];
782 printer->fmt_push_block(
"struct {}", functor_name);
784 auto params = functor_params();
785 for (
const auto& param: params) {
786 printer->fmt_line(
"{}{} {};", std::get<0>(param), std::get<1>(param), std::get<3>(param));
789 if (ion_variable_struct_required()) {
790 print_ion_variable();
794 printer->add_newline();
796 printer->push_block(
"void initialize()");
798 printer->pop_block();
799 printer->add_newline();
801 printer->fmt_line(
"{}({})", functor_name, get_parameter_str(params));
802 printer->increase_indent();
803 auto initializers = std::vector<std::string>();
804 for (
const auto& param: params) {
805 initializers.push_back(fmt::format(
"{0}({0})", std::get<3>(param)));
808 printer->add_multi_line(
": " + fmt::format(
"{}", fmt::join(initializers,
", ")));
809 printer->decrease_indent();
810 printer->add_line(
"{}");
812 printer->add_indent();
818 "void operator()(const Eigen::Matrix<{0}, {1}, 1>& nmodl_eigen_xm, Eigen::Matrix<{0}, {1}, "
819 "1>& nmodl_eigen_dxm, Eigen::Matrix<{0}, {1}, "
820 "1>& nmodl_eigen_fm, "
821 "Eigen::Matrix<{0}, {1}, {1}>& nmodl_eigen_jm) {2}",
824 is_functor_const(variable_block, functor_block) ?
"const " :
"");
825 printer->push_block();
826 printer->fmt_line(
"const {}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
827 printer->fmt_line(
"{}* nmodl_eigen_dx = nmodl_eigen_dxm.data();", float_type);
828 printer->fmt_line(
"{}* nmodl_eigen_j = nmodl_eigen_jm.data();", float_type);
829 printer->fmt_line(
"{}* nmodl_eigen_f = nmodl_eigen_fm.data();", float_type);
831 for (
size_t i = 0; i < N; ++i) {
833 "nmodl_eigen_dx[{0}] = std::max(1e-6, 0.02*std::fabs(nmodl_eigen_x[{0}]));", i);
836 print_statement_block(functor_block,
false,
false);
837 printer->pop_block();
838 printer->add_newline();
841 printer->push_block(
"void finalize()");
843 printer->pop_block();
845 printer->pop_block(
";");
852 printer->add_multi_line(R
"CODE(
854 nmodl_eigen_jm.computeInverseWithCheck(nmodl_eigen_jm_inv,invertible);
855 nmodl_eigen_xm = nmodl_eigen_jm_inv*nmodl_eigen_fm;
856 if (!invertible) assert(false && "Singular or ill-conditioned matrix (Eigen::inverse)!");
863 printer->add_line(
"if (!nmodl_eigen_jm.IsRowMajor) nmodl_eigen_jm.transposeInPlace();");
866 printer->fmt_line(
"Eigen::Matrix<int, {}, 1> pivot;", N);
867 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, 1> rowmax;", float_type, N);
871 "if (nmodl::crout::Crout<{0}>({1}, nmodl_eigen_jm.data(), pivot.data(), rowmax.data()) "
872 "< 0) assert(false && \"Singular or ill-conditioned matrix (nmodl::crout)!\");",
878 "nmodl::crout::solveCrout<{0}>({1}, nmodl_eigen_jm.data(), nmodl_eigen_fm.data(), "
879 "nmodl_eigen_xm.data(), pivot.data());",
896 if (!info.factor_definitions.empty()) {
897 printer->add_newline(2);
898 printer->add_line(
"/** constants used in nmodl from UNITS */");
899 for (
const auto& it: info.factor_definitions) {
900 const std::string format_string =
"static const double {} = {};";
901 printer->fmt_line(format_string, it->get_node_name(), it->get_value()->get_value());
916 std::string name = node.
eval();
917 if (enable_variable_name_lookup) {
918 name = get_variable_name(name);
920 printer->add_text(name);
956 throw std::runtime_error(
"PRIME encountered during code generation, ODEs not solved?");
965 const auto& at_index = node.
get_at();
969 printer->add_text(
"@");
970 at_index->accept(*
this);
973 printer->add_text(
"[");
974 printer->add_text(
"static_cast<int>(");
975 index->accept(*
this);
976 printer->add_text(
")");
977 printer->add_text(
"]");
984 printer->add_text(
"[");
985 printer->add_text(
"static_cast<int>(");
987 printer->add_text(
")");
988 printer->add_text(
"]");
993 printer->add_text(local_var_type(),
' ');
999 printer->add_text(
"if (");
1001 printer->add_text(
") ");
1006 elses->accept(*
this);
1012 printer->add_text(
" else if (");
1014 printer->add_text(
") ");
1020 printer->add_text(
" else ");
1026 printer->add_text(
"while (");
1028 printer->add_text(
") ");
1035 const auto& from = node.
get_from();
1036 const auto& to = node.
get_to();
1039 printer->fmt_text(
"for (int {} = ", name);
1040 from->accept(*
this);
1041 printer->fmt_text(
"; {} <= ", name);
1044 printer->fmt_text(
"; {} += ", name);
1047 printer->fmt_text(
"; {}++", name);
1049 printer->add_text(
") ");
1050 block->accept(*
this);
1055 printer->add_text(
"(");
1057 printer->add_text(
")");
1063 const auto& lhs = node.
get_lhs();
1064 const auto& rhs = node.
get_rhs();
1066 printer->add_text(
"pow(");
1068 printer->add_text(
", ");
1070 printer->add_text(
")");
1073 printer->add_text(
" " + op +
" ");
1080 printer->add_text(node.
eval());
1085 printer->add_text(
" " + node.
eval());
1095 print_statement_block(node);
1100 print_function_call(node);
1110 printer->fmt_line(
"#pragma omp critical ({})", info.mod_suffix);
1111 printer->add_indent();
1112 printer->push_block();
1117 printer->pop_block();
1123 if (block->is_statement_block()) {
1125 print_statement_block(*statement_block,
false,
false);
1127 block->accept(*
this);
1134 printer->add_newline();
1136 auto float_type = default_float_data_type();
1138 printer->fmt_line(
"Eigen::Matrix<{}, {}, 1> nmodl_eigen_xm;", float_type, N);
1139 printer->fmt_line(
"{}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
1144 printer->add_line(
"// call newton solver");
1145 printer->fmt_line(
"{} newton_functor({});",
1146 info.functor_names[&node],
1147 get_arg_str(functor_params()));
1148 printer->add_line(
"newton_functor.initialize();");
1150 "int newton_iterations = nmodl::newton::newton_solver(nmodl_eigen_xm, newton_functor);");
1152 "if (newton_iterations < 0) assert(false && \"Newton solver did not converge!\");");
1156 printer->add_line(
"newton_functor.initialize(); // TODO mimic calling F again.");
1157 printer->add_line(
"newton_functor.finalize();");
1162 printer->add_newline();
1164 const std::string float_type = default_float_data_type();
1166 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, 1> nmodl_eigen_xm, nmodl_eigen_fm;", float_type, N);
1167 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, {1}> nmodl_eigen_jm;", float_type, N);
1169 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, {1}> nmodl_eigen_jm_inv;", float_type, N);
1171 printer->fmt_line(
"{}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
1172 printer->fmt_line(
"{}* nmodl_eigen_j = nmodl_eigen_jm.data();", float_type);
1173 printer->fmt_line(
"{}* nmodl_eigen_f = nmodl_eigen_fm.data();", float_type);
1178 printer->add_newline();
1179 print_eigen_linear_solver(float_type, N);
1180 printer->add_newline();
1193 info.semantics.clear();
1195 if (info.point_process) {
1199 for (
const auto& ion: info.ions) {
1200 for (
auto i = 0; i < ion.reads.size(); ++i) {
1201 info.semantics.emplace_back(
index++, ion.name +
"_ion", 1);
1203 for (
const auto& var: ion.writes) {
1205 if (std::find(ion.reads.begin(), ion.reads.end(), var) == ion.reads.end()) {
1206 info.semantics.emplace_back(
index++, ion.name +
"_ion", 1);
1208 if (ion.is_ionic_current(var)) {
1209 info.semantics.emplace_back(
index++, ion.name +
"_ion", 1);
1212 if (ion.need_style) {
1213 info.semantics.emplace_back(
index++, fmt::format(
"{}_ion", ion.name), 1);
1214 info.semantics.emplace_back(
index++, fmt::format(
"#{}_ion", ion.name), 1);
1217 for (
auto& var: info.pointer_variables) {
1218 if (info.first_pointer_var_index == -1) {
1219 info.first_pointer_var_index =
index;
1221 int size = var->get_length();
1222 if (var->has_any_property(NmodlType::pointer_var)) {
1230 for (
auto& var: info.random_variables) {
1231 if (info.first_random_var_index == -1) {
1232 info.first_random_var_index =
index;
1234 int size = var->get_length();
1239 if (info.diam_used) {
1243 if (info.area_used) {
1247 if (info.net_send_used) {
1255 if (!info.watch_statements.empty()) {
1256 for (
int i = 0; i < info.watch_statements.size() + 1; i++) {
1261 if (info.for_netcon_used) {
1270 return first->get_definition_order() < second->get_definition_order();
1273 auto assigned = info.assigned_vars;
1274 auto states = info.state_vars;
1277 for (
const auto& state: states) {
1278 auto name =
"D" + state->get_name();
1279 auto symbol = make_symbol(name);
1280 if (state->is_array()) {
1281 symbol->set_as_array(state->get_length());
1283 symbol->set_definition_order(state->get_definition_order());
1284 assigned.push_back(symbol);
1286 std::sort(assigned.begin(), assigned.end(), comparator);
1288 auto variables = info.range_parameter_vars;
1289 variables.insert(variables.end(),
1290 info.range_assigned_vars.begin(),
1291 info.range_assigned_vars.end());
1292 variables.insert(variables.end(), info.range_state_vars.begin(), info.range_state_vars.end());
1294 for (
const auto& v: assigned) {
1295 auto it = std::find_if(info.external_variables.begin(),
1296 info.external_variables.end(),
1297 [&v](
auto it) { return it->get_name() == get_name(v); });
1299 if (it == info.external_variables.end()) {
1300 variables.push_back(v);
1304 if (needs_v_unused()) {
1308 if (breakpoint_exist()) {
1313 if (
auto r = std::find_if(variables.cbegin(),
1315 [&](
const auto& s) { return name == s->get_name(); });
1316 r == variables.cend()) {
1317 variables.push_back(make_symbol(name));
1321 if (net_receive_exist()) {
1344 std::vector<IndexVariableInfo> variables;
1345 if (info.point_process) {
1347 variables.back().is_constant =
true;
1349 add_variable_point_process(variables);
1352 for (
auto& ion: info.ions) {
1353 bool need_style =
false;
1354 std::unordered_map<std::string, int> ion_vars;
1358 auto const has_var = [&ion](
const char* suffix) ->
bool {
1359 auto const pred = [name = ion.name + suffix](
auto const& x) {
return x == name; };
1360 return std::any_of(ion.reads.begin(), ion.reads.end(), pred) ||
1361 std::any_of(ion.writes.begin(), ion.writes.end(), pred);
1363 auto const add_implicit_read = [&ion](
const char* suffix) {
1364 auto name = ion.name + suffix;
1365 ion.reads.push_back(name);
1366 ion.implicit_reads.push_back(std::move(name));
1368 bool const have_ionin{has_var(
"i")}, have_ionout{has_var(
"o")};
1369 if (have_ionin && !have_ionout) {
1370 add_implicit_read(
"o");
1371 }
else if (have_ionout && !have_ionin) {
1372 add_implicit_read(
"i");
1374 for (
const auto& var: ion.reads) {
1376 variables.emplace_back(make_symbol(name));
1377 variables.back().is_constant =
true;
1378 ion_vars[name] =
static_cast<int>(variables.size() - 1);
1382 std::shared_ptr<symtab::Symbol> ion_di_dv_var =
nullptr;
1384 for (
const auto& var: ion.writes) {
1387 const auto ion_vars_it = ion_vars.find(name);
1388 if (ion_vars_it != ion_vars.end()) {
1389 variables[ion_vars_it->second].is_constant =
false;
1393 if (ion.is_ionic_current(var)) {
1397 if (ion.is_intra_cell_conc(var) || ion.is_extra_cell_conc(var)) {
1403 if (ion_di_dv_var !=
nullptr) {
1404 variables.emplace_back(ion_di_dv_var);
1409 variables.emplace_back(make_symbol(
"style_" + ion.name),
false,
true);
1410 variables.back().is_constant =
true;
1414 for (
const auto& var: info.pointer_variables) {
1415 auto name = var->get_name();
1416 if (var->has_any_property(NmodlType::pointer_var)) {
1417 variables.emplace_back(make_symbol(name));
1419 variables.emplace_back(make_symbol(name),
true);
1423 for (
const auto& var: info.random_variables) {
1424 auto name = var->get_name();
1425 variables.emplace_back(make_symbol(name),
true);
1426 variables.back().symbol->add_properties(NmodlType::random_var);
1429 if (info.diam_used) {
1433 if (info.area_used) {
1437 add_variable_tqitem(variables);
1444 if (!info.watch_statements.empty()) {
1445 for (
int i = 0; i < info.watch_statements.size() + 1; i++) {
1446 variables.emplace_back(make_symbol(fmt::format(
"watch{}", i)),
false,
false,
true);
1450 if (info.for_netcon_used) {
1464 if (info.mod_suffix ==
"") {
1465 info.mod_suffix = std::filesystem::path(mod_filename).stem().string();
1467 info.rsuffix = info.point_process ?
"" :
"_" + info.mod_suffix;
1468 if (info.mod_suffix ==
"nothing") {
1472 if (!info.vectorize) {
1473 logger->warn(
"CodegenCppVisitor : MOD file uses non-thread safe constructs of NMODL");
1476 codegen_float_variables = get_float_variables();
1477 codegen_int_variables = get_int_variables();
1479 update_index_semantics();
1481 info.semantic_variable_count = int_variables_size();
1504 throw std::logic_error(
"compute_method_name not implemented");
1510 print_codegen_routines();
1516 auto statement = get_table_statement(node);
1517 auto table_variables = statement->get_table_vars();
1518 auto with = statement->get_with()->eval();
1520 auto tmin_name = get_variable_name(
"tmin_" + name);
1521 auto mfac_name = get_variable_name(
"mfac_" + name);
1522 auto function_name = method_name(
"f_" + name);
1524 printer->add_newline(2);
1525 print_function_declaration(node, name);
1526 printer->push_block();
1529 printer->fmt_push_block(
"if ({} == 0)", use_table_var);
1531 printer->fmt_line(
"{}({}, {});",
1533 internal_method_arguments(),
1534 params[0].get()->get_node_name());
1535 printer->add_line(
"return 0;");
1537 printer->fmt_line(
"return {}({}, {});",
1539 internal_method_arguments(),
1540 params[0].get()->get_node_name());
1542 printer->pop_block();
1544 printer->fmt_line(
"double xi = {} * ({} - {});",
1546 params[0].get()->get_node_name(),
1548 printer->push_block(
"if (isnan(xi))");
1550 for (
const auto& var: table_variables) {
1551 auto var_name = get_variable_name(var->get_node_name());
1552 auto [is_array, array_length] = check_if_var_is_array(var->get_node_name());
1554 for (
int j = 0; j < array_length; j++) {
1555 printer->fmt_line(
"{}[{}] = xi;", var_name, j);
1558 printer->fmt_line(
"{} = xi;", var_name);
1561 printer->add_line(
"return 0;");
1563 printer->add_line(
"return xi;");
1565 printer->pop_block();
1567 printer->fmt_push_block(
"if (xi <= 0. || xi >= {}.)", with);
1568 printer->fmt_line(
"int index = (xi <= 0.) ? 0 : {};", with);
1570 for (
const auto& variable: table_variables) {
1571 auto var_name = variable->get_node_name();
1572 auto instance_name = get_variable_name(var_name);
1573 auto table_name = get_variable_name(
"t_" + var_name);
1574 auto [is_array, array_length] = check_if_var_is_array(var_name);
1576 for (
int j = 0; j < array_length; j++) {
1578 "{}[{}] = {}[{}][index];", instance_name, j, table_name, j);
1581 printer->fmt_line(
"{} = {}[index];", instance_name, table_name);
1584 printer->add_line(
"return 0;");
1586 auto table_name = get_variable_name(
"t_" + name);
1587 printer->fmt_line(
"return {}[index];", table_name);
1589 printer->pop_block();
1591 printer->add_line(
"int i = int(xi);");
1592 printer->add_line(
"double theta = xi - double(i);");
1594 for (
const auto& var: table_variables) {
1595 auto var_name = var->get_node_name();
1596 auto instance_name = get_variable_name(var_name);
1597 auto table_name = get_variable_name(
"t_" + var_name);
1598 auto [is_array, array_length] = check_if_var_is_array(var->get_node_name());
1600 for (
size_t j = 0; j < array_length; j++) {
1602 "{0}[{1}] = {2}[{1}][i] + theta*({2}[{1}][i+1]-{2}[{1}][i]);",
1608 printer->fmt_line(
"{0} = {1}[i] + theta*({1}[i+1]-{1}[i]);",
1613 printer->add_line(
"return 0;");
1615 auto table_name = get_variable_name(
"t_" + name);
1616 printer->fmt_line(
"return {0}[i] + theta * ({0}[i+1] - {0}[i]);", table_name);
1619 printer->pop_block();
1624 auto statement = get_table_statement(node);
1625 auto table_variables = statement->get_table_vars();
1626 auto depend_variables = statement->get_depend_vars();
1627 const auto& from = statement->get_from();
1628 const auto& to = statement->get_to();
1630 auto internal_params = internal_method_parameters();
1631 auto with = statement->get_with()->eval();
1633 auto tmin_name = get_variable_name(
"tmin_" + name);
1634 auto mfac_name = get_variable_name(
"mfac_" + name);
1635 auto float_type = default_float_data_type();
1637 printer->add_newline(2);
1638 printer->fmt_push_block(
"void {}({})",
1639 table_update_function_name(name),
1640 get_parameter_str(internal_params));
1642 printer->fmt_push_block(
"if ({} == 0)", use_table_var);
1643 printer->add_line(
"return;");
1644 printer->pop_block();
1646 printer->add_line(
"static bool make_table = true;");
1647 for (
const auto& variable: depend_variables) {
1648 printer->fmt_line(
"static {} save_{};", float_type, variable->get_node_name());
1651 for (
const auto& variable: depend_variables) {
1652 const auto& var_name = variable->get_node_name();
1653 const auto& instance_name = get_variable_name(var_name);
1654 printer->fmt_push_block(
"if (save_{} != {})", var_name, instance_name);
1655 printer->add_line(
"make_table = true;");
1656 printer->pop_block();
1659 printer->push_block(
"if (make_table)");
1661 printer->add_line(
"make_table = false;");
1663 printer->add_indent();
1664 printer->add_text(tmin_name,
" = ");
1665 from->accept(*
this);
1666 printer->add_text(
';');
1667 printer->add_newline();
1669 printer->add_indent();
1670 printer->add_text(
"double tmax = ");
1672 printer->add_text(
';');
1673 printer->add_newline();
1676 printer->fmt_line(
"double dx = (tmax-{}) / {}.;", tmin_name, with);
1677 printer->fmt_line(
"{} = 1./dx;", mfac_name);
1679 printer->fmt_line(
"double x = {};", tmin_name);
1680 printer->fmt_push_block(
"for (std::size_t i = 0; i < {}; x += dx, i++)", with + 1);
1681 auto function = method_name(
"f_" + name);
1683 printer->fmt_line(
"{}({}, x);",
function, internal_method_arguments());
1684 for (
const auto& variable: table_variables) {
1685 auto var_name = variable->get_node_name();
1686 auto instance_name = get_variable_name(var_name);
1687 auto table_name = get_variable_name(
"t_" + var_name);
1688 auto [is_array, array_length] = check_if_var_is_array(var_name);
1690 for (
int j = 0; j < array_length; j++) {
1692 "{}[{}][i] = {}[{}];", table_name, j, instance_name, j);
1695 printer->fmt_line(
"{}[i] = {};", table_name, instance_name);
1699 auto table_name = get_variable_name(
"t_" + name);
1700 printer->fmt_line(
"{}[i] = {}({}, x);",
1703 internal_method_arguments());
1705 printer->pop_block();
1707 for (
const auto& variable: depend_variables) {
1708 auto var_name = variable->get_node_name();
1709 auto instance_name = get_variable_name(var_name);
1710 printer->fmt_line(
"save_{} = {};", var_name, instance_name);
1713 printer->pop_block();
1715 printer->pop_block();
1720 const std::unordered_set<CppObjectSpecifier>& specifiers) {
1722 for (
const auto& specifier: specifiers) {
1723 if (!result.empty()) {
1726 result += object_specifier_map[specifier];
1733 const auto& table_statements =
collect_nodes(node, {AstNodeType::TABLE_STATEMENT});
1735 if (table_statements.size() != 1) {
1736 auto message = fmt::format(
"One table statement expected in {} found {}",
1738 table_statements.size());
1739 throw std::runtime_error(message);
1746 auto symbol = program_symtab->lookup_in_scope(name);
1748 throw std::runtime_error(
1749 fmt::format(
"CodegenCppVisitor:: {} not found in symbol table!", name));
1751 if (symbol->is_array()) {
1752 return {
true, symbol->get_length()};
1760 for (
const auto& state: info.state_vars) {
1761 auto state_name = state->get_name();
1762 auto lhs = get_variable_name(state_name);
1763 auto rhs = get_variable_name(state_name +
"0");
1765 if (state->is_array()) {
1766 for (
int i = 0; i < state->get_length(); ++i) {
1767 printer->fmt_line(
"{}[{}] = {};", lhs, i, rhs);
1770 printer->fmt_line(
"{} = {};", lhs, rhs);