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