NEURON
grids.cpp
Go to the documentation of this file.
1 /******************************************************************
2 Author: Austin Lachance
3 Date: 10/28/16
4 Description: Defines the functions for implementing and manipulating
5 a linked list of Grid_nodes
6 ******************************************************************/
7 #include <stdio.h>
8 #include <assert.h>
9 #include "nrnpython.h"
10 #include "grids.h"
11 #include "rxd.h"
12 
13 extern int NUM_THREADS;
14 double* dt_ptr;
15 double* t_ptr;
17 
18 /* globals used by ECS do_currents */
19 extern TaskQueue* AllTasks;
20 /*Current from multicompartment reations*/
21 extern int _memb_curr_total;
22 extern int* _rxd_induced_currents_grid;
24 extern double* _rxd_induced_currents_ecs;
25 extern double* _rxd_induced_currents_scale;
26 
27 // Set dt, t pointers
28 extern "C" void make_time_ptr(PyHocObject* my_dt_ptr, PyHocObject* my_t_ptr) {
29  dt_ptr = my_dt_ptr->u.px_;
30  t_ptr = my_t_ptr->u.px_;
31 }
32 
33 static double get_alpha_scalar(double* alpha, int) {
34  return alpha[0];
35 }
36 static double get_alpha_array(double* alpha, int idx) {
37  return alpha[idx];
38 }
39 
40 
41 static double get_permeability_scalar(double*, int) {
42  return 1.; /*already rescale the diffusion coefficients*/
43 }
44 static double get_permeability_array(double* permeability, int idx) {
45  return permeability[idx];
46 }
47 
48 // Make a new Grid_node given required Grid_node parameters
51  int my_num_states_x,
52  int my_num_states_y,
53  int my_num_states_z,
54  double my_dc_x,
55  double my_dc_y,
56  double my_dc_z,
57  double my_dx,
58  double my_dy,
59  double my_dz,
60  PyHocObject* my_alpha,
61  PyHocObject* my_permeability,
62  int bc_type,
63  double bc_value,
64  double atolscale) {
65  int k;
66  states = my_states->u.px_;
67 
68  /*TODO: When there are multiple grids share the largest intermediate arrays to save memory*/
69  /*intermediate states for DG-ADI*/
70  states_x = (double*) malloc(sizeof(double) * my_num_states_x * my_num_states_y *
71  my_num_states_z);
72  states_y = (double*) malloc(sizeof(double) * my_num_states_x * my_num_states_y *
73  my_num_states_z);
74  states_cur = (double*) malloc(sizeof(double) * my_num_states_x * my_num_states_y *
75  my_num_states_z);
76 
77  size_x = my_num_states_x;
78  size_y = my_num_states_y;
79  size_z = my_num_states_z;
80 
81  dc_x = my_dc_x;
82  dc_y = my_dc_y;
83  dc_z = my_dc_z;
84  diffusable = (dc_x > 0) || (dc_y > 0) || (dc_z > 0);
85 
86  dx = my_dx;
87  dy = my_dy;
88  dz = my_dz;
89 
93  num_currents = 0;
94 
95  next = NULL;
97 
98  /*Check to see if variable tortuosity/volume fraction is used*/
99  if (PyFloat_Check(my_permeability)) {
100  /*note permeability is the tortuosity squared*/
101  permeability = (double*) malloc(sizeof(double));
102  permeability[0] = PyFloat_AsDouble((PyObject*) my_permeability);
104 
105  /*apply the tortuosity*/
106  dc_x = my_dc_x * permeability[0];
107  dc_y = my_dc_y * permeability[0];
108  dc_z = my_dc_z * permeability[0];
109  } else {
110  permeability = my_permeability->u.px_;
113  }
114 
115  if (PyFloat_Check(my_alpha)) {
116  alpha = (double*) malloc(sizeof(double));
117  alpha[0] = PyFloat_AsDouble((PyObject*) my_alpha);
119 
120  } else {
121  alpha = my_alpha->u.px_;
124  }
125 #if NRNMPI
126  if (nrnmpi_use) {
127  proc_offsets = (int*) calloc(nrnmpi_numprocs, sizeof(int));
128  proc_num_currents = (int*) calloc(nrnmpi_numprocs, sizeof(int));
129  proc_flux_offsets = (int*) calloc(nrnmpi_numprocs, sizeof(int));
130  proc_num_fluxes = (int*) calloc(nrnmpi_numprocs, sizeof(int));
131  proc_num_reactions = (int*) calloc(nrnmpi_numprocs, sizeof(int));
132  proc_num_reaction_states = (int*) calloc(nrnmpi_numprocs, sizeof(int*));
133  proc_induced_current_count = (int*) calloc(nrnmpi_numprocs, sizeof(int*));
134  proc_induced_current_offset = (int*) calloc(nrnmpi_numprocs, sizeof(int*));
135  }
136 #endif
140  react_offsets = (int*) calloc(1, sizeof(int));
143  react_offset_count = 1;
144  num_all_currents = 0;
145  current_dest = NULL;
146  all_currents = NULL;
152 
153  bc = (BoundaryConditions*) malloc(sizeof(BoundaryConditions));
154  bc->type = bc_type;
155  bc->value = bc_value;
156 
157  ecs_tasks = NULL;
158  ecs_tasks = (ECSAdiGridData*) malloc(NUM_THREADS * sizeof(ECSAdiGridData));
159  for (k = 0; k < NUM_THREADS; k++) {
160  ecs_tasks[k].scratchpad = (double*) malloc(
161  sizeof(double) * MAX(my_num_states_x, MAX(my_num_states_y, my_num_states_z)));
162  ecs_tasks[k].g = this;
163  }
164 
165 
166  ecs_adi_dir_x = (ECSAdiDirection*) malloc(sizeof(ECSAdiDirection));
169  ecs_adi_dir_x->line_size = my_num_states_x;
170 
171 
172  ecs_adi_dir_y = (ECSAdiDirection*) malloc(sizeof(ECSAdiDirection));
175  ecs_adi_dir_y->line_size = my_num_states_y;
176 
177 
178  ecs_adi_dir_z = (ECSAdiDirection*) malloc(sizeof(ECSAdiDirection));
181  ecs_adi_dir_z->line_size = my_num_states_z;
182 
183  this->atolscale = atolscale;
184 
185  node_flux_count = 0;
189  hybrid = false;
190  volume_setup();
191 }
192 
193 
194 // Insert a Grid_node "new_Grid" into the list located at grid_list_index in Parallel_grids
195 /* returns the grid number
196  TODO: change this to returning the pointer */
197 extern "C" int ECS_insert(int grid_list_index,
198  PyHocObject* my_states,
199  int my_num_states_x,
200  int my_num_states_y,
201  int my_num_states_z,
202  double my_dc_x,
203  double my_dc_y,
204  double my_dc_z,
205  double my_dx,
206  double my_dy,
207  double my_dz,
208  PyHocObject* my_alpha,
209  PyHocObject* my_permeability,
210  int bc,
211  double bc_value,
212  double atolscale) {
213  ECS_Grid_node* new_Grid = new ECS_Grid_node(my_states,
214  my_num_states_x,
215  my_num_states_y,
216  my_num_states_z,
217  my_dc_x,
218  my_dc_y,
219  my_dc_z,
220  my_dx,
221  my_dy,
222  my_dz,
223  my_alpha,
224  my_permeability,
225  bc,
226  bc_value,
227  atolscale);
228 
229  return new_Grid->insert(grid_list_index);
230 }
231 
234  long num_nodes,
235  long* neighbors,
236  long* x_line_defs,
237  long x_lines_length,
238  long* y_line_defs,
239  long y_lines_length,
240  long* z_line_defs,
241  long z_lines_length,
242  double* dc,
243  double* dcgrid,
244  double dx,
245  bool is_diffusable,
246  double atolscale,
247  double* ics_alphas) {
248  int k;
249  ics_num_segs = 0;
250  _num_nodes = num_nodes;
251  diffusable = is_diffusable;
252  this->atolscale = atolscale;
253 
254  states = my_states->u.px_;
255  states_x = (double*) malloc(sizeof(double) * _num_nodes);
256  states_y = (double*) malloc(sizeof(double) * _num_nodes);
257  states_z = (double*) malloc(sizeof(double) * _num_nodes);
258  states_cur = (double*) malloc(sizeof(double) * _num_nodes);
259  next = NULL;
260 
261  size_x = _num_nodes;
262  size_y = 1;
263  size_z = 1;
264 
265 
267  num_concentrations = 0;
268  current_list = NULL;
269  num_currents = 0;
270  node_flux_count = 0;
271 
277 
278 #if NRNMPI
279  if (nrnmpi_use) {
280  proc_offsets = (int*) malloc(nrnmpi_numprocs * sizeof(int));
281  proc_num_currents = (int*) calloc(nrnmpi_numprocs, sizeof(int));
282  proc_num_fluxes = (int*) calloc(nrnmpi_numprocs, sizeof(int));
283  proc_flux_offsets = (int*) malloc(nrnmpi_numprocs * sizeof(int));
284  }
285 #endif
286  num_all_currents = 0;
287  current_dest = NULL;
288  all_currents = NULL;
289 
290  _ics_alphas = ics_alphas;
292 
293  // stores the positive x,y, and z neighbors for each node. [node0_x, node0_y, node0_z, node1_x
294  // ...]
295  _neighbors = neighbors;
296 
297  /*Line definitions from Python. In pattern of [line_start_node, line_length, ...]
298  Array is sorted from longest to shortest line */
299  _sorted_x_lines = x_line_defs;
300  _sorted_y_lines = y_line_defs;
301  _sorted_z_lines = z_line_defs;
302 
303  // Lengths of _sorted_lines arrays. Used to find thread start and stop indices
304  _x_lines_length = x_lines_length;
305  _y_lines_length = y_lines_length;
306  _z_lines_length = z_lines_length;
307 
308  // Find the maximum line length for scratchpad memory allocation
309  long x_max = x_line_defs[1];
310  long y_max = y_line_defs[1];
311  long z_max = z_line_defs[1];
312  long xy_max = (x_max > y_max) ? x_max : y_max;
313  _line_length_max = (z_max > xy_max) ? z_max : xy_max;
314 
315  ics_tasks = (ICSAdiGridData*) malloc(NUM_THREADS * sizeof(ICSAdiGridData));
316 
317  for (k = 0; k < NUM_THREADS; k++) {
318  ics_tasks[k].RHS = (double*) malloc(sizeof(double) * (_line_length_max));
319  ics_tasks[k].scratchpad = (double*) malloc(sizeof(double) * (_line_length_max - 1));
320  ics_tasks[k].g = this;
321  ics_tasks[k].u_diag = (double*) malloc(sizeof(double) * _line_length_max - 1);
322  ics_tasks[k].diag = (double*) malloc(sizeof(double) * _line_length_max);
323  ics_tasks[k].l_diag = (double*) malloc(sizeof(double) * _line_length_max - 1);
324  }
325 
326  hybrid = false;
327  hybrid_data = (Hybrid_data*) malloc(sizeof(Hybrid_data));
328 
329  ics_adi_dir_x = (ICSAdiDirection*) malloc(sizeof(ICSAdiDirection));
332  ics_adi_dir_x->ordered_start_stop_indices = (long*) malloc(sizeof(long) * NUM_THREADS * 2);
333  ics_adi_dir_x->line_start_stop_indices = (long*) malloc(sizeof(long) * NUM_THREADS * 2);
334  ics_adi_dir_x->ordered_nodes = (long*) malloc(sizeof(long) * _num_nodes);
335  ics_adi_dir_x->ordered_line_defs = (long*) malloc(sizeof(long) * _x_lines_length);
336  ics_adi_dir_x->deltas = (double*) malloc(sizeof(double) * _num_nodes);
337  ics_adi_dir_x->d = dx;
338 
339  ics_adi_dir_y = (ICSAdiDirection*) malloc(sizeof(ICSAdiDirection));
342  ics_adi_dir_y->ordered_start_stop_indices = (long*) malloc(sizeof(long) * NUM_THREADS * 2);
343  ics_adi_dir_y->line_start_stop_indices = (long*) malloc(sizeof(long) * NUM_THREADS * 2);
344  ics_adi_dir_y->ordered_nodes = (long*) malloc(sizeof(long) * _num_nodes);
345  ics_adi_dir_y->ordered_line_defs = (long*) malloc(sizeof(long) * _y_lines_length);
346  ics_adi_dir_y->deltas = (double*) malloc(sizeof(double) * _num_nodes);
347  ics_adi_dir_y->d = dx;
348 
349  ics_adi_dir_z = (ICSAdiDirection*) malloc(sizeof(ICSAdiDirection));
352  ics_adi_dir_z->ordered_start_stop_indices = (long*) malloc(sizeof(long) * NUM_THREADS * 2);
353  ics_adi_dir_z->line_start_stop_indices = (long*) malloc(sizeof(long) * NUM_THREADS * 2);
354  ics_adi_dir_z->ordered_nodes = (long*) malloc(sizeof(long) * _num_nodes);
355  ics_adi_dir_z->ordered_line_defs = (long*) malloc(sizeof(long) * _z_lines_length);
356  ics_adi_dir_z->deltas = (double*) malloc(sizeof(double) * _num_nodes);
357  ics_adi_dir_z->d = dx;
358 
359  if (dcgrid == NULL) {
360  ics_adi_dir_x->dc = dc[0];
361  ics_adi_dir_y->dc = dc[1];
362  ics_adi_dir_z->dc = dc[2];
366  } else {
367  ics_adi_dir_x->dcgrid = dcgrid;
368  ics_adi_dir_y->dcgrid = &dcgrid[_num_nodes];
369  ics_adi_dir_z->dcgrid = &dcgrid[2 * _num_nodes];
370  }
371  volume_setup();
375 
376  node_flux_count = 0;
380 }
381 
382 
383 // Insert a Grid_node "new_Grid" into the list located at grid_list_index in Parallel_grids
384 /* returns the grid number
385  TODO: change this to returning the pointer */
386 extern "C" int ICS_insert(int grid_list_index,
387  PyHocObject* my_states,
388  long num_nodes,
389  long* neighbors,
390  long* x_line_defs,
391  long x_lines_length,
392  long* y_line_defs,
393  long y_lines_length,
394  long* z_line_defs,
395  long z_lines_length,
396  double* dcs,
397  double dx,
398  bool is_diffusable,
399  double atolscale,
400  double* ics_alphas) {
401  ICS_Grid_node* new_Grid = new ICS_Grid_node(my_states,
402  num_nodes,
403  neighbors,
404  x_line_defs,
405  x_lines_length,
406  y_line_defs,
407  y_lines_length,
408  z_line_defs,
409  z_lines_length,
410  dcs,
411  NULL,
412  dx,
413  is_diffusable,
414  atolscale,
415  ics_alphas);
416 
417  return new_Grid->insert(grid_list_index);
418 }
419 
420 int ICS_insert_inhom(int grid_list_index,
421  PyHocObject* my_states,
422  long num_nodes,
423  long* neighbors,
424  long* x_line_defs,
425  long x_lines_length,
426  long* y_line_defs,
427  long y_lines_length,
428  long* z_line_defs,
429  long z_lines_length,
430  double* dcs,
431  double dx,
432  bool is_diffusable,
433  double atolscale,
434  double* ics_alphas) {
435  ICS_Grid_node* new_Grid = new ICS_Grid_node(my_states,
436  num_nodes,
437  neighbors,
438  x_line_defs,
439  x_lines_length,
440  y_line_defs,
441  y_lines_length,
442  z_line_defs,
443  z_lines_length,
444  NULL,
445  dcs,
446  dx,
447  is_diffusable,
448  atolscale,
449  ics_alphas);
450  return new_Grid->insert(grid_list_index);
451 }
452 
453 
454 extern "C" int set_diffusion(int grid_list_index, int grid_id, double* dc, int length) {
455  int id = 0;
456  Grid_node* node = Parallel_grids[grid_list_index];
457  while (id < grid_id) {
458  node = node->next;
459  id++;
460  if (node == NULL)
461  return -1;
462  }
463  node->set_diffusion(dc, length);
464  return 0;
465 }
466 
467 extern "C" int set_tortuosity(int grid_list_index, int grid_id, PyHocObject* my_permeability) {
468  int id = 0;
469  Grid_node* node = Parallel_grids[grid_list_index];
470  while (id < grid_id) {
471  node = node->next;
472  id++;
473  if (node == NULL)
474  return -1;
475  }
476  static_cast<ECS_Grid_node*>(node)->set_tortuosity(my_permeability);
477  return 0;
478 }
479 
480 
482  /*Check to see if variable tortuosity/volume fraction is used*/
483  /*note permeability is the 1/tortuosity^2*/
484  if (PyFloat_Check(my_permeability)) {
486  double new_permeability = PyFloat_AsDouble((PyObject*) my_permeability);
488  dc_x *= new_permeability / permeability[0];
489  dc_y *= new_permeability / permeability[0];
490  dc_z *= new_permeability / permeability[0];
491  permeability[0] = new_permeability;
492  } else {
493  permeability = (double*) malloc(sizeof(double));
494  permeability[0] = PyFloat_AsDouble((PyObject*) my_permeability);
495  /* don't free the old permeability -- let python do it */
496  dc_x *= permeability[0];
497  dc_y *= permeability[0];
498  dc_z *= permeability[0];
501  }
502  } else {
504  /* rescale to remove old permeability*/
505  dc_x /= permeability[0];
506  dc_y /= permeability[0];
507  dc_z /= permeability[0];
508  free(permeability);
509  permeability = my_permeability->u.px_;
512  } else {
513  permeability = my_permeability->u.px_;
514  }
515  }
516 }
517 
518 extern "C" int set_volume_fraction(int grid_list_index, int grid_id, PyHocObject* my_alpha) {
519  int id = 0;
520  Grid_node* node = Parallel_grids[grid_list_index];
521  while (id < grid_id) {
522  node = node->next;
523  id++;
524  if (node == NULL)
525  return -1;
526  }
527  static_cast<ECS_Grid_node*>(node)->set_volume_fraction(my_alpha);
528  return 0;
529 }
530 
532  if (PyFloat_Check(my_alpha)) {
533  if (get_alpha == &get_alpha_scalar) {
534  alpha[0] = PyFloat_AsDouble((PyObject*) my_alpha);
535  } else {
536  alpha = (double*) malloc(sizeof(double));
537  alpha[0] = PyFloat_AsDouble((PyObject*) my_alpha);
540  : FALSE;
541  }
542  } else {
543  if (get_alpha == &get_alpha_scalar)
544  free(alpha);
545  alpha = my_alpha->u.px_;
548  }
549 }
550 
551 
552 /*Set the diffusion coefficients*/
553 void ICS_Grid_node::set_diffusion(double* dc, int length) {
554  if (length == 1) {
555  ics_adi_dir_x->dc = dc[0];
556  ics_adi_dir_y->dc = dc[1];
557  ics_adi_dir_z->dc = dc[2];
558  // NOTE: dcgrid is owned by _IntracellularSpecies in python
559  if (ics_adi_dir_x->dcgrid != NULL) {
563  }
564  } else {
565  assert(length == _num_nodes);
569  }
570  volume_setup();
571 }
572 
573 
574 /*Set the diffusion coefficients*/
575 void ECS_Grid_node::set_diffusion(double* dc, int) {
577  /* note permeability[0] is the tortuosity squared*/
578  dc_x = dc[0] * permeability[0];
579  dc_y = dc[1] * permeability[0];
580  dc_z = dc[2] * permeability[0];
581  } else {
582  dc_x = dc[0];
583  dc_y = dc[1];
584  dc_z = dc[2];
585  }
586  diffusable = (dc_x > 0) || (dc_y > 0) || (dc_z > 0);
587 }
588 
589 
590 extern "C" void ics_set_grid_concentrations(int grid_list_index,
591  int index_in_list,
592  int64_t* nodes_per_seg,
593  int64_t* nodes_per_seg_start_indices,
594  PyObject* neuron_pointers) {
595  Grid_node* g;
596  ssize_t i;
597  ssize_t n = (ssize_t) PyList_Size(neuron_pointers); // number of segments.
598 
599  /* Find the Grid Object */
600  g = Parallel_grids[grid_list_index];
601  for (i = 0; i < index_in_list; i++) {
602  g = g->next;
603  }
604 
605  g->ics_surface_nodes_per_seg = nodes_per_seg;
606 
607  g->ics_surface_nodes_per_seg_start_indices = nodes_per_seg_start_indices;
608 
609  g->ics_concentration_seg_ptrs = (double**) malloc(n * sizeof(double*));
610  for (i = 0; i < n; i++) {
611  g->ics_concentration_seg_ptrs[i] =
612  ((PyHocObject*) PyList_GET_ITEM(neuron_pointers, i))->u.px_;
613  }
614 
615  g->ics_num_segs = n;
616 }
617 
618 extern "C" void ics_set_grid_currents(int grid_list_index,
619  int index_in_list,
620  PyObject* neuron_pointers,
621  double* scale_factors) {
622  Grid_node* g;
623  ssize_t i;
624  ssize_t n = (ssize_t) PyList_Size(neuron_pointers);
625  /* Find the Grid Object */
626  g = Parallel_grids[grid_list_index];
627  for (i = 0; i < index_in_list; i++) {
628  g = g->next;
629  }
630  g->ics_scale_factors = scale_factors;
631 
632  g->ics_current_seg_ptrs = (double**) malloc(n * sizeof(double*));
633 
634  for (i = 0; i < n; i++) {
635  g->ics_current_seg_ptrs[i] = ((PyHocObject*) PyList_GET_ITEM(neuron_pointers, i))->u.px_;
636  }
637 }
638 
639 
640 /* TODO: make this work with Grid_node ptrs instead of pairs of list indices */
641 extern "C" void set_grid_concentrations(int grid_list_index,
642  int index_in_list,
643  PyObject* grid_indices,
644  PyObject* neuron_pointers) {
645  /*
646  Preconditions:
647 
648  Assumes the specified grid has been created.
649  Assumes len(grid_indices) = len(neuron_pointers) and that both are proper python lists
650  */
651  /* TODO: note that these will need updating anytime the structure of the model changes... look
652  * at the structure change count at each advance and trigger a callback to regenerate if
653  * necessary */
654  Grid_node* g;
655  ssize_t i;
656  ssize_t n = (ssize_t) PyList_Size(grid_indices);
657 
658  /* Find the Grid Object */
659  g = Parallel_grids[grid_list_index];
660  for (i = 0; i < index_in_list; i++) {
661  g = g->next;
662  }
663 
664  /* free the old concentration list */
665  free(g->concentration_list);
666 
667  /* allocate space for the new list */
668  g->concentration_list = (Concentration_Pair*) malloc(sizeof(Concentration_Pair) * n);
669  g->num_concentrations = n;
670 
671  /* populate the list */
672  /* TODO: it would be more general to iterate instead of assuming lists and using list lookups */
673  for (i = 0; i < n; i++) {
674  /* printf("set_grid_concentrations %ld\n", i); */
675  g->concentration_list[i].source = PyInt_AS_LONG(PyList_GET_ITEM(grid_indices, i));
676  g->concentration_list[i].destination =
677  ((PyHocObject*) PyList_GET_ITEM(neuron_pointers, i))->u.px_;
678  }
679 }
680 
681 /* TODO: make this work with Grid_node ptrs instead of pairs of list indices */
682 extern "C" void set_grid_currents(int grid_list_index,
683  int index_in_list,
684  PyObject* grid_indices,
685  PyObject* neuron_pointers,
686  PyObject* scale_factors) {
687  /*
688  Preconditions:
689 
690  Assumes the specified grid has been created.
691  Assumes len(grid_indices) = len(neuron_pointers) = len(scale_factors) and that all are proper
692  python lists
693  */
694  /* TODO: note that these will need updating anytime the structure of the model changes... look
695  * at the structure change count at each advance and trigger a callback to regenerate if
696  * necessary */
697  Grid_node* g;
698  ssize_t i;
699  ssize_t n = (ssize_t) PyList_Size(grid_indices);
700  long* dests;
701 
702  /* Find the Grid Object */
703  g = Parallel_grids[grid_list_index];
704  for (i = 0; i < index_in_list; i++) {
705  g = g->next;
706  }
707 
708  /* free the old current list */
709  free(g->current_list);
710 
711  /* allocate space for the new list */
712  g->current_list = (Current_Triple*) malloc(sizeof(Current_Triple) * n);
713  g->num_currents = n;
714 
715  /* populate the list */
716  /* TODO: it would be more general to iterate instead of assuming lists and using list lookups */
717  for (i = 0; i < n; i++) {
718  g->current_list[i].destination = PyInt_AS_LONG(PyList_GET_ITEM(grid_indices, i));
719  g->current_list[i].scale_factor = PyFloat_AS_DOUBLE(PyList_GET_ITEM(scale_factors, i));
720  g->current_list[i].source = ((PyHocObject*) PyList_GET_ITEM(neuron_pointers, i))->u.px_;
721  /* printf("set_grid_currents %ld out of %ld, %ld, %ld\n", i, n,
722  * PyList_Size(neuron_pointers), PyList_Size(scale_factors)); */
723  } /*
724  if (PyErr_Occurred()) {
725  printf("uh oh\n");
726  PyErr_PrintEx(0);
727  } else {
728  printf("no problems\n");
729  }
730  PyErr_Clear(); */
731 
732 #if NRNMPI
733  if (nrnmpi_use) {
734  /*Gather an array of the number of currents for each process*/
735  g->proc_num_currents[nrnmpi_myid] = n;
736  nrnmpi_int_allgather_inplace(g->proc_num_currents, 1);
737 
738  g->proc_offsets[0] = 0;
739  for (i = 1; i < nrnmpi_numprocs; i++)
740  g->proc_offsets[i] = g->proc_offsets[i - 1] + g->proc_num_currents[i - 1];
741  g->num_all_currents = g->proc_offsets[i - 1] + g->proc_num_currents[i - 1];
742 
743  /*Copy array of current destinations (index to states) across all processes*/
744  free(g->current_dest);
745  free(g->all_currents);
746  g->current_dest = (long*) malloc(g->num_all_currents * sizeof(long));
747  g->all_currents = (double*) malloc(g->num_all_currents * sizeof(double));
748  dests = g->current_dest + g->proc_offsets[nrnmpi_myid];
749  /*TODO: Get rid of duplication with current_list*/
750  for (i = 0; i < n; i++) {
751  dests[i] = g->current_list[i].destination;
752  }
753  nrnmpi_long_allgatherv_inplace(g->current_dest, g->proc_num_currents, g->proc_offsets);
754  } else {
755  free(g->all_currents);
756  g->all_currents = (double*) malloc(sizeof(double) * g->num_currents);
757  g->num_all_currents = g->num_currents;
758  }
759 #else
760  free(g->all_currents);
761  g->all_currents = (double*) malloc(sizeof(double) * g->num_currents);
762  g->num_all_currents = g->num_currents;
763 #endif
764 }
765 
766 // Delete a specific Grid_node from the list
768  if (*head == find) {
769  Grid_node* temp = *head;
770  *head = (*head)->next;
771  delete temp;
772  return 1;
773  }
774  Grid_node* temp = *head;
775  while (temp->next != find) {
776  temp = temp->next;
777  }
778  if (!temp)
779  return 0;
780  Grid_node* delete_me = temp->next;
781  temp->next = delete_me->next;
782  delete delete_me;
783  return 1;
784 }
785 
786 extern "C" void delete_by_id(int id) {
787  Grid_node* grid;
788  int k;
789  for (k = 0, grid = Parallel_grids[0]; grid != NULL; grid = grid->next, k++) {
790  if (k == id) {
791  remove(Parallel_grids, grid);
792  break;
793  }
794  }
795 }
796 
797 
798 // Destroy the list located at list_index and free all memory
799 void empty_list(int list_index) {
800  Grid_node** head = &(Parallel_grids[list_index]);
801  while (*head != NULL) {
802  Grid_node* old_head = *head;
803  *head = (*head)->next;
804  delete old_head;
805  }
806 }
807 
808 int Grid_node::insert(int grid_list_index) {
809  int i = 0;
810  Grid_node** head = &(Parallel_grids[grid_list_index]);
811 
812  if (!(*head)) {
813  *head = this;
814  } else {
815  i++; /*count the head as the first grid*/
816  Grid_node* end = *head;
817  while (end->next != NULL) {
818  i++;
819  end = end->next;
820  }
821  end->next = this;
822  }
823  return i;
824 }
825 
826 /*****************************************************************************
827  *
828  * Begin ECS_Grid_node Functions
829  *
830  *****************************************************************************/
831 
833  int i;
834  if (ecs_tasks != NULL) {
835  for (i = 0; i < NUM_THREADS; i++) {
836  free(ecs_tasks[i].scratchpad);
837  }
838  }
839  free(ecs_tasks);
840  ecs_tasks = (ECSAdiGridData*) malloc(n * sizeof(ECSAdiGridData));
841  for (i = 0; i < n; i++) {
842  ecs_tasks[i].scratchpad = (double*) malloc(sizeof(double) *
843  MAX(size_x, MAX(size_y, size_z)));
844  ecs_tasks[i].g = this;
845  }
846 }
847 
848 static void* gather_currents(void* dataptr) {
849  CurrentData* d = (CurrentData*) dataptr;
850  Grid_node* grid = d->g;
851  double* val = d->val;
852  int i, start = d->onset, stop = d->offset;
853  Current_Triple* c = grid->current_list;
854  if (grid->VARIABLE_ECS_VOLUME == VOLUME_FRACTION) {
855  for (i = start; i < stop; i++)
856  val[i] = c[i].scale_factor * (*c[i].source) / grid->alpha[c[i].destination];
857  } else if (grid->VARIABLE_ECS_VOLUME == ICS_ALPHA) {
858  // TODO: Check if this is used.
859  for (i = start; i < stop; i++)
860  val[i] = c[i].scale_factor * (*c[i].source) /
861  ((ICS_Grid_node*) grid)->_ics_alphas[c[i].destination];
862  } else {
863  for (i = start; i < stop; i++)
864  val[i] = c[i].scale_factor * (*c[i].source) / grid->alpha[0];
865  }
866  return NULL;
867 }
868 
869 /*
870  * do_current - process the current for a given grid
871  * Grid_node* grid - the grid used
872  * double* output - for fixed step this is the states for variable ydot
873  * double dt - for fixed step the step size, for variable step 1
874  */
875 void ECS_Grid_node::do_grid_currents(double* output, double dt, int grid_id) {
876  ssize_t m, n, i;
877  /*Currents to broadcast via MPI*/
878  /*TODO: Handle multiple grids with one pass*/
879  /*Maybe TODO: Should check #currents << #voxels and not the other way round*/
880  double* val;
881  // MEM_ZERO(output,sizeof(double)*grid->size_x*grid->size_y*grid->size_z);
882  /* currents, via explicit Euler */
884  m = num_currents;
885  CurrentData* tasks = (CurrentData*) malloc(NUM_THREADS * sizeof(CurrentData));
886 #if NRNMPI
888 #else
889  val = all_currents;
890 #endif
891  int tasks_per_thread = (m + NUM_THREADS - 1) / NUM_THREADS;
892 
893  for (i = 0; i < NUM_THREADS; i++) {
894  tasks[i].g = this;
895  tasks[i].onset = i * tasks_per_thread;
896  tasks[i].offset = MIN((i + 1) * tasks_per_thread, m);
897  tasks[i].val = val;
898  }
899  for (i = 0; i < NUM_THREADS - 1; i++) {
901  }
902  /* run one task in the main thread */
903  gather_currents(&tasks[NUM_THREADS - 1]);
904 
905  /* wait for them to finish */
907  free(tasks);
908 #if NRNMPI
909  if (nrnmpi_use) {
910  nrnmpi_dbl_allgatherv_inplace(all_currents, proc_num_currents, proc_offsets);
911  nrnmpi_dbl_allgatherv_inplace(induced_currents,
914  for (i = 0; i < n; i++)
915  output[current_dest[i]] += dt * all_currents[i];
916  } else {
917  for (i = 0; i < n; i++) {
918  output[current_list[i].destination] += dt * all_currents[i];
919  }
920  }
921 
922 #else
923  for (i = 0; i < n; i++)
924  output[current_list[i].destination] += dt * all_currents[i];
925 #endif
926 
927  /*Remove the contribution from membrane currents*/
928  for (i = 0; i < induced_current_count; i++)
931 }
932 
933 double* ECS_Grid_node::set_rxd_currents(int current_count,
934  int* current_indices,
935  PyHocObject** ptrs) {
936  int i, j;
937  double volume_fraction;
938 
941  induced_currents_scale = (double*) calloc(current_count, sizeof(double));
943  induced_current_count = current_count;
944  induced_currents_index = current_indices;
945  for (i = 0; i < current_count; i++) {
946  for (j = 0; j < num_all_currents; j++) {
947  if (ptrs[i]->u.px_ == current_list[j].source) {
948  volume_fraction = (VARIABLE_ECS_VOLUME == VOLUME_FRACTION
950  : alpha[0]);
951  induced_currents_scale[i] = current_list[j].scale_factor / volume_fraction;
952  assert(current_list[j].destination == current_indices[i]);
953  break;
954  }
955  }
956  }
957  return induced_currents_scale;
958 }
959 
960 void ECS_Grid_node::apply_node_flux3D(double dt, double* ydot) {
961  double* dest;
962  if (ydot == NULL)
963  dest = states_cur;
964  else
965  dest = ydot;
966 #if NRNMPI
967  double* sources;
968  int i;
969  int offset;
970 
971  if (nrnmpi_use) {
972  sources = (double*) calloc(node_flux_count, sizeof(double));
973  offset = proc_flux_offsets[nrnmpi_myid];
975  NULL,
976  &node_flux_scale[offset],
978  dt,
979  &sources[offset]);
980 
981  nrnmpi_dbl_allgatherv_inplace(sources, proc_num_fluxes, proc_flux_offsets);
982 
983  for (i = 0; i < node_flux_count; i++)
984  dest[node_flux_idx[i]] += sources[i];
985  free(sources);
986  } else {
988  }
989 #else
991 #endif
992 }
993 
994 
996  switch (VARIABLE_ECS_VOLUME) {
997  case VOLUME_FRACTION:
998  ecs_set_adi_vol(this);
999  break;
1000  case TORTUOSITY:
1001  ecs_set_adi_tort(this);
1002  break;
1003  default:
1005  }
1006 }
1007 
1009  unsigned long i;
1010  if (diffusable) {
1011  /* first step: advance the x direction */
1013 
1014  /* second step: advance the y direction */
1016 
1017  /* third step: advance the z direction */
1019 
1020  /* transfer data */
1021  /*TODO: Avoid copy by switching pointers and updating Python copy
1022  tmp = g->states;
1023  g->states = g->adi_dir_z->states_out;
1024  g->adi_dir_z->states_out = tmp;
1025  */
1026  memcpy(states, ecs_adi_dir_z->states_out, sizeof(double) * size_x * size_y * size_z);
1027  } else {
1028  for (i = 0; i < size_x * size_y * size_z; i++)
1029  states[i] += states_cur[i];
1030  }
1031  // TODO: Should this return 0?
1032  return 0;
1033 }
1034 
1035 void ECS_Grid_node::variable_step_diffusion(const double* states, double* ydot) {
1036  switch (VARIABLE_ECS_VOLUME) {
1037  case VOLUME_FRACTION:
1039  break;
1040  case TORTUOSITY:
1042  break;
1043  default:
1044  _rhs_variable_step_helper(this, states, ydot);
1045  }
1046 }
1047 
1049  ssize_t i, n;
1050  Concentration_Pair* cp;
1051 
1053  cp = concentration_list;
1054  for (i = 0; i < n; i++) {
1055  (*cp[i].destination) = states[cp[i].source];
1056  }
1057 }
1058 
1060 
1062  double* const,
1063  const double*,
1064  double* const) {}
1065 
1066 int ECS_Grid_node::add_multicompartment_reaction(int nstates, int* indices, int step) {
1067  // Set the current reaction offsets and increment the local offset count
1068  // This is stored as an array/pointer so it can be updated if the grid is
1069  // on multiple MPI nodes.
1070  int i = 0, j = 0;
1071  int offset = react_offsets[react_offset_count - 1];
1072  // Increase the size of the reaction indices to accomidate the maximum
1073  // number of potential new indicies
1074  reaction_indices = (int*) realloc(reaction_indices, (offset + nstates) * sizeof(int));
1075  // TODO: Aggregate the common indicies on the local node, so the state
1076  // changes can be added together before they are broadcast.
1077  for (i = 0, j = 0; i < nstates; i++, j += step) {
1078  if (indices[j] != SPECIES_ABSENT)
1079  reaction_indices[offset++] = indices[j];
1080  }
1081  // Resize to remove ununused indices
1082  if (offset < react_offsets[react_offset_count - 1] + nstates)
1083  reaction_indices = (int*) realloc((void*) reaction_indices, offset * sizeof(int));
1084 
1085  // Store the new offset and return the start offset to the Reaction
1086  react_offsets = (int*) realloc((void*) react_offsets, (++react_offset_count) * sizeof(int));
1087  react_offsets[react_offset_count - 1] = offset;
1089  return react_offset_count - 2;
1090 }
1091 
1093  free(all_reaction_states);
1094  free(react_offsets);
1096  free(all_reaction_indices);
1097  else
1098  free(reaction_indices);
1102  react_offsets = (int*) calloc(1, sizeof(int));
1103  react_offset_count = 1;
1106 }
1107 
1108 
1110 #if NRNMPI
1111  int i, j;
1112  int total_react = 0;
1113  int start_state;
1114  int* proc_num_init;
1115  int* all_indices;
1116  double* all_scales;
1117  // Copy the reaction indices across all nodes and update the local
1118  // react_offsets used by Reaction to access the indicies.
1119  if (nrnmpi_use) {
1120  proc_num_init = (int*) calloc(nrnmpi_numprocs, sizeof(int));
1121  proc_num_init[nrnmpi_myid] = (int) multicompartment_inititalized;
1122  nrnmpi_int_allgather_inplace(proc_num_init, 1);
1123  for (i = 0; i < nrnmpi_numprocs; i++)
1124  if (!proc_num_init[i])
1125  break;
1126 
1127  if (i != nrnmpi_numprocs) {
1128  // number of offsets (Reaction) stored in each process
1129  proc_num_reactions = (int*) calloc(nrnmpi_numprocs, sizeof(int));
1131 
1132  // number of states/indices stored in each process
1133  proc_num_reaction_states = (int*) calloc(nrnmpi_numprocs, sizeof(int));
1135  nrnmpi_int_allgather_inplace(proc_num_reactions, 1);
1136  nrnmpi_int_allgather_inplace(proc_num_reaction_states, 1);
1137 
1138  for (i = 0; i < nrnmpi_numprocs; i++) {
1139  if (i == nrnmpi_myid)
1140  start_state = total_reaction_states;
1142  total_react += proc_num_reactions[i];
1144  }
1145 
1146  // Move the offsets for each reaction so they reference the
1147  // corresponding indices in the all_reaction_indices array
1148  for (j = 0; j < react_offset_count; j++)
1149  react_offsets[j] += start_state;
1150 
1151  all_reaction_indices = (int*) malloc(total_reaction_states * sizeof(int));
1152  all_reaction_states = (double*) calloc(total_reaction_states, sizeof(double));
1153 
1154  memcpy(&all_reaction_indices[start_state],
1156  proc_num_reaction_states[nrnmpi_myid] * sizeof(int));
1157  nrnmpi_int_allgatherv_inplace(all_reaction_indices,
1160  free(reaction_indices);
1163 
1164  // Handle currents induced by multicompartment reactions.
1166  nrnmpi_int_allgather_inplace(proc_induced_current_count, 1);
1168  for (i = 1; i < nrnmpi_numprocs; i++)
1173 
1174  all_scales = (double*) malloc(induced_current_count * sizeof(double));
1175  all_indices = (int*) malloc(induced_current_count * sizeof(double));
1176  memcpy(&all_scales[proc_induced_current_offset[nrnmpi_myid]],
1178  sizeof(double) * proc_induced_current_count[nrnmpi_myid]);
1179 
1180  memcpy(&all_indices[proc_induced_current_offset[nrnmpi_myid]],
1182  sizeof(int) * proc_induced_current_count[nrnmpi_myid]);
1183 
1184  nrnmpi_dbl_allgatherv_inplace(all_scales,
1187 
1188  nrnmpi_int_allgatherv_inplace(all_indices,
1191  free(induced_currents_scale);
1192  free(induced_currents_index);
1193  free(induced_currents);
1194  induced_currents_scale = all_scales;
1195  induced_currents_index = all_indices;
1196  induced_currents = (double*) malloc(induced_current_count * sizeof(double));
1198  }
1199  } else {
1203  all_reaction_states = (double*) calloc(total_reaction_states, sizeof(double));
1205  induced_currents = (double*) malloc(induced_current_count * sizeof(double));
1207  }
1208  }
1209 #else
1213  all_reaction_states = (double*) calloc(total_reaction_states, sizeof(double));
1215  induced_currents = (double*) malloc(induced_current_count * sizeof(double));
1217  }
1218 #endif
1219 }
1220 
1222  int i;
1223 #if NRNMPI
1224  if (nrnmpi_use) {
1225  // Copy the states between all of the nodes
1226  nrnmpi_dbl_allgatherv_inplace(all_reaction_states,
1229  }
1230 #endif
1231  if (result == NULL) // fixed step
1232  {
1233  for (i = 0; i < total_reaction_states; i++)
1235  } else // variable step
1236  {
1237  for (i = 0; i < total_reaction_states; i++)
1239  }
1241 }
1242 
1243 // TODO: Implement this
1245 
1246 // Free a single Grid_node
1248  int i;
1249  free(states_x);
1250  free(states_y);
1251  free(states_cur);
1252  free(concentration_list);
1253  free(current_list);
1254  free(bc);
1255  free(current_dest);
1256 #if NRNMPI
1257  if (nrnmpi_use) {
1258  free(proc_offsets);
1259  free(proc_num_currents);
1260  free(proc_flux_offsets);
1261  free(proc_num_fluxes);
1263  free(proc_num_reactions);
1264  }
1265 #endif
1266  free(all_currents);
1267  free(ecs_adi_dir_x);
1268  free(ecs_adi_dir_y);
1269  free(ecs_adi_dir_z);
1270  if (node_flux_count > 0) {
1271  free(node_flux_idx);
1272  free(node_flux_scale);
1273  free(node_flux_src);
1274  }
1275 
1276 
1277  if (ecs_tasks != NULL) {
1278  for (i = 0; i < NUM_THREADS; i++) {
1279  free(ecs_tasks[i].scratchpad);
1280  }
1281  }
1282  free(ecs_tasks);
1283 }
1284 
1285 /*****************************************************************************
1286  *
1287  * Begin ICS_Grid_node Functions
1288  *
1289  *****************************************************************************/
1290 static int find_min_element_index(const int thread_sizes[], const int nthreads) {
1291  int new_min_index = 0;
1292  int min_element = thread_sizes[0];
1293  for (int i = 0; i < nthreads; i++) {
1294  if (min_element > thread_sizes[i]) {
1295  min_element = thread_sizes[i];
1296  new_min_index = i;
1297  }
1298  }
1299  return new_min_index;
1300 }
1301 
1302 void ICS_Grid_node::divide_x_work(const int nthreads) {
1303  int i, j, k;
1304  // nodes in each thread. (work each thread has to do)
1305  int* nodes_per_thread = (int*) calloc(nthreads, sizeof(int));
1306  // number of lines in each thread
1307  int* lines_per_thread = (int*) calloc(nthreads, sizeof(int));
1308  // To determine which index to put the start node and line length in thread_line_defs
1309  int* thread_idx_counter = (int*) calloc(nthreads, sizeof(int));
1310  // To determine which thread array to put the start node and line length in thread_line_defs
1311  int line_thread_id[_x_lines_length / 2];
1312  // Array of nthreads arrays that hold the line defs for each thread
1313  int** thread_line_defs = (int**) malloc(nthreads * sizeof(int*));
1314 
1315  int min_index = 0;
1316 
1317  // Find the total line length for each thread
1318  for (i = 0; i < _x_lines_length; i += 2) {
1319  min_index = find_min_element_index(nodes_per_thread, nthreads);
1320  nodes_per_thread[min_index] += _sorted_x_lines[i + 1];
1321  line_thread_id[i / 2] = min_index;
1322  lines_per_thread[min_index] += 1;
1323  }
1324 
1325  // Allocate memory for each array in thread_line_defs
1326  for (i = 0; i < nthreads; i++) {
1327  thread_line_defs[i] = (int*) malloc(lines_per_thread[i] * 2 * sizeof(int));
1328  }
1329 
1330  int thread_idx;
1331  int line_idx;
1332 
1333  // Populate each array of thread_line_defs
1334  for (i = 0; i < _x_lines_length; i += 2) {
1335  thread_idx = line_thread_id[i / 2];
1336  line_idx = thread_idx_counter[thread_idx];
1337  thread_line_defs[thread_idx][line_idx] = _sorted_x_lines[i];
1338  thread_line_defs[thread_idx][line_idx + 1] = _sorted_x_lines[i + 1];
1339  thread_idx_counter[thread_idx] += 2;
1340  }
1341 
1342  // Populate ordered_line_def
1343  int ordered_line_def_counter = 0;
1344  for (i = 0; i < nthreads; i++) {
1345  for (j = 0; j < lines_per_thread[i] * 2; j++) {
1346  ics_adi_dir_x->ordered_line_defs[ordered_line_def_counter] = thread_line_defs[i][j];
1347  ordered_line_def_counter++;
1348  }
1349  }
1350  // Set direction node and line start/stop indices
1351  // thread 0 start and stop
1353  ics_adi_dir_x->ordered_start_stop_indices[1] = nodes_per_thread[0];
1355  ics_adi_dir_x->line_start_stop_indices[1] = lines_per_thread[0] * 2;
1356  long start_node;
1357  long line_start_node;
1358  for (i = 2; i < nthreads * 2; i += 2) {
1359  start_node = ics_adi_dir_x->ordered_start_stop_indices[i - 1];
1361  ics_adi_dir_x->ordered_start_stop_indices[i + 1] = start_node + nodes_per_thread[i / 2];
1362 
1363  line_start_node = ics_adi_dir_x->line_start_stop_indices[i - 1];
1364  ics_adi_dir_x->line_start_stop_indices[i] = line_start_node;
1365  ics_adi_dir_x->line_start_stop_indices[i + 1] = line_start_node +
1366  lines_per_thread[i / 2] * 2;
1367  }
1368 
1369  // Put the Nodes in order in the ordered_nodes array
1370  int ordered_node_idx_counter = 0;
1371  int current_node;
1372  for (i = 0; i < nthreads; i++) {
1373  for (j = 0; j < lines_per_thread[i] * 2; j += 2) {
1374  current_node = thread_line_defs[i][j];
1375  ics_adi_dir_x->ordered_nodes[ordered_node_idx_counter] = current_node;
1376  ics_adi_dir_x->states_in[ordered_node_idx_counter] = states[current_node];
1377  ordered_node_idx_counter++;
1378  for (k = 1; k < thread_line_defs[i][j + 1]; k++) {
1379  current_node = _neighbors[current_node * 3];
1380  ics_adi_dir_x->ordered_nodes[ordered_node_idx_counter] = current_node;
1381  ics_adi_dir_x->states_in[ordered_node_idx_counter] = states[current_node];
1382  ordered_node_idx_counter++;
1383  }
1384  }
1385  }
1386 
1387  // Delete thread_line_defs array
1388  for (i = 0; i < nthreads; i++) {
1389  free(thread_line_defs[i]);
1390  }
1391  free(thread_line_defs);
1392  free(nodes_per_thread);
1393  free(lines_per_thread);
1394  free(thread_idx_counter);
1395 }
1396 
1397 void ICS_Grid_node::divide_y_work(const int nthreads) {
1398  int i, j, k;
1399  // nodes in each thread. (work each thread has to do)
1400  int* nodes_per_thread = (int*) calloc(nthreads, sizeof(int));
1401  // number of lines in each thread
1402  int* lines_per_thread = (int*) calloc(nthreads, sizeof(int));
1403  // To determine which index to put the start node and line length in thread_line_defs
1404  int* thread_idx_counter = (int*) calloc(nthreads, sizeof(int));
1405  // To determine which thread array to put the start node and line length in thread_line_defs
1406  int line_thread_id[_y_lines_length / 2];
1407  // Array of nthreads arrays that hold the line defs for each thread
1408  int** thread_line_defs = (int**) malloc(nthreads * sizeof(int*));
1409 
1410  int min_index = 0;
1411 
1412  // Find the total line length for each thread
1413  for (i = 0; i < _y_lines_length; i += 2) {
1414  min_index = find_min_element_index(nodes_per_thread, nthreads);
1415  nodes_per_thread[min_index] += _sorted_y_lines[i + 1];
1416  line_thread_id[i / 2] = min_index;
1417  lines_per_thread[min_index] += 1;
1418  }
1419 
1420  // Allocate memory for each array in thread_line_defs
1421  for (i = 0; i < nthreads; i++) {
1422  thread_line_defs[i] = (int*) malloc(lines_per_thread[i] * 2 * sizeof(int));
1423  }
1424 
1425  int thread_idx;
1426  int line_idx;
1427 
1428  // Populate each array of thread_line_defs
1429  for (i = 0; i < _y_lines_length; i += 2) {
1430  thread_idx = line_thread_id[i / 2];
1431  line_idx = thread_idx_counter[thread_idx];
1432  thread_line_defs[thread_idx][line_idx] = _sorted_y_lines[i];
1433  thread_line_defs[thread_idx][line_idx + 1] = _sorted_y_lines[i + 1];
1434  thread_idx_counter[thread_idx] += 2;
1435  }
1436 
1437  // Populate ordered_line_def
1438  int ordered_line_def_counter = 0;
1439  for (i = 0; i < nthreads; i++) {
1440  for (j = 0; j < lines_per_thread[i] * 2; j++) {
1441  ics_adi_dir_y->ordered_line_defs[ordered_line_def_counter] = thread_line_defs[i][j];
1442  ordered_line_def_counter++;
1443  }
1444  }
1445 
1446  // Set direction start/stop indices
1447  // thread 0 start and stop
1449  ics_adi_dir_y->ordered_start_stop_indices[1] = nodes_per_thread[0];
1451  ics_adi_dir_y->line_start_stop_indices[1] = lines_per_thread[0] * 2;
1452 
1453  long start_node;
1454  long line_start_node;
1455  for (i = 2; i < nthreads * 2; i += 2) {
1456  start_node = ics_adi_dir_y->ordered_start_stop_indices[i - 1];
1458  ics_adi_dir_y->ordered_start_stop_indices[i + 1] = start_node + nodes_per_thread[i / 2];
1459 
1460  line_start_node = ics_adi_dir_y->line_start_stop_indices[i - 1];
1461  ics_adi_dir_y->line_start_stop_indices[i] = line_start_node;
1462  ics_adi_dir_y->line_start_stop_indices[i + 1] = line_start_node +
1463  (lines_per_thread[i / 2] * 2);
1464  }
1465 
1466  // Put the Nodes in order in the ordered_nodes array
1467  int ordered_node_idx_counter = 0;
1468  int current_node;
1469  for (i = 0; i < nthreads; i++) {
1470  for (j = 0; j < lines_per_thread[i] * 2; j += 2) {
1471  current_node = thread_line_defs[i][j];
1472  ics_adi_dir_y->ordered_nodes[ordered_node_idx_counter] = current_node;
1473  ics_adi_dir_y->states_in[ordered_node_idx_counter] = states[current_node];
1474  ordered_node_idx_counter++;
1475  for (k = 1; k < thread_line_defs[i][j + 1]; k++) {
1476  current_node = _neighbors[(current_node * 3) + 1];
1477  ics_adi_dir_y->ordered_nodes[ordered_node_idx_counter] = current_node;
1478  ics_adi_dir_y->states_in[ordered_node_idx_counter] = states[current_node];
1479  ordered_node_idx_counter++;
1480  }
1481  }
1482  }
1483 
1484  // Delete thread_line_defs array
1485  for (i = 0; i < nthreads; i++) {
1486  free(thread_line_defs[i]);
1487  }
1488  free(thread_line_defs);
1489  free(nodes_per_thread);
1490  free(lines_per_thread);
1491  free(thread_idx_counter);
1492 }
1493 
1494 void ICS_Grid_node::divide_z_work(const int nthreads) {
1495  int i, j, k;
1496  // nodes in each thread. (work each thread has to do)
1497  int* nodes_per_thread = (int*) calloc(nthreads, sizeof(int));
1498  // number of lines in each thread
1499  int* lines_per_thread = (int*) calloc(nthreads, sizeof(int));
1500  // To determine which index to put the start node and line length in thread_line_defs
1501  int* thread_idx_counter = (int*) calloc(nthreads, sizeof(int));
1502  // To determine which thread array to put the start node and line length in thread_line_defs
1503  int line_thread_id[_z_lines_length / 2];
1504  // Array of nthreads arrays that hold the line defs for each thread
1505  int** thread_line_defs = (int**) malloc(nthreads * sizeof(int*));
1506 
1507  int min_index = 0;
1508 
1509  // Find the total line length for each thread
1510  for (i = 0; i < _z_lines_length; i += 2) {
1511  min_index = find_min_element_index(nodes_per_thread, nthreads);
1512  nodes_per_thread[min_index] += _sorted_z_lines[i + 1];
1513  line_thread_id[i / 2] = min_index;
1514  lines_per_thread[min_index] += 1;
1515  }
1516 
1517  // Allocate memory for each array in thread_line_defs
1518  // Add indices to Grid_data
1519  for (i = 0; i < nthreads; i++) {
1520  thread_line_defs[i] = (int*) malloc(lines_per_thread[i] * 2 * sizeof(int));
1521  }
1522 
1523  int thread_idx;
1524  int line_idx;
1525 
1526  // Populate each array of thread_line_defs
1527  for (i = 0; i < _z_lines_length; i += 2) {
1528  thread_idx = line_thread_id[i / 2];
1529  line_idx = thread_idx_counter[thread_idx];
1530  thread_line_defs[thread_idx][line_idx] = _sorted_z_lines[i];
1531  thread_line_defs[thread_idx][line_idx + 1] = _sorted_z_lines[i + 1];
1532  thread_idx_counter[thread_idx] += 2;
1533  }
1534 
1535  // Populate ordered_line_def
1536  int ordered_line_def_counter = 0;
1537  for (i = 0; i < nthreads; i++) {
1538  for (j = 0; j < lines_per_thread[i] * 2; j++) {
1539  ics_adi_dir_z->ordered_line_defs[ordered_line_def_counter] = thread_line_defs[i][j];
1540  ordered_line_def_counter++;
1541  }
1542  }
1543 
1544  // Set direction start/stop indices
1545  // thread 0 start and stop
1547  ics_adi_dir_z->ordered_start_stop_indices[1] = nodes_per_thread[0];
1549  ics_adi_dir_z->line_start_stop_indices[1] = lines_per_thread[0] * 2;
1550 
1551  long start_node;
1552  long line_start_node;
1553  for (i = 2; i < nthreads * 2; i += 2) {
1554  start_node = ics_adi_dir_z->ordered_start_stop_indices[i - 1];
1556  ics_adi_dir_z->ordered_start_stop_indices[i + 1] = start_node + nodes_per_thread[i / 2];
1557 
1558  line_start_node = ics_adi_dir_z->line_start_stop_indices[i - 1];
1559  ics_adi_dir_z->line_start_stop_indices[i] = line_start_node;
1560  ics_adi_dir_z->line_start_stop_indices[i + 1] = line_start_node +
1561  lines_per_thread[i / 2] * 2;
1562  }
1563 
1564  // Put the Nodes in order in the ordered_nodes array
1565  int ordered_node_idx_counter = 0;
1566  int current_node;
1567  for (i = 0; i < nthreads; i++) {
1568  for (j = 0; j < lines_per_thread[i] * 2; j += 2) {
1569  current_node = thread_line_defs[i][j];
1570  ics_adi_dir_z->ordered_nodes[ordered_node_idx_counter] = current_node;
1571  ics_adi_dir_z->states_in[ordered_node_idx_counter] = states[current_node];
1572  ordered_node_idx_counter++;
1573  for (k = 1; k < thread_line_defs[i][j + 1]; k++) {
1574  current_node = _neighbors[(current_node * 3) + 2];
1575  ics_adi_dir_z->ordered_nodes[ordered_node_idx_counter] = current_node;
1576  ics_adi_dir_z->states_in[ordered_node_idx_counter] = states[current_node];
1577  ordered_node_idx_counter++;
1578  }
1579  }
1580  }
1581 
1582  // Delete thread_line_defs array
1583  for (i = 0; i < nthreads; i++) {
1584  free(thread_line_defs[i]);
1585  }
1586  free(thread_line_defs);
1587  free(nodes_per_thread);
1588  free(lines_per_thread);
1589  free(thread_idx_counter);
1590 }
1591 
1592 
1594  int i;
1595  if (ics_tasks != NULL) {
1596  for (i = 0; i < NUM_THREADS; i++) {
1597  free(ics_tasks[i].scratchpad);
1598  free(ics_tasks[i].RHS);
1599  }
1600  }
1601  free(ics_tasks);
1602  ics_tasks = (ICSAdiGridData*) malloc(n * sizeof(ICSAdiGridData));
1603  for (i = 0; i < n; i++) {
1604  ics_tasks[i].RHS = (double*) malloc(sizeof(double) * _line_length_max);
1605  ics_tasks[i].scratchpad = (double*) malloc(sizeof(double) * _line_length_max - 1);
1606  ics_tasks[i].g = this;
1607  ics_tasks[i].u_diag = (double*) malloc(sizeof(double) * _line_length_max - 1);
1608  ics_tasks[i].diag = (double*) malloc(sizeof(double) * _line_length_max);
1609  ics_tasks[i].l_diag = (double*) malloc(sizeof(double) * _line_length_max - 1);
1610  }
1611 
1614 
1617 
1620 
1621  ics_adi_dir_x->ordered_start_stop_indices = (long*) malloc(sizeof(long) * n * 2);
1622  ics_adi_dir_x->line_start_stop_indices = (long*) malloc(sizeof(long) * n * 2);
1623 
1624  ics_adi_dir_y->ordered_start_stop_indices = (long*) malloc(sizeof(long) * n * 2);
1625  ics_adi_dir_y->line_start_stop_indices = (long*) malloc(sizeof(long) * n * 2);
1626 
1627  ics_adi_dir_z->ordered_start_stop_indices = (long*) malloc(sizeof(long) * n * 2);
1628  ics_adi_dir_z->line_start_stop_indices = (long*) malloc(sizeof(long) * n * 2);
1629 
1630  divide_x_work(n);
1631  divide_y_work(n);
1632  divide_z_work(n);
1633 }
1634 
1635 
1636 void ICS_Grid_node::apply_node_flux3D(double dt, double* ydot) {
1637  double* dest;
1638  if (ydot == NULL)
1639  dest = states_cur;
1640  else
1641  dest = ydot;
1643 }
1644 
1645 void ICS_Grid_node::do_grid_currents(double* output, double dt, int) {
1646  MEM_ZERO(states_cur, sizeof(double) * _num_nodes);
1647  if (ics_current_seg_ptrs != NULL) {
1648  ssize_t i, j, n;
1649  int seg_start_index, seg_stop_index;
1650  int state_index;
1651  double seg_cur;
1652  n = ics_num_segs;
1653  for (i = 0; i < n; i++) {
1654  seg_start_index = ics_surface_nodes_per_seg_start_indices[i];
1655  seg_stop_index = ics_surface_nodes_per_seg_start_indices[i + 1];
1656  seg_cur = *ics_current_seg_ptrs[i];
1657  for (j = seg_start_index; j < seg_stop_index; j++) {
1658  state_index = ics_surface_nodes_per_seg[j];
1659  output[state_index] += seg_cur * ics_scale_factors[state_index] * dt;
1660  }
1661  }
1662  }
1663 }
1664 
1666  if (ics_adi_dir_x->dcgrid == NULL) {
1670  } else {
1674  }
1675 }
1676 
1678  if (diffusable) {
1685  }
1686  return 0;
1687 }
1688 
1689 
1690 void ICS_Grid_node::variable_step_diffusion(const double* states, double* ydot) {
1691  if (diffusable) {
1693  }
1694 
1695  // TODO: Get volume fraction/tortuosity working as well as take care of this in this file
1696  /*switch(VARIABLE_ECS_VOLUME)
1697  {
1698  case VOLUME_FRACTION:
1699  _ics_rhs_variable_step_helper_vol(this, states, ydot);
1700  break;
1701  case TORTUOSITY:
1702  _ics_rhs_variable_step_helper_tort(this, states, ydot);
1703  break;
1704  default:
1705  _ics_rhs_variable_step_helper(this, states, ydot);
1706  }*/
1707 }
1708 
1710  if (diffusable) {
1711  ics_ode_solve_helper(this, dt, RHS);
1712  }
1713 }
1714 
1716  _ics_hybrid_helper(this);
1717 }
1718 
1719 void ICS_Grid_node::variable_step_hybrid_connections(const double* cvode_states_3d,
1720  double* const ydot_3d,
1721  const double* cvode_states_1d,
1722  double* const ydot_1d) {
1723  _ics_variable_hybrid_helper(this, cvode_states_3d, ydot_3d, cvode_states_1d, ydot_1d);
1724 }
1725 
1727  ssize_t i, j, n;
1728  double total_seg_concentration;
1729  double average_seg_concentration;
1730  int seg_start_index, seg_stop_index;
1731 
1732  n = ics_num_segs;
1733 
1734  for (i = 0; i < n; i++) {
1735  total_seg_concentration = 0.0;
1736  seg_start_index = ics_surface_nodes_per_seg_start_indices[i];
1737  seg_stop_index = ics_surface_nodes_per_seg_start_indices[i + 1];
1738  for (j = seg_start_index; j < seg_stop_index; j++) {
1739  total_seg_concentration += states[ics_surface_nodes_per_seg[j]];
1740  }
1741  average_seg_concentration = total_seg_concentration / (seg_stop_index - seg_start_index);
1742 
1743  *ics_concentration_seg_ptrs[i] = average_seg_concentration;
1744  }
1745 }
1746 
1747 // Free a single Grid_node
1749  int i;
1750  free(states_x);
1751  free(states_y);
1752  free(states_z);
1753  free(states_cur);
1754  free(concentration_list);
1755  free(current_list);
1756  free(current_dest);
1757 #if NRNMPI
1758  if (nrnmpi_use) {
1759  free(proc_offsets);
1760  free(proc_num_currents);
1761  free(proc_num_fluxes);
1762  }
1763 #endif
1767  free(ics_adi_dir_x->deltas);
1768  free(ics_adi_dir_x);
1769 
1773  free(ics_adi_dir_y->deltas);
1774  free(ics_adi_dir_y);
1775 
1779  free(ics_adi_dir_z->deltas);
1780  free(ics_adi_dir_z);
1781 
1782  free(hybrid_data);
1783  if (node_flux_count > 0) {
1784  free(node_flux_idx);
1785  free(node_flux_scale);
1786  free(node_flux_src);
1787  }
1788 
1789  if (ics_tasks != NULL) {
1790  for (i = 0; i < NUM_THREADS; i++) {
1791  free(ics_tasks[i].scratchpad);
1792  free(ics_tasks[i].RHS);
1793  free(ics_tasks[i].u_diag);
1794  free(ics_tasks[i].l_diag);
1795  }
1796  }
1797  free(ics_tasks);
1798 }
#define alpha
Definition: bkpfacto.c:43
double * induced_currents
Definition: grids.h:240
unsigned char multicompartment_inititalized
Definition: grids.h:234
double * induced_currents_scale
Definition: grids.h:242
ECS_Grid_node()
Definition: grids.cpp:49
void apply_node_flux3D(double dt, double *states)
Definition: grids.cpp:960
void set_tortuosity(PyHocObject *)
Definition: grids.cpp:481
int induced_current_count
Definition: grids.h:236
int react_offset_count
Definition: grids.h:228
int dg_adi()
Definition: grids.cpp:1008
int * all_reaction_indices
Definition: grids.h:230
void volume_setup()
Definition: grids.cpp:995
int * proc_induced_current_count
Definition: grids.h:237
void do_grid_currents(double *, double, int)
Definition: grids.cpp:875
void variable_step_diffusion(const double *states, double *ydot)
Definition: grids.cpp:1035
struct ECSAdiDirection * ecs_adi_dir_z
Definition: grids.h:223
double * set_rxd_currents(int, int *, PyHocObject **)
Definition: grids.cpp:933
void initialize_multicompartment_reaction()
Definition: grids.cpp:1109
void set_volume_fraction(PyHocObject *)
Definition: grids.cpp:531
struct ECSAdiDirection * ecs_adi_dir_y
Definition: grids.h:222
int add_multicompartment_reaction(int, int *, int)
Definition: grids.cpp:1066
struct ECSAdiGridData * ecs_tasks
Definition: grids.h:220
void clear_multicompartment_reaction()
Definition: grids.cpp:1092
void variable_step_ode_solve(double *RHS, double dt)
Definition: grids.cpp:1244
int total_reaction_states
Definition: grids.h:233
int * react_offsets
Definition: grids.h:227
void variable_step_hybrid_connections(const double *cvode_states_3d, double *const ydot_3d, const double *cvode_states_1d, double *const ydot_1d)
Definition: grids.cpp:1061
int * proc_num_reaction_states
Definition: grids.h:232
int * proc_induced_current_offset
Definition: grids.h:238
int * proc_num_reactions
Definition: grids.h:231
struct ECSAdiDirection * ecs_adi_dir_x
Definition: grids.h:221
void set_num_threads(const int n)
Definition: grids.cpp:832
void hybrid_connections()
Definition: grids.cpp:1059
void scatter_grid_concentrations()
Definition: grids.cpp:1048
double * all_reaction_states
Definition: grids.h:239
double * local_induced_currents
Definition: grids.h:241
void set_diffusion(double *, int)
Definition: grids.cpp:575
int * reaction_indices
Definition: grids.h:229
void do_multicompartment_reactions(double *)
Definition: grids.cpp:1221
int * induced_currents_index
Definition: grids.h:235
double(* get_alpha)(double *, int)
Definition: grids.h:165
int node_flux_count
Definition: grids.h:177
double * permeability
Definition: grids.h:160
bool hybrid
Definition: grids.h:139
int * proc_num_fluxes
Definition: grids.h:151
int size_y
Definition: grids.h:130
int * proc_offsets
Definition: grids.h:148
double * states_x
Definition: grids.h:125
int64_t * ics_surface_nodes_per_seg
Definition: grids.h:169
Concentration_Pair * concentration_list
Definition: grids.h:142
long * node_flux_idx
Definition: grids.h:178
int size_x
Definition: grids.h:129
double * states_cur
Definition: grids.h:128
bool diffusable
Definition: grids.h:138
double * states
Definition: grids.h:124
double atolscale
Definition: grids.h:167
int * proc_flux_offsets
Definition: grids.h:150
BoundaryConditions * bc
Definition: grids.h:140
double * node_flux_scale
Definition: grids.h:179
double dy
Definition: grids.h:136
double * states_z
Definition: grids.h:127
double * states_y
Definition: grids.h:126
Grid_node * next
Definition: grids.h:122
double(* get_permeability)(double *, int)
Definition: grids.h:166
Hybrid_data * hybrid_data
Definition: grids.h:141
int64_t * ics_surface_nodes_per_seg_start_indices
Definition: grids.h:170
PyObject ** node_flux_src
Definition: grids.h:180
int num_all_currents
Definition: grids.h:147
unsigned char VARIABLE_ECS_VOLUME
Definition: grids.h:156
int insert(int grid_list_index)
Definition: grids.cpp:808
double ** ics_current_seg_ptrs
Definition: grids.h:172
double dc_z
Definition: grids.h:134
double * all_currents
Definition: grids.h:153
double * ics_scale_factors
Definition: grids.h:173
double dc_y
Definition: grids.h:133
Current_Triple * current_list
Definition: grids.h:143
int size_z
Definition: grids.h:131
int * proc_num_currents
Definition: grids.h:149
long * current_dest
Definition: grids.h:152
double dc_x
Definition: grids.h:132
double ** ics_concentration_seg_ptrs
Definition: grids.h:171
double dz
Definition: grids.h:137
int ics_num_segs
Definition: grids.h:174
double * alpha
Definition: grids.h:162
ssize_t num_currents
Definition: grids.h:144
double dx
Definition: grids.h:135
ssize_t num_concentrations
Definition: grids.h:144
struct ICSAdiDirection * ics_adi_dir_x
Definition: grids.h:321
long _x_lines_length
Definition: grids.h:306
void run_threaded_ics_dg_adi(struct ICSAdiDirection *)
void scatter_grid_concentrations()
Definition: grids.cpp:1726
long * _sorted_y_lines
Definition: grids.h:302
void hybrid_connections()
Definition: grids.cpp:1715
void apply_node_flux3D(double dt, double *states)
Definition: grids.cpp:1636
struct ICSAdiDirection * ics_adi_dir_y
Definition: grids.h:322
void divide_y_work(const int nthreads)
Definition: grids.cpp:1397
long _y_lines_length
Definition: grids.h:307
struct ICSAdiGridData * ics_tasks
Definition: grids.h:320
struct ICSAdiDirection * ics_adi_dir_z
Definition: grids.h:323
void variable_step_ode_solve(double *RHS, double dt)
Definition: grids.cpp:1709
void variable_step_diffusion(const double *states, double *ydot)
Definition: grids.cpp:1690
int dg_adi()
Definition: grids.cpp:1677
long _z_lines_length
Definition: grids.h:308
void divide_x_work(const int nthreads)
Definition: grids.cpp:1302
long * _sorted_x_lines
Definition: grids.h:301
long _num_nodes
Definition: grids.h:314
void set_diffusion(double *, int)
Definition: grids.cpp:553
void do_grid_currents(double *, double, int)
Definition: grids.cpp:1645
double * _ics_alphas
Definition: grids.h:294
void set_num_threads(const int n)
Definition: grids.cpp:1593
long * _sorted_z_lines
Definition: grids.h:303
long * _neighbors
Definition: grids.h:297
long _line_length_max
Definition: grids.h:311
void divide_z_work(const int nthreads)
Definition: grids.cpp:1494
void variable_step_hybrid_connections(const double *cvode_states_3d, double *const ydot_3d, const double *cvode_states_1d, double *const ydot_1d)
Definition: grids.cpp:1719
void volume_setup()
Definition: grids.cpp:1665
double dt
Definition: netcvode.cpp:76
#define dc
#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
int _memb_curr_total
Definition: rxd.cpp:74
double * dt_ptr
Definition: grids.cpp:14
int ICS_insert_inhom(int grid_list_index, PyHocObject *my_states, long num_nodes, long *neighbors, long *x_line_defs, long x_lines_length, long *y_line_defs, long y_lines_length, long *z_line_defs, long z_lines_length, double *dcs, double dx, bool is_diffusable, double atolscale, double *ics_alphas)
Definition: grids.cpp:420
static double get_permeability_array(double *permeability, int idx)
Definition: grids.cpp:44
int ICS_insert(int grid_list_index, PyHocObject *my_states, long num_nodes, long *neighbors, long *x_line_defs, long x_lines_length, long *y_line_defs, long y_lines_length, long *z_line_defs, long z_lines_length, double *dcs, double dx, bool is_diffusable, double atolscale, double *ics_alphas)
Definition: grids.cpp:386
double * _rxd_induced_currents_scale
Definition: rxd.cpp:80
static int find_min_element_index(const int thread_sizes[], const int nthreads)
Definition: grids.cpp:1290
int set_tortuosity(int grid_list_index, int grid_id, PyHocObject *my_permeability)
Definition: grids.cpp:467
void ics_set_grid_concentrations(int grid_list_index, int index_in_list, int64_t *nodes_per_seg, int64_t *nodes_per_seg_start_indices, PyObject *neuron_pointers)
Definition: grids.cpp:590
static double get_alpha_array(double *alpha, int idx)
Definition: grids.cpp:36
double * t_ptr
Definition: grids.cpp:15
int ECS_insert(int grid_list_index, PyHocObject *my_states, int my_num_states_x, int my_num_states_y, int my_num_states_z, double my_dc_x, double my_dc_y, double my_dc_z, double my_dx, double my_dy, double my_dz, PyHocObject *my_alpha, PyHocObject *my_permeability, int bc, double bc_value, double atolscale)
Definition: grids.cpp:197
int * _rxd_induced_currents_ecs_idx
TaskQueue * AllTasks
Definition: rxd.cpp:28
void make_time_ptr(PyHocObject *my_dt_ptr, PyHocObject *my_t_ptr)
Definition: grids.cpp:28
void empty_list(int list_index)
Definition: grids.cpp:799
int * _rxd_induced_currents_grid
Definition: rxd.cpp:95
static void * gather_currents(void *dataptr)
Definition: grids.cpp:848
void set_grid_currents(int grid_list_index, int index_in_list, PyObject *grid_indices, PyObject *neuron_pointers, PyObject *scale_factors)
Definition: grids.cpp:682
int set_diffusion(int grid_list_index, int grid_id, double *dc, int length)
Definition: grids.cpp:454
int NUM_THREADS
Definition: rxd.cpp:26
static double get_alpha_scalar(double *alpha, int)
Definition: grids.cpp:33
double * _rxd_induced_currents_ecs
void set_grid_concentrations(int grid_list_index, int index_in_list, PyObject *grid_indices, PyObject *neuron_pointers)
Definition: grids.cpp:641
static double get_permeability_scalar(double *, int)
Definition: grids.cpp:41
Grid_node * Parallel_grids[100]
Definition: grids.cpp:16
void delete_by_id(int id)
Definition: grids.cpp:786
int set_volume_fraction(int grid_list_index, int grid_id, PyHocObject *my_alpha)
Definition: grids.cpp:518
void ics_set_grid_currents(int grid_list_index, int index_in_list, PyObject *neuron_pointers, double *scale_factors)
Definition: grids.cpp:618
int remove(Grid_node **head, Grid_node *find)
Definition: grids.cpp:767
#define TORTUOSITY
Definition: grids.h:28
#define MIN(a, b)
Definition: grids.h:36
#define VOLUME_FRACTION
Definition: grids.h:29
void apply_node_flux(int, long *, double *, PyObject **, double, double *)
Definition: rxd.cpp:304
#define MAX(a, b)
Definition: grids.h:35
#define ICS_ALPHA
Definition: grids.h:30
void start()
Definition: hel2mos.cpp:204
void stop()
Definition: hel2mos.cpp:212
#define assert(ex)
Definition: hocassrt.h:32
#define i
Definition: md1redef.h:12
step
Definition: extdef.h:7
#define RHS(i)
Definition: multisplit.cpp:66
static int nrnmpi_use
Definition: multisplit.cpp:48
static Node * node(Object *)
Definition: netcvode.cpp:340
int const size_t const size_t n
Definition: nrngsl.h:11
size_t j
int nrnmpi_myid
int nrnmpi_numprocs
#define PyInt_AS_LONG
Definition: nrnpython.h:27
static philox4x32_key_t k
Definition: nrnran123.cpp:11
#define g
Definition: passive0.cpp:21
double * states
Definition: rxd.cpp:62
void TaskQueue_add_task(TaskQueue *q, void *(*task)(void *), void *args, void *result)
Definition: rxd.cpp:1087
void TaskQueue_sync(TaskQueue *q)
Definition: rxd.cpp:1187
void _ics_variable_hybrid_helper(ICS_Grid_node *, const double *, double *const, const double *, double *const)
void _ics_rhs_variable_step_helper(ICS_Grid_node *, double const *const, double *)
void ecs_run_threaded_dg_adi(const int, const int, ECS_Grid_node *, ECSAdiDirection *, const int)
void ecs_set_adi_tort(ECS_Grid_node *)
Definition: rxd_vol.cpp:773
void ics_dg_adi_z(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
void ecs_set_adi_vol(ECS_Grid_node *)
Definition: rxd_vol.cpp:411
void run_threaded_deltas(ICS_Grid_node *g, ICSAdiDirection *ics_adi_dir)
void ics_ode_solve_helper(ICS_Grid_node *, double, double *)
void _rhs_variable_step_helper(Grid_node *, double const *const, double *)
void ics_dg_adi_x_inhom(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
int find(const int, const int, const int, const int, const int)
void ics_dg_adi_z_inhom(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
#define SPECIES_ABSENT
Definition: rxd.h:6
void ecs_set_adi_homogeneous(ECS_Grid_node *)
void _rhs_variable_step_helper_tort(Grid_node *, double const *const, double *)
Definition: rxd_vol.cpp:786
void ics_dg_adi_y(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
void _ics_hybrid_helper(ICS_Grid_node *)
void _rhs_variable_step_helper_vol(Grid_node *, double const *const, double *)
Definition: rxd_vol.cpp:895
void ics_dg_adi_x(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
void ics_dg_adi_y_inhom(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
#define NULL
Definition: sptree.h:16
double value
Definition: grids.h:117
unsigned char type
Definition: grids.h:116
double * destination
Definition: grids.h:77
double * source
Definition: grids.h:83
long destination
Definition: grids.h:82
double scale_factor
Definition: grids.h:84
double * val
Definition: rxd.h:46
int onset
Definition: rxd.h:45
Grid_node * g
Definition: rxd.h:44
int offset
Definition: rxd.h:45
double * states_in
Definition: grids.h:275
int line_size
Definition: grids.h:277
double * states_out
Definition: grids.h:276
ECS_Grid_node * g
Definition: grids.h:283
double * scratchpad
Definition: grids.h:286
double * states_in
Definition: grids.h:377
double * dcgrid
Definition: grids.h:385
long * ordered_start_stop_indices
Definition: grids.h:382
double dc
Definition: grids.h:384
double d
Definition: grids.h:386
long * ordered_nodes
Definition: grids.h:381
void(* ics_dg_adi_dir)(ICS_Grid_node *g, int, int, int, double, double *, double *, double *, double *, double *, double *)
Definition: grids.h:366
long * line_start_stop_indices
Definition: grids.h:383
double * states_out
Definition: grids.h:378
long * ordered_line_defs
Definition: grids.h:380
double * deltas
Definition: grids.h:379
double * RHS
Definition: grids.h:399
double * l_diag
Definition: grids.h:400
ICS_Grid_node * g
Definition: grids.h:396
double * diag
Definition: grids.h:401
double * u_diag
Definition: grids.h:402
double * scratchpad
Definition: grids.h:398
union PyHocObject::@27 u
double * px_
Definition: grids.h:44
Definition: rxd.h:109