28 using visitor::RenameVisitor;
44 return "C++ (api-compatibility)";
54 const auto has_name = [&name](
const SymbolType& symbol) {
return symbol->get_name() == name; };
56 std::find_if(codegen_float_variables.begin(), codegen_float_variables.end(), has_name);
57 if (var_iter != codegen_float_variables.end()) {
58 return var_iter - codegen_float_variables.begin();
60 throw std::logic_error(name +
" variable not found");
67 return index_var_symbol.symbol->get_name() == name;
70 std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), has_name);
71 if (var_iter != codegen_int_variables.end()) {
72 return var_iter - codegen_int_variables.begin();
74 throw std::logic_error(name +
" variable not found");
90 if (optimize_ionvar_copies) {
91 throw std::runtime_error(
"Not implemented.");
103 if (info.point_process) {
104 printer->add_multi_line(R
"CODE(
105 /* Point Process specific functions */
106 static void* _hoc_create_pnt(Object* _ho) {
107 return create_point_process(_pointtype, _ho);
110 printer->push_block("static void _hoc_destroy_pnt(void* _vptr)");
111 if (info.is_watch_used() || info.for_netcon_used) {
112 printer->add_line(
"Prop* _prop = ((Point_process*)_vptr)->prop;");
114 if (info.is_watch_used()) {
115 printer->push_block(
"if (_prop)");
116 printer->fmt_line(
"_nrn_free_watch(_nrn_mechanism_access_dparam(_prop), {}, {});",
118 info.is_watch_used());
119 printer->pop_block();
121 if (info.for_netcon_used) {
122 printer->push_block(
"if (_prop)");
124 "_nrn_free_fornetcon(&(_nrn_mechanism_access_dparam(_prop)[_fnc_index].literal_"
125 "value<void*>()));");
126 printer->pop_block();
128 printer->add_line(
"destroy_point_process(_vptr);");
129 printer->pop_block();
130 printer->add_multi_line(R
"CODE(
131 static double _hoc_loc_pnt(void* _vptr) {
132 return loc_point_process(_pointtype, _vptr);
135 static double _hoc_has_loc(void* _vptr) {
136 return has_loc_point(_vptr);
139 static double _hoc_get_loc_pnt(void* _vptr) {
140 return (get_loc_point_process(_vptr));
148 printer->add_line(
"/* Neuron setdata functions */");
149 printer->add_line(
"extern void _nrn_setdata_reg(int, void(*)(Prop*));");
150 printer->push_block(
"static void _setdata(Prop* _prop)");
151 if (!info.point_process) {
152 printer->add_multi_line(R
"CODE(
153 _extcall_prop = _prop;
154 _prop_id = _nrn_get_prop_id(_prop);
157 if (!info.vectorize) {
158 printer->add_multi_line(R
"CODE(
159 neuron::legacy::set_globals_from_prop(_prop, _ml_real, _ml, _iml);
160 _ppvar = _nrn_mechanism_access_dparam(_prop);
163 printer->pop_block();
165 if (info.point_process) {
166 printer->push_block(
"static void _hoc_setdata(void* _vptr)");
167 printer->add_multi_line(R
"CODE(
169 _prop = ((Point_process*)_vptr)->prop;
173 printer->push_block(
"static void _hoc_setdata()");
174 printer->add_multi_line(R
"CODE(
175 Prop *_prop = hoc_getdata_range(mech_type);
180 printer->pop_block();
182 printer->add_line("/* Mechanism procedures and functions */");
183 for (
const auto& node: info.functions) {
184 print_function_declaration(*node, node->get_node_name());
185 printer->add_text(
';');
186 printer->add_newline();
188 for (
const auto& node: info.procedures) {
189 print_function_declaration(*node, node->get_node_name());
190 printer->add_text(
';');
191 printer->add_newline();
198 printer->add_newline(2);
200 print_point_process_function_definitions();
201 print_setdata_functions();
208 const std::string& name) {
209 printer->add_newline(2);
210 print_function_declaration(node, name);
211 printer->add_text(
" ");
212 printer->push_block();
216 auto type = default_float_data_type();
217 printer->fmt_line(
"{} ret_{} = 0.0;", type, name);
219 printer->fmt_line(
"int ret_{} = 0;", name);
223 printer->fmt_line(
"return ret_{};", name);
224 printer->pop_block();
231 if (info.function_uses_table(name)) {
232 throw std::runtime_error(
"Function tables not implemented.");
234 print_function_or_procedure(node, name);
240 print_function_procedure_helper(node);
248 std::string return_var;
249 if (info.function_uses_table(name)) {
250 throw std::runtime_error(
"Function tables not implemented.");
252 return_var =
"ret_" + name;
260 print_function_procedure_helper(node);
264 const ast::Block* function_or_procedure_block,
269 const auto block_name = function_or_procedure_block->
get_node_name();
270 if (info.point_process) {
271 printer->fmt_push_block(
"static double _hoc_{}(void* _vptr)", block_name);
273 printer->fmt_push_block(
"static void _hoc_{}(void)", block_name);
275 printer->fmt_push_block(
"static double _npy_{}(Prop* _prop)", block_name);
277 printer->add_multi_line(R
"CODE(
283 if (info.point_process) {
284 printer->add_multi_line(R
"CODE(
285 auto* const _pnt = static_cast<Point_process*>(_vptr);
286 auto* const _p = _pnt->prop;
288 hoc_execerror("POINT_PROCESS data instance not valid", NULL);
290 _nrn_mechanism_cache_instance _ml_real{_p};
291 auto* const _ml = &_ml_real;
293 _ppvar = _nrn_mechanism_access_dparam(_p);
294 _thread = _extcall_thread.data();
295 _nt = static_cast<NrnThread*>(_pnt->_vnt);
298 if (program_symtab->lookup(block_name)->has_all_properties(NmodlType::use_range_ptr_var)) {
299 printer->push_block(
"if (!_prop_id)");
301 "hoc_execerror(\"No data for {}_{}. Requires prior call to setdata_{} and that the "
302 "specified mechanism instance still be in existence.\", NULL);",
306 printer->pop_block();
307 printer->add_line(
"Prop* _local_prop = _extcall_prop;");
309 printer->add_line(
"Prop* _local_prop = _prop_id ? _extcall_prop : nullptr;");
311 printer->add_multi_line(R
"CODE(
312 _nrn_mechanism_cache_instance _ml_real{_local_prop};
313 auto* const _ml = &_ml_real;
315 _ppvar = _local_prop ? _nrn_mechanism_access_dparam(_local_prop) : nullptr;
316 _thread = _extcall_thread.data();
320 printer->add_multi_line(R
"CODE(
321 _nrn_mechanism_cache_instance _ml_real{_prop};
322 auto* const _ml = &_ml_real;
324 _ppvar = _nrn_mechanism_access_dparam(_prop);
325 _thread = _extcall_thread.data();
329 printer->fmt_line("auto inst = make_instance_{}(_ml_real);", info.mod_suffix);
330 if (info.function_uses_table(block_name)) {
331 printer->fmt_line(
"_check_{}({})", block_name, internal_method_arguments());
333 const auto get_func_call_str = [&]() {
334 const auto params = function_or_procedure_block->
get_parameters();
335 const auto func_proc_name = block_name +
"_" + info.mod_suffix;
336 auto func_call = fmt::format(
"{}({}", func_proc_name, internal_method_arguments());
337 for (
int i = 0; i < params.size(); ++i) {
338 func_call.append(fmt::format(
", *getarg({})", i + 1));
340 func_call.append(
")");
344 printer->add_indent();
345 printer->fmt_text(
"_r = {};", get_func_call_str());
346 printer->add_newline();
348 printer->add_line(
"_r = 1.;");
349 printer->fmt_line(
"{};", get_func_call_str());
352 printer->add_line(
"return(_r);");
354 printer->add_line(
"hoc_retpushx(_r);");
356 printer->pop_block();
361 for (
const auto& procedure: info.procedures) {
365 for (
const auto&
function: info.functions) {
378 return "_ml, inst, id, _ppvar, _thread, _nt";
384 params.emplace_back(
"",
"_nrn_mechanism_cache_range*",
"",
"_ml");
385 params.emplace_back(
"", fmt::format(
"{}&", instance_struct()),
"",
"inst");
386 params.emplace_back(
"",
"size_t",
"",
"id");
387 params.emplace_back(
"",
"Datum*",
"",
"_ppvar");
388 params.emplace_back(
"",
"Datum*",
"",
"_thread");
389 params.emplace_back(
"",
"NrnThread*",
"",
"_nt");
431 const std::string& function_or_procedure_name)
const {
432 return fmt::format(
"_hoc_{}", function_or_procedure_name);
437 const std::string& function_or_procedure_name)
const {
438 return fmt::format(
"static {} {}(void{})",
439 info.point_process ?
"double" :
"void",
440 hoc_function_name(function_or_procedure_name),
441 info.point_process ?
"*" :
"");
446 const std::string& function_or_procedure_name)
const {
447 return fmt::format(
"_npy_{}", function_or_procedure_name);
452 const std::string& function_or_procedure_name)
const {
453 return fmt::format(
"static double {}(Prop*)", py_function_name(function_or_procedure_name));
463 printer->add_newline(2);
464 printer->push_block(
"namespace neuron");
469 printer->pop_block();
474 const std::string& concentration,
487 bool use_instance)
const {
488 auto name = symbol->get_name();
489 auto dimension = symbol->get_length();
491 if (symbol->is_array()) {
493 return fmt::format(
"(inst.{}+id*{})", name, dimension);
495 throw std::runtime_error(
"Printing non-instance variables is not implemented.");
499 return fmt::format(
"inst.{}[id]", name);
501 throw std::runtime_error(
"Not implemented.");
508 const std::string& name,
509 bool use_instance)
const {
510 auto position = position_of_int_var(name);
513 throw std::runtime_error(
"Not implemented. [wiejo]");
516 throw std::runtime_error(
"Not implemented. [ncuwi]");
521 throw std::runtime_error(
"Not implemented. [cnuoe]");
524 throw std::runtime_error(
"Not implemented. [u32ow]");
528 return fmt::format(
"(*inst.{}[id])", name);
531 throw std::runtime_error(
"Not implemented. [nvueir]");
538 bool use_instance)
const {
542 return fmt::format(
"{}.{}", global_struct_instance(), symbol->get_name());
548 bool use_instance)
const {
549 const std::string& varname = update_if_ion_variable_name(name);
551 auto symbol_comparator = [&varname](
const SymbolType& sym) {
552 return varname == sym->get_name();
556 return varname == var.symbol->get_name();
560 auto f = std::find_if(codegen_float_variables.begin(),
561 codegen_float_variables.end(),
563 if (f != codegen_float_variables.end()) {
564 return float_variable_name(*f, use_instance);
569 std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), index_comparator);
570 if (i != codegen_int_variables.end()) {
571 return int_variable_name(*i, varname, use_instance);
575 auto g = std::find_if(codegen_global_variables.begin(),
576 codegen_global_variables.end(),
578 if (g != codegen_global_variables.end()) {
579 return global_variable_name(*g, use_instance);
593 std::find_if(info.neuron_global_variables.begin(),
594 info.neuron_global_variables.end(),
595 [&varname](
auto const& entry) { return entry.first->get_name() == varname; });
596 if (iter != info.neuron_global_variables.end()) {
619 time_t current_time{};
621 std::string data_time_str{std::ctime(¤t_time)};
624 printer->add_line(
"/*********************************************************");
625 printer->add_line(
"Model Name : ", info.mod_suffix);
626 printer->add_line(
"Filename : ", info.mod_file,
".mod");
627 printer->add_line(
"NMODL Version : ", nmodl_version());
628 printer->fmt_line(
"Vectorized : {}", info.vectorize);
629 printer->fmt_line(
"Threadsafe : {}", info.thread_safe);
631 printer->add_line(
"Simulator : ", simulator_name());
632 printer->add_line(
"Backend : ", backend_name());
633 printer->add_line(
"NMODL Compiler : ", version);
634 printer->add_line(
"*********************************************************/");
639 printer->add_newline();
640 printer->add_multi_line(R
"CODE(
645 if (!info.vectorize) {
646 printer->add_line(
"#include <vector>");
652 printer->add_newline();
653 printer->add_multi_line(R
"CODE(
654 #include "mech_api.h"
655 #include "neuron/cache/mechanism_range.hpp"
656 #include "nrniv_mf.h"
657 #include "section_fwd.hpp"
665 printer->add_newline(2);
666 printer->push_block(
"static void _initlists()");
667 for (
auto i = 0; i < info.prime_variables_by_order.size(); ++i) {
668 const auto& prime_var = info.prime_variables_by_order[i];
673 if (prime_var->is_array()) {
677 printer->fmt_push_block(
"for (int _i = 0; _i < {}; ++_i)", prime_var->get_length());
678 printer->fmt_line(
"/* {}[{}] */", prime_var->get_name(), prime_var->get_length());
679 printer->fmt_line(
"_slist1[{}+_i] = {{{}, _i}};",
681 position_of_float_var(prime_var->get_name()));
682 const auto prime_var_deriv_name =
"D" + prime_var->get_name();
683 printer->fmt_line(
"/* {}[{}] */", prime_var_deriv_name, prime_var->get_length());
684 printer->fmt_line(
"_dlist1[{}+_i] = {{{}, _i}};",
686 position_of_float_var(prime_var_deriv_name));
687 printer->pop_block();
689 printer->fmt_line(
"/* {} */", prime_var->get_name());
690 printer->fmt_line(
"_slist1[{}] = {{{}, 0}};",
692 position_of_float_var(prime_var->get_name()));
693 const auto prime_var_deriv_name =
"D" + prime_var->get_name();
694 printer->fmt_line(
"/* {} */", prime_var_deriv_name);
695 printer->fmt_line(
"_dlist1[{}] = {{{}, 0}};",
697 position_of_float_var(prime_var_deriv_name));
700 printer->pop_block();
705 const auto value_initialize = print_initializers ?
"{}" :
"";
708 printer->add_newline(2);
709 printer->add_line(
"/* NEURON global variables */");
710 if (info.primes_size != 0) {
711 printer->fmt_line(
"static neuron::container::field_index _slist1[{0}], _dlist1[{0}];",
715 for (
const auto& ion: info.ions) {
716 printer->fmt_line(
"static Symbol* _{}_sym;", ion.name);
719 printer->add_line(
"static int mech_type;");
721 if (info.point_process) {
722 printer->add_line(
"static int _pointtype;");
724 printer->add_multi_line(R
"CODE(
725 static Prop* _extcall_prop;
726 /* _prop_id kind of shadows _extcall_prop to allow validity checking. */
727 static _nrn_non_owning_id_without_container _prop_id{};)CODE");
730 printer->fmt_line("static int {} = {};",
732 info.pointer_variables.size() > 0
733 ?
static_cast<int>(info.pointer_variables.size())
736 printer->add_line(
"static _nrn_mechanism_std_vector<Datum> _extcall_thread;");
739 auto float_type = default_float_data_type();
740 printer->add_newline(2);
741 printer->add_line(
"/** all global variables */");
742 printer->fmt_push_block(
"struct {}", global_struct());
744 if (!info.ions.empty()) {
748 if (!info.vectorize && !info.top_local_variables.empty()) {
749 throw std::runtime_error(
"Not implemented, global vectorize something.");
752 if (!info.thread_variables.empty()) {
753 throw std::runtime_error(
"Not implemented, global thread variables.");
756 if (info.table_count > 0) {
757 throw std::runtime_error(
"Not implemented, global table count.");
760 for (
const auto& var: info.state_vars) {
761 auto name = var->get_name() +
"0";
762 auto symbol = program_symtab->lookup(name);
763 if (symbol ==
nullptr) {
764 printer->fmt_line(
"{} {}{};", float_type, name, value_initialize);
765 codegen_global_variables.push_back(make_symbol(name));
769 for (
const auto& var: info.global_variables) {
770 auto name = var->get_name();
771 auto length = var->get_length();
772 if (var->is_array()) {
773 printer->fmt_line(
"{} {}[{}] /* TODO init const-array */;", float_type, name, length);
776 if (
auto const& value_ptr = var->get_value()) {
779 printer->fmt_line(
"{} {}{};",
782 print_initializers ? fmt::format(
"{{{:g}}}", value) : std::string{});
784 codegen_global_variables.push_back(var);
788 for (
const auto& f: info.function_tables) {
789 throw std::runtime_error(
"Not implemented, global function tables.");
792 if (info.vectorize && info.thread_data_index) {
793 throw std::runtime_error(
"Not implemented, global vectorize something else.");
796 printer->pop_block(
";");
798 print_global_var_struct_assertions();
799 print_global_var_struct_decl();
806 auto variable_printer =
807 [&](
const std::vector<SymbolType>& variables,
bool if_array,
bool if_vector) {
808 for (
const auto& variable: variables) {
809 if (variable->is_array() == if_array) {
812 auto name = get_variable_name(variable->get_name(),
false);
813 auto ename = add_escape_quote(variable->get_name() +
"_" + info.mod_suffix);
814 auto length = variable->get_length();
816 printer->fmt_line(
"{{{}, {}, {}}},", ename, name, length);
818 printer->fmt_line(
"{{{}, &{}}},", ename, name);
824 auto globals = info.global_variables;
825 auto thread_vars = info.thread_variables;
827 if (info.table_count > 0) {
831 printer->add_newline(2);
832 printer->add_line(
"/** connect global (scalar) variables to hoc -- */");
833 printer->add_line(
"static DoubScal hoc_scalar_double[] = {");
834 printer->increase_indent();
835 variable_printer(globals,
false,
false);
836 variable_printer(thread_vars,
false,
false);
837 printer->add_line(
"{nullptr, nullptr}");
838 printer->decrease_indent();
839 printer->add_line(
"};");
841 printer->add_newline(2);
842 printer->add_line(
"/** connect global (array) variables to hoc -- */");
843 printer->add_line(
"static DoubVec hoc_vector_double[] = {");
844 printer->increase_indent();
845 variable_printer(globals,
true,
true);
846 variable_printer(thread_vars,
true,
true);
847 printer->add_line(
"{nullptr, nullptr, 0}");
848 printer->decrease_indent();
849 printer->add_line(
"};");
851 printer->add_newline(2);
852 printer->add_line(
"/* declaration of user functions */");
853 for (
const auto& procedure: info.procedures) {
854 const auto proc_name = procedure->get_node_name();
855 printer->fmt_line(
"{};", hoc_function_signature(proc_name));
857 for (
const auto&
function: info.functions) {
858 const auto func_name =
function->get_node_name();
859 printer->fmt_line(
"{};", hoc_function_signature(func_name));
861 if (!info.point_process) {
862 for (
const auto& procedure: info.procedures) {
863 const auto proc_name = procedure->get_node_name();
864 printer->fmt_line(
"{};", py_function_signature(proc_name));
866 for (
const auto&
function: info.functions) {
867 const auto func_name =
function->get_node_name();
868 printer->fmt_line(
"{};", py_function_signature(func_name));
872 printer->add_newline(2);
873 printer->add_line(
"/* connect user functions to hoc names */");
874 printer->add_line(
"static VoidFunc hoc_intfunc[] = {");
875 printer->increase_indent();
876 if (info.point_process) {
877 printer->add_line(
"{0, 0}");
878 printer->decrease_indent();
879 printer->add_line(
"};");
880 printer->add_line(
"static Member_func _member_func[] = {");
881 printer->increase_indent();
882 printer->add_multi_line(R
"CODE(
883 {"loc", _hoc_loc_pnt},
884 {"has_loc", _hoc_has_loc},
885 {"get_loc", _hoc_get_loc_pnt},)CODE");
887 printer->fmt_line(
"{{\"setdata_{}\", _hoc_setdata}},", info.mod_suffix);
890 for (
const auto& procedure: info.procedures) {
891 const auto proc_name = procedure->get_node_name();
892 printer->fmt_line(
"{{\"{}{}\", {}}},",
895 hoc_function_name(proc_name));
897 for (
const auto&
function: info.functions) {
898 const auto func_name =
function->get_node_name();
899 printer->fmt_line(
"{{\"{}{}\", {}}},",
902 hoc_function_name(func_name));
905 printer->add_line(
"{0, 0}");
906 printer->decrease_indent();
907 printer->add_line(
"};");
908 if (!info.point_process) {
909 printer->push_block(
"static NPyDirectMechFunc npy_direct_func_proc[] =");
910 for (
const auto& procedure: info.procedures) {
911 const auto proc_name = procedure->get_node_name();
912 printer->fmt_line(
"{{\"{}\", {}}},", proc_name, py_function_name(proc_name));
914 for (
const auto&
function: info.functions) {
915 const auto func_name =
function->get_node_name();
916 printer->fmt_line(
"{{\"{}\", {}}},", func_name, py_function_name(func_name));
918 printer->pop_block(
";");
924 printer->add_newline(2);
925 printer->add_line(
"/** register channel with the simulator */");
926 printer->fmt_push_block(
"extern \"C\" void _{}_reg()", info.mod_file);
927 printer->add_line(
"_initlists();");
929 printer->add_newline();
931 for (
const auto& ion: info.ions) {
932 printer->fmt_line(
"ion_reg(\"{}\", {});", ion.name,
"-10000.");
934 printer->add_newline();
936 if (info.diam_used) {
937 printer->add_line(
"_morphology_sym = hoc_lookup(\"morphology\");");
938 printer->add_newline();
941 for (
const auto& ion: info.ions) {
942 printer->fmt_line(
"_{0}_sym = hoc_lookup(\"{0}_ion\");", ion.name);
945 printer->add_newline();
947 const auto compute_functions_parameters =
949 ? fmt::format(
"{}, {}, {}",
953 :
"nullptr, nullptr, nullptr";
954 const auto register_mech_args = fmt::format(
"{}, {}, {}, {}, {}, {}",
955 get_channel_info_var_name(),
957 compute_functions_parameters,
960 1 + info.thread_data_index);
961 if (info.point_process) {
963 "_pointtype = point_register_mech({}, _hoc_create_pnt, _hoc_destroy_pnt, "
967 printer->fmt_line(
"register_mech({});", register_mech_args);
971 printer->add_newline();
972 printer->fmt_line(
"mech_type = nrn_get_mechtype({}[1]);", get_channel_info_var_name());
983 printer->add_line(
"_nrn_mechanism_register_data_fields(mech_type,");
984 printer->increase_indent();
986 const auto codegen_float_variables_size = codegen_float_variables.size();
987 std::vector<std::string> mech_register_args;
989 for (
int i = 0; i < codegen_float_variables_size; ++i) {
990 const auto& float_var = codegen_float_variables[i];
991 if (float_var->is_array()) {
992 mech_register_args.push_back(
993 fmt::format(
"_nrn_mechanism_field<double>{{\"{}\", {}}} /* {} */",
994 float_var->get_name(),
995 float_var->get_length(),
998 mech_register_args.push_back(fmt::format(
999 "_nrn_mechanism_field<double>{{\"{}\"}} /* {} */", float_var->get_name(), i));
1003 const auto codegen_int_variables_size = codegen_int_variables.size();
1004 for (
int i = 0; i < codegen_int_variables_size; ++i) {
1005 const auto& int_var = codegen_int_variables[i];
1006 const auto& name = int_var.symbol->get_name();
1007 if (i != info.semantics[i].index) {
1008 throw std::runtime_error(
"Broken logic.");
1012 mech_register_args.push_back(
1013 fmt::format(
"_nrn_mechanism_field<{}>{{\"{}\", \"{}\"}} /* {} */",
1016 info.semantics[i].name,
1019 if (info.emit_cvode) {
1020 mech_register_args.push_back(
1021 "_nrn_mechanism_field<int>{\"_cvode_ieq\", \"cvodeieq\"} /* 0 */");
1024 printer->add_multi_line(fmt::format(
"{}", fmt::join(mech_register_args,
",\n")));
1026 printer->decrease_indent();
1027 printer->add_line(
");");
1028 printer->add_newline();
1030 printer->fmt_line(
"hoc_register_prop_size(mech_type, {}, {});",
1031 codegen_float_variables_size,
1032 codegen_int_variables_size);
1034 for (
int i = 0; i < codegen_int_variables_size; ++i) {
1035 const auto& int_var = codegen_int_variables[i];
1036 const auto& name = int_var.symbol->get_name();
1037 if (i != info.semantics[i].index) {
1038 throw std::runtime_error(
"Broken logic.");
1041 printer->fmt_line(
"hoc_register_dparam_semantics(mech_type, {}, \"{}\");",
1043 info.semantics[i].name);
1046 printer->add_line(
"hoc_register_var(hoc_scalar_double, hoc_vector_double, hoc_intfunc);");
1047 if (!info.point_process) {
1048 printer->add_line(
"hoc_register_npy_direct(mech_type, npy_direct_func_proc);");
1050 printer->pop_block();
1055 auto const value_initialize = print_initializers ?
"{}" :
"";
1056 auto int_type = default_int_data_type();
1057 printer->add_newline(2);
1058 printer->add_line(
"/** all mechanism instance variables and global variables */");
1059 printer->fmt_push_block(
"struct {} ", instance_struct());
1061 for (
auto const& [var, type]: info.neuron_global_variables) {
1062 auto const name = var->get_name();
1063 printer->fmt_line(
"{}* {}{};",
1066 print_initializers ? fmt::format(
"{{&coreneuron::{}}}", name)
1069 for (
auto& var: codegen_float_variables) {
1070 const auto& name = var->get_name();
1071 printer->fmt_line(
"double* {}{};", name, value_initialize);
1073 for (
auto& var: codegen_int_variables) {
1074 const auto& name = var.symbol->get_name();
1077 }
else if (var.is_index || var.is_integer) {
1078 auto qualifier = var.is_constant ?
"const " :
"";
1079 printer->fmt_line(
"{}{}* const* {}{};", qualifier, int_type, name, value_initialize);
1081 auto qualifier = var.is_constant ?
"const " :
"";
1082 auto type = var.is_vdata ?
"void*" : default_float_data_type();
1083 printer->fmt_line(
"{}{}* const* {}{};", qualifier, type, name, value_initialize);
1087 printer->fmt_line(
"{}* {}{};",
1090 print_initializers ? fmt::format(
"{{&{}}}", global_struct_instance())
1092 printer->pop_block(
";");
1096 printer->add_newline(2);
1097 printer->fmt_push_block(
"static {} make_instance_{}(_nrn_mechanism_cache_range& _ml)",
1100 printer->fmt_push_block(
"return {}", instance_struct());
1102 std::vector<std::string> make_instance_args;
1104 const auto codegen_float_variables_size = codegen_float_variables.size();
1105 for (
int i = 0; i < codegen_float_variables_size; ++i) {
1106 const auto& float_var = codegen_float_variables[i];
1107 if (float_var->is_array()) {
1108 make_instance_args.push_back(
1109 fmt::format(
"_ml.template data_array_ptr<{}, {}>()", i, float_var->get_length()));
1111 make_instance_args.push_back(fmt::format(
"_ml.template fpfield_ptr<{}>()", i));
1115 const auto codegen_int_variables_size = codegen_int_variables.size();
1116 for (
size_t i = 0; i < codegen_int_variables_size; ++i) {
1117 const auto& var = codegen_int_variables[i];
1118 auto name = var.symbol->get_name();
1119 auto const variable = [&var, i]() -> std::string {
1120 if (var.is_index || var.is_integer) {
1122 }
else if (var.is_vdata) {
1125 return fmt::format(
"_ml.template dptr_field_ptr<{}>()", i);
1128 if (variable !=
"") {
1129 make_instance_args.push_back(variable);
1133 printer->add_multi_line(fmt::format(
"{}", fmt::join(make_instance_args,
",\n")));
1135 printer->pop_block(
";");
1136 printer->pop_block();
1140 auto const value_initialize = print_initializers ?
"{}" :
"";
1141 printer->add_newline(2);
1142 printer->fmt_push_block(
"struct {} ", node_data_struct());
1145 printer->add_line(
"int const * nodeindices;");
1146 printer->add_line(
"double const * node_voltages;");
1147 printer->add_line(
"double * node_rhs;");
1148 printer->add_line(
"int nodecount;");
1150 printer->pop_block(
";");
1154 printer->add_newline(2);
1155 printer->fmt_push_block(
"static {} make_node_data_{}(NrnThread& _nt, Memb_list& _ml_arg)",
1159 std::vector<std::string> make_node_data_args;
1160 make_node_data_args.push_back(
"_ml_arg.nodeindices");
1161 make_node_data_args.push_back(
"_nt.node_voltage_storage()");
1162 make_node_data_args.push_back(
"_nt.node_rhs_storage()");
1163 make_node_data_args.push_back(
"_ml_arg.nodecount");
1165 printer->fmt_push_block(
"return {}", node_data_struct());
1166 printer->add_multi_line(fmt::format(
"{}", fmt::join(make_node_data_args,
",\n")));
1168 printer->pop_block(
";");
1169 printer->pop_block();
1176 for (
auto& statement: read_statements) {
1177 printer->add_line(statement);
1181 if (node !=
nullptr) {
1183 print_statement_block(*block,
false,
false);
1188 for (
auto& statement: write_statements) {
1190 printer->add_line(text);
1196 const std::string& function_name) {
1197 std::string method = function_name.empty() ? compute_method_name(type) : function_name;
1199 "_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, Memb_list* _ml_arg, int "
1201 printer->fmt_push_block(
"void {}({})", method, args);
1203 printer->add_line(
"_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};");
1204 printer->fmt_line(
"auto inst = make_instance_{}(_lmr);", info.mod_suffix);
1205 printer->fmt_line(
"auto node_data = make_node_data_{}(*_nt, *_ml_arg);", info.mod_suffix);
1207 printer->add_line(
"auto nodecount = _ml_arg->nodecount;");
1212 printer->add_newline(2);
1216 printer->push_block(
"for (int id = 0; id < nodecount; id++)");
1217 print_initial_block(info.initial_node);
1218 printer->pop_block();
1220 printer->pop_block();
1224 printer->add_newline(2);
1225 printer->add_line(
"/** nrn_jacob function */");
1228 "static void {}(_nrn_model_sorted_token const& _sorted_token, NrnThread* "
1229 "_nt, Memb_list* _ml_arg, int _type) {{}}",
1248 printer->add_newline(2);
1251 printer->fmt_push_block(
"static void {}(Prop* _prop)", method);
1252 printer->add_multi_line(R
"CODE(
1257 if (info.point_process) {
1258 printer->push_block(
"if (nrn_point_prop_)");
1259 printer->add_multi_line(R
"CODE(
1260 _nrn_mechanism_access_alloc_seq(_prop) = _nrn_mechanism_access_alloc_seq(nrn_point_prop_);
1261 _ppvar = _nrn_mechanism_access_dparam(nrn_point_prop_);
1263 printer->chain_block("else");
1265 if (info.semantic_variable_count) {
1266 printer->fmt_line(
"_ppvar = nrn_prop_datum_alloc(mech_type, {}, _prop);",
1267 info.semantic_variable_count);
1268 printer->add_line(
"_nrn_mechanism_access_dparam(_prop) = _ppvar;");
1270 printer->add_multi_line(R
"CODE(
1271 _nrn_mechanism_cache_instance _ml_real{_prop};
1272 auto* const _ml = &_ml_real;
1273 size_t const _iml{};
1275 printer->fmt_line("assert(_nrn_mechanism_get_num_vars(_prop) == {});",
1276 codegen_float_variables.size());
1277 if (float_variables_size()) {
1278 printer->add_line(
"/*initialize range parameters*/");
1279 for (
const auto& var: info.range_parameter_vars) {
1280 if (var->is_array()) {
1283 const auto& var_name = var->get_name();
1284 printer->fmt_line(
"_ml->template fpfield<{}>(_iml) = {}; /* {} */",
1285 position_of_float_var(var_name),
1290 if (info.point_process) {
1291 printer->pop_block();
1294 if (info.semantic_variable_count) {
1295 printer->add_line(
"_nrn_mechanism_access_dparam(_prop) = _ppvar;");
1298 if (info.diam_used) {
1299 throw std::runtime_error(
"Diam allocation not implemented.");
1302 if (info.area_used) {
1303 throw std::runtime_error(
"Area allocation not implemented.");
1306 const auto codegen_int_variables_size = codegen_int_variables.size();
1308 for (
const auto& ion: info.ions) {
1309 printer->fmt_line(
"Symbol * {}_sym = hoc_lookup(\"{}_ion\");", ion.name, ion.name);
1310 printer->fmt_line(
"Prop * {}_prop = need_memb({}_sym);", ion.name, ion.name);
1312 for (
size_t i = 0; i < codegen_int_variables_size; ++i) {
1313 const auto& var = codegen_int_variables[i];
1316 const std::string& var_name = var.symbol->get_name();
1317 if (var_name.rfind(
"ion_", 0) != 0) {
1321 std::string ion_var_name = std::string(var_name.begin() + 4, var_name.end());
1322 if (ion.is_ionic_variable(ion_var_name)) {
1323 printer->fmt_line(
"_ppvar[{}] = _nrn_mechanism_get_param_handle({}_prop, {});",
1326 ion.variable_index(ion_var_name));
1334 printer->pop_block();
1345 if (!nrn_state_required()) {
1349 printer->add_newline(2);
1352 printer->push_block(
"for (int id = 0; id < nodecount; id++)");
1358 if (ion_variable_struct_required()) {
1359 throw std::runtime_error(
"Not implemented.");
1363 for (
auto& statement: read_statements) {
1364 printer->add_line(statement);
1367 if (info.nrn_state_block) {
1368 info.nrn_state_block->visit_children(*
this);
1371 if (info.currents.empty() && info.breakpoint_node !=
nullptr) {
1372 auto block = info.breakpoint_node->get_statement_block();
1373 print_statement_block(*block,
false,
false);
1377 for (
auto& statement: write_statements) {
1378 const auto& text = process_shadow_update_statement(statement,
BlockType::State);
1379 printer->add_line(text);
1382 printer->pop_block();
1383 printer->pop_block();
1392 if (ion_variable_struct_required()) {
1393 throw std::runtime_error(
"Not implemented.");
1395 return "id, inst, node_data, v";
1400 if (ion_variable_struct_required()) {
1401 throw std::runtime_error(
"Not implemented.");
1405 params.emplace_back(
"",
"size_t",
"",
"id");
1406 params.emplace_back(
"", fmt::format(
"{}&", instance_struct()),
"",
"inst");
1407 params.emplace_back(
"", fmt::format(
"{}&", node_data_struct()),
"",
"node_data");
1408 params.emplace_back(
"",
"double",
"",
"v");
1415 const auto& args = nrn_current_parameters();
1417 printer->add_newline(2);
1419 printer->fmt_push_block(
"inline double nrn_current_{}({})",
1421 get_parameter_str(args));
1422 printer->add_line(
"double current = 0.0;");
1423 print_statement_block(*block,
false,
false);
1424 for (
auto& current: info.currents) {
1425 const auto& name = get_variable_name(current);
1426 printer->fmt_line(
"current += {};", name);
1428 printer->add_line(
"return current;");
1429 printer->pop_block();
1436 print_statement_block(*block,
false,
false);
1437 if (!info.currents.empty()) {
1439 for (
const auto& current: info.currents) {
1440 auto var = breakpoint_current(current);
1441 sum += get_variable_name(var);
1442 if (¤t != &info.currents.back()) {
1446 printer->fmt_line(
"double rhs = {};", sum);
1450 for (
const auto& conductance: info.conductances) {
1451 auto var = breakpoint_current(conductance.variable);
1452 sum += get_variable_name(var);
1453 if (&conductance != &info.conductances.back()) {
1457 printer->fmt_line(
"double g = {};", sum);
1459 for (
const auto& conductance: info.conductances) {
1460 if (!conductance.ion.empty()) {
1463 const auto& rhs = get_variable_name(conductance.variable);
1466 printer->add_line(text);
1474 printer->fmt_line(
"double I1 = nrn_current_{}({}+0.001);",
1476 nrn_current_arguments());
1477 for (
auto& ion: info.ions) {
1478 for (
auto& var: ion.writes) {
1479 if (ion.is_ionic_current(var)) {
1480 const auto& name = get_variable_name(var);
1481 printer->fmt_line(
"double di{} = {};", ion.name, name);
1485 printer->fmt_line(
"double I0 = nrn_current_{}({});", info.mod_suffix, nrn_current_arguments());
1486 printer->add_line(
"double rhs = I0;");
1488 printer->add_line(
"double g = (I1-I0)/0.001;");
1489 for (
auto& ion: info.ions) {
1490 for (
auto& var: ion.writes) {
1491 if (ion.is_ionic_current(var)) {
1493 auto rhs = fmt::format(
"(di{}-{})/0.001", ion.name, get_variable_name(var));
1494 if (info.point_process) {
1496 rhs += fmt::format(
"*1.e2/{}", area);
1500 printer->add_line(text);
1509 printer->add_line(
"int node_id = node_data.nodeindices[id];");
1510 printer->add_line(
"double v = node_data.node_voltages[node_id];");
1513 for (
auto& statement: read_statements) {
1514 printer->add_line(statement);
1517 if (info.conductances.empty()) {
1518 print_nrn_cur_non_conductance_kernel();
1520 print_nrn_cur_conductance_kernel(node);
1524 for (
auto& statement: write_statements) {
1526 printer->add_line(text);
1529 if (info.point_process) {
1531 printer->fmt_line(
"double mfactor = 1.e2/{};", area);
1532 printer->add_line(
"g = g*mfactor;");
1533 printer->add_line(
"rhs = rhs*mfactor;");
1548 if (!nrn_cur_required()) {
1552 if (info.conductances.empty()) {
1553 print_nrn_current(*info.breakpoint_node);
1556 printer->add_newline(2);
1557 printer->add_line(
"/** update current */");
1560 printer->push_block(
"for (int id = 0; id < nodecount; id++)");
1561 print_nrn_cur_kernel(*info.breakpoint_node);
1568 printer->add_line(
"node_data.node_rhs[node_id] -= rhs;");
1571 printer->pop_block();
1581 printer->pop_block();
1590 print_standard_includes();
1591 print_neuron_includes();
1596 print_global_macros();
1597 print_mechanism_variables_macros();
1602 printer->add_newline();
1603 printer->add_line(
"/* NEURON global macro definitions */");
1604 if (info.vectorize) {
1605 printer->add_multi_line(R
"CODE(
1607 #define NRN_VECTORIZED 1
1610 printer->add_multi_line(R
"CODE(
1611 /* NOT VECTORIZED */
1612 #define NRN_VECTORIZED 0
1619 printer->add_newline();
1620 printer->add_line(
"static constexpr auto number_of_datum_variables = ",
1623 printer->add_line(
"static constexpr auto number_of_floating_point_variables = ",
1626 printer->add_newline();
1627 printer->add_multi_line(R
"CODE(
1629 template <typename T>
1630 using _nrn_mechanism_std_vector = std::vector<T>;
1631 using _nrn_model_sorted_token = neuron::model_sorted_token;
1632 using _nrn_mechanism_cache_range = neuron::cache::MechanismRange<number_of_floating_point_variables, number_of_datum_variables>;
1633 using _nrn_mechanism_cache_instance = neuron::cache::MechanismInstance<number_of_floating_point_variables, number_of_datum_variables>;
1634 using _nrn_non_owning_id_without_container = neuron::container::non_owning_identifier_without_container;
1635 template <typename T>
1636 using _nrn_mechanism_field = neuron::mechanism::field<T>;
1637 template <typename... Args>
1638 void _nrn_mechanism_register_data_fields(Args&&... args) {
1639 neuron::mechanism::register_data_fields(std::forward<Args>(args)...);
1644 if (info.point_process) {
1645 printer->add_line(
"extern Prop* nrn_point_prop_;");
1647 printer->add_line(
"Prop* hoc_getdata_range(int type);");
1654 print_namespace_start();
1659 print_namespace_stop();
1664 print_mechanism_global_var_structure(print_initializers);
1665 print_mechanism_range_var_structure(print_initializers);
1666 print_node_data_structure(print_initializers);
1667 print_make_instance();
1668 print_make_node_data();
1673 if (!info.vectorize) {
1676 printer->add_multi_line(R
"CODE(
1678 inst->v_unused[id] = v;
1685 printer->add_multi_line(R
"CODE(
1687 inst->g_unused[id] = g;
1695 print_hoc_py_wrapper_function_definitions();
1696 for (
const auto& procedure: info.procedures) {
1697 print_procedure(*procedure);
1699 for (
const auto&
function: info.functions) {
1700 print_function(*
function);
1711 print_backend_info();
1712 print_headers_include();
1713 print_macro_definitions();
1714 print_namespace_begin();
1715 print_nmodl_constants();
1716 print_prcellstate_macros();
1717 print_mechanism_info();
1718 print_data_structures(
true);
1720 print_function_prototypes();
1721 print_global_variables_for_hoc();
1722 print_compute_functions();
1723 print_sdlists_init(
true);
1724 print_mechanism_register();
1725 print_namespace_end();
1729 throw std::runtime_error(
"Not implemented.");
1733 throw std::runtime_error(
"Not implemented.");
1737 throw std::runtime_error(
"Not implemented.");