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;
62  assert(last_created_pp_ob_ == NULL);
63  last_created_pp_ob_ = ob;
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);
107  nrn_loc_point_process(ptype, ob2pntproc(ob), sec, node);
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  }
150  last_created_pp_ob_ = NULL;
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, Symbol* classsym, Symlist* slist, void (hm_alloc)(Prop*), int& type){
188  Pvmi cur, jacob, stat, initialize;
189  cur = NULL;
190  jacob = NULL;
191  stat = NULL;
192  initialize = NULL;
193  HocMech* hm = new HocMech();
194  hm->slist = NULL;
195  hm->mech = classsym;
196  hm->initial = hoc_table_lookup("initial", slist);
197  hm->after_step = hoc_table_lookup("after_step", slist);
198  if (hm->initial) initialize = (Pvmi)initial;
199  if (hm->after_step) stat = (Pvmi)after_step;
200  register_mech(m, hm_alloc, cur, jacob, stat, initialize, -1, 0);
201  type = nrn_get_mechtype(m[1]);
203  memb_func[type].hoc_mech = hm;
204  return hm;
205 }
206 
208  char buf[256];
209  int i, cnt;
210  Symbol* sp;
211  char* mname = gargstr(1);
212 //printf("mname=%s\n", mname);
213  check(mname);
214  char* classname = gargstr(2);
215 //printf("classname=%s\n", classname);
216  char* parnames = NULL;
217  if (ifarg(3)) {
218  parnames = new char[strlen(gargstr(3)) + 1];
219  strcpy(parnames, gargstr(3));
220  }
221 //if(parnames) printf("parnames=%s\n", parnames);
222  Symbol* classsym = hoc_lookup(classname);
223  if (classsym->type != TEMPLATE) {
224  hoc_execerror(classname, "not a template");
225  }
226  cTemplate* tp = classsym->u.ctemplate;
227  Symlist* slist = tp->symtable;
228  const char** m = make_m(true, cnt, slist, mname, parnames);
229 
230  common_register(m, classsym, slist, alloc_mech, i);
231 
232  for (sp = slist->first; sp; sp = sp->next) {
233  if (sp->type == VAR && sp->cpublic) {
234  sprintf(buf, "%s_%s", sp->name, m[1]);
235  Symbol* sp1 = hoc_lookup(buf);
236  sp1->u.rng.index = sp->u.oboff;
237  }
238  }
239  for (i=0; i < cnt; ++i) {
240  if (m[i]) {
241  delete [] m[i];
242  }
243  }
244  delete [] m;
245  delete [] parnames;
246  hoc_retpushx(1.);
247 }
248 
250  char buf[256];
251  int i, cnt, type, ptype;
252  Symbol* sp, *s2;
253  char* classname = gargstr(1);
254 //printf("classname=%s\n", classname);
255  char* parnames = NULL;
256  if (ifarg(2)) {
257  parnames = new char[strlen(gargstr(2)) + 1];
258  strcpy(parnames, gargstr(2));
259  }
260 //if(parnames) printf("parnames=%s\n", parnames);
261  Symbol* classsym = hoc_lookup(classname);
262  if (classsym->type != TEMPLATE) {
263  hoc_execerror(classname, "not a template");
264  }
265  cTemplate* tp = classsym->u.ctemplate;
266  Symlist* slist = tp->symtable;
267  // increase the dataspace by 1 void pointer. The last element
268  // is where the Point_process pointer can be found and when
269  // the object dataspace is freed, so is the Point_process.
270  if (tp->count > 0) {
271 fprintf(stderr, "%d object(s) of type %s already exist.\n", tp->count, classsym->name);
272 hoc_execerror("Can't make a template into a PointProcess when instances already exist", 0);
273  }
274  ++tp->dataspace_size;
275  const char** m = make_m(false, cnt, slist, classsym->name, parnames);
276 
277  check_list("loc", slist);
278  check_list("get_loc", slist);
279  check_list("has_loc", slist);
280  //so far we need only the name and type
281  sp = hoc_install("loc", FUNCTION, 0., &slist); sp->cpublic = 1;
282  sp = hoc_install("get_loc", FUNCTION, 0., &slist); sp->cpublic = 1;
283  sp = hoc_install("has_loc", FUNCTION, 0., &slist); sp->cpublic = 1;
284 
285  Symlist* slsav = hoc_symlist;
286  hoc_symlist = NULL;
287  HocMech* hm = common_register(m, classsym, slist, alloc_pnt, type);
288  hm->slist = hoc_symlist;
289  hoc_symlist = slsav;
290  s2 = hoc_table_lookup(m[1], hm->slist);
291  assert(s2->subtype == type);
292 // type = s2->subtype;
293  ptype = point_reg_helper(s2);
294 //printf("type=%d pointtype=%d %s %p\n", type, ptype, s2->name, s2);
295  classsym->u.ctemplate->is_point_ = ptype;
296 
297  // classsym->name is already in slist as an undef, Remove it and
298  // move s2 out of HocMech->slist and into slist.
299  // That is the one with the u.ppsym.
300  // The only reason it needs to be in slist is to find the
301  // mechanims type. And it needs to be LAST in that list.
302  // The only reason for the u.ppsym is for ndatclas.cpp and we
303  // need to fill those symbols with oboff.
304  sp = hoc_table_lookup(classsym->name, slist);
305  hoc_unlink_symbol(sp, slist);
306  hoc_unlink_symbol(s2, hm->slist);
307  hoc_link_symbol(s2, slist);
308  hoc_link_symbol(sp, hm->slist); // just so it isn't counted as leakage
309  for (i=0; i < s2->s_varn; ++i) {
310  Symbol* sp = hoc_table_lookup(s2->u.ppsym[i]->name, slist);
311  s2->u.ppsym[i]->cpublic = 2;
312  s2->u.ppsym[1]->u.oboff = sp->u.oboff;
313  }
314  for (i=0; i < cnt; ++i) {
315  if (m[i]) {
316  delete [] m[i];
317  }
318  }
319  delete [] m;
320  if (parnames) {
321  delete [] parnames;
322  }
323  hoc_retpushx(1.);
324 }
325 
326 static const char** make_m(bool suffix, int& cnt, Symlist* slist, char* mname, char* parnames) {
327  char buf[256];
328  char* cc;
329  Symbol* sp;
330  int i, imax;
331  cnt = 0;
332  for (sp = slist->first; sp; sp = sp->next) {
333  if (sp->type == VAR) {
334  ++cnt;
335 //printf ("cnt=%d |%s|\n", cnt, sp->name);
336  }
337  }
338  cnt += 6;
339 //printf("cnt=%d\n", cnt);
340  const char** m = new const char*[cnt];
341  for (i=0; i<cnt; ++i) { // not all space is used since some variables
342  m[i] = 0; // are not public
343  }
344  i = 0;
345  cc = new char[2];
346  strcpy(cc, "0"); m[i] = cc;
347 //printf("m[%d]=%s\n", i, m[i]);
348  ++i;
349  cc = new char[strlen(mname)+1];
350  strcpy(cc, mname); m[i] = cc;
351 //printf("m[%d]=%s\n", i, m[i]);
352  ++i;
353 
354  //the remaining part of m must be a 0 separated list of
355  // CONSTANT (actually PARAMETER), ASSIGNED, STATE
356  // Normally these are contiguous in the p array.
357  // At any rate the param array is not the normal representation
358  // of scalar and array values in the object dataspace.
359  // Since the object dataspace representtion is much more flexible
360  // it will be the reponsibility of the allocation routine to
361  // make sure that the style
362  // &(m->param[sym->u.rng.index])
363  // has to actually execute the variant
364  // hoc_objectdata[sym->u.oboff].pval
365  // when assigning and setting from the var_suffix form.
366 
367  // the PARAMETER names are space separated in parnames.
368  char* cp, *csp = NULL;
369  if(parnames) for (cp = parnames; cp && *cp; cp = csp) {
370  csp = strchr(cp, ' ');
371  if (csp) {
372  *csp = '\0';
373  ++csp;
374  if (!isalpha(*csp)) {
375 hoc_execerror("Must be a space separated list of names\n", gargstr(3));
376  }
377  }
378  if (suffix) {
379  sprintf(buf, "%s_%s", cp, m[1]);
380  check(buf);
381  }else{
382  sprintf(buf, "%s", cp);
383  }
384  if (!(sp = hoc_table_lookup(cp, slist))
385  || !sp->cpublic || !(sp->type == VAR)) {
386  hoc_execerror(cp, "is not a public variable");
387  }
388  cc = new char[strlen(cp) + strlen(m[1]) + 20];
389  //above 20 give enough room for _ and possible array size
390  imax = hoc_total_array_data(sp, 0);
391  if (imax > 1) {
392  sprintf(cc, "%s[%d]", buf, imax);
393  }else{
394  sprintf(cc, "%s", buf);
395  }
396  m[i] = cc;
397 //printf("m[%d]=%s\n", i, m[i]);
398  ++i;
399  }
400  int j, jmax = i;
401  m[i++] = 0; // CONSTANT ASSIGNED separator
402 //printf("m[%d] = NULL\n", i);
403  for (sp = slist->first; sp; sp = sp->next) {
404  if (sp->type == VAR && sp->cpublic) {
405  if (suffix) {
406  sprintf(buf, "%s_%s", sp->name, m[1]);
407  check(buf);
408  }else{
409  sprintf(buf, "%s", sp->name);
410  }
411  bool b = false;
412  for (j=1; j < jmax; ++j) {
413  if (strstr(m[j], buf)) {
414  b = true; // already a PARAMETER
415  break;
416  }
417  }
418  if (b) {
419  continue;
420  }
421  cc = new char[strlen(buf) + 20];
422  //above 20 give enough room for possible array size
423  imax = hoc_total_array_data(sp, 0);
424  if (imax > 1) {
425  sprintf(cc, "%s[%d]", buf, imax);
426  }else{
427  sprintf(cc, "%s", buf);
428  }
429  m[i] = cc;
430 //printf("m[%d]=%s\n", i, m[i]);
431  ++i;
432  }
433  }
434 //printf("m[%d] = NULL\n", i);
435  m[i++] = 0; // ASSIGNED STATE separator
436 //printf("m[%d] = NULL\n", i);
437  m[i++] = 0; // STATE NRNPOINTER separator
438 //printf("m[%d] = NULL\n", i);
439  m[i++] = 0; // end
440  return m;
441 }
Definition: hocdec.h:84
void hoc_link_symbol(Symbol *, Symlist *)
Definition: symbol.cpp:174
size_t hoc_total_array_data(Symbol *s, Objectdata *obd)
Definition: hoc_oop.cpp:106
int dataspace_size
Definition: hocdec.h:197
char * strstr(cs, ct) char *cs
#define assert(ex)
Definition: hocassrt.h:26
void print_symlist(const char *, Symlist *)
Definition: symbol.cpp:52
Prop * nrn_point_prop_
Definition: point.cpp:28
short type
Definition: cabvars.h:10
short type
Definition: model.h:58
static const char ** make_m(bool, int &, Symlist *, char *, char *)
Definition: hocmech.cpp:326
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1880
Object * hoc_new_opoint(int)
Definition: hocmech.cpp:153
Symbol * hoc_lookup(const char *)
Symlist * symtable
Definition: hocdec.h:196
void * this_pointer
Definition: hocdec.h:231
static void check_list(const char *s, Symlist *sl)
Definition: hocmech.cpp:46
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:84
size_t p
static HocMech * common_register(const char **m, Symbol *classsym, Symlist *slist, void(hm_alloc)(Prop *), int &type)
Definition: hocmech.cpp:187
Point_process * ob2pntproc(Object *ob)
Definition: hocmech.cpp:88
char * name
Definition: model.h:72
Object * ob
Definition: section.h:224
Memb_func * memb_func
Definition: init.cpp:161
nd
Definition: treeset.cpp:893
static int narg()
Definition: ivocvect.cpp:135
Symlist * slist
Definition: hocmech.cpp:37
void * hoc_mech
Definition: membfunc.h:54
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
Prop ** prop
Definition: nrnoc_ml.h:16
#define cur
Definition: eion.cpp:338
Symbol * hoc_install(const char *, int, double, Symlist **)
#define gargstr
Definition: hocdec.h:14
short type
Definition: section.h:215
Symbol * after_step
Definition: hocmech.cpp:36
void hoc_construct_point(Object *, int)
Definition: hocmech.cpp:52
void * create_point_process(int, Object *)
Definition: point.cpp:32
Point_process * ob2pntproc_0(Object *ob)
Definition: hocmech.cpp:78
unsigned s_varn
Definition: hocdec.h:157
sl
Definition: seclist.cpp:186
int nrn_get_mechtype(const char *mechname)
Definition: cabcode.cpp:2017
HocStruct Symbol ** ppsym
Definition: hocdec.h:149
int nodecount
Definition: nrnoc_ml.h:18
_CONST char * s
Definition: system.cpp:74
Objectdata * dataspace
Definition: hocdec.h:230
Prop * prop
Definition: section.h:264
void(* Pvmi)(struct NrnThread *, Memb_list *, int)
Definition: membfunc.h:18
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:97
void hoc_free_list(Symlist **)
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
#define cnt
Definition: spt2queue.cpp:19
char * pnt_map
Definition: init.cpp:166
hoc_retpushx(1.0)
size_t j
Section * sec
Definition: section.h:262
fprintf(stderr, "Don't know the location of params at %p\, pp)
Definition: model.h:57
Definition: section.h:213
char * name
Definition: init.cpp:16
int is_point_
Definition: hocdec.h:198
int oboff
Definition: hocdec.h:131
void nrn_loc_point_process(int, Point_process *, Section *, Node *)
Definition: point.cpp:87
Symbol * mech
Definition: hocmech.cpp:34
Symlist * hoc_symlist
int ifarg(int)
Definition: code.cpp:1562
HocStruct Symbol * next
Definition: hocdec.h:161
void make_mechanism()
Definition: hocmech.cpp:207
Datum * dparam
Definition: section.h:219
long subtype
Definition: model.h:59
void hoc_pushx(double)
void hoc_unlink_symbol(Symbol *, Symlist *)
Definition: symbol.cpp:149
int special_pnt_call(Object *ob, Symbol *sym, int narg)
Definition: hocmech.cpp:96
Object * hoc_newobj1(Symbol *, int)
Definition: hoc_oop.cpp:576
struct Symbol::@52::@53 rng
static void alloc_pnt(Prop *p)
Definition: hocmech.cpp:128
void hoc_register_cvode(int i, nrn_ode_count_t cnt, nrn_ode_map_t map, Pvmi spec, Pvmi matsol)
Definition: init.cpp:779
void register_mech(const char **, Pvmp, Pvmi, Pvmi, Pvmi, Pvmi, int, int)
Definition: init.cpp:688
Node ** nodelist
Definition: nrnoc_ml.h:5
Symbol * initial
Definition: hocmech.cpp:35
short cpublic
Note: public is a reserved keyword.
Definition: hocdec.h:125
#define FUNCTION(a, b)
Definition: nrngsl.h:6
Section * sec
Definition: section.h:154
int point_reg_helper(Symbol *)
Definition: init.cpp:800
Definition: hocdec.h:226
HocStruct cTemplate * ctemplate
Definition: hocdec.h:151
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:60
Datum * hoc_look_inside_stack(int, int)
Definition: code.cpp:754
#define i
Definition: md1redef.h:12
double get_loc_point_process(void *)
Definition: point.cpp:239
static void alloc_mech(Prop *p)
Definition: hocmech.cpp:122
sec
Definition: solve.cpp:885
static Object * last_created_pp_ob_
Definition: hocmech.cpp:27
char buf[512]
Definition: init.cpp:13
static bool skip_
Definition: hocmech.cpp:28
#define imax
void nrn_popsec(void)
Definition: cabcode.cpp:122
static char suffix[256]
Definition: nocpout.cpp:149
double hoc_call_objfunc(Symbol *s, int narg, Object *ob)
Definition: hoc_oop.cpp:390
static void check(const char *s)
Definition: hocmech.cpp:40
union Symbol::@18 u
union Object::@54 u
static Node * node(Object *)
Definition: netcvode.cpp:318
Definition: section.h:132
void * _pvoid
Definition: hocdec.h:223
int count
Definition: hocdec.h:202
Definition: hocdec.h:176
double val
Definition: hocdec.h:177
void make_pointprocess()
Definition: hocmech.cpp:249
Section * chk_access(void)
Definition: cabcode.cpp:437
void * hoc_Ecalloc(size_t nmemb, size_t size)
Definition: symbol.cpp:209
return NULL
Definition: cabcode.cpp:461
Node * node_exact(Section *sec, double x)
Definition: cabcode.cpp:1956
static void call(Symbol *s, Node *nd, Prop *p)
Definition: hocmech.cpp:158
Symbol ** pointsym
Definition: init.cpp:164
HocStruct Symbol * first
Definition: hocdec.h:85