NEURON
hocmech.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #undef check
3 #include <InterViews/resource.h>
4 #include <ctype.h>
5 #include "nrnoc2iv.h"
6 #include "nrniv_mf.h"
7 
8 #include "parse.hpp"
9 extern int point_reg_helper(Symbol*);
10 extern Object* hoc_newobj1(Symbol*, int);
11 extern Symlist* hoc_symlist;
12 extern void hoc_unlink_symbol(Symbol*, Symlist*);
13 extern void hoc_link_symbol(Symbol*, Symlist*);
14 extern "C" void hoc_free_list(Symlist**);
15 extern Datum* hoc_look_inside_stack(int, int);
16 extern void nrn_loc_point_process(int, Point_process*, Section*, Node*);
17 extern char* pnt_map;
18 extern Symbol** pointsym;
19 extern Prop* nrn_point_prop_;
20 extern void print_symlist(const char*, Symlist*);
21 
22 extern void make_mechanism();
23 extern void make_pointprocess();
24 extern void hoc_construct_point(Object*, int);
25 extern Object* hoc_new_opoint(int);
26 
28 static bool skip_;
29 
30 static const char** make_m(bool, int&, Symlist*, char*, char*);
31 
32 class HocMech {
33  public:
34  Symbol* mech; // template name
35  Symbol* initial; // INITIAL proc initial()
36  Symbol* after_step; // SOLVE ... METHOD after_cvode;proc after_step()
37  Symlist* slist; // point process range variables.
38 };
39 
40 static void check(const char* s) {
41  if (hoc_lookup(s)) {
42  hoc_execerror(s, "already exists");
43  }
44 }
45 
46 static void check_list(const char* s, Symlist* sl) {
47  if (hoc_table_lookup(s, sl)) {
48  hoc_execerror(s, "already exists");
49  }
50 }
51 
53  if (skip_) {
54  // printf("skipped hoc_construct_point\n");
55  return;
56  }
57  // printf("%s is a pointprocess\n", hoc_object_name(ob));
58  int type = ob->ctemplate->symtable->last->subtype;
59  int ptype = pnt_map[type];
61  ob->u.dataspace[ob->ctemplate->dataspace_size - 1]._pvoid = (void*) pnt;
64  if (narg > 0) {
65  double x = hoc_look_inside_stack(narg - 1, NUMBER)->val;
66  // printf("x=%g\n", x);
67  Section* sec = chk_access();
68  Node* nd = node_exact(sec, x);
69  // printf("ptype=%d pnt=%p %s nd=%p\n", ptype, pnt, secname(sec), nd);
70  // printf("type=%d pointsym=%p\n", type, pointsym[ptype]);
71  // printf("type=%d from pointsym %s = %d\n", type, pointsym[ptype]->name,
72  // pointsym[ptype]->subtype);
73 
74  nrn_loc_point_process(ptype, pnt, sec, nd);
75  }
76 }
77 
78 extern "C" Point_process* ob2pntproc_0(Object* ob) {
79  Point_process* pp;
80  if (ob->ctemplate->steer) {
81  pp = (Point_process*) ob->u.this_pointer;
82  } else {
83  pp = (Point_process*) ob->u.dataspace[ob->ctemplate->dataspace_size - 1]._pvoid;
84  }
85  return pp;
86 }
87 
88 extern "C" Point_process* ob2pntproc(Object* ob) {
89  Point_process* pp = ob2pntproc_0(ob);
90  if (!pp || !pp->prop) {
91  hoc_execerror(hoc_object_name(ob), "point process not located in a section");
92  }
93  return pp;
94 }
95 
96 int special_pnt_call(Object* ob, Symbol* sym, int narg) {
97  char* name = sym->name;
98  if (strcmp(name, "loc") == 0) {
99  int type = ob->ctemplate->symtable->last->subtype;
100  int ptype = pnt_map[type];
101  if (narg != 1) {
102  hoc_execerror("no argument", 0);
103  }
104  double x = hoc_look_inside_stack(narg - 1, NUMBER)->val;
105  Section* sec = chk_access();
106  Node* node = node_exact(sec, x);
108  hoc_pushx(x);
109  return 1;
110  } else if (strcmp(name, "has_loc") == 0) {
111  Point_process* p = ob2pntproc(ob);
112  hoc_pushx(double(p != NULL && p->sec != NULL));
113  return 1;
114  } else if (strcmp(name, "get_loc") == 0) {
116  return 1;
117  } else {
118  return 0;
119  }
120 }
121 
122 static void alloc_mech(Prop* p) {
123  Symbol* mech = ((HocMech*) memb_func[p->type].hoc_mech)->mech;
124  p->ob = hoc_newobj1(mech, 0);
125  // printf("alloc_mech %s\n", hoc_object_name(p->ob));
126 }
127 
128 static void alloc_pnt(Prop* p) {
129  // this is complex because it can be called either before or
130  // after the hoc object has been created. And so there
131  // must be communication between alloc_pnt and hoc_construct_point.
132  // need the prop->dparam[1]._pvoid
133  if (nrn_point_prop_) {
134  p->dparam = nrn_point_prop_->dparam;
135  p->ob = nrn_point_prop_->ob;
136  // printf("p->ob comes from nrn_point_prop_ %s\n", hoc_object_name(p->ob));
137  } else {
138  p->dparam = (Datum*) hoc_Ecalloc(2, sizeof(Datum));
139  if (last_created_pp_ob_) {
140  p->ob = last_created_pp_ob_;
141  // printf("p->ob comes from last_created %s\n", hoc_object_name(p->ob));
142  } else {
143  Symbol* mech = ((HocMech*) memb_func[p->type].hoc_mech)->mech;
144  skip_ = true;
145  // printf("p->ob comes from hoc_newobj1 %s\n", mech->name);
146  p->ob = hoc_newobj1(mech, 0);
147  skip_ = false;
148  }
149  }
151 }
152 
154  HocMech* hm = (HocMech*) memb_func[type].hoc_mech;
155  return hoc_newobj1(hm->mech, 0);
156 }
157 
158 static void call(Symbol* s, Node* nd, Prop* p) {
159  Section* sec = nd->sec;
160  Object* ob = p->ob;
161  double x = nrn_arc_position(sec, nd);
162  nrn_pushsec(sec);
163  hoc_pushx(x);
164  // printf("hoc_call_objfunc %s ob=%s\n", s->name, hoc_object_name(ob));
165  hoc_call_objfunc(s, 1, ob);
166  nrn_popsec();
167 }
168 
169 static void initial(void* nt, Memb_list* ml, int type) {
170  HocMech* hm = (HocMech*) memb_func[type].hoc_mech;
171  int i, cnt = ml->nodecount;
172  for (i = 0; i < cnt; ++i) {
173  call(hm->initial, ml->nodelist[i], ml->prop[i]);
174  }
175 }
176 
177 static void after_step(void* nt, Memb_list* ml, int type) {
178  HocMech* hm = (HocMech*) memb_func[type].hoc_mech;
179  int i, cnt = ml->nodecount;
180  for (i = 0; i < cnt; ++i) {
181  call(hm->after_step, ml->nodelist[i], ml->prop[i]);
182  }
183 }
184 
185 // note that an sgi CC complained about the alloc token not being interpretable
186 // as std::alloc so we changed to hm_alloc
187 static HocMech* common_register(const char** m,
188  Symbol* classsym,
189  Symlist* slist,
190  void(hm_alloc)(Prop*),
191  int& type) {
192  Pvmi cur, jacob, stat, initialize;
193  cur = NULL;
194  jacob = NULL;
195  stat = NULL;
196  initialize = NULL;
197  HocMech* hm = new HocMech();
198  hm->slist = NULL;
199  hm->mech = classsym;
200  hm->initial = hoc_table_lookup("initial", slist);
201  hm->after_step = hoc_table_lookup("after_step", slist);
202  if (hm->initial)
203  initialize = (Pvmi) initial;
204  if (hm->after_step)
205  stat = (Pvmi) after_step;
206  register_mech(m, hm_alloc, cur, jacob, stat, initialize, -1, 0);
207  type = nrn_get_mechtype(m[1]);
209  memb_func[type].hoc_mech = hm;
210  return hm;
211 }
212 
214  char buf[256];
215  int i, cnt;
216  Symbol* sp;
217  char* mname = gargstr(1);
218  // printf("mname=%s\n", mname);
219  check(mname);
220  char* classname = gargstr(2);
221  // printf("classname=%s\n", classname);
222  char* parnames = NULL;
223  if (ifarg(3)) {
224  parnames = new char[strlen(gargstr(3)) + 1];
225  strcpy(parnames, gargstr(3));
226  }
227  // if(parnames) printf("parnames=%s\n", parnames);
228  Symbol* classsym = hoc_lookup(classname);
229  if (classsym->type != TEMPLATE) {
230  hoc_execerror(classname, "not a template");
231  }
232  cTemplate* tp = classsym->u.ctemplate;
233  Symlist* slist = tp->symtable;
234  const char** m = make_m(true, cnt, slist, mname, parnames);
235 
236  common_register(m, classsym, slist, alloc_mech, i);
237 
238  for (sp = slist->first; sp; sp = sp->next) {
239  if (sp->type == VAR && sp->cpublic) {
240  sprintf(buf, "%s_%s", sp->name, m[1]);
241  Symbol* sp1 = hoc_lookup(buf);
242  sp1->u.rng.index = sp->u.oboff;
243  }
244  }
245  for (i = 0; i < cnt; ++i) {
246  if (m[i]) {
247  delete[] m[i];
248  }
249  }
250  delete[] m;
251  delete[] parnames;
252  hoc_retpushx(1.);
253 }
254 
256  char buf[256];
257  int i, cnt, type, ptype;
258  Symbol *sp, *s2;
259  char* classname = gargstr(1);
260  // printf("classname=%s\n", classname);
261  char* parnames = NULL;
262  if (ifarg(2)) {
263  parnames = new char[strlen(gargstr(2)) + 1];
264  strcpy(parnames, gargstr(2));
265  }
266  // if(parnames) printf("parnames=%s\n", parnames);
267  Symbol* classsym = hoc_lookup(classname);
268  if (classsym->type != TEMPLATE) {
269  hoc_execerror(classname, "not a template");
270  }
271  cTemplate* tp = classsym->u.ctemplate;
272  Symlist* slist = tp->symtable;
273  // increase the dataspace by 1 void pointer. The last element
274  // is where the Point_process pointer can be found and when
275  // the object dataspace is freed, so is the Point_process.
276  if (tp->count > 0) {
277  fprintf(stderr, "%d object(s) of type %s already exist.\n", tp->count, classsym->name);
278  hoc_execerror("Can't make a template into a PointProcess when instances already exist", 0);
279  }
280  ++tp->dataspace_size;
281  const char** m = make_m(false, cnt, slist, classsym->name, parnames);
282 
283  check_list("loc", slist);
284  check_list("get_loc", slist);
285  check_list("has_loc", slist);
286  // so far we need only the name and type
287  sp = hoc_install("loc", FUNCTION, 0., &slist);
288  sp->cpublic = 1;
289  sp = hoc_install("get_loc", FUNCTION, 0., &slist);
290  sp->cpublic = 1;
291  sp = hoc_install("has_loc", FUNCTION, 0., &slist);
292  sp->cpublic = 1;
293 
294  Symlist* slsav = hoc_symlist;
295  hoc_symlist = NULL;
296  HocMech* hm = common_register(m, classsym, slist, alloc_pnt, type);
297  hm->slist = hoc_symlist;
298  hoc_symlist = slsav;
299  s2 = hoc_table_lookup(m[1], hm->slist);
300  assert(s2->subtype == type);
301  // type = s2->subtype;
302  ptype = point_reg_helper(s2);
303  // printf("type=%d pointtype=%d %s %p\n", type, ptype, s2->name, s2);
304  classsym->u.ctemplate->is_point_ = ptype;
305 
306  // classsym->name is already in slist as an undef, Remove it and
307  // move s2 out of HocMech->slist and into slist.
308  // That is the one with the u.ppsym.
309  // The only reason it needs to be in slist is to find the
310  // mechanims type. And it needs to be LAST in that list.
311  // The only reason for the u.ppsym is for ndatclas.cpp and we
312  // need to fill those symbols with oboff.
313  sp = hoc_table_lookup(classsym->name, slist);
314  hoc_unlink_symbol(sp, slist);
315  hoc_unlink_symbol(s2, hm->slist);
316  hoc_link_symbol(s2, slist);
317  hoc_link_symbol(sp, hm->slist); // just so it isn't counted as leakage
318  for (i = 0; i < s2->s_varn; ++i) {
319  Symbol* sp = hoc_table_lookup(s2->u.ppsym[i]->name, slist);
320  s2->u.ppsym[i]->cpublic = 2;
321  s2->u.ppsym[1]->u.oboff = sp->u.oboff;
322  }
323  for (i = 0; i < cnt; ++i) {
324  if (m[i]) {
325  delete[] m[i];
326  }
327  }
328  delete[] m;
329  if (parnames) {
330  delete[] parnames;
331  }
332  hoc_retpushx(1.);
333 }
334 
335 static const char** make_m(bool suffix, int& cnt, Symlist* slist, char* mname, char* parnames) {
336  char buf[256];
337  char* cc;
338  Symbol* sp;
339  int i, imax;
340  cnt = 0;
341  for (sp = slist->first; sp; sp = sp->next) {
342  if (sp->type == VAR) {
343  ++cnt;
344  // printf ("cnt=%d |%s|\n", cnt, sp->name);
345  }
346  }
347  cnt += 6;
348  // printf("cnt=%d\n", cnt);
349  const char** m = new const char*[cnt];
350  for (i = 0; i < cnt; ++i) { // not all space is used since some variables
351  m[i] = 0; // are not public
352  }
353  i = 0;
354  cc = new char[2];
355  strcpy(cc, "0");
356  m[i] = cc;
357  // printf("m[%d]=%s\n", i, m[i]);
358  ++i;
359  cc = new char[strlen(mname) + 1];
360  strcpy(cc, mname);
361  m[i] = cc;
362  // printf("m[%d]=%s\n", i, m[i]);
363  ++i;
364 
365  // the remaining part of m must be a 0 separated list of
366  // CONSTANT (actually PARAMETER), ASSIGNED, STATE
367  // Normally these are contiguous in the p array.
368  // At any rate the param array is not the normal representation
369  // of scalar and array values in the object dataspace.
370  // Since the object dataspace representtion is much more flexible
371  // it will be the reponsibility of the allocation routine to
372  // make sure that the style
373  // &(m->param[sym->u.rng.index])
374  // has to actually execute the variant
375  // hoc_objectdata[sym->u.oboff].pval
376  // when assigning and setting from the var_suffix form.
377 
378  // the PARAMETER names are space separated in parnames.
379  char *cp, *csp = NULL;
380  if (parnames)
381  for (cp = parnames; cp && *cp; cp = csp) {
382  csp = strchr(cp, ' ');
383  if (csp) {
384  *csp = '\0';
385  ++csp;
386  if (!isalpha(*csp)) {
387  hoc_execerror("Must be a space separated list of names\n", gargstr(3));
388  }
389  }
390  if (suffix) {
391  sprintf(buf, "%s_%s", cp, m[1]);
392  check(buf);
393  } else {
394  sprintf(buf, "%s", cp);
395  }
396  if (!(sp = hoc_table_lookup(cp, slist)) || !sp->cpublic || !(sp->type == VAR)) {
397  hoc_execerror(cp, "is not a public variable");
398  }
399  cc = new char[strlen(cp) + strlen(m[1]) + 20];
400  // above 20 give enough room for _ and possible array size
401  imax = hoc_total_array_data(sp, 0);
402  if (imax > 1) {
403  sprintf(cc, "%s[%d]", buf, imax);
404  } else {
405  sprintf(cc, "%s", buf);
406  }
407  m[i] = cc;
408  // printf("m[%d]=%s\n", i, m[i]);
409  ++i;
410  }
411  int j, jmax = i;
412  m[i++] = 0; // CONSTANT ASSIGNED separator
413  // printf("m[%d] = NULL\n", i);
414  for (sp = slist->first; sp; sp = sp->next) {
415  if (sp->type == VAR && sp->cpublic) {
416  if (suffix) {
417  sprintf(buf, "%s_%s", sp->name, m[1]);
418  check(buf);
419  } else {
420  sprintf(buf, "%s", sp->name);
421  }
422  bool b = false;
423  for (j = 1; j < jmax; ++j) {
424  if (strstr(m[j], buf)) {
425  b = true; // already a PARAMETER
426  break;
427  }
428  }
429  if (b) {
430  continue;
431  }
432  cc = new char[strlen(buf) + 20];
433  // above 20 give enough room for possible array size
434  imax = hoc_total_array_data(sp, 0);
435  if (imax > 1) {
436  sprintf(cc, "%s[%d]", buf, imax);
437  } else {
438  sprintf(cc, "%s", buf);
439  }
440  m[i] = cc;
441  // printf("m[%d]=%s\n", i, m[i]);
442  ++i;
443  }
444  }
445  // printf("m[%d] = NULL\n", i);
446  m[i++] = 0; // ASSIGNED STATE separator
447  // printf("m[%d] = NULL\n", i);
448  m[i++] = 0; // STATE NRNPOINTER separator
449  // printf("m[%d] = NULL\n", i);
450  m[i++] = 0; // end
451  return m;
452 }
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:99
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1867
int nrn_get_mechtype(const char *mechname)
Definition: cabcode.cpp:2000
Section * chk_access(void)
Definition: cabcode.cpp:444
void nrn_popsec(void)
Definition: cabcode.cpp:123
Node * node_exact(Section *sec, double x)
Definition: cabcode.cpp:1940
Memb_func * memb_func
Definition: init.cpp:123
short type
Definition: cabvars.h:9
Symbol * initial
Definition: hocmech.cpp:35
Symbol * mech
Definition: hocmech.cpp:34
Symbol * after_step
Definition: hocmech.cpp:36
Symlist * slist
Definition: hocmech.cpp:37
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:61
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
void register_mech(const char **, Pvmp, Pvmi, Pvmi, Pvmi, Pvmi, int, int)
Definition: init.cpp:674
#define cur
Definition: eion.cpp:364
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
char buf[512]
Definition: init.cpp:13
void hoc_construct_point(Object *, int)
Definition: hocmech.cpp:52
size_t hoc_total_array_data(Symbol *s, Objectdata *obd)
Definition: hoc_oop.cpp:94
void * hoc_Ecalloc(size_t nmemb, size_t size)
Definition: symbol.cpp:205
Symbol * hoc_install(const char *, int, double, Symlist **)
double hoc_call_objfunc(Symbol *s, int narg, Object *ob)
Definition: hoc_oop.cpp:389
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:72
Symbol * hoc_lookup(const char *)
#define assert(ex)
Definition: hocassrt.h:32
#define gargstr
Definition: hocdec.h:14
static void after_step(void *nt, Memb_list *ml, int type)
Definition: hocmech.cpp:177
void hoc_unlink_symbol(Symbol *, Symlist *)
Definition: symbol.cpp:146
Prop * nrn_point_prop_
Definition: point.cpp:28
static void check_list(const char *s, Symlist *sl)
Definition: hocmech.cpp:46
void make_mechanism()
Definition: hocmech.cpp:213
Point_process * ob2pntproc(Object *ob)
Definition: hocmech.cpp:88
void print_symlist(const char *, Symlist *)
Definition: symbol.cpp:53
void make_pointprocess()
Definition: hocmech.cpp:255
Object * hoc_new_opoint(int)
Definition: hocmech.cpp:153
Point_process * ob2pntproc_0(Object *ob)
Definition: hocmech.cpp:78
static void alloc_pnt(Prop *p)
Definition: hocmech.cpp:128
static void initial(void *nt, Memb_list *ml, int type)
Definition: hocmech.cpp:169
int special_pnt_call(Object *ob, Symbol *sym, int narg)
Definition: hocmech.cpp:96
void hoc_free_list(Symlist **)
Object * hoc_newobj1(Symbol *, int)
Definition: hoc_oop.cpp:565
char * pnt_map
Definition: init.cpp:128
static Object * last_created_pp_ob_
Definition: hocmech.cpp:27
static void check(const char *s)
Definition: hocmech.cpp:40
void nrn_loc_point_process(int, Point_process *, Section *, Node *)
Definition: point.cpp:84
int point_reg_helper(Symbol *)
Definition: init.cpp:786
Symbol ** pointsym
Definition: init.cpp:126
Datum * hoc_look_inside_stack(int, int)
Definition: code.cpp:765
Symlist * hoc_symlist
static const char ** make_m(bool, int &, Symlist *, char *, char *)
Definition: hocmech.cpp:335
static HocMech * common_register(const char **m, Symbol *classsym, Symlist *slist, void(hm_alloc)(Prop *), int &type)
Definition: hocmech.cpp:187
static bool skip_
Definition: hocmech.cpp:28
static void alloc_mech(Prop *p)
Definition: hocmech.cpp:122
static void call(Symbol *s, Node *nd, Prop *p)
Definition: hocmech.cpp:158
void hoc_link_symbol(Symbol *, Symlist *)
Definition: symbol.cpp:170
int ifarg(int)
Definition: code.cpp:1581
void hoc_pushx(double)
static int narg()
Definition: ivocvect.cpp:150
#define sec
Definition: md1redef.h:13
#define i
Definition: md1redef.h:12
void(* Pvmi)(struct NrnThread *, Memb_list *, int)
Definition: membfunc.h:18
char * name
Definition: init.cpp:16
#define fprintf
Definition: mwprefix.h:30
static Node * node(Object *)
Definition: netcvode.cpp:340
static char suffix[256]
Definition: nocpout.cpp:149
#define FUNCTION(a, b)
Definition: nrngsl.h:6
size_t p
size_t j
void * create_point_process(int, Object *)
Definition: point.cpp:32
double get_loc_point_process(void *)
Definition: point.cpp:232
void hoc_register_cvode(int i, nrn_ode_count_t cnt, nrn_ode_map_t map, Pvmi spec, Pvmi matsol)
Definition: init.cpp:767
sl
Definition: seclist.cpp:181
#define cnt
Definition: spt2queue.cpp:19
#define NULL
Definition: sptree.h:16
void * hoc_mech
Definition: membfunc.h:54
int nodecount
Definition: nrnoc_ml.h:18
Node ** nodelist
Definition: nrnoc_ml.h:5
Prop ** prop
Definition: nrnoc_ml.h:16
Definition: section.h:133
Section * sec
Definition: section.h:155
Definition: hocdec.h:227
void * this_pointer
Definition: hocdec.h:232
Objectdata * dataspace
Definition: hocdec.h:231
union Object::@39 u
Prop * prop
Definition: section.h:265
Definition: section.h:214
Datum * dparam
Definition: section.h:220
Object * ob
Definition: section.h:225
Definition: model.h:57
short cpublic
Note: public is a reserved keyword.
Definition: hocdec.h:125
HocStruct Symbol ** ppsym
Definition: hocdec.h:150
short type
Definition: model.h:58
struct Symbol::@37::@38 rng
long subtype
Definition: model.h:59
HocStruct Symbol * next
Definition: hocdec.h:162
union Symbol::@18 u
unsigned s_varn
Definition: hocdec.h:158
char * name
Definition: model.h:72
HocStruct cTemplate * ctemplate
Definition: hocdec.h:152
int oboff
Definition: hocdec.h:132
Definition: hocdec.h:84
HocStruct Symbol * first
Definition: hocdec.h:85
int dataspace_size
Definition: hocdec.h:198
Symlist * symtable
Definition: hocdec.h:197
int count
Definition: hocdec.h:203
int is_point_
Definition: hocdec.h:199
Definition: hocdec.h:177
double val
Definition: hocdec.h:178
void * _pvoid
Definition: hocdec.h:224
char * strstr(char *cs, char *ct)
Definition: xred.cpp:173