Layers
Diffusion in heterogeneous environments
model.c
Go to the documentation of this file.
1 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17 #include <math.h>
18 #include "header.h"
19 
20 
94 void calc_diffusion_curve_layer_fit_layer(int nt, int nz, int nr, int iprobe, int jprobe, int iz1, int iz2, int nolayer, double dt, double dr, double sd, double st, double alpha_so, double theta_so, double kappa_so, double alpha_sp, double theta_sp, double kappa_sp, double alpha_sr, double theta_sr, double kappa_sr, double dfree, double *t, double *s, double *invr, double *p)
95 {
96  int i, j, k;
97  double dstar_so = theta_so * dfree;
98  double dstar_sp = theta_sp * dfree;
99  double dstar_sr = theta_sr * dfree;
100  double const_so1 = dstar_so * dt / SQR(dr);
101  double const_so2 = dstar_so * dt / (2.0 * dr);
102  double const_sp1 = dstar_sp * dt / SQR(dr);
103  double const_sp2 = dstar_sp * dt / (2.0 * dr);
104  double const_sr1 = dstar_sr * dt / SQR(dr);
105  double const_sr2 = dstar_sr * dt / (2.0 * dr);
106 
107  /* Arrays internal to this function */
108  double *c; /* concentration */
109  double *c_sr; /* concentration (SR layer) */
110  double *c_sp; /* concentration (SP layer)*/
111  double *c_so; /* concentration (SO layer)*/
112  double *cb_sr; /* Average of rows at SR layer boundary */
113  double *cb_so; /* Average of rows at SO layer boundary */
114  double *dc; /* Change in concentration */
115  double *dc_sr;
116  double *dc_sp;
117  double *dc_so;
118 
119  /* Arrays for concentrations
120  r=0 is at c[1,*]
121  c[0,*] is for extended symmetrical values */
122  c = create_array(nz*(nr+1), "concentration");
123 
124  /* Arrays for concentration changes (d*) and for layers */
125  dc = create_array(nz*(nr+1), "dc");
126 
127  cb_sr = create_array(nr+1, "cb_sr");
128  cb_so = create_array(nr+1, "cb_so");
129 
130  c_sr = create_array((iz1+2)*(nr+1), "c_sr");
131  dc_sr = create_array((iz1+2)*(nr+1), "dc_sr");
132 
133  c_sp = create_array((iz2-iz1+2)*(nr+1), "c_sp");
134  dc_sp = create_array((iz2-iz1+2)*(nr+1), "dc_sp");
135 
136  c_so = create_array((nz-iz2)*(nr+1), "c_so");
137  dc_so = create_array((nz-iz2)*(nr+1), "dc_so");
138 
139 
140  /* Initialize the concentration at t=0 */
141  for (i=0; i<nz*(nr+1); i++)
142  c[i] = s[i];
143 
144  /* Source delay: Concentration = 0 for sd seconds */
145  int nds = lround(sd/dt);
146  if (nds >= nt)
147  error("nds=%d, nt=%d. Delay start should be < total expt time",
148  nds, nt);
149  for (k=0; k<nds; k++)
150  p[k] = 0.0;
151 
152 
153  /* Loop over time */
154  for (k=nds; k<nt; k++) {
155  p[k] = c[INDEX(iprobe,jprobe)]; /* record c at time t[k] */
156 
157  /* Calculate c at time t[k+1] = t[k] + dt */
158  if (nolayer == FALSE) { /* 3-layer model */
159  /*
160  * The SR/SP/SO arrays extend in z one more row
161  * to include extrapolated boundary values (the true
162  * boundary is right in the middle of node positions)
163  */
164  for (j=0; j<nr+1; j++) {
165  cb_sr[j] = ( dstar_sr * alpha_sr * c[INDEX(iz1,j)]
166  + dstar_sp * alpha_sp * c[INDEX(iz1+1,j)] )
167  / ( dstar_sr * alpha_sr + dstar_sp * alpha_sp );
168 
169  cb_so[j] = ( dstar_sp * alpha_sp * c[INDEX(iz2,j)]
170  + dstar_so * alpha_so * c[INDEX(iz2+1,j)] )
171  / ( dstar_sp * alpha_sp + dstar_so * alpha_so );
172  }
173 
174  for (j=0; j<nr+1; j++) {
175  for (i=0; i<iz1+1; i++)
176  c_sr[INDEX(i,j)] = c[INDEX(i,j)];
177  c_sr[INDEX(iz1+1,j)] = 2.0 * cb_sr[j] - c[INDEX(iz1,j)];
178 
179  c_sp[INDEX(0,j)] = 2.0 * cb_sr[j] - c[INDEX(iz1+1,j)];
180  for (i=iz1+1; i<iz2+1; i++)
181  c_sp[INDEX(i-iz1,j)] = c[INDEX(i,j)];
182  c_sp[INDEX(iz2-iz1+1,j)] = 2.0 * cb_so[j] - c[INDEX(iz2,j)];
183 
184  c_so[INDEX(0,j)] = 2.0 * cb_so[j] - c[INDEX(iz2+1,j)];
185  for (i=iz2+1; i<nz; i++)
186  c_so[INDEX(i-iz2,j)] = c[INDEX(i,j)];
187  }
188 
189  /* Calculate the delta-c matrices */
190  convolve3(iz1+2, nr+1, c_sr, const_sr1, const_sr2, invr, dc_sr);
191 
192  convolve3(iz2-iz1+2, nr+1, c_sp, const_sp1, const_sp2, invr,
193  dc_sp);
194  convolve3(nz-iz2, nr+1, c_so, const_so1, const_so2, invr, dc_so);
195 
196  /* Update the concentration matrix */
197  for (j=0; j<nr+1; j++) {
198  for (i=0; i<iz1+1; i++)
199  c[INDEX(i,j)] = c_sr[INDEX(i,j)]
200  + dc_sr[INDEX(i,j)];
201 
202  for (i=iz1+1; i<iz2+1; i++)
203  c[INDEX(i,j)] = c_sp[INDEX(i-iz1,j)]
204  + dc_sp[INDEX(i-iz1,j)];
205 
206  for (i=iz2+1; i<nz; i++)
207  c[INDEX(i,j)] = c_so[INDEX(i-iz2,j)]
208  + dc_so[INDEX(i-iz2,j)];
209  }
210 
211  } else { /* 1-layer model */
212  /* Print a warning to the user */
213  if (k==0) printf("\nNOTE: nolayer = %d, "
214  "so using the 1 layer model\n\n", nolayer);
215 
216  /* Calculate the delta-c matrix */
217  convolve3(nz, nr+1, c, const_sr1, const_sr2, invr, dc);
218 
219  /* Update the concentration matrix */
220  for (i=0; i<nz*(nr+1); i++)
221  c[i] += dc[i];
222 
223  }
224 
225 
226  /* If t < st, the source gets added to the concentration matrix
227  for the next time-step */
228  if (t[k] + dt/2.0 < sd + st) {
229  for (i=0; i<nz*(nr+1); i++)
230  c[i] += s[i];
231  }
232 
233  /* Model the non-specific clearance */
234  for (j=0; j<nr+1; j++) {
235  for (i=0; i<iz1+1; i++)
236  c[INDEX(i,j)] *= (1. - kappa_sr * dt);
237  for (i=iz1+1; i<iz2+1; i++)
238  c[INDEX(i,j)] *= (1. - kappa_sp * dt);
239  for (i=iz2+1; i<nz; i++)
240  c[INDEX(i,j)] *= (1. - kappa_so * dt);
241  }
242 
243  /* Set the i=0 row to be the same as the i=2 row
244  (symmetry about r=0 (i=1)) */
245  for (i=0; i<nz; i++)
246  c[INDEX(i,0)] = c[INDEX(i,2)];
247 
248  } /* End of k for loop */
249 
250 
251  /* Deallocate arrays */
252  free(c);
253  free(dc);
254  free(cb_sr);
255  free(cb_so);
256  free(c_sr);
257  free(c_sp);
258  free(c_so);
259  free(dc_sr);
260  free(dc_sp);
261  free(dc_so);
262 
263  return;
264 }
#define SQR(x)
Computes the square of x.
Definition: header.h:88
void calc_diffusion_curve_layer_fit_layer(int nt, int nz, int nr, int iprobe, int jprobe, int iz1, int iz2, int nolayer, double dt, double dr, double sd, double st, double alpha_so, double theta_so, double kappa_so, double alpha_sp, double theta_sp, double kappa_sp, double alpha_sr, double theta_sr, double kappa_sr, double dfree, double *t, double *s, double *invr, double *p)
Calculates the concentration as a function of space and time and returns the probe concentration as a...
Definition: model.c:94
Header file for program fit-layer.
void error(char *errorstring,...)
Print an error message to stderr and exit with status EXIT_FAILURE.
Definition: extras.c:20
double * create_array(int N, char *string)
Create an array of doubles of the specified size.
Definition: extras.c:105
#define INDEX(i, j)
Computes the 1D index for concentration or alpha arrays, given pseudo-2D indices i (z index) and j (r...
Definition: header.h:112
void convolve3(int M, int N, double *a, double scale1, double scale2, double *invr, double *out)
Calculates updates to the concentration in a layer by applying the Laplacian in cylindrical coordinat...
Definition: convo.c:133
#define FALSE
FALSE assigned to 0.
Definition: header.h:43