9#include "tpcclibConfig.h"
25double func1821(
int parNr,
double *p,
void*);
26double func1801(
int parNr,
double *p,
void*);
28double (*func)(
int parNr,
double *p,
void*);
29double *x, *ymeas, *yfit, *w;
36static char *info[] = {
37 "Non-linear fitting of the sum of Hill and Hill derivative function to",
38 "the PET time-activity curves (TACs):",
39 "f(x) = A * { [n*xt^(n-1)]/[h^n+xt^n] - [n*xt^(2*n-1)]/[h^n+xt^n]^2 ",
40 " + [k*xt^n]/[h^n+xt^n] }",
41 ", where xt=x-dt and n>=1.",
43 "Usage: @P [Options] tacfile [parfile]",
47 " Hill function without the Hill derivative function is used;",
48 " f(x) = (A*xt^n)/(h^n+xt^n).",
49 " -w1 All weights are set to 1.0 (no weighting); by default, weights in",
50 " data file are used, if available.",
52 " Weight by sampling interval.",
54 " Parameter k is constrained to given value; setting k to zero causes",
55 " the function to approach zero.",
57 " Parameter n (HillSlope) is constrained to the given value;",
58 " n<1 is not allowed.",
59 " -delay=<<value>|mean|median>",
60 " Delay time (dt) is constrained to specified value or to mean or median",
66 " Error is returned if MRL check is not passed.",
68 " Fitted parameters are also written in result file format.",
70 " Fitted and measured TACs are plotted in specified SVG file.",
72 " Fitted TACs are written in TAC format.",
75 "TAC file must contain at least 2 columns, sample times (x) and",
76 "concentrations (y).",
77 "Weights can be specified as usual if data is in DFT format.",
79 "Program writes the fit start and end times, nr of points, WSS,",
80 "and parameters of the fitted function to the fit file.",
82 "See also: fit2dat, fit_sigm, fit_bpr, fit_ppf, fit_exp, fit_ratf",
84 "Keywords: curve fitting, Hill function",
103int main(
int argc,
char **argv)
105 int ai, help=0, version=0, verbose=1;
106 int fi, pi, ri, m, n, ret;
109 double fixed_n=nan(
"");
110 double fixed_k=nan(
"");
111 double fixed_delay=nan(
"");
115 char datfile[FILENAME_MAX], fitfile[FILENAME_MAX], parfile[FILENAME_MAX],
116 svgfile[FILENAME_MAX], resfile[FILENAME_MAX], *cptr, temp[512];
120 double tstart, tstop, miny, maxy, maxt;
121 int tgo_nr, iter_nr, neigh_nr;
128 def_pmin[0]=0.0; def_pmax[0]=0.0;
129 def_pmin[1]=1.0E-06; def_pmax[1]=1.0E+06;
130 def_pmin[2]=1.0E-06; def_pmax[2]=200.0;
131 def_pmin[3]=1.0; def_pmax[3]=10.0;
132 def_pmin[4]=0.0; def_pmax[4]=20.0;
138 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
139 datfile[0]=fitfile[0]=parfile[0]=svgfile[0]=resfile[0]=(char)0;
143 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
144 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
146 if(strcasecmp(cptr,
"W1")==0) {
148 }
else if(strcasecmp(cptr,
"WF")==0) {
150 }
else if(strcasecmp(cptr,
"HILL")==0) {
151 type=1801; parNr=4;
continue;
152 }
else if(strncasecmp(cptr,
"N=", 2)==0) {
154 def_pmin[3]=def_pmax[3]=fixed_n;
continue;
156 }
else if(strncasecmp(cptr,
"k=", 2)==0 && strlen(cptr)>2) {
158 def_pmin[4]=def_pmax[4]=fixed_k;
continue;
160 }
else if(strncasecmp(cptr,
"DELAY=", 6)==0 && strlen(cptr)>6) {
162 if(strcasecmp(cptr,
"MEAN")==0) {fix_delay=2;
continue;}
163 else if(strncasecmp(cptr,
"AVERAGE", 2)==0) {fix_delay=2;
continue;}
164 if(strcasecmp(cptr,
"MEDIAN")==0) {fix_delay=3;
continue;}
166 fix_delay=1; def_pmin[0]=def_pmax[0]=fixed_delay;
169 }
else if(strncasecmp(cptr,
"DLOW=", 5)==0) {
171 }
else if(strcasecmp(cptr,
"MRL")==0) {
172 MRL_check=1;
continue;
173 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
174 strcpy(svgfile, cptr+4);
continue;
175 }
else if(strncasecmp(cptr,
"FIT=", 4)==0 && strlen(cptr)>4) {
176 strcpy(fitfile, cptr+4);
continue;
177 }
else if(strncasecmp(cptr,
"RES=", 4)==0 && strlen(cptr)>4) {
178 strcpy(resfile, cptr+4);
continue;
180 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
185 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
190 for(; ai<argc; ai++) {
191 if(!datfile[0]) {strcpy(datfile, argv[ai]);
continue;}
192 else if(!parfile[0]) {strcpy(parfile, argv[ai]);
continue;}
193 fprintf(stderr,
"Error: invalid argument '%s'\n", argv[ai]);
196 if(!parfile[0]) strcpy(parfile,
"stdout");
197 if(type==1821) func=func1821;
else func=func1801;
202 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
208 printf(
"datfile := %s\n", datfile);
209 printf(
"parfile := %s\n", parfile);
210 printf(
"fitfile := %s\n", fitfile);
211 printf(
"resfile := %s\n", resfile);
212 printf(
"svgfile := %s\n", svgfile);
213 printf(
"MRL_check := %d\n", MRL_check);
214 if(!isnan(fixed_n)) printf(
"fixed_n := %g\n", fixed_n);
215 if(!isnan(fixed_k)) printf(
"fixed_k := %g\n", fixed_k);
216 if(!isnan(dlowtime)) printf(
"dlowtime := %g\n", dlowtime);
217 printf(
"fix_delay := %d\n", fix_delay);
218 if(fix_delay==1) printf(
"fixed_delay := %g\n", fixed_delay);
219 printf(
"type := %d\n", type);
220 printf(
"weights := %d\n", weights);
227 if(verbose>1) printf(
"reading %s\n", datfile);
229 fprintf(stderr,
"Error in reading '%s': %s\n", datfile,
dfterrmsg);
239 ret=
dftMinMax(&dft, &tstart, &tstop, &miny, &maxy);
241 fprintf(stderr,
"Error: invalid contents in %s\n", datfile);
244 if(tstop<=0.0 || maxy<=0.0) {
245 fprintf(stderr,
"Error: invalid contents in %s\n", datfile);
248 if(tstart<0.0) fprintf(stderr,
"Warning: negative x value(s).\n");
249 if(miny<0.0) fprintf(stderr,
"Warning: negative y value(s).\n");
255 }
else if(weights==1) {
257 }
else if(weights==2) {
260 for(fi=0; fi<dft.
frameNr; fi++)
if(isnan(dft.
voi[0].
y[fi])) dft.
w[fi]=0;
262 printf(
"data_weights := %g", dft.
w[0]);
263 for(fi=1; fi<dft.
frameNr; fi++) printf(
", %g", dft.
w[fi]);
270 if(dft.
voiNr==1 && (fix_delay==2 || fix_delay==3)) {
271 fprintf(stderr,
"Note: delay setting ignored because only one TAC to fit.\n");
278 if(verbose>1) printf(
"allocating memory for fits.\n");
281 fprintf(stderr,
"Error: cannot allocate space for fit results (%d).\n", ret);
286 strncpy(fit.
datafile, datfile, FILENAME_MAX);
289 for(ri=0; ri<dft.
voiNr; ri++) {
301 if(fix_delay==2 || fix_delay==3) {
303 if(verbose>0) {printf(
"fitting common delay time\n"); fflush(stdout);}
304 def_pmin[0]=def_pmax[0]=0.0;
305 for(ri=0; ri<dft.
voiNr; ri++) {
307 printf(
"%d: %s\n", ri+1, dft.
voi[ri].
name); fflush(stdout);}
310 x=dft.
x; ymeas=dft.
voi[ri].
y; yfit=dft.
voi[ri].
y2; w=dft.
w;
312 fit.
voi[ri].
wss=3.402823e+38;
315 for(pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
317 ret=
dftMinMaxTAC(&dft, ri, NULL, &maxt, NULL, &maxv, NULL, NULL, NULL, NULL);
319 fprintf(stderr,
"Error: invalid TAC data for fitting.\n");
322 if(verbose>4) printf(
" maxt := %g\n maxv := %g\n", maxt, maxv);
324 pmin[0]=-0.05*fabs(tstop); def_pmin[0]+=pmin[0];
325 pmax[0]=0.95*fabs(maxt); def_pmax[0]+=pmax[0];
330 pmax[2]=0.2*fabs(maxt);
332 printf(
" constraints :=");
333 for(pi=0; pi<parNr; pi++) printf(
" [%g,%g]", pmin[pi], pmax[pi]);
340 neigh_nr=6; iter_nr=1; tgo_nr=1000;
341 ret=
tgo(pmin, pmax, func, NULL, parNr, neigh_nr, &fit.
voi[ri].
wss,
342 fit.
voi[ri].
p, tgo_nr, iter_nr, verbose-5);
344 fprintf(stderr,
"Error %d in TGO.\n", ret);
350 if(ret!=0 && verbose>0)
351 fprintf(stderr,
"Warning: fit collided with the limits.\n");
353 printf(
" fitted parameters:");
354 for(pi=0; pi<parNr; pi++) printf(
" %g", fit.
voi[ri].
p[pi]);
355 printf(
"\n wss := %g\n", fit.
voi[ri].
wss);
357 if(verbose==1 && dft.
voiNr>1) {printf(
"."); fflush(stdout);}
359 if(verbose==1) {printf(
"\n");}
362 double dfm[dft.
voiNr], delay_mean, delay_median, delay_sd, v;
363 for(ri=0; ri<dft.
voiNr; ri++) dfm[ri]=fit.
voi[ri].
p[0];
367 printf(
"mean_delay_time := %6.4f +- %6.4f\n", delay_mean, delay_sd);
368 printf(
"median_delay_time := %.4f\n", delay_median);
370 if(fix_delay==2) v=delay_mean;
else v=delay_median;
371 def_pmin[0]/=(double)dft.
voiNr; def_pmax[0]/=(double)dft.
voiNr;
372 if(v<def_pmin[0] || v>def_pmax[0]) {
374 printf(
"def_pmin[0] := %g\n", def_pmin[0]);
375 printf(
"def_pmax[0] := %g\n", def_pmax[0]);
378 "Error: delay time could not be fixed to regional mean or median\n");
381 def_pmin[0]=def_pmax[0]=v;
382 if(verbose>0) printf(
"fixed_delay_time := %g\n", def_pmin[0]);
390 if(verbose>0) {printf(
"fitting\n"); fflush(stdout);}
391 for(ri=0; ri<dft.
voiNr; ri++) {
392 if(verbose>1) {printf(
"%d: %s\n", ri+1, dft.
voi[ri].
name); fflush(stdout);}
394 x=dft.
x; ymeas=dft.
voi[ri].
y; yfit=dft.
voi[ri].
y2; w=dft.
w;
396 fit.
voi[ri].
wss=3.402823e+38;
399 for(pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
402 ret=
dftMinMaxTAC(&dft, ri, NULL, &maxt, NULL, &maxv, NULL, NULL, NULL, NULL);
404 fprintf(stderr,
"Error: invalid TAC data for fitting.\n");
407 if(verbose>4) printf(
" maxt := %g\n maxv := %g\n", maxt, maxv);
410 pmin[0]=-0.05*fabs(tstop);
411 pmax[0]=0.95*fabs(maxt);
419 printf(
" constraints :=");
420 for(pi=0; pi<parNr; pi++) printf(
" [%g,%g]", pmin[pi], pmax[pi]);
427 neigh_nr=6; iter_nr=1; tgo_nr=1000;
428 ret=
tgo(pmin, pmax, func, NULL, parNr, neigh_nr, &fit.
voi[ri].
wss,
429 fit.
voi[ri].
p, tgo_nr, iter_nr, verbose-5);
431 fprintf(stderr,
"Error %d in TGO.\n", ret);
437 if(ret!=0 && verbose>0)
438 fprintf(stderr,
"Warning: fit collided with the limits.\n");
445 printf(
" fitted parameters:");
446 for(pi=0; pi<parNr; pi++) printf(
" %g", fit.
voi[ri].
p[pi]);
447 printf(
"\n wss := %g\n", fit.
voi[ri].
wss);
450 if(verbose>1 && type!=1801) {
451 double a, b, c, A, h, n, s, maxx1, maxx2;
452 A=fit.
voi[ri].
p[1]; h=fit.
voi[ri].
p[2]; n=fit.
voi[ri].
p[3];
453 a=2.0*n-n*n-1.0; b=-n*(n-1.0)*pow(h, n); c=n*(n-1.0)*pow(h, 2.0*n);
454 s=sqrt(b*b - 4.0*a*c);
455 maxx1=pow((-b-s)/a, 1.0/n)/pow(2.0, 1.0/n);
456 maxx2=pow((-b+s)/a, 1.0/n)/pow(2.0, 1.0/n);
457 double hn, xn, hnxn, hilld;
459 xn=pow(maxx1, n); hnxn=hn+xn;
460 hilld= A*n*pow(maxx1, n-1.0)/hnxn - n*pow(maxx1, 2.0*n-1.0)/(hnxn*hnxn);
461 printf(
"maxx1=%g maxy1=%g\n", maxx1+fit.
voi[ri].
p[0], hilld);
462 xn=pow(maxx2, n); hnxn=hn+xn;
463 hilld= A*n*pow(maxx2, n-1.0)/hnxn - n*pow(maxx2, 2.0*n-1.0)/(hnxn*hnxn);
464 printf(
"maxx2=%g maxy2=%g\n", maxx2+fit.
voi[ri].
p[0], hilld);
468 if(verbose>1) printf(
"Checking the MRL.\n");
470 if(m>3 && m>dataNr/3) {
472 fprintf(stderr,
"Error: bad fit.\n");
473 fprintf(stderr,
"MRL := %d / %d\n", m, dataNr);
478 if(m>2 && m>dataNr/4) {
479 fprintf(stderr,
"Warning: bad fit.\n");
480 fprintf(stderr,
"MRL := %d / %d\n", m, dataNr);
481 }
else if(verbose>1) {
482 printf(
"MRL test passed.\n");
483 if(verbose>2) fprintf(stderr,
"MRL := %d / %d\n", m, dataNr);
486 if(verbose==1 && dft.
voiNr>1) {printf(
"."); fflush(stdout);}
488 if(verbose==1) {printf(
"\n");}
495 if(verbose>1) printf(
"saving results in %s\n", parfile);
496 ret=
fitWrite(&fit, parfile);
if(ret) {
497 fprintf(stderr,
"Error (%d) in writing '%s': %s\n", ret, parfile,
fiterrmsg);
500 if(verbose>0) printf(
"Function parameters written in %s\n", parfile);
505 if(verbose>1) printf(
"allocating memory for results.\n");
510 fprintf(stderr,
"Error in making results: %s\n", temp);
513 n=0; strcpy(res.
parname[n++],
"Function");
514 strcpy(res.
parname[n++],
"Delay");
521 strcpy(res.
parname[n++],
"WSS");
523 sprintf(res.
datarange,
"%g - %g", tstart, tstop);
526 if(verbose>1) printf(
"saving results in %s\n", resfile);
527 if(
resWrite(&res, resfile, verbose-3)) {
528 fprintf(stderr,
"Error in writing '%s': %s\n", resfile,
reserrmsg);
532 if(verbose>1) printf(
"Function parameters written in %s\n", resfile);
541 if(verbose>1) printf(
"creating SVG plot\n");
543 char tmp[FILENAME_MAX];
547 printf(
"calculating fitted curve at automatically generated sample times\n");
551 fprintf(stderr,
"Error %d in memory allocation for fitted curves.\n", ret);
556 for(ri=0, ret=0; ri<adft.
voiNr; ri++) {
557 for(fi=0; fi<adft.
frameNr; fi++) {
558 ret=
fitEval(&fit.
voi[ri], adft.
x[fi], &a);
if(ret!=0)
break;
559 adft.
voi[ri].
y[fi]=a;
564 fprintf(stderr,
"Error: cannot calculate fitted TAC for '%s'.\n", svgfile);
570 if(verbose>1) printf(
"writing %s\n", svgfile);
574 svgfile, verbose-10);
576 fprintf(stderr,
"Error (%d) in writing '%s'.\n", ret, svgfile);
580 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
589 if(verbose>1) printf(
"saving fitted curves in %s\n", fitfile);
591 for(ri=0, ret=0; ri<dft.
voiNr; ri++) {
592 for(fi=0; fi<dft.
frameNr; fi++) {
593 ret=
fitEval(&fit.
voi[ri], dft.
x[fi], &a);
if(ret!=0)
break;
599 fprintf(stderr,
"Error: cannot calculate fitted TACs for '%s'.\n", fitfile);
604 sprintf(dft.
comments,
"# program := %s\n", temp);
607 fprintf(stderr,
"Error in writing '%s': %s\n", fitfile,
dfterrmsg);
611 if(verbose>0) printf(
"Fitted TACs written in %s\n", fitfile);
627double func1821(
int parNr,
double *p,
void *fdata)
630 double t, A, h, n, k,
631 xt, xn, hn, hnxn, hill, hilld, v, wss;
640 t=pa[0]; A=pa[1]; h=pa[2]; n=pa[3]; k=pa[4];
644 for(i=0, wss=0.0; i<dataNr; i++)
if(w[i]>0.0) {
645 xt=x[i]-t;
if(xt<=0.0) {
646 yfit[i]=0.0; hilld=0.0;
648 xn=pow(xt, n); hnxn=hn+xn;
649 hilld= n*pow(xt, n-1.0)/hnxn - n*pow(xt, 2.0*n-1.0)/(hnxn*hnxn);
651 if(hilld>=0.0 && hilld<1.0E20 && hill>=0.0 && hill<1.0E20) {
652 yfit[i]=A*(hilld+hill);
670 xn=pow(xt, n); hnxn=hn+xn;
671 hilld= n*pow(xt, n-1.0)/hnxn - n*pow(xt, 2.0*n-1.0)/(hnxn*hnxn);
673 v=hilld/(hill+hilld);
674 v*=10000.0; v-=1.0;
if(v<0.0) v=0.0;
675 v+=1.0; v=v*v*v*v; penalty*=v;
686double func1801(
int parNr,
double *p,
void *fdata)
690 xt, xn, hn, hnxn, hill, v, wss;
698 t=pa[0]; A=pa[1]; h=pa[2]; n=pa[3];
702 for(i=0, wss=0.0; i<dataNr; i++)
if(w[i]>0.0) {
703 xt=x[i]-t;
if(xt<=0.0) {
706 xn=pow(xt, n); hnxn=hn+xn;
708 if(hill>=0.0 && hill<1.0E20) {
713 v=yfit[i]-ymeas[i]; v*=v;
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 dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
int fitToResult(FIT *fit, RES *res, char *status)
int fit_allocate_with_dft(FIT *fit, DFT *dft)
Header file for libtpccurveio.
int fitEval(FitVOI *r, double x, double *y)
int fitWrite(FIT *fit, char *filename)
int resWrite(RES *res, char *filename, int verbose)
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)
int mrl_between_tacs(double y1[], double y2[], int n)
double dmean(double *data, int n, double *sd)
double dmedian(double *data, int n)
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 datafile[FILENAME_MAX]
char studynr[MAX_STUDYNR_LEN+1]
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]