NEURON
cell_group.cpp
Go to the documentation of this file.
1 #include "cell_group.h"
3 #include "nrnran123.h" // globalindex written to globals.dat
4 #include "section.h"
5 #include "parse.hpp"
6 #include "nrnmpi.h"
7 #include "netcon.h"
8 
9 #include <limits>
10 #include <sstream>
11 
12 extern short* nrn_is_artificial_;
13 extern bool corenrn_direct;
14 extern int* bbcore_dparam_size;
16 extern int nrn_has_net_event_cnt_;
17 extern int* nrn_has_net_event_;
18 extern short* nrn_is_artificial_;
19 
23 
26  group_id = -1;
28  netcons = 0;
29  output_ps = 0;
30  ndiam = 0;
32  datumindices = 0;
34  for (int i = 0; i < n_memb_func; ++i) {
35  type2ml[i] = 0;
36  }
38 }
39 
41  if (output_gid)
42  delete[] output_gid;
43  if (output_vindex)
44  delete[] output_vindex;
45  if (netcon_srcgid)
46  delete[] netcon_srcgid;
47  if (netcon_pnttype)
48  delete[] netcon_pnttype;
49  if (netcon_pntindex)
50  delete[] netcon_pntindex;
51  if (datumindices)
52  delete[] datumindices;
53  if (netcons)
54  delete[] netcons;
55  if (output_ps)
56  delete[] output_ps;
57  if (ml_vdata_offset)
58  delete[] ml_vdata_offset;
59  delete[] type2ml;
60 }
61 
62 
64  for (int i = 0; i < nrn_nthread; ++i) {
65  int ncell = nrn_threads[i].ncell; // real cell count
66  int npre = ncell;
67  MlWithArt& mla = cgs[i].mlwithart;
68  for (size_t j = 0; j < mla.size(); ++j) {
69  int type = mla[j].first;
70  Memb_list* ml = mla[j].second;
71  cgs[i].type2ml[type] = ml;
72  if (nrn_has_net_event(type)) {
73  npre += ml->nodecount;
74  }
75  }
76  cgs[i].n_presyn = npre;
77  cgs[i].n_real_output = ncell;
78  cgs[i].output_ps = new PreSyn*[npre];
79  cgs[i].output_gid = new int[npre];
80  cgs[i].output_vindex = new int[npre];
81  // in case some cells do not have voltage presyns (eg threshold detection
82  // computed from a POINT_PROCESS NET_RECEIVE with WATCH and net_event)
83  // initialize as unused.
84  for (int j = 0; j < npre; ++j) {
85  cgs[i].output_ps[j] = NULL;
86  cgs[i].output_gid[j] = -1;
87  cgs[i].output_vindex[j] = -1;
88  }
89 
90  // fill in the artcell info
91  npre = ncell;
92  cgs[i].n_output = ncell; // add artcell (and PP with net_event) with gid in following loop
93  for (size_t j = 0; j < mla.size(); ++j) {
94  int type = mla[j].first;
95  Memb_list* ml = mla[j].second;
96  if (nrn_has_net_event(type)) {
97  for (int j = 0; j < ml->nodecount; ++j) {
98  Point_process* pnt = (Point_process*) ml->pdata[j][1]._pvoid;
99  PreSyn* ps = (PreSyn*) pnt->presyn_;
100  cgs[i].output_ps[npre] = ps;
101  long agid = -1;
102  if (nrn_is_artificial_[type]) {
103  // static_cast<long> ensures the RHS is calculated with
104  // `long` precision, not `int` precision. This lets us
105  // check for overflow below.
106  agid = -(type +
107  1000 * static_cast<long>(nrncore_art2index(pnt->prop->param)));
108  } else { // POINT_PROCESS with net_event
109  int sz = nrn_prop_param_size_[type];
110  double* d1 = ml->data[0];
111  double* d2 = pnt->prop->param;
112  assert(d2 >= d1 && d2 < (d1 + (sz * ml->nodecount)));
113  long ix{(d2 - d1) / sz};
114  agid = -(type + 1000 * ix);
115  }
116  if (ps) {
117  if (ps->output_index_ >= 0) { // has gid
118  cgs[i].output_gid[npre] = ps->output_index_;
119  if (cgs[i].group_id < 0) {
120  cgs[i].group_id = ps->output_index_;
121  }
122  ++cgs[i].n_output;
123  } else {
124  cgs[i].output_gid[npre] = agid;
125  }
126  } else { // if an acell is never a source, it will not have a presyn
127  cgs[i].output_gid[npre] = -1;
128  }
129  // the way we associate an acell PreSyn with the
130  // Point_process.
131  if (agid < std::numeric_limits<int>::min() || agid >= -1) {
132  std::ostringstream oss;
133  oss << "maximum of ~" << std::numeric_limits<int>::max() / 1000
134  << " artificial cells of a given type can be created per NrnThread, "
135  "this model has "
136  << ml->nodecount << " instances of " << memb_func[type].sym->name
137  << " (cannot store cgs[" << i << "].output_vindex[" << npre
138  << "]=" << agid << ')';
139  hoc_execerror("integer overflow", oss.str().c_str());
140  }
141  cgs[i].output_vindex[npre] = agid;
142  ++npre;
143  }
144  }
145  }
146  }
147  // work at netpar.cpp because we don't have the output gid hash tables here.
148  // fill in the output_ps, output_gid, and output_vindex for the real cells.
150 
151  // use first real cell gid, if it exists, as the group_id
152  if (corenrn_direct == false)
153  for (int i = 0; i < nrn_nthread; ++i) {
154  if (cgs[i].n_real_output && cgs[i].output_gid[0] >= 0) {
155  cgs[i].group_id = cgs[i].output_gid[0];
156  } else if (cgs[i].group_id >= 0) {
157  // set above to first artificial cell with a ps->output_index >= 0
158  } else {
159  // Don't die yet as the thread may be empty. That just means no files
160  // output for this thread and no mention in files.dat.
161  // Can check for empty near end of datatransform(CellGroup* cgs)
162  }
163  }
164 
165  // use the Hoc NetCon object list to segregate according to threads
166  // and fill the CellGroup netcons, netcon_srcgid, netcon_pnttype, and
167  // netcon_pntindex (and, if nrn_nthread > 1, netcon_negsrcgid_tid).
169 
170  return cgs;
171 }
172 
174  // ions, area, and POINTER to v or mechanism data.
175  for (int ith = 0; ith < nrn_nthread; ++ith) {
176  NrnThread& nt = nrn_threads[ith];
177  CellGroup& cg = cgs[ith];
178  // how many mechanisms in use and how many DatumIndices do we need.
179  MlWithArt& mla = cgs[ith].mlwithart;
180  for (size_t j = 0; j < mla.size(); ++j) {
181  Memb_list* ml = mla[j].second;
182  ++cg.n_mech;
183  if (ml->pdata[0]) {
184  ++cg.ntype;
185  }
186  }
187  cg.datumindices = new DatumIndices[cg.ntype];
188  // specify type, allocate the space, and fill the indices
189  int i = 0;
190  for (size_t j = 0; j < mla.size(); ++j) {
191  int type = mla[j].first;
192  Memb_list* ml = mla[j].second;
193  int sz = bbcore_dparam_size[type];
194  if (sz) {
195  DatumIndices& di = cg.datumindices[i++];
196  di.type = type;
197  int n = ml->nodecount * sz;
198  di.ion_type = new int[n];
199  di.ion_index = new int[n];
200  // fill the indices.
201  // had tointroduce a memb_func[i].dparam_semantics registered by each mod file.
202  datumindex_fill(ith, cg, di, ml);
203  }
204  }
205  // if model is being transferred via files, and
206  // if there are no gids in the thread (group_id < 0), and
207  // if the thread is not empty (mechanisms exist, n_mech > 0)
208  if (corenrn_direct == false && cg.group_id < 0 && cg.n_mech > 0) {
209  hoc_execerror("A nonempty thread has no real cell or ARTIFICIAL_CELL with a gid", NULL);
210  }
211  }
212 }
213 
214 
216  NrnThread& nt = nrn_threads[ith];
217  double* a = nt._actual_area;
218  int nnode = nt.end;
219  int mcnt = ml->nodecount;
220  int dsize = bbcore_dparam_size[di.type];
221  if (dsize == 0) {
222  return;
223  }
224  int* dmap = memb_func[di.type].dparam_semantics;
225  assert(dmap);
226  // what is the size of the nt._vdata portion needed for a single ml->dparam[i]
227  int vdata_size = 0;
228  for (int i = 0; i < dsize; ++i) {
229  int* ds = memb_func[di.type].dparam_semantics;
230  if (ds[i] == -4 || ds[i] == -6 || ds[i] == -7 || ds[i] == 0) {
231  ++vdata_size;
232  }
233  }
234 
235  int isart = nrn_is_artificial_[di.type];
236  for (int i = 0; i < mcnt; ++i) {
237  // Prop* datum instance arrays are not in cache efficient order
238  // ie. ml->pdata[i] are not laid out end to end in memory.
239  // Also, ml->data for artificial cells is not in cache efficient order
240  // but in the artcell case there are no pointers to doubles and
241  // the _actual_area pointer should be left unfilled.
242  Datum* dparam = ml->pdata[i];
243  int offset = i * dsize;
244  int vdata_offset = i * vdata_size;
245  for (int j = 0; j < dsize; ++j) {
246  int etype = -100; // uninterpreted
247  int eindex = -1;
248  if (dmap[j] == -1) { // double* into _actual_area
249  if (isart) {
250  etype = -1;
251  eindex = -1; // the signal to ignore in bbcore.
252  } else {
253  if (dparam[j].pval == &ml->nodelist[i]->_area) {
254  // possibility it points directly into Node._area instead of
255  // _actual_area. For our purposes we need to figure out the
256  // _actual_area index.
257  etype = -1;
258  eindex = ml->nodeindices[i];
259  assert(a[ml->nodeindices[i]] == *dparam[j].pval);
260  } else {
261  if (dparam[j].pval < a || dparam[j].pval >= (a + nnode)) {
262  printf("%s dparam=%p a=%p a+nnode=%p j=%d\n",
263  memb_func[di.type].sym->name,
264  dparam[j].pval,
265  a,
266  a + nnode,
267  j);
268  abort();
269  }
270  assert(dparam[j].pval >= a && dparam[j].pval < (a + nnode));
271  etype = -1;
272  eindex = dparam[j].pval - a;
273  }
274  }
275  } else if (dmap[j] == -2) { // this is an ion and dparam[j][0].i is the iontype
276  etype = -2;
277  eindex = dparam[j].i;
278  } else if (dmap[j] == -3) { // cvodeieq is always last and never seen
279  assert(dmap[j] != -3);
280  } else if (dmap[j] == -4) { // netsend (_tqitem pointer)
281  // eventually index into nt->_vdata
282  etype = -4;
283  eindex = vdata_offset++;
284  } else if (dmap[j] == -6) { // pntproc
285  // eventually index into nt->_vdata
286  etype = -6;
287  eindex = vdata_offset++;
288  } else if (dmap[j] == -7) { // bbcorepointer
289  // eventually index into nt->_vdata
290  etype = -6;
291  eindex = vdata_offset++;
292  } else if (dmap[j] == -8) { // watch
293  etype = -8;
294  eindex = 0;
295  } else if (dmap[j] == -10) { // fornetcon
296  etype = -10;
297  eindex = 0;
298  } else if (dmap[j] == -9) { // diam
299  cg.ndiam = nt.end;
300  etype = -9;
301  // Rare for a mechanism to use dparam pointing to diam.
302  // MORPHOLOGY was never made cache efficient. And
303  // is not in the tml_with_art.
304  // Need to determine this node and then simple to search its
305  // mechanism list for MORPHOLOGY and then know the diam.
306  Node* nd = ml->nodelist[i];
307  double* pdiam = NULL;
308  for (Prop* p = nd->prop; p; p = p->next) {
309  if (p->type == MORPHOLOGY) {
310  pdiam = p->param;
311  break;
312  }
313  }
314  assert(dparam[j].pval == pdiam);
315  eindex = ml->nodeindices[i];
316  } else if (dmap[j] == -5) { // POINTER
317  // must be a pointer into nt->_data. Handling is similar to eion so
318  // give proper index into the type.
319  double* pd = dparam[j].pval;
320  nrn_dblpntr2nrncore(pd, nt, etype, eindex);
321  if (etype == 0) {
322  fprintf(stderr,
323  "POINTER is not pointing to voltage or mechanism data. Perhaps it "
324  "should be a BBCOREPOINTER\n");
325  }
326  assert(etype != 0);
327  // pointer into one of the tml types?
328  } else if (dmap[j] > 0 && dmap[j] < 1000) { // double* into eion type data
329  Memb_list* eml = cg.type2ml[dmap[j]];
330  assert(eml);
331  if (dparam[j].pval < eml->data[0]) {
332  printf("%s dparam=%p data=%p j=%d etype=%d %s\n",
333  memb_func[di.type].sym->name,
334  dparam[j].pval,
335  eml->data[0],
336  j,
337  dmap[j],
338  memb_func[dmap[j]].sym->name);
339  abort();
340  }
341  assert(dparam[j].pval >= eml->data[0]);
342  etype = dmap[j];
343  if (dparam[j].pval >=
344  (eml->data[0] + (nrn_prop_param_size_[etype] * eml->nodecount))) {
345  printf("%s dparam=%p data=%p j=%d psize=%d nodecount=%d etype=%d %s\n",
346  memb_func[di.type].sym->name,
347  dparam[j].pval,
348  eml->data[0],
349  j,
350  nrn_prop_param_size_[etype],
351  eml->nodecount,
352  etype,
353  memb_func[etype].sym->name);
354  }
355  assert(dparam[j].pval <
356  (eml->data[0] + (nrn_prop_param_size_[etype] * eml->nodecount)));
357  eindex = dparam[j].pval - eml->data[0];
358  } else if (dmap[j] > 1000) { // int* into ion dparam[xxx][0]
359  // store the actual ionstyle
360  etype = dmap[j];
361  eindex = *((int*) dparam[j]._pvoid);
362  } else {
363  char errmes[100];
364  sprintf(errmes, "Unknown semantics type %d for dparam item %d of", dmap[j], j);
365  hoc_execerror(errmes, memb_func[di.type].sym->name);
366  }
367  di.ion_type[offset + j] = etype;
368  di.ion_index[offset + j] = eindex;
369  }
370  }
371 }
372 
373 
374 // use the Hoc NetCon object list to segregate according to threads
375 // and fill the CellGroup netcons, netcon_srcgid, netcon_pnttype, and
376 // netcon_pntindex (called at end of mk_cellgroups);
378  // count the netcons for each thread
379  int* nccnt = new int[nrn_nthread];
380  for (int i = 0; i < nrn_nthread; ++i) {
381  nccnt[i] = 0;
382  }
383  Symbol* ncsym = hoc_lookup("NetCon");
384  hoc_List* ncl = ncsym->u.ctemplate->olist;
385  hoc_Item* q;
386  ITERATE(q, ncl) {
387  Object* ho = (Object*) VOIDITM(q);
388  NetCon* nc = (NetCon*) ho->u.this_pointer;
389  int ith = 0; // if no _vnt, put in thread 0
390  if (nc->target_ && nc->target_->_vnt) {
391  ith = ((NrnThread*) (nc->target_->_vnt))->id;
392  }
393  ++nccnt[ith];
394  }
395 
396  // allocate
397  for (int i = 0; i < nrn_nthread; ++i) {
398  cgs[i].n_netcon = nccnt[i];
399  cgs[i].netcons = new NetCon*[nccnt[i] + 1];
400  cgs[i].netcon_srcgid = new int[nccnt[i] + 1];
401  cgs[i].netcon_pnttype = new int[nccnt[i] + 1];
402  cgs[i].netcon_pntindex = new int[nccnt[i] + 1];
403  }
404 
405  // reset counts and fill
406  for (int i = 0; i < nrn_nthread; ++i) {
407  nccnt[i] = 0;
408  }
409  ITERATE(q, ncl) {
410  Object* ho = (Object*) VOIDITM(q);
411  NetCon* nc = (NetCon*) ho->u.this_pointer;
412  int ith = 0; // if no _vnt, put in thread 0
413  if (nc->target_ && nc->target_->_vnt) {
414  ith = ((NrnThread*) (nc->target_->_vnt))->id;
415  }
416  int i = nccnt[ith];
417  cgs[ith].netcons[i] = nc;
418 
419  if (nc->target_) {
420  int type = nc->target_->prop->type;
421  cgs[ith].netcon_pnttype[i] = type;
422  if (nrn_is_artificial_[type]) {
423  cgs[ith].netcon_pntindex[i] = nrncore_art2index(nc->target_->prop->param);
424  } else {
425  // cache efficient so can calculate index from pointer
426  Memb_list* ml = cgs[ith].type2ml[type];
427  int sz = nrn_prop_param_size_[type];
428  double* d1 = ml->data[0];
429  double* d2 = nc->target_->prop->param;
430  assert(d2 >= d1 && d2 < (d1 + (sz * ml->nodecount)));
431  int ix = (d2 - d1) / sz;
432  cgs[ith].netcon_pntindex[i] = ix;
433  }
434  } else {
435  cgs[ith].netcon_pnttype[i] = 0;
436  cgs[ith].netcon_pntindex[i] = -1;
437  }
438 
439  if (nc->src_) {
440  PreSyn* ps = nc->src_;
441  if (ps->gid_ >= 0) {
442  cgs[ith].netcon_srcgid[i] = ps->gid_;
443  } else {
444  if (ps->osrc_) {
445  assert(ps->thvar_ == NULL);
446  if (nrn_nthread > 1) { // negative gid and multiple threads.
447  cgs[ith].netcon_negsrcgid_tid.push_back(ps->nt_->id);
448  // Raise error if file mode transfer and nc and ps not
449  // in same thread. In that case we cannot guarantee that
450  // the PreSyn will end up in the same coreneuron process.
451  if (!corenrn_direct && ith != ps->nt_->id) {
453  "NetCon and NetCon source with no gid are not in the same thread",
454  NULL);
455  }
456  }
458  int type = pnt->prop->type;
460  int ix = nrncore_art2index(pnt->prop->param);
461  cgs[ith].netcon_srcgid[i] = -(type + 1000 * ix);
462  } else {
464  Memb_list* ml = cgs[ith].type2ml[type];
465  int sz = nrn_prop_param_size_[type];
466  double* d1 = ml->data[0];
467  double* d2 = pnt->prop->param;
468  assert(d2 >= d1 && d2 < (d1 + (sz * ml->nodecount)));
469  int ix = (d2 - d1) / sz;
470  cgs[ith].netcon_srcgid[i] = -(type + 1000 * ix);
471  }
472  } else {
473  cgs[ith].netcon_srcgid[i] = -1;
474  }
475  }
476  } else {
477  cgs[ith].netcon_srcgid[i] = -1;
478  }
479  ++nccnt[ith];
480  }
481  delete[] nccnt;
482 }
483 
484 
485 // Up to now all the artificial cells have been left out of the processing.
486 // Since most processing is in the context of iteration over nt.tml it
487 // might be easiest to transform the loops using a
488 // copy of nt.tml with artificial cell types belonging to nt at the end.
489 // Treat these artificial cell memb_list as much as possible like the others.
490 // The only issue is that data for artificial cells is not in cache order
491 // (after all there is no BREAKPOINT or SOLVE block for ARTIFICIAL_CELLs)
492 // so we assume there will be no POINTER usage into that data.
493 // Also, note that ml.nodecount for artificial cell does not refer to
494 // a list of voltage nodes but just to the count of instances.
496  // copy NrnThread tml list and append ARTIFICIAL cell types
497  // but do not include PatternStim if file mode.
498  // For direct mode PatternStim is not treated specially except that
499  // the Info struct is shared.
500  // For file mode transfer PatternStim has always been treated
501  // specially by CoreNEURON as it is not conceptually a part of
502  // the model but is invoked via an argument when launching
503  // CoreNEURON from the shell.
504  // Now using cgs[tid].mlwithart instead of
505  // tml_with_art = new NrnThreadMembList*[nrn_nthread];
506  // to allow fast retrieval of type and Memb_list* given index into the vector.
507 
508  // copy from NrnThread
509  for (int id = 0; id < nrn_nthread; ++id) {
510  MlWithArt& mla = cgs[id].mlwithart;
511  for (NrnThreadMembList* tml = nrn_threads[id].tml; tml; tml = tml->next) {
512  mla.push_back(MlWithArtItem(tml->index, tml->ml));
513  }
514  }
515  int* acnt = new int[nrn_nthread];
516 
517  for (int i = 0; i < n_memb_func; ++i) {
519  // skip PatternStim if file mode transfer.
520  if (!corenrn_direct && strcmp(memb_func[i].sym->name, "PatternStim") == 0) {
521  continue;
522  }
523  if (strcmp(memb_func[i].sym->name, "HDF5Reader") == 0) {
524  continue;
525  }
526  Memb_list* ml = memb_list + i;
527  // how many artificial in each thread
528  for (int id = 0; id < nrn_nthread; ++id) {
529  acnt[id] = 0;
530  }
531  for (int j = 0; j < memb_list[i].nodecount; ++j) {
532  Point_process* pnt = (Point_process*) memb_list[i].pdata[j][1]._pvoid;
533  int id = ((NrnThread*) pnt->_vnt)->id;
534  ++acnt[id];
535  }
536 
537  // allocate
538  for (int id = 0; id < nrn_nthread; ++id) {
539  if (acnt[id]) {
540  MlWithArt& mla = cgs[id].mlwithart;
541  ml = new Memb_list;
542  mla.push_back(MlWithArtItem(i, ml)); // need to delete ml when mla destroyed.
543  ml->nodecount = acnt[id];
544  ml->nodelist = NULL;
545  ml->nodeindices = NULL;
546  ml->prop = NULL;
547  ml->_thread = NULL;
548  ml->data = new double*[acnt[id]];
549  ml->pdata = new Datum*[acnt[id]];
550  }
551  }
552  // fill data and pdata pointers
553  // and fill the artdata2index hash table
554  for (int id = 0; id < nrn_nthread; ++id) {
555  acnt[id] = 0;
556  }
557  for (int j = 0; j < memb_list[i].nodecount; ++j) {
558  Point_process* pnt = (Point_process*) memb_list[i].pdata[j][1]._pvoid;
559  int id = ((NrnThread*) pnt->_vnt)->id;
560  Memb_list* ml = cgs[id].mlwithart.back().second;
561  ml->data[acnt[id]] = memb_list[i].data[j];
562  ml->pdata[acnt[id]] = memb_list[i].pdata[j];
563  artdata2index_.insert(std::pair<double*, int>(ml->data[acnt[id]], acnt[id]));
564  ++acnt[id];
565  }
566  }
567  }
568  delete[] acnt;
569 }
570 
572  size_t mla_rankbytes = 0;
573  size_t nbytes;
574  NrnThread* nt;
575  NrnThreadMembList* tml;
576  FOR_THREADS(nt) {
577  size_t threadbytes = 0;
578  size_t npnt = 0;
579  size_t nart = 0;
580  int ith = nt->id;
581  // printf("rank %d thread %d\n", nrnmpi_myid, ith);
582  // printf(" ncell=%d nnode=%d\n", nt->ncell, nt->end);
583  // v_parent_index, _actual_a, _actual_b, _actual_area
584  nbytes = nt->end * (1 * sizeof(int) + 3 * sizeof(double));
585  threadbytes += nbytes;
586 
587  int mechcnt = 0;
588  size_t mechcnt_instances = 0;
589  MlWithArt& mla = cellgroups_[ith].mlwithart;
590  for (size_t i = 0; i < mla.size(); ++i) {
591  int type = mla[i].first;
592  Memb_list* ml = mla[i].second;
593  ++mechcnt;
594  mechcnt_instances += ml->nodecount;
595  npnt += (memb_func[type].is_point ? ml->nodecount : 0);
596  int psize = nrn_prop_param_size_[type];
597  int dpsize = nrn_prop_dparam_size_[type]; // includes cvodeieq if present
598  // printf("%d %s ispnt %d cnt %d psize %d dpsize %d\n",tml->index,
599  // memb_func[type].sym->name, memb_func[type].is_point, ml->nodecount, psize, dpsize);
600  // nodeindices, data, pdata + pnt with prop
601  int notart = nrn_is_artificial_[type] ? 0 : 1;
602  if (nrn_is_artificial_[type]) {
603  nart += ml->nodecount;
604  }
605  nbytes = ml->nodecount *
606  (notart * sizeof(int) + 1 * sizeof(double*) + 1 * sizeof(Datum*) +
607  psize * sizeof(double) + dpsize * sizeof(Datum));
608  threadbytes += nbytes;
609  }
610  nbytes += npnt * (sizeof(Point_process) + sizeof(Prop));
611  // printf(" mech in use %d Point instances %ld artcells %ld total instances %ld\n",
612  // mechcnt, npnt, nart, mechcnt_instances);
613  // printf(" thread bytes %ld\n", threadbytes);
614  mla_rankbytes += threadbytes;
615  }
616  return mla_rankbytes;
617 }
618 
620  // clean up the art Memb_list of CellGroup[].mlwithart
621  // But if multithread and direct transfer mode, defer deletion of
622  // data for artificial cells, so that the artificial cell ml->data
623  // can be used when nrnthreads_type_return is called.
624  if (corenrn_direct && nrn_nthread > 0) {
626  }
627  for (int ith = 0; ith < nrn_nthread; ++ith) {
628  MlWithArt& mla = cgs[ith].mlwithart;
629  for (size_t i = 0; i < mla.size(); ++i) {
630  int type = mla[i].first;
631  Memb_list* ml = mla[i].second;
632  if (nrn_is_artificial_[type]) {
633  if (!deferred_type2artml_.empty()) {
634  deferred_type2artml_[ith][type] = ml;
635  } else {
636  delete[] ml->data;
637  delete[] ml->pdata;
638  delete ml;
639  }
640  }
641  }
642  }
643 }
644 
646  if (has_net_event_) {
647  return;
648  }
649 
650  has_net_event_ = new int[n_memb_func];
651  for (int i = 0; i < n_memb_func; ++i) {
652  has_net_event_[i] = 0;
653  }
654  for (int i = 0; i < nrn_has_net_event_cnt_; ++i) {
656  }
657 }
Memb_func * memb_func
Definition: init.cpp:123
short type
Definition: cabvars.h:9
short * nrn_is_artificial_
Definition: cell_group.cpp:18
bool corenrn_direct
int nrn_has_net_event_cnt_
Definition: init.cpp:138
int * bbcore_dparam_size
int * nrn_has_net_event_
Definition: init.cpp:139
void nrncore_netpar_cellgroups_helper(CellGroup *)
Definition: netpar.cpp:1658
std::vector< std::map< int, Memb_list * > > Deferred_Type2ArtMl
Definition: cell_group.h:18
std::vector< MlWithArtItem > MlWithArt
Definition: cell_group.h:16
std::pair< int, Memb_list * > MlWithArtItem
Definition: cell_group.h:13
std::map< double *, int > PVoid2Int
Definition: cell_group.h:17
int group_id
Definition: cell_group.h:25
int n_real_output
Definition: cell_group.h:29
static void mk_cgs_netcon_info(CellGroup *cgs)
Definition: cell_group.cpp:377
int * ml_vdata_offset
Definition: cell_group.h:32
static PVoid2Int artdata2index_
Definition: cell_group.h:87
int n_mech
Definition: cell_group.h:31
int * output_vindex
Definition: cell_group.h:36
NetCon ** netcons
Definition: cell_group.h:39
static int * has_net_event_
Definition: cell_group.h:89
int * netcon_srcgid
Definition: cell_group.h:40
virtual ~CellGroup()
Definition: cell_group.cpp:40
static CellGroup * mk_cellgroups(CellGroup *)
Definition: cell_group.cpp:63
static int nrn_has_net_event(int type)
Definition: cell_group.h:96
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
static void datumindex_fill(int, CellGroup &, DatumIndices &, Memb_list *)
Definition: cell_group.cpp:215
int ntype
Definition: cell_group.h:48
PreSyn ** output_ps
Definition: cell_group.h:34
int n_presyn
Definition: cell_group.h:27
static void mk_tml_with_art(CellGroup *)
Definition: cell_group.cpp:495
MlWithArt mlwithart
Definition: cell_group.h:50
static void setup_nrn_has_net_event()
Definition: cell_group.cpp:645
static size_t get_mla_rankbytes(CellGroup *)
Definition: cell_group.cpp:571
static void datumtransform(CellGroup *)
Definition: cell_group.cpp:173
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
static int nrncore_art2index(double *d)
Definition: cell_group.h:91
DatumIndices * datumindices
Definition: cell_group.h:49
int n_output
Definition: cell_group.h:28
int ndiam
Definition: cell_group.h:30
Definition: netcon.h:83
Point_process * target_
Definition: netcon.h:111
PreSyn * src_
Definition: netcon.h:110
Definition: netcon.h:255
double * thvar_
Definition: netcon.h:294
NrnThread * nt_
Definition: netcon.h:300
int gid_
Definition: netcon.h:307
Object * osrc_
Definition: netcon.h:295
VEC * cgs(MTX_FN A, void *A_params, VEC *b, VEC *r0, double tol, VEC *x)
Definition: conjgrad.c:179
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)
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
Symbol * hoc_lookup(const char *)
#define assert(ex)
Definition: hocassrt.h:32
union Datum Datum
#define VOIDITM(q)
Definition: hoclist.h:68
#define min(a, b)
Definition: matrix.h:157
#define max(a, b)
Definition: matrix.h:154
#define pval
Definition: md1redef.h:32
#define nodecount
Definition: md1redef.h:30
#define id
Definition: md1redef.h:33
#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
int nrn_nthread
Definition: multicore.cpp:46
NrnThread * nrn_threads
Definition: multicore.cpp:47
#define FOR_THREADS(nt)
Definition: multicore.h:104
#define printf
Definition: mwprefix.h:26
#define fprintf
Definition: mwprefix.h:30
int * nrn_prop_param_size_
Definition: init.cpp:140
CellGroup * cellgroups_
int nrn_dblpntr2nrncore(double *pd, NrnThread &nt, int &type, int &index)
int * nrn_prop_dparam_size_
Definition: init.cpp:141
int const size_t const size_t n
Definition: nrngsl.h:11
size_t q
if(status)
size_t p
size_t j
Memb_list * memb_list
Definition: init.cpp:124
int n_memb_func
Definition: init.cpp:440
struct Memb_list Memb_list
#define data
Definition: rbtqueue.cpp:49
struct Point_process Point_process
#define NULL
Definition: sptree.h:16
int * dparam_semantics
Definition: membfunc.h:56
int is_point
Definition: membfunc.h:53
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
double _area
Definition: section.h:141
struct Prop * prop
Definition: section.h:152
Represent main neuron object computed by single thread.
Definition: multicore.h:58
int ncell
Definition: multicore.h:64
int id
Definition: multicore.h:66
int end
Definition: multicore.h:65
double * _actual_area
Definition: multicore.h:75
Definition: hocdec.h:227
void * this_pointer
Definition: hocdec.h:232
union Object::@39 u
void * presyn_
Definition: section.h:268
void * _vnt
Definition: section.h:270
Prop * prop
Definition: section.h:265
Definition: section.h:214
double * param
Definition: section.h:219
short type
Definition: section.h:216
Definition: model.h:57
union Symbol::@18 u
char * name
Definition: model.h:72
HocStruct cTemplate * ctemplate
Definition: hocdec.h:152
hoc_List * olist
Definition: hocdec.h:204
Definition: hocdec.h:177
double * pval
Definition: hocdec.h:181
void * _pvoid
Definition: hocdec.h:187
int i
Definition: hocdec.h:180