NEURON
netcvode.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 //define to 0 if do not wish use_min_delay_ to ever be 1
4 #define USE_MIN_DELAY 1
5 
6 #include <stdlib.h>
7 #include <nrnmpi.h>
8 #include <errno.h>
9 #include <time.h>
10 #include <InterViews/resource.h>
11 #include <OS/list.h>
12 #include <OS/math.h>
13 #include <OS/table.h>
14 #include <InterViews/regexp.h>
15 #include "classreg.h"
16 #include "nrnoc2iv.h"
17 #include "parse.hpp"
18 #include "cvodeobj.h"
19 #include "hoclist.h"
20 #include "pool.h"
21 #include "tqueue.h"
22 #include "ocobserv.h"
23 #include "nrnneosm.h"
24 #include "datapath.h"
25 #include "objcmd.h"
26 #include "shared/sundialsmath.h"
27 #include "kssingle.h"
28 #include "ocnotify.h"
29 #if HAVE_IV
30 #include "ivoc.h"
31 #include "glinerec.h"
32 #include "ocjump.h"
33 #endif
34 #include "vrecitem.h"
35 #include "oclist.h"
36 #define PROFILE 0
37 #include "htlist.h"
38 #include "ivocvect.h"
39 #include "netcon.h"
40 #include "netcvode.h"
42 #include "nrnste.h"
43 #include "profile.h"
45 #include <unordered_map>
46 
47 typedef void (*ReceiveFunc)(Point_process*, double*, double);
48 
49 #define lvardtloop(i,j) for(i=0; i < nrn_nthread; ++i) for (j=0; j < p[i].nlcv_; ++j)
50 
51 #define NVI_SUCCESS 0
52 #define PP2NT(pp) ((NrnThread*)((pp)->_vnt))
53 #define PP2t(pp) (PP2NT(pp)->_t)
54 #define LOCK(m) /**/
55 #define UNLOCK(m) /**/
56 // classical and when DiscreteEvent::deliver is already in the right thread
57 // via a future thread instance of NrnNetItem with its own tqe.
58 #define POINT_RECEIVE(type, tar, w, f) (*pnt_receive[type])(tar, w, f)
59 // when global tqe is managed by master thread and the correct thread
60 // needs to be fired to execute the NET_RECEIVE block.
61 //#define POINT_RECEIVE(type, tar, w, f) ns->point_receive(type, tar, w, f)
62 
63 #include "membfunc.h"
64 extern void single_event_run();
65 extern void setup_topology(), v_setup_vectors();
66 extern "C" int structure_change_cnt;
67 extern int v_structure_change;
68 extern int tree_changed, nrn_matrix_cnt_;
69 extern int diam_changed;
70 extern int nrn_errno_check(int);
71 extern void nrn_ba(NrnThread*, int);
72 extern int cvode_active_;
75 extern double t, dt;
76 extern void nrn_cvfun(double t, double* y, double* ydot);
77 extern void nrn_cleanup_presyn(PreSyn*);
78 #define nt_dt nrn_threads->_dt
79 #define nt_t nrn_threads->_t
80 extern void nrn_parent_info(Section*);
81 extern Object* nrn_sec2cell(Section*);
82 extern int nrn_sec2cell_equals(Section*, Object*);
83 extern ReceiveFunc* pnt_receive;
85 extern short* pnt_receive_size;
86 extern short* nrn_is_artificial_; // should be bool but not using that type in c
87 extern short* nrn_artcell_qindex_;
88 extern "C" void net_send(void**, double*, Point_process*, double, double);
89 extern "C" void net_move(void**, Point_process*, double);
90 extern "C" void artcell_net_send(void**, double*, Point_process*, double, double);
91 extern "C" void artcell_net_move(void**, Point_process*, double);
93 void nrn_pending_selfqueue(double tt, NrnThread*);
94 static void all_pending_selfqueue(double tt);
95 static void* pending_selfqueue(NrnThread*);
96 extern "C" void net_event(Point_process*, double);
97 extern "C" void _nrn_watch_activate(Datum*, double (*)(Point_process*), int, Point_process*, int, double);
98 extern "C" void _nrn_free_watch(Datum*, int, int);
99 extern int hoc_araypt(Symbol*, int);
100 extern int hoc_stacktype();
101 extern "C" Point_process* ob2pntproc(Object*);
102 extern "C" Point_process* ob2pntproc_0(Object*);
103 void nrn_use_daspk(int);
104 extern int nrn_use_daspk_;
106 extern int nrn_modeltype();
111 extern PlayRecList* net_cvode_instance_prl();
112 extern void nrn_update_ps2nt();
113 extern void nrn_use_busywait(int);
114 extern "C" double* nrn_recalc_ptr(double*);
117 Object* (*nrnpy_seg_from_sec_x)(Section*, double);
118 extern "C" void nrnthread_get_trajectory_requests(int tid, int& bsize, int& n_pr, void**& vpr, int& n_trajec, int*& types, int*& indices, double**& pvars, double**& varrays);
119 extern "C" void nrnthread_trajectory_values(int tid, int n_pr, void** vpr, double t);
120 extern "C" void nrnthread_trajectory_return(int tid, int n_pr, int bsize, int vecsz, void** vpr, double t);
122 #if NRN_MUSIC
123 extern void nrnmusic_injectlist(void*, double);
124 #endif
125 
126 extern int hoc_return_type_code;
127 
128 extern int nrn_fornetcon_cnt_;
129 extern int* nrn_fornetcon_index_;
130 extern int* nrn_fornetcon_type_;
131 void _nrn_free_fornetcon(void**);
132 //int _nrn_netcon_args(void*, double***);
133 
134 // for use in mod files
135 double nrn_netcon_get_delay(NetCon* nc) { return nc->delay_; }
136 void nrn_netcon_set_delay(NetCon* nc, double d) { nc->delay_ = d; }
137 int nrn_netcon_weight(NetCon* nc, double** pw) {
138  *pw = nc->weight_;
139  return nc->cnt_;
140 }
141 extern "C" double nrn_event_queue_stats(double* stats) {
142 #if COLLECT_TQueue_STATISTICS
144  return (stats[0]-stats[2]);
145 #else
146  return -1.;
147 #endif
148 }
150  if (nc->src_) {
151  return nc->src_->threshold_;
152  }else{
153  return 0;
154  }
155 }
156 void nrn_netcon_set_thresh(NetCon* nc, double th) {
157  if (nc->src_) {
158  nc->src_->threshold_ = th;
159  }
160 }
161 
162 void nrn_netcon_event(NetCon* nc, double td) {
163  nc->chktar();
164  net_cvode_instance->event(td, nc, PP2NT(nc->target_));
165 }
166 
168  nc->chktar();
169  return nc->target_;
170 }
171 
172 int nrn_netcon_info(NetCon* nc, double **pw, Point_process **target,
173  double **th, double **del) {
174  *target=(nc->target_)? nc->target_:(Point_process*)0;
175  *th=(nc->src_)?&(nc->src_->threshold_):(double*)0;
176  *del=&nc->delay_;
177  *pw = nc->weight_;
178  return nc->cnt_;
179 }
180 
182  return ps->dil_.size();
183 }
184 void* nrn_presyn_netcon(PreSyn* ps, int i) {
185  return ps->dil_[i];
186 }
187 
188 #if USENEOSIM
189 void neosim2nrn_advance(void*, void*, double);
190 void neosim2nrn_deliver(void*, void*);
191 void (*p_nrn2neosim_send)(void*, double);
192 static void* neosim_entity_;
193 #endif
194 
195 void ncs2nrn_integrate(double tstop);
196 void nrn_fixed_step();
197 void nrn_fixed_step_group(int);
198 extern void (*nrn_allthread_handle)();
200  net_cvode_instance->allthread_handle();
201 }
202 
203 #if USENCS
204 // As a subroutine for NCS, NEURON simulates the cells of a subnet
205 // (usually a single cell) and NCS manages whatever intercellular
206 // NetCon connections were specified by the hoc cvode method
207 // Cvode.ncs_netcons(List nc_inlist, List nc_outlist) . The former list
208 // is normally in one to one correspondence with all the synapses. These
209 // NetCon objects have those synapses as targets and nil sources.
210 // The latter list is normally in one to one correspondence with
211 // the cells of the subnet. Those NetCon objects have sources of the form
212 // cell.axon.v(1) and nil targets.
213 // Note that the program that creates the hoc file knows
214 // how to tell NCS that a particular integer corresponds to a particular
215 // NetCon
216 
217 // NCS tells NEURON what time to integrate to. (Using any integration method)
218 // Probably the step size will be the minimum delay between output spike
219 // and its effect on any synapse.
220 // void ncs2nrn_integrate(double tstop);
221 
222 // NCS gives synaptic events to NEURON but tdeliver must be >= t
223 void ncs2nrn_inputevent(int netcon_input_index, double tdeliver);
224 
225 // and NEURON notifies NCS if cell ouputs a spike during integrate
226 extern void nrn2ncs_outputevent(int netcon_output_index, double firetime);
227 
228 // netcon_input_index specifies the NetCon object
229 // in the following list. The hoc file sets this up via cvode.ncs_netcons
230 static NetConPList* ncs2nrn_input_;
231 
232 // the netcon_ouput_index is specified in a NetCon field called
233 // nrn2ncs_output_index_
234 
235 // helper functions
236 void nrn2ncs_netcons();
237 #endif
238 #if NRNMPI
239 extern void nrn2ncs_outputevent(int netcon_output_index, double firetime);
240 #endif
241 
242 #if BGPDMA
243 extern void bgp_dma_send(PreSyn*, double t);
244 extern bool use_bgpdma_;
245 extern void nrnbgp_messager_advance();
246 #endif
247 
249 
250 #if BBTQ == 5
252 #endif
253 
254 #if NRNMPI
255 // for compressed info during spike exchange
256 extern bool nrn_use_localgid_;
257 extern void nrn_outputevent(unsigned char, double);
258 #endif
259 
261  double** argslist;
262  int size;
263 };
264 
265 static unsigned long deliver_cnt_, net_event_cnt_;
268 unsigned long NetCon::netcon_send_active_;
269 unsigned long NetCon::netcon_send_inactive_;
270 unsigned long NetCon::netcon_deliver_;
271 unsigned long SelfEvent::selfevent_send_;
272 unsigned long SelfEvent::selfevent_move_;
273 unsigned long SelfEvent::selfevent_deliver_;
274 unsigned long WatchCondition::watch_send_;
275 unsigned long WatchCondition::watch_deliver_;
276 unsigned long ConditionEvent::init_above_;
277 unsigned long ConditionEvent::send_qthresh_;
279 unsigned long ConditionEvent::abandon_;
280 unsigned long ConditionEvent::eq_abandon_;
283 unsigned long ConditionEvent::abandon_above_;
284 unsigned long ConditionEvent::abandon_below_;
285 unsigned long PreSyn::presyn_send_mindelay_;
286 unsigned long PreSyn::presyn_send_direct_;
287 unsigned long PreSyn::presyn_deliver_netcon_;
288 unsigned long PreSyn::presyn_deliver_direct_;
289 unsigned long PreSyn::presyn_deliver_ncsend_;
292 unsigned long HocEvent::hocevent_send_;
293 unsigned long HocEvent::hocevent_deliver_;
294 unsigned long KSSingle::singleevent_deliver_;
295 unsigned long KSSingle::singleevent_move_;
296 
298  return net_cvode_instance->event_queue(nt);
299 }
300 
302  return net_cvode_instance->psl_;
303 }
304 
305 PlayRecList* net_cvode_instance_prl() {
306  return net_cvode_instance->playrec_list();
307 }
308 
309 void nrn_use_daspk(int b) {
310  if (net_cvode_instance) {
311  net_cvode_instance->use_daspk(b == 1);
312  }
313 }
314 
315 double NetCvode::eps_;
316 
317 static Node* node(Object*);
318 Node* node(Object* ob) {
319  return ob2pntproc(ob)->node;
320 }
321 
324 
326  PlayRecordEvent* pre = new PlayRecordEvent();
327  pre->plr_ = plr_;
328  return pre;
329 }
331  nc->event(tt, plr_->event(), nrn_threads + plr_->ith_);
332 }
334  fprintf(f, "%d\n", PlayRecordEventType);
335  fprintf(f, "%d %d\n", plr_->type(), net_cvode_instance->playrec_item(plr_));
336 }
337 
339  DiscreteEvent* de = nil;
340  char buf[100];
341  int type, plr_index;
342  nrn_assert(fgets(buf, 100, f));
343  sscanf(buf, "%d %d\n", &type, &plr_index);
344  PlayRecord* plr = net_cvode_instance->playrec_item(plr_index);
345  assert(plr && plr->type() == type);
346  return plr->event()->savestate_save();
347 }
348 
349 PlayRecordSave* PlayRecord::savestate_save() {
350  return new PlayRecordSave(this);
351 }
352 
353 PlayRecordSave* PlayRecord::savestate_read(FILE* f) {
354  PlayRecordSave* prs = nil;
355  int type, index;
356  char buf[100];
357  nrn_assert(fgets(buf, 100, f));
358  nrn_assert(sscanf(buf, "%d %d\n", &type, &index) == 2);
359  PlayRecord* plr = net_cvode_instance->playrec_item(index);
360  assert(plr->type() == type);
361  switch (type) {
363  prs = new VecRecordDiscreteSave(plr);
364  break;
365  case VecRecordDtType:
366  prs = new VecRecordDtSave(plr);
367  break;
368  case VecPlayStepType:
369  prs = new VecPlayStepSave(plr);
370  break;
372  prs = new VecPlayContinuousSave(plr);
373  break;
374  default:
375  // whenever there is no subclass specific data to save
376  prs = new PlayRecordSave(plr);
377  break;
378  }
379  prs->savestate_read(f);
380  return prs;
381 }
382 
383 PlayRecordSave::PlayRecordSave(PlayRecord* plr) {
384  pr_ = plr;
385  prl_index_ = net_cvode_instance->playrec_item(pr_);
386  assert(prl_index_ >= 0);
387 }
388 PlayRecordSave::~PlayRecordSave() {
389 }
390 void PlayRecordSave::check() {
391  assert(pr_ == net_cvode_instance->playrec_item(prl_index_));
392 }
393 
395  if (!src_) {
396  hoc_execerror(hoc_object_name(obj_), "source is missing");
397  }
398 }
400  if (!target_) {
401  hoc_execerror(hoc_object_name(obj_), "target is missing");
402  }
403 }
404 
406  Object* ob = ((ObjObservable*)o)->object();
407 //printf("%s disconnect from ", hoc_object_name(obj_));
408  if (target_->ob == ob) {
409 //printf("target %s\n", hoc_object_name(target_->ob));
410  target_ = nil;
411  active_ = 0;
412  }
413 }
414 
415 #if 0 // way of printing dinfo
416 printf("NetCon from %s to ",
417 d->src_->osrc_ ? hoc_object_name(d->src_->osrc_) : secname(d->src_->ssrc_));
418 printf("%s ", hoc_object_name(d->target_->ob));
419 printf(" weight index=%d\n", l);
420 #endif
421 
423 public:
425  double max_;
426  double amax_;
427 };
428 
431  double t_;
432 };
433 
434 declareTable(MaxStateTable, void*, MaxStateItem*)
435 implementTable(MaxStateTable, void*, MaxStateItem*)
436 declarePtrList(PreSynList, PreSyn)
437 implementPtrList(PreSynList, PreSyn)
438 declarePtrList(WatchList, WatchCondition)
440 declareTable(PreSynTable, double*, PreSyn*)
441 implementTable(PreSynTable, double*, PreSyn*)
442 declarePool(SelfEventPool, SelfEvent)
443 implementPool(SelfEventPool, SelfEvent)
444 declarePtrList(TQList, TQItem)
445 implementPtrList(TQList, TQItem)
446 declarePtrList(HocEventList, HocEvent)
447 implementPtrList(HocEventList, HocEvent)
448 
449 // allows marshalling of all items in the event queue that need to be
450 // removed to avoid duplicates due to frecord_init after finitialize
451 static TQList* record_init_items_;
452 
455 
456 static PreSyn* unused_presyn; // holds the NetCons with no source
457 
458 static double nc_preloc(void* v) { // user must pop section stack after call
459  NetCon* d = (NetCon*)v;
460  Section* s = nil;
461  if (d->src_) {
462  s = d->src_->ssrc_;
463  }
464  if (s) {
465  nrn_pushsec(s);
466  double* v = d->src_->thvar_;
467  nrn_parent_info(s); // make sure parentnode exists
468  // there is no efficient search for the location of
469  // an arbitrary variable. Search only for v at 0 - 1.
470  // Otherwise return .5 .
471  if (v == &NODEV(s->parentnode)) {
472  return nrn_arc_position(s, s->parentnode);
473  }
474  for (int i = 0; i < s->nnode; ++i) {
475  if (v == &NODEV(s->pnode[i])) {
476  return nrn_arc_position(s, s->pnode[i]);
477  }
478  }
479  return -2.; // not voltage
480  }else{
481  return -1.;
482  }
483 }
484 
485 static Object** nc_preseg(void* v) { // user must pop section stack after call
486  NetCon* d = (NetCon*)v;
487  Section* s = NULL;
488  Object* obj = NULL;
489  double x = -1.;
490  if (d->src_) {
491  s = d->src_->ssrc_;
492  }
493  if (s && nrnpy_seg_from_sec_x) {
494  double* v = d->src_->thvar_;
495  nrn_parent_info(s); // make sure parentnode exists
496  // there is no efficient search for the location of
497  // an arbitrary variable. Search only for v at 0 - 1.
498  // Otherwise return NULL.
499  if (v == &NODEV(s->parentnode)) {
500  x = nrn_arc_position(s, s->parentnode);
501  }
502  for (int i = 0; i < s->nnode; ++i) {
503  if (v == &NODEV(s->pnode[i])) {
504  x = nrn_arc_position(s, s->pnode[i]);
505  continue;
506  }
507  }
508  // perhaps should search for v
509  if (x >= 0) {
510  obj = (*nrnpy_seg_from_sec_x)(s, x);
511  --obj->refcount;
512  }
513  }
514  return hoc_temp_objptr(obj);
515 }
516 
517 static double nc_postloc(void* v) { // user must pop section stack after call
518  NetCon* d = (NetCon*)v;
519  if (d->target_ && d->target_->sec) {
520  nrn_pushsec(d->target_->sec);
521  return nrn_arc_position(d->target_->sec, d->target_->node);
522  }else{
523  return -1.;
524  }
525 }
526 
527 static Object** nc_postseg(void* v) { // user must pop section stack after call
528  NetCon* d = (NetCon*)v;
529  Object* obj = NULL;
530  if (d->target_ && d->target_->sec && nrnpy_seg_from_sec_x) {
531  double x = nrn_arc_position(d->target_->sec, d->target_->node);
532  obj = (*nrnpy_seg_from_sec_x)(d->target_->sec, x);
533  --obj->refcount;
534  }
535  return hoc_temp_objptr(obj);
536 }
537 
538 static Object** nc_syn(void* v) {
539  NetCon* d = (NetCon*)v;
540  Object* ob = nil;
541  if (d->target_) {
542  ob = d->target_->ob;
543  }
544  return hoc_temp_objptr(ob);
545 }
546 
547 static Object** nc_pre(void* v) {
548  NetCon* d = (NetCon*)v;
549  Object* ob = nil;
550  if (d->src_) {
551  ob = d->src_->osrc_;
552  }
553  return hoc_temp_objptr(ob);
554 }
555 
556 static Object** newoclist(int i, OcList*& o) {
557  Object** po;
558  if (ifarg(i) && hoc_is_object_arg(i)) {
559  po = hoc_objgetarg(i);
560  check_obj_type(*po, "List");
561  o = (OcList*)((*po)->u.this_pointer);
562  }else{
563  o = new OcList();
564  o->ref();
565  Symbol* sl = hoc_lookup("List");
566  po = hoc_temp_objvar(sl, o);
567  }
568  return po;
569 }
570 
571 static Object** nc_prelist(void* v) {
572  NetCon* d = (NetCon*)v;
573  OcList* o;
574  Object** po = newoclist(1, o);
575  if (d->src_) {
576  const NetConPList& dil = d->src_->dil_;
577  for (const auto& d : dil) {
578  if (d->obj_) {
579  o->append(d->obj_);
580  }
581  }
582  }
583  return po;
584 }
585 
586 static Object** nc_synlist(void* v) {
587  NetCon* d = (NetCon*)v;
588  OcList* o;
589  Object** po = newoclist(1, o);
590  hoc_Item* q;
591  if (net_cvode_instance->psl_) ITERATE(q, net_cvode_instance->psl_) {
592  PreSyn* ps = (PreSyn*)VOIDITM(q);
593  const NetConPList& dil = ps->dil_;
594  for (const auto& d1 : dil) {
595  if (d1->obj_ && d1->target_ == d->target_) {
596  o->append(d1->obj_);
597  }
598  }
599  }
600  return po;
601 }
602 
603 static Object** nc_postcelllist(void* v) {
604  NetCon* d = (NetCon*)v;
605  OcList* o;
606  Object** po = newoclist(1, o);
607  hoc_Item* q;
608  Object* cell = nil;
609  if (d->target_ && d->target_->sec) {
610  cell = nrn_sec2cell(d->target_->sec);
611  }
612  if (cell && net_cvode_instance->psl_) ITERATE(q, net_cvode_instance->psl_) {
613  PreSyn* ps = (PreSyn*)VOIDITM(q);
614  const NetConPList& dil = ps->dil_;
615  for (const auto& d1 : dil) {
616  if (d1->obj_ && d1->target_
617  && nrn_sec2cell_equals(d1->target_->sec, cell)) {
618  o->append(d1->obj_);
619  }
620  }
621  }
622  return po;
623 }
624 
625 static Object** nc_precelllist(void* v) {
626  NetCon* d = (NetCon*)v;
627  OcList* o;
628  Object** po = newoclist(1, o);
629  hoc_Item* q;
630  Object* cell = nil;
631  if (d->src_ && d->src_->ssrc_) { cell = nrn_sec2cell(d->src_->ssrc_);}
632  if (cell && net_cvode_instance->psl_) ITERATE(q, net_cvode_instance->psl_) {
633  PreSyn* ps = (PreSyn*)VOIDITM(q);
634  const NetConPList& dil = ps->dil_;
635  for (const auto& d1 : dil) {
636  if (d1->obj_ && d1->src_ && ps->ssrc_
637  && nrn_sec2cell_equals(ps->ssrc_, cell)) {
638  o->append(d1->obj_);
639  }
640  }
641  }
642  return po;
643 }
644 
645 static Object** nc_precell(void* v) {
646  NetCon* d = (NetCon*)v;
647  if (d->src_ && d->src_->ssrc_) {
648  return hoc_temp_objptr(nrn_sec2cell(d->src_->ssrc_));
649  }else{
650  return hoc_temp_objptr(0);
651  }
652 }
653 
654 static Object** nc_postcell(void* v) {
655  NetCon* d = (NetCon*)v;
656  Object* ob = nil;
657  if (d->target_ && d->target_->sec) {
658  ob = nrn_sec2cell(d->target_->sec);
659  }
660  return hoc_temp_objptr(ob);
661 }
662 
663 static double nc_setpost(void* v) {
664  NetCon* d = (NetCon*)v;
665  Object* otar = nil;
666  if (ifarg(1)) {
667  otar = *hoc_objgetarg(1);
668  }
669  if (otar && !is_point_process(otar)) {
670  hoc_execerror("argument must be a point process or NULLobject",0);
671  }
672  Point_process* tar = nil;
673  if (otar) {
674  tar = ob2pntproc(otar);
675  }
676  if (d->target_ && d->target_ != tar) {
677 #if DISCRETE_EVENT_OBSERVER
679 #endif
680  d->target_ = nil;
681  }
682  int cnt = 1;
683  if (tar) {
684  cnt = pnt_receive_size[tar->prop->type];
685  d->target_ = tar;
686 #if DISCRETE_EVENT_OBSERVER
687  ObjObservable::Attach(otar, d);
688 #endif
689  }else{
690  d->active_ = false;
691  }
692  if (d->cnt_ != cnt) {
693  d->cnt_ = cnt;
694  delete [] d->weight_;
695  d->weight_ = new double[d->cnt_];
696  }
697  return 0.;
698 }
699 
700 static double nc_valid(void* v) {
701  NetCon* d = (NetCon*)v;
702  hoc_return_type_code = 2;
703  if (d->src_ && d->target_) {
704  return 1.;
705  }
706  return 0.;
707 }
708 
709 static double nc_active(void* v) {
710  NetCon* d = (NetCon*)v;
711  bool a = d->active_;
712  if (d->target_ && ifarg(1)) {
713  d->active_ = bool(chkarg(1, 0, 1));
714  }
715  hoc_return_type_code = 2;
716  return double(a);
717 }
718 
719 // for threads, revised net_send to use absolute time (in the
720 // mod file we add the thread time when we call it).
721 // And we can no longer check with respect to minimum time in chkarg
722 static double nc_event(void* v) {
723  NetCon* d = (NetCon*)v;
724  double td = chkarg(1, -1e20,1e20);
725  if (d->active_ == 0) { return 0.0; }
726  d->chktar();
727  NrnThread* nt = PP2NT(d->target_);
728  if (!nt || nt < nrn_threads || nt > (nrn_threads+(nrn_nthread-1))){
729 //printf("%s.event %s\n", hoc_object_name(d->obj_), "target does not know its thread yet.");
730  return 0.0;
731  }
732  if (ifarg(2)) {
733  double flag = *getarg(2);
734  Point_process* pnt = d->target_;
735  int type = pnt->prop->type;
736  if (!nrn_is_artificial_[type]) {
737  hoc_execerror("Can only send fake self-events to ARTIFICIAL_CELLs",0);
738  }
739  void** pq = (void**)(&pnt->prop->dparam[nrn_artcell_qindex_[type]]._pvoid);
740  net_send(pq, d->weight_, pnt, td, flag);
741  }else{
742  net_cvode_instance->event(td, d, PP2NT(d->target_));
743  }
744  return (double)d->active_;
745 }
746 static double nc_record(void* v) {
747  NetCon* d = (NetCon*)v;
748  d->chksrc();
749  if (ifarg(1)) {
750  if (ifarg(2)) {
751  int recid = d->obj_->index;
752  if (ifarg(3)) {
753  recid = (int)(*getarg(3));
754  }
755  d->src_->record(vector_arg(1), vector_arg(2), recid);
756  }else if (hoc_is_str_arg(1)) {
757  d->src_->record_stmt(gargstr(1));
758  }else if (is_vector_arg(1)){
759  d->src_->record(vector_arg(1));
760  }else{
761  d->src_->record_stmt(*hoc_objgetarg(1));
762  }
763  }else{
764  d->src_->record((IvocVect*)nil);
765  }
766  return 0;
767 }
768 
769 static double nc_srcgid(void* v) {
770  NetCon* d = (NetCon*)v;
771  hoc_return_type_code = 1;
772  if (d->src_) {
773  return (double)d->src_->gid_;
774  }
775  return -1.;
776 }
777 
778 static Object** nc_get_recordvec(void* v) {
779  NetCon* d = (NetCon*)v;
780  Object* ob = nil;
781  if (d->src_ && d->src_->tvec_) {
782  ob = d->src_->tvec_->obj_;
783  }
784  return hoc_temp_objptr(ob);
785 }
786 
787 static double nc_wcnt(void* v) {
788  NetCon* d = (NetCon*)v;
789  return d->cnt_;
790 }
791 
792 static Member_func members[] = {
793  "active", nc_active,
794  "valid", nc_valid,
795  "preloc", nc_preloc,
796  "postloc", nc_postloc,
797  "setpost", nc_setpost,
798  "event", nc_event,
799  "record", nc_record,
800  "srcgid", nc_srcgid,
801  "wcnt", nc_wcnt,
802  "delay", 0, // these four changed below
803  "weight", 0,
804  "threshold", 0,
805  "x", 0,
806  0, 0
807 };
808 
810  "syn", nc_syn,
811  "pre", nc_pre,
812  "precell", nc_precell,
813  "postcell", nc_postcell,
814  "preseg", nc_preseg,
815  "postseg", nc_postseg,
816  "prelist", nc_prelist,
817  "synlist", nc_synlist,
818  "precelllist", nc_precelllist,
819  "postcelllist", nc_postcelllist,
820  "get_recordvec", nc_get_recordvec,
821  0, 0
822 };
823 
824 static void steer_val(void* v) {
825  NetCon* d = (NetCon*)v;
826  Symbol* s = hoc_spop();
827  if (strcmp(s->name, "delay") == 0) {
828  d->chksrc();
829  hoc_pushpx(&d->delay_);
830  d->src_->use_min_delay_ = 0;
831  }else if (strcmp(s->name, "weight") == 0) {
832  int index = 0;
833  if (hoc_stacktype() == NUMBER) {
834  s->arayinfo->sub[0] = d->cnt_;
835  index = hoc_araypt(s, SYMBOL);
836  }
837  hoc_pushpx(d->weight_ + index);
838  }else if (strcmp(s->name, "x") == 0) {
839  static double dummy = 0.;
840  d->chksrc();
841  if (d->src_->thvar_) {
842  hoc_pushpx(d->src_->thvar_);
843  }else{
844  dummy = 0.;
845  hoc_pushpx(&dummy);
846  }
847  }else if (strcmp(s->name, "threshold") == 0) {
848  d->chksrc();
849  hoc_pushpx(&d->src_->threshold_);
850  }
851 }
852 
853 static void* cons(Object* o) {
854  NetCon* d;
855  if (!net_cvode_instance) {
856  hoc_execerror("CVode instance must exist", 0);
857  }
858  // source, target, threshold, delay, magnitude
859  Object* osrc = nil, *otar;
860  Section* srcsec = nil;
861  double* psrc = nil;
862  if (hoc_is_object_arg(1)) {
863  osrc = *hoc_objgetarg(1);
864  if (osrc && !is_point_process(osrc)) {
865  hoc_execerror("if arg 1 is an object it must be a point process or NULLObject", 0);
866  }
867  }else{
868  psrc = hoc_pgetarg(1);
869  srcsec = chk_access();
870  }
871  otar = *hoc_objgetarg(2);
872  if (otar && !is_point_process(otar)) {
873  hoc_execerror("arg 2 must be a point process or NULLobject", 0);
874  }
875  double thresh = -1.e9; // sentinal value. default is 10 if new PreSyn
876  double delay = 1.;
877  double weight = 0.;
878 
879  if (ifarg(3)) {
880  thresh = *getarg(3);
881  delay = chkarg(4, 0, 1e15);
882  weight = *getarg(5);
883  }
884  d = net_cvode_instance->install_deliver(psrc, srcsec, osrc, otar,
885  thresh, delay, weight);
886  d->obj_ = o;
887  return (void*)d;
888 }
889 
890 static void destruct(void* v) {
891  NetCon* d = (NetCon*)v;
892  delete d;
893 }
894 
895 void NetCon_reg() {
896  class2oc("NetCon", cons, destruct, members, NULL, omembers, NULL);
897  Symbol* nc = hoc_lookup("NetCon");
898  nc->u.ctemplate->steer = steer_val;
899  Symbol* s;
900  s = hoc_table_lookup("delay", nc->u.ctemplate->symtable);
901  s->type = VAR;
902  s->arayinfo = nil;
903  s = hoc_table_lookup("x", nc->u.ctemplate->symtable);
904  s->type = VAR;
905  s->arayinfo = nil;
906  s = hoc_table_lookup("threshold", nc->u.ctemplate->symtable);
907  s->type = VAR;
908  s->arayinfo = nil;
909  s = hoc_table_lookup("weight", nc->u.ctemplate->symtable);
910  s->type = VAR;
911  s->arayinfo = new Arrayinfo;
912  s->arayinfo->refcount = 1;
913  s->arayinfo->a_varn = nil;
914  s->arayinfo->nsub = 1;
915  s->arayinfo->sub[0] = 1;
916 }
917 
918 static char* escape_bracket(const char* s) {
919  static char* b;
920  const char* p1;
921  char* p2;
922  if (!b) {
923  b = new char[256];
924  }
925  for (p1 = s, p2 = b; *p1; ++p1, ++p2) {
926  switch (*p1) {
927  case '<':
928  *p2 = '[';
929  break;
930  case '>':
931  *p2 = ']';
932  break;
933  case '[':
934  case ']':
935  *p2 = '\\';
936  *(++p2) = *p1;
937  break;
938  default:
939  *p2 = *p1;
940  break;
941  }
942  }
943  *p2 = '\0';
944  return b;
945 }
946 
948  // interface to cvode.netconlist(precell, postcell, target, [list])
949  OcList* o;
950 
951  Object** po = newoclist(4, o);
952 
953  Object *opre = nil, *opost = nil, *otar = nil;
954  Regexp* spre = nil, *spost = nil, *star = nil;
955  char* s;
956  int n;
957 
958  if (hoc_is_object_arg(1)) {
959  opre = *hoc_objgetarg(1);
960  }else{
961  s = gargstr(1);
962  if (s[0] == '\0') {
963  spre = new Regexp(".*");
964  }else{
965  spre = new Regexp(escape_bracket(s));
966  }
967  if(!spre->pattern()) {
968  hoc_execerror(gargstr(1), "not a valid regular expression");
969  }
970  }
971  if (hoc_is_object_arg(2)) {
972  opost = *hoc_objgetarg(2);
973  }else{
974  s = gargstr(2);
975  if (s[0] == '\0') {
976  spost = new Regexp(".*");
977  }else{
978  spost = new Regexp(escape_bracket(s));
979  }
980  if(!spost->pattern()) {
981  hoc_execerror(gargstr(2), "not a valid regular expression");
982  }
983  }
984  if (hoc_is_object_arg(3)) {
985  otar = *hoc_objgetarg(3);
986  }else{
987  s = gargstr(3);
988  if (s[0] == '\0') {
989  star = new Regexp(".*");
990  }else{
991  star = new Regexp(escape_bracket(s));
992  }
993  if(!star->pattern()) {
994  hoc_execerror(gargstr(3), "not a valid regular expression");
995  }
996  }
997 
998  bool b;
999  hoc_Item* q;
1000  if (psl_) ITERATE(q, psl_) {
1001  PreSyn* ps = (PreSyn*)VOIDITM(q);
1002  b = false;
1003  if (ps->ssrc_) {
1004  Object* precell = nrn_sec2cell(ps->ssrc_);
1005  if (opre) {
1006  if (precell == opre) {
1007  b = true;
1008  }else{
1009  b = false;
1010  }
1011  }else{
1012  s = hoc_object_name(precell);
1013  n = strlen(s);
1014  if (spre->Match(s, n, 0) > 0) {
1015  b = true;
1016  }else{
1017  b = false;
1018  }
1019  }
1020  }else if (ps->osrc_) {
1021  Object* presyn = ps->osrc_;
1022  if (opre) {
1023  if (presyn == opre) {
1024  b = true;
1025  }else{
1026  b = false;
1027  }
1028  }else{
1029  s = hoc_object_name(presyn);
1030  n = strlen(s);
1031  if (spre->Match(s, n, 0) > 0) {
1032  b = true;
1033  }else{
1034  b = false;
1035  }
1036  }
1037  }
1038  if (b == true) {
1039  const NetConPList& dil = ps->dil_;
1040  for (const auto& d : dil) {
1041  Object* postcell = nil;
1042  Object* target = nil;
1043  if (d->target_) {
1044  Point_process* p = d->target_;
1045  target = p->ob;
1046  if (p->sec) {
1047  postcell = nrn_sec2cell(p->sec);
1048  }
1049  }
1050  if (opost) {
1051  if (postcell == opost) {
1052  b = true;
1053  }else{
1054  b = false;
1055  }
1056  }else{
1057  s = hoc_object_name(postcell);
1058  n = strlen(s);
1059  if (spost->Match(s, n, 0) > 0) {
1060  b = true;
1061  }else{
1062  b = false;
1063  }
1064  }
1065  if (b == true) {
1066  if (otar) {
1067  if (target == otar) {
1068  b = true;
1069  }else{
1070  b = false;
1071  }
1072  }else{
1073  s = hoc_object_name(target);
1074  n = strlen(s);
1075  if (star->Match(s, n, 0) > 0) {
1076  b = true;
1077  }else{
1078  b = false;
1079  }
1080  }
1081  if (b == true) {
1082  o->append(d->obj_);
1083  }
1084  }
1085  }
1086  }
1087  }
1088  if (spre) delete spre;
1089  if (spost) delete spost;
1090  if (star) delete star;
1091  return po;
1092 }
1093 
1094 #define ITE_SIZE 10
1096  tpool_ = new TQItemPool(1000, 1);
1097  // tqe_ accessed only by thread i so no locking
1098  tqe_ = new TQueue(tpool_, 0);
1099  sepool_ = new SelfEventPool(1000,1);
1100  selfqueue_ = nil;
1101  psl_thr_ = nil;
1102  tq_ = nil;
1103  lcv_ = nil;
1104  ite_size_ = ITE_SIZE;
1105  ite_cnt_ = 0;
1106  unreffed_event_cnt_ = 0;
1107  immediate_deliver_ = -1e100;
1108  inter_thread_events_ = new InterThreadEvent[ite_size_];
1109  nlcv_ = 0;
1110  MUTCONSTRUCT(1)
1111 }
1112 
1114  delete [] inter_thread_events_;
1115  if (psl_thr_) { hoc_l_freelist(&psl_thr_); }
1116  if (tq_) { delete tq_; }
1117  delete tqe_;
1118  delete tpool_;
1119  if (selfqueue_) {
1120  selfqueue_->remove_all();
1121  delete selfqueue_;
1122  }
1123  delete sepool_;
1124  if (lcv_) {
1125  for (int i=0; i < nlcv_; ++i) {
1126  net_cvode_instance->delete_list(lcv_ + i);
1127  }
1128  delete [] lcv_;
1129  }
1130  MUTDESTRUCT
1131 }
1132 
1134  //bin_event(td, db, nt);
1135  MUTLOCK
1136 #if PRINT_EVENT
1137 if (net_cvode_instance->print_event_) {
1138 Printf("interthread send td=%.15g DE type=%d thread=%d target=%d %s\n",
1139 td, db->type(), nt->id, (db->type() == 2) ? PP2NT(((NetCon*)db)->target_)->id:-1,
1140 (db->type() == 2) ? hoc_object_name(((NetCon*)(db))->target_->ob):"?");
1141 }
1142 #endif
1143  if(ite_cnt_ >= ite_size_) {
1144  ite_size_ *= 2;
1145  InterThreadEvent* in = new InterThreadEvent[ite_size_];
1146  for (int i=0; i < ite_cnt_; ++i) {
1147  in[i].de_ = inter_thread_events_[i].de_;
1148  in[i].t_ = inter_thread_events_[i].t_;
1149  }
1150  delete [] inter_thread_events_;
1151  inter_thread_events_ = in;
1152  }
1153  InterThreadEvent& ite = inter_thread_events_[ite_cnt_++];
1154  ite.de_ = db;
1155  ite.t_ = td;
1156  // race since each NetCvodeThreadData has its own lock and enqueueing_
1157  // is a NetCvode instance variable. enqueuing_ is not logically
1158  // needed but can avoid a nrn_multithread_job call in allthread_least_t
1159  // which does nothing if there are no interthread events.
1160  //int& b = net_cvode_instance->enqueueing_;
1161  //if (!b) { b = 1; }
1162  MUTUNLOCK
1163  // have decided to lock net_cvode_instance and set it
1164  net_cvode_instance->set_enqueueing();
1165 }
1166 
1168  int i;
1169  MUTLOCK
1170  for (i = 0; i < ite_cnt_; ++i) {
1171  InterThreadEvent& ite = inter_thread_events_[i];
1172 #if PRINT_EVENT
1173 if (net_cvode_instance->print_event_) {
1174 Printf("interthread enqueue td=%.15g DE type=%d thread=%d target=%d %s\n",
1175 ite.t_, ite.de_->type(), nt->id, (ite.de_->type() == 2) ? PP2NT(((NetCon*)(ite.de_))->target_)->id:-1,
1176 (ite.de_->type() == 2) ? hoc_object_name(((NetCon*)(ite.de_))->target_->ob):"?");
1177 }
1178 #endif
1179  nc->bin_event(ite.t_, ite.de_, nt);
1180  }
1181  ite_cnt_ = 0;
1182  MUTUNLOCK
1183 }
1184 
1185 NetCvode::NetCvode(bool single) {
1186  use_long_double_ = 0;
1187  empty_ = true; // no equations (only artificial cells).
1188  MUTCONSTRUCT(0);
1189  maxorder_ = 5;
1190  maxstep_ = 1e9;
1191  minstep_ = 0.;
1192  rtol_ = 0.;
1193  atol_ = 1e-3;
1194  jacobian_ = 0;
1195  stiff_ = 2;
1196  mst_ = nil;
1197  condition_order_ = 1;
1198  null_event_ = new DiscreteEvent();
1199  tstop_event_ = new TstopEvent();
1200  eps_ = 100.*UNIT_ROUNDOFF;
1201  hdp_ = nil;
1202  print_event_ = 0;
1203  nrn_use_fifo_queue_ = false;
1204  single_ = single;
1205  nrn_use_daspk_ = false;
1206  gcv_ = nil;
1207  allthread_hocevents_ = new HocEventList();
1208  pcnt_ = 0;
1209  p = nil;
1210  p_construct(1);
1211  // eventually these should not have to be thread safe
1212  pst_ = nil;
1213  pst_cnt_ = 0;
1214  psl_ = nil;
1215  // for parallel network simulations hardly any presyns have
1216  // a threshold and it can be very inefficient to check the entire
1217  // presyn list for thresholds during the fixed step method.
1218  // So keep a threshold list.
1219  unused_presyn = nil;
1220  structure_change_cnt_ = -1;
1221  fornetcon_change_cnt_ = -2;
1222  matrix_change_cnt_ = -1;
1223  playrec_change_cnt_ = 0;
1224  alloc_list();
1225  prl_ = new PlayRecList(10);
1226  fixed_play_ = new PlayRecList(10);
1227  fixed_record_ = new PlayRecList(10);
1228  vec_event_store_ = nil;
1229  if (!record_init_items_) {
1230  record_init_items_ = new TQList();
1231  }
1232 // re_init(t);
1233 }
1234 
1236  MUTDESTRUCT
1237  if (net_cvode_instance == (NetCvode*)this) {
1238  net_cvode_instance = nil;
1239  }
1240  if (hdp_) {
1241  hdp_ = nil;
1242  }
1243  delete_list();
1244  p_construct(0);
1245  if (mst_) {
1246  // and should also iterate and delete the MaxStateItem
1247  delete mst_;
1248  }
1249  if (psl_) {
1250  hoc_Item* q;
1251  ITERATE(q, psl_) {
1252  PreSyn* ps = (PreSyn*)VOIDITM(q);
1253  for (auto it = ps->dil_.rbegin(); it != ps->dil_.rend(); ++it) {
1254  NetCon* d = *it;
1255  d->src_ = nil;
1256  delete d;
1257  }
1258  delete ps;
1259  }
1260  hoc_l_freelist(&psl_);
1261  }
1262  if (pst_) {
1263  delete pst_;
1264  }
1265  delete fixed_play_;
1266  delete fixed_record_;
1267  while(prl_->count()) {
1268  delete prl_->item(prl_->count()-1);
1269  }
1270  delete prl_;
1271  unused_presyn = nil;
1272  wl_list_.clear();
1273  delete allthread_hocevents_;
1274 }
1275 
1277  return !single_;
1278 }
1279 
1280 bool NetCvode::is_local() { return (cvode_active_ && localstep()); }
1281 
1282 void NetCvode::localstep(bool b) {
1283  // due to possibility of gap junctions and until the complete matrix
1284  // is analysed for block structure localstep and daspk are incompatible
1285  b = (nrn_modeltype() == 1 ? b : false); // localstep doesn't work yet with DAE's
1286 
1287  if (!b != single_) {
1288  delete_list();
1289  single_ = !b;
1290  structure_change_cnt_ = 0;
1291  use_sparse13 = 0;
1292  nrn_use_daspk_ = false;
1293  re_init(nt_t);
1294  }
1295 }
1296 
1298  return (gcv_ != 0) ? gcv_->use_daspk_ : false;
1299 }
1300 
1301 void NetCvode::use_daspk(bool b) {
1302  b = (nrn_modeltype() == 2 ? true : b); // not optional if algebraic
1303  if (gcv_ && b != gcv_->use_daspk_) {
1304  delete_list();
1305  single_ = (b ? true : single_);
1306  structure_change_cnt_ = 0;
1307  nrn_use_daspk_ = b;
1308 //printf("NetCvode::use_daspk nrn_use_daspk=%d\n", nrn_use_daspk_);
1309  if (use_sparse13 != nrn_use_daspk_) {
1311  diam_changed = 1;
1312  }
1313  re_init(nt_t);
1314  }
1315 }
1316 
1317 BAMechList::BAMechList(BAMechList** first) { // preserve the list order
1318  next = nil;
1319  BAMechList* last;
1320  if (*first) {
1321  for (last = *first; last->next; last = last->next){}
1322  last->next = this;
1323  }else{
1324  *first = this;
1325  }
1326 }
1327 
1329  BAMechList* b, *bn;
1330  for (b = *first; b; b = bn) {
1331  bn = b->next;
1332  delete b;
1333  }
1334  *first = nil;
1335 }
1336 
1338  no_cap_count_ = 0;
1339  no_cap_child_count_ = 0;
1340  no_cap_node_ = nil;
1341  no_cap_child_ = nil;
1342  cv_memb_list_ = nil;
1343  cmlcap_ = nil;
1344  cmlext_ = nil;
1345  no_cap_memb_ = nil;
1346  before_breakpoint_ = nil;
1347  after_solve_ = nil;
1348  before_step_ = nil;
1349  rootnodecount_ = 0;
1350  v_node_count_ = 0;
1351  v_node_ = nil;
1352  v_parent_ = nil;
1353  psl_th_ = nil;
1354  watch_list_ = nil;
1355  pv_ = nil;
1356  pvdot_ = nil;
1357  nvoffset_ = 0;
1358  nvsize_ = 0;
1359  neq_v_ = nonvint_offset_ = 0;
1360  nonvint_extra_offset_ = 0;
1361  record_ = nil;
1362  play_ = nil;
1363 }
1365  if (no_cap_memb_) {
1366  delete_memb_list(no_cap_memb_);
1367  }
1368  if (pv_) {
1369  delete [] pv_;
1370  delete [] pvdot_;
1371  }
1372  if (no_cap_node_) {
1373  delete [] no_cap_node_;
1374  delete [] no_cap_child_;
1375  }
1376  if (watch_list_) {
1377  watch_list_->RemoveAll();
1378  delete watch_list_;
1379  }
1380 }
1381 
1383  int i, j;
1384  wl_list_.clear();
1385  wl_list_.resize(nrn_nthread);
1386  if (gcv_) {
1387  delete_list(gcv_);
1388  delete gcv_;
1389  gcv_ = nil;
1390  }
1391  for (i = 0; i < pcnt_; ++i) {
1392  NetCvodeThreadData& d = p[i];
1393  if (d.lcv_) {
1394  for (j = 0; j < d.nlcv_; ++j) {
1395  delete_list(d.lcv_ + j);
1396  }
1397  delete [] d.lcv_;
1398  d.lcv_ = nil;
1399  d.nlcv_ = 0;
1400  }
1401  if (d.tq_) {
1402  delete d.tq_;
1403  d.tq_ = nil;
1404  }
1405  }
1406  empty_ = true;
1407 }
1408 
1410  del_cv_memb_list(cvode);
1411  Cvode& cv = *cvode;
1412  cv.delete_prl();
1413  delete [] cv.ctd_;
1414  cv.ctd_ = nil;
1415 }
1416 
1418  if (gcv_) { del_cv_memb_list(gcv_); }
1419  for (int i = 0; i < pcnt_; ++i) {
1420  NetCvodeThreadData& d = p[i];
1421  for (int j = 0; j < d.nlcv_; ++j) {
1422  del_cv_memb_list(d.lcv_ + j);
1423  }
1424  }
1425 }
1427  int i, j;
1428  if (!cvode) { return; }
1429  Cvode& cv = *cvode;
1430  for (j=0; j < cv.nctd_; ++j) {
1431  CvodeThreadData& z = cv.ctd_[j];
1432  if (z.psl_th_) {
1433  z.psl_th_->remove_all();
1434  delete z.psl_th_;
1435  z.psl_th_ = nil;
1436  }
1437  if (cvode != gcv_) {
1438  if (z.v_node_) {
1439  delete [] z.v_node_;
1440  delete [] z.v_parent_;
1441  z.v_node_ = nil;
1442  z.v_parent_ = nil;
1443  }
1445  }else{
1446  CvMembList* cml, *cmlnext;
1447  for (cml = z.cv_memb_list_; cml; cml = cmlnext) {
1448  cmlnext = cml->next;
1449  delete cml;
1450  }
1451  }
1452  z.cv_memb_list_ = nil;
1456  }
1457 }
1458 
1460  index = -1;
1461  ml = new Memb_list;
1462 }
1464  delete ml;
1465 }
1466 
1468  CvMembList* cml, *cmlnext;
1469  for (cml = cmlist; cml; cml = cmlnext) {
1470  Memb_list* ml = cml->ml;
1471  cmlnext = cml->next;
1472  delete [] ml->nodelist;
1473 #if CACHEVEC
1474  if (ml->nodeindices) {
1475  delete [] ml->nodeindices;
1476  }
1477 #endif
1478  if (memb_func[cml->index].hoc_mech) {
1479  delete [] ml->prop;
1480  }else{
1481  delete [] ml->data;
1482  delete [] ml->pdata;
1483  }
1484  delete cml;
1485  }
1486 }
1487 
1488 void NetCvode::distribute_dinfo(int* cellnum, int tid) {
1489  int i, j;
1490 //printf("distribute_dinfo %d\n", pst_cnt_);
1491  if (psl_) {
1492  hoc_Item* q;
1493  ITERATE(q, psl_) {
1494  PreSyn* ps = (PreSyn*)VOIDITM(q);
1495 //printf("\tPreSyn %s\n", ps->osrc_ ? hoc_object_name(ps->osrc_):secname(ps->ssrc_));
1496  if (ps->thvar_) { // artcells and presyns for gid's not on this cpu have no threshold check
1497  NrnThread* nt;
1498  Cvode* cvsrc;
1499  CvodeThreadData* z;
1500  // cvode instances poll which presyns
1501  if (single_) {
1502  if (ps->osrc_) {
1503  nt = (NrnThread*)ob2pntproc(ps->osrc_)->_vnt;
1504  }else if (ps->ssrc_) {
1505  nt = ps->ssrc_->pnode[0]->_nt;
1506  }else{
1507  nt = nrn_threads;
1508  }
1509  cvsrc = gcv_;
1510  z = cvsrc->ctd_ + nt->id;
1511  if (!z->psl_th_) {
1512  z->psl_th_ = new PreSynList(pst_cnt_);
1513  }
1514  z->psl_th_->append(ps);
1515  }else{
1516 
1517  if (ps->osrc_) {
1518  j = node(ps->osrc_)->v_node_index;
1519  nt = (NrnThread*)ob2pntproc(ps->osrc_)->_vnt;
1520  }else if (ps->ssrc_) {
1521  j = ps->ssrc_->pnode[0]->v_node_index;
1522  nt = ps->ssrc_->pnode[0]->_nt;
1523  }else{
1524  j = 0;
1525  nt = nrn_threads;
1526  }
1527  if (tid == nt->id) {
1528  cvsrc = p[tid].lcv_ + cellnum[j];
1529  z = cvsrc->ctd_;
1530  if (nt == cvsrc->nth_) {
1531  if (!z->psl_th_) {
1532  z->psl_th_ = new PreSynList(1);
1533  }
1534  z->psl_th_->append(ps);
1535  }
1536  }
1537  }
1538  }
1539  }
1540  }
1541 }
1542 
1544  int i;
1545  set_CVRhsFn();
1546  wl_list_.clear();
1547  wl_list_.resize(nrn_nthread);
1548  if (single_) {
1549  gcv_ = new Cvode();
1550  Cvode& cv = *gcv_;
1551  cv.ncv_ = this;
1552  cv.nctd_ = nrn_nthread;
1553  cv.ctd_ = new CvodeThreadData[cv.nctd_];
1554  }else{
1555  for (int id=0; id < nrn_nthread; ++id) {
1556  NrnThread& nt = nrn_threads[id];
1557  NetCvodeThreadData& d = p[id];
1558  d.nlcv_ = nt.ncell;
1559  d.lcv_ = new Cvode[d.nlcv_];
1560  d.tq_ = new TQueue(d.tpool_);
1561  for (i=0; i < d.nlcv_; ++i) {
1562  TQItem* ti = d.tq_->insert(0., d.lcv_+i);
1563  d.lcv_[i].tqitem_ = ti;
1564  Cvode& cv = d.lcv_[i];
1565  cv.nth_ = &nt;
1566  cv.ncv_ = this;
1567  cv.nctd_ = 1;
1568  cv.ctd_ = new CvodeThreadData[cv.nctd_];
1569  }
1570  }
1571  }
1572  empty_ = false;
1573 #if USENEOSIM
1574  if (p_nrn2neosim_send) for (i=0; i < nlist_; ++i) {
1575  p.lcv_[i].neosim_self_events_ = new TQueue();
1576  }
1577 #endif
1578 }
1579 
1581  int i;
1582  CvMembList* cml;
1583  if (tree_changed) { setup_topology(); }
1585  if (structure_change_cnt_ == structure_change_cnt) {
1586  return false;
1587  }
1588  if (diam_changed) { // need to guarantee that the matrix is allocated
1589  recalc_diam(); // for the present method
1590  }
1591  structure_change_cnt_ = structure_change_cnt;
1592  matrix_change_cnt_ = -1;
1593  playrec_change_cnt_ = 0;
1594  if (hdp_) {
1595  delete hdp_;
1596  hdp_ = nil;
1597  }
1598  NrnThread* _nt;
1599  if (single_) {
1600  if (!gcv_ || gcv_->nctd_ != nrn_nthread) {
1601  delete_list();
1602  alloc_list();
1603  }
1604  del_cv_memb_list();
1605  Cvode& cv = *gcv_;
1606  distribute_dinfo(nil, 0);
1607  FOR_THREADS(_nt) {
1608  CvodeThreadData& z = cv.ctd_[_nt->id];
1609  z.rootnodecount_ = _nt->ncell;
1610  z.v_node_count_ = _nt->end;
1611  z.v_node_ = _nt->_v_node;
1612  z.v_parent_ = _nt->_v_parent;
1613 
1614  CvMembList* last = 0;
1615  for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next) {
1616  i = tml->index;
1617  Memb_func* mf = memb_func + i;
1618  Memb_list* ml = tml->ml;
1619  if (ml->nodecount
1620  && (i == CAP
1621  || mf->current || mf->ode_count || mf->ode_matsol
1622  || mf->ode_spec || mf->state )
1623  ) {
1624  // maintain same order (not reversed) for
1625  // singly linked list built below
1626  cml = new CvMembList;
1627  if (!z.cv_memb_list_) {
1628  z.cv_memb_list_ = cml;
1629  }else{
1630  last->next = cml;
1631  }
1632  last = cml;
1633  cml->next = nil;
1634  cml->index = i;
1635  cml->ml->nodecount = ml->nodecount;
1636  // assumes cell info grouped contiguously
1637  cml->ml->nodelist = ml->nodelist;
1638 #if CACHEVEC
1639  cml->ml->nodeindices = ml->nodeindices;
1640 #endif
1641  if (mf->hoc_mech) {
1642  cml->ml->prop = ml->prop;
1643  }else{
1644  cml->ml->data = ml->data;
1645  cml->ml->pdata = ml->pdata;
1646  }
1647  cml->ml->_thread = ml->_thread;
1648  }
1649  }
1650  fill_global_ba(_nt, BEFORE_BREAKPOINT, &z.before_breakpoint_);
1651  fill_global_ba(_nt, AFTER_SOLVE, &z.after_solve_);
1652  fill_global_ba(_nt, BEFORE_STEP, &z.before_step_);
1653  // Every point process, but not artificial cells, cause at least a retreat.
1654  // All point processes, but not artificial cells,
1655  // have the global cvode as its nvi field
1656  for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next) {
1657  i = tml->index;
1658  Memb_func* mf = memb_func + i;
1659  if (mf->is_point && !nrn_is_artificial_[i]) {
1660  Memb_list* ml = tml->ml;
1661  int j;
1662  for (j = 0; j < ml->nodecount; ++j) {
1663  Point_process* pp;
1664  if (mf->hoc_mech) {
1665  pp = (Point_process*)ml->prop[j]->dparam[1]._pvoid;
1666  }else{
1667  pp = (Point_process*)ml->pdata[j][1]._pvoid;
1668  }
1669  pp->nvi_ = gcv_;
1670  }
1671  }
1672  }
1673  }
1674  }else{ // lvardt
1675  bool b = false;
1676  if (gcv_) { b = true; }
1677  if (!b) for (i=0; i < pcnt_; ++i) {
1678  if (p[i].nlcv_ != nrn_threads[i].ncell) {
1679  b = true;
1680  }
1681  }
1682  if(b) {
1683  delete_list();
1684  alloc_list();
1685  }
1686  del_cv_memb_list();
1687  // each node has a cell number
1688  for (int id = 0; id < nrn_nthread; ++id) {
1689  NrnThread* _nt = nrn_threads + id;
1690  NetCvodeThreadData& d = p[id];
1691  if (_nt->end == 0) { continue; }
1692  int* cellnum = new int[_nt->end];
1693  for (i=0; i < _nt->ncell; ++i) {
1694  cellnum[i] = i;
1695  }
1696  for (i=_nt->ncell; i < _nt->end; ++i) {
1697  cellnum[i] = cellnum[_nt->_v_parent[i]->v_node_index];
1698  }
1699 
1700  for (i=0; i < _nt->ncell; ++i) {
1701  d.lcv_[i].ctd_[0].v_node_count_ = 0;
1702  }
1703  for (i=0; i < _nt->end; ++i) {
1704  ++d.lcv_[cellnum[i]].ctd_[0].v_node_count_;
1705  }
1706  for (i=0; i < _nt->ncell; ++i) {
1707  d.lcv_[cellnum[i]].ctd_[0].v_node_ = new Node*[d.lcv_[cellnum[i]].ctd_[0].v_node_count_];
1708  d.lcv_[cellnum[i]].ctd_[0].v_parent_ = new Node*[d.lcv_[cellnum[i]].ctd_[0].v_node_count_];
1709  }
1710  for (i=0; i < _nt->ncell; ++i) {
1711  d.lcv_[i].ctd_[0].v_node_count_ = 0;
1712  d.lcv_[i].ctd_[0].rootnodecount_ = 1;
1713  }
1714  for (i=0; i < _nt->end; ++i) {
1715  d.lcv_[cellnum[i]].ctd_[0].v_node_[d.lcv_[cellnum[i]].ctd_[0].v_node_count_] = _nt->_v_node[i];
1716  d.lcv_[cellnum[i]].ctd_[0].v_parent_[d.lcv_[cellnum[i]].ctd_[0].v_node_count_++] = _nt->_v_parent[i];
1717  }
1718  // divide the memb_list info into per cell info
1719  // count
1720  CvMembList** last = new CvMembList*[_nt->ncell];
1721  for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next) {
1722  i = tml->index;
1723  Memb_func* mf = memb_func + i;
1724  Memb_list* ml = tml->ml;
1725  if (ml->nodecount
1726  && (mf->current || mf->ode_count || mf->ode_matsol
1727  || mf->ode_spec || mf->state || i == CAP)
1728  ) {
1729  // maintain same order (not reversed) for
1730  // singly linked list built below
1731  int j;
1732  for (j = 0; j < ml->nodecount; ++j) {
1733  int inode = ml->nodelist[j]->v_node_index;
1734  Cvode& cv = d.lcv_[cellnum[inode]];
1735  CvodeThreadData& z = cv.ctd_[0];
1736  if (!z.cv_memb_list_) {
1737  cml = new CvMembList;
1738  cml->next = nil;
1739  cml->index = i;
1740  cml->ml->nodecount = 0;
1741  z.cv_memb_list_ = cml;
1742  last[cellnum[inode]] = cml;
1743  }
1744  if (last[cellnum[inode]]->index == i) {
1745  ++last[cellnum[inode]]->ml->nodecount;
1746  }else{
1747  cml = new CvMembList;
1748  last[cellnum[inode]]->next = cml;
1749  cml->next = nil;
1750  last[cellnum[inode]] = cml;
1751  cml->index = i;
1752  cml->ml->nodecount = 1;
1753  }
1754  }
1755  }
1756  }
1757  delete [] last;
1758  // allocate and re-initialize count
1759  CvMembList** cvml = new CvMembList*[d.nlcv_];
1760  for (i=0; i < d.nlcv_; ++i) {
1761  cvml[i] = d.lcv_[i].ctd_[0].cv_memb_list_;
1762  for (cml = cvml[i]; cml; cml = cml->next) {
1763  Memb_list* ml = cml->ml;
1764  ml->nodelist = new Node*[ml->nodecount];
1765 #if CACHEVEC
1766  ml->nodeindices = new int[ml->nodecount];
1767 #endif
1768  if (memb_func[cml->index].hoc_mech) {
1769  ml->prop = new Prop*[ml->nodecount];
1770  }else{
1771  ml->data = new double*[ml->nodecount];
1772  ml->pdata = new Datum*[ml->nodecount];
1773  }
1774  ml->nodecount = 0;
1775  }
1776  }
1777  // fill pointers (and nodecount)
1778  // now list order is from 0 to n_memb_func
1779  for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next) {
1780  i = tml->index;
1781  Memb_func* mf = memb_func + i;
1782  Memb_list* ml = tml->ml;
1783  if (ml->nodecount
1784  && (mf->current || mf->ode_count || mf->ode_matsol
1785  || mf->ode_spec || mf->state || i == CAP)
1786  ) {
1787  int j;
1788  for (j = 0; j < ml->nodecount; ++j) {
1789  int icell = cellnum[ml->nodelist[j]->v_node_index];
1790  Cvode& cv = d.lcv_[icell];
1791  CvodeThreadData& z = cv.ctd_[0];
1792  if (cvml[icell]->index != i) {
1793  cvml[icell] = cvml[icell]->next;
1794  assert (cvml[icell] && cvml[icell]->index);
1795  }
1796  cml = cvml[icell];
1797  cml->ml->nodelist[cml->ml->nodecount] = ml->nodelist[j];
1798 #if CACHEVEC
1799  cml->ml->nodeindices[cml->ml->nodecount] = ml->nodeindices[j];
1800 #endif
1801  if (mf->hoc_mech) {
1802  cml->ml->prop[cml->ml->nodecount] = ml->prop[j];
1803  }else{
1804  cml->ml->data[cml->ml->nodecount] = ml->data[j];
1805  cml->ml->pdata[cml->ml->nodecount] = ml->pdata[j];
1806  }
1807  cml->ml->_thread = ml->_thread;
1808  ++cml->ml->nodecount;
1809  }
1810  }
1811  }
1812  // do the above for the BEFORE/AFTER functions
1813  fill_local_ba(cellnum, d);
1814 
1815  distribute_dinfo(cellnum, id);
1816  // If a point process is not an artificial cell, fill its nvi_ field.
1817  // artifical cells have no integrator
1818  for (NrnThreadMembList* tml = _nt->tml; tml; tml = tml->next) {
1819  i = tml->index;
1820  Memb_func* mf = memb_func + i;
1821  if (mf->is_point) {
1822  Memb_list* ml = tml->ml;
1823  int j;
1824  for (j = 0; j < ml->nodecount; ++j) {
1825  Point_process* pp;
1826  if (mf->hoc_mech) {
1827  pp = (Point_process*)ml->prop[j]->dparam[1]._pvoid;
1828  }else{
1829  pp = (Point_process*)ml->pdata[j][1]._pvoid;
1830  }
1831  if (nrn_is_artificial_[i] == 0) {
1832  int inode = ml->nodelist[j]->v_node_index;
1833  pp->nvi_ = d.lcv_ + cellnum[inode];
1834  }else{
1835  pp->nvi_ = nil;
1836  }
1837  }
1838  }
1839  }
1840  delete [] cellnum;
1841  delete [] cvml;
1842  }
1843  }
1844  return true;
1845 }
1846 
1847 void NetCvode::fill_global_ba(NrnThread* nt, int bat, BAMechList** baml) {
1848  NrnThreadBAList* tbl;
1849  for (tbl = nt->tbl[bat]; tbl; tbl = tbl->next) {
1850  BAMechList* ba = new BAMechList(baml);
1851  ba->bam = tbl->bam;
1852  ba->ml = tbl->ml;
1853  }
1854 }
1855 
1857  fill_local_ba_cnt(BEFORE_BREAKPOINT, celnum, d);
1858  fill_local_ba_cnt(AFTER_SOLVE, celnum, d);
1859  fill_local_ba_cnt(BEFORE_STEP, celnum, d);
1860 }
1861 
1862 void NetCvode::fill_local_ba_cnt(int bat, int* celnum, NetCvodeThreadData& d) {
1863  BAMech* bam;
1864  for (bam = bamech_[bat]; bam; bam = bam->next) {
1865  for (int icv = 0; icv < d.nlcv_; ++icv) {
1866  Cvode* cv = d.lcv_ + icv;
1867  assert(cv->nctd_ == 1);
1868  for (CvMembList* cml = cv->ctd_[0].cv_memb_list_; cml; cml = cml->next) {
1869  if (cml->index == bam->type) {
1870  Memb_list* ml = cml->ml;
1871  BAMechList* bl = cvbml(bat, bam, cv);
1872  bl->bam = bam;
1873  bl->ml = ml;
1874  }
1875  }
1876  }
1877  }
1878 }
1879 
1880 BAMechList* NetCvode::cvbml(int bat, BAMech* bam, Cvode* cv) {
1881  BAMechList** pbml;
1882  BAMechList* ba;
1883  if (bat == BEFORE_BREAKPOINT) {
1884  pbml = &cv->ctd_->before_breakpoint_;
1885  }else if (bat == AFTER_SOLVE) {
1886  pbml = &cv->ctd_->after_solve_;
1887  }else{
1888  pbml = &cv->ctd_->before_step_;
1889  }
1890  if (!*pbml) {
1891  ba = new BAMechList(pbml);
1892  }else{
1893  for (ba = *pbml; ba; ba = ba->next) {
1894  if (ba->bam->type == bam->type) {
1895  return ba;
1896  }
1897  }
1898  ba = new BAMechList(pbml);
1899  }
1900  ba->bam = bam;
1901  return ba;
1902 }
1903 
1904 /*
1905 The path through NetCvode::solve path is determined by the case dimensions of
1906 (single step, integrate to tout) and (no model, global dt, localdt).
1907 For threads there is one more constraint--- do not allow t0_ to pass
1908 by the minimum interthread netcon delay integration interval barrier
1909 without making sure all the interthread events to be delivered before
1910 that barrier are on the thread queue. For classical mpi spike exchange
1911 this was ensured by a NetParEvent which provided a synchronization barrier.
1912 We generalized this to a NetParEvent per thread and a thread barrier but
1913 there was a consequent loss of the possibility of sequential threads since
1914 in that context a barrier makes no sense (each job must run to completion).
1915 Hence the desire to avoid barriers and handle the interval barrier explicity
1916 here to make sure NetCvode::enqueue is called frequently enough.
1917 (Actually, it is called very frequently since it is called by deliver_events,
1918 so it is only required that the interval between the least and greatest
1919 integrator t0_ be less than the maximum).
1920 
1921 Without a thread barrier in NetParEvent,
1922 this mostly affects the "integrate to tout" case. But it also affects
1923 the single step case in that we are not allowed to handle any
1924 events with delivery time > barrier time. Since a microstep does the
1925 earliest next thing, we need to check that before the call.
1926 
1927 Can we deal with multisplit conveniently without a thread barrier.
1928 Yes if we split up the process into its three phases of triangularization,
1929 reduced tree solve, back substitution. No if we retain a single
1930 integration step quantum for the thread.
1931 Without barriers, we end up with finer and finer grain nrn_multithread_job.
1932 
1933 It is sounding more and more reasonable to sacrifice the debugging convenience
1934 of sequential threads in favor of allowing thread barriers.
1935 ...but... a look at the nrn_fixed_step and nrn_multisplit_solve shows
1936 that it would certainly be easy to split into the proper
1937 nrn_multithread_job groups since it is already functionally decomposed
1938 in that way. And we may want to limit NetParEvent to serve only as
1939 interprocessor spike exchange signals for the main thread.
1940 ...but... a look at cvode in a multisplit context
1941 means there must be one global cvode instance
1942 and when f and jacob is called it would divide there and do the scatter
1943 gather etc. Of course, with separate cvode instances with multisplit we
1944 still have to have a proper Vector library which does the corresponding
1945 mpi reduce functions. Conceptually much simpler with barrier and maybe
1946 impossible without. If we went with one global cvode it would be
1947 possible. And cvode overhead seems independent of number of equations
1948 so confining it to the main thread may not be bad.
1949 
1950 The principle multithread domain we design for below is the few event,
1951 multisplit case. That is, there is one cvode instance managed by thread 0
1952 and all events go onto one queue. However, an event is delivered according
1953 to its proper delivery thread. Note that the possiblity of 0 delay
1954 events is allowed. There is nothing that can be done at the minimum
1955 delay integration interval level since each step divides into a dozen or so
1956 multithread jobs.
1957 
1958 Threads and lvardt.
1959 Consider the global cv (used to be p.lcv_[0]) as gcv_ which has ctd[nrn_nthread]
1960 instances of separate CvodeThreadData and works with multisplit.
1961 Now consider the lvardt method (used to be supported by p.lcv_[i]) as
1962 NetCvodeThreadData instances of lcv_[i] and of course move tq_ into
1963 the NetCvodeThreadData. Then each of the p.lcv_[i] would have Cvode.nctd_
1964 equal 1 in which p.lcv_[i].ctd_[0] is the proper CvodeThreadData. Then
1965 Cvode would never look at nrn_nthread to determine the CvodeThreadData
1966 but only the Cvode.nctd_. And if Cvode.nctd_ > 1 which would be
1967 possible only for gcv_, only then would nt->id be used to get the proper
1968 CvodeThreadData. We presume for now that if lvardt is used with nrn_nthread > 1
1969 then the usual minimum delay interval requirements hold for interthread
1970 events.
1971 
1972 Inter-Thread-Events (possibility of 0 delay).
1973 
1974 The fixed step method is that for each step, the sequence of actions
1975 for each thread is:
1976 1) at time tbegin: check thresholds, if source and target on same thread
1977  put directly onto queue. If different threads (PreSyn only), do an
1978  interthread send which puts the event into the target thread
1979  inter_thread_events list. Finally we deliver all events up to tbegin+.5dt,
1980  this first transfers all the threads inter-thread-events onto the queue.
1981 2) at time tbegin + .5dt: v(tbegin) -> v(tend)
1982 3) at time tend: integrate states one step using v(tend)
1983 4) deliver events up to but not past tend (first transfers inter-thread-events
1984  onto queue).
1985 Therefore, a zero-delay inter-thread-event from an artificial cell
1986 generated in step 4 may or may not be delivered
1987 in the time step it is generated. And zero-delay threshold detection interthread
1988 events will be delivered in the time step but either in step 1 or step 4 (ie.
1989 beginning or end of the time step). For this reason, if there are zero-delay
1990 NetCon, then both the source and target should be on the same thread. In practice
1991 we should force them onto thread 0 or at least the source onto the
1992 target thread.
1993 
1994 What about cvode?
1995 Global variable time step method.
1996 As mentioned above, all events, when global cvode active, go onto the thread 0 event
1997 queue (interthread via the thread 0 inter_thread_events list)
1998 and from there are delivered in the context of the proper thread
1999 for cache efficiency (by means of nrn_onethread_job.) Again, as mentioned,
2000 the design side is for few events. With this in mind, there does not seem
2001 any impediment to 0 delay events. But note that an event with source and
2002 target on thread 2 (e.g. a self event) goes onto the thread 0 inter_thread_events
2003 list (in the context of thread 2), then in the context of thread 0 is transferred
2004 from the thread 0 inter_thread_events list to the thread 0 queue, then
2005 in the context of thread 0, the event is taken off the queue and delivered
2006 in the context of thread 2 (by means of nrn_onethread_job). (See why we
2007 are thinking few events? A bothersome aspect is that after every event
2008 delivery least_t has to enqueue onto the thread 0 queue the nthread
2009 inter_thread_events lists.
2010 The one queue idea for global variable time step is unsound because of the
2011 problem that multiple threads call the queue methods and so cause excessive
2012 cache line sharing. And if we avoided this through the use of the
2013 inter_thread_events list then consider a 0 delay NetCon
2014 event between artificial cells on thread 2 and thread 3.
2015 thread 0 in deliver_events_when_threads, least event for thread 2
2016 thread 2 (NET_RECEIVE -> net_send -> PreSyn::send -> p[3].interthead_send
2017 thread 0 enqueue onto thread 0 queue all inter_thread_events lists
2018 thread 0 least event for thread 3
2019 thread 3 (NET_RECEIVE ...)
2020 Actually, there are real problems. E.g ConditionEvent::condition is
2021 in the context of some thread and must remove an event on the thread 0 queue.
2022 That is a recipe for horrendous cacheline sharing and is the whole reason
2023 we designed inter_thread_events in the first place. Also the call to
2024 enqueue_thread0() is multiplying alarmingly (every call before least_t())
2025 and the reason for the privileged thread 0 queue has more or less disappeared.
2026 Instead we only need an effective reduce to find the minimum of the least_t()
2027 in each thread. Expensive but no more expensive than the single queue and without
2028 the cache-line shareing. And allows 0 delay events. And keeps a kind of uniformity
2029 between fixed step, global cvode, and the future lvardt in that each thread
2030 has its own event queue.
2031 Far reaching Local variable time step method change.
2032 gcv_ if it exists, refers to the global variable time step method
2033 and there are nthread CvodeThreadData instances in ctd_. If gcv_ is 0 and
2034 !empty_, then each NetCvodeThreadData manages an array of nlcv_
2035 Cvode instances in the lcv_ array. Each Cvode instance has only one ctd_
2036 Thus for global step the CvodeThreadData for a thread is gcv_->ctd_[i] whereas
2037 for lvardt it is p[i].lcv_[jcell_in_thread_i].ctd_[0].
2038 */
2039 
2040 int NetCvode::solve(double tout) {
2041  if (nrn_nthread > 1) {
2042  return solve_when_threads(tout); // more or less a copy of below
2043  }
2044  NrnThread* nt = nrn_threads;
2045  int err = NVI_SUCCESS;
2046  if (empty_) {
2047  if (tout >= 0.) {
2048  while (p[0].tqe_->least_t() <= tout && stoprun==0) {
2049  deliver_least_event(nt);
2050  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
2051  }
2052  if (stoprun==0) { nt_t = tout; }
2053  } else {
2054  if (p[0].tqe_->least()) {
2055  nt_t = p[0].tqe_->least_t();
2056  deliver_events(p[0].tqe_->least_t(), nt);
2057  }else{
2058  nt_t += 1e6;
2059  }
2060  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
2061  }
2062  }else if (single_) {
2063  if (tout >= 0.) {
2064  while (gcv_->t_ < tout || p[0].tqe_->least_t() < tout) {
2065  err = global_microstep();
2066  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
2067  if (err != NVI_SUCCESS || stoprun) { return err; }
2068  }
2069  retreat(tout, gcv_);
2070  gcv_->record_continuous();
2071  } else {
2072  // advance or initialized
2073  double tc = gcv_->t_;
2074  initialized_ = false;
2075  while (gcv_->t_ <= tc && !initialized_) {
2076  err = global_microstep();
2077  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
2078  if (err != NVI_SUCCESS || stoprun) { return err; }
2079  }
2080  }
2081  }else if (!gcv_) { // lvardt
2082  if (tout >= 0.) {
2083  time_t rt = time(nil);
2084 // int cnt = 0;
2085  TQueue* tq = p[0].tq_;
2086  TQueue* tqe = p[0].tqe_;
2087  NrnThread* nt = nrn_threads;
2088  while (tq->least_t() < tout || tqe->least_t() <= tout) {
2089  err = local_microstep(nt);
2090  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
2091  if (err != NVI_SUCCESS || stoprun) { return err; }
2092 #if HAVE_IV
2093 IFGUI
2094  if (rt < time(nil)) {
2095 // if (++cnt > 10000) {
2096 // cnt = 0;
2097  Oc oc; oc.notify();
2098  single_event_run();
2099  rt = time(nil);
2100  }
2101 ENDGUI
2102 #endif
2103  }
2104  int n = p[0].nlcv_;
2105  Cvode* lcv = p[0].lcv_;
2106  for (int i=0; i < n; ++i) {
2107  local_retreat(tout, lcv + i);
2108  lcv[i].record_continuous();
2109  }
2110  } else {
2111  // an fadvance is not every microstep but
2112  // only when all the discontinuities at te take place or
2113  // tc increases.
2114  TQueue* tq = p[0].tq_;
2115  double tc = tq->least_t();
2116  double te = p[0].tqe_->least_t();
2117  while (tq->least_t() <= tc && p[0].tqe_->least_t() <= te){
2118  err = local_microstep(nrn_threads);
2119  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
2120  if (err != NVI_SUCCESS || stoprun) { return err; }
2121  }
2122  // But make sure t is not past the least time.
2123  // fadvance and local step do not coexist seamlessly.
2124  nt_t = tq->least_t();
2125  if (te < nt_t) {
2126  nt_t = te;
2127  }
2128  }
2129  }else{
2130  nt_t += 1e9;
2131  }
2132  return err;
2133 }
2134 
2136 #if 0 // now a HocEvent is used to do this
2137  nt->_stop_stepping = 1;
2138  if (cvode_active_) {
2139  if (gcv_) {
2140  retreat(tt, gcv_);
2141  gcv_->record_continuous();
2142  }else{
2143  int i, n = p[nt->id].nlcv_;
2144  Cvode* lcv = p[nt->id].lcv_;
2145  for (i = 0; i < n; ++i) {
2146  local_retreat(tt, lcv + i);
2147  lcv[i].record_continuous();
2148  }
2149  }
2150  }
2151 #endif
2152 }
2153 
2155  TQItem* q = p[nt->id].tqe_->least();
2156  DiscreteEvent* de = (DiscreteEvent*)q->data_;
2157  double tt = q->t_;
2158  p[nt->id].tqe_->remove(q);
2159 #if PRINT_EVENT
2160  if (print_event_) { de->pr("deliver", tt, this); }
2161 #endif
2162  STATISTICS(deliver_cnt_);
2163  de->deliver(tt, this, nt);
2164 }
2165 
2166 bool NetCvode::deliver_event(double til, NrnThread* nt) {
2167  TQItem* q;
2168  if ((q = p[nt->id].tqe_->atomic_dq(til)) != 0) {
2169  DiscreteEvent* de = (DiscreteEvent*)q->data_;
2170  double tt = q->t_;
2171  p[nt->id].tqe_->release(q);
2172 #if PRINT_EVENT
2173  if (print_event_) { de->pr("deliver", tt, this); }
2174 #endif
2175  STATISTICS(deliver_cnt_);
2176  de->deliver(tt, this, nt);
2177  return true;
2178  }else{
2179  return false;
2180  }
2181 }
2182 
2184  int err = NVI_SUCCESS;
2185  int i = nt->id;
2186  if (p[i].tqe_->least_t() <= p[i].tq_->least_t()) {
2187  deliver_least_event(nt);
2188  }else{
2189  TQItem* q = p[i].tq_->least();
2190  Cvode* cv = (Cvode*)q->data_;
2191  err = cv->handle_step(this, 1e100);
2192  p[i].tq_->move_least(cv->t_);
2193  }
2194  return err;
2195 }
2196 
2198  NrnThread* nt = nrn_threads;
2199  int err = NVI_SUCCESS;
2200  double tt = p[0].tqe_->least_t();
2201  double tdiff = tt - gcv_->t_;
2202  if (tdiff <= 0) {
2203  // since events do not internally retreat with the
2204  // global step, we should already be at the event time
2205  // if this is too strict, we could use eps(list_->t_).
2206  assert(tdiff == 0.0 || ( gcv_->tstop_begin_ <= tt && tt <= gcv_->tstop_end_));
2207  deliver_events(tt, nt);
2208  }else{
2209  err = gcv_->handle_step(this, tt);
2210  }
2211  if (p[0].tqe_->least_t() < gcv_->t_) {
2212  gcv_->interpolate(p[0].tqe_->least_t());
2213  }
2214  return err;
2215 }
2216 
2217 int Cvode::handle_step(NetCvode* ns, double te) {
2218  int err = NVI_SUCCESS;
2219  // first order correct condition evaluation goes here
2220  if (ns->condition_order() == 1) {
2221  if (ns->gcv_) {// global step
2222  for (int i=0; i < nctd_; ++i) {
2223  nrn_threads[i]._t = t_; // for global step could be assert
2224  }
2225  check_deliver();
2226  // done if the check puts a 0 delay event on queue
2227  if (nctd_ > 1) {
2228  int tid;
2229  if (ns->allthread_least_t(tid) <= t_) {
2230  return err;
2231  }
2232  }else{
2233  if (ns->p[0].tqe_->least_t() <= t_) {
2234  return err;
2235  }
2236  }
2237  }else{ //lvardt so in a specific thread
2238  // for localstep method t is for a different cvode.fun call
2239  nth_->_t = t_;
2240  check_deliver(nth_);
2241  if (ns->p[nth_->id].tqe_->least_t() <= t_) {
2242  return err;
2243  }
2244  }
2245  }
2246  if (initialize_) {
2247  err = init(t_);
2248  if (ns->gcv_) { ns->initialized_ = true; }
2249  // second order correct condition evaluation goes here
2250  if (ns->condition_order() == 2) {
2251  evaluate_conditions(nth_);
2252  }
2253  }else if (te <= tn_) {
2254  err = interpolate(te);
2255  }else if (t_ < tn_) {
2256  err = interpolate(tn_);
2257  }else{
2258  record_continuous();
2259  err = advance_tn();
2260  // second order correct condition evaluation goes here
2261  if (ns->condition_order() == 2) {
2262  evaluate_conditions(nth_);
2263  }
2264  }
2265  return err;
2266 }
2267 
2268 extern "C" void net_move(void** v, Point_process* pnt, double tt) {
2269  if (!(*v)) {
2270  hoc_execerror( "No event with flag=1 for net_move in ", hoc_object_name(pnt->ob));
2271  }
2272  TQItem* q = (TQItem*)(*v);
2273 //printf("net_move tt=%g %s *v=%p\n", tt, hoc_object_name(pnt->ob), *v);
2274  if (tt < PP2t(pnt)) {
2275  SelfEvent* se = (SelfEvent*)q->data_;
2276  char buf[100];
2277  sprintf(buf, "net_move tt-nt_t = %g", tt-PP2t(pnt));
2278  se->pr(buf, tt, net_cvode_instance);
2279  assert(0);
2280  hoc_execerror("net_move tt < t", 0);
2281  }
2282  net_cvode_instance->move_event(q, tt, PP2NT(pnt));
2283 }
2284 
2285 extern "C" void artcell_net_move(void** v, Point_process* pnt, double tt) {
2286  if (nrn_use_selfqueue_) {
2287  if (!(*v)) {
2288  hoc_execerror( "No event with flag=1 for net_move in ", hoc_object_name(pnt->ob));
2289  }
2290  NrnThread* nt = PP2NT(pnt);
2291  NetCvodeThreadData& p = net_cvode_instance->p[nt->id];
2292  TQItem* q = (TQItem*)(*v);
2293 //printf("artcell_net_move t=%g qt_=%g tt=%g %s *v=%p\n", nt->_t, q->t_, tt, hoc_object_name(pnt->ob), *v);
2294  if (tt < nt->_t) {
2295  SelfEvent* se = (SelfEvent*)q->data_;
2296  char buf[100];
2297  sprintf(buf, "artcell_net_move tt-nt_t = %g", tt - nt->_t);
2298  se->pr(buf, tt, net_cvode_instance);
2299  hoc_execerror("net_move tt < t", 0);
2300  }
2301  q->t_ = tt;
2302  if (tt < p.immediate_deliver_) {
2303 //printf("artcell_net_move_ %s immediate %g %g %g\n", hoc_object_name(pnt->ob), PP2t(pnt), tt, p.immediate_deliver_);
2304  SelfEvent* se = (SelfEvent*)q->data_;
2305  se->deliver(tt, net_cvode_instance, nt);
2306  }
2307  }else{
2308  net_move(v, pnt, tt);
2309  }
2310 }
2311 
2312 void NetCvode::move_event(TQItem* q, double tnew, NrnThread* nt) {
2313  int tid = nt->id;
2314  STATISTICS(SelfEvent::selfevent_move_);
2315 #if PRINT_EVENT
2316 if (print_event_) {
2317  SelfEvent* se = (SelfEvent*)q->data_;
2318 Printf("NetCvode::move_event self event target %s t=%g, old=%g new=%g\n", hoc_object_name(se->target_->ob), nt->_t, q->t_, tnew);
2319 }
2320 #endif
2321 #if USENEOSIM
2322  // only self events move
2323  if (neosim_entity_){
2324  assert(0);
2325  //cvode_instance->neosim_self_events_->move(q, tnew);
2326  }else{
2327  p[tid].tqe_->move(q, tnew);
2328  }
2329 #else
2330  p[tid].tqe_->move(q, tnew);
2331 #endif
2332 }
2333 
2335  p[tid].tqe_->remove(q);
2336 }
2337 
2338 // for threads, revised net_send to use absolute time (in the
2339 // mod file we add the thread time when we call it).
2340 extern "C" void net_send(void** v, double* weight, Point_process* pnt, double td, double flag) {
2341  STATISTICS(SelfEvent::selfevent_send_);
2342  NrnThread* nt = PP2NT(pnt);
2343  NetCvodeThreadData& p = net_cvode_instance->p[nt->id];
2344  SelfEvent* se = p.sepool_->alloc();
2345  se->flag_ = flag;
2346  se->target_ = pnt;
2347  se->weight_ = weight;
2348  se->movable_ = v; // needed for SaveState
2349  assert(net_cvode_instance);
2350  ++p.unreffed_event_cnt_;
2351  if (td < nt->_t) {
2352  char buf[100];
2353  sprintf(buf, "net_send td-t = %g", td - nt->_t);
2354  se->pr(buf, td, net_cvode_instance);
2355  abort();
2356  hoc_execerror("net_send delay < 0", 0);
2357  }
2358  TQItem* q;
2359 #if USENEOSIM
2360  if (neosim_entity_) {
2361  assert(0);
2362  //cvode_instance->neosim_self_events_->insert(td, se);
2363  }else{
2364  q = net_cvode_instance->event(td, se, nt);
2365  }
2366 #else
2367  q = net_cvode_instance->event(td, se, nt);
2368 #endif
2369  if (flag == 1.0) {
2370  *v = (void*)q;
2371  }
2372 //printf("net_send %g %s %g %p\n", td, hoc_object_name(pnt->ob), flag, *v);
2373 }
2374 
2375 extern "C" void artcell_net_send(void** v, double* weight, Point_process* pnt, double td, double flag) {
2376  if (nrn_use_selfqueue_ && flag == 1.0) {
2377  STATISTICS(SelfEvent::selfevent_send_);
2378  NrnThread* nt = PP2NT(pnt);
2379  NetCvodeThreadData& p = net_cvode_instance->p[nt->id];
2380  SelfEvent* se = p.sepool_->alloc();
2381  se->flag_ = flag;
2382  se->target_ = pnt;
2383  se->weight_ = weight;
2384  se->movable_ = v; // needed for SaveState
2385  assert(net_cvode_instance);
2386  ++p.unreffed_event_cnt_;
2387  if (td < nt->_t) {
2388  char buf[100];
2389  sprintf(buf, "net_send td-t = %g", td - nt->_t);
2390  se->pr(buf, td, net_cvode_instance);
2391  hoc_execerror("net_send delay < 0", 0);
2392  }
2393  TQItem* q;
2394  q = p.selfqueue_->insert(se);
2395  q->t_ = td;
2396  *v = (void*)q;
2397 //printf("artcell_net_send %g %s %g %p\n", td, hoc_object_name(pnt->ob), flag, v);
2398  if (q->t_ < p.immediate_deliver_) {
2399 //printf("artcell_net_send_ %s immediate %g %g %g\n", hoc_object_name(pnt->ob), nt->_t, q->t_, p.immediate_deliver_);
2400  SelfEvent* se = (SelfEvent*)q->data_;
2401  p.selfqueue_->remove(q);
2402  se->deliver(td, net_cvode_instance, nt);
2403  }
2404  }else{
2405  net_send(v, weight, pnt, td, flag);
2406  }
2407 }
2408 
2409 extern "C" void net_event(Point_process* pnt, double time) {
2410  STATISTICS(net_event_cnt_);
2411  PreSyn* ps = (PreSyn*)pnt->presyn_;
2412  if (ps) {
2413  if (time < PP2t(pnt)) {
2414  char buf[100];
2415  sprintf(buf, "net_event time-t = %g", time-PP2t(pnt));
2416  ps->pr(buf, time, net_cvode_instance);
2417  hoc_execerror("net_event time < t", 0);
2418  }
2419 #if USENEOSIM
2420  if (neosim_entity_) {
2421  (*p_nrn2neosim_send)(neosim_entity_, nt_t);
2422  }else{
2423 #endif
2424  ps->send(time, net_cvode_instance, ps->nt_);
2425 #if USENEOSIM
2426  }
2427 #endif
2428  }
2429 }
2430 
2431 extern "C" void _nrn_watch_activate(Datum* d, double (*c)(Point_process*), int i, Point_process* pnt, int r, double flag) {
2432  if (!d[i]._pvoid || !d[0]._pvoid) {
2433  // When c is NULL, i.e. called from CoreNEURON,
2434  // we never get here because we made sure
2435  // _nrn_watch_allocated for this has been called earlier from
2436  // within the translated mod file.
2437  _nrn_watch_allocate(d, c, i, pnt, flag); // d[0]._pvoid and d[i]._pvoid exist
2438  }
2439  WatchList* wl = (WatchList*)d->_pvoid;
2440  if (r == 0) {
2441  int j;
2442  for (j=0; j < wl->count(); ++j) {
2443  WatchCondition* wc1 = wl->item(j);
2444  wc1->Remove();
2445  if (wc1->qthresh_) { // is it on the queue?
2446  net_cvode_instance->remove_event(wc1->qthresh_, PP2NT(pnt)->id);
2447  wc1->qthresh_ = nil;
2448  }
2449  }
2450  wl->remove_all();
2451  }
2452  WatchCondition* wc = (WatchCondition*)d[i]._pvoid;
2453  wl->append(wc);
2454  wc->activate(flag); // nr_flag_ (NetReceive flag) not flag_ for above threshold.
2455 }
2456 
2457 /*
2458 An example of a call to _nrn_watch_activate from within the NET_RECEIVE
2459 block of a translated mod file is
2460 _nrn_watch_activate(_watch_array, _watch1_cond, 1, _pnt, _watch_rm++, 2.0);
2461 
2462 _watch_array begins at _ppvar+first_index_of_watch_information and the number
2463  of indices is 1 more than the number of watch statements. Each of those
2464  (starting at index 1) is a pointer to a WatchCondition.
2465  The 0th is a pointer to a HTList (HeadTailList) of the active WatchConditions.
2466  Third arg is index of the WatchCondition to be activated.
2467  The _watch_rm when 0 means, empty the HTList before adding the
2468  WatchCondition to the HTList, when > 0, just add (It is possible for
2469  several WatchCondition to be active at the same time. That is useful when
2470  the conceptual condition is for a variable to be within a specific range
2471  or when multiple variables need to be watched at the same time.
2472  The last arg is the flag value used by the NET_RECEIVE block to activate
2473  a new set of WATCH statements. Note that that particular flag does not
2474  have to result in the activation of a new set. In that case, the old set
2475  stays active.
2476 
2477 Note. At time of writing this note,
2478  _watch_array[1:] are only created the first time that 'i' WatchCondition
2479  is activated. And at that time the 2nd callback arg is stored in the
2480  WatchCondition. So, at the moment, return from CoreNEURON cannot count on
2481  all WatchConditions being in existence. Given that the 2nd callback arg
2482  is only known to the translated mod file, the most straightforward solution
2483  is for nocmodl to generate
2484  an "initialization" function that calls all possible _nrn_watch_activate.
2485  That could be done at the Point_process* pnt creation time (or after
2486  transfer of WATCH info to CoreNEURON (using structure_change_cnt_).)
2487  It could even be done as necessary when CoreNEURON sends back activated
2488  WatchCondition info when the WatchCondition* slot on the NEURON side
2489  is NULL. Then the "initialization" function could call a stripped down
2490  version of _nrn_watch_activate for only its NULL slots.
2491 
2492 Here are some more notes about WatchCondition, HTList, HTListList, and
2493  WatchList.
2494  The (WatchList*)d->_pvoid is used only in _nrn_watch_activate to
2495  iterate over its previously activated list in order to remove all those from
2496  its HTList.
2497  WatchCondition is a subclass of ConditionEvent and HTList
2498  Because of the latter, we can say
2499  WatchCondition.Remove() and HTList.append(WatchCondition)
2500  The former can be called any number of times. When it is called it becomes
2501  a singleton WatchCondition (only in itself as an HTList).
2502  The latter can be called any number of times. Whereever the
2503  WatchCondition is located before calling HTList.append ---
2504  singleton, in another list, or already in this list --- it will end up
2505  as the htlist.Last()
2506 
2507 */
2508 
2509 /** Introduced so corenrn->nrn can request the mod file to make sure
2510  * all WatchCondition are allocated. When that is the case then
2511  * corenrn can call _nrn_watch_activate with all args filled out
2512  * because the allocated WatchCondition has double (*c_)(Point_process)
2513  * and flag_ filled in.
2514 **/
2515 extern "C" void _nrn_watch_allocate(Datum* d, double (*c)(Point_process*), int i, Point_process* pnt, double flag) {
2516  if (!d->_pvoid) {
2517  d->_pvoid = (void*)new WatchList();
2518  }
2519  if (!d[i]._pvoid) {
2520  WatchCondition* wc = new WatchCondition(pnt, c);
2521  wc->c_ = c;
2522  wc->nrflag_ = flag;
2523  d[i]._pvoid = (void*)wc;
2524  // Simplify transfer to CoreNEURON
2525  // To avoid searching for the beginning of _watch_array after
2526  // transfer to CoreNEURON, compute the offset with respect to
2527  // dparam. That, of course, assumes NEURON and CoreNEURON
2528  // have same pdata arrangement.
2529  wc->watch_index_ = i + (d - pnt->prop->dparam);
2530  }
2531 }
2532 
2533 /** Watch info corenrn->nrn transfer requires all activated
2534  * WatchCondition be deactivated prior to mirroring the activation
2535  * that exists on the corenrn side.
2536 **/
2537 extern "C" void nrn_watch_clear() {
2538  assert(net_cvode_instance->wl_list_.size() == (size_t)nrn_nthread);
2539  for (auto& htlists_of_thread: net_cvode_instance->wl_list_) {
2540  for (HTList* wl: htlists_of_thread) {
2541  wl->RemoveAll();
2542  }
2543  }
2544  // not necessary to empty the WatchList in the Point_process dparam array
2545  // as that will happen when _nrn_watch_activate is called with an r
2546  // arg of 0.
2547 }
2548 
2549 /** Called by Point_process destructor in translated mod file **/
2550 extern "C" void _nrn_free_watch(Datum* d, int offset, int n) {
2551  int i;
2552  int nn = offset + n;
2553  if (d[offset]._pvoid) {
2554  WatchList* wl = (WatchList*)d[offset]._pvoid;
2555  delete wl;
2556  }
2557  for (i=offset+1; i < nn; ++i) {
2558  if (d[i]._pvoid) {
2559  WatchCondition* wc = (WatchCondition*)d[i]._pvoid;
2560  wc->Remove();
2561  delete wc;
2562  }
2563  }
2564 }
2565 
2567  // not destroyed when vector destroyed.
2568  // should resize to 0 or remove before storing, just keeps incrementing
2569  if (vec_event_store_) {
2570  vec_event_store_ = nil;
2571  }
2572  if (ifarg(1)) {
2573  vec_event_store_ = vector_arg(1);
2574  }
2575 }
2576 
2577 #if BBTQ == 3 || BBTQ == 4
2578 TQItem* NetCvode::fifo_event(double td, DiscreteEvent* db) {
2579  if (nrn_use_fifo_queue_) {
2580 #if PRINT_EVENT
2581  if (print_event_) { db->pr("send", td, this); }
2582  if (vec_event_store_) {
2583  Vect* x = vec_event_store_;
2584  int n = x->size();
2585  x->resize_chunk(n+2);
2586  x->elem(n) = t;
2587  x->elem(n+1) = td;
2588  }
2589 #endif
2590  return p[0].tqe_->insert_fifo(td, db);
2591  }else{
2592  return p[0].tqe_->insert(td, db);
2593  }
2594 }
2595 #else
2596 #define fifo_event event
2597 #endif
2598 
2599 #if BBTQ == 5
2601  if (nrn_use_bin_queue_) {
2602 #if PRINT_EVENT
2603  if (print_event_) {db->pr("binq send", td, this);}
2604  if (vec_event_store_) {
2605  assert(0);
2606  Vect* x = vec_event_store_;
2607  x->push_back(nt_t);
2608  x->push_back(td);
2609  }
2610 #endif
2611  return p[nt->id].tqe_->enqueue_bin(td, db);
2612  }else{
2613 #if PRINT_EVENT
2614  if (print_event_) {db->pr("send", td, this);}
2615 #endif
2616  return p[nt->id].tqe_->insert(td, db);
2617  }
2618 }
2619 #else
2620 #define bin_event event
2621 #endif
2622 
2624 #if PRINT_EVENT
2625  if (print_event_) { db->pr("send", td, this); }
2626  if (vec_event_store_) {
2627  Vect* x = vec_event_store_;
2628  x->push_back(nt_t);
2629  x->push_back(td);
2630  }
2631 #endif
2632  return p[nt->id].tqe_->insert(td, db);
2633 }
2634 
2635 void NetCvode::null_event(double tt) {
2636  assert(0);
2637  NrnThread* nt = nrn_threads;
2638  if (tt - nt->_t < 0) { return; }
2639 #if USENEOSIM
2640  if (neosim_entity_) {
2641  // ignore for neosim. There is no appropriate cvode_instance
2642  // cvode_instance->neosim_self_events_->insert(nt_t + delay, null_event_);
2643  }else{
2644  event(tt, null_event_, nt);
2645  }
2646 #else
2647  event(tt, null_event_, nt);
2648 #endif
2649 }
2650 
2651 void NetCvode::tstop_event(double tt) {
2652  if (tt - nt_t < 0) { return; }
2653 #if USENEOSIM
2654  if (neosim_entity_) {
2655  // ignore for neosim. There is no appropriate cvode_instance
2656  // cvode_instance->neosim_self_events_->insert(nt_t + delay, tstop_event_);
2657  }else
2658 #endif
2659  {
2660  if (gcv_) {
2661  event(tt, tstop_event_, nrn_threads);
2662  }else{
2663  NrnThread* nt;
2664  FOR_THREADS(nt) {
2665  event(tt, tstop_event_, nt);
2666  }
2667  }
2668  }
2669 }
2670 
2671 void NetCvode::hoc_event(double tt, const char* stmt, Object* ppobj, int reinit, Object* pyact) {
2672  if (!ppobj && tt - nt_t < 0) { return; }
2673 #if USENEOSIM
2674  if (neosim_entity_) {
2675  // ignore for neosim. There is no appropriate cvode_instance
2676  // cvode_instance->neosim_self_events_->insert(nt_t + delay, null_event_);
2677  }else
2678 #endif
2679  {
2680  NrnThread* nt = nrn_threads;
2681  if (nrn_nthread > 1 && (!cvode_active_ || localstep())) {
2682  if (ppobj) {
2683  int i = PP2NT(ob2pntproc(ppobj))->id;
2684  p[i].interthread_send(tt, HocEvent::alloc(stmt, ppobj, reinit, pyact), nt+i);
2685  nrn_interthread_enqueue(nt + i);
2686  }else{
2687  HocEvent* he = HocEvent::alloc(stmt, nil, 0, pyact);
2688  // put on each queue. The first thread to execute the deliver
2689  // for he will set the nrn_allthread_handle
2690  // callback which will cause all threads to rejoin at the
2691  // end of the current fixed step or, for var step methods,
2692  // after all events at this time are delivered. It is up
2693  // to the callers of the multithread_job functions
2694  // to do the right thing.
2695  for (int i=0; i < nrn_nthread; ++i) {
2696  p[i].interthread_send(tt, he, nt + i);
2697  }
2699  }
2700  }else{
2701  event(tt, HocEvent::alloc(stmt, ppobj, reinit, pyact), nt);
2702  }
2703  }
2704 }
2705 
2708  t = nt_t;
2709  while (allthread_hocevents_->count()) {
2710  HocEvent* he = allthread_hocevents_->item(0);
2711  allthread_hocevents_->remove(0);
2712  he->allthread_handle();
2713  }
2714 }
2715 
2716 void NetCvode::allthread_handle(double tt, HocEvent* he, NrnThread* nt) {
2717  //printf("allthread_handle tt=%g nt=%d nt_t=%g\n", tt, nt->id, nt->_t);
2718  nt->_stop_stepping = 1;
2719  if (is_local()) {
2720  int i, n = p[nt->id].nlcv_;
2721  Cvode* lcv = p[nt->id].lcv_;
2722  if (n) for (i = 0; i < n; ++i) {
2723  local_retreat(tt, lcv + i);
2724  if (!he->stmt()) {
2725  lcv[i].record_continuous();
2726  }
2727  }else{
2728  nt->_t = tt;
2729  }
2730  } else if (!he->stmt() && cvode_active_ && gcv_) {
2731  assert(MyMath::eq2(tt, gcv_->t_, NetCvode::eps(tt)));
2732  gcv_->record_continuous();
2733  }
2734  if (nt->id == 0) {
2736  allthread_hocevents_->append(he);
2737  nt->_t = tt;
2738  }
2739  if (cvode_active_ && gcv_ && nrnmpi_numprocs > 1) {
2740  assert(nrn_nthread == 1);
2741  return;
2742  }
2743  // deliver any other events at this time (in particular, a possible NetParEvent)
2744  // to guarantee consistency of the NetParEvent for all threads
2745  // Otherwise, if some threads do a NetParEvent and others not, then
2746  // the interthread enqueue can put an earlier event onto the thread queue
2747  // than the last delivered event
2748  deliver_events(tt, nt);
2749 }
2750 
2751 #if 0
2752 struct PPArgs {
2753  int type;
2754  Point_process* pp;
2755  double* w;
2756  double f;
2757 };
2758 
2759 static PPArgs* ppargs;
2760 
2761 static void point_receive_job(NrnThread* nt) {
2762  PPArgs* p = ppargs + nt->id;
2763  (*pnt_receive[p->type])(p->pp, p->w, p->f);
2764 }
2765 
2766 void NetCvode::point_receive(int type, Point_process* pp, double* w, double f) {
2767  // this is the master thread. need to execute the pthread associated
2768  // with the pp.
2769  int id = PP2NT(pp)->id;
2770  if (id == 0) { // execute on this, the master thread
2771  (*pnt_receive[type])(pp, w, f);
2772  }else{
2773  // marshall the args
2774  PPArgs* p = ppargs + id;
2775  p->type = type;
2776  p->pp = pp;
2777  p->w = w;
2778  p->f = f;
2779  nrn_onethread_job(id, point_receive_job);
2780  }
2781  // global queue with different threads putting things in
2782  // means no guarantee that something goes into the queue
2783  // to be delivered earlier than something last extracted.
2784  // so return to calling main thread only after the
2785  // worker thread is done. Too bad...
2786  // this needs to be worked on. Only thread id is executing.
2788 }
2789 #endif
2790 
2792  int i;
2793  deliver_cnt_ = net_event_cnt_ = 0;
2794  NetCon::netcon_send_active_ = 0;
2795  NetCon::netcon_send_inactive_ = 0;
2796  NetCon::netcon_deliver_ = 0;
2797  ConditionEvent::init_above_ = 0;
2798  ConditionEvent::send_qthresh_ = 0;
2799  ConditionEvent::deliver_qthresh_ = 0;
2800  ConditionEvent::abandon_ = 0;
2801  ConditionEvent::eq_abandon_ = 0;
2802  ConditionEvent::abandon_init_above_ = 0;
2803  ConditionEvent::abandon_init_below_ = 0;
2804  ConditionEvent::abandon_above_ = 0;
2805  ConditionEvent::abandon_below_ = 0;
2806  PreSyn::presyn_send_mindelay_ = 0;
2807  PreSyn::presyn_send_direct_ = 0;
2808  PreSyn::presyn_deliver_netcon_ = 0;
2809  PreSyn::presyn_deliver_direct_ = 0;
2810  PreSyn::presyn_deliver_ncsend_ = 0;
2811  SelfEvent::selfevent_send_ = 0;
2812  SelfEvent::selfevent_move_ = 0;
2813  SelfEvent::selfevent_deliver_ = 0;
2814  WatchCondition::watch_send_ = 0;
2815  WatchCondition::watch_deliver_ = 0;
2816  PlayRecordEvent::playrecord_deliver_ = 0;
2817  PlayRecordEvent::playrecord_send_ = 0;
2818  HocEvent::hocevent_send_ = 0;
2819  HocEvent::hocevent_deliver_ = 0;
2820  DiscreteEvent::discretevent_send_ = 0;
2821  DiscreteEvent::discretevent_deliver_ = 0;
2822  KSSingle::singleevent_deliver_ = 0;
2823  KSSingle::singleevent_move_ = 0;
2824 
2825  // SelfEvents need to be "freed". Other kinds of DiscreteEvents may
2826  // already have gone out of existence so the tqe_ may contain many
2827  // invalid item data pointers
2829  allthread_hocevents_->remove_all();
2831 #if USENEOSIM
2832  if (p_nrn2neosim_send) for (i=0; i < nlist_; ++i) {
2833  TQueue* tq = p.lcv_[i].neosim_self_events_;
2834  while(tq->least()) { tq->remove(tq->least());}
2835  // and have already been reclaimed by SelfEvent::reclaim()
2836  }
2837 #endif
2838  if (!MUTCONSTRUCTED) {MUTCONSTRUCT(1);}
2839  enqueueing_ = 0;
2840  for (i=0; i < nrn_nthread; ++i) {
2841  NetCvodeThreadData& d = p[i];
2842  delete d.tqe_;
2843  d.tqe_ = new TQueue(p[i].tpool_);
2844  d.unreffed_event_cnt_ = 0;
2845  d.sepool_->free_all();
2846  d.immediate_deliver_ = -1e100;
2847  d.ite_cnt_ = 0;
2848  if (nrn_use_selfqueue_) {
2849  if (!d.selfqueue_) {
2850  d.selfqueue_ = new SelfQueue(d.tpool_, 0);
2851  }else{
2852  d.selfqueue_->remove_all();
2853  }
2854  }
2855 #if BBTQ == 5
2856  d.tqe_->nshift_ = -1;
2857  d.tqe_->shift_bin(nt_t - 0.5*nt_dt);
2858 #endif
2859  }
2860  // I don't believe this is needed anymore since cvode not needed
2861  // til delivery.
2862  if (cvode_active_) { // in case there is a net_send from INITIAL cvode
2863  // then this needs to be done before INITIAL blocks are called
2864  init_global();
2865  }
2866 }
2867 
2869  hoc_Item* q;
2870  int i, j;
2871  double fifodelay;
2872 #if BBTQ == 5
2873  for (i=0; i < nrn_nthread; ++i) {
2874  p[i].tqe_->nshift_ = -1;
2875  // first bin starts 1/2 time step early because per time step
2876  // binq delivery during simulation from deliver_net_events,
2877  // after delivering all events in the current bin, shifts to
2878  // nt->_t + 0.5*nt->_dt where nt->_t is a multiple of dt.
2879  p[i].tqe_->shift_bin(nt_t - 0.5*nt_dt);
2880  }
2881 #endif
2882  if (psl_) {
2883  ITERATE(q, psl_) {
2884  PreSyn* ps = (PreSyn*)VOIDITM(q);
2885  ps->init();
2886  ps->flag_ = false;
2887  NetConPList& dil = ps->dil_;
2888  ps->use_min_delay_ = 0;
2889 #if USE_MIN_DELAY
2890  // also decide what to do about use_min_delay_
2891  // the rule for now is to use it if all delays are
2892  // the same and there are more than 2
2893 #if BBTQ == 3 || BBTQ == 4
2894  // but
2895  // if we desire nrn_use_fifo_queue_ then use it
2896  // even if just one
2897  if (nrn_use_fifo_queue_) {
2898  if (!dil.empty()) {
2899  ps->use_min_delay_ = 1;
2900  ps->delay_ = dil[0]->delay_;
2901  fifodelay = ps->delay_;
2902  }
2903  }else
2904 #endif // BBTQ
2905  {
2906  if (dil.size() > 2) {
2907  ps->use_min_delay_ = 1;
2908  ps->delay_ = dil[0]->delay_;
2909  }
2910  }
2911 #endif // USE_MIN_DELAY
2912 
2913  for (auto it = dil.rbegin(); it != dil.rend(); ++it) {
2914  NetCon* d = *it;
2915  if (ps->use_min_delay_ && ps->delay_ != d->delay_) {
2916  ps->use_min_delay_ = false;
2917  }
2918 #if BBTQ == 3 || BBTQ == 4
2919  if (nrn_use_fifo_queue_ && d->delay_ != fifodelay) {
2920 hoc_warning("Use of the event fifo queue is turned off due to more than one value for NetCon.delay", 0);
2921  nrn_use_fifo_queue_ = false;
2922  }
2923 #endif
2924  }
2925  }
2926  }
2927  // iterate over all NetCon in creation order to call
2928  // NETRECEIVE INITIAL blocks.
2929  static hoc_List* nclist = NULL;
2930  if (!nclist) {
2931  Symbol* sym = hoc_lookup("NetCon");
2932  nclist = sym->u.ctemplate->olist;
2933  }
2934  ITERATE(q, nclist) {
2935  Object* obj = OBJ(q);
2936  NetCon* d = (NetCon*)obj->u.this_pointer;
2937  if (d->target_) {
2938  int type = d->target_->prop->type;
2939  if (pnt_receive_init[type]) {
2940 (*pnt_receive_init[type])(d->target_, d->weight_, 0);
2941  }else{
2942  //not the first
2943  for (j = d->cnt_-1; j > 0; --j) {
2944  d->weight_[j] = 0.;
2945  }
2946  }
2947  }
2948  }
2949  if (gcv_) {
2950  for (int j=0; j < nrn_nthread; ++j) {
2951  if (gcv_->ctd_[j].watch_list_) {
2952  gcv_->ctd_[j].watch_list_->RemoveAll();
2953  }
2954  }
2955  }else{
2956  for (int j=0; j < nrn_nthread; ++j) {
2957  NetCvodeThreadData& d = p[j];
2958  for (i = 0; i < d.nlcv_; ++i) {
2959  if (d.lcv_[i].ctd_[0].watch_list_) {
2960  d.lcv_[i].ctd_[0].watch_list_->RemoveAll();
2961  }
2962  }
2963  }
2964  }
2965 }
2966 
2968  double md = 1e9;
2969  for (auto it = dil_.rbegin(); it != dil_.rend(); ++it) {
2970  NetCon* d = *it;
2971  if (md > d->delay_) {
2972  md = d->delay_;
2973  }
2974  }
2975  return md;
2976 }
2977 
2978 void NetCvode::deliver_events(double til, NrnThread* nt) {
2979 //printf("deliver_events til %20.15g\n", til);
2980  p[nt->id].enqueue(this, nt);
2981  while(deliver_event(til, nt)) {
2982  ;
2983  }
2984 }
2985 
2986 static IvocVect* peqvec; //if not nil then the sorted times on the event queue.
2987 static void peq(const TQItem*, int);
2988 static void peq(const TQItem* q, int) {
2989  if (peqvec) {
2990  peqvec->push_back(q->t_);
2991  }else{
2992  DiscreteEvent* d = (DiscreteEvent*)q->data_;
2993  d->pr("", q->t_, net_cvode_instance);
2994  }
2995 }
2996 
2998  // dangerous since many events can go out of existence after
2999  // a simulation and before NetCvode::clear at the next initialization
3000  if (ifarg(1)) {
3001  peqvec = vector_arg(1);
3002  peqvec->resize(0);
3003  }
3004  p[0].tqe_->forall_callback(peq);
3005  peqvec = nil;
3006 }
3007 
3008 static int event_info_type_;
3011 static OcList* event_info_list_; // netcon or point_process
3012 
3013 static void event_info_callback(const TQItem*, int);
3014 static void event_info_callback(const TQItem* q, int) {
3015  DiscreteEvent* d = (DiscreteEvent*)q->data_;
3016  NetCon* nc;
3017  PreSyn* ps;
3018  SelfEvent* se;
3019  int n = event_info_tvec_->size();
3020  switch(d->type()) {
3021  case NetConType:
3022  if (event_info_type_ == NetConType) {
3023  nc = (NetCon*)d;
3024  event_info_tvec_->push_back(q->t_);
3025  event_info_list_->append(nc->obj_);
3026  }
3027  break;
3028  case SelfEventType:
3029  if (event_info_type_ == SelfEventType) {
3030  se = (SelfEvent*)d;
3031  event_info_tvec_->push_back(q->t_);
3032  event_info_flagvec_->push_back(se->flag_);
3033  event_info_list_->append(se->target_->ob);
3034  }
3035  break;
3036  case PreSynType:
3037  if (event_info_type_ == NetConType) {
3038  ps = (PreSyn*)d;
3039  for (auto it = ps->dil_.rbegin(); it != ps->dil_.rend(); ++it) {
3040  nc = *it;
3041  double td = nc->delay_ - ps->delay_;
3042  event_info_tvec_->push_back(q->t_ + td);
3043  event_info_list_->append(nc->obj_);
3044  ++n;
3045  }
3046  }
3047  break;
3048  }
3049 }
3050 
3052  // dangerous since many events can go out of existence after
3053  // a simulation and before NetCvode::clear at the next initialization
3054  int i = 1;
3055  event_info_type_ = (int)chkarg(i++, 2, 3);
3056  event_info_tvec_ = vector_arg(i++);
3057  event_info_tvec_->resize(0);
3058  if (event_info_type_ == SelfEventType) {
3059  event_info_flagvec_ = vector_arg(i++);
3060  event_info_flagvec_->resize(0);
3061  }
3062  Object* o = *hoc_objgetarg(i++);
3063  check_obj_type(o, "List");
3064  event_info_list_ = (OcList*)o->u.this_pointer;
3065  event_info_list_->remove_all();
3066  p[0].tqe_->forall_callback(event_info_callback);
3067 }
3068 
3069 void DiscreteEvent::send(double tt, NetCvode* ns, NrnThread* nt) {
3070  STATISTICS(discretevent_send_);
3071  ns->event(tt, this, nt);
3072 }
3073 
3074 void DiscreteEvent::deliver(double tt, NetCvode* ns, NrnThread* nt) {
3075  STATISTICS(discretevent_deliver_);
3076 }
3077 
3079 
3081  STATISTICS(discretevent_deliver_);
3082 }
3083 
3084 void DiscreteEvent::pr(const char* s, double tt, NetCvode* ns) {
3085  Printf("%s DiscreteEvent %.15g\n", s, tt);
3086 }
3087 
3088 void NetCon::send(double tt, NetCvode* ns, NrnThread* nt) {
3089  if (active_ && target_) {
3090  assert(PP2NT(target_) == nt);
3091  STATISTICS(netcon_send_active_);
3092 #if BBTQ == 5
3093  ns->bin_event(tt, this, PP2NT(target_));
3094 #else
3095  ns->event(tt, this, PP2NT(target_));
3096 #endif
3097  }else{
3098  STATISTICS(netcon_send_inactive_);
3099  }
3100 }
3101 
3102 void NetCon::deliver(double tt, NetCvode* ns, NrnThread* nt) {
3103  assert(target_);
3104  int type = target_->prop->type;
3105  std::string ss("net-receive-");
3106  ss += memb_func[type].sym->name;
3107  nrn::Instrumentor::phase p_get_pnt_receive(ss.c_str());
3108  if (PP2NT(target_) != nt) {
3109  Printf("NetCon::deliver nt=%d target=%d\n", nt->id, PP2NT(target_)->id);
3110  }
3111  assert(PP2NT(target_) == nt);
3112  Cvode* cv = (Cvode*)target_->nvi_;
3114  TQItem** pq = (TQItem**)(&target_->prop->dparam[nrn_artcell_qindex_[type]]._pvoid);
3115  TQItem* q;
3116  while ((q = *(pq)) != nil && q->t_ < tt) {
3117  double t1 = q->t_;
3118  SelfEvent* se = (SelfEvent*)ns->p[nt->id].selfqueue_->remove(q);
3119 //printf("%d NetCon::deliver %g , earlier selfevent at %g\n", nrnmpi_myid, tt, q->t_);
3120  se->deliver(t1, ns, nt);
3121  }
3122  }
3123  if (cvode_active_ && cv) {
3124  ns->local_retreat(tt, cv);
3125  cv->set_init_flag();
3126  }else{
3127 // no interpolation necessary for local step method and ARTIFICIAL_CELL
3128  nt->_t = tt;
3129  }
3130 
3131 //printf("NetCon::deliver t=%g tt=%g %s\n", t, tt, hoc_object_name(target_->ob));
3132  STATISTICS(netcon_deliver_);
3133  POINT_RECEIVE(type, target_, weight_, 0);
3134  if (errno) {
3135  if (nrn_errno_check(type)) {
3136 hoc_warning("errno set during NetCon deliver to NET_RECEIVE", (char*)0);
3137  }
3138  }
3139 }
3140 
3141 NrnThread* NetCon::thread() { return PP2NT(target_); }
3142 
3143 void NetCon::pgvts_deliver(double tt, NetCvode* ns) {
3144  assert(target_);
3145  int type = target_->prop->type;
3146  STATISTICS(netcon_deliver_);
3147  POINT_RECEIVE(type, target_, weight_, 0);
3148  if (errno) {
3149  if (nrn_errno_check(type)) {
3150 hoc_warning("errno set during NetCon deliver to NET_RECEIVE", (char*)0);
3151  }
3152  }
3153 }
3154 
3155 void NetCon::pr(const char* s, double tt, NetCvode* ns) {
3156  Printf("%s %s", s, hoc_object_name(obj_));
3157  if (src_) {
3158  Printf(" src=%s", src_->osrc_ ? hoc_object_name(src_->osrc_):secname(src_->ssrc_));
3159  }else{
3160  Printf(" src=nil");
3161  }
3162  Printf(" target=%s %.15g\n", (target_?hoc_object_name(target_->ob):"nil"), tt);
3163 }
3164 
3165 void PreSyn::send(double tt, NetCvode* ns, NrnThread* nt) {
3166  int i;
3167  record(tt);
3168 #ifndef USENCS
3169  if (use_min_delay_) {
3170  STATISTICS(presyn_send_mindelay_);
3171 #if BBTQ == 3 || BBTQ == 4
3172  ns->fifo_event(tt+delay_, this);
3173 #else
3174 #if BBTQ == 5
3175  for (i=0; i < nrn_nthread; ++i) {
3176  if (nt->id == i) {
3177  ns->bin_event(tt+delay_, this, nt);
3178  }else{
3179  ns->p[i].interthread_send(tt+delay_, this, nrn_threads + i);
3180  }
3181  }
3182 #else
3183  ns->event(tt+delay_, this);
3184 #endif
3185 #endif
3186  }else{
3187  STATISTICS(presyn_send_direct_);
3188  for (auto it = dil_.rbegin(); it != dil_.rend(); ++it) {
3189  NetCon* d = *it;
3190  if (d->active_ && d->target_) {
3191  NrnThread* n = PP2NT(d->target_);
3192 #if BBTQ == 5
3193  if (nt == n) {
3194  ns->bin_event(tt + d->delay_, d, n);
3195  }else{
3196  ns->p[n->id].interthread_send(tt + d->delay_, d, n);
3197  }
3198 #else
3199  ns->event(tt + d->delay_, d, PP2NT(d->target_));
3200 #endif
3201  }
3202  }
3203  }
3204 #endif //ndef USENCS
3205 #if USENCS || NRNMPI
3206  if (output_index_ >= 0) {
3207 #if BGPDMA
3208  if (use_bgpdma_) {
3209  bgp_dma_send(this, tt);
3210  }else{
3211 #endif //BGPDMA
3212 
3213 #if NRNMPI
3214  if (nrn_use_localgid_) {
3215  nrn_outputevent(localgid_, tt);
3216  }else
3217 #endif //NRNMPI
3218  nrn2ncs_outputevent(output_index_, tt);
3219 #if BGPDMA
3220  }
3221 #endif //BGPDMA
3222 #if NRN_MUSIC
3223  if (music_port_) {
3224  nrnmusic_injectlist(music_port_, tt);
3225  }
3226 #endif // NRN_MUSIC
3227  }
3228 #endif //USENCS || NRNMPI
3229 }
3230 
3231 void PreSyn::deliver(double tt, NetCvode* ns, NrnThread* nt) {
3232  if (qthresh_) {
3233  // the thread is the one that owns the PreSyn
3234  assert(nt == nt_);
3235  qthresh_ = nil;
3236 //printf("PreSyn::deliver %s condition event tt=%20.15g\n", ssrc_?secname(ssrc_):"", tt);
3237  STATISTICS(deliver_qthresh_);
3238  send(tt, ns, nt);
3239  return;
3240  }
3241  // the thread is the one that owns the targets
3242  STATISTICS(presyn_deliver_netcon_);
3243  for (const auto& d : dil_) {
3244  if (d->active_ && d->target_ && PP2NT(d->target_) == nt) {
3245  double dtt = d->delay_ - delay_;
3246  if (dtt == 0.) {
3247  STATISTICS(presyn_deliver_direct_);
3248  STATISTICS(deliver_cnt_);
3249  d->deliver(tt, ns, nt);
3250  }else if (dtt < 0.) {
3251 hoc_execerror("internal error: Source delay is > NetCon delay", 0);
3252  }else{
3253  STATISTICS(presyn_deliver_ncsend_);
3254  ns->event(tt + dtt, d, nt);
3255  }
3256  }
3257  }
3258 }
3259 
3260 // used by bbsavestate since during restore, some NetCon spikes may
3261 // have already been delivered while others need to be delivered in
3262 // the future. Not implemented fof qthresh_ case. No statistics.
3263 void PreSyn::fanout(double td, NetCvode* ns, NrnThread* nt) {
3264  for (const auto& d : dil_) {
3265  if (d->active_ && d->target_ && PP2NT(d->target_) == nt) {
3266  double dtt = d->delay_ - delay_;
3267  ns->bin_event(td + dtt, d, nt);
3268  }
3269  }
3270 }
3271 
3272 NrnThread* PreSyn::thread() { return nt_; }
3273 
3274 void PreSyn::pgvts_deliver(double tt, NetCvode* ns) {
3275  NrnThread* nt = 0;
3276  assert(0);
3277  if (qthresh_) {
3278  qthresh_ = nil;
3279 //printf("PreSyn::deliver %s condition event tt=%20.15g\n", ssrc_?secname(ssrc_):"", tt);
3280  STATISTICS(deliver_qthresh_);
3281  send(tt, ns, nt);
3282  return;
3283  }
3284  STATISTICS(presyn_deliver_netcon_);
3285  for (const auto& d : dil_) {
3286  if (d->active_ && d->target_) {
3287  double dtt = d->delay_ - delay_;
3288  if (0 && dtt == 0.) {
3289  STATISTICS(presyn_deliver_direct_);
3290  STATISTICS(deliver_cnt_);
3291  d->deliver(tt, ns, nt);
3292  }else if (dtt < 0.) {
3293 hoc_execerror("internal error: Source delay is > NetCon delay", 0);
3294  }else{
3295  STATISTICS(presyn_deliver_ncsend_);
3296  ns->event(tt + dtt, d, nt);
3297  }
3298  }
3299  }
3300 }
3301 
3302 void PreSyn::pr(const char* s, double tt, NetCvode* ns) {
3303  Printf("%s", s);
3304  Printf(" PreSyn src=%s", osrc_ ? hoc_object_name(osrc_):secname(ssrc_));
3305  Printf(" %.15g\n", tt);
3306 }
3307 
3310 
3312 // pr("savestate_save", 0, net_cvode_instance);
3313  SelfEvent* se = new SelfEvent();
3314  se->flag_ = flag_;
3315  se->target_ = target_;
3316  se->weight_ = weight_;
3317  se->movable_ = movable_;
3318  return se;
3319 }
3320 
3322 // pr("savestate_restore", tt, nc);
3323  net_send(movable_, weight_, target_, tt, flag_);
3324 }
3325 
3327  SelfEvent* se = new SelfEvent();
3328  char buf[300];
3329  char ppname[200];
3330  int ppindex, ncindex, moff, pptype, iml;
3331  double flag;
3332  Object* obj;
3333  nrn_assert(fgets(buf, 300, f));
3334  nrn_assert(sscanf(buf, "%s %d %d %d %d %lf\n", ppname, &ppindex, &pptype, &ncindex, &moff, &flag) == 6);
3335 #if 0
3336  // use of hoc_name2obj is way too inefficient
3337  se->target_ = ob2pntproc(hoc_name2obj(ppname, ppindex));
3338 #else
3339  se->target_ = SelfEvent::index2pp(pptype, ppindex);
3340 #endif
3341  se->weight_ = nil;
3342  if (ncindex >= 0) {
3343 #if 0
3344  // extremely inefficient. There are a LOT of NetCon.
3345  obj = hoc_name2obj("NetCon", ncindex);
3346  assert(obj);
3347  NetCon* nc = (NetCon*)obj->u.this_pointer;
3348 #else
3349  NetCon* nc = NetConSave::index2netcon(ncindex);
3350 #endif
3351  se->weight_ = nc->weight_;
3352  }
3353  se->flag_ = flag;
3354  se->movable_ = nil;
3355  if (moff >= 0) {
3356  se->movable_ = &(se->target_->prop->dparam[moff]._pvoid);
3357  }
3358  return se;
3359 }
3360 
3361 std::unique_ptr<SelfEventPPTable> SelfEvent::sepp_;
3362 
3363 Point_process* SelfEvent::index2pp(int type, int oindex) {
3364  // code the type and object index together
3365  if (!sepp_) {
3366  int i;
3367  sepp_.reset(new SelfEventPPTable());
3368  sepp_->reserve(211);
3369  // should only be the ones that call net_send
3370  for (i=0; i < n_memb_func; ++i) if (pnt_receive[i]) {
3371  hoc_List* hl = nrn_pnt_template_[i]->olist;
3372  hoc_Item* q;
3373  ITERATE (q, hl) {
3374  Object* o = OBJ(q);
3375  (*sepp_)[i + n_memb_func * o->index] = ob2pntproc(o);
3376  }
3377  }
3378  }
3379  const auto& iter = sepp_->find(type + n_memb_func*oindex);
3380  nrn_assert(iter != sepp_->end());
3381  return iter->second;
3382 }
3383 
3385  sepp_.reset();
3386 }
3387 
3389  fprintf(f, "%d\n", SelfEventType);
3390  int moff = -1;
3391  if (movable_) {
3392  moff = (Datum*)(movable_) - target_->prop->dparam;
3393  assert(movable_ == &(target_->prop->dparam[moff]._pvoid));
3394  }
3395 
3396  int ncindex = -1;
3397  // find the NetCon index for weight_
3398  if (weight_) {
3399  NetCon* nc = NetConSave::weight2netcon(weight_);
3400  assert(nc);
3401  ncindex = nc->obj_->index;
3402  }
3403 
3404  fprintf(f, "%s %d %d %d %d %g\n",
3405  target_->ob->ctemplate->sym->name, target_->ob->index,
3406  target_->prop->type,
3407  ncindex,
3408  moff, flag_
3409  );
3410 }
3411 
3412 void SelfEvent::deliver(double tt, NetCvode* ns, NrnThread* nt) {
3413  Cvode* cv = (Cvode*)target_->nvi_;
3414  int type = target_->prop->type;
3415  assert(nt == PP2NT(target_));
3416  if (nrn_use_selfqueue_ && nrn_is_artificial_[type]) { // handle possible earlier flag=1 self event
3417  if (flag_ == 1.0) { *movable_ = 0; }
3418  TQItem* q;
3419  while ((q = (TQItem*)(*movable_)) != 0 && q->t_ <= tt) {
3420 //printf("handle earlier %g selfqueue event from within %g SelfEvent::deliver\n", q->t_, tt);
3421  double t1 = q->t_;
3422  SelfEvent* se = (SelfEvent*)ns->p[nt->id].selfqueue_->remove(q);
3423  PP2t(target_) = t1;
3424  se->call_net_receive(ns);
3425  }
3426  }
3427  if (cvode_active_ && cv) {
3428  ns->local_retreat(tt, cv);
3429  cv->set_init_flag();
3430  }else{
3431  PP2t(target_) = tt;
3432  }
3433 //printf("SelfEvent::deliver t=%g tt=%g %s\n", PP2t(target), tt, hoc_object_name(target_->ob));
3434  call_net_receive(ns);
3435 }
3436 
3437 NrnThread* SelfEvent::thread() { return PP2NT(target_); }
3438 
3439 void SelfEvent::pgvts_deliver(double tt, NetCvode* ns) {
3440  call_net_receive(ns);
3441 }
3443  STATISTICS(selfevent_deliver_);
3444  POINT_RECEIVE(target_->prop->type, target_, weight_, flag_);
3445  if (errno) {
3446  if (nrn_errno_check(target_->prop->type)) {
3447 hoc_warning("errno set during SelfEvent deliver to NET_RECEIVE", (char*)0);
3448  }
3449  }
3450  NetCvodeThreadData& nctd = ns->p[PP2NT(target_)->id];
3451  --nctd.unreffed_event_cnt_;
3452  nctd.sepool_->hpfree(this);
3453 }
3454 
3455 void SelfEvent::pr(const char* s, double tt, NetCvode* ns) {
3456  Printf("%s", s);
3457  Printf(" SelfEvent target=%s %.15g flag=%g\n", hoc_object_name(target_->ob), tt, flag_);
3458 }
3459 
3461  plr_->frecord_init(q);
3462 }
3463 
3464 void PlayRecordEvent::deliver(double tt, NetCvode* ns, NrnThread* nt) {
3465  if (plr_->cvode_ && plr_->cvode_->nth_) {
3466  assert(nt == plr_->cvode_->nth_);
3467  ns->local_retreat(tt, plr_->cvode_);
3468  }
3469  STATISTICS(playrecord_deliver_);
3470  plr_->deliver(tt, ns);
3471 }
3472 
3473 NrnThread* PlayRecordEvent::thread() { return nrn_threads + plr_->ith_; }
3474 
3475 void PlayRecordEvent::pr(const char* s, double tt, NetCvode* ns) {
3476  Printf("%s PlayRecordEvent %.15g ", s, tt);
3477  plr_->pr();
3478 }
3479 
3480 // For localstep makes sure all cvode instances are at this time and
3481 // makes sure the continuous record records values at this time.
3484 
3485 void TstopEvent::deliver(double tt, NetCvode* ns, NrnThread* nt) {
3486  STATISTICS(discretevent_deliver_);
3487  ns->handle_tstop_event(tt, nt);
3488 }
3489 void TstopEvent::pgvts_deliver(double tt, NetCvode* ns) {
3490  assert(0);
3491  deliver(tt, ns, 0);
3492 }
3493 
3494 void TstopEvent::pr(const char* s, double tt, NetCvode* ns) {
3495  Printf("%s TstopEvent %.15g\n", s, tt);
3496 }
3497 
3499 // pr("savestate_save", 0, net_cvode_instance);
3500  if (this != tstop_event_) {
3501  hoc_execerror("TstopEvent::savestate_save:", " is not the tstop_event_");
3502  }
3503  return new TstopEvent();
3504 }
3505 
3507 // pr("savestate_restore", tt, nc);
3508  Printf("tstop_event_ onto queue\n");
3509  nc->tstop_event(tt);
3510 }
3511 
3513  return new TstopEvent();
3514 }
3515 
3517  fprintf(f, "%d\n", TstopEventType);
3518 }
3519 
3520 #include <hocevent.cpp>
3521 
3522 void NetCvode::local_retreat(double t, Cvode* cv) {
3523  if (!cvode_active_) { return; }
3524  TQueue* tq = p[cv->nth_ ? cv->nth_->id : 0].tq_;
3525  if (tq) {
3526 #if PRINT_EVENT
3527  if (print_event_) {
3528 Printf("microstep local retreat from %g (cvode_%p is at %g) for event onset=%g\n", cv->tqitem_->t_, cv, cv->t_, t);
3529  }
3530 #endif
3531  cv->interpolate(t);
3532  tq->move(cv->tqitem_, t);
3533 #if PRINT_EVENT
3534  if (print_event_ > 1) {
3535 Printf("after target solve time for %p is %g , dt=%g\n", cv, cv->time(), nt_dt);
3536  }
3537 #endif
3538  }else{
3539  assert(t == cv->t_ || ( cv->tstop_begin_ <= t && t <= cv->tstop_end_));
3540  }
3541 }
3542 
3543 void NetCvode::retreat(double t, Cvode* cv) {
3544  if (!cvode_active_) { return; }
3545  TQueue* tq = p[cv->nth_ ? cv->nth_->id : 0].tq_;
3546 #if PRINT_EVENT
3547  if (print_event_) {
3548 Printf("microstep retreat from %g (cvode_%p is at %g) for event onset=%g\n",
3549  tq ? cv->tqitem_->t_ : cv->t_, cv, cv->t_, t);
3550  }
3551 #endif
3552  cv->interpolate(t);
3553  if (tq) {
3554  tq->move(cv->tqitem_, t);
3555  }
3556 #if PRINT_EVENT
3557  if (print_event_ > 1) {
3558 Printf("after target solve time for %p is %g , dt=%g\n", cv, cv->time(), dt);
3559  }
3560 #endif
3561 }
3562 
3563 #if USENEOSIM
3564 
3565 bool neosim_deliver_self_events(TQueue* tqe, double til);
3566 bool neosim_deliver_self_events(TQueue* tqe, double til) {
3567  bool b;
3568  TQItem* q;
3569  DiscreteEvent* d;
3570  b = false;
3571  while (tqe->least_t() <= til + .5e-8) {
3572  b = true;
3573  q = tqe->least();
3574  t = q->t_;
3575  d = (DiscreteEvent*)q->data_;
3576  assert(d->type() == SelfEventType);
3577  tqe->remove(q);
3578  d->deliver(t, net_cvode_instance);
3579  }
3580 }
3581 
3582 void neosim2nrn_advance(void* e, void* v, double tout) {
3583  neosim_entity_ = e;
3584  NetCon* d = (NetCon*)v;
3585  TQueue* tqe;
3586 
3587  // now can integrate to tout since it is guaranteed there will
3588  // be no further real events to this cell before tout.
3589  // but we must handle self events. The implementation is
3590  // analogous to the NetCvode::solve with single and tout
3591  Cvode* cv = (Cvode*)d->target_->nvi_; // so self event from INITIAL block
3592  tqe = cv->neosim_self_events_;
3593  // not a bug even if there is no BREAKPOINT block. I.e.
3594  // artificial cells will work.
3595  t = cv->time();
3596  while (tout > t) {
3597  do {
3598  cv->check_deliver();
3599  }while (neosim_deliver_self_events(tqe, t));
3600  cv->solve();
3601  }
3602  cv->interpolate(tout);
3603  cv->check_deliver();
3604 }
3605 
3606 void neosim2nrn_deliver(void* e, void* v) {
3607  neosim_entity_ = e;
3608  NetCon* d = (NetCon*)v;
3609  Cvode* cv = (Cvode*)d->target_->nvi_;
3610  d->deliver(cv->t_, net_cvode_instance);
3611 }
3612 
3613 #endif
3614 
3615 //parallel global variable time-step
3616 int NetCvode::pgvts(double tstop) {
3617  int err = NVI_SUCCESS;
3618  double tt = nt_t;
3619  while (tt < tstop && !stoprun && err == NVI_SUCCESS) {
3620  err = pgvts_event(tt);
3621  }
3622  return err;
3623 }
3624 
3625 // parallel global variable time-step event handling
3626 // return is what cvode call to make and the value of tt to make it at
3627 // in response to the next global event. We try to do only one
3628 // allreduce for a given event. Since all processes have to stay together
3629 // with respect to cvode, we have to factor out those calls from the
3630 // classical DiscreteEvent::deliver methods. I.e. deliver can only
3631 // deliver an event, it cannot interpolate, etc.
3632 // Assume events are sparse and handle them one at a time.
3633 int NetCvode::pgvts_event(double& tt) {
3634  int rank, op, err, init;
3635  DiscreteEvent* de;
3636  assert(gcv_);
3637  de = pgvts_least(tt, op, init);
3638  err = pgvts_cvode(tt, op);
3639  if (init) { gcv_->set_init_flag(); }
3640  if (de) { // handle the event and others just like it
3641  de->pgvts_deliver(tt, this);
3642  while (p[0].tqe_->least_t() == tt) {
3643  TQItem* q = p[0].tqe_->least();
3644  de = (DiscreteEvent*)q->data_;
3645  int i1;
3646  if (de->pgvts_op(i1) == op && i1 == init) {
3647  p[0].tqe_->remove(q);
3648  de->pgvts_deliver(tt, this);
3649  }else{
3650  break;
3651  }
3652  }
3653  }
3654  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
3655  return err;
3656 }
3657 
3658 DiscreteEvent* NetCvode::pgvts_least(double& tt, int& op, int& init) {
3659  DiscreteEvent* de = nil;
3660 #if PARANEURON
3661  TQItem* q = nil;
3662  if (gcv_->initialize_ && p[0].tqe_->least_t() > gcv_->t_) {
3663  tt = gcv_->t_;
3664  op = 3;
3665  init = 0;
3666  }else if (gcv_->tn_ < p[0].tqe_->least_t()) {
3667  tt = gcv_->tn_;
3668  op = 1;
3669  init = 0;
3670  }else{
3671  // If there are several events at the same time we need the
3672  // highest priority (in particular, NetParEvent last).
3673  // This is due to the fact that NetParEvent.deliver
3674  // handles all the events at that time so there better not
3675  // be any after it on the queue.
3676  q = p[0].tqe_->least();
3677  if (q) {
3678  de = (DiscreteEvent*)q->data_;
3679  tt = q->t_;
3680  op = de->pgvts_op(init);
3681  if (op == 4) { // is there another event at the same time?
3682  TQItem* q2 = p[0].tqe_->second_least(tt);
3683  if (q2) {
3684  q = q2;
3685  de = (DiscreteEvent*)q2->data_;
3686  op = de->pgvts_op(init);
3687  assert(op != 4);
3688 //printf("%d Type %d event after NetParEvent with deliver %g and t=%g\n", nrnmpi_myid, de->type(), tt, gcv_->t_);
3689  }
3690  }
3691  }else{
3692  tt = 1e20;
3693  op = 1;
3694  init = 0;
3695  }
3696  }
3697  double ts = tt; int ops = op;
3698  if (nrnmpi_pgvts_least(&tt, &op, &init)) {
3699  if (q) {
3700  p[0].tqe_->remove(q);
3701  }
3702  }else if (op == 4) {//NetParEvent need to be done all together
3703  p[0].tqe_->remove(q);
3704  }else if (ts == tt && q && ops == op) { // safe to do this event as well
3705  p[0].tqe_->remove(q);
3706  }else{
3707  de = nil;
3708  }
3709 #endif
3710  return de;
3711 }
3712 
3713 int NetCvode::pgvts_cvode(double tt, int op) {
3714  int err = NVI_SUCCESS;
3715  // this is the only place where we can enter cvode
3716  switch (op) {
3717  case 1: // advance
3718  if (condition_order() == 1) {
3719  gcv_->check_deliver();
3720  }
3721  gcv_->record_continuous();
3722  err = gcv_->advance_tn();
3723  if (condition_order() == 2) {
3724  gcv_->evaluate_conditions();
3725  }
3726  break;
3727  case 2: // interpolate
3728  err = gcv_->interpolate(tt);
3729  break;
3730  case 3: // initialize
3731  err = gcv_->init(tt);
3732  initialized_ = true;
3733  if (condition_order() == 2) {
3734  gcv_->evaluate_conditions();
3735  }
3736  break;
3737  }
3738  return err;
3739 }
3740 
3742 #if PARANEURON
3743  if ( gcv_) { return gcv_->use_partrans_; } else { return 0; }
3744 #endif
3745  return 0;
3746 }
3747 
3748 void ncs2nrn_integrate(double tstop) {
3749  double ts;
3750  nrn_use_busywait(1); // just a possibility
3751  if (cvode_active_) {
3752 #if PARANEURON
3753  if (net_cvode_instance->use_partrans()) {
3754  net_cvode_instance->pgvts(tstop);
3755  t = nt_t;
3756  dt = nt_dt;
3757  }else
3758 #endif
3759  {
3760  net_cvode_instance->solve(tstop);
3761  t = nt_t;
3762  dt = nt_dt;
3763  }
3764  }else{
3765 #if 1
3766  int n = (int)((tstop - nt_t)/dt + 1e-9);
3767  if (n > 3 && !nrnthread_v_transfer_) {
3769  }else
3770 #endif
3771  {
3772 #if NRNMPI && !defined(USENCS)
3773  ts = tstop - dt;
3774  assert(nt_t <= tstop);
3775  // It may very well be the case that we do not advance at all
3776  while (nt_t <= ts) {
3777 #else
3778  ts = tstop - .5*dt;
3779  while (nt_t < ts) {
3780 #endif
3781  nrn_fixed_step();
3782  if (stoprun) {break;}
3783  }
3784  }
3785  }
3786  // handle all the pending flag=1 self events
3787 for (int i=0; i < nrn_nthread; ++i) { assert(nrn_threads[i]._t == nt_t);}
3789  nrn_use_busywait(0); // certainly not
3790 }
3791 
3793  return p[nt->id].tqe_;
3794 }
3795 
3797 static void* pending_selfqueue(NrnThread* nt) {
3798  nrn_pending_selfqueue(pending_selfqueue_deliver_, nt);
3799  return 0;
3800 }
3801 
3802 void nrn_pending_selfqueue(double tt, NrnThread* nt) {
3803  NetCvodeThreadData& nctd = net_cvode_instance->p[nt->id];
3804  double ts = nt->_t;
3805 // net_cvode_instance->deliver_events(nctd.immediate_deliver_, nt);
3806  SelfQueue* sq = nctd.selfqueue_;
3807  TQItem* q1, *q2;
3808  nctd.immediate_deliver_ = tt;
3809  for (q1 = sq->first(); q1; q1 = q2) {
3810  if (q1->t_ <= tt) {
3811  SelfEvent* se = (SelfEvent*)q1->data_;
3812 //printf("ncs2nrn_integrate %g SelfEvent for %s at %g\n", tstop, hoc_object_name(se->target_->ob), q1->t_);
3813  se->deliver(q1->t_, net_cvode_instance, nt);
3814  // could it add another self-event?, check before removal
3815  q2 = sq->next(q1);
3816  sq->remove(q1);
3817  }else{
3818  q2 = sq->next(q1);
3819  }
3820  }
3821  assert(nctd.tqe_->least_t() >= tt);
3822  nt->_t = ts;
3823  nctd.immediate_deliver_ = -1e100;
3824 }
3825 
3826 // only the main thread can calls this
3827 static void all_pending_selfqueue(double tt) {
3828  if (nrn_use_selfqueue_) {
3830 //for (int i=0; i < nrn_nthread; ++i) { assert(nrn_threads[i]._t == nt_t);}
3831  pending_selfqueue_deliver_ = tt;
3833  }
3834 }
3835 
3836 #if USENCS
3837 
3838 void ncs2nrn_inputevent(int i, double tdeliver) {
3839  NrnThread* nt = nrn_threads;
3840  net_cvode_instance->event(tdeliver, ncs2nrn_input_->item(i), nt);
3841 }
3842 
3843 // hoc tells us which are the input NetCons and which are the
3844 // output NetCons
3845 
3846 void nrn2ncs_netcons() {
3847  int i;
3848  Object* o;
3849  NetCon* nc;
3850  o = *hoc_objgetarg(1);
3851  check_obj_type(o, "List");
3852  OcList* list = (OcList*)(o->u.this_pointer);
3853  if (ncs2nrn_input_) {
3854  for (i=0; i < ncs2nrn_input_->count(); ++i) {
3855  hoc_obj_unref(ncs2nrn_input_->item(i)->obj_);
3856  }
3857  ncs2nrn_input_->remove_all();
3858  }else{
3859  ncs2nrn_input_ = new NetConPList(list->count());
3860 
3861  }
3862  for (i=0; i < list->count(); ++i) {
3863  hoc_obj_ref(list->object(i));
3864  nc = (NetCon*)(list->object(i)->u.this_pointer);
3865  ncs2nrn_input_->append(nc);
3866  }
3867 
3868  o = *hoc_objgetarg(2);
3869  check_obj_type(o, "List");
3870  list = (OcList*)(o->u.this_pointer);
3871  for (i=0; i < list->count(); ++i) {
3872  nc = (NetCon*)(list->object(i)->u.this_pointer);
3873  assert(nc->src_);
3874  nc->src_->output_index_ = i;
3875  }
3876 }
3877 
3878 #endif //USENCS
3879 
3881  int id, j, ii = 0;
3882  if (gcv_) {
3883  gcv_->statistics();
3884  }else{
3885  lvardtloop(id, j) {
3886  if (i < 0 || ii++ == i) {
3887  p[id].lcv_[j].statistics();
3888  }
3889  }
3890  }
3891  Printf("NetCon active=%lu (not sent)=%lu delivered=%lu\n", NetCon::netcon_send_active_, NetCon::netcon_send_inactive_, NetCon::netcon_deliver_);
3892  Printf("Condition O2 thresh detect=%lu via init=%lu effective=%lu abandoned=%lu (unnecesarily=%lu init+=%lu init-=%lu above=%lu below=%lu)\n",ConditionEvent::send_qthresh_, ConditionEvent::init_above_, ConditionEvent::deliver_qthresh_, ConditionEvent::abandon_, ConditionEvent::eq_abandon_, ConditionEvent::abandon_init_above_, ConditionEvent::abandon_init_below_, ConditionEvent::abandon_above_, ConditionEvent::abandon_below_);
3893  Printf("PreSyn send: mindelay=%lu direct=%lu\n", PreSyn::presyn_send_mindelay_, PreSyn::presyn_send_direct_);
3894  Printf("PreSyn deliver: O2 thresh=%lu NetCon=%lu (send=%lu deliver=%lu)\n", ConditionEvent::deliver_qthresh_, PreSyn::presyn_deliver_netcon_, PreSyn::presyn_deliver_ncsend_, PreSyn::presyn_deliver_direct_);
3895  Printf("SelfEvent send=%lu move=%lu deliver=%lu\n", SelfEvent::selfevent_send_, SelfEvent::selfevent_move_, SelfEvent::selfevent_deliver_);
3896  Printf("Watch send=%lu deliver=%lu\n", WatchCondition::watch_send_, WatchCondition::watch_deliver_);
3897  Printf("PlayRecord send=%lu deliver=%lu\n", PlayRecordEvent::playrecord_send_, PlayRecordEvent::playrecord_deliver_);
3898  Printf("HocEvent send=%lu deliver=%lu\n", HocEvent::hocevent_send_, HocEvent::hocevent_deliver_);
3899  Printf("SingleEvent deliver=%lu move=%lu\n", KSSingle::singleevent_deliver_, KSSingle::singleevent_move_);
3900  Printf("DiscreteEvent send=%lu deliver=%lu\n", DiscreteEvent::discretevent_send_, DiscreteEvent::discretevent_deliver_);
3901  Printf("%lu total events delivered net_event=%lu\n", deliver_cnt_, net_event_cnt_);
3902  Printf("Discrete event TQueue\n");
3903  p[0].tqe_->statistics();
3904  if (p[0].tq_) {
3905  Printf("Variable step integrator TQueue\n");
3906  p[0].tq_->statistics();
3907  }
3908 }
3909 
3911  Vect* v = vector_arg(1);
3912  v->resize(11);
3913  double* d = vector_vec(v);
3914  int i, j, n = 0;
3915  if (gcv_) {
3916  n += gcv_->neq_;
3917  }else{
3918  lvardtloop(i,j) {
3919  n += p[i].lcv_[j].neq_;
3920  }
3921  }
3922  d[0] = n;
3923  Symbol* nc = hoc_lookup("NetCon");
3924  d[1] = nc->u.ctemplate->count;
3925  d[2] = deliver_cnt_;
3926  d[3] = NetCon::netcon_deliver_;
3927  d[4] = PreSyn::presyn_send_mindelay_ + PreSyn::presyn_send_direct_;
3931  // should do all threads
3932  p[0].tqe_->spike_stat(d+8);
3933 }
3934 
3936  int i, j;
3937  fornetcon_prepare();
3938  if (nrn_modeltype() == 0) {
3939  delete_list();
3940  }else{
3941  init_global();
3942  if (cvode_active_) {
3943  if (matrix_change_cnt_ != nrn_matrix_cnt_) {
3944  structure_change();
3945  matrix_change_cnt_ = nrn_matrix_cnt_;
3946  }
3947  if (gcv_) {
3948  gcv_->use_daspk_ = nrn_use_daspk_;
3949  gcv_->init_prepare();
3950  // since there may be Vector.play events and INITIAL send events
3951  // at time 0 before actual initialization of integrators.
3952  gcv_->can_retreat_ = false;
3953  }else{
3954  lvardtloop(i,j) {
3955  Cvode& cv = p[i].lcv_[j];
3957  cv.init_prepare();
3958  cv.can_retreat_ = false;
3959  }
3960  }
3961  }
3962  }
3963  if (playrec_change_cnt_ != structure_change_cnt_) {
3964  playrec_setup();
3965  }
3966 }
3967 
3968 void NetCvode::re_init(double t) {
3969  int i, j, k, l;
3970  if (nrn_modeltype() == 0) {
3971  if (gcv_) {
3972  gcv_->t_ = t; gcv_->tn_ = t;
3973  }else{
3974  lvardtloop(i,j) {
3975  Cvode& cv = p[i].lcv_[j];
3976  cv.t_ = t; cv.tn_ = t;
3977  }
3978  }
3979  return;
3980  }
3981  double dtsav = nt_dt;
3982  solver_prepare();
3983  if (gcv_) {
3984  gcv_->stat_init();
3985  gcv_->init(t);
3986  if (condition_order() == 2) {
3987  gcv_->evaluate_conditions();
3988  }
3989  }else{
3990  lvardtloop(i, j) {
3991  Cvode& cv = p[i].lcv_[j];
3992  cv.stat_init();
3993  cv.init(t);
3994  cv.tqitem_->t_ = t;
3995  if (condition_order() == 2) {
3996  cv.evaluate_conditions();
3997  }
3998  }
3999  }
4000  nt_dt = dtsav;
4001 }
4002 
4004  NrnThread* nt;
4005  NrnThreadMembList* tml;
4006  if (fornetcon_change_cnt_ == structure_change_cnt) { return; }
4007  fornetcon_change_cnt_ = structure_change_cnt;
4008  if (nrn_fornetcon_cnt_ == 0) { return; }
4009  int i, j;
4010  // initialize a map from type to dparam index, -1 means no FOR_NETCONS statement
4011  int* t2i = new int[n_memb_func];
4012  for (i=0; i < n_memb_func; ++i) { t2i[i] = -1; }
4013  // create ForNetConsInfo in all the relevant point processes
4014  // and fill in the t2i map.
4015  for (i = 0; i < nrn_fornetcon_cnt_; ++i) {
4016  int index = nrn_fornetcon_index_[i];
4017  int type = nrn_fornetcon_type_[i];
4018  t2i[type] = index;
4019  if (nrn_is_artificial_[type]) {
4020  Memb_list* m = memb_list + type;
4021  for (j = 0; j < m->nodecount; ++j) {
4022  void** v = &(m->pdata[j][index]._pvoid);
4024  ForNetConsInfo* fnc = new ForNetConsInfo;
4025  *v = fnc;
4026  fnc->argslist = 0;
4027  fnc->size = 0;
4028  }
4029  }else{
4030  FOR_THREADS(nt) for(tml = nt->tml; tml; tml = tml->next) if (tml->index == type) {
4031  Memb_list* m = tml->ml;
4032  for (j = 0; j < m->nodecount; ++j) {
4033  void** v = &(m->pdata[j][index]._pvoid);
4035  ForNetConsInfo* fnc = new ForNetConsInfo;
4036  *v = fnc;
4037  fnc->argslist = 0;
4038  fnc->size = 0;
4039  }
4040  }
4041  }
4042  }
4043  // two loops over all netcons. one to count, one to fill in argslist
4044  // count
4045  hoc_Item* q;
4046  if (psl_) ITERATE(q, psl_) {
4047  PreSyn* ps = (PreSyn*)VOIDITM(q);
4048  const NetConPList& dil = ps->dil_;
4049  for (const auto& d1 : dil) {
4050  Point_process* pnt = d1->target_;
4051  if (pnt && t2i[pnt->prop->type] > -1) {
4052 ForNetConsInfo* fnc = (ForNetConsInfo*)pnt->prop->dparam[t2i[pnt->prop->type]]._pvoid;
4053  assert(fnc);
4054  fnc->size += 1;
4055  }
4056  }
4057  }
4058 
4059  // allocate argslist space and initialize for another count
4060  for (i = 0; i < nrn_fornetcon_cnt_; ++i) {
4061  int index = nrn_fornetcon_index_[i];
4062  int type = nrn_fornetcon_type_[i];
4063  if (nrn_is_artificial_[type]) {
4064  Memb_list* m = memb_list + type;
4065  for (j = 0; j < m->nodecount; ++j) {
4066  ForNetConsInfo* fnc = (ForNetConsInfo*)m->pdata[j][index]._pvoid;
4067  if (fnc->size > 0) {
4068  fnc->argslist = new double*[fnc->size];
4069  fnc->size = 0;
4070  }
4071  }
4072  }else{
4073  FOR_THREADS(nt) for(tml = nt->tml; tml; tml = tml->next) if (tml->index == nrn_fornetcon_type_[i]) {
4074  Memb_list* m = tml->ml;
4075  for (j = 0; j < m->nodecount; ++j) {
4076  ForNetConsInfo* fnc = (ForNetConsInfo*)m->pdata[j][index]._pvoid;
4077  if (fnc->size > 0) {
4078  fnc->argslist = new double*[fnc->size];
4079  fnc->size = 0;
4080  }
4081  }
4082  }
4083  }
4084  }
4085  // fill in argslist and count again
4086  if (psl_) ITERATE(q, psl_) {
4087  PreSyn* ps = (PreSyn*)VOIDITM(q);
4088  const NetConPList& dil = ps->dil_;
4089  for (const auto& d1 : dil) {
4090  Point_process* pnt = d1->target_;
4091  if (pnt && t2i[pnt->prop->type] > -1) {
4092 ForNetConsInfo* fnc = (ForNetConsInfo*)pnt->prop->dparam[t2i[pnt->prop->type]]._pvoid;
4093  fnc->argslist[fnc->size] = d1->weight_;
4094  fnc->size += 1;
4095  }
4096  }
4097  }
4098  delete [] t2i;
4099 }
4100 
4101 extern "C" int _nrn_netcon_args(void* v, double*** argslist) {
4102  ForNetConsInfo* fnc = (ForNetConsInfo*)v;
4103  assert(fnc);
4104  *argslist = fnc->argslist;
4105  return fnc->size;
4106 }
4107 
4108 extern "C" void _nrn_free_fornetcon(void** v) {
4109  ForNetConsInfo* fnc = (ForNetConsInfo*)(*v);
4110  if (fnc) {
4111  if (fnc->argslist) {
4112  delete [] fnc->argslist;
4113  }
4114  delete fnc;
4115  *v = nil;
4116  }
4117 }
4118 
4119 void record_init_clear(const TQItem* q, int) {
4120  DiscreteEvent* d = (DiscreteEvent*)q->data_;
4121  d->frecord_init((TQItem*)q);
4122 }
4123 
4125  int i, cnt = prl_->count();
4126  if (cnt) {
4127  // there may be some events on the queue descended from
4128  // finitialize that need to be removed
4129  record_init_items_->remove_all();
4130  p[0].tqe_->forall_callback(record_init_clear);
4131  int j, jcnt = record_init_items_->count();
4132  for (j=0; j < jcnt; ++j) {
4133  p[0].tqe_->remove(record_init_items_->item(j));
4134  }
4135  record_init_items_->remove_all();
4136  }
4137  for (i=0; i < cnt; ++i) {
4138  prl_->item(i)->record_init();
4139  }
4140 }
4141 
4143  int i, cnt = prl_->count();
4144  for (i=0; i < cnt; ++i) {
4145  prl_->item(i)->play_init();
4146  }
4147 }
4148 
4150  Section* sec = chk_access();
4151  int i, j, ii;
4152  if (single_) {
4153  return 0;
4154  }else{
4155  ii = 0;
4156  lvardtloop(i, j) {
4157  if (sec == p[i].lcv_[j].ctd_[0].v_node_[p[i].lcv_[j].ctd_[0].rootnodecount_]->sec) {
4158  return ii;
4159  }
4160  ii++;
4161  }
4162  }
4163  hoc_execerror(secname(sec), " is not the root section for any local step cvode instance");
4164  return 0;
4165 }
4166 
4168  int i, j, k, n;
4169  Vect* v = vector_arg(1);
4170  if (!cvode_active_){
4171  v->resize(0);
4172  return;
4173  }
4174  double* vp;
4175  n = 0;
4176  if (gcv_) {
4177  n += gcv_->neq_;
4178  }else{
4179  lvardtloop(i, j) {
4180  n += p[i].lcv_[j].neq_;
4181  }
4182  }
4183  v->resize(n);
4184  vp = vector_vec(v);
4185  k = 0;
4186  if (gcv_) {
4187  gcv_->states(vp);
4188  }else{
4189  lvardtloop(i, j) {
4190  p[i].lcv_[j].states(vp+k);
4191  k += p[i].lcv_[j].neq_;
4192  }
4193  }
4194 }
4195 
4197  int i, j, k, n;
4198  Vect* v = vector_arg(1);
4199  if (!cvode_active_){
4200  v->resize(0);
4201  return;
4202  }
4203  double* vp;
4204  n = 0;
4205  if (gcv_) {
4206  n += gcv_->neq_;
4207  }else{
4208  lvardtloop(i, j) {
4209  n += p[i].lcv_[j].neq_;
4210  }
4211  }
4212  v->resize(n);
4213  vp = vector_vec(v);
4214  k = 0;
4215  if (gcv_) {
4216  gcv_->dstates(vp);
4217  }else{
4218  lvardtloop(i, j) {
4219  p[i].lcv_[j].dstates(vp+k);
4220  k += p[i].lcv_[j].neq_;
4221  }
4222  }
4223 }
4224 
4225 void nrn_cvfun(double t, double* y, double* ydot) {
4227  d->gcv_->fun_thread(t, y, ydot, nrn_threads);
4228 }
4229 
4230 double nrn_hoc2fixed_step(void*) {
4231  nrn_fixed_step();
4232  return 0.;
4233 }
4234 
4235 double nrn_hoc2fun(void* v) {
4236  NetCvode* d = (NetCvode*)v;
4237  double tt = *getarg(1);
4238  Vect* s = vector_arg(2);
4239  Vect* ds = vector_arg(3);
4240  if (!d->gcv_){hoc_execerror("not global variable time step", 0);}
4241  if (s->size() != d->gcv_->neq_) { hoc_execerror("size of state vector != number of state equations", 0); }
4242  if (nrn_nthread > 1) {hoc_execerror("only one thread allowed", 0);}
4243  ds->resize(s->size());
4244  nrn_cvfun(tt, vector_vec(s), vector_vec(ds));
4245  return 0.;
4246 }
4247 
4248 double nrn_hoc2scatter_y(void* v) {
4249  NetCvode* d = (NetCvode*)v;
4250  Vect* s = vector_arg(1);
4251  if (!d->gcv_){hoc_execerror("not global variable time step", 0);}
4252  if (s->size() != d->gcv_->neq_) { hoc_execerror("size of state vector != number of state equations", 0); }
4253  if (nrn_nthread > 1) {hoc_execerror("only one thread allowed", 0);}
4254  d->gcv_->scatter_y(vector_vec(s), 0);
4255  return 0.;
4256 }
4257 
4258 double nrn_hoc2gather_y(void* v) {
4259  NetCvode* d = (NetCvode*)v;
4260  Vect* s = vector_arg(1);
4261  if (!d->gcv_){hoc_execerror("not global variable time step", 0);}
4262  if (nrn_nthread > 1) {hoc_execerror("only one thread allowed", 0);}
4263  s->resize(d->gcv_->neq_);
4264  d->gcv_->gather_y(vector_vec(s), 0);
4265  return s->size();
4266 }
4267 
4269  int i, j, k, n;
4270  Vect* v = vector_arg(1);
4271  if (!cvode_active_){
4272  v->resize(0);
4273  return;
4274  }
4275  double* vp;
4276  n = 0;
4277  if (gcv_) {
4278  n += gcv_->neq_;
4279  }else{
4280  lvardtloop(i, j) {
4281  n += p[i].lcv_[j].neq_;
4282  }
4283  }
4284  v->resize(n);
4285  vp = vector_vec(v);
4286  k = 0;
4287  if (gcv_) {
4288  gcv_->states(vp + j);
4289  }else{
4290  lvardtloop(i, j) {
4291  p[i].lcv_[j].error_weights(vp+k);
4292  k += p[i].lcv_[j].neq_;
4293  }
4294  }
4295 }
4296 
4298  int i, j, k, n;
4299  Vect* v = vector_arg(1);
4300  if (!cvode_active_){
4301  v->resize(0);
4302  return;
4303  }
4304  double* vp;
4305  n = 0;
4306  if (gcv_) {
4307  n += gcv_->neq_;
4308  }else{
4309  lvardtloop(i, j) {
4310  n += p[i].lcv_[j].neq_;
4311  }
4312  }
4313  v->resize(n);
4314  vp = vector_vec(v);
4315  k = 0;
4316  if (gcv_) {
4317  gcv_->states(vp + j);
4318  }else{
4319  lvardtloop(i, j) {
4320  p[i].lcv_[j].acor(vp+k);
4321  k += p[i].lcv_[j].neq_;
4322  }
4323  }
4324 }
4325 
4326 const char* NetCvode::statename(int is, int style) {
4327  int i, it, j, n, neq;
4328  if (!cvode_active_){
4329  hoc_execerror("Cvode is not active", 0);
4330  }
4331  double** pv;
4332  n = 0;
4333  if (gcv_) {
4334  n += gcv_->neq_;
4335  }else{
4336  lvardtloop(i, j) {
4337  n += p[i].lcv_[j].neq_;
4338  }
4339  }
4340  if (is >= n) {
4341  hoc_execerror("Cvode::statename argument out of range", 0);
4342  }
4343  if (!hdp_ || hdp_->style() != style) {
4344  if (hdp_) {
4345  delete hdp_;
4346  }
4347  hdp_ = new HocDataPaths(2*n, style);
4348  if (gcv_) {
4349  for (it=0; it < nrn_nthread; ++it){
4350  CvodeThreadData& z = gcv_->ctd_[it];
4351  neq = z.nvsize_;
4352  pv = z.pv_;
4353  for (j=0; j < z.nonvint_extra_offset_; ++j) {
4354  hdp_->append(pv[j]);
4355  }
4356  }
4357  }else{
4358  lvardtloop(it, i) {
4359  neq = p[it].lcv_[i].ctd_[0].nvsize_;
4360  pv = p[it].lcv_[i].ctd_[0].pv_;
4361  for (j=0; j < neq; ++j) {
4362  hdp_->append(pv[j]);
4363  }
4364  }
4365  }
4366  hdp_->search();
4367  }
4368  j = 0;
4369  if (gcv_) {
4370  for (it=0; it < nrn_nthread; ++it){
4371  CvodeThreadData& z = gcv_->ctd_[it];
4372  if (j + z.nvoffset_ + z.nvsize_ > is) {
4373  if (style == 2) {
4374  Symbol* sym = hdp_->retrieve_sym(z.pv_[is - j]);
4375  assert(sym);
4376  return sym2name(sym);
4377  }else{
4378  String* s = hdp_->retrieve(z.pv_[is - j]);
4379  if (s) {
4380  return s->string();
4381  }else{
4382  return "unknown";
4383  }
4384  }
4385  }
4386  j += z.nvsize_;
4387  }
4388  }else{
4389  lvardtloop(it, i) {
4390  if (j + p[it].lcv_[i].neq_ > is) {
4391  CvodeThreadData& z = p[it].lcv_[i].ctd_[0];
4392  if (style == 2) {
4393  Symbol* sym = hdp_->retrieve_sym(z.pv_[is - j]);
4394  assert(sym);
4395  return sym2name(sym);
4396  }else{
4397  String* s = hdp_->retrieve(z.pv_[is - j]);
4398  if (s) {
4399  return s->string();
4400  }else{
4401  return "unknown";
4402  }
4403  }
4404  }
4405  j += p[it].lcv_[i].neq_;
4406  }
4407  }
4408  return "unknown";
4409 }
4410 
4411 const char* NetCvode::sym2name(Symbol* sym) {
4412  if (sym->type == RANGEVAR && sym->u.rng.type > 1
4413  && memb_func[sym->u.rng.type].is_point) {
4414  static char buf[200];
4415  sprintf(buf, "%s.%s", memb_func[sym->u.rng.type].sym->name, sym->name);
4416  return buf;
4417  }else{
4418  return sym->name;
4419  }
4420 }
4421 
4423  char* buf = new char[strlen(name)+1];
4424  strcpy(buf, name);
4425  char* cp;
4426  for (cp = buf; *cp; ++cp) {
4427  if (*cp == '.') {
4428  *cp = '\0';
4429  ++cp;
4430  break;
4431  }
4432  }
4433  Symbol* sym = hoc_table_lookup(buf, hoc_built_in_symlist);
4434  if (!sym) {
4435  sym = hoc_table_lookup(buf, hoc_top_level_symlist);
4436  }
4437  if (sym && *cp == '\0' && (sym->type == RANGEVAR || strcmp(sym->name, "Vector") == 0)) {
4438  delete [] buf;
4439  return sym;
4440  }else if (sym && sym->type == TEMPLATE && *cp != '\0') {
4441  sym = hoc_table_lookup(cp, sym->u.ctemplate->symtable);
4442  if (sym) {
4443  delete [] buf;
4444  return sym;
4445  }
4446  }
4447  delete [] buf;
4448  hoc_execerror(name, "must be in form rangevar or Template.var");
4449  return nil;
4450 }
4451 
4452 void NetCvode::rtol(double x) {
4453  rtol_ = x;
4454 }
4455 void NetCvode::atol(double x) {
4456  atol_ = x;
4457 }
4458 void NetCvode::stiff(int x) {
4459  if ((stiff_ == 0) != (x == 0)) { // need to free if change between 0 and nonzero
4460  if (gcv_) {
4461  gcv_->free_cvodemem();
4462  }else{
4463  int i, j;
4464  lvardtloop(i,j) {
4465  p[i].lcv_[j].free_cvodemem();
4466  }
4467  }
4468  }
4469  stiff_ = x;
4470 }
4471 void NetCvode::maxorder(int x) {
4472  maxorder_ = x;
4473  if (gcv_) {
4474  gcv_->maxorder(maxorder_);
4475  }else{
4476  int i, j;
4477  lvardtloop(i,j) {
4478  p[i].lcv_[j].maxorder(maxorder_);
4479  }
4480  }
4481 }
4482 int NetCvode::order(int ii) {
4483  int o = 0;
4484  if (gcv_) {
4485  o = gcv_->order();
4486  }else{
4487  int i, j, i2 = 0;
4488  lvardtloop(i,j) {
4489  if (ii == i2++) {
4490  o = p[i].lcv_[j].order();
4491  }
4492  }
4493  }
4494  return o;
4495 }
4496 void NetCvode::minstep(double x) {
4497  minstep_ = x;
4498  if (gcv_) {
4499  gcv_->minstep(minstep_);
4500  }else{
4501  int i, j;
4502  lvardtloop(i,j) {
4503  p[i].lcv_[j].minstep(minstep_);
4504  }
4505  }
4506 }
4507 void NetCvode::maxstep(double x) {
4508  maxstep_ = x;
4509  if (gcv_) {
4510  gcv_->maxstep(maxstep_);
4511  }else{
4512  int i, j;
4513  lvardtloop(i,j) {
4514  p[i].lcv_[j].maxstep(maxstep_);
4515  }
4516  }
4517 }
4518 void NetCvode::jacobian(int x) {
4519  jacobian_ = x;
4520 }
4522  if (gcv_) {
4523  gcv_->structure_change_ = true;
4524  }else{
4525  int i, j;
4526  lvardtloop(i,j) {
4527  p[i].lcv_[j].structure_change_ = true;
4528  }
4529  }
4530 }
4531 
4532 NetCon* NetCvode::install_deliver(double* dsrc, Section* ssrc, Object* osrc,
4533  Object* target, double threshold, double delay, double magnitude
4534  ) {
4535  PreSyn* ps = nil;
4536  double* psrc = nil;
4537  int i;
4538  if (ssrc) { consist_sec_pd("NetCon", ssrc, dsrc); }
4539  if (!pst_) {
4540  pst_ = new PreSynTable(1000);
4541  pst_cnt_ = 0;
4542  }
4543  if (!psl_) {
4544  psl_ = hoc_l_newlist();
4545  }
4546  if (osrc) {
4547  if (dsrc) {
4548  psrc = dsrc;
4549  }else{
4550  char buf[256];
4551  if (hoc_table_lookup("x", osrc->ctemplate->symtable)) {
4552  sprintf(buf, "%s.x", hoc_object_name(osrc));
4553  psrc = hoc_val_pointer(buf);
4554  }
4555  }
4556  }else{
4557  psrc = dsrc;
4558  }
4559  if (psrc) {
4560  if (!pst_->find(ps, psrc)) {
4561  ps = new PreSyn(psrc, osrc, ssrc);
4562  ps->hi_ = hoc_l_insertvoid(psl_, ps);
4563  pst_->insert(psrc, ps);
4564  ++pst_cnt_;
4565  }
4566  if (threshold != -1e9) { ps->threshold_ = threshold; }
4567  }else if (osrc){
4568  Point_process* pnt = ob2pntproc(osrc);
4569  if (pnt->presyn_) {
4570  ps = (PreSyn*)pnt->presyn_;
4571  }else{
4572  ps = new PreSyn(psrc, osrc, ssrc);
4573  if (threshold != -1e9) { ps->threshold_ = threshold; }
4574  ps->hi_ = hoc_l_insertvoid(psl_, ps);
4575  pnt->presyn_ = ps;
4576  }
4577  }else if (target) { // no source so use the special presyn
4578  if (!unused_presyn) {
4579  unused_presyn = new PreSyn(nil, nil, nil);
4581  }
4582  ps = unused_presyn;
4583  }
4584  ps_thread_link(ps);
4585  NetCon* d = new NetCon(ps, target);
4586  d->delay_ = delay;
4587  d->weight_[0] = magnitude;
4588  structure_change_cnt_ = 0;
4589  return d;
4590 }
4591 
4593  if (!psl_) {
4594  psl_ = hoc_l_newlist();
4595  }
4596  ps->hi_ = hoc_l_insertvoid(psl_, ps);
4597 }
4598 
4600  if (ps == unused_presyn) {
4601  unused_presyn = nil;
4602  }
4603  if (ps->hi_) {
4604  hoc_l_delete(ps->hi_);
4605  ps->hi_ = nil;
4606  }
4607  if (ps->hi_th_) {
4608  hoc_l_delete(ps->hi_th_);
4609  ps->hi_th_ = nil;
4610  }
4611  if (ps->thvar_) {
4612  --pst_cnt_;
4613  pst_->remove(ps->thvar_);
4614  ps->thvar_ = nil;
4615  }
4616  if (gcv_) {
4617  for (int it = 0; it < gcv_->nctd_; ++it) {
4618  PreSynList* psl = gcv_->ctd_[it].psl_th_;
4619  if (psl) for (int j = 0; j < psl->count(); ++j) {
4620  if (psl->item(j) == ps) {
4621  psl->remove(j);
4622  return;
4623  }
4624  }
4625  }
4626  }else{
4627  int i, j;
4628  lvardtloop(i, j) {
4629  PreSynList* psl = p[i].lcv_[j].ctd_[0].psl_th_;
4630  if (psl) for (int j = 0; j < psl->count(); ++j) {
4631  if (psl->item(j) == ps) {
4632  psl->remove(j);
4633  return;
4634  }
4635  }
4636  }
4637  }
4638 }
4639 
4642 
4644 // pr("savestate_save", 0, net_cvode_instance);
4645  if (this != null_event_) {
4646  pr("savestate_save", 0, net_cvode_instance);
4647  hoc_execerror("DiscreteEvent::savestate_save:", " is not the null_event_");
4648  }
4649  return new DiscreteEvent();
4650 }
4651 
4653 // pr("savestate_restore", tt, nc);
4654  Printf("null_event_ onto queue\n");
4655  nc->null_event(tt);
4656 }
4657 
4659  return new DiscreteEvent();
4660 }
4661 
4663  fprintf(f, "%d\n", DiscreteEventType);
4664 }
4665 
4667  cnt_ = 0; obj_ = nil; active_ = false; weight_ = nil;
4669 }
4670 
4671 NetCon::NetCon(PreSyn* src, Object* target) {
4673  obj_ = nil;
4674  src_ = src;
4675  delay_ = 1.0;
4676  if (src_) {
4677  src_->dil_.push_back(this);
4678  src_->use_min_delay_ = 0;
4679  }
4680  if (target == nil) {
4681  target_ = nil;
4682  active_ = false;
4683  cnt_ = 1;
4684  weight_ = new double[cnt_];
4685  weight_[0] = 0.0;
4686  return;
4687  }
4688  target_ = ob2pntproc(target);
4689  active_ = true;
4690 #if DISCRETE_EVENT_OBSERVER
4691  ObjObservable::Attach(target, this);
4692 #endif
4693  if (!pnt_receive[target_->prop->type]) {
4694 hoc_execerror("No NET_RECEIVE in target PointProcess:", hoc_object_name(target));
4695  }
4696  cnt_ = pnt_receive_size[target_->prop->type];
4697  weight_ = nil;
4698  if (cnt_) {
4699  weight_ = new double[cnt_];
4700  for (int i=0; i < cnt_; ++i) {
4701  weight_[i] = 0.0;
4702  }
4703  }
4704 }
4705 
4707 //printf("~NetCon\n");
4709  rmsrc();
4710  if (cnt_) {
4711  delete [] weight_;
4712  }
4713 #if DISCRETE_EVENT_OBSERVER
4714  if (target_) {
4715  ObjObservable::Detach(target_->ob, this);
4716  }
4717 #endif
4718 }
4719 
4721  if (src_) {
4722  for (int i=0; i < src_->dil_.size(); ++i) {
4723  if (src_->dil_[i] == this) {
4724  src_->dil_.erase(src_->dil_.begin()+i);
4725  if (src_->dil_.size() == 0 && src_->tvec_ == nil
4726  && src_->idvec_ == nil) {
4727 #if 1 || NRNMPI
4728  if (src_->output_index_ == -1)
4729 #endif
4730  delete src_;
4731  src_ = nullptr;
4732  }
4733  break;
4734  }
4735  }
4736  }
4737  src_ = nil;
4738 }
4739 
4741  rmsrc();
4742  src_ = p;
4743  if (src_) {
4744  src_->dil_.push_back(this);
4745  src_->use_min_delay_ = 0;
4746  }
4747 }
4748 
4750 // pr("savestate_save", 0, net_cvode_instance);
4751  return new NetConSave(this);
4752 }
4753 
4755  netcon_ = netcon;
4756 }
4758 
4760 // netcon_->pr("savestate_restore", tt, nc);
4761  NrnThread* nt;
4762  if (netcon_ && netcon_->target_) {
4763  nt = PP2NT(netcon_->target_);
4764 //printf(" on thread %d\n", nt->id);
4765  }else{
4766  nt = nrn_threads;
4767  }
4768  nc->event(tt, netcon_, nt);
4769 }
4770 
4772  int index;
4773  char buf[200];
4774 // fscanf(f, "%d\n", &index);
4775  nrn_assert(fgets(buf, 200, f));
4776  sscanf(buf, "%d\n", &index);
4777  NetCon* nc = NetConSave::index2netcon(index);
4778  assert(nc);
4779  return new NetConSave(nc);
4780 }
4781 
4783  fprintf(f, "%d\n", NetConType);
4784  fprintf(f, "%d\n", netcon_->obj_->index);
4785 }
4786 
4787 declareTable(NetConSaveWeightTable, void*, NetCon*)
4788 implementTable(NetConSaveWeightTable, void*, NetCon*)
4789 NetConSaveWeightTable* NetConSave::wtable_;
4790 
4791 declareTable(NetConSaveIndexTable, long, NetCon*)
4792 implementTable(NetConSaveIndexTable, long, NetCon*)
4793 NetConSaveIndexTable* NetConSave::idxtable_;
4794 
4795 void NetConSave::invalid() {
4796  if (wtable_) {
4797  delete wtable_;
4798  wtable_ = nil;
4799  }
4800  if (idxtable_) {
4801  delete idxtable_;
4802  idxtable_ = nil;
4803  }
4804 }
4805 
4807  NetCon* nc;
4808  if (!wtable_) {
4809  hoc_Item* q;
4810  Symbol* sym = hoc_lookup("NetCon");
4811  wtable_ = new NetConSaveWeightTable(2*sym->u.ctemplate->count);
4812  ITERATE (q, sym->u.ctemplate->olist) {
4813  Object* obj = OBJ(q);
4814  nc = (NetCon*)obj->u.this_pointer;
4815  if (nc->weight_) {
4816  wtable_->insert(nc->weight_, nc);
4817  }
4818  }
4819  }
4820  if (wtable_->find(nc, pd)) {
4821  assert(nc->weight_ == pd);
4822  return nc;
4823  }else{
4824  return nil;
4825  }
4826 }
4827 
4829  NetCon* nc;
4830  if (!idxtable_) {
4831  hoc_Item* q;
4832  Symbol* sym = hoc_lookup("NetCon");
4833  idxtable_ = new NetConSaveIndexTable(2*sym->u.ctemplate->count);
4834  ITERATE (q, sym->u.ctemplate->olist) {
4835  Object* obj = OBJ(q);
4836  nc = (NetCon*)obj->u.this_pointer;
4837  if (nc->weight_) {
4838  idxtable_->insert(obj->index, nc);
4839  }
4840  }
4841  }
4842  if (idxtable_->find(nc, id)) {
4843  assert(nc->obj_->index == id);
4844  return nc;
4845  }else{
4846  return nil;
4847  }
4848 }
4849 
4851  net_cvode_instance->update_ps2nt();
4852 }
4853 
4855  if (!ps) { return; }
4856  ps->nt_ = nil;
4857  if (!v_structure_change) { // PP2NT etc are correct
4858  if (ps->osrc_) {
4859  ps->nt_ = PP2NT(ob2pntproc(ps->osrc_));
4860  }else if (ps->ssrc_) {
4861  ps->nt_ = (NrnThread*)ps->ssrc_->prop->dparam[9]._pvoid;
4862  }
4863  }
4864  if (!ps->nt_) { // premature, reorder_secorder() not called yet
4865  return;
4866  }
4867  if (ps->thvar_) {
4868  int i = ps->nt_->id;
4869  if (!p[i].psl_thr_) {
4870  p[i].psl_thr_ = hoc_l_newlist();
4871  }
4872  ps->hi_th_ = hoc_l_insertvoid(p[i].psl_thr_, ps);
4873  }
4874 }
4875 
4877  int i;
4878  // first, opportunistically create p[]
4879  p_construct(nrn_nthread);
4880  // iterate over all threshold PreSyn and fill the NrnThread field
4881  hoc_Item* q;
4882  for (i=0; i < nrn_nthread; ++i) {
4883  if (p[i].psl_thr_) {
4884  hoc_l_freelist(&p[i].psl_thr_);
4885  }
4886  }
4887  if (psl_) ITERATE(q, psl_) {
4888  PreSyn* ps = (PreSyn*)VOIDITM(q);
4889  ps_thread_link(ps);
4890  }
4891 }
4892 
4894  int i;
4895  if (pcnt_ != n) {
4896  if (p) {
4897  delete [] p;
4898  p = nil;
4899  }
4900  if (n > 0) {
4901  p = new NetCvodeThreadData[n];
4902  }else{
4903  p = nil;
4904  }
4905  pcnt_ = n;
4906  }
4907  for (i=0; i < n; ++i) {
4908  p[i].unreffed_event_cnt_ = 0;
4909  }
4910 }
4911 
4912 PreSyn::PreSyn(double* src, Object* osrc, Section* ssrc) {
4913 // printf("Presyn %x %s\n", (long)this, osrc?hoc_object_name(osrc):"nil");
4915  hi_index_ = -1;
4916  hi_th_ = nil;
4917  flag_ = false;
4918  valthresh_ = 0;
4919  thvar_ = src;
4920  osrc_ = osrc;
4921  ssrc_ = ssrc;
4922  threshold_ = 10.;
4923  use_min_delay_ = 0;
4924  tvec_ = nil;
4925  idvec_ = nil;
4926  stmt_ = nil;
4927  gid_ = -1;
4928  nt_ = nil;
4929  if (src) {
4930  if (osrc) {
4931  nt_ = PP2NT(ob2pntproc(osrc));
4932  }else if (ssrc) {
4933  nt_ = (NrnThread*)ssrc->prop->dparam[9]._pvoid;
4934  }
4935  }
4936  if (osrc_ && !src) {
4937  nt_ = PP2NT(ob2pntproc(osrc));
4938  }
4939 #if 1 || USENCS || NRNMPI
4940  output_index_ = -1;
4941 #endif
4942 #if BGPDMA
4943  bgp.dma_send_ = 0;
4944 #endif
4945 #if NRN_MUSIC
4946  music_port_ = 0;
4947 #endif
4948 #if DISCRETE_EVENT_OBSERVER
4949  if(thvar_) {
4950  nrn_notify_when_double_freed(thvar_, this);
4951  }else if (osrc_) {
4952  nrn_notify_when_void_freed(osrc_, this);
4953  }
4954 #endif
4955 }
4956 
4959 // printf("~PreSyn %p\n", this);
4960  nrn_cleanup_presyn(this);
4961  if (stmt_) {
4962  delete stmt_;
4963  }
4964 #if DISCRETE_EVENT_OBSERVER
4965  if (tvec_) {
4966  ObjObservable::Detach(tvec_->obj_, this);
4967  tvec_ = nil;
4968  }
4969  if (idvec_) {
4970  ObjObservable::Detach(idvec_->obj_, this);
4971  idvec_ = nil;
4972  }
4973 #endif
4974  if (thvar_ || osrc_) {
4975 #if DISCRETE_EVENT_OBSERVER
4977 #endif
4978  if (!thvar_) {
4979  // even if the point process section was deleted earlier
4980  Point_process* pnt = ob2pntproc_0(osrc_);
4981  if (pnt) {
4982  pnt->presyn_ = nil;
4983  }
4984  }
4985  }
4986  for (const auto& d : dil_) {
4987  d->src_ = nil;
4988  }
4989  net_cvode_instance->presyn_disconnect(this);
4990 }
4991 
4993 // pr("savestate_save", 0, net_cvode_instance);
4994  return new PreSynSave(this);
4995 }
4996 
4998  presyn_ = presyn;
4999 }
5001 
5003 // presyn_->pr("savestate_restore", tt, nc);
5004  nc->event(tt, presyn_, presyn_->nt_);
5005 }
5006 
5008  PreSyn* ps = nil;
5009  char buf[200];
5010  int index, tid;
5011  nrn_assert(fgets(buf, 200, f));
5012  nrn_assert(sscanf(buf, "%d %d\n", &index, &tid) == 2);
5013  ps = PreSynSave::hindx2presyn(index);
5014  assert(ps);
5015  ps->nt_ = nrn_threads + tid;
5016  return new PreSynSave(ps);
5017 }
5018 
5020  fprintf(f, "%d\n", PreSynType);
5021  fprintf(f, "%ld %d\n", presyn_->hi_index_, presyn_->nt_?presyn_->nt_->id:0);
5022 }
5023 
5024 declareTable(PreSynSaveIndexTable, long, PreSyn*)
5025 implementTable(PreSynSaveIndexTable, long, PreSyn*)
5026 PreSynSaveIndexTable* PreSynSave::idxtable_;
5027 
5029  if (idxtable_) {
5030  delete idxtable_;
5031  idxtable_ = nil;
5032  }
5033 }
5034 
5036  PreSyn* ps;
5037  if (!idxtable_) {
5038  hoc_Item* q;
5039  int cnt = 0;
5040  ITERATE (q, net_cvode_instance->psl_) {
5041  ++cnt;
5042  }
5043 //printf("%d PreSyn instances\n", cnt);
5044  idxtable_ = new PreSynSaveIndexTable(2*cnt);
5045  cnt = 0;
5046  ITERATE (q, net_cvode_instance->psl_) {
5047  ps = (PreSyn*)VOIDITM(q);
5048  assert(ps->hi_index_ == cnt);
5049  idxtable_->insert(ps->hi_index_, ps);
5050  ++cnt;
5051  }
5052  }
5053  if (idxtable_->find(ps, id)) {
5054  assert(ps->hi_index_ == id);
5055  return ps;
5056  }else{
5057  return nil;
5058  }
5059 }
5060 
5062  qthresh_ = nil;
5063  if (tvec_) {
5064  tvec_->resize(0);
5065  }
5066  if (idvec_) {
5067  idvec_->resize(0);
5068  }
5069 }
5070 
5071 void PreSyn::record_stmt(const char* stmt) {
5072  if (stmt_) {
5073  delete stmt_;
5074  stmt_ = nil;
5075  }
5076  if (strlen(stmt) > 0) {
5077  stmt_ = new HocCommand(stmt);
5078  }
5079 }
5080 
5082  if (stmt_) {
5083  delete stmt_;
5084  stmt_ = nil;
5085  }
5086  if (pyact) {
5087  stmt_ = new HocCommand(pyact);
5088  }
5089 }
5090 
5091 void PreSyn::record(IvocVect* vec, IvocVect* idvec, int rec_id) {
5092 #if DISCRETE_EVENT_OBSERVER
5093  if (tvec_) {
5094  ObjObservable::Detach(tvec_->obj_, this);
5095  }
5096  if (idvec_) {
5097  ObjObservable::Detach(idvec_->obj_, this);
5098  }
5099 #endif
5100  tvec_ = vec;
5101  idvec_ = idvec;
5102  rec_id_ = rec_id;
5103 #if DISCRETE_EVENT_OBSERVER
5104  if (tvec_) {
5105  ObjObservable::Attach(tvec_->obj_, this);
5106  }
5107  if (idvec_) {
5108  ObjObservable::Attach(idvec_->obj_, this);
5109  tvec_->mutconstruct(1);
5110  }
5111 #endif
5112 }
5113 
5114 void PreSyn::record(double tt) {
5115  if (tvec_) {
5116  // need to lock the vector if shared by other PreSyn
5117  // since we get here in the thread that manages the
5118  // threshold detection (or net_event from NET_RECEIVE).
5119  if (idvec_) {tvec_->lock();}
5120  tvec_->push_back(tt);
5121  if (idvec_) {
5122  idvec_->push_back(rec_id_);
5123  tvec_->unlock();
5124  }
5125  }
5126  if (stmt_) {
5127  if (nrn_nthread > 1) { nrn_hoc_lock(); }
5128  t = tt;
5129  stmt_->execute(false);
5130  if (nrn_nthread > 1) { nrn_hoc_unlock(); }
5131  }
5132 }
5133 
5135 //printf("PreSyn::disconnect %s\n", hoc_object_name(((ObjObservable*)o)->object()));
5136  if (tvec_ && tvec_->obj_ == ((ObjObservable*)o)->object()) {
5137  tvec_ = nil;
5138  }
5139  if (idvec_ && idvec_->obj_ == ((ObjObservable*)o)->object()) {
5140  idvec_ = nil;
5141  }
5142  if (dil_.size() == 0 && tvec_ == nil && idvec_ == nil && output_index_ == -1) {
5143  delete this;
5144  }
5145 }
5146 
5147 void PreSyn::update(Observable* o) { // should be disconnect
5148 //printf("PreSyn::update\n");
5149  for (const auto& d : dil_) {
5150 #if 0 // osrc_ below is invalid
5151 if (d->obj_) {
5152  printf("%s disconnect from ", hoc_object_name(d->obj_));
5153  printf("source %s\n", osrc_ ? hoc_object_name(osrc_) : secname(ssrc_));
5154 }
5155 #endif
5156  d->src_ = nullptr;
5157  }
5158  if (tvec_) {
5159 #if DISCRETE_EVENT_OBSERVER
5160  ObjObservable::Detach(tvec_->obj_, this);
5161 #endif
5162  tvec_ = nil;
5163  }
5164  if (idvec_) {
5165 #if DISCRETE_EVENT_OBSERVER
5166  ObjObservable::Detach(idvec_->obj_, this);
5167 #endif
5168  idvec_ = nil;
5169  }
5170  net_cvode_instance->presyn_disconnect(this);
5171  thvar_ = nil;
5172  osrc_ = nil;
5173  delete this;
5174 }
5175 
5176 void PreSyn::update_ptr(double* pd) {
5177 #if DISCRETE_EVENT_OBSERVER
5179  nrn_notify_when_double_freed(pd, this);
5180 #endif
5181  thvar_ = pd;
5182 }
5183 
5184 void ConditionEvent::check(NrnThread* nt, double tt, double teps) {
5185  if (value() > 0.0) {
5186  if (flag_ == false) {
5187  flag_ = true;
5188  valthresh_ = 0.;
5189 #if USENEOSIM
5190  if (neosim_entity_) {
5191  (*p_nrn2neosim_send)(neosim_entity_, tt);
5192  }else{
5193 #endif
5194  send(tt + teps, net_cvode_instance, nt);
5195 #if USENEOSIM
5196  }
5197 #endif
5198  }
5199  }else{
5200  flag_ = false;
5201  }
5202 }
5203 
5204 ConditionEvent::ConditionEvent() {qthresh_ = NULL; valold_ = 0.0;}
5206 
5207 void ConditionEvent::condition(Cvode* cv) { //logic for high order threshold detection
5208 //printf("ConditionEvent::condition f=%d t=%20.15g v=%20.15g\n", flag_, t, value());
5209  NrnThread* nt = thread();
5210  if (qthresh_) { // the threshold event has not
5211  // been handled. i.e. the cell must have retreated to
5212  // a time not later than the threshold time.
5213  assert (nt->_t <= qthresh_->t_);
5214  abandon_statistics(cv);
5215  // abandon the event
5216  STATISTICS(abandon_);
5217  net_cvode_instance->remove_event(qthresh_, nt->id);
5218  qthresh_ = nil;
5219  valthresh_ = 0.;
5220  flag_ = false;
5221  }
5222 
5223  double val = value();
5224  if (flag_ == false && val >= 0.0) { // above threshold
5225  flag_ = true;
5226  valthresh_ = 0.;
5227  if (cv->t0_ == cv->tn_) { //inited
5228  // means immediate threshold event now.
5229  // no need for qthresh since there is
5230  // no question of abandoning it so instead
5231  // of a qthresh it is a send event.
5232  STATISTICS(init_above_);
5233  send(nt->_t, net_cvode_instance, nt);
5234  }else{ // crossed somewhere in the told to t interval
5235  STATISTICS(send_qthresh_);
5236  // reset the flag_ when the value goes lower than
5237  // valold since value() when qthresh_ handled
5238  // may in fact be below 0.0
5239  valthresh_ = valold_;
5240  double th = -valold_/(val - valold_);
5241  th = th*nt->_t + (1. - th)*told_;
5242  assert(th >= cv->t0_ && th <= cv->tn_);
5243  qthresh_ = net_cvode_instance->event(th, this, nt);
5244  }
5245  }else if (flag_ == true && valold_ < valthresh_ && val < valthresh_) {
5246  // below threshold
5247  // previous step crossed in negative direction
5248  // and there was not any retreat or initialization
5249  // to give spurious crossing.
5250  flag_ = false;
5251  }
5252  valold_ = val;
5253  told_ = nt->_t;
5254 }
5255 
5257  double val = stet_->value();
5258  return val;
5259 }
5260 
5262 #if 1
5263 //printf("ConditionEvent::condition %s t=%20.15g abandon event at %20.15g\n", ssrc_?secname(ssrc_):"", t, qthresh_->t_);
5264  if (nt_t == qthresh_->t_) {// it is not clear whether
5265  // this could happen and if it does it may
5266  // take fastidiousness to
5267  // an extreme
5268  STATISTICS(eq_abandon_);
5269  Printf("abandon when t == qthresh_->t_ = %20.15g\n", nt_t);
5270  }
5271  if (cv->t0_ == cv->tn_) { // inited
5272  if (value() > 0.0) { // above threshold
5273  STATISTICS(abandon_init_above_);
5274  }else{
5275  STATISTICS(abandon_init_below_);
5276  }
5277  }else{
5278  if (value() > 0.0) { // above threshold
5279  STATISTICS(abandon_above_);
5280  }else{
5281  STATISTICS(abandon_below_);
5282  }
5283  }
5284 #endif
5285 }
5286 
5288  : HTList(nil)
5289 {
5290  pnt_ = pnt;
5291  c_ = c;
5292  watch_index_ = 0; // For transfer, will be a small positive integer.
5293 }
5294 
5296 //printf("~WatchCondition\n");
5297  Remove();
5298 }
5299 
5300 // A WatchCondition but with different deliver
5302  : WatchCondition(pnt, c)
5303 {
5304 //printf("STECondition\n");
5305 }
5306 
5308 //printf("~STECondition\n");
5309 }
5310 
5311 void WatchCondition::activate(double flag) {
5312  Cvode* cv = NULL;
5313  int id = 0;
5314  qthresh_ = nil;
5315  flag_ = (value() >= -hoc_epsilon) ? true: false;
5316  valthresh_ = 0.;
5317  nrflag_ = flag;
5318  if (!pnt_) { // possible for StateTransitionEvent
5319  // but only if 1 thread and no lvardt
5320  assert(nrn_nthread == 1);
5321  assert(net_cvode_instance->localstep() == false);
5322  cv = net_cvode_instance->gcv_;
5323  }else{
5324  cv = (Cvode*)pnt_->nvi_;
5325  }
5326  assert(cv);
5327  id = (cv->nctd_ > 1) ? thread()->id : 0;
5328  HTList*& wl = cv->ctd_[id].watch_list_;
5329  if (!wl) {
5330  wl = new HTList(nil);
5331  net_cvode_instance->wl_list_[id].push_back(wl);
5332  }
5333  Remove();
5334  wl->Append(this);
5335 }
5336 
5338 fprintf(stderr, "WATCH condition with flag=%g for %s\n",
5340 }
5341 
5343 fprintf(stderr, "PreSyn threshold for %s\n", osrc_ ? hoc_object_name(osrc_):secname(ssrc_));
5344 }
5345 
5346 void WatchCondition::send(double tt, NetCvode* nc, NrnThread* nt) {
5347  qthresh_ = nc->event(tt, this, nt);
5349 }
5350 
5351 void WatchCondition::deliver(double tt, NetCvode* ns, NrnThread* nt) {
5352  if (qthresh_) {
5353  qthresh_ = nil;
5355  }
5356  Cvode* cv = (Cvode*)pnt_->nvi_;
5357  int type = pnt_->prop->type;
5358  if (cvode_active_ && cv) {
5359  ns->local_retreat(tt, cv);
5360  cv->set_init_flag();
5361  }else{
5362  PP2t(pnt_) = tt;
5363  }
5365  POINT_RECEIVE(type, pnt_, nil, nrflag_);
5366  if (errno) {
5367  if (nrn_errno_check(type)) {
5368 hoc_warning("errno set during WatchCondition deliver to NET_RECEIVE", (char*)0);
5369  }
5370  }
5371 }
5372 
5373 void StateTransitionEvent::transition(int src, int dest,
5374  double* var1, double* var2,
5375  HocCommand* hc
5376 ){
5377  STETransition* st = states_[src].add_transition();
5378  st->dest_ = dest;
5379  st->var1_ = var1;
5380  st->var2_ = var2;
5381  st->hc_ = hc;
5382  st->ste_ = (StateTransitionEvent*)this;
5383  st->stec_ = new STECondition(pnt_, NULL);
5384  st->stec_->stet_ = st;
5385  if (st->var1_ == &t) {
5386  st->var1_is_time_ = true;
5387  }
5388 }
5389 
5391  if (var1_is_time_) {
5392  var1_ = &stec_->thread()->_t;
5393  }
5394  if (stec_->qthresh_) { // is it on the queue
5395  net_cvode_instance->remove_event(stec_->qthresh_, stec_->thread()->id);
5396  stec_->qthresh_ = NULL;
5397  }
5398  stec_->activate(0);
5399 }
5400 
5402  if (stec_->qthresh_) { // is it on the queue
5403  net_cvode_instance->remove_event(stec_->qthresh_, stec_->thread()->id);
5404  stec_->qthresh_ = NULL;
5405  }
5406  stec_->Remove();
5407 }
5408 
5409 void STECondition::deliver(double tt, NetCvode* ns, NrnThread* nt) {
5410  if (qthresh_) {
5411  qthresh_ = nil;
5413  }
5414  if (!pnt_) {
5415  assert(nrn_nthread == 1 && ns->localstep() == false);
5416  if (cvode_active_) {
5417  Cvode* cv = ns->gcv_;
5418  ns->local_retreat(tt, cv);
5419  cv->set_init_flag();
5420  }else{
5421  nt->_t = tt;
5422  }
5423  }else{
5424  Cvode* cv = (Cvode*)pnt_->nvi_;
5425  if (cvode_active_ && cv) {
5426  ns->local_retreat(tt, cv);
5427  cv->set_init_flag();
5428  }else{
5429  PP2t(pnt_) = tt;
5430  }
5431  }
5433  t = tt;
5434  stet_->event();
5435 }
5436 
5438 
5440  if (pnt_) {
5441  return PP2NT(pnt_);
5442  }else{
5443  assert(nrn_nthread == 1);
5444  return nrn_threads;
5445  }
5446 }
5447 
5449  NrnThread* nt;
5450  assert(0);
5451  if (qthresh_) {
5452  qthresh_ = nil;
5454  }
5455  int type = pnt_->prop->type;
5457  POINT_RECEIVE(type, pnt_, nil, nrflag_);
5458  if (errno) {
5459  if (nrn_errno_check(type)) {
5460 hoc_warning("errno set during WatchCondition deliver to NET_RECEIVE", (char*)0);
5461  }
5462  }
5463 }
5464 
5466  NrnThread* nt;
5467  assert(0);
5468  if (qthresh_) {
5469  qthresh_ = nil;
5471  }
5472  int type = pnt_->prop->type;
5474  stet_->event();
5475  if (errno) {
5476  if (nrn_errno_check(type)) {
5477 hoc_warning("errno set during STECondition pgvts_deliver to NET_RECEIVE", (char*)0);
5478  }
5479  }
5480 }
5481 
5482 void WatchCondition::pr(const char* s, double tt, NetCvode* ns) {
5483  Printf("%s", s);
5484  Printf(" WatchCondition %s %.15g flag=%g\n", hoc_object_name(pnt_->ob), tt, nrflag_);
5485 }
5486 
5487 static Cvode* eval_cv;
5488 static void* eval_cond(NrnThread* nt) {
5489  eval_cv->evaluate_conditions(nt);
5490  return 0;
5491 }
5493  if (!nt) {
5494  if (nrn_nthread > 1) {
5495  eval_cv = this;
5497  return;
5498  }
5499  nt = nrn_threads;
5500  }
5501  CvodeThreadData& z = CTD(nt->id);
5502  int i;
5503  if (z.psl_th_) {
5504  for (i = z.psl_th_->count()-1; i >= 0; --i) {
5505  z.psl_th_->item(i)->condition( this);
5506  }
5507  }
5508  if (z.watch_list_) {
5509  for (HTList* item = z.watch_list_->First(); item != z.watch_list_->End(); item = item->Next()) {
5510  ((WatchCondition*)item)->condition(this);
5511  }
5512  }
5513 }
5514 
5515 static void* chk_deliv(NrnThread* nt) {
5516  eval_cv->check_deliver(nt);
5517  return 0;
5518 }
5520  if (!nt) {
5521  if (nrn_nthread > 1) {
5522  eval_cv = this;
5524  return;
5525  }
5526  nt = nrn_threads;
5527  }
5528  CvodeThreadData& z = CTD(nt->id);
5529  int i;
5530  if (z.psl_th_) {
5531  for (i = z.psl_th_->count()-1; i >= 0; --i) {
5532  z.psl_th_->item(i)->check(nt, nt->_t);
5533  }
5534  }
5535  if (z.watch_list_) {
5536  for (HTList* item = z.watch_list_->First(); item != z.watch_list_->End(); item = item->Next()) {
5537  ((WatchCondition*)item)->check(nt, nt->_t);
5538  }
5539  }
5540 }
5541 
5543  int i, cnt;
5544  nrn_ba(nt, BEFORE_STEP);
5545  cnt = fixed_record_->count();
5546  for (i=0; i < cnt; ++i) { // should be made more efficient
5547  PlayRecord* pr = fixed_record_->item(i);
5548  if (pr->ith_ == nt->id) {
5549  pr->continuous(nt->_t);
5550  }
5551  }
5552 }
5553 
5555  int i, cnt;
5556  cnt = fixed_play_->count();
5557  for (i=0; i < cnt; ++i) {
5558  PlayRecord* pr = fixed_play_->item(i);
5559  if (pr->ith_ == nt->id) {
5560  pr->continuous(nt->_t);
5561  }
5562  }
5563 }
5564 
5565 // nrnthread_get_trajectory_requests helper for buffered trajectories
5566 // also for per time step return (no Vector and varrays is NULL)
5567 // if bsize > 0 then CoreNEURON will write that number of values to the vectors.
5568 // If CoreNEURON has a start time > 0, (current value of t),
5569 // the amount to augment the vector depends
5570 // on the vector's current size in the current NEURON context and the
5571 // varray[i_trajec] double* will be determined by that current size.
5572 // However determination of whether to do per time step return or buffering
5573 // can be specified on the NEURON side.
5575  int bsize, IvocVect* v,
5576  double* pd,
5577  int i_pr, PlayRecord* pr, void** vpr,
5578  int i_trajec, int* types, int* indices, double** pvars, double** varrays)
5579 {
5580  int err = 0; //success
5581  if (bsize > 0) {
5582  int cur_size = v->size();
5583  if (v->buffer_size() < bsize + cur_size) {
5584  v->buffer_size(bsize + cur_size);
5585  }
5586  // nrnthread_trajectory_values will resize to correct size.
5587  v->resize(bsize + cur_size);
5588  varrays[i_trajec] = vector_vec(v) + cur_size; // begin filling here
5589  }else{
5590  pvars[i_trajec] = pd;
5591  }
5592  vpr[i_pr] = pr;
5593  if (pd == &nt._t) {
5594  types[i_trajec] = 0;
5595  indices[i_trajec] = 0;
5596  }else{
5597  err = nrn_dblpntr2nrncore(pd, nt, types[i_trajec], indices[i_trajec]);
5598  if (err) {
5599  Fprintf(stderr, "Pointer %p of PlayRecord type %d ignored because not a Range Variable",
5600  pd, pr->type());
5601  }
5602  }
5603  return err;
5604 }
5605 
5606 // Transfer of trajectories from CoreNEURON to NEURON.
5607 // bsize == 0: Most flexible interactivity, transfer on a per time step basis.
5608 // bsize > 0: Greatest performance, fill the entire trajectory arrays on
5609 // the CoreNEURON side and transferring at the end of a CoreNEURON run.
5610 // Here, we ensure the arrays have at least bsize size (i.e. at least tstop/dt)
5611 // beyond their current size and CoreNEURON will start filling from the
5612 // current fill time, h.t, location of the arrays. I.e. starting at CoreNEURON's
5613 // start time. (Multiple calls to psolve append to these arrays.)
5614 // n_pr refers the the number of PlayRecord instances in the vpr array.
5615 // n_trajec refers to the number of trajectories to be recorded on the
5616 // CoreNEURON side and is the size of the types, indices, and varrays.
5617 // n_pr is different from n_trajec when one of the GLineRecord instances has
5618 // a gl_->name that is an expression that contains several range variables.
5619 // Per time step transfer now uses pvars so CoreNEURON scatters values
5620 // to pvars instead of collecting in double array.
5621 void nrnthread_get_trajectory_requests(int tid, int& bsize,
5622 int& n_pr, void**& vpr,
5623 int& n_trajec, int*& types, int*& indices, double**& pvars, double**& varrays) {
5624  if (bsize > 0) { // but would NEURON rather use per time step mode
5625  if (nrn_trajectory_request_per_time_step_) {
5626  bsize = 0;
5627  }
5628  }
5629  n_pr = 0;
5630  n_trajec = 0;
5631  types = NULL;
5632  indices = NULL;
5633  vpr = NULL;
5634  varrays = NULL;
5635  pvars = NULL;
5636  if (tid < nrn_nthread) {
5637  NrnThread& nt = nrn_threads[tid];
5638  PlayRecList* fr = net_cvode_instance->fixed_record_;
5639  int cntp;
5640  cntp = fr->count();
5641  // allocate
5642  for (int i=0; i < cntp; ++i) {
5643  PlayRecord* pr = fr->item(i);
5644  if (pr->ith_ == tid) {
5645  if (pr->type() == TvecRecordType || pr->type() == YvecRecordType) {
5646  n_pr++;
5647  n_trajec++;
5648 #if HAVE_IV
5649  }else if (pr->type() == GLineRecordType) {
5650  n_pr++;
5651  if (pr->pd_ == NULL) {
5652  GLineRecord* glr = (GLineRecord*)pr;
5653  assert(glr->gl_->expr_);
5654  glr->fill_pd();
5655  if (pr->pd_) {
5656  n_trajec++;
5657  }else{
5658  n_trajec += glr->pd_and_vec_.size();
5659  }
5660  }else{
5661  n_trajec++;
5662  }
5663  }else if (pr->type() == GVectorRecordType) {
5664  GVectorRecord* gvr = (GVectorRecord*)pr;
5665  if (gvr->count()) {
5666  bsize = 0;
5667  n_pr++;
5668  for (int j=0; j < gvr->count(); ++j) {
5669  if (gvr->pdata(j)) {
5670  n_trajec++;
5671  }
5672  }
5673  }
5674 #endif // HAVE_IV
5675  }
5676  }
5677  }
5678  if (n_pr == 0) {
5679  return;
5680  }
5681  vpr = new void*[n_pr];
5682  types = new int[n_trajec];
5683  indices = new int[n_trajec];
5684  if (bsize > 0) {
5685  varrays = new double*[n_trajec];
5686  }else{
5687  pvars = new double*[n_trajec];
5688  } // if both varrays and pvars are NULL then CoreNEURON will return values every time step
5689  // everything allocated, start over and fill
5690  n_pr = 0;
5691  n_trajec = 0;
5692  for (int i=0; i < cntp; ++i) {
5693  int err = 0;
5694  PlayRecord* pr = fr->item(i);
5695  if (pr->ith_ == tid) {
5696  if (1) { // buffered or per time step value return
5697  IvocVect* v = NULL;
5698  if (pr->type() == TvecRecordType) {
5699  v = ((TvecRecord*)pr)->t_;
5700  err = trajec_buffered(nt, bsize, v, &nt._t, n_pr++, pr, vpr, n_trajec++, types, indices, pvars, varrays);
5701  if (err) { n_pr--; n_trajec--; }
5702  }else if (pr->type() == YvecRecordType) {
5703  v = ((YvecRecord*)pr)->y_;
5704  err = trajec_buffered(nt, bsize, v, pr->pd_, n_pr++, pr, vpr, n_trajec++, types, indices, pvars, varrays);
5705  if (err) { n_pr--; n_trajec--; }
5706 #if HAVE_IV
5707  }else if (pr->type() == GLineRecordType) {
5708  GLineRecord* glr = (GLineRecord*)pr;
5709  if (pr->pd_) { // glr->gl_->name is an expression resolved to a double*
5710  if (bsize && !glr->v_) {
5711  glr->v_ = new IvocVect(bsize);
5712  }
5713  v = glr->v_;
5714  err = trajec_buffered(nt, bsize, v, pr->pd_, n_pr++, pr, vpr, n_trajec++, types, indices, pvars, varrays);
5715  if (err) { n_pr--; n_trajec--; }
5716  }else{ // glr->gl_->name expression involves several range variables
5717  GLineRecordEData& ed = glr->pd_and_vec_;
5718  int n = n_trajec;
5719  for (GLineRecordEData::iterator it = ed.begin(); it != ed.end(); ++it) {
5720  double* pd = (*it).first;
5721  assert(pd);
5722  v = (*it).second;
5723  if (bsize && v == NULL) {
5724  v = (*it).second = new IvocVect(bsize);
5725  }
5726  err = trajec_buffered(nt, bsize, v, pd, n_pr, pr, vpr, n_trajec++, types, indices, pvars, varrays);
5727  if (err) { break; }
5728  }
5729  n_pr++;
5730  if (err) { // single error removes entire GLineRecord
5731  n_pr--;
5732  n_trajec = n;
5733  }
5734  }
5735  }else if (pr->type() == GVectorRecordType) {
5736  GVectorRecord* gvr = (GVectorRecord*)pr;
5737  if (gvr->count()) {
5738  int n = n_trajec;
5739  for (int j=0; j < gvr->count(); ++j) {
5740  if (gvr->pdata(j)) {
5741  err = trajec_buffered(nt, bsize, NULL, gvr->pdata(j), n_pr, pr, vpr, n_trajec++, types, indices, pvars, varrays);
5742  if (err) { break; }
5743  }
5744  }
5745  n_pr++;
5746  if (err) { // single error removes entire GVectorRecord
5747  n_pr--;
5748  n_trajec = n;
5749  }
5750  }
5751 #endif // HAVE_IV
5752  }
5753  }
5754  }
5755  }
5756  if (n_trajec == 0) { // if errors reduced to 0, clean up
5757  assert(n_pr == 0);
5758  if (types) { delete [] types; types = NULL; }
5759  if (indices) { delete [] indices; indices = NULL; }
5760  if (vpr) { delete [] vpr; vpr = NULL; }
5761  if (varrays) { delete [] varrays; varrays = NULL; }
5762  if (pvars) { delete [] pvars; pvars = NULL; }
5763  }
5764 #if 0
5765  printf("nrnthread_get_trajectory_requests tid=%d bsize=%d n_pr=%d n_trajec=%d\n", tid, bsize, n_pr, n_trajec);
5766  int i_trajec = 0;
5767  double* pd;
5768  for (int i=0; i < n_pr; ++i) {
5769  PlayRecord* pr = (PlayRecord*)vpr[i];
5770  pd = pr->pd_;
5771  if (pd) {
5772  printf(" %d %d prtype=%d %p type=%d index=%d\n", i, i_trajec, pr->type(), pd, types[i_trajec], indices[i_trajec]);
5773  i_trajec++;
5774  }else{
5775  assert(pr->type() == GLineRecordType);
5776  GLineRecord* glr = (GLineRecord*)pr;
5777  GLineRecordEData& ed = glr->pd_and_vec_;
5778  i_trajec += ed.size();
5779  }
5780  }
5781 #endif
5782  }
5783 }
5784 
5785 void nrnthread_trajectory_values(int tid, int n_pr, void** vpr, double tt){ //, int n_trajec, double* values) {
5786  if (tid < 0) {
5787  return;
5788  }
5789  if (tid < nrn_nthread) {
5790 #if HAVE_IV
5791  ObjectContext obc(NULL); // in case GLineRecord with expression.
5792 #endif // HAVE_IV
5793  nrn_threads[tid]._t = tt;
5794  if (tid == 0) { t = tt; }
5795  int i_trajec = 0;
5796  int flush = 0;
5797  for (int i=0; i < n_pr; ++i) {
5798  PlayRecord* pr = (PlayRecord*)vpr[i];
5799  pr->continuous(tt);
5800 #if HAVE_IV
5801  if (pr->type() == GVectorRecordType) { // see the movie
5802  flush = 1;
5803  }
5804  }
5805  if (flush) {
5806  Oc oc;
5807  oc.run("screen_update()\n");
5808  }
5809  obc.restore();
5810 #else
5811  }
5812 #endif // HAVE_IV
5813  }
5814 }
5815 
5816 // CoreNEURON received pointers to the data of each Vector (resized so that
5817 // the data is long enough to hold the trajectory (tstop/dt). On calling
5818 // this, each Vector needs only be resized to the actual vecsz.
5819 // Note that we have not bothered to fill the variables on the hoc side with
5820 // the last values, though we did fill t.
5821 // In the case where glr->pd_ = NULL, the GraphLine is an expression that
5822 // cannot be interpreted as a pointer and the expression involves one or
5823 // more range variables that individually were resolved into pointers. In
5824 // this case in glr->plot, the relevant Vector elements are copied into those
5825 // pointers and the expression is then evaluated and plotted.
5826 void nrnthread_trajectory_return(int tid, int n_pr, int bsize, int vecsz, void** vpr, double tt) {
5827  if (tid < 0) {
5828  return;
5829  }
5830  if (tid < nrn_nthread) {
5831  nrn_threads[tid]._t = tt;
5832  if (tid == 0) { t = tt; }
5833  for (int i=0; i < n_pr; ++i) {
5834  PlayRecord* pr = (PlayRecord*)vpr[i];
5835  IvocVect* v = NULL;
5836  if (pr->type() == TvecRecordType) {
5837  v = ((TvecRecord*)pr)->t_;
5838  // reserved bsize but only used vecsz. (need non-zeroing resize).
5839  v->resize(v->size() - (bsize - vecsz)); // do not zero
5840  }else if (pr->type() == YvecRecordType) {
5841  v = ((YvecRecord*)pr)->y_;
5842  v->resize(v->size() - (bsize - vecsz)); // do not zero
5843 #if HAVE_IV
5844  }else if (pr->type() == GLineRecordType) {
5845  GLineRecord* glr = (GLineRecord*)pr;
5846  glr->plot(vecsz, tt);
5847 #endif // HAVE_IV
5848  }else{
5849  assert(0);
5850  }
5851  }
5852  }
5853 }
5854 
5855 // factored this out from deliver_net_events so we can
5856 // stay in the cache
5857 void NetCvode::check_thresh(NrnThread* nt) { // for default method
5858  nrn::Instrumentor::phase p_check_threshold("check-threshold");
5859  int i;
5860  hoc_Item* pth = p[nt->id].psl_thr_;
5861 
5862  if (pth) { /* only look at ones with a threshold */
5863  hoc_Item* q1;
5864  ITERATE(q1, pth) {
5865  PreSyn* ps = (PreSyn*)VOIDITM(q1);
5866  // only the ones for this thread
5867  if (ps->nt_ == nt) {
5868  if (ps->thvar_) {
5869  ps->check(nt, nt->_t, 1e-10);
5870  }
5871  }
5872  }
5873  }
5874 
5875  for (HTList* wl: wl_list_[nt->id]) {
5876  for (HTList* item = wl->First(); item != wl->End(); item = item->Next()) {
5877  WatchCondition* wc = (WatchCondition*)item;
5878  wc->check(nt, nt->_t);
5879  }
5880  }
5881 }
5882 
5883 /** In nrncore_callbacks.cpp **/
5885  void(*cb)(int, int, int, int, int));
5886 extern "C" {
5887 void nrn2core_transfer_WATCH(void(*cb)(int, int, int, int, int));
5888 }
5889 void nrn2core_transfer_WATCH(void(*cb)(int, int, int, int, int)) {
5890  // should be revisited for possible simplification since wl_list now
5891  // segregated by threads.
5892  for (auto& htlists_of_thread : net_cvode_instance->wl_list_) {
5893  for (HTList* wl : htlists_of_thread) {
5894  for (HTList* item = wl->First(); item != wl->End(); item = item->Next()) {
5895  WatchCondition* wc = (WatchCondition*)item;
5897  }
5898  }
5899  }
5900 }
5901 
5902 void NetCvode::deliver_net_events(NrnThread* nt) { // for default method
5903  TQItem* q;
5904  double tm, tt, tsav;
5905 #if BGPDMA
5906  if (use_bgpdma_) { nrnbgp_messager_advance(); }
5907 #endif
5908  int tid = nt->id;
5909  tsav = nt->_t;
5910  tm = nt->_t + 0.5*nt->_dt;
5911 #if BBTQ == 5
5912  tryagain:
5913  // one of the events on the main queue may be a NetParEvent
5914  // which due to dt round off error can result in an event
5915  // placed on the bin queue to be delivered now, which
5916  // can put 0 delay events on to the main queue. So loop til
5917  // no events. The alternative would be to deliver an idt=0 event
5918  // immediately but that would very much change the sequence
5919  // with respect to what is being done here and it is unclear
5920  // how to fix the value of t there. This can be a do while loop
5921  // but I do not want to affect the case of not using a bin queue.
5922 
5923  if (nrn_use_bin_queue_) {
5924  // it was noticed on binq + compressed spike exchange +
5925  // threads that a transferred event may be languishing in
5926  // the interthread event buffer. Perhaps this is better done
5927  // as a multithread job at the end of nrn_spike_exchange
5928  // instead of every time step --- but here we are
5929  // already in a multithread job, so what is the overhead of
5930  // starting such a small one in nrn_spike_exchange.
5931 #if NRNMPI
5932  extern bool nrn_use_compress_;
5933  if (nrn_use_compress_ && nrn_nthread > 1) {
5934  p[tid].enqueue(this, nt);
5935  }
5936 #endif
5937  while ((q = p[tid].tqe_->dequeue_bin()) != 0) {
5938  DiscreteEvent* db = (DiscreteEvent*)q->data_;
5939 #if PRINT_EVENT
5940 if (print_event_) {db->pr("binq deliver", nt_t, this);}
5941 #endif
5942  p[tid].tqe_->release(q);
5943  db->deliver(nt->_t, this, nt);
5944  }
5945 // assert(int(tm/nt->_dt)%1000 == p[tid].tqe_->nshift_);
5946  }
5947 #endif
5948 
5949  deliver_events(tm, nt);
5950 
5951 #if BBTQ == 5
5952  if (nrn_use_bin_queue_) {
5953  if (p[tid].tqe_->top()) { goto tryagain; }
5954  p[tid].tqe_->shift_bin(tm);
5955  }
5956 #endif
5957  nt->_t = tsav;
5958 }
5959 
5961 
5962 void NetCvode::playrec_add(PlayRecord* pr) { // called by PlayRecord constructor
5963 //printf("NetCvode::playrec_add %p\n", pr);
5964  playrec_change_cnt_ = 0;
5965  prl_->append(pr);
5966 }
5967 
5968 void NetCvode::playrec_remove(PlayRecord* pr) { // called by PlayRecord destructor
5969 //printf("NetCvode::playrec_remove %p\n", pr);
5970  playrec_change_cnt_ = 0;
5971  int i, cnt = prl_->count();
5972  for (i=0; i < cnt; ++i) {
5973  if (prl_->item(i) == pr) {
5974  prl_->remove(i);
5975  break;
5976  }
5977  }
5978  cnt = fixed_play_->count();
5979  for (i=0; i < cnt; ++i) {
5980  if (fixed_play_->item(i) == pr) {
5981  fixed_play_->remove(i);
5982  break;
5983  }
5984  }
5985  cnt = fixed_record_->count();
5986  for (i=0; i < cnt; ++i) {
5987  if (fixed_record_->item(i) == pr) {
5988  fixed_record_->remove(i);
5989  break;
5990  }
5991  }
5992 }
5993 
5995  int i, cnt = prl_->count();
5996  for (i=0; i < cnt; ++i) {
5997  if (prl_->item(i) == pr) {
5998  return i;
5999  }
6000  }
6001  return -1;
6002 }
6003 
6005  assert(i < prl_->count());
6006  return prl_->item(i);
6007 }
6008 
6010  int i, cnt = prl_->count();
6011  for (i=0; i < cnt; ++i) {
6012  if (prl_->item(i)->uses(v)) {
6013  return prl_->item(i);
6014  }
6015  }
6016  return nil;
6017 }
6018 
6019 PlayRecord::PlayRecord(double* pd, Object* ppobj) {
6020 //printf("PlayRecord::PlayRecord %p\n", this);
6021  pd_ = pd;
6022  cvode_ = nil;
6023  ith_ = 0;
6024  if (pd_) {
6025  nrn_notify_when_double_freed(pd_, this);
6026  }
6027  ppobj_ = ppobj;
6028  if (ppobj_) {
6029  ObjObservable::Attach(ppobj_, this);
6030  }
6031  net_cvode_instance->playrec_add(this);
6032 }
6033 
6035 //printf("PlayRecord::~PlayRecord %p\n", this);
6037  if (ppobj_) {
6038  ObjObservable::Detach(ppobj_, this);
6039  }
6040  net_cvode_instance->playrec_remove(this);
6041 }
6042 
6043 void PlayRecord::update_ptr(double* pd) {
6045  nrn_notify_when_double_freed(pd, this);
6046  pd_ = pd;
6047 }
6048 
6050 //printf("PlayRecord::disconnect %ls\n", (long)this);
6051  delete this;
6052 }
6053 
6055  cvode_ = cv;
6056  if (cv) {
6057  cv->record_add(this);
6058  }
6059  net_cvode_instance->fixed_record_->append(this);
6060 }
6061 
6063  cvode_ = cv;
6064  if (cv) {
6065  cv->play_add(this);
6066  }
6067  net_cvode_instance->fixed_play_->append(this);
6068 }
6069 
6071  Printf("PlayRecord\n");
6072 }
6073 
6074 TvecRecord::TvecRecord(Section* sec, IvocVect* t, Object* ppobj) : PlayRecord(&NODEV(sec->pnode[0]), ppobj) {
6075 //printf("TvecRecord\n");
6076  t_ = t;
6077  ObjObservable::Attach(t_->obj_, this);
6078 }
6079 
6081 //printf("~TvecRecord\n");
6082  ObjObservable::Detach(t_->obj_, this);
6083 }
6084 
6086 // printf("%s TvecRecord disconnect\n", hoc_object_name(t_->obj_));
6087  delete this;
6088 }
6089 
6091  record_add(cv);
6092 }
6093 
6095  t_->resize(0);
6096 }
6097 
6098 void TvecRecord::continuous(double tt) {
6099  t_->push_back(tt);
6100 }
6101 
6102 YvecRecord::YvecRecord(double* pd, IvocVect* y, Object* ppobj) : PlayRecord(pd, ppobj) {
6103 //printf("YvecRecord\n");
6104  y_ = y;
6105  ObjObservable::Attach(y_->obj_, this);
6106 }
6107 
6109 //printf("~YvecRecord\n");
6110  ObjObservable::Detach(y_->obj_, this);
6111 }
6112 
6114 // printf("%s YvecRecord disconnect\n", hoc_object_name(y_->obj_));
6115  delete this;
6116 }
6117 
6119  record_add(cv);
6120 }
6121 
6123  y_->resize(0);
6124 }
6125 
6126 void YvecRecord::continuous(double tt) {
6127  y_->push_back(*pd_);
6128 }
6129 
6130 VecRecordDiscrete::VecRecordDiscrete(double* pd, IvocVect* y, IvocVect* t, Object* ppobj) : PlayRecord(pd, ppobj) {
6131 //printf("VecRecordDiscrete\n");
6132  y_ = y;
6133  t_ = t;
6134  ObjObservable::Attach(y_->obj_, this);
6135  ObjObservable::Attach(t_->obj_, this);
6136  e_ = new PlayRecordEvent();
6137  e_->plr_ = this;
6138 }
6139 
6141 //printf("~VecRecordDiscrete\n");
6142  ObjObservable::Detach(y_->obj_, this);
6143  ObjObservable::Detach(t_->obj_, this);
6144  delete e_;
6145 }
6146 
6148  return new VecRecordDiscreteSave(this);
6149 }
6150 
6152  cursize_ = ((VecRecordDiscrete*)pr_)->y_->size();
6153 }
6155 }
6157  check();
6158  VecRecordDiscrete* vrd = (VecRecordDiscrete*)pr_;
6159  vrd->y_->resize(cursize_);
6160  assert(cursize_ <= vrd->t_->size());
6161 }
6163  fprintf(f, "%d\n", cursize_);
6164 }
6166  char buf[100];
6167  nrn_assert(fgets(buf, 100, f));
6168  nrn_assert(sscanf(buf, "%d\n", &cursize_) == 1);
6169 }
6170 
6172 // printf("%s VecRecordDiscrete disconnect\n", hoc_object_name(y_->obj_));
6173  delete this;
6174 }
6175 
6177  record_add(cv);
6178 }
6179 
6181  y_->resize(0);
6182  if (t_->size() > 0) {
6183  e_->send(t_->elem(0), net_cvode_instance, nrn_threads);
6184  }
6185 }
6186 
6188  record_init_items_->append(q);
6189 }
6190 
6191 void VecRecordDiscrete::deliver(double tt, NetCvode* nc) {
6192  y_->push_back(*pd_);
6193  assert(Math::equal(t_->elem(y_->size()-1), tt, 1e-8));
6194  if (y_->size() < t_->size()) {
6195  e_->send(t_->elem(y_->size()), nc, nrn_threads);
6196  }
6197 }
6198 
6199 VecRecordDt::VecRecordDt(double* pd, IvocVect* y, double dt, Object* ppobj) : PlayRecord(pd, ppobj) {
6200 //printf("VecRecordDt\n");
6201  y_ = y;
6202  dt_ = dt;
6203  ObjObservable::Attach(y_->obj_, this);
6204  e_ = new PlayRecordEvent();
6205  e_->plr_ = this;
6206 }
6207 
6209 //printf("~VecRecordDt\n");
6210  ObjObservable::Detach(y_->obj_, this);
6211  delete e_;
6212 }
6213 
6214 PlayRecordSave* VecRecordDt::savestate_save() {
6215  return new VecRecordDtSave(this);
6216 }
6217 
6219 }
6221 }
6223  check();
6224 }
6225 
6227 // printf("%s VecRecordDt disconnect\n", hoc_object_name(y_->obj_));
6228  delete this;
6229 }
6230 
6232  record_add(cv);
6233 }
6234 
6236  y_->resize(0);
6237  e_->send(nrn_threads->_t, net_cvode_instance, nrn_threads);
6238 }
6239 
6241  record_init_items_->append(q);
6242 }
6243 
6244 void VecRecordDt::deliver(double tt, NetCvode* nc) {
6245  if (pd_ == &t) {
6246  y_->push_back(tt);
6247  }else{
6248  y_->push_back(*pd_);
6249  }
6250  e_->send(tt + dt_, nc, nrn_threads);
6251 }
6252 
6254  double* pd = hoc_pgetarg(1);
6255  consist_sec_pd("Cvode.record", chk_access(), pd);
6256  IvocVect* y = vector_arg(2);
6257  IvocVect* t = vector_arg(3);
6258  PlayRecord* pr = playrec_uses(y);
6259  if (pr) {
6260  delete pr;
6261  }
6262  bool discrete = ( (ifarg(4) && (int)chkarg(4,0,1) == 1) ? true : false);
6263  if (discrete) {
6264  pr = new VecRecordDiscrete(pd, y, t);
6265  }else{
6266  pr = playrec_uses(t);
6267  if (pr) {
6268  delete pr;
6269  }
6270  pr = new TvecRecord(chk_access(), t);
6271  pr = new YvecRecord(pd, y);
6272  }
6273 }
6274 
6276  IvocVect* iv = vector_arg(1);
6277  PlayRecord* pr;
6278  while((pr = playrec_uses(vector_arg(1))) != nil) {
6279  delete pr;
6280  }
6281 }
6282 
6284  long i, j, iprl, prlc;
6285  double* px;
6286  prlc = prl_->count();
6287  fixed_record_->remove_all();
6288  fixed_play_->remove_all();
6289  if (gcv_) {
6290  gcv_->delete_prl();
6291  }else{
6292  lvardtloop(i, j) {
6293  p[i].lcv_[j].delete_prl();
6294  }
6295  }
6296  for (iprl = 0; iprl < prlc; ++iprl) {
6297  PlayRecord* pr = prl_->item(iprl);
6298  bool b = false;
6299  if (single_) {
6300  pr->install(gcv_);
6301  b = true;
6302  }else{
6303  if (pr->ppobj_ && ob2pntproc(pr->ppobj_)->nvi_) {
6304  pr->install((Cvode*)ob2pntproc(pr->ppobj_)->nvi_);
6305  b = true;
6306  }else{
6307  lvardtloop(i, j) {
6308  Cvode& cv= p[i].lcv_[j];
6309  if (cv.is_owner(pr->pd_)) {
6310  pr->install(&cv);
6311  b = true;
6312  break;
6313  }
6314  }
6315  }
6316  }
6317  if (b == false) {
6318 hoc_execerror("We were unable to associate a PlayRecord item with a RANGE variable", nil);
6319  }
6320  // and need to know the thread owners
6321  if (pr->ppobj_) {
6322  i = PP2NT(ob2pntproc(pr->ppobj_))->id;
6323  }else{
6324  i = owned_by_thread(pr->pd_);
6325  }
6326  if (i < 0) {
6327 hoc_execerror("We were unable to associate a PlayRecord item with a thread", nil);
6328  }
6329  pr->ith_ = i;
6330  }
6331  playrec_change_cnt_ = structure_change_cnt_;
6332 }
6333 
6334 bool Cvode::is_owner(double* pd) { // is a pointer to range variable in this cell
6335  int in, it;
6336  for (it=0; it < nrn_nthread; ++it) {
6337  CvodeThreadData& z = CTD(it);
6338  for (in=0; in < z.v_node_count_; ++in) {
6339  Node* nd = z.v_node_[in];
6340  if (&NODEV(nd) == pd) {
6341  return true;
6342  }
6343  Prop* p;
6344  for (p = nd->prop; p; p = p->next) {
6345  if (pd >= p->param && pd < (p->param + p->param_size)) {
6346  return true;
6347  }
6348  }
6349  if (nd->extnode) {
6350  if (pd >= nd->extnode->v && pd < (nd->extnode->v + nlayer)) {
6351  return true;
6352  }
6353  }
6354  // will need to check the linear mechanisms when there is a cvode
6355  // specific list of them and IDA is allowed for local step method.
6356  }
6357  if (nth_) { break;} // lvardt
6358  }
6359  return false;
6360 }
6361 
6362 int NetCvode::owned_by_thread(double* pd) {
6363  if (nrn_nthread == 1) { return 0; }
6364  int in, it;
6365  for (it = 0; it < nrn_nthread; ++it) {
6366  NrnThread& nt = nrn_threads[it];
6367  int i1 = 0;
6368  int i3 = nt.end;
6369  for (in=i1; in < i3; ++in) {
6370  Node* nd = nt._v_node[in];
6371  if (&NODEV(nd) == pd) {
6372  return it;
6373  }
6374  Prop* p;
6375  for (p = nd->prop; p; p = p->next) {
6376  if (pd >= p->param && pd < (p->param + p->param_size)) {
6377  return it;
6378  }
6379  }
6380  if (nd->extnode) {
6381  if (pd >= nd->extnode->v && pd < (nd->extnode->v + nlayer)) {
6382  return it;
6383  }
6384  }
6385  // will need to check the line mechanisms when there is a cvode
6386  // specific list of them and IDA is allowed for local step method.
6387  }
6388  }
6389  return -1;
6390 }
6391 
6392 void NetCvode::consist_sec_pd(const char* msg, Section* sec, double* pd) {
6393  int in;
6394  Node* nd;
6395  for (in=-1; in < sec->nnode; ++in) {
6396  if (in == -1) {
6397  nd = sec->parentnode; // in case &v(0)
6398  if (!nd) { continue; }
6399  }else{
6400  nd = sec->pnode[in];
6401  }
6402  if (&NODEV(nd) == pd) {
6403  return;
6404  }
6405  Prop* p;
6406  for (p = nd->prop; p; p = p->next) {
6407  if (pd >= p->param && pd < (p->param + p->param_size)) {
6408  return;
6409  }
6410  }
6411  if (nd->extnode) {
6412  if (pd >= nd->extnode->v && pd < (nd->extnode->v + nlayer)) {
6413  return;
6414  }
6415  }
6416  // will need to check the linear mechanisms when there is a cvode
6417  // specific list of them and IDA is allowed for local step method.
6418  }
6419  hoc_execerror(msg, " pointer not associated with currently accessed section\n\
6420 Use section ... (&var(x)...) intead of ...(&section.var(x)...)\n");
6421 }
6422 
6424  int i, j;
6425  if (hoc_is_double_arg(1)) {
6426  int on = (int)chkarg(1, 0, 2);
6427  int i;
6428  if (on == 2) {
6429  maxstate_analyse();
6430  }else{
6431  if (gcv_) {
6432  gcv_->activate_maxstate(on?true:false);
6433  }else{
6434  lvardtloop(i, j) {
6435  p[i].lcv_[j].activate_maxstate(on?true:false);
6436  }
6437  }
6438  }
6439  return 0.;
6440  }else if (hoc_is_str_arg(1)) {
6441  Symbol* sym = name2sym(gargstr(1));
6442  double dummy;
6443  double* pamax = &dummy;
6444  if (ifarg(2)) {
6445  pamax = hoc_pgetarg(2);
6446  }
6447  return maxstate_analyse(sym, pamax);
6448  }else{
6449  int i, j, n;
6450  Vect* v = vector_arg(1);
6451  if (!cvode_active_){
6452  v->resize(0);
6453  return 0.;
6454  }
6455  double* vp;
6456  double* ms;
6457  n = 0;
6458  if (gcv_) {
6459  n += gcv_->neq_;
6460  }else{
6461  lvardtloop(i, j) {
6462  n += p[i].lcv_[j].neq_;
6463  }
6464  }
6465  v->resize(n);
6466  vp = vector_vec(v);
6467  int getacor = 0;
6468  if (ifarg(2)) {
6469  getacor = (int)chkarg(2, 0, 1);
6470  }
6471  j = 0;
6472  if (gcv_) {
6473  if (gcv_->maxstate_) {
6474  if (getacor) {
6475  gcv_->maxacor(vp);
6476  }else{
6477  gcv_->maxstate(vp);
6478  }
6479  }
6480  }else{
6481  lvardtloop(i, j) {
6482  Cvode& cv = p[i].lcv_[j];
6483  if (cv.maxstate_) {
6484  if (getacor) {
6485  cv.maxacor(vp+j);
6486  }else{
6487  cv.maxstate(vp+j);
6488  }
6489  }
6490  j += cv.neq_;
6491  }
6492  }
6493  return 0.;
6494  }
6495 }
6497  int j, n;
6498  Symbol* sym;
6499  double* ms;
6500  double* ma;
6501  n = z.nvsize_;
6502  ms = cv.n_vector_data(cv.maxstate_, it);
6503  ma = cv.n_vector_data(cv.maxacor_, it);
6504  for (j=0; j < n; ++j) {
6505  sym = hdp_->retrieve_sym(z.pv_[j]);
6506  if (!mst_->find(msi, (void*)sym)) {
6507  msi = new MaxStateItem();
6508  msi->sym_ = sym;
6509  msi->max_ = -1e9;
6510  msi->amax_ = -1e9;
6511  mst_->insert((void*)sym, msi);
6512  }
6513  if (msi->max_ < ms[j]) { msi->max_ = ms[j];}
6514  if (msi->amax_ < ma[j]) { msi->amax_ = ma[j];}
6515  }
6516 }
6517 
6519  int i, it, j, n;
6520  MaxStateItem* msi;
6521  Symbol* sym;
6522  if (!mst_) {
6523  int n = 0;
6524  for (sym = hoc_built_in_symlist->first; sym; sym = sym->next) {
6525  ++n;
6526  }
6527  mst_ = new MaxStateTable(3*n);
6528  }
6529  {for (TableIterator(MaxStateTable) ti(*mst_); ti.more(); ti.next()) {
6530  msi = ti.cur_value();
6531  msi->max_ = -1e9;
6532  msi->amax_ = -1e9;
6533  }}
6534  if (empty_) { return; }
6535  statename(0,2);
6536  if (gcv_) {
6537  for (it=0; it < nrn_nthread; ++it) {
6538  maxstate_analyze_1(it, *gcv_, msi, gcv_->ctd_[it]);
6539  }
6540  }else{
6541  lvardtloop(i, j) {
6542  Cvode& cv = p[i].lcv_[j];
6543  maxstate_analyze_1(i, cv, msi, cv.ctd_[0]);
6544  }
6545  }
6546 }
6547 
6548 double NetCvode::maxstate_analyse(Symbol* sym, double* pamax) {
6549  MaxStateItem* msi;
6550  if (mst_ && mst_->find(msi, (void*)sym)) {
6551  *pamax = msi->amax_;
6552  return msi->max_;
6553  }
6554  *pamax = -1e9;
6555  return -1e9;
6556 }
6557 
6559 #if CACHEVEC
6560  // update PlayRecord pointers to v
6561  int i, cnt = prl_->count();
6562  for (i=0; i < cnt; ++i) {
6563  PlayRecord* pr = prl_->item(i);
6564  if (pr->pd_) {
6565  pr->update_ptr(nrn_recalc_ptr(pr->pd_));
6566  }
6567  }
6568  // update PreSyn pointers to v
6569  hoc_Item* q;
6570  if (psl_) ITERATE(q, psl_) {
6571  PreSyn* ps = (PreSyn*)VOIDITM(q);
6572  if (ps->thvar_) {
6573  double* pd = nrn_recalc_ptr(ps->thvar_);
6574  if (pd != ps->thvar_) {
6575  pst_->remove(ps->thvar_);
6576  pst_->insert(pd, ps);
6577  ps->update_ptr(pd);
6578  }
6579  }
6580  }
6581 #endif
6582 }
6583 
6584 static double lvardt_tout_;
6585 
6586 static void* lvardt_integrate(NrnThread* nt) {
6587  size_t err = NVI_SUCCESS;
6588  int id = nt->id;
6590  NetCvodeThreadData& p = nc->p[id];
6591  TQueue* tq = p.tq_;
6592  TQueue* tqe = p.tqe_;
6593  double tout = lvardt_tout_;
6594  nt->_stop_stepping = 0;
6595  while (tq->least_t() < tout || tqe->least_t() <= tout) {
6596  err = nc->local_microstep(nt);
6597  if (nt->_stop_stepping) {
6598  nt->_stop_stepping = 0;
6599  return (void*)err;
6600  }
6601  if (err != NVI_SUCCESS || stoprun) { return (void*)err; }
6602  }
6603  int n = p.nlcv_;
6604  Cvode* lcv = p.lcv_;
6605  if (n) for (int i=0; i < n; ++i) {
6606  nc->retreat(tout, lcv + i);
6607  lcv[i].record_continuous();
6608  }else{
6609  nt->_t = tout;
6610  }
6611  return (void*)err;
6612 }
6613 
6615  int err = NVI_SUCCESS;
6616  int tid;
6617  double til;
6618  nrn_use_busywait(1); // just a possibility
6619  if (empty_) {
6620  if (tout >= 0.) {
6621  while (nt_t < tout && !stoprun) {
6622  deliver_events_when_threads(tout);
6623  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
6624  }
6625  if (stoprun==0) {
6626  nt_t = tout;
6627  }
6628  } else {
6629 
6630  if ((til = allthread_least_t(tid)) < 1e10) {
6631  deliver_events_when_threads(til);
6632  }else{
6633  nt_t += 1e6;
6634  }
6635  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
6636  }
6637  }else if (gcv_) {
6638  if (tout >= 0.) {
6639  while (gcv_->t_ < tout || allthread_least_t(tid) < tout) {
6640  err = global_microstep_when_threads();
6641  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
6642  if (err != NVI_SUCCESS || stoprun) { return err; }
6643  }
6644  retreat(tout, gcv_);
6645  gcv_->record_continuous();
6646  } else {
6647  // advance or initialized
6648  double tc = gcv_->t_;
6649  initialized_ = false;
6650  while (gcv_->t_ <= tc && !initialized_) {
6651  err = global_microstep_when_threads();
6652  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
6653  if (err != NVI_SUCCESS || stoprun) { return err; }
6654  }
6655  }
6656  }else{ // lvardt
6657  if (tout >= 0.) {
6658  // Each thread could integrate independently to tout
6659  // as long as no thread got more than
6660  // a minimum delay interval ahead of any other.
6661  // For now just integrate by min delay intervals.
6662  lvardt_tout_ = tout;
6663  while(nt_t < tout) {
6665  if (nrn_allthread_handle) { (*nrn_allthread_handle)(); }
6666  if (err != NVI_SUCCESS || stoprun) { return err; }
6667  int tid;
6668  allthread_least_t(tid);
6669  }
6670  }else{
6671  // nthread>1 is more or less purposeless if we mean
6672  // that only the least cvode of all threads advances.
6673  // (which is required if minimum delay = 0)
6674  if (nrn_nthread > 1) {
6675 hoc_execerror("Lvardt method from fadvance()", "presently limited to single thread.");
6676  }
6677  }
6678  }
6679  nrn_use_busywait(0);
6680  t = nt_t;
6681  dt = nt_dt;
6682  return err;
6683 }
6684 
6685 static void* deliver_for_thread(NrnThread* nt) {
6687  NetCvodeThreadData& d = nc->p[nt->id];
6688  TQItem* q = d.tqe_->least();
6689  DiscreteEvent* de = (DiscreteEvent*)q->data_;
6690  double tt = q->t_;
6691  d.tqe_->remove(q);
6692 #if PRINT_EVENT
6693  if (nc->print_event_) { de->pr("deliver", tt, nc); }
6694 #endif
6695  de->deliver(tt, nc, nt);
6696  return 0;
6697 }
6698 
6700 //printf("deliver_events til %20.15g\n", til);
6701  int tid;
6702  while(allthread_least_t(tid) <= til) {
6703  STATISTICS(deliver_cnt_);
6705  if (stoprun || nrn_allthread_handle) { return; }
6706  }
6707 }
6708 
6710  int err = NVI_SUCCESS;
6711  int tid;
6712  double tt = allthread_least_t(tid);
6713  double tdiff = tt - gcv_->t_;
6714  if (tdiff <= 0) {
6715  // since events do not internally retreat with the
6716  // global step, we should already be at the event time
6717  // if this is too strict, we could use eps(list_->t_).
6718 //if (tdiff != 0.0) { printf("tdiff=%g\n", tdiff); }
6719  assert(tdiff == 0.0 || ( gcv_->tstop_begin_ <= tt && tt <= gcv_->tstop_end_));
6720  deliver_events_when_threads(tt);
6721  }else{
6722  err = gcv_->handle_step(this, tt);
6723  }
6724  if ((tt = allthread_least_t(tid)) < gcv_->t_) {
6725  gcv_->interpolate(tt);
6726  }
6727  return err;
6728 }
6729 
6731  net_cvode_instance->p[nt->id].enqueue(net_cvode_instance, nt);
6732  return 0;
6733 }
6734 
6736  MUTLOCK
6737  enqueueing_ = 1;
6738  MUTUNLOCK
6739 }
6740 
6742  // reduce (take minimum) of p[i].tqe_->least_t()
6743  double tt, min = 1e50;
6744 // setting enqueueing_ in interthread_send was a race. Logically it is not
6745 // needed. It is not clear if higher performance would result in having
6746 // a MUTEX for the NetCvode instance but that is the current implementation
6747 // instead of commenting out the enqueuing related lines.
6748  if (enqueueing_) {
6750  enqueueing_ = 0;
6751  }
6752  for (int id = 0; id < pcnt_; ++id) {
6753  tt = p[id].tqe_->least_t();
6754  if (tt < min) { tid = id; min = tt; }
6755  }
6756  return min;
6757 }
static unsigned long abandon_init_below_
Definition: netcon.h:187
o
Definition: seclist.cpp:180
ReceiveFunc * pnt_receive
Definition: init.cpp:171
IvocVect * tvec_
Definition: netcon.h:267
void error_weights()
Definition: netcvode.cpp:4268
static unsigned long send_qthresh_
Definition: netcon.h:183
ms
Definition: extargs.h:1
HTList * Next()
Definition: htlist.h:67
HTList * End()
Definition: htlist.h:66
int owned_by_thread(double *)
Definition: netcvode.cpp:6362
int nonvint_extra_offset_
Definition: cvodeobj.h:70
int cnt_
Definition: netcon.h:109
Definition: hocdec.h:84
HTListList wl_list_
Definition: netcvode.h:209
void p_construct(int)
Definition: netcvode.cpp:4893
virtual void savestate_restore(double deliverytime, NetCvode *)
Definition: netcvode.cpp:3506
#define STATISTICS(arg)
Definition: netcon.h:21
#define Printf
Definition: model.h:252
virtual void deliver(double t, NetCvode *)
Definition: netcvode.cpp:6191
static int trajec_buffered(NrnThread &nt, int bsize, IvocVect *v, double *pd, int i_pr, PlayRecord *pr, void **vpr, int i_trajec, int *types, int *indices, double **pvars, double **varrays)
Definition: netcvode.cpp:5574
FOR_THREADS(_nt)
Definition: multicore.cpp:887
double * v
Definition: section.h:195
void fornetcon_prepare()
Definition: netcvode.cpp:4003
int param_size
Definition: section.h:217
#define nrn_assert(ex)
Definition: nrnassrt.h:35
virtual ~VecRecordDt()
Definition: netcvode.cpp:6208
void deliver_events(double til, NrnThread *)
Definition: netcvode.cpp:2978
hoc_List * hoc_l_newlist()
struct Memb_list Memb_list
void distribute_dinfo(int *, int)
Definition: netcvode.cpp:1488
double * param
Definition: section.h:218
void record_add(Cvode *)
Definition: netcvode.cpp:6054
struct Prop * prop
Definition: section.h:62
virtual ~NetConSave()
Definition: netcvode.cpp:4757
int _stop_stepping
Definition: multicore.h:67
bool is_local()
Definition: netcvode.cpp:1280
#define assert(ex)
Definition: hocassrt.h:26
bool flag_
Definition: netcon.h:180
virtual void update_ptr(double *)
Definition: netcvode.cpp:6043
static double nc_active(void *v)
Definition: netcvode.cpp:709
struct Arrayinfo Arrayinfo
Object * nrn_sec2cell(Section *)
Definition: cabcode.cpp:224
short type
Definition: cabvars.h:10
virtual ~CvMembList()
Definition: netcvode.cpp:1463
short nnode
Definition: section.h:41
int hoc_is_str_arg(int narg)
Definition: code.cpp:741
int nrn_modeltype()
Definition: treeset.cpp:1934
return true
Definition: savstate.cpp:357
void allthread_handle()
Definition: netcvode.cpp:2706
int maxorder()
Definition: netcvode.h:139
static void * eval_cond(NrnThread *nt)
Definition: netcvode.cpp:5488
void update_ptr(double *)
Definition: netcvode.cpp:5176
void * _vnt
Definition: section.h:269
void nrn_multithread_job(void *(*job)(NrnThread *))
Definition: multicore.cpp:1081
static double nc_srcgid(void *v)
Definition: netcvode.cpp:769
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:3489
void init()
Definition: netcvode.cpp:5061
virtual ~NetCon()
Definition: netcvode.cpp:4706
TQItem * event(double tdeliver, DiscreteEvent *, NrnThread *)
Definition: netcvode.cpp:2623
void re_init(double t0=0.)
Definition: netcvode.cpp:3968
virtual void disconnect(Observable *)
Definition: netcvode.cpp:6049
std::unordered_map< long, Point_process * > SelfEventPPTable
Definition: netcon.h:41
void * _pvoid
Definition: hocdec.h:186
void record_continuous()
Definition: occvode.cpp:991
struct Node * parentnode
Definition: section.h:50
BAMechList * cvbml(int, BAMech *, Cvode *)
Definition: netcvode.cpp:1880
Memb_list * ml
Definition: multicore.h:40
TQItem * bin_event(double tdeliver, DiscreteEvent *, NrnThread *)
Definition: netcvode.cpp:2600
HTList(void *=NULL)
Definition: htlist.cpp:41
bool var1_is_time_
Definition: nrnste.h:28
implementPtrList(PlayRecList, PlayRecord) void NetCvode
Definition: netcvode.cpp:5960
void statistics(int)
Definition: netcvode.cpp:3880
static unsigned long presyn_send_direct_
Definition: netcon.h:294
virtual ~ConditionEvent()
Definition: netcvode.cpp:5205
virtual void disconnect(Observable *)
Definition: netcvode.cpp:6113
static unsigned long hocevent_deliver_
Definition: netcon.h:337
void nrn_ba(NrnThread *, int)
Definition: fadvance.cpp:1041
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:3388
Definition: netcon.h:232
#define NODEV(n)
Definition: section.h:114
#define Vect
Definition: ivocvect.h:14
double(* c_)(Point_process *)
Definition: netcon.h:209
void(* ReceiveFunc)(Point_process *, double *, double)
Definition: netcvode.cpp:47
void activate(double flag)
Definition: netcvode.cpp:5311
double nrn_hoc2gather_y(void *v)
Definition: netcvode.cpp:4258
struct NrnThreadMembList * next
Definition: multicore.h:34
#define GLineRecordType
Definition: vrecitem.h:25
Symlist * hoc_top_level_symlist
Definition: symbol.cpp:41
if(status)
#define nt_dt
Definition: netcvode.cpp:78
short type
Definition: model.h:58
virtual ~VecRecordDiscreteSave()
Definition: netcvode.cpp:6154
HocCommand * stmt()
Definition: netcon.h:328
void condition(Cvode *)
Definition: netcvode.cpp:5207
static unsigned long abandon_below_
Definition: netcon.h:189
static double stats(void *v)
Definition: tqueue.cpp:75
void deliver_events_when_threads(double)
Definition: netcvode.cpp:6699
int _nrn_netcon_args(void *v, double ***argslist)
Definition: netcvode.cpp:4101
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:3302
int nsub
Definition: hocdec.h:70
bool active_
Definition: netcon.h:110
#define min(a, b)
Definition: matrix.h:157
static void pnode(Prop *)
Definition: psection.cpp:47
double rtol()
Definition: netcvode.h:135
void update_ps2nt()
Definition: netcvode.cpp:4876
int nrn_dblpntr2nrncore(double *pd, NrnThread &nt, int &type, int &index)
void hoc_l_delete(hoc_Item *)
double * n_vector_data(N_Vector, int)
Definition: occvode.cpp:434
int global_microstep_when_threads()
Definition: netcvode.cpp:6709
CvodeThreadData * ctd_
Definition: cvodeobj.h:199
int playrec_item(PlayRecord *)
Definition: netcvode.cpp:5994
#define ITERATE(itm, lst)
Definition: model.h:25
Definition: ivoc.h:36
size_t size() const
Definition: ivocvect.h:43
int hoc_is_double_arg(int narg)
Definition: code.cpp:733
double amax_
Definition: netcvode.cpp:426
NrnThread * nt_
Definition: netcon.h:270
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1880
virtual void allthread_handle()
Definition: hocevent.cpp:102
void disconnect(Observable *)
Definition: netcvode.cpp:5134
void play_add(Cvode *)
Definition: netcvode.cpp:6062
virtual void send(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:5346
int index
Definition: cvodeobj.h:28
TQItem * tqitem_
Definition: cvodeobj.h:224
virtual void savestate_restore(double deliverytime, NetCvode *)
Definition: netcvode.cpp:330
static unsigned long abandon_init_above_
Definition: netcon.h:186
Symbol * hoc_lookup(const char *)
#define MUTLOCK
Definition: nrnmutdec.h:32
virtual void deliver(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3464
void deliver_least_event(NrnThread *)
Definition: netcvode.cpp:2154
Symlist * symtable
Definition: hocdec.h:196
void nrn_netcon_event(NetCon *nc, double td)
Definition: netcvode.cpp:162
void playrec_remove(PlayRecord *)
Definition: netcvode.cpp:5968
void
int local_microstep(NrnThread *)
Definition: netcvode.cpp:2183
PlayRecList * prl
Definition: savstate.cpp:439
void activate()
Definition: netcvode.cpp:5390
void playrec_add(PlayRecord *)
DiscreteEvent * pgvts_least(double &tt, int &op, int &init)
Definition: netcvode.cpp:3658
virtual void send(double sendtime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3165
#define GVectorRecordType
Definition: vrecitem.h:26
static bool equal(float x, float y, float e)
Definition: math.h:108
void * this_pointer
Definition: hocdec.h:231
Node ** _v_parent
Definition: multicore.h:78
Pvmi current
Definition: membfunc.h:33
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:84
virtual NrnThread * thread()
Definition: netcvode.cpp:5437
virtual ~PreSyn()
Definition: netcvode.cpp:4957
size_t p
Represent main neuron object computed by single thread.
Definition: multicore.h:58
void shift_bin(double t)
Definition: sptbinq.h:81
Symlist * hoc_built_in_symlist
Definition: symbol.cpp:39
int nctd_
Definition: cvodeobj.h:201
IvocVect * y_
Definition: vrecitem.h:147
int nrn_matrix_cnt_
Definition: treeset.cpp:68
int hoc_araypt(Symbol *, int)
static int first
Definition: fmenu.cpp:186
STECondition(Point_process *, double(*)(Point_process *)=NULL)
Definition: netcvode.cpp:5301
static Member_func members[]
Definition: netcvode.cpp:792
STETransition * stet_
Definition: netcon.h:229
int output_index_
Definition: netcon.h:276
void setup_topology()
void artcell_net_move(void **, Point_process *, double)
Definition: netcvode.cpp:2285
void retreat(double, Cvode *)
Definition: netcvode.cpp:3543
static DiscreteEvent * savestate_read(FILE *)
Definition: netcvode.cpp:4658
std::vector< std::pair< double *, IvocVect *> > GLineRecordEData
Definition: glinerec.h:11
Object * obj_
Definition: netcon.h:108
int cvode_active_
Definition: fadvance.cpp:158
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:3455
void record_init_clear(const TQItem *q, int)
Definition: netcvode.cpp:4119
int rootnodecount_
Definition: cvodeobj.h:58
NrnThreadBAList * tbl[BEFORE_AFTER_SIZE]
Definition: multicore.h:89
void nrn2core_transfer_WATCH(void(*cb)(int, int, int, int, int))
Definition: netcvode.cpp:5889
static DiscreteEvent * savestate_read(FILE *)
Definition: netcvode.cpp:3326
void nrn_notify_when_void_freed(void *p, Observer *ob)
Definition: ivoc.cpp:54
void psl_append(PreSyn *)
Definition: netcvode.cpp:4592
int neq_
Definition: cvodeobj.h:204
StateTransitionEvent * ste_
Definition: nrnste.h:25
virtual NrnThread * thread()
Definition: netcvode.cpp:3437
check_obj_type(o, "SectionList")
virtual void asf_err()
Definition: netcvode.cpp:5337
PlayRecList * fixed_play_
Definition: netcvode.h:120
char * name
Definition: model.h:72
virtual int type()
Definition: vrecitem.h:60
#define MUTUNLOCK
Definition: nrnmutdec.h:33
#define PRINT_EVENT
Definition: netcvode.h:4
Memb_func * memb_func
Definition: init.cpp:161
virtual void send(double sendtime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3088
nd
Definition: treeset.cpp:893
Object * osrc_
Definition: netcon.h:265
Point_process * target_
Definition: netcon.h:106
static double dummy
Definition: ocptrvector.cpp:27
void ps_thread_link(PreSyn *)
Definition: netcvode.cpp:4854
static DiscreteEvent * null_event_
Definition: netcvode.cpp:453
double hoc_epsilon
Definition: hoc_init.cpp:260
static IvocVect * event_info_tvec_
Definition: netcvode.cpp:3009
void playrec_setup()
Definition: netcvode.cpp:6283
#define Fprintf
Definition: model.h:249
#define v
Definition: md1redef.h:4
virtual void disconnect(Observable *)
Definition: netcvode.cpp:405
double ** data
Definition: nrnoc_ml.h:14
Section * ssrc_
Definition: netcon.h:266
NetCvode * ncv_
Definition: cvodeobj.h:203
implementPool(TQItemPool, TQItem) SelfQueue
Definition: tqueue.cpp:110
static unsigned long singleevent_move_
Definition: kssingle.h:69
void vec_event_store()
Definition: netcvode.cpp:2566
Item * next(Item *item)
Definition: list.cpp:95
#define PreSynType
Definition: netcon.h:47
Point_process * nrn_netcon_target(NetCon *nc)
Definition: netcvode.cpp:167
double t_
Definition: bbtqueue.h:18
int pgvts(double tstop)
Definition: netcvode.cpp:3616
static unsigned long netcon_deliver_
Definition: netcon.h:114
void solver_prepare()
Definition: netcvode.cpp:3935
static unsigned long net_event_cnt_
Definition: netcvode.cpp:265
Object ** netconlist()
Definition: netcvode.cpp:947
#define SYMBOL
Definition: model.h:102
static IvocVect * event_info_flagvec_
Definition: netcvode.cpp:3010
static void * lvardt_integrate(NrnThread *nt)
Definition: netcvode.cpp:6586
virtual void ref() const
Definition: resource.cpp:47
void hoc_l_freelist(hoc_List **)
void notify()
int condition_order()
Definition: netcvode.h:129
static DiscreteEvent * savestate_read(FILE *)
Definition: netcvode.cpp:4771
Object * obj_
Definition: ivocvect.h:86
void presyn_disconnect(PreSyn *)
Definition: netcvode.cpp:4599
#define fifo_event
Definition: netcvode.cpp:2596
VecRecordDiscrete(double *, IvocVect *y, IvocVect *t, Object *ppobj=nil)
Definition: netcvode.cpp:6130
std::vector< NetCon * > NetConPList
Definition: netcon.h:164
static philox4x32_key_t k
Definition: nrnran123.cpp:11
void * hoc_mech
Definition: membfunc.h:54
void init_prepare()
Definition: cvodeobj.cpp:879
NetCvode * net_cvode_instance
Definition: cvodestb.cpp:27
virtual DiscreteEvent * savestate_save()
Definition: netcvode.cpp:4749
void scatter_y(double *, int)
Definition: occvode.cpp:445
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
BAMechList * after_solve_
Definition: cvodeobj.h:56
PlayRecordEvent * e_
Definition: vrecitem.h:149
#define PlayRecordEventType
Definition: netcon.h:49
virtual void savestate_restore(double deliverytime, NetCvode *)
Definition: netcvode.cpp:4759
static Object ** nc_preseg(void *v)
Definition: netcvode.cpp:485
Definition: bbtqueue.h:6
STECondition * stec_
Definition: nrnste.h:26
Prop ** prop
Definition: nrnoc_ml.h:16
void fun_thread(double t, double *y, double *ydot, NrnThread *nt)
Definition: occvode.cpp:635
#define AFTER_SOLVE
Definition: membfunc.h:76
inode
Definition: multicore.cpp:985
bool localstep()
Definition: netcvode.cpp:1276
double delay_
Definition: netcon.h:104
static void pr(N_Vector x)
short * nrn_artcell_qindex_
Definition: init.cpp:232
int type
Definition: membfunc.h:81
virtual NrnThread * thread()
Definition: netcvode.cpp:3473
double atol()
Definition: netcvode.h:136
double * pd_
Definition: vrecitem.h:78
Point_process * pnt_
Definition: netcon.h:208
void nrn_hoc_lock()
Definition: multicore.cpp:1064
static double condition_order(void *v)
Definition: cvodeobj.cpp:380
hoc_List * olist
Definition: hocdec.h:203
#define e
Definition: passive0.cpp:24
Datum * _thread
Definition: nrnoc_ml.h:17
#define gargstr
Definition: hocdec.h:14
int is_vector_arg(int i)
Definition: ivocvect.cpp:340
static unsigned long selfevent_send_
Definition: netcon.h:154
static Object ** nc_prelist(void *v)
Definition: netcvode.cpp:571
int refcount
Definition: hocdec.h:71
double nrn_event_queue_stats(double *stats)
Definition: netcvode.cpp:141
int watch_index_
Definition: netcon.h:214
PreSyn * src_
Definition: netcon.h:105
void maxstate(double *)
Definition: cvodeobj.cpp:969
static DiscreteEvent * savestate_read(FILE *)
Definition: netcvode.cpp:5007
static NetConSaveWeightTable * wtable_
Definition: netcon.h:128
static void Attach(Object *, Observer *)
Definition: ocobserv.cpp:20
#define implementTable(Table, Key, Value)
Definition: table.h:113
Node * node
Definition: section.h:263
double * hoc_pgetarg(int narg)
Definition: code.cpp:1604
static unsigned long selfevent_move_
Definition: netcon.h:155
void evaluate_conditions(NrnThread *nt=0)
Definition: netcvode.cpp:5492
short type
Definition: section.h:215
void(* nrnthread_v_transfer_)(NrnThread *)
Definition: fadvance.cpp:148
double nrn_hoc2fixed_step(void *)
Definition: netcvode.cpp:4230
void restore()
Definition: ocjump.cpp:303
Point_process * ob2pntproc(Object *)
Definition: hocmech.cpp:88
void local_retreat(double, Cvode *)
Definition: netcvode.cpp:3522
bool initialized_
Definition: netcvode.h:148
static double re_init(void *v)
Definition: cvodeobj.cpp:158
double t
Definition: init.cpp:123
void init_events()
Definition: netcvode.cpp:2868
const char * string() const
Definition: string.h:139
void ncs2nrn_integrate(double tstop)
Definition: netcvode.cpp:3748
void(* nrn_allthread_handle)()
Definition: fadvance.cpp:69
void init()
Definition: init.cpp:169
Node ** v_node_
Definition: cvodeobj.h:60
virtual void deliver(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3102
bool deliver_event(double til, NrnThread *)
Definition: netcvode.cpp:2166
void bgp_dma_send(PreSyn *ps, double t)
Definition: bgpdma.cpp:624
void dstates()
Definition: netcvode.cpp:4196
int use_sparse13
Definition: treeset.cpp:69
virtual int init(double t)
Definition: cvodeobj.cpp:1174
static DiscreteEvent * savestate_read(FILE *)
Definition: netcvode.cpp:3512
int id
Definition: multicore.h:66
double least_t()
Definition: bbtqueue.cpp:136
double _dt
Definition: multicore.h:60
static Object ** newoclist(int i, OcList *&o)
Definition: netcvode.cpp:556
void(* steer)(void *)
Definition: hocdec.h:208
int ncell
Definition: multicore.h:64
virtual ~PlayRecord()
Definition: netcvode.cpp:6034
virtual PlayRecordSave * savestate_save()
Definition: netcvode.cpp:6147
static double nc_valid(void *v)
Definition: netcvode.cpp:700
ReceiveFunc * pnt_receive_init
Definition: init.cpp:172
void alloc_list()
Definition: netcvode.cpp:1543
YvecRecord(double *, IvocVect *y, Object *ppobj=nil)
Definition: netcvode.cpp:6102
double nrn_netcon_get_delay(NetCon *nc)
Definition: netcvode.cpp:135
int nrn_use_daspk_
Definition: treeset.cpp:70
double ** pv_
Definition: cvodeobj.h:64
double immediate_deliver_
Definition: netcvode.h:59
bool use_daspk_
Definition: cvodeobj.h:168
virtual ~CvodeThreadData()
Definition: netcvode.cpp:1364
int use_min_delay_
Definition: netcon.h:274
void chktar()
Definition: netcvode.cpp:399
#define ITE_SIZE
Definition: netcvode.cpp:1094
double time() const
Definition: cvodeobj.h:92
Symbol * sym
Definition: membfunc.h:38
int refcount
Definition: hocdec.h:227
HTList * First()
Definition: htlist.h:64
#define CTD(i)
Definition: cvodeobj.h:40
static unsigned long playrecord_send_
Definition: vrecitem.h:39
TQueue * event_queue(NrnThread *nt)
Definition: netcvode.cpp:3792
virtual DiscreteEvent * savestate_save()
Definition: netcvode.cpp:325
virtual void savestate_restore(double deliverytime, NetCvode *)
Definition: netcvode.cpp:3321
void play_init()
Definition: netcvode.cpp:4142
NetCon * install_deliver(double *psrc, Section *ssrc, Object *osrc, Object *target, double threshold, double delay, double weight)
Definition: netcvode.cpp:4532
Object ** hoc_temp_objvar(Symbol *symtemp, void *v)
Definition: hoc_oop.cpp:503
N_Vector maxstate_
Definition: cvodeobj.h:191
static double nc_wcnt(void *v)
Definition: netcvode.cpp:787
void localstep(bool)
Definition: netcvode.cpp:1282
void record(IvocVect *, IvocVect *idvec=nil, int rec_id=0)
Definition: netcvode.cpp:5091
virtual ~WatchCondition()
Definition: netcvode.cpp:5295
Definition: oclist.h:11
void remove_event(TQItem *, int threadid)
Definition: netcvode.cpp:2334
void gather_y(N_Vector)
Definition: occvode.cpp:471
#define BEFORE_STEP
Definition: membfunc.h:77
double max_
Definition: netcvode.cpp:425
sl
Definition: seclist.cpp:186
int nrn_nthread
Definition: multicore.cpp:44
VecRecordDiscreteSave(PlayRecord *)
Definition: netcvode.cpp:6151
Node ** _v_node
Definition: multicore.h:77
void record_init()
Definition: netcvode.cpp:4124
void * presyn_
Definition: section.h:267
NetConSave(NetCon *)
Definition: netcvode.cpp:4754
void record_add(PlayRecord *)
Definition: occvode.cpp:983
static double cell(void *v)
Definition: ocbbs.cpp:573
TQItem * least()
Definition: bbtqueue.cpp:145
void _nrn_free_fornetcon(void **)
Definition: netcvode.cpp:4108
int sub[1]
Definition: hocdec.h:72
void nrnmusic_injectlist(void *vp, double tt)
Definition: nrnmusic.cpp:91
void nrn_parent_info(Section *)
Definition: cabcode.cpp:1689
int const size_t const size_t n
Definition: nrngsl.h:12
virtual void frecord_init(TQItem *)
Definition: netcvode.cpp:6240
virtual NrnThread * thread()
Definition: netcvode.cpp:3141
virtual void frecord_init(TQItem *)
Definition: netcon.h:76
double * var1_
Definition: nrnste.h:22
void record_stmt(const char *)
Definition: netcvode.cpp:5071
static double check(double t, Daspk *ida)
Definition: nrndaspk.cpp:214
void _nrn_free_watch(Datum *, int, int)
Called by Point_process destructor in translated mod file.
Definition: netcvode.cpp:2550
int cellindex()
Definition: netcvode.cpp:4149
Memb_list * ml
Definition: multicore.h:35
double threshold_
Definition: netcon.h:262
virtual void install(Cvode *)
Definition: netcvode.cpp:6090
Symbol * hoc_spop(void)
int nodecount
Definition: nrnoc_ml.h:18
virtual NrnThread * thread()
Definition: netcvode.cpp:3272
int nrnmpi_numprocs
virtual void record_init()
Definition: netcvode.cpp:6180
virtual void install(Cvode *cv)
Definition: vrecitem.h:53
_CONST char * s
Definition: system.cpp:74
double nrn_hoc2fun(void *v)
Definition: netcvode.cpp:4235
virtual NrnThread * thread()
Definition: netcvode.cpp:3078
NrnThread * nrn_threads
Definition: multicore.cpp:45
virtual void asf_err()
Definition: netcvode.cpp:5342
static Point_process * index2pp(int type, int oindex)
Definition: netcvode.cpp:3363
#define VecRecordDiscreteType
Definition: vrecitem.h:19
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:5019
BAMechList * next
Definition: cvodeobj.h:34
SelfQueue * selfqueue_
Definition: netcvode.h:53
void Remove()
Definition: htlist.cpp:71
Pvmi state
Definition: membfunc.h:35
Node ** v_parent_
Definition: cvodeobj.h:61
virtual void savestate_restore()
Definition: netcvode.cpp:6156
virtual void disconnect(Observable *)
Definition: netcvode.cpp:6171
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
static unsigned long singleevent_deliver_
Definition: kssingle.h:68
static unsigned long deliver_qthresh_
Definition: netcon.h:190
double allthread_least_t(int &tid)
Definition: netcvode.cpp:6741
static unsigned long deliver_cnt_
Definition: netcvode.cpp:265
HTList * watch_list_
Definition: cvodeobj.h:63
Memb_list * memb_list
Definition: init.cpp:162
void hoc_event(double, const char *hoc_stmt, Object *ppobj=nil, int reinit=0, Object *pyact=nil)
Definition: netcvode.cpp:2671
void update(Observable *)
Definition: netcvode.cpp:5147
int val
Definition: dll.cpp:167
hoc_Item * psl_
Definition: netcvode.h:208
double t_
Definition: cvodeobj.h:97
static Object ** nc_get_recordvec(void *v)
Definition: netcvode.cpp:778
virtual void disconnect(Observable *)
Definition: netcvode.cpp:6085
virtual void deliver(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:5351
Arrayinfo * arayinfo
Definition: hocdec.h:158
int diam_changed
Definition: cabcode.cpp:23
Prop * prop
Definition: section.h:264
#define printf
Definition: mwprefix.h:26
void states()
Definition: netcvode.cpp:4167
SelfEventPool * sepool_
Definition: netcvode.h:50
VecRecordDt(double *, IvocVect *y, double dt, Object *ppobj=nil)
Definition: netcvode.cpp:6199
static unsigned long discretevent_deliver_
Definition: netcon.h:79
virtual void frecord_init(TQItem *q)
Definition: netcvode.cpp:3460
virtual ~SelfEvent()
Definition: netcvode.cpp:3309
double nrflag_
Definition: netcon.h:207
#define VOIDITM(q)
Definition: hoclist.h:68
void remove_all()
Definition: oclist.cpp:241
int
Definition: nrnmusic.cpp:71
void spike_stat(double *)
Definition: spt2queue.cpp:170
const char * secname(Section *sec)
Definition: cabcode.cpp:1787
void maxacor(double *)
Definition: cvodeobj.cpp:984
void hoc_warning(const char *, const char *)
static double eps_
Definition: netcvode.h:162
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:3439
virtual void record_init()
Definition: netcvode.cpp:6122
static PreSyn * hindx2presyn(long)
Definition: netcvode.cpp:5035
void single_event_run()
virtual int type()
Definition: netcon.h:69
static unsigned long presyn_deliver_direct_
Definition: netcon.h:296
int v_structure_change
Definition: cvodestb.cpp:99
static double interpolate(double x0, double x1, double y0, double y1, double xnew)
Definition: nrnpy_nrn.cpp:1406
struct NrnThread * _nt
Definition: section.h:157
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:97
#define TvecRecordType
Definition: vrecitem.h:23
void structure_change()
Definition: netcvode.cpp:4521
void fill_local_ba(int *, NetCvodeThreadData &)
Definition: netcvode.cpp:1856
void allthread_handle(double, HocEvent *, NrnThread *)
Definition: netcvode.cpp:2716
void net_event(Point_process *, double)
Definition: netcvode.cpp:2409
static unsigned long presyn_send_mindelay_
Definition: netcon.h:293
void nrn_netcon_set_delay(NetCon *nc, double d)
Definition: netcvode.cpp:136
#define ENDGUI
Definition: hocdec.h:352
static void del(int *a)
Definition: bgpdmasetup.cpp:97
virtual ~VecRecordDiscrete()
Definition: netcvode.cpp:6140
static Cvode * eval_cv
Definition: netcvode.cpp:5487
static unsigned long netcon_send_inactive_
Definition: netcon.h:113
void clear_events()
Definition: netcvode.cpp:2791
int n_memb_func
Definition: init.cpp:471
void vec_remove()
Definition: netcvode.cpp:6275
void check_thresh(NrnThread *)
Definition: netcvode.cpp:5857
#define DiscreteEventType
Definition: netcon.h:43
static unsigned long watch_deliver_
Definition: netcon.h:217
virtual void savestate_restore()
Definition: netcvode.cpp:6222
static unsigned long presyn_deliver_ncsend_
Definition: netcon.h:297
static unsigned long eq_abandon_
Definition: netcon.h:185
static double nc_setpost(void *v)
Definition: netcvode.cpp:663
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
TQueue * net_cvode_instance_event_queue(NrnThread *)
Definition: netcvode.cpp:297
void ** movable_
Definition: netcon.h:152
#define cnt
Definition: spt2queue.cpp:19
virtual ~TstopEvent()
Definition: netcvode.cpp:3483
double nrn_netcon_get_thresh(NetCon *nc)
Definition: netcvode.cpp:149
static bool eq2(double x, double y, double e)
Definition: mymath.h:81
void v_setup_vectors()
Definition: treeset.cpp:1623
VecRecordDtSave(PlayRecord *)
Definition: netcvode.cpp:6218
double t0_
Definition: cvodeobj.h:97
void nrn_netcon_set_thresh(NetCon *nc, double th)
Definition: netcvode.cpp:156
TQueue * tq_
Definition: netcvode.h:46
int jacobian()
Definition: netcvode.h:143
double * thvar_
Definition: netcon.h:264
errno
Definition: system.cpp:98
TQItem * insert(double t, void *data_)
Definition: bbtqueue.cpp:391
#define NetConType
Definition: netcon.h:45
int is_point_process(Object *)
Definition: point.cpp:405
static void reclaim()
Definition: hocevent.cpp:115
static void steer_val(void *v)
Definition: netcvode.cpp:824
virtual int pgvts_op(int &i)
Definition: netcon.h:65
virtual void record_init()
Definition: netcvode.cpp:6094
int global_microstep()
Definition: netcvode.cpp:2197
MUTDEC void set_enqueueing()
Definition: netcvode.cpp:6735
void acor()
Definition: netcvode.cpp:4297
int solve_when_threads(double)
Definition: netcvode.cpp:6614
virtual void savestate_restore(double deliverytime, NetCvode *)
Definition: netcvode.cpp:5002
void use_daspk(bool)
Definition: netcvode.cpp:1301
MUTDEC int nlcv_
Definition: netcvode.h:55
#define POINT_RECEIVE(type, tar, w, f)
Definition: netcvode.cpp:58
bool is_owner(double *)
Definition: netcvode.cpp:6334
Object * hoc_name2obj(const char *name, int index)
Definition: hoc_oop.cpp:955
size_t j
void nrn_pending_selfqueue(double tt, NrnThread *)
Definition: netcvode.cpp:3802
void MaxStateItem PreSyn WatchCondition double PreSyn SelfEvent TQItem static HocEvent TQList * record_init_items_
Definition: netcvode.cpp:451
int nrn_use_selfqueue_
Definition: netcvode.cpp:92
Datum ** pdata
Definition: nrnoc_ml.h:15
void rmsrc()
Definition: netcvode.cpp:4720
Section * sec
Definition: section.h:262
fprintf(stderr, "Don't know the location of params at %p\, pp)
BAMechList(BAMechList **first)
Definition: netcvode.cpp:1317
long hi_index_
Definition: netcon.h:273
virtual PlayRecordSave * savestate_save()
Definition: netcvode.cpp:6214
void cb(const char *s)
Definition: bbstest.cpp:5
bool can_retreat_
Definition: cvodeobj.h:99
void MaxStateItem PreSyn WatchCondition double PreSyn * declarePool(SelfEventPool, SelfEvent) implementPool(SelfEventPool
Definition: model.h:57
int solve()
Definition: cvodeobj.cpp:1154
virtual void deliver(double t, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3074
virtual void record_init()
Definition: netcvode.cpp:6235
void transition(int src, int dest, double *var1, double *var2, HocCommand *)
Definition: netcvode.cpp:5373
void enqueue(NetCvode *, NrnThread *)
Definition: netcvode.cpp:1167
BAMech ** bamech_
Definition: init.cpp:167
static unsigned long init_above_
Definition: netcon.h:182
virtual void send(double deliverytime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3069
static NetCon * weight2netcon(double *)
Definition: netcvode.cpp:4806
static void peq(const TQItem *, int)
Definition: netcvode.cpp:2988
int * nrn_fornetcon_type_
Definition: init.cpp:219
void maxstate_analyse()
Definition: netcvode.cpp:6518
double dt_
Definition: vrecitem.h:179
static double nc_postloc(void *v)
Definition: netcvode.cpp:517
Definition: section.h:213
Point_process * ob2pntproc_0(Object *)
Definition: hocmech.cpp:78
char * name
Definition: init.cpp:16
Symbol * expr_
Definition: graph.h:281
static Object ** nc_pre(void *v)
Definition: netcvode.cpp:547
PreSynList * psl_th_
Definition: cvodeobj.h:62
static void prs(int, int, int, const char *)
Definition: fmenu.cpp:623
inode< _nt-> end
Definition: multicore.cpp:985
int nrn_netcon_weight(NetCon *nc, double **pw)
Definition: netcvode.cpp:137
double * weight_
Definition: netcon.h:151
void nrn_cleanup_presyn(PreSyn *)
Definition: netpar.cpp:932
PlayRecordEvent * e_
Definition: vrecitem.h:180
static N_Vector y_
static void * chk_deliv(NrnThread *nt)
Definition: netcvode.cpp:5515
TQueue * tqe_
Definition: netcvode.h:48
static Object ** nc_syn(void *v)
Definition: netcvode.cpp:538
short * nrn_is_artificial_
Definition: init.cpp:231
void del_cv_memb_list()
Definition: netcvode.cpp:1417
void NetCon_reg()
Definition: netcvode.cpp:895
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:3494
#define nil
Definition: enter-scope.h:36
long count()
Definition: oclist.cpp:189
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:4662
int dest_
Definition: nrnste.h:27
void _nrn_watch_activate(Datum *, double(*)(Point_process *), int, Point_process *, int, double)
Definition: netcvode.cpp:2431
Definition: netcon.h:82
void nrnthread_trajectory_return(int tid, int n_pr, int bsize, int vecsz, void **vpr, double t)
Definition: netcvode.cpp:5826
BAMechList * before_breakpoint_
Definition: cvodeobj.h:55
static Object ** nc_synlist(void *v)
Definition: netcvode.cpp:586
double * weight_
Definition: netcon.h:107
bool use_partrans()
Definition: netcvode.cpp:3741
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1980
Object * ob
Definition: section.h:266
virtual ~STECondition()
Definition: netcvode.cpp:5307
static Object ** nc_postcell(void *v)
Definition: netcvode.cpp:654
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:6162
void fill_pd()
PlayRecList * net_cvode_instance_prl()
Definition: netcvode.cpp:305
bool use_daspk()
Definition: netcvode.cpp:1297
int gid_
Definition: netcon.h:277
Memb_list * ml
Definition: cvodeobj.h:36
#define CAP
Definition: membfunc.h:64
static DiscreteEvent * savestate_read(FILE *)
Definition: netcvode.cpp:338
static DiscreteEvent * tstop_event_
Definition: netcvode.cpp:454
int tree_changed
Definition: cabcode.cpp:19
bool init_global()
Definition: netcvode.cpp:1580
virtual void deliver(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3412
virtual ~NetCvodeThreadData()
Definition: netcvode.cpp:1113
static PlayRecordSave * savestate_read(FILE *)
Definition: netcvode.cpp:353
static unsigned long discretevent_send_
Definition: netcon.h:76
static void destruct(void *v)
Definition: netcvode.cpp:890
NetCvodeThreadData * p
Definition: netcvode.h:211
CvMembList * next
Definition: cvodeobj.h:26
void nrn_update_ps2nt()
Definition: netcvode.cpp:4850
double state_magnitudes()
Definition: netcvode.cpp:6423
void handle_tstop_event(double, NrnThread *nt)
Definition: netcvode.cpp:2135
#define nlayer
Definition: section.h:187
static uint32_t value
Definition: scoprand.cpp:26
double flag_
Definition: netcon.h:149
void MaxStateItem * declarePtrList(PreSynList, PreSyn) implementPtrList(PreSynList
static unsigned long playrecord_deliver_
Definition: vrecitem.h:40
int ifarg(int)
Definition: code.cpp:1562
HocStruct Symbol * next
Definition: hocdec.h:161
GLineRecordEData pd_and_vec_
Definition: glinerec.h:29
virtual void install(Cvode *)
Definition: netcvode.cpp:6231
double ** argslist
Definition: netcvode.cpp:261
IvocVect * t_
Definition: vrecitem.h:111
IvocVect * v_
Definition: glinerec.h:25
void send(const char *url)
Definition: hel2mos.cpp:212
double maxstep()
Definition: netcvode.h:142
int stiff()
Definition: netcvode.h:138
int end
Definition: multicore.h:65
#define TableIterator(Table)
Definition: table.h:38
declareTable(MaxStateTable, void *, MaxStateItem *) implementTable(MaxStateTable
static double pending_selfqueue_deliver_
Definition: netcvode.cpp:3796
int hoc_return_type_code
Definition: code.cpp:41
static void invalid()
Definition: netcvode.cpp:5028
Datum * dparam
Definition: section.h:219
void deliver_net_events(NrnThread *)
Definition: netcvode.cpp:5902
static unsigned long netcon_send_active_
Definition: netcon.h:112
void plot(int, double)
virtual void continuous(double t)
Definition: netcvode.cpp:6126
void nrn_onethread_job(int i, void *(*job)(NrnThread *))
Definition: multicore.cpp:1111
static NetCon * index2netcon(long)
Definition: netcvode.cpp:4828
static void destruct(BAMechList **first)
Definition: netcvode.cpp:1328
struct Symbol::@52::@53 rng
#define VecRecordDtType
Definition: vrecitem.h:20
PreSyn(double *src, Object *osrc, Section *ssrc=nil)
Definition: netcvode.cpp:4912
PreSynSave(PreSyn *)
Definition: netcvode.cpp:4997
static void savestate_free()
Definition: netcvode.cpp:3384
#define MUTCONSTRUCT(mkmut)
Definition: nrnmutdec.h:30
bool nrn_use_fifo_queue_
Definition: netcvode.cpp:248
#define OBJ(q)
Definition: hoclist.h:67
void * nrn_interthread_enqueue(NrnThread *)
Definition: netcvode.cpp:6730
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:3080
void nrn_hoc_unlock()
Definition: multicore.cpp:1072
void consist_sec_pd(const char *, Section *, double *)
Definition: netcvode.cpp:6392
static void invalid()
Definition: netcvode.cpp:4795
Definition: htlist.h:35
void artcell_net_send(void **, double *, Point_process *, double, double)
Definition: netcvode.cpp:2375
Cvode * gcv_
Definition: netcvode.h:205
threshold
Definition: extdef.h:3
bool nrn_trajectory_request_per_time_step_
Definition: netcvode.cpp:121
Node ** nodelist
Definition: nrnoc_ml.h:5
virtual void continuous(double t)
Definition: netcvode.cpp:6098
static unsigned long selfevent_deliver_
Definition: netcon.h:156
Vect * vector_arg(int i)
Definition: ivocvect.cpp:332
PlayRecList * fixed_record_
Definition: netcvode.h:121
double _t
Definition: multicore.h:59
BAMech * bam
Definition: multicore.h:41
bool nrn_use_bin_queue_
Definition: netcvode.cpp:251
hoc_Item * hi_
Definition: netcon.h:271
void nrn_notify_when_double_freed(double *p, Observer *ob)
Definition: ivoc.cpp:63
const char * statename(int, int style=1)
Definition: netcvode.cpp:4326
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:5482
Definition: regexp.h:61
static int active_
Definition: netpar.cpp:206
static void * pending_selfqueue(NrnThread *)
Definition: netcvode.cpp:3797
void nrn_fixed_step()
Definition: fadvance.cpp:338
static double statename(void *v)
Definition: cvodeobj.cpp:303
IvocVect * y_
Definition: vrecitem.h:178
TQItem * qthresh_
Definition: netcon.h:179
static double eps(double x)
Definition: netcvode.h:128
int unreffed_event_cnt_
Definition: netcvode.h:58
int * nrn_fornetcon_index_
Definition: init.cpp:220
int v_node_index
Definition: section.h:174
static OcList * event_info_list_
Definition: netcvode.cpp:3011
IvocVect * t_
Definition: vrecitem.h:148
void fanout(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3263
WatchCondition(Point_process *, double(*)(Point_process *))
Definition: netcvode.cpp:5287
Object * object(long)
Definition: oclist.cpp:232
static double lvardt_tout_
Definition: netcvode.cpp:6584
#define MUTCONSTRUCTED
Definition: nrnmutdec.h:29
virtual void deliver(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:5409
static Member_ret_obj_func omembers[]
Definition: netcvode.cpp:809
N_Vector maxacor_
Definition: cvodeobj.h:192
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:333
int pgvts_event(double &tt)
Definition: netcvode.cpp:3633
void delete_list()
Definition: netcvode.cpp:1382
int print_event_
Definition: netcvode.h:145
virtual void install(Cvode *)
Definition: netcvode.cpp:6118
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:3274
TEXTMETRIC tm
Definition: ddesrvr.cpp:43
double tstop_begin_
Definition: cvodeobj.h:208
Definition: hocdec.h:226
HocStruct cTemplate * ctemplate
Definition: hocdec.h:151
int stoprun
Definition: fadvance.cpp:161
void replace_src(PreSyn *)
Definition: netcvode.cpp:4740
static unsigned long watch_send_
Definition: netcon.h:216
virtual NrnThread * thread()
Definition: netcvode.cpp:5439
Symbol * sym_
Definition: netcvode.cpp:424
static unsigned long hocevent_send_
Definition: netcon.h:336
Definition: cvodeobj.h:75
double minstep()
Definition: netcvode.h:141
virtual void savestate_restore(double deliverytime, NetCvode *)
Definition: netcvode.cpp:4652
Symbol * name2sym(const char *)
Definition: netcvode.cpp:4422
NrnThread * nth_
Definition: cvodeobj.h:200
void fixed_play_continuous(NrnThread *)
Definition: netcvode.cpp:5554
const char * pattern() const
Definition: regexp.cpp:109
void Remove(HTList *)
Definition: htlist.cpp:65
#define getarg
Definition: hocdec.h:15
void abandon_statistics(Cvode *)
Definition: netcvode.cpp:5261
void nrnthread_trajectory_values(int tid, int n_pr, void **vpr, double t)
Definition: netcvode.cpp:5785
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:60
double * hoc_val_pointer(const char *s)
Definition: code2.cpp:699
NetConPList dil_
Definition: netcon.h:261
virtual ~TvecRecord()
Definition: netcvode.cpp:6080
int nrn_fornetcon_cnt_
Definition: init.cpp:218
void * nrn_presyn_netcon(PreSyn *ps, int i)
Definition: netcvode.cpp:184
virtual int interpolate(double t)
Definition: cvodeobj.cpp:1207
void deactivate()
Definition: netcvode.cpp:5401
void interthread_send(double, DiscreteEvent *, NrnThread *)
Definition: netcvode.cpp:1133
Object * ppobj_
Definition: vrecitem.h:79
virtual double value()
Definition: netcvode.cpp:5256
static void event_info_callback(const TQItem *, int)
Definition: netcvode.cpp:3014
Object *(* nrnpy_seg_from_sec_x)(Section *, double)
Definition: netcvode.cpp:117
#define i
Definition: md1redef.h:12
#define lvardtloop(i, j)
Definition: netcvode.cpp:49
static void allthread_handle_callback()
Definition: netcvode.cpp:199
void set_init_flag()
Definition: cvodeobj.cpp:790
#define VecPlayContinuousType
Definition: vrecitem.h:22
#define MUTDESTRUCT
Definition: nrnmutdec.h:31
int is_point
Definition: membfunc.h:53
#define id
Definition: md1redef.h:33
double tn_
Definition: cvodeobj.h:97
#define c
TQItemPool * tpool_
Definition: netcvode.h:51
PlayRecord(double *pd, Object *ppobj=nil)
Definition: netcvode.cpp:6019
virtual void check(NrnThread *, double sendtime, double teps=0.0)
Definition: netcvode.cpp:5184
void * nvi_
Definition: section.h:268
virtual DiscreteEvent * savestate_save()
Definition: netcvode.cpp:4992
void recalc_diam()
Definition: treeset.cpp:940
void move_event(TQItem *, double, NrnThread *)
Definition: netcvode.cpp:2312
hoc_Item * hoc_l_insertvoid(hoc_Item *, void *)
double * vector_vec(Vect *v)
Definition: ivocvect.cpp:271
static PreSyn * unused_presyn
Definition: netcvode.cpp:456
struct Prop * next
Definition: section.h:214
void Append(HTList *)
Definition: htlist.cpp:51
virtual PlayRecordSave * savestate_save()
Definition: netcvode.cpp:349
virtual void pr()
Definition: netcvode.cpp:6070
static Object ** nc_precelllist(void *v)
Definition: netcvode.cpp:625
Definition: string.h:34
#define SelfEventType
Definition: netcon.h:46
void point_receive(int, Point_process *, double *, double)
int structure_change_cnt
Definition: netcvode.cpp:66
double * var2_
Definition: nrnste.h:23
sec
Definition: solve.cpp:885
#define NVI_SUCCESS
Definition: netcvode.cpp:51
int hoc_stacktype()
Definition: code.cpp:720
static void Detach(Object *, Observer *)
Definition: ocobserv.cpp:27
virtual int type()
Definition: netcon.h:94
PlayRecord * plr_
Definition: vrecitem.h:38
virtual int handle_step(NetCvode *, double)
Definition: netcvode.cpp:2217
void nrn_notify_pointer_disconnect(Observer *ob)
Definition: ivoc.cpp:72
#define nt_t
Definition: netcvode.cpp:79
char buf[512]
Definition: init.cpp:13
void fill_local_ba_cnt(int, int *, NetCvodeThreadData &)
Definition: netcvode.cpp:1862
static std::unique_ptr< SelfEventPPTable > sepp_
Definition: netcon.h:161
void stat_init()
Definition: cvodeobj.cpp:873
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:3475
int nrn_netcon_info(NetCon *nc, double **pw, Point_process **target, double **th, double **del)
Definition: netcvode.cpp:172
struct Node ** pnode
Definition: section.h:51
virtual void deliver(double, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3231
PlayRecList * playrec_list()
Definition: netcvode.h:117
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:5448
void delete_memb_list(CvMembList *)
Definition: netcvode.cpp:1467
double * pdata(int)
PlayRecord * playrec_uses(void *)
Definition: netcvode.cpp:6009
void hoc_pushpx(double *d)
Definition: code.cpp:702
void maxstate_analyze_1(int, Cvode &, MaxStateItem *, CvodeThreadData &)
Definition: netcvode.cpp:6496
int nrn_errno_check(int)
Definition: fadvance.cpp:784
void net_send(void **, double *, Point_process *, double, double)
Definition: netcvode.cpp:2340
virtual void continuous(double t)
Definition: vrecitem.h:56
int hoc_is_object_arg(int narg)
Definition: code.cpp:745
void push_back(double v)
Definition: ivocvect.h:73
hoc_Item * hi_th_
Definition: netcon.h:272
void print_event_queue()
Definition: netcvode.cpp:2997
static unsigned long presyn_deliver_netcon_
Definition: netcon.h:295
NrnThreadMembList * tml
Definition: multicore.h:62
void event_queue_info()
Definition: netcvode.cpp:3051
double dt
Definition: init.cpp:123
void nrn_use_busywait(int)
Definition: multicore.cpp:1224
static Object ** nc_precell(void *v)
Definition: netcvode.cpp:645
void nrn_use_daspk(int)
Definition: netcvode.cpp:309
double nrn_hoc2scatter_y(void *v)
Definition: netcvode.cpp:4248
void recalc_ptrs()
Definition: netcvode.cpp:6558
int order(int)
Definition: netcvode.cpp:4482
void null_event(double)
Definition: netcvode.cpp:2635
static double nc_event(void *v)
Definition: netcvode.cpp:722
short * pnt_receive_size
Definition: init.cpp:173
virtual void install(Cvode *)
Definition: netcvode.cpp:6176
static unsigned long abandon_
Definition: netcon.h:184
static HocEvent * alloc(const char *stmt, Object *, int, Object *pyact=nil)
Definition: hocevent.cpp:29
int Match(const char *text, int length, int index)
Definition: regexp.cpp:206
void * data_
Definition: bbtqueue.h:17
static PreSynSaveIndexTable * idxtable_
Definition: netcon.h:311
BAMech * bam
Definition: cvodeobj.h:35
union Symbol::@18 u
static Object ** nc_postcelllist(void *v)
Definition: netcvode.cpp:603
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:3155
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:3516
void append(Object *)
Definition: oclist.cpp:96
union Object::@54 u
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:209
#define PP2NT(pp)
Definition: netcvode.cpp:52
static Symbol * pv[4]
Definition: partial.cpp:80
#define IFGUI
Definition: hocdec.h:351
void tstop_event(double)
Definition: netcvode.cpp:2651
static void all_pending_selfqueue(double tt)
Definition: netcvode.cpp:3827
void remove(TQItem *)
Definition: bbtqueue.cpp:239
NetCvode(bool single=true)
Definition: netcvode.cpp:1185
static Node * node(Object *)
Definition: netcvode.cpp:318
virtual ~PreSynSave()
Definition: netcvode.cpp:5000
double mindelay()
Definition: netcvode.cpp:2967
double valthresh_
Definition: netcon.h:178
Definition: section.h:132
int run(int argc, const char **argv)
#define YvecRecordType
Definition: vrecitem.h:24
void check_deliver(NrnThread *nt=0)
Definition: netcvode.cpp:5519
#define VecPlayStepType
Definition: vrecitem.h:21
virtual ~VecRecordDtSave()
Definition: netcvode.cpp:6220
int buffer_size()
Definition: ivocvect.cpp:1289
struct BAMech * next
Definition: membfunc.h:82
static double nc_record(void *v)
Definition: netcvode.cpp:746
int count
Definition: hocdec.h:202
size_t q
Definition: hocdec.h:176
#define PP2t(pp)
Definition: netcvode.cpp:53
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:5465
static IvocVect * peqvec
Definition: netcvode.cpp:2986
CvMembList * cv_memb_list_
Definition: cvodeobj.h:51
void call_net_receive(NetCvode *)
Definition: netcvode.cpp:3442
virtual DiscreteEvent * savestate_save()
Definition: netcvode.cpp:3311
GraphLine * gl_
Definition: glinerec.h:24
int nrn_sec2cell_equals(Section *, Object *)
Definition: cabcode.cpp:239
virtual ~DiscreteEvent()
Definition: netcvode.cpp:4641
Object ** hoc_objgetarg(int)
Definition: code.cpp:1568
Section * chk_access(void)
Definition: cabcode.cpp:437
static double nc_preloc(void *v)
Definition: netcvode.cpp:458
void move(TQItem *, double tnew)
Definition: bbtqueue.cpp:188
int index
Definition: hocdec.h:228
#define IvocVect
Definition: oc_ansi.h:27
unsigned * a_varn
Definition: hocdec.h:69
#define BEFORE_BREAKPOINT
Definition: membfunc.h:75
hoc_Item * net_cvode_instance_psl()
Definition: netcvode.cpp:301
void nrn2core_transfer_WatchCondition(WatchCondition *wc, void(*cb)(int, int, int, int, int))
In nrncore_callbacks.cpp.
virtual PlayRecordEvent * event()
Definition: vrecitem.h:58
void nrn_fixed_step_group(int)
Definition: fadvance.cpp:392
virtual ~YvecRecord()
Definition: netcvode.cpp:6108
IvocVect * y_
Definition: vrecitem.h:127
const char * sym2name(Symbol *)
Definition: netcvode.cpp:4411
TvecRecord(Section *, IvocVect *tvec, Object *ppobj=nil)
Definition: netcvode.cpp:6074
static unsigned long abandon_above_
Definition: netcon.h:188
Memb_list * ml
Definition: cvodeobj.h:27
return NULL
Definition: cabcode.cpp:461
int nrn_presyn_count(PreSyn *ps)
Definition: netcvode.cpp:181
void event()
Definition: nrnste.cpp:162
virtual void pgvts_deliver(double t, NetCvode *)
Definition: netcvode.cpp:3143
double chkarg(int, double low, double high)
Definition: code2.cpp:608
static Object ** nc_postseg(void *v)
Definition: netcvode.cpp:527
void fixed_record_continuous(NrnThread *)
Definition: netcvode.cpp:5542
void nrn_wait_for_threads()
Definition: multicore.cpp:1132
double * nrn_recalc_ptr(double *)
Definition: treeset.cpp:2158
void nrn_watch_clear()
Watch info corenrn->nrn transfer requires all activated WatchCondition be deactivated prior to mirror...
Definition: netcvode.cpp:2537
void net_move(void **, Point_process *, double)
Definition: netcvode.cpp:2268
void nrnthread_get_trajectory_requests(int tid, int &bsize, int &n_pr, void **&vpr, int &n_trajec, int *&types, int *&indices, double **&pvars, double **&varrays)
Definition: netcvode.cpp:5621
virtual void disconnect(Observable *)
Definition: netcvode.cpp:6226
static void * deliver_for_thread(NrnThread *nt)
Definition: netcvode.cpp:6685
virtual DiscreteEvent * savestate_save()
Definition: netcvode.cpp:3498
HocCommand * hc_
Definition: nrnste.h:24
virtual void frecord_init(TQItem *)
Definition: netcvode.cpp:6187
short index
Definition: cabvars.h:11
struct Extnode * extnode
Definition: section.h:160
void nrn_cvfun(double t, double *y, double *ydot)
Definition: netcvode.cpp:4225
static int event_info_type_
Definition: netcvode.cpp:3008
int linmod_extra_eqn_count()
void play_add(PlayRecord *)
Definition: occvode.cpp:1022
void chksrc()
Definition: netcvode.cpp:394
virtual void savestate_read(FILE *)
Definition: netcvode.cpp:6165
BAMechList * before_step_
Definition: cvodeobj.h:57
int ith_
Definition: vrecitem.h:81
virtual ~NetCvode()
Definition: netcvode.cpp:1235
void vecrecord_add()
Definition: netcvode.cpp:6253
void RemoveAll()
Definition: htlist.cpp:76
Point_process * target_
Definition: netcon.h:150
int solve(double t)
Definition: netcvode.cpp:2040
void delete_prl()
Definition: occvode.cpp:968
virtual ~PlayRecordEvent()
Definition: netcvode.cpp:323
virtual void deliver(double t, NetCvode *)
Definition: netcvode.cpp:6244
double delay_
Definition: netcon.h:263
cTemplate ** nrn_pnt_template_
Definition: init.cpp:169
int pgvts_cvode(double tt, int op)
Definition: netcvode.cpp:3713
int nshift_
Definition: sptbinq.h:94
DiscreteEvent * de_
Definition: netcvode.cpp:430
static void * cons(Object *o)
Definition: netcvode.cpp:853
struct Prop * prop
Definition: section.h:151
virtual void savestate_write(FILE *)
Definition: netcvode.cpp:4782
void _nrn_watch_allocate(Datum *d, double(*c)(Point_process *), int i, Point_process *pnt, double flag)
Introduced so corenrn->nrn can request the mod file to make sure all WatchCondition are allocated...
Definition: netcvode.cpp:2515
void fill_global_ba(NrnThread *, int, BAMechList **)
Definition: netcvode.cpp:1847
virtual void pr(const char *, double t, NetCvode *)
Definition: netcvode.cpp:3084
HocStruct Symbol * first
Definition: hocdec.h:85
struct NrnThreadBAList * next
Definition: multicore.h:42
void spike_stat()
Definition: netcvode.cpp:3910
static char * escape_bracket(const char *s)
Definition: netcvode.cpp:918
virtual void deliver(double t, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3485
int v_node_count_
Definition: cvodeobj.h:59
#define Regexp
Definition: _defines.h:222
void resize(size_t n)
Definition: ivocvect.h:47
#define TstopEventType
Definition: netcon.h:44
virtual DiscreteEvent * savestate_save()
Definition: netcvode.cpp:4643