NEURON
rxd_extracellular.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <stdio.h>
3 #include <assert.h>
4 #include <string.h>
5 #include "grids.h"
6 #include "rxd.h"
7 #include <nrnwrap_Python.h>
8 #include <cmath>
9 
10 #define loc(x, y, z) ((z) + (y) *grid->size_z + (x) *grid->size_z * grid->size_y)
11 
12 static void ecs_refresh_reactions(int);
13 /*
14  Globals
15 */
16 
17 /*Store the onset/offset for each threads reaction tasks*/
19 
20 extern int NUM_THREADS;
21 extern pthread_t* Threads;
22 extern TaskQueue* AllTasks;
23 extern double* t_ptr;
24 extern double* states;
25 
27 
29 
30 /*Update the global array of reaction tasks when the number of reactions
31  *or threads change.
32  *n - the old number of threads - use to free the old threaded_reactions_tasks*/
33 static void ecs_refresh_reactions(const int n) {
34  int k;
36  for (k = 0; k < NUM_THREADS; k++) {
39  }
41  }
43 }
44 
45 void set_num_threads_3D(const int n) {
46  Grid_node* grid;
47  if (n != NUM_THREADS) {
48  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
49  grid->set_num_threads(n);
50  }
51  }
53 }
54 
55 
56 /*Removal all reactions*/
57 void clear_rates_ecs(void) {
58  Reaction *r, *tmp;
59  Grid_node* grid;
61 
62  for (r = ecs_reactions; r != NULL; r = tmp) {
64  if (r->subregion) {
65  SAFE_FREE(r->subregion);
66  }
67 
68  tmp = r->next;
69  SAFE_FREE(r);
70  }
72 
74  for (Grid_node* grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
75  g = dynamic_cast<ECS_Grid_node*>(grid);
76  if (g)
77  g->clear_multicompartment_reaction();
78  }
79 }
80 
81 /*Create a reaction
82  * list_idx - the index for the linked list in the global array Parallel_grids
83  * grid_id - the grid id within the linked list
84  * ECSReactionRate - the reaction function
85  * subregion - either NULL or a boolean array the same size as the grid
86  * indicating if reaction occurs at a specific voxel
87  */
89  int num_species,
90  int num_params,
91  int* species_ids,
93  unsigned char* subregion,
94  uint64_t* mc3d_start_indices,
95  int mc3d_region_size,
96  double* mc3d_mults) {
97  Grid_node* grid;
98  Reaction* r;
99  int i, j;
100 
101  r = (Reaction*) malloc(sizeof(Reaction));
102  assert(r);
103  r->reaction = f;
104  /*place reaction on the top of the stack of reactions*/
105  r->next = ecs_reactions;
106  ecs_reactions = r;
107 
108  for (grid = Parallel_grids[list_idx], i = 0; grid != NULL; grid = grid->next, i++) {
109  /* Assume all species have the same grid */
110  if (i == species_ids[0]) {
111  if (mc3d_region_size > 0) {
112  r->subregion = NULL;
113  r->region_size = mc3d_region_size;
114  r->mc3d_indices_offsets = (uint64_t*) malloc(sizeof(uint64_t) *
115  (num_species + num_params));
116  memcpy(r->mc3d_indices_offsets,
117  mc3d_start_indices,
118  sizeof(uint64_t) * (num_species + num_params));
119  r->mc3d_mults = (double**) malloc(sizeof(double*) * (num_species + num_params));
120  int mult_idx = 0;
121  for (int row = 0; row < num_species + num_params; row++) {
122  r->mc3d_mults[row] = (double*) malloc(sizeof(double) * mc3d_region_size);
123  for (int c = 0; c < mc3d_region_size; c++, mult_idx++) {
124  r->mc3d_mults[row][c] = mc3d_mults[mult_idx];
125  }
126  }
127 
128 
129  } else if (subregion == NULL) {
130  r->subregion = NULL;
131  r->region_size = grid->size_x * grid->size_y * grid->size_z;
133  } else {
134  for (r->region_size = 0, j = 0; j < grid->size_x * grid->size_y * grid->size_z; j++)
135  r->region_size += subregion[j];
136  r->subregion = subregion;
138  }
139  }
140  }
141 
142  r->num_species_involved = num_species;
143  r->num_params_involved = num_params;
144  r->species_states = (double**) malloc(sizeof(Grid_node*) * (num_species + num_params));
146 
147  for (i = 0; i < num_species + num_params; i++) {
148  /*Assumes grids are the same size (no interpolation)
149  *Assumes all the species will be in the same Parallel_grids list*/
150  for (grid = Parallel_grids[list_idx], j = 0; grid != NULL; grid = grid->next, j++) {
151  if (j == species_ids[i])
152  r->species_states[i] = grid->states;
153  }
154  }
155 
156  return r;
157 }
158 
159 /*ics_register_reaction is called from python it creates a reaction with
160  * list_idx - the index for the linked list in the global array Parallel_grids
161  * (currently this is always 0)
162  * grid_id - the grid id within the linked list - this corresponds to species
163  * ECSReactionRate - the reaction function
164  */
165 extern "C" void ics_register_reaction(int list_idx,
166  int num_species,
167  int num_params,
168  int* species_id,
169  uint64_t* mc3d_start_indices,
170  int mc3d_region_size,
171  double* mc3d_mults,
172  ECSReactionRate f) {
173  ecs_create_reaction(list_idx,
174  num_species,
175  num_params,
176  species_id,
177  f,
178  NULL,
179  mc3d_start_indices,
180  mc3d_region_size,
181  mc3d_mults);
183 }
184 
185 /*ecs_register_reaction is called from python it creates a reaction with
186  * list_idx - the index for the linked list in the global array Parallel_grids
187  * (currently this is always 0)
188  * grid_id - the grid id within the linked list - this corresponds to species
189  * ECSReactionRate - the reaction function
190  */
191 extern "C" void ecs_register_reaction(int list_idx,
192  int num_species,
193  int num_params,
194  int* species_id,
195  ECSReactionRate f) {
196  ecs_create_reaction(list_idx, num_species, num_params, species_id, f, NULL, NULL, 0, NULL);
198 }
199 
200 
201 /*register_subregion_reaction is called from python it creates a reaction with
202  * list_idx - the index for the linked list in the global array Parallel_grids
203  * (currently this is always 0)
204  * grid_id - the grid id within the linked list - this corresponds to species
205  * my_subregion - a boolean array indicating the voxels where a reaction occurs
206  * ECSReactionRate - the reaction function
207  */
209  int num_species,
210  int num_params,
211  int* species_id,
212  unsigned char* my_subregion,
213  ECSReactionRate f) {
215  list_idx, num_species, num_params, species_id, f, my_subregion, NULL, 0, NULL);
217 }
218 
219 
220 /*create_threaded_reactions is used to generate evenly distribution of reactions
221  * across NUM_THREADS
222  * returns ReactGridData* which can be used as the global
223  * threaded_reactions_tasks
224  */
226  unsigned int i;
227  int load, k;
228  int react_count = 0;
229  Reaction* react;
230 
231  for (react = ecs_reactions; react != NULL; react = react->next)
232  react_count += react->region_size;
233 
234  if (react_count == 0)
235  return NULL;
236 
237  /*Divide the number of reactions between the threads*/
238  const int tasks_per_thread = (react_count) / n;
239  ReactGridData* tasks = (ReactGridData*) calloc(sizeof(ReactGridData), n);
240  const int extra = react_count % n;
241 
242  tasks[0].onset = (ReactSet*) malloc(sizeof(ReactSet));
243  tasks[0].onset->reaction = ecs_reactions;
244  tasks[0].onset->idx = 0;
245 
246  for (k = 0, load = 0, react = ecs_reactions; react != NULL; react = react->next) {
247  for (i = 0; i < react->region_size; i++) {
248  if (!react->subregion || react->subregion[i])
249  load++;
250  if (load >= tasks_per_thread + (extra > k)) {
251  tasks[k].offset = (ReactSet*) malloc(sizeof(ReactSet));
252  tasks[k].offset->reaction = react;
253  tasks[k].offset->idx = i;
254 
255  if (++k < n) {
256  tasks[k].onset = (ReactSet*) malloc(sizeof(ReactSet));
257  tasks[k].onset->reaction = react;
258  tasks[k].onset->idx = i + 1;
259  load = 0;
260  }
261  }
262  if (k == n - 1 && react->next == NULL) {
263  tasks[k].offset = (ReactSet*) malloc(sizeof(ReactSet));
264  tasks[k].offset->reaction = react;
265  tasks[k].offset->idx = i;
266  }
267  }
268  }
269  return tasks;
270 }
271 
272 /*ecs_do_reactions takes ReactGridData which defines the set of reactions to be
273  * performed. It calculate the reaction based on grid->old_states and updates
274  * grid->states
275  */
276 void* ecs_do_reactions(void* dataptr) {
277  ReactGridData task = *(ReactGridData*) dataptr;
278  unsigned char started = FALSE, stop = FALSE;
279  unsigned int i, j, k, n, start_idx, stop_idx, offset_idx;
280  double temp, ge_value, val_to_set;
281  double dt = *dt_ptr;
282  Reaction* react;
283 
284  double* states_cache = NULL;
285  double* params_cache = NULL;
286  double* states_cache_dx = NULL;
287  double* results_array = NULL;
288  double* results_array_dx = NULL;
289  double* mc_mults_array = NULL;
290  double dx = FLT_EPSILON;
291  double pd;
292  MAT* jacobian;
293  VEC* x;
294  VEC* b;
295  PERM* pivot;
296 
297  for (react = ecs_reactions; react != NULL; react = react->next) {
298  // TODO: This is bad. Need to refactor
299  if (react->mc3d_indices_offsets != NULL) {
300  /*find start location for this thread*/
301  if (started || react == task.onset->reaction) {
302  if (!started) {
303  started = TRUE;
304  start_idx = task.onset->idx;
305  } else {
306  start_idx = 0;
307  }
308 
309  if (task.offset->reaction == react) {
310  stop_idx = task.offset->idx;
311  stop = TRUE;
312  } else {
313  stop_idx = react->region_size - 1;
314  stop = FALSE;
315  }
316  if (react->num_species_involved == 0)
317  continue;
318  /*allocate data structures*/
320  b = v_get(react->num_species_involved);
321  x = v_get(react->num_species_involved);
322  pivot = px_get(jacobian->m);
323  states_cache = (double*) malloc(sizeof(double) * react->num_species_involved);
324  params_cache = (double*) malloc(sizeof(double) * react->num_params_involved);
325  states_cache_dx = (double*) malloc(sizeof(double) * react->num_species_involved);
326  results_array = (double*) malloc(react->num_species_involved * sizeof(double));
327  results_array_dx = (double*) malloc(react->num_species_involved * sizeof(double));
328  mc_mults_array = (double*) malloc(react->num_species_involved * sizeof(double));
329  for (i = start_idx; i <= stop_idx; i++) {
330  if (!react->subregion || react->subregion[i]) {
331  // TODO: this assumes grids are the same size/shape
332  // add interpolation in case they aren't
333  for (j = 0; j < react->num_species_involved; j++) {
334  offset_idx = i + react->mc3d_indices_offsets[j];
335  states_cache[j] = react->species_states[j][offset_idx];
336  states_cache_dx[j] = react->species_states[j][offset_idx];
337  mc_mults_array[j] = react->mc3d_mults[j][i];
338  }
339  MEM_ZERO(results_array, react->num_species_involved * sizeof(double));
340  for (k = 0; j < react->num_species_involved + react->num_params_involved;
341  k++, j++) {
342  offset_idx = i + react->mc3d_indices_offsets[j];
343  params_cache[k] = react->species_states[j][offset_idx];
344  mc_mults_array[k] = react->mc3d_mults[j][i];
345  }
346  react->reaction(states_cache, params_cache, results_array, mc_mults_array);
347 
348  for (j = 0; j < react->num_species_involved; j++) {
349  states_cache_dx[j] += dx;
350  MEM_ZERO(results_array_dx,
351  react->num_species_involved * sizeof(double));
352  react->reaction(states_cache_dx,
353  params_cache,
354  results_array_dx,
355  mc_mults_array);
356  v_set_val(b, j, dt * results_array[j]);
357 
358  for (k = 0; k < react->num_species_involved; k++) {
359  pd = (results_array_dx[k] - results_array[k]) / dx;
360  m_set_val(jacobian, k, j, (j == k) - dt * pd);
361  }
362  states_cache_dx[j] -= dx;
363  }
364  // solve for x
365  if (react->num_species_involved == 1) {
366  react->species_states[0][i] += v_get_val(b, 0) /
367  m_get_val(jacobian, 0, 0);
368  } else {
369  // find entry in leftmost column with largest absolute value
370  // Pivot
371  for (j = 0; j < react->num_species_involved; j++) {
372  for (k = j + 1; k < react->num_species_involved; k++) {
373  if (abs(m_get_val(jacobian, j, j)) <
374  abs(m_get_val(jacobian, k, j))) {
375  for (n = 0; n < react->num_species_involved; n++) {
376  temp = m_get_val(jacobian, j, n);
378  m_set_val(jacobian, k, n, temp);
379  }
380  }
381  }
382  }
383 
384  for (j = 0; j < react->num_species_involved - 1; j++) {
385  for (k = j + 1; k < react->num_species_involved; k++) {
386  ge_value = m_get_val(jacobian, k, j) /
387  m_get_val(jacobian, j, j);
388  for (n = 0; n < react->num_species_involved; n++) {
389  val_to_set = m_get_val(jacobian, k, n) -
390  ge_value * m_get_val(jacobian, j, n);
391  m_set_val(jacobian, k, n, val_to_set);
392  }
393  v_set_val(b, k, v_get_val(b, k) - ge_value * v_get_val(b, j));
394  }
395  }
396 
397  for (j = react->num_species_involved - 1; j + 1 > 0; j--) {
398  v_set_val(x, j, v_get_val(b, j));
399  for (k = j + 1; k < react->num_species_involved; k++) {
400  if (k != j) {
401  v_set_val(x,
402  j,
403  v_get_val(x, j) -
404  m_get_val(jacobian, j, k) * v_get_val(x, k));
405  }
406  }
407  v_set_val(x, j, v_get_val(x, j) / m_get_val(jacobian, j, j));
408  }
409  for (j = 0; j < react->num_species_involved; j++) {
410  // I think this should be something like
411  // react->species_states[j][mc3d_indices[i]] += v_get_val(x,j);
412  // Since the grid has a uniform discretization, the mc3d_indices
413  // should be the same length. So just need to access the correct
414  // mc3d_indices[i] maybe do two lines?: index =
415  // react->species_indices[j][i] react->species_states[j][index] +=
416  // v_get_val(x,j);
417  offset_idx = i + react->mc3d_indices_offsets[j];
418  react->species_states[j][offset_idx] += v_get_val(x, j);
419  }
420  }
421  }
422  }
423  m_free(jacobian);
424  v_free(b);
425  v_free(x);
426  px_free(pivot);
427 
428  SAFE_FREE(states_cache);
429  SAFE_FREE(states_cache_dx);
430  SAFE_FREE(params_cache);
431  SAFE_FREE(results_array);
432  SAFE_FREE(results_array_dx);
433  SAFE_FREE(mc_mults_array);
434 
435  if (stop)
436  return NULL;
437  }
438  } else {
439  /*find start location for this thread*/
440  if (started || react == task.onset->reaction) {
441  if (!started) {
442  started = TRUE;
443  start_idx = task.onset->idx;
444  } else {
445  start_idx = 0;
446  }
447 
448  if (task.offset->reaction == react) {
449  stop_idx = task.offset->idx;
450  stop = TRUE;
451  } else {
452  stop_idx = react->region_size - 1;
453  stop = FALSE;
454  }
455  if (react->num_species_involved == 0)
456  continue;
457  /*allocate data structures*/
459  b = v_get(react->num_species_involved);
460  x = v_get(react->num_species_involved);
461  pivot = px_get(jacobian->m);
462  states_cache = (double*) malloc(sizeof(double) * react->num_species_involved);
463  params_cache = (double*) malloc(sizeof(double) * react->num_params_involved);
464  states_cache_dx = (double*) malloc(sizeof(double) * react->num_species_involved);
465  results_array = (double*) malloc(react->num_species_involved * sizeof(double));
466  results_array_dx = (double*) malloc(react->num_species_involved * sizeof(double));
467  for (i = start_idx; i <= stop_idx; i++) {
468  if (!react->subregion || react->subregion[i]) {
469  // TODO: this assumes grids are the same size/shape
470  // add interpolation in case they aren't
471  for (j = 0; j < react->num_species_involved; j++) {
472  states_cache[j] = react->species_states[j][i];
473  states_cache_dx[j] = react->species_states[j][i];
474  }
475  MEM_ZERO(results_array, react->num_species_involved * sizeof(double));
476  for (k = 0; j < react->num_species_involved + react->num_params_involved;
477  k++, j++) {
478  params_cache[k] = react->species_states[j][i];
479  }
480  react->reaction(states_cache, params_cache, results_array, NULL);
481 
482  for (j = 0; j < react->num_species_involved; j++) {
483  states_cache_dx[j] += dx;
484  MEM_ZERO(results_array_dx,
485  react->num_species_involved * sizeof(double));
486  react->reaction(states_cache_dx, params_cache, results_array_dx, NULL);
487  v_set_val(b, j, dt * results_array[j]);
488 
489  for (k = 0; k < react->num_species_involved; k++) {
490  pd = (results_array_dx[k] - results_array[k]) / dx;
491  m_set_val(jacobian, k, j, (j == k) - dt * pd);
492  }
493  states_cache_dx[j] -= dx;
494  }
495  // solve for x
496  if (react->num_species_involved == 1) {
497  react->species_states[0][i] += v_get_val(b, 0) /
498  m_get_val(jacobian, 0, 0);
499  } else {
500  // find entry in leftmost column with largest absolute value
501  // Pivot
502  for (j = 0; j < react->num_species_involved; j++) {
503  for (k = j + 1; k < react->num_species_involved; k++) {
504  if (abs(m_get_val(jacobian, j, j)) <
505  abs(m_get_val(jacobian, k, j))) {
506  for (n = 0; n < react->num_species_involved; n++) {
507  temp = m_get_val(jacobian, j, n);
509  m_set_val(jacobian, k, n, temp);
510  }
511  }
512  }
513  }
514 
515  for (j = 0; j < react->num_species_involved - 1; j++) {
516  for (k = j + 1; k < react->num_species_involved; k++) {
517  ge_value = m_get_val(jacobian, k, j) /
518  m_get_val(jacobian, j, j);
519  for (n = 0; n < react->num_species_involved; n++) {
520  val_to_set = m_get_val(jacobian, k, n) -
521  ge_value * m_get_val(jacobian, j, n);
522  m_set_val(jacobian, k, n, val_to_set);
523  }
524  v_set_val(b, k, v_get_val(b, k) - ge_value * v_get_val(b, j));
525  }
526  }
527 
528  for (j = react->num_species_involved - 1; j + 1 > 0; j--) {
529  v_set_val(x, j, v_get_val(b, j));
530  for (k = j + 1; k < react->num_species_involved; k++) {
531  if (k != j) {
532  v_set_val(x,
533  j,
534  v_get_val(x, j) -
535  m_get_val(jacobian, j, k) * v_get_val(x, k));
536  }
537  }
538  v_set_val(x, j, v_get_val(x, j) / m_get_val(jacobian, j, j));
539  }
540  for (j = 0; j < react->num_species_involved; j++) {
541  // I think this should be something like
542  // react->species_states[j][mc3d_indices[i]] += v_get_val(x,j);
543  // Since the grid has a uniform discretization, the mc3d_indices
544  // should be the same length. So just need to access the correct
545  // mc3d_indices[i] maybe do two lines?: index =
546  // react->species_indices[j][i] react->species_states[j][index] +=
547  // v_get_val(x,j);
548  react->species_states[j][i] += v_get_val(x, j);
549  }
550  }
551  }
552  }
553  m_free(jacobian);
554  v_free(b);
555  v_free(x);
556  px_free(pivot);
557 
558  SAFE_FREE(states_cache);
559  SAFE_FREE(states_cache_dx);
560  SAFE_FREE(params_cache);
561  SAFE_FREE(results_array);
562  SAFE_FREE(results_array_dx);
563 
564  if (stop)
565  return NULL;
566  }
567  }
568  }
569  return NULL;
570 }
571 
572 /* run_threaded_reactions
573  * Array ReactGridData tasks length NUM_THREADS and calls ecs_do_reactions and
574  * executes each task with a separate thread
575  */
577  int k;
578  /* launch threads */
579  for (k = 0; k < NUM_THREADS - 1; k++) {
581  }
582  /* run one task in the main thread */
583  ecs_do_reactions(&tasks[NUM_THREADS - 1]);
584 
585  /* wait for them to finish */
587 }
588 
590  Grid_node* grid;
591  ECS_Grid_node* g;
592  double dt = (*dt_ptr);
593 
594  /*Currents to broadcast via MPI*/
595  /*TODO: Handle multiple grids with one pass*/
596  /*Maybe TODO: Should check #currents << #voxels and not the other way round*/
597  int id;
598 
601 
602  for (id = 0, grid = Parallel_grids[0]; grid != NULL; grid = grid->next, id++) {
603  MEM_ZERO(grid->states_cur, sizeof(double) * grid->size_x * grid->size_y * grid->size_z);
604  g = dynamic_cast<ECS_Grid_node*>(grid);
605  if (g)
606  g->do_multicompartment_reactions(NULL);
607  grid->do_grid_currents(grid->states_cur, dt, id);
608  grid->apply_node_flux3D(dt, NULL);
609 
610  // grid->volume_setup();
611  if (grid->hybrid) {
612  grid->hybrid_connections();
613  }
614  grid->dg_adi();
615  }
616  /* transfer concentrations */
618 }
619 
620 extern "C" void scatter_concentrations(void) {
621  /* transfer concentrations to classic NEURON */
622  Grid_node* grid;
623 
624  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
626  }
627 }
628 
629 /*****************************************************************************
630  *
631  * Begin variable step code
632  *
633  *****************************************************************************/
634 
635 /* count the total number of state variables AND store their offset (passed in) in the cvode vector
636  */
637 int ode_count(const int offset) {
638  int count = 0;
639  states_cvode_offset = offset;
640  Grid_node* grid;
641  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
642  count += grid->size_x * grid->size_y * grid->size_z;
643  }
644  return count;
645 }
646 
647 
648 void ecs_atolscale(double* y) {
649  Grid_node* grid;
650  ssize_t i;
651  int grid_size;
652  y += states_cvode_offset;
653  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
654  grid_size = grid->size_x * grid->size_y * grid->size_z;
655  for (i = 0; i < grid_size; i++) {
656  y[i] *= grid->atolscale;
657  }
658  y += grid_size;
659  }
660 }
661 
662 void _ecs_ode_reinit(double* y) {
663  Grid_node* grid;
664  ECS_Grid_node* g;
665 
666  ssize_t i;
667  int grid_size;
668  double* grid_states;
669  y += states_cvode_offset;
670  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
671  grid_states = grid->states;
672  grid_size = grid->size_x * grid->size_y * grid->size_z;
673 
674  for (i = 0; i < grid_size; i++) {
675  y[i] = grid_states[i];
676  }
677  y += grid_size;
678  g = dynamic_cast<ECS_Grid_node*>(grid);
679  if (g)
680  g->initialize_multicompartment_reaction();
681  }
682 }
683 
684 
685 void _rhs_variable_step_ecs(const double* states, double* ydot) {
686  Grid_node* grid;
687  ECS_Grid_node* g;
688  ssize_t i;
689  int grid_size;
690  double dt = *dt_ptr;
691  double* grid_states;
692  double* const orig_ydot = ydot + states_cvode_offset;
693  double const* const orig_states = states + states_cvode_offset;
694  const unsigned char calculate_rhs = ydot == NULL ? 0 : 1;
695  states = orig_states;
696  ydot = orig_ydot;
697  /* prepare for advance by syncing data with local copy */
698  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
699  grid_states = grid->states;
700  grid_size = grid->size_x * grid->size_y * grid->size_z;
701 
702  /* copy the passed in states to local memory (needed to make reaction rates correct) */
703  for (i = 0; i < grid_size; i++) {
704  grid_states[i] = states[i];
705  }
706  states += grid_size;
707  }
708  /* transfer concentrations to classic NEURON states */
710  if (!calculate_rhs) {
711  return;
712  }
713 
714  states = orig_states;
715  ydot = orig_ydot;
716  /* TODO: reactions contribute to adaptive step-size*/
719  }
720  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
721  grid_states = grid->states;
722  grid_size = grid->size_x * grid->size_y * grid->size_z;
723  for (i = 0; i < grid_size; i++) {
724  ydot[i] += (grid_states[i] - states[i]) / dt;
725  grid_states[i] = states[i];
726  }
727  states += grid_size;
728  ydot += grid_size;
729  }
730 
731  ydot = orig_ydot;
732  states = orig_states;
733  /* process currents */
734  for (i = 0, grid = Parallel_grids[0]; grid != NULL; grid = grid->next, i++) {
735  g = dynamic_cast<ECS_Grid_node*>(grid);
736  if (g)
737  g->do_multicompartment_reactions(ydot);
738  grid->do_grid_currents(ydot, 1.0, i);
739 
740  /*Add node fluxes to the result*/
741  grid->apply_node_flux3D(1.0, ydot);
742 
743  ydot += grid_size;
744  }
745  ydot = orig_ydot;
746 
747  /* do the diffusion rates */
748  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
749  grid_size = grid->size_x * grid->size_y * grid->size_z;
750  grid->variable_step_diffusion(states, ydot);
751 
752  ydot += grid_size;
753  states += grid_size;
754  }
755 }
756 
757 
758 void _rhs_variable_step_helper(Grid_node* g, double const* const states, double* ydot) {
759  int num_states_x = g->size_x, num_states_y = g->size_y, num_states_z = g->size_z;
760  double dx = g->dx, dy = g->dy, dz = g->dz;
761  int i, j, k, stop_i, stop_j, stop_k;
762  double dc_x = g->dc_x, dc_y = g->dc_y, dc_z = g->dc_z;
763 
764  double rate_x = dc_x / (dx * dx);
765  double rate_y = dc_y / (dy * dy);
766  double rate_z = dc_z / (dz * dz);
767 
768  /*indices*/
769  int index, prev_i, prev_j, prev_k, next_i, next_j, next_k;
770  double div_x, div_y, div_z;
771 
772  /* Euler advance x, y, z (all points) */
773  stop_i = num_states_x - 1;
774  stop_j = num_states_y - 1;
775  stop_k = num_states_z - 1;
776  if (g->bc->type == NEUMANN) {
777  for (i = 0,
778  index = 0,
779  prev_i = num_states_y * num_states_z,
780  next_i = num_states_y * num_states_z;
781  i < num_states_x;
782  i++) {
783  /*Zero flux boundary conditions*/
784  div_x = (i == 0 || i == stop_i) ? 2. : 1.;
785 
786  for (j = 0, prev_j = index + num_states_z, next_j = index + num_states_z;
787  j < num_states_y;
788  j++) {
789  div_y = (j == 0 || j == stop_j) ? 2. : 1.;
790 
791  for (k = 0, prev_k = index + 1, next_k = index + 1; k < num_states_z;
792  k++, index++, prev_i++, next_i++, prev_j++, next_j++) {
793  div_z = (k == 0 || k == stop_k) ? 2. : 1.;
794 
795  if (stop_i > 0) {
796  ydot[index] += rate_x *
797  (states[prev_i] - 2.0 * states[index] + states[next_i]) /
798  div_x;
799  }
800  if (stop_j > 0) {
801  ydot[index] += rate_y *
802  (states[prev_j] - 2.0 * states[index] + states[next_j]) /
803  div_y;
804  }
805  if (stop_k > 0) {
806  ydot[index] += rate_z *
807  (states[prev_k] - 2.0 * states[index] + states[next_k]) /
808  div_z;
809  }
810  next_k = (k == stop_k - 1) ? index : index + 2;
811  prev_k = index;
812  }
813  prev_j = index - num_states_z;
814  next_j = (j == stop_j - 1) ? prev_j : index + num_states_z;
815  }
816  prev_i = index - num_states_y * num_states_z;
817  next_i = (i == stop_i - 1) ? prev_i : index + num_states_y * num_states_z;
818  }
819  } else {
820  for (i = 0, index = 0, prev_i = 0, next_i = num_states_y * num_states_z; i < num_states_x;
821  i++) {
822  for (j = 0, prev_j = index - num_states_z, next_j = index + num_states_z;
823  j < num_states_y;
824  j++) {
825  for (k = 0, prev_k = index - 1, next_k = index + 1; k < num_states_z;
826  k++, index++, prev_i++, next_i++, prev_j++, next_j++, next_k++, prev_k++) {
827  if (i == 0 || i == stop_i || j == 0 || j == stop_j || k == 0 || k == stop_k) {
828  // set to zero to prevent currents altering concentrations at the boundary
829  ydot[index] = 0;
830  } else {
831  ydot[index] += rate_x *
832  (states[prev_i] - 2.0 * states[index] + states[next_i]);
833 
834  ydot[index] += rate_y *
835  (states[prev_j] - 2.0 * states[index] + states[next_j]);
836 
837  ydot[index] += rate_z *
838  (states[prev_k] - 2.0 * states[index] + states[next_k]);
839  }
840  }
841  prev_j = index - num_states_z;
842  next_j = index + num_states_z;
843  }
844  prev_i = index - num_states_y * num_states_z;
845  next_i = index + num_states_y * num_states_z;
846  }
847  }
848  /*
849  for (i = 1, index = (num_states_y+1)*num_states_z + 1,
850  prev_i = num_states_z + 1, next_i = (2*num_states_y+1)*num_states_z + 1;
851  i < stop_i; i++) {
852  for (j = 1, prev_j = index - num_states_z, next_j = index + num_states_z; j <
853  stop_j; j++) {
854 
855  for(k = 1, prev_k = index - 1, next_k = index + 1; k < stop_k;
856  k++, index++, prev_i++, next_i++, prev_j++, next_j++, next_k++) {
857  if(index != i*num_states_y*num_states_z + j*num_states_z + k)
858  {
859  fprintf(stderr,"%i \t %i %i %i\n", index,i,j,k);
860  }
861  if(prev_i != (i-1)*num_states_y*num_states_z + j*num_states_z + k)
862  {
863  fprintf(stderr,"prev_i %i %i \t %i %i %i\n",
864  prev_i,(i-1)*num_states_y*num_states_z + j*num_states_z + k,i,j,k);
865  }
866  if(next_i != (i+1)*num_states_y*num_states_z + j*num_states_z + k)
867  {
868  fprintf(stderr,"next_i %i %i \t %i %i %i\n",
869  next_i,(i+1)*num_states_y*num_states_z + j*num_states_z + k,i,j,k);
870  }
871  if(prev_j != i*num_states_y*num_states_z + (j-1)*num_states_z + k)
872  {
873  fprintf(stderr,"prev_j %i %i \t %i %i %i\n",
874  prev_j,i*num_states_y*num_states_z + (j-1)*num_states_z + k,i,j,k);
875  }
876  if(next_j != i*num_states_y*num_states_z + (j+1)*num_states_z + k)
877  {
878  fprintf(stderr,"next_j %i %i \t %i %i %i\n",
879  next_j,i*num_states_y*num_states_z + (j+1)*num_states_z + k,i,j,k);
880  }
881  if(prev_k != i*num_states_y*num_states_z + j*num_states_z + k-1)
882  {
883  fprintf(stderr,"prev_k %i %i \t %i %i %i\n",
884  prev_k,i*num_states_y*num_states_z + j*num_states_z + k-1,i,j,k);
885  }
886  if(next_k != i*num_states_y*num_states_z + j*num_states_z + k+1)
887  {
888  fprintf(stderr,"next_k %i %i \t %i %i %i\n",
889  next_k,i*num_states_y*num_states_z + j*num_states_z + k+1,i,j,k);
890  }
891 
892  ydot[index] += rate_x * (states[prev_i] -
893  2.0 * states[index] + states[next_i]);
894 
895  ydot[index] += rate_y * (states[prev_j] -
896  2.0 * states[index] + states[next_j]);
897 
898  ydot[index] += rate_z * (states[prev_k] -
899  2.0 * states[index] + states[next_k]);
900 
901  }
902  index += 2; //skip z boundaries
903  //prev_j = index - num_states_z;
904  //next_j = index + num_states_z;
905  }
906  index += 2*num_states_z; //skip y boundaries
907  //prev_i = index - num_states_y*num_states_z;
908  //next_i = index + num_states_y*num_states_z;
909  }
910  }
911  */
912 }
913 
914 // p1 = b p2 = states
915 void ics_ode_solve(double dt, double* RHS, const double* states) {
916  Grid_node* grid;
917  ssize_t i;
918  int grid_size = 0;
919  double* grid_states;
920  double const* const orig_states = states + states_cvode_offset;
921  const unsigned char calculate_rhs = RHS == NULL ? 0 : 1;
922  double* const orig_RHS = RHS + states_cvode_offset;
923  states = orig_states;
924  RHS = orig_RHS;
925 
926  /* prepare for advance by syncing data with local copy */
927  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
928  grid_states = grid->states;
929  grid_size = grid->size_x * grid->size_y * grid->size_z;
930 
931  /* copy the passed in states to local memory (needed to make reaction rates correct) */
932  for (i = 0; i < grid_size; i++) {
933  grid_states[i] = states[i];
934  }
935  states += grid_size;
936  }
937  /* transfer concentrations to classic NEURON states */
939  if (!calculate_rhs) {
940  return;
941  }
942 
943  states = orig_states;
944  RHS = orig_RHS;
945 
946  /* TODO: reactions contribute to adaptive step-size*/
949  }
950  /* do the diffusion rates */
951  for (grid = Parallel_grids[0]; grid != NULL; grid = grid->next) {
953  RHS += grid_size;
954  states += grid_size;
955  }
956 }
957 /*****************************************************************************
958  *
959  * End variable step code
960  *
961  *****************************************************************************/
962 
963 
964 /* solve_dd_clhs_tridiag uses Thomas Algorithm to solves a
965  * diagonally dominant tridiagonal matrix (Ax=b), where the
966  * triple (lower, diagonal and upper) are repeated to form A.
967  * N - length of the matrix
968  * l_diag - lower diagonal
969  * diag - diagonal
970  * u_diag - upper diagonal
971  * b - pointer to the RHS (length N)
972  * lbc_diag - the lower boundary diagonal (the first diagonal element)
973  * lbc_u_diag - the lower boundary upper diagonal (the first upper
974  * diagonal element)
975  * ubc_l_diag - the upper boundary lower diagonal (the last lower
976  * diagonal element)
977  * ubc_diag - the upper boundary diagonal (the last diagonal element)
978  * The solution (x) is stored in b.
979  * c - scratchpad array, N - 1 doubles long
980  */
981 static int solve_dd_clhs_tridiag(const int N,
982  const double l_diag,
983  const double diag,
984  const double u_diag,
985  const double lbc_diag,
986  const double lbc_u_diag,
987  const double ubc_l_diag,
988  const double ubc_diag,
989  double* const b,
990  double* const c) {
991  int i;
992 
993 
994  c[0] = lbc_u_diag / lbc_diag;
995  b[0] = b[0] / lbc_diag;
996 
997  for (i = 1; i < N - 1; i++) {
998  c[i] = u_diag / (diag - l_diag * c[i - 1]);
999  b[i] = (b[i] - l_diag * b[i - 1]) / (diag - l_diag * c[i - 1]);
1000  }
1001  b[N - 1] = (b[N - 1] - ubc_l_diag * b[N - 2]) / (ubc_diag - ubc_l_diag * c[N - 2]);
1002 
1003  /*back substitution*/
1004  for (i = N - 2; i >= 0; i--) {
1005  b[i] = b[i] - c[i] * b[i + 1];
1006  }
1007  return 0;
1008 }
1009 
1010 /*
1011 static int solve_dd_clhs_tridiag_rev(const int N, const double l_diag, const double diag,
1012  const double u_diag, const double lbc_diag, const double lbc_u_diag,
1013  const double ubc_l_diag, const double ubc_diag, double* const d, double* const a)
1014 {
1015  int i;
1016 
1017 
1018  a[N-2] = ubc_l_diag/ubc_diag;
1019  d[N-1] = d[N-1]/ubc_diag;
1020 
1021  for(i=N-2; i>0; i--)
1022  {
1023  a[i-1] = l_diag/(diag - u_diag*a[i]);
1024  d[i] = (d[i] - u_diag*d[i+1])/(diag - u_diag*a[i]);
1025  }
1026  d[0] = (d[0] - lbc_u_diag*d[1])/(lbc_diag - lbc_u_diag*a[0]);
1027 
1028  for(i=1; i<N; i++)
1029  {
1030  d[i] = d[i] - a[i-1]*d[i-1];
1031 
1032  }
1033  return 0;
1034 }
1035 unsigned char callcount = TRUE;
1036 static int solve_dd_clhs_tridiag(const int N, const double l_diag, const double diag,
1037  const double u_diag, const double lbc_diag, const double lbc_u_diag,
1038  const double ubc_l_diag, const double ubc_diag, double* const b, double* const c)
1039 {
1040  if(callcount)
1041  {
1042  callcount = FALSE;
1043  return solve_dd_clhs_tridiag_for(N, l_diag, diag, u_diag, lbc_diag, lbc_u_diag, ubc_l_diag,
1044 ubc_diag, b, c);
1045  }
1046  else
1047  {
1048  callcount = TRUE;
1049  return solve_dd_clhs_tridiag_rev(N, l_diag, diag, u_diag, lbc_diag, lbc_u_diag, ubc_l_diag,
1050 ubc_diag, b, c);
1051  }
1052 }
1053 */
1054 
1055 
1056 /* dg_adi_x performs the first of 3 steps in DG-ADI
1057  * g - the parameters and state of the grid
1058  * dt - the time step
1059  * y - the index for the y plane
1060  * z - the index for the z plane
1061  * state - where the output of this step is stored
1062  * scratch - scratchpad array of doubles, length g->size_x - 1
1063  */
1065  const double dt,
1066  const int y,
1067  const int z,
1068  double const* const state,
1069  double* const RHS,
1070  double* const scratch) {
1071  int yp, ym, zp, zm;
1072  int x;
1073  double r = g->dc_x * dt / SQ(g->dx);
1074  double div_y, div_z;
1075  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
1076  if (g->bc->type == DIRICHLET &&
1077  (y == 0 || z == 0 || y == g->size_y - 1 || z == g->size_z - 1)) {
1078  for (x = 0; x < g->size_x; x++)
1079  RHS[x] = g->bc->value;
1080  return;
1081  }
1082 
1083  if (g->size_y > 1) {
1084  yp = (y == g->size_y - 1) ? y - 1 : y + 1;
1085  ym = (y == 0) ? y + 1 : y - 1;
1086  div_y = (y == 0 || y == g->size_y - 1) ? 2. : 1.;
1087  } else {
1088  yp = 0;
1089  ym = 0;
1090  div_y = 1;
1091  }
1092  if (g->size_z > 1) {
1093  zp = (z == g->size_z - 1) ? z - 1 : z + 1;
1094  zm = (z == 0) ? z + 1 : z - 1;
1095  div_z = (z == 0 || z == g->size_z - 1) ? 2. : 1.;
1096  } else {
1097  zp = 0;
1098  zm = 0;
1099  div_z = 1;
1100  }
1101 
1102  if (g->bc->type == NEUMANN) {
1103  /*zero flux boundary condition*/
1104  RHS[0] = state[IDX(0, y, z)] + g->states_cur[IDX(0, y, z)] +
1105  dt *
1106  ((g->dc_y / SQ(g->dy)) *
1107  (state[IDX(0, yp, z)] - 2. * state[IDX(0, y, z)] + state[IDX(0, ym, z)]) /
1108  div_y +
1109  (g->dc_z / SQ(g->dz)) *
1110  (state[IDX(0, y, zp)] - 2. * state[IDX(0, y, z)] + state[IDX(0, y, zm)]) /
1111  div_z);
1112  if (g->size_x > 1) {
1113  RHS[0] += dt * (g->dc_x / SQ(g->dx)) * (state[IDX(1, y, z)] - state[IDX(0, y, z)]);
1114  x = g->size_x - 1;
1115  RHS[x] =
1116  state[IDX(x, y, z)] + g->states_cur[IDX(x, y, z)] +
1117  dt * ((g->dc_x / SQ(g->dx)) * (state[IDX(x - 1, y, z)] - state[IDX(x, y, z)]) +
1118  (g->dc_y / SQ(g->dy)) *
1119  (state[IDX(x, yp, z)] - 2. * state[IDX(x, y, z)] + state[IDX(x, ym, z)]) /
1120  div_y +
1121  (g->dc_z / SQ(g->dz)) *
1122  (state[IDX(x, y, zp)] - 2. * state[IDX(x, y, z)] + state[IDX(x, y, zm)]) /
1123  div_z);
1124  }
1125  } else {
1126  RHS[0] = g->bc->value;
1127  RHS[g->size_x - 1] = g->bc->value;
1128  }
1129  for (x = 1; x < g->size_x - 1; x++) {
1130 #ifndef __PGI
1131  __builtin_prefetch(&(state[IDX(x + PREFETCH, y, z)]), 0, 1);
1132  __builtin_prefetch(&(state[IDX(x + PREFETCH, yp, z)]), 0, 0);
1133  __builtin_prefetch(&(state[IDX(x + PREFETCH, ym, z)]), 0, 0);
1134 #endif
1135  RHS[x] = state[IDX(x, y, z)] +
1136  dt *
1137  ((g->dc_x / SQ(g->dx)) *
1138  (state[IDX(x + 1, y, z)] - 2. * state[IDX(x, y, z)] +
1139  state[IDX(x - 1, y, z)]) /
1140  2. +
1141  (g->dc_y / SQ(g->dy)) *
1142  (state[IDX(x, yp, z)] - 2. * state[IDX(x, y, z)] + state[IDX(x, ym, z)]) /
1143  div_y +
1144  (g->dc_z / SQ(g->dz)) *
1145  (state[IDX(x, y, zp)] - 2. * state[IDX(x, y, z)] + state[IDX(x, y, zm)]) /
1146  div_z) +
1147  g->states_cur[IDX(x, y, z)];
1148  }
1149  if (g->size_x > 1) {
1150  if (g->bc->type == NEUMANN)
1151  solve_dd_clhs_tridiag(g->size_x,
1152  -r / 2.0,
1153  1.0 + r,
1154  -r / 2.0,
1155  1.0 + r / 2.0,
1156  -r / 2.0,
1157  -r / 2.0,
1158  1.0 + r / 2.0,
1159  RHS,
1160  scratch);
1161  else
1163  g->size_x, -r / 2.0, 1.0 + r, -r / 2.0, 1.0, 0, 0, 1.0, RHS, scratch);
1164  }
1165 }
1166 
1167 
1168 /* dg_adi_y performs the second of 3 steps in DG-ADI
1169  * g - the parameters and state of the grid
1170  * dt - the time step
1171  * x - the index for the x plane
1172  * z - the index for the z plane
1173  * state - the values from the first step, which are
1174  * overwritten by the output of this step
1175  * scratch - scratchpad array of doubles, length g->size_y - 1
1176  */
1178  double const dt,
1179  int const x,
1180  int const z,
1181  double const* const state,
1182  double* const RHS,
1183  double* const scratch) {
1184  int y;
1185  double r = (g->dc_y * dt / SQ(g->dy));
1186  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
1187  if (g->bc->type == DIRICHLET &&
1188  (x == 0 || z == 0 || x == g->size_x - 1 || z == g->size_z - 1)) {
1189  for (y = 0; y < g->size_y; y++)
1190  RHS[y] = g->bc->value;
1191  return;
1192  }
1193  if (g->size_y == 1) {
1194  if (g->bc->type == NEUMANN)
1195  RHS[0] = state[x + z * g->size_x];
1196  else
1197  RHS[0] = g->bc->value;
1198  return;
1199  }
1200  if (g->bc->type == NEUMANN) {
1201  /*zero flux boundary condition*/
1202  RHS[0] = state[x + z * g->size_x] -
1203  (g->dc_y * dt / SQ(g->dy)) *
1204  (g->states[IDX(x, 1, z)] - 2.0 * g->states[IDX(x, 0, z)] +
1205  g->states[IDX(x, 1, z)]) /
1206  4.0;
1207  y = g->size_y - 1;
1208  RHS[y] = state[x + (z + y * g->size_z) * g->size_x] -
1209  (g->dc_y * dt / SQ(g->dy)) *
1210  (g->states[IDX(x, y - 1, z)] - 2. * g->states[IDX(x, y, z)] +
1211  g->states[IDX(x, y - 1, z)]) /
1212  4.0;
1213  } else {
1214  RHS[0] = g->bc->value;
1215  RHS[g->size_y - 1] = g->bc->value;
1216  }
1217  for (y = 1; y < g->size_y - 1; y++) {
1218 #ifndef __PGI
1219  __builtin_prefetch(&state[x + (z + (y + PREFETCH) * g->size_z) * g->size_x], 0, 0);
1220  __builtin_prefetch(&(g->states[IDX(x, y + PREFETCH, z)]), 0, 1);
1221 #endif
1222  RHS[y] = state[x + (z + y * g->size_z) * g->size_x] -
1223  (g->dc_y * dt / SQ(g->dy)) *
1224  (g->states[IDX(x, y + 1, z)] - 2. * g->states[IDX(x, y, z)] +
1225  g->states[IDX(x, y - 1, z)]) /
1226  2.0;
1227  }
1228  if (g->bc->type == NEUMANN)
1229  solve_dd_clhs_tridiag(g->size_y,
1230  -r / 2.0,
1231  1.0 + r,
1232  -r / 2.0,
1233  1.0 + r / 2.0,
1234  -r / 2.0,
1235  -r / 2.0,
1236  1.0 + r / 2.0,
1237  RHS,
1238  scratch);
1239  else
1240  solve_dd_clhs_tridiag(g->size_y, -r / 2., 1. + r, -r / 2., 1.0, 0, 0, 1.0, RHS, scratch);
1241 }
1242 
1243 
1244 /* dg_adi_z performs the final step in DG-ADI
1245  * g - the parameters and state of the grid
1246  * dt - the time step
1247  * x - the index for the x plane
1248  * y - the index for the y plane
1249  * state - the values from the second step, which are
1250  * overwritten by the output of this step
1251  * scratch - scratchpad array of doubles, length g->size_z - 1
1252  */
1254  double const dt,
1255  int const x,
1256  int const y,
1257  double const* const state,
1258  double* const RHS,
1259  double* const scratch) {
1260  int z;
1261  double r = g->dc_z * dt / SQ(g->dz);
1262  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
1263  if (g->bc->type == DIRICHLET &&
1264  (x == 0 || y == 0 || x == g->size_x - 1 || y == g->size_y - 1)) {
1265  for (z = 0; z < g->size_z; z++)
1266  RHS[z] = g->bc->value;
1267  return;
1268  }
1269 
1270  if (g->size_z == 1) {
1271  if (g->bc->type == NEUMANN)
1272  RHS[0] = state[y + g->size_y * x];
1273  else
1274  RHS[0] = g->bc->value;
1275  return;
1276  }
1277 
1278  if (g->bc->type == NEUMANN) {
1279  /*zero flux boundary condition*/
1280  RHS[0] = state[y + g->size_y * (x * g->size_z)] -
1281  (g->dc_z * dt / SQ(g->dz)) *
1282  (g->states[IDX(x, y, 1)] - 2.0 * g->states[IDX(x, y, 0)] +
1283  g->states[IDX(x, y, 1)]) /
1284  4.0;
1285  z = g->size_z - 1;
1286  RHS[z] = state[y + g->size_y * (x * g->size_z + z)] -
1287  (g->dc_z * dt / SQ(g->dz)) *
1288  (g->states[IDX(x, y, z - 1)] - 2.0 * g->states[IDX(x, y, z)] +
1289  g->states[IDX(x, y, z - 1)]) /
1290  4.0;
1291 
1292  } else {
1293  RHS[0] = g->bc->value;
1294  RHS[g->size_z - 1] = g->bc->value;
1295  }
1296  for (z = 1; z < g->size_z - 1; z++) {
1297  RHS[z] = state[y + g->size_y * (x * g->size_z + z)] -
1298  (g->dc_z * dt / SQ(g->dz)) *
1299  (g->states[IDX(x, y, z + 1)] - 2. * g->states[IDX(x, y, z)] +
1300  g->states[IDX(x, y, z - 1)]) /
1301  2.;
1302  }
1303 
1304  if (g->bc->type == NEUMANN)
1305  solve_dd_clhs_tridiag(g->size_z,
1306  -r / 2.0,
1307  1.0 + r,
1308  -r / 2.0,
1309  1.0 + r / 2.0,
1310  -r / 2.0,
1311  -r / 2.0,
1312  1.0 + r / 2.0,
1313  RHS,
1314  scratch);
1315  else
1316  solve_dd_clhs_tridiag(g->size_z, -r / 2., 1. + r, -r / 2., 1.0, 0, 0, 1.0, RHS, scratch);
1317 }
1318 
1319 static void* ecs_do_dg_adi(void* dataptr) {
1320  ECSAdiGridData* data = (ECSAdiGridData*) dataptr;
1321  int start = data->start;
1322  int stop = data->stop;
1323  int i, j, k;
1324  ECSAdiDirection* ecs_adi_dir = data->ecs_adi_dir;
1325  double dt = *dt_ptr;
1326  int sizej = data->sizej;
1327  ECS_Grid_node* g = data->g;
1328  double* state_in = ecs_adi_dir->states_in;
1329  double* state_out = ecs_adi_dir->states_out;
1330  int offset = ecs_adi_dir->line_size;
1331  double* scratchpad = data->scratchpad;
1332  void (*ecs_dg_adi_dir)(
1333  ECS_Grid_node*, double, int, int, double const* const, double* const, double* const) =
1334  ecs_adi_dir->ecs_dg_adi_dir;
1335  for (k = start; k < stop; k++) {
1336  i = k / sizej;
1337  j = k % sizej;
1338  ecs_dg_adi_dir(g, dt, i, j, state_in, &state_out[k * offset], scratchpad);
1339  }
1340 
1341  return NULL;
1342 }
1343 
1345  const int j,
1346  ECS_Grid_node* g,
1347  ECSAdiDirection* ecs_adi_dir,
1348  const int n) {
1349  int k;
1350  /* when doing any given direction, the number of tasks is the product of the other two, so
1351  * multiply everything then divide out the current direction */
1352  const int tasks_per_thread = (g->size_x * g->size_y * g->size_z / n) / NUM_THREADS;
1353  const int extra = (g->size_x * g->size_y * g->size_z / n) % NUM_THREADS;
1354 
1355  g->ecs_tasks[0].start = 0;
1356  g->ecs_tasks[0].stop = tasks_per_thread + (extra > 0);
1357  g->ecs_tasks[0].sizej = j;
1358  g->ecs_tasks[0].ecs_adi_dir = ecs_adi_dir;
1359  for (k = 1; k < NUM_THREADS; k++) {
1360  g->ecs_tasks[k].start = g->ecs_tasks[k - 1].stop;
1361  g->ecs_tasks[k].stop = g->ecs_tasks[k].start + tasks_per_thread + (extra > k);
1362  g->ecs_tasks[k].sizej = j;
1363  g->ecs_tasks[k].ecs_adi_dir = ecs_adi_dir;
1364  }
1365  g->ecs_tasks[NUM_THREADS - 1].stop = i * j;
1366  /* launch threads */
1367  for (k = 0; k < NUM_THREADS - 1; k++) {
1368  TaskQueue_add_task(AllTasks, &ecs_do_dg_adi, &(g->ecs_tasks[k]), NULL);
1369  }
1370  /* run one task in the main thread */
1371  ecs_do_dg_adi(&(g->ecs_tasks[NUM_THREADS - 1]));
1372  /* wait for them to finish */
1374 }
1375 
1377  g->ecs_adi_dir_x->ecs_dg_adi_dir = ecs_dg_adi_x;
1378  g->ecs_adi_dir_y->ecs_dg_adi_dir = ecs_dg_adi_y;
1379  g->ecs_adi_dir_z->ecs_dg_adi_dir = ecs_dg_adi_z;
1380 }
short index
Definition: cabvars.h:10
virtual void apply_node_flux3D(double dt, double *states)=0
bool hybrid
Definition: grids.h:139
int size_y
Definition: grids.h:130
virtual void hybrid_connections()=0
virtual void variable_step_diffusion(const double *states, double *ydot)=0
int size_x
Definition: grids.h:129
double * states_cur
Definition: grids.h:128
double * states
Definition: grids.h:124
double atolscale
Definition: grids.h:167
virtual void set_num_threads(const int n)=0
Grid_node * next
Definition: grids.h:122
virtual void do_grid_currents(double *, double, int)=0
virtual void variable_step_ode_solve(double *RHS, double dt)=0
int size_z
Definition: grids.h:131
virtual int dg_adi()=0
virtual void scatter_grid_concentrations()=0
double dt
Definition: netcvode.cpp:76
static double jacobian(void *v)
Definition: cvodeobj.cpp:266
#define c
#define TRUE
Definition: err.c:57
#define FALSE
Definition: err.c:56
void MEM_ZERO(char *ptr, int len)
Definition: extras.c:58
#define diag(s)
Definition: fmenu.cpp:192
double * dt_ptr
Definition: grids.cpp:14
Grid_node * Parallel_grids[100]
Definition: grids.cpp:16
#define IDX(x, y, z)
Definition: grids.h:18
#define NEUMANN
Definition: grids.h:32
#define SAFE_FREE(ptr)
Definition: grids.h:13
#define DIRICHLET
Definition: grids.h:33
void(* ECSReactionRate)(double *, double *, double *, double *)
Definition: grids.h:96
#define SQ(x)
Definition: grids.h:24
void start()
Definition: hel2mos.cpp:204
void stop()
Definition: hel2mos.cpp:212
#define assert(ex)
Definition: hocassrt.h:32
static int started
Definition: init.c:142
void
static double v_get(void *v)
Definition: ivocvect.cpp:1395
int abs(int)
#define m_set_val(A, i, j, val)
Definition: matrix.h:277
PERM * px_get(int)
#define v_set_val(x, i, val)
Definition: matrix.h:265
int v_free(VEC *)
int px_free(PERM *)
Definition: memory.c:201
int m_free(MAT *)
#define id
Definition: md1redef.h:33
#define i
Definition: md1redef.h:12
#define RHS(i)
Definition: multisplit.cpp:66
static unsigned row
Definition: nonlin.cpp:85
int const size_t const size_t n
Definition: nrngsl.h:11
for(i=0;i< n;i++)
if(status)
size_t j
static philox4x32_key_t k
Definition: nrnran123.cpp:11
MAT * m_get(int, int)
Definition: memory.c:36
static char scratch[MAXLINE+1]
Definition: otherio.c:41
#define g
Definition: passive0.cpp:21
#define data
Definition: rbtqueue.cpp:49
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
#define m_get_val(A, i, j)
Definition: rxd.h:5
#define PREFETCH
Definition: rxd.h:7
#define v_get_val(x, i)
Definition: rxd.h:4
static int solve_dd_clhs_tridiag(const int N, const double l_diag, const double diag, const double u_diag, const double lbc_diag, const double lbc_u_diag, const double ubc_l_diag, const double ubc_diag, double *const b, double *const c)
static void ecs_dg_adi_y(ECS_Grid_node *g, double const dt, int const x, int const z, double const *const state, double *const RHS, double *const scratch)
void set_num_threads_3D(const int n)
static void run_threaded_reactions(ReactGridData *tasks)
ReactGridData * create_threaded_reactions(const int n)
void * ecs_do_reactions(void *dataptr)
static void ecs_refresh_reactions(int)
void _rhs_variable_step_helper(Grid_node *g, double const *const states, double *ydot)
static void ecs_dg_adi_x(ECS_Grid_node *g, const double dt, const int y, const int z, double const *const state, double *const RHS, double *const scratch)
void scatter_concentrations(void)
void ics_register_reaction(int list_idx, int num_species, int num_params, int *species_id, uint64_t *mc3d_start_indices, int mc3d_region_size, double *mc3d_mults, ECSReactionRate f)
void ecs_set_adi_homogeneous(ECS_Grid_node *g)
double * t_ptr
Definition: grids.cpp:15
void ecs_register_reaction(int list_idx, int num_species, int num_params, int *species_id, ECSReactionRate f)
int ode_count(const int offset)
TaskQueue * AllTasks
Definition: rxd.cpp:28
int states_cvode_offset
double * states
Definition: rxd.cpp:62
void ecs_atolscale(double *y)
pthread_t * Threads
Definition: rxd.cpp:27
void ecs_run_threaded_dg_adi(const int i, const int j, ECS_Grid_node *g, ECSAdiDirection *ecs_adi_dir, const int n)
Reaction * ecs_create_reaction(int list_idx, int num_species, int num_params, int *species_ids, ECSReactionRate f, unsigned char *subregion, uint64_t *mc3d_start_indices, int mc3d_region_size, double *mc3d_mults)
void clear_rates_ecs(void)
static void ecs_dg_adi_z(ECS_Grid_node *g, double const dt, int const x, int const y, double const *const state, double *const RHS, double *const scratch)
static void * ecs_do_dg_adi(void *dataptr)
void _rhs_variable_step_ecs(const double *states, double *ydot)
void _fadvance_fixed_step_3D(void)
void _ecs_ode_reinit(double *y)
int NUM_THREADS
Definition: rxd.cpp:26
void ecs_register_subregion_reaction_ecs(int list_idx, int num_species, int num_params, int *species_id, unsigned char *my_subregion, ECSReactionRate f)
void ics_ode_solve(double dt, double *RHS, const double *states)
ReactGridData * threaded_reactions_tasks
Reaction * ecs_reactions
#define NULL
Definition: sptree.h:16
double * states_in
Definition: grids.h:275
int line_size
Definition: grids.h:277
double * states_out
Definition: grids.h:276
void(* ecs_dg_adi_dir)(ECS_Grid_node *, const double, const int, const int, double const *const, double *const, double *const)
Definition: grids.h:268
Definition: matrix.h:73
Definition: matrix.h:87
ReactSet * onset
Definition: rxd.h:38
ReactSet * offset
Definition: rxd.h:39
Definition: rxd.h:32
int idx
Definition: rxd.h:34
Reaction * reaction
Definition: rxd.h:33
double ** species_states
Definition: grids.h:102
unsigned int region_size
Definition: grids.h:104
uint64_t * mc3d_indices_offsets
Definition: grids.h:105
unsigned char * subregion
Definition: grids.h:103
ECSReactionRate reaction
Definition: grids.h:99
double ** mc3d_mults
Definition: grids.h:106
struct Reaction * next
Definition: grids.h:98
unsigned int num_params_involved
Definition: grids.h:101
unsigned int num_species_involved
Definition: grids.h:100
Definition: rxd.h:109
Definition: matrix.h:67