10#include "tpcclibConfig.h"
36double func_wliv(
int parNr,
double *p,
void*);
38typedef struct FITDATA {
67static char *info[] = {
68 "Non-linear fitting of the liver radiowater model to TTACs using arterial",
69 "BTAC as the input function. Small delay of arterial input function is",
70 "fitted by default, as well as larger delay and dispersion representing",
71 "the portal vein input from GI system.",
73 "Usage: @P [Options] btacfile ttacfile [parfile]",
77 " Delay time (sec) between BTAC and liver is constrained to given value.",
79 " Delay time (sec) in GI system is constrained to given value.",
81 " Dispersion in GI system is constrained to given rate constant (1/min);",
82 " dispersion time constant tau=1/kGI.",
84 " Blood volume is constrained to given value (mL/mL of liver).",
86 " All weights are set to 1.0 (no weighting), or based on TTAC frame",
87 " lengths; by default, weights in TTAC file are used, if available.",
89 " Fitted and measured TACs are plotted in specified SVG file.",
91 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
94 "Sample times must be in seconds, unless units are specified in the file.",
96 "See also: fit_h2o, bfmh2o, fitk2, sim_wliv, simdisp",
98 "Keywords: TAC, liver, modelling, perfusion, radiowater",
117int main(
int argc,
char **argv)
119 int ai, help=0, version=0, verbose=1;
120 char btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], parfile[FILENAME_MAX],
121 svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
123 double fixed_kgi=nan(
"");
124 double fixed_vb=nan(
"");
125 double fixed_dt_liver=nan(
"");
126 double fixed_dt_gi=nan(
"");
133 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
134 btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
136 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
138 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
139 if(strcasecmp(cptr,
"W1")==0) {
141 }
else if(strcasecmp(cptr,
"WF")==0) {
143 }
else if(strncasecmp(cptr,
"kGI=", 4)==0 && strlen(cptr)>4) {
144 if(!
atofCheck(cptr+4, &fixed_kgi) && fixed_kgi>=0.0)
continue;
145 }
else if(strncasecmp(cptr,
"VB=", 3)==0 && strlen(cptr)>3) {
146 if(!
atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0)
continue;
147 }
else if(strncasecmp(cptr,
"DELAY=", 6)==0 && strlen(cptr)>6) {
148 if(!
atofCheck(cptr+6, &fixed_dt_liver) && fixed_dt_liver>=0.0)
continue;
149 }
else if(strncasecmp(cptr,
"DELAYL=", 7)==0 && strlen(cptr)>7) {
150 if(!
atofCheck(cptr+7, &fixed_dt_liver) && fixed_dt_liver>=0.0)
continue;
151 }
else if(strncasecmp(cptr,
"DELAYP=", 7)==0 && strlen(cptr)>7) {
152 if(!
atofCheck(cptr+7, &fixed_dt_gi) && fixed_dt_gi>=0.0)
continue;
153 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
154 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
155 }
else if(strncasecmp(cptr,
"SIM=", 4)==0 && strlen(cptr)>4) {
156 strlcpy(simfile, cptr+4, FILENAME_MAX);
continue;
158 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
167 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
172 if(ai<argc)
strlcpy(btacfile, argv[ai++], FILENAME_MAX);
173 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
174 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
176 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
181 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
187 printf(
"btacfile := %s\n", btacfile);
188 printf(
"ttacfile := %s\n", ttacfile);
189 if(parfile[0]) printf(
"parfile := %s\n", parfile);
190 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
191 if(simfile[0]) printf(
"simfile := %s\n", simfile);
192 printf(
"weights := %d\n",
weights);
193 if(!isnan(fixed_kgi)) printf(
"fixed_kGI := %g\n", fixed_kgi);
194 if(!isnan(fixed_vb)) printf(
"fixed_vb := %g\n", fixed_vb);
195 if(!isnan(fixed_dt_liver)) printf(
"fixed_dt_liver := %g\n", fixed_dt_liver);
196 if(!isnan(fixed_dt_gi)) printf(
"fixed_dt_gi := %g\n", fixed_dt_gi);
204 if(verbose>1) printf(
"reading TACs\n");
214 printf(
"ttacNr := %d\n", ttac.
tacNr);
215 printf(
"ttac.sampleNr := %d\n", ttac.
sampleNr);
225 printf(
"btacNr := %d\n", btac.
tacNr);
226 printf(
"btac.sampleNr := %d\n", btac.
sampleNr);
230 if(verbose>0) fprintf(stderr,
"Warning: BTAC file contains more than one TAC.\n");
235 fprintf(stderr,
"Error: too few samples.\n");
240 fprintf(stderr,
"Error: data contains missing values.\n");
255 fprintf(stderr,
"Error: check and set the data units.\n");
261 fprintf(stderr,
"Error: invalid data sample times.\n");
265 printf(
"xmin := %g\n", xmin);
266 printf(
"xmax := %g\n", xmax);
282 for(
int i=0; i<ttac.
sampleNr; i++) ttac.
w[i]=1.0;
286 for(
int i=0; i<ttac.
sampleNr; i++) ttac.
w[i]=1.0;
295 if(verbose>2) printf(
"wsampleNr := %u\n", wsampleNr);
297 fprintf(stderr,
"Error: too few samples for fitting.\n");
305 if(verbose>1) printf(
"preparing space for parameters\n");
318 iftPut(&par.
h,
"program", buf, 0, NULL);
322 for(
int i=0; i<par.
tacNr; i++) {
338 iftPut(&par.
h,
"inputfile", btacfile, 0, NULL);
339 iftPut(&par.
h,
"datafile", ttacfile, 0, NULL);
345 if(verbose==1) {printf(
"\nfitting...\n"); fflush(stdout);}
348 for(
int ri=0; ri<ttac.
tacNr; ri++) {
349 if(verbose>1) {printf(
"\nfitting %s\n", ttac.
c[ri].
name); fflush(stdout);}
354 fitdata.yi=btac.
c[0].
y;
365 fitdata.yt=ttac.
c[ri].
y;
367 fitdata.syt=ttac.
c[ttac.
tacNr+ri].
y;
368 if(verbose>10) fitdata.verbose=verbose-10;
else fitdata.verbose=0;
372 fprintf(stderr,
"Error: cannot initiate NLLS.\n"); fflush(stderr); failed++;
389 if(!isnan(fixed_vb)) {
392 if(!isnan(fixed_dt_liver)) {
395 if(!isnan(fixed_dt_gi)) {
398 if(!isnan(fixed_kgi)) {
408 printf(
"\nTime\tTTAC\tsimTTAC\n");
409 for(
unsigned int i=0; i<fitdata.nt; i++)
410 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
411 printf(
"\n"); fflush(stdout);
413 if(verbose>1) {printf(
"\twss := %g\n", wss); fflush(stdout);}
430 printf(
"initial guess\n");
436 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr); failed++;
441 printf(
"\nTime\tTTAC\tsimTTAC\n");
442 for(
unsigned int i=0; i<fitdata.nt; i++)
443 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
444 printf(
"\n"); fflush(stdout);
447 if(verbose>2) printf(
" wss1 := %g\n", wss1);
450 if(verbose>2) printf(
" AIC1 := %g\n", aic1);
473 if(!isnan(fixed_vb)) {
476 if(!isnan(fixed_dt_liver)) {
480 printf(
"initial guess\n");
486 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr); failed++;
491 printf(
"\nTime\tTTAC\tsimTTAC\n");
492 for(
unsigned int i=0; i<fitdata.nt; i++)
493 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
494 printf(
"\n"); fflush(stdout);
497 if(verbose>2) printf(
" wss2 := %g\n", wss2);
500 if(verbose>2) printf(
" AIC2 := %g\n", aic2);
539 if(verbose>1) printf(
" saving %s\n", parfile);
540 FILE *fp=fopen(parfile,
"w");
542 fprintf(stderr,
"Error: cannot open file for writing.\n");
551 if(verbose>0) printf(
"parameters saved in %s\n", parfile);
559 if(verbose>1) printf(
"plotting measured and fitted data\n");
562 for(
int r=0; r<ttac.
tacNr; r++)
572 if(verbose>0) printf(
"Measured and fitted data plotted in %s\n", svgfile);
581 if(verbose>1) printf(
"calculating simulated TTACs\n");
586 fprintf(stderr,
"Error: cannot allocate space for simulated TTACs\n");
599 fitdata.yi=btac.
c[0].
y;
613 for(
int i=0; i<sim.
tacNr; i++) {
614 fitdata.yt=fitdata.syt=sim.
c[i].
y;
615 func_wliv(7, par.
r[i].
p, &fitdata);
619 if(verbose>1) printf(
"writing %s\n", simfile);
620 FILE *fp; fp=fopen(simfile,
"w");
622 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
628 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
631 if(verbose>=0) {printf(
"%s saved.\n", simfile); fflush(stdout);}
645double func_wliv(
int parNr,
double *p,
void *fdata)
647 FITDATA *d=(FITDATA*)fdata;
649 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
650 if(parNr!=7 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1)
return(nan(
""));
652 printf(
"p[]: %g", p[0]);
653 for(
int i=1; i<parNr; i++) printf(
" %g", p[i]);
654 printf(
"\n"); fflush(stdout);
658 double K1a=p[0]/60.0;
659 double K1p=p[1]/60.0;
664 double kGI=p[6]/60.0;
667 double x[d->ni], *ca=d->yi;
668 for(
unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+LdT;
671 double x2[d->ni], cp[d->ni], sy[d->ni];
672 for(
unsigned int i=0; i<d->ni; i++) x2[i]=x[i]+PdT;
674 for(
unsigned int i=0; i<d->ni; i++) cp[i]=0.0;
676 for(
unsigned int i=0; i<d->ni; i++) sy[i]=d->yi[i];
677 if(
simDispersion(x2, sy, d->ni, 1.0/kGI, 0.0, cp)!=0)
return(nan(
""));
679 if(
liInterpolate(x2, sy, d->ni, x, cp, NULL, NULL, d->ni, 3, 1, 0))
return(nan(
""));
683 if(
simC1DI(x, ca, cp, d->ni, K1a, K1p, k2, sy)!=0)
return(nan(
""));
685 for(
unsigned int i=0; i<d->ni; i++) sy[i]*=(1.0-Vb);
687 for(
unsigned int i=0; i<d->ni; i++) sy[i]+= Vb*(K1a*ca[i] + K1p*cp[i])/(K1a+K1p);
689 for(
unsigned int i=0; i<d->ni; i++) sy[i]+= Vb*ca[i];
692 if(d->xt1==NULL || d->xt2==NULL) {
693 if(
liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
696 if(
liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
701 if(d->verbose>2) {fprintf(stdout,
"computing WSS...\n"); fflush(stdout);}
703 for(
unsigned i=0; i<d->nt; i++) {
704 double v=d->syt[i] - d->yt[i];
double aicSS(double ss, const unsigned int n, const unsigned int k)
Calculate corrected AIC.
unsigned int parFreeNr(const unsigned int n, double *pLower, double *pUpper)
Calculate the number of free parameters.
char * ctime_r_int(const time_t *t, char *buf)
Convert calendar time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
int atofCheck(const char *s, double *v)
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET(double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear TAC interpolation and/or integration to PET frames.
unsigned int modelCodeIndex(const char *s)
void nloptInit(NLOPT *nlo)
int nloptAllocate(NLOPT *nlo, unsigned int parNr)
void nloptFree(NLOPT *nlo)
void nloptWrite(NLOPT *d, FILE *fp)
char * parFormattxt(parformat c)
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
int parFormatFromExtension(const char *s)
int parAllocateWithTAC(PAR *par, TAC *tac, int parNr, TPCSTATUS *status)
Allocate PAR based on data in TAC.
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)
int simC1DI(double *t, double *cba, double *cbb, const int nr, const double k1a, const double k1b, const double k2, double *ct)
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
int nloptSimplexARRS(NLOPT *nlo, unsigned int maxIter, TPCSTATUS *status)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
double(* _fun)(int, double *, void *)
IFT h
Optional (but often useful) header information.
char name[MAX_PARNAME_LEN+1]
char name[MAX_TACNAME_LEN+1]
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
int tacAllocateMoreSamples(TAC *tac, int addNr)
Allocate memory for more samples in TAC data.
int tacAllocateMore(TAC *tac, int tacNr)
int tacPlotFitSVG(TAC *tac1, TAC *tac2, const char *main_title, const double x1, const double x2, const double y1, const double y2, const char *fname, TPCSTATUS *status)
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
int tacSortByTime(TAC *d, TPCSTATUS *status)
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacIsWeighted(TAC *tac)
unsigned int tacWSampleNr(TAC *tac)
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Header file for libtpcbfm.
Header file for libtpccm.
Header file for library libtpcextensions.
weights
Is data weighted, or are weight factors available with data?
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
Header file for library libtpcift.
@ ISOTOPE_UNKNOWN
Unknown.
Header file for libtpcli.
Header file for libtpclinopt.
Header file for library libtpcnlopt.
Header file for libtpcpar.
@ PAR_FORMAT_FIT
Function fit format of Turku PET Centre.
@ PAR_FORMAT_UNKNOWN
Unknown format.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Header file for libtpcrand.
Header file for library libtpctac.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Header file for libtpctacmod.