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