NEURON
rxd_vol.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <stdio.h>
3 #include <assert.h>
4 #include "grids.h"
5 #include "rxd.h"
6 #include <pthread.h>
7 #include <nrnwrap_Python.h>
8 
9 /*Tortuous diffusion coefficients*/
10 #define DcX(x,y,z) (g->dc_x*PERM(x,y,z))
11 #define DcY(x,y,z) (g->dc_y*PERM(x,y,z))
12 #define DcZ(x,y,z) (g->dc_z*PERM(x,y,z))
13 
14 /*Flux in the x,y,z directions*/
15 //TODO: Refactor to avoid calculating indices
16 #define Fxx(x1,x2) (ALPHA(x1,y,z)*ALPHA(x2,y,z)*DcX(x1,y,z)*(g->states[IDX(x1,y,z)] - g->states[IDX(x2,y,z)])/((ALPHA(x1,y,z)+ALPHA(x2,y,z))))
17 #define Fxy(y1,y1d,y2) (ALPHA(x,y1,z)*ALPHA(x,y2,z)*DcY(x,y1d,z)*(g->states[IDX(x,y1,z)] - g->states[IDX(x,y2,z)])/((ALPHA(x,y1,z)+ALPHA(x,y2,z))))
18 #define Fxz(z1,z1d,z2) (ALPHA(x,y,z1)*ALPHA(x,y,z2)*DcZ(x,y,z1d)*(g->states[IDX(x,y,z1)] - g->states[IDX(x,y,z2)])/((ALPHA(x,y,z1)+ALPHA(x,y,z2))))
19 #define Fyy(y1,y2) (ALPHA(x,y1,z)*ALPHA(x,y2,z)*DcY(x,y1,z)*(g->states[IDX(x,y1,z)] - g->states[IDX(x,y2,z)])/((ALPHA(x,y1,z)+ALPHA(x,y2,z))))
20 #define Fzz(z1,z2) (ALPHA(x,y,z1)*ALPHA(x,y,z2)*DcZ(x,y,z1)*(g->states[IDX(x,y,z1)] - g->states[IDX(x,y,z2)])/((ALPHA(x,y,z1)+ALPHA(x,y,z2))))
21 
22 /*Flux for used by variable step inhomogeneous volume fraction*/
23 #define FLUX(pidx,idx) (VOLFRAC(pidx)*VOLFRAC(idx)*(states[pidx] - states[idx]))/(0.5*(VOLFRAC(pidx)+VOLFRAC(idx)))
24 
25 extern int NUM_THREADS;
26 /* solve Ax=b where A is a diagonally dominant tridiagonal matrix
27  * N - length of the matrix
28  * l_diag - pointer to the lower diagonal (length N-1)
29  * diag - pointer to diagonal (length N)
30  * u_diag - pointer to the upper diagonal (length N-1)
31  * B - pointer to the RHS (length N)
32  * The solution (x) will be stored in B.
33  * l_diag, diag and u_diag are not changed.
34  * c - scratch pad, preallocated memory for (N-1) doubles
35  */
36 static int solve_dd_tridiag(int N, const double* l_diag, const double* diag,
37  const double* u_diag, double* b, double *c)
38 {
39  int i;
40 
41  c[0] = u_diag[0]/diag[0];
42  b[0] = b[0]/diag[0];
43 
44  for(i=1;i<N-1;i++)
45  {
46  c[i] = u_diag[i]/(diag[i]-l_diag[i-1]*c[i-1]);
47  b[i] = (b[i]-l_diag[i-1]*b[i-1])/(diag[i]-l_diag[i-1]*c[i-1]);
48  }
49  b[N-1] = (b[N-1]-l_diag[N-2]*b[N-2])/(diag[N-1]-l_diag[N-2]*c[N-2]);
50 
51 
52  /*back substitution*/
53  for(i=N-2;i>=0;i--)
54  {
55  b[i]=b[i]-c[i]*b[i+1];
56  }
57  return 0;
58 }
59 
60 
61 /* dg_adi_vol_x performs the first of 3 steps in DG-ADI
62  * g - the parameters and state of the grid
63  * dt - the time step
64  * y - the index for the y plane
65  * z - the index for the z plane
66  * state - where the output of this step is stored
67  * scratch - scratchpad array of doubles, length g.size_x - 1
68  * like dg_adi_x except the grid has a variable volume fraction
69  * g.alpha and my have variable tortuosity g.lambda
70  */
71 static void ecs_dg_adi_vol_x(ECS_Grid_node* g, const double dt, const int y, const int z, double const * const state, double* const RHS, double* const scratch)
72 {
73  int yp,ypd,ym,ymd,zp,zpd,zm,zmd;
74  int x;
75  double *diag;
76  double *l_diag;
77  double *u_diag;
78  double prev, next, div_y, div_z;
79 
80  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
81  if(g->bc->type == DIRICHLET && (y == 0 || z == 0 || y == g->size_y-1 || z == g->size_z-1))
82  {
83  for(x=0; x<g->size_x; x++)
84  RHS[x] = g->bc->value;
85  return;
86  }
87 
88  /*zero flux boundary condition*/
89  div_y = ((y==0||y==g->size_y-1)?1.0:0.5)*SQ(g->dy);
90  div_z = ((z==0||z==g->size_z-1)?1.0:0.5)*SQ(g->dz);
91  if(g->size_y == 1)
92  {
93  yp = 0;
94  ypd = 0;
95  ym = 0;
96  ymd = 0;
97  }
98  else
99  {
100  yp = (y==g->size_y-1)?y-1:y+1;
101  ypd = (y==g->size_y-1)?y:y+1;
102  ym = (y==0)?y+1:y-1;
103  ymd = (y==0)?1:y;
104  }
105  if(g->size_z == 1)
106  {
107  zp = 0;
108  zpd = 0;
109  zm = 0;
110  zmd = 0;
111  }
112  else
113  {
114  zp = (z==g->size_z-1)?z-1:z+1;
115  zpd = (z==g->size_z-1)?z:z+1;
116  zm = (z==0)?z+1:z-1;
117  zmd = (z==0)?1:z;
118  }
119 
120  if(g->size_x == 1)
121  {
122  if(g->bc->type == DIRICHLET)
123  {
124  RHS[0] = g->bc->value;
125  }
126  else
127  {
128  x = 0;
129  RHS[0] = 0;
130  if(g->size_y > 1)
131  RHS[0] += (Fxy(yp,ypd,y) - Fxy(y,ymd,ym))/div_y;
132  if(g->size_z > 1)
133  RHS[0] += (Fxz(zp,zpd,z) - Fxz(z,zmd,zm))/div_z;
134  RHS[0] *= (dt/ALPHA(0,y,z));
135  RHS[0] += state[IDX(0,y,z)] + g->states_cur[IDX(0,y,z)];
136  }
137  return;
138  }
139 
140  /*TODO: move allocation out of loop*/
141  diag = (double*)malloc(g->size_x*sizeof(double));
142  l_diag = (double*)malloc((g->size_x-1)*sizeof(double));
143  u_diag = (double*)malloc((g->size_x-1)*sizeof(double));
144 
145  for(x=1;x<g->size_x-1;x++)
146  {
147  prev = ALPHA(x-1,y,z)*DcX(x,y,z)/(ALPHA(x-1,y,z) + ALPHA(x,y,z));
148  next = ALPHA(x+1,y,z)*DcX(x+1,y,z)/(ALPHA(x+1,y,z) + ALPHA(x,y,z));
149 
150  l_diag[x-1] = -dt*prev/SQ(g->dx);
151  diag[x] = 1. + dt*(prev + next)/SQ(g->dx);
152  u_diag[x] = -dt*next/SQ(g->dx);
153  }
154 
155 
156  if(g->bc->type == NEUMANN)
157  {
158  /*zero flux boundary condition*/
159  next = ALPHA(1,y,z)*DcX(1,y,z)/(ALPHA(1,y,z) + ALPHA(0,y,z));
160  diag[0] = 1. + dt*next/SQ(g->dx);
161  u_diag[0] = -dt*next/SQ(g->dx);
162 
163  prev = ALPHA(g->size_x-2,y,z)*DcX(g->size_x-1,y,z)/
164  (ALPHA(g->size_x-1,y,z) + ALPHA(g->size_x-2,y,z));
165  diag[g->size_x-1] = 1. + dt*prev/SQ(g->dx);
166  l_diag[g->size_x-2] = -dt*prev/SQ(g->dx);
167 
168  x=0;
169  RHS[x] = state[IDX(x,y,z)] + (dt/ALPHA(x,y,z))*
170  ((Fxx(x+1,x)/SQ(g->dx))
171  + (Fxy(yp,ypd,y) - Fxy(y,ymd,ym))/div_y
172  + (Fxz(zp,zpd,z) - Fxz(z,zmd,zm))/div_z)
173  + g->states_cur[IDX(x,y,z)];
174 
175  x = g->size_x-1;
176  RHS[x] = state[IDX(x,y,z)] + (dt/ALPHA(x,y,z))*
177  ((Fxx(x-1,x))/SQ(g->dx)
178  + (Fxy(yp,ypd,y) - Fxy(y,ymd,ym))/div_y
179  + (Fxz(zp,zpd,z) - Fxz(z,zmd,zm))/div_z)
180  + g->states_cur[IDX(x,y,z)];
181  }
182  else
183  {
184  diag[0] = 1.0;
185  u_diag[0] = 0;
186  diag[g->size_x-1] = 1.0;
187  l_diag[g->size_x-2] = 0;
188  RHS[0] = g->bc->value;
189  RHS[g->size_x-1] = g->bc->value;
190  }
191 
192  for(x=1;x<g->size_x-1;x++)
193  {
194 #ifndef __PGI
195  __builtin_prefetch(&(state[IDX(x+PREFETCH,y,z)]), 0, 1);
196  __builtin_prefetch(&(state[IDX(x+PREFETCH,yp,z)]), 0, 0);
197  __builtin_prefetch(&(state[IDX(x+PREFETCH,ym,z)]), 0, 0);
198  __builtin_prefetch(&(state[IDX(x+PREFETCH,ypd,z)]), 0, 0);
199  __builtin_prefetch(&(state[IDX(x+PREFETCH,ymd,z)]), 0, 0);
200 #endif
201  RHS[x] = state[IDX(x,y,z)] + (dt/ALPHA(x,y,z))*
202  ((Fxx(x+1,x) - Fxx(x,x-1))/SQ(g->dx)
203  + (Fxy(yp,ypd,y) - Fxy(y,ymd,ym))/div_y
204  + (Fxz(zp,zpd,z) - Fxz(z,zmd,zm))/div_z)
205  + g->states_cur[IDX(x,y,z)];
206  }
207 
208  solve_dd_tridiag(g->size_x, l_diag, diag, u_diag, RHS, scratch);
209 
210  free(diag);
211  free(l_diag);
212  free(u_diag);
213 }
214 
215 /* dg_adi_vol_y performs the second of 3 steps in DG-ADI
216  * g - the parameters and state of the grid
217  * dt - the time step
218  * y - the index for the y plane
219  * z - the index for the z plane
220  * state - where the output of this step is stored
221  * scratch - scratchpad array of doubles, length g->size_y
222  * like dg_adi_y except the grid has a variable volume fraction
223  * g->alpha and my have variable tortuosity g->lambda
224  */
225 static void ecs_dg_adi_vol_y(ECS_Grid_node* g, double const dt, int const x, int const z, double const * const state, double* const RHS, double* const scratch)
226 {
227  int y;
228  double *diag;
229  double *l_diag;
230  double *u_diag;
231  double prev, next;
232 
233  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
234  if(g->bc->type == DIRICHLET && (x == 0 || z == 0 || x == g->size_x-1 || z == g->size_z-1))
235  {
236  for(y=0; y<g->size_y; y++)
237  RHS[y] = g->bc->value;
238  return;
239  }
240 
241  if(g->size_y == 1)
242  {
243  if(g->bc->type == DIRICHLET)
244  {
245  RHS[0] = g->bc->value;
246  }
247  else
248  {
249  RHS[0] = state[x + z*g->size_x];
250  }
251  return;
252  }
253 
254  diag = (double*)malloc(g->size_y*sizeof(double));
255  l_diag = (double*)malloc((g->size_y-1)*sizeof(double));
256  u_diag = (double*)malloc((g->size_y-1)*sizeof(double));
257 
258  for(y=1;y<g->size_y-1;y++)
259  {
260  prev = ALPHA(x,y-1,z)*DcY(x,y,z)/(ALPHA(x,y-1,z) + ALPHA(x,y,z));
261  next = ALPHA(x,y+1,z)*DcY(x,y+1,z)/(ALPHA(x,y+1,z) + ALPHA(x,y,z));
262 
263  l_diag[y-1] = -dt*prev/SQ(g->dy);
264  diag[y] = 1. + dt*(prev + next)/SQ(g->dy);
265  u_diag[y] = -dt*next/SQ(g->dy);
266  }
267 
268 
269  if(g->bc->type == NEUMANN)
270  {
271  /*zero flux boundary condition*/
272  next = ALPHA(x,1,z)*DcY(x,1,z)/(ALPHA(x,1,z) + ALPHA(x,0,z));
273  diag[0] = 1. + dt*next/SQ(g->dy);
274  u_diag[0] = -dt*next/SQ(g->dy);
275 
276  prev = ALPHA(x,g->size_y-2,z)*DcY(x,g->size_y-1,z)/
277  (ALPHA(x,g->size_y-1,z) + ALPHA(x,g->size_y-2,z));
278 
279  diag[g->size_y-1] = 1. + dt*prev/SQ(g->dy);
280  l_diag[g->size_y-2] = -dt*prev/SQ(g->dy);
281 
282  RHS[0] = state[x + z*g->size_x] - dt*Fyy(1,0)/(SQ(g->dy)*ALPHA(x,0,z));
283  y = g->size_y-1;
284  RHS[y] = state[x + (z + y*g->size_z)*g->size_x] + (dt/ALPHA(x,y,z))*Fyy(y,y-1)/SQ(g->dy);
285  }
286  else
287  {
288  diag[0] = 1.0;
289  u_diag[0] = 0;
290  diag[g->size_y-1] = 1.0;
291  l_diag[g->size_y-2] = 0;
292  RHS[0] = g->bc->value;
293  RHS[g->size_y-1] = g->bc->value;
294 
295  }
296  for(y=1;y<g->size_y-1;y++)
297  {
298 #ifndef __PGI
299  __builtin_prefetch(&state[x + (z + (y+PREFETCH)*g->size_z)*g->size_x], 0, 0);
300  __builtin_prefetch(&(g->states[IDX(x,y+PREFETCH,z)]), 0, 1);
301 #endif
302  RHS[y] = state[x + (z + y*g->size_z)*g->size_x]
303  - (dt/ALPHA(x,y,z))*(Fyy(y+1,y) - Fyy(y,y-1))/SQ(g->dy);
304  }
305 
306  solve_dd_tridiag(g->size_y, l_diag, diag, u_diag, RHS, scratch);
307 
308  free(diag);
309  free(l_diag);
310  free(u_diag);
311 
312 }
313 
314 /* dg_adi_vol_z performs the third of 3 steps in DG-ADI
315  * g - the parameters and state of the grid
316  * dt - the time step
317  * y - the index for the y plane
318  * z - the index for the z plane
319  * state - where the output of this step is stored
320  * scratch - scratchpad array of doubles, length g->size_y
321  * like dg_adi_z except the grid has a variable volume fraction
322  * g->alpha and my have variable tortuosity g->lambda
323  */
324 static void ecs_dg_adi_vol_z(ECS_Grid_node* g, double const dt, int const x, int const y, double const * const state, double* const RHS, double* const scratch)
325 {
326  int z;
327  double *diag;
328  double *l_diag;
329  double *u_diag;
330  double prev, next;
331 
332  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
333  if(g->bc->type == DIRICHLET && (x == 0 || y == 0 || x == g->size_x-1 || y == g->size_y-1))
334  {
335  for(z=0; z<g->size_z; z++)
336  RHS[z] = g->bc->value;
337  return;
338  }
339  if(g->size_z == 1)
340  {
341  if(g->bc->type == DIRICHLET)
342  {
343  RHS[0] = g->bc->value;
344  }
345  else
346  {
347  RHS[0] = state[y + g->size_y*x];
348  }
349  return;
350  }
351 
352  diag = (double*)malloc(g->size_z*sizeof(double));
353  l_diag = (double*)malloc((g->size_z-1)*sizeof(double));
354  u_diag = (double*)malloc((g->size_z-1)*sizeof(double));
355 
356  for(z=1;z<g->size_z-1;z++)
357  {
358  prev = ALPHA(x,y,z-1)*DcZ(x,y,z)/(ALPHA(x,y,z-1) + ALPHA(x,y,z));
359  next = ALPHA(x,y,z+1)*DcZ(x,y,z+1)/(ALPHA(x,y,z+1) + ALPHA(x,y,z));
360 
361  l_diag[z-1] = -dt*prev/SQ(g->dz);
362  diag[z] = 1. + dt*(prev + next)/SQ(g->dz);
363  u_diag[z] = -dt*next/SQ(g->dz);
364  }
365 
366  if(g->bc->type == NEUMANN)
367  {
368  /*zero flux boundary condition*/
369  next = ALPHA(x,y,1)*DcZ(x,y,1)/(ALPHA(x,y,1) + ALPHA(x,y,0));
370  diag[0] = 1. + dt*next/SQ(g->dz);
371  u_diag[0] = -dt*next/SQ(g->dz);
372 
373  prev = ALPHA(x,y,g->size_z-2)*DcZ(x,y,g->size_z-1)/
374  (ALPHA(x,y,g->size_z-1) + ALPHA(x,y,g->size_z-2));
375 
376  diag[g->size_z-1] = 1. + dt*prev/SQ(g->dz);
377  l_diag[g->size_z-2] = -dt*prev/SQ(g->dz);
378 
379  RHS[0] = state[y + g->size_y*(x*g->size_z)] - dt*Fzz(1,0)/(SQ(g->dz)*ALPHA(x,y,0));
380  z = g->size_z-1;
381  RHS[z] = state[y + g->size_y*(x*g->size_z + z)] + (dt/ALPHA(x,y,z))*Fzz(z,z-1)/SQ(g->dz);
382  }
383  else
384  {
385  diag[0] = 1.0;
386  u_diag[0] = 0;
387  diag[g->size_z-1] = 1.0;
388  l_diag[g->size_z-2] = 0;
389  RHS[0] = g->bc->value;
390  RHS[g->size_z-1] = g->bc->value;
391 
392  }
393  for(z=1;z<g->size_z-1;z++)
394  {
395  RHS[z] = state[y + g->size_y*(x*g->size_z + z)]
396  - (dt/ALPHA(x,y,z))*(Fzz(z+1,z) - Fzz(z,z-1))/SQ(g->dz);
397  }
398 
399  solve_dd_tridiag(g->size_z, l_diag, diag, u_diag, RHS, scratch);
400 
401  free(diag);
402  free(l_diag);
403  free(u_diag);
404 
405 }
406 
407 /*DG-ADI implementation the 3 step process to diffusion species in grid g by time step *dt_ptr
408  * g - the state and parameters
409  * like dg_adi execpt the Grid_node g has variable volume fraction g.alpha and may have
410  * variable tortuosity g.lambda
411  */
413 {
417 }
418 
419 
420 /* dg_adi_tort_x performs the first of 3 steps in DG-ADI
421  * g - the parameters and state of the grid
422  * dt - the time step
423  * y - the index for the y plane
424  * z - the index for the z plane
425  * state - where the output of this step is stored
426  * scratch - scratchpad array of doubles, length g.size_x - 1
427  * like dg_adi_x except the grid has a variable tortuosity
428  * g.lambda (but it still has fixed volume fraction)
429  */
430 static void ecs_dg_adi_tort_x(ECS_Grid_node* g, const double dt, const int y, const int z, double const * const state, double* const RHS, double* const scratch)
431 {
432  int yp,ypd,ym,ymd,zp,zpd,zm,zmd,div_y,div_z;
433  int x;
434  double *diag;
435  double *l_diag;
436  double *u_diag;
437 
438  if(g->bc->type == DIRICHLET && (y == 0 || z == 0 || y == g->size_y-1 || z == g->size_z-1))
439  {
440  for(x=0; x<g->size_x; x++)
441  RHS[x] = g->bc->value;
442  return;
443  }
444 
445  /*zero flux boundary condition*/
446  div_y = (y==0||y==g->size_y-1)?2:1;
447  div_z = (z==0||z==g->size_z-1)?2:1;
448  if(g->size_y == 1)
449  {
450  yp = 0;
451  ypd = 0;
452  ym = 0;
453  ymd = 0;
454  }
455  else
456  {
457  yp = (y==g->size_y-1)?y-1:y+1;
458  ypd = (y==g->size_y-1)?y:y+1;
459  ym = (y==0)?y+1:y-1;
460  ymd = (y==0)?1:y;
461  }
462  if(g->size_z == 1)
463  {
464  zp = 0;
465  zpd = 0;
466  zm = 0;
467  zmd = 0;
468  }
469  else
470  {
471  zp = (z==g->size_z-1)?z-1:z+1;
472  zpd = (z==g->size_z-1)?z:z+1;
473  zm = (z==0)?z+1:z-1;
474  zmd = (z==0)?1:z;
475  }
476 
477  if(g->size_x == 1)
478  {
479  if(g->bc->type == DIRICHLET)
480  {
481  RHS[0] = g->bc->value;
482  }
483  else
484  {
485  RHS[0] = 0;
486  if(g->size_y > 1)
487  RHS[0] += (DcY(0,ypd,z)*state[IDX(0,yp,z)] - (DcY(0,ypd,z)+DcY(0,ymd,z))*state[IDX(0,y,z)] + DcY(0,ymd,z)*state[IDX(0,ym,z)])/(div_y*SQ(g->dy));
488  if(g->size_z > 1)
489  RHS[0] += (DcZ(0,y,zpd)*state[IDX(0,y,zp)] - (DcZ(0,y,zpd)+DcZ(0,y,zmd))*state[IDX(0,y,z)] + DcZ(0,y,zmd)*state[IDX(0,y,zm)])/(div_z*SQ(g->dz));
490  RHS[0] *= dt;
491  RHS[0] += state[IDX(0,y,z)] + g->states_cur[IDX(0,y,z)];
492  }
493  return;
494  }
495 
496  diag = (double*)malloc(g->size_x*sizeof(double));
497  l_diag = (double*)malloc((g->size_x-1)*sizeof(double));
498  u_diag = (double*)malloc((g->size_x-1)*sizeof(double));
499 
500  for(x=1;x<g->size_x-1;x++)
501  {
502  l_diag[x-1] = -dt*DcX(x,y,z)/(2.*SQ(g->dx));
503  diag[x] = 1. + dt*(DcX(x,y,z) + DcX(x+1,y,z))/(2.*SQ(g->dx));
504  u_diag[x] = -dt*DcX(x+1,y,z)/(2.*SQ(g->dx));
505  }
506 
507 
508  if(g->bc->type == NEUMANN)
509  {
510  diag[0] = 1. + 0.5*dt*DcX(1,y,z)/SQ(g->dx);
511  u_diag[0] = -0.5*dt*DcX(1,y,z)/SQ(g->dx);
512  diag[g->size_x-1] = 1. + 0.5*dt*DcX(g->size_x-1,y,z)/SQ(g->dx);
513  l_diag[g->size_x-2] = -0.5*dt*DcX(g->size_x-1,y,z)/SQ(g->dx);
514 
515 
516  RHS[0] = state[IDX(0,y,z)]
517  + dt*((DcX(1,y,z)*state[IDX(1,y,z)] - DcX(1,y,z)*state[IDX(0,y,z)])/(2.*SQ(g->dx))
518  + (DcY(0,ypd,z)*state[IDX(0,yp,z)] - (DcY(0,ypd,z)+DcY(0,ymd,z))*state[IDX(0,y,z)] + DcY(0,ymd,z)*state[IDX(0,ym,z)])/(div_y*SQ(g->dy))
519  + (DcZ(0,y,zpd)*state[IDX(0,y,zp)] - (DcZ(0,y,zpd)+DcZ(0,y,zmd))*state[IDX(0,y,z)] + DcZ(0,y,zmd)*state[IDX(0,y,zm)])/(div_z*SQ(g->dz)))
520  + g->states_cur[IDX(0,y,z)];
521  x = g->size_x-1;
522  RHS[x] = state[IDX(x,y,z)]
523  + dt*((DcX(x,y,z)*state[IDX(x-1,y,z)] - DcX(x,y,z)*state[IDX(x,y,z)])/(2.*SQ(g->dx))
524  + (DcY(x,ypd,z)*state[IDX(x,yp,z)] - (DcY(x,ypd,z)+DcY(x,ymd,z))*state[IDX(x,y,z)] + DcY(x,ymd,z)*state[IDX(x,ym,z)])/(div_y*SQ(g->dy))
525  + (DcZ(x,y,zpd)*state[IDX(x,y,zp)] - (DcZ(x,y,zpd)+DcZ(x,y,zmd))*state[IDX(x,y,z)] + DcZ(x,y,zmd)*state[IDX(x,y,zm)])/(div_z*SQ(g->dz)))
526  + g->states_cur[IDX(x,y,z)];
527 
528  }
529  else
530  {
531  diag[0] = 1.0;
532  u_diag[0] = 0.0;
533  diag[g->size_x-1] = 1.0;
534  l_diag[g->size_x-2] = 0.0;
535  RHS[0] = g->bc->value;
536  RHS[g->size_x-1] = g->bc->value;
537  }
538 
539  for(x=1;x<g->size_x-1;x++)
540  {
541 #ifndef __PGI
542  __builtin_prefetch(&(state[IDX(x+PREFETCH,y,z)]), 0, 1);
543  __builtin_prefetch(&(state[IDX(x+PREFETCH,yp,z)]), 0, 0);
544  __builtin_prefetch(&(state[IDX(x+PREFETCH,ym,z)]), 0, 0);
545 #endif
546 
547  RHS[x] = state[IDX(x,y,z)]
548  + dt*((DcX(x+1,y,z)*state[IDX(x+1,y,z)] - (DcX(x+1,y,z)+DcX(x,y,z))*state[IDX(x,y,z)] + DcX(x,y,z)*state[IDX(x-1,y,z)])/(2.*SQ(g->dx))
549  + (DcY(x,ypd,z)*state[IDX(x,yp,z)] - (DcY(x,ypd,z)+DcY(x,ymd,z))*state[IDX(x,y,z)] + DcY(x,ymd,z)*state[IDX(x,ym,z)])/(div_y*SQ(g->dy))
550  + (DcZ(x,y,zpd)*state[IDX(x,y,zp)] - (DcZ(x,y,zpd)+DcZ(x,y,zmd))*state[IDX(x,y,z)] + DcZ(x,y,zmd)*state[IDX(x,y,zm)])/(div_z*SQ(g->dz)))
551  + g->states_cur[IDX(x,y,z)];
552  }
553 
554  solve_dd_tridiag(g->size_x, l_diag, diag, u_diag, RHS, scratch);
555 
556  free(diag);
557  free(l_diag);
558  free(u_diag);
559 }
560 
561 
562 /* dg_adi_tort_y performs the second of 3 steps in DG-ADI
563  * g - the parameters and state of the grid
564  * dt - the time step
565  * y - the index for the y plane
566  * z - the index for the z plane
567  * state - where the output of this step is stored
568  * scratch - scratchpad array of doubles, length g->size_y - 1
569  * like dg_adi_y except the grid has a variable tortuosity
570  * g->lambda (but it still has fixed volume fraction)
571  */
572 static void ecs_dg_adi_tort_y(ECS_Grid_node* g, double const dt, int const x, int const z, double const * const state, double* const RHS, double* const scratch)
573 {
574  int y;
575  double *diag;
576  double *l_diag;
577  double *u_diag;
578 
579  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
580  if(g->bc->type == DIRICHLET && (x == 0 || z == 0 || x == g->size_x-1 || z == g->size_z-1))
581  {
582  for(y=0; y<g->size_y; y++)
583  RHS[y] = g->bc->value;
584  return;
585  }
586 
587  if(g->size_y == 1)
588  {
589  if(g->bc->type == DIRICHLET)
590  {
591  RHS[0] = g->bc->value;
592  }
593  else
594  {
595  RHS[0] = state[x + z*g->size_x];
596  }
597  return;
598  }
599 
600  diag = (double*)malloc(g->size_y*sizeof(double));
601  l_diag = (double*)malloc((g->size_y-1)*sizeof(double));
602  u_diag = (double*)malloc((g->size_y-1)*sizeof(double));
603 
604  for(y=1;y<g->size_y-1;y++)
605  {
606  l_diag[y-1] = -dt*DcY(x,y,z)/(2.*SQ(g->dy));
607  diag[y] = 1. + dt*(DcY(x,y,z)+DcY(x,y+1,z))/(2.*SQ(g->dy));
608  u_diag[y] = -dt*DcY(x,y+1,z)/(2.*SQ(g->dy));
609  }
610 
611  if(g->bc->type == NEUMANN)
612  {
613  /*zero flux boundary condition*/
614  diag[0] = 1. + 0.5*dt*DcY(x,1,z)/SQ(g->dy);
615  u_diag[0] = -0.5*dt*DcY(x,1,z)/SQ(g->dy);
616  diag[g->size_y-1] = 1. + 0.5*dt*DcY(x,g->size_y-1,z)/SQ(g->dy);
617  l_diag[g->size_y-2] = -0.5*dt*DcY(x,g->size_y-1,z)/SQ(g->dy);
618 
619 
620 
621  RHS[0] = state[x + z*g->size_x] - dt*((DcY(x,1,z)*g->states[IDX(x,1,z)] - DcY(x,1,z)*g->states[IDX(x,0,z)])/(2.*SQ(g->dy)));
622  y = g->size_y-1;
623  RHS[y] = state[x + (z + y*g->size_z)*g->size_x]
624  - dt*(DcY(x,y,z)*g->states[IDX(x,y-1,z)] - DcY(x,y,z)*g->states[IDX(x,y,z)])/(2.*SQ(g->dy));
625  }
626  else
627  {
628  diag[0] = 1.0;
629  u_diag[0] = 0.0;
630  diag[g->size_y-1] = 1.0;
631  l_diag[g->size_y-2] = 0.0;
632  RHS[0] = g->bc->value;
633  RHS[g->size_y-1] = g->bc->value;
634  }
635 
636 
637  for(y=1;y<g->size_y-1;y++)
638  {
639 #ifndef __PGI
640  __builtin_prefetch(&state[x + (z + (y+PREFETCH)*g->size_z)*g->size_x], 0, 0);
641  __builtin_prefetch(&(g->states[IDX(x,y+PREFETCH,z)]), 0, 1);
642 #endif
643  RHS[y] = state[x + (z + y*g->size_z)*g->size_x] - dt*(DcY(x,y+1,z)*g->states[IDX(x,y+1,z)] - (DcY(x,y+1,z)+DcY(x,y,z))*g->states[IDX(x,y,z)] + DcY(x,y,z)*g->states[IDX(x,y-1,z)])/(2.*SQ(g->dy));
644 
645  }
646 
647  solve_dd_tridiag(g->size_y, l_diag, diag, u_diag, RHS, scratch);
648 
649  free(diag);
650  free(l_diag);
651  free(u_diag);
652 
653 }
654 
655 /* dg_adi_tort_z performs the second of 3 steps in DG-ADI
656  * g - the parameters and state of the grid
657  * dt - the time step
658  * y - the index for the y plane
659  * z - the index for the z plane
660  * state - where the output of this step is stored
661  * scratch - scratchpad array of doubles, length g->size_z - 1
662  * like dg_adi_z except the grid has a variable tortuosity
663  * g->lambda (but it still has fixed volume fraction)
664  */
665 static void ecs_dg_adi_tort_z(ECS_Grid_node* g, double const dt, int const x, int const y, double const * const state, double* const RHS, double* const scratch)
666 {
667  int z;
668  double *diag;
669  double *l_diag;
670  double *u_diag;
671 
672  /*TODO: Get rid of this by not calling dg_adi when on the boundary for DIRICHLET conditions*/
673  if(g->bc->type == DIRICHLET && (x == 0 || y == 0 || x == g->size_x-1 || y == g->size_y-1))
674  {
675  for(z=0; z<g->size_z; z++)
676  RHS[z] = g->bc->value;
677  return;
678  }
679 
680  if(g->size_z == 1)
681  {
682  if(g->bc->type == DIRICHLET)
683  {
684  RHS[0] = g->bc->value;
685  }
686  else
687  {
688  RHS[0] = state[y + g->size_y*x];
689  }
690  return;
691  }
692  diag = (double*)malloc(g->size_z*sizeof(double));
693  l_diag = (double*)malloc((g->size_z-1)*sizeof(double));
694  u_diag = (double*)malloc((g->size_z-1)*sizeof(double));
695 
696 
697  for(z=1;z<g->size_z-1;z++)
698  {
699  l_diag[z-1] = -dt*DcZ(x,y,z)/(2.*SQ(g->dz));
700  diag[z] = 1. + dt*(DcZ(x,y,z)+DcZ(x,y,z+1))/(2.*SQ(g->dz));
701  u_diag[z] = -dt*DcZ(x,y,z+1)/(2.*SQ(g->dz));
702  }
703 
704  if(g->bc->type == NEUMANN)
705  {
706  /*zero flux boundary condition*/
707  diag[0] = 1. + 0.5*dt*DcZ(x,y,1)/SQ(g->dz);
708  u_diag[0] = -0.5*dt*DcZ(x,y,1)/SQ(g->dz);
709  diag[g->size_z-1] = 1. + 0.5*dt*DcZ(x,y,g->size_z-1)/SQ(g->dz);
710  l_diag[g->size_z-2] = -0.5*dt*DcZ(x,y,g->size_z-1)/SQ(g->dz);
711 
712  RHS[0] = state[y + g->size_y*(x*g->size_z)] - dt*((DcZ(x,y,1)*g->states[IDX(x,y,1)] - DcZ(x,y,1)*g->states[IDX(x,y,0)])/(2.*SQ(g->dz)));
713  z = g->size_z-1;
714  RHS[z] = state[y + g->size_y*(x*g->size_z + z)]
715  - dt*(DcZ(x,y,z)*g->states[IDX(x,y,z-1)] - DcZ(x,y,z)*g->states[IDX(x,y,z)])/(2.*SQ(g->dz));
716  }
717  else
718  {
719  diag[0] = 1.0;
720  u_diag[0] = 0.0;
721  diag[g->size_z-1] = 1.0;
722  l_diag[g->size_z-2] = 0.0;
723  RHS[0] = g->bc->value;
724  RHS[g->size_z-1] = g->bc->value;
725  }
726 
727 
728 
729  for(z=1;z<g->size_z-1;z++)
730  {
731  RHS[z] = state[y + g->size_y*(x*g->size_z + z)]
732  - dt*(DcZ(x,y,z+1)*g->states[IDX(x,y,z+1)] - (DcZ(x,y,z+1)+DcZ(x,y,z))*g->states[IDX(x,y,z)] + DcZ(x,y,z)*g->states[IDX(x,y,z-1)])/(2.*SQ(g->dz));
733 
734  }
735 
736  solve_dd_tridiag(g->size_z, l_diag, diag, u_diag, RHS, scratch);
737 
738  free(diag);
739  free(l_diag);
740  free(u_diag);
741 }
742 
743 /*DG-ADI implementation the 3 step process to diffusion species in grid g by time step *dt_ptr
744  * g - the state and parameters
745  * like dg_adi except the grid node g has variable tortuosity g.lambda (but fixed volume
746  * fraction)
747  */
749 {
753 }
754 
755 
756 /*****************************************************************************
757 *
758 * Begin variable step code
759 *
760 *****************************************************************************/
761 
762 void _rhs_variable_step_helper_tort(Grid_node* g, double const * const states, double* ydot) {
763  int num_states_x = g->size_x, num_states_y = g->size_y, num_states_z = g->size_z;
764  double dx = g->dx, dy = g->dy, dz = g->dz;
765  int i, j, k, stop_i, stop_j, stop_k;
766  double rate_x = 1. / (dx * dx);
767  double rate_y = 1. / (dy * dy);
768  double rate_z = 1. / (dz * dz);
769 
770  /*indices*/
771  int index, prev_i, prev_j, prev_k, next_i ,next_j, next_k;
772  int xpd, xmd, ypd, ymd, zpd, zmd;
773  double div_x, div_y, div_z;
774 
775  /* Euler advance x, y, z (all points) */
776  stop_i = num_states_x - 1;
777  stop_j = num_states_y - 1;
778  stop_k = num_states_z - 1;
779  if(g->bc->type == NEUMANN) {
780  for (i = 0, index = 0, prev_i = num_states_y*num_states_z, next_i = num_states_y*num_states_z;
781  i < num_states_x; i++) {
782  /*Zero flux boundary conditions*/
783  div_x = (i==0||i==stop_i)?2.:1.;
784  xpd = (i==stop_i)?i:i+1;
785  xmd = (i==0)?1:i;
786 
787  for(j = 0, prev_j = index + num_states_z, next_j = index + num_states_z; j < num_states_y; j++) {
788  div_y = (j==0||j==stop_j)?2.:1.;
789  ypd = (j==stop_j)?j:j+1;
790  ymd = (j==0)?1:j;
791 
792  for(k = 0, prev_k = index + 1, next_k = index + 1; k < num_states_z;
793  k++, index++, prev_i++, next_i++, prev_j++, next_j++) {
794  div_z = (k==0||k==stop_k)?2.:1.;
795  zpd = (k==stop_k)?k:k+1;
796  zmd = (k==0)?1:k;
797 
798  if(stop_i > 0)
799  {
800  ydot[index] += rate_x * (DcX(xmd,j,k)*states[prev_i] -
801  (DcX(xmd,j,k)+DcX(xpd,j,k)) * states[index] +
802  DcX(xpd,j,k)*states[next_i])/div_x;
803  }
804  if(stop_j > 0)
805  {
806  ydot[index] += rate_y * (DcY(i,ymd,k)*states[prev_j] -
807  (DcY(i,ymd,k)+DcY(i,ypd,k)) * states[index] +
808  DcY(i,ypd,k)*states[next_j])/div_y;
809  }
810 
811  if(stop_k > 0)
812  {
813  ydot[index] += rate_z * (DcZ(i,j,zmd)*states[prev_k] -
814  (DcZ(i,j,zmd)+DcZ(i,j,zpd)) * states[index] +
815  DcZ(i,j,zpd)*states[next_k])/div_z;
816  }
817 
818  next_k = (k==stop_k-1)?index:index+2;
819  prev_k = index;
820 
821  }
822  prev_j = index - num_states_z;
823  next_j = (j==stop_j-1)?prev_j:index + num_states_z;
824  }
825  prev_i = index - num_states_y*num_states_z;
826  next_i = (i==stop_i-1)?prev_i:index+num_states_y*num_states_z;
827  }
828  }
829  else {
830  for (i = 0, index = 0, prev_i = 0, next_i = num_states_y*num_states_z;
831  i < num_states_x; i++) {
832  for(j = 0, prev_j = index - num_states_z, next_j = index + num_states_z; j < num_states_y; j++) {
833 
834  for(k = 0, prev_k = index - 1, next_k = index + 1; k < num_states_z;
835  k++, index++, prev_i++, next_i++, prev_j++, next_j++, next_k++, prev_k++) {
836 
837  if(i==0||i==stop_i||j==0||j==stop_j||k==0||k==stop_k)
838  {
839  //set to zero to prevent currents altering concentrations at the boundary
840  ydot[index] = 0;
841  }
842  else
843  {
844 
845  ydot[index] += rate_x * (DcX(i,j,k)*states[prev_i] -
846  (DcX(i,j,k)+DcX(i+1,j,k)) * states[index] +
847  DcX(i+1,j,k)*states[next_i]);
848 
849  ydot[index] += rate_y * (DcY(i,j,k)*states[prev_j] -
850  (DcY(i,j,k)+DcY(i,j+1,k)) * states[index] +
851  DcY(i,j+1,k)*states[next_j]);
852 
853  ydot[index] += rate_z * (DcZ(i,j,k)*states[prev_k] -
854  (DcZ(i,j,k)+DcZ(i,j,k+1)) * states[index] +
855  DcZ(i,j,k+1)*states[next_k]);
856  }
857  }
858  prev_j = index - num_states_z;
859  next_j = index + num_states_z;
860  }
861  prev_i = index - num_states_y*num_states_z;
862  next_i = index + num_states_y*num_states_z;
863  }
864  }
865 }
866 
867 
868 
869 
870 void _rhs_variable_step_helper_vol(Grid_node* g, double const * const states, double* ydot) {
871  int num_states_x = g->size_x, num_states_y = g->size_y, num_states_z = g->size_z;
872  double dx = g->dx, dy = g->dy, dz = g->dz;
873  int i, j, k, stop_i, stop_j, stop_k;
874  double rate_x = g->dc_x / (dx * dx);
875  double rate_y = g->dc_y / (dy * dy);
876  double rate_z = g->dc_z / (dz * dz);
877 
878 
879  /*indices*/
880  int index, prev_i, prev_j, prev_k, next_i ,next_j, next_k;
881 
882  /*zero flux boundary conditions*/
883  int xpd, xmd, ypd, ymd, zpd, zmd;
884  double div_x, div_y, div_z;
885 
886  /* Euler advance x, y, z (all points) */
887  stop_i = num_states_x - 1;
888  stop_j = num_states_y - 1;
889  stop_k = num_states_z - 1;
890  if(g->bc->type == NEUMANN) {
891  for (i = 0, index = 0, prev_i = num_states_y*num_states_z, next_i = num_states_y*num_states_z;
892  i < num_states_x; i++) {
893  /*Zero flux boundary conditions*/
894  div_x = (i==0||i==stop_i)?2.:1.;
895  xpd = (i==stop_i)?i:i+1;
896  xmd = (i==0)?1:i;
897 
898  for(j = 0, prev_j = index + num_states_z, next_j = index + num_states_z; j < num_states_y; j++) {
899  div_y = (j==0||j==stop_j)?2.:1.;
900  ypd = (j==stop_j)?j:j+1;
901  ymd = (j==0)?1:j;
902 
903  for(k = 0, prev_k = index + 1, next_k = index + 1; k < num_states_z;
904  k++, index++, prev_i++, next_i++, prev_j++, next_j++) {
905  div_z = (k==0||k==stop_k)?2.:1.;
906  zpd = (k==stop_k)?k:k+1;
907  zmd = (k==0)?1:k;
908 
909  /*x-direction*/
910  if(stop_i > 0)
911  {
912  ydot[index] += rate_x * (FLUX(next_i,index)*PERM(xpd,j,k) +
913  FLUX(prev_i,index)*PERM(xmd,j,k))/(VOLFRAC(index)*div_x);
914  }
915 
916  /*y-direction*/
917  if(stop_j > 0)
918  {
919  ydot[index] += rate_y * (FLUX(next_j,index)*PERM(i,ypd,k) +
920  FLUX(prev_j,index)*PERM(i,ymd,k))/(VOLFRAC(index)*div_y);
921  }
922 
923  /*z-direction*/
924  if(stop_k > 0)
925  {
926  ydot[index] += rate_z * (FLUX(next_k,index)*PERM(i,j,zpd) +
927  FLUX(prev_k,index)*PERM(i,j,zmd))/(VOLFRAC(index)*div_z);
928  }
929 
930  next_k = (k==stop_k-1)?index:index+2;
931  prev_k = index;
932 
933  }
934  prev_j = index - num_states_z;
935  next_j = (j==stop_j-1)?prev_j:index + num_states_z;
936  }
937  prev_i = index - num_states_y*num_states_z;
938  next_i = (i==stop_i-1)?prev_i:index+num_states_y*num_states_z;
939  }
940  }
941  else {
942  for (i = 0, index = 0, prev_i = 0, next_i = num_states_y*num_states_z;
943  i < num_states_x; i++) {
944  for(j = 0, prev_j = index - num_states_z, next_j = index + num_states_z; j < num_states_y; j++) {
945 
946  for(k = 0, prev_k = index - 1, next_k = index + 1; k < num_states_z;
947  k++, index++, prev_i++, next_i++, prev_j++, next_j++, next_k++, prev_k++) {
948 
949  if(i==0||i==stop_i||j==0||j==stop_j||k==0||k==stop_k)
950  {
951  //set to zero to prevent currents altering concentrations at the boundary
952  ydot[index] = 0;
953  }
954  else
955  {
956  /*x-direction*/
957  ydot[index] += rate_x * (FLUX(next_i,index)*PERM(i+1,j,k) +
958  FLUX(prev_i,index)*PERM(i,j,k))/(VOLFRAC(index));
959 
960  /*y-direction*/
961  ydot[index] += rate_y * (FLUX(next_j,index)*PERM(i,j+1,k) +
962  FLUX(prev_j,index)*PERM(i,j,k))/(VOLFRAC(index));
963 
964  /*z-direction*/
965  ydot[index] += rate_z * (FLUX(next_k,index)*PERM(i,j,k+1) +
966  FLUX(prev_k,index)*PERM(i,j,k))/(VOLFRAC(index));
967  }
968  }
969  prev_j = index - num_states_z;
970  next_j = index + num_states_z;
971  }
972  prev_i = index - num_states_y*num_states_z;
973  next_i = index + num_states_y*num_states_z;
974  }
975  }
976 
977 }
978 
979 
double value
Definition: grids.h:106
double dc_z
Definition: grids.h:123
void ecs_set_adi_vol(ECS_Grid_node *g)
Definition: rxd_vol.cpp:412
static void ecs_dg_adi_tort_x(ECS_Grid_node *g, const double dt, const int y, const int z, double const *const state, double *const RHS, double *const scratch)
Definition: rxd_vol.cpp:430
#define PREFETCH
Definition: rxd.h:7
#define ALPHA(x, y, z)
Definition: grids.h:16
#define Fxz(z1, z1d, z2)
Definition: rxd_vol.cpp:18
#define diag(s)
Definition: fmenu.cpp:188
#define g
Definition: passive0.cpp:23
#define IDX(x, y, z)
Definition: grids.h:14
double * states_cur
Definition: grids.h:117
static void ecs_dg_adi_vol_x(ECS_Grid_node *g, const double dt, const int y, const int z, double const *const state, double *const RHS, double *const scratch)
Definition: rxd_vol.cpp:71
static void ecs_dg_adi_tort_z(ECS_Grid_node *g, double const dt, int const x, int const y, double const *const state, double *const RHS, double *const scratch)
Definition: rxd_vol.cpp:665
int size_x
Definition: grids.h:118
#define DIRICHLET
Definition: grids.h:29
int size_y
Definition: grids.h:119
Item * next(Item *item)
Definition: list.cpp:95
#define DcZ(x, y, z)
Definition: rxd_vol.cpp:12
#define NEUMANN
Definition: grids.h:28
static philox4x32_key_t k
Definition: nrnran123.cpp:11
double dt
Definition: init.cpp:123
Item * prev(Item *item)
Definition: list.cpp:101
double dc_x
Definition: grids.h:121
void ecs_set_adi_tort(ECS_Grid_node *g)
Definition: rxd_vol.cpp:748
void _rhs_variable_step_helper_vol(Grid_node *g, double const *const states, double *ydot)
Definition: rxd_vol.cpp:870
#define SQ(x)
Definition: grids.h:20
static void ecs_dg_adi_tort_y(ECS_Grid_node *g, double const dt, int const x, int const z, double const *const state, double *const RHS, double *const scratch)
Definition: rxd_vol.cpp:572
#define VOLFRAC(idx)
Definition: grids.h:17
double * states
Definition: grids.h:113
double dz
Definition: grids.h:126
size_t j
unsigned char type
Definition: grids.h:105
static char scratch[MAXLINE+1]
Definition: otherio.c:41
static void ecs_dg_adi_vol_z(ECS_Grid_node *g, double const dt, int const x, int const y, double const *const state, double *const RHS, double *const scratch)
Definition: rxd_vol.cpp:324
double dc_y
Definition: grids.h:122
#define Fyy(y1, y2)
Definition: rxd_vol.cpp:19
int size_z
Definition: grids.h:120
struct ECSAdiDirection * ecs_adi_dir_z
Definition: grids.h:197
int NUM_THREADS
Definition: rxd.cpp:26
BoundaryConditions * bc
Definition: grids.h:129
#define i
Definition: md1redef.h:12
#define c
#define RHS(i)
Definition: multisplit.cpp:64
#define FLUX(pidx, idx)
Definition: rxd_vol.cpp:23
double dy
Definition: grids.h:125
struct ECSAdiDirection * ecs_adi_dir_y
Definition: grids.h:196
#define Fzz(z1, z2)
Definition: rxd_vol.cpp:20
#define DcY(x, y, z)
Definition: rxd_vol.cpp:11
static int solve_dd_tridiag(int N, const double *l_diag, const double *diag, const double *u_diag, double *b, double *c)
Definition: rxd_vol.cpp:36
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
#define Fxy(y1, y1d, y2)
Definition: rxd_vol.cpp:17
static void ecs_dg_adi_vol_y(ECS_Grid_node *g, double const dt, int const x, int const z, double const *const state, double *const RHS, double *const scratch)
Definition: rxd_vol.cpp:225
#define Fxx(x1, x2)
Definition: rxd_vol.cpp:16
struct ECSAdiDirection * ecs_adi_dir_x
Definition: grids.h:195
void _rhs_variable_step_helper_tort(Grid_node *g, double const *const states, double *ydot)
Definition: rxd_vol.cpp:762
double dx
Definition: grids.h:124
short index
Definition: cabvars.h:11
double * states
Definition: rxd.cpp:62
#define PERM
Definition: ocmatrix.h:7
#define DcX(x, y, z)
Definition: rxd_vol.cpp:10