NEURON
rxd_intracellular.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 <unistd.h>
9 
10 #include<cmath>
11 
12 extern int NUM_THREADS;
13 extern TaskQueue* AllTasks;
14 extern double* states;
15 const int ICS_PREFETCH = 3;
16 
17 /*
18  * Sets the data to be used by the grids for 1D/3D hybrid models
19  */
20 extern "C" void set_hybrid_data(int64_t* num_1d_indices_per_grid, int64_t* num_3d_indices_per_grid, int64_t* hybrid_indices1d, int64_t* hybrid_indices3d, int64_t* num_3d_indices_per_1d_seg, int64_t* hybrid_grid_ids, double* rates, double* volumes1d, double* volumes3d, double* dxs)
21 {
22  Grid_node* grid;
23  int i, j, k, id;
24  int grid_id_check = 0;
25 
26  int index_ctr_1d = 0;
27  int index_ctr_3d = 0;
28 
29  int num_grid_3d_indices;
30  int num_grid_1d_indices;
31 
32  double dx;
33 
34  //loop over grids
35  for (id = 0, grid = Parallel_grids[0]; grid != NULL; grid = grid -> next, id++) {
36  //if the grid we are on is the next grid in the hybrid grids
37  if(id == hybrid_grid_ids[grid_id_check])
38  {
39  num_grid_1d_indices = num_1d_indices_per_grid[grid_id_check];
40  num_grid_3d_indices = num_3d_indices_per_grid[grid_id_check];
41  //Allocate memory for hybrid data
42  grid->hybrid = true;
43  grid->hybrid_data->indices1d = (long*)malloc(sizeof(long)*num_grid_1d_indices);
44  grid->hybrid_data->num_3d_indices_per_1d_seg = (long*)malloc(sizeof(long)*num_grid_1d_indices);
45  grid->hybrid_data->volumes1d = (double*)malloc(sizeof(double)*num_grid_1d_indices);
46 
47 
48  grid->hybrid_data->indices3d = (long*)malloc(sizeof(long)*num_grid_3d_indices);
49  grid->hybrid_data->rates = (double*)malloc(sizeof(double)*num_grid_3d_indices);
50  grid->hybrid_data->volumes3d = (double*)malloc(sizeof(double)*num_grid_3d_indices);
51 
52  dx = *dxs++;
53 
54  //Assign grid data
55  grid->hybrid_data->num_1d_indices = num_grid_1d_indices;
56  for(i = 0, k = 0; i < num_grid_1d_indices; i++, index_ctr_1d++)
57  {
58  grid->hybrid_data->indices1d[i] = hybrid_indices1d[index_ctr_1d];
59  grid->hybrid_data->num_3d_indices_per_1d_seg[i] = num_3d_indices_per_1d_seg[index_ctr_1d];
60  grid->hybrid_data->volumes1d[i] = volumes1d[index_ctr_1d];
61 
62  for (j = 0; j < num_3d_indices_per_1d_seg[index_ctr_1d]; j++, index_ctr_3d++, k++)
63  {
64  grid->hybrid_data->indices3d[k] = hybrid_indices3d[index_ctr_3d];
65  grid->hybrid_data->rates[k] = rates[index_ctr_3d];
66  grid->hybrid_data->volumes3d[k] = volumes3d[index_ctr_3d];
67  ((ICS_Grid_node*)grid)->_ics_alphas[hybrid_indices3d[index_ctr_3d]] = volumes3d[index_ctr_3d]/dx;
68  }
69  }
70  grid_id_check++;
71  }
72  }
73 }
74 
75 /* solve Ax=b where A is a diagonally dominant tridiagonal matrix
76  * N - length of the matrix
77  * l_diag - pointer to the lower diagonal (length N-1)
78  * diag - pointer to diagonal (length N)
79  * u_diag - pointer to the upper diagonal (length N-1)
80  * B - pointer to the RHS (length N)
81  * The solution (x) will be stored in B.
82  * l_diag, diag and u_diag are not changed.
83  * c - scratch pad, preallocated memory for (N-1) doubles
84  */
85 static int solve_dd_tridiag(int N, const double* l_diag, const double* diag,
86  const double* u_diag, double* b, double *c)
87 {
88  int i;
89 
90  c[0] = u_diag[0]/diag[0];
91  b[0] = b[0]/diag[0];
92 
93  for(i=1;i<N-1;i++)
94  {
95  c[i] = u_diag[i]/(diag[i]-l_diag[i-1]*c[i-1]);
96  b[i] = (b[i]-l_diag[i-1]*b[i-1])/(diag[i]-l_diag[i-1]*c[i-1]);
97  }
98  b[N-1] = (b[N-1]-l_diag[N-2]*b[N-2])/(diag[N-1]-l_diag[N-2]*c[N-2]);
99 
100 
101  /*back substitution*/
102  for(i=N-2;i>=0;i--)
103  {
104  b[i]=b[i]-c[i]*b[i+1];
105  }
106  return 0;
107 }
108 
109 //Homogeneous diffusion coefficient
110 void ics_find_deltas(long start, long stop, long node_start, double* delta, long* line_defs, long* ordered_nodes, double* states, double dc, double* alphas){
111  long ordered_index = node_start;
112  long current_index = -1;
113  long next_index = -1;
114  double prev_state;
115  double current_state;
116  double next_state;
117  double prev_alpha;
118  double current_alpha;
119  double next_alpha;
120  for(int i = start; i < stop - 1; i += 2)
121  {
122  long line_start = ordered_nodes[ordered_index];
123  int line_length = line_defs[i+1];
124  if(line_length > 1)
125  {
126  current_index = line_start;
127  ordered_index++;
128  next_index = ordered_nodes[ordered_index];
129  current_state = states[current_index];
130  next_state = states[next_index];
131  current_alpha = alphas[current_index];
132  next_alpha = alphas[next_index];
133  delta[current_index] = dc * next_alpha * current_alpha * (next_state - current_state) / (next_alpha + current_alpha);
134  ordered_index++;
135  for(int j = 1; j < line_length - 1; j++)
136  {
137  prev_state = current_state;
138  current_index = next_index;
139  next_index = ordered_nodes[ordered_index];
140  current_state = next_state;
141  next_state = states[next_index];
142  prev_alpha = current_alpha;
143  current_alpha = next_alpha;
144  next_alpha = alphas[next_index];
145  delta[current_index] = dc * ((next_alpha * current_alpha / (next_alpha + current_alpha)) * (next_state - current_state) -
146  (prev_alpha * current_alpha / (prev_alpha + current_alpha)) * (current_state - prev_state));
147  ordered_index++;
148  }
149  //Here next_state is actually current_state and current_state is prev_state
150  delta[next_index] = dc * (next_alpha * current_alpha) * (current_state - next_state) / (next_alpha + current_alpha);
151  }
152  else
153  {
154  ordered_index++;
155  delta[line_start] = 0.0;
156  }
157  }
158 }
159 
160 //Inhomogeneous diffusion coefficient
161 void ics_find_deltas(long start, long stop, long node_start, double* delta, long* line_defs, long* ordered_nodes, double* states, double* dc, double* alphas){
162  long ordered_index = node_start;
163  long current_index = -1;
164  long next_index = -1;
165  double prev_state;
166  double current_state;
167  double next_state;
168  double prev_alpha;
169  double current_alpha;
170  double next_alpha;
171  for(int i = start; i < stop - 1; i += 2)
172  {
173  long line_start = ordered_nodes[ordered_index];
174  int line_length = line_defs[i+1];
175  if(line_length > 1)
176  {
177  current_index = line_start;
178  ordered_index++;
179  next_index = ordered_nodes[ordered_index];
180  current_state = states[current_index];
181  next_state = states[next_index];
182  current_alpha = alphas[current_index];
183  next_alpha = alphas[next_index];
184  delta[current_index] = dc[next_index] * next_alpha * current_alpha * (next_state - current_state) / (next_alpha + current_alpha);
185  ordered_index++;
186  for(int j = 1; j < line_length - 1; j++)
187  {
188  prev_state = current_state;
189  current_index = next_index;
190  next_index = ordered_nodes[ordered_index];
191  current_state = next_state;
192  next_state = states[next_index];
193  prev_alpha = current_alpha;
194  current_alpha = next_alpha;
195  next_alpha = alphas[next_index];
196  delta[current_index] = dc[next_index] * (next_alpha * current_alpha * (next_state - current_state)/(next_alpha + current_alpha)) -
197  dc[current_index] * (prev_alpha * current_alpha * (current_state - prev_state) / (prev_alpha + current_alpha));
198  ordered_index++;
199  }
200  //Here next_state is actually current_state and current_state is prev_state
201  delta[next_index] = dc[next_index] * (next_alpha * current_alpha) * (current_state - next_state) / (next_alpha + current_alpha);
202  }
203  else
204  {
205  ordered_index++;
206  delta[line_start] = 0.0;
207  }
208  }
209 }
210 
211 static void* do_ics_deltas(void* dataptr){
212  ICSAdiGridData* data = (ICSAdiGridData*) dataptr;
213  ICSAdiDirection* ics_adi_dir = data -> ics_adi_dir;
214  ICS_Grid_node* g = data -> g;
215  int line_start = data->line_start;
216  int line_stop = data->line_stop;
217  int node_start = data->ordered_start;
218  double* states = g->states;
219  double* deltas = ics_adi_dir->deltas;
220  long* line_defs = ics_adi_dir->ordered_line_defs;
221  long* ordered_nodes = ics_adi_dir->ordered_nodes;
222  double* alphas = g->_ics_alphas;
223 
224  if(ics_adi_dir->dcgrid == NULL)
225  ics_find_deltas(line_start, line_stop, node_start, deltas, line_defs, ordered_nodes, states, ics_adi_dir->dc, alphas);
226  else
227  ics_find_deltas(line_start, line_stop, node_start, deltas, line_defs, ordered_nodes, states, ics_adi_dir->dcgrid, alphas);
228 
229 
230  return NULL;
231 }
232 
234  int i;
235  for(i = 0; i < NUM_THREADS; i++){
236  g->ics_tasks[i].line_start = ics_adi_dir->line_start_stop_indices[2*i];
237  g->ics_tasks[i].line_stop = ics_adi_dir->line_start_stop_indices[(2*i)+1];
238  g->ics_tasks[i].ordered_start = ics_adi_dir->ordered_start_stop_indices[(2*i)]; //Change what I'm storing in ordered_start_stop_indices so index is just i
239  g->ics_tasks[i].ics_adi_dir = ics_adi_dir;
240  }
241  /* launch threads */
242  for (i = 0; i < NUM_THREADS-1; i++)
243  {
244  TaskQueue_add_task(AllTasks, &do_ics_deltas, &(g->ics_tasks[i]), NULL);
245  }
246  /* run one task in the main thread */
247  do_ics_deltas(&(g->ics_tasks[NUM_THREADS - 1]));
248  /* wait for them to finish */
249  TaskQueue_sync(AllTasks);
250 }
251 
252 //Inhomogeneous diffusion coefficient
253 void ics_dg_adi_x_inhom(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double, double* states, double* RHS, double* scratchpad, double* u_diag, double* diag, double* l_diag){
254  double* delta_x = g->ics_adi_dir_x->deltas;
255  double* delta_y = g->ics_adi_dir_y->deltas;
256  double* delta_z = g->ics_adi_dir_z->deltas;
257  double* states_cur = g->states_cur;
258  double* alphas = g->_ics_alphas;
259  double* dc = g->ics_adi_dir_x->dcgrid;
260  double dx = g->ics_adi_dir_x->d;
261  double dy = g->ics_adi_dir_y->d;
262  double dz = g->ics_adi_dir_z->d;
263  double dt = *dt_ptr;
264  long next_index = -1;
265  long prev_index = -1;
266  double next;
267  double prev;
268 
269  long* x_lines = g->ics_adi_dir_x->ordered_line_defs;
270  long* ordered_nodes = g->ics_adi_dir_x->ordered_nodes;
271 
272  long current_index;
273  long ordered_index = node_start;
274  for(int i = line_start; i < line_stop - 1; i += 2)
275  {
276  long N = x_lines[i+1];
277  long ordered_index_start = ordered_index;
278  for(int j = 0; j < N; j++)
279  {
280  current_index = ordered_nodes[ordered_index];
281  RHS[j] = (dt / alphas[current_index])*
282  (delta_x[current_index] / SQ(dx)
283  + 2.0 * delta_y[current_index] / SQ(dy)
284  + 2.0 * delta_z[current_index] / SQ(dz))
285  + states[current_index] + states_cur[current_index];
286  ordered_index++;
287  }
288 
289  ordered_index = ordered_index_start;
290  current_index = ordered_nodes[ordered_index];
291  ordered_index++;
292  next_index = ordered_nodes[ordered_index];
293  next = alphas[next_index] * dc[next_index] / (alphas[next_index] + alphas[current_index]);
294  diag[0] = 1.0 + dt * next / SQ(dx);
295  u_diag[0] = -dt * next / SQ(dx);
296  ordered_index++;
297  for(int c = 1; c < N - 1; c++){
298  prev_index = current_index;
299  current_index = next_index;
300  next_index = ordered_nodes[ordered_index];
301  prev = alphas[prev_index] * dc[current_index] / (alphas[prev_index] + alphas[current_index]);
302  next = alphas[next_index] * dc[next_index] / (alphas[next_index] + alphas[current_index]);
303  l_diag[c-1] = -dt*prev/ SQ(dx);
304  diag[c] = 1. + dt*(prev + next)/ SQ(dx);
305  u_diag[c] = -dt*next/ SQ(dx);
306  ordered_index++;
307  }
308  prev = alphas[current_index] * dc[next_index] / (alphas[current_index] + alphas[next_index]);
309  diag[N-1] = 1.0 + dt * prev / SQ(dx);
310  l_diag[N-2] = -dt * prev / SQ(dx);
311 
312 
313  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
314 
315  ordered_index = ordered_index_start;
316  for(int k = 0; k < N; k++)
317  {
318  current_index = ordered_nodes[ordered_index];
319  states[current_index] = RHS[k];
320  ordered_index++;
321  }
322  }
323 }
324 
325 void ics_dg_adi_y_inhom(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double, double* states, double* RHS, double* scratchpad, double* u_diag, double* diag, double* l_diag){
326  double* delta = g->ics_adi_dir_y->deltas;
327  long* lines = g->ics_adi_dir_y->ordered_line_defs;
328  double* alphas = g->_ics_alphas;
329  double* dc = g->ics_adi_dir_y->dcgrid;
330  double dy = g->ics_adi_dir_y->d;
331  double dt = *dt_ptr;
332  long next_index = -1;
333  long prev_index = -1;
334  double next;
335  double prev;
336 
337  long current_index;
338  long* ordered_y_nodes = g->ics_adi_dir_y->ordered_nodes;
339  long ordered_index = node_start;
340 
341  for(int i = line_start; i < line_stop - 1; i += 2)
342  {
343  long N = lines[i+1];
344  long ordered_index_start = ordered_index;
345 
346  for(int j = 0; j < N; j++)
347  {
348  current_index = ordered_y_nodes[ordered_index];
349  RHS[j] = states[current_index] - dt * delta[current_index] / (alphas[current_index] * SQ(dy));
350  ordered_index++;
351  }
352 
353  ordered_index = ordered_index_start;
354  current_index = ordered_y_nodes[ordered_index];
355  ordered_index++;
356  next_index = ordered_y_nodes[ordered_index];
357  next = alphas[next_index] * dc[next_index] / (alphas[next_index] + alphas[current_index]);
358  diag[0] = 1.0 + dt * next / SQ(dy);
359  u_diag[0] = -dt * next / SQ(dy);
360  ordered_index++;
361  for(int c = 1; c < N - 1; c++){
362  prev_index = current_index;
363  current_index = next_index;
364  next_index = ordered_y_nodes[ordered_index];
365  prev = alphas[prev_index] * dc[prev_index] / (alphas[prev_index] + alphas[current_index]);
366  next = alphas[next_index] * dc[next_index] / (alphas[next_index] + alphas[current_index]);
367  l_diag[c-1] = -dt*prev/ SQ(dy);
368  diag[c] = 1. + dt*(prev + next)/ SQ(dy);
369  u_diag[c] = -dt*next/ SQ(dy);
370  ordered_index++;
371  }
372  prev = alphas[current_index] * dc[current_index] / (alphas[current_index] + alphas[next_index]);
373  diag[N-1] = 1.0 + dt * prev / SQ(dy);
374  l_diag[N-2] = -dt * prev / SQ(dy);
375 
376  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
377 
378  ordered_index = ordered_index_start;
379  for(int k = 0; k < N; k++)
380  {
381  current_index = ordered_y_nodes[ordered_index];
382  states[current_index] = RHS[k];
383  ordered_index++;
384  }
385  }
386 
387 }
388 void ics_dg_adi_z_inhom(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double, double* states, double* RHS, double* scratchpad, double* u_diag, double* diag, double* l_diag){
389  double* delta = g->ics_adi_dir_z->deltas;
390  long* lines = g->ics_adi_dir_z->ordered_line_defs;
391  long* ordered_z_nodes = g->ics_adi_dir_z->ordered_nodes;
392  double* alphas = g->_ics_alphas;
393  double* dc = g->ics_adi_dir_z->dcgrid;
394  double dz = g->ics_adi_dir_z->d;
395  double dt = *dt_ptr;
396  long next_index = -1;
397  long prev_index = -1;
398  double next;
399  double prev;
400 
401  long current_index;
402  long ordered_index = node_start;
403  for(int i = line_start; i< line_stop - 1; i+=2)
404  {
405  long N = lines[i+1];
406  long ordered_index_start = ordered_index;
407 
408  for(int j = 0; j < N; j++)
409  {
410  current_index = ordered_z_nodes[ordered_index];
411  RHS[j] = states[current_index] - dt * delta[current_index] / (SQ(dz) * alphas[current_index]);
412  ordered_index++;
413  }
414 
415  ordered_index = ordered_index_start;
416  current_index = ordered_z_nodes[ordered_index];
417  ordered_index++;
418  next_index = ordered_z_nodes[ordered_index];
419  next = alphas[next_index] * dc[next_index] / (alphas[next_index] + alphas[current_index]);
420  diag[0] = 1.0 + dt * next / SQ(dz);
421  u_diag[0] = -dt * next / SQ(dz);
422  ordered_index++;
423  for(int c = 1; c < N - 1; c++){
424  prev_index = current_index;
425  current_index = next_index;
426  next_index = ordered_z_nodes[ordered_index];
427  prev = alphas[prev_index] * dc[prev_index] / (alphas[prev_index] + alphas[current_index]);
428  next = alphas[next_index] * dc[next_index] / (alphas[next_index] + alphas[current_index]);
429  l_diag[c-1] = -dt*prev/ SQ(dz);
430  diag[c] = 1. + dt*(prev + next)/ SQ(dz);
431  u_diag[c] = -dt*next/ SQ(dz);
432  ordered_index++;
433  }
434  prev = alphas[current_index] * dc[current_index] / (alphas[current_index] + alphas[next_index]);
435  diag[N-1] = 1.0 + dt * prev / SQ(dz);
436  l_diag[N-2] = -dt * prev / SQ(dz);
437  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
438 
439  ordered_index = ordered_index_start;
440  for(int k = 0; k < N; k++)
441  {
442  current_index = ordered_z_nodes[ordered_index];
443  states[current_index] = RHS[k];
444  ordered_index++;
445  }
446  }
447 }
448 
449 //Homogeneous diffusion coefficient
450 void ics_dg_adi_x(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double, double* states, double* RHS, double* scratchpad, double* u_diag, double* diag, double* l_diag){
451  double* delta_x = g->ics_adi_dir_x->deltas;
452  double* delta_y = g->ics_adi_dir_y->deltas;
453  double* delta_z = g->ics_adi_dir_z->deltas;
454  double* states_cur = g->states_cur;
455  double* alphas = g->_ics_alphas;
456  double dc = g->ics_adi_dir_x->dc;
457  double dx = g->ics_adi_dir_x->d;
458  double dy = g->ics_adi_dir_y->d;
459  double dz = g->ics_adi_dir_z->d;
460  double dt = *dt_ptr;
461  long next_index = -1;
462  long prev_index = -1;
463  double next;
464  double prev;
465 
466  long* x_lines = g->ics_adi_dir_x->ordered_line_defs;
467  long* ordered_nodes = g->ics_adi_dir_x->ordered_nodes;
468 
469  long current_index;
470  long ordered_index = node_start;
471  for(int i = line_start; i < line_stop - 1; i += 2)
472  {
473  long N = x_lines[i+1];
474  long ordered_index_start = ordered_index;
475  for(int j = 0; j < N; j++)
476  {
477  current_index = ordered_nodes[ordered_index];
478  RHS[j] = (dt / alphas[current_index])*(delta_x[current_index] / (SQ(dx)) + 2 * delta_y[current_index] / SQ(dy) + 2 * delta_z[current_index] / SQ(dz)) + states[current_index] + states_cur[current_index];
479  ordered_index++;
480  }
481 
482  ordered_index = ordered_index_start;
483  current_index = ordered_nodes[ordered_index];
484  ordered_index++;
485  next_index = ordered_nodes[ordered_index];
486  next = alphas[next_index] * dc / (alphas[next_index] + alphas[current_index]);
487  diag[0] = 1.0 + dt * next / SQ(dx);
488  u_diag[0] = -dt * next / SQ(dx);
489  ordered_index++;
490  for(int c = 1; c < N - 1; c++){
491  prev_index = current_index;
492  current_index = next_index;
493  next_index = ordered_nodes[ordered_index];
494  prev = alphas[prev_index] * dc / (alphas[prev_index] + alphas[current_index]);
495  next = alphas[next_index] * dc / (alphas[next_index] + alphas[current_index]);
496  l_diag[c-1] = -dt*prev/ SQ(dx);
497  diag[c] = 1. + dt*(prev + next)/ SQ(dx);
498  u_diag[c] = -dt*next/ SQ(dx);
499  ordered_index++;
500  }
501  prev = alphas[current_index] * dc / (alphas[current_index] + alphas[next_index]);
502  diag[N-1] = 1.0 + dt * prev / SQ(dx);
503  l_diag[N-2] = -dt * prev / SQ(dx);
504 
505 
506  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
507 
508  ordered_index = ordered_index_start;
509  for(int k = 0; k < N; k++)
510  {
511  current_index = ordered_nodes[ordered_index];
512  states[current_index] = RHS[k];
513  ordered_index++;
514  }
515  }
516 }
517 
518 void ics_dg_adi_y(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double, double* states, double* RHS, double* scratchpad, double* u_diag, double* diag, double* l_diag){
519  double* delta = g->ics_adi_dir_y->deltas;
520  long* lines = g->ics_adi_dir_y->ordered_line_defs;
521  double* alphas = g->_ics_alphas;
522  double dc = g->ics_adi_dir_y->dc;
523  double dy = g->ics_adi_dir_y->d;
524  double dt = *dt_ptr;
525  long next_index = -1;
526  long prev_index = -1;
527  double next;
528  double prev;
529 
530  long current_index;
531  long* ordered_y_nodes = g->ics_adi_dir_y->ordered_nodes;
532  long ordered_index = node_start;
533 
534  for(int i = line_start; i < line_stop - 1; i += 2)
535  {
536  long N = lines[i+1];
537  long ordered_index_start = ordered_index;
538 
539  for(int j = 0; j < N; j++)
540  {
541  current_index = ordered_y_nodes[ordered_index];
542  RHS[j] = states[current_index] - dt * delta[current_index] / (alphas[current_index] * SQ(dy));
543  ordered_index++;
544  }
545 
546  ordered_index = ordered_index_start;
547  current_index = ordered_y_nodes[ordered_index];
548  ordered_index++;
549  next_index = ordered_y_nodes[ordered_index];
550  next = alphas[next_index] * dc / (alphas[next_index] + alphas[current_index]);
551  diag[0] = 1.0 + dt * next / SQ(dy);
552  u_diag[0] = -dt * next / SQ(dy);
553  ordered_index++;
554  for(int c = 1; c < N - 1; c++){
555  prev_index = current_index;
556  current_index = next_index;
557  next_index = ordered_y_nodes[ordered_index];
558  prev = alphas[prev_index] * dc / (alphas[prev_index] + alphas[current_index]);
559  next = alphas[next_index] * dc / (alphas[next_index] + alphas[current_index]);
560  l_diag[c-1] = -dt*prev/ SQ(dy);
561  diag[c] = 1. + dt*(prev + next)/ SQ(dy);
562  u_diag[c] = -dt*next/ SQ(dy);
563  ordered_index++;
564  }
565  prev = alphas[current_index] * dc / (alphas[current_index] + alphas[next_index]);
566  diag[N-1] = 1.0 + dt * prev / SQ(dy);
567  l_diag[N-2] = -dt * prev / SQ(dy);
568 
569  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
570 
571  ordered_index = ordered_index_start;
572  for(int k = 0; k < N; k++)
573  {
574  current_index = ordered_y_nodes[ordered_index];
575  states[current_index] = RHS[k];
576  ordered_index++;
577  }
578  }
579 
580 }
581 void ics_dg_adi_z(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double, double* states, double* RHS, double* scratchpad, double* u_diag, double* diag, double* l_diag){
582  double* delta = g->ics_adi_dir_z->deltas;
583  long* lines = g->ics_adi_dir_z->ordered_line_defs;
584  long* ordered_z_nodes = g->ics_adi_dir_z->ordered_nodes;
585  double* alphas = g->_ics_alphas;
586  double dc = g->ics_adi_dir_z->dc;
587  double dz = g->ics_adi_dir_z->d;
588  double dt = *dt_ptr;
589  long next_index = -1;
590  long prev_index = -1;
591  double next;
592  double prev;
593 
594  long current_index;
595  long ordered_index = node_start;
596  for(int i = line_start; i< line_stop - 1; i+=2)
597  {
598  long N = lines[i+1];
599  long ordered_index_start = ordered_index;
600 
601  for(int j = 0; j < N; j++)
602  {
603  current_index = ordered_z_nodes[ordered_index];
604  RHS[j] = states[current_index] - dt * delta[current_index] / (SQ(dz) * alphas[current_index]);
605  ordered_index++;
606  }
607 
608  ordered_index = ordered_index_start;
609  current_index = ordered_z_nodes[ordered_index];
610  ordered_index++;
611  next_index = ordered_z_nodes[ordered_index];
612  next = alphas[next_index] * dc / (alphas[next_index] + alphas[current_index]);
613  diag[0] = 1.0 + dt * next / SQ(dz);
614  u_diag[0] = -dt * next / SQ(dz);
615  ordered_index++;
616  for(int c = 1; c < N - 1; c++){
617  prev_index = current_index;
618  current_index = next_index;
619  next_index = ordered_z_nodes[ordered_index];
620  prev = alphas[prev_index] * dc / (alphas[prev_index] + alphas[current_index]);
621  next = alphas[next_index] * dc / (alphas[next_index] + alphas[current_index]);
622  l_diag[c-1] = -dt*prev/ SQ(dz);
623  diag[c] = 1. + dt*(prev + next)/ SQ(dz);
624  u_diag[c] = -dt*next/ SQ(dz);
625  ordered_index++;
626  }
627  prev = alphas[current_index] * dc / (alphas[current_index] + alphas[next_index]);
628  diag[N-1] = 1.0 + dt * prev / SQ(dz);
629  l_diag[N-2] = -dt * prev / SQ(dz);
630  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
631 
632  ordered_index = ordered_index_start;
633  for(int k = 0; k < N; k++)
634  {
635  current_index = ordered_z_nodes[ordered_index];
636  states[current_index] = RHS[k];
637  ordered_index++;
638  }
639  }
640 }
641 
642 void* do_ics_dg_adi(void* dataptr){
643  ICSAdiGridData* data = (ICSAdiGridData*) dataptr;
644  ICSAdiDirection* ics_adi_dir = data -> ics_adi_dir;
645  ICS_Grid_node* g = data->g;
646  void (*ics_dg_adi_dir)(ICS_Grid_node* g, int, int, int, double, double*, double*, double*, double*, double*, double*) = ics_adi_dir -> ics_dg_adi_dir;
647  int line_start = data->line_start;
648  int line_stop = data->line_stop;
649  int node_start = data->ordered_start;
650  double dt = *dt_ptr;
651  double r = dt/(ics_adi_dir->d * ics_adi_dir->d);
652  ics_dg_adi_dir(g, line_start, line_stop, node_start, r, g->states, data->RHS, data->scratchpad, data->u_diag, data->diag, data->l_diag);
653  return NULL;
654 }
655 
657  int i;
658  for(i = 0; i < NUM_THREADS; i++){
659  ics_tasks[i].line_start = ics_adi_dir->line_start_stop_indices[2*i];
660  ics_tasks[i].line_stop = ics_adi_dir->line_start_stop_indices[(2*i)+1];
661  ics_tasks[i].ordered_start = ics_adi_dir->ordered_start_stop_indices[(2*i)]; //Change what I'm storing in ordered_start_stop_indices so index is just i
662  ics_tasks[i].ics_adi_dir = ics_adi_dir;
663  }
664  /* launch threads */
665  for (i = 0; i < NUM_THREADS-1; i++)
666  {
668  }
669  /* run one task in the main thread */
670  do_ics_dg_adi(&ics_tasks[NUM_THREADS - 1]);
671  /* wait for them to finish */
672  TaskQueue_sync(AllTasks);
673 }
674 
675 
676 /* ------- Variable Step ICS Code ------- */
677 static inline double flux(const double alphai, const double alphaj,
678  const double statei, const double statej)
679 {
680  return 2.0 * alphai * alphaj * (statei - statej) /
681  ((alphai + alphaj));
682 }
683 
684 static void variable_step_delta(long start, long stop, long node_start,
685  double* ydot, long* line_defs,
686  long* ordered_nodes,
687  double const * const states,
688  double r, double* alphas)
689 {
690  long ordered_index = node_start;
691  long current_index = -1;
692  long next_index = -1;
693  double prev_state;
694  double current_state;
695  double next_state;
696  double prev_alpha;
697  double current_alpha;
698  double next_alpha;
699  for(int i = start; i < stop - 1; i += 2)
700  {
701  long line_start = ordered_nodes[ordered_index];
702  int line_length = line_defs[i+1];
703  if(line_length > 1)
704  {
705  current_index = line_start;
706  ordered_index++;
707  next_index = ordered_nodes[ordered_index];
708  current_state = states[current_index];
709  next_state = states[next_index];
710  current_alpha = alphas[current_index];
711  next_alpha = alphas[next_index];
712  ydot[current_index] += (r / current_alpha) *
713  flux(next_alpha, current_alpha,
714  next_state, current_state);
715  ordered_index++;
716  for(int j = 1; j < line_length - 1; j++)
717  {
718  prev_state = current_state;
719  current_index = next_index;
720  next_index = ordered_nodes[ordered_index];
721  current_state = next_state;
722  next_state = states[next_index];
723  prev_alpha = current_alpha;
724  current_alpha = next_alpha;
725  next_alpha = alphas[next_index];
726  ydot[current_index] += (r / current_alpha) * ( flux(prev_alpha, current_alpha, prev_state, current_state) +
727  flux(next_alpha, current_alpha, next_state, current_state));
728  ordered_index++;
729  }
730  ydot[next_index] += r * flux(current_alpha, next_alpha, current_state, next_state)/next_alpha;
731  }
732  else
733  {
734  ordered_index++;
735  //ydot[line_start] += 0.0;
736  }
737  }
738 }
739 
740 static void variable_step_delta(long start, long stop, long node_start,
741  double* ydot, long* line_defs,
742  long* ordered_nodes,
743  double const * const states,
744  double r, double* dcs, double* alphas)
745 {
746  long ordered_index = node_start;
747  long current_index = -1;
748  long next_index = -1;
749  double prev_state;
750  double current_state;
751  double next_state;
752  double prev_alpha;
753  double current_alpha;
754  double next_alpha;
755  double current_dc, next_dc;
756  for(int i = start; i < stop - 1; i += 2)
757  {
758  long line_start = ordered_nodes[ordered_index];
759  int line_length = line_defs[i+1];
760  if(line_length > 1)
761  {
762  current_index = line_start;
763  ordered_index++;
764  next_index = ordered_nodes[ordered_index];
765  current_state = states[current_index];
766  next_state = states[next_index];
767  current_alpha = alphas[current_index];
768  next_alpha = alphas[next_index];
769  current_dc = dcs[current_index];
770  next_dc = dcs[next_index];
771  ydot[current_index] += (r/current_alpha) * next_dc
772  * flux(next_alpha, current_alpha,
773  next_state, current_state);
774  ordered_index++;
775  for(int j = 1; j < line_length - 1; j++)
776  {
777  prev_state = current_state;
778  current_index = next_index;
779  next_index = ordered_nodes[ordered_index];
780  current_state = next_state;
781  next_state = states[next_index];
782  prev_alpha = current_alpha;
783  current_alpha = next_alpha;
784  next_alpha = alphas[next_index];
785  current_dc = next_dc;
786  next_dc = dcs[next_index];
787  ydot[current_index] += (r / current_alpha) * ( current_dc * flux(prev_alpha, current_alpha, prev_state, current_state) +
788  next_dc * flux(next_alpha, current_alpha, next_state, current_state));
789  ordered_index++;
790  }
791  ydot[next_index] += r * next_dc * flux(current_alpha, next_alpha, current_state, next_state)/next_alpha;
792  }
793  else
794  {
795  ordered_index++;
796  //ydot[line_start] += 0.0;
797  }
798  }
799 }
800 void _ics_rhs_variable_step_helper(ICS_Grid_node* g, double const * const states, double* ydot)
801 {
802  double rate_x, rate_y, rate_z;
803  //Find rate for each direction
804  double dx = g->ics_adi_dir_x->d, dy = g->ics_adi_dir_y->d, dz = g->ics_adi_dir_z->d;
805 
806  long x_line_start = g->ics_adi_dir_x->line_start_stop_indices[0];
807  long x_line_stop = g->ics_adi_dir_x->line_start_stop_indices[NUM_THREADS * 2 - 1];
808  long x_node_start = g->ics_adi_dir_x->ordered_start_stop_indices[0];
809  long* x_line_defs = g->ics_adi_dir_x->ordered_line_defs;
810  long* x_ordered_nodes = g->ics_adi_dir_x->ordered_nodes;
811 
812  long y_line_start = g->ics_adi_dir_y->line_start_stop_indices[0];
813  long y_line_stop = g->ics_adi_dir_y->line_start_stop_indices[NUM_THREADS * 2 - 1];
814  long y_node_start = g->ics_adi_dir_y->ordered_start_stop_indices[0];
815  long* y_line_defs = g->ics_adi_dir_y->ordered_line_defs;
816  long* y_ordered_nodes = g->ics_adi_dir_y->ordered_nodes;
817 
818  long z_line_start = g->ics_adi_dir_z->line_start_stop_indices[0];
819  long z_line_stop = g->ics_adi_dir_z->line_start_stop_indices[NUM_THREADS * 2 - 1];
820  long z_node_start = g->ics_adi_dir_z->ordered_start_stop_indices[0];
821  long* z_line_defs = g->ics_adi_dir_z->ordered_line_defs;
822  long* z_ordered_nodes = g->ics_adi_dir_z->ordered_nodes;
823 
824  double* alphas = g->_ics_alphas;
825 
826  if(g->ics_adi_dir_x->dcgrid == NULL)
827  {
828  rate_x = g->ics_adi_dir_x->dc / (dx * dx);
829  rate_y = g->ics_adi_dir_y->dc / (dy * dy);
830  rate_z = g->ics_adi_dir_z->dc / (dz * dz);
831  //x contribution
832  variable_step_delta(x_line_start, x_line_stop, x_node_start, ydot,
833  x_line_defs, x_ordered_nodes, states, rate_x,
834  alphas);
835  //y contribution
836  variable_step_delta(y_line_start, y_line_stop, y_node_start, ydot,
837  y_line_defs, y_ordered_nodes, states, rate_y,
838  alphas);
839  //z contribution
840  variable_step_delta(z_line_start, z_line_stop, z_node_start, ydot,
841  z_line_defs, z_ordered_nodes, states, rate_z,
842  alphas);
843  }
844  else
845  {
846  rate_x = 1.0 / (dx * dx);
847  rate_y = 1.0 / (dy * dy);
848  rate_z = 1.0 / (dz * dz);
849  //x contribution
850  variable_step_delta(x_line_start, x_line_stop, x_node_start, ydot,
851  x_line_defs, x_ordered_nodes, states, rate_x,
852  g->ics_adi_dir_x->dcgrid, alphas);
853  //y contribution
854  variable_step_delta(y_line_start, y_line_stop, y_node_start, ydot,
855  y_line_defs, y_ordered_nodes, states, rate_y,
856  g->ics_adi_dir_y->dcgrid, alphas);
857  //z contribution
858  variable_step_delta(z_line_start, z_line_stop, z_node_start, ydot,
859  z_line_defs, z_ordered_nodes, states, rate_z,
860  g->ics_adi_dir_z->dcgrid, alphas);
861  }
862 }
863 
864 //Inhomogeneous diffusion coefficient
865 static void variable_step_x(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double* states, double* CVodeRHS, double* RHS, double* scratchpad, double* alphas, double *dcs, double dt)
866 {
867  long* x_lines = g->ics_adi_dir_x->ordered_line_defs;
868  long* ordered_nodes = g->ics_adi_dir_x->ordered_nodes;
869  double* l_diag = g->ics_tasks->l_diag;
870  double* diag = g->ics_tasks->diag;
871  double* u_diag = g->ics_tasks->u_diag;
872  double* delta_x = g->ics_adi_dir_x->deltas;
873  double* delta_y = g->ics_adi_dir_y->deltas;
874  double* delta_z = g->ics_adi_dir_z->deltas;
875 
876  long next_index = -1;
877  long prev_index = -1;
878  double next;
879  double prev;
880  double dx = g->ics_adi_dir_x->d;
881  double dy = g->ics_adi_dir_y->d;
882  double dz = g->ics_adi_dir_z->d;
883 
884  long current_index;
885  long ordered_index = node_start;
886  for(int i = line_start; i < line_stop - 1; i += 2)
887  {
888  long N = x_lines[i+1];
889  long ordered_index_start = ordered_index;
890  for(int j = 0; j < N; j++)
891  {
892  current_index = ordered_nodes[ordered_index];
893  RHS[j] = CVodeRHS[current_index]
894  - dt * (delta_x[current_index]/SQ(dx)
895  + delta_y[current_index]/SQ(dy)
896  + delta_z[current_index]/SQ(dz)
897  )/alphas[current_index];
898  ordered_index++;
899  }
900 
901  ordered_index = ordered_index_start;
902  current_index = ordered_nodes[ordered_index];
903  ordered_index++;
904  next_index = ordered_nodes[ordered_index];
905  next = alphas[next_index] * dcs[next_index] / (alphas[next_index] + alphas[current_index]);
906  diag[0] = 1.0 + dt * next / SQ(dx);
907  u_diag[0] = -dt * next / SQ(dx);
908  ordered_index++;
909  for(int c = 1; c < N - 1; c++){
910  prev_index = current_index;
911  current_index = next_index;
912  next_index = ordered_nodes[ordered_index];
913  prev = alphas[prev_index] * dcs[current_index] / (alphas[prev_index] + alphas[current_index]);
914  next = alphas[next_index] * dcs[next_index] / (alphas[next_index] + alphas[current_index]);
915  l_diag[c-1] = -dt*prev / SQ(dx);
916  diag[c] = 1. + dt*(prev + next) / SQ(dx);
917  u_diag[c] = -dt*next / SQ(dx);
918  ordered_index++;
919  }
920  prev = alphas[current_index] * dcs[current_index] / (alphas[current_index] + alphas[next_index]);
921  diag[N-1] = 1.0 + dt * prev / SQ(dx);
922  l_diag[N-2] = -dt * prev / SQ(dx);
923 
924  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
925 
926  ordered_index = ordered_index_start;
927  for(int k = 0; k < N; k++)
928  {
929  current_index = ordered_nodes[ordered_index];
930  states[current_index] = RHS[k];
931  ordered_index++;
932  }
933  }
934 }
935 static void variable_step_y(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double* states, double* RHS, double* scratchpad, double* alphas, double *dcs, double dt)
936 {
937  double* delta = g->ics_adi_dir_y->deltas;
938  long* lines = g->ics_adi_dir_y->ordered_line_defs;
939 
940  double* l_diag = g->ics_tasks->l_diag;
941  double* diag = g->ics_tasks->diag;
942  double* u_diag = g->ics_tasks->u_diag;
943 
944  long next_index = -1;
945  long prev_index = -1;
946  double next;
947  double prev;
948  double dy = g->ics_adi_dir_y->d;
949 
950  long current_index;
951  long* ordered_y_nodes = g->ics_adi_dir_y->ordered_nodes;
952  long ordered_index = node_start;
953 
954  for(int i = line_start; i < line_stop - 1; i += 2)
955  {
956  long N = lines[i+1];
957  long ordered_index_start = ordered_index;
958 
959  for(int j = 0; j < N; j++)
960  {
961  current_index = ordered_y_nodes[ordered_index];
962  RHS[j] = states[current_index] - dt * delta[current_index]
963  / (alphas[current_index] * SQ(dy));
964  ordered_index++;
965  }
966 
967  ordered_index = ordered_index_start;
968  current_index = ordered_y_nodes[ordered_index];
969  ordered_index++;
970  next_index = ordered_y_nodes[ordered_index];
971  next = alphas[next_index] * dcs[next_index] / (alphas[next_index] + alphas[current_index]);
972  diag[0] = 1.0 + dt * next / SQ(dy);
973  u_diag[0] = -dt * next / SQ(dy);
974  ordered_index++;
975  for(int c = 1; c < N - 1; c++){
976  prev_index = current_index;
977  current_index = next_index;
978  next_index = ordered_y_nodes[ordered_index];
979  prev = alphas[prev_index] * dcs[current_index] / (alphas[prev_index] + alphas[current_index]);
980  next = alphas[next_index] * dcs[next_index] / (alphas[next_index] + alphas[current_index]);
981  l_diag[c-1] = -dt*prev/ SQ(dy);
982  diag[c] = 1. + dt*(prev + next)/ SQ(dy);
983  u_diag[c] = -dt*next/ SQ(dy);
984  ordered_index++;
985  }
986  prev = alphas[current_index] * dcs[current_index] / (alphas[current_index] + alphas[next_index]);
987  diag[N-1] = 1.0 + dt * prev / SQ(dy);
988  l_diag[N-2] = -dt * prev / SQ(dy);
989 
990  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
991 
992  ordered_index = ordered_index_start;
993  for(int k = 0; k < N; k++)
994  {
995  current_index = ordered_y_nodes[ordered_index];
996  states[current_index] = RHS[k];
997  ordered_index++;
998  }
999  }
1000 }
1001 static void variable_step_z(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double* states, double* RHS, double* scratchpad, double* alphas, double *dcs, double dt)
1002 {
1003  double* delta = g->ics_adi_dir_z->deltas;
1004  long* lines = g->ics_adi_dir_z->ordered_line_defs;
1005  long* ordered_z_nodes = g->ics_adi_dir_z->ordered_nodes;
1006 
1007  double* l_diag = g->ics_tasks->l_diag;
1008  double* diag = g->ics_tasks->diag;
1009  double* u_diag = g->ics_tasks->u_diag;
1010 
1011  long next_index = -1;
1012  long prev_index = -1;
1013  double next;
1014  double prev;
1015  double dz = g->ics_adi_dir_z->d;
1016 
1017  long current_index;
1018  long ordered_index = node_start;
1019  for(int i = line_start; i< line_stop - 1; i+=2)
1020  {
1021  long N = lines[i+1];
1022  long ordered_index_start = ordered_index;
1023 
1024  for(int j = 0; j < N; j++)
1025  {
1026  current_index = ordered_z_nodes[ordered_index];
1027  RHS[j] = states[current_index] - dt * delta[current_index]
1028  / (alphas[current_index] * SQ(dz));
1029  ordered_index++;
1030  }
1031 
1032  ordered_index = ordered_index_start;
1033  current_index = ordered_z_nodes[ordered_index];
1034  ordered_index++;
1035  next_index = ordered_z_nodes[ordered_index];
1036  next = alphas[next_index] * dcs[next_index] / (alphas[next_index] + alphas[current_index]);
1037  diag[0] = 1.0 + dt * next / SQ(dz);
1038  u_diag[0] = -dt * next / SQ(dz);
1039  ordered_index++;
1040  for(int c = 1; c < N - 1; c++){
1041  prev_index = current_index;
1042  current_index = next_index;
1043  next_index = ordered_z_nodes[ordered_index];
1044  prev = alphas[prev_index] * dcs[current_index] / (alphas[prev_index] + alphas[current_index]);
1045  next = alphas[next_index] * dcs[next_index] / (alphas[next_index] + alphas[current_index]);
1046  l_diag[c-1] = -dt*prev / SQ(dz);
1047  diag[c] = 1. + dt*(prev + next) / SQ(dz);
1048  u_diag[c] = -dt*next / SQ(dz);
1049  ordered_index++;
1050  }
1051  prev = alphas[current_index] * dcs[current_index] / (alphas[current_index] + alphas[next_index]);
1052  diag[N-1] = 1.0 + dt * prev / SQ(dz);
1053  l_diag[N-2] = -dt * prev / SQ(dz);
1054  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
1055 
1056  ordered_index = ordered_index_start;
1057  for(int k = 0; k < N; k++)
1058  {
1059  current_index = ordered_z_nodes[ordered_index];
1060  states[current_index] = RHS[k];
1061  ordered_index++;
1062  }
1063  }
1064 }
1065 
1066 //Homogeneous diffusion coefficient
1067 static void variable_step_x(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double* states, double* CVodeRHS, double* RHS, double* scratchpad, double* alphas, double dt)
1068 {
1069  long* x_lines = g->ics_adi_dir_x->ordered_line_defs;
1070  long* ordered_nodes = g->ics_adi_dir_x->ordered_nodes;
1071  double* l_diag = g->ics_tasks->l_diag;
1072  double* diag = g->ics_tasks->diag;
1073  double* u_diag = g->ics_tasks->u_diag;
1074  double* delta_x = g->ics_adi_dir_x->deltas;
1075  double* delta_y = g->ics_adi_dir_y->deltas;
1076  double* delta_z = g->ics_adi_dir_z->deltas;
1077  long next_index = -1;
1078  long prev_index = -1;
1079  double next;
1080  double prev;
1081  double dx = g->ics_adi_dir_x->d;
1082  double dy = g->ics_adi_dir_y->d;
1083  double dz = g->ics_adi_dir_z->d;
1084  double dc = g->ics_adi_dir_x->dc;
1085 
1086  double r = dt * dc / SQ(dx);
1087 
1088  long current_index;
1089  long ordered_index = node_start;
1090  for(int i = line_start; i < line_stop - 1; i += 2)
1091  {
1092  long N = x_lines[i+1];
1093  long ordered_index_start = ordered_index;
1094  for(int j = 0; j < N; j++)
1095  {
1096  current_index = ordered_nodes[ordered_index];
1097  RHS[j] = CVodeRHS[current_index]
1098  - dt * (delta_x[current_index]/SQ(dx)
1099  + delta_y[current_index]/SQ(dy)
1100  + delta_z[current_index]/SQ(dz)
1101  )/alphas[current_index];
1102  ordered_index++;
1103  }
1104 
1105  ordered_index = ordered_index_start;
1106  current_index = ordered_nodes[ordered_index];
1107  ordered_index++;
1108  next_index = ordered_nodes[ordered_index];
1109  next = alphas[next_index] * r / (alphas[next_index] + alphas[current_index]);
1110  diag[0] = 1.0 + next;
1111  u_diag[0] = -next;
1112  ordered_index++;
1113  for(int c = 1; c < N - 1; c++){
1114  prev_index = current_index;
1115  current_index = next_index;
1116  next_index = ordered_nodes[ordered_index];
1117  prev = alphas[prev_index] * r / (alphas[prev_index] + alphas[current_index]);
1118  next = alphas[next_index] * r / (alphas[next_index] + alphas[current_index]);
1119  l_diag[c-1] = -prev;
1120  diag[c] = 1. + prev + next;
1121  u_diag[c] = -next;
1122  ordered_index++;
1123  }
1124  prev = alphas[current_index] * r / (alphas[current_index] + alphas[next_index]);
1125  diag[N-1] = 1.0 + prev;
1126  l_diag[N-2] = -prev;
1127 
1128  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
1129 
1130  ordered_index = ordered_index_start;
1131  for(int k = 0; k < N; k++)
1132  {
1133  current_index = ordered_nodes[ordered_index];
1134  states[current_index] = RHS[k];
1135  ordered_index++;
1136  }
1137  }
1138 }
1139 static void variable_step_y(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double* states, double* RHS, double* scratchpad, double* alphas, double dt)
1140 {
1141  double* delta = g->ics_adi_dir_y->deltas;
1142  long* lines = g->ics_adi_dir_y->ordered_line_defs;
1143 
1144  double* l_diag = g->ics_tasks->l_diag;
1145  double* diag = g->ics_tasks->diag;
1146  double* u_diag = g->ics_tasks->u_diag;
1147 
1148  long next_index = -1;
1149  long prev_index = -1;
1150  double next;
1151  double prev;
1152  double dy = g->ics_adi_dir_y->d;
1153  double dc = g->ics_adi_dir_y->dc;
1154 
1155  double r = dt * dc / SQ(dy);
1156 
1157  long current_index;
1158  long* ordered_y_nodes = g->ics_adi_dir_y->ordered_nodes;
1159  long ordered_index = node_start;
1160 
1161  for(int i = line_start; i < line_stop - 1; i += 2)
1162  {
1163  long N = lines[i+1];
1164  long ordered_index_start = ordered_index;
1165 
1166  for(int j = 0; j < N; j++)
1167  {
1168  current_index = ordered_y_nodes[ordered_index];
1169  RHS[j] = states[current_index]
1170  -dt * delta[current_index]/(alphas[current_index]*SQ(dy));
1171  ordered_index++;
1172  }
1173 
1174  ordered_index = ordered_index_start;
1175  current_index = ordered_y_nodes[ordered_index];
1176  ordered_index++;
1177  next_index = ordered_y_nodes[ordered_index];
1178  next = alphas[next_index] * r / (alphas[next_index] + alphas[current_index]);
1179  diag[0] = 1.0 + next;
1180  u_diag[0] = -next;
1181  ordered_index++;
1182  for(int c = 1; c < N - 1; c++){
1183  prev_index = current_index;
1184  current_index = next_index;
1185  next_index = ordered_y_nodes[ordered_index];
1186  prev = alphas[prev_index] * r / (alphas[prev_index] + alphas[current_index]);
1187  next = alphas[next_index] * r / (alphas[next_index] + alphas[current_index]);
1188  l_diag[c-1] = -prev;
1189  diag[c] = 1. + prev + next;
1190  u_diag[c] = -next;
1191  ordered_index++;
1192  }
1193  prev = alphas[current_index] * r / (alphas[current_index] + alphas[next_index]);
1194  diag[N-1] = 1.0 + prev;
1195  l_diag[N-2] = - prev;
1196 
1197  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
1198 
1199  ordered_index = ordered_index_start;
1200  for(int k = 0; k < N; k++)
1201  {
1202  current_index = ordered_y_nodes[ordered_index];
1203  states[current_index] = RHS[k];
1204  ordered_index++;
1205  }
1206  }
1207 }
1208 static void variable_step_z(ICS_Grid_node* g, int line_start, int line_stop, int node_start, double* states, double* RHS, double* scratchpad, double* alphas, double dt)
1209 {
1210  double* delta = g->ics_adi_dir_z->deltas;
1211  long* lines = g->ics_adi_dir_z->ordered_line_defs;
1212  long* ordered_z_nodes = g->ics_adi_dir_z->ordered_nodes;
1213 
1214  double* l_diag = g->ics_tasks->l_diag;
1215  double* diag = g->ics_tasks->diag;
1216  double* u_diag = g->ics_tasks->u_diag;
1217 
1218  long next_index = -1;
1219  long prev_index = -1;
1220  double next;
1221  double prev;
1222  double dz = g->ics_adi_dir_z->d;
1223  double dc = g->ics_adi_dir_z->dc;
1224  double r = dt * dc / SQ(dz);
1225 
1226 
1227  long current_index;
1228  long ordered_index = node_start;
1229  for(int i = line_start; i< line_stop - 1; i+=2)
1230  {
1231  long N = lines[i+1];
1232  long ordered_index_start = ordered_index;
1233 
1234  for(int j = 0; j < N; j++)
1235  {
1236  current_index = ordered_z_nodes[ordered_index];
1237  RHS[j] = states[current_index]
1238  -dt * delta[current_index]/(alphas[current_index]*SQ(dz));
1239  ordered_index++;
1240  }
1241 
1242  ordered_index = ordered_index_start;
1243  current_index = ordered_z_nodes[ordered_index];
1244  ordered_index++;
1245  next_index = ordered_z_nodes[ordered_index];
1246  next = alphas[next_index] * r / (alphas[next_index] + alphas[current_index]);
1247  diag[0] = 1.0 + next;
1248  u_diag[0] = - next;
1249  ordered_index++;
1250  for(int c = 1; c < N - 1; c++){
1251  prev_index = current_index;
1252  current_index = next_index;
1253  next_index = ordered_z_nodes[ordered_index];
1254  prev = alphas[prev_index] * r / (alphas[prev_index] + alphas[current_index]);
1255  next = alphas[next_index] * r / (alphas[next_index] + alphas[current_index]);
1256  l_diag[c-1] = -prev;
1257  diag[c] = 1. + prev + next;
1258  u_diag[c] = -next;
1259  ordered_index++;
1260  }
1261  prev = alphas[current_index] * r / (alphas[current_index] + alphas[next_index]);
1262  diag[N-1] = 1.0 + prev;
1263  l_diag[N-2] = -prev;
1264  solve_dd_tridiag(N, l_diag, diag, u_diag, RHS, scratchpad);
1265 
1266  ordered_index = ordered_index_start;
1267  for(int k = 0; k < N; k++)
1268  {
1269  current_index = ordered_z_nodes[ordered_index];
1270  states[current_index] = RHS[k];
1271  ordered_index++;
1272  }
1273  }
1274 }
1275 
1276 void ics_ode_solve_helper(ICS_Grid_node* g, double dt, double* CVodeRHS)
1277 {
1278  int num_states = g->_num_nodes;
1279 
1280  long x_line_start = g->ics_adi_dir_x->line_start_stop_indices[0];
1281  long x_line_stop = g->ics_adi_dir_x->line_start_stop_indices[NUM_THREADS * 2 - 1];
1282  long x_node_start = g->ics_adi_dir_x->ordered_start_stop_indices[0];
1283  long* x_line_defs = g->ics_adi_dir_x->ordered_line_defs;
1284  long* x_ordered_nodes = g->ics_adi_dir_x->ordered_nodes;
1285  double* delta_x = g->ics_adi_dir_x->deltas;
1286 
1287  long y_line_start = g->ics_adi_dir_y->line_start_stop_indices[0];
1288  long y_line_stop = g->ics_adi_dir_y->line_start_stop_indices[NUM_THREADS * 2 - 1];
1289  long y_node_start = g->ics_adi_dir_y->ordered_start_stop_indices[0];
1290  long* y_line_defs = g->ics_adi_dir_y->ordered_line_defs;
1291  long* y_ordered_nodes = g->ics_adi_dir_y->ordered_nodes;
1292  double* delta_y = g->ics_adi_dir_y->deltas;
1293 
1294  long z_line_start = g->ics_adi_dir_z->line_start_stop_indices[0];
1295  long z_line_stop = g->ics_adi_dir_z->line_start_stop_indices[NUM_THREADS * 2 - 1];
1296  long z_node_start = g->ics_adi_dir_z->ordered_start_stop_indices[0];
1297  long* z_line_defs = g->ics_adi_dir_z->ordered_line_defs;
1298  long* z_ordered_nodes = g->ics_adi_dir_z->ordered_nodes;
1299  double* delta_z = g->ics_adi_dir_z->deltas;
1300 
1301  double* Grid_RHS = g->ics_tasks->RHS;
1302  double* Grid_ScratchPad = g->ics_tasks->scratchpad;
1303 
1304  double* CVode_states_copy = (double*)calloc(num_states, sizeof(double));
1305  memcpy(CVode_states_copy, CVodeRHS, sizeof(double)*num_states);
1306 
1307  double* alphas = g->_ics_alphas;
1308 
1309  if(g->ics_adi_dir_x->dcgrid == NULL)
1310  {
1311  //find deltas for x, y and z directions
1312  ics_find_deltas(x_line_start, x_line_stop, x_node_start, delta_x,
1313  x_line_defs, x_ordered_nodes, CVode_states_copy,
1314  g->ics_adi_dir_x->dc, alphas);
1315  ics_find_deltas(y_line_start, y_line_stop, y_node_start, delta_y,
1316  y_line_defs, y_ordered_nodes, CVode_states_copy,
1317  g->ics_adi_dir_y->dc, alphas);
1318  ics_find_deltas(z_line_start, z_line_stop, z_node_start, delta_z,
1319  z_line_defs, z_ordered_nodes, CVode_states_copy,
1320  g->ics_adi_dir_z->dc, alphas);
1321 
1322  variable_step_x(g, x_line_start, x_line_stop, x_node_start,
1323  CVode_states_copy, CVodeRHS, Grid_RHS, Grid_ScratchPad,
1324  alphas, dt);
1325  variable_step_y(g, y_line_start, y_line_stop, y_node_start,
1326  CVode_states_copy, Grid_RHS, Grid_ScratchPad, alphas,
1327  dt);
1328  variable_step_z(g, z_line_start, z_line_stop, z_node_start,
1329  CVode_states_copy, Grid_RHS, Grid_ScratchPad, alphas,
1330  dt);
1331  }
1332  else
1333  {
1334  //find deltas for x, y and z directions
1335  ics_find_deltas(x_line_start, x_line_stop, x_node_start, delta_x,
1336  x_line_defs, x_ordered_nodes, CVode_states_copy,
1337  g->ics_adi_dir_x->dcgrid, alphas);
1338  ics_find_deltas(y_line_start, y_line_stop, y_node_start, delta_y,
1339  y_line_defs, y_ordered_nodes, CVode_states_copy,
1340  g->ics_adi_dir_y->dcgrid, alphas);
1341  ics_find_deltas(z_line_start, z_line_stop, z_node_start, delta_z,
1342  z_line_defs, z_ordered_nodes, CVode_states_copy,
1343  g->ics_adi_dir_z->dcgrid, alphas);
1344 
1345  variable_step_x(g, x_line_start, x_line_stop, x_node_start,
1346  CVode_states_copy, CVodeRHS, Grid_RHS,
1347  Grid_ScratchPad, alphas, g->ics_adi_dir_x->dcgrid,
1348  dt);
1349  variable_step_y(g, y_line_start, y_line_stop, y_node_start,
1350  CVode_states_copy, Grid_RHS, Grid_ScratchPad, alphas,
1351  g->ics_adi_dir_y->dcgrid, dt);
1352  variable_step_z(g, z_line_start, z_line_stop, z_node_start,
1353  CVode_states_copy, Grid_RHS, Grid_ScratchPad, alphas,
1354  g->ics_adi_dir_z->dcgrid, dt);
1355  }
1356 
1357  memcpy(CVodeRHS, CVode_states_copy, sizeof(double)*num_states);
1358  free(CVode_states_copy);
1359 }
1360 
1362 {
1363  double dt = *dt_ptr;
1364  long num_1d_indices = g->hybrid_data->num_1d_indices;
1365  long* indices1d = g->hybrid_data->indices1d;
1366  long* num_3d_indices_per_1d_seg = g->hybrid_data->num_3d_indices_per_1d_seg;
1367  long* indices3d = g->hybrid_data->indices3d;
1368  double* rates = g->hybrid_data->rates;
1369  double* volumes1d = g->hybrid_data->volumes1d;
1370  double* volumes3d = g->hybrid_data->volumes3d;
1371 
1372  double vol_1d, vol_3d, rate, conc_1d;
1373  int my_3d_index, my_1d_index;
1374  int vol_3d_index;
1375 
1376  int total_num_3d_indices_per_1d_seg = 0;
1377  for(int i = 0; i < num_1d_indices; i++) {
1378  total_num_3d_indices_per_1d_seg += num_3d_indices_per_1d_seg[i];
1379  }
1380 
1381  // store the state values in the order that we need them
1382  double* old_g_states = (double*) malloc(sizeof(double) * total_num_3d_indices_per_1d_seg);
1383 
1384  vol_3d_index = 0;
1385  for(int i = 0; i < num_1d_indices; i++) {
1386  for (int j = 0; j < num_3d_indices_per_1d_seg[i]; j++, vol_3d_index++) {
1387  old_g_states[vol_3d_index] = g->states[indices3d[vol_3d_index]];
1388  }
1389  }
1390 
1391  vol_3d_index = 0;
1392  for(int i = 0; i<num_1d_indices; i++)
1393  {
1394  vol_1d = volumes1d[i];
1395  my_1d_index = indices1d[i];
1396  conc_1d = states[my_1d_index];
1397 
1398 
1399  //printf("for 1d index %d: volume 1d = %g and conc1d = %g\n", my_1d_index, vol_1d, conc_1d);
1400  for(int j=0; j<num_3d_indices_per_1d_seg[i]; j++, vol_3d_index++)
1401  {
1402  vol_3d = volumes3d[vol_3d_index];
1403  //rate is rate of change of 3d concentration
1404  my_3d_index = indices3d[vol_3d_index];
1405  rate = (rates[vol_3d_index]) * (old_g_states[vol_3d_index] - conc_1d);
1406  //forward euler coupling
1407  g->states[my_3d_index] -= dt * rate;
1408  states[my_1d_index] += dt * rate * vol_3d / vol_1d;
1409  //printf("for 3d index %d: volume 3d = %g and states3d = %g and rate3d = %g\n", my_3d_index, vol_3d, g->states[my_3d_index], rates[vol_3d_index]);
1410  }
1411  }
1412 
1413  free(old_g_states);
1414 }
1415 
1416 void _ics_variable_hybrid_helper(ICS_Grid_node* g, const double* cvode_states_3d, double* const ydot_3d, const double* cvode_states_1d, double *const ydot_1d)
1417 {
1418  long num_1d_indices = g->hybrid_data->num_1d_indices;
1419  long* indices1d = g->hybrid_data->indices1d;
1420  long* num_3d_indices_per_1d_seg = g->hybrid_data->num_3d_indices_per_1d_seg;
1421  long* indices3d = g->hybrid_data->indices3d;
1422  double* rates = g->hybrid_data->rates;
1423  double* volumes1d = g->hybrid_data->volumes1d;
1424  double* volumes3d = g->hybrid_data->volumes3d;
1425 
1426  double vol_1d, vol_3d, rate, conc_1d;
1427  int my_3d_index, my_1d_index;
1428  int vol_3d_index = 0;
1429 
1430  for(int i = 0; i<num_1d_indices; i++)
1431  {
1432  vol_1d = volumes1d[i];
1433  my_1d_index = indices1d[i];
1434  conc_1d = cvode_states_1d[my_1d_index];
1435  for(int j=0; j<num_3d_indices_per_1d_seg[i]; j++, vol_3d_index++)
1436  {
1437  vol_3d = volumes3d[vol_3d_index];
1438  //rate is rate of change of 3d concentration
1439  my_3d_index = indices3d[vol_3d_index];
1440  rate = (rates[vol_3d_index]) * (cvode_states_3d[my_3d_index] - conc_1d);
1441  //forward euler coupling
1442  ydot_3d[my_3d_index] -= rate;
1443  ydot_1d[my_1d_index] += rate * vol_3d / vol_1d;
1444  }
1445  }
1446 }
#define data
Definition: rbtqueue.cpp:49
void run_threaded_ics_dg_adi(struct ICSAdiDirection *)
double d
Definition: grids.h:325
TaskQueue * AllTasks
Definition: rxd.cpp:28
int ordered_start
Definition: grids.h:333
void ics_dg_adi_y_inhom(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double, double *states, double *RHS, double *scratchpad, double *u_diag, double *diag, double *l_diag)
bool hybrid
Definition: grids.h:128
long * indices1d
Definition: grids.h:60
void ics_dg_adi_z(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double, double *states, double *RHS, double *scratchpad, double *u_diag, double *diag, double *l_diag)
void _ics_hybrid_helper(ICS_Grid_node *g)
Definition: rxd.h:111
static void * do_ics_deltas(void *dataptr)
#define dc
#define diag(s)
Definition: fmenu.cpp:188
void ics_dg_adi_z_inhom(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double, double *states, double *RHS, double *scratchpad, double *u_diag, double *diag, double *l_diag)
long * ordered_start_stop_indices
Definition: grids.h:321
#define g
Definition: passive0.cpp:23
ICSAdiDirection * ics_adi_dir
Definition: grids.h:336
void ics_dg_adi_x(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double, double *states, double *RHS, double *scratchpad, double *u_diag, double *diag, double *l_diag)
void
double * states_cur
Definition: grids.h:117
void TaskQueue_sync(TaskQueue *q)
Definition: rxd.cpp:1324
double * states
Definition: rxd.cpp:62
static void variable_step_z(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double *states, double *RHS, double *scratchpad, double *alphas, double *dcs, double dt)
struct ICSAdiDirection * ics_adi_dir_y
Definition: grids.h:286
long * ordered_line_defs
Definition: grids.h:319
Item * next(Item *item)
Definition: list.cpp:95
static philox4x32_key_t k
Definition: nrnran123.cpp:11
long * line_start_stop_indices
Definition: grids.h:322
void start()
Definition: hel2mos.cpp:205
double * diag
Definition: grids.h:340
void set_hybrid_data(int64_t *num_1d_indices_per_grid, int64_t *num_3d_indices_per_grid, int64_t *hybrid_indices1d, int64_t *hybrid_indices3d, int64_t *num_3d_indices_per_1d_seg, int64_t *hybrid_grid_ids, double *rates, double *volumes1d, double *volumes3d, double *dxs)
double dt
Definition: init.cpp:123
Grid_node * Parallel_grids[100]
Definition: grids.cpp:16
Item * prev(Item *item)
Definition: list.cpp:101
void ics_dg_adi_y(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double, double *states, double *RHS, double *scratchpad, double *u_diag, double *diag, double *l_diag)
double * _ics_alphas
Definition: grids.h:259
void run_threaded_deltas(ICS_Grid_node *g, ICSAdiDirection *ics_adi_dir)
int NUM_THREADS
Definition: rxd.cpp:26
static void variable_step_y(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double *states, double *RHS, double *scratchpad, double *alphas, double *dcs, double dt)
#define SQ(x)
Definition: grids.h:20
void stop()
Definition: hel2mos.cpp:209
const int ICS_PREFETCH
int
Definition: nrnmusic.cpp:71
int line_start
Definition: grids.h:331
double * volumes3d
Definition: grids.h:65
double * RHS
Definition: grids.h:338
double * states
Definition: grids.h:113
double * dt_ptr
Definition: grids.cpp:14
double * deltas
Definition: grids.h:318
double dz
Definition: grids.h:126
double * volumes1d
Definition: grids.h:64
size_t j
static double current_state(void *v)
Definition: singlech.cpp:347
double dc
Definition: grids.h:323
double * l_diag
Definition: grids.h:339
static double flux(const double alphai, const double alphaj, const double statei, const double statej)
void * do_ics_dg_adi(void *dataptr)
double * dcgrid
Definition: grids.h:324
long * indices3d
Definition: grids.h:62
unsigned int num_states
Definition: rxd.cpp:63
int line_stop
Definition: grids.h:331
void ics_dg_adi_x_inhom(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double, double *states, double *RHS, double *scratchpad, double *u_diag, double *diag, double *l_diag)
double * scratchpad
Definition: grids.h:337
double * rates
Definition: grids.h:63
void ics_ode_solve_helper(ICS_Grid_node *g, double dt, double *CVodeRHS)
long _num_nodes
Definition: grids.h:278
void _ics_rhs_variable_step_helper(ICS_Grid_node *g, double const *const states, double *ydot)
long * ordered_nodes
Definition: grids.h:320
Grid_node * next
Definition: grids.h:111
#define i
Definition: md1redef.h:12
#define id
Definition: md1redef.h:33
#define c
struct ICSAdiDirection * ics_adi_dir_x
Definition: grids.h:285
static int solve_dd_tridiag(int N, const double *l_diag, const double *diag, const double *u_diag, double *b, double *c)
Hybrid_data * hybrid_data
Definition: grids.h:130
static void variable_step_delta(long start, long stop, long node_start, double *ydot, long *line_defs, long *ordered_nodes, double const *const states, double r, double *alphas)
#define RHS(i)
Definition: multisplit.cpp:64
long num_1d_indices
Definition: grids.h:59
struct ICSAdiDirection * ics_adi_dir_z
Definition: grids.h:287
double dy
Definition: grids.h:125
void ics_find_deltas(long start, long stop, long node_start, double *delta, long *line_defs, long *ordered_nodes, double *states, double dc, double *alphas)
ICS_Grid_node * g
Definition: grids.h:335
static void variable_step_x(ICS_Grid_node *g, int line_start, int line_stop, int node_start, double *states, double *CVodeRHS, double *RHS, double *scratchpad, double *alphas, double *dcs, double dt)
void TaskQueue_add_task(TaskQueue *q, void *(*task)(void *), void *args, void *result)
Definition: rxd.cpp:1210
long * num_3d_indices_per_1d_seg
Definition: grids.h:61
return NULL
Definition: cabcode.cpp:461
void _ics_variable_hybrid_helper(ICS_Grid_node *g, const double *cvode_states_3d, double *const ydot_3d, const double *cvode_states_1d, double *const ydot_1d)
double dx
Definition: grids.h:124
struct ICSAdiGridData * ics_tasks
Definition: grids.h:284
double * u_diag
Definition: grids.h:341