TPCCLIB
Loading...
Searching...
No Matches
paucinf.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13#include <string.h>
14#include <time.h>
15/*****************************************************************************/
16#include "libtpcmisc.h"
17#include "libtpcmodel.h"
18#include "libtpccurveio.h"
19#include "libtpcsvg.h"
20#include "libtpcmodext.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
24/* Local functions */
25double func(int parNr, double *p, void*);
26/*****************************************************************************/
27
28/*****************************************************************************/
29double *x, *ymeas, *yfit, *w;
30int dataNr=0, parNr=0;
31double pmin[MAX_PARAMETERS], pmax[MAX_PARAMETERS];
32double start_time, end_time;
33/*****************************************************************************/
34
35/*****************************************************************************/
36static char *info[] = {
37 "Estimates the half-life (t1/2) and elimination rate constant (kEL) of",
38 "a PET tracer in plasma, and the AUC of plasma time-activity curve (PTAC)",
39 "from 0 to infinite time. AUC can be used e.g. to estimate the total",
40 "clearance (ClT) of PET tracer after a single intravenous dose:",
41 " ",
42 " Dose ",
43 " CL = -------- ",
44 " T AUC ",
45 " 0-Inf ",
46 " ",
47 "The natural logarithm of tracer concentration is plotted against time",
48 "from bolus infusion. The plot becomes linear in the end phase, as the",
49 "tracer is eliminated according to the laws of first-order reaction",
50 "kinetics. The slope of the linear part of the plot equals -kEL.",
51 " ",
52 "Usage: @P [Options] ptacfile [resultfile]",
53 " ",
54 "Options:",
55 " -end=<sample time>",
56 " Use data from 0 to given time in the line fit; by default",
57 " search for the best line fit extends to the last PTAC sample.",
58 " -start=<sample time>",
59 " Use data from given time to end in the line fit; by default,",
60 " the search for the best line fit extends to the first sample.",
61 " -winnonlin",
62 " Best line fit is searched using algorithm that gives similar results",
63 " to WinNonlin with the same simple model.",
64//" -nlfit",
65//" Result based on line fitting is refined with exp function fitting.",
66 " -minnr=<sample number>",
67 " Enter the minimum number of samples to use in the fit; by default 3.",
68 " -svg=<Filename>",
69 " Plots of log transformed TACs and fitted lines are written in specified",
70 " SVG file.",
71 " -stdoptions", // List standard options like --help, -v, etc
72 " ",
73 "Plasmafile must contain a time column, and one or more concentration columns",
74 "separated by space(s) or tabulator(s). The result is printed on screen.",
75 " ",
76 "See also: extrapol, interpol, fit_exp, fit_dexp, fit2dat, fit2auc",
77 " ",
78 "Keywords: input, modelling, pharmacokinetics, clearance, elimination rate",
79 0};
80/*****************************************************************************/
81
82/*****************************************************************************/
83/* Turn on the globbing of the command line, since it is disabled by default in
84 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
85 In Unix&Linux wildcard command line processing is enabled by default. */
86/*
87#undef _CRT_glob
88#define _CRT_glob -1
89*/
90int _dowildcard = -1;
91/*****************************************************************************/
92
93/*****************************************************************************/
97int main(int argc, char **argv)
98{
99 int ai, help=0, version=0, verbose=1;
100 char datfile[FILENAME_MAX], outfile[FILENAME_MAX], svgfile[FILENAME_MAX], temp[512];
101 double fittime=-1.0, starttime=0.0;
102 int check_for_improvement=0; // 1=WinNonlin compatibility mode
103 int nonlinfit=0; // 1=best line fit range is re-fitted (non-linear)
104 int forced_minNr=0;
105 FILE *logfp; // file pointer for extra output
106 int ret;
107
108
109 /*
110 * Get arguments
111 */
112 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
113 datfile[0]=outfile[0]=svgfile[0]=(char)0;
114 /* Options */
115 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
116 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
117 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
118 if(strncasecmp(cptr, "E=", 2)==0 && strlen(cptr)>2) {
119 fittime=atof_dpi(cptr+2); if(fittime>0.0) continue;
120 } else if(strncasecmp(cptr, "END=", 4)==0 && strlen(cptr)>4) {
121 fittime=atof_dpi(cptr+4); if(fittime>0.0) continue;
122 } else if(strncasecmp(cptr, "ENDTIME=", 8)==0) {
123 fittime=atof_dpi(cptr+8); if(fittime>0.0) continue;
124 } else if(strncasecmp(cptr, "START=", 6)==0 && strlen(cptr)>6) {
125 starttime=atof_dpi(cptr+6); if(starttime>=0.0) continue;
126 } else if(strncasecmp(cptr, "STARTTIME=", 10)==0) {
127 starttime=atof_dpi(cptr+10); if(starttime>=0.0) continue;
128 } else if(strncasecmp(cptr, "WINNONLIN", 3)==0) {
129 check_for_improvement=1; continue;
130 } else if(strcasecmp(cptr, "NLFIT")==0) {
131 nonlinfit=1; continue;
132 } else if(strncasecmp(cptr, "MINNR=", 6)==0) {
133 if(atoi_with_check(cptr+6, &forced_minNr)==0 && forced_minNr>=3) continue;
134 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
135 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
136 }
137 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
138 return(1);
139 } else break;
140
141 /* Print help or version? */
142 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
143 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
144 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
145
146 /* Process other arguments, starting from the first non-option */
147 if(ai<argc) strlcpy(datfile, argv[ai++], FILENAME_MAX);
148 if(ai<argc) strlcpy(outfile, argv[ai++], FILENAME_MAX);
149 if(ai<argc) {fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]); return(1);}
150
151 /* Is something missing? */
152 if(!datfile[0]) {
153 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
154 return(1);
155 }
156 /* WinNonlin does not do nonlinear fitting */
157 if(check_for_improvement==1) nonlinfit=0;
158
159 /* In verbose mode print arguments and options */
160 if(verbose>1) {
161 printf("ptacfile := %s\n", datfile);
162 printf("svgfile := %s\n", svgfile);
163 if(outfile[0]) printf("resfile := %s\n", outfile);
164 if(fittime>=0.0) printf("endtime := %g\n", fittime);
165 if(starttime>=0.0) printf("starttime := %g\n", starttime);
166 if(forced_minNr>0) printf("forced_minNr := %d\n", forced_minNr);
167 printf("starttime := %g\n", starttime);
168 printf("check_for_improvement := %d\n", check_for_improvement);
169 printf("nonlinfit := %d\n", nonlinfit);
170 }
171 if(verbose>1) logfp=stdout; else logfp=NULL;
172
173
174 /*
175 * Read data
176 */
177 if(verbose>1) printf("reading %s\n", datfile);
178 if(verbose>10) CSV_TEST=verbose-10; else CSV_TEST=0;
179 DFT dft; dftInit(&dft);
180 if(dftRead(datfile, &dft)) {
181 fprintf(stderr, "Error in reading '%s': %s\n", datfile, dfterrmsg);
182 return(2);
183 }
184 /* Check for NA's */
185 if(dft_nr_of_NA(&dft) > 0) {
186 fprintf(stderr, "Error: missing sample(s) in %s\n", datfile);
187 dftEmpty(&dft); return(2);
188 }
189 /* Sort the samples by time in case data is catenated from several curves */
190 (void)dftSortByFrame(&dft);
191
192 /* Set the last sample to be fitted */
193 int fitNr=dft.frameNr;
194 if(fittime>0.0) {
195 while(dft.x[fitNr-1]>fittime && fitNr>0) fitNr--;
196 }
197 fittime=dft.x[fitNr-1];
198 if(verbose>1) printf("fittime := %g\n", dft.x[fitNr-1]);
199
200 /* Set Max nr of fitted points */
201 int max_nr=fitNr;
202 int min_nr=3; if(forced_minNr>min_nr) min_nr=forced_minNr;
203 if(starttime>0.0) {
204 int i;
205 for(i=fitNr-1; i>=0; i--) if(dft.x[i]<starttime) break;
206 max_nr=fitNr-(i+1);
207 }
208 if(verbose>1) {
209 printf("min_nr := %d\n", min_nr);
210 printf("max_nr := %d\n", max_nr);
211 }
212 /* Check that there are at least 3 samples */
213 if(max_nr<3 || max_nr<min_nr) {
214 fflush(stdout);
215 fprintf(stderr, "Error: too few samples for exponential fitting\n");
216 fflush(stderr); dftEmpty(&dft); return(2);
217 }
218 /* or give a warning if less than 5 samples */
219 if(max_nr<5) {
220 fprintf(stderr, "Warning: few samples for exponential fitting\n");
221 }
222
223
224 /*
225 * Allocate memory for results
226 */
227 if(verbose>1) printf("allocating memory for results.\n");
228 RES res; resInit(&res);
229 if(res_allocate_with_dft(&res, &dft)!=0) {
230 fprintf(stderr, "Error: cannot setup memory for results.\n");
231 dftEmpty(&dft); resEmpty(&res); return(3);
232 }
233 /* Copy titles & filenames */
234 tpcProgramName(argv[0], 1, 1, res.program, 128);
235 strncpy(res.plasmafile, datfile, FILENAME_MAX);
236 sprintf(res.datarange, "%g %s", fittime, petTunit(dft.timeunit));
237 res.datanr=max_nr;
238 res.time=time(NULL);
239 res.isweight=0;
240 /* Set the parameter names */
241 res.parNr=5;
242 {
243 int pi;
244 pi=0; strcpy(res.parname[pi], "kEL"); strcpy(res.parunit[pi], "");
245 pi++; strcpy(res.parname[pi], "t1/2"); strcpy(res.parunit[pi], "");
246 pi++; strcpy(res.parname[pi], "AUC"); strcpy(res.parunit[pi], "");
247 pi++; strcpy(res.parname[pi], "Start"); strcpy(res.parunit[pi], "");
248 pi++; strcpy(res.parname[pi], "C0"); strcpy(res.parunit[pi], "");
249 }
250
251 /*
252 * Make ln transformation for TACs
253 */
254 if(verbose>1) printf("allocating memory for ln transformed data\n");
255 DFT dftln; dftInit(&dftln);
256 if(dftdup(&dft, &dftln)!=0) {
257 fprintf(stderr, "Error: out of memory.\n");
258 dftEmpty(&dft); resEmpty(&res); return(4);
259 }
260 if(verbose>1) printf("ln transformation\n");
261 if(dft_ln(&dftln, NULL)!=0) {
262 fprintf(stderr, "Error: cannot make ln transformation.\n");
263 dftEmpty(&dft); resEmpty(&res); return(4);
264 }
265 if(verbose>10) {dftPrint(&dftln); fflush(stdout);}
266
267
268 /*
269 * Compute best linear fit to the end of ln transformed TACs.
270 */
271 if(verbose>1) printf("linear fitting\n");
272 FIT fit; fitInit(&fit);
273 {
274 double f;
275 int n;
276 f=fittime; n=min_nr;
277 ret=dft_end_line(&dftln, &f, &n, max_nr, -1.0, check_for_improvement,
278 &fit, logfp, temp);
279 }
280 if(ret!=0) {
281 fprintf(stderr, "Error in linear fit: %s.\n", temp);
282 dftEmpty(&dft); dftEmpty(&dftln); resEmpty(&res); fitEmpty(&fit);
283 return(6);
284 }
285 if(verbose>1) {
286 printf("Results of linear fitting:\n");
287 fitPrint(&fit);
288 }
289 if(verbose>1) {
290 if(fit.voiNr==1) printf("Adj_R^2 := %g (n=%d)\n", fit.voi[0].p[2], fit.voi[0].dataNr);
291 else for(int ri=0; ri<fit.voiNr; ri++)
292 printf("Adj_R^2(%s) := %g (n=%d)\n", fit.voi[ri].name, fit.voi[ri].p[2], fit.voi[ri].dataNr);
293 }
294
295 /* Non-linear fit to the previously found fit time range, if required.
296 * Note that this is NOT done in WinNonlin
297 */
298 if(nonlinfit==1) {
299 if(verbose>0) printf("non-linear fitting\n");
300 for(int ri=0; ri<dft.voiNr; ri++) {
301 int pi;
302 double pfit[MAX_PARAMETERS];
303 if(verbose>1) {fprintf(stdout, "%s: \n", dft.voi[ri].name); fflush(stdout);}
304 /* Set data pointers */
305 dataNr=dft.frameNr;
306 x=dft.x; ymeas=dft.voi[ri].y; yfit=dft.voi[ri].y2; w=dft.w;
307 start_time=fit.voi[ri].start;
308 end_time=fit.voi[ri].end;
309 /* Set the initial values for parameters */
310 fit.voi[ri].wss=3.402823e+38;
311 for(pi=0; pi<parNr; pi++) pfit[pi]=0.0;
312 /* Set parameter constraints for 1-exp fit */
313 pmin[0]=0.0; pmax[0]=2.0*exp(fit.voi[ri].p[0]);
314 pmin[1]=2.0*fit.voi[ri].p[1]; pmax[1]=0.0;
315 /* fit */
316 ret=tgo(pmin, pmax, func, NULL, parNr, 4, &fit.voi[ri].wss, pfit, 0, 0, verbose-19);
317 if(ret) {
318 fprintf(stderr, "Error %d in TGO.\n", ret);
319 dftEmpty(&dft); dftEmpty(&dftln); resEmpty(&res); fitEmpty(&fit);
320 return(7);
321 }
322 /* Print measured and fitted curve */
323 if(verbose>9) {
324 printf(" Measured Fitted:\n");
325 for(int i=0; i<dft.frameNr; i++)
326 printf(" %2d: %8.2e %8.2e %8.2e\n", i+1, x[i], ymeas[i], yfit[i]);
327 }
328 if(verbose>2) {
329 printf(" fitted parameters:");
330 for(int pi=0; pi<parNr; pi++) printf(" %g", pfit[pi]);
331 printf("\n");
332 }
333 if(verbose>3) {
334 printf(" parameter constraints:");
335 for(int pi=0; pi<parNr; pi++) printf(" (%g - %g)", pmin[pi], pmax[pi]);
336 printf("\n");
337 }
338 /* Write fit results into FIT struct */
339 fit.voi[ri].p[0]=log(pfit[0]);
340 fit.voi[ri].p[1]=pfit[1];
341 } /* next TAC */
342 }
343
344 /* Calculate AUC using trapezoidal rule from time 0 to the time of last
345 * measured sample, where the extrapolation starts.
346 * Write fit parameters into results
347 */
348 for(int ri=0; ri<dftln.voiNr; ri++) {
349 double auc_0_t, kel, c0, t12, auc_t_inf, auc_0_inf;
350 auc_0_t=kel=c0=t12=auc_t_inf=auc_0_inf=0.0;
351 if(verbose>0 && dft.voiNr>1) printf("%s :\n", dftln.voi[ri].name);
352 /* Trapezoidal AUC calculation */
353 integrate(dft.x, dft.voi[ri].y, dft.frameNr, dft.voi[ri].y3);
354 auc_0_t=dft.voi[ri].y3[fitNr-1];
355 if(verbose>2) printf("auc_0_t := %g\n", auc_0_t);
356 /* Get parameters from the fit */
357 kel=-fit.voi[ri].p[1];
358 c0=exp(fit.voi[ri].p[0]);
359 /* Calculate t(1/2) */
360 t12=M_LN2/kel; if(verbose>1) printf("t(1/2) := %g\n", t12);
361 /* Exp function integral from last (fitted) time point to infinity */
362 auc_t_inf=c0*exp(-kel*fit.voi[ri].end)/kel;
363 if(verbose>2) printf("auc_t_inf := %g\n", auc_t_inf);
364 /* Fill the results */
365 res.voi[ri].parameter[0]=kel;
366 res.voi[ri].parameter[1]=t12;
367 res.voi[ri].parameter[2]=auc_0_inf=auc_0_t+auc_t_inf;
368 res.voi[ri].parameter[3]=fit.voi[ri].start; // selected fit start time
369 res.voi[ri].parameter[4]=c0;
370 /* Print results */
371 if(verbose>0 || !outfile[0]) {
372 fprintf(stdout, " AUC(0-Inf)=%g [AUC(0-%g)=%g AUC(%g-Inf)=%g]\n",
373 auc_0_inf, fit.voi[ri].end, auc_0_t, fit.voi[ri].end, auc_t_inf);
374 fprintf(stdout, " k(el)=%g t(1/2)=%g estimated between %g-%g\n",
375 kel, t12, fit.voi[ri].start, fit.voi[ri].end);
376 }
377 }
378 fitEmpty(&fit);
379
380
381 /*
382 * Plotting of fitted TACs
383 */
384 if(svgfile[0]) {
385
386 /* Create a DFT containing fitted TACs */
387 double k, b;
388 char tmp[64];
389 DFT dft3;
390 dftInit(&dft3); ret=dftdup(&dftln, &dft3);
391 if(ret) {
392 fprintf(stderr, "Error: cannot save fitted curves.\n");
393 dftEmpty(&dft); dftEmpty(&dftln); resEmpty(&res);
394 return(21);
395 }
396 for(int ri=0; ri<dft3.voiNr; ri++) {
397 k=-res.voi[ri].parameter[0];
398 b=log(res.voi[ri].parameter[4]);
399 for(int fi=0; fi<dft3.frameNr; fi++) {
400 dft3.voi[ri].y[fi]=nan("");
401 if(dft3.x[fi]<res.voi[ri].parameter[3]) continue;
402 if(dft3.x[fi]>fittime) continue;
403 dft3.voi[ri].y[fi]=b+k*dft3.x[fi];
404 }
405 }
406
407 /* Save SVG plot of fitted and original data */
408 if(verbose>1) printf("saving SVG plot\n");
409 sprintf(tmp, "Line fit to log-transformed data ");
410 if(strlen(res.studynr)>0 && strcmp(res.studynr, ".")!=0) strcat(tmp, res.studynr);
411 ret=plot_fit_svg(&dftln, &dft3, tmp, svgfile, verbose-30);
412 if(ret) {
413 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
414 dftEmpty(&dftln); dftEmpty(&dft3); dftEmpty(&dft); resEmpty(&res);
415 return(30+ret);
416 }
417 if(verbose>0) printf("Plots written in %s\n", svgfile);
418
419 dftEmpty(&dft3);
420 }
421 dftEmpty(&dftln);
422
423
424 /*
425 * Save the results, if required
426 */
427 if(outfile[0]) {
428 if(verbose>1) printf("saving results in %s\n", outfile);
429 ret=resWrite(&res, outfile, verbose-10);
430 if(ret) {
431 fprintf(stderr, "Error in writing '%s': %s\n", outfile, reserrmsg);
432 dftEmpty(&dft); resEmpty(&res); return(11);
433 }
434 }
435
436 /* Free memory */
437 dftEmpty(&dft); resEmpty(&res);
438
439 return(0);
440}
441/*****************************************************************************/
442
443/*****************************************************************************
444 *
445 * Functions to be minimized
446 *
447 *****************************************************************************/
448double func(int parNr, double *p, void *fdata)
449{
450 double v, wss=0.0;
451 double pa[MAX_PARAMETERS], penalty=1.0;
452
453
454 /* Check parameters against the constraints */
455 (void)modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
456 if(fdata) {}
457
458 /* Calculate the curve values and weighted SS */
459 for(int i=0; i<dataNr; i++) {
460 if(x[i]<start_time || x[i]>end_time || w[i]<=0.0) continue;
461 yfit[i]=pa[0]*exp(pa[1]*x[i]);
462 v=yfit[i]-ymeas[i]; wss+=w[i]*v*v;
463 }
464 wss*=penalty;
465
466 return(wss);
467}
468/*****************************************************************************/
469
470/*****************************************************************************/
472
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
Definition constraints.c:15
int CSV_TEST
Definition csv.c:6
double atof_dpi(char *str)
Definition decpoint.c:59
int atoi_with_check(const char *int_as_string, int *result_value)
Definition decpoint.c:238
void dftInit(DFT *data)
Definition dft.c:38
int dftdup(DFT *dft1, DFT *dft2)
Definition dft.c:655
char dfterrmsg[64]
Definition dft.c:6
int dftSortByFrame(DFT *dft)
Definition dft.c:1169
void dftEmpty(DFT *data)
Definition dft.c:20
int dft_nr_of_NA(DFT *dft)
Definition dft.c:905
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
void dftPrint(DFT *data)
Definition dftio.c:538
int res_allocate_with_dft(RES *res, DFT *dft)
Definition dftres.c:14
int dft_end_line(DFT *dft, double *fittime, int *min_nr, int max_nr, double mintime, int check_impr, FIT *fit, FILE *loginfo, char *status)
int dft_ln(DFT *dft1, DFT *dft2)
int integrate(double *x, double *y, int nr, double *yi)
Definition integr.c:271
Header file for libtpccurveio.
char reserrmsg[64]
Definition result.c:6
void resInit(RES *res)
Definition result.c:52
void fitEmpty(FIT *fit)
Definition mathfunc.c:18
int resWrite(RES *res, char *filename, int verbose)
Definition result.c:565
void fitInit(FIT *fit)
Definition mathfunc.c:38
void resEmpty(RES *res)
Definition result.c:22
void fitPrint(FIT *fit)
Definition mathfunc.c:180
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:101
#define M_LN2
Definition libtpcmisc.h:90
char * petTunit(int tunit)
Definition petunits.c:226
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
int tgo(double *lowlim, double *uplim, double(*objf)(int, double *, void *), void *objfData, int dim, int neighNr, double *fmin, double *gmin, int samNr, int tgoNr, int verbose)
Definition tgo.c:39
#define MAX_PARAMETERS
Definition libtpcmodel.h:31
Header file for libtpcmodext.
int plot_fit_svg(DFT *dft1, DFT *dft2, char *main_title, char *fname, int verbose)
Definition plotfit.c:216
Header file for libtpcsvg.
Voi * voi
int timeunit
double * w
int voiNr
int frameNr
double * x
int voiNr
FitVOI * voi
double wss
double end
char name[MAX_REGIONNAME_LEN+1]
double start
double p[MAX_FITPARAMS]
char studynr[MAX_STUDYNR_LEN+1]
int parNr
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
int datanr
ResVOI * voi
char program[1024]
char plasmafile[FILENAME_MAX]
char datarange[128]
int isweight
char parunit[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
time_t time
double parameter[MAX_RESPARAMS]
double * y2
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3