Layers
Diffusion in heterogeneous environments
3layer.c
Go to the documentation of this file.
1 
41 // includes
42 #include "header.h"
43 
44 
46 int main(int argc, char *argv[])
47 {
48  /* Input parameters */
49  int opt = -1;
50  int opt_index = -1;
51  int opt_help = FALSE;
52  int opt_verbose = FALSE;
53  int opt_pathfile = FALSE;
54  int num_args_left = -1;
55  FILE *file_ptr = NULL;
56  FILE *pathfile_ptr = NULL;
57  char basename[FILENAME_MAX];
58  memset(basename, '\0', FILENAME_MAX);
59  char infilename[FILENAME_MAX];
60  memset(infilename, '\0', FILENAME_MAX);
61  char outfilename[FILENAME_MAX];
62  memset(outfilename, '\0', FILENAME_MAX);
63  char pathfilename[FILENAME_MAX];
64  memset(pathfilename, '\0', FILENAME_MAX);
65  char string[MAX_LINELENGTH];
66  memset(string, '\0', MAX_LINELENGTH);
67  char parameter[MAX_LINELENGTH];
68  memset(parameter, '\0', MAX_LINELENGTH);
69  char value[MAX_LINELENGTH];
70  memset(value, '\0', MAX_LINELENGTH);
71  char junk_char = '\0';
72  int i, j, k;
73  i = j = k = -1;
74  int linelength = -1;
75 
76  time_t start_time = -1;
77  time_t end_time = -1;
78  double total_time = -1.;
79  double program_version = 0.2;
80 
81  /* struct for holding comments from the input parameter file */
82  struct {
83  int n;
85  char command[MAX_COMMAND_LENGTH];
86  } comments;
87  comments.n = 0;
88  memset(comments.command, '\0', MAX_COMMAND_LENGTH);
89 
90  /* Geometry */
91  double rmax = 1000.0e-6; /* m */
92  double zmax = 2000.0e-6; /* m */
93  int specified_zmax = FALSE;
94  double lz1 = -1.; /* Default depends on zmax */
95  int specified_lz1 = FALSE;
96  double lz2 = -1.; /* Default depends on zmax */
97  int specified_lz2 = FALSE;
98  int iz1 = -1;
99  int iz2 = -1;
100  int nolayer = FALSE; /* layer flag (simplifies numerical
101  calculation of a homogeneous case) */
102  double ez1 = -1.; /* Location of lower edge of cylinder */
103  int specified_ez1 = FALSE;
104  double ez2 = -1.; /* Location of upper edge of cylinder */
105  int specified_ez2 = FALSE;
106 
107  /* Discretization steps in r, z, and t */
108  int nr = 500;
109  int nz = 1000;
110  int nt = -1; /* Default determined from von Neumann
111  stability criterion */
112  int specified_nt = FALSE;
113  double nt_scale = -1.;
114  int specified_nt_scale = FALSE;
115  int ns = -1;
116  int nds = -1; /* Number of points in delay period before source */
117  double dr = -1.;
118  double dz = -1.;
119  double dt = -1.;
120 
121  /* Source */
122  double trn = 0.35;
123  double crnt = 80.0e-9; /* A */
124  double samplitude = -1.;
125  double tmax = 150.0; /* s */
126  double sdelay = 10.0; /* s */
127  double sduration = 50.0; /* s */
128  double sr = 0.0; /* Source defines origin in this program */
129  double sz = -1.; /* Default depends on zmax */
130  int isource, jsource;
131  isource = jsource = -1;
132 
133  /* Probe */
134  double pr = 0.0; /* m */
135  double pz = -1.; /* Default depends on sz */
136  int specified_pz = FALSE;
137  int iprobe, jprobe;
138  iprobe = jprobe = -1;
139 
140  /* ECS parameters -- got defaults from paper -- p. 12 and Table 1
141  of manuscript submitted in summer 2011 */
142  int opt_global_kappa = FALSE;
143  double alpha_so = 0.218;
144  double theta_so = 0.447;
145  double kappa_so = 0.0;
146  double alpha_sp = 0.2;
147  double theta_sp = 0.4;
148  double kappa_sp = 0.0;
149  double alpha_sr = 0.218;
150  double theta_sr = 0.447;
151  double kappa_sr = 0.0;
152  double kappa_outside = 0.0;
153  int specified_kappa_outside = FALSE;
154  double dstar_so, dstar_sp, dstar_sr, dstar_max;
155  dstar_so = dstar_sp = dstar_sr = dstar_max = -1.;
156 
157  double dfree = 1.24e-09;
158 
159  /* Arrays */
160  double *t = NULL; /* time */
161  double *s = NULL; /* source */
162  double *p = NULL; /* probe (calculated) */
163  double *alphas = NULL; /* alpha */
164  double *invr = NULL; /* 1/r */
165 
166  /* Parameters for output files */
167  int opt_output_conc_image = FALSE;
168  double image_spacing = 1.;
169  char imagebasename[FILENAME_MAX-32];
170  memset(imagebasename, '\0', FILENAME_MAX-32);
171 
172  /* Parameters for additional sources */
173  int nsource;
174  char *token;
175  char additional_sources_string[ADDITIONAL_SOURCES_STRING_LENGTH];
176  memset(additional_sources_string, '\0', ADDITIONAL_SOURCES_STRING_LENGTH);
177  more_sources_struct_type more_sources;
178  more_sources.n = 0;
179  more_sources.source = NULL;
180  source_struct_type new_source;
181 
182  /* Parameters to send to calc_mse_rti */
183  double spdist = -1.;
184 
185  mse_rti_params_struct_type mse_rti_params;
186 
187  mse_rti_params.nt = -1;
188  mse_rti_params.spdist = -1.;
189  mse_rti_params.samplitude = -1.;
190  mse_rti_params.sdelay = -1.;
191  mse_rti_params.sduration = -1.;
192  mse_rti_params.kappa = -1.;
193  mse_rti_params.dfree = -1.;
194  mse_rti_params.alpha = -1.;
195  mse_rti_params.theta = -1.;
196 
197  mse_rti_params.t = NULL;
198  mse_rti_params.p_model = NULL;
199  mse_rti_params.p_theory = NULL;
200 
201 
202  /* Parameters for curve fitting */
203  double alpha_start = 0.2; /* Sarting value for theoretical fit */
204  double theta_start = 0.4; /* Sarting value for theoretical fit */
205  double alpha_fit = -1.;
206  double theta_fit = -1.;
207  double mse = -1.;
208  gsl_vector *steps = NULL;
209  gsl_vector *simplex = NULL;
210  double alpha_step = 0.1;
211  double theta_step = 0.2;
212  const gsl_multimin_fminimizer_type *fit_algorithm =
213  gsl_multimin_fminimizer_nmsimplex;
214  gsl_multimin_fminimizer *fit_state = NULL;
215  gsl_multimin_function fit_func;
216  size_t fit_iter = 0;
217  int itermax = 100;
218  int fit_status = -1;
219  double fit_size = -1.;
220  double fit_tol = 1.e-4;
221 
222 
223  /* Get start time of program */
224  start_time = time(NULL);
225 
226  /* If no arguments are given, or if there is on argument
227  beginning with - (like -h), print the usage statement
228  ((argc == 2) &&(argv[argc-1][0] == '-')))
229 Note: Previously it parsed the command line and then the input file.
230 It used the last argument as the name of the input file.
231 Now it parses the input file first, because that makes it easy for
232 the command-line parameters to override the parameters in the input
233 file (the desired behavior). But now it doesn't handle options that
234 come after the input filename.
235 Currently it just checks if the first character of the last arg is -
236 */
237  if ((argc < 2) || (argv[argc-1][0] == '-'))
238  print_usage(argv[0]);
239 
240 /*
241  * Read the parameters and the data from the input file
242  */
243 
244  /* Get the names of the input and output files from the last
245  argument on the command line. (The output filename determined
246  here can be overridden with a command line argument.) */
247  get_io_filenames(argv[argc-1], ".par", ".dat", infilename, outfilename);
248 
249  /* Open file */
250  if ((file_ptr = fopen(infilename,"r")) == NULL) {
251  fprintf(stderr, "Error opening input file %s\n", infilename);
252  exit(EXIT_FAILURE);
253  }
254 
255  /* Read input parameter file and parse the parameters */
256  comments.n = 0; /* counter for the comment lines in the parameter file */
257  for (i=0; i<MAXNUM_LINES; i++) {
258  if (fgets(string,MAX_LINELENGTH,file_ptr) == NULL)
259  break; /* Assume that EOF was found, rather than an error */
260 
261  /* If the line that was read into 'string' was not EOF
262  and there was no error, continue; get length of 'string' */
263  linelength = strlen(string);
264 
265  /* If the line starts with '#', it's a comment;
266  copy the comment, but don't parse it */
267  if (string[0] == '#') {
268  if (comments.n > MAXNUM_COMMENTLINES)
269  fprintf(stderr, "Warning: Maximum # of comment lines "
270  "exceeded.\nWill not copy more comment lines to "
271  "the output file.\n");
272  else
273  strcpy(comments.line[comments.n], string);
274  comments.n++;
275  /* If the line is 1 character long, stop reading header */
276  } else if (linelength < 3) {
277  break;
278  /* If the line is too long, just skip it */
279  } else if (linelength >= MAX_LINELENGTH-1) {
280  fprintf(stderr, "Warning: Line %d seems to be too long\n", i+1);
281  /* Put a null character at end of string and feel good */
282  string[MAX_LINELENGTH-1] = '\0';
283  /* Ignore the rest of the line */
284  if (fscanf(file_ptr, "%*[^\n] %[\n]", &junk_char) == EOF)
285  error("fscanf returned EOF");
286  /* Read parameters */
287  } else {
288  if (sscanf(string, "%s = %s", parameter, value) == EOF)
289  error("scanf returned EOF");
290  if (STREQ(parameter, "dfree")) {
291  dfree = atof(value);
292  /* Normally dfree = 1.24e-9 or so. However, in some
293  parameter files dfree might be read as 1.24 instead
294  (e.g. if the parameter file has 1.24e_09, or if
295  the user just inputs 1.24). So if the value for
296  dfree is unrealistically high, assume that it
297  needs to be multiplied by 1e-9. */
298  if (dfree > 0.01) dfree *= 1e-9;
299  }
300  if (STREQ(parameter, "trn")) trn = atof(value);
301  if (STREQ(parameter, "current")) {
302  crnt = atof(value);
303  crnt *= 1e-9; /* Input in nA; convert to A */
304  }
305  if (STREQ(parameter, "delay")) sdelay = atof(value);
306  if (STREQ(parameter, "duration")) sduration = atof(value);
307  if (STREQ(parameter, "source_z")) {
308  sz = atof(value);
309  /* sz *= 1e-6; */ /* Input in microns; convert to m */
310  if (! IS_ZERO(sz)) /* The source location should be 0. */
311  error("source_z = %f microns but should be 0 "
312  "(or not specified in the output file)", sz);
313  }
314  if (STREQ(parameter, "probe_z")) {
315  pz = atof(value);
316  specified_pz = TRUE;
317  pz *= 1e-6; /* Input in microns; convert to m */
318  }
319  if (STREQ(parameter, "probe_r")) {
320  pr = atof(value);
321  pr *= 1e-6; /* Input in microns; convert to m */
322  }
323  if (STREQ(parameter, "nolayer")) nolayer = atoi(value);
324  if (STREQ(parameter, "lz1")) {
325  lz1 = atof(value);
326  specified_lz1 = TRUE;
327  lz1 *= 1e-6; /* Input in microns; convert to m */
328  }
329  if (STREQ(parameter, "lz2")) {
330  lz2 = atof(value);
331  specified_lz2 = TRUE;
332  lz2 *= 1e-6; /* Input in microns; convert to m */
333  }
334  if (STREQ(parameter, "ez1")) {
335  ez1 = atof(value);
336  specified_ez1 = TRUE;
337  ez1 *= 1e-6; /* Input in microns; convert to m */
338  }
339  if (STREQ(parameter, "ez2")) {
340  ez2 = atof(value);
341  specified_ez2 = TRUE;
342  ez2 *= 1e-6; /* Input in microns; convert to m */
343  }
344  if (STREQ(parameter, "alpha_so")) alpha_so = atof(value);
345  if (STREQ(parameter, "alpha_sp")) alpha_sp = atof(value);
346  if (STREQ(parameter, "alpha_sr")) alpha_sr = atof(value);
347  if (STREQ(parameter, "theta_so")) theta_so = atof(value);
348  if (STREQ(parameter, "theta_sp")) theta_sp = atof(value);
349  if (STREQ(parameter, "theta_sr")) theta_sr = atof(value);
350  if (STREQ(parameter, "kappa_so")) kappa_so = atof(value);
351  if (STREQ(parameter, "kappa_sp")) kappa_sp = atof(value);
352  if (STREQ(parameter, "kappa_sr")) kappa_sr = atof(value);
353  if (STREQ(parameter, "nt")) {
354  nt = atoi(value);
355  specified_nt = TRUE;
356  }
357  if (STREQ(parameter, "nt_scale")) {
358  nt_scale = atof(value);
359  specified_nt_scale = TRUE;
360  }
361  if (STREQ(parameter, "nr")) nr = atoi(value);
362  if (STREQ(parameter, "nz")) nz = atoi(value);
363  if (STREQ(parameter, "rmax")) {
364  rmax = atof(value);
365  rmax *= 1e-6; /* Input in microns; convert to m */
366  }
367  if (STREQ(parameter, "zmax")) {
368  zmax = atof(value);
369  zmax *= 1e-6; /* Input in microns; convert to m */
370  specified_zmax = TRUE;
371  }
372  if (STREQ(parameter, "tmax")) tmax = atof(value);
373  }
374  }
375 
376 
377  /* Close the file */
378  fclose(file_ptr);
379 
380 
381 /*
382  * Parse the command line options
383  */
384  static struct option long_opts[] = {
385  {"help", no_argument, NULL, 'h'},
386  {"verbose", no_argument, NULL, 'v'},
387  {"global_kappa", no_argument, NULL, 'g'},
388  {"nr", required_argument, NULL, 0},
389  {"nz", required_argument, NULL, 0},
390  {"nt", required_argument, NULL, 0},
391  {"nt_scale", required_argument, NULL, 0},
392  {"probe_z", required_argument, NULL, 0},
393  {"probe_r", required_argument, NULL, 0},
394  {"ez1", required_argument, NULL, 0},
395  {"ez2", required_argument, NULL, 0},
396  {"alpha_so", required_argument, NULL, 0},
397  {"alpha_sp", required_argument, NULL, 0},
398  {"alpha_sr", required_argument, NULL, 0},
399  {"theta_so", required_argument, NULL, 0},
400  {"theta_sp", required_argument, NULL, 0},
401  {"theta_sr", required_argument, NULL, 0},
402  {"kappa_so", required_argument, NULL, 0},
403  {"kappa_sp", required_argument, NULL, 0},
404  {"kappa_sr", required_argument, NULL, 0},
405  {"kappa_outside", required_argument, NULL, 0},
406  {"alpha_start", required_argument, NULL, 0},
407  {"theta_start", required_argument, NULL, 0},
408  {"alpha_step", required_argument, NULL, 0},
409  {"theta_step", required_argument, NULL, 0},
410  {"tmax", required_argument, NULL, 0},
411  {"fit_tol", required_argument, NULL, 0},
412  {"itermax", required_argument, NULL, 0},
413  {"outfile", required_argument, NULL, 0},
414  {"pathfile", required_argument, NULL, 0},
415  {"images", required_argument, NULL, 0},
416  {"image_spacing", required_argument, NULL, 0},
417  {"additional_sources", required_argument, NULL, 0},
418  {NULL, no_argument, NULL, 0}
419  };
420 
421  while ((opt = getopt_long(argc, argv, "hvg",
422  long_opts, &opt_index)) != -1) {
423  switch (opt) {
424 
425  case 'h': /* user needs help -- print usage */
426  opt_help = TRUE;
427  break;
428 
429  case 'v': /* user wants verbose output */
430  opt_verbose = TRUE;
431  break;
432 
433  case 'g': /* user wants kappa to be the same in all regions */
434  opt_global_kappa = TRUE;
435  break;
436 
437  case 0: /* long option has no corresponding short option */
438  if (STREQ("nr", long_opts[opt_index].name)) {
439  nr = atoi(optarg);
440  } else if (STREQ("nz", long_opts[opt_index].name)) {
441  nz = atoi(optarg);
442  } else if (STREQ("nt", long_opts[opt_index].name)) {
443  nt = atoi(optarg);
444  specified_nt = TRUE;
445  } else if (STREQ("nt_scale", long_opts[opt_index].name)) {
446  nt_scale = atof(optarg);
447  specified_nt_scale = TRUE;
448  } else if (STREQ("probe_z", long_opts[opt_index].name)) {
449  pz = atof(optarg);
450  specified_pz = TRUE;
451  pz *= 1e-6; /* Input in microns; convert to m */
452  } else if (STREQ("probe_r", long_opts[opt_index].name)) {
453  pr = atof(optarg);
454  pr *= 1e-6; /* Input in microns; convert to m */
455  } else if (STREQ("ez1", long_opts[opt_index].name)) {
456  ez1 = atof(optarg);
457  specified_ez1 = TRUE;
458  ez1 *= 1e-6; /* Input in microns; convert to m */
459  } else if (STREQ("ez2", long_opts[opt_index].name)) {
460  ez2 = atof(optarg);
461  specified_ez2 = TRUE;
462  ez2 *= 1e-6; /* Input in microns; convert to m */
463  } else if (STREQ("alpha_so", long_opts[opt_index].name)) {
464  alpha_so = atof(optarg);
465  } else if (STREQ("alpha_sp", long_opts[opt_index].name)) {
466  alpha_sp = atof(optarg);
467  } else if (STREQ("alpha_sr", long_opts[opt_index].name)) {
468  alpha_sr = atof(optarg);
469  } else if (STREQ("theta_so", long_opts[opt_index].name)) {
470  theta_so = atof(optarg);
471  } else if (STREQ("theta_sp", long_opts[opt_index].name)) {
472  theta_sp = atof(optarg);
473  } else if (STREQ("theta_sr", long_opts[opt_index].name)) {
474  theta_sr = atof(optarg);
475  } else if (STREQ("kappa_so", long_opts[opt_index].name)) {
476  kappa_so = atof(optarg);
477  } else if (STREQ("kappa_sp", long_opts[opt_index].name)) {
478  kappa_sp = atof(optarg);
479  } else if (STREQ("kappa_sr", long_opts[opt_index].name)) {
480  kappa_sr = atof(optarg);
481  } else if (STREQ("kappa_outside", long_opts[opt_index].name)) {
482  kappa_outside = atof(optarg);
483  specified_kappa_outside = TRUE;
484  } else if (STREQ("alpha_start", long_opts[opt_index].name)) {
485  alpha_start = atof(optarg);
486  } else if (STREQ("theta_start", long_opts[opt_index].name)) {
487  theta_start = atof(optarg);
488  } else if (STREQ("alpha_step", long_opts[opt_index].name)) {
489  alpha_step = atof(optarg);
490  } else if (STREQ("theta_step", long_opts[opt_index].name)) {
491  theta_step = atof(optarg);
492  } else if (STREQ("tmax", long_opts[opt_index].name)) {
493  tmax = atof(optarg);
494  } else if (STREQ("fit_tol", long_opts[opt_index].name)) {
495  fit_tol = atof(optarg);
496  } else if (STREQ("itermax", long_opts[opt_index].name)) {
497  itermax = atoi(optarg);
498  } else if (STREQ("outfile", long_opts[opt_index].name)) {
499  get_filename(optarg, outfilename);
500  } else if (STREQ("pathfile", long_opts[opt_index].name)) {
501  get_filename(optarg, pathfilename);
502  opt_pathfile = TRUE;
503  } else if (STREQ("images", long_opts[opt_index].name)) {
504  get_filename(optarg, imagebasename);
505  opt_output_conc_image = TRUE;
506  } else if (STREQ("image_spacing", long_opts[opt_index].name)) {
507  image_spacing = atof(optarg);
508  } else if (STREQ("additional_sources", long_opts[opt_index].name)) {
509  if (strlen (optarg) < ADDITIONAL_SOURCES_STRING_LENGTH)
510  strcpy(additional_sources_string, optarg);
511  else
512  error("additional_sources_string is too long");
513 
514  token = strtok(additional_sources_string, " ,");
515  more_sources.n = atoi(token);
516 
517  if (more_sources.n > 0) {
518  more_sources.source =
520  malloc( sizeof(source_struct_type) * more_sources.n );
521  if (more_sources.source == NULL)
522  error("Cannot allocate memory for more_sources");
523  /* Read parameters for each additional source */
524  for (nsource = 0; nsource < more_sources.n; nsource++) {
525  more_sources.source[nsource].sz =
526  read_source_parameter("sz", nsource) * 1e-6;
527  more_sources.source[nsource].sr =
528  read_source_parameter("sr", nsource) * 1e-6;
529  more_sources.source[nsource].crnt =
530  read_source_parameter("crnt", nsource) * 1e-9;
531  }
532  }
533  }
534  break;
535 
536  case ':': /* missing argument for an option */
537  error("Missing argument for a command-line option '-%c'",
538  optopt);
539  break;
540 
541  case '?': /* unknown option */
542  error("Unknown command line option '-%c'", optopt);
543  break;
544 
545  default:
546  error("Problem in parsing command line options");
547  break;
548  }
549  }
550 
551 
552  /* See if any options are left */
553  num_args_left = argc - optind;
554  if ((num_args_left != 1) || opt_help)
555  print_usage(argv[0]);
556 
557 
558  if (opt_verbose) {
559  printf("The name of the input file is %s\n", infilename);
560  printf("The name of the output file will be %s\n", outfilename);
561  if (opt_pathfile)
562  printf("The name of the simplex path file will be %s\n",
563  pathfilename);
564  }
565 
566  /* Check for conflicts */
567  if (STREQ(infilename, outfilename))
568  error("The input and output filenames cannot be the same.");
569  if (STREQ(infilename, pathfilename))
570  error("The input and simplex path filenames cannot be the same.");
571  if (STREQ(outfilename, pathfilename))
572  error("The output and simplex path filenames cannot be the same.");
573 
574  if (specified_ez1 && !specified_ez2)
575  error("You specified ez1 but did not specify ez2");
576  if (specified_ez2 && !specified_ez1)
577  error("You specified ez2 but did not specify ez1");
578  if (specified_ez1 && specified_zmax)
579  error("You specified ez1 and ez2, so you should not specify zmax");
580 
581  if (specified_ez1) {
582  if (ez1 > 0) error("Bottom of cylinder ez1 = %f > 0\n", ez1);
583  if (ez2 < 0) error("Top of cylinder ez2 = %f < 0\n", ez2);
584  if (ez1 > lz1) error("Bottom of cylinder ez1 = %f > lz1 = %f\n",
585  ez1, lz1);
586  if (ez2 < lz2) error("Top of cylinder ez2 = %f < lz2 = %f\n",
587  ez2, lz2);
588  }
589 
590 
591  /* Default values of parameters that depend on zmax */
592  if (specified_pz == FALSE) {
593  pz = 120.0e-6; /* m */
594 if (opt_verbose)
595  printf("Warning: probe location set to default value of %g m = "
596  "%f microns\n (relative to source)",
597  pz, 1e6*pz);
598  }
599 
600  if (specified_lz1 == FALSE) {
601  lz1 = - 50.0e-6 / 2.0;
602 if (opt_verbose)
603  printf("Warning: lz1 set to default value of %g m = "
604  "%f microns\n (relative to source)",
605  lz1, 1e6*lz1);
606  }
607 
608  if (specified_lz2 == FALSE) {
609  lz2 = lz1 + 50.0e-6;
610 if (opt_verbose)
611  printf("Warning: lz2 set to default value of %g m = "
612  "%f microns\n (relative to source)",
613  lz2, 1e6*lz2);
614  }
615 
616 /* Set kappa in SR and SO to kappa_outside */
617  if (specified_kappa_outside) {
618  kappa_sr = kappa_outside;
619  kappa_so = kappa_outside;
620  if (opt_global_kappa) {
621  error("You've specified both global kappa and kappa_outside.\n"
622  "The global kappa option sets kappa_so and kappa_sr to kappa_sp.\n"
623  "When you specify kappa_outside, kappa_so and kappa_sr are set \n"
624  "to that value.");
625  }
626  }
627 
628 /* If nolayer option, the SR parameters are used for the whole
629  environment; the SO and SP parameters are not used. However,
630  their values are still listed in the output file. Set their
631  values equal to the SR values here so that the correct values
632  are printed to the output file. */
633 
634  if (nolayer) {
635  alpha_so = alpha_sr;
636  alpha_sp = alpha_sr;
637  theta_so = theta_sr;
638  theta_sp = theta_sr;
639  kappa_so = kappa_sr;
640  kappa_sp = kappa_sr;
641  if (opt_verbose)
642  printf("\nNOTE: nolayer option given; the diffusion "
643  "parameters of \nthe homogeneous environment "
644  "are set to the SR values\n");
645  }
646 
647 /* If using a global value for kappa, set kappa_sr=kappa_so=kappa_sp */
648  if (opt_global_kappa) {
649  kappa_sr = kappa_sp;
650  kappa_so = kappa_sp;
651  if (opt_verbose)
652  printf("NOTE: kappa will be the same in all layers (-g)\n"
653  "kappa_sr and kappa_so set to kappa_sp\n");
654  }
655 
656 /*
657  * Change coordinates. In the coordinate system used in the
658  * input file, source_z is always 0, so lz1, lz2, and pz are
659  * measured relative to the source. This was done because in
660  * the experiments distances are measured relative to the
661  * source.
662  *
663  * In the coordinate system used in the model, the bottom of
664  * the cylinder is at z=0 and the top of the cylinder is at
665  * z=zmax. The length of the cylinder is therefore zmax.
666  * So we shift the z-coordinates here.
667  *
668  * By default the z-coordinates are shifted such that the
669  * SP layer is centered in the volume, ie the midplane of SP is
670  * at z=zmax/2. However, the user might instead want to specify
671  * the location of the ends of the cylinder relative to the
672  * source (ez1 and ez2), which requires a different z-shift.
673  */
674  double coord_shift;
675 
676  if (specified_ez1) {
677  zmax = ez2 + (-ez1); /* Calculate the cylinder length */
678  coord_shift = (-ez1);
679  } else {
680  coord_shift = (zmax - (lz1+lz2))/2.;
681  }
682  sz = coord_shift;
683  pz += coord_shift;
684  lz1 += coord_shift;
685  lz2 += coord_shift;
686 
687  /* Discretization intervals in r, z */
688  dr = rmax / nr;
689  dz = zmax / nz;
690  if (fabs(dr - dz) > 1.0e-15) {
691  dr = dz;
692  rmax = dr * nr;
693  }
694 
695  sz = round(sz / dz) * dz;
696  pz = round(pz / dz) * dz;
697  pr = round(pr / dr) * dr;
698 
699  /* Layer geometry */
700  iz1 = (int) round((lz1 / dz));
701  lz1 = iz1 * dz + dz / 2.0;
702 
703  iz2 = (int) round((lz2 / dz));
704  lz2 = iz2 * dz + dz / 2.0;
705 
706 
707  /* D* */
708  dstar_so = theta_so * dfree;
709  dstar_sp = theta_sp * dfree;
710  dstar_sr = theta_sr * dfree;
711  dstar_max = MAX(dstar_so, dstar_sp);
712  dstar_max = MAX(dstar_max, dstar_sr);
713 
714 
715  /* Check if layer thickness is numerically reasonable */
716  if ( ((iz2 - iz1) < 2) && (nolayer == 0) )
717  error("Layer has too few discrete steps to continue.");
718 
719  /* Calculate time step from nt or from von Neumann criterion */
720  if (specified_nt == TRUE)
721  dt = tmax / nt;
722  else
723  dt = 0.9 * dr*dr / (6.0 * dstar_max);
724 
725  /* Scale nt if the user specified to do so -- but do it via dt */
726  if (specified_nt_scale == TRUE) {
727  if (IS_ZERO(nt_scale)) error("nt_scale = 0");
728  if (nt_scale < 0.) error("nt_scale < 0");
729  dt /= nt_scale;
730  }
731 
732  /* Round off tmax, sduration, and sdelay to multiples of dt */
733  nt = lround(tmax / dt);
734  tmax = dt * nt;
735  ns = lround(sduration / dt);
736  sduration = dt * ns;
737  nds = lround(sdelay / dt);
738  sdelay = dt * nds;
739 
740  if (sdelay >= tmax)
741  error("Source delay (%f) should be < tmax (%f)", sdelay, tmax);
742  if (sduration >= tmax)
743  error("Source duration (%f) should be < tmax (%f)", sduration, tmax);
744  if (sdelay+sduration >= tmax)
745  error("Source delay (%f) + duration (%f) should be < tmax (%f)",
746  sdelay, sduration, tmax);
747 
748 
749  /* Calculate source amplitude in mol/s from current and transport number*/
750  samplitude = crnt * trn / FARADAY; /* source strength in mol/s
751  (not a concentration) */
752 
753 
754  /* Assemble string with command that user input */
755  i = assemble_command(argc, argv, comments.command);
756  if (opt_verbose)
757  printf("\nIn main(): The command used was\n\t%s\n(%d words)\n\n",
758  comments.command, i);
759 
760 
761  /* Put start time in string */
762  strncpy(string, ctime(&start_time), MAX_LINELENGTH-1);
763 
764  /* Feedback to user to check adjusted values */
765  if (opt_verbose) {
766  printf("Output from 3layer.c, version %.1f:\n", program_version);
767  printf("Note that the z-values (sz, pz, lz1, and lz2) have been shifted \n");
768  printf("by %f microns to center the SP layer in the volume.\n",
769  1.0e6*coord_shift);
770  printf("nr x nz = %d x %d\n", nr, nz);
771  printf("rmax x zmax = %f x %f microns\n", 1.0e6 * rmax, 1.0e6 * zmax);
772  printf("dr x dz = %f x %f microns\n", 1.0e6 * dr, 1.0e6 * dz);
773  printf("(sr, sz) = (%f, %f) microns\n", 1.0e6 * sr, 1.0e6 * sz);
774  printf("(pr, pz) = (%f, %f) microns\n", 1.0e6 * pr, 1.0e6 * pz);
775  printf("Electrode distance = %f microns\n",
776  1.0e6 * sqrt(SQR(pr-sr) + SQR(pz-sz)));
777  printf("(iz1, iz2) = (%d, %d)\n", iz1, iz2);
778  printf("(lz1, lz2) = (%f, %f) microns\n", 1.0e6 * lz1, 1.0e6 * lz2);
779  printf("Layer thickness = %f microns\n", 1.0e6 * (lz2 - lz1));
780  printf("Layer discrete steps = %d\n", iz2 - iz1);
781  printf("Nolayer flag = %d\n" , nolayer);
782  printf("dfree = %g m^2/s\n", dfree);
783  printf("alpha_so = %.4f, theta_so = %.4f, "
784  "lambda_so = %.4f, kappa_so = %.6f\n",
785  alpha_so, theta_so, 1.0/sqrt(theta_so), kappa_so);
786  printf("alpha_sp = %.4f, theta_sp = %.4f, "
787  "lambda_sp = %.4f, kappa_sp = %.6f\n",
788  alpha_sp, theta_sp, 1.0/sqrt(theta_sp), kappa_sp);
789  printf("alpha_sr = %.4f, theta_sr = %.4f, "
790  "lambda_sr = %.4f, kappa_sr = %.6f\n",
791  alpha_sr, theta_sr, 1.0/sqrt(theta_sr), kappa_sr);
792  if (opt_global_kappa)
793  printf("NOTE: kappa_sr and kappa_so set to kappa_sp (-g)\n");
794  printf("nt = %d\n", nt);
795  printf("tmax = %f s\n", tmax);
796  printf("dt = %f ms\n", 1.0e3 * dt);
797  printf("von Neumann dt / (dr^2/(6*dstar)) = %f\n",
798  dt * 6.0 * dstar_max / (dr*dr));
799  printf("ns = %d\n", ns);
800  printf("source delay sdelay = %f s\n", sdelay);
801  printf("source duration sduration = %f s\n", sduration);
802  printf("Current = %g nA\n", 1.0e9 * crnt);
803  printf("Transport number = %f\n", trn);
804  printf("Start time = %s", string);
805  }
806 
807 
808  /* Open output data file */
809  if ((file_ptr = fopen(outfilename,"w")) == NULL) {
810  fprintf(stderr, "Error opening output file %s\n", outfilename);
811  exit(EXIT_FAILURE);
812  }
813 
814  /* Write out command line to output file */
815  fprintf(file_ptr, "# 3layer Output File\n");
816  fprintf(file_ptr, "# ~~~~~~~~~~~~~~~~~~\n");
817  fprintf(file_ptr, "# Command used to run program:\n");
818  fprintf(file_ptr, "# %s\n", comments.command);
819 
820  /* Write comments from input file to output file */
821  if (comments.n > 0) {
822  fprintf(file_ptr, "# --------------------------------------\n");
823  fprintf(file_ptr, "# Comments from input parameter file:\n");
824  for (j=0; j<comments.n; j++)
825  fprintf(file_ptr, "%s", comments.line[j]);
826  fprintf(file_ptr, "# --------------------------------------\n");
827  }
828 
829 
830  /* Write parameters to output file */
831  fprintf(file_ptr, "# Output from 3layer.c, version %.1f:\n", program_version);
832  fprintf(file_ptr, "# Note that the z-values (sz, pz, lz1, and lz2) ");
833  fprintf(file_ptr, "have been shifted \n# by %f microns ", 1.0e6*coord_shift);
834  if (specified_ez1) {
835  fprintf(file_ptr, "to have the volume go from z=0 to z=zmax.\n");
836  } else {
837  fprintf(file_ptr, "to center the SP layer in the volume.\n");
838  }
839  fprintf(file_ptr, "# nr x nz = %d x %d\n", nr, nz);
840  fprintf(file_ptr, "# rmax x zmax = %f x %f microns\n", 1.0e6 * rmax, 1.0e6 * zmax);
841  fprintf(file_ptr, "# dr x dz = %f x %f microns\n", 1.0e6 * dr, 1.0e6 * dz);
842  fprintf(file_ptr, "# (sr, sz) = (%f, %f) microns\n", 1.0e6 * sr, 1.0e6 * sz);
843  fprintf(file_ptr, "# (pr, pz) = (%f, %f) microns\n", 1.0e6 * pr, 1.0e6 * pz);
844  fprintf(file_ptr, "# Electrode distance = %f microns\n",
845  1.0e6 * sqrt(SQR(pr-sr) + SQR(pz-sz)));
846  fprintf(file_ptr, "# (iz1, iz2) = (%d, %d)\n", iz1, iz2);
847  fprintf(file_ptr, "# (lz1, lz2) = (%f, %f) microns\n", 1.0e6 * lz1, 1.0e6 * lz2);
848  fprintf(file_ptr, "# Layer thickness = %f microns\n", 1.0e6 * (lz2 - lz1));
849  fprintf(file_ptr, "# Layer discrete steps = %d\n", iz2 - iz1);
850  fprintf(file_ptr, "# Nolayer flag = %d\n" , nolayer);
851  fprintf(file_ptr, "# dfree = %g m^2/s\n", dfree);
852  fprintf(file_ptr, "# alpha_so = %.4f, theta_so = %.4f, "
853  "lambda_so = %.4f, kappa_so = %.6f\n",
854  alpha_so, theta_so, 1.0/sqrt(theta_so), kappa_so);
855  fprintf(file_ptr, "# alpha_sp = %.4f, theta_sp = %.4f, "
856  "lambda_sp = %.4f, kappa_sp = %.6f\n",
857  alpha_sp, theta_sp, 1.0/sqrt(theta_sp), kappa_sp);
858  fprintf(file_ptr, "# alpha_sr = %.4f, theta_sr = %.4f, "
859  "lambda_sr = %.4f, kappa_sr = %.6f\n",
860  alpha_sr, theta_sr, 1.0/sqrt(theta_sr), kappa_sr);
861  if (opt_global_kappa)
862  fprintf(file_ptr, "# NOTE: kappa_sr and kappa_so set to kappa_sp (-g)\n");
863  fprintf(file_ptr, "# nt = %d\n", nt);
864  fprintf(file_ptr, "# tmax = %f s\n", tmax);
865  fprintf(file_ptr, "# dt = %f ms\n", 1.0e3 * dt);
866  fprintf(file_ptr, "# von Neumann dt / (dr^2/(6*dstar)) = %f\n",
867  dt * 6.0 * dstar_max / (dr*dr));
868  fprintf(file_ptr, "# ns = %d\n", ns);
869  fprintf(file_ptr, "# Source delay sdelay = %f s\n", sdelay);
870  fprintf(file_ptr, "# Source duration sduration = %f s\n", sduration);
871  fprintf(file_ptr, "# Current = %g nA\n", 1.0e9 * crnt);
872  fprintf(file_ptr, "# Transport number = %f\n", trn);
873  if (more_sources.n > 0) {
874  fprintf(file_ptr, "# Number of extra sources = %d\n", more_sources.n);
875  for (nsource = 0; nsource < more_sources.n; nsource++)
876  fprintf(file_ptr, "# Additional source #%d: \n"
877  "#\tsz = %lf microns, sr = %lf microns, crnt = %lf nA\n",
878  nsource+1,
879  1.0e6 * (more_sources.source[nsource].sz + coord_shift),
880  1.0e6 * more_sources.source[nsource].sr,
881  1.0e9 * more_sources.source[nsource].crnt);
882  }
883  fprintf(file_ptr, "# Start time = %s", string); /* ctime() added the \n */
884 
885  /* Close the file */
886  fclose(file_ptr);
887 
888  /* Array of alpha values -- use 1D index to access elements of
889  the 2D array, so a[i*(nr+1)+j] = a[i][j] (use macro INDEX(i,j) */
890  alphas = create_array(nz*(nr+1), "alphas array");
891  for (j=0; j<nr+1; j++) {
892  for (i=0; i<iz1+1; i++) alphas[INDEX(i,j)] = alpha_sr;
893  for (i=iz1+1; i<iz2+1; i++) alphas[INDEX(i,j)] = alpha_sp;
894  for (i=iz2+1; i<nz; i++) alphas[INDEX(i,j)] = alpha_so;
895  }
896 
897  /* Array of 1/r values, except it is 0 for r=0 */
898  /* - in layer.pro it's a 2D array with all column identical,
899  but it doesn't have to be; I'm doing 1D (i only) */
900  invr = create_array(nr+1, "param invr array");
901  invr[0] = 1.0 / dr;
902  invr[1] = 0.0;
903  for (j=2; j<nr+1; j++) {
904  invr[j] = 1.0 / ((j-1.)*dr);
905  }
906 
907 
908  /* Source */
909  s = create_array(nz*(nr+1), "param s array");
910  isource = lround(sz/dz); /* index to z position of source */
911  jsource = 1+lround(sr/dr); /* index to r position of source */
912  s[INDEX(isource,jsource)]
913  = (1.0 / alphas[INDEX(isource,jsource)]) *
914  samplitude * dt * 4.0 / (PI * SQR(dr) * dz);
915 
916  /* If there are additional sources, add them to the s array */
917  if (more_sources.n > 0) {
918  for (nsource = 0; nsource < more_sources.n; nsource++) {
919  new_source.sz = more_sources.source[nsource].sz;
920  new_source.sr = more_sources.source[nsource].sr;
921  new_source.crnt = more_sources.source[nsource].crnt;
922 
923  new_source.sz += coord_shift; /* Convert to shifted coordinates */
924 
925  isource = lround((new_source.sz)/dz);
926  jsource = 1+lround(new_source.sr/dr);
927  samplitude = new_source.crnt * trn / FARADAY;
928 
929  if (isource < 0)
930  error("adding additional source %d; isource = %d < 0",
931  nsource, isource);
932  if (isource > nz-1)
933  error("adding additional source %d; isource = %d > nz-1",
934  nsource, isource);
935  if (jsource < 0)
936  error("adding additional source %d; jsource = %d < 0",
937  nsource, jsource);
938  if (jsource > nr)
939  error("adding additional source %d; jsource = %d > nr",
940  nsource, jsource);
941 
942  s[INDEX(isource,jsource)]
943  += (1.0 / alphas[INDEX(isource,jsource)]) *
944  samplitude * dt * 4.0 / (PI * SQR(dr) * dz);
945  }
946  }
947 
948 
949  /* Time and probe arrays */
950  t = create_array(nt, "time");
951  p = create_array(nt, "p");
952  for (k=0; k<nt; k++)
953  t[k] = dt * k;
954 
955  iprobe = lround(pz/dz); /* index to z position of probe */
956  jprobe = 1+lround(pr/dr); /* index to r position of probe */
957 
958 
959 
960  /* Calculate p[], the diffusion curve at the probe */
961  if (opt_verbose)
962  printf("About to calculate diffusion curve\n");
963 
964  /* If the output concentration images will not be saved,
965  set the image spacing time to -1 */
966  if (! opt_output_conc_image)
967  image_spacing = -1.;
968 
969 
970  /* Calculate the concentration as a function of time and space;
971  return the probe concentration as a function of time */
972  calc_diffusion_curve_layer(nt, nz, nr, iprobe, jprobe,
973  iz1, iz2, nolayer, dt, dr, sdelay, sduration,
974  alpha_so, theta_so, kappa_so,
975  alpha_sp, theta_sp, kappa_sp,
976  alpha_sr, theta_sr, kappa_sr,
977  dfree, t, s, invr,
978  imagebasename, image_spacing,
979  p);
980 
981 
982  /* Fit the traditional model (p_theory[]) to the concentration
983  calculated with the multilayer model (p[]) to get the
984  apparent parameters and characteristic curves. Surprisingly,
985  you can often generate a characteristic curve with the
986  traditional model that fits the calculated curve (from the
987  multilayer model) very well.
988  This step is not really necessary -- the apparent parameters
989  aren't physically meaningful -- but sometimes it's useful. */
990 
991  if (opt_verbose) {
992  printf("\nFitting for apparent parameters/characteristic curve:\n");
993  printf("Iter\talpha_fit\ttheta_fit\tmse \tfit size\n");
994  printf("%d\t%f\t%f\n",
995  0, alpha_start, theta_start);
996  }
997 
998  if (opt_pathfile) {
999  if ((pathfile_ptr = fopen(pathfilename,"w")) == NULL) {
1000  fprintf(stderr, "Error opening simplex path file %s\n",
1001  pathfilename);
1002  exit(EXIT_FAILURE);
1003  }
1004  fprintf(pathfile_ptr, "\nFitting for apparent parameters/characteristic curve:\n");
1005  fprintf(pathfile_ptr,
1006  "Iter\talpha_fit\ttheta_fit\tmse \tfit size\n");
1007  fprintf(pathfile_ptr, "%d\t%f\t%f\n",
1008  0, alpha_start, theta_start);
1009  }
1010 
1011 
1012  /* Fill struct with values for passing to mse function */
1013  spdist = sqrt(SQR(pr-sr) + SQR(pz-sz));
1014  mse_rti_params.nt = nt;
1015  mse_rti_params.spdist = spdist;
1016  mse_rti_params.samplitude = samplitude;
1017  mse_rti_params.sdelay = sdelay;
1018  mse_rti_params.sduration = sduration;
1019  mse_rti_params.kappa = 0.; /* not using this currently */
1020  mse_rti_params.dfree = dfree;
1021 
1022  mse_rti_params.t = create_array(nt, "param t array");
1023  mse_rti_params.p_model = create_array(nt, "param p_model array");
1024  mse_rti_params.p_theory = create_array(nt, "param p_theory array");
1025  for (k=0; k<nt; k++) {
1026  mse_rti_params.t[k] = t[k];
1027  mse_rti_params.p_model[k] = p[k];
1028  }
1029 
1030 
1031  /* Initialize the simplex */
1032  simplex = gsl_vector_alloc(2);
1033  gsl_vector_set(simplex, 0, alpha_start);
1034  gsl_vector_set(simplex, 1, theta_start);
1035 
1036  /* Initialize step sizes */
1037  steps = gsl_vector_alloc(2);
1038  gsl_vector_set(steps, 0, alpha_step);
1039  gsl_vector_set(steps, 1, theta_step);
1040 
1041  /* Set up minimization method */
1042  fit_func.n = 2; /* 2 parameters to fit */
1043  fit_func.f = calc_mse_rti; /* function to minimize */
1044  fit_func.params = &mse_rti_params; /* extra parameters to function */
1045 
1046  fit_state = gsl_multimin_fminimizer_alloc(fit_algorithm, 2);
1047  gsl_multimin_fminimizer_set(fit_state, &fit_func, simplex, steps);
1048 
1049  do {
1050  fit_iter++;
1051  fit_status = gsl_multimin_fminimizer_iterate(fit_state);
1052 
1053  if (fit_status) break;
1054 
1055  fit_size = gsl_multimin_fminimizer_size(fit_state);
1056  fit_status = gsl_multimin_test_size(fit_size, fit_tol);
1057 
1058  if (opt_verbose)
1059  if (fit_status == GSL_SUCCESS) printf("Finished fit\n");
1060 
1061  alpha_fit = gsl_vector_get(fit_state->x, 0);
1062  theta_fit = gsl_vector_get(fit_state->x, 1);
1063  mse = fit_state->fval;
1064 
1065  if (opt_verbose)
1066  printf("%d\t%f\t%f\t%g\t%g\n",
1067  (int) fit_iter, alpha_fit, theta_fit, mse, fit_size);
1068 
1069  if (opt_pathfile)
1070  fprintf(pathfile_ptr, "%d\t%f\t%f\t%g\t%g\n",
1071  (int) fit_iter, alpha_fit, theta_fit, mse, fit_size);
1072 
1073  } while (fit_status == GSL_CONTINUE && fit_iter < itermax);
1074 
1075  if (fit_status != GSL_SUCCESS) {
1076  printf("Warning: failed to converge, status = %d, "
1077  "# iterations = %zd\n", fit_status, fit_iter);
1078  if (opt_pathfile)
1079  fprintf(pathfile_ptr, "Warning: failed to converge, "
1080  "status = %d, # iterations = %zd\n", fit_status, fit_iter);
1081  }
1082 
1083  if (opt_pathfile)
1084  fclose(pathfile_ptr);
1085 
1086  double lambda_fit = 1./sqrt(theta_fit);
1087  if (opt_verbose) {
1088  printf("Fitted alpha = %f\n", alpha_fit);
1089  printf("Fitted theta = %f (lambda = %f)\n",
1090  theta_fit, lambda_fit);
1091  }
1092 
1093 
1094  /* Get end time of program */
1095  end_time = time(NULL);
1096  strncpy(string, ctime(&end_time), MAX_LINELENGTH-1);
1097 if (opt_verbose)
1098  printf("End time = %s", string);
1099 
1100  total_time = difftime(end_time, start_time);
1101 if (opt_verbose)
1102  printf("Total time = %d seconds = %f minutes = %f hours\n",
1103  (int) round(total_time), total_time/60., total_time/3600.);
1104 
1105 
1106  /* Write concentration curves to output file. Two conc. columns
1107  -- the data from the layer model and also the apparent curve */
1108  if ((file_ptr = fopen(outfilename,"a")) == NULL) {
1109  fprintf(stderr, "Error opening output file %s\n", outfilename);
1110  exit(EXIT_FAILURE);
1111  }
1112 
1113  fprintf(file_ptr, "# End time = %s", string); /* ctime() added the \n */
1114  fprintf(file_ptr, "# Total time = %d seconds = %f minutes = %f hours\n",
1115  (int) round(total_time), total_time/60., total_time/3600.);
1116  fprintf(file_ptr, "# --------------------------------------\n");
1117  fprintf(file_ptr, "# Fit for characteristic curve:\n");
1118  fprintf(file_ptr, "# Number of iterations = %d\n", (int)fit_iter);
1119  fprintf(file_ptr, "# Fitted apparent alpha = %f\n", alpha_fit);
1120  fprintf(file_ptr, "# Fitted apparent theta = %f (lambda = %f)\n",
1121  theta_fit, lambda_fit);
1122  fprintf(file_ptr, "# Final mean squared error = %g\n", mse);
1123  fprintf(file_ptr, "# Final simplex size = %g\n", fit_size);
1124  fprintf(file_ptr, "# Solution: apparent alpha\tapparent theta\t"
1125  "apparent lambda\t MSE\tsimplex size\t# iter."
1126  "\tTime (s)\tTime (m)\tTime (h) \n");
1127  fprintf(file_ptr, "# Solution: %f\t%f\t%f\t%f\t%g \t%7d\t%8d\t%f\t%f\n",
1128  alpha_fit, theta_fit, lambda_fit, mse, fit_size, (int) fit_iter,
1129  (int) round(total_time), total_time/60., total_time/3600.);
1130  fprintf(file_ptr, "# --------------------------------------\n");
1131  fprintf(file_ptr, "# Probe concentration data:\n");
1132  fprintf(file_ptr, "# time \t c (3-layer model) \t c (characteristic curve) \n");
1133 
1134 
1135  /* Print concentration arrays to output file */
1136  if (nt > 1000)
1137  for (i=0; i<1000; i++) {
1138  k = (i * nt) / 1000;
1139  fprintf(file_ptr, "%#12.8g\t%#12.8g\t%#12.8g\n",
1140  t[k], p[k], mse_rti_params.p_theory[k]);
1141  }
1142  else
1143  for (i=0; i<nt; i++) {
1144  fprintf(file_ptr, "%#12.8g\t%#12.8g\t%#12.8g\n",
1145  t[i], p[i], mse_rti_params.p_theory[i]);
1146  }
1147  fprintf(file_ptr, "\n");
1148 
1149  /* Close the file */
1150  fclose(file_ptr);
1151 
1152 
1153 
1154  /* Deallocate arrays */
1155  free(t);
1156  free(p);
1157  free(s);
1158  free(alphas);
1159  free(invr);
1160 
1161  free(mse_rti_params.t);
1162  free(mse_rti_params.p_model);
1163  free(mse_rti_params.p_theory);
1164 
1165  gsl_vector_free(simplex);
1166  gsl_vector_free(steps);
1167  gsl_multimin_fminimizer_free(fit_state);
1168 
1169 if (opt_verbose)
1170  printf("All done\n");
1171 
1172  return(EXIT_SUCCESS);
1173 }
#define MAX(x, y)
Computes the maximum of x and y.
Definition: header.h:94
int n
Number of additional sources.
Definition: header.h:169
double sr
r-coordinate of additional source
Definition: header.h:161
#define SQR(x)
Computes the square of x.
Definition: header.h:88
#define MAXNUM_COMMENTLINES
Maximum number of comment lines of input file to copy to output file.
Definition: header.h:34
double * p_theory
Probe concentration from homogeneous model (characteristic curve)
Definition: header.h:153
#define IS_ZERO(x)
Evaluates to TRUE if |x| < SMALLNUM, FALSE otherwise.
Definition: header.h:74
void get_io_filenames(char *argstring, const char *inf_extension, const char *outf_extension, char *infilename, char *outfilename)
Determine the input filename and the default output file name.
Definition: io.c:60
#define STREQ(s1, s2)
Compares strings s1 and s2; evaluates to TRUE if strings are equal, FALSE if not. ...
Definition: header.h:82
void get_filename(char *in, char *out)
Make sure that the filename is not too long.
Definition: io.c:25
Header file for program 3layer.
double sduration
Duration of source.
Definition: header.h:146
double kappa
Nonspecific clearance factor.
Definition: header.h:147
double sdelay
Source delay (time before source starts)
Definition: header.h:145
void error(char *errorstring,...)
Print an error message to stderr and exit with status EXIT_FAILURE.
Definition: extras.c:20
int main(int argc, char *argv[])
Main program.
Definition: 3layer.c:46
#define MAX_COMMAND_LENGTH
Maximum number of characters of command to copy to output file.
Definition: header.h:37
double * p_model
Probe concentration from multilayer model.
Definition: header.h:152
double * create_array(int N, char *string)
Create an array of doubles of the specified size.
Definition: extras.c:105
double sz
z-coordinate of additional source
Definition: header.h:160
double * t
Time array.
Definition: header.h:151
double samplitude
Amplitude of source.
Definition: header.h:144
void print_usage(char *program)
Print usage message and exit with status EXIT_FAILURE.
Definition: extras.c:40
#define ADDITIONAL_SOURCES_STRING_LENGTH
Maximum length of string argument to additional_sources option.
Definition: header.h:40
#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
double dfree
Free diffusion coefficient.
Definition: header.h:148
double spdist
Distance between source and probe.
Definition: header.h:143
#define FARADAY
Faraday constant in C/mol.
Definition: header.h:56
source_struct_type * source
Struct of parameters for each additional source.
Definition: header.h:170
int assemble_command(int argc, char *argv[], char *command)
Create a string containing the command used to run the program.
Definition: io.c:91
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 MAX_LINELENGTH
Maximum length of any line in input file.
Definition: header.h:31
double alpha
Extracellular volume fraction.
Definition: header.h:149
double crnt
Current of additional source.
Definition: header.h:162
#define PI
Sets constant PI to M_PI if that is defined; otherwise, computes PI as .
Definition: header.h:52
double theta
Permeability.
Definition: header.h:150
#define FALSE
FALSE assigned to 0.
Definition: header.h:43
int nt
Number of time points of calculation.
Definition: header.h:142
double read_source_parameter(char *string, int nsource)
Read a parameter from the string argument to the additional_sources option.
Definition: io.c:153
#define TRUE
TRUE assigned to 1.
Definition: header.h:46
#define MAXNUM_LINES
Maximum number of lines in input file.
Definition: header.h:28
double calc_mse_rti(const gsl_vector *x, void *params)
Mean squared error function for simplex fitting.
Definition: rti-theory.c:42