8#include "tpcclibConfig.h"
34double func_wpul(
int parNr,
double *p,
void*);
36typedef struct FITDATA {
65static char *info[] = {
66 "Non-linear fitting of the radiowater model to pulmonary TTACs using BTAC",
67 "from RV cavity as the input function. Small delay and dispersion of input",
68 "function prior to lungs is allowed and fitted by default. Regional",
69 "radioactivity concentration is modelled as Cpet(t) = Vb*Cb(t) + Ct(t),",
70 "and thus the estimated K1 = (1-Va-Vb)*f. Air volume fraction (Va) could",
71 "be estimated from transmission or CT scan.",
73 "Usage: @P [Options] btacfile ttacfile [parfile]",
77 " Dispersion time constant is constrained to given value (sec).",
79 " Blood volume is constrained to given value (mL/mL of lung).",
81 " All weights are set to 1.0 (no weighting), or based on TTAC frame",
82 " lengths; by default, weights in TTAC file are used, if available.",
84 " Fitted and measured TACs are plotted in specified SVG file.",
86 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
89 "Sample times must be in seconds, unless units are specified in the file.",
91 "See also: fit_h2o, bfmh2o, fitk2, fit_wrlv, fit_disp",
93 "Keywords: TAC, modelling, perfusion, lungs, radiowater",
112int main(
int argc,
char **argv)
114 int ai, help=0, version=0, verbose=1;
115 char btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], parfile[FILENAME_MAX],
116 svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
118 double fixed_tau=nan(
"");
119 double fixed_vb=nan(
"");
127 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
128 btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
130 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
132 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
133 if(strcasecmp(cptr,
"W1")==0) {
135 }
else if(strcasecmp(cptr,
"WF")==0) {
137 }
else if(strncasecmp(cptr,
"TAU=", 4)==0 && strlen(cptr)>4) {
138 if(!
atofCheck(cptr+4, &fixed_tau) && fixed_tau>=0.0)
continue;
139 }
else if(strncasecmp(cptr,
"VB=", 3)==0 && strlen(cptr)>3) {
140 if(!
atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0)
continue;
141 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
142 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
143 }
else if(strncasecmp(cptr,
"SIM=", 4)==0 && strlen(cptr)>4) {
144 strlcpy(simfile, cptr+4, FILENAME_MAX);
continue;
146 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
155 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
160 if(ai<argc)
strlcpy(btacfile, argv[ai++], FILENAME_MAX);
161 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
162 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
164 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
169 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
175 printf(
"btacfile := %s\n", btacfile);
176 printf(
"ttacfile := %s\n", ttacfile);
177 if(parfile[0]) printf(
"parfile := %s\n", parfile);
178 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
179 if(simfile[0]) printf(
"simfile := %s\n", simfile);
180 printf(
"weights := %d\n",
weights);
181 if(!isnan(fixed_tau)) printf(
"fixed_tau := %g\n", fixed_tau);
182 if(!isnan(fixed_vb)) printf(
"fixed_vb := %g\n", fixed_vb);
190 if(verbose>1) printf(
"reading TACs\n");
200 printf(
"ttacNr := %d\n", ttac.
tacNr);
201 printf(
"ttac.sampleNr := %d\n", ttac.
sampleNr);
211 printf(
"btacNr := %d\n", btac.
tacNr);
212 printf(
"btac.sampleNr := %d\n", btac.
sampleNr);
216 if(verbose>0) fprintf(stdout,
"Note: BTAC file assumed to contain RV and LV BTACs.\n");
217 }
else if(btac.
tacNr>2) {
218 if(verbose>0) fprintf(stderr,
"Warning: BTAC file contains more than two TACs.\n");
223 fprintf(stderr,
"Error: too few samples.\n");
228 fprintf(stderr,
"Error: data contains missing values.\n");
236 fprintf(stderr,
"Error: invalid data sample times.\n");
248 fprintf(stderr,
"Error: check and set the data units.\n");
254 fprintf(stderr,
"Error: invalid data sample times.\n");
258 printf(
"xmin := %g\n", xmin);
259 printf(
"xmax := %g\n", xmax);
275 for(
int i=0; i<ttac.
sampleNr; i++) ttac.
w[i]=1.0;
279 for(
int i=0; i<ttac.
sampleNr; i++) ttac.
w[i]=1.0;
292 fprintf(stderr,
"Error: invalid input sample times.\n");
297 fprintf(stderr,
"Error: invalid input sample times.\n");
311 for(
int i=0; i<btac.
sampleNr; i++) x[i]=btac.
x[i]+4.0;
312 if(
liInterpolate(x, btac.
c[1].
y, btac.
sampleNr, btac.
x, y, NULL, NULL, btac.
sampleNr, 3, 1, 0))
314 fprintf(stderr,
"Error: invalid input sample times.\n");
317 for(
int i=0; i<btac.
sampleNr; i++) btac.
c[0].
y[i]=0.95*btac.
c[0].
y[i]+0.05*y[i];
325 if(verbose>1) printf(
"preparing space for parameters\n");
338 iftPut(&par.
h,
"program", buf, 0, NULL);
342 for(
int i=0; i<par.
tacNr; i++) {
356 iftPut(&par.
h,
"inputfile", btacfile, 0, NULL);
357 iftPut(&par.
h,
"datafile", ttacfile, 0, NULL);
363 if(verbose==1) {printf(
"\nfitting...\n"); fflush(stdout);}
366 for(
int ri=0; ri<ttac.
tacNr; ri++) {
367 if(verbose>1) {printf(
"\nfitting %s\n", ttac.
c[ri].
name); fflush(stdout);}
372 fitdata.yi=btac.
c[0].
y;
383 fitdata.yt=ttac.
c[ri].
y;
385 fitdata.syt=ttac.
c[ttac.
tacNr+ri].
y;
386 if(verbose>10) fitdata.verbose=verbose-10;
else fitdata.verbose=0;
390 fprintf(stderr,
"Error: cannot initiate NLLS.\n"); fflush(stderr); failed++;
398 if(isnan(fixed_tau)) {
406 if(isnan(fixed_vb)) {
422 printf(
"\nTime\tTTAC\tsimTTAC\n");
423 for(
unsigned int i=0; i<fitdata.nt; i++)
424 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
425 printf(
"\n"); fflush(stdout);
427 if(verbose>1) {printf(
"\twss := %g\n", wss); fflush(stdout);}
432 printf(
"initial guess\n");
441 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr); failed++;
447 printf(
"\nTime\tTTAC\tsimTTAC\n");
448 for(
unsigned int i=0; i<fitdata.nt; i++)
449 printf(
"%g\t%g\t%g\n", ttac.
x[i], ttac.
c[ri].
y[i], ttac.
c[ri+ttac.
tacNr].
y[i]);
450 printf(
"\n"); fflush(stdout);
453 if(verbose>2) printf(
" wss := %g\n", wss);
464 par.
r[ri].
p[5]=par.
r[ri].
p[3]/par.
r[ri].
p[4];
479 if(verbose>1) printf(
" saving %s\n", parfile);
480 FILE *fp=fopen(parfile,
"w");
482 fprintf(stderr,
"Error: cannot open file for writing.\n");
491 if(verbose>0) printf(
"parameters saved in %s\n", parfile);
499 if(verbose>1) printf(
"plotting measured and fitted data\n");
502 for(
int r=0; r<ttac.
tacNr; r++)
512 if(verbose>0) printf(
"Measured and fitted data plotted in %s\n", svgfile);
521 if(verbose>1) printf(
"calculating simulated TTACs\n");
526 fprintf(stderr,
"Error: cannot allocate space for simulated TTACs\n");
539 fitdata.yi=btac.
c[0].
y;
553 for(
int i=0; i<sim.
tacNr; i++) {
554 fitdata.yt=fitdata.syt=sim.
c[i].
y;
555 func_wpul(5, par.
r[i].
p, &fitdata);
559 if(verbose>1) printf(
"writing %s\n", simfile);
560 FILE *fp; fp=fopen(simfile,
"w");
562 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
568 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
571 if(verbose>=0) {printf(
"%s saved.\n", simfile); fflush(stdout);}
585double func_wpul(
int parNr,
double *p,
void *fdata)
587 FITDATA *d=(FITDATA*)fdata;
589 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
590 if(parNr!=5 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1)
return(nan(
""));
592 printf(
"p[]: %g", p[0]);
593 for(
int i=1; i<parNr; i++) printf(
" %g", p[i]);
594 printf(
"\n"); fflush(stdout);
598 double tau=p[0];
if(tau<0.0) tau=0.0;
600 double Vb=p[2];
if(Vb<0.0) Vb=0.0;
601 double K1=p[3]/60.0;
if(K1<0.0) K1=0.0;
602 double k2=p[4]/60.0;
if(k2<0.0) k2=0.0;
605 double x[d->ni], y[d->ni], sy[d->ni];
606 for(
unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+deltaT;
607 for(
unsigned int i=0; i<d->ni; i++) y[i]=d->yi[i];
608 if(
simDispersion(x, y, d->ni, tau, 0.0, sy)!=0)
return(nan(
""));
611 if(
simC1(x, y, d->ni, K1, k2, sy)!=0)
return(nan(
""));
612 for(
unsigned int i=0; i<d->ni; i++) sy[i]+=Vb*y[i];
615 if(d->xt1==NULL || d->xt2==NULL) {
616 if(
liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
619 if(
liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
624 if(d->verbose>2) {fprintf(stdout,
"computing WSS...\n"); fflush(stdout);}
626 for(
unsigned i=0; i<d->nt; i++) {
627 double v=d->syt[i] - d->yt[i];
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 simC1(double *t, double *ca, const int nr, const double k1, 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 tacFramesToSteps(TAC *inp, TAC *out, TPCSTATUS *status)
Transform TAC with frames into TAC with frames represented with stepwise changing dot-to-dot data.
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
int tacSetXContiguous(TAC *d)
Set PET TAC frame times contiguous, without even tiny overlap or gaps in between.
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.