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