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