NEURON
nrncore_callbacks.cpp
Go to the documentation of this file.
1 #include <vector>
2 #include <unordered_map>
3 #include "nrncore_callbacks.h"
4 #include "nrnconf.h"
5 #include "nrnmpi.h"
6 #include "section.h"
7 #include "netcon.h"
8 #include "nrncvode.h"
9 #include "nrniv_mf.h"
10 #include "hocdec.h"
14 #include "parse.hpp"
15 #include "nrnran123.h" // globalindex written to globals.
16 #include "netcvode.h" // for nrnbbcore_vecplay_write and PreSyn.flag_
18 #include "vrecitem.h" // for nrnbbcore_vecplay_write
19 
20 #include "nrnwrap_dlfcn.h"
21 
24 extern short* nrn_is_artificial_;
25 extern bool corenrn_direct;
26 extern int* bbcore_dparam_size;
27 extern double nrn_ion_charge(Symbol*);
28 extern CellGroup* cellgroups_;
30 extern char* pnt_map;
31 extern void* nrn_interthread_enqueue(NrnThread*);
32 
33 /** Populate function pointers by mapping function pointers for callback */
34 void map_coreneuron_callbacks(void* handle) {
35  for (int i = 0; cnbs[i].name; ++i) {
36  void* sym = NULL;
37 #if defined(HAVE_DLFCN_H)
38  sym = dlsym(handle, cnbs[i].name);
39 #endif
40  if (!sym) {
41  fprintf(stderr, "Could not get symbol %s from CoreNEURON\n", cnbs[i].name);
42  hoc_execerror("dlsym returned NULL", NULL);
43  }
44  void** c = (void**) sym;
45  *c = (void*) (cnbs[i].f);
46  }
47 }
48 
49 void write_memb_mech_types_direct(std::ostream& s) {
50  // list of Memb_func names, types, point type info, is_ion
51  // and data, pdata instance sizes. If the mechanism is an eion type,
52  // the following line is the charge.
53  // Not all Memb_func are necessarily used in the model.
54  s << bbcore_write_version << std::endl;
55  s << n_memb_func << std::endl;
56  for (int type = 2; type < n_memb_func; ++type) {
57  const char* w = " ";
58  Memb_func& mf = memb_func[type];
59  s << mf.sym->name << w << type << w << int(pnt_map[type])
60  << w // the pointtype, 0 means not a POINT_PROCESS
62  << w << bbcore_dparam_size[type] << std::endl;
63 
64  if (nrn_is_ion(type)) {
65  s << nrn_ion_charge(mf.sym) << std::endl;
66  }
67  }
68 }
69 
70 
71 // just for secondorder and Random123_globalindex and legacy units flag
72 int get_global_int_item(const char* name) {
73  if (strcmp(name, "secondorder") == 0) {
74  return secondorder;
75  } else if (strcmp(name, "Random123_global_index") == 0) {
77  } else if (strcmp(name, "_nrnunit_use_legacy_") == 0) {
78  return _nrnunit_use_legacy_;
79  }
80  return 0;
81 }
82 
83 // successively return global double info. Begin with p==NULL.
84 // Done when return NULL.
85 void* get_global_dbl_item(void* p, const char*& name, int& size, double*& val) {
86  Symbol* sp = (Symbol*) p;
87  if (sp == NULL) {
89  }
90  for (; sp; sp = sp->next) {
91  if (sp->type == VAR && sp->subtype == USERDOUBLE) {
92  name = sp->name;
93  if (ISARRAY(sp)) {
94  Arrayinfo* a = sp->arayinfo;
95  if (a->nsub == 1) {
96  size = a->sub[0];
97  val = new double[size];
98  for (int i = 0; i < a->sub[0]; ++i) {
99  char n[256];
100  sprintf(n, "%s[%d]", sp->name, i);
101  val[i] = *hoc_val_pointer(n);
102  }
103  }
104  } else {
105  size = 0;
106  val = new double[1];
107  val[0] = *sp->u.pval;
108  }
109  return sp->next;
110  }
111  }
112  return NULL;
113 }
114 
115 
116 /**
117  Copy weights from all coreneuron::NrnThread to NetCon instances.
118  This depends on the CoreNEURON weight order for each thread to be
119  the same as was originally sent from NEURON. See how that order
120  was constructed in CellGroup::mk_cgs_netcon_info.
121 **/
122 
123 void nrnthreads_all_weights_return(std::vector<double*>& weights) {
124  std::vector<int> iw(nrn_nthread); // index for each thread
125  Symbol* ncsym = hoc_lookup("NetCon");
126  hoc_List* ncl = ncsym->u.ctemplate->olist;
127  hoc_Item* q;
128  ITERATE(q, ncl) {
129  Object* ho = (Object*) VOIDITM(q);
130  NetCon* nc = (NetCon*) ho->u.this_pointer;
131  std::size_t ith = 0; // if no _vnt, put in thread 0
132  if (nc->target_ && nc->target_->_vnt) {
133  ith = std::size_t(((NrnThread*) (nc->target_->_vnt))->id);
134  }
135  for (int i = 0; i < nc->cnt_; ++i) {
136  nc->weight_[i] = weights[ith][iw[ith]++];
137  }
138  }
139 }
140 
141 /** @brief Return location for CoreNEURON to copy data into.
142  * The type is mechanism type or special negative type for voltage,
143  * i_membrane_, or time. See coreneuron/io/nrn_setup.cpp:stdindex2ptr.
144  * We allow coreneuron to copy to NEURON's AoS data as CoreNEURON knows
145  * how its data is arranged (SoA and possibly permuted).
146  * This function figures out the size (just for sanity check)
147  * and data pointer to be returned based on type and thread id.
148  * The ARTIFICIAL_CELL type case is special as there is no thread specific
149  * Memb_list for those.
150  */
151 size_t nrnthreads_type_return(int type, int tid, double*& data, double**& mdata) {
152  size_t n = 0;
153  data = NULL;
154  mdata = NULL;
155  if (tid >= nrn_nthread) {
156  return n;
157  }
158  NrnThread& nt = nrn_threads[tid];
159  if (type == voltage) {
160  data = nt._actual_v;
161  n = size_t(nt.end);
162  } else if (type == i_membrane_) { // i_membrane_
164  n = size_t(nt.end);
165  } else if (type == 0) { // time
166  data = &nt._t;
167  n = 1;
168  } else if (type > 0 && type < n_memb_func) {
169  Memb_list* ml = nt._ml_list[type];
170  if (ml) {
171  mdata = ml->data;
172  n = ml->nodecount;
173  } else {
174  // The single thread case is easy
175  if (nrn_nthread == 1) {
176  ml = memb_list + type;
177  mdata = ml->data;
178  n = ml->nodecount;
179  } else {
180  // mk_tml_with_art() created a cgs[id].mlwithart which appended
181  // artificial cells to the end. Turns out that
182  // cellgroups_[tid].type2ml[type]
183  // is the Memb_list we need. Sadly, by the time we get here, cellgroups_
184  // has already been deleted. So we defer deletion of the necessary
185  // cellgroups_ portion (deleting it on return from nrncore_run).
186  auto& ml = CellGroup::deferred_type2artml_[tid][type];
187  n = size_t(ml->nodecount);
188  mdata = ml->data;
189  }
190  }
191  }
192  return n;
193 }
194 
195 
196 void nrnthread_group_ids(int* grp) {
197  for (int i = 0; i < nrn_nthread; ++i) {
198  grp[i] = cellgroups_[i].group_id;
199  }
200 }
201 
202 
203 int nrnthread_dat1(int tid,
204  int& n_presyn,
205  int& n_netcon,
206  int*& output_gid,
207  int*& netcon_srcgid,
208  std::vector<int>& netcon_negsrcgid_tid) {
209  if (tid >= nrn_nthread) {
210  return 0;
211  }
212  CellGroup& cg = cellgroups_[tid];
213  n_presyn = cg.n_presyn;
214  n_netcon = cg.n_netcon;
215  output_gid = cg.output_gid;
216  cg.output_gid = NULL;
217  netcon_srcgid = cg.netcon_srcgid;
218  cg.netcon_srcgid = NULL;
219  netcon_negsrcgid_tid = cg.netcon_negsrcgid_tid;
220  return 1;
221 }
222 
223 // sizes and total data count
224 int nrnthread_dat2_1(int tid,
225  int& ngid,
226  int& n_real_gid,
227  int& nnode,
228  int& ndiam,
229  int& nmech,
230  int*& tml_index,
231  int*& ml_nodecount,
232  int& nidata,
233  int& nvdata,
234  int& nweight) {
235  if (tid >= nrn_nthread) {
236  return 0;
237  }
238  CellGroup& cg = cellgroups_[tid];
239  NrnThread& nt = nrn_threads[tid];
240 
241  ngid = cg.n_output;
242  n_real_gid = cg.n_real_output;
243  nnode = nt.end;
244  ndiam = cg.ndiam;
245  nmech = cg.n_mech;
246 
247  cg.ml_vdata_offset = new int[nmech];
248  int vdata_offset = 0;
249  tml_index = new int[nmech];
250  ml_nodecount = new int[nmech];
251  MlWithArt& mla = cg.mlwithart;
252  for (size_t j = 0; j < mla.size(); ++j) {
253  int type = mla[j].first;
254  Memb_list* ml = mla[j].second;
255  tml_index[j] = type;
256  ml_nodecount[j] = ml->nodecount;
257  cg.ml_vdata_offset[j] = vdata_offset;
258  int* ds = memb_func[type].dparam_semantics;
259  for (int psz = 0; psz < bbcore_dparam_size[type]; ++psz) {
260  if (ds[psz] == -4 || ds[psz] == -6 || ds[psz] == -7 || ds[psz] == 0) {
261  // printf("%s ds[%d]=%d vdata_offset=%d\n", memb_func[type].sym->name, psz, ds[psz],
262  // vdata_offset);
263  vdata_offset += ml->nodecount;
264  }
265  }
266  }
267  nvdata = vdata_offset;
268  nidata = 0;
269  // printf("nidata=%d nvdata=%d nnetcon=%d\n", nidata, nvdata, cg.n_netcon);
270  nweight = 0;
271  for (int i = 0; i < cg.n_netcon; ++i) {
272  nweight += cg.netcons[i]->cnt_;
273  }
274 
275  return 1;
276 }
277 
278 int nrnthread_dat2_2(int tid,
279  int*& v_parent_index,
280  double*& a,
281  double*& b,
282  double*& area,
283  double*& v,
284  double*& diamvec) {
285  if (tid >= nrn_nthread) {
286  return 0;
287  }
288  CellGroup& cg = cellgroups_[tid];
289  NrnThread& nt = nrn_threads[tid];
290 
291  assert(cg.n_real_output == nt.ncell);
292 
293  // If direct transfer, copy, because target space already allocated
294  bool copy = corenrn_direct;
295  if (copy) {
296  for (int i = 0; i < nt.end; ++i) {
297  v_parent_index[i] = nt._v_parent_index[i];
298  a[i] = nt._actual_a[i];
299  b[i] = nt._actual_b[i];
300  area[i] = nt._actual_area[i];
301  v[i] = nt._actual_v[i];
302  }
303  } else {
304  v_parent_index = nt._v_parent_index;
305  a = nt._actual_a;
306  b = nt._actual_b;
307  area = nt._actual_area;
308  v = nt._actual_v;
309  }
310  if (cg.ndiam) {
311  if (!copy) {
312  diamvec = new double[nt.end];
313  }
314  for (int i = 0; i < nt.end; ++i) {
315  Node* nd = nt._v_node[i];
316  double diam = 0.0;
317  for (Prop* p = nd->prop; p; p = p->next) {
318  if (p->type == MORPHOLOGY) {
319  diam = p->param[0];
320  break;
321  }
322  }
323  diamvec[i] = diam;
324  }
325  }
326  return 1;
327 }
328 
330  size_t i,
331  int dsz_inst,
332  int*& nodeindices,
333  double*& data,
334  int*& pdata,
335  std::vector<int>& pointer2type) {
336  if (tid >= nrn_nthread) {
337  return 0;
338  }
339  CellGroup& cg = cellgroups_[tid];
340  NrnThread& nt = nrn_threads[tid];
341  MlWithArtItem& mlai = cg.mlwithart[i];
342  int type = mlai.first;
343  Memb_list* ml = mlai.second;
344  // for direct transfer, data=NULL means copy into passed space for nodeindices, data, and pdata
345  bool copy = data ? true : false;
346 
347  int vdata_offset = cg.ml_vdata_offset[i];
348  int isart = nrn_is_artificial_[type];
349  int n = ml->nodecount;
350  int sz = nrn_prop_param_size_[type];
351  double* data1;
352  if (isart) { // data may not be contiguous
353  data1 = contiguous_art_data(ml->data, n, sz); // delete after use
354  nodeindices = NULL;
355  } else {
356  nodeindices = ml->nodeindices; // allocated below if copy
357  data1 = ml->data[0]; // do not delete after use
358  }
359  if (copy) {
360  if (!isart) {
361  nodeindices = (int*) emalloc(n * sizeof(int));
362  for (int i = 0; i < n; ++i) {
363  nodeindices[i] = ml->nodeindices[i];
364  }
365  }
366  int nn = n * sz;
367  for (int i = 0; i < nn; ++i) {
368  data[i] = data1[i];
369  }
370  if (isart) {
371  delete[] data1;
372  }
373  } else {
374  data = data1;
375  }
376 
377  sz = bbcore_dparam_size[type]; // nrn_prop_dparam_size off by 1 if cvode_ieq.
378  if (sz) {
379  int* pdata1;
380  pdata1 = datum2int(type, ml, nt, cg, cg.datumindices[dsz_inst], vdata_offset, pointer2type);
381  if (copy) {
382  int nn = n * sz;
383  for (int i = 0; i < nn; ++i) {
384  pdata[i] = pdata1[i];
385  }
386  delete[] pdata1;
387  } else {
388  pdata = pdata1;
389  }
390  } else {
391  pdata = NULL;
392  }
393 
394  return 1;
395 }
396 
397 int nrnthread_dat2_3(int tid,
398  int nweight,
399  int*& output_vindex,
400  double*& output_threshold,
401  int*& netcon_pnttype,
402  int*& netcon_pntindex,
403  double*& weights,
404  double*& delays) {
405  if (tid >= nrn_nthread) {
406  return 0;
407  }
408  CellGroup& cg = cellgroups_[tid];
409 
410  output_vindex = new int[cg.n_presyn];
411  output_threshold = new double[cg.n_real_output];
412  for (int i = 0; i < cg.n_presyn; ++i) {
413  output_vindex[i] = cg.output_vindex[i];
414  }
415  for (int i = 0; i < cg.n_real_output; ++i) {
416  output_threshold[i] = cg.output_ps[i] ? cg.output_ps[i]->threshold_ : 0.0;
417  }
418 
419  // connections
420  int n = cg.n_netcon;
421  // printf("n_netcon=%d nweight=%d\n", n, nweight);
422  netcon_pnttype = cg.netcon_pnttype;
423  cg.netcon_pnttype = NULL;
424  netcon_pntindex = cg.netcon_pntindex;
425  cg.netcon_pntindex = NULL;
426  // alloc a weight array and write netcon weights
427  weights = new double[nweight];
428  int iw = 0;
429  for (int i = 0; i < n; ++i) {
430  NetCon* nc = cg.netcons[i];
431  for (int j = 0; j < nc->cnt_; ++j) {
432  weights[iw++] = nc->weight_[j];
433  }
434  }
435  // alloc a delay array and write netcon delays
436  delays = new double[n];
437  for (int i = 0; i < n; ++i) {
438  NetCon* nc = cg.netcons[i];
439  delays[i] = nc->delay_;
440  }
441 
442  return 1;
443 }
444 
445 int nrnthread_dat2_corepointer(int tid, int& n) {
446  if (tid >= nrn_nthread) {
447  return 0;
448  }
449 
450  n = 0;
451  MlWithArt& mla = cellgroups_[tid].mlwithart;
452  for (size_t i = 0; i < mla.size(); ++i) {
453  if (nrn_bbcore_write_[mla[i].first]) {
454  ++n;
455  }
456  }
457 
458  return 1;
459 }
460 
462  int type,
463  int& icnt,
464  int& dcnt,
465  int*& iArray,
466  double*& dArray) {
467  if (tid >= nrn_nthread) {
468  return 0;
469  }
470  NrnThread& nt = nrn_threads[tid];
471  CellGroup& cg = cellgroups_[tid];
472  Memb_list* ml = cg.type2ml[type];
473 
474  dcnt = 0;
475  icnt = 0;
476  // data size and allocate
477  for (int i = 0; i < ml->nodecount; ++i) {
479  NULL, NULL, &dcnt, &icnt, ml->data[i], ml->pdata[i], ml->_thread, &nt);
480  }
481  dArray = NULL;
482  iArray = NULL;
483  if (icnt) {
484  iArray = new int[icnt];
485  }
486  if (dcnt) {
487  dArray = new double[dcnt];
488  }
489  icnt = dcnt = 0;
490  // data values
491  for (int i = 0; i < ml->nodecount; ++i) {
493  dArray, iArray, &dcnt, &icnt, ml->data[i], ml->pdata[i], ml->_thread, &nt);
494  }
495 
496  return 1;
497 }
498 
499 
500 // primarily to return nrnran123 sequence info when psolve on the coreneuron
501 // side is finished so can either do another coreneuron psolve or
502 // continue on neuron side.
503 int core2nrn_corepointer_mech(int tid, int type, int icnt, int dcnt, int* iArray, double* dArray) {
504  if (tid >= nrn_nthread) {
505  return 0;
506  }
507  NrnThread& nt = nrn_threads[tid];
508  Memb_list* ml = nt._ml_list[type];
509  // ARTIFICIAL_CELL are not in nt.
510  if (!ml) {
512  assert(ml);
513  }
514 
515  int ik = 0;
516  int dk = 0;
517  // data values
518  for (int i = 0; i < ml->nodecount; ++i) {
520  dArray, iArray, &dk, &ik, ml->data[i], ml->pdata[i], ml->_thread, &nt);
521  }
522  assert(dk == dcnt);
523  assert(ik == icnt);
524  return 1;
525 }
526 
527 int* datum2int(int type,
528  Memb_list* ml,
529  NrnThread& nt,
530  CellGroup& cg,
531  DatumIndices& di,
532  int ml_vdata_offset,
533  std::vector<int>& pointer2type) {
534  int isart = nrn_is_artificial_[di.type];
535  int sz = bbcore_dparam_size[type];
536  int* pdata = new int[ml->nodecount * sz];
537  int* semantics = memb_func[type].dparam_semantics;
538  for (int i = 0; i < ml->nodecount; ++i) {
539  int ioff = i * sz;
540  for (int j = 0; j < sz; ++j) {
541  int jj = ioff + j;
542  int etype = di.ion_type[jj];
543  int eindex = di.ion_index[jj];
544  const int seman = semantics[j];
545  // Would probably be more clear if use seman for as many as
546  // possible of the cases
547  // below and within each case deal with etype appropriately.
548  // ion_type and ion_index have become misnomers as they no longer
549  // refer to ions specificially but the mechanism type where the
550  // range variable lives (and otherwise is generally the same as
551  // seman). And ion_index refers to the index of the range variable
552  // within the mechanism (or voltage, area, etc.)
553  if (seman == -5) { // POINTER to range variable (e.g. voltage)
554  pdata[jj] = eindex;
555  pointer2type.push_back(etype);
556  } else if (etype == -1) {
557  if (isart) {
558  pdata[jj] = -1; // maybe save this space eventually. but not many of these in
559  // bb models
560  } else {
561  pdata[jj] = eindex;
562  }
563  } else if (etype == -9) {
564  pdata[jj] = eindex;
565  } else if (etype > 0 && etype < 1000) { // ion pointer
566  pdata[jj] = eindex;
567  } else if (etype > 1000 && etype < 2000) { // ionstyle can be explicit instead of
568  // pointer to int*
569  pdata[jj] = eindex;
570  } else if (etype == -2) { // an ion and this is the iontype
571  pdata[jj] = eindex;
572  } else if (etype == -4) { // netsend (_tqitem)
573  pdata[jj] = ml_vdata_offset + eindex;
574  // printf("etype %d jj=%d eindex=%d pdata=%d\n", etype, jj, eindex, pdata[jj]);
575  } else if (etype == -6) { // pntproc
576  pdata[jj] = ml_vdata_offset + eindex;
577  // printf("etype %d jj=%d eindex=%d pdata=%d\n", etype, jj, eindex, pdata[jj]);
578  } else if (etype == -7) { // bbcorepointer
579  pdata[jj] = ml_vdata_offset + eindex;
580  // printf("etype %d jj=%d eindex=%d pdata=%d\n", etype, jj, eindex, pdata[jj]);
581  } else { // uninterpreted
582  assert(eindex != -3); // avoided if last
583  pdata[jj] = 0;
584  }
585  }
586  }
587  return pdata;
588 }
589 
590 void part2_clean() {
592 
594 
595  if (corenrn_direct) {
597  }
598 
599  delete[] cellgroups_;
600  cellgroups_ = NULL;
601 }
602 
603 std::vector<NetCon**> CellGroup::deferred_netcons;
604 
607  for (int tid = 0; tid < nrn_nthread; ++tid) {
608  CellGroup& cg = cgs[tid];
609  deferred_netcons.push_back(cg.netcons);
610  cg.netcons = nullptr;
611  }
612 }
613 
615  for (auto ncs: deferred_netcons) {
616  if (ncs) {
617  delete[] ncs;
618  }
619  }
620  deferred_netcons.clear();
621 }
622 
623 // Vector.play information.
624 // Must play into a data element in this thread
625 // File format is # of play instances in this thread (generally VecPlayContinuous)
626 // For each Play instance
627 // VecPlayContinuousType (4), pd (index), y.size, yvec, tvec
628 // Other VecPlay instance types are possible, such as VecPlayContinuous with
629 // a discon vector or VecPlayStep with a DT or tvec, but are not implemented
630 // at present. Assertion errors are generated if not type 0 of if we
631 // cannot determine the index into the NrnThread._data .
632 
633 int nrnthread_dat2_vecplay(int tid, std::vector<int>& indices) {
634  if (tid >= nrn_nthread) {
635  return 0;
636  }
637  NrnThread& nt = nrn_threads[tid];
638 
639  // add the index of each instance in fixed_play_ for thread tid.
640  // error if not a VecPlayContinuous with no discon vector
641  PlayRecList* fp = net_cvode_instance->fixed_play_;
642  for (int i = 0; i < fp->count(); ++i) {
643  if (fp->item(i)->type() == VecPlayContinuousType) {
644  VecPlayContinuous* vp = (VecPlayContinuous*) fp->item(i);
645  if (vp->discon_indices_ == NULL) {
646  if (vp->ith_ == nt.id) {
647  assert(vp->y_ && vp->t_);
648  indices.push_back(i);
649  }
650  } else {
651  assert(0);
652  }
653  } else {
654  assert(0);
655  }
656  }
657 
658  return 1;
659 }
660 
662  int i,
663  int& vptype,
664  int& mtype,
665  int& ix,
666  int& sz,
667  double*& yvec,
668  double*& tvec,
669  int& last_index,
670  int& discon_index,
671  int& ubound_index) {
672  if (tid >= nrn_nthread) {
673  return 0;
674  }
675  NrnThread& nt = nrn_threads[tid];
676 
677  PlayRecList* fp = net_cvode_instance->fixed_play_;
678  if (fp->item(i)->type() == VecPlayContinuousType) {
679  VecPlayContinuous* vp = (VecPlayContinuous*) fp->item(i);
680  if (vp->discon_indices_ == NULL) {
681  if (vp->ith_ == nt.id) {
682  double* pd = vp->pd_;
683  int found = 0;
684  vptype = vp->type();
685  for (NrnThreadMembList* tml = nt.tml; tml; tml = tml->next) {
686  if (nrn_is_artificial_[tml->index]) {
687  continue;
688  }
689  Memb_list* ml = tml->ml;
690  int nn = nrn_prop_param_size_[tml->index] * ml->nodecount;
691  if (pd >= ml->data[0] && pd < (ml->data[0] + nn)) {
692  mtype = tml->index;
693  ix = (pd - ml->data[0]);
694  sz = vector_capacity(vp->y_);
695  yvec = vector_vec(vp->y_);
696  tvec = vector_vec(vp->t_);
697  found = 1;
698  break;
699  }
700  }
701  assert(found);
702  // following 3 used for direct-mode.
703  last_index = vp->last_index_;
704  discon_index = vp->discon_index_;
705  ubound_index = vp->ubound_index_;
706  return 1;
707  }
708  }
709  }
710 
711  return 0;
712 }
713 
714 /** getting one item at a time from CoreNEURON **/
715 void core2nrn_vecplay(int tid, int i, int last_index, int discon_index, int ubound_index) {
716  if (tid >= nrn_nthread) {
717  return;
718  }
719  PlayRecList* fp = net_cvode_instance->fixed_play_;
720  assert(fp->item(i)->type() == VecPlayContinuousType);
721  VecPlayContinuous* vp = (VecPlayContinuous*) fp->item(i);
722  vp->last_index_ = last_index;
723  vp->discon_index_ = discon_index;
724  vp->ubound_index_ = ubound_index;
725 }
726 
727 /** start the vecplay events **/
729  PlayRecList* fp = net_cvode_instance->fixed_play_;
730  for (int i = 0; i < fp->count(); ++i) {
731  if (fp->item(i)->type() == VecPlayContinuousType) {
732  VecPlayContinuous* vp = (VecPlayContinuous*) fp->item(i);
733  NrnThread* nt = nrn_threads + vp->ith_;
734  vp->e_->send(vp->t_->elem(vp->ubound_index_), net_cvode_instance, nt);
735  }
736  }
737 }
738 
739 /** getting one item at a time from nrn2core_transfer_WATCH **/
740 void nrn2core_transfer_WatchCondition(WatchCondition* wc, void (*cb)(int, int, int, int, int)) {
741  Point_process* pnt = wc->pnt_;
742  assert(pnt);
743  int tid = ((NrnThread*) (pnt->_vnt))->id;
744  int pnttype = pnt->prop->type;
745  int watch_index = wc->watch_index_;
746  int triggered = wc->flag_ ? 1 : 0;
747  int pntindex = CellGroup::nrncore_pntindex_for_queue(pnt->prop->param, tid, pnttype);
748  (*cb)(tid, pnttype, pntindex, watch_index, triggered);
749 
750  // This transfers CvodeThreadData activated WatchCondition
751  // information. All WatchCondition stuff is implemented in netcvode.cpp.
752  // cvodeobj.h: HTList* CvodeThreadData.watch_list_
753  // netcon.h: WatchCondition
754  // On the NEURON side, WatchCondition is activated within a
755  // NET_RECEIVE block with the NMODL WATCH statement translated into a
756  // call to _nrn_watch_activate implmented as a function in netcvode.cpp.
757  // Note that on the CoreNEURON side, all the WATCH functionality is
758  // implemented within the mod file translation, and the info from this side
759  // is used to assign a value in the location specified by the
760  // _watch_array(flag) macro.
761  // The return from psolve must transfer back the correct conditions
762  // so that NEURON can continue with a classical psolve, or, if CoreNEURON
763  // continues, receive the correct transfer of conditions back from NEURON
764  // again.
765  // Note: the reason CoreNEURON does not already have the correct watch
766  // condition from phase2 setup is because, on the NEURON side,
767  // _nrn_watch_activate fills in the _watch_array[0] with a pointer to
768  // WatchList and _watch_array[i] with a pointer to WatchCondition.
769  // Activation consists of removing all conditions from a HTList (HeadTailList)
770  // and _watch_array[0] (only on the first _nrn_watch_activate call from a
771  // NET_RECEIVE delivery event). And appending to _watch_array[0] and
772  // Append to the HTList which is the CvodeThreadData.watch_list_;
773  // But on the CoreNEURON side, _watch_array[0] is unused and _watch_array[i]
774  // is a two bit integer. Bit 2 on means the WATCH is activated Bit 1
775  // is used to determine the transition from false to true for doing a
776  // net_send (immediate deliver).
777 }
778 
779 // for faster determination of the movable index given the type
780 static std::map<int, int> type2movable;
781 static void setup_type2semantics() {
782  if (type2movable.empty()) {
783  for (int type = 0; type < n_memb_func; ++type) {
784  int* ds = memb_func[type].dparam_semantics;
785  if (ds) {
786  for (int psz = 0; psz < bbcore_dparam_size[type]; ++psz) {
787  if (ds[psz] == -4) { // netsend semantics
788  type2movable[type] = psz;
789  }
790  }
791  }
792  }
793  }
794 }
795 
796 // Copying TQItem information for transfer to CoreNEURON has been factored
797 // out of nrn2core_transfer_tqueue since, if BinQ is being used, it involves
798 // iterating over the BinQ as well as the normal TQueue.
799 static void set_info(TQItem* tqi,
800  int tid,
801  NrnCoreTransferEvents* core_te,
802  std::unordered_map<NetCon*, std::vector<size_t>>& netcon2intdata,
803  std::unordered_map<PreSyn*, std::vector<size_t>>& presyn2intdata,
804  std::unordered_map<double*, std::vector<size_t>>& weight2intdata) {
805  DiscreteEvent* de = (DiscreteEvent*) (tqi->data_);
806  int type = de->type();
807  double tdeliver = tqi->t_;
808  core_te->type.push_back(type);
809  core_te->td.push_back(tdeliver);
810 
811  switch (type) {
812  case DiscreteEventType: { // 0
813  } break;
814  case NetConType: { // 2
815  NetCon* nc = (NetCon*) de;
816  // To find the i for cg.netcons[i] == nc
817  // and since there are generally very many fewer nc on the queue
818  // than netcons. Begin a nc2i map that we can fill in for i
819  // later in one sweep through the cg.netcons.
820  // Here is where it goes.
821  size_t iloc = core_te->intdata.size();
822  core_te->intdata.push_back(-1);
823  // But must take into account the rare situation where the same
824  // NetCon is on the queue more than once. Hence the std::vector
825  netcon2intdata[nc].push_back(iloc);
826  } break;
827  case SelfEventType: { // 3
828  SelfEvent* se = (SelfEvent*) de;
829  Point_process* pnt = se->target_;
830  int type = pnt->prop->type;
831  int movable_index = type2movable[type];
832  double* wt = se->weight_;
833 
834  core_te->intdata.push_back(type);
835  core_te->dbldata.push_back(se->flag_);
836 
837  // All SelfEvent have a target. A SelfEvent only has a weight if
838  // it was issued in response to a NetCon event to the target
839  // NET_RECEIVE block. Determination of Point_process* target_ on the
840  // CoreNEURON side uses mechanism type and instance index from here
841  // on the NEURON side. And the latter can be determined now from pnt.
842  // On the other hand, if there is a non-null weight pointer, its index
843  // can only be determined by sweeping over all NetCon.
844 
845  double* data = pnt->prop->param;
846  // Introduced the public static method below because ARTIFICIAL_CELL
847  // are not located in NrnThread and are not cache efficient.
849  core_te->intdata.push_back(index);
850 
851  size_t iloc_wt = core_te->intdata.size();
852  if (wt) { // don't bother with NULL weights
853  weight2intdata[wt].push_back(iloc_wt);
854  }
855  core_te->intdata.push_back(-1); // If NULL weight this is the indicator
856 
857  TQItem** movable = (TQItem**) se->movable_;
858  TQItem** pnt_movable = (TQItem**) (&pnt->prop->dparam[movable_index]);
859  // Only one SelfEvent on the queue for a given point process can be movable
860  core_te->intdata.push_back((movable && *movable == tqi) ? 1 : 0);
861  if (movable && *movable == tqi) {
862  assert(pnt_movable && *pnt_movable == tqi);
863  }
864 
865  } break;
866  case PreSynType: { // 4
867  PreSyn* ps = (PreSyn*) de;
868 
869  // NEURON puts PreSyn on every thread queue
870  // Skip if PreSyn not associated with this thread.
871  bool skip = (ps->nt_ && (ps->nt_->id != tid)) ? true : false;
872  // Skip if effectively an InputPresyn (ps->nt_ == NULL)
873  // and this is not thread 0.
874  skip = (!ps->nt_ && tid != 0) ? true : skip;
875  if (skip) {
876  // erase what was already added
877  core_te->type.pop_back();
878  core_te->td.pop_back();
879  break;
880  }
881  // Output PreSyn similar to NetCon but more data.
882  // Input PreSyn (ps->output_index = -1 and ps->gid >= 0)
883  // is distinquished from PreSyn (ps->output_index == ps->gid
884  // or both negative) by the first item of 0 or 1 respectively followed
885  // by gid or presyn index respectively.
886  // That is:
887  // Output PreSyn format is 0, presyn index
888  // initialized to -1 and figured out from presyn2intdata, and
889  // ps->delay_
890  // Input PreSyn format is 1, gid, and ps->delay_
891  if (ps->output_index_ < 0 && ps->gid_ >= 0) {
892  // InputPreSyn on the CoreNEURON side
893  core_te->intdata.push_back(1);
894  core_te->intdata.push_back(ps->gid_);
895  } else {
896  // PreSyn on the NEURON side
897  core_te->intdata.push_back(0);
898  size_t iloc = core_te->intdata.size();
899  core_te->intdata.push_back(-1);
900  presyn2intdata[ps].push_back(iloc);
901  }
902  // CoreNEURON PreSyn has no notion of use_min_delay_ so if that
903  // is in effect, then the send time is actually tt - nc->delay_
904  // (Note there is no core2nrn inverse as PreSyn does not appear on
905  // the CoreNEURON event queue).
906  if (ps->use_min_delay_) {
907  core_te->td.back() -= ps->delay_;
908  }
909  } break;
910  case HocEventType: { // 5
911  // Not supported in CoreNEURON, discard and print a warning.
912  core_te->td.pop_back();
913  core_te->type.pop_back();
914  // Delivery time was often reduced by a quarter step to avoid
915  // fixed step roundoff problems.
916  Fprintf(stderr,
917  "WARNING: CVode.event(...) for delivery at time step nearest %g discarded. "
918  "CoreNEURON cannot presently handle interpreter events (rank %d, thread %d).\n",
919  nrnmpi_myid,
920  tdeliver,
921  nrnmpi_myid,
922  tid);
923  } break;
924  case PlayRecordEventType: { // 6
925  } break;
926  case NetParEventType: { // 7
927  } break;
928  default: {
929  } break;
930  }
931 }
932 
934  if (tid >= nrn_nthread) {
935  return NULL;
936  }
937 
939 
941 
942  // see comments below about same object multiple times on queue
943  // and single sweep fill
944  std::unordered_map<NetCon*, std::vector<size_t>> netcon2intdata;
945  std::unordered_map<PreSyn*, std::vector<size_t>> presyn2intdata;
946  std::unordered_map<double*, std::vector<size_t>> weight2intdata;
947 
948  NrnThread& nt = nrn_threads[tid];
950  TQItem* tqi;
951  auto& cg = cellgroups_[tid];
952  // make sure all buffered interthread events are on the queue
954 
955  // Iterate over all tqueue items to record info needed for transfer to
956  // coreneuron. The atomic_dq removes items from the queue but misses
957  // BinQ items if present. So need separate iteration for that (hence the
958  // factoring out of the loop bodies into set_info.)
959  while ((tqi = tq->atomic_dq(1e15)) != NULL) {
960  set_info(tqi, tid, core_te, netcon2intdata, presyn2intdata, weight2intdata);
961  }
962  if (nrn_use_bin_queue_) {
963  // does not remove items but the entire queue will be cleared
964  // before using again.
965  for (tqi = tq->binq()->first(); tqi; tqi = tq->binq()->next(tqi)) {
966  set_info(tqi, tid, core_te, netcon2intdata, presyn2intdata, weight2intdata);
967  }
968  }
969 
970  // fill in the integers for the pointer translation
971 
972  // NEURON NetCon* to CoreNEURON index into nt.netcons
973  for (int i = 0; i < cg.n_netcon; ++i) {
974  NetCon* nc = cg.netcons[i];
975  auto iter = netcon2intdata.find(nc);
976  if (iter != netcon2intdata.end()) {
977  for (auto iloc: iter->second) {
978  core_te->intdata[iloc] = i;
979  }
980  }
981  }
982 
983  // NEURON PreSyn* to CoreNEURON index into nt.presyns
984 #define NRN_SENTINAL 100000000000
985  for (int i = 0; i < cg.n_presyn; ++i) {
986  PreSyn* ps = cg.output_ps[i];
987  auto iter = presyn2intdata.find(ps);
988  if (iter != presyn2intdata.end()) {
989  // not visited twice
990  assert(iter->second[0] < NRN_SENTINAL);
991  for (auto iloc: iter->second) {
992  core_te->intdata[iloc] = i;
993  }
994  presyn2intdata[ps][0] = i + NRN_SENTINAL;
995  }
996  }
997  // all presyn2intdata should have been visited so all
998  // presyn2intdata[ps][0] must be >= NRN_SENTINAL
999  for (auto& iter: presyn2intdata) {
1000  assert(iter.second[0] >= NRN_SENTINAL);
1001  }
1002 
1003  // NEURON SelfEvent weight* into CoreNEURON index into nt.netcons
1004  // On the CoreNEURON side we find the NetCon and then the
1005  // nc.u.weight_index_
1006  for (int i = 0; i < cg.n_netcon; ++i) {
1007  NetCon* nc = cg.netcons[i];
1008  double* wt = nc->weight_;
1009  auto iter = weight2intdata.find(wt);
1010  if (iter != weight2intdata.end()) {
1011  for (auto iloc: iter->second) {
1012  core_te->intdata[iloc] = i;
1013  }
1014  }
1015  }
1016 
1017  return core_te;
1018 }
1019 
1020 /** @brief Initialize queues before transfer
1021  Probably aleady clear, but if binq then must be initialized to time.
1022  */
1023 void core2nrn_clear_queues(double time) {
1024  nrn_threads[0]._t = time; // used by clear_event_queue
1026 }
1027 
1028 /** @brief Called from CoreNEURON core2nrn_tqueue_item.
1029  */
1030 void core2nrn_NetCon_event(int tid, double td, size_t nc_index) {
1031  assert(tid < nrn_nthread);
1032  NrnThread& nt = nrn_threads[tid];
1033  // cellgroups_ has been deleted but deletion of cg.netcons was deferred
1034  // (and will be deleted on return from nrncore_run).
1035  // This is tragic for memory usage. There are more NetCon's than anything.
1036  // Would be better to save the memory at a cost of single iteration over
1037  // NetCon.
1038  NetCon* nc = CellGroup::deferred_netcons[tid][nc_index];
1039  nc->send(td, net_cvode_instance, &nt);
1040 }
1041 
1042 static void core2nrn_SelfEvent_helper(int tid,
1043  double td,
1044  int tar_type,
1045  int tar_index,
1046  double flag,
1047  double* weight,
1048  int is_movable) {
1049  if (type2movable.empty()) {
1051  }
1052  Memb_list* ml = nrn_threads[tid]._ml_list[tar_type];
1053  Point_process* pnt;
1054  if (ml) {
1055  pnt = (Point_process*) ml->pdata[tar_index][1]._pvoid;
1056  } else {
1057  // In NEURON world, ARTIFICIAL_CELLs do not live in NrnThread.
1058  // And the old deferred_type2artdata_ only gave us data, not pdata.
1059  // So this is where I decided to replace the more
1060  // expensive deferred_type2artml_.
1061  ml = CellGroup::deferred_type2artml_[tid][tar_type];
1062  pnt = (Point_process*) ml->pdata[tar_index][1]._pvoid;
1063  }
1064 
1065  // Needs to be tested when permuted on CoreNEURON side.
1066  assert(tar_type == pnt->prop->type);
1067  // assert(tar_index == CellGroup::nrncore_pntindex_for_queue(pnt->prop->param, tid, tar_type));
1068 
1069  int movable_index = type2movable[tar_type];
1070  void** movable_arg = &(pnt->prop->dparam[movable_index]._pvoid);
1071  TQItem* old_movable_arg = (TQItem*) (*movable_arg);
1072 
1073  nrn_net_send(&(pnt->prop->dparam[movable_index]._pvoid), weight, pnt, td, flag);
1074  if (!is_movable) {
1075  *movable_arg = (void*) old_movable_arg;
1076  }
1077 }
1078 
1080  double td,
1081  int tar_type,
1082  int tar_index,
1083  double flag,
1084  size_t nc_index,
1085  int is_movable) {
1086  assert(tid < nrn_nthread);
1087  NetCon* nc = CellGroup::deferred_netcons[tid][nc_index];
1088 
1089 #if 1
1090  // verify nc->target_ consistent with tar_type, tar_index.
1091  Memb_list* ml = nrn_threads[tid]._ml_list[tar_type];
1092  Point_process* pnt = (Point_process*) ml->pdata[tar_index][1]._pvoid;
1093  assert(nc->target_ == pnt);
1094 #endif
1095 
1096  double* weight = nc->weight_;
1097  core2nrn_SelfEvent_helper(tid, td, tar_type, tar_index, flag, weight, is_movable);
1098 }
1099 
1101  double td,
1102  int tar_type,
1103  int tar_index,
1104  double flag,
1105  int is_movable) {
1106  assert(tid < nrn_nthread);
1107  double* weight = NULL;
1108  core2nrn_SelfEvent_helper(tid, td, tar_type, tar_index, flag, weight, is_movable);
1109 }
1110 
1111 // Set of the voltage indices in which PreSyn.flag_ == true
1112 void core2nrn_PreSyn_flag(int tid, std::set<int> presyns_flag_true) {
1113  if (tid >= nrn_nthread) {
1114  return;
1115  }
1116  NetCvodeThreadData& nctd = net_cvode_instance->p[tid];
1117  hoc_Item* pth = nctd.psl_thr_;
1118  if (pth) {
1119  hoc_Item* q;
1120  // turn off all the PreSyn.flag_ as they might have been turned off
1121  // during the psolve on the coreneuron side.
1122  ITERATE(q, pth) {
1123  PreSyn* ps = (PreSyn*) VOIDITM(q);
1124  ps->flag_ = false;
1125  }
1126  if (presyns_flag_true.empty()) {
1127  return;
1128  }
1129  ITERATE(q, pth) {
1130  PreSyn* ps = (PreSyn*) VOIDITM(q);
1131  assert(ps->nt_ == (nrn_threads + tid));
1132  if (ps->thvar_) {
1133  int type = 0;
1134  int index_v = -1;
1135  nrn_dblpntr2nrncore(ps->thvar_, *ps->nt_, type, index_v);
1136  assert(type == voltage);
1137  if (presyns_flag_true.erase(index_v)) {
1138  ps->flag_ = true;
1139  if (presyns_flag_true.empty()) {
1140  break;
1141  }
1142  }
1143  }
1144  }
1145  }
1146 }
1147 
1148 // Add the voltage indices in which PreSyn.flag_ == true to the set.
1149 void nrn2core_PreSyn_flag(int tid, std::set<int>& presyns_flag_true) {
1150  if (tid >= nrn_nthread) {
1151  return;
1152  }
1153  NetCvodeThreadData& nctd = net_cvode_instance->p[tid];
1154  hoc_Item* pth = nctd.psl_thr_;
1155  if (pth) {
1156  hoc_Item* q;
1157  ITERATE(q, pth) {
1158  PreSyn* ps = (PreSyn*) VOIDITM(q);
1159  assert(ps->nt_ == (nrn_threads + tid));
1160  if (ps->flag_ == true && ps->thvar_) {
1161  int type = 0;
1162  int index_v = -1;
1163  nrn_dblpntr2nrncore(ps->thvar_, *ps->nt_, type, index_v);
1164  assert(type == voltage);
1165  presyns_flag_true.insert(index_v);
1166  }
1167  }
1168  }
1169 }
1170 
1171 // For each watch index, activate the WatchCondition
1172 void core2nrn_watch_activate(int tid, int type, int watch_begin, Core2NrnWatchInfo& wi) {
1173  if (tid >= nrn_nthread) {
1174  return;
1175  }
1176  NrnThread& nt = nrn_threads[tid];
1177  Memb_list* ml = nt._ml_list[type];
1178  for (size_t i = 0; i < wi.size(); ++i) {
1179  Core2NrnWatchInfoItem& active_watch_items = wi[i];
1180  Datum* pd = ml->pdata[i];
1181  int r = 0; // first activate removes formerly active from pd.
1182  for (auto watch_item: active_watch_items) {
1183  int watch_index = watch_item.first;
1184  bool above_thresh = watch_item.second;
1185  WatchCondition* wc = (WatchCondition*) pd[watch_index]._pvoid;
1186  if (!wc) { // if any do not exist in this instance, create them all
1187  // with proper callback and flag.
1188  (*(nrn_watch_allocate_[type]))(pd);
1189  wc = (WatchCondition*) pd[watch_index]._pvoid;
1190  }
1192  pd + watch_begin, wc->c_, watch_index - watch_begin, wc->pnt_, r++, wc->nrflag_);
1193  wc->flag_ = above_thresh ? 1 : 0;
1194  // If flag_ is 1
1195  // there will not be a (immediate) transition event
1196  // til the value() becomes negative again and then goes positive.
1197  }
1198  }
1199 }
1200 
1201 // nrn<->corenrn PatternStim
1202 
1203 extern "C" {
1205 }
1206 static int patternstim_type;
1207 
1208 // Info from NEURON PatternStim at beginning of psolve.
1210  if (!patternstim_type) {
1211  for (int i = 3; i < n_memb_func; ++i) {
1212  if (strcmp(memb_func[i].sym->name, "PatternStim") == 0) {
1213  patternstim_type = i;
1214  break;
1215  }
1216  }
1217  }
1218 
1220  assert(ml.nodecount == 1);
1222 }
void cb(const char *s)
Definition: bbstest.cpp:5
short index
Definition: cabvars.h:10
Memb_func * memb_func
Definition: init.cpp:123
short type
Definition: cabvars.h:9
std::vector< MlWithArtItem > MlWithArt
Definition: cell_group.h:16
std::pair< int, Memb_list * > MlWithArtItem
Definition: cell_group.h:13
TQItem * next(TQItem *)
Definition: sptbinq.cpp:374
TQItem * first()
Iterate in ascending bin order starting at current bin.
Definition: sptbinq.cpp:363
int group_id
Definition: cell_group.h:25
static void clean_deferred_netcons()
int n_real_output
Definition: cell_group.h:29
static std::vector< NetCon ** > deferred_netcons
Definition: cell_group.h:82
int * ml_vdata_offset
Definition: cell_group.h:32
static void clear_artdata2index()
Definition: cell_group.h:61
int n_mech
Definition: cell_group.h:31
static int nrncore_pntindex_for_queue(double *d, int tid, int type)
Definition: cell_group.h:101
static void defer_clean_netcons(CellGroup *)
int * output_vindex
Definition: cell_group.h:36
NetCon ** netcons
Definition: cell_group.h:39
int * netcon_srcgid
Definition: cell_group.h:40
static void clean_art(CellGroup *)
Definition: cell_group.cpp:619
Memb_list ** type2ml
Definition: cell_group.h:24
int * output_gid
Definition: cell_group.h:35
std::vector< int > netcon_negsrcgid_tid
Definition: cell_group.h:42
PreSyn ** output_ps
Definition: cell_group.h:34
int n_presyn
Definition: cell_group.h:27
MlWithArt mlwithart
Definition: cell_group.h:50
int n_netcon
Definition: cell_group.h:38
static Deferred_Type2ArtMl deferred_type2artml_
Definition: cell_group.h:81
int * netcon_pnttype
Definition: cell_group.h:45
int * netcon_pntindex
Definition: cell_group.h:46
DatumIndices * datumindices
Definition: cell_group.h:49
int n_output
Definition: cell_group.h:28
int ndiam
Definition: cell_group.h:30
bool flag_
Definition: netcon.h:198
virtual int type()
Definition: netcon.h:68
virtual void send(double deliverytime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3152
double & elem(int n)
Definition: ivocvect.h:31
Definition: netcon.h:83
double * weight_
Definition: netcon.h:112
int cnt_
Definition: netcon.h:114
virtual void send(double sendtime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3173
double delay_
Definition: netcon.h:109
Point_process * target_
Definition: netcon.h:111
NetCvodeThreadData * p
Definition: netcvode.h:252
PlayRecList * fixed_play_
Definition: netcvode.h:131
hoc_Item * psl_thr_
Definition: netcvode.h:50
double * pd_
Definition: vrecitem.h:91
int ith_
Definition: vrecitem.h:94
Definition: netcon.h:255
double * thvar_
Definition: netcon.h:294
int output_index_
Definition: netcon.h:306
NrnThread * nt_
Definition: netcon.h:300
int gid_
Definition: netcon.h:307
double delay_
Definition: netcon.h:293
double threshold_
Definition: netcon.h:292
int use_min_delay_
Definition: netcon.h:304
void ** movable_
Definition: netcon.h:167
double * weight_
Definition: netcon.h:166
Point_process * target_
Definition: netcon.h:165
double flag_
Definition: netcon.h:164
Definition: bbtqueue.h:6
double t_
Definition: bbtqueue.h:23
void * data_
Definition: bbtqueue.h:22
BinQ * binq()
Definition: sptbinq.h:137
TQItem * atomic_dq(double til)
Definition: sptbinq.cpp:251
virtual int type()
Definition: vrecitem.h:293
PlayRecordEvent * e_
Definition: vrecitem.h:305
IvocVect * discon_indices_
Definition: vrecitem.h:300
IvocVect * y_
Definition: vrecitem.h:298
IvocVect * t_
Definition: vrecitem.h:299
double(* c_)(Point_process *)
Definition: netcon.h:232
Point_process * pnt_
Definition: netcon.h:231
double nrflag_
Definition: netcon.h:230
int watch_index_
Definition: netcon.h:237
static Frame * fp
Definition: code.cpp:161
VEC * cgs(MTX_FN A, void *A_params, VEC *b, VEC *r0, double tol, VEC *x)
Definition: conjgrad.c:179
bool nrn_use_bin_queue_
Definition: netcvode.cpp:273
int secondorder
Definition: init.cpp:96
void clear_event_queue()
Definition: cvodestb.cpp:57
int nrn_is_ion(int)
Definition: eion.cpp:51
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)
DLFCN_NOINLINE DLFCN_EXPORT void * dlsym(void *handle, const char *name)
Definition: dlfcn.c:447
#define c
static int first
Definition: fmenu.cpp:190
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
double * hoc_val_pointer(const char *s)
Definition: code2.cpp:727
Symbol * hoc_lookup(const char *)
#define assert(ex)
Definition: hocassrt.h:32
#define ISARRAY(arg)
Definition: hocdec.h:164
#define USERDOUBLE
Definition: hocdec.h:93
#define VOIDITM(q)
Definition: hoclist.h:68
Symlist * hoc_built_in_symlist
Definition: ivocmac.cpp:76
int vector_capacity(Vect *v)
Definition: ivocvect.cpp:319
double * vector_vec(Vect *v)
Definition: ivocvect.cpp:328
#define nodeindices
Definition: md1redef.h:26
#define area
Definition: md1redef.h:5
#define v
Definition: md1redef.h:4
#define i
Definition: md1redef.h:12
#define pdata
Definition: md1redef.h:28
#define MORPHOLOGY
Definition: membfunc.h:63
#define ITERATE(itm, lst)
Definition: model.h:25
#define Fprintf
Definition: model.h:234
char * name
Definition: init.cpp:16
char * emalloc(unsigned n)
Definition: list.cpp:166
int nrn_nthread
Definition: multicore.cpp:46
NrnThread * nrn_threads
Definition: multicore.cpp:47
#define fprintf
Definition: mwprefix.h:30
#define NetParEventType
Definition: netcon.h:47
#define PreSynType
Definition: netcon.h:43
#define HocEventType
Definition: netcon.h:44
#define DiscreteEventType
Definition: netcon.h:39
#define SelfEventType
Definition: netcon.h:42
#define PlayRecordEventType
Definition: netcon.h:45
#define NetConType
Definition: netcon.h:41
void _nrn_watch_activate(Datum *, double(*)(Point_process *), int, Point_process *, int, double)
Definition: netcvode.cpp:2507
int * nrn_prop_param_size_
Definition: init.cpp:140
static List * info
short * nrn_is_artificial_
Definition: init.cpp:193
CellGroup * cellgroups_
void nrn2core_transfer_WatchCondition(WatchCondition *wc, void(*cb)(int, int, int, int, int))
getting one item at a time from nrn2core_transfer_WATCH
void nrnthread_group_ids(int *grp)
NrnCoreTransferEvents * nrn2core_transfer_tqueue(int tid)
int nrnthread_dat2_corepointer_mech(int tid, int type, int &icnt, int &dcnt, int *&iArray, double *&dArray)
void core2nrn_NetCon_event(int tid, double td, size_t nc_index)
Called from CoreNEURON core2nrn_tqueue_item.
int nrnthread_dat2_3(int tid, int nweight, int *&output_vindex, double *&output_threshold, int *&netcon_pnttype, int *&netcon_pntindex, double *&weights, double *&delays)
static void core2nrn_SelfEvent_helper(int tid, double td, int tar_type, int tar_index, double flag, double *weight, int is_movable)
void map_coreneuron_callbacks(void *handle)
Populate function pointers by mapping function pointers for callback.
void * get_global_dbl_item(void *p, const char *&name, int &size, double *&val)
void nrn2core_PreSyn_flag(int tid, std::set< int > &presyns_flag_true)
static std::map< int, int > type2movable
bool corenrn_direct
int nrnthread_dat2_1(int tid, int &ngid, int &n_real_gid, int &nnode, int &ndiam, int &nmech, int *&tml_index, int *&ml_nodecount, int &nidata, int &nvdata, int &nweight)
int * datum2int(int type, Memb_list *ml, NrnThread &nt, CellGroup &cg, DatumIndices &di, int ml_vdata_offset, std::vector< int > &pointer2type)
void core2nrn_SelfEvent_event(int tid, double td, int tar_type, int tar_index, double flag, size_t nc_index, int is_movable)
void part2_clean()
int nrnthread_dat2_vecplay(int tid, std::vector< int > &indices)
void core2nrn_SelfEvent_event_noweight(int tid, double td, int tar_type, int tar_index, double flag, int is_movable)
static void setup_type2semantics()
int nrnthread_dat2_vecplay_inst(int tid, int i, int &vptype, int &mtype, int &ix, int &sz, double *&yvec, double *&tvec, int &last_index, int &discon_index, int &ubound_index)
void core2nrn_vecplay_events()
start the vecplay events
void core2nrn_PreSyn_flag(int tid, std::set< int > presyns_flag_true)
void write_memb_mech_types_direct(std::ostream &s)
int nrnthread_dat2_mech(int tid, size_t i, int dsz_inst, int *&nodeindices, double *&data, int *&pdata, std::vector< int > &pointer2type)
int nrnthread_dat1(int tid, int &n_presyn, int &n_netcon, int *&output_gid, int *&netcon_srcgid, std::vector< int > &netcon_negsrcgid_tid)
void nrnthreads_all_weights_return(std::vector< double * > &weights)
Copy weights from all coreneuron::NrnThread to NetCon instances.
int * bbcore_dparam_size
void * nrn_patternstim_info_ref(Datum *)
int get_global_int_item(const char *name)
int nrnthread_dat2_corepointer(int tid, int &n)
void core2nrn_watch_activate(int tid, int type, int watch_begin, Core2NrnWatchInfo &wi)
char * pnt_map
Definition: init.cpp:128
void core2nrn_vecplay(int tid, int i, int last_index, int discon_index, int ubound_index)
getting one item at a time from CoreNEURON
int nrnthread_dat2_2(int tid, int *&v_parent_index, double *&a, double *&b, double *&area, double *&v, double *&diamvec)
#define NRN_SENTINAL
bbcore_write_t * nrn_bbcore_write_
Definition: init.cpp:152
int core2nrn_corepointer_mech(int tid, int type, int icnt, int dcnt, int *iArray, double *dArray)
static int patternstim_type
TQueue * net_cvode_instance_event_queue(NrnThread *)
Definition: netcvode.cpp:319
NetCvode * net_cvode_instance
Definition: cvodestb.cpp:27
size_t nrnthreads_type_return(int type, int tid, double *&data, double **&mdata)
Return location for CoreNEURON to copy data into.
void nrn2core_patternstim(void **info)
bbcore_write_t * nrn_bbcore_read_
Definition: init.cpp:153
double nrn_ion_charge(Symbol *)
Definition: eion.cpp:61
void * nrn_interthread_enqueue(NrnThread *)
Definition: netcvode.cpp:7051
void core2nrn_clear_queues(double time)
Initialize queues before transfer Probably aleady clear, but if binq then must be initialized to time...
static void set_info(TQItem *tqi, int tid, NrnCoreTransferEvents *core_te, std::unordered_map< NetCon *, std::vector< size_t >> &netcon2intdata, std::unordered_map< PreSyn *, std::vector< size_t >> &presyn2intdata, std::unordered_map< double *, std::vector< size_t >> &weight2intdata)
static core2nrn_callback_t cnbs[]
std::vector< Core2NrnWatchInfoItem > Core2NrnWatchInfo
@ i_membrane_
@ voltage
std::vector< std::pair< int, bool > > Core2NrnWatchInfoItem
double * contiguous_art_data(double **data, int nitem, int szitem)
Definition: nrncore_io.cpp:316
const char * bbcore_write_version
Definition: nrncore_io.cpp:25
int nrn_dblpntr2nrncore(double *pd, NrnThread &nt, int &type, int &index)
int const size_t const size_t n
Definition: nrngsl.h:11
size_t q
if(status)
size_t p
size_t j
void nrn_net_send(void **, double *, Point_process *, double, double)
int nrnmpi_myid
NrnWatchAllocateFunc_t * nrn_watch_allocate_
Definition: init.cpp:144
Memb_list * memb_list
Definition: init.cpp:124
void(*)(double *, int *, int *, int *, double *, Datum *, Datum *, NrnThread *) bbcore_write_t
Definition: init.cpp:151
int n_memb_func
Definition: init.cpp:440
uint32_t nrnran123_get_globalindex()
Definition: nrnran123.cpp:24
#define data
Definition: rbtqueue.cpp:49
int _nrnunit_use_legacy_
Definition: hoc_init.cpp:409
#define NULL
Definition: sptree.h:16
double * _nrn_sav_rhs
Definition: multicore.h:46
int nsub
Definition: hocdec.h:70
int sub[1]
Definition: hocdec.h:72
int * dparam_semantics
Definition: membfunc.h:56
Symbol * sym
Definition: membfunc.h:38
int nodecount
Definition: nrnoc_ml.h:18
double ** data
Definition: nrnoc_ml.h:14
Datum ** pdata
Definition: nrnoc_ml.h:15
Datum * _thread
Definition: nrnoc_ml.h:17
Definition: section.h:133
struct Prop * prop
Definition: section.h:152
std::vector< double > dbldata
std::vector< double > td
std::vector< int > intdata
std::vector< int > type
Represent main neuron object computed by single thread.
Definition: multicore.h:58
int * _v_parent_index
Definition: multicore.h:76
NrnThreadMembList * tml
Definition: multicore.h:62
int ncell
Definition: multicore.h:64
_nrn_Fast_Imem * _nrn_fast_imem
Definition: multicore.h:82
int id
Definition: multicore.h:66
int end
Definition: multicore.h:65
double * _actual_b
Definition: multicore.h:73
double * _actual_v
Definition: multicore.h:74
Memb_list ** _ml_list
Definition: multicore.h:63
double * _actual_a
Definition: multicore.h:72
Node ** _v_node
Definition: multicore.h:77
double _t
Definition: multicore.h:59
double * _actual_area
Definition: multicore.h:75
struct NrnThreadMembList * next
Definition: multicore.h:34
Definition: hocdec.h:227
void * this_pointer
Definition: hocdec.h:232
union Object::@39 u
void * _vnt
Definition: section.h:270
Prop * prop
Definition: section.h:265
Definition: section.h:214
Datum * dparam
Definition: section.h:220
double * param
Definition: section.h:219
short type
Definition: section.h:216
Definition: model.h:57
short type
Definition: model.h:58
long subtype
Definition: model.h:59
HocStruct Symbol * next
Definition: hocdec.h:162
union Symbol::@18 u
char * name
Definition: model.h:72
double * pval
Definition: hocdec.h:137
HocStruct cTemplate * ctemplate
Definition: hocdec.h:152
Arrayinfo * arayinfo
Definition: hocdec.h:159
HocStruct Symbol * first
Definition: hocdec.h:85
hoc_List * olist
Definition: hocdec.h:204
Definition: hocdec.h:177
void * _pvoid
Definition: hocdec.h:187
#define VecPlayContinuousType
Definition: vrecitem.h:22