NEURON
kschan.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <OS/list.h>
5 #include <math.h>
6 #include "nrnoc2iv.h"
7 #include "classreg.h"
8 #include "kschan.h"
9 #include "kssingle.h"
10 #include "parse.hpp"
11 #include "nrniv_mf.h"
12 
13 #define NSingleIndex 0
14 #if defined(__MWERKS__) && !defined(_MSC_VER)
15 #include <extras.h>
16 #define strdup _strdup
17 #endif
18 
19 using KSChanList = std::vector<KSChan*>;
21 
22 extern char* hoc_symbol_units(Symbol*, const char*);
23 extern void nrn_mk_table_check();
24 extern spREAL* spGetElement(char*, int, int);
25 
29 
30 #define nt_dt nrn_threads->_dt
31 
32 static void check_objtype(Object* o, Symbol* s) {
33  if (o->ctemplate->sym != s) {
34  char buf[200];
35  sprintf(buf, "%s is not a %s", o->ctemplate->sym->name, s->name);
36  hoc_execerror(buf, 0);
37  }
38  if (!o->u.this_pointer) {
39  hoc_execerror(hoc_object_name(o), " was deleted by KSChan");
40  }
41 }
42 
43 static void unref(Object* obj) {
44  if (obj) {
45  obj->u.this_pointer = 0;
46  hoc_obj_unref(obj);
47  }
48 }
49 
50 static void chkobj(void* v) {
51  if (!v) {
52  hoc_execerror("This object was deleted by KSChan", 0);
53  }
54 }
55 
56 static void check_table_thread_(double* p, Datum* ppvar, Datum* thread, NrnThread* vnt, int type) {
57  KSChan* c = (*channels)[type];
58  c->check_table_thread((NrnThread*) vnt);
59 }
60 
61 static void nrn_alloc(Prop* prop) {
62  KSChan* c = (*channels)[prop->type];
63  c->alloc(prop);
64 }
65 
66 static void nrn_init(NrnThread* nt, Memb_list* ml, int type) {
67  // printf("nrn_init\n");
68  KSChan* c = (*channels)[type];
69  c->init(ml->nodecount, ml->nodelist, ml->data, ml->pdata, nt);
70 }
71 
72 static void nrn_cur(NrnThread* nt, Memb_list* ml, int type) {
73  // printf("nrn_cur\n");
74  KSChan* c = (*channels)[type];
75 #if CACHEVEC
76  if (use_cachevec) {
77  c->cur(ml->nodecount, ml->nodeindices, ml->data, ml->pdata, nt);
78  } else
79 #endif /* CACHEVEC */
80  {
81  c->cur(ml->nodecount, ml->nodelist, ml->data, ml->pdata);
82  }
83 }
84 
85 static void nrn_jacob(NrnThread* nt, Memb_list* ml, int type) {
86  // printf("nrn_jacob\n");
87  KSChan* c = (*channels)[type];
88 #if CACHEVEC
89  if (use_cachevec) {
90  c->jacob(ml->nodecount, ml->nodeindices, ml->data, ml->pdata, nt);
91  } else
92 #endif /* CACHEVEC */
93  {
94  c->jacob(ml->nodecount, ml->nodelist, ml->data, ml->pdata);
95  }
96 }
97 
98 static void nrn_state(NrnThread* nt, Memb_list* ml, int type) {
99  // printf("nrn_state\n");
100  KSChan* c = (*channels)[type];
101 #if CACHEVEC
102  if (use_cachevec) {
103  c->state(ml->nodecount, ml->nodeindices, ml->nodelist, ml->data, ml->pdata, nt);
104  } else
105 #endif /* CACHEVEC */
106  {
107  c->state(ml->nodecount, ml->nodelist, ml->data, ml->pdata, nt);
108  }
109 }
110 
111 static int ode_count(int type) {
112  // printf("ode_count\n");
113  KSChan* c = (*channels)[type];
114  return c->count();
115 }
116 static void
117 ode_map(int ieq, double** pv, double** pvdot, double* p, Datum* pd, double* atol, int type) {
118  // printf("ode_map\n");
119  KSChan* c = (*channels)[type];
120  c->map(ieq, pv, pvdot, p, pd, atol);
121 }
122 static void ode_spec(NrnThread*, Memb_list* ml, int type) {
123  // printf("ode_spec\n");
124  KSChan* c = (*channels)[type];
125  c->spec(ml->nodecount, ml->nodelist, ml->data, ml->pdata);
126 }
127 static void ode_matsol(NrnThread* nt, Memb_list* ml, int type) {
128  // printf("ode_matsol\n");
129  KSChan* c = (*channels)[type];
130  c->matsol(ml->nodecount, ml->nodelist, ml->data, ml->pdata, nt);
131 }
132 static void singchan(NrnThread* nt, Memb_list* ml, int type) {
133  // printf("singchan_\n");
134  KSChan* c = (*channels)[type];
135  c->cv_sc_update(ml->nodecount, ml->nodelist, ml->data, ml->pdata, nt);
136 }
137 static void* hoc_create_pnt(Object* ho) {
138  return create_point_process(ho->ctemplate->is_point_, ho);
139 }
140 static void hoc_destroy_pnt(void* v) {
141  // first free the KSSingleNodeData if it exists.
142  Point_process* pp = (Point_process*) v;
143  if (pp->prop) {
144  KSChan* c = (*channels)[pp->prop->type];
145  c->destroy_pnt(pp);
146  }
147 }
148 
150  if (single_ && pp->prop->dparam[2]._pvoid) {
151  // printf("deleteing KSSingleNodeData\n");
153  delete snd;
154  pp->prop->dparam[2]._pvoid = NULL;
155  }
157 }
158 static double hoc_loc_pnt(void* v) {
159  Point_process* pp = (Point_process*) v;
160  return loc_point_process(pp->ob->ctemplate->is_point_, pp);
161 }
162 static double hoc_has_loc(void* v) {
163  return has_loc_point(v);
164 }
165 static double hoc_get_loc_pnt(void* v) {
166  return get_loc_point_process(v);
167 }
168 static double hoc_nsingle(void* v) {
169  Point_process* pp = (Point_process*) v;
170  KSChan* c = (*channels)[pp->prop->type];
171  if (ifarg(1)) {
172  c->nsingle(pp, (int) chkarg(1, 1, 1e9));
173  }
174  return (double) c->nsingle(pp);
175 }
176 static Member_func member_func[] = {{"loc", hoc_loc_pnt},
177  {"has_loc", hoc_has_loc},
178  {"get_loc", hoc_get_loc_pnt},
179  {"nsingle", hoc_nsingle},
180  {nullptr, nullptr}};
181 
183 
184 // hoc interface
185 
186 static double ks_setstructure(void* v) {
187  KSChan* ks = (KSChan*) v;
188  ks->setstructure(vector_arg(1));
189  return 1;
190 }
191 
192 static double ks_remove_state(void* v) {
193  KSChan* ks = (KSChan*) v;
194  int is;
195  if (hoc_is_double_arg(1)) {
196  is = (int) chkarg(1, 0, ks->nstate_ - 1);
197  } else {
198  Object* obj = *hoc_objgetarg(1);
200  KSState* kss = (KSState*) obj->u.this_pointer;
201  is = kss->index_;
202  }
203  ks->remove_state(is);
204  return 0.;
205 }
206 
207 static double ks_remove_transition(void* v) {
208  KSChan* ks = (KSChan*) v;
209  int it;
210  if (hoc_is_double_arg(1)) {
211  it = (int) chkarg(1, ks->ivkstrans_, ks->ntrans_ - 1);
212  } else {
213  Object* obj = *hoc_objgetarg(1);
215  KSTransition* kst = (KSTransition*) obj->u.this_pointer;
216  it = kst->index_;
217  assert(it >= ks->ivkstrans_ && it < ks->ntrans_);
218  }
219  ks->remove_transition(it);
220  return 0.;
221 }
222 
223 static double ks_ngate(void* v) {
224  KSChan* ks = (KSChan*) v;
225  return (double) ks->ngate_;
226 }
227 
228 static double ks_nstate(void* v) {
229  KSChan* ks = (KSChan*) v;
230  return (double) ks->nstate_;
231 }
232 
233 static double ks_ntrans(void* v) {
234  KSChan* ks = (KSChan*) v;
235  return (double) ks->ntrans_;
236 }
237 
238 static double ks_nligand(void* v) {
239  KSChan* ks = (KSChan*) v;
240  return (double) ks->nligand_;
241 }
242 
243 static double ks_is_point(void* v) {
244  KSChan* ks = (KSChan*) v;
245  return (ks->is_point() ? 1. : 0.);
246 }
247 
248 static double ks_single(void* v) {
249  KSChan* ks = (KSChan*) v;
250  if (ifarg(1)) {
251  ks->set_single(((int) chkarg(1, 0, 1)) != 0);
252  }
253  return (ks->is_single() ? 1. : 0.);
254 }
255 
256 static double ks_iv_type(void* v) {
257  KSChan* ks = (KSChan*) v;
258  if (ifarg(1)) {
259  ks->cond_model_ = (int) chkarg(1, 0, 2);
260  ks->setcond();
261  }
262  if (ks->ion_sym_) {
263  return (double) ks->cond_model_;
264  }
265  return 0.;
266 }
267 
268 static double ks_gmax(void* v) {
269  KSChan* ks = (KSChan*) v;
270  if (ifarg(1)) {
271  ks->gmax_deflt_ = chkarg(1, 0., 1e9);
272  }
273  return ks->gmax_deflt_;
274 }
275 
276 static double ks_erev(void* v) {
277  KSChan* ks = (KSChan*) v;
278  if (ifarg(1)) {
279  ks->erev_deflt_ = chkarg(1, -1e9, 1e9);
280  }
281  return ks->erev_deflt_;
282 }
283 
284 static double ks_vres(void* v) {
285  if (ifarg(1)) {
286  KSSingle::vres_ = chkarg(1, 1e-9, 1e9);
287  }
288  return KSSingle::vres_;
289 }
290 
291 static double ks_rseed(void* v) {
292  if (ifarg(1)) {
293  KSSingle::idum_ = (unsigned int) chkarg(1, 0, 1e9);
294  }
295  return (double) KSSingle::idum_;
296 }
297 
298 static double ks_usetable(void* v) {
299  KSChan* ks = (KSChan*) v;
300  if (ifarg(1)) {
301  if (hoc_is_pdouble_arg(1)) {
302  int n;
303  n = ks->usetable(hoc_pgetarg(1), hoc_pgetarg(2));
304  return double(n);
305  } else {
306  bool use = ((int) chkarg(1, 0, 1)) ? true : false;
307  if (ifarg(2)) {
308  ks->usetable(use, (int) chkarg(2, 2, 10000), *getarg(3), *getarg(4));
309  } else {
310  ks->usetable(use);
311  }
312  }
313  }
314  return ks->usetable() ? 1. : 0.;
315 }
316 
317 static Object** temp_objvar(const char* name, void* v, Object** obp) {
318  Object** po;
319  if (*obp) {
320  po = hoc_temp_objptr(*obp);
321  } else {
323  *obp = *po;
324  hoc_obj_ref(*po);
325  }
326  return po;
327 }
328 
329 static Object** ks_add_hhstate(void* v) {
330  KSChan* ks = (KSChan*) v;
331  KSState* kss = ks->add_hhstate(gargstr(1));
332  return temp_objvar("KSState", kss, &kss->obj_);
333 }
334 
335 static Object** ks_add_ksstate(void* v) {
336  KSChan* ks = (KSChan*) v;
337  Object* obj = *hoc_objgetarg(1);
338  int ig = ks->ngate_;
339  if (obj) {
341  KSGateComplex* ksg = (KSGateComplex*) obj->u.this_pointer;
342  assert(ksg && ksg->index_ < ks->ngate_);
343  ig = ksg->index_;
344  }
345  KSState* kss = ks->add_ksstate(ig, gargstr(2));
346  return temp_objvar("KSState", kss, &kss->obj_);
347 }
348 
349 static Object** ks_add_transition(void* v) {
350  KSChan* ks = (KSChan*) v;
351  const char* lig = NULL;
352  if (ifarg(3)) {
353  lig = gargstr(3);
354  }
355  int src, target;
356  if (hoc_is_double_arg(1)) {
357  src = (int) chkarg(1, ks->nhhstate_, ks->nstate_ - 1);
358  target = (int) chkarg(2, ks->nhhstate_, ks->nstate_ - 1);
359  } else {
360  Object* obj = *hoc_objgetarg(1);
362  src = ((KSState*) obj->u.this_pointer)->index_;
363  obj = *hoc_objgetarg(2);
365  target = ((KSState*) obj->u.this_pointer)->index_;
366  }
367  KSTransition* kst = ks->add_transition(src, target, lig);
368  return temp_objvar("KSTrans", kst, &kst->obj_);
369 }
370 
371 static Object** ks_trans(void* v) {
372  KSChan* ks = (KSChan*) v;
373  KSTransition* kst;
374  if (hoc_is_double_arg(1)) {
375  kst = ks->trans_ + (int) chkarg(1, 0, ks->ntrans_ - 1);
376  } else {
377  int src, target;
378  Object* obj = *hoc_objgetarg(1);
380  src = ((KSState*) obj->u.this_pointer)->index_;
381  obj = *hoc_objgetarg(2);
383  target = ((KSState*) obj->u.this_pointer)->index_;
384  kst = ks->trans_ + ks->trans_index(src, target);
385  }
386  return temp_objvar("KSTrans", kst, &kst->obj_);
387 }
388 
389 static Object** ks_state(void* v) {
390  KSChan* ks = (KSChan*) v;
391  KSState* kss = ks->state_ + (int) chkarg(1, 0, ks->nstate_ - 1);
392  return temp_objvar("KSState", kss, &kss->obj_);
393 }
394 
395 static Object** ks_gate(void* v) {
396  KSChan* ks = (KSChan*) v;
397  KSGateComplex* ksg = ks->gc_ + (int) chkarg(1, 0, ks->ngate_ - 1);
398  return temp_objvar("KSGate", ksg, &ksg->obj_);
399 }
400 
401 static const char** ks_name(void* v) {
402  KSChan* ks = (KSChan*) v;
403  if (ifarg(1)) {
404  ks->setname(gargstr(1));
405  }
406  char** ps = hoc_temp_charptr();
407  *ps = (char*) ks->name_.string();
408  return (const char**) ps;
409 }
410 
411 static const char** ks_ion(void* v) {
412  KSChan* ks = (KSChan*) v;
413  if (ifarg(1)) {
414  ks->setion(gargstr(1));
415  }
416  char** ps = hoc_temp_charptr();
417  *ps = (char*) ks->ion_.string();
418  return (const char**) ps;
419 }
420 
421 static const char** ks_ligand(void* v) {
422  KSChan* ks = (KSChan*) v;
423  char** ps = hoc_temp_charptr();
424  *ps = (char*) ks->ligands_[(int) chkarg(1, 0, ks->nligand_ - 1)]->name;
425  return (const char**) ps;
426 }
427 
428 static double kss_frac(void* v) {
429  chkobj(v);
430  KSState* kss = (KSState*) v;
431  if (ifarg(1)) {
432  kss->f_ = chkarg(1, 0., 1e9);
433  }
434  return kss->f_;
435 }
436 
437 static double kss_index(void* v) {
438  chkobj(v);
439  KSState* kss = (KSState*) v;
440  return kss->index_;
441 }
442 
443 static Object** kss_gate(void* v) {
444  chkobj(v);
445  KSState* kss = (KSState*) v;
446  KSChan* ks = kss->ks_;
447  int ig = ks->gate_index(kss->index_);
448  KSGateComplex* ksg = ks->gc_ + ig;
449  return temp_objvar("KSGate", ksg, &ksg->obj_);
450 }
451 
452 static const char** kss_name(void* v) {
453  chkobj(v);
454  KSState* kss = (KSState*) v;
455  if (ifarg(1)) {
456  kss->ks_->setsname(kss->index_, gargstr(1));
457  }
458  char** ps = hoc_temp_charptr();
459  *ps = (char*) kss->string();
460  return (const char**) ps;
461 }
462 
463 static double ksg_nstate(void* v) {
464  chkobj(v);
465  KSGateComplex* ksg = (KSGateComplex*) v;
466  return (double) ksg->nstate_;
467 }
468 
469 static double ksg_power(void* v) {
470  chkobj(v);
471  KSGateComplex* ksg = (KSGateComplex*) v;
472  if (ifarg(1)) {
473  // could affect validity of single channel style
474  ksg->ks_->power(ksg, (int) chkarg(1, 0, 1e6));
475  }
476  return (double) ksg->power_;
477 }
478 
479 static double ksg_sindex(void* v) {
480  chkobj(v);
481  KSGateComplex* ksg = (KSGateComplex*) v;
482  return (double) ksg->sindex_;
483 }
484 
485 static double ksg_index(void* v) {
486  chkobj(v);
487  KSGateComplex* ksg = (KSGateComplex*) v;
488  return (double) ksg->index_;
489 }
490 
491 static double kst_set_f(void* v) {
492  chkobj(v);
493  KSTransition* kst = (KSTransition*) v;
494  int i = (int) chkarg(1, 0, 1);
495  int type = (int) chkarg(2, 0, 7);
496  Vect* vec = vector_arg(3);
497  double vmin = -100;
498  double vmax = 50;
499  if (type == 7) { // table, optional vmin, vmax
500  if (ifarg(4)) {
501  vmin = *getarg(4);
502  vmax = *getarg(5);
503  }
504  }
505  kst->setf(i, type, vec, vmin, vmax);
506  return 0;
507 }
508 
509 static double kst_index(void* v) {
510  chkobj(v);
511  KSTransition* kst = (KSTransition*) v;
512  return (double) kst->index_;
513 }
514 
515 static double kst_type(void* v) {
516  chkobj(v);
517  KSTransition* kst = (KSTransition*) v;
518  if (ifarg(1)) {
519  int type = (int) chkarg(1, 0, 3);
520  char* s = NULL;
521  if (type >= 2) {
522  s = gargstr(2);
523  }
524  Object* o = kst->obj_;
525  kst->ks_->settype(kst, type, s); // kst may change
526  kst = (KSTransition*) o->u.this_pointer;
527  }
528  return (double) kst->type_;
529 }
530 
531 static double kst_ftype(void* v) {
532  chkobj(v);
533  KSTransition* kst = (KSTransition*) v;
534  KSChanFunction* f;
535  if ((int) chkarg(1, 0, 1) == 0) {
536  f = kst->f0;
537  } else {
538  f = kst->f1;
539  }
540  if (f) {
541  return (double) f->type();
542  }
543  return -1.;
544 }
545 
546 static double kst_ab(void* v) {
547  chkobj(v);
548  KSTransition* kst = (KSTransition*) v;
549  Vect* x = vector_arg(1);
550  Vect* a = vector_arg(2);
551  Vect* b = vector_arg(3);
552  kst->ab(x, a, b);
553  return 0;
554 }
555 
556 static double kst_inftau(void* v) {
557  chkobj(v);
558  KSTransition* kst = (KSTransition*) v;
559  Vect* x = vector_arg(1);
560  Vect* a = vector_arg(2);
561  Vect* b = vector_arg(3);
562  kst->inftau(x, a, b);
563  return 0;
564 }
565 
566 static double kst_f(void* v) {
567  chkobj(v);
568  KSTransition* kst = (KSTransition*) v;
569  int i = (int) chkarg(1, 0, 1);
570  KSChanFunction* f = (i ? kst->f1 : kst->f0);
571  if (!f) {
572  return 0.;
573  }
574  double x = *getarg(2);
575  return f->f(x);
576 }
577 
578 static Object** kst_src(void* v) {
579  chkobj(v);
580  KSTransition* kst = (KSTransition*) v;
581  KSState* kss = kst->ks_->state_ + kst->src_;
582  return temp_objvar("KSState", kss, &kss->obj_);
583 }
584 
585 static Object** kst_target(void* v) {
586  chkobj(v);
587  KSTransition* kst = (KSTransition*) v;
588  KSState* kss = kst->ks_->state_ + kst->target_;
589  return temp_objvar("KSState", kss, &kss->obj_);
590 }
591 
592 static Object** kst_parm(void* v) {
593  chkobj(v);
594  KSTransition* kst = (KSTransition*) v;
595  KSChanFunction* f;
596  if ((int) chkarg(1, 0, 1) == 0) {
597  f = kst->f0;
598  } else {
599  f = kst->f1;
600  }
601  Vect* vec = NULL;
602  if (f) {
603  vec = f->gp_;
604  if (f->type() == 7) {
605  if (ifarg(2)) {
606  double* px;
607  px = hoc_pgetarg(2);
608  *px = ((KSChanTable*) f)->vmin_;
609  px = hoc_pgetarg(3);
610  *px = ((KSChanTable*) f)->vmax_;
611  }
612  }
613  }
614  return vector_temp_objvar(vec);
615 };
616 
617 static const char** kst_ligand(void* v) {
618  static char s[20];
619  ;
620  s[0] = '\0';
621  chkobj(v);
622  KSTransition* kst = (KSTransition*) v;
623  if (kst->type_ >= 2) {
624  strncpy(s, kst->ks_->ligands_[kst->ligand_index_]->name, 20);
625  s[strlen(s) - 4] = (kst->type_ == 3) ? 'i' : 'o';
626  s[strlen(s) - 3] = '\0';
627  }
628  char** ps = hoc_temp_charptr();
629  *ps = s;
630  return (const char**) ps;
631 }
632 
633 static double kst_stoichiometry(void* v) {
634  KSTransition* kst = (KSTransition*) v;
635  if (ifarg(1)) {
636  kst->stoichiom_ = (int) chkarg(1, 1, 1e9);
637  }
638  return double(kst->stoichiom_);
639 }
640 
641 static double ks_pr(void* v) {
642  KSChan* ks = (KSChan*) v;
643  KSTransition* kt;
644 
645  Printf("%s type properties\n", hoc_object_name(ks->obj_));
646  Printf("name=%s is_point_=%s ion_=%s cond_model_=%d\n",
647  ks->name_.string(),
648  (ks->is_point() ? "true" : "false"),
649  ks->ion_.string(),
650  ks->cond_model_);
651  Printf(" ngate=%d nstate=%d nhhstate=%d nligand=%d ntrans=%d ivkstrans=%d iligtrans=%d\n",
652  ks->ngate_,
653  ks->nstate_,
654  ks->nhhstate_,
655  ks->nligand_,
656  ks->ntrans_,
657  ks->ivkstrans_,
658  ks->iligtrans_);
659  Printf(" default gmax=%g erev=%g\n", ks->gmax_deflt_, ks->erev_deflt_);
660  for (int i = 0; i < ks->ngate_; ++i) {
661  Printf(" gate %d index=%d nstate=%d power=%d\n",
662  i,
663  ks->gc_[i].sindex_,
664  ks->gc_[i].nstate_,
665  ks->gc_[i].power_);
666  }
667  for (int i = 0; i < ks->nligand_; ++i) {
668  Printf(" ligand %d %s\n", i, ks->ligands_[i]->name);
669  }
670  for (int i = 0; i < ks->iligtrans_; ++i) {
671  kt = ks->trans_ + i;
672  Printf(" trans %d src=%d target=%d type=%d\n", i, kt->src_, kt->target_, kt->type_);
673  Printf(" f0 type=%d f1 type=%d\n",
674  kt->f0 ? kt->f0->type() : -1,
675  kt->f1 ? kt->f1->type() : -1);
676  }
677  for (int i = ks->iligtrans_; i < ks->ntrans_; ++i) {
678  kt = ks->trans_ + i;
679  Printf(" trans %d src=%d target=%d type=%d ligindex=%d\n",
680  i,
681  kt->src_,
682  kt->target_,
683  kt->type_,
684  kt->ligand_index_);
685  Printf(" f0 type=%d f1 type=%d\n",
686  kt->f0 ? kt->f0->type() : -1,
687  kt->f1 ? kt->f1->type() : -1);
688  }
689  Printf(" state names and fractional conductance\n");
690  for (int i = 0; i < ks->nstate_; ++i) {
691  Printf(" %d %s %g\n", i, ks->state_[i].string(), ks->state_[i].f_);
692  }
693  return 1;
694 }
695 
696 static Member_func ks_dmem[] = {
697  // keeping c++ consistent with java
698  {"setstructure", ks_setstructure},
699 
700  {"remove_state", ks_remove_state},
701  {"remove_transition", ks_remove_transition},
702 
703  {"ngate", ks_ngate},
704  {"nstate", ks_nstate},
705  {"ntrans", ks_ntrans},
706  {"nligand", ks_nligand},
707  {"is_point", ks_is_point},
708  {"single", ks_single},
709  {"pr", ks_pr},
710 
711  {"iv_type", ks_iv_type},
712  {"gmax", ks_gmax},
713  {"erev", ks_erev},
714  {"vres", ks_vres},
715  {"rseed", ks_rseed},
716  {"usetable", ks_usetable},
717  {nullptr, nullptr}};
718 
719 static Member_ret_obj_func ks_omem[] = {{"add_hhstate", ks_add_hhstate},
720  {"add_ksstate", ks_add_ksstate},
721  {"add_transition", ks_add_transition},
722  {"trans", ks_trans},
723  {"state", ks_state},
724  {"gate", ks_gate},
725  {nullptr, nullptr}};
726 
727 static Member_ret_str_func ks_smem[] = {{"name", ks_name},
728  {"ion", ks_ion},
729  {"ligand", ks_ligand},
730  {nullptr, nullptr}};
731 
732 static Member_func kss_dmem[] = {{"frac", kss_frac}, {"index", kss_index}, {nullptr, nullptr}};
733 
734 static Member_ret_obj_func kss_omem[] = {{"gate", kss_gate}, {nullptr, nullptr}};
735 
736 static Member_ret_str_func kss_smem[] = {{"name", kss_name}, {nullptr, nullptr}};
737 
738 static Member_func ksg_dmem[] = {{"nstate", ksg_nstate},
739  {"power", ksg_power},
740  {"sindex", ksg_sindex},
741  {"index", ksg_index},
742  {nullptr, nullptr}};
743 
744 static Member_ret_obj_func ksg_omem[] = {{nullptr, nullptr}};
745 
746 static Member_ret_str_func ksg_smem[] = {{nullptr, nullptr}};
747 
748 static Member_func kst_dmem[] = {{"set_f", kst_set_f},
749  {"index", kst_index},
750  {"type", kst_type},
751  {"ftype", kst_ftype},
752  {"ab", kst_ab},
753  {"inftau", kst_inftau},
754  {"f", kst_f},
755  {"stoichiometry", kst_stoichiometry},
756  {nullptr, nullptr}};
757 
758 static Member_ret_obj_func kst_omem[] = {{"src", kst_src},
759  {"target", kst_target},
760  {"parm", kst_parm},
761  {nullptr, nullptr}};
762 
763 static Member_ret_str_func kst_smem[] = {{"ligand", kst_ligand}, {nullptr, nullptr}};
764 
765 static void* ks_cons(Object* o) {
766  /*
767  hoc_obj_ref(o); // so never destroyed
768  char* suffix = gargstr(1);
769  check(suffix);
770  char* ion = gargstr(2);
771  Object* t1 = *hoc_objgetarg(4);
772  Object* t2 = *hoc_objgetarg(7);
773  check_obj_type(t1, "VGateTransRate");
774  check_obj_type(t2, "VGateTransRate");
775  hoc_obj_ref(t1); // never destroyed
776  hoc_obj_ref(t2); // never destroyed
777  */
778  bool isp = false;
779  if (ifarg(1)) {
780  isp = ((int) chkarg(1, 0, 1)) != 0;
781  }
782  KSChan* c = new KSChan(o, isp);
783  return c;
784 }
785 static void ks_destruct(void*) {
786  assert(0);
787 }
788 
789 // construction of KSState, KSGateComplex, and KSTransition are
790 // handled by KSChan in order for it to maintain its slightly more
791 // computationally efficient lists
792 static void* kss_cons(Object* o) {
793  hoc_execerror("Cannot create a KSState except through KSChan", 0);
794  return NULL;
795 }
796 static void kss_destruct(void*) {}
797 static void* ksg_cons(Object* o) {
798  hoc_execerror("Cannot create a KSGate except through KSChan", 0);
799  return NULL;
800 }
801 static void ksg_destruct(void*) {}
802 static void* kst_cons(Object* o) {
803  hoc_execerror("Cannot create a KSTransition except through KSChan", 0);
804  return NULL;
805 }
806 static void kst_destruct(void*) {}
807 
808 void KSChan_reg() {
813  ksstate_sym = hoc_lookup("KSState");
814  ksgate_sym = hoc_lookup("KSGate");
815  kstrans_sym = hoc_lookup("KSTrans");
816  KSSingle::vres_ = 0.1;
817  KSSingle::idum_ = 0;
818 }
819 
820 // param is gmax, g, i --- if change then change numbers below
821 // state names are handled individually
822 static const char* m_kschan_pat[] = {"0", "kschan", "gmax", 0, "g", "i", 0, 0, 0};
823 static const char* m_kschan[9];
824 // gmax=0 g=1 i=1 state names will be modltype 2, there are no pointer variables
825 
826 void KSChan::add_channel(const char** m) {
827  KSChan* c = (KSChan*) this;
828  Symlist* sav = hoc_symlist;
831  if (is_point()) {
833  nrn_alloc,
834  nrn_cur,
835  nrn_jacob,
836  nrn_state,
837  nrn_init,
838  -1,
839  1,
842  member_func);
843  } else {
845  }
847  hoc_symlist = sav;
848  mechtype_ = nrn_get_mechtype(m[1]);
849  // printf("mechanism type is %d\n", mechtype_);
851  if (!channels) {
852  channels = new KSChanList;
853  }
854  while (channels->size() < mechtype_) {
855  channels->push_back(nullptr);
856  }
857  channels->push_back(c);
858 }
859 
860 KSChan::KSChan(Object* obj, bool is_p) {
861  // printf("KSChan created\n");
862  nhhstate_ = 0;
863  mechtype_ = -1;
864  usetable(false, 0, 1., 0.);
865 
866  is_point_ = is_p;
867  is_single_ = false;
868  single_ = NULL;
869  ppoff_ = (is_point() ? (is_single() ? 3 : 2) : 0); // area, pnt, single
870  gmaxoffset_ = (is_single() ? 1 : 0); // and Nsingle is the first
871  obj_ = obj;
872  hoc_obj_ref(obj_);
873  gc_ = NULL;
874  state_ = NULL;
875  trans_ = NULL;
876  iv_relation_ = NULL;
878  ngate_ = nligand_ = nstate_ = nksstate_ = 0;
879  ntrans_ = iligtrans_ = ivkstrans_ = 0;
880  cond_model_ = 0;
881  ion_sym_ = NULL;
882  ligands_ = NULL;
883  mechsym_ = NULL;
884  rlsym_ = NULL;
885  char buf[50];
886  sprintf(buf, "Chan%d", obj_->index);
887  name_ = buf;
888  ion_ = "NonSpecific";
889  mat_ = NULL;
890  elms_ = NULL;
891  diag_ = NULL;
892  gmax_deflt_ = 0.;
893  erev_deflt_ = 0.;
894  soffset_ = 4; // gmax, e, g, i before the first state in p array
895  build();
896 }
897 
899 
901  if (mechsym_) {
902  return;
903  }
904  int i;
905  char buf[100];
906  if (strcmp(ion_.string(), "NonSpecific") != 0) {
907  ion_reg(ion_.string(), -10000.);
908  sprintf(buf, "%s_ion", ion_.string());
909  ion_sym_ = looksym(buf);
910  if (!ion_sym_) {
911  hoc_execerror(buf, " is not an ion mechanism");
912  }
913  }
914  const char* suffix = name_.string();
915  char unsuffix[100];
916  if (is_point()) {
917  unsuffix[0] = '\0';
918  } else {
919  sprintf(unsuffix, "_%s", name_.string());
920  }
921  if (looksym(suffix)) {
922  hoc_execerror(suffix, "already exists");
923  }
924  nrn_assert((m_kschan[0] = strdup(m_kschan_pat[0])) != 0);
925  nrn_assert((m_kschan[1] = strdup(suffix)) != 0);
926  nrn_assert(snprintf(buf, 100, "gmax%s", unsuffix) < 100);
927  nrn_assert((m_kschan[2] = strdup(buf)) != 0);
928  int aoff = 0;
929  if (!ion_sym_) {
930  nrn_assert(snprintf(buf, 100, "e%s", unsuffix) < 100);
931  nrn_assert((m_kschan[3] = strdup(buf)) != 0);
932  aoff = 1;
933  }
934  m_kschan[3 + aoff] = 0;
935  nrn_assert(snprintf(buf, 100, "g%s", unsuffix) < 100);
936  nrn_assert((m_kschan[4 + aoff] = strdup(buf)) != 0);
937  nrn_assert(snprintf(buf, 100, "i%s", unsuffix) < 100);
938  nrn_assert((m_kschan[5 + aoff] = strdup(buf)) != 0);
939  m_kschan[6 + aoff] = 0;
940  m_kschan[7 + aoff] = 0;
941  soffset_ = 3 + aoff; // first state points here in p array
943  for (i = 0; i < 9; ++i)
944  if (m_kschan[i]) {
945  free((void*) m_kschan[i]);
946  }
948  if (is_point()) {
950  } else {
951  rlsym_ = mechsym_;
952  }
953  setcond();
954  sname_install();
955  // printf("%s allowed in insert statement\n", name_.string());
956 }
957 
958 void KSChan::setname(const char* s) {
959  // printf("KSChan::setname\n");
960  int i;
961  if (strcmp(s, name_.string()) == 0) {
962  return;
963  }
964  name_ = s;
965  if (mechsym_) {
966  char old_suffix[100];
967  i = 0;
968  while (strcmp(mechsym_->name, name_.string()) != 0 && looksym(name_.string())) {
969  Printf("KSChan::setname %s already in use\n", name_.string());
970  sprintf(old_suffix, "%s%d", s, i);
971  name_ = old_suffix;
972  ++i;
973  // if want original name use if statement and something like this
974  // name_ = mechsym_->name
975  // return;
976  }
977  sprintf(old_suffix, "_%s", mechsym_->name);
978  const char* suffix = name_.string();
979  free(mechsym_->name);
980  mechsym_->name = strdup(suffix);
981  if (is_point()) {
982  free(rlsym_->name);
983  rlsym_->name = strdup(suffix);
984  }
985 
986  Symbol* sp;
987  if (!is_point())
988  for (i = 0; i < rlsym_->s_varn; ++i) {
989  sp = rlsym_->u.ppsym[i];
990  char* cp = strstr(sp->name, old_suffix);
991  if (cp) {
992  int nbase = cp - sp->name;
993  int n = nbase + strlen(suffix) + 2;
994  char* s1 = static_cast<char*>(hoc_Emalloc(n));
995  hoc_malchk();
996  strncpy(s1, sp->name, nbase);
997  sprintf(s1 + nbase, "_%s", suffix);
998  // printf("KSChan::setname change %s to %s\n", sp->name, s1);
999  free(sp->name);
1000  sp->name = s1;
1001  }
1002  }
1003  // printf("%s renamed to %s\n", old_suffix+1, name_.string());
1004  }
1005 }
1006 
1007 int KSChan::state(const char* s) {
1008  int i;
1009  for (i = 0; i < nstate_; ++i) {
1010  if (strcmp(state_[i].string(), s) == 0) {
1011  return i;
1012  }
1013  }
1014  return -1;
1015 }
1016 
1018  if (is_single() && p != 1) {
1019  set_single(false);
1020  }
1021  gc->power_ = p;
1022 }
1023 
1024 void KSChan::set_single(bool b, bool update) {
1025  if (!is_point()) {
1026  b = false;
1027  return;
1028  }
1029  if (b && (ngate_ != 1 || gc_[0].power_ != 1 || nhhstate_ > 0 || nksstate_ < 2)) {
1030  b = false;
1031  hoc_warning(
1032  "KSChan single channel mode implemented only for single ks gating complex to first "
1033  "power",
1034  0);
1035  }
1036  if (is_single()) {
1037  memb_func[mechtype_].singchan_ = NULL;
1039  delete single_;
1040  single_ = NULL;
1041  }
1042  is_single_ = b;
1043  if (update) {
1044  update_prop();
1045  }
1046  if (b) {
1047  single_ = new KSSingle(this);
1048  memb_func[mechtype_].singchan_ = singchan;
1050  }
1051 }
1052 
1053 const char* KSChan::state(int i) {
1054  return state_[i].string();
1055 }
1056 
1057 int KSChan::trans_index(const char* s, const char* t) {
1058  int i;
1059  for (i = 0; i < ntrans_; ++i) {
1060  if (strcmp(state_[trans_[i].src_].string(), s) == 0 &&
1061  strcmp(state_[trans_[i].target_].string(), t) == 0) {
1062  return i;
1063  }
1064  }
1065  return -1;
1066 }
1067 
1068 int KSChan::trans_index(int s, int t) {
1069  int i;
1070  for (i = 0; i < ntrans_; ++i) {
1071  if (trans_[i].src_ == s && trans_[i].target_ == t) {
1072  return i;
1073  }
1074  }
1075  return -1;
1076 }
1077 
1078 int KSChan::gate_index(int is) {
1079  int i;
1080  for (i = 1; i < ngate_; ++i) {
1081  if (is < gc_[i].sindex_) {
1082  return i - 1;
1083  }
1084  }
1085  return ngate_ - 1;
1086 }
1087 
1089  // prop.param is [Nsingle], gmax, [e], g, i, states
1090  // prop.dparam for density is [4ion], [4ligands]
1091  // prop.dparam for point is area, pnt, [singledata], [4ion], [4ligands]
1092  int i;
1093  Symbol* searchsym = (is_point() ? mechsym_ : NULL);
1094 
1095  // some old sym pointers
1096  Symbol* gmaxsym = rlsym_->u.ppsym[gmaxoffset_];
1097  Symbol* gsym = rlsym_->u.ppsym[soffset_ - 2];
1098  Symbol* isym = rlsym_->u.ppsym[soffset_ - 1];
1099  Symbol* esym = ion_sym_ ? NULL : rlsym_->u.ppsym[gmaxoffset_ + 1];
1100  int old_gmaxoffset = gmaxoffset_;
1101  int old_soffset = soffset_;
1102  int old_svarn = rlsym_->s_varn;
1103 
1104  // sizes and offsets
1105  psize_ = 3; // prop->param: gmax, g, i
1106  dsize_ = 0; // prop->dparam: empty
1107  ppoff_ = 0;
1108  soffset_ = 3;
1109  gmaxoffset_ = 0;
1110  if (is_single()) {
1111  psize_ += 1; // Nsingle exists
1112  dsize_ += 1; // KSSingleNodeData* exists
1113  gmaxoffset_ = 1;
1114  ppoff_ += 1;
1115  soffset_ += 1;
1116  }
1117  if (is_point()) {
1118  dsize_ += 2; // area, Point_process* exists
1119  ppoff_ += 2;
1120  }
1121  if (ion_sym_ == NULL) {
1122  psize_ += 1; // e exists
1123  soffset_ += 1;
1124  } else {
1125  dsize_ += 4; // ion current
1126  }
1127  dsize_ += 4 * nligand_;
1128  psize_ += nstate_;
1129 
1130  // range variable names associated with prop->param
1131  rlsym_->s_varn = psize_; // problem here
1132  Symbol** ppsym = newppsym(rlsym_->s_varn);
1133  if (is_point()) {
1134  Symbol* sym = looksym("Nsingle", searchsym);
1135  if (is_single()) { // Nsingle exists with offset 0
1136  if (!sym) {
1137  sym = installsym("Nsingle", RANGEVAR, searchsym);
1138  }
1139  ppsym[NSingleIndex] = sym;
1140  sym->subtype = nrnocCONST; // PARAMETER
1141  sym->u.rng.type = rlsym_->subtype;
1142  sym->u.rng.index = NSingleIndex;
1143  } else if (sym) { // eliminate if Nsingle exists
1144  freesym(sym, searchsym);
1145  }
1146  }
1147  ppsym[gmaxoffset_] = gmaxsym;
1148  gmaxsym->u.rng.index = gmaxoffset_;
1149  ppsym[soffset_ - 2] = gsym;
1150  gsym->u.rng.index = soffset_ - 2;
1151  ppsym[soffset_ - 1] = isym;
1152  isym->u.rng.index = soffset_ - 1;
1153  if (esym) {
1154  ppsym[gmaxoffset_ + 1] = esym;
1155  esym->u.rng.index = gmaxoffset_ + 1;
1156  }
1157  int j;
1158  for (j = soffset_, i = old_soffset; i < old_svarn; ++i, ++j) {
1159  ppsym[j] = rlsym_->u.ppsym[i];
1160  ppsym[j]->u.rng.index = j;
1161  }
1162  free(rlsym_->u.ppsym);
1163  rlsym_->u.ppsym = ppsym;
1164  setcond();
1165  state_consist(gmaxoffset_ - old_gmaxoffset);
1166  ion_consist();
1167 }
1168 
1169 void KSChan::setion(const char* s) {
1170  // printf("KSChan::setion\n");
1171  int i;
1172  if (strcmp(ion_.string(), s) == 0) {
1173  return;
1174  }
1175  Symbol* searchsym = (is_point() ? mechsym_ : NULL);
1176  if (strlen(s) == 0) {
1177  ion_ = "NonSpecific";
1178  } else {
1179  ion_ = s;
1180  }
1181  char buf[100];
1182  int pdoff = ppoff_;
1183  int io = gmaxoffset_;
1184  if (strcmp(ion_.string(), "NonSpecific") == 0) { // non-specific
1185  if (ion_sym_) { // switch from useion to non-specific
1186  printf("switch from useion to non-specific\n");
1187  rlsym_->s_varn += 1;
1188  Symbol** ppsym = newppsym(rlsym_->s_varn);
1189  for (i = 0; i <= io; ++i) {
1190  ppsym[i] = rlsym_->u.ppsym[i];
1191  }
1192  ion_sym_ = NULL;
1193  if (is_point()) {
1194  sprintf(buf, "e");
1195  } else {
1196  sprintf(buf, "e_%s", rlsym_->name);
1197  }
1198  if (looksym(buf, searchsym)) {
1199  hoc_execerror(buf, "already exists");
1200  }
1201  ppsym[1 + io] = installsym(buf, RANGEVAR, searchsym);
1202  ppsym[1 + io]->subtype = 0;
1203  ppsym[1 + io]->u.rng.type = rlsym_->subtype;
1204  ppsym[1 + io]->cpublic = 1;
1205  ppsym[1 + io]->u.rng.index = 1 + io;
1206  for (i = 2 + io; i < rlsym_->s_varn; ++i) {
1207  ppsym[i] = rlsym_->u.ppsym[i - 1];
1208  ppsym[i]->u.rng.index += 1;
1209  }
1210  free(rlsym_->u.ppsym);
1211  rlsym_->u.ppsym = ppsym;
1212  soffset_ += 1;
1213  setcond();
1214  state_consist();
1215  ion_consist();
1216  }
1217  } else { // want useion
1218  pdoff = 5 + ppoff_;
1219  sprintf(buf, "%s_ion", s);
1220  // is it an ion
1221  Symbol* sym = looksym(buf);
1222  if (!sym || sym->type != MECHANISM ||
1223  memb_func[sym->subtype].alloc != memb_func[looksym("na_ion")->subtype].alloc) {
1224  Printf("%s is not an ion mechanism", sym->name);
1225  }
1226  if (ion_sym_) { // there already is an ion
1227  if (strcmp(ion_sym_->name, buf) != 0) { // is it different
1228  // printf(" mechanism %s now uses %s instead of %s\n",
1229  // name_.string(), sym->name, ion_sym_->name);
1230  ion_sym_ = sym;
1231  state_consist();
1232  ion_consist();
1233  }
1234  // if same do nothing
1235  } else { // switch from non-specific to useion
1236  Symbol* searchsym = (is_point() ? mechsym_ : NULL);
1237  ion_sym_ = sym;
1238  rlsym_->s_varn -= 1;
1239  Symbol** ppsym = newppsym(rlsym_->s_varn);
1240  for (i = 0; i <= io; ++i) {
1241  ppsym[i] = rlsym_->u.ppsym[i];
1242  }
1243  freesym(rlsym_->u.ppsym[1 + io], searchsym);
1244  for (i = 1 + io; i < rlsym_->s_varn; ++i) {
1245  ppsym[i] = rlsym_->u.ppsym[i + 1];
1246  ppsym[i]->u.rng.index -= 1;
1247  }
1248  free(rlsym_->u.ppsym);
1249  rlsym_->u.ppsym = ppsym;
1250  --soffset_;
1251  setcond();
1252  state_consist();
1253  ion_consist();
1254  }
1255  }
1256  for (i = iligtrans_; i < ntrans_; ++i) {
1257  trans_[i].lig2pd(pdoff);
1258  }
1259 }
1260 
1261 void KSChan::setsname(int i, const char* s) {
1262  state_[i].name_ = s;
1263  sname_install();
1264 }
1265 
1267  int i;
1268  for (i = 0; i < nstate_; ++i) {
1269  unref(state_[i].obj_);
1270  }
1271  for (i = 0; i < ngate_; ++i) {
1272  unref(gc_[i].obj_);
1273  }
1274  for (i = 0; i < ntrans_; ++i) {
1275  unref(trans_[i].obj_);
1276  }
1277  if (gc_) {
1278  delete[] gc_;
1279  gc_ = NULL;
1280  }
1281  if (state_) {
1282  delete[] state_;
1283  state_ = NULL;
1284  }
1285  if (trans_) {
1286  delete[] trans_;
1287  trans_ = NULL;
1288  }
1289  if (iv_relation_) {
1290  delete iv_relation_;
1291  iv_relation_ = NULL;
1292  }
1293  if (ligands_) {
1294  delete[] ligands_;
1295  ligands_ = NULL;
1296  }
1297  if (mat_) {
1298  spDestroy(mat_);
1299  delete[] elms_;
1300  delete[] diag_;
1301  mat_ = NULL;
1302  }
1303  ngate_ = 0;
1304  nstate_ = 0;
1305  ntrans_ = 0;
1306  state_size_ = 0;
1307  gate_size_ = 0;
1308  trans_size_ = 0;
1309 }
1310 
1312  // printf("KSChan::setcond\n");
1313  int i;
1314  if (iv_relation_) {
1315  delete iv_relation_;
1316  }
1317  if (ion_sym_) {
1318  if (cond_model_ == 2) {
1319  if (is_point()) {
1320  iv_relation_ = new KSPPIvghk();
1322  } else {
1323  iv_relation_ = new KSIvghk();
1325  }
1326  for (i = gmaxoffset_; i < 2 + gmaxoffset_; ++i) {
1327  rlsym_->u.ppsym[i]->name[0] = 'p';
1328  hoc_symbol_units(rlsym_->u.ppsym[i], (is_point() ? "cm3/s" : "cm/s"));
1329  }
1330  } else {
1331  if (is_point()) {
1332  iv_relation_ = new KSPPIv();
1333  } else {
1334  iv_relation_ = new KSIv();
1335  }
1336  for (i = gmaxoffset_; i < 2 + gmaxoffset_; ++i) {
1337  rlsym_->u.ppsym[i]->name[0] = 'g';
1338  hoc_symbol_units(rlsym_->u.ppsym[i], is_point() ? "uS" : "S/cm2");
1339  }
1340  }
1341  hoc_symbol_units(rlsym_->u.ppsym[2 + gmaxoffset_], is_point() ? "nA" : "mA/cm2");
1342  } else {
1343  if (is_point()) {
1344  iv_relation_ = new KSPPIvNonSpec();
1345  } else {
1346  iv_relation_ = new KSIvNonSpec();
1347  }
1348  for (i = gmaxoffset_; i < 3 + gmaxoffset_; i += 2) {
1349  rlsym_->u.ppsym[i]->name[0] = 'g';
1350  hoc_symbol_units(rlsym_->u.ppsym[i], is_point() ? "uS" : "S/cm2");
1351  }
1352  hoc_symbol_units(rlsym_->u.ppsym[1 + gmaxoffset_], "mV");
1353  hoc_symbol_units(rlsym_->u.ppsym[3 + gmaxoffset_], is_point() ? "nA" : "mA/cm2");
1354  }
1355  if (is_point()) {
1356  ((KSPPIv*) iv_relation_)->ppoff_ = ppoff_;
1357  }
1358 }
1359 
1360 void KSChan::setligand(int i, const char* lig) {
1361  char buf[100];
1362  // printf("KSChan::setligand %d %s\n", i, lig);
1363  sprintf(buf, "%s_ion", lig);
1364  Symbol* s = looksym(buf);
1365  if (!s) {
1366  ion_reg(lig, 0);
1367  s = looksym(buf);
1368  }
1369  if (s->type != MECHANISM ||
1370  memb_func[s->subtype].alloc != memb_func[looksym("na_ion")->subtype].alloc) {
1371  hoc_execerror(buf, "is already in use and is not an ion.");
1372  }
1373  ligands_[i] = s;
1374  if (mechsym_) {
1375  state_consist();
1376  ion_consist();
1377  }
1378 }
1379 
1380 void KSChan::settype(KSTransition* t, int type, const char* lig) {
1381  int i, j;
1382  // if no ligands involved then it is just a type change.
1383  usetable(false);
1384  if (type < 2 && t->type_ < 2) {
1385  t->type_ = type;
1386  return;
1387  }
1388  set_single(false);
1389  int ilig = -1;
1390  // is t already using a ligand
1391  int iligold = -2;
1392  if (t->type_ >= 2) {
1393  iligold = t->ligand_index_;
1394  // printf("t already using a ligand index %d\n", iligold);
1395  if (type < 2) { // from having to not having
1396  // what is to be done with existing ligand
1397  // is anybody else using it
1398  bool remove = true;
1399  for (i = iligtrans_; i < ntrans_; ++i) {
1400  if (trans_[i].ligand_index_ == iligold && iligold != i) {
1401  remove = false; // old is still needed
1402  }
1403  }
1404  if (remove) { // unneeded
1405  Symbol** ligands = NULL;
1406  --nligand_;
1407  if (nligand_ > 0) {
1408  ligands = new Symbol*[nligand_];
1409  }
1410  for (i = 0, j = 0; j < nligand_; ++i, ++j) {
1411  if (i == iligold) {
1412  ++j;
1413  }
1414  ligands[i] = ligands_[j];
1415  }
1416  delete[] ligands_;
1417  ligands_ = ligands;
1418  }
1419  // transitions with ligands may get decremented
1420  for (i = iligtrans_; i < ntrans_; ++i) {
1421  if (trans_[i].ligand_index_ > iligold) {
1422  --trans_[i].ligand_index_;
1423  }
1424  }
1425  // the transition may have to be moved forward
1426  assert(t->index_ >= iligtrans_);
1427  KSTransition tt = *t;
1428  t->obj_ = NULL;
1429  trans_remove(t->index_);
1431  t = trans_ + iligtrans_ - 1;
1432  t->type_ = type;
1433  t->ligand_index_ = -1;
1434  t->obj_ = tt.obj_;
1435  if (t->obj_) {
1436  t->obj_->u.this_pointer = t;
1437  }
1438  t->f0 = tt.f0;
1439  t->f1 = tt.f1;
1440  tt.f0 = NULL;
1441  tt.f1 = NULL;
1442  check_struct();
1443  state_consist();
1444  ion_consist();
1445  setupmat();
1446  return;
1447  }
1448  }
1449  // there is a ligand, handle the last two cases
1450  // is ligand valid
1451  char buf[100];
1452  // printf("KSChan::settype %s %d %s\n", hoc_object_name(t->obj_), type, lig);
1453  // printf("old t->ligand_index_=%d type=%d\n", t->ligand_index_, t->type_);
1454  strcpy(buf, lig);
1455  strcpy(buf + strlen(buf) - 1, "_ion");
1456  // printf("ion name %s\n", buf);
1457  Symbol* s = looksym(buf);
1458  if (!s) {
1459  hoc_execerror(buf, "does not exist");
1460  ion_reg(lig, 0);
1461  s = looksym(buf);
1462  }
1463  if (s->type != MECHANISM ||
1464  memb_func[s->subtype].alloc != memb_func[looksym("na_ion")->subtype].alloc) {
1465  hoc_execerror(buf, "is already in use and is not an ion.");
1466  }
1467  // is ligand in list
1468  for (i = 0; i < nligand_; ++i) {
1469  if (ligands_[i] == s) {
1470  ilig = i;
1471  break;
1472  }
1473  }
1474  // printf("ilig=%d iligold=%d\n", ilig, iligold);
1475  bool add2list = true;
1476  // if t already using a ligand, what is to be done with it
1477  if (t->type_ >= 2) {
1478  add2list = false;
1479  for (i = iligtrans_; i < ntrans_; ++i) {
1480  if (trans_[i].ligand_index_ == iligold && t->index_ != i) {
1481  add2list = true; // old is still needed
1482  }
1483  }
1484  }
1485  // printf("add2list=%d\n", add2list);
1486  if (add2list) { // add it to list
1487  Symbol** ligands = new Symbol*[nligand_ + 1];
1488  for (i = 0; i < nligand_; ++i) {
1489  ligands[i] = ligands_[i];
1490  }
1491  if (nligand_) {
1492  delete[] ligands_;
1493  }
1494  ilig = nligand_;
1495  ++nligand_;
1496  ligands_ = ligands;
1497  } else { // replace
1498  ilig = iligold;
1499  }
1500  ligands_[ilig] = s;
1501 #if 0
1502 printf("ligands\n");
1503 for (i=0; i < nligand_; ++i) {printf("%s\n", ligands_[ilig]->name);}
1504 #endif
1505  // update the transition
1506  t->ligand_index_ = ilig;
1507  t->type_ = type;
1508  // printf("new t->ligand_index_=%d type=%d\n", t->ligand_index_, t->type_);
1509  // if switch from no ligand to ligand
1510  // then transition must be moved to iligtrans or above
1511  if (iligold < 0 && ilig >= 0) {
1512 #if 0
1513 printf("old transition order\n");
1514 for (i=0; i < ntrans_; ++i) {
1515 printf("i=%d index=%d type=%d ligand_index=%d %s<->%s\n", i,
1516 trans_[i].index_, trans_[i].type_, trans_[i].ligand_index_,
1517 state_[trans_[i].src_].string(), state_[trans_[i].target_].string());
1518 }
1519 #endif
1520  assert(t->index_ < iligtrans_);
1521  KSTransition tt = *t;
1522  t->obj_ = NULL;
1523  t->f0 = NULL;
1524  t->f1 = NULL;
1525  trans_remove(t->index_);
1526  trans_insert(ntrans_, tt.src_, tt.target_);
1527  t = trans_ + ntrans_ - 1;
1528  t->obj_ = tt.obj_;
1529  t->ligand_index_ = tt.ligand_index_;
1530  t->type_ = tt.type_;
1531  t->f0 = tt.f0;
1532  t->f1 = tt.f1;
1533  tt.f0 = NULL;
1534  tt.f1 = NULL;
1535  if (t->obj_) {
1536  t->obj_->u.this_pointer = t;
1537  }
1538  if (iligtrans_ == ntrans_) {
1539  --iligtrans_;
1540  }
1541 #if 0
1542 printf("new transition order\n");
1543 for (i=0; i < ntrans_; ++i) {
1544 printf("i=%d index=%d type=%d ligand_index=%d %s<->%s %s\n", i,
1545 trans_[i].index_, trans_[i].type_, trans_[i].ligand_index_,
1546 state_[trans_[i].src_].string(), state_[trans_[i].target_].string(),
1548 }
1549 #endif
1550  }
1551  check_struct();
1552  state_consist();
1553  ion_consist();
1554  setupmat();
1555 }
1556 
1558  int i;
1559  usetable(false);
1560  // new state, transition, gate, and f
1561  int is = nhhstate_;
1562  state_insert(is, name, 1.);
1563  gate_insert(is, is, 1);
1564  trans_insert(is, is, is);
1565  trans_[is].ligand_index_ = -1;
1566  trans_[is].type_ = 0;
1567  // adjust gate indices
1568  for (i = nhhstate_; i < ngate_; ++i) {
1569  ++gc_[i].sindex_;
1570  }
1571  // adjust transition indices
1572  for (i = ivkstrans_; i < ntrans_; ++i) {
1573  ++trans_[i].src_;
1574  ++trans_[i].target_;
1575  }
1576  set_single(false);
1577  check_struct();
1578  sname_install();
1579  state_consist();
1580  setupmat();
1581  return state_ + is;
1582 }
1583 
1584 KSState* KSChan::add_ksstate(int ig, const char* name) {
1585  // states must be added so that the gate states are in sequence
1586  int i, is;
1587  usetable(false);
1588  if (ig == ngate_) {
1589  is = nstate_;
1590  gate_insert(ig, is, 1);
1591  } else {
1592  is = gc_[ig].sindex_ + gc_[ig].nstate_;
1593  ++gc_[ig].nstate_;
1594  }
1595  state_insert(is, name, 0.);
1596  if (nksstate_ == 0) {
1597  --nhhstate_;
1598  ++nksstate_;
1599  }
1600  // update gate indices
1601  for (i = ig + 1; i < ngate_; ++i) {
1602  ++gc_[i].sindex_;
1603  }
1604  // update transition indices
1605  for (i = ivkstrans_; i < ntrans_; ++i) {
1606  if (trans_[i].src_ > is) {
1607  --trans_[i].src_;
1608  }
1609  if (trans_[i].target_ > is) {
1610  --trans_[i].target_;
1611  }
1612  }
1613  check_struct();
1614  sname_install();
1615  set_single(false);
1616  state_consist();
1617  setupmat();
1618  return state_ + is;
1619 }
1620 
1621 void KSChan::remove_state(int is) {
1622  int i;
1623  usetable(false);
1624  if (is < nhhstate_) {
1625  state_remove(is);
1626  gate_remove(is);
1627  trans_remove(is);
1628  // adjust gate indices
1629  for (i = is; i < ngate_; ++i) {
1630  --gc_[i].sindex_;
1631  }
1632  // adjust transition indices
1633  for (i = is; i < ntrans_; ++i) {
1634  --trans_[i].src_;
1635  --trans_[i].target_;
1636  }
1637  } else { // remove a kinetic scheme state
1638  state_remove(is);
1639  // remove all the transitions involving this state
1640  for (i = ntrans_ - 1; i >= ivkstrans_; --i) {
1641  if (trans_[i].src_ == is || trans_[i].target_ == is) {
1642  trans_remove(i);
1643  }
1644  }
1645  // adjust transition indices
1646  for (i = ivkstrans_; i < ntrans_; ++i) {
1647  if (trans_[i].src_ > is) {
1648  --trans_[i].src_;
1649  }
1650  if (trans_[i].target_ > is) {
1651  --trans_[i].target_;
1652  }
1653  }
1654  // If this is the only state
1655  // the gate is removed. Otherwise the index and nstate
1656  // are updated. Note that it is not inconsistent for
1657  // the state graph of a gate to be multiple.
1658  for (i = nhhstate_; i < ngate_; ++i) {
1659  if (is >= gc_[i].sindex_ && is < (gc_[i].sindex_ + gc_[i].nstate_)) {
1660  if (gc_[i].nstate_ == 1) { // remove gate
1661  gate_remove(i);
1662  } else {
1663  --gc_[i].nstate_;
1664  if (is == gc_[i].sindex_) {
1665  ++gc_[i].sindex_;
1666  }
1667  }
1668  break;
1669  }
1670  }
1671  for (i = nhhstate_; i < ngate_; ++i) {
1672  if (gc_[i].sindex_ > is) {
1673  --gc_[i].sindex_;
1674  }
1675  }
1676  }
1677  set_single(false);
1678  check_struct();
1679  sname_install();
1680  state_consist();
1681  setupmat();
1682 }
1683 
1684 KSTransition* KSChan::add_transition(int src, int target, const char* ligand) {
1685  usetable(false);
1686  assert(ligand == NULL);
1687  int it = (ligand ? ntrans_ : iligtrans_);
1688  trans_insert(it, src, target);
1689  trans_[it].ligand_index_ = -1;
1690  trans_[it].type_ = 0;
1691  set_single(false);
1692  check_struct();
1693  setupmat();
1694  return trans_ + it;
1695 }
1696 
1698  usetable(false);
1699  assert(it >= ivkstrans_);
1700  set_single(false);
1701  trans_remove(it);
1702  check_struct();
1703  setupmat();
1704 }
1705 
1706 //#undef assert
1707 //#define assert(arg) if (!(arg)) { abort(); }
1708 
1710  int i;
1711  assert(ngate_ >= nhhstate_);
1714  for (i = 0; i < nhhstate_; ++i) {
1715  assert(trans_[i].src_ == i);
1716  assert(trans_[i].target_ == i);
1717  assert(gc_[i].sindex_ == i);
1718  assert(gc_[i].nstate_ == 1);
1719  }
1720  for (i = 1; i < ngate_; ++i) {
1721  assert(gc_[i].index_ == i);
1722  assert(gc_[i].sindex_ == gc_[i - 1].sindex_ + gc_[i - 1].nstate_);
1723  }
1724  for (i = ivkstrans_; i < ntrans_; ++i) {
1725  assert(trans_[i].src_ >= nhhstate_);
1726  assert(trans_[i].target_ >= nhhstate_);
1727  }
1728  for (i = 0; i < iligtrans_; ++i) {
1729  assert(trans_[i].type_ < 2);
1730  if (trans_[i].ligand_index_ != -1) {
1731  printf("trans_ %d ligand_index_=%d\n", i, trans_[i].ligand_index_);
1732  }
1733  assert(trans_[i].ligand_index_ == -1);
1734  }
1735  for (i = iligtrans_; i < ntrans_; ++i) {
1736  int j = trans_[i].ligand_index_;
1737  assert(j >= 0 && j < nligand_);
1738  assert(trans_[i].type_ >= 2);
1739  }
1740  for (i = 0; i < nstate_; ++i) {
1741  assert(state_[i].ks_ == this);
1742  assert(state_[i].index_ == i);
1743  Object* o = state_[i].obj_;
1744  if (o) {
1745  assert(o->u.this_pointer == state_ + i);
1746  }
1747  }
1748  for (i = 0; i < ntrans_; ++i) {
1749  assert(trans_[i].ks_ == this);
1750  assert(trans_[i].index_ == i);
1751  Object* o = trans_[i].obj_;
1752  if (o) {
1753  assert(o->u.this_pointer == trans_ + i);
1754  }
1755  }
1756 }
1757 
1758 KSState* KSChan::state_insert(int i, const char* n, double d) {
1759  int j;
1760  usetable(false);
1761  if (nstate_ >= state_size_) {
1762  state_size_ += 5;
1763  KSState* state = new KSState[state_size_];
1764  for (j = 0; j < nstate_; ++j) {
1765  state[j] = state_[j];
1766  }
1767  delete[] state_;
1768  for (j = 0; j < state_size_; ++j) {
1769  state[j].ks_ = this;
1770  }
1771  state_ = state;
1772  }
1773  for (j = i; j < nstate_; ++j) {
1774  state_[j + 1] = state_[j];
1775  }
1776  state_[i].f_ = d;
1777  state_[i].name_ = n;
1778  if (i <= nhhstate_) {
1779  ++nhhstate_;
1780  } else {
1781  ++nksstate_;
1782  }
1783  ++nstate_;
1784  for (j = 0; j < nstate_; ++j) {
1785  state_[j].index_ = j;
1786  if (state_[j].obj_) {
1787  state_[j].obj_->u.this_pointer = state_ + j;
1788  }
1789  }
1790  return state_ + i;
1791 }
1792 
1794  int j;
1795  usetable(false);
1796  unref(state_[i].obj_);
1797  for (j = i + 1; j < nstate_; ++j) {
1798  state_[j - 1] = state_[j];
1799  if (state_[j - 1].obj_) {
1800  state_[j - 1].obj_->u.this_pointer = state_ + j - 1;
1801  }
1802  }
1803  if (i < nhhstate_) {
1804  --nhhstate_;
1805  } else {
1806  --nksstate_;
1807  }
1808  --nstate_;
1809  state_[nstate_].obj_ = NULL;
1810  for (j = 0; j < nstate_; ++j) {
1811  state_[j].index_ = j;
1812  if (state_[j].obj_) {
1813  state_[j].obj_->u.this_pointer = state_ + j;
1814  }
1815  }
1816 }
1817 
1818 KSGateComplex* KSChan::gate_insert(int ig, int is, int power) {
1819  int j;
1820  usetable(false);
1821  if (ngate_ >= gate_size_) {
1822  gate_size_ += 5;
1824  for (j = 0; j < ngate_; ++j) {
1825  gc[j] = gc_[j];
1826  }
1827  delete[] gc_;
1828  gc_ = gc;
1829  for (j = 0; j < gate_size_; ++j) {
1830  gc_[j].ks_ = this;
1831  }
1832  }
1833  for (j = ig; j < ngate_; ++j) {
1834  gc_[j + 1] = gc_[j];
1835  }
1836  gc_[ig].sindex_ = is;
1837  gc_[ig].nstate_ = 1;
1838  gc_[ig].power_ = power;
1839  ++ngate_;
1840  for (j = 0; j < ngate_; ++j) {
1841  gc_[j].index_ = j;
1842  if (gc_[j].obj_) {
1843  gc_[j].obj_->u.this_pointer = gc_ + j;
1844  }
1845  }
1846  return gc_ + ig;
1847 }
1848 
1850  int j;
1851  usetable(false);
1852  unref(gc_[i].obj_);
1853  for (j = i + 1; j < ngate_; ++j) {
1854  gc_[j - 1] = gc_[j];
1855  if (gc_[j - 1].obj_) {
1856  gc_[j - 1].obj_->u.this_pointer = gc_ + j - 1;
1857  }
1858  }
1859  --ngate_;
1860  gc_[ngate_].obj_ = NULL;
1861  for (j = 0; j < ngate_; ++j) {
1862  gc_[j].index_ = j;
1863  if (gc_[j].obj_) {
1864  gc_[j].obj_->u.this_pointer = gc_ + j;
1865  }
1866  }
1867 }
1868 
1869 KSTransition* KSChan::trans_insert(int i, int src, int target) {
1870  int j;
1871  usetable(false);
1872  if (ntrans_ >= trans_size_) {
1873  trans_size_ += 5;
1874  KSTransition* trans = new KSTransition[trans_size_];
1875  for (j = 0; j < ntrans_; ++j) {
1876  trans[j] = trans_[j];
1877  trans_[j].f0 = NULL;
1878  trans_[j].f1 = NULL;
1879  }
1880  delete[] trans_;
1881  trans_ = trans;
1882  }
1883  for (j = i; j < ntrans_; ++j) {
1884  trans_[j + 1] = trans_[j];
1885  }
1886  trans_[i].src_ = src;
1887  trans_[i].target_ = target;
1888  trans_[i].f0 = NULL;
1889  trans_[i].f1 = NULL;
1891  if (i <= iligtrans_) {
1892  ++iligtrans_;
1893  }
1894  ++ntrans_;
1895  for (j = 0; j < ntrans_; ++j) {
1896  trans_[j].index_ = j;
1897  trans_[j].ks_ = this;
1898  if (trans_[j].obj_) {
1899  trans_[j].obj_->u.this_pointer = trans_ + j;
1900  }
1901  }
1902  return trans_ + i;
1903 }
1904 
1906  int j;
1907  usetable(false);
1908  unref(trans_[i].obj_);
1909  for (j = i + 1; j < ntrans_; ++j) {
1910  trans_[j - 1] = trans_[j];
1911  if (trans_[j - 1].obj_) {
1912  trans_[j - 1].obj_->u.this_pointer = trans_ + j - 1;
1913  }
1914  }
1915  if (i < ivkstrans_) {
1916  --ivkstrans_;
1917  }
1918  if (i < iligtrans_) {
1919  --iligtrans_;
1920  }
1921  --ntrans_;
1922  for (j = 0; j < ntrans_; ++j) {
1923  trans_[j].index_ = j;
1924  if (trans_[j].obj_) {
1925  trans_[j].obj_->u.this_pointer = trans_ + j;
1926  }
1927  }
1928  trans_[ntrans_].obj_ = NULL;
1929 }
1930 
1932  int i, j, ii, idx, ns;
1933 // printf("setstructure called for KSChan %p %s\n", this, name_.string());
1934 #if 0
1935 for (i=0; i < vec->size(); ++i) {
1936  printf("%d %g\n", i, vec->elem(i));
1937 }
1938 #endif
1939  usetable(false);
1940  int nstate_old = nstate_;
1941  KSState* state_old = state_;
1942  nstate_ = 0;
1943  state_ = 0;
1944  free1();
1945  j = 0;
1946  cond_model_ = (int) vec->elem(j++);
1947  setcond();
1948  ngate_ = (int) vec->elem(j++);
1949  nstate_ = (int) vec->elem(j++);
1950  nhhstate_ = (int) vec->elem(j++);
1953  ntrans_ = (int) vec->elem(j++);
1954  nligand_ = (int) vec->elem(j++);
1955  iligtrans_ = (int) vec->elem(j++);
1956  if (ngate_) {
1957  gc_ = new KSGateComplex[ngate_];
1958  gate_size_ = ngate_;
1959  }
1960  if (ntrans_) {
1961  trans_ = new KSTransition[ntrans_];
1962  trans_size_ = ntrans_;
1963  }
1964  if (nstate_) {
1965  state_ = new KSState[nstate_];
1966  state_size_ = nstate_;
1967  // preserve old names as much as possible
1968  for (i = 0; i < nstate_; ++i) {
1969  state_[i].index_ = i;
1970  state_[i].ks_ = this;
1971  if (i < nstate_old) {
1972  state_[i].name_ = state_old[i].name_;
1973  } else {
1974  char buf[20];
1975  sprintf(buf, "s%d", i);
1976  state_[i].name_ = buf;
1977  }
1978  }
1979  if (state_old) {
1980  for (i = 0; i < nstate_old; ++i) {
1981  unref(state_old[i].obj_);
1982  }
1983  delete[] state_old;
1984  }
1985  }
1986  for (i = 0; i < nstate_; ++i) {
1987  state_[i].f_ = 0.;
1988  }
1989  for (i = 0; i < ngate_; ++i) {
1990  gc_[i].ks_ = this;
1991  gc_[i].index_ = i;
1992  gc_[i].sindex_ = idx = (int) vec->elem(j++);
1993  gc_[i].nstate_ = ns = (int) vec->elem(j++);
1994  gc_[i].power_ = (int) vec->elem(j++);
1995  for (ii = 0; ii < ns; ++ii) {
1996  state_[ii + idx].f_ = vec->elem(j++);
1997  }
1998  }
1999  // assert that order is all vtrans and then all lig trans
2000  int pdoff = ppoff_ + (ion_sym_ ? 5 : 0);
2001  for (i = 0; i < ntrans_; ++i) {
2002  trans_[i].index_ = i;
2003  trans_[i].ks_ = this;
2004  trans_[i].src_ = (int) vec->elem(j++);
2005  trans_[i].target_ = (int) vec->elem(j++);
2006  trans_[i].type_ = (int) vec->elem(j++);
2007  trans_[i].ligand_index_ = (int) vec->elem(j++);
2008  if (i >= iligtrans_) {
2009  trans_[i].lig2pd(pdoff);
2010  }
2011  }
2012  if (nligand_) {
2013  ligands_ = new Symbol*[nligand_];
2014  for (i = 0; i < nligand_; ++i) {
2015  ligands_[i] = NULL;
2016  }
2017  }
2018  check_struct();
2019  if (mechsym_) {
2020  set_single(false, false);
2021  sname_install();
2022  state_consist();
2023  setupmat();
2024  }
2025 }
2026 
2028  Symbol* searchsym = is_point() ? mechsym_ : NULL;
2029  char unsuffix[100];
2030  if (is_point()) {
2031  unsuffix[0] = '\0';
2032  } else {
2033  sprintf(unsuffix, "_%s", mechsym_->name);
2034  }
2035  // there need to be symbols for nstate_ states
2036  int i;
2037  int nold = rlsym_->s_varn;
2038  int nnew = soffset_ + nstate_;
2039  Symbol** snew;
2040  Symbol** sold = rlsym_->u.ppsym;
2041  // the ones that exist and new symbols get a temporary name of "".
2042 
2043  snew = newppsym(nnew);
2044  for (i = 0; i < nnew; ++i) {
2045  if (i < nold) {
2046  snew[i] = sold[i];
2047  if (i >= soffset_) {
2048  snew[i]->name[0] = '\0'; // will be freed below
2049  }
2050  } else {
2051  // if not enough make more with a name of ""
2052  snew[i] = installsym("", RANGEVAR, searchsym);
2053  snew[i]->subtype = 3;
2054  snew[i]->u.rng.type = rlsym_->subtype;
2055  snew[i]->u.rng.index = i;
2056  }
2057  }
2058  // if too many then free the unused symbols and hope they really are unused
2059  for (i = nnew; i < nold; ++i) {
2060  freesym(sold[i], searchsym);
2061  }
2062  rlsym_->s_varn = nnew;
2063  free(rlsym_->u.ppsym);
2064  rlsym_->u.ppsym = snew;
2065 
2066  // fill the names checking for conflicts
2067  char buf[100], buf1[100];
2068  for (i = 0; i < nstate_; ++i) {
2069  sprintf(buf, "%s%s", state_[i].string(), unsuffix);
2070  int j = 0;
2071  buf1[0] = '\0';
2072  while (looksym(buf, searchsym)) {
2073  sprintf(buf1, "%s%d", state_[i].string(), j++);
2074  nrn_assert(snprintf(buf, 100, "%s%s", buf1, unsuffix) < 100);
2075  }
2076  free(snew[i + soffset_]->name);
2077  snew[i + soffset_]->name = strdup(buf);
2078  if (strlen(buf1) > 0) {
2079  state_[i].name_ = buf1;
2080  }
2081  }
2082 }
2083 
2084 // check at the top and built-in level, or, if top!= NULL check the template
2085 Symbol* KSChan::looksym(const char* name, Symbol* top) {
2086  if (top) {
2087  if (top->type != TEMPLATE) {
2088  printf("%s type=%d\n", top->name, top->type);
2089  abort();
2090  }
2091  assert(top->type == TEMPLATE);
2092  return hoc_table_lookup(name, top->u.ctemplate->symtable);
2093  }
2095  if (sp) {
2096  return sp;
2097  }
2099  return sp;
2100 }
2101 
2102 // install in the built-in list or the template list
2103 Symbol* KSChan::installsym(const char* name, int type, Symbol* top) {
2104  if (top) {
2105  assert(top->type == TEMPLATE);
2106  Symbol* s = hoc_install(name, type, 0.0, &top->u.ctemplate->symtable);
2107  s->cpublic = 1;
2108  return s;
2109  }
2110  return hoc_install(name, type, 0.0, &hoc_built_in_symlist);
2111 }
2112 
2114  Symbol** spp = (Symbol**) hoc_Emalloc(n * sizeof(Symbol*));
2115  hoc_malchk();
2116  return spp;
2117 }
2118 
2120  if (top) {
2121  assert(top->type == TEMPLATE);
2123  } else {
2125  }
2126  free(s->name);
2127  if (s->extra) {
2128  if (s->extra->parmlimits) {
2129  free(s->extra->parmlimits);
2130  }
2131  if (s->extra->units) {
2132  free(s->extra->units);
2133  }
2134  free(s->extra);
2135  }
2136  free(s);
2137 }
2138 
2140  int i, j, err;
2141  // printf("KSChan::setupmat nksstate=%d\n", nksstate_);
2142  if (mat_) {
2143  spDestroy(mat_);
2144  delete[] elms_;
2145  delete[] diag_;
2146  mat_ = NULL;
2147  }
2148  if (!nksstate_) {
2149  return;
2150  }
2151  mat_ = spCreate(nksstate_, 0, &err);
2152  if (err != spOKAY) {
2153  hoc_execerror("Couldn't create sparse matrix", 0);
2154  }
2155  spFactor(mat_); // will fail but creates an internal vector needed by
2156  // mulmat which might be called prior to initialization
2157  // when switching to cvode active.
2158  elms_ = new double*[4 * (ntrans_ - ivkstrans_)];
2159  diag_ = new double*[nksstate_];
2160  for (i = ivkstrans_, j = 0; i < ntrans_; ++i) {
2161  int s, t;
2162  s = trans_[i].src_ - nhhstate_ + 1;
2163  t = trans_[i].target_ - nhhstate_ + 1;
2164  elms_[j++] = spGetElement(mat_, s, s);
2165  elms_[j++] = spGetElement(mat_, s, t);
2166  elms_[j++] = spGetElement(mat_, t, t);
2167  elms_[j++] = spGetElement(mat_, t, s);
2168  }
2169  for (i = 0; i < nksstate_; ++i) {
2170  diag_[i] = spGetElement(mat_, i + 1, i + 1);
2171  }
2172 }
2173 
2174 void KSChan::fillmat(double v, Datum* pd) {
2175  int i, j;
2176  double a, b;
2177  spClear(mat_);
2178  for (i = ivkstrans_, j = 0; i < iligtrans_; ++i) {
2179  trans_[i].ab(v, a, b);
2180  // printf("trans %d v=%g a=%g b=%g\n", i, v, a, b);
2181  *elms_[j++] -= a;
2182  *elms_[j++] += b;
2183  *elms_[j++] -= b;
2184  *elms_[j++] += a;
2185  }
2186  for (i = iligtrans_; i < ntrans_; ++i) {
2187  a = trans_[i].alpha(pd);
2188  b = trans_[i].beta();
2189  *elms_[j++] -= a;
2190  *elms_[j++] += b;
2191  *elms_[j++] -= b;
2192  *elms_[j++] += a;
2193  }
2194  // printf("after fill\n");
2195  // spPrint(mat_, 0, 1, 0);
2196 }
2197 
2198 void KSChan::mat_dt(double dt, double* p) {
2199  // y' = m*y this part add the dt for the form ynew/dt - yold/dt =m*ynew
2200  // the matrix ends up as (m-1/dt)ynew = -1/dt*yold
2201  int i;
2202  double dt1 = -1. / dt;
2203  for (i = 0; i < nksstate_; ++i) {
2204  *(diag_[i]) += dt1;
2205  p[i] *= dt1;
2206  }
2207 }
2208 
2209 void KSChan::solvemat(double* s) {
2210  int e;
2211  e = spFactor(mat_);
2212  if (e != spOKAY) {
2213  switch (e) {
2214  case spZERO_DIAG:
2215  hoc_execerror("spFactor error:", "Zero Diagonal");
2216  case spNO_MEMORY:
2217  hoc_execerror("spFactor error:", "No Memory");
2218  case spSINGULAR:
2219  hoc_execerror("spFactor error:", "Singular");
2220  }
2221  }
2222  spSolve(mat_, s - 1, s - 1);
2223 }
2224 
2225 void KSChan::mulmat(double* s, double* ds) {
2226  spMultiply(mat_, ds - 1, s - 1);
2227 }
2228 
2230  // printf("KSChan::alloc nstate_=%d nligand_=%d\n", nstate_, nligand_);
2231  // printf("KSChan::alloc %s param=%p\n", name_.string(), prop->param);
2232  int j;
2233  prop->param_size = soffset_ + 2 * nstate_;
2234  if (is_point() && nrn_point_prop_) {
2235  assert(nrn_point_prop_->param_size == prop->param_size);
2236  prop->param = nrn_point_prop_->param;
2237  prop->dparam = nrn_point_prop_->dparam;
2238  } else {
2239  prop->param = nrn_prop_data_alloc(prop->type, prop->param_size, prop);
2240  prop->param[gmaxoffset_] = gmax_deflt_;
2241  if (is_point()) {
2242  prop->param[NSingleIndex] = 1.;
2243  }
2244  if (!ion_sym_) {
2245  prop->param[1 + gmaxoffset_] = erev_deflt_;
2246  }
2247  }
2248  int ppsize = ppoff_;
2249  if (ion_sym_) {
2250  ppsize += 5 + 2 * nligand_;
2251  } else {
2252  ppsize += 2 * nligand_;
2253  }
2254  if (!is_point() || nrn_point_prop_ == 0) {
2255  if (ppsize > 0) {
2256  prop->dparam = nrn_prop_datum_alloc(prop->type, ppsize, prop);
2257  if (is_point()) {
2258  prop->dparam[2]._pvoid = NULL;
2259  }
2260  } else {
2261  prop->dparam = 0;
2262  }
2263  }
2264  Datum* pp = prop->dparam;
2265  int poff = ppoff_;
2266  if (ion_sym_) {
2267  Prop* prop_ion = need_memb(ion_sym_);
2268  if (cond_model_ == 0) { // ohmic
2269  nrn_promote(prop_ion, 0, 1);
2270  } else if (cond_model_ == 1) { // nernst
2271  nrn_promote(prop_ion, 1, 0);
2272  } else { // ghk
2273  nrn_promote(prop_ion, 1, 0);
2274  }
2275  pp[ppoff_ + 0].pval = prop_ion->param + 0; // ena
2276  pp[ppoff_ + 1].pval = prop_ion->param + 3; // ina
2277  pp[ppoff_ + 2].pval = prop_ion->param + 4; // dinadv
2278  pp[ppoff_ + 3].pval = prop_ion->param + 1; // nai
2279  pp[ppoff_ + 4].pval = prop_ion->param + 2; // nao
2280  poff += 5;
2281  }
2282  for (j = 0; j < nligand_; ++j) {
2283  Prop* pion = need_memb(ligands_[j]);
2284  nrn_promote(pion, 1, 0);
2285  pp[poff + 2 * j].pval = pion->param + 2; // nao
2286  pp[poff + 2 * j + 1].pval = pion->param + 1; // nai
2287  }
2288  if (single_ && prop->dparam[2]._pvoid == NULL) {
2290  }
2291 }
2292 
2294  Prop *p, *pion;
2295  int type = s->subtype;
2296  for (p = nd->prop; p; p = p->next) {
2297  if (p->type == type) {
2298  break;
2299  }
2300  }
2301  pion = p;
2302  // printf("KSChan::needion %s\n", s->name);
2303  // printf("before ion rearrangement\n");
2304  // for (p=nd->prop; p; p=p->next) {printf("\t%s\n", memb_func[p->type].sym->name);}
2305  if (!pion) {
2306  pion = prop_alloc(&nd->prop, type, nd);
2307  } else { // if after then move to beginning
2308  for (p = pm; p; p = p->next) {
2309  if (p->next == pion) {
2310  p->next = p->next->next;
2311  pion->next = nd->prop;
2312  nd->prop = pion;
2313  break;
2314  }
2315  }
2316  }
2317  // printf("after ion rearrangement\n");
2318  // for (p=nd->prop; p; p=p->next) {printf("\t%s\n", memb_func[p->type].sym->name);}
2319  return pion;
2320 }
2321 
2323  // printf("KSChan::ion_consist\n");
2324  int i, j;
2325  Node* nd;
2326  hoc_Item* qsec;
2327  int mtype = rlsym_->subtype;
2328  int poff = ppoff_;
2329  if (ion_sym_) {
2330  poff += 5;
2331  }
2332  for (i = iligtrans_; i < ntrans_; ++i) {
2333  trans_[i].lig2pd(poff);
2334  }
2335  int ppsize = poff + 2 * nligand_;
2336  // ForAllSections(sec)
2337  ITERATE(qsec, section_list) {
2338  Section* sec = hocSEC(qsec);
2339  for (i = 0; i < sec->nnode; ++i) {
2340  nd = sec->pnode[i];
2341  Prop *p, *pion;
2342  for (p = nd->prop; p; p = p->next) {
2343  if (p->type == mtype) {
2344  break;
2345  }
2346  }
2347  if (!p) {
2348  continue;
2349  }
2350  p->dparam = (Datum*) erealloc(p->dparam, ppsize * sizeof(Datum));
2351  // printf("KSChan::ion_consist %s node %d mtype=%d ion_type=%d\n",
2352  // secname(sec), i, mtype, ion_sym_->subtype);
2353  if (ion_sym_) {
2354  pion = needion(ion_sym_, nd, p);
2355  if (cond_model_ == 0) { // ohmic
2356  nrn_promote(pion, 0, 1);
2357  } else if (cond_model_ == 1) { // nernst
2358  nrn_promote(pion, 1, 0);
2359  } else { // ghk
2360  nrn_promote(pion, 1, 0);
2361  }
2362  Datum* pp = p->dparam;
2363  pp[ppoff_ + 0].pval = pion->param + 0; // ena
2364  pp[ppoff_ + 1].pval = pion->param + 3; // ina
2365  pp[ppoff_ + 2].pval = pion->param + 4; // dinadv
2366  pp[ppoff_ + 3].pval = pion->param + 1; // nai
2367  pp[ppoff_ + 4].pval = pion->param + 2; // nao
2368  }
2369  for (j = 0; j < nligand_; ++j) {
2370  ligand_consist(j, poff, p, nd);
2371  }
2372  }
2373  }
2374 }
2375 
2376 void KSChan::ligand_consist(int j, int poff, Prop* p, Node* nd) {
2377  Prop* pion;
2378  pion = needion(ligands_[j], nd, p);
2379  nrn_promote(pion, 1, 0);
2380  p->dparam[poff + 2 * j].pval = pion->param + 2; // nao
2381  p->dparam[poff + 2 * j + 1].pval = pion->param + 1; // nai
2382 }
2383 
2384 void KSChan::state_consist(int shift) { // shift when Nsingle winks in and out of existence
2385  // printf("KSChan::state_consist\n");
2386  int i, j, ns;
2387  Node* nd;
2388  hoc_Item* qsec;
2389  int mtype = rlsym_->subtype;
2390  ns = soffset_ + 2 * nstate_;
2391  // ForAllSections(sec)
2392  ITERATE(qsec, section_list) {
2393  Section* sec = hocSEC(qsec);
2394  for (i = 0; i < sec->nnode; ++i) {
2395  nd = sec->pnode[i];
2396  Prop* p;
2397  for (p = nd->prop; p; p = p->next) {
2398  if (p->type == mtype) {
2399  if (p->param_size != ns) {
2400  v_structure_change = 1;
2401  double* oldp = p->param;
2402  p->param = (double*) erealloc(oldp, ns * sizeof(double));
2403  if (oldp != p->param || shift != 0) {
2404  // printf("KSChan::state_consist realloc changed location\n");
2405  notify_freed_val_array(oldp, p->param_size);
2406  }
2407  p->param_size = ns;
2408  if (shift == 1) {
2409  for (j = ns - 1; j > 0; --j) {
2410  p->param[j] = p->param[j - 1];
2411  }
2412  p->param[0] = 1;
2413  } else if (shift == -1) {
2414  for (j = 1; j < ns; ++j) {
2415  p->param[j - 1] = p->param[j];
2416  }
2417  }
2418  }
2419  break;
2420  }
2421  }
2422  }
2423  }
2424 }
2425 
2427  hoc_List* list = mechsym_->u.ctemplate->olist;
2428  hoc_Item* q;
2429  ITERATE(q, list) {
2430  Point_process* pnt = (Point_process*) (OBJ(q)->u.this_pointer);
2431  if (pnt && pnt->prop && pnt->prop->dparam[2]._pvoid) {
2432  KSSingleNodeData* snd = (KSSingleNodeData*) pnt->prop->dparam[2]._pvoid;
2433  delete snd;
2434  pnt->prop->dparam[2]._pvoid = NULL;
2435  }
2436  }
2437 }
2438 
2440  hoc_List* list = mechsym_->u.ctemplate->olist;
2441  hoc_Item* q;
2442  ITERATE(q, list) {
2443  Point_process* pnt = (Point_process*) (OBJ(q)->u.this_pointer);
2444  if (pnt && pnt->prop) {
2445  single_->alloc(pnt->prop, soffset_);
2446  }
2447  }
2448 }
2449 
2450 void KSChan::init(int n, Node** nd, double** pp, Datum** ppd, NrnThread* nt) {
2451  int i, j;
2452  if (nstate_)
2453  for (i = 0; i < n; ++i) {
2454  double v = NODEV(nd[i]);
2455  double* s = pp[i] + soffset_;
2456  for (j = 0; j < nstate_; ++j) {
2457  s[j] = 0;
2458  }
2459  for (j = 0; j < ngate_; ++j) {
2460  s[gc_[j].sindex_] = 1;
2461  }
2462  for (j = 0; j < nhhstate_; ++j) {
2463  s[j] = trans_[j].inf(v);
2464  }
2465  if (nksstate_) {
2466  s += nhhstate_;
2467  fillmat(v, ppd[i]);
2468  mat_dt(1e9, s);
2469  solvemat(s);
2470  }
2471  if (is_single()) {
2472  KSSingleNodeData* snd = (KSSingleNodeData*) ppd[i][2]._pvoid;
2473  snd->nsingle_ = int(pp[i][NSingleIndex] + .5);
2474  pp[i][NSingleIndex] = double(snd->nsingle_);
2475  if (snd->nsingle_ > 0) {
2476  // replace population fraction with integers.
2477  single_->init(v, s, snd, nt);
2478  }
2479  }
2480  // printf("KSChan::init\n");
2481  // s = pp[i] + soffset_;
2482  // for (j=0; j < nstate_; ++j) {
2483  // printf("%d %g\n", j, s[j]);
2484  //}
2485  }
2486 }
2487 
2488 void KSChan::state(int n, Node** nd, double** pp, Datum** ppd, NrnThread* nt) {
2489  int i, j;
2490  double* s;
2491  if (nstate_) {
2492  for (i = 0; i < n; ++i) {
2493  if (is_single() && pp[i][NSingleIndex] > .999) {
2494  single_->state(nd[i], pp[i], ppd[i], nt);
2495  continue;
2496  }
2497  double v = NODEV(nd[i]);
2498  s = pp[i] + soffset_;
2499  if (usetable_) {
2500  double inf, tau;
2501  int k;
2502  double x, y;
2503  x = (v - vmin_) * dvinv_;
2504  y = floor(x);
2505  k = int(y);
2506  x -= y;
2507  if (k < 0) {
2508  for (j = 0; j < nhhstate_; ++j) {
2509  trans_[j].inftau_hh_table(0, inf, tau);
2510  s[j] += (inf - s[j]) * tau;
2511  }
2512  } else if (k >= hh_tab_size_) {
2513  for (j = 0; j < nhhstate_; ++j) {
2514  trans_[j].inftau_hh_table(hh_tab_size_ - 1, inf, tau);
2515  s[j] += (inf - s[j]) * tau;
2516  }
2517  } else {
2518  for (j = 0; j < nhhstate_; ++j) {
2519  trans_[j].inftau_hh_table(k, x, inf, tau);
2520  s[j] += (inf - s[j]) * tau;
2521  }
2522  }
2523  } else {
2524  for (j = 0; j < nhhstate_; ++j) {
2525  double inf, tau;
2526  trans_[j].inftau(v, inf, tau);
2527  tau = 1. - KSChanFunction::Exp(-nt->_dt / tau);
2528  s[j] += (inf - s[j]) * tau;
2529  }
2530  }
2531  if (nksstate_) {
2532  s += nhhstate_;
2533  fillmat(v, ppd[i]);
2534  mat_dt(nt->_dt, s);
2535  solvemat(s);
2536  }
2537  }
2538  }
2539 }
2540 
2541 #if CACHEVEC
2542 void KSChan::state(int n, int* ni, Node** nd, double** pp, Datum** ppd, NrnThread* _nt) {
2543  int i, j;
2544  double* s;
2545  if (nstate_) {
2546  for (i = 0; i < n; ++i) {
2547  if (is_single() && pp[i][NSingleIndex] > .999) {
2548  single_->state(nd[i], pp[i], ppd[i], _nt);
2549  continue;
2550  }
2551  double v = VEC_V(ni[i]);
2552  s = pp[i] + soffset_;
2553  if (usetable_) {
2554  double inf, tau;
2555  int k;
2556  double x, y;
2557  x = (v - vmin_) * dvinv_;
2558  y = floor(x);
2559  k = int(y);
2560  x -= y;
2561  if (k < 0) {
2562  for (j = 0; j < nhhstate_; ++j) {
2563  trans_[j].inftau_hh_table(0, inf, tau);
2564  s[j] += (inf - s[j]) * tau;
2565  }
2566  } else if (k >= hh_tab_size_) {
2567  for (j = 0; j < nhhstate_; ++j) {
2568  trans_[j].inftau_hh_table(hh_tab_size_ - 1, inf, tau);
2569  s[j] += (inf - s[j]) * tau;
2570  }
2571  } else {
2572  for (j = 0; j < nhhstate_; ++j) {
2573  trans_[j].inftau_hh_table(k, x, inf, tau);
2574  s[j] += (inf - s[j]) * tau;
2575  }
2576  }
2577  } else {
2578  for (j = 0; j < nhhstate_; ++j) {
2579  double inf, tau;
2580  trans_[j].inftau(v, inf, tau);
2581  tau = 1. - KSChanFunction::Exp(-_nt->_dt / tau);
2582  s[j] += (inf - s[j]) * tau;
2583  }
2584  }
2585  if (nksstate_) {
2586  s += nhhstate_;
2587  fillmat(v, ppd[i]);
2588  mat_dt(_nt->_dt, s);
2589  solvemat(s);
2590  }
2591  }
2592  }
2593 }
2594 #endif /* CACHEVEC */
2595 
2596 void KSChan::cur(int n, Node** nd, double** pp, Datum** ppd) {
2597  int i;
2598  for (i = 0; i < n; ++i) {
2599  double g, ic;
2600  g = conductance(pp[i][gmaxoffset_], pp[i] + soffset_);
2601  ic = iv_relation_->cur(g, pp[i] + gmaxoffset_, ppd[i], NODEV(nd[i]));
2602  NODERHS(nd[i]) -= ic;
2603  }
2604 }
2605 
2606 #if CACHEVEC
2607 void KSChan::cur(int n, int* nodeindices, double** pp, Datum** ppd, NrnThread* _nt) {
2608  int i;
2609  for (i = 0; i < n; ++i) {
2610  double g, ic;
2611  int ni = nodeindices[i];
2612  g = conductance(pp[i][gmaxoffset_], pp[i] + soffset_);
2613  ic = iv_relation_->cur(g, pp[i] + gmaxoffset_, ppd[i], VEC_V(ni));
2614  VEC_RHS(ni) -= ic;
2615  }
2616 }
2617 #endif /* CACHEVEC */
2618 
2619 void KSChan::jacob(int n, Node** nd, double** pp, Datum** ppd) {
2620  int i;
2621  for (i = 0; i < n; ++i) {
2622  NODED(nd[i]) += iv_relation_->jacob(pp[i] + gmaxoffset_, ppd[i], NODEV(nd[i]));
2623  }
2624 }
2625 
2626 #if CACHEVEC
2627 void KSChan::jacob(int n, int* nodeindices, double** pp, Datum** ppd, NrnThread* _nt) {
2628  int i;
2629  for (i = 0; i < n; ++i) {
2630  int ni = nodeindices[i];
2631  VEC_D(ni) += iv_relation_->jacob(pp[i] + gmaxoffset_, ppd[i], VEC_V(ni));
2632  }
2633 }
2634 #endif /* CACHEVEC */
2635 
2636 double KSIv::cur(double g, double* p, Datum* pd, double v) {
2637  double i, ena;
2638  ena = *pd[0].pval;
2639  p[1] = g;
2640  i = g * (v - ena);
2641  p[2] = i;
2642  *pd[1].pval += i; // iion
2643  return i;
2644 }
2645 
2646 double KSIv::jacob(double* p, Datum* pd, double) {
2647  *pd[2].pval += p[1]; // diion/dv
2648  return p[1];
2649 }
2650 
2651 double KSIvghk::cur(double g, double* p, Datum* pd, double v) {
2652  double i, ci, co;
2653  ci = *pd[3].pval;
2654  co = *pd[4].pval;
2655  p[1] = g;
2656  i = g * nrn_ghk(v, ci, co, z);
2657  p[2] = i;
2658  *pd[1].pval += i;
2659  return i;
2660 }
2661 
2662 double KSIvghk::jacob(double* p, Datum* pd, double v) {
2663  double i1, ci, co, didv;
2664  ci = *pd[3].pval;
2665  co = *pd[4].pval;
2666  i1 = p[1] * nrn_ghk(v + .001, ci, co, z); // g is p[1]
2667  didv = (i1 - p[2]) * 1000.;
2668  *pd[2].pval += didv;
2669  return didv;
2670 }
2671 
2672 double KSIvNonSpec::cur(double g, double* p, Datum* pd, double v) {
2673  double i;
2674  p[2] = g; // gmax, e, g
2675  i = g * (v - p[1]);
2676  p[3] = i;
2677  return i;
2678 }
2679 
2680 double KSIvNonSpec::jacob(double* p, Datum* pd, double) {
2681  return p[2];
2682 }
2683 
2684 double KSPPIv::cur(double g, double* p, Datum* pd, double v) {
2685  double afac = 1.e2 / (*pd[0].pval);
2686  pd += ppoff_;
2687  double i, ena;
2688  ena = *pd[0].pval;
2689  p[1] = g;
2690  i = g * (v - ena);
2691  p[2] = i;
2692  i *= afac;
2693  *pd[1].pval += i; // iion
2694  return i;
2695 }
2696 
2697 double KSPPIv::jacob(double* p, Datum* pd, double) {
2698  double afac = 1.e2 / (*pd[0].pval);
2699  pd += ppoff_;
2700  double g = p[1] * afac;
2701  *pd[2].pval += g; // diion/dv
2702  return g;
2703 }
2704 
2705 double KSPPIvghk::cur(double g, double* p, Datum* pd, double v) {
2706  double afac = 1.e2 / (*pd[0].pval);
2707  pd += ppoff_;
2708  double i, ci, co;
2709  ci = *pd[3].pval;
2710  co = *pd[4].pval;
2711  p[1] = g;
2712  i = g * nrn_ghk(v, ci, co, z) * 1e6;
2713  p[2] = i;
2714  i *= afac;
2715  *pd[1].pval += i;
2716  return i;
2717 }
2718 
2719 double KSPPIvghk::jacob(double* p, Datum* pd, double v) {
2720  double afac = 1.e2 / (*pd[0].pval);
2721  pd += ppoff_;
2722  double i1, ci, co, didv;
2723  ci = *pd[3].pval;
2724  co = *pd[4].pval;
2725  i1 = p[1] * nrn_ghk(v + .001, ci, co, z) * 1e6; // g is p[1]
2726  didv = (i1 - p[2]) * 1000.;
2727  didv *= afac;
2728  *pd[2].pval += didv;
2729  return didv;
2730 }
2731 
2732 double KSPPIvNonSpec::cur(double g, double* p, Datum* pd, double v) {
2733  double afac = 1.e2 / (*pd[0].pval);
2734  double i;
2735  p[2] = g; // gmax, e, g
2736  i = g * (v - p[1]);
2737  p[3] = i;
2738  return i * afac;
2739 }
2740 
2741 double KSPPIvNonSpec::jacob(double* p, Datum* pd, double) {
2742  double afac = 1.e2 / (*pd[0].pval);
2743  return p[2] * afac;
2744 }
2745 
2746 double KSChan::conductance(double gmax, double* s) {
2747  double g = 1.;
2748  int i;
2749  for (i = 0; i < ngate_; ++i) {
2750  g *= gc_[i].conductance(s, state_);
2751  }
2752  return gmax * g;
2753 }
2754 
2756  obj_ = NULL;
2757  f0 = NULL;
2758  f1 = NULL;
2759  size1_ = 0;
2760  inftab_ = NULL;
2761  tautab_ = NULL;
2762  stoichiom_ = 1;
2763  // f0 = new KSChanFunction();
2764  // f1 = new KSChanFunction();
2765 }
2766 
2768  if (f0) {
2769  delete f0;
2770  }
2771  if (f1) {
2772  delete f1;
2773  }
2774  hh_table_make(0., 0);
2775 }
2776 
2777 void KSTransition::setf(int i, int type, Vect* vec, double vmin, double vmax) {
2778  ks_->usetable(false);
2779  if (i == 0) {
2780  if (f0) {
2781  delete f0;
2782  }
2783  f0 = KSChanFunction::new_function(type, vec, vmin, vmax);
2784  } else {
2785  if (f1) {
2786  delete f1;
2787  }
2788  f1 = KSChanFunction::new_function(type, vec, vmin, vmax);
2789  }
2790 }
2791 
2792 void KSTransition::lig2pd(int poff) {
2793  ks_->usetable(false);
2794  if (type_ == 2) {
2795  pd_index_ = poff + 2 * ligand_index_;
2796  } else if (type_ == 3) {
2797  pd_index_ = poff + 2 * ligand_index_ + 1;
2798  } else {
2799  assert(0);
2800  }
2801 }
2802 
2803 void KSTransition::ab(double v, double& a, double& b) {
2804  a = f0->f(v);
2805  if (f0->type() == 5 && f1->type() == 6) {
2806  b = ((KSChanBGinf*) f0)->tau;
2807  } else {
2808  b = f1->f(v);
2809  }
2810  if (type_ == 1) {
2811  double t = a;
2812  a = t / b;
2813  b = (1. - t) / b;
2814  }
2815 }
2816 
2817 void KSTransition::ab(Vect* v, Vect* a, Vect* b) {
2818  int i, n = v->size();
2819  a->resize(n);
2820  b->resize(n);
2821  if (f0->type() == 5 && f1->type() == 6) {
2822  for (i = 0; i < n; ++i) {
2823  a->elem(i) = f0->f(v->elem(i));
2824  b->elem(i) = ((KSChanBGinf*) f0)->tau;
2825  }
2826  } else {
2827  for (i = 0; i < n; ++i) {
2828  a->elem(i) = f0->f(v->elem(i));
2829  b->elem(i) = f1->f(v->elem(i));
2830  }
2831  }
2832  if (type_ == 1) {
2833  for (i = 0; i < n; ++i) {
2834  double t = a->elem(i);
2835  a->elem(i) = t / b->elem(i);
2836  b->elem(i) = (1. - t) / b->elem(i);
2837  }
2838  }
2839 }
2840 
2841 void KSTransition::inftau(double v, double& a, double& b) {
2842  a = f0->f(v);
2843  if (f0->type() == 5 && f1->type() == 6) {
2844  b = ((KSChanBGinf*) f0)->tau;
2845  } else {
2846  b = f1->f(v);
2847  }
2848  if (type_ != 1) {
2849  double t = 1. / (a + b);
2850  a = a * t;
2851  b = t;
2852  }
2853 }
2854 
2856  int i, n = v->size();
2857  a->resize(n);
2858  b->resize(n);
2859  if (f0->type() == 5 && f1->type() == 6) {
2860  for (i = 0; i < n; ++i) {
2861  a->elem(i) = f0->f(v->elem(i));
2862  b->elem(i) = ((KSChanBGinf*) f0)->tau;
2863  }
2864  } else {
2865  for (i = 0; i < n; ++i) {
2866  a->elem(i) = f0->f(v->elem(i));
2867  b->elem(i) = f1->f(v->elem(i));
2868  }
2869  }
2870  if (type_ != 1) {
2871  for (i = 0; i < n; ++i) {
2872  double t = 1. / (a->elem(i) + b->elem(i));
2873  a->elem(i) = a->elem(i) * t;
2874  b->elem(i) = t;
2875  }
2876  }
2877 }
2878 
2880  double x = *(pd[pd_index_].pval);
2881  switch (stoichiom_) {
2882  case 1:
2883  return x * f0->c(0);
2884  case 2:
2885  return x * x * f0->c(0);
2886  case 3:
2887  return x * x * x * f0->c(0);
2888  case 4: {
2889  x *= x;
2890  return x * x * f0->c(0);
2891  }
2892  default:
2893  return f0->c(0) * pow(x, double(stoichiom_));
2894  }
2895 }
2896 
2898  return f1->c(0);
2899 }
2900 
2902  power_ = 0;
2903  obj_ = NULL;
2904 }
2905 
2907 double KSGateComplex::conductance(double* s, KSState* st) {
2908  double g = 0.;
2909  int i;
2910  s += sindex_;
2911  st += sindex_;
2912  for (i = 0; i < nstate_; ++i) {
2913  g += s[i] * st[i].f_;
2914  }
2915 #if 1
2916  switch (power_) { // 14.42
2917  case 1:
2918  return g;
2919  case 2:
2920  return g * g;
2921  case 3:
2922  return g * g * g;
2923  case 4:
2924  g = g * g;
2925  return g * g;
2926  }
2927 #endif
2928  return pow(g, (double) power_); // 18.74
2929 }
2930 
2932  obj_ = NULL;
2933  f_ = 0.;
2934 }
2935 
2937 
2939  return nstate_;
2940 }
2941 
2942 void KSChan::map(int ieq, double** pv, double** pvdot, double* p, Datum* pd, double* atol) {
2943  int i;
2944  double* p1 = p + soffset_;
2945  double* p2 = p1 + nstate_;
2946  for (i = 0; i < nstate_; ++i) {
2947  pv[i] = p1 + i;
2948  pvdot[i] = p2 + i;
2949  }
2950 }
2951 
2952 void KSChan::spec(int n, Node** nd, double** p, Datum** ppd) {
2953  int i, j;
2954  if (nstate_)
2955  for (i = 0; i < n; ++i) {
2956  // for (j=0; j < nstate_; ++j) {
2957  // printf("KSChan spec before j=%d s=%g ds=%g\n", j, p[i][soffset_+j],
2958  // p[i][soffset_+nstate_+j]);
2959  //}
2960  double v = NODEV(nd[i]);
2961  double* p1 = p[i] + soffset_;
2962  double* p2 = p1 + nstate_;
2963  if (is_single() && p[i][NSingleIndex] > .999) {
2964  for (j = 0; j < nstate_; ++j) {
2965  p2[j] = 0.;
2966  }
2967  continue;
2968  }
2969  for (j = 0; j < nhhstate_; ++j) {
2970  double inf, tau;
2971  trans_[j].inftau(v, inf, tau);
2972  p2[j] = (inf - p1[j]) / tau;
2973  }
2974  if (nksstate_) {
2975  fillmat(v, ppd[i]);
2976  mulmat(p1 + nhhstate_, p2 + nhhstate_);
2977  }
2978  // for (j=0; j < nstate_; ++j) {
2979  // printf("KSChan spec after j=%d s=%g ds=%g\n", j, p[i][soffset_+j],
2980  // p[i][soffset_+nstate_+j]);
2981  //}
2982  }
2983 }
2984 
2985 void KSChan::matsol(int n, Node** nd, double** p, Datum** ppd, NrnThread* nt) {
2986  int i, j;
2987  double* p2;
2988  if (nstate_)
2989  for (i = 0; i < n; ++i) {
2990  if (is_single() && p[i][NSingleIndex] > .999) {
2991  continue;
2992  }
2993  double v = NODEV(nd[i]);
2994  p2 = p[i] + soffset_ + nstate_;
2995  for (j = 0; j < nhhstate_; ++j) {
2996  double tau;
2997  tau = trans_[j].tau(v);
2998  p2[j] /= (1 + nt->_dt / tau);
2999  }
3000  if (nksstate_) {
3001  p2 += nhhstate_;
3002  fillmat(v, ppd[i]);
3003  mat_dt(nt->_dt, p2);
3004  solvemat(p2);
3005  }
3006  }
3007 }
3008 
3009 // from Cvode::do_nonode
3010 void KSChan::cv_sc_update(int n, Node** nd, double** pp, Datum** ppd, NrnThread* nt) {
3011  int i;
3012  if (nstate_) {
3013  for (i = 0; i < n; ++i) {
3014  if (pp[i][NSingleIndex] > .999) {
3015  single_->cv_update(nd[i], pp[i], ppd[i], nt);
3016  }
3017  }
3018  }
3019 }
3020 
3022  gp_ = NULL;
3023 }
3024 
3026  if (gp_) {
3027  hoc_obj_unref(gp_->obj_);
3028  }
3029 }
3030 
3031 KSChanFunction* KSChanFunction::new_function(int type, Vect* vec, double vmin, double vmax) {
3032  KSChanFunction* f;
3033  switch (type) {
3034  case 1:
3035  f = new KSChanConst();
3036  break;
3037  case 2:
3038  f = new KSChanExp();
3039  break;
3040  case 3:
3041  f = new KSChanLinoid();
3042  break;
3043  case 4:
3044  f = new KSChanSigmoid();
3045  break;
3046  case 5:
3047  f = new KSChanBGinf();
3048  break;
3049  case 6:
3050  f = new KSChanBGtau();
3051  break;
3052  case 7:
3053  f = new KSChanTable(vec, vmin, vmax);
3054  break;
3055  default:
3056  f = new KSChanFunction();
3057  break;
3058  }
3059  f->gp_ = vec;
3060  hoc_obj_ref(f->gp_->obj_);
3061  return f;
3062 }
3063 
3064 KSChanTable::KSChanTable(Vect* vec, double vmin, double vmax) {
3065  vmin_ = vmin;
3066  vmax_ = vmax;
3067  assert(vmax > vmin);
3068  assert(vec->size() > 1);
3069  dvinv_ = (vec->size() - 1) / (vmax - vmin);
3070 }
3071 
3072 double KSChanTable::f(double v) {
3073  double x;
3074  if (v <= vmin_) {
3075  x = c(0);
3076  } else if (v >= vmax_) {
3077  x = c(gp_->size() - 1);
3078  } else {
3079  x = (v - vmin_) * dvinv_;
3080  int i = (int) x;
3081  x -= floor(x);
3082  x = c(i) + (c(i + 1) - c(i)) * x;
3083  }
3084  return x;
3085 }
3086 
3087 void KSTransition::hh_table_make(double dt, int size, double vmin, double vmax) {
3088  int i;
3089  double dv, tau;
3090  if (size < 1 || vmin >= vmax || size - size1_ != 1) {
3091  if (size1_) {
3092  delete[] inftab_;
3093  delete[] tautab_;
3094  size1_ = 0;
3095  inftab_ = NULL;
3096  tautab_ = NULL;
3097  }
3098  if (size < 1) {
3099  return;
3100  }
3101  }
3102  if (inftab_ == NULL) {
3103  inftab_ = new double[size];
3104  tautab_ = new double[size];
3105  }
3106  size1_ = size - 1;
3107  dv = (vmax - vmin) / size1_;
3108  for (i = 0; i < size; ++i) {
3109  inftau(vmin + i * dv, inftab_[i], tau);
3110  tautab_[i] = 1. - KSChanFunction::Exp(-dt / tau);
3111  }
3112 }
3113 
3114 void KSChan::usetable(bool use, int size, double vmin, double vmax) {
3115  if (vmin >= vmax) {
3116  vmin_ = -100;
3117  vmax_ = 50;
3118  } else {
3119  vmin_ = vmin;
3120  vmax_ = vmax;
3121  }
3122  if (size < 2) {
3123  hh_tab_size_ = 200;
3124  } else {
3125  hh_tab_size_ = size;
3126  }
3127  dvinv_ = (hh_tab_size_ - 1) / (vmax_ - vmin_);
3128  usetable(use);
3129 }
3130 
3131 static int ksusing(int type) {
3132  for (int i = 0; i < nrn_nthread; ++i) {
3133  for (NrnThreadMembList* tml = nrn_threads[i].tml; tml; tml = tml->next) {
3134  if (tml->index == type) {
3135  return 1;
3136  }
3137  }
3138  }
3139  return 0;
3140 }
3141 
3142 void KSChan::usetable(bool use) {
3143  if (nhhstate_ == 0) {
3144  use = false;
3145  }
3146  usetable_ = use;
3147  if (mechtype_ == -1) {
3148  return;
3149  }
3150  if (usetable_) {
3151  dtsav_ = -1.0;
3153  if (memb_func[mechtype_].thread_table_check_ != check_table_thread_) {
3155  if (ksusing(mechtype_)) {
3157  }
3158  }
3159  } else {
3160  if (memb_func[mechtype_].thread_table_check_) {
3162  if (ksusing(mechtype_)) {
3164  }
3165  }
3166  }
3167 }
3168 
3169 int KSChan::usetable(double* vmin, double* vmax) {
3170  *vmin = vmin_;
3171  *vmax = vmax_;
3172  return hh_tab_size_;
3173 }
3174 
3176  int i;
3177  if (usetable_ && nt->_dt != dtsav_) {
3178  for (i = 0; i < nhhstate_; ++i) {
3180  }
3181  dtsav_ = nt->_dt;
3182  }
3183 }
int nrn_get_mechtype(const char *mechname)
Definition: cabcode.cpp:2000
Memb_func * memb_func
Definition: init.cpp:123
short type
Definition: cabvars.h:9
virtual int type()
Definition: kschan.h:24
static double Exp(double x)
Definition: kschan.h:41
Vect * gp_
Definition: kschan.h:37
static KSChanFunction * new_function(int type, Vect *, double, double)
Definition: kschan.cpp:3031
double c(int i)
Definition: kschan.h:38
virtual ~KSChanFunction()
Definition: kschan.cpp:3025
virtual double f(double v)
Definition: kschan.h:27
Definition: kschan.h:291
int trans_index(const char *src, const char *target)
Definition: kschan.cpp:1057
int mechtype_
Definition: kschan.h:397
void add_channel(const char **)
Definition: kschan.cpp:826
Object * obj_
Definition: kschan.h:422
char * mat_
Definition: kschan.h:429
void ligand_consist(int, int, Prop *, Node *)
Definition: kschan.cpp:2376
void alloc_schan_node_data()
Definition: kschan.cpp:2439
void mulmat(double *, double *)
Definition: kschan.cpp:2225
void state_remove(int i)
Definition: kschan.cpp:1793
int soffset_
Definition: kschan.h:434
virtual void alloc(Prop *)
Definition: kschan.cpp:2229
void set_single(bool, bool update=true)
Definition: kschan.cpp:1024
virtual void state(int, Node **, double **, Datum **, NrnThread *)
Definition: kschan.cpp:2488
void check_struct()
Definition: kschan.cpp:1709
Symbol * ion_sym_
Definition: kschan.h:419
double gmax_deflt_
Definition: kschan.h:402
int ntrans_
Definition: kschan.h:407
void setupmat()
Definition: kschan.cpp:2139
void fillmat(double v, Datum *pd)
Definition: kschan.cpp:2174
double conductance(double gmax, double *state)
Definition: kschan.cpp:2746
int nligand_
Definition: kschan.h:420
KSState * state_
Definition: kschan.h:416
int gate_size_
Definition: kschan.h:391
void usetable(bool, int size, double vmin, double vmax)
Definition: kschan.cpp:3114
int trans_size_
Definition: kschan.h:392
void delete_schan_node_data()
Definition: kschan.cpp:2426
int nstate_
Definition: kschan.h:413
int hh_tab_size_
Definition: kschan.h:441
double dvinv_
Definition: kschan.h:440
KSState * add_hhstate(const char *)
Definition: kschan.cpp:1557
virtual ~KSChan()
Definition: kschan.cpp:898
CopyString name_
Definition: kschan.h:400
KSTransition * trans_
Definition: kschan.h:418
KSGateComplex * gate_insert(int ig, int is, int power)
Definition: kschan.cpp:1818
void gate_remove(int i)
Definition: kschan.cpp:1849
KSState * state_insert(int i, const char *name, double frac)
Definition: kschan.cpp:1758
bool usetable()
Definition: kschan.h:357
void setname(const char *)
Definition: kschan.cpp:958
int ngate_
Definition: kschan.h:406
virtual void jacob(int, Node **, double **, Datum **)
Definition: kschan.cpp:2619
virtual void spec(int, Node **, double **, Datum **)
Definition: kschan.cpp:2952
int pointtype_
Definition: kschan.h:396
double erev_deflt_
Definition: kschan.h:403
int ppoff_
Definition: kschan.h:437
virtual void map(int, double **, double **, double *, Datum *, double *)
Definition: kschan.cpp:2942
void check_table_thread(NrnThread *)
Definition: kschan.cpp:3175
KSChan(Object *, bool is_point=false)
Definition: kschan.cpp:860
void update_prop()
Definition: kschan.cpp:1088
void build()
Definition: kschan.cpp:900
bool is_point()
Definition: kschan.h:321
void setstructure(Vect *)
Definition: kschan.cpp:1931
bool is_point_
Definition: kschan.h:393
double dtsav_
Definition: kschan.h:440
KSSingle * single_
Definition: kschan.h:423
int state_size_
Definition: kschan.h:390
void state_consist(int shift=0)
Definition: kschan.cpp:2384
double vmin_
Definition: kschan.h:440
Prop * needion(Symbol *, Node *, Prop *)
Definition: kschan.cpp:2293
void remove_state(int)
Definition: kschan.cpp:1621
double ** elms_
Definition: kschan.h:430
void power(KSGateComplex *, int)
Definition: kschan.cpp:1017
double vmax_
Definition: kschan.h:440
Symbol * mechsym_
Definition: kschan.h:427
void ion_consist()
Definition: kschan.cpp:2322
void trans_remove(int i)
Definition: kschan.cpp:1905
void sname_install()
Definition: kschan.cpp:2027
void destroy_pnt(Point_process *)
Definition: kschan.cpp:149
void setcond()
Definition: kschan.cpp:1311
int dsize_
Definition: kschan.h:432
KSTransition * add_transition(int src, int target, const char *ligand)
Definition: kschan.cpp:1684
void remove_transition(int)
Definition: kschan.cpp:1697
void setion(const char *)
Definition: kschan.cpp:1169
virtual void cv_sc_update(int, Node **, double **, Datum **, NrnThread *)
Definition: kschan.cpp:3010
KSTransition * trans_insert(int i, int src, int target)
Definition: kschan.cpp:1869
Symbol * installsym(const char *, int, Symbol *tmplt=NULL)
Definition: kschan.cpp:2103
double ** diag_
Definition: kschan.h:431
virtual void cur(int, Node **, double **, Datum **)
Definition: kschan.cpp:2596
int psize_
Definition: kschan.h:433
void setsname(int, const char *)
Definition: kschan.cpp:1261
Symbol ** newppsym(int)
Definition: kschan.cpp:2113
KSState * add_ksstate(int igate, const char *)
Definition: kschan.cpp:1584
int nksstate_
Definition: kschan.h:412
int ivkstrans_
Definition: kschan.h:408
void freesym(Symbol *, Symbol *tmplt=NULL)
Definition: kschan.cpp:2119
Symbol * rlsym_
Definition: kschan.h:428
Symbol ** ligands_
Definition: kschan.h:421
bool usetable_
Definition: kschan.h:442
KSIv * iv_relation_
Definition: kschan.h:405
int nhhstate_
Definition: kschan.h:411
virtual int count()
Definition: kschan.cpp:2938
bool is_single_
Definition: kschan.h:394
void free1()
Definition: kschan.cpp:1266
int gmaxoffset_
Definition: kschan.h:435
virtual void matsol(int, Node **, double **, Datum **, NrnThread *)
Definition: kschan.cpp:2985
void mat_dt(double dt, double *p)
Definition: kschan.cpp:2198
void solvemat(double *)
Definition: kschan.cpp:2209
void setligand(int i, const char *)
Definition: kschan.cpp:1360
virtual void init(int, Node **, double **, Datum **, NrnThread *)
Definition: kschan.cpp:2450
KSGateComplex * gc_
Definition: kschan.h:417
int cond_model_
Definition: kschan.h:404
int iligtrans_
Definition: kschan.h:409
bool is_single()
Definition: kschan.h:324
CopyString ion_
Definition: kschan.h:401
int gate_index(int state_index)
Definition: kschan.cpp:1078
void settype(KSTransition *, int type, const char *)
Definition: kschan.cpp:1380
Symbol * looksym(const char *, Symbol *tmplt=NULL)
Definition: kschan.cpp:2085
double dvinv_
Definition: kschan.h:155
KSChanTable(Vect *, double vmin, double vmax)
Definition: kschan.cpp:3064
virtual double f(double v)
Definition: kschan.cpp:3072
double vmax_
Definition: kschan.h:152
double vmin_
Definition: kschan.h:152
KSChan * ks_
Definition: kschan.h:230
Object * obj_
Definition: kschan.h:229
int index_
Definition: kschan.h:231
int sindex_
Definition: kschan.h:232
int nstate_
Definition: kschan.h:233
double conductance(double *state, KSState *st)
Definition: kschan.cpp:2907
virtual ~KSGateComplex()
Definition: kschan.cpp:2906
int power_
Definition: kschan.h:234
Definition: kschan.h:237
virtual double cur(double g, double *p, Datum *pd, double v)
Definition: kschan.cpp:2636
virtual double jacob(double *p, Datum *pd, double v)
Definition: kschan.cpp:2646
virtual double cur(double g, double *p, Datum *pd, double v)
Definition: kschan.cpp:2672
virtual double jacob(double *p, Datum *pd, double v)
Definition: kschan.cpp:2680
virtual double cur(double g, double *p, Datum *pd, double v)
Definition: kschan.cpp:2651
double z
Definition: kschan.h:249
virtual double jacob(double *p, Datum *pd, double v)
Definition: kschan.cpp:2662
Definition: kschan.h:257
virtual double cur(double g, double *p, Datum *pd, double v)
Definition: kschan.cpp:2684
virtual double jacob(double *p, Datum *pd, double v)
Definition: kschan.cpp:2697
int ppoff_
Definition: kschan.h:262
virtual double jacob(double *p, Datum *pd, double v)
Definition: kschan.cpp:2741
virtual double cur(double g, double *p, Datum *pd, double v)
Definition: kschan.cpp:2732
double z
Definition: kschan.h:269
virtual double jacob(double *p, Datum *pd, double v)
Definition: kschan.cpp:2719
virtual double cur(double g, double *p, Datum *pd, double v)
Definition: kschan.cpp:2705
void alloc(Prop *, int sindex)
Definition: kssingle.cpp:371
void init(double v, double *s, KSSingleNodeData *snd, NrnThread *)
Definition: kssingle.cpp:383
void state(Node *, double *, Datum *, NrnThread *)
Definition: kssingle.cpp:242
void cv_update(Node *, double *, Datum *, NrnThread *)
Definition: kssingle.cpp:257
static unsigned int idum_
Definition: kssingle.h:72
static double vres_
Definition: kssingle.h:71
int index_
Definition: kschan.h:286
CopyString name_
Definition: kschan.h:285
const char * string()
Definition: kschan.h:281
KSChan * ks_
Definition: kschan.h:287
virtual ~KSState()
Definition: kschan.cpp:2936
KSState()
Definition: kschan.cpp:2931
Object * obj_
Definition: kschan.h:288
double f_
Definition: kschan.h:284
virtual double beta()
Definition: kschan.cpp:2897
KSChanFunction * f0
Definition: kschan.h:207
KSChan * ks_
Definition: kschan.h:206
double * inftab_
Definition: kschan.h:217
int stoichiom_
Definition: kschan.h:213
double alpha(double v)
Definition: kschan.h:165
double tau(double v)
Definition: kschan.h:174
double * tautab_
Definition: kschan.h:218
int pd_index_
Definition: kschan.h:212
double inf(double v)
Definition: kschan.h:171
Object * obj_
Definition: kschan.h:202
void lig2pd(int pdoff)
Definition: kschan.cpp:2792
int index_
Definition: kschan.h:203
void inftau_hh_table(int i, double &inf, double &tau)
Definition: kschan.h:188
double beta(double v)
Definition: kschan.h:168
int src_
Definition: kschan.h:204
void ab(double v, double &a, double &b)
Definition: kschan.cpp:2803
void inftau(double v, double &inf, double &tau)
Definition: kschan.cpp:2841
int ligand_index_
Definition: kschan.h:211
KSChanFunction * f1
Definition: kschan.h:208
void hh_table_make(double dt, int size=200, double vmin=-100., double vmax=50.)
Definition: kschan.cpp:3087
int target_
Definition: kschan.h:205
void setf(int direction, int type, Vect *vec, double vmin, double vmax)
Definition: kschan.cpp:2777
virtual ~KSTransition()
Definition: kschan.cpp:2767
int size1_
Definition: kschan.h:219
int type_
Definition: kschan.h:209
const char * string() const
Definition: string.h:139
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:61
#define spClear
Definition: cspredef.h:5
#define spCreate
Definition: cspredef.h:7
#define spSolve
Definition: cspredef.h:39
#define spDestroy
Definition: cspredef.h:9
#define spFactor
Definition: cspredef.h:13
#define spMultiply
Definition: cspredef.h:29
double dt
Definition: netcvode.cpp:76
int use_cachevec
Definition: treeset.cpp:63
double t
Definition: cvodeobj.cpp:59
int v_structure_change
Definition: cvodestb.cpp:99
Datum * nrn_prop_datum_alloc(int type, int count, Prop *p)
Definition: cxprop.cpp:289
double * nrn_prop_data_alloc(int type, int count, Prop *p)
Definition: cxprop.cpp:277
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)
double chkarg(int, double low, double high)
Definition: code2.cpp:638
void register_mech(const char **, Pvmp, Pvmi, Pvmi, Pvmi, Pvmi, int, int)
Definition: init.cpp:674
void nrn_promote(Prop *p, int conc, int rev)
Definition: eion.cpp:539
#define c
void ion_reg(const char *name, double valence)
Definition: eion.cpp:154
nrn_ghk
Definition: extargs.h:2
static void update(NrnThread *)
Definition: fadvance.cpp:597
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
char buf[512]
Definition: init.cpp:13
Object ** hoc_temp_objvar(Symbol *symtemp, void *v)
Definition: hoc_oop.cpp:491
void notify_freed_val_array(double *p, size_t size)
Definition: ivoc.cpp:101
Symbol * hoc_install(const char *, int, double, Symlist **)
void hoc_warning(const char *, const char *)
int hoc_is_double_arg(int narg)
Definition: code.cpp:744
char ** hoc_temp_charptr(void)
Definition: code.cpp:642
Vect * vector_arg(int i)
Definition: ivocvect.cpp:397
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1810
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:72
Symbol * hoc_lookup(const char *)
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:748
double * hoc_pgetarg(int narg)
Definition: code.cpp:1623
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1828
#define assert(ex)
Definition: hocassrt.h:32
void * erealloc(void *ptr, size_t n)
Definition: symbol.cpp:263
#define getarg
Definition: hocdec.h:15
#define gargstr
Definition: hocdec.h:14
#define hocSEC(q)
Definition: hoclist.h:66
#define OBJ(q)
Definition: hoclist.h:67
void hoc_unlink_symbol(Symbol *, Symlist *)
Definition: symbol.cpp:146
Prop * nrn_point_prop_
Definition: point.cpp:28
Object ** hoc_objgetarg(int)
Definition: code.cpp:1587
Symlist * hoc_top_level_symlist
Definition: code2.cpp:690
Symlist * hoc_built_in_symlist
Definition: ivocmac.cpp:76
Symlist * hoc_symlist
int ifarg(int)
Definition: code.cpp:1581
Object ** vector_temp_objvar(Vect *v)
Definition: ivocvect.cpp:325
#define Vect
Definition: ivocvect.h:14
static double ks_gmax(void *v)
Definition: kschan.cpp:268
static double ks_setstructure(void *v)
Definition: kschan.cpp:186
static const char ** ks_ion(void *v)
Definition: kschan.cpp:411
static void nrn_init(NrnThread *nt, Memb_list *ml, int type)
Definition: kschan.cpp:66
static double kst_set_f(void *v)
Definition: kschan.cpp:491
static double hoc_nsingle(void *v)
Definition: kschan.cpp:168
static Symbol * ksgate_sym
Definition: kschan.cpp:27
static void nrn_cur(NrnThread *nt, Memb_list *ml, int type)
Definition: kschan.cpp:72
static void nrn_jacob(NrnThread *nt, Memb_list *ml, int type)
Definition: kschan.cpp:85
static double ks_ngate(void *v)
Definition: kschan.cpp:223
static double ks_remove_transition(void *v)
Definition: kschan.cpp:207
static double ksg_nstate(void *v)
Definition: kschan.cpp:463
static void * kst_cons(Object *o)
Definition: kschan.cpp:802
static Object ** ks_state(void *v)
Definition: kschan.cpp:389
static Object ** ks_add_hhstate(void *v)
Definition: kschan.cpp:329
static double kst_index(void *v)
Definition: kschan.cpp:509
static double kst_ftype(void *v)
Definition: kschan.cpp:531
static int ode_count(int type)
Definition: kschan.cpp:111
static Object ** kst_src(void *v)
Definition: kschan.cpp:578
static double kst_inftau(void *v)
Definition: kschan.cpp:556
static const char * m_kschan[9]
Definition: kschan.cpp:823
static double ks_rseed(void *v)
Definition: kschan.cpp:291
static Member_ret_obj_func kst_omem[]
Definition: kschan.cpp:758
static Member_ret_str_func ksg_smem[]
Definition: kschan.cpp:746
static double ks_single(void *v)
Definition: kschan.cpp:248
static double ks_remove_state(void *v)
Definition: kschan.cpp:192
static Member_ret_str_func kst_smem[]
Definition: kschan.cpp:763
static void ksg_destruct(void *)
Definition: kschan.cpp:801
static double hoc_has_loc(void *v)
Definition: kschan.cpp:162
static Member_ret_obj_func ksg_omem[]
Definition: kschan.cpp:744
static void nrn_state(NrnThread *nt, Memb_list *ml, int type)
Definition: kschan.cpp:98
static double hoc_get_loc_pnt(void *v)
Definition: kschan.cpp:165
static Object ** kst_target(void *v)
Definition: kschan.cpp:585
static double kss_index(void *v)
Definition: kschan.cpp:437
static double ks_erev(void *v)
Definition: kschan.cpp:276
static Object ** kss_gate(void *v)
Definition: kschan.cpp:443
static void ks_destruct(void *)
Definition: kschan.cpp:785
static Object ** ks_gate(void *v)
Definition: kschan.cpp:395
std::vector< KSChan * > KSChanList
Definition: kschan.cpp:19
static double kst_stoichiometry(void *v)
Definition: kschan.cpp:633
static Member_ret_str_func kss_smem[]
Definition: kschan.cpp:736
static double ks_usetable(void *v)
Definition: kschan.cpp:298
static Member_func kst_dmem[]
Definition: kschan.cpp:748
static Object ** ks_add_ksstate(void *v)
Definition: kschan.cpp:335
static void * ks_cons(Object *o)
Definition: kschan.cpp:765
static void hoc_destroy_pnt(void *v)
Definition: kschan.cpp:140
static Symbol * ksstate_sym
Definition: kschan.cpp:26
static double kst_f(void *v)
Definition: kschan.cpp:566
static double ksg_power(void *v)
Definition: kschan.cpp:469
char * hoc_symbol_units(Symbol *, const char *)
Definition: code2.cpp:126
static void check_table_thread_(double *p, Datum *ppvar, Datum *thread, NrnThread *vnt, int type)
Definition: kschan.cpp:56
static void * kss_cons(Object *o)
Definition: kschan.cpp:792
static double ksg_sindex(void *v)
Definition: kschan.cpp:479
static double ks_is_point(void *v)
Definition: kschan.cpp:243
static Member_func ks_dmem[]
Definition: kschan.cpp:696
static void ode_spec(NrnThread *, Memb_list *ml, int type)
Definition: kschan.cpp:122
static const char ** kss_name(void *v)
Definition: kschan.cpp:452
static double ksg_index(void *v)
Definition: kschan.cpp:485
static double kst_ab(void *v)
Definition: kschan.cpp:546
static Object ** kst_parm(void *v)
Definition: kschan.cpp:592
static double ks_vres(void *v)
Definition: kschan.cpp:284
static double ks_nligand(void *v)
Definition: kschan.cpp:238
#define NSingleIndex
Definition: kschan.cpp:13
static const char * m_kschan_pat[]
Definition: kschan.cpp:822
static double hoc_loc_pnt(void *v)
Definition: kschan.cpp:158
static void check_objtype(Object *o, Symbol *s)
Definition: kschan.cpp:32
static int ksusing(int type)
Definition: kschan.cpp:3131
void nrn_mk_table_check()
Definition: multicore.cpp:1065
static double ks_nstate(void *v)
Definition: kschan.cpp:228
static void singchan(NrnThread *nt, Memb_list *ml, int type)
Definition: kschan.cpp:132
static Member_func kss_dmem[]
Definition: kschan.cpp:732
static Object ** temp_objvar(const char *name, void *v, Object **obp)
Definition: kschan.cpp:317
static double kss_frac(void *v)
Definition: kschan.cpp:428
static double kst_type(void *v)
Definition: kschan.cpp:515
static Object ** ks_add_transition(void *v)
Definition: kschan.cpp:349
static void * hoc_create_pnt(Object *ho)
Definition: kschan.cpp:137
static void chkobj(void *v)
Definition: kschan.cpp:50
spREAL * spGetElement(char *, int, int)
Definition: spbuild.c:195
void KSChan_reg()
Definition: kschan.cpp:808
static void unref(Object *obj)
Definition: kschan.cpp:43
static void nrn_alloc(Prop *prop)
Definition: kschan.cpp:61
static Object ** ks_trans(void *v)
Definition: kschan.cpp:371
static void kst_destruct(void *)
Definition: kschan.cpp:806
static const char ** ks_ligand(void *v)
Definition: kschan.cpp:421
static double ks_pr(void *v)
Definition: kschan.cpp:641
static KSChanList * channels
Definition: kschan.cpp:20
static void * ksg_cons(Object *o)
Definition: kschan.cpp:797
static Member_func ksg_dmem[]
Definition: kschan.cpp:738
static void ode_matsol(NrnThread *nt, Memb_list *ml, int type)
Definition: kschan.cpp:127
void kschan_cvode_single_update()
Definition: kschan.cpp:182
static Member_ret_str_func ks_smem[]
Definition: kschan.cpp:727
static double ks_iv_type(void *v)
Definition: kschan.cpp:256
static void ode_map(int ieq, double **pv, double **pvdot, double *p, Datum *pd, double *atol, int type)
Definition: kschan.cpp:117
static const char ** kst_ligand(void *v)
Definition: kschan.cpp:617
static const char ** ks_name(void *v)
Definition: kschan.cpp:401
static Symbol * kstrans_sym
Definition: kschan.cpp:28
static Member_ret_obj_func kss_omem[]
Definition: kschan.cpp:734
static Member_func member_func[]
Definition: kschan.cpp:176
static double ks_ntrans(void *v)
Definition: kschan.cpp:233
static Member_ret_obj_func ks_omem[]
Definition: kschan.cpp:719
static void kss_destruct(void *)
Definition: kschan.cpp:796
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:216
#define nodeindices
Definition: md1redef.h:26
#define v
Definition: md1redef.h:4
#define sec
Definition: md1redef.h:13
#define i
Definition: md1redef.h:12
#define prop
Definition: md1redef.h:29
#define nrnocCONST
Definition: membfunc.h:69
#define ITERATE(itm, lst)
Definition: model.h:25
#define Printf
Definition: model.h:237
floor
Definition: extdef.h:4
pow
Definition: extdef.h:4
char * name
Definition: init.cpp:16
long subtype
Definition: init.cpp:215
int nrn_nthread
Definition: multicore.cpp:46
NrnThread * nrn_threads
Definition: multicore.cpp:47
#define printf
Definition: mwprefix.h:26
Prop * prop_alloc(Prop **, int, Node *)
Definition: treeset.cpp:694
static char suffix[256]
Definition: nocpout.cpp:149
#define nrn_assert(ex)
Definition: nrnassrt.h:53
double nrn_ion_charge(Symbol *)
Definition: eion.cpp:61
int const size_t const size_t n
Definition: nrngsl.h:11
size_t q
size_t p
size_t j
void destroy_point_process(void *)
Definition: point.cpp:75
double loc_point_process(int, void *)
Definition: point.cpp:217
double has_loc_point(void *)
Definition: point.cpp:252
void * create_point_process(int, Object *)
Definition: point.cpp:32
double get_loc_point_process(void *)
Definition: point.cpp:232
Prop * need_memb(Symbol *)
Definition: treeset.cpp:645
void * hoc_Emalloc(size_t size)
Definition: symbol.cpp:190
void hoc_malchk()
Definition: symbol.cpp:183
hoc_List * section_list
Definition: init.cpp:102
void hoc_register_cvode(int i, nrn_ode_count_t cnt, nrn_ode_map_t map, Pvmi spec, Pvmi matsol)
Definition: init.cpp:767
int point_register_mech(const char **m, Pvmp alloc, Pvmi cur, Pvmi jacob, Pvmi stat, Pvmi initialize, int nrnpointerindex, int vectorized, void *(*constructor)(Object *), void(*destructor)(void *), Member_func *fmember)
Definition: init.cpp:806
void class2oc(const char *, void *(*cons)(Object *), void(*destruct)(void *), Member_func *, int(*checkpoint)(void **), Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1560
static philox4x32_key_t k
Definition: nrnran123.cpp:11
static void * vmin(NrnThread *nt)
static double remove(void *v)
Definition: ocdeck.cpp:207
static Symbol * pv[4]
Definition: partial.cpp:80
#define g
Definition: passive0.cpp:21
#define e
Definition: passive0.cpp:22
#define power
Definition: redef.h:107
o
Definition: seclist.cpp:175
#define VEC_D(i)
Definition: section.h:120
#define VEC_RHS(i)
Definition: section.h:121
#define NODEV(n)
Definition: section.h:115
#define NODERHS(n)
Definition: section.h:105
#define NODED(n)
Definition: section.h:104
#define VEC_V(i)
Definition: section.h:122
#define spNO_MEMORY
Definition: spmatrix.h:101
#define spZERO_DIAG
Definition: spmatrix.h:99
#define spSINGULAR
Definition: spmatrix.h:100
#define spREAL
Definition: spmatrix.h:127
#define spOKAY
Definition: spmatrix.h:97
#define NULL
Definition: sptree.h:16
float * parmlimits
Definition: hocdec.h:111
char * units
Definition: hocdec.h:112
void(* thread_table_check_)(double *, Datum *, Datum *, NrnThread *, int)
Definition: membfunc.h:51
Pvmp alloc
Definition: membfunc.h:32
int nodecount
Definition: nrnoc_ml.h:18
Node ** nodelist
Definition: nrnoc_ml.h:5
double ** data
Definition: nrnoc_ml.h:14
Datum ** pdata
Definition: nrnoc_ml.h:15
Definition: section.h:133
struct Prop * prop
Definition: section.h:152
Represent main neuron object computed by single thread.
Definition: multicore.h:58
double _dt
Definition: multicore.h:60
Definition: hocdec.h:227
void * this_pointer
Definition: hocdec.h:232
int index
Definition: hocdec.h:229
union Object::@39 u
Object * ob
Definition: section.h:267
Prop * prop
Definition: section.h:265
Definition: section.h:214
Datum * dparam
Definition: section.h:220
double * param
Definition: section.h:219
int param_size
Definition: section.h:218
short type
Definition: section.h:216
struct Prop * next
Definition: section.h:215
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
union Symbol::@18 u
unsigned s_varn
Definition: hocdec.h:158
char * name
Definition: model.h:72
HocSymExtension * extra
Definition: hocdec.h:160
HocStruct cTemplate * ctemplate
Definition: hocdec.h:152
Definition: hocdec.h:84
Symlist * symtable
Definition: hocdec.h:197
hoc_List * olist
Definition: hocdec.h:204
Definition: hocdec.h:177
double * pval
Definition: hocdec.h:181
void * _pvoid
Definition: hocdec.h:187
char * strstr(char *cs, char *ct)
Definition: xred.cpp:173