8#include "tpcclibConfig.h"
22double func_gvar(
int parNr,
double *p,
void*);
24double *x, *ymeas, *yfit, *w;
30static char *info[] = {
31 "Non-linear fitting of Gamma variate bolus plus recirculation function",
32 "with time delay term to plasma and tissue time-activity curves (TACs).",
37 " | p2*((t-p1)^p3)*exp(-(t-p1)/p4) , t >= p1 ",
38 " | + p5*(1-exp(-(t-p1)/p4))*exp(-(t-p1)/p6) ",
40 "Usage: @P [Options] tacfile [fitfile]",
44 " Fit recirculation terms p5 and p6 (y, default), or fit only",
45 " gamma variate function setting p5=p6=0 (n).",
47 " Specify the constraints for function parameters;",
48 " This file with default values can be created by giving this",
49 " option as the only command-line argument to this program.",
51 " All weights are set to 1.0 (no weighting); by default, weights in",
52 " data file are used, if available.",
54 " Weight by sampling interval.",
55 " -stoptime=<Fit end time>",
56 " All data with sample time > stoptime is excluded from the fit.",
58 " If sample value after the peak is less than Threshold% of the peak,",
59 " then that sample and all samples after that are omitted from the fit.",
60 " Hint: try to set threshold close to 100, e.g. 99%, to get a good",
61 " estimate of tracer appearance time.",
63 " Automatically sets the fit range from 0 to peak + at least one",
64 " sample more, until WSS/(sum of weights) gets worse.",
66 " Fitted and measured TACs are plotted in specified SVG file.",
68 " Fitted TACs are written in TAC format.",
71 "TAC file must contain at least 2 columns, sample times and",
73 "Weights can be specified as usual if data is in DFT format.",
75 "Program writes the fit start and end times, nr of points, WSS,",
76 "and parameters (p1, p2, ...) of the fitted function to the fit file.",
78 "See also: fit2dat, fit_sinf, fit_exp, fit_ratf, fit_hiad",
80 "Keywords: curve fitting, TAC, simulation",
99int main(
int argc,
char **argv)
101 int ai, help=0, version=0, verbose=1;
103 char datfile[FILENAME_MAX], fitfile[FILENAME_MAX], parfile[FILENAME_MAX],
104 svgfile[FILENAME_MAX], limfile[FILENAME_MAX];
108 double threshold=0.0, stoptime=-1.0;
118 def_pmin[0]=0.0; def_pmax[0]=100.0;
119 def_pmin[1]=1.0E-06; def_pmax[1]=1.0E+06;
120 def_pmin[2]=1.0E-03; def_pmax[2]=2.0;
121 def_pmin[3]=1.0E-01; def_pmax[3]=1.0E+03;
122 def_pmin[4]=1.0E-06; def_pmax[4]=1.0E+06;
123 def_pmin[5]=1.0; def_pmax[5]=1.0E+06;
128 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
129 datfile[0]=fitfile[0]=parfile[0]=svgfile[0]=limfile[0]=(char)0;
131 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
132 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
134 if(strcasecmp(cptr,
"W1")==0) {
136 }
else if(strcasecmp(cptr,
"WF")==0) {
138 }
else if(strncasecmp(cptr,
"LIM=", 4)==0) {
139 strlcpy(limfile, cptr+4, FILENAME_MAX);
continue;
140 }
else if(strncasecmp(cptr,
"SVG=", 4)==0) {
141 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
142 }
else if(strncasecmp(cptr,
"FIT=", 4)==0) {
143 strlcpy(fitfile, cptr+4, FILENAME_MAX);
continue;
144 }
else if(strncasecmp(cptr,
"STOPTIME=", 9)==0) {
146 }
else if(strncasecmp(cptr,
"AUTO", 4)==0) {
148 }
else if(strncasecmp(cptr,
"THR=", 4)==0) {
150 if(threshold<0.0) threshold=0.0;
151 else threshold/=100.0;
152 if(threshold<1.0)
continue;
154 }
else if(strncasecmp(cptr,
"RECIRC=", 7)==0) {
155 if(strncasecmp(cptr+7,
"YES", 1)==0) {recirc=1;
continue;}
156 else if(strncasecmp(cptr+7,
"NO", 1)==0) {recirc=0;
continue;}
158 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
165 def_pmax[4]=def_pmin[4]=def_pmax[5]=def_pmin[5]=0.0;
169 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
174 if(ai<argc) {
strlcpy(datfile, argv[ai++], FILENAME_MAX);}
175 if(ai<argc) {
strlcpy(parfile, argv[ai++], FILENAME_MAX);}
177 fprintf(stderr,
"Error: invalid argument '%s'\n", argv[ai]);
180 if(!parfile[0]) strcpy(parfile,
"stdout");
182 for(; ai<argc; ai++) {
183 if(!datfile[0]) {strcpy(datfile, argv[ai]);
continue;}
184 else if(!parfile[0]) {strcpy(parfile, argv[ai]);
continue;}
185 fprintf(stderr,
"Error: invalid argument '%s'\n", argv[ai]);
188 if(!parfile[0]) strcpy(parfile,
"stdout");
193 if(limfile[0] && !datfile[0]) {
195 if(strcasecmp(limfile,
"stdout")!=0 && access(limfile, 0) != -1) {
196 fprintf(stderr,
"Error: parameter constraint file %s exists.\n", limfile);
199 if(verbose>1 && strcasecmp(limfile,
"stdout")!=0)
200 printf(
"writing parameter constraints file\n");
204 for(
int i=0; i<parNr; i++) {
205 sprintf(buf,
"p%d_lower", 1+i);
207 sprintf(buf,
"p%d_upper", 1+i);
212 fprintf(stderr,
"Error in writing '%s': %s\n", limfile, ift.
status);
215 if(strcasecmp(limfile,
"stdout")!=0)
216 fprintf(stdout,
"Parameter file %s with initial values written.\n", limfile);
223 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
229 if(limfile[0]) printf(
"limfile := %s\n", limfile);
230 printf(
"datfile := %s\n", datfile);
231 printf(
"parfile := %s\n", parfile);
232 if(fitfile[0]) printf(
"fitfile := %s\n", fitfile);
233 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
235 printf(
"weights := %d\n", weights);
236 printf(
"threshold := %g\n", threshold);
237 printf(
"autoend := %d\n", autoend);
238 printf(
"stoptime := %g\n", stoptime);
248 if(verbose>1) printf(
"reading %s\n", limfile);
250 ret=
iftRead(&ift, limfile, 1, 0);
252 fprintf(stderr,
"Error in reading '%s': %s\n", limfile, ift.
status);
255 if(verbose>10)
iftWrite(&ift,
"stdout", 0);
258 for(
int i=0; i<6; i++) {
259 sprintf(buf,
"p%d_lower", 1+i);
261 sprintf(buf,
"p%d_upper", 1+i);
267 for(i=0, ret=0; i<parNr; i++) {
268 if(def_pmin[i]<0.0) ret++;
269 if(def_pmax[i]<def_pmin[i]) ret++;
270 if(def_pmax[i]>def_pmin[i]) n++;
273 fprintf(stderr,
"Error: invalid parameter constraints.\n");
277 fprintf(stderr,
"Error: no model parameters left free for fitting.\n");
282 if(def_pmax[4]<1.0E-10 && def_pmin[4]<1.0E-10) {
283 def_pmax[4]=def_pmin[4]=def_pmax[5]=def_pmin[5]=0.0;
291 printf(
"recirc := %d\n", recirc);
292 printf(
"parNr := %d\n", parNr);
296 for(
int i=0; i<parNr; i++) {
297 printf(
"def_pmin[%d] := %g\n", i, def_pmin[i]);
298 printf(
"def_pmax[%d] := %g\n", i, def_pmax[i]);
307 if(verbose>1) {printf(
"reading %s\n", datfile); fflush(stdout);}
310 fprintf(stderr,
"Error in reading '%s': %s\n", datfile,
dfterrmsg);
321 for(fi=1; fi<dft.
frameNr; fi++)
if(dft.
x[fi]>stoptime)
break;
324 if((dft.
frameNr<4 && recirc==0) || (dft.
frameNr<6 && recirc==1)) {
325 fprintf(stderr,
"Error: not enough samples for decent fitting.\n");
326 dftEmpty(&dft); fflush(stderr);
return(3);
330 fprintf(stderr,
"Error: missing sample(s) in %s\n", datfile);
331 dftEmpty(&dft); fflush(stderr);
return(3);
335 double tstart, tstop, miny, maxy;
336 ret=
dftMinMax(&dft, &tstart, &tstop, &miny, &maxy);
338 fprintf(stderr,
"Error: invalid contents in %s\n", datfile);
341 if(tstop<=0.0 || maxy<=0.0) {
342 fprintf(stderr,
"Error: invalid contents in %s\n", datfile);
343 dftEmpty(&dft); fflush(stderr);
return(3);
345 if(tstart<0.0) fprintf(stderr,
"Warning: negative x value(s).\n");
346 if(miny<0.0) fprintf(stderr,
"Warning: negative y value(s).\n");
351 }
else if(weights==1) {
353 }
else if(weights==2) {
362 if(verbose>1) printf(
"allocating memory for fits.\n");
366 fprintf(stderr,
"Error: cannot allocate space for fit results (%d).\n", ret);
375 for(
int i=0; i<dft.
voiNr; i++) {
387 if(verbose>0) {printf(
"fitting\n"); fflush(stdout);}
388 for(
int ri=0; ri<dft.
voiNr; ri++) {
389 if(verbose>1) {printf(
"%d: %s\n", ri+1, dft.
voi[ri].
name); fflush(stdout);}
391 x=dft.
x; ymeas=dft.
voi[ri].
y; yfit=dft.
voi[ri].
y2; w=dft.
w;
394 fit.
voi[ri].
wss=3.402823e+38;
399 ret=
dftMinMaxTAC(&dft, ri, NULL, &peakx, NULL, &peaky, NULL, NULL, NULL, &peaki);
401 fprintf(stderr,
"Error: invalid TAC data for fitting.\n");
404 if(verbose>4) printf(
" peakx := %g\n peaky := %g\n", peakx, peaky);
409 double a=threshold*peaky;
411 for(; i<dft.
frameNr; i++)
if((ymeas[i])<a) {dataNr=i;
break;}
413 else fit.
voi[ri].
end=dft.
x[dataNr-1];
419 for(
int pi=0; pi<6; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
422 if(verbose>3) printf(
" refining limits\n");
424 pmin[0]=-0.05*fabs(peakx);
425 pmax[0]=0.95*fabs(peakx);
427 pmax[1]=10.0*peaky;
if(pmin[1]>0.1*pmax[1]) pmin[1]=pmax[1]*1.0E-06;
430 pmax[4]=10.0*peaky;
if(pmin[4]>0.1*pmax[4]) pmin[4]=pmax[4]*1.0E-06;
434 printf(
" constraints\n");
435 for(
int pi=0; pi<parNr; pi++) {
436 printf(
" pmin[%d] := %g\n", pi, pmin[pi]);
437 printf(
" pmax[%d] := %g\n", pi, pmax[pi]);
450 ret=
tgo(pmin, pmax, func_gvar, NULL, parNr, neighNr, &fit.
voi[ri].
wss,
451 fit.
voi[ri].
p, samNr, tgoNr, verbose-8);
453 fprintf(stderr,
"Error: error %d in TGO.\n", ret);
459 int saveDataNr=dataNr;
462 double lastRelWSS=3.402823e+38;
463 while(dataNr<=saveDataNr) {
464 ret=
tgo(pmin, pmax, func_gvar, NULL, parNr, neighNr, &fit.
voi[ri].
wss,
465 fit.
voi[ri].
p, samNr, tgoNr, verbose-10);
467 fprintf(stderr,
"Error: error %d in TGO.\n", ret);
472 if((fit.
voi[ri].
wss/wsum)>lastRelWSS) {
475 ret=
tgo(pmin, pmax, func_gvar, NULL, parNr, neighNr, &fit.
voi[ri].
wss,
476 fit.
voi[ri].
p, samNr, tgoNr, verbose-10);
478 fprintf(stderr,
"Error: error %d in TGO.\n", ret);
483 lastRelWSS=fit.
voi[ri].
wss/wsum;
489 else fit.
voi[ri].
end=dft.
x[dataNr-1];
496 printf(
"\n Frame Time Value Fitted Weight \n");
497 for(
int i=0; i<dft.
frameNr; i++)
498 printf(
" %02d %8.3f %12.4f %12.4f %8.4f\n",
499 i+1, x[i], ymeas[i], yfit[i], w[i]);
504 if(ret!=0 && verbose>0)
505 fprintf(stderr,
"Warning: fit collided with the limits.\n");
514 for(
int i=0; i<dataNr; i++)
if(w[i]>1.0E-10) n++;
518 if(verbose>0) fprintf(stdout,
"\n");
530 if(strcasecmp(parfile,
"stdout")!=0) {
531 if(verbose>1) printf(
"saving results in %s\n", parfile);
533 fprintf(stderr,
"Error in writing '%s': %s\n", parfile,
fiterrmsg);
543 if(verbose>1) printf(
"creating SVG plot\n");
545 char tmp[FILENAME_MAX];
549 printf(
"calculating fitted curve at automatically generated sample times\n");
553 fprintf(stderr,
"Error: cannot allocate memory for fitted curves.\n");
558 for(
int ri=0, ret=0; ri<adft.
voiNr; ri++) {
559 for(
int fi=0; fi<adft.
frameNr; fi++) {
560 ret=
fitEval(&fit.
voi[ri], adft.
x[fi], &a);
if(ret!=0)
break;
561 adft.
voi[ri].
y[fi]=a;
566 fprintf(stderr,
"Error: cannot calculate fitted TAC for '%s'.\n", svgfile);
572 if(verbose>1) printf(
"writing %s\n", svgfile);
579 svgfile, verbose-10);
581 fprintf(stderr,
"Error: cannot write '%s'.\n", svgfile);
585 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
594 if(verbose>1) printf(
"saving fitted curves in %s\n", fitfile);
596 for(
int ri=0, ret=0; ri<dft.
voiNr; ri++) {
597 for(
int fi=0; fi<dft.
frameNr; fi++) {
598 ret=
fitEval(&fit.
voi[ri], dft.
x[fi], &a);
if(ret!=0)
break;
604 fprintf(stderr,
"Error: cannot calculate fitted TACs for '%s'.\n", fitfile);
609 snprintf(dft.
comments, 128,
"# program := %s\n", progname);
612 fprintf(stderr,
"Error in writing '%s': %s\n", fitfile,
dfterrmsg);
616 if(verbose>0) printf(
"Fitted TACs written in %s\n", fitfile);
628double func_gvar(
int parNr,
double *p,
void *fdata)
631 double xt, et, v, wss;
638 for(i=0; i<parNr; i++) printf(
" p[%d]=%g", i, p[i]);
643 for(i=0, wss=0.0; i<dataNr; i++) {
648 if(pa[1]>0.0) yfit[i]+=pa[1]*pow(xt, pa[2])*et;
649 if(parNr>5 && pa[4]>0.0) yfit[i]+=pa[4]*(1.0-et)*exp(-xt/pa[5]);
652 v=yfit[i]-ymeas[i]; wss+=w[i]*v*v;
654 if(!isfinite(wss)) wss=nan(
"");
656 if(0) printf(
" wss=%g penalty=%g\n", wss, penalty);
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
int modelCheckLimits(int par_nr, double *lower_p, double *upper_p, double *test_p)
int atof_with_check(char *double_as_string, double *result_value)
int dftMinMaxTAC(DFT *dft, int tacindex, double *minx, double *maxx, double *miny, double *maxy, int *mini, int *maxi, int *mins, int *maxs)
int dftSortByFrame(DFT *dft)
int dftMinMax(DFT *dft, double *minx, double *maxx, double *miny, double *maxy)
int dft_nr_of_NA(DFT *dft)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
double doubleSum(double *a, const unsigned int n)
int fit_allocate_with_dft(FIT *fit, DFT *dft)
int iftPutDouble(IFT *ift, char *key, double value, char *cmt_type, int verbose)
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
int iftWrite(IFT *ift, char *filename, int verbose)
int iftGetDoubleValue(IFT *ift, int si, const char *key, double *value, int verbose)
Header file for libtpccurveio.
int fitEval(FitVOI *r, double x, double *y)
int fitWrite(FIT *fit, char *filename)
#define DFT_TIME_STARTEND
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
size_t strlcat(char *dst, const char *src, size_t dstsize)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
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)
Header file for libtpcmodext.
int dftWeightByFreq(DFT *dft)
int plot_fitrange_svg(DFT *dft1, DFT *dft2, char *main_title, double x1, double x2, double y1, double y2, char *fname, int verbose)
Header file for libtpcsvg.
char studynr[MAX_STUDYNR_LEN+1]
char comments[_DFT_COMMENT_LEN+1]
char unit[MAX_UNITS_LEN+1]
char datafile[FILENAME_MAX]
char unit[MAX_UNITS_LEN+1]
char name[MAX_REGIONNAME_LEN+1]