NEURON
rxd.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <stdio.h>
3 #include <assert.h>
4 #include <string.h>
5 #include "grids.h"
6 #include "rxd.h"
7 #include <../nrnoc/section.h>
8 #include <../nrnoc/nrn_ansi.h>
9 #include <../nrnoc/multicore.h>
10 #include <nrnwrap_Python.h>
11 #include <nrnpython.h>
12 
13 static void ode_solve(double, double*, double*);
14 extern PyTypeObject* hocobject_type;
15 extern int structure_change_cnt;
16 extern int states_cvode_offset;
17 extern int _nrnunit_use_legacy_;
20 unsigned char initialized = FALSE;
21 
22 /*
23  Globals
24 */
25 extern NrnThread* nrn_threads;
26 int NUM_THREADS = 1;
27 pthread_t* Threads = NULL;
29 
30 
31 extern double *dt_ptr;
32 extern double *t_ptr;
33 
34 
37 
38 /*intracellular diffusion*/
39 unsigned char diffusion = FALSE;
45 double* _rxd_a = NULL;
46 double* _rxd_b = NULL;
47 double* _rxd_c = NULL;
48 double* _rxd_d = NULL;
49 long* _rxd_p = NULL;
50 unsigned int* _rxd_zvi_child_count = NULL;
52 static int _cvode_offset;
53 static int _ecs_count;
54 
55 /*intracellular reactions*/
57 
58 /*Indices used to set atol scale*/
60 
61 /*intracellular reactions*/
62 double* states;
63 unsigned int num_states=0;
67 double* _curr_scales = NULL;
68 double** _curr_ptrs = NULL;
71 double** _conc_ptrs = NULL;
72 
73 /*membrane fluxes*/
74 int _memb_curr_total = 0; /*number of membrane currents (sum of
75  _memb_species_count)*/
76 int _memb_curr_nodes = 0; /*corresponding number of nodes
77  equal to _memb_curr_total if Extracellular is not used*/
78 int _memb_count = 0; /*number of membrane currents*/
79 double* _rxd_flux_scale; /*array length _memb_count to scale fluxes*/
80 double* _rxd_induced_currents_scale; /*array of Extracellular current scales*/
81 int* _cur_node_indices; /*array length _memb_count into nodes index*/
82 
83 
84 int* _memb_species_count; /*array of length _memb_count
85  number of species involved in each membrane
86  current*/
87 
88 /*arrays of size _memb_count by _memb_species_count*/
89 double*** _memb_cur_ptrs; /*hoc pointers TODO: replace with index for _curr_ptrs*/
91 int*** _memb_cur_mapped; /*array of pairs of indices*/
92 int*** _memb_cur_mapped_ecs; /*array of pointer into ECS grids*/
93 
94 double* _rxd_induced_currents = NULL; /*set when calculating reactions*/
96 
97 unsigned char _membrane_flux = FALSE; /*TRUE if any membrane fluxes are in the model*/
98 int* _membrane_lookup; /*states index -> position in _rxd_induced_currents*/
99 
103 PyObject** _node_flux_src = NULL;
104 
105 static void free_zvi_child()
106 {
107  int i;
108  /*Clear previous _rxd_zvi_child*/
110  {
111  for(i = 0; i < _rxd_num_zvi; i++)
112  if(_rxd_zvi_child_count[i]>0) free(_rxd_zvi_child[i]);
113  free(_rxd_zvi_child);
114  free(_rxd_zvi_child_count);
117  }
118 }
119 
120 static void transfer_to_legacy()
121 {
122  /*TODO: support 3D*/
123  int i;
124  for(i = 0; i < _conc_count; i++)
125  {
126  *(double*)_conc_ptrs[i] = states[_conc_indices[i]];
127  }
128 }
129 
130 static inline void* allocopy(void* src, size_t size)
131 {
132  void* dst = malloc(size);
133  memcpy(dst, src, size);
134  return dst;
135 }
136 
137 extern "C" void rxd_set_no_diffusion()
138 {
139  int i;
140  diffusion = FALSE;
141  if(_rxd_a != NULL)
142  {
143  free(_rxd_a);
144  free(_rxd_b);
145  free(_rxd_c);
146  free(_rxd_d);
147  free(_rxd_p);
148  free(_rxd_euler_nonzero_i);
149  free(_rxd_euler_nonzero_j);
151  _rxd_a = NULL;
152  }
153 }
154 
155 extern "C" void free_curr_ptrs()
156 {
157  _curr_count = 0;
158  if(_curr_indices != NULL)
159  free(_curr_indices);
161  if(_curr_scales != NULL)
162  free(_curr_scales);
163  _curr_scales = NULL;
164  if(_curr_ptrs != NULL)
165  free(_curr_ptrs);
166  _curr_ptrs = NULL;
167 }
168 
169 extern "C" void free_conc_ptrs()
170 {
171  _conc_count = 0;
172  if(_conc_indices != NULL)
173  free(_conc_indices);
175  if(_conc_ptrs != NULL)
176  free(_conc_ptrs);
177  _conc_ptrs = NULL;
178 }
179 
180 
181 extern "C" void rxd_setup_curr_ptrs(int num_currents, int* curr_index, double* curr_scale,
182  PyHocObject** curr_ptrs)
183 {
184  int i;
185  free_curr_ptrs();
186  /* info for NEURON currents - to update states */
187  _curr_count = num_currents;
188  _curr_indices = (int*)malloc(sizeof(int)*num_currents);
189  memcpy(_curr_indices,curr_index, sizeof(int)*num_currents);
190 
191  _curr_scales = (double*)malloc(sizeof(double)*num_currents);
192  memcpy(_curr_scales, curr_scale, sizeof(double)*num_currents);
193 
194  _curr_ptrs = (double**)malloc(sizeof(double*)*num_currents);
195  for(i = 0; i < num_currents; i++)
196  _curr_ptrs[i] = (double*)curr_ptrs[i]->u.px_;
197 }
198 
199 extern "C" void rxd_setup_conc_ptrs(int conc_count, int* conc_index,
200  PyHocObject** conc_ptrs)
201 {
202  /* info for NEURON concentration - to transfer to legacy */
203  int i;
204  free_conc_ptrs();
205  _conc_count = conc_count;
206  _conc_indices = (int*)malloc(sizeof(int)*conc_count);
207  memcpy(_conc_indices, conc_index, sizeof(int)*conc_count);
208 
209  _conc_ptrs = (double**)malloc(sizeof(double*)*conc_count);
210  for(i = 0; i < conc_count; i++)
211  _conc_ptrs[i] = (double*)conc_ptrs[i]->u.px_;
212 }
213 
214 extern "C" void rxd_include_node_flux3D(int grid_count, int* grid_counts,
215  int* grids, long* index, double* scales,
216  PyObject** sources)
217 {
218  Grid_node* g;
219  int i = 0, j, k, n, grid_id;
220  int offset = 0;
221 
222  for(g = Parallel_grids[0]; g != NULL; g = g->next)
223  {
224  if(g->node_flux_count > 0)
225  {
226  g->node_flux_count = 0;
227  free(g->node_flux_scale);
228  free(g->node_flux_idx);
229  free(g->node_flux_src);
230  }
231  }
232  if(grid_count == 0)
233  return;
234  for(grid_id=0, g = Parallel_grids[0]; g != NULL; grid_id++, g = g->next)
235  {
236 #if NRNMPI
237  if(nrnmpi_use && dynamic_cast<ECS_Grid_node*>(g))
238  {
239  if (grid_id == grids[i])
240  n = grid_counts[i++];
241  else
242  n = 0;
243 
244  g->proc_num_fluxes[nrnmpi_myid] = n;
245  nrnmpi_int_allgather_inplace(g->proc_num_fluxes, 1);
246 
247  g->proc_flux_offsets[0] = 0;
248  for(j = 1; j < nrnmpi_numprocs; j++)
249  g->proc_flux_offsets[j] = g->proc_flux_offsets[j-1] +
250  g->proc_num_fluxes[j-1];
251  g->node_flux_count = g->proc_flux_offsets[j-1] + g->proc_num_fluxes[j-1];
252  /*Copy array of the indexes and scales -- sources are evaluated at runtime*/
253  if(n > 0)
254  {
255  g->node_flux_idx = (long*)malloc(g->node_flux_count*sizeof(long));
256  g->node_flux_scale = (double*)malloc(g->node_flux_count*sizeof(double));
257  g->node_flux_src = (PyObject**)allocopy(&sources[offset], n*sizeof(PyObject*));
258  }
259 
260  for(j = 0, k = g->proc_flux_offsets[nrnmpi_myid]; j < n; j++, k++)
261  {
262  g->node_flux_idx[k] = index[offset + j];
263  g->node_flux_scale[k] = scales[offset + j];
264  }
265  nrnmpi_long_allgatherv_inplace(g->node_flux_idx, g->proc_num_fluxes, g->proc_flux_offsets);
266  nrnmpi_dbl_allgatherv_inplace(g->node_flux_scale, g->proc_num_fluxes, g->proc_flux_offsets);
267 
268  offset += n;
269  }
270  else
271  {
272  if(grid_id == grids[i])
273  {
274  g->node_flux_count = grid_counts[i];
275  if(grid_counts[i] > 0)
276  {
277  g->node_flux_idx = (long*)allocopy(&index[offset], grid_counts[i]*sizeof(long));
278  g->node_flux_scale = (double*)allocopy(&scales[offset], grid_counts[i]*sizeof(double));
279  g->node_flux_src = (PyObject**)allocopy(&sources[offset], grid_counts[i]*sizeof(PyObject*));
280  }
281  offset += grid_counts[i++];
282  }
283  }
284 #else
285  if(grid_id == grids[i])
286  {
287  g->node_flux_count = grid_counts[i];
288  if(grid_counts[i] > 0)
289  {
290  g->node_flux_idx = (long*)allocopy(&index[offset], grid_counts[i]*sizeof(long));
291  g->node_flux_scale = (double*)allocopy(&scales[offset], grid_counts[i]*sizeof(double));
292  g->node_flux_src = (PyObject**)allocopy(&sources[offset], grid_counts[i]*sizeof(PyObject*));
293  }
294  offset += grid_counts[i++];
295 
296  }
297 #endif
298  }
299 }
300 
301 extern "C" void rxd_include_node_flux1D(int n, long* index, double* scales,
302  PyObject** sources)
303 {
304  if (_node_flux_count != 0)
305  {
306  free(_node_flux_idx);
307  free(_node_flux_scale);
308  free(_node_flux_src);
309  }
311  if (n > 0)
312  {
313  _node_flux_idx = (long*)allocopy(index, n*sizeof(long)*n);
314  _node_flux_scale = (double*)allocopy(scales, n*sizeof(double));
315  _node_flux_src = (PyObject**)allocopy(sources, n*sizeof(PyObject*));
316  }
317 }
318 
319 
320 
321 void apply_node_flux(int n, long* index, double* scale, PyObject** source, double dt, double* states)
322 {
323  long i, j;
324  PyObject *result;
325  PyHocObject *src;
326 
327  for(i = 0; i < n; i++)
328  {
329  if(index == NULL)
330  j = i;
331  else
332  j = index[i];
333  if(PyFloat_Check(source[i]))
334  {
335  states[j] += dt * PyFloat_AsDouble(source[i]) / scale[i];
336  }
337  else if(PyCallable_Check(source[i]))
338  {
339  /* It is a Python function or a PyHocObject*/
340  if (PyObject_TypeCheck(source[i], hocobject_type))
341  {
342  src = (PyHocObject*)source[i];
343  /*TODO: check it is a reference */
344  if(src->type_ == PyHoc::HocRefNum)
345  {
346  states[j] += dt * (src->u.x_) / scale[i];
347  }
348  else
349  {
350  states[j] += dt * *(src->u.px_) / scale[i];
351  }
352  }
353  else
354  {
355  result = PyEval_CallObject(source[i], NULL);
356  if(PyFloat_Check(result))
357  {
358  states[j] += dt * PyFloat_AsDouble(result) / scale[i];
359  }
360  else if(PyLong_Check(result))
361  {
362  states[j] += dt * (double)PyLong_AsLong(result) / scale[i];
363  }
364  else if(PyInt_Check(result))
365  {
366  states[j] += dt * (double)PyInt_AsLong(result) / scale[i];
367  }
368 
369  else
370  {
371  PyErr_SetString(PyExc_Exception, "node._include_flux callback did not return a number.\n");
372  }
373  }
374  }
375  else
376  {
377  PyErr_SetString(PyExc_Exception, "node._include_flux unrecognised source term.\n");
378  }
379  }
380 }
381 
382 
383 static void apply_node_flux1D(double dt, double *states)
384 {
386 }
387 
388 extern "C" void rxd_set_euler_matrix(int nrow, int nnonzero, long* nonzero_i,
389  long* nonzero_j, double* nonzero_values,
390  double* c_diagonal)
391 {
392  long i, j, idx;
393  double val;
394  unsigned int k, ps;
395  unsigned int* parent_count;
396  /*free old data*/
397  if(_rxd_a != NULL)
398  {
399  free(_rxd_a);
400  free(_rxd_b);
401  free(_rxd_c);
402  free(_rxd_d);
403  free(_rxd_p);
404  free(_rxd_euler_nonzero_i);
405  free(_rxd_euler_nonzero_j);
407  _rxd_a = NULL;
408  }
409  diffusion = TRUE;
410 
411  _rxd_euler_nrow = nrow;
412  _rxd_euler_nnonzero = nnonzero;
413  _rxd_euler_nonzero_i = (long*)allocopy(nonzero_i, sizeof(long) * nnonzero);
414  _rxd_euler_nonzero_j = (long*)allocopy(nonzero_j, sizeof(long) * nnonzero);
415  _rxd_euler_nonzero_values = (double*)allocopy(nonzero_values, sizeof(double) * nnonzero);
416 
417  _rxd_a = (double*)calloc(nrow,sizeof(double));
418  _rxd_b = (double*)calloc(nrow,sizeof(double));
419  _rxd_c = (double*)calloc(nrow,sizeof(double));
420  _rxd_d = (double*)calloc(nrow,sizeof(double));
421  _rxd_p = (long*)malloc(nrow*sizeof(long));
422  parent_count = (unsigned int*)calloc(nrow,sizeof(unsigned int));
423 
424  for(idx = 0; idx < nrow; idx++)
425  _rxd_p[idx] = -1;
426 
427  for(idx = 0; idx < nnonzero; idx++)
428  {
429  i = nonzero_i[idx];
430  j = nonzero_j[idx];
431  val = nonzero_values[idx];
432  if(i < j)
433  {
434  _rxd_p[j] = i;
435  parent_count[i]++;
436  _rxd_a[j] = val;
437  }
438  else if(i == j)
439  {
440  _rxd_d[i] = val;
441  }
442  else
443  {
444  _rxd_b[i] = val;
445  }
446 
447  }
448 
449  for(idx = 0; idx < nrow; idx++)
450  {
451  _rxd_c[idx] = _rxd_d[idx] > 0 ? c_diagonal[idx] : 1.0;
452  }
453 
454  if(_rxd_num_zvi > 0)
455  {
456  _rxd_zvi_child_count = (unsigned int*)malloc(_rxd_num_zvi*sizeof(unsigned int));
457  _rxd_zvi_child = (long**)malloc(_rxd_num_zvi*sizeof(long*));
458 
459  /* find children of zero-volume-indices */
460  for(i = 0; i < _rxd_num_zvi; i++)
461  {
462  ps = parent_count[_rxd_zero_volume_indices[i]];
463  if(ps == 0)
464  {
465  _rxd_zvi_child_count[i] = 0;
466  _rxd_zvi_child[i] = NULL;
467 
468  continue;
469  }
470  _rxd_zvi_child[i] = (long*)malloc(ps*sizeof(long));
471  _rxd_zvi_child_count[i] = ps;
472  for(j = 0, k = 0; k < ps; j++)
473  {
474  if(_rxd_zero_volume_indices[i] == _rxd_p[j])
475  {
476  _rxd_zvi_child[i][k] = j;
477  k++;
478  }
479  }
480  }
481  }
482  free(parent_count);
483 }
484 
485 static void add_currents(double * result)
486 {
487  long i, j, k, idx;
488  short side;
489  /*Add currents to the result*/
490  for (k = 0; k < _curr_count; k++)
491  result[_curr_indices[k]] += _curr_scales[k] * (*_curr_ptrs[k]);
492 
493  /*Subtract rxd induced currents*/
494  if(_membrane_flux)
495  {
496  for(i = 0, k = 0; i < _memb_count; i++)
497  {
498  for(j = 0; j < _memb_species_count[i]; j++, k++)
499  {
500  for(side = 0; side < 2; side++)
501  {
502  idx = _memb_cur_mapped[i][j][side];
503  if (idx != SPECIES_ABSENT)
504  {
505  result[_curr_indices[idx]] -= _curr_scales[idx] * _rxd_induced_currents[k];
506  }
507  }
508  }
509  }
510  }
511 }
512 static void mul(int nnonzero, long* nonzero_i, long* nonzero_j, const double* nonzero_values, const double* v, double* result) {
513  long i, j, k;
514  /* now loop through all the nonzero locations */
515  /* NOTE: this would be more efficient if not repeatedly doing the result[i] lookup */
516  for (k = 0; k < nnonzero; k++) {
517  i = *nonzero_i++;
518  j = *nonzero_j++;
519  result[i] -= (*nonzero_values++) * v[j];
520  }
521 }
522 
523 extern "C" void set_setup(const fptr setup_fn) {
524  _setup = setup_fn;
525 }
526 
527 extern "C" void set_initialize(const fptr initialize_fn) {
528  _initialize = initialize_fn;
530 }
531 
532 extern "C" void set_setup_matrices(fptr setup_matrices) {
533  _setup_matrices = setup_matrices;
534 }
535 
536 extern "C" void set_setup_units(fptr setup_units) {
537  _setup_units = setup_units;
538  _setup_units();
539 }
540 
541 /* nrn_tree_solve modified from nrnoc/ldifus.c */
542 static void nrn_tree_solve(double* a, double* b, double* c, double* dbase, double* rhs, long* pindex, long n, double dt) {
543  /*
544  treesolver
545 
546  a - above the diagonal
547  b - below the diagonal
548  c - used to define diagonal: diag = c + dt * dbase
549  dbase - together with c, used to define diagonal
550  rhs - right hand side, which is changed to the result
551  pindex - parent indices
552  n - number of states
553  */
554  long i, pin;
555  double* d = (double*)malloc(sizeof(double) * n);
556  double* myd;
557  double* myc;
558  double* mydbase;
559 
560  /* TODO: check that d non-null */
561 
562  /* construct diagonal */
563  myd = d;
564  mydbase = dbase;
565  myc = c;
566  for (i = 0; i < n; i++) {
567  *myd++ = *myc++ + dt * (*mydbase++);
568  }
569 
570  /* triang */
571  for (i = n - 1; i > 0; --i) {
572  pin = pindex[i];
573  if (pin > -1) {
574  double p;
575  p = dt * a[i] / d[i];
576  d[pin] -= dt * p * b[i];
577  rhs[pin] -= p * rhs[i];
578  }
579  }
580  /* bksub */
581  for (i = 0; i < n; ++i) {
582  pin = pindex[i];
583  if (pin > -1) {
584  rhs[i] -= dt * b[i] * rhs[pin];
585  }
586  rhs[i] /= d[i];
587  }
588 
589  free(d);
590 }
591 
592 
593 
594 static void ode_solve(double dt, double* p1, double* p2)
595 {
596  long i, j;
597  double* b = p1 + _cvode_offset;
598  double* y = p2 + _cvode_offset;
599  double* full_b, *full_y;
600  long* zvi = _rxd_zero_volume_indices;
601 
602  if(_rxd_num_zvi > 0)
603  {
604  full_b = (double*)calloc(sizeof(double), num_states);
605  full_y = (double*)calloc(sizeof(double), num_states);
606  for(i = 0, j = 0; i < num_states; i++)
607  {
608  if(i == zvi[j])
609  {
610  j++;
611  }
612  else
613  {
614  full_b[i] = b[i-j];
615  full_y[i] = y[i-j];
616  }
617  }
618  }
619  else
620  {
621  full_b = b;
622  full_y = y;
623  }
624  if(diffusion)
626 
627  do_ics_reactions(full_y, full_b, y, b);
628 
629  if(_rxd_num_zvi > 0)
630  {
631  for(i = 0, j = 0; i < num_states; i++)
632  {
633  if(i == zvi[j])
634  j++;
635  else
636  b[i-j] = full_b[i];
637  }
638  free(full_b);
639  free(full_y);
640  }
641 
642 }
643 
644 static void ode_abs_tol(double* p1)
645 {
646  int i, j;
647  double* y = p1 + _cvode_offset;
648  if(species_indices != NULL)
649  {
650  SpeciesIndexList* list;
651  for(list = species_indices; list->next != NULL; list = list->next)
652  {
653  for(i=0, j=0; i<list->length; i++)
654  {
655  for(; j < _rxd_num_zvi && _rxd_zero_volume_indices[j] <= list->indices[i]; j++);
656  y[list->indices[i] - j] *= list->atolscale;
657  }
658 
659  }
660  }
661 }
662 
663 static void free_currents()
664 {
665  int i, j;
666  if(!_membrane_flux)
667  return;
668  for(i = 0; i < _memb_count; i++)
669  {
670  for(j = 0; j < _memb_species_count[i]; j++)
671  {
672  free(_memb_cur_mapped[i][j]);
673  }
674  free(_memb_cur_mapped[i]);
675  free(_memb_cur_ptrs[i]);
676  }
677  free(_memb_cur_ptrs);
678  free(_memb_cur_mapped);
679  free(_memb_species_count);
680  free(_cur_node_indices);
681  free(_rxd_induced_currents);
682  free(_rxd_flux_scale);
683  free(_membrane_lookup);
684  free(_memb_cur_mapped_ecs);
685  free(_rxd_induced_currents_grid);
688 }
689 
690 extern "C" void setup_currents(int num_currents, int num_fluxes,
691  int* num_species, int* node_idxs, double* scales,
692  PyHocObject** ptrs, int* mapped, int* mapped_ecs)
693 {
694  int i, j, k, id, side, count;
695  int* induced_currents_ecs_idx;
696  int* induced_currents_grid_id;
697  int* ecs_indices;
698  double* current_scales;
699  PyHocObject** ecs_ptrs;
700 
701  Current_Triple* c;
702  Grid_node* g;
703  ECS_Grid_node* grid;
704 
705 
706  free_currents();
707 
708  _memb_count = num_currents;
709  _memb_curr_total = num_fluxes;
710  _memb_species_count = (int*)malloc(sizeof(int)*num_currents);
711  memcpy(_memb_species_count,num_species,sizeof(int)*num_currents);
712 
713  _rxd_flux_scale = (double*)calloc(sizeof(double),num_fluxes);
714  //memcpy(_rxd_flux_scale,scales,sizeof(double)*num_currents);
715 
716  /*TODO: if memory is an issue - replace with a map*/
717  _membrane_lookup = (int*)malloc(sizeof(int)*num_states);
718  memset(_membrane_lookup, SPECIES_ABSENT, sizeof(int)*num_states);
719 
720  _memb_cur_ptrs = (double***)malloc(sizeof(double**)*num_currents);
721  _memb_cur_mapped_ecs = (int***)malloc(sizeof(int*)*num_currents);
722  _memb_cur_mapped = (int***)malloc(sizeof(int**)*num_currents);
723  induced_currents_ecs_idx = (int*)malloc(sizeof(int)*_memb_curr_total);
724  induced_currents_grid_id = (int*)malloc(sizeof(int)*_memb_curr_total);
725  // initialize memory here to allow currents from an intracellular species
726  // with no corresponding nrn_region='o' or Extracellular species
727  memset(induced_currents_ecs_idx, SPECIES_ABSENT,
728  sizeof(int)*_memb_curr_total);
729 
730  for(i = 0, k = 0; i < num_currents; i++)
731  {
732  _memb_cur_ptrs[i] = (double**)malloc(sizeof(double*)*num_species[i]);
733  //memcpy(_memb_cur_ptrs[i], &ptrs[k], sizeof(PyHocObject*)*num_species[i]);
734  _memb_cur_mapped_ecs[i] = (int**)malloc(sizeof(int*)*num_species[i]);
735  _memb_cur_mapped[i] = (int**)malloc(sizeof(int*)*num_species[i]);
736 
737 
738  for(j = 0; j < num_species[i]; j++, k++)
739  {
740  _memb_cur_ptrs[i][j] = (double*)ptrs[k]->u.px_;
741  _memb_cur_mapped[i][j] = (int*)malloc(2*sizeof(int));
742  _memb_cur_mapped_ecs[i][j] = (int*)malloc(2*sizeof(int));
743 
744 
745  for(side = 0; side < 2; side++)
746  {
747  _memb_cur_mapped[i][j][side] = mapped[2*k + side];
748  _memb_cur_mapped_ecs[i][j][side] = mapped_ecs[2*k + side];
749  }
750  for(side = 0; side < 2; side++)
751  {
752  if(_memb_cur_mapped[i][j][side] != SPECIES_ABSENT)
753  {
755  _rxd_flux_scale[k] = scales[i];
756  if(_memb_cur_mapped[i][j][(side+1)%2] == SPECIES_ABSENT)
757  {
758  induced_currents_grid_id[k] = _memb_cur_mapped_ecs[i][j][0];
759  induced_currents_ecs_idx[k] = _memb_cur_mapped_ecs[i][j][1];
760  }
761  }
762  }
763  }
764  }
765  _rxd_induced_currents_grid = (ECS_Grid_node**)calloc(_memb_curr_total,sizeof(ECS_Grid_node*));
766  _rxd_induced_currents_scale = (double*)calloc(_memb_curr_total,sizeof(double));
767  for (id = 0, g = Parallel_grids[0]; g != NULL; g = g -> next, id++)
768  {
769  grid = dynamic_cast<ECS_Grid_node*>(g);
770  if(grid == NULL) continue; // ignore ICS grids
771 
772  for(count = 0, k = 0; k < _memb_curr_total; k++)
773  {
774  if(induced_currents_grid_id[k] == id)
775  {
776  _rxd_induced_currents_grid[k] = grid;
777  count++;
778  }
779  }
780  if(count > 0)
781  {
782  ecs_indices = (int*)malloc(count * sizeof(int));
783  ecs_ptrs = (PyHocObject**)malloc(count * sizeof(PyHocObject*));
784  for(i = 0, k = 0; k < _memb_curr_total; k++)
785  {
786  if(induced_currents_grid_id[k] == id)
787  {
788  ecs_indices[i] = induced_currents_ecs_idx[k];
789  ecs_ptrs[i++] = ptrs[k];
790  }
791  }
792  current_scales = grid->set_rxd_currents(count, ecs_indices, ecs_ptrs);
793  free(ecs_ptrs);
794 
795  for(i = 0, k = 0; k < _memb_curr_total; k++)
796  {
797  if(induced_currents_grid_id[k] == id)
798  _rxd_induced_currents_scale[k] = current_scales[i];
799  }
800  }
801  }
802  /*index into arrays of nodes/states*/
803  _cur_node_indices = (int*)malloc(sizeof(int)*num_currents);
804  memcpy(_cur_node_indices, node_idxs, sizeof(int)*num_currents);
806  _rxd_induced_currents = (double*)malloc(sizeof(double)*_memb_curr_total);
807  free(induced_currents_ecs_idx);
808  free(induced_currents_grid_id);
809 
810 }
811 
812 static void _currents(double* rhs)
813 {
814  int i, j, k, idx, side;
815  Grid_node* g;
816  ECS_Grid_node* grid;
817  if(!_membrane_flux)
818  return;
820  for (g = Parallel_grids[0]; g != NULL; g = g -> next)
821  {
822  grid = dynamic_cast<ECS_Grid_node*>(g);
823  if(grid)
824  grid->induced_idx = 0;
825  }
826  for(i = 0, k = 0; i < _memb_count; i++)
827  {
828  idx = _cur_node_indices[i];
829 
830  for(j = 0; j < _memb_species_count[i]; j++, k++)
831  {
832  rhs[idx] -= _rxd_induced_currents[k];
834 
835  for(side = 0; side < 2; side++)
836  {
837  if(_memb_cur_mapped[i][j][side] == SPECIES_ABSENT)
838  {
839  /*Extracellular region is within the ECS grid*/
840  grid = _rxd_induced_currents_grid[k];
841  if(grid != NULL &&_memb_cur_mapped[i][j][(side+1)%2] != SPECIES_ABSENT)
843  }
844  }
845  }
846  }
847 
848 }
849 
850 extern "C" int rxd_nonvint_block(int method, int size, double* p1, double* p2, int) {
851  if(initialized)
852  {
854  {
855  /*TODO: Exclude irrelevant (non-rxd) structural changes*/
856  /*Needed for node.include_flux*/
857  _setup_matrices();
858  }
860  {
861  _setup_units();
863  }
864  }
865  switch (method) {
866  case 0:
867  _setup();
868  break;
869  case 1:
870  _initialize();
871  //TODO: is there a better place to initialize multicompartment reactions
872  Grid_node* grid;
873  ECS_Grid_node* g;
874  for (grid = Parallel_grids[0]; grid != NULL; grid = grid -> next)
875  {
876  g = dynamic_cast<ECS_Grid_node*>(grid);
878  }
879  break;
880  case 2:
881  /* compute outward current to be subtracted from rhs */
882  _currents(p1);
883  break;
884  case 3:
885  /* conductance to be added to d */
886  break;
887  case 4:
888  /* fixed step solve */
889  _fadvance();
891  break;
892  case 5:
893  /* ode_count */
894  _cvode_offset = size;
897  case 6:
898  /* ode_reinit(y) */
899  _ode_reinit(p1);
900  _ecs_ode_reinit(p1);
901  break;
902  case 7:
903  /* ode_fun(t, y, ydot); from t and y determine ydot */
904  _rhs_variable_step(p1, p2);
905  _rhs_variable_step_ecs(p1, p2);
906  break;
907  case 8:
908  ode_solve(*dt_ptr, p1, p2); /*solve mx=b replace b with x */
909  /* TODO: we can probably reuse the dgadi code here... for now, we do nothing, which implicitly approximates the Jacobian as the identity matrix */
910  //y= p1 = states and b = p2 = RHS for x direction
911  ics_ode_solve(*dt_ptr, p1, p2);
912  break;
913  case 9:
914  //ode_jacobian(*dt_ptr, p1, p2); /* optionally prepare jacobian for fast ode_solve */
915  break;
916  case 10:
917  ode_abs_tol(p1);
918  ecs_atolscale(p1);
919  /* ode_abs_tol(y_abs_tolerance); fill with cvode.atol() * scalefactor */
920  break;
921  default:
922  printf("Unknown rxd_nonvint_block call: %d\n", method);
923  break;
924  }
925  return 0;
926 }
927 
928 
929 
930 /*****************************************************************************
931 *
932 * Begin intracellular code
933 *
934 *****************************************************************************/
935 
936 
937 extern "C" void register_rate(int nspecies, int nparam, int nregions, int nseg,
938  int* sidx, int necs, int necsparam, int* ecs_ids,
939  int* ecsidx, int nmult, double* mult,
940  PyHocObject** vptrs, ReactionRate f)
941 {
942  int i,j,k,idx, ecs_id, ecs_index, ecs_offset;
943  unsigned char counted;
944  Grid_node* g;
945  ECS_Grid_node* grid;
946  ICSReactions* react = (ICSReactions*)malloc(sizeof(ICSReactions));
947  react->reaction = f;
948  react->num_species = nspecies;
949  react->num_regions = nregions;
950  react->num_params = nparam;
951  react->num_segments = nseg;
952  react->num_ecs_species = necs;
953  react->num_ecs_params = necsparam;
954  react->num_mult = nmult;
955  react->icsN = 0;
956  react->ecsN = 0;
957  if (vptrs != NULL)
958  {
959  react->vptrs = (double**)malloc(nseg*sizeof(double*));
960  for(i = 0; i < nseg; i++)
961  react->vptrs[i] = vptrs[i]->u.px_;
962  }
963  else
964  {
965  react->vptrs = NULL;
966  }
967  react->state_idx = (int***)malloc(nseg*sizeof(double**));
968  for(i = 0, idx = 0; i < nseg; i++)
969  {
970  react->state_idx[i] = (int**)malloc((nspecies + nparam)*sizeof(int*));
971  for(j = 0; j < nspecies + nparam; j++)
972  {
973  react->state_idx[i][j] = (int*)malloc(nregions*sizeof(int));
974  for(k = 0; k < nregions; k++, idx++)
975  {
976  if(sidx[idx] < 0)
977  {
978  react->state_idx[i][j][k] = SPECIES_ABSENT;
979  }
980  else
981  {
982  react->state_idx[i][j][k] = sidx[idx];
983  if(i==0 && j < nspecies)
984  react->icsN++;
985  }
986  }
987  }
988  }
989  if( nmult > 0 )
990  {
991  react->mc_multiplier = (double**)malloc(nmult*sizeof(double*));
992  for(i = 0; i < nmult; i++)
993  {
994  react->mc_multiplier[i] = (double*)malloc(nseg*sizeof(double));
995  memcpy(react->mc_multiplier[i], (mult+i*nseg), nseg*sizeof(double));
996  }
997  }
998 
999  if(react->num_ecs_species + react->num_ecs_params > 0)
1000  {
1001  react->ecs_grid = (ECS_Grid_node**)malloc(react->num_ecs_species*sizeof(Grid_node*));
1002  react->ecs_state = (double***)malloc(nseg*sizeof(double**));
1003  react->ecs_index = (int**)malloc(nseg*sizeof(int*));
1004  react->ecs_offset_index = (int*)malloc(react->num_ecs_species*sizeof(int));
1005  for(i = 0; i < nseg; i++)
1006  {
1007  react->ecs_state[i] = (double**)malloc((necs+necsparam)*sizeof(double*));
1008  react->ecs_index[i] = (int*)malloc((necs+necsparam)*sizeof(int));
1009 
1010  }
1011  for(j = 0; j < necs + necsparam; j++)
1012  {
1013  ecs_offset = num_states - _rxd_num_zvi;
1014 
1015  for(ecs_id = 0, g = Parallel_grids[0]; g != NULL; g = g -> next, ecs_id++)
1016  {
1017 
1018  if (ecs_id == ecs_ids[j])
1019  {
1020  grid = dynamic_cast<ECS_Grid_node*>(g);
1021  assert(grid != NULL);
1022  if (j < necs)
1023  {
1024  react->ecs_grid[j] = grid;
1025  react->ecs_offset_index[j] = grid->add_multicompartment_reaction(nseg, &ecsidx[j], necs + necsparam);
1026  }
1027 
1028  for(i = 0, counted=FALSE; i < nseg; i++)
1029  {
1030  //nseg x nregion x nspecies
1031  ecs_index = ecsidx[i*(necs + necsparam) + j];
1032 
1033  if(ecs_index >= 0)
1034  {
1035  react->ecs_state[i][j] = &(grid->states[ecs_index]);
1036  react->ecs_index[i][j] = ecs_offset + ecs_index;
1037  if(j < necs && !counted)
1038  {
1039  react->ecsN++;
1040  counted=TRUE;
1041  }
1042  }
1043  else
1044  {
1045  react->ecs_state[i][j] = NULL;
1046  }
1047  }
1048  ecs_offset += grid->size_x*grid->size_y*grid->size_z;
1049  }
1050  }
1051  }
1052  }
1053  else
1054  {
1055  react->ecs_state = NULL;
1056  }
1057  if(_reactions == NULL)
1058  {
1059  _reactions = react;
1060  react -> next = NULL;
1061 
1062  }
1063  else
1064  {
1065  react -> next = _reactions;
1066  _reactions = react;
1067  }
1068 
1069  for (g = Parallel_grids[0]; g != NULL; g = g -> next)
1070  {
1071  grid = dynamic_cast<ECS_Grid_node*>(g);
1072  if(grid)
1074  }
1075 }
1076 
1077 extern "C" void clear_rates()
1078 {
1079  ICSReactions *react, *prev;
1080  int i, j;
1081  for(react = _reactions; react != NULL;)
1082  {
1083  if(react->vptrs != NULL)
1084  free(react->vptrs);
1085  for(i = 0; i < react->num_segments; i++)
1086  {
1087  for(j = 0; j < react->num_species; j++)
1088  {
1089  free(react->state_idx[i][j]);
1090  }
1091  free(react->state_idx[i]);
1092 
1093  if(react->num_ecs_species + react->num_ecs_params > 0)
1094  {
1095  free(react->ecs_state[i]);
1096  }
1097  }
1098  if(react->num_mult > 0)
1099  {
1100  for(i = 0; i < react->num_mult; i++)
1101  free(react->mc_multiplier[i]);
1102  free(react->mc_multiplier);
1103  }
1104 
1105  free(react->state_idx);
1106  SAFE_FREE(react->ecs_state);
1107  prev = react;
1108  react = react->next;
1109  SAFE_FREE(prev);
1110  }
1111  _reactions = NULL;
1112  /*clear extracellular reactions*/
1113  clear_rates_ecs();
1114 }
1115 
1116 
1117 extern "C" void species_atolscale(int id, double scale, int len, int* idx)
1118 {
1119  SpeciesIndexList* list;
1121  if(species_indices != NULL)
1122  {
1123  for(list = species_indices, prev = NULL;
1124  list != NULL; list = list->next)
1125  {
1126  if(list->id == id)
1127  {
1128  list->atolscale = scale;
1129  return;
1130  }
1131  prev = list;
1132  }
1133  prev->next = (SpeciesIndexList*)malloc(sizeof(SpeciesIndexList));
1134  list = prev->next;
1135  }
1136  else
1137  {
1138  species_indices = (SpeciesIndexList*)malloc(sizeof(SpeciesIndexList));
1139  list = species_indices;
1140  }
1141  list->id = id;
1142  list->indices = (int*)malloc(sizeof(int)*len);
1143  memcpy(list->indices,idx,sizeof(int)*len);
1144  list->length = len;
1145  list->atolscale = scale;
1146  list->next = NULL;
1147 }
1148 
1149 extern "C" void remove_species_atolscale(int id)
1150 {
1151  SpeciesIndexList* list;
1153  for(list = species_indices, prev = NULL;
1154  list != NULL; prev = list, list = list->next)
1155  {
1156  if(list->id == id)
1157  {
1158  if(prev == NULL)
1159  species_indices = list->next;
1160  else
1161  prev->next = list->next;
1162  free(list->indices);
1163  free(list);
1164  break;
1165  }
1166  }
1167 }
1168 
1169 extern "C" void setup_solver(double* my_states, int my_num_states, long* zvi, int num_zvi) {
1170  free_currents();
1171  states = my_states;
1172  num_states = my_num_states;
1173  free_zvi_child();
1174  _rxd_num_zvi = num_zvi;
1177  if (num_zvi == 0)
1179  else
1180  _rxd_zero_volume_indices = (long*)allocopy(zvi, num_zvi * sizeof(long));
1181  dt_ptr = &nrn_threads->_dt;
1182  t_ptr = &nrn_threads->_t;
1184  initialized = TRUE;
1186 }
1187 
1188 void start_threads(const int n)
1189 {
1190  int i;
1191  if(Threads == NULL)
1192  {
1193  AllTasks = (TaskQueue*)calloc(1,sizeof(TaskQueue));
1194  Threads = (pthread_t*)malloc(sizeof(pthread_t)*(n-1));
1195  AllTasks->task_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
1196  AllTasks->waiting_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
1197  AllTasks->task_cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
1198  AllTasks->waiting_cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
1199  pthread_mutex_init(AllTasks->task_mutex, NULL);
1200  pthread_cond_init(AllTasks->task_cond, NULL);
1201  pthread_mutex_init(AllTasks->waiting_mutex, NULL);
1202  pthread_cond_init(AllTasks->waiting_cond, NULL);
1203  AllTasks->length = 0;
1204  for(i = 0; i < n-1; i++)
1205  pthread_create(&Threads[i], NULL, TaskQueue_exe_tasks, AllTasks);
1206  }
1207 
1208 }
1209 
1210 void TaskQueue_add_task(TaskQueue* q, void* (*task)(void*), void* args, void* result)
1211 {
1212  TaskList *t;
1213  t = (TaskList*)malloc(sizeof(TaskList));
1214  t->task = task;
1215  t->args = args;
1216  t->result = result;
1217  t->next = NULL;
1218 
1219  //Add task to the queue
1220  pthread_mutex_lock(q->task_mutex);
1221  if(q->first == NULL) //empty queue
1222  {
1223  q->first=t;
1224  q->last=t;
1225  }
1226  else //non-empty
1227  {
1228  q->last->next = t;
1229  q->last = t;
1230  }
1231 
1232  pthread_mutex_lock(q->waiting_mutex);
1233  q->length++;
1234  pthread_mutex_unlock(q->waiting_mutex);
1235  pthread_mutex_unlock(q->task_mutex);
1236 
1237  //signal waiting threads
1238  pthread_cond_signal(q->task_cond);
1239 
1240 }
1241 
1242 void* TaskQueue_exe_tasks(void* dat)
1243 {
1244  TaskList* job;
1245  TaskQueue* q = (TaskQueue*)dat;
1246  /*int id;
1247  for(id=0;id<NUM_THREADS;id++)
1248  {
1249  if (pthread_equal(Threads[id],pthread_self()))
1250  {
1251  break;
1252  }
1253  }
1254  fprintf(stderr,"%i] ready\n",id);
1255  */
1256  while(1) //loop until thread is killed
1257  {
1258  pthread_mutex_lock(q->task_mutex);
1259  while(q->first == NULL) //no tasks
1260  {
1261  //Wait for new tasks
1262  pthread_cond_wait(q->task_cond, q->task_mutex);
1263  }
1264  //fprintf(stderr,"%i] running\n",id);
1265  job = q->first;
1266  q->first = job->next;
1267  pthread_mutex_unlock(q->task_mutex);
1268 
1269  //execute
1270  job->result = job->task(job->args);
1271  free(job);
1272 
1273  //fprintf(stderr,"%i] updating\n",id);
1274  pthread_mutex_lock(q->waiting_mutex);
1275  if(--(q->length) == 0) //all finished
1276  {
1277  pthread_cond_broadcast(q->waiting_cond);
1278  }
1279  pthread_mutex_unlock(q->waiting_mutex);
1280  //fprintf(stderr,"%i] done\n",id);
1281  }
1282 
1283  return NULL;
1284 }
1285 
1286 
1287 void set_num_threads(const int n)
1288 {
1289  int k, old_num = NUM_THREADS;
1290  if(Threads == NULL)
1291  {
1292  start_threads(n);
1293  }
1294  else
1295  {
1296  if(n<old_num)
1297  {
1298  //Kill some threads
1299  for(k=old_num-1; k>=n; k--)
1300  {
1301  TaskQueue_sync(AllTasks);
1302  pthread_cancel(Threads[k]);
1303  }
1304  Threads = (pthread_t*)realloc(Threads,sizeof(pthread_t) * n);
1305  assert(Threads);
1306  }
1307  else if(n>old_num)
1308  {
1309  //Create some threads
1310  Threads = (pthread_t*)realloc(Threads,sizeof(pthread_t) * n);
1311  assert(Threads);
1312 
1313  for (k = old_num-1; k < n; k++)
1314  {
1315  pthread_create(&Threads[k], NULL, TaskQueue_exe_tasks, AllTasks);
1316  }
1317  }
1318  }
1319  set_num_threads_3D(n);
1320  NUM_THREADS = n;
1321 
1322 }
1323 
1325 {
1326  //Wait till the queue is empty
1327  pthread_mutex_lock(q->waiting_mutex);
1328  while(q->length > 0)
1329  pthread_cond_wait(q->waiting_cond,q->waiting_mutex);
1330  pthread_mutex_unlock(q->waiting_mutex);
1331 }
1332 
1333 int get_num_threads(void) {
1334  return NUM_THREADS;
1335 }
1336 
1337 
1338 void _fadvance(void) {
1339  double dt = *dt_ptr;
1340  long i;
1341  /*variables for diffusion*/
1342  double *rhs;
1343  long* zvi = _rxd_zero_volume_indices;
1344 
1345  rhs = (double*)calloc(num_states,sizeof(double));
1346  /*diffusion*/
1347  if(diffusion)
1349 
1350  add_currents(rhs);
1351 
1352  /* multiply rhs vector by dt */
1353  for (i = 0; i < num_states; i++) {
1354  rhs[i] *= dt;
1355  }
1356 
1357  if(diffusion)
1359 
1360  /* increment states by rhs which is now really deltas */
1361  for (i = 0; i < num_states; i++) {
1362  states[i] += rhs[i];
1363  }
1364 
1365  /* clear zero volume indices (conservation nodes) */
1366  for (i = 0; i < _rxd_num_zvi; i++) {
1367  states[zvi[i]] = 0;
1368  }
1369 
1370  free(rhs);
1371 
1372  /*reactions*/
1374 
1375  /*node fluxes*/
1377 
1379 }
1380 
1381 
1382 void _ode_reinit(double* y)
1383 {
1384  long i, j;
1385  long* zvi = _rxd_zero_volume_indices;
1386  y += _cvode_offset;
1387  /*Copy states to CVode*/
1388  if(_rxd_num_zvi > 0)
1389  {
1390  for(i=0, j=0; i < num_states; i++)
1391  {
1392  if(zvi[j] == i)
1393  j++;
1394  else
1395  {
1396  y[i-j] = states[i];
1397  }
1398  }
1399  }
1400  else
1401  {
1402  memcpy(y,states,sizeof(double)*num_states);
1403  }
1404 }
1405 
1406 
1407 void _rhs_variable_step(const double* p1, double* p2)
1408 {
1409  Grid_node *grid;
1410  long i, j, p, c;
1411  unsigned int k;
1412  const unsigned char calculate_rhs = p2 == NULL ? 0 : 1;
1413  const double* my_states = p1 + _cvode_offset;
1414  double* ydot = p2 + _cvode_offset;
1415  /*variables for diffusion*/
1416  double *rhs;
1417  long* zvi = _rxd_zero_volume_indices;
1418 
1419  double const * const orig_states3d = p1 + states_cvode_offset;
1420  double* const orig_ydot3d = p2 + states_cvode_offset;
1421 
1422  /*Copy states from CVode*/
1423  if(_rxd_num_zvi > 0)
1424  {
1425  for(i=0, j=0; i < num_states; i++)
1426  {
1427  if(zvi[j] == i)
1428  j++;
1429  else{
1430  states[i] = my_states[i-j];
1431  }
1432  }
1433  }
1434  else
1435  {
1436  memcpy(states,my_states,sizeof(double)*num_states);
1437  }
1438 
1439  if(diffusion)
1440  {
1441  for(i = 0; i < _rxd_num_zvi; i++)
1442  {
1443  j = zvi[i];
1444  p = _rxd_p[j];
1445  states[j] = (p>0?-(_rxd_b[j]/_rxd_d[j])*states[p]:0);
1446  for(k = 0; k < _rxd_zvi_child_count[i]; k++)
1447  {
1448  c = _rxd_zvi_child[i][k];
1449  states[j] -= (_rxd_a[c]/_rxd_d[j])*states[c];
1450  }
1451  }
1452  }
1453 
1455 
1456  if(!calculate_rhs)
1457  {
1458  for(i = 0; i < _rxd_num_zvi; i++)
1459  states[zvi[i]] = 0;
1460  return;
1461  }
1462 
1463  /*diffusion*/
1464  rhs = (double*)calloc(num_states,sizeof(double));
1465 
1466  if(diffusion)
1468 
1469  /*reactions*/
1470  MEM_ZERO(&ydot[num_states - _rxd_num_zvi], sizeof(double)*_ecs_count);
1471  get_all_reaction_rates(states, rhs, ydot);
1472 
1473 
1474  const double* states3d = orig_states3d;
1475  double* ydot3d = orig_ydot3d;
1476  int grid_size;
1477  for (grid = Parallel_grids[0]; grid != NULL; grid = grid -> next) {
1478  grid_size = grid->size_x * grid->size_y * grid->size_z;
1479  if(grid->hybrid)
1480  {
1481  grid->variable_step_hybrid_connections(states3d, ydot3d, states, rhs);
1482  }
1483  ydot3d += grid_size;
1484  states3d += grid_size;
1485  }
1486 
1487  /*Add currents to the result*/
1488  add_currents(rhs);
1489 
1490  /*Add node fluxes to the result*/
1491  apply_node_flux1D(1.0, rhs);
1492 
1493  /* increment states by rhs which is now really deltas */
1494  if(_rxd_num_zvi > 0)
1495  {
1496  for (i = 0, j = 0; i < num_states; i++)
1497  {
1498  if(zvi[j] == i)
1499  {
1500  states[i] = 0;
1501  j++;
1502  }
1503  else
1504  {
1505  ydot[i-j] = rhs[i];
1506  }
1507  }
1508  }
1509  else
1510  {
1511  memcpy(ydot,rhs,sizeof(double)*num_states);
1512  }
1513  free(rhs);
1514 }
1515 
1516 void get_reaction_rates(ICSReactions* react, double* states, double* rates, double* ydot)
1517 {
1518  int segment;
1519  int i, j, k, idx;
1520  double** states_for_reaction = (double**)malloc(react->num_species*sizeof(double*));
1521  double** params_for_reaction = (double**)malloc(react->num_params*sizeof(double*));
1522  double** result_array = (double**)malloc(react->num_species*sizeof(double*));
1523  double* mc_mult = NULL;
1524  double** flux = NULL;
1525  if(react->num_mult > 0)
1526  mc_mult = (double*)malloc(react->num_mult*sizeof(double));
1527 
1528  double* ecs_states_for_reaction = NULL;
1529  double* ecs_params_for_reaction = NULL;
1530  double* ecs_result = NULL;
1531  int * ecsindex = NULL;
1532  double v = 0;
1533  if(react->num_ecs_species > 0)
1534  {
1535  ecs_states_for_reaction = (double*)malloc(react->num_ecs_species*sizeof(double));
1536  ecs_result = (double*)malloc(react->num_ecs_species*sizeof(double));
1537  }
1538  if(react->num_ecs_params > 0)
1539  ecs_params_for_reaction = (double*)calloc(react->num_ecs_params,sizeof(double));
1540 
1541  if(_membrane_flux)
1542  {
1543  flux = (double**)malloc(react->icsN*sizeof(double*));
1544  for(i = 0; i < react->icsN; i++)
1545  flux[i] = (double*)calloc(react->num_regions, sizeof(double));
1546  }
1547 
1548  for(i = 0; i < react->num_species; i++)
1549  {
1550  states_for_reaction[i] = (double*)calloc(react->num_regions,sizeof(double));
1551  result_array[i] = (double*)malloc(react->num_regions*sizeof(double));
1552 
1553  }
1554  for(i = 0; i < react->num_params; i++)
1555  params_for_reaction[i] = (double*)calloc(react->num_regions,sizeof(double));
1556  ecsindex = (int*)malloc(react->num_ecs_species*sizeof(int));
1557  for(i = 0; i < react->num_ecs_species; i++)
1558  ecsindex[i] = react->ecs_grid[i]->react_offsets[react->ecs_offset_index[i]];
1559 
1560  for(segment = 0; segment < react->num_segments; segment++)
1561  {
1562  for(i = 0; i < react->num_species; i++)
1563  {
1564  for(j = 0; j < react->num_regions; j++)
1565  {
1566  if(react->state_idx[segment][i][j] != SPECIES_ABSENT)
1567  {
1568  states_for_reaction[i][j] = states[react->state_idx[segment][i][j]];
1569  }
1570  else
1571  {
1572  states_for_reaction[i][j] = NAN;
1573  }
1574  }
1575  MEM_ZERO(result_array[i],react->num_regions*sizeof(double));
1576  }
1577  for(k = 0; i < react->num_species + react->num_params; i++, k++)
1578  {
1579  for(j = 0; j < react->num_regions; j++)
1580  {
1581  if(react->state_idx[segment][i][j] != SPECIES_ABSENT)
1582  {
1583  params_for_reaction[k][j] = states[react->state_idx[segment][i][j]];
1584  }
1585  else
1586  {
1587  params_for_reaction[k][j] = NAN;
1588  }
1589  }
1590  }
1591 
1592  for(i = 0; i < react->num_ecs_species; i++)
1593  {
1594  if(react->ecs_state[segment][i] != NULL)
1595  {
1596  ecs_states_for_reaction[i] = *(react->ecs_state[segment][i]);
1597  }
1598  else
1599  {
1600  ecs_states_for_reaction[i] = NAN;
1601 
1602  }
1603  }
1604  for(k = 0; i < react->num_ecs_species + react->num_ecs_params; i++, k++)
1605  {
1606  if(react->ecs_state[segment][i] != NULL)
1607  {
1608  ecs_params_for_reaction[k] = *(react->ecs_state[segment][i]);
1609  }
1610  else
1611  {
1612  ecs_params_for_reaction[k] = NAN;
1613  }
1614  }
1615  MEM_ZERO(ecs_result,react->num_ecs_species*sizeof(double));
1616 
1617  for(i = 0; i < react->num_mult; i++)
1618  {
1619  mc_mult[i] = react->mc_multiplier[i][segment];
1620  }
1621 
1622  if(react->vptrs != NULL)
1623  {
1624  v = *(react->vptrs[segment]);
1625  }
1626 
1627  react->reaction(states_for_reaction, params_for_reaction, result_array, mc_mult, ecs_states_for_reaction, ecs_params_for_reaction, ecs_result, flux, v);
1628 
1629  for(i = 0; i < react->num_species; i++)
1630  {
1631  for(j = 0; j < react->num_regions; j++)
1632  {
1633  idx = react->state_idx[segment][i][j];
1634  if(idx != SPECIES_ABSENT)
1635  {
1637  {
1638  _rxd_induced_currents[_membrane_lookup[idx]] -= _rxd_flux_scale[_membrane_lookup[idx]] * flux[i][j];
1639  }
1640  if(rates != NULL)
1641  {
1642  rates[idx] += result_array[i][j];
1643  }
1644  }
1645  }
1646  }
1647  if(ydot != NULL)
1648  {
1649  for(i = 0; i < react->num_ecs_species; i++)
1650  {
1651  if(react->ecs_state[segment][i] != NULL)
1652  react->ecs_grid[i]->all_reaction_states[ecsindex[i]++] = ecs_result[i];
1653  //ydot[react->ecs_index[segment][i]] += ecs_result[i];
1654  }
1655  }
1656  }
1657  /* free allocated memory */
1658  if(react->num_mult > 0)
1659  free(mc_mult);
1660  if(_membrane_flux)
1661  {
1662  for(i = 0; i < react->icsN; i++)
1663  free(flux[i]);
1664  free(flux);
1665  }
1666  if(react->num_ecs_species>0)
1667  {
1668  free(ecs_states_for_reaction);
1669  free(ecs_result);
1670  }
1671  for(i = 0; i < react->num_species; i++)
1672  {
1673  free(states_for_reaction[i]);
1674  free(result_array[i]);
1675  }
1676  free(states_for_reaction);
1677  free(result_array);
1678  for(i = 0; i < react->num_params; i++)
1679  {
1680  free(params_for_reaction[i]);
1681  }
1682  free(params_for_reaction);
1683  if(react->num_ecs_params>0)
1684  {
1685  free(ecs_params_for_reaction);
1686  }
1687 
1688 
1689 }
1690 
1691 void solve_reaction(ICSReactions* react, double* states, double *bval, double* cvode_states, double* cvode_b)
1692 {
1693  int segment;
1694  int i, j, k, idx, jac_i, jac_j, jac_idx;
1695  int N = react->icsN + react->ecsN; /*size of Jacobian (number species*regions for a segments)*/
1696  double pd;
1697  double dt = *dt_ptr;
1698  double dx = FLT_EPSILON;
1699  MAT* jacobian = m_get(N,N);
1700  VEC* b = v_get(N);
1701  VEC* x = v_get(N);
1702  PERM* pivot = px_get(N);
1703 
1704  double** states_for_reaction = (double**)malloc(react->num_species*sizeof(double*));
1705  double** states_for_reaction_dx = (double**)malloc(react->num_species*sizeof(double*));
1706  double** params_for_reaction = (double**)malloc(react->num_params*sizeof(double*));
1707  double** result_array = (double**)malloc(react->num_species*sizeof(double*));
1708  double** result_array_dx = (double**)malloc(react->num_species*sizeof(double*));
1709  double* mc_mult = NULL;
1710  if(react->num_mult > 0)
1711  mc_mult = (double*)malloc(react->num_mult*sizeof(double));
1712 
1713  double* ecs_states_for_reaction = NULL;
1714  double* ecs_states_for_reaction_dx = NULL;
1715  double* ecs_params_for_reaction = NULL;
1716  double* ecs_result = NULL;
1717  double* ecs_result_dx = NULL;
1718  double v = 0;
1719  int* ecsindex = NULL;
1720 
1721  if(react->num_ecs_species > 0)
1722  {
1723  ecsindex = (int*)malloc(react->num_ecs_species*sizeof(int));
1724  for(i = 0; i < react->num_ecs_species; i++)
1725  ecsindex[i] = react->ecs_grid[i]->react_offsets[react->ecs_offset_index[i]];
1726  ecs_states_for_reaction = (double*)malloc(react->num_ecs_species*sizeof(double));
1727  ecs_states_for_reaction_dx = (double*)malloc(react->num_ecs_species*sizeof(double));
1728  ecs_result = (double*)malloc(react->num_ecs_species*sizeof(double));
1729  ecs_result_dx = (double*)malloc(react->num_ecs_species*sizeof(double));
1730  }
1731 
1732  if(react->num_ecs_params > 0)
1733  ecs_params_for_reaction = (double*)malloc(react->num_ecs_params*sizeof(double));
1734 
1735 
1736  for(i = 0; i < react->num_species; i++)
1737  {
1738  states_for_reaction[i] = (double*)malloc(react->num_regions*sizeof(double));
1739  states_for_reaction_dx[i] = (double*)malloc(react->num_regions*sizeof(double));
1740  result_array[i] = (double*)malloc(react->num_regions*sizeof(double));
1741  result_array_dx[i] = (double*)malloc(react->num_regions*sizeof(double));
1742  }
1743  for(i = 0; i < react->num_params; i++)
1744  params_for_reaction[i] = (double*)malloc(react->num_regions*sizeof(double));
1745 
1746  for(segment = 0; segment < react->num_segments; segment++)
1747  {
1748  if(react->vptrs != NULL)
1749  v = *(react->vptrs[segment]);
1750 
1751  for(i = 0; i < react->num_species; i++)
1752  {
1753  for(j = 0; j < react->num_regions; j++)
1754  {
1755  if(react->state_idx[segment][i][j] != SPECIES_ABSENT)
1756  {
1757  states_for_reaction[i][j] = states[react->state_idx[segment][i][j]];
1758  states_for_reaction_dx[i][j] = states_for_reaction[i][j];
1759  }
1760  else
1761  {
1762  states_for_reaction[i][j] = SPECIES_ABSENT;
1763  states_for_reaction_dx[i][j] = states_for_reaction[i][j];
1764  }
1765 
1766  }
1767  MEM_ZERO(result_array[i],react->num_regions*sizeof(double));
1768  MEM_ZERO(result_array_dx[i],react->num_regions*sizeof(double));
1769  }
1770  for(k = 0; i < react->num_species + react->num_params; i++, k++)
1771  {
1772  for(j = 0; j < react->num_regions; j++)
1773  {
1774  if(react->state_idx[segment][i][j] != SPECIES_ABSENT)
1775  {
1776  params_for_reaction[k][j] = states[react->state_idx[segment][i][j]];
1777  }
1778  else
1779  {
1780  params_for_reaction[k][j] = SPECIES_ABSENT;
1781  }
1782 
1783  }
1784  }
1785 
1786 
1787  for(i = 0; i < react->num_ecs_species; i++)
1788  {
1789  if(react->ecs_state[segment][i] != NULL)
1790  {
1791  if(cvode_states != NULL)
1792  {
1793  ecs_states_for_reaction[i] = cvode_states[react->ecs_index[segment][i]];
1794  }
1795  else
1796  {
1797  ecs_states_for_reaction[i] = *(react->ecs_state[segment][i]);
1798  }
1799  ecs_states_for_reaction_dx[i] = ecs_states_for_reaction[i];
1800  }
1801  }
1802  for(k = 0; i < react->num_ecs_species + react->num_ecs_params; i++, k++)
1803  {
1804  if(react->ecs_state[segment][i] != NULL)
1805  {
1806  ecs_params_for_reaction[k] = *(react->ecs_state[segment][i]);
1807  }
1808  }
1809 
1810  if(react->num_ecs_species > 0)
1811  {
1812  MEM_ZERO(ecs_result,react->num_ecs_species*sizeof(double));
1813  MEM_ZERO(ecs_result_dx,react->num_ecs_species*sizeof(double));
1814  }
1815 
1816  for(i = 0; i < react->num_mult; i++)
1817  {
1818  mc_mult[i] = react->mc_multiplier[i][segment];
1819  }
1820 
1821  react->reaction(states_for_reaction, params_for_reaction, result_array,
1822  mc_mult, ecs_states_for_reaction,
1823  ecs_params_for_reaction, ecs_result, NULL, v);
1824 
1825  /*Calculate I - Jacobian for ICS reactions*/
1826  for(i = 0, idx = 0; i < react->num_species; i++)
1827  {
1828  for(j = 0; j < react->num_regions; j++)
1829  {
1830  if(react->state_idx[segment][i][j] != SPECIES_ABSENT)
1831  {
1832  if(bval == NULL)
1833  v_set_val(b, idx, dt*result_array[i][j]);
1834  else
1835  v_set_val(b, idx, bval[react->state_idx[segment][i][j]]);
1836 
1837 
1838  // set up the changed states array
1839  states_for_reaction_dx[i][j] += dx;
1840 
1841  /* TODO: Handle approximating the Jacobian at a function upper
1842  * limit, e.g. acos(1)
1843  */
1844  react->reaction(states_for_reaction_dx, params_for_reaction,
1845  result_array_dx, mc_mult,
1846  ecs_states_for_reaction,
1847  ecs_params_for_reaction, ecs_result_dx,
1848  NULL, v);
1849 
1850  for (jac_i = 0, jac_idx = 0; jac_i < react->num_species; jac_i++)
1851  {
1852  for (jac_j = 0; jac_j < react->num_regions; jac_j++)
1853  {
1854  // pd is our Jacobian approximated
1855  if(react->state_idx[segment][jac_i][jac_j] != SPECIES_ABSENT)
1856  {
1857  pd = (result_array_dx[jac_i][jac_j] - result_array[jac_i][jac_j])/dx;
1858  m_set_val(jacobian, jac_idx, idx, (idx==jac_idx) - dt*pd);
1859  jac_idx += 1;
1860  }
1861  result_array_dx[jac_i][jac_j] = 0;
1862  }
1863  }
1864  for (jac_i = 0; jac_i < react->num_ecs_species; jac_i++)
1865  {
1866  // pd is our Jacobian approximated
1867  if(react->ecs_state[segment][jac_i] != NULL)
1868  {
1869  pd = (ecs_result_dx[jac_i] - ecs_result[jac_i])/dx;
1870  m_set_val(jacobian, jac_idx, idx, -dt*pd);
1871  jac_idx += 1;
1872  }
1873  ecs_result_dx[jac_i] = 0;
1874  }
1875  // reset dx array
1876  states_for_reaction_dx[i][j] -= dx;
1877  idx++;
1878  }
1879  }
1880  }
1881 
1882  /*Calculate I - Jacobian for MultiCompartment ECS reactions*/
1883  for(i = 0; i < react->num_ecs_species; i++)
1884  {
1885  if(react->ecs_state[segment][i] != NULL)
1886  {
1887  if(bval == NULL)
1888  v_set_val(b, idx, dt*ecs_result[i]);
1889  else
1890  v_set_val(b, idx, cvode_b[react->ecs_index[segment][i]]);
1891 
1892 
1893  // set up the changed states array
1894  ecs_states_for_reaction_dx[i] += dx;
1895 
1896  /* TODO: Handle approximating the Jacobian at a function upper
1897  * limit, e.g. acos(1)
1898  */
1899  react->reaction(states_for_reaction, params_for_reaction, result_array_dx,
1900  mc_mult, ecs_states_for_reaction_dx,
1901  ecs_params_for_reaction, ecs_result_dx, NULL, v);
1902 
1903  for (jac_i = 0, jac_idx = 0; jac_i < react->num_species; jac_i++)
1904  {
1905  for (jac_j = 0; jac_j < react->num_regions; jac_j++)
1906  {
1907  // pd is our Jacobian approximated
1908  if(react->state_idx[segment][jac_i][jac_j] != SPECIES_ABSENT)
1909  {
1910  pd = (result_array_dx[jac_i][jac_j] - result_array[jac_i][jac_j])/dx;
1911  m_set_val(jacobian, jac_idx, idx, - dt*pd);
1912  jac_idx += 1;
1913  }
1914  }
1915  }
1916  for (jac_i = 0; jac_i < react->num_ecs_species; jac_i++)
1917  {
1918  // pd is our Jacobian approximated
1919  if(react->ecs_state[segment][jac_i] != NULL)
1920  {
1921  pd = (ecs_result_dx[jac_i] - ecs_result[jac_i])/dx;
1922  m_set_val(jacobian, jac_idx, idx, (idx==jac_idx) - dt*pd);
1923  jac_idx += 1;
1924  }
1925  else
1926  {
1927  m_set_val(jacobian, idx, idx, 1.0);
1928  }
1929  // reset dx array
1930  ecs_states_for_reaction_dx[i] -= dx;
1931  }
1932  idx++;
1933  }
1934  }
1935  // solve for x, destructively
1936  LUfactor(jacobian, pivot);
1937  LUsolve(jacobian, pivot, b, x);
1938 
1939  if(bval != NULL) //variable-step
1940  {
1941  for(i = 0, jac_idx=0; i < react->num_species; i++)
1942  {
1943  for(j = 0; j < react->num_regions; j++)
1944  {
1945  idx = react->state_idx[segment][i][j];
1946  if(idx != SPECIES_ABSENT)
1947  {
1948  bval[idx] = v_get_val(x, jac_idx++);
1949  }
1950  }
1951  }
1952  for(i = 0; i < react->num_ecs_species; i++)
1953  {
1954  if(react->ecs_state[segment][i] != NULL)
1955  react->ecs_grid[i]->all_reaction_states[ecsindex[i]++] = v_get_val(x,jac_idx++);
1956  //cvode_b[react->ecs_index[segment][i]] = v_get_val(x, jac_idx++);
1957  }
1958  }
1959  else //fixed-step
1960  {
1961  for(i = 0, jac_idx=0; i < react->num_species; i++)
1962  {
1963  for(j = 0; j < react->num_regions; j++)
1964  {
1965  idx = react->state_idx[segment][i][j];
1966  if(idx != SPECIES_ABSENT)
1967  states[idx] += v_get_val(x, jac_idx++);
1968  }
1969  }
1970  for(i = 0; i < react->num_ecs_species; i++)
1971  {
1972  if(react->ecs_state[segment][i] != NULL)
1973  react->ecs_grid[i]->all_reaction_states[ecsindex[i]++] = v_get_val(x,jac_idx++);
1974  }
1975  }
1976  }
1977  free(ecsindex);
1978  m_free(jacobian);
1979  v_free(b);
1980  v_free(x);
1981  px_free(pivot);
1982  for(i = 0; i < react->num_species; i++)
1983  {
1984  free(states_for_reaction[i]);
1985  free(states_for_reaction_dx[i]);
1986  free(result_array[i]);
1987  free(result_array_dx[i]);
1988  }
1989  for(i = 0; i < react->num_params; i++)
1990  free(params_for_reaction[i]);
1991  if(react->num_mult > 0)
1992  free(mc_mult);
1993  free(states_for_reaction_dx);
1994  free(states_for_reaction);
1995  free(params_for_reaction);
1996  free(result_array);
1997  free(result_array_dx);
1998  if(react->num_ecs_species > 0)
1999  {
2000  free(ecs_states_for_reaction);
2001  free(ecs_states_for_reaction_dx);
2002  free(ecs_result);
2003  free(ecs_result_dx);
2004  }
2005  if(react->num_ecs_params > 0)
2006  free(ecs_params_for_reaction);
2007 }
2008 
2009 void do_ics_reactions(double* states, double* b, double* cvode_states, double* cvode_b)
2010 {
2011  ICSReactions* react;
2012  for(react = _reactions; react != NULL; react = react->next)
2013  {
2014  if(react->icsN + react->ecsN > 0)
2015  solve_reaction(react, states, b, cvode_states, cvode_b);
2016  }
2017 }
2018 
2019 void get_all_reaction_rates(double* states, double* rates, double* ydot)
2020 {
2021  ICSReactions* react;
2022  if(_membrane_flux)
2024  for(react = _reactions; react != NULL; react = react->next)
2025  {
2026  if(react->icsN + react->ecsN > 0)
2027  get_reaction_rates(react, states, rates, ydot);
2028  }
2029 }
2030 
2031 /*****************************************************************************
2032 *
2033 * End intracellular code
2034 *
2035 *****************************************************************************/
2036 
2037 
2038 
2039 
MAT * m_get(int, int)
Definition: memory.c:36
NrnThread * nrn_threads
Definition: rxd.cpp:36
int * indices
Definition: rxd.h:54
union PyHocObject::@42 u
int * react_offsets
Definition: grids.h:201
int px_free(PERM *)
Definition: memory.c:201
void free_curr_ptrs()
Definition: rxd.cpp:155
void(* fptr)(void)
Definition: rxd.h:9
static void free_currents()
Definition: rxd.cpp:663
MAT * LUfactor(MAT *A, PERM *pivot)
Definition: lufactor.c:46
int prev_structure_change_cnt
Definition: rxd.cpp:18
#define assert(ex)
Definition: hocassrt.h:26
#define PyInt_Check
Definition: nrnpython.h:25
bool hybrid
Definition: grids.h:128
void * result
Definition: rxd.h:107
double * _node_flux_scale
Definition: rxd.cpp:102
int * _cur_node_indices
Definition: rxd.cpp:81
int *** state_idx
Definition: rxd.h:65
void _ecs_ode_reinit(double *)
void solve_reaction(ICSReactions *react, double *states, double *bval, double *cvode_states, double *cvode_b)
Definition: rxd.cpp:1691
Definition: rxd.h:111
int length
Definition: rxd.h:55
long * _node_flux_idx
Definition: rxd.cpp:101
double * local_induced_currents
Definition: grids.h:215
void * args
Definition: rxd.h:106
void rxd_set_euler_matrix(int nrow, int nnonzero, long *nonzero_i, long *nonzero_j, double *nonzero_values, double *c_diagonal)
Definition: rxd.cpp:388
struct TaskList * last
Definition: rxd.h:119
int rxd_nonvint_block(int method, int size, double *p1, double *p2, int)
Definition: rxd.cpp:850
unsigned char diffusion
Definition: rxd.cpp:39
int _memb_curr_nodes
Definition: rxd.cpp:76
void _ode_reinit(double *y)
Definition: rxd.cpp:1382
struct ICSReactions * next
Definition: rxd.h:83
Definition: rxd.h:103
#define SAFE_FREE(ptr)
Definition: grids.h:13
#define g
Definition: passive0.cpp:23
int * _curr_indices
Definition: rxd.cpp:66
void clear_rates_ecs()
struct TaskList * next
Definition: rxd.h:108
ECS_Grid_node ** ecs_grid
Definition: rxd.h:75
static void mul(int nnonzero, long *nonzero_i, long *nonzero_j, const double *nonzero_values, const double *v, double *result)
Definition: rxd.cpp:512
size_t p
Represent main neuron object computed by single thread.
Definition: multicore.h:58
long * _rxd_zero_volume_indices
Definition: rxd.cpp:44
fptr _setup_matrices
Definition: rxd.cpp:35
int _memb_curr_total
Definition: rxd.cpp:74
#define TRUE
Definition: err.c:57
int * ecs_offset_index
Definition: rxd.h:74
int size_x
Definition: grids.h:118
void TaskQueue_sync(TaskQueue *q)
Definition: rxd.cpp:1324
int _nrnunit_use_legacy_
Definition: hoc_init.cpp:273
unsigned char _membrane_flux
Definition: rxd.cpp:97
#define m_set_val(A, i, j, val)
Definition: matrix.h:277
static int nrnmpi_use
Definition: multisplit.cpp:48
struct SpeciesIndexList * next
Definition: rxd.h:56
double * dt_ptr
Definition: grids.cpp:14
static int ode_count(int type)
Definition: kschan.cpp:114
void set_num_threads(const int n)
Definition: rxd.cpp:1287
void _rhs_variable_step(const double *p1, double *p2)
Definition: rxd.cpp:1407
#define v
Definition: md1redef.h:4
int size_y
Definition: grids.h:119
Item * next(Item *item)
Definition: list.cpp:95
static void nrn_tree_solve(double *a, double *b, double *c, double *dbase, double *rhs, long *pindex, long n, double dt)
Definition: rxd.cpp:542
static void * allocopy(void *src, size_t size)
Definition: rxd.cpp:130
static philox4x32_key_t k
Definition: nrnran123.cpp:11
void ecs_atolscale(double *)
void start_threads(const int n)
Definition: rxd.cpp:1188
long * _rxd_euler_nonzero_i
Definition: rxd.cpp:41
double * set_rxd_currents(int, int *, PyHocObject **)
Definition: grids.cpp:891
#define v_get_val(x, i)
Definition: rxd.h:4
static int _cvode_offset
Definition: rxd.cpp:52
void rxd_setup_curr_ptrs(int num_currents, int *curr_index, double *curr_scale, PyHocObject **curr_ptrs)
Definition: rxd.cpp:181
void _fadvance(void)
Definition: rxd.cpp:1338
double ** mc_multiplier
Definition: rxd.h:80
pthread_cond_t * task_cond
Definition: rxd.h:114
fptr _initialize
Definition: rxd.cpp:35
unsigned int * _rxd_zvi_child_count
Definition: rxd.cpp:50
double dt
Definition: init.cpp:123
double * _curr_scales
Definition: rxd.cpp:67
double * all_reaction_states
Definition: grids.h:213
Grid_node * Parallel_grids[100]
Definition: grids.cpp:16
TaskQueue * AllTasks
Definition: rxd.cpp:28
double _dt
Definition: multicore.h:60
Definition: matrix.h:67
void species_atolscale(int id, double scale, int len, int *idx)
Definition: rxd.cpp:1117
Item * prev(Item *item)
Definition: list.cpp:101
void set_initialize(const fptr initialize_fn)
Definition: rxd.cpp:527
void do_ics_reactions(double *states, double *b, double *cvode_states, double *cvode_b)
Definition: rxd.cpp:2009
void _rhs_variable_step_ecs(const double *, double *)
void register_rate(int nspecies, int nparam, int nregions, int nseg, int *sidx, int necs, int necsparam, int *ecs_ids, int *ecsidx, int nmult, double *mult, PyHocObject **vptrs, ReactionRate f)
Definition: rxd.cpp:937
static void _currents(double *rhs)
Definition: rxd.cpp:812
double * _rxd_flux_scale
Definition: rxd.cpp:79
int const size_t const size_t n
Definition: nrngsl.h:12
static void free_zvi_child()
Definition: rxd.cpp:105
int nrnmpi_numprocs
double * t_ptr
Definition: grids.cpp:15
VEC * LUsolve(MAT *A, PERM *pivot, VEC *b, VEC *x)
Definition: lufactor.c:140
int icsN
Definition: rxd.h:66
int val
Definition: dll.cpp:167
void get_all_reaction_rates(double *states, double *rates, double *ydot)
Definition: rxd.cpp:2019
pthread_mutex_t * task_mutex
Definition: rxd.h:113
#define printf
Definition: mwprefix.h:26
int
Definition: nrnmusic.cpp:71
double * _rxd_euler_nonzero_values
Definition: rxd.cpp:43
double * _rxd_a
Definition: rxd.cpp:45
void rxd_set_no_diffusion()
Definition: rxd.cpp:137
double * states
Definition: grids.h:113
fptr _setup_units
Definition: rxd.cpp:35
int m_free(MAT *)
PyObject ** _node_flux_src
Definition: rxd.cpp:103
PyTypeObject * hocobject_type
Definition: nrnpy_hoc.cpp:162
double * _rxd_induced_currents_scale
Definition: rxd.cpp:80
size_t j
void remove_species_atolscale(int id)
Definition: rxd.cpp:1149
#define v_set_val(x, i, val)
Definition: matrix.h:265
double * node_flux_scale
Definition: grids.h:168
long * _rxd_p
Definition: rxd.cpp:49
virtual void variable_step_hybrid_connections(const double *cvode_states_3d, double *const ydot_3d, const double *cvode_states_1d, double *const ydot_1d)=0
int num_segments
Definition: rxd.h:64
static void transfer_to_legacy()
Definition: rxd.cpp:120
unsigned char initialized
Definition: rxd.cpp:20
static void add_currents(double *result)
Definition: rxd.cpp:485
int num_ecs_species
Definition: rxd.h:71
int * _memb_species_count
Definition: rxd.cpp:84
int _conc_count
Definition: rxd.cpp:69
double * _rxd_b
Definition: rxd.cpp:46
pthread_t * Threads
Definition: rxd.cpp:27
unsigned int num_states
Definition: rxd.cpp:63
void apply_node_flux(int n, long *index, double *scale, PyObject **source, double dt, double *states)
Definition: rxd.cpp:321
int _rxd_euler_nnonzero
Definition: rxd.cpp:40
double * _rxd_c
Definition: rxd.cpp:47
int _curr_count
Definition: rxd.cpp:65
int num_regions
Definition: rxd.h:62
static double v_get(void *v)
Definition: ivocvect.cpp:1309
double *** ecs_state
Definition: rxd.h:73
double ** _conc_ptrs
Definition: rxd.cpp:71
void get_reaction_rates(ICSReactions *react, double *states, double *rates, double *ydot)
Definition: rxd.cpp:1516
void _fadvance_fixed_step_3D(void)
void rxd_include_node_flux1D(int n, long *index, double *scales, PyObject **sources)
Definition: rxd.cpp:301
void setup_currents(int num_currents, int num_fluxes, int *num_species, int *node_idxs, double *scales, PyHocObject **ptrs, int *mapped, int *mapped_ecs)
Definition: rxd.cpp:690
double ** vptrs
Definition: rxd.h:82
double atolscale
Definition: rxd.h:53
#define rhs
Definition: lineq.h:6
SpeciesIndexList * species_indices
Definition: rxd.cpp:59
int induced_idx
Definition: grids.h:200
int NUM_THREADS
Definition: rxd.cpp:26
double * _rxd_induced_currents
Definition: rxd.cpp:94
int structure_change_cnt
Definition: cvodeobj.cpp:75
void rxd_include_node_flux3D(int grid_count, int *grid_counts, int *grids, long *index, double *scales, PyObject **sources)
Definition: rxd.cpp:214
double ** _curr_ptrs
Definition: rxd.cpp:68
ICSReactions * _reactions
Definition: rxd.cpp:56
double * px_
Definition: grids.h:41
int size_z
Definition: grids.h:120
int num_params
Definition: rxd.h:63
int states_cvode_offset
static void apply_node_flux1D(double dt, double *states)
Definition: rxd.cpp:383
void rxd_setup_conc_ptrs(int conc_count, int *conc_index, PyHocObject **conc_ptrs)
Definition: rxd.cpp:199
void set_setup_units(fptr setup_units)
Definition: rxd.cpp:536
double _t
Definition: multicore.h:59
int node_flux_count
Definition: grids.h:166
int _num_reactions
Definition: rxd.cpp:64
int v_free(VEC *)
int length
Definition: rxd.h:117
pthread_mutex_t * waiting_mutex
Definition: rxd.h:115
int nrnmpi_myid
int ** _memb_cur_charges
Definition: rxd.cpp:90
int * _membrane_lookup
Definition: rxd.cpp:98
void flux(Item *qREACTION, Item *qdir, Item *qlast)
Definition: kinetic.cpp:221
ECS_Grid_node ** _rxd_induced_currents_grid
Definition: rxd.cpp:95
int _memb_count
Definition: rxd.cpp:78
PERM * px_get(int)
int * _conc_indices
Definition: rxd.cpp:70
void * TaskQueue_exe_tasks(void *dat)
Definition: rxd.cpp:1242
int prev_nrnunit_use_legacy
Definition: rxd.cpp:19
#define FALSE
Definition: err.c:56
int _node_flux_count
Definition: rxd.cpp:100
Grid_node * next
Definition: grids.h:111
#define i
Definition: md1redef.h:12
static int _ecs_count
Definition: rxd.cpp:53
#define id
Definition: md1redef.h:33
pthread_cond_t * waiting_cond
Definition: rxd.h:116
#define c
int get_num_threads(void)
Definition: rxd.cpp:1333
int num_ecs_params
Definition: rxd.h:72
PyObject ** node_flux_src
Definition: grids.h:169
double *** _memb_cur_ptrs
Definition: rxd.cpp:89
struct TaskList * first
Definition: rxd.h:118
fptr _setup
Definition: rxd.cpp:35
int ecsN
Definition: rxd.h:77
long ** _rxd_zvi_child
Definition: rxd.cpp:51
int _rxd_num_zvi
Definition: rxd.cpp:40
ReactionRate reaction
Definition: rxd.h:60
double x_
Definition: grids.h:38
void set_num_threads_3D(int n)
int _rxd_euler_nrow
Definition: rxd.cpp:40
void MEM_ZERO(char *ptr, int len)
Definition: extras.c:58
long * node_flux_idx
Definition: grids.h:167
int type_
Definition: grids.h:47
#define SPECIES_ABSENT
Definition: rxd.h:6
void initialize_multicompartment_reaction()
Definition: grids.cpp:1080
void ics_ode_solve(double, double *, const double *)
void free_conc_ptrs()
Definition: rxd.cpp:169
double t
Definition: init.cpp:123
int *** _memb_cur_mapped
Definition: rxd.cpp:91
size_t q
int num_mult
Definition: rxd.h:79
int num_species
Definition: rxd.h:61
Definition: matrix.h:87
void(* ReactionRate)(double **, double **, double **, double *, double *, double *, double *, double **, double)
Definition: grids.h:84
#define PyInt_AsLong
Definition: nrnpython.h:28
void clear_rates()
Definition: rxd.cpp:1077
void set_setup_matrices(fptr setup_matrices)
Definition: rxd.cpp:532
static void ode_abs_tol(double *p1)
Definition: rxd.cpp:644
double * _rxd_d
Definition: rxd.cpp:48
void TaskQueue_add_task(TaskQueue *q, void *(*task)(void *), void *args, void *result)
Definition: rxd.cpp:1210
return NULL
Definition: cabcode.cpp:461
Definition: matrix.h:73
void *(* task)(void *)
Definition: rxd.h:105
short index
Definition: cabvars.h:11
double * states
Definition: rxd.cpp:62
static double jacobian(void *v)
Definition: cvodeobj.cpp:265
static void ode_solve(double, double *, double *)
Definition: rxd.cpp:594
long * _rxd_euler_nonzero_j
Definition: rxd.cpp:42
void setup_solver(double *my_states, int my_num_states, long *zvi, int num_zvi)
Definition: rxd.cpp:1169
void set_setup(const fptr setup_fn)
Definition: rxd.cpp:523
int ** ecs_index
Definition: rxd.h:76
int add_multicompartment_reaction(int, int *, int)
Definition: grids.cpp:1034
int *** _memb_cur_mapped_ecs
Definition: rxd.cpp:92