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