Layers
Diffusion in heterogeneous environments
model.c
Go to the documentation of this file.
1 
24 #include "header.h"
25 
101 void calc_diffusion_curve_layer(int nt, int nz, int nr, int iprobe, int jprobe, int iz1, int iz2, int nolayer, double dt, double dr, double sdelay, double sduration, 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, char *imagebasename, double image_spacing, double *p)
102 {
103  int i, j, k;
104  double dstar_so = theta_so * dfree;
105  double dstar_sp = theta_sp * dfree;
106  double dstar_sr = theta_sr * dfree;
107  double const_so1 = dstar_so * dt / SQR(dr);
108  double const_so2 = dstar_so * dt / (2.0 * dr);
109  double const_sp1 = dstar_sp * dt / SQR(dr);
110  double const_sp2 = dstar_sp * dt / (2.0 * dr);
111  double const_sr1 = dstar_sr * dt / SQR(dr);
112  double const_sr2 = dstar_sr * dt / (2.0 * dr);
113 
114  /* Arrays internal to this function */
115  double *c; /* concentration */
116  double *c_sr; /* concentration (SR layer) */
117  double *c_sp; /* concentration (SP layer)*/
118  double *c_so; /* concentration (SO layer)*/
119  double *cb_sr; /* Average of rows at SR layer boundary */
120  double *cb_so; /* Average of rows at SO layer boundary */
121  double *dc; /* Change in concentration */
122  double *dc_sr;
123  double *dc_sp;
124  double *dc_so;
125 
126  /* For optional output of concentration images */
127  double conc;
128  double conc_min;
129  double conc_max;
130  int image_counter; /* Count of image to output */
131  float time; /* Time rel. to start of source */
132  char imagefilename[FILENAME_MAX]; /* Name of output image file */
133  memset(imagefilename, '\0', FILENAME_MAX);
134  FILE *image_file_ptr = NULL; /* File pointer for images */
135  char timestring[20];
136  memset(timestring, '\0', 20);
137  char infofilename[FILENAME_MAX]; /* Name of image info file */
138  memset(infofilename, '\0', FILENAME_MAX);
139  FILE *info_file_ptr = NULL; /* File pointer for image info file */
140  double *conc_out = NULL; /* Concentration image to output */
141 
142  /* Arrays for concentrations
143  r=0 is at c[1,*]
144  c[0,*] is for extended symmetrical values */
145  c = create_array(nz*(nr+1), "concentration");
146 
147 
148  /* Arrays for concentration changes (d*) and for layers */
149  dc = create_array(nz*(nr+1), "dc");
150 
151  cb_sr = create_array(nr+1, "cb_sr");
152  cb_so = create_array(nr+1, "cb_so");
153 
154  c_sr = create_array((iz1+2)*(nr+1), "c_sr");
155  dc_sr = create_array((iz1+2)*(nr+1), "dc_sr");
156 
157  c_sp = create_array((iz2-iz1+2)*(nr+1), "c_sp");
158  dc_sp = create_array((iz2-iz1+2)*(nr+1), "dc_sp");
159 
160  c_so = create_array((nz-iz2)*(nr+1), "c_so");
161  dc_so = create_array((nz-iz2)*(nr+1), "dc_so");
162 
163  /* Initialize the concentration at t=0 */
164  for (i=0; i<nz*(nr+1); i++)
165  c[i] = s[i];
166 
167  /* Source delay: Concentration = 0 for sdelay seconds */
168  int nds = lround(sdelay/dt);
169  if (nds >= nt)
170  error("nds=%d, nt=%d. Delay start should be < total expt time",
171  nds, nt);
172  for (k=0; k<nds; k++)
173  p[k] = 0.0;
174 
175  /* Optional concentration output images */
176  image_counter = 0; /* Initialize counter */
177  if (image_spacing > 0.) { /* Create concentration array to output */
178  conc_out = create_array(nz*(2*nr-1), "output concentration");
179  for (i=0; i<nz*(2*nr-1); i++)
180  conc_out[i] = 0.;
181 
182  /* Generate the filename of the image info output file */
183  snprintf(infofilename, sizeof(infofilename),
184  "%s.info.txt", imagebasename);
185 
186  /* Write image information to file */
187  if ((info_file_ptr = fopen(infofilename,"w")) == NULL)
188  error("Error opening image info output file %s\n",
189  infofilename);
190 
191  fprintf(info_file_ptr, "Information about the images:\n"
192  "\tImage dimensions: %d x %d\n"
193  "\tPixels are 64-bit floating point (doubles)\n",
194  (2*nr-1), nz);
195 
196  fclose(info_file_ptr);
197  }
198 
199  /* Loop over time */
200  for (k=nds; k<nt; k++) {
201  if (image_spacing > 0.) { /* Output conc images unless sp < 0 */
202  time = (k - nds) * dt; /* Time relative to start of source */
203  /* If it's time to output the next image, do it */
204  if (time >= image_counter * image_spacing) {
205  /* Create a string with the time in ms */
206  snprintf(timestring, sizeof(timestring), "%ld",
207  (lround) (time * 1000.));
208  /* Generate the filename, including the time string */
209  snprintf(imagefilename, sizeof(imagefilename),
210  "%s.%sms.raw", imagebasename, timestring);
211 
212  /* Write the concentration image (binary, double prec.) */
213  if ((image_file_ptr = fopen(imagefilename,"w")) == NULL)
214  error("Error opening concentration image file %s\n",
215  imagefilename);
216 
217  /* The concentrations are in the c array, which is in
218  cylindrical coordinates with 0 < r < rmax (roughly).
219  Copy them to the conc_out array for writing images.
220  The conc_out array has -rmax < r < rmax. Since the
221  source is on the z-axis, images are symmetric L-R.
222  Find and print out the min and max pixel values. */
223  conc_max = c[0];
224  conc_min = c[0];
225  for (j=0; j<nr+1; j++) {
226  for (i=0; i<nz; i++) {
227  conc = c[INDEX(i,j)];
228  conc_min = MIN(conc,conc_min);
229  conc_max = MAX(conc,conc_max);
230  conc_out[INDEX_FULL_P(i,j)] = c[INDEX(i,j)];
231  conc_out[INDEX_FULL_N(i,j)] = c[INDEX(i,j)];
232  }
233  }
234 
235  /* Write concentration image to file.
236  If the number of items written is 0, warn the user;
237  don't abort, because the normal output file might
238  still get written. (For example, the user might
239  have specified that the images get written to
240  some location that the program can't write to
241  because of space limitations; the normal output
242  file might fit or might be going somewhere else.) */
243  if (fwrite(conc_out, sizeof(double), nz*(2*nr-1),
244  image_file_ptr) == 0) {
245  printf("3layer: WARNING: Output image file %s "
246  "not written\n", imagefilename);
247  }
248 
249  fclose(image_file_ptr);
250 
251  /* Generate the filename of the image info output file */
252  snprintf(infofilename, sizeof(infofilename),
253  "%s.info.txt", imagebasename);
254 
255  /* Write image information to file */
256  if ((info_file_ptr = fopen(infofilename,"a")) == NULL)
257  error("Error opening image info output file %s\n",
258  infofilename);
259 
260  fprintf(info_file_ptr,
261  "Image file #%d: %s: max = %lf, min = %lf\n",
262  image_counter, imagefilename, conc_max, conc_min);
263 
264  fclose(info_file_ptr);
265 
266  image_counter++ ;
267  }
268  }
269 
270  p[k] = c[INDEX(iprobe,jprobe)]; /* record c at time t[k] */
271 
272  /* Calculate c at time t[k+1] = t[k] + dt */
273  if (nolayer == FALSE) { /* 3-layer model */
274  /*
275  * The SR/SP/SO arrays extend in z one more row
276  * to include extrapolated boundary values (the true
277  * boundary is right in the middle of node positions)
278  */
279  for (j=0; j<nr+1; j++) {
280  cb_sr[j] = ( dstar_sr * alpha_sr * c[INDEX(iz1,j)]
281  + dstar_sp * alpha_sp * c[INDEX(iz1+1,j)] )
282  / ( dstar_sr * alpha_sr + dstar_sp * alpha_sp );
283 
284  cb_so[j] = ( dstar_sp * alpha_sp * c[INDEX(iz2,j)]
285  + dstar_so * alpha_so * c[INDEX(iz2+1,j)] )
286  / ( dstar_sp * alpha_sp + dstar_so * alpha_so );
287  }
288 
289  for (j=0; j<nr+1; j++) {
290  for (i=0; i<iz1+1; i++)
291  c_sr[INDEX(i,j)] = c[INDEX(i,j)];
292  c_sr[INDEX(iz1+1,j)] = 2.0 * cb_sr[j] - c[INDEX(iz1,j)];
293 
294  c_sp[INDEX(0,j)] = 2.0 * cb_sr[j] - c[INDEX(iz1+1,j)];
295  for (i=iz1+1; i<iz2+1; i++)
296  c_sp[INDEX(i-iz1,j)] = c[INDEX(i,j)];
297  c_sp[INDEX(iz2-iz1+1,j)] = 2.0 * cb_so[j] - c[INDEX(iz2,j)];
298 
299  c_so[INDEX(0,j)] = 2.0 * cb_so[j] - c[INDEX(iz2+1,j)];
300  for (i=iz2+1; i<nz; i++)
301  c_so[INDEX(i-iz2,j)] = c[INDEX(i,j)];
302  }
303 
304  /* Calculate the delta-c matrices */
305  convolve3(iz1+2, nr+1, c_sr, const_sr1, const_sr2, invr, dc_sr);
306 
307  convolve3(iz2-iz1+2, nr+1, c_sp, const_sp1, const_sp2, invr,
308  dc_sp);
309  convolve3(nz-iz2, nr+1, c_so, const_so1, const_so2, invr, dc_so);
310 
311  /* Update the concentration matrix */
312  for (j=0; j<nr+1; j++) {
313  for (i=0; i<iz1+1; i++)
314  c[INDEX(i,j)] = c_sr[INDEX(i,j)]
315  + dc_sr[INDEX(i,j)];
316 
317  for (i=iz1+1; i<iz2+1; i++)
318  c[INDEX(i,j)] = c_sp[INDEX(i-iz1,j)]
319  + dc_sp[INDEX(i-iz1,j)];
320 
321  for (i=iz2+1; i<nz; i++)
322  c[INDEX(i,j)] = c_so[INDEX(i-iz2,j)]
323  + dc_so[INDEX(i-iz2,j)];
324  }
325 
326  } else { /* 1-layer model */
327  /* Print a warning to the user */
328  if (k==0) printf("\nNOTE: nolayer = %d, "
329  "so using the 1 layer model\n\n", nolayer);
330 
331  /* Calculate the delta-c matrix */
332  convolve3(nz, nr+1, c, const_sr1, const_sr2, invr, dc);
333 
334  /* Update the concentration matrix */
335  for (i=0; i<nz*(nr+1); i++)
336  c[i] += dc[i];
337 
338  }
339 
340 
341  /* If t < sduration, the source gets added to the
342  concentration matrix for the next time-step */
343  if (t[k] + dt/2.0 < sdelay + sduration) {
344  for (i=0; i<nz*(nr+1); i++)
345  c[i] += s[i];
346  }
347 
348  /* Model the non-specific clearance */
349  for (j=0; j<nr+1; j++) {
350  for (i=0; i<iz1+1; i++)
351  c[INDEX(i,j)] *= (1. - kappa_sr * dt);
352  for (i=iz1+1; i<iz2+1; i++)
353  c[INDEX(i,j)] *= (1. - kappa_sp * dt);
354  for (i=iz2+1; i<nz; i++)
355  c[INDEX(i,j)] *= (1. - kappa_so * dt);
356  }
357 
358  /* Set the i=0 row to be the same as the i=2 row
359  (symmetry about r=0 (i=1)) */
360  for (i=0; i<nz; i++)
361  c[INDEX(i,0)] = c[INDEX(i,2)];
362 
363  } /* End of k for loop */
364 
365 
366  /* Deallocate arrays */
367  free(c);
368  free(dc);
369  free(cb_sr);
370  free(cb_so);
371  free(c_sr);
372  free(c_sp);
373  free(c_so);
374  free(dc_sr);
375  free(dc_sp);
376  free(dc_so);
377  if (image_spacing > 0.)
378  free(conc_out);
379 
380  return;
381 }
#define MAX(x, y)
Computes the maximum of x and y.
Definition: header.h:94
#define SQR(x)
Computes the square of x.
Definition: header.h:88
Header file for program 3layer.
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 MIN(x, y)
Computes the minimum of x and y.
Definition: header.h:100
void calc_diffusion_curve_layer(int nt, int nz, int nr, int iprobe, int jprobe, int iz1, int iz2, int nolayer, double dt, double dr, double sdelay, double sduration, 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, char *imagebasename, double image_spacing, double *p)
Calculates the concentration as a function of space and time and returns the probe concentration as a...
Definition: model.c:101
#define INDEX_FULL_P(i, j)
Computes the 1D index for r >= 0 part of a concentration image, given pseudo-2D indices i (z index) a...
Definition: header.h:127
#define FALSE
FALSE assigned to 0.
Definition: header.h:43
#define INDEX_FULL_N(i, j)
Computes the 1D index for r >= 0 part of a concentration image, given pseudo-2D indices i (z index) a...
Definition: header.h:133