NEURON
init.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <nrnmpiuse.h>
3 #include "nrn_ansi.h"
5 #include "oc_ansi.h"
6 #include <stdio.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #ifdef HAVE_UNISTD_H
11 #include <unistd.h>
12 #endif
13 #include "section.h"
14 #include "seclist.h" // SectionList_reg
15 #include "parse.hpp"
16 #include "nrniv_mf.h"
17 #include "cabvars.h"
18 #include "neuron.h"
20 #include "membdef.h"
21 #include "multicore.h"
22 #include "nrnmpi.h"
23 
24 #include <vector>
25 #include <unordered_map>
26 #include <filesystem>
27 namespace fs = std::filesystem;
28 
29 /* change this to correspond to the ../nmodl/nocpout nmodl_version_ string*/
30 static char nmodl_version_[] = "7.7.0";
31 
32 static char banner[] =
33  "Duke, Yale, and the BlueBrain Project -- Copyright 1984-2022\n\
34 See http://neuron.yale.edu/neuron/credits\n";
35 
36 #if defined(WIN32) || defined(NRNMECH_DLL_STYLE)
37 extern const char* nrn_mech_dll; /* declared in hoc_init.cpp so ivocmain.cpp can see it */
38 extern int nrn_noauto_dlopen_nrnmech; /* default 0 declared in hoc_init.cpp */
39 #endif // WIN32 or NRNMEHC_DLL_STYLE
40 
41 #if defined(WIN32)
42 #undef DLL_DEFAULT_FNAME
43 #define DLL_DEFAULT_FNAME "nrnmech.dll"
44 #endif // WIN32
45 
46 #if defined(NRNMECH_DLL_STYLE)
47 #if defined(DARWIN)
48 
49 #ifndef DLL_DEFAULT_FNAME
50 #define DLL_DEFAULT_FNAME "libnrnmech.dylib"
51 #endif // DLL_DEFAULT_FNAME
52 
53 // error message hint with regard to mismatched arch
54 void nrn_possible_mismatched_arch(const char* libname) {
55  if (neuron::config::system_processor == "arm64") {
56  // what arch are we running on
57 #if __arm64__
58  const char* we_are{"arm64"};
59 #elif __x86_64__
60  const char* we_are{"x86_64"};
61 #endif // !__arm64__
62 
63  // what arch did we try to dlopen
64  auto const cmd_size = strlen(libname) + 100;
65  auto* cmd = new char[cmd_size];
66  std::snprintf(cmd, cmd_size, "lipo -archs %s 2> /dev/null", libname);
67  char libname_arch[20]{0};
68  FILE* p = popen(cmd, "r");
69  delete[] cmd;
70  if (!p) {
71  return;
72  }
73  fgets(libname_arch, 18, p);
74  if (strlen(libname_arch) == 0) {
75  return;
76  }
77  pclose(p);
78 
79  if (strstr(libname_arch, we_are) == NULL) {
80  fprintf(stderr, "libnrniv.dylib running as %s\n", we_are);
81  fprintf(stderr, "but %s can only run as %s\n", libname, libname_arch);
82  }
83  }
84 }
85 
86 #else // ! DARWIN
87 
88 #ifndef DLL_DEFAULT_FNAME
89 #define DLL_DEFAULT_FNAME "./libnrnmech.so"
90 #endif // DLL_DEFAULT_FNAME
91 
92 #endif // ! DARWIN
93 #endif // NRNMECH_DLL_STYLE
94 
95 #include "nrnwrap_dlfcn.h"
96 
97 #define CHECK(name) \
98  if (hoc_lookup(name) != (Symbol*) 0) { \
99  IGNORE(fprintf(stderr, CHKmes, name)); \
100  nrn_exit(1); \
101  }
102 
103 static char CHKmes[] = "The user defined name, %s, already exists\n";
104 
105 void (*nrnpy_reg_mech_p_)(int);
106 
107 int secondorder = 0;
109 extern int nrn_nobanner_;
114 int nrn_global_ncell = 0; /* used to be rootnodecount */
115 extern double hoc_default_dll_loaded_;
116 extern int nrn_istty_;
117 extern int nrn_nobanner_;
118 static std::vector<double> morph_parm_default{DEF_diam};
119 
120 static HocParmLimits _hoc_parm_limits[] = {{"Ra", {1e-6, 1e9}},
121  {"L", {1e-4, 1e20}},
122  {"diam", {1e-9, 1e9}},
123  {"cm", {0., 1e9}},
124  {"rallbranch", {1., 1e9}},
125  {"nseg", {1., 1e9}},
126  {"celsius", {-273., 1e6}},
127  {"dt", {1e-9, 1e15}},
128  {nullptr, {0., 0.}}};
129 
130 static HocParmUnits _hoc_parm_units[] = {{"Ra", "ohm-cm"},
131  {"L", "um"},
132  {"diam", "um"},
133  {"cm", "uF/cm2"},
134  {"celsius", "degC"},
135  {"dt", "ms"},
136  {"t", "ms"},
137  {"v", "mV"},
138  {"i_cap", "mA/cm2"},
139  {nullptr, nullptr}};
140 
142 extern int nrn_load_dll_recover_error();
143 extern void nrn_load_name_check(const char* name);
144 static int memb_func_size_;
145 std::vector<Memb_func> memb_func;
146 std::vector<Memb_list> memb_list;
147 short* memb_order_;
150 char* pnt_map; /* so prop_free can know its a point mech*/
152 
153 cTemplate** nrn_pnt_template_; /* for finding artificial cells */
154 /* for synaptic events. */
158 
159 /* values are type numbers of mechanisms which do net_send call */
167 std::unordered_map<int, void (*)(Prop*)> nrn_mech_inst_destruct;
168 
170  nrn_watch_allocate_[type] = waf;
171 }
172 
175 
176 void hoc_reg_bbcore_write(int mechtype, bbcore_write_t f) {
177  nrn_bbcore_write_[mechtype] = f;
178 }
179 
180 void hoc_reg_bbcore_read(int mechtype, bbcore_write_t f) {
181  nrn_bbcore_read_[mechtype] = f;
182 }
183 
184 const char** nrn_nmodl_text_;
185 void hoc_reg_nmodl_text(int mechtype, const char* txt) {
186  nrn_nmodl_text_[mechtype] = txt;
187 }
188 
189 const char** nrn_nmodl_filename_;
190 void hoc_reg_nmodl_filename(int mechtype, const char* filename) {
191  nrn_nmodl_filename_[mechtype] = filename;
192 }
193 
194 void add_nrn_has_net_event(int mechtype) {
198 }
199 
200 /* values are type numbers of mechanisms which have FOR_NETCONS statement */
201 int nrn_fornetcon_cnt_; /* how many models have a FOR_NETCONS statement */
202 int* nrn_fornetcon_type_; /* what are the type numbers */
203 int* nrn_fornetcon_index_; /* what is the index into the ppvar array */
204 
205 void add_nrn_fornetcons(int type, int indx) {
206  int i = nrn_fornetcon_cnt_++;
207  nrn_fornetcon_type_ = (int*) erealloc(nrn_fornetcon_type_, (i + 1) * sizeof(int));
208  nrn_fornetcon_index_ = (int*) erealloc(nrn_fornetcon_index_, (i + 1) * sizeof(int));
211 }
212 
213 /* array is parallel to memb_func. All are 0 except 1 for ARTIFICIAL_CELL */
216 
217 void add_nrn_artcell(int mechtype, int qi) {
218  nrn_is_artificial_[mechtype] = 1;
219  nrn_artcell_qindex_[mechtype] = qi;
220 }
221 
222 int nrn_is_artificial(int pnttype) {
223  return (int) nrn_is_artificial_[pointsym[pnttype]->subtype];
224 }
225 
226 int nrn_is_cable(void) {
227  return 1;
228 }
229 
230 void* nrn_realpath_dlopen(const char* relpath, int flags) {
231  void* handle = nullptr;
232  try { // Try with an absolute path otherwise relpath
233  auto abspath = fs::absolute(relpath);
234  handle = dlopen(abspath.string().c_str(), flags);
235 #if DARWIN
236  if (!handle) {
237  nrn_possible_mismatched_arch(abspath.c_str());
238  }
239 #endif
240  } catch (const std::filesystem::filesystem_error& e) {
241  handle = dlopen(relpath, flags);
242  if (!handle) {
243  Fprintf(
244  stderr,
245  fmt::format("std::filesystem::absolute failed ({}) and dlopen failed with '{}'\n",
246  e.what(),
247  relpath)
248  .c_str());
249 #if DARWIN
250  nrn_possible_mismatched_arch(relpath);
251 #endif
252  }
253  }
254  return handle;
255 }
256 
257 int mswin_load_dll(const char* cp1) {
258  void* handle;
259  if (nrnmpi_myid < 1)
260  if (!nrn_nobanner_ && nrn_istty_) {
261  fprintf(stderr, "loading membrane mechanisms from %s\n", cp1);
262  }
263 #if DARWIN
265 #else // not DARWIN
266  handle = dlopen(cp1, RTLD_NOW);
267 #endif // not DARWIN
268  if (handle) {
269  Pfrv mreg = (Pfrv) dlsym(handle, "modl_reg");
270  if (mreg) {
271  (*mreg)();
272  } else {
273  fprintf(stderr, "dlsym modl_reg failed\n%s\n", dlerror());
274  dlclose(handle);
275  return 0;
276  }
277  return 1;
278  } else {
279  fprintf(stderr, "dlopen failed - \n%s\n", dlerror());
280  }
281  return 0;
282 }
283 
284 void hoc_nrn_load_dll(void) {
285  int i;
286  FILE* f;
287  const char* fn;
288  fn = expand_env_var(gargstr(1));
289  f = fopen(fn, "rb");
290  if (f) {
291  fclose(f);
295  /* If hoc_execerror, recover before that call */
296  i = mswin_load_dll(fn);
300  hoc_retpushx((double) i);
301  } else {
302  hoc_retpushx(0.);
303  }
304 }
305 
306 static DoubScal scdoub[] = {{"t", &t}, {"dt", &dt}, {nullptr, nullptr}};
307 
308 void hoc_last_init(void) {
309  int i;
310  Pfrv* m;
311  Symbol* s;
312 
314  nrn_threads_create(1, false); // single thread
315 
316  if (nrnmpi_myid < 1)
317  if (nrn_nobanner_ == 0) {
318  Fprintf(stderr, "%s\n", nrn_version(1));
319  Fprintf(stderr, "%s\n", banner);
320  IGNORE(fflush(stderr));
321  }
322  memb_func_size_ = 30; // initial allocation size
323  memb_list.reserve(memb_func_size_);
324  memb_func.resize(memb_func_size_); // we directly resize because it is used below
325  pointsym = (Symbol**) ecalloc(memb_func_size_, sizeof(Symbol*));
327  pnt_map = static_cast<char*>(ecalloc(memb_func_size_, sizeof(char)));
328  memb_func[1].alloc = cab_alloc;
332  pnt_receive_size = (short*) ecalloc(memb_func_size_, sizeof(short));
333  nrn_is_artificial_ = (short*) ecalloc(memb_func_size_, sizeof(short));
334  nrn_artcell_qindex_ = (short*) ecalloc(memb_func_size_, sizeof(short));
335  nrn_prop_param_size_ = (int*) ecalloc(memb_func_size_, sizeof(int));
336  nrn_prop_dparam_size_ = (int*) ecalloc(memb_func_size_, sizeof(int));
337  nrn_dparam_ptr_start_ = (int*) ecalloc(memb_func_size_, sizeof(int));
338  nrn_dparam_ptr_end_ = (int*) ecalloc(memb_func_size_, sizeof(int));
339  memb_order_ = (short*) ecalloc(memb_func_size_, sizeof(short));
340  bamech_ = (BAMech**) ecalloc(BEFORE_AFTER_SIZE, sizeof(BAMech*));
344  nrn_nmodl_text_ = (const char**) ecalloc(memb_func_size_, sizeof(const char*));
345  nrn_nmodl_filename_ = (const char**) ecalloc(memb_func_size_, sizeof(const char*));
347  sizeof(NrnWatchAllocateFunc_t));
348 
349 #if KEEP_NSEG_PARM
350  {
351  extern int keep_nseg_parm_;
352  keep_nseg_parm_ = 1;
353  }
354 #endif // KEEP_NSEG_PARM
355 
357 
358  CHECK("v");
359  s = hoc_install("v", RANGEVAR, 0.0, &hoc_symlist);
360  s->u.rng.type = VINDEX;
361 
362  CHECK("i_membrane_");
363  s = hoc_install("i_membrane_", RANGEVAR, 0.0, &hoc_symlist);
364  s->u.rng.type = IMEMFAST;
365 
366  for (i = 0; usrprop[i].name; i++) {
367  CHECK(usrprop[i].name);
368  s = hoc_install(usrprop[i].name, UNDEF, 0.0, &hoc_symlist);
369  s->type = VAR;
370  s->subtype = USERPROPERTY;
371  s->u.rng.type = usrprop[i].type;
372  s->u.rng.index = usrprop[i].index;
373  }
374  SectionList_reg();
375  SectionRef_reg();
376  register_mech(morph_mech, morph_alloc, nullptr, nullptr, nullptr, nullptr, -1, 0);
380  for (m = mechanism; *m; m++) {
381  (*m)();
382  }
383 #if !defined(WIN32)
384  modl_reg();
385 #endif // not WIN32
388 #if defined(WIN32) || defined(NRNMECH_DLL_STYLE)
389  /* use the default if it exists (and not a binary special) */
391  FILE* ff = fopen(DLL_DEFAULT_FNAME, "r");
392  if (ff) {
393  fclose(ff);
394  nrn_mech_dll = DLL_DEFAULT_FNAME;
395  }
396  }
397  if (nrn_mech_dll) {
399 #if defined(WIN32)
400  /* Sometimes (windows 10 and launch recent enthought canopy) it seems that
401  mswin_load_dll fails if the filename is not a full path to nrnmech.dll
402  */
403  if (strcmp(nrn_mech_dll, "nrnmech.dll") == 0) {
404  char buf[5100];
405  char* retval = getcwd(buf, 4096);
406  if (retval) {
407  strncat(buf, "\\", 100);
408  strncat(buf, nrn_mech_dll, 100);
410  }
411  } else {
412 #endif /*WIN32*/
413  char *cp1{}, *cp2{};
414  std::string tmp{nrn_mech_dll};
415  for (cp1 = tmp.data(); *cp1; cp1 = cp2) {
416  for (cp2 = cp1; *cp2; ++cp2) {
417  if (*cp2 == ';') {
418  *cp2 = '\0';
419  ++cp2;
420  break;
421  }
422  }
423  mswin_load_dll(cp1);
424  }
425 #if defined(WIN32)
426  }
427 #endif /*WIN32*/
428  }
429 #endif /* WIN32 || NRNMECH_DLL_STYLE */
430  s = hoc_lookup("section_owner");
431  s->type = OBJECTFUNC;
432 
433  /* verify that all ions have a defined CHARGE */
435 }
436 
437 void initnrn(void) {
438  secondorder = DEF_secondorder; /* >0 means crank-nicolson. 2 means currents
439  adjusted to t+dt/2 */
440  t = 0; /* msec */
441  dt = DEF_dt; /* msec */
442  clamp_resist = DEF_clamp_resist; /*megohm*/
443  celsius = DEF_celsius; /* degrees celsius */
444  hoc_retpushx(1.);
445 }
446 
447 static int pointtype = 1; /* starts at 1 since 0 means not point in pnt_map*/
449 
450 
451 void reallocate_mech_data(int mechtype);
452 void initialize_memb_func(int mechtype,
453  nrn_cur_t cur,
454  nrn_jacob_t jacob,
455  Pvmp alloc,
456  nrn_state_t stat,
457  nrn_init_t initialize,
458  int vectorized);
459 void check_mech_version(const char** m);
460 int count_variables_in_mechanism(const char** m2, int modltypemax);
461 void register_mech_vars(const char** var_buffers,
462  int modltypemax,
463  Symbol* mech_symbol,
464  int mechtype,
465  int nrnpointerindex);
466 
467 /* if vectorized then thread_data_size added to it */
468 void nrn_register_mech_common(const char** m,
469  Pvmp alloc,
470  nrn_cur_t cur,
471  nrn_jacob_t jacob,
472  nrn_state_t stat,
473  nrn_init_t initialize,
474  int nrnpointerindex, /* if -1 then there are none */
475  int vectorized) {
476  // initialize at first entry, it will be incremented at exit of the function
477  static int mechtype = 2; /* 0 unused, 1 for cable section */
478  int modltypemax;
479  Symbol* mech_symbol;
480  const char** m2;
481 
482  nrn_load_name_check(m[1]);
483 
484  reallocate_mech_data(mechtype);
485 
486  initialize_memb_func(mechtype, cur, jacob, alloc, stat, initialize, vectorized);
487 
489 
490  mech_symbol = hoc_install(m[1], MECHANISM, 0.0, &hoc_symlist);
491  mech_symbol->subtype = mechtype;
492  memb_func[mechtype].sym = mech_symbol;
493  m2 = m + 2;
494  if (nrnpointerindex == -1) {
495  modltypemax = STATE;
496  } else {
497  modltypemax = NRNPOINTER;
498  }
499  int nvars = count_variables_in_mechanism(m2, modltypemax);
500  mech_symbol->s_varn = nvars;
501  mech_symbol->u.ppsym = (Symbol**) emalloc((unsigned) (nvars * sizeof(Symbol*)));
502 
503  register_mech_vars(m2, modltypemax, mech_symbol, mechtype, nrnpointerindex);
504  ++mechtype;
505  n_memb_func = mechtype;
506  // n_memb_func has changed, so any existing NrnThread do not know about the
507  // new mechanism
508  v_structure_change = 1;
509 }
510 
511 void register_mech_vars(const char** var_buffers,
512  int modltypemax,
513  Symbol* mech_symbol,
514  int mechtype,
515  int nrnpointerindex) {
516  /* this is set up for the possiblility of overloading range variables.
517  We are currently not allowing this. Hence the #if.
518  If never overloaded then no reason for list of symbols for each mechanism.
519  */
520  /* the indexing is confusing because k refers to index in the range indx list
521  and j refers to index in mechanism list which has 0 elements to separate
522  nrnocCONST, DEPENDENT, and STATE */
523  /* variable pointers added on at end, if they exist */
524  /* allowing range variable arrays. Must extract dimension info from name[%d]*/
525  /* pindx refers to index into the p-array */
526  int pindx = 0;
527  int modltype;
528  int j, k;
529  for (j = 0, k = 0, modltype = nrnocCONST; modltype <= modltypemax; modltype++, j++) {
530  for (; var_buffers[j]; j++, k++) {
531  Symbol* var_symbol;
532  std::string varname(var_buffers[j]); // copy out the varname to allow modifying it
533  int index = 1;
534  unsigned nsub = 0;
535  auto subscript = varname.find('[');
536  if (subscript != varname.npos) {
537 #if EXTRACELLULAR
538  if (varname[subscript + 1] == 'N') {
539  index = nlayer;
540  } else
541 #endif // EXTRACELLULAR
542  {
543  index = std::stoi(varname.substr(subscript + 1));
544  }
545  nsub = 1;
546  varname.erase(subscript);
547  }
548  if ((var_symbol = hoc_lookup(varname.c_str()))) {
549  IGNORE(fprintf(stderr, CHKmes, varname.c_str()));
550  } else {
551  var_symbol = hoc_install(varname.c_str(), RANGEVAR, 0.0, &hoc_symlist);
552  var_symbol->subtype = modltype;
553  var_symbol->u.rng.type = mechtype;
554  var_symbol->cpublic = 1;
555  if (modltype == NRNPOINTER) { /* not in p array */
556  var_symbol->u.rng.index = nrnpointerindex;
557  } else {
558  var_symbol->u.rng.index = pindx;
559  }
560  if (nsub) {
561  var_symbol->arayinfo = (Arrayinfo*) emalloc(sizeof(Arrayinfo) +
562  nsub * sizeof(int));
563  var_symbol->arayinfo->a_varn = nullptr;
564  var_symbol->arayinfo->refcount = 1;
565  var_symbol->arayinfo->nsub = nsub;
566  var_symbol->arayinfo->sub[0] = index;
567  }
568  if (modltype == NRNPOINTER) {
569  if (nrn_dparam_ptr_end_[mechtype] == 0) {
570  nrn_dparam_ptr_start_[mechtype] = nrnpointerindex;
571  }
572  nrnpointerindex += index;
573  nrn_dparam_ptr_end_[mechtype] = nrnpointerindex;
574  } else {
575  pindx += index;
576  }
577  }
578  mech_symbol->u.ppsym[k] = var_symbol;
579  }
580  }
581 }
582 
583 int count_variables_in_mechanism(const char** m2, int modltypemax) {
584  int j;
585  int modltype;
586  int nvars;
587  // count the number of variables registered in this mechanism
588  for (j = 0, nvars = 0, modltype = nrnocCONST; modltype <= modltypemax; modltype++) {
589  // while we have not encountered a 0 (sentinel for variable type)
590  while (m2[j++]) {
591  nvars++;
592  }
593  }
594  return nvars;
595 }
596 
597 void reallocate_mech_data(int mechtype) {
598  if (mechtype >= memb_func_size_) {
599  memb_func_size_ += 20;
602  memb_func_size_ * sizeof(Point_process*));
603  pnt_map = static_cast<char*>(erealloc(pnt_map, memb_func_size_ * sizeof(char)));
605  memb_func_size_ * sizeof(cTemplate*));
607  memb_func_size_ * sizeof(pnt_receive_t));
610  sizeof(pnt_receive_init_t));
611  pnt_receive_size = (short*) erealloc(pnt_receive_size, memb_func_size_ * sizeof(short));
612  nrn_is_artificial_ = (short*) erealloc(nrn_is_artificial_, memb_func_size_ * sizeof(short));
614  memb_func_size_ * sizeof(short));
617  memb_func_size_ * sizeof(int));
619  memb_func_size_ * sizeof(int));
621  memb_order_ = (short*) erealloc(memb_order_, memb_func_size_ * sizeof(short));
623  memb_func_size_ * sizeof(bbcore_write_t));
625  memb_func_size_ * sizeof(bbcore_write_t));
626  nrn_nmodl_text_ = (const char**) erealloc(nrn_nmodl_text_,
627  memb_func_size_ * sizeof(const char*));
629  memb_func_size_ * sizeof(const char*));
633  for (int j = memb_func_size_ - 20; j < memb_func_size_; ++j) {
634  pnt_map[j] = 0;
635  point_process[j] = (Point_process*) 0;
636  pointsym[j] = (Symbol*) 0;
637  nrn_pnt_template_[j] = (cTemplate*) 0;
638  pnt_receive[j] = (pnt_receive_t) 0;
640  pnt_receive_size[j] = 0;
641  nrn_is_artificial_[j] = 0;
642  nrn_artcell_qindex_[j] = 0;
643  memb_order_[j] = 0;
646  nrn_nmodl_text_[j] = (const char*) 0;
647  nrn_nmodl_filename_[j] = (const char*) 0;
649  }
651  }
652 }
653 
654 void initialize_memb_func(int mechtype,
655  nrn_cur_t cur,
656  nrn_jacob_t jacob,
657  Pvmp alloc,
658  nrn_state_t stat,
659  nrn_init_t initialize,
660  int vectorized) {
661  assert(mechtype >= memb_list.size());
662  memb_list.resize(mechtype + 1);
663  memb_func.resize(mechtype + 1);
664  nrn_prop_param_size_[mechtype] = 0; /* fill in later */
665  nrn_prop_dparam_size_[mechtype] = 0; /* fill in later */
666  nrn_dparam_ptr_start_[mechtype] = 0; /* fill in later */
667  nrn_dparam_ptr_end_[mechtype] = 0; /* fill in later */
668  memb_func[mechtype].current = cur;
669  memb_func[mechtype].jacob = jacob;
670  memb_func[mechtype].alloc = alloc;
671  memb_func[mechtype].state = stat;
672  memb_func[mechtype].set_initialize(initialize);
673  memb_func[mechtype].destructor = nullptr;
674  memb_func[mechtype].vectorized = vectorized ? 1 : 0;
675  memb_func[mechtype].thread_size_ = vectorized ? (vectorized - 1) : 0;
676  memb_func[mechtype].thread_mem_init_ = nullptr;
677  memb_func[mechtype].thread_cleanup_ = nullptr;
678  memb_func[mechtype].thread_table_check_ = nullptr;
679  memb_func[mechtype].is_point = 0;
680  memb_func[mechtype].hoc_mech = nullptr;
681  memb_func[mechtype].setdata_ = nullptr;
682  memb_func[mechtype].dparam_semantics = nullptr;
683  memb_order_[mechtype] = mechtype;
684  memb_func[mechtype].ode_count = nullptr;
685  memb_func[mechtype].ode_map = nullptr;
686  memb_func[mechtype].ode_spec = nullptr;
687  memb_func[mechtype].ode_matsol = nullptr;
688  memb_func[mechtype].ode_synonym = nullptr;
689  memb_func[mechtype].singchan_ = nullptr;
690 }
691 
692 void check_mech_version(const char** m) {
693  /* as of 5.2 nmodl translates so that the version string
694  is the first string in m. This allows the neuron application
695  to determine if nmodl c files are compatible with this version
696  Note that internal mechanisms have a version of "0" and are
697  by nature consistent.
698  */
699 
700  /*printf("%s %s\n", m[0], m[1]);*/
701  if (strcmp(m[0], "0") == 0) { /* valid by nature */
702  } else if (m[0][0] > '9') { /* must be 5.1 or before */
703  Fprintf(stderr,
704  "Mechanism %s needs to be re-translated.\n\
705 It's pre version 6.0 \"c\" code is incompatible with this neuron version.\n",
706  m[0]);
708  hoc_execerror("Mechanism needs to be retranslated:", m[0]);
709  } else {
710  nrn_exit(1);
711  }
712  } else if (strcmp(m[0], nmodl_version_) != 0) {
713  Fprintf(stderr,
714  "Mechanism %s needs to be re-translated.\n\
715 It's version %s \"c\" code is incompatible with this neuron version.\n",
716  m[1],
717  m[0]);
719  hoc_execerror("Mechanism needs to be retranslated:", m[1]);
720  } else {
721  nrn_exit(1);
722  }
723  }
724 }
725 
726 void register_mech(const char** m,
727  Pvmp alloc,
728  nrn_cur_t cur,
729  nrn_jacob_t jacob,
730  nrn_state_t stat,
731  nrn_init_t initialize,
732  int nrnpointerindex, /* if -1 then there are none */
733  int vectorized) {
734  int mechtype = n_memb_func;
735  nrn_register_mech_common(m, alloc, cur, jacob, stat, initialize, nrnpointerindex, vectorized);
736  if (nrnpy_reg_mech_p_) {
737  (*nrnpy_reg_mech_p_)(mechtype);
738  }
739 }
740 
741 void hoc_register_parm_default(int mechtype, const std::vector<double>* pd) {
742  memb_func[mechtype].parm_default = pd;
743 }
744 
745 void nrn_writes_conc(int mechtype, int unused) {
746  static int lastion = EXTRACELL + 1;
747  int i;
748  for (i = n_memb_func - 2; i >= lastion; --i) {
749  memb_order_[i + 1] = memb_order_[i];
750  }
751  memb_order_[lastion] = mechtype;
752 #if 0
753  printf("%s reordered from %d to %d\n", memb_func[mechtype].sym->name, mechtype, lastion);
754 #endif // 0
755  if (nrn_is_ion(mechtype)) {
756  ++lastion;
757  }
758 }
759 
760 namespace {
761 /**
762  * @brief Translate a dparam semantic string to integer form.
763  *
764  * This logic used to live inside hoc_register_dparam_semantics.
765  */
766 
767 // name to int map for the negative types
768 // xx_ion and #xx_ion will get values of type*2 and type*2+1 respectively
769 static std::unordered_map<std::string, int> name_to_negint = {{"area", -1},
770  {"iontype", -2},
771  {"cvodeieq", -3},
772  {"netsend", -4},
773  {"pointer", -5},
774  {"pntproc", -6},
775  {"bbcorepointer", -7},
776  {"watch", -8},
777  {"diam", -9},
778  {"fornetcon", -10},
779  {"random", -11}};
780 
781 int dparam_semantics_to_int(std::string_view name) {
782  if (auto got = name_to_negint.find(std::string{name}); got != name_to_negint.end()) {
783  return got->second;
784  } else {
785  bool const i{name[0] == '#'};
786  Symbol* s = hoc_lookup(std::string{name.substr(i)}.c_str());
787  if (s && s->type == MECHANISM) {
788  return nrn_semantics_from_ion(s->subtype, i);
789  }
790  throw std::runtime_error("unknown dparam semantics: " + std::string{name});
791  }
792 }
793 
794 std::vector<int> indices_of_type(
795  const char* semantic_type,
796  std::vector<std::pair<const char*, const char*>> const& dparam_info) {
797  std::vector<int> indices{};
798  int inttype = dparam_semantics_to_int(std::string{semantic_type});
799  for (auto i = 0; i < dparam_info.size(); ++i) {
800  if (dparam_semantics_to_int(dparam_info[i].second) == inttype) {
801  indices.push_back(i);
802  }
803  }
804  return indices;
805 }
806 
807 static std::unordered_map<int, std::vector<int>> mech_random_indices{};
808 
809 void update_mech_ppsym_for_modlrandom(
810  int mechtype,
811  std::vector<std::pair<const char*, const char*>> const& dparam_info) {
812  std::vector<int> indices = indices_of_type("random", dparam_info);
813  mech_random_indices[mechtype] = indices;
814  if (indices.empty()) {
815  return;
816  }
817  Symbol* mechsym = memb_func[mechtype].sym;
818  int is_point = memb_func[mechtype].is_point;
819 
820  int k = mechsym->s_varn;
821  mechsym->s_varn += int(indices.size());
822  mechsym->u.ppsym = (Symbol**) erealloc(mechsym->u.ppsym, mechsym->s_varn * sizeof(Symbol*));
823 
824 
825  for (auto i: indices) {
826  auto& p = dparam_info[i];
827  Symbol* ransym{};
828  if (is_point) {
829  ransym = hoc_install(p.first, RANGEOBJ, 0.0, &(nrn_pnt_template_[mechtype]->symtable));
830  } else {
831  std::string s{p.first};
832  s += "_";
833  s += mechsym->name;
834  ransym = hoc_install(s.c_str(), RANGEOBJ, 0.0, &hoc_symlist);
835  }
836  ransym->subtype = NMODLRANDOM;
837  ransym->u.rng.type = mechtype;
838  ransym->cpublic = 1;
839  ransym->u.rng.index = i;
840  mechsym->u.ppsym[k++] = ransym;
841  }
842 }
843 
844 } // namespace
845 
847 
848 
849 // Use this if string.c_str() causes possibility of
850 // AddressSanitizer: stack-use-after-scope on address
851 void register_data_fields(int mechtype,
852  std::vector<std::pair<std::string, int>> const& param_info,
853  std::vector<std::pair<std::string, std::string>> const& dparam_info) {
854  std::vector<std::pair<const char*, int>> params{};
855  std::vector<std::pair<const char*, const char*>> dparams{};
856 
857  for (auto&& [str, i]: param_info) {
858  params.emplace_back(str.c_str(), i);
859  }
860  for (auto&& [str1, str2]: dparam_info) {
861  dparams.emplace_back(str1.c_str(), str2.c_str());
862  }
863 
864  register_data_fields(mechtype, params, dparams);
865 }
866 
867 
868 // Count the number of floating point variables.
869 //
870 // An array variable with N elements counts as N floating point variables.
871 static int count_prop_param_size(const std::vector<std::pair<const char*, int>>& param_info) {
872  int float_variables = 0;
873  for (const auto& [i, n]: param_info) {
874  float_variables += n;
875  }
876 
877  return float_variables;
878 }
879 
880 void register_data_fields(int mechtype,
881  std::vector<std::pair<const char*, int>> const& param_info,
882  std::vector<std::pair<const char*, const char*>> const& dparam_info) {
883  nrn_prop_param_size_[mechtype] = count_prop_param_size(param_info);
884  nrn_prop_dparam_size_[mechtype] = dparam_info.size();
885  if (dparam_info.empty()) {
886  memb_func[mechtype].dparam_semantics = nullptr;
887  } else {
888  memb_func[mechtype].dparam_semantics.reset(new int[dparam_info.size()]);
889  for (auto i = 0; i < dparam_info.size(); ++i) {
890  // dparam_info[i].first is the name of the variable, currently unused...
891  memb_func[mechtype].dparam_semantics[i] = dparam_semantics_to_int(
892  dparam_info[i].second);
893  }
894  }
895 
896  // Translate param_info into the type we want to use internally now we're fully inside NEURON
897  // library code (wheels...)
898  std::vector<container::Mechanism::Variable> param_info_new{};
899  std::transform(param_info.begin(),
900  param_info.end(),
901  std::back_inserter(param_info_new),
902  [](auto const& old) -> container::Mechanism::Variable {
903  return {old.first, old.second};
904  });
905  // Create a per-mechanism data structure as part of the top-level
906  // neuron::model() structure.
907  auto& model = neuron::model();
908  model.delete_mechanism(mechtype); // e.g. extracellular can call hoc_register_prop_size
909  // multiple times
910  auto& mech_data = model.add_mechanism(mechtype,
911  memb_func[mechtype].sym->name, // the mechanism name
912  std::move(param_info_new)); // names and array dimensions
913  // of double-valued
914  // per-instance variables
915  memb_list[mechtype].set_storage_pointer(&mech_data);
916  update_mech_ppsym_for_modlrandom(mechtype, dparam_info);
917 }
918 } // namespace neuron::mechanism::detail
919 namespace neuron::mechanism {
920 template <>
922  if (mech_type < 0) {
923  return nullptr;
924  }
925  return neuron::model()
928 }
929 template <>
930 double* const* get_data_ptrs<double>(int mech_type) {
931  if (mech_type < 0) {
932  return nullptr;
933  }
934  return neuron::model()
937 }
938 template <>
940  if (mech_type < 0) {
941  return -1;
942  }
943  return neuron::model()
946  .num_variables();
947 }
948 } // namespace neuron::mechanism
949 
950 /**
951  * @brief Support mechanism FUNCTION/PROCEDURE python syntax seg.mech.f()
952  *
953  * Python (density) mechanism registration uses nrn_mechs2func_map to
954  * create a per mechanism map of f members that can be called directly
955  * without prior call to setmech.
956  */
958  auto& fmap = nrn_mech2funcs_map[mechtype] = {};
959  for (int i = 0; f[i].name; ++i) {
960  fmap[f[i].name] = &f[i];
961  }
962 }
963 std::unordered_map<int, NPyDirectMechFuncs> nrn_mech2funcs_map;
964 
965 /**
966  * @brief Legacy way of registering mechanism data/pdata size.
967  *
968  * Superseded by neuron::mechanism::register_data_fields.
969  */
970 void hoc_register_prop_size(int mechtype, int psize, int dpsize) {
971  assert(nrn_prop_param_size_[mechtype] == psize);
972  assert(nrn_prop_dparam_size_[mechtype] == dpsize);
973 }
974 
975 /**
976  * @brief Legacy way of registering pdata semantics.
977  *
978  * Superseded by neuron::mechanism::register_data_fields.
979  */
980 void hoc_register_dparam_semantics(int mechtype, int ix, const char* name) {
981  assert(memb_func[mechtype].dparam_semantics[ix] == dparam_semantics_to_int(name));
982 }
983 
985  return dparam_semantics_to_int(name);
986 }
987 
988 /**
989  * @brief dparam indices with random semantics for mechtype
990  */
991 std::vector<int>& nrn_mech_random_indices(int type) {
992  return mech_random_indices[type];
993 }
994 
998  nrn_ode_spec_t spec,
1000  memb_func[i].ode_count = cnt;
1001  memb_func[i].ode_map = map;
1002  memb_func[i].ode_spec = spec;
1003  memb_func[i].ode_matsol = matsol;
1004 }
1006  memb_func[i].ode_synonym = syn;
1007 }
1008 
1010  memb_func[n_memb_func - 1].destructor = d;
1011 }
1012 
1014  pointsym[pointtype] = s2;
1015  s2->cpublic = 0;
1016  pnt_map[n_memb_func - 1] = pointtype;
1017  memb_func[n_memb_func - 1].is_point = 1;
1018  if (nrnpy_reg_mech_p_) {
1019  (*nrnpy_reg_mech_p_)(n_memb_func - 1);
1020  }
1021  return pointtype++;
1022 }
1023 
1024 extern void class2oc_base(const char*,
1025  ctor_f* cons,
1026  dtor_f* destruct,
1027  Member_func*,
1030 
1031 
1032 int point_register_mech(const char** m,
1033  Pvmp alloc,
1034  nrn_cur_t cur,
1035  nrn_jacob_t jacob,
1036  nrn_state_t stat,
1037  nrn_init_t initialize,
1038  int nrnpointerindex,
1039  int vectorized,
1040 
1041  void* (*constructor)(Object*),
1042  void (*destructor)(void*),
1043  Member_func* fmember) {
1044  Symlist* sl;
1045  Symbol *s, *s2;
1046  nrn_load_name_check(m[1]);
1047  class2oc_base(m[1], constructor, destructor, fmember, nullptr, nullptr);
1048  s = hoc_lookup(m[1]);
1049  sl = hoc_symlist;
1050  hoc_symlist = s->u.ctemplate->symtable;
1051  s->u.ctemplate->steer = steer_point_process;
1052  s->u.ctemplate->is_point_ = pointtype;
1053  nrn_register_mech_common(m, alloc, cur, jacob, stat, initialize, nrnpointerindex, vectorized);
1054  nrn_pnt_template_[n_memb_func - 1] = s->u.ctemplate;
1055  s2 = hoc_lookup(m[1]);
1056  hoc_symlist = sl;
1057  return point_reg_helper(s2);
1058 }
1059 
1060 /* some stuff from scopmath needed for built-in models */
1061 
1062 #if 0
1063 double* makevector(int nrows)
1064 {
1065  double* v;
1066  v = (double*)emalloc((unsigned)(nrows*sizeof(double)));
1067  return v;
1068 }
1069 #endif // 0
1070 
1072 
1073 void _modl_set_dt(double newdt) {
1074  dt = newdt;
1075  nrn_threads->_dt = newdt;
1076 }
1077 void _modl_set_dt_thread(double newdt, NrnThread* nt) {
1078  nt->_dt = newdt;
1079 }
1081  return nt->_dt;
1082 }
1083 
1085 void state_discontinuity(int i, double* pd, double d) {
1087  *pd = d;
1088  /*printf("state_discontinuity t=%g pd=%lx d=%g\n", t, (long)pd, d);*/
1089  }
1090 }
1091 
1093  int i;
1094  Symbol* sym;
1095  for (i = 0; limits[i].name; ++i) {
1096  sym = (Symbol*) 0;
1097  if (mechtype && memb_func[mechtype].is_point) {
1098  Symbol* t;
1099  t = hoc_lookup(memb_func[mechtype].sym->name);
1100  sym = hoc_table_lookup(limits[i].name, t->u.ctemplate->symtable);
1101  }
1102  if (!sym) {
1103  sym = hoc_lookup(limits[i].name);
1104  }
1105  hoc_symbol_limits(sym, limits[i].bnd[0], limits[i].bnd[1]);
1106  }
1107 }
1108 
1109 void hoc_register_units(int mechtype, HocParmUnits* units) {
1110  int i;
1111  Symbol* sym;
1112  for (i = 0; units[i].name; ++i) {
1113  sym = (Symbol*) 0;
1114  if (mechtype && memb_func[mechtype].is_point) {
1115  Symbol* t;
1116  t = hoc_lookup(memb_func[mechtype].sym->name);
1117  sym = hoc_table_lookup(units[i].name, t->u.ctemplate->symtable);
1118  }
1119  if (!sym) {
1120  sym = hoc_lookup(units[i].name);
1121  }
1122  hoc_symbol_units(sym, units[i].units);
1123  }
1124 }
1125 
1126 void hoc_reg_ba(int mt, nrn_bamech_t f, int type) {
1127  BAMech* bam;
1128  switch (type) { /* see bablk in src/nmodl/nocpout.cpp */
1129  case 11:
1131  break;
1132  case 22:
1133  type = AFTER_SOLVE;
1134  break;
1135  case 13:
1136  type = BEFORE_INITIAL;
1137  break;
1138  case 23:
1139  type = AFTER_INITIAL;
1140  break;
1141  case 14:
1142  type = BEFORE_STEP;
1143  break;
1144  default:
1145  printf("before-after processing type %d for %s not implemented\n",
1146  type,
1147  memb_func[mt].sym->name);
1148  nrn_exit(1);
1149  }
1150  bam = (BAMech*) emalloc(sizeof(BAMech));
1151  bam->f = f;
1152  bam->type = mt;
1153  bam->next = nullptr;
1154  // keep in call order
1155  if (!bamech_[type]) {
1156  bamech_[type] = bam;
1157  } else {
1158  BAMech* last;
1159  for (last = bamech_[type]; last->next; last = last->next) {
1160  }
1161  last->next = bam;
1162  }
1163 }
1164 
1165 void _cvode_abstol(Symbol** s, double* tol, int i) {
1166  if (s && s[i]->extra) {
1167  double x;
1168  x = s[i]->extra->tolerance;
1169  if (x != 0) {
1170  tol[i] *= x;
1171  }
1172  }
1173 }
1174 
1175 void hoc_register_tolerance(int mechtype, HocStateTolerance* tol, Symbol*** stol) {
1176  int i;
1177  Symbol* sym;
1178  /*printf("register tolerance for %s\n", memb_func[mechtype].sym->name);*/
1179  for (i = 0; tol[i].name; ++i) {
1180  if (memb_func[mechtype].is_point) {
1181  Symbol* t;
1182  t = hoc_lookup(memb_func[mechtype].sym->name);
1183  sym = hoc_table_lookup(tol[i].name, t->u.ctemplate->symtable);
1184  } else {
1185  sym = hoc_lookup(tol[i].name);
1186  }
1187  hoc_symbol_tolerance(sym, tol[i].tolerance);
1188  }
1189 
1190  if (memb_func[mechtype].ode_count) {
1191  if (auto const n = memb_func[mechtype].ode_count(mechtype); n > 0) {
1192  auto* const psym = new Symbol* [n] {};
1193  Node node{}; // dummy node
1194  node.sec_node_index_ = 0;
1195  prop_alloc(&(node.prop), MORPHOLOGY, &node); /* in case we need diam */
1196  auto* p = prop_alloc(&(node.prop), mechtype, &node); /* this and any ions */
1197  // Fill `pv` with pointers to `2*n` parameters inside `p`
1198  std::vector<neuron::container::data_handle<double>> pv(2 * n);
1199  memb_func[mechtype].ode_map(p, 0, pv.data(), pv.data() + n, nullptr, mechtype);
1200  // The first n elements of `pv` are "pv", the second n are "pvdot"
1201  for (int i = 0; i < n; ++i) {
1202  // `index` is the legacy index of `pv[i]` inside mechanism instance `p`
1203  auto const [p, index] = [&h = pv[i]](Prop* p) {
1204  for (; p; p = p->next) {
1205  int legacy_index{};
1206  auto const num_params = p->param_num_vars();
1207  for (auto i_param = 0; i_param < num_params; ++i_param) {
1208  auto const array_dim = p->param_array_dimension(i_param);
1209  for (auto j = 0; j < array_dim; ++j, ++legacy_index) {
1210  if (h == p->param_handle(i_param, j)) {
1211  return std::make_pair(p, legacy_index);
1212  }
1213  }
1214  }
1215  }
1216  std::ostringstream oss;
1217  oss << "could not find " << h << " starting from " << *p;
1218  throw std::runtime_error(oss.str());
1219  }(node.prop);
1220  /* need to find symbol for this */
1221  auto* msym = memb_func[p->_type].sym;
1222  for (int j = 0; j < msym->s_varn; ++j) {
1223  auto* vsym = msym->u.ppsym[j];
1224  if (vsym->type == RANGEVAR && vsym->u.rng.index == index) {
1225  psym[i] = vsym;
1226  /*printf("identified %s at index %d of %s\n", vsym->name, index,
1227  * msym->name);*/
1228  if (is_array(*vsym)) {
1229  int const na = vsym->arayinfo->sub[0];
1230  for (int k = 1; k < na; ++k) {
1231  psym[++i] = vsym;
1232  }
1233  }
1234  break;
1235  }
1236  }
1237  }
1238  *stol = psym;
1239  }
1240  }
1241 }
1242 
1243 void _nrn_thread_reg(int i, int cons, void (*f)(Datum*)) {
1244  if (cons == 1) {
1245  memb_func[i].thread_mem_init_ = f;
1246  } else if (cons == 0) {
1247  memb_func[i].thread_cleanup_ = f;
1248  }
1249 }
1250 
1252  memb_func[i].thread_table_check_ = f;
1253 }
1254 
1255 void _nrn_setdata_reg(int i, void (*call)(Prop*)) {
1256  memb_func[i].setdata_ = call;
1257 }
1258 /* there is some question about the _extcall_thread variables, if any. */
1259 double nrn_call_mech_func(Symbol* s, int narg, Prop* p, int mechtype) {
1260  void (*call)(Prop*) = memb_func[mechtype].setdata_;
1261  if (call) {
1262  (*call)(p);
1263  }
1264  return hoc_call_func(s, narg);
1265 }
1266 
1268  hoc_warning("nrnunit_use_legacy() is deprecated as only modern units are supported.",
1269  "If you want to still use legacy unit you can use a version of nrn < 9.");
1270  if (ifarg(1)) {
1271  int arg = (int) chkarg(1, 0, 1);
1272  if (arg == 1) {
1273  hoc_execerror(
1274  "'nrnunit_use_legacy(1)' have been called but legacy units are no more supported.",
1275  nullptr);
1276  }
1277  }
1278  hoc_retpushx(0.); // This value means modern unit
1279 }
int keep_nseg_parm_
Definition: cabcode.cpp:1474
void cab_alloc(Prop *p)
Definition: cabcode.cpp:421
void morph_alloc(Prop *p)
Definition: cabcode.cpp:438
void *(Object *) ctor_f
Definition: classreg.h:5
void(void *) dtor_f
Definition: classreg.h:6
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:48
char * gargstr(int narg)
Definition: code2.cpp:227
#define cnt
Definition: tqueue.hpp:44
#define v
Definition: md1redef.h:11
#define i
Definition: md1redef.h:19
void hoc_symbol_tolerance(Symbol *, double)
Definition: code2.cpp:111
void nrn_mk_prop_pools(int n)
Definition: cxprop.cpp:27
static int indx
Definition: deriv.cpp:289
DLFCN_EXPORT void * dlopen(const char *file, int mode)
Definition: dlfcn.c:331
DLFCN_EXPORT char * dlerror(void)
Definition: dlfcn.c:548
DLFCN_EXPORT int dlclose(void *handle)
Definition: dlfcn.c:423
DLFCN_NOINLINE DLFCN_EXPORT void * dlsym(void *handle, const char *name)
Definition: dlfcn.c:447
#define RTLD_NOW
Definition: dlfcn.h:47
static HocParmLimits limits[]
Definition: extcelln.cpp:36
double chkarg(int, double low, double high)
Definition: code2.cpp:626
static RNG::key_type k
Definition: nrnran123.cpp:9
static void destruct(void *v)
Definition: grglyph.cpp:207
static void * cons(Object *o)
Definition: grglyph.cpp:200
#define NMODLRANDOM
Definition: modl.h:226
char buf[512]
Definition: init.cpp:13
void hoc_reg_nmodl_filename(int mechtype, const char *filename)
Definition: init.cpp:190
void hoc_reg_nmodl_text(int mechtype, const char *txt)
Definition: init.cpp:185
double hoc_call_func(Symbol *s, int narg)
Definition: code.cpp:1477
void hoc_last_init(void)
Definition: init.cpp:308
Symbol * hoc_install(const char *, int, double, Symlist **)
Definition: symbol.cpp:77
const char * expand_env_var(const char *s)
Definition: fileio.cpp:113
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
void hoc_symbol_limits(Symbol *sym, float low, float high)
Definition: code2.cpp:102
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
void state_discontinuity(int i, double *pd, double d)
Definition: init.cpp:1085
int nrn_is_cable(void)
Definition: init.cpp:226
const char * nrn_mech_dll
Definition: hoc_init.cpp:228
#define assert(ex)
Definition: hocassrt.h:24
#define USERPROPERTY
Definition: hocdec.h:85
void(* Pfrv)(void)
Definition: hocdec.h:31
bool is_array(const Symbol &sym)
Definition: hocdec.h:136
hoc_List * hoc_l_newlist()
static void call(Symbol *s, Node *nd, Prop *p)
Definition: hocmech.cpp:170
static double tolerance
Definition: hocprax.cpp:54
int nrn_semantics_from_ion(int type, int i)
Definition: ion_semantics.h:3
static int narg()
Definition: ivocvect.cpp:121
static int ode_count(int type)
Definition: kschan.cpp:93
char * hoc_symbol_units(Symbol *, const char *)
Definition: code2.cpp:128
int matsol(void)
Definition: lineq.cpp:15
void(*)(Prop *, int, neuron::container::data_handle< double > *, neuron::container::data_handle< double > *, double *, int) nrn_ode_map_t
Definition: membfunc.h:39
#define IMEMFAST
Definition: membfunc.h:114
void(*)(Memb_list *, std::size_t, Datum *, Datum *, double *, NrnThread *, int, neuron::model_sorted_token const &) nrn_thread_table_check_t
Definition: membfunc.h:51
void(* Pvmp)(Prop *)
Definition: membfunc.h:22
int(* nrn_ode_count_t)(int)
Definition: membfunc.h:23
nrn_cur_t nrn_ode_spec_t
Definition: membfunc.h:41
nrn_cur_t nrn_state_t
Definition: membfunc.h:43
nrn_cur_t nrn_init_t
Definition: membfunc.h:32
void(*)(neuron::model_sorted_token const &, NrnThread *, Memb_list *, int) nrn_cur_t
Definition: membfunc.h:31
nrn_cur_t nrn_ode_matsol_t
Definition: membfunc.h:40
nrn_cur_t nrn_jacob_t
Definition: membfunc.h:33
void(*)(Node *, Datum *, Datum *, NrnThread *, Memb_list *, std::size_t, neuron::model_sorted_token const &) nrn_bamech_t
Definition: membfunc.h:30
void(*)(neuron::model_sorted_token const &, NrnThread &, Memb_list &, int) nrn_ode_synonym_t
Definition: membfunc.h:42
#define AFTER_SOLVE
Definition: membfunc.hpp:70
#define NRNPOINTER
Definition: membfunc.hpp:83
#define MORPHOLOGY
Definition: membfunc.hpp:59
#define BEFORE_INITIAL
Definition: membfunc.hpp:67
#define nrnocCONST
Definition: membfunc.hpp:63
#define STATE
Definition: membfunc.hpp:65
#define BEFORE_STEP
Definition: membfunc.hpp:71
#define AFTER_INITIAL
Definition: membfunc.hpp:68
#define BEFORE_AFTER_SIZE
Definition: membfunc.hpp:72
#define EXTRACELL
Definition: membfunc.hpp:61
#define VINDEX
Definition: membfunc.hpp:57
#define BEFORE_BREAKPOINT
Definition: membfunc.hpp:69
#define DEF_clamp_resist
#define DEF_dt
#define DEF_diam
#define DEF_secondorder
#define DEF_celsius
static double map(void *v)
Definition: mlinedit.cpp:43
#define IGNORE(arg)
Definition: model.h:224
#define RANGEOBJ
Definition: model.h:124
printf
Definition: extdef.h:5
Symbol ** p
Definition: init.cpp:108
const char * name
Definition: init.cpp:16
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
NrnThread * nrn_threads
Definition: multicore.cpp:56
void nrn_threads_create(int n)
Definition: multicore.cpp:102
void nrn_exit(int err)
Definition: nrnoc_aux.cpp:30
double * makevector(size_t size)
Definition: nrnoc_aux.cpp:48
static const char * mechanism[]
Definition: capac.cpp:19
int v_structure_change
Definition: nrnoc_aux.cpp:20
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void hoc_register_var(DoubScal *ds, DoubVec *dv, VoidFunc *)
Definition: global_vars.cpp:31
void * erealloc(void *ptr, size_t size)
Definition: nrnoc_aux.cpp:94
void * ecalloc(size_t n, size_t size)
Definition: nrnoc_aux.cpp:85
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
int nrn_is_ion(int)
void modl_reg()
Mechanism registration function.
Definition: enginemech.cpp:33
void hoc_warning(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:44
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
static int count_prop_param_size(const std::vector< std::pair< const char *, int >> &param_info)
Definition: init.cpp:871
void register_data_fields(int mechtype, std::vector< std::pair< std::string, int >> const &param_info, std::vector< std::pair< std::string, std::string >> const &dparam_info)
Definition: init.cpp:851
static void register_data_fields(int mech_type, Fields const &... fields)
Type- and array-aware version of hoc_register_prop_size.
Definition: membfunc.h:235
int get_field_count< double >(int mech_type)
Definition: init.cpp:939
int const * get_array_dims< double >(int mech_type)
Definition: init.cpp:921
double *const * get_data_ptrs< double >(int mech_type)
Definition: init.cpp:930
Model & model()
Access the global Model instance.
Definition: model_data.hpp:206
Prop * prop_alloc(Prop **, int, Node *)
Definition: treeset.cpp:671
data_handle< T > transform(data_handle< T > handle, Transform type)
Definition: node.cpp:32
void SectionRef_reg(void)
Definition: secref.cpp:363
char * nrn_version(int)
Definition: nrnversion.cpp:27
mech_type
void(*)(double *, int *, int *, int *, Memb_list *, std::size_t, Datum *, Datum *, double *, NrnThread *) bbcore_write_t
Definition: nrncore_io.h:48
static Node * node(Object *)
Definition: netcvode.cpp:291
int const size_t const size_t n
Definition: nrngsl.h:10
size_t j
s
Definition: multisend.cpp:521
void(* pnt_receive_t)(Point_process *, double *, double)
Definition: nrniv_mf.h:22
void(* pnt_receive_init_t)(Point_process *, double *, double)
Definition: nrniv_mf.h:23
int ifarg(int)
Definition: code.cpp:1607
void(* NrnWatchAllocateFunc_t)(Datum *)
Definition: nrniv_mf.h:101
void steer_point_process(void *v)
Definition: point.cpp:288
int nrn_noauto_dlopen_nrnmech
Definition: hoc_init.cpp:229
short index
Definition: cabvars.h:11
static const char * morph_mech[]
Definition: cabvars.h:57
short type
Definition: cabvars.h:10
static struct @36 usrprop[]
void nrn_verify_ion_charge_defined()
Definition: eion.cpp:263
const char ** nrn_nmodl_filename_
Definition: init.cpp:189
double _modl_get_dt_thread(NrnThread *nt)
Definition: init.cpp:1080
double dt
Definition: init.cpp:110
void hoc_reg_ba(int mt, nrn_bamech_t f, int type)
Definition: init.cpp:1126
void hoc_nrn_load_dll(void)
Definition: init.cpp:284
short * nrn_is_artificial_
Definition: init.cpp:214
short * nrn_artcell_qindex_
Definition: init.cpp:215
static char CHKmes[]
Definition: init.cpp:103
double htablemin
Definition: init.cpp:110
double nrn_call_mech_func(Symbol *s, int narg, Prop *p, int mechtype)
Definition: init.cpp:1259
static HocParmLimits _hoc_parm_limits[]
Definition: init.cpp:120
void add_nrn_fornetcons(int type, int indx)
Definition: init.cpp:205
void nrnunit_use_legacy()
Definition: init.cpp:1267
NrnWatchAllocateFunc_t * nrn_watch_allocate_
Definition: init.cpp:166
double celsius
Definition: init.cpp:110
int * nrn_fornetcon_type_
Definition: init.cpp:202
int count_variables_in_mechanism(const char **m2, int modltypemax)
Definition: init.cpp:583
void * nrn_realpath_dlopen(const char *relpath, int flags)
Definition: init.cpp:230
hoc_List * section_list
Definition: init.cpp:113
void hoc_reg_bbcore_read(int mechtype, bbcore_write_t f)
Definition: init.cpp:180
short * pnt_receive_size
Definition: init.cpp:157
int state_discon_flag_
Definition: init.cpp:1084
void _cvode_abstol(Symbol **s, double *tol, int i)
Definition: init.cpp:1165
double htablemax
Definition: init.cpp:110
std::vector< Memb_list > memb_list
Definition: init.cpp:146
double clamp_resist
Definition: init.cpp:110
void _modl_set_dt_thread(double newdt, NrnThread *nt)
Definition: init.cpp:1077
void hoc_register_limits(int mechtype, HocParmLimits *limits)
Definition: init.cpp:1092
std::vector< Memb_func > memb_func
Definition: init.cpp:145
#define CHECK(name)
Definition: init.cpp:97
pnt_receive_init_t * pnt_receive_init
Definition: init.cpp:156
static HocParmUnits _hoc_parm_units[]
Definition: init.cpp:130
int * nrn_fornetcon_index_
Definition: init.cpp:203
void hoc_register_npy_direct(int mechtype, NPyDirectMechFunc *f)
Support mechanism FUNCTION/PROCEDURE python syntax seg.mech.f()
Definition: init.cpp:957
void register_mech(const char **m, Pvmp alloc, nrn_cur_t cur, nrn_jacob_t jacob, nrn_state_t stat, nrn_init_t initialize, int nrnpointerindex, int vectorized)
Definition: init.cpp:726
static DoubScal scdoub[]
Definition: init.cpp:306
void hoc_register_synonym(int i, nrn_ode_synonym_t syn)
Definition: init.cpp:1005
int nrn_istty_
Definition: hoc.cpp:778
int nrn_global_ncell
Definition: init.cpp:114
int nrn_fornetcon_cnt_
Definition: init.cpp:201
int nrn_nobanner_
Definition: init.cpp:117
static std::vector< double > morph_parm_default
Definition: init.cpp:118
Point_process ** point_process
Definition: init.cpp:149
int mswin_load_dll(const char *cp1)
Definition: init.cpp:257
int nrn_netrec_state_adjust
Definition: init.cpp:111
cTemplate ** nrn_pnt_template_
Definition: init.cpp:153
int nrn_load_dll_recover_error()
Definition: hocusr.cpp:22
int nrn_dparam_semantics_to_int(const char *name)
Definition: init.cpp:984
static int memb_func_size_
Definition: init.cpp:144
std::unordered_map< int, NPyDirectMechFuncs > nrn_mech2funcs_map
Definition: init.cpp:963
void class2oc_base(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1583
int point_register_mech(const char **m, Pvmp alloc, nrn_cur_t cur, nrn_jacob_t jacob, nrn_state_t stat, nrn_init_t initialize, int nrnpointerindex, int vectorized, void *(*constructor)(Object *), void(*destructor)(void *), Member_func *fmember)
Definition: init.cpp:1032
int * nrn_prop_param_size_
Definition: init.cpp:162
int state_discon_allowed_
Definition: init.cpp:108
double t
Definition: init.cpp:110
void hoc_register_cvode(int i, nrn_ode_count_t cnt, nrn_ode_map_t map, nrn_ode_spec_t spec, nrn_ode_matsol_t matsol)
Definition: init.cpp:995
void hoc_reg_bbcore_write(int mechtype, bbcore_write_t f)
Definition: init.cpp:176
void initnrn(void)
Definition: init.cpp:437
int nrn_is_artificial(int pnttype)
Definition: init.cpp:222
int point_reg_helper(Symbol *s2)
Definition: init.cpp:1013
void initialize_memb_func(int mechtype, nrn_cur_t cur, nrn_jacob_t jacob, Pvmp alloc, nrn_state_t stat, nrn_init_t initialize, int vectorized)
Definition: init.cpp:654
int nrn_has_net_event_cnt_
Definition: init.cpp:160
static int pointtype
Definition: init.cpp:447
void add_nrn_artcell(int mechtype, int qi)
Definition: init.cpp:217
int secondorder
Definition: init.cpp:107
int _ninits
Definition: init.cpp:1071
int * nrn_has_net_event_
Definition: init.cpp:161
void _nrn_thread_table_reg(int i, nrn_thread_table_check_t f)
Definition: init.cpp:1251
char * pnt_map
Definition: init.cpp:150
int * nrn_dparam_ptr_start_
Definition: init.cpp:164
void hoc_register_parm_default(int mechtype, const std::vector< double > *pd)
Definition: init.cpp:741
void _modl_set_dt(double newdt)
Definition: init.cpp:1073
std::vector< int > & nrn_mech_random_indices(int type)
dparam indices with random semantics for mechtype
Definition: init.cpp:991
void nrn_load_name_check(const char *name)
Definition: hocusr.cpp:33
BAMech ** bamech_
Definition: init.cpp:151
void hoc_register_tolerance(int mechtype, HocStateTolerance *tol, Symbol ***stol)
Definition: init.cpp:1175
int * nrn_prop_dparam_size_
Definition: init.cpp:163
void hoc_register_prop_size(int mechtype, int psize, int dpsize)
Legacy way of registering mechanism data/pdata size.
Definition: init.cpp:970
bbcore_write_t * nrn_bbcore_write_
Definition: init.cpp:173
void nrn_writes_conc(int mechtype, int unused)
Definition: init.cpp:745
std::unordered_map< int, void(*)(Prop *)> nrn_mech_inst_destruct
Definition: init.cpp:167
double hoc_default_dll_loaded_
Definition: hoc_init.cpp:225
void register_destructor(Pvmp d)
Definition: init.cpp:1009
Symlist * nrn_load_dll_called_
Definition: hocusr.cpp:17
int * nrn_dparam_ptr_end_
Definition: init.cpp:165
Symbol ** pointsym
Definition: init.cpp:148
void reallocate_mech_data(int mechtype)
Definition: init.cpp:597
pnt_receive_t * pnt_receive
Definition: init.cpp:155
const char ** nrn_nmodl_text_
Definition: init.cpp:184
static char banner[]
Definition: init.cpp:32
short * memb_order_
Definition: init.cpp:147
void hoc_reg_watch_allocate(int type, NrnWatchAllocateFunc_t waf)
Definition: init.cpp:169
void(* nrnpy_reg_mech_p_)(int)
Definition: init.cpp:105
bbcore_write_t * nrn_bbcore_read_
Definition: init.cpp:174
void register_mech_vars(const char **var_buffers, int modltypemax, Symbol *mech_symbol, int mechtype, int nrnpointerindex)
Definition: init.cpp:511
static char nmodl_version_[]
Definition: init.cpp:30
void check_mech_version(const char **m)
Definition: init.cpp:692
void hoc_register_units(int mechtype, HocParmUnits *units)
Definition: init.cpp:1109
int nrn_sparse_partrans
Definition: init.cpp:112
void nrn_register_mech_common(const char **m, Pvmp alloc, nrn_cur_t cur, nrn_jacob_t jacob, nrn_state_t stat, nrn_init_t initialize, int nrnpointerindex, int vectorized)
Definition: init.cpp:468
void add_nrn_has_net_event(int mechtype)
Definition: init.cpp:194
void hoc_register_dparam_semantics(int mechtype, int ix, const char *name)
Legacy way of registering pdata semantics.
Definition: init.cpp:980
void _nrn_setdata_reg(int i, void(*call)(Prop *))
Definition: init.cpp:1255
void _nrn_thread_reg(int i, int cons, void(*f)(Datum *))
Definition: init.cpp:1243
int n_memb_func
Definition: init.cpp:448
static realtype retval
Symlist * hoc_symlist
Definition: symbol.cpp:34
int nrnmpi_myid
HOC interpreter function declarations (included by hocdec.h)
static Symbol * vsym
Definition: occvode.cpp:42
static void * constructor(Object *ho)
Definition: seclist.cpp:52
static void destructor(void *v)
Definition: seclist.cpp:61
void SectionList_reg(void)
Definition: seclist.cpp:259
#define nlayer
Definition: section_fwd.hpp:31
#define NULL
Definition: spdefs.h:105
void units(unit *)
Definition: units.cpp:641
Symlist * hoc_built_in_symlist
Definition: symbol.cpp:28
unsigned * a_varn
Definition: hocdec.h:60
int nsub
Definition: hocdec.h:61
int refcount
Definition: hocdec.h:62
int sub[1]
Definition: hocdec.h:63
struct BAMech * next
Definition: membfunc.h:178
nrn_bamech_t f
Definition: membfunc.h:176
int type
Definition: membfunc.h:177
const char * name
Definition: hocdec.h:207
const char * name
Definition: hocdec.h:212
const char * name
Definition: membfunc.h:97
Definition: section.h:105
int sec_node_index_
Definition: section.h:213
Prop * prop
Definition: section.h:190
Represent main neuron object computed by single thread.
Definition: multicore.h:58
double _dt
Definition: multicore.h:60
Definition: hocdec.h:173
A point process is computed just like regular mechanisms.
Definition: section_fwd.hpp:77
Definition: section.h:231
Definition: model.h:47
Symbol * next
Definition: hocdec.h:133
union Symbol::@28 u
short cpublic
Definition: hocdec.h:107
Symbol ** ppsym
Definition: hocdec.h:125
struct Symbol::@45::@46 rng
short type
Definition: model.h:48
long subtype
Definition: model.h:49
unsigned s_varn
Definition: hocdec.h:129
char * name
Definition: model.h:61
Arrayinfo * arayinfo
Definition: hocdec.h:130
Definition: hocdec.h:75
Symlist * symtable
Definition: hocdec.h:148
void delete_mechanism(int type)
Destroy the structure holding the data of a particular mechanism.
Definition: model_data.hpp:79
container::Mechanism::storage & add_mechanism(int type, Args &&... args)
Create a structure to hold the data of a new Mechanism.
Definition: model_data.hpp:60
container::Mechanism::storage & mechanism_data(int type)
Get the structure holding the data of a particular Mechanism.
Definition: model_data.hpp:93
Catch-all for floating point per-instance variables in the MOD file.
Definition: mechanism.hpp:21
Non-template stable handle to a generic value.
int const * get_array_dims() const
Get a pointer to an array holding the array dimensions of the fields associated with this tag.
constexpr Tag const & get_tag() const
Get the instance of the given tag type.
Tag::type *const * get_data_ptrs() const
Get a pointer to a range of pointers that always point to the start of the contiguous storage.
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8