1 #include <../../nrnconf.h>
75 namespace fs = std::filesystem;
76 #define GETWD(buf) getcwd(buf, NRN_BUFSIZE)
145 int iontype(
char* s1,
char* s2);
175 #define SYMITER(arg) \
176 ITERATE(q, syminorder) { \
180 #define SYMLISTITER \
181 for (i = 'A'; i <= 'z'; i++) \
182 ITERATE(q, symlist[i])
208 int i, ioncount, pointercount, gind, emit_check_table_thread;
223 if (*modbase ==
'\\' || *modbase ==
'/') {
231 }
else if (strcmp(
mechname,
"nothing") == 0) {
244 "Notice: ARTIFICIAL_CELL models that would require thread specific data are not "
258 \n#define exp hoc_Exp\
259 \n#if NRN_ENABLE_ARCH_INDEP_EXP_POW\
261 \n#define pow hoc_pow\
273 #define nrn_init _nrn_init_%s\n\
274 #define _nrn_initial _nrn_initial_%s\n\
275 #define nrn_cur _nrn_cur_%s\n\
276 #define _nrn_current _nrn_current_%s\n\
277 #define nrn_jacob _nrn_jacob_%s\n\
278 #define nrn_state _nrn_state_%s\n\
279 #define _net_receive _net_receive_%s\
303 #define _threadargscomma_ _ml, _iml, _ppvar, _thread, _globals, _nt,\n\
304 #define _threadargsprotocomma_ Memb_list* _ml, size_t _iml, Datum* _ppvar, Datum* _thread, double* _globals, NrnThread* _nt,\n\
305 #define _internalthreadargsprotocomma_ _nrn_mechanism_cache_range* _ml, size_t _iml, Datum* _ppvar, Datum* _thread, double* _globals, NrnThread* _nt,\n\
306 #define _threadargs_ _ml, _iml, _ppvar, _thread, _globals, _nt\n\
307 #define _threadargsproto_ Memb_list* _ml, size_t _iml, Datum* _ppvar, Datum* _thread, double* _globals, NrnThread* _nt\n\
308 #define _internalthreadargsproto_ _nrn_mechanism_cache_range* _ml, size_t _iml, Datum* _ppvar, Datum* _thread, double* _globals, NrnThread* _nt\n\
313 #define _threadargscomma_ /**/\n\
314 #define _threadargsprotocomma_ /**/\n\
315 #define _internalthreadargsprotocomma_ /**/\n\
316 #define _threadargs_ /**/\n\
317 #define _threadargsproto_ /**/\n\
318 #define _internalthreadargsproto_ /**/\n\
334 ioncount =
iondef(&pointercount);
336 Sprintf(
buf,
"/* Thread safe. No static _ml, _iml or _ppvar. */\n");
339 "static _nrn_mechanism_cache_instance _ml_real{nullptr};\n"
340 "static _nrn_mechanism_cache_range *_ml{&_ml_real};\n"
341 "static size_t _iml{0};\n"
342 "static Datum *_ppvar;\n");
361 "/* _prop_id kind of shadows _extcall_prop to allow validity checking. */\n");
369 if (strcmp(
s->name,
"dt") == 0) {
372 if (strcmp(
s->name,
"t") == 0) {
389 Sprintf(
buf,
"static double _hoc_%s(void*);\n",
s->name);
391 Sprintf(
buf,
"static void _hoc_%s(void);\n",
s->name);
398 "static int _mechtype;\n\
399 extern void _nrn_cacheloop_reg(int, int);\n\
400 extern void hoc_register_limits(int, HocParmLimits*);\n\
401 extern void hoc_register_units(int, HocParmUnits*);\n\
402 extern void nrn_promote(Prop*, int, int);\n\
408 "#define NMODL_TEXT 1\n"
410 "static void register_nmodl_text_and_filename(int mechtype);\n"
419 "static void* _hoc_create_pnt(Object* _ho) { void* create_point_process(int, "
425 "static double _hoc_loc_pnt(void* _vptr) {double loc_point_process(int, void*);\n");
428 "static double _hoc_has_loc(void* _vptr) {double has_loc_point(void*);\n");
433 "double get_loc_point_process(void*); return (get_loc_point_process(_vptr));\n}\n");
437 Sprintf(
buf,
"static void _hoc_setdata(%s);\n", hoc_setdata_arg.c_str());
448 Sprintf(
buf,
"{\"has_loc\", _hoc_has_loc},\n");
450 Sprintf(
buf,
"{\"get_loc\", _hoc_get_loc_pnt},\n");
469 "\n/* Direct Python call wrappers to density mechanism functions.*/\n");
473 Sprintf(
buf,
"static double _npy_%s(Prop*);\n",
s->name,
s->name);
479 "static NPyDirectMechFunc npy_direct_func_proc[] = {\n");
497 if ((
s->subtype &
FUNCT)) {
506 if ((
s->subtype &
FUNCT)) {
516 for (
j = 0;
j <
s->varnum; ++
j) {
518 if (
j + 1 <
s->varnum) {
532 if (
SYM(
q)->assigned_to_ != 2) {
541 " _thread[%d] = {neuron::container::do_not_search, new double[%d]{}};\n",
549 if (
SYM(
q)->assigned_to_ != 2) {
552 "#define %s (_thread[%d].get<double*>() + %d)\n",
559 "#define %s _thread[%d].get<double*>()[%d]\n",
581 if (
s->nrntype & (
NRNGLOBAL) &&
s->assigned_to_ == 1) {
600 "static int _thread1data_inuse = 0;\nstatic double _thread1data[%d];\n#define _gth "
606 "if (_thread1data_inuse) {\n"
607 " _thread[_gth] = {neuron::container::do_not_search, new double[%d]{}};\n"
609 " _thread[_gth] = {neuron::container::do_not_search, _thread1data};\n"
610 " _thread1data_inuse = 1;\n"
615 " if (_thread[_gth].get<double*>() == _thread1data) {\n "
616 "_thread1data_inuse = 0;\n "
617 "}else{\n delete[] _thread[_gth].get<double*>();\n }\n");
627 "#define %s%s (_thread1data + %d)\n\
628 #define %s (_globals + %d)\n",
636 "#define %s%s _thread1data[%d]\n\
637 #define %s _globals[%d]\n",
668 emit_check_table_thread = 0;
670 emit_check_table_thread = 1;
677 if (
s->subtype &
PARM) {
678 double d1 = 0., d2 = 0.;
683 Sprintf(
buf,
"{\"%s\", %g, %g},\n",
s->name, d1, d2);
698 Sprintf(
buf,
"static double %s[%d];\n",
s->name,
s->araydim);
700 Sprintf(
buf,
"static double %s = %g;\n",
s->name, d1);
730 "static void _ba%d(Node*_nd, Datum* _ppd, Datum* _thread, NrnThread* _nt, "
731 "Memb_list* _ml, size_t _iml, _nrn_model_sorted_token const&);\n",
746 "neuron::legacy::set_globals_from_prop(_prop, _ml_real, _ml, _iml);\n"
747 "_ppvar = _nrn_mechanism_access_dparam(_prop);\n");
750 "Node * _node = _nrn_mechanism_access_node(_prop);\n"
751 "v = _nrn_mechanism_access_voltage(_node);\n");
761 "static void _hoc_setdata() {\n Prop *_prop, *hoc_getdata_range(int);\n");
762 Sprintf(
buf,
"_prop = hoc_getdata_range(_mechtype);\n");
778 "static void nrn_alloc(Prop*);\n"
779 "static void nrn_init(_nrn_model_sorted_token const&, NrnThread*, Memb_list*, int);\n"
780 "static void nrn_state(_nrn_model_sorted_token const&, NrnThread*, Memb_list*, int);\n");
784 "static void nrn_cur(_nrn_model_sorted_token const&, NrnThread*, Memb_list*, int);\n"
785 "static void nrn_jacob(_nrn_model_sorted_token const&, NrnThread*, "
786 "Memb_list*, int);\n");
832 " if (_prop) { _nrn_free_watch(_nrn_mechanism_access_dparam(_prop), "
841 "_nrn_free_fornetcon(&(_nrn_mechanism_access_dparam(_prop)[_fnc_index]"
842 ".literal_value<void*>()));}\n");
855 diag(
"DESTRUCTOR only permitted for POINT_PROCESS", (
char*) 0);
865 "/* connect range variables in _p that hoc is supposed to know about */\n");
868 static const char *_mechanism[] = {\n\
932 q =
q->next->next->next;
940 "extern Prop* need_memb(Symbol*);\n"
941 "static void nrn_alloc(Prop* _prop) {\n"
942 " Prop *prop_ion{};\n"
943 " Datum *_ppvar{};\n");
946 " if (nrn_point_prop_) {\n"
947 " _nrn_mechanism_access_alloc_seq(_prop) = "
948 "_nrn_mechanism_access_alloc_seq(nrn_point_prop_);\n"
949 " _ppvar = _nrn_mechanism_access_dparam(nrn_point_prop_);\n"
961 " _nrn_mechanism_cache_instance _ml_real{_prop};\n"
962 " auto* const _ml = &_ml_real;\n"
963 " size_t const _iml{};\n"
964 " assert(_nrn_mechanism_get_num_vars(_prop) == %d);\n",
981 Sprintf(
buf,
" %s = _parm_default[%d]; /* %g */\n",
s->name,
i, d1);
1001 Sprintf(
buf,
"prop_ion = need_memb(_morphology_sym);\n");
1004 "\t_ppvar[%d] = _nrn_mechanism_get_param_handle(prop_ion, 0); /* diam */\n",
1005 ioncount + pointercount),
1011 "\t_ppvar[%d] = _nrn_mechanism_get_area_handle(nrn_alloc_node_);\n",
1012 ioncount + pointercount +
diamdec),
1029 Sprintf(
buf,
" _type_i%s = _nrn_mechanism_get_type(prop_ion);\n", sion->
name);
1037 "\t_ppvar[%d] = _nrn_mechanism_get_param_handle(prop_ion, %d); /* %s */\n",
1051 "\t_ppvar[%d] = _nrn_mechanism_get_param_handle(prop_ion, %d); /* %s */\n",
1060 "\t_ppvar[%d] = _nrn_mechanism_get_param_handle(prop_ion, %d); /* "
1073 "\t_ppvar[%d] = _nrn_mechanism_get_param_handle(prop_ion, %d); // erev %s\n",
1079 "\t_ppvar[%d] = {neuron::container::do_not_search, "
1080 "&(_nrn_mechanism_access_dparam(prop_ion)[0].literal_value<int>())}; /* "
1081 "iontype for %s */\n",
1090 "\t_ppvar[%d] = _nrn_mechanism_get_param_handle(prop_ion, %d); /* _ion_di%sdv */\n",
1114 "\nstatic void _mech_inst_destruct(Prop* _prop) {\n"
1115 " Datum* _ppvar = _nrn_mechanism_access_dparam(_prop);\n");
1119 insertstr(before_nrn_alloc,
"\nstatic void _mech_inst_destruct(Prop* _prop);\n");
1127 "static void _constructor(Prop* _prop) {\n"
1128 " _nrn_mechanism_cache_instance _ml_real{_prop};\n"
1129 " auto* const _ml = &_ml_real;\n"
1130 " size_t const _iml{};\n"
1131 " Datum *_ppvar{_nrn_mechanism_access_dparam(_prop)}, *_thread{};\n"
1136 "static void _constructor(Prop* _prop) {\n"
1137 " neuron::legacy::set_globals_from_prop(_prop, _ml_real, _ml, _iml);\n"
1138 " _ppvar = _nrn_mechanism_access_dparam(_prop);\n"
1168 diag(
"can't use net_send if there is no NET_RECEIVE block", (
char*) 0);
1193 "static void bbcore_write(double*, int*, int*, int*, _threadargsproto_);\n");
1195 "extern void hoc_reg_bbcore_write(int, void(*)(double*, int*, int*, int*, "
1196 "_threadargsproto_));\n");
1198 "static void bbcore_read(double*, int*, int*, int*, _threadargsproto_);\n");
1200 "extern void hoc_reg_bbcore_read(int, void(*)(double*, int*, int*, int*, "
1201 "_threadargsproto_));\n");
1205 extern Symbol* hoc_lookup(const char*);\n\
1206 extern void _nrn_thread_reg(int, int, void(*)(Datum*));\n\
1207 void _nrn_thread_table_reg(int, nrn_thread_table_check_t);\n\
1208 extern void hoc_register_tolerance(int, HocStateTolerance*, Symbol***);\n\
1209 extern void _cvode_abstol( Symbol**, double*, int);\n\n\
1212 "extern \"C\" void _%s_reg() {\n\
1213 int _vectorized = %d;\n",
1225 q =
q->next->next->next;
1233 q =
q->next->next->next;
1238 _pointtype = point_register_mech(_mechanism,\n\
1239 nrn_alloc,%s, nrn_init,\n\
1240 hoc_nrnpointerindex, %d,\n\
1241 _hoc_create_pnt, _hoc_destroy_pnt, _member_func);\n",
1251 register_mech(_mechanism, nrn_alloc,%s, nrn_init, hoc_nrnpointerindex, %d);\n",
1270 " hoc_register_npy_direct(_mechtype, npy_direct_func_proc);\n");
1279 if (emit_check_table_thread) {
1288 "#if NMODL_TEXT\n register_nmodl_text_and_filename(_mechtype);\n#endif\n");
1294 [](
auto const& pair) { return pair.second; });
1314 " hoc_register_dparam_semantics(_mechtype, %d, \"%s\");\n",
1330 q =
q->next->next->next;
1339 hoc_register_cvode(_mechtype, _ode_count, _ode_map, _ode_spec, _ode_matsol);\n");
1342 hoc_register_tolerance(_mechtype, _hoc_state_tol, &_atollist);\n");
1349 hoc_register_cvode(_mechtype, _ode_count, 0, 0, 0);\n");
1355 "Notice: ARTIFICIAL_CELL is a synonym for POINT_PROCESS which hints that it\n\
1356 only affects and is affected by discrete events. As such it is not\n\
1357 located in a section and is not associated with an integrator\n");
1374 Sprintf(
buf,
"add_nrn_fornetcons(_mechtype, _fnc_index);\n");
1384 #if EXTRACELLULAR\n\
1385 if (auto* const _extnode = _nrn_mechanism_access_extnode(_nd); _extnode) {\n\
1386 v = NODEV(_nd) + _extnode->_v[0];\n\
1415 "static void _difusfunc(ldifusfunc2_t, neuron::model_sorted_token const&, "
1421 " hoc_register_var(hoc_scdoub, hoc_vdoub, hoc_intfunc);\n");
1424 #if !defined(NRN_AVOID_ABSOLUTE_PATHS)
1426 "\tivoc_help(\"help ?1 %s %s\\n\");\n",
1428 fs::absolute(
finname).c_str());
1431 "\tivoc_help(\"help ?1 %s %s\\n\");\n",
1433 fs::path(
finname).filename().c_str());
1456 "static void _destructor(Prop* _prop) {\n"
1457 " _nrn_mechanism_cache_instance _ml_real{_prop};\n"
1458 " auto* const _ml = &_ml_real;\n"
1459 " size_t const _iml{};\n"
1460 " Datum *_ppvar{_nrn_mechanism_access_dparam(_prop)}, *_thread{};\n"
1465 "static void _destructor(Prop* _prop) {\n"
1466 " neuron::legacy::set_globals_from_prop(_prop, _ml_real, _ml, _iml);\n"
1467 " _ppvar = _nrn_mechanism_access_dparam(_prop);\n"
1478 if ((
s->subtype &
PARM)) {
1498 " used in USEION statement can not be re-declared in a CONSTANT block");
1505 List* read_variables,
1506 List* write_variables) {
1507 auto const have_type = [ion_name, read_variables, write_variables](
int type) {
1508 for (
auto*
const ion_var_list: {read_variables, write_variables}) {
1512 if (
iontype(var_sym->
name,
const_cast<char*
>(ion_name.c_str())) ==
type) {
1519 auto const add_readion = [read_variables](std::string
name) {
1525 bool const have_ionin{have_type(
IONIN)}, have_ionout{have_type(
IONOUT)};
1526 if (have_ionin && !have_ionout) {
1527 add_readion(ion_name +
"o");
1528 }
else if (have_ionout && !have_ionin) {
1529 add_readion(ion_name +
"i");
1535 const Item* ion_var;
1557 if (strcmp(
s->name,
"v") == 0)
1564 printf(
"Warning: Default %g of PARAMETER %s will be ignored and set by NEURON.\n",
1571 Item *
q, *qdexp, *qb1, *qvexp, *qb2, *q1;
1572 char *cfindex, *dfdcur;
1596 "static void* _difspace%d;\n"
1597 "extern double nrn_nernst_coef(int);\n"
1598 "static double _difcoef%d(int _i, Memb_list* _ml_arg, size_t _iml, Datum* _ppvar, "
1599 "double* _pdvol, double* _pdfcdc, Datum* _thread, NrnThread* _nt, "
1600 "_nrn_model_sorted_token const& _sorted_token) {\n"
1601 " _nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _ml_arg->_type()};\n"
1602 " auto* const _ml = &_lmr;\n"
1603 " double* _globals = nullptr;\n"
1604 " if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n"
1609 for (q1 = qvexp; q1 != qb2; q1 = q1->
next) {
1615 if (_i == %s) {\n *_pdfcdc = %s;\n }else{ *_pdfcdc=0.;}\n",
1623 for (q1 = qdexp; q1 != qb1; q1 = q1->
next) {
1629 "static void _difusfunc(ldifusfunc2_t _f, _nrn_model_sorted_token const& "
1630 "sorted_token, NrnThread& _nt) {int _i;\n");
1648 if (
s->subtype &
ARRAY) {
1650 " for (_i=0; _i < %d; ++_i) (*_f)(_mechtype, _difcoef%d, &_difspace%d, _i, ",
1655 Sprintf(
buf,
" (*_f)(_mechtype, _difcoef%d, &_difspace%d, 0, ",
n,
n);
1679 for (
n = 0, cp = sym->
u.
str; *cp; ++cp) {
1688 i = sscanf(cp,
"%lf %lf\n", pg1, pg2);
1701 for (
n = 0, cp = sym->
u.
str; *cp; ++cp) {
1710 i = sscanf(cp,
"%lf\n", pg1);
1729 i = sscanf(sym->
u.
str,
"[%*d]\n%lf%*c%lf", pg1, pg2);
1731 i = sscanf(sym->
u.
str,
"%lf%*c%lf", pg1, pg2);
1734 for (
n = 0, cp = sym->
u.
str;
n < 2;) {
1735 if (*cp++ ==
'\n') {
1739 for (cp1 =
s; *cp !=
'\n';) {
1748 i = sscanf(sym->
u.
str,
"[%*d]\n%lf\n%s", pg1,
s);
1750 i = sscanf(sym->
u.
str,
"%lf\n%s", pg1,
s);
1759 diag(sym->
name,
" does not have a proper declaration");
1822 std::string
field{
"_nrn_mechanism_field<double>{\""};
1824 field.append(1,
'"');
1825 if (
s->subtype &
ARRAY) {
1835 field.append(
"} /* ");
1837 field.append(
" */");
1844 if (
s->subtype &
ARRAY) {
1846 "#define %s _ml->template data_array<%d, %d>(_iml)\n"
1847 "#define %s_columnindex %d\n",
1856 "#define %s _ml->template fpfield<%d>(_iml)\n"
1857 "#define %s_columnindex %d\n",
1864 q->itemtype = VERBATIM;
1871 switch (
SYM(q1)->type) {
1881 if (strcmp(
SYM(q1)->
name,
"POINT_PROCESS") == 0) {
1883 }
else if (strcmp(
SYM(q1)->
name,
"ARTIFICIAL_CELL") == 0) {
1888 case ELECTRODE_CURRENT:
1903 threadsafe(
"Use of EXTERNAL is not thread safe.");
1910 threadsafe(
"Use of POINTER is not thread safe.");
1917 threadsafe(
"Use of BBCOREPOINTER is not thread safe.");
1927 if (
s->type != NAME ||
s->subtype ||
s->nrntype) {
1928 diag(
s->name,
" cannot be redeclared as RANDOM");
1931 s->type = RANDOMVAR;
1953 "static void _ba%d(Node*_nd, Datum* _ppd, Datum* _thread, NrnThread* _nt, Memb_list* "
1954 "_ml_arg, size_t _iml, _nrn_model_sorted_token const& _sorted_token) ",
1961 "_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, "
1962 "_ml_arg->_type()}; auto* const "
1964 "double* _globals = nullptr;\n"
1965 "if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n");
1969 ba = (ba == BEFORE) ? 10 : 20;
1970 ba += (
type == BREAKPOINT) ? 1 : 0;
1971 ba += (
type == SOLVE) ? 2 : 0;
1972 ba += (
type == INITIAL1) ? 3 : 0;
1987 q =
q->next->next->next;
1995 List *readlist, *writelist;
2002 diag(
"merging of neuron models not supported", (
char*) 0);
2015 LST(qw) = writelist;
2057 if (strcmp(
buf, s1) == 0) {
2061 if (strcmp(
buf, s1) == 0) {
2065 if (strcmp(
buf, s1) == 0) {
2069 if (strcmp(
buf, s1) == 0) {
2072 Sprintf(
buf,
"%s is not a valid ionic variable for %s", s1, s2);
2094 diag(
s->name,
"cannot be a RANGE or GLOBAL variable for this mechanism");
2102 diag(
s->name,
"cannot be a RANGE or GLOBAL variable for this mechanism");
2119 "\n#define t nrn_threads->_t\n#define dt nrn_threads->_dt\n"),
2120 "\n#define t _nt->_t\n#define dt _nt->_dt\n");
2132 diag(
"celcius should be spelled celsius", (
char*) 0);
2136 if (
s->type == NAME ||
s->type == PRIME) {
2139 }
else if (
s->subtype &
STAT) {
2146 if (
s->subtype &
PARM) {
2213 "template <typename T>\n"
2214 "using _nrn_mechanism_std_vector = std::vector<T>;\n"
2215 "using _nrn_model_sorted_token = neuron::model_sorted_token;\n"
2216 "using _nrn_mechanism_cache_range = "
2217 "neuron::cache::MechanismRange<number_of_floating_point_variables, "
2218 "number_of_datum_variables>;\n"
2219 "using _nrn_mechanism_cache_instance = "
2220 "neuron::cache::MechanismInstance<number_of_floating_point_variables, "
2221 "number_of_datum_variables>;\n"
2222 "using _nrn_non_owning_id_without_container = "
2223 "neuron::container::non_owning_identifier_without_container;\n"
2224 "template <typename T>\n"
2225 "using _nrn_mechanism_field = neuron::mechanism::field<T>;\n"
2226 "template <typename... Args>\n"
2227 "void _nrn_mechanism_register_data_fields(Args&&... args) {\n"
2228 " neuron::mechanism::register_data_fields(std::forward<Args>(args)...);\n"
2240 Item *
q, *q1, *qconc;
2287 if (block == 2 && qconc) {
2295 " nrn_wrote_conc(_%s_sym, _ion_%s_erev, _ion_%si, _ion_%so, _style_%s);\n",
2329 "WARNING: Dimensions may be wrong for READ %s with POINT_PROCESS\n",
2348 "WARNING: WRITE %s with it a STATE may not be translated correctly\n",
2359 int ioncount, it, need_style;
2368 q->itemtype = VERBATIM;
2380 std::string
name{
"_ion_"};
2384 "#define %s *(_ml->dptr_field<%d>(_iml))\n"
2385 "#define _p%s static_cast<neuron::container::data_handle<double>>(_ppvar[%d])\n",
2392 SYM(q1)->ioncount_ = ioncount;
2395 (
"_ion_" + std::string{
SYM(q1)->name}).c_str(),
2404 std::string
name{
"_ion_"};
2407 "#define %s *(_ml->dptr_field<%d>(_iml))\n"
2409 "static_cast<neuron::container::data_handle<double>>(_ppvar[%d])\n",
2416 SYM(q1)->ioncount_ = ioncount;
2423 std::string
name{
"_ion_di"};
2426 Sprintf(
buf,
"#define %s *(_ml->dptr_field<%d>(_iml))\n",
name.c_str(), ioncount);
2441 std::string
name{
"_ion_"};
2443 name.append(
"_erev");
2444 Sprintf(
buf,
"#define %s *_ml->dptr_field<%d>(_iml)\n",
name.c_str(), ioncount);
2449 std::string stylename{
"_style_"};
2450 stylename.append(sion->
name);
2451 Sprintf(
buf,
"#define %s\t*_ppvar[%d].get<int*>()\n", stylename.c_str(), ioncount);
2460 std::string
name{
"_ion_di"};
2463 Sprintf(
buf,
"#define %s *_ml->dptr_field<%d>(_iml)\n",
name.c_str(), ioncount);
2470 *p_pointercount = 0;
2474 "#define %s *_ppvar[%d].get<double*>()\n",
2476 ioncount + *p_pointercount);
2477 sion->
used = ioncount + *p_pointercount;
2481 "#define _p_%s _ppvar[%d].literal_value<void*>()\n",
2483 ioncount + *p_pointercount);
2484 sion->
used = ioncount + *p_pointercount;
2492 (*p_pointercount)++;
2508 "#define %s (nrnran123_State*)_ppvar[%d].get<void*>()\n",
2510 ioncount + *p_pointercount +
index);
2513 "#define _p_%s _ppvar[%d].literal_value<void*>()\n",
2515 ioncount + *p_pointercount +
index);
2525 "#define diam (*(_ml->dptr_field<%d>(_iml)))\n",
2533 "#define area (*(_ml->dptr_field<%d>(_iml)))\n",
2539 "static constexpr auto number_of_datum_variables = %d;\n",
2551 q->itemtype = (short)
i;
2552 std::string
field{
"_nrn_mechanism_field<"};
2554 field.append(
">{\"");
2556 field.append(
"\", \"");
2557 field.append(semantics);
2558 field.append(
"\"} /* ");
2560 field.append(
" */");
2566 Item *
q, *q1, *qbrak;
2573 strion =
SYM(
q)->name;
2596 strion =
SYM(
q)->name;
2602 buf,
" _ion_di%sdv += (_di%s - %s)/%s", strion, strion,
SYM(q1)->
name, strdel);
2624 in =
SYM(qion)->name;
2649 Sprintf(
buf,
"nrn_promote(prop_ion, %d, %d);\n", conc, rev);
2654 #define NRNFIX(arg) \
2655 if (strcmp(n, arg) == 0) \
2661 if (
s->assigned_to_ == 0) {
2662 s->assigned_to_ = 1;
2665 s->assigned_to_ = 2;
2676 "is a special NEURON variable that should not be\n assigned a value\
2677 in a model description file\n");
2690 if (
s->slist_info_) {
2693 n =
s->slist_info_[0] + 1;
2694 pi = (
int*)
emalloc((1 + 2 *
n) *
sizeof(int));
2695 for (
i = 2 * (
n - 1);
i > 0; --
i) {
2696 pi[
i] =
s->slist_info_[
i];
2698 free(
s->slist_info_);
2699 s->slist_info_ =
pi;
2701 pi[2 *
n - 1] = findx;
2704 s->slist_info_ =
pi = (
int*)
emalloc(3 *
sizeof(
int));
2713 pi =
s->slist_info_;
2714 if (
pi == (
int*) 0) {
2715 diag(
s->name,
"not really a STATE; Ie. No differential equation for it.\n");
2718 for (
i = 0;
i <
pi[0]; ++
i) {
2719 if (
pi[1 + 2 *
i] ==
n) {
2720 return pi[2 + 2 *
i];
2739 Item *
q, *q1, *q2, *q3;
2789 "is WRITE but is not a STATE and has no assignment statement");
2807 " _nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n"
2809 " _cntml = _ml_arg->_nodecount;\n"
2810 " Datum *_thread{_ml_arg->_thread};\n"
2811 " double* _globals = nullptr;\n"
2812 " if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n"
2813 " for (_iml = 0; _iml < _cntml; ++_iml) {\n"
2814 " _ppvar = _ml_arg->_pdata[_iml];\n"
2815 " _nd = _ml_arg->_nodelist[_iml];\n"
2816 " v = NODEV(_nd);\n");
2825 static int _ode_count(int);\n");
2828 static int _ode_count(int _type){ hoc_execerror(\"%s\", \"cannot be used with CVODE\"); return 0;}\n",
2834 static int _ode_count(int);\n\
2835 static void _ode_map(Prop*, int, neuron::container::data_handle<double>*, neuron::container::data_handle<double>*, double*, int);\n\
2836 static void _ode_spec(_nrn_model_sorted_token const&, NrnThread*, Memb_list*, int);\n\
2837 static void _ode_matsol(_nrn_model_sorted_token const&, NrnThread*, Memb_list*, int);\n\
2841 static int _ode_count(int _type){ return %d;}\n",
2851 "\nstatic void _ode_spec(_nrn_model_sorted_token const& _sorted_token, "
2852 "NrnThread* _nt, Memb_list* _ml_arg, int _type) {\n");
2867 static void _ode_map(Prop* _prop, int _ieq, neuron::container::data_handle<double>* _pv, neuron::container::data_handle<double>* _pvdot, double* _atol, int _type) {");
2870 " _ppvar = _nrn_mechanism_access_dparam(_prop);\n"
2871 " _cvode_ieq = _ieq;\n"
2872 " for (int _i=0; _i < %d; ++_i) {\n"
2873 " _pv[_i] = _nrn_mechanism_get_param_handle(_prop, _slist%d[_i]);\n"
2874 " _pvdot[_i] = _nrn_mechanism_get_param_handle(_prop, _dlist%d[_i]);\n"
2875 " _cvode_abstol(_atollist, _atol, _i);\n"
2887 "static void _ode_synonym(_nrn_model_sorted_token const&, "
2888 "NrnThread&, Memb_list&, int);\n");
2890 "static void _ode_synonym(_nrn_model_sorted_token const& "
2891 "_sorted_token, NrnThread& _nt, Memb_list& _ml_arg, int _type) {\n");
2893 "_nrn_mechanism_cache_range _lmr{_sorted_token, _nt, _ml_arg, _type};\n"
2894 "auto* const _ml = &_lmr;\n"
2895 "auto const _cnt = _ml_arg._nodecount;\n"
2896 "for (int _iml = 0; _iml < _cnt; ++_iml) {\n"
2897 " Datum* _ppvar = _ml_arg._pdata[_iml];\n");
2903 "static void _ode_matsol_instance%d(_internalthreadargsproto_);\n",
2907 "\nstatic void _ode_matsol_instance%d(_internalthreadargsproto_) {\n",
2913 "_cvode_sparse(&_cvsparseobj%d, %d, _dlist%d, "
2914 "neuron::scopmath::row_view{_ml, _iml}, "
2915 "_ode_matsol%d, &_coef%d);\n",
2923 "_cvode_sparse_thread(&(_thread[_cvspth%d].literal_value<void*>()), %d, "
2924 "_dlist%d, neuron::scopmath::row_view{_ml, _iml}, _ode_matsol%d, "
2938 "\nstatic void _ode_matsol(_nrn_model_sorted_token const& _sorted_token, "
2939 "NrnThread* _nt, Memb_list* _ml_arg, int _type) {\n");
2967 static void _ode_spec(Node* _nd, double* _pp, Datum* _ppd) {\n\
2968 _p = _pp; _ppvar = _ppd; v = NODEV(_nd);\n\
2975 static void _ode_map(int _ieq, double** _pv, doubl** _pvdot, double* _pp){}\n");
2980 static void _ode_matsol(Node* _nd, double* _pp, Datum* _ppd){}\n");
2997 static int _ode_spec%d(_internalthreadargsproto_);\n\
2998 /*static int _ode_matsol%d(_internalthreadargsproto_);*/\n\
3008 Fprintf(stderr,
"Notice: This mechanism cannot be used with CVODE\n");
3046 diag(
"Only one NET_RECEIVE block allowed", (
char*) 0);
3049 diag(
"NET_RECEIVE can only exist in a POINT_PROCESS", (
char*) 0);
3053 insertstr(qstmt,
"(Point_process* _pnt, double* _args, double _lflag)");
3059 for (
q = qstmt;
q != qend;
q =
q->next) {
3069 insertstr(qstmt,
" int _watch_rm = 0;\n");
3073 " neuron::legacy::set_globals_from_prop(_pnt->_prop, _ml_real, _ml, _iml);\n"),
3074 " _nrn_mechanism_cache_instance _ml_real{_pnt->_prop};\n"
3075 " auto* const _ml = &_ml_real;\n"
3076 " size_t const _iml{};\n");
3077 q =
insertstr(qstmt,
" _ppvar = _nrn_mechanism_access_dparam(_pnt->_prop);\n");
3080 " _thread = nullptr; double* _globals = nullptr; _nt = (NrnThread*)_pnt->_vnt;");
3083 insertstr(qstmt,
" assert(_tsav <= t); _tsav = t;");
3086 " if (_tsav > t){ hoc_execerror(hoc_object_name(_pnt->ob), \":Event arrived "
3087 "out of order. Must call ParallelContext.set_maxstep AFTER assigning minimum "
3088 "NetCon.delay\");}\n _tsav = t;");
3101 for (
q = qstmt;
q != qend;
q =
q->next) {
3103 insertstr(qstmt,
" v = NODEV(_pnt->node);\n");
3104 insertstr(qend,
"\n NODEV(_pnt->node) = v;\n");
3114 for (
q = qstmt;
q != qend;
q =
q->next) {
3121 diag(
s->name,
":only concentrations can be mentioned in a NET_RECEIVE block");
3124 for (
j = 0;
j < nion; ++
j) {
3131 diag(
"too many ions mentioned in NET_RECEIVE block (limit 10", (
char*) 0);
3138 for (
j = 0;
j < nion; ++
j) {
3140 buf,
"%s %s = _ion_%s;\n", (
j == 0) ?
"\n" :
"", ions[
j]->
name, ions[
j]->
name);
3143 for (
j = 0;
j < nion; ++
j) {
3146 "%s _ion_%s = %s;\n",
3147 (
j == 0) ?
"\n" :
"",
3164 replacstr(qinit,
"\nstatic void _net_init(Point_process* _pnt, double* _args, double _lflag)");
3165 Sprintf(
buf,
" _ppvar = _nrn_mechanism_access_dparam(_pnt->_prop);\n");
3167 " _nrn_mechanism_cache_instance _ml_real{_pnt->_prop};\n"
3168 " auto* const _ml = &_ml_real;\n"
3169 " size_t const _iml{};\n"
3170 " Datum* _ppvar = _nrn_mechanism_access_dparam(_pnt->_prop);\n"
3171 " Datum* _thread = nullptr;\n"
3172 " double* _globals = nullptr;\n"
3173 " NrnThread* _nt = (NrnThread*)_pnt->_vnt;\n");
3175 diag(
"NET_RECEIVE block can contain only one INITIAL block", (
char*) 0);
3191 "{int _ifn%d, _nfn%d; double* _fnargs%d, **_fnargslist%d;\n\
3192 \t_nfn%d = _nrn_netcon_args(_ppvar[_fnc_index].get<void*>(), &_fnargslist%d);\n\
3193 \tfor (_ifn%d = 0; _ifn%d < _nfn%d; ++_ifn%d) {\n",
3205 Sprintf(
buf,
"\t _fnargs%d = _fnargslist%d[_ifn%d];\n",
i,
i,
i);
3213 for (
q = stmt;
q != qend;
q =
q->next) {
3227 if (
s->nrntype & (
NRNGLOBAL) &&
s->assigned_to_ == 1) {
3228 Sprintf(
buf,
"Assignment to the GLOBAL variable, \"%s\", is not thread safe",
s->name);
3241 diag(
s->name,
" is a STATE variable and hence cannot be declared as GLOBAL");
3247 if (blocktype != BREAKPOINT) {
3248 diag(
"CONDUCTANCE can only appear in BREAKPOINT block", (
char*) 0);
3254 if (q2 != q1->
next) {
3257 diag(
s->name,
"not declared as USEION in NEURON block");
3269 if (blocktype != BREAKPOINT) {
3274 char*
n =
SYM(q2)->name + 2;
3291 return SYM(
q->next);
3304 #include <unordered_set>
3305 #include <unordered_map>
3314 static std::unordered_map<Symbol*, Info>
funcs;
3324 i.need_setdata =
true;
3326 i.need_setdata =
true;
3327 }
else if (
s->usage &
FUNCT) {
3328 i.func_calls.insert(
s);
3352 for (
auto& f:
funcs) {
3353 f.second.is_being_looked_at =
false;
3368 for (
auto& f:
funcs) {
3369 f.second.need_setdata =
false;
3373 for (
auto& f:
funcs) {
3376 for (
auto& f:
funcs) {
3377 auto&
q = f.second.q;
3378 if (
q && f.second.need_setdata) {
3383 " if(!_prop_id) {\n"
3385 "No data for %s_%s. Requires prior call to setdata_%s"
3386 " and that the specified mechanism instance still be in existence.\","
3395 " Prop* _local_prop = _extcall_prop;\n");
3400 " _setdata(_extcall_prop);\n"
3408 insertstr(
q,
"\n Prop* _local_prop = _prop_id ? _extcall_prop : nullptr;\n");
3415 if (
funcs.count(
s) == 0) {
3419 if (
i.need_setdata) {
3422 if (
i.is_being_looked_at) {
3425 i.is_being_looked_at =
true;
3426 for (
auto& s1:
i.func_calls) {
3428 i.need_setdata =
true;
constexpr auto range(T &&iterable)
char finname[NRN_BUFSIZE]
double var(InputIterator begin, InputIterator end)
#define ITERATE(itm, lst)
Symbol * lookup(const char *)
Symbol * install(const char *, int)
char * stralloc(const char *buf, char *rel)
void movelist(Item *q1, Item *q2, List *s)
void move(Item *q1, Item *q2, Item *q3)
Item * linsertstr(List *list, const char *str)
void replacstr(Item *q, const char *s)
void deltokens(Item *q1, Item *q2)
Item * lappenditem(List *list, Item *item)
Item * insertstr(Item *item, const char *str)
Item * lappendsym(List *list, Symbol *sym)
Item * lappendstr(List *list, const char *str)
void freelist(List *list)
List * newlist()
The following routines support the concept of a list.
static void * emalloc(size_t size)
void register_data_fields(int mechtype, std::vector< std::pair< std::string, int >> const ¶m_info, std::vector< std::pair< std::string, std::string >> const &dparam_info)
void SprintfAsrt(char(&buf)[N], const char *fmt, Args &&... args)
assert if the Sprintf format data does not fit into buf
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
std::string to_string(const T &obj)
void threadsafe(const char *)
void parminstall(Symbol *n, const char *num, const char *units, const char *limits)
void indepinstall(Symbol *n, const char *from, const char *to, const char *with, const char *units)
void vectorize_substitute(Item *q, const char *str)
NMODL parser global flags / functions.
void check_useion_variables()
static std::unordered_map< Symbol *, Info > funcs
static void var_count(Symbol *s)
void possible_local_current(int blocktype, List *symlist)
List * get_ion_variables(int)
void slist_data(Symbol *s, int indx, int findx)
List * set_ion_variables(int)
static int use_bbcorepointer
static int num_random_vars
int decode_tolerance(Symbol *sym, double *pg1)
List * thread_cleanup_list
Item * defs_list_parm_default
Symbol * breakpoint_current(Symbol *s)
static std::vector< std::pair< int, std::string > > ppvar_data_field_strings
int check_tables_threads(List *)
static void ppvar_semantics(int, const char *semantics, const char *name, const char *type)
void nrn_list(Item *q1, Item *q2)
void nrn_use(Item *q1, Item *q2, Item *q3, Item *q4)
void func_needs_setdata()
static const char * rsuffix
static std::vector< std::string > data_field_strings
void net_receive(Item *qarg, Item *qp1, Item *qp2, Item *qstmt, Item *qend)
static const char * brkpnt_str_
static Symbol * cvode_fun_
List * state_discon_list_
int iontype(char *s1, char *s2)
void hocfunc_setdata_item(Symbol *s, Item *q)
static Item * net_init_q1_
List * end_dion_stmt(const char *strdel)
List * thread_mem_init_list
const char * nmodl_version_
void check_range_in_func(Symbol *s)
void net_init(Item *qinit, Item *qp2)
int slist_search(int n, Symbol *s)
static Item * net_send_delivered_
static List * nmodlrandoms
static Symbol * ifnew_install(const char *name)
void check_ion_vars_as_constant(char *ion_name, const List *ion_var_list)
void bablk(int ba, int type, Item *q1, Item *q2)
int ion_declared(Symbol *s)
void cvode_rw_cur(char(&b)[NRN_BUFSIZE])
void set_inside_func(Symbol *s)
static List * nrn_mech_inst_destruct_list
void cvode_interface(Symbol *fun, int num, int neq)
void nrn_var_assigned(Symbol *s)
static Item * net_init_q2_
static int cvode_ieq_index
static void cvode_conc_map()
void conductance_hint(int blocktype, Item *q1, Item *q2)
static List * ppvar_semantics_
void decode_ustr(Symbol *sym, double *pg1, double *pg2, char *s)
int decode_limits(Symbol *sym, double *pg1, double *pg2)
static List * ion_synonym
static void check_sufficient_ion_read_statements(std::string const &ion_name, List *read_variables, List *write_variables)
static List * nrnpointers
static bool check_func(Symbol *s)
void fornetcon(Item *keyword, Item *par1, Item *args, Item *par2, Item *stmt, Item *qend)
void out_nt_ml_frag(List *p)
void cvode_emit_interface()
List * breakpoint_local_current_
void warn_ignore(Symbol *s)
data_handle< T > transform(data_handle< T > handle, Transform type)
int const size_t const size_t n
static double remove(void *v)
std::unordered_set< Symbol * > func_calls
int Fprintf(FILE *stream, const char *fmt, Args... args)