10#include "tpcclibConfig.h"
32double func_wliv(
int parNr,
double *p,
void*);
34typedef struct FITDATA {
63static char *info[] = {
64 "Non-linear fitting of the liver radiowater model to TTACs using arterial",
65 "BTAC as the input function. Small delay of arterial input function is",
66 "fitted by default, as well as larger delay and dispersion representing",
67 "the portal vein input from GI system.",
69 "Usage: @P [Options] btacfile ttacfile [parfile]",
73 " Delay time (sec) between BTAC and liver is constrained to given value.",
75 " Delay time (sec) in GI system is constrained to given value.",
77 " Dispersion in GI system is constrained to given rate constant (1/min);",
78 " dispersion time constant tau=1/kGI.",
80 " Blood volume is constrained to given value (mL/mL of liver).",
82 " All weights are set to 1.0 (no weighting), or based on TTAC frame",
83 " lengths; by default, weights in TTAC file are used, if available.",
85 " Fitted and measured TACs are plotted in specified SVG file.",
87 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
90 "Sample times must be in seconds, unless units are specified in the file.",
92 "See also: fit_h2o, bfmh2o, fitk2, sim_wliv, simdisp",
94 "Keywords: TAC, liver, modelling, perfusion, radiowater",
113int main(
int argc,
char **argv)
115 int ai, help=0, version=0, verbose=1;
116 char btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], parfile[FILENAME_MAX],
117 svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
119 double fixed_kgi=nan(
"");
120 double fixed_vb=nan(
"");
121 double fixed_dt_liver=nan(
"");
122 double fixed_dt_gi=nan(
"");
129 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
130 btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
132 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
134 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
135 if(strcasecmp(cptr,
"W1")==0) {
137 }
else if(strcasecmp(cptr,
"WF")==0) {
139 }
else if(strncasecmp(cptr,
"kGI=", 4)==0 && strlen(cptr)>4) {
140 if(!
atofCheck(cptr+4, &fixed_kgi) && fixed_kgi>=0.0)
continue;
141 }
else if(strncasecmp(cptr,
"VB=", 3)==0 && strlen(cptr)>3) {
142 if(!
atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0)
continue;
143 }
else if(strncasecmp(cptr,
"DELAY=", 6)==0 && strlen(cptr)>6) {
144 if(!
atofCheck(cptr+6, &fixed_dt_liver) && fixed_dt_liver>=0.0)
continue;
145 }
else if(strncasecmp(cptr,
"DELAYL=", 7)==0 && strlen(cptr)>7) {
146 if(!
atofCheck(cptr+7, &fixed_dt_liver) && fixed_dt_liver>=0.0)
continue;
147 }
else if(strncasecmp(cptr,
"DELAYP=", 7)==0 && strlen(cptr)>7) {
148 if(!
atofCheck(cptr+7, &fixed_dt_gi) && fixed_dt_gi>=0.0)
continue;
149 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
150 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
151 }
else if(strncasecmp(cptr,
"SIM=", 4)==0 && strlen(cptr)>4) {
152 strlcpy(simfile, cptr+4, FILENAME_MAX);
continue;
154 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
163 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
168 if(ai<argc)
strlcpy(btacfile, argv[ai++], FILENAME_MAX);
169 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
170 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
172 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
177 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
183 printf(
"btacfile := %s\n", btacfile);
184 printf(
"ttacfile := %s\n", ttacfile);
185 if(parfile[0]) printf(
"parfile := %s\n", parfile);
186 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
187 if(simfile[0]) printf(
"simfile := %s\n", simfile);
188 printf(
"weights := %d\n",
weights);
189 if(!isnan(fixed_kgi)) printf(
"fixed_kGI := %g\n", fixed_kgi);
190 if(!isnan(fixed_vb)) printf(
"fixed_vb := %g\n", fixed_vb);
191 if(!isnan(fixed_dt_liver)) printf(
"fixed_dt_liver := %g\n", fixed_dt_liver);
192 if(!isnan(fixed_dt_gi)) printf(
"fixed_dt_gi := %g\n", fixed_dt_gi);
200 if(verbose>1) printf(
"reading TACs\n");
210 printf(
"ttacNr := %d\n", ttac.
tacNr);
211 printf(
"ttac.sampleNr := %d\n", ttac.
sampleNr);
221 printf(
"btacNr := %d\n", btac.
tacNr);
222 printf(
"btac.sampleNr := %d\n", btac.
sampleNr);
226 if(verbose>0) fprintf(stderr,
"Warning: BTAC file contains more than one TAC.\n");
231 fprintf(stderr,
"Error: too few samples.\n");
236 fprintf(stderr,
"Error: data contains missing values.\n");
251 fprintf(stderr,
"Error: check and set the data units.\n");
257 fprintf(stderr,
"Error: invalid data sample times.\n");
261 printf(
"xmin := %g\n", xmin);
262 printf(
"xmax := %g\n", xmax);
278 for(
int i=0; i<ttac.
sampleNr; i++) ttac.
w[i]=1.0;
282 for(
int i=0; i<ttac.
sampleNr; i++) ttac.
w[i]=1.0;
291 if(verbose>2) printf(
"wsampleNr := %u\n", wsampleNr);
293 fprintf(stderr,
"Error: too few samples for fitting.\n");
301 if(verbose>1) printf(
"preparing space for parameters\n");
314 iftPut(&par.
h,
"program", buf, 0, NULL);
318 for(
int i=0; i<par.
tacNr; i++) {
334 iftPut(&par.
h,
"inputfile", btacfile, 0, NULL);
335 iftPut(&par.
h,
"datafile", ttacfile, 0, NULL);
341 if(verbose==1) {printf(
"\nfitting...\n"); fflush(stdout);}
344 for(
int ri=0; ri<ttac.
tacNr; ri++) {
345 if(verbose>1) {printf(
"\nfitting %s\n", ttac.
c[ri].
name); fflush(stdout);}
350 fitdata.yi=btac.
c[0].
y;
361 fitdata.yt=ttac.
c[ri].
y;
363 fitdata.syt=ttac.
c[ttac.
tacNr+ri].
y;
364 if(verbose>10) fitdata.verbose=verbose-10;
else fitdata.verbose=0;
368 fprintf(stderr,
"Error: cannot initiate NLLS.\n"); fflush(stderr); failed++;
385 if(!isnan(fixed_vb)) {
388 if(!isnan(fixed_dt_liver)) {
391 if(!isnan(fixed_dt_gi)) {
394 if(!isnan(fixed_kgi)) {
404 printf(
"\nTime\tTTAC\tsimTTAC\n");
405 for(
unsigned int i=0; i<fitdata.nt; i++)
406 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
407 printf(
"\n"); fflush(stdout);
409 if(verbose>1) {printf(
"\twss := %g\n", wss); fflush(stdout);}
426 printf(
"initial guess\n");
432 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr); failed++;
437 printf(
"\nTime\tTTAC\tsimTTAC\n");
438 for(
unsigned int i=0; i<fitdata.nt; i++)
439 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
440 printf(
"\n"); fflush(stdout);
443 if(verbose>2) printf(
" wss1 := %g\n", wss1);
446 if(verbose>2) printf(
" AIC1 := %g\n", aic1);
469 if(!isnan(fixed_vb)) {
472 if(!isnan(fixed_dt_liver)) {
476 printf(
"initial guess\n");
482 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr); failed++;
487 printf(
"\nTime\tTTAC\tsimTTAC\n");
488 for(
unsigned int i=0; i<fitdata.nt; i++)
489 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
490 printf(
"\n"); fflush(stdout);
493 if(verbose>2) printf(
" wss2 := %g\n", wss2);
496 if(verbose>2) printf(
" AIC2 := %g\n", aic2);
535 if(verbose>1) printf(
" saving %s\n", parfile);
536 FILE *fp=fopen(parfile,
"w");
538 fprintf(stderr,
"Error: cannot open file for writing.\n");
547 if(verbose>0) printf(
"parameters saved in %s\n", parfile);
555 if(verbose>1) printf(
"plotting measured and fitted data\n");
558 for(
int r=0; r<ttac.
tacNr; r++)
568 if(verbose>0) printf(
"Measured and fitted data plotted in %s\n", svgfile);
577 if(verbose>1) printf(
"calculating simulated TTACs\n");
582 fprintf(stderr,
"Error: cannot allocate space for simulated TTACs\n");
595 fitdata.yi=btac.
c[0].
y;
609 for(
int i=0; i<sim.
tacNr; i++) {
610 fitdata.yt=fitdata.syt=sim.
c[i].
y;
611 func_wliv(7, par.
r[i].
p, &fitdata);
615 if(verbose>1) printf(
"writing %s\n", simfile);
616 FILE *fp; fp=fopen(simfile,
"w");
618 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
624 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
627 if(verbose>=0) {printf(
"%s saved.\n", simfile); fflush(stdout);}
641double func_wliv(
int parNr,
double *p,
void *fdata)
643 FITDATA *d=(FITDATA*)fdata;
645 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
646 if(parNr!=7 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1)
return(nan(
""));
648 printf(
"p[]: %g", p[0]);
649 for(
int i=1; i<parNr; i++) printf(
" %g", p[i]);
650 printf(
"\n"); fflush(stdout);
654 double K1a=p[0]/60.0;
655 double K1p=p[1]/60.0;
660 double kGI=p[6]/60.0;
663 double x[d->ni], *ca=d->yi;
664 for(
unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+LdT;
667 double x2[d->ni], cp[d->ni], sy[d->ni];
668 for(
unsigned int i=0; i<d->ni; i++) x2[i]=x[i]+PdT;
670 for(
unsigned int i=0; i<d->ni; i++) cp[i]=0.0;
672 for(
unsigned int i=0; i<d->ni; i++) sy[i]=d->yi[i];
673 if(
simDispersion(x2, sy, d->ni, 1.0/kGI, 0.0, cp)!=0)
return(nan(
""));
675 if(
liInterpolate(x2, sy, d->ni, x, cp, NULL, NULL, d->ni, 3, 1, 0))
return(nan(
""));
679 if(
simC1DI(x, ca, cp, d->ni, K1a, K1p, k2, sy)!=0)
return(nan(
""));
681 for(
unsigned int i=0; i<d->ni; i++) sy[i]*=(1.0-Vb);
683 for(
unsigned int i=0; i<d->ni; i++) sy[i]+= Vb*(K1a*ca[i] + K1p*cp[i])/(K1a+K1p);
685 for(
unsigned int i=0; i<d->ni; i++) sy[i]+= Vb*ca[i];
688 if(d->xt1==NULL || d->xt2==NULL) {
689 if(
liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
692 if(
liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
697 if(d->verbose>2) {fprintf(stdout,
"computing WSS...\n"); fflush(stdout);}
699 for(
unsigned i=0; i<d->nt; i++) {
700 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.