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