8#include "tpcclibConfig.h"
25enum {MODEL_UNKNOWN, MODEL_IGV, MODEL_HILLB, MODEL_IHILLB};
26int model=MODEL_UNKNOWN;
27int func_par_nr[MAX_FUNC_NR]={0,5,5,5};
28static char *model_name[] = {
"Unknown",
"IGV",
"HILLB",
"IHILLB", 0};
30#define MAX_MINMEAS_NR 3
31enum {MINMEAS_UNKNOWN, MINMEAS_SS, MINMEAS_ABS};
32int min_meas=MINMEAS_UNKNOWN;
34double *x, *ymeas, *yfit, *w;
40double (*func)(int,
double*,
void*);
41double func_igv(
int parNr,
double *p,
void*);
42double func_hillb(
int parNr,
double *p,
void*);
46static char *info[] = {
47 "Non-linear fitting of a function to sampled blood-to-plasma ratio data.",
49 "Usage: @P [Options] datafile fitfile",
52 " -model=<igv|hillb|ihillb>",
53 " Select the function; default is IGV.",
55 " Fit also delay time, or, set delay time (0 by default).",
57 " Constrain baseline level to specified value; fitted by default.",
58 " -w1 All weights are set to 1.0 (no weighting); by default, weights in",
59 " data file are used, if available.",
61 " Weight by sampling interval.",
63 " Speed up the fitting but increase the chance of failure, or",
64 " increase the reliability at the cost of computing time.",
66 " Sum-of-squares (SS) is minimized by default, but optionally",
67 " sum of absolute deviations can be selected.",
69 " Fitted and measured TACs are plotted in specified SVG file.",
72 "Datafile must contain at least 2 columns, sample times and ratios;",
73 "DFT file (1) can include also weights.",
74 "Program writes the fit start and end times, nr of points, WSS/n,",
75 "and parameters of the fitted function to the FIT file (2).",
78 " @P -model=igv -svg=ia765bprat.svg ia765bp.rat ia765bprat.fit",
81 "1. https://www.turkupetcentre.net/petanalysis/format_tpc_dft.html",
82 "2. https://www.turkupetcentre.net/petanalysis/format_tpc_fit.html",
84 "See also: fit2dat, avgfract, b2plasma, bpr2cpr, tacinv, taccat, tacblend",
86 "Keywords: curve fitting, input, blood, plasma, modelling, simulation",
105int main(
int argc,
char **argv)
107 int ai, help=0, version=0, verbose=1;
108 int fi, ri, pi, type, ret;
110 double fixedDelay=0.0;
111 double fixedBaseline=-1.0;
112 char dftfile[FILENAME_MAX], fitfile[FILENAME_MAX], svgfile[FILENAME_MAX];
115 int tgo_nr, neighNr=0, reliability_level=2;
123 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
125 dftfile[0]=fitfile[0]=svgfile[0]=(char)0;
127 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
128 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
130 if(strcasecmp(cptr,
"SAFE")==0) {
131 reliability_level=3;
continue;
132 }
else if(strcasecmp(cptr,
"NORMAL")==0) {
133 reliability_level=2;
continue;
134 }
else if(strcasecmp(cptr,
"FAST")==0) {
135 reliability_level=1;
continue;
136 }
else if(strcasecmp(cptr,
"W1")==0) {
138 }
else if(strcasecmp(cptr,
"WF")==0) {
140 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
141 strcpy(svgfile, cptr+4);
continue;
142 }
else if(strncasecmp(cptr,
"MODEL=", 6)==0) {
144 if(strncasecmp(cptr,
"IGV", 3)==0) {model=MODEL_IGV;
continue;}
145 if(strncasecmp(cptr,
"HILLB", 3)==0) {model=MODEL_HILLB;
continue;}
146 if(strncasecmp(cptr,
"IHILLB", 3)==0) {model=MODEL_IHILLB;
continue;}
147 fprintf(stderr,
"Error: invalid ratio model.\n");
return(1);
148 }
else if(strncasecmp(cptr,
"MIN=", 4)==0) {
150 if(strcasecmp(cptr,
"SS")==0 || strcasecmp(cptr,
"WSS")==0) {
151 min_meas=MINMEAS_SS;
continue;}
152 if(strcasecmp(cptr,
"ABS")==0 || strcasecmp(cptr,
"WABS")==0) {
153 min_meas=MINMEAS_ABS;
continue;}
154 fprintf(stderr,
"Error: invalid minimization measure.\n");
return(1);
155 }
else if(strncasecmp(cptr,
"DELAY=", 6)==0) {
156 fixedDelay=
atof_dpi(cptr+6);
if(fixedDelay>=0.0)
continue;
157 }
else if(strcasecmp(cptr,
"DELAY")==0) {
158 fixedDelay=-1.0;
continue;
159 }
else if(strncasecmp(cptr,
"BL=", 3)==0) {
160 fixedBaseline=
atof_dpi(cptr+3);
if(fixedBaseline>=0.0)
continue;
162 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
167 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
172 for(; ai<argc; ai++) {
173 if(!dftfile[0]) {strcpy(dftfile, argv[ai]);
continue;}
174 if(!fitfile[0]) {strcpy(fitfile, argv[ai]);
continue;}
175 fprintf(stderr,
"Error: too many arguments: '%s'.\n", argv[ai]);
181 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
184 if(model==MODEL_UNKNOWN) model=MODEL_IGV;
185 if(min_meas==MINMEAS_UNKNOWN) min_meas=MINMEAS_SS;
190 printf(
"dftfile := %s\n", dftfile);
191 printf(
"fitfile := %s\n", fitfile);
192 printf(
"svgfile := %s\n", svgfile);
193 printf(
"model := %d\n", model);
194 printf(
"min_meas := %d\n", min_meas);
195 printf(
"reliability_level := %d\n", reliability_level);
196 printf(
"weights := %d\n", weights);
197 if(fixedDelay>=0) printf(
"fixedDelay := %g\n", fixedDelay);
198 if(fixedBaseline>=0) printf(
"fixedBaseline := %g\n", fixedBaseline);
206 if(verbose>1) printf(
"reading '%s'\n", dftfile);
208 fprintf(stderr,
"Error in reading '%s': %s\n", dftfile,
dfterrmsg);
212 fprintf(stderr,
"Error: not enough samples for decent fitting.\n");
223 fprintf(stderr,
"Error: missing sample(s) in %s\n", dftfile);
228 ret=
dftMinMax(&dft, &tstart, &tstop, &miny, &maxy);
230 fprintf(stderr,
"Error: invalid contents in %s\n", dftfile);
233 if(tstop<=0.0 || maxy<=0.0) {
234 fprintf(stderr,
"Error: invalid contents in %s\n", dftfile);
237 if(tstart<0.0) fprintf(stderr,
"Warning: negative x value(s).\n");
238 if(miny<0.0) fprintf(stderr,
"Warning: negative y value(s).\n");
244 }
else if(weights==1) {
246 }
else if(weights==2) {
255 if(verbose>1) printf(
"allocating memory for fits.\n");
257 fprintf(stderr,
"Error: cannot allocate space for fit results (%d).\n", ret);
262 strncpy(fit.
datafile, dftfile, FILENAME_MAX);
265 parNr=func_par_nr[model];
266 if(model==MODEL_IGV) type=1402;
267 else if(model==MODEL_HILLB) type=844;
268 else if(model==MODEL_IHILLB) type=844;
270 for(ri=0; ri<fit.
voiNr; ri++) {
281 switch(reliability_level) {
282 case 1: tgo_nr=150; neighNr=4;
break;
283 case 3: tgo_nr=1200; neighNr=6;
break;
285 default: tgo_nr=300; neighNr=5;
break;
288 if(fixedDelay>=0.0) pmin[0]=pmax[0]=fixedDelay;
289 else {pmin[0]=0.0; pmax[0]=0.10*tstop;}
294 if(fixedBaseline>=0.0) {pmin[1]=pmax[1]=fixedBaseline;}
295 else {pmin[1]=0.80; pmax[1]=1.20;}
297 pmin[2]=0.001; pmax[2]=1.0;
299 pmin[3]=0.0; pmax[3]=1.0;
301 pmin[4]=1.0e-05; pmax[4]=1.0e+03;
306 pmin[1]=0.0; pmax[1]=5.0;
308 pmin[2]=1.0; pmax[2]=20.0;
310 pmin[3]=1.0E-6; pmax[3]=1.0E+8;
312 if(fixedBaseline>=0.0) {pmin[4]=pmax[4]=fixedBaseline;}
313 else {pmin[4]=0.5; pmax[4]=1.0;}
318 pmin[1]=-5.0; pmax[1]=0.0;
320 pmin[2]=1.0; pmax[2]=20.0;
322 pmin[3]=1.0E-6; pmax[3]=1.0E+8;
324 if(fixedBaseline>=0.0) {pmin[4]=pmax[4]=fixedBaseline;}
325 else {pmin[4]=0.5; pmax[4]=5.0;}
332 if(verbose>0) {printf(
"fitting\n"); fflush(stdout);}
333 for(ri=0; ri<dft.
voiNr; ri++) {
336 fprintf(stdout,
" fitting %s: ", dft.
voi[ri].
name);
338 }
else if(dft.
voiNr>1 && verbose>0) {
339 fprintf(stdout,
"."); fflush(stdout);
343 x=dft.
x; ymeas=dft.
voi[ri].
y; yfit=dft.
voi[ri].
y2;
344 w=dft.
voi[ri].
y3;
for(fi=0; fi<dataNr; fi++) w[fi]=dft.
w[fi];
347 fit.
voi[ri].
wss=3.402823e+38;
350 ret=
tgo(pmin, pmax, func, NULL, parNr, neighNr,
351 &fit.
voi[ri].
wss, fit.
voi[ri].
p, tgo_nr, 0, verbose-5);
353 fprintf(stderr,
"Error %d in TGO.\n", ret);
364 if(ret==0) {
if(verbose>2) fprintf(stdout,
"ok\n");}
365 else fprintf(stderr,
"warning, fit collided with the limits.\n");
374 if(dft.
voiNr==1) strcpy(tmp,
"");
else sprintf(tmp,
"[%d]", ri+1);
377 for(fi=0; fi<dataNr; fi++) {
378 a=ymeas[fi]-yfit[fi];
381 printf(
"WSS%s := %g\n", tmp, wss);
383 for(pi=k=0; pi<parNr; pi++)
if(pmax[pi]>pmin[pi]) k++;
384 printf(
"Nr_of_fitted_parameters%s := %d\n", tmp, k);
386 for(fi=n=0; fi<dataNr; fi++)
if(w[fi]>0.0) n++;
387 printf(
"Nr_of_fitted_samples%s := %d\n", tmp, n);
389 aic=
aicSS(wss, n, k); printf(
"AIC%s := %g\n", tmp, aic);
394 printf(
"\n Frame Time Value Fitted Weight \n");
395 for(fi=0; fi<dataNr; fi++)
396 printf(
" %02d %8.3f %12.4f %12.4f %8.4f\n",
397 fi+1, x[fi], ymeas[fi], yfit[fi], w[fi]);
400 printf(
" fitted parameters:\n");
401 for(pi=0; pi<fit.
voi[ri].
parNr; pi++)
402 printf(
" p[%d] := %g [%g, %g]\n",
403 pi+1, fit.
voi[ri].
p[pi], pmin[pi], pmax[pi]);
406 if(verbose>0) fprintf(stdout,
"\n");
412 for(ri=0; ri<dft.
voiNr; ri++) {
413 for(pi=0; pi<parNr; pi++) par_tmp[pi]=fit.
voi[ri].
p[pi];
416 fit.
voi[ri].
p[0]=-par_tmp[2];
417 fit.
voi[ri].
p[1]= par_tmp[3];
418 fit.
voi[ri].
p[2]= par_tmp[4];
419 fit.
voi[ri].
p[3]= par_tmp[0];
420 fit.
voi[ri].
p[4]= par_tmp[1];
424 fit.
voi[ri].
p[0]=par_tmp[1];
425 fit.
voi[ri].
p[1]=par_tmp[2];
426 fit.
voi[ri].
p[2]=par_tmp[3];
427 fit.
voi[ri].
p[3]=par_tmp[4];
428 fit.
voi[ri].
p[4]=par_tmp[0];
442 if(verbose>1) printf(
"saving results in %s\n", fitfile);
444 fprintf(stderr,
"Error in writing '%s': %s\n", fitfile,
fiterrmsg);
452 if(verbose>1) printf(
"saving SVG plot\n");
459 fprintf(stderr,
"Error: cannot save fitted curves.\n");
463 for(ri=0; ri<dft.
voiNr; ri++)
for(fi=0; fi<dft.
frameNr; fi++)
468 strcat(tmp, model_name[model]); strcat(tmp,
" ");
472 fprintf(stderr,
"Error (%d) in writing '%s'.\n", ret, svgfile);
476 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
493double func_igv(
int parNr,
double *p,
void *fdata)
504 for(i=0; i<parNr; i++) printf(
" p[%d]=%g", i, p[i]);
509 for(i=0, wss=0.0; i<dataNr; i++) {
514 yfit[i]=pa[2]*pow(xt, pa[3])*exp(-xt/pa[4]);
516 yfit[i]=pa[1]-yfit[i];
519 if(min_meas==MINMEAS_SS) v*=v;
else v=fabs(v);
526double func_hillb(
int parNr,
double *p,
void *fdata)
537 for(i=0; i<parNr; i++) printf(
" p[%d]=%g", i, p[i]);
542 for(i=0, wss=0.0; i<dataNr; i++) {
548 yfit[i]=pa[1]*v/(v+pa[3]);
553 if(min_meas==MINMEAS_SS) v*=v;
else v=fabs(v);
double aicSS(double ss, const int n, const int k)
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)
double atof_dpi(char *str)
int dftdup(DFT *dft1, DFT *dft2)
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 fit_allocate_with_dft(FIT *fit, DFT *dft)
Header file for libtpccurveio.
int fitWrite(FIT *fit, char *filename)
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
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 plot_fit_svg(DFT *dft1, DFT *dft2, char *main_title, char *fname, int verbose)
int dftWeightByFreq(DFT *dft)
Header file for libtpcsvg.
char studynr[MAX_STUDYNR_LEN+1]
char datafile[FILENAME_MAX]
char name[MAX_REGIONNAME_LEN+1]